quad and conic do not intersect
If a quad a conic intersect only where the end of one
is contained by the convex hull of the other, and the
curve contained by the hull is nearly a straight line,
treating it as a line may move the end point to the
other side of the curve.
Detect this by checking to see if the end point is in
the hull, and if so, continue to subdivide the curve
rather than treating it as a line.
This fixes several existing tests that were disabled
earlier this year.
A typo in SkDCurve::nearPoint() prevented detecting when
the end of a line was nearly touching a curve.
Also fixed concidence a bit to get the second half of
tiger further along.
All existing tests, including extended testing in
Release and the first half of tiger, work.
TBR=reed@google.com
BUG=skia:5131
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2338323002
Review-Url: https://codereview.chromium.org/2338323002
diff --git a/src/pathops/SkDConicLineIntersection.cpp b/src/pathops/SkDConicLineIntersection.cpp
index 3bca611..eb32068 100644
--- a/src/pathops/SkDConicLineIntersection.cpp
+++ b/src/pathops/SkDConicLineIntersection.cpp
@@ -21,7 +21,7 @@
, fLine(&l)
, fIntersections(i)
, fAllowNear(true) {
- i->setMax(3); // allow short partial coincidence plus discrete intersection
+ i->setMax(4); // allow short partial coincidence plus discrete intersection
}
LineConicIntersections(const SkDConic& c)
diff --git a/src/pathops/SkOpCoincidence.cpp b/src/pathops/SkOpCoincidence.cpp
index c7a39fc..719c939 100755
--- a/src/pathops/SkOpCoincidence.cpp
+++ b/src/pathops/SkOpCoincidence.cpp
@@ -746,8 +746,8 @@
const SkOpPtT* csExisting = !cs ? coinSeg->existing(coinTs, nullptr) : nullptr;
const SkOpPtT* ceExisting = !ce ? coinSeg->existing(coinTe, nullptr) : nullptr;
FAIL_IF(csExisting && csExisting == ceExisting);
- FAIL_IF(csExisting && (csExisting == ce ||
- csExisting->contains(ceExisting ? ceExisting : ce)));
+// FAIL_IF(csExisting && (csExisting == ce ||
+// csExisting->contains(ceExisting ? ceExisting : ce)));
FAIL_IF(ceExisting && (ceExisting == cs ||
ceExisting->contains(csExisting ? csExisting : cs)));
const SkOpPtT* osExisting = !os ? oppSeg->existing(oppTs, nullptr) : nullptr;
@@ -762,6 +762,9 @@
if (!cs || !os) {
SkOpPtT* csWritable = cs ? const_cast<SkOpPtT*>(cs)
: coinSeg->addT(coinTs);
+ if (csWritable == ce) {
+ return true;
+ }
SkOpPtT* osWritable = os ? const_cast<SkOpPtT*>(os)
: oppSeg->addT(oppTs);
FAIL_IF(!csWritable || !osWritable);
diff --git a/src/pathops/SkPathOpsCurve.cpp b/src/pathops/SkPathOpsCurve.cpp
index 4bc518a..e96c4e8 100644
--- a/src/pathops/SkPathOpsCurve.cpp
+++ b/src/pathops/SkPathOpsCurve.cpp
@@ -14,7 +14,7 @@
int count = SkPathOpsVerbToPoints(verb);
double minX = fCubic.fPts[0].fX;
double maxX = minX;
- for (int index = 0; index < count; ++index) {
+ for (int index = 1; index <= count; ++index) {
minX = SkTMin(minX, fCubic.fPts[index].fX);
maxX = SkTMax(maxX, fCubic.fPts[index].fX);
}
@@ -23,7 +23,7 @@
}
double minY = fCubic.fPts[0].fY;
double maxY = minY;
- for (int index = 0; index < count; ++index) {
+ for (int index = 1; index <= count; ++index) {
minY = SkTMin(minY, fCubic.fPts[index].fY);
maxY = SkTMax(maxY, fCubic.fPts[index].fY);
}
diff --git a/src/pathops/SkPathOpsDebug.h b/src/pathops/SkPathOpsDebug.h
index dfe68bb..e390b91 100644
--- a/src/pathops/SkPathOpsDebug.h
+++ b/src/pathops/SkPathOpsDebug.h
@@ -37,7 +37,7 @@
if (!SkPathOpsDebug::ValidWind(x)) strcpy(x##Str, "?"); \
else SK_SNPRINTF(x##Str, sizeof(x##Str), "%d", x)
-#define DEBUG_UNDER_DEVELOPMENT 01
+#define DEBUG_UNDER_DEVELOPMENT 1
#if FORCE_RELEASE
@@ -77,7 +77,7 @@
#define DEBUG_ALIGNMENT 0
#define DEBUG_ANGLE 1
#define DEBUG_ASSEMBLE 1
-#define DEBUG_COINCIDENCE 01
+#define DEBUG_COINCIDENCE 1
#define DEBUG_COINCIDENCE_ORDER 0 // tight arc quads may generate out-of-order coincdence spans
#define DEBUG_COINCIDENCE_VERBOSE 0
#define DEBUG_CUBIC_BINARY_SEARCH 0
@@ -91,7 +91,7 @@
#define DEBUG_SHOW_TEST_NAME 1
#define DEBUG_SORT 1
#define DEBUG_T_SECT 0
-#define DEBUG_T_SECT_DUMP 0
+#define DEBUG_T_SECT_DUMP 0 // Use 1 normally. Use 2 to number segments, 3 for script output
#define DEBUG_T_SECT_LOOP_COUNT 0
#define DEBUG_VALIDATE 1
#define DEBUG_WINDING 1
diff --git a/src/pathops/SkPathOpsQuad.cpp b/src/pathops/SkPathOpsQuad.cpp
index dafa3f5..ab1ba05 100644
--- a/src/pathops/SkPathOpsQuad.cpp
+++ b/src/pathops/SkPathOpsQuad.cpp
@@ -10,6 +10,28 @@
#include "SkPathOpsCurve.h"
#include "SkPathOpsQuad.h"
+// from blackpawn.com/texts/pointinpoly
+static bool pointInTriangle(const SkDPoint fPts[3], const SkDPoint& test) {
+ SkDVector v0 = fPts[2] - fPts[0];
+ SkDVector v1 = fPts[1] - fPts[0];
+ SkDVector v2 = test - fPts[0];
+ double dot00 = v0.dot(v0);
+ double dot01 = v0.dot(v1);
+ double dot02 = v0.dot(v2);
+ double dot11 = v1.dot(v1);
+ double dot12 = v1.dot(v2);
+ // Compute barycentric coordinates
+ double invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
+ double u = (dot11 * dot02 - dot01 * dot12) * invDenom;
+ double v = (dot00 * dot12 - dot01 * dot02) * invDenom;
+ // Check if point is in triangle
+ return u >= 0 && v >= 0 && u + v < 1;
+}
+
+static bool matchesEnd(const SkDPoint fPts[3], const SkDPoint& test) {
+ return fPts[0] == test || fPts[2] == test;
+}
+
/* started with at_most_end_pts_in_common from SkDQuadIntersection.cpp */
// Do a quick reject by rotating all points relative to a line formed by
// a pair of one quad's points. If the 2nd quad's points
@@ -44,6 +66,14 @@
return false;
}
}
+ if (linear && !matchesEnd(fPts, q2.fPts[0]) && !matchesEnd(fPts, q2.fPts[2])) {
+ // if the end point of the opposite quad is inside the hull that is nearly a line,
+ // then representing the quad as a line may cause the intersection to be missed.
+ // Check to see if the endpoint is in the triangle.
+ if (pointInTriangle(fPts, q2.fPts[0]) || pointInTriangle(fPts, q2.fPts[2])) {
+ linear = false;
+ }
+ }
*isLinear = linear;
return true;
}
diff --git a/src/pathops/SkPathOpsTSect.h b/src/pathops/SkPathOpsTSect.h
index 70ee8ab..6ae6ee5 100644
--- a/src/pathops/SkPathOpsTSect.h
+++ b/src/pathops/SkPathOpsTSect.h
@@ -795,11 +795,11 @@
#endif
#if DEBUG_T_SECT
SkASSERT(fBounds.width() || fBounds.height() || fCollapsed);
- SkASSERT(fBoundsMax == SkTMax(fBounds.width(), fBounds.height()));
+ SkASSERT(fBoundsMax == SkTMax(fBounds.width(), fBounds.height()) || fCollapsed == 0xFF);
SkASSERT(0 <= fStartT);
SkASSERT(fEndT <= 1);
SkASSERT(fStartT <= fEndT);
- SkASSERT(fBounded);
+ SkASSERT(fBounded || fCollapsed == 0xFF);
if (fHasPerp) {
if (fCoinStart.isCoincident()) {
validatePerpT(fCoinStart.perpT());
diff --git a/tests/PathOpsFuzz763Test.cpp b/tests/PathOpsFuzz763Test.cpp
index ba0aa05..ecbada2 100755
--- a/tests/PathOpsFuzz763Test.cpp
+++ b/tests/PathOpsFuzz763Test.cpp
@@ -454,8 +454,7 @@
path.close();
SkPath path2(path);
-// DEBUG_UNDER_DEVELOPMENT fuzz763_378a disable expectation check for now
- testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, !FLAGS_runFail);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
}
@@ -496,7 +495,7 @@
path.close();
SkPath path2(path);
- testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, !FLAGS_runFail);
+ testPathOp(reporter, path1, path2, (SkPathOp) 2, filename);
}
static void fuzz763_8712(skiatest::Reporter* reporter, const char* filename) {
@@ -933,8 +932,7 @@
path.close();
SkPath path2(path);
-// DEBUG_UNDER_DEVELOPMENT fuzz763_4713 disable expectation check for now
- 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) {
diff --git a/tests/PathOpsSimplifyTest.cpp b/tests/PathOpsSimplifyTest.cpp
index d91cc98..07e3720 100644
--- a/tests/PathOpsSimplifyTest.cpp
+++ b/tests/PathOpsSimplifyTest.cpp
@@ -5331,7 +5331,7 @@
#if DEBUG_UNDER_DEVELOPMENT // tiger
return;
#endif
- uint64_t testlines = 0x0000000001000893; // best so far: 0x0000000001000893
+ uint64_t testlines = 0x0000001000350204; // best so far: 0x0000000104080223
tiger8b_x(reporter, filename, testlines);
}
@@ -5382,8 +5382,6 @@
testSimplify(reporter, path, filename);
}
-// FIXME: this should not fail -- it was isolated looking for the root cause to fuzz763_4713
-// it fails with and without that change
static void fuzz763_4713_b(skiatest::Reporter* reporter, const char* filename) {
SkPath path;
path.setFillType((SkPath::FillType) 0);
@@ -5416,8 +5414,7 @@
path.quadTo(SkBits2Float(0x41dcaf1e), SkBits2Float(0x41d8ca01), SkBits2Float(0x41dcdc4c), SkBits2Float(0x41d89bf0));
path.quadTo(SkBits2Float(0x41ef6c33), SkBits2Float(0x41c5aec5), SkBits2Float(0x4204f72e), SkBits2Float(0x41c56cd2));
path.close();
-// DEBUG_UNDER_DEVELOPMENT fuzz763_4713_b disable expectation check for now
-testSimplifyCheck(reporter, path, filename, !FLAGS_runFail);
+testSimplify(reporter, path, filename);
}
static void dean4(skiatest::Reporter* reporter, const char* filename) {
@@ -5859,11 +5856,25 @@
testSimplify(reporter, path, filename);
}
+static void testQuads73(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path;
+ path.moveTo(0, 0);
+ path.quadTo(0, 1, 1, 2);
+ path.lineTo(0, 3);
+ path.close();
+ path.moveTo(0, 0);
+ path.lineTo(0, 0);
+ path.quadTo(0, 1, 1, 1);
+ path.close();
+ testSimplify(reporter, path, filename);
+}
+
static void (*skipTest)(skiatest::Reporter* , const char* filename) = 0;
static void (*firstTest)(skiatest::Reporter* , const char* filename) = tiger8b_h_1;
static void (*stopTest)(skiatest::Reporter* , const char* filename) = 0;
static TestDesc tests[] = {
+ TEST(testQuads73),
TEST(tiger8a_h_1),
TEST(tiger8a_h),
TEST(tiger8a),
diff --git a/tools/pathops_sorter.htm b/tools/pathops_sorter.htm
index 053cc10..667e86d 100644
--- a/tools/pathops_sorter.htm
+++ b/tools/pathops_sorter.htm
@@ -7,9 +7,8 @@
<div style="height:0">
<div id="lineconic">
- {{{494.348663f, 224.583771f}, {494.37619f, 224.68309f}}} id=1
-{{{494.375671f, 224.680908f}, {494.375397f, 224.67955f}, {494.376495f, 224.683868f}}} id=3
- {{fX=494.37557983398438 fY=224.68092346191406 }, {fX=494.47489929199219 fY=224.65339660644531 }}
+{{{{494.348663330078125, 224.583770751953125}, {494.365142822265625, 224.6331939697265625}, {494.37640380859375, 224.6840667724609375}}}, 0.998645842f},
+{{{494.371185302734375, 224.66168212890625}, {494.375213623046875, 224.6787261962890625}}},
</div>
</div>
diff --git a/tools/pathops_visualizer.htm b/tools/pathops_visualizer.htm
index 52c4417..945a6a9 100644
--- a/tools/pathops_visualizer.htm
+++ b/tools/pathops_visualizer.htm
@@ -3,22 +3,87 @@
<div height="0" hidden="true">
<div id="tiger8b_h_1">
-seg=1 {{{494.348663f, 224.583771f}, {494.375946f, 224.681992f}}}
-seg=2 {{{494.375946f, 224.681992f}, {494.376221f, 224.683273f}}}
-seg=3 {{{494.376221f, 224.683273f}, {494.375397f, 224.67955f}, {494.376495f, 224.683868f}}}
-seg=4 {{{494.376495f, 224.683868f}, {494.348663f, 224.583771f}}}
-debugShowLineIntersection wtTs[0]=1 {{{494.348663,224.583771}, {494.375946,224.681992}}} {{494.375946,224.681992}} wnTs[0]=0 {{{494.375946,224.681992}, {494.376221,224.683273}}}
-debugShowQuadLineIntersection wtTs[0]=0.228424525 {{{494.376221,224.683273}, {494.375397,224.67955}, {494.376495,224.683868}}} {{494.375946,224.681992}} wnTs[0]=1 {{{494.348663,224.583771}, {494.375946,224.681992}}}
-SkOpSegment::addT insert t=0.228424525 segID=3 spanID=9
-debugShowLineIntersection wtTs[0]=0 {{{494.348663,224.583771}, {494.375946,224.681992}}} {{494.348663,224.583771}} wtTs[1]=1 {{494.375946,224.681992}} wnTs[0]=1 {{{494.376495,224.683868}, {494.348663,224.583771}}} wnTs[1]=0.0188208188
-SkOpSegment::addT insert t=0.0188208188 segID=4 spanID=10
-debugShowQuadLineIntersection wtTs[0]=0 {{{494.376221,224.683273}, {494.375397,224.67955}, {494.376495,224.683868}}} {{494.376221,224.683273}} wtTs[1]=0.228448008 {{494.375946,224.681992}} wnTs[0]=1 {{{494.375946,224.681992}, {494.376221,224.683273}}} wnTs[1]=0
-debugShowLineIntersection wtTs[0]=0 {{{494.375946,224.681992}, {494.376221,224.683273}}} {{494.375946,224.681992}} wtTs[1]=1 {{494.376221,224.683273}} wnTs[0]=0.0188208 {{{494.376495,224.683868}, {494.348663,224.583771}}} wnTs[1]=0.00622666983
-SkOpSegment::addT insert t=0.00622666983 segID=4 spanID=11
-debugShowQuadLineIntersection wtTs[0]=0 {{{494.376221,224.683273}, {494.375397,224.67955}, {494.376495,224.683868}}} {{494.376221,224.683273}} wtTs[1]=1 {{494.376495,224.683868}} wnTs[0]=0.00622667 {{{494.376495,224.683868}, {494.348663,224.583771}}} wnTs[1]=0
-c:\puregit\src\pathops\skpathopsdebug.cpp:988: fatal error: "assert((t - fDebugBaseMin > 0) == (fDebugLastMin - fDebugBaseMin > 0))"
-pathops_unittest.exe has triggered a breakpoint.
-
+seg=1 {{{{494.348663f, 224.583771f}, {494.365143f, 224.633194f}, {494.376404f, 224.684067f}}}, 0.998645842f}
+seg=2 {{{494.376404f, 224.684067f}, {492.527069f, 224.218475f}, {492.952789f, 224.005585f}}}
+seg=3 {{{492.952789f, 224.005585f}, {494.375336f, 224.679337f}, {494.376038f, 224.682449f}}}
+seg=4 {{{494.376038f, 224.682449f}, {494.37619f, 224.68309f}}}
+seg=5 {{{494.37619f, 224.68309f}, {494.634338f, 225.414886f}, {494.895874f, 225.840698f}}}
+seg=6 {{{494.895874f, 225.840698f}, {494.348663f, 224.583771f}}}
+debugShowConicQuadIntersection wtTs[0]=1 {{{{494.348663,224.583771}, {494.365143,224.633194}, {494.376404,224.684067}}}, 0.998645842} {{494.376404,224.684067}} wnTs[0]=0 {{{494.376404,224.684067}, {492.527069,224.218475}, {492.952789,224.005585}}}
+id=1 1=(0,1) [4] id=2 4=(0.5,1) [1]
+id=1 1=(0,1) [6] id=2 6=(0.75,1) [1]
+id=1 3=(0.5,1) [6] id=2 6=(0.75,1) [3]
+id=1 3=(0.5,1) [8] id=2 8=(0.875,1) [3]
+id=1 5=(0.75,1) [8] id=2 8=(0.875,1) [5]
+id=1 7=(0.875,1) [8] id=2 8=(0.875,1) [7]
+id=1 7=(0.875,1) [10] id=2 10=(0.9375,1) [7]
+id=1 (empty) id=2 (empty)
+debugShowConicQuadIntersection no intersect {{{{494.348663,224.583771}, {494.365143,224.633194}, {494.376404,224.684067}}}, 0.998645842} {{{492.952789,224.005585}, {494.375336,224.679337}, {494.376038,224.682449}}}
+debugShowConicLineIntersection wtTs[0]=0.988457533 {{{{494.348663,224.583771}, {494.365143,224.633194}, {494.376404,224.684067}}}, 0.998645842} {{494.376038,224.682449}} wnTs[0]=0 {{{494.376038,224.682449}, {494.37619,224.68309}}}
+SkOpSegment::addT insert t=0.988457533 segID=1 spanID=13
+debugShowConicQuadIntersection no intersect {{{{494.348663,224.583771}, {494.365143,224.633194}, {494.376404,224.684067}}}, 0.998645842} {{{494.37619,224.68309}, {494.634338,225.414886}, {494.895874,225.840698}}}
+debugShowConicLineIntersection wtTs[0]=0 {{{{494.348663,224.583771}, {494.365143,224.633194}, {494.376404,224.684067}}}, 0.998645842} {{494.348663,224.583771}} wnTs[0]=1 {{{494.895874,225.840698}, {494.348663,224.583771}}}
+debugShowQuadIntersection wtTs[0]=1 {{{494.376404,224.684067}, {492.527069,224.218475}, {492.952789,224.005585}}} {{492.952789,224.005585}} wnTs[0]=0 {{{492.952789,224.005585}, {494.375336,224.679337}, {494.376038,224.682449}}}
+debugShowQuadLineIntersection no intersect {{{494.376404,224.684067}, {492.527069,224.218475}, {492.952789,224.005585}}} {{{494.376038,224.682449}, {494.37619,224.68309}}}
+id=1 1=(0,0.5) [2] id=2 2=(0,1) [1]
+id=1 1=(0,0.25) [2] id=2 2=(0,1) [1]
+id=1 (empty) id=2 (empty)
+debugShowQuadIntersection no intersect {{{494.376404,224.684067}, {492.527069,224.218475}, {492.952789,224.005585}}} {{{494.37619,224.68309}, {494.634338,225.414886}, {494.895874,225.840698}}}
+debugShowQuadLineIntersection no intersect {{{494.376404,224.684067}, {492.527069,224.218475}, {492.952789,224.005585}}} {{{494.895874,225.840698}, {494.348663,224.583771}}}
+debugShowQuadLineIntersection wtTs[0]=1 {{{492.952789,224.005585}, {494.375336,224.679337}, {494.376038,224.682449}}} {{494.376038,224.682449}} wnTs[0]=0 {{{494.376038,224.682449}, {494.37619,224.68309}}}
+debugShowQuadLineIntersection no intersect {{{492.952789,224.005585}, {494.375336,224.679337}, {494.376038,224.682449}}} {{{494.895874,225.840698}, {494.348663,224.583771}}}
+debugShowQuadLineIntersection wtTs[0]=0 {{{494.37619,224.68309}, {494.634338,225.414886}, {494.895874,225.840698}}} {{494.37619,224.68309}} wnTs[0]=1 {{{494.376038,224.682449}, {494.37619,224.68309}}}
+debugShowLineIntersection no intersect {{{494.376038,224.682449}, {494.37619,224.68309}}} {{{494.895874,225.840698}, {494.348663,224.583771}}}
+debugShowQuadLineIntersection wtTs[0]=1 {{{494.37619,224.68309}, {494.634338,225.414886}, {494.895874,225.840698}}} {{494.895874,225.840698}} wnTs[0]=0 {{{494.895874,225.840698}, {494.348663,224.583771}}}
+SkOpSegment::markDone id=4 (494.376038,224.682449 494.37619,224.68309) t=0 [7] (494.376038,224.682449) tEnd=1 newWindSum=? newOppSum=? oppSum=? windSum=? windValue=0 oppValue=0
+SkOpSegment::sortAngles [1] tStart=0.988457533 [13]
+SkOpAngle::after [1/1] 9/9 tStart=0.988457533 tEnd=0 < [3/3] 13/13 tStart=1 tEnd=0 < [1/2] 25/25 tStart=0.988457533 tEnd=1 T 4
+SkOpAngle::afterPart {{{{494.376038,224.682449}, {494.364861,224.63218}, {494.348663,224.583771}}}, 0.998676896} id=1
+SkOpAngle::afterPart {{{494.376038,224.682449}, {492.952789,224.005585}, {492.952789,224.005585}}} id=3
+SkOpAngle::afterPart {{{{494.376038,224.682449}, {494.376312,224.683624}, {494.376404,224.684067}}}, 0.999999821} id=1
+SkOpSegment::sortAngles [3] tStart=1 [6]
+SkOpSegment::debugShowActiveSpans id=1 (494.348663,224.583771 494.364952,224.632623 494.376129,224.682892 0.998676896f) t=0 tEnd=0.988457533 windSum=? windValue=1
+SkOpSegment::debugShowActiveSpans id=1 (494.376129,224.682892 494.376274,224.68348 494.376404,224.684067 0.999999821f) t=0.988457533 tEnd=1 windSum=? windValue=1
+SkOpSegment::debugShowActiveSpans id=2 (494.376404,224.684067 492.527069,224.218475 492.952789,224.005585) t=0 tEnd=1 windSum=? windValue=1
+SkOpSegment::debugShowActiveSpans id=3 (492.952789,224.005585 494.375336,224.679337 494.376038,224.682449) t=0 tEnd=1 windSum=? windValue=1
+SkOpSegment::debugShowActiveSpans id=5 (494.37619,224.68309 494.634338,225.414886 494.895874,225.840698) t=0 tEnd=1 windSum=? windValue=1
+SkOpSegment::debugShowActiveSpans id=6 (494.895874,225.840698 494.348663,224.583771) t=0 tEnd=1 windSum=? windValue=1
+SkOpSpan::sortableTop dir=kLeft seg=1 t=0.494228767 pt=(494.363678,224.63298)
+SkOpSpan::sortableTop [0] valid=1 operand=0 span=3 ccw=1 seg=2 {{{494.376404f, 224.684067f}, {492.527069f, 224.218475f}, {492.952789f, 224.005585f}}} t=0.0557039225 pt=(494.177429,224.63298) slope=(-1.72260523,-0.451515005)
+SkOpSpan::sortableTop [1] valid=1 operand=0 span=5 ccw=0 seg=3 {{{492.952789f, 224.005585f}, {494.375336f, 224.679337f}, {494.376038f, 224.682449f}}} t=0.733006652 pt=(494.274292,224.63298) slope=(0.380324923,0.182168955)
+SkOpSpan::sortableTop [2] valid=1 operand=0 span=1 ccw=0 seg=1 {{{{494.348663f, 224.583771f}, {494.365143f, 224.633194f}, {494.376404f, 224.684067f}}}, 0.998645842f} t=0.494228767 pt=(494.363678,224.63298) slope=(0.0138909232,0.050105697)
+SkOpSegment::markWinding id=2 (494.376404,224.684067 492.527069,224.218475 492.952789,224.005585) t=0 [3] (494.376404,224.684067) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
+SkOpSegment::markWinding id=3 (492.952789,224.005585 494.375336,224.679337 494.376038,224.682449) t=0 [5] (492.952789,224.005585) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markWinding id=2 (494.376404,224.684067 492.527069,224.218475 492.952789,224.005585) t=0 [3] (494.376404,224.684067) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
+SkOpSegment::markWinding id=1 (494.348663,224.583771 494.365143,224.633194 494.376404,224.684067) t=0.988457533 [13] (494.376129,224.682892) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markWinding id=1 (494.348663,224.583771 494.365143,224.633194 494.376404,224.684067) t=0 [1] (494.348663,224.583771) tEnd=0.988457533 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
+SkOpSegment::markWinding id=1 (494.348663,224.583771 494.365143,224.633194 494.376404,224.684067) t=0 [1] (494.348663,224.583771) tEnd=0.988457533 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
+SkOpSegment::markWinding id=6 (494.895874,225.840698 494.348663,224.583771) t=0 [11] (494.895874,225.840698) tEnd=1 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markWinding id=5 (494.37619,224.68309 494.634338,225.414886 494.895874,225.840698) t=0 [9] (494.37619,224.68309) tEnd=1 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::findNextWinding simple
+SkOpSegment::markDone id=1 (494.348663,224.583771 494.365143,224.633194 494.376404,224.684067) t=0 [1] (494.348663,224.583771) tEnd=0.988457533 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
+bridgeWinding current id=1 from=(494.376129,224.682892) to=(494.348663,224.583771)
+path.moveTo(494.376129,224.682892);
+path.conicTo(494.36496,224.632629, 494.348663,224.583771, 0.998676896);
+SkOpSegment::findNextWinding simple
+SkOpSegment::markDone id=6 (494.895874,225.840698 494.348663,224.583771) t=0 [11] (494.895874,225.840698) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
+bridgeWinding current id=6 from=(494.348663,224.583771) to=(494.895874,225.840698)
+SkOpSegment::markDone id=5 (494.37619,224.68309 494.634338,225.414886 494.895874,225.840698) t=0 [9] (494.37619,224.68309) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
+path.lineTo(494.895874,225.840698);
+SkOpSegment::debugShowActiveSpans id=1 (494.376129,224.682892 494.376274,224.68348 494.376404,224.684067 0.999999821f) t=0.988457533 tEnd=1 windSum=-1 oppSum=0 windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=2 (494.376404,224.684067 492.527069,224.218475 492.952789,224.005585) t=0 tEnd=1 windSum=-1 oppSum=0 windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=3 (492.952789,224.005585 494.375336,224.679337 494.376038,224.682449) t=0 tEnd=1 windSum=-1 oppSum=0 windValue=1 oppValue=0
+SkOpSegment::findNextWinding
+SkOpAngle::dumpOne [1/2] next=1/1 sect=25/25 s=0.988457533 [13] e=1 [2] sgn=-1 windVal=1 windSum=-1 oppVal=0 oppSum=0
+SkOpAngle::dumpOne [1/1] next=3/3 sect=9/9 s=0.988457533 [13] e=0 [1] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=0 done
+SkOpAngle::dumpOne [3/3] next=1/2 sect=13/13 s=1 [6] e=0 [5] sgn=1 windVal=1 windSum=-1 oppVal=0 oppSum=0
+SkOpSegment::markDone id=3 (492.952789,224.005585 494.375336,224.679337 494.376038,224.682449) t=0 [5] (492.952789,224.005585) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
+SkOpSegment::markDone id=2 (494.376404,224.684067 492.527069,224.218475 492.952789,224.005585) t=0 [3] (494.376404,224.684067) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
+SkOpSegment::markDone id=1 (494.348663,224.583771 494.365143,224.633194 494.376404,224.684067) t=0.988457533 [13] (494.376129,224.682892) tEnd=1 newWindSum=-1 newOppSum=0 oppSum=0 windSum=-1 windValue=1 oppValue=0
+SkOpSegment::findNextWinding from:[1] to:[1] start=13259432 end=18937312
+bridgeWinding current id=1 from=(494.376404,224.684067) to=(494.376129,224.682892)
+path.moveTo(494.376404,224.684067);
+path.lineTo(494.376129,224.682892);
</div>
</div>