diff options
author | 2013-01-03 21:18:16 +0000 | |
---|---|---|
committer | 2013-01-03 21:18:16 +0000 | |
commit | 8f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1b (patch) | |
tree | 1d5fe46fdbe7848894373ca588597358ee427258 /experimental/Intersection | |
parent | ee5a5eee12b3befac33ed6c379f81bf749f57161 (diff) |
shape ops work in progress
basic functionality works at this point
git-svn-id: http://skia.googlecode.com/svn/trunk@7004 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'experimental/Intersection')
-rw-r--r-- | experimental/Intersection/EdgeWalkerQuadratic4x4_Test.cpp | 7 | ||||
-rw-r--r-- | experimental/Intersection/EdgeWalker_TestUtility.cpp | 135 | ||||
-rw-r--r-- | experimental/Intersection/Intersection_Tests.cpp | 2 | ||||
-rw-r--r-- | experimental/Intersection/Simplify.cpp | 564 | ||||
-rw-r--r-- | experimental/Intersection/SimplifyFindNext_Test.cpp | 3 | ||||
-rw-r--r-- | experimental/Intersection/SimplifyNew_Test.cpp | 260 | ||||
-rw-r--r-- | experimental/Intersection/SimplifyRect4x4_Test.cpp | 8 | ||||
-rw-r--r-- | experimental/Intersection/op.htm | 155 |
8 files changed, 692 insertions, 442 deletions
diff --git a/experimental/Intersection/EdgeWalkerQuadratic4x4_Test.cpp b/experimental/Intersection/EdgeWalkerQuadratic4x4_Test.cpp index a2b6befe34..3a0a8f5b97 100644 --- a/experimental/Intersection/EdgeWalkerQuadratic4x4_Test.cpp +++ b/experimental/Intersection/EdgeWalkerQuadratic4x4_Test.cpp @@ -84,7 +84,12 @@ void Simplify4x4QuadraticsThreaded_Test(int& testsRun) const char testStr[] = "testQuadratic"; initializeTests(testStr, sizeof(testStr)); int testsStart = testsRun; - for (int a = 0; a < 16; ++a) { + int a = 0; +#define SKIP_A 0 +#if SKIP_A + a = 2; +#endif + for (; a < 16; ++a) { for (int b = a ; b < 16; ++b) { for (int c = b ; c < 16; ++c) { for (int d = c; d < 16; ++d) { diff --git a/experimental/Intersection/EdgeWalker_TestUtility.cpp b/experimental/Intersection/EdgeWalker_TestUtility.cpp index f07eebe179..de5967cd95 100644 --- a/experimental/Intersection/EdgeWalker_TestUtility.cpp +++ b/experimental/Intersection/EdgeWalker_TestUtility.cpp @@ -53,109 +53,10 @@ static bool gComparePathsAssert = true; static bool gPathStrAssert = true; static bool gUsePhysicalFiles = false; -static bool isRectContour(SkPath::Iter& iter, SkRect& rect, SkPath::Direction& direction) { - int corners = 0; - SkPoint first, last; - first.set(0, 0); - last.set(0, 0); - int firstDirection = 0; - int lastDirection = 0; - int nextDirection = 0; - bool closedOrMoved = false; - bool autoClose = false; - rect.setEmpty(); - uint8_t verb; - SkPoint data[4]; - SkTDArray<SkPoint> sides; - bool empty = true; - while ((verb = iter.next(data)) != SkPath::kDone_Verb && !autoClose) { - empty = false; - SkPoint* pts = &data[1]; - switch (verb) { - case SkPath::kClose_Verb: - pts = &last; - autoClose = true; - case SkPath::kLine_Verb: { - SkScalar left = last.fX; - SkScalar top = last.fY; - SkScalar right = pts->fX; - SkScalar bottom = pts->fY; - *sides.append() = *pts; - ++pts; - if (left != right && top != bottom) { - return false; // diagonal - } - if (left == right && top == bottom) { - break; // single point on side OK - } - nextDirection = (left != right) << 0 | - (left < right || top < bottom) << 1; - if (0 == corners) { - firstDirection = nextDirection; - first = last; - last = pts[-1]; - corners = 1; - closedOrMoved = false; - break; - } - if (closedOrMoved) { - return false; // closed followed by a line - } - if (autoClose && nextDirection == firstDirection) { - break; // colinear with first - } - closedOrMoved = autoClose; - if (lastDirection != nextDirection) { - if (++corners > 4) { - return false; // too many direction changes - } - } - last = pts[-1]; - if (lastDirection == nextDirection) { - break; // colinear segment - } - // Possible values for corners are 2, 3, and 4. - // When corners == 3, nextDirection opposes firstDirection. - // Otherwise, nextDirection at corner 2 opposes corner 4. - int turn = firstDirection ^ (corners - 1); - int directionCycle = 3 == corners ? 0 : nextDirection ^ turn; - if ((directionCycle ^ turn) != nextDirection) { - return false; // direction didn't follow cycle - } - break; - } - case SkPath::kQuad_Verb: - case SkPath::kCubic_Verb: - return false; // quadratic, cubic not allowed - case SkPath::kMove_Verb: - last = *pts++; - *sides.append() = last; - closedOrMoved = true; - break; - } - lastDirection = nextDirection; - } - // Success if 4 corners and first point equals last - bool result = 4 == corners && (first == last || autoClose); - if (result) { - direction = firstDirection == (lastDirection + 1 & 3) ? SkPath::kCCW_Direction - : SkPath::kCW_Direction; - rect.set(&sides[0], sides.count()); - } else { - rect.setEmpty(); - } - return !empty; -} - -static void showPathContour(SkPath::Iter& iter, bool skip) { +static void showPathContour(SkPath::Iter& iter) { uint8_t verb; SkPoint pts[4]; while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { - if (skip) { - if (verb == SkPath::kClose_Verb) { - return; - } - } switch (verb) { case SkPath::kMove_Verb: SkDebugf("path.moveTo(%1.9g, %1.9g);\n", pts[0].fX, pts[0].fY); @@ -174,7 +75,7 @@ static void showPathContour(SkPath::Iter& iter, bool skip) { break; case SkPath::kClose_Verb: SkDebugf("path.close();\n"); - return; + break; default: SkDEBUGFAIL("bad verb"); return; @@ -185,25 +86,23 @@ static void showPathContour(SkPath::Iter& iter, bool skip) { void showPath(const SkPath& path, const char* str) { SkDebugf("%s\n", !str ? "original:" : str); SkPath::Iter iter(path, true); - SkTDArray<SkRect> rects; - SkTDArray<SkPath::Direction> directions; - SkRect rect; - SkPath::Direction direction; - while (isRectContour(iter, rect, direction)) { - *rects.append() = rect; - *directions.append() = direction; - } - iter.setPath(path, true); - for (int contour = 0; contour < rects.count(); ++contour) { - const SkRect& rect = rects[contour]; - bool useRect = !rect.isEmpty(); - showPathContour(iter, useRect); - if (useRect) { + int rectCount = path.isRectContours() ? path.rectContours(NULL, NULL) : 0; + if (rectCount > 0) { + SkTDArray<SkRect> rects; + SkTDArray<SkPath::Direction> directions; + rects.setCount(rectCount); + directions.setCount(rectCount); + path.rectContours(rects.begin(), directions.begin()); + for (int contour = 0; contour < rectCount; ++contour) { + const SkRect& rect = rects[contour]; SkDebugf("path.addRect(%1.9g, %1.9g, %1.9g, %1.9g, %s);\n", rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, directions[contour] == SkPath::kCCW_Direction ? "SkPath::kCCW_Direction" : "SkPath::kCW_Direction"); } + return; } + iter.setPath(path, true); + showPathContour(iter); } static int pathsDrawTheSame(const SkPath& one, const SkPath& two, @@ -331,7 +230,7 @@ int comparePaths(const SkPath& one, const SkPath& two, SkBitmap& bitmap) { if (errors2x2 == 0) { return 0; } - const int MAX_ERRORS = 8; + const int MAX_ERRORS = 9; if (errors2x2 == MAX_ERRORS || errors2x2 == MAX_ERRORS - 1) { showSimplifiedPath(one, two, scaledOne, scaledTwo); } @@ -682,7 +581,7 @@ void outputToStream(const State4& state, const char* pathStr, const char* pathPr outFile.writeText("static void "); writeTestName(nameSuffix, outFile); - outFile.writeText("() {\n SkPath path, pathB;\n"); + outFile.writeText("() {\n SkPath path;\n"); if (pathPrefix) { outFile.writeText(pathPrefix); } @@ -699,7 +598,7 @@ void outputToStream(const State4& state, const char* pathStr, const char* pathPr outFile.writeText(" const char* str;\n"); outFile.writeText("} tests[] = {\n"); outFile.writeText(" TEST("); - writeTestName(pathPrefix, outFile); + writeTestName(nameSuffix, outFile); outFile.writeText("),\n"); outFile.flush(); } diff --git a/experimental/Intersection/Intersection_Tests.cpp b/experimental/Intersection/Intersection_Tests.cpp index 9ae4ff59d0..c7ec3109e4 100644 --- a/experimental/Intersection/Intersection_Tests.cpp +++ b/experimental/Intersection/Intersection_Tests.cpp @@ -16,9 +16,9 @@ void Intersection_Tests() { int testsRun = 0; SimplifyNew_Test(); + Simplify4x4RectsThreaded_Test(testsRun); Simplify4x4QuadraticsThreaded_Test(testsRun); QuadLineIntersectThreaded_Test(testsRun); - Simplify4x4RectsThreaded_Test(testsRun); SimplifyNondegenerate4x4TrianglesThreaded_Test(testsRun); SimplifyDegenerate4x4TrianglesThreaded_Test(testsRun); Simplify4x4QuadralateralsThreaded_Test(testsRun); diff --git a/experimental/Intersection/Simplify.cpp b/experimental/Intersection/Simplify.cpp index f854718af5..cbf33d0439 100644 --- a/experimental/Intersection/Simplify.cpp +++ b/experimental/Intersection/Simplify.cpp @@ -27,9 +27,10 @@ int gDebugMaxWindValue = SK_MaxS32; #define PIN_ADD_T 0 #define TRY_ROTATE 1 +#define ONE_PASS_COINCIDENCE_CHECK 0 #define DEBUG_UNUSED 0 // set to expose unused functions -#define FORCE_RELEASE 0 // set force release to 1 for multiple thread -- no debugging +#define FORCE_RELEASE 1 // set force release to 1 for multiple thread -- no debugging #if FORCE_RELEASE || defined SK_RELEASE @@ -48,8 +49,10 @@ const bool gRunTestsInOneThread = false; #define DEBUG_PATH_CONSTRUCTION 0 #define DEBUG_SHOW_WINDING 0 #define DEBUG_SORT 0 +#define DEBUG_UNSORTABLE 0 #define DEBUG_WIND_BUMP 0 #define DEBUG_WINDING 0 +#define DEBUG_WINDING_AT_T 0 #else @@ -68,8 +71,10 @@ const bool gRunTestsInOneThread = true; #define DEBUG_PATH_CONSTRUCTION 1 #define DEBUG_SHOW_WINDING 0 #define DEBUG_SORT 1 +#define DEBUG_UNSORTABLE 1 #define DEBUG_WIND_BUMP 0 #define DEBUG_WINDING 1 +#define DEBUG_WINDING_AT_T 1 #endif @@ -618,12 +623,14 @@ public: if (longer.lengthen() | rhLonger.lengthen()) { return longer < rhLonger; } + #if 0 // what if we extend in the other direction? longer = *this; rhLonger = rh; if (longer.reverseLengthen() | rhLonger.reverseLengthen()) { return longer < rhLonger; } + #endif } if ((fVerb == SkPath::kLine_Verb && approximately_zero(x) && approximately_zero(y)) || (rh.fVerb == SkPath::kLine_Verb @@ -749,6 +756,7 @@ public: setSpans(); } + void setSpans() { double startT = (*fSpans)[fStart].fT; double endT = (*fSpans)[fEnd].fT; @@ -781,18 +789,40 @@ public: SkASSERT(fStart != fEnd); int step = fStart < fEnd ? 1 : -1; // OPTIMIZE: worth fStart - fEnd >> 31 type macro? for (int index = fStart; index != fEnd; index += step) { - if ((*fSpans)[index].fUnsortableStart) { - fUnsortable = true; - return; +#if 1 + const Span& thisSpan = (*fSpans)[index]; + const Span& nextSpan = (*fSpans)[index + step]; + if (thisSpan.fTiny || thisSpan.fT == nextSpan.fT) { + continue; } -#if 0 - if (index != fStart && (*fSpans)[index].fUnsortableEnd) { - SkASSERT(0); + fUnsortable = step > 0 ? thisSpan.fUnsortableStart : nextSpan.fUnsortableEnd; +#if DEBUG_UNSORTABLE + if (fUnsortable) { + SkPoint iPt, ePt; + (*SegmentXYAtT[fVerb])(fPts, thisSpan.fT, &iPt); + (*SegmentXYAtT[fVerb])(fPts, nextSpan.fT, &ePt); + SkDebugf("%s unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__, + index, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY); + } +#endif + return; +#else + if ((*fSpans)[index].fUnsortableStart) { fUnsortable = true; return; } #endif } +#if 1 +#if DEBUG_UNSORTABLE + SkPoint iPt, ePt; + (*SegmentXYAtT[fVerb])(fPts, startT, &iPt); + (*SegmentXYAtT[fVerb])(fPts, endT, &ePt); + SkDebugf("%s all tiny unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__, + fStart, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY); +#endif + fUnsortable = true; +#endif } Segment* segment() const { @@ -1511,41 +1541,45 @@ public: } span->fUnsortableStart = false; span->fUnsortableEnd = false; - if (span - fTs.begin() > 0 && !span[-1].fDone - && !precisely_negative(newT - span[-1].fT) - // && approximately_negative(newT - span[-1].fT) - && xyAtT(&span[-1]) == xyAtT(span)) { - span[-1].fTiny = true; - span[-1].fDone = true; - if (approximately_negative(newT - span[-1].fT)) { + int less = -1; + while (&span[less + 1] - fTs.begin() > 0 && !span[less].fDone + && !precisely_negative(newT - span[less].fT) + // && approximately_negative(newT - span[less].fT) + && xyAtT(&span[less]) == xyAtT(span)) { + span[less].fTiny = true; + span[less].fDone = true; + if (approximately_negative(newT - span[less].fT)) { if (approximately_greater_than_one(newT)) { - span[-1].fUnsortableStart = true; - span[-2].fUnsortableEnd = true; + span[less].fUnsortableStart = true; + span[less - 1].fUnsortableEnd = true; } - if (approximately_less_than_zero(span[-1].fT)) { - span->fUnsortableStart = true; - span[-1].fUnsortableEnd = true; + if (approximately_less_than_zero(span[less].fT)) { + span[less + 1].fUnsortableStart = true; + span[less].fUnsortableEnd = true; } } ++fDoneSpans; - } - if (fTs.end() - span > 1 && !span->fDone - && !precisely_negative(span[1].fT - newT) - // && approximately_negative(span[1].fT - newT) - && xyAtT(&span[1]) == xyAtT(span)) { - span->fTiny = true; - span->fDone = true; - if (approximately_negative(span[1].fT - newT)) { - if (approximately_greater_than_one(span[1].fT)) { - span->fUnsortableStart = true; - span[-1].fUnsortableEnd = true; + --less; + } + int more = 1; + while (fTs.end() - &span[more - 1] > 1 && !span[more - 1].fDone + && !precisely_negative(span[more].fT - newT) + // && approximately_negative(span[more].fT - newT) + && xyAtT(&span[more]) == xyAtT(span)) { + span[more - 1].fTiny = true; + span[more - 1].fDone = true; + if (approximately_negative(span[more].fT - newT)) { + if (approximately_greater_than_one(span[more].fT)) { + span[more + 1].fUnsortableStart = true; + span[more].fUnsortableEnd = true; } if (approximately_less_than_zero(newT)) { - span[1].fUnsortableStart = true; - span->fUnsortableEnd = true; + span[more].fUnsortableStart = true; + span[more - 1].fUnsortableEnd = true; } } ++fDoneSpans; + ++more; } return insertedAt; } @@ -1944,7 +1978,8 @@ public: return bestTIndex; } if (fBounds.fLeft == fBounds.fRight) { - return bestTIndex; + // if vertical, and directly above test point, wait for another one + return approximately_equal(basePt.fX, fBounds.fLeft) ? SK_MinS32 : bestTIndex; } // intersect ray starting at basePt with edge Intersections intersections; @@ -1973,21 +2008,22 @@ public: double bestT = -1; for (int index = 0; index < pts; ++index) { double foundT = intersections.fT[0][index]; + if (approximately_less_than_zero(foundT) + || approximately_greater_than_one(foundT)) { + continue; + } SkScalar testY = (*SegmentYAtT[fVerb])(fPts, foundT); if (approximately_negative(testY - bestY) || approximately_negative(basePt.fY - testY)) { continue; } if (pts > 1 && fVerb == SkPath::kLine_Verb) { - // if the intersection is edge on, wait for another one - hitSomething = true; - return bestTIndex; + return SK_MinS32; // if the intersection is edge on, wait for another one } - if (fVerb > SkPath::kLine_Verb && !approximately_less_than_zero(foundT) - && !approximately_greater_than_one(foundT)) { + if (fVerb > SkPath::kLine_Verb) { SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, foundT); if (approximately_zero(dx)) { - continue; + return SK_MinS32; // hit vertical, wait for another one } } bestY = testY; @@ -2008,10 +2044,9 @@ public: while (start + 1 < end && fTs[start].fDone) { ++start; } - int testTIndex = bestT < 1 ? start : end; - if (!isCanceled(testTIndex)) { + if (!isCanceled(start)) { hitT = bestT; - bestTIndex = testTIndex; + bestTIndex = start; hitSomething = true; } return bestTIndex; @@ -2205,217 +2240,6 @@ public: return nextSegment; } - // 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 - // (maybe discarded == abs(winding) > 1) ? - // only need derivatives for duration of sorting, add a new struct - // for pairings, remove extra spans that have zero length and - // reference an unused other - // for coincident, the last span on the other may be marked done - // (always?) - - // if loop is exhausted, contour may be closed. - // FIXME: pass in close point so we can check for closure - - // given a segment, and a sense of where 'inside' is, return the next - // segment. If this segment has an intersection, or ends in multiple - // segments, find the mate that continues the outside. - // note that if there are multiples, but no coincidence, we can limit - // choices to connections in the correct direction - - // mark found segments as done - - // start is the index of the beginning T of this edge - // it is guaranteed to have an end which describes a non-zero length (?) - // winding -1 means ccw, 1 means cw - Segment* findNextWinding(SkTDArray<Span*>& chase, bool active, - int& nextStart, int& nextEnd, int& winding, int& spanWinding, - bool& unsortable) { - const int startIndex = nextStart; - const int endIndex = nextEnd; - int outerWinding = winding; - int innerWinding = winding + spanWinding; - #if DEBUG_WINDING - SkDebugf("%s winding=%d spanWinding=%d outerWinding=%d innerWinding=%d\n", - __FUNCTION__, winding, spanWinding, outerWinding, innerWinding); - #endif - if (useInnerWinding(outerWinding, innerWinding)) { - outerWinding = innerWinding; - } - SkASSERT(startIndex != endIndex); - int count = fTs.count(); - SkASSERT(startIndex < endIndex ? startIndex < count - 1 - : startIndex > 0); - int step = SkSign32(endIndex - startIndex); - int end = nextExactSpan(startIndex, step); - SkASSERT(end >= 0); - Span* endSpan = &fTs[end]; - Segment* other; - if (isSimple(end)) { - // mark the smaller of startIndex, endIndex done, and all adjacent - // spans with the same T value (but not 'other' spans) - #if DEBUG_WINDING - SkDebugf("%s simple\n", __FUNCTION__); - #endif - int min = SkMin32(startIndex, endIndex); - if (fTs[min].fDone) { - return NULL; - } - markDone(min, outerWinding); - other = endSpan->fOther; - nextStart = endSpan->fOtherIndex; - double startT = other->fTs[nextStart].fT; - nextEnd = nextStart; - do { - nextEnd += step; - } - while (precisely_zero(startT - other->fTs[nextEnd].fT)); - SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count()); - return other; - } - // more than one viable candidate -- measure angles to find best - SkTDArray<Angle> angles; - SkASSERT(startIndex - endIndex != 0); - SkASSERT((startIndex - endIndex < 0) ^ (step < 0)); - addTwoAngles(startIndex, end, angles); - buildAngles(end, angles, false); - SkTDArray<Angle*> sorted; - bool sortable = SortAngles(angles, sorted); - int angleCount = angles.count(); - int firstIndex = findStartingEdge(sorted, startIndex, end); - SkASSERT(firstIndex >= 0); - #if DEBUG_SORT - debugShowSort(__FUNCTION__, sorted, firstIndex, winding, 0); - #endif - if (!sortable) { - unsortable = true; - return NULL; - } - SkASSERT(sorted[firstIndex]->segment() == this); - #if DEBUG_WINDING - SkDebugf("%s [%d] sign=%d\n", __FUNCTION__, firstIndex, sorted[firstIndex]->sign()); - #endif - int sumWinding = winding - spanSign(sorted[firstIndex]); - int nextIndex = firstIndex + 1; - int lastIndex = firstIndex != 0 ? firstIndex : angleCount; - const Angle* foundAngle = NULL; - // FIXME: found done logic probably fails if there are more than 4 - // sorted angles. It should bias towards the first and last undone - // edges -- but not sure that it won't choose a middle (incorrect) - // edge if one is undone - bool foundDone = false; - bool foundDone2 = false; - // iterate through the angle, and compute everyone's winding - bool altFlipped = false; - bool foundFlipped = false; - int foundSum = SK_MinS32; - Segment* nextSegment; - int lastNonZeroSum = winding; - do { - if (nextIndex == angleCount) { - nextIndex = 0; - } - const Angle* nextAngle = sorted[nextIndex]; - int maxWinding = sumWinding; - if (sumWinding) { - lastNonZeroSum = sumWinding; - } - nextSegment = nextAngle->segment(); - bool nextDone = nextSegment->done(nextAngle); - bool nextTiny = nextSegment->tiny(nextAngle); - sumWinding -= nextSegment->spanSign(nextAngle); - altFlipped ^= lastNonZeroSum * sumWinding < 0; // flip if different signs - #if 0 && DEBUG_WINDING - SkASSERT(abs(sumWinding) <= gDebugMaxWindSum); - SkDebugf("%s [%d] maxWinding=%d sumWinding=%d sign=%d altFlipped=%d\n", __FUNCTION__, - nextIndex, maxWinding, sumWinding, nextAngle->sign(), altFlipped); - #endif - if (!sumWinding) { - if (!active) { - // FIXME: shouldn't this call mark and chase done ? - markDone(SkMin32(startIndex, endIndex), outerWinding); - // FIXME: shouldn't this call mark and chase winding ? - nextSegment->markWinding(SkMin32(nextAngle->start(), - nextAngle->end()), maxWinding); - #if DEBUG_WINDING - SkDebugf("%s [%d] inactive\n", __FUNCTION__, nextIndex); - #endif - return NULL; - } - if (!foundAngle || foundDone) { - foundAngle = nextAngle; - foundDone = nextDone && !nextTiny; - foundFlipped = altFlipped; - } - continue; - } - - if (!maxWinding && (!foundAngle || foundDone2)) { - #if DEBUG_WINDING - if (foundAngle && foundDone2) { - SkDebugf("%s [%d] !foundAngle && foundDone2\n", __FUNCTION__, nextIndex); - } - #endif - foundAngle = nextAngle; - foundDone2 = nextDone && !nextTiny; - foundFlipped = altFlipped; - foundSum = sumWinding; - } - if (nextSegment->done()) { - continue; - } - // if the winding is non-zero, nextAngle does not connect to - // current chain. If we haven't done so already, mark the angle - // as done, record the winding value, and mark connected unambiguous - // segments as well. - if (nextSegment->windSum(nextAngle) == SK_MinS32) { - if (useInnerWinding(maxWinding, sumWinding)) { - maxWinding = sumWinding; - } - Span* last; - if (foundAngle) { - last = nextSegment->markAndChaseWinding(nextAngle, maxWinding); - } else { - last = nextSegment->markAndChaseDone(nextAngle, maxWinding); - } - if (last) { - *chase.append() = last; - #if DEBUG_WINDING - SkDebugf("%s chase.append id=%d\n", __FUNCTION__, - last->fOther->fTs[last->fOtherIndex].fOther->debugID()); - #endif - } - } - } while (++nextIndex != lastIndex); - markDone(SkMin32(startIndex, endIndex), outerWinding); - if (!foundAngle) { - return NULL; - } - nextStart = foundAngle->start(); - nextEnd = foundAngle->end(); - nextSegment = foundAngle->segment(); - int flipped = foundFlipped ? -1 : 1; - spanWinding = SkSign32(spanWinding) * flipped * nextSegment->windValue( - SkMin32(nextStart, nextEnd)); - if (winding) { - #if DEBUG_WINDING - SkDebugf("%s ---6 winding=%d foundSum=", __FUNCTION__, winding); - if (foundSum == SK_MinS32) { - SkDebugf("?"); - } else { - SkDebugf("%d", foundSum); - } - SkDebugf("\n"); - #endif - winding = foundSum; - } - #if DEBUG_WINDING - SkDebugf("%s spanWinding=%d flipped=%d\n", __FUNCTION__, spanWinding, flipped); - #endif - return nextSegment; - } - Segment* findNextWinding(SkTDArray<Span*>& chase, int& nextStart, int& nextEnd, bool& unsortable) { const int startIndex = nextStart; @@ -2524,7 +2348,6 @@ public: nextStart = foundAngle->start(); nextEnd = foundAngle->end(); nextSegment = foundAngle->segment(); - #if DEBUG_WINDING SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd); @@ -2556,6 +2379,7 @@ public: other = endSpan->fOther; nextStart = endSpan->fOtherIndex; double startT = other->fTs[nextStart].fT; + #if 01 // FIXME: I don't know why the logic here is difference from the winding case SkDEBUGCODE(bool firstLoop = true;) if ((approximately_less_than_zero(startT) && step < 0) || (approximately_greater_than_one(startT) && step > 0)) { @@ -2563,11 +2387,13 @@ public: SkDEBUGCODE(firstLoop = false;) } do { + #endif nextEnd = nextStart; do { nextEnd += step; } while (precisely_zero(startT - other->fTs[nextEnd].fT)); + #if 01 if (other->fTs[SkMin32(nextStart, nextEnd)].fWindValue) { break; } @@ -2577,6 +2403,7 @@ public: SkDEBUGCODE(firstLoop = false;) step = -step; } while (true); + #endif SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count()); return other; } @@ -2589,6 +2416,9 @@ public: bool sortable = SortAngles(angles, sorted); if (!sortable) { unsortable = true; + #if DEBUG_SORT + debugShowSort(__FUNCTION__, sorted, findStartingEdge(sorted, startIndex, end), 0, 0); + #endif return NULL; } int angleCount = angles.count(); @@ -2600,27 +2430,41 @@ public: SkASSERT(sorted[firstIndex]->segment() == this); int nextIndex = firstIndex + 1; int lastIndex = firstIndex != 0 ? firstIndex : angleCount; - const Angle* nextAngle; + const Angle* foundAngle = NULL; + bool foundDone = false; Segment* nextSegment; - bool foundAngle = false; + int activeCount = 0; do { + SkASSERT(nextIndex != firstIndex); if (nextIndex == angleCount) { nextIndex = 0; } - nextAngle = sorted[nextIndex]; + const Angle* nextAngle = sorted[nextIndex]; nextSegment = nextAngle->segment(); - if (!nextSegment->done(nextAngle) || nextSegment->tiny(nextAngle)) { - foundAngle = true; - break; + ++activeCount; + if (!foundAngle || (foundDone && activeCount & 1)) { + if (nextSegment->tiny(nextAngle)) { + unsortable = true; + return NULL; + } + foundAngle = nextAngle; + foundDone = nextSegment->done(nextAngle); + } + if (nextSegment->done()) { + continue; } } while (++nextIndex != lastIndex); markDone(SkMin32(startIndex, endIndex), 1); if (!foundAngle) { - nextIndex = firstIndex + 1 == angleCount ? 0 : firstIndex + 1; - nextAngle = sorted[nextIndex]; + return NULL; } - nextStart = nextAngle->start(); - nextEnd = nextAngle->end(); + nextStart = foundAngle->start(); + nextEnd = foundAngle->end(); + nextSegment = foundAngle->segment(); + #if DEBUG_WINDING + SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", + __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd); + #endif return nextSegment; } @@ -2639,6 +2483,7 @@ public: } // FIXME: this is tricky code; needs its own unit test + // note that fOtherIndex isn't computed yet, so it can't be used here void findTooCloseToCall() { int count = fTs.count(); if (count < 3) { // require t=0, x, 1 at minimum @@ -2705,7 +2550,7 @@ public: continue; } if (moSpan.fOther == tOther) { - if (tOther->fTs[moSpan.fOtherIndex].fWindValue == 0) { + if (tOther->windValueAt(moSpan.fOtherT) == 0) { moStart = -1; break; } @@ -2737,7 +2582,7 @@ public: continue; } if (toSpan.fOther == mOther && toSpan.fOtherT == moEndT) { - if (mOther->fTs[toSpan.fOtherIndex].fWindValue == 0) { + if (mOther->windValueAt(toSpan.fOtherT) == 0) { moStart = -1; break; } @@ -2906,14 +2751,21 @@ the same winding is shared by both. SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, tHit); SkASSERT(dx); int windVal = windValue(SkMin32(start, end)); + #if DEBUG_WINDING_AT_T + SkDebugf("%s oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, winding, + hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal); + #endif if (!winding) { winding = dx < 0 ? windVal : -windVal; - } else if (hitDx * dx >= 0) { + } else if (winding * dx < 0) { int sideWind = winding + (dx < 0 ? windVal : -windVal); if (abs(winding) < abs(sideWind)) { winding = sideWind; } } + #if DEBUG_WINDING_AT_T + SkDebugf(" winding=%d\n", winding); + #endif int oppLocal = oppSign(start, end); SkASSERT(hitOppDx || !oppWind || !oppLocal); int oppWindVal = oppValue(SkMin32(start, end)); @@ -3319,12 +3171,21 @@ the same winding is shared by both. // note that just because a span has one end that is unsortable, that's // not enough to mark it done. The other end may be sortable, allowing the // span to be added. + // FIXME: if abs(start - end) > 1, mark intermediates as unsortable on both ends void markUnsortable(int start, int end) { Span* span = &fTs[start]; if (start < end) { +#if DEBUG_UNSORTABLE + SkDebugf("%s start id=%d [%d] (%1.9g,%1.9g)\n", __FUNCTION__, fID, start, + xAtT(start), yAtT(start)); +#endif span->fUnsortableStart = true; } else { --span; +#if DEBUG_UNSORTABLE + SkDebugf("%s end id=%d [%d] (%1.9g,%1.9g) next:(%1.9g,%1.9g)\n", __FUNCTION__, fID, + start - 1, xAtT(start - 1), yAtT(start - 1), xAtT(start), yAtT(start)); +#endif span->fUnsortableEnd = true; } if (!span->fUnsortableStart || !span->fUnsortableEnd || span->fDone) { @@ -3718,27 +3579,26 @@ the same winding is shared by both. int winding = crossOpp ? oppSum(tIndex) : windSum(tIndex); SkASSERT(winding != SK_MinS32); int windVal = crossOpp ? oppValue(tIndex) : windValue(tIndex); - #if DEBUG_WINDING - SkDebugf("%s single winding=%d windValue=%d\n", __FUNCTION__, winding, - windVal); + #if DEBUG_WINDING_AT_T + SkDebugf("%s oldWinding=%d windValue=%d", __FUNCTION__, winding, windVal); #endif // see if a + change in T results in a +/- change in X (compute x'(T)) dx = (*SegmentDXAtT[fVerb])(fPts, tHit); if (fVerb > SkPath::kLine_Verb && approximately_zero(dx)) { dx = fPts[2].fX - fPts[1].fX - dx; } - #if DEBUG_WINDING - SkDebugf("%s dx=%1.9g\n", __FUNCTION__, dx); - #endif if (dx == 0) { + #if DEBUG_WINDING_AT_T + SkDebugf(" dx=0 winding=SK_MinS32\n"); + #endif return SK_MinS32; } if (winding * dx > 0) { // if same signs, result is negative winding += dx > 0 ? -windVal : windVal; - #if DEBUG_WINDING - SkDebugf("%s final winding=%d\n", __FUNCTION__, winding); - #endif } + #if DEBUG_WINDING_AT_T + SkDebugf(" dx=%c winding=%d\n", dx > 0 ? '+' : '-', winding); + #endif return winding; } @@ -3764,6 +3624,17 @@ the same winding is shared by both. return windValue(index); } + int windValueAt(double t) const { + int count = fTs.count(); + for (int index = 0; index < count; ++index) { + if (fTs[index].fT == t) { + return fTs[index].fWindValue; + } + } + SkASSERT(0); + return 0; + } + SkScalar xAtT(int index) const { return xAtT(&fTs[index]); } @@ -4409,6 +4280,116 @@ public: } } + // first pass, add missing T values + // second pass, determine winding values of overlaps + void addCoincidentPoints() { + int count = fCoincidences.count(); + for (int index = 0; index < count; ++index) { + Coincidence& coincidence = fCoincidences[index]; + SkASSERT(coincidence.fContours[0] == this); + int thisIndex = coincidence.fSegments[0]; + Segment& thisOne = fSegments[thisIndex]; + Contour* otherContour = coincidence.fContours[1]; + int otherIndex = coincidence.fSegments[1]; + Segment& other = otherContour->fSegments[otherIndex]; + if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) { + // OPTIMIZATION: remove from array + continue; + } + #if DEBUG_CONCIDENT + thisOne.debugShowTs(); + other.debugShowTs(); + #endif + double startT = coincidence.fTs[0][0]; + double endT = coincidence.fTs[0][1]; + bool cancelers; + if ((cancelers = startT > endT)) { + SkTSwap<double>(startT, endT); + } + SkASSERT(!approximately_negative(endT - startT)); + double oStartT = coincidence.fTs[1][0]; + double oEndT = coincidence.fTs[1][1]; + if (oStartT > oEndT) { + SkTSwap<double>(oStartT, oEndT); + cancelers ^= true; + } + SkASSERT(!approximately_negative(oEndT - oStartT)); + bool opp = fOperand ^ otherContour->fOperand; + if (cancelers && !opp) { + // make sure startT and endT have t entries + if (startT > 0 || oEndT < 1 + || thisOne.isMissing(startT) || other.isMissing(oEndT)) { + thisOne.addTPair(startT, other, oEndT, true); + } + if (oStartT > 0 || endT < 1 + || thisOne.isMissing(endT) || other.isMissing(oStartT)) { + other.addTPair(oStartT, thisOne, endT, true); + } + } else { + if (startT > 0 || oStartT > 0 + || thisOne.isMissing(startT) || other.isMissing(oStartT)) { + thisOne.addTPair(startT, other, oStartT, true); + } + if (endT < 1 || oEndT < 1 + || thisOne.isMissing(endT) || other.isMissing(oEndT)) { + other.addTPair(oEndT, thisOne, endT, true); + } + } + #if DEBUG_CONCIDENT + thisOne.debugShowTs(); + other.debugShowTs(); + #endif + } + } + + void calcCoincidentWinding() { + int count = fCoincidences.count(); + for (int index = 0; index < count; ++index) { + Coincidence& coincidence = fCoincidences[index]; + SkASSERT(coincidence.fContours[0] == this); + int thisIndex = coincidence.fSegments[0]; + Segment& thisOne = fSegments[thisIndex]; + if (thisOne.done()) { + continue; + } + Contour* otherContour = coincidence.fContours[1]; + int otherIndex = coincidence.fSegments[1]; + Segment& other = otherContour->fSegments[otherIndex]; + if (other.done()) { + continue; + } + double startT = coincidence.fTs[0][0]; + double endT = coincidence.fTs[0][1]; + bool cancelers; + if ((cancelers = startT > endT)) { + SkTSwap<double>(startT, endT); + } + SkASSERT(!approximately_negative(endT - startT)); + double oStartT = coincidence.fTs[1][0]; + double oEndT = coincidence.fTs[1][1]; + if (oStartT > oEndT) { + SkTSwap<double>(oStartT, oEndT); + cancelers ^= true; + } + SkASSERT(!approximately_negative(oEndT - oStartT)); + bool opp = fOperand ^ otherContour->fOperand; + if (cancelers && !opp) { + // make sure startT and endT have t entries + if (!thisOne.done() && !other.done()) { + thisOne.addTCancel(startT, endT, other, oStartT, oEndT); + } + } else { + if (!thisOne.done() && !other.done()) { + thisOne.addTCoincident(startT, endT, other, oStartT, oEndT); + } + } + #if DEBUG_CONCIDENT + thisOne.debugShowTs(); + other.debugShowTs(); + #endif + } + } + SkTArray<Segment>& segments() { return fSegments; } @@ -5267,10 +5248,21 @@ static bool addIntersectTs(Contour* test, Contour* next) { // see if coincidence is formed by clipping non-concident segments static void coincidenceCheck(SkTDArray<Contour*>& contourList, int total) { int contourCount = contourList.count(); +#if ONE_PASS_COINCIDENCE_CHECK for (int cIndex = 0; cIndex < contourCount; ++cIndex) { Contour* contour = contourList[cIndex]; contour->resolveCoincidence(contourList); } +#else + for (int cIndex = 0; cIndex < contourCount; ++cIndex) { + Contour* contour = contourList[cIndex]; + contour->addCoincidentPoints(); + } + for (int cIndex = 0; cIndex < contourCount; ++cIndex) { + Contour* contour = contourList[cIndex]; + contour->calcCoincidentWinding(); + } +#endif for (int cIndex = 0; cIndex < contourCount; ++cIndex) { Contour* contour = contourList[cIndex]; contour->findTooCloseToCall(); @@ -5305,6 +5297,11 @@ static int contourRangeCheckY(SkTDArray<Contour*>& contourList, Segment*& curre int testTIndex = testSeg->crossedSpanY(basePt, testY, testHit, hitSomething, tAtMid, testOpp, testSeg == current); if (testTIndex < 0) { + if (testTIndex == SK_MinS32) { + hitSomething = true; + bestSeg = NULL; + goto abortContours; // vertical encountered, return and try different point + } continue; } if (testSeg == current && current->betweenTs(index, testHit, endIndex)) { @@ -5335,6 +5332,7 @@ static int contourRangeCheckY(SkTDArray<Contour*>& contourList, Segment*& curre bestY = testY; } } +abortContours: int result; if (!bestSeg) { result = hitSomething ? SK_MinS32 : 0; @@ -5680,11 +5678,16 @@ static bool bridgeWinding(SkTDArray<Contour*>& contourList, PathWrapper& simple) } break; } + #if DEBUG_FLOW + SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__, + current->debugID(), current->xyAtT(index).fX, current->xyAtT(index).fY, + current->xyAtT(endIndex).fX, current->xyAtT(endIndex).fY); + #endif current->addCurveTo(index, endIndex, simple, true); current = next; index = nextStart; endIndex = nextEnd; - } while (!simple.isClosed() && ((!unsortable) + } while (!simple.isClosed() && (!unsortable || !current->done(SkMin32(index, endIndex)))); if (current->activeWinding(index, endIndex) && !simple.isClosed()) { SkASSERT(unsortable); @@ -5721,6 +5724,11 @@ static bool bridgeXor(SkTDArray<Contour*>& contourList, PathWrapper& simple) { bool closable = true; while ((current = findUndone(contourList, start, end))) { do { + #if DEBUG_ACTIVE_SPANS + if (!unsortable && current->done()) { + debugShowActiveSpans(contourList); + } + #endif SkASSERT(unsortable || !current->done()); int nextStart = start; int nextEnd = end; @@ -5743,7 +5751,7 @@ static bool bridgeXor(SkTDArray<Contour*>& contourList, PathWrapper& simple) { current = next; start = nextStart; end = nextEnd; - } while (!simple.isClosed() && (!unsortable || !current->done())); + } while (!simple.isClosed() && (!unsortable || !current->done(SkMin32(start, end)))); if (!simple.isClosed()) { SkASSERT(unsortable); int min = SkMin32(start, end); diff --git a/experimental/Intersection/SimplifyFindNext_Test.cpp b/experimental/Intersection/SimplifyFindNext_Test.cpp index b01b951d23..0a04747bbb 100644 --- a/experimental/Intersection/SimplifyFindNext_Test.cpp +++ b/experimental/Intersection/SimplifyFindNext_Test.cpp @@ -37,8 +37,7 @@ static const SimplifyFindNextTest::Segment* testCommon( SkTDArray<SimplifyFindNextTest::Span*> chaseArray; bool unsortable = false; SimplifyFindNextTest::Segment* next = segment.findNextWinding(chaseArray, - true, nextStart, nextEnd, contourWinding, spanWinding, - unsortable); + nextStart, nextEnd, unsortable); pts[1] = next->xyAtT(&next->span(nextStart)); SkASSERT(pts[0] == pts[1]); return next; diff --git a/experimental/Intersection/SimplifyNew_Test.cpp b/experimental/Intersection/SimplifyNew_Test.cpp index c206d9e716..2559e80a05 100644 --- a/experimental/Intersection/SimplifyNew_Test.cpp +++ b/experimental/Intersection/SimplifyNew_Test.cpp @@ -2893,7 +2893,7 @@ path.close(); } static void testQuadratic59x() { - SkPath path, pathB; + SkPath path; path.setFillType(SkPath::kEvenOdd_FillType); path.moveTo(0, 0); path.quadTo(0, 0, 0, 0); @@ -2907,7 +2907,7 @@ static void testQuadratic59x() { } static void testQuadratic59() { - SkPath path, pathB; + SkPath path; path.setFillType(SkPath::kWinding_FillType); path.moveTo(0, 0); path.quadTo(0, 0, 0, 0); @@ -2921,7 +2921,7 @@ static void testQuadratic59() { } static void testQuadratic63() { - SkPath path, pathB; + SkPath path; path.moveTo(0, 0); path.quadTo(0, 0, 0, 0); path.lineTo(3, 2); @@ -2934,7 +2934,7 @@ static void testQuadratic63() { } static void testQuadratic64() { - SkPath path, pathB; + SkPath path; path.moveTo(0, 0); path.quadTo(0, 0, 0, 0); path.lineTo(2, 3); @@ -2947,7 +2947,7 @@ static void testQuadratic64() { } static void testQuadratic65() { - SkPath path, pathB; + SkPath path; path.moveTo(0, 0); path.quadTo(0, 0, 0, 0); path.lineTo(3, 2); @@ -2960,7 +2960,7 @@ static void testQuadratic65() { } static void testQuadratic67x() { - SkPath path, pathB; + SkPath path; path.setFillType(SkPath::kEvenOdd_FillType); path.moveTo(0, 0); path.quadTo(0, 0, 2, 1); @@ -2974,7 +2974,7 @@ static void testQuadratic67x() { } static void testQuadratic68() { - SkPath path, pathB; + SkPath path; path.moveTo(0, 0); path.quadTo(1, 0, 0, 1); path.lineTo(1, 2); @@ -2987,7 +2987,7 @@ static void testQuadratic68() { } static void testQuadratic69() { - SkPath path, pathB; + SkPath path; path.moveTo(0, 0); path.quadTo(0, 0, 0, 1); path.lineTo(3, 2); @@ -3000,7 +3000,7 @@ static void testQuadratic69() { } static void testQuadratic70x() { - SkPath path, pathB; + SkPath path; path.setFillType(SkPath::kEvenOdd_FillType); path.moveTo(0, 0); path.quadTo(1, 0, 0, 1); @@ -3014,7 +3014,7 @@ static void testQuadratic70x() { } static void testQuadratic71() { - SkPath path, pathB; + SkPath path; path.moveTo(0, 0); path.quadTo(1, 0, 1, 1); path.lineTo(3, 2); @@ -3027,7 +3027,7 @@ static void testQuadratic71() { } static void testQuadratic72() { - SkPath path, pathB; + SkPath path; path.moveTo(0, 0); path.quadTo(1, 0, 1, 2); path.lineTo(1, 2); @@ -3040,7 +3040,7 @@ static void testQuadratic72() { } static void testQuadratic73() { - SkPath path, pathB; + SkPath path; path.moveTo(0, 0); path.quadTo(1, 0, 0, 3); path.lineTo(0, 3); @@ -3053,7 +3053,7 @@ static void testQuadratic73() { } static void testQuadratic74() { - SkPath path, pathB; + SkPath path; path.moveTo(0, 0); path.quadTo(1, 0, 1, 3); path.lineTo(1, 3); @@ -3066,7 +3066,7 @@ static void testQuadratic74() { } static void testQuadratic75() { - SkPath path, pathB; + SkPath path; path.moveTo(0, 0); path.quadTo(1, 0, 1, 3); path.lineTo(2, 3); @@ -3079,7 +3079,7 @@ static void testQuadratic75() { } static void testQuadratic76() { - SkPath path, pathB; + SkPath path; path.moveTo(0, 0); path.quadTo(0, 0, 0, 0); path.lineTo(2, 3); @@ -3092,7 +3092,7 @@ static void testQuadratic76() { } static void testQuadratic77() { - SkPath path, pathB; + SkPath path; path.moveTo(0, 0); path.quadTo(1, 0, 1, 1); path.lineTo(3, 1); @@ -3105,7 +3105,7 @@ static void testQuadratic77() { } static void testQuadratic78() { - SkPath path, pathB; + SkPath path; path.moveTo(0, 0); path.quadTo(1, 0, 1, 2); path.lineTo(3, 2); @@ -3118,7 +3118,7 @@ static void testQuadratic78() { } static void testQuadratic79() { - SkPath path, pathB; + SkPath path; path.moveTo(0, 0); path.quadTo(1, 0, 1, 2); path.lineTo(3, 2); @@ -3131,7 +3131,7 @@ static void testQuadratic79() { } static void testEight1() { - SkPath path, pathB; + SkPath path; path.moveTo(0, 0); path.lineTo(2, 2); path.lineTo(0, 2); @@ -3141,7 +3141,7 @@ static void testEight1() { } static void testEight2() { - SkPath path, pathB; + SkPath path; path.moveTo(0, 0); path.lineTo(2, 0); path.lineTo(0, 2); @@ -3151,7 +3151,7 @@ static void testEight2() { } static void testEight3() { - SkPath path, pathB; + SkPath path; path.moveTo(0, 0); path.lineTo(0, 2); path.lineTo(2, 0); @@ -3161,7 +3161,7 @@ static void testEight3() { } static void testEight4() { - SkPath path, pathB; + SkPath path; path.moveTo(0, 0); path.lineTo(2, 2); path.lineTo(2, 0); @@ -3171,7 +3171,7 @@ static void testEight4() { } static void testEight5() { - SkPath path, pathB; + SkPath path; path.moveTo(1, 0); path.lineTo(1, 2); path.lineTo(0, 2); @@ -3181,7 +3181,7 @@ static void testEight5() { } static void testEight6() { - SkPath path, pathB; + SkPath path; path.moveTo(1, 0); path.lineTo(2, 0); path.lineTo(0, 2); @@ -3191,7 +3191,7 @@ static void testEight6() { } static void testEight7() { - SkPath path, pathB; + SkPath path; path.moveTo(0, 0); path.lineTo(0, 1); path.lineTo(2, 1); @@ -3201,7 +3201,7 @@ static void testEight7() { } static void testEight8() { - SkPath path, pathB; + SkPath path; path.moveTo(0, 0); path.lineTo(2, 2); path.lineTo(2, 1); @@ -3211,7 +3211,7 @@ static void testEight8() { } static void testEight9() { - SkPath path, pathB; + SkPath path; path.moveTo(1, 0); path.lineTo(1, 2); path.lineTo(2, 1); @@ -3221,7 +3221,7 @@ static void testEight9() { } static void testEight10() { - SkPath path, pathB; + SkPath path; path.moveTo(1, 0); path.lineTo(0, 1); path.lineTo(2, 1); @@ -3231,7 +3231,7 @@ static void testEight10() { } static void testQuadratic80() { - SkPath path, pathB; + SkPath path; path.moveTo(0, 0); path.quadTo(1, 0, 2, 3); path.lineTo(2, 3); @@ -3244,7 +3244,7 @@ static void testQuadratic80() { } static void testQuadratic81() { - SkPath path, pathB; + SkPath path; path.moveTo(0, 0); path.quadTo(2, 0, 1, 1); path.lineTo(1, 1); @@ -3257,7 +3257,7 @@ static void testQuadratic81() { } static void testQuadratic82() { - SkPath path, pathB; + SkPath path; path.moveTo(0, 0); path.quadTo(2, 0, 1, 1); path.lineTo(0, 3); @@ -3270,7 +3270,7 @@ static void testQuadratic82() { } static void testQuadratic83() { - SkPath path, pathB; + SkPath path; path.moveTo(0, 0); path.quadTo(0, 0, 2, 0); path.lineTo(2, 2); @@ -3283,7 +3283,7 @@ static void testQuadratic83() { } static void testQuadratic84() { - SkPath path, pathB; + SkPath path; path.moveTo(0, 0); path.quadTo(2, 0, 1, 1); path.lineTo(2, 1); @@ -3296,7 +3296,7 @@ static void testQuadratic84() { } static void testQuadratic85() { - SkPath path, pathB; + SkPath path; path.moveTo(0, 0); path.quadTo(3, 0, 1, 1); path.lineTo(1, 1); @@ -3309,7 +3309,7 @@ static void testQuadratic85() { } static void testQuadratic86() { - SkPath path, pathB; + SkPath path; path.moveTo(0, 0); path.quadTo(0, 1, 1, 1); path.lineTo(2, 3); @@ -3322,7 +3322,7 @@ static void testQuadratic86() { } static void testQuadratic87() { - SkPath path, pathB; + SkPath path; path.moveTo(0, 0); path.quadTo(2, 1, 0, 2); path.lineTo(2, 3); @@ -3335,7 +3335,7 @@ static void testQuadratic87() { } static void testQuadratic88() { - SkPath path, pathB; + SkPath path; path.moveTo(0, 0); path.quadTo(2, 1, 0, 2); path.lineTo(2, 2); @@ -3347,12 +3347,192 @@ static void testQuadratic88() { testSimplifyx(path); } -static void (*firstTest)() = testQuadratic88; +static void testQuadratic89x() { + SkPath path; + path.setFillType(SkPath::kEvenOdd_FillType); + path.moveTo(0, 0); + path.quadTo(3, 1, 2, 2); + path.lineTo(0, 3); + path.close(); + path.moveTo(0, 0); + path.lineTo(2, 1); + path.quadTo(3, 1, 3, 3); + path.close(); + testSimplifyx(path); +} + +static void testQuadratic90x() { + SkPath path; + path.setFillType(SkPath::kEvenOdd_FillType); + path.moveTo(0, 0); + path.quadTo(3, 0, 2, 2); + path.lineTo(1, 3); + path.close(); + path.moveTo(0, 0); + path.lineTo(0, 1); + path.quadTo(3, 2, 2, 3); + path.close(); + testSimplifyx(path); +} + +static void testQuadratic91() { + SkPath path; + path.moveTo(0, 0); + path.quadTo(3, 2, 2, 3); + path.lineTo(2, 3); + path.close(); + path.moveTo(0, 0); + path.lineTo(1, 1); + path.quadTo(2, 1, 2, 3); + path.close(); + testSimplifyx(path); +} + +static void testQuadratic92x() { + SkPath path; + path.setFillType(SkPath::kEvenOdd_FillType); + path.moveTo(1, 0); + path.quadTo(3, 0, 2, 2); + path.lineTo(2, 2); + path.close(); + path.moveTo(2, 0); + path.lineTo(0, 1); + path.quadTo(3, 2, 2, 3); + path.close(); + testSimplifyx(path); +} + +static void testLine82() { + SkPath path; + path.addRect(20, 0, 40, 40, SkPath::kCCW_Direction); + path.addRect(24, 20, 36, 30, SkPath::kCCW_Direction); + path.addRect(24, 32, 33, 36, SkPath::kCCW_Direction); + testSimplifyx(path); +} + +static void testLine82a() { + SkPath path; + path.addRect(0, 0, 6, 10, SkPath::kCW_Direction); + path.addRect(2, 2, 4, 4, SkPath::kCW_Direction); + path.addRect(2, 6, 4, 8, SkPath::kCW_Direction); + testSimplifyx(path); +} + +static void testLine82b() { + SkPath path; + path.addRect(0, 0, 6, 10, SkPath::kCW_Direction); + path.addRect(2, 2, 4, 4, SkPath::kCW_Direction); + path.addRect(2, 6, 4, 8, SkPath::kCCW_Direction); + testSimplifyx(path); +} + +static void testLine82c() { + SkPath path; + path.addRect(0, 0, 6, 10, SkPath::kCW_Direction); + path.addRect(2, 2, 4, 4, SkPath::kCCW_Direction); + path.addRect(2, 6, 4, 8, SkPath::kCW_Direction); + testSimplifyx(path); +} + +static void testLine82d() { + SkPath path; + path.addRect(0, 0, 6, 10, SkPath::kCW_Direction); + path.addRect(2, 2, 4, 4, SkPath::kCCW_Direction); + path.addRect(2, 6, 4, 8, SkPath::kCCW_Direction); + testSimplifyx(path); +} + +static void testLine82e() { + SkPath path; + path.addRect(0, 0, 6, 10, SkPath::kCCW_Direction); + path.addRect(2, 2, 4, 4, SkPath::kCW_Direction); + path.addRect(2, 6, 4, 8, SkPath::kCW_Direction); + testSimplifyx(path); +} + +static void testLine82f() { + SkPath path; + path.addRect(0, 0, 6, 10, SkPath::kCCW_Direction); + path.addRect(2, 2, 4, 4, SkPath::kCW_Direction); + path.addRect(2, 6, 4, 8, SkPath::kCCW_Direction); + testSimplifyx(path); +} + +static void testLine82g() { + SkPath path; + path.addRect(0, 0, 6, 10, SkPath::kCCW_Direction); + path.addRect(2, 2, 4, 4, SkPath::kCCW_Direction); + path.addRect(2, 6, 4, 8, SkPath::kCW_Direction); + testSimplifyx(path); +} + +static void testLine82h() { + SkPath path; + path.addRect(0, 0, 6, 10, SkPath::kCCW_Direction); + path.addRect(2, 2, 4, 4, SkPath::kCCW_Direction); + path.addRect(2, 6, 4, 8, SkPath::kCCW_Direction); + testSimplifyx(path); +} + +static void testLine83() { + SkPath path; +path.addRect(10, 30, 30, 40, SkPath::kCCW_Direction); +path.addRect(0, 12, 12, 18, SkPath::kCCW_Direction); +path.addRect(4, 13, 13, 16, SkPath::kCCW_Direction); + testSimplifyx(path); +} + +static void testLine84() { + SkPath path; + path.addRect(0, 12, 60, 30, SkPath::kCCW_Direction); + path.addRect(10, 20, 40, 30, SkPath::kCW_Direction); + path.addRect(0, 12, 12, 12, SkPath::kCW_Direction); + path.addRect(4, 12, 13, 13, SkPath::kCW_Direction); + testSimplifyx(path); +} + +static void testLine84x() { + SkPath path; + path.setFillType(SkPath::kEvenOdd_FillType); + path.addRect(0, 12, 60, 30, SkPath::kCCW_Direction); + path.addRect(10, 20, 40, 30, SkPath::kCCW_Direction); + path.addRect(0, 12, 12, 12, SkPath::kCCW_Direction); + path.addRect(4, 12, 13, 13, SkPath::kCCW_Direction); + testSimplifyx(path); +} + +static void testLine85() { + SkPath path; + path.addRect(36, 0, 66, 60, SkPath::kCCW_Direction); + path.addRect(20, 0, 40, 40, SkPath::kCCW_Direction); + path.addRect(12, 0, 24, 24, SkPath::kCCW_Direction); + path.addRect(32, 0, 36, 41, SkPath::kCCW_Direction); + testSimplifyx(path); +} + +static void (*firstTest)() = testLine85; static struct { void (*fun)(); const char* str; } tests[] = { + TEST(testLine85), + TEST(testLine84), + TEST(testLine84x), + TEST(testLine83), + TEST(testLine82h), + TEST(testLine82g), + TEST(testLine82f), + TEST(testLine82e), + TEST(testLine82d), + TEST(testLine82c), + TEST(testLine82b), + TEST(testLine82a), + TEST(testLine82), + TEST(testQuadratic92x), + TEST(testQuadratic91), + TEST(testQuadratic90x), + TEST(testQuadratic89x), TEST(testQuadratic88), TEST(testQuadratic87), TEST(testQuadratic86), @@ -3849,6 +4029,7 @@ static void (*firstBinaryTest)() = 0; static bool skipAll = false; static bool runBinaryTestsFirst = false; static bool runReverse = false; +static void (*stopTest)() = 0; void SimplifyNew_Test() { if (skipAll) { @@ -3889,6 +4070,9 @@ void SimplifyNew_Test() { SkDebugf(" %s [%s]\n", __FUNCTION__, tests[index].str); (*tests[index].fun)(); firstTestComplete = true; + if (tests[index].fun == stopTest) { + SkDebugf("lastTest\n"); + } if (index == last) { break; } diff --git a/experimental/Intersection/SimplifyRect4x4_Test.cpp b/experimental/Intersection/SimplifyRect4x4_Test.cpp index 5d857e9a74..add48d8df8 100644 --- a/experimental/Intersection/SimplifyRect4x4_Test.cpp +++ b/experimental/Intersection/SimplifyRect4x4_Test.cpp @@ -65,7 +65,7 @@ static void* testSimplify4x4RectsMain(void* data) } path.addRect(l, t, r, b, aCW); str += sprintf(str, " path.addRect(%d, %d, %d, %d," - " SkPath::kC%sWDirection);\n", l, t, r, b, aCW ? "C" : ""); + " SkPath::kC%sW_Direction);\n", l, t, r, b, aCW ? "C" : ""); } else { aXAlign = 5; aYAlign = 5; @@ -93,7 +93,7 @@ static void* testSimplify4x4RectsMain(void* data) } path.addRect(l, t, r, b, bCW); str += sprintf(str, " path.addRect(%d, %d, %d, %d," - " SkPath::kC%sWDirection);\n", l, t, r, b, bCW ? "C" : ""); + " SkPath::kC%sW_Direction);\n", l, t, r, b, bCW ? "C" : ""); } else { bXAlign = 5; bYAlign = 5; @@ -121,7 +121,7 @@ static void* testSimplify4x4RectsMain(void* data) } path.addRect(l, t, r, b, cCW); str += sprintf(str, " path.addRect(%d, %d, %d, %d," - " SkPath::kC%sWDirection);\n", l, t, r, b, cCW ? "C" : ""); + " SkPath::kC%sW_Direction);\n", l, t, r, b, cCW ? "C" : ""); } else { cXAlign = 5; cYAlign = 5; @@ -149,7 +149,7 @@ static void* testSimplify4x4RectsMain(void* data) } path.addRect(l, t, r, b, dCW); str += sprintf(str, " path.addRect(%d, %d, %d, %d," - " SkPath::kC%sWDirection);\n", l, t, r, b, dCW ? "C" : ""); + " SkPath::kC%sW_Direction);\n", l, t, r, b, dCW ? "C" : ""); } else { dXAlign = 5; dYAlign = 5; diff --git a/experimental/Intersection/op.htm b/experimental/Intersection/op.htm index f2936e06f3..50c26e90c2 100644 --- a/experimental/Intersection/op.htm +++ b/experimental/Intersection/op.htm @@ -3156,11 +3156,166 @@ path.close(); path.close(); </div> +<div id="testQuadratic89x"> + path.setFillType(SkPath::kEvenOdd_FillType); + path.moveTo(0, 0); + path.quadTo(3, 1, 2, 2); + path.lineTo(0, 3); + path.close(); + path.moveTo(0, 0); + path.lineTo(2, 1); + path.quadTo(3, 1, 3, 3); + path.close(); +</div> + +<div id="testQuadratic90x"> + path.setFillType(SkPath::kEvenOdd_FillType); + path.moveTo(0, 0); + path.quadTo(3, 0, 2, 2); + path.lineTo(1, 3); + path.close(); + path.moveTo(0, 0); + path.lineTo(0, 1); + path.quadTo(3, 2, 2, 3); + path.close(); +</div> + +<div id="testQuadratic91"> + path.moveTo(0, 0); + path.quadTo(3, 2, 2, 3); + path.lineTo(2, 3); + path.close(); + path.moveTo(0, 0); + path.lineTo(1, 1); + path.quadTo(2, 1, 2, 3); + path.close(); +</div> + +<div id="testQuadratic92x"> + path.setFillType(SkPath::kEvenOdd_FillType); + path.moveTo(1, 0); + path.quadTo(3, 0, 2, 2); + path.lineTo(2, 2); + path.close(); + path.moveTo(2, 0); + path.lineTo(0, 1); + path.quadTo(3, 2, 2, 3); + path.close(); +</div> + +<div id="testLine82"> + path.addRect(20, 0, 40, 40, SkPath::kCCWDirection); + path.addRect(24, 20, 36, 30, SkPath::kCCWDirection); + path.addRect(24, 32, 33, 36, SkPath::kCCWDirection); +</div> + +<div id="testLine82a"> + SkPath path; + path.addRect(0, 0, 6, 10, SkPath::kCW_Direction); + path.addRect(2, 2, 4, 4, SkPath::kCW_Direction); + path.addRect(2, 6, 4, 8, SkPath::kCW_Direction); + testSimplifyx(path); +</div> + +<div id="testLine82b"> + SkPath path; + path.addRect(0, 0, 6, 10, SkPath::kCW_Direction); + path.addRect(2, 2, 4, 4, SkPath::kCW_Direction); + path.addRect(2, 6, 4, 8, SkPath::kCCW_Direction); + testSimplifyx(path); +</div> + +<div id="testLine82c"> + SkPath path; + path.addRect(0, 0, 6, 10, SkPath::kCW_Direction); + path.addRect(2, 2, 4, 4, SkPath::kCCW_Direction); + path.addRect(2, 6, 4, 8, SkPath::kCW_Direction); + testSimplifyx(path); +</div> + + +<div id="testLine82d"> + SkPath path; + path.addRect(0, 0, 6, 10, SkPath::kCW_Direction); + path.addRect(2, 2, 4, 4, SkPath::kCCW_Direction); + path.addRect(2, 6, 4, 8, SkPath::kCCW_Direction); + testSimplifyx(path); +</div> + +<div id="testLine82e"> + SkPath path; + path.addRect(0, 0, 6, 10, SkPath::kCCW_Direction); + path.addRect(2, 2, 4, 4, SkPath::kCW_Direction); + path.addRect(2, 6, 4, 8, SkPath::kCW_Direction); + testSimplifyx(path); +</div> + +<div id="testLine82f"> + SkPath path; + path.addRect(0, 0, 6, 10, SkPath::kCCW_Direction); + path.addRect(2, 2, 4, 4, SkPath::kCW_Direction); + path.addRect(2, 6, 4, 8, SkPath::kCCW_Direction); + testSimplifyx(path); +</div> + +<div id="testLine82g"> + SkPath path; + path.addRect(0, 0, 6, 10, SkPath::kCCW_Direction); + path.addRect(2, 2, 4, 4, SkPath::kCCW_Direction); + path.addRect(2, 6, 4, 8, SkPath::kCW_Direction); + testSimplifyx(path); +</div> + +<div id="testLine82h"> + SkPath path; + path.addRect(0, 0, 6, 10, SkPath::kCCW_Direction); + path.addRect(2, 2, 4, 4, SkPath::kCCW_Direction); + path.addRect(2, 6, 4, 8, SkPath::kCCW_Direction); + testSimplifyx(path); +</div> + +<div id="testLine83"> +path.addRect(10, 30, 30, 40, SkPath::kCCW_Direction); +path.addRect(0, 12, 12, 18, SkPath::kCCW_Direction); +path.addRect(4, 13, 13, 16, SkPath::kCCW_Direction); +</div> + +<div id="testLine84x"> + path.setFillType(SkPath::kEvenOdd_FillType); + path.addRect(0, 12, 60, 30, SkPath::kCCW_Direction); + path.addRect(10, 20, 40, 30, SkPath::kCCW_Direction); + path.addRect(0, 12, 12, 12, SkPath::kCCW_Direction); + path.addRect(4, 12, 13, 13, SkPath::kCCW_Direction); +</div> + +<div id="testLine85"> + path.addRect(36, 0, 66, 60, SkPath::kCCW_Direction); + path.addRect(20, 0, 40, 40, SkPath::kCCW_Direction); + path.addRect(12, 0, 24, 24, SkPath::kCCW_Direction); + path.addRect(32, 0, 36, 41, SkPath::kCCW_Direction); +</div> + </div> <script type="text/javascript"> var testDivs = [ + testLine85, + testLine84x, + testLine83, + testLine82h, + testLine82g, + testLine82f, + testLine82e, + testLine82d, + testLine82c, + testLine82b, + testLine82a, + testLine82, + testQuadratic92x, + testQuadratic91, + testQuadratic90x, + testQuadratic89x, testQuadratic88, testQuadratic87, testQuadratic86, |