diff options
author | caryclark@google.com <caryclark@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2012-07-23 12:14:49 +0000 |
---|---|---|
committer | caryclark@google.com <caryclark@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2012-07-23 12:14:49 +0000 |
commit | 47580694fbe974a065caf7c39c3d2075708c2018 (patch) | |
tree | 9bfc91cbdc71b2aaa913fd81ba8761208e58c910 /experimental | |
parent | a276975a62ef4d9941e40c831fdfe7852e0e243e (diff) |
shape ops work in progress
git-svn-id: http://skia.googlecode.com/svn/trunk@4713 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'experimental')
-rw-r--r-- | experimental/Intersection/EdgeWalker.cpp | 4 | ||||
-rw-r--r-- | experimental/Intersection/EdgeWalker_Test.h | 1 | ||||
-rw-r--r-- | experimental/Intersection/ShapeOps.h | 7 | ||||
-rw-r--r-- | experimental/Intersection/Simplify.cpp | 419 | ||||
-rw-r--r-- | experimental/Intersection/SimplifyAddIntersectingTs_Test.cpp | 2 | ||||
-rw-r--r-- | experimental/Intersection/SimplifyNew_Test.cpp | 215 | ||||
-rw-r--r-- | experimental/Intersection/SimplifyRect4x4_Test.cpp | 119 | ||||
-rw-r--r-- | experimental/Intersection/op.htm | 122 |
8 files changed, 684 insertions, 205 deletions
diff --git a/experimental/Intersection/EdgeWalker.cpp b/experimental/Intersection/EdgeWalker.cpp index 0f624b5633..4442e9226a 100644 --- a/experimental/Intersection/EdgeWalker.cpp +++ b/experimental/Intersection/EdgeWalker.cpp @@ -13,7 +13,7 @@ // FIXME: remove once debugging is complete #if 01 // set to 1 for no debugging whatsoever -const bool gRunTestsInOneThread = false; +//const bool gRunTestsInOneThread = false; #define DEBUG_ACTIVE_LESS_THAN 0 #define DEBUG_ADD 0 @@ -33,7 +33,7 @@ const bool gRunTestsInOneThread = false; #else -const bool gRunTestsInOneThread = true; +//const bool gRunTestsInOneThread = true; #define DEBUG_ACTIVE_LESS_THAN 0 #define DEBUG_ADD 01 diff --git a/experimental/Intersection/EdgeWalker_Test.h b/experimental/Intersection/EdgeWalker_Test.h index b35da6d351..e07e708f46 100644 --- a/experimental/Intersection/EdgeWalker_Test.h +++ b/experimental/Intersection/EdgeWalker_Test.h @@ -26,6 +26,7 @@ struct State4 { int b; int c; int d; + char filename[256]; pthread_t threadID; SkCanvas* canvas; SkBitmap bitmap; diff --git a/experimental/Intersection/ShapeOps.h b/experimental/Intersection/ShapeOps.h index 9cd22ec5f6..728d89e775 100644 --- a/experimental/Intersection/ShapeOps.h +++ b/experimental/Intersection/ShapeOps.h @@ -4,4 +4,9 @@ void contourBounds(const SkPath& path, SkTDArray<SkRect>& boundsArray); void simplify(const SkPath& path, bool asFill, SkPath& simple); void simplifyx(const SkPath& path, SkPath& simple); -extern const bool gRunTestsInOneThread; // FIXME: remove once debugging is complete +// FIXME: remove this section once debugging is complete +extern const bool gRunTestsInOneThread; +#ifdef SK_DEBUG +extern int gDebugMaxWindSum; +extern int gDebugMaxWindValue; +#endif diff --git a/experimental/Intersection/Simplify.cpp b/experimental/Intersection/Simplify.cpp index 1fd818558b..7da8c133d7 100644 --- a/experimental/Intersection/Simplify.cpp +++ b/experimental/Intersection/Simplify.cpp @@ -17,39 +17,51 @@ // A Segment contains a Span array // A Span is describes a portion of a Segment using starting and ending T // T values range from 0 to 1, where 0 is the first Point in the Segment +// An Edge is a Segment generated from a Span // FIXME: remove once debugging is complete -#if 0 // set to 1 for no debugging whatsoever +#ifdef SK_DEBUG +int gDebugMaxWindSum = SK_MaxS32; +int gDebugMaxWindValue = SK_MaxS32; +#endif + +#define DEBUG_UNUSED 0 // set to expose unused functions + +#if 0 // set to 1 for multiple thread -- no debugging -//const bool gxRunTestsInOneThread = false; +const bool gRunTestsInOneThread = false; +#define DEBUG_ACTIVE_SPANS 0 #define DEBUG_ADD_INTERSECTING_TS 0 +#define DEBUG_ADD_T_PAIR 0 #define DEBUG_BRIDGE 0 +#define DEBUG_CONCIDENT 0 #define DEBUG_CROSS 0 #define DEBUG_DUMP 0 +#define DEBUG_MARK_DONE 0 #define DEBUG_PATH_CONSTRUCTION 0 -#define DEBUG_ACTIVE_SPANS 0 +#define DEBUG_SORT 0 #define DEBUG_WINDING 0 -#define DEBUG_UNUSED 0 // set to expose unused functions -#define DEBUG_MARK_DONE 0 #else -//const bool gRunTestsInOneThread = true; +const bool gRunTestsInOneThread = true; +#define DEBUG_ACTIVE_SPANS 1 #define DEBUG_ADD_INTERSECTING_TS 0 -#define DEBUG_BRIDGE 1 -#define DEBUG_CROSS 1 +#define DEBUG_ADD_T_PAIR 1 +#define DEBUG_BRIDGE 0 +#define DEBUG_CONCIDENT 1 +#define DEBUG_CROSS 0 #define DEBUG_DUMP 1 +#define DEBUG_MARK_DONE 1 #define DEBUG_PATH_CONSTRUCTION 1 -#define DEBUG_ACTIVE_SPANS 01 -#define DEBUG_WINDING 01 -#define DEBUG_UNUSED 0 // set to expose unused functions -#define DEBUG_MARK_DONE 01 +#define DEBUG_SORT 1 +#define DEBUG_WINDING 1 #endif -#if DEBUG_ACTIVE_SPANS && !DEBUG_DUMP +#if (DEBUG_ACTIVE_SPANS || DEBUG_CONCIDENT) && !DEBUG_DUMP #undef DEBUG_DUMP #define DEBUG_DUMP 1 #endif @@ -466,6 +478,10 @@ public: } return fDDDx * rh.fDDDy < rh.fDDDx * fDDDy; } + + double dx() const { + return fDx; + } int end() const { return fEnd; @@ -925,6 +941,7 @@ public: do { if (transfer) { if (decrementOther) { + SkASSERT(abs(end->fWindValue) < gDebugMaxWindValue); ++(end->fWindValue); } else { SkASSERT(end->fWindValue > 0); @@ -958,6 +975,7 @@ public: } } } else { + SkASSERT(abs(oEnd->fWindValue) < gDebugMaxWindValue); ++(oEnd->fWindValue); } } @@ -975,54 +993,93 @@ public: other.addTOutsides(oOutsideTs, *this, endT); } } - + void addTOutsides(const SkTDArray<double>& outsideTs, Segment& other, - double otherEnd) { - int count = outsideTs.count(); - double endT = 0; - int endSpan = 0; - for (int index = 0; index < count; index += 2) { - double t = outsideTs[index]; - double otherT = outsideTs[index + 1]; - if (t > 1 - FLT_EPSILON) { - return; - } - if (t - endT > FLT_EPSILON) { - endSpan = addTDonePair(t, other, otherT); + double oEnd) { + // walk this to outsideTs[0] + // walk other to outsideTs[1] + // if either is > 0, add a pointer to the other, copying adjacent winding + int tIndex = -1; + int tCount = fTs.count(); + int oIndex = -1; + int oCount = other.fTs.count(); + double tStart = outsideTs[0]; + double oStart = outsideTs[1]; + Span* tSpan; + Span* oSpan; + do { + tSpan = &fTs[++tIndex]; + if (tStart - tSpan->fT < FLT_EPSILON) { + break; } - do { - endT = fTs[++endSpan].fT; - } while (endT - t < FLT_EPSILON); + } while (tIndex < tCount); + do { + oSpan = &other.fTs[++oIndex]; + if (oStart - oSpan->fT < FLT_EPSILON) { + break; + } + } while (oIndex < oCount); + if (tIndex > 0 || oIndex > 0) { + addTPair(tStart, other, oStart); + // note: counts for fT, other.fT are one greater + } else { + --tCount; + --oCount; } - addTPair(endT, other, otherEnd); + tStart = fTs[tIndex].fT; + oStart = other.fTs[oIndex].fT; + do { + do { + tSpan = &fTs[++tIndex]; + } while (tSpan->fT - tStart < FLT_EPSILON && tIndex < tCount); + tStart = fTs[tIndex].fT; + do { + oSpan = &other.fTs[++oIndex]; + } while (oSpan->fT - oStart < FLT_EPSILON && oIndex < oCount); + oStart = other.fTs[oIndex].fT; + if (tStart == 1 && oStart == 1) { + break; + } + addTPair(tStart, other, oStart); + ++tCount; + ++oCount; + } while (tStart < 1 && oStart < 1 && oEnd - oSpan->fT >= FLT_EPSILON); } - // match the other.fWindValue to its mates - int addTDonePair(double t, Segment& other, double otherT) { - int insertedAt = addTPair(t, other, otherT); - Span& end = fTs[insertedAt]; - SkASSERT(end.fWindValue == 1); - end.fWindValue = 0; - end.fDone = true; - ++fDoneSpans; - Span& otherEnd = other.fTs[end.fOtherIndex]; - Span* match = NULL; - if (end.fOtherIndex > 0) { - match = &other.fTs[end.fOtherIndex - 1]; - } - if (!match || match->fT < otherT) { - match = &other.fTs[end.fOtherIndex + 1]; - } - otherEnd.fWindValue = match->fWindValue; - return insertedAt; - } - - int addTPair(double t, Segment& other, double otherT) { + void addTPair(double t, Segment& other, double otherT) { +#if DEBUG_ADD_T_PAIR + SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n", + __FUNCTION__, fID, t, other.fID, otherT); +#endif int insertedAt = addT(t, &other); int otherInsertedAt = other.addT(otherT, this); addOtherT(insertedAt, otherT, otherInsertedAt); other.addOtherT(otherInsertedAt, t, insertedAt); - return insertedAt; + Span& newSpan = fTs[insertedAt]; + if (insertedAt > 0) { + const Span& lastSpan = fTs[insertedAt - 1]; + if (t - lastSpan.fT < FLT_EPSILON) { + int tWind = lastSpan.fWindValue; + newSpan.fWindValue = tWind; + if (!tWind) { + newSpan.fDone = true; + ++fDoneSpans; + } + } + } + int oIndex = newSpan.fOtherIndex; + if (oIndex > 0) { + const Span& lastOther = other.fTs[oIndex - 1]; + if (otherT - lastOther.fT < FLT_EPSILON) { + int oWind = lastOther.fWindValue; + Span& otherSpan = other.fTs[oIndex]; + otherSpan.fWindValue = oWind; + if (!oWind) { + otherSpan.fDone = true; + ++(other.fDoneSpans); + } + } + } } void addTwoAngles(int start, int end, SkTDArray<Angle>& angles) const { @@ -1037,7 +1094,7 @@ public: addAngle(angles, end, tIndex); } } - + const Bounds& bounds() const { return fBounds; } @@ -1099,6 +1156,9 @@ public: do { int start = end; end = nextSpan(start, 1); + if (fTs[start].fWindValue == 0) { + continue; + } SkPoint edge[4]; // OPTIMIZE: wrap this so that if start==0 end==fTCount-1 we can // work with the original data directly @@ -1121,7 +1181,7 @@ public: if (bestY < pt.fY) { bestY = pt.fY; bestT = foundT < 1 ? start : end; - hitT = foundT; + hitT = fTs[start].fT + (fTs[end].fT - fTs[start].fT) * foundT; } } while (fTs[end].fT != 1); return bestT; @@ -1132,6 +1192,13 @@ public: return fDoneSpans == fTs.count(); } + bool done(const Angle& angle) const { + int start = angle.start(); + int end = angle.end(); + const Span& mSpan = fTs[SkMin32(start, end)]; + return mSpan.fDone; + } + // so the span needs to contain the pairing info found here // this should include the winding computed for the edge, and // what edge it connects to, and whether it is discarded @@ -1190,20 +1257,25 @@ public: int angleCount = angles.count(); int firstIndex = findStartingEdge(sorted, startIndex, end); SkASSERT(firstIndex >= 0); + #if DEBUG_SORT + debugShowSort(sorted, firstIndex, winding); + #endif #if DEBUG_WINDING SkDebugf("%s (first) winding=%d sign=%d\n", __FUNCTION__, winding, sorted[firstIndex]->sign()); #endif bool innerSwap = false; int startWinding = winding; - if (winding * sorted[firstIndex]->sign() > 0 && active) { - // FIXME: this means winding was computed wrong by caller ? - winding = 0; - innerSwap = true; + if (sorted[firstIndex]->sign() * winding > 0) { + winding -= rewind(sorted[firstIndex]); + if (active) { + innerSwap = true; + } } 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 firstEdge = true; do { @@ -1216,27 +1288,37 @@ public: int windValue = nextSegment->windValue(nextAngle); SkASSERT(windValue > 0); winding -= nextAngle->sign() * windValue; + SkASSERT(abs(winding) <= gDebugMaxWindSum); #if DEBUG_WINDING SkDebugf("%s maxWinding=%d winding=%d sign=%d\n", __FUNCTION__, maxWinding, winding, nextAngle->sign()); #endif if (maxWinding * winding < 0) { flipped = -flipped; + #if DEBUG_WINDING SkDebugf("flipped sign %d %d\n", maxWinding, winding); + #endif } firstEdge = false; if (!winding) { if (!active) { - SkASSERT(nextAngle->segment() == this); - markWinding(SkMin32(nextAngle->start(), nextAngle->end()), - maxWinding); + markDone(SkMin32(startIndex, endIndex), startWinding); + nextSegment->markWinding(SkMin32(nextAngle->start(), + nextAngle->end()), maxWinding); #if DEBUG_WINDING SkDebugf("%s inactive\n", __FUNCTION__); #endif return NULL; } - if (!foundAngle) { + if (!foundAngle || foundDone) { foundAngle = nextAngle; + foundDone = nextSegment->done(*nextAngle); + if (flipped > 0 && maxWinding * startWinding < 0) { + flipped = -flipped; + #if DEBUG_WINDING + SkDebugf("flopped sign %d %d\n", maxWinding, winding); + #endif + } } continue; } @@ -1265,8 +1347,8 @@ public: } } } while (++nextIndex != lastIndex); - sorted[firstIndex]->segment()-> - markDone(SkMin32(startIndex, endIndex), startWinding); + SkASSERT(sorted[firstIndex]->segment() == this); + markDone(SkMin32(startIndex, endIndex), startWinding); if (!foundAngle) { return NULL; } @@ -1628,6 +1710,7 @@ public: #endif span.fDone = true; SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding); + SkASSERT(abs(winding) <= gDebugMaxWindSum); span.fWindSum = winding; fDoneSpans++; } @@ -1644,6 +1727,7 @@ public: #endif span.fDone = true; SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding); + SkASSERT(abs(winding) <= gDebugMaxWindSum); span.fWindSum = winding; fDoneSpans++; } while (++index < fTs.count() && fTs[index].fT - referenceT < FLT_EPSILON); @@ -1658,13 +1742,14 @@ public: if (span.fDone) { continue; } - SkASSERT(span.fWindValue == 1 || winding == 0); + // SkASSERT(span.fWindValue == 1 || winding == 0); 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", __FUNCTION__, fID, lesser, span.fT, pt.fX, pt.fY, winding); #endif + SkASSERT(abs(winding) <= gDebugMaxWindSum); span.fWindSum = winding; } do { @@ -1673,13 +1758,14 @@ public: if (span.fDone) { continue; } - SkASSERT(span.fWindValue == 1 || winding == 0); + // SkASSERT(span.fWindValue == 1 || winding == 0); 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", __FUNCTION__, fID, index, span.fT, pt.fX, pt.fY, winding); #endif + SkASSERT(abs(winding) <= gDebugMaxWindSum); span.fWindSum = winding; } while (++index < fTs.count() && fTs[index].fT - referenceT < FLT_EPSILON); } @@ -1724,6 +1810,15 @@ public: fTs.reset(); } + int rewind(const Angle* angle) { + SkASSERT(angle->segment() == this); + const Span& span = fTs[SkMin32(angle->start(), angle->end())]; +#if DEBUG_SORT + SkDebugf("%s offset=%d\n", __FUNCTION__, angle->sign() * span.fWindValue); +#endif + return angle->sign() * span.fWindValue; + } + // OPTIMIZATION: mark as debugging only if used solely by tests const Span& span(int tIndex) const { return fTs[tIndex]; @@ -1819,6 +1914,17 @@ public: } #endif +#if DEBUG_CONCIDENT + void debugShowTs() { + 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, + fTs[i].fT, xAtT(&fTs[i]), yAtT(&fTs[i]), fTs[i].fWindValue); + } + SkDebugf("\n"); + } +#endif + #if DEBUG_ACTIVE_SPANS void debugShowActiveSpans(int contourID, int segmentIndex) { if (done()) { @@ -1846,6 +1952,42 @@ public: } #endif +#if DEBUG_SORT + void debugShowSort(const SkTDArray<Angle*>& angles, int first, int winding) { + int index = first; + int windSum = winding; + const Angle& fAngle = *angles[first]; + const Segment& fSegment = *fAngle.segment(); + SkASSERT(&fSegment == this); + const Span& fSpan = fSegment.fTs[SkMin32(fAngle.start(), fAngle.end())]; + if (fAngle.sign() * winding < 0) { + windSum += fAngle.sign() * fSpan.fWindValue; + } + do { + const Angle& angle = *angles[index]; + const Segment& segment = *angle.segment(); + int start = angle.start(); + int end = angle.end(); + const Span& sSpan = segment.fTs[start]; + const Span& eSpan = segment.fTs[end]; + const Span& mSpan = segment.fTs[SkMin32(start, end)]; + int lastSum = windSum; + windSum -= angle.sign() * mSpan.fWindValue; + SkDebugf("%s [%d] id=%d start=%d (%1.9g,%,1.9g) end=%d (%1.9g,%,1.9g)" + " sign=%d windValue=%d winding: %d->%d (max=%d) done=%d\n", + __FUNCTION__, index, segment.fID, start, segment.xAtT(&sSpan), + segment.yAtT(&sSpan), end, segment.xAtT(&eSpan), + segment.yAtT(&eSpan), angle.sign(), mSpan.fWindValue, + lastSum, windSum, abs(lastSum) > abs(windSum) ? lastSum : + windSum, mSpan.fDone); + ++index; + if (index == angles.count()) { + index = 0; + } + } while (index != first); + } +#endif + private: const SkPoint* fPts; SkPath::Verb fVerb; @@ -2017,6 +2159,10 @@ public: int otherIndex = coincidence.fSegments[1]; Segment& thisOne = thisContour->fSegments[thisIndex]; Segment& other = otherContour->fSegments[otherIndex]; + #if DEBUG_CONCIDENT + thisOne.debugShowTs(); + other.debugShowTs(); + #endif double startT = coincidence.fTs[0][0]; double endT = coincidence.fTs[0][1]; if (startT > endT) { @@ -2047,6 +2193,10 @@ public: } thisOne.addTCoincident(startT, endT, other, oStartT, oEndT); } + #if DEBUG_CONCIDENT + thisOne.debugShowTs(); + other.debugShowTs(); + #endif } } @@ -2715,8 +2865,10 @@ static void coincidenceCheck(SkTDArray<Contour*>& contourList, int winding) { static int innerContourCheck(SkTDArray<Contour*>& contourList, Contour* baseContour, const SkPoint& basePt) { int contourCount = contourList.count(); - int winding = 0; SkScalar bestY = SK_ScalarMin; + const Segment* test = NULL; + int tIndex; + double tHit; for (int cTest = 0; cTest < contourCount; ++cTest) { Contour* contour = contourList[cTest]; if (basePt.fY < contour->bounds().fTop) { @@ -2728,58 +2880,88 @@ static int innerContourCheck(SkTDArray<Contour*>& contourList, if (baseContour->crosses(contour)) { continue; } - int tIndex; - double tHit; - const Segment* test = contour->crossedSegment(basePt, bestY, tIndex, - tHit); - if (!test) { - continue; + const Segment* next = contour->crossedSegment(basePt, bestY, tIndex, tHit); + if (next) { + test = next; } - // 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. - if (tHit == test->t(tIndex)) { - SkTDArray<Angle> angles; - int end = test->nextSpan(tIndex, 1); - if (end < 0) { - end = test->nextSpan(tIndex, -1); - } - test->addTwoAngles(tIndex, end, angles); - // test->buildAnglesInner(tIndex, angles); - test->buildAngles(tIndex, angles); - SkTDArray<Angle*> sorted; - sortAngles(angles, sorted); - const Angle* angle = sorted[0]; - test = angle->segment(); - SkScalar testDx = (*SegmentDXAtT[test->verb()])(test->pts(), tHit); - if (testDx == 0) { - angle = *(sorted.end() - 1); - test = angle->segment(); - SkASSERT((*SegmentDXAtT[test->verb()])(test->pts(), tHit) != 0); - } - tIndex = angle->start(); // lesser Y - winding = test->windSum(SkMin32(tIndex, angle->end())); - #if DEBUG_WINDING - SkDebugf("%s 1 winding=%d\n", __FUNCTION__, winding); - #endif - } else { - winding = test->windSum(tIndex); - #if DEBUG_WINDING - SkDebugf("%s 2 winding=%d\n", __FUNCTION__, winding); - #endif + } + 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. + if (tHit == test->t(tIndex)) { + SkTDArray<Angle> angles; + int end = test->nextSpan(tIndex, 1); + if (end < 0) { + end = test->nextSpan(tIndex, -1); } - // see if a + change in T results in a +/- change in X (compute x'(T)) - SkScalar dx = (*SegmentDXAtT[test->verb()])(test->pts(), tHit); - #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 - winding += dx > 0 ? -1 : 1; - #if DEBUG_WINDING - SkDebugf("%s 3 winding=%d\n", __FUNCTION__, winding); - #endif + test->addTwoAngles(end, tIndex, angles); + test->buildAngles(tIndex, angles); + SkTDArray<Angle*> sorted; + // OPTIMIZATION: call a sort that, if base point is the leftmost, + // returns the first counterclockwise hour before 6 o'clock, + // or if the base point is rightmost, returns the first clockwise + // hour after 6 o'clock + sortAngles(angles, sorted); +#if DEBUG_SORT + 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 + // is 12 noon or an earlier hour (the next counterclockwise) + int count = sorted.count(); + int left = -1; + int right = -1; + for (int index = 0; index < count; ++index) { + double indexDx = sorted[index]->dx(); + if (indexDx < 0) { + left = index; + } else if (indexDx > 0) { + right = index; + break; + } } + SkASSERT(left >= 0 || right >= 0); + if (left < 0) { + left = right; + } + const Angle* angle = sorted[left]; + test = angle->segment(); + winding = test->windSum(angle); + windValue = test->windValue(angle); + #if 0 + int firstSign = angle->sign(); + if (firstSign * winding > 0) { + winding -= test->rewind(angle); + } + #endif +#if DEBUG_WINDING + SkDebugf("%s angle winding=%d windValue=%d\n", __FUNCTION__, winding, + windValue); +#endif + } else { + winding = test->windSum(tIndex); + windValue = test->windValue(tIndex); +#if DEBUG_WINDING + SkDebugf("%s single winding=%d windValue=%d\n", __FUNCTION__, winding, + windValue); +#endif + } + // see if a + change in T results in a +/- change in X (compute x'(T)) + SkScalar dx = (*SegmentDXAtT[test->verb()])(test->pts(), tHit); +#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 + winding += dx > 0 ? -windValue : windValue; +#if DEBUG_WINDING + SkDebugf("%s final winding=%d\n", __FUNCTION__, winding); +#endif } baseContour->setWinding(winding); return winding; @@ -2851,9 +3033,12 @@ static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex) { angle = sorted[++firstIndex]; winding = angle->segment()->windSum(angle); } while (winding == SK_MinS32); + #if DEBUG_SORT + angle->segment()->debugShowSort(sorted, firstIndex, winding); + #endif int firstSign = angle->sign(); if (firstSign * winding > 0) { - winding -= firstSign; + winding -= angle->segment()->rewind(angle); } // SkDebugf("%s firstSign=%d\n", __FUNCTION__, firstSign); // we care about first sign and whether wind sum indicates this diff --git a/experimental/Intersection/SimplifyAddIntersectingTs_Test.cpp b/experimental/Intersection/SimplifyAddIntersectingTs_Test.cpp index 09481c385a..f70d2f8916 100644 --- a/experimental/Intersection/SimplifyAddIntersectingTs_Test.cpp +++ b/experimental/Intersection/SimplifyAddIntersectingTs_Test.cpp @@ -87,9 +87,9 @@ static void testPath(const SkPath& path, const SkPoint* pts1, SkPath::Verb c1Typ SimplifyAddIntersectingTsTest::Contour& c1 = contour[0]; SimplifyAddIntersectingTsTest::Contour& c2 = contour[1]; addIntersectTs(&c1, &c2); +#if DEBUG_DUMP bool c1Intersected = c1.segments()[0].intersected(); // bool c2Intersected = c2.fSegments[0].intersected(); -#if DEBUG_DUMP SkDebugf("%s %s (%1.9g,%1.9g %1.9g,%1.9g) %s %s (%1.9g,%1.9g %1.9g,%1.9g)\n", __FUNCTION__, SimplifyAddIntersectingTsTest::kLVerbStr[c1Type], pts1[0].fX, pts1[0].fY, diff --git a/experimental/Intersection/SimplifyNew_Test.cpp b/experimental/Intersection/SimplifyNew_Test.cpp index a7c5c31fd7..b730466cea 100644 --- a/experimental/Intersection/SimplifyNew_Test.cpp +++ b/experimental/Intersection/SimplifyNew_Test.cpp @@ -9,6 +9,8 @@ #include "Intersection_Tests.h" #include "ShapeOps.h" +#define TEST(name) { name, #name } + static void testLine1() { SkPath path, simple; path.moveTo(2,0); @@ -404,63 +406,192 @@ static void testLine36() { testSimplifyx(path); } -#define TEST(name) { name, #name } +static void testLine37() { + SkPath path, simple; + path.addRect(0, 20, 20, 20, (SkPath::Direction) 0); + path.addRect(18, 24, 30, 30, (SkPath::Direction) 0); + path.addRect(0, 0, 9, 9, (SkPath::Direction) 0); + testSimplifyx(path); +} + +static void testLine38() { + SkPath path, simple; + path.addRect(10, 0, 30, 30, (SkPath::Direction) 0); + path.addRect(6, 12, 18, 18, (SkPath::Direction) 0); + path.addRect(12, 12, 21, 21, (SkPath::Direction) 0); + testSimplifyx(path); +} + +static void testLine40() { + SkPath path, simple; + path.addRect(10, 0, 30, 30, (SkPath::Direction) 0); + path.addRect(12, 18, 24, 24, (SkPath::Direction) 0); + path.addRect(4, 16, 13, 13, (SkPath::Direction) 0); + testSimplifyx(path); +} + +static void testLine41() { + SkPath path, simple; + path.addRect(0, 0, 20, 20, (SkPath::Direction) 0); + path.addRect(18, 24, 30, 30, (SkPath::Direction) 0); + path.addRect(12, 0, 21, 21, (SkPath::Direction) 0); + testSimplifyx(path); +} + +static void testLine42() { + SkPath path, simple; + path.addRect(0, 0, 20, 20, (SkPath::Direction) 0); + path.addRect(0, 0, 12, 12, (SkPath::Direction) 0); + path.addRect(8, 16, 17, 17, (SkPath::Direction) 0); + testSimplifyx(path); +} + +static void testLine43() { + SkPath path, simple; + path.addRect(0, 0, 20, 20, (SkPath::Direction) 0); + path.addRect(6, 24, 18, 18, (SkPath::Direction) 0); + path.addRect(0, 32, 9, 36, (SkPath::Direction) 1); + testSimplifyx(path); +} + +static void testLine44() { + SkPath path, simple; + path.addRect(10, 40, 30, 30, (SkPath::Direction) 0); + path.addRect(18, 0, 30, 30, (SkPath::Direction) 0); + path.addRect(18, 32, 27, 36, (SkPath::Direction) 1); + testSimplifyx(path); +} + +static void testLine45() { + SkPath path, simple; + path.addRect(10, 0, 30, 30, (SkPath::Direction) 0); + path.addRect(18, 0, 30, 30, (SkPath::Direction) 0); + path.addRect(24, 32, 33, 36, (SkPath::Direction) 0); + testSimplifyx(path); +} + +static void testLine46() { + SkPath path, simple; + path.addRect(10, 40, 30, 30, (SkPath::Direction) 0); + path.addRect(24, 0, 36, 36, (SkPath::Direction) 0); + path.addRect(24, 32, 33, 36, (SkPath::Direction) 0); + testSimplifyx(path); +} + +static void testLine47() { + SkPath path, simple; + path.addRect(0, 0, 20, 20, (SkPath::Direction) 0); + path.addRect(0, 0, 12, 12, (SkPath::Direction) 0); + path.addRect(0, 0, 9, 9, (SkPath::Direction) 1); + testSimplifyx(path); +} + +static void testLine48() { + SkPath path, simple; + path.addRect(0, 0, 20, 20, (SkPath::Direction) 0); + path.addRect(0, 6, 12, 12, (SkPath::Direction) 0); + path.addRect(0, 0, 9, 9, (SkPath::Direction) 1); + testSimplifyx(path); +} + +static void testLine49() { + SkPath path, simple; + path.addRect(0, 0, 20, 20, (SkPath::Direction) 0); + path.addRect(0, 0, 12, 12, (SkPath::Direction) 0); + path.addRect(0, 0, 9, 9, (SkPath::Direction) 0); + testSimplifyx(path); +} + +static void testLine50() { + SkPath path, simple; + path.addRect(10, 30, 30, 30, (SkPath::Direction) 0); + path.addRect(24, 20, 36, 30, (SkPath::Direction) 0); + testSimplifyx(path); +} + + +static void testLine51() { + SkPath path, simple; + path.addRect(0, 0, 20, 20, (SkPath::Direction) 0); + path.addRect(0, 12, 12, 12, (SkPath::Direction) 0); + path.addRect(4, 12, 13, 13, (SkPath::Direction) 1); + testSimplifyx(path); +} + +static void (*firstTest)() = testLine51; static struct { void (*fun)(); const char* str; } tests[] = { - TEST(testLine1), - TEST(testLine2), - TEST(testLine3), - TEST(testLine4), - TEST(testLine5), - TEST(testLine6), - TEST(testLine7a), - TEST(testLine7b), - TEST(testLine7), - TEST(testLine8), - TEST(testLine9), - TEST(testLine10), - TEST(testLine10a), - TEST(testLine11), - TEST(testLine12), - TEST(testLine13), - TEST(testLine14), - TEST(testLine15), - TEST(testLine16), - TEST(testLine17), - TEST(testLine18), - TEST(testLine19), - TEST(testLine20), - TEST(testLine21), - TEST(testLine22), - TEST(testLine23), + TEST(testLine51), + TEST(testLine50), + TEST(testLine49), + TEST(testLine48), + TEST(testLine47), + TEST(testLine46), + TEST(testLine45), + TEST(testLine44), + TEST(testLine43), + TEST(testLine42), + TEST(testLine41), + TEST(testLine40), + TEST(testLine38), + TEST(testLine37), + TEST(testLine36), + TEST(testLine35), + TEST(testLine34), + TEST(testLine33), + TEST(testLine32), + TEST(testLine31), + TEST(testLine30), + TEST(testLine29), + TEST(testLine28), + TEST(testLine27), + TEST(testLine26), + TEST(testLine25), TEST(testLine24a), TEST(testLine24), - TEST(testLine25), - TEST(testLine26), - TEST(testLine27), - TEST(testLine28), - TEST(testLine29), - TEST(testLine30), - TEST(testLine31), - TEST(testLine32), - TEST(testLine33), - TEST(testLine34), - TEST(testLine35), - TEST(testLine36), + TEST(testLine23), + TEST(testLine22), + TEST(testLine21), + TEST(testLine20), + TEST(testLine19), + TEST(testLine18), + TEST(testLine17), + TEST(testLine16), + TEST(testLine15), + TEST(testLine14), + TEST(testLine13), + TEST(testLine12), + TEST(testLine11), + TEST(testLine10a), + TEST(testLine10), + TEST(testLine9), + TEST(testLine8), + TEST(testLine7b), + TEST(testLine7a), + TEST(testLine7), + TEST(testLine6), + TEST(testLine5), + TEST(testLine4), + TEST(testLine3), + TEST(testLine2), + TEST(testLine1), }; static const size_t testCount = sizeof(tests) / sizeof(tests[0]); -static void (*firstTest)() = 0; static bool skipAll = false; void SimplifyNew_Test() { if (skipAll) { return; } +#ifdef SK_DEBUG + gDebugMaxWindSum = 3; + gDebugMaxWindValue = 3; +#endif size_t index = 0; if (firstTest) { while (index < testCount && tests[index].fun != firstTest) { @@ -473,4 +604,8 @@ void SimplifyNew_Test() { (*tests[index].fun)(); firstTestComplete = true; } +#ifdef SK_DEBUG + gDebugMaxWindSum = SK_MaxS32; + gDebugMaxWindValue = SK_MaxS32; +#endif } diff --git a/experimental/Intersection/SimplifyRect4x4_Test.cpp b/experimental/Intersection/SimplifyRect4x4_Test.cpp index ef468068ae..0143e1a336 100644 --- a/experimental/Intersection/SimplifyRect4x4_Test.cpp +++ b/experimental/Intersection/SimplifyRect4x4_Test.cpp @@ -19,6 +19,15 @@ // same with x (3 bits, 5 values) // not included, square, tall, wide (2 bits) // cw or ccw (1 bit) +static const char marker[] = + "</div>\n" + "\n" + "<script type=\"text/javascript\">\n" + "\n" + "var testDivs = [\n"; +static const char testLineStr[] = " testLine"; +static const char filename[] = "../../experimental/Intersection/debugXX.txt"; +static int testNumber; static void* testSimplify4x4RectsMain(void* data) { @@ -27,13 +36,13 @@ static void* testSimplify4x4RectsMain(void* data) SkASSERT(data); State4& state = *(State4*) data; int aShape = state.a & 0x03; - int aCW = state.a >> 1; + int aCW = state.a >> 2; int bShape = state.b & 0x03; - int bCW = state.b >> 1; + int bCW = state.b >> 2; int cShape = state.c & 0x03; - int cCW = state.c >> 1; + int cCW = state.c >> 2; int dShape = state.d & 0x03; - int dCW = state.d >> 1; + int dCW = state.d >> 2; for (int aXAlign = 0 ; aXAlign < 5; ++aXAlign) { for (int aYAlign = 0 ; aYAlign < 5; ++aYAlign) { for (int bXAlign = 0 ; bXAlign < 5; ++bXAlign) { @@ -159,54 +168,43 @@ static void* testSimplify4x4RectsMain(void* data) dYAlign = 5; } path.close(); - SkDebugf("%s", pathStr); - if (!testSimplifyx(path, out, state.bitmap, state.canvas)) { - SkDebugf("*/\n{ %s %d, %d, %d, %d, %d, %d, %d, %d," - " %d, %d, %d, %d },\n/*\n", - __FUNCTION__, state.a, state.b, state.c, state.d, - aXAlign, aYAlign, bXAlign, bYAlign, - cXAlign, cYAlign, dXAlign, dYAlign); - SkFILEStream inFile("../../experimental/Intersection/op.htm"); - if (!inFile.isValid()) { - continue; - } - SkTDArray<char> inData; - inData.setCount(inFile.getLength()); - size_t inLen = inData.count(); - inFile.read(inData.begin(), inLen); - inFile.setPath(NULL); - SkFILEWStream outFile("../../experimental/Intersection/xop.htm"); + if (gRunTestsInOneThread) { + SkDebugf("%s\n", pathStr); + } else { + SkFILEWStream outFile(state.filename); if (!outFile.isValid()) { continue; } - const char marker[] = - "</div>\n" - "\n" - "<script type=\"text/javascript\">\n" - "\n" - "var testDivs = [\n"; - const char testLineStr[] = " testLine"; - char* insert = strstr(inData.begin(), marker); - if (!insert) { - continue; - } - size_t startLen = insert - inData.begin(); - insert += sizeof(marker); - const char* numLoc = insert + sizeof(testLineStr); - int testNumber = atoi(numLoc) + 1; - outFile.write(inData.begin(), startLen); outFile.writeText("<div id=\"testLine"); outFile.writeDecAsText(testNumber); outFile.writeText("\">\n"); outFile.writeText(pathStr); outFile.writeText("</div>\n\n"); + outFile.writeText(marker); outFile.writeText(testLineStr); outFile.writeDecAsText(testNumber); - outFile.writeText(",\n"); - outFile.write(insert, inLen - startLen - sizeof(marker)); + outFile.writeText(",\n\n\n"); + + outFile.writeText("static void testLine"); + outFile.writeDecAsText(testNumber); + outFile.writeText("() {\n SkPath path, simple;\n"); + outFile.writeText(pathStr); + outFile.writeText(" testSimplifyx(path);\n}\n"); + outFile.writeText("static void (*firstTest)() = testLine"); + outFile.writeDecAsText(testNumber); + outFile.writeText(";\n\n"); + + outFile.writeText("static struct {\n"); + outFile.writeText(" void (*fun)();\n"); + outFile.writeText(" const char* str;\n"); + outFile.writeText("} tests[] = {\n"); + outFile.writeText(" TEST(testLine"); + outFile.writeDecAsText(testNumber); + outFile.writeText("),\n"); outFile.flush(); - } + } + testSimplifyx(path, out, state.bitmap, state.canvas); } } } @@ -218,12 +216,41 @@ static void* testSimplify4x4RectsMain(void* data) return NULL; } -const int maxThreads = 1; // gRunTestsInOneThread ? 1 : 24; +const int maxThreads = gRunTestsInOneThread ? 1 : 8; void Simplify4x4RectsThreaded_Test() { +#ifdef SK_DEBUG + gDebugMaxWindSum = 3; + gDebugMaxWindValue = 3; +#endif + if (maxThreads > 1) { + SkFILEStream inFile("../../experimental/Intersection/op.htm"); + if (inFile.isValid()) { + SkTDArray<char> inData; + inData.setCount(inFile.getLength()); + size_t inLen = inData.count(); + inFile.read(inData.begin(), inLen); + inFile.setPath(NULL); + char* insert = strstr(inData.begin(), marker); + if (insert) { + insert += sizeof(marker) - 1; + const char* numLoc = insert + sizeof(testLineStr) - 1; + testNumber = atoi(numLoc) + 1; + } + } + } State4 threadState[maxThreads]; - int threadIndex = 0; + int threadIndex; + for (threadIndex = 0; threadIndex < maxThreads; ++threadIndex) { + State4* statePtr = &threadState[threadIndex]; + strcpy(statePtr->filename, filename); + SkASSERT(statePtr->filename[sizeof(filename) - 7] == 'X'); + SkASSERT(statePtr->filename[sizeof(filename) - 6] == 'X'); + statePtr->filename[sizeof(filename) - 7] = '0' + threadIndex / 10; + statePtr->filename[sizeof(filename) - 6] = '0' + threadIndex % 10; + } + threadIndex = 0; for (int a = 0; a < 8; ++a) { // outermost for (int b = a ; b < 8; ++b) { for (int c = b ; c < 8; ++c) { @@ -241,10 +268,18 @@ void Simplify4x4RectsThreaded_Test() } else { testSimplify4x4RectsMain(statePtr); } + if (maxThreads > 1) SkDebugf("."); } + if (maxThreads > 1) SkDebugf("%d", c); } + if (maxThreads > 1) SkDebugf("\n%d", b); } + if (maxThreads > 1) SkDebugf("\n\n%d", a); } waitForCompletion(threadState, threadIndex); +#ifdef SK_DEBUG + gDebugMaxWindSum = SK_MaxS32; + gDebugMaxWindValue = SK_MaxS32; +#endif } diff --git a/experimental/Intersection/op.htm b/experimental/Intersection/op.htm index a1f390c6cf..d2892b1740 100644 --- a/experimental/Intersection/op.htm +++ b/experimental/Intersection/op.htm @@ -345,6 +345,18 @@ path.close(); testSimplifyx(path); </div> +<div id="testLine19"> + SkPath path, simple; + path.addRect(0, 0, 12, 12, (SkPath::Direction) 0); + path.addRect(12, 16, 21, 21, (SkPath::Direction) 0); + testSimplifyx(path); +</div> + +<div id="testLine24"> + path.addRect(0, 18, 12, 12, (SkPath::Direction) 0); + path.addRect(4, 12, 13, 13, (SkPath::Direction) 0); +</div> + <div id="testLine28"> SkPath path, simple; path.addRect(0, 6, 12, 12, (SkPath::Direction) 0); @@ -401,23 +413,129 @@ path.close(); path.addRect(4, 16, 13, 13, (SkPath::Direction) 0); </div> +<div id="testLine37"> + path.addRect(0, 20, 20, 20, (SkPath::Direction) 0); + path.addRect(18, 24, 30, 30, (SkPath::Direction) 0); + path.addRect(0, 0, 9, 9, (SkPath::Direction) 0); +</div> + +<div id="testLine38"> + path.addRect(10, 0, 30, 30, (SkPath::Direction) 0); + path.addRect(6, 12, 18, 18, (SkPath::Direction) 0); + path.addRect(12, 12, 21, 21, (SkPath::Direction) 0); +</div> + +<div id="testLine39"> + path.addRect(10, 0, 30, 30, (SkPath::Direction) 0); + path.addRect(12, 6, 24, 24, (SkPath::Direction) 0); + path.addRect(12, 4, 21, 21, (SkPath::Direction) 0); +</div> + +<div id="testLine40"> + path.addRect(10, 0, 30, 30, (SkPath::Direction) 0); + path.addRect(12, 18, 24, 24, (SkPath::Direction) 0); + path.addRect(4, 16, 13, 13, (SkPath::Direction) 0); +</div> + +<div id="testLine41"> + path.addRect(0, 0, 20, 20, (SkPath::Direction) 0); + path.addRect(18, 24, 30, 30, (SkPath::Direction) 0); + path.addRect(12, 0, 21, 21, (SkPath::Direction) 0); +</div> + +<div id="testLine42"> + path.addRect(0, 0, 20, 20, (SkPath::Direction) 0); + path.addRect(0, 0, 12, 12, (SkPath::Direction) 0); + path.addRect(8, 16, 17, 17, (SkPath::Direction) 0); +</div> + +<div id="testLine43"> + path.addRect(0, 0, 20, 20, (SkPath::Direction) 0); + path.addRect(6, 24, 18, 18, (SkPath::Direction) 0); + path.addRect(0, 32, 9, 36, (SkPath::Direction) 1); +</div> + +<div id="testLine44"> + path.addRect(10, 40, 30, 30, (SkPath::Direction) 0); + path.addRect(18, 0, 30, 30, (SkPath::Direction) 0); + path.addRect(18, 32, 27, 36, (SkPath::Direction) 1); +</div> + +<div id="testLine45"> + path.addRect(10, 0, 30, 30, (SkPath::Direction) 0); + path.addRect(18, 0, 30, 30, (SkPath::Direction) 0); + path.addRect(24, 32, 33, 36, (SkPath::Direction) 0); +</div> + +<div id="testLine46"> + path.addRect(10, 40, 30, 30, (SkPath::Direction) 0); + path.addRect(24, 0, 36, 36, (SkPath::Direction) 0); + path.addRect(24, 32, 33, 36, (SkPath::Direction) 0); +</div> + +<div id="testLine47"> + path.addRect(0, 0, 20, 20, (SkPath::Direction) 0); + path.addRect(0, 0, 12, 12, (SkPath::Direction) 0); + path.addRect(0, 0, 9, 9, (SkPath::Direction) 1); +</div> + +<div id="testLine48"> + path.addRect(0, 0, 20, 20, (SkPath::Direction) 0); + path.addRect(0, 6, 12, 12, (SkPath::Direction) 0); + path.addRect(0, 0, 9, 9, (SkPath::Direction) 1); +</div> + +<div id="testLine49"> + path.addRect(0, 0, 20, 20, (SkPath::Direction) 0); + path.addRect(0, 0, 12, 12, (SkPath::Direction) 0); + path.addRect(0, 0, 9, 9, (SkPath::Direction) 0); +</div> + +<div id="testLine50"> + path.addRect(10, 30, 30, 30, (SkPath::Direction) 0); + path.addRect(24, 20, 36, 30, (SkPath::Direction) 0); +</div> + +<div id="testLine51"> + path.addRect(0, 0, 20, 20, (SkPath::Direction) 0); + path.addRect(0, 12, 12, 12, (SkPath::Direction) 0); + path.addRect(4, 12, 13, 13, (SkPath::Direction) 1); +</div> + </div> <script type="text/javascript"> var testDivs = [ + testLine51, + testLine50, + testLine49, + testLine48, + testLine47, + testLine46, + testLine45, + testLine44, + testLine43, + testLine42, + testLine41, + testLine40, + testLine39, + testLine38, + testLine37, testLine36, testLine35, testLine34, testLine33, - testLine9, - testLine7, testLine30, testLine32, testLine31, testLine29, testLine28, + testLine24, + testLine19, testLine17, + testLine9, + testLine7, testSimplifyQuadratic21, testSimplifyQuadratic20, testSimplifyQuadratic19, |