| Index: src/pathops/SkPathOpsTSect.h
|
| diff --git a/src/pathops/SkPathOpsTSect.h b/src/pathops/SkPathOpsTSect.h
|
| index e8a0fd499bfad171af18769b9ed98869292c1560..0da4d7f9f4248e25521d011cd3bcc33526e37cbb 100644
|
| --- a/src/pathops/SkPathOpsTSect.h
|
| +++ b/src/pathops/SkPathOpsTSect.h
|
| @@ -87,6 +87,7 @@ public:
|
| bool debugIsBefore(const SkTSpan* span) const;
|
| #endif
|
| void dump() const;
|
| + void dumpAll() const;
|
| void dumpBounded(int id) const;
|
| void dumpBounds() const;
|
| void dumpCoin() const;
|
| @@ -244,6 +245,7 @@ private:
|
| double* oppT);
|
| SkTSpan<TCurve, OppCurve>* boundsMax() const;
|
| void coincidentCheck(SkTSect<OppCurve, TCurve>* sect2);
|
| + void coincidentForce(SkTSect<OppCurve, TCurve>* sect2, double start1s, double start1e);
|
| bool coincidentHasT(double t);
|
| int collapsed() const;
|
| void computePerpendiculars(SkTSect<OppCurve, TCurve>* sect2, SkTSpan<TCurve, OppCurve>* first,
|
| @@ -385,14 +387,14 @@ void SkTSect<TCurve, OppCurve>::addForPerp(SkTSpan<OppCurve, TCurve>* span, doub
|
| if (!opp) {
|
| opp = this->addFollowing(priorSpan);
|
| #if DEBUG_PERP
|
| - SkDebugf("%s priorSpan=%d t=%1.9g opp=%d\n", __FUNCTION__, priorSpan->debugID(), t,
|
| - opp->debugID());
|
| + SkDebugf("%s priorSpan=%d t=%1.9g opp=%d\n", __FUNCTION__, priorSpan ?
|
| + priorSpan->debugID() : -1, t, opp->debugID());
|
| #endif
|
| }
|
| #if DEBUG_PERP
|
| opp->dump(); SkDebugf("\n");
|
| - SkDebugf("%s addBounded span=%d opp=%d\n", __FUNCTION__, priorSpan->debugID(),
|
| - opp->debugID());
|
| + SkDebugf("%s addBounded span=%d opp=%d\n", __FUNCTION__, priorSpan ?
|
| + priorSpan->debugID() : -1, opp->debugID());
|
| #endif
|
| opp->addBounded(span, &fHeap);
|
| span->addBounded(opp, &fHeap);
|
| @@ -792,7 +794,7 @@ void SkTSpan<TCurve, OppCurve>::validatePerpT(double oppT) const {
|
| const SkTSpanBounded<OppCurve, TCurve>* testBounded = fBounded;
|
| while (testBounded) {
|
| const SkTSpan<OppCurve, TCurve>* overlap = testBounded->fBounded;
|
| - if (between(overlap->fStartT, oppT, overlap->fEndT)) {
|
| + if (precisely_between(overlap->fStartT, oppT, overlap->fEndT)) {
|
| return;
|
| }
|
| testBounded = testBounded->fNext;
|
| @@ -944,6 +946,39 @@ void SkTSect<TCurve, OppCurve>::coincidentCheck(SkTSect<OppCurve, TCurve>* sect2
|
| }
|
|
|
| template<typename TCurve, typename OppCurve>
|
| +void SkTSect<TCurve, OppCurve>::coincidentForce(SkTSect<OppCurve, TCurve>* sect2,
|
| + double start1s, double start1e) {
|
| + SkTSpan<TCurve, OppCurve>* first = fHead;
|
| + SkTSpan<TCurve, OppCurve>* last = this->tail();
|
| + SkTSpan<OppCurve, TCurve>* oppFirst = sect2->fHead;
|
| + SkTSpan<OppCurve, TCurve>* oppLast = sect2->tail();
|
| + bool deleteEmptySpans = this->updateBounded(first, last, oppFirst);
|
| + deleteEmptySpans |= sect2->updateBounded(oppFirst, oppLast, first);
|
| + this->removeSpanRange(first, last);
|
| + sect2->removeSpanRange(oppFirst, oppLast);
|
| + first->fStartT = start1s;
|
| + first->fEndT = start1e;
|
| + first->resetBounds(fCurve);
|
| + first->fCoinStart.setPerp(fCurve, start1s, fCurve[0], sect2->fCurve);
|
| + first->fCoinEnd.setPerp(fCurve, start1e, fCurve[TCurve::kPointLast], sect2->fCurve);
|
| + bool oppMatched = first->fCoinStart.perpT() < first->fCoinEnd.perpT();
|
| + double oppStartT = SkTMax(0., first->fCoinStart.perpT());
|
| + double oppEndT = SkTMin(1., first->fCoinEnd.perpT());
|
| + if (!oppMatched) {
|
| + SkTSwap(oppStartT, oppEndT);
|
| + }
|
| + oppFirst->fStartT = oppStartT;
|
| + oppFirst->fEndT = oppEndT;
|
| + oppFirst->resetBounds(sect2->fCurve);
|
| + this->removeCoincident(first, false);
|
| + sect2->removeCoincident(oppFirst, true);
|
| + if (deleteEmptySpans) {
|
| + this->deleteEmptySpans();
|
| + sect2->deleteEmptySpans();
|
| + }
|
| +}
|
| +
|
| +template<typename TCurve, typename OppCurve>
|
| bool SkTSect<TCurve, OppCurve>::coincidentHasT(double t) {
|
| SkTSpan<TCurve, OppCurve>* test = fCoincident;
|
| while (test) {
|
| @@ -1226,6 +1261,9 @@ int SkTSect<TCurve, OppCurve>::intersects(SkTSpan<TCurve, OppCurve>* span,
|
| if (span->fIsLine && oppSpan->fIsLine) {
|
| SkIntersections i;
|
| int sects = this->linesIntersect(span, opp, oppSpan, &i);
|
| + if (sects == 2) {
|
| + return *oppResult = 1;
|
| + }
|
| if (!sects) {
|
| return -1;
|
| }
|
| @@ -1257,6 +1295,29 @@ int SkTSect<TCurve, OppCurve>::linesIntersect(SkTSpan<TCurve, OppCurve>* span,
|
| if (!oppRayI.intersectRay(this->fCurve, oppLine)) {
|
| return 0;
|
| }
|
| + // if the ends of each line intersect the opposite curve, the lines are coincident
|
| + if (thisRayI.used() > 1) {
|
| + int ptMatches = 0;
|
| + for (int tIndex = 0; tIndex < thisRayI.used(); ++tIndex) {
|
| + for (int lIndex = 0; lIndex < (int) SK_ARRAY_COUNT(thisLine.fPts); ++lIndex) {
|
| + ptMatches += thisRayI.pt(tIndex).approximatelyEqual(thisLine.fPts[lIndex]);
|
| + }
|
| + }
|
| + if (ptMatches == 2) {
|
| + return 2;
|
| + }
|
| + }
|
| + if (oppRayI.used() > 1) {
|
| + int ptMatches = 0;
|
| + for (int oIndex = 0; oIndex < oppRayI.used(); ++oIndex) {
|
| + for (int lIndex = 0; lIndex < (int) SK_ARRAY_COUNT(thisLine.fPts); ++lIndex) {
|
| + ptMatches += oppRayI.pt(oIndex).approximatelyEqual(oppLine.fPts[lIndex]);
|
| + }
|
| + }
|
| + if (ptMatches == 2) {
|
| + return 2;
|
| + }
|
| + }
|
| do {
|
| // pick the closest pair of points
|
| double closest = DBL_MAX;
|
| @@ -1921,6 +1982,10 @@ void SkTSect<TCurve, OppCurve>::BinarySearch(SkTSect<TCurve, OppCurve>* sect1,
|
| }
|
| span1->addBounded(span2, §1->fHeap);
|
| span2->addBounded(span1, §2->fHeap);
|
| + const int kMaxCoinLoopCount = 8;
|
| + int coinLoopCount = kMaxCoinLoopCount;
|
| + double start1s SK_INIT_TO_AVOID_WARNING;
|
| + double start1e SK_INIT_TO_AVOID_WARNING;
|
| do {
|
| // find the largest bounds
|
| SkTSpan<TCurve, OppCurve>* largest1 = sect1->boundsMax();
|
| @@ -1955,12 +2020,32 @@ void SkTSect<TCurve, OppCurve>::BinarySearch(SkTSect<TCurve, OppCurve>* sect1,
|
| }
|
| sect1->validate();
|
| sect2->validate();
|
| +#if DEBUG_T_SECT_LOOP_COUNT
|
| + intersections->debugBumpLoopCount(SkIntersections::kIterations_DebugLoop);
|
| +#endif
|
| // if there are 9 or more continuous spans on both sects, suspect coincidence
|
| if (sect1->fActiveCount >= COINCIDENT_SPAN_COUNT
|
| && sect2->fActiveCount >= COINCIDENT_SPAN_COUNT) {
|
| + if (coinLoopCount == kMaxCoinLoopCount) {
|
| + start1s = sect1->fHead->fStartT;
|
| + start1e = sect1->tail()->fEndT;
|
| + }
|
| sect1->coincidentCheck(sect2);
|
| sect1->validate();
|
| sect2->validate();
|
| +#if DEBUG_T_SECT_LOOP_COUNT
|
| + intersections->debugBumpLoopCount(SkIntersections::kCoinCheck_DebugLoop);
|
| +#endif
|
| + if (!--coinLoopCount) {
|
| + /* All known working cases resolve in two tries. Sadly, cubicConicTests[0]
|
| + gets stuck in a loop. It adds an extension to allow a coincident end
|
| + perpendicular to track its intersection in the opposite curve. However,
|
| + the bounding box of the extension does not intersect the original curve,
|
| + so the extension is discarded, only to be added again the next time around. */
|
| + sect1->coincidentForce(sect2, start1s, start1e);
|
| + sect1->validate();
|
| + sect2->validate();
|
| + }
|
| }
|
| if (sect1->fActiveCount >= COINCIDENT_SPAN_COUNT
|
| && sect2->fActiveCount >= COINCIDENT_SPAN_COUNT) {
|
| @@ -1969,6 +2054,9 @@ void SkTSect<TCurve, OppCurve>::BinarySearch(SkTSect<TCurve, OppCurve>* sect1,
|
| sect1->removeByPerpendicular(sect2);
|
| sect1->validate();
|
| sect2->validate();
|
| +#if DEBUG_T_SECT_LOOP_COUNT
|
| + intersections->debugBumpLoopCount(SkIntersections::kComputePerp_DebugLoop);
|
| +#endif
|
| if (sect1->collapsed() > TCurve::kMaxIntersections) {
|
| break;
|
| }
|
|
|