OLD | NEW |
1 | 1 |
2 /* | 2 /* |
3 * Copyright 2006 The Android Open Source Project | 3 * Copyright 2006 The Android Open Source Project |
4 * | 4 * |
5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
7 */ | 7 */ |
8 | 8 |
9 | 9 |
10 #include "SkGeometry.h" | 10 #include "SkGeometry.h" |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
61 SkScalar b = pts[0].fY - SkScalarMul(slope, pts[0].fX); | 61 SkScalar b = pts[0].fY - SkScalarMul(slope, pts[0].fX); |
62 // Solve for x coordinate at y = pt.fY | 62 // Solve for x coordinate at y = pt.fY |
63 SkScalar x = SkScalarDiv(pt.fY - b, slope); | 63 SkScalar x = SkScalarDiv(pt.fY - b, slope); |
64 return pt.fX <= x; | 64 return pt.fX <= x; |
65 } | 65 } |
66 | 66 |
67 /** If defined, this makes eval_quad and eval_cubic do more setup (sometimes | 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. | 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. | 69 May also introduce overflow of fixed when we compute our setup. |
70 */ | 70 */ |
71 #ifdef SK_SCALAR_IS_FIXED | 71 // #define DIRECT_EVAL_OF_POLYNOMIALS |
72 #define DIRECT_EVAL_OF_POLYNOMIALS | |
73 #endif | |
74 | 72 |
75 //////////////////////////////////////////////////////////////////////// | 73 //////////////////////////////////////////////////////////////////////// |
76 | 74 |
77 #ifdef SK_SCALAR_IS_FIXED | 75 static int is_not_monotonic(float a, float b, float c) { |
78 static int is_not_monotonic(int a, int b, int c, int d) | 76 float ab = a - b; |
79 { | 77 float bc = b - c; |
80 return (((a - b) | (b - c) | (c - d)) & ((b - a) | (c - b) | (d - c))) >
> 31; | 78 if (ab < 0) { |
| 79 bc = -bc; |
81 } | 80 } |
82 | 81 return ab == 0 || bc < 0; |
83 static int is_not_monotonic(int a, int b, int c) | 82 } |
84 { | |
85 return (((a - b) | (b - c)) & ((b - a) | (c - b))) >> 31; | |
86 } | |
87 #else | |
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 | 83 |
98 //////////////////////////////////////////////////////////////////////// | 84 //////////////////////////////////////////////////////////////////////// |
99 | 85 |
100 static bool is_unit_interval(SkScalar x) | 86 static bool is_unit_interval(SkScalar x) |
101 { | 87 { |
102 return x > 0 && x < SK_Scalar1; | 88 return x > 0 && x < SK_Scalar1; |
103 } | 89 } |
104 | 90 |
105 static int valid_unit_divide(SkScalar numer, SkScalar denom, SkScalar* ratio) | 91 static int valid_unit_divide(SkScalar numer, SkScalar denom, SkScalar* ratio) |
106 { | 92 { |
(...skipping 27 matching lines...) Expand all Loading... |
134 */ | 120 */ |
135 int SkFindUnitQuadRoots(SkScalar A, SkScalar B, SkScalar C, SkScalar roots[2]) | 121 int SkFindUnitQuadRoots(SkScalar A, SkScalar B, SkScalar C, SkScalar roots[2]) |
136 { | 122 { |
137 SkASSERT(roots); | 123 SkASSERT(roots); |
138 | 124 |
139 if (A == 0) | 125 if (A == 0) |
140 return valid_unit_divide(-C, B, roots); | 126 return valid_unit_divide(-C, B, roots); |
141 | 127 |
142 SkScalar* r = roots; | 128 SkScalar* r = roots; |
143 | 129 |
144 #ifdef SK_SCALAR_IS_FLOAT | |
145 float R = B*B - 4*A*C; | 130 float R = B*B - 4*A*C; |
146 if (R < 0 || SkScalarIsNaN(R)) { // complex roots | 131 if (R < 0 || SkScalarIsNaN(R)) { // complex roots |
147 return 0; | 132 return 0; |
148 } | 133 } |
149 R = sk_float_sqrt(R); | 134 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 | 135 |
162 SkScalar Q = (B < 0) ? -(B-R)/2 : -(B+R)/2; | 136 SkScalar Q = (B < 0) ? -(B-R)/2 : -(B+R)/2; |
163 r += valid_unit_divide(Q, A, r); | 137 r += valid_unit_divide(Q, A, r); |
164 r += valid_unit_divide(C, Q, r); | 138 r += valid_unit_divide(C, Q, r); |
165 if (r - roots == 2) | 139 if (r - roots == 2) |
166 { | 140 { |
167 if (roots[0] > roots[1]) | 141 if (roots[0] > roots[1]) |
168 SkTSwap<SkScalar>(roots[0], roots[1]); | 142 SkTSwap<SkScalar>(roots[0], roots[1]); |
169 else if (roots[0] == roots[1]) // nearly-equal? | 143 else if (roots[0] == roots[1]) // nearly-equal? |
170 r -= 1; // skip the double root | 144 r -= 1; // skip the double root |
171 } | 145 } |
172 return (int)(r - roots); | 146 return (int)(r - roots); |
173 } | 147 } |
174 | 148 |
175 #ifdef SK_SCALAR_IS_FIXED | 149 /////////////////////////////////////////////////////////////////////////////// |
176 /** Trim A/B/C down so that they are all <= 32bits | 150 /////////////////////////////////////////////////////////////////////////////// |
177 and then call SkFindUnitQuadRoots() | |
178 */ | |
179 static int Sk64FindFixedQuadRoots(const Sk64& A, const Sk64& B, const Sk64& C, S
kFixed 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 | 151 |
195 static SkScalar eval_quad(const SkScalar src[], SkScalar t) | 152 static SkScalar eval_quad(const SkScalar src[], SkScalar t) |
196 { | 153 { |
197 SkASSERT(src); | 154 SkASSERT(src); |
198 SkASSERT(t >= 0 && t <= SK_Scalar1); | 155 SkASSERT(t >= 0 && t <= SK_Scalar1); |
199 | 156 |
200 #ifdef DIRECT_EVAL_OF_POLYNOMIALS | 157 #ifdef DIRECT_EVAL_OF_POLYNOMIALS |
201 SkScalar C = src[0]; | 158 SkScalar C = src[0]; |
202 SkScalar A = src[4] - 2 * src[2] + C; | 159 SkScalar A = src[4] - 2 * src[2] + C; |
203 SkScalar B = 2 * (src[2] - C); | 160 SkScalar B = 2 * (src[2] - C); |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
290 /** Quad'(t) = At + B, where | 247 /** Quad'(t) = At + B, where |
291 A = 2(a - 2b + c) | 248 A = 2(a - 2b + c) |
292 B = 2(b - a) | 249 B = 2(b - a) |
293 Solve for t, only if it fits between 0 < t < 1 | 250 Solve for t, only if it fits between 0 < t < 1 |
294 */ | 251 */ |
295 int SkFindQuadExtrema(SkScalar a, SkScalar b, SkScalar c, SkScalar tValue[1]) | 252 int SkFindQuadExtrema(SkScalar a, SkScalar b, SkScalar c, SkScalar tValue[1]) |
296 { | 253 { |
297 /* At + B == 0 | 254 /* At + B == 0 |
298 t = -B / A | 255 t = -B / A |
299 */ | 256 */ |
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); | 257 return valid_unit_divide(a - b, a - b - b + c, tValue); |
304 #endif | |
305 } | 258 } |
306 | 259 |
307 static inline void flatten_double_quad_extrema(SkScalar coords[14]) | 260 static inline void flatten_double_quad_extrema(SkScalar coords[14]) |
308 { | 261 { |
309 coords[2] = coords[6] = coords[4]; | 262 coords[2] = coords[6] = coords[4]; |
310 } | 263 } |
311 | 264 |
312 /* Returns 0 for 1 quad, and 1 for two quads, either way the answer is | 265 /* 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. | 266 stored in dst[]. Guarantees that the 1/2 quads will be monotonic. |
314 */ | 267 */ |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
394 // | 347 // |
395 // t = - (Ax Bx + Ay By) / (Bx ^ 2 + By ^ 2) | 348 // t = - (Ax Bx + Ay By) / (Bx ^ 2 + By ^ 2) |
396 // | 349 // |
397 float SkFindQuadMaxCurvature(const SkPoint src[3]) { | 350 float SkFindQuadMaxCurvature(const SkPoint src[3]) { |
398 SkScalar Ax = src[1].fX - src[0].fX; | 351 SkScalar Ax = src[1].fX - src[0].fX; |
399 SkScalar Ay = src[1].fY - src[0].fY; | 352 SkScalar Ay = src[1].fY - src[0].fY; |
400 SkScalar Bx = src[0].fX - src[1].fX - src[1].fX + src[2].fX; | 353 SkScalar Bx = src[0].fX - src[1].fX - src[1].fX + src[2].fX; |
401 SkScalar By = src[0].fY - src[1].fY - src[1].fY + src[2].fY; | 354 SkScalar By = src[0].fY - src[1].fY - src[1].fY + src[2].fY; |
402 SkScalar t = 0; // 0 means don't chop | 355 SkScalar t = 0; // 0 means don't chop |
403 | 356 |
404 #ifdef SK_SCALAR_IS_FLOAT | |
405 (void)valid_unit_divide(-(Ax * Bx + Ay * By), Bx * Bx + By * By, &t); | 357 (void)valid_unit_divide(-(Ax * Bx + Ay * By), Bx * Bx + By * By, &t); |
406 #else | |
407 // !!! should I use SkFloat here? seems like it | |
408 Sk64 numer, denom, tmp; | |
409 | |
410 numer.setMul(Ax, -Bx); | |
411 tmp.setMul(Ay, -By); | |
412 numer.add(tmp); | |
413 | |
414 if (numer.isPos()) // do nothing if numer <= 0 | |
415 { | |
416 denom.setMul(Bx, Bx); | |
417 tmp.setMul(By, By); | |
418 denom.add(tmp); | |
419 SkASSERT(!denom.isNeg()); | |
420 if (numer < denom) | |
421 { | |
422 t = numer.getFixedDiv(denom); | |
423 SkASSERT(t >= 0 && t <= SK_Fixed1); // assert that we're numeric
ally stable (ha!) | |
424 if ((unsigned)t >= SK_Fixed1) // runtime check for numeric
al stability | |
425 t = 0; // ignore the chop | |
426 } | |
427 } | |
428 #endif | |
429 return t; | 358 return t; |
430 } | 359 } |
431 | 360 |
432 int SkChopQuadAtMaxCurvature(const SkPoint src[3], SkPoint dst[5]) | 361 int SkChopQuadAtMaxCurvature(const SkPoint src[3], SkPoint dst[5]) |
433 { | 362 { |
434 SkScalar t = SkFindQuadMaxCurvature(src); | 363 SkScalar t = SkFindQuadMaxCurvature(src); |
435 if (t == 0) { | 364 if (t == 0) { |
436 memcpy(dst, src, 3 * sizeof(SkPoint)); | 365 memcpy(dst, src, 3 * sizeof(SkPoint)); |
437 return 1; | 366 return 1; |
438 } else { | 367 } else { |
439 SkChopQuadAt(src, dst, t); | 368 SkChopQuadAt(src, dst, t); |
440 return 2; | 369 return 2; |
441 } | 370 } |
442 } | 371 } |
443 | 372 |
444 #ifdef SK_SCALAR_IS_FLOAT | 373 #define SK_ScalarTwoThirds (0.666666666f) |
445 #define SK_ScalarTwoThirds (0.666666666f) | |
446 #else | |
447 #define SK_ScalarTwoThirds ((SkFixed)(43691)) | |
448 #endif | |
449 | 374 |
450 void SkConvertQuadToCubic(const SkPoint src[3], SkPoint dst[4]) { | 375 void SkConvertQuadToCubic(const SkPoint src[3], SkPoint dst[4]) { |
451 const SkScalar scale = SK_ScalarTwoThirds; | 376 const SkScalar scale = SK_ScalarTwoThirds; |
452 dst[0] = src[0]; | 377 dst[0] = src[0]; |
453 dst[1].set(src[0].fX + SkScalarMul(src[1].fX - src[0].fX, scale), | 378 dst[1].set(src[0].fX + SkScalarMul(src[1].fX - src[0].fX, scale), |
454 src[0].fY + SkScalarMul(src[1].fY - src[0].fY, scale)); | 379 src[0].fY + SkScalarMul(src[1].fY - src[0].fY, scale)); |
455 dst[2].set(src[2].fX + SkScalarMul(src[1].fX - src[2].fX, scale), | 380 dst[2].set(src[2].fX + SkScalarMul(src[1].fX - src[2].fX, scale), |
456 src[2].fY + SkScalarMul(src[1].fY - src[2].fY, scale)); | 381 src[2].fY + SkScalarMul(src[1].fY - src[2].fY, scale)); |
457 dst[3] = src[2]; | 382 dst[3] = src[2]; |
458 } | 383 } |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
546 } | 471 } |
547 | 472 |
548 /** Cubic'(t) = At^2 + Bt + C, where | 473 /** Cubic'(t) = At^2 + Bt + C, where |
549 A = 3(-a + 3(b - c) + d) | 474 A = 3(-a + 3(b - c) + d) |
550 B = 6(a - 2b + c) | 475 B = 6(a - 2b + c) |
551 C = 3(b - a) | 476 C = 3(b - a) |
552 Solve for t, keeping only those that fit betwee 0 < t < 1 | 477 Solve for t, keeping only those that fit betwee 0 < t < 1 |
553 */ | 478 */ |
554 int SkFindCubicExtrema(SkScalar a, SkScalar b, SkScalar c, SkScalar d, SkScalar
tValues[2]) | 479 int SkFindCubicExtrema(SkScalar a, SkScalar b, SkScalar c, SkScalar d, SkScalar
tValues[2]) |
555 { | 480 { |
556 #ifdef SK_SCALAR_IS_FIXED | |
557 if (!is_not_monotonic(a, b, c, d)) | |
558 return 0; | |
559 #endif | |
560 | |
561 // we divide A,B,C by 3 to simplify | 481 // we divide A,B,C by 3 to simplify |
562 SkScalar A = d - a + 3*(b - c); | 482 SkScalar A = d - a + 3*(b - c); |
563 SkScalar B = 2*(a - b - b + c); | 483 SkScalar B = 2*(a - b - b + c); |
564 SkScalar C = b - a; | 484 SkScalar C = b - a; |
565 | 485 |
566 return SkFindUnitQuadRoots(A, B, C, tValues); | 486 return SkFindUnitQuadRoots(A, B, C, tValues); |
567 } | 487 } |
568 | 488 |
569 static void interp_cubic_coords(const SkScalar* src, SkScalar* dst, SkScalar t) | 489 static void interp_cubic_coords(const SkScalar* src, SkScalar* dst, SkScalar t) |
570 { | 490 { |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
740 (BxCy - ByCx)t^2 + (AxCy - AyCx)t + AxBy - AyBx == 0 | 660 (BxCy - ByCx)t^2 + (AxCy - AyCx)t + AxBy - AyBx == 0 |
741 */ | 661 */ |
742 int SkFindCubicInflections(const SkPoint src[4], SkScalar tValues[]) | 662 int SkFindCubicInflections(const SkPoint src[4], SkScalar tValues[]) |
743 { | 663 { |
744 SkScalar Ax = src[1].fX - src[0].fX; | 664 SkScalar Ax = src[1].fX - src[0].fX; |
745 SkScalar Ay = src[1].fY - src[0].fY; | 665 SkScalar Ay = src[1].fY - src[0].fY; |
746 SkScalar Bx = src[2].fX - 2 * src[1].fX + src[0].fX; | 666 SkScalar Bx = src[2].fX - 2 * src[1].fX + src[0].fX; |
747 SkScalar By = src[2].fY - 2 * src[1].fY + src[0].fY; | 667 SkScalar By = src[2].fY - 2 * src[1].fY + src[0].fY; |
748 SkScalar Cx = src[3].fX + 3 * (src[1].fX - src[2].fX) - src[0].fX; | 668 SkScalar Cx = src[3].fX + 3 * (src[1].fX - src[2].fX) - src[0].fX; |
749 SkScalar Cy = src[3].fY + 3 * (src[1].fY - src[2].fY) - src[0].fY; | 669 SkScalar Cy = src[3].fY + 3 * (src[1].fY - src[2].fY) - src[0].fY; |
750 int count; | |
751 | 670 |
752 #ifdef SK_SCALAR_IS_FLOAT | 671 return SkFindUnitQuadRoots(Bx*Cy - By*Cx, Ax*Cy - Ay*Cx, Ax*By - Ay*Bx, tVal
ues); |
753 count = SkFindUnitQuadRoots(Bx*Cy - By*Cx, Ax*Cy - Ay*Cx, Ax*By - Ay*Bx, tVa
lues); | |
754 #else | |
755 Sk64 A, B, C, tmp; | |
756 | |
757 A.setMul(Bx, Cy); | |
758 tmp.setMul(By, Cx); | |
759 A.sub(tmp); | |
760 | |
761 B.setMul(Ax, Cy); | |
762 tmp.setMul(Ay, Cx); | |
763 B.sub(tmp); | |
764 | |
765 C.setMul(Ax, By); | |
766 tmp.setMul(Ay, Bx); | |
767 C.sub(tmp); | |
768 | |
769 count = Sk64FindFixedQuadRoots(A, B, C, tValues); | |
770 #endif | |
771 | |
772 return count; | |
773 } | 672 } |
774 | 673 |
775 int SkChopCubicAtInflections(const SkPoint src[], SkPoint dst[10]) | 674 int SkChopCubicAtInflections(const SkPoint src[], SkPoint dst[10]) |
776 { | 675 { |
777 SkScalar tValues[2]; | 676 SkScalar tValues[2]; |
778 int count = SkFindCubicInflections(src, tValues); | 677 int count = SkFindCubicInflections(src, tValues); |
779 | 678 |
780 if (dst) | 679 if (dst) |
781 { | 680 { |
782 if (count == 0) | 681 if (count == 0) |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
884 memcpy(dst, data[i].fData, data[i].fCount * sizeof(dst[0])); | 783 memcpy(dst, data[i].fData, data[i].fCount * sizeof(dst[0])); |
885 int count = collaps_duplicates(dst, data[i].fCount); | 784 int count = collaps_duplicates(dst, data[i].fCount); |
886 SkASSERT(data[i].fCollapsedCount == count); | 785 SkASSERT(data[i].fCollapsedCount == count); |
887 for (int j = 1; j < count; ++j) { | 786 for (int j = 1; j < count; ++j) { |
888 SkASSERT(dst[j-1] < dst[j]); | 787 SkASSERT(dst[j-1] < dst[j]); |
889 } | 788 } |
890 } | 789 } |
891 } | 790 } |
892 #endif | 791 #endif |
893 | 792 |
894 #if defined _WIN32 && _MSC_VER >= 1300 && defined SK_SCALAR_IS_FIXED // disable
warning : unreachable code if building fixed point for windows desktop | |
895 #pragma warning ( disable : 4702 ) | |
896 #endif | |
897 | |
898 static SkScalar SkScalarCubeRoot(SkScalar x) { | 793 static SkScalar SkScalarCubeRoot(SkScalar x) { |
899 return sk_float_pow(x, 0.3333333f); | 794 return sk_float_pow(x, 0.3333333f); |
900 } | 795 } |
901 | 796 |
902 /* Solve coeff(t) == 0, returning the number of roots that | 797 /* Solve coeff(t) == 0, returning the number of roots that |
903 lie withing 0 < t < 1. | 798 lie withing 0 < t < 1. |
904 coeff[0]t^3 + coeff[1]t^2 + coeff[2]t + coeff[3] | 799 coeff[0]t^3 + coeff[1]t^2 + coeff[2]t + coeff[3] |
905 | 800 |
906 Eliminates repeated roots (so that all tValues are distinct, and are always | 801 Eliminates repeated roots (so that all tValues are distinct, and are always |
907 in increasing order. | 802 in increasing order. |
(...skipping 720 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1628 } | 1523 } |
1629 if (this->findYExtrema(&t)) { | 1524 if (this->findYExtrema(&t)) { |
1630 this->evalAt(t, &pts[count++]); | 1525 this->evalAt(t, &pts[count++]); |
1631 } | 1526 } |
1632 bounds->set(pts, count); | 1527 bounds->set(pts, count); |
1633 } | 1528 } |
1634 | 1529 |
1635 void SkConic::computeFastBounds(SkRect* bounds) const { | 1530 void SkConic::computeFastBounds(SkRect* bounds) const { |
1636 bounds->set(fPts, 3); | 1531 bounds->set(fPts, 3); |
1637 } | 1532 } |
OLD | NEW |