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