Index: experimental/Intersection/NearestPoint.cpp |
diff --git a/experimental/Intersection/NearestPoint.cpp b/experimental/Intersection/NearestPoint.cpp |
deleted file mode 100644 |
index 2b3c11d20a95099d3e143d082121fdb3b6d3441e..0000000000000000000000000000000000000000 |
--- a/experimental/Intersection/NearestPoint.cpp |
+++ /dev/null |
@@ -1,473 +0,0 @@ |
-/* |
-Solving the Nearest Point-on-Curve Problem |
-and |
-A Bezier Curve-Based Root-Finder |
-by Philip J. Schneider |
-from "Graphics Gems", Academic Press, 1990 |
-*/ |
- |
- /* point_on_curve.c */ |
- |
-#include <stdio.h> |
-#include <malloc.h> |
-#include <math.h> |
-#include "GraphicsGems.h" |
- |
-#define TESTMODE |
- |
-/* |
- * Forward declarations |
- */ |
-Point2 NearestPointOnCurve(); |
-static int FindRoots(); |
-static Point2 *ConvertToBezierForm(); |
-static double ComputeXIntercept(); |
-static int ControlPolygonFlatEnough(); |
-static int CrossingCount(); |
-static Point2 Bezier(); |
-static Vector2 V2ScaleII(); |
- |
-int MAXDEPTH = 64; /* Maximum depth for recursion */ |
- |
-#define EPSILON (ldexp(1.0,-MAXDEPTH-1)) /*Flatness control value */ |
-#define DEGREE 3 /* Cubic Bezier curve */ |
-#define W_DEGREE 5 /* Degree of eqn to find roots of */ |
- |
-#ifdef TESTMODE |
-/* |
- * main : |
- * Given a cubic Bezier curve (i.e., its control points), and some |
- * arbitrary point in the plane, find the point on the curve |
- * closest to that arbitrary point. |
- */ |
-main() |
-{ |
- |
- static Point2 bezCurve[4] = { /* A cubic Bezier curve */ |
- { 0.0, 0.0 }, |
- { 1.0, 2.0 }, |
- { 3.0, 3.0 }, |
- { 4.0, 2.0 }, |
- }; |
- static Point2 arbPoint = { 3.5, 2.0 }; /*Some arbitrary point*/ |
- Point2 pointOnCurve; /* Nearest point on the curve */ |
- |
- /* Find the closest point */ |
- pointOnCurve = NearestPointOnCurve(arbPoint, bezCurve); |
- printf("pointOnCurve : (%4.4f, %4.4f)\n", pointOnCurve.x, |
- pointOnCurve.y); |
-} |
-#endif /* TESTMODE */ |
- |
- |
-/* |
- * NearestPointOnCurve : |
- * Compute the parameter value of the point on a Bezier |
- * curve segment closest to some arbtitrary, user-input point. |
- * Return the point on the curve at that parameter value. |
- * |
- */ |
-Point2 NearestPointOnCurve(P, V) |
- Point2 P; /* The user-supplied point */ |
- Point2 *V; /* Control points of cubic Bezier */ |
-{ |
- Point2 *w; /* Ctl pts for 5th-degree eqn */ |
- double t_candidate[W_DEGREE]; /* Possible roots */ |
- int n_solutions; /* Number of roots found */ |
- double t; /* Parameter value of closest pt*/ |
- |
- /* Convert problem to 5th-degree Bezier form */ |
- w = ConvertToBezierForm(P, V); |
- |
- /* Find all possible roots of 5th-degree equation */ |
- n_solutions = FindRoots(w, W_DEGREE, t_candidate, 0); |
- free((char *)w); |
- |
- /* Compare distances of P to all candidates, and to t=0, and t=1 */ |
- { |
- double dist, new_dist; |
- Point2 p; |
- Vector2 v; |
- int i; |
- |
- |
- /* Check distance to beginning of curve, where t = 0 */ |
- dist = V2SquaredLength(V2Sub(&P, &V[0], &v)); |
- t = 0.0; |
- |
- /* Find distances for candidate points */ |
- for (i = 0; i < n_solutions; i++) { |
- p = Bezier(V, DEGREE, t_candidate[i], |
- (Point2 *)NULL, (Point2 *)NULL); |
- new_dist = V2SquaredLength(V2Sub(&P, &p, &v)); |
- if (new_dist < dist) { |
- dist = new_dist; |
- t = t_candidate[i]; |
- } |
- } |
- |
- /* Finally, look at distance to end point, where t = 1.0 */ |
- new_dist = V2SquaredLength(V2Sub(&P, &V[DEGREE], &v)); |
- if (new_dist < dist) { |
- dist = new_dist; |
- t = 1.0; |
- } |
- } |
- |
- /* Return the point on the curve at parameter value t */ |
- printf("t : %4.12f\n", t); |
- return (Bezier(V, DEGREE, t, (Point2 *)NULL, (Point2 *)NULL)); |
-} |
- |
- |
-/* |
- * ConvertToBezierForm : |
- * Given a point and a Bezier curve, generate a 5th-degree |
- * Bezier-format equation whose solution finds the point on the |
- * curve nearest the user-defined point. |
- */ |
-static Point2 *ConvertToBezierForm(P, V) |
- Point2 P; /* The point to find t for */ |
- Point2 *V; /* The control points */ |
-{ |
- int i, j, k, m, n, ub, lb; |
- int row, column; /* Table indices */ |
- Vector2 c[DEGREE+1]; /* V(i)'s - P */ |
- Vector2 d[DEGREE]; /* V(i+1) - V(i) */ |
- Point2 *w; /* Ctl pts of 5th-degree curve */ |
- double cdTable[3][4]; /* Dot product of c, d */ |
- static double z[3][4] = { /* Precomputed "z" for cubics */ |
- {1.0, 0.6, 0.3, 0.1}, |
- {0.4, 0.6, 0.6, 0.4}, |
- {0.1, 0.3, 0.6, 1.0}, |
- }; |
- |
- |
- /*Determine the c's -- these are vectors created by subtracting*/ |
- /* point P from each of the control points */ |
- for (i = 0; i <= DEGREE; i++) { |
- V2Sub(&V[i], &P, &c[i]); |
- } |
- /* Determine the d's -- these are vectors created by subtracting*/ |
- /* each control point from the next */ |
- for (i = 0; i <= DEGREE - 1; i++) { |
- d[i] = V2ScaleII(V2Sub(&V[i+1], &V[i], &d[i]), 3.0); |
- } |
- |
- /* Create the c,d table -- this is a table of dot products of the */ |
- /* c's and d's */ |
- for (row = 0; row <= DEGREE - 1; row++) { |
- for (column = 0; column <= DEGREE; column++) { |
- cdTable[row][column] = V2Dot(&d[row], &c[column]); |
- } |
- } |
- |
- /* Now, apply the z's to the dot products, on the skew diagonal*/ |
- /* Also, set up the x-values, making these "points" */ |
- w = (Point2 *)malloc((unsigned)(W_DEGREE+1) * sizeof(Point2)); |
- for (i = 0; i <= W_DEGREE; i++) { |
- w[i].y = 0.0; |
- w[i].x = (double)(i) / W_DEGREE; |
- } |
- |
- n = DEGREE; |
- m = DEGREE-1; |
- for (k = 0; k <= n + m; k++) { |
- lb = MAX(0, k - m); |
- ub = MIN(k, n); |
- for (i = lb; i <= ub; i++) { |
- j = k - i; |
- w[i+j].y += cdTable[j][i] * z[j][i]; |
- } |
- } |
- |
- return (w); |
-} |
- |
- |
-/* |
- * FindRoots : |
- * Given a 5th-degree equation in Bernstein-Bezier form, find |
- * all of the roots in the interval [0, 1]. Return the number |
- * of roots found. |
- */ |
-static int FindRoots(w, degree, t, depth) |
- Point2 *w; /* The control points */ |
- int degree; /* The degree of the polynomial */ |
- double *t; /* RETURN candidate t-values */ |
- int depth; /* The depth of the recursion */ |
-{ |
- int i; |
- Point2 Left[W_DEGREE+1], /* New left and right */ |
- Right[W_DEGREE+1]; /* control polygons */ |
- int left_count, /* Solution count from */ |
- right_count; /* children */ |
- double left_t[W_DEGREE+1], /* Solutions from kids */ |
- right_t[W_DEGREE+1]; |
- |
- switch (CrossingCount(w, degree)) { |
- case 0 : { /* No solutions here */ |
- return 0; |
- } |
- case 1 : { /* Unique solution */ |
- /* Stop recursion when the tree is deep enough */ |
- /* if deep enough, return 1 solution at midpoint */ |
- if (depth >= MAXDEPTH) { |
- t[0] = (w[0].x + w[W_DEGREE].x) / 2.0; |
- return 1; |
- } |
- if (ControlPolygonFlatEnough(w, degree)) { |
- t[0] = ComputeXIntercept(w, degree); |
- return 1; |
- } |
- break; |
- } |
-} |
- |
- /* Otherwise, solve recursively after */ |
- /* subdividing control polygon */ |
- Bezier(w, degree, 0.5, Left, Right); |
- left_count = FindRoots(Left, degree, left_t, depth+1); |
- right_count = FindRoots(Right, degree, right_t, depth+1); |
- |
- |
- /* Gather solutions together */ |
- for (i = 0; i < left_count; i++) { |
- t[i] = left_t[i]; |
- } |
- for (i = 0; i < right_count; i++) { |
- t[i+left_count] = right_t[i]; |
- } |
- |
- /* Send back total number of solutions */ |
- return (left_count+right_count); |
-} |
- |
- |
-/* |
- * CrossingCount : |
- * Count the number of times a Bezier control polygon |
- * crosses the 0-axis. This number is >= the number of roots. |
- * |
- */ |
-static int CrossingCount(V, degree) |
- Point2 *V; /* Control pts of Bezier curve */ |
- int degree; /* Degreee of Bezier curve */ |
-{ |
- int i; |
- int n_crossings = 0; /* Number of zero-crossings */ |
- int sign, old_sign; /* Sign of coefficients */ |
- |
- sign = old_sign = SGN(V[0].y); |
- for (i = 1; i <= degree; i++) { |
- sign = SGN(V[i].y); |
- if (sign != old_sign) n_crossings++; |
- old_sign = sign; |
- } |
- return n_crossings; |
-} |
- |
- |
- |
-/* |
- * ControlPolygonFlatEnough : |
- * Check if the control polygon of a Bezier curve is flat enough |
- * for recursive subdivision to bottom out. |
- * |
- */ |
-static int ControlPolygonFlatEnough(V, degree) |
- Point2 *V; /* Control points */ |
- int degree; /* Degree of polynomial */ |
-{ |
- int i; /* Index variable */ |
- double *distance; /* Distances from pts to line */ |
- double max_distance_above; /* maximum of these */ |
- double max_distance_below; |
- double error; /* Precision of root */ |
- double intercept_1, |
- intercept_2, |
- left_intercept, |
- right_intercept; |
- double a, b, c; /* Coefficients of implicit */ |
- /* eqn for line from V[0]-V[deg]*/ |
- |
- /* Find the perpendicular distance */ |
- /* from each interior control point to */ |
- /* line connecting V[0] and V[degree] */ |
- distance = (double *)malloc((unsigned)(degree + 1) * sizeof(double)); |
- { |
- double abSquared; |
- |
- /* Derive the implicit equation for line connecting first *' |
- /* and last control points */ |
- a = V[0].y - V[degree].y; |
- b = V[degree].x - V[0].x; |
- c = V[0].x * V[degree].y - V[degree].x * V[0].y; |
- |
- abSquared = (a * a) + (b * b); |
- |
- for (i = 1; i < degree; i++) { |
- /* Compute distance from each of the points to that line */ |
- distance[i] = a * V[i].x + b * V[i].y + c; |
- if (distance[i] > 0.0) { |
- distance[i] = (distance[i] * distance[i]) / abSquared; |
- } |
- if (distance[i] < 0.0) { |
- distance[i] = -((distance[i] * distance[i]) / abSquared); |
- } |
- } |
- } |
- |
- |
- /* Find the largest distance */ |
- max_distance_above = 0.0; |
- max_distance_below = 0.0; |
- for (i = 1; i < degree; i++) { |
- if (distance[i] < 0.0) { |
- max_distance_below = MIN(max_distance_below, distance[i]); |
- }; |
- if (distance[i] > 0.0) { |
- max_distance_above = MAX(max_distance_above, distance[i]); |
- } |
- } |
- free((char *)distance); |
- |
- { |
- double det, dInv; |
- double a1, b1, c1, a2, b2, c2; |
- |
- /* Implicit equation for zero line */ |
- a1 = 0.0; |
- b1 = 1.0; |
- c1 = 0.0; |
- |
- /* Implicit equation for "above" line */ |
- a2 = a; |
- b2 = b; |
- c2 = c + max_distance_above; |
- |
- det = a1 * b2 - a2 * b1; |
- dInv = 1.0/det; |
- |
- intercept_1 = (b1 * c2 - b2 * c1) * dInv; |
- |
- /* Implicit equation for "below" line */ |
- a2 = a; |
- b2 = b; |
- c2 = c + max_distance_below; |
- |
- det = a1 * b2 - a2 * b1; |
- dInv = 1.0/det; |
- |
- intercept_2 = (b1 * c2 - b2 * c1) * dInv; |
- } |
- |
- /* Compute intercepts of bounding box */ |
- left_intercept = MIN(intercept_1, intercept_2); |
- right_intercept = MAX(intercept_1, intercept_2); |
- |
- error = 0.5 * (right_intercept-left_intercept); |
- if (error < EPSILON) { |
- return 1; |
- } |
- else { |
- return 0; |
- } |
-} |
- |
- |
- |
-/* |
- * ComputeXIntercept : |
- * Compute intersection of chord from first control point to last |
- * with 0-axis. |
- * |
- */ |
-/* NOTE: "T" and "Y" do not have to be computed, and there are many useless |
- * operations in the following (e.g. "0.0 - 0.0"). |
- */ |
-static double ComputeXIntercept(V, degree) |
- Point2 *V; /* Control points */ |
- int degree; /* Degree of curve */ |
-{ |
- double XLK, YLK, XNM, YNM, XMK, YMK; |
- double det, detInv; |
- double S, T; |
- double X, Y; |
- |
- XLK = 1.0 - 0.0; |
- YLK = 0.0 - 0.0; |
- XNM = V[degree].x - V[0].x; |
- YNM = V[degree].y - V[0].y; |
- XMK = V[0].x - 0.0; |
- YMK = V[0].y - 0.0; |
- |
- det = XNM*YLK - YNM*XLK; |
- detInv = 1.0/det; |
- |
- S = (XNM*YMK - YNM*XMK) * detInv; |
-/* T = (XLK*YMK - YLK*XMK) * detInv; */ |
- |
- X = 0.0 + XLK * S; |
-/* Y = 0.0 + YLK * S; */ |
- |
- return X; |
-} |
- |
- |
-/* |
- * Bezier : |
- * Evaluate a Bezier curve at a particular parameter value |
- * Fill in control points for resulting sub-curves if "Left" and |
- * "Right" are non-null. |
- * |
- */ |
-static Point2 Bezier(V, degree, t, Left, Right) |
- int degree; /* Degree of bezier curve */ |
- Point2 *V; /* Control pts */ |
- double t; /* Parameter value */ |
- Point2 *Left; /* RETURN left half ctl pts */ |
- Point2 *Right; /* RETURN right half ctl pts */ |
-{ |
- int i, j; /* Index variables */ |
- Point2 Vtemp[W_DEGREE+1][W_DEGREE+1]; |
- |
- |
- /* Copy control points */ |
- for (j =0; j <= degree; j++) { |
- Vtemp[0][j] = V[j]; |
- } |
- |
- /* Triangle computation */ |
- for (i = 1; i <= degree; i++) { |
- for (j =0 ; j <= degree - i; j++) { |
- Vtemp[i][j].x = |
- (1.0 - t) * Vtemp[i-1][j].x + t * Vtemp[i-1][j+1].x; |
- Vtemp[i][j].y = |
- (1.0 - t) * Vtemp[i-1][j].y + t * Vtemp[i-1][j+1].y; |
- } |
- } |
- |
- if (Left != NULL) { |
- for (j = 0; j <= degree; j++) { |
- Left[j] = Vtemp[j][0]; |
- } |
- } |
- if (Right != NULL) { |
- for (j = 0; j <= degree; j++) { |
- Right[j] = Vtemp[degree-j][j]; |
- } |
- } |
- |
- return (Vtemp[degree][0]); |
-} |
- |
-static Vector2 V2ScaleII(v, s) |
- Vector2 *v; |
- double s; |
-{ |
- Vector2 result; |
- |
- result.x = v->x * s; result.y = v->y * s; |
- return (result); |
-} |