bezier.h
Go to the documentation of this file.
00001 00034 #ifndef SEEN_BEZIER_H 00035 #define SEEN_BEZIER_H 00036 00037 #include <2geom/coord.h> 00038 #include <valarray> 00039 #include <2geom/isnan.h> 00040 #include <2geom/d2.h> 00041 #include <2geom/solver.h> 00042 #include <boost/optional/optional.hpp> 00043 00044 namespace Geom { 00045 00046 inline Coord subdivideArr(Coord t, Coord const *v, Coord *left, Coord *right, unsigned order) { 00047 /* 00048 * Bernstein : 00049 * Evaluate a Bernstein function at a particular parameter value 00050 * Fill in control points for resulting sub-curves. 00051 * 00052 */ 00053 00054 unsigned N = order+1; 00055 std::valarray<Coord> row(N); 00056 for (unsigned i = 0; i < N; i++) 00057 row[i] = v[i]; 00058 00059 // Triangle computation 00060 const double omt = (1-t); 00061 if(left) 00062 left[0] = row[0]; 00063 if(right) 00064 right[order] = row[order]; 00065 for (unsigned i = 1; i < N; i++) { 00066 for (unsigned j = 0; j < N - i; j++) { 00067 row[j] = omt*row[j] + t*row[j+1]; 00068 } 00069 if(left) 00070 left[i] = row[0]; 00071 if(right) 00072 right[order-i] = row[order-i]; 00073 } 00074 return (row[0]); 00075 /* 00076 Coord vtemp[order+1][order+1]; 00077 00078 // Copy control points 00079 std::copy(v, v+order+1, vtemp[0]); 00080 00081 // Triangle computation 00082 for (unsigned i = 1; i <= order; i++) { 00083 for (unsigned j = 0; j <= order - i; j++) { 00084 vtemp[i][j] = lerp(t, vtemp[i-1][j], vtemp[i-1][j+1]); 00085 } 00086 } 00087 if(left != NULL) 00088 for (unsigned j = 0; j <= order; j++) 00089 left[j] = vtemp[j][0]; 00090 if(right != NULL) 00091 for (unsigned j = 0; j <= order; j++) 00092 right[j] = vtemp[order-j][j]; 00093 00094 return (vtemp[order][0]);*/ 00095 } 00096 00097 template <typename T> 00098 inline T bernsteinValueAt(double t, T const *c_, unsigned n) { 00099 double u = 1.0 - t; 00100 double bc = 1; 00101 double tn = 1; 00102 T tmp = c_[0]*u; 00103 for(unsigned i=1; i<n; i++){ 00104 tn = tn*t; 00105 bc = bc*(n-i+1)/i; 00106 tmp = (tmp + tn*bc*c_[i])*u; 00107 } 00108 return (tmp + tn*t*c_[n]); 00109 } 00110 00111 00112 class Bezier { 00113 private: 00114 std::valarray<Coord> c_; 00115 00116 friend Bezier portion(const Bezier & a, Coord from, Coord to); 00117 00118 friend OptInterval bounds_fast(Bezier const & b); 00119 00120 friend Bezier derivative(const Bezier & a); 00121 00122 protected: 00123 Bezier(Coord const c[], unsigned ord) : c_(c, ord+1){ 00124 //std::copy(c, c+order()+1, &c_[0]); 00125 } 00126 00127 public: 00128 unsigned int order() const { return c_.size()-1;} 00129 unsigned int size() const { return c_.size();} 00130 00131 Bezier() {} 00132 Bezier(const Bezier& b) :c_(b.c_) {} 00133 Bezier &operator=(Bezier const &other) { 00134 if ( c_.size() != other.c_.size() ) { 00135 c_.resize(other.c_.size()); 00136 } 00137 c_ = other.c_; 00138 return *this; 00139 } 00140 00141 struct Order { 00142 unsigned order; 00143 explicit Order(Bezier const &b) : order(b.order()) {} 00144 explicit Order(unsigned o) : order(o) {} 00145 operator unsigned() const { return order; } 00146 }; 00147 00148 //Construct an arbitrary order bezier 00149 Bezier(Order ord) : c_(0., ord.order+1) { 00150 assert(ord.order == order()); 00151 } 00152 00153 explicit Bezier(Coord c0) : c_(0., 1) { 00154 c_[0] = c0; 00155 } 00156 00157 //Construct an order-1 bezier (linear Bézier) 00158 Bezier(Coord c0, Coord c1) : c_(0., 2) { 00159 c_[0] = c0; c_[1] = c1; 00160 } 00161 00162 //Construct an order-2 bezier (quadratic Bézier) 00163 Bezier(Coord c0, Coord c1, Coord c2) : c_(0., 3) { 00164 c_[0] = c0; c_[1] = c1; c_[2] = c2; 00165 } 00166 00167 //Construct an order-3 bezier (cubic Bézier) 00168 Bezier(Coord c0, Coord c1, Coord c2, Coord c3) : c_(0., 4) { 00169 c_[0] = c0; c_[1] = c1; c_[2] = c2; c_[3] = c3; 00170 } 00171 00172 void resize (unsigned int n, Coord v = 0) 00173 { 00174 c_.resize (n, v); 00175 } 00176 00177 void clear() 00178 { 00179 c_.resize(0); 00180 } 00181 00182 inline unsigned degree() const { return order(); } 00183 00184 //IMPL: FragmentConcept 00185 typedef Coord output_type; 00186 inline bool isZero() const { 00187 for(unsigned i = 0; i <= order(); i++) { 00188 if(c_[i] != 0) return false; 00189 } 00190 return true; 00191 } 00192 inline bool isConstant() const { 00193 for(unsigned i = 1; i <= order(); i++) { 00194 if(c_[i] != c_[0]) return false; 00195 } 00196 return true; 00197 } 00198 inline bool isFinite() const { 00199 for(unsigned i = 0; i <= order(); i++) { 00200 if(!IS_FINITE(c_[i])) return false; 00201 } 00202 return true; 00203 } 00204 inline Coord at0() const { return c_[0]; } 00205 inline Coord at1() const { return c_[order()]; } 00206 00207 inline Coord valueAt(double t) const { 00208 int n = order(); 00209 double u, bc, tn, tmp; 00210 int i; 00211 u = 1.0 - t; 00212 bc = 1; 00213 tn = 1; 00214 tmp = c_[0]*u; 00215 for(i=1; i<n; i++){ 00216 tn = tn*t; 00217 bc = bc*(n-i+1)/i; 00218 tmp = (tmp + tn*bc*c_[i])*u; 00219 } 00220 return (tmp + tn*t*c_[n]); 00221 //return subdivideArr(t, &c_[0], NULL, NULL, order()); 00222 } 00223 inline Coord operator()(double t) const { return valueAt(t); } 00224 00225 SBasis toSBasis() const; 00226 // inline SBasis toSBasis() const { 00227 // SBasis sb; 00228 // bezier_to_sbasis(sb, (*this)); 00229 // return sb; 00230 // //return bezier_to_sbasis(&c_[0], order()); 00231 // } 00232 00233 //Only mutator 00234 inline Coord &operator[](unsigned ix) { return c_[ix]; } 00235 inline Coord const &operator[](unsigned ix) const { return const_cast<std::valarray<Coord>&>(c_)[ix]; } 00236 //inline Coord const &operator[](unsigned ix) const { return c_[ix]; } 00237 inline void setPoint(unsigned ix, double val) { c_[ix] = val; } 00238 00242 std::vector<Coord> valueAndDerivatives(Coord t, unsigned n_derivs) const { 00243 /* This is inelegant, as it uses several extra stores. I think there might be a way to 00244 * evaluate roughly in situ. */ 00245 00246 // initialize return vector with zeroes, such that we only need to replace the non-zero derivs 00247 std::vector<Coord> val_n_der(n_derivs + 1, Coord(0.0)); 00248 00249 // initialize temp storage variables 00250 std::valarray<Coord> d_(order()+1); 00251 for (unsigned i = 0; i < size(); i++) { 00252 d_[i] = c_[i]; 00253 } 00254 00255 unsigned nn = n_derivs + 1; 00256 if(n_derivs > order()) { 00257 nn = order()+1; // only calculate the non zero derivs 00258 } 00259 for (unsigned di = 0; di < nn; di++) { 00260 //val_n_der[di] = (subdivideArr(t, &d_[0], NULL, NULL, order() - di)); 00261 val_n_der[di] = bernsteinValueAt(t, &d_[0], order() - di); 00262 for (unsigned i = 0; i < order() - di; i++) { 00263 d_[i] = (order()-di)*(d_[i+1] - d_[i]); 00264 } 00265 } 00266 00267 return val_n_der; 00268 } 00269 00270 std::pair<Bezier, Bezier > subdivide(Coord t) const { 00271 Bezier a(Bezier::Order(*this)), b(Bezier::Order(*this)); 00272 subdivideArr(t, &const_cast<std::valarray<Coord>&>(c_)[0], &a.c_[0], &b.c_[0], order()); 00273 return std::pair<Bezier, Bezier >(a, b); 00274 } 00275 00276 std::vector<double> roots() const { 00277 std::vector<double> solutions; 00278 find_bernstein_roots(&const_cast<std::valarray<Coord>&>(c_)[0], order(), solutions, 0, 0.0, 1.0); 00279 return solutions; 00280 } 00281 std::vector<double> roots(Interval const ivl) const { 00282 std::vector<double> solutions; 00283 find_bernstein_roots(&const_cast<std::valarray<Coord>&>(c_)[0], order(), solutions, 0, ivl[0], ivl[1]); 00284 return solutions; 00285 } 00286 }; 00287 00288 00289 void bezier_to_sbasis (SBasis & sb, Bezier const& bz); 00290 00291 00292 inline 00293 SBasis Bezier::toSBasis() const { 00294 SBasis sb; 00295 bezier_to_sbasis(sb, (*this)); 00296 return sb; 00297 //return bezier_to_sbasis(&c_[0], order()); 00298 } 00299 00300 //TODO: implement others 00301 inline Bezier operator+(const Bezier & a, double v) { 00302 Bezier result = Bezier(Bezier::Order(a)); 00303 for(unsigned i = 0; i <= a.order(); i++) 00304 result[i] = a[i] + v; 00305 return result; 00306 } 00307 00308 inline Bezier operator-(const Bezier & a, double v) { 00309 Bezier result = Bezier(Bezier::Order(a)); 00310 for(unsigned i = 0; i <= a.order(); i++) 00311 result[i] = a[i] - v; 00312 return result; 00313 } 00314 00315 inline Bezier operator*(const Bezier & a, double v) { 00316 Bezier result = Bezier(Bezier::Order(a)); 00317 for(unsigned i = 0; i <= a.order(); i++) 00318 result[i] = a[i] * v; 00319 return result; 00320 } 00321 00322 inline Bezier operator/(const Bezier & a, double v) { 00323 Bezier result = Bezier(Bezier::Order(a)); 00324 for(unsigned i = 0; i <= a.order(); i++) 00325 result[i] = a[i] / v; 00326 return result; 00327 } 00328 00329 inline Bezier reverse(const Bezier & a) { 00330 Bezier result = Bezier(Bezier::Order(a)); 00331 for(unsigned i = 0; i <= a.order(); i++) 00332 result[i] = a[a.order() - i]; 00333 return result; 00334 } 00335 00336 inline Bezier portion(const Bezier & a, double from, double to) { 00337 //TODO: implement better? 00338 std::valarray<Coord> res(a.order() + 1); 00339 if(from == 0) { 00340 if(to == 1) { return Bezier(a); } 00341 subdivideArr(to, &const_cast<Bezier&>(a).c_[0], &res[0], NULL, a.order()); 00342 return Bezier(&res[0], a.order()); 00343 } 00344 subdivideArr(from, &const_cast<Bezier&>(a).c_[0], NULL, &res[0], a.order()); 00345 if(to == 1) return Bezier(&res[0], a.order()); 00346 std::valarray<Coord> res2(a.order()+1); 00347 subdivideArr((to - from)/(1 - from), &res[0], &res2[0], NULL, a.order()); 00348 return Bezier(&res2[0], a.order()); 00349 } 00350 00351 // XXX Todo: how to handle differing orders 00352 inline std::vector<Point> bezier_points(const D2<Bezier > & a) { 00353 std::vector<Point> result; 00354 for(unsigned i = 0; i <= a[0].order(); i++) { 00355 Point p; 00356 for(unsigned d = 0; d < 2; d++) p[d] = a[d][i]; 00357 result.push_back(p); 00358 } 00359 return result; 00360 } 00361 00362 inline Bezier derivative(const Bezier & a) { 00363 //if(a.order() == 1) return Bezier(0.0); 00364 if(a.order() == 1) return Bezier(a.c_[1]-a.c_[0]); 00365 Bezier der(Bezier::Order(a.order()-1)); 00366 00367 for(unsigned i = 0; i < a.order(); i++) { 00368 der.c_[i] = a.order()*(a.c_[i+1] - a.c_[i]); 00369 } 00370 return der; 00371 } 00372 00373 inline Bezier integral(const Bezier & a) { 00374 Bezier inte(Bezier::Order(a.order()+1)); 00375 00376 inte[0] = 0; 00377 for(unsigned i = 0; i < inte.order(); i++) { 00378 inte[i+1] = inte[i] + a[i]/(inte.order()); 00379 } 00380 return inte; 00381 } 00382 00383 inline OptInterval bounds_fast(Bezier const & b) { 00384 return Interval::fromArray(&const_cast<Bezier&>(b).c_[0], b.size()); 00385 } 00386 00387 //TODO: better bounds exact 00388 inline OptInterval bounds_exact(Bezier const & b) { 00389 return bounds_exact(b.toSBasis()); 00390 } 00391 00392 inline OptInterval bounds_local(Bezier const & b, OptInterval i) { 00393 //return bounds_local(b.toSBasis(), i); 00394 if (i) { 00395 return bounds_fast(portion(b, i->min(), i->max())); 00396 } else { 00397 return OptInterval(); 00398 } 00399 } 00400 00401 inline std::ostream &operator<< (std::ostream &out_file, const Bezier & b) { 00402 for(unsigned i = 0; i < b.size(); i++) { 00403 out_file << b[i] << ", "; 00404 } 00405 return out_file; 00406 } 00407 00408 } 00409 #endif //SEEN_BEZIER_H 00410 00411 /* 00412 Local Variables: 00413 mode:c++ 00414 c-file-style:"stroustrup" 00415 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) 00416 indent-tabs-mode:nil 00417 fill-column:99 00418 End: 00419 */ 00420 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
