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