/* * 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); }
/* ** Compute uv-coordinates of the point ** Return TRUE if the point is in the quadrangle */ static boolean point_in_quad (QUAD *Quad, HIT *Hit) { char LargestComponent; /* of the normal vector */ Point2 A, B, C, D; /* Projected vertices */ Point2 M; /* Projected intersection point */ Vector2 AB, BC, CD, AD, AM, AE; /* AE = DC - AB = DA - CB */ REAL u, v; /* Parametric coordinates */ REAL a, b, c, SqrtDelta; /* for the quadratic equation */ boolean IsInside = FALSE; /* if u and v are inside */ Vector2 Vector; /* temporary 2D-vector */ /* ** Projection on the plane that is most parallel to the facet */ LargestComponent = LARGEST_COMPONENT(Quad->Normal); if (LargestComponent == 'x') { A.x = Quad->A.y; B.x = Quad->B.y; C.x = Quad->C.y; D.x = Quad->D.y; M.x = Hit->Point.y; } else { A.x = Quad->A.x; B.x = Quad->B.x; C.x = Quad->C.x; D.x = Quad->D.x; M.x = Hit->Point.x; } if (LargestComponent == 'z') { A.y = Quad->A.y; B.y = Quad->B.y; C.y = Quad->C.y; D.y = Quad->D.y; M.y = Hit->Point.y; } else { A.y = Quad->A.z; B.y = Quad->B.z; C.y = Quad->C.z; D.y = Quad->D.z; M.y = Hit->Point.z; } V2Sub (&B, &A, &AB); V2Sub (&C, &B, &BC); V2Sub (&D, &C, &CD); V2Sub (&D, &A, &AD); V2Add (&CD, &AB, &AE); V2Negate (&AE); V2Sub (&M, &A, &AM); if (fabs(DETERMINANT(AB, CD)) < EPSILON) /* case AB // CD */ { V2Sub (&AB, &CD, &Vector); v = DETERMINANT(AM, Vector) / DETERMINANT(AD, Vector); if ((v >= 0.0) && (v <= 1.0)) { b = DETERMINANT(AB, AD) - DETERMINANT(AM, AE); c = DETERMINANT (AM, AD); u = ABS(b) < EPSILON ? -1 : c/b; IsInside = ((u >= 0.0) && (u <= 1.0)); } } else if (fabs(DETERMINANT(BC, AD)) < EPSILON) /* case AD // BC */ { V2Add (&AD, &BC, &Vector); u = DETERMINANT(AM, Vector) / DETERMINANT(AB, Vector); if ((u >= 0.0) && (u <= 1.0)) { b = DETERMINANT(AD, AB) - DETERMINANT(AM, AE); c = DETERMINANT (AM, AB); v = ABS(b) < EPSILON ? -1 : c/b; IsInside = ((v >= 0.0) && (v <= 1.0)); } } else /* general case */ { a = DETERMINANT(AB, AE); c = - DETERMINANT (AM,AD); b = DETERMINANT(AB, AD) - DETERMINANT(AM, AE); a = -0.5/a; b *= a; c *= (a + a); SqrtDelta = b*b + c; if (SqrtDelta >= 0.0) { SqrtDelta = sqrt(SqrtDelta); u = b - SqrtDelta; if ((u < 0.0) || (u > 1.0)) /* to choose u between 0 and 1 */ u = b + SqrtDelta; if ((u >= 0.0) && (u <= 1.0)) { v = AD.x + u * AE.x; if (ABS(v) < EPSILON) v = (AM.y - u * AB.y) / (AD.y + u * AE.y); else v = (AM.x - u * AB.x) / v; IsInside = ((v >= 0.0) && (v <= 1.0)); } } } if (IsInside) { Hit->u = u; Hit->v = v; } return (IsInside); }