aboutsummaryrefslogtreecommitdiffhomepage
path: root/experimental
diff options
context:
space:
mode:
authorGravatar caryclark@google.com <caryclark@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-12-21 21:34:36 +0000
committerGravatar caryclark@google.com <caryclark@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-12-21 21:34:36 +0000
commitdb0b3e099f888213535c4ad4c785b84544309033 (patch)
treead55aabb844f5044ffa4186d67264f181538649a /experimental
parent635c331b29ae9c9be8e0e4059881558acd660cc9 (diff)
shape ops work in progress
git-svn-id: http://skia.googlecode.com/svn/trunk@6929 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'experimental')
-rw-r--r--experimental/Intersection/LineIntersection.cpp3
-rw-r--r--experimental/Intersection/ShapeOps.cpp7
-rw-r--r--experimental/Intersection/Simplify.cpp688
-rw-r--r--experimental/Intersection/SimplifyFindTop_Test.cpp4
-rw-r--r--experimental/Intersection/SimplifyNew_Test.cpp212
-rw-r--r--experimental/Intersection/op.htm95
6 files changed, 802 insertions, 207 deletions
diff --git a/experimental/Intersection/LineIntersection.cpp b/experimental/Intersection/LineIntersection.cpp
index c425cd1ff5..394d4ddfc3 100644
--- a/experimental/Intersection/LineIntersection.cpp
+++ b/experimental/Intersection/LineIntersection.cpp
@@ -76,6 +76,9 @@ int intersect(const _Line& a, const _Line& b, double aRange[2], double bRange[2]
double a1 = aPtr[2];
double b0 = bPtr[0];
double b1 = bPtr[2];
+ // OPTIMIZATION: restructure to reject before the divide
+ // e.g., if ((a0 - b0) * (a0 - a1) < 0 || abs(a0 - b0) > abs(a0 - a1))
+ // (except efficient)
double at0 = (a0 - b0) / (a0 - a1);
double at1 = (a0 - b1) / (a0 - a1);
if ((at0 < 0 && at1 < 0) || (at0 > 1 && at1 > 1)) {
diff --git a/experimental/Intersection/ShapeOps.cpp b/experimental/Intersection/ShapeOps.cpp
index 281cf7f8ad..0e0b1debd6 100644
--- a/experimental/Intersection/ShapeOps.cpp
+++ b/experimental/Intersection/ShapeOps.cpp
@@ -72,11 +72,11 @@ static Segment* findChaseOp(SkTDArray<Span*>& chase, int& nextStart, int& nextEn
if (nextIndex == angleCount) {
nextIndex = 0;
}
- int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
angle = sorted[nextIndex];
segment = angle->segment();
int start = angle->start();
int end = angle->end();
+ int maxWinding, sumWinding, oppMaxWinding, oppSumWinding;
segment->setUpWindings(start, end, sumMiWinding, sumSuWinding,
maxWinding, sumWinding, oppMaxWinding, oppSumWinding);
if (!segment->done(angle)) {
@@ -139,10 +139,11 @@ static bool bridgeOp(SkTDArray<Contour*>& contourList, const ShapeOp op,
SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
do {
int index, endIndex;
+ bool done;
Segment* current = findSortableTopNew(contourList, firstContour, index, endIndex, topLeft,
- topUnsortable);
+ topUnsortable, done, true);
if (!current) {
- if (topUnsortable) {
+ if (topUnsortable || !done) {
topUnsortable = false;
SkASSERT(!firstRetry);
firstRetry = true;
diff --git a/experimental/Intersection/Simplify.cpp b/experimental/Intersection/Simplify.cpp
index 6c6f5cb366..fba7e5f95b 100644
--- a/experimental/Intersection/Simplify.cpp
+++ b/experimental/Intersection/Simplify.cpp
@@ -28,6 +28,7 @@ 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
@@ -513,6 +514,34 @@ static int QuadRayIntersect(const SkPoint a[3], const _Line& bLine,
return intersectRay(aQuad, bLine, intersections);
}
+static bool LineVertical(const SkPoint a[2], double startT, double endT) {
+ MAKE_CONST_LINE(aLine, a);
+ double x[2];
+ xy_at_t(aLine, startT, x[0], *(double*) 0);
+ xy_at_t(aLine, endT, x[1], *(double*) 0);
+ return approximately_equal((float) x[0], (float) x[1]);
+}
+
+static bool QuadVertical(const SkPoint a[3], double startT, double endT) {
+ SkPoint dst[3];
+ QuadSubDivide(a, startT, endT, dst);
+ return approximately_equal(dst[0].fX, dst[1].fX) && approximately_equal(dst[1].fX, dst[2].fX);
+}
+
+static bool CubicVertical(const SkPoint a[4], double startT, double endT) {
+ SkPoint dst[4];
+ CubicSubDivide(a, startT, endT, dst);
+ return approximately_equal(dst[0].fX, dst[1].fX) && approximately_equal(dst[1].fX, dst[2].fX)
+ && approximately_equal(dst[2].fX, dst[3].fX);
+}
+
+static bool (* const SegmentVertical[])(const SkPoint [], double , double) = {
+ NULL,
+ LineVertical,
+ QuadVertical,
+ CubicVertical
+};
+
class Segment;
struct Span {
@@ -731,7 +760,6 @@ public:
LineSubDivideHD(fPts, startT, endT, l);
// OPTIMIZATION: for pure line compares, we never need fTangent1.c
fTangent1.lineEndPoints(l);
- fUnsortable = dx() == 0 && dy() == 0;
fSide = 0;
break;
case SkPath::kQuad_Verb:
@@ -748,6 +776,7 @@ public:
default:
SkASSERT(0);
}
+ fUnsortable = dx() == 0 && dy() == 0;
if (fUnsortable) {
return;
}
@@ -1084,18 +1113,18 @@ public:
if (activeAngleInner(index, done, angles)) {
return true;
}
- double referenceT = fTs[index].fT;
int lesser = index;
- while (--lesser >= 0 && approximately_negative(referenceT - fTs[lesser].fT)) {
+ while (--lesser >= 0 && equalPoints(index, lesser)) {
if (activeAngleOther(lesser, done, angles)) {
return true;
}
}
+ lesser = index;
do {
if (activeAngleOther(index, done, angles)) {
return true;
}
- } while (++index < fTs.count() && approximately_negative(fTs[index].fT - referenceT));
+ } while (++index < fTs.count() && equalPoints(index, lesser));
return false;
}
@@ -1144,7 +1173,7 @@ public:
void activeLeftTop(SkPoint& result) const {
SkASSERT(!done());
int count = fTs.count();
- result.fY = SK_ScalarMax;
+ result.fX = result.fY = SK_ScalarMax;
bool lastDone = true;
bool lastUnsortable = false;
for (int index = 0; index < count; ++index) {
@@ -1166,7 +1195,6 @@ public:
lastDone = span.fDone;
lastUnsortable = span.fUnsortableEnd;
}
- SkASSERT(result.fY < SK_ScalarMax);
}
bool activeOp(int index, int endIndex, int xorMiMask, int xorSuMask, ShapeOp op) {
@@ -1756,6 +1784,13 @@ public:
}
return oIndex;
}
+
+ bool betweenTs(int lesser, double testT, int greater) {
+ if (lesser > greater) {
+ SkTSwap<int>(lesser, greater);
+ }
+ return approximately_between(fTs[lesser].fT, testT, fTs[greater].fT);
+ }
const Bounds& bounds() const {
return fBounds;
@@ -1893,14 +1928,30 @@ public:
return windSum(minIndex);
}
- int crossedSpanX(const SkPoint& basePt, SkScalar& bestX, double& hitT, bool opp) const {
+ int crossedSpanX(const SkPoint& basePt, SkScalar& bestX, double& hitT,
+ bool opp) const {
+ SkScalar right = fBounds.fRight;
int bestT = -1;
- SkScalar left = bounds().fLeft;
- SkScalar right = bounds().fRight;
+ 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 = nextSpan(start, 1);
+ end = nextExactSpan(start, 1);
if ((opp ? fTs[start].fOppValue : fTs[start].fWindValue) == 0) {
continue;
}
@@ -1937,6 +1988,9 @@ public:
}
}
bestX = testX;
+ while (start + 1 < end && fTs[start].fDone) {
+ ++start;
+ }
bestT = foundT < 1 ? start : end;
hitT = testT;
}
@@ -1945,10 +1999,26 @@ public:
return bestT;
}
- int crossedSpanY(const SkPoint& basePt, SkScalar& bestY, double& hitT, bool opp) const {
+ int crossedSpanY(const SkPoint& basePt, SkScalar& bestY, double& hitT,
+ bool opp) const {
+ SkScalar bottom = fBounds.fBottom;
int bestT = -1;
- SkScalar top = bounds().fTop;
- SkScalar bottom = bounds().fBottom;
+ if (bottom <= bestY) {
+ return bestT;
+ }
+ SkScalar top = fBounds.fTop;
+ if (top >= basePt.fY) {
+ return bestT;
+ }
+ if (fBounds.fLeft > basePt.fX) {
+ return bestT;
+ }
+ if (fBounds.fRight < basePt.fX) {
+ return bestT;
+ }
+ if (fBounds.fLeft == fBounds.fRight) {
+ return bestT;
+ }
int end = 0;
do {
int start = end;
@@ -1989,6 +2059,9 @@ public:
}
}
bestY = testY;
+ while (start + 1 < end && fTs[start].fDone) {
+ ++start;
+ }
bestT = foundT < 1 ? start : end;
hitT = testT;
}
@@ -2050,6 +2123,19 @@ public:
return done(SkMin32(angle->start(), angle->end()));
}
+ bool equalPoints(int greaterTIndex, int lesserTIndex) {
+ SkASSERT(greaterTIndex >= lesserTIndex);
+ double greaterT = fTs[greaterTIndex].fT;
+ double lesserT = fTs[lesserTIndex].fT;
+ if (greaterT == lesserT) {
+ return true;
+ }
+ if (!approximately_negative(greaterT - lesserT)) {
+ return false;
+ }
+ return xyAtT(greaterTIndex) == xyAtT(lesserTIndex);
+ }
+
/*
The M and S variable name parts stand for the operators.
Mi stands for Minuend (see wiki subtraction, analogous to difference)
@@ -2441,13 +2527,13 @@ public:
sorted[firstIndex]->sign());
#endif
int sumWinding = updateWinding(endIndex, startIndex);
- int outside = sumWinding & 1; // associate pairs together to avoid figure eights
int nextIndex = firstIndex + 1;
int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
const Angle* foundAngle = NULL;
bool foundDone = false;
// iterate through the angle, and compute everyone's winding
Segment* nextSegment;
+ int activeCount = 0;
do {
SkASSERT(nextIndex != firstIndex);
if (nextIndex == angleCount) {
@@ -2458,9 +2544,16 @@ public:
int maxWinding;
bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(),
maxWinding, sumWinding);
- if (activeAngle && (!foundAngle || foundDone) && outside != (sumWinding & 1)) {
- foundAngle = nextAngle;
- foundDone = nextSegment->done(nextAngle) && !nextSegment->tiny(nextAngle);
+ if (activeAngle) {
+ ++activeCount;
+ if (!foundAngle || (foundDone && activeCount & 1)) {
+ if (nextSegment->tiny(nextAngle)) {
+ unsortable = true;
+ return NULL;
+ }
+ foundAngle = nextAngle;
+ foundDone = nextSegment->done(nextAngle);
+ }
}
if (nextSegment->done()) {
continue;
@@ -2833,14 +2926,32 @@ public:
fVerb = verb;
}
- void initWinding(int start, int end, int winding, int oppWinding) {
+ void initWinding(int start, int end, bool checkInX, int winding, int oppWinding) {
+ int local = spanSign(start, end);
+ if (checkInX && !winding) {
+ winding = -local;
+ } else if ((local * winding >= 0) ^ (checkInX && winding != 0)) {
+ winding += local;
+ }
+ int oppLocal = oppSign(start, end);
+ if ((oppLocal * oppWinding >= 0) ^ (checkInX & oppWinding != 0)) {
+ oppWinding += oppLocal;
+ }
+ (void) markAndChaseWinding(start, end, winding, oppWinding);
+ }
+
+ void initWindingX(int start, int end, double tHit, int winding, int oppWinding) {
+ SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, tHit);
+ SkASSERT(dx);
int local = spanSign(start, end);
- if (local * winding >= 0) {
+ if (!winding) {
+ winding = dx < 0 ? -local : local;
+ } else if (local * winding >= 0) {
winding += local;
}
- local = oppSign(start, end);
- if (local * oppWinding >= 0) {
- oppWinding += local;
+ int oppLocal = oppSign(start, end);
+ if (oppLocal * oppWinding >= 0) {
+ oppWinding += oppLocal;
}
(void) markAndChaseWinding(start, end, winding, oppWinding);
}
@@ -2904,6 +3015,10 @@ public:
bool isVertical() const {
return fBounds.fLeft == fBounds.fRight;
}
+
+ bool isVertical(int start, int end) const {
+ return (*SegmentVertical[fVerb])(fPts, start, end);
+ }
SkScalar leftMost(int start, int end) const {
return (*SegmentLeftMost[fVerb])(fPts, fTs[start].fT, fTs[end].fT);
@@ -2959,6 +3074,21 @@ public:
return last;
}
+ Span* markAndChaseDoneUnary(int index, int endIndex) {
+ int step = SkSign32(endIndex - index);
+ int min = SkMin32(index, endIndex);
+ markDoneUnary(min);
+ Span* last;
+ Segment* other = this;
+ while ((other = other->nextChase(index, step, min, last))) {
+ if (other->done()) {
+ return NULL;
+ }
+ other->markDoneUnary(min);
+ }
+ return last;
+ }
+
Span* markAndChaseDoneUnary(const Angle* angle, int winding) {
int index = angle->start();
int endIndex = angle->end();
@@ -3287,6 +3417,26 @@ public:
}
}
+ bool moreHorizontal(int index, int endIndex, bool& unsortable) const {
+ // find bounds
+ Bounds bounds;
+ bounds.setPoint(xyAtT(index));
+ bounds.add(xyAtT(endIndex));
+ SkScalar width = bounds.width();
+ SkScalar height = bounds.height();
+ if (width > height) {
+ if (approximately_negative(width)) {
+ unsortable = true; // edge is too small to resolve meaningfully
+ }
+ return false;
+ } else {
+ if (approximately_negative(height)) {
+ unsortable = true; // edge is too small to resolve meaningfully
+ }
+ return true;
+ }
+ }
+
// return span if when chasing, two or more radiating spans are not done
// OPTIMIZATION: ? multiple spans is detected when there is only one valid
// candidate and the remaining spans have windValue == 0 (canceled by
@@ -3296,6 +3446,17 @@ public:
return end > 0 && end < fTs.count() - 1;
}
+ bool nextCandidate(int& start, int& end) const {
+ do {
+ start = end;
+ if (fTs[start].fT == 1) {
+ return false;
+ }
+ end = nextExactSpan(start, 1);
+ } while (fTs[start].fDone);
+ return true;
+ }
+
Segment* nextChase(int& index, const int step, int& min, Span*& last) const {
int end = nextExactSpan(index, step);
SkASSERT(end >= 0);
@@ -3568,8 +3729,19 @@ public:
SkPath::Verb verb() const {
return fVerb;
}
+
+ int windingAtTX(double tHit, int tIndex, bool crossOpp) const {
+ if (approximately_zero(tHit - t(tIndex))) { // if we hit the end of a span, disregard
+ return SK_MinS32;
+ }
+ int endIndex = nextSpan(tIndex, 1);
+ if (crossOpp) {
+ return updateOppWinding(tIndex, endIndex);
+ }
+ return updateWinding(tIndex, endIndex);
+ }
- int windingAtT(double tHit, int tIndex, bool crossOpp) const {
+ int windingAtT(double tHit, int tIndex, bool crossOpp, bool& zeroDx) const {
if (approximately_zero(tHit - t(tIndex))) { // if we hit the end of a span, disregard
return SK_MinS32;
}
@@ -3588,7 +3760,10 @@ public:
#if DEBUG_WINDING
SkDebugf("%s dx=%1.9g\n", __FUNCTION__, dx);
#endif
- SkASSERT(dx != 0);
+ if (dx == 0) {
+ zeroDx = true;
+ return SK_MinS32;
+ }
if (winding * dx > 0) { // if same signs, result is negative
winding += dx > 0 ? -windVal : windVal;
#if DEBUG_WINDING
@@ -3641,6 +3816,12 @@ public:
return span->fPt;
}
+ // used only by right angle winding finding
+ void xyAtT(int start, int end, double mid, SkPoint& pt) const {
+ double t = fTs[start].fT * (1 - mid) + fTs[end].fT * mid;
+ (*SegmentXYAtT[fVerb])(fPts, t, &pt);
+ }
+
SkScalar yAtT(int index) const {
return yAtT(&fTs[index]);
}
@@ -4127,61 +4308,12 @@ public:
fContainsIntercepts = true;
}
- const Segment* crossedSegmentX(const SkPoint& basePt, SkScalar& bestX,
- int& tIndex, double& hitT, bool opp) {
- int segmentCount = fSegments.count();
- const Segment* bestSegment = NULL;
- for (int test = 0; test < segmentCount; ++test) {
- Segment* testSegment = &fSegments[test];
- const SkRect& bounds = testSegment->bounds();
- if (bounds.fRight <= bestX) {
- continue;
- }
- if (bounds.fLeft >= basePt.fX) {
- continue;
- }
- if (bounds.fTop > basePt.fY) {
- continue;
- }
- if (bounds.fBottom < basePt.fY) {
- continue;
- }
- if (bounds.fTop == bounds.fBottom) {
- continue;
- }
- double testHitT;
- int testT = testSegment->crossedSpanX(basePt, bestX, testHitT, opp);
- if (testT >= 0) {
- bestSegment = testSegment;
- tIndex = testT;
- hitT = testHitT;
- }
- }
- return bestSegment;
- }
-
const Segment* crossedSegmentY(const SkPoint& basePt, SkScalar& bestY,
int &tIndex, double& hitT, bool opp) {
int segmentCount = fSegments.count();
const Segment* bestSegment = NULL;
for (int test = 0; test < segmentCount; ++test) {
Segment* testSegment = &fSegments[test];
- const SkRect& bounds = testSegment->bounds();
- if (bounds.fBottom <= bestY) {
- continue;
- }
- if (bounds.fTop >= basePt.fY) {
- continue;
- }
- if (bounds.fLeft > basePt.fX) {
- continue;
- }
- if (bounds.fRight < basePt.fX) {
- continue;
- }
- if (bounds.fLeft == bounds.fRight) {
- continue;
- }
double testHitT;
int testT = testSegment->crossedSpanY(basePt, bestY, testHitT, opp);
if (testT >= 0) {
@@ -4202,6 +4334,10 @@ public:
return false;
}
+ bool done() const {
+ return fDone;
+ }
+
const SkPoint& end() const {
const Segment& segment = fSegments.back();
return segment.pts()[segment.verb()];
@@ -4221,6 +4357,24 @@ public:
}
}
+ Segment* nonVerticalSegment(int& start, int& end) {
+ int segmentCount = fSortedSegments.count();
+ SkASSERT(segmentCount > 0);
+ for (int sortedIndex = fFirstSorted; sortedIndex < segmentCount; ++sortedIndex) {
+ Segment* testSegment = fSortedSegments[sortedIndex];
+ if (testSegment->done()) {
+ continue;
+ }
+ start = end = 0;
+ while (testSegment->nextCandidate(start, end)) {
+ if (!testSegment->isVertical(start, end)) {
+ return testSegment;
+ }
+ }
+ }
+ return NULL;
+ }
+
bool operand() const {
return fOperand;
}
@@ -4228,7 +4382,7 @@ public:
void reset() {
fSegments.reset();
fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
- fContainsCurves = fContainsIntercepts = false;
+ fContainsCurves = fContainsIntercepts = fDone = false;
}
void resolveCoincidence(SkTDArray<Contour*>& contourList) {
@@ -4300,7 +4454,7 @@ public:
}
}
- const SkTArray<Segment>& segments() {
+ SkTArray<Segment>& segments() {
return fSegments;
}
@@ -4400,11 +4554,11 @@ public:
}
#endif
- Segment* topSortableSegment(const SkPoint& topLeft, SkPoint& bestXY) {
+ void topSortableSegment(const SkPoint& topLeft, SkPoint& bestXY, Segment*& topStart) {
int segmentCount = fSortedSegments.count();
SkASSERT(segmentCount > 0);
- Segment* bestSegment = NULL;
int sortedIndex = fFirstSorted;
+ fDone = true; // may be cleared below
for ( ; sortedIndex < segmentCount; ++sortedIndex) {
Segment* testSegment = fSortedSegments[sortedIndex];
if (testSegment->done()) {
@@ -4413,24 +4567,26 @@ public:
}
continue;
}
+ fDone = false;
SkPoint testXY;
testSegment->activeLeftTop(testXY);
- if (testXY.fY < topLeft.fY) {
- continue;
- }
- if (testXY.fY == topLeft.fY && testXY.fX <= topLeft.fX) {
- continue;
- }
- if (bestXY.fY < testXY.fY) {
- continue;
- }
- if (bestXY.fY == testXY.fY && bestXY.fX < testXY.fX) {
- continue;
+ if (topStart) {
+ if (testXY.fY < topLeft.fY) {
+ continue;
+ }
+ if (testXY.fY == topLeft.fY && testXY.fX < topLeft.fX) {
+ continue;
+ }
+ if (bestXY.fY < testXY.fY) {
+ continue;
+ }
+ if (bestXY.fY == testXY.fY && bestXY.fX < testXY.fX) {
+ continue;
+ }
}
- bestSegment = testSegment;
+ topStart = testSegment;
bestXY = testXY;
}
- return bestSegment;
}
Segment* undoneSegment(int& start, int& end) {
@@ -4546,6 +4702,7 @@ private:
Bounds fBounds;
bool fContainsIntercepts;
bool fContainsCurves;
+ bool fDone;
bool fOperand; // true for the second argument to a binary operator
bool fXor;
bool fOppXor;
@@ -5207,15 +5364,16 @@ static void coincidenceCheck(SkTDArray<Contour*>& contourList, int total) {
}
}
-static int contourRangeCheckX(SkTDArray<Contour*>& contourList, double mid,
- const Segment* current, int index, int endIndex, bool opp) {
- const SkPoint& basePt = current->xyAtT(endIndex);
+#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;
- const Segment* test = NULL;
- int tIndex;
- double tHit;
- bool crossOpp;
+ 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;
@@ -5225,27 +5383,60 @@ static int contourRangeCheckX(SkTDArray<Contour*>& contourList, double mid,
if (bestX > contour->bounds().fRight) {
continue;
}
- const Segment* next = contour->crossedSegmentX(basePt, bestX, tIndex, tHit, testOpp);
- if (next) {
- test = next;
- crossOpp = testOpp;
+ 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 (!test) {
+ if (!bestSeg) {
return 0;
}
- return test->windingAtT(tHit, tIndex, crossOpp);
+ 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, double mid,
- const Segment* current, int index, int endIndex, bool opp) {
- const SkPoint& basePt = current->xyAtT(endIndex);
+static int contourRangeCheckY(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 bestY = SK_ScalarMin;
- const Segment* test = NULL;
- int tIndex;
- double tHit;
- bool crossOpp;
+ 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;
@@ -5255,16 +5446,44 @@ static int contourRangeCheckY(SkTDArray<Contour*>& contourList, double mid,
if (bestY > contour->bounds().fBottom) {
continue;
}
- const Segment* next = contour->crossedSegmentY(basePt, bestY, tIndex, tHit, testOpp);
- if (next) {
- test = next;
- crossOpp = testOpp;
+ int segmentCount = contour->segments().count();
+ for (int test = 0; test < segmentCount; ++test) {
+ Segment* testSeg = &contour->segments()[test];
+ SkScalar testY = bestY;
+ double testHit;
+ int testTIndex = testSeg->crossedSpanY(basePt, testY, testHit, testOpp);
+ if (testTIndex < 0) {
+ continue;
+ }
+ if (testSeg == current && current->betweenTs(index, testHit, endIndex)) {
+ continue;
+ }
+ bestSeg = testSeg;
+ bestHit = testHit;
+ bestOpp = testOpp;
+ bestTIndex = testTIndex;
+ bestY = testY;
}
}
- if (!test) {
+ if (!bestSeg) {
+ return 0;
+ }
+ if (bestSeg->windSum(bestTIndex) == SK_MinS32) {
+ current = bestSeg;
+ index = bestTIndex;
+ endIndex = bestSeg->nextSpan(bestTIndex, 1);
+ tryAgain = true;
return 0;
}
- return test->windingAtT(tHit, tIndex, crossOpp);
+ bool zeroDx = false;
+ int tryAnother = bestSeg->windingAtTX(bestHit, bestTIndex, bestOpp);
+ int result = bestSeg->windingAtT(bestHit, bestTIndex, bestOpp, zeroDx);
+ if (result != tryAnother) {
+ SkDebugf("%s result=%d tryAnother=%d\n", __FUNCTION__, result,
+ tryAnother);
+ }
+ SkASSERT(!zeroDx);
+ return result;
}
// project a ray from the top of the contour up and see if it hits anything
@@ -5445,7 +5664,7 @@ static Segment* findUndone(SkTDArray<Contour*>& contourList, int& start, int& en
return NULL;
}
-
+#define OLD_FIND_CHASE 1
static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex) {
while (chase.count()) {
@@ -5472,6 +5691,7 @@ static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex) {
}
SkTDArray<Angle*> sorted;
bool sortable = Segment::SortAngles(angles, sorted);
+ int angleCount = sorted.count();
#if DEBUG_SORT
sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0);
#endif
@@ -5481,6 +5701,7 @@ static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex) {
// find first angle, initialize winding to computed fWindSum
int firstIndex = -1;
const Angle* angle;
+#if OLD_FIND_CHASE
int winding;
do {
angle = sorted[++firstIndex];
@@ -5505,10 +5726,22 @@ static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex) {
// 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];
winding -= angle->segment()->spanSign(angle);
+#else
+ do {
+ angle = sorted[++firstIndex];
+ segment = angle->segment();
+ } while (segment->windSum(angle) == SK_MinS32);
+ #if DEBUG_SORT
+ segment->debugShowSort(__FUNCTION__, sorted, firstIndex);
+ #endif
+ int sumWinding = segment->updateWindingReverse(angle);
+ int nextIndex = firstIndex + 1;
+ int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
+ Segment* first = NULL;
+#endif
do {
SkASSERT(nextIndex != firstIndex);
if (nextIndex == angleCount) {
@@ -5516,6 +5749,7 @@ static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex) {
}
angle = sorted[nextIndex];
segment = angle->segment();
+#if OLD_FIND_CHASE
int maxWinding = winding;
winding -= segment->spanSign(angle);
#if DEBUG_SORT
@@ -5528,16 +5762,30 @@ static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex) {
const Span& nextSpan = segment->span(lesser);
if (!nextSpan.fDone) {
#if 1
- // FIXME: this be wrong. assign startWinding if edge is in
+ // FIXME: this be wrong? assign startWinding if edge is in
// same direction. If the direction is opposite, winding to
// assign is flipped sign or +/- 1?
if (useInnerWinding(maxWinding, winding)) {
maxWinding = winding;
}
- segment->markWinding(lesser, maxWinding);
+ segment->markAndChaseWinding(angle, maxWinding, 0);
#endif
break;
}
+#else
+ int start = angle->start();
+ int end = angle->end();
+ int maxWinding;
+ segment->setUpWinding(start, end, maxWinding, sumWinding);
+ if (!segment->done(angle)) {
+ if (!first) {
+ first = segment;
+ tIndex = start;
+ endIndex = end;
+ }
+ (void) segment->markAngle(maxWinding, sumWinding, true, angle);
+ }
+#endif
} while (++nextIndex != lastIndex);
#if TRY_ROTATE
*chase.insert(0) = span;
@@ -5568,24 +5816,30 @@ static bool windingIsActive(int winding, int spanWinding) {
}
static Segment* findSortableTop(SkTDArray<Contour*>& contourList, int& index,
- int& endIndex, SkPoint& topLeft, bool& unsortable, bool onlySortable) {
+ int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool onlySortable) {
Segment* result;
do {
SkPoint bestXY = {SK_ScalarMax, SK_ScalarMax};
int contourCount = contourList.count();
Segment* topStart = NULL;
+ done = true;
for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
Contour* contour = contourList[cIndex];
+ if (contour->done()) {
+ continue;
+ }
const Bounds& bounds = contour->bounds();
if (bounds.fBottom < topLeft.fY) {
+ done = false;
continue;
}
if (bounds.fBottom == topLeft.fY && bounds.fRight < topLeft.fX) {
+ done = false;
continue;
}
- Segment* test = contour->topSortableSegment(topLeft, bestXY);
- if (test) {
- topStart = test;
+ contour->topSortableSegment(topLeft, bestXY, topStart);
+ if (!contour->done()) {
+ done = false;
}
}
if (!topStart) {
@@ -5616,16 +5870,23 @@ static int updateWindings(const Segment* current, int index, int endIndex, int&
return winding;
}
-typedef int (*RangeChecker)(SkTDArray<Contour*>& contourList, double mid,
- const Segment* current, int index, int endIndex, bool opp);
+typedef int (*RangeChecker)(SkTDArray<Contour*>& contourList, Segment*& current,
+ int& index, int& endIndex, double& tHit, bool& tryAgain, double mid, bool opp);
-static int rightAngleWinding(RangeChecker rangeChecker, SkTDArray<Contour*>& contourList,
- Segment* current, int index, int endIndex, bool opp) {
+static int rightAngleWinding(SkTDArray<Contour*>& contourList,
+ Segment*& current, int& index, int& endIndex, double& tHit, bool& checkInX, 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 = (*rangeChecker)(contourList, test, current, index, endIndex, opp);
- if (contourWinding != SK_MinS32) {
+ contourWinding = (*checker)(contourList, current, index, endIndex, tHit, tryAgain, test,
+ opp);
+ if (contourWinding != SK_MinS32 || tryAgain) {
return contourWinding;
}
test /= 2;
@@ -5634,33 +5895,36 @@ static int rightAngleWinding(RangeChecker rangeChecker, SkTDArray<Contour*>& con
return contourWinding;
}
+static void skipVertical(SkTDArray<Contour*>& contourList,
+ Segment*& current, int& index, int& endIndex) {
+ if (!current->isVertical(index, endIndex)) {
+ return;
+ }
+ int contourCount = contourList.count();
+ for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
+ Contour* contour = contourList[cIndex];
+ if (contour->done()) {
+ continue;
+ }
+ current = contour->nonVerticalSegment(index, endIndex);
+ if (current) {
+ return;
+ }
+ }
+}
+
static Segment* tryRightAngleRay(SkTDArray<Contour*>& contourList, int& index,
- int& endIndex, SkPoint& topLeft, bool& unsortable, RangeChecker& rangeChecker) {
+ 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 {
- current = findSortableTop(contourList, index, endIndex, topLeft, unsortable, false);
+ bool done;
+ current = findSortableTop(contourList, index, endIndex, topLeft, unsortable, done, false);
SkASSERT(current); // FIXME: return to caller that path cannot be simplified (yet)
- // find bounds
- Bounds bounds;
- bounds.setPoint(current->xyAtT(index));
- bounds.add(current->xyAtT(endIndex));
- SkScalar width = bounds.width();
- SkScalar height = bounds.height();
- if (width > height) {
- if (approximately_negative(width)) {
- continue; // edge is too small to resolve meaningfully
- }
- rangeChecker = contourRangeCheckY;
- } else {
- if (approximately_negative(height)) {
- continue; // edge is too small to resolve meaningfully
- }
- rangeChecker = contourRangeCheckX;
- }
- } while (!current);
+ checkInX = current->moreHorizontal(index, endIndex, unsortable);
+ } while (unsortable);
return current;
}
@@ -5668,7 +5932,8 @@ static Segment* findSortableTopOld(SkTDArray<Contour*>& contourList, bool& first
int& endIndex, SkPoint& topLeft, int& contourWinding, bool& unsortable) {
Segment* current;
do {
- current = findSortableTop(contourList, index, endIndex, topLeft, unsortable, true);
+ bool done;
+ current = findSortableTop(contourList, index, endIndex, topLeft, unsortable, done, true);
if (!current) {
break;
}
@@ -5704,9 +5969,14 @@ static Segment* findSortableTopOld(SkTDArray<Contour*>& contourList, bool& first
#endif
return current;
}
- RangeChecker rangeChecker = NULL;
- current = tryRightAngleRay(contourList, index, endIndex, topLeft, unsortable, rangeChecker);
- contourWinding = rightAngleWinding(rangeChecker, contourList, current, index, endIndex, false);
+ 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;
}
@@ -5811,53 +6081,72 @@ static bool bridgeWinding(SkTDArray<Contour*>& contourList, PathWrapper& simple)
}
static Segment* findSortableTopNew(SkTDArray<Contour*>& contourList, bool& firstContour, int& index,
- int& endIndex, SkPoint& topLeft, bool& unsortable) {
- Segment* current;
- bool first = true;
- int contourWinding, oppContourWinding;
- do {
- current = findSortableTop(contourList, index, endIndex, topLeft, unsortable, true);
- if (!current) {
- if (first) {
- return NULL;
- }
- break;
+ int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool binary) {
+ Segment* current = findSortableTop(contourList, index, endIndex, topLeft, unsortable, done,
+ true);
+ if (!current) {
+ return NULL;
+ }
+ if (firstContour) {
+ current->initWinding(index, endIndex, false, 0, 0);
+ firstContour = false;
+ return current;
+ }
+ int minIndex = SkMin32(index, endIndex);
+ int sumWinding = current->windSum(minIndex);
+ if (sumWinding != SK_MinS32) {
+ return current;
+ }
+ sumWinding = current->computeSum(index, endIndex, binary);
+ if (sumWinding != SK_MinS32) {
+ return current;
+ }
+ int contourWinding;
+ int oppContourWinding = 0;
+#if 1
+ contourWinding = innerContourCheck(contourList, current, index, endIndex, false);
+ if (contourWinding != SK_MinS32) {
+ if (binary) {
+ oppContourWinding = innerContourCheck(contourList, current, index, endIndex, true);
}
- first = false;
- if (firstContour) {
- current->initWinding(index, endIndex, 0, 0);
- firstContour = false;
+ if (!binary || oppContourWinding != SK_MinS32) {
+ current->initWinding(index, endIndex, false, contourWinding, oppContourWinding);
return current;
}
- int minIndex = SkMin32(index, endIndex);
- int sumWinding = current->windSum(minIndex);
- if (sumWinding == SK_MinS32) {
- sumWinding = current->computeSum(index, endIndex, true);
- if (sumWinding != SK_MinS32) {
- return current;
- }
- }
- contourWinding = innerContourCheck(contourList, current, index, endIndex, false);
- if (contourWinding == SK_MinS32) {
+ }
+#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;
+ 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,
+ tryAgain, false);
+ if (tryAgain) {
continue;
}
- oppContourWinding = innerContourCheck(contourList, current, index, endIndex, true);
- if (oppContourWinding != SK_MinS32) {
+ if (!binary) {
break;
}
- current->initWinding(index, endIndex, contourWinding, oppContourWinding);
- return current;
- } while (true);
- if (!current) {
- // 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
- int (*checker)(SkTDArray<Contour*>& contourList, double mid,
- const Segment* current, int index, int endIndex, bool opp);
- current = tryRightAngleRay(contourList, index, endIndex, topLeft, unsortable, checker);
- contourWinding = rightAngleWinding(checker, contourList, current, index, endIndex, false);
- oppContourWinding = rightAngleWinding(checker, contourList, current, index, endIndex, true);
- }
- current->initWinding(index, endIndex, contourWinding, oppContourWinding);
+ oppContourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, checkInX,
+ tryAgain, true);
+ } while (tryAgain);
+#if CHECK_IN_X
+ current->initWinding(index, endIndex, checkInX, contourWinding, oppContourWinding);
+#else
+ current->initWindingX(index, endIndex, tHit, contourWinding, oppContourWinding);
+#endif
return current;
}
@@ -5866,17 +6155,16 @@ static bool bridgeWindingX(SkTDArray<Contour*>& contourList, PathWrapper& simple
bool firstContour = true;
bool unsortable = false;
bool topUnsortable = false;
- bool firstRetry = false;
SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
do {
int index, endIndex;
+ bool topDone;
Segment* current = findSortableTopNew(contourList, firstContour, index, endIndex, topLeft,
- topUnsortable);
+ topUnsortable, topDone, false);
if (!current) {
- if (topUnsortable) {
+ if (topUnsortable || !topDone) {
topUnsortable = false;
- SkASSERT(!firstRetry);
- firstRetry = true;
+ SkASSERT(topLeft.fX != SK_ScalarMin && topLeft.fY != SK_ScalarMin);
topLeft.fX = topLeft.fY = SK_ScalarMin;
continue;
}
@@ -5920,7 +6208,7 @@ static bool bridgeWindingX(SkTDArray<Contour*>& contourList, PathWrapper& simple
}
simple.close();
} else {
- Span* last = current->markAndChaseDoneBinary(index, endIndex);
+ Span* last = current->markAndChaseDoneUnary(index, endIndex);
if (last) {
*chaseArray.append() = last;
}
diff --git a/experimental/Intersection/SimplifyFindTop_Test.cpp b/experimental/Intersection/SimplifyFindTop_Test.cpp
index d29325cebd..5f267503a9 100644
--- a/experimental/Intersection/SimplifyFindTop_Test.cpp
+++ b/experimental/Intersection/SimplifyFindTop_Test.cpp
@@ -33,9 +33,9 @@ static const SimplifyFindTopTest::Segment* testCommon(
end);
#else
SkPoint bestXY = {SK_ScalarMin, SK_ScalarMin};
- bool unsortable = false;
+ bool done, unsortable = false;
const SimplifyFindTopTest::Segment* topSegment =
- findSortableTop(contourList, index, end, bestXY, unsortable, true);
+ findSortableTop(contourList, index, end, bestXY, unsortable, done, true);
#endif
return topSegment;
}
diff --git a/experimental/Intersection/SimplifyNew_Test.cpp b/experimental/Intersection/SimplifyNew_Test.cpp
index 7a1fc12a67..ecdf489614 100644
--- a/experimental/Intersection/SimplifyNew_Test.cpp
+++ b/experimental/Intersection/SimplifyNew_Test.cpp
@@ -3078,13 +3078,221 @@ static void testQuadratic75() {
testSimplifyx(path);
}
-static void (*firstTest)() = testQuadratic63;
+static void testQuadratic76() {
+ SkPath path, pathB;
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 0, 0);
+ path.lineTo(2, 3);
+ path.close();
+ path.moveTo(1, 0);
+ path.lineTo(1, 2);
+ path.quadTo(1, 2, 2, 2);
+ path.close();
+ testSimplifyx(path);
+}
+
+static void testQuadratic77() {
+ SkPath path, pathB;
+ path.moveTo(0, 0);
+ path.quadTo(1, 0, 1, 1);
+ path.lineTo(3, 1);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(1, 0);
+ path.quadTo(0, 1, 3, 2);
+ path.close();
+ testSimplifyx(path);
+}
+
+static void testQuadratic78() {
+ SkPath path, pathB;
+ path.moveTo(0, 0);
+ path.quadTo(1, 0, 1, 2);
+ path.lineTo(3, 2);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(2, 1, 0, 2);
+ path.close();
+ testSimplifyx(path);
+}
+
+static void testQuadratic79() {
+ SkPath path, pathB;
+ path.moveTo(0, 0);
+ path.quadTo(1, 0, 1, 2);
+ path.lineTo(3, 2);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(1, 0);
+ path.quadTo(0, 1, 3, 2);
+ path.close();
+ testSimplifyx(path);
+}
+
+static void testEight1() {
+ SkPath path, pathB;
+ path.moveTo(0, 0);
+ path.lineTo(2, 2);
+ path.lineTo(0, 2);
+ path.lineTo(2, 0);
+ path.close();
+ testSimplifyx(path);
+}
+
+static void testEight2() {
+ SkPath path, pathB;
+ path.moveTo(0, 0);
+ path.lineTo(2, 0);
+ path.lineTo(0, 2);
+ path.lineTo(2, 2);
+ path.close();
+ testSimplifyx(path);
+}
+
+static void testEight3() {
+ SkPath path, pathB;
+ path.moveTo(0, 0);
+ path.lineTo(0, 2);
+ path.lineTo(2, 0);
+ path.lineTo(2, 2);
+ path.close();
+ testSimplifyx(path);
+}
+
+static void testEight4() {
+ SkPath path, pathB;
+ path.moveTo(0, 0);
+ path.lineTo(2, 2);
+ path.lineTo(2, 0);
+ path.lineTo(0, 2);
+ path.close();
+ testSimplifyx(path);
+}
+
+static void testEight5() {
+ SkPath path, pathB;
+ path.moveTo(1, 0);
+ path.lineTo(1, 2);
+ path.lineTo(0, 2);
+ path.lineTo(2, 0);
+ path.close();
+ testSimplifyx(path);
+}
+
+static void testEight6() {
+ SkPath path, pathB;
+ path.moveTo(1, 0);
+ path.lineTo(2, 0);
+ path.lineTo(0, 2);
+ path.lineTo(1, 2);
+ path.close();
+ testSimplifyx(path);
+}
+
+static void testEight7() {
+ SkPath path, pathB;
+ path.moveTo(0, 0);
+ path.lineTo(0, 1);
+ path.lineTo(2, 1);
+ path.lineTo(2, 2);
+ path.close();
+ testSimplifyx(path);
+}
+
+static void testEight8() {
+ SkPath path, pathB;
+ path.moveTo(0, 0);
+ path.lineTo(2, 2);
+ path.lineTo(2, 1);
+ path.lineTo(0, 1);
+ path.close();
+ testSimplifyx(path);
+}
+
+static void testEight9() {
+ SkPath path, pathB;
+ path.moveTo(1, 0);
+ path.lineTo(1, 2);
+ path.lineTo(2, 1);
+ path.lineTo(0, 1);
+ path.close();
+ testSimplifyx(path);
+}
+
+static void testEight10() {
+ SkPath path, pathB;
+ path.moveTo(1, 0);
+ path.lineTo(0, 1);
+ path.lineTo(2, 1);
+ path.lineTo(1, 2);
+ path.close();
+ testSimplifyx(path);
+}
+
+static void testQuadratic80() {
+ SkPath path, pathB;
+ path.moveTo(0, 0);
+ path.quadTo(1, 0, 2, 3);
+ path.lineTo(2, 3);
+ path.close();
+ path.moveTo(1, 0);
+ path.lineTo(3, 0);
+ path.quadTo(0, 1, 1, 1);
+ path.close();
+ testSimplifyx(path);
+}
+
+static void testQuadratic81() {
+ SkPath path, pathB;
+ path.moveTo(0, 0);
+ path.quadTo(2, 0, 1, 1);
+ path.lineTo(1, 1);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(2, 1, 0, 2);
+ path.close();
+ testSimplifyx(path);
+}
+
+static void testQuadratic82() {
+ SkPath path, pathB;
+ path.moveTo(0, 0);
+ path.quadTo(2, 0, 1, 1);
+ path.lineTo(0, 3);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(2, 1, 0, 2);
+ path.close();
+ testSimplifyx(path);
+}
+
+static void (*firstTest)() = testQuadratic82;
static struct {
void (*fun)();
const char* str;
} tests[] = {
-// TEST(testQuadratic75),
+ TEST(testQuadratic82),
+ TEST(testQuadratic81),
+ TEST(testQuadratic80),
+ TEST(testEight1),
+ TEST(testEight2),
+ TEST(testEight3),
+ TEST(testEight4),
+ TEST(testEight5),
+ TEST(testEight6),
+ TEST(testEight7),
+ TEST(testEight8),
+ TEST(testEight9),
+ TEST(testEight10),
+ TEST(testQuadratic79),
+ TEST(testQuadratic78),
+ TEST(testQuadratic77),
+ TEST(testQuadratic76),
+ TEST(testQuadratic75),
TEST(testQuadratic74),
TEST(testQuadratic73),
TEST(testQuadratic72),
diff --git a/experimental/Intersection/op.htm b/experimental/Intersection/op.htm
index e251a8e7f2..ce8f14155c 100644
--- a/experimental/Intersection/op.htm
+++ b/experimental/Intersection/op.htm
@@ -2794,6 +2794,16 @@ path.quadTo(344.825195,175.778046, 345.858368,175.888794);
path.close();
</div>
+<div id="testQuadratic59">
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 0, 0);
+ path.lineTo(2, 2);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(2, 0);
+ path.quadTo(3, 1, 1, 2);
+</div>
+
<div id="testQuadratic59o">
path.moveTo(369.863983, 145.645813);
path.quadTo(382.380371, 121.254936, 406.236359, 121.254936);
@@ -3003,11 +3013,95 @@ path.close();
path.close();
</div>
+<div id="testQuadratic76">
+ path.moveTo(0, 0);
+ path.quadTo(0, 0, 0, 0);
+ path.lineTo(2, 3);
+ path.close();
+ path.moveTo(1, 0);
+ path.lineTo(1, 2);
+ path.quadTo(1, 2, 2, 2);
+ path.close();
+</div>
+
+<div id="testQuadratic77">
+ path.moveTo(0, 0);
+ path.quadTo(1, 0, 1, 1);
+ path.lineTo(3, 1);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(1, 0);
+ path.quadTo(0, 1, 3, 2);
+ path.close();
+</div>
+
+<div id="testQuadratic78">
+ path.moveTo(0, 0);
+ path.quadTo(1, 0, 1, 2);
+ path.lineTo(3, 2);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(2, 1, 0, 2);
+ path.close();
+</div>
+
+<div id="testQuadratic79">
+ path.moveTo(0, 0);
+ path.quadTo(1, 0, 1, 2);
+ path.lineTo(3, 2);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(1, 0);
+ path.quadTo(0, 1, 3, 2);
+ path.close();
+</div>
+
+<div id="testQuadratic80">
+ path.moveTo(0, 0);
+ path.quadTo(1, 0, 2, 3);
+ path.lineTo(2, 3);
+ path.close();
+ path.moveTo(1, 0);
+ path.lineTo(3, 0);
+ path.quadTo(0, 1, 1, 1);
+ path.close();
+</div>
+
+<div id="testQuadratic81">
+ path.moveTo(0, 0);
+ path.quadTo(2, 0, 1, 1);
+ path.lineTo(1, 1);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(2, 1, 0, 2);
+ path.close();
+</div>
+
+<div id="testQuadratic82">
+ path.moveTo(0, 0);
+ path.quadTo(2, 0, 1, 1);
+ path.lineTo(0, 3);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(2, 1, 0, 2);
+ path.close();
+</div>
+
</div>
<script type="text/javascript">
var testDivs = [
+ testQuadratic82,
+ testQuadratic81,
+ testQuadratic80,
+ testQuadratic79,
+ testQuadratic78,
+ testQuadratic77,
+ testQuadratic76,
testQuadratic75,
testQuadratic74,
testQuadratic73,
@@ -3026,6 +3120,7 @@ var testDivs = [
testLine81,
testQuadratic61,
testQuadratic60,
+ testQuadratic59,
testQuadratic59o,
testQuadratic59s,
testQuadratic58o,