Panda3D
 All Classes Functions Variables Enumerations
parametricCurveCollection.cxx
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 }
 All Classes Functions Variables Enumerations