Panda3D
 All Classes Functions Variables Enumerations
nurbsCurve.cxx
00001 // Filename: nurbsCurve.cxx
00002 // Created by:  drose (27Feb98)
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 "nurbsCurve.h"
00016 #include "config_parametrics.h"
00017 
00018 #include "indent.h"
00019 #include "datagram.h"
00020 #include "datagramIterator.h"
00021 #include "bamWriter.h"
00022 #include "bamReader.h"
00023 
00024 TypeHandle NurbsCurve::_type_handle;
00025 
00026 
00027 ////////////////////////////////////////////////////////////////////
00028 //     Function: NurbsCurve::Constructor
00029 //       Access: Published
00030 //  Description:
00031 ////////////////////////////////////////////////////////////////////
00032 NurbsCurve::
00033 NurbsCurve() {
00034   _order = 4;
00035 }
00036 
00037 ////////////////////////////////////////////////////////////////////
00038 //     Function: NurbsCurve::Copy Constructor
00039 //       Access: Published
00040 //  Description: Constructs a NURBS curve equivalent to the indicated
00041 //               (possibly non-NURBS) curve.
00042 ////////////////////////////////////////////////////////////////////
00043 NurbsCurve::
00044 NurbsCurve(const ParametricCurve &pc) {
00045   _order = 4;
00046 
00047   if (!pc.convert_to_nurbs(this)) {
00048     parametrics_cat->warning()
00049       << "Cannot make a NURBS from the indicated curve.\n";
00050   }
00051 }
00052 
00053 ////////////////////////////////////////////////////////////////////
00054 //     Function: NurbsCurve::Constructor
00055 //       Access: Published
00056 //  Description: Constructs a NURBS curve according to the indicated
00057 //               NURBS parameters.
00058 ////////////////////////////////////////////////////////////////////
00059 NurbsCurve::
00060 NurbsCurve(int order, int num_cvs,
00061            const PN_stdfloat knots[], const LVecBase4 cvs[]) {
00062   _order = order;
00063 
00064   int i;
00065   _cvs.reserve(num_cvs);
00066   for (i = 0; i < num_cvs; i++) {
00067     append_cv(cvs[i]);
00068   }
00069 
00070   int num_knots = num_cvs + order;
00071   for (i = 0; i < num_knots; i++) {
00072     set_knot(i, knots[i]);
00073   }
00074 
00075   recompute();
00076 }
00077 
00078 ////////////////////////////////////////////////////////////////////
00079 //     Function: NurbsCurve::Destructor
00080 //       Access: Published, Virtual
00081 //  Description:
00082 ////////////////////////////////////////////////////////////////////
00083 NurbsCurve::
00084 ~NurbsCurve() {
00085 }
00086 
00087 ////////////////////////////////////////////////////////////////////
00088 //     Function: NurbsCurve::make_copy
00089 //       Access: Public, Virtual
00090 //  Description: Returns a newly-allocated PandaNode that is a shallow
00091 //               copy of this one.  It will be a different pointer,
00092 //               but its internal data may or may not be shared with
00093 //               that of the original PandaNode.  No children will be
00094 //               copied.
00095 ////////////////////////////////////////////////////////////////////
00096 PandaNode *NurbsCurve::
00097 make_copy() const {
00098   return new NurbsCurve(*this);
00099 }
00100 
00101 ////////////////////////////////////////////////////////////////////
00102 //     Function: NurbsCurve::set_order
00103 //       Access: Published, Virtual
00104 //  Description: Changes the order of the curve.  Must be a value from
00105 //               1 to 4.  Can only be done when there are no cv's.
00106 ////////////////////////////////////////////////////////////////////
00107 void NurbsCurve::
00108 set_order(int order) {
00109   nassertv(order >= 1 && order <= 4);
00110   nassertv(_cvs.empty());
00111 
00112   _order = order;
00113 }
00114 
00115 ////////////////////////////////////////////////////////////////////
00116 //     Function: NurbsCurve::get_order
00117 //       Access: Published, Virtual
00118 //  Description:
00119 ////////////////////////////////////////////////////////////////////
00120 int NurbsCurve::
00121 get_order() const {
00122   return _order;
00123 }
00124 
00125 ////////////////////////////////////////////////////////////////////
00126 //     Function: NurbsCurve::get_num_cvs
00127 //       Access: Published, Virtual
00128 //  Description:
00129 ////////////////////////////////////////////////////////////////////
00130 int NurbsCurve::
00131 get_num_cvs() const {
00132   return _cvs.size();
00133 }
00134 
00135 ////////////////////////////////////////////////////////////////////
00136 //     Function: NurbsCurve::get_num_knots
00137 //       Access: Published, Virtual
00138 //  Description: Returns the number of knots on the curve.
00139 ////////////////////////////////////////////////////////////////////
00140 int NurbsCurve::
00141 get_num_knots() const {
00142   return _cvs.size() + _order;
00143 }
00144 
00145 
00146 
00147 ////////////////////////////////////////////////////////////////////
00148 //     Function: NurbsCurve::insert_cv
00149 //       Access: Published, Virtual
00150 //  Description: Inserts a new CV into the middle of the curve at the
00151 //               indicated parametric value.  This doesn't change the
00152 //               shape or timing of the curve; however, it is
00153 //               irreversible: if the new CV is immediately removed,
00154 //               the curve will be changed.  Returns true if
00155 //               successful, false otherwise.
00156 ////////////////////////////////////////////////////////////////////
00157 bool NurbsCurve::
00158 insert_cv(PN_stdfloat t) {
00159   if (_cvs.empty()) {
00160     append_cv(0.0f, 0.0f, 0.0f);
00161     return true;
00162   }
00163 
00164   if (t <= 0) {
00165     t = 0.0f;
00166   }
00167 
00168   int k = find_cv(t);
00169   if (k < 0) {
00170     append_cv(_cvs.back()._p);
00171     return true;
00172   }
00173 
00174   // Now we are inserting a knot between k-1 and k.  We'll adjust the
00175   // CV's according to Bohm's rule.
00176 
00177   // First, get the new values of all the CV's that will change.
00178   // These are the CV's in the range [k - (_order-1), k-1].
00179 
00180   LVecBase4 new_cvs[3];
00181   int i;
00182   for (i = 0; i < _order-1; i++) {
00183     int nk = i + k - (_order-1);
00184     PN_stdfloat ti = get_knot(nk);
00185     PN_stdfloat d = get_knot(nk + _order-1) - ti;
00186     if (d == 0.0f) {
00187       new_cvs[i] = _cvs[nk-1]._p;
00188     } else {
00189       PN_stdfloat a = (t - ti) / d;
00190       new_cvs[i] = (1.0f-a)*_cvs[nk-1]._p + a*_cvs[nk]._p;
00191     }
00192   }
00193 
00194   // Now insert the new CV
00195   _cvs.insert(_cvs.begin() + k-1, CV());
00196 
00197   // Set all the new position values
00198   for (i = 0; i < _order-1; i++) {
00199     int nk = i + k - (_order-1);
00200     _cvs[nk]._p = new_cvs[i];
00201   }
00202 
00203   // And set the new knot value.
00204   _cvs[k-1]._t = t;
00205 
00206   return true;
00207 }
00208 
00209 ////////////////////////////////////////////////////////////////////
00210 //     Function: NurbsCurve::remove_cv
00211 //       Access: Published, Virtual
00212 //  Description: Removes the indicated CV from the curve.  Returns
00213 //               true if the CV index was valid, false otherwise.
00214 ////////////////////////////////////////////////////////////////////
00215 bool NurbsCurve::
00216 remove_cv(int n) {
00217   if (n < 0 || n >= (int)_cvs.size()) {
00218     return false;
00219   }
00220 
00221   _cvs.erase(_cvs.begin() + n);
00222   return true;
00223 }
00224 
00225 ////////////////////////////////////////////////////////////////////
00226 //     Function: NurbsCurve::remove_all_cvs
00227 //       Access: Published, Virtual
00228 //  Description: Removes all CV's from the curve.
00229 ////////////////////////////////////////////////////////////////////
00230 void NurbsCurve::
00231 remove_all_cvs() {
00232   _cvs.erase(_cvs.begin(), _cvs.end());
00233 }
00234 
00235 
00236 ////////////////////////////////////////////////////////////////////
00237 //     Function: NurbsCurve::set_cv
00238 //       Access: Published, Virtual
00239 //  Description: Repositions the indicated CV.  Returns true if
00240 //               successful, false otherwise.
00241 ////////////////////////////////////////////////////////////////////
00242 bool NurbsCurve::
00243 set_cv(int n, const LVecBase4 &v) {
00244   nassertr(n >= 0 && n < get_num_cvs(), false);
00245 
00246   _cvs[n]._p = v;
00247   return true;
00248 }
00249 
00250 ////////////////////////////////////////////////////////////////////
00251 //     Function: NurbsCurve::get_cv
00252 //       Access: Published, Virtual
00253 //  Description: Returns the position in homogeneous space of the
00254 //               indicated CV.
00255 ////////////////////////////////////////////////////////////////////
00256 LVecBase4 NurbsCurve::
00257 get_cv(int n) const {
00258   nassertr(n >= 0 && n < get_num_cvs(), LVecBase4::zero());
00259 
00260   return _cvs[n]._p;
00261 }
00262 
00263 
00264 ////////////////////////////////////////////////////////////////////
00265 //     Function: NurbsCurve::set_knot
00266 //       Access: Published, Virtual
00267 //  Description: Sets the value of the indicated knot.  There are
00268 //               get_num_cvs() + _order knot values, but the first
00269 //               _order - 1 and the last 1 knot values cannot be
00270 //               changed.  It is also an error to set a knot value
00271 //               outside the range of its neighbors.
00272 ////////////////////////////////////////////////////////////////////
00273 bool NurbsCurve::
00274 set_knot(int n, PN_stdfloat t) {
00275   nassertr(n >= 0 && n < get_num_knots(), false);
00276 
00277   if (n < _order || n-1 >= (int)_cvs.size()) {
00278     return false;
00279   }
00280   _cvs[n-1]._t = t;
00281   return true;
00282 }
00283 
00284 ////////////////////////////////////////////////////////////////////
00285 //     Function: NurbsCurve::get_knot
00286 //       Access: Published, Virtual
00287 //  Description: Retrieves the value of the indicated knot.
00288 ////////////////////////////////////////////////////////////////////
00289 PN_stdfloat NurbsCurve::
00290 get_knot(int n) const {
00291   if (n < _order || _cvs.empty()) {
00292     return 0.0f;
00293   } else if (n-1 >= (int)_cvs.size()) {
00294     return _cvs.back()._t;
00295   } else {
00296     return _cvs[n-1]._t;
00297   }
00298 }
00299 
00300 
00301 ////////////////////////////////////////////////////////////////////
00302 //     Function: NurbsCurve::recompute
00303 //       Access: Published, Virtual
00304 //  Description: Recalculates the curve basis according to the latest
00305 //               position of the CV's, knots, etc.  Until this
00306 //               function is called, adjusting the NURBS parameters
00307 //               will have no visible effect on the curve.  Returns
00308 //               true if the resulting curve is valid, false
00309 //               otherwise.
00310 ////////////////////////////////////////////////////////////////////
00311 bool NurbsCurve::
00312 recompute() {
00313   _segs.erase(_segs.begin(), _segs.end());
00314 
00315   PN_stdfloat knots[8];
00316   LVecBase4 cvs[4];
00317 
00318   if ((int)_cvs.size() > _order-1) {
00319     for (int cv = 0; cv < (int)_cvs.size()-(_order-1); cv++) {
00320       if (get_knot(cv+_order-1) < get_knot(cv+_order)) {
00321         // There are _order consecutive CV's that define each segment,
00322         // beginning at cv.  Collect the CV's and knot values that define
00323         // this segment.
00324         int c;
00325         for (c = 0; c < _order; c++) {
00326           cvs[c] = _cvs[c+cv]._p;
00327         }
00328         for (c = 0; c < _order+_order; c++) {
00329           knots[c] = get_knot(c+cv);
00330         }
00331 
00332         insert_curveseg(_segs.size(), new CubicCurveseg(_order, knots, cvs),
00333                         knots[_order] - knots[_order-1]);
00334       }
00335     }
00336   }
00337 
00338   return !_segs.empty();
00339 }
00340 
00341 ////////////////////////////////////////////////////////////////////
00342 //     Function: NurbsCurve::rebuild_curveseg
00343 //       Access: Public, Virtual
00344 //  Description: Rebuilds the current curve segment (as selected by
00345 //               the most recent call to find_curve()) according to
00346 //               the specified properties (see
00347 //               CubicCurveseg::compute_seg).  Returns true if
00348 //               possible, false if something goes horribly wrong.
00349 ////////////////////////////////////////////////////////////////////
00350 bool NurbsCurve::
00351 rebuild_curveseg(int rtype0, PN_stdfloat t0, const LVecBase4 &v0,
00352                  int rtype1, PN_stdfloat t1, const LVecBase4 &v1,
00353                  int rtype2, PN_stdfloat t2, const LVecBase4 &v2,
00354                  int rtype3, PN_stdfloat t3, const LVecBase4 &v3) {
00355   // Figure out which CV's contributed to this segment.
00356   int seg = 0;
00357 
00358   nassertr((int)_cvs.size() > _order-1, false);
00359 
00360   int cv = 0;
00361   for (cv = 0; cv < (int)_cvs.size()-(_order-1); cv++) {
00362     if (get_knot(cv+_order-1) < get_knot(cv+_order)) {
00363       if (seg == _last_ti) {
00364         break;
00365       }
00366       seg++;
00367     }
00368   }
00369 
00370   // Now copy the cvs and knots in question.
00371   LMatrix4 G;
00372   PN_stdfloat knots[8];
00373 
00374   int c;
00375 
00376   // We only need to build the geometry matrix if at least one of the
00377   // properties depends on the original value.
00378   if ((rtype0 | rtype1 | rtype2 | rtype3) & RT_KEEP_ORIG) {
00379     for (c = 0; c < 4; c++) {
00380       const LVecBase4 &s = (c < _order) ? _cvs[c+cv]._p : LVecBase4::zero();
00381 
00382       G.set_col(c, s);
00383     }
00384   }
00385 
00386   // But we always need the knot vector to determine the basis matrix.
00387   for (c = 0; c < _order+_order; c++) {
00388     knots[c] = get_knot(c+cv);
00389   }
00390 
00391   LMatrix4 B;
00392   compute_nurbs_basis(_order, knots, B);
00393 
00394   LMatrix4 Bi;
00395   Bi = invert(B);
00396 
00397   if (!CubicCurveseg::compute_seg(rtype0, t0, v0,
00398                                   rtype1, t1, v1,
00399                                   rtype2, t2, v2,
00400                                   rtype3, t3, v3,
00401                                   B, Bi, G)) {
00402     return false;
00403   }
00404 
00405   // Now extract the new CV's from the new G matrix, and restore them
00406   // to the curve.
00407   for (c = 0; c < _order; c++) {
00408     _cvs[c+cv]._p = G.get_col(c);
00409   }
00410 
00411   return true;
00412 }
00413 
00414 ////////////////////////////////////////////////////////////////////
00415 //     Function: NurbsCurve::stitch
00416 //       Access: Published, Virtual
00417 //  Description: Regenerates this curve as one long curve: the first
00418 //               curve connected end-to-end with the second one.
00419 //               Either a or b may be the same as 'this'.
00420 //
00421 //               Returns true if successful, false on failure or if
00422 //               the curve type does not support stitching.
00423 ////////////////////////////////////////////////////////////////////
00424 bool NurbsCurve::
00425 stitch(const ParametricCurve *a, const ParametricCurve *b) {
00426   // First, make a copy of both of our curves.  This ensures they are
00427   // of the correct type, and also protects us in case one of them is
00428   // the same as 'this'.
00429   PT(NurbsCurve) na = new NurbsCurve(*a);
00430   PT(NurbsCurve) nb = new NurbsCurve(*b);
00431 
00432   if (na->get_num_cvs() == 0 || nb->get_num_cvs() == 0) {
00433     return false;
00434   }
00435 
00436   if (na->get_order() != nb->get_order()) {
00437     parametrics_cat->error()
00438       << "Cannot stitch NURBS curves of different orders!\n";
00439     return false;
00440   }
00441 
00442   // First, translate curve B to move its first CV to curve A's last
00443   // CV.
00444   LVecBase3 point_offset =
00445     na->get_cv_point(na->get_num_cvs() - 1) - nb->get_cv_point(0);
00446   int num_b_cvs = nb->get_num_cvs();
00447   for (int i = 0; i < num_b_cvs; i++) {
00448     nb->set_cv_point(i, nb->get_cv_point(i) + point_offset);
00449   }
00450 
00451   // Now define a vector of all of A's CV's except the last one.
00452   _cvs = na->_cvs;
00453   if (!_cvs.empty()) {
00454     _cvs.pop_back();
00455   }
00456 
00457   PN_stdfloat t = na->get_max_t();
00458 
00459   // Now add all the new CV's.
00460   epvector<CV>::iterator ci;
00461   for (ci = nb->_cvs.begin(); ci != nb->_cvs.end(); ++ci) {
00462     CV new_cv = (*ci);
00463     new_cv._t += t;
00464     _cvs.push_back(new_cv);
00465   }
00466 
00467   recompute();
00468   return true;
00469 }
00470 
00471 
00472 ////////////////////////////////////////////////////////////////////
00473 //     Function: NurbsCurve::get_nurbs_interface
00474 //       Access: Public, Virtual
00475 //  Description: Returns a pointer to the object as a
00476 //               NurbsCurveInterface object if it happens to be a
00477 //               NURBS-style curve; otherwise, returns NULL.
00478 ////////////////////////////////////////////////////////////////////
00479 NurbsCurveInterface *NurbsCurve::
00480 get_nurbs_interface() {
00481   return this;
00482 }
00483 
00484 ////////////////////////////////////////////////////////////////////
00485 //     Function: NurbsCurve::convert_to_nurbs
00486 //       Access: Public, Virtual
00487 //  Description: Stores in the indicated NurbsCurve a NURBS
00488 //               representation of an equivalent curve.  Returns true
00489 //               if successful, false otherwise.
00490 ////////////////////////////////////////////////////////////////////
00491 bool NurbsCurve::
00492 convert_to_nurbs(ParametricCurve *nc) const {
00493   nc->set_curve_type(_curve_type);
00494   return NurbsCurveInterface::convert_to_nurbs(nc);
00495 }
00496 
00497 ////////////////////////////////////////////////////////////////////
00498 //     Function: NurbsCurve::write
00499 //       Access: Public, Virtual
00500 //  Description:
00501 ////////////////////////////////////////////////////////////////////
00502 void NurbsCurve::
00503 write(ostream &out, int indent_level) const {
00504   NurbsCurveInterface::write(out, indent_level);
00505 }
00506 
00507 ////////////////////////////////////////////////////////////////////
00508 //     Function: NurbsCurve::append_cv_impl
00509 //       Access: Protected, Virtual
00510 //  Description: Adds a new CV to the end of the curve.  Creates a new
00511 //               knot value by adding 1 to the last knot value.
00512 //               Returns the index of the new CV.
00513 ////////////////////////////////////////////////////////////////////
00514 int NurbsCurve::
00515 append_cv_impl(const LVecBase4 &v) {
00516   _cvs.push_back(CV(v, get_knot(_cvs.size())+1.0f));
00517   return _cvs.size()-1;
00518 }
00519 
00520 ////////////////////////////////////////////////////////////////////
00521 //     Function: NurbsCurve::format_egg
00522 //       Access: Protected, Virtual
00523 //  Description: Formats the curve as an egg structure to write to the
00524 //               indicated stream.  Returns true on success, false on
00525 //               failure.
00526 ////////////////////////////////////////////////////////////////////
00527 bool NurbsCurve::
00528 format_egg(ostream &out, const string &name, const string &curve_type,
00529            int indent_level) const {
00530   return NurbsCurveInterface::format_egg(out, name, curve_type, indent_level);
00531 }
00532 
00533 ////////////////////////////////////////////////////////////////////
00534 //     Function: NurbsCurve::find_cv
00535 //       Access: Protected
00536 //  Description: Finds the first knot whose value is >= t, or -1 if t
00537 //               is beyond the end of the curve.
00538 ////////////////////////////////////////////////////////////////////
00539 int NurbsCurve::
00540 find_cv(PN_stdfloat t) {
00541   int i;
00542   for (i = _order-1; i < (int)_cvs.size(); i++) {
00543     if (_cvs[i]._t >= t) {
00544       return i+1;
00545     }
00546   }
00547 
00548   return -1;
00549 }
00550 
00551 ////////////////////////////////////////////////////////////////////
00552 //     Function: NurbsCurve::register_with_read_factory
00553 //       Access: Public, Static
00554 //  Description: Initializes the factory for reading these things from
00555 //               Bam files.
00556 ////////////////////////////////////////////////////////////////////
00557 void NurbsCurve::
00558 register_with_read_factory() {
00559   BamReader::get_factory()->register_factory(get_class_type(), make_NurbsCurve);
00560 }
00561 
00562 ////////////////////////////////////////////////////////////////////
00563 //     Function: NurbsCurve::make_NurbsCurve
00564 //       Access: Protected
00565 //  Description: Factory method to generate an object of this type.
00566 ////////////////////////////////////////////////////////////////////
00567 TypedWritable *NurbsCurve::
00568 make_NurbsCurve(const FactoryParams &params) {
00569   NurbsCurve *me = new NurbsCurve;
00570   DatagramIterator scan;
00571   BamReader *manager;
00572 
00573   parse_params(params, scan, manager);
00574   me->fillin(scan, manager);
00575   return me;
00576 }
00577 
00578 ////////////////////////////////////////////////////////////////////
00579 //     Function: NurbsCurve::write_datagram
00580 //       Access: Protected, Virtual
00581 //  Description: Function to write the important information in
00582 //               the particular object to a Datagram
00583 ////////////////////////////////////////////////////////////////////
00584 void NurbsCurve::
00585 write_datagram(BamWriter *manager, Datagram &me) {
00586   PiecewiseCurve::write_datagram(manager, me);
00587 
00588   me.add_int8(_order);
00589 
00590   me.add_uint32(_cvs.size());
00591   size_t i;
00592   for (i = 0; i < _cvs.size(); i++) {
00593     const CV &cv = _cvs[i];
00594     cv._p.write_datagram(me);
00595     me.add_float64(cv._t);
00596   }
00597 }
00598 
00599 ////////////////////////////////////////////////////////////////////
00600 //     Function: NurbsCurve::fillin
00601 //       Access: Protected
00602 //  Description: Function that reads out of the datagram (or asks
00603 //               manager to read) all of the data that is needed to
00604 //               re-create this object and stores it in the appropiate
00605 //               place
00606 ////////////////////////////////////////////////////////////////////
00607 void NurbsCurve::
00608 fillin(DatagramIterator &scan, BamReader *manager) {
00609   PiecewiseCurve::fillin(scan, manager);
00610 
00611   _order = scan.get_int8();
00612 
00613   size_t num_cvs = scan.get_uint32();
00614 
00615   _cvs.reserve(num_cvs);
00616   size_t i;
00617   for (i = 0; i < num_cvs; i++) {
00618     CV cv;
00619     cv._p.read_datagram(scan);
00620     cv._t = scan.get_float64();
00621     _cvs.push_back(cv);
00622   }
00623 }
 All Classes Functions Variables Enumerations