1
2 /*
3 * Copyright 2006 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10 #include "SkGeometry.h"
11 #include "Sk64.h"
12 #include "SkMatrix.h"
13
SkXRayCrossesLine(const SkXRay & pt,const SkPoint pts[2],bool * ambiguous)14 bool SkXRayCrossesLine(const SkXRay& pt, const SkPoint pts[2], bool* ambiguous) {
15 if (ambiguous) {
16 *ambiguous = false;
17 }
18 // Determine quick discards.
19 // Consider query line going exactly through point 0 to not
20 // intersect, for symmetry with SkXRayCrossesMonotonicCubic.
21 if (pt.fY == pts[0].fY) {
22 if (ambiguous) {
23 *ambiguous = true;
24 }
25 return false;
26 }
27 if (pt.fY < pts[0].fY && pt.fY < pts[1].fY)
28 return false;
29 if (pt.fY > pts[0].fY && pt.fY > pts[1].fY)
30 return false;
31 if (pt.fX > pts[0].fX && pt.fX > pts[1].fX)
32 return false;
33 // Determine degenerate cases
34 if (SkScalarNearlyZero(pts[0].fY - pts[1].fY))
35 return false;
36 if (SkScalarNearlyZero(pts[0].fX - pts[1].fX)) {
37 // We've already determined the query point lies within the
38 // vertical range of the line segment.
39 if (pt.fX <= pts[0].fX) {
40 if (ambiguous) {
41 *ambiguous = (pt.fY == pts[1].fY);
42 }
43 return true;
44 }
45 return false;
46 }
47 // Ambiguity check
48 if (pt.fY == pts[1].fY) {
49 if (pt.fX <= pts[1].fX) {
50 if (ambiguous) {
51 *ambiguous = true;
52 }
53 return true;
54 }
55 return false;
56 }
57 // Full line segment evaluation
58 SkScalar delta_y = pts[1].fY - pts[0].fY;
59 SkScalar delta_x = pts[1].fX - pts[0].fX;
60 SkScalar slope = SkScalarDiv(delta_y, delta_x);
61 SkScalar b = pts[0].fY - SkScalarMul(slope, pts[0].fX);
62 // Solve for x coordinate at y = pt.fY
63 SkScalar x = SkScalarDiv(pt.fY - b, slope);
64 return pt.fX <= x;
65 }
66
67 /** If defined, this makes eval_quad and eval_cubic do more setup (sometimes
68 involving integer multiplies by 2 or 3, but fewer calls to SkScalarMul.
69 May also introduce overflow of fixed when we compute our setup.
70 */
71 #ifdef SK_SCALAR_IS_FIXED
72 #define DIRECT_EVAL_OF_POLYNOMIALS
73 #endif
74
75 ////////////////////////////////////////////////////////////////////////
76
77 #ifdef SK_SCALAR_IS_FIXED
is_not_monotonic(int a,int b,int c,int d)78 static int is_not_monotonic(int a, int b, int c, int d)
79 {
80 return (((a - b) | (b - c) | (c - d)) & ((b - a) | (c - b) | (d - c))) >> 31;
81 }
82
is_not_monotonic(int a,int b,int c)83 static int is_not_monotonic(int a, int b, int c)
84 {
85 return (((a - b) | (b - c)) & ((b - a) | (c - b))) >> 31;
86 }
87 #else
is_not_monotonic(float a,float b,float c)88 static int is_not_monotonic(float a, float b, float c)
89 {
90 float ab = a - b;
91 float bc = b - c;
92 if (ab < 0)
93 bc = -bc;
94 return ab == 0 || bc < 0;
95 }
96 #endif
97
98 ////////////////////////////////////////////////////////////////////////
99
is_unit_interval(SkScalar x)100 static bool is_unit_interval(SkScalar x)
101 {
102 return x > 0 && x < SK_Scalar1;
103 }
104
valid_unit_divide(SkScalar numer,SkScalar denom,SkScalar * ratio)105 static int valid_unit_divide(SkScalar numer, SkScalar denom, SkScalar* ratio)
106 {
107 SkASSERT(ratio);
108
109 if (numer < 0)
110 {
111 numer = -numer;
112 denom = -denom;
113 }
114
115 if (denom == 0 || numer == 0 || numer >= denom)
116 return 0;
117
118 SkScalar r = SkScalarDiv(numer, denom);
119 if (SkScalarIsNaN(r)) {
120 return 0;
121 }
122 SkASSERT(r >= 0 && r < SK_Scalar1);
123 if (r == 0) // catch underflow if numer <<<< denom
124 return 0;
125 *ratio = r;
126 return 1;
127 }
128
129 /** From Numerical Recipes in C.
130
131 Q = -1/2 (B + sign(B) sqrt[B*B - 4*A*C])
132 x1 = Q / A
133 x2 = C / Q
134 */
SkFindUnitQuadRoots(SkScalar A,SkScalar B,SkScalar C,SkScalar roots[2])135 int SkFindUnitQuadRoots(SkScalar A, SkScalar B, SkScalar C, SkScalar roots[2])
136 {
137 SkASSERT(roots);
138
139 if (A == 0)
140 return valid_unit_divide(-C, B, roots);
141
142 SkScalar* r = roots;
143
144 #ifdef SK_SCALAR_IS_FLOAT
145 float R = B*B - 4*A*C;
146 if (R < 0 || SkScalarIsNaN(R)) { // complex roots
147 return 0;
148 }
149 R = sk_float_sqrt(R);
150 #else
151 Sk64 RR, tmp;
152
153 RR.setMul(B,B);
154 tmp.setMul(A,C);
155 tmp.shiftLeft(2);
156 RR.sub(tmp);
157 if (RR.isNeg())
158 return 0;
159 SkFixed R = RR.getSqrt();
160 #endif
161
162 SkScalar Q = (B < 0) ? -(B-R)/2 : -(B+R)/2;
163 r += valid_unit_divide(Q, A, r);
164 r += valid_unit_divide(C, Q, r);
165 if (r - roots == 2)
166 {
167 if (roots[0] > roots[1])
168 SkTSwap<SkScalar>(roots[0], roots[1]);
169 else if (roots[0] == roots[1]) // nearly-equal?
170 r -= 1; // skip the double root
171 }
172 return (int)(r - roots);
173 }
174
175 #ifdef SK_SCALAR_IS_FIXED
176 /** Trim A/B/C down so that they are all <= 32bits
177 and then call SkFindUnitQuadRoots()
178 */
Sk64FindFixedQuadRoots(const Sk64 & A,const Sk64 & B,const Sk64 & C,SkFixed roots[2])179 static int Sk64FindFixedQuadRoots(const Sk64& A, const Sk64& B, const Sk64& C, SkFixed roots[2])
180 {
181 int na = A.shiftToMake32();
182 int nb = B.shiftToMake32();
183 int nc = C.shiftToMake32();
184
185 int shift = SkMax32(na, SkMax32(nb, nc));
186 SkASSERT(shift >= 0);
187
188 return SkFindUnitQuadRoots(A.getShiftRight(shift), B.getShiftRight(shift), C.getShiftRight(shift), roots);
189 }
190 #endif
191
192 /////////////////////////////////////////////////////////////////////////////////////
193 /////////////////////////////////////////////////////////////////////////////////////
194
eval_quad(const SkScalar src[],SkScalar t)195 static SkScalar eval_quad(const SkScalar src[], SkScalar t)
196 {
197 SkASSERT(src);
198 SkASSERT(t >= 0 && t <= SK_Scalar1);
199
200 #ifdef DIRECT_EVAL_OF_POLYNOMIALS
201 SkScalar C = src[0];
202 SkScalar A = src[4] - 2 * src[2] + C;
203 SkScalar B = 2 * (src[2] - C);
204 return SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C);
205 #else
206 SkScalar ab = SkScalarInterp(src[0], src[2], t);
207 SkScalar bc = SkScalarInterp(src[2], src[4], t);
208 return SkScalarInterp(ab, bc, t);
209 #endif
210 }
211
eval_quad_derivative(const SkScalar src[],SkScalar t)212 static SkScalar eval_quad_derivative(const SkScalar src[], SkScalar t)
213 {
214 SkScalar A = src[4] - 2 * src[2] + src[0];
215 SkScalar B = src[2] - src[0];
216
217 return 2 * SkScalarMulAdd(A, t, B);
218 }
219
eval_quad_derivative_at_half(const SkScalar src[])220 static SkScalar eval_quad_derivative_at_half(const SkScalar src[])
221 {
222 SkScalar A = src[4] - 2 * src[2] + src[0];
223 SkScalar B = src[2] - src[0];
224 return A + 2 * B;
225 }
226
SkEvalQuadAt(const SkPoint src[3],SkScalar t,SkPoint * pt,SkVector * tangent)227 void SkEvalQuadAt(const SkPoint src[3], SkScalar t, SkPoint* pt, SkVector* tangent)
228 {
229 SkASSERT(src);
230 SkASSERT(t >= 0 && t <= SK_Scalar1);
231
232 if (pt)
233 pt->set(eval_quad(&src[0].fX, t), eval_quad(&src[0].fY, t));
234 if (tangent)
235 tangent->set(eval_quad_derivative(&src[0].fX, t),
236 eval_quad_derivative(&src[0].fY, t));
237 }
238
SkEvalQuadAtHalf(const SkPoint src[3],SkPoint * pt,SkVector * tangent)239 void SkEvalQuadAtHalf(const SkPoint src[3], SkPoint* pt, SkVector* tangent)
240 {
241 SkASSERT(src);
242
243 if (pt)
244 {
245 SkScalar x01 = SkScalarAve(src[0].fX, src[1].fX);
246 SkScalar y01 = SkScalarAve(src[0].fY, src[1].fY);
247 SkScalar x12 = SkScalarAve(src[1].fX, src[2].fX);
248 SkScalar y12 = SkScalarAve(src[1].fY, src[2].fY);
249 pt->set(SkScalarAve(x01, x12), SkScalarAve(y01, y12));
250 }
251 if (tangent)
252 tangent->set(eval_quad_derivative_at_half(&src[0].fX),
253 eval_quad_derivative_at_half(&src[0].fY));
254 }
255
interp_quad_coords(const SkScalar * src,SkScalar * dst,SkScalar t)256 static void interp_quad_coords(const SkScalar* src, SkScalar* dst, SkScalar t)
257 {
258 SkScalar ab = SkScalarInterp(src[0], src[2], t);
259 SkScalar bc = SkScalarInterp(src[2], src[4], t);
260
261 dst[0] = src[0];
262 dst[2] = ab;
263 dst[4] = SkScalarInterp(ab, bc, t);
264 dst[6] = bc;
265 dst[8] = src[4];
266 }
267
SkChopQuadAt(const SkPoint src[3],SkPoint dst[5],SkScalar t)268 void SkChopQuadAt(const SkPoint src[3], SkPoint dst[5], SkScalar t)
269 {
270 SkASSERT(t > 0 && t < SK_Scalar1);
271
272 interp_quad_coords(&src[0].fX, &dst[0].fX, t);
273 interp_quad_coords(&src[0].fY, &dst[0].fY, t);
274 }
275
SkChopQuadAtHalf(const SkPoint src[3],SkPoint dst[5])276 void SkChopQuadAtHalf(const SkPoint src[3], SkPoint dst[5])
277 {
278 SkScalar x01 = SkScalarAve(src[0].fX, src[1].fX);
279 SkScalar y01 = SkScalarAve(src[0].fY, src[1].fY);
280 SkScalar x12 = SkScalarAve(src[1].fX, src[2].fX);
281 SkScalar y12 = SkScalarAve(src[1].fY, src[2].fY);
282
283 dst[0] = src[0];
284 dst[1].set(x01, y01);
285 dst[2].set(SkScalarAve(x01, x12), SkScalarAve(y01, y12));
286 dst[3].set(x12, y12);
287 dst[4] = src[2];
288 }
289
290 /** Quad'(t) = At + B, where
291 A = 2(a - 2b + c)
292 B = 2(b - a)
293 Solve for t, only if it fits between 0 < t < 1
294 */
SkFindQuadExtrema(SkScalar a,SkScalar b,SkScalar c,SkScalar tValue[1])295 int SkFindQuadExtrema(SkScalar a, SkScalar b, SkScalar c, SkScalar tValue[1])
296 {
297 /* At + B == 0
298 t = -B / A
299 */
300 #ifdef SK_SCALAR_IS_FIXED
301 return is_not_monotonic(a, b, c) && valid_unit_divide(a - b, a - b - b + c, tValue);
302 #else
303 return valid_unit_divide(a - b, a - b - b + c, tValue);
304 #endif
305 }
306
flatten_double_quad_extrema(SkScalar coords[14])307 static inline void flatten_double_quad_extrema(SkScalar coords[14])
308 {
309 coords[2] = coords[6] = coords[4];
310 }
311
312 /* Returns 0 for 1 quad, and 1 for two quads, either way the answer is
313 stored in dst[]. Guarantees that the 1/2 quads will be monotonic.
314 */
SkChopQuadAtYExtrema(const SkPoint src[3],SkPoint dst[5])315 int SkChopQuadAtYExtrema(const SkPoint src[3], SkPoint dst[5])
316 {
317 SkASSERT(src);
318 SkASSERT(dst);
319
320 #if 0
321 static bool once = true;
322 if (once)
323 {
324 once = false;
325 SkPoint s[3] = { 0, 26398, 0, 26331, 0, 20621428 };
326 SkPoint d[6];
327
328 int n = SkChopQuadAtYExtrema(s, d);
329 SkDebugf("chop=%d, Y=[%x %x %x %x %x %x]\n", n, d[0].fY, d[1].fY, d[2].fY, d[3].fY, d[4].fY, d[5].fY);
330 }
331 #endif
332
333 SkScalar a = src[0].fY;
334 SkScalar b = src[1].fY;
335 SkScalar c = src[2].fY;
336
337 if (is_not_monotonic(a, b, c))
338 {
339 SkScalar tValue;
340 if (valid_unit_divide(a - b, a - b - b + c, &tValue))
341 {
342 SkChopQuadAt(src, dst, tValue);
343 flatten_double_quad_extrema(&dst[0].fY);
344 return 1;
345 }
346 // if we get here, we need to force dst to be monotonic, even though
347 // we couldn't compute a unit_divide value (probably underflow).
348 b = SkScalarAbs(a - b) < SkScalarAbs(b - c) ? a : c;
349 }
350 dst[0].set(src[0].fX, a);
351 dst[1].set(src[1].fX, b);
352 dst[2].set(src[2].fX, c);
353 return 0;
354 }
355
356 /* Returns 0 for 1 quad, and 1 for two quads, either way the answer is
357 stored in dst[]. Guarantees that the 1/2 quads will be monotonic.
358 */
SkChopQuadAtXExtrema(const SkPoint src[3],SkPoint dst[5])359 int SkChopQuadAtXExtrema(const SkPoint src[3], SkPoint dst[5])
360 {
361 SkASSERT(src);
362 SkASSERT(dst);
363
364 SkScalar a = src[0].fX;
365 SkScalar b = src[1].fX;
366 SkScalar c = src[2].fX;
367
368 if (is_not_monotonic(a, b, c)) {
369 SkScalar tValue;
370 if (valid_unit_divide(a - b, a - b - b + c, &tValue)) {
371 SkChopQuadAt(src, dst, tValue);
372 flatten_double_quad_extrema(&dst[0].fX);
373 return 1;
374 }
375 // if we get here, we need to force dst to be monotonic, even though
376 // we couldn't compute a unit_divide value (probably underflow).
377 b = SkScalarAbs(a - b) < SkScalarAbs(b - c) ? a : c;
378 }
379 dst[0].set(a, src[0].fY);
380 dst[1].set(b, src[1].fY);
381 dst[2].set(c, src[2].fY);
382 return 0;
383 }
384
385 // F(t) = a (1 - t) ^ 2 + 2 b t (1 - t) + c t ^ 2
386 // F'(t) = 2 (b - a) + 2 (a - 2b + c) t
387 // F''(t) = 2 (a - 2b + c)
388 //
389 // A = 2 (b - a)
390 // B = 2 (a - 2b + c)
391 //
392 // Maximum curvature for a quadratic means solving
393 // Fx' Fx'' + Fy' Fy'' = 0
394 //
395 // t = - (Ax Bx + Ay By) / (Bx ^ 2 + By ^ 2)
396 //
SkChopQuadAtMaxCurvature(const SkPoint src[3],SkPoint dst[5])397 int SkChopQuadAtMaxCurvature(const SkPoint src[3], SkPoint dst[5])
398 {
399 SkScalar Ax = src[1].fX - src[0].fX;
400 SkScalar Ay = src[1].fY - src[0].fY;
401 SkScalar Bx = src[0].fX - src[1].fX - src[1].fX + src[2].fX;
402 SkScalar By = src[0].fY - src[1].fY - src[1].fY + src[2].fY;
403 SkScalar t = 0; // 0 means don't chop
404
405 #ifdef SK_SCALAR_IS_FLOAT
406 (void)valid_unit_divide(-(Ax * Bx + Ay * By), Bx * Bx + By * By, &t);
407 #else
408 // !!! should I use SkFloat here? seems like it
409 Sk64 numer, denom, tmp;
410
411 numer.setMul(Ax, -Bx);
412 tmp.setMul(Ay, -By);
413 numer.add(tmp);
414
415 if (numer.isPos()) // do nothing if numer <= 0
416 {
417 denom.setMul(Bx, Bx);
418 tmp.setMul(By, By);
419 denom.add(tmp);
420 SkASSERT(!denom.isNeg());
421 if (numer < denom)
422 {
423 t = numer.getFixedDiv(denom);
424 SkASSERT(t >= 0 && t <= SK_Fixed1); // assert that we're numerically stable (ha!)
425 if ((unsigned)t >= SK_Fixed1) // runtime check for numerical stability
426 t = 0; // ignore the chop
427 }
428 }
429 #endif
430
431 if (t == 0)
432 {
433 memcpy(dst, src, 3 * sizeof(SkPoint));
434 return 1;
435 }
436 else
437 {
438 SkChopQuadAt(src, dst, t);
439 return 2;
440 }
441 }
442
443 #ifdef SK_SCALAR_IS_FLOAT
444 #define SK_ScalarTwoThirds (0.666666666f)
445 #else
446 #define SK_ScalarTwoThirds ((SkFixed)(43691))
447 #endif
448
SkConvertQuadToCubic(const SkPoint src[3],SkPoint dst[4])449 void SkConvertQuadToCubic(const SkPoint src[3], SkPoint dst[4]) {
450 const SkScalar scale = SK_ScalarTwoThirds;
451 dst[0] = src[0];
452 dst[1].set(src[0].fX + SkScalarMul(src[1].fX - src[0].fX, scale),
453 src[0].fY + SkScalarMul(src[1].fY - src[0].fY, scale));
454 dst[2].set(src[2].fX + SkScalarMul(src[1].fX - src[2].fX, scale),
455 src[2].fY + SkScalarMul(src[1].fY - src[2].fY, scale));
456 dst[3] = src[2];
457 }
458
459 ////////////////////////////////////////////////////////////////////////////////////////
460 ///// CUBICS // CUBICS // CUBICS // CUBICS // CUBICS // CUBICS // CUBICS // CUBICS /////
461 ////////////////////////////////////////////////////////////////////////////////////////
462
get_cubic_coeff(const SkScalar pt[],SkScalar coeff[4])463 static void get_cubic_coeff(const SkScalar pt[], SkScalar coeff[4])
464 {
465 coeff[0] = pt[6] + 3*(pt[2] - pt[4]) - pt[0];
466 coeff[1] = 3*(pt[4] - pt[2] - pt[2] + pt[0]);
467 coeff[2] = 3*(pt[2] - pt[0]);
468 coeff[3] = pt[0];
469 }
470
SkGetCubicCoeff(const SkPoint pts[4],SkScalar cx[4],SkScalar cy[4])471 void SkGetCubicCoeff(const SkPoint pts[4], SkScalar cx[4], SkScalar cy[4])
472 {
473 SkASSERT(pts);
474
475 if (cx)
476 get_cubic_coeff(&pts[0].fX, cx);
477 if (cy)
478 get_cubic_coeff(&pts[0].fY, cy);
479 }
480
eval_cubic(const SkScalar src[],SkScalar t)481 static SkScalar eval_cubic(const SkScalar src[], SkScalar t)
482 {
483 SkASSERT(src);
484 SkASSERT(t >= 0 && t <= SK_Scalar1);
485
486 if (t == 0)
487 return src[0];
488
489 #ifdef DIRECT_EVAL_OF_POLYNOMIALS
490 SkScalar D = src[0];
491 SkScalar A = src[6] + 3*(src[2] - src[4]) - D;
492 SkScalar B = 3*(src[4] - src[2] - src[2] + D);
493 SkScalar C = 3*(src[2] - D);
494
495 return SkScalarMulAdd(SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C), t, D);
496 #else
497 SkScalar ab = SkScalarInterp(src[0], src[2], t);
498 SkScalar bc = SkScalarInterp(src[2], src[4], t);
499 SkScalar cd = SkScalarInterp(src[4], src[6], t);
500 SkScalar abc = SkScalarInterp(ab, bc, t);
501 SkScalar bcd = SkScalarInterp(bc, cd, t);
502 return SkScalarInterp(abc, bcd, t);
503 #endif
504 }
505
506 /** return At^2 + Bt + C
507 */
eval_quadratic(SkScalar A,SkScalar B,SkScalar C,SkScalar t)508 static SkScalar eval_quadratic(SkScalar A, SkScalar B, SkScalar C, SkScalar t)
509 {
510 SkASSERT(t >= 0 && t <= SK_Scalar1);
511
512 return SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C);
513 }
514
eval_cubic_derivative(const SkScalar src[],SkScalar t)515 static SkScalar eval_cubic_derivative(const SkScalar src[], SkScalar t)
516 {
517 SkScalar A = src[6] + 3*(src[2] - src[4]) - src[0];
518 SkScalar B = 2*(src[4] - 2 * src[2] + src[0]);
519 SkScalar C = src[2] - src[0];
520
521 return eval_quadratic(A, B, C, t);
522 }
523
eval_cubic_2ndDerivative(const SkScalar src[],SkScalar t)524 static SkScalar eval_cubic_2ndDerivative(const SkScalar src[], SkScalar t)
525 {
526 SkScalar A = src[6] + 3*(src[2] - src[4]) - src[0];
527 SkScalar B = src[4] - 2 * src[2] + src[0];
528
529 return SkScalarMulAdd(A, t, B);
530 }
531
SkEvalCubicAt(const SkPoint src[4],SkScalar t,SkPoint * loc,SkVector * tangent,SkVector * curvature)532 void SkEvalCubicAt(const SkPoint src[4], SkScalar t, SkPoint* loc, SkVector* tangent, SkVector* curvature)
533 {
534 SkASSERT(src);
535 SkASSERT(t >= 0 && t <= SK_Scalar1);
536
537 if (loc)
538 loc->set(eval_cubic(&src[0].fX, t), eval_cubic(&src[0].fY, t));
539 if (tangent)
540 tangent->set(eval_cubic_derivative(&src[0].fX, t),
541 eval_cubic_derivative(&src[0].fY, t));
542 if (curvature)
543 curvature->set(eval_cubic_2ndDerivative(&src[0].fX, t),
544 eval_cubic_2ndDerivative(&src[0].fY, t));
545 }
546
547 /** Cubic'(t) = At^2 + Bt + C, where
548 A = 3(-a + 3(b - c) + d)
549 B = 6(a - 2b + c)
550 C = 3(b - a)
551 Solve for t, keeping only those that fit betwee 0 < t < 1
552 */
SkFindCubicExtrema(SkScalar a,SkScalar b,SkScalar c,SkScalar d,SkScalar tValues[2])553 int SkFindCubicExtrema(SkScalar a, SkScalar b, SkScalar c, SkScalar d, SkScalar tValues[2])
554 {
555 #ifdef SK_SCALAR_IS_FIXED
556 if (!is_not_monotonic(a, b, c, d))
557 return 0;
558 #endif
559
560 // we divide A,B,C by 3 to simplify
561 SkScalar A = d - a + 3*(b - c);
562 SkScalar B = 2*(a - b - b + c);
563 SkScalar C = b - a;
564
565 return SkFindUnitQuadRoots(A, B, C, tValues);
566 }
567
interp_cubic_coords(const SkScalar * src,SkScalar * dst,SkScalar t)568 static void interp_cubic_coords(const SkScalar* src, SkScalar* dst, SkScalar t)
569 {
570 SkScalar ab = SkScalarInterp(src[0], src[2], t);
571 SkScalar bc = SkScalarInterp(src[2], src[4], t);
572 SkScalar cd = SkScalarInterp(src[4], src[6], t);
573 SkScalar abc = SkScalarInterp(ab, bc, t);
574 SkScalar bcd = SkScalarInterp(bc, cd, t);
575 SkScalar abcd = SkScalarInterp(abc, bcd, t);
576
577 dst[0] = src[0];
578 dst[2] = ab;
579 dst[4] = abc;
580 dst[6] = abcd;
581 dst[8] = bcd;
582 dst[10] = cd;
583 dst[12] = src[6];
584 }
585
SkChopCubicAt(const SkPoint src[4],SkPoint dst[7],SkScalar t)586 void SkChopCubicAt(const SkPoint src[4], SkPoint dst[7], SkScalar t)
587 {
588 SkASSERT(t > 0 && t < SK_Scalar1);
589
590 interp_cubic_coords(&src[0].fX, &dst[0].fX, t);
591 interp_cubic_coords(&src[0].fY, &dst[0].fY, t);
592 }
593
594 /* http://code.google.com/p/skia/issues/detail?id=32
595
596 This test code would fail when we didn't check the return result of
597 valid_unit_divide in SkChopCubicAt(... tValues[], int roots). The reason is
598 that after the first chop, the parameters to valid_unit_divide are equal
599 (thanks to finite float precision and rounding in the subtracts). Thus
600 even though the 2nd tValue looks < 1.0, after we renormalize it, we end
601 up with 1.0, hence the need to check and just return the last cubic as
602 a degenerate clump of 4 points in the sampe place.
603
604 static void test_cubic() {
605 SkPoint src[4] = {
606 { 556.25000, 523.03003 },
607 { 556.23999, 522.96002 },
608 { 556.21997, 522.89001 },
609 { 556.21997, 522.82001 }
610 };
611 SkPoint dst[10];
612 SkScalar tval[] = { 0.33333334f, 0.99999994f };
613 SkChopCubicAt(src, dst, tval, 2);
614 }
615 */
616
SkChopCubicAt(const SkPoint src[4],SkPoint dst[],const SkScalar tValues[],int roots)617 void SkChopCubicAt(const SkPoint src[4], SkPoint dst[], const SkScalar tValues[], int roots)
618 {
619 #ifdef SK_DEBUG
620 {
621 for (int i = 0; i < roots - 1; i++)
622 {
623 SkASSERT(is_unit_interval(tValues[i]));
624 SkASSERT(is_unit_interval(tValues[i+1]));
625 SkASSERT(tValues[i] < tValues[i+1]);
626 }
627 }
628 #endif
629
630 if (dst)
631 {
632 if (roots == 0) // nothing to chop
633 memcpy(dst, src, 4*sizeof(SkPoint));
634 else
635 {
636 SkScalar t = tValues[0];
637 SkPoint tmp[4];
638
639 for (int i = 0; i < roots; i++)
640 {
641 SkChopCubicAt(src, dst, t);
642 if (i == roots - 1)
643 break;
644
645 dst += 3;
646 // have src point to the remaining cubic (after the chop)
647 memcpy(tmp, dst, 4 * sizeof(SkPoint));
648 src = tmp;
649
650 // watch out in case the renormalized t isn't in range
651 if (!valid_unit_divide(tValues[i+1] - tValues[i],
652 SK_Scalar1 - tValues[i], &t)) {
653 // if we can't, just create a degenerate cubic
654 dst[4] = dst[5] = dst[6] = src[3];
655 break;
656 }
657 }
658 }
659 }
660 }
661
SkChopCubicAtHalf(const SkPoint src[4],SkPoint dst[7])662 void SkChopCubicAtHalf(const SkPoint src[4], SkPoint dst[7])
663 {
664 SkScalar x01 = SkScalarAve(src[0].fX, src[1].fX);
665 SkScalar y01 = SkScalarAve(src[0].fY, src[1].fY);
666 SkScalar x12 = SkScalarAve(src[1].fX, src[2].fX);
667 SkScalar y12 = SkScalarAve(src[1].fY, src[2].fY);
668 SkScalar x23 = SkScalarAve(src[2].fX, src[3].fX);
669 SkScalar y23 = SkScalarAve(src[2].fY, src[3].fY);
670
671 SkScalar x012 = SkScalarAve(x01, x12);
672 SkScalar y012 = SkScalarAve(y01, y12);
673 SkScalar x123 = SkScalarAve(x12, x23);
674 SkScalar y123 = SkScalarAve(y12, y23);
675
676 dst[0] = src[0];
677 dst[1].set(x01, y01);
678 dst[2].set(x012, y012);
679 dst[3].set(SkScalarAve(x012, x123), SkScalarAve(y012, y123));
680 dst[4].set(x123, y123);
681 dst[5].set(x23, y23);
682 dst[6] = src[3];
683 }
684
flatten_double_cubic_extrema(SkScalar coords[14])685 static void flatten_double_cubic_extrema(SkScalar coords[14])
686 {
687 coords[4] = coords[8] = coords[6];
688 }
689
690 /** Given 4 points on a cubic bezier, chop it into 1, 2, 3 beziers such that
691 the resulting beziers are monotonic in Y. This is called by the scan converter.
692 Depending on what is returned, dst[] is treated as follows
693 0 dst[0..3] is the original cubic
694 1 dst[0..3] and dst[3..6] are the two new cubics
695 2 dst[0..3], dst[3..6], dst[6..9] are the three new cubics
696 If dst == null, it is ignored and only the count is returned.
697 */
SkChopCubicAtYExtrema(const SkPoint src[4],SkPoint dst[10])698 int SkChopCubicAtYExtrema(const SkPoint src[4], SkPoint dst[10]) {
699 SkScalar tValues[2];
700 int roots = SkFindCubicExtrema(src[0].fY, src[1].fY, src[2].fY,
701 src[3].fY, tValues);
702
703 SkChopCubicAt(src, dst, tValues, roots);
704 if (dst && roots > 0) {
705 // we do some cleanup to ensure our Y extrema are flat
706 flatten_double_cubic_extrema(&dst[0].fY);
707 if (roots == 2) {
708 flatten_double_cubic_extrema(&dst[3].fY);
709 }
710 }
711 return roots;
712 }
713
SkChopCubicAtXExtrema(const SkPoint src[4],SkPoint dst[10])714 int SkChopCubicAtXExtrema(const SkPoint src[4], SkPoint dst[10]) {
715 SkScalar tValues[2];
716 int roots = SkFindCubicExtrema(src[0].fX, src[1].fX, src[2].fX,
717 src[3].fX, tValues);
718
719 SkChopCubicAt(src, dst, tValues, roots);
720 if (dst && roots > 0) {
721 // we do some cleanup to ensure our Y extrema are flat
722 flatten_double_cubic_extrema(&dst[0].fX);
723 if (roots == 2) {
724 flatten_double_cubic_extrema(&dst[3].fX);
725 }
726 }
727 return roots;
728 }
729
730 /** http://www.faculty.idc.ac.il/arik/quality/appendixA.html
731
732 Inflection means that curvature is zero.
733 Curvature is [F' x F''] / [F'^3]
734 So we solve F'x X F''y - F'y X F''y == 0
735 After some canceling of the cubic term, we get
736 A = b - a
737 B = c - 2b + a
738 C = d - 3c + 3b - a
739 (BxCy - ByCx)t^2 + (AxCy - AyCx)t + AxBy - AyBx == 0
740 */
SkFindCubicInflections(const SkPoint src[4],SkScalar tValues[])741 int SkFindCubicInflections(const SkPoint src[4], SkScalar tValues[])
742 {
743 SkScalar Ax = src[1].fX - src[0].fX;
744 SkScalar Ay = src[1].fY - src[0].fY;
745 SkScalar Bx = src[2].fX - 2 * src[1].fX + src[0].fX;
746 SkScalar By = src[2].fY - 2 * src[1].fY + src[0].fY;
747 SkScalar Cx = src[3].fX + 3 * (src[1].fX - src[2].fX) - src[0].fX;
748 SkScalar Cy = src[3].fY + 3 * (src[1].fY - src[2].fY) - src[0].fY;
749 int count;
750
751 #ifdef SK_SCALAR_IS_FLOAT
752 count = SkFindUnitQuadRoots(Bx*Cy - By*Cx, Ax*Cy - Ay*Cx, Ax*By - Ay*Bx, tValues);
753 #else
754 Sk64 A, B, C, tmp;
755
756 A.setMul(Bx, Cy);
757 tmp.setMul(By, Cx);
758 A.sub(tmp);
759
760 B.setMul(Ax, Cy);
761 tmp.setMul(Ay, Cx);
762 B.sub(tmp);
763
764 C.setMul(Ax, By);
765 tmp.setMul(Ay, Bx);
766 C.sub(tmp);
767
768 count = Sk64FindFixedQuadRoots(A, B, C, tValues);
769 #endif
770
771 return count;
772 }
773
SkChopCubicAtInflections(const SkPoint src[],SkPoint dst[10])774 int SkChopCubicAtInflections(const SkPoint src[], SkPoint dst[10])
775 {
776 SkScalar tValues[2];
777 int count = SkFindCubicInflections(src, tValues);
778
779 if (dst)
780 {
781 if (count == 0)
782 memcpy(dst, src, 4 * sizeof(SkPoint));
783 else
784 SkChopCubicAt(src, dst, tValues, count);
785 }
786 return count + 1;
787 }
788
bubble_sort(T array[],int count)789 template <typename T> void bubble_sort(T array[], int count)
790 {
791 for (int i = count - 1; i > 0; --i)
792 for (int j = i; j > 0; --j)
793 if (array[j] < array[j-1])
794 {
795 T tmp(array[j]);
796 array[j] = array[j-1];
797 array[j-1] = tmp;
798 }
799 }
800
801 #include "SkFP.h"
802
803 // newton refinement
804 #if 0
805 static SkScalar refine_cubic_root(const SkFP coeff[4], SkScalar root)
806 {
807 // x1 = x0 - f(t) / f'(t)
808
809 SkFP T = SkScalarToFloat(root);
810 SkFP N, D;
811
812 // f' = 3*coeff[0]*T^2 + 2*coeff[1]*T + coeff[2]
813 D = SkFPMul(SkFPMul(coeff[0], SkFPMul(T,T)), 3);
814 D = SkFPAdd(D, SkFPMulInt(SkFPMul(coeff[1], T), 2));
815 D = SkFPAdd(D, coeff[2]);
816
817 if (D == 0)
818 return root;
819
820 // f = coeff[0]*T^3 + coeff[1]*T^2 + coeff[2]*T + coeff[3]
821 N = SkFPMul(SkFPMul(SkFPMul(T, T), T), coeff[0]);
822 N = SkFPAdd(N, SkFPMul(SkFPMul(T, T), coeff[1]));
823 N = SkFPAdd(N, SkFPMul(T, coeff[2]));
824 N = SkFPAdd(N, coeff[3]);
825
826 if (N)
827 {
828 SkScalar delta = SkFPToScalar(SkFPDiv(N, D));
829
830 if (delta)
831 root -= delta;
832 }
833 return root;
834 }
835 #endif
836
837 /**
838 * Given an array and count, remove all pair-wise duplicates from the array,
839 * keeping the existing sorting, and return the new count
840 */
collaps_duplicates(float array[],int count)841 static int collaps_duplicates(float array[], int count) {
842 int n = count;
843 for (int n = count; n > 1; --n) {
844 if (array[0] == array[1]) {
845 for (int i = 1; i < n; ++i) {
846 array[i - 1] = array[i];
847 }
848 count -= 1;
849 } else {
850 array += 1;
851 }
852 }
853 return count;
854 }
855
856 #ifdef SK_DEBUG
857
858 #define TEST_COLLAPS_ENTRY(array) array, SK_ARRAY_COUNT(array)
859
test_collaps_duplicates()860 static void test_collaps_duplicates() {
861 static bool gOnce;
862 if (gOnce) { return; }
863 gOnce = true;
864 const float src0[] = { 0 };
865 const float src1[] = { 0, 0 };
866 const float src2[] = { 0, 1 };
867 const float src3[] = { 0, 0, 0 };
868 const float src4[] = { 0, 0, 1 };
869 const float src5[] = { 0, 1, 1 };
870 const float src6[] = { 0, 1, 2 };
871 const struct {
872 const float* fData;
873 int fCount;
874 int fCollapsedCount;
875 } data[] = {
876 { TEST_COLLAPS_ENTRY(src0), 1 },
877 { TEST_COLLAPS_ENTRY(src1), 1 },
878 { TEST_COLLAPS_ENTRY(src2), 2 },
879 { TEST_COLLAPS_ENTRY(src3), 1 },
880 { TEST_COLLAPS_ENTRY(src4), 2 },
881 { TEST_COLLAPS_ENTRY(src5), 2 },
882 { TEST_COLLAPS_ENTRY(src6), 3 },
883 };
884 for (size_t i = 0; i < SK_ARRAY_COUNT(data); ++i) {
885 float dst[3];
886 memcpy(dst, data[i].fData, data[i].fCount * sizeof(dst[0]));
887 int count = collaps_duplicates(dst, data[i].fCount);
888 SkASSERT(data[i].fCollapsedCount == count);
889 for (int j = 1; j < count; ++j) {
890 SkASSERT(dst[j-1] < dst[j]);
891 }
892 }
893 }
894 #endif
895
896 #if defined _WIN32 && _MSC_VER >= 1300 && defined SK_SCALAR_IS_FIXED // disable warning : unreachable code if building fixed point for windows desktop
897 #pragma warning ( disable : 4702 )
898 #endif
899
900 /* Solve coeff(t) == 0, returning the number of roots that
901 lie withing 0 < t < 1.
902 coeff[0]t^3 + coeff[1]t^2 + coeff[2]t + coeff[3]
903
904 Eliminates repeated roots (so that all tValues are distinct, and are always
905 in increasing order.
906 */
solve_cubic_polynomial(const SkFP coeff[4],SkScalar tValues[3])907 static int solve_cubic_polynomial(const SkFP coeff[4], SkScalar tValues[3])
908 {
909 #ifndef SK_SCALAR_IS_FLOAT
910 return 0; // this is not yet implemented for software float
911 #endif
912
913 if (SkScalarNearlyZero(coeff[0])) // we're just a quadratic
914 {
915 return SkFindUnitQuadRoots(coeff[1], coeff[2], coeff[3], tValues);
916 }
917
918 SkFP a, b, c, Q, R;
919
920 {
921 SkASSERT(coeff[0] != 0);
922
923 SkFP inva = SkFPInvert(coeff[0]);
924 a = SkFPMul(coeff[1], inva);
925 b = SkFPMul(coeff[2], inva);
926 c = SkFPMul(coeff[3], inva);
927 }
928 Q = SkFPDivInt(SkFPSub(SkFPMul(a,a), SkFPMulInt(b, 3)), 9);
929 // R = (2*a*a*a - 9*a*b + 27*c) / 54;
930 R = SkFPMulInt(SkFPMul(SkFPMul(a, a), a), 2);
931 R = SkFPSub(R, SkFPMulInt(SkFPMul(a, b), 9));
932 R = SkFPAdd(R, SkFPMulInt(c, 27));
933 R = SkFPDivInt(R, 54);
934
935 SkFP Q3 = SkFPMul(SkFPMul(Q, Q), Q);
936 SkFP R2MinusQ3 = SkFPSub(SkFPMul(R,R), Q3);
937 SkFP adiv3 = SkFPDivInt(a, 3);
938
939 SkScalar* roots = tValues;
940 SkScalar r;
941
942 if (SkFPLT(R2MinusQ3, 0)) // we have 3 real roots
943 {
944 #ifdef SK_SCALAR_IS_FLOAT
945 float theta = sk_float_acos(R / sk_float_sqrt(Q3));
946 float neg2RootQ = -2 * sk_float_sqrt(Q);
947
948 r = neg2RootQ * sk_float_cos(theta/3) - adiv3;
949 if (is_unit_interval(r))
950 *roots++ = r;
951
952 r = neg2RootQ * sk_float_cos((theta + 2*SK_ScalarPI)/3) - adiv3;
953 if (is_unit_interval(r))
954 *roots++ = r;
955
956 r = neg2RootQ * sk_float_cos((theta - 2*SK_ScalarPI)/3) - adiv3;
957 if (is_unit_interval(r))
958 *roots++ = r;
959
960 SkDEBUGCODE(test_collaps_duplicates();)
961
962 // now sort the roots
963 int count = (int)(roots - tValues);
964 SkASSERT((unsigned)count <= 3);
965 bubble_sort(tValues, count);
966 count = collaps_duplicates(tValues, count);
967 roots = tValues + count; // so we compute the proper count below
968 #endif
969 }
970 else // we have 1 real root
971 {
972 SkFP A = SkFPAdd(SkFPAbs(R), SkFPSqrt(R2MinusQ3));
973 A = SkFPCubeRoot(A);
974 if (SkFPGT(R, 0))
975 A = SkFPNeg(A);
976
977 if (A != 0)
978 A = SkFPAdd(A, SkFPDiv(Q, A));
979 r = SkFPToScalar(SkFPSub(A, adiv3));
980 if (is_unit_interval(r))
981 *roots++ = r;
982 }
983
984 return (int)(roots - tValues);
985 }
986
987 /* Looking for F' dot F'' == 0
988
989 A = b - a
990 B = c - 2b + a
991 C = d - 3c + 3b - a
992
993 F' = 3Ct^2 + 6Bt + 3A
994 F'' = 6Ct + 6B
995
996 F' dot F'' -> CCt^3 + 3BCt^2 + (2BB + CA)t + AB
997 */
formulate_F1DotF2(const SkScalar src[],SkFP coeff[4])998 static void formulate_F1DotF2(const SkScalar src[], SkFP coeff[4])
999 {
1000 SkScalar a = src[2] - src[0];
1001 SkScalar b = src[4] - 2 * src[2] + src[0];
1002 SkScalar c = src[6] + 3 * (src[2] - src[4]) - src[0];
1003
1004 SkFP A = SkScalarToFP(a);
1005 SkFP B = SkScalarToFP(b);
1006 SkFP C = SkScalarToFP(c);
1007
1008 coeff[0] = SkFPMul(C, C);
1009 coeff[1] = SkFPMulInt(SkFPMul(B, C), 3);
1010 coeff[2] = SkFPMulInt(SkFPMul(B, B), 2);
1011 coeff[2] = SkFPAdd(coeff[2], SkFPMul(C, A));
1012 coeff[3] = SkFPMul(A, B);
1013 }
1014
1015 // EXPERIMENTAL: can set this to zero to accept all t-values 0 < t < 1
1016 //#define kMinTValueForChopping (SK_Scalar1 / 256)
1017 #define kMinTValueForChopping 0
1018
1019 /* Looking for F' dot F'' == 0
1020
1021 A = b - a
1022 B = c - 2b + a
1023 C = d - 3c + 3b - a
1024
1025 F' = 3Ct^2 + 6Bt + 3A
1026 F'' = 6Ct + 6B
1027
1028 F' dot F'' -> CCt^3 + 3BCt^2 + (2BB + CA)t + AB
1029 */
SkFindCubicMaxCurvature(const SkPoint src[4],SkScalar tValues[3])1030 int SkFindCubicMaxCurvature(const SkPoint src[4], SkScalar tValues[3])
1031 {
1032 SkFP coeffX[4], coeffY[4];
1033 int i;
1034
1035 formulate_F1DotF2(&src[0].fX, coeffX);
1036 formulate_F1DotF2(&src[0].fY, coeffY);
1037
1038 for (i = 0; i < 4; i++)
1039 coeffX[i] = SkFPAdd(coeffX[i],coeffY[i]);
1040
1041 SkScalar t[3];
1042 int count = solve_cubic_polynomial(coeffX, t);
1043 int maxCount = 0;
1044
1045 // now remove extrema where the curvature is zero (mins)
1046 // !!!! need a test for this !!!!
1047 for (i = 0; i < count; i++)
1048 {
1049 // if (not_min_curvature())
1050 if (t[i] > kMinTValueForChopping && t[i] < SK_Scalar1 - kMinTValueForChopping)
1051 tValues[maxCount++] = t[i];
1052 }
1053 return maxCount;
1054 }
1055
SkChopCubicAtMaxCurvature(const SkPoint src[4],SkPoint dst[13],SkScalar tValues[3])1056 int SkChopCubicAtMaxCurvature(const SkPoint src[4], SkPoint dst[13], SkScalar tValues[3])
1057 {
1058 SkScalar t_storage[3];
1059
1060 if (tValues == NULL)
1061 tValues = t_storage;
1062
1063 int count = SkFindCubicMaxCurvature(src, tValues);
1064
1065 if (dst)
1066 {
1067 if (count == 0)
1068 memcpy(dst, src, 4 * sizeof(SkPoint));
1069 else
1070 SkChopCubicAt(src, dst, tValues, count);
1071 }
1072 return count + 1;
1073 }
1074
SkXRayCrossesMonotonicCubic(const SkXRay & pt,const SkPoint cubic[4],bool * ambiguous)1075 bool SkXRayCrossesMonotonicCubic(const SkXRay& pt, const SkPoint cubic[4], bool* ambiguous) {
1076 if (ambiguous) {
1077 *ambiguous = false;
1078 }
1079
1080 // Find the minimum and maximum y of the extrema, which are the
1081 // first and last points since this cubic is monotonic
1082 SkScalar min_y = SkMinScalar(cubic[0].fY, cubic[3].fY);
1083 SkScalar max_y = SkMaxScalar(cubic[0].fY, cubic[3].fY);
1084
1085 if (pt.fY == cubic[0].fY
1086 || pt.fY < min_y
1087 || pt.fY > max_y) {
1088 // The query line definitely does not cross the curve
1089 if (ambiguous) {
1090 *ambiguous = (pt.fY == cubic[0].fY);
1091 }
1092 return false;
1093 }
1094
1095 bool pt_at_extremum = (pt.fY == cubic[3].fY);
1096
1097 SkScalar min_x =
1098 SkMinScalar(
1099 SkMinScalar(
1100 SkMinScalar(cubic[0].fX, cubic[1].fX),
1101 cubic[2].fX),
1102 cubic[3].fX);
1103 if (pt.fX < min_x) {
1104 // The query line definitely crosses the curve
1105 if (ambiguous) {
1106 *ambiguous = pt_at_extremum;
1107 }
1108 return true;
1109 }
1110
1111 SkScalar max_x =
1112 SkMaxScalar(
1113 SkMaxScalar(
1114 SkMaxScalar(cubic[0].fX, cubic[1].fX),
1115 cubic[2].fX),
1116 cubic[3].fX);
1117 if (pt.fX > max_x) {
1118 // The query line definitely does not cross the curve
1119 return false;
1120 }
1121
1122 // Do a binary search to find the parameter value which makes y as
1123 // close as possible to the query point. See whether the query
1124 // line's origin is to the left of the associated x coordinate.
1125
1126 // kMaxIter is chosen as the number of mantissa bits for a float,
1127 // since there's no way we are going to get more precision by
1128 // iterating more times than that.
1129 const int kMaxIter = 23;
1130 SkPoint eval;
1131 int iter = 0;
1132 SkScalar upper_t;
1133 SkScalar lower_t;
1134 // Need to invert direction of t parameter if cubic goes up
1135 // instead of down
1136 if (cubic[3].fY > cubic[0].fY) {
1137 upper_t = SK_Scalar1;
1138 lower_t = SkFloatToScalar(0);
1139 } else {
1140 upper_t = SkFloatToScalar(0);
1141 lower_t = SK_Scalar1;
1142 }
1143 do {
1144 SkScalar t = SkScalarAve(upper_t, lower_t);
1145 SkEvalCubicAt(cubic, t, &eval, NULL, NULL);
1146 if (pt.fY > eval.fY) {
1147 lower_t = t;
1148 } else {
1149 upper_t = t;
1150 }
1151 } while (++iter < kMaxIter
1152 && !SkScalarNearlyZero(eval.fY - pt.fY));
1153 if (pt.fX <= eval.fX) {
1154 if (ambiguous) {
1155 *ambiguous = pt_at_extremum;
1156 }
1157 return true;
1158 }
1159 return false;
1160 }
1161
SkNumXRayCrossingsForCubic(const SkXRay & pt,const SkPoint cubic[4],bool * ambiguous)1162 int SkNumXRayCrossingsForCubic(const SkXRay& pt, const SkPoint cubic[4], bool* ambiguous) {
1163 int num_crossings = 0;
1164 SkPoint monotonic_cubics[10];
1165 int num_monotonic_cubics = SkChopCubicAtYExtrema(cubic, monotonic_cubics);
1166 if (ambiguous) {
1167 *ambiguous = false;
1168 }
1169 bool locally_ambiguous;
1170 if (SkXRayCrossesMonotonicCubic(pt, &monotonic_cubics[0], &locally_ambiguous))
1171 ++num_crossings;
1172 if (ambiguous) {
1173 *ambiguous |= locally_ambiguous;
1174 }
1175 if (num_monotonic_cubics > 0)
1176 if (SkXRayCrossesMonotonicCubic(pt, &monotonic_cubics[3], &locally_ambiguous))
1177 ++num_crossings;
1178 if (ambiguous) {
1179 *ambiguous |= locally_ambiguous;
1180 }
1181 if (num_monotonic_cubics > 1)
1182 if (SkXRayCrossesMonotonicCubic(pt, &monotonic_cubics[6], &locally_ambiguous))
1183 ++num_crossings;
1184 if (ambiguous) {
1185 *ambiguous |= locally_ambiguous;
1186 }
1187 return num_crossings;
1188 }
1189
1190 ////////////////////////////////////////////////////////////////////////////////
1191
1192 /* Find t value for quadratic [a, b, c] = d.
1193 Return 0 if there is no solution within [0, 1)
1194 */
quad_solve(SkScalar a,SkScalar b,SkScalar c,SkScalar d)1195 static SkScalar quad_solve(SkScalar a, SkScalar b, SkScalar c, SkScalar d)
1196 {
1197 // At^2 + Bt + C = d
1198 SkScalar A = a - 2 * b + c;
1199 SkScalar B = 2 * (b - a);
1200 SkScalar C = a - d;
1201
1202 SkScalar roots[2];
1203 int count = SkFindUnitQuadRoots(A, B, C, roots);
1204
1205 SkASSERT(count <= 1);
1206 return count == 1 ? roots[0] : 0;
1207 }
1208
1209 /* given a quad-curve and a point (x,y), chop the quad at that point and return
1210 the new quad's offCurve point. Should only return false if the computed pos
1211 is the start of the curve (i.e. root == 0)
1212 */
quad_pt2OffCurve(const SkPoint quad[3],SkScalar x,SkScalar y,SkPoint * offCurve)1213 static bool quad_pt2OffCurve(const SkPoint quad[3], SkScalar x, SkScalar y, SkPoint* offCurve)
1214 {
1215 const SkScalar* base;
1216 SkScalar value;
1217
1218 if (SkScalarAbs(x) < SkScalarAbs(y)) {
1219 base = &quad[0].fX;
1220 value = x;
1221 } else {
1222 base = &quad[0].fY;
1223 value = y;
1224 }
1225
1226 // note: this returns 0 if it thinks value is out of range, meaning the
1227 // root might return something outside of [0, 1)
1228 SkScalar t = quad_solve(base[0], base[2], base[4], value);
1229
1230 if (t > 0)
1231 {
1232 SkPoint tmp[5];
1233 SkChopQuadAt(quad, tmp, t);
1234 *offCurve = tmp[1];
1235 return true;
1236 } else {
1237 /* t == 0 means either the value triggered a root outside of [0, 1)
1238 For our purposes, we can ignore the <= 0 roots, but we want to
1239 catch the >= 1 roots (which given our caller, will basically mean
1240 a root of 1, give-or-take numerical instability). If we are in the
1241 >= 1 case, return the existing offCurve point.
1242
1243 The test below checks to see if we are close to the "end" of the
1244 curve (near base[4]). Rather than specifying a tolerance, I just
1245 check to see if value is on to the right/left of the middle point
1246 (depending on the direction/sign of the end points).
1247 */
1248 if ((base[0] < base[4] && value > base[2]) ||
1249 (base[0] > base[4] && value < base[2])) // should root have been 1
1250 {
1251 *offCurve = quad[1];
1252 return true;
1253 }
1254 }
1255 return false;
1256 }
1257
1258 static const SkPoint gQuadCirclePts[kSkBuildQuadArcStorage] = {
1259 { SK_Scalar1, 0 },
1260 { SK_Scalar1, SK_ScalarTanPIOver8 },
1261 { SK_ScalarRoot2Over2, SK_ScalarRoot2Over2 },
1262 { SK_ScalarTanPIOver8, SK_Scalar1 },
1263
1264 { 0, SK_Scalar1 },
1265 { -SK_ScalarTanPIOver8, SK_Scalar1 },
1266 { -SK_ScalarRoot2Over2, SK_ScalarRoot2Over2 },
1267 { -SK_Scalar1, SK_ScalarTanPIOver8 },
1268
1269 { -SK_Scalar1, 0 },
1270 { -SK_Scalar1, -SK_ScalarTanPIOver8 },
1271 { -SK_ScalarRoot2Over2, -SK_ScalarRoot2Over2 },
1272 { -SK_ScalarTanPIOver8, -SK_Scalar1 },
1273
1274 { 0, -SK_Scalar1 },
1275 { SK_ScalarTanPIOver8, -SK_Scalar1 },
1276 { SK_ScalarRoot2Over2, -SK_ScalarRoot2Over2 },
1277 { SK_Scalar1, -SK_ScalarTanPIOver8 },
1278
1279 { SK_Scalar1, 0 }
1280 };
1281
SkBuildQuadArc(const SkVector & uStart,const SkVector & uStop,SkRotationDirection dir,const SkMatrix * userMatrix,SkPoint quadPoints[])1282 int SkBuildQuadArc(const SkVector& uStart, const SkVector& uStop,
1283 SkRotationDirection dir, const SkMatrix* userMatrix,
1284 SkPoint quadPoints[])
1285 {
1286 // rotate by x,y so that uStart is (1.0)
1287 SkScalar x = SkPoint::DotProduct(uStart, uStop);
1288 SkScalar y = SkPoint::CrossProduct(uStart, uStop);
1289
1290 SkScalar absX = SkScalarAbs(x);
1291 SkScalar absY = SkScalarAbs(y);
1292
1293 int pointCount;
1294
1295 // check for (effectively) coincident vectors
1296 // this can happen if our angle is nearly 0 or nearly 180 (y == 0)
1297 // ... we use the dot-prod to distinguish between 0 and 180 (x > 0)
1298 if (absY <= SK_ScalarNearlyZero && x > 0 &&
1299 ((y >= 0 && kCW_SkRotationDirection == dir) ||
1300 (y <= 0 && kCCW_SkRotationDirection == dir))) {
1301
1302 // just return the start-point
1303 quadPoints[0].set(SK_Scalar1, 0);
1304 pointCount = 1;
1305 } else {
1306 if (dir == kCCW_SkRotationDirection)
1307 y = -y;
1308
1309 // what octant (quadratic curve) is [xy] in?
1310 int oct = 0;
1311 bool sameSign = true;
1312
1313 if (0 == y)
1314 {
1315 oct = 4; // 180
1316 SkASSERT(SkScalarAbs(x + SK_Scalar1) <= SK_ScalarNearlyZero);
1317 }
1318 else if (0 == x)
1319 {
1320 SkASSERT(absY - SK_Scalar1 <= SK_ScalarNearlyZero);
1321 if (y > 0)
1322 oct = 2; // 90
1323 else
1324 oct = 6; // 270
1325 }
1326 else
1327 {
1328 if (y < 0)
1329 oct += 4;
1330 if ((x < 0) != (y < 0))
1331 {
1332 oct += 2;
1333 sameSign = false;
1334 }
1335 if ((absX < absY) == sameSign)
1336 oct += 1;
1337 }
1338
1339 int wholeCount = oct << 1;
1340 memcpy(quadPoints, gQuadCirclePts, (wholeCount + 1) * sizeof(SkPoint));
1341
1342 const SkPoint* arc = &gQuadCirclePts[wholeCount];
1343 if (quad_pt2OffCurve(arc, x, y, &quadPoints[wholeCount + 1]))
1344 {
1345 quadPoints[wholeCount + 2].set(x, y);
1346 wholeCount += 2;
1347 }
1348 pointCount = wholeCount + 1;
1349 }
1350
1351 // now handle counter-clockwise and the initial unitStart rotation
1352 SkMatrix matrix;
1353 matrix.setSinCos(uStart.fY, uStart.fX);
1354 if (dir == kCCW_SkRotationDirection) {
1355 matrix.preScale(SK_Scalar1, -SK_Scalar1);
1356 }
1357 if (userMatrix) {
1358 matrix.postConcat(*userMatrix);
1359 }
1360 matrix.mapPoints(quadPoints, pointCount);
1361 return pointCount;
1362 }
1363
1364