aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gyp/core.gypi1
-rw-r--r--src/pathops/SkDConicLineIntersection.cpp70
-rw-r--r--src/pathops/SkDLineIntersection.cpp8
-rw-r--r--src/pathops/SkDQuadLineIntersection.cpp51
-rw-r--r--src/pathops/SkIntersections.cpp65
-rw-r--r--src/pathops/SkIntersections.h20
-rw-r--r--src/pathops/SkOpAngle.cpp102
-rw-r--r--src/pathops/SkOpAngle.h7
-rw-r--r--src/pathops/SkOpCoincidence.h1
-rw-r--r--src/pathops/SkOpContour.cpp57
-rw-r--r--src/pathops/SkOpContour.h60
-rw-r--r--src/pathops/SkOpSegment.cpp540
-rw-r--r--src/pathops/SkOpSegment.h48
-rwxr-xr-xsrc/pathops/SkOpSpan.cpp75
-rw-r--r--src/pathops/SkOpSpan.h13
-rw-r--r--src/pathops/SkPathOpsBounds.h13
-rw-r--r--src/pathops/SkPathOpsCommon.cpp414
-rw-r--r--src/pathops/SkPathOpsCommon.h17
-rw-r--r--src/pathops/SkPathOpsCubic.cpp141
-rw-r--r--src/pathops/SkPathOpsCubic.h12
-rw-r--r--src/pathops/SkPathOpsCurve.cpp107
-rw-r--r--src/pathops/SkPathOpsCurve.h62
-rw-r--r--src/pathops/SkPathOpsDebug.cpp101
-rw-r--r--src/pathops/SkPathOpsDebug.h34
-rw-r--r--src/pathops/SkPathOpsLine.h3
-rw-r--r--src/pathops/SkPathOpsOp.cpp78
-rw-r--r--src/pathops/SkPathOpsPoint.cpp5
-rw-r--r--src/pathops/SkPathOpsPoint.h4
-rw-r--r--src/pathops/SkPathOpsQuad.cpp63
-rw-r--r--src/pathops/SkPathOpsQuad.h5
-rw-r--r--src/pathops/SkPathOpsSimplify.cpp70
-rw-r--r--src/pathops/SkPathOpsTightBounds.cpp16
-rw-r--r--src/pathops/SkPathOpsTypes.h19
-rw-r--r--src/pathops/SkPathOpsWinding.cpp402
-rwxr-xr-xtests/PathOpsAngleIdeas.cpp4
-rw-r--r--tests/PathOpsAngleTest.cpp8
-rw-r--r--tests/PathOpsBattles.cpp4
-rw-r--r--tests/PathOpsBoundsTest.cpp43
-rw-r--r--tests/PathOpsCubicReduceOrderTest.cpp6
-rw-r--r--tests/PathOpsDCubicTest.cpp21
-rw-r--r--tests/PathOpsDVectorTest.cpp2
-rwxr-xr-xtests/PathOpsDebug.cpp174
-rw-r--r--tests/PathOpsExtendedTest.cpp27
-rw-r--r--tests/PathOpsExtendedTest.h2
-rwxr-xr-xtests/PathOpsFuzz763Test.cpp12
-rw-r--r--tests/PathOpsIssue3651.cpp6
-rw-r--r--tests/PathOpsOpTest.cpp336
-rw-r--r--tests/PathOpsQuadIntersectionTest.cpp69
-rw-r--r--tests/PathOpsSimplifyTest.cpp28
-rwxr-xr-xtests/PathOpsSkpTest.cpp4
-rw-r--r--tools/pathops_sorter.htm6
-rw-r--r--tools/pathops_visualizer.htm673
52 files changed, 1648 insertions, 2461 deletions
diff --git a/gyp/core.gypi b/gyp/core.gypi
index fef6fe45b3..b6a929fc9d 100644
--- a/gyp/core.gypi
+++ b/gyp/core.gypi
@@ -365,6 +365,7 @@
'<(skia_src_path)/pathops/SkPathOpsTSect.cpp',
'<(skia_src_path)/pathops/SkPathOpsTightBounds.cpp',
'<(skia_src_path)/pathops/SkPathOpsTypes.cpp',
+ '<(skia_src_path)/pathops/SkPathOpsWinding.cpp',
'<(skia_src_path)/pathops/SkPathWriter.cpp',
'<(skia_src_path)/pathops/SkReduceOrder.cpp',
diff --git a/src/pathops/SkDConicLineIntersection.cpp b/src/pathops/SkDConicLineIntersection.cpp
index 674068d55f..c9d825d56c 100644
--- a/src/pathops/SkDConicLineIntersection.cpp
+++ b/src/pathops/SkDConicLineIntersection.cpp
@@ -17,12 +17,19 @@ public:
LineConicIntersections(const SkDConic& c, const SkDLine& l, SkIntersections* i)
: fConic(c)
- , fLine(l)
+ , fLine(&l)
, fIntersections(i)
, fAllowNear(true) {
i->setMax(3); // allow short partial coincidence plus discrete intersection
}
+ LineConicIntersections(const SkDConic& c)
+ : fConic(c)
+ SkDEBUGPARAMS(fLine(NULL))
+ SkDEBUGPARAMS(fIntersections(NULL))
+ SkDEBUGPARAMS(fAllowNear(false)) {
+ }
+
void allowNear(bool allow) {
fAllowNear = allow;
}
@@ -32,7 +39,7 @@ public:
for (int index = 0; index < last; ) {
double conicMidT = ((*fIntersections)[0][index] + (*fIntersections)[0][index + 1]) / 2;
SkDPoint conicMidPt = fConic.ptAtT(conicMidT);
- double t = fLine.nearPoint(conicMidPt, NULL);
+ double t = fLine->nearPoint(conicMidPt, NULL);
if (t < 0) {
++index;
continue;
@@ -56,6 +63,10 @@ public:
return approximately_zero_when_compared_to(a - b, max);
}
#endif
+ int horizontalIntersect(double axisIntercept, double roots[2]) {
+ double conicVals[] = { fConic[0].fY, fConic[1].fY, fConic[2].fY };
+ return this->validT(conicVals, axisIntercept, roots);
+ }
int horizontalIntersect(double axisIntercept, double left, double right, bool flipped) {
this->addExactHorizontalEndPoints(left, right, axisIntercept);
@@ -63,11 +74,11 @@ public:
this->addNearHorizontalEndPoints(left, right, axisIntercept);
}
double roots[2];
- double conicVals[] = { fConic[0].fY, fConic[1].fY, fConic[2].fY };
- int count = this->validT(conicVals, axisIntercept, roots);
+ int count = this->horizontalIntersect(axisIntercept, roots);
for (int index = 0; index < count; ++index) {
double conicT = roots[index];
SkDPoint pt = fConic.ptAtT(conicT);
+ SkDEBUGCODE_(double conicVals[] = { fConic[0].fY, fConic[1].fY, fConic[2].fY });
SkASSERT(close_to(pt.fY, axisIntercept, conicVals));
double lineT = (pt.fX - left) / (right - left);
if (this->pinTs(&conicT, &lineT, &pt, kPointInitialized)
@@ -93,7 +104,7 @@ public:
double conicT = rootVals[index];
double lineT = this->findLineT(conicT);
SkDEBUGCODE(SkDPoint conicPt = fConic.ptAtT(conicT));
- SkDEBUGCODE(SkDPoint linePt = fLine.ptAtT(lineT));
+ SkDEBUGCODE(SkDPoint linePt = fLine->ptAtT(lineT));
SkASSERT(conicPt.approximatelyEqual(linePt));
SkDPoint pt;
if (this->pinTs(&conicT, &lineT, &pt, kPointUninitialized)
@@ -106,11 +117,11 @@ public:
}
int intersectRay(double roots[2]) {
- double adj = fLine[1].fX - fLine[0].fX;
- double opp = fLine[1].fY - fLine[0].fY;
+ double adj = (*fLine)[1].fX - (*fLine)[0].fX;
+ double opp = (*fLine)[1].fY - (*fLine)[0].fY;
double r[3];
for (int n = 0; n < 3; ++n) {
- r[n] = (fConic[n].fY - fLine[0].fY) * adj - (fConic[n].fX - fLine[0].fX) * opp;
+ r[n] = (fConic[n].fY - (*fLine)[0].fY) * adj - (fConic[n].fX - (*fLine)[0].fX) * opp;
}
return this->validT(r, 0, roots);
}
@@ -125,17 +136,22 @@ public:
return SkDQuad::RootsValidT(A, 2 * B, C, roots);
}
+ int verticalIntersect(double axisIntercept, double roots[2]) {
+ double conicVals[] = { fConic[0].fX, fConic[1].fX, fConic[2].fX };
+ return this->validT(conicVals, axisIntercept, roots);
+ }
+
int verticalIntersect(double axisIntercept, double top, double bottom, bool flipped) {
this->addExactVerticalEndPoints(top, bottom, axisIntercept);
if (fAllowNear) {
this->addNearVerticalEndPoints(top, bottom, axisIntercept);
}
double roots[2];
- double conicVals[] = { fConic[0].fX, fConic[1].fX, fConic[2].fX };
- int count = this->validT(conicVals, axisIntercept, roots);
+ int count = this->verticalIntersect(axisIntercept, roots);
for (int index = 0; index < count; ++index) {
double conicT = roots[index];
SkDPoint pt = fConic.ptAtT(conicT);
+ SkDEBUGCODE_(double conicVals[] = { fConic[0].fX, fConic[1].fX, fConic[2].fX });
SkASSERT(close_to(pt.fX, axisIntercept, conicVals));
double lineT = (pt.fY - top) / (bottom - top);
if (this->pinTs(&conicT, &lineT, &pt, kPointInitialized)
@@ -155,7 +171,7 @@ protected:
// add endpoints first to get zero and one t values exactly
void addExactEndPoints() {
for (int cIndex = 0; cIndex < SkDConic::kPointCount; cIndex += SkDConic::kPointLast) {
- double lineT = fLine.exactPoint(fConic[cIndex]);
+ double lineT = fLine->exactPoint(fConic[cIndex]);
if (lineT < 0) {
continue;
}
@@ -170,7 +186,7 @@ protected:
if (fIntersections->hasT(conicT)) {
continue;
}
- double lineT = fLine.nearPoint(fConic[cIndex], NULL);
+ double lineT = fLine->nearPoint(fConic[cIndex], NULL);
if (lineT < 0) {
continue;
}
@@ -233,12 +249,12 @@ protected:
double findLineT(double t) {
SkDPoint xy = fConic.ptAtT(t);
- double dx = fLine[1].fX - fLine[0].fX;
- double dy = fLine[1].fY - fLine[0].fY;
+ double dx = (*fLine)[1].fX - (*fLine)[0].fX;
+ double dy = (*fLine)[1].fY - (*fLine)[0].fY;
if (fabs(dx) > fabs(dy)) {
- return (xy.fX - fLine[0].fX) / dx;
+ return (xy.fX - (*fLine)[0].fX) / dx;
}
- return (xy.fY - fLine[0].fY) / dy;
+ return (xy.fY - (*fLine)[0].fY) / dy;
}
bool pinTs(double* conicT, double* lineT, SkDPoint* pt, PinTPoint ptSet) {
@@ -251,16 +267,16 @@ protected:
double qT = *conicT = SkPinT(*conicT);
double lT = *lineT = SkPinT(*lineT);
if (lT == 0 || lT == 1 || (ptSet == kPointUninitialized && qT != 0 && qT != 1)) {
- *pt = fLine.ptAtT(lT);
+ *pt = (*fLine).ptAtT(lT);
} else if (ptSet == kPointUninitialized) {
*pt = fConic.ptAtT(qT);
}
SkPoint gridPt = pt->asSkPoint();
- if (SkDPoint::ApproximatelyEqual(gridPt, fLine[0].asSkPoint())) {
- *pt = fLine[0];
+ if (SkDPoint::ApproximatelyEqual(gridPt, (*fLine)[0].asSkPoint())) {
+ *pt = (*fLine)[0];
*lineT = 0;
- } else if (SkDPoint::ApproximatelyEqual(gridPt, fLine[1].asSkPoint())) {
- *pt = fLine[1];
+ } else if (SkDPoint::ApproximatelyEqual(gridPt, (*fLine)[1].asSkPoint())) {
+ *pt = (*fLine)[1];
*lineT = 1;
}
if (fIntersections->used() > 0 && approximately_equal((*fIntersections)[1][0], *lineT)) {
@@ -302,7 +318,7 @@ protected:
private:
const SkDConic& fConic;
- const SkDLine& fLine;
+ const SkDLine* fLine;
SkIntersections* fIntersections;
bool fAllowNear;
};
@@ -335,3 +351,13 @@ int SkIntersections::intersectRay(const SkDConic& conic, const SkDLine& line) {
}
return fUsed;
}
+
+int SkIntersections::HorizontalIntercept(const SkDConic& conic, SkScalar y, double* roots) {
+ LineConicIntersections c(conic);
+ return c.horizontalIntersect(y, roots);
+}
+
+int SkIntersections::VerticalIntercept(const SkDConic& conic, SkScalar x, double* roots) {
+ LineConicIntersections c(conic);
+ return c.verticalIntersect(x, roots);
+}
diff --git a/src/pathops/SkDLineIntersection.cpp b/src/pathops/SkDLineIntersection.cpp
index ed96b9c5d7..5fd8e7fdb7 100644
--- a/src/pathops/SkDLineIntersection.cpp
+++ b/src/pathops/SkDLineIntersection.cpp
@@ -188,7 +188,7 @@ static int horizontal_coincident(const SkDLine& line, double y) {
return 1;
}
-static double horizontal_intercept(const SkDLine& line, double y) {
+double SkIntersections::HorizontalIntercept(const SkDLine& line, double y) {
return SkPinT((y - line[0].fY) / (line[1].fY - line[0].fY));
}
@@ -214,7 +214,7 @@ int SkIntersections::horizontal(const SkDLine& line, double left, double right,
}
int result = horizontal_coincident(line, y);
if (result == 1 && fUsed == 0) {
- fT[0][0] = horizontal_intercept(line, y);
+ fT[0][0] = HorizontalIntercept(line, y);
double xIntercept = line[0].fX + fT[0][0] * (line[1].fX - line[0].fX);
if (between(left, xIntercept, right)) {
fT[1][0] = (xIntercept - left) / (right - left);
@@ -264,7 +264,7 @@ static int vertical_coincident(const SkDLine& line, double x) {
return 1;
}
-static double vertical_intercept(const SkDLine& line, double x) {
+double SkIntersections::VerticalIntercept(const SkDLine& line, double x) {
return SkPinT((x - line[0].fX) / (line[1].fX - line[0].fX));
}
@@ -290,7 +290,7 @@ int SkIntersections::vertical(const SkDLine& line, double top, double bottom,
}
int result = vertical_coincident(line, x);
if (result == 1 && fUsed == 0) {
- fT[0][0] = vertical_intercept(line, x);
+ fT[0][0] = VerticalIntercept(line, x);
double yIntercept = line[0].fY + fT[0][0] * (line[1].fY - line[0].fY);
if (between(top, yIntercept, bottom)) {
fT[1][0] = (yIntercept - top) / (bottom - top);
diff --git a/src/pathops/SkDQuadLineIntersection.cpp b/src/pathops/SkDQuadLineIntersection.cpp
index b8a9a641dd..5e3596ec20 100644
--- a/src/pathops/SkDQuadLineIntersection.cpp
+++ b/src/pathops/SkDQuadLineIntersection.cpp
@@ -95,12 +95,19 @@ public:
LineQuadraticIntersections(const SkDQuad& q, const SkDLine& l, SkIntersections* i)
: fQuad(q)
- , fLine(l)
+ , fLine(&l)
, fIntersections(i)
, fAllowNear(true) {
i->setMax(3); // allow short partial coincidence plus discrete intersection
}
+ LineQuadraticIntersections(const SkDQuad& q)
+ : fQuad(q)
+ SkDEBUGPARAMS(fLine(NULL))
+ SkDEBUGPARAMS(fIntersections(NULL))
+ SkDEBUGPARAMS(fAllowNear(false)) {
+ }
+
void allowNear(bool allow) {
fAllowNear = allow;
}
@@ -110,7 +117,7 @@ public:
for (int index = 0; index < last; ) {
double quadMidT = ((*fIntersections)[0][index] + (*fIntersections)[0][index + 1]) / 2;
SkDPoint quadMidPt = fQuad.ptAtT(quadMidT);
- double t = fLine.nearPoint(quadMidPt, NULL);
+ double t = fLine->nearPoint(quadMidPt, NULL);
if (t < 0) {
++index;
continue;
@@ -144,11 +151,11 @@ public:
for each of the three points (e.g. n = 0 to 2)
quad[n].fY' = (quad[n].fY - line[0].fY) * A - (quad[n].fX - line[0].fX) * O
*/
- double adj = fLine[1].fX - fLine[0].fX;
- double opp = fLine[1].fY - fLine[0].fY;
+ double adj = (*fLine)[1].fX - (*fLine)[0].fX;
+ double opp = (*fLine)[1].fY - (*fLine)[0].fY;
double r[3];
for (int n = 0; n < 3; ++n) {
- r[n] = (fQuad[n].fY - fLine[0].fY) * adj - (fQuad[n].fX - fLine[0].fX) * opp;
+ r[n] = (fQuad[n].fY - (*fLine)[0].fY) * adj - (fQuad[n].fX - (*fLine)[0].fX) * opp;
}
double A = r[2];
double B = r[1];
@@ -269,7 +276,7 @@ protected:
// add endpoints first to get zero and one t values exactly
void addExactEndPoints() {
for (int qIndex = 0; qIndex < 3; qIndex += 2) {
- double lineT = fLine.exactPoint(fQuad[qIndex]);
+ double lineT = fLine->exactPoint(fQuad[qIndex]);
if (lineT < 0) {
continue;
}
@@ -284,7 +291,7 @@ protected:
if (fIntersections->hasT(quadT)) {
continue;
}
- double lineT = fLine.nearPoint(fQuad[qIndex], NULL);
+ double lineT = fLine->nearPoint(fQuad[qIndex], NULL);
if (lineT < 0) {
continue;
}
@@ -347,12 +354,12 @@ protected:
double findLineT(double t) {
SkDPoint xy = fQuad.ptAtT(t);
- double dx = fLine[1].fX - fLine[0].fX;
- double dy = fLine[1].fY - fLine[0].fY;
+ double dx = (*fLine)[1].fX - (*fLine)[0].fX;
+ double dy = (*fLine)[1].fY - (*fLine)[0].fY;
if (fabs(dx) > fabs(dy)) {
- return (xy.fX - fLine[0].fX) / dx;
+ return (xy.fX - (*fLine)[0].fX) / dx;
}
- return (xy.fY - fLine[0].fY) / dy;
+ return (xy.fY - (*fLine)[0].fY) / dy;
}
bool pinTs(double* quadT, double* lineT, SkDPoint* pt, PinTPoint ptSet) {
@@ -365,16 +372,16 @@ protected:
double qT = *quadT = SkPinT(*quadT);
double lT = *lineT = SkPinT(*lineT);
if (lT == 0 || lT == 1 || (ptSet == kPointUninitialized && qT != 0 && qT != 1)) {
- *pt = fLine.ptAtT(lT);
+ *pt = (*fLine).ptAtT(lT);
} else if (ptSet == kPointUninitialized) {
*pt = fQuad.ptAtT(qT);
}
SkPoint gridPt = pt->asSkPoint();
- if (SkDPoint::ApproximatelyEqual(gridPt, fLine[0].asSkPoint())) {
- *pt = fLine[0];
+ if (SkDPoint::ApproximatelyEqual(gridPt, (*fLine)[0].asSkPoint())) {
+ *pt = (*fLine)[0];
*lineT = 0;
- } else if (SkDPoint::ApproximatelyEqual(gridPt, fLine[1].asSkPoint())) {
- *pt = fLine[1];
+ } else if (SkDPoint::ApproximatelyEqual(gridPt, (*fLine)[1].asSkPoint())) {
+ *pt = (*fLine)[1];
*lineT = 1;
}
if (fIntersections->used() > 0 && approximately_equal((*fIntersections)[1][0], *lineT)) {
@@ -392,7 +399,7 @@ protected:
private:
const SkDQuad& fQuad;
- const SkDLine& fLine;
+ const SkDLine* fLine;
SkIntersections* fIntersections;
bool fAllowNear;
};
@@ -425,3 +432,13 @@ int SkIntersections::intersectRay(const SkDQuad& quad, const SkDLine& line) {
}
return fUsed;
}
+
+int SkIntersections::HorizontalIntercept(const SkDQuad& quad, SkScalar y, double* roots) {
+ LineQuadraticIntersections q(quad);
+ return q.horizontalIntersect(y, roots);
+}
+
+int SkIntersections::VerticalIntercept(const SkDQuad& quad, SkScalar x, double* roots) {
+ LineQuadraticIntersections q(quad);
+ return q.verticalIntersect(x, roots);
+}
diff --git a/src/pathops/SkIntersections.cpp b/src/pathops/SkIntersections.cpp
index a1f859833a..7caf04bf4d 100644
--- a/src/pathops/SkIntersections.cpp
+++ b/src/pathops/SkIntersections.cpp
@@ -25,37 +25,6 @@ int SkIntersections::closestTo(double rangeStart, double rangeEnd, const SkDPoin
return closest;
}
-// called only by test code
-int SkIntersections::coincidentUsed() const {
- if (!fIsCoincident[0]) {
- SkASSERT(!fIsCoincident[1]);
- return 0;
- }
- int count = 0;
- SkDEBUGCODE(int count2 = 0;)
- for (int index = 0; index < fUsed; ++index) {
- if (fIsCoincident[0] & (1 << index)) {
- ++count;
- }
-#ifdef SK_DEBUG
- if (fIsCoincident[1] & (1 << index)) {
- ++count2;
- }
-#endif
- }
- SkASSERT(count == count2);
- return count;
-}
-
-int (SkIntersections::* const CurveVertical[])(const SkPoint[], SkScalar,
- SkScalar, SkScalar, SkScalar, bool) = {
- NULL,
- &SkIntersections::verticalLine,
- &SkIntersections::verticalQuad,
- &SkIntersections::verticalConic,
- &SkIntersections::verticalCubic
-};
-
void SkIntersections::flip() {
for (int index = 0; index < fUsed; ++index) {
fT[1][index] = 1 - fT[1][index];
@@ -174,12 +143,6 @@ int SkIntersections::mostOutside(double rangeStart, double rangeEnd, const SkDPo
return result;
}
-void SkIntersections::quickRemoveOne(int index, int replace) {
- if (index < replace) {
- fT[0][index] = fT[0][replace];
- }
-}
-
void SkIntersections::removeOne(int index) {
int remaining = --fUsed - index;
if (remaining <= 0) {
@@ -194,31 +157,3 @@ void SkIntersections::removeOne(int index) {
SkASSERT(!(coBit ^ (fIsCoincident[1] & (1 << index))));
fIsCoincident[1] -= ((fIsCoincident[1] >> 1) & ~((1 << index) - 1)) + coBit;
}
-
-int SkIntersections::verticalConic(const SkPoint a[3], SkScalar weight,
- SkScalar top, SkScalar bottom, SkScalar x, bool flipped) {
- SkDConic conic;
- conic.set(a, weight);
- return vertical(conic, top, bottom, x, flipped);
-}
-
-int SkIntersections::verticalCubic(const SkPoint a[4], SkScalar weight,
- SkScalar top, SkScalar bottom, SkScalar x, bool flipped) {
- SkDCubic cubic;
- cubic.set(a);
- return vertical(cubic, top, bottom, x, flipped);
-}
-
-int SkIntersections::verticalLine(const SkPoint a[2], SkScalar weight,
- SkScalar top, SkScalar bottom, SkScalar x, bool flipped) {
- SkDLine line;
- line.set(a);
- return vertical(line, top, bottom, x, flipped);
-}
-
-int SkIntersections::verticalQuad(const SkPoint a[3], SkScalar weight,
- SkScalar top, SkScalar bottom, SkScalar x, bool flipped) {
- SkDQuad quad;
- quad.set(a);
- return vertical(quad, top, bottom, x, flipped);
-}
diff --git a/src/pathops/SkIntersections.h b/src/pathops/SkIntersections.h
index 57fb49bcd2..c12db38b6c 100644
--- a/src/pathops/SkIntersections.h
+++ b/src/pathops/SkIntersections.h
@@ -224,7 +224,6 @@ public:
void alignQuadPts(const SkPoint a[3], const SkPoint b[3]);
int cleanUpCoincidence();
int closestTo(double rangeStart, double rangeEnd, const SkDPoint& testPt, double* dist) const;
- int coincidentUsed() const;
void cubicInsert(double one, double two, const SkDPoint& pt, const SkDCubic& c1,
const SkDCubic& c2);
void flip();
@@ -235,6 +234,9 @@ public:
int horizontal(const SkDConic&, double left, double right, double y, bool flipped);
int horizontal(const SkDCubic&, double left, double right, double y, bool flipped);
int horizontal(const SkDCubic&, double left, double right, double y, double tRange[3]);
+ static double HorizontalIntercept(const SkDLine& line, double y);
+ static int HorizontalIntercept(const SkDQuad& quad, SkScalar y, double* roots);
+ static int HorizontalIntercept(const SkDConic& conic, SkScalar y, double* roots);
// FIXME : does not respect swap
int insert(double one, double two, const SkDPoint& pt);
void insertNear(double one, double two, const SkDPoint& pt1, const SkDPoint& pt2);
@@ -256,21 +258,15 @@ public:
int intersectRay(const SkDCubic&, const SkDLine&);
void merge(const SkIntersections& , int , const SkIntersections& , int );
int mostOutside(double rangeStart, double rangeEnd, const SkDPoint& origin) const;
- void quickRemoveOne(int index, int replace);
void removeOne(int index);
void setCoincident(int index);
int vertical(const SkDLine&, double top, double bottom, double x, bool flipped);
int vertical(const SkDQuad&, double top, double bottom, double x, bool flipped);
int vertical(const SkDConic&, double top, double bottom, double x, bool flipped);
int vertical(const SkDCubic&, double top, double bottom, double x, bool flipped);
- int verticalConic(const SkPoint a[3], SkScalar weight, SkScalar top, SkScalar bottom,
- SkScalar x, bool flipped);
- int verticalCubic(const SkPoint a[4], SkScalar weight, SkScalar top, SkScalar bottom,
- SkScalar x, bool flipped);
- int verticalLine(const SkPoint a[2], SkScalar weight, SkScalar top, SkScalar bottom,
- SkScalar x, bool flipped);
- int verticalQuad(const SkPoint a[3], SkScalar weight, SkScalar top, SkScalar bottom,
- SkScalar x, bool flipped);
+ static double VerticalIntercept(const SkDLine& line, double x);
+ static int VerticalIntercept(const SkDQuad& quad, SkScalar x, double* roots);
+ static int VerticalIntercept(const SkDConic& conic, SkScalar x, double* roots);
int depth() const {
#ifdef SK_DEBUG
@@ -280,6 +276,7 @@ public:
#endif
}
+ int debugCoincidentUsed() const;
void dump() const; // implemented for testing only
private:
@@ -303,7 +300,4 @@ private:
#endif
};
-extern int (SkIntersections::* const CurveVertical[])(const SkPoint[], SkScalar weight,
- SkScalar top, SkScalar bottom, SkScalar x, bool flipped);
-
#endif
diff --git a/src/pathops/SkOpAngle.cpp b/src/pathops/SkOpAngle.cpp
index 52a98d0ba7..6e49c4977f 100644
--- a/src/pathops/SkOpAngle.cpp
+++ b/src/pathops/SkOpAngle.cpp
@@ -360,6 +360,10 @@ recomputeSector:
fUnorderable = true;
return false;
}
+ if (stepUp != (fStart->t() < computedEnd->t())) {
+ fUnorderable = true;
+ return false;
+ }
SkOpSpanBase* saveEnd = fEnd;
fComputedEnd = fEnd = computedEnd;
setSpans();
@@ -597,78 +601,6 @@ bool SkOpAngle::endToSide(const SkOpAngle* rh, bool* inside) const {
return true;
}
-// Most of the time, the first one can be found trivially by detecting the smallest sector value.
-// If all angles have the same sector value, actual sorting is required.
-SkOpAngle* SkOpAngle::findFirst() {
- SkOpAngle* best = this;
- int bestStart = SkTMin(fSectorStart, fSectorEnd);
- SkOpAngle* angle = this;
- while ((angle = angle->fNext) != this) {
- int angleEnd = SkTMax(angle->fSectorStart, angle->fSectorEnd);
- if (angleEnd < bestStart) {
- return angle; // we wrapped around
- }
- int angleStart = SkTMin(angle->fSectorStart, angle->fSectorEnd);
- if (bestStart > angleStart) {
- best = angle;
- bestStart = angleStart;
- }
- }
- // back up to the first possible angle
- SkOpAngle* firstBest = best;
- angle = best;
- int bestEnd = SkTMax(best->fSectorStart, best->fSectorEnd);
- while ((angle = angle->previous()) != firstBest) {
- if (angle->fStop) {
- break;
- }
- int angleStart = SkTMin(angle->fSectorStart, angle->fSectorEnd);
- // angles that are smaller by one aren't necessary better, since the larger may be a line
- // and the smaller may be a curve that curls to the other side of the line.
- if (bestEnd + 1 < angleStart) {
- return best;
- }
- best = angle;
- bestEnd = SkTMax(angle->fSectorStart, angle->fSectorEnd);
- }
- // in the case where all angles are nearly in the same sector, check the order to find the best
- firstBest = best;
- angle = best;
- do {
- angle = angle->fNext;
- if (angle->fStop) {
- return firstBest;
- }
- bool orderable = best->orderable(angle); // note: may return an unorderable angle
- if (orderable == 0) {
- return angle;
- }
- best = angle;
- } while (angle != firstBest);
- // if the angles are equally ordered, fall back on the initial tangent
- bool foundBelow = false;
- while ((angle = angle->fNext)) {
- SkDVector scratch[2];
- const SkDVector* sweep;
- if (!angle->fUnorderedSweep) {
- sweep = angle->fSweep;
- } else {
- scratch[0] = angle->fCurvePart[1] - angle->fCurvePart[0];
- sweep = &scratch[0];
- }
- bool isAbove = sweep->fY <= 0;
- if (isAbove && foundBelow) {
- return angle;
- }
- foundBelow |= !isAbove;
- if (angle == firstBest) {
- return NULL; // should not loop around
- }
- }
- SkASSERT(0); // should never get here
- return NULL;
-}
-
/* y<0 y==0 y>0 x<0 x==0 x>0 xy<0 xy==0 xy>0
0 x x x
1 x x x
@@ -816,26 +748,6 @@ int SkOpAngle::loopCount() const {
return count;
}
-// OPTIMIZATION: can this be done better in after when angles are sorted?
-bool SkOpAngle::markStops() {
- SkOpAngle* angle = this;
- int lastEnd = SkTMax(fSectorStart, fSectorEnd);
- do {
- angle = angle->fNext;
- if (!angle) {
- return false;
- }
- int angleStart = SkTMin(angle->fSectorStart, angle->fSectorEnd);
- // angles that are smaller by one aren't necessary better, since the larger may be a line
- // and the smaller may be a curve that curls to the other side of the line.
- if (lastEnd + 1 < angleStart) {
- angle->fStop = true;
- }
- lastEnd = SkTMax(angle->fSectorStart, angle->fSectorEnd);
- } while (angle != this);
- return true;
-}
-
bool SkOpAngle::merge(SkOpAngle* angle) {
SkASSERT(fNext);
SkASSERT(angle->fNext);
@@ -968,7 +880,6 @@ void SkOpAngle::set(SkOpSpanBase* start, SkOpSpanBase* end) {
SkASSERT(start != end);
fNext = NULL;
fComputeSector = fComputedSector = fCheckCoincidence = false;
- fStop = false;
setSpans();
setSector();
SkDEBUGCODE(fID = start ? start->globalState()->nextAngleID() : -1);
@@ -1157,11 +1068,6 @@ deferTilLater:
}
}
-int SkOpAngle::sign() const {
- SkASSERT(fStart->t() != fEnd->t());
- return fStart->t() < fEnd->t() ? -1 : 1;
-}
-
SkOpSpan* SkOpAngle::starter() {
return fStart->starter(fEnd);
}
diff --git a/src/pathops/SkOpAngle.h b/src/pathops/SkOpAngle.h
index 7088dd716f..dba3f3ffac 100644
--- a/src/pathops/SkOpAngle.h
+++ b/src/pathops/SkOpAngle.h
@@ -42,7 +42,7 @@ struct SkOpAngle {
return SkDEBUGRELEASE(fID, -1);
}
-#if DEBUG_SORT || DEBUG_SWAP_TOP
+#if DEBUG_SORT
void debugLoop() const;
#endif
@@ -51,6 +51,7 @@ struct SkOpAngle {
#endif
const SkOpPtT* debugPtT(int id) const;
const SkOpSegment* debugSegment(int id) const;
+ int debugSign() const;
const SkOpSpanBase* debugSpan(int id) const;
void debugValidate() const;
void debugValidateNext() const; // in debug builds, verify that angle loop is uncorrupted
@@ -69,14 +70,12 @@ struct SkOpAngle {
bool endsIntersect(SkOpAngle* );
bool endToSide(const SkOpAngle* rh, bool* inside) const;
- SkOpAngle* findFirst();
int findSector(SkPath::Verb verb, double x, double y) const;
SkOpGlobalState* globalState() const;
void insert(SkOpAngle* );
SkOpSpanBase* lastMarked() const;
bool loopContains(const SkOpAngle* ) const;
int loopCount() const;
- bool markStops();
bool merge(SkOpAngle* );
double midT() const;
bool midToSide(const SkOpAngle* rh, bool* inside) const;
@@ -112,7 +111,6 @@ struct SkOpAngle {
void setSector();
void setSpans();
- int sign() const;
SkOpSpanBase* start() const {
return fStart;
@@ -138,7 +136,6 @@ struct SkOpAngle {
int8_t fSectorStart; // in 32nds of a circle
int8_t fSectorEnd;
bool fIsCurve;
- bool fStop; // set if ordered angle is greater than the previous
bool fUnorderable;
bool fUnorderedSweep; // set when a cubic's first control point between the sweep vectors
bool fComputeSector;
diff --git a/src/pathops/SkOpCoincidence.h b/src/pathops/SkOpCoincidence.h
index 84bc832e9f..4d906e1af1 100644
--- a/src/pathops/SkOpCoincidence.h
+++ b/src/pathops/SkOpCoincidence.h
@@ -36,6 +36,7 @@ public:
bool apply();
bool contains(SkOpPtT* coinPtTStart, SkOpPtT* coinPtTEnd, SkOpPtT* oppPtTStart,
SkOpPtT* oppPtTEnd, bool flipped);
+ void debugShowCoincidence() const;
void detach(SkCoincidentSpans* );
void dump() const;
void expand();
diff --git a/src/pathops/SkOpContour.cpp b/src/pathops/SkOpContour.cpp
index 107c83169b..178ba3e89c 100644
--- a/src/pathops/SkOpContour.cpp
+++ b/src/pathops/SkOpContour.cpp
@@ -37,28 +37,6 @@ SkOpSegment* SkOpContour::addCurve(SkPath::Verb verb, const SkPoint pts[4],
return NULL;
}
-SkOpSegment* SkOpContour::nonVerticalSegment(SkOpSpanBase** start, SkOpSpanBase** end) {
- int segmentCount = fSortedSegments.count();
- SkASSERT(segmentCount > 0);
- for (int sortedIndex = fFirstSorted; sortedIndex < segmentCount; ++sortedIndex) {
- SkOpSegment* testSegment = fSortedSegments[sortedIndex];
- if (testSegment->done()) {
- continue;
- }
- SkOpSpanBase* span = testSegment->head();
- SkOpSpanBase* testS, * testE;
- while (SkOpSegment::NextCandidate(span, &testS, &testE)) {
- if (!testSegment->isVertical(testS, testE)) {
- *start = testS;
- *end = testE;
- return testSegment;
- }
- span = span->upCast()->next();
- }
- }
- return NULL;
-}
-
void SkOpContour::toPath(SkPathWriter* path) const {
const SkPoint& pt = fHead.pts()[0];
path->deferredMove(pt);
@@ -69,41 +47,6 @@ void SkOpContour::toPath(SkPathWriter* path) const {
path->close();
}
-void SkOpContour::topSortableSegment(const SkDPoint& topLeft, SkDPoint* bestXY,
- SkOpSegment** topStart) {
- int segmentCount = fSortedSegments.count();
- SkASSERT(segmentCount > 0);
- int sortedIndex = fFirstSorted;
- fDone = true; // may be cleared below
- for ( ; sortedIndex < segmentCount; ++sortedIndex) {
- SkOpSegment* testSegment = fSortedSegments[sortedIndex];
- if (testSegment->done()) {
- if (sortedIndex == fFirstSorted) {
- ++fFirstSorted;
- }
- continue;
- }
- fDone = false;
- SkDPoint testXY = testSegment->activeLeftTop(NULL);
- 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;
- }
- }
- *topStart = testSegment;
- *bestXY = testXY;
- }
-}
-
SkOpSegment* SkOpContour::undoneSegment(SkOpSpanBase** startPtr, SkOpSpanBase** endPtr) {
SkOpSegment* segment = &fHead;
do {
diff --git a/src/pathops/SkOpContour.h b/src/pathops/SkOpContour.h
index 9abf38238b..dd5dbb40ca 100644
--- a/src/pathops/SkOpContour.h
+++ b/src/pathops/SkOpContour.h
@@ -12,6 +12,8 @@
#include "SkTSort.h"
class SkChunkAlloc;
+enum class SkOpRayDir;
+struct SkOpRayHit;
class SkPathWriter;
class SkOpContour {
@@ -106,7 +108,7 @@ public:
}
int debugIndent() const {
- return SkDEBUGRELEASE(fIndent, 0);
+ return SkDEBUGRELEASE(fDebugIndent, 0);
}
#if DEBUG_ACTIVE_SPANS
@@ -119,23 +121,23 @@ public:
#endif
const SkOpAngle* debugAngle(int id) const {
- return SkDEBUGRELEASE(globalState()->debugAngle(id), NULL);
+ return SkDEBUGRELEASE(this->globalState()->debugAngle(id), NULL);
}
SkOpContour* debugContour(int id) {
- return SkDEBUGRELEASE(globalState()->debugContour(id), NULL);
+ return SkDEBUGRELEASE(this->globalState()->debugContour(id), NULL);
}
const SkOpPtT* debugPtT(int id) const {
- return SkDEBUGRELEASE(globalState()->debugPtT(id), NULL);
+ return SkDEBUGRELEASE(this->globalState()->debugPtT(id), NULL);
}
const SkOpSegment* debugSegment(int id) const {
- return SkDEBUGRELEASE(globalState()->debugSegment(id), NULL);
+ return SkDEBUGRELEASE(this->globalState()->debugSegment(id), NULL);
}
const SkOpSpanBase* debugSpan(int id) const {
- return SkDEBUGRELEASE(globalState()->debugSpan(id), NULL);
+ return SkDEBUGRELEASE(this->globalState()->debugSpan(id), NULL);
}
SkOpGlobalState* globalState() const {
@@ -159,9 +161,17 @@ public:
return fDone;
}
- void dump();
- void dumpAll();
+ void dump() const;
+ void dumpAll() const;
void dumpAngles() const;
+ void dumpContours() const;
+ void dumpContoursAll() const;
+ void dumpContoursAngles() const;
+ void dumpContoursPts() const;
+ void dumpContoursPt(int segmentID) const;
+ void dumpContoursSegment(int segmentID) const;
+ void dumpContoursSpan(int segmentID) const;
+ void dumpContoursSpans() const;
void dumpPt(int ) const;
void dumpPts() const;
void dumpPtsX() const;
@@ -174,6 +184,8 @@ public:
return fTail->pts()[SkPathOpsVerbToPoints(fTail->verb())];
}
+ SkOpSpan* findSortableTop(SkOpContour* );
+
SkOpSegment* first() {
SkASSERT(fCount > 0);
return &fHead;
@@ -184,8 +196,8 @@ public:
return &fHead;
}
- void indentDump() {
- SkDEBUGCODE(fIndent += 2);
+ void indentDump() const {
+ SkDEBUGCODE(fDebugIndent += 2);
}
void init(SkOpGlobalState* globalState, bool operand, bool isXor) {
@@ -236,8 +248,6 @@ public:
return fNext;
}
- SkOpSegment* nonVerticalSegment(SkOpSpanBase** start, SkOpSpanBase** end);
-
bool operand() const {
return fOperand;
}
@@ -246,10 +256,12 @@ public:
return fOppXor;
}
- void outdentDump() {
- SkDEBUGCODE(fIndent -= 2);
+ void outdentDump() const {
+ SkDEBUGCODE(fDebugIndent -= 2);
}
+ void rayCheck(const SkOpRayHit& base, SkOpRayDir dir, SkOpRayHit** hits, SkChunkAlloc* );
+
void remove(SkOpContour* contour) {
if (contour == this) {
SkASSERT(fCount == 0);
@@ -271,9 +283,10 @@ public:
fNext = NULL;
fCount = 0;
fDone = false;
+ fTopsFound = false;
SkDEBUGCODE(fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMin, SK_ScalarMin));
SkDEBUGCODE(fFirstSorted = -1);
- SkDEBUGCODE(fIndent = 0);
+ SkDEBUGCODE(fDebugIndent = 0);
}
void setBounds() {
@@ -316,15 +329,6 @@ public:
} while ((segment = segment->next()));
}
- void sortSegments() {
- SkOpSegment* segment = &fHead;
- do {
- *fSortedSegments.append() = segment;
- } while ((segment = segment->next()));
- SkTQSort<SkOpSegment>(fSortedSegments.begin(), fSortedSegments.end() - 1);
- fFirstSorted = 0;
- }
-
const SkPoint& start() const {
return fHead.pts()[0];
}
@@ -344,7 +348,6 @@ public:
}
void toPath(SkPathWriter* path) const;
- void topSortableSegment(const SkDPoint& topLeft, SkDPoint* bestXY, SkOpSegment** topStart);
SkOpSegment* undoneSegment(SkOpSpanBase** startPtr, SkOpSpanBase** endPtr);
private:
@@ -352,16 +355,19 @@ private:
SkOpSegment fHead;
SkOpSegment* fTail;
SkOpContour* fNext;
- SkTDArray<SkOpSegment*> fSortedSegments; // set by find top segment
SkPathOpsBounds fBounds;
int fCount;
int fFirstSorted;
bool fDone; // set by find top segment
+ bool fTopsFound;
bool fOperand; // true for the second argument to a binary operator
bool fXor; // set if original path had even-odd fill
bool fOppXor; // set if opposite path had even-odd fill
SkDEBUGCODE(int fID);
- SkDEBUGCODE(int fIndent);
+ SkDEBUGCODE(mutable int fDebugIndent);
+};
+
+class SkOpContourHead : public SkOpContour {
};
#endif
diff --git a/src/pathops/SkOpSegment.cpp b/src/pathops/SkOpSegment.cpp
index ce35f846b3..de813cb7c9 100644
--- a/src/pathops/SkOpSegment.cpp
+++ b/src/pathops/SkOpSegment.cpp
@@ -102,47 +102,6 @@ SkOpAngle* SkOpSegment::activeAngleOther(SkOpSpanBase* start, SkOpSpanBase** sta
return other->activeAngleInner(oSpan, startPtr, endPtr, done, sortable);
}
-SkDPoint SkOpSegment::activeLeftTop(SkOpSpanBase** firstSpan) {
- SkASSERT(!done());
- SkDPoint topPt = {SK_ScalarMax, SK_ScalarMax};
- // see if either end is not done since we want smaller Y of the pair
- bool lastDone = true;
- SkOpSpanBase* span = &fHead;
- SkOpSpanBase* lastSpan = NULL;
- do {
- if (!lastDone || (!span->final() && !span->upCast()->done())) {
- const SkPoint& xy = span->pt();
- if (topPt.fY > xy.fY || (topPt.fY == xy.fY && topPt.fX > xy.fX)) {
- topPt = xy;
- if (firstSpan) {
- *firstSpan = span;
- }
- }
- if (fVerb != SkPath::kLine_Verb && !lastDone) {
- double curveTopT;
- SkDCurve curve;
- this->subDivide(lastSpan, span, &curve);
- SkDPoint curveTop = (curve.*Top[fVerb])(fPts, fWeight, lastSpan->t(), span->t(),
- &curveTopT);
- if (topPt.fY > curveTop.fY || (topPt.fY == curveTop.fY && topPt.fX > curveTop.fX)) {
- topPt = curveTop;
- if (firstSpan) {
- const SkPoint& lastXY = lastSpan->pt();
- *firstSpan = lastXY.fY > xy.fY || (lastXY.fY == xy.fY && lastXY.fX > xy.fX)
- ? span : lastSpan;
- }
- }
- }
- lastSpan = span;
- }
- if (span->final()) {
- break;
- }
- lastDone = span->upCast()->done();
- } while ((span = span->upCast()->next()));
- return topPt;
-}
-
bool SkOpSegment::activeOp(SkOpSpanBase* start, SkOpSpanBase* end, int xorMiMask, int xorSuMask,
SkPathOp op) {
int sumMiWinding = this->updateWinding(end, start);
@@ -278,88 +237,6 @@ SkOpPtT* SkOpSegment::addMissing(double t, SkOpSegment* opp, SkChunkAlloc* alloc
return result;
}
-SkOpAngle* SkOpSegment::addSingletonAngleDown(SkOpSegment** otherPtr, SkOpAngle** anglePtr,
- SkChunkAlloc* allocator) {
- SkOpSpan* startSpan = fTail.prev();
- SkASSERT(startSpan);
- SkOpAngle* angle = SkOpTAllocator<SkOpAngle>::Allocate(allocator);
- *anglePtr = angle;
- angle->set(&fTail, startSpan);
- fTail.setFromAngle(angle);
- SkOpSegment* other = NULL; // these initializations silence a release build warning
- SkOpSpan* oStartSpan = NULL;
- SkOpSpanBase* oEndSpan = NULL;
- SkOpPtT* ptT = fTail.ptT(), * startPtT = ptT;
- while ((ptT = ptT->next()) != startPtT) {
- other = ptT->segment();
- oStartSpan = ptT->span()->upCastable();
- if (oStartSpan && oStartSpan->windValue()) {
- oEndSpan = oStartSpan->next();
- break;
- }
- oEndSpan = ptT->span();
- oStartSpan = oEndSpan->prev();
- if (oStartSpan && oStartSpan->windValue()) {
- break;
- }
- }
- if (!oStartSpan) {
- return NULL;
- }
- SkOpAngle* oAngle = SkOpTAllocator<SkOpAngle>::Allocate(allocator);
- oAngle->set(oStartSpan, oEndSpan);
- oStartSpan->setToAngle(oAngle);
- *otherPtr = other;
- return oAngle;
-}
-
-SkOpAngle* SkOpSegment::addSingletonAngles(int step, SkChunkAlloc* allocator) {
- SkOpSegment* other;
- SkOpAngle* angle, * otherAngle;
- if (step > 0) {
- otherAngle = addSingletonAngleUp(&other, &angle, allocator);
- } else {
- otherAngle = addSingletonAngleDown(&other, &angle, allocator);
- }
- if (!otherAngle) {
- return NULL;
- }
- angle->insert(otherAngle);
- return angle;
-}
-
-SkOpAngle* SkOpSegment::addSingletonAngleUp(SkOpSegment** otherPtr, SkOpAngle** anglePtr,
- SkChunkAlloc* allocator) {
- SkOpSpanBase* endSpan = fHead.next();
- SkASSERT(endSpan);
- SkOpAngle* angle = SkOpTAllocator<SkOpAngle>::Allocate(allocator);
- *anglePtr = angle;
- angle->set(&fHead, endSpan);
- fHead.setToAngle(angle);
- SkOpSegment* other = NULL; // these initializations silence a release build warning
- SkOpSpan* oStartSpan = NULL;
- SkOpSpanBase* oEndSpan = NULL;
- SkOpPtT* ptT = fHead.ptT(), * startPtT = ptT;
- while ((ptT = ptT->next()) != startPtT) {
- other = ptT->segment();
- oEndSpan = ptT->span();
- oStartSpan = oEndSpan->prev();
- if (oStartSpan && oStartSpan->windValue()) {
- break;
- }
- oStartSpan = oEndSpan->upCastable();
- if (oStartSpan && oStartSpan->windValue()) {
- oEndSpan = oStartSpan->next();
- break;
- }
- }
- SkOpAngle* oAngle = SkOpTAllocator<SkOpAngle>::Allocate(allocator);
- oAngle->set(oEndSpan, oStartSpan);
- oEndSpan->setFromAngle(oAngle);
- *otherPtr = other;
- return oAngle;
-}
-
SkOpPtT* SkOpSegment::addT(double t, AllowAlias allowAlias, SkChunkAlloc* allocator) {
debugValidate();
SkPoint pt = this->ptAtT(t);
@@ -437,14 +314,6 @@ void SkOpSegment::align() {
debugValidate();
}
-bool SkOpSegment::BetweenTs(const SkOpSpanBase* lesser, double testT,
- const SkOpSpanBase* greater) {
- if (lesser->t() > greater->t()) {
- SkTSwap<const SkOpSpanBase*>(lesser, greater);
- }
- return approximately_between(lesser->t(), testT, greater->t());
-}
-
void SkOpSegment::calcAngles(SkChunkAlloc* allocator) {
bool activePrior = !fHead.isCanceled();
if (activePrior && !fHead.simple()) {
@@ -494,20 +363,9 @@ void SkOpSegment::checkAngleCoin(SkOpCoincidence* coincidences, SkChunkAlloc* al
} while ((base = span->next()));
}
-// from http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of-polygon-points-are-in-clockwise-order
-bool SkOpSegment::clockwise(const SkOpSpanBase* start, const SkOpSpanBase* end, bool* swap) const {
- SkASSERT(fVerb != SkPath::kLine_Verb);
- if (fVerb != SkPath::kCubic_Verb) {
- SkOpCurve edge;
- this->subDivide(start, end, &edge);
- return SkDQuad::Clockwise(edge, swap);
- }
- return SkDCubic::Clockwise(fPts, start->t(), end->t(), swap);
-}
-
void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
SkOpAngle::IncludeType includeType) {
- const SkOpSegment* baseSegment = baseAngle->segment();
+ SkOpSegment* baseSegment = baseAngle->segment();
int sumMiWinding = baseSegment->updateWindingReverse(baseAngle);
int sumSuWinding;
bool binary = includeType >= SkOpAngle::kBinarySingle;
@@ -534,9 +392,9 @@ void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle
nextAngle->setLastMarked(last);
}
-void SkOpSegment::ComputeOneSumReverse(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
+void SkOpSegment::ComputeOneSumReverse(SkOpAngle* baseAngle, SkOpAngle* nextAngle,
SkOpAngle::IncludeType includeType) {
- const SkOpSegment* baseSegment = baseAngle->segment();
+ SkOpSegment* baseSegment = baseAngle->segment();
int sumMiWinding = baseSegment->updateWinding(baseAngle);
int sumSuWinding;
bool binary = includeType >= SkOpAngle::kBinarySingle;
@@ -634,102 +492,6 @@ int SkOpSegment::computeSum(SkOpSpanBase* start, SkOpSpanBase* end,
return start->starter(end)->windSum();
}
-SkOpSpan* SkOpSegment::crossedSpanY(const SkPoint& basePt, double mid, bool opp, bool current,
- SkScalar* bestY, double* hitT, bool* hitSomething, bool* vertical) {
- SkScalar bottom = fBounds.fBottom;
- *vertical = false;
- if (bottom <= *bestY) {
- return NULL;
- }
- SkScalar top = fBounds.fTop;
- if (top >= basePt.fY) {
- return NULL;
- }
- if (fBounds.fLeft > basePt.fX) {
- return NULL;
- }
- if (fBounds.fRight < basePt.fX) {
- return NULL;
- }
- if (fBounds.fLeft == fBounds.fRight) {
- // if vertical, and directly above test point, wait for another one
- *vertical = AlmostEqualUlps(basePt.fX, fBounds.fLeft);
- return NULL;
- }
- // intersect ray starting at basePt with edge
- SkIntersections intersections;
- // OPTIMIZE: use specialty function that intersects ray with curve,
- // returning t values only for curve (we don't care about t on ray)
- intersections.allowNear(false);
- int pts = (intersections.*CurveVertical[fVerb])(fPts, fWeight, top, bottom, basePt.fX, false);
- if (pts == 0 || (current && pts == 1)) {
- return NULL;
- }
- if (current) {
- SkASSERT(pts > 1);
- int closestIdx = 0;
- double closest = fabs(intersections[0][0] - mid);
- for (int idx = 1; idx < pts; ++idx) {
- double test = fabs(intersections[0][idx] - mid);
- if (closest > test) {
- closestIdx = idx;
- closest = test;
- }
- }
- intersections.quickRemoveOne(closestIdx, --pts);
- }
- double bestT = -1;
- for (int index = 0; index < pts; ++index) {
- double foundT = intersections[0][index];
- if (approximately_less_than_zero(foundT)
- || approximately_greater_than_one(foundT)) {
- continue;
- }
- SkScalar testY = (*CurvePointAtT[fVerb])(fPts, fWeight, foundT).fY;
- if (approximately_negative(testY - *bestY)
- || approximately_negative(basePt.fY - testY)) {
- continue;
- }
- if (pts > 1 && fVerb == SkPath::kLine_Verb) {
- *vertical = true;
- return NULL; // if the intersection is edge on, wait for another one
- }
- if (fVerb > SkPath::kLine_Verb) {
- SkScalar dx = (*CurveSlopeAtT[fVerb])(fPts, fWeight, foundT).fX;
- if (approximately_zero(dx)) {
- *vertical = true;
- return NULL; // hit vertical, wait for another one
- }
- }
- *bestY = testY;
- bestT = foundT;
- }
- if (bestT < 0) {
- return NULL;
- }
- SkASSERT(bestT >= 0);
- SkASSERT(bestT < 1);
- SkOpSpanBase* testTSpanBase = &this->fHead;
- SkOpSpanBase* nextTSpan;
- double endT = 0;
- do {
- nextTSpan = testTSpanBase->upCast()->next();
- endT = nextTSpan->t();
- if (endT >= bestT) {
- break;
- }
- testTSpanBase = nextTSpan;
- } while (testTSpanBase);
- SkOpSpan* bestTSpan = NULL;
- SkOpSpan* testTSpan = testTSpanBase->upCast();
- if (!testTSpan->isCanceled()) {
- *hitT = bestT;
- bestTSpan = testTSpan;
- *hitSomething = true;
- }
- return bestTSpan;
-}
-
void SkOpSegment::detach(const SkOpSpan* span) {
if (span->done()) {
--fDoneCount;
@@ -1036,126 +798,6 @@ SkOpSegment* SkOpSegment::findNextXor(SkOpSpanBase** nextStart, SkOpSpanBase** n
return nextSegment;
}
-SkOpSegment* SkOpSegment::findTop(bool firstPass, SkOpSpanBase** startPtr, SkOpSpanBase** endPtr,
- bool* unsortable, SkChunkAlloc* allocator) {
- // iterate through T intersections and return topmost
- // topmost tangent from y-min to first pt is closer to horizontal
- SkASSERT(!done());
- SkOpSpanBase* firstT = NULL;
- (void) this->activeLeftTop(&firstT);
- if (!firstT) {
- *unsortable = !firstPass;
- firstT = &fHead;
- while (firstT->upCast()->done()) {
- firstT = firstT->upCast()->next();
- }
- *startPtr = firstT;
- *endPtr = firstT->upCast()->next();
- return this;
- }
- // sort the edges to find the leftmost
- int step = 1;
- SkOpSpanBase* end;
- if (firstT->final() || firstT->upCast()->done()) {
- step = -1;
- end = firstT->prev();
- SkASSERT(end);
- } else {
- end = firstT->upCast()->next();
- }
- // if the topmost T is not on end, or is three-way or more, find left
- // look for left-ness from tLeft to firstT (matching y of other)
- SkASSERT(firstT != end);
- SkOpAngle* markAngle = spanToAngle(firstT, end);
- if (!markAngle) {
- markAngle = addSingletonAngles(step, allocator);
- }
- if (!markAngle) {
- return NULL;
- }
- if (!markAngle->markStops()) {
- return NULL;
- }
- const SkOpAngle* baseAngle = markAngle->next() == markAngle && !isVertical() ? markAngle
- : markAngle->findFirst();
- if (!baseAngle) {
- return NULL; // nothing to do
- }
- SkScalar top = SK_ScalarMax;
- const SkOpAngle* firstAngle = NULL;
- const SkOpAngle* angle = baseAngle;
-#if DEBUG_SWAP_TOP
- SkDebugf("-%s- baseAngle\n", __FUNCTION__);
- baseAngle->debugLoop();
-#endif
- do {
- if (!angle->unorderable()) {
- const SkOpSegment* next = angle->segment();
- SkPathOpsBounds bounds;
- next->subDivideBounds(angle->end(), angle->start(), &bounds);
- if (top > bounds.fTop) {
- top = bounds.fTop;
- firstAngle = angle;
- }
- }
- angle = angle->next();
- } while (angle != baseAngle);
- if (!firstAngle) {
- return NULL; // if all are unorderable, give up
- }
-#if DEBUG_SWAP_TOP
- SkDebugf("-%s- firstAngle\n", __FUNCTION__);
- firstAngle->debugLoop();
-#endif
- // skip edges that have already been processed
- angle = firstAngle;
- SkOpSegment* leftSegment = NULL;
- bool looped = false;
- do {
- *unsortable = angle->unorderable();
- if (firstPass || !*unsortable) {
- leftSegment = angle->segment();
- *startPtr = angle->end();
- *endPtr = angle->start();
- const SkOpSpan* firstSpan = (*startPtr)->starter(*endPtr);
- if (!firstSpan->done()) {
- break;
- }
- }
- angle = angle->next();
- looped = true;
- } while (angle != firstAngle);
- if (angle == firstAngle && looped) {
- return NULL;
- }
- if (leftSegment->verb() >= SkPath::kQuad_Verb) {
- SkOpSpanBase* start = *startPtr;
- SkOpSpanBase* end = *endPtr;
- bool swap;
- bool cw = leftSegment->clockwise(start, end, &swap);
-#if DEBUG_SWAP_TOP
- SkDebugf("%s id=%d s=%1.9g e=%1.9g (%c) cw=%d swap=%d inflections=%d monotonic=%d\n",
- __FUNCTION__, leftSegment->debugID(), start->t(), end->t(),
- start->t() < end->t() ? '-' : '+', cw,
- swap, leftSegment->debugInflections(start, end),
- leftSegment->monotonicInY(start, end));
-#endif
- if (!cw && swap) {
- // FIXME: I doubt it makes sense to (necessarily) swap if the edge was not the first
- // sorted but merely the first not already processed (i.e., not done)
- SkTSwap(*startPtr, *endPtr);
- }
- // FIXME: clockwise isn't reliable -- try computing swap from tangent ?
- } else {
-#if DEBUG_SWAP_TOP
- SkDebugf("%s id=%d s=%1.9g e=%1.9g (%c) cw=%d swap=%d inflections=%d monotonic=%d\n",
- __FUNCTION__, leftSegment->debugID(), (*startPtr)->t(), (*endPtr)->t(),
- (*startPtr)->t() < (*endPtr)->t() ? '-' : '+', -1, -1, -1, 1);
-#endif
- }
- return leftSegment;
-}
-
SkOpGlobalState* SkOpSegment::globalState() const {
return contour()->globalState();
}
@@ -1169,6 +811,7 @@ void SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkP
fCubicType = SkDCubic::kUnsplit_SkDCubicType;
fCount = 0;
fDoneCount = 0;
+ fTopsFound = false;
fVisited = false;
SkOpSpan* zeroSpan = &fHead;
zeroSpan->init(this, NULL, 0, fPts[0]);
@@ -1178,68 +821,6 @@ void SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkP
SkDEBUGCODE(fID = globalState()->nextSegmentID());
}
-void SkOpSegment::initWinding(SkOpSpanBase* start, SkOpSpanBase* end,
- SkOpAngle::IncludeType angleIncludeType) {
- int local = SkOpSegment::SpanSign(start, end);
- SkDEBUGCODE(bool success);
- if (angleIncludeType == SkOpAngle::kBinarySingle) {
- int oppLocal = SkOpSegment::OppSign(start, end);
- SkDEBUGCODE(success =) markAndChaseWinding(start, end, local, oppLocal, NULL);
- // OPTIMIZATION: the reverse mark and chase could skip the first marking
- SkDEBUGCODE(success |=) markAndChaseWinding(end, start, local, oppLocal, NULL);
- } else {
- SkDEBUGCODE(success =) markAndChaseWinding(start, end, local, NULL);
- // OPTIMIZATION: the reverse mark and chase could skip the first marking
- SkDEBUGCODE(success |=) markAndChaseWinding(end, start, local, NULL);
- }
- SkASSERT(success);
-}
-
-/*
-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.
-*/
-bool SkOpSegment::initWinding(SkOpSpanBase* start, SkOpSpanBase* end, double tHit,
- int winding, SkScalar hitDx, int oppWind, SkScalar hitOppDx) {
- SkASSERT(this == start->segment());
- SkASSERT(hitDx || !winding);
- SkScalar dx = (*CurveSlopeAtT[fVerb])(fPts, fWeight, tHit).fX;
-// SkASSERT(dx);
- int windVal = start->starter(end)->windValue();
-#if DEBUG_WINDING_AT_T
- SkDebugf("%s id=%d oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, debugID(), winding,
- hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal);
-#endif
- int sideWind = winding + (dx < 0 ? windVal : -windVal);
- if (abs(winding) < abs(sideWind)) {
- winding = sideWind;
- }
- SkDEBUGCODE(int oppLocal = SkOpSegment::OppSign(start, end));
- SkASSERT(hitOppDx || !oppWind || !oppLocal);
- int oppWindVal = start->starter(end)->oppValue();
- 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;
- }
- }
-#if DEBUG_WINDING_AT_T
- SkDebugf(" winding=%d oppWind=%d\n", winding, oppWind);
-#endif
- // if this fails to mark (because the edges are too small) inform caller to try again
- bool success = markAndChaseWinding(start, end, winding, oppWind, NULL);
- // OPTIMIZATION: the reverse mark and chase could skip the first marking
- success |= markAndChaseWinding(end, start, winding, oppWind, NULL);
- return success;
-}
-
bool SkOpSegment::isClose(double t, const SkOpSegment* opp) const {
SkDPoint cPt = this->dPtAtT(t);
SkDVector dxdy = (*CurveDSlopeAtT[this->verb()])(this->pts(), this->weight(), t);
@@ -1306,8 +887,7 @@ bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end,
while ((other = other->nextChase(&start, &step, &spanStart, &last))) {
if (spanStart->windSum() != SK_MinS32) {
if (this->operand() == other->operand()) {
- SkASSERT(spanStart->windSum() == winding);
- if (spanStart->oppSum() != oppWinding) {
+ if (spanStart->windSum() != winding || spanStart->oppSum() != oppWinding) {
this->globalState()->setWindingFailed();
return false;
}
@@ -1438,39 +1018,6 @@ static SkOpSegment* set_last(SkOpSpanBase** last, SkOpSpanBase* endSpan) {
return NULL;
}
-bool SkOpSegment::monotonicInY(const SkOpSpanBase* start, const SkOpSpanBase* end) const {
- SkASSERT(fVerb != SkPath::kLine_Verb);
- if (fVerb == SkPath::kQuad_Verb) {
- SkDQuad dst = SkDQuad::SubDivide(fPts, start->t(), end->t());
- return dst.monotonicInY();
- }
- if (fVerb == SkPath::kConic_Verb) {
- SkDConic dst = SkDConic::SubDivide(fPts, fWeight, start->t(), end->t());
- return dst.monotonicInY();
- }
- SkASSERT(fVerb == SkPath::kCubic_Verb);
- SkDCubic dst = SkDCubic::SubDivide(fPts, start->t(), end->t());
- if (dst.monotonicInY()) {
- return true;
- }
- SkDCubic whole;
- whole.set(fPts);
- return whole.monotonicInY();
-}
-
-bool SkOpSegment::NextCandidate(SkOpSpanBase* span, SkOpSpanBase** start,
- SkOpSpanBase** end) {
- while (span->final() || span->upCast()->done()) {
- if (span->final()) {
- return false;
- }
- span = span->upCast()->next();
- }
- *start = span;
- *end = span->upCast()->next();
- return true;
-}
-
SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpSpan** minPtr,
SkOpSpanBase** last) const {
SkOpSpanBase* origStart = *startPtr;
@@ -1499,7 +1046,7 @@ SkOpSegment* SkOpSegment::nextChase(SkOpSpanBase** startPtr, int* stepPtr, SkOpS
return NULL;
}
#if DEBUG_WINDING
- if (angle->sign() != next->sign() && !angle->segment()->contour()->isXor()
+ if (angle->debugSign() != next->debugSign() && !angle->segment()->contour()->isXor()
&& !next->segment()->contour()->isXor()) {
SkDebugf("%s mismatched signs\n", __FUNCTION__);
}
@@ -1558,7 +1105,7 @@ void SkOpSegment::missingCoincidence(SkOpCoincidence* coincidences, SkChunkAlloc
SkASSERT(ptT->span() == span);
while ((ptT = ptT->next()) != spanStopPtT) {
SkOpSegment* opp = ptT->span()->segment();
- if (opp->setVisited()) {
+ if (!opp->setVisited()) {
continue;
}
if (opp->verb() == SkPath::kLine_Verb) {
@@ -2024,19 +1571,6 @@ bool SkOpSegment::subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end,
return true;
}
-void SkOpSegment::subDivideBounds(const SkOpSpanBase* start, const SkOpSpanBase* end,
- SkPathOpsBounds* bounds) const {
- SkDCurve edge;
- subDivide(start, end, &edge);
- (edge.*SetBounds[fVerb])(fPts, fWeight, start->t(), end->t(), bounds);
-}
-
-SkDPoint SkOpSegment::top(const SkOpSpanBase* start, const SkOpSpanBase* end, double* topT) const {
- SkDCurve edge;
- subDivide(start, end, &edge);
- return (edge.*Top[fVerb])(fPts, fWeight, start->t(), end->t(), topT);
-}
-
void SkOpSegment::undoneSpan(SkOpSpanBase** start, SkOpSpanBase** end) {
SkOpSpan* span = this->head();
do {
@@ -2072,10 +1606,19 @@ int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const {
return updateOppWinding(startSpan, endSpan);
}
-int SkOpSegment::updateWinding(const SkOpSpanBase* start, const SkOpSpanBase* end) const {
- const SkOpSpan* lesser = start->starter(end);
+int SkOpSegment::updateWinding(SkOpSpanBase* start, SkOpSpanBase* end) {
+ SkOpSpan* lesser = start->starter(end);
int winding = lesser->windSum();
if (winding == SK_MinS32) {
+ SkOpGlobalState* globals = this->globalState();
+ SkOpContour* contourHead = globals->contourHead();
+ int windTry = 0;
+ while (!lesser->sortableTop(contourHead) && ++windTry < SkOpGlobalState::kMaxWindingTries) {
+ ;
+ }
+ winding = lesser->windSum();
+ }
+ if (winding == SK_MinS32) {
return winding;
}
int spanWinding = SkOpSegment::SpanSign(start, end);
@@ -2086,15 +1629,15 @@ int SkOpSegment::updateWinding(const SkOpSpanBase* start, const SkOpSpanBase* en
return winding;
}
-int SkOpSegment::updateWinding(const SkOpAngle* angle) const {
- const SkOpSpanBase* startSpan = angle->start();
- const SkOpSpanBase* endSpan = angle->end();
+int SkOpSegment::updateWinding(SkOpAngle* angle) {
+ SkOpSpanBase* startSpan = angle->start();
+ SkOpSpanBase* endSpan = angle->end();
return updateWinding(endSpan, startSpan);
}
-int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) const {
- const SkOpSpanBase* startSpan = angle->start();
- const SkOpSpanBase* endSpan = angle->end();
+int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) {
+ SkOpSpanBase* startSpan = angle->start();
+ SkOpSpanBase* endSpan = angle->end();
return updateWinding(startSpan, endSpan);
}
@@ -2110,41 +1653,6 @@ bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) {
return result;
}
-int SkOpSegment::windingAtT(double tHit, const SkOpSpan* span, bool crossOpp,
- SkScalar* dx) const {
- if (approximately_zero(tHit - span->t())) { // if we hit the end of a span, disregard
- return SK_MinS32;
- }
- int winding = crossOpp ? span->oppSum() : span->windSum();
- SkASSERT(winding != SK_MinS32);
- int windVal = crossOpp ? span->oppValue() : span->windValue();
-#if DEBUG_WINDING_AT_T
- SkDebugf("%s id=%d opp=%d tHit=%1.9g t=%1.9g oldWinding=%d windValue=%d", __FUNCTION__,
- debugID(), crossOpp, tHit, span->t(), winding, windVal);
-#endif
- // see if a + change in T results in a +/- change in X (compute x'(T))
- *dx = (*CurveSlopeAtT[fVerb])(fPts, fWeight, tHit).fX;
- if (fVerb > SkPath::kLine_Verb && approximately_zero(*dx)) {
- *dx = fPts[2].fX - fPts[1].fX - *dx;
- }
- if (*dx == 0) {
-#if DEBUG_WINDING_AT_T
- SkDebugf(" dx=0 winding=SK_MinS32\n");
-#endif
- return SK_MinS32;
- }
- if (windVal < 0) { // reverse sign if opp contour traveled in reverse
- *dx = -*dx;
- }
- if (winding * *dx > 0) { // if same signs, result is negative
- winding += *dx > 0 ? -windVal : windVal;
- }
-#if DEBUG_WINDING_AT_T
- SkDebugf(" dx=%c winding=%d\n", *dx > 0 ? '+' : '-', winding);
-#endif
- return winding;
-}
-
int SkOpSegment::windSum(const SkOpAngle* angle) const {
const SkOpSpan* minSpan = angle->start()->starter(angle->end());
return minSpan->windSum();
diff --git a/src/pathops/SkOpSegment.h b/src/pathops/SkOpSegment.h
index a762a66a5a..13b99c6f46 100644
--- a/src/pathops/SkOpSegment.h
+++ b/src/pathops/SkOpSegment.h
@@ -17,6 +17,8 @@
struct SkDCurve;
class SkOpCoincidence;
class SkOpContour;
+enum class SkOpRayDir;
+struct SkOpRayHit;
class SkPathWriter;
class SkOpSegment {
@@ -41,8 +43,6 @@ public:
bool activeOp(int xorMiMask, int xorSuMask, SkOpSpanBase* start, SkOpSpanBase* end, SkPathOp op,
int* sumMiWinding, int* sumSuWinding);
- SkDPoint activeLeftTop(SkOpSpanBase** firstT);
-
bool activeWinding(SkOpSpanBase* start, SkOpSpanBase* end);
bool activeWinding(SkOpSpanBase* start, SkOpSpanBase* end, int* sumWinding);
@@ -79,9 +79,6 @@ public:
}
SkOpPtT* addMissing(double t, SkOpSegment* opp, SkChunkAlloc* );
- SkOpAngle* addSingletonAngleDown(SkOpSegment** otherPtr, SkOpAngle** , SkChunkAlloc* );
- SkOpAngle* addSingletonAngles(int step, SkChunkAlloc* );
- SkOpAngle* addSingletonAngleUp(SkOpSegment** otherPtr, SkOpAngle** , SkChunkAlloc* );
SkOpAngle* addStartSpan(SkChunkAlloc* allocator) {
SkOpAngle* angle = SkOpTAllocator<SkOpAngle>::Allocate(allocator);
@@ -101,7 +98,6 @@ public:
SkOpPtT* addT(double t, AllowAlias , SkChunkAlloc* );
void align();
- static bool BetweenTs(const SkOpSpanBase* lesser, double testT, const SkOpSpanBase* greater);
const SkPathOpsBounds& bounds() const {
return fBounds;
@@ -114,10 +110,9 @@ public:
void calcAngles(SkChunkAlloc*);
void checkAngleCoin(SkOpCoincidence* coincidences, SkChunkAlloc* allocator);
void checkNearCoincidence(SkOpAngle* );
- bool clockwise(const SkOpSpanBase* start, const SkOpSpanBase* end, bool* swap) const;
static void ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
SkOpAngle::IncludeType );
- static void ComputeOneSumReverse(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
+ static void ComputeOneSumReverse(SkOpAngle* baseAngle, SkOpAngle* nextAngle,
SkOpAngle::IncludeType );
int computeSum(SkOpSpanBase* start, SkOpSpanBase* end, SkOpAngle::IncludeType includeType);
@@ -129,9 +124,6 @@ public:
return fCount;
}
- SkOpSpan* crossedSpanY(const SkPoint& basePt, double mid, bool opp, bool current,
- SkScalar* bestY, double* hitT, bool* hitSomething, bool* vertical);
-
void debugAddAngle(double startT, double endT, SkChunkAlloc*);
const SkOpAngle* debugAngle(int id) const;
SkOpContour* debugContour(int id);
@@ -140,10 +132,6 @@ public:
return SkDEBUGRELEASE(fID, -1);
}
-#if DEBUG_SWAP_TOP
- int debugInflections(const SkOpSpanBase* start, const SkOpSpanBase* end) const;
-#endif
-
SkOpAngle* debugLastAngle();
const SkOpPtT* debugPtT(int id) const;
void debugReset();
@@ -184,6 +172,7 @@ public:
void dumpAngles() const;
void dumpCoin() const;
void dumpPts() const;
+ void dumpPtsInner() const;
SkOpSegment* findNextOp(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** nextStart,
SkOpSpanBase** nextEnd, bool* unsortable, SkPathOp op,
@@ -191,8 +180,7 @@ public:
SkOpSegment* findNextWinding(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** nextStart,
SkOpSpanBase** nextEnd, bool* unsortable);
SkOpSegment* findNextXor(SkOpSpanBase** nextStart, SkOpSpanBase** nextEnd, bool* unsortable);
- SkOpSegment* findTop(bool firstPass, SkOpSpanBase** startPtr, SkOpSpanBase** endPtr,
- bool* unsortable, SkChunkAlloc* );
+ SkOpSpan* findSortableTop(SkOpContour* );
SkOpGlobalState* globalState() const;
const SkOpSpan* head() const {
@@ -204,10 +192,6 @@ public:
}
void init(SkPoint pts[], SkScalar weight, SkOpContour* parent, SkPath::Verb verb);
- void initWinding(SkOpSpanBase* start, SkOpSpanBase* end,
- SkOpAngle::IncludeType angleIncludeType);
- bool initWinding(SkOpSpanBase* start, SkOpSpanBase* end, double tHit, int winding,
- SkScalar hitDx, int oppWind, SkScalar hitOppDx);
SkOpSpan* insert(SkOpSpan* prev, SkChunkAlloc* allocator) {
SkOpSpan* result = SkOpTAllocator<SkOpSpan>::Allocate(allocator);
@@ -259,7 +243,6 @@ public:
bool markWinding(SkOpSpan* , int winding, int oppWinding);
bool match(const SkOpPtT* span, const SkOpSegment* parent, double t, const SkPoint& pt) const;
void missingCoincidence(SkOpCoincidence* coincidences, SkChunkAlloc* allocator);
- bool monotonicInY(const SkOpSpanBase* start, const SkOpSpanBase* end) const;
void moveMultiples();
void moveNearby();
@@ -267,7 +250,6 @@ public:
return fNext;
}
- static bool NextCandidate(SkOpSpanBase* span, SkOpSpanBase** start, SkOpSpanBase** end);
SkOpSegment* nextChase(SkOpSpanBase** , int* step, SkOpSpan** , SkOpSpanBase** last) const;
bool operand() const;
@@ -301,6 +283,9 @@ public:
bool ptsDisjoint(double t1, const SkPoint& pt1, double t2, const SkPoint& pt2) const;
+ void rayCheck(const SkOpRayHit& base, SkOpRayDir dir, SkOpRayHit** hits,
+ SkChunkAlloc* allocator);
+
void resetVisited() {
fVisited = false;
}
@@ -353,8 +338,6 @@ public:
bool subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end, SkDCurve* result) const;
bool subDivide(const SkOpSpanBase* start, const SkOpSpanBase* end, SkOpCurve* result) const;
- void subDivideBounds(const SkOpSpanBase* start, const SkOpSpanBase* end,
- SkPathOpsBounds* bounds) const;
const SkOpSpanBase* tail() const {
return &fTail;
@@ -364,19 +347,13 @@ public:
return &fTail;
}
- static double TAtMid(const SkOpSpanBase* start, const SkOpSpanBase* end, double mid) {
- return start->t() * (1 - mid) + end->t() * mid;
- }
-
- SkDPoint top(const SkOpSpanBase* start, const SkOpSpanBase* end, double* topT) const;
-
void undoneSpan(SkOpSpanBase** start, SkOpSpanBase** end);
int updateOppWinding(const SkOpSpanBase* start, const SkOpSpanBase* end) const;
int updateOppWinding(const SkOpAngle* angle) const;
int updateOppWindingReverse(const SkOpAngle* angle) const;
- int updateWinding(const SkOpSpanBase* start, const SkOpSpanBase* end) const;
- int updateWinding(const SkOpAngle* angle) const;
- int updateWindingReverse(const SkOpAngle* angle) const;
+ int updateWinding(SkOpSpanBase* start, SkOpSpanBase* end);
+ int updateWinding(SkOpAngle* angle);
+ int updateWindingReverse(const SkOpAngle* angle);
static bool UseInnerWinding(int outerWinding, int innerWinding);
@@ -388,7 +365,7 @@ public:
return fWeight;
}
- int windingAtT(double tHit, const SkOpSpan* span, bool crossOpp, SkScalar* dx) const;
+ SkOpSpan* windingSpanAtT(double tHit);
int windSum(const SkOpAngle* angle) const;
SkPoint* writablePt(bool end) {
@@ -408,6 +385,7 @@ private:
int fDoneCount; // number of processed spans (zero initially)
SkPath::Verb fVerb;
SkDCubic::CubicType fCubicType;
+ bool fTopsFound;
bool fVisited; // used by missing coincidence check
SkDEBUGCODE(int fID);
};
diff --git a/src/pathops/SkOpSpan.cpp b/src/pathops/SkOpSpan.cpp
index b75a692f74..9c9e07f985 100755
--- a/src/pathops/SkOpSpan.cpp
+++ b/src/pathops/SkOpSpan.cpp
@@ -86,65 +86,6 @@ SkOpSegment* SkOpPtT::segment() {
return span()->segment();
}
-// find the starting or ending span with an existing loop of angles
-// OPTIMIZE? remove the spans pointing to windValue==0 here or earlier?
-// FIXME? assert that only one other span has a valid windValue or oppValue
-bool SkOpSpanBase::addSimpleAngle(bool checkFrom, SkChunkAlloc* allocator) {
- SkOpAngle* angle;
- if (checkFrom) {
- if (!this->final()) {
- return false;
- }
- if (this->fromAngle()) {
- SkASSERT(this->fromAngle()->loopCount() == 2);
- return true;
- }
- angle = this->segment()->addEndSpan(allocator);
- } else {
- SkASSERT(this->t() == 0);
- SkOpSpan* span = this->upCast();
- if (span->toAngle()) {
- SkASSERT(span->toAngle()->loopCount() == 2);
- SkASSERT(!span->fromAngle());
- span->setFromAngle(span->toAngle()->next());
- return true;
- }
- angle = this->segment()->addStartSpan(allocator);
- }
- SkOpPtT* ptT = this->ptT();
- SkOpSpanBase* oSpanBase;
- SkOpSpan* oSpan;
- SkOpSegment* other;
- do {
- ptT = ptT->next();
- oSpanBase = ptT->span();
- oSpan = oSpanBase->upCastable();
- other = oSpanBase->segment();
- if (oSpan && oSpan->windValue()) {
- break;
- }
- if (oSpanBase->t() == 0) {
- continue;
- }
- SkOpSpan* oFromSpan = oSpanBase->prev();
- SkASSERT(oFromSpan->t() < 1);
- if (oFromSpan->windValue()) {
- break;
- }
- } while (ptT != this->ptT());
- SkOpAngle* oAngle;
- if (checkFrom) {
- oAngle = other->addStartSpan(allocator);
- SkASSERT(oSpan && !oSpan->final());
- SkASSERT(oAngle == oSpan->toAngle());
- } else {
- oAngle = other->addEndSpan(allocator);
- SkASSERT(oAngle == oSpanBase->fromAngle());
- }
- angle->insert(oAngle);
- return true;
-}
-
void SkOpSpanBase::align() {
if (this->fAligned) {
return;
@@ -308,11 +249,6 @@ tryNextRemainder:
fSpanAdds += span->fSpanAdds;
}
-void SkOpSpan::applyCoincidence(SkOpSpan* opp) {
- SkASSERT(!final());
- SkASSERT(0); // incomplete
-}
-
bool SkOpSpan::containsCoincidence(const SkOpSegment* segment) const {
SkASSERT(this->segment() != segment);
const SkOpSpan* next = fCoincident;
@@ -345,6 +281,7 @@ void SkOpSpan::init(SkOpSegment* segment, SkOpSpan* prev, double t, const SkPoin
fWindSum = fOppSum = SK_MinS32;
fWindValue = 1;
fOppValue = 0;
+ fTopTTry = 0;
fChased = fDone = false;
segment->bumpCount();
}
@@ -358,3 +295,13 @@ void SkOpSpan::setOppSum(int oppSum) {
SkASSERT(!DEBUG_LIMIT_WIND_SUM || abs(oppSum) <= DEBUG_LIMIT_WIND_SUM);
fOppSum = oppSum;
}
+
+void SkOpSpan::setWindSum(int windSum) {
+ SkASSERT(!final());
+ if (fWindSum != SK_MinS32 && fWindSum != windSum) {
+ this->globalState()->setWindingFailed();
+ return;
+ }
+ SkASSERT(!DEBUG_LIMIT_WIND_SUM || abs(windSum) <= DEBUG_LIMIT_WIND_SUM);
+ fWindSum = windSum;
+}
diff --git a/src/pathops/SkOpSpan.h b/src/pathops/SkOpSpan.h
index ee2f332440..1d535d2635 100644
--- a/src/pathops/SkOpSpan.h
+++ b/src/pathops/SkOpSpan.h
@@ -124,7 +124,6 @@ protected:
class SkOpSpanBase {
public:
- bool addSimpleAngle(bool checkFrom , SkChunkAlloc* );
void align();
bool aligned() const {
@@ -333,8 +332,6 @@ protected: // no direct access to internals to avoid treating a span base as a
class SkOpSpan : public SkOpSpanBase {
public:
- void applyCoincidence(SkOpSpan* opp);
-
bool clearCoincident() {
SkASSERT(!final());
if (fCoincident == this) {
@@ -432,12 +429,7 @@ public:
fToAngle = angle;
}
- void setWindSum(int windSum) {
- SkASSERT(!final());
- SkASSERT(fWindSum == SK_MinS32 || fWindSum == windSum);
- SkASSERT(!DEBUG_LIMIT_WIND_SUM || abs(windSum) <= DEBUG_LIMIT_WIND_SUM);
- fWindSum = windSum;
- }
+ void setWindSum(int windSum);
void setWindValue(int windValue) {
SkASSERT(!final());
@@ -446,6 +438,8 @@ public:
fWindValue = windValue;
}
+ bool sortableTop(SkOpContour* );
+
SkOpAngle* toAngle() const {
SkASSERT(!final());
return fToAngle;
@@ -469,6 +463,7 @@ private: // no direct access to internals to avoid treating a span base as a sp
int fOppSum; // for binary operators: the opposite winding sum
int fWindValue; // 0 == canceled; 1 == normal; >1 == coincident
int fOppValue; // normally 0 -- when binary coincident edges combine, opp value goes here
+ int fTopTTry; // specifies direction and t value to try next
bool fDone; // if set, this span to next higher T has been processed
};
diff --git a/src/pathops/SkPathOpsBounds.h b/src/pathops/SkPathOpsBounds.h
index 7b9daa3671..b99f36f5d9 100644
--- a/src/pathops/SkPathOpsBounds.h
+++ b/src/pathops/SkPathOpsBounds.h
@@ -47,19 +47,6 @@ struct SkPathOpsBounds : public SkRect {
&& AlmostLessOrEqualUlps(pt.fY, fBottom);
}
- // unlike isEmpty(), this permits lines, but not points
- // FIXME: unused for now
- bool isReallyEmpty() const {
- // use !<= instead of > to detect NaN values
- return !(fLeft <= fRight) || !(fTop <= fBottom)
- || (fLeft == fRight && fTop == fBottom);
- }
-
- void setPointBounds(const SkDPoint& pt) {
- fLeft = fRight = SkDoubleToScalar(pt.fX);
- fTop = fBottom = SkDoubleToScalar(pt.fY);
- }
-
typedef SkRect INHERITED;
};
diff --git a/src/pathops/SkPathOpsCommon.cpp b/src/pathops/SkPathOpsCommon.cpp
index 05b370a1df..734b5f0819 100644
--- a/src/pathops/SkPathOpsCommon.cpp
+++ b/src/pathops/SkPathOpsCommon.cpp
@@ -11,106 +11,16 @@
#include "SkPathWriter.h"
#include "SkTSort.h"
-static int contourRangeCheckY(const SkTDArray<SkOpContour* >& contourList,
- SkOpSegment** currentPtr, SkOpSpanBase** startPtr, SkOpSpanBase** endPtr,
- double* bestHit, SkScalar* bestDx, bool* tryAgain, double* midPtr, bool opp) {
- SkOpSpanBase* start = *startPtr;
- SkOpSpanBase* end = *endPtr;
- const double mid = *midPtr;
- const SkOpSegment* current = *currentPtr;
- double tAtMid = SkOpSegment::TAtMid(start, end, mid);
- SkPoint basePt = current->ptAtT(tAtMid);
- int contourCount = contourList.count();
- SkScalar bestY = SK_ScalarMin;
- SkOpSegment* bestSeg = NULL;
- SkOpSpan* bestTSpan = NULL;
- bool bestOpp;
- bool hitSomething = false;
- for (int cTest = 0; cTest < contourCount; ++cTest) {
- SkOpContour* contour = contourList[cTest];
- bool testOpp = contour->operand() ^ current->operand() ^ opp;
- if (basePt.fY < contour->bounds().fTop) {
- continue;
- }
- if (bestY > contour->bounds().fBottom) {
- continue;
- }
- SkOpSegment* testSeg = contour->first();
- SkASSERT(testSeg);
- do {
- SkScalar testY = bestY;
- double testHit;
- bool vertical;
- SkOpSpan* testTSpan = testSeg->crossedSpanY(basePt, tAtMid, testOpp,
- testSeg == current, &testY, &testHit, &hitSomething, &vertical);
- if (!testTSpan) {
- if (vertical) {
- hitSomething = true;
- bestSeg = NULL;
- goto abortContours; // vertical encountered, return and try different point
- }
- continue;
- }
- if (testSeg == current && SkOpSegment::BetweenTs(start, testHit, end)) {
- double baseT = start->t();
- double endT = end->t();
- double newMid = (testHit - baseT) / (endT - baseT);
-#if DEBUG_WINDING
- double midT = SkOpSegment::TAtMid(start, end, mid);
- SkPoint midXY = current->ptAtT(midT);
- double newMidT = SkOpSegment::TAtMid(start, end, newMid);
- SkPoint newXY = current->ptAtT(newMidT);
- 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, start->pt().fX, start->pt().fY,
- baseT + mid * (endT - baseT), midXY.fX, midXY.fY,
- baseT + newMid * (endT - baseT), newXY.fX, newXY.fY,
- endT, end->pt().fX, end->pt().fY);
-#endif
- *midPtr = newMid * 2; // calling loop with divide by 2 before continuing
- return SK_MinS32;
- }
- bestSeg = testSeg;
- *bestHit = testHit;
- bestOpp = testOpp;
- bestTSpan = testTSpan;
- bestY = testY;
- } while ((testSeg = testSeg->next()));
- }
-abortContours:
- int result;
- if (!bestSeg) {
- result = hitSomething ? SK_MinS32 : 0;
- } else {
- if (bestTSpan->windSum() == SK_MinS32) {
- *currentPtr = bestSeg;
- *startPtr = bestTSpan;
- *endPtr = bestTSpan->next();
- SkASSERT(*startPtr != *endPtr && *startPtr && *endPtr);
- *tryAgain = true;
- return 0;
- }
- result = bestSeg->windingAtT(*bestHit, bestTSpan, bestOpp, bestDx);
- SkASSERT(result == SK_MinS32 || *bestDx);
- }
- double baseT = (*startPtr)->t();
- double endT = (*endPtr)->t();
- *bestHit = baseT + mid * (endT - baseT);
- return result;
-}
-
-SkOpSegment* FindUndone(SkTDArray<SkOpContour* >& contourList, SkOpSpanBase** startPtr,
+SkOpSegment* FindUndone(SkOpContourHead* contourList, SkOpSpanBase** startPtr,
SkOpSpanBase** endPtr) {
- int contourCount = contourList.count();
SkOpSegment* result;
- for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
- SkOpContour* contour = contourList[cIndex];
+ SkOpContour* contour = contourList;
+ do {
result = contour->undoneSegment(startPtr, endPtr);
if (result) {
return result;
}
- }
+ } while ((contour = contour->next()));
return NULL;
}
@@ -196,234 +106,41 @@ SkOpSegment* FindChase(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** startPtr,
}
#if DEBUG_ACTIVE_SPANS
-void DebugShowActiveSpans(SkTDArray<SkOpContour* >& contourList) {
- int index;
- for (index = 0; index < contourList.count(); ++ index) {
- contourList[index]->debugShowActiveSpans();
- }
-}
-#endif
-
-static SkOpSegment* findTopSegment(const SkTDArray<SkOpContour* >& contourList,
- bool firstPass, SkOpSpanBase** start, SkOpSpanBase** end, SkDPoint* topLeft,
- bool* unsortable, bool* done, SkChunkAlloc* allocator) {
- SkOpSegment* result;
- const SkOpSegment* lastTopStart = NULL;
- SkOpSpanBase* lastStart = NULL, * lastEnd = NULL;
- do {
- SkDPoint bestXY = {SK_ScalarMax, SK_ScalarMax};
- int contourCount = contourList.count();
- SkOpSegment* topStart = NULL;
- *done = true;
- for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
- SkOpContour* contour = contourList[cIndex];
- if (contour->done()) {
- continue;
- }
- const SkPathOpsBounds& bounds = contour->bounds();
- if (bounds.fBottom < topLeft->fY) {
- *done = false;
- continue;
- }
- if (bounds.fBottom == topLeft->fY && bounds.fRight < topLeft->fX) {
- *done = false;
- continue;
- }
- contour->topSortableSegment(*topLeft, &bestXY, &topStart);
- if (!contour->done()) {
- *done = false;
- }
- }
- if (!topStart) {
- return NULL;
- }
- *topLeft = bestXY;
- result = topStart->findTop(firstPass, start, end, unsortable, allocator);
- if (!result) {
- if (lastTopStart == topStart && lastStart == *start && lastEnd == *end) {
- *done = true;
- return NULL;
- }
- lastTopStart = topStart;
- lastStart = *start;
- lastEnd = *end;
- }
- } while (!result);
- return result;
-}
-
-static int rightAngleWinding(const SkTDArray<SkOpContour* >& contourList,
- SkOpSegment** currentPtr, SkOpSpanBase** start, SkOpSpanBase** end, double* tHit,
- SkScalar* hitDx, bool* tryAgain, bool* onlyVertical, bool opp) {
- double test = 0.9;
- int contourWinding;
+void DebugShowActiveSpans(SkOpContourHead* contourList) {
+ SkOpContour* contour = contourList;
do {
- contourWinding = contourRangeCheckY(contourList, currentPtr, start, end,
- tHit, hitDx, tryAgain, &test, opp);
- if (contourWinding != SK_MinS32 || *tryAgain) {
- return contourWinding;
- }
- if (*currentPtr && (*currentPtr)->isVertical()) {
- *onlyVertical = true;
- return contourWinding;
- }
- test /= 2;
- } while (!approximately_negative(test));
- SkASSERT(0); // FIXME: incomplete functionality
- return contourWinding;
-}
-
-static void skipVertical(const SkTDArray<SkOpContour* >& contourList,
- SkOpSegment** current, SkOpSpanBase** start, SkOpSpanBase** end) {
- if (!(*current)->isVertical(*start, *end)) {
- return;
- }
- int contourCount = contourList.count();
- for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
- SkOpContour* contour = contourList[cIndex];
- if (contour->done()) {
- continue;
- }
- SkOpSegment* nonVertical = contour->nonVerticalSegment(start, end);
- if (nonVertical) {
- *current = nonVertical;
- return;
- }
- }
- return;
+ contour->debugShowActiveSpans();
+ } while ((contour = contour->next()));
}
-
-struct SortableTop2 { // error if local in pre-C++11
- SkOpSpanBase* fStart;
- SkOpSpanBase* fEnd;
-};
-
-SkOpSegment* FindSortableTop(const SkTDArray<SkOpContour* >& contourList, bool firstPass,
- SkOpAngle::IncludeType angleIncludeType, bool* firstContour, SkOpSpanBase** startPtr,
- SkOpSpanBase** endPtr, SkDPoint* topLeft, bool* unsortable, bool* done, bool* onlyVertical,
- SkChunkAlloc* allocator) {
- SkOpSegment* current = findTopSegment(contourList, firstPass, startPtr, endPtr, topLeft,
- unsortable, done, allocator);
- if (!current) {
- return NULL;
- }
- SkOpSpanBase* start = *startPtr;
- SkOpSpanBase* end = *endPtr;
- SkASSERT(current == start->segment());
- if (*firstContour) {
- current->initWinding(start, end, angleIncludeType);
- *firstContour = false;
- return current;
- }
- SkOpSpan* minSpan = start->starter(end);
- int sumWinding = minSpan->windSum();
- if (sumWinding == SK_MinS32) {
- SkOpSpanBase* iSpan = end;
- SkOpSpanBase* oSpan = start;
- do {
- bool checkFrom = oSpan->t() < iSpan->t();
- if ((checkFrom ? iSpan->fromAngle() : iSpan->upCast()->toAngle()) == NULL) {
- if (!iSpan->addSimpleAngle(checkFrom, allocator)) {
- *unsortable = true;
- return NULL;
- }
- }
- sumWinding = current->computeSum(oSpan, iSpan, angleIncludeType);
- SkTSwap(iSpan, oSpan);
- } while (sumWinding == SK_MinS32 && iSpan == start);
- }
- if (sumWinding != SK_MinS32 && sumWinding != SK_NaN32) {
- return current;
- }
- int contourWinding;
- int oppContourWinding = 0;
- // 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
- bool tryAgain;
- double tHit;
- SkScalar hitDx = 0;
- SkScalar hitOppDx = 0;
- // keep track of subsequent returns to detect infinite loops
- SkTDArray<SortableTop2> sortableTops;
- do {
- // if current is vertical, find another candidate which is not
- // if only remaining candidates are vertical, then they can be marked done
- SkASSERT(*startPtr != *endPtr && *startPtr && *endPtr);
- SkASSERT(current == (*startPtr)->segment());
- skipVertical(contourList, &current, startPtr, endPtr);
- SkASSERT(current); // FIXME: if null, all remaining are vertical
- SkASSERT(*startPtr != *endPtr && *startPtr && *endPtr);
- SkASSERT(current == (*startPtr)->segment());
- tryAgain = false;
- contourWinding = rightAngleWinding(contourList, &current, startPtr, endPtr, &tHit,
- &hitDx, &tryAgain, onlyVertical, false);
- SkASSERT(current == (*startPtr)->segment());
- if (tryAgain) {
- bool giveUp = false;
- int count = sortableTops.count();
- for (int index = 0; index < count; ++index) {
- const SortableTop2& prev = sortableTops[index];
- if (giveUp) {
- prev.fStart->segment()->markDone(prev.fStart->starter(prev.fEnd));
- } else if (prev.fStart == *startPtr || prev.fEnd == *endPtr) {
- // remaining edges are non-vertical and cannot have their winding computed
- // mark them as done and return, and hope that assembly can fill the holes
- giveUp = true;
- index = -1;
- }
- }
- if (giveUp) {
- *done = true;
- return NULL;
- }
- }
- SortableTop2* sortableTop = sortableTops.append();
- sortableTop->fStart = *startPtr;
- sortableTop->fEnd = *endPtr;
-#if DEBUG_SORT
- SkDebugf("%s current=%d index=%d endIndex=%d tHit=%1.9g hitDx=%1.9g try=%d vert=%d\n",
- __FUNCTION__, current->debugID(), (*startPtr)->debugID(), (*endPtr)->debugID(),
- tHit, hitDx, tryAgain, *onlyVertical);
#endif
- if (*onlyVertical) {
- return current;
- }
- if (tryAgain) {
- continue;
- }
- if (angleIncludeType < SkOpAngle::kBinarySingle) {
- break;
- }
- oppContourWinding = rightAngleWinding(contourList, &current, startPtr, endPtr, &tHit,
- &hitOppDx, &tryAgain, NULL, true);
- SkASSERT(current == (*startPtr)->segment());
- } while (tryAgain);
- bool success = current->initWinding(*startPtr, *endPtr, tHit, contourWinding, hitDx,
- oppContourWinding, hitOppDx);
- if (current->done()) {
- return NULL;
- } else if (!success) { // check if the span has a valid winding
- SkOpSpan* minSpan = (*startPtr)->t() < (*endPtr)->t() ? (*startPtr)->upCast()
- : (*endPtr)->upCast();
- if (minSpan->windSum() == SK_MinS32) {
- return NULL;
- }
- }
- return current;
-}
-void MakeContourList(SkOpContour* contour, SkTDArray<SkOpContour* >& list,
- bool evenOdd, bool oppEvenOdd) {
+bool SortContourList(SkOpContourHead** contourList, bool evenOdd, bool oppEvenOdd) {
+ SkTDArray<SkOpContour* > list;
+ SkOpContour* contour = *contourList;
do {
if (contour->count()) {
contour->setOppXor(contour->operand() ? evenOdd : oppEvenOdd);
*list.append() = contour;
}
} while ((contour = contour->next()));
- if (list.count() < 2) {
- return;
+ int count = list.count();
+ if (!count) {
+ return false;
+ }
+ if (count > 1) {
+ SkTQSort<SkOpContour>(list.begin(), list.end() - 1);
}
- SkTQSort<SkOpContour>(list.begin(), list.end() - 1);
+ contour = list[0];
+ SkOpContourHead* contourHead = static_cast<SkOpContourHead*>(contour);
+ contour->globalState()->setContourHead(contourHead);
+ *contourList = contourHead;
+ for (int index = 1; index < count; ++index) {
+ SkOpContour* next = list[index];
+ contour->setNext(next);
+ contour = next;
+ }
+ contour->setNext(NULL);
+ return true;
}
class DistanceLessThan {
@@ -444,8 +161,8 @@ public:
*/
void Assemble(const SkPathWriter& path, SkPathWriter* simple) {
SkChunkAlloc allocator(4096); // FIXME: constant-ize, tune
- SkOpContour contour;
- SkOpGlobalState globalState(NULL SkDEBUGPARAMS(&contour));
+ SkOpContourHead contour;
+ SkOpGlobalState globalState(NULL, &contour);
#if DEBUG_SHOW_TEST_NAME
SkDebugf("</div>\n");
#endif
@@ -634,65 +351,52 @@ void Assemble(const SkPathWriter& path, SkPathWriter* simple) {
#endif
}
-static void align(SkTDArray<SkOpContour* >* contourList) {
- int contourCount = (*contourList).count();
- for (int cTest = 0; cTest < contourCount; ++cTest) {
- SkOpContour* contour = (*contourList)[cTest];
+static void align(SkOpContourHead* contourList) {
+ SkOpContour* contour = contourList;
+ do {
contour->align();
- }
+ } while ((contour = contour->next()));
}
-static void calcAngles(SkTDArray<SkOpContour* >* contourList, SkChunkAlloc* allocator) {
- int contourCount = (*contourList).count();
- for (int cTest = 0; cTest < contourCount; ++cTest) {
- SkOpContour* contour = (*contourList)[cTest];
+static void calcAngles(SkOpContourHead* contourList, SkChunkAlloc* allocator) {
+ SkOpContour* contour = contourList;
+ do {
contour->calcAngles(allocator);
- }
+ } while ((contour = contour->next()));
}
-static void missingCoincidence(SkTDArray<SkOpContour* >* contourList,
+static void missingCoincidence(SkOpContourHead* contourList,
SkOpCoincidence* coincidence, SkChunkAlloc* allocator) {
- int contourCount = (*contourList).count();
- for (int cTest = 0; cTest < contourCount; ++cTest) {
- SkOpContour* contour = (*contourList)[cTest];
+ SkOpContour* contour = contourList;
+ do {
contour->missingCoincidence(coincidence, allocator);
- }
+ } while ((contour = contour->next()));
}
-static void moveMultiples(SkTDArray<SkOpContour* >* contourList) {
- int contourCount = (*contourList).count();
- for (int cTest = 0; cTest < contourCount; ++cTest) {
- SkOpContour* contour = (*contourList)[cTest];
+static void moveMultiples(SkOpContourHead* contourList) {
+ SkOpContour* contour = contourList;
+ do {
contour->moveMultiples();
- }
+ } while ((contour = contour->next()));
}
-static void moveNearby(SkTDArray<SkOpContour* >* contourList) {
- int contourCount = (*contourList).count();
- for (int cTest = 0; cTest < contourCount; ++cTest) {
- SkOpContour* contour = (*contourList)[cTest];
+static void moveNearby(SkOpContourHead* contourList) {
+ SkOpContour* contour = contourList;
+ do {
contour->moveNearby();
- }
+ } while ((contour = contour->next()));
}
-static void sortAngles(SkTDArray<SkOpContour* >* contourList) {
- int contourCount = (*contourList).count();
- for (int cTest = 0; cTest < contourCount; ++cTest) {
- SkOpContour* contour = (*contourList)[cTest];
+static void sortAngles(SkOpContourHead* contourList) {
+ SkOpContour* contour = contourList;
+ do {
contour->sortAngles();
- }
-}
-
-static void sortSegments(SkTDArray<SkOpContour* >* contourList) {
- int contourCount = (*contourList).count();
- for (int cTest = 0; cTest < contourCount; ++cTest) {
- SkOpContour* contour = (*contourList)[cTest];
- contour->sortSegments();
- }
+ } while ((contour = contour->next()));
}
-bool HandleCoincidence(SkTDArray<SkOpContour* >* contourList, SkOpCoincidence* coincidence,
- SkChunkAlloc* allocator, SkOpGlobalState* globalState) {
+bool HandleCoincidence(SkOpContourHead* contourList, SkOpCoincidence* coincidence,
+ SkChunkAlloc* allocator) {
+ SkOpGlobalState* globalState = contourList->globalState();
// combine t values when multiple intersections occur on some segments but not others
moveMultiples(contourList);
// move t values and points together to eliminate small/tiny gaps
@@ -711,7 +415,6 @@ bool HandleCoincidence(SkTDArray<SkOpContour* >* contourList, SkOpCoincidence* c
if (!coincidence->apply()) { // adjust the winding value to account for coincident edges
return false;
}
- sortSegments(contourList);
calcAngles(contourList, allocator);
sortAngles(contourList);
if (globalState->angleCoincidence()) {
@@ -721,7 +424,8 @@ bool HandleCoincidence(SkTDArray<SkOpContour* >* contourList, SkOpCoincidence* c
}
}
#if DEBUG_ACTIVE_SPANS
- DebugShowActiveSpans(*contourList);
+ coincidence->debugShowCoincidence();
+ DebugShowActiveSpans(contourList);
#endif
return true;
}
diff --git a/src/pathops/SkPathOpsCommon.h b/src/pathops/SkPathOpsCommon.h
index 82eb5da215..25faf8223e 100644
--- a/src/pathops/SkPathOpsCommon.h
+++ b/src/pathops/SkPathOpsCommon.h
@@ -17,19 +17,14 @@ class SkPathWriter;
void Assemble(const SkPathWriter& path, SkPathWriter* simple);
SkOpSegment* FindChase(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** startPtr,
SkOpSpanBase** endPtr);
-SkOpSegment* FindSortableTop(const SkTDArray<SkOpContour*>& , bool firstPass,
- SkOpAngle::IncludeType , bool* firstContour, SkOpSpanBase** index,
- SkOpSpanBase** endIndex, SkDPoint* topLeft, bool* unsortable,
- bool* done, bool* onlyVertical, SkChunkAlloc* );
-SkOpSegment* FindUndone(SkTDArray<SkOpContour*>& contourList, SkOpSpanBase** startPtr,
+SkOpSpan* FindSortableTop(SkOpContourHead* );
+SkOpSegment* FindUndone(SkOpContourHead* , SkOpSpanBase** startPtr,
SkOpSpanBase** endPtr);
-void MakeContourList(SkOpContour* , SkTDArray<SkOpContour*>& list,
- bool evenOdd, bool oppEvenOdd);
-bool HandleCoincidence(SkTDArray<SkOpContour*>* , SkOpCoincidence* , SkChunkAlloc* ,
- SkOpGlobalState* );
-
+bool SortContourList(SkOpContourHead** , bool evenOdd, bool oppEvenOdd);
+bool HandleCoincidence(SkOpContourHead* , SkOpCoincidence* , SkChunkAlloc* );
+bool OpDebug(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result, bool expectSuccess);
#if DEBUG_ACTIVE_SPANS
-void DebugShowActiveSpans(SkTDArray<SkOpContour*>& contourList);
+void DebugShowActiveSpans(SkOpContourHead* );
#endif
#endif
diff --git a/src/pathops/SkPathOpsCubic.cpp b/src/pathops/SkPathOpsCubic.cpp
index 777298b297..972c510643 100644
--- a/src/pathops/SkPathOpsCubic.cpp
+++ b/src/pathops/SkPathOpsCubic.cpp
@@ -16,6 +16,15 @@
const int SkDCubic::gPrecisionUnit = 256; // FIXME: test different values in test framework
+void SkDCubic::align(int endIndex, int ctrlIndex, SkDPoint* dstPt) const {
+ if (fPts[endIndex].fX == fPts[ctrlIndex].fX) {
+ dstPt->fX = fPts[endIndex].fX;
+ }
+ if (fPts[endIndex].fY == fPts[ctrlIndex].fY) {
+ dstPt->fY = fPts[endIndex].fY;
+ }
+}
+
// give up when changing t no longer moves point
// also, copy point rather than recompute it when it does change
double SkDCubic::binarySearch(double min, double max, double axisIntercept,
@@ -75,45 +84,45 @@ double SkDCubic::calcPrecision() const {
return (width > height ? width : height) / gPrecisionUnit;
}
-bool SkDCubic::clockwise(const SkDCubic& whole, bool* swap) const {
- SkDPoint lastPt = fPts[kPointLast];
- SkDPoint firstPt = fPts[0];
- double sum = 0;
- // pick the control point furthest from the line connecting the end points
- SkLineParameters lineParameters;
- lineParameters.cubicEndPoints(*this, 0, 3);
- lineParameters.normalize();
- double tiniest = SkTMin(SkTMin(SkTMin(SkTMin(SkTMin(SkTMin(SkTMin(fPts[0].fX, fPts[0].fY),
- fPts[1].fX), fPts[1].fY), fPts[2].fX), fPts[2].fY), fPts[3].fX), fPts[3].fY);
- double largest = SkTMax(SkTMax(SkTMax(SkTMax(SkTMax(SkTMax(SkTMax(fPts[0].fX, fPts[0].fY),
- fPts[1].fX), fPts[1].fY), fPts[2].fX), fPts[2].fY), fPts[3].fX), fPts[3].fY);
- largest = SkTMax(largest, -tiniest);
- double pt1dist = lineParameters.controlPtDistance(*this, 1);
- double pt2dist = lineParameters.controlPtDistance(*this, 2);
-#if DEBUG_SWAP_TOP
- SkDebugf("%s pt1dist=%1.9g pt2dist=%1.9g\n", __FUNCTION__, pt1dist, pt2dist);
-#endif
- int furthest;
- if (!approximately_zero_when_compared_to(pt1dist, largest)
- && !approximately_zero_when_compared_to(pt2dist, largest) && pt1dist * pt2dist < 0) {
- furthest = 2;
- } else {
- furthest = fabs(pt1dist) < fabs(pt2dist) ? 2 : 1;
- }
- for (int idx = 1; idx <= 3; ++idx) {
- sum += (firstPt.fX - lastPt.fX) * (firstPt.fY + lastPt.fY);
- lastPt = firstPt;
- firstPt = idx == 1 ? fPts[furthest] : fPts[kPointLast];
- }
- *swap = sum > 0 && !this->monotonicInY() && !whole.monotonicInY();
- return sum <= 0;
+
+/* classic one t subdivision */
+static void interp_cubic_coords(const double* src, double* dst, double t) {
+ double ab = SkDInterp(src[0], src[2], t);
+ double bc = SkDInterp(src[2], src[4], t);
+ double cd = SkDInterp(src[4], src[6], t);
+ double abc = SkDInterp(ab, bc, t);
+ double bcd = SkDInterp(bc, cd, t);
+ double abcd = SkDInterp(abc, bcd, t);
+
+ dst[0] = src[0];
+ dst[2] = ab;
+ dst[4] = abc;
+ dst[6] = abcd;
+ dst[8] = bcd;
+ dst[10] = cd;
+ dst[12] = src[6];
}
-bool SkDCubic::Clockwise(const SkPoint* pts, double startT, double endT, bool* swap) {
- SkDCubic cubic;
- cubic.set(pts);
- SkDCubic part = cubic.subDivide(startT, endT);
- return part.clockwise(cubic, swap);
+SkDCubicPair SkDCubic::chopAt(double t) const {
+ SkDCubicPair dst;
+ if (t == 0.5) {
+ dst.pts[0] = fPts[0];
+ dst.pts[1].fX = (fPts[0].fX + fPts[1].fX) / 2;
+ dst.pts[1].fY = (fPts[0].fY + fPts[1].fY) / 2;
+ dst.pts[2].fX = (fPts[0].fX + 2 * fPts[1].fX + fPts[2].fX) / 4;
+ dst.pts[2].fY = (fPts[0].fY + 2 * fPts[1].fY + fPts[2].fY) / 4;
+ dst.pts[3].fX = (fPts[0].fX + 3 * (fPts[1].fX + fPts[2].fX) + fPts[3].fX) / 8;
+ dst.pts[3].fY = (fPts[0].fY + 3 * (fPts[1].fY + fPts[2].fY) + fPts[3].fY) / 8;
+ dst.pts[4].fX = (fPts[1].fX + 2 * fPts[2].fX + fPts[3].fX) / 4;
+ dst.pts[4].fY = (fPts[1].fY + 2 * fPts[2].fY + fPts[3].fY) / 4;
+ dst.pts[5].fX = (fPts[2].fX + fPts[3].fX) / 2;
+ dst.pts[5].fY = (fPts[2].fY + fPts[3].fY) / 2;
+ dst.pts[6] = fPts[3];
+ return dst;
+ }
+ interp_cubic_coords(&fPts[0].fX, &dst.pts[0].fX, t);
+ interp_cubic_coords(&fPts[0].fY, &dst.pts[0].fY, t);
+ return dst;
}
void SkDCubic::Coefficients(const double* src, double* A, double* B, double* C, double* D) {
@@ -636,15 +645,6 @@ SkDCubic SkDCubic::subDivide(double t1, double t2) const {
return dst;
}
-void SkDCubic::align(int endIndex, int ctrlIndex, SkDPoint* dstPt) const {
- if (fPts[endIndex].fX == fPts[ctrlIndex].fX) {
- dstPt->fX = fPts[endIndex].fX;
- }
- if (fPts[endIndex].fY == fPts[ctrlIndex].fY) {
- dstPt->fY = fPts[endIndex].fY;
- }
-}
-
void SkDCubic::subDivide(const SkDPoint& a, const SkDPoint& d,
double t1, double t2, SkDPoint dst[2]) const {
SkASSERT(t1 != t2);
@@ -672,42 +672,17 @@ void SkDCubic::subDivide(const SkDPoint& a, const SkDPoint& d,
}
}
-/* classic one t subdivision */
-static void interp_cubic_coords(const double* src, double* dst, double t) {
- double ab = SkDInterp(src[0], src[2], t);
- double bc = SkDInterp(src[2], src[4], t);
- double cd = SkDInterp(src[4], src[6], t);
- double abc = SkDInterp(ab, bc, t);
- double bcd = SkDInterp(bc, cd, t);
- double abcd = SkDInterp(abc, bcd, t);
-
- dst[0] = src[0];
- dst[2] = ab;
- dst[4] = abc;
- dst[6] = abcd;
- dst[8] = bcd;
- dst[10] = cd;
- dst[12] = src[6];
-}
-
-SkDCubicPair SkDCubic::chopAt(double t) const {
- SkDCubicPair dst;
- if (t == 0.5) {
- dst.pts[0] = fPts[0];
- dst.pts[1].fX = (fPts[0].fX + fPts[1].fX) / 2;
- dst.pts[1].fY = (fPts[0].fY + fPts[1].fY) / 2;
- dst.pts[2].fX = (fPts[0].fX + 2 * fPts[1].fX + fPts[2].fX) / 4;
- dst.pts[2].fY = (fPts[0].fY + 2 * fPts[1].fY + fPts[2].fY) / 4;
- dst.pts[3].fX = (fPts[0].fX + 3 * (fPts[1].fX + fPts[2].fX) + fPts[3].fX) / 8;
- dst.pts[3].fY = (fPts[0].fY + 3 * (fPts[1].fY + fPts[2].fY) + fPts[3].fY) / 8;
- dst.pts[4].fX = (fPts[1].fX + 2 * fPts[2].fX + fPts[3].fX) / 4;
- dst.pts[4].fY = (fPts[1].fY + 2 * fPts[2].fY + fPts[3].fY) / 4;
- dst.pts[5].fX = (fPts[2].fX + fPts[3].fX) / 2;
- dst.pts[5].fY = (fPts[2].fY + fPts[3].fY) / 2;
- dst.pts[6] = fPts[3];
- return dst;
+double SkDCubic::top(const SkDCubic& dCurve, double startT, double endT, SkDPoint*topPt) const {
+ double extremeTs[2];
+ double topT = -1;
+ int roots = SkDCubic::FindExtrema(&fPts[0].fY, extremeTs);
+ for (int index = 0; index < roots; ++index) {
+ double t = startT + (endT - startT) * extremeTs[index];
+ SkDPoint mid = dCurve.ptAtT(t);
+ if (topPt->fY > mid.fY || (topPt->fY == mid.fY && topPt->fX > mid.fX)) {
+ topT = t;
+ *topPt = mid;
+ }
}
- interp_cubic_coords(&fPts[0].fX, &dst.pts[0].fX, t);
- interp_cubic_coords(&fPts[0].fY, &dst.pts[0].fY, t);
- return dst;
+ return topT;
}
diff --git a/src/pathops/SkPathOpsCubic.h b/src/pathops/SkPathOpsCubic.h
index 3d68151852..7a57e94ef6 100644
--- a/src/pathops/SkPathOpsCubic.h
+++ b/src/pathops/SkPathOpsCubic.h
@@ -57,8 +57,6 @@ struct SkDCubic {
double binarySearch(double min, double max, double axisIntercept, SearchAxis xAxis) const;
double calcPrecision() const;
SkDCubicPair chopAt(double t) const;
- bool clockwise(const SkDCubic& whole, bool* swap) const;
- static bool Clockwise(const SkPoint* pts, double startT, double endT, bool* swap);
static void Coefficients(const double* cubic, double* A, double* B, double* C, double* D);
static bool ComplexBreak(const SkPoint pts[4], SkScalar* t, CubicType* cubicType);
int convexHull(char order[kPointCount]) const;
@@ -77,8 +75,7 @@ struct SkDCubic {
static int FindInflections(const SkPoint a[kPointCount], double tValues[2]) {
SkDCubic cubic;
- cubic.set(a);
- return cubic.findInflections(tValues);
+ return cubic.set(a).findInflections(tValues);
}
int findMaxCurvature(double tValues[]) const;
@@ -120,8 +117,7 @@ struct SkDCubic {
static SkDCubic SubDivide(const SkPoint a[kPointCount], double t1, double t2) {
SkDCubic cubic;
- cubic.set(a);
- return cubic.subDivide(t1, t2);
+ return cubic.set(a).subDivide(t1, t2);
}
void subDivide(const SkDPoint& a, const SkDPoint& d, double t1, double t2, SkDPoint p[2]) const;
@@ -129,10 +125,10 @@ struct SkDCubic {
static void SubDivide(const SkPoint pts[kPointCount], const SkDPoint& a, const SkDPoint& d, double t1,
double t2, SkDPoint p[2]) {
SkDCubic cubic;
- cubic.set(pts);
- cubic.subDivide(a, d, t1, t2, p);
+ cubic.set(pts).subDivide(a, d, t1, t2, p);
}
+ double top(const SkDCubic& dCurve, double startT, double endT, SkDPoint*topPt) const;
SkDQuad toQuad() const;
static const int gPrecisionUnit;
diff --git a/src/pathops/SkPathOpsCurve.cpp b/src/pathops/SkPathOpsCurve.cpp
index 651e64a908..bf44d25e17 100644
--- a/src/pathops/SkPathOpsCurve.cpp
+++ b/src/pathops/SkPathOpsCurve.cpp
@@ -8,98 +8,6 @@
#include "SkPathOpsRect.h"
#include "SkPathOpsCurve.h"
-SkDPoint SkDCurve::conicTop(const SkPoint curve[3], SkScalar curveWeight,
- double startT, double endT, double* topT) {
- SkDPoint topPt = fConic[0];
- *topT = startT;
- if (topPt.fY > fConic[2].fY || (topPt.fY == fConic[2].fY && topPt.fX > fConic[2].fX)) {
- *topT = endT;
- topPt = fConic[2];
- }
- if (!fConic.monotonicInY()) {
- double extremeT;
- if (SkDConic::FindExtrema(&fConic.fPts.fPts[0].fY, fConic.fWeight, &extremeT)) {
- SkDConic dCurve;
- dCurve.set(curve, curveWeight);
- extremeT = startT + (endT - startT) * extremeT;
- SkDPoint test = dCurve.ptAtT(extremeT);
- if (topPt.fY > test.fY || (topPt.fY == test.fY && topPt.fX > test.fX)) {
- *topT = extremeT;
- topPt = test;
- }
- }
- }
- return topPt;
-}
-
-SkDPoint SkDCurve::cubicTop(const SkPoint curve[4], SkScalar ,
- double startT, double endT, double* topT) {
- SkDPoint topPt = fCubic[0];
- *topT = startT;
- if (topPt.fY > fCubic[3].fY || (topPt.fY == fCubic[3].fY && topPt.fX > fCubic[3].fX)) {
- *topT = endT;
- topPt = fCubic[3];
- }
- double extremeTs[2];
- if (!fCubic.monotonicInY()) {
- int roots = SkDCubic::FindExtrema(&fCubic.fPts[0].fY, extremeTs);
- SkDCubic dCurve;
- dCurve.set(curve);
- for (int index = 0; index < roots; ++index) {
- double t = startT + (endT - startT) * extremeTs[index];
- SkDPoint mid = dCurve.ptAtT(t);
- if (topPt.fY > mid.fY || (topPt.fY == mid.fY && topPt.fX > mid.fX)) {
- *topT = t;
- topPt = mid;
- }
- }
- }
- return topPt;
-}
-
-SkDPoint SkDCurve::lineTop(const SkPoint[2], SkScalar , double startT, double endT, double* topT) {
- SkDPoint topPt = fLine[0];
- *topT = startT;
- if (topPt.fY > fLine[1].fY || (topPt.fY == fLine[1].fY && topPt.fX > fLine[1].fX)) {
- *topT = endT;
- topPt = fLine[1];
- }
- return topPt;
-}
-
-SkDPoint SkDCurve::quadTop(const SkPoint curve[3], SkScalar ,
- double startT, double endT, double* topT) {
- SkDPoint topPt = fQuad[0];
- *topT = startT;
- if (topPt.fY > fQuad[2].fY || (topPt.fY == fQuad[2].fY && topPt.fX > fQuad[2].fX)) {
- *topT = endT;
- topPt = fQuad[2];
- }
- if (!fQuad.monotonicInY()) {
- double extremeT;
- if (SkDQuad::FindExtrema(&fQuad.fPts[0].fY, &extremeT)) {
- SkDQuad dCurve;
- dCurve.set(curve);
- extremeT = startT + (endT - startT) * extremeT;
- SkDPoint test = dCurve.ptAtT(extremeT);
- if (topPt.fY > test.fY || (topPt.fY == test.fY && topPt.fX > test.fX)) {
- *topT = extremeT;
- topPt = test;
- }
- }
- }
- return topPt;
-}
-
-SkDPoint (SkDCurve::* const Top[])(const SkPoint curve[], SkScalar curveWeight,
- double tStart, double tEnd, double* topT) = {
- NULL,
- &SkDCurve::lineTop,
- &SkDCurve::quadTop,
- &SkDCurve::conicTop,
- &SkDCurve::cubicTop
-};
-
void SkDCurve::setConicBounds(const SkPoint curve[3], SkScalar curveWeight,
double tStart, double tEnd, SkPathOpsBounds* bounds) {
SkDConic dCurve;
@@ -120,12 +28,6 @@ void SkDCurve::setCubicBounds(const SkPoint curve[4], SkScalar ,
SkDoubleToScalar(dRect.fRight), SkDoubleToScalar(dRect.fBottom));
}
-void SkDCurve::setLineBounds(const SkPoint[2], SkScalar ,
- double , double , SkPathOpsBounds* bounds) {
- bounds->setPointBounds(fLine[0]);
- bounds->add(fLine[1]);
-}
-
void SkDCurve::setQuadBounds(const SkPoint curve[3], SkScalar ,
double tStart, double tEnd, SkPathOpsBounds* bounds) {
SkDQuad dCurve;
@@ -135,12 +37,3 @@ void SkDCurve::setQuadBounds(const SkPoint curve[3], SkScalar ,
bounds->set(SkDoubleToScalar(dRect.fLeft), SkDoubleToScalar(dRect.fTop),
SkDoubleToScalar(dRect.fRight), SkDoubleToScalar(dRect.fBottom));
}
-
-void (SkDCurve::* const SetBounds[])(const SkPoint curve[], SkScalar curveWeight,
- double tStart, double tEnd, SkPathOpsBounds* bounds) = {
- NULL,
- &SkDCurve::setLineBounds,
- &SkDCurve::setQuadBounds,
- &SkDCurve::setConicBounds,
- &SkDCurve::setCubicBounds
-};
diff --git a/src/pathops/SkPathOpsCurve.h b/src/pathops/SkPathOpsCurve.h
index bfbc515719..c830e66d4d 100644
--- a/src/pathops/SkPathOpsCurve.h
+++ b/src/pathops/SkPathOpsCurve.h
@@ -8,9 +8,6 @@
#define SkPathOpsCurve_DEFINE
#include "SkIntersections.h"
-#include "SkPathOpsCubic.h"
-#include "SkPathOpsLine.h"
-#include "SkPathOpsQuad.h"
#ifndef SK_RELEASE
#include "SkPath.h"
@@ -78,15 +75,11 @@ struct SkDCurve {
double s, double e, SkPathOpsBounds* );
void setCubicBounds(const SkPoint curve[4], SkScalar ,
double s, double e, SkPathOpsBounds* );
- void setLineBounds(const SkPoint[2], SkScalar , double , double , SkPathOpsBounds* );
void setQuadBounds(const SkPoint curve[3], SkScalar ,
double s, double e, SkPathOpsBounds*);
};
-extern void (SkDCurve::* const SetBounds[])(const SkPoint curve[], SkScalar cWeight,
- double tStart, double tEnd, SkPathOpsBounds* );
-
extern SkDPoint (SkDCurve::* const Top[])(const SkPoint curve[], SkScalar cWeight,
double tStart, double tEnd, double* topT);
@@ -276,4 +269,59 @@ static void (* const CurveIntersectRay[])(const SkPoint[] , SkScalar , const SkD
cubic_intersect_ray
};
+static int line_intercept_h(const SkPoint a[2], SkScalar , SkScalar y, double* roots) {
+ SkDLine line;
+ roots[0] = SkIntersections::HorizontalIntercept(line.set(a), y);
+ return between(0, roots[0], 1);
+}
+
+static int line_intercept_v(const SkPoint a[2], SkScalar , SkScalar x, double* roots) {
+ SkDLine line;
+ roots[0] = SkIntersections::VerticalIntercept(line.set(a), x);
+ return between(0, roots[0], 1);
+}
+
+static int quad_intercept_h(const SkPoint a[2], SkScalar , SkScalar y, double* roots) {
+ SkDQuad quad;
+ return SkIntersections::HorizontalIntercept(quad.set(a), y, roots);
+}
+
+static int quad_intercept_v(const SkPoint a[2], SkScalar , SkScalar x, double* roots) {
+ SkDQuad quad;
+ return SkIntersections::VerticalIntercept(quad.set(a), x, roots);
+}
+
+static int conic_intercept_h(const SkPoint a[2], SkScalar w, SkScalar y, double* roots) {
+ SkDConic conic;
+ return SkIntersections::HorizontalIntercept(conic.set(a, w), y, roots);
+}
+
+static int conic_intercept_v(const SkPoint a[2], SkScalar w, SkScalar x, double* roots) {
+ SkDConic conic;
+ return SkIntersections::VerticalIntercept(conic.set(a, w), x, roots);
+}
+
+static int cubic_intercept_h(const SkPoint a[3], SkScalar , SkScalar y, double* roots) {
+ SkDCubic cubic;
+ return cubic.set(a).horizontalIntersect(y, roots);
+}
+
+static int cubic_intercept_v(const SkPoint a[3], SkScalar , SkScalar x, double* roots) {
+ SkDCubic cubic;
+ return cubic.set(a).verticalIntersect(x, roots);
+}
+
+static int (* const CurveIntercept[])(const SkPoint[] , SkScalar , SkScalar , double* ) = {
+ NULL,
+ NULL,
+ line_intercept_h,
+ line_intercept_v,
+ quad_intercept_h,
+ quad_intercept_v,
+ conic_intercept_h,
+ conic_intercept_v,
+ cubic_intercept_h,
+ cubic_intercept_v,
+};
+
#endif
diff --git a/src/pathops/SkPathOpsDebug.cpp b/src/pathops/SkPathOpsDebug.cpp
index a9f8fe6acc..2903e08984 100644
--- a/src/pathops/SkPathOpsDebug.cpp
+++ b/src/pathops/SkPathOpsDebug.cpp
@@ -14,6 +14,15 @@
extern bool FLAGS_runFail;
#endif
+#if DEBUG_SORT
+int SkPathOpsDebug::gSortCountDefault = SK_MaxS32;
+int SkPathOpsDebug::gSortCount;
+#endif
+
+#if DEBUG_ACTIVE_OP
+const char* SkPathOpsDebug::kPathOpStr[] = {"diff", "sect", "union", "xor"};
+#endif
+
#if defined SK_DEBUG || !FORCE_RELEASE
const char* SkPathOpsDebug::kLVerbStr[] = {"", "line", "quad", "cubic"};
@@ -23,15 +32,6 @@ int SkPathOpsDebug::gContourID = 0;
int SkPathOpsDebug::gSegmentID = 0;
#endif
-#if DEBUG_SORT || DEBUG_SWAP_TOP
-int SkPathOpsDebug::gSortCountDefault = SK_MaxS32;
-int SkPathOpsDebug::gSortCount;
-#endif
-
-#if DEBUG_ACTIVE_OP
-const char* SkPathOpsDebug::kPathOpStr[] = {"diff", "sect", "union", "xor"};
-#endif
-
bool SkPathOpsDebug::ChaseContains(const SkTDArray<SkOpSpanBase* >& chaseArray,
const SkOpSpanBase* span) {
for (int index = 0; index < chaseArray.count(); ++index) {
@@ -135,20 +135,25 @@ void SkPathOpsDebug::ShowPath(const SkPath& a, const SkPath& b, SkPathOp shapeOp
show_op(shapeOp, "path", "pathB");
}
+#include "SkPathOpsCubic.h"
+#include "SkPathOpsQuad.h"
+
+SkDCubic SkDQuad::debugToCubic() const {
+ SkDCubic cubic;
+ cubic[0] = fPts[0];
+ cubic[2] = fPts[1];
+ cubic[3] = fPts[2];
+ cubic[1].fX = (cubic[0].fX + cubic[2].fX * 2) / 3;
+ cubic[1].fY = (cubic[0].fY + cubic[2].fY * 2) / 3;
+ cubic[2].fX = (cubic[3].fX + cubic[2].fX * 2) / 3;
+ cubic[2].fY = (cubic[3].fY + cubic[2].fY * 2) / 3;
+ return cubic;
+}
+
#include "SkOpAngle.h"
+#include "SkOpCoincidence.h"
#include "SkOpSegment.h"
-#if DEBUG_SWAP_TOP
-int SkOpSegment::debugInflections(const SkOpSpanBase* start, const SkOpSpanBase* end) const {
- if (fVerb != SkPath::kCubic_Verb) {
- return false;
- }
- SkDCubic dst = SkDCubic::SubDivide(fPts, start->t(), end->t());
- double inflections[2];
- return dst.findInflections(inflections);
-}
-#endif
-
SkOpAngle* SkOpSegment::debugLastAngle() {
SkOpAngle* result = NULL;
SkOpSpan* span = this->head();
@@ -195,13 +200,20 @@ void SkOpSegment::debugShowActiveSpans() const {
const SkOpPtT* ptT = span->ptT();
SkDebugf(") t=%1.9g (%1.9g,%1.9g)", ptT->fT, ptT->fPt.fX, ptT->fPt.fY);
SkDebugf(" tEnd=%1.9g", span->next()->t());
- SkDebugf(" windSum=");
if (span->windSum() == SK_MinS32) {
- SkDebugf("?");
+ SkDebugf(" windSum=?");
} else {
- SkDebugf("%d", span->windSum());
+ SkDebugf(" windSum=%d", span->windSum());
+ }
+ if (span->oppValue() && span->oppSum() == SK_MinS32) {
+ SkDebugf(" oppSum=?");
+ } else if (span->oppValue() || span->oppSum() != SK_MinS32) {
+ SkDebugf(" oppSum=%d", span->oppSum());
+ }
+ SkDebugf(" windValue=%d", span->windValue());
+ if (span->oppValue() || span->oppSum() != SK_MinS32) {
+ SkDebugf(" oppValue=%d", span->oppValue());
}
- SkDebugf(" windValue=%d oppValue=%d", span->windValue(), span->oppValue());
SkDebugf("\n");
} while ((span = span->next()->upCastable()));
}
@@ -297,7 +309,7 @@ SkString SkOpAngle::debugPart() const {
}
#endif
-#if DEBUG_SORT || DEBUG_SWAP_TOP
+#if DEBUG_SORT
void SkOpAngle::debugLoop() const {
const SkOpAngle* first = this;
const SkOpAngle* next = this;
@@ -339,14 +351,14 @@ void SkOpAngle::debugValidate() const {
bool useXor = op ? oppXor : isXor;
SkASSERT(lastXor == -1 || lastXor == (int) useXor);
lastXor = (int) useXor;
- wind += next->sign() * (op ? minSpan->oppValue() : minSpan->windValue());
+ wind += next->debugSign() * (op ? minSpan->oppValue() : minSpan->windValue());
if (useXor) {
wind &= 1;
}
useXor = op ? isXor : oppXor;
SkASSERT(lastOppXor == -1 || lastOppXor == (int) useXor);
lastOppXor = (int) useXor;
- opp += next->sign() * (op ? minSpan->windValue() : minSpan->oppValue());
+ opp += next->debugSign() * (op ? minSpan->windValue() : minSpan->oppValue());
if (useXor) {
opp &= 1;
}
@@ -377,6 +389,19 @@ void SkOpAngle::debugValidateNext() const {
#endif
}
+void SkOpCoincidence::debugShowCoincidence() const {
+ SkCoincidentSpans* span = fHead;
+ while (span) {
+ SkDebugf("%s - id=%d t=%1.9g tEnd=%1.9g\n", __FUNCTION__,
+ span->fCoinPtTStart->segment()->debugID(),
+ span->fCoinPtTStart->fT, span->fCoinPtTEnd->fT);
+ SkDebugf("%s + id=%d t=%1.9g tEnd=%1.9g\n", __FUNCTION__,
+ span->fOppPtTStart->segment()->debugID(),
+ span->fOppPtTStart->fT, span->fOppPtTEnd->fT);
+ span = span->fNext;
+ }
+}
+
void SkOpSegment::debugValidate() const {
#if DEBUG_VALIDATE
const SkOpSpanBase* span = &fHead;
@@ -474,6 +499,28 @@ bool SkOpSpan::debugCoinLoopCheck() const {
return true;
}
+// called only by test code
+int SkIntersections::debugCoincidentUsed() const {
+ if (!fIsCoincident[0]) {
+ SkASSERT(!fIsCoincident[1]);
+ return 0;
+ }
+ int count = 0;
+ SkDEBUGCODE(int count2 = 0;)
+ for (int index = 0; index < fUsed; ++index) {
+ if (fIsCoincident[0] & (1 << index)) {
+ ++count;
+ }
+#ifdef SK_DEBUG
+ if (fIsCoincident[1] & (1 << index)) {
+ ++count2;
+ }
+#endif
+ }
+ SkASSERT(count == count2);
+ return count;
+}
+
#include "SkOpContour.h"
int SkOpPtT::debugLoopLimit(bool report) const {
diff --git a/src/pathops/SkPathOpsDebug.h b/src/pathops/SkPathOpsDebug.h
index 0624ad687a..61c2ecab53 100644
--- a/src/pathops/SkPathOpsDebug.h
+++ b/src/pathops/SkPathOpsDebug.h
@@ -45,15 +45,14 @@
#define DEBUG_ASSEMBLE 0
#define DEBUG_CUBIC_BINARY_SEARCH 0
#define DEBUG_CUBIC_SPLIT 0
-#define DEBUG_DUMP_SEGMENTS 0 // 1
+#define DEBUG_DUMP_SEGMENTS 0
#define DEBUG_FLOW 0
#define DEBUG_LIMIT_WIND_SUM 0
#define DEBUG_MARK_DONE 0
#define DEBUG_PATH_CONSTRUCTION 0
#define DEBUG_PERP 0
-#define DEBUG_SHOW_TEST_NAME 0 // 1
+#define DEBUG_SHOW_TEST_NAME 0
#define DEBUG_SORT 0
-#define DEBUG_SWAP_TOP 0 // 1
#define DEBUG_T_SECT 0
#define DEBUG_T_SECT_DUMP 0
#define DEBUG_VALIDATE 0
@@ -78,7 +77,6 @@
#define DEBUG_PERP 1
#define DEBUG_SHOW_TEST_NAME 1
#define DEBUG_SORT 1
-#define DEBUG_SWAP_TOP 1
#define DEBUG_T_SECT 0
#define DEBUG_T_SECT_DUMP 0
#define DEBUG_VALIDATE 1
@@ -133,8 +131,6 @@
#include "SkTLS.h"
#endif
-#include "SkTDArray.h"
-
class SkPathOpsDebug {
public:
static const char* kLVerbStr[];
@@ -144,7 +140,7 @@ public:
static int gSegmentID;
#endif
-#if DEBUG_SORT || DEBUG_SWAP_TOP
+#if DEBUG_SORT
static int gSortCountDefault;
static int gSortCount;
#endif
@@ -200,15 +196,6 @@ public:
static const class SkOpPtT* DebugSpanPtT(const class SkOpSpanBase*, int id);
static const class SkOpSegment* DebugSpanSegment(const class SkOpSpanBase*, int id);
static const class SkOpSpanBase* DebugSpanSpan(const class SkOpSpanBase*, int id);
-
- static void DumpContours(SkTDArray<class SkOpContour* >* contours);
- static void DumpContoursAll(SkTDArray<class SkOpContour* >* contours);
- static void DumpContoursAngles(const SkTDArray<class SkOpContour* >* contours);
- static void DumpContoursPt(const SkTDArray<class SkOpContour* >* contours, int id);
- static void DumpContoursPts(const SkTDArray<class SkOpContour* >* contours);
- static void DumpContoursSegment(const SkTDArray<class SkOpContour* >* contours, int id);
- static void DumpContoursSpan(const SkTDArray<class SkOpContour* >* contours, int id);
- static void DumpContoursSpans(const SkTDArray<class SkOpContour* >* contours);
};
struct SkDQuad;
@@ -217,19 +204,4 @@ struct SkDQuad;
void DumpQ(const SkDQuad& quad1, const SkDQuad& quad2, int testNo);
void DumpT(const SkDQuad& quad, double t);
-const struct SkOpAngle* DebugAngle(const SkTDArray<class SkOpContour* >* contours, int id);
-class SkOpContour* DebugContour(const SkTDArray<class SkOpContour* >* contours, int id);
-const class SkOpPtT* DebugPtT(const SkTDArray<class SkOpContour* >* contours, int id);
-const class SkOpSegment* DebugSegment(const SkTDArray<class SkOpContour* >* contours, int id);
-const class SkOpSpanBase* DebugSpan(const SkTDArray<class SkOpContour* >* contours, int id);
-
-void Dump(const SkTDArray<class SkOpContour* >* contours);
-void DumpAll(SkTDArray<class SkOpContour* >* contours);
-void DumpAngles(const SkTDArray<class SkOpContour* >* contours);
-void DumpCoin(const SkTDArray<class SkOpContour* >* contours);
-void DumpPt(const SkTDArray<class SkOpContour* >* contours, int segmentID);
-void DumpPts(const SkTDArray<class SkOpContour* >* contours);
-void DumpSegment(const SkTDArray<class SkOpContour* >* contours, int segmentID);
-void DumpSpan(const SkTDArray<class SkOpContour* >* contours, int spanID);
-void DumpSpans(const SkTDArray<class SkOpContour* >* contours);
#endif
diff --git a/src/pathops/SkPathOpsLine.h b/src/pathops/SkPathOpsLine.h
index ce55861522..ce502019ae 100644
--- a/src/pathops/SkPathOpsLine.h
+++ b/src/pathops/SkPathOpsLine.h
@@ -15,9 +15,10 @@ struct SkDLine {
const SkDPoint& operator[](int n) const { SkASSERT(n >= 0 && n < 2); return fPts[n]; }
SkDPoint& operator[](int n) { SkASSERT(n >= 0 && n < 2); return fPts[n]; }
- void set(const SkPoint pts[2]) {
+ const SkDLine& set(const SkPoint pts[2]) {
fPts[0] = pts[0];
fPts[1] = pts[1];
+ return *this;
}
double exactPoint(const SkDPoint& xy) const;
diff --git a/src/pathops/SkPathOpsOp.cpp b/src/pathops/SkPathOpsOp.cpp
index 1105af5d70..f9a4fa3ca6 100644
--- a/src/pathops/SkPathOpsOp.cpp
+++ b/src/pathops/SkPathOpsOp.cpp
@@ -98,41 +98,17 @@ static SkOpSegment* findChaseOp(SkTDArray<SkOpSpanBase*>& chase, SkOpSpanBase**
return NULL;
}
-static bool bridgeOp(SkTDArray<SkOpContour* >& contourList, const SkPathOp op,
+static bool bridgeOp(SkOpContourHead* contourList, const SkPathOp op,
const int xorMask, const int xorOpMask, SkPathWriter* simple, SkChunkAlloc* allocator) {
- bool firstContour = true;
bool unsortable = false;
- bool topUnsortable = false;
- bool firstPass = true;
- SkDPoint lastTopLeft;
- SkDPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
do {
- SkOpSpanBase* start = NULL;
- SkOpSpanBase* end = NULL;
- bool topDone;
- bool onlyVertical = false;
- lastTopLeft = topLeft;
- SkOpSegment* current = FindSortableTop(contourList, firstPass, SkOpAngle::kBinarySingle,
- &firstContour, &start, &end, &topLeft, &topUnsortable, &topDone, &onlyVertical,
- allocator);
- if (!current) {
- if ((!topUnsortable || firstPass) && !topDone) {
- SkASSERT(topLeft.fX != SK_ScalarMin && topLeft.fY != SK_ScalarMin);
- if (lastTopLeft.fX == SK_ScalarMin && lastTopLeft.fY == SK_ScalarMin) {
- if (firstPass) {
- firstPass = false;
- } else {
- break;
- }
- }
- topLeft.fX = topLeft.fY = SK_ScalarMin;
- continue;
- }
- break;
- } else if (onlyVertical) {
+ SkOpSpan* span = FindSortableTop(contourList);
+ if (!span) {
break;
}
- firstPass = !topUnsortable || lastTopLeft != topLeft;
+ SkOpSegment* current = span->segment();
+ SkOpSpanBase* start = span->next();
+ SkOpSpanBase* end = span;
SkTDArray<SkOpSpanBase*> chase;
do {
if (current->activeOp(start, end, xorMask, xorOpMask, op)) {
@@ -260,11 +236,13 @@ static void dump_op(const SkPath& one, const SkPath& two, SkPathOp op) {
}
#endif
-bool Op(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result) {
+bool OpDebug(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result,
+ bool expectSuccess) {
SkChunkAlloc allocator(4096); // FIXME: add a constant expression here, tune
SkOpContour contour;
+ SkOpContourHead* contourList = static_cast<SkOpContourHead*>(&contour);
SkOpCoincidence coincidence;
- SkOpGlobalState globalState(&coincidence SkDEBUGPARAMS(&contour));
+ SkOpGlobalState globalState(&coincidence, contourList);
#if DEBUGGING_PATHOPS_FROM_HOST
dump_op(one, two, op);
#endif
@@ -285,7 +263,7 @@ bool Op(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result) {
subtrahend = &one;
op = kDifference_SkPathOp;
}
-#if DEBUG_SORT || DEBUG_SWAP_TOP
+#if DEBUG_SORT
SkPathOpsDebug::gSortCount = SkPathOpsDebug::gSortCountDefault;
#endif
// turn path into list of segments
@@ -303,36 +281,24 @@ bool Op(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result) {
#endif
const int xorOpMask = builder.xorMask();
- SkTDArray<SkOpContour* > contourList;
- MakeContourList(&contour, contourList, xorMask == kEvenOdd_PathOpsMask,
- xorOpMask == kEvenOdd_PathOpsMask);
- SkOpContour** currentPtr = contourList.begin();
- if (!currentPtr) {
+ if (!SortContourList(&contourList, xorMask == kEvenOdd_PathOpsMask,
+ xorOpMask == kEvenOdd_PathOpsMask)) {
result->reset();
result->setFillType(fillType);
return true;
}
- if ((*currentPtr)->count() == 0) {
- SkASSERT((*currentPtr)->next() == NULL);
- result->reset();
- result->setFillType(fillType);
- return true;
- }
- SkOpContour** listEnd = contourList.end();
// find all intersections between segments
+ SkOpContour* current = contourList;
do {
- SkOpContour** nextPtr = currentPtr;
- SkOpContour* current = *currentPtr++;
- SkOpContour* next;
- do {
- next = *nextPtr++;
- } while (AddIntersectTs(current, next, &coincidence, &allocator) && nextPtr != listEnd);
- } while (currentPtr != listEnd);
+ SkOpContour* next = current;
+ while (AddIntersectTs(current, next, &coincidence, &allocator)
+ && (next = next->next()))
+ ;
+ } while ((current = current->next()));
#if DEBUG_VALIDATE
globalState.setPhase(SkOpGlobalState::kWalking);
#endif
- // eat through coincident edges
- if (!HandleCoincidence(&contourList, &coincidence, &allocator, &globalState)) {
+ if (!HandleCoincidence(contourList, &coincidence, &allocator)) {
return false;
}
// construct closed contours
@@ -350,3 +316,7 @@ bool Op(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result) {
}
return true;
}
+
+bool Op(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result) {
+ return OpDebug(one, two, op, result, true);
+}
diff --git a/src/pathops/SkPathOpsPoint.cpp b/src/pathops/SkPathOpsPoint.cpp
index dc9cde55a3..e0f175dac5 100644
--- a/src/pathops/SkPathOpsPoint.cpp
+++ b/src/pathops/SkPathOpsPoint.cpp
@@ -10,8 +10,3 @@ SkDVector operator-(const SkDPoint& a, const SkDPoint& b) {
SkDVector v = {a.fX - b.fX, a.fY - b.fY};
return v;
}
-
-SkDPoint operator+(const SkDPoint& a, const SkDVector& b) {
- SkDPoint v = {a.fX + b.fX, a.fY + b.fY};
- return v;
-}
diff --git a/src/pathops/SkPathOpsPoint.h b/src/pathops/SkPathOpsPoint.h
index c596b91cc0..e3f722bede 100644
--- a/src/pathops/SkPathOpsPoint.h
+++ b/src/pathops/SkPathOpsPoint.h
@@ -23,8 +23,6 @@ struct SkDVector {
fY = pt.fY;
}
- friend SkDPoint operator+(const SkDPoint& a, const SkDVector& b);
-
// only used by testing
void operator+=(const SkDVector& v) {
fX += v.fX;
@@ -208,7 +206,7 @@ struct SkDPoint {
}
static bool RoughlyEqual(const SkPoint& a, const SkPoint& b) {
- if (!RoughlyEqualUlps(a.fX, b.fX) || !RoughlyEqualUlps(a.fY, b.fY)) {
+ if (!RoughlyEqualUlps(a.fX, b.fX) && !RoughlyEqualUlps(a.fY, b.fY)) {
return false;
}
SkDPoint dA, dB;
diff --git a/src/pathops/SkPathOpsQuad.cpp b/src/pathops/SkPathOpsQuad.cpp
index 66f191bb0e..717d8bc03d 100644
--- a/src/pathops/SkPathOpsQuad.cpp
+++ b/src/pathops/SkPathOpsQuad.cpp
@@ -73,39 +73,6 @@ void SkDQuad::otherPts(int oddMan, const SkDPoint* endPt[2]) const {
}
}
-// from http://blog.gludion.com/2009/08/distance-to-quadratic-bezier-curve.html
-// (currently only used by testing)
-double SkDQuad::nearestT(const SkDPoint& pt) const {
- SkDVector pos = fPts[0] - pt;
- // search points P of bezier curve with PM.(dP / dt) = 0
- // a calculus leads to a 3d degree equation :
- SkDVector A = fPts[1] - fPts[0];
- SkDVector B = fPts[2] - fPts[1];
- B -= A;
- double a = B.dot(B);
- double b = 3 * A.dot(B);
- double c = 2 * A.dot(A) + pos.dot(B);
- double d = pos.dot(A);
- double ts[3];
- int roots = SkDCubic::RootsValidT(a, b, c, d, ts);
- double d0 = pt.distanceSquared(fPts[0]);
- double d2 = pt.distanceSquared(fPts[2]);
- double distMin = SkTMin(d0, d2);
- int bestIndex = -1;
- for (int index = 0; index < roots; ++index) {
- SkDPoint onQuad = ptAtT(ts[index]);
- double dist = pt.distanceSquared(onQuad);
- if (distMin > dist) {
- distMin = dist;
- bestIndex = index;
- }
- }
- if (bestIndex >= 0) {
- return ts[bestIndex];
- }
- return d0 < d2 ? 0 : 1;
-}
-
int SkDQuad::AddValidTs(double s[], int realRoots, double* t) {
int foundRoots = 0;
for (int index = 0; index < realRoots; ++index) {
@@ -188,25 +155,6 @@ bool SkDQuad::isLinear(int startIndex, int endIndex) const {
return approximately_zero_when_compared_to(distance, largest);
}
-SkDConic SkDQuad::toConic() const {
- SkDConic conic;
- memcpy(conic.fPts.fPts, fPts, sizeof(fPts));
- conic.fWeight = 1;
- return conic;
-}
-
-SkDCubic SkDQuad::toCubic() const {
- SkDCubic cubic;
- cubic[0] = fPts[0];
- cubic[2] = fPts[1];
- cubic[3] = fPts[2];
- cubic[1].fX = (cubic[0].fX + cubic[2].fX * 2) / 3;
- cubic[1].fY = (cubic[0].fY + cubic[2].fY * 2) / 3;
- cubic[2].fX = (cubic[3].fX + cubic[2].fX * 2) / 3;
- cubic[2].fY = (cubic[3].fY + cubic[2].fY * 2) / 3;
- return cubic;
-}
-
SkDVector SkDQuad::dxdyAtT(double t) const {
double a = t - 1;
double b = 1 - 2 * t;
@@ -346,17 +294,6 @@ SkDQuadPair SkDQuad::chopAt(double t) const
return dst;
}
-bool SkDQuad::Clockwise(const SkOpCurve& edge, bool* swap) {
- SkDQuad temp;
- double sum = (edge[0].fX - edge[kPointLast].fX) * (edge[0].fY + edge[kPointLast].fY);
- for (int idx = 0; idx < kPointLast; ++idx){
- sum += (edge[idx + 1].fX - edge[idx].fX) * (edge[idx + 1].fY + edge[idx].fY);
- }
- temp.set(edge.fPts);
- *swap = sum > 0 && !temp.monotonicInY();
- return sum <= 0;
-}
-
static int valid_unit_divide(double numer, double denom, double* ratio)
{
if (numer < 0) {
diff --git a/src/pathops/SkPathOpsQuad.h b/src/pathops/SkPathOpsQuad.h
index de4ce4baa3..01d4d64dbb 100644
--- a/src/pathops/SkPathOpsQuad.h
+++ b/src/pathops/SkPathOpsQuad.h
@@ -60,7 +60,6 @@ struct SkDQuad {
static int AddValidTs(double s[], int realRoots, double* t);
void align(int endIndex, SkDPoint* dstPt) const;
SkDQuadPair chopAt(double t) const;
- static bool Clockwise(const SkOpCurve& edge, bool* swap);
SkDVector dxdyAtT(double t) const;
static int FindExtrema(const double src[], double tValue[1]);
bool hullIntersects(const SkDQuad& , bool* isLinear) const;
@@ -69,7 +68,6 @@ struct SkDQuad {
bool isLinear(int startIndex, int endIndex) const;
bool monotonicInX() const;
bool monotonicInY() const;
- double nearestT(const SkDPoint&) const;
void otherPts(int oddMan, const SkDPoint* endPt[2]) const;
SkDPoint ptAtT(double t) const;
static int RootsReal(double A, double B, double C, double t[2]);
@@ -88,9 +86,8 @@ struct SkDQuad {
quad.set(pts);
return quad.subDivide(a, c, t1, t2);
}
- SkDConic toConic() const;
- SkDCubic toCubic() const;
+ SkDCubic debugToCubic() const;
// utilities callable by the user from the debugger when the implementation code is linked in
void dump() const;
void dumpID(int id) const;
diff --git a/src/pathops/SkPathOpsSimplify.cpp b/src/pathops/SkPathOpsSimplify.cpp
index 14c6837c1b..d37998b448 100644
--- a/src/pathops/SkPathOpsSimplify.cpp
+++ b/src/pathops/SkPathOpsSimplify.cpp
@@ -10,41 +10,17 @@
#include "SkPathOpsCommon.h"
#include "SkPathWriter.h"
-static bool bridgeWinding(SkTDArray<SkOpContour* >& contourList, SkPathWriter* simple,
+static bool bridgeWinding(SkOpContourHead* contourList, SkPathWriter* simple,
SkChunkAlloc* allocator) {
- bool firstContour = true;
bool unsortable = false;
- bool topUnsortable = false;
- bool firstPass = true;
- SkDPoint lastTopLeft;
- SkDPoint topLeft = {SK_ScalarMin, SK_ScalarMin};
do {
- SkOpSpanBase* start = NULL;
- SkOpSpanBase* end = NULL;
- bool topDone;
- bool onlyVertical = false;
- lastTopLeft = topLeft;
- SkOpSegment* current = FindSortableTop(contourList, firstPass, SkOpAngle::kUnaryWinding,
- &firstContour, &start, &end, &topLeft, &topUnsortable, &topDone, &onlyVertical,
- allocator);
- if (!current) {
- if ((!topUnsortable || firstPass) && !topDone) {
- SkASSERT(topLeft.fX != SK_ScalarMin && topLeft.fY != SK_ScalarMin);
- if (lastTopLeft.fX == SK_ScalarMin && lastTopLeft.fY == SK_ScalarMin) {
- if (firstPass) {
- firstPass = false;
- } else {
- break;
- }
- }
- topLeft.fX = topLeft.fY = SK_ScalarMin;
- continue;
- }
- break;
- } else if (onlyVertical) {
+ SkOpSpan* span = FindSortableTop(contourList);
+ if (!span) {
break;
}
- firstPass = !topUnsortable || lastTopLeft != topLeft;
+ SkOpSegment* current = span->segment();
+ SkOpSpanBase* start = span->next();
+ SkOpSpanBase* end = span;
SkTDArray<SkOpSpanBase*> chase;
do {
if (current->activeWinding(start, end)) {
@@ -93,7 +69,6 @@ static bool bridgeWinding(SkTDArray<SkOpContour* >& contourList, SkPathWriter* s
if (last && !last->chased()) {
last->setChased(true);
SkASSERT(!SkPathOpsDebug::ChaseContains(chase, last));
- // assert that last isn't already in array
*chase.append() = last;
#if DEBUG_WINDING
SkDebugf("%s chase.append id=%d", __FUNCTION__, last->segment()->debugID());
@@ -117,7 +92,7 @@ static bool bridgeWinding(SkTDArray<SkOpContour* >& contourList, SkPathWriter* s
}
// returns true if all edges were processed
-static bool bridgeXor(SkTDArray<SkOpContour* >& contourList, SkPathWriter* simple,
+static bool bridgeXor(SkOpContourHead* contourList, SkPathWriter* simple,
SkChunkAlloc* allocator) {
SkOpSegment* current;
SkOpSpanBase* start;
@@ -191,8 +166,9 @@ bool Simplify(const SkPath& path, SkPath* result) {
// turn path into list of segments
SkOpCoincidence coincidence;
SkOpContour contour;
- SkOpGlobalState globalState(&coincidence SkDEBUGPARAMS(&contour));
-#if DEBUG_SORT || DEBUG_SWAP_TOP
+ SkOpContourHead* contourList = static_cast<SkOpContourHead*>(&contour);
+ SkOpGlobalState globalState(&coincidence, contourList);
+#if DEBUG_SORT
SkPathOpsDebug::gSortCount = SkPathOpsDebug::gSortCountDefault;
#endif
SkOpEdgeBuilder builder(path, &contour, &allocator, &globalState);
@@ -202,34 +178,22 @@ bool Simplify(const SkPath& path, SkPath* result) {
#if DEBUG_DUMP_SEGMENTS
contour.dumpSegments((SkPathOp) -1);
#endif
- SkTDArray<SkOpContour* > contourList;
- MakeContourList(&contour, contourList, false, false);
- SkOpContour** currentPtr = contourList.begin();
- if (!currentPtr) {
+ if (!SortContourList(&contourList, false, false)) {
result->reset();
result->setFillType(fillType);
return true;
}
- if ((*currentPtr)->count() == 0) {
- SkASSERT((*currentPtr)->next() == NULL);
- result->reset();
- result->setFillType(fillType);
- return true;
- }
- SkOpContour** listEnd2 = contourList.end();
// find all intersections between segments
+ SkOpContour* current = contourList;
do {
- SkOpContour** nextPtr = currentPtr;
- SkOpContour* current = *currentPtr++;
- SkOpContour* next;
- do {
- next = *nextPtr++;
- } while (AddIntersectTs(current, next, &coincidence, &allocator) && nextPtr != listEnd2);
- } while (currentPtr != listEnd2);
+ SkOpContour* next = current;
+ while (AddIntersectTs(current, next, &coincidence, &allocator)
+ && (next = next->next()));
+ } while ((current = current->next()));
#if DEBUG_VALIDATE
globalState.setPhase(SkOpGlobalState::kWalking);
#endif
- if (!HandleCoincidence(&contourList, &coincidence, &allocator, &globalState)) {
+ if (!HandleCoincidence(contourList, &coincidence, &allocator)) {
return false;
}
// construct closed contours
diff --git a/src/pathops/SkPathOpsTightBounds.cpp b/src/pathops/SkPathOpsTightBounds.cpp
index 01c16732c2..f60c291710 100644
--- a/src/pathops/SkPathOpsTightBounds.cpp
+++ b/src/pathops/SkPathOpsTightBounds.cpp
@@ -10,24 +10,20 @@
bool TightBounds(const SkPath& path, SkRect* result) {
SkChunkAlloc allocator(4096); // FIXME: constant-ize, tune
SkOpContour contour;
- SkOpGlobalState globalState( NULL SkDEBUGPARAMS(&contour));
+ SkOpContourHead* contourList = static_cast<SkOpContourHead*>(&contour);
+ SkOpGlobalState globalState(NULL, contourList);
// turn path into list of segments
SkOpEdgeBuilder builder(path, &contour, &allocator, &globalState);
if (!builder.finish(&allocator)) {
return false;
}
- SkTDArray<SkOpContour* > contourList;
- MakeContourList(&contour, contourList, false, false);
- SkOpContour** currentPtr = contourList.begin();
- result->setEmpty();
- if (!currentPtr) {
+ if (!SortContourList(&contourList, false, false)) {
+ result->setEmpty();
return true;
}
- SkOpContour** listEnd = contourList.end();
- SkOpContour* current = *currentPtr++;
+ SkOpContour* current = contourList;
SkPathOpsBounds bounds = current->bounds();
- while (currentPtr != listEnd) {
- current = *currentPtr++;
+ while ((current = current->next())) {
bounds.add(current->bounds());
}
*result = bounds;
diff --git a/src/pathops/SkPathOpsTypes.h b/src/pathops/SkPathOpsTypes.h
index 15a1b4b89b..845288f609 100644
--- a/src/pathops/SkPathOpsTypes.h
+++ b/src/pathops/SkPathOpsTypes.h
@@ -24,17 +24,18 @@ enum SkPathOpsMask {
class SkOpCoincidence;
class SkOpContour;
+class SkOpContourHead;
class SkOpGlobalState {
public:
- SkOpGlobalState(SkOpCoincidence* coincidence SkDEBUGPARAMS(SkOpContour* head))
+ SkOpGlobalState(SkOpCoincidence* coincidence, SkOpContourHead* head)
: fCoincidence(coincidence)
+ , fContourHead(head)
, fWindingFailed(false)
, fAngleCoincidence(false)
#if DEBUG_VALIDATE
, fPhase(kIntersecting)
#endif
- SkDEBUGPARAMS(fHead(head))
SkDEBUGPARAMS(fAngleID(0))
SkDEBUGPARAMS(fContourID(0))
SkDEBUGPARAMS(fPtTID(0))
@@ -49,6 +50,10 @@ public:
};
#endif
+ enum {
+ kMaxWindingTries = 10
+ };
+
bool angleCoincidence() {
return fAngleCoincidence;
}
@@ -57,6 +62,10 @@ public:
return fCoincidence;
}
+ SkOpContourHead* contourHead() {
+ return fContourHead;
+ }
+
#ifdef SK_DEBUG
const struct SkOpAngle* debugAngle(int id) const;
SkOpContour* debugContour(int id);
@@ -94,6 +103,10 @@ public:
fAngleCoincidence = true;
}
+ void setContourHead(SkOpContourHead* contourHead) {
+ fContourHead = contourHead;
+ }
+
#if DEBUG_VALIDATE
void setPhase(Phase phase) {
SkASSERT(fPhase != phase);
@@ -112,13 +125,13 @@ public:
private:
SkOpCoincidence* fCoincidence;
+ SkOpContourHead* fContourHead;
bool fWindingFailed;
bool fAngleCoincidence;
#if DEBUG_VALIDATE
Phase fPhase;
#endif
#ifdef SK_DEBUG
- SkOpContour* fHead;
int fAngleID;
int fContourID;
int fPtTID;
diff --git a/src/pathops/SkPathOpsWinding.cpp b/src/pathops/SkPathOpsWinding.cpp
new file mode 100644
index 0000000000..53083e484e
--- /dev/null
+++ b/src/pathops/SkPathOpsWinding.cpp
@@ -0,0 +1,402 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// given a prospective edge, compute its initial winding by projecting a ray
+// if the ray hits another edge
+ // if the edge doesn't have a winding yet, hop up to that edge and start over
+ // concern : check for hops forming a loop
+ // if the edge is unsortable, or
+ // the intersection is nearly at the ends, or
+ // the tangent at the intersection is nearly coincident to the ray,
+ // choose a different ray and try again
+ // concern : if it is unable to succeed after N tries, try another edge? direction?
+// if no edge is hit, compute the winding directly
+
+// given the top span, project the most perpendicular ray and look for intersections
+ // let's try up and then down. What the hey
+
+// bestXY is initialized by caller with basePt
+
+#include "SkOpContour.h"
+#include "SkOpSegment.h"
+#include "SkPathOpsCurve.h"
+
+enum class SkOpRayDir {
+ kLeft,
+ kTop,
+ kRight,
+ kBottom,
+};
+
+#if DEBUG_WINDING
+const char* gDebugRayDirName[] = {
+ "kLeft",
+ "kTop",
+ "kRight",
+ "kBottom"
+};
+#endif
+
+static int xy_index(SkOpRayDir dir) {
+ return static_cast<int>(dir) & 1;
+}
+
+static SkScalar pt_xy(const SkPoint& pt, SkOpRayDir dir) {
+ return (&pt.fX)[xy_index(dir)];
+}
+
+static SkScalar pt_yx(const SkPoint& pt, SkOpRayDir dir) {
+ return (&pt.fX)[!xy_index(dir)];
+}
+
+static double pt_dxdy(const SkDVector& v, SkOpRayDir dir) {
+ return (&v.fX)[xy_index(dir)];
+}
+
+static double pt_dydx(const SkDVector& v, SkOpRayDir dir) {
+ return (&v.fX)[!xy_index(dir)];
+}
+
+static SkScalar rect_side(const SkRect& r, SkOpRayDir dir) {
+ return (&r.fLeft)[static_cast<int>(dir)];
+}
+
+static bool sideways_overlap(const SkRect& rect, const SkPoint& pt, SkOpRayDir dir) {
+ int i = !xy_index(dir);
+ return approximately_between((&rect.fLeft)[i], (&pt.fX)[i], (&rect.fRight)[i]);
+}
+
+static bool less_than(SkOpRayDir dir) {
+ return static_cast<bool>((static_cast<int>(dir) & 2) == 0);
+}
+
+static bool ccw_dxdy(const SkDVector& v, SkOpRayDir dir) {
+ bool vPartPos = pt_dydx(v, dir) > 0;
+ bool leftBottom = ((static_cast<int>(dir) + 1) & 2) != 0;
+ return vPartPos == leftBottom;
+}
+
+struct SkOpRayHit {
+ SkOpRayDir makeTestBase(SkOpSpan* span, double t) {
+ fNext = NULL;
+ fSpan = span;
+ fT = span->t() * (1 - t) + span->next()->t() * t;
+ SkOpSegment* segment = span->segment();
+ fSlope = segment->dSlopeAtT(fT);
+ fPt = segment->ptAtT(fT);
+ fValid = true;
+ return fabs(fSlope.fX) < fabs(fSlope.fY) ? SkOpRayDir::kLeft : SkOpRayDir::kTop;
+ }
+
+ SkOpRayHit* fNext;
+ SkOpSpan* fSpan;
+ SkPoint fPt;
+ double fT;
+ SkDVector fSlope;
+ bool fValid;
+};
+
+void SkOpContour::rayCheck(const SkOpRayHit& base, SkOpRayDir dir, SkOpRayHit** hits,
+ SkChunkAlloc* allocator) {
+ // if the bounds extreme is outside the best, we're done
+ SkScalar baseXY = pt_xy(base.fPt, dir);
+ SkScalar boundsXY = rect_side(fBounds, dir);
+ bool checkLessThan = less_than(dir);
+ if (!approximately_equal(baseXY, boundsXY) && (baseXY < boundsXY) == checkLessThan) {
+ return;
+ }
+ SkOpSegment* testSegment = &fHead;
+ do {
+ testSegment->rayCheck(base, dir, hits, allocator);
+ } while ((testSegment = testSegment->next()));
+}
+
+void SkOpSegment::rayCheck(const SkOpRayHit& base, SkOpRayDir dir, SkOpRayHit** hits,
+ SkChunkAlloc* allocator) {
+ if (!sideways_overlap(fBounds, base.fPt, dir)) {
+ return;
+ }
+ SkScalar baseXY = pt_xy(base.fPt, dir);
+ SkScalar boundsXY = rect_side(fBounds, dir);
+ bool checkLessThan = less_than(dir);
+ if (!approximately_equal(baseXY, boundsXY) && (baseXY < boundsXY) == checkLessThan) {
+ return;
+ }
+ double tVals[3];
+ SkScalar baseYX = pt_yx(base.fPt, dir);
+ int roots = (*CurveIntercept[fVerb * 2 + xy_index(dir)])(fPts, fWeight, baseYX, tVals);
+ for (int index = 0; index < roots; ++index) {
+ double t = tVals[index];
+ if (base.fSpan->segment() == this && approximately_equal(base.fT, t)) {
+ continue;
+ }
+ SkDVector slope;
+ SkPoint pt;
+ SkDEBUGCODE(sk_bzero(&slope, sizeof(slope)));
+ bool valid = false;
+ if (approximately_zero(t)) {
+ pt = fPts[0];
+ } else if (approximately_equal(t, 1)) {
+ pt = fPts[SkPathOpsVerbToPoints(fVerb)];
+ } else {
+ SkASSERT(between(0, t, 1));
+ pt = this->ptAtT(t);
+ if (SkDPoint::ApproximatelyEqual(pt, base.fPt)) {
+ if (base.fSpan->segment() == this) {
+ continue;
+ }
+ } else {
+ SkScalar ptXY = pt_xy(pt, dir);
+ if (!approximately_equal(baseXY, ptXY) && (baseXY < ptXY) == checkLessThan) {
+ continue;
+ }
+ slope = this->dSlopeAtT(t);
+ if (fVerb == SkPath::kCubic_Verb && base.fSpan->segment() == this
+ && roughly_equal(base.fT, t)
+ && SkDPoint::RoughlyEqual(pt, base.fPt)) {
+ #if DEBUG_WINDING
+ SkDebugf("%s (rarely expect this)\n", __FUNCTION__);
+ #endif
+ continue;
+ }
+ if (fabs(pt_dydx(slope, dir) * 10000) > fabs(pt_dxdy(slope, dir))) {
+ valid = true;
+ }
+ }
+ }
+ SkOpSpan* span = this->windingSpanAtT(t);
+ if (!span) {
+ valid = false;
+ } else if (!span->windValue() && !span->oppValue()) {
+ continue;
+ }
+ SkOpRayHit* newHit = SkOpTAllocator<SkOpRayHit>::Allocate(allocator);
+ newHit->fNext = *hits;
+ newHit->fPt = pt;
+ newHit->fSlope = slope;
+ newHit->fSpan = span;
+ newHit->fT = t;
+ newHit->fValid = valid;
+ *hits = newHit;
+ }
+}
+
+SkOpSpan* SkOpSegment::windingSpanAtT(double tHit) {
+ SkOpSpan* span = &fHead;
+ SkOpSpanBase* next;
+ do {
+ next = span->next();
+ if (approximately_equal(tHit, next->t())) {
+ return NULL;
+ }
+ if (tHit < next->t()) {
+ return span;
+ }
+ } while (!next->final() && (span = next->upCast()));
+ return NULL;
+}
+
+static bool hit_compare_x(const SkOpRayHit* a, const SkOpRayHit* b) {
+ return a->fPt.fX < b->fPt.fX;
+}
+
+static bool reverse_hit_compare_x(const SkOpRayHit* a, const SkOpRayHit* b) {
+ return b->fPt.fX < a->fPt.fX;
+}
+
+static bool hit_compare_y(const SkOpRayHit* a, const SkOpRayHit* b) {
+ return a->fPt.fY < b->fPt.fY;
+}
+
+static bool reverse_hit_compare_y(const SkOpRayHit* a, const SkOpRayHit* b) {
+ return b->fPt.fY < a->fPt.fY;
+}
+
+static double get_t_guess(int tTry, int* dirOffset) {
+ double t = 0.5;
+ *dirOffset = tTry & 1;
+ int tBase = tTry >> 1;
+ int tBits = 0;
+ while (tTry >>= 1) {
+ t /= 2;
+ ++tBits;
+ }
+ if (tBits) {
+ int tIndex = (tBase - 1) & ((1 << tBits) - 1);
+ t += t * 2 * tIndex;
+ }
+ return t;
+}
+
+bool SkOpSpan::sortableTop(SkOpContour* contourHead) {
+ SkChunkAlloc allocator(1024);
+ int dirOffset;
+ double t = get_t_guess(fTopTTry++, &dirOffset);
+ SkOpRayHit hitBase;
+ SkOpRayDir dir = hitBase.makeTestBase(this, t);
+ if (hitBase.fSlope.fX == 0 && hitBase.fSlope.fY == 0) {
+ return false;
+ }
+ SkOpRayHit* hitHead = &hitBase;
+ dir = static_cast<SkOpRayDir>(static_cast<int>(dir) + dirOffset);
+ SkOpContour* contour = contourHead;
+ do {
+ contour->rayCheck(hitBase, dir, &hitHead, &allocator);
+ } while ((contour = contour->next()));
+ // sort hits
+ SkSTArray<1, SkOpRayHit*> sorted;
+ SkOpRayHit* hit = hitHead;
+ while (hit) {
+ sorted.push_back(hit);
+ hit = hit->fNext;
+ }
+ int count = sorted.count();
+ SkTQSort(sorted.begin(), sorted.end() - 1, xy_index(dir)
+ ? less_than(dir) ? hit_compare_y : reverse_hit_compare_y
+ : less_than(dir) ? hit_compare_x : reverse_hit_compare_x);
+ // verify windings
+#if DEBUG_WINDING
+ SkDebugf("%s dir=%s seg=%d t=%1.9g pt=(%1.9g,%1.9g)\n", __FUNCTION__,
+ gDebugRayDirName[static_cast<int>(dir)], hitBase.fSpan->segment()->debugID(),
+ hitBase.fT, hitBase.fPt.fX, hitBase.fPt.fY);
+ for (int index = 0; index < count; ++index) {
+ hit = sorted[index];
+ SkOpSpan* span = hit->fSpan;
+ SkOpSegment* hitSegment = span ? span->segment() : NULL;
+ bool operand = span ? hitSegment->operand() : false;
+ bool ccw = ccw_dxdy(hit->fSlope, dir);
+ SkDebugf("%s [%d] valid=%d operand=%d span=%d ccw=%d ", __FUNCTION__, index,
+ hit->fValid, operand, span ? span->debugID() : -1, ccw);
+ if (span) {
+ hitSegment->dumpPtsInner();
+ }
+ SkDebugf(" t=%1.9g pt=(%1.9g,%1.9g) slope=(%1.9g,%1.9g)\n", hit->fT,
+ hit->fPt.fX, hit->fPt.fY, hit->fSlope.fX, hit->fSlope.fY);
+ }
+#endif
+ const SkPoint* last = NULL;
+ int wind = 0;
+ int oppWind = 0;
+ for (int index = 0; index < count; ++index) {
+ hit = sorted[index];
+ if (!hit->fValid) {
+ return false;
+ }
+ bool ccw = ccw_dxdy(hit->fSlope, dir);
+ SkASSERT(!approximately_zero(hit->fT) || !hit->fValid);
+ SkOpSpan* span = hit->fSpan;
+ SkOpSegment* hitSegment = span->segment();
+ if (!span) {
+ return false;
+ }
+ if (span->windValue() == 0 && span->oppValue() == 0) {
+ continue;
+ }
+ if (last && SkDPoint::ApproximatelyEqual(*last, hit->fPt)) {
+ return false;
+ }
+ if (index < count - 1) {
+ const SkPoint& next = sorted[index + 1]->fPt;
+ if (SkDPoint::ApproximatelyEqual(next, hit->fPt)) {
+ return false;
+ }
+ }
+ bool operand = hitSegment->operand();
+ if (operand) {
+ SkTSwap(wind, oppWind);
+ }
+ int lastWind = wind;
+ int lastOpp = oppWind;
+ int windValue = ccw ? -span->windValue() : span->windValue();
+ int oppValue = ccw ? -span->oppValue() : span->oppValue();
+ wind += windValue;
+ oppWind += oppValue;
+ bool sumSet = false;
+ int spanSum = span->windSum();
+ int windSum = SkOpSegment::UseInnerWinding(lastWind, wind) ? wind : lastWind;
+ if (spanSum == SK_MinS32) {
+ span->setWindSum(windSum);
+ sumSet = true;
+ } else {
+ // the need for this condition suggests that UseInnerWinding is flawed
+ // happened when last = 1 wind = -1
+#if 0
+ SkASSERT((hitSegment->isXor() ? (windSum & 1) == (spanSum & 1) : windSum == spanSum)
+ || (abs(wind) == abs(lastWind)
+ && (windSum ^ wind ^ lastWind) == spanSum));
+#endif
+ }
+ int oSpanSum = span->oppSum();
+ int oppSum = SkOpSegment::UseInnerWinding(lastOpp, oppWind) ? oppWind : lastOpp;
+ if (oSpanSum == SK_MinS32) {
+ span->setOppSum(oppSum);
+ } else {
+#if 0
+ SkASSERT(hitSegment->oppXor() ? (oppSum & 1) == (oSpanSum & 1) : oppSum == oSpanSum
+ || (abs(oppWind) == abs(lastOpp)
+ && (oppSum ^ oppWind ^ lastOpp) == oSpanSum));
+#endif
+ }
+ if (sumSet) {
+ (void) hitSegment->markAndChaseWinding(span, span->next(), windSum, oppSum, NULL);
+ (void) hitSegment->markAndChaseWinding(span->next(), span, windSum, oppSum, NULL);
+ }
+ if (operand) {
+ SkTSwap(wind, oppWind);
+ }
+ last = &hit->fPt;
+ }
+ return true;
+}
+
+SkOpSpan* SkOpSegment::findSortableTop(SkOpContour* contourHead) {
+ SkOpSpan* span = &fHead;
+ SkOpSpanBase* next;
+ do {
+ next = span->next();
+ if (span->done()) {
+ continue;
+ }
+ if (span->windSum() != SK_MinS32) {
+ return span;
+ }
+ if (span->sortableTop(contourHead)) {
+ return span;
+ }
+ } while (!next->final() && (span = next->upCast()));
+ return NULL;
+}
+
+SkOpSpan* SkOpContour::findSortableTop(SkOpContour* contourHead) {
+ SkOpSegment* testSegment = &fHead;
+ do {
+ if (testSegment->done()) {
+ continue;
+ }
+ SkOpSpan* result = testSegment->findSortableTop(contourHead);
+ if (result) {
+ return result;
+ }
+ } while ((testSegment = testSegment->next()));
+ return NULL;
+}
+
+SkOpSpan* FindSortableTop(SkOpContourHead* contourHead) {
+ for (int index = 0; index < SkOpGlobalState::kMaxWindingTries; ++index) {
+ SkOpContour* contour = contourHead;
+ do {
+ if (contour->done()) {
+ continue;
+ }
+ SkOpSpan* result = contour->findSortableTop(contourHead);
+ if (result) {
+ return result;
+ }
+ } while ((contour = contour->next()));
+ }
+ return NULL;
+}
diff --git a/tests/PathOpsAngleIdeas.cpp b/tests/PathOpsAngleIdeas.cpp
index d0b0858750..79e09b9865 100755
--- a/tests/PathOpsAngleIdeas.cpp
+++ b/tests/PathOpsAngleIdeas.cpp
@@ -418,8 +418,8 @@ static void testQuadAngles(skiatest::Reporter* reporter, const SkDQuad& quad1, c
int testNo, SkChunkAlloc* allocator) {
SkPoint shortQuads[2][3];
- SkOpContour contour;
- SkOpGlobalState state(NULL SkDEBUGPARAMS(&contour));
+ SkOpContourHead contour;
+ SkOpGlobalState state(NULL, &contour);
contour.init(&state, false, false);
makeSegment(&contour, quad1, shortQuads[0], allocator);
makeSegment(&contour, quad1, shortQuads[1], allocator);
diff --git a/tests/PathOpsAngleTest.cpp b/tests/PathOpsAngleTest.cpp
index 6fead61a19..9c707743cf 100644
--- a/tests/PathOpsAngleTest.cpp
+++ b/tests/PathOpsAngleTest.cpp
@@ -234,8 +234,8 @@ static const int circleDataSetSize = (int) SK_ARRAY_COUNT(circleDataSet);
DEF_TEST(PathOpsAngleCircle, reporter) {
SkChunkAlloc allocator(4096);
- SkOpContour contour;
- SkOpGlobalState state(NULL SkDEBUGPARAMS(&contour));
+ SkOpContourHead contour;
+ SkOpGlobalState state(NULL, &contour);
contour.init(&state, false, false);
for (int index = 0; index < circleDataSetSize; ++index) {
CircleData& data = circleDataSet[index];
@@ -426,8 +426,8 @@ struct FourPoints {
DEF_TEST(PathOpsAngleAfter, reporter) {
SkChunkAlloc allocator(4096);
- SkOpContour contour;
- SkOpGlobalState state(NULL SkDEBUGPARAMS(&contour));
+ SkOpContourHead contour;
+ SkOpGlobalState state(NULL, &contour);
contour.init(&state, false, false);
for (int index = intersectDataSetsSize - 1; index >= 0; --index) {
IntersectData* dataArray = intersectDataSets[index];
diff --git a/tests/PathOpsBattles.cpp b/tests/PathOpsBattles.cpp
index 40abe84523..8f59f9f48e 100644
--- a/tests/PathOpsBattles.cpp
+++ b/tests/PathOpsBattles.cpp
@@ -4831,7 +4831,7 @@ path.lineTo(SkBits2Float(0x425b4ae0), SkBits2Float(0x427944c0));
path.close();
SkPath path2(path);
- testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, FLAGS_runFail);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
}
// op end success 1
@@ -10681,7 +10681,7 @@ path.close();
testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
}
-static void (*firstTest)(skiatest::Reporter* , const char* filename) = battleOp1394;
+static void (*firstTest)(skiatest::Reporter* , const char* filename) = battleOp121;
static void (*stopTest)(skiatest::Reporter* , const char* filename) = 0;
static struct TestDesc tests[] = {
diff --git a/tests/PathOpsBoundsTest.cpp b/tests/PathOpsBoundsTest.cpp
index 0c74b69b12..573a0cecf9 100644
--- a/tests/PathOpsBoundsTest.cpp
+++ b/tests/PathOpsBoundsTest.cpp
@@ -29,24 +29,6 @@ static const SkRect noSectTests[][2] = {
static const size_t noSectTestsCount = SK_ARRAY_COUNT(noSectTests);
-static const SkRect reallyEmpty[] = {
- {0, 0, 0, 0},
- {1, 1, 1, 0},
- {1, 1, 0, 1},
- {1, 1, 0, 0},
- {1, 2, 3, SK_ScalarNaN},
-};
-
-static const size_t emptyTestsCount = SK_ARRAY_COUNT(reallyEmpty);
-
-static const SkRect notReallyEmpty[] = {
- {0, 0, 1, 0},
- {0, 0, 0, 1},
- {0, 0, 1, 1},
-};
-
-static const size_t notEmptyTestsCount = SK_ARRAY_COUNT(notReallyEmpty);
-
DEF_TEST(PathOpsBounds, reporter) {
for (size_t index = 0; index < sectTestsCount; ++index) {
const SkPathOpsBounds& bounds1 = static_cast<const SkPathOpsBounds&>(sectTests[index][0]);
@@ -75,41 +57,18 @@ DEF_TEST(PathOpsBounds, reporter) {
ordinal.set(1, 2, 3, 4);
bounds.add(ordinal);
REPORTER_ASSERT(reporter, bounds == expected);
- SkDPoint topLeft = {0, 0};
- bounds.setPointBounds(topLeft);
+ bounds.setEmpty();
SkDPoint botRight = {3, 4};
bounds.add(botRight);
REPORTER_ASSERT(reporter, bounds == expected);
- for (size_t index = 0; index < emptyTestsCount; ++index) {
- const SkPathOpsBounds& bounds = static_cast<const SkPathOpsBounds&>(reallyEmpty[index]);
- // SkASSERT(ValidBounds(bounds)); // don't check because test may contain nan
- bool empty = bounds.isReallyEmpty();
- REPORTER_ASSERT(reporter, empty);
- }
- for (size_t index = 0; index < notEmptyTestsCount; ++index) {
- const SkPathOpsBounds& bounds = static_cast<const SkPathOpsBounds&>(notReallyEmpty[index]);
- SkASSERT(ValidBounds(bounds));
- bool empty = bounds.isReallyEmpty();
- REPORTER_ASSERT(reporter, !empty);
- }
const SkPoint curvePts[] = {{0, 0}, {1, 2}, {3, 4}, {5, 6}};
SkDCurve curve;
- curve.fLine.set(curvePts);
- curve.setLineBounds(curvePts, 1, 0, 1, &bounds);
- expected.set(0, 0, 1, 2);
- REPORTER_ASSERT(reporter, bounds == expected);
- (curve.*SetBounds[SkPath::kLine_Verb])(curvePts, 1, 0, 1, &bounds);
- REPORTER_ASSERT(reporter, bounds == expected);
curve.fQuad.set(curvePts);
curve.setQuadBounds(curvePts, 1, 0, 1, &bounds);
expected.set(0, 0, 3, 4);
REPORTER_ASSERT(reporter, bounds == expected);
- (curve.*SetBounds[SkPath::kQuad_Verb])(curvePts, 1, 0, 1, &bounds);
- REPORTER_ASSERT(reporter, bounds == expected);
curve.fCubic.set(curvePts);
curve.setCubicBounds(curvePts, 1, 0, 1, &bounds);
expected.set(0, 0, 5, 6);
REPORTER_ASSERT(reporter, bounds == expected);
- (curve.*SetBounds[SkPath::kCubic_Verb])(curvePts, 1, 0, 1, &bounds);
- REPORTER_ASSERT(reporter, bounds == expected);
}
diff --git a/tests/PathOpsCubicReduceOrderTest.cpp b/tests/PathOpsCubicReduceOrderTest.cpp
index dc779b86f5..6b5cd9bde1 100644
--- a/tests/PathOpsCubicReduceOrderTest.cpp
+++ b/tests/PathOpsCubicReduceOrderTest.cpp
@@ -172,7 +172,7 @@ DEF_TEST(PathOpsReduceOrderCubic, reporter) {
for (index = firstQuadraticPointTest; index < quadraticPoints_count; ++index) {
const SkDQuad& quad = quadraticPoints[index];
SkASSERT(ValidQuad(quad));
- SkDCubic cubic = quad.toCubic();
+ SkDCubic cubic = quad.debugToCubic();
order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
if (order != 1) {
SkDebugf("[%d] point quad order=%d\n", static_cast<int>(index), order);
@@ -182,7 +182,7 @@ DEF_TEST(PathOpsReduceOrderCubic, reporter) {
for (index = firstQuadraticLineTest; index < quadraticLines_count; ++index) {
const SkDQuad& quad = quadraticLines[index];
SkASSERT(ValidQuad(quad));
- SkDCubic cubic = quad.toCubic();
+ SkDCubic cubic = quad.debugToCubic();
order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
if (order != 2) {
SkDebugf("[%d] line quad order=%d\n", static_cast<int>(index), order);
@@ -192,7 +192,7 @@ DEF_TEST(PathOpsReduceOrderCubic, reporter) {
for (index = firstQuadraticModLineTest; index < quadraticModEpsilonLines_count; ++index) {
const SkDQuad& quad = quadraticModEpsilonLines[index];
SkASSERT(ValidQuad(quad));
- SkDCubic cubic = quad.toCubic();
+ SkDCubic cubic = quad.debugToCubic();
order = reducer.reduce(cubic, SkReduceOrder::kAllow_Quadratics);
if (order != 3) {
SkDebugf("[%d] line mod quad order=%d\n", static_cast<int>(index), order);
diff --git a/tests/PathOpsDCubicTest.cpp b/tests/PathOpsDCubicTest.cpp
index b5fe8f744b..4b5e7b4b67 100644
--- a/tests/PathOpsDCubicTest.cpp
+++ b/tests/PathOpsDCubicTest.cpp
@@ -8,27 +8,6 @@
#include "SkPathOpsCubic.h"
#include "Test.h"
-static const SkDCubic tests[] = {
- {{{2, 0}, {3, 1}, {2, 2}, {1, 1}}},
- {{{3, 1}, {2, 2}, {1, 1}, {2, 0}}},
- {{{3, 0}, {2, 1}, {3, 2}, {1, 1}}},
-};
-
-static const size_t tests_count = SK_ARRAY_COUNT(tests);
-
-DEF_TEST(PathOpsDCubic, reporter) {
- for (size_t index = 0; index < tests_count; ++index) {
- const SkDCubic& cubic = tests[index];
- SkASSERT(ValidCubic(cubic));
- bool skip;
- bool result = cubic.clockwise(cubic, &skip);
- if (!result) {
- SkDebugf("%s [%d] expected clockwise\n", __FUNCTION__, index);
- REPORTER_ASSERT(reporter, 0);
- }
- }
-}
-
static const SkDCubic hullTests[] = {
{{{2.6250000819563866, 2.3750000223517418}, {2.833333432674408, 2.3333333432674408}, {3.1111112236976624, 2.3333333134651184}, {3.4074075222015381, 2.3333332538604736}}},
};
diff --git a/tests/PathOpsDVectorTest.cpp b/tests/PathOpsDVectorTest.cpp
index ab291b2477..583a868149 100644
--- a/tests/PathOpsDVectorTest.cpp
+++ b/tests/PathOpsDVectorTest.cpp
@@ -28,8 +28,6 @@ DEF_TEST(PathOpsDVector, reporter) {
SkASSERT(ValidVector(v2));
v1 += v2;
REPORTER_ASSERT(reporter, v1.fX == 0 && v1.fY == 0);
- SkDPoint p = tests[index + 1] + v2;
- REPORTER_ASSERT(reporter, p == tests[index]);
v2 -= v2;
REPORTER_ASSERT(reporter, v2.fX == 0 && v2.fY == 0);
v1 = tests[index + 1] - tests[index];
diff --git a/tests/PathOpsDebug.cpp b/tests/PathOpsDebug.cpp
index d2e8bd0867..95f06e5b7d 100755
--- a/tests/PathOpsDebug.cpp
+++ b/tests/PathOpsDebug.cpp
@@ -298,60 +298,60 @@ const SkOpSpanBase* SkPathOpsDebug::DebugSpanSpan(const SkOpSpanBase* span, int
return span->debugSpan(id);
}
-void SkPathOpsDebug::DumpContours(SkTDArray<SkOpContour* >* contours) {
- int count = contours->count();
- for (int index = 0; index < count; ++index) {
- (*contours)[index]->dump();
- }
+void SkOpContour::dumpContours() const {
+ SkOpContour* contour = this->globalState()->contourHead();
+ do {
+ contour->dump();
+ } while ((contour = contour->next()));
}
-void SkPathOpsDebug::DumpContoursAll(SkTDArray<SkOpContour* >* contours) {
- int count = contours->count();
- for (int index = 0; index < count; ++index) {
- (*contours)[index]->dumpAll();
- }
+void SkOpContour::dumpContoursAll() const {
+ SkOpContour* contour = this->globalState()->contourHead();
+ do {
+ contour->dumpAll();
+ } while ((contour = contour->next()));
}
-void SkPathOpsDebug::DumpContoursAngles(const SkTDArray<SkOpContour* >* contours) {
- int count = contours->count();
- for (int index = 0; index < count; ++index) {
- (*contours)[index]->dumpAngles();
- }
+void SkOpContour::dumpContoursAngles() const {
+ SkOpContour* contour = this->globalState()->contourHead();
+ do {
+ contour->dumpAngles();
+ } while ((contour = contour->next()));
}
-void SkPathOpsDebug::DumpContoursPts(const SkTDArray<SkOpContour* >* contours) {
- int count = contours->count();
- for (int index = 0; index < count; ++index) {
- (*contours)[index]->dumpPts();
- }
+void SkOpContour::dumpContoursPts() const {
+ SkOpContour* contour = this->globalState()->contourHead();
+ do {
+ contour->dumpPts();
+ } while ((contour = contour->next()));
}
-void SkPathOpsDebug::DumpContoursPt(const SkTDArray<SkOpContour* >* contours, int segmentID) {
- int count = contours->count();
- for (int index = 0; index < count; ++index) {
- (*contours)[index]->dumpPt(segmentID);
- }
+void SkOpContour::dumpContoursPt(int segmentID) const {
+ SkOpContour* contour = this->globalState()->contourHead();
+ do {
+ contour->dumpPt(segmentID);
+ } while ((contour = contour->next()));
}
-void SkPathOpsDebug::DumpContoursSegment(const SkTDArray<SkOpContour* >* contours,
- int segmentID) {
- if (contours->count()) {
- (*contours)[0]->dumpSegment(segmentID);
- }
+void SkOpContour::dumpContoursSegment(int segmentID) const {
+ SkOpContour* contour = this->globalState()->contourHead();
+ do {
+ contour->dumpSegment(segmentID);
+ } while ((contour = contour->next()));
}
-void SkPathOpsDebug::DumpContoursSpan(const SkTDArray<SkOpContour* >* contours,
- int spanID) {
- if (contours->count()) {
- (*contours)[0]->dumpSpan(spanID);
- }
+void SkOpContour::dumpContoursSpan(int spanID) const {
+ SkOpContour* contour = this->globalState()->contourHead();
+ do {
+ contour->dumpSpan(spanID);
+ } while ((contour = contour->next()));
}
-void SkPathOpsDebug::DumpContoursSpans(const SkTDArray<SkOpContour* >* contours) {
- int count = contours->count();
- for (int index = 0; index < count; ++index) {
- (*contours)[index]->dumpSpans();
- }
+void SkOpContour::dumpContoursSpans() const {
+ SkOpContour* contour = this->globalState()->contourHead();
+ do {
+ contour->dumpSpans();
+ } while ((contour = contour->next()));
}
template <typename TCurve, typename OppCurve>
@@ -728,6 +728,11 @@ const SkOpSegment* SkOpAngle::debugSegment(int id) const {
return this->segment()->debugSegment(id);
}
+int SkOpAngle::debugSign() const {
+ SkASSERT(fStart->t() != fEnd->t());
+ return fStart->t() < fEnd->t() ? -1 : 1;
+}
+
const SkOpSpanBase* SkOpAngle::debugSpan(int id) const {
return this->segment()->debugSpan(id);
}
@@ -756,7 +761,7 @@ void SkOpAngle::dumpOne(bool functionHeader) const {
SkDebugf(" sect=%d/%d ", fSectorStart, fSectorEnd);
SkDebugf(" s=%1.9g [%d] e=%1.9g [%d]", fStart->t(), fStart->debugID(),
fEnd->t(), fEnd->debugID());
- SkDebugf(" sgn=%d windVal=%d", this->sign(), mSpan.windValue());
+ SkDebugf(" sgn=%d windVal=%d", this->debugSign(), mSpan.windValue());
SkDebugf(" windSum=");
SkPathOpsDebug::WindingPrintf(mSpan.windSum());
@@ -774,9 +779,6 @@ void SkOpAngle::dumpOne(bool functionHeader) const {
if (segment->operand()) {
SkDebugf(" operand");
}
- if (fStop) {
- SkDebugf(" stop");
- }
}
void SkOpAngle::dumpTo(const SkOpSegment* segment, const SkOpAngle* to) const {
@@ -1061,7 +1063,7 @@ void SkOpSegment::dumpCoin() const {
} while ((span = span->next()->upCastable()));
}
-void SkOpSegment::dumpPts() const {
+void SkOpSegment::dumpPtsInner() const {
int last = SkPathOpsVerbToPoints(fVerb);
SkDebugf("seg=%d {{", this->debugID());
if (fVerb == SkPath::kConic_Verb) {
@@ -1077,6 +1079,10 @@ void SkOpSegment::dumpPts() const {
if (fVerb == SkPath::kConic_Verb) {
SkDebugf(", %1.9gf}", fWeight);
}
+}
+
+void SkOpSegment::dumpPts() const {
+ dumpPtsInner();
SkDebugf("\n");
}
@@ -1115,32 +1121,32 @@ void SkOpCoincidence::dump() const {
}
}
-void SkOpContour::dump() {
+void SkOpContour::dump() const {
SkDebugf("contour=%d count=%d op=%d xor=%d\n", this->debugID(), fCount, fOperand, fXor);
if (!fCount) {
return;
}
const SkOpSegment* segment = &fHead;
- SkDEBUGCODE(fIndent = 0);
- indentDump();
+ SkDEBUGCODE(fDebugIndent = 0);
+ this->indentDump();
do {
segment->dump();
} while ((segment = segment->next()));
- outdentDump();
+ this->outdentDump();
}
-void SkOpContour::dumpAll() {
+void SkOpContour::dumpAll() const {
SkDebugf("contour=%d count=%d op=%d xor=%d\n", this->debugID(), fCount, fOperand, fXor);
if (!fCount) {
return;
}
const SkOpSegment* segment = &fHead;
- SkDEBUGCODE(fIndent = 0);
- indentDump();
+ SkDEBUGCODE(fDebugIndent = 0);
+ this->indentDump();
do {
segment->dumpAll();
} while ((segment = segment->next()));
- outdentDump();
+ this->outdentDump();
}
@@ -1225,7 +1231,7 @@ void SkOpCurve::dump() const {
#ifdef SK_DEBUG
const SkOpAngle* SkOpGlobalState::debugAngle(int id) const {
- const SkOpContour* contour = fHead;
+ const SkOpContour* contour = fContourHead;
do {
const SkOpSegment* segment = contour->first();
while (segment) {
@@ -1252,7 +1258,7 @@ const SkOpAngle* SkOpGlobalState::debugAngle(int id) const {
}
SkOpContour* SkOpGlobalState::debugContour(int id) {
- SkOpContour* contour = fHead;
+ SkOpContour* contour = fContourHead;
do {
if (contour->debugID() == id) {
return contour;
@@ -1262,7 +1268,7 @@ SkOpContour* SkOpGlobalState::debugContour(int id) {
}
const SkOpPtT* SkOpGlobalState::debugPtT(int id) const {
- const SkOpContour* contour = fHead;
+ const SkOpContour* contour = fContourHead;
do {
const SkOpSegment* segment = contour->first();
while (segment) {
@@ -1285,7 +1291,7 @@ const SkOpPtT* SkOpGlobalState::debugPtT(int id) const {
}
const SkOpSegment* SkOpGlobalState::debugSegment(int id) const {
- const SkOpContour* contour = fHead;
+ const SkOpContour* contour = fContourHead;
do {
const SkOpSegment* segment = contour->first();
while (segment) {
@@ -1299,7 +1305,7 @@ const SkOpSegment* SkOpGlobalState::debugSegment(int id) const {
}
const SkOpSpanBase* SkOpGlobalState::debugSpan(int id) const {
- const SkOpContour* contour = fHead;
+ const SkOpContour* contour = fContourHead;
do {
const SkOpSegment* segment = contour->first();
while (segment) {
@@ -1320,58 +1326,6 @@ const SkOpSpanBase* SkOpGlobalState::debugSpan(int id) const {
}
#endif
-const SkOpAngle* DebugAngle(const SkTDArray<SkOpContour* >* contours, int id) {
- return (*contours)[0]->debugAngle(id);
-}
-
-SkOpContour* DumpContour(const SkTDArray<SkOpContour* >* contours, int id) {
- return (*contours)[0]->debugContour(id);
-}
-
-const SkOpPtT* DebugPtT(const SkTDArray<SkOpContour* >* contours, int id) {
- return (*contours)[0]->debugPtT(id);
-}
-
-const SkOpSegment* DebugSegment(const SkTDArray<SkOpContour* >* contours, int id) {
- return (*contours)[0]->debugSegment(id);
-}
-
-const SkOpSpanBase* DebugSpan(const SkTDArray<SkOpContour* >* contours, int id) {
- return (*contours)[0]->debugSpan(id);
-}
-
-void Dump(SkTDArray<SkOpContour* >* contours) {
- SkPathOpsDebug::DumpContours(contours);
-}
-
-void DumpAll(SkTDArray<SkOpContour* >* contours) {
- SkPathOpsDebug::DumpContoursAll(contours);
-}
-
-void DumpAngles(const SkTDArray<SkOpContour* >* contours) {
- SkPathOpsDebug::DumpContoursAngles(contours);
-}
-
-void DumpSegment(const SkTDArray<SkOpContour* >* contours, int segmentID) {
- SkPathOpsDebug::DumpContoursSegment(contours, segmentID);
-}
-
-void DumpSpan(const SkTDArray<SkOpContour* >* contours, int spanID) {
- SkPathOpsDebug::DumpContoursSpan(contours, spanID);
-}
-
-void DumpSpans(const SkTDArray<SkOpContour* >* contours) {
- SkPathOpsDebug::DumpContoursSpans(contours);
-}
-
-void DumpPt(const SkTDArray<SkOpContour* >* contours, int segmentID) {
- SkPathOpsDebug::DumpContoursPt(contours, segmentID);
-}
-
-void DumpPts(const SkTDArray<SkOpContour* >* contours) {
- SkPathOpsDebug::DumpContoursPts(contours);
-}
-
#if DEBUG_T_SECT_DUMP > 1
int gDumpTSectNum;
#endif
diff --git a/tests/PathOpsExtendedTest.cpp b/tests/PathOpsExtendedTest.cpp
index 9c57797987..de5c6475b6 100644
--- a/tests/PathOpsExtendedTest.cpp
+++ b/tests/PathOpsExtendedTest.cpp
@@ -326,7 +326,7 @@ SK_DECLARE_STATIC_MUTEX(compareDebugOut4);
static int comparePaths(skiatest::Reporter* reporter, const char* testName, const SkPath& one,
const SkPath& scaledOne, const SkPath& two, const SkPath& scaledTwo, SkBitmap& bitmap,
const SkPath& a, const SkPath& b, const SkPathOp shapeOp, const SkMatrix& scale,
- bool expectSuccess) {
+ bool expectSuccess, bool flaky) {
int errors2x2;
const int MAX_ERRORS = 8;
(void) pathsDrawTheSame(bitmap, scaledOne, scaledTwo, errors2x2);
@@ -339,6 +339,9 @@ static int comparePaths(skiatest::Reporter* reporter, const char* testName, cons
if (errors2x2 == 0) {
return 0;
}
+ if (flaky) {
+ return 0;
+ }
if (errors2x2 > MAX_ERRORS) {
SkAutoMutexAcquire autoM(compareDebugOut3);
showPathOpPath(testName, one, two, a, b, scaledOne, scaledTwo, shapeOp, scale);
@@ -492,13 +495,16 @@ static void showName(const SkPath& a, const SkPath& b, const SkPathOp shapeOp) {
}
#endif
+bool OpDebug(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result, bool expectSuccess);
+
static bool innerPathOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
- const SkPathOp shapeOp, const char* testName, bool threaded, bool expectSuccess) {
+ const SkPathOp shapeOp, const char* testName, bool threaded, bool expectSuccess,
+ bool flaky) {
#if 0 && DEBUG_SHOW_TEST_NAME
showName(a, b, shapeOp);
#endif
SkPath out;
- if (!Op(a, b, shapeOp, &out) ) {
+ if (!OpDebug(a, b, shapeOp, &out, expectSuccess)) {
SkDebugf("%s did not expect failure\n", __FUNCTION__);
REPORTER_ASSERT(reporter, 0);
return false;
@@ -531,24 +537,29 @@ static bool innerPathOp(skiatest::Reporter* reporter, const SkPath& a, const SkP
scaledOut.addPath(out, scale);
scaledOut.setFillType(out.getFillType());
int result = comparePaths(reporter, testName, pathOut, scaledPathOut, out, scaledOut, bitmap,
- a, b, shapeOp, scale, expectSuccess);
+ a, b, shapeOp, scale, expectSuccess, flaky);
reporter->bumpTestCount();
return result == 0;
}
bool testPathOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
const SkPathOp shapeOp, const char* testName) {
- return innerPathOp(reporter, a, b, shapeOp, testName, false, true);
+ return innerPathOp(reporter, a, b, shapeOp, testName, false, true, false);
+}
+
+bool testPathOpFlaky(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
+ const SkPathOp shapeOp, const char* testName) {
+ return innerPathOp(reporter, a, b, shapeOp, testName, false, true, true);
}
bool testPathOpCheck(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
const SkPathOp shapeOp, const char* testName, bool checkFail) {
- return innerPathOp(reporter, a, b, shapeOp, testName, false, checkFail);
+ return innerPathOp(reporter, a, b, shapeOp, testName, false, checkFail, false);
}
bool testPathOpFailCheck(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
const SkPathOp shapeOp, const char* testName) {
- return innerPathOp(reporter, a, b, shapeOp, testName, false, false);
+ return innerPathOp(reporter, a, b, shapeOp, testName, false, false, false);
}
bool testPathFailOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
@@ -570,7 +581,7 @@ bool testPathFailOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath&
bool testThreadedPathOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
const SkPathOp shapeOp, const char* testName) {
- return innerPathOp(reporter, a, b, shapeOp, testName, true, true);
+ return innerPathOp(reporter, a, b, shapeOp, testName, true, true, false);
}
SK_DECLARE_STATIC_MUTEX(gMutex);
diff --git a/tests/PathOpsExtendedTest.h b/tests/PathOpsExtendedTest.h
index f81c42e512..46ee03b193 100644
--- a/tests/PathOpsExtendedTest.h
+++ b/tests/PathOpsExtendedTest.h
@@ -37,6 +37,8 @@ extern bool testPathOpCheck(skiatest::Reporter* reporter, const SkPath& a, const
const SkPathOp , const char* testName, bool checkFail);
extern bool testPathOpFailCheck(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
const SkPathOp , const char* testName);
+extern bool testPathOpFlaky(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
+ const SkPathOp , const char* testName);
extern bool testPathFailOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
const SkPathOp , const char* testName);
extern bool testThreadedPathOp(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
diff --git a/tests/PathOpsFuzz763Test.cpp b/tests/PathOpsFuzz763Test.cpp
index 51e4f9442e..f782941d14 100755
--- a/tests/PathOpsFuzz763Test.cpp
+++ b/tests/PathOpsFuzz763Test.cpp
@@ -454,7 +454,7 @@ path.quadTo(SkBits2Float(0xc2382594), SkBits2Float(0x41a85c76), SkBits2Float(0xc
path.close();
SkPath path2(path);
- testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+ testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, FLAGS_runFail);
}
@@ -932,7 +932,7 @@ path.quadTo(SkBits2Float(0x42240000), SkBits2Float(0x41ed7d86), SkBits2Float(0x4
path.close();
SkPath path2(path);
- testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, FLAGS_runFail);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
}
static void fuzz763_24588(skiatest::Reporter* reporter, const char* filename) {
@@ -1528,7 +1528,7 @@ path.quadTo(SkBits2Float(0xc238d05c), SkBits2Float(0x41a56952), SkBits2Float(0xc
path.close();
SkPath path2(path);
- testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
+ testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, FLAGS_runFail);
}
static void fuzz763_34974(skiatest::Reporter* reporter, const char* filename) {
@@ -2198,7 +2198,7 @@ path.quadTo(SkBits2Float(0x424a2ff8), SkBits2Float(0xc02cd470), SkBits2Float(0x4
path.close();
SkPath path2(path);
- testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, FLAGS_runFail);
+ testPathOpFlaky(reporter, path1, path2, (SkPathOp) 2, filename);
}
static void fuzz763_2674194(skiatest::Reporter* reporter, const char* filename) {
@@ -2391,11 +2391,11 @@ path.quadTo(SkBits2Float(0x42240000), SkBits2Float(0x41ed7d86), SkBits2Float(0x4
path.close();
SkPath path2(path);
- testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, FLAGS_runFail);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
}
static void (*skipTest)(skiatest::Reporter* , const char* filename) = 0;
-static void (*firstTest)(skiatest::Reporter* , const char* filename) = fuzz763_2674194;
+static void (*firstTest)(skiatest::Reporter* , const char* filename) = 0;
static void (*stopTest)(skiatest::Reporter* , const char* filename) = 0;
static struct TestDesc tests[] = {
diff --git a/tests/PathOpsIssue3651.cpp b/tests/PathOpsIssue3651.cpp
index cb4c7e81f3..4e732a1f1e 100644
--- a/tests/PathOpsIssue3651.cpp
+++ b/tests/PathOpsIssue3651.cpp
@@ -1094,7 +1094,7 @@ path.close();
static void issue3651_1(skiatest::Reporter* reporter, const char* filename) {
SkPath path = path1();
SkPath pathB = path2();
- testPathOp(reporter, path, pathB, SkPathOp::kUnion_SkPathOp, filename);
+ testPathOpCheck(reporter, path, pathB, SkPathOp::kUnion_SkPathOp, filename, FLAGS_runFail);
}
static void issue3651_2(skiatest::Reporter* reporter, const char* filename) {
@@ -1281,7 +1281,7 @@ path.cubicTo(SkBits2Float(0x433f5555), SkBits2Float(0x43346920), SkBits2Float(0x
path.lineTo(SkBits2Float(0x4340b333), SkBits2Float(0x43346666)); // 192.7f, 180.4f
path.lineTo(SkBits2Float(0x433a8ccd), SkBits2Float(0x43346666)); // 186.55f, 180.4f
path.close();
- testPathOpCheck(reporter, pathA, path, SkPathOp::kUnion_SkPathOp, filename, FLAGS_runFail);
+ testPathOp(reporter, pathA, path, SkPathOp::kUnion_SkPathOp, filename);
}
static void issue3651_5(skiatest::Reporter* reporter, const char* filename) {
@@ -1344,7 +1344,7 @@ path.cubicTo(SkBits2Float(0x42a73333), SkBits2Float(0x4380ab4f), SkBits2Float(0x
path.lineTo(SkBits2Float(0x42ab999a), SkBits2Float(0x4380b333)); // 85.8f, 257.4f
path.lineTo(SkBits2Float(0x411e6666), SkBits2Float(0x4380b333)); // 9.9f, 257.4f
path.close();
- testPathOpCheck(reporter, pathA, path, SkPathOp::kUnion_SkPathOp, filename, FLAGS_runFail);
+ testPathOp(reporter, pathA, path, SkPathOp::kUnion_SkPathOp, filename);
}
static void issue3651_6(skiatest::Reporter* reporter, const char* filename) {
diff --git a/tests/PathOpsOpTest.cpp b/tests/PathOpsOpTest.cpp
index f25ebc97a1..bab678b8ed 100644
--- a/tests/PathOpsOpTest.cpp
+++ b/tests/PathOpsOpTest.cpp
@@ -7,7 +7,27 @@
#include "PathOpsExtendedTest.h"
#include "PathOpsTestCommon.h"
-#define TEST(name) { name, #name }
+class PathTest_Private {
+public:
+ PathTest_Private(SkPath* path)
+ : fPath(path) {}
+
+ void setPt(int index, SkScalar x, SkScalar y) {
+ fPath->setPt(index, x, y);
+ }
+
+ SkPath* fPath;
+};
+
+static void path_edit(const SkPoint& from, const SkPoint& to, SkPath* path) {
+ PathTest_Private testPath(path);
+ for (int index = 0; index < path->countPoints(); ++index) {
+ if (SkDPoint::ApproximatelyEqual(path->getPoint(index), from)) {
+ testPath.setPt(index, to.fX, to.fY);
+ return;
+ }
+ }
+}
static void cubicOp1d(skiatest::Reporter* reporter, const char* filename) {
SkPath path, pathB;
@@ -2455,7 +2475,7 @@ static void skpaiaigames_com870(skiatest::Reporter* reporter, const char* filena
pathB.cubicTo(145, 715.477173f, 149.477158f, 711, 155, 711);
pathB.lineTo(317, 711);
pathB.close();
- testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
}
static void cubicOp92i(skiatest::Reporter* reporter, const char* filename) {
@@ -3639,7 +3659,7 @@ static void issue3517(skiatest::Reporter* reporter, const char* filename) {
const char strB[] = "M31.35 57.75L31.35 57.75C31.9 57.7514 32.45 57.7052 33 57.7587C33.55 57.8122 34.1 57.9986 34.65 58.0709C35.2 58.1431 35.75 58.1777 36.3 58.1921C36.85 58.2065 37.4 58.1857 37.95 58.1572C38.5 58.1288 39.05 58.0888 39.6 58.0214C40.15 57.954 40.7 57.7971 41.25 57.7528C41.8 57.7084 42.35 57.7038 42.9 57.7555C43.45 57.8072 44 57.9655 44.55 58.0627C45.1 58.16 45.65 58.2885 46.2 58.3389C46.75 58.3893 47.3 58.3629 47.85 58.3651C48.4 58.3673 48.95 58.356 49.5 58.3522C50.05 58.3484 50.6 58.3447 51.15 58.3421C51.7 58.3395 52.25 58.3399 52.8 58.3366C53.35 58.3333 53.9 58.3269 54.45 58.3224C55 58.318 55.55 58.3084 56.1 58.31C56.65 58.3116 57.2 58.322 57.75 58.332C58.3 58.342 58.85 58.3645 59.4 58.3701C59.95 58.3757 60.5 58.3662 61.05 58.3655C61.6 58.3648 62.15 58.376 62.7 58.366C63.25 58.3559 63.8 58.3269 64.35 58.305C64.9 58.2831 65.45 58.2468 66 58.2345C66.55 58.2222 67.1 58.2353 67.65 58.2313C68.2 58.2272 68.75 58.233 69.3 58.2104C69.85 58.1878 70.4 58.129 70.95 58.0956C71.5 58.0623 72.05 58.0332 72.6 58.0104C73.15 57.9877 73.7 57.955 74.25 57.9592C74.8 57.9635 75.35 57.9932 75.9 58.0359C76.45 58.0787 77 58.1756 77.55 58.2158C78.1 58.256 78.65 58.2837 79.2 58.2772C79.75 58.2707 80.3 58.21 80.85 58.1768C81.4 58.1437 81.95 58.104 82.5 58.0781C83.05 58.0522 83.6 58.0363 84.15 58.0213C84.7 58.0063 85.25 57.9989 85.8 57.9879C86.35 57.977 86.9 57.9589 87.45 57.9556C88 57.9523 88.55 57.9337 89.1 57.9682C89.65 58.0028 90.2 58.1874 90.75 58.163C91.3 58.1387 91.85 57.8912 92.4 57.8224C92.95 57.7535 93.5 57.7621 94.05 57.75C94.6 57.7379 95.15 57.75 95.7 57.75L95.7 57.75L31.35 57.75Z";
SkParsePath::FromSVGString(strB, &pathB);
- testPathOp(reporter, path, pathB, kUnion_SkPathOp, filename);
+ testPathOpCheck(reporter, path, pathB, kUnion_SkPathOp, filename, FLAGS_runFail);
}
static void cubicOp119(skiatest::Reporter* reporter, const char* filename) {
@@ -4030,29 +4050,6 @@ static void loop12(skiatest::Reporter* reporter, const char* filename) {
testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
}
-static void loop15(skiatest::Reporter* reporter, const char* filename) {
- SkPath path, pathB;
- path.moveTo(2,6);
- path.cubicTo(1,2, 7.16666698f,6.66666698f, -4.66666651f,7.66666651f);
- path.close();
- pathB.moveTo(1,2);
- pathB.cubicTo(7.16666698f,6.66666698f, -4.66666651f,7.66666651f, 2,6);
- pathB.close();
- testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
-}
-
-// lots of loopy interesections -- all points appear to be present -- needs more investigation
-static void loop16(skiatest::Reporter* reporter, const char* filename) {
- SkPath path, pathB;
- path.moveTo(1,5);
- path.cubicTo(0,1, 7.33333302f,5.33333349f, -7,7);
- path.close();
- pathB.moveTo(0,1);
- pathB.cubicTo(7.33333302f,5.33333349f, -7,7, 1,5);
- pathB.close();
- testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
-}
-
static void cubicOp133(skiatest::Reporter* reporter, const char* filename) {
SkPath path, pathB;
path.setFillType(SkPath::kWinding_FillType);
@@ -4540,7 +4537,7 @@ static void loops23i(skiatest::Reporter* reporter, const char* filename) {
pathB.moveTo(0, 1);
pathB.cubicTo(6.16666698f, 5.66666698f, -5.66666651f, 6.66666651f, 1, 5);
pathB.close();
- testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
}
static void loops24i(skiatest::Reporter* reporter, const char* filename) {
@@ -4579,7 +4576,7 @@ static void loops26i(skiatest::Reporter* reporter, const char* filename) {
pathB.moveTo(0, 2);
pathB.cubicTo(6.16666698f, 6.66666698f, -5.66666651f, 7.66666651f, 1, 6);
pathB.close();
- testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
}
static void loops27i(skiatest::Reporter* reporter, const char* filename) {
@@ -4670,7 +4667,7 @@ static void loops33i(skiatest::Reporter* reporter, const char* filename) {
pathB.moveTo(1, 2);
pathB.cubicTo(7.16666698f, 6.66666698f, -4.66666651f, 7.66666651f, 2, 6);
pathB.close();
- testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
}
static void loops33iMod(skiatest::Reporter* reporter, const char* filename) {
@@ -4696,8 +4693,7 @@ static void loops33iMod(skiatest::Reporter* reporter, const char* filename) {
pathB.moveTo(pts[4]);
pathB.cubicTo(pts[5], pts[6], pts[7]);
pathB.close();
- bool result = testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, name.c_str(),
- FLAGS_runFail);
+ bool result = testPathOp(reporter, path, pathB, kIntersect_SkPathOp, name.c_str());
if (lastResult != result) {
up = !up;
}
@@ -4831,51 +4827,6 @@ static void loops40iAsQuads(skiatest::Reporter* reporter, const char* filename)
testPathOp(reporter, qPath, qPathB, kIntersect_SkPathOp, filename);
}
-static void loops41i(skiatest::Reporter* reporter, const char* filename) {
- SkPath path, pathB;
- path.setFillType(SkPath::kWinding_FillType);
- path.moveTo(1, 5);
- path.cubicTo(0, 1, 6.16666698f, 5.66666698f, -5.66666651f, 6.66666651f);
- path.close();
- pathB.setFillType(SkPath::kWinding_FillType);
- pathB.moveTo(0, 1);
- pathB.cubicTo(6.16666698f, 5.66666698f, -5.66666651f, 6.66666651f, 1, 5);
- pathB.close();
- testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
-}
-
-/*
-FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346 0 */
-static void loops42i(skiatest::Reporter* reporter, const char* filename) {
- SkPath path, pathB;
- path.setFillType(SkPath::kWinding_FillType);
- path.moveTo(1, 6);
- path.cubicTo(0, 2, 6.16666698f, 6.66666698f, -5.66666651f, 7.66666651f);
- path.close();
- pathB.setFillType(SkPath::kWinding_FillType);
- pathB.moveTo(0, 2);
- pathB.cubicTo(6.16666698f, 6.66666698f, -5.66666651f, 7.66666651f, 1, 6);
- pathB.close();
- testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
-}
-
-/*
-FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346 0 */
-static void loops43i(skiatest::Reporter* reporter, const char* filename) {
- SkPath path, pathB;
- path.setFillType(SkPath::kWinding_FillType);
- path.moveTo(2, 6);
- path.cubicTo(1, 2, 7.16666698f, 6.66666698f, -4.66666651f, 7.66666651f);
- path.close();
- pathB.setFillType(SkPath::kWinding_FillType);
- pathB.moveTo(1, 2);
- pathB.cubicTo(7.16666698f, 6.66666698f, -4.66666651f, 7.66666651f, 2, 6);
- pathB.close();
- testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
-}
-
-/*
-FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346 0 */
static void loops44i(skiatest::Reporter* reporter, const char* filename) {
SkPath path, pathB;
path.setFillType(SkPath::kWinding_FillType);
@@ -4886,11 +4837,9 @@ static void loops44i(skiatest::Reporter* reporter, const char* filename) {
pathB.moveTo(0, 1);
pathB.cubicTo(7.33333302f, 5.33333349f, -7, 7, 1, 5);
pathB.close();
- testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
}
-/*
-FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346 0 */
static void loops45i(skiatest::Reporter* reporter, const char* filename) {
SkPath path, pathB;
path.setFillType(SkPath::kWinding_FillType);
@@ -4901,11 +4850,9 @@ static void loops45i(skiatest::Reporter* reporter, const char* filename) {
pathB.moveTo(0, 2);
pathB.cubicTo(7.33333302f, 6.33333302f, -7, 8, 1, 6);
pathB.close();
- testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
}
-/*
-FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346 0 */
static void loops46i(skiatest::Reporter* reporter, const char* filename) {
SkPath path, pathB;
path.setFillType(SkPath::kWinding_FillType);
@@ -4916,7 +4863,7 @@ static void loops46i(skiatest::Reporter* reporter, const char* filename) {
pathB.moveTo(1, 2);
pathB.cubicTo(8.33333302f, 6.33333302f, -6, 8, 2, 6);
pathB.close();
- testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
}
/*
@@ -4931,11 +4878,9 @@ static void loops47i(skiatest::Reporter* reporter, const char* filename) {
pathB.moveTo(0, 1);
pathB.cubicTo(6, 5.83333302f, -4, 8, 2, 4);
pathB.close();
- testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
}
-/*
-FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346 0 */
static void loops48i(skiatest::Reporter* reporter, const char* filename) {
SkPath path, pathB;
path.setFillType(SkPath::kWinding_FillType);
@@ -4946,11 +4891,9 @@ static void loops48i(skiatest::Reporter* reporter, const char* filename) {
pathB.moveTo(0, 1);
pathB.cubicTo(9.33333302f, 6.83333302f, -8.33333302f, 9.16666603f, 2, 6);
pathB.close();
- testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
}
-/*
-FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346 0 */
static void loops49i(skiatest::Reporter* reporter, const char* filename) {
SkPath path, pathB;
path.setFillType(SkPath::kWinding_FillType);
@@ -4961,11 +4904,9 @@ static void loops49i(skiatest::Reporter* reporter, const char* filename) {
pathB.moveTo(1, 4);
pathB.cubicTo(-0.166666687f, 2.66666675f, 1.66666675f, 2, 0, 2);
pathB.close();
- testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
}
-/*
-FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346 0 */
static void loops50i(skiatest::Reporter* reporter, const char* filename) {
SkPath path, pathB;
path.setFillType(SkPath::kWinding_FillType);
@@ -4976,11 +4917,9 @@ static void loops50i(skiatest::Reporter* reporter, const char* filename) {
pathB.moveTo(1, 5);
pathB.cubicTo(-0.166666687f, 3.66666675f, 1.66666675f, 3, 0, 3);
pathB.close();
- testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
}
-/*
-FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346 0 */
static void loops51i(skiatest::Reporter* reporter, const char* filename) {
SkPath path, pathB;
path.setFillType(SkPath::kWinding_FillType);
@@ -4991,11 +4930,9 @@ static void loops51i(skiatest::Reporter* reporter, const char* filename) {
pathB.moveTo(2, 4);
pathB.cubicTo(0.833333313f, 2.66666675f, 2.66666675f, 2, 1, 2);
pathB.close();
- testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
}
-/*
-FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346 0 */
static void loops52i(skiatest::Reporter* reporter, const char* filename) {
SkPath path, pathB;
path.setFillType(SkPath::kWinding_FillType);
@@ -5006,11 +4943,9 @@ static void loops52i(skiatest::Reporter* reporter, const char* filename) {
pathB.moveTo(2, 5);
pathB.cubicTo(0.833333313f, 3.66666675f, 2.66666675f, 3, 1, 3);
pathB.close();
- testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
}
-/*
-FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346 0 */
static void loops53i(skiatest::Reporter* reporter, const char* filename) {
SkPath path, pathB;
path.setFillType(SkPath::kWinding_FillType);
@@ -5021,11 +4956,9 @@ static void loops53i(skiatest::Reporter* reporter, const char* filename) {
pathB.moveTo(3, 5);
pathB.cubicTo(1.83333325f, 3.66666675f, 3.66666651f, 3, 2, 3);
pathB.close();
- testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
}
-/*
-FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346 0 */
static void loops54i(skiatest::Reporter* reporter, const char* filename) {
SkPath path, pathB;
path.setFillType(SkPath::kWinding_FillType);
@@ -5036,11 +4969,9 @@ static void loops54i(skiatest::Reporter* reporter, const char* filename) {
pathB.moveTo(1, 4);
pathB.cubicTo(0, 3, 1.66666675f, 2, 0, 2);
pathB.close();
- testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
}
-/*
-FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346 0 */
static void loops55i(skiatest::Reporter* reporter, const char* filename) {
SkPath path, pathB;
path.setFillType(SkPath::kWinding_FillType);
@@ -5051,11 +4982,9 @@ static void loops55i(skiatest::Reporter* reporter, const char* filename) {
pathB.moveTo(1, 5);
pathB.cubicTo(0, 4, 1.66666675f, 3, 0, 3);
pathB.close();
- testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
}
-/*
-FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346 0 */
static void loops56i(skiatest::Reporter* reporter, const char* filename) {
SkPath path, pathB;
path.setFillType(SkPath::kWinding_FillType);
@@ -5066,11 +4995,9 @@ static void loops56i(skiatest::Reporter* reporter, const char* filename) {
pathB.moveTo(2, 4);
pathB.cubicTo(0.99999994f, 3, 2.66666675f, 2, 1, 2);
pathB.close();
- testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
}
-/*
-FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346 0 */
static void loops57i(skiatest::Reporter* reporter, const char* filename) {
SkPath path, pathB;
path.setFillType(SkPath::kWinding_FillType);
@@ -5081,11 +5008,9 @@ static void loops57i(skiatest::Reporter* reporter, const char* filename) {
pathB.moveTo(2, 5);
pathB.cubicTo(0.99999994f, 4, 2.66666675f, 3, 1, 3);
pathB.close();
- testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
}
-/*
-FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346 0 */
static void loops58i(skiatest::Reporter* reporter, const char* filename) {
SkPath path, pathB;
path.setFillType(SkPath::kWinding_FillType);
@@ -5096,11 +5021,28 @@ static void loops58i(skiatest::Reporter* reporter, const char* filename) {
pathB.moveTo(3, 5);
pathB.cubicTo(2, 4, 3.66666651f, 3, 2, 3);
pathB.close();
- testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void loops58iAsQuads(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(2, 3);
+ path.cubicTo(3, 5, 2, 4, 3.66666651f, 3);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(3, 5);
+ pathB.cubicTo(2, 4, 3.66666651f, 3, 2, 3);
+ pathB.close();
+ SkPath qPath, qPathB;
+ CubicPathToQuads(path, &qPath);
+ CubicPathToQuads(pathB, &qPathB);
+// SkPoint from = {2.61714339f,1.90228665f};
+// SkPoint to = {2.617045833359139f,1.9013528935803314f};
+// path_edit(from, to, &qPathB);
+ testPathOp(reporter, qPath, qPathB, kIntersect_SkPathOp, filename);
}
-/*
-FAILED: d:\cygwin\puregit\tests\pathopsextendedtest.cpp:346 0 */
static void loops59i(skiatest::Reporter* reporter, const char* filename) {
SkPath path, pathB;
path.setFillType(SkPath::kWinding_FillType);
@@ -5114,28 +5056,6 @@ static void loops59i(skiatest::Reporter* reporter, const char* filename) {
testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
}
-class PathTest_Private {
-public:
- PathTest_Private(SkPath* path)
- : fPath(path) {}
-
- void setPt(int index, SkScalar x, SkScalar y) {
- fPath->setPt(index, x, y);
- }
-
- SkPath* fPath;
-};
-
-static void path_edit(const SkPoint& from, const SkPoint& to, SkPath* path) {
- PathTest_Private testPath(path);
- for (int index = 0; index < path->countPoints(); ++index) {
- if (SkDPoint::ApproximatelyEqual(path->getPoint(index), from)) {
- testPath.setPt(index, to.fX, to.fY);
- return;
- }
- }
-}
-
static void loops59iasQuads(skiatest::Reporter* reporter, const char* filename) {
SkPath path, pathB;
path.setFillType(SkPath::kWinding_FillType);
@@ -5168,17 +5088,87 @@ static void cubics41d(skiatest::Reporter* reporter, const char* filename) {
testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
}
+void loops61i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0, 1);
+ path.cubicTo(1, 5, -6.33333302f, 0.666666627f, 8, -1);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 5);
+ pathB.cubicTo(-6.33333302f, 0.666666627f, 8, -1, 0, 1);
+ pathB.close();
+ testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+}
+
+static void loops62i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0, 2);
+ path.cubicTo(1, 6, -6.33333302f, 1.66666663f, 8, 0);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 6);
+ pathB.cubicTo(-6.33333302f, 1.66666663f, 8, 0, 0, 2);
+ pathB.close();
+ testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+}
+
+static void loops63i(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(0, 1);
+ path.cubicTo(2, 4, -4, -0.833333254f, 6, -3);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(2, 4);
+ pathB.cubicTo(-4, -0.833333254f, 6, -3, 0, 1);
+ pathB.close();
+ testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+}
+
+static void cubics44d(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(3, 4);
+ path.cubicTo(2, 5, 3, 1, 6, 2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(1, 3);
+ pathB.cubicTo(2, 6, 4, 3, 5, 2);
+ pathB.close();
+ testPathOpCheck(reporter, path, pathB, kDifference_SkPathOp, filename, FLAGS_runFail);
+}
+
+static void cubics45u(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.moveTo(1, 3);
+ path.cubicTo(2, 6, 4, 3, 5, 2);
+ path.close();
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.moveTo(3, 4);
+ pathB.cubicTo(2, 5, 3, 1, 6, 2);
+ pathB.close();
+ testPathOpCheck(reporter, path, pathB, kUnion_SkPathOp, filename, FLAGS_runFail);
+}
+
static void (*skipTest)(skiatest::Reporter* , const char* filename) = 0;
-static void (*firstTest)(skiatest::Reporter* , const char* filename) = loops59i;
+static void (*firstTest)(skiatest::Reporter* , const char* filename) = 0;
static void (*stopTest)(skiatest::Reporter* , const char* filename) = 0;
+#define TEST(name) { name, #name }
+
static struct TestDesc tests[] = {
+ TEST(cubics44d),
+ TEST(cubics45u),
+ TEST(loops61i),
+ TEST(loops62i),
+ TEST(loops63i),
+ TEST(loops58iAsQuads),
TEST(cubics41d),
TEST(loops59iasQuads),
TEST(loops59i),
- TEST(loops41i),
- TEST(loops42i),
- TEST(loops43i),
TEST(loops44i),
TEST(loops45i),
TEST(loops46i),
@@ -5254,8 +5244,6 @@ static struct TestDesc tests[] = {
TEST(cubicOp135),
TEST(cubicOp134),
TEST(cubicOp133),
- TEST(loop16),
- TEST(loop15),
TEST(loop12),
TEST(cubicOp132),
TEST(loop11),
@@ -5509,58 +5497,16 @@ static struct TestDesc tests[] = {
static const size_t testCount = SK_ARRAY_COUNT(tests);
static struct TestDesc subTests[] = {
- TEST(loops40i),
- TEST(loops39i),
- TEST(loops38i),
- TEST(loops37i),
- TEST(loops36i),
- TEST(loops35i),
- TEST(loops34i),
- TEST(loops33i),
- TEST(loops32i),
- TEST(loops31i),
- TEST(loops30i),
- TEST(loops29i),
- TEST(loops28i),
- TEST(loops27i),
- TEST(loops26i),
- TEST(loops25i),
- TEST(loops24i),
- TEST(loops23i),
- TEST(loops22i),
- TEST(loops21i),
- TEST(loops20i),
- TEST(cubics20d),
- TEST(cubics6d),
- TEST(cubics7d),
- TEST(cubics8d),
- TEST(cubics9d),
- TEST(cubics10u),
- TEST(cubics11i),
- TEST(cubics12d),
- TEST(cubics13d),
- TEST(cubics14d),
- TEST(cubics15d),
- TEST(cubics16i),
- TEST(cubics17d),
- TEST(cubics18d),
- TEST(cubics19d),
- TEST(cubicOp157),
- TEST(cubicOp142),
- TEST(loops4i),
- TEST(quadRect1),
- TEST(quadRect2),
- TEST(quadRect3),
- TEST(quadRect4),
- TEST(quadRect5),
- TEST(quadRect6),
+ TEST(cubics45u),
+ TEST(loops61i),
+ TEST(loops62i),
};
static const size_t subTestCount = SK_ARRAY_COUNT(subTests);
static void (*firstSubTest)(skiatest::Reporter* , const char* filename) = 0;
-static bool runSubTests = false;
+static bool runSubTests = true;
static bool runSubTestsFirst = true;
static bool runReverse = false;
@@ -5582,7 +5528,7 @@ static void bufferOverflow(skiatest::Reporter* reporter, const char* filename) {
path.addRect(0,0, 300,170141183460469231731687303715884105728.f);
SkPath pathB;
pathB.addRect(0,0, 300,16);
- testPathOp(reporter, path, pathB, kUnion_SkPathOp, filename);
+ testPathOpFailCheck(reporter, path, pathB, kUnion_SkPathOp, filename);
}
// m 100,0 60,170 -160,-110 200,0 -170,11000000000 z
@@ -5769,10 +5715,10 @@ path.close();
}
static struct TestDesc failTests[] = {
+ TEST(fuzz487a),
TEST(fuzz433),
TEST(fuzz1),
TEST(fuzz714),
- TEST(fuzz487a),
TEST(fuzz487b),
TEST(fuzz433b),
TEST(bufferOverflow),
diff --git a/tests/PathOpsQuadIntersectionTest.cpp b/tests/PathOpsQuadIntersectionTest.cpp
index 577d2002c0..f01262201f 100644
--- a/tests/PathOpsQuadIntersectionTest.cpp
+++ b/tests/PathOpsQuadIntersectionTest.cpp
@@ -377,9 +377,9 @@ static void coincidentTestOne(skiatest::Reporter* reporter, int test1, int test2
SkASSERT(ValidQuad(quad2));
SkIntersections intersections2;
intersections2.intersect(quad1, quad2);
- REPORTER_ASSERT(reporter, intersections2.coincidentUsed() >= 2);
+ REPORTER_ASSERT(reporter, intersections2.debugCoincidentUsed() >= 2);
REPORTER_ASSERT(reporter, intersections2.used() >= 2);
- for (int pt = 0; pt < intersections2.coincidentUsed(); pt += 2) {
+ for (int pt = 0; pt < intersections2.debugCoincidentUsed(); pt += 2) {
double tt1 = intersections2[0][pt];
double tt2 = intersections2[1][pt];
SkDPoint pt1 = quad1.ptAtT(tt1);
@@ -394,70 +394,6 @@ static void coincidentTest(skiatest::Reporter* reporter) {
}
}
-static int floatSign(double x) {
- return x < 0 ? -1 : x > 0 ? 1 : 0;
-}
-
-static const SkDQuad pointFinderTestSet[] = {
- //>=0.633974464 0.633974846 <=
-{{{1.2071879545809394, 0.82163474041730045}, {1.1534203513372994, 0.52790870069930229},
- {1.0880000000000001, 0.29599999999999982}}}, //t=0.63155333662549329, 0.80000000000000004
-{{{1.2071879545809394, 0.82163474041730045}, {1.2065040319428038, 0.81766753259119995},
- {1.2058123269101506, 0.81370135061854221}}}, //t=0.63155333662549329, 0.6339049773632347
-{{{1.2058123269101506, 0.81370135061854221}, {1.152376363978022, 0.5244097415381026},
- {1.0880000000000001, 0.29599999999999982}}}, //t=0.6339049773632347, 0.80000000000000004
- //>=0.633974083 0.633975227 <=
-{{{0.33333333333333326, 0.81481481481481488}, {0.63395173631977997, 0.68744136726313931},
- {1.205684411948591, 0.81344322326274499}}}, //t=0.33333333333333331, 0.63395173631977986
-{{{0.33333333333333326, 0.81481481481481488}, {0.63396444791444551, 0.68743368362444768},
- {1.205732763658403, 0.81345617746834109}}}, //t=0.33333333333333331, 0.63396444791444551
-{{{1.205684411948591, 0.81344322326274499}, {1.2057085875611198, 0.81344969999329253},
- {1.205732763658403, 0.81345617746834109}}}, //t=0.63395173631977986, 0.63396444791444551
-{{{1.205732763658403, 0.81345617746834109}, {1.267928895828891, 0.83008534558465619},
- {1.3333333333333333, 0.85185185185185175}}}, //t=0.63396444791444551, 0.66666666666666663
-};
-
-static void pointFinder(const SkDQuad& q1, const SkDQuad& q2) {
- for (int index = 0; index < 3; ++index) {
- double t = q1.nearestT(q2[index]);
- SkDPoint onQuad = q1.ptAtT(t);
- SkDebugf("%s t=%1.9g (%1.9g,%1.9g) dist=%1.9g\n", __FUNCTION__, t, onQuad.fX, onQuad.fY,
- onQuad.distance(q2[index]));
- double left[3];
- left[0] = ((const SkDLine&) q1[0]).isLeft(q2[index]);
- left[1] = ((const SkDLine&) q1[1]).isLeft(q2[index]);
- SkDLine diag = {{q1[0], q1[2]}};
- left[2] = diag.isLeft(q2[index]);
- SkDebugf("%s left=(%d, %d, %d)\n", __FUNCTION__, floatSign(left[0]),
- floatSign(left[1]), floatSign(left[2]));
- }
- SkDebugf("\n");
-}
-
-static void hullIntersect(const SkDQuad& q1, const SkDQuad& q2) {
- SkDebugf("%s", __FUNCTION__);
- SkIntersections ts;
- for (int i1 = 0; i1 < 3; ++i1) {
- SkDLine l1 = {{q1[i1], q1[(i1 + 1) % 3]}};
- for (int i2 = 0; i2 < 3; ++i2) {
- SkDLine l2 = {{q2[i2], q2[(i2 + 1) % 3]}};
- if (ts.intersect(l1, l2)) {
- SkDebugf(" [%d,%d]", i1, i2);
- }
- }
- }
- SkDebugf("\n");
-}
-
-static void QuadraticIntersection_PointFinder() {
- pointFinder(pointFinderTestSet[0], pointFinderTestSet[4]);
- pointFinder(pointFinderTestSet[4], pointFinderTestSet[0]);
- pointFinder(pointFinderTestSet[0], pointFinderTestSet[6]);
- pointFinder(pointFinderTestSet[6], pointFinderTestSet[0]);
- hullIntersect(pointFinderTestSet[0], pointFinderTestSet[4]);
- hullIntersect(pointFinderTestSet[0], pointFinderTestSet[6]);
-}
-
static void intersectionFinder(int test1, int test2) {
const SkDQuad& quad1 = testSet[test1];
const SkDQuad& quad2 = testSet[test2];
@@ -569,7 +505,6 @@ DEF_TEST(PathOpsQuadIntersection, reporter) {
coincidentTest(reporter);
standardTestCases(reporter);
if (false) QuadraticIntersection_IntersectionFinder();
- if (false) QuadraticIntersection_PointFinder();
}
#include "SkCommonFlags.h"
diff --git a/tests/PathOpsSimplifyTest.cpp b/tests/PathOpsSimplifyTest.cpp
index 599fb1a785..de08bd81d9 100644
--- a/tests/PathOpsSimplifyTest.cpp
+++ b/tests/PathOpsSimplifyTest.cpp
@@ -4726,11 +4726,39 @@ static void testQuads64(skiatest::Reporter* reporter,const char* filename) {
testSimplify(reporter, path, filename);
}
+static void testTriangle1(skiatest::Reporter* reporter,const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(1, 0);
+ path.lineTo(2, 3);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(1, 2);
+ path.lineTo(1, 0);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
+static void testTriangle2(skiatest::Reporter* reporter,const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(1, 0);
+ path.lineTo(0, 1);
+ path.close();
+ path.moveTo(2, 0);
+ path.lineTo(0, 2);
+ path.lineTo(2, 2);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
static void (*skipTest)(skiatest::Reporter* , const char* filename) = 0;
static void (*firstTest)(skiatest::Reporter* , const char* filename) = 0;
static void (*stopTest)(skiatest::Reporter* , const char* filename) = 0;
static TestDesc tests[] = {
+ TEST(testTriangle2),
+ TEST(testTriangle1),
TEST(testQuads64),
TEST(testQuads63),
TEST(testQuads62),
diff --git a/tests/PathOpsSkpTest.cpp b/tests/PathOpsSkpTest.cpp
index a86218da78..bbf3453b6d 100755
--- a/tests/PathOpsSkpTest.cpp
+++ b/tests/PathOpsSkpTest.cpp
@@ -1090,7 +1090,7 @@ static void skpcyclist_friends_gr52(skiatest::Reporter* reporter, const char* fi
// FIXME: this generates quads and cubics that are (correctly) not coincident unlike the old code
// however, somewhere the angles are sorted incorrectly and the winding is computed to be -1/-2
// but I can't find the error
- testPathOpCheck(reporter, path, pathB, kIntersect_SkPathOp, filename, FLAGS_runFail);
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
}
static void skpwww_fj_p_com_22(skiatest::Reporter* reporter, const char* filename) {
@@ -3769,7 +3769,7 @@ pathB.cubicTo(980.018494f, 1481.22131f, 979.602478f, 1478.38831f, 984.546021f, 1
}
static void (*skipTest)(skiatest::Reporter* , const char* filename) = 0;
-static void (*firstTest)(skiatest::Reporter* , const char* filename) = skpwww_macrumors_com_131;
+static void (*firstTest)(skiatest::Reporter* , const char* filename) = skpwww_cooksnaps_com_32;
static void (*stopTest)(skiatest::Reporter* , const char* filename) = 0;
static struct TestDesc tests[] = {
diff --git a/tools/pathops_sorter.htm b/tools/pathops_sorter.htm
index c515fe9b87..3e71f610f2 100644
--- a/tools/pathops_sorter.htm
+++ b/tools/pathops_sorter.htm
@@ -7,8 +7,10 @@
<div style="height:0">
<div id="sect1">
-{{{2.18726921f, 2.37414956f}, {2.17974997f, 1.98023772f}, {0.0679920018f, 1.92180145f}}}
-{{{1.58881736f, 3.34967732f}, {2.89432383f, 1.86175978f}, {2.97965813f, 1.76450205f}, {-7.5f, 2}}}
+SkOpAngle::afterPart {{{3,4}, {2.87721833,4.1227816}, {2.78458726,4.17018661}, {2.72210693,4.16072464}}} id=1
+SkOpAngle::afterPart {{{3,4}, {3.00020218,3.99986529}}} id=3
+SkOpAngle::afterPart {{{3,4}, {3.00006742,3.99995506}, {3.00013476,3.99991025}, {3.00020218,3.99986529}}} id=4
+
</div>
</div>
diff --git a/tools/pathops_visualizer.htm b/tools/pathops_visualizer.htm
index f1288f0fe8..8f939313ab 100644
--- a/tools/pathops_visualizer.htm
+++ b/tools/pathops_visualizer.htm
@@ -2,225 +2,389 @@
<head>
<div height="0" hidden="true">
-<div id="loops59i">
-SkDCubic::ComplexBreak
-{{{1, 2}, {7.3333330154418945, 1.6666666269302368}, {-7.5, 2}, {0, 6}}},
-inflectionsTs[0]=0.22755391 {{{5.6899562470344014, 1.5351137489099846}, {-0.59395324579271769, 2.2875990427916371}}},
-inflectionsTs[1]=0.134608255 {{{-1.7562572007939035, 2.2074401507711405}, {6.7824037520473279, 1.6104549548102116}}},
-maxCurvature[0]=0.184583395 {{{2.612965320628251, 1.8574526830515183}, {2.6213210132912339, 1.9473982945574213}}},
-maxCurvature[1]=0.764880287 {{{-0.3599143419711428, -3.5772335093952985}, {-3.9435828934112642, 11.072562225478482}}},
-maxCurvature[2]=0.500240448 {{{11.93379531543474, -0.87734455447864557}, {-11.814505983496176, 5.6289081865421942}}},
-seg=1 {{{0, 6}, {0.293506175f, 4.82597542f}, {1.04645705f, 3.96781874f}, {1.58881736f, 3.34967732f}}}
-seg=2 {{{1.58881736f, 3.34967732f}, {2.89432383f, 1.86175978f}, {2.97965813f, 1.76450205f}, {-7.5f, 2}}}
-seg=3 {{{-7.5f, 2}, {0, 6}}}
-op sect
-seg=4 {{{1, 2}, {2.16902828f, 1.93847215f}, {2.61688614f, 1.89965844f}, {2.61714315f, 1.90242553f}}}
-seg=5 {{{2.61714315f, 1.90242553f}, {2.61827874f, 1.91464937f}, {-6.11562443f, 2.7383337f}, {0, 6}}}
-seg=6 {{{0, 6}, {1, 2}}}
-debugShowCubicIntersection wtTs[0]=1 {{{0,6}, {0.293506175,4.82597542}, {1.04645705,3.96781874}, {1.58881736,3.34967732}}} {{1.58881736,3.34967732}} wnTs[0]=0 {{{1.58881736,3.34967732}, {2.89432383,1.86175978}, {2.97965813,1.76450205}, {-7.5,2}}}
-debugShowCubicLineIntersection wtTs[0]=0 {{{0,6}, {0.293506175,4.82597542}, {1.04645705,3.96781874}, {1.58881736,3.34967732}}} {{0,6}} wnTs[0]=1 {{{-7.5,2}, {0,6}}}
-debugShowCubicLineIntersection wtTs[0]=1 {{{1.58881736,3.34967732}, {2.89432383,1.86175978}, {2.97965813,1.76450205}, {-7.5,2}}} {{-7.5,2}} wnTs[0]=0 {{{-7.5,2}, {0,6}}}
-debugShowCubicIntersection wtTs[0]=0 {{{0,6}, {0.293506175,4.82597542}, {1.04645705,3.96781874}, {1.58881736,3.34967732}}} {{0,6}} wnTs[0]=1 {{{2.61714315,1.90242553}, {2.61827874,1.91464937}, {-6.11562443,2.7383337}, {0,6}}}
-debugShowCubicLineIntersection wtTs[0]=0 {{{0,6}, {0.293506175,4.82597542}, {1.04645705,3.96781874}, {1.58881736,3.34967732}}} {{0,6}} wnTs[0]=0 {{{0,6}, {1,2}}}
-debugShowCubicIntersection wtTs[0]=0.538493706 {{{1.58881736,3.34967732}, {2.89432383,1.86175978}, {2.97965813,1.76450205}, {-7.5,2}}} {{1.17718506,1.99055469}} wnTs[0]=0.0521913 {{{1,2}, {2.16902828,1.93847215}, {2.61688614,1.89965844}, {2.61714315,1.90242553}}}
-SkOpSegment::addT insert t=0.538493706 segID=2 spanID=13
-SkOpSegment::addT insert t=0.0521913275 segID=4 spanID=14
-debugShowCubicIntersection wtTs[0]=0.481912781 {{{1.58881736,3.34967732}, {2.89432383,1.86175978}, {2.97965813,1.76450205}, {-7.5,2}}} {{1.58025348,2.04903817}} wnTs[0]=0.222514 {{{2.61714315,1.90242553}, {2.61827874,1.91464937}, {-6.11562443,2.7383337}, {0,6}}}
-SkOpSegment::addT insert t=0.481912781 segID=2 spanID=15
-SkOpSegment::addT insert t=0.222514468 segID=5 spanID=16
-debugShowCubicLineIntersection no intersect {{{1.58881736,3.34967732}, {2.89432383,1.86175978}, {2.97965813,1.76450205}, {-7.5,2}}} {{{0,6}, {1,2}}}
-debugShowCubicLineIntersection wtTs[0]=1 {{{2.61714315,1.90242553}, {2.61827874,1.91464937}, {-6.11562443,2.7383337}, {0,6}}} {{0,6}} wnTs[0]=1 {{{-7.5,2}, {0,6}}}
-debugShowLineIntersection wtTs[0]=1 {{{-7.5,2}, {0,6}}} {{0,6}} wnTs[0]=0 {{{0,6}, {1,2}}}
-debugShowCubicIntersection wtTs[0]=1 {{{1,2}, {2.16902828,1.93847215}, {2.61688614,1.89965844}, {2.61714315,1.90242553}}} {{2.61714315,1.90242553}} wnTs[0]=0 {{{2.61714315,1.90242553}, {2.61827874,1.91464937}, {-6.11562443,2.7383337}, {0,6}}}
-debugShowCubicLineIntersection wtTs[0]=0 {{{1,2}, {2.16902828,1.93847215}, {2.61688614,1.89965844}, {2.61714315,1.90242553}}} {{1,2}} wnTs[0]=1 {{{0,6}, {1,2}}}
-debugShowCubicLineIntersection wtTs[0]=0.293280033 {{{2.61714315,1.90242553}, {2.61827874,1.91464937}, {-6.11562443,2.7383337}, {0,6}}} {{0.959100008,2.16359997}} wtTs[1]=1 {{0,6}} wnTs[0]=0.9591 {{{0,6}, {1,2}}} wnTs[1]=0
-SkOpSegment::addT insert t=0.293280033 segID=5 spanID=17
-SkOpSegment::addT insert t=0.959100004 segID=6 spanID=18
-SkOpSegment::sortAngles [1] tStart=0 [1]
-SkOpAngle::after [1/1] 5/5 tStart=0 tEnd=1 < [5/13] 13/5 tStart=1 tEnd=0.293280033 < [6/14] 5/5 tStart=0 tEnd=0.959100004 F 7
-SkOpAngle::afterPart {{{0,6}, {0.293506175,4.82597542}, {1.04645705,3.96781874}, {1.58881736,3.34967732}}} id=1
-SkOpAngle::afterPart {{{0,6}, {-4.3220339,3.6949153}, {-1.22742501,2.60748826}, {0.959100008,2.16359997}}} id=5
-SkOpAngle::afterPart {{{0,6}, {0.959100008,2.16359997}}} id=6
-SkOpAngle::after [1/1] 5/5 tStart=0 tEnd=1 < [3/6] 13/13 tStart=1 tEnd=0 < [6/14] 5/5 tStart=0 tEnd=0.959100004 F 5
-SkOpAngle::afterPart {{{0,6}, {0.293506175,4.82597542}, {1.04645705,3.96781874}, {1.58881736,3.34967732}}} id=1
-SkOpAngle::afterPart {{{0,6}, {-7.5,2}}} id=3
-SkOpAngle::afterPart {{{0,6}, {0.959100008,2.16359997}}} id=6
-SkOpAngle::after [6/14] 5/5 tStart=0 tEnd=0.959100004 < [3/6] 13/13 tStart=1 tEnd=0 < [5/13] 13/5 tStart=1 tEnd=0.293280033 F 7
-SkOpAngle::afterPart {{{0,6}, {0.959100008,2.16359997}}} id=6
-SkOpAngle::afterPart {{{0,6}, {-7.5,2}}} id=3
-SkOpAngle::afterPart {{{0,6}, {-4.3220339,3.6949153}, {-1.22742501,2.60748826}, {0.959100008,2.16359997}}} id=5
-SkOpAngle::after [5/13] 13/5 tStart=1 tEnd=0.293280033 < [3/6] 13/13 tStart=1 tEnd=0 < [1/1] 5/5 tStart=0 tEnd=1 T 7
-SkOpAngle::afterPart {{{0,6}, {-4.3220339,3.6949153}, {-1.22742501,2.60748826}, {0.959100008,2.16359997}}} id=5
-SkOpAngle::afterPart {{{0,6}, {-7.5,2}}} id=3
-SkOpAngle::afterPart {{{0,6}, {0.293506175,4.82597542}, {1.04645705,3.96781874}, {1.58881736,3.34967732}}} id=1
-SkOpSegment::sortAngles [2] tStart=0.481912781 [15]
-SkOpAngle::after [2/2] 29/25 tStart=0.481912781 tEnd=0 < [5/9] 1/1 tStart=0.222514468 tEnd=0 < [2/3] 13/13 tStart=0.481912781 tEnd=0.538493706 T 4
-SkOpAngle::afterPart {{{1.58025348,2.04903817}, {2.5637252,2.23855117}, {2.21795761,2.63263084}, {1.58881736,3.34967732}}} id=2
-SkOpAngle::afterPart {{{1.58025348,2.04903817}, {2.18515331,1.94804315}, {2.61739584,1.90514551}, {2.61714315,1.90242553}}} id=5
-SkOpAngle::afterPart {{{1.58025348,2.04903817}, {1.464785,2.02678763}, {1.33099307,2.007357}, {1.17718506,1.99055469}}} id=2
-SkOpAngle::after [2/2] 29/25 tStart=0.481912781 tEnd=0 < [5/10] 17/17 tStart=0.222514468 tEnd=0.293280033 < [5/9] 1/1 tStart=0.222514468 tEnd=0 F 4
-SkOpAngle::afterPart {{{1.58025348,2.04903817}, {2.5637252,2.23855117}, {2.21795761,2.63263084}, {1.58881736,3.34967732}}} id=2
-SkOpAngle::afterPart {{{1.58025348,2.04903817}, {1.38787913,2.0811573}, {1.178042,2.11915237}, {0.959100008,2.16359997}}} id=5
-SkOpAngle::afterPart {{{1.58025348,2.04903817}, {2.18515331,1.94804315}, {2.61739584,1.90514551}, {2.61714315,1.90242553}}} id=5
-SkOpAngle::after [5/9] 1/1 tStart=0.222514468 tEnd=0 < [5/10] 17/17 tStart=0.222514468 tEnd=0.293280033 < [2/3] 13/13 tStart=0.481912781 tEnd=0.538493706 F 4
-SkOpAngle::afterPart {{{1.58025348,2.04903817}, {2.18515331,1.94804315}, {2.61739584,1.90514551}, {2.61714315,1.90242553}}} id=5
-SkOpAngle::afterPart {{{1.58025348,2.04903817}, {1.38787913,2.0811573}, {1.178042,2.11915237}, {0.959100008,2.16359997}}} id=5
-SkOpAngle::afterPart {{{1.58025348,2.04903817}, {1.464785,2.02678763}, {1.33099307,2.007357}, {1.17718506,1.99055469}}} id=2
-SkOpAngle::after [2/3] 13/13 tStart=0.481912781 tEnd=0.538493706 < [5/10] 17/17 tStart=0.222514468 tEnd=0.293280033 < [2/2] 29/25 tStart=0.481912781 tEnd=0 T 4
-SkOpAngle::afterPart {{{1.58025348,2.04903817}, {1.464785,2.02678763}, {1.33099307,2.007357}, {1.17718506,1.99055469}}} id=2
-SkOpAngle::afterPart {{{1.58025348,2.04903817}, {1.38787913,2.0811573}, {1.178042,2.11915237}, {0.959100008,2.16359997}}} id=5
-SkOpAngle::afterPart {{{1.58025348,2.04903817}, {2.5637252,2.23855117}, {2.21795761,2.63263084}, {1.58881736,3.34967732}}} id=2
-SkOpSegment::sortAngles [2] tStart=0.538493706 [13]
-SkOpAngle::after [2/4] 29/29 tStart=0.538493706 tEnd=0.481912781 < [4/7] 17/17 tStart=0.0521913275 tEnd=0 < [2/5] 13/17 tStart=0.538493706 tEnd=1 F 11
-SkOpAngle::afterPart {{{1.17718506,1.99055469}, {1.33099307,2.007357}, {1.464785,2.02678763}, {1.58025348,2.04903817}}} id=2
-SkOpAngle::afterPart {{{1.17718506,1.99055469}, {1.12006187,1.99363948}, {1.06101314,1.99678878}, {1,2}}} id=4
-SkOpAngle::afterPart {{{1.17718506,1.99055469}, {-0.0773608463,1.85350547}, {-2.66357181,1.89131621}, {-7.5,2}}} id=2
-SkOpAngle::after [2/4] 29/29 tStart=0.538493706 tEnd=0.481912781 < [4/8] 1/1 tStart=0.0521913275 tEnd=1 < [2/5] 13/17 tStart=0.538493706 tEnd=1 T 4
-SkOpAngle::afterPart {{{1.17718506,1.99055469}, {1.33099307,2.007357}, {1.464785,2.02678763}, {1.58025348,2.04903817}}} id=2
-SkOpAngle::afterPart {{{1.17718506,1.99055469}, {2.21455765,1.93453399}, {2.61689955,1.89980286}, {2.61714315,1.90242553}}} id=4
-SkOpAngle::afterPart {{{1.17718506,1.99055469}, {-0.0773608463,1.85350547}, {-2.66357181,1.89131621}, {-7.5,2}}} id=2
-SkOpSegment::sortAngles [3] tStart=1 [6]
-SkOpSegment::sortAngles [4] tStart=0.0521913275 [14]
-SkOpSegment::sortAngles [5] tStart=0.222514468 [16]
-SkOpSegment::sortAngles [5] tStart=0.293280033 [17]
-SkOpAngle::after [5/11] 1/1 tStart=0.293280033 tEnd=0.222514468 < [6/15] 21/21 tStart=0.959100004 tEnd=0 < [5/12] 17/21 tStart=0.293280033 tEnd=1 F 11
-SkOpAngle::afterPart {{{0.959100008,2.16359997}, {1.178042,2.11915237}, {1.38787913,2.0811573}, {1.58025348,2.04903817}}} id=5
-SkOpAngle::afterPart {{{0.959100008,2.16359997}, {0,6}}} id=6
-SkOpAngle::afterPart {{{0.959100008,2.16359997}, {-1.22742501,2.60748826}, {-4.3220339,3.6949153}, {0,6}}} id=5
-SkOpAngle::after [5/11] 1/1 tStart=0.293280033 tEnd=0.222514468 < [6/16] 5/5 tStart=0.959100004 tEnd=1 < [5/12] 17/21 tStart=0.293280033 tEnd=1 T 4
-SkOpAngle::afterPart {{{0.959100008,2.16359997}, {1.178042,2.11915237}, {1.38787913,2.0811573}, {1.58025348,2.04903817}}} id=5
-SkOpAngle::afterPart {{{0.959100008,2.16359997}, {1,2}}} id=6
-SkOpAngle::afterPart {{{0.959100008,2.16359997}, {-1.22742501,2.60748826}, {-4.3220339,3.6949153}, {0,6}}} id=5
-SkOpSegment::sortAngles [5] tStart=1 [10]
-SkOpSegment::sortAngles [6] tStart=0 [11]
-SkOpSegment::sortAngles [6] tStart=0.959100004 [18]
-SkOpSegment::debugShowActiveSpans id=1 (0,6 0.293506175,4.82597542 1.04645705,3.96781874 1.58881736,3.34967732) t=0 (0,6) tEnd=1 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=2 (1.58881736,3.34967732 2.89432383,1.86175978 2.97965813,1.76450205 -7.5,2) t=0 (1.58881736,3.34967732) tEnd=0.481912781 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=2 (1.58881736,3.34967732 2.89432383,1.86175978 2.97965813,1.76450205 -7.5,2) t=0.481912781 (1.58025348,2.04903817) tEnd=0.538493706 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=2 (1.58881736,3.34967732 2.89432383,1.86175978 2.97965813,1.76450205 -7.5,2) t=0.538493706 (1.17718506,1.99055469) tEnd=1 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=3 (-7.5,2 0,6) t=0 (-7.5,2) tEnd=1 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=4 (1,2 2.16902828,1.93847215 2.61688614,1.89965844 2.61714315,1.90242553) t=0 (1,2) tEnd=0.0521913275 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=4 (1,2 2.16902828,1.93847215 2.61688614,1.89965844 2.61714315,1.90242553) t=0.0521913275 (1.17718506,1.99055469) tEnd=1 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=5 (2.61714315,1.90242553 2.61827874,1.91464937 -6.11562443,2.7383337 0,6) t=0 (2.61714315,1.90242553) tEnd=0.222514468 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=5 (2.61714315,1.90242553 2.61827874,1.91464937 -6.11562443,2.7383337 0,6) t=0.222514468 (1.58025348,2.04903817) tEnd=0.293280033 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=5 (2.61714315,1.90242553 2.61827874,1.91464937 -6.11562443,2.7383337 0,6) t=0.293280033 (0.959100008,2.16359997) tEnd=1 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=6 (0,6 1,2) t=0 (0,6) tEnd=0.959100004 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=6 (0,6 1,2) t=0.959100004 (0.959100008,2.16359997) tEnd=1 windSum=? windValue=1 oppValue=0
--SkOpSegment::findTop- baseAngle
-SkOpAngle::dumpOne [4/8] next=2/5 sect=1/1 s=0.0521913275 [14] e=1 [8] sgn=-1 windVal=1 windSum=? operand
-SkOpAngle::dumpOne [2/5] next=4/7 sect=13/17 s=0.538493706 [13] e=1 [4] sgn=-1 windVal=1 windSum=? stop
-SkOpAngle::dumpOne [4/7] next=2/4 sect=17/17 s=0.0521913275 [14] e=0 [7] sgn=1 windVal=1 windSum=? operand
-SkOpAngle::dumpOne [2/4] next=4/8 sect=29/29 s=0.538493706 [13] e=0.481912781 [15] sgn=1 windVal=1 windSum=? stop
--SkOpSegment::findTop- firstAngle
-SkOpAngle::dumpOne [4/8] next=2/5 sect=1/1 s=0.0521913275 [14] e=1 [8] sgn=-1 windVal=1 windSum=? operand
-SkOpAngle::dumpOne [2/5] next=4/7 sect=13/17 s=0.538493706 [13] e=1 [4] sgn=-1 windVal=1 windSum=? stop
-SkOpAngle::dumpOne [4/7] next=2/4 sect=17/17 s=0.0521913275 [14] e=0 [7] sgn=1 windVal=1 windSum=? operand
-SkOpAngle::dumpOne [2/4] next=4/8 sect=29/29 s=0.538493706 [13] e=0.481912781 [15] sgn=1 windVal=1 windSum=? stop
-SkDCubic::clockwise pt1dist=0.00263265113 pt2dist=-0.00745519926
-SkOpSegment::findTop id=4 s=1 e=0.0521913275 (+) cw=1 swap=0 inflections=1 monotonic=0
-SkOpSegment::markWinding id=4 (1,2 2.16902828,1.93847215 2.61688614,1.89965844 2.61714315,1.90242553) t=0.0521913275 [14] (1.17718506,1.99055469) tEnd=1 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
-SkOpSegment::markWinding id=4 (1,2 2.16902828,1.93847215 2.61688614,1.89965844 2.61714315,1.90242553) t=0.0521913275 [14] (1.17718506,1.99055469) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
-SkOpSegment::markWinding id=5 (2.61714315,1.90242553 2.61827874,1.91464937 -6.11562443,2.7383337 0,6) t=0 [9] (2.61714315,1.90242553) tEnd=0.222514468 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
-SkOpSegment::activeOp id=4 t=1 tEnd=0.0521913275 op=sect miFrom=0 miTo=0 suFrom=1 suTo=0 result=0
-SkOpSegment::markDone id=4 (1,2 2.16902828,1.93847215 2.61688614,1.89965844 2.61714315,1.90242553) t=0.0521913275 [14] (1.17718506,1.99055469) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
-bridgeOp chase.append id=4 windSum=1
-SkOpSegment::markWinding id=2 (1.58881736,3.34967732 2.89432383,1.86175978 2.97965813,1.76450205 -7.5,2) t=0.538493706 [13] (1.17718506,1.99055469) tEnd=1 newWindSum=1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
-SkOpSegment::markWinding id=3 (-7.5,2 0,6) t=0 [5] (-7.5,2) tEnd=1 newWindSum=1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
-SkOpSegment::markAngle last segment=3 span=6
-SkOpSegment::markWinding id=4 (1,2 2.16902828,1.93847215 2.61688614,1.89965844 2.61714315,1.90242553) t=0 [7] (1,2) tEnd=0.0521913275 newWindSum=1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
-SkOpSegment::markWinding id=6 (0,6 1,2) t=0.959100004 [18] (0.959100008,2.16359997) tEnd=1 newWindSum=1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
-SkOpSegment::markAngle last segment=6 span=18 windSum=1
-SkOpSegment::markWinding id=2 (1.58881736,3.34967732 2.89432383,1.86175978 2.97965813,1.76450205 -7.5,2) t=0.481912781 [15] (1.58025348,2.04903817) tEnd=0.538493706 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
-SkOpSegment::markAngle last segment=2 span=15 windSum=1
-SkOpSegment::debugShowActiveSpans id=1 (0,6 0.293506175,4.82597542 1.04645705,3.96781874 1.58881736,3.34967732) t=0 (0,6) tEnd=1 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=2 (1.58881736,3.34967732 2.89432383,1.86175978 2.97965813,1.76450205 -7.5,2) t=0 (1.58881736,3.34967732) tEnd=0.481912781 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=2 (1.58881736,3.34967732 2.89432383,1.86175978 2.97965813,1.76450205 -7.5,2) t=0.481912781 (1.58025348,2.04903817) tEnd=0.538493706 windSum=1 windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=2 (1.58881736,3.34967732 2.89432383,1.86175978 2.97965813,1.76450205 -7.5,2) t=0.538493706 (1.17718506,1.99055469) tEnd=1 windSum=1 windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=3 (-7.5,2 0,6) t=0 (-7.5,2) tEnd=1 windSum=1 windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=4 (1,2 2.16902828,1.93847215 2.61688614,1.89965844 2.61714315,1.90242553) t=0 (1,2) tEnd=0.0521913275 windSum=1 windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=5 (2.61714315,1.90242553 2.61827874,1.91464937 -6.11562443,2.7383337 0,6) t=0 (2.61714315,1.90242553) tEnd=0.222514468 windSum=1 windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=5 (2.61714315,1.90242553 2.61827874,1.91464937 -6.11562443,2.7383337 0,6) t=0.222514468 (1.58025348,2.04903817) tEnd=0.293280033 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=5 (2.61714315,1.90242553 2.61827874,1.91464937 -6.11562443,2.7383337 0,6) t=0.293280033 (0.959100008,2.16359997) tEnd=1 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=6 (0,6 1,2) t=0 (0,6) tEnd=0.959100004 windSum=? windValue=1 oppValue=0
-SkOpSegment::debugShowActiveSpans id=6 (0,6 1,2) t=0.959100004 (0.959100008,2.16359997) tEnd=1 windSum=1 windValue=1 oppValue=0
-SkOpSegment::activeOp id=2 t=0.538493706 tEnd=1 op=sect miFrom=0 miTo=1 suFrom=1 suTo=1 result=1
+<div id="cubics45u_release">
+seg=-1 {{{1, 3}, {1.84861219f, 5.54583645f}, {3.41736698f, 3.77081728f}, {4.48402119f, 2.56391668f}}}
+seg=-1 {{{4.48402119f, 2.56391668f}, {4.67430639f, 2.34861207f}, {4.84861231f, 2.15138769f}, {5, 2}}}
+seg=-1 {{{5, 2}, {1, 3}}}
+op union
+seg=-1 {{{3, 4}, {2.61882615f, 4.38117361f}, {2.52823925f, 4.03588009f}, {2.7282393f, 3.51794004f}}}
+seg=-1 {{{2.7282393f, 3.51794004f}, {3.05293441f, 2.67707705f}, {4.14352131f, 1.38117373f}, {6, 2}}}
+seg=-1 {{{6, 2}, {3, 4}}}
+debugShowCubicIntersection wtTs[0]=1 {{{3,4}, {2.61882615,4.38117361}, {2.52823925,4.03588009}, {2.7282393,3.51794004}}} {{2.7282393,3.51794004}} wnTs[0]=0 {{{2.7282393,3.51794004}, {3.05293441,2.67707705}, {4.14352131,1.38117373}, {6,2}}}
+debugShowCubicLineIntersection wtTs[0]=0 {{{3,4}, {2.61882615,4.38117361}, {2.52823925,4.03588009}, {2.7282393,3.51794004}}} {{3,4}} wnTs[0]=1 {{{6,2}, {3,4}}}
+debugShowCubicLineIntersection wtTs[0]=1 {{{2.7282393,3.51794004}, {3.05293441,2.67707705}, {4.14352131,1.38117373}, {6,2}}} {{6,2}} wnTs[0]=0 {{{6,2}, {3,4}}}
+debugShowCubicIntersection wtTs[0]=0 {{{3,4}, {2.61882615,4.38117361}, {2.52823925,4.03588009}, {2.7282393,3.51794004}}} {{3,4}} wtTs[1]=0.322114632 {{2.72210693,4.16072464}} wnTs[0]=0.589197 {{{1,3}, {1.84861219,5.54583645}, {3.41736698,3.77081728}, {4.48402119,2.56391668}}} wnTs[1]=0.516302729
+SkOpSegment::addT insert t=0.589197265 segID=-1 spanID=-1
+SkOpSegment::addT insert t=0.322114632 segID=-1 spanID=-1
+SkOpSegment::addT insert t=0.516302729 segID=-1 spanID=-1
+debugShowCubicIntersection no intersect {{{2.7282393,3.51794004}, {3.05293441,2.67707705}, {4.14352131,1.38117373}, {6,2}}} {{{1,3}, {1.84861219,5.54583645}, {3.41736698,3.77081728}, {4.48402119,2.56391668}}}
+debugShowCubicIntersection no intersect {{{2.7282393,3.51794004}, {3.05293441,2.67707705}, {4.14352131,1.38117373}, {6,2}}} {{{4.48402119,2.56391668}, {4.67430639,2.34861207}, {4.84861231,2.15138769}, {5,2}}}
+debugShowCubicLineIntersection wtTs[0]=0.437504678 {{{2.7282393,3.51794004}, {3.05293441,2.67707705}, {4.14352131,1.38117373}, {6,2}}} {{3.5942049,2.35144877}} wnTs[0]=0.351449 {{{5,2}, {1,3}}}
+SkOpSegment::addT insert t=0.437504678 segID=-1 spanID=-1
+SkOpSegment::addT insert t=0.351448746 segID=-1 spanID=-1
+debugShowCubicLineIntersection wtTs[0]=0.589250227 {{{1,3}, {1.84861219,5.54583645}, {3.41736698,3.77081728}, {4.48402119,2.56391668}}} {{3.00020218,3.99986529}} wnTs[0]=0.999933 {{{6,2}, {3,4}}}
+SkOpSegment::addT insert t=0.999932596 segID=-1 spanID=-1
+SkOpSegment::addT insert t=0.589250227 segID=-1 spanID=-1
+debugShowCubicLineIntersection no intersect {{{4.48402119,2.56391668}, {4.67430639,2.34861207}, {4.84861231,2.15138769}, {5,2}}} {{{6,2}, {3,4}}}
+debugShowLineIntersection no intersect {{{6,2}, {3,4}}} {{{5,2}, {1,3}}}
+debugShowCubicIntersection wtTs[0]=1 {{{1,3}, {1.84861219,5.54583645}, {3.41736698,3.77081728}, {4.48402119,2.56391668}}} {{4.48402119,2.56391668}} wnTs[0]=0 {{{4.48402119,2.56391668}, {4.67430639,2.34861207}, {4.84861231,2.15138769}, {5,2}}}
+debugShowCubicLineIntersection wtTs[0]=0 {{{1,3}, {1.84861219,5.54583645}, {3.41736698,3.77081728}, {4.48402119,2.56391668}}} {{1,3}} wnTs[0]=1 {{{5,2}, {1,3}}}
+debugShowCubicLineIntersection wtTs[0]=1 {{{4.48402119,2.56391668}, {4.67430639,2.34861207}, {4.84861231,2.15138769}, {5,2}}} {{5,2}} wnTs[0]=0 {{{5,2}, {1,3}}}
+SkOpSegment::sortAngles [-1] tStart=0 [-1]
+SkOpAngle::after [-1/-1] 18/17 tStart=0 tEnd=0.322114632 < [-1/-1] 1/1 tStart=0.589197265 tEnd=0.589250227 < [-1/-1] 17/17 tStart=0.589197265 tEnd=0.516302729 T 5
+SkOpAngle::afterPart {{{3,4}, {2.87721833,4.1227816}, {2.78458726,4.17018661}, {2.72210693,4.16072464}}} id=-1
+SkOpAngle::afterPart {{{3,4}, {3.00006742,3.99995506}, {3.00013476,3.99991025}, {3.00020218,3.99986529}}} id=-1
+SkOpAngle::afterPart {{{3,4}, {2.9072112,4.06185918}, {2.81442231,4.11606536}, {2.72210693,4.16072464}}} id=-1
+SkOpAngle::after [-1/-1] 18/17 tStart=0 tEnd=0.322114632 < [-1/-1] 1/1 tStart=1 tEnd=0.999932596 < [-1/-1] 1/1 tStart=0.589197265 tEnd=0.589250227 F 11
+SkOpAngle::afterPart {{{3,4}, {2.87721833,4.1227816}, {2.78458726,4.17018661}, {2.72210693,4.16072464}}} id=-1
+SkOpAngle::afterPart {{{3,4}, {3.00020218,3.99986529}}} id=-1
+SkOpAngle::afterPart {{{3,4}, {3.00006742,3.99995506}, {3.00013476,3.99991025}, {3.00020218,3.99986529}}} id=-1
+SkOpAngle::after [-1/-1] 1/1 tStart=0.589197265 tEnd=0.589250227 < [-1/-1] 1/1 tStart=1 tEnd=0.999932596 < [-1/-1] 17/17 tStart=0.589197265 tEnd=0.516302729 T 12
+SkOpAngle::afterPart {{{3,4}, {3.00006742,3.99995506}, {3.00013476,3.99991025}, {3.00020218,3.99986529}}} id=-1
+SkOpAngle::afterPart {{{3,4}, {3.00020218,3.99986529}}} id=-1
+SkOpAngle::afterPart {{{3,4}, {2.9072112,4.06185918}, {2.81442231,4.11606536}, {2.72210693,4.16072464}}} id=-1
+SkOpSegment::sortAngles [-1] tStart=0.322114632 [-1]
+SkOpAngle::after [-1/-1] 29/1 tStart=0.322114632 tEnd=0 < [-1/-1] 17/13 tStart=0.516302729 tEnd=0 < [-1/-1] 13/5 tStart=0.322114632 tEnd=1 F 11
+SkOpAngle::afterPart {{{2.72210693,4.16072464}, {2.78458726,4.17018661}, {2.87721833,4.1227816}, {3,4}}} id=-1
+SkOpAngle::afterPart {{{2.72210693,4.16072464}, {2.06824885,4.47704065}, {1.43814079,4.31442231}, {1,3}}} id=-1
+SkOpAngle::afterPart {{{2.72210693,4.16072464}, {2.59061803,4.14081206}, {2.59266219,3.86904402}, {2.7282393,3.51794004}}} id=-1
+SkOpAngle::after [-1/-1] 29/1 tStart=0.322114632 tEnd=0 < [-1/-1] 1/1 tStart=0.516302729 tEnd=0.589197265 < [-1/-1] 13/5 tStart=0.322114632 tEnd=1 T 12
+SkOpAngle::afterPart {{{2.72210693,4.16072464}, {2.78458726,4.17018661}, {2.87721833,4.1227816}, {3,4}}} id=-1
+SkOpAngle::afterPart {{{2.72210693,4.16072464}, {2.81442231,4.11606536}, {2.9072112,4.06185918}, {3,4}}} id=-1
+SkOpAngle::afterPart {{{2.72210693,4.16072464}, {2.59061803,4.14081206}, {2.59266219,3.86904402}, {2.7282393,3.51794004}}} id=-1
+SkOpSegment::sortAngles [-1] tStart=0.437504678 [-1]
+SkOpAngle::after [-1/-1] 17/21 tStart=0.437504678 tEnd=0 < [-1/-1] 1/1 tStart=0.351448746 tEnd=0 < [-1/-1] 1/1 tStart=0.437504678 tEnd=1 T 11
+SkOpAngle::afterPart {{{3.5942049,2.35144877}, {3.15895005,2.69507766}, {2.87029493,3.15005855}, {2.7282393,3.51794004}}} id=-1
+SkOpAngle::afterPart {{{3.5942049,2.35144877}, {5,2}}} id=-1
+SkOpAngle::afterPart {{{3.5942049,2.35144877}, {4.15380764,1.9096486}, {4.95573942,1.65191312}, {6,2}}} id=-1
+SkOpAngle::after [-1/-1] 17/21 tStart=0.437504678 tEnd=0 < [-1/-1] 17/17 tStart=0.351448746 tEnd=1 < [-1/-1] 1/1 tStart=0.351448746 tEnd=0 F 12
+SkOpAngle::afterPart {{{3.5942049,2.35144877}, {3.15895005,2.69507766}, {2.87029493,3.15005855}, {2.7282393,3.51794004}}} id=-1
+SkOpAngle::afterPart {{{3.5942049,2.35144877}, {1,3}}} id=-1
+SkOpAngle::afterPart {{{3.5942049,2.35144877}, {5,2}}} id=-1
+SkOpAngle::after [-1/-1] 1/1 tStart=0.351448746 tEnd=0 < [-1/-1] 17/17 tStart=0.351448746 tEnd=1 < [-1/-1] 1/1 tStart=0.437504678 tEnd=1 F 5
+SkOpAngle::afterPart {{{3.5942049,2.35144877}, {5,2}}} id=-1
+SkOpAngle::afterPart {{{3.5942049,2.35144877}, {1,3}}} id=-1
+SkOpAngle::afterPart {{{3.5942049,2.35144877}, {4.15380764,1.9096486}, {4.95573942,1.65191312}, {6,2}}} id=-1
+SkOpAngle::after [-1/-1] 1/1 tStart=0.437504678 tEnd=1 < [-1/-1] 17/17 tStart=0.351448746 tEnd=1 < [-1/-1] 17/21 tStart=0.437504678 tEnd=0 T 11
+SkOpAngle::afterPart {{{3.5942049,2.35144877}, {4.15380764,1.9096486}, {4.95573942,1.65191312}, {6,2}}} id=-1
+SkOpAngle::afterPart {{{3.5942049,2.35144877}, {1,3}}} id=-1
+SkOpAngle::afterPart {{{3.5942049,2.35144877}, {3.15895005,2.69507766}, {2.87029493,3.15005855}, {2.7282393,3.51794004}}} id=-1
+SkOpSegment::sortAngles [-1] tStart=0.999932596 [-1]
+SkOpAngle::after [-1/-1] 1/1 tStart=0.999932596 tEnd=0 < [-1/-1] 17/17 tStart=0.589250227 tEnd=0.589197265 < [-1/-1] 17/17 tStart=0.999932596 tEnd=1 T 11
+SkOpAngle::afterPart {{{3.00020218,3.99986529}, {6,2}}} id=-1
+SkOpAngle::afterPart {{{3.00020218,3.99986529}, {3.00013476,3.99991025}, {3.00006742,3.99995506}, {3,4}}} id=-1
+SkOpAngle::afterPart {{{3.00020218,3.99986529}, {3,4}}} id=-1
+SkOpAngle::after [-1/-1] 1/1 tStart=0.999932596 tEnd=0 < [-1/-1] 1/1 tStart=0.589250227 tEnd=1 < [-1/-1] 17/17 tStart=0.589250227 tEnd=0.589197265 T 12
+SkOpAngle::afterPart {{{3.00020218,3.99986529}, {6,2}}} id=-1
+SkOpAngle::afterPart {{{3.00020218,3.99986529}, {3.52305312,3.65123542}, {4.04589321,3.05965083}, {4.48402119,2.56391668}}} id=-1
+SkOpAngle::afterPart {{{3.00020218,3.99986529}, {3.00013476,3.99991025}, {3.00006742,3.99995506}, {3,4}}} id=-1
+SkOpSegment::sortAngles [-1] tStart=1 [-1]
+SkOpSegment::sortAngles [-1] tStart=0.516302729 [-1]
+SkOpSegment::sortAngles [-1] tStart=0.589197265 [-1]
+SkOpSegment::sortAngles [-1] tStart=0.589250227 [-1]
+SkOpSegment::sortAngles [-1] tStart=0.351448746 [-1]
+SkOpSegment::debugShowActiveSpans id=-1 (3,4 2.61882615,4.38117361 2.52823925,4.03588009 2.7282393,3.51794004) t=0 (3,4) tEnd=0.322114632 windSum=? windValue=1
+SkOpSegment::debugShowActiveSpans id=-1 (3,4 2.61882615,4.38117361 2.52823925,4.03588009 2.7282393,3.51794004) t=0.322114632 (2.72210693,4.16072464) tEnd=1 windSum=? windValue=1
+SkOpSegment::debugShowActiveSpans id=-1 (2.7282393,3.51794004 3.05293441,2.67707705 4.14352131,1.38117373 6,2) t=0 (2.7282393,3.51794004) tEnd=0.437504678 windSum=? windValue=1
+SkOpSegment::debugShowActiveSpans id=-1 (2.7282393,3.51794004 3.05293441,2.67707705 4.14352131,1.38117373 6,2) t=0.437504678 (3.5942049,2.35144877) tEnd=1 windSum=? windValue=1
+SkOpSegment::debugShowActiveSpans id=-1 (6,2 3,4) t=0 (6,2) tEnd=0.999932596 windSum=? windValue=1
+SkOpSegment::debugShowActiveSpans id=-1 (6,2 3,4) t=0.999932596 (3.00020218,3.99986529) tEnd=1 windSum=? windValue=1
+SkOpSegment::debugShowActiveSpans id=-1 (1,3 1.84861219,5.54583645 3.41736698,3.77081728 4.48402119,2.56391668) t=0 (1,3) tEnd=0.516302729 windSum=? windValue=1
+SkOpSegment::debugShowActiveSpans id=-1 (1,3 1.84861219,5.54583645 3.41736698,3.77081728 4.48402119,2.56391668) t=0.516302729 (2.72210693,4.16072464) tEnd=0.589197265 windSum=? windValue=1
+SkOpSegment::debugShowActiveSpans id=-1 (1,3 1.84861219,5.54583645 3.41736698,3.77081728 4.48402119,2.56391668) t=0.589197265 (3,4) tEnd=0.589250227 windSum=? windValue=1
+SkOpSegment::debugShowActiveSpans id=-1 (1,3 1.84861219,5.54583645 3.41736698,3.77081728 4.48402119,2.56391668) t=0.589250227 (3.00020218,3.99986529) tEnd=1 windSum=? windValue=1
+SkOpSegment::debugShowActiveSpans id=-1 (4.48402119,2.56391668 4.67430639,2.34861207 4.84861231,2.15138769 5,2) t=0 (4.48402119,2.56391668) tEnd=1 windSum=? windValue=1
+SkOpSegment::debugShowActiveSpans id=-1 (5,2 1,3) t=0 (5,2) tEnd=0.351448746 windSum=? windValue=1
+SkOpSegment::debugShowActiveSpans id=-1 (5,2 1,3) t=0.351448746 (3.5942049,2.35144877) tEnd=1 windSum=? windValue=1
+SkOpSpan::sortableTop dir=kTop seg=-1 t=0.161057316 pt=(2.83844042,4.12995338)
+SkOpSpan::sortableTop [0] valid=1 operand=0 span=-1 ccw=0 seg=-1 {{{5, 2}, {1, 3}}} t=0.540389895 pt=(2.83844042,2.54039001) slope=(-4,1)
+SkOpSpan::sortableTop [1] valid=1 operand=1 span=-1 ccw=1 seg=-1 {{{2.7282393f, 3.51794004f}, {3.05293441f, 2.67707705f}, {4.14352131f, 1.38117373f}, {6, 2}}} t=0.0928134153 pt=(2.83844042,3.27394509) slope=(1.40059553,-2.71475011)
+SkOpSpan::sortableTop [2] valid=1 operand=0 span=-1 ccw=1 seg=-1 {{{1, 3}, {1.84861219f, 5.54583645f}, {3.41736698f, 3.77081728f}, {4.48402119f, 2.56391668f}}} t=0.546866125 pt=(2.83844042,4.09965467) slope=(3.81218461,-2.15374068)
+SkOpSpan::sortableTop [3] valid=1 operand=1 span=-1 ccw=0 seg=-1 {{{3, 4}, {2.61882615f, 4.38117361f}, {2.52823925f, 4.03588009f}, {2.7282393f, 3.51794004f}}} t=0.161057316 pt=(2.83844042,4.12995338) slope=(-0.862714624,0.484601174)
+SkOpSegment::markWinding id=-1 (5,2 1,3) t=0.351448746 [-1] (3.5942049,2.35144877) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
+SkOpSegment::markWinding id=-1 (1,3 1.84861219,5.54583645 3.41736698,3.77081728 4.48402119,2.56391668) t=0 [-1] (1,3) tEnd=0.516302729 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markWinding id=-1 (5,2 1,3) t=0.351448746 [-1] (3.5942049,2.35144877) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
+SkOpSegment::markWinding id=-1 (2.7282393,3.51794004 3.05293441,2.67707705 4.14352131,1.38117373 6,2) t=0 [-1] (2.7282393,3.51794004) tEnd=0.437504678 newWindSum=-1 newOppSum=1 oppSum=1 windSum=-1 windValue=1 oppValue=0
+SkOpSegment::markWinding id=-1 (2.7282393,3.51794004 3.05293441,2.67707705 4.14352131,1.38117373 6,2) t=0 [-1] (2.7282393,3.51794004) tEnd=0.437504678 newWindSum=-1 newOppSum=1 oppSum=1 windSum=-1 windValue=1 oppValue=0
+SkOpSegment::markWinding id=-1 (3,4 2.61882615,4.38117361 2.52823925,4.03588009 2.7282393,3.51794004) t=0.322114632 [-1] (2.72210693,4.16072464) tEnd=1 newWindSum=-1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markWinding id=-1 (1,3 1.84861219,5.54583645 3.41736698,3.77081728 4.48402119,2.56391668) t=0.516302729 [-1] (2.72210693,4.16072464) tEnd=0.589197265 newWindSum=1 newOppSum=-1 oppSum=-1 windSum=1 windValue=1 oppValue=0
+SkOpSegment::markWinding id=-1 (1,3 1.84861219,5.54583645 3.41736698,3.77081728 4.48402119,2.56391668) t=0.516302729 [-1] (2.72210693,4.16072464) tEnd=0.589197265 newWindSum=1 newOppSum=-1 oppSum=-1 windSum=1 windValue=1 oppValue=0
+SkOpSegment::markWinding id=-1 (3,4 2.61882615,4.38117361 2.52823925,4.03588009 2.7282393,3.51794004) t=0 [-1] (3,4) tEnd=0.322114632 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
+SkOpSegment::markWinding id=-1 (3,4 2.61882615,4.38117361 2.52823925,4.03588009 2.7282393,3.51794004) t=0 [-1] (3,4) tEnd=0.322114632 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
+SkOpSegment::activeOp id=-1 t=0.322114632 tEnd=0 op=union miFrom=0 miTo=0 suFrom=0 suTo=1 result=1
+SkOpSegment::markWinding id=-1 (1,3 1.84861219,5.54583645 3.41736698,3.77081728 4.48402119,2.56391668) t=0.589197265 [-1] (3,4) tEnd=0.589250227 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markAngle last segment=-1 span=-1 windSum=?
+SkOpSegment::markWinding id=-1 (6,2 3,4) t=0.999932596 [-1] (3.00020218,3.99986529) tEnd=1 newWindSum=-1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markAngle last segment=-1 span=-1 windSum=-1
+SkOpSegment::findNextOp
+SkOpAngle::dumpOne [-1/-1] next=-1/-1 sect=18/17 s=0 [-1] e=0.322114632 [-1] sgn=-1 windVal=1 windSum=-1 oppVal=0 oppSum=0 operand
+SkOpAngle::dumpOne [-1/-1] next=-1/-1 sect=1/1 s=0.589197265 [-1] e=0.589250227 [-1] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=0
+SkOpAngle::dumpOne [-1/-1] next=-1/-1 sect=1/1 s=1 [-1] e=0.999932596 [-1] sgn=1 windVal=1 windSum=-1 oppVal=0 oppSum=1 operand
+SkOpAngle::dumpOne [-1/-1] next=-1/-1 sect=17/17 s=0.589197265 [-1] e=0.516302729 [-1] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=-1
+SkOpSegment::activeOp id=-1 t=0.589197265 tEnd=0.589250227 op=union miFrom=0 miTo=1 suFrom=0 suTo=0 result=1
+SkOpSegment::findNextOp chase.append segment=-1 span=-1 windSum=-2147483647
+SkOpSegment::activeOp id=-1 t=1 tEnd=0.999932596 op=union miFrom=1 miTo=1 suFrom=0 suTo=1 result=0
+SkOpSegment::markDone id=-1 (6,2 3,4) t=0.999932596 [-1] (3.00020218,3.99986529) tEnd=1 newWindSum=-1 newOppSum=1 oppSum=1 windSum=-1 windValue=1 oppValue=0
+SkOpSegment::findNextOp chase.append segment=-1 span=-1 windSum=-1
+SkOpSegment::activeOp id=-1 t=0.589197265 tEnd=0.516302729 op=union miFrom=1 miTo=0 suFrom=1 suTo=1 result=0
+SkOpSegment::markDone id=-1 (1,3 1.84861219,5.54583645 3.41736698,3.77081728 4.48402119,2.56391668) t=0.516302729 [-1] (2.72210693,4.16072464) tEnd=0.589197265 newWindSum=1 newOppSum=-1 oppSum=-1 windSum=1 windValue=1 oppValue=0
+SkOpSegment::markDone id=-1 (3,4 2.61882615,4.38117361 2.52823925,4.03588009 2.7282393,3.51794004) t=0 [-1] (3,4) tEnd=0.322114632 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
+SkOpSegment::findNextOp from:[-1] to:[-1] start=7083452 end=7084028
+bridgeOp current id=-1 from=(2.72210693,4.16072464) to=(3,4)
+path.moveTo(2.72210693,4.16072464);
+path.cubicTo(2.78458714,4.17018652, 2.87721825,4.12278175, 3,4);
+SkOpSegment::markDone id=-1 (1,3 1.84861219,5.54583645 3.41736698,3.77081728 4.48402119,2.56391668) t=0.589197265 [-1] (3,4) tEnd=0.589250227 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
+SkOpSegment::markWinding id=-1 (6,2 3,4) t=0 [-1] (6,2) tEnd=0.999932596 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markWinding id=-1 (2.7282393,3.51794004 3.05293441,2.67707705 4.14352131,1.38117373 6,2) t=0.437504678 [-1] (3.5942049,2.35144877) tEnd=1 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markAngle last segment=-1 span=-1 windSum=1
+SkOpSegment::markWinding id=-1 (1,3 1.84861219,5.54583645 3.41736698,3.77081728 4.48402119,2.56391668) t=0.589250227 [-1] (3.00020218,3.99986529) tEnd=1 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markWinding id=-1 (4.48402119,2.56391668 4.67430639,2.34861207 4.84861231,2.15138769 5,2) t=0 [-1] (4.48402119,2.56391668) tEnd=1 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markWinding id=-1 (5,2 1,3) t=0 [-1] (5,2) tEnd=0.351448746 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markAngle last segment=-1 span=-1 windSum=1
+SkOpSegment::debugShowActiveSpans id=-1 (3,4 2.61882615,4.38117361 2.52823925,4.03588009 2.7282393,3.51794004) t=0.322114632 (2.72210693,4.16072464) tEnd=1 windSum=-1 oppSum=1 windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=-1 (2.7282393,3.51794004 3.05293441,2.67707705 4.14352131,1.38117373 6,2) t=0 (2.7282393,3.51794004) tEnd=0.437504678 windSum=-1 oppSum=1 windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=-1 (2.7282393,3.51794004 3.05293441,2.67707705 4.14352131,1.38117373 6,2) t=0.437504678 (3.5942049,2.35144877) tEnd=1 windSum=1 oppSum=0 windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=-1 (6,2 3,4) t=0 (6,2) tEnd=0.999932596 windSum=1 oppSum=0 windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=-1 (1,3 1.84861219,5.54583645 3.41736698,3.77081728 4.48402119,2.56391668) t=0 (1,3) tEnd=0.516302729 windSum=1 oppSum=0 windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=-1 (1,3 1.84861219,5.54583645 3.41736698,3.77081728 4.48402119,2.56391668) t=0.589250227 (3.00020218,3.99986529) tEnd=1 windSum=1 oppSum=0 windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=-1 (4.48402119,2.56391668 4.67430639,2.34861207 4.84861231,2.15138769 5,2) t=0 (4.48402119,2.56391668) tEnd=1 windSum=1 oppSum=0 windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=-1 (5,2 1,3) t=0 (5,2) tEnd=0.351448746 windSum=1 oppSum=0 windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=-1 (5,2 1,3) t=0.351448746 (3.5942049,2.35144877) tEnd=1 windSum=1 oppSum=0 windValue=1 oppValue=0
+SkOpSegment::activeOp id=-1 t=0.999932596 tEnd=0 op=union miFrom=0 miTo=0 suFrom=1 suTo=0 result=1
SkOpSegment::findNextOp simple
-SkOpSegment::markDone id=2 (1.58881736,3.34967732 2.89432383,1.86175978 2.97965813,1.76450205 -7.5,2) t=0.538493706 [13] (1.17718506,1.99055469) tEnd=1 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=0
-bridgeOp current id=2 from=(1.17718506,1.99055469) to=(-7.5,2)
-path.moveTo(1.17718506,1.99055469);
-path.cubicTo(-0.0773608461,1.85350549, -2.66357183,1.89131618, -7.5,2);
-SkOpSegment::markWinding id=1 (0,6 0.293506175,4.82597542 1.04645705,3.96781874 1.58881736,3.34967732) t=0 [1] (0,6) tEnd=1 newWindSum=1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
-SkOpSegment::markWinding id=2 (1.58881736,3.34967732 2.89432383,1.86175978 2.97965813,1.76450205 -7.5,2) t=0 [3] (1.58881736,3.34967732) tEnd=0.481912781 newWindSum=1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
-SkOpSegment::markAngle last segment=2 span=15 windSum=1
-SkOpSegment::markWinding id=6 (0,6 1,2) t=0 [11] (0,6) tEnd=0.959100004 newWindSum=2 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
-SkOpSegment::markAngle last segment=6 span=18 windSum=1
-SkOpSegment::markWinding id=5 (2.61714315,1.90242553 2.61827874,1.91464937 -6.11562443,2.7383337 0,6) t=0.293280033 [17] (0.959100008,2.16359997) tEnd=1 newWindSum=2 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
-SkOpSegment::markAngle last segment=5 span=17 windSum=2
+SkOpSegment::markDone id=-1 (6,2 3,4) t=0 [-1] (6,2) tEnd=0.999932596 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
+bridgeOp current id=-1 from=(3.00020218,3.99986529) to=(6,2)
SkOpSegment::findNextOp
-SkOpAngle::dumpOne [3/6] next=1/1 sect=13/13 s=1 [6] e=0 [5] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=1
-SkOpAngle::dumpOne [1/1] next=6/14 sect=5/5 s=0 [1] e=1 [2] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=1
-SkOpAngle::dumpOne [6/14] next=5/13 sect=5/5 s=0 [11] e=0.959100004 [18] sgn=-1 windVal=1 windSum=2 oppVal=0 oppSum=1 operand
-SkOpAngle::dumpOne [5/13] next=3/6 sect=13/5 s=1 [10] e=0.293280033 [17] sgn=1 windVal=1 windSum=2 oppVal=0 oppSum=1 operand
-SkOpSegment::activeOp id=1 t=0 tEnd=1 op=sect miFrom=0 miTo=1 suFrom=1 suTo=1 result=1
-SkOpSegment::findNextOp chase.append segment=2 span=15 windSum=1
-SkOpSegment::activeOp id=6 t=0 tEnd=0.959100004 op=sect miFrom=1 miTo=1 suFrom=1 suTo=1 result=0
-SkOpSegment::markDone id=6 (0,6 1,2) t=0 [11] (0,6) tEnd=0.959100004 newWindSum=2 newOppSum=1 oppSum=1 windSum=2 windValue=1 oppValue=0
-SkOpSegment::findNextOp chase.append segment=6 span=18 windSum=1
-SkOpSegment::activeOp id=5 t=1 tEnd=0.293280033 op=sect miFrom=1 miTo=1 suFrom=1 suTo=1 result=0
-SkOpSegment::markDone id=5 (2.61714315,1.90242553 2.61827874,1.91464937 -6.11562443,2.7383337 0,6) t=0.293280033 [17] (0.959100008,2.16359997) tEnd=1 newWindSum=2 newOppSum=1 oppSum=1 windSum=2 windValue=1 oppValue=0
-SkOpSegment::findNextOp chase.append segment=5 span=17 windSum=2
-SkOpSegment::markDone id=3 (-7.5,2 0,6) t=0 [5] (-7.5,2) tEnd=1 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=0
-SkOpSegment::findNextOp from:[3] to:[1] start=43971536 end=43971632
-bridgeOp current id=3 from=(-7.5,2) to=(0,6)
+SkOpAngle::dumpOne [-1/-1] next=-1/-1 sect=1/1 s=0.437504678 [-1] e=1 [-1] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=0 operand
+SkOpAngle::dumpOne [-1/-1] next=-1/-1 sect=17/17 s=0.351448746 [-1] e=1 [-1] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=0
+SkOpAngle::dumpOne [-1/-1] next=-1/-1 sect=17/21 s=0.437504678 [-1] e=0 [-1] sgn=1 windVal=1 windSum=-1 oppVal=0 oppSum=1 operand
+SkOpAngle::dumpOne [-1/-1] next=-1/-1 sect=1/1 s=0.351448746 [-1] e=0 [-1] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=0
+SkOpSegment::activeOp id=-1 t=0.351448746 tEnd=1 op=union miFrom=0 miTo=1 suFrom=1 suTo=1 result=0
+SkOpSegment::markDone id=-1 (5,2 1,3) t=0.351448746 [-1] (3.5942049,2.35144877) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
+SkOpSegment::markDone id=-1 (1,3 1.84861219,5.54583645 3.41736698,3.77081728 4.48402119,2.56391668) t=0 [-1] (1,3) tEnd=0.516302729 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
+SkOpSegment::activeOp id=-1 t=0.437504678 tEnd=0 op=union miFrom=1 miTo=1 suFrom=1 suTo=0 result=0
+SkOpSegment::markDone id=-1 (2.7282393,3.51794004 3.05293441,2.67707705 4.14352131,1.38117373 6,2) t=0 [-1] (2.7282393,3.51794004) tEnd=0.437504678 newWindSum=-1 newOppSum=1 oppSum=1 windSum=-1 windValue=1 oppValue=0
+SkOpSegment::markDone id=-1 (3,4 2.61882615,4.38117361 2.52823925,4.03588009 2.7282393,3.51794004) t=0.322114632 [-1] (2.72210693,4.16072464) tEnd=1 newWindSum=-1 newOppSum=1 oppSum=1 windSum=-1 windValue=1 oppValue=0
+SkOpSegment::activeOp id=-1 t=0.351448746 tEnd=0 op=union miFrom=1 miTo=0 suFrom=0 suTo=0 result=1
+SkOpSegment::markDone id=-1 (2.7282393,3.51794004 3.05293441,2.67707705 4.14352131,1.38117373 6,2) t=0.437504678 [-1] (3.5942049,2.35144877) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
+SkOpSegment::findNextOp from:[-1] to:[-1] start=7083836 end=7082508
+bridgeOp current id=-1 from=(6,2) to=(3.5942049,2.35144877)
+path.moveTo(3.00020218,3.99986529);
+path.lineTo(6,2);
+path.cubicTo(4.9557395,1.65191317, 4.15380764,1.90964866, 3.5942049,2.35144877);
+SkOpSegment::findNextOp simple
+SkOpSegment::markDone id=-1 (5,2 1,3) t=0 [-1] (5,2) tEnd=0.351448746 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
+bridgeOp current id=-1 from=(3.5942049,2.35144877) to=(5,2)
SkOpSegment::findNextOp simple
-SkOpSegment::markDone id=1 (0,6 0.293506175,4.82597542 1.04645705,3.96781874 1.58881736,3.34967732) t=0 [1] (0,6) tEnd=1 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=0
-bridgeOp current id=1 from=(0,6) to=(1.58881736,3.34967732)
-path.lineTo(0,6);
-path.cubicTo(0.293506175,4.82597542, 1.04645705,3.96781874, 1.58881736,3.34967732);
-SkOpSegment::markWinding id=5 (2.61714315,1.90242553 2.61827874,1.91464937 -6.11562443,2.7383337 0,6) t=0.222514468 [16] (1.58025348,2.04903817) tEnd=0.293280033 newWindSum=1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
-SkOpSegment::markAngle last segment=5 span=17 windSum=2
+SkOpSegment::markDone id=-1 (4.48402119,2.56391668 4.67430639,2.34861207 4.84861231,2.15138769 5,2) t=0 [-1] (4.48402119,2.56391668) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
+bridgeOp current id=-1 from=(5,2) to=(4.48402119,2.56391668)
+path.lineTo(5,2);
+path.cubicTo(4.84861231,2.15138769, 4.67430639,2.34861207, 4.48402119,2.56391668);
SkOpSegment::findNextOp
-SkOpAngle::dumpOne [2/2] next=5/9 sect=29/25 s=0.481912781 [15] e=0 [3] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=1
-SkOpAngle::dumpOne [5/9] next=2/3 sect=1/1 s=0.222514468 [16] e=0 [9] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=0 operand
-SkOpAngle::dumpOne [2/3] next=5/10 sect=13/13 s=0.481912781 [15] e=0.538493706 [13] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=0
-SkOpAngle::dumpOne [5/10] next=2/2 sect=17/17 s=0.222514468 [16] e=0.293280033 [17] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=1 operand
-SkOpSegment::activeOp id=5 t=0.222514468 tEnd=0 op=sect miFrom=0 miTo=0 suFrom=1 suTo=0 result=0
-SkOpSegment::markDone id=5 (2.61714315,1.90242553 2.61827874,1.91464937 -6.11562443,2.7383337 0,6) t=0 [9] (2.61714315,1.90242553) tEnd=0.222514468 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
-SkOpSegment::activeOp id=2 t=0.481912781 tEnd=0.538493706 op=sect miFrom=0 miTo=1 suFrom=0 suTo=0 result=0
-SkOpSegment::markDone id=2 (1.58881736,3.34967732 2.89432383,1.86175978 2.97965813,1.76450205 -7.5,2) t=0.481912781 [15] (1.58025348,2.04903817) tEnd=0.538493706 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
-SkOpSegment::activeOp id=5 t=0.222514468 tEnd=0.293280033 op=sect miFrom=1 miTo=1 suFrom=0 suTo=1 result=1
-SkOpSegment::markDone id=2 (1.58881736,3.34967732 2.89432383,1.86175978 2.97965813,1.76450205 -7.5,2) t=0 [3] (1.58881736,3.34967732) tEnd=0.481912781 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=0
-SkOpSegment::findNextOp from:[2] to:[5] start=2579180 end=2579276
-bridgeOp current id=2 from=(1.58881736,3.34967732) to=(1.58025348,2.04903817)
-path.cubicTo(2.2179575,2.63263083, 2.56372523,2.23855114, 1.58025348,2.04903817);
+SkOpAngle::dumpOne [-1/-1] next=-1/-1 sect=1/1 s=0.589250227 [-1] e=1 [-1] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=0
+SkOpAngle::dumpOne [-1/-1] next=-1/-1 sect=17/17 s=0.589250227 [-1] e=0.589197265 [-1] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=0 done unorderable
+SkOpAngle::dumpOne [-1/-1] next=-1/-1 sect=17/17 s=0.999932596 [-1] e=1 [-1] sgn=-1 windVal=1 windSum=-1 oppVal=0 oppSum=1 done unorderable operand
+SkOpAngle::dumpOne [-1/-1] next=-1/-1 sect=1/1 s=0.999932596 [-1] e=0 [-1] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=0 done operand
+SkOpSegment::activeOp id=-1 t=0.589250227 tEnd=0.589197265 op=union miFrom=1 miTo=0 suFrom=0 suTo=0 result=1
+SkOpSegment::activeOp id=-1 t=0.999932596 tEnd=1 op=union miFrom=0 miTo=0 suFrom=0 suTo=1 result=1
+SkOpSegment::activeOp id=-1 t=0.999932596 tEnd=0 op=union miFrom=0 miTo=0 suFrom=1 suTo=0 result=1
+SkOpSegment::markDone id=-1 (1,3 1.84861219,5.54583645 3.41736698,3.77081728 4.48402119,2.56391668) t=0.589250227 [-1] (3.00020218,3.99986529) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
+SkOpSegment::findNextOp from:[-1] to:[-1] start=7083932 end=7083244
+bridgeOp current id=-1 from=(4.48402119,2.56391668) to=(3.00020218,3.99986529)
+path.cubicTo(4.04589319,3.0596509, 3.52305317,3.65123534, 3.00020218,3.99986529);
+path.close();
+</div>
+
+<div id="cubics45u_debug">
+seg=1 {{{1, 3}, {1.84861219f, 5.54583645f}, {3.41736698f, 3.77081728f}, {4.48402119f, 2.56391668f}}}
+seg=2 {{{4.48402119f, 2.56391668f}, {4.67430639f, 2.34861207f}, {4.84861231f, 2.15138769f}, {5, 2}}}
+seg=3 {{{5, 2}, {1, 3}}}
+op union
+seg=4 {{{3, 4}, {2.61882615f, 4.38117361f}, {2.52823925f, 4.03588009f}, {2.7282393f, 3.51794004f}}}
+seg=5 {{{2.7282393f, 3.51794004f}, {3.05293441f, 2.67707705f}, {4.14352131f, 1.38117373f}, {6, 2}}}
+seg=6 {{{6, 2}, {3, 4}}}
+debugShowCubicIntersection wtTs[0]=1 {{{3,4}, {2.61882615,4.38117361}, {2.52823925,4.03588009}, {2.7282393,3.51794004}}} {{2.7282393,3.51794004}} wnTs[0]=0 {{{2.7282393,3.51794004}, {3.05293441,2.67707705}, {4.14352131,1.38117373}, {6,2}}}
+debugShowCubicLineIntersection wtTs[0]=0 {{{3,4}, {2.61882615,4.38117361}, {2.52823925,4.03588009}, {2.7282393,3.51794004}}} {{3,4}} wnTs[0]=1 {{{6,2}, {3,4}}}
+debugShowCubicLineIntersection wtTs[0]=1 {{{2.7282393,3.51794004}, {3.05293441,2.67707705}, {4.14352131,1.38117373}, {6,2}}} {{6,2}} wnTs[0]=0 {{{6,2}, {3,4}}}
+debugShowCubicIntersection wtTs[0]=0 {{{3,4}, {2.61882615,4.38117361}, {2.52823925,4.03588009}, {2.7282393,3.51794004}}} {{3,4}} wtTs[1]=0.322114632 {{2.72210693,4.16072464}} wnTs[0]=0.589197 {{{1,3}, {1.84861219,5.54583645}, {3.41736698,3.77081728}, {4.48402119,2.56391668}}} wnTs[1]=0.516302729
+SkOpSegment::addT insert t=0.589197265 segID=1 spanID=13
+SkOpSegment::addT insert t=0.322114632 segID=4 spanID=14
+SkOpSegment::addT insert t=0.516302729 segID=1 spanID=15
+debugShowCubicIntersection no intersect {{{2.7282393,3.51794004}, {3.05293441,2.67707705}, {4.14352131,1.38117373}, {6,2}}} {{{1,3}, {1.84861219,5.54583645}, {3.41736698,3.77081728}, {4.48402119,2.56391668}}}
+debugShowCubicIntersection no intersect {{{2.7282393,3.51794004}, {3.05293441,2.67707705}, {4.14352131,1.38117373}, {6,2}}} {{{4.48402119,2.56391668}, {4.67430639,2.34861207}, {4.84861231,2.15138769}, {5,2}}}
+debugShowCubicLineIntersection wtTs[0]=0.437504678 {{{2.7282393,3.51794004}, {3.05293441,2.67707705}, {4.14352131,1.38117373}, {6,2}}} {{3.5942049,2.35144877}} wnTs[0]=0.351449 {{{5,2}, {1,3}}}
+SkOpSegment::addT insert t=0.437504678 segID=5 spanID=16
+SkOpSegment::addT insert t=0.351448746 segID=3 spanID=17
+debugShowCubicLineIntersection wtTs[0]=0.589250227 {{{1,3}, {1.84861219,5.54583645}, {3.41736698,3.77081728}, {4.48402119,2.56391668}}} {{3.00020218,3.99986529}} wnTs[0]=0.999933 {{{6,2}, {3,4}}}
+SkOpSegment::addT insert t=0.999932596 segID=6 spanID=18
+SkOpSegment::addT insert t=0.589250227 segID=1 spanID=19
+debugShowCubicLineIntersection no intersect {{{4.48402119,2.56391668}, {4.67430639,2.34861207}, {4.84861231,2.15138769}, {5,2}}} {{{6,2}, {3,4}}}
+debugShowLineIntersection no intersect {{{6,2}, {3,4}}} {{{5,2}, {1,3}}}
+debugShowCubicIntersection wtTs[0]=1 {{{1,3}, {1.84861219,5.54583645}, {3.41736698,3.77081728}, {4.48402119,2.56391668}}} {{4.48402119,2.56391668}} wnTs[0]=0 {{{4.48402119,2.56391668}, {4.67430639,2.34861207}, {4.84861231,2.15138769}, {5,2}}}
+debugShowCubicLineIntersection wtTs[0]=0 {{{1,3}, {1.84861219,5.54583645}, {3.41736698,3.77081728}, {4.48402119,2.56391668}}} {{1,3}} wnTs[0]=1 {{{5,2}, {1,3}}}
+debugShowCubicLineIntersection wtTs[0]=1 {{{4.48402119,2.56391668}, {4.67430639,2.34861207}, {4.84861231,2.15138769}, {5,2}}} {{5,2}} wnTs[0]=0 {{{5,2}, {1,3}}}
+SkOpSegment::sortAngles [4] tStart=0 [7]
+SkOpAngle::after [4/1] 18/17 tStart=0 tEnd=0.322114632 < [1/12] 1/1 tStart=0.589197265 tEnd=0.589250227 < [1/11] 17/17 tStart=0.589197265 tEnd=0.516302729 T 5
+SkOpAngle::afterPart {{{3,4}, {2.87721833,4.1227816}, {2.78458726,4.17018661}, {2.72210693,4.16072464}}} id=4
+SkOpAngle::afterPart {{{3,4}, {3.00006742,3.99995506}, {3.00013476,3.99991025}, {3.00020218,3.99986529}}} id=1
+SkOpAngle::afterPart {{{3,4}, {2.9072112,4.06185918}, {2.81442231,4.11606536}, {2.72210693,4.16072464}}} id=1
+SkOpAngle::after [4/1] 18/17 tStart=0 tEnd=0.322114632 < [6/8] 1/1 tStart=1 tEnd=0.999932596 < [1/12] 1/1 tStart=0.589197265 tEnd=0.589250227 F 11
+SkOpAngle::afterPart {{{3,4}, {2.87721833,4.1227816}, {2.78458726,4.17018661}, {2.72210693,4.16072464}}} id=4
+SkOpAngle::afterPart {{{3,4}, {3.00020218,3.99986529}}} id=6
+SkOpAngle::afterPart {{{3,4}, {3.00006742,3.99995506}, {3.00013476,3.99991025}, {3.00020218,3.99986529}}} id=1
+SkOpAngle::after [1/12] 1/1 tStart=0.589197265 tEnd=0.589250227 < [6/8] 1/1 tStart=1 tEnd=0.999932596 < [1/11] 17/17 tStart=0.589197265 tEnd=0.516302729 T 12
+SkOpAngle::afterPart {{{3,4}, {3.00006742,3.99995506}, {3.00013476,3.99991025}, {3.00020218,3.99986529}}} id=1
+SkOpAngle::afterPart {{{3,4}, {3.00020218,3.99986529}}} id=6
+SkOpAngle::afterPart {{{3,4}, {2.9072112,4.06185918}, {2.81442231,4.11606536}, {2.72210693,4.16072464}}} id=1
+SkOpSegment::sortAngles [4] tStart=0.322114632 [14]
+SkOpAngle::after [4/2] 29/1 tStart=0.322114632 tEnd=0 < [1/9] 17/13 tStart=0.516302729 tEnd=0 < [4/3] 13/5 tStart=0.322114632 tEnd=1 F 11
+SkOpAngle::afterPart {{{2.72210693,4.16072464}, {2.78458726,4.17018661}, {2.87721833,4.1227816}, {3,4}}} id=4
+SkOpAngle::afterPart {{{2.72210693,4.16072464}, {2.06824885,4.47704065}, {1.43814079,4.31442231}, {1,3}}} id=1
+SkOpAngle::afterPart {{{2.72210693,4.16072464}, {2.59061803,4.14081206}, {2.59266219,3.86904402}, {2.7282393,3.51794004}}} id=4
+SkOpAngle::after [4/2] 29/1 tStart=0.322114632 tEnd=0 < [1/10] 1/1 tStart=0.516302729 tEnd=0.589197265 < [4/3] 13/5 tStart=0.322114632 tEnd=1 T 12
+SkOpAngle::afterPart {{{2.72210693,4.16072464}, {2.78458726,4.17018661}, {2.87721833,4.1227816}, {3,4}}} id=4
+SkOpAngle::afterPart {{{2.72210693,4.16072464}, {2.81442231,4.11606536}, {2.9072112,4.06185918}, {3,4}}} id=1
+SkOpAngle::afterPart {{{2.72210693,4.16072464}, {2.59061803,4.14081206}, {2.59266219,3.86904402}, {2.7282393,3.51794004}}} id=4
+SkOpSegment::sortAngles [5] tStart=0.437504678 [16]
+SkOpAngle::after [5/4] 17/21 tStart=0.437504678 tEnd=0 < [3/15] 1/1 tStart=0.351448746 tEnd=0 < [5/5] 1/1 tStart=0.437504678 tEnd=1 T 11
+SkOpAngle::afterPart {{{3.5942049,2.35144877}, {3.15895005,2.69507766}, {2.87029493,3.15005855}, {2.7282393,3.51794004}}} id=5
+SkOpAngle::afterPart {{{3.5942049,2.35144877}, {5,2}}} id=3
+SkOpAngle::afterPart {{{3.5942049,2.35144877}, {4.15380764,1.9096486}, {4.95573942,1.65191312}, {6,2}}} id=5
+SkOpAngle::after [5/4] 17/21 tStart=0.437504678 tEnd=0 < [3/16] 17/17 tStart=0.351448746 tEnd=1 < [3/15] 1/1 tStart=0.351448746 tEnd=0 F 12
+SkOpAngle::afterPart {{{3.5942049,2.35144877}, {3.15895005,2.69507766}, {2.87029493,3.15005855}, {2.7282393,3.51794004}}} id=5
+SkOpAngle::afterPart {{{3.5942049,2.35144877}, {1,3}}} id=3
+SkOpAngle::afterPart {{{3.5942049,2.35144877}, {5,2}}} id=3
+SkOpAngle::after [3/15] 1/1 tStart=0.351448746 tEnd=0 < [3/16] 17/17 tStart=0.351448746 tEnd=1 < [5/5] 1/1 tStart=0.437504678 tEnd=1 F 5
+SkOpAngle::afterPart {{{3.5942049,2.35144877}, {5,2}}} id=3
+SkOpAngle::afterPart {{{3.5942049,2.35144877}, {1,3}}} id=3
+SkOpAngle::afterPart {{{3.5942049,2.35144877}, {4.15380764,1.9096486}, {4.95573942,1.65191312}, {6,2}}} id=5
+SkOpAngle::after [5/5] 1/1 tStart=0.437504678 tEnd=1 < [3/16] 17/17 tStart=0.351448746 tEnd=1 < [5/4] 17/21 tStart=0.437504678 tEnd=0 T 11
+SkOpAngle::afterPart {{{3.5942049,2.35144877}, {4.15380764,1.9096486}, {4.95573942,1.65191312}, {6,2}}} id=5
+SkOpAngle::afterPart {{{3.5942049,2.35144877}, {1,3}}} id=3
+SkOpAngle::afterPart {{{3.5942049,2.35144877}, {3.15895005,2.69507766}, {2.87029493,3.15005855}, {2.7282393,3.51794004}}} id=5
+SkOpSegment::sortAngles [6] tStart=0.999932596 [18]
+SkOpAngle::after [6/6] 1/1 tStart=0.999932596 tEnd=0 < [1/13] 17/17 tStart=0.589250227 tEnd=0.589197265 < [6/7] 17/17 tStart=0.999932596 tEnd=1 T 11
+SkOpAngle::afterPart {{{3.00020218,3.99986529}, {6,2}}} id=6
+SkOpAngle::afterPart {{{3.00020218,3.99986529}, {3.00013476,3.99991025}, {3.00006742,3.99995506}, {3,4}}} id=1
+SkOpAngle::afterPart {{{3.00020218,3.99986529}, {3,4}}} id=6
+SkOpAngle::after [6/6] 1/1 tStart=0.999932596 tEnd=0 < [1/14] 1/1 tStart=0.589250227 tEnd=1 < [1/13] 17/17 tStart=0.589250227 tEnd=0.589197265 T 12
+SkOpAngle::afterPart {{{3.00020218,3.99986529}, {6,2}}} id=6
+SkOpAngle::afterPart {{{3.00020218,3.99986529}, {3.52305312,3.65123542}, {4.04589321,3.05965083}, {4.48402119,2.56391668}}} id=1
+SkOpAngle::afterPart {{{3.00020218,3.99986529}, {3.00013476,3.99991025}, {3.00006742,3.99995506}, {3,4}}} id=1
+SkOpSegment::sortAngles [6] tStart=1 [12]
+SkOpSegment::sortAngles [1] tStart=0.516302729 [15]
+SkOpSegment::sortAngles [1] tStart=0.589197265 [13]
+SkOpSegment::sortAngles [1] tStart=0.589250227 [19]
+SkOpSegment::sortAngles [3] tStart=0.351448746 [17]
+SkOpSegment::debugShowActiveSpans id=4 (3,4 2.61882615,4.38117361 2.52823925,4.03588009 2.7282393,3.51794004) t=0 (3,4) tEnd=0.322114632 windSum=? windValue=1
+SkOpSegment::debugShowActiveSpans id=4 (3,4 2.61882615,4.38117361 2.52823925,4.03588009 2.7282393,3.51794004) t=0.322114632 (2.72210693,4.16072464) tEnd=1 windSum=? windValue=1
+SkOpSegment::debugShowActiveSpans id=5 (2.7282393,3.51794004 3.05293441,2.67707705 4.14352131,1.38117373 6,2) t=0 (2.7282393,3.51794004) tEnd=0.437504678 windSum=? windValue=1
+SkOpSegment::debugShowActiveSpans id=5 (2.7282393,3.51794004 3.05293441,2.67707705 4.14352131,1.38117373 6,2) t=0.437504678 (3.5942049,2.35144877) tEnd=1 windSum=? windValue=1
+SkOpSegment::debugShowActiveSpans id=6 (6,2 3,4) t=0 (6,2) tEnd=0.999932596 windSum=? windValue=1
+SkOpSegment::debugShowActiveSpans id=6 (6,2 3,4) t=0.999932596 (3.00020218,3.99986529) tEnd=1 windSum=? windValue=1
+SkOpSegment::debugShowActiveSpans id=1 (1,3 1.84861219,5.54583645 3.41736698,3.77081728 4.48402119,2.56391668) t=0 (1,3) tEnd=0.516302729 windSum=? windValue=1
+SkOpSegment::debugShowActiveSpans id=1 (1,3 1.84861219,5.54583645 3.41736698,3.77081728 4.48402119,2.56391668) t=0.516302729 (2.72210693,4.16072464) tEnd=0.589197265 windSum=? windValue=1
+SkOpSegment::debugShowActiveSpans id=1 (1,3 1.84861219,5.54583645 3.41736698,3.77081728 4.48402119,2.56391668) t=0.589197265 (3,4) tEnd=0.589250227 windSum=? windValue=1
+SkOpSegment::debugShowActiveSpans id=1 (1,3 1.84861219,5.54583645 3.41736698,3.77081728 4.48402119,2.56391668) t=0.589250227 (3.00020218,3.99986529) tEnd=1 windSum=? windValue=1
+SkOpSegment::debugShowActiveSpans id=2 (4.48402119,2.56391668 4.67430639,2.34861207 4.84861231,2.15138769 5,2) t=0 (4.48402119,2.56391668) tEnd=1 windSum=? windValue=1
+SkOpSegment::debugShowActiveSpans id=3 (5,2 1,3) t=0 (5,2) tEnd=0.351448746 windSum=? windValue=1
+SkOpSegment::debugShowActiveSpans id=3 (5,2 1,3) t=0.351448746 (3.5942049,2.35144877) tEnd=1 windSum=? windValue=1
+SkOpSpan::sortableTop dir=kTop seg=4 t=0.161057316 pt=(2.83844042,4.12995338)
+SkOpSpan::sortableTop [0] valid=1 operand=0 span=17 ccw=0 seg=3 {{{5, 2}, {1, 3}}} t=0.540389895 pt=(2.83844042,2.54039001) slope=(-4,1)
+SkOpSpan::sortableTop [1] valid=1 operand=1 span=9 ccw=1 seg=5 {{{2.7282393f, 3.51794004f}, {3.05293441f, 2.67707705f}, {4.14352131f, 1.38117373f}, {6, 2}}} t=0.0928134153 pt=(2.83844042,3.27394509) slope=(1.40059553,-2.71475011)
+SkOpSpan::sortableTop [2] valid=1 operand=0 span=15 ccw=1 seg=1 {{{1, 3}, {1.84861219f, 5.54583645f}, {3.41736698f, 3.77081728f}, {4.48402119f, 2.56391668f}}} t=0.546866125 pt=(2.83844042,4.09965467) slope=(3.81218461,-2.15374068)
+SkOpSpan::sortableTop [3] valid=1 operand=1 span=7 ccw=0 seg=4 {{{3, 4}, {2.61882615f, 4.38117361f}, {2.52823925f, 4.03588009f}, {2.7282393f, 3.51794004f}}} t=0.161057316 pt=(2.83844042,4.12995338) slope=(-0.862714624,0.484601174)
+SkOpSegment::markWinding id=3 (5,2 1,3) t=0.351448746 [17] (3.5942049,2.35144877) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
+SkOpSegment::markWinding id=1 (1,3 1.84861219,5.54583645 3.41736698,3.77081728 4.48402119,2.56391668) t=0 [1] (1,3) tEnd=0.516302729 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markWinding id=3 (5,2 1,3) t=0.351448746 [17] (3.5942049,2.35144877) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
+SkOpSegment::markWinding id=5 (2.7282393,3.51794004 3.05293441,2.67707705 4.14352131,1.38117373 6,2) t=0 [9] (2.7282393,3.51794004) tEnd=0.437504678 newWindSum=-1 newOppSum=1 oppSum=1 windSum=-1 windValue=1 oppValue=0
+SkOpSegment::markWinding id=5 (2.7282393,3.51794004 3.05293441,2.67707705 4.14352131,1.38117373 6,2) t=0 [9] (2.7282393,3.51794004) tEnd=0.437504678 newWindSum=-1 newOppSum=1 oppSum=1 windSum=-1 windValue=1 oppValue=0
+SkOpSegment::markWinding id=4 (3,4 2.61882615,4.38117361 2.52823925,4.03588009 2.7282393,3.51794004) t=0.322114632 [14] (2.72210693,4.16072464) tEnd=1 newWindSum=-1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markWinding id=1 (1,3 1.84861219,5.54583645 3.41736698,3.77081728 4.48402119,2.56391668) t=0.516302729 [15] (2.72210693,4.16072464) tEnd=0.589197265 newWindSum=1 newOppSum=-1 oppSum=-1 windSum=1 windValue=1 oppValue=0
+SkOpSegment::markWinding id=1 (1,3 1.84861219,5.54583645 3.41736698,3.77081728 4.48402119,2.56391668) t=0.516302729 [15] (2.72210693,4.16072464) tEnd=0.589197265 newWindSum=1 newOppSum=-1 oppSum=-1 windSum=1 windValue=1 oppValue=0
+SkOpSegment::markWinding id=4 (3,4 2.61882615,4.38117361 2.52823925,4.03588009 2.7282393,3.51794004) t=0 [7] (3,4) tEnd=0.322114632 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
+SkOpSegment::markWinding id=4 (3,4 2.61882615,4.38117361 2.52823925,4.03588009 2.7282393,3.51794004) t=0 [7] (3,4) tEnd=0.322114632 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
+SkOpSegment::activeOp id=4 t=0.322114632 tEnd=0 op=union miFrom=0 miTo=0 suFrom=0 suTo=1 result=1
+SkOpSegment::markWinding id=1 (1,3 1.84861219,5.54583645 3.41736698,3.77081728 4.48402119,2.56391668) t=0.589197265 [13] (3,4) tEnd=0.589250227 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markAngle last segment=1 span=19 windSum=?
+SkOpSegment::markWinding id=6 (6,2 3,4) t=0.999932596 [18] (3.00020218,3.99986529) tEnd=1 newWindSum=-1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markAngle last segment=6 span=18 windSum=-1
SkOpSegment::findNextOp
-SkOpAngle::dumpOne [5/11] next=6/16 sect=1/1 s=0.293280033 [17] e=0.222514468 [16] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=1 operand
-SkOpAngle::dumpOne [6/16] next=5/12 sect=5/5 s=0.959100004 [18] e=1 [12] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=1 operand
-SkOpAngle::dumpOne [5/12] next=6/15 sect=17/21 s=0.293280033 [17] e=1 [10] sgn=-1 windVal=1 windSum=2 oppVal=0 oppSum=1 done operand
-SkOpAngle::dumpOne [6/15] next=5/11 sect=21/21 s=0.959100004 [18] e=0 [11] sgn=1 windVal=1 windSum=2 oppVal=0 oppSum=1 done operand
-SkOpSegment::activeOp id=6 t=0.959100004 tEnd=1 op=sect miFrom=1 miTo=1 suFrom=0 suTo=1 result=1
-SkOpSegment::activeOp id=5 t=0.293280033 tEnd=1 op=sect miFrom=1 miTo=1 suFrom=1 suTo=1 result=0
-SkOpSegment::activeOp id=6 t=0.959100004 tEnd=0 op=sect miFrom=1 miTo=1 suFrom=1 suTo=1 result=0
-SkOpSegment::markDone id=5 (2.61714315,1.90242553 2.61827874,1.91464937 -6.11562443,2.7383337 0,6) t=0.222514468 [16] (1.58025348,2.04903817) tEnd=0.293280033 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=0
-SkOpSegment::findNextOp from:[5] to:[6] start=2579372 end=2578764
-bridgeOp current id=5 from=(1.58025348,2.04903817) to=(0.959100008,2.16359997)
-path.cubicTo(1.38787913,2.08115721, 1.17804205,2.11915231, 0.959100008,2.16359997);
+SkOpAngle::dumpOne [4/1] next=1/12 sect=18/17 s=0 [7] e=0.322114632 [14] sgn=-1 windVal=1 windSum=-1 oppVal=0 oppSum=0 operand
+SkOpAngle::dumpOne [1/12] next=6/8 sect=1/1 s=0.589197265 [13] e=0.589250227 [19] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=0
+SkOpAngle::dumpOne [6/8] next=1/11 sect=1/1 s=1 [12] e=0.999932596 [18] sgn=1 windVal=1 windSum=-1 oppVal=0 oppSum=1 operand
+SkOpAngle::dumpOne [1/11] next=4/1 sect=17/17 s=0.589197265 [13] e=0.516302729 [15] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=-1
+SkOpSegment::activeOp id=1 t=0.589197265 tEnd=0.589250227 op=union miFrom=0 miTo=1 suFrom=0 suTo=0 result=1
+SkOpSegment::findNextOp chase.append segment=1 span=19 windSum=-2147483647
+SkOpSegment::activeOp id=6 t=1 tEnd=0.999932596 op=union miFrom=1 miTo=1 suFrom=0 suTo=1 result=0
+SkOpSegment::markDone id=6 (6,2 3,4) t=0.999932596 [18] (3.00020218,3.99986529) tEnd=1 newWindSum=-1 newOppSum=1 oppSum=1 windSum=-1 windValue=1 oppValue=0
+SkOpSegment::findNextOp chase.append segment=6 span=18 windSum=-1
+SkOpSegment::activeOp id=1 t=0.589197265 tEnd=0.516302729 op=union miFrom=1 miTo=0 suFrom=1 suTo=1 result=0
+SkOpSegment::markDone id=1 (1,3 1.84861219,5.54583645 3.41736698,3.77081728 4.48402119,2.56391668) t=0.516302729 [15] (2.72210693,4.16072464) tEnd=0.589197265 newWindSum=1 newOppSum=-1 oppSum=-1 windSum=1 windValue=1 oppValue=0
+SkOpSegment::markDone id=4 (3,4 2.61882615,4.38117361 2.52823925,4.03588009 2.7282393,3.51794004) t=0 [7] (3,4) tEnd=0.322114632 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
+SkOpSegment::findNextOp from:[4] to:[1] start=11952148 end=11952772
+bridgeOp current id=4 from=(2.72210693,4.16072464) to=(3,4)
+path.moveTo(2.72210693,4.16072464);
+path.cubicTo(2.78458714,4.17018652, 2.87721825,4.12278175, 3,4);
+SkOpSegment::markDone id=1 (1,3 1.84861219,5.54583645 3.41736698,3.77081728 4.48402119,2.56391668) t=0.589197265 [13] (3,4) tEnd=0.589250227 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
+SkOpSegment::markWinding id=6 (6,2 3,4) t=0 [11] (6,2) tEnd=0.999932596 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markWinding id=5 (2.7282393,3.51794004 3.05293441,2.67707705 4.14352131,1.38117373 6,2) t=0.437504678 [16] (3.5942049,2.35144877) tEnd=1 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markAngle last segment=5 span=16 windSum=1
+SkOpSegment::markWinding id=1 (1,3 1.84861219,5.54583645 3.41736698,3.77081728 4.48402119,2.56391668) t=0.589250227 [19] (3.00020218,3.99986529) tEnd=1 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markWinding id=2 (4.48402119,2.56391668 4.67430639,2.34861207 4.84861231,2.15138769 5,2) t=0 [3] (4.48402119,2.56391668) tEnd=1 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markWinding id=3 (5,2 1,3) t=0 [5] (5,2) tEnd=0.351448746 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markAngle last segment=3 span=17 windSum=1
+SkOpSegment::debugShowActiveSpans id=4 (3,4 2.61882615,4.38117361 2.52823925,4.03588009 2.7282393,3.51794004) t=0.322114632 (2.72210693,4.16072464) tEnd=1 windSum=-1 oppSum=1 windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=5 (2.7282393,3.51794004 3.05293441,2.67707705 4.14352131,1.38117373 6,2) t=0 (2.7282393,3.51794004) tEnd=0.437504678 windSum=-1 oppSum=1 windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=5 (2.7282393,3.51794004 3.05293441,2.67707705 4.14352131,1.38117373 6,2) t=0.437504678 (3.5942049,2.35144877) tEnd=1 windSum=1 oppSum=0 windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=6 (6,2 3,4) t=0 (6,2) tEnd=0.999932596 windSum=1 oppSum=0 windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=1 (1,3 1.84861219,5.54583645 3.41736698,3.77081728 4.48402119,2.56391668) t=0 (1,3) tEnd=0.516302729 windSum=1 oppSum=0 windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=1 (1,3 1.84861219,5.54583645 3.41736698,3.77081728 4.48402119,2.56391668) t=0.589250227 (3.00020218,3.99986529) tEnd=1 windSum=1 oppSum=0 windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=2 (4.48402119,2.56391668 4.67430639,2.34861207 4.84861231,2.15138769 5,2) t=0 (4.48402119,2.56391668) tEnd=1 windSum=1 oppSum=0 windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=3 (5,2 1,3) t=0 (5,2) tEnd=0.351448746 windSum=1 oppSum=0 windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=3 (5,2 1,3) t=0.351448746 (3.5942049,2.35144877) tEnd=1 windSum=1 oppSum=0 windValue=1 oppValue=0
+SkOpSegment::activeOp id=6 t=0.999932596 tEnd=0 op=union miFrom=0 miTo=0 suFrom=1 suTo=0 result=1
SkOpSegment::findNextOp simple
-SkOpSegment::markDone id=6 (0,6 1,2) t=0.959100004 [18] (0.959100008,2.16359997) tEnd=1 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=0
-bridgeOp current id=6 from=(0.959100008,2.16359997) to=(1,2)
+SkOpSegment::markDone id=6 (6,2 3,4) t=0 [11] (6,2) tEnd=0.999932596 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
+bridgeOp current id=6 from=(3.00020218,3.99986529) to=(6,2)
SkOpSegment::findNextOp
-SkOpAngle::dumpOne [4/7] next=2/4 sect=17/17 s=0.0521913275 [14] e=0 [7] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=1 operand
-SkOpAngle::dumpOne [2/4] next=4/8 sect=29/29 s=0.538493706 [13] e=0.481912781 [15] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=0 done stop
-SkOpAngle::dumpOne [4/8] next=2/5 sect=1/1 s=0.0521913275 [14] e=1 [8] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=0 done operand
-SkOpAngle::dumpOne [2/5] next=4/7 sect=13/17 s=0.538493706 [13] e=1 [4] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=1 done stop
-SkOpSegment::activeOp id=2 t=0.538493706 tEnd=0.481912781 op=sect miFrom=1 miTo=0 suFrom=0 suTo=0 result=0
-SkOpSegment::activeOp id=4 t=0.0521913275 tEnd=1 op=sect miFrom=0 miTo=0 suFrom=0 suTo=1 result=0
-SkOpSegment::activeOp id=2 t=0.538493706 tEnd=1 op=sect miFrom=0 miTo=1 suFrom=1 suTo=1 result=1
-SkOpSegment::markDone id=4 (1,2 2.16902828,1.93847215 2.61688614,1.89965844 2.61714315,1.90242553) t=0 [7] (1,2) tEnd=0.0521913275 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=0
-SkOpSegment::findNextOp from:[4] to:[2] start=2578892 end=2577740
-bridgeOp current id=4 from=(1,2) to=(1.17718506,1.99055469)
-path.lineTo(1,2);
-path.cubicTo(1.0610131,1.99678874, 1.12006187,1.99363947, 1.17718506,1.99055469);
+SkOpAngle::dumpOne [5/5] next=3/16 sect=1/1 s=0.437504678 [16] e=1 [10] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=0 operand
+SkOpAngle::dumpOne [3/16] next=5/4 sect=17/17 s=0.351448746 [17] e=1 [6] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=0
+SkOpAngle::dumpOne [5/4] next=3/15 sect=17/21 s=0.437504678 [16] e=0 [9] sgn=1 windVal=1 windSum=-1 oppVal=0 oppSum=1 operand
+SkOpAngle::dumpOne [3/15] next=5/5 sect=1/1 s=0.351448746 [17] e=0 [5] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=0
+SkOpSegment::activeOp id=3 t=0.351448746 tEnd=1 op=union miFrom=0 miTo=1 suFrom=1 suTo=1 result=0
+SkOpSegment::markDone id=3 (5,2 1,3) t=0.351448746 [17] (3.5942049,2.35144877) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
+SkOpSegment::markDone id=1 (1,3 1.84861219,5.54583645 3.41736698,3.77081728 4.48402119,2.56391668) t=0 [1] (1,3) tEnd=0.516302729 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
+SkOpSegment::activeOp id=5 t=0.437504678 tEnd=0 op=union miFrom=1 miTo=1 suFrom=1 suTo=0 result=0
+SkOpSegment::markDone id=5 (2.7282393,3.51794004 3.05293441,2.67707705 4.14352131,1.38117373 6,2) t=0 [9] (2.7282393,3.51794004) tEnd=0.437504678 newWindSum=-1 newOppSum=1 oppSum=1 windSum=-1 windValue=1 oppValue=0
+SkOpSegment::markDone id=4 (3,4 2.61882615,4.38117361 2.52823925,4.03588009 2.7282393,3.51794004) t=0.322114632 [14] (2.72210693,4.16072464) tEnd=1 newWindSum=-1 newOppSum=1 oppSum=1 windSum=-1 windValue=1 oppValue=0
+SkOpSegment::activeOp id=3 t=0.351448746 tEnd=0 op=union miFrom=1 miTo=0 suFrom=0 suTo=0 result=1
+SkOpSegment::markDone id=5 (2.7282393,3.51794004 3.05293441,2.67707705 4.14352131,1.38117373 6,2) t=0.437504678 [16] (3.5942049,2.35144877) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
+SkOpSegment::findNextOp from:[5] to:[3] start=11952564 end=11951100
+bridgeOp current id=5 from=(6,2) to=(3.5942049,2.35144877)
+path.moveTo(3.00020218,3.99986529);
+path.lineTo(6,2);
+path.cubicTo(4.9557395,1.65191317, 4.15380764,1.90964866, 3.5942049,2.35144877);
+SkOpSegment::findNextOp simple
+SkOpSegment::markDone id=3 (5,2 1,3) t=0 [5] (5,2) tEnd=0.351448746 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
+bridgeOp current id=3 from=(3.5942049,2.35144877) to=(5,2)
+SkOpSegment::findNextOp simple
+SkOpSegment::markDone id=2 (4.48402119,2.56391668 4.67430639,2.34861207 4.84861231,2.15138769 5,2) t=0 [3] (4.48402119,2.56391668) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
+bridgeOp current id=2 from=(5,2) to=(4.48402119,2.56391668)
+path.lineTo(5,2);
+path.cubicTo(4.84861231,2.15138769, 4.67430639,2.34861207, 4.48402119,2.56391668);
+SkOpSegment::findNextOp
+SkOpAngle::dumpOne [1/14] next=1/13 sect=1/1 s=0.589250227 [19] e=1 [2] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=0
+SkOpAngle::dumpOne [1/13] next=6/7 sect=17/17 s=0.589250227 [19] e=0.589197265 [13] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=0 done unorderable
+SkOpAngle::dumpOne [6/7] next=6/6 sect=17/17 s=0.999932596 [18] e=1 [12] sgn=-1 windVal=1 windSum=-1 oppVal=0 oppSum=1 done unorderable operand
+SkOpAngle::dumpOne [6/6] next=1/14 sect=1/1 s=0.999932596 [18] e=0 [11] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=0 done operand
+SkOpSegment::activeOp id=1 t=0.589250227 tEnd=0.589197265 op=union miFrom=1 miTo=0 suFrom=0 suTo=0 result=1
+SkOpSegment::activeOp id=6 t=0.999932596 tEnd=1 op=union miFrom=0 miTo=0 suFrom=0 suTo=1 result=1
+SkOpSegment::activeOp id=6 t=0.999932596 tEnd=0 op=union miFrom=0 miTo=0 suFrom=1 suTo=0 result=1
+SkOpSegment::markDone id=1 (1,3 1.84861219,5.54583645 3.41736698,3.77081728 4.48402119,2.56391668) t=0.589250227 [19] (3.00020218,3.99986529) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
+SkOpSegment::findNextOp from:[1] to:[6] start=11952668 end=11951916
+bridgeOp current id=1 from=(4.48402119,2.56391668) to=(3.00020218,3.99986529)
+path.cubicTo(4.04589319,3.0596509, 3.52305317,3.65123534, 3.00020218,3.99986529);
path.close();
</div>
@@ -229,7 +393,8 @@ path.close();
<script type="text/javascript">
var testDivs = [
- loops59i,
+ cubics45u_release,
+ cubics45u_debug,
];
var decimal_places = 3; // make this 3 to show more precision
@@ -260,6 +425,7 @@ var step_limit = 0;
var draw_active = false;
var draw_add = false;
var draw_angle = 0;
+var draw_coincidence = false;
var draw_deriviatives = 0;
var draw_hints = false;
var draw_id = false;
@@ -280,6 +446,7 @@ var retina_scale = !!window.devicePixelRatio;
var activeCount = 0;
var addCount = 0;
var angleCount = 0;
+var coinCount = 0;
var opCount = 0;
var sectCount = 0;
var sortCount = 0;
@@ -288,6 +455,7 @@ var markCount = 0;
var activeMax = 0;
var addMax = 0;
var angleMax = 0;
+var coinMax = 0;
var sectMax = 0;
var sectMax2 = 0;
var sortMax = 0;
@@ -450,12 +618,15 @@ var MARK_ANGLE_LAST = MARK_DONE_UNARY_CUBIC + 1;
var COMPUTED_SET_1 = MARK_ANGLE_LAST + 1;
var COMPUTED_SET_2 = COMPUTED_SET_1 + 1;
-var ANGLE_AFTER = COMPUTED_SET_2;
+var ANGLE_AFTER = COMPUTED_SET_2 + 1;
var ANGLE_AFTERPART = ANGLE_AFTER + 1;
var ACTIVE_OP = ANGLE_AFTERPART + 1;
-var FRAG_TYPE_LAST = ACTIVE_OP;
+var COIN_MAIN_SPAN = ACTIVE_OP + 1;
+var COIN_OPP_SPAN = COIN_MAIN_SPAN + 1;
+
+var FRAG_TYPE_LAST = COIN_OPP_SPAN;
var REC_TYPE_UNKNOWN = -1;
var REC_TYPE_PATH = 0;
@@ -472,7 +643,8 @@ var REC_TYPE_ANGLE = 10;
var REC_TYPE_ACTIVE_OP = 11;
var REC_TYPE_AFTERPART = 12;
var REC_TYPE_TOP = 13;
-var REC_TYPE_LAST = REC_TYPE_TOP;
+var REC_TYPE_COINCIDENCE = 14;
+var REC_TYPE_LAST = REC_TYPE_COINCIDENCE;
function strs_to_nums(strs) {
var result = [];
@@ -574,7 +746,12 @@ function parse_all(test) {
if (line.lastIndexOf(angleStart, 0) === 0) {
line = line.substr(angleStart.length);
}
+ var coinStart = "SkOpCoincidence::";
+ if (line.lastIndexOf(coinStart, 0) === 0) {
+ line = line.substr(coinStart.length);
+ }
var type = line.lastIndexOf("debugShowActiveSpans", 0) === 0 ? REC_TYPE_ACTIVE
+ : line.lastIndexOf("debugShowCoincidence", 0) === 0 ? REC_TYPE_COINCIDENCE
: line.lastIndexOf("((SkOpSegment*)", 0) === 0 ? REC_TYPE_PATH2
: line.lastIndexOf("debugShowTs", 0) === 0 ? REC_TYPE_COIN
: line.lastIndexOf("afterPart", 0) === 0 ? REC_TYPE_AFTERPART
@@ -608,13 +785,21 @@ function parse_all(test) {
switch (recType) {
case REC_TYPE_ACTIVE:
found = match_regexp(line, lineNo, record, ACTIVE_LINE_SPAN, "debugShowActiveSpans" +
-" id=IDX LINE_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT windValue=IDX oppValue=NUM"
+" id=IDX LINE_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
) || match_regexp(line, lineNo, record, ACTIVE_QUAD_SPAN, "debugShowActiveSpans" +
-" id=IDX QUAD_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT windValue=IDX oppValue=NUM"
+" id=IDX QUAD_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
) || match_regexp(line, lineNo, record, ACTIVE_CONIC_SPAN, "debugShowActiveSpans" +
-" id=IDX CONIC_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT windValue=IDX oppValue=NUM"
+" id=IDX CONIC_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
) || match_regexp(line, lineNo, record, ACTIVE_CUBIC_SPAN, "debugShowActiveSpans" +
-" id=IDX CUBIC_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT windValue=IDX oppValue=NUM"
+" id=IDX CUBIC_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT windValue=IDX"
+ ) || match_regexp(line, lineNo, record, ACTIVE_LINE_SPAN, "debugShowActiveSpans" +
+" id=IDX LINE_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM"
+ ) || match_regexp(line, lineNo, record, ACTIVE_QUAD_SPAN, "debugShowActiveSpans" +
+" id=IDX QUAD_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM"
+ ) || match_regexp(line, lineNo, record, ACTIVE_CONIC_SPAN, "debugShowActiveSpans" +
+" id=IDX CONIC_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM"
+ ) || match_regexp(line, lineNo, record, ACTIVE_CUBIC_SPAN, "debugShowActiveSpans" +
+" id=IDX CUBIC_VAL t=T_VAL PT_VAL tEnd=T_VAL windSum=OPT oppSum=OPT windValue=IDX oppValue=NUM"
);
break;
case REC_TYPE_ACTIVE_OP:
@@ -670,6 +855,13 @@ function parse_all(test) {
case REC_TYPE_COIN:
found = true;
break;
+ case REC_TYPE_COINCIDENCE:
+ found = match_regexp(line, lineNo, record, COIN_MAIN_SPAN, "debugShowCoincidence" +
+" + id=IDX t=T_VAL tEnd=T_VAL"
+ ) || match_regexp(line, lineNo, record, COIN_OPP_SPAN, "debugShowCoincidence" +
+" - id=IDX t=T_VAL tEnd=T_VAL"
+ );
+ break;
case REC_TYPE_COMPUTED:
found = line == "computed quadratics given"
|| match_regexp(line, lineNo, record, COMPUTED_SET_1, "computed quadratics set 1"
@@ -1151,6 +1343,15 @@ function init(test) {
curve = curvePartialByID(test, frags[12], frags[16], frags[17]);
}
break;
+ case REC_TYPE_COINCIDENCE:
+ if (!draw_coincidence) {
+ break;
+ }
+ {
+ var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
+ curve_extremes(curve, angleBounds);
+ }
+ break;
case REC_TYPE_SORT:
if (!draw_sort) {
break;
@@ -2417,6 +2618,7 @@ function draw(test, lines, title) {
var hasOp = false;
var lastActive = 0;
var lastAdd = 0;
+ var lastCoin = 0;
var lastSect = 0;
var lastSort = 0;
var lastMark = 0;
@@ -2432,6 +2634,7 @@ function draw(test, lines, title) {
activeMax = 0;
addMax = 0;
angleMax = 0;
+ coinMax = 0;
opMax = 0;
sectMax = 0;
sectMax2 = 0;
@@ -2518,6 +2721,15 @@ function draw(test, lines, title) {
++angleCount;
bumpStep = true;
}
+ if (recType == REC_TYPE_COINCIDENCE) {
+ ++coinMax;
+ if (!draw_coincidence || !inStepRange) {
+ continue;
+ }
+ lastCoin = tIndex;
+ ++coinCount;
+ bumpStep = true;
+ }
if (recType == REC_TYPE_SECT) {
if (records.length != 2) {
console.log("expect only two elements: " + records.length);
@@ -2616,13 +2828,14 @@ function draw(test, lines, title) {
stepMax = (draw_add ? addMax : 0)
+ (draw_active ? activeMax : 0)
+ (draw_angle ? angleMax : 0)
+ + (draw_coincidence ? coinMax : 0)
+ (draw_op ? opMax : 0)
+ (draw_sort ? sortMax : 0)
+ (draw_top ? topMax : 0)
+ (draw_mark ? markMax : 0)
+ (draw_intersection == 2 ? sectMax : draw_intersection == 3 ? sectMax2 : 0);
if (stepMax == 0) {
- stepMax = addMax + activeMax + angleMax + opMax + sortMax + topMax + markMax;
+ stepMax = addMax + activeMax + angleMax + coinMax + opMax + sortMax + topMax + markMax;
}
drawnPts = [];
drawnLines = [];
@@ -2917,6 +3130,16 @@ function draw(test, lines, title) {
}
++afterIndex;
break;
+ case REC_TYPE_COINCIDENCE:
+ if (!draw_coincidence || (step_limit > 0 && tIndex < lastCoin)) {
+ continue;
+ }
+ focus_enabled = true;
+ ctx.lineWidth = 3;
+ ctx.strokeStyle = "rgba(127,45,63, 0.3)";
+ var curve = curvePartialByID(test, frags[0], frags[1], frags[2]);
+ drawCurve(curve);
+ break;
case REC_TYPE_SECT:
if (!draw_intersection) {
continue;
@@ -3371,12 +3594,13 @@ function draw(test, lines, title) {
}
if (draw_legend) {
var pos = 0;
- var drawSomething = draw_add | draw_active | draw_angle | draw_sort | draw_mark;
+ var drawSomething = draw_add | draw_active | draw_angle | draw_coincidence | draw_sort | draw_mark;
// drawBox(pos++, "yellow", "black", opLetter, true, '');
drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_intersection > 1 ? sectCount : sectMax2, draw_intersection, intersectionKey);
drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_add ? addCount : addMax, draw_add, addKey);
drawBox(pos++, "rgba(0,0,255, 0.3)", "black", draw_active ? activeCount : activeMax, draw_active, activeKey);
drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_angle ? angleCount : angleMax, draw_angle, angleKey);
+ drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_coincidence ? coinCount : coinMax, draw_coincidence, coincidenceKey);
drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_op ? opCount : opMax, draw_op, opKey);
drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_sort ? sortCount : sortMax, draw_sort, sortKey);
drawBox(pos++, "rgba(127,127,0, 0.3)", "black", draw_top ? topCount : topMax, draw_top, topKey);
@@ -3560,6 +3784,7 @@ var activeKey = 'a';
var pathKey = 'b';
var pathBackKey = 'B';
var centerKey = 'c';
+var coincidenceKey = 'C';
var addKey = 'd';
var deriviativesKey = 'f';
var angleKey = 'g';
@@ -3627,6 +3852,10 @@ function doKeyPress(evt) {
setScale(xmin, xmax, ymin, ymax);
redraw();
break;
+ case coincidenceKey:
+ draw_coincidence ^= true;
+ redraw();
+ break;
case controlLinesBackKey:
control_lines = (control_lines + 3) % 4;
redraw();