Index: src/pathops/SkAddIntersections.cpp |
diff --git a/src/pathops/SkAddIntersections.cpp b/src/pathops/SkAddIntersections.cpp |
index b507eb7560989665109fd358e7b5fc9b359c4f21..c27434f9f778cb1a4df19570b6ecfdbeb8d90e38 100644 |
--- a/src/pathops/SkAddIntersections.cpp |
+++ b/src/pathops/SkAddIntersections.cpp |
@@ -5,7 +5,6 @@ |
* found in the LICENSE file. |
*/ |
#include "SkAddIntersections.h" |
-#include "SkOpCoincidence.h" |
#include "SkPathOpsBounds.h" |
#if DEBUG_ADD_INTERSECTING_TS |
@@ -131,6 +130,20 @@ |
SkDebugf("\n"); |
} |
+static void debugShowCubicIntersection(int pts, const SkIntersectionHelper& wt, |
+ const SkIntersections& i) { |
+ SkASSERT(i.used() == pts); |
+ if (!pts) { |
+ SkDebugf("%s no self intersect " CUBIC_DEBUG_STR "\n", __FUNCTION__, |
+ CUBIC_DEBUG_DATA(wt.pts())); |
+ return; |
+ } |
+ SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__, |
+ i[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0)); |
+ SkDebugf(" " T_DEBUG_STR(wtTs, 1), i[1][0]); |
+ SkDebugf("\n"); |
+} |
+ |
#else |
static void debugShowLineIntersection(int , const SkIntersectionHelper& , |
const SkIntersectionHelper& , const SkIntersections& ) { |
@@ -155,10 +168,13 @@ |
static void debugShowCubicIntersection(int , const SkIntersectionHelper& , |
const SkIntersectionHelper& , const SkIntersections& ) { |
} |
+ |
+static void debugShowCubicIntersection(int , const SkIntersectionHelper& , |
+ const SkIntersections& ) { |
+} |
#endif |
-bool AddIntersectTs(SkOpContour* test, SkOpContour* next, SkOpCoincidence* coincidence, |
- SkChunkAlloc* allocator) { |
+bool AddIntersectTs(SkOpContour* test, SkOpContour* next) { |
if (test != next) { |
if (AlmostLessUlps(test->bounds().fBottom, next->bounds().fTop)) { |
return false; |
@@ -170,11 +186,10 @@ |
} |
SkIntersectionHelper wt; |
wt.init(test); |
+ bool foundCommonContour = test == next; |
do { |
SkIntersectionHelper wn; |
wn.init(next); |
- test->debugValidate(); |
- next->debugValidate(); |
if (test == next && !wn.startAfter(wt)) { |
continue; |
} |
@@ -291,22 +306,14 @@ |
break; |
} |
case SkIntersectionHelper::kQuad_Segment: { |
- SkDQuad quad1; |
- quad1.set(wt.pts()); |
- SkDQuad quad2; |
- quad2.set(wn.pts()); |
- pts = ts.intersect(quad1, quad2); |
+ pts = ts.quadQuad(wt.pts(), wn.pts()); |
+ ts.alignQuadPts(wt.pts(), wn.pts()); |
debugShowQuadIntersection(pts, wt, wn, ts); |
break; |
} |
case SkIntersectionHelper::kCubic_Segment: { |
swap = true; |
- SkDQuad quad1; |
- quad1.set(wt.pts()); |
- SkDCubic cubic1 = quad1.toCubic(); |
- SkDCubic cubic2; |
- cubic2.set(wn.pts()); |
- pts = ts.intersect(cubic2, cubic1); |
+ pts = ts.cubicQuad(wn.pts(), wt.pts()); |
debugShowCubicQuadIntersection(pts, wn, wt, ts); |
break; |
} |
@@ -332,21 +339,12 @@ |
break; |
} |
case SkIntersectionHelper::kQuad_Segment: { |
- SkDCubic cubic1; |
- cubic1.set(wt.pts()); |
- SkDQuad quad2; |
- quad2.set(wn.pts()); |
- SkDCubic cubic2 = quad2.toCubic(); |
- pts = ts.intersect(cubic1, cubic2); |
+ pts = ts.cubicQuad(wt.pts(), wn.pts()); |
debugShowCubicQuadIntersection(pts, wt, wn, ts); |
break; |
} |
case SkIntersectionHelper::kCubic_Segment: { |
- SkDCubic cubic1; |
- cubic1.set(wt.pts()); |
- SkDCubic cubic2; |
- cubic2.set(wn.pts()); |
- pts = ts.intersect(cubic1, cubic2); |
+ pts = ts.cubicCubic(wt.pts(), wn.pts()); |
debugShowCubicIntersection(pts, wt, wn, ts); |
break; |
} |
@@ -357,53 +355,102 @@ |
default: |
SkASSERT(0); |
} |
- int coinIndex = -1; |
- SkOpPtT* coinPtT[2]; |
+ if (!foundCommonContour && pts > 0) { |
+ test->addCross(next); |
+ next->addCross(test); |
+ foundCommonContour = true; |
+ } |
+ // in addition to recording T values, record matching segment |
+ if (pts == 2) { |
+ if (wn.segmentType() <= SkIntersectionHelper::kLine_Segment |
+ && wt.segmentType() <= SkIntersectionHelper::kLine_Segment) { |
+ if (wt.addCoincident(wn, ts, swap)) { |
+ continue; |
+ } |
+ pts = ts.cleanUpCoincidence(); // prefer (t == 0 or t == 1) |
+ } else if (wn.segmentType() >= SkIntersectionHelper::kQuad_Segment |
+ && wt.segmentType() >= SkIntersectionHelper::kQuad_Segment |
+ && ts.isCoincident(0)) { |
+ SkASSERT(ts.coincidentUsed() == 2); |
+ if (wt.addCoincident(wn, ts, swap)) { |
+ continue; |
+ } |
+ pts = ts.cleanUpCoincidence(); // prefer (t == 0 or t == 1) |
+ } |
+ } |
+ if (pts >= 2) { |
+ for (int pt = 0; pt < pts - 1; ++pt) { |
+ const SkDPoint& point = ts.pt(pt); |
+ const SkDPoint& next = ts.pt(pt + 1); |
+ if (wt.isPartial(ts[swap][pt], ts[swap][pt + 1], point, next) |
+ && wn.isPartial(ts[!swap][pt], ts[!swap][pt + 1], point, next)) { |
+ if (!wt.addPartialCoincident(wn, ts, pt, swap)) { |
+ // remove extra point if two map to same float values |
+ pts = ts.cleanUpCoincidence(); // prefer (t == 0 or t == 1) |
+ } |
+ } |
+ } |
+ } |
for (int pt = 0; pt < pts; ++pt) { |
SkASSERT(ts[0][pt] >= 0 && ts[0][pt] <= 1); |
SkASSERT(ts[1][pt] >= 0 && ts[1][pt] <= 1); |
- wt.segment()->debugValidate(); |
- SkOpPtT* testTAt = wt.segment()->addT(ts[swap][pt], SkOpSegment::kAllowAlias, |
- allocator); |
- wn.segment()->debugValidate(); |
- SkOpPtT* nextTAt = wn.segment()->addT(ts[!swap][pt], SkOpSegment::kAllowAlias, |
- allocator); |
- testTAt->addOpp(nextTAt); |
- if (testTAt->fPt != nextTAt->fPt) { |
- testTAt->span()->unaligned(); |
- nextTAt->span()->unaligned(); |
- } |
- wt.segment()->debugValidate(); |
- wn.segment()->debugValidate(); |
- if (!ts.isCoincident(pt)) { |
- continue; |
- } |
- if (coinIndex < 0) { |
- coinPtT[0] = testTAt; |
- coinPtT[1] = nextTAt; |
- coinIndex = pt; |
- continue; |
- } |
- if (coinPtT[0]->span() == testTAt->span()) { |
- coinIndex = -1; |
- continue; |
- } |
- if (coinPtT[1]->span() == nextTAt->span()) { |
- coinIndex = -1; // coincidence span collapsed |
- continue; |
- } |
- if (swap) { |
- SkTSwap(coinPtT[0], coinPtT[1]); |
- SkTSwap(testTAt, nextTAt); |
- } |
- SkASSERT(coinPtT[0]->span()->t() < testTAt->span()->t()); |
- coincidence->add(coinPtT[0], testTAt, coinPtT[1], nextTAt, allocator); |
- wt.segment()->debugValidate(); |
- wn.segment()->debugValidate(); |
- coinIndex = -1; |
- } |
- SkASSERT(coinIndex < 0); // expect coincidence to be paired |
+ SkPoint point = ts.pt(pt).asSkPoint(); |
+ wt.alignTPt(wn, swap, pt, &ts, &point); |
+ int testTAt = wt.addT(wn, point, ts[swap][pt]); |
+ int nextTAt = wn.addT(wt, point, ts[!swap][pt]); |
+ wt.addOtherT(testTAt, ts[!swap][pt], nextTAt); |
+ wn.addOtherT(nextTAt, ts[swap][pt], testTAt); |
+ } |
} while (wn.advance()); |
} while (wt.advance()); |
return true; |
} |
+ |
+void AddSelfIntersectTs(SkOpContour* test) { |
+ SkIntersectionHelper wt; |
+ wt.init(test); |
+ do { |
+ if (wt.segmentType() != SkIntersectionHelper::kCubic_Segment) { |
+ continue; |
+ } |
+ SkIntersections ts; |
+ int pts = ts.cubic(wt.pts()); |
+ debugShowCubicIntersection(pts, wt, ts); |
+ if (!pts) { |
+ continue; |
+ } |
+ SkASSERT(pts == 1); |
+ SkASSERT(ts[0][0] >= 0 && ts[0][0] <= 1); |
+ SkASSERT(ts[1][0] >= 0 && ts[1][0] <= 1); |
+ SkPoint point = ts.pt(0).asSkPoint(); |
+ int testTAt = wt.addSelfT(point, ts[0][0]); |
+ int nextTAt = wt.addSelfT(point, ts[1][0]); |
+ wt.addOtherT(testTAt, ts[1][0], nextTAt); |
+ wt.addOtherT(nextTAt, ts[0][0], testTAt); |
+ } while (wt.advance()); |
+} |
+ |
+// resolve any coincident pairs found while intersecting, and |
+// see if coincidence is formed by clipping non-concident segments |
+bool CoincidenceCheck(SkTArray<SkOpContour*, true>* contourList, int total) { |
+ int contourCount = (*contourList).count(); |
+ for (int cIndex = 0; cIndex < contourCount; ++cIndex) { |
+ SkOpContour* contour = (*contourList)[cIndex]; |
+ contour->resolveNearCoincidence(); |
+ } |
+ for (int cIndex = 0; cIndex < contourCount; ++cIndex) { |
+ SkOpContour* contour = (*contourList)[cIndex]; |
+ contour->addCoincidentPoints(); |
+ } |
+ for (int cIndex = 0; cIndex < contourCount; ++cIndex) { |
+ SkOpContour* contour = (*contourList)[cIndex]; |
+ if (!contour->calcCoincidentWinding()) { |
+ return false; |
+ } |
+ } |
+ for (int cIndex = 0; cIndex < contourCount; ++cIndex) { |
+ SkOpContour* contour = (*contourList)[cIndex]; |
+ contour->calcPartialCoincidentWinding(); |
+ } |
+ return true; |
+} |