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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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 }
Filename::set_text
void set_text()
Indicates that the filename represents a text file.
Definition: filename.I:424
NurbsCurveInterface
This abstract class defines the interface only for a Nurbs-style curve, with knots and coordinates in...
Definition: nurbsCurveInterface.h:30
HermiteCurve::remove_all_cvs
void remove_all_cvs()
Removes all CV's from the curve.
Definition: hermiteCurve.cxx:370
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
pvector
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:42
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
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
ParametricCurve::recompute
virtual bool recompute()
Recalculates the curve, if necessary.
Definition: parametricCurve.cxx:283
DatagramIterator
A class to retrieve the individual data elements previously stored in a Datagram.
Definition: datagramIterator.h:27
parametricCurve.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
HermiteCurve::set_cv_type
bool set_cv_type(int n, int type)
Changes the given CV's continuity type.
Definition: hermiteCurve.cxx:393
BamReader
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
ParametricCurve
A virtual base class for parametric curves.
Definition: parametricCurve.h:56
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
HermiteCurve
A parametric curve defined by a sequence of control vertices, each with an in and out tangent.
Definition: hermiteCurve.h:83
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
BamWriter
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
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::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::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::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
bamReader.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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::BezierSeg
Definition: parametricCurve.h:99
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
Datagram
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
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
nurbsCurve.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
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
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
HermiteCurve::get_cv_in
const LVecBase3 & get_cv_in(int n) const
Returns the in tangent of the given CV.
Definition: hermiteCurve.cxx:518
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::is_valid
virtual bool is_valid() const
Returns true if the curve is defined.
Definition: parametricCurve.cxx:78
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
DatagramIterator::get_int8
int8_t get_int8()
Extracts a signed 8-bit integer.
Definition: datagramIterator.I:56
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::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
config_parametrics.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
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
datagram.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
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
ParametricCurve::ParametricCurve
ParametricCurve()
This is a virtual base class.
Definition: parametricCurve.cxx:34
omniBoundingVolume.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
Datagram::add_int8
void add_int8(int8_t value)
Adds a signed 8-bit integer to the datagram.
Definition: datagram.I:42
datagramIterator.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
HermiteCurve::get_num_cvs
int get_num_cvs() const
Returns the number of CV's in the curve.
Definition: hermiteCurve.cxx:273
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
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
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
bamWriter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PandaNode
A basic node of the scene graph or data graph.
Definition: pandaNode.h:64
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
Filename
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
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
hermiteCurve.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
HermiteCurve::get_cv_out
const LVecBase3 & get_cv_out(int n) const
Returns the out tangent of the given CV.
Definition: hermiteCurve.cxx:535