Panda3D

parametricCurve.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 parametricCurve.cxx
10 * @author drose
11 * @date 2001-03-04
12 */
13
14 #include "parametricCurve.h"
15 #include "config_parametrics.h"
16 #include "hermiteCurve.h"
17 #include "nurbsCurve.h"
18
19 #include "datagram.h"
20 #include "datagramIterator.h"
21 #include "bamWriter.h"
22 #include "bamReader.h"
23 #include "omniBoundingVolume.h"
24
25 static const PN_stdfloat tolerance_divisor = 100000.0f;
26
27 TypeHandle ParametricCurve::_type_handle;
28
29
30 /**
31 * This is a virtual base class. Don't try to construct one from Scheme.
32 */
33 ParametricCurve::
34 ParametricCurve() : PandaNode("curve") {
35 _curve_type = PCT_NONE;
36 _num_dimensions = 3;
37 }
38
39 /**
40 *
41 */
42 ParametricCurve::
43 ~ParametricCurve() {
44 // Our drawer list must be empty by the time we destruct, since our drawers
45 // all maintain reference-counting pointers to us! If this is not so, we
46 // have lost a reference count somewhere, or we have gotten confused about
47 // which drawers we're registered to.
48 nassertv(_drawers.empty());
49 }
50
51 /**
52 * Returns true if it is generally safe to flatten out this particular kind of
53 * PandaNode by duplicating instances, false otherwise (for instance, a Camera
54 * cannot be safely flattened, because the Camera pointer itself is
55 * meaningful).
56 */
57 bool ParametricCurve::
58 safe_to_flatten() const {
59 return false;
60 }
61
62 /**
63 * Returns true if it is generally safe to transform this particular kind of
64 * PandaNode by calling the xform() method, false otherwise. For instance,
65 * it's usually a bad idea to attempt to xform a Character.
66 */
67 bool ParametricCurve::
68 safe_to_transform() const {
69 return false;
70 }
71
72 /**
73 * Returns true if the curve is defined. This base class function always
74 * returns true; derived classes might override this to sometimes return
75 * false.
76 */
77 bool ParametricCurve::
78 is_valid() const {
79 return true;
80 }
81
82
83 /**
84 * Returns the upper bound of t for the entire curve. The curve is defined in
85 * the range 0.0f <= t <= get_max_t(). This base class function always
86 * returns 1.0f; derived classes might override this to return something else.
87 */
88 PN_stdfloat ParametricCurve::
89 get_max_t() const {
90 return 1.0f;
91 }
92
93
94 /**
95 * Sets the flag indicating the use to which the curve is intended to be put.
96 * This flag is optional and only serves to provide a hint to the egg reader
97 * and writer code; it has no effect on the curve's behavior.
98 *
99 * Setting the curve type also sets the num_dimensions to 3 or 1 according to
100 * the type.
101 *
102 * THis flag may have one of the values PCT_XYZ, PCT_HPR, or PCT_T.
103 */
104 void ParametricCurve::
105 set_curve_type(int type) {
106 _curve_type = type;
107 switch (_curve_type) {
108 case PCT_XYZ:
109 case PCT_HPR:
110 case PCT_NONE:
111 _num_dimensions = 3;
112 break;
113
114 case PCT_T:
115 _num_dimensions = 1;
116 break;
117
118 default:
119 assert(0);
120 }
121 }
122
123 /**
124 * Returns the flag indicating the use to which the curve is intended to be
125 * put.
126 */
127 int ParametricCurve::
128 get_curve_type() const {
129 return _curve_type;
130 }
131
132 /**
133 * Specifies the number of significant dimensions in the curve's vertices.
134 * This should be one of 1, 2, or 3. Normally, XYZ and HPR curves have three
135 * dimensions; time curves should always have one dimension. This only serves
136 * as a hint to the mopath editor, and also controls how the curve is written
137 * out.
138 */
139 void ParametricCurve::
140 set_num_dimensions(int num) {
141 _num_dimensions = num;
142 }
143
144 /**
145 * Returns the number of significant dimensions in the curve's vertices, as
146 * set by a previous call to set_num_dimensions(). This is only a hint as to
147 * how the curve is intended to be used; the actual number of dimensions of
148 * any curve is always three.
149 */
150 int ParametricCurve::
151 get_num_dimensions() const {
152 return _num_dimensions;
153 }
154
155
156 /**
157 * Approximates the length of the entire curve to within a few decimal places.
158 */
159 PN_stdfloat ParametricCurve::
160 calc_length() const {
161 return calc_length(0.0f, get_max_t());
162 }
163
164 /**
165 * Approximates the length of the curve segment from parametric time 'from' to
166 * time 'to'.
167 */
168 PN_stdfloat ParametricCurve::
169 calc_length(PN_stdfloat from, PN_stdfloat to) const {
170 PN_stdfloat t1, t2;
171 LPoint3 p1, p2;
172
173 // Normally we expect from < to. If they came in backwards, reverse them.
174 PN_stdfloat to_minus_from = to - from;
175
176 if (to_minus_from < 0.0f) {
177 PN_stdfloat temp = to;
178 to = from;
179 from = temp;
180 to_minus_from=-to_minus_from;
181 }
182
183 // Start with a segment for each unit of t.
184 int num_segs = (int)(to_minus_from) + 1;
185 t2 = from;
186 get_point(t2, p2);
187 PN_stdfloat net = 0.0f;
188
189 for (int i = 1; i <= num_segs; i++) {
190 t1 = t2;
191 p1 = p2;
192
193 t2 = (to - from) * (PN_stdfloat)i / (PN_stdfloat)num_segs + from;
194 get_point(t2, p2);
195
196 net += r_calc_length(t1, t2, p1, p2, (p1 - p2).length());
197 }
198 return net;
199 }
200
201 /**
202 * Returns the parametric value corresponding to the indicated distance along
203 * the curve from the starting parametric value.
204 *
205 * This is the inverse of calc_length(): rather than determining the length
206 * along the curve between two parametric points, it determines the position
207 * in parametric time of a point n units along the curve.
208 *
209 * The search distance must not be negative.
210 */
211 PN_stdfloat ParametricCurve::
212 find_length(PN_stdfloat start_t, PN_stdfloat length_offset) const {
213 nassertr(length_offset >= 0.0f, start_t);
214 nassertr(start_t >= 0.0f && start_t <= get_max_t(), start_t);
215
216 PN_stdfloat t1, t2;
217 LPoint3 p1, p2;
218
219 // Start with a segment for each unit of t.
220 PN_stdfloat max_t = get_max_t();
221 int num_segs = (int)cfloor(max_t - start_t + 1);
222 t2 = start_t;
223 get_point(t2, p2);
224 PN_stdfloat net = 0.0f;
225
226 for (int i = 1; i <= num_segs; i++) {
227 assert(net <= length_offset);
228
229 t1 = t2;
230 p1 = p2;
231
232 t2 = start_t + (((max_t - start_t) * (PN_stdfloat)i) / (PN_stdfloat)num_segs);
233 get_point(t2, p2);
234
235 PN_stdfloat seglength = (p1 - p2).length();
236 PN_stdfloat result;
237
238 if (r_find_length(length_offset - net, result,
239 t1, t2, p1, p2, seglength)) {
240 // Found it!
241 return result;
242 }
243
244 net += seglength;
245 }
246
247 // Not on the curve? Huh.
248 return max_t;
249 }
250
251 /**
252 * Recomputes the curve such that it passes through the point (px, py, pz) at
253 * time t, but keeps the same tangent value at that point.
254 */
255 bool ParametricCurve::
256 adjust_point(PN_stdfloat, PN_stdfloat, PN_stdfloat, PN_stdfloat) {
257 return false;
258 }
259
260 /**
261 * Recomputes the curve such that it has the tangent (tx, ty, tz) at time t,
262 * but keeps the same position at the point.
263 */
264 bool ParametricCurve::
265 adjust_tangent(PN_stdfloat, PN_stdfloat, PN_stdfloat, PN_stdfloat) {
266 return false;
267 }
268
269 /**
270 * Recomputes the curve such that it passes through the point (px, py, pz)
271 * with the tangent (tx, ty, tz).
272 */
273 bool ParametricCurve::
274 adjust_pt(PN_stdfloat, PN_stdfloat, PN_stdfloat, PN_stdfloat, PN_stdfloat, PN_stdfloat, PN_stdfloat) {
275 return false;
276 }
277
278 /**
279 * Recalculates the curve, if necessary. Returns true if the resulting curve
280 * is valid, false otherwise.
281 */
282 bool ParametricCurve::
283 recompute() {
284 return is_valid();
285 }
286
287 /**
288 * Regenerates this curve as one long curve: the first curve connected end-to-
289 * end with the second one. Either a or b may be the same as 'this'.
290 *
291 * Returns true if successful, false on failure or if the curve type does not
292 * support stitching.
293 */
294 bool ParametricCurve::
295 stitch(const ParametricCurve *, const ParametricCurve *) {
296 parametrics_cat.error()
297 << get_type() << " does not support stitching.\n";
298 return false;
299 }
300
301
302 /**
303 * Writes an egg description of the nurbs curve to the specified output file.
304 * Returns true if the file is successfully written.
305 */
306 bool ParametricCurve::
307 write_egg(Filename filename, CoordinateSystem cs) {
308 pofstream out;
309 filename.set_text();
310
311 if (!filename.open_write(out)) {
312 parametrics_cat.error()
313 << "Unable to write to " << filename << "\n";
314 return false;
315 }
316 return write_egg(out, filename, cs);
317 }
318
319 /**
320 * Writes an egg description of the nurbs curve to the specified output
321 * stream. Returns true if the file is successfully written.
322 */
323 bool ParametricCurve::
324 write_egg(std::ostream &out, const Filename &filename, CoordinateSystem cs) {
325 std::string curve_type;
326 switch (get_curve_type()) {
327 case PCT_XYZ:
328 curve_type = "xyz";
329 break;
330
331 case PCT_HPR:
332 curve_type = "hpr";
333 break;
334
335 case PCT_T:
336 curve_type = "t";
337 break;
338 }
339
340 if (!has_name()) {
341 // If we don't have a name, come up with one.
342 std::string name = filename.get_basename_wo_extension();
343
344 if (!curve_type.empty()) {
345 name += "_";
346 name += curve_type;
347 }
348
349 set_name(name);
350 }
351
352 if (cs == CS_default) {
353 cs = get_default_coordinate_system();
354 }
355
356 if (cs != CS_invalid) {
357 out << "<CoordinateSystem> { ";
358 switch (cs) {
359 case CS_zup_right:
360 out << "Z-Up";
361 break;
362
363 case CS_yup_right:
364 out << "Y-Up";
365 break;
366
367 case CS_zup_left:
368 out << "Z-Up-Left";
369 break;
370
371 case CS_yup_left:
372 out << "Y-Up-Left";
373 break;
374
375 default:
376 break;
377 }
378 out << " }\n\n";
379 }
380
381
382 if (!format_egg(out, get_name(), curve_type, 0)) {
383 return false;
384 }
385
386 if (out) {
387 return true;
388 } else {
389 return false;
390 }
391 }
392
393
394
395 /**
396 * Fills up the indicated vector with a list of BezierSeg structs that
397 * describe the curve. This assumes the curve is a PiecewiseCurve of
398 * CubicCurvesegs. Returns true if successful, false otherwise.
399 */
400 bool ParametricCurve::
401 get_bezier_segs(ParametricCurve::BezierSegs &) const {
402 return false;
403 }
404
405 /**
406 * Fills the BezierSeg structure with a description of the curve segment as a
407 * Bezier, if possible, but does not change the _t member of the structure.
408 * Returns true if successful, false otherwise.
409 */
410 bool ParametricCurve::
411 get_bezier_seg(ParametricCurve::BezierSeg &) const {
412 return false;
413 }
414
415 /**
416 * Returns a pointer to the object as a NurbsCurveInterface object if it
417 * happens to be a NURBS-style curve; otherwise, returns NULL.
418 */
419 NurbsCurveInterface *ParametricCurve::
420 get_nurbs_interface() {
421 return nullptr;
422 }
423
424 /**
425 * Stores an equivalent curve representation in the indicated Hermite curve,
426 * if possible. Returns true if successful, false otherwise.
427 */
428 bool ParametricCurve::
429 convert_to_hermite(HermiteCurve *hc) const {
430 BezierSegs bz_segs;
431 if (!get_bezier_segs(bz_segs)) {
432 return false;
433 }
434
435 hc->set_curve_type(_curve_type);
436
437 // Now convert the Bezier segments to a Hermite. Normally, the Beziers will
438 // match up head-to-tail, but if they don't, that's a cut.
439 hc->remove_all_cvs();
440
441 int i, n;
442 if (!bz_segs.empty()) {
443 PN_stdfloat scale_in = 0.0f;
444 PN_stdfloat scale_out = bz_segs[0]._t;
445 n = hc->append_cv(HC_SMOOTH, bz_segs[0]._v[0]);
446 hc->set_cv_out(n, 3.0f * (bz_segs[0]._v[1] - bz_segs[0]._v[0]) / scale_out);
447
448 for (i = 0; i < (int)bz_segs.size()-1; i++) {
449 scale_in = scale_out;
450 scale_out = bz_segs[i+1]._t - bz_segs[i]._t;
451
452 if (!bz_segs[i]._v[3].almost_equal(bz_segs[i+1]._v[0], 0.0001f)) {
453 // Oops, we have a cut.
454 hc->set_cv_type(n, HC_CUT);
455 }
456
457 n = hc->append_cv(HC_FREE, bz_segs[i+1]._v[0]);
458 hc->set_cv_in(n, 3.0f * (bz_segs[i]._v[3] - bz_segs[i]._v[2]) / scale_in);
459 hc->set_cv_tstart(n, bz_segs[i]._t);
460
461 hc->set_cv_out(n, 3.0f * (bz_segs[i+1]._v[1] - bz_segs[i+1]._v[0]) / scale_out);
462 }
463
464 // Now the last CV.
465 scale_in = scale_out;
466 i = bz_segs.size()-1;
467 n = hc->append_cv(HC_SMOOTH, bz_segs[i]._v[3]);
468 hc->set_cv_in(n, 3.0f * (bz_segs[i]._v[3] - bz_segs[i]._v[2]) / scale_in);
469 hc->set_cv_tstart(n, bz_segs[i]._t);
470 }
471
472 // Finally, go through and figure out which CV's are smooth or G1.
473 int num_cvs = hc->get_num_cvs();
474 for (n = 1; n < num_cvs-1; n++) {
475 if (hc->get_cv_type(n)!=HC_CUT) {
476 LVector3 in = hc->get_cv_in(n);
477 LVector3 out = hc->get_cv_out(n);
478
479 if (in.almost_equal(out, 0.0001f)) {
480 hc->set_cv_type(n, HC_SMOOTH);
481 } else {
482 in.normalize();
483 out.normalize();
484 if (in.almost_equal(out, 0.0001f)) {
485 hc->set_cv_type(n, HC_G1);
486 }
487 }
488 }
489 }
490 return true;
491 }
492
493 /**
494 * Stores in the indicated NurbsCurve a NURBS representation of an equivalent
495 * curve. Returns true if successful, false otherwise.
496 */
497 bool ParametricCurve::
498 convert_to_nurbs(ParametricCurve *nc) const {
499 NurbsCurveInterface *nurbs = nc->get_nurbs_interface();
500 nassertr(nurbs != nullptr, false);
501
502 BezierSegs bz_segs;
503 if (!get_bezier_segs(bz_segs)) {
504 return false;
505 }
506
507 nc->set_curve_type(_curve_type);
508
509 nurbs->remove_all_cvs();
510 nurbs->set_order(4);
511 if (!bz_segs.empty()) {
512 int i;
513 for (i = 0; i < (int)bz_segs.size(); i++) {
514 nurbs->append_cv(bz_segs[i]._v[0]);
515 nurbs->append_cv(bz_segs[i]._v[1]);
516 nurbs->append_cv(bz_segs[i]._v[2]);
517 if (i == (int)bz_segs.size()-1 ||
518 !bz_segs[i]._v[3].almost_equal(bz_segs[i+1]._v[0], 0.0001f)) {
519 nurbs->append_cv(bz_segs[i]._v[3]);
520 }
521 }
522
523 PN_stdfloat t;
524 int ki = 4;
525 nurbs->set_knot(0, 0.0f);
526 nurbs->set_knot(1, 0.0f);
527 nurbs->set_knot(2, 0.0f);
528 nurbs->set_knot(3, 0.0f);
529
530 for (i = 0; i < (int)bz_segs.size(); i++) {
531 t = bz_segs[i]._t;
532
533 nurbs->set_knot(ki, t);
534 nurbs->set_knot(ki+1, t);
535 nurbs->set_knot(ki+2, t);
536 ki += 3;
537 if (i == ((int)bz_segs.size())-1 ||
538 !bz_segs[i]._v[3].almost_equal(bz_segs[i+1]._v[0], 0.0001f)) {
539 nurbs->set_knot(ki, t);
540 ki++;
541 }
542 }
543 }
544
545 return nc->recompute();
546 }
547
548
549 /**
550 * Registers a Drawer with this curve that will automatically be updated
551 * whenever the curve is modified, so that the visible representation of the
552 * curve is kept up to date. This is called automatically by the
553 * ParametricCurveDrawer.
554 *
555 * Any number of Drawers may be registered with a particular curve.
556 */
557 void ParametricCurve::
558 register_drawer(ParametricCurveDrawer *drawer) {
559 _drawers.push_back(drawer);
560 }
561
562 /**
563 * Removes a previously registered drawer from the list of automatically-
564 * refreshed drawers. This is called automatically by the
565 * ParametricCurveDrawer.
566 */
567 void ParametricCurve::
568 unregister_drawer(ParametricCurveDrawer *drawer) {
569 _drawers.remove(drawer);
570 }
571
572
573
574
575 /**
576 * Called from a base class to mark a section of the curve that has been
577 * modified and must be redrawn or recomputed in some way.
578 */
579 void ParametricCurve::
580 invalidate(PN_stdfloat, PN_stdfloat) {
581 invalidate_all();
582 }
583
584 /**
585 * Called from a base class to indicate that the curve has changed in some
586 * substantial way and must be entirely redrawn.
587 */
588 void ParametricCurve::
589 invalidate_all() {
590 /*
591 DrawerList::iterator n;
592 for (n = _drawers.begin();
593 n != _drawers.end();
594 ++n) {
595 (*n)->redraw();
596 }
597 */
598 }
599
600 /**
601 * Formats the curve as an egg structure to write to the indicated stream.
602 * Returns true on success, false on failure.
603 */
604 bool ParametricCurve::
605 format_egg(std::ostream &, const std::string &, const std::string &, int) const {
606 return false;
607 }
608
609
610 /**
611 * The recursive implementation of calc_length. This function calculates the
612 * length of a segment of the curve between points t1 and t2, which presumably
613 * evaluate to the endpoints p1 and p2, and the segment has the length
614 * seglength.
615 */
616 PN_stdfloat ParametricCurve::
617 r_calc_length(PN_stdfloat t1, PN_stdfloat t2, const LPoint3 &p1, const LPoint3 &p2,
618 PN_stdfloat seglength) const {
619 static const PN_stdfloat length_tolerance = 0.0000001f;
620 static const PN_stdfloat t_tolerance = 0.000001f;
621
622 if (t2 - t1 < t_tolerance) {
623 // Stop recursing--we've just walked off the limit for representing
624 // smaller values of t.
625 return 0.0f;
626 }
627
628 PN_stdfloat tmid;
629 LPoint3 pmid;
630 PN_stdfloat left, right;
631
632 // Calculate the point on the curve midway between the two endpoints.
633 tmid = (t1+t2)*0.5f;
634 get_point(tmid, pmid);
635
636 // Did we increase the length of the segment measurably?
637 left = (p1 - pmid).length();
638 right = (pmid - p2).length();
639
640 if ((left + right) - seglength < length_tolerance) {
641 // No. We're done.
642 return seglength;
643 } else {
644 // Yes. Keep going.
645 return r_calc_length(t1, tmid, p1, pmid, left) +
646 r_calc_length(tmid, t2, pmid, p2, right);
647 }
648 }
649
650 /**
651 * The recursive implementation of find_length. This is similar to
652 * r_calc_length, above. target_length is the length along the curve past t1
653 * that we hope to find. If the indicated target_length falls within this
654 * segment, returns true and sets found_t to the point along the segment.
655 * Otherwise, updates seglength with the accurate calculated length of the
656 * segment and returns false.
657 */
658 bool ParametricCurve::
659 r_find_length(PN_stdfloat target_length, PN_stdfloat &found_t,
660 PN_stdfloat t1, PN_stdfloat t2,
661 const LPoint3 &p1, const LPoint3 &p2,
662 PN_stdfloat &seglength) const {
663 static const PN_stdfloat length_tolerance = 0.0000001f;
664 static const PN_stdfloat t_tolerance = 0.000001f;
665
666 if (target_length < t_tolerance) {
667 // Stop recursing--we've just walked off the limit for representing
668 // smaller values of t.
669 found_t = t1;
670 return true;
671
672 }
673
674 PN_stdfloat tmid;
675 LPoint3 pmid;
676 PN_stdfloat left, right;
677
678 // Calculate the point on the curve midway between the two endpoints.
679 tmid = (t1+t2)*0.5f;
680 get_point(tmid, pmid);
681
682 // Did we increase the length of the segment measurably?
683 left = (p1 - pmid).length();
684 right = (pmid - p2).length();
685
686 if ((left + right) - seglength < length_tolerance) {
687 // No. Curve is relatively straight over this interval.
688 return find_t_linear(target_length, found_t, t1, t2, p1, p2);
689 /*
690 if (target_length <= seglength) {
691 // Compute t value that corresponds to target_length Maybe the point is
692 // in the left half of the segment?
693 if (r_find_t(target_length, found_t, t1, tmid, p1, pmid)) {
694 return true;
695 }
696 // Maybe it's on the right half?
697 if (r_find_t(target_length - left, found_t, tmid, t2, pmid, p2)) {
698 return true;
699 }
700 }
701 return false;
702 */
703 } else {
704 // Yes. Keep going.
705
706 // Maybe the point is in the left half of the segment?
707 if (r_find_length(target_length, found_t, t1, tmid, p1, pmid, left)) {
708 return true;
709 }
710
711 // Maybe it's on the right half?
712 if (r_find_length(target_length - left, found_t, tmid, t2, pmid, p2, right)) {
713 return true;
714 }
715
716 // Neither. Keep going.
717 seglength = left + right;
718 return false;
719 }
720 }
721
722
723
724 /**
725 * computes the t value in the parametric domain of a target point along a
726 * straight section of a curve. This is similar to r_calc_length, above.
727 * target_length is the length along the curve past t1 that we hope to find.
728 * If the indicated target_length falls within this segment, returns true and
729 * sets found_t to the point along the segment.
730 */
731 bool ParametricCurve::
732 r_find_t(PN_stdfloat target_length, PN_stdfloat &found_t,
733 PN_stdfloat t1, PN_stdfloat t2,
734 const LPoint3 &p1, const LPoint3 &p2) const {
735 static const PN_stdfloat length_tolerance = 0.0001f;
736 static const PN_stdfloat t_tolerance = 0.0001f;
737
738 if (parametrics_cat.is_spam()) {
739 parametrics_cat.spam()
740 << "target_length " << target_length << " t1 " << t1 << " t2 " << t2 << "\n";
741 }
742
743 // Is the target point close to the near endpoint
744 if (target_length < length_tolerance) {
745 found_t = t1;
746 return true;
747 }
748
749 // No, compute distance between two endpoints
750 PN_stdfloat point_dist;
751 point_dist = (p2 - p1).length();
752
753 // Is the target point past the far endpoint?
754 if (point_dist < target_length) {
755 return false;
756 }
757
758 // Is the target point close to far endpoint?
759 if ( (point_dist - target_length ) < length_tolerance ) {
760 found_t = t2;
761 return true;
762 }
763
764 // are we running out of parametric precision?
765 if ((t2 - t1) < t_tolerance) {
766 found_t = t1;
767 return true;
768 }
769
770 // No, subdivide and continue
771 PN_stdfloat tmid;
772 LPoint3 pmid;
773 PN_stdfloat left;
774
775 // Calculate the point on the curve midway between the two endpoints.
776 tmid = (t1+t2)*0.5f;
777 get_point(tmid, pmid);
778
779 // Maybe the point is in the left half of the segment?
780 if (r_find_t(target_length, found_t, t1, tmid, p1, pmid)) {
781 return true;
782 }
783 // Nope, must be in the right half
784 left = (p1 - pmid).length();
785 if (r_find_t(target_length - left, found_t, tmid, t2, pmid, p2)) {
786 return true;
787 }
788
789 // not found in either half, keep looking
790 return false;
791 }
792
793
794 /**
795 * non-recursive version of r_find_t (see above)
796 */
797 bool ParametricCurve::
798 find_t_linear(PN_stdfloat target_length, PN_stdfloat &found_t,
799 PN_stdfloat t1, PN_stdfloat t2,
800 const LPoint3 &p1, const LPoint3 &p2) const {
801 const PN_stdfloat length_tolerance = (p1-p2).length()/tolerance_divisor;
802 const PN_stdfloat t_tolerance = (t1+t2)/tolerance_divisor;
803
804 if (parametrics_cat.is_spam()) {
805 parametrics_cat.spam()
806 << "target_length " << target_length << " t1 " << t1 << " t2 " << t2 << "\n";
807 }
808
809 // first, check to make sure this segment contains the point we're looking
810 // for
811 if (target_length > (p1 - p2).length()) {
812 // segment is too short
813 return false;
814 }
815
816 PN_stdfloat tleft = t1;
817 PN_stdfloat tright = t2;
818 PN_stdfloat tmid;
819 LPoint3 pmid;
820 PN_stdfloat len;
821
822 while (1) {
823 tmid = (tleft + tright) * 0.5f;
824 get_point(tmid, pmid);
825 len = (pmid - p1).length();
826
827 /*
828 if (parametrics_cat.is_spam()) {
829 parametrics_cat.spam()
830 << "tleft " << tleft << " tright " << tright <<
831 " tmid " << tmid << " len " << len << endl;
832 }
833 */
834
835 // is our midpoint at the right distance?
836 if (fabs(len - target_length) < length_tolerance) {
837 found_t = tmid;
838 return true;
839 }
840
841 /*
842 if (parametrics_cat.is_spam()) {
843 parametrics_cat.spam()
844 << "tright-tleft " << tright-tleft << " t_tolerance " << t_tolerance << endl;
845 }
846 */
847
848 // are we out of parametric precision?
849 if ((tright - tleft) < t_tolerance) {
850 // unfortunately, we can't get any closer in parametric space
851 found_t = tmid;
852 return true;
853 }
854
855 // should we look closer or farther?
856 if (len > target_length) {
857 // look closer
858 tright = tmid;
859 } else {
860 // look farther
861 tleft = tmid;
862 }
863 }
864 }
865
866
867 /**
868 * Function to write the important information in the particular object to a
869 * Datagram
870 */
871 void ParametricCurve::
872 write_datagram(BamWriter *manager, Datagram &me) {
873 PandaNode::write_datagram(manager, me);
874
875 me.add_int8(_curve_type);
876 me.add_int8(_num_dimensions);
877 }
878
879 /**
880 * Function that reads out of the datagram (or asks manager to read) all of
881 * the data that is needed to re-create this object and stores it in the
882 * appropiate place
883 */
884 void ParametricCurve::
885 fillin(DatagramIterator &scan, BamReader *manager) {
886 PandaNode::fillin(scan, manager);
887
888 _curve_type = scan.get_int8();
889 _num_dimensions = scan.get_int8();
890 }
bamReader.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bamWriter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
BamReader
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
BamWriter
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
DatagramIterator
A class to retrieve the individual data elements previously stored in a Datagram.
Definition: datagramIterator.h:27
DatagramIterator::get_int8
int8_t get_int8()
Extracts a signed 8-bit integer.
Definition: datagramIterator.I:56
Datagram
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
Datagram::add_int8
void add_int8(int8_t value)
Adds a signed 8-bit integer to the datagram.
Definition: datagram.I:42
Filename
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
Filename::set_text
void set_text()
Indicates that the filename represents a text file.
Definition: filename.I:424
Filename::open_write
bool open_write(std::ofstream &stream, bool truncate=true) const
Opens the indicated ifstream for writing the file, if possible.
Definition: filename.cxx:1899
Filename::get_basename_wo_extension
std::string get_basename_wo_extension() const
Returns the basename part of the filename, without the file extension.
Definition: filename.I:386
HermiteCurve
A parametric curve defined by a sequence of control vertices, each with an in and out tangent.
Definition: hermiteCurve.h:83
HermiteCurve::append_cv
int append_cv(int type, PN_stdfloat x, PN_stdfloat y, PN_stdfloat z)
Adds a new CV to the end of the curve.
Definition: hermiteCurve.cxx:325
HermiteCurve::set_cv_out
bool set_cv_out(int n, PN_stdfloat x, PN_stdfloat y, PN_stdfloat z)
Changes the given CV's out tangent.
Definition: hermiteCurve.cxx:442
HermiteCurve::set_cv_tstart
bool set_cv_tstart(int n, PN_stdfloat tstart)
Changes the given CV's parametric starting time.
Definition: hermiteCurve.cxx:456
HermiteCurve::get_cv_out
const LVecBase3 & get_cv_out(int n) const
Returns the out tangent of the given CV.
Definition: hermiteCurve.cxx:535
HermiteCurve::get_num_cvs
int get_num_cvs() const
Returns the number of CV's in the curve.
Definition: hermiteCurve.cxx:273
HermiteCurve::set_cv_in
bool set_cv_in(int n, PN_stdfloat x, PN_stdfloat y, PN_stdfloat z)
Changes the given CV's in tangent.
Definition: hermiteCurve.cxx:428
HermiteCurve::get_cv_type
int get_cv_type(int n) const
Returns the given CV's continuity type, HC_CUT, HC_FREE, HC_G1, or HC_SMOOTH, or 0 if there is no suc...
Definition: hermiteCurve.cxx:488
HermiteCurve::remove_all_cvs
void remove_all_cvs()
Removes all CV's from the curve.
Definition: hermiteCurve.cxx:370
HermiteCurve::set_cv_type
bool set_cv_type(int n, int type)
Changes the given CV's continuity type.
Definition: hermiteCurve.cxx:393
HermiteCurve::get_cv_in
const LVecBase3 & get_cv_in(int n) const
Returns the in tangent of the given CV.
Definition: hermiteCurve.cxx:518
Namable::has_name
bool has_name() const
Returns true if the Namable has a nonempty name set, false if the name is empty.
Definition: namable.I:44
NurbsCurveInterface
This abstract class defines the interface only for a Nurbs-style curve, with knots and coordinates in...
Definition: nurbsCurveInterface.h:30
PandaNode
A basic node of the scene graph or data graph.
Definition: pandaNode.h:65
PandaNode::write_datagram
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
Definition: pandaNode.cxx:3583
ParametricCurve
A virtual base class for parametric curves.
Definition: parametricCurve.h:56
ParametricCurve::adjust_pt
virtual bool adjust_pt(PN_stdfloat t, PN_stdfloat px, PN_stdfloat py, PN_stdfloat pz, PN_stdfloat tx, PN_stdfloat ty, PN_stdfloat tz)
Recomputes the curve such that it passes through the point (px, py, pz) with the tangent (tx,...
Definition: parametricCurve.cxx:274
ParametricCurve::adjust_tangent
virtual bool adjust_tangent(PN_stdfloat t, PN_stdfloat tx, PN_stdfloat ty, PN_stdfloat tz)
Recomputes the curve such that it has the tangent (tx, ty, tz) at time t, but keeps the same position...
Definition: parametricCurve.cxx:265
ParametricCurve::calc_length
PN_stdfloat calc_length() const
Approximates the length of the entire curve to within a few decimal places.
Definition: parametricCurve.cxx:160
ParametricCurve::get_curve_type
int get_curve_type() const
Returns the flag indicating the use to which the curve is intended to be put.
Definition: parametricCurve.cxx:128
ParametricCurve::recompute
virtual bool recompute()
Recalculates the curve, if necessary.
Definition: parametricCurve.cxx:283
ParametricCurve::get_num_dimensions
int get_num_dimensions() const
Returns the number of significant dimensions in the curve's vertices, as set by a previous call to se...
Definition: parametricCurve.cxx:151
ParametricCurve::convert_to_nurbs
virtual bool convert_to_nurbs(ParametricCurve *nc) const
Stores in the indicated NurbsCurve a NURBS representation of an equivalent curve.
Definition: parametricCurve.cxx:498
ParametricCurve::get_nurbs_interface
virtual NurbsCurveInterface * get_nurbs_interface()
Returns a pointer to the object as a NurbsCurveInterface object if it happens to be a NURBS-style cur...
Definition: parametricCurve.cxx:420
ParametricCurve::get_bezier_seg
virtual bool get_bezier_seg(BezierSeg &) const
Fills the BezierSeg structure with a description of the curve segment as a Bezier,...
Definition: parametricCurve.cxx:411
ParametricCurve::get_bezier_segs
virtual bool get_bezier_segs(BezierSegs &) const
Fills up the indicated vector with a list of BezierSeg structs that describe the curve.
Definition: parametricCurve.cxx:401
ParametricCurve::ParametricCurve
ParametricCurve()
This is a virtual base class.
Definition: parametricCurve.cxx:34
ParametricCurve::adjust_point
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,...
Definition: parametricCurve.cxx:256
ParametricCurve::get_max_t
virtual PN_stdfloat get_max_t() const
Returns the upper bound of t for the entire curve.
Definition: parametricCurve.cxx:89
ParametricCurve::set_curve_type
void set_curve_type(int type)
Sets the flag indicating the use to which the curve is intended to be put.
Definition: parametricCurve.cxx:105
ParametricCurve::safe_to_transform
virtual bool safe_to_transform() const
Returns true if it is generally safe to transform this particular kind of PandaNode by calling the xf...
Definition: parametricCurve.cxx:68
ParametricCurve::is_valid
virtual bool is_valid() const
Returns true if the curve is defined.
Definition: parametricCurve.cxx:78
ParametricCurve::register_drawer
void register_drawer(ParametricCurveDrawer *drawer)
Registers a Drawer with this curve that will automatically be updated whenever the curve is modified,...
Definition: parametricCurve.cxx:558
ParametricCurve::write_egg
bool write_egg(Filename filename, CoordinateSystem cs=CS_default)
Writes an egg description of the nurbs curve to the specified output file.
Definition: parametricCurve.cxx:307
ParametricCurve::set_num_dimensions
void set_num_dimensions(int num)
Specifies the number of significant dimensions in the curve's vertices.
Definition: parametricCurve.cxx:140
ParametricCurve::stitch
virtual bool stitch(const ParametricCurve *a, const ParametricCurve *b)
Regenerates this curve as one long curve: the first curve connected end-to- end with the second one.
Definition: parametricCurve.cxx:295
ParametricCurve::safe_to_flatten
virtual bool safe_to_flatten() const
Returns true if it is generally safe to flatten out this particular kind of PandaNode by duplicating ...
Definition: parametricCurve.cxx:58
ParametricCurve::unregister_drawer
void unregister_drawer(ParametricCurveDrawer *drawer)
Removes a previously registered drawer from the list of automatically- refreshed drawers.
Definition: parametricCurve.cxx:568
ParametricCurve::convert_to_hermite
virtual bool convert_to_hermite(HermiteCurve *hc) const
Stores an equivalent curve representation in the indicated Hermite curve, if possible.
Definition: parametricCurve.cxx:429
ParametricCurve::find_length
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...
Definition: parametricCurve.cxx:212
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
pvector
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:42
config_parametrics.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
datagramIterator.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
datagram.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
hermiteCurve.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
nurbsCurve.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
omniBoundingVolume.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
parametricCurve.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
ParametricCurve::BezierSeg
Definition: parametricCurve.h:99