| 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 |