/* * 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; }