aboutsummaryrefslogtreecommitdiffhomepage
path: root/experimental/Intersection
diff options
context:
space:
mode:
authorGravatar caryclark@google.com <caryclark@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-01-03 21:18:16 +0000
committerGravatar caryclark@google.com <caryclark@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-01-03 21:18:16 +0000
commit8f9f468b0555e95b8fc3cf4e6ee1f1fbf5492a1b (patch)
tree1d5fe46fdbe7848894373ca588597358ee427258 /experimental/Intersection
parentee5a5eee12b3befac33ed6c379f81bf749f57161 (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.cpp7
-rw-r--r--experimental/Intersection/EdgeWalker_TestUtility.cpp135
-rw-r--r--experimental/Intersection/Intersection_Tests.cpp2
-rw-r--r--experimental/Intersection/Simplify.cpp564
-rw-r--r--experimental/Intersection/SimplifyFindNext_Test.cpp3
-rw-r--r--experimental/Intersection/SimplifyNew_Test.cpp260
-rw-r--r--experimental/Intersection/SimplifyRect4x4_Test.cpp8
-rw-r--r--experimental/Intersection/op.htm155
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,