Panda3D
Loading...
Searching...
No Matches
parametricCurveCollection.cxx
Go to the documentation of this file.
1/**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file parametricCurveCollection.cxx
10 * @author drose
11 * @date 2001-03-04
12 */
13
15#include "config_parametrics.h"
16#include "curveFitter.h"
17#include "nurbsCurve.h"
18
19#include "indent.h"
20#include "compose_matrix.h"
21#include "string_utils.h"
22#include "look_at.h"
23
24/**
25 *
26 */
27ParametricCurveCollection::
28ParametricCurveCollection() {
29}
30
31/**
32 * Adds a new ParametricCurve to the collection.
33 */
36 prepare_add_curve(curve);
37 _curves.push_back(curve);
38 redraw();
39}
40
41/**
42 * Adds a new ParametricCurve to the collection at the indicated index.
43 */
45insert_curve(size_t index, ParametricCurve *curve) {
46 prepare_add_curve(curve);
47 index = std::min(index, _curves.size());
48 _curves.insert(_curves.begin() + index, curve);
49 redraw();
50}
51
52/**
53 * Adds all the curves found in the scene graph rooted at the given node.
54 * Returns the number of curves found.
55 */
57add_curves(PandaNode *node) {
58 int num_curves = r_add_curves(node);
59
60 if (num_curves > 0) {
61 redraw();
62 }
63
64 return num_curves;
65}
66
67/**
68 * Removes the indicated ParametricCurve from the collection. Returns true if
69 * the curve was removed, false if it was not a member of the collection.
70 */
73 int curve_index = -1;
74 for (int i = 0; curve_index == -1 && i < (int)_curves.size(); i++) {
75 if (_curves[i] == curve) {
76 curve_index = i;
77 }
78 }
79
80 if (curve_index == -1) {
81 // The indicated curve was not a member of the collection.
82 return false;
83 }
84
85 remove_curve(curve_index);
86
87 return true;
88}
89
90
91/**
92 * Removes the indicated ParametricCurve from the collection, by its index
93 * number.
94 */
96remove_curve(size_t index) {
97 nassertv(index < _curves.size());
98 PT(ParametricCurve) curve = _curves[index];
99 prepare_remove_curve(curve);
100 _curves.erase(_curves.begin() + index);
101 redraw();
102}
103
104
105/**
106 * Replaces the indicated ParametricCurve from the collection, by its index
107 * number.
108 */
110set_curve(size_t index, ParametricCurve *curve) {
111 nassertv(index < _curves.size());
112 prepare_remove_curve(_curves[index]);
113 prepare_add_curve(curve);
114 _curves[index] = curve;
115 redraw();
116}
117
118/**
119 * Returns true if the indicated ParametricCurve appears in this collection,
120 * false otherwise.
121 */
123has_curve(ParametricCurve *curve) const {
124 ParametricCurves::const_iterator ci;
125 for (ci = _curves.begin(); ci != _curves.end(); ++ci) {
126 if (curve == (*ci)) {
127 return true;
128 }
129 }
130 return false;
131}
132
133/**
134 * Removes all ParametricCurves from the collection.
135 */
137clear() {
138 ParametricCurves::iterator ci;
139 for (ci = _curves.begin(); ci != _curves.end(); ++ci) {
140 ParametricCurve *curve = (*ci);
141 prepare_remove_curve(curve);
142 }
143 _curves.clear();
144
145 redraw();
146}
147
148/**
149 * Removes all the timewarp curves from the collection.
150 */
153 PT(ParametricCurve) xyz_curve = nullptr;
154 PT(ParametricCurve) hpr_curve = nullptr;
155
156 ParametricCurves::iterator ci;
157 for (ci = _curves.begin(); ci != _curves.end(); ++ci) {
158 ParametricCurve *curve = (*ci);
159
160 switch (curve->get_curve_type()) {
161 case PCT_XYZ:
162 if (xyz_curve == nullptr) {
163 xyz_curve = curve;
164 } else {
165 prepare_remove_curve(curve);
166 }
167 break;
168
169 case PCT_HPR:
170 if (hpr_curve == nullptr) {
171 hpr_curve = curve;
172 } else {
173 prepare_remove_curve(curve);
174 }
175 break;
176
177 default:
178 prepare_remove_curve(curve);
179 }
180 }
181
182 _curves.clear();
183 _curves.push_back(xyz_curve);
184
185 if (hpr_curve != nullptr) {
186 _curves.push_back(hpr_curve);
187 }
188
189 redraw();
190}
191
192/**
193 * Returns the first XYZ curve in the collection, if any, or NULL if there are
194 * none.
195 */
197get_xyz_curve() const {
198 ParametricCurves::const_iterator ci;
199 for (ci = _curves.begin(); ci != _curves.end(); ++ci) {
200 ParametricCurve *curve = (*ci);
201 if (curve->get_curve_type() == PCT_XYZ) {
202 return curve;
203 }
204 }
205 return nullptr;
206}
207
208/**
209 * Returns the first HPR curve in the collection, if any, or NULL if there are
210 * none.
211 */
213get_hpr_curve() const {
214 ParametricCurves::const_iterator ci;
215 for (ci = _curves.begin(); ci != _curves.end(); ++ci) {
216 ParametricCurve *curve = (*ci);
217 if (curve->get_curve_type() == PCT_HPR) {
218 return curve;
219 }
220 }
221 return nullptr;
222}
223
224/**
225 * If there is an XYZ curve in the collection, returns it; otherwise, returns
226 * the first curve whose type is unspecified. Returns NULL if no curve meets
227 * the criteria.
228 */
230get_default_curve() const {
231 ParametricCurve *xyz_curve = get_xyz_curve();
232 if (xyz_curve != nullptr) {
233 return xyz_curve;
234 }
235
236 ParametricCurves::const_iterator ci;
237 for (ci = _curves.begin(); ci != _curves.end(); ++ci) {
238 ParametricCurve *curve = (*ci);
239 if (curve->get_curve_type() == PCT_NONE) {
240 return curve;
241 }
242 }
243 return nullptr;
244}
245
246/**
247 * Returns the number of timewarp curves in the collection.
248 */
250get_num_timewarps() const {
251 int count = 0;
252
253 ParametricCurves::const_iterator ci;
254 for (ci = _curves.begin(); ci != _curves.end(); ++ci) {
255 ParametricCurve *curve = (*ci);
256 if (curve->get_curve_type() == PCT_T) {
257 count++;
258 }
259 }
260
261 return count;
262}
263
264/**
265 * Returns the nth timewarp curve in the collection.
266 */
268get_timewarp_curve(int n) const {
269 ParametricCurves::const_iterator ci;
270 for (ci = _curves.begin(); ci != _curves.end(); ++ci) {
271 ParametricCurve *curve = (*ci);
272 if (curve->get_curve_type() == PCT_T) {
273 if (n == 0) {
274 return curve;
275 }
276 n--;
277 }
278 }
279 nassert_raise("index out of range");
280 return nullptr;
281}
282
283/**
284 * Discards all existing timewarp curves and recomputes a new timewarp curve
285 * that maps distance along the curve to parametric time, so that the distance
286 * between any two points in parametric time is proportional to the
287 * approximate distance of those same two points along the XYZ curve.
288 *
289 * segments_per_unit represents the number of segments to take per each unit
290 * of parametric time of the original XYZ curve.
291 *
292 * The new timewarp curve (and thus, the apparent range of the collection)
293 * will range from 0 to max_t.
294 */
296make_even(PN_stdfloat max_t, PN_stdfloat segments_per_unit) {
297 ParametricCurve *xyz_curve = get_xyz_curve();
298 if (xyz_curve == nullptr) {
299 parametrics_cat.error()
300 << "No XYZ curve for make_even().\n";
301 return;
302 }
303
305
306 // Now divvy up the XYZ curve into num_segments sections, each approximately
307 // the same length as all the others.
308 CurveFitter fitter;
309
310 int num_segments = std::max(1, (int)cfloor(segments_per_unit * xyz_curve->get_max_t() + 0.5f));
311
312 if (parametrics_cat.is_debug()) {
313 parametrics_cat.debug()
314 << "Calculating length of curve.\n";
315 }
316
317 PN_stdfloat net_length = xyz_curve->calc_length();
318 PN_stdfloat segment_length = net_length / (PN_stdfloat)num_segments;
319
320 if (parametrics_cat.is_debug()) {
321 parametrics_cat.debug()
322 << "Curve has total length " << net_length << "; dividing into "
323 << num_segments << " segments of " << segment_length << " units each.\n";
324 }
325
326 PN_stdfloat last_t = 0.0f;
327 fitter.add_xyz(0.0f, LVecBase3(last_t, 0.0f, 0.0f));
328 PN_stdfloat val_inc= max_t/num_segments;
329 PN_stdfloat val=val_inc;
330
331 for (int i = 0; i < num_segments; i++,val+=val_inc) {
332 PN_stdfloat next_t = xyz_curve->find_length(last_t, segment_length);
333 fitter.add_xyz(/*(PN_stdfloat)(i + 1)/num_segments * max_t,*/
334 val, LVecBase3(next_t, 0.0f, 0.0f));
335
336 if (parametrics_cat.is_spam()) {
337 parametrics_cat.spam()
338 << "Point " << i << " is at " << next_t << "\n";
339 }
340
341 last_t = next_t;
342 }
343
344 if (parametrics_cat.is_debug()) {
345 parametrics_cat.debug()
346 << "Done computing segments.\n";
347 }
348
349 fitter.compute_tangents(1);
350 PT(ParametricCurveCollection) fit = fitter.make_nurbs();
351 ParametricCurve *t_curve = fit->get_xyz_curve();
352 nassertv(t_curve != nullptr);
353 t_curve->set_curve_type(PCT_T);
354 add_curve(t_curve);
355}
356
357/**
358 * Discards the existing HPR curve and generates a new one that looks in the
359 * direction of travel along the XYZ curve, based on the XYZ curve's tangent
360 * at each point.
361 */
363face_forward(PN_stdfloat segments_per_unit) {
364 ParametricCurve *xyz_curve = get_xyz_curve();
365 if (xyz_curve == nullptr) {
366 parametrics_cat.error()
367 << "No XYZ curve for face_forward().\n";
368 return;
369 }
370
371 // Eliminate all the old hpr curves, and also take note of the index number
372 // of the first XYZ curve.
373 int xyz_index = -1;
374 ParametricCurves::const_iterator ci;
375 ParametricCurves new_curves;
376
377 for (ci = _curves.begin(); ci != _curves.end(); ++ci) {
378 ParametricCurve *curve = (*ci);
379 if (curve->get_curve_type() == PCT_HPR) {
380 prepare_remove_curve(curve);
381 } else {
382 if (curve->get_curve_type() == PCT_XYZ && xyz_index == -1) {
383 xyz_index = (ci - _curves.begin());
384 }
385 new_curves.push_back(curve);
386 }
387 }
388 _curves.swap(new_curves);
389
390 // Now divvy up the XYZ curve into num_segments sections, of equal length in
391 // parametric time (based on the timewarp curves).
392 CurveFitter fitter;
393
394 PN_stdfloat max_t = get_max_t();
395 int num_segments = (int)cfloor(segments_per_unit * max_t + 0.5);
396
397 LVecBase3 hpr(0.0f, 0.0f, 0.0f);
398
399 // We compute the first HPR point a little point into the beginning of the
400 // curve, instead of at 0.0f, because the tangent at 0.0f is likely to be
401 // zero.
402 determine_hpr(0.001, xyz_curve, hpr);
403 fitter.add_hpr(0.0f, hpr);
404
405 for (int i = 0; i < num_segments; i++) {
406 PN_stdfloat t = (PN_stdfloat)(i + 1) / num_segments * max_t;
407 determine_hpr(t, xyz_curve, hpr);
408 fitter.add_hpr(t, hpr);
409 }
410
411 fitter.wrap_hpr();
412 fitter.compute_tangents(1);
413 PT(ParametricCurveCollection) fit = fitter.make_nurbs();
414 ParametricCurve *hpr_curve = fit->get_hpr_curve();
415 nassertv(hpr_curve != nullptr);
416 add_curve(hpr_curve, xyz_index + 1);
417}
418
419/**
420 * Adjusts the apparent length of the curve by applying a new timewarp that
421 * maps the range [0..max_t] to the range [0..get_max_t()]. After this call,
422 * the curve collection will contain one more timewarp curve, and get_max_t()
423 * will return the given max_t value.
424 */
426reset_max_t(PN_stdfloat max_t) {
427 // Define a linear NURBS curve.
428 PT(NurbsCurve) nurbs = new NurbsCurve;
429 nurbs->set_curve_type(PCT_T);
430 nurbs->set_order(2);
431 nurbs->append_cv(LVecBase3(0.0f, 0.0f, 0.0f));
432 nurbs->append_cv(LVecBase3(get_max_t(), 0.0f, 0.0f));
433 nurbs->set_knot(0, 0.0f);
434 nurbs->set_knot(1, 0.0f);
435 nurbs->set_knot(2, max_t);
436 nurbs->set_knot(3, max_t);
437 nurbs->recompute();
438 add_curve(nurbs);
439}
440
441/**
442 * Computes the position and rotation represented by the first XYZ and HPR
443 * curves in the collection at the given point t, after t has been modified by
444 * all the timewarp curves in the collection applied in sequence, from back to
445 * front.
446 *
447 * Returns true if the point is valid (i.e. t is within the bounds indicated
448 * by all the timewarp curves and within the bounds of the curves themselves),
449 * or false otherwise.
450 */
452evaluate(PN_stdfloat t, LVecBase3 &xyz, LVecBase3 &hpr) const {
453 // First, apply all the timewarps in sequence, from back to front. Also
454 // take note of the XYZ and HPR curves.
455 ParametricCurve *xyz_curve = nullptr;
456 ParametricCurve *hpr_curve = nullptr;
457 ParametricCurve *default_curve = nullptr;
458
459 PN_stdfloat t0 = t;
460 LVecBase3 point;
461
462 ParametricCurves::const_reverse_iterator ci;
463 for (ci = _curves.rbegin(); ci != _curves.rend(); ++ci) {
464 ParametricCurve *curve = (*ci);
465
466 switch (curve->get_curve_type()) {
467 case PCT_XYZ:
468 xyz_curve = curve;
469 break;
470
471 case PCT_HPR:
472 hpr_curve = curve;
473 break;
474
475 case PCT_NONE:
476 default_curve = curve;
477 break;
478
479 case PCT_T:
480 if (!curve->get_point(t0, point)) {
481 return false;
482 }
483 t0 = point[0];
484 }
485 }
486
487 if (xyz_curve == nullptr) {
488 xyz_curve = default_curve;
489 }
490
491 // Now compute the position and orientation.
492 if (xyz_curve != nullptr) {
493 if (!xyz_curve->get_point(t0, xyz)) {
494 return false;
495 }
496 }
497
498 if (hpr_curve != nullptr) {
499 if (!hpr_curve->get_point(t0, hpr)) {
500 return false;
501 }
502 }
503
504 return true;
505}
506
507/**
508 * Computes the transform matrix representing translation to the position
509 * indicated by the first XYZ curve in the collection and the rotation
510 * indicated by the first HPR curve in the collection, after t has been
511 * modified by all the timewarp curves in the collection applied in sequence,
512 * from back to front.
513 *
514 * Returns true if the point is valid (i.e. t is within the bounds indicated
515 * by all the timewarp curves and within the bounds of the curves themselves),
516 * or false otherwise.
517 */
519evaluate(PN_stdfloat t, LMatrix4 &result, CoordinateSystem cs) const {
520 LVecBase3 xyz(0.0f, 0.0f, 0.0f);
521 LVecBase3 hpr(0.0f, 0.0f, 0.0f);
522
523 if (!evaluate(t, xyz, hpr)) {
524 return false;
525 }
526
527 compose_matrix(result,
528 LVecBase3(1.0f, 1.0f, 1.0f),
529 LVecBase3(0.0f, 0.0f, 0.0f),
530 hpr, xyz, cs);
531 return true;
532}
533
534/**
535 * Determines the value of t that should be passed to the XYZ and HPR curves,
536 * after applying the given value of t to all the timewarps. Return -1.0f if
537 * the value of t exceeds one of the timewarps' ranges.
538 */
540evaluate_t(PN_stdfloat t) const {
541 PN_stdfloat t0 = t;
542 LVecBase3 point;
543
544 ParametricCurves::const_iterator ci;
545 for (ci = _curves.begin(); ci != _curves.end(); ++ci) {
546 ParametricCurve *curve = (*ci);
547
548 if (curve->get_curve_type() == PCT_T) {
549 if (!curve->get_point(t0, point)) {
550 return -1.0f;
551 }
552 t0 = point[0];
553 }
554 }
555
556 return t0;
557}
558
559/**
560 * Adjust the XYZ curve at the indicated time to the new value. The curve
561 * shape will change correspondingly. Returns true if successful, false if
562 * unable to make the adjustment for some reason.
563 */
565adjust_xyz(PN_stdfloat t, const LVecBase3 &xyz) {
566 ParametricCurve *xyz_curve = get_xyz_curve();
567 if (xyz_curve == nullptr) {
568 return false;
569 }
570
571 PN_stdfloat t0 = evaluate_t(t);
572 if (t0 >= 0.0f && t < xyz_curve->get_max_t()) {
573 return xyz_curve->adjust_point(t, xyz[0], xyz[1], xyz[2]);
574 }
575 return false;
576}
577
578/**
579 * Adjust the HPR curve at the indicated time to the new value. The curve
580 * shape will change correspondingly. Returns true if successful, false if
581 * unable to make the adjustment for some reason.
582 */
584adjust_hpr(PN_stdfloat t, const LVecBase3 &hpr) {
585 ParametricCurve *hpr_curve = get_hpr_curve();
586 if (hpr_curve == nullptr) {
587 return false;
588 }
589
590 PN_stdfloat t0 = evaluate_t(t);
591 if (t0 >= 0.0f && t < hpr_curve->get_max_t()) {
592 return hpr_curve->adjust_point(t, hpr[0], hpr[1], hpr[2]);
593 }
594 return false;
595}
596
597/**
598 * Ensures all the curves are freshly computed and up-to-date. Returns true
599 * if everything is valid, false if at least one curve is incorrect.
600 */
602recompute() {
603 bool all_ok = true;
604
605 ParametricCurves::iterator ci;
606 for (ci = _curves.begin(); ci != _curves.end(); ++ci) {
607 ParametricCurve *curve = (*ci);
608 if (!curve->recompute()) {
609 all_ok = false;
610 }
611 }
612
613 return all_ok;
614}
615
616/**
617 * Regenerates this curve as one long curve: the first curve connected end-to-
618 * end with the second one. Either a or b may be the same as 'this'. This
619 * will lose any timewarps on the input curves.
620 *
621 * Returns true if successful, false on failure.
622 */
625 const ParametricCurveCollection *b) {
626 PT(ParametricCurve) a_xyz = a->get_xyz_curve();
627 PT(ParametricCurve) b_xyz = b->get_xyz_curve();
628
629 PT(ParametricCurve) a_hpr = a->get_hpr_curve();
630 PT(ParametricCurve) b_hpr = b->get_hpr_curve();
631
632 clear();
633
634 if (a_xyz != nullptr && b_xyz != nullptr) {
635 PT(NurbsCurve) new_xyz = new NurbsCurve;
636 if (!new_xyz->stitch(a_xyz, b_xyz)) {
637 return false;
638 }
639 new_xyz->set_curve_type(PCT_XYZ);
640 add_curve(new_xyz);
641 }
642
643 if (a_hpr != nullptr && b_hpr != nullptr) {
644 PT(NurbsCurve) new_hpr = new NurbsCurve;
645 if (!new_hpr->stitch(a_hpr, b_hpr)) {
646 return false;
647 }
648 new_hpr->set_curve_type(PCT_HPR);
649 add_curve(new_hpr);
650 }
651
652 return true;
653}
654
655/**
656 * Writes a brief one-line description of the ParametricCurveCollection to the
657 * indicated output stream.
658 */
660output(std::ostream &out) const {
661 if (get_num_curves() == 1) {
662 out << "1 ParametricCurve";
663 } else {
664 out << get_num_curves() << " ParametricCurves";
665 }
666}
667
668/**
669 * Writes a complete multi-line description of the ParametricCurveCollection
670 * to the indicated output stream.
671 */
673write(std::ostream &out, int indent_level) const {
674 ParametricCurves::const_iterator ci;
675 for (ci = _curves.begin(); ci != _curves.end(); ++ci) {
676 ParametricCurve *curve = (*ci);
677 indent(out, indent_level) << *curve << "\n";
678 }
679}
680
681/**
682 * Writes an egg description of all the nurbs curves in the collection to the
683 * specified output file. Returns true if the file is successfully written.
684 */
686write_egg(Filename filename, CoordinateSystem cs) {
687 pofstream out;
688 filename.set_text();
689
690 if (!filename.open_write(out)) {
691 parametrics_cat.error()
692 << "Unable to write to " << filename << "\n";
693 return false;
694 }
695 return write_egg(out, filename, cs);
696}
697
698/**
699 * Writes an egg description of all the nurbs curves in the collection to the
700 * specified output stream. Returns true if the file is successfully written.
701 */
703write_egg(std::ostream &out, const Filename &filename, CoordinateSystem cs) {
704 if (cs == CS_default) {
705 cs = get_default_coordinate_system();
706 }
707
708 if (cs != CS_invalid) {
709 out << "<CoordinateSystem> { ";
710 switch (cs) {
711 case CS_zup_right:
712 out << "Z-Up";
713 break;
714
715 case CS_yup_right:
716 out << "Y-Up";
717 break;
718
719 case CS_zup_left:
720 out << "Z-Up-Left";
721 break;
722
723 case CS_yup_left:
724 out << "Y-Up-Left";
725 break;
726
727 default:
728 break;
729 }
730 out << " }\n\n";
731 }
732
733 int xyz_count = 0;
734 int hpr_count = 0;
735 int t_count = 0;
736
737 ParametricCurves::iterator ci;
738 for (ci = _curves.begin(); ci != _curves.end(); ++ci) {
739 ParametricCurve *curve = (*ci);
740
741 if (!curve->has_name()) {
742 // If we don't have a name, come up with one.
743 std::string name = filename.get_basename_wo_extension();
744
745 switch (curve->get_curve_type()) {
746 case PCT_XYZ:
747 name += "_xyz";
748 if (xyz_count > 0) {
749 name += format_string(xyz_count);
750 }
751 xyz_count++;
752 break;
753
754 case PCT_HPR:
755 name += "_hpr";
756 if (hpr_count > 0) {
757 name += format_string(hpr_count);
758 }
759 hpr_count++;
760 break;
761
762 case PCT_T:
763 name += "_t";
764 if (t_count > 0) {
765 name += format_string(t_count);
766 }
767 t_count++;
768 break;
769 }
770
771 curve->set_name(name);
772 }
773
774 if (!curve->write_egg(out, filename, CS_invalid)) {
775 return false;
776 }
777 }
778
779 return true;
780}
781
782/**
783 * The recursive implementation of add_curves().
784 */
786r_add_curves(PandaNode *node) {
787 int num_curves = 0;
788
789 if (node->is_of_type(ParametricCurve::get_class_type())) {
790 ParametricCurve *curve = DCAST(ParametricCurve, node);
791 prepare_add_curve(curve);
792 _curves.push_back(curve);
793 num_curves++;
794 }
795
796 int num_children = node->get_num_children();
797 for (int i = 0; i < num_children; i++) {
798 PandaNode *child = node->get_child(i);
799 num_curves += r_add_curves(child);
800 }
801
802 return num_curves;
803}
804
805/**
806 * Registers a Drawer with this curve collection that will automatically be
807 * updated whenever the collection is modified, so that the visible
808 * representation of the curve is kept up to date. This is called
809 * automatically by the ParametricCurveDrawer.
810 *
811 * Any number of Drawers may be registered with a particular curve collection.
812 */
814register_drawer(ParametricCurveDrawer *drawer) {
815 _drawers.push_back(drawer);
816
817 ParametricCurves::iterator ci;
818 for (ci = _curves.begin(); ci != _curves.end(); ++ci) {
819 ParametricCurve *curve = (*ci);
820 curve->register_drawer(drawer);
821 }
822}
823
824/**
825 * Removes a previously registered drawer from the list of automatically-
826 * refreshed drawers. This is called automatically by the
827 * ParametricCurveDrawer.
828 */
830unregister_drawer(ParametricCurveDrawer *drawer) {
831 _drawers.remove(drawer);
832
833 ParametricCurves::iterator ci;
834 for (ci = _curves.begin(); ci != _curves.end(); ++ci) {
835 ParametricCurve *curve = (*ci);
836 curve->unregister_drawer(drawer);
837 }
838}
839
840/**
841 * Computes the orientation at the given point in time, based on the tangent
842 * of the XYZ curve. Returns true if the orientation can be determined, or
843 * false if it cannot (in which case hpr is left unchanged).
844 */
845bool ParametricCurveCollection::
846determine_hpr(PN_stdfloat t, ParametricCurve *xyz_curve, LVecBase3 &hpr) const {
847 PN_stdfloat t0 = evaluate_t(t);
848
849 LVector3 tangent;
850 if (!xyz_curve->get_tangent(t0, tangent)) {
851 return false;
852 }
853
854 if (tangent.length_squared() == 0.0f) {
855 return false;
856 }
857
858 LMatrix3 mat;
859 look_at(mat, tangent);
860
861 LVecBase3 scale, shear;
862 return decompose_matrix(mat, scale, shear, hpr);
863}
864
865/**
866 * Registers the curve with the list of drawers that share this collection, in
867 * preparation for adding it to the _curves list.
868 */
869void ParametricCurveCollection::
870prepare_add_curve(ParametricCurve *curve) {
871 DrawerList::iterator di;
872 for (di = _drawers.begin(); di != _drawers.end(); ++di) {
873 ParametricCurveDrawer *drawer = (*di);
874 curve->register_drawer(drawer);
875 }
876}
877
878/**
879 * Unregisters the curve with the list of drawers that share this collection,
880 * in preparation for removing it from the _curves list.
881 */
882void ParametricCurveCollection::
883prepare_remove_curve(ParametricCurve *curve) {
884 DrawerList::iterator di;
885 for (di = _drawers.begin(); di != _drawers.end(); ++di) {
886 ParametricCurveDrawer *drawer = (*di);
887 curve->unregister_drawer(drawer);
888 }
889}
890
891/**
892 * Calls redraw() on all drawers that share this collection.
893 */
894void ParametricCurveCollection::
895redraw() {
896 /*
897 DrawerList::iterator di;
898 for (di = _drawers.begin(); di != _drawers.end(); ++di) {
899 ParametricCurveDrawer *drawer = (*di);
900 drawer->redraw();
901 }
902 */
903}
void add_xyz(PN_stdfloat t, const LVecBase3 &xyz)
Adds a single sample xyz.
void wrap_hpr()
Resets each HPR data point so that the maximum delta between any two consecutive points is 180 degree...
void compute_tangents(PN_stdfloat scale)
Once a set of points has been built, and prior to calling MakeHermite() or MakeNurbs(),...
void add_hpr(PN_stdfloat t, const LVecBase3 &hpr)
Adds a single sample hpr.
The name of a file, such as a texture file or an Egg file.
Definition filename.h:44
void set_text()
Indicates that the filename represents a text file.
Definition filename.I:424
bool open_write(std::ofstream &stream, bool truncate=true) const
Opens the indicated ifstream for writing the file, if possible.
std::string get_basename_wo_extension() const
Returns the basename part of the filename, without the file extension.
Definition filename.I:386
bool has_name() const
Returns true if the Namable has a nonempty name set, false if the name is empty.
Definition namable.I:44
A Nonuniform Rational B-Spline.
Definition nurbsCurve.h:41
A basic node of the scene graph or data graph.
Definition pandaNode.h:65
get_child
Returns the nth child node of this node.
Definition pandaNode.h:124
get_num_children
Returns the number of child nodes this node has.
Definition pandaNode.h:124
This is a set of zero or more ParametricCurves, which may or may not be related.
bool recompute()
Ensures all the curves are freshly computed and up-to-date.
void clear_timewarps()
Removes all the timewarp curves from the collection.
get_default_curve
If there is an XYZ curve in the collection, returns it; otherwise, returns the first curve whose type...
int add_curves(PandaNode *node)
Adds all the curves found in the scene graph rooted at the given node.
void insert_curve(size_t index, ParametricCurve *curve)
Adds a new ParametricCurve to the collection at the indicated index.
void unregister_drawer(ParametricCurveDrawer *drawer)
Removes a previously registered drawer from the list of automatically- refreshed drawers.
bool adjust_xyz(PN_stdfloat t, PN_stdfloat x, PN_stdfloat y, PN_stdfloat z)
Adjust the XYZ curve at the indicated time to the new value.
bool has_curve(ParametricCurve *curve) const
Returns true if the indicated ParametricCurve appears in this collection, false otherwise.
void write(std::ostream &out, int indent_level=0) const
Writes a complete multi-line description of the ParametricCurveCollection to the indicated output str...
void add_curve(ParametricCurve *curve)
Adds a new ParametricCurve to the collection.
bool adjust_hpr(PN_stdfloat t, PN_stdfloat h, PN_stdfloat p, PN_stdfloat r)
Adjust the HPR curve at the indicated time to the new value.
void face_forward(PN_stdfloat segments_per_unit)
Discards the existing HPR curve and generates a new one that looks in the direction of travel along t...
bool stitch(const ParametricCurveCollection *a, const ParametricCurveCollection *b)
Regenerates this curve as one long curve: the first curve connected end-to- end with the second one.
get_xyz_curve
Returns the first XYZ curve in the collection, if any, or NULL if there are none.
get_timewarp_curve
Returns the nth timewarp curve in the collection.
get_num_curves
Returns the number of ParametricCurves in the collection.
int r_add_curves(PandaNode *node)
The recursive implementation of add_curves().
void register_drawer(ParametricCurveDrawer *drawer)
Registers a Drawer with this curve collection that will automatically be updated whenever the collect...
void make_even(PN_stdfloat max_t, PN_stdfloat segments_per_unit)
Discards all existing timewarp curves and recomputes a new timewarp curve that maps distance along th...
get_num_timewarps
Returns the number of timewarp curves in the collection.
PN_stdfloat evaluate_t(PN_stdfloat t) const
Determines the value of t that should be passed to the XYZ and HPR curves, after applying the given v...
bool write_egg(Filename filename, CoordinateSystem cs=CS_default)
Writes an egg description of all the nurbs curves in the collection to the specified output file.
remove_curve
Removes the indicated ParametricCurve from the collection.
void clear()
Removes all ParametricCurves from the collection.
set_curve
Replaces the indicated ParametricCurve from the collection, by its index number.
bool evaluate(PN_stdfloat t, LVecBase3 &xyz, LVecBase3 &hpr) const
Computes the position and rotation represented by the first XYZ and HPR curves in the collection at t...
void reset_max_t(PN_stdfloat max_t)
Adjusts the apparent length of the curve by applying a new timewarp that maps the range [0....
void output(std::ostream &out) const
Writes a brief one-line description of the ParametricCurveCollection to the indicated output stream.
get_hpr_curve
Returns the first HPR curve in the collection, if any, or NULL if there are none.
get_max_t
Returns the maximum T value associated with the *last* curve in the collection.
A virtual base class for parametric curves.
PN_stdfloat calc_length() const
Approximates the length of the entire curve to within a few decimal places.
int get_curve_type() const
Returns the flag indicating the use to which the curve is intended to be put.
virtual bool recompute()
Recalculates the curve, if necessary.
virtual bool adjust_point(PN_stdfloat t, PN_stdfloat px, PN_stdfloat py, PN_stdfloat pz)
Recomputes the curve such that it passes through the point (px, py, pz) at time t,...
virtual PN_stdfloat get_max_t() const
Returns the upper bound of t for the entire curve.
void set_curve_type(int type)
Sets the flag indicating the use to which the curve is intended to be put.
void register_drawer(ParametricCurveDrawer *drawer)
Registers a Drawer with this curve that will automatically be updated whenever the curve is modified,...
bool write_egg(Filename filename, CoordinateSystem cs=CS_default)
Writes an egg description of the nurbs curve to the specified output file.
void unregister_drawer(ParametricCurveDrawer *drawer)
Removes a previously registered drawer from the list of automatically- refreshed drawers.
PN_stdfloat find_length(PN_stdfloat start_t, PN_stdfloat length_offset) const
Returns the parametric value corresponding to the indicated distance along the curve from the startin...
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition typedObject.I:28
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition indent.cxx:20
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.