00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 #include "nurbsPPCurve.h"
00020 #include "config_parametrics.h"
00021 
00022 #include <indent.h>
00023 
00024 
00025 TypeHandle NurbsPPCurve::_type_handle;
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 NurbsPPCurve::
00034 NurbsPPCurve() {
00035   _nurbs_valid = false;
00036   _order = 4;
00037 }
00038 
00039 
00040 
00041 
00042 
00043 
00044 
00045 NurbsPPCurve::
00046 NurbsPPCurve(const ParametricCurve &pc) {
00047   _nurbs_valid = false;
00048   _order = 4;
00049 
00050   if (!pc.convert_to_nurbs(this)) {
00051     parametrics_cat->warning()
00052       << "Cannot make a NURBS from the indicated curve.\n";
00053   }
00054 }
00055 
00056 
00057 
00058 
00059 
00060 
00061 
00062 NurbsPPCurve::
00063 NurbsPPCurve(int order, int num_cvs,
00064              const float knots[], const LVecBase4f cvs[]) {
00065   _nurbs_valid = false;
00066   _order = order;
00067 
00068   _points = Points(cvs, cvs + num_cvs);
00069   _knots = Knots(knots, knots + num_cvs + _order);
00070 }
00071 
00072 
00073 
00074 
00075 
00076 
00077 NurbsPPCurve::
00078 ~NurbsPPCurve() {
00079 }
00080 
00081 
00082 
00083 
00084 
00085 
00086 
00087 
00088 float NurbsPPCurve::
00089 get_max_t() const {
00090   if (_nurbs_valid) {
00091     return _nurbs.maxKnot();
00092 
00093   } else {
00094     if (_knots.empty()) {
00095       return 0.0f;
00096     } else {
00097       return _knots.back();
00098     }
00099   }
00100 }
00101 
00102 
00103 
00104 
00105 
00106 
00107 
00108 void NurbsPPCurve::
00109 set_order(int order) {
00110   nassertv(order >= 1 && order <= 4);
00111   nassertv(!_nurbs_valid && _points.empty());
00112 
00113   _order = order;
00114 }
00115 
00116 
00117 
00118 
00119 
00120 
00121 
00122 int NurbsPPCurve::
00123 get_order() const {
00124   if (_nurbs_valid) {
00125     return _nurbs.degree() + 1;
00126   } else {
00127     return _order;
00128   }
00129 }
00130 
00131 
00132 
00133 
00134 
00135 
00136 
00137 int NurbsPPCurve::
00138 get_num_cvs() const {
00139   if (_nurbs_valid) {
00140     return _nurbs.ctrlPnts().size();
00141   } else {
00142     return _points.size();
00143   }
00144 }
00145 
00146 
00147 
00148 
00149 
00150 
00151 int NurbsPPCurve::
00152 get_num_knots() const {
00153   if (_nurbs_valid) {
00154     return _nurbs.knot().size();
00155   } else {
00156     return _knots.size();
00157   }
00158 }
00159 
00160 
00161 
00162 
00163 
00164 
00165 
00166 
00167 
00168 
00169 
00170 
00171 bool NurbsPPCurve::
00172 insert_cv(float t) {
00173   if (!make_nurbs_valid()) {
00174     return false;
00175   }
00176 
00177   PLib::NurbsCurvef result;
00178   _nurbs.knotInsertion(t, 1, result);
00179   _nurbs = result;
00180   return true;
00181 }
00182 
00183 
00184 
00185 
00186 
00187 
00188 
00189 
00190 bool NurbsPPCurve::
00191 remove_cv(int n) {
00192   if (_nurbs_valid) {
00193     _nurbs.removeKnot(n + _order, 1, 1);
00194 
00195   } else {
00196     if (n < 0 || n >= (int)_points.size()) {
00197       return false;
00198     }
00199 
00200     _points.erase(_points.begin() + n);
00201     if (_points.empty()) {
00202       _knots.clear();
00203     } else {
00204       _knots.erase(_knots.begin() + _order + n);
00205     }
00206   }
00207   return true;
00208 }
00209 
00210 
00211 
00212 
00213 
00214 
00215 void NurbsPPCurve::
00216 remove_all_cvs() {
00217   _nurbs_valid = false;
00218   _points.clear();
00219   _knots.clear();
00220 }
00221 
00222 
00223 
00224 
00225 
00226 
00227 
00228 
00229 bool NurbsPPCurve::
00230 set_cv(int n, const LVecBase4f &v) {
00231   nassertr(n >= 0 && n < get_num_cvs(), false);
00232 
00233   if (_nurbs_valid) {
00234     _nurbs.modCP(n, PLib::HPoint3Df(v[0], v[1], v[2], v[3]));
00235   } else {
00236     _points[n] = v;
00237   }
00238   return true;
00239 }
00240 
00241 
00242 
00243 
00244 
00245 
00246 
00247 LVecBase4f NurbsPPCurve::
00248 get_cv(int n) const {
00249   nassertr(n >= 0 && n < get_num_cvs(), LVecBase4f::zero());
00250 
00251   if (_nurbs_valid) {
00252     PLib::HPoint3Df p = _nurbs.ctrlPnts(n);
00253     return LVecBase4f(p.x(), p.y(), p.z(), p.w());
00254   } else {
00255     return _points[n];
00256   }
00257 }
00258 
00259 
00260 
00261 
00262 
00263 
00264 bool NurbsPPCurve::
00265 set_knot(int n, float t) {
00266   nassertr(n >= 0 && n < get_num_knots(), false);
00267 
00268   make_arrays_valid();
00269   nassertr(n >= 0 && n < (int)_knots.size(), false);
00270   _knots[n] = t;
00271 
00272   return true;
00273 }
00274 
00275 
00276 
00277 
00278 
00279 
00280 float NurbsPPCurve::
00281 get_knot(int n) const {
00282   nassertr(n >= 0 && n < get_num_knots(), 0.0f);
00283 
00284   if (_nurbs_valid) {
00285     return _nurbs.knot(n);
00286   } else {
00287     nassertr(n >= 0 && n < (int)_knots.size(), 0.0f);
00288     return _knots[n];
00289   }
00290 }
00291 
00292 
00293 
00294 
00295 
00296 
00297 
00298 
00299 
00300 
00301 
00302 bool NurbsPPCurve::
00303 recompute() {
00304   return make_nurbs_valid();
00305 }
00306 
00307 
00308 
00309 
00310 
00311 
00312 
00313 
00314 
00315 
00316 bool NurbsPPCurve::
00317 get_point(float t, LVecBase3f &point) const {
00318   nassertr(_nurbs_valid, false);
00319 
00320   bool in_range = true;
00321   float max_t = get_max_t();
00322 
00323   if (t < 0.0f) {
00324     t = 0.0f;
00325     in_range = false;
00326 
00327   } else if (t > max_t) {
00328     t = max_t;
00329     in_range = false;
00330   }
00331 
00332   PLib::Point3Df p = Cp(t, _nurbs);
00333   point.set(p.x(), p.y(), p.z());
00334   return in_range;
00335 }
00336 
00337 
00338 
00339 
00340 
00341 
00342 
00343 
00344 
00345 
00346 bool NurbsPPCurve::
00347 get_tangent(float t, LVecBase3f &tangent) const {
00348   nassertr(_nurbs_valid, false);
00349 
00350   bool in_range = true;
00351   float max_t = get_max_t();
00352 
00353   if (t < 0.0f) {
00354     t = 0.0f;
00355     in_range = false;
00356 
00357   } else if (t > max_t) {
00358     t = max_t;
00359     in_range = false;
00360   }
00361 
00362   PLib::Point3Df p = _nurbs.derive3D(t, 1);
00363   tangent.set(p.x(), p.y(), p.z());
00364   return in_range;
00365 }
00366 
00367 
00368 
00369 
00370 
00371 
00372 
00373 bool NurbsPPCurve::
00374 get_pt(float t, LVecBase3f &point, LVecBase3f &tangent) const {
00375   nassertr(_nurbs_valid, false);
00376 
00377   bool in_range = true;
00378   float max_t = get_max_t();
00379 
00380   if (t < 0.0f) {
00381     t = 0.0f;
00382     in_range = false;
00383 
00384   } else if (t > max_t) {
00385     t = max_t;
00386     in_range = false;
00387   }
00388 
00389   PLib::Point3Df p = Cp(t, _nurbs);
00390   point.set(p.x(), p.y(), p.z());
00391   p = _nurbs.derive3D(t, 1);
00392   tangent.set(p.x(), p.y(), p.z());
00393   return in_range;
00394 }
00395 
00396 
00397 
00398 
00399 
00400 
00401 
00402 
00403 
00404 
00405 
00406 bool NurbsPPCurve::
00407 get_2ndtangent(float t, LVecBase3f &tangent2) const {
00408   nassertr(_nurbs_valid, false);
00409 
00410   bool in_range = true;
00411   float max_t = get_max_t();
00412 
00413   if (t < 0.0f) {
00414     t = 0.0f;
00415     in_range = false;
00416 
00417   } else if (t > max_t) {
00418     t = max_t;
00419     in_range = false;
00420   }
00421 
00422   PLib::Point3Df p = _nurbs.derive3D(t, 2);
00423   tangent2.set(p.x(), p.y(), p.z());
00424   return in_range;
00425 }
00426 
00427 
00428 
00429 
00430 
00431 
00432 
00433 
00434 
00435 
00436 
00437 bool NurbsPPCurve::
00438 stitch(const ParametricCurve *a, const ParametricCurve *b) {
00439   
00440   
00441   
00442   PT(NurbsPPCurve) na = new NurbsPPCurve(*a);
00443   PT(NurbsPPCurve) nb = new NurbsPPCurve(*b);
00444 
00445   if (na->get_num_cvs() == 0 || nb->get_num_cvs() == 0) {
00446     return false;
00447   }
00448 
00449   if (!na->make_nurbs_valid()) {
00450     return false;
00451   }
00452 
00453   
00454   
00455   LVecBase3f point_offset =
00456     na->get_cv_point(na->get_num_cvs() - 1) - nb->get_cv_point(0);
00457   int num_b_cvs = nb->get_num_cvs();
00458   for (int i = 0; i < num_b_cvs; i++) {
00459     nb->set_cv_point(i, nb->get_cv_point(i) + point_offset);
00460   }
00461 
00462   
00463   
00464   Points b_points;
00465   Knots b_knots;
00466   int b_order;
00467   nb->copy_arrays(b_points, b_knots, b_order);
00468   nassertr(!b_knots.empty(), false)
00469 
00470   float knot_offset = na->get_max_t() - b_knots.front();
00471   Knots::iterator ki;
00472   for (ki = b_knots.begin(); ki != b_knots.end(); ++ki) {
00473     (*ki) += knot_offset;
00474   }
00475 
00476   
00477   PLib::NurbsCurvef b_nurbs;
00478   if (!make_nurbs_from(b_nurbs, b_points, b_knots, b_order)) {
00479     return false;
00480   }
00481 
00482   PLib::NurbsCurvef result;
00483   if (!result.mergeOf(na->_nurbs, b_nurbs)) {
00484     return false;
00485   }
00486 
00487   _nurbs = result;
00488   _nurbs_valid = true;
00489   return true;
00490 }
00491 
00492 
00493 
00494 
00495 
00496 
00497 
00498 
00499 NurbsCurveInterface *NurbsPPCurve::
00500 get_nurbs_interface() {
00501   return this;
00502 }
00503 
00504 
00505 
00506 
00507 
00508 
00509 
00510 
00511 bool NurbsPPCurve::
00512 convert_to_nurbs(ParametricCurve *nc) const {
00513   nc->set_curve_type(_curve_type);
00514   return NurbsCurveInterface::convert_to_nurbs(nc);
00515 }
00516 
00517 
00518 
00519 
00520 
00521 
00522 void NurbsPPCurve::
00523 write(ostream &out, int indent_level) const {
00524   NurbsCurveInterface::write(out, indent_level);
00525 }
00526 
00527 
00528 
00529 
00530 
00531 
00532 
00533 
00534 int NurbsPPCurve::
00535 append_cv_impl(const LVecBase4f &cv) {
00536   make_arrays_valid();
00537 
00538   _points.push_back(cv);
00539 
00540   if (_knots.empty()) {
00541     for (int i = 0; i < _order; i++) {
00542       _knots.push_back(0.0f);
00543     }
00544     _knots.push_back(1.0f);
00545   } else {
00546     _knots.push_back(_knots.back() + 1.0f);
00547   }
00548 
00549   return _points.size() - 1;
00550 }
00551 
00552 
00553 
00554 
00555 
00556 
00557 
00558 
00559 bool NurbsPPCurve::
00560 format_egg(ostream &out, const string &name, const string &curve_type,
00561            int indent_level) const {
00562   return NurbsCurveInterface::format_egg(out, name, curve_type, indent_level);
00563 }
00564 
00565 
00566 
00567 
00568 
00569 
00570 
00571 
00572 bool NurbsPPCurve::
00573 make_nurbs_valid() {
00574   if (_nurbs_valid) {
00575     return true;
00576   }
00577 
00578   if (!make_nurbs_from(_nurbs, _points, _knots, _order)) {
00579     return false;
00580   }
00581 
00582   _nurbs_valid = true;
00583   _points.clear();
00584   _knots.clear();
00585   return true;
00586 }
00587 
00588 
00589 
00590 
00591 
00592 
00593 
00594 void NurbsPPCurve::
00595 make_arrays_valid() {
00596   if (!_nurbs_valid) {
00597     return;
00598   }
00599 
00600   make_arrays_from(_nurbs, _points, _knots, _order);
00601 
00602   _nurbs_valid = false;
00603   _nurbs = PLib::NurbsCurvef();
00604 }
00605 
00606 
00607 
00608 
00609 
00610 
00611 
00612 bool NurbsPPCurve::
00613 copy_nurbs(PLib::NurbsCurvef &nurbs) const {
00614   if (_nurbs_valid) {
00615     nurbs = _nurbs;
00616     return true;
00617   } else {
00618     return make_nurbs_from(nurbs, _points, _knots, _order);
00619   }
00620 }
00621 
00622 
00623 
00624 
00625 
00626 
00627 void NurbsPPCurve::
00628 copy_arrays(NurbsPPCurve::Points &points, NurbsPPCurve::Knots &knots,
00629             int &order) const {
00630   if (_nurbs_valid) {
00631     make_arrays_from(_nurbs, points, knots, order);
00632   } else {
00633     points = _points;
00634     knots = _knots;
00635     order = _order;
00636   }
00637 }
00638 
00639 
00640 
00641 
00642 
00643 
00644 
00645 bool NurbsPPCurve::
00646 make_nurbs_from(PLib::NurbsCurvef &nurbs,
00647                 const NurbsPPCurve::Points &points,
00648                 const NurbsPPCurve::Knots &knots, int order) {
00649   if (order < 1 || knots.size() != points.size() + order) {
00650     parametrics_cat.error()
00651       << "Invalid NURBS curve: order " << order << " with "
00652       << points.size() << " CV's and " << knots.size() << " knots.\n";
00653     nassertr(false, false);
00654     return false;
00655   }
00656 
00657   Vector_HPoint3Df v_points(points.size());
00658   Vector_FLOAT v_knots(knots.size());
00659 
00660   size_t i;
00661   for (i = 0; i < points.size(); i++) {
00662     const LVecBase4f &p = points[i];
00663     v_points[i] = PLib::HPoint3Df(p[0], p[1], p[2], p[3]);
00664   }
00665   for (i = 0; i < knots.size(); i++) {
00666     v_knots[i] = knots[i];
00667   }
00668 
00669   nassertr(v_knots.size() == v_points.size() + order, false);
00670 
00671   nurbs.reset(v_points, v_knots, order - 1);
00672   return true;
00673 }
00674 
00675 
00676 
00677 
00678 
00679 
00680 void NurbsPPCurve::
00681 make_arrays_from(const PLib::NurbsCurvef &nurbs,
00682                  NurbsPPCurve::Points &points,
00683                  NurbsPPCurve::Knots &knots, int &order) {
00684   const Vector_HPoint3Df &v_points = nurbs.ctrlPnts();
00685   const Vector_FLOAT &v_knots = nurbs.knot();
00686 
00687   points.clear();
00688   knots.clear();
00689 
00690   points.reserve(v_points.size());
00691   knots.reserve(v_knots.size());
00692 
00693   Vector_HPoint3Df::const_iterator pi;
00694   for (pi = v_points.begin(); pi != v_points.end(); ++pi) {
00695     const PLib::HPoint3Df &p = (*pi);
00696     points.push_back(LVecBase4f(p.x(), p.y(), p.z(), p.w()));
00697   }
00698   Vector_FLOAT::const_iterator ki;
00699   for (ki = v_knots.begin(); ki != v_knots.end(); ++ki) {
00700     knots.push_back(*ki);
00701   }
00702 
00703   order = nurbs.degree() + 1;
00704 }