ETL  0.04.19
_bezier.h
Go to the documentation of this file.
1 
26 /* === S T A R T =========================================================== */
27 
28 #ifndef __ETL__BEZIER_H
29 #define __ETL__BEZIER_H
30 
31 /* === H E A D E R S ======================================================= */
32 
33 #include "_curve_func.h"
34 #include <cmath> // for ldexp
35 // #include <ETL/fixed> // not used
36 
37 /* === M A C R O S ========================================================= */
38 
39 #define MAXDEPTH 64 /* Maximum depth for recursion */
40 
41 /* take binary sign of a, either -1, or 1 if >= 0 */
42 #define SGN(a) (((a)<0) ? -1 : 1)
43 
44 /* find minimum of a and b */
45 #ifndef MIN
46 #define MIN(a,b) (((a)<(b))?(a):(b))
47 #endif
48 
49 /* find maximum of a and b */
50 #ifndef MAX
51 #define MAX(a,b) (((a)>(b))?(a):(b))
52 #endif
53 
54 #define BEZIER_EPSILON (ldexp(1.0,-MAXDEPTH-1)) /*Flatness control value */
55 //#define BEZIER_EPSILON 0.00005 /*Flatness control value */
56 #define DEGREE 3 /* Cubic Bezier curve */
57 #define W_DEGREE 5 /* Degree of eqn to find roots of */
58 
59 /* === T Y P E D E F S ===================================================== */
60 
61 /* === C L A S S E S & S T R U C T S ======================================= */
62 
64 
65 template<typename V,typename T> class bezier;
66 
68 // This generic implementation uses the DeCasteljau algorithm.
69 // Works for just about anything that has an affine combination function
70 template <typename V,typename T=float>
71 class bezier_base : public std::unary_function<T,V>
72 {
73 public:
74  typedef V value_type;
75  typedef T time_type;
76 
77 private:
80 
81 protected:
83 
84 public:
85  bezier_base():r(0.0),s(1.0) { }
87  const value_type &a, const value_type &b, const value_type &c, const value_type &d,
88  const time_type &r=0.0, const time_type &s=1.0):
89  a(a),b(b),c(c),d(d),r(r),s(s) { sync(); }
90 
91  void sync()
92  {
93  }
94 
97  {
98  t=(t-r)/(s-r);
99  return
100  affine_func(
101  affine_func(
102  affine_func(a,b,t),
103  affine_func(b,c,t)
104  ,t),
105  affine_func(
106  affine_func(b,c,t),
107  affine_func(c,d,t)
108  ,t)
109  ,t);
110  }
111 
112  /*
113  void evaluate(time_type t, value_type &f, value_type &df) const
114  {
115  t=(t-r)/(s-r);
116 
117  value_type p1 = affine_func(
118  affine_func(a,b,t),
119  affine_func(b,c,t)
120  ,t);
121  value_type p2 = affine_func(
122  affine_func(b,c,t),
123  affine_func(c,d,t)
124  ,t);
125 
126  f = affine_func(p1,p2,t);
127  df = (p2-p1)*3;
128  }
129  */
130 
131  void set_rs(time_type new_r, time_type new_s) { r=new_r; s=new_s; }
132  void set_r(time_type new_r) { r=new_r; }
133  void set_s(time_type new_s) { s=new_s; }
134  const time_type &get_r()const { return r; }
135  const time_type &get_s()const { return s; }
136  time_type get_dt()const { return s-r; }
137 
139  {
140  return 0;
141  }
142 
144 
165  {
166  return 0;
167  }
168 
169  /* subdivide at some time t into 2 separate curves left and right
170 
171  b0 l1
172  * 0+1 l2
173  b1 * 1+2*1+2 l3
174  * 1+2 * 0+3*1+3*2+3 l4,r1
175  b2 * 1+2*2+2 r2 *
176  * 2+3 r3 *
177  b3 r4 *
178  *
179 
180  0.1 2.3 -> 0.1 2 3 4 5.6
181  */
182 /* void subdivide(bezier_base *left, bezier_base *right, const time_type &time = (time_type)0.5) const
183  {
184  time_type t = (time-r)/(s-r);
185  bezier_base lt,rt;
186 
187  value_type temp;
188 
189  //1st stage points to keep
190  lt.a = a;
191  rt.d = d;
192 
193  //2nd stage calc
194  lt.b = affine_func(a,b,t);
195  temp = affine_func(b,c,t);
196  rt.c = affine_func(c,d,t);
197 
198  //3rd stage calc
199  lt.c = affine_func(lt.b,temp,t);
200  rt.b = affine_func(temp,rt.c,t);
201 
202  //last stage calc
203  lt.d = rt.a = affine_func(lt.c,rt.b,t);
204 
205  //set the time range for l,r (the inside values should be 1, 0 respectively)
206  lt.r = r;
207  rt.s = s;
208 
209  //give back the curves
210  if(left) *left = lt;
211  if(right) *right = rt;
212  }
213  */
214  value_type &
215  operator[](int i)
216  { return (&a)[i]; }
217 
218  const value_type &
219  operator[](int i) const
220  { return (&a)[i]; }
221 };
222 
223 
224 #if 1
225 // Fast float implementation of a cubic bezier curve
226 template <>
227 class bezier_base<float,float> : public std::unary_function<float,float>
228 {
229 public:
230  typedef float value_type;
231  typedef float time_type;
232 private:
233  // affine_combo<value_type,time_type> affine_func;
236 
237  value_type _coeff[4];
238  time_type drs; // reciprocal of (s-r)
239 public:
240  bezier_base():r(0.0),s(1.0),drs(1.0) { }
242  const value_type &a, const value_type &b, const value_type &c, const value_type &d,
243  const time_type &r=0.0, const time_type &s=1.0):
244  a(a),b(b),c(c),d(d),r(r),s(s),drs(1.0/(s-r)) { sync(); }
245 
246  void sync()
247  {
248 // drs=1.0/(s-r);
249  _coeff[0]= a;
250  _coeff[1]= b*3 - a*3;
251  _coeff[2]= c*3 - b*6 + a*3;
252  _coeff[3]= d - c*3 + b*3 - a;
253  }
254 
255  // Cost Summary: 4 products, 3 sums, and 1 difference.
256  inline value_type
258  { t-=r; t*=drs; return _coeff[0]+(_coeff[1]+(_coeff[2]+(_coeff[3])*t)*t)*t; }
259 
260  void set_rs(time_type new_r, time_type new_s) { r=new_r; s=new_s; drs=1.0/(s-r); }
261  void set_r(time_type new_r) { r=new_r; drs=1.0/(s-r); }
262  void set_s(time_type new_s) { s=new_s; drs=1.0/(s-r); }
263  const time_type &get_r()const { return r; }
264  const time_type &get_s()const { return s; }
265  time_type get_dt()const { return s-r; }
266 
268 
272  {
273  //BROKEN - the time values of the 2 curves should be independent
274  value_type system[4];
275  system[0]=_coeff[0]-x._coeff[0];
276  system[1]=_coeff[1]-x._coeff[1];
277  system[2]=_coeff[2]-x._coeff[2];
278  system[3]=_coeff[3]-x._coeff[3];
279 
280  t-=r;
281  t*=drs;
282 
283  // Newton's method
284  // Inner loop cost summary: 7 products, 5 sums, 1 difference
285  for(;i;i--)
286  t-= (system[0]+(system[1]+(system[2]+(system[3])*t)*t)*t)/
287  (system[1]+(system[2]*2+(system[3]*3)*t)*t);
288 
289  t*=(s-r);
290  t+=r;
291 
292  return t;
293  }
294 
295  value_type &
296  operator[](int i)
297  { return (&a)[i]; }
298 
299  const value_type &
300  operator[](int i) const
301  { return (&a)[i]; }
302 };
303 
304 
305 // Fast double implementation of a cubic bezier curve
306 template <>
307 class bezier_base<double,float> : public std::unary_function<float,double>
308 {
309 public:
310  typedef double value_type;
311  typedef float time_type;
312 private:
313  // affine_combo<value_type,time_type> affine_func;
316 
317  value_type _coeff[4];
318  time_type drs; // reciprocal of (s-r)
319 public:
320  bezier_base():r(0.0),s(1.0),drs(1.0) { }
322  const value_type &a, const value_type &b, const value_type &c, const value_type &d,
323  const time_type &r=0.0, const time_type &s=1.0):
324  a(a),b(b),c(c),d(d),r(r),s(s),drs(1.0/(s-r)) { sync(); }
325 
326  void sync()
327  {
328 // drs=1.0/(s-r);
329  _coeff[0]= a;
330  _coeff[1]= b*3 - a*3;
331  _coeff[2]= c*3 - b*6 + a*3;
332  _coeff[3]= d - c*3 + b*3 - a;
333  }
334 
335  // 4 products, 3 sums, and 1 difference.
336  inline value_type
338  { t-=r; t*=drs; return _coeff[0]+(_coeff[1]+(_coeff[2]+(_coeff[3])*t)*t)*t; }
339 
340  void set_rs(time_type new_r, time_type new_s) { r=new_r; s=new_s; drs=1.0/(s-r); }
341  void set_r(time_type new_r) { r=new_r; drs=1.0/(s-r); }
342  void set_s(time_type new_s) { s=new_s; drs=1.0/(s-r); }
343  const time_type &get_r()const { return r; }
344  const time_type &get_s()const { return s; }
345  time_type get_dt()const { return s-r; }
346 
348 
352  {
353  //BROKEN - the time values of the 2 curves should be independent
354  value_type system[4];
355  system[0]=_coeff[0]-x._coeff[0];
356  system[1]=_coeff[1]-x._coeff[1];
357  system[2]=_coeff[2]-x._coeff[2];
358  system[3]=_coeff[3]-x._coeff[3];
359 
360  t-=r;
361  t*=drs;
362 
363  // Newton's method
364  // Inner loop: 7 products, 5 sums, 1 difference
365  for(;i;i--)
366  t-= (system[0]+(system[1]+(system[2]+(system[3])*t)*t)*t)/
367  (system[1]+(system[2]*2+(system[3]*3)*t)*t);
368 
369  t*=(s-r);
370  t+=r;
371 
372  return t;
373  }
374 
375  value_type &
376  operator[](int i)
377  { return (&a)[i]; }
378 
379  const value_type &
380  operator[](int i) const
381  { return (&a)[i]; }
382 };
383 
384 //#ifdef __FIXED__
385 
386 // Fast double implementation of a cubic bezier curve
387 /*
388 template <>
389 template <class T,unsigned int FIXED_BITS>
390 class bezier_base<fixed_base<T,FIXED_BITS> > : std::unary_function<fixed_base<T,FIXED_BITS>,fixed_base<T,FIXED_BITS> >
391 {
392 public:
393  typedef fixed_base<T,FIXED_BITS> value_type;
394  typedef fixed_base<T,FIXED_BITS> time_type;
395 
396 private:
397  affine_combo<value_type,time_type> affine_func;
398  value_type a,b,c,d;
399  time_type r,s;
400 
401  value_type _coeff[4];
402  time_type drs; // reciprocal of (s-r)
403 public:
404  bezier_base():r(0.0),s(1.0),drs(1.0) { }
405  bezier_base(
406  const value_type &a, const value_type &b, const value_type &c, const value_type &d,
407  const time_type &r=0, const time_type &s=1):
408  a(a),b(b),c(c),d(d),r(r),s(s),drs(1.0/(s-r)) { sync(); }
409 
410  void sync()
411  {
412  drs=time_type(1)/(s-r);
413  _coeff[0]= a;
414  _coeff[1]= b*3 - a*3;
415  _coeff[2]= c*3 - b*6 + a*3;
416  _coeff[3]= d - c*3 + b*3 - a;
417  }
418 
419  // 4 products, 3 sums, and 1 difference.
420  inline value_type
421  operator()(time_type t)const
422  { t-=r; t*=drs; return _coeff[0]+(_coeff[1]+(_coeff[2]+(_coeff[3])*t)*t)*t; }
423 
424  void set_rs(time_type new_r, time_type new_s) { r=new_r; s=new_s; drs=time_type(1)/(s-r); }
425  void set_r(time_type new_r) { r=new_r; drs=time_type(1)/(s-r); }
426  void set_s(time_type new_s) { s=new_s; drs=time_type(1)/(s-r); }
427  const time_type &get_r()const { return r; }
428  const time_type &get_s()const { return s; }
429  time_type get_dt()const { return s-r; }
430 
433  // for the calling curve.
434  //
435  time_type intersect(const bezier_base<value_type,time_type> &x, time_type t=0,int i=15)const
436  {
437  value_type system[4];
438  system[0]=_coeff[0]-x._coeff[0];
439  system[1]=_coeff[1]-x._coeff[1];
440  system[2]=_coeff[2]-x._coeff[2];
441  system[3]=_coeff[3]-x._coeff[3];
442 
443  t-=r;
444  t*=drs;
445 
446  // Newton's method
447  // Inner loop: 7 products, 5 sums, 1 difference
448  for(;i;i--)
449  t-=(time_type) ( (system[0]+(system[1]+(system[2]+(system[3])*t)*t)*t)/
450  (system[1]+(system[2]*2+(system[3]*3)*t)*t) );
451 
452  t*=(s-r);
453  t+=r;
454 
455  return t;
456  }
457 
458  value_type &
459  operator[](int i)
460  { return (&a)[i]; }
461 
462  const value_type &
463  operator[](int i) const
464  { return (&a)[i]; }
465 };
466 */
467 //#endif
468 
469 #endif
470 
471 
472 
473 template <typename V, typename T>
475 {
476 public:
477 
478  struct iterator_category {};
479  typedef V value_type;
480  typedef T difference_type;
481  typedef V reference;
482 
483 private:
487 
488 public:
489 
490 /*
491  reference
492  operator*(void)const { return curve(t); }
493  const surface_iterator&
494 
495  operator++(void)
496  { t+=dt; return &this; }
497 
498  const surface_iterator&
499  operator++(int)
500  { hermite_iterator _tmp=*this; t+=dt; return _tmp; }
501 
502  const surface_iterator&
503  operator--(void)
504  { t-=dt; return &this; }
505 
506  const surface_iterator&
507  operator--(int)
508  { hermite_iterator _tmp=*this; t-=dt; return _tmp; }
509 
510 
511  surface_iterator
512  operator+(difference_type __n) const
513  { return surface_iterator(data+__n[0]+__n[1]*pitch,pitch); }
514 
515  surface_iterator
516  operator-(difference_type __n) const
517  { return surface_iterator(data-__n[0]-__n[1]*pitch,pitch); }
518 */
519 
520 };
521 
522 template <typename V,typename T=float>
523 class bezier : public bezier_base<V,T>
524 {
525 public:
526  typedef V value_type;
527  typedef T time_type;
528  typedef float distance_type;
531 
533 
537 
538 public:
539  bezier() { }
540  bezier(const value_type &a, const value_type &b, const value_type &c, const value_type &d):
541  bezier_base<V,T>(a,b,c,d) { }
542 
543 
544  const_iterator begin()const;
545  const_iterator end()const;
546 
547  time_type find_closest(bool fast, const value_type& x, int i=7)const
548  {
549  if (!fast)
550  {
551  value_type array[4] = {
556  return NearestPointOnCurve(x, array);
557  }
558  else
559  {
560  time_type r(0), s(1);
561  float t((r+s)*0.5); /* half way between r and s */
562 
563  for(;i;i--)
564  {
565  // compare 33% of the way between r and s with 67% of the way between r and s
566  if(dist(this->operator()((s-r)*(1.0/3.0)+r), x) <
567  dist(this->operator()((s-r)*(2.0/3.0)+r), x))
568  s=t;
569  else
570  r=t;
571  t=((r+s)*0.5);
572  }
573  return t;
574  }
575  }
576 
578  {
579  const time_type inc((s-r)/steps);
580  if (!inc) return 0;
581  distance_type ret(0);
582  value_type last(this->operator()(r));
583 
584  for(r+=inc;r<s;r+=inc)
585  {
586  const value_type n(this->operator()(r));
587  ret+=dist.uncook(dist(last,n));
588  last=n;
589  }
590  ret+=dist.uncook(dist(last,this->operator()(r)))*(s-(r-inc))/inc;
591 
592  return ret;
593  }
594 
595  distance_type length()const { return find_distance(get_r(),get_s()); }
596 
597  /* subdivide at some time t into 2 separate curves left and right
598 
599  b0 l1
600  * 0+1 l2
601  b1 * 1+2*1+2 l3
602  * 1+2 * 0+3*1+3*2+3 l4,r1
603  b2 * 1+2*2+2 r2 *
604  * 2+3 r3 *
605  b3 r4 *
606  *
607 
608  0.1 2.3 -> 0.1 2 3 4 5.6
609  */
610  void subdivide(bezier *left, bezier *right, const time_type &time = (time_type)0.5) const
611  {
612  time_type t=(time-get_r())/get_dt();
613  bezier lt,rt;
614 
615  value_type temp;
616  const value_type& a((*this)[0]);
617  const value_type& b((*this)[1]);
618  const value_type& c((*this)[2]);
619  const value_type& d((*this)[3]);
620 
621  //1st stage points to keep
622  lt[0] = a;
623  rt[3] = d;
624 
625  //2nd stage calc
626  lt[1] = this->affine_func(a,b,t);
627  temp = this->affine_func(b,c,t);
628  rt[2] = this->affine_func(c,d,t);
629 
630  //3rd stage calc
631  lt[2] = this->affine_func(lt[1],temp,t);
632  rt[1] = this->affine_func(temp,rt[2],t);
633 
634  //last stage calc
635  lt[3] = rt[0] = this->affine_func(lt[2],rt[1],t);
636 
637  //set the time range for l,r (the inside values should be 1, 0 respectively)
638  lt.set_r(get_r());
639  rt.set_s(get_s());
640 
641  lt.sync();
642  rt.sync();
643 
644  //give back the curves
645  if(left) *left = lt;
646  if(right) *right = rt;
647  }
648 
649 
650  void evaluate(time_type t, value_type &f, value_type &df) const
651  {
652  t=(t-get_r())/get_dt();
653 
654  const value_type& a((*this)[0]);
655  const value_type& b((*this)[1]);
656  const value_type& c((*this)[2]);
657  const value_type& d((*this)[3]);
658 
659  const value_type p1 = affine_func(
660  affine_func(a,b,t),
661  affine_func(b,c,t)
662  ,t);
663  const value_type p2 = affine_func(
664  affine_func(b,c,t),
665  affine_func(c,d,t)
666  ,t);
667 
668  f = affine_func(p1,p2,t);
669  df = (p2-p1)*3;
670  }
671 
672 private:
673  /*
674  * Bezier :
675  * Evaluate a Bezier curve at a particular parameter value
676  * Fill in control points for resulting sub-curves if "Left" and
677  * "Right" are non-null.
678  *
679  * int degree; Degree of bezier curve
680  * value_type *VT; Control pts
681  * time_type t; Parameter value
682  * value_type *Left; RETURN left half ctl pts
683  * value_type *Right; RETURN right half ctl pts
684  */
685  static value_type Bezier(value_type *VT, int degree, time_type t, value_type *Left, value_type *Right)
686  {
687  int i, j; /* Index variables */
688  value_type Vtemp[W_DEGREE+1][W_DEGREE+1];
689 
690  /* Copy control points */
691  for (j = 0; j <= degree; j++)
692  Vtemp[0][j] = VT[j];
693 
694  /* Triangle computation */
695  for (i = 1; i <= degree; i++)
696  for (j =0 ; j <= degree - i; j++)
697  {
698  Vtemp[i][j][0] = (1.0 - t) * Vtemp[i-1][j][0] + t * Vtemp[i-1][j+1][0];
699  Vtemp[i][j][1] = (1.0 - t) * Vtemp[i-1][j][1] + t * Vtemp[i-1][j+1][1];
700  }
701 
702  if (Left != NULL)
703  for (j = 0; j <= degree; j++)
704  Left[j] = Vtemp[j][0];
705 
706  if (Right != NULL)
707  for (j = 0; j <= degree; j++)
708  Right[j] = Vtemp[degree-j][j];
709 
710  return (Vtemp[degree][0]);
711  }
712 
713  /*
714  * CrossingCount :
715  * Count the number of times a Bezier control polygon
716  * crosses the 0-axis. This number is >= the number of roots.
717  *
718  * value_type *VT; Control pts of Bezier curve
719  */
720  static int CrossingCount(value_type *VT)
721  {
722  int i;
723  int n_crossings = 0; /* Number of zero-crossings */
724  int sign, old_sign; /* Sign of coefficients */
725 
726  sign = old_sign = SGN(VT[0][1]);
727  for (i = 1; i <= W_DEGREE; i++)
728  {
729  sign = SGN(VT[i][1]);
730  if (sign != old_sign) n_crossings++;
731  old_sign = sign;
732  }
733 
734  return n_crossings;
735  }
736 
737  /*
738  * ControlPolygonFlatEnough :
739  * Check if the control polygon of a Bezier curve is flat enough
740  * for recursive subdivision to bottom out.
741  *
742  * value_type *VT; Control points
743  */
745  {
746  int i; /* Index variable */
747  distance_type distance[W_DEGREE]; /* Distances from pts to line */
748  distance_type max_distance_above; /* maximum of these */
749  distance_type max_distance_below;
750  time_type intercept_1, intercept_2, left_intercept, right_intercept;
751  distance_type a, b, c; /* Coefficients of implicit */
752  /* eqn for line from VT[0]-VT[deg] */
753  /* Find the perpendicular distance */
754  /* from each interior control point to */
755  /* line connecting VT[0] and VT[W_DEGREE] */
756  {
757  distance_type abSquared;
758 
759  /* Derive the implicit equation for line connecting first *
760  * and last control points */
761  a = VT[0][1] - VT[W_DEGREE][1];
762  b = VT[W_DEGREE][0] - VT[0][0];
763  c = VT[0][0] * VT[W_DEGREE][1] - VT[W_DEGREE][0] * VT[0][1];
764 
765  abSquared = (a * a) + (b * b);
766 
767  for (i = 1; i < W_DEGREE; i++)
768  {
769  /* Compute distance from each of the points to that line */
770  distance[i] = a * VT[i][0] + b * VT[i][1] + c;
771  if (distance[i] > 0.0) distance[i] = (distance[i] * distance[i]) / abSquared;
772  if (distance[i] < 0.0) distance[i] = -(distance[i] * distance[i]) / abSquared;
773  }
774  }
775 
776  /* Find the largest distance */
777  max_distance_above = max_distance_below = 0.0;
778 
779  for (i = 1; i < W_DEGREE; i++)
780  {
781  if (distance[i] < 0.0) max_distance_below = MIN(max_distance_below, distance[i]);
782  if (distance[i] > 0.0) max_distance_above = MAX(max_distance_above, distance[i]);
783  }
784 
785  /* Implicit equation for "above" line */
786  intercept_1 = -(c + max_distance_above)/a;
787 
788  /* Implicit equation for "below" line */
789  intercept_2 = -(c + max_distance_below)/a;
790 
791  /* Compute intercepts of bounding box */
792  left_intercept = MIN(intercept_1, intercept_2);
793  right_intercept = MAX(intercept_1, intercept_2);
794 
795  return 0.5 * (right_intercept-left_intercept) < BEZIER_EPSILON ? 1 : 0;
796  }
797 
798  /*
799  * ComputeXIntercept :
800  * Compute intersection of chord from first control point to last
801  * with 0-axis.
802  *
803  * value_type *VT; Control points
804  */
806  {
807  distance_type YNM = VT[W_DEGREE][1] - VT[0][1];
808  return (YNM*VT[0][0] - (VT[W_DEGREE][0] - VT[0][0])*VT[0][1]) / YNM;
809  }
810 
811  /*
812  * FindRoots :
813  * Given a 5th-degree equation in Bernstein-Bezier form, find
814  * all of the roots in the interval [0, 1]. Return the number
815  * of roots found.
816  *
817  * value_type *w; The control points
818  * time_type *t; RETURN candidate t-values
819  * int depth; The depth of the recursion
820  */
821  static int FindRoots(value_type *w, time_type *t, int depth)
822  {
823  int i;
824  value_type Left[W_DEGREE+1]; /* New left and right */
825  value_type Right[W_DEGREE+1]; /* control polygons */
826  int left_count; /* Solution count from */
827  int right_count; /* children */
828  time_type left_t[W_DEGREE+1]; /* Solutions from kids */
829  time_type right_t[W_DEGREE+1];
830 
831  switch (CrossingCount(w))
832  {
833  case 0 :
834  { /* No solutions here */
835  return 0;
836  }
837  case 1 :
838  { /* Unique solution */
839  /* Stop recursion when the tree is deep enough */
840  /* if deep enough, return 1 solution at midpoint */
841  if (depth >= MAXDEPTH)
842  {
843  t[0] = (w[0][0] + w[W_DEGREE][0]) / 2.0;
844  return 1;
845  }
847  {
848  t[0] = ComputeXIntercept(w);
849  return 1;
850  }
851  break;
852  }
853  }
854 
855  /* Otherwise, solve recursively after */
856  /* subdividing control polygon */
857  Bezier(w, W_DEGREE, 0.5, Left, Right);
858  left_count = FindRoots(Left, left_t, depth+1);
859  right_count = FindRoots(Right, right_t, depth+1);
860 
861  /* Gather solutions together */
862  for (i = 0; i < left_count; i++) t[i] = left_t[i];
863  for (i = 0; i < right_count; i++) t[i+left_count] = right_t[i];
864 
865  /* Send back total number of solutions */
866  return (left_count+right_count);
867  }
868 
869  /*
870  * ConvertToBezierForm :
871  * Given a point and a Bezier curve, generate a 5th-degree
872  * Bezier-format equation whose solution finds the point on the
873  * curve nearest the user-defined point.
874  *
875  * value_type& P; The point to find t for
876  * value_type *VT; The control points
877  */
879  {
880  int i, j, k, m, n, ub, lb;
881  int row, column; /* Table indices */
882  value_type c[DEGREE+1]; /* VT(i)'s - P */
883  value_type d[DEGREE]; /* VT(i+1) - VT(i) */
884  distance_type cdTable[3][4]; /* Dot product of c, d */
885  static distance_type z[3][4] = { /* Precomputed "z" for cubics */
886  {1.0, 0.6, 0.3, 0.1},
887  {0.4, 0.6, 0.6, 0.4},
888  {0.1, 0.3, 0.6, 1.0}};
889 
890  /* Determine the c's -- these are vectors created by subtracting */
891  /* point P from each of the control points */
892  for (i = 0; i <= DEGREE; i++)
893  c[i] = VT[i] - P;
894 
895  /* Determine the d's -- these are vectors created by subtracting */
896  /* each control point from the next */
897  for (i = 0; i <= DEGREE - 1; i++)
898  d[i] = (VT[i+1] - VT[i]) * 3.0;
899 
900  /* Create the c,d table -- this is a table of dot products of the */
901  /* c's and d's */
902  for (row = 0; row <= DEGREE - 1; row++)
903  for (column = 0; column <= DEGREE; column++)
904  cdTable[row][column] = d[row] * c[column];
905 
906  /* Now, apply the z's to the dot products, on the skew diagonal */
907  /* Also, set up the x-values, making these "points" */
908  for (i = 0; i <= W_DEGREE; i++)
909  {
910  w[i][0] = (distance_type)(i) / W_DEGREE;
911  w[i][1] = 0.0;
912  }
913 
914  n = DEGREE;
915  m = DEGREE-1;
916  for (k = 0; k <= n + m; k++)
917  {
918  lb = MAX(0, k - m);
919  ub = MIN(k, n);
920  for (i = lb; i <= ub; i++)
921  {
922  j = k - i;
923  w[i+j][1] += cdTable[j][i] * z[j][i];
924  }
925  }
926  }
927 
928  /*
929  * NearestPointOnCurve :
930  * Compute the parameter value of the point on a Bezier
931  * curve segment closest to some arbitrary, user-input point.
932  * Return the point on the curve at that parameter value.
933  *
934  * value_type& P; The user-supplied point
935  * value_type *VT; Control points of cubic Bezier
936  */
938  {
939  value_type w[W_DEGREE+1]; /* Ctl pts of 5th-degree curve */
940  time_type t_candidate[W_DEGREE]; /* Possible roots */
941  int n_solutions; /* Number of roots found */
942  time_type t; /* Parameter value of closest pt */
943 
944  /* Convert problem to 5th-degree Bezier form */
945  ConvertToBezierForm(P, VT, w);
946 
947  /* Find all possible roots of 5th-degree equation */
948  n_solutions = FindRoots(w, t_candidate, 0);
949 
950  /* Compare distances of P to all candidates, and to t=0, and t=1 */
951  {
952  distance_type dist, new_dist;
953  value_type p, v;
954  int i;
955 
956  /* Check distance to beginning of curve, where t = 0 */
957  dist = (P - VT[0]).mag_squared();
958  t = 0.0;
959 
960  /* Find distances for candidate points */
961  for (i = 0; i < n_solutions; i++)
962  {
963  p = Bezier(VT, DEGREE, t_candidate[i], (value_type *)NULL, (value_type *)NULL);
964  new_dist = (P - p).mag_squared();
965  if (new_dist < dist)
966  {
967  dist = new_dist;
968  t = t_candidate[i];
969  }
970  }
971 
972  /* Finally, look at distance to end point, where t = 1.0 */
973  new_dist = (P - VT[DEGREE]).mag_squared();
974  if (new_dist < dist)
975  {
976  dist = new_dist;
977  t = 1.0;
978  }
979  }
980 
981  /* Return the point on the curve at parameter value t */
982  return t;
983  }
984 };
985 
987 
988 /* === E X T E R N S ======================================================= */
989 
990 /* === E N D =============================================================== */
991 
992 #endif