changed: gcc8 base update
[opensg.git] / Source / System / NodeCores / Drawables / Nurbs / Internal / OSGBezierCurve2D.cpp
blob74a0caf3a158230c383aa75bb6e63951ee89ab16
1 /*---------------------------------------------------------------------------*\
2 * OpenSG NURBS Library *
3 * *
4 * *
5 * Copyright (C) 2001-2006 by the University of Bonn, Computer Graphics Group*
6 * *
7 * http://cg.cs.uni-bonn.de/ *
8 * *
9 * contact: edhellon@cs.uni-bonn.de, guthe@cs.uni-bonn.de, rk@cs.uni-bonn.de *
10 * *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
13 * License *
14 * *
15 * This library is free software; you can redistribute it and/or modify it *
16 * under the terms of the GNU Library General Public License as published *
17 * by the Free Software Foundation, version 2. *
18 * *
19 * This library is distributed in the hope that it will be useful, but *
20 * WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
22 * Library General Public License for more details. *
23 * *
24 * You should have received a copy of the GNU Library General Public *
25 * License along with this library; if not, write to the Free Software *
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
27 * *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
30 * Changes *
31 * *
32 * *
33 * *
34 * *
35 * *
36 * *
37 \*---------------------------------------------------------------------------*/
38 #ifdef WIN32
39 # pragma warning (disable : 985)
40 #endif
42 #include "OSGBezierCurve2D.h"
44 OSG_USING_NAMESPACE
47 #ifdef _DEBUG
48 #ifdef WIN32
49 #undef THIS_FILE
50 static char THIS_FILE[] = __FILE__;
51 #endif
52 #endif
54 //setup functions
55 int BezierCurve2D::setControlPointVector(const DCTPVec3dvector& cps)
57 if(cps.size() < 2)
58 return -1; //invalid dimension, at least rwo points are required
59 control_points = cps;
60 return 0;
64 //some REAL functionality
65 //! Compute the value of the Bezier curve at given the parameter value.
66 /*!
67 * This function computes the value of the Bezier curve
68 * at the given parameter value, using de Casteljau's method of
69 * repeated linear interpolations.
71 * \param t the parameter value at which to compute the approximation
72 * \param error flag to indicate if an error has happened
73 * \return the computed value
76 Vec2d BezierCurve2D::computewdeCasteljau(double t, int &error)
78 //FIXME: verification before goin' into computation!!
79 DCTPVec3dvector Q = control_points; //local array not to destroy da other points
80 DCTPVec3dvector::size_type n = Q.size() - 1;
81 Vec2d result;
83 error = 0;
84 if(n < 1) //too few points, at least 2 needed
86 error = -1;
87 Q[0][0] = DCTP_EPS * floor(Q[0][0] / DCTP_EPS);
88 Q[0][1] = DCTP_EPS * floor(Q[0][1] / DCTP_EPS);
89 result[0] = Q[0][0] / Q[0][2];
90 result[1] = Q[0][1] / Q[0][2];
91 return result;
93 // std::cerr.precision( DCTP_PRECISION );
94 // for ( unsigned int kkk = 0; kkk < Q.size(); kkk++ )
95 // std::cerr << Q[ kkk ] << " " ;
96 // std::cerr << std::endl;
98 // orig fecu code
99 for(DCTPVec3dvector::size_type k = 0; k < n; ++k)
100 for(DCTPVec3dvector::size_type i = 0; i < n - k; ++i)
101 Q[i] = Q[i] * (1.0 - t) + Q[i + 1] * t;
103 result[0] = Q[0][0] / Q[0][2];
104 result[1] = Q[0][1] / Q[0][2];
106 return result;
109 //! Compute the linear approximation of the Bezier curve at the given parameter value.
111 * This function computes the linear approximation of the Bezier curve
112 * at the given parameter value.
114 * \param t the parameter value at which to compute the approximation
115 * \param error flag to indicate if an error has happened
116 * \return the approximated value
119 Vec2d BezierCurve2D::computeLinearApproximation(double t, int &error)
121 //FIXME: verification before goin' into computation!!
122 DCTPVec3dvector::size_type n = control_points.size() - 1;
123 Vec2d result(0.0, 0.0);
124 Vec3d tempres;
126 error = 0;
127 if(n < 1) //too few points, at least 2 needed
129 error = -1;
130 return result;
132 tempres = control_points[0] * (1 - t) + control_points[n] * t;
133 result[0] = tempres[0] / tempres[2];
134 result[1] = tempres[1] / tempres[2];
135 return (result);
138 //! Subdivide Bezier curve at midpoint into two new curves.
140 * This function subdivides a Bezier curve into two new Bezier curves
141 * of the same degree at the midpoint, using de Casteljau's
142 * algorithm.
144 * \param newbeziers the two new Bezier curves (returned in a vector of size 2)
145 * \return zero on success, and a negative value when some error occured.
149 int BezierCurve2D::midPointSubDivision(bezier2dvector &newbeziers)
151 // This function is time critical so optimize at the cost of readabiltity...
152 DCTPVec3dvector::size_type n = control_points.size();
154 if(n < 2) //too few points, at least 2 needed to split curve
156 return -1;
159 newbeziers.resize(2); // we return exactly two curves
160 DCTPVec3dvector::size_type i, k;
162 DCTPVec3dvector &cp1 = newbeziers[0].control_points;
163 DCTPVec3dvector &cp2 = newbeziers[1].control_points;
165 cp1.clear(); // very imporatant for performance (no copying around of obsolte stuff!)
166 cp2.clear(); // very imporatant for performance (no copying around of obsolte stuff!)
167 cp1.resize(n);
168 cp2.resize(n);
170 for(k = 0; k < n; ++k)
172 cp1[k] = control_points[k];
175 --n;
177 for(k = 0; k < n; ++k)
179 cp2[n - k] = cp1[n];
181 for(i = n; i > k; --i)
183 cp1[i] += cp1[i - 1];
184 cp1[i] *= 0.5;
188 cp2[0] = cp1[n];
189 return 0;
192 //! Subdivide Bezier curve at midpoint into two new curves.
194 * This function subdivides a Bezier curve into two new Bezier curves
195 * of the same degree at the midpoint, using de Casteljau's
196 * algorithm.
198 * \param newbeziers the two new Bezier curves (returned in a vector of size 2)
199 * \return zero on success, and a negative value when some error occured.
203 int BezierCurve2D::midPointSubDivision(BezierCurve2D &newcurve)
205 // This function is time critical so optimize at the cost of readabiltity...
206 DCTPVec3dvector::size_type n = control_points.size();
208 if(n < 2)
210 return -1; //too few points, at least 2 needed to split curve
213 DCTPVec3dvector::size_type i, k;
215 DCTPVec3dvector &cp1 = control_points;
216 DCTPVec3dvector &cp2 = newcurve.control_points;
218 cp2.clear(); // very imporatant for performance (no copying around of obsolte stuff!)
219 cp2.resize(n);
221 --n;
223 for(k = 0; k < n; ++k)
225 cp2[n - k] = cp1[n];
227 // cp2[ n - k ][0] = cp1[ n ][0];
228 // cp2[ n - k ][1] = cp1[ n ][1];
229 for(i = n; i > k; --i)
231 cp1[i] += cp1[i - 1];
232 // cp1[ i ][0] += cp1[ i - 1 ][0];
233 // cp1[ i ][1] += cp1[ i - 1 ][1];
234 cp1[i] *= 0.5;
235 // cp1[ i ][0] *= 0.5;
236 // cp1[ i ][1] *= 0.5;
240 cp2[0] = cp1[n];
241 // cp2[ 0 ][0] = cp1[ n ][0];
242 // cp2[ 0 ][1] = cp1[ n ][1];
244 return 0;
247 //! Subdivide Bezier curve at t into two new curves.
249 * This function subdivides a Bezier curve into two new Bezier curves
250 * of the same degree at the parameter value `t', using de Casteljau's
251 * algorithm.
253 * \param t the parameter at which to subdivide the curve.
254 * \param newbeziers the two new Bezier curves (returned in a vector of size 2)
255 * \return zero on success, and a negative value when some error occured.
259 int BezierCurve2D::subDivision(double t, bezier2dvector &newbeziers)
261 if(t <= 0.0 || t >= 1.0)
262 return -1; // t must be between (0, 1) exclusive
264 newbeziers.resize(2); // we return exactly two curves
265 DCTPVec3dvector Q = control_points; //local array not to destroy da other points
266 DCTPVec3dvector::size_type n = control_points.size() - 1;
267 DCTPVec3dvector cp1(n + 1);
268 DCTPVec3dvector cp2(n + 1);
269 if(n < 1) //too few points, at least 2 needed to split curve
271 return -1;
274 for(DCTPVec3dvector::size_type k = 0; k < n; ++k)
276 cp1[k] = Q [0];
277 cp2[n - k] = Q [n - k];
279 for(DCTPVec3dvector::size_type i = 0; i < n - k; ++i)
281 Q[i] = Q[i] * (1.0 - t) + Q[i + 1] * t;
285 cp1[n] = Q[0];
286 cp2[0] = Q[0];
287 newbeziers[0].setControlPointVector(cp1);
288 newbeziers[1].setControlPointVector(cp2);
289 return 0;
292 //! Subdivide Bezier curve at t into two new curves.
294 * This function subdivides a Bezier curve into two new Bezier curves
295 * of the same degree at the parameter value `t', using de Casteljau's
296 * algorithm.
298 * \param t the parameter at which to subdivide the curve.
299 * \param newbeziers the two new Bezier curves (returned in a vector of size 2)
300 * \return zero on success, and a negative value when some error occured.
304 int BezierCurve2D::subDivision(double t, BezierCurve2D &newcurve)
306 if(t <= 0.0 || t >= 1.0)
308 return -1; // t must be between (0, 1) exclusive
311 // This function is time critical so optimize at the cost of readabiltity...
312 DCTPVec3dvector::size_type n = control_points.size();
314 if(n < 2)
316 return -1; //too few points, at least 2 needed to split curve
319 double t2 = 1.0 - t;
321 DCTPVec3dvector::size_type i, k;
323 DCTPVec3dvector &cp1 = control_points;
324 DCTPVec3dvector &cp2 = newcurve.control_points;
326 cp2.clear(); // very important for performance (no copying around of obsolte stuff!)
327 cp2.resize(n);
329 --n;
331 for(k = 0; k < n; ++k)
333 cp2[n - k] = cp1[n];
335 for(i = n; i > k; --i)
337 cp1[i] *= t;
338 cp1[i] += cp1[i - 1] * t2;
342 cp2[0] = cp1[n];
344 return 0;
347 //! Calculate intersection of the Bezier curve with the polyline (a, b).
349 * This function calculates the number of intersections the curve has
350 * with the polyline (a, b), using Bezier clipping and the minmax algorithm.
352 * \param res the double vector which will contain the results
353 * (in (0, 1) parameter space)
354 * \param a the first point of the polyline
355 * \param b the second point of the polyline
356 * \return zero on success, a negative value if some error occured, and <BR>
357 * 1 if the curve lies entirely on the polyline. <BR>
358 * 2 if the curve lies partly on the polyline. <BR>
361 int BezierCurve2D::intersection(DCTPdvector &res, Vec2d a, Vec2d b)
363 int result;
364 unsigned int i;
366 if(osgAbs(a[0] - b[0]) < DCTP_EPS && osgAbs(a[1] - b[1]) < DCTP_EPS)
367 return -1; // the two points are (almost) the same
369 // DCTPdvector dists( control_points.size() ); // the signed distance of the control points and the polyline
370 Vec2d norm; // norm of ( a - b )
371 //due to the check above, lab must be positive
372 double lab = sqrt( (a[0] - b[0]) * (a[0] - b[0]) + (a[1] - b[1]) * (a[1] - b[1]) );
373 norm[0] = -(b[1] - a[1]) / lab; // This is a normal -> rotated 90 degrees
374 norm[1] = (b[0] - a[0]) / lab;
377 DCTPVec3dvector newcp(control_points.size() ); // the control points of the explicit Bezier curve
378 int flag = 1;
379 unsigned int cpsize = UInt32(control_points.size()) - 1;
381 for(i = 0; i <= cpsize; i++)
383 // std::cerr.precision( DCTP_PRECISION );
384 // std::cerr << "cp[i].x: " << control_points[ i ][0] << " cp[i].y: " << control_points[ i ][1] << std::endl;
385 newcp[i][0] = (i / cpsize) * control_points[i][2];
386 newcp[i][1] = pointLineDistancewNormal(control_points[i], a, norm);
387 newcp[i][2] = control_points[i][2];
388 //std::cerr << " dists[i]: " << newcp[ i ][1] << std::endl;
389 if(newcp[i][1] < -DCTP_EPS || newcp[i][1] > DCTP_EPS)
390 flag = 0;
393 if(flag)
395 res.resize(0); // zero result vector because
396 // check start and endpoint of curve, is it really on the polyline, or before/after ?
397 double ta, tb;
398 Vec2d first, last;
399 // we assume that the first and last control points can't have zero weights !!!
400 // (if they were zero, the curve goes through infinity...
401 first[0] = control_points[0][0] / control_points[0][2];
402 first[1] = control_points[0][1] / control_points[0][2];
403 last[0] = control_points[cpsize][0] / control_points[cpsize][2];
404 last[1] = control_points[cpsize][1] / control_points[cpsize][2];
406 if(osgAbs(first[0] - last[0]) > DCTP_EPS)
408 ta = (a[0] - first[0]) / (last[0] - first[0]);
409 tb = (b[0] - first[0]) / (last[0] - first[0]);
411 else
413 ta = (a[1] - first[1]) / (last[1] - first[1]);
414 tb = (b[1] - first[1]) / (last[1] - first[1]);
417 if(tb < ta)
419 double tmp = ta;
420 ta = tb;
421 tb = tmp;
423 if(ta <= 0.0)
424 ta = 0.0;
425 if(tb <= 0.0)
426 tb = 0.0;
427 if(ta >= 1.0)
428 ta = 1.0;
429 if(tb >= 1.0)
430 tb = 1.0;
432 if(ta == tb)
433 return 0; // fully before or after
434 if(ta == 0.0 && tb == 1.0)
435 return 1; // fully on the polyline
437 res.resize(2); // the curve lies partially on the polyline
438 // std::cerr << " ta: " << ta << " tb: " << tb << std::endl;
439 res[0] = ta;
440 res[1] = tb;
441 return 2; //the curve partially lies on the polyline
444 BezierCurve2D bstart;
445 result = bstart.setControlPointVector(newcp);
446 if(result)
447 return result; // some error happened
448 result = bstart.minMaxIntersection(res, 0.0, 1.0);
449 bool zeroroot = (osgAbs(newcp[0][1]) < DCTP_EPS);
450 bool oneroot = (osgAbs(newcp[cpsize][1]) < DCTP_EPS);
452 // special care taken for start/end points
453 // FIXME: hack #1 :-|
454 if(res.size() )
456 if(res[res.size() - 1] >= 1.0 - DCTP_EPS)
457 res[res.size() - 1] = 1.0;
458 if(res[0] <= DCTP_EPS)
459 res[0] = 0.0;
461 if(zeroroot)
463 // we have some solutions, but the first solution is not 0.0, we
464 // have to insert 0.0 as first solution
465 if(res.size() && res[0] >= DCTP_EPS)
466 res.insert(res.begin(), 0.0);
467 // we don't have any solutions yet, but this is a solution, so we have to
468 // insert this
469 else if(!res.size() )
470 res.push_back(0.0);
472 if(oneroot)
474 // if we have oneroot, and the last item is not 1.0, we have to insert it
475 // as last result, regardless of what is actually in the vector (it can even be empty)
476 // check for the last item ( & its existence )
477 if(res.size() && res[res.size() - 1] < 1.0 - DCTP_EPS)
478 res.push_back(1.0);
479 // insert it if the resultvector is empty
480 else if(!res.size() )
481 res.push_back(1.0);
485 // std::cerr << "still here. solutions: " << res.size() << std::endl;
486 for(i = 0; i < res.size(); i++)
488 Vec2d p;
489 int er;
490 double t;
491 // std::cerr << " i: " << i << " solution[i]: " << res[ i ];
492 p = computewdeCasteljau(res[i], er);
493 // std::cerr << " value: " << p[0] << " " << p[1] << std::endl;
494 if(osgAbs(b[0] - a[0]) > DCTP_EPS)
495 t = (p[0] - a[0]) / (b[0] - a[0]);
496 else
497 t = (p[1] - a[1]) / (b[1] - a[1]);
498 // std::cerr << " lineparam: " << t << std::endl;
499 if(DCTPVecIsNotEqual(p, a) && DCTPVecIsNotEqual(p, b) )
500 if(t < -DCTP_EPS || t > (1 + DCTP_EPS) )
502 res.erase(res.begin() + i);
503 i--;
507 // std::cerr << "still here. solutions after: " << res.size() << std::endl;
508 // if ( res.size() ) std::cerr << res[ 0 ] << std::endl;
510 #if 0
511 // we have to make this check _after_ the results have been filtered
512 if(res.size() > control_points.size() )
515 * We have more results than possible, the curve partly lies on the polyline
516 * we only return the first and last results, and hope for the best.
517 * note this is not a 100% general solution, but in the vast majority
518 * of cases it works.
519 * FIXME: a 100% general solution may be desirable some day...
521 double tt = res[res.size() - 1];
522 res.resize(2);
523 res[1] = tt;
524 return -2; // to indicate some problem happened
526 #endif
527 return result;
531 // calculate intersection of curve with line (a)
532 int BezierCurve2D::intersection(DCTPdvector &res, double a, bool horiz)
534 DCTPVec3dvector newcp(control_points.size() ); // the control points of the explicit Bezier curve
535 BezierCurve2D tempcurve;
536 const unsigned int cpsize = UInt32(control_points.size()) - 1;
538 for(unsigned int i = 0; i < newcp.size(); ++i)
540 if(horiz)
542 newcp[i] = control_points[i];
544 else
546 newcp[i][0] = control_points[i][1];
547 newcp[i][1] = control_points[i][0];
548 newcp[i][2] = control_points[i][2];
550 newcp[i][1] -= a * newcp[i][2];
553 int result = tempcurve.setControlPointVector(newcp);
554 if(result)
555 return result; // some error happened
556 result = tempcurve.minMaxIntersection(res, 0.0, 1.0);
557 bool zeroroot = (osgAbs(newcp[0][1]) < DCTP_EPS);
558 bool oneroot = (osgAbs(newcp[cpsize][1]) < DCTP_EPS);
559 // special care taken for start/end points
560 // FIXME: hack #1 :-|
561 if(res.size() )
563 if(res[res.size() - 1] >= 1.0 - DCTP_EPS)
564 res[res.size() - 1] = 1.0;
565 if(res[0] <= DCTP_EPS)
566 res[0] = 0.0;
568 if(zeroroot)
570 // we have some solutions, but the first solution is not 0.0, we
571 // have to insert 0.0 as first solution
572 if(res.size() && res[0] >= DCTP_EPS)
573 res.insert(res.begin(), 0.0);
574 // we don't have any solutions yet, but this is a solution, so we have to
575 // insert this
576 else if(!res.size() )
577 res.push_back(0.0);
579 if(oneroot)
581 // if we have oneroot, and the last item is not 1.0, we have to insert it
582 // as last result, regardless of what is actually in the vector (it can even be empty)
583 // check for the last item ( & its existence )
584 if(res.size() && res[res.size() - 1] < 1.0 - DCTP_EPS)
585 res.push_back(1.0);
586 // insert it if the resultvector is empty
587 else if(!res.size() )
588 res.push_back(1.0);
590 return result;
594 // calculate intersection of x axis and Bezier curve, calls itself recursively
595 int BezierCurve2D::minMaxIntersection(DCTPdvector &res, double s, double e)
597 double miny = control_points[0][1];
598 double maxy = control_points[0][1];
599 int result;
600 Vec2d r;
601 double mid = 0.0;
603 // std::cerr.precision( DCTP_PRECISION );
604 // std::cerr << "minmax for: " << s << " " << e << std::endl;
605 // find the minmax box of the control polygon - note we only need the y values
606 // meanwhile also check that we do not lie on the line :)
607 DCTPVec3dvector::size_type cpsize = control_points.size();
608 DCTPVec3dvector::size_type i;
610 for(i = 1; i < cpsize; i++)
612 if(control_points[i][1] > maxy)
613 maxy = control_points[i][1];
614 else if(control_points[i][1] < miny)
615 miny = control_points[i][1];
618 // std::cerr << " miny: " << miny << " maxy: " << maxy << std::endl;
620 #if 0
621 if(miny > -DCTP_EPS && miny < DCTP_EPS && maxy > -DCTP_EPS && maxy < DCTP_EPS)
623 std::cerr << " found interval: [ " << control_points[0][0] << " - " << control_points[cpsize - 1][0] << " ]" << std::endl;
624 return 0;
626 if(osgAbs(control_points[0][1]) < DCTP_EPS)
628 /// original code
629 // if ( res.size() && res[ res.size() - 1 ] == s ) return 0;
630 if(!res.size() || res[res.size() - 1] != s)
632 std::cerr << " special recording: " << s << std::endl;
633 res.push_back(s);
634 // we have to check for the last point too, for really degenerate cases
635 // if ( !( osgAbs( control_points[ cpsize - 1 ][1] ) < DCTP_EPS ) || control_points[ 0 ] == control_points[ cpsize - 1 ] )
636 // return 0;
639 std::cerr << "still here 1 " << std::endl;
640 if(osgAbs(control_points[cpsize - 1][1]) < DCTP_EPS)
642 /// original code
643 // if ( res.size() && res[ res.size() - 1 ] == e ) return 0;
644 if(!res.size() || res[res.size() - 1] != e)
646 std::cerr << " special recording #2: " << e << std::endl;
647 res.push_back(e);
648 // return 0;
651 std::cerr << "still here 2 " << std::endl;
652 #endif /* 0 */
654 if( (miny > 0 && maxy > 0) || (miny < 0 && maxy < 0) )
655 return 0;
658 if ( ( miny <= 0.0 && maxy <= 0.0 ) ||
659 ( miny > 0.0 && maxy > 0.0 ) ) return 0;
661 // if ( ! ( (miny < 0.0 && maxy > 0.0) ||
662 // (miny > 0.0 && maxy < 0.0) ) ) return 0;
663 // std::cerr <<"still here 3 " << std::endl;
664 if(maxy - miny < DCTP_EPS)
666 if(e - s > DCTP_EPS)
668 // completely on the line, so return start and end...
669 if(res.size() == 0)
671 res.push_back(s);
673 res.push_back(e);
675 else
677 res.push_back( (s + e) / 2.0); // we have a new (unique) solution, record it
679 return 0;
681 /* if( maxy - miny < DCTP_EPS ) // this should be sufficient...
682 // if( control_points[ 0 ] == control_points[ cpsize - 1 ] &&
683 // (e - s ) < DCTP_EPS )
685 if ( res.size() > 0 ) {
686 if ( osgAbs( res[ res.size() - 1 ] - (s + e) / 2.0 ) > DCTP_EPS )
687 // osgAbs( res[ res.size() - 1 ][0] - e ) > DCTP_MINMAX_DIFFTOL) {
688 // std::cerr << " recording : " << s << std::endl;
689 // std::cerr << " res.size(): " << res.size() << " res[res.size()-1]: " << res[res.size()-1] << std::endl;
690 res.push_back( (s + e) / 2.0 ); // we have a new (unique) solution, record it
691 // }
692 return 0;
694 else {
695 // std::cerr << " recording first: " << s << std::endl;
696 res.push_back( (s + e) / 2.0 ); // this is the first solution, record it anyway
697 return 0;
700 // we have a solution in our minmax box, subdivide and continue recursively
701 BezierCurve2D newbez;
703 // find first intersection of contol polygon with axis
704 for(i = 1; i < cpsize; ++i)
706 const double &p1 = control_points[i - 1][1];
707 const double &p2 = control_points[i][1];
709 if(p1 < 0.0)
711 if(p2 >= 0.0)
713 if( (p2 == 0.0) && (i == cpsize - 1) )
715 res.push_back(e);
716 return 0;
718 else
720 mid = (i - p2 / (p2 - p1) ) / cpsize;
721 break;
725 else if(p1 > 0.0)
727 if(p2 <= 0.0)
729 if( (p2 == 0.0) && (i == cpsize - 1) )
731 res.push_back(e);
732 return 0;
734 else
736 mid = (i + p2 / (p1 - p2) ) / cpsize;
737 break;
741 else if(i == 1)
743 if(res.size() != 0)
745 if(osgAbs(res[res.size() - 1] - s) > DCTP_EPS)
747 res.push_back(s); // we have a new (unique) solution, record it
750 else
752 res.push_back(s); // this is the first solution, record it anyway
757 if(i == cpsize)
759 return 0;
761 // for( i = 0; i < cpsize; ++i )
762 // {
763 // std::cerr << control_points[ i ][1] << " ";
764 // }
765 // std::cerr << std::endl;
767 mid = osgMin(0.999, osgMax(0.001, mid) );
768 // std::cerr << mid << std::endl;
769 result = subDivision(mid, newbez);
770 // result = midPointSubDivision( newbez );
771 if(result)
772 return result; // some error happened
774 result = minMaxIntersection(res, s, s + (e - s) * mid);
775 // result = minMaxIntersection( res, s, ( (s + e) / 2 ) );
776 if(result)
777 return result; // some error happened
779 result = newbez.minMaxIntersection(res, s + (e - s) * mid, e);
780 // result = newbez.minMaxIntersection( res, ( (s + e) / 2 ), e );
781 return result;
785 // calculate the signed distance between a homogenious point and a line (given with a point and a normalvector)
786 // returns the signed distance
787 double BezierCurve2D::pointLineDistancewNormal(Vec3d p, Vec2d a, Vec2d n)
789 Vec2d t, l;
790 l[0] = p[0];
791 l[1] = p[1];
792 t = l - a;
793 // t[0] = p[0] - a[0];
794 // t[1] = p[1] - a[1];
795 // std::cerr << " a.x: " << a[0] << " a.y: " << a[1] << " p.x: " << p[0] << " p.y: " << p[1] << std::endl;
796 return t[0] * n[0] + t[1] * n[1];
799 //! Approximate curve linearly with given maximum tolerance.
801 * This function approximates the Bezier curve with a polyline. The maximum
802 * error of the approximation will not be larger than the given tolerance.
805 * \param vertices the vertices of the approximating polyline.
806 * \param delta maximum error.
807 * \return zero on success, and a negative value when some error occured.
809 int BezierCurve2D::approximate(DCTPVec2dvector &vertices, double delta)
811 vertices.resize(0);
813 // check for first degree Bezier.
814 if(control_points.size() == 2)
816 Vec2d tmp;
817 tmp[0] = control_points[0][0] / control_points[0][2];
818 tmp[1] = control_points[0][1] / control_points[0][2];
819 vertices.push_back(tmp);
820 tmp[0] = control_points[1][0] / control_points[1][2];
821 tmp[1] = control_points[1][1] / control_points[1][2];
822 vertices.push_back(tmp);
823 return 0;
826 // call recursive subdividing function
827 return approximate_sub(vertices, delta);
830 #if 0
831 int BezierCurve2D::approximateLength(DCTPVec2dvector &vertices, double delta)
833 vertices.resize(0);
835 // check for first degree Bezier.
836 std::cerr << control_points.size() << std::endl;
837 if(control_points.size() == 2)
839 double d_dist = sqrt( (control_points[1] - control_points[0]).squareLength() );
840 int i_steps = ( int ) ceil(d_dist / (1.5 * delta) );
841 int i_step;
842 double d_param;
844 std::cerr << d_dist << " - " << delta << " -> " << i_steps << " " << d_dist / (3.0 * delta) << std::endl;
846 vertices.push_back(control_points[0]);
848 for(i_step = 1; i_step < i_steps; ++i_step)
850 d_param = ( double ) i_step / ( double ) i_steps;
851 vertices.push_back(control_points[0] + (control_points[1] - control_points[0]) * d_param);
854 vertices.push_back(control_points[1]);
855 return 0;
858 // call recursive subdividing function
859 // std::cerr << "approx..." << std::endl;
860 return approximateLength_sub(vertices, delta);
863 #endif /* 0 */
865 int BezierCurve2D::approximate_sub(DCTPVec2dvector &vertices, double delta)
867 double max_error = 0;
868 Vec2d ae;
869 double aenorm;
870 double t1, t2;
871 int i;
872 int n = UInt32(control_points.size()) - 1;
873 std::vector<double> t;
874 Vec2d e0, en, ei;
876 for(i = 0; i <= n; i++)
878 t.push_back((double( n - i ) ) / n);
881 // first, make a copy of the cp vector, and do one
882 // or more de Casteljau steps to get rid of 0 weights
883 DCTPVec3dvector mycps;
884 mycps = control_points;
886 for(i = 0; i <= n; ++i)
888 unsigned int s = UInt32(mycps.size());
889 bool ok = true;
891 mycps.push_back(mycps[s - 1]);
892 t.push_back(t[s - 1]);
894 for(int j = s; j > i; --j)
896 mycps[j] = (mycps[j] + mycps[j - 1]) * 0.5f;
897 t[j] = (t[j] + t[j - 1]) * 0.5f;
898 if(mycps[j][2] < DCTP_EPS)
899 ok = false;
902 if(ok)
903 break;
906 n = UInt32(mycps.size()) - 1;
907 e0[0] = mycps[0][0] / mycps[0][2];
908 e0[1] = mycps[0][1] / mycps[0][2];
909 en[0] = mycps[n][0] / mycps[n][2];
910 en[1] = mycps[n][1] / mycps[n][2];
912 for(i = 0; i <= n; i++)
914 t1 = t[i];
915 t2 = 1.0 - t[i];
916 ei[0] = mycps[i][0] / mycps[i][2];
917 ei[1] = mycps[i][1] / mycps[i][2];
918 ae = ei - e0 * t1 - en * t2;
919 // ae[0] = control_points[ i ][0] - t1 * control_points[ 0 ][0] - t2 * control_points[ n ][0];
920 // ae[1] = control_points[ i ][1] - t1 * control_points[ 0 ][1] - t2 * control_points[ n ][1];
922 // std::cerr << "i: " << i << " ae.x: " << ae[0] << " ae.y: " << ae[1] << std::endl;
924 aenorm = sqrt(ae[0] * ae[0] + ae[1] * ae[1]);
925 if(aenorm > max_error)
926 max_error = aenorm;
929 // std::cerr.precision( DCTP_PRECISION );
930 // std::cerr << " twopower: " << twopower << std::endl;
931 // std::cerr << " act_error: " << act_error << " max_error: " << max_error << std::endl;
932 // std::cerr << control_points[ 0 ][0] << " " << control_points[ 0 ][1] << std::endl;
933 // std::cerr << control_points[ control_points.size() - 1 ][0] << " " << control_points[ control_points.size() - 1 ][1] << std::endl;
934 if(max_error > delta)
936 // we have to subdivide further
937 BezierCurve2D newbez;
938 int error;
939 error = midPointSubDivision(newbez);
940 if(error)
941 return error;
942 approximate_sub(vertices, delta);
943 newbez.approximate_sub(vertices, delta);
945 else
947 // this is a good enough approximation
948 Vec2d tmp;
949 if(!vertices.size() )
951 // this is the first approximation, we have to record both the
952 // startpoint and the endpoint
953 tmp[0] = control_points[0][0] / control_points[0][2];
954 tmp[1] = control_points[0][1] / control_points[0][2];
955 vertices.push_back(tmp);
956 tmp[0] = control_points[control_points.size() - 1][0] / control_points[control_points.size() - 1][2];
957 tmp[1] = control_points[control_points.size() - 1][1] / control_points[control_points.size() - 1][2];
958 vertices.push_back(tmp);
960 else
962 // we had some subdivisions before, we only need to record the endpoint
963 tmp[0] = control_points[control_points.size() - 1][0] / control_points[control_points.size() - 1][2];
964 tmp[1] = control_points[control_points.size() - 1][1] / control_points[control_points.size() - 1][2];
965 vertices.push_back(tmp);
968 return 0;
971 #if 0
972 int BezierCurve2D::approximateLength_sub(DCTPVec2dvector &vertices, double delta)
974 double act_error;
975 double max_error = 0;
976 Vec2d ae;
977 double twopower = 1;
978 double aenorm;
979 double t1, t2;
981 int n = control_points.size() - 1;
982 double d_dist = sqrt( (control_points[n] - control_points[0]).squareLength() );
983 // std::cerr << d_dist << " - " << delta << std::endl;
984 if(d_dist > delta * 1.5)
986 // we have to subdivide further
987 bezier2dvector newbez;
988 int error;
989 error = midPointSubDivision(newbez);
990 if(error)
991 return error;
992 newbez[0].approximateLength_sub(vertices, delta);
993 newbez[1].approximateLength_sub(vertices, delta);
995 else
997 for(int i = 0; i <= n; i++)
999 t1 = ( (double) (n - i) ) / n;
1000 t2 = ( (double) i) / n;
1001 ae = control_points[i] - control_points[0] * t1 - control_points[n] * t2;
1002 // ae[0] = control_points[ i ][0] - t1 * control_points[ 0 ][0] - t2 * control_points[ n ][0];
1003 // ae[1] = control_points[ i ][1] - t1 * control_points[ 0 ][1] - t2 * control_points[ n ][1];
1005 // std::cerr << "i: " << i << " ae.x: " << ae[0] << " ae.y: " << ae[1] << std::endl;
1007 aenorm = sqrt(ae[0] * ae[0] + ae[1] * ae[1]);
1008 if(aenorm > max_error)
1009 max_error = aenorm;
1010 if(i)
1011 twopower *= 2; // this is a double so it can be arbitrarily high, an int wouldn't suffice
1014 act_error = ( (twopower - 1) / twopower) * max_error;
1015 // std::cerr.precision( DCTP_PRECISION );
1016 // std::cerr << " twopower: " << twopower << std::endl;
1017 // std::cerr << " act_error: " << act_error << " max_error: " << max_error << std::endl;
1018 // std::cerr << control_points[ 0 ][0] << " " << control_points[ 0 ][1] << std::endl;
1019 // std::cerr << control_points[ control_points.size() - 1 ][0] << " " << control_points[ control_points.size() - 1 ][1] << std::endl;
1020 if(act_error > delta)
1022 // we have to subdivide further
1023 bezier2dvector newbez;
1024 int error;
1025 error = midPointSubDivision(newbez);
1026 if(error)
1027 return error;
1028 newbez[0].approximateLength_sub(vertices, delta);
1029 newbez[1].approximateLength_sub(vertices, delta);
1031 else
1033 // this is a good enough approximation
1034 if(!vertices.size() )
1036 // this is the first approximation, we have to record both the
1037 // startpoint and the endpoint
1038 vertices.push_back(control_points[0]);
1039 vertices.push_back(control_points[control_points.size() - 1]);
1041 else
1043 // we had some subdivisions before, we only need to record the endpoint
1044 vertices.push_back(control_points[control_points.size() - 1]);
1048 return 0;
1050 #endif /* 0 */
1052 //! Return distance between two homogenious control points
1054 * This functions returns the norm of the difference of the two control points
1055 * which serves as the distance betwen the two homogenious control points.
1057 double BezierCurve2D::homogeniousDistanceSquared(Vec3d v1, Vec3d v2)
1060 return v1.dist2(v2);
1063 //! Degree reduce the Bezier curve with t tolerance if possible.
1065 * This function tries to degree reduce the Bezier curve ensuring
1066 * that the new curve does not deviate more from the original curve
1067 * than a specified error tolerance.
1069 * \param t error tolerance which is still accepted for the new
1070 * (lower degree) curve.
1071 * \return true on success, false if degree reduction is not possible
1072 * within the given tolerance.
1074 bool BezierCurve2D::reduceDegree(double tol)
1076 unsigned int n = UInt32(control_points.size()) - 1; // orig cps: 0, ..., n
1077 if(n < 2)
1079 // cannot degree reduce a first degree curve
1080 return false;
1082 DCTPVec3dvector b_left(n);
1083 DCTPVec3dvector b_right(n);
1084 unsigned int i;
1086 // calculate b_right:
1087 b_right[0] = control_points[0];
1089 for(i = 1; i < n; ++i)
1091 b_right[i] = (control_points[i] * n - b_right[i - 1] * i) *
1092 (1.0 / double(n - i));
1095 // calculate b_left:
1096 b_left[n - 1] = control_points[n];
1098 for(i = n - 1; i > 0; --i)
1100 b_left[i - 1] = (control_points[i] * n - b_left[i] * (n - i)) *
1101 (1.0 / double(i));
1104 // check for introduced error:
1105 double quad_error = tol * tol;
1106 double dist4d;
1108 unsigned int n_half = n >> 1;
1109 unsigned int n_half1 = (n + 1) >> 1;
1111 // for (i = 0; i < n_half; ++i)
1112 // {
1113 // control_points[ i ] = b_right[ i ];
1114 // }
1115 for(i = n_half1; i < n; ++i)
1117 b_right[i] = b_left[i];
1120 if(n_half != n_half1)
1122 dist4d = homogeniousDistanceSquared(b_right[n_half], b_left[n_half]);
1123 b_right[n_half] = b_left[n_half] * 0.5 + b_right[n_half] * 0.5;
1125 else
1127 dist4d = homogeniousDistanceSquared(control_points[n_half],
1128 0.5 * (b_right[n_half - 1] + b_left[n_half]));
1133 //Vec3d dist;
1134 double minweight = b_right[0][2];
1136 for(i = 1; i < n; ++i)
1138 if(minweight > b_right[i][2])
1139 minweight = b_right[i][2];
1142 if(minweight < DCTP_EPS)
1144 // can't degree reduce a curve with zero weight(s)...
1145 return false;
1148 if(dist4d / (minweight * minweight) > quad_error)
1150 return false;
1153 control_points = b_right;
1154 // setControlPointVector( b_new );
1156 return true;
1160 unsigned int BezierCurve2D::computeNonratApproximationDegree(double eps) const
1162 BezierCurve2D nonrat_curve;
1163 bool rational = false;
1164 unsigned int n = UInt32(control_points.size());
1165 unsigned int i, k;
1166 Vec3d nonrat_cp;
1167 Vec3d d0, d1;
1168 BezierCurve2D deriv_curve;
1169 BezierCurve2D diff_curve;
1171 nonrat_cp[2] = 1.0;
1172 d0[2] = d1[2] = 0.0;
1174 for(i = 0; i < n; ++i)
1176 if(osgAbs(control_points[i][2] - 1.0) > DCTP_EPS)
1178 rational = true;
1179 break;
1183 if(!rational)
1185 return n - 1;
1188 // end control points
1189 nonrat_cp[0] = control_points[0][0] / control_points[0][2];
1190 nonrat_cp[1] = control_points[0][1] / control_points[0][2];
1191 nonrat_curve.control_points.push_back(nonrat_cp);
1192 nonrat_cp[0] = control_points[n - 1][0] / control_points[n - 1][2];
1193 nonrat_cp[1] = control_points[n - 1][1] / control_points[n - 1][2];
1194 nonrat_curve.control_points.push_back(nonrat_cp);
1196 n = 1;
1197 deriv_curve.control_points = control_points;
1198 while(n < 15)
1200 deriv_curve.CalculateDerivativeCurve();
1201 k = UInt32(deriv_curve.control_points.size()) - 1;
1202 d0[0] = deriv_curve.control_points[0][0] / deriv_curve.control_points[0][2];
1203 d0[1] = deriv_curve.control_points[0][1] / deriv_curve.control_points[0][2];
1204 d1[0] = deriv_curve.control_points[k][0] / deriv_curve.control_points[k][2];
1205 d1[1] = deriv_curve.control_points[k][1] / deriv_curve.control_points[k][2];
1206 ++n;
1208 // add points to hermite curve
1209 nonrat_curve.AddNthHermitePoints(d0, d1);
1211 // check difference
1212 CalculateDifferenceCurve(nonrat_curve, diff_curve);
1213 if(diff_curve.CalculateSupinumSquared() < eps * eps)
1215 break;
1219 // degree might be too high by one
1220 nonrat_curve.reduceDegree(eps);
1222 return UInt32(nonrat_curve.control_points.size()) - 1;
1226 void BezierCurve2D::CalculateDerivativeCurve()
1228 unsigned int n;
1229 unsigned int i;
1230 BezierCurve2D deriv_curve;
1231 BezierCurve2D temp_curve;
1232 std::vector<double> squared_weight;
1233 bool rational = false;
1235 // check for single point curves
1236 n = UInt32(control_points.size());
1237 if(n == 1)
1239 control_points[0] = Vec3d(0.0, 0.0, 1.0);
1242 // deriv: P'(t)/w'(t)
1243 CalculatePolyDerivCurve(deriv_curve);
1245 // check for non-rational curves
1246 for(i = 0; i < n; ++i)
1248 if(osgAbs(control_points[i][2] - 1.0) > DCTP_EPS)
1250 rational = true;
1251 break;
1255 if(!rational)
1257 // deriv: P'(t)/1
1258 control_points = deriv_curve.control_points;
1260 for(i = 0; i < n - 1; ++i)
1262 control_points[i][2] = 1.0;
1265 return;
1268 // deriv: P'(t)w(t) / w(t)w'(t), temp: P(t)w'(t) / w(t)w'(t)
1269 temp_curve.control_points = control_points;
1270 temp_curve.CrossMultiply(deriv_curve);
1272 // deriv: ( P'(t)w(t) - P(t)w'(t) ) / 1
1273 for(i = 0; i < deriv_curve.control_points.size(); ++i)
1275 deriv_curve.control_points[i] -= temp_curve.control_points[i];
1276 deriv_curve.control_points[i][2] = 1.0;
1279 // elevate degree from 2n-1 to 2n
1280 deriv_curve.DegreeElevate();
1282 // deriv: ( P'(t)w(t) - P(t)w'(t) )~ / w(t)^2
1283 SquareWeight(squared_weight);
1285 for(i = 0; i < deriv_curve.control_points.size(); ++i)
1287 deriv_curve.control_points[i][2] = squared_weight[i];
1290 control_points = deriv_curve.control_points;
1294 void BezierCurve2D::CalculateNOverIVector(std::vector<double> &NOverI, const unsigned int n) const
1296 unsigned int i;
1298 NOverI.resize(n + 1);
1299 NOverI[0] = NOverI[n] = 1.0;
1301 for(i = 1; i <= n / 2; ++i)
1303 NOverI[i] = NOverI[i - 1] * (n + 1 - i) / i;
1304 NOverI[n - i] = NOverI[i];
1309 void BezierCurve2D::CalculatePolyDerivCurve(BezierCurve2D &DerivativeCurve) const
1311 const unsigned int n = UInt32(control_points.size()) - 1;
1312 unsigned int i;
1314 DerivativeCurve.control_points.resize(n);
1316 for(i = 0; i < n; ++i)
1318 DerivativeCurve.control_points[i] = (control_points[i + 1] - control_points[i]) * n;
1323 void BezierCurve2D::CrossMultiply(BezierCurve2D &OtherCurve)
1325 std::vector<Vec3d> p_wo;
1326 std::vector<Vec3d> po_w;
1327 const unsigned int n = UInt32(control_points.size()) - 1;
1328 const unsigned int m = UInt32(OtherCurve.control_points.size()) - 1;
1329 const unsigned int nm = n + m;
1330 unsigned int i;
1331 unsigned int j;
1332 unsigned int k;
1333 std::vector<double> i_over_n;
1334 std::vector<double> j_over_m;
1335 std::vector<double> k_over_nm;
1337 // calculate a over b arrays
1338 CalculateNOverIVector(i_over_n, n);
1339 CalculateNOverIVector(j_over_m, m);
1340 CalculateNOverIVector(k_over_nm, nm);
1342 // init
1343 p_wo.resize(nm + 1);
1344 po_w.resize(nm + 1);
1346 for(k = 0; k <= nm; ++k)
1348 p_wo[k] = po_w[k] = Vec3d(0.0, 0.0, 0.0);
1351 // cross multiply (leave out Bernstein factor)
1352 for(i = 0; i <= n; ++i)
1354 k = i;
1356 for(j = 0; j <= m; ++j)
1358 p_wo[k] += control_points[i] * OtherCurve.control_points[j][2] * i_over_n[i] * j_over_m[j];
1359 po_w[k] += OtherCurve.control_points[j] * control_points[i][2] * i_over_n[i] * j_over_m[j];
1360 ++k;
1364 // divide by new Bernstein factor
1365 for(k = 0; k <= nm; ++k)
1367 p_wo[k] /= k_over_nm[k];
1368 po_w[k] /= k_over_nm[k];
1371 control_points = p_wo;
1372 OtherCurve.control_points = po_w;
1376 void BezierCurve2D::SquareWeight(std::vector<double> &Squared) const
1378 const unsigned int n = UInt32(control_points.size()) - 1;
1379 const unsigned int nn = n * 2;
1380 unsigned int i;
1381 unsigned int j;
1382 unsigned int k;
1383 std::vector<double> i_over_n;
1384 std::vector<double> k_over_nn;
1386 // calculate a over b arrays
1387 CalculateNOverIVector(i_over_n, n);
1388 CalculateNOverIVector(k_over_nn, nn);
1390 // init
1391 Squared.resize(nn + 1);
1393 for(k = 0; k <= nn; ++k)
1395 Squared[k] = 0.0;
1398 // cross multiply (leave out Bernstein factor)
1399 for(i = 0; i <= n; ++i)
1401 for(j = 0; j <= n; ++j)
1403 k = i + j;
1404 Squared[k] += control_points[i][2] * control_points[j][2] * i_over_n[i] * i_over_n[j];
1408 // divide by new Bernstein factor
1409 for(k = 0; k <= nn; ++k)
1411 Squared[k] /= k_over_nn[k];
1416 double BezierCurve2D::CalculateSupinumSquared() const
1418 const unsigned int n = UInt32(control_points.size());
1419 unsigned int i;
1420 Vec3d curr;
1421 double sup;
1422 double diff;
1424 // generalized convex hull property
1425 sup = (control_points[0][0] * control_points[0][0] + control_points[0][1] * control_points[0][1])
1426 / (control_points[0][2] * control_points[0][2]);
1428 for(i = 1; i < n; ++i)
1430 curr = (control_points[i] + control_points[i - 1]) * 0.5;
1431 diff = (curr[0] * curr[0] + curr[1] * curr[1]) / (curr[2] * curr[2]);
1432 if(diff > sup)
1434 sup = diff;
1438 diff = (control_points[n - 1][0] * control_points[n - 1][0] + control_points[n - 1][1] * control_points[n - 1][1])
1439 / (control_points[n - 1][2] * control_points[n - 1][2]);
1440 if(diff > sup)
1442 sup = diff;
1445 // std::cerr << " CalculateSupinumSquared::sup: " << sup << std::endl;
1446 return sup;
1450 void BezierCurve2D::CalculateDifferenceCurve(const BezierCurve2D &Other, BezierCurve2D &Diff) const
1452 BezierCurve2D temp_curve;
1453 unsigned int i;
1454 bool rational = false;
1456 Diff.control_points = control_points;
1457 temp_curve.control_points = Other.control_points;
1459 // check for non-rational curves
1460 for(i = 0; i < control_points.size(); ++i)
1462 if(osgAbs(control_points[i][2] - 1.0) > DCTP_EPS)
1464 rational = true;
1465 break;
1469 if(!rational)
1471 for(i = 0; i < temp_curve.control_points.size(); ++i)
1473 if(osgAbs(temp_curve.control_points[i][2] - 1.0) > DCTP_EPS)
1475 rational = true;
1476 break;
1481 if(rational)
1483 // rational curvel -> cross multiply with denominator
1484 Diff.CrossMultiply(temp_curve);
1486 else
1488 // polynomial curves -> elevate to same degree
1489 while(Diff.control_points.size() < temp_curve.control_points.size() )
1491 Diff.DegreeElevate();
1493 while(temp_curve.control_points.size() < control_points.size() )
1495 temp_curve.DegreeElevate();
1499 for(i = 0; i < Diff.control_points.size(); ++i)
1501 Diff.control_points[i][0] -= temp_curve.control_points[i][0];
1502 Diff.control_points[i][1] -= temp_curve.control_points[i][1];
1507 void BezierCurve2D::DegreeElevate()
1509 const unsigned int n = UInt32(control_points.size());
1510 unsigned int i;
1512 control_points.push_back(control_points[n - 1]);
1514 for(i = n - 1; i != 0; --i)
1516 double alpha = i / double(n);
1517 double malpha = 1.0 - alpha;
1519 control_points[i] = control_points[i - 1] * alpha + control_points[i] * malpha;
1524 void BezierCurve2D::AddNthHermitePoints(Vec3d d0, Vec3d d1)
1526 const unsigned int n = UInt32(control_points.size()) / 2;
1527 unsigned int i;
1528 std::vector<double> n_over_i;
1529 int sign = 1;
1530 double fact;
1532 DegreeElevate();
1533 DegreeElevate();
1535 fact = 1.0;
1537 for(i = UInt32(control_points.size()) - 1; i >= UInt32(control_points.size()) - n; --i)
1539 fact *= i;
1542 d1 /= fact;
1543 d0 /= fact;
1545 // TODO: CHECK!!!
1546 CalculateNOverIVector(n_over_i, n);
1548 for(i = 0; i <= n; ++i)
1550 if(i > 0)
1551 d0 -= control_points[n - i] * (n_over_i[i] * sign);
1552 if(i < n)
1553 d1 -= control_points[2 * n + 1 - i] * (n_over_i[i] * sign);
1554 sign = -sign;
1555 // std::cerr<<"i: " << i << " d1: " << d1 << std::endl;
1558 d1 *= -sign;
1560 // insert
1561 // std::cerr<<"bah0: "<< d0 << std::endl;
1562 control_points[n] = d0;
1563 // std::cerr<<"bah1: "<< d1 << std::endl;
1564 control_points[n + 1] = d1;
1565 // std::cerr<<"bah3"<<std::endl;
1566 // for ( i = 0; i < control_points.size(); ++i )
1567 // {
1568 // std::cerr<<"AddNthHermitePoints:: cps[i]: " << control_points[i] << std::endl;
1569 // }