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

panda/src/parametrics/curveFitter.cxx

Go to the documentation of this file.
00001 // Filename: curveFitter.cxx
00002 // Created by:  drose (17Sep98)
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 "pandabase.h"
00020 #include "pointerTo.h"
00021 
00022 #include "curveFitter.h"
00023 #include "config_parametrics.h"
00024 #include "parametricCurve.h"
00025 #include "classicNurbsCurve.h"
00026 #include "hermiteCurve.h"
00027 #include <algorithm>
00028 
00029 TypeHandle CurveFitter::_type_handle;
00030 
00031 ////////////////////////////////////////////////////////////////////
00032 //     Function: CurveFitter::Constructor
00033 //       Access: Public
00034 //  Description:
00035 ////////////////////////////////////////////////////////////////////
00036 CurveFitter::
00037 CurveFitter() {
00038   _got_xyz = false;
00039   _got_hpr = false;
00040 }
00041 
00042 ////////////////////////////////////////////////////////////////////
00043 //     Function: CurveFitter::Destructor
00044 //       Access: Public
00045 //  Description:
00046 ////////////////////////////////////////////////////////////////////
00047 CurveFitter::
00048 ~CurveFitter() {
00049 }
00050 
00051 ////////////////////////////////////////////////////////////////////
00052 //     Function: CurveFitter::reset
00053 //       Access: Public
00054 //  Description: Removes all the data points previously added to the
00055 //               CurveFitter, and initializes it for a new curve.
00056 ////////////////////////////////////////////////////////////////////
00057 void CurveFitter::
00058 reset() {
00059   _data.erase(_data.begin(), _data.end());
00060 }
00061 
00062 ////////////////////////////////////////////////////////////////////
00063 //     Function: CurveFitter::add_xyz
00064 //       Access: Public
00065 //  Description: Adds a single sample xyz.
00066 ////////////////////////////////////////////////////////////////////
00067 void CurveFitter::
00068 add_xyz(float t, const LVecBase3f &xyz) {
00069   DataPoint dp;
00070   dp._t = t;
00071   dp._xyz = xyz;
00072   _data.push_back(dp);
00073   _got_xyz = true;
00074 }
00075 
00076 ////////////////////////////////////////////////////////////////////
00077 //     Function: CurveFitter::add_hpr
00078 //       Access: Public
00079 //  Description: Adds a single sample hpr.
00080 ////////////////////////////////////////////////////////////////////
00081 void CurveFitter::
00082 add_hpr(float t, const LVecBase3f &hpr) {
00083   DataPoint dp;
00084   dp._t = t;
00085   dp._hpr = hpr;
00086   _data.push_back(dp);
00087   _got_hpr = true;
00088 }
00089 
00090 ////////////////////////////////////////////////////////////////////
00091 //     Function: CurveFitter::add_xyz_hpr
00092 //       Access: Public
00093 //  Description: Adds a single sample xyz & hpr simultaneously.
00094 ////////////////////////////////////////////////////////////////////
00095 void CurveFitter::
00096 add_xyz_hpr(float t, const LVecBase3f &xyz, const LVecBase3f &hpr) {
00097   DataPoint dp;
00098   dp._t = t;
00099   dp._xyz = xyz;
00100   dp._hpr = hpr;
00101   _data.push_back(dp);
00102   _got_xyz = true;
00103   _got_hpr = true;
00104 }
00105 
00106 ////////////////////////////////////////////////////////////////////
00107 //     Function: CurveFitter::get_num_samples
00108 //       Access: Public
00109 //  Description: Returns the number of sample points that have been
00110 //               added.
00111 ////////////////////////////////////////////////////////////////////
00112 int CurveFitter::
00113 get_num_samples() const {
00114   return _data.size();
00115 }
00116 
00117 ////////////////////////////////////////////////////////////////////
00118 //     Function: CurveFitter::get_sample_t
00119 //       Access: Public
00120 //  Description: Returns the parametric value of the nth sample added.
00121 ////////////////////////////////////////////////////////////////////
00122 float CurveFitter::
00123 get_sample_t(int n) const {
00124   nassertr(n >= 0 && n < (int)_data.size(), 0.0f);
00125   return _data[n]._t;
00126 }
00127 
00128 ////////////////////////////////////////////////////////////////////
00129 //     Function: CurveFitter::get_sample_xyz
00130 //       Access: Public
00131 //  Description: Returns the point in space of the nth sample added.
00132 ////////////////////////////////////////////////////////////////////
00133 LVecBase3f CurveFitter::
00134 get_sample_xyz(int n) const {
00135   nassertr(n >= 0 && n < (int)_data.size(), LVecBase3f::zero());
00136   return _data[n]._xyz;
00137 }
00138 
00139 ////////////////////////////////////////////////////////////////////
00140 //     Function: CurveFitter::get_sample_hpr
00141 //       Access: Public
00142 //  Description: Returns the orientation of the nth sample added.
00143 ////////////////////////////////////////////////////////////////////
00144 LVecBase3f CurveFitter::
00145 get_sample_hpr(int n) const {
00146   nassertr(n >= 0 && n < (int)_data.size(), LVecBase3f::zero());
00147   return _data[n]._hpr;
00148 }
00149 
00150 ////////////////////////////////////////////////////////////////////
00151 //     Function: CurveFitter::get_sample_tangent
00152 //       Access: Public
00153 //  Description: Returns the tangent associated with the nth sample
00154 //               added.  This is only meaningful if compute_tangents()
00155 //               has already been called.
00156 ////////////////////////////////////////////////////////////////////
00157 LVecBase3f CurveFitter::
00158 get_sample_tangent(int n) const {
00159   nassertr(n >= 0 && n < (int)_data.size(), LVecBase3f::zero());
00160   return _data[n]._tangent;
00161 }
00162 
00163 ////////////////////////////////////////////////////////////////////
00164 //     Function: CurveFitter::remove_samples
00165 //       Access: Public
00166 //  Description: Eliminates all samples from index begin, up to but not
00167 //               including index end, from the database.
00168 ////////////////////////////////////////////////////////////////////
00169 void CurveFitter::
00170 remove_samples(int begin, int end) {
00171   begin = max(0, min((int)_data.size(), begin));
00172   end = max(0, min((int)_data.size(), end));
00173 
00174   nassertv(begin <= end);
00175 
00176   _data.erase(_data.begin() + begin, _data.begin() + end);
00177 }
00178 
00179 ////////////////////////////////////////////////////////////////////
00180 //     Function: CurveFitter::sample
00181 //       Access: Public
00182 //  Description: Generates a series of data points by sampling the
00183 //               given curve (or xyz/hpr curves) the indicated number
00184 //               of times.  The sampling is made evenly in parametric
00185 //               time, and then the timewarps, if any, are applied.
00186 ////////////////////////////////////////////////////////////////////
00187 void CurveFitter::
00188 sample(ParametricCurveCollection *curves, int count) {
00189   nassertv(curves != (ParametricCurveCollection *)NULL);
00190   float max_t = curves->get_max_t();
00191   float t, last_t, d;
00192   DataPoint dp;
00193 
00194   last_t = 0.0f;
00195   d = 0.0f;
00196   int i;
00197   for (i = 0; i < count; i++) {
00198     t = max_t * (float)i / (float)(count-1);
00199     if (curves->evaluate(t, dp._xyz, dp._hpr)) {
00200       dp._t = t;
00201       _data.push_back(dp);
00202     }
00203   }
00204 
00205   if (curves->get_xyz_curve() != (ParametricCurve *)NULL) {
00206     _got_xyz = true;
00207   }
00208   if (curves->get_hpr_curve() != (ParametricCurve *)NULL) {
00209     _got_hpr = true;
00210   }
00211 }
00212 
00213 
00214 
00215 ////////////////////////////////////////////////////////////////////
00216 //     Function: CurveFitter::wrap_hpr
00217 //       Access: Public
00218 //  Description: Resets each HPR data point so that the maximum delta
00219 //               between any two consecutive points is 180 degrees,
00220 //               which should prevent incorrect HPR wrapping.
00221 ////////////////////////////////////////////////////////////////////
00222 void CurveFitter::
00223 wrap_hpr() {
00224   Data::iterator di;
00225   LVecBase3f last(0.0f, 0.0f, 0.0f);
00226   LVecBase3f net(0.0f, 0.0f, 0.0f);
00227 
00228   for (di = _data.begin(); di != _data.end(); ++di) {
00229     int i;
00230     for (i = 0; i < 3; i++) {
00231       (*di)._hpr[i] += net[i];
00232 
00233       while (((*di)._hpr[i] - last[i]) > 180.0f) {
00234         (*di)._hpr[i] -= 360.0f;
00235         net[i] -= 360.0f;
00236       }
00237 
00238       while (((*di)._hpr[i] - last[i]) < -180.0f) {
00239         (*di)._hpr[i] += 360.0f;
00240         net[i] += 360.0f;
00241       }
00242 
00243       last[i] = (*di)._hpr[i];
00244     }
00245   }
00246 }
00247 
00248 ////////////////////////////////////////////////////////////////////
00249 //     Function: CurveFitter::sort_points
00250 //       Access: Public
00251 //  Description: Sorts all the data points in order by parametric
00252 //               time, in case they were added in an incorrect order.
00253 ////////////////////////////////////////////////////////////////////
00254 void CurveFitter::
00255 sort_points() {
00256   sort(_data.begin(), _data.end());
00257 }
00258 
00259 ////////////////////////////////////////////////////////////////////
00260 //     Function: CurveFitter::desample
00261 //       Access: Public
00262 //  Description: Removes sample points in order to reduce the
00263 //               complexity of a sampled curve.  Keeps one out of
00264 //               every factor samples.  Also keeps the first and the
00265 //               last samples.
00266 ////////////////////////////////////////////////////////////////////
00267 void CurveFitter::
00268 desample(float factor) {
00269   int in, out;
00270   float count = factor;
00271 
00272   out = 0;
00273   for (in = 0; in < (int)_data.size()-1; in++) {
00274     if (count >= factor) {
00275       _data[out] = _data[in];
00276       out++;
00277       count -= factor;
00278     }
00279     count += 1.0f;
00280   }
00281 
00282   _data[out] = _data.back();
00283   out++;
00284 
00285   _data.erase(_data.begin() + out, _data.end());
00286 }
00287 
00288 ////////////////////////////////////////////////////////////////////
00289 //     Function: CurveFitter::compute_tangents
00290 //       Access: Public
00291 //  Description: Once a set of points has been built, and prior to
00292 //               calling MakeHermite() or MakeNurbs(),
00293 //               ComputeTangents() must be called to set up the
00294 //               tangents correctly (unless the tangents were defined
00295 //               as the points were added).
00296 ////////////////////////////////////////////////////////////////////
00297 void CurveFitter::
00298 compute_tangents(float scale) {
00299   // If the head and tail points match up, close the curve.
00300   bool closed = false;
00301 
00302   if (_got_xyz) {
00303     closed =
00304       (_data.front()._xyz.almost_equal(_data.back()._xyz, 0.001f));
00305 
00306   } else if (_got_hpr) {
00307     closed =
00308       (_data.front()._hpr.almost_equal(_data.back()._hpr, 0.001f));
00309   }
00310 
00311   int i;
00312   int len = _data.size();
00313 
00314   // First, get all the points in the middle, excluding endpoints.
00315   // These are handled the same whether we are closing the curve or
00316   // not.
00317   if (_got_xyz) {
00318     for (i = 1; i < len-1; i++) {
00319       _data[i]._tangent =
00320         (_data[i+1]._xyz - _data[i-1]._xyz) * scale /
00321         (_data[i+1]._t - _data[i-1]._t);
00322     }
00323   }
00324   if (_got_hpr) {
00325     for (i = 1; i < len-1; i++) {
00326       _data[i]._hpr_tangent =
00327         (_data[i+1]._hpr - _data[i-1]._hpr) * scale /
00328         (_data[i+1]._t - _data[i-1]._t);
00329     }
00330   }
00331 
00332   // Now handle the endpoints.
00333   if (closed) {
00334     if (_got_xyz) {
00335       _data[0]._tangent = _data[len-1]._tangent =
00336         (_data[1]._xyz - _data[len-2]._xyz) * scale /
00337         ((_data[1]._t - _data[0]._t) + (_data[len-1]._t - _data[len-2]._t));
00338     }
00339     if (_got_hpr) {
00340       _data[0]._tangent = _data[len-1]._tangent =
00341         (_data[1]._hpr - _data[len-2]._hpr) * scale /
00342         ((_data[1]._t - _data[0]._t) + (_data[len-1]._t - _data[len-2]._t));
00343     }
00344 
00345   } else {
00346     if (_got_xyz) {
00347       _data[0]._tangent =
00348         (_data[1]._xyz - _data[0]._xyz) * scale /
00349         ((_data[1]._t - _data[0]._t) * 2.0f);
00350       _data[len-1]._tangent =
00351         (_data[len-1]._xyz - _data[len-2]._xyz) * scale /
00352         ((_data[len-1]._t - _data[len-2]._t) * 2.0f);
00353     }
00354     if (_got_hpr) {
00355       _data[0]._tangent =
00356         (_data[1]._hpr - _data[0]._hpr) * scale /
00357         ((_data[1]._t - _data[0]._t) * 2.0f);
00358       _data[len-1]._tangent =
00359         (_data[len-1]._hpr - _data[len-2]._hpr) * scale /
00360         ((_data[len-1]._t - _data[len-2]._t) * 2.0f);
00361     }
00362   }
00363 }
00364 
00365 ////////////////////////////////////////////////////////////////////
00366 //     Function: CurveFitter::make_hermite
00367 //       Access: Public
00368 //  Description: Converts the current set of data points into a
00369 //               Hermite curve.
00370 ////////////////////////////////////////////////////////////////////
00371 PT(ParametricCurveCollection) CurveFitter::
00372 make_hermite() const {
00373   PT(ParametricCurveCollection) result = new ParametricCurveCollection;
00374 
00375   if (_got_xyz) {
00376     HermiteCurve *hc = new HermiteCurve;
00377     result->add_curve(hc);
00378     hc->set_curve_type(PCT_XYZ);
00379 
00380     Data::const_iterator di;
00381     for (di = _data.begin(); di != _data.end(); ++di) {
00382       int n = hc->insert_cv((*di)._t);
00383       hc->set_cv_type(n, HC_SMOOTH);
00384       hc->set_cv_point(n, (*di)._xyz);
00385       hc->set_cv_in(n, (*di)._tangent);
00386       hc->set_cv_out(n, (*di)._tangent);
00387     }
00388   }
00389 
00390   if (_got_hpr) {
00391     HermiteCurve *hc = new HermiteCurve;
00392     result->add_curve(hc);
00393     hc->set_curve_type(PCT_HPR);
00394 
00395     Data::const_iterator di;
00396     for (di = _data.begin(); di != _data.end(); ++di) {
00397       int n = hc->insert_cv((*di)._t);
00398       hc->set_cv_type(n, HC_SMOOTH);
00399       hc->set_cv_point(n, (*di)._hpr);
00400       hc->set_cv_in(n, (*di)._hpr_tangent);
00401       hc->set_cv_out(n, (*di)._hpr_tangent);
00402     }
00403   }
00404 
00405   return result;
00406 }
00407 
00408 ////////////////////////////////////////////////////////////////////
00409 //     Function: CurveFitter::make_nurbs
00410 //       Access: Public
00411 //  Description: Converts the current set of data points into a
00412 //               NURBS curve.  This gives a smoother curve than
00413 //               produced by MakeHermite().
00414 ////////////////////////////////////////////////////////////////////
00415 PT(ParametricCurveCollection) CurveFitter::
00416 make_nurbs() const {
00417   // We start with the HermiteCurves produced above, then convert them
00418   // to NURBS form.
00419   PT(ParametricCurveCollection) hermites = make_hermite();
00420   PT(ParametricCurveCollection) result = new ParametricCurveCollection;
00421 
00422   int num_curves = hermites->get_num_curves();
00423   for (int c = 0; c < num_curves; c++) {
00424     ClassicNurbsCurve *nc = new ClassicNurbsCurve(*hermites->get_curve(c));
00425     result->add_curve(nc);
00426 
00427     // Now we even out the knots to smooth out the curve and make
00428     // everything c2 continuous.
00429 
00430     int num_knots = nc->get_num_knots();
00431 
00432     // We expect this to be a 4th order curve, since we just converted
00433     // it from a Hermite.
00434     assert(nc->get_order() == 4);
00435     assert(num_knots > 0);
00436 
00437     // Now the knot sequence goes something like this:
00438     //    0 0 0 0 1 1 1 2 2 2 3 3 3 4 4 4 4
00439 
00440     // We'll consider pairs of knot values beginning at position 3 and
00441     // every third position thereafter.  We just even out these values
00442     // between their two neighbors.
00443 
00444     int i;
00445     float k1, k2 = nc->get_knot(num_knots-1);
00446     const float one_third = 1.0f/3.0f;
00447     for (i = 3; i < num_knots - 4; i += 3) {
00448       k1 = nc->get_knot(i-1);
00449       k2 = nc->get_knot(i+2);
00450       nc->set_knot(i, (k1 + k1 + k2) * one_third);
00451       nc->set_knot(i+1, (k1 + k2 + k2) * one_third);
00452     }
00453 
00454     // The last knot must have the terminal value.
00455     nc->set_knot(num_knots-4, k2);
00456 
00457     // Finally, recompute the curve.
00458     nc->recompute();
00459   }
00460 
00461   return result;
00462 }
00463 
00464 ////////////////////////////////////////////////////////////////////
00465 //     Function: CurveFitter::output
00466 //       Access: Public
00467 //  Description:
00468 ////////////////////////////////////////////////////////////////////
00469 void CurveFitter::
00470 output(ostream &out) const {
00471   out << "CurveFitter, " << _data.size() << " samples.\n";
00472 }
00473 
00474 ////////////////////////////////////////////////////////////////////
00475 //     Function: CurveFitter::write
00476 //       Access: Public
00477 //  Description:
00478 ////////////////////////////////////////////////////////////////////
00479 void CurveFitter::
00480 write(ostream &out) const {
00481   out << "CurveFitter, " << _data.size() << " samples:\n";
00482   Data::const_iterator di;
00483   for (di = _data.begin(); di != _data.end(); ++di) {
00484     out << "  " << (*di) << "\n";
00485   }
00486 }
00487 

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