/* * FitCurve : * Fit a Bezier curve to a set of digitized points */ void FitCurve(Point2 *d, int nPts, double error) /* Array of digitized points */ /* Number of digitized points */ /* User-defined error squared */ { Vector2 tHat1, tHat2; /* Unit tangent vectors at endpoints */ tHat1 = ComputeLeftTangent(d, 0); tHat2 = ComputeRightTangent(d, nPts - 1); FitCubic(d, 0, nPts - 1, tHat1, tHat2, error); }
/* * FitCurve : * Fit a Bezier curve to a set of digitized points */ void CBCStroke::FitCurve( DISCURVE& d, /* Array of digitized points */ int nPts, /* Number of digitized points */ double error) /* User-defined error squared */ { Vector2 tHat1, tHat2; /* Unit tangent vectors at endpoints */ tHat1 = ComputeLeftTangent(d, 0); tHat2 = ComputeRightTangent(d, nPts - 1); FitCubic(d, 0, nPts - 1, tHat1, tHat2, error); }
/* * FitCurve : * Fit a Bezier curve to a set of digitized points */ BezierContour FitCurve(PointContour &contour, double error) { Vector2 tHat1, tHat2; /* Unit tangent vectors at endpoints */ PointContour::iterator iter; BezierContour bezContour; int i = 0; int nPts = contour.size(); Point2 *d = (Point2 *)malloc(nPts * sizeof(Point2)); for (iter = contour.begin(); iter != contour.end(); ++iter) { Point2 a; a.x = (*iter)[0]; a.y = (*iter)[1]; d[i++] = a; } tHat1 = ComputeLeftTangent(d, 0); tHat2 = ComputeRightTangent(d, nPts - 1); FitCubic(d, 0, nPts - 1, tHat1, tHat2, error, bezContour); free(d); return bezContour; }
QPainterPath bezierFit(const QList<QPointF> &points,float error){ FitVector tHat1, tHat2; tHat1 = ComputeLeftTangent(points,0); tHat2 = ComputeRightTangent(points,points.count()-1); int width=0; QPointF *curve; curve = FitCubic(points,0,points.count()-1,tHat1,tHat2,error,width); QPainterPath path; if(width>3){ path.moveTo(curve[0]); path.cubicTo(curve[1],curve[2],curve[3]); for(int i=4;i<width;i+=4){ path.cubicTo(curve[i+1],curve[i+2],curve[i+3]); } } delete[] curve; return path; }
/* * FitCubic : * Fit a Bezier curve to a (sub)set of digitized points */ static void FitCubic(Point2 *d, int first, int last, Vector2 tHat1, Vector2 tHat2, double error, BezierContour &bezContour) { BezierCurve bezCurve; /*Control points of fitted Bezier curve*/ double *u; /* Parameter values for point */ double *uPrime; /* Improved parameter values */ double maxError; /* Maximum fitting error */ int splitPoint; /* Point to split point set at */ int nPts; /* Number of points in subset */ double iterationError; /*Error below which you try iterating */ int maxIterations = 4; /* Max times to try iterating */ Vector2 tHatCenter; /* Unit tangent vector at splitPoint */ int i; iterationError = error * error; nPts = last - first + 1; /* Use heuristic if region only has two points in it */ if (nPts == 2) { double dist = V2DistanceBetween2Points(&d[last], &d[first]) / 3.0; bezCurve = (Point2 *)malloc(4 * sizeof(Point2)); bezCurve[0] = d[first]; bezCurve[3] = d[last]; V2Add(&bezCurve[0], V2Scale(&tHat1, dist), &bezCurve[1]); V2Add(&bezCurve[3], V2Scale(&tHat2, dist), &bezCurve[2]); DrawBezierCurve(3, bezCurve, bezContour); free((void *)bezCurve); return; } /* Parameterize points, and attempt to fit curve */ u = ChordLengthParameterize(d, first, last); bezCurve = GenerateBezier(d, first, last, u, tHat1, tHat2); /* Find max deviation of points to fitted curve */ maxError = ComputeMaxError(d, first, last, bezCurve, u, &splitPoint); if (maxError < error) { DrawBezierCurve(3, bezCurve, bezContour); free((void *)u); free((void *)bezCurve); return; } /* If error not too large, try some reparameterization */ /* and iteration */ if (maxError < iterationError) { for (i = 0; i < maxIterations; i++) { uPrime = Reparameterize(d, first, last, u, bezCurve); free((void *)bezCurve); bezCurve = GenerateBezier(d, first, last, uPrime, tHat1, tHat2); maxError = ComputeMaxError(d, first, last, bezCurve, uPrime, &splitPoint); if (maxError < error) { DrawBezierCurve(3, bezCurve, bezContour); free((void *)u); free((void *)bezCurve); free((void *)uPrime); return; } free((void *)u); u = uPrime; } } /* Fitting failed -- split at max error point and fit recursively */ free((void *)u); free((void *)bezCurve); tHatCenter = ComputeCenterTangent(d, splitPoint); FitCubic(d, first, splitPoint, tHat1, tHatCenter, error, bezContour); V2Negate(&tHatCenter); FitCubic(d, splitPoint, last, tHatCenter, tHat2, error, bezContour); }
QPointF *FitCubic(const QList<QPointF> &points, int first, int last, FitVector tHat1, FitVector tHat2, float error, int &width) { qreal *u; qreal *uPrime; qreal maxError; int splitPoint; int nPts; qreal iterationError; int maxIterations = 4; FitVector tHatCenter; QPointF *curve; int i; width = 0; iterationError = error * error; nPts = last - first + 1; if (nPts == 2) { qreal dist = distance(points.at(last), points.at(first)) / 3.0; curve = new QPointF[4]; curve[0] = points.at(first); curve[3] = points.at(last); tHat1.scale(dist); tHat2.scale(dist); curve[1] = tHat1 + curve[0]; curve[2] = tHat2 + curve[3]; width = 4; return curve; } /* Parameterize points, and attempt to fit curve */ u = ChordLengthParameterize(points, first, last); curve = GenerateBezier(points, first, last, u, tHat1, tHat2); /* Find max deviation of points to fitted curve */ maxError = ComputeMaxError(points, first, last, curve, u, &splitPoint); if (maxError < error) { delete[] u; width = 4; return curve; } /* If error not too large, try some reparameterization */ /* and iteration */ if (maxError < iterationError) { for (i = 0; i < maxIterations; ++i) { uPrime = Reparameterize(points, first, last, u, curve); delete[] curve; curve = GenerateBezier(points, first, last, uPrime, tHat1, tHat2); maxError = ComputeMaxError(points, first, last, curve, uPrime, &splitPoint); if (maxError < error) { delete[] u; delete[] uPrime; width = 4; return curve; } delete[] u; u = uPrime; } } /* Fitting failed -- split at max error point and fit recursively */ delete[] u; delete[] curve; tHatCenter = ComputeCenterTangent(points, splitPoint); int w1, w2; QPointF *cu1 = NULL, *cu2 = NULL; cu1 = FitCubic(points, first, splitPoint, tHat1, tHatCenter, error, w1); tHatCenter.negate(); cu2 = FitCubic(points, splitPoint, last, tHatCenter, tHat2, error, w2); QPointF *newcurve = new QPointF[w1+w2]; for (int i = 0; i < w1; ++i) { newcurve[i] = cu1[i]; } for (int i = 0; i < w2; ++i) { newcurve[i+w1] = cu2[i]; } delete[] cu1; delete[] cu2; width = w1 + w2; return newcurve; }
bool Path::AttemptSimplify(int off, int N, double treshhold, PathDescrCubicTo &res,int &worstP) { Geom::Point start; Geom::Point end; // pour une coordonnee double *Xk; // la coordonnee traitee (x puis y) double *Yk; // la coordonnee traitee (x puis y) double *lk; // les longueurs de chaque segment double *tk; // les tk double *Qk; // les Qk char *fk; // si point force Geom::Point cp1; Geom::Point cp2; if (N == 2) { worstP = 1; return true; } start = pts[off].p; cp1 = pts[off + 1].p; end = pts[off + N - 1].p; res.p = end; res.start[0] = res.start[1] = 0; res.end[0] = res.end[1] = 0; if (N == 3) { // start -> cp1 -> end res.start = cp1 - start; res.end = end - cp1; worstP = 1; return true; } // Totally inefficient, allocates & deallocates all the time. tk = (double *) g_malloc(N * sizeof(double)); Qk = (double *) g_malloc(N * sizeof(double)); Xk = (double *) g_malloc(N * sizeof(double)); Yk = (double *) g_malloc(N * sizeof(double)); lk = (double *) g_malloc(N * sizeof(double)); fk = (char *) g_malloc(N * sizeof(char)); // chord length method tk[0] = 0.0; lk[0] = 0.0; { Geom::Point prevP = start; for (int i = 1; i < N; i++) { Xk[i] = pts[off + i].p[Geom::X]; Yk[i] = pts[off + i].p[Geom::Y]; if ( pts[off + i].isMoveTo == polyline_forced ) { fk[i] = 0x01; } else { fk[i] = 0; } Geom::Point diff(Xk[i] - prevP[Geom::X], Yk[i] - prevP[1]); prevP[0] = Xk[i]; prevP[1] = Yk[i]; lk[i] = Geom::L2(diff); tk[i] = tk[i - 1] + lk[i]; } } if (tk[N - 1] < 0.00001) { // longueur nulle res.start[0] = res.start[1] = 0; res.end[0] = res.end[1] = 0; double worstD = 0; worstP = -1; for (int i = 1; i < N; i++) { Geom::Point nPt; bool isForced = fk[i]; nPt[0] = Xk[i]; nPt[1] = Yk[i]; double nle = DistanceToCubic(start, res, nPt); if ( isForced ) { // forced points are favored for splitting the recursion; we do this by increasing their distance if ( worstP < 0 || 2 * nle > worstD ) { worstP = i; worstD = 2 * nle; } } else { if ( worstP < 0 || nle > worstD ) { worstP = i; worstD = nle; } } } g_free(tk); g_free(Qk); g_free(Xk); g_free(Yk); g_free(fk); g_free(lk); return false; } double totLen = tk[N - 1]; for (int i = 1; i < N - 1; i++) { tk[i] /= totLen; } res.p = end; if ( FitCubic(start, res, Xk, Yk, Qk, tk, N) ) { cp1 = start + res.start / 3; cp2 = end + res.end / 3; } else { // aie, non-inversible res.start[0] = res.start[1] = 0; res.end[0] = res.end[1] = 0; double worstD = 0; worstP = -1; for (int i = 1; i < N; i++) { Geom::Point nPt(Xk[i], Yk[i]); bool isForced = fk[i]; double nle = DistanceToCubic(start, res, nPt); if ( isForced ) { // forced points are favored for splitting the recursion; we do this by increasing their distance if ( worstP < 0 || 2 * nle > worstD ) { worstP = i; worstD = 2 * nle; } } else { if ( worstP < 0 || nle > worstD ) { worstP = i; worstD = nle; } } } g_free(tk); g_free(Qk); g_free(Xk); g_free(Yk); g_free(fk); g_free(lk); return false; } // calcul du delta= pondere par les longueurs des segments double delta = 0; { double worstD = 0; worstP = -1; Geom::Point prevAppP; Geom::Point prevP; double prevDist; prevP[0] = Xk[0]; prevP[1] = Yk[0]; prevAppP = prevP; // le premier seulement prevDist = 0; #ifdef with_splotch_killer if ( N <= 20 ) { for (int i = 1; i < N - 1; i++) { Geom::Point curAppP; Geom::Point curP; double curDist; Geom::Point midAppP; Geom::Point midP; double midDist; curAppP[0] = N13 (tk[i]) * cp1[0] + N23 (tk[i]) * cp2[0] + N03 (tk[i]) * Xk[0] + N33 (tk[i]) * Xk[N - 1]; curAppP[1] = N13 (tk[i]) * cp1[1] + N23 (tk[i]) * cp2[1] + N03 (tk[i]) * Yk[0] + N33 (tk[i]) * Yk[N - 1]; curP[0] = Xk[i]; curP[1] = Yk[i]; midAppP[0] = N13 (0.5*(tk[i]+tk[i-1])) * cp1[0] + N23 (0.5*(tk[i]+tk[i-1])) * cp2[0] + N03 (0.5*(tk[i]+tk[i-1])) * Xk[0] + N33 (0.5*(tk[i]+tk[i-1])) * Xk[N - 1]; midAppP[1] = N13 (0.5*(tk[i]+tk[i-1])) * cp1[1] + N23 (0.5*(tk[i]+tk[i-1])) * cp2[1] + N03 (0.5*(tk[i]+tk[i-1])) * Yk[0] + N33 (0.5*(tk[i]+tk[i-1])) * Yk[N - 1]; midP=0.5*(curP+prevP); Geom::Point diff; diff = curAppP-curP; curDist = dot(diff,diff); diff = midAppP-midP; midDist = dot(diff,diff); delta+=0.3333*(curDist+prevDist+midDist)/**lk[i]*/; if ( curDist > worstD ) { worstD = curDist; worstP = i; } else if ( fk[i] && 2*curDist > worstD ) { worstD = 2*curDist; worstP = i; } prevP = curP; prevAppP = curAppP; prevDist = curDist; } delta/=totLen; } else { #endif for (int i = 1; i < N - 1; i++) { Geom::Point curAppP; Geom::Point curP; double curDist; curAppP[0] = N13 (tk[i]) * cp1[0] + N23 (tk[i]) * cp2[0] + N03 (tk[i]) * Xk[0] + N33 (tk[i]) * Xk[N - 1]; curAppP[1] = N13 (tk[i]) * cp1[1] + N23 (tk[i]) * cp2[1] + N03 (tk[i]) * Yk[0] + N33 (tk[i]) * Yk[N - 1]; curP[0] = Xk[i]; curP[1] = Yk[i]; Geom::Point diff; diff = curAppP-curP; curDist = dot(diff,diff); delta += curDist; if ( curDist > worstD ) { worstD = curDist; worstP = i; } else if ( fk[i] && 2*curDist > worstD ) { worstD = 2*curDist; worstP = i; } prevP = curP; prevAppP = curAppP; prevDist = curDist; } #ifdef with_splotch_killer } #endif } if (delta < treshhold * treshhold) { // premier jet res.start = 3.0 * (cp1 - start); res.end = -3.0 * (cp2 - end); res.p = end; // Refine a little. for (int i = 1; i < N - 1; i++) { Geom::Point pt; pt[0] = Xk[i]; pt[1] = Yk[i]; tk[i] = RaffineTk (pt, start, cp1, cp2, end, tk[i]); if (tk[i] < tk[i - 1]) { // Force tk to be monotonic non-decreasing. tk[i] = tk[i - 1]; } } if ( FitCubic(start,res,Xk,Yk,Qk,tk,N) ) { } else { // ca devrait jamais arriver, mais bon res.start = 3.0 * (cp1 - start); res.end = -3.0 * (cp2 - end); g_free(tk); g_free(Qk); g_free(Xk); g_free(Yk); g_free(fk); g_free(lk); return true; } double ndelta = 0; { double worstD = 0; worstP = -1; Geom::Point prevAppP; Geom::Point prevP; double prevDist; prevP[0] = Xk[0]; prevP[1] = Yk[0]; prevAppP = prevP; // le premier seulement prevDist = 0; #ifdef with_splotch_killer if ( N <= 20 ) { for (int i = 1; i < N - 1; i++) { Geom::Point curAppP; Geom::Point curP; double curDist; Geom::Point midAppP; Geom::Point midP; double midDist; curAppP[0] = N13 (tk[i]) * cp1[0] + N23 (tk[i]) * cp2[0] + N03 (tk[i]) * Xk[0] + N33 (tk[i]) * Xk[N - 1]; curAppP[1] = N13 (tk[i]) * cp1[1] + N23 (tk[i]) * cp2[1] + N03 (tk[i]) * Yk[0] + N33 (tk[i]) * Yk[N - 1]; curP[0] = Xk[i]; curP[1] = Yk[i]; midAppP[0] = N13 (0.5*(tk[i]+tk[i-1])) * cp1[0] + N23 (0.5*(tk[i]+tk[i-1])) * cp2[0] + N03 (0.5*(tk[i]+tk[i-1])) * Xk[0] + N33 (0.5*(tk[i]+tk[i-1])) * Xk[N - 1]; midAppP[1] = N13 (0.5*(tk[i]+tk[i-1])) * cp1[1] + N23 (0.5*(tk[i]+tk[i-1])) * cp2[1] + N03 (0.5*(tk[i]+tk[i-1])) * Yk[0] + N33 (0.5*(tk[i]+tk[i-1])) * Yk[N - 1]; midP = 0.5*(curP+prevP); Geom::Point diff; diff = curAppP-curP; curDist = dot(diff,diff); diff = midAppP-midP; midDist = dot(diff,diff); ndelta+=0.3333*(curDist+prevDist+midDist)/**lk[i]*/; if ( curDist > worstD ) { worstD = curDist; worstP = i; } else if ( fk[i] && 2*curDist > worstD ) { worstD = 2*curDist; worstP = i; } prevP = curP; prevAppP = curAppP; prevDist = curDist; } ndelta /= totLen; } else { #endif for (int i = 1; i < N - 1; i++) { Geom::Point curAppP; Geom::Point curP; double curDist; curAppP[0] = N13 (tk[i]) * cp1[0] + N23 (tk[i]) * cp2[0] + N03 (tk[i]) * Xk[0] + N33 (tk[i]) * Xk[N - 1]; curAppP[1] = N13 (tk[i]) * cp1[1] + N23 (tk[i]) * cp2[1] + N03 (tk[i]) * Yk[0] + N33 (tk[i]) * Yk[N - 1]; curP[0]=Xk[i]; curP[1]=Yk[i]; Geom::Point diff; diff=curAppP-curP; curDist=dot(diff,diff); ndelta+=curDist; if ( curDist > worstD ) { worstD=curDist; worstP=i; } else if ( fk[i] && 2*curDist > worstD ) { worstD=2*curDist; worstP=i; } prevP=curP; prevAppP=curAppP; prevDist=curDist; } #ifdef with_splotch_killer } #endif } g_free(tk); g_free(Qk); g_free(Xk); g_free(Yk); g_free(fk); g_free(lk); if (ndelta < delta + 0.00001) { return true; } else { // nothing better to do res.start = 3.0 * (cp1 - start); res.end = -3.0 * (cp2 - end); } return true; } else { // nothing better to do } g_free(tk); g_free(Qk); g_free(Xk); g_free(Yk); g_free(fk); g_free(lk); return false; }
// fit a polyline to a bezier patch, return true is treshhold not exceeded (ie: you can continue) // version that uses tables from the previous iteration, to minimize amount of work done bool Path::AttemptSimplify (fitting_tables &data,double treshhold, PathDescrCubicTo & res,int &worstP) { Geom::Point start,end; // pour une coordonnee Geom::Point cp1, cp2; worstP = 1; if (pts.size() == 2) { return true; } start[0] = data.Xk[0]; start[1] = data.Yk[0]; cp1[0] = data.Xk[1]; cp1[1] = data.Yk[1]; end[0] = data.Xk[data.nbPt - 1]; end[1] = data.Yk[data.nbPt - 1]; cp2 = cp1; if (pts.size() == 3) { // start -> cp1 -> end res.start = cp1 - start; res.end = end - cp1; worstP = 1; return true; } if ( FitCubic(start, res, data.Xk, data.Yk, data.Qk, data.tk, data.nbPt) ) { cp1 = start + res.start / 3; cp2 = end - res.end / 3; } else { // aie, non-inversible double worstD = 0; worstP = -1; for (int i = 1; i < data.nbPt; i++) { Geom::Point nPt; nPt[Geom::X] = data.Xk[i]; nPt[Geom::Y] = data.Yk[i]; double nle = DistanceToCubic(start, res, nPt); if ( data.fk[i] ) { // forced points are favored for splitting the recursion; we do this by increasing their distance if ( worstP < 0 || 2 * nle > worstD ) { worstP = i; worstD = 2 * nle; } } else { if ( worstP < 0 || nle > worstD ) { worstP = i; worstD = nle; } } } return false; } // calcul du delta= pondere par les longueurs des segments double delta = 0; { double worstD = 0; worstP = -1; Geom::Point prevAppP; Geom::Point prevP; double prevDist; prevP[Geom::X] = data.Xk[0]; prevP[Geom::Y] = data.Yk[0]; prevAppP = prevP; // le premier seulement prevDist = 0; #ifdef with_splotch_killer if ( data.nbPt <= 20 ) { for (int i = 1; i < data.nbPt - 1; i++) { Geom::Point curAppP; Geom::Point curP; double curDist; Geom::Point midAppP; Geom::Point midP; double midDist; curAppP[Geom::X] = N13(data.tk[i]) * cp1[Geom::X] + N23(data.tk[i]) * cp2[Geom::X] + N03(data.tk[i]) * data.Xk[0] + N33(data.tk[i]) * data.Xk[data.nbPt - 1]; curAppP[Geom::Y] = N13(data.tk[i]) * cp1[Geom::Y] + N23(data.tk[i]) * cp2[Geom::Y] + N03(data.tk[i]) * data.Yk[0] + N33(data.tk[i]) * data.Yk[data.nbPt - 1]; curP[Geom::X] = data.Xk[i]; curP[Geom::Y] = data.Yk[i]; double mtk = 0.5 * (data.tk[i] + data.tk[i - 1]); midAppP[Geom::X] = N13(mtk) * cp1[Geom::X] + N23(mtk) * cp2[Geom::X] + N03(mtk) * data.Xk[0] + N33(mtk) * data.Xk[data.nbPt - 1]; midAppP[Geom::Y] = N13(mtk) * cp1[Geom::Y] + N23(mtk) * cp2[Geom::Y] + N03(mtk) * data.Yk[0] + N33(mtk) * data.Yk[data.nbPt - 1]; midP = 0.5 * (curP + prevP); Geom::Point diff = curAppP - curP; curDist = dot(diff, diff); diff = midAppP - midP; midDist = dot(diff, diff); delta += 0.3333 * (curDist + prevDist + midDist) * data.lk[i]; if ( curDist > worstD ) { worstD = curDist; worstP = i; } else if ( data.fk[i] && 2 * curDist > worstD ) { worstD = 2*curDist; worstP = i; } prevP = curP; prevAppP = curAppP; prevDist = curDist; } delta /= data.totLen; } else { #endif for (int i = 1; i < data.nbPt - 1; i++) { Geom::Point curAppP; Geom::Point curP; double curDist; curAppP[Geom::X] = N13(data.tk[i]) * cp1[Geom::X] + N23(data.tk[i]) * cp2[Geom::X] + N03(data.tk[i]) * data.Xk[0] + N33(data.tk[i]) * data.Xk[data.nbPt - 1]; curAppP[Geom::Y] = N13(data.tk[i]) * cp1[Geom::Y] + N23(data.tk[i]) * cp2[Geom::Y] + N03(data.tk[i]) * data.Yk[0] + N33(data.tk[i]) * data.Yk[data.nbPt - 1]; curP[Geom::X] = data.Xk[i]; curP[Geom::Y] = data.Yk[i]; Geom::Point diff = curAppP-curP; curDist = dot(diff, diff); delta += curDist; if ( curDist > worstD ) { worstD = curDist; worstP = i; } else if ( data.fk[i] && 2 * curDist > worstD ) { worstD = 2*curDist; worstP = i; } prevP = curP; prevAppP = curAppP; prevDist = curDist; } #ifdef with_splotch_killer } #endif } if (delta < treshhold * treshhold) { // premier jet // Refine a little. for (int i = 1; i < data.nbPt - 1; i++) { Geom::Point pt(data.Xk[i], data.Yk[i]); data.tk[i] = RaffineTk(pt, start, cp1, cp2, end, data.tk[i]); if (data.tk[i] < data.tk[i - 1]) { // Force tk to be monotonic non-decreasing. data.tk[i] = data.tk[i - 1]; } } if ( FitCubic(start, res, data.Xk, data.Yk, data.Qk, data.tk, data.nbPt) == false) { // ca devrait jamais arriver, mais bon res.start = 3.0 * (cp1 - start); res.end = 3.0 * (end - cp2 ); return true; } double ndelta = 0; { double worstD = 0; worstP = -1; Geom::Point prevAppP; Geom::Point prevP(data.Xk[0], data.Yk[0]); double prevDist = 0; prevAppP = prevP; // le premier seulement #ifdef with_splotch_killer if ( data.nbPt <= 20 ) { for (int i = 1; i < data.nbPt - 1; i++) { Geom::Point curAppP; Geom::Point curP; double curDist; Geom::Point midAppP; Geom::Point midP; double midDist; curAppP[Geom::X] = N13(data.tk[i]) * cp1[Geom::X] + N23(data.tk[i]) * cp2[Geom::X] + N03(data.tk[i]) * data.Xk[0] + N33(data.tk[i]) * data.Xk[data.nbPt - 1]; curAppP[Geom::Y] = N13(data.tk[i]) * cp1[Geom::Y] + N23(data.tk[i]) * cp2[Geom::Y] + N03(data.tk[i]) * data.Yk[0] + N33(data.tk[i]) * data.Yk[data.nbPt - 1]; curP[Geom::X] = data.Xk[i]; curP[Geom::Y] = data.Yk[i]; double mtk = 0.5 * (data.tk[i] + data.tk[i - 1]); midAppP[Geom::X] = N13(mtk) * cp1[Geom::X] + N23(mtk) * cp2[Geom::X] + N03(mtk) * data.Xk[0] + N33(mtk) * data.Xk[data.nbPt - 1]; midAppP[Geom::Y] = N13(mtk) * cp1[Geom::Y] + N23(mtk) * cp2[Geom::Y] + N03(mtk) * data.Yk[0] + N33(mtk) * data.Yk[data.nbPt - 1]; midP = 0.5 * (curP + prevP); Geom::Point diff = curAppP - curP; curDist = dot(diff, diff); diff = midAppP - midP; midDist = dot(diff, diff); ndelta += 0.3333 * (curDist + prevDist + midDist) * data.lk[i]; if ( curDist > worstD ) { worstD = curDist; worstP = i; } else if ( data.fk[i] && 2 * curDist > worstD ) { worstD = 2*curDist; worstP = i; } prevP = curP; prevAppP = curAppP; prevDist = curDist; } ndelta /= data.totLen; } else { #endif for (int i = 1; i < data.nbPt - 1; i++) { Geom::Point curAppP; Geom::Point curP; double curDist; curAppP[Geom::X] = N13(data.tk[i]) * cp1[Geom::X] + N23(data.tk[i]) * cp2[Geom::X] + N03(data.tk[i]) * data.Xk[0] + N33(data.tk[i]) * data.Xk[data.nbPt - 1]; curAppP[Geom::Y] = N13(data.tk[i]) * cp1[Geom::Y] + N23(data.tk[i]) * cp2[1] + N03(data.tk[i]) * data.Yk[0] + N33(data.tk[i]) * data.Yk[data.nbPt - 1]; curP[Geom::X] = data.Xk[i]; curP[Geom::Y] = data.Yk[i]; Geom::Point diff = curAppP - curP; curDist = dot(diff, diff); ndelta += curDist; if ( curDist > worstD ) { worstD = curDist; worstP = i; } else if ( data.fk[i] && 2 * curDist > worstD ) { worstD = 2 * curDist; worstP = i; } prevP = curP; prevAppP = curAppP; prevDist = curDist; } #ifdef with_splotch_killer } #endif } if (ndelta < delta + 0.00001) { return true; } else { // nothing better to do res.start = 3.0 * (cp1 - start); res.end = 3.0 * (end - cp2 ); } return true; } return false; }