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