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 }