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