static void CalcBSpline( IntCoord cminus1x, IntCoord cminus1y, IntCoord cx, IntCoord cy, IntCoord cplus1x, IntCoord cplus1y, IntCoord cplus2x, IntCoord cplus2y ) { double p0x, p1x, p2x, p3x, tempx, p0y, p1y, p2y, p3y, tempy; ThirdPoint( double(cx), double(cy), double(cplus1x), double(cplus1y), p1x, p1y ); ThirdPoint( double(cplus1x), double(cplus1y), double(cx), double(cy), p2x, p2y ); ThirdPoint( double(cx), double(cy), double(cminus1x), double(cminus1y), tempx, tempy ); Midpoint(tempx, tempy, p1x, p1y, p0x, p0y); ThirdPoint( double(cplus1x), double(cplus1y), double(cplus2x), double(cplus2y), tempx, tempy ); Midpoint(tempx, tempy, p2x, p2y, p3x, p3y); AddBezierCurve(p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y); }
void Painter::Curve( Canvas* c, IntCoord x0, IntCoord y0, IntCoord x1, IntCoord y1, IntCoord x2, IntCoord y2, IntCoord x3, IntCoord y3 ) { IntCoord tx0, ty0, tx1, ty1, tx2, ty2, tx3, ty3; llcount = 0; Map(c, x0, y0, tx0, ty0); Map(c, x1, y1, tx1, ty1); Map(c, x2, y2, tx2, ty2); Map(c, x3, y3, tx3, ty3); AddBezierCurve(tx0, ty0, tx1, ty1, tx2, ty2, tx3, ty3); MultiLineNoMap(c, llx, lly, llcount); }
static void AddBezierCurve( double x0, double y0, double x1, double y1, double x2, double y2, double x3, double y3 ) { double midx01, midx12, midx23, midlsegx, midrsegx, cx; double midy01, midy12, midy23, midlsegy, midrsegy, cy; Midpoint(x0, y0, x1, y1, midx01, midy01); Midpoint(x1, y1, x2, y2, midx12, midy12); Midpoint(x2, y2, x3, y3, midx23, midy23); Midpoint(midx01, midy01, midx12, midy12, midlsegx, midlsegy); Midpoint(midx12, midy12, midx23, midy23, midrsegx, midrsegy); Midpoint(midlsegx, midlsegy, midrsegx, midrsegy, cx, cy); if (CanApproxWithLine(x0, y0, midlsegx, midlsegy, cx, cy)) { AddLine(x0, y0, cx, cy); } else if ( (midx01 != x1) || (midy01 != y1) || (midlsegx != x2) || (midlsegy != y2) || (cx != x3) || (cy != y3) ) { AddBezierCurve( x0, y0, midx01, midy01, midlsegx, midlsegy, cx, cy ); } if (CanApproxWithLine(cx, cy, midx23, midy23, x3, y3)) { AddLine(cx, cy, x3, y3); } else if ( (cx != x0) || (cy != y0) || (midrsegx != x1) || (midrsegy != y1) || (midx23 != x2) || (midy23 != y2) ) { AddBezierCurve( cx, cy, midrsegx, midrsegy, midx23, midy23, x3, y3 ); } }
/* * FitCubic : * Fit a Bezier curve to a (sub)set of digitized points */ void CBCStroke::FitCubic( DISCURVE& d, /* Array of digitized points */ int first,int last,/* Indices of first and last pts in region */ Vector2 tHat1,Vector2 tHat2, /* Unit tangent vectors at endpoints */ double error) /* User-defined error squared */ { 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 = 5; /* 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(, bezCurve); double u[2]; u[0]=0; u[1]=1; PARAMERLIST paramList; CopyParamList(first,last,u,paramList); AddBezierCurve(3,bezCurve,paramList); 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); PARAMERLIST paramList; CopyParamList(first,last,u,paramList); AddBezierCurve(3,bezCurve,paramList); 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); bezCurve = GenerateBezier(d, first, last, uPrime, tHat1, tHat2); maxError = ComputeMaxError(d, first, last, bezCurve, uPrime, &splitPoint); if (maxError < error) { //DrawBezierCurve(3, bezCurve); PARAMERLIST paramList; CopyParamList(first,last,u,paramList); AddBezierCurve(3,bezCurve,paramList); free((void *)u); free((void *)bezCurve); 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); V2Negate(&tHatCenter); FitCubic(d, splitPoint, last, tHatCenter, tHat2, error); }