OLD | NEW |
1 // Another approach is to start with the implicit form of one curve and solve | 1 // Another approach is to start with the implicit form of one curve and solve |
2 // (seek implicit coefficients in QuadraticParameter.cpp | 2 // (seek implicit coefficients in QuadraticParameter.cpp |
3 // by substituting in the parametric form of the other. | 3 // by substituting in the parametric form of the other. |
4 // The downside of this approach is that early rejects are difficult to come by. | 4 // The downside of this approach is that early rejects are difficult to come by. |
5 // http://planetmath.org/encyclopedia/GaloisTheoreticDerivationOfTheQuarticFormu
la.html#step | 5 // http://planetmath.org/encyclopedia/GaloisTheoreticDerivationOfTheQuarticFormu
la.html#step |
6 | 6 |
7 | 7 |
8 #include "SkDQuadImplicit.h" | 8 #include "SkDQuadImplicit.h" |
9 #include "SkIntersections.h" | 9 #include "SkIntersections.h" |
10 #include "SkPathOpsLine.h" | 10 #include "SkPathOpsLine.h" |
11 #include "SkQuarticRoot.h" | 11 #include "SkQuarticRoot.h" |
12 #include "SkTDArray.h" | 12 #include "SkTDArray.h" |
13 #include "SkTSort.h" | 13 #include "SkTSort.h" |
14 | 14 |
15 /* given the implicit form 0 = Ax^2 + Bxy + Cy^2 + Dx + Ey + F | 15 /* given the implicit form 0 = Ax^2 + Bxy + Cy^2 + Dx + Ey + F |
16 * and given x = at^2 + bt + c (the parameterized form) | 16 * and given x = at^2 + bt + c (the parameterized form) |
17 * y = dt^2 + et + f | 17 * y = dt^2 + et + f |
18 * then | 18 * then |
19 * 0 = A(at^2+bt+c)(at^2+bt+c)+B(at^2+bt+c)(dt^2+et+f)+C(dt^2+et+f)(dt^2+et+f)+D
(at^2+bt+c)+E(dt^2+et+f)+F | 19 * 0 = A(at^2+bt+c)(at^2+bt+c)+B(at^2+bt+c)(dt^2+et+f)+C(dt^2+et+f)(dt^2+et+f)+D
(at^2+bt+c)+E(dt^2+et+f)+F |
20 */ | 20 */ |
21 | 21 |
22 static int findRoots(const SkDQuadImplicit& i, const SkDQuad& q2, double roots[4
], | 22 static int findRoots(const SkDQuadImplicit& i, const SkDQuad& quad, double roots
[4], |
23 bool oneHint, int firstCubicRoot) { | 23 bool oneHint, bool flip, int firstCubicRoot) { |
| 24 SkDQuad flipped; |
| 25 const SkDQuad& q = flip ? (flipped = quad.flip()) : quad; |
24 double a, b, c; | 26 double a, b, c; |
25 SkDQuad::SetABC(&q2[0].fX, &a, &b, &c); | 27 SkDQuad::SetABC(&q[0].fX, &a, &b, &c); |
26 double d, e, f; | 28 double d, e, f; |
27 SkDQuad::SetABC(&q2[0].fY, &d, &e, &f); | 29 SkDQuad::SetABC(&q[0].fY, &d, &e, &f); |
28 const double t4 = i.x2() * a * a | 30 const double t4 = i.x2() * a * a |
29 + i.xy() * a * d | 31 + i.xy() * a * d |
30 + i.y2() * d * d; | 32 + i.y2() * d * d; |
31 const double t3 = 2 * i.x2() * a * b | 33 const double t3 = 2 * i.x2() * a * b |
32 + i.xy() * (a * e + b * d) | 34 + i.xy() * (a * e + b * d) |
33 + 2 * i.y2() * d * e; | 35 + 2 * i.y2() * d * e; |
34 const double t2 = i.x2() * (b * b + 2 * a * c) | 36 const double t2 = i.x2() * (b * b + 2 * a * c) |
35 + i.xy() * (c * d + b * e + a * f) | 37 + i.xy() * (c * d + b * e + a * f) |
36 + i.y2() * (e * e + 2 * d * f) | 38 + i.y2() * (e * e + 2 * d * f) |
37 + i.x() * a | 39 + i.x() * a |
38 + i.y() * d; | 40 + i.y() * d; |
39 const double t1 = 2 * i.x2() * b * c | 41 const double t1 = 2 * i.x2() * b * c |
40 + i.xy() * (c * e + b * f) | 42 + i.xy() * (c * e + b * f) |
41 + 2 * i.y2() * e * f | 43 + 2 * i.y2() * e * f |
42 + i.x() * b | 44 + i.x() * b |
43 + i.y() * e; | 45 + i.y() * e; |
44 const double t0 = i.x2() * c * c | 46 const double t0 = i.x2() * c * c |
45 + i.xy() * c * f | 47 + i.xy() * c * f |
46 + i.y2() * f * f | 48 + i.y2() * f * f |
47 + i.x() * c | 49 + i.x() * c |
48 + i.y() * f | 50 + i.y() * f |
49 + i.c(); | 51 + i.c(); |
50 int rootCount = SkReducedQuarticRoots(t4, t3, t2, t1, t0, oneHint, roots); | 52 int rootCount = SkReducedQuarticRoots(t4, t3, t2, t1, t0, oneHint, roots); |
51 if (rootCount >= 0) { | 53 if (rootCount < 0) { |
52 return rootCount; | 54 rootCount = SkQuarticRootsReal(firstCubicRoot, t4, t3, t2, t1, t0, roots
); |
53 } | 55 } |
54 return SkQuarticRootsReal(firstCubicRoot, t4, t3, t2, t1, t0, roots); | 56 if (flip) { |
| 57 for (int index = 0; index < rootCount; ++index) { |
| 58 roots[index] = 1 - roots[index]; |
| 59 } |
| 60 } |
| 61 return rootCount; |
55 } | 62 } |
56 | 63 |
57 static int addValidRoots(const double roots[4], const int count, double valid[4]
) { | 64 static int addValidRoots(const double roots[4], const int count, double valid[4]
) { |
58 int result = 0; | 65 int result = 0; |
59 int index; | 66 int index; |
60 for (index = 0; index < count; ++index) { | 67 for (index = 0; index < count; ++index) { |
61 if (!approximately_zero_or_more(roots[index]) || !approximately_one_or_l
ess(roots[index])) { | 68 if (!approximately_zero_or_more(roots[index]) || !approximately_one_or_l
ess(roots[index])) { |
62 continue; | 69 continue; |
63 } | 70 } |
64 double t = 1 - roots[index]; | 71 double t = 1 - roots[index]; |
(...skipping 331 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
396 if ((t = SkIntersections::Axial(q2, q1[0], useVertical)) >= 0) { | 403 if ((t = SkIntersections::Axial(q2, q1[0], useVertical)) >= 0) { |
397 insertCoincident(0, t, q1[0]); | 404 insertCoincident(0, t, q1[0]); |
398 } | 405 } |
399 if ((t = SkIntersections::Axial(q2, q1[2], useVertical)) >= 0) { | 406 if ((t = SkIntersections::Axial(q2, q1[2], useVertical)) >= 0) { |
400 insertCoincident(1, t, q1[2]); | 407 insertCoincident(1, t, q1[2]); |
401 } | 408 } |
402 SkASSERT(coincidentUsed() <= 2); | 409 SkASSERT(coincidentUsed() <= 2); |
403 return fUsed; | 410 return fUsed; |
404 } | 411 } |
405 int index; | 412 int index; |
406 bool useCubic = q1[0] == q2[0] || q1[0] == q2[2] || q1[2] == q2[0]; | 413 bool flip1 = q1[2] == q2[0]; |
| 414 bool flip2 = q1[0] == q2[2]; |
| 415 bool useCubic = q1[0] == q2[0]; |
407 double roots1[4]; | 416 double roots1[4]; |
408 int rootCount = findRoots(i2, q1, roots1, useCubic, 0); | 417 int rootCount = findRoots(i2, q1, roots1, useCubic, flip1, 0); |
409 // OPTIMIZATION: could short circuit here if all roots are < 0 or > 1 | 418 // OPTIMIZATION: could short circuit here if all roots are < 0 or > 1 |
410 double roots1Copy[4]; | 419 double roots1Copy[4]; |
411 int r1Count = addValidRoots(roots1, rootCount, roots1Copy); | 420 int r1Count = addValidRoots(roots1, rootCount, roots1Copy); |
412 SkDPoint pts1[4]; | 421 SkDPoint pts1[4]; |
413 for (index = 0; index < r1Count; ++index) { | 422 for (index = 0; index < r1Count; ++index) { |
414 pts1[index] = q1.xyAtT(roots1Copy[index]); | 423 pts1[index] = q1.xyAtT(roots1Copy[index]); |
415 } | 424 } |
416 double roots2[4]; | 425 double roots2[4]; |
417 int rootCount2 = findRoots(i1, q2, roots2, useCubic, 0); | 426 int rootCount2 = findRoots(i1, q2, roots2, useCubic, flip2, 0); |
418 double roots2Copy[4]; | 427 double roots2Copy[4]; |
419 int r2Count = addValidRoots(roots2, rootCount2, roots2Copy); | 428 int r2Count = addValidRoots(roots2, rootCount2, roots2Copy); |
420 SkDPoint pts2[4]; | 429 SkDPoint pts2[4]; |
421 for (index = 0; index < r2Count; ++index) { | 430 for (index = 0; index < r2Count; ++index) { |
422 pts2[index] = q2.xyAtT(roots2Copy[index]); | 431 pts2[index] = q2.xyAtT(roots2Copy[index]); |
423 } | 432 } |
424 if (r1Count == r2Count && r1Count <= 1) { | 433 if (r1Count == r2Count && r1Count <= 1) { |
425 if (r1Count == 1) { | 434 if (r1Count == 1) { |
426 if (pts1[0].approximatelyEqualHalf(pts2[0])) { | 435 if (pts1[0].approximatelyEqualHalf(pts2[0])) { |
427 insert(roots1Copy[0], roots2Copy[0], pts1[0]); | 436 insert(roots1Copy[0], roots2Copy[0], pts1[0]); |
428 } else if (pts1[0].moreRoughlyEqual(pts2[0])) { | 437 } else if (pts1[0].moreRoughlyEqual(pts2[0])) { |
429 // experiment: try to find intersection by chasing t | 438 // experiment: try to find intersection by chasing t |
430 rootCount = findRoots(i2, q1, roots1, useCubic, 0); | 439 rootCount = findRoots(i2, q1, roots1, useCubic, flip1, 0); |
431 (void) addValidRoots(roots1, rootCount, roots1Copy); | 440 (void) addValidRoots(roots1, rootCount, roots1Copy); |
432 rootCount2 = findRoots(i1, q2, roots2, useCubic, 0); | 441 rootCount2 = findRoots(i1, q2, roots2, useCubic, flip2, 0); |
433 (void) addValidRoots(roots2, rootCount2, roots2Copy); | 442 (void) addValidRoots(roots2, rootCount2, roots2Copy); |
434 if (binary_search(q1, q2, roots1Copy, roots2Copy, pts1)) { | 443 if (binary_search(q1, q2, roots1Copy, roots2Copy, pts1)) { |
435 insert(roots1Copy[0], roots2Copy[0], pts1[0]); | 444 insert(roots1Copy[0], roots2Copy[0], pts1[0]); |
436 } | 445 } |
437 } | 446 } |
438 } | 447 } |
439 return fUsed; | 448 return fUsed; |
440 } | 449 } |
441 int closest[4]; | 450 int closest[4]; |
442 double dist[4]; | 451 double dist[4]; |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
489 } | 498 } |
490 if (lowestIndex < 0) { | 499 if (lowestIndex < 0) { |
491 break; | 500 break; |
492 } | 501 } |
493 insert(roots1Copy[lowestIndex], roots2Copy[closest[lowestIndex]], | 502 insert(roots1Copy[lowestIndex], roots2Copy[closest[lowestIndex]], |
494 pts1[lowestIndex]); | 503 pts1[lowestIndex]); |
495 closest[lowestIndex] = -1; | 504 closest[lowestIndex] = -1; |
496 } while (++used < r1Count); | 505 } while (++used < r1Count); |
497 return fUsed; | 506 return fUsed; |
498 } | 507 } |
OLD | NEW |