00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "parametricCurve.h"
00016 #include "config_parametrics.h"
00017 #include "hermiteCurve.h"
00018 #include "nurbsCurve.h"
00019
00020 #include "datagram.h"
00021 #include "datagramIterator.h"
00022 #include "bamWriter.h"
00023 #include "bamReader.h"
00024 #include "omniBoundingVolume.h"
00025
00026 static const PN_stdfloat tolerance_divisor = 100000.0f;
00027
00028 TypeHandle ParametricCurve::_type_handle;
00029
00030
00031
00032
00033
00034
00035
00036
00037 ParametricCurve::
00038 ParametricCurve() : PandaNode("curve") {
00039 _curve_type = PCT_NONE;
00040 _num_dimensions = 3;
00041 }
00042
00043
00044
00045
00046
00047
00048 ParametricCurve::
00049 ~ParametricCurve() {
00050
00051
00052
00053
00054 nassertv(_drawers.empty());
00055 }
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066 bool ParametricCurve::
00067 safe_to_flatten() const {
00068 return false;
00069 }
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079 bool ParametricCurve::
00080 safe_to_transform() const {
00081 return false;
00082 }
00083
00084
00085
00086
00087
00088
00089
00090
00091 bool ParametricCurve::
00092 is_valid() const {
00093 return true;
00094 }
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106 PN_stdfloat ParametricCurve::
00107 get_max_t() const {
00108 return 1.0f;
00109 }
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127 void ParametricCurve::
00128 set_curve_type(int type) {
00129 _curve_type = type;
00130 switch (_curve_type) {
00131 case PCT_XYZ:
00132 case PCT_HPR:
00133 case PCT_NONE:
00134 _num_dimensions = 3;
00135 break;
00136
00137 case PCT_T:
00138 _num_dimensions = 1;
00139 break;
00140
00141 default:
00142 assert(0);
00143 }
00144 }
00145
00146
00147
00148
00149
00150
00151
00152 int ParametricCurve::
00153 get_curve_type() const {
00154 return _curve_type;
00155 }
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167 void ParametricCurve::
00168 set_num_dimensions(int num) {
00169 _num_dimensions = num;
00170 }
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181 int ParametricCurve::
00182 get_num_dimensions() const {
00183 return _num_dimensions;
00184 }
00185
00186
00187
00188
00189
00190
00191
00192
00193 PN_stdfloat ParametricCurve::
00194 calc_length() const {
00195 return calc_length(0.0f, get_max_t());
00196 }
00197
00198
00199
00200
00201
00202
00203
00204 PN_stdfloat ParametricCurve::
00205 calc_length(PN_stdfloat from, PN_stdfloat to) const {
00206 PN_stdfloat t1, t2;
00207 LPoint3 p1, p2;
00208
00209
00210
00211 PN_stdfloat to_minus_from = to - from;
00212
00213 if (to_minus_from < 0.0f) {
00214 PN_stdfloat temp = to;
00215 to = from;
00216 from = temp;
00217 to_minus_from=-to_minus_from;
00218 }
00219
00220
00221 int num_segs = (int)(to_minus_from) + 1;
00222 t2 = from;
00223 get_point(t2, p2);
00224 PN_stdfloat net = 0.0f;
00225
00226 for (int i = 1; i <= num_segs; i++) {
00227 t1 = t2;
00228 p1 = p2;
00229
00230 t2 = (to - from) * (PN_stdfloat)i / (PN_stdfloat)num_segs + from;
00231 get_point(t2, p2);
00232
00233 net += r_calc_length(t1, t2, p1, p2, (p1 - p2).length());
00234 }
00235 return net;
00236 }
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252 PN_stdfloat ParametricCurve::
00253 find_length(PN_stdfloat start_t, PN_stdfloat length_offset) const {
00254 nassertr(length_offset >= 0.0f, start_t);
00255 nassertr(start_t >= 0.0f && start_t <= get_max_t(), start_t);
00256
00257 PN_stdfloat t1, t2;
00258 LPoint3 p1, p2;
00259
00260
00261 PN_stdfloat max_t = get_max_t();
00262 int num_segs = (int)cfloor(max_t - start_t + 1);
00263 t2 = start_t;
00264 get_point(t2, p2);
00265 PN_stdfloat net = 0.0f;
00266
00267 for (int i = 1; i <= num_segs; i++) {
00268 assert(net <= length_offset);
00269
00270 t1 = t2;
00271 p1 = p2;
00272
00273 t2 = start_t + (((max_t - start_t) * (PN_stdfloat)i) / (PN_stdfloat)num_segs);
00274 get_point(t2, p2);
00275
00276 PN_stdfloat seglength = (p1 - p2).length();
00277 PN_stdfloat result;
00278
00279 if (r_find_length(length_offset - net, result,
00280 t1, t2, p1, p2, seglength)) {
00281
00282 return result;
00283 }
00284
00285 net += seglength;
00286 }
00287
00288
00289 return max_t;
00290 }
00291
00292
00293
00294
00295
00296
00297
00298
00299 bool ParametricCurve::
00300 adjust_point(PN_stdfloat, PN_stdfloat, PN_stdfloat, PN_stdfloat) {
00301 return false;
00302 }
00303
00304
00305
00306
00307
00308
00309
00310
00311 bool ParametricCurve::
00312 adjust_tangent(PN_stdfloat, PN_stdfloat, PN_stdfloat, PN_stdfloat) {
00313 return false;
00314 }
00315
00316
00317
00318
00319
00320
00321
00322 bool ParametricCurve::
00323 adjust_pt(PN_stdfloat, PN_stdfloat, PN_stdfloat, PN_stdfloat, PN_stdfloat, PN_stdfloat, PN_stdfloat) {
00324 return false;
00325 }
00326
00327
00328
00329
00330
00331
00332
00333
00334 bool ParametricCurve::
00335 recompute() {
00336 return is_valid();
00337 }
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349 bool ParametricCurve::
00350 stitch(const ParametricCurve *, const ParametricCurve *) {
00351 parametrics_cat.error()
00352 << get_type() << " does not support stitching.\n";
00353 return false;
00354 }
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364 bool ParametricCurve::
00365 write_egg(Filename filename, CoordinateSystem cs) {
00366 pofstream out;
00367 filename.set_text();
00368
00369 if (!filename.open_write(out)) {
00370 parametrics_cat.error()
00371 << "Unable to write to " << filename << "\n";
00372 return false;
00373 }
00374 return write_egg(out, filename, cs);
00375 }
00376
00377
00378
00379
00380
00381
00382
00383
00384 bool ParametricCurve::
00385 write_egg(ostream &out, const Filename &filename, CoordinateSystem cs) {
00386 string curve_type;
00387 switch (get_curve_type()) {
00388 case PCT_XYZ:
00389 curve_type = "xyz";
00390 break;
00391
00392 case PCT_HPR:
00393 curve_type = "hpr";
00394 break;
00395
00396 case PCT_T:
00397 curve_type = "t";
00398 break;
00399 }
00400
00401 if (!has_name()) {
00402
00403 string name = filename.get_basename_wo_extension();
00404
00405 if (!curve_type.empty()) {
00406 name += "_";
00407 name += curve_type;
00408 }
00409
00410 set_name(name);
00411 }
00412
00413 if (cs == CS_default) {
00414 cs = get_default_coordinate_system();
00415 }
00416
00417 if (cs != CS_invalid) {
00418 out << "<CoordinateSystem> { ";
00419 switch (cs) {
00420 case CS_zup_right:
00421 out << "Z-Up";
00422 break;
00423
00424 case CS_yup_right:
00425 out << "Y-Up";
00426 break;
00427
00428 case CS_zup_left:
00429 out << "Z-Up-Left";
00430 break;
00431
00432 case CS_yup_left:
00433 out << "Y-Up-Left";
00434 break;
00435
00436 default:
00437 break;
00438 }
00439 out << " }\n\n";
00440 }
00441
00442
00443 if (!format_egg(out, get_name(), curve_type, 0)) {
00444 return false;
00445 }
00446
00447 if (out) {
00448 return true;
00449 } else {
00450 return false;
00451 }
00452 }
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465 bool ParametricCurve::
00466 get_bezier_segs(ParametricCurve::BezierSegs &) const {
00467 return false;
00468 }
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478 bool ParametricCurve::
00479 get_bezier_seg(ParametricCurve::BezierSeg &) const {
00480 return false;
00481 }
00482
00483
00484
00485
00486
00487
00488
00489
00490 NurbsCurveInterface *ParametricCurve::
00491 get_nurbs_interface() {
00492 return (NurbsCurveInterface *)NULL;
00493 }
00494
00495
00496
00497
00498
00499
00500
00501
00502 bool ParametricCurve::
00503 convert_to_hermite(HermiteCurve *hc) const {
00504 BezierSegs bz_segs;
00505 if (!get_bezier_segs(bz_segs)) {
00506 return false;
00507 }
00508
00509 hc->set_curve_type(_curve_type);
00510
00511
00512
00513
00514 hc->remove_all_cvs();
00515
00516 int i, n;
00517 if (!bz_segs.empty()) {
00518 PN_stdfloat scale_in = 0.0f;
00519 PN_stdfloat scale_out = bz_segs[0]._t;
00520 n = hc->append_cv(HC_SMOOTH, bz_segs[0]._v[0]);
00521 hc->set_cv_out(n, 3.0f * (bz_segs[0]._v[1] - bz_segs[0]._v[0]) / scale_out);
00522
00523 for (i = 0; i < (int)bz_segs.size()-1; i++) {
00524 scale_in = scale_out;
00525 scale_out = bz_segs[i+1]._t - bz_segs[i]._t;
00526
00527 if (!bz_segs[i]._v[3].almost_equal(bz_segs[i+1]._v[0], 0.0001f)) {
00528
00529 hc->set_cv_type(n, HC_CUT);
00530 }
00531
00532 n = hc->append_cv(HC_FREE, bz_segs[i+1]._v[0]);
00533 hc->set_cv_in(n, 3.0f * (bz_segs[i]._v[3] - bz_segs[i]._v[2]) / scale_in);
00534 hc->set_cv_tstart(n, bz_segs[i]._t);
00535
00536 hc->set_cv_out(n, 3.0f * (bz_segs[i+1]._v[1] - bz_segs[i+1]._v[0]) / scale_out);
00537 }
00538
00539
00540 scale_in = scale_out;
00541 i = bz_segs.size()-1;
00542 n = hc->append_cv(HC_SMOOTH, bz_segs[i]._v[3]);
00543 hc->set_cv_in(n, 3.0f * (bz_segs[i]._v[3] - bz_segs[i]._v[2]) / scale_in);
00544 hc->set_cv_tstart(n, bz_segs[i]._t);
00545 }
00546
00547
00548 int num_cvs = hc->get_num_cvs();
00549 for (n = 1; n < num_cvs-1; n++) {
00550 if (hc->get_cv_type(n)!=HC_CUT) {
00551 LVector3 in = hc->get_cv_in(n);
00552 LVector3 out = hc->get_cv_out(n);
00553
00554 if (in.almost_equal(out, 0.0001f)) {
00555 hc->set_cv_type(n, HC_SMOOTH);
00556 } else {
00557 in.normalize();
00558 out.normalize();
00559 if (in.almost_equal(out, 0.0001f)) {
00560 hc->set_cv_type(n, HC_G1);
00561 }
00562 }
00563 }
00564 }
00565 return true;
00566 }
00567
00568
00569
00570
00571
00572
00573
00574
00575 bool ParametricCurve::
00576 convert_to_nurbs(ParametricCurve *nc) const {
00577 NurbsCurveInterface *nurbs = nc->get_nurbs_interface();
00578 nassertr(nurbs != (NurbsCurveInterface *)NULL, false);
00579
00580 BezierSegs bz_segs;
00581 if (!get_bezier_segs(bz_segs)) {
00582 return false;
00583 }
00584
00585 nc->set_curve_type(_curve_type);
00586
00587 nurbs->remove_all_cvs();
00588 nurbs->set_order(4);
00589 if (!bz_segs.empty()) {
00590 int i;
00591 for (i = 0; i < (int)bz_segs.size(); i++) {
00592 nurbs->append_cv(bz_segs[i]._v[0]);
00593 nurbs->append_cv(bz_segs[i]._v[1]);
00594 nurbs->append_cv(bz_segs[i]._v[2]);
00595 if (i == (int)bz_segs.size()-1 ||
00596 !bz_segs[i]._v[3].almost_equal(bz_segs[i+1]._v[0], 0.0001f)) {
00597 nurbs->append_cv(bz_segs[i]._v[3]);
00598 }
00599 }
00600
00601 PN_stdfloat t;
00602 int ki = 4;
00603 nurbs->set_knot(0, 0.0f);
00604 nurbs->set_knot(1, 0.0f);
00605 nurbs->set_knot(2, 0.0f);
00606 nurbs->set_knot(3, 0.0f);
00607
00608 for (i = 0; i < (int)bz_segs.size(); i++) {
00609 t = bz_segs[i]._t;
00610
00611 nurbs->set_knot(ki, t);
00612 nurbs->set_knot(ki+1, t);
00613 nurbs->set_knot(ki+2, t);
00614 ki += 3;
00615 if (i == ((int)bz_segs.size())-1 ||
00616 !bz_segs[i]._v[3].almost_equal(bz_segs[i+1]._v[0], 0.0001f)) {
00617 nurbs->set_knot(ki, t);
00618 ki++;
00619 }
00620 }
00621 }
00622
00623 return nc->recompute();
00624 }
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639 void ParametricCurve::
00640 register_drawer(ParametricCurveDrawer *drawer) {
00641 _drawers.push_back(drawer);
00642 }
00643
00644
00645
00646
00647
00648
00649
00650
00651 void ParametricCurve::
00652 unregister_drawer(ParametricCurveDrawer *drawer) {
00653 _drawers.remove(drawer);
00654 }
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666 void ParametricCurve::
00667 invalidate(PN_stdfloat, PN_stdfloat) {
00668 invalidate_all();
00669 }
00670
00671
00672
00673
00674
00675
00676
00677
00678 void ParametricCurve::
00679 invalidate_all() {
00680
00681
00682
00683
00684
00685
00686
00687
00688 }
00689
00690
00691
00692
00693
00694
00695
00696
00697 bool ParametricCurve::
00698 format_egg(ostream &, const string &, const string &, int) const {
00699 return false;
00700 }
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712 PN_stdfloat ParametricCurve::
00713 r_calc_length(PN_stdfloat t1, PN_stdfloat t2, const LPoint3 &p1, const LPoint3 &p2,
00714 PN_stdfloat seglength) const {
00715 static const PN_stdfloat length_tolerance = 0.0000001f;
00716 static const PN_stdfloat t_tolerance = 0.000001f;
00717
00718 if (t2 - t1 < t_tolerance) {
00719
00720
00721 return 0.0f;
00722 }
00723
00724 PN_stdfloat tmid;
00725 LPoint3 pmid;
00726 PN_stdfloat left, right;
00727
00728
00729
00730 tmid = (t1+t2)*0.5f;
00731 get_point(tmid, pmid);
00732
00733
00734 left = (p1 - pmid).length();
00735 right = (pmid - p2).length();
00736
00737 if ((left + right) - seglength < length_tolerance) {
00738
00739 return seglength;
00740 } else {
00741
00742 return r_calc_length(t1, tmid, p1, pmid, left) +
00743 r_calc_length(tmid, t2, pmid, p2, right);
00744 }
00745 }
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759 bool ParametricCurve::
00760 r_find_length(PN_stdfloat target_length, PN_stdfloat &found_t,
00761 PN_stdfloat t1, PN_stdfloat t2,
00762 const LPoint3 &p1, const LPoint3 &p2,
00763 PN_stdfloat &seglength) const {
00764 static const PN_stdfloat length_tolerance = 0.0000001f;
00765 static const PN_stdfloat t_tolerance = 0.000001f;
00766
00767 if (target_length < t_tolerance) {
00768
00769
00770 found_t = t1;
00771 return true;
00772
00773 }
00774
00775 PN_stdfloat tmid;
00776 LPoint3 pmid;
00777 PN_stdfloat left, right;
00778
00779
00780
00781 tmid = (t1+t2)*0.5f;
00782 get_point(tmid, pmid);
00783
00784
00785 left = (p1 - pmid).length();
00786 right = (pmid - p2).length();
00787
00788 if ((left + right) - seglength < length_tolerance) {
00789
00790 return find_t_linear(target_length, found_t, t1, t2, p1, p2);
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805 } else {
00806
00807
00808
00809 if (r_find_length(target_length, found_t, t1, tmid, p1, pmid, left)) {
00810 return true;
00811 }
00812
00813
00814 if (r_find_length(target_length - left, found_t, tmid, t2, pmid, p2, right)) {
00815 return true;
00816 }
00817
00818
00819 seglength = left + right;
00820 return false;
00821 }
00822 }
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837 bool ParametricCurve::
00838 r_find_t(PN_stdfloat target_length, PN_stdfloat &found_t,
00839 PN_stdfloat t1, PN_stdfloat t2,
00840 const LPoint3 &p1, const LPoint3 &p2) const {
00841 static const PN_stdfloat length_tolerance = 0.0001f;
00842 static const PN_stdfloat t_tolerance = 0.0001f;
00843
00844 if (parametrics_cat.is_spam()) {
00845 parametrics_cat.spam()
00846 << "target_length " << target_length << " t1 " << t1 << " t2 " << t2 << "\n";
00847 }
00848
00849
00850 if (target_length < length_tolerance) {
00851 found_t = t1;
00852 return true;
00853 }
00854
00855
00856 PN_stdfloat point_dist;
00857 point_dist = (p2 - p1).length();
00858
00859
00860 if (point_dist < target_length) {
00861 return false;
00862 }
00863
00864
00865 if ( (point_dist - target_length ) < length_tolerance ) {
00866 found_t = t2;
00867 return true;
00868 }
00869
00870
00871 if ((t2 - t1) < t_tolerance) {
00872 found_t = t1;
00873 return true;
00874 }
00875
00876
00877 PN_stdfloat tmid;
00878 LPoint3 pmid;
00879 PN_stdfloat left;
00880
00881
00882
00883 tmid = (t1+t2)*0.5f;
00884 get_point(tmid, pmid);
00885
00886
00887 if (r_find_t(target_length, found_t, t1, tmid, p1, pmid)) {
00888 return true;
00889 }
00890
00891 left = (p1 - pmid).length();
00892 if (r_find_t(target_length - left, found_t, tmid, t2, pmid, p2)) {
00893 return true;
00894 }
00895
00896
00897 return false;
00898 }
00899
00900
00901
00902
00903
00904
00905
00906 bool ParametricCurve::
00907 find_t_linear(PN_stdfloat target_length, PN_stdfloat &found_t,
00908 PN_stdfloat t1, PN_stdfloat t2,
00909 const LPoint3 &p1, const LPoint3 &p2) const {
00910 const PN_stdfloat length_tolerance = (p1-p2).length()/tolerance_divisor;
00911 const PN_stdfloat t_tolerance = (t1+t2)/tolerance_divisor;
00912
00913 if (parametrics_cat.is_spam()) {
00914 parametrics_cat.spam()
00915 << "target_length " << target_length << " t1 " << t1 << " t2 " << t2 << "\n";
00916 }
00917
00918
00919
00920 if (target_length > (p1 - p2).length()) {
00921
00922 return false;
00923 }
00924
00925 PN_stdfloat tleft = t1;
00926 PN_stdfloat tright = t2;
00927 PN_stdfloat tmid;
00928 LPoint3 pmid;
00929 PN_stdfloat len;
00930
00931 while (1) {
00932 tmid = (tleft + tright) * 0.5f;
00933 get_point(tmid, pmid);
00934 len = (pmid - p1).length();
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945 if (fabs(len - target_length) < length_tolerance) {
00946 found_t = tmid;
00947 return true;
00948 }
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958 if ((tright - tleft) < t_tolerance) {
00959
00960 found_t = tmid;
00961 return true;
00962 }
00963
00964
00965 if (len > target_length) {
00966
00967 tright = tmid;
00968 } else {
00969
00970 tleft = tmid;
00971 }
00972 }
00973 }
00974
00975
00976
00977
00978
00979
00980
00981
00982 void ParametricCurve::
00983 write_datagram(BamWriter *manager, Datagram &me) {
00984 PandaNode::write_datagram(manager, me);
00985
00986 me.add_int8(_curve_type);
00987 me.add_int8(_num_dimensions);
00988 }
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998 void ParametricCurve::
00999 fillin(DatagramIterator &scan, BamReader *manager) {
01000 PandaNode::fillin(scan, manager);
01001
01002 _curve_type = scan.get_int8();
01003 _num_dimensions = scan.get_int8();
01004 }