Index: src/pathops/SkDQuadIntersection.cpp |
diff --git a/src/pathops/SkDQuadIntersection.cpp b/src/pathops/SkDQuadIntersection.cpp |
index 124c7dab065cec479aa8362202bd9c4e374c8245..e10fb3f139f703abd3da67bc4fd161a16a2e046a 100644 |
--- a/src/pathops/SkDQuadIntersection.cpp |
+++ b/src/pathops/SkDQuadIntersection.cpp |
@@ -87,8 +87,8 @@ static bool only_end_pts_in_common(const SkDQuad& q1, const SkDQuad& q2) { |
for (int oddMan = 0; oddMan < 3; ++oddMan) { |
const SkDPoint* endPt[2]; |
for (int opp = 1; opp < 3; ++opp) { |
- int end = oddMan ^ opp; |
- if (end == 3) { |
+ int end = oddMan ^ opp; // choose a value not equal to oddMan |
+ if (3 == end) { // and correct so that largest value is 1 or 2 |
end = opp; |
} |
endPt[opp - 1] = &q1[end]; |
@@ -120,7 +120,7 @@ tryNextHalfPlane: |
static bool add_intercept(const SkDQuad& q1, const SkDQuad& q2, double tMin, double tMax, |
SkIntersections* i, bool* subDivide) { |
double tMid = (tMin + tMax) / 2; |
- SkDPoint mid = q2.xyAtT(tMid); |
+ SkDPoint mid = q2.ptAtT(tMid); |
SkDLine line; |
line[0] = line[1] = mid; |
SkDVector dxdy = q2.dxdyAtT(tMid); |
@@ -138,7 +138,7 @@ static bool add_intercept(const SkDQuad& q1, const SkDQuad& q2, double tMin, dou |
if (roots == 2) { |
return false; |
} |
- SkDPoint pt2 = q1.xyAtT(rootTs[0][0]); |
+ SkDPoint pt2 = q1.ptAtT(rootTs[0][0]); |
if (!pt2.approximatelyEqualHalf(mid)) { |
return false; |
} |
@@ -160,8 +160,8 @@ static bool is_linear_inner(const SkDQuad& q1, double t1s, double t1e, const SkD |
for (int idx2 = 0; idx2 < roots; ++idx2) { |
double t = rootTs[0][idx2]; |
#ifdef SK_DEBUG |
- SkDPoint qPt = q2.xyAtT(t); |
- SkDPoint lPt = testLines[index]->xyAtT(rootTs[1][idx2]); |
+ SkDPoint qPt = q2.ptAtT(t); |
+ SkDPoint lPt = testLines[index]->ptAtT(rootTs[1][idx2]); |
SkASSERT(qPt.approximatelyEqual(lPt)); |
#endif |
if (approximately_negative(t - t2s) || approximately_positive(t - t2e)) { |
@@ -183,12 +183,12 @@ static bool is_linear_inner(const SkDQuad& q1, double t1s, double t1e, const SkD |
tMin = tsFound[0]; |
tMax = tsFound[tsFound.count() - 1]; |
} |
- SkDPoint end = q2.xyAtT(t2s); |
+ SkDPoint end = q2.ptAtT(t2s); |
bool startInTriangle = hull.pointInHull(end); |
if (startInTriangle) { |
tMin = t2s; |
} |
- end = q2.xyAtT(t2e); |
+ end = q2.ptAtT(t2e); |
bool endInTriangle = hull.pointInHull(end); |
if (endInTriangle) { |
tMax = t2e; |
@@ -290,8 +290,8 @@ static bool binary_search(const SkDQuad& quad1, const SkDQuad& quad2, double* t1 |
SkDPoint t1[3], t2[3]; |
int calcMask = ~0; |
do { |
- if (calcMask & (1 << 1)) t1[1] = quad1.xyAtT(*t1Seed); |
- if (calcMask & (1 << 4)) t2[1] = quad2.xyAtT(*t2Seed); |
+ if (calcMask & (1 << 1)) t1[1] = quad1.ptAtT(*t1Seed); |
+ if (calcMask & (1 << 4)) t2[1] = quad2.ptAtT(*t2Seed); |
if (t1[1].approximatelyEqual(t2[1])) { |
*pt = t1[1]; |
#if ONE_OFF_DEBUG |
@@ -300,10 +300,10 @@ static bool binary_search(const SkDQuad& quad1, const SkDQuad& quad2, double* t1 |
#endif |
return true; |
} |
- if (calcMask & (1 << 0)) t1[0] = quad1.xyAtT(*t1Seed - tStep); |
- if (calcMask & (1 << 2)) t1[2] = quad1.xyAtT(*t1Seed + tStep); |
- if (calcMask & (1 << 3)) t2[0] = quad2.xyAtT(*t2Seed - tStep); |
- if (calcMask & (1 << 5)) t2[2] = quad2.xyAtT(*t2Seed + tStep); |
+ if (calcMask & (1 << 0)) t1[0] = quad1.ptAtT(*t1Seed - tStep); |
+ if (calcMask & (1 << 2)) t1[2] = quad1.ptAtT(*t1Seed + tStep); |
+ if (calcMask & (1 << 3)) t2[0] = quad2.ptAtT(*t2Seed - tStep); |
+ if (calcMask & (1 << 5)) t2[2] = quad2.ptAtT(*t2Seed + tStep); |
double dist[3][3]; |
// OPTIMIZE: using calcMask value permits skipping some distance calcuations |
// if prior loop's results are moved to correct slot for reuse |
@@ -361,6 +361,34 @@ static bool binary_search(const SkDQuad& quad1, const SkDQuad& quad2, double* t1 |
return false; |
} |
+static void lookNearEnd(const SkDQuad& q1, const SkDQuad& q2, int testT, |
+ const SkIntersections& orig, bool swap, SkIntersections* i) { |
+ if (orig.used() == 1 && orig[!swap][0] == testT) { |
+ return; |
+ } |
+ if (orig.used() == 2 && orig[!swap][1] == testT) { |
+ return; |
+ } |
+ SkDLine tmpLine; |
+ int testTIndex = testT << 1; |
+ tmpLine[0] = tmpLine[1] = q2[testTIndex]; |
+ tmpLine[1].fX += q2[1].fY - q2[testTIndex].fY; |
+ tmpLine[1].fY -= q2[1].fX - q2[testTIndex].fX; |
+ SkIntersections impTs; |
+ impTs.intersectRay(q1, tmpLine); |
+ for (int index = 0; index < impTs.used(); ++index) { |
+ SkDPoint realPt = impTs.pt(index); |
+ if (!tmpLine[0].approximatelyEqualHalf(realPt)) { |
+ continue; |
+ } |
+ if (swap) { |
+ i->insert(testT, impTs[0][index], tmpLine[0]); |
+ } else { |
+ i->insert(impTs[0][index], testT, tmpLine[0]); |
+ } |
+ } |
+} |
+ |
int SkIntersections::intersect(const SkDQuad& q1, const SkDQuad& q2) { |
// if the quads share an end point, check to see if they overlap |
@@ -379,6 +407,7 @@ int SkIntersections::intersect(const SkDQuad& q1, const SkDQuad& q2) { |
return fUsed; |
} |
// see if either quad is really a line |
+ // FIXME: figure out why reduce step didn't find this earlier |
if (is_linear(q1, q2, this)) { |
return fUsed; |
} |
@@ -388,30 +417,42 @@ int SkIntersections::intersect(const SkDQuad& q1, const SkDQuad& q2) { |
set(swapped); |
return fUsed; |
} |
- SkDQuadImplicit i1(q1); |
- SkDQuadImplicit i2(q2); |
- if (i1.match(i2)) { |
- // FIXME: compute T values |
- // compute the intersections of the ends to find the coincident span |
- reset(); |
- bool useVertical = fabs(q1[0].fX - q1[2].fX) < fabs(q1[0].fY - q1[2].fY); |
- double t; |
- if ((t = SkIntersections::Axial(q1, q2[0], useVertical)) >= 0) { |
- insertCoincident(t, 0, q2[0]); |
- } |
- if ((t = SkIntersections::Axial(q1, q2[2], useVertical)) >= 0) { |
- insertCoincident(t, 1, q2[2]); |
- } |
- useVertical = fabs(q2[0].fX - q2[2].fX) < fabs(q2[0].fY - q2[2].fY); |
- if ((t = SkIntersections::Axial(q2, q1[0], useVertical)) >= 0) { |
- insertCoincident(0, t, q1[0]); |
+ SkIntersections copyI(*this); |
+ lookNearEnd(q1, q2, 0, *this, false, ©I); |
+ lookNearEnd(q1, q2, 1, *this, false, ©I); |
+ lookNearEnd(q2, q1, 0, *this, true, ©I); |
+ lookNearEnd(q2, q1, 1, *this, true, ©I); |
+ int innerEqual = 0; |
+ if (copyI.fUsed >= 2) { |
+ SkASSERT(copyI.fUsed <= 4); |
+ double width = copyI[0][1] - copyI[0][0]; |
+ int midEnd = 1; |
+ for (int index = 2; index < copyI.fUsed; ++index) { |
+ double testWidth = copyI[0][index] - copyI[0][index - 1]; |
+ if (testWidth <= width) { |
+ continue; |
+ } |
+ midEnd = index; |
} |
- if ((t = SkIntersections::Axial(q2, q1[2], useVertical)) >= 0) { |
- insertCoincident(1, t, q1[2]); |
+ for (int index = 0; index < 2; ++index) { |
+ double testT = (copyI[0][midEnd] * (index + 1) |
+ + copyI[0][midEnd - 1] * (2 - index)) / 3; |
+ SkDPoint testPt1 = q1.ptAtT(testT); |
+ testT = (copyI[1][midEnd] * (index + 1) + copyI[1][midEnd - 1] * (2 - index)) / 3; |
+ SkDPoint testPt2 = q2.ptAtT(testT); |
+ innerEqual += testPt1.approximatelyEqual(testPt2); |
} |
- SkASSERT(coincidentUsed() <= 2); |
+ } |
+ bool expectCoincident = copyI.fUsed >= 2 && innerEqual == 2; |
+ if (expectCoincident) { |
+ reset(); |
+ insertCoincident(copyI[0][0], copyI[1][0], copyI.fPt[0]); |
+ int last = copyI.fUsed - 1; |
+ insertCoincident(copyI[0][last], copyI[1][last], copyI.fPt[last]); |
return fUsed; |
} |
+ SkDQuadImplicit i1(q1); |
+ SkDQuadImplicit i2(q2); |
int index; |
bool flip1 = q1[2] == q2[0]; |
bool flip2 = q1[0] == q2[2]; |
@@ -423,7 +464,7 @@ int SkIntersections::intersect(const SkDQuad& q1, const SkDQuad& q2) { |
int r1Count = addValidRoots(roots1, rootCount, roots1Copy); |
SkDPoint pts1[4]; |
for (index = 0; index < r1Count; ++index) { |
- pts1[index] = q1.xyAtT(roots1Copy[index]); |
+ pts1[index] = q1.ptAtT(roots1Copy[index]); |
} |
double roots2[4]; |
int rootCount2 = findRoots(i1, q2, roots2, useCubic, flip2, 0); |
@@ -431,7 +472,7 @@ int SkIntersections::intersect(const SkDQuad& q1, const SkDQuad& q2) { |
int r2Count = addValidRoots(roots2, rootCount2, roots2Copy); |
SkDPoint pts2[4]; |
for (index = 0; index < r2Count; ++index) { |
- pts2[index] = q2.xyAtT(roots2Copy[index]); |
+ pts2[index] = q2.ptAtT(roots2Copy[index]); |
} |
if (r1Count == r2Count && r1Count <= 1) { |
if (r1Count == 1) { |