Panda3D
|
00001 // Filename: parametricCurveCollection.cxx 00002 // Created by: drose (04Mar01) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "parametricCurveCollection.h" 00016 #include "config_parametrics.h" 00017 #include "curveFitter.h" 00018 #include "nurbsCurve.h" 00019 00020 #include "indent.h" 00021 #include "compose_matrix.h" 00022 #include "string_utils.h" 00023 #include "look_at.h" 00024 00025 //////////////////////////////////////////////////////////////////// 00026 // Function: ParametricCurveCollection::Constructor 00027 // Access: Published 00028 // Description: 00029 //////////////////////////////////////////////////////////////////// 00030 ParametricCurveCollection:: 00031 ParametricCurveCollection() { 00032 } 00033 00034 //////////////////////////////////////////////////////////////////// 00035 // Function: ParametricCurveCollection::add_curve 00036 // Access: Published 00037 // Description: Adds a new ParametricCurve to the collection. 00038 //////////////////////////////////////////////////////////////////// 00039 void ParametricCurveCollection:: 00040 add_curve(ParametricCurve *curve) { 00041 prepare_add_curve(curve); 00042 _curves.push_back(curve); 00043 redraw(); 00044 } 00045 00046 //////////////////////////////////////////////////////////////////// 00047 // Function: ParametricCurveCollection::add_curve 00048 // Access: Published 00049 // Description: Adds a new ParametricCurve to the collection at the 00050 // indicated index. 00051 //////////////////////////////////////////////////////////////////// 00052 void ParametricCurveCollection:: 00053 add_curve(ParametricCurve *curve, int index) { 00054 prepare_add_curve(curve); 00055 index = max(min(index, (int)_curves.size()), 0); 00056 _curves.insert(_curves.begin() + index, curve); 00057 redraw(); 00058 } 00059 00060 //////////////////////////////////////////////////////////////////// 00061 // Function: ParametricCurveCollection::add_curves 00062 // Access: Published 00063 // Description: Adds all the curves found in the scene graph rooted 00064 // at the given node. Returns the number of curves 00065 // found. 00066 //////////////////////////////////////////////////////////////////// 00067 int ParametricCurveCollection:: 00068 add_curves(PandaNode *node) { 00069 int num_curves = r_add_curves(node); 00070 00071 if (num_curves > 0) { 00072 redraw(); 00073 } 00074 00075 return num_curves; 00076 } 00077 00078 //////////////////////////////////////////////////////////////////// 00079 // Function: ParametricCurveCollection::remove_curve 00080 // Access: Published 00081 // Description: Removes the indicated ParametricCurve from the 00082 // collection. Returns true if the curve was removed, 00083 // false if it was not a member of the collection. 00084 //////////////////////////////////////////////////////////////////// 00085 bool ParametricCurveCollection:: 00086 remove_curve(ParametricCurve *curve) { 00087 int curve_index = -1; 00088 for (int i = 0; curve_index == -1 && i < (int)_curves.size(); i++) { 00089 if (_curves[i] == curve) { 00090 curve_index = i; 00091 } 00092 } 00093 00094 if (curve_index == -1) { 00095 // The indicated curve was not a member of the collection. 00096 return false; 00097 } 00098 00099 remove_curve(curve_index); 00100 00101 return true; 00102 } 00103 00104 //////////////////////////////////////////////////////////////////// 00105 // Function: ParametricCurveCollection::remove_curve 00106 // Access: Published 00107 // Description: Removes the indicated ParametricCurve from the 00108 // collection, by its index number. 00109 //////////////////////////////////////////////////////////////////// 00110 void ParametricCurveCollection:: 00111 remove_curve(int index) { 00112 nassertv(index >= 0 && index < (int)_curves.size()); 00113 PT(ParametricCurve) curve = _curves[index]; 00114 prepare_remove_curve(curve); 00115 _curves.erase(_curves.begin() + index); 00116 redraw(); 00117 } 00118 00119 //////////////////////////////////////////////////////////////////// 00120 // Function: ParametricCurveCollection::has_curve 00121 // Access: Published 00122 // Description: Returns true if the indicated ParametricCurve appears in 00123 // this collection, false otherwise. 00124 //////////////////////////////////////////////////////////////////// 00125 bool ParametricCurveCollection:: 00126 has_curve(ParametricCurve *curve) const { 00127 ParametricCurves::const_iterator ci; 00128 for (ci = _curves.begin(); ci != _curves.end(); ++ci) { 00129 if (curve == (*ci)) { 00130 return true; 00131 } 00132 } 00133 return false; 00134 } 00135 00136 //////////////////////////////////////////////////////////////////// 00137 // Function: ParametricCurveCollection::clear 00138 // Access: Published 00139 // Description: Removes all ParametricCurves from the collection. 00140 //////////////////////////////////////////////////////////////////// 00141 void ParametricCurveCollection:: 00142 clear() { 00143 ParametricCurves::iterator ci; 00144 for (ci = _curves.begin(); ci != _curves.end(); ++ci) { 00145 ParametricCurve *curve = (*ci); 00146 prepare_remove_curve(curve); 00147 } 00148 _curves.clear(); 00149 00150 redraw(); 00151 } 00152 00153 //////////////////////////////////////////////////////////////////// 00154 // Function: ParametricCurveCollection::clear_timewarps 00155 // Access: Published 00156 // Description: Removes all the timewarp curves from the collection. 00157 //////////////////////////////////////////////////////////////////// 00158 void ParametricCurveCollection:: 00159 clear_timewarps() { 00160 PT(ParametricCurve) xyz_curve = (ParametricCurve *)NULL; 00161 PT(ParametricCurve) hpr_curve = (ParametricCurve *)NULL; 00162 00163 ParametricCurves::iterator ci; 00164 for (ci = _curves.begin(); ci != _curves.end(); ++ci) { 00165 ParametricCurve *curve = (*ci); 00166 00167 switch (curve->get_curve_type()) { 00168 case PCT_XYZ: 00169 if (xyz_curve == (ParametricCurve *)NULL) { 00170 xyz_curve = curve; 00171 } else { 00172 prepare_remove_curve(curve); 00173 } 00174 break; 00175 00176 case PCT_HPR: 00177 if (hpr_curve == (ParametricCurve *)NULL) { 00178 hpr_curve = curve; 00179 } else { 00180 prepare_remove_curve(curve); 00181 } 00182 break; 00183 00184 default: 00185 prepare_remove_curve(curve); 00186 } 00187 } 00188 00189 _curves.clear(); 00190 _curves.push_back(xyz_curve); 00191 00192 if (hpr_curve != (ParametricCurve *)NULL) { 00193 _curves.push_back(hpr_curve); 00194 } 00195 00196 redraw(); 00197 } 00198 00199 //////////////////////////////////////////////////////////////////// 00200 // Function: ParametricCurveCollection::get_xyz_curve 00201 // Access: Published 00202 // Description: Returns the first XYZ curve in the collection, if 00203 // any, or NULL if there are none. 00204 //////////////////////////////////////////////////////////////////// 00205 ParametricCurve *ParametricCurveCollection:: 00206 get_xyz_curve() const { 00207 ParametricCurves::const_iterator ci; 00208 for (ci = _curves.begin(); ci != _curves.end(); ++ci) { 00209 ParametricCurve *curve = (*ci); 00210 if (curve->get_curve_type() == PCT_XYZ) { 00211 return curve; 00212 } 00213 } 00214 return (ParametricCurve *)NULL; 00215 } 00216 00217 //////////////////////////////////////////////////////////////////// 00218 // Function: ParametricCurveCollection::get_hpr_curve 00219 // Access: Published 00220 // Description: Returns the first HPR curve in the collection, if 00221 // any, or NULL if there are none. 00222 //////////////////////////////////////////////////////////////////// 00223 ParametricCurve *ParametricCurveCollection:: 00224 get_hpr_curve() const { 00225 ParametricCurves::const_iterator ci; 00226 for (ci = _curves.begin(); ci != _curves.end(); ++ci) { 00227 ParametricCurve *curve = (*ci); 00228 if (curve->get_curve_type() == PCT_HPR) { 00229 return curve; 00230 } 00231 } 00232 return (ParametricCurve *)NULL; 00233 } 00234 00235 //////////////////////////////////////////////////////////////////// 00236 // Function: ParametricCurveCollection::get_default_curve 00237 // Access: Published 00238 // Description: If there is an XYZ curve in the collection, returns 00239 // it; otherwise, returns the first curve whose type is 00240 // unspecified. Returns NULL if no curve meets the 00241 // criteria. 00242 //////////////////////////////////////////////////////////////////// 00243 ParametricCurve *ParametricCurveCollection:: 00244 get_default_curve() const { 00245 ParametricCurve *xyz_curve = get_xyz_curve(); 00246 if (xyz_curve != (ParametricCurve *)NULL) { 00247 return xyz_curve; 00248 } 00249 00250 ParametricCurves::const_iterator ci; 00251 for (ci = _curves.begin(); ci != _curves.end(); ++ci) { 00252 ParametricCurve *curve = (*ci); 00253 if (curve->get_curve_type() == PCT_NONE) { 00254 return curve; 00255 } 00256 } 00257 return (ParametricCurve *)NULL; 00258 } 00259 00260 //////////////////////////////////////////////////////////////////// 00261 // Function: ParametricCurveCollection::get_num_timewarps 00262 // Access: Published 00263 // Description: Returns the number of timewarp curves in the 00264 // collection. 00265 //////////////////////////////////////////////////////////////////// 00266 int ParametricCurveCollection:: 00267 get_num_timewarps() const { 00268 int count = 0; 00269 00270 ParametricCurves::const_iterator ci; 00271 for (ci = _curves.begin(); ci != _curves.end(); ++ci) { 00272 ParametricCurve *curve = (*ci); 00273 if (curve->get_curve_type() == PCT_T) { 00274 count++; 00275 } 00276 } 00277 00278 return count; 00279 } 00280 00281 //////////////////////////////////////////////////////////////////// 00282 // Function: ParametricCurveCollection::get_timewarp_curve 00283 // Access: Published 00284 // Description: Returns the nth timewarp curve in the collection. 00285 //////////////////////////////////////////////////////////////////// 00286 ParametricCurve *ParametricCurveCollection:: 00287 get_timewarp_curve(int n) const { 00288 ParametricCurves::const_iterator ci; 00289 for (ci = _curves.begin(); ci != _curves.end(); ++ci) { 00290 ParametricCurve *curve = (*ci); 00291 if (curve->get_curve_type() == PCT_T) { 00292 if (n == 0) { 00293 return curve; 00294 } 00295 n--; 00296 } 00297 } 00298 nassertr(false, (ParametricCurve *)NULL); 00299 return (ParametricCurve *)NULL; 00300 } 00301 00302 //////////////////////////////////////////////////////////////////// 00303 // Function: ParametricCurveCollection::make_even 00304 // Access: Published 00305 // Description: Discards all existing timewarp curves and recomputes 00306 // a new timewarp curve that maps distance along the 00307 // curve to parametric time, so that the distance 00308 // between any two points in parametric time is 00309 // proportional to the approximate distance of those 00310 // same two points along the XYZ curve. 00311 // 00312 // segments_per_unit represents the number of segments to 00313 // take per each unit of parametric time of the original 00314 // XYZ curve. 00315 // 00316 // The new timewarp curve (and thus, the apparent range 00317 // of the collection) will range from 0 to max_t. 00318 //////////////////////////////////////////////////////////////////// 00319 void ParametricCurveCollection:: 00320 make_even(PN_stdfloat max_t, PN_stdfloat segments_per_unit) { 00321 ParametricCurve *xyz_curve = get_xyz_curve(); 00322 if (xyz_curve == (ParametricCurve *)NULL) { 00323 parametrics_cat.error() 00324 << "No XYZ curve for make_even().\n"; 00325 return; 00326 } 00327 00328 clear_timewarps(); 00329 00330 // Now divvy up the XYZ curve into num_segments sections, each 00331 // approximately the same length as all the others. 00332 CurveFitter fitter; 00333 00334 int num_segments = max(1, (int)cfloor(segments_per_unit * xyz_curve->get_max_t() + 0.5f)); 00335 00336 if (parametrics_cat.is_debug()) { 00337 parametrics_cat.debug() 00338 << "Calculating length of curve.\n"; 00339 } 00340 00341 PN_stdfloat net_length = xyz_curve->calc_length(); 00342 PN_stdfloat segment_length = net_length / (PN_stdfloat)num_segments; 00343 00344 if (parametrics_cat.is_debug()) { 00345 parametrics_cat.debug() 00346 << "Curve has total length " << net_length << "; dividing into " 00347 << num_segments << " segments of " << segment_length << " units each.\n"; 00348 } 00349 00350 PN_stdfloat last_t = 0.0f; 00351 fitter.add_xyz(0.0f, LVecBase3(last_t, 0.0f, 0.0f)); 00352 PN_stdfloat val_inc= max_t/num_segments; 00353 PN_stdfloat val=val_inc; 00354 00355 for (int i = 0; i < num_segments; i++,val+=val_inc) { 00356 PN_stdfloat next_t = xyz_curve->find_length(last_t, segment_length); 00357 fitter.add_xyz(/*(PN_stdfloat)(i + 1)/num_segments * max_t,*/ 00358 val, LVecBase3(next_t, 0.0f, 0.0f)); 00359 00360 if (parametrics_cat.is_spam()) { 00361 parametrics_cat.spam() 00362 << "Point " << i << " is at " << next_t << "\n"; 00363 } 00364 00365 last_t = next_t; 00366 } 00367 00368 if (parametrics_cat.is_debug()) { 00369 parametrics_cat.debug() 00370 << "Done computing segments.\n"; 00371 } 00372 00373 fitter.compute_tangents(1); 00374 PT(ParametricCurveCollection) fit = fitter.make_nurbs(); 00375 ParametricCurve *t_curve = fit->get_xyz_curve(); 00376 nassertv(t_curve != (ParametricCurve *)NULL); 00377 t_curve->set_curve_type(PCT_T); 00378 add_curve(t_curve); 00379 } 00380 00381 //////////////////////////////////////////////////////////////////// 00382 // Function: ParametricCurveCollection::face_forward 00383 // Access: Published 00384 // Description: Discards the existing HPR curve and generates a new 00385 // one that looks in the direction of travel along the 00386 // XYZ curve, based on the XYZ curve's tangent at each 00387 // point. 00388 //////////////////////////////////////////////////////////////////// 00389 void ParametricCurveCollection:: 00390 face_forward(PN_stdfloat segments_per_unit) { 00391 ParametricCurve *xyz_curve = get_xyz_curve(); 00392 if (xyz_curve == (ParametricCurve *)NULL) { 00393 parametrics_cat.error() 00394 << "No XYZ curve for face_forward().\n"; 00395 return; 00396 } 00397 00398 // Eliminate all the old hpr curves, and also take note of the index 00399 // number of the first XYZ curve. 00400 int xyz_index = -1; 00401 ParametricCurves::const_iterator ci; 00402 ParametricCurves new_curves; 00403 00404 for (ci = _curves.begin(); ci != _curves.end(); ++ci) { 00405 ParametricCurve *curve = (*ci); 00406 if (curve->get_curve_type() == PCT_HPR) { 00407 prepare_remove_curve(curve); 00408 } else { 00409 if (curve->get_curve_type() == PCT_XYZ && xyz_index == -1) { 00410 xyz_index = (ci - _curves.begin()); 00411 } 00412 new_curves.push_back(curve); 00413 } 00414 } 00415 _curves.swap(new_curves); 00416 00417 // Now divvy up the XYZ curve into num_segments sections, of equal 00418 // length in parametric time (based on the timewarp curves). 00419 CurveFitter fitter; 00420 00421 PN_stdfloat max_t = get_max_t(); 00422 int num_segments = (int)cfloor(segments_per_unit * max_t + 0.5); 00423 00424 LVecBase3 hpr(0.0f, 0.0f, 0.0f); 00425 00426 // We compute the first HPR point a little point into the beginning 00427 // of the curve, instead of at 0.0f, because the tangent at 0.0f is 00428 // likely to be zero. 00429 determine_hpr(0.001, xyz_curve, hpr); 00430 fitter.add_hpr(0.0f, hpr); 00431 00432 for (int i = 0; i < num_segments; i++) { 00433 PN_stdfloat t = (PN_stdfloat)(i + 1) / num_segments * max_t; 00434 determine_hpr(t, xyz_curve, hpr); 00435 fitter.add_hpr(t, hpr); 00436 } 00437 00438 fitter.wrap_hpr(); 00439 fitter.compute_tangents(1); 00440 PT(ParametricCurveCollection) fit = fitter.make_nurbs(); 00441 ParametricCurve *hpr_curve = fit->get_hpr_curve(); 00442 nassertv(hpr_curve != (ParametricCurve *)NULL); 00443 add_curve(hpr_curve, xyz_index + 1); 00444 } 00445 00446 //////////////////////////////////////////////////////////////////// 00447 // Function: ParametricCurveCollection::reset_max_t 00448 // Access: Published 00449 // Description: Adjusts the apparent length of the curve by applying 00450 // a new timewarp that maps the range [0..max_t] to the 00451 // range [0..get_max_t()]. After this call, the curve 00452 // collection will contain one more timewarp curve, and 00453 // get_max_t() will return the given max_t value. 00454 //////////////////////////////////////////////////////////////////// 00455 void ParametricCurveCollection:: 00456 reset_max_t(PN_stdfloat max_t) { 00457 // Define a linear NURBS curve. 00458 PT(NurbsCurve) nurbs = new NurbsCurve; 00459 nurbs->set_curve_type(PCT_T); 00460 nurbs->set_order(2); 00461 nurbs->append_cv(LVecBase3(0.0f, 0.0f, 0.0f)); 00462 nurbs->append_cv(LVecBase3(get_max_t(), 0.0f, 0.0f)); 00463 nurbs->set_knot(0, 0.0f); 00464 nurbs->set_knot(1, 0.0f); 00465 nurbs->set_knot(2, max_t); 00466 nurbs->set_knot(3, max_t); 00467 nurbs->recompute(); 00468 add_curve(nurbs); 00469 } 00470 00471 //////////////////////////////////////////////////////////////////// 00472 // Function: ParametricCurveCollection::evaluate 00473 // Access: Published 00474 // Description: Computes the position and rotation represented by the 00475 // first XYZ and HPR curves in the collection at the 00476 // given point t, after t has been modified by all the 00477 // timewarp curves in the collection applied in 00478 // sequence, from back to front. 00479 // 00480 // Returns true if the point is valid (i.e. t is within 00481 // the bounds indicated by all the timewarp curves and 00482 // within the bounds of the curves themselves), or false 00483 // otherwise. 00484 //////////////////////////////////////////////////////////////////// 00485 bool ParametricCurveCollection:: 00486 evaluate(PN_stdfloat t, LVecBase3 &xyz, LVecBase3 &hpr) const { 00487 // First, apply all the timewarps in sequence, from back to front. 00488 // Also take note of the XYZ and HPR curves. 00489 ParametricCurve *xyz_curve = (ParametricCurve *)NULL; 00490 ParametricCurve *hpr_curve = (ParametricCurve *)NULL; 00491 ParametricCurve *default_curve = (ParametricCurve *)NULL; 00492 00493 PN_stdfloat t0 = t; 00494 LVecBase3 point; 00495 00496 ParametricCurves::const_reverse_iterator ci; 00497 for (ci = _curves.rbegin(); ci != _curves.rend(); ++ci) { 00498 ParametricCurve *curve = (*ci); 00499 00500 switch (curve->get_curve_type()) { 00501 case PCT_XYZ: 00502 xyz_curve = curve; 00503 break; 00504 00505 case PCT_HPR: 00506 hpr_curve = curve; 00507 break; 00508 00509 case PCT_NONE: 00510 default_curve = curve; 00511 break; 00512 00513 case PCT_T: 00514 if (!curve->get_point(t0, point)) { 00515 return false; 00516 } 00517 t0 = point[0]; 00518 } 00519 } 00520 00521 if (xyz_curve == (ParametricCurve *)NULL) { 00522 xyz_curve = default_curve; 00523 } 00524 00525 // Now compute the position and orientation. 00526 if (xyz_curve != (ParametricCurve *)NULL) { 00527 if (!xyz_curve->get_point(t0, xyz)) { 00528 return false; 00529 } 00530 } 00531 00532 if (hpr_curve != (ParametricCurve *)NULL) { 00533 if (!hpr_curve->get_point(t0, hpr)) { 00534 return false; 00535 } 00536 } 00537 00538 return true; 00539 } 00540 00541 //////////////////////////////////////////////////////////////////// 00542 // Function: ParametricCurveCollection::evaluate 00543 // Access: Published 00544 // Description: Computes the transform matrix representing 00545 // translation to the position indicated by the first 00546 // XYZ curve in the collection and the rotation 00547 // indicated by the first HPR curve in the collection, 00548 // after t has been modified by all the timewarp curves 00549 // in the collection applied in sequence, from back to 00550 // front. 00551 // 00552 // Returns true if the point is valid (i.e. t is within 00553 // the bounds indicated by all the timewarp curves and 00554 // within the bounds of the curves themselves), or false 00555 // otherwise. 00556 //////////////////////////////////////////////////////////////////// 00557 bool ParametricCurveCollection:: 00558 evaluate(PN_stdfloat t, LMatrix4 &result, CoordinateSystem cs) const { 00559 LVecBase3 xyz(0.0f, 0.0f, 0.0f); 00560 LVecBase3 hpr(0.0f, 0.0f, 0.0f); 00561 00562 if (!evaluate(t, xyz, hpr)) { 00563 return false; 00564 } 00565 00566 compose_matrix(result, 00567 LVecBase3(1.0f, 1.0f, 1.0f), 00568 LVecBase3(0.0f, 0.0f, 0.0f), 00569 hpr, xyz, cs); 00570 return true; 00571 } 00572 00573 //////////////////////////////////////////////////////////////////// 00574 // Function: ParametricCurveCollection::evaluate_t 00575 // Access: Published 00576 // Description: Determines the value of t that should be passed to 00577 // the XYZ and HPR curves, after applying the given 00578 // value of t to all the timewarps. Return -1.0f if the 00579 // value of t exceeds one of the timewarps' ranges. 00580 //////////////////////////////////////////////////////////////////// 00581 PN_stdfloat ParametricCurveCollection:: 00582 evaluate_t(PN_stdfloat t) const { 00583 PN_stdfloat t0 = t; 00584 LVecBase3 point; 00585 00586 ParametricCurves::const_iterator ci; 00587 for (ci = _curves.begin(); ci != _curves.end(); ++ci) { 00588 ParametricCurve *curve = (*ci); 00589 00590 if (curve->get_curve_type() == PCT_T) { 00591 if (!curve->get_point(t0, point)) { 00592 return -1.0f; 00593 } 00594 t0 = point[0]; 00595 } 00596 } 00597 00598 return t0; 00599 } 00600 00601 //////////////////////////////////////////////////////////////////// 00602 // Function: ParametricCurveCollection::adjust_xyz 00603 // Access: Published 00604 // Description: Adjust the XYZ curve at the indicated time to the new 00605 // value. The curve shape will change correspondingly. 00606 // Returns true if successful, false if unable to make 00607 // the adjustment for some reason. 00608 //////////////////////////////////////////////////////////////////// 00609 bool ParametricCurveCollection:: 00610 adjust_xyz(PN_stdfloat t, const LVecBase3 &xyz) { 00611 ParametricCurve *xyz_curve = get_xyz_curve(); 00612 if (xyz_curve == (ParametricCurve *)NULL) { 00613 return false; 00614 } 00615 00616 PN_stdfloat t0 = evaluate_t(t); 00617 if (t0 >= 0.0f && t < xyz_curve->get_max_t()) { 00618 return xyz_curve->adjust_point(t, xyz[0], xyz[1], xyz[2]); 00619 } 00620 return false; 00621 } 00622 00623 //////////////////////////////////////////////////////////////////// 00624 // Function: ParametricCurveCollection::adjust_hpr 00625 // Access: Published 00626 // Description: Adjust the HPR curve at the indicated time to the new 00627 // value. The curve shape will change correspondingly. 00628 // Returns true if successful, false if unable to make 00629 // the adjustment for some reason. 00630 //////////////////////////////////////////////////////////////////// 00631 bool ParametricCurveCollection:: 00632 adjust_hpr(PN_stdfloat t, const LVecBase3 &hpr) { 00633 ParametricCurve *hpr_curve = get_hpr_curve(); 00634 if (hpr_curve == (ParametricCurve *)NULL) { 00635 return false; 00636 } 00637 00638 PN_stdfloat t0 = evaluate_t(t); 00639 if (t0 >= 0.0f && t < hpr_curve->get_max_t()) { 00640 return hpr_curve->adjust_point(t, hpr[0], hpr[1], hpr[2]); 00641 } 00642 return false; 00643 } 00644 00645 //////////////////////////////////////////////////////////////////// 00646 // Function: ParametricCurveCollection::recompute 00647 // Access: Published 00648 // Description: Ensures all the curves are freshly computed and 00649 // up-to-date. Returns true if everything is valid, 00650 // false if at least one curve is incorrect. 00651 //////////////////////////////////////////////////////////////////// 00652 bool ParametricCurveCollection:: 00653 recompute() { 00654 bool all_ok = true; 00655 00656 ParametricCurves::iterator ci; 00657 for (ci = _curves.begin(); ci != _curves.end(); ++ci) { 00658 ParametricCurve *curve = (*ci); 00659 if (!curve->recompute()) { 00660 all_ok = false; 00661 } 00662 } 00663 00664 return all_ok; 00665 } 00666 00667 //////////////////////////////////////////////////////////////////// 00668 // Function: ParametricCurveCollection::stitch 00669 // Access: Published 00670 // Description: Regenerates this curve as one long curve: the first 00671 // curve connected end-to-end with the second one. 00672 // Either a or b may be the same as 'this'. This will 00673 // lose any timewarps on the input curves. 00674 // 00675 // Returns true if successful, false on failure. 00676 //////////////////////////////////////////////////////////////////// 00677 bool ParametricCurveCollection:: 00678 stitch(const ParametricCurveCollection *a, 00679 const ParametricCurveCollection *b) { 00680 PT(ParametricCurve) a_xyz = a->get_xyz_curve(); 00681 PT(ParametricCurve) b_xyz = b->get_xyz_curve(); 00682 00683 PT(ParametricCurve) a_hpr = a->get_hpr_curve(); 00684 PT(ParametricCurve) b_hpr = b->get_hpr_curve(); 00685 00686 clear(); 00687 00688 if (a_xyz != (ParametricCurve *)NULL && b_xyz != (ParametricCurve *)NULL) { 00689 PT(NurbsCurve) new_xyz = new NurbsCurve; 00690 if (!new_xyz->stitch(a_xyz, b_xyz)) { 00691 return false; 00692 } 00693 new_xyz->set_curve_type(PCT_XYZ); 00694 add_curve(new_xyz); 00695 } 00696 00697 if (a_hpr != (ParametricCurve *)NULL && b_hpr != (ParametricCurve *)NULL) { 00698 PT(NurbsCurve) new_hpr = new NurbsCurve; 00699 if (!new_hpr->stitch(a_hpr, b_hpr)) { 00700 return false; 00701 } 00702 new_hpr->set_curve_type(PCT_HPR); 00703 add_curve(new_hpr); 00704 } 00705 00706 return true; 00707 } 00708 00709 //////////////////////////////////////////////////////////////////// 00710 // Function: ParametricCurveCollection::output 00711 // Access: Published 00712 // Description: Writes a brief one-line description of the 00713 // ParametricCurveCollection to the indicated output stream. 00714 //////////////////////////////////////////////////////////////////// 00715 void ParametricCurveCollection:: 00716 output(ostream &out) const { 00717 if (get_num_curves() == 1) { 00718 out << "1 ParametricCurve"; 00719 } else { 00720 out << get_num_curves() << " ParametricCurves"; 00721 } 00722 } 00723 00724 //////////////////////////////////////////////////////////////////// 00725 // Function: ParametricCurveCollection::write 00726 // Access: Published 00727 // Description: Writes a complete multi-line description of the 00728 // ParametricCurveCollection to the indicated output stream. 00729 //////////////////////////////////////////////////////////////////// 00730 void ParametricCurveCollection:: 00731 write(ostream &out, int indent_level) const { 00732 ParametricCurves::const_iterator ci; 00733 for (ci = _curves.begin(); ci != _curves.end(); ++ci) { 00734 ParametricCurve *curve = (*ci); 00735 indent(out, indent_level) << *curve << "\n"; 00736 } 00737 } 00738 00739 //////////////////////////////////////////////////////////////////// 00740 // Function: ParametricCurveCollection::write_egg 00741 // Access: Published 00742 // Description: Writes an egg description of all the nurbs curves in 00743 // the collection to the specified output file. Returns 00744 // true if the file is successfully written. 00745 //////////////////////////////////////////////////////////////////// 00746 bool ParametricCurveCollection:: 00747 write_egg(Filename filename, CoordinateSystem cs) { 00748 pofstream out; 00749 filename.set_text(); 00750 00751 if (!filename.open_write(out)) { 00752 parametrics_cat.error() 00753 << "Unable to write to " << filename << "\n"; 00754 return false; 00755 } 00756 return write_egg(out, filename, cs); 00757 } 00758 00759 //////////////////////////////////////////////////////////////////// 00760 // Function: ParametricCurveCollection::write_egg 00761 // Access: Published 00762 // Description: Writes an egg description of all the nurbs curves in 00763 // the collection to the specified output stream. Returns 00764 // true if the file is successfully written. 00765 //////////////////////////////////////////////////////////////////// 00766 bool ParametricCurveCollection:: 00767 write_egg(ostream &out, const Filename &filename, CoordinateSystem cs) { 00768 if (cs == CS_default) { 00769 cs = get_default_coordinate_system(); 00770 } 00771 00772 if (cs != CS_invalid) { 00773 out << "<CoordinateSystem> { "; 00774 switch (cs) { 00775 case CS_zup_right: 00776 out << "Z-Up"; 00777 break; 00778 00779 case CS_yup_right: 00780 out << "Y-Up"; 00781 break; 00782 00783 case CS_zup_left: 00784 out << "Z-Up-Left"; 00785 break; 00786 00787 case CS_yup_left: 00788 out << "Y-Up-Left"; 00789 break; 00790 00791 default: 00792 break; 00793 } 00794 out << " }\n\n"; 00795 } 00796 00797 int xyz_count = 0; 00798 int hpr_count = 0; 00799 int t_count = 0; 00800 00801 ParametricCurves::iterator ci; 00802 for (ci = _curves.begin(); ci != _curves.end(); ++ci) { 00803 ParametricCurve *curve = (*ci); 00804 00805 if (!curve->has_name()) { 00806 // If we don't have a name, come up with one. 00807 string name = filename.get_basename_wo_extension(); 00808 00809 switch (curve->get_curve_type()) { 00810 case PCT_XYZ: 00811 name += "_xyz"; 00812 if (xyz_count > 0) { 00813 name += format_string(xyz_count); 00814 } 00815 xyz_count++; 00816 break; 00817 00818 case PCT_HPR: 00819 name += "_hpr"; 00820 if (hpr_count > 0) { 00821 name += format_string(hpr_count); 00822 } 00823 hpr_count++; 00824 break; 00825 00826 case PCT_T: 00827 name += "_t"; 00828 if (t_count > 0) { 00829 name += format_string(t_count); 00830 } 00831 t_count++; 00832 break; 00833 } 00834 00835 curve->set_name(name); 00836 } 00837 00838 if (!curve->write_egg(out, filename, CS_invalid)) { 00839 return false; 00840 } 00841 } 00842 00843 return true; 00844 } 00845 00846 //////////////////////////////////////////////////////////////////// 00847 // Function: ParametricCurveCollection::r_add_curves 00848 // Access: Private 00849 // Description: The recursive implementation of add_curves(). 00850 //////////////////////////////////////////////////////////////////// 00851 int ParametricCurveCollection:: 00852 r_add_curves(PandaNode *node) { 00853 int num_curves = 0; 00854 00855 if (node->is_of_type(ParametricCurve::get_class_type())) { 00856 ParametricCurve *curve = DCAST(ParametricCurve, node); 00857 prepare_add_curve(curve); 00858 _curves.push_back(curve); 00859 num_curves++; 00860 } 00861 00862 int num_children = node->get_num_children(); 00863 for (int i = 0; i < num_children; i++) { 00864 PandaNode *child = node->get_child(i); 00865 num_curves += r_add_curves(child); 00866 } 00867 00868 return num_curves; 00869 } 00870 00871 //////////////////////////////////////////////////////////////////// 00872 // Function: ParametricCurveCollection::register_drawer 00873 // Access: Public 00874 // Description: Registers a Drawer with this curve collection that 00875 // will automatically be updated whenever the collection 00876 // is modified, so that the visible representation of 00877 // the curve is kept up to date. This is called 00878 // automatically by the ParametricCurveDrawer. 00879 // 00880 // Any number of Drawers may be registered with a 00881 // particular curve collection. 00882 //////////////////////////////////////////////////////////////////// 00883 void ParametricCurveCollection:: 00884 register_drawer(ParametricCurveDrawer *drawer) { 00885 _drawers.push_back(drawer); 00886 00887 ParametricCurves::iterator ci; 00888 for (ci = _curves.begin(); ci != _curves.end(); ++ci) { 00889 ParametricCurve *curve = (*ci); 00890 curve->register_drawer(drawer); 00891 } 00892 } 00893 00894 //////////////////////////////////////////////////////////////////// 00895 // Function: ParametricCurveCollection::unregister_drawer 00896 // Access: Public 00897 // Description: Removes a previously registered drawer from the list 00898 // of automatically-refreshed drawers. This is called 00899 // automatically by the ParametricCurveDrawer. 00900 //////////////////////////////////////////////////////////////////// 00901 void ParametricCurveCollection:: 00902 unregister_drawer(ParametricCurveDrawer *drawer) { 00903 _drawers.remove(drawer); 00904 00905 ParametricCurves::iterator ci; 00906 for (ci = _curves.begin(); ci != _curves.end(); ++ci) { 00907 ParametricCurve *curve = (*ci); 00908 curve->unregister_drawer(drawer); 00909 } 00910 } 00911 00912 //////////////////////////////////////////////////////////////////// 00913 // Function: ParametricCurveCollection::determine_hpr 00914 // Access: Private 00915 // Description: Computes the orientation at the given point in time, 00916 // based on the tangent of the XYZ curve. Returns true 00917 // if the orientation can be determined, or false if it 00918 // cannot (in which case hpr is left unchanged). 00919 //////////////////////////////////////////////////////////////////// 00920 bool ParametricCurveCollection:: 00921 determine_hpr(PN_stdfloat t, ParametricCurve *xyz_curve, LVecBase3 &hpr) const { 00922 PN_stdfloat t0 = evaluate_t(t); 00923 00924 LVector3 tangent; 00925 if (!xyz_curve->get_tangent(t0, tangent)) { 00926 return false; 00927 } 00928 00929 if (tangent.length_squared() == 0.0f) { 00930 return false; 00931 } 00932 00933 LMatrix3 mat; 00934 look_at(mat, tangent); 00935 00936 LVecBase3 scale, shear; 00937 return decompose_matrix(mat, scale, shear, hpr); 00938 } 00939 00940 //////////////////////////////////////////////////////////////////// 00941 // Function: ParametricCurveCollection::prepare_add_curve 00942 // Access: Private 00943 // Description: Registers the curve with the list of drawers that 00944 // share this collection, in preparation for adding it 00945 // to the _curves list. 00946 //////////////////////////////////////////////////////////////////// 00947 void ParametricCurveCollection:: 00948 prepare_add_curve(ParametricCurve *curve) { 00949 DrawerList::iterator di; 00950 for (di = _drawers.begin(); di != _drawers.end(); ++di) { 00951 ParametricCurveDrawer *drawer = (*di); 00952 curve->register_drawer(drawer); 00953 } 00954 } 00955 00956 //////////////////////////////////////////////////////////////////// 00957 // Function: ParametricCurveCollection::prepare_remove_curve 00958 // Access: Private 00959 // Description: Unregisters the curve with the list of drawers that 00960 // share this collection, in preparation for removing it 00961 // from the _curves list. 00962 //////////////////////////////////////////////////////////////////// 00963 void ParametricCurveCollection:: 00964 prepare_remove_curve(ParametricCurve *curve) { 00965 DrawerList::iterator di; 00966 for (di = _drawers.begin(); di != _drawers.end(); ++di) { 00967 ParametricCurveDrawer *drawer = (*di); 00968 curve->unregister_drawer(drawer); 00969 } 00970 } 00971 00972 //////////////////////////////////////////////////////////////////// 00973 // Function: ParametricCurveCollection::redraw 00974 // Access: Private 00975 // Description: Calls redraw() on all drawers that share this 00976 // collection. 00977 //////////////////////////////////////////////////////////////////// 00978 void ParametricCurveCollection:: 00979 redraw() { 00980 /* 00981 DrawerList::iterator di; 00982 for (di = _drawers.begin(); di != _drawers.end(); ++di) { 00983 ParametricCurveDrawer *drawer = (*di); 00984 drawer->redraw(); 00985 } 00986 */ 00987 }