blob: 2b3c11d20a95099d3e143d082121fdb3b6d3441e [file] [log] [blame]
caryclark@google.com7e0274e2013-04-08 20:36:19 +00001/*
skia.committer@gmail.com32840172013-04-09 07:01:27 +00002Solving the Nearest Point-on-Curve Problem
caryclark@google.com7e0274e2013-04-08 20:36:19 +00003and
4A Bezier Curve-Based Root-Finder
5by Philip J. Schneider
6from "Graphics Gems", Academic Press, 1990
7*/
8
skia.committer@gmail.com32840172013-04-09 07:01:27 +00009 /* point_on_curve.c */
10
caryclark@google.com7e0274e2013-04-08 20:36:19 +000011#include <stdio.h>
12#include <malloc.h>
13#include <math.h>
14#include "GraphicsGems.h"
15
16#define TESTMODE
17
18/*
19 * Forward declarations
20 */
21Point2 NearestPointOnCurve();
skia.committer@gmail.com32840172013-04-09 07:01:27 +000022static int FindRoots();
23static Point2 *ConvertToBezierForm();
24static double ComputeXIntercept();
25static int ControlPolygonFlatEnough();
26static int CrossingCount();
27static Point2 Bezier();
28static Vector2 V2ScaleII();
caryclark@google.com7e0274e2013-04-08 20:36:19 +000029
skia.committer@gmail.com32840172013-04-09 07:01:27 +000030int MAXDEPTH = 64; /* Maximum depth for recursion */
caryclark@google.com7e0274e2013-04-08 20:36:19 +000031
skia.committer@gmail.com32840172013-04-09 07:01:27 +000032#define EPSILON (ldexp(1.0,-MAXDEPTH-1)) /*Flatness control value */
33#define DEGREE 3 /* Cubic Bezier curve */
34#define W_DEGREE 5 /* Degree of eqn to find roots of */
caryclark@google.com7e0274e2013-04-08 20:36:19 +000035
36#ifdef TESTMODE
37/*
38 * main :
skia.committer@gmail.com32840172013-04-09 07:01:27 +000039 * Given a cubic Bezier curve (i.e., its control points), and some
40 * arbitrary point in the plane, find the point on the curve
41 * closest to that arbitrary point.
caryclark@google.com7e0274e2013-04-08 20:36:19 +000042 */
43main()
44{
skia.committer@gmail.com32840172013-04-09 07:01:27 +000045
46 static Point2 bezCurve[4] = { /* A cubic Bezier curve */
47 { 0.0, 0.0 },
48 { 1.0, 2.0 },
49 { 3.0, 3.0 },
50 { 4.0, 2.0 },
caryclark@google.com7e0274e2013-04-08 20:36:19 +000051 };
52 static Point2 arbPoint = { 3.5, 2.0 }; /*Some arbitrary point*/
skia.committer@gmail.com32840172013-04-09 07:01:27 +000053 Point2 pointOnCurve; /* Nearest point on the curve */
caryclark@google.com7e0274e2013-04-08 20:36:19 +000054
55 /* Find the closest point */
56 pointOnCurve = NearestPointOnCurve(arbPoint, bezCurve);
57 printf("pointOnCurve : (%4.4f, %4.4f)\n", pointOnCurve.x,
skia.committer@gmail.com32840172013-04-09 07:01:27 +000058 pointOnCurve.y);
caryclark@google.com7e0274e2013-04-08 20:36:19 +000059}
60#endif /* TESTMODE */
61
62
63/*
64 * NearestPointOnCurve :
skia.committer@gmail.com32840172013-04-09 07:01:27 +000065 * Compute the parameter value of the point on a Bezier
66 * curve segment closest to some arbtitrary, user-input point.
67 * Return the point on the curve at that parameter value.
caryclark@google.com7e0274e2013-04-08 20:36:19 +000068 *
69 */
70Point2 NearestPointOnCurve(P, V)
skia.committer@gmail.com32840172013-04-09 07:01:27 +000071 Point2 P; /* The user-supplied point */
72 Point2 *V; /* Control points of cubic Bezier */
caryclark@google.com7e0274e2013-04-08 20:36:19 +000073{
skia.committer@gmail.com32840172013-04-09 07:01:27 +000074 Point2 *w; /* Ctl pts for 5th-degree eqn */
75 double t_candidate[W_DEGREE]; /* Possible roots */
76 int n_solutions; /* Number of roots found */
77 double t; /* Parameter value of closest pt*/
caryclark@google.com7e0274e2013-04-08 20:36:19 +000078
skia.committer@gmail.com32840172013-04-09 07:01:27 +000079 /* Convert problem to 5th-degree Bezier form */
caryclark@google.com7e0274e2013-04-08 20:36:19 +000080 w = ConvertToBezierForm(P, V);
81
82 /* Find all possible roots of 5th-degree equation */
83 n_solutions = FindRoots(w, W_DEGREE, t_candidate, 0);
84 free((char *)w);
85
86 /* Compare distances of P to all candidates, and to t=0, and t=1 */
87 {
skia.committer@gmail.com32840172013-04-09 07:01:27 +000088 double dist, new_dist;
89 Point2 p;
90 Vector2 v;
91 int i;
caryclark@google.com7e0274e2013-04-08 20:36:19 +000092
caryclark@google.com7e0274e2013-04-08 20:36:19 +000093
skia.committer@gmail.com32840172013-04-09 07:01:27 +000094 /* Check distance to beginning of curve, where t = 0 */
95 dist = V2SquaredLength(V2Sub(&P, &V[0], &v));
96 t = 0.0;
97
98 /* Find distances for candidate points */
caryclark@google.com7e0274e2013-04-08 20:36:19 +000099 for (i = 0; i < n_solutions; i++) {
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000100 p = Bezier(V, DEGREE, t_candidate[i],
101 (Point2 *)NULL, (Point2 *)NULL);
102 new_dist = V2SquaredLength(V2Sub(&P, &p, &v));
103 if (new_dist < dist) {
104 dist = new_dist;
105 t = t_candidate[i];
106 }
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000107 }
108
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000109 /* Finally, look at distance to end point, where t = 1.0 */
110 new_dist = V2SquaredLength(V2Sub(&P, &V[DEGREE], &v));
111 if (new_dist < dist) {
112 dist = new_dist;
113 t = 1.0;
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000114 }
115 }
116
117 /* Return the point on the curve at parameter value t */
118 printf("t : %4.12f\n", t);
119 return (Bezier(V, DEGREE, t, (Point2 *)NULL, (Point2 *)NULL));
120}
121
122
123/*
124 * ConvertToBezierForm :
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000125 * Given a point and a Bezier curve, generate a 5th-degree
126 * Bezier-format equation whose solution finds the point on the
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000127 * curve nearest the user-defined point.
128 */
129static Point2 *ConvertToBezierForm(P, V)
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000130 Point2 P; /* The point to find t for */
131 Point2 *V; /* The control points */
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000132{
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000133 int i, j, k, m, n, ub, lb;
134 int row, column; /* Table indices */
135 Vector2 c[DEGREE+1]; /* V(i)'s - P */
136 Vector2 d[DEGREE]; /* V(i+1) - V(i) */
137 Point2 *w; /* Ctl pts of 5th-degree curve */
138 double cdTable[3][4]; /* Dot product of c, d */
139 static double z[3][4] = { /* Precomputed "z" for cubics */
140 {1.0, 0.6, 0.3, 0.1},
141 {0.4, 0.6, 0.6, 0.4},
142 {0.1, 0.3, 0.6, 1.0},
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000143 };
144
145
146 /*Determine the c's -- these are vectors created by subtracting*/
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000147 /* point P from each of the control points */
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000148 for (i = 0; i <= DEGREE; i++) {
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000149 V2Sub(&V[i], &P, &c[i]);
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000150 }
151 /* Determine the d's -- these are vectors created by subtracting*/
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000152 /* each control point from the next */
153 for (i = 0; i <= DEGREE - 1; i++) {
154 d[i] = V2ScaleII(V2Sub(&V[i+1], &V[i], &d[i]), 3.0);
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000155 }
156
157 /* Create the c,d table -- this is a table of dot products of the */
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000158 /* c's and d's */
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000159 for (row = 0; row <= DEGREE - 1; row++) {
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000160 for (column = 0; column <= DEGREE; column++) {
161 cdTable[row][column] = V2Dot(&d[row], &c[column]);
162 }
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000163 }
164
165 /* Now, apply the z's to the dot products, on the skew diagonal*/
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000166 /* Also, set up the x-values, making these "points" */
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000167 w = (Point2 *)malloc((unsigned)(W_DEGREE+1) * sizeof(Point2));
168 for (i = 0; i <= W_DEGREE; i++) {
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000169 w[i].y = 0.0;
170 w[i].x = (double)(i) / W_DEGREE;
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000171 }
172
173 n = DEGREE;
174 m = DEGREE-1;
175 for (k = 0; k <= n + m; k++) {
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000176 lb = MAX(0, k - m);
177 ub = MIN(k, n);
178 for (i = lb; i <= ub; i++) {
179 j = k - i;
180 w[i+j].y += cdTable[j][i] * z[j][i];
181 }
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000182 }
183
184 return (w);
185}
186
187
188/*
189 * FindRoots :
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000190 * Given a 5th-degree equation in Bernstein-Bezier form, find
191 * all of the roots in the interval [0, 1]. Return the number
192 * of roots found.
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000193 */
194static int FindRoots(w, degree, t, depth)
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000195 Point2 *w; /* The control points */
196 int degree; /* The degree of the polynomial */
197 double *t; /* RETURN candidate t-values */
198 int depth; /* The depth of the recursion */
199{
200 int i;
201 Point2 Left[W_DEGREE+1], /* New left and right */
202 Right[W_DEGREE+1]; /* control polygons */
203 int left_count, /* Solution count from */
204 right_count; /* children */
205 double left_t[W_DEGREE+1], /* Solutions from kids */
206 right_t[W_DEGREE+1];
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000207
208 switch (CrossingCount(w, degree)) {
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000209 case 0 : { /* No solutions here */
210 return 0;
211 }
212 case 1 : { /* Unique solution */
213 /* Stop recursion when the tree is deep enough */
214 /* if deep enough, return 1 solution at midpoint */
215 if (depth >= MAXDEPTH) {
216 t[0] = (w[0].x + w[W_DEGREE].x) / 2.0;
217 return 1;
218 }
219 if (ControlPolygonFlatEnough(w, degree)) {
220 t[0] = ComputeXIntercept(w, degree);
221 return 1;
222 }
223 break;
224 }
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000225}
226
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000227 /* Otherwise, solve recursively after */
228 /* subdividing control polygon */
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000229 Bezier(w, degree, 0.5, Left, Right);
230 left_count = FindRoots(Left, degree, left_t, depth+1);
231 right_count = FindRoots(Right, degree, right_t, depth+1);
232
233
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000234 /* Gather solutions together */
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000235 for (i = 0; i < left_count; i++) {
236 t[i] = left_t[i];
237 }
238 for (i = 0; i < right_count; i++) {
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000239 t[i+left_count] = right_t[i];
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000240 }
241
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000242 /* Send back total number of solutions */
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000243 return (left_count+right_count);
244}
245
246
247/*
248 * CrossingCount :
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000249 * Count the number of times a Bezier control polygon
250 * crosses the 0-axis. This number is >= the number of roots.
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000251 *
252 */
253static int CrossingCount(V, degree)
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000254 Point2 *V; /* Control pts of Bezier curve */
255 int degree; /* Degreee of Bezier curve */
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000256{
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000257 int i;
258 int n_crossings = 0; /* Number of zero-crossings */
259 int sign, old_sign; /* Sign of coefficients */
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000260
261 sign = old_sign = SGN(V[0].y);
262 for (i = 1; i <= degree; i++) {
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000263 sign = SGN(V[i].y);
264 if (sign != old_sign) n_crossings++;
265 old_sign = sign;
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000266 }
267 return n_crossings;
268}
269
270
271
272/*
273 * ControlPolygonFlatEnough :
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000274 * Check if the control polygon of a Bezier curve is flat enough
275 * for recursive subdivision to bottom out.
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000276 *
277 */
278static int ControlPolygonFlatEnough(V, degree)
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000279 Point2 *V; /* Control points */
280 int degree; /* Degree of polynomial */
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000281{
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000282 int i; /* Index variable */
283 double *distance; /* Distances from pts to line */
284 double max_distance_above; /* maximum of these */
285 double max_distance_below;
286 double error; /* Precision of root */
287 double intercept_1,
288 intercept_2,
289 left_intercept,
290 right_intercept;
291 double a, b, c; /* Coefficients of implicit */
292 /* eqn for line from V[0]-V[deg]*/
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000293
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000294 /* Find the perpendicular distance */
295 /* from each interior control point to */
296 /* line connecting V[0] and V[degree] */
297 distance = (double *)malloc((unsigned)(degree + 1) * sizeof(double));
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000298 {
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000299 double abSquared;
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000300
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000301 /* Derive the implicit equation for line connecting first *'
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000302 /* and last control points */
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000303 a = V[0].y - V[degree].y;
304 b = V[degree].x - V[0].x;
305 c = V[0].x * V[degree].y - V[degree].x * V[0].y;
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000306
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000307 abSquared = (a * a) + (b * b);
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000308
309 for (i = 1; i < degree; i++) {
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000310 /* Compute distance from each of the points to that line */
311 distance[i] = a * V[i].x + b * V[i].y + c;
312 if (distance[i] > 0.0) {
313 distance[i] = (distance[i] * distance[i]) / abSquared;
314 }
315 if (distance[i] < 0.0) {
316 distance[i] = -((distance[i] * distance[i]) / abSquared);
317 }
318 }
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000319 }
320
321
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000322 /* Find the largest distance */
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000323 max_distance_above = 0.0;
324 max_distance_below = 0.0;
325 for (i = 1; i < degree; i++) {
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000326 if (distance[i] < 0.0) {
327 max_distance_below = MIN(max_distance_below, distance[i]);
328 };
329 if (distance[i] > 0.0) {
330 max_distance_above = MAX(max_distance_above, distance[i]);
331 }
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000332 }
333 free((char *)distance);
334
335 {
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000336 double det, dInv;
337 double a1, b1, c1, a2, b2, c2;
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000338
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000339 /* Implicit equation for zero line */
340 a1 = 0.0;
341 b1 = 1.0;
342 c1 = 0.0;
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000343
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000344 /* Implicit equation for "above" line */
345 a2 = a;
346 b2 = b;
347 c2 = c + max_distance_above;
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000348
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000349 det = a1 * b2 - a2 * b1;
350 dInv = 1.0/det;
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000351
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000352 intercept_1 = (b1 * c2 - b2 * c1) * dInv;
353
354 /* Implicit equation for "below" line */
355 a2 = a;
356 b2 = b;
357 c2 = c + max_distance_below;
358
359 det = a1 * b2 - a2 * b1;
360 dInv = 1.0/det;
361
362 intercept_2 = (b1 * c2 - b2 * c1) * dInv;
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000363 }
364
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000365 /* Compute intercepts of bounding box */
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000366 left_intercept = MIN(intercept_1, intercept_2);
367 right_intercept = MAX(intercept_1, intercept_2);
368
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000369 error = 0.5 * (right_intercept-left_intercept);
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000370 if (error < EPSILON) {
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000371 return 1;
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000372 }
373 else {
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000374 return 0;
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000375 }
376}
377
378
379
380/*
381 * ComputeXIntercept :
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000382 * Compute intersection of chord from first control point to last
383 * with 0-axis.
384 *
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000385 */
386/* NOTE: "T" and "Y" do not have to be computed, and there are many useless
387 * operations in the following (e.g. "0.0 - 0.0").
388 */
389static double ComputeXIntercept(V, degree)
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000390 Point2 *V; /* Control points */
391 int degree; /* Degree of curve */
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000392{
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000393 double XLK, YLK, XNM, YNM, XMK, YMK;
394 double det, detInv;
395 double S, T;
396 double X, Y;
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000397
398 XLK = 1.0 - 0.0;
399 YLK = 0.0 - 0.0;
400 XNM = V[degree].x - V[0].x;
401 YNM = V[degree].y - V[0].y;
402 XMK = V[0].x - 0.0;
403 YMK = V[0].y - 0.0;
404
405 det = XNM*YLK - YNM*XLK;
406 detInv = 1.0/det;
407
408 S = (XNM*YMK - YNM*XMK) * detInv;
409/* T = (XLK*YMK - YLK*XMK) * detInv; */
410
411 X = 0.0 + XLK * S;
412/* Y = 0.0 + YLK * S; */
413
414 return X;
415}
416
417
418/*
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000419 * Bezier :
420 * Evaluate a Bezier curve at a particular parameter value
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000421 * Fill in control points for resulting sub-curves if "Left" and
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000422 * "Right" are non-null.
423 *
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000424 */
425static Point2 Bezier(V, degree, t, Left, Right)
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000426 int degree; /* Degree of bezier curve */
427 Point2 *V; /* Control pts */
428 double t; /* Parameter value */
429 Point2 *Left; /* RETURN left half ctl pts */
430 Point2 *Right; /* RETURN right half ctl pts */
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000431{
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000432 int i, j; /* Index variables */
433 Point2 Vtemp[W_DEGREE+1][W_DEGREE+1];
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000434
435
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000436 /* Copy control points */
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000437 for (j =0; j <= degree; j++) {
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000438 Vtemp[0][j] = V[j];
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000439 }
440
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000441 /* Triangle computation */
442 for (i = 1; i <= degree; i++) {
443 for (j =0 ; j <= degree - i; j++) {
444 Vtemp[i][j].x =
445 (1.0 - t) * Vtemp[i-1][j].x + t * Vtemp[i-1][j+1].x;
446 Vtemp[i][j].y =
447 (1.0 - t) * Vtemp[i-1][j].y + t * Vtemp[i-1][j+1].y;
448 }
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000449 }
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000450
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000451 if (Left != NULL) {
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000452 for (j = 0; j <= degree; j++) {
453 Left[j] = Vtemp[j][0];
454 }
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000455 }
456 if (Right != NULL) {
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000457 for (j = 0; j <= degree; j++) {
458 Right[j] = Vtemp[degree-j][j];
459 }
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000460 }
461
462 return (Vtemp[degree][0]);
463}
464
465static Vector2 V2ScaleII(v, s)
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000466 Vector2 *v;
467 double s;
caryclark@google.com7e0274e2013-04-08 20:36:19 +0000468{
469 Vector2 result;
470
471 result.x = v->x * s; result.y = v->y * s;
472 return (result);
473}