aboutsummaryrefslogtreecommitdiffhomepage
path: root/experimental
diff options
context:
space:
mode:
authorGravatar caryclark@google.com <caryclark@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-12-27 18:46:58 +0000
committerGravatar caryclark@google.com <caryclark@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-12-27 18:46:58 +0000
commit3586ece1ddbb48cabb2e7a4792be9ff5d74e40d9 (patch)
tree339722c40af7a892484142b8b099c8e35a1f8894 /experimental
parent87a1fd08f1048ea9ef23bba6bcfbc6037861eb0f (diff)
shape ops work in progress
git-svn-id: http://skia.googlecode.com/svn/trunk@6952 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'experimental')
-rw-r--r--experimental/Intersection/ShapeOps.cpp2
-rw-r--r--experimental/Intersection/Simplify.cpp554
-rw-r--r--experimental/Intersection/SimplifyNew_Test.cpp16
-rw-r--r--experimental/Intersection/op.htm12
4 files changed, 207 insertions, 377 deletions
diff --git a/experimental/Intersection/ShapeOps.cpp b/experimental/Intersection/ShapeOps.cpp
index 0e0b1debd6..57aedd6c96 100644
--- a/experimental/Intersection/ShapeOps.cpp
+++ b/experimental/Intersection/ShapeOps.cpp
@@ -140,7 +140,7 @@ static bool bridgeOp(SkTDArray<Contour*>& contourList, const ShapeOp op,
do {
int index, endIndex;
bool done;
- Segment* current = findSortableTopNew(contourList, firstContour, index, endIndex, topLeft,
+ Segment* current = findSortableTop(contourList, firstContour, index, endIndex, topLeft,
topUnsortable, done, true);
if (!current) {
if (topUnsortable || !done) {
diff --git a/experimental/Intersection/Simplify.cpp b/experimental/Intersection/Simplify.cpp
index 838067aa42..35ccbc8846 100644
--- a/experimental/Intersection/Simplify.cpp
+++ b/experimental/Intersection/Simplify.cpp
@@ -24,11 +24,9 @@
int gDebugMaxWindSum = SK_MaxS32;
int gDebugMaxWindValue = SK_MaxS32;
#endif
-bool gUseOldBridgeWinding = false;
#define PIN_ADD_T 0
#define TRY_ROTATE 1
-#define CHECK_IN_X 0
#define DEBUG_UNUSED 0 // set to expose unused functions
#define FORCE_RELEASE 0 // set force release to 1 for multiple thread -- no debugging
@@ -1928,78 +1926,7 @@ public:
return windSum(minIndex);
}
- int crossedSpanX(const SkPoint& basePt, SkScalar& bestX, double& hitT,
- bool opp) const {
- SkScalar right = fBounds.fRight;
- int bestT = -1;
- if (right <= bestX) {
- return bestT;
- }
- SkScalar left = fBounds.fLeft;
- if (left >= basePt.fX) {
- return bestT;
- }
- if (fBounds.fTop > basePt.fY) {
- return bestT;
- }
- if (fBounds.fBottom < basePt.fY) {
- return bestT;
- }
- if (fBounds.fTop == fBounds.fBottom) {
- return bestT;
- }
- int end = 0;
- do {
- int start = end;
- end = nextExactSpan(start, 1);
- if ((opp ? fTs[start].fOppValue : fTs[start].fWindValue) == 0) {
- continue;
- }
- SkPoint edge[4];
- double startT = fTs[start].fT;
- double endT = fTs[end].fT;
- (*SegmentSubDivide[fVerb])(fPts, startT, endT, edge);
- // intersect ray starting at basePt with edge
- Intersections intersections;
- // FIXME: always use original and limit results to T values within
- // start t and end t.
- // OPTIMIZE: use specialty function that intersects ray with curve,
- // returning t values only for curve (we don't care about t on ray)
- int pts = (*HSegmentIntersect[fVerb])(edge, left, right, basePt.fY,
- false, intersections);
- if (pts == 0) {
- continue;
- }
- if (pts > 1 && fVerb == SkPath::kLine_Verb) {
- // if the intersection is edge on, wait for another one
- continue;
- }
- for (int index = 0; index < pts; ++index) {
- double foundT = intersections.fT[0][index];
- double testT = startT + (endT - startT) * foundT;
- SkScalar testX = (*SegmentXAtT[fVerb])(fPts, testT);
- if (bestX < testX && testX < basePt.fX) {
- if (fVerb > SkPath::kLine_Verb
- && !approximately_less_than_zero(foundT)
- && !approximately_greater_than_one(foundT)) {
- SkScalar dy = (*SegmentDYAtT[fVerb])(fPts, testT);
- if (approximately_zero(dy)) {
- continue;
- }
- }
- bestX = testX;
- while (start + 1 < end && fTs[start].fDone) {
- ++start;
- }
- bestT = foundT < 1 ? start : end;
- hitT = testT;
- }
- }
- } while (fTs[end].fT != 1);
- return bestT;
- }
-
- int crossedSpanY(const SkPoint& basePt, SkScalar& bestY, double& hitT,
+ int crossedSpanY(const SkPoint& basePt, SkScalar& bestY, double& hitT, bool& hitSomething,
bool opp) const {
SkScalar bottom = fBounds.fBottom;
int bestT = -1;
@@ -2020,6 +1947,11 @@ public:
return bestT;
}
int end = 0;
+ int xbestT = -1;
+ double xhitT;
+ bool xhitSomething = false;
+ SkScalar xbestY = bestY;
+ bool expectNoDx = false;
do {
int start = end;
end = nextSpan(start, 1);
@@ -2031,29 +1963,58 @@ public:
double endT = fTs[end].fT;
(*SegmentSubDivide[fVerb])(fPts, startT, endT, edge);
// intersect ray starting at basePt with edge
- Intersections intersections;
+ Intersections intersections, intersectionsX;
// FIXME: always use original and limit results to T values within
// start t and end t.
// OPTIMIZE: use specialty function that intersects ray with curve,
// returning t values only for curve (we don't care about t on ray)
int pts = (*VSegmentIntersect[fVerb])(edge, top, bottom, basePt.fX,
false, intersections);
- if (pts == 0) {
- continue;
- }
- if (pts > 1 && fVerb == SkPath::kLine_Verb) {
- // if the intersection is edge on, wait for another one
- continue;
+ int ptsX = (*VSegmentIntersect[fVerb])(fPts, top, bottom, basePt.fX,
+ false, intersectionsX);
+ int index;
+ for (index = 0; index < ptsX; ++index) {
+ double xfoundT = intersectionsX.fT[0][index];
+ SkScalar xtestY = (*SegmentYAtT[fVerb])(fPts, xfoundT);
+ if (approximately_negative(xtestY - bestY)
+ || approximately_negative(basePt.fY - xtestY)) {
+ continue;
+ }
+ xhitSomething = true;
+ if (pts > 1 && fVerb == SkPath::kLine_Verb) {
+ // if the intersection is edge on, wait for another one
+ expectNoDx = true;
+ break;
+ }
+ if (fVerb > SkPath::kLine_Verb
+ && !approximately_negative(xfoundT - startT)
+ && !approximately_negative(endT - xfoundT)) {
+ SkScalar xdx = (*SegmentDXAtT[fVerb])(fPts, xfoundT);
+ if (approximately_zero(xdx)) {
+ continue;
+ }
+ }
+ xbestY = xtestY;
+ while (start + 1 < end && fTs[start].fDone) {
+ ++start;
+ }
+ xbestT = xfoundT < 1 ? start : end;
+ xhitT = xfoundT;
}
- for (int index = 0; index < pts; ++index) {
+ for (index = 0; index < pts; ++index) {
double foundT = intersections.fT[0][index];
- double testT = startT + (endT - startT) * foundT;
- SkScalar testY = (*SegmentYAtT[fVerb])(fPts, testT);
+ SkScalar testY = (*SegmentYAtT[fVerb])(edge, foundT);
if (bestY < testY && testY < basePt.fY) {
+ hitSomething = true;
+ if (pts > 1 && fVerb == SkPath::kLine_Verb) {
+ // if the intersection is edge on, wait for another one
+ SkASSERT(expectNoDx);
+ return -1;
+ }
if (fVerb > SkPath::kLine_Verb
&& !approximately_less_than_zero(foundT)
&& !approximately_greater_than_one(foundT)) {
- SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, testT);
+ SkScalar dx = (*SegmentDXAtT[fVerb])(edge, foundT);
if (approximately_zero(dx)) {
continue;
}
@@ -2063,10 +2024,29 @@ public:
++start;
}
bestT = foundT < 1 ? start : end;
- hitT = testT;
+ hitT = startT + (endT - startT) * foundT;
}
}
} while (fTs[end].fT != 1);
+ SkASSERT(!expectNoDx);
+ if (bestT != xbestT) {
+ SkDebugf("%s mismatch bestT=%d xbestT=%d\n", __FUNCTION__, bestT, xbestT);
+ bestT = xbestT;
+ }
+ if (bestY != xbestY) {
+ SkDebugf("%s mismatch bestY=%1.9g xbestY=%1.9g\n", __FUNCTION__, bestY, xbestY);
+ bestY = xbestY;
+ }
+ if (hitT != xhitT) {
+ SkDebugf("%s mismatch hitT=%1.9g xhitT=%1.9g\n", __FUNCTION__, hitT, xhitT);
+ hitT = xhitT;
+ }
+ if (hitSomething != xhitSomething) {
+ SkDebugf("%s mismatch hitSomething=%d xhitSomething=%d\n", __FUNCTION__, hitSomething,
+ xhitSomething);
+ hitSomething = xhitSomething;
+ }
+
return bestT;
}
@@ -2925,35 +2905,60 @@ public:
fPts = pts;
fVerb = verb;
}
+
+ void initWinding(int start, int end) {
+ int local = spanSign(start, end);
+ int oppLocal = oppSign(start, end);
+ (void) markAndChaseWinding(start, end, local, oppLocal);
+ }
- void initWinding(int start, int end, bool checkInX, int winding, int oppWinding) {
+ void initWinding(int start, int end, int winding, int oppWinding) {
int local = spanSign(start, end);
- if (checkInX && !winding) {
- winding = -local;
- } else if ((local * winding >= 0) ^ (checkInX && winding != 0)) {
+ if (local * winding >= 0) {
winding += local;
}
int oppLocal = oppSign(start, end);
- if ((oppLocal * oppWinding >= 0) ^ (checkInX & oppWinding != 0)) {
+ if (oppLocal * oppWinding >= 0) {
oppWinding += oppLocal;
}
(void) markAndChaseWinding(start, end, winding, oppWinding);
}
- void initWindingX(int start, int end, double tHit, int winding, int oppWinding) {
+/*
+when we start with a vertical intersect, we try to use the dx to determine if the edge is to
+the left or the right of vertical. This determines if we need to add the span's
+sign or not. However, this isn't enough.
+If the supplied sign (winding) is zero, then we didn't hit another vertical span, so dx is needed.
+If there was a winding, then it may or may not need adjusting. If the span the winding was borrowed
+from has the same x direction as this span, the winding should change. If the dx is opposite, then
+the same winding is shared by both.
+*/
+ void initWinding(int start, int end, double tHit, int winding, SkScalar hitDx, int oppWind,
+ SkScalar hitOppDx) {
+ SkASSERT(hitDx || !winding);
SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, tHit);
SkASSERT(dx);
- int local = spanSign(start, end);
+ int windVal = windValue(SkMin32(start, end));
if (!winding) {
- winding = dx < 0 ? -local : local;
- } else if (local * winding >= 0) {
- winding += local;
+ winding = dx < 0 ? windVal : -windVal;
+ } else if (hitDx * dx >= 0) {
+ int sideWind = winding + (dx < 0 ? windVal : -windVal);
+ if (abs(winding) < abs(sideWind)) {
+ winding = sideWind;
+ }
}
int oppLocal = oppSign(start, end);
- if (oppLocal * oppWinding >= 0) {
- oppWinding += oppLocal;
+ SkASSERT(hitOppDx || !oppWind || !oppLocal);
+ int oppWindVal = oppValue(SkMin32(start, end));
+ if (!oppWind) {
+ oppWind = dx < 0 ? oppWindVal : -oppWindVal;
+ } else if (hitOppDx * dx >= 0) {
+ int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal);
+ if (abs(oppWind) < abs(oppSideWind)) {
+ oppWind = oppSideWind;
+ }
}
- (void) markAndChaseWinding(start, end, winding, oppWinding);
+ (void) markAndChaseWinding(start, end, winding, oppWind);
}
bool intersected() const {
@@ -3741,7 +3746,7 @@ public:
return updateWinding(tIndex, endIndex);
}
- int windingAtT(double tHit, int tIndex, bool crossOpp, bool& zeroDx) const {
+ int windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar& dx) const {
if (approximately_zero(tHit - t(tIndex))) { // if we hit the end of a span, disregard
return SK_MinS32;
}
@@ -3753,7 +3758,7 @@ public:
windVal);
#endif
// see if a + change in T results in a +/- change in X (compute x'(T))
- SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, tHit);
+ dx = (*SegmentDXAtT[fVerb])(fPts, tHit);
if (fVerb > SkPath::kLine_Verb && approximately_zero(dx)) {
dx = fPts[2].fX - fPts[1].fX - dx;
}
@@ -3761,7 +3766,6 @@ public:
SkDebugf("%s dx=%1.9g\n", __FUNCTION__, dx);
#endif
if (dx == 0) {
- zeroDx = true;
return SK_MinS32;
}
if (winding * dx > 0) { // if same signs, result is negative
@@ -3795,6 +3799,10 @@ public:
return windValue(index);
}
+ SkScalar xAtT(int index) const {
+ return xAtT(&fTs[index]);
+ }
+
SkScalar xAtT(const Span* span) const {
return xyAtT(span).fX;
}
@@ -4308,6 +4316,7 @@ public:
fContainsIntercepts = true;
}
+#if 0
const Segment* crossedSegmentY(const SkPoint& basePt, SkScalar& bestY,
int &tIndex, double& hitT, bool opp) {
int segmentCount = fSegments.count();
@@ -4324,6 +4333,7 @@ public:
}
return bestSegment;
}
+#endif
bool crosses(const Contour* crosser) const {
for (int index = 0; index < fCrosses.count(); ++index) {
@@ -5364,72 +5374,8 @@ static void coincidenceCheck(SkTDArray<Contour*>& contourList, int total) {
}
}
-#if CHECK_IN_X
-static int contourRangeCheckX(SkTDArray<Contour*>& contourList, Segment*& current, int& index,
- int& endIndex, double& bestHit, bool& tryAgain, double mid, bool opp) {
- SkPoint basePt;
- current->xyAtT(index, endIndex, mid, basePt);
- int contourCount = contourList.count();
- SkScalar bestX = SK_ScalarMin;
- Segment* bestSeg = NULL;
- int bestTIndex;
- bool bestOpp;
- for (int cTest = 0; cTest < contourCount; ++cTest) {
- Contour* contour = contourList[cTest];
- bool testOpp = contour->operand() ^ current->operand() ^ opp;
- if (basePt.fX < contour->bounds().fLeft) {
- continue;
- }
- if (bestX > contour->bounds().fRight) {
- continue;
- }
- int segmentCount = contour->segments().count();
- for (int test = 0; test < segmentCount; ++test) {
- Segment* testSeg = &contour->segments()[test];
- SkScalar testX = bestX;
- double testHit;
- int testTIndex = testSeg->crossedSpanX(basePt, testX, testHit, testOpp);
- if (testTIndex < 0) {
- continue;
- }
- if (testSeg == current && current->betweenTs(index, testHit, endIndex)) {
- continue;
- }
- bestSeg = testSeg;
- bestHit = testHit;
- bestOpp = testOpp;
- bestTIndex = testTIndex;
- bestX = testX;
- }
- }
- if (!bestSeg) {
- return 0;
- }
- bool zeroDx = bestSeg->windSum(bestTIndex) == SK_MinS32;
- int result;
- if (!zeroDx) {
- int tryAnother = bestSeg->windingAtTX(bestHit, bestTIndex, bestOpp);
- result = bestSeg->windingAtT(bestHit, bestTIndex, bestOpp, zeroDx);
- if (result != tryAnother) {
- SkDebugf("%s result=%d tryAnother=%d\n", __FUNCTION__, result,
- tryAnother);
- }
- result = tryAnother;
- zeroDx = false;
- }
- if (zeroDx) {
- current = bestSeg;
- index = bestTIndex;
- endIndex = bestSeg->nextSpan(bestTIndex, 1);
- tryAgain = true;
- return 0;
- }
- return result;
-}
-#endif
-
static int contourRangeCheckY(SkTDArray<Contour*>& contourList, Segment*& current, int& index,
- int& endIndex, double& bestHit, bool& tryAgain, double mid, bool opp) {
+ int& endIndex, double& bestHit, SkScalar& bestDx, bool& tryAgain, double& mid, bool opp) {
SkPoint basePt;
current->xyAtT(index, endIndex, mid, basePt);
int contourCount = contourList.count();
@@ -5437,6 +5383,7 @@ static int contourRangeCheckY(SkTDArray<Contour*>& contourList, Segment*& curre
Segment* bestSeg = NULL;
int bestTIndex;
bool bestOpp;
+ bool hitSomething = false;
for (int cTest = 0; cTest < contourCount; ++cTest) {
Contour* contour = contourList[cTest];
bool testOpp = contour->operand() ^ current->operand() ^ opp;
@@ -5451,12 +5398,28 @@ static int contourRangeCheckY(SkTDArray<Contour*>& contourList, Segment*& curre
Segment* testSeg = &contour->segments()[test];
SkScalar testY = bestY;
double testHit;
- int testTIndex = testSeg->crossedSpanY(basePt, testY, testHit, testOpp);
+ int testTIndex = testSeg->crossedSpanY(basePt, testY, testHit, hitSomething, testOpp);
if (testTIndex < 0) {
continue;
}
if (testSeg == current && current->betweenTs(index, testHit, endIndex)) {
- continue;
+ double baseT = current->t(index);
+ double endT = current->t(endIndex);
+ double newMid = (testHit - baseT) / (endT - baseT);
+#if DEBUG_WINDING
+ SkPoint midXY, newXY;
+ current->xyAtT(index, endIndex, mid, midXY);
+ current->xyAtT(index, endIndex, newMid, newXY);
+ SkDebugf("%s [%d] mid=%1.9g->%1.9g s=%1.9g (%1.9g,%1.9g) m=%1.9g (%1.9g,%1.9g)"
+ " n=%1.9g (%1.9g,%1.9g) e=%1.9g (%1.9g,%1.9g)\n", __FUNCTION__,
+ current->debugID(), mid, newMid,
+ baseT, current->xAtT(index), current->yAtT(index),
+ baseT + mid * (endT - baseT), midXY.fX, midXY.fY,
+ baseT + newMid * (endT - baseT), newXY.fX, newXY.fY,
+ endT, current->xAtT(endIndex), current->yAtT(endIndex));
+#endif
+ mid = newMid * 2; // calling loop with divide by 2 before continuing
+ return SK_MinS32;
}
bestSeg = testSeg;
bestHit = testHit;
@@ -5466,7 +5429,7 @@ static int contourRangeCheckY(SkTDArray<Contour*>& contourList, Segment*& curre
}
}
if (!bestSeg) {
- return 0;
+ return hitSomething ? SK_MinS32 : 0;
}
if (bestSeg->windSum(bestTIndex) == SK_MinS32) {
current = bestSeg;
@@ -5475,14 +5438,16 @@ static int contourRangeCheckY(SkTDArray<Contour*>& contourList, Segment*& curre
tryAgain = true;
return 0;
}
- bool zeroDx = false;
int tryAnother = bestSeg->windingAtTX(bestHit, bestTIndex, bestOpp);
- int result = bestSeg->windingAtT(bestHit, bestTIndex, bestOpp, zeroDx);
+ int result = bestSeg->windingAtT(bestHit, bestTIndex, bestOpp, bestDx);
if (result != tryAnother) {
SkDebugf("%s result=%d tryAnother=%d\n", __FUNCTION__, result,
tryAnother);
}
- SkASSERT(!zeroDx);
+ double baseT = current->t(index);
+ double endT = current->t(endIndex);
+ bestHit = baseT + mid * (endT - baseT);
+ SkASSERT(bestDx);
return result;
}
@@ -5490,6 +5455,7 @@ static int contourRangeCheckY(SkTDArray<Contour*>& contourList, Segment*& curre
// note: when we compute line intersections, we keep track of whether
// two contours touch, so we need only look at contours not touching this one.
// OPTIMIZATION: sort contourList vertically to avoid linear walk
+#if 0
static int innerContourCheck(SkTDArray<Contour*>& contourList,
const Segment* current, int index, int endIndex, bool opp) {
const SkPoint& basePt = current->xyAtT(endIndex);
@@ -5622,6 +5588,24 @@ static int innerContourCheck(SkTDArray<Contour*>& contourList,
windValue, angle->sign());
#endif
} else {
+ // start here;
+ /*
+ FIXME: fails because the span found by findTop is not the span closest to vertical
+ intersecting the found point. Because the most vertical span could be done, and the
+ span found undone, findTop should not be changed. Instead, the spans at the found
+ point need to be sorted again, and the winding found below needs to be adjusted by
+ the span signs of the spans walking from vertical to the findTop span
+ findTop could but probably shouldn't compute this adjustment, since if the found span
+ already has computed winding, we won't get to innerContourCheck --
+ best solution -- findTop could check to see if found span already has computed winding
+ before returning adjustment
+ */
+ #if 0
+ int windingTx = test->windingAtTX(tHit, tIndex, crossOpp);
+ SkScalar dx;
+ int windingT = test->windingAtT(tHit, tIndex, crossOpp, dx);
+ SkDebugf("%s windingTx=%d windingT=%d\n", __FUNCTION__, windingTx, windingT);
+ #endif
winding = crossOpp ? test->oppSum(tIndex) : test->windSum(tIndex);
if (winding == SK_MinS32) {
return SK_MinS32; // unsortable
@@ -5639,7 +5623,7 @@ static int innerContourCheck(SkTDArray<Contour*>& contourList,
dx = pts[2].fX - pts[1].fX - dx;
}
#if DEBUG_WINDING
- SkDebugf("%s dx=%1.9g\n", __FUNCTION__, dx);
+ SkDebugf("%s dx=%1.9g winding=%d\n", __FUNCTION__, dx, winding);
#endif
SkASSERT(dx != 0);
if (winding * dx > 0) { // if same signs, result is negative
@@ -5650,6 +5634,7 @@ static int innerContourCheck(SkTDArray<Contour*>& contourList,
}
return winding;
}
+#endif
static Segment* findUndone(SkTDArray<Contour*>& contourList, int& start, int& end) {
int contourCount = contourList.count();
@@ -5809,11 +5794,13 @@ static void debugShowActiveSpans(SkTDArray<Contour*>& contourList) {
}
#endif
+#if 0
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);
}
+#endif
static Segment* findSortableTop(SkTDArray<Contour*>& contourList, int& index,
int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool onlySortable) {
@@ -5851,6 +5838,7 @@ static Segment* findSortableTop(SkTDArray<Contour*>& contourList, int& index,
return result;
}
+#if 0
static int updateWindings(const Segment* current, int index, int endIndex, int& spanWinding) {
int lesser = SkMin32(index, endIndex);
spanWinding = current->spanSign(index, endIndex);
@@ -5869,23 +5857,16 @@ static int updateWindings(const Segment* current, int index, int endIndex, int&
}
return winding;
}
-
-typedef int (*RangeChecker)(SkTDArray<Contour*>& contourList, Segment*& current,
- int& index, int& endIndex, double& tHit, bool& tryAgain, double mid, bool opp);
+#endif
static int rightAngleWinding(SkTDArray<Contour*>& contourList,
- Segment*& current, int& index, int& endIndex, double& tHit, bool& checkInX, bool& tryAgain,
+ Segment*& current, int& index, int& endIndex, double& tHit, SkScalar& hitDx, bool& tryAgain,
bool opp) {
-#if CHECK_IN_X
- RangeChecker checker = checkInX ? contourRangeCheckX : contourRangeCheckY;
-#else
- RangeChecker checker = contourRangeCheckY;
-#endif
double test = 0.9;
int contourWinding;
do {
- contourWinding = (*checker)(contourList, current, index, endIndex, tHit, tryAgain, test,
- opp);
+ contourWinding = contourRangeCheckY(contourList, current, index, endIndex, tHit, hitDx,
+ tryAgain, test, opp);
if (contourWinding != SK_MinS32 || tryAgain) {
return contourWinding;
}
@@ -5913,174 +5894,7 @@ static void skipVertical(SkTDArray<Contour*>& contourList,
}
}
-static Segment* tryRightAngleRay(SkTDArray<Contour*>& contourList, int& index,
- int& endIndex, SkPoint& topLeft, bool& unsortable, bool& checkInX) {
- // the simple upward projection of the unresolved points hit unsortable angles
- // shoot rays at right angles to the segment to find its winding, ignoring angle cases
- topLeft.fX = topLeft.fY = SK_ScalarMin;
- Segment* current;
- do {
- bool done;
- current = findSortableTop(contourList, index, endIndex, topLeft, unsortable, done, false);
- SkASSERT(current); // FIXME: return to caller that path cannot be simplified (yet)
- checkInX = current->moreHorizontal(index, endIndex, unsortable);
- } while (unsortable);
- return current;
-}
-
-static Segment* findSortableTopOld(SkTDArray<Contour*>& contourList, bool& firstContour, int& index,
- int& endIndex, SkPoint& topLeft, int& contourWinding, bool& unsortable) {
- Segment* current;
- do {
- bool done;
- current = findSortableTop(contourList, index, endIndex, topLeft, unsortable, done, true);
- if (!current) {
- break;
- }
- if (firstContour) {
- contourWinding = 0;
- firstContour = false;
- break;
- }
- int sumWinding = current->windSum(SkMin32(index, endIndex));
- // FIXME: don't I have to adjust windSum to get contourWinding?
- if (sumWinding == SK_MinS32) {
- sumWinding = current->computeSum(index, endIndex, false);
- }
- if (sumWinding == SK_MinS32) {
- contourWinding = innerContourCheck(contourList, current, index, endIndex, false);
- } else {
- contourWinding = sumWinding;
- int spanWinding = current->spanSign(index, endIndex);
- bool inner = useInnerWinding(sumWinding - spanWinding, sumWinding);
- if (inner) {
- contourWinding -= spanWinding;
- }
-#if DEBUG_WINDING
- SkDebugf("%s sumWinding=%d spanWinding=%d sign=%d inner=%d result=%d\n",
- __FUNCTION__, sumWinding, spanWinding, SkSign32(index - endIndex),
- inner, contourWinding);
-#endif
- }
- } while (contourWinding == SK_MinS32);
- if (contourWinding != SK_MinS32) {
-#if DEBUG_WINDING
- SkDebugf("%s contourWinding=%d\n", __FUNCTION__, contourWinding);
-#endif
- return current;
- }
- bool checkInX;
- current = tryRightAngleRay(contourList, index, endIndex, topLeft, unsortable, checkInX);
- bool tryAgain = false;
- double tHit;
- do {
- contourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit,
- checkInX, tryAgain, false);
- } while (tryAgain);
- return current;
-}
-
-// 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
-// ignored. Segments that are coincident with opposing direction segments may
-// have outsides on either side, and should also disappear.
-// 'Normal' segments will have one inside and one outside. Subsequent connections
-// when winding should follow the intersection direction. If more than one edge
-// is an option, choose first edge that continues the inside.
- // since we start with leftmost top edge, we'll traverse through a
- // smaller angle counterclockwise to get to the next edge.
-// returns true if all edges were processed
-static bool bridgeWinding(SkTDArray<Contour*>& contourList, PathWrapper& simple) {
- bool firstContour = true;
- bool unsortable = false;
- bool topUnsortable = false;
- bool firstRetry = false;
- bool closable = true;
- SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
- do {
- int index, endIndex;
- // iterates while top is unsortable
- int contourWinding;
- Segment* current = findSortableTopOld(contourList, firstContour, index, endIndex, topLeft,
- contourWinding, topUnsortable);
- if (!current) {
- if (topUnsortable) {
- topUnsortable = false;
- SkASSERT(!firstRetry);
- firstRetry = true;
- topLeft.fX = topLeft.fY = SK_ScalarMin;
- continue;
- }
- break;
- }
- int winding = contourWinding;
- int spanWinding = current->spanSign(index, endIndex);
- // FIXME: needs work. While it works in limited situations, it does
- // not always compute winding correctly. Active should be removed and instead
- // the initial winding should be correctly passed in so that if the
- // 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.
- 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",
- winding, spanWinding);
- #endif
- do {
- SkASSERT(unsortable || !current->done());
- int nextStart = index;
- int nextEnd = endIndex;
- Segment* next = current->findNextWinding(chaseArray, active,
- nextStart, nextEnd, winding, spanWinding, unsortable);
- if (!next) {
- if (active && !unsortable && simple.hasMove()
- && current->verb() != SkPath::kLine_Verb
- && !simple.isClosed()) {
- current->addCurveTo(index, endIndex, simple, true);
- SkASSERT(simple.isClosed());
- }
- 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, active);
- current = next;
- index = nextStart;
- endIndex = nextEnd;
- } 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(min, winding ? winding : spanWinding);
- }
- closable = false;
- }
- simple.close();
- }
- current = findChase(chaseArray, index, endIndex);
- #if DEBUG_ACTIVE_SPANS
- debugShowActiveSpans(contourList);
- #endif
- if (!current) {
- break;
- }
- winding = updateWindings(current, index, endIndex, spanWinding);
- } while (true);
- } while (true);
- return closable;
-}
-
-static Segment* findSortableTopNew(SkTDArray<Contour*>& contourList, bool& firstContour, int& index,
+static Segment* findSortableTop(SkTDArray<Contour*>& contourList, bool& firstContour, int& index,
int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool binary) {
Segment* current = findSortableTop(contourList, index, endIndex, topLeft, unsortable, done,
true);
@@ -6088,7 +5902,7 @@ static Segment* findSortableTopNew(SkTDArray<Contour*>& contourList, bool& first
return NULL;
}
if (firstContour) {
- current->initWinding(index, endIndex, false, 0, 0);
+ current->initWinding(index, endIndex);
firstContour = false;
return current;
}
@@ -6103,35 +5917,30 @@ static Segment* findSortableTopNew(SkTDArray<Contour*>& contourList, bool& first
}
int contourWinding;
int oppContourWinding = 0;
-#if 1
+#if 0
contourWinding = innerContourCheck(contourList, current, index, endIndex, false);
if (contourWinding != SK_MinS32) {
if (binary) {
oppContourWinding = innerContourCheck(contourList, current, index, endIndex, true);
}
if (!binary || oppContourWinding != SK_MinS32) {
- current->initWinding(index, endIndex, false, contourWinding, oppContourWinding);
+ current->initWinding(index, endIndex, contourWinding, oppContourWinding);
return current;
}
}
#endif
// the simple upward projection of the unresolved points hit unsortable angles
// shoot rays at right angles to the segment to find its winding, ignoring angle cases
-#if CHECK_IN_X
- bool checkInX = current->moreHorizontal(index, endIndex, unsortable);
-#else
- bool checkInX = false;
-#endif
bool tryAgain;
double tHit;
+ SkScalar hitDx = 0;
+ SkScalar hitOppDx = 0;
do {
-#if !CHECK_IN_X
// if current is vertical, find another candidate which is not
// if only remaining candidates are vertical, then they can be marked done
skipVertical(contourList, current, index, endIndex);
-#endif
tryAgain = false;
- contourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, checkInX,
+ contourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, hitDx,
tryAgain, false);
if (tryAgain) {
continue;
@@ -6139,19 +5948,16 @@ static Segment* findSortableTopNew(SkTDArray<Contour*>& contourList, bool& first
if (!binary) {
break;
}
- oppContourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, checkInX,
+ oppContourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, hitOppDx,
tryAgain, true);
} while (tryAgain);
-#if CHECK_IN_X
- current->initWinding(index, endIndex, checkInX, contourWinding, oppContourWinding);
-#else
- current->initWindingX(index, endIndex, tHit, contourWinding, oppContourWinding);
-#endif
+
+ current->initWinding(index, endIndex, tHit, contourWinding, hitDx, oppContourWinding, hitOppDx);
return current;
}
// rewrite that abandons keeping local track of winding
-static bool bridgeWindingX(SkTDArray<Contour*>& contourList, PathWrapper& simple) {
+static bool bridgeWinding(SkTDArray<Contour*>& contourList, PathWrapper& simple) {
bool firstContour = true;
bool unsortable = false;
bool topUnsortable = false;
@@ -6159,7 +5965,7 @@ static bool bridgeWindingX(SkTDArray<Contour*>& contourList, PathWrapper& simple
do {
int index, endIndex;
bool topDone;
- Segment* current = findSortableTopNew(contourList, firstContour, index, endIndex, topLeft,
+ Segment* current = findSortableTop(contourList, firstContour, index, endIndex, topLeft,
topUnsortable, topDone, false);
if (!current) {
if (topUnsortable || !topDone) {
@@ -6541,9 +6347,7 @@ void simplifyx(const SkPath& path, SkPath& result) {
debugShowActiveSpans(contourList);
#endif
// construct closed contours
- if (builder.xorMask() == kWinding_Mask
- ? gUseOldBridgeWinding ? !bridgeWinding(contourList, simple)
- : bridgeWindingX(contourList, simple)
+ if (builder.xorMask() == kWinding_Mask ? bridgeWinding(contourList, simple)
: !bridgeXor(contourList, simple))
{ // if some edges could not be resolved, assemble remaining fragments
SkPath temp;
diff --git a/experimental/Intersection/SimplifyNew_Test.cpp b/experimental/Intersection/SimplifyNew_Test.cpp
index ecdf489614..0ff1b6b0e2 100644
--- a/experimental/Intersection/SimplifyNew_Test.cpp
+++ b/experimental/Intersection/SimplifyNew_Test.cpp
@@ -3269,12 +3269,26 @@ static void testQuadratic82() {
testSimplifyx(path);
}
-static void (*firstTest)() = testQuadratic82;
+static void testQuadratic83() {
+ SkPath path, pathB;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 2, 0);
+ path.lineTo(2, 2);
+ path.close();
+ path.moveTo(0, 1);
+ path.lineTo(0, 2);
+ path.quadTo(2, 2, 1, 3);
+ path.close();
+ testSimplifyx(path);
+}
+
+static void (*firstTest)() = testQuadratic83;
static struct {
void (*fun)();
const char* str;
} tests[] = {
+ TEST(testQuadratic83),
TEST(testQuadratic82),
TEST(testQuadratic81),
TEST(testQuadratic80),
diff --git a/experimental/Intersection/op.htm b/experimental/Intersection/op.htm
index ce8f14155c..841c5a078d 100644
--- a/experimental/Intersection/op.htm
+++ b/experimental/Intersection/op.htm
@@ -3090,11 +3090,23 @@ path.close();
path.close();
</div>
+<div id="testQuadratic83">
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 2, 0);
+ path.lineTo(2, 2);
+ path.close();
+ path.moveTo(0, 1);
+ path.lineTo(0, 2);
+ path.quadTo(2, 2, 1, 3);
+ path.close();
+</div>
+
</div>
<script type="text/javascript">
var testDivs = [
+ testQuadratic83,
testQuadratic82,
testQuadratic81,
testQuadratic80,