Panda3D
|
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 ¶ms) { 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 }