diff options
author | caryclark@google.com <caryclark@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2012-08-02 20:08:21 +0000 |
---|---|---|
committer | caryclark@google.com <caryclark@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2012-08-02 20:08:21 +0000 |
commit | 534aa5b9460639a09b9dc30d29e77782e44b8fff (patch) | |
tree | 65e6b14b072baadf682f09753b7e115a7347015e | |
parent | 795cd47342509da7924e703bc5c8503cbf00b10a (diff) |
shape ops work in progress
git-svn-id: http://skia.googlecode.com/svn/trunk@4939 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r-- | experimental/Intersection/Simplify.cpp | 456 | ||||
-rw-r--r-- | experimental/Intersection/SimplifyFindTop_Test.cpp | 3 | ||||
-rw-r--r-- | experimental/Intersection/SimplifyNew_Test.cpp | 158 | ||||
-rw-r--r-- | experimental/Intersection/op.htm | 92 |
4 files changed, 517 insertions, 192 deletions
diff --git a/experimental/Intersection/Simplify.cpp b/experimental/Intersection/Simplify.cpp index 53abe8b07d..80846c23e0 100644 --- a/experimental/Intersection/Simplify.cpp +++ b/experimental/Intersection/Simplify.cpp @@ -27,7 +27,7 @@ int gDebugMaxWindValue = SK_MaxS32; #define DEBUG_UNUSED 0 // set to expose unused functions -#if 0 // set to 1 for multiple thread -- no debugging +#if 01 // set to 1 for multiple thread -- no debugging const bool gRunTestsInOneThread = false; @@ -51,7 +51,7 @@ const bool gRunTestsInOneThread = true; #define DEBUG_ADD_INTERSECTING_TS 0 #define DEBUG_ADD_T_PAIR 0 #define DEBUG_CONCIDENT 0 -#define DEBUG_CROSS 1 +#define DEBUG_CROSS 0 #define DEBUG_DUMP 1 #define DEBUG_MARK_DONE 1 #define DEBUG_PATH_CONSTRUCTION 1 @@ -61,7 +61,7 @@ const bool gRunTestsInOneThread = true; #endif -#if (DEBUG_ACTIVE_SPANS || DEBUG_CONCIDENT) && !DEBUG_DUMP +#if (DEBUG_ACTIVE_SPANS || DEBUG_CONCIDENT || DEBUG_SORT) && !DEBUG_DUMP #undef DEBUG_DUMP #define DEBUG_DUMP 1 #endif @@ -492,6 +492,7 @@ public: } bool firstBump(int sumWinding) const { + SkDebugf("%s sign=%d sumWinding=%d\n", __FUNCTION__, sign(), sumWinding); return sign() * sumWinding > 0; } @@ -1237,6 +1238,57 @@ public: SkASSERT(0); // incomplete return false; } + + int computeSum(int startIndex, int endIndex) { + SkTDArray<Angle> angles; + addTwoAngles(startIndex, endIndex, angles); + buildAngles(endIndex, angles); + SkTDArray<Angle*> sorted; + sortAngles(angles, sorted); + int angleCount = angles.count(); + const Angle* angle; + const Segment* base; + int winding; + int firstIndex = 0; + do { + angle = sorted[firstIndex]; + base = angle->segment(); + winding = base->windSum(angle); + if (winding != SK_MinS32) { + break; + } + if (++firstIndex == angleCount) { + return SK_MinS32; + } + } while (true); + // turn winding into contourWinding + int spanWinding = base->spanSign(angle->start(), angle->end()); + if (spanWinding * winding < 0) { + winding += spanWinding; + } + #if DEBUG_SORT + base->debugShowSort(sorted, firstIndex, winding); + #endif + int nextIndex = firstIndex + 1; + int lastIndex = firstIndex != 0 ? firstIndex : angleCount; + winding -= base->windBump(angle); + do { + if (nextIndex == angleCount) { + nextIndex = 0; + } + angle = sorted[nextIndex]; + Segment* segment = angle->segment(); + int maxWinding = winding; + winding -= segment->windBump(angle); + if (segment->windSum(nextIndex) == SK_MinS32) { + if (abs(maxWinding) < abs(winding) || maxWinding * winding < 0) { + maxWinding = winding; + } + segment->markAndChaseWinding(angle, maxWinding); + } + } while (++nextIndex != lastIndex); + return windSum(SkMin32(startIndex, endIndex)); + } int crossedSpan(const SkPoint& basePt, SkScalar& bestY, double& hitT) const { int bestT = -1; @@ -1277,6 +1329,40 @@ public: return bestT; } + bool crossedSpanHalves(const SkPoint& basePt, bool leftHalf, bool rightHalf) { + // if a segment is connected to this one, consider it crossing + int tIndex; + if (fPts[0].fX == basePt.fX) { + tIndex = 0; + do { + const Span& sSpan = fTs[tIndex]; + const Segment* sOther = sSpan.fOther; + if (!sOther->fTs[sSpan.fOtherIndex].fWindValue) { + continue; + } + if (leftHalf ? sOther->fBounds.fLeft < basePt.fX + : sOther->fBounds.fRight > basePt.fX) { + return true; + } + } while (fTs[++tIndex].fT == 0); + } + if (fPts[fVerb].fX == basePt.fX) { + tIndex = fTs.count() - 1; + do { + const Span& eSpan = fTs[tIndex]; + const Segment* eOther = eSpan.fOther; + if (!eOther->fTs[eSpan.fOtherIndex].fWindValue) { + continue; + } + if (leftHalf ? eOther->fBounds.fLeft < basePt.fX + : eOther->fBounds.fRight > basePt.fX) { + return true; + } + } while (fTs[--tIndex].fT == 1); + } + return false; + } + bool decrementSpan(Span* span) { SkASSERT(span->fWindValue > 0); if (--(span->fWindValue) == 0) { @@ -1327,19 +1413,16 @@ public: Segment* findNext(SkTDArray<Span*>& chase, bool firstFind, bool active, const int startIndex, const int endIndex, int& nextStart, int& nextEnd, int& winding, int& spanWinding) { - int sumWinding = winding + spanWinding; - if (sumWinding == 0) { - sumWinding = spanWinding; - } - bool insideContour = active && winding && winding * sumWinding < 0; - if (insideContour) { - sumWinding = winding; - } - + int outerWinding = winding; + int innerWinding = winding + spanWinding; #if DEBUG_WINDING - SkDebugf("%s winding=%d spanWinding=%d sumWinding=%d\n", - __FUNCTION__, winding, spanWinding, sumWinding); + SkDebugf("%s winding=%d spanWinding=%d outerWinding=%d innerWinding=%d\n", + __FUNCTION__, winding, spanWinding, outerWinding, innerWinding); #endif + if (abs(outerWinding) < abs(innerWinding) + || outerWinding * innerWinding < 0) { + outerWinding = innerWinding; + } SkASSERT(startIndex != endIndex); int count = fTs.count(); SkASSERT(startIndex < endIndex ? startIndex < count - 1 @@ -1352,7 +1435,10 @@ public: if (isSimple(end)) { // mark the smaller of startIndex, endIndex done, and all adjacent // spans with the same T value (but not 'other' spans) - markDone(SkMin32(startIndex, endIndex), sumWinding); + #if DEBUG_WINDING + SkDebugf("%s simple\n", __FUNCTION__); + #endif + markDone(SkMin32(startIndex, endIndex), outerWinding); other = endSpan->fOther; nextStart = endSpan->fOtherIndex; double startT = other->fTs[nextStart].fT; @@ -1375,25 +1461,19 @@ public: int firstIndex = findStartingEdge(sorted, startIndex, end); SkASSERT(firstIndex >= 0); #if DEBUG_SORT - debugShowSort(sorted, firstIndex, winding, sumWinding); + debugShowSort(sorted, firstIndex, winding); #endif - bool doBump = sorted[firstIndex]->firstBump(sumWinding); + SkASSERT(sorted[firstIndex]->segment() == this); #if DEBUG_WINDING - SkDebugf("%s sumWinding=%d sign=%d (%sbump)\n", __FUNCTION__, - sumWinding, sorted[firstIndex]->sign(), doBump ? "" : "no "); + SkDebugf("%s sign=%d\n", __FUNCTION__, sorted[firstIndex]->sign()); #endif - bool innerSwap = active && (doBump || insideContour); - int startWinding = sumWinding; - // SkASSERT(SkSign32(sumWinding) == SkSign32(winding) || winding == 0); - if (doBump || insideContour) { - sumWinding -= windBump(sorted[firstIndex]); - } + int sumWinding = winding - windBump(sorted[firstIndex]); int nextIndex = firstIndex + 1; int lastIndex = firstIndex != 0 ? firstIndex : angleCount; const Angle* foundAngle = NULL; bool foundDone = false; // iterate through the angle, and compute everyone's winding - bool toggleWinding = false; + int toggleWinding = SK_MinS32; bool flipFound = false; int flipped = 1; Segment* nextSegment; @@ -1413,13 +1493,13 @@ public: if (maxWinding * sumWinding < 0) { flipFound ^= true; #if DEBUG_WINDING - SkDebugf("flipFound maxWinding=%d sumWinding=%d\n", - maxWinding, sumWinding); + SkDebugf("%s flipFound=%d maxWinding=%d sumWinding=%d\n", + __FUNCTION__, flipFound, maxWinding, sumWinding); #endif } if (!sumWinding) { if (!active) { - markDone(SkMin32(startIndex, endIndex), startWinding); + markDone(SkMin32(startIndex, endIndex), outerWinding); nextSegment->markWinding(SkMin32(nextAngle->start(), nextAngle->end()), maxWinding); #if DEBUG_WINDING @@ -1430,30 +1510,42 @@ public: if (!foundAngle || foundDone) { foundAngle = nextAngle; foundDone = nextSegment->done(*nextAngle); - if (flipFound || (maxWinding * startWinding < 0)) { + if (flipFound || (maxWinding * outerWinding < 0)) { flipped = -flipped; #if DEBUG_WINDING - SkDebugf("flipped flipFound=%d maxWinding=%d startWinding=%d\n", - flipFound, maxWinding, startWinding); + SkDebugf("%s flipped=%d flipFound=%d maxWinding=%d" + " outerWinding=%d\n", __FUNCTION__, flipped, + flipFound, maxWinding, outerWinding); #endif } } continue; } - if (!maxWinding && innerSwap && !foundAngle) { - if (sumWinding * startWinding < 0 && flipped > 0) { + if (!maxWinding && !foundAngle) { + #if DEBUG_WINDING + if (flipped > 0) { + SkDebugf("%s sumWinding=%d * outerWinding=%d < 0 (%s)\n", + __FUNCTION__, sumWinding, outerWinding, + sumWinding * outerWinding < 0 ? "true" : "false"); + } + #endif + if (sumWinding * outerWinding < 0 && flipped > 0) { + #if DEBUG_WINDING + SkDebugf("%s toggleWinding=%d\n", __FUNCTION__, sumWinding); + #endif + toggleWinding = sumWinding; + } else if (outerWinding != sumWinding) { #if DEBUG_WINDING - SkDebugf("%s toggleWinding\n"); + SkDebugf("%s outerWinding=%d != sumWinding=%d winding=%d\n", + __FUNCTION__, outerWinding, sumWinding, winding); #endif - toggleWinding = true; - } else if (startWinding != sumWinding) { winding = sumWinding; } foundAngle = nextAngle; if (flipFound) { - flipped = -1; + flipped = -flipped; #if DEBUG_WINDING - SkDebugf("flipped flipFound=%d\n", flipFound); + SkDebugf("%s flipped flipFound=%d\n", __FUNCTION__, flipFound); #endif } } @@ -1465,11 +1557,12 @@ public: // as done, record the winding value, and mark connected unambiguous // segments as well. if (nextSegment->windSum(nextAngle) == SK_MinS32) { - if (abs(maxWinding) < abs(sumWinding)) { + if (abs(maxWinding) < abs(sumWinding) + || maxWinding * sumWinding < 0) { maxWinding = sumWinding; } Span* last; - if (foundAngle || innerSwap) { + if (foundAngle) { last = nextSegment->markAndChaseWinding(nextAngle, maxWinding); } else { last = nextSegment->markAndChaseDone(nextAngle, maxWinding); @@ -1480,7 +1573,7 @@ public: } } while (++nextIndex != lastIndex); SkASSERT(sorted[firstIndex]->segment() == this); - markDone(SkMin32(startIndex, endIndex), startWinding); + markDone(SkMin32(startIndex, endIndex), outerWinding); if (!foundAngle) { return NULL; } @@ -1489,20 +1582,10 @@ public: nextSegment = foundAngle->segment(); spanWinding = SkSign32(spanWinding) * flipped * nextSegment->windValue( SkMin32(nextStart, nextEnd)); - if (toggleWinding) { - if (winding) { - winding = 0; - } else { - winding = -startWinding; - } + if (toggleWinding != SK_MinS32) { + winding = toggleWinding; + spanWinding = -spanWinding; } - #if 0 - int min = SkMin32(nextStart, nextEnd); - int sign = foundAngle->sign(); - int windSum = nextSegment->windSum(min); - int windValue = nextSegment->windValue(min); - SkASSERT(winding + sign * windValue == windSum); - #endif #if DEBUG_WINDING SkDebugf("%s spanWinding=%d\n", __FUNCTION__, spanWinding); #endif @@ -1694,6 +1777,17 @@ public: } while (leftSegment->fTs[SkMin32(tIndex, endIndex)].fDone); return leftSegment; } + + bool firstBump(const Angle* angle, int sumWinding) const { + int winding = spanSign(angle->start(), angle->end()); + sumWinding -= winding; + if (sumWinding == 0) { + sumWinding = winding; + } + bool result = angle->sign() * sumWinding > 0; + SkASSERT(result == angle->firstBump(sumWinding)); + return result; + } // FIXME: not crazy about this // when the intersections are performed, the other index is into an @@ -1862,7 +1956,7 @@ public: } #if DEBUG_MARK_DONE const SkPoint& pt = xyAtT(&span); - SkDebugf("%s segment=%d index=%d t=%1.9g pt=(%1.9g,%1.9g) wind=%d\n", + SkDebugf("%s id=%d index=%d t=%1.9g pt=(%1.9g,%1.9g) wind=%d\n", __FUNCTION__, fID, lesser, span.fT, pt.fX, pt.fY, winding); #endif span.fDone = true; @@ -1879,7 +1973,7 @@ public: } #if DEBUG_MARK_DONE const SkPoint& pt = xyAtT(&span); - SkDebugf("%s segment=%d index=%d t=%1.9g pt=(%1.9g,%1.9g) wind=%d\n", + SkDebugf("%s id=%d index=%d t=%1.9g pt=(%1.9g,%1.9g) wind=%d\n", __FUNCTION__, fID, index, span.fT, pt.fX, pt.fY, winding); #endif span.fDone = true; @@ -1903,7 +1997,7 @@ public: SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding); #if DEBUG_MARK_DONE const SkPoint& pt = xyAtT(&span); - SkDebugf("%s segment=%d index=%d t=%1.9g pt=(%1.9g,%1.9g) wind=%d\n", + SkDebugf("%s id=%d index=%d t=%1.9g pt=(%1.9g,%1.9g) wind=%d\n", __FUNCTION__, fID, lesser, span.fT, pt.fX, pt.fY, winding); #endif SkASSERT(abs(winding) <= gDebugMaxWindSum); @@ -1919,7 +2013,7 @@ public: SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding); #if DEBUG_MARK_DONE const SkPoint& pt = xyAtT(&span); - SkDebugf("%s segment=%d index=%d t=%1.9g pt=(%1.9g,%1.9g) wind=%d\n", + SkDebugf("%s id=%d index=%d t=%1.9g pt=(%1.9g,%1.9g) wind=%d\n", __FUNCTION__, fID, index, span.fT, pt.fX, pt.fY, winding); #endif SkASSERT(abs(winding) <= gDebugMaxWindSum); @@ -2081,7 +2175,7 @@ public: #if DEBUG_CONCIDENT // assert if pair has not already been added - void debugAddTPair(double t, const Segment& other, double otherT) { + void debugAddTPair(double t, const Segment& other, double otherT) const { for (int i = 0; i < fTs.count(); ++i) { if (fTs[i].fT == t && fTs[i].fOther == &other && fTs[i].fOtherT == otherT) { return; @@ -2091,8 +2185,14 @@ public: } #endif +#if DEBUG_DUMP + int debugID() const { + return fID; + } +#endif + #if DEBUG_CONCIDENT - void debugShowTs() { + void debugShowTs() const { SkDebugf("%s %d", __FUNCTION__, fID); for (int i = 0; i < fTs.count(); ++i) { SkDebugf(" [o=%d %1.9g (%1.9g,%1.9g) w=%d]", fTs[i].fOther->fID, @@ -2103,7 +2203,7 @@ public: #endif #if DEBUG_ACTIVE_SPANS - void debugShowActiveSpans(int contourID, int segmentIndex) { + void debugShowActiveSpans() const { if (done()) { return; } @@ -2111,8 +2211,7 @@ public: if (fTs[i].fDone) { continue; } - SkDebugf("%s contour=%d segment=%d (%d)", __FUNCTION__, contourID, - segmentIndex, fID); + SkDebugf("%s id=%d", __FUNCTION__, fID); SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY); for (int vIndex = 1; vIndex <= fVerb; ++vIndex) { SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY); @@ -2121,27 +2220,26 @@ public: SkDebugf(") fT=%d (%1.9g) (%1.9g,%1.9g)", i, fTs[i].fT, xAtT(span), yAtT(i)); const Segment* other = fTs[i].fOther; - SkDebugf(" other=%d otherT=%1.9g otherIndex=%d", other->fID, - fTs[i].fOtherT, fTs[i].fOtherIndex); - SkDebugf(" windSum=%d windValue=%d\n", fTs[i].fWindSum, - fTs[i].fWindValue); + SkDebugf(" other=%d otherT=%1.9g otherIndex=%d windSum=", + other->fID, fTs[i].fOtherT, fTs[i].fOtherIndex); + if (fTs[i].fWindSum == SK_MinS32) { + SkDebugf("?"); + } else { + SkDebugf("%d", fTs[i].fWindSum); + } + SkDebugf(" windValue=%d\n", fTs[i].fWindValue); } } #endif #if DEBUG_SORT void debugShowSort(const SkTDArray<Angle*>& angles, int first, - int contourWinding, int sumWinding) { + const int contourWinding) const { SkASSERT(angles[first]->segment() == this); - bool doBump = angles[first]->firstBump(sumWinding); - bool insideContour = contourWinding && contourWinding * sumWinding < 0; - int windSum = insideContour ? contourWinding : sumWinding; - int lastSum = windSum; - if (insideContour || doBump) { - windSum -= windBump(angles[first]); - } else { - lastSum += windBump(angles[first]); - } + int lastSum = contourWinding; + int windSum = lastSum - windBump(angles[first]); + SkDebugf("%s contourWinding=%d bump=%d\n", __FUNCTION__, + contourWinding, windBump(angles[first])); int index = first; bool firstTime = true; do { @@ -2152,9 +2250,7 @@ public: const Span& sSpan = segment.fTs[start]; const Span& eSpan = segment.fTs[end]; const Span& mSpan = segment.fTs[SkMin32(start, end)]; - if (firstTime) { - firstTime = false; - } else { + if (!firstTime) { lastSum = windSum; windSum -= segment.windBump(&angle); } @@ -2169,10 +2265,29 @@ public: if (index == angles.count()) { index = 0; } + if (firstTime) { + firstTime = false; + } } while (index != first); } #endif +#if DEBUG_WINDING + bool debugVerifyWinding(int start, int end, int winding) const { + const Span& span = fTs[SkMin32(start, end)]; + int spanWinding = span.fWindSum; + if (spanWinding == SK_MinS32) { + return true; + } + int spanSign = SkSign32(start - end); + int signedVal = spanSign * span.fWindValue; + if (signedVal < 0) { + spanWinding -= signedVal; + } + return span.fWindSum == winding; + } +#endif + private: const SkPoint* fPts; SkPath::Verb fVerb; @@ -2274,10 +2389,10 @@ public: for (int test = 0; test < segmentCount; ++test) { Segment* testSegment = &fSegments[test]; const SkRect& bounds = testSegment->bounds(); - if (bounds.fTop < bestY) { + if (bounds.fBottom <= bestY) { continue; } - if (bounds.fTop > basePt.fY) { + if (bounds.fTop >= basePt.fY) { continue; } if (bounds.fLeft > basePt.fX) { @@ -2286,6 +2401,17 @@ public: if (bounds.fRight < basePt.fX) { continue; } + if (bounds.fLeft == bounds.fRight) { + continue; + } + #if 0 + bool leftHalf = bounds.fLeft == basePt.fX; + bool rightHalf = bounds.fRight == basePt.fX; + if ((leftHalf || rightHalf) && !testSegment->crossedSpanHalves( + basePt, leftHalf, rightHalf)) { + continue; + } + #endif double testHitT; int testT = testSegment->crossedSpan(basePt, bestY, testHitT); if (testT >= 0) { @@ -2324,7 +2450,6 @@ public: fSegments.reset(); fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax); fContainsCurves = fContainsIntercepts = false; - fWindingSum = SK_MinS32; } void resolveCoincidence(int winding) { @@ -2382,11 +2507,6 @@ public: return fSegments; } - void setWinding(int winding) { - SkASSERT(fWindingSum < 0 || fWindingSum == winding); - fWindingSum = winding; - } - // OPTIMIZATION: feel pretty uneasy about this. It seems like once again // we need to sort and walk edges in y, but that on the surface opens the // same can of worms as before. But then, this is a rough sort based on @@ -2433,22 +2553,6 @@ public: return segment.verb() + 1; } - int windSum() { - if (fWindingSum >= 0) { - return fWindingSum; - } - // check peers - int count = fCrosses.count(); - for (int index = 0; index < count; ++index) { - const Contour* crosser = fCrosses[index]; - if (0 <= crosser->fWindingSum) { - fWindingSum = crosser->fWindingSum; - break; - } - } - return fWindingSum; - } - #if DEBUG_TEST SkTArray<Segment>& debugSegments() { return fSegments; @@ -2480,7 +2584,7 @@ public: #if DEBUG_ACTIVE_SPANS void debugShowActiveSpans() { for (int index = 0; index < fSegments.count(); ++index) { - fSegments[index].debugShowActiveSpans(fID, index); + fSegments[index].debugShowActiveSpans(); } } #endif @@ -2507,7 +2611,6 @@ private: Bounds fBounds; bool fContainsIntercepts; bool fContainsCurves; - int fWindingSum; // initial winding number outside #if DEBUG_DUMP int fID; #endif @@ -3041,14 +3144,14 @@ static void coincidenceCheck(SkTDArray<Contour*>& contourList, int winding) { // two contours touch, so we need only look at contours not touching this one. // OPTIMIZATION: sort contourList vertically to avoid linear walk static int innerContourCheck(SkTDArray<Contour*>& contourList, - Contour* baseContour, const Segment* current, int index, int endIndex) { + const Segment* current, int index, int endIndex) { const SkPoint& basePt = current->xyAtT(endIndex); int contourCount = contourList.count(); SkScalar bestY = SK_ScalarMin; const Segment* test = NULL; int tIndex; double tHit; - bool checkCrosses = true; + // bool checkCrosses = true; for (int cTest = 0; cTest < contourCount; ++cTest) { Contour* contour = contourList[cTest]; if (basePt.fY < contour->bounds().fTop) { @@ -3057,6 +3160,7 @@ static int innerContourCheck(SkTDArray<Contour*>& contourList, if (bestY > contour->bounds().fBottom) { continue; } +#if 0 // even though the contours crossed, if spans cancel through concidence, // the contours may be not have any span links to chase, and the current // segment may be isolated. Detect this by seeing if current has @@ -3071,19 +3175,20 @@ static int innerContourCheck(SkTDArray<Contour*>& contourList, } checkCrosses = false; } +#endif const Segment* next = contour->crossedSegment(basePt, bestY, tIndex, tHit); if (next) { test = next; } } if (!test) { - baseContour->setWinding(0); return 0; } int winding, windValue; // If the ray hit the end of a span, we need to construct the wheel of // angles to find the span closest to the ray -- even if there are just // two spokes on the wheel. + const Angle* angle = NULL; if (fabs(tHit - test->t(tIndex)) < FLT_EPSILON) { SkTDArray<Angle> angles; int end = test->nextSpan(tIndex, 1); @@ -3099,7 +3204,7 @@ static int innerContourCheck(SkTDArray<Contour*>& contourList, // hour after 6 o'clock sortAngles(angles, sorted); #if DEBUG_SORT - sorted[0]->segment()->debugShowSort(sorted, 0, 0, 0); + sorted[0]->segment()->debugShowSort(sorted, 0, 0); #endif // walk the sorted angle fan to find the lowest angle // above the base point. Currently, the first angle in the sorted array @@ -3130,20 +3235,18 @@ static int innerContourCheck(SkTDArray<Contour*>& contourList, SkASSERT(left >= 0 || right >= 0); if (left < 0) { left = right; + } else if (left >= 0 && mid >= 0 && right >= 0 + && sorted[mid]->sign() == sorted[right]->sign()) { + left = right; } - const Angle* angle = sorted[left]; + angle = sorted[left]; test = angle->segment(); winding = test->windSum(angle); SkASSERT(winding != SK_MinS32); windValue = test->windValue(angle); - #if 0 - if (angle->firstBump(winding)) { - winding -= test->windBump(angle); - } - #endif #if DEBUG_WINDING - SkDebugf("%s angle winding=%d windValue=%d\n", __FUNCTION__, winding, - windValue); + SkDebugf("%s angle winding=%d windValue=%d sign=%d\n", __FUNCTION__, winding, + windValue, angle->sign()); #endif } else { winding = test->windSum(tIndex); @@ -3159,19 +3262,19 @@ static int innerContourCheck(SkTDArray<Contour*>& contourList, #if DEBUG_WINDING SkDebugf("%s dx=%1.9g\n", __FUNCTION__, dx); #endif - SkASSERT(dx != 0); - if (winding * dx > 0) { // if same signs, result is negative + if (dx == 0) { + SkASSERT(angle); + if (test->firstBump(angle, winding)) { + winding -= test->windBump(angle); + } + } else if (winding * dx > 0) { // if same signs, result is negative winding += dx > 0 ? -windValue : windValue; #if DEBUG_WINDING SkDebugf("%s final winding=%d\n", __FUNCTION__, winding); #endif } - start here; + // start here; // we're broken because we find a vertical span - // also, does it make sense to compute a contour's winding? Won't it - // depend on coincidence and (e.g. a figure eight) self intersection? - // (hopefully no one uses this) so remove it - baseContour->setWinding(winding); return winding; } @@ -3181,8 +3284,7 @@ static int innerContourCheck(SkTDArray<Contour*>& contourList, // Once the segment array is built, there's no reason I can think of not to // sort it in Y. hmmm // FIXME: return the contour found to pass to inner contour check -static Segment* findTopContour(SkTDArray<Contour*>& contourList, - Contour*& topContour) { +static Segment* findTopContour(SkTDArray<Contour*>& contourList) { int contourCount = contourList.count(); int cIndex = 0; Segment* topStart; @@ -3195,7 +3297,6 @@ static Segment* findTopContour(SkTDArray<Contour*>& contourList, if (!topStart) { return NULL; } - topContour = contour; while (++cIndex < contourCount) { contour = contourList[cIndex]; if (bestY < contour->bounds().fTop) { @@ -3206,7 +3307,6 @@ static Segment* findTopContour(SkTDArray<Contour*>& contourList, if (!test || bestY <= testY) { continue; } - topContour = contour; topStart = test; bestY = testY; } @@ -3237,18 +3337,24 @@ static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex, // find first angle, initialize winding to computed fWindSum int firstIndex = -1; const Angle* angle; - int spanWinding; + int winding; do { angle = sorted[++firstIndex]; - spanWinding = angle->segment()->windSum(angle); - } while (spanWinding == SK_MinS32); - #if DEBUG_SORT - angle->segment()->debugShowSort(sorted, firstIndex, contourWinding, - spanWinding); + segment = angle->segment(); + winding = segment->windSum(angle); + } while (winding == SK_MinS32); + int spanWinding = segment->spanSign(angle->start(), angle->end()); + #if DEBUG_WINDING + SkDebugf("%s winding=%d spanWinding=%d contourWinding=%d\n", + __FUNCTION__, winding, spanWinding, contourWinding); #endif - if (angle->firstBump(spanWinding)) { - spanWinding -= angle->segment()->windBump(angle); + // turn swinding into contourWinding + if (spanWinding * winding < 0) { + winding += spanWinding; } + #if DEBUG_SORT + segment->debugShowSort(sorted, firstIndex, winding); + #endif // we care about first sign and whether wind sum indicates this // edge is inside or outside. Maybe need to pass span winding // or first winding or something into this function? @@ -3257,30 +3363,35 @@ static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex, int nextIndex = firstIndex + 1; int angleCount = sorted.count(); int lastIndex = firstIndex != 0 ? firstIndex : angleCount; + angle = sorted[firstIndex]; + winding -= angle->segment()->windBump(angle); do { SkASSERT(nextIndex != firstIndex); if (nextIndex == angleCount) { nextIndex = 0; } - const Angle* angle = sorted[nextIndex]; + angle = sorted[nextIndex]; segment = angle->segment(); - int maxWinding = spanWinding; - spanWinding -= segment->windBump(angle); - if (maxWinding * spanWinding < 0) { - SkDebugf("%s flipped sign %d %d\n", __FUNCTION__, maxWinding, spanWinding); - } + int maxWinding = winding; + winding -= segment->windBump(angle); + #if DEBUG_SORT + SkDebugf("%s id=%d maxWinding=%d winding=%d\n", __FUNCTION__, + segment->debugID(), maxWinding, winding); + #endif tIndex = angle->start(); endIndex = angle->end(); int lesser = SkMin32(tIndex, endIndex); const Span& nextSpan = segment->span(lesser); if (!nextSpan.fDone) { +#if 1 // FIXME: this be wrong. assign startWinding if edge is in // same direction. If the direction is opposite, winding to // assign is flipped sign or +/- 1? - if (abs(maxWinding) < abs(spanWinding)) { - maxWinding = spanWinding; + if (abs(maxWinding) < abs(winding)) { + maxWinding = winding; } segment->markWinding(lesser, maxWinding); +#endif break; } } while (++nextIndex != lastIndex); @@ -3314,8 +3425,7 @@ static bool windingIsActive(int winding, int spanWinding) { static void bridge(SkTDArray<Contour*>& contourList, SkPath& simple) { bool firstContour = true; do { - Contour* topContour; - Segment* topStart = findTopContour(contourList, topContour); + Segment* topStart = findTopContour(contourList); if (!topStart) { break; } @@ -3328,9 +3438,17 @@ static void bridge(SkTDArray<Contour*>& contourList, SkPath& simple) { contourWinding = 0; firstContour = false; } else { - contourWinding = innerContourCheck(contourList, topContour, current, - index, endIndex); + contourWinding = current->windSum(SkMin32(index, endIndex)); + // FIXME: don't I have to adjust windSum to get contourWinding? + if (contourWinding == SK_MinS32) { + contourWinding = current->computeSum(index, endIndex); + if (contourWinding == SK_MinS32) { + contourWinding = innerContourCheck(contourList, current, + index, endIndex); + } + } #if DEBUG_WINDING + // SkASSERT(current->debugVerifyWinding(index, endIndex, contourWinding)); SkDebugf("%s contourWinding=%d\n", __FUNCTION__, contourWinding); #endif } @@ -3338,16 +3456,6 @@ static void bridge(SkTDArray<Contour*>& contourList, SkPath& simple) { bool firstTime = true; int winding = contourWinding; int spanWinding = current->spanSign(index, endIndex); - int spanWindSum = current->windSum(SkMin32(index, endIndex)); - if (spanWindSum != SK_MinS32) { - int calcWinding = spanWindSum; - if (spanWinding > 0) { - // calcWinding -= spanWinding; - } - SkDebugf("%s *** winding=%d calcWinding=%d\n", __FUNCTION__, - winding, calcWinding); - winding = calcWinding; - } // FIXME: needs work. While it works in limited situations, it does // not always compute winding correctly. Active should be removed and instead // the initial winding should be correctly passed in so that if the @@ -3395,32 +3503,12 @@ static void bridge(SkTDArray<Contour*>& contourList, SkPath& simple) { break; } int lesser = SkMin32(index, endIndex); - spanWinding = current->windSum(lesser); - int spanValue = current->windValue(lesser); - SkASSERT(spanWinding != SK_MinS32); - #if DEBUG_WINDING - SkDebugf("%s spanWinding=%d winding=%d spanValue=%d\n", - __FUNCTION__, spanWinding, winding, spanValue); - #endif - if (abs(spanWinding) != spanValue) { - winding = spanWinding; - spanWinding = spanValue * SkSign32(spanWinding); + spanWinding = current->spanSign(index, endIndex); + winding = current->windSum(lesser); + if (spanWinding * winding > 0) { winding -= spanWinding; - #if DEBUG_WINDING - SkDebugf("%s != spanWinding=%d winding=%d\n", __FUNCTION__, - spanWinding, winding); - #endif - active = windingIsActive(winding, spanWinding); - } else if (winding) { - #if DEBUG_WINDING - SkDebugf("%s ->0 contourWinding=%d winding=%d\n", __FUNCTION__, - contourWinding, winding); - #endif - // start here; - // set active=false if it was false when chase was created - active = abs(winding) <= abs(spanWinding); - winding = 0; } + active = windingIsActive(winding, spanWinding); } while (true); } while (true); } diff --git a/experimental/Intersection/SimplifyFindTop_Test.cpp b/experimental/Intersection/SimplifyFindTop_Test.cpp index 9e8d2bbfe7..0c9c2e0803 100644 --- a/experimental/Intersection/SimplifyFindTop_Test.cpp +++ b/experimental/Intersection/SimplifyFindTop_Test.cpp @@ -27,8 +27,7 @@ static const SimplifyFindTopTest::Segment* testCommon( addIntersectTs(contourList[1], contourList[1]); } fixOtherTIndex(contourList); - SimplifyFindTopTest::Contour* top; - SimplifyFindTopTest::Segment* topStart = findTopContour(contourList, top); + SimplifyFindTopTest::Segment* topStart = findTopContour(contourList); const SimplifyFindTopTest::Segment* topSegment = topStart->findTop(index, end); return topSegment; diff --git a/experimental/Intersection/SimplifyNew_Test.cpp b/experimental/Intersection/SimplifyNew_Test.cpp index 2b7d4e44da..eeae035ed1 100644 --- a/experimental/Intersection/SimplifyNew_Test.cpp +++ b/experimental/Intersection/SimplifyNew_Test.cpp @@ -62,6 +62,20 @@ static void testLine3() { testSimplifyx(path); } +static void testLine3a() { + SkPath path, simple; + addInnerCWTriangle(path); + addOuterCCWTriangle(path); + testSimplifyx(path); +} + +static void testLine3b() { + SkPath path, simple; + addInnerCCWTriangle(path); + addOuterCCWTriangle(path); + testSimplifyx(path); +} + static void testLine4() { SkPath path, simple; addOuterCCWTriangle(path); @@ -641,12 +655,127 @@ static void testLine66() { testSimplifyx(path); } +static void testLine67() { + SkPath path, simple; + path.addRect(0, 0, 60, 60, (SkPath::Direction) 0); + path.addRect(10, 40, 30, 30, (SkPath::Direction) 0); + path.addRect(24, 20, 36, 30, (SkPath::Direction) 0); + path.addRect(32, 0, 36, 41, (SkPath::Direction) 0); + testSimplifyx(path); +} + +static void testLine68a() { + SkPath path, simple; + path.addRect(0, 0, 8, 8, (SkPath::Direction) 0); + path.addRect(2, 2, 6, 6, (SkPath::Direction) 0); + path.addRect(1, 2, 4, 2, (SkPath::Direction) 0); + testSimplifyx(path); +} + +static void testLine68b() { + SkPath path, simple; + path.addRect(0, 0, 8, 8, (SkPath::Direction) 0); + path.addRect(2, 2, 6, 6, (SkPath::Direction) 1); + path.addRect(1, 2, 2, 2, (SkPath::Direction) 0); + testSimplifyx(path); +} + +static void testLine68c() { + SkPath path, simple; + path.addRect(0, 0, 8, 8, (SkPath::Direction) 1); + path.addRect(2, 2, 6, 6, (SkPath::Direction) 0); + path.addRect(1, 2, 4, 2, (SkPath::Direction) 0); + testSimplifyx(path); +} + +static void testLine68d() { + SkPath path, simple; + path.addRect(0, 0, 8, 8, (SkPath::Direction) 1); + path.addRect(2, 2, 6, 6, (SkPath::Direction) 1); + path.addRect(1, 2, 4, 2, (SkPath::Direction) 0); + testSimplifyx(path); +} + +static void testLine68e() { + SkPath path, simple; + path.addRect(0, 0, 8, 8, (SkPath::Direction) 0); + path.addRect(0, 0, 8, 8, (SkPath::Direction) 0); + path.addRect(2, 2, 6, 6, (SkPath::Direction) 1); + path.addRect(1, 2, 2, 2, (SkPath::Direction) 0); + testSimplifyx(path); +} + +static void testLine68f() { + SkPath path, simple; + path.addRect(0, 0, 8, 8, (SkPath::Direction) 0); + path.addRect(2, 2, 6, 6, (SkPath::Direction) 1); + path.addRect(2, 2, 6, 6, (SkPath::Direction) 1); + path.addRect(1, 2, 2, 2, (SkPath::Direction) 0); + testSimplifyx(path); +} + +static void testLine68g() { + SkPath path, simple; + path.addRect(0, 0, 8, 8, (SkPath::Direction) 0); + path.addRect(0, 0, 8, 8, (SkPath::Direction) 0); + path.addRect(2, 2, 6, 6, (SkPath::Direction) 1); + path.addRect(2, 2, 6, 6, (SkPath::Direction) 1); + path.addRect(1, 2, 2, 2, (SkPath::Direction) 0); + testSimplifyx(path); +} + +static void testLine68h() { + SkPath path, simple; + path.addRect(0, 0, 8, 8, (SkPath::Direction) 0); + path.addRect(2, 2, 6, 6, (SkPath::Direction) 1); + path.addRect(2, 2, 6, 6, (SkPath::Direction) 1); + path.addRect(2, 2, 6, 6, (SkPath::Direction) 1); + path.addRect(1, 2, 2, 2, (SkPath::Direction) 0); + testSimplifyx(path); +} + +static void testLine69() { + SkPath path, simple; + path.addRect(0, 20, 20, 20, (SkPath::Direction) 0); + path.addRect(0, 20, 12, 30, (SkPath::Direction) 0); + path.addRect(12, 32, 21, 36, (SkPath::Direction) 0); + testSimplifyx(path); +} + +static void testLine70() { + SkPath path, simple; + path.addRect(0, 0, 20, 20, (SkPath::Direction) 0); + path.addRect(0, 24, 12, 12, (SkPath::Direction) 0); + path.addRect(12, 32, 21, 36, (SkPath::Direction) 1); + testSimplifyx(path); +} + +static void testLine71() { + SkPath path, simple; + path.addRect(0, 0, 20, 20, (SkPath::Direction) 0); + path.addRect(12, 0, 24, 24, (SkPath::Direction) 0); + path.addRect(12, 32, 21, 36, (SkPath::Direction) 0); + testSimplifyx(path); +} + static void (*firstTest)() = 0; static struct { void (*fun)(); const char* str; } tests[] = { + TEST(testLine71), + TEST(testLine70), + TEST(testLine69), + TEST(testLine68h), + TEST(testLine68g), + TEST(testLine68f), + TEST(testLine68e), + TEST(testLine68d), + TEST(testLine68c), + TEST(testLine68b), + TEST(testLine68a), + TEST(testLine67), TEST(testLine66), TEST(testLine65), TEST(testLine64), @@ -713,6 +842,8 @@ static struct { TEST(testLine6), TEST(testLine5), TEST(testLine4), + TEST(testLine3b), + TEST(testLine3a), TEST(testLine3), TEST(testLine2), TEST(testLine1), @@ -720,7 +851,24 @@ static struct { static const size_t testCount = sizeof(tests) / sizeof(tests[0]); +static struct { + void (*fun)(); + const char* str; +} subTests[] = { + TEST(testLine68h), + TEST(testLine68g), + TEST(testLine68f), + TEST(testLine68e), + TEST(testLine68d), + TEST(testLine68c), + TEST(testLine68b), + TEST(testLine68a), +}; + +static const size_t subTestCount = sizeof(subTests) / sizeof(subTests[0]); + static bool skipAll = false; +static bool runSubTests = false; void SimplifyNew_Test() { if (skipAll) { @@ -729,8 +877,16 @@ void SimplifyNew_Test() { #ifdef SK_DEBUG gDebugMaxWindSum = 4; gDebugMaxWindValue = 4; + size_t index; #endif - size_t index = testCount - 1; + if (runSubTests) { + index = subTestCount - 1; + do { + SkDebugf(" %s [%s]\n", __FUNCTION__, subTests[index].str); + (*subTests[index].fun)(); + } while (index--); + } + index = testCount - 1; if (firstTest) { while (index > 0 && tests[index].fun != firstTest) { --index; diff --git a/experimental/Intersection/op.htm b/experimental/Intersection/op.htm index 531812e299..7049f0262b 100644 --- a/experimental/Intersection/op.htm +++ b/experimental/Intersection/op.htm @@ -632,11 +632,84 @@ path.close(); path.addRect(12, 20, 24, 30, (SkPath::Direction) 0); </div> +<div id="testLine67"> + path.addRect(0, 0, 60, 60, (SkPath::Direction) 0); + path.addRect(10, 40, 30, 30, (SkPath::Direction) 0); + path.addRect(24, 20, 36, 30, (SkPath::Direction) 0); + path.addRect(32, 0, 36, 41, (SkPath::Direction) 0); +</div> + +<div id="testLine68a"> + path.addRect(0, 0, 8, 8, (SkPath::Direction) 0); + path.addRect(2, 2, 6, 6, (SkPath::Direction) 0); + path.addRect(1, 2, 4, 2, (SkPath::Direction) 0); +</div> + +<div id="testLine68b"> + path.addRect(0, 0, 8, 8, (SkPath::Direction) 0); + path.addRect(2, 2, 6, 6, (SkPath::Direction) 1); + path.addRect(1, 2, 4, 2, (SkPath::Direction) 0); +</div> + +<div id="testLine68c"> + path.addRect(0, 0, 8, 8, (SkPath::Direction) 1); + path.addRect(2, 2, 6, 6, (SkPath::Direction) 0); + path.addRect(1, 2, 4, 2, (SkPath::Direction) 0); +</div> + +<div id="testLine68d"> + path.addRect(0, 0, 8, 8, (SkPath::Direction) 1); + path.addRect(2, 2, 6, 6, (SkPath::Direction) 1); + path.addRect(1, 2, 4, 2, (SkPath::Direction) 0); +</div> + +<div id="testLine68e"> + path.addRect(0, 0, 8, 8, (SkPath::Direction) 0); + path.addRect(0, 0, 8, 8, (SkPath::Direction) 0); + path.addRect(2, 2, 6, 6, (SkPath::Direction) 1); + path.addRect(1, 2, 2, 2, (SkPath::Direction) 0); +</div> + +<div id="testLine68f"> + path.addRect(0, 0, 8, 8, (SkPath::Direction) 0); + path.addRect(2, 2, 6, 6, (SkPath::Direction) 1); + path.addRect(2, 2, 6, 6, (SkPath::Direction) 1); + path.addRect(1, 2, 2, 2, (SkPath::Direction) 0); +</div> + +<div id="testLine69"> + path.addRect(0, 20, 20, 20, (SkPath::Direction) 0); + path.addRect(0, 20, 12, 30, (SkPath::Direction) 0); + path.addRect(12, 32, 21, 36, (SkPath::Direction) 0); +</div> + +<div id="testLine70"> + path.addRect(0, 0, 20, 20, (SkPath::Direction) 0); + path.addRect(0, 24, 12, 12, (SkPath::Direction) 0); + path.addRect(12, 32, 21, 36, (SkPath::Direction) 1); +</div> + +<div id="testLine71"> + path.addRect(0, 0, 20, 20, (SkPath::Direction) 0); + path.addRect(12, 0, 24, 24, (SkPath::Direction) 0); + path.addRect(12, 32, 21, 36, (SkPath::Direction) 0); +</div> + </div> <script type="text/javascript"> var testDivs = [ + testLine71, + testLine70, + testLine69, + testLine68f, + testLine68e, + testLine68d, + testLine68c, + testLine68b, + testLine68a, + testLine67, testLine66, testLine65, testLine64, @@ -671,9 +744,9 @@ var testDivs = [ testLine35, testLine34, testLine33, - testLine30, testLine32, testLine31, + testLine30, testLine29, testLine28, testLine24, @@ -805,8 +878,8 @@ function parseRect(test, title) { function init(test) { var canvas = document.getElementById('canvas'); if (!canvas.getContext) return; - canvas.width = document.width; - canvas.height = document.height; + canvas.width = window.innerWidth - at_x; + canvas.height = window.innerHeight - at_y; ctx = canvas.getContext('2d'); var xmin = Infinity; var xmax = -Infinity; @@ -982,6 +1055,7 @@ function doKeyPress(evt) { var char = String.fromCharCode(evt.charCode); switch (char) { case 'N': + testIndex += 9; case 'n': if (++testIndex >= tests.length) testIndex = 0; @@ -989,6 +1063,7 @@ function doKeyPress(evt) { drawTop(); break; case 'P': + testIndex -= 9; case 'p': if (--testIndex < 0) testIndex = tests.length - 1; @@ -999,15 +1074,19 @@ function doKeyPress(evt) { case 't': break; case '-': - redraw(); + drawTop(); break; case '=': case '+': - redraw(); + drawTop(); break; } } +function doResize(evt) { + drawTop(); +} + function start() { for (i = 0; i < testDivs.length; ++i) { var title = testDivs[i].id.toString(); @@ -1020,6 +1099,9 @@ function start() { } drawTop(); window.addEventListener('keypress', doKeyPress, true); + window.onresize = function() { + drawTop(); + } } </script> |