Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/parametrics/parametricCurveCollection.cxx

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

Generated on Fri May 2 00:40:50 2003 for Panda by doxygen1.3