+++ /dev/null
-/*! ========================================================================
-** Extended Template Library
-** Bezier Template Class Implementation
-** $Id: _bezier.h,v 1.1.1.1 2005/01/04 01:31:46 darco Exp $
-**
-** Copyright (c) 2002 Robert B. Quattlebaum Jr.
-**
-** This package is free software; you can redistribute it and/or
-** modify it under the terms of the GNU General Public License as
-** published by the Free Software Foundation; either version 2 of
-** the License, or (at your option) any later version.
-**
-** This package is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-** General Public License for more details.
-**
-** === N O T E S ===========================================================
-**
-** This is an internal header file, included by other ETL headers.
-** You should not attempt to use it directly.
-**
-** ========================================================================= */
-
-/* === S T A R T =========================================================== */
-
-#ifndef __ETL_BEZIER_H
-#define __ETL_BEZIER_H
-
-/* === H E A D E R S ======================================================= */
-
-#include "_curve_func.h"
-#include <ETL/fixed>
-
-/* === M A C R O S ========================================================= */
-
-/* === T Y P E D E F S ===================================================== */
-
-/* === C L A S S E S & S T R U C T S ======================================= */
-
-_ETL_BEGIN_NAMESPACE
-
-template<typename V,typename T> class bezier;
-
-//! Cubic Bezier Curve Base Class
-// This generic implementation uses the DeCasteljau algorithm.
-// Works for just about anything that has an affine combination function
-template <typename V,typename T=float>
-class bezier_base : public std::unary_function<T,V>
-{
-public:
- typedef V value_type;
- typedef T time_type;
-
-private:
- value_type a,b,c,d;
- time_type r,s;
-
-protected:
- affine_combo<value_type,time_type> affine_func;
-
-public:
- bezier_base():r(0.0),s(1.0) { }
- bezier_base(
- const value_type &a, const value_type &b, const value_type &c, const value_type &d,
- const time_type &r=0.0, const time_type &s=1.0):
- a(a),b(b),c(c),d(d),r(r),s(s) { sync(); }
-
- void sync()
- {
- }
-
- value_type
- operator()(time_type t)const
- {
- t=(t-r)/(s-r);
- return
- affine_func(
- affine_func(
- affine_func(a,b,t),
- affine_func(b,c,t)
- ,t),
- affine_func(
- affine_func(b,c,t),
- affine_func(c,d,t)
- ,t)
- ,t);
- }
-
- /*
- void evaluate(time_type t, value_type &f, value_type &df) const
- {
- t=(t-r)/(s-r);
-
- value_type p1 = affine_func(
- affine_func(a,b,t),
- affine_func(b,c,t)
- ,t);
- value_type p2 = affine_func(
- affine_func(b,c,t),
- affine_func(c,d,t)
- ,t);
-
- f = affine_func(p1,p2,t);
- df = (p2-p1)*3;
- }
- */
-
- void set_rs(time_type new_r, time_type new_s) { r=new_r; s=new_s; }
- void set_r(time_type new_r) { r=new_r; }
- void set_s(time_type new_s) { s=new_s; }
- const time_type &get_r()const { return r; }
- const time_type &get_s()const { return s; }
- time_type get_dt()const { return s-r; }
-
- bool intersect_hull(const bezier_base<value_type,time_type> &x)const
- {
- return 0;
- }
-
- //! Bezier curve intersection function
- /*! Calculates the time of intersection
- ** for the calling curve.
- **
- ** I still have not figured out a good generic
- ** method of doing this for a bi-infinite
- ** cubic bezier curve calculated with the DeCasteljau
- ** algorithm.
- **
- ** One method, although it does not work for the
- ** entire bi-infinite curve, is to iteratively
- ** intersect the hulls. However, we would only detect
- ** intersections that occur between R and S.
- **
- ** It is entirely possible that a new construct similar
- ** to the affine combination function will be necessary
- ** for this to work properly.
- **
- ** For now, this function is BROKEN. (although it works
- ** for the floating-point specializations, using newton's method)
- */
- time_type intersect(const bezier_base<value_type,time_type> &x, time_type near=0.0)const
- {
- return 0;
- }
-
- /* subdivide at some time t into 2 separate curves left and right
-
- b0 l1
- * 0+1 l2
- b1 * 1+2*1+2 l3
- * 1+2 * 0+3*1+3*2+3 l4,r1
- b2 * 1+2*2+2 r2 *
- * 2+3 r3 *
- b3 r4 *
- *
-
- 0.1 2.3 -> 0.1 2 3 4 5.6
- */
-/* void subdivide(bezier_base *left, bezier_base *right, const time_type &time = (time_type)0.5) const
- {
- time_type t = (time-r)/(s-r);
- bezier_base lt,rt;
-
- value_type temp;
-
- //1st stage points to keep
- lt.a = a;
- rt.d = d;
-
- //2nd stage calc
- lt.b = affine_func(a,b,t);
- temp = affine_func(b,c,t);
- rt.c = affine_func(c,d,t);
-
- //3rd stage calc
- lt.c = affine_func(lt.b,temp,t);
- rt.b = affine_func(temp,rt.c,t);
-
- //last stage calc
- lt.d = rt.a = affine_func(lt.c,rt.b,t);
-
- //set the time range for l,r (the inside values should be 1, 0 respectively)
- lt.r = r;
- rt.s = s;
-
- //give back the curves
- if(left) *left = lt;
- if(right) *right = rt;
- }
- */
- value_type &
- operator[](int i)
- { return (&a)[i]; }
-
- const value_type &
- operator[](int i) const
- { return (&a)[i]; }
-};
-
-
-#if 1
-// Fast float implementation of a cubic bezier curve
-template <>
-class bezier_base<float,float> : public std::unary_function<float,float>
-{
-public:
- typedef float value_type;
- typedef float time_type;
-private:
- affine_combo<value_type,time_type> affine_func;
- value_type a,b,c,d;
- time_type r,s;
-
- value_type _coeff[4];
- time_type drs; // reciprocal of (s-r)
-public:
- bezier_base():r(0.0),s(1.0),drs(1.0) { }
- bezier_base(
- const value_type &a, const value_type &b, const value_type &c, const value_type &d,
- const time_type &r=0.0, const time_type &s=1.0):
- a(a),b(b),c(c),d(d),r(r),s(s),drs(1.0/(s-r)) { sync(); }
-
- void sync()
- {
-// drs=1.0/(s-r);
- _coeff[0]= a;
- _coeff[1]= b*3 - a*3;
- _coeff[2]= c*3 - b*6 + a*3;
- _coeff[3]= d - c*3 + b*3 - a;
- }
-
- // Cost Summary: 4 products, 3 sums, and 1 difference.
- inline value_type
- operator()(time_type t)const
- { t-=r; t*=drs; return _coeff[0]+(_coeff[1]+(_coeff[2]+(_coeff[3])*t)*t)*t; }
-
- void set_rs(time_type new_r, time_type new_s) { r=new_r; s=new_s; drs=1.0/(s-r); }
- void set_r(time_type new_r) { r=new_r; drs=1.0/(s-r); }
- void set_s(time_type new_s) { s=new_s; drs=1.0/(s-r); }
- const time_type &get_r()const { return r; }
- const time_type &get_s()const { return s; }
- time_type get_dt()const { return s-r; }
-
- //! Bezier curve intersection function
- /*! Calculates the time of intersection
- ** for the calling curve.
- */
- time_type intersect(const bezier_base<value_type,time_type> &x, time_type t=0.0,int i=15)const
- {
- //BROKEN - the time values of the 2 curves should be independent
- value_type system[4];
- system[0]=_coeff[0]-x._coeff[0];
- system[1]=_coeff[1]-x._coeff[1];
- system[2]=_coeff[2]-x._coeff[2];
- system[3]=_coeff[3]-x._coeff[3];
-
- t-=r;
- t*=drs;
-
- // Newton's method
- // Inner loop cost summary: 7 products, 5 sums, 1 difference
- for(;i;i--)
- t-= (system[0]+(system[1]+(system[2]+(system[3])*t)*t)*t)/
- (system[1]+(system[2]*2+(system[3]*3)*t)*t);
-
- t*=(s-r);
- t+=r;
-
- return t;
- }
-
- value_type &
- operator[](int i)
- { return (&a)[i]; }
-
- const value_type &
- operator[](int i) const
- { return (&a)[i]; }
-};
-
-
-// Fast double implementation of a cubic bezier curve
-template <>
-class bezier_base<double,float> : public std::unary_function<float,double>
-{
-public:
- typedef double value_type;
- typedef float time_type;
-private:
- affine_combo<value_type,time_type> affine_func;
- value_type a,b,c,d;
- time_type r,s;
-
- value_type _coeff[4];
- time_type drs; // reciprocal of (s-r)
-public:
- bezier_base():r(0.0),s(1.0),drs(1.0) { }
- bezier_base(
- const value_type &a, const value_type &b, const value_type &c, const value_type &d,
- const time_type &r=0.0, const time_type &s=1.0):
- a(a),b(b),c(c),d(d),r(r),s(s),drs(1.0/(s-r)) { sync(); }
-
- void sync()
- {
-// drs=1.0/(s-r);
- _coeff[0]= a;
- _coeff[1]= b*3 - a*3;
- _coeff[2]= c*3 - b*6 + a*3;
- _coeff[3]= d - c*3 + b*3 - a;
- }
-
- // 4 products, 3 sums, and 1 difference.
- inline value_type
- operator()(time_type t)const
- { t-=r; t*=drs; return _coeff[0]+(_coeff[1]+(_coeff[2]+(_coeff[3])*t)*t)*t; }
-
- void set_rs(time_type new_r, time_type new_s) { r=new_r; s=new_s; drs=1.0/(s-r); }
- void set_r(time_type new_r) { r=new_r; drs=1.0/(s-r); }
- void set_s(time_type new_s) { s=new_s; drs=1.0/(s-r); }
- const time_type &get_r()const { return r; }
- const time_type &get_s()const { return s; }
- time_type get_dt()const { return s-r; }
-
- //! Bezier curve intersection function
- /*! Calculates the time of intersection
- ** for the calling curve.
- */
- time_type intersect(const bezier_base<value_type,time_type> &x, time_type t=0.0,int i=15)const
- {
- //BROKEN - the time values of the 2 curves should be independent
- value_type system[4];
- system[0]=_coeff[0]-x._coeff[0];
- system[1]=_coeff[1]-x._coeff[1];
- system[2]=_coeff[2]-x._coeff[2];
- system[3]=_coeff[3]-x._coeff[3];
-
- t-=r;
- t*=drs;
-
- // Newton's method
- // Inner loop: 7 products, 5 sums, 1 difference
- for(;i;i--)
- t-= (system[0]+(system[1]+(system[2]+(system[3])*t)*t)*t)/
- (system[1]+(system[2]*2+(system[3]*3)*t)*t);
-
- t*=(s-r);
- t+=r;
-
- return t;
- }
-
- value_type &
- operator[](int i)
- { return (&a)[i]; }
-
- const value_type &
- operator[](int i) const
- { return (&a)[i]; }
-};
-
-//#ifdef __FIXED__
-
-// Fast double implementation of a cubic bezier curve
-/*
-template <>
-template <class T,unsigned int FIXED_BITS>
-class bezier_base<fixed_base<T,FIXED_BITS> > : std::unary_function<fixed_base<T,FIXED_BITS>,fixed_base<T,FIXED_BITS> >
-{
-public:
- typedef fixed_base<T,FIXED_BITS> value_type;
- typedef fixed_base<T,FIXED_BITS> time_type;
-
-private:
- affine_combo<value_type,time_type> affine_func;
- value_type a,b,c,d;
- time_type r,s;
-
- value_type _coeff[4];
- time_type drs; // reciprocal of (s-r)
-public:
- bezier_base():r(0.0),s(1.0),drs(1.0) { }
- bezier_base(
- const value_type &a, const value_type &b, const value_type &c, const value_type &d,
- const time_type &r=0, const time_type &s=1):
- a(a),b(b),c(c),d(d),r(r),s(s),drs(1.0/(s-r)) { sync(); }
-
- void sync()
- {
- drs=time_type(1)/(s-r);
- _coeff[0]= a;
- _coeff[1]= b*3 - a*3;
- _coeff[2]= c*3 - b*6 + a*3;
- _coeff[3]= d - c*3 + b*3 - a;
- }
-
- // 4 products, 3 sums, and 1 difference.
- inline value_type
- operator()(time_type t)const
- { t-=r; t*=drs; return _coeff[0]+(_coeff[1]+(_coeff[2]+(_coeff[3])*t)*t)*t; }
-
- void set_rs(time_type new_r, time_type new_s) { r=new_r; s=new_s; drs=time_type(1)/(s-r); }
- void set_r(time_type new_r) { r=new_r; drs=time_type(1)/(s-r); }
- void set_s(time_type new_s) { s=new_s; drs=time_type(1)/(s-r); }
- const time_type &get_r()const { return r; }
- const time_type &get_s()const { return s; }
- time_type get_dt()const { return s-r; }
-
- //! Bezier curve intersection function
- //! Calculates the time of intersection
- // for the calling curve.
- //
- time_type intersect(const bezier_base<value_type,time_type> &x, time_type t=0,int i=15)const
- {
- value_type system[4];
- system[0]=_coeff[0]-x._coeff[0];
- system[1]=_coeff[1]-x._coeff[1];
- system[2]=_coeff[2]-x._coeff[2];
- system[3]=_coeff[3]-x._coeff[3];
-
- t-=r;
- t*=drs;
-
- // Newton's method
- // Inner loop: 7 products, 5 sums, 1 difference
- for(;i;i--)
- t-=(time_type) ( (system[0]+(system[1]+(system[2]+(system[3])*t)*t)*t)/
- (system[1]+(system[2]*2+(system[3]*3)*t)*t) );
-
- t*=(s-r);
- t+=r;
-
- return t;
- }
-
- value_type &
- operator[](int i)
- { return (&a)[i]; }
-
- const value_type &
- operator[](int i) const
- { return (&a)[i]; }
-};
-*/
-//#endif
-
-#endif
-
-
-
-template <typename V, typename T>
-class bezier_iterator
-{
-public:
-
- struct iterator_category {};
- typedef V value_type;
- typedef T difference_type;
- typedef V reference;
-
-private:
- difference_type t;
- difference_type dt;
- bezier_base<V,T> curve;
-
-public:
-
-/*
- reference
- operator*(void)const { return curve(t); }
- const surface_iterator&
-
- operator++(void)
- { t+=dt; return &this; }
-
- const surface_iterator&
- operator++(int)
- { hermite_iterator _tmp=*this; t+=dt; return _tmp; }
-
- const surface_iterator&
- operator--(void)
- { t-=dt; return &this; }
-
- const surface_iterator&
- operator--(int)
- { hermite_iterator _tmp=*this; t-=dt; return _tmp; }
-
-
- surface_iterator
- operator+(difference_type __n) const
- { return surface_iterator(data+__n[0]+__n[1]*pitch,pitch); }
-
- surface_iterator
- operator-(difference_type __n) const
- { return surface_iterator(data-__n[0]-__n[1]*pitch,pitch); }
-*/
-
-};
-
-template <typename V,typename T=float>
-class bezier : public bezier_base<V,T>
-{
-public:
- typedef V value_type;
- typedef T time_type;
- typedef float distance_type;
- typedef bezier_iterator<V,T> iterator;
- typedef bezier_iterator<V,T> const_iterator;
-
- distance_func<value_type> dist;
-
- using bezier_base<V,T>::get_r;
- using bezier_base<V,T>::get_s;
- using bezier_base<V,T>::get_dt;
-
-public:
- bezier() { }
- bezier(const value_type &a, const value_type &b, const value_type &c, const value_type &d):
- bezier_base<V,T>(a,b,c,d) { }
-
-
- const_iterator begin()const;
- const_iterator end()const;
-
- time_type find_closest(const value_type& x, int i=7, time_type r=(0), time_type s=(1))const
- {
- float t((r+s)*0.5);
- for(;i;i--)
- {
- if(dist(operator()((s-r)*(1.0/3.0)+r),x) < dist(operator()((s-r)*(2.0/3.0)+r),x))
- s=t;
- else
- r=t;
- t=((r+s)*0.5);
- }
- return t;
- }
-
-
- distance_type find_distance(time_type r, time_type s, int steps=7)const
- {
- const time_type inc((s-r)/steps);
- distance_type ret(0);
- value_type last(operator()(r));
-
- for(r+=inc;r<s;r+=inc)
- {
- const value_type n(operator()(r));
- ret+=dist.uncook(dist(last,n));
- last=n;
- }
- ret+=dist.uncook(dist(last,operator()(r)))*(s-(r-inc))/inc;
-
- return ret;
- }
-
- distance_type length()const { return find_distance(get_r(),get_s()); }
-
- /* subdivide at some time t into 2 separate curves left and right
-
- b0 l1
- * 0+1 l2
- b1 * 1+2*1+2 l3
- * 1+2 * 0+3*1+3*2+3 l4,r1
- b2 * 1+2*2+2 r2 *
- * 2+3 r3 *
- b3 r4 *
- *
-
- 0.1 2.3 -> 0.1 2 3 4 5.6
- */
- void subdivide(bezier *left, bezier *right, const time_type &time = (time_type)0.5) const
- {
- time_type t=(t-get_r())/get_dt();
- bezier lt,rt;
-
- value_type temp;
- const value_type& a((*this)[0]);
- const value_type& b((*this)[1]);
- const value_type& c((*this)[2]);
- const value_type& d((*this)[3]);
-
- //1st stage points to keep
- lt[0] = a;
- rt[3] = d;
-
- //2nd stage calc
- lt[1] = affine_func(a,b,t);
- temp = affine_func(b,c,t);
- rt[2] = affine_func(c,d,t);
-
- //3rd stage calc
- lt[2] = affine_func(lt[1],temp,t);
- rt[1] = affine_func(temp,rt[2],t);
-
- //last stage calc
- lt[3] = rt[0] = affine_func(lt[2],rt[1],t);
-
- //set the time range for l,r (the inside values should be 1, 0 respectively)
- lt.set_r(get_r());
- rt.set_s(get_s());
-
- lt.sync();
- rt.sync();
-
- //give back the curves
- if(left) *left = lt;
- if(right) *right = rt;
- }
-
-
- void evaluate(time_type t, value_type &f, value_type &df) const
- {
- t=(t-get_r())/get_dt();
-
- const value_type& a((*this)[0]);
- const value_type& b((*this)[1]);
- const value_type& c((*this)[2]);
- const value_type& d((*this)[3]);
-
- const value_type p1 = affine_func(
- affine_func(a,b,t),
- affine_func(b,c,t)
- ,t);
- const value_type p2 = affine_func(
- affine_func(b,c,t),
- affine_func(c,d,t)
- ,t);
-
- f = affine_func(p1,p2,t);
- df = (p2-p1)*3;
- }
-};
-
-_ETL_END_NAMESPACE
-
-/* === E X T E R N S ======================================================= */
-
-/* === E N D =============================================================== */
-
-#endif