- Main Page
- Related Pages
- Classes
- Files

# _bezier.h

Go to the documentation of this file.

    00001
    00026 /* === S T A R T =========================================================== */
    00027
    00028 #ifndef __ETL__BEZIER_H
    00029 #define __ETL__BEZIER_H
    00030
    00031 /* === H E A D E R S ======================================================= */
    00032
    00033 #include "_curve_func.h"
    00034 #include <cmath>                // for ldexp
    00035 // #include <ETL/fixed>         // not used
    00036
    00037 /* === M A C R O S ========================================================= */
    00038
    00039 #define MAXDEPTH 64 /*  Maximum depth for recursion */
    00040
    00041 /* take binary sign of a, either -1, or 1 if >= 0 */
    00042 #define SGN(a)      (((a)<0) ? -1 : 1)
    00043
    00044 /* find minimum of a and b */
    00045 #ifndef MIN
    00046 #define MIN(a,b)    (((a)<(b))?(a):(b))
    00047 #endif
    00048
    00049 /* find maximum of a and b */
    00050 #ifndef MAX
    00051 #define MAX(a,b)    (((a)>(b))?(a):(b))
    00052 #endif
    00053
    00054 #define BEZIER_EPSILON  (ldexp(1.0,-MAXDEPTH-1)) /*Flatness control value */
    00055 //#define   BEZIER_EPSILON  0.00005 /*Flatness control value */
    00056 #define DEGREE  3           /*  Cubic Bezier curve      */
    00057 #define W_DEGREE 5          /*  Degree of eqn to find roots of */
    00058
    00059 /* === T Y P E D E F S ===================================================== */
    00060
    00061 /* === C L A S S E S & S T R U C T S ======================================= */
    00062
    00063 _ETL_BEGIN_NAMESPACE
    00064
    00065 template<typename V,typename T> class bezier;
    00066
    00068 // This generic implementation uses the DeCasteljau algorithm.
    00069 // Works for just about anything that has an affine combination function
    00070 template <typename V,typename T=float>
    00071 class bezier_base : public std::unary_function<T,V>
    00072 {
    00073 public:
    00074     typedef V value_type;
    00075     typedef T time_type;
    00076
    00077 private:
    00078     value_type a,b,c,d;
    00079     time_type r,s;
    00080
    00081 protected:
    00082     affine_combo<value_type,time_type> affine_func;
    00083
    00084 public:
    00085     bezier_base():r(0.0),s(1.0) { }
    00086     bezier_base(
    00087         const value_type &a, const value_type &b, const value_type &c, const value_type &d,
    00088         const time_type &r=0.0, const time_type &s=1.0):
    00089         a(a),b(b),c(c),d(d),r(r),s(s) { sync(); }
    00090
    00091     void sync()
    00092     {
    00093     }
    00094
    00095     value_type
    00096     operator()(time_type t)const
    00097     {
    00098         t=(t-r)/(s-r);
    00099         return
    00100         affine_func(
    00101             affine_func(
    00102                 affine_func(a,b,t),
    00103                 affine_func(b,c,t)
    00104             ,t),
    00105             affine_func(
    00106                 affine_func(b,c,t),
    00107                 affine_func(c,d,t)
    00108             ,t)
    00109         ,t);
    00110     }
    00111
    00112     /*
    00113     void evaluate(time_type t, value_type &f, value_type &df) const
    00114     {
    00115         t=(t-r)/(s-r);
    00116
    00117         value_type p1 = affine_func(
    00118                             affine_func(a,b,t),
    00119                             affine_func(b,c,t)
    00120                             ,t);
    00121         value_type p2 = affine_func(
    00122                             affine_func(b,c,t),
    00123                             affine_func(c,d,t)
    00124                         ,t);
    00125
    00126         f = affine_func(p1,p2,t);
    00127         df = (p2-p1)*3;
    00128     }
    00129     */
    00130
    00131     void set_rs(time_type new_r, time_type new_s) { r=new_r; s=new_s; }
    00132     void set_r(time_type new_r) { r=new_r; }
    00133     void set_s(time_type new_s) { s=new_s; }
    00134     const time_type &get_r()const { return r; }
    00135     const time_type &get_s()const { return s; }
    00136     time_type get_dt()const { return s-r; }
    00137
    00138     bool intersect_hull(const bezier_base<value_type,time_type> &x)const
    00139     {
    00140         return 0;
    00141     }
    00142
    00144
    00164     time_type intersect(const bezier_base<value_type,time_type> &x, time_type near=0.0)const
    00165     {
    00166         return 0;
    00167     }
    00168
    00169     /* subdivide at some time t into 2 separate curves left and right
    00170
    00171         b0 l1
    00172         *       0+1 l2
    00173         b1      *       1+2*1+2 l3
    00174         *       1+2     *           0+3*1+3*2+3 l4,r1
    00175         b2      *       1+2*2+2 r2  *
    00176         *       2+3 r3  *
    00177         b3 r4   *
    00178         *
    00179
    00180         0.1 2.3 ->  0.1 2 3 4 5.6
    00181     */
    00182 /*  void subdivide(bezier_base *left, bezier_base *right, const time_type &time = (time_type)0.5) const
    00183     {
    00184         time_type t = (time-r)/(s-r);
    00185         bezier_base lt,rt;
    00186
    00187         value_type temp;
    00188
    00189         //1st stage points to keep
    00190         lt.a = a;
    00191         rt.d = d;
    00192
    00193         //2nd stage calc
    00194         lt.b = affine_func(a,b,t);
    00195         temp = affine_func(b,c,t);
    00196         rt.c = affine_func(c,d,t);
    00197
    00198         //3rd stage calc
    00199         lt.c = affine_func(lt.b,temp,t);
    00200         rt.b = affine_func(temp,rt.c,t);
    00201
    00202         //last stage calc
    00203         lt.d = rt.a = affine_func(lt.c,rt.b,t);
    00204
    00205         //set the time range for l,r (the inside values should be 1, 0 respectively)
    00206         lt.r = r;
    00207         rt.s = s;
    00208
    00209         //give back the curves
    00210         if(left) *left = lt;
    00211         if(right) *right = rt;
    00212     }
    00213     */
    00214     value_type &
    00215     operator[](int i)
    00216     { return (&a)[i]; }
    00217
    00218     const value_type &
    00219     operator[](int i) const
    00220     { return (&a)[i]; }
    00221 };
    00222
    00223
    00224 #if 1
    00225 // Fast float implementation of a cubic bezier curve
    00226 template <>
    00227 class bezier_base<float,float> : public std::unary_function<float,float>
    00228 {
    00229 public:
    00230     typedef float value_type;
    00231     typedef float time_type;
    00232 private:
    00233     affine_combo<value_type,time_type> affine_func;
    00234     value_type a,b,c,d;
    00235     time_type r,s;
    00236
    00237     value_type _coeff[4];
    00238     time_type drs; // reciprocal of (s-r)
    00239 public:
    00240     bezier_base():r(0.0),s(1.0),drs(1.0) { }
    00241     bezier_base(
    00242         const value_type &a, const value_type &b, const value_type &c, const value_type &d,
    00243         const time_type &r=0.0, const time_type &s=1.0):
    00244         a(a),b(b),c(c),d(d),r(r),s(s),drs(1.0/(s-r)) { sync(); }
    00245
    00246     void sync()
    00247     {
    00248 //      drs=1.0/(s-r);
    00249         _coeff[0]=                 a;
    00250         _coeff[1]=           b*3 - a*3;
    00251         _coeff[2]=     c*3 - b*6 + a*3;
    00252         _coeff[3]= d - c*3 + b*3 - a;
    00253     }
    00254
    00255     // Cost Summary: 4 products, 3 sums, and 1 difference.
    00256     inline value_type
    00257     operator()(time_type t)const
    00258     { t-=r; t*=drs; return _coeff[0]+(_coeff[1]+(_coeff[2]+(_coeff[3])*t)*t)*t; }
    00259
    00260     void set_rs(time_type new_r, time_type new_s) { r=new_r; s=new_s; drs=1.0/(s-r); }
    00261     void set_r(time_type new_r) { r=new_r; drs=1.0/(s-r); }
    00262     void set_s(time_type new_s) { s=new_s; drs=1.0/(s-r); }
    00263     const time_type &get_r()const { return r; }
    00264     const time_type &get_s()const { return s; }
    00265     time_type get_dt()const { return s-r; }
    00266
    00268
    00271     time_type intersect(const bezier_base<value_type,time_type> &x, time_type t=0.0,int i=15)const
    00272     {
    00273         //BROKEN - the time values of the 2 curves should be independent
    00274         value_type system[4];
    00275         system[0]=_coeff[0]-x._coeff[0];
    00276         system[1]=_coeff[1]-x._coeff[1];
    00277         system[2]=_coeff[2]-x._coeff[2];
    00278         system[3]=_coeff[3]-x._coeff[3];
    00279
    00280         t-=r;
    00281         t*=drs;
    00282
    00283         // Newton's method
    00284         // Inner loop cost summary: 7 products, 5 sums, 1 difference
    00285         for(;i;i--)
    00286             t-= (system[0]+(system[1]+(system[2]+(system[3])*t)*t)*t)/
    00287                 (system[1]+(system[2]*2+(system[3]*3)*t)*t);
    00288
    00289         t*=(s-r);
    00290         t+=r;
    00291
    00292         return t;
    00293     }
    00294
    00295     value_type &
    00296     operator[](int i)
    00297     { return (&a)[i]; }
    00298
    00299     const value_type &
    00300     operator[](int i) const
    00301     { return (&a)[i]; }
    00302 };
    00303
    00304
    00305 // Fast double implementation of a cubic bezier curve
    00306 template <>
    00307 class bezier_base<double,float> : public std::unary_function<float,double>
    00308 {
    00309 public:
    00310     typedef double value_type;
    00311     typedef float time_type;
    00312 private:
    00313     affine_combo<value_type,time_type> affine_func;
    00314     value_type a,b,c,d;
    00315     time_type r,s;
    00316
    00317     value_type _coeff[4];
    00318     time_type drs; // reciprocal of (s-r)
    00319 public:
    00320     bezier_base():r(0.0),s(1.0),drs(1.0) { }
    00321     bezier_base(
    00322         const value_type &a, const value_type &b, const value_type &c, const value_type &d,
    00323         const time_type &r=0.0, const time_type &s=1.0):
    00324         a(a),b(b),c(c),d(d),r(r),s(s),drs(1.0/(s-r)) { sync(); }
    00325
    00326     void sync()
    00327     {
    00328 //      drs=1.0/(s-r);
    00329         _coeff[0]=                 a;
    00330         _coeff[1]=           b*3 - a*3;
    00331         _coeff[2]=     c*3 - b*6 + a*3;
    00332         _coeff[3]= d - c*3 + b*3 - a;
    00333     }
    00334
    00335     // 4 products, 3 sums, and 1 difference.
    00336     inline value_type
    00337     operator()(time_type t)const
    00338     { t-=r; t*=drs; return _coeff[0]+(_coeff[1]+(_coeff[2]+(_coeff[3])*t)*t)*t; }
    00339
    00340     void set_rs(time_type new_r, time_type new_s) { r=new_r; s=new_s; drs=1.0/(s-r); }
    00341     void set_r(time_type new_r) { r=new_r; drs=1.0/(s-r); }
    00342     void set_s(time_type new_s) { s=new_s; drs=1.0/(s-r); }
    00343     const time_type &get_r()const { return r; }
    00344     const time_type &get_s()const { return s; }
    00345     time_type get_dt()const { return s-r; }
    00346
    00348
    00351     time_type intersect(const bezier_base<value_type,time_type> &x, time_type t=0.0,int i=15)const
    00352     {
    00353         //BROKEN - the time values of the 2 curves should be independent
    00354         value_type system[4];
    00355         system[0]=_coeff[0]-x._coeff[0];
    00356         system[1]=_coeff[1]-x._coeff[1];
    00357         system[2]=_coeff[2]-x._coeff[2];
    00358         system[3]=_coeff[3]-x._coeff[3];
    00359
    00360         t-=r;
    00361         t*=drs;
    00362
    00363         // Newton's method
    00364         // Inner loop: 7 products, 5 sums, 1 difference
    00365         for(;i;i--)
    00366             t-= (system[0]+(system[1]+(system[2]+(system[3])*t)*t)*t)/
    00367                 (system[1]+(system[2]*2+(system[3]*3)*t)*t);
    00368
    00369         t*=(s-r);
    00370         t+=r;
    00371
    00372         return t;
    00373     }
    00374
    00375     value_type &
    00376     operator[](int i)
    00377     { return (&a)[i]; }
    00378
    00379     const value_type &
    00380     operator[](int i) const
    00381     { return (&a)[i]; }
    00382 };
    00383
    00384 //#ifdef __FIXED__
    00385
    00386 // Fast double implementation of a cubic bezier curve
    00387 /*
    00388 template <>
    00389 template <class T,unsigned int FIXED_BITS>
    00390 class bezier_base<fixed_base<T,FIXED_BITS> > : std::unary_function<fixed_base<T,FIXED_BITS>,fixed_base<T,FIXED_BITS> >
    00391 {
    00392 public:
    00393     typedef fixed_base<T,FIXED_BITS> value_type;
    00394     typedef fixed_base<T,FIXED_BITS> time_type;
    00395
    00396 private:
    00397     affine_combo<value_type,time_type> affine_func;
    00398     value_type a,b,c,d;
    00399     time_type r,s;
    00400
    00401     value_type _coeff[4];
    00402     time_type drs; // reciprocal of (s-r)
    00403 public:
    00404     bezier_base():r(0.0),s(1.0),drs(1.0) { }
    00405     bezier_base(
    00406         const value_type &a, const value_type &b, const value_type &c, const value_type &d,
    00407         const time_type &r=0, const time_type &s=1):
    00408         a(a),b(b),c(c),d(d),r(r),s(s),drs(1.0/(s-r)) { sync(); }
    00409
    00410     void sync()
    00411     {
    00412         drs=time_type(1)/(s-r);
    00413         _coeff[0]=                 a;
    00414         _coeff[1]=           b*3 - a*3;
    00415         _coeff[2]=     c*3 - b*6 + a*3;
    00416         _coeff[3]= d - c*3 + b*3 - a;
    00417     }
    00418
    00419     // 4 products, 3 sums, and 1 difference.
    00420     inline value_type
    00421     operator()(time_type t)const
    00422     { t-=r; t*=drs; return _coeff[0]+(_coeff[1]+(_coeff[2]+(_coeff[3])*t)*t)*t; }
    00423
    00424     void set_rs(time_type new_r, time_type new_s) { r=new_r; s=new_s; drs=time_type(1)/(s-r); }
    00425     void set_r(time_type new_r) { r=new_r; drs=time_type(1)/(s-r); }
    00426     void set_s(time_type new_s) { s=new_s; drs=time_type(1)/(s-r); }
    00427     const time_type &get_r()const { return r; }
    00428     const time_type &get_s()const { return s; }
    00429     time_type get_dt()const { return s-r; }
    00430
    00433     //  for the calling curve.
    00434     //
    00435     time_type intersect(const bezier_base<value_type,time_type> &x, time_type t=0,int i=15)const
    00436     {
    00437         value_type system[4];
    00438         system[0]=_coeff[0]-x._coeff[0];
    00439         system[1]=_coeff[1]-x._coeff[1];
    00440         system[2]=_coeff[2]-x._coeff[2];
    00441         system[3]=_coeff[3]-x._coeff[3];
    00442
    00443         t-=r;
    00444         t*=drs;
    00445
    00446         // Newton's method
    00447         // Inner loop: 7 products, 5 sums, 1 difference
    00448         for(;i;i--)
    00449             t-=(time_type) ( (system[0]+(system[1]+(system[2]+(system[3])*t)*t)*t)/
    00450                 (system[1]+(system[2]*2+(system[3]*3)*t)*t) );
    00451
    00452         t*=(s-r);
    00453         t+=r;
    00454
    00455         return t;
    00456     }
    00457
    00458     value_type &
    00459     operator[](int i)
    00460     { return (&a)[i]; }
    00461
    00462     const value_type &
    00463     operator[](int i) const
    00464     { return (&a)[i]; }
    00465 };
    00466 */
    00467 //#endif
    00468
    00469 #endif
    00470
    00471
    00472
    00473 template <typename V, typename T>
    00474 class bezier_iterator
    00475 {
    00476 public:
    00477
    00478     struct iterator_category {};
    00479     typedef V value_type;
    00480     typedef T difference_type;
    00481     typedef V reference;
    00482
    00483 private:
    00484     difference_type t;
    00485     difference_type dt;
    00486     bezier_base<V,T>    curve;
    00487
    00488 public:
    00489
    00490 /*
    00491     reference
    00492     operator*(void)const { return curve(t); }
    00493     const surface_iterator&
    00494
    00495     operator++(void)
    00496     { t+=dt; return &this; }
    00497
    00498     const surface_iterator&
    00499     operator++(int)
    00500     { hermite_iterator _tmp=*this; t+=dt; return _tmp; }
    00501
    00502     const surface_iterator&
    00503     operator--(void)
    00504     { t-=dt; return &this; }
    00505
    00506     const surface_iterator&
    00507     operator--(int)
    00508     { hermite_iterator _tmp=*this; t-=dt; return _tmp; }
    00509
    00510
    00511     surface_iterator
    00512     operator+(difference_type __n) const
    00513     { return surface_iterator(data+__n[0]+__n[1]*pitch,pitch); }
    00514
    00515     surface_iterator
    00516     operator-(difference_type __n) const
    00517     { return surface_iterator(data-__n[0]-__n[1]*pitch,pitch); }
    00518 */
    00519
    00520 };
    00521
    00522 template <typename V,typename T=float>
    00523 class bezier : public bezier_base<V,T>
    00524 {
    00525 public:
    00526     typedef V value_type;
    00527     typedef T time_type;
    00528     typedef float distance_type;
    00529     typedef bezier_iterator<V,T> iterator;
    00530     typedef bezier_iterator<V,T> const_iterator;
    00531
    00532     distance_func<value_type> dist;
    00533
    00534     using bezier_base<V,T>::get_r;
    00535     using bezier_base<V,T>::get_s;
    00536     using bezier_base<V,T>::get_dt;
    00537
    00538 public:
    00539     bezier() { }
    00540     bezier(const value_type &a, const value_type &b, const value_type &c, const value_type &d):
    00541         bezier_base<V,T>(a,b,c,d) { }
    00542
    00543
    00544     const_iterator begin()const;
    00545     const_iterator end()const;
    00546
    00547     time_type find_closest(bool fast, const value_type& x, int i=7)const
    00548     {
    00549         if (!fast)
    00550         {
    00551             value_type array[4] = {
    00552                 bezier<V,T>::operator[](0),
    00553                 bezier<V,T>::operator[](1),
    00554                 bezier<V,T>::operator[](2),
    00555                 bezier<V,T>::operator[](3)};
    00556             return NearestPointOnCurve(x, array);
    00557         }
    00558         else
    00559         {
    00560             time_type r(0), s(1);
    00561             float t((r+s)*0.5); /* half way between r and s */
    00562
    00563             for(;i;i--)
    00564             {
    00565                 // compare 33% of the way between r and s with 67% of the way between r and s
    00566                 if(dist(operator()((s-r)*(1.0/3.0)+r), x) <
    00567                    dist(operator()((s-r)*(2.0/3.0)+r), x))
    00568                     s=t;
    00569                 else
    00570                     r=t;
    00571                 t=((r+s)*0.5);
    00572             }
    00573             return t;
    00574         }
    00575     }
    00576
    00577     distance_type find_distance(time_type r, time_type s, int steps=7)const
    00578     {
    00579         const time_type inc((s-r)/steps);
    00580         if (!inc) return 0;
    00581         distance_type ret(0);
    00582         value_type last(operator()(r));
    00583
    00584         for(r+=inc;r<s;r+=inc)
    00585         {
    00586             const value_type n(operator()(r));
    00587             ret+=dist.uncook(dist(last,n));
    00588             last=n;
    00589         }
    00590         ret+=dist.uncook(dist(last,operator()(r)))*(s-(r-inc))/inc;
    00591
    00592         return ret;
    00593     }
    00594
    00595     distance_type length()const { return find_distance(get_r(),get_s()); }
    00596
    00597     /* subdivide at some time t into 2 separate curves left and right
    00598
    00599         b0 l1
    00600         *       0+1 l2
    00601         b1      *       1+2*1+2 l3
    00602         *       1+2     *           0+3*1+3*2+3 l4,r1
    00603         b2      *       1+2*2+2 r2  *
    00604         *       2+3 r3  *
    00605         b3 r4   *
    00606         *
    00607
    00608         0.1 2.3 ->  0.1 2 3 4 5.6
    00609     */
    00610     void subdivide(bezier *left, bezier *right, const time_type &time = (time_type)0.5) const
    00611     {
    00612         time_type t=(time-get_r())/get_dt();
    00613         bezier lt,rt;
    00614
    00615         value_type temp;
    00616         const value_type& a((*this)[0]);
    00617         const value_type& b((*this)[1]);
    00618         const value_type& c((*this)[2]);
    00619         const value_type& d((*this)[3]);
    00620
    00621         //1st stage points to keep
    00622         lt[0] = a;
    00623         rt[3] = d;
    00624
    00625         //2nd stage calc
    00626         lt[1] = affine_func(a,b,t);
    00627         temp = affine_func(b,c,t);
    00628         rt[2] = affine_func(c,d,t);
    00629
    00630         //3rd stage calc
    00631         lt[2] = affine_func(lt[1],temp,t);
    00632         rt[1] = affine_func(temp,rt[2],t);
    00633
    00634         //last stage calc
    00635         lt[3] = rt[0] = affine_func(lt[2],rt[1],t);
    00636
    00637         //set the time range for l,r (the inside values should be 1, 0 respectively)
    00638         lt.set_r(get_r());
    00639         rt.set_s(get_s());
    00640
    00641         lt.sync();
    00642         rt.sync();
    00643
    00644         //give back the curves
    00645         if(left) *left = lt;
    00646         if(right) *right = rt;
    00647     }
    00648
    00649
    00650     void evaluate(time_type t, value_type &f, value_type &df) const
    00651     {
    00652         t=(t-get_r())/get_dt();
    00653
    00654         const value_type& a((*this)[0]);
    00655         const value_type& b((*this)[1]);
    00656         const value_type& c((*this)[2]);
    00657         const value_type& d((*this)[3]);
    00658
    00659         const value_type p1 = affine_func(
    00660                             affine_func(a,b,t),
    00661                             affine_func(b,c,t)
    00662                             ,t);
    00663         const value_type p2 = affine_func(
    00664                             affine_func(b,c,t),
    00665                             affine_func(c,d,t)
    00666                         ,t);
    00667
    00668         f = affine_func(p1,p2,t);
    00669         df = (p2-p1)*3;
    00670     }
    00671
    00672 private:
    00673     /*
    00674      *  Bezier :
    00675      *  Evaluate a Bezier curve at a particular parameter value
    00676      *      Fill in control points for resulting sub-curves if "Left" and
    00677      *  "Right" are non-null.
    00678      *
    00679      *    int           degree;     Degree of bezier curve
    00680      *    value_type    *VT;        Control pts
    00681      *    time_type     t;          Parameter value
    00682      *    value_type    *Left;      RETURN left half ctl pts
    00683      *    value_type    *Right;     RETURN right half ctl pts
    00684      */
    00685     static value_type Bezier(value_type *VT, int degree, time_type t, value_type *Left, value_type *Right)
    00686     {
    00687         int         i, j;       /* Index variables  */
    00688         value_type  Vtemp[W_DEGREE+1][W_DEGREE+1];
    00689
    00690         /* Copy control points  */
    00691         for (j = 0; j <= degree; j++)
    00692             Vtemp[0][j] = VT[j];
    00693
    00694         /* Triangle computation */
    00695         for (i = 1; i <= degree; i++)
    00696             for (j =0 ; j <= degree - i; j++)
    00697             {
    00698                 Vtemp[i][j][0] = (1.0 - t) * Vtemp[i-1][j][0] + t * Vtemp[i-1][j+1][0];
    00699                 Vtemp[i][j][1] = (1.0 - t) * Vtemp[i-1][j][1] + t * Vtemp[i-1][j+1][1];
    00700             }
    00701
    00702         if (Left != NULL)
    00703             for (j = 0; j <= degree; j++)
    00704                 Left[j]  = Vtemp[j][0];
    00705
    00706         if (Right != NULL)
    00707             for (j = 0; j <= degree; j++)
    00708                 Right[j] = Vtemp[degree-j][j];
    00709
    00710         return (Vtemp[degree][0]);
    00711     }
    00712
    00713     /*
    00714      * CrossingCount :
    00715      *  Count the number of times a Bezier control polygon
    00716      *  crosses the 0-axis. This number is >= the number of roots.
    00717      *
    00718      *    value_type    *VT;            Control pts of Bezier curve
    00719      */
    00720     static int CrossingCount(value_type *VT)
    00721     {
    00722         int     i;
    00723         int     n_crossings = 0;    /*  Number of zero-crossings    */
    00724         int     sign, old_sign;     /*  Sign of coefficients        */
    00725
    00726         sign = old_sign = SGN(VT[0][1]);
    00727         for (i = 1; i <= W_DEGREE; i++)
    00728         {
    00729             sign = SGN(VT[i][1]);
    00730             if (sign != old_sign) n_crossings++;
    00731             old_sign = sign;
    00732         }
    00733
    00734         return n_crossings;
    00735     }
    00736
    00737     /*
    00738      *  ControlPolygonFlatEnough :
    00739      *  Check if the control polygon of a Bezier curve is flat enough
    00740      *  for recursive subdivision to bottom out.
    00741      *
    00742      *    value_type    *VT;        Control points
    00743      */
    00744     static int ControlPolygonFlatEnough(value_type *VT)
    00745     {
    00746         int             i;                  /* Index variable                   */
    00747         distance_type   distance[W_DEGREE]; /* Distances from pts to line       */
    00748         distance_type   max_distance_above; /* maximum of these                 */
    00749         distance_type   max_distance_below;
    00750         time_type       intercept_1, intercept_2, left_intercept, right_intercept;
    00751         distance_type   a, b, c;            /* Coefficients of implicit         */
    00752         /* eqn for line from VT[0]-VT[deg]          */
    00753         /* Find the  perpendicular distance         */
    00754         /* from each interior control point to      */
    00755         /* line connecting VT[0] and VT[W_DEGREE]   */
    00756         {
    00757             distance_type   abSquared;
    00758
    00759             /* Derive the implicit equation for line connecting first *
    00760              *  and last control points */
    00761             a = VT[0][1] - VT[W_DEGREE][1];
    00762             b = VT[W_DEGREE][0] - VT[0][0];
    00763             c = VT[0][0] * VT[W_DEGREE][1] - VT[W_DEGREE][0] * VT[0][1];
    00764
    00765             abSquared = (a * a) + (b * b);
    00766
    00767             for (i = 1; i < W_DEGREE; i++)
    00768             {
    00769                 /* Compute distance from each of the points to that line    */
    00770                 distance[i] = a * VT[i][0] + b * VT[i][1] + c;
    00771                 if (distance[i] > 0.0) distance[i] =  (distance[i] * distance[i]) / abSquared;
    00772                 if (distance[i] < 0.0) distance[i] = -(distance[i] * distance[i]) / abSquared;
    00773             }
    00774         }
    00775
    00776         /* Find the largest distance */
    00777         max_distance_above = max_distance_below = 0.0;
    00778
    00779         for (i = 1; i < W_DEGREE; i++)
    00780         {
    00781             if (distance[i] < 0.0) max_distance_below = MIN(max_distance_below, distance[i]);
    00782             if (distance[i] > 0.0) max_distance_above = MAX(max_distance_above, distance[i]);
    00783         }
    00784
    00785         /* Implicit equation for "above" line */
    00786         intercept_1 = -(c + max_distance_above)/a;
    00787
    00788         /*  Implicit equation for "below" line */
    00789         intercept_2 = -(c + max_distance_below)/a;
    00790
    00791         /* Compute intercepts of bounding box   */
    00792         left_intercept = MIN(intercept_1, intercept_2);
    00793         right_intercept = MAX(intercept_1, intercept_2);
    00794
    00795         return 0.5 * (right_intercept-left_intercept) < BEZIER_EPSILON ? 1 : 0;
    00796     }
    00797
    00798     /*
    00799      *  ComputeXIntercept :
    00800      *  Compute intersection of chord from first control point to last
    00801      *  with 0-axis.
    00802      *
    00803      *    value_type    *VT;            Control points
    00804      */
    00805     static time_type ComputeXIntercept(value_type *VT)
    00806     {
    00807         distance_type YNM = VT[W_DEGREE][1] - VT[0][1];
    00808         return (YNM*VT[0][0] - (VT[W_DEGREE][0] - VT[0][0])*VT[0][1]) / YNM;
    00809     }
    00810
    00811     /*
    00812      *  FindRoots :
    00813      *  Given a 5th-degree equation in Bernstein-Bezier form, find
    00814      *  all of the roots in the interval [0, 1].  Return the number
    00815      *  of roots found.
    00816      *
    00817      *    value_type    *w;             The control points
    00818      *    time_type     *t;             RETURN candidate t-values
    00819      *    int           depth;          The depth of the recursion
    00820      */
    00821     static int FindRoots(value_type *w, time_type *t, int depth)
    00822     {
    00823         int         i;
    00824         value_type  Left[W_DEGREE+1];   /* New left and right   */
    00825         value_type  Right[W_DEGREE+1];  /* control polygons     */
    00826         int         left_count;         /* Solution count from  */
    00827         int         right_count;        /* children             */
    00828         time_type   left_t[W_DEGREE+1]; /* Solutions from kids  */
    00829         time_type   right_t[W_DEGREE+1];
    00830
    00831         switch (CrossingCount(w))
    00832         {
    00833             case 0 :
    00834             {   /* No solutions here    */
    00835                 return 0;
    00836             }
    00837             case 1 :
    00838             {   /* Unique solution  */
    00839                 /* Stop recursion when the tree is deep enough      */
    00840                 /* if deep enough, return 1 solution at midpoint    */
    00841                 if (depth >= MAXDEPTH)
    00842                 {
    00843                     t[0] = (w[0][0] + w[W_DEGREE][0]) / 2.0;
    00844                     return 1;
    00845                 }
    00846                 if (ControlPolygonFlatEnough(w))
    00847                 {
    00848                     t[0] = ComputeXIntercept(w);
    00849                     return 1;
    00850                 }
    00851                 break;
    00852             }
    00853         }
    00854
    00855         /* Otherwise, solve recursively after   */
    00856         /* subdividing control polygon          */
    00857         Bezier(w, W_DEGREE, 0.5, Left, Right);
    00858         left_count  = FindRoots(Left,  left_t,  depth+1);
    00859         right_count = FindRoots(Right, right_t, depth+1);
    00860
    00861         /* Gather solutions together    */
    00862         for (i = 0; i < left_count;  i++) t[i] = left_t[i];
    00863         for (i = 0; i < right_count; i++) t[i+left_count] = right_t[i];
    00864
    00865         /* Send back total number of solutions  */
    00866         return (left_count+right_count);
    00867     }
    00868
    00869     /*
    00870      *  ConvertToBezierForm :
    00871      *      Given a point and a Bezier curve, generate a 5th-degree
    00872      *      Bezier-format equation whose solution finds the point on the
    00873      *      curve nearest the user-defined point.
    00874      *
    00875      *    value_type&   P;              The point to find t for
    00876      *    value_type    *VT;            The control points
    00877      */
    00878     static void ConvertToBezierForm(const value_type& P, value_type *VT, value_type w[W_DEGREE+1])
    00879     {
    00880         int     i, j, k, m, n, ub, lb;
    00881         int     row, column;                /* Table indices                */
    00882         value_type  c[DEGREE+1];            /* VT(i)'s - P                  */
    00883         value_type  d[DEGREE];              /* VT(i+1) - VT(i)              */
    00884         distance_type   cdTable[3][4];      /* Dot product of c, d          */
    00885         static distance_type z[3][4] = {    /* Precomputed "z" for cubics   */
    00886             {1.0, 0.6, 0.3, 0.1},
    00887             {0.4, 0.6, 0.6, 0.4},
    00888             {0.1, 0.3, 0.6, 1.0}};
    00889
    00890         /* Determine the c's -- these are vectors created by subtracting */
    00891         /* point P from each of the control points                       */
    00892         for (i = 0; i <= DEGREE; i++)
    00893             c[i] = VT[i] - P;
    00894
    00895         /* Determine the d's -- these are vectors created by subtracting */
    00896         /* each control point from the next                              */
    00897         for (i = 0; i <= DEGREE - 1; i++)
    00898             d[i] = (VT[i+1] - VT[i]) * 3.0;
    00899
    00900         /* Create the c,d table -- this is a table of dot products of the */
    00901         /* c's and d's                                                    */
    00902         for (row = 0; row <= DEGREE - 1; row++)
    00903             for (column = 0; column <= DEGREE; column++)
    00904                 cdTable[row][column] = d[row] * c[column];
    00905
    00906         /* Now, apply the z's to the dot products, on the skew diagonal */
    00907         /* Also, set up the x-values, making these "points"             */
    00908         for (i = 0; i <= W_DEGREE; i++)
    00909         {
    00910             w[i][0] = (distance_type)(i) / W_DEGREE;
    00911             w[i][1] = 0.0;
    00912         }
    00913
    00914         n = DEGREE;
    00915         m = DEGREE-1;
    00916         for (k = 0; k <= n + m; k++)
    00917         {
    00918             lb = MAX(0, k - m);
    00919             ub = MIN(k, n);
    00920             for (i = lb; i <= ub; i++)
    00921             {
    00922                 j = k - i;
    00923                 w[i+j][1] += cdTable[j][i] * z[j][i];
    00924             }
    00925         }
    00926     }
    00927
    00928     /*
    00929      *  NearestPointOnCurve :
    00930      *      Compute the parameter value of the point on a Bezier
    00931      *      curve segment closest to some arbitrary, user-input point.
    00932      *      Return the point on the curve at that parameter value.
    00933      *
    00934      *    value_type&   P;          The user-supplied point
    00935      *    value_type    *VT;        Control points of cubic Bezier
    00936      */
    00937     static time_type NearestPointOnCurve(const value_type& P, value_type VT[4])
    00938     {
    00939         value_type  w[W_DEGREE+1];          /* Ctl pts of 5th-degree curve  */
    00940         time_type   t_candidate[W_DEGREE];  /* Possible roots                */
    00941         int         n_solutions;            /* Number of roots found         */
    00942         time_type   t;                      /* Parameter value of closest pt */
    00943
    00944         /*  Convert problem to 5th-degree Bezier form */
    00945         ConvertToBezierForm(P, VT, w);
    00946
    00947         /* Find all possible roots of 5th-degree equation */
    00948         n_solutions = FindRoots(w, t_candidate, 0);
    00949
    00950         /* Compare distances of P to all candidates, and to t=0, and t=1 */
    00951         {
    00952             distance_type   dist, new_dist;
    00953             value_type      p, v;
    00954             int             i;
    00955
    00956             /* Check distance to beginning of curve, where t = 0    */
    00957             dist = (P - VT[0]).mag_squared();
    00958             t = 0.0;
    00959
    00960             /* Find distances for candidate points  */
    00961             for (i = 0; i < n_solutions; i++)
    00962             {
    00963                 p = Bezier(VT, DEGREE, t_candidate[i], (value_type *)NULL, (value_type *)NULL);
    00964                 new_dist = (P - p).mag_squared();
    00965                 if (new_dist < dist)
    00966                 {
    00967                     dist = new_dist;
    00968                     t = t_candidate[i];
    00969                 }
    00970             }
    00971
    00972             /* Finally, look at distance to end point, where t = 1.0 */
    00973             new_dist = (P - VT[DEGREE]).mag_squared();
    00974             if (new_dist < dist)
    00975             {
    00976                 dist = new_dist;
    00977                 t = 1.0;
    00978             }
    00979         }
    00980
    00981         /*  Return the point on the curve at parameter value t */
    00982         return t;
    00983     }
    00984 };
    00985
    00986 _ETL_END_NAMESPACE
    00987
    00988 /* === E X T E R N S ======================================================= */
    00989
    00990 /* === E N D =============================================================== */
    00991
    00992 #endif