aboutsummaryrefslogtreecommitdiffhomepage
path: root/experimental
diff options
context:
space:
mode:
authorGravatar caryclark@google.com <caryclark@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-11-09 22:14:19 +0000
committerGravatar caryclark@google.com <caryclark@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-11-09 22:14:19 +0000
commit31143cf37fa38dc98f71c71e518ecc21c83b5e27 (patch)
treeefab01dcd9599414a75554c6ec8a7dc2479b8121 /experimental
parent3fb91a1fe939c827495ed22d7a95bd093d663efe (diff)
shape ops work in progress
first cut at getting binary ops to work (union/intersection/diff/xor) git-svn-id: http://skia.googlecode.com/svn/trunk@6375 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'experimental')
-rw-r--r--experimental/Intersection/EdgeDemo.cpp8
-rw-r--r--experimental/Intersection/EdgeDemoApp.mm2
-rw-r--r--experimental/Intersection/EdgeWalker_Test.h1
-rw-r--r--experimental/Intersection/EdgeWalker_TestUtility.cpp18
-rw-r--r--experimental/Intersection/ShapeOps.cpp232
-rw-r--r--experimental/Intersection/ShapeOps.h3
-rw-r--r--experimental/Intersection/Simplify.cpp733
-rw-r--r--experimental/Intersection/SimplifyNew_Test.cpp41
8 files changed, 570 insertions, 468 deletions
diff --git a/experimental/Intersection/EdgeDemo.cpp b/experimental/Intersection/EdgeDemo.cpp
index 8586c2bfb4..841678aa49 100644
--- a/experimental/Intersection/EdgeDemo.cpp
+++ b/experimental/Intersection/EdgeDemo.cpp
@@ -24,9 +24,9 @@ static bool drawPaths(SkCanvas* canvas, const SkPath& path, bool useOld)
SkPaint paint;
paint.setAntiAlias(true);
paint.setStyle(SkPaint::kStroke_Style);
- // paint.setStrokeWidth(6);
- // paint.setColor(0x1F003f7f);
- // canvas->drawPath(path, paint);
+// paint.setStrokeWidth(6);
+ // paint.setColor(0x1F003f7f);
+ // canvas->drawPath(path, paint);
paint.setColor(0xFF305F00);
paint.setStrokeWidth(1);
canvas->drawPath(out, paint);
@@ -287,7 +287,7 @@ static bool drawLetters(SkCanvas* canvas, int step, bool useOld)
textPos[x].fY = height / 2;
}
paint.setTextSize(40 + step / 100.0f);
-#if 1
+#if 0
bool oneShot = false;
for (int mask = 0; mask < 1 << testStrLen; ++mask) {
char maskStr[testStrLen];
diff --git a/experimental/Intersection/EdgeDemoApp.mm b/experimental/Intersection/EdgeDemoApp.mm
index 41dea67a4b..7c50fea617 100644
--- a/experimental/Intersection/EdgeDemoApp.mm
+++ b/experimental/Intersection/EdgeDemoApp.mm
@@ -16,7 +16,7 @@ public:
};
protected:
virtual void onDraw(SkCanvas* canvas) {
- static int step = 17907; // 17907 drawLetters first error
+ static int step = 0; // 17907 drawLetters first error
// drawStars triggers error at 33348
// drawStars error not easy to debug last time I checked
static double seconds;
diff --git a/experimental/Intersection/EdgeWalker_Test.h b/experimental/Intersection/EdgeWalker_Test.h
index 55f8bf3b23..30c8ace359 100644
--- a/experimental/Intersection/EdgeWalker_Test.h
+++ b/experimental/Intersection/EdgeWalker_Test.h
@@ -22,6 +22,7 @@ extern bool testSimplify(const SkPath& path, bool fill, SkPath& out,
extern bool testSimplifyx(SkPath& path, bool useXor, SkPath& out,
State4& state, const char* pathStr);
extern bool testSimplifyx(const SkPath& path);
+extern bool testShapeOp(const SkPath& a, const SkPath& b, const ShapeOp );
struct State4 {
State4();
diff --git a/experimental/Intersection/EdgeWalker_TestUtility.cpp b/experimental/Intersection/EdgeWalker_TestUtility.cpp
index e236cca455..7887b54d95 100644
--- a/experimental/Intersection/EdgeWalker_TestUtility.cpp
+++ b/experimental/Intersection/EdgeWalker_TestUtility.cpp
@@ -286,6 +286,24 @@ bool testSimplifyx(const SkPath& path) {
return result == 0;
}
+bool testShapeOp(const SkPath& a, const SkPath& b, const ShapeOp shapeOp) {
+ SkPath out;
+ operate(a, b, shapeOp, out);
+ SkPath pathOut;
+ SkRegion rgnA, rgnB, openClip, rgnOut;
+ openClip.setRect(-16000, -16000, 16000, 16000);
+ rgnA.setPath(a, openClip);
+ rgnB.setPath(b, openClip);
+ rgnOut.op(rgnA, rgnB, (SkRegion::Op) shapeOp);
+ rgnOut.getBoundaryPath(&pathOut);
+ SkBitmap bitmap;
+ int result = comparePaths(pathOut, out, bitmap);
+ if (result && gPathStrAssert) {
+ SkASSERT(0);
+ }
+ return result == 0;
+}
+
const int maxThreadsAllocated = 64;
static int maxThreads = 1;
static int threadIndex;
diff --git a/experimental/Intersection/ShapeOps.cpp b/experimental/Intersection/ShapeOps.cpp
index 669fa6d14d..dad482aefb 100644
--- a/experimental/Intersection/ShapeOps.cpp
+++ b/experimental/Intersection/ShapeOps.cpp
@@ -10,37 +10,146 @@ namespace Op {
#include "Simplify.cpp"
-static bool windingIsActive(int winding, int spanWinding, int oppWinding,
- const ShapeOp op) {
- return winding * spanWinding <= 0 && abs(winding) <= abs(spanWinding)
- && (!winding || !spanWinding || winding == -spanWinding);
+// FIXME: this and find chase should be merge together, along with
+// other code that walks winding in angles
+// OPTIMIZATION: Probably, the walked winding should be rolled into the angle structure
+// so it isn't duplicated by walkers like this one
+static Segment* findChaseOp(SkTDArray<Span*>& chase, int& tIndex, int& endIndex) {
+ while (chase.count()) {
+ Span* span;
+ chase.pop(&span);
+ const Span& backPtr = span->fOther->span(span->fOtherIndex);
+ Segment* segment = backPtr.fOther;
+ tIndex = backPtr.fOtherIndex;
+ SkTDArray<Angle> angles;
+ int done = 0;
+ if (segment->activeAngle(tIndex, done, angles)) {
+ Angle* last = angles.end() - 1;
+ tIndex = last->start();
+ endIndex = last->end();
+ #if TRY_ROTATE
+ *chase.insert(0) = span;
+ #else
+ *chase.append() = span;
+ #endif
+ return last->segment();
+ }
+ if (done == angles.count()) {
+ continue;
+ }
+ SkTDArray<Angle*> sorted;
+ bool sortable = Segment::SortAngles(angles, sorted);
+#if DEBUG_SORT
+ sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
+#endif
+ if (!sortable) {
+ continue;
+ }
+ // find first angle, initialize winding to computed fWindSum
+ int firstIndex = -1;
+ const Angle* angle;
+ int winding;
+ do {
+ angle = sorted[++firstIndex];
+ segment = angle->segment();
+ winding = segment->windSum(angle);
+ } while (winding == SK_MinS32);
+ int spanWinding = segment->spanSign(angle->start(), angle->end());
+ #if DEBUG_WINDING
+ SkDebugf("%s winding=%d spanWinding=%d\n",
+ __FUNCTION__, winding, spanWinding);
+ #endif
+ // turn span winding into contour winding
+ if (spanWinding * winding < 0) {
+ winding += spanWinding;
+ }
+ // we care about first sign and whether wind sum indicates this
+ // edge is inside or outside. Maybe need to pass span winding
+ // or first winding or something into this function?
+ // advance to first undone angle, then return it and winding
+ // (to set whether edges are active or not)
+ int nextIndex = firstIndex + 1;
+ int angleCount = sorted.count();
+ int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
+ angle = sorted[firstIndex];
+ segment = angle->segment();
+ int oWinding = segment->oppSum(angle);
+ #if DEBUG_SORT
+ segment->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, oWinding);
+ #endif
+ winding -= segment->spanSign(angle);
+ bool firstOperand = segment->operand();
+ do {
+ SkASSERT(nextIndex != firstIndex);
+ if (nextIndex == angleCount) {
+ nextIndex = 0;
+ }
+ angle = sorted[nextIndex];
+ segment = angle->segment();
+ int deltaSum = segment->spanSign(angle);
+ bool angleIsOp = segment->operand() ^ firstOperand;
+ int maxWinding;
+ if (angleIsOp) {
+ maxWinding = oWinding;
+ oWinding -= deltaSum;
+ } else {
+ maxWinding = winding;
+ winding -= deltaSum;
+ }
+ #if DEBUG_SORT
+ SkDebugf("%s id=%d maxWinding=%d winding=%d oWinding=%d sign=%d\n", __FUNCTION__,
+ segment->debugID(), maxWinding, winding, oWinding, angle->sign());
+ #endif
+ tIndex = angle->start();
+ endIndex = angle->end();
+ int lesser = SkMin32(tIndex, endIndex);
+ const Span& nextSpan = segment->span(lesser);
+ if (!nextSpan.fDone) {
+ if (angleIsOp) {
+ SkTSwap(winding, oWinding);
+ }
+ if (useInnerWinding(maxWinding, winding)) {
+ maxWinding = winding;
+ }
+ segment->markWinding(lesser, maxWinding, oWinding);
+ break;
+ }
+ } while (++nextIndex != lastIndex);
+ #if TRY_ROTATE
+ *chase.insert(0) = span;
+ #else
+ *chase.append() = span;
+ #endif
+ return segment;
+ }
+ return NULL;
}
-static void bridgeOp(SkTDArray<Contour*>& contourList, const ShapeOp op,
+static bool windingIsActive(int winding, int oppWinding, int spanWinding,
+ bool windingIsOp, ShapeOp op) {
+ bool active = windingIsActive(winding, spanWinding);
+ if (!active) {
+ return false;
+ }
+ bool opActive = oppWinding != 0;
+ return gOpLookup[op][opActive][windingIsOp];
+}
+
+static bool bridgeOp(SkTDArray<Contour*>& contourList, const ShapeOp op,
const int aXorMask, const int bXorMask, PathWrapper& simple) {
bool firstContour = true;
+ bool unsortable = false;
+ bool closable = true;
SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
do {
-
-#if SORTABLE_CONTOURS // old way
- Segment* topStart = findTopContour(contourList);
- if (!topStart) {
- break;
- }
- // Start at the top. Above the top is outside, below is inside.
- // follow edges to intersection by changing the index by direction.
- int index, endIndex;
- Segment* current = topStart->findTop(index, endIndex);
-#else // new way: iterate while top is unsortable
int index, endIndex;
Segment* current = findSortableTop(contourList, index, endIndex, topLeft);
if (!current) {
break;
}
-#endif
- int contourWinding;
+ int contourWinding, oppContourWinding;
if (firstContour) {
- contourWinding = 0;
+ contourWinding = oppContourWinding = 0;
firstContour = false;
} else {
int sumWinding = current->windSum(SkMin32(index, endIndex));
@@ -50,9 +159,16 @@ static void bridgeOp(SkTDArray<Contour*>& contourList, const ShapeOp op,
}
if (sumWinding == SK_MinS32) {
contourWinding = innerContourCheck(contourList, current,
- index, endIndex);
+ index, endIndex, false);
+ oppContourWinding = innerContourCheck(contourList, current,
+ index, endIndex, true);
} else {
contourWinding = sumWinding;
+ oppContourWinding = 0;
+ SkASSERT(0);
+ // FIXME: need to get oppContourWinding by building sort wheel and
+ // retrieving sumWinding of uphill opposite span, calling inner contour check
+ // if need be
int spanWinding = current->spanSign(index, endIndex);
bool inner = useInnerWinding(sumWinding - spanWinding, sumWinding);
if (inner) {
@@ -69,79 +185,69 @@ static void bridgeOp(SkTDArray<Contour*>& contourList, const ShapeOp op,
SkDebugf("%s contourWinding=%d\n", __FUNCTION__, contourWinding);
#endif
}
- // SkPoint lastPt;
int winding = contourWinding;
+ int oppWinding = oppContourWinding;
int spanWinding = current->spanSign(index, endIndex);
- int oppWinding = current->oppSign(index, endIndex);
- bool active = windingIsActive(winding, spanWinding, oppWinding, op);
SkTDArray<Span*> chaseArray;
- bool unsortable = false;
do {
+ bool active = windingIsActive(winding, oppWinding, spanWinding,
+ current->operand(), op);
#if DEBUG_WINDING
- SkDebugf("%s active=%s winding=%d spanWinding=%d\n",
+ SkDebugf("%s active=%s winding=%d oppWinding=%d spanWinding=%d\n",
__FUNCTION__, active ? "true" : "false",
- winding, spanWinding);
+ winding, oppWinding, spanWinding);
#endif
- // const SkPoint* firstPt = NULL;
do {
- SkASSERT(!current->done());
+ #if DEBUG_ACTIVE_SPANS
+ if (!unsortable && current->done()) {
+ debugShowActiveSpans(contourList);
+ }
+ #endif
+ SkASSERT(unsortable || !current->done());
int nextStart = index;
int nextEnd = endIndex;
Segment* next = current->findNextOp(chaseArray, active,
- nextStart, nextEnd, winding, spanWinding, unsortable, op,
- aXorMask, bXorMask);
+ nextStart, nextEnd, winding, oppWinding, spanWinding,
+ unsortable, op, aXorMask, bXorMask);
if (!next) {
- // FIXME: if unsortable, allow partial paths to be later
- // assembled
SkASSERT(!unsortable);
- if (active && simple.hasMove()
+ if (active && !unsortable && simple.hasMove()
&& current->verb() != SkPath::kLine_Verb
&& !simple.isClosed()) {
- /* lastPt = */ current->addCurveTo(index, endIndex, simple, true);
+ current->addCurveTo(index, endIndex, simple, true);
SkASSERT(simple.isClosed());
}
break;
}
- // if (!firstPt) {
- // firstPt = &current->addMoveTo(index, simple, active);
- // }
- /* lastPt = */ current->addCurveTo(index, endIndex, simple, active);
+ current->addCurveTo(index, endIndex, simple, active);
current = next;
index = nextStart;
endIndex = nextEnd;
- } while (!simple.isClosed() && (active || !current->done()));
- if (simple.hasMove() && active) {
- #if DEBUG_PATH_CONSTRUCTION
- SkDebugf("%s close\n", __FUNCTION__);
- #endif
+ } while (!simple.isClosed()
+ && ((active && !unsortable) || !current->done()));
+ if (active) {
+ if (!simple.isClosed()) {
+ SkASSERT(unsortable);
+ int min = SkMin32(index, endIndex);
+ if (!current->done(min)) {
+ current->addCurveTo(index, endIndex, simple, true);
+ current->markDone(SkMin32(index, endIndex), winding ? winding : spanWinding);
+ }
+ closable = false;
+ }
simple.close();
}
- current = findChase(chaseArray, index, endIndex, contourWinding);
+ current = findChaseOp(chaseArray, index, endIndex);
#if DEBUG_ACTIVE_SPANS
debugShowActiveSpans(contourList);
#endif
if (!current) {
break;
}
- int lesser = SkMin32(index, endIndex);
- spanWinding = current->spanSign(index, endIndex);
- winding = current->windSum(lesser);
- bool inner = useInnerWinding(winding - spanWinding, winding);
- #if DEBUG_WINDING
- SkDebugf("%s id=%d t=%1.9g spanWinding=%d winding=%d sign=%d"
- " inner=%d result=%d\n",
- __FUNCTION__, current->debugID(), current->t(lesser),
- spanWinding, winding, SkSign32(index - endIndex),
- useInnerWinding(winding - spanWinding, winding),
- inner ? winding - spanWinding : winding);
- #endif
- if (inner) {
- winding -= spanWinding;
- }
- int oppWinding = current->oppSign(index, endIndex);
- active = windingIsActive(winding, spanWinding, oppWinding, op);
+ winding = updateWindings(current, index, endIndex, spanWinding, &oppWinding);
} while (true);
} while (true);
+ return closable;
}
} // end of Op namespace
@@ -177,6 +283,10 @@ void operate(const SkPath& one, const SkPath& two, ShapeOp op, SkPath& result) {
// eat through coincident edges
coincidenceCheck(contourList);
fixOtherTIndex(contourList);
+ sortSegments(contourList);
+#if DEBUG_ACTIVE_SPANS
+ debugShowActiveSpans(contourList);
+#endif
// construct closed contours
Op::PathWrapper wrapper(result);
bridgeOp(contourList, op, aXorMask, bXorMask, wrapper);
diff --git a/experimental/Intersection/ShapeOps.h b/experimental/Intersection/ShapeOps.h
index 8ea3691041..f12a23b91a 100644
--- a/experimental/Intersection/ShapeOps.h
+++ b/experimental/Intersection/ShapeOps.h
@@ -18,7 +18,8 @@ enum ShapeOp {
kDifference_Op,
kIntersect_Op,
kUnion_Op,
- kXor_Op
+ kXor_Op,
+ kShapeOp_Count
};
enum ShapeOpMask {
diff --git a/experimental/Intersection/Simplify.cpp b/experimental/Intersection/Simplify.cpp
index ced59bab05..02be64c311 100644
--- a/experimental/Intersection/Simplify.cpp
+++ b/experimental/Intersection/Simplify.cpp
@@ -25,15 +25,13 @@ int gDebugMaxWindSum = SK_MaxS32;
int gDebugMaxWindValue = SK_MaxS32;
#endif
-#define PRECISE_T_SORT 1
-#define SORTABLE_CONTOURS 0 // set to 1 for old code that works most of the time
#define PIN_ADD_T 0
#define TRY_ROTATE 1
#define DEBUG_UNUSED 0 // set to expose unused functions
-#define FORCE_RELEASE 0
+#define FORCE_RELEASE 1 // set force release to 1 for multiple thread -- no debugging
-#if FORCE_RELEASE || defined SK_RELEASE // set force release to 1 for multiple thread -- no debugging
+#if FORCE_RELEASE || defined SK_RELEASE
const bool gRunTestsInOneThread = false;
@@ -481,9 +479,9 @@ struct Span {
double fT;
double fOtherT; // value at fOther[fOtherIndex].fT
int fOtherIndex; // can't be used during intersection
- int fWindSum; // accumulated from contours surrounding this one
+ int fWindSum; // accumulated from contours surrounding this one.
+ int fOppSum; // for binary operators: the opposite winding sum
int fWindValue; // 0 == canceled; 1 == normal; >1 == coincident
- int fWindValueOpp; // opposite value, if any (for binary ops with coincidence)
bool fDone; // if set, this span to next higher T has been processed
bool fUnsortableStart; // set when start is part of an unsortable pair
bool fUnsortableEnd; // set when end is part of an unsortable pair
@@ -534,7 +532,8 @@ public:
return cmp < 0;
}
// at this point, the initial tangent line is coincident
- if (fSide * rh.fSide <= 0 && (!approximately_zero(fSide) || !approximately_zero(rh.fSide))) {
+ if (fSide * rh.fSide <= 0 && (!approximately_zero(fSide)
+ || !approximately_zero(rh.fSide))) {
// FIXME: running demo will trigger this assertion
// (don't know if commenting out will trigger further assertion or not)
// commenting it out allows demo to run in release, though
@@ -557,7 +556,8 @@ public:
}
}
if ((fVerb == SkPath::kLine_Verb && approximately_zero(x) && approximately_zero(y))
- || (rh.fVerb == SkPath::kLine_Verb && approximately_zero(rx) && approximately_zero(ry))) {
+ || (rh.fVerb == SkPath::kLine_Verb
+ && approximately_zero(rx) && approximately_zero(ry))) {
// See general unsortable comment below. This case can happen when
// one line has a non-zero change in t but no change in x and y.
fUnsortable = true;
@@ -828,7 +828,7 @@ static bool useInnerWinding(int outerWinding, int innerWinding) {
return result;
}
-static const bool opLookup[][2][2] = {
+static const bool gOpLookup[][2][2] = {
// ==0 !=0
// b a b a
{{true , false}, {false, true }}, // a - b
@@ -838,10 +838,9 @@ static const bool opLookup[][2][2] = {
};
static bool activeOp(bool angleIsOp, int otherNonZero, ShapeOp op) {
- return opLookup[op][otherNonZero][angleIsOp];
+ return gOpLookup[op][otherNonZero][angleIsOp];
}
-
// wrap path to keep track of whether the contour is initialized and non-empty
class PathWrapper {
public:
@@ -1081,7 +1080,7 @@ public:
SkASSERT(start != end);
Angle* angle = angles.append();
#if DEBUG_ANGLE
- if (angles.count() > 1) {
+ if (angles.count() > 1 && !fTs[start].fTiny) {
SkPoint angle0Pt, newPt;
(*SegmentXYAtT[angles[0].verb()])(angles[0].pts(),
(*angles[0].spans())[angles[0].start()].fT, &angle0Pt);
@@ -1333,8 +1332,8 @@ public:
span->fOther = other;
span->fPt.fX = SK_ScalarNaN;
span->fWindSum = SK_MinS32;
+ span->fOppSum = SK_MinS32;
span->fWindValue = 1;
- span->fWindValueOpp = 0;
span->fTiny = false;
if ((span->fDone = newT == 1)) {
++fDoneSpans;
@@ -1407,18 +1406,14 @@ public:
SkTDArray<double> outsideTs;
SkTDArray<double> oOutsideTs;
do {
- bool decrement = test->fWindValue && oTest->fWindValue;
+ bool decrement = test->fWindValue && oTest->fWindValue && !binary;
bool track = test->fWindValue || oTest->fWindValue;
double testT = test->fT;
double oTestT = oTest->fT;
Span* span = test;
do {
if (decrement) {
- if (binary) {
- --(span->fWindValueOpp);
- } else {
- decrementSpan(span);
- }
+ decrementSpan(span);
} else if (track && span->fT < 1 && oTestT < 1) {
TrackOutside(outsideTs, span->fT, oTestT);
}
@@ -1468,11 +1463,11 @@ public:
// set spans from start to end to increment the greater by one and decrement
// the lesser
- void addTCoincident(const bool isXor, double startT, double endT,
+ void addTCoincident(bool isXor, double startT, double endT,
Segment& other, double oStartT, double oEndT) {
SkASSERT(!approximately_negative(endT - startT));
SkASSERT(!approximately_negative(oEndT - oStartT));
- bool binary = fOperand != other.fOperand;
+ isXor |= fOperand != other.fOperand;
int index = 0;
while (!approximately_negative(startT - fTs[index].fT)) {
++index;
@@ -1503,11 +1498,7 @@ public:
#ifdef SK_DEBUG
SkASSERT(abs(end->fWindValue) < gDebugMaxWindValue);
#endif
- if (binary) {
- ++(end->fWindValueOpp);
- } else {
- ++(end->fWindValue);
- }
+ ++(end->fWindValue);
} else if (decrementSpan(end)) {
TrackOutside(outsideTs, end->fT, oStartT);
}
@@ -1525,17 +1516,14 @@ public:
// and walk other conditionally -- hoping that it catches up in the end
double otherTMatch = (test->fT - startT) * tRatio + oStartT;
Span* oEnd = oTest;
- while (!approximately_negative(oEndT - oEnd->fT) && approximately_negative(oEnd->fT - otherTMatch)) {
+ while (!approximately_negative(oEndT - oEnd->fT)
+ && approximately_negative(oEnd->fT - otherTMatch)) {
if (transfer) {
if (decrementThis) {
#ifdef SK_DEBUG
SkASSERT(abs(oEnd->fWindValue) < gDebugMaxWindValue);
#endif
- if (binary) {
- ++(oEnd->fWindValueOpp);
- } else {
- ++(oEnd->fWindValue);
- }
+ ++(oEnd->fWindValue);
} else if (other.decrementSpan(oEnd)) {
TrackOutside(oOutsideTs, oEnd->fT, startT);
}
@@ -1612,24 +1600,17 @@ public:
return fBounds;
}
- void buildAngles(int index, SkTDArray<Angle>& angles) const {
+ void buildAngles(int index, SkTDArray<Angle>& angles, bool includeOpp) const {
double referenceT = fTs[index].fT;
int lesser = index;
- #if PRECISE_T_SORT
- while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
- buildAnglesInner(lesser, angles);
- }
- do {
- buildAnglesInner(index, angles);
- } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
- #else
- while (--lesser >= 0 && approximately_negative(referenceT - fTs[lesser].fT)) {
+ while (--lesser >= 0 && (includeOpp || fTs[lesser].fOther->fOperand == fOperand)
+ && precisely_negative(referenceT - fTs[lesser].fT)) {
buildAnglesInner(lesser, angles);
}
do {
buildAnglesInner(index, angles);
- } while (++index < fTs.count() && approximately_negative(fTs[index].fT - referenceT));
- #endif
+ } while (++index < fTs.count() && (includeOpp || fTs[index].fOther->fOperand == fOperand)
+ && precisely_negative(fTs[index].fT - referenceT));
}
void buildAnglesInner(int index, SkTDArray<Angle>& angles) const {
@@ -1642,99 +1623,25 @@ public:
int oIndex = span->fOtherIndex;
// if done == -1, prior span has already been processed
int step = 1;
- #if PRECISE_T_SORT
int next = other->nextExactSpan(oIndex, step);
- #else
- int next = other->nextSpan(oIndex, step);
- #endif
if (next < 0) {
step = -step;
- #if PRECISE_T_SORT
next = other->nextExactSpan(oIndex, step);
- #else
- next = other->nextSpan(oIndex, step);
- #endif
}
// add candidate into and away from junction
other->addTwoAngles(next, oIndex, angles);
}
- // figure out if the segment's ascending T goes clockwise or not
- // not enough context to write this as shown
- // instead, add all segments meeting at the top
- // sort them using buildAngleList
- // find the first in the sort
- // see if ascendingT goes to top
- bool clockwise(int /* tIndex */) const {
- SkASSERT(0); // incomplete
- return false;
- }
-
- // FIXME may not need this at all
- // FIXME once I figure out the logic, merge this and too close to call
- // NOTE not sure if tiny triangles can ever form at the edge, so until we
- // see one, only worry about triangles that happen away from 0 and 1
- void collapseTriangles(bool isXor) {
- if (fTs.count() < 3) { // require t=0, x, 1 at minimum
- return;
- }
- int lastIndex = 1;
- double lastT;
- while (approximately_less_than_zero((lastT = fTs[lastIndex].fT))) {
- ++lastIndex;
- }
- if (approximately_greater_than_one(lastT)) {
- return;
- }
- int matchIndex = lastIndex;
- do {
- Span& match = fTs[++matchIndex];
- double matchT = match.fT;
- if (approximately_greater_than_one(matchT)) {
- return;
- }
- if (matchT == lastT) {
- goto nextSpan;
- }
- if (approximately_negative(matchT - lastT)) {
- Span& last = fTs[lastIndex];
- Segment* lOther = last.fOther;
- double lT = last.fOtherT;
- if (approximately_less_than_zero(lT) || approximately_greater_than_one(lT)) {
- goto nextSpan;
- }
- Segment* mOther = match.fOther;
- double mT = match.fOtherT;
- if (approximately_less_than_zero(mT) || approximately_greater_than_one(mT)) {
- goto nextSpan;
- }
- // add new point to connect adjacent spurs
- int count = lOther->fTs.count();
- for (int index = 0; index < count; ++index) {
- Span& span = lOther->fTs[index];
- if (span.fOther == mOther && approximately_zero(span.fOtherT - mT)) {
- goto nextSpan;
- }
- }
- mOther->addTPair(mT, *lOther, lT, false);
- // FIXME ? this could go on to detect that spans on mOther, lOther are now coincident
- }
- nextSpan:
- lastIndex = matchIndex;
- lastT = matchT;
- } while (true);
- }
-
int computeSum(int startIndex, int endIndex) {
SkTDArray<Angle> angles;
addTwoAngles(startIndex, endIndex, angles);
- buildAngles(endIndex, angles);
+ buildAngles(endIndex, angles, false);
// OPTIMIZATION: check all angles to see if any have computed wind sum
// before sorting (early exit if none)
SkTDArray<Angle*> sorted;
bool sortable = SortAngles(angles, sorted);
#if DEBUG_SORT
- sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0);
+ sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
#endif
if (!sortable) {
return SK_MinS32;
@@ -1767,7 +1674,7 @@ public:
winding += spanWinding;
}
#if DEBUG_SORT
- base->debugShowSort(__FUNCTION__, sorted, firstIndex, winding);
+ base->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, 0);
#endif
int nextIndex = firstIndex + 1;
int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
@@ -1903,16 +1810,16 @@ public:
}
Segment* findNextOp(SkTDArray<Span*>& chase, bool active,
- int& nextStart, int& nextEnd, int& winding, int& spanWinding,
- bool& unsortable, ShapeOp op,
+ int& nextStart, int& nextEnd, int& winding, int& oppWinding,
+ int& spanWinding, bool& unsortable, ShapeOp op,
const int aXorMask, const int bXorMask) {
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);
+ SkDebugf("%s winding=%d spanWinding=%d outerWinding=%d innerWinding=%d oppWinding=%d\n",
+ __FUNCTION__, winding, spanWinding, outerWinding, innerWinding, oppWinding);
#endif
if (useInnerWinding(outerWinding, innerWinding)) {
outerWinding = innerWinding;
@@ -1922,11 +1829,7 @@ public:
SkASSERT(startIndex < endIndex ? startIndex < count - 1
: startIndex > 0);
int step = SkSign32(endIndex - startIndex);
- #if PRECISE_T_SORT
int end = nextExactSpan(startIndex, step);
- #else
- int end = nextSpan(startIndex, step);
- #endif
SkASSERT(end >= 0);
Span* endSpan = &fTs[end];
Segment* other;
@@ -1936,7 +1839,7 @@ public:
#if DEBUG_WINDING
SkDebugf("%s simple\n", __FUNCTION__);
#endif
- markDone(SkMin32(startIndex, endIndex), outerWinding);
+ markDone(SkMin32(startIndex, endIndex), outerWinding, oppWinding);
other = endSpan->fOther;
nextStart = endSpan->fOtherIndex;
double startT = other->fTs[nextStart].fT;
@@ -1944,11 +1847,7 @@ public:
do {
nextEnd += step;
}
- #if PRECISE_T_SORT
while (precisely_zero(startT - other->fTs[nextEnd].fT));
- #else
- while (approximately_zero(startT - other->fTs[nextEnd].fT));
- #endif
SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
return other;
}
@@ -1957,14 +1856,14 @@ public:
SkASSERT(startIndex - endIndex != 0);
SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
addTwoAngles(startIndex, end, angles);
- buildAngles(end, angles);
+ buildAngles(end, angles, true);
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);
+ debugShowSort(__FUNCTION__, sorted, firstIndex, winding, oppWinding);
#endif
if (!sortable) {
unsortable = true;
@@ -1975,8 +1874,8 @@ public:
SkDebugf("%s [%d] sign=%d\n", __FUNCTION__, firstIndex, sorted[firstIndex]->sign());
#endif
int aSumWinding = winding;
- int bSumWinding = winding;
- bool angleIsOp = sorted[firstIndex]->segment()->operand();
+ int bSumWinding = oppWinding;
+ bool angleIsOp = sorted[firstIndex]->segment()->operand() ^ operand();
int angleSpan = spanSign(sorted[firstIndex]);
if (angleIsOp) {
bSumWinding -= angleSpan;
@@ -1986,19 +1885,24 @@ public:
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;
+#define TWO_CHANNEL_DONE 0
+#if TWO_CHANNEL_DONE
bool foundDone2 = false;
+#define FOUND_DONE2 foundDone2
+#else
+#define FOUND_DONE2 foundDone
+#endif
// iterate through the angle, and compute everyone's winding
- bool altFlipped = false;
+ bool aAltFlipped = false;
+ bool bAltFlipped = false;
bool foundFlipped = false;
- int foundMax = SK_MinS32;
int foundSum = SK_MinS32;
+ int foundOppWinding = SK_MinS32;
Segment* nextSegment;
- int lastNonZeroSum = winding;
+ int aLastNonZeroSum = winding;
+ int bLastNonZeroSum = oppWinding;
+ bool foundOpp;
do {
if (nextIndex == angleCount) {
nextIndex = 0;
@@ -2007,59 +1911,66 @@ public:
nextSegment = nextAngle->segment();
bool nextDone = nextSegment->done(*nextAngle);
bool nextTiny = nextSegment->tiny(*nextAngle);
- angleIsOp = nextSegment->operand();
- int sumWinding = angleIsOp ? bSumWinding : aSumWinding;
- int maxWinding = sumWinding;
- if (sumWinding) {
- lastNonZeroSum = sumWinding;
- }
- sumWinding -= nextSegment->spanSign(nextAngle);
- int xorMask = nextSegment->operand() ? bXorMask : aXorMask;
- bool otherNonZero;
+ angleIsOp = nextSegment->operand() ^ operand();
+ int deltaSum = nextSegment->spanSign(nextAngle);
+ int maxWinding, xorMask, sumWinding;
+ bool otherNonZero, altFlipped;
if (angleIsOp) {
- bSumWinding = sumWinding;
+ maxWinding = bSumWinding;
+ if (bSumWinding) {
+ bLastNonZeroSum = bSumWinding;
+ }
+ bSumWinding -= deltaSum;
+ sumWinding = bSumWinding;
otherNonZero = aSumWinding & aXorMask;
+ xorMask = bXorMask;
+ bAltFlipped ^= bLastNonZeroSum * bSumWinding < 0; // flip if different signs
+ altFlipped = bAltFlipped;
} else {
- aSumWinding = sumWinding;
+ maxWinding = aSumWinding;
+ if (aSumWinding) {
+ aLastNonZeroSum = aSumWinding;
+ }
+ aSumWinding -= deltaSum;
+ sumWinding = aSumWinding;
otherNonZero = bSumWinding & bXorMask;
+ xorMask = aXorMask;
+ aAltFlipped ^= aLastNonZeroSum * aSumWinding < 0; // flip if different signs
+ altFlipped = aAltFlipped;
}
- 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 & xorMask) && activeOp(angleIsOp, otherNonZero, op)) {
+ bool opIsActive = activeOp(nextSegment->operand(), otherNonZero, op);
+ int oWinding = angleIsOp ? aSumWinding : bSumWinding;
+ if (!(sumWinding & xorMask)) {
if (!active) {
- markDone(SkMin32(startIndex, endIndex), outerWinding);
- // FIXME: seems like a bug that this isn't calling userInnerWinding
- nextSegment->markWinding(SkMin32(nextAngle->start(),
- nextAngle->end()), maxWinding);
+ markAndChaseDone(startIndex, endIndex, outerWinding, oppWinding);
+ nextSegment->markAndChaseWinding(nextAngle, maxWinding, oWinding);
#if DEBUG_WINDING
SkDebugf("%s [%d] inactive\n", __FUNCTION__, nextIndex);
#endif
return NULL;
}
- if (!foundAngle || foundDone) {
+ if (opIsActive && (!foundAngle || foundDone)) {
foundAngle = nextAngle;
foundDone = nextDone && !nextTiny;
foundFlipped = altFlipped;
- foundMax = maxWinding;
+ foundSum = 0;
+ foundOpp = angleIsOp;
+ foundOppWinding = oWinding;
}
continue;
}
- if (!(maxWinding & xorMask) && (!foundAngle || foundDone2)
- && activeOp(angleIsOp, otherNonZero, op)) {
+ if (opIsActive && !(maxWinding & xorMask) && (!foundAngle || FOUND_DONE2)) {
#if DEBUG_WINDING
- if (foundAngle && foundDone2) {
+ if (foundAngle && FOUND_DONE2) {
SkDebugf("%s [%d] !foundAngle && foundDone2\n", __FUNCTION__, nextIndex);
}
#endif
foundAngle = nextAngle;
- foundDone2 = nextDone && !nextTiny;
+ FOUND_DONE2 = nextDone && !nextTiny;
foundFlipped = altFlipped;
foundSum = sumWinding;
+ foundOpp = angleIsOp;
+ foundOppWinding = oWinding;
}
if (nextSegment->done()) {
continue;
@@ -2074,46 +1985,49 @@ public:
}
Span* last;
if (foundAngle) {
- last = nextSegment->markAndChaseWinding(nextAngle, maxWinding);
+ last = nextSegment->markAndChaseWinding(nextAngle, maxWinding, oWinding);
} else {
- last = nextSegment->markAndChaseDone(nextAngle, maxWinding);
+ last = nextSegment->markAndChaseDone(nextAngle, maxWinding, oWinding);
}
if (last) {
*chase.append() = last;
}
}
} while (++nextIndex != lastIndex);
- markDone(SkMin32(startIndex, endIndex), outerWinding);
+ markDone(SkMin32(startIndex, endIndex), outerWinding, oppWinding);
if (!foundAngle) {
return NULL;
}
+ #if DEBUG_WINDING
+ int oldSpanSign = spanSign(nextStart, nextEnd);
+ #endif
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(" foundMax=");
- if (foundMax == SK_MinS32) {
- SkDebugf("?");
- } else {
- SkDebugf("%d", foundMax);
- }
- SkDebugf("\n");
+ SkDebugf("%s foundFlipped=%d spanWinding=%d oldSpanSign=%d spanSign=%d\n",
+ __FUNCTION__, foundFlipped, spanWinding, oldSpanSign,
+ nextSegment->spanSign(foundAngle));
+ SkDebugf("%s foundOpp=%d oppWinding=%d foundOppWinding=%d winding=%d foundSum=",
+ __FUNCTION__, foundOpp, oppWinding, foundOppWinding, winding);
+ if (foundSum == SK_MinS32) {
+ SkDebugf("?");
+ } else {
+ SkDebugf("%d", foundSum);
+ }
+ SkDebugf("\n");
#endif
- winding = foundSum;
+ if (oppWinding != foundOppWinding) {
+ oppWinding = foundOppWinding;
+ if (foundOpp) {
+ SkASSERT(foundSum != SK_MinS32);
+ winding = foundSum;
+ spanWinding = nextSegment->spanSign(foundAngle);
+ }
}
- #if DEBUG_WINDING
- SkDebugf("%s spanWinding=%d flipped=%d\n", __FUNCTION__, spanWinding, flipped);
- #endif
return nextSegment;
}
@@ -2160,11 +2074,7 @@ public:
SkASSERT(startIndex < endIndex ? startIndex < count - 1
: startIndex > 0);
int step = SkSign32(endIndex - startIndex);
- #if PRECISE_T_SORT
int end = nextExactSpan(startIndex, step);
- #else
- int end = nextSpan(startIndex, step);
- #endif
SkASSERT(end >= 0);
Span* endSpan = &fTs[end];
Segment* other;
@@ -2182,11 +2092,7 @@ public:
do {
nextEnd += step;
}
- #if PRECISE_T_SORT
while (precisely_zero(startT - other->fTs[nextEnd].fT));
- #else
- while (approximately_zero(startT - other->fTs[nextEnd].fT));
- #endif
SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count());
return other;
}
@@ -2195,14 +2101,14 @@ public:
SkASSERT(startIndex - endIndex != 0);
SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
addTwoAngles(startIndex, end, angles);
- buildAngles(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);
+ debugShowSort(__FUNCTION__, sorted, firstIndex, winding, 0);
#endif
if (!sortable) {
unsortable = true;
@@ -2225,7 +2131,6 @@ public:
// iterate through the angle, and compute everyone's winding
bool altFlipped = false;
bool foundFlipped = false;
- int foundMax = SK_MinS32;
int foundSum = SK_MinS32;
Segment* nextSegment;
int lastNonZeroSum = winding;
@@ -2250,8 +2155,9 @@ public:
#endif
if (!sumWinding) {
if (!active) {
+ // FIXME: shouldn't this call mark and chase done ?
markDone(SkMin32(startIndex, endIndex), outerWinding);
- // FIXME: seems like a bug that this isn't calling userInnerWinding
+ // FIXME: shouldn't this call mark and chase winding ?
nextSegment->markWinding(SkMin32(nextAngle->start(),
nextAngle->end()), maxWinding);
#if DEBUG_WINDING
@@ -2263,7 +2169,6 @@ public:
foundAngle = nextAngle;
foundDone = nextDone && !nextTiny;
foundFlipped = altFlipped;
- foundMax = maxWinding;
}
continue;
}
@@ -2319,12 +2224,6 @@ public:
} else {
SkDebugf("%d", foundSum);
}
- SkDebugf(" foundMax=");
- if (foundMax == SK_MinS32) {
- SkDebugf("?");
- } else {
- SkDebugf("%d", foundMax);
- }
SkDebugf("\n");
#endif
winding = foundSum;
@@ -2343,11 +2242,7 @@ public:
SkASSERT(startIndex < endIndex ? startIndex < count - 1
: startIndex > 0);
int step = SkSign32(endIndex - startIndex);
- #if PRECISE_T_SORT
int end = nextExactSpan(startIndex, step);
- #else
- int end = nextSpan(startIndex, step);
- #endif
SkASSERT(end >= 0);
Span* endSpan = &fTs[end];
Segment* other;
@@ -2370,11 +2265,7 @@ public:
do {
nextEnd += step;
}
- #if PRECISE_T_SORT
while (precisely_zero(startT - other->fTs[nextEnd].fT));
- #else
- while (approximately_zero(startT - other->fTs[nextEnd].fT));
- #endif
if (other->fTs[SkMin32(nextStart, nextEnd)].fWindValue) {
break;
}
@@ -2391,14 +2282,14 @@ public:
SkASSERT(startIndex - endIndex != 0);
SkASSERT((startIndex - endIndex < 0) ^ (step < 0));
addTwoAngles(startIndex, end, angles);
- buildAngles(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, 0);
+ debugShowSort(__FUNCTION__, sorted, firstIndex, 0, 0);
#endif
if (!sortable) {
unsortable = true;
@@ -2626,11 +2517,11 @@ public:
SkTDArray<Angle> angles;
SkASSERT(firstT - end != 0);
addTwoAngles(end, firstT, angles);
- buildAngles(firstT, angles);
+ buildAngles(firstT, angles, true);
SkTDArray<Angle*> sorted;
bool sortable = SortAngles(angles, sorted);
#if DEBUG_SORT
- sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0);
+ sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
#endif
if (!sortable) {
return NULL;
@@ -2687,6 +2578,22 @@ public:
return last;
}
+ Span* innerChaseDone(int index, int step, int winding, int oppWinding) {
+ int end = nextExactSpan(index, step);
+ SkASSERT(end >= 0);
+ if (multipleSpans(end)) {
+ return &fTs[end];
+ }
+ const Span& endSpan = fTs[end];
+ Segment* other = endSpan.fOther;
+ index = endSpan.fOtherIndex;
+ int otherEnd = other->nextExactSpan(index, step);
+ Span* last = other->innerChaseDone(index, step, winding, oppWinding);
+ other->markDone(SkMin32(index, otherEnd), winding, oppWinding);
+ return last;
+ }
+
+
Span* innerChaseWinding(int index, int step, int winding) {
int end = nextExactSpan(index, step);
SkASSERT(end >= 0);
@@ -2707,6 +2614,26 @@ public:
return last;
}
+ Span* innerChaseWinding(int index, int step, int winding, int oppWinding) {
+ int end = nextExactSpan(index, step);
+ SkASSERT(end >= 0);
+ if (multipleSpans(end)) {
+ return &fTs[end];
+ }
+ const Span& endSpan = fTs[end];
+ Segment* other = endSpan.fOther;
+ index = endSpan.fOtherIndex;
+ int otherEnd = other->nextExactSpan(index, step);
+ int min = SkMin32(index, otherEnd);
+ if (other->fTs[min].fWindSum != SK_MinS32) {
+ SkASSERT(other->fTs[min].fWindSum == winding);
+ return NULL;
+ }
+ Span* last = other->innerChaseWinding(index, step, winding, oppWinding);
+ other->markWinding(min, winding, oppWinding);
+ return last;
+ }
+
void init(const SkPoint pts[], SkPath::Verb verb, bool operand) {
fDoneSpans = 0;
fOperand = operand;
@@ -2784,12 +2711,29 @@ public:
Span* markAndChaseDone(const Angle* angle, int winding) {
int index = angle->start();
int endIndex = angle->end();
+ return markAndChaseDone(index, endIndex, winding);
+ }
+
+ Span* markAndChaseDone(const Angle* angle, int winding, int oppWinding) {
+ int index = angle->start();
+ int endIndex = angle->end();
+ return markAndChaseDone(index, endIndex, winding, oppWinding);
+ }
+
+ Span* markAndChaseDone(int index, int endIndex, int winding) {
int step = SkSign32(endIndex - index);
Span* last = innerChaseDone(index, step, winding);
markDone(SkMin32(index, endIndex), winding);
return last;
}
+ Span* markAndChaseDone(int index, int endIndex, int winding, int oppWinding) {
+ int step = SkSign32(endIndex - index);
+ Span* last = innerChaseDone(index, step, winding, oppWinding);
+ markDone(SkMin32(index, endIndex), winding, oppWinding);
+ return last;
+ }
+
Span* markAndChaseWinding(const Angle* angle, int winding) {
int index = angle->start();
int endIndex = angle->end();
@@ -2800,6 +2744,16 @@ public:
return last;
}
+ Span* markAndChaseWinding(const Angle* angle, int winding, int oppWinding) {
+ int index = angle->start();
+ int endIndex = angle->end();
+ int min = SkMin32(index, endIndex);
+ int step = SkSign32(endIndex - index);
+ Span* last = innerChaseWinding(index, step, winding, oppWinding);
+ markWinding(min, winding, oppWinding);
+ return last;
+ }
+
// FIXME: this should also mark spans with equal (x,y)
// This may be called when the segment is already marked done. While this
// wastes time, it shouldn't do any more than spin through the T spans.
@@ -2810,21 +2764,25 @@ public:
SkASSERT(winding);
double referenceT = fTs[index].fT;
int lesser = index;
- #if PRECISE_T_SORT
while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
markOneDone(__FUNCTION__, lesser, winding);
}
do {
markOneDone(__FUNCTION__, index, winding);
} while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
- #else
- while (--lesser >= 0 && approximately_negative(referenceT - fTs[lesser].fT)) {
- markOneDone(__FUNCTION__, lesser, winding);
+ }
+
+ void markDone(int index, int winding, int oppWinding) {
+ // SkASSERT(!done());
+ SkASSERT(winding);
+ double referenceT = fTs[index].fT;
+ int lesser = index;
+ while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
+ markOneDone(__FUNCTION__, lesser, winding, oppWinding);
}
do {
- markOneDone(__FUNCTION__, index, winding);
- } while (++index < fTs.count() && approximately_negative(fTs[index].fT - referenceT));
- #endif
+ markOneDone(__FUNCTION__, index, winding, oppWinding);
+ } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
}
void markOneDone(const char* funName, int tIndex, int winding) {
@@ -2836,6 +2794,15 @@ public:
fDoneSpans++;
}
+ void markOneDone(const char* funName, int tIndex, int winding, int oppWinding) {
+ Span* span = markOneWinding(funName, tIndex, winding, oppWinding);
+ if (!span) {
+ return;
+ }
+ span->fDone = true;
+ fDoneSpans++;
+ }
+
Span* markOneWinding(const char* funName, int tIndex, int winding) {
Span& span = fTs[tIndex];
if (span.fDone) {
@@ -2852,6 +2819,27 @@ public:
return &span;
}
+ Span* markOneWinding(const char* funName, int tIndex, int winding, int oppWinding) {
+ Span& span = fTs[tIndex];
+ if (span.fDone) {
+ return NULL;
+ }
+ #if DEBUG_MARK_DONE
+ debugShowNewWinding(funName, span, winding, oppWinding);
+ #endif
+ SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
+ #ifdef SK_DEBUG
+ SkASSERT(abs(winding) <= gDebugMaxWindSum);
+ #endif
+ span.fWindSum = winding;
+ SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding);
+ #ifdef SK_DEBUG
+ SkASSERT(abs(oppWinding) <= gDebugMaxWindSum);
+ #endif
+ span.fOppSum = oppWinding;
+ return &span;
+ }
+
// 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.
@@ -2875,21 +2863,25 @@ public:
SkASSERT(winding);
double referenceT = fTs[index].fT;
int lesser = index;
- #if PRECISE_T_SORT
while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
markOneWinding(__FUNCTION__, lesser, winding);
}
do {
markOneWinding(__FUNCTION__, index, winding);
} while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
- #else
- while (--lesser >= 0 && approximately_negative(referenceT - fTs[lesser].fT)) {
- markOneWinding(__FUNCTION__, lesser, winding);
+ }
+
+ void markWinding(int index, int winding, int oppWinding) {
+ // SkASSERT(!done());
+ SkASSERT(winding);
+ double referenceT = fTs[index].fT;
+ int lesser = index;
+ while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) {
+ markOneWinding(__FUNCTION__, lesser, winding, oppWinding);
}
do {
- markOneWinding(__FUNCTION__, index, winding);
- } while (++index < fTs.count() && approximately_negative(fTs[index].fT - referenceT));
- #endif
+ markOneWinding(__FUNCTION__, index, winding, oppWinding);
+ } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT));
}
void matchWindingValue(int tIndex, double t, bool borrowWind) {
@@ -2950,7 +2942,6 @@ public:
return -1;
}
-#if PRECISE_T_SORT
// FIXME
// this returns at any difference in T, vs. a preset minimum. It may be
// that all callers to nextSpan should use this instead.
@@ -2969,19 +2960,18 @@ public:
}
return -1;
}
-#endif
bool operand() const {
return fOperand;
}
- int oppSign(int startIndex, int endIndex) const {
- int result = startIndex < endIndex ? -fTs[startIndex].fWindValueOpp :
- fTs[endIndex].fWindValueOpp;
-#if DEBUG_WIND_BUMP
- SkDebugf("%s spanSign=%d\n", __FUNCTION__, result);
-#endif
- return result;
+ int oppSum(int tIndex) const {
+ return fTs[tIndex].fOppSum;
+ }
+
+ int oppSum(const Angle* angle) const {
+ int lesser = SkMin32(angle->start(), angle->end());
+ return fTs[lesser].fOppSum;
}
const SkPoint* pts() const {
@@ -3037,8 +3027,8 @@ public:
}
int spanSign(int startIndex, int endIndex) const {
- int result = startIndex < endIndex ? -fTs[startIndex].fWindValue :
- fTs[endIndex].fWindValue;
+ int result = startIndex < endIndex ? -fTs[startIndex].fWindValue
+ : fTs[endIndex].fWindValue;
#if DEBUG_WIND_BUMP
SkDebugf("%s spanSign=%d\n", __FUNCTION__, result);
#endif
@@ -3094,7 +3084,7 @@ public:
SkPath::Verb verb() const {
return fVerb;
}
-
+
int windSum(int tIndex) const {
return fTs[tIndex].fWindSum;
}
@@ -3116,7 +3106,7 @@ public:
int index = SkMin32(start, end);
return windValue(index);
}
-
+
SkScalar xAtT(const Span* span) const {
return xyAtT(span).fX;
}
@@ -3295,17 +3285,45 @@ public:
}
SkDebugf(" windValue=%d\n", span.fWindValue);
}
+
+ void debugShowNewWinding(const char* fun, const Span& span, int winding, int oppWinding) {
+ const SkPoint& pt = xyAtT(&span);
+ SkDebugf("%s id=%d", fun, fID);
+ SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
+ for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
+ SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
+ }
+ SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther->
+ fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]);
+ SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) newWindSum=%d newOppSum=%d oppSum=",
+ span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY,
+ winding, oppWinding);
+ if (span.fOppSum == SK_MinS32) {
+ SkDebugf("?");
+ } else {
+ SkDebugf("%d", span.fOppSum);
+ }
+ SkDebugf(" windSum=");
+ if (span.fWindSum == SK_MinS32) {
+ SkDebugf("?");
+ } else {
+ SkDebugf("%d", span.fWindSum);
+ }
+ SkDebugf(" windValue=%d\n", span.fWindValue);
+ }
#endif
#if DEBUG_SORT
void debugShowSort(const char* fun, const SkTDArray<Angle*>& angles, int first,
- const int contourWinding) const {
+ const int contourWinding, const int oppContourWinding) const {
SkASSERT(angles[first]->segment() == this);
SkASSERT(angles.count() > 1);
int lastSum = contourWinding;
+ int oppLastSum = oppContourWinding;
int windSum = lastSum - spanSign(angles[first]);
- SkDebugf("%s %s contourWinding=%d sign=%d\n", fun, __FUNCTION__,
- contourWinding, spanSign(angles[first]));
+ int oppWindSum = oppLastSum;
+ SkDebugf("%s %s contourWinding=%d oppContourWinding=%d sign=%d\n", fun, __FUNCTION__,
+ contourWinding, oppContourWinding, spanSign(angles[first]));
int index = first;
bool firstTime = true;
do {
@@ -3316,9 +3334,15 @@ public:
const Span& sSpan = segment.fTs[start];
const Span& eSpan = segment.fTs[end];
const Span& mSpan = segment.fTs[SkMin32(start, end)];
+ bool opp = segment.fOperand ^ fOperand;
if (!firstTime) {
- lastSum = windSum;
- windSum -= segment.spanSign(&angle);
+ if (opp) {
+ oppLastSum = oppWindSum;
+ oppWindSum -= segment.spanSign(&angle);
+ } else {
+ lastSum = windSum;
+ windSum -= segment.spanSign(&angle);
+ }
}
SkDebugf("%s [%d] %sid=%d %s start=%d (%1.9g,%,1.9g) end=%d (%1.9g,%,1.9g)"
" sign=%d windValue=%d windSum=",
@@ -3332,9 +3356,17 @@ public:
} else {
SkDebugf("%d", mSpan.fWindSum);
}
- SkDebugf(" winding: %d->%d (max=%d) done=%d tiny=%d\n", lastSum, windSum,
- useInnerWinding(lastSum, windSum) ? windSum : lastSum,
- mSpan.fDone, mSpan.fTiny);
+ int last, wind;
+ if (opp) {
+ last = oppLastSum;
+ wind = oppWindSum;
+ } else {
+ last = lastSum;
+ wind = windSum;
+ }
+ SkDebugf(" winding: %d->%d (max=%d) ", last, wind,
+ useInnerWinding(last, wind) ? wind : last);
+ SkDebugf(" done=%d tiny=%d opp=%d\n", mSpan.fDone, mSpan.fTiny, opp);
#if false && DEBUG_ANGLE
angle.debugShow(segment.xyAtT(&sSpan));
#endif
@@ -3463,13 +3495,6 @@ public:
return fBounds;
}
- void collapseTriangles() {
- int segmentCount = fSegments.count();
- for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
- fSegments[sIndex].collapseTriangles(fXor);
- }
- }
-
void complete() {
setBounds();
fContainsIntercepts = false;
@@ -3547,6 +3572,10 @@ public:
fSegments[sIndex].fixOtherTIndex();
}
}
+
+ bool operand() const {
+ return fOperand;
+ }
void reset() {
fSegments.reset();
@@ -3627,7 +3656,6 @@ public:
fXor = isXor;
}
-#if !SORTABLE_CONTOURS
void sortSegments() {
int segmentCount = fSegments.count();
fSortedSegments.setReserve(segmentCount);
@@ -3637,7 +3665,6 @@ public:
QSort<Segment>(fSortedSegments.begin(), fSortedSegments.end() - 1);
fFirstSorted = 0;
}
-#endif
const SkPoint& start() const {
return fSegments.front().pts()[0];
@@ -3709,7 +3736,6 @@ public:
}
#endif
-#if !SORTABLE_CONTOURS
Segment* topSortableSegment(const SkPoint& topLeft, SkPoint& bestXY) {
int segmentCount = fSortedSegments.count();
SkASSERT(segmentCount > 0);
@@ -3742,7 +3768,6 @@ public:
}
return bestSegment;
}
-#endif
Segment* undoneSegment(int& start, int& end) {
int segmentCount = fSegments.count();
@@ -3822,10 +3847,8 @@ protected:
private:
SkTArray<Segment> fSegments;
-#if !SORTABLE_CONTOURS
SkTDArray<Segment*> fSortedSegments;
int fFirstSorted;
-#endif
SkTDArray<Coincidence> fCoincidences;
SkTDArray<const Contour*> fCrosses;
Bounds fBounds;
@@ -3867,6 +3890,8 @@ void init() {
}
void addOperand(const SkPath& path) {
+ SkASSERT(fPathVerbs.count() > 0 && fPathVerbs.end()[-1] == SkPath::kDone_Verb);
+ fPathVerbs.pop();
fPath = &path;
fXorMask = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
preFetch();
@@ -3924,7 +3949,7 @@ int preFetch() {
fPathPts.append(verb, &pts[1]);
}
} while (verb != SkPath::kDone_Verb);
- return fPathVerbs.count();
+ return fPathVerbs.count() - 1;
}
void walk() {
@@ -3946,7 +3971,7 @@ void walk() {
*fExtra.append() = -1; // start new contour
}
finalCurveEnd = pointsPtr++;
- continue;
+ goto nextVerb;
case SkPath::kLine_Verb:
// skip degenerate points
if (pointsPtr[-1].fX != pointsPtr[0].fX
@@ -3994,7 +4019,7 @@ void walk() {
fCurrentContour->addLine(fReducePts.end() - 2);
}
complete();
- continue;
+ goto nextVerb;
default:
SkDEBUGFAIL("bad verb");
return;
@@ -4002,6 +4027,7 @@ void walk() {
finalCurveStart = &pointsPtr[verb - 1];
pointsPtr += verb;
SkASSERT(fCurrentContour);
+ nextVerb:
if (verbPtr == endOfFirstHalf) {
fOperand = true;
}
@@ -4486,13 +4512,6 @@ static void coincidenceCheck(SkTDArray<Contour*>& contourList) {
Contour* contour = contourList[cIndex];
contour->findTooCloseToCall();
}
-#if 0
- // OPTIMIZATION: this check could be folded in with findTooClose -- maybe
- for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
- Contour* contour = contourList[cIndex];
- contour->collapseTriangles();
- }
-#endif
}
// project a ray from the top of the contour up and see if it hits anything
@@ -4500,38 +4519,24 @@ static void coincidenceCheck(SkTDArray<Contour*>& contourList) {
// two contours touch, so we need only look at contours not touching this one.
// OPTIMIZATION: sort contourList vertically to avoid linear walk
static int innerContourCheck(SkTDArray<Contour*>& contourList,
- const Segment* current, int index, int endIndex) {
+ const Segment* current, int index, int endIndex, bool opp) {
const SkPoint& basePt = current->xyAtT(endIndex);
int contourCount = contourList.count();
SkScalar bestY = SK_ScalarMin;
const Segment* test = NULL;
int tIndex;
double tHit;
- // bool checkCrosses = true;
for (int cTest = 0; cTest < contourCount; ++cTest) {
Contour* contour = contourList[cTest];
- if (basePt.fY < contour->bounds().fTop) {
+ if (contour->operand() ^ current->operand() != opp) {
continue;
}
- if (bestY > contour->bounds().fBottom) {
+ if (basePt.fY < contour->bounds().fTop) {
continue;
}
-#if 0
- // even though the contours crossed, if spans cancel through concidence,
- // the contours may be not have any span links to chase, and the current
- // segment may be isolated. Detect this by seeing if current has
- // uninitialized wind sums. If so, project a ray instead of relying on
- // previously found intersections.
- if (baseContour == contour) {
+ if (bestY > contour->bounds().fBottom) {
continue;
}
- if (checkCrosses && baseContour->crosses(contour)) {
- if (current->isConnected(index, endIndex)) {
- continue;
- }
- checkCrosses = false;
- }
-#endif
const Segment* next = contour->crossedSegment(basePt, bestY, tIndex, tHit);
if (next) {
test = next;
@@ -4559,7 +4564,7 @@ static int innerContourCheck(SkTDArray<Contour*>& contourList,
#endif
return 0;
}
- test->buildAngles(tIndex, angles);
+ test->buildAngles(tIndex, angles, false);
SkTDArray<Angle*> sorted;
// OPTIMIZATION: call a sort that, if base point is the leftmost,
// returns the first counterclockwise hour before 6 o'clock,
@@ -4567,7 +4572,7 @@ static int innerContourCheck(SkTDArray<Contour*>& contourList,
// hour after 6 o'clock
(void) Segment::SortAngles(angles, sorted);
#if DEBUG_SORT
- sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0);
+ sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
#endif
// walk the sorted angle fan to find the lowest angle
// above the base point. Currently, the first angle in the sorted array
@@ -4658,43 +4663,6 @@ static int innerContourCheck(SkTDArray<Contour*>& contourList,
return winding;
}
-#if SORTABLE_CONTOURS
-// OPTIMIZATION: not crazy about linear search here to find top active y.
-// seems like we should break down and do the sort, or maybe sort each
-// contours' segments?
-// Once the segment array is built, there's no reason I can think of not to
-// sort it in Y. hmmm
-// FIXME: return the contour found to pass to inner contour check
-static Segment* findTopContour(SkTDArray<Contour*>& contourList) {
- int contourCount = contourList.count();
- int cIndex = 0;
- Segment* topStart;
- SkScalar bestY = SK_ScalarMax;
- Contour* contour;
- do {
- contour = contourList[cIndex];
- topStart = contour->topSegment(bestY);
- } while (!topStart && ++cIndex < contourCount);
- if (!topStart) {
- return NULL;
- }
- while (++cIndex < contourCount) {
- contour = contourList[cIndex];
- if (bestY < contour->bounds().fTop) {
- continue;
- }
- SkScalar testY = SK_ScalarMax;
- Segment* test = contour->topSegment(testY);
- if (!test || bestY <= testY) {
- continue;
- }
- topStart = test;
- bestY = testY;
- }
- return topStart;
-}
-#endif
-
static Segment* findUndone(SkTDArray<Contour*>& contourList, int& start, int& end) {
int contourCount = contourList.count();
Segment* result;
@@ -4710,8 +4678,7 @@ static Segment* findUndone(SkTDArray<Contour*>& contourList, int& start, int& en
-static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex,
- int contourWinding) {
+static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex) {
while (chase.count()) {
Span* span;
chase.pop(&span);
@@ -4737,7 +4704,7 @@ static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex,
SkTDArray<Angle*> sorted;
bool sortable = Segment::SortAngles(angles, sorted);
#if DEBUG_SORT
- sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0);
+ sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
#endif
if (!sortable) {
continue;
@@ -4753,15 +4720,15 @@ static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex,
} while (winding == SK_MinS32);
int spanWinding = segment->spanSign(angle->start(), angle->end());
#if DEBUG_WINDING
- SkDebugf("%s winding=%d spanWinding=%d contourWinding=%d\n",
- __FUNCTION__, winding, spanWinding, contourWinding);
+ SkDebugf("%s winding=%d spanWinding=%d\n",
+ __FUNCTION__, winding, spanWinding);
#endif
- // turn swinding into contourWinding
+ // turn span winding into contour winding
if (spanWinding * winding < 0) {
winding += spanWinding;
}
#if DEBUG_SORT
- segment->debugShowSort(__FUNCTION__, sorted, firstIndex, winding);
+ segment->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, 0);
#endif
// we care about first sign and whether wind sum indicates this
// edge is inside or outside. Maybe need to pass span winding
@@ -4826,11 +4793,11 @@ static void debugShowActiveSpans(SkTDArray<Contour*>& contourList) {
#endif
static bool windingIsActive(int winding, int spanWinding) {
+ // FIXME: !spanWinding test must be superflorous, true?
return winding * spanWinding <= 0 && abs(winding) <= abs(spanWinding)
&& (!winding || !spanWinding || winding == -spanWinding);
}
-#if !SORTABLE_CONTOURS
static Segment* findSortableTop(SkTDArray<Contour*>& contourList, int& index,
int& endIndex, SkPoint& topLeft) {
Segment* result;
@@ -4860,7 +4827,29 @@ static Segment* findSortableTop(SkTDArray<Contour*>& contourList, int& index,
} while (!result);
return result;
}
+
+static int updateWindings(const Segment* current, int index, int endIndex,
+ int& spanWinding, int* oppWinding) {
+ int lesser = SkMin32(index, endIndex);
+ spanWinding = current->spanSign(index, endIndex);
+ int winding = current->windSum(lesser);
+ bool inner = useInnerWinding(winding - spanWinding, winding);
+#if DEBUG_WINDING
+ SkDebugf("%s id=%d t=%1.9g spanWinding=%d winding=%d sign=%d"
+ " inner=%d result=%d\n",
+ __FUNCTION__, current->debugID(), current->t(lesser),
+ spanWinding, winding, SkSign32(index - endIndex),
+ useInnerWinding(winding - spanWinding, winding),
+ inner ? winding - spanWinding : winding);
#endif
+ if (inner) {
+ winding -= spanWinding;
+ }
+ if (oppWinding) {
+ *oppWinding = current->oppSum(lesser);
+ }
+ return winding;
+}
// Each segment may have an inside or an outside. Segments contained within
// winding may have insides on either side, and form a contour that should be
@@ -4878,22 +4867,12 @@ static bool bridgeWinding(SkTDArray<Contour*>& contourList, PathWrapper& simple)
bool closable = true;
SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
do {
-#if SORTABLE_CONTOURS // old way
- Segment* topStart = findTopContour(contourList);
- if (!topStart) {
- break;
- }
- // Start at the top. Above the top is outside, below is inside.
- // follow edges to intersection by changing the index by direction.
- int index, endIndex;
- Segment* current = topStart->findTop(index, endIndex);
-#else // new way: iterate while top is unsortable
int index, endIndex;
+ // iterates while top is unsortable
Segment* current = findSortableTop(contourList, index, endIndex, topLeft);
if (!current) {
break;
}
-#endif
int contourWinding;
if (firstContour) {
contourWinding = 0;
@@ -4906,7 +4885,7 @@ static bool bridgeWinding(SkTDArray<Contour*>& contourList, PathWrapper& simple)
}
if (sumWinding == SK_MinS32) {
contourWinding = innerContourCheck(contourList, current,
- index, endIndex);
+ index, endIndex, false);
} else {
contourWinding = sumWinding;
int spanWinding = current->spanSign(index, endIndex);
@@ -4915,8 +4894,8 @@ static bool bridgeWinding(SkTDArray<Contour*>& contourList, PathWrapper& simple)
contourWinding -= spanWinding;
}
#if DEBUG_WINDING
- SkDebugf("%s sumWinding=%d spanWinding=%d sign=%d inner=%d result=%d\n", __FUNCTION__,
- sumWinding, spanWinding, SkSign32(index - endIndex),
+ SkDebugf("%s sumWinding=%d spanWinding=%d sign=%d inner=%d result=%d\n",
+ __FUNCTION__, sumWinding, spanWinding, SkSign32(index - endIndex),
inner, contourWinding);
#endif
}
@@ -4933,9 +4912,9 @@ static bool bridgeWinding(SkTDArray<Contour*>& contourList, PathWrapper& simple)
// inner contour is wound the same way, it never finds an accumulated
// winding of zero. Inside 'find next', we need to look for transitions
// other than zero when resolving sorted angles.
- bool active = windingIsActive(winding, spanWinding);
SkTDArray<Span*> chaseArray;
do {
+ bool active = windingIsActive(winding, spanWinding);
#if DEBUG_WINDING
SkDebugf("%s active=%s winding=%d spanWinding=%d\n",
__FUNCTION__, active ? "true" : "false",
@@ -4968,35 +4947,21 @@ static bool bridgeWinding(SkTDArray<Contour*>& contourList, PathWrapper& simple)
int min = SkMin32(index, endIndex);
if (!current->done(min)) {
current->addCurveTo(index, endIndex, simple, true);
- current->markDone(SkMin32(index, endIndex), winding ? winding : spanWinding);
+ current->markDone(SkMin32(index, endIndex),
+ winding ? winding : spanWinding);
}
closable = false;
}
simple.close();
}
- current = findChase(chaseArray, index, endIndex, contourWinding);
+ current = findChase(chaseArray, index, endIndex);
#if DEBUG_ACTIVE_SPANS
debugShowActiveSpans(contourList);
#endif
if (!current) {
break;
}
- int lesser = SkMin32(index, endIndex);
- spanWinding = current->spanSign(index, endIndex);
- winding = current->windSum(lesser);
- bool inner = useInnerWinding(winding - spanWinding, winding);
- #if DEBUG_WINDING
- SkDebugf("%s id=%d t=%1.9g spanWinding=%d winding=%d sign=%d"
- " inner=%d result=%d\n",
- __FUNCTION__, current->debugID(), current->t(lesser),
- spanWinding, winding, SkSign32(index - endIndex),
- useInnerWinding(winding - spanWinding, winding),
- inner ? winding - spanWinding : winding);
- #endif
- if (inner) {
- winding -= spanWinding;
- }
- active = windingIsActive(winding, spanWinding);
+ winding = updateWindings(current, index, endIndex, spanWinding, NULL);
} while (true);
} while (true);
return closable;
@@ -5046,7 +5011,6 @@ static void fixOtherTIndex(SkTDArray<Contour*>& contourList) {
}
}
-#if !SORTABLE_CONTOURS
static void sortSegments(SkTDArray<Contour*>& contourList) {
int contourCount = contourList.count();
for (int cTest = 0; cTest < contourCount; ++cTest) {
@@ -5054,7 +5018,6 @@ static void sortSegments(SkTDArray<Contour*>& contourList) {
contour->sortSegments();
}
}
-#endif
static void makeContourList(SkTArray<Contour>& contours,
SkTDArray<Contour*>& list) {
@@ -5273,9 +5236,7 @@ void simplifyx(const SkPath& path, SkPath& result) {
// eat through coincident edges
coincidenceCheck(contourList);
fixOtherTIndex(contourList);
-#if !SORTABLE_CONTOURS
sortSegments(contourList);
-#endif
#if DEBUG_ACTIVE_SPANS
debugShowActiveSpans(contourList);
#endif
diff --git a/experimental/Intersection/SimplifyNew_Test.cpp b/experimental/Intersection/SimplifyNew_Test.cpp
index e2f64fc45f..6a805415c6 100644
--- a/experimental/Intersection/SimplifyNew_Test.cpp
+++ b/experimental/Intersection/SimplifyNew_Test.cpp
@@ -2556,55 +2556,59 @@ static void testIntersect1() {
one.addRect(0, 0, 6, 6, (SkPath::Direction) 0);
two.addRect(3, 3, 9, 9, (SkPath::Direction) 0);
operate(one, two, kIntersect_Op, result);
- SkASSERT(result.countPoints() == 4);
+ SkASSERT(result.countPoints() == 5);
SkASSERT(result.countVerbs() == 6); // move, 4 lines, close
SkRect bounds = result.getBounds();
SkASSERT(bounds.fLeft == 3);
SkASSERT(bounds.fTop == 3);
SkASSERT(bounds.fRight == 6);
SkASSERT(bounds.fBottom == 6);
+ testShapeOp(one, two, kIntersect_Op);
}
static void testUnion1() {
SkPath one, two, result;
one.addRect(0, 0, 6, 6, (SkPath::Direction) 0);
two.addRect(3, 3, 9, 9, (SkPath::Direction) 0);
- operate(one, two, kIntersect_Op, result);
- SkASSERT(result.countPoints() == 8);
+ operate(one, two, kUnion_Op, result);
+ SkASSERT(result.countPoints() == 9);
SkASSERT(result.countVerbs() == 10); // move, 8 lines, close
SkRect bounds = result.getBounds();
SkASSERT(bounds.fLeft == 0);
SkASSERT(bounds.fTop == 0);
SkASSERT(bounds.fRight == 9);
SkASSERT(bounds.fBottom == 9);
+ testShapeOp(one, two, kUnion_Op);
}
static void testDiff1() {
SkPath one, two, result;
one.addRect(0, 0, 6, 6, (SkPath::Direction) 0);
two.addRect(3, 3, 9, 9, (SkPath::Direction) 0);
- operate(one, two, kIntersect_Op, result);
- SkASSERT(result.countPoints() == 6);
- SkASSERT(result.countVerbs() == 8); // move, 8 lines, close
+ operate(one, two, kDifference_Op, result);
+ SkASSERT(result.countPoints() == 7);
+ SkASSERT(result.countVerbs() == 8); // move, 6 lines, close
SkRect bounds = result.getBounds();
SkASSERT(bounds.fLeft == 0);
SkASSERT(bounds.fTop == 0);
SkASSERT(bounds.fRight == 6);
SkASSERT(bounds.fBottom == 6);
+ testShapeOp(one, two, kDifference_Op);
}
static void testXor1() {
SkPath one, two, result;
one.addRect(0, 0, 6, 6, (SkPath::Direction) 0);
two.addRect(3, 3, 9, 9, (SkPath::Direction) 0);
- operate(one, two, kIntersect_Op, result);
- SkASSERT(result.countPoints() == 10);
- SkASSERT(result.countVerbs() == 12); // move, 8 lines, close
+ operate(one, two, kXor_Op, result);
+ SkASSERT(result.countPoints() == 14);
+ SkASSERT(result.countVerbs() == 16); // move, 6 lines, close, move, 6 lines, close
SkRect bounds = result.getBounds();
SkASSERT(bounds.fLeft == 0);
SkASSERT(bounds.fTop == 0);
- SkASSERT(bounds.fRight == 12);
- SkASSERT(bounds.fBottom == 12);
+ SkASSERT(bounds.fRight == 9);
+ SkASSERT(bounds.fBottom == 9);
+ testShapeOp(one, two, kXor_Op);
}
static void testQuadratic22() {
@@ -3213,15 +3217,15 @@ static struct {
} subTests[] = {
TEST(testXor1),
TEST(testDiff1),
- TEST(testUnion1),
TEST(testIntersect1),
+ TEST(testUnion1),
};
static const size_t subTestCount = sizeof(subTests) / sizeof(subTests[0]);
static bool skipAll = false;
-static bool runSubTests = false;
-static bool runReverse = true;
+static bool runBinaryTestsFirst = true;
+static bool runReverse = false;
void SimplifyNew_Test() {
if (skipAll) {
@@ -3232,7 +3236,7 @@ void SimplifyNew_Test() {
gDebugMaxWindValue = 4;
size_t index;
#endif
- if (runSubTests) {
+ if (runBinaryTestsFirst) {
index = subTestCount - 1;
do {
SkDebugf(" %s [%s]\n", __FUNCTION__, subTests[index].str);
@@ -3259,6 +3263,13 @@ void SimplifyNew_Test() {
}
index += runReverse ? -1 : 1;
} while (true);
+ if (!runBinaryTestsFirst) {
+ index = subTestCount - 1;
+ do {
+ SkDebugf(" %s [%s]\n", __FUNCTION__, subTests[index].str);
+ (*subTests[index].fun)();
+ } while (index--);
+ }
#ifdef SK_DEBUG
gDebugMaxWindSum = SK_MaxS32;
gDebugMaxWindValue = SK_MaxS32;