aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar caryclark <caryclark@google.com>2016-09-23 05:47:20 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-09-23 05:47:20 -0700
commit27c015dfcf4e2b8fb1abe327cc40204e2a4f452a (patch)
tree1fab83dc8286a4f1900871c69e80e624203e7e3e
parent5a9c2f110e4f1a78d9bfedcf708168909706d7fd (diff)
split tight quads and conics
Tight quads and conics may nearly fold over on themselves, confusing coincidence against other curves. Split them at their max curvature early on to avoid complicating later logic. TBR=reed@google.com BUG=skia:5131 GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2357353002 Review-Url: https://codereview.chromium.org/2357353002
-rw-r--r--src/pathops/SkAddIntersections.cpp3
-rwxr-xr-xsrc/pathops/SkOpCoincidence.cpp3
-rw-r--r--src/pathops/SkOpContour.cpp6
-rw-r--r--src/pathops/SkOpContour.h2
-rw-r--r--src/pathops/SkOpEdgeBuilder.cpp140
-rw-r--r--src/pathops/SkOpSegment.cpp2
-rw-r--r--src/pathops/SkPathOpsDebug.cpp2
-rw-r--r--src/pathops/SkPathOpsDebug.h4
-rw-r--r--src/pathops/SkPathOpsOp.cpp2
-rw-r--r--src/pathops/SkPathOpsTSect.h3
-rw-r--r--src/pathops/SkReduceOrder.cpp7
-rw-r--r--src/pathops/SkReduceOrder.h4
-rw-r--r--tests/PathOpsConicLineIntersectionTest.cpp5
-rw-r--r--tests/PathOpsCubicIntersectionTest.cpp5
-rw-r--r--tests/PathOpsOpTest.cpp22
-rw-r--r--tests/PathOpsQuadIntersectionTest.cpp3
-rw-r--r--tests/PathOpsSimplifyFailTest.cpp2
-rw-r--r--tests/PathOpsSimplifyTest.cpp8
-rw-r--r--tests/PathOpsThreeWayTest.cpp2
-rw-r--r--tools/pathops_sorter.htm33
-rw-r--r--tools/pathops_visualizer.htm226
21 files changed, 329 insertions, 155 deletions
diff --git a/src/pathops/SkAddIntersections.cpp b/src/pathops/SkAddIntersections.cpp
index 2abf67a09d..b3a82cdeca 100644
--- a/src/pathops/SkAddIntersections.cpp
+++ b/src/pathops/SkAddIntersections.cpp
@@ -542,7 +542,8 @@ bool AddIntersectTs(SkOpContour* test, SkOpContour* next, SkOpCoincidence* coinc
SkTSwap(coinPtT[0], coinPtT[1]);
SkTSwap(testTAt, nextTAt);
}
- SkASSERT(coinPtT[0]->span()->t() < testTAt->span()->t());
+ SkASSERT(coincidence->globalState()->debugSkipAssert()
+ || coinPtT[0]->span()->t() < testTAt->span()->t());
if (coinPtT[0]->span()->deleted()) {
coinIndex = -1;
continue;
diff --git a/src/pathops/SkOpCoincidence.cpp b/src/pathops/SkOpCoincidence.cpp
index 1bbb82a9e0..d2874c3c5e 100755
--- a/src/pathops/SkOpCoincidence.cpp
+++ b/src/pathops/SkOpCoincidence.cpp
@@ -334,6 +334,9 @@ bool SkOpCoincidence::addEndMovedSpans(const SkOpSpan* base, const SkOpSpanBase*
}
SkOpSegment* writableSeg = const_cast<SkOpSegment*>(testSeg);
SkOpPtT* oppStart = writableSeg->addT(t);
+ if (oppStart == testPtT) {
+ continue;
+ }
SkOpSpan* writableBase = const_cast<SkOpSpan*>(base);
oppStart->span()->addOpp(writableBase);
if (oppStart->deleted()) {
diff --git a/src/pathops/SkOpContour.cpp b/src/pathops/SkOpContour.cpp
index 3b2318c306..981bd29573 100644
--- a/src/pathops/SkOpContour.cpp
+++ b/src/pathops/SkOpContour.cpp
@@ -10,7 +10,7 @@
#include "SkReduceOrder.h"
#include "SkTSort.h"
-SkOpSegment* SkOpContour::addCurve(SkPath::Verb verb, const SkPoint pts[4]) {
+SkOpSegment* SkOpContour::addCurve(SkPath::Verb verb, const SkPoint pts[4], SkScalar weight) {
SkChunkAlloc* allocator = this->globalState()->allocator();
switch (verb) {
case SkPath::kLine_Verb: {
@@ -24,7 +24,9 @@ SkOpSegment* SkOpContour::addCurve(SkPath::Verb verb, const SkPoint pts[4]) {
return appendSegment().addQuad(ptStorage, this);
} break;
case SkPath::kConic_Verb: {
- SkASSERT(0); // the original curve is a cubic, which will never reduce to a conic
+ SkPoint* ptStorage = SkOpTAllocator<SkPoint>::AllocateArray(allocator, 3);
+ memcpy(ptStorage, pts, sizeof(SkPoint) * 3);
+ return appendSegment().addConic(ptStorage, weight, this);
} break;
case SkPath::kCubic_Verb: {
SkPoint* ptStorage = SkOpTAllocator<SkPoint>::AllocateArray(allocator, 4);
diff --git a/src/pathops/SkOpContour.h b/src/pathops/SkOpContour.h
index acc6744f2a..4390fe4e1f 100644
--- a/src/pathops/SkOpContour.h
+++ b/src/pathops/SkOpContour.h
@@ -41,7 +41,7 @@ public:
appendSegment().addCubic(pts, this);
}
- SkOpSegment* addCurve(SkPath::Verb verb, const SkPoint pts[4]);
+ SkOpSegment* addCurve(SkPath::Verb verb, const SkPoint pts[4], SkScalar weight = 1);
SkOpSegment* addLine(SkPoint pts[2]) {
SkASSERT(pts[0] != pts[1]);
diff --git a/src/pathops/SkOpEdgeBuilder.cpp b/src/pathops/SkOpEdgeBuilder.cpp
index 36fc9ed161..d67ed44ddc 100644
--- a/src/pathops/SkOpEdgeBuilder.cpp
+++ b/src/pathops/SkOpEdgeBuilder.cpp
@@ -17,6 +17,26 @@ void SkOpEdgeBuilder::init() {
fSecondHalf = preFetch();
}
+// very tiny points cause numerical instability : don't allow them
+static void force_small_to_zero(SkPoint* pt) {
+ if (SkScalarAbs(pt->fX) < FLT_EPSILON_ORDERABLE_ERR) {
+ pt->fX = 0;
+ }
+ if (SkScalarAbs(pt->fY) < FLT_EPSILON_ORDERABLE_ERR) {
+ pt->fY = 0;
+ }
+}
+
+static bool can_add_curve(SkPath::Verb verb, SkPoint* curve) {
+ if (SkPath::kMove_Verb == verb) {
+ return false;
+ }
+ for (int index = 0; index < SkPathOpsVerbToPoints(verb); ++index) {
+ force_small_to_zero(&curve[index]);
+ }
+ return SkPath::kLine_Verb != verb || !SkDPoint::ApproximatelyEqual(curve[0], curve[1]);
+}
+
void SkOpEdgeBuilder::addOperand(const SkPath& path) {
SkASSERT(fPathVerbs.count() > 0 && fPathVerbs.end()[-1] == SkPath::kDone_Verb);
fPathVerbs.pop();
@@ -48,16 +68,6 @@ void SkOpEdgeBuilder::closeContour(const SkPoint& curveEnd, const SkPoint& curve
*fPathVerbs.append() = SkPath::kClose_Verb;
}
-// very tiny points cause numerical instability : don't allow them
-static void force_small_to_zero(SkPoint* pt) {
- if (SkScalarAbs(pt->fX) < FLT_EPSILON_ORDERABLE_ERR) {
- pt->fX = 0;
- }
- if (SkScalarAbs(pt->fY) < FLT_EPSILON_ORDERABLE_ERR) {
- pt->fY = 0;
- }
-}
-
int SkOpEdgeBuilder::preFetch() {
if (!fPath->isFinite()) {
fUnparseable = true;
@@ -107,8 +117,10 @@ int SkOpEdgeBuilder::preFetch() {
force_small_to_zero(&pts[2]);
curve[1] = pts[1];
curve[2] = pts[2];
- verb = SkReduceOrder::Conic(curve, iter.conicWeight(), pts);
- if (verb == SkPath::kMove_Verb) {
+ verb = SkReduceOrder::Quad(curve, pts);
+ if (SkPath::kQuad_Verb == verb && 1 != iter.conicWeight()) {
+ verb = SkPath::kConic_Verb;
+ } else if (verb == SkPath::kMove_Verb) {
continue; // skip degenerate points
}
break;
@@ -183,49 +195,83 @@ bool SkOpEdgeBuilder::walk() {
fCurrentContour->addLine(pointsPtr);
break;
case SkPath::kQuad_Verb:
- fCurrentContour->addQuad(pointsPtr);
- break;
- case SkPath::kConic_Verb:
- fCurrentContour->addConic(pointsPtr, *weightPtr++);
- break;
- case SkPath::kCubic_Verb: {
- // Split complex cubics (such as self-intersecting curves or
- // ones with difficult curvature) in two before proceeding.
- // This can be required for intersection to succeed.
- SkScalar splitT;
- if (SkDCubic::ComplexBreak(pointsPtr, &splitT)) {
- SkPoint cubicPair[7];
- SkChopCubicAt(pointsPtr, cubicPair, splitT);
- if (!SkScalarsAreFinite(&cubicPair[0].fX, SK_ARRAY_COUNT(cubicPair) * 2)) {
- return false;
- }
- SkPoint cStorage[2][4];
- SkPath::Verb v1 = SkReduceOrder::Cubic(&cubicPair[0], cStorage[0]);
- SkPath::Verb v2 = SkReduceOrder::Cubic(&cubicPair[3], cStorage[1]);
- if (v1 != SkPath::kMove_Verb && v2 != SkPath::kMove_Verb) {
- SkPoint* curve1 = v1 == SkPath::kCubic_Verb ? &cubicPair[0] : cStorage[0];
- SkPoint* curve2 = v2 == SkPath::kCubic_Verb ? &cubicPair[3] : cStorage[1];
- for (int index = 0; index < SkPathOpsVerbToPoints(v1); ++index) {
- force_small_to_zero(&curve1[index]);
+ {
+ SkVector v1 = pointsPtr[1] - pointsPtr[0];
+ SkVector v2 = pointsPtr[2] - pointsPtr[1];
+ if (v1.dot(v2) < 0) {
+ SkPoint pair[5];
+ if (SkChopQuadAtMaxCurvature(pointsPtr, pair) == 1) {
+ goto addOneQuad;
}
- for (int index = 0; index < SkPathOpsVerbToPoints(v2); ++index) {
- force_small_to_zero(&curve2[index]);
+ if (!SkScalarsAreFinite(&pair[0].fX, SK_ARRAY_COUNT(pair) * 2)) {
+ return false;
}
- if (SkPath::kLine_Verb != v1 ||
- !SkDPoint::ApproximatelyEqual(curve1[0], curve1[1])) {
+ SkPoint cStorage[2][2];
+ SkPath::Verb v1 = SkReduceOrder::Quad(&pair[0], cStorage[0]);
+ SkPath::Verb v2 = SkReduceOrder::Quad(&pair[2], cStorage[1]);
+ SkPoint* curve1 = v1 == SkPath::kQuad_Verb ? &pair[0] : cStorage[0];
+ SkPoint* curve2 = v2 == SkPath::kQuad_Verb ? &pair[2] : cStorage[1];
+ if (can_add_curve(v1, curve1) && can_add_curve(v2, curve2)) {
fCurrentContour->addCurve(v1, curve1);
- }
- if (SkPath::kLine_Verb != v2 ||
- !SkDPoint::ApproximatelyEqual(curve2[0], curve2[1])) {
fCurrentContour->addCurve(v2, curve2);
+ break;
}
- } else {
- fCurrentContour->addCubic(pointsPtr);
}
- } else {
- fCurrentContour->addCubic(pointsPtr);
}
+ addOneQuad:
+ fCurrentContour->addQuad(pointsPtr);
+ break;
+ case SkPath::kConic_Verb: {
+ SkVector v1 = pointsPtr[1] - pointsPtr[0];
+ SkVector v2 = pointsPtr[2] - pointsPtr[1];
+ SkScalar weight = *weightPtr++;
+ if (v1.dot(v2) < 0) {
+ // FIXME: max curvature for conics hasn't been implemented; use placeholder
+ SkScalar maxCurvature = SkFindQuadMaxCurvature(pointsPtr);
+ if (maxCurvature > 0) {
+ SkConic conic(pointsPtr, weight);
+ SkConic pair[2];
+ conic.chopAt(maxCurvature, pair);
+ SkPoint cStorage[2][3];
+ SkPath::Verb v1 = SkReduceOrder::Conic(pair[0], cStorage[0]);
+ SkPath::Verb v2 = SkReduceOrder::Conic(pair[1], cStorage[1]);
+ SkPoint* curve1 = v1 == SkPath::kConic_Verb ? pair[0].fPts : cStorage[0];
+ SkPoint* curve2 = v2 == SkPath::kConic_Verb ? pair[1].fPts : cStorage[1];
+ if (can_add_curve(v1, curve1) && can_add_curve(v2, curve2)) {
+ fCurrentContour->addCurve(v1, curve1, pair[0].fW);
+ fCurrentContour->addCurve(v2, curve2, pair[1].fW);
+ break;
+ }
+ }
+ }
+ fCurrentContour->addConic(pointsPtr, weight);
} break;
+ case SkPath::kCubic_Verb:
+ {
+ // Split complex cubics (such as self-intersecting curves or
+ // ones with difficult curvature) in two before proceeding.
+ // This can be required for intersection to succeed.
+ SkScalar splitT;
+ if (SkDCubic::ComplexBreak(pointsPtr, &splitT)) {
+ SkPoint pair[7];
+ SkChopCubicAt(pointsPtr, pair, splitT);
+ if (!SkScalarsAreFinite(&pair[0].fX, SK_ARRAY_COUNT(pair) * 2)) {
+ return false;
+ }
+ SkPoint cStorage[2][4];
+ SkPath::Verb v1 = SkReduceOrder::Cubic(&pair[0], cStorage[0]);
+ SkPath::Verb v2 = SkReduceOrder::Cubic(&pair[3], cStorage[1]);
+ SkPoint* curve1 = v1 == SkPath::kCubic_Verb ? &pair[0] : cStorage[0];
+ SkPoint* curve2 = v2 == SkPath::kCubic_Verb ? &pair[3] : cStorage[1];
+ if (can_add_curve(v1, curve1) && can_add_curve(v2, curve2)) {
+ fCurrentContour->addCurve(v1, curve1);
+ fCurrentContour->addCurve(v2, curve2);
+ break;
+ }
+ }
+ }
+ fCurrentContour->addCubic(pointsPtr);
+ break;
case SkPath::kClose_Verb:
SkASSERT(fCurrentContour);
if (!close()) {
diff --git a/src/pathops/SkOpSegment.cpp b/src/pathops/SkOpSegment.cpp
index 1a965c2474..9ab240d2cb 100644
--- a/src/pathops/SkOpSegment.cpp
+++ b/src/pathops/SkOpSegment.cpp
@@ -249,7 +249,7 @@ SkOpPtT* SkOpSegment::addT(double t) {
SkOpSpanBase* spanBase = &fHead;
do {
SkOpPtT* result = spanBase->ptT();
- if (t == result->fT || this->match(result, this, t, pt)) {
+ if (t == result->fT || (!zero_or_one(t) && this->match(result, this, t, pt))) {
spanBase->bumpSpanAdds();
return result;
}
diff --git a/src/pathops/SkPathOpsDebug.cpp b/src/pathops/SkPathOpsDebug.cpp
index 67bcee4070..5326addf8d 100644
--- a/src/pathops/SkPathOpsDebug.cpp
+++ b/src/pathops/SkPathOpsDebug.cpp
@@ -1876,7 +1876,7 @@ static void DebugValidate(const SkOpSpanBase* next, const SkOpSpanBase* end,
do {
const SkOpPtT* ptT = next->ptT();
int index = 0;
- bool somethingBetween;
+ bool somethingBetween = false;
do {
++index;
ptT = ptT->next();
diff --git a/src/pathops/SkPathOpsDebug.h b/src/pathops/SkPathOpsDebug.h
index e390b91b56..f0e384a7e3 100644
--- a/src/pathops/SkPathOpsDebug.h
+++ b/src/pathops/SkPathOpsDebug.h
@@ -19,6 +19,8 @@
#define FORCE_RELEASE 1 // set force release to 1 for multiple thread -- no debugging
#endif
+#define DEBUG_UNDER_DEVELOPMENT 1
+
#define ONE_OFF_DEBUG 0
#define ONE_OFF_DEBUG_MATHEMATICA 0
@@ -37,8 +39,6 @@
if (!SkPathOpsDebug::ValidWind(x)) strcpy(x##Str, "?"); \
else SK_SNPRINTF(x##Str, sizeof(x##Str), "%d", x)
-#define DEBUG_UNDER_DEVELOPMENT 1
-
#if FORCE_RELEASE
#define DEBUG_ACTIVE_OP 0
diff --git a/src/pathops/SkPathOpsOp.cpp b/src/pathops/SkPathOpsOp.cpp
index 0f4415bec1..d34c0579e4 100644
--- a/src/pathops/SkPathOpsOp.cpp
+++ b/src/pathops/SkPathOpsOp.cpp
@@ -207,7 +207,7 @@ static void dump_path(FILE* file, const SkPath& path, bool force, bool dumpAsHex
SkDynamicMemoryWStream wStream;
path.dump(&wStream, force, dumpAsHex);
sk_sp<SkData> data(wStream.detachAsData());
- fprintf(file, "%.*s\n", (int) data->size(), data->data());
+ fprintf(file, "%.*s\n", (int) data->size(), (char*) data->data());
}
static int dumpID = 0;
diff --git a/src/pathops/SkPathOpsTSect.h b/src/pathops/SkPathOpsTSect.h
index 6ae6ee528f..f84aaaa6b7 100644
--- a/src/pathops/SkPathOpsTSect.h
+++ b/src/pathops/SkPathOpsTSect.h
@@ -1531,7 +1531,8 @@ int SkTSect<TCurve, OppCurve>::linesIntersect(SkTSpan<TCurve, OppCurve>* span,
workT += tStep;
workPt = fCurve.ptAtT(workT);
coinW.setPerp(fCurve, workT, workPt, opp->fCurve);
- if (coinW.perpT() < 0) {
+ double perpT = coinW.perpT();
+ if (coinW.isCoincident() ? !between(oppSpan->fStartT, perpT, oppSpan->fEndT) : perpT < 0) {
continue;
}
SkDVector perpW = workPt - coinW.perpPt();
diff --git a/src/pathops/SkReduceOrder.cpp b/src/pathops/SkReduceOrder.cpp
index 48624baee9..7f7ea11d3b 100644
--- a/src/pathops/SkReduceOrder.cpp
+++ b/src/pathops/SkReduceOrder.cpp
@@ -4,6 +4,7 @@
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
+#include "SkGeometry.h"
#include "SkReduceOrder.h"
int SkReduceOrder::reduce(const SkDLine& line) {
@@ -255,9 +256,9 @@ SkPath::Verb SkReduceOrder::Quad(const SkPoint a[3], SkPoint* reducePts) {
return SkPathOpsPointsToVerb(order - 1);
}
-SkPath::Verb SkReduceOrder::Conic(const SkPoint a[3], SkScalar weight, SkPoint* reducePts) {
- SkPath::Verb verb = SkReduceOrder::Quad(a, reducePts);
- if (verb > SkPath::kLine_Verb && weight == 1) {
+SkPath::Verb SkReduceOrder::Conic(const SkConic& c, SkPoint* reducePts) {
+ SkPath::Verb verb = SkReduceOrder::Quad(c.fPts, reducePts);
+ if (verb > SkPath::kLine_Verb && c.fW == 1) {
return SkPath::kQuad_Verb;
}
return verb == SkPath::kQuad_Verb ? SkPath::kConic_Verb : verb;
diff --git a/src/pathops/SkReduceOrder.h b/src/pathops/SkReduceOrder.h
index e9e4090deb..7efb71d4fe 100644
--- a/src/pathops/SkReduceOrder.h
+++ b/src/pathops/SkReduceOrder.h
@@ -11,6 +11,8 @@
#include "SkPathOpsLine.h"
#include "SkPathOpsQuad.h"
+struct SkConic;
+
union SkReduceOrder {
enum Quadratics {
kNo_Quadratics,
@@ -21,7 +23,7 @@ union SkReduceOrder {
int reduce(const SkDLine& line);
int reduce(const SkDQuad& quad);
- static SkPath::Verb Conic(const SkPoint pts[3], SkScalar weight, SkPoint* reducePts);
+ static SkPath::Verb Conic(const SkConic& conic, SkPoint* reducePts);
static SkPath::Verb Cubic(const SkPoint pts[4], SkPoint* reducePts);
static SkPath::Verb Quad(const SkPoint pts[3], SkPoint* reducePts);
diff --git a/tests/PathOpsConicLineIntersectionTest.cpp b/tests/PathOpsConicLineIntersectionTest.cpp
index 62195060e9..ecc4a47f17 100644
--- a/tests/PathOpsConicLineIntersectionTest.cpp
+++ b/tests/PathOpsConicLineIntersectionTest.cpp
@@ -6,6 +6,7 @@
*/
#include "PathOpsExtendedTest.h"
#include "PathOpsTestCommon.h"
+#include "SkGeometry.h"
#include "SkIntersections.h"
#include "SkPathOpsConic.h"
#include "SkPathOpsLine.h"
@@ -103,7 +104,9 @@ DEF_TEST(PathOpsConicLineIntersection, reporter) {
SkPoint pts[3] = { conic.fPts.fPts[0].asSkPoint(), conic.fPts.fPts[1].asSkPoint(),
conic.fPts.fPts[2].asSkPoint() };
SkPoint reduced[3];
- SkPath::Verb order1 = SkReduceOrder::Conic(pts, conic.fWeight, reduced);
+ SkConic floatConic;
+ floatConic.set(pts, conic.fWeight);
+ SkPath::Verb order1 = SkReduceOrder::Conic(floatConic, reduced);
if (order1 != SkPath::kConic_Verb) {
SkDebugf("%s [%d] conic verb=%d\n", __FUNCTION__, iIndex, order1);
REPORTER_ASSERT(reporter, 0);
diff --git a/tests/PathOpsCubicIntersectionTest.cpp b/tests/PathOpsCubicIntersectionTest.cpp
index dd7a7f7e2f..9bf60b7e39 100644
--- a/tests/PathOpsCubicIntersectionTest.cpp
+++ b/tests/PathOpsCubicIntersectionTest.cpp
@@ -165,6 +165,9 @@ static const SkDCubic testSet[] = {
const int testSetCount = (int) SK_ARRAY_COUNT(testSet);
static const SkDCubic newTestSet[] = {
+{ { { 130.0427549999999997, 11417.41309999999976 },{ 130.2331240000000037, 11418.3192999999992 },{ 131.0370790000000056, 11419 },{ 132, 11419 } } },
+{ { { 132, 11419 },{ 130.8954319999999996, 11419 },{ 130, 11418.10449999999946 },{ 130, 11417 } } },
+
{{{1,3}, {-1.0564518,1.79032254}, {1.45265341,0.229448318}, {1.45381773,0.22913377}}},
{{{1.45381773,0.22913377}, {1.45425761,0.229014933}, {1.0967741,0.451612949}, {0,1}}},
@@ -698,7 +701,7 @@ DEF_TEST(PathOpsCubicCoinOneOff, reporter) {
}
DEF_TEST(PathOpsCubicIntersectionOneOff, reporter) {
- newOneOff(reporter, 66, 70);
+ newOneOff(reporter, 0, 1);
}
DEF_TEST(PathOpsCubicIntersectionTestsOneOff, reporter) {
diff --git a/tests/PathOpsOpTest.cpp b/tests/PathOpsOpTest.cpp
index 8ff0079dd4..9bb3a0fbb6 100644
--- a/tests/PathOpsOpTest.cpp
+++ b/tests/PathOpsOpTest.cpp
@@ -5375,6 +5375,26 @@ static void cubicOp158(skiatest::Reporter* reporter, const char* filename) {
testPathOp(reporter, path, pathB, kDifference_SkPathOp, filename);
}
+static void loop17(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.moveTo(1, 2);
+ path.cubicTo(0, 3, -0.333333343f, 3.33333325f, 0.833333373f, 3.5f);
+ path.close();
+ pathB.moveTo(0, 3);
+ pathB.cubicTo(-0.333333343f, 3.33333325f, 0.833333373f, 3.5f, 1, 2);
+ pathB.close();
+ testPathOp(reporter, path, pathB, kIntersect_SkPathOp, filename);
+}
+
+static void circlesOp4(skiatest::Reporter* reporter, const char* filename) {
+ SkPath path, pathB;
+ path.setFillType(SkPath::kWinding_FillType);
+ path.addCircle(0, 1, 5, SkPath::kCW_Direction);
+ pathB.setFillType(SkPath::kWinding_FillType);
+ pathB.addCircle(0, 1, 0, SkPath::kCW_Direction);
+ testPathOp(reporter, path, pathB, kDifference_SkPathOp, 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;
@@ -5382,6 +5402,8 @@ static void (*stopTest)(skiatest::Reporter* , const char* filename) = 0;
#define TEST(name) { name, #name }
static struct TestDesc tests[] = {
+ TEST(circlesOp4),
+ TEST(loop17),
TEST(cubicOp158),
TEST(loops_i1),
TEST(loops_i2),
diff --git a/tests/PathOpsQuadIntersectionTest.cpp b/tests/PathOpsQuadIntersectionTest.cpp
index f01262201f..be3d5a86d1 100644
--- a/tests/PathOpsQuadIntersectionTest.cpp
+++ b/tests/PathOpsQuadIntersectionTest.cpp
@@ -53,6 +53,9 @@ static void standardTestCases(skiatest::Reporter* reporter) {
}
static const SkDQuad testSet[] = {
+{{{-0.001019871095195412636, -0.008523519150912761688}, {-0.005396408028900623322, -0.005396373569965362549}, {-0.02855382487177848816, -0.02855364233255386353}}},
+{{{-0.004567248281091451645, -0.01482933573424816132}, {-0.01142475008964538574, -0.01140109263360500336}, {-0.02852955088019371033, -0.02847047336399555206}}},
+
{{{1, 1}, {0, 2}, {3, 3}}},
{{{3, 0}, {0, 1}, {1, 2}}},
diff --git a/tests/PathOpsSimplifyFailTest.cpp b/tests/PathOpsSimplifyFailTest.cpp
index 4da43b8532..0166a841fa 100644
--- a/tests/PathOpsSimplifyFailTest.cpp
+++ b/tests/PathOpsSimplifyFailTest.cpp
@@ -154,7 +154,7 @@ path.quadTo(SkBits2Float(0xe93ae9e9), SkBits2Float(0xe964b6e9), SkBits2Float(0x0
path.moveTo(SkBits2Float(0x64b6b6b6), SkBits2Float(0xe9e9e900)); // 2.69638e+22f, -3.53475e+25f
path.quadTo(SkBits2Float(0xb6b6b6e9), SkBits2Float(0xb6b6b6b6), SkBits2Float(0xe9e9b6ce), SkBits2Float(0xe9e93ae9)); // -5.44532e-06f, -5.44529e-06f, -3.53179e+25f, -3.52447e+25f
- testSimplify(reporter, path, filename);
+ testSimplifyFuzz(reporter, path, filename);
}
diff --git a/tests/PathOpsSimplifyTest.cpp b/tests/PathOpsSimplifyTest.cpp
index 07e3720583..55f0447bae 100644
--- a/tests/PathOpsSimplifyTest.cpp
+++ b/tests/PathOpsSimplifyTest.cpp
@@ -5256,7 +5256,7 @@ static void tiger8a_h_1(skiatest::Reporter* reporter, const char* filename) {
#if DEBUG_UNDER_DEVELOPMENT // tiger
return;
#endif
- uint64_t testlines = 0x0000000a01900c00; // best so far: 0x0000001d14c14bb1;
+ uint64_t testlines = 0x0000000000002008; // best so far: 0x0000001d14c14bb1;
tiger8a_x(reporter, filename, testlines);
}
@@ -5331,7 +5331,7 @@ static void tiger8b_h_1(skiatest::Reporter* reporter, const char* filename) {
#if DEBUG_UNDER_DEVELOPMENT // tiger
return;
#endif
- uint64_t testlines = 0x0000001000350204; // best so far: 0x0000000104080223
+ uint64_t testlines = 0x000000201304b4a3; // best so far: 0x000000201304b4a3
tiger8b_x(reporter, filename, testlines);
}
@@ -5870,11 +5870,10 @@ static void testQuads73(skiatest::Reporter* reporter, const char* filename) {
}
static void (*skipTest)(skiatest::Reporter* , const char* filename) = 0;
-static void (*firstTest)(skiatest::Reporter* , const char* filename) = tiger8b_h_1;
+static void (*firstTest)(skiatest::Reporter* , const char* filename) = 0;
static void (*stopTest)(skiatest::Reporter* , const char* filename) = 0;
static TestDesc tests[] = {
- TEST(testQuads73),
TEST(tiger8a_h_1),
TEST(tiger8a_h),
TEST(tiger8a),
@@ -5882,6 +5881,7 @@ static TestDesc tests[] = {
TEST(tiger8b_h),
TEST(tiger8b),
TEST(tiger8),
+ TEST(testQuads73),
TEST(testQuads72),
TEST(testQuads71),
TEST(testQuads70),
diff --git a/tests/PathOpsThreeWayTest.cpp b/tests/PathOpsThreeWayTest.cpp
index bf634f9f7e..6a93bfbc59 100644
--- a/tests/PathOpsThreeWayTest.cpp
+++ b/tests/PathOpsThreeWayTest.cpp
@@ -75,6 +75,6 @@ DEF_TEST(PathOpsThreeWay, reporter) {
}
DEF_TEST(PathOpsThreeWayOneOff, reporter) {
- int index = 1;
+ int index = 0;
testSetTest(reporter, index);
}
diff --git a/tools/pathops_sorter.htm b/tools/pathops_sorter.htm
index 667e86dac4..0983b704dc 100644
--- a/tools/pathops_sorter.htm
+++ b/tools/pathops_sorter.htm
@@ -6,9 +6,30 @@
<title></title>
<div style="height:0">
-<div id="lineconic">
-{{{{494.348663330078125, 224.583770751953125}, {494.365142822265625, 224.6331939697265625}, {494.37640380859375, 224.6840667724609375}}}, 0.998645842f},
-{{{494.371185302734375, 224.66168212890625}, {494.375213623046875, 224.6787261962890625}}},
+<div id="perp">
+{{{130.0427549999999997, 11417.41309999999976}, {130.2331240000000037, 11418.3192999999992}, {131.0370790000000056, 11419}, {132, 11419}}},
+{{{132, 11419}, {130.8954319999999996, 11419}, {130, 11418.10449999999946}, {130, 11417}}},
+</div>
+
+<div id="quads">
+{{{-0.001019871095195412636, -0.008523519150912761688}, {-0.005396408028900623322, -0.005396373569965362549}, {-0.02855382487177848816, -0.02855364233255386353}}},
+{{{-0.004567248281091451645, -0.01482933573424816132}, {-0.01142475008964538574, -0.01140109263360500336}, {-0.02852955088019371033, -0.02847047336399555206}}},
+ </div>
+
+<div id="both">
+{{fX=0.000000000 fY=0.000000000 }, {fX=494.350159 fY=228.773712 }, {fX=493.191650 fY=226.887451 }}
+{{fX=0.000000000 fY=0.000000000 } {fX=492.680206 fY=228.000900 } {fX=493.193817 fY=226.897568 }
+{{fX=493.193817 fY=226.897568 } {fX=493.195557 fY=226.893829 } {fX=493.191650 fY=226.887451 }
+ </div>
+
+<div id="startguy">
+{{fX=0.000000000 fY=0.000000000 }, {fX=494.350159 fY=228.773712 }, {fX=493.191650 fY=226.887451 }}
+{{fX=0.000000000 fY=0.000000000 }, {fX=494.350159 fY=228.773712 }, {fX=493.191650 fY=226.887451 }}
+ </div>
+
+<div id="splitted">
+{{fX=0.000000000 fY=0.000000000 } {fX=492.680206 fY=228.000900 } {fX=493.193817 fY=226.897568 }
+{{fX=493.193817 fY=226.897568 } {fX=493.195557 fY=226.893829 } {fX=493.191650 fY=226.887451 }
</div>
</div>
@@ -16,7 +37,11 @@
<script type="text/javascript">
var testDivs = [
- lineconic,
+ perp,
+ quads,
+ both,
+ startguy,
+ splitted
];
var decimal_places = 3;
diff --git a/tools/pathops_visualizer.htm b/tools/pathops_visualizer.htm
index 945a6a9e6c..5cec64f5bf 100644
--- a/tools/pathops_visualizer.htm
+++ b/tools/pathops_visualizer.htm
@@ -2,88 +2,150 @@
<head>
<div height="0" hidden="true">
-<div id="tiger8b_h_1">
-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
+<div id="loop17">
+seg=1 {{{1, 2}, {0, 3}, {-0.333333343f, 3.33333325f}, {0.833333373f, 3.5f}}}
+seg=2 {{{0.833333373f, 3.5f}, {1, 2}}}
+op sect
+seg=3 {{{0, 3}, {-0.333333343f, 3.33333325f}, {0.833333373f, 3.5f}, {1, 2}}}
+seg=4 {{{1, 2}, {0, 3}}}
+debugShowCubicLineIntersection wtTs[0]=0 {{{0,3}, {-0.333333343,3.33333325}, {0.833333373,3.5}, {1,2}}} {{0,3}} wtTs[1]=1 {{1,2}} wnTs[0]=1 {{{1,2}, {0,3}}} wnTs[1]=0
+id=1 1=(0,1) [4,2] id=2 2=(0,0.5) [1] 4=(0.5,1) [1]
+id=1 1=(0,0.5) [4] 3=(0.5,1) [2,4] id=2 2=(0,0) [3] 4=(0.5,1) [3,1]
+id=1 1=(0,0.5) [4] 3=(0.5,0.75) [4] 5=(1,1) [2] id=2 2=(0,0) [5] 4=(0.5,1) [3,1]
+id=1 1=(0,0.5) [4] 5=(1,1) [2] id=2 2=(0,0) [5] 4=(0.5,0.75) [1]
+id=1 7=(0.25,0.5) [4] 5=(1,1) [2] id=2 2=(0,0) [5] 4=(0.5,0.75) [7]
+id=1 7=(0.25,0.375) [4] 9=(0.375,0.5) [4] 5=(1,1) [2] id=2 2=(0,0) [5] 4=(0.5,0.75) [9,7]
+id=1 7=(0.25,0.375) [8,4] 5=(1,1) [2] id=2 2=(0,0) [5] 4=(0.5,0.625) [7] 8=(0.625,0.75) [7]
+id=1 7=(0.25,0.375) [10,8] 5=(1,1) [2] id=2 2=(0,0) [5] 10=(0.5625,0.625) [7] 8=(0.625,0.75) [7]
+id=1 11=(0.3125,0.375) [8] 5=(1,1) [2] id=2 2=(0,0) [5] 8=(0.625,0.75) [11]
+id=1 11=(0.3125,0.375) [8] 5=(1,1) [2] id=2 2=(0,0) [5] 8=(0.625,0.6875) [11]
+id=1 13=(0.34375,0.375) [8] 5=(1,1) [2] id=2 2=(0,0) [5] 8=(0.625,0.6875) [13]
+id=1 13=(0.34375,0.375) [8] 5=(1,1) [2] id=2 2=(0,0) [5] 8=(0.625,0.65625) [13]
+id=1 15=(0.359375,0.375) [8] 5=(1,1) [2] id=2 2=(0,0) [5] 8=(0.625,0.65625) [15]
+id=1 15=(0.359375,0.375) [8] 5=(1,1) [2] id=2 2=(0,0) [5] 8=(0.625,0.640625) [15]
+id=1 15=(0.359375,0.367188) [8] 17=(0.367188,0.375) [8] 5=(1,1) [2] id=2 2=(0,0) [5] 8=(0.625,0.640625) [17,15]
+id=1 15=(0.359375,0.367188) [18] 5=(1,1) [2] id=2 2=(0,0) [5] 18=(0.632813,0.640625) [15]
+id=1 19=(0.363281,0.367188) [18] 5=(1,1) [2] id=2 2=(0,0) [5] 18=(0.632813,0.640625) [19]
+setPerp t=0.36328125 cPt=(0.110739922,3.22537946) != oppT=0.627603681 fPerpPt=(0.110965509,3.21864052)
+setPerp t=0.3671875 cPt=(0.115765816,3.22551414) != oppT=0.636601379 fPerpPt=(0.115710094,3.22827643)
+setPerp t=0.6328125 cPt=(0.113641506,3.22423955) != oppT=0.363729545 fPerpPt=(0.111313976,3.22539824)
+setPerp t=0.63470694 cPt=(0.114662928,3.22626175) != oppT=0.367452497 fPerpPt=(0.116108709,3.2255209)
+setPerp t=0.635654159 cPt=(0.115183291,3.22727003) != oppT=0.369275918 fPerpPt=(0.118474752,3.22555923)
+setPerp t=0.636127769 cPt=(0.115445887,3.22777346) != oppT=0.370178237 fPerpPt=(0.119649848,3.22557288)
+setPerp t=0.636364574 cPt=(0.115577789,3.228025) != oppT=0.370627065 fPerpPt=(0.120235406,3.22557836)
+setPerp t=0.636482977 cPt=(0.115643891,3.22815073) != oppT=0.370850898 fPerpPt=(0.120527686,3.22558077)
+setPerp t=0.636542178 cPt=(0.11567698,3.22821358) != oppT=0.370962669 fPerpPt=(0.120673701,3.22558189)
+setPerp t=0.636571779 cPt=(0.115693534,3.22824501) != oppT=0.371018519 fPerpPt=(0.120746678,3.22558243)
+setPerp t=0.636586579 cPt=(0.115701813,3.22826072) != oppT=0.371046435 fPerpPt=(0.120783158,3.22558269)
+setPerp t=0.636593979 cPt=(0.115705954,3.22826857) != oppT=0.37106039 fPerpPt=(0.120801396,3.22558282)
+setPerp t=0.636597679 cPt=(0.115708024,3.2282725) != oppT=0.371067368 fPerpPt=(0.120810515,3.22558289)
+setPerp t=0.636599529 cPt=(0.115709059,3.22827446) != oppT=0.371070856 fPerpPt=(0.120815074,3.22558292)
+setPerp t=0.636600454 cPt=(0.115709577,3.22827545) != oppT=0.3710726 fPerpPt=(0.120817354,3.22558294)
+setPerp t=0.636600917 cPt=(0.115709835,3.22827594) != oppT=0.371073472 fPerpPt=(0.120818494,3.22558294)
+setPerp t=0.636601148 cPt=(0.115709965,3.22827618) != oppT=0.371073908 fPerpPt=(0.120819063,3.22558295)
+setPerp t=0.636601264 cPt=(0.11571003,3.2282763) != oppT=0.371074126 fPerpPt=(0.120819348,3.22558295)
+setPerp t=0.636601322 cPt=(0.115710062,3.22827637) != oppT=0.371074235 fPerpPt=(0.120819491,3.22558295)
+setPerp t=0.63660135 cPt=(0.115710078,3.2282764) != oppT=0.37107429 fPerpPt=(0.120819562,3.22558295)
+setPerp t=0.636601365 cPt=(0.115710086,3.22827641) != oppT=0.371074317 fPerpPt=(0.120819598,3.22558295)
+setPerp t=0.636601372 cPt=(0.11571009,3.22827642) != oppT=0.371074331 fPerpPt=(0.120819616,3.22558295)
+setPerp t=0.636601376 cPt=(0.115710092,3.22827642) != oppT=0.371074338 fPerpPt=(0.120819624,3.22558295)
+setPerp t=0.636601378 cPt=(0.115710093,3.22827643) != oppT=0.371074341 fPerpPt=(0.120819629,3.22558295)
+setPerp t=0.636601378 cPt=(0.115710094,3.22827643) != oppT=0.371074343 fPerpPt=(0.120819631,3.22558295)
+setPerp t=0.636601379 cPt=(0.115710094,3.22827643) != oppT=0.371074344 fPerpPt=(0.120819632,3.22558295)
+setPerp t=0.636601379 cPt=(0.115710094,3.22827643) != oppT=0.371074344 fPerpPt=(0.120819633,3.22558295)
+setPerp t=0.636601379 cPt=(0.115710094,3.22827643) != oppT=0.371074344 fPerpPt=(0.120819633,3.22558295)
+setPerp t=0.636601379 cPt=(0.115710094,3.22827643) != oppT=0.371074344 fPerpPt=(0.120819633,3.22558295)
+setPerp t=0.636601379 cPt=(0.115710094,3.22827643) != oppT=0.371074344 fPerpPt=(0.120819633,3.22558295)
+setPerp t=0.636601379 cPt=(0.115710094,3.22827643) != oppT=0.371074344 fPerpPt=(0.120819633,3.22558295)
+setPerp t=0.636601379 cPt=(0.115710094,3.22827643) != oppT=0.371074344 fPerpPt=(0.120819633,3.22558295)
+setPerp t=0.636601379 cPt=(0.115710094,3.22827643) != oppT=0.371074344 fPerpPt=(0.120819633,3.22558295)
+setPerp t=0.636601379 cPt=(0.115710094,3.22827643) != oppT=0.371074344 fPerpPt=(0.120819633,3.22558295)
+setPerp t=0.636601379 cPt=(0.115710094,3.22827643) != oppT=0.371074344 fPerpPt=(0.120819633,3.22558295)
+setPerp t=0.636601379 cPt=(0.115710094,3.22827643) != oppT=0.371074344 fPerpPt=(0.120819633,3.22558295)
+setPerp t=0.636601379 cPt=(0.115710094,3.22827643) != oppT=0.371074344 fPerpPt=(0.120819633,3.22558295)
+setPerp t=0.636601379 cPt=(0.115710094,3.22827643) != oppT=0.371074344 fPerpPt=(0.120819633,3.22558295)
+setPerp t=0.636601379 cPt=(0.115710094,3.22827643) != oppT=0.371074344 fPerpPt=(0.120819633,3.22558295)
+setPerp t=0.636601379 cPt=(0.115710094,3.22827643) != oppT=0.371074344 fPerpPt=(0.120819633,3.22558295)
+setPerp t=0.636601379 cPt=(0.115710094,3.22827643) != oppT=0.371074344 fPerpPt=(0.120819633,3.22558295)
+setPerp t=0.636601379 cPt=(0.115710094,3.22827643) != oppT=0.371074344 fPerpPt=(0.120819633,3.22558295)
+setPerp t=0.636601379 cPt=(0.115710094,3.22827643) != oppT=0.371074344 fPerpPt=(0.120819633,3.22558295)
+setPerp t=0.636601379 cPt=(0.115710094,3.22827643) != oppT=0.371074344 fPerpPt=(0.120819633,3.22558295)
+id=1 5=(1,1) [2] id=2 2=(0,0) [5]
+debugShowCubicIntersection wtTs[0]=1 {{{0,3}, {-0.333333343,3.33333325}, {0.833333373,3.5}, {1,2}}} {{1,2}} wnTs[0]=0 {{{1,2}, {0,3}, {-0.333333343,3.33333325}, {0.833333373,3.5}}}
+debugShowCubicLineIntersection wtTs[0]=1 {{{0,3}, {-0.333333343,3.33333325}, {0.833333373,3.5}, {1,2}}} {{1,2}} wnTs[0]=1 {{{0.833333373,3.5}, {1,2}}}
+debugShowCubicLineIntersection wtTs[0]=0 {{{1,2}, {0,3}, {-0.333333343,3.33333325}, {0.833333373,3.5}}} {{1,2}} wnTs[0]=0 {{{1,2}, {0,3}}}
+debugShowLineIntersection wtTs[0]=0 {{{1,2}, {0,3}}} {{1,2}} wnTs[0]=1 {{{0.833333373,3.5}, {1,2}}}
+debugShowCubicLineIntersection wtTs[0]=0 {{{1,2}, {0,3}, {-0.333333343,3.33333325}, {0.833333373,3.5}}} {{1,2}} wtTs[1]=1 {{0.833333373,3.5}} wnTs[0]=1 {{{0.833333373,3.5}, {1,2}}} wnTs[1]=0
+----------------------------------- start
+----------------------------------- addExpanded
+----------------------------------- moveMultiples
+----------------------------------- moveNearby
+----------------------------------- addEndMovedSpans
+----------------------------------- addMissing2
+----------------------------------- moveNearby2
+----------------------------------- expand2
+----------------------------------- addExpanded3
+----------------------------------- mark1
+----------------------------------- missingCoincidence2
+----------------------------------- missingCoincidence3
+----------------------------------- coincidence.reorder
+----------------------------------- pairs->apply
+----------------------------------- pairs->findOverlaps
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);
+SkOpAngle::after [3/1] 21/20 tStart=1 tEnd=0 < [1/3] 20/21 tStart=0 tEnd=1 < [2/4] 21/21 tStart=1 tEnd=0 F 7
+SkOpAngle::afterPart {{{1,2}, {0.833333373,3.5}, {-0.333333343,3.33333325}, {0,3}}} id=3
+SkOpAngle::afterPart {{{1,2}, {0,3}, {-0.333333343,3.33333325}, {0.833333373,3.5}}} id=1
+SkOpAngle::afterPart {{{1,2}, {0.833333373,3.5}}} id=2
+SkOpAngle::after [3/1] 21/20 tStart=1 tEnd=0 < [4/2] 19/19 tStart=0 tEnd=1 < [2/4] 21/21 tStart=1 tEnd=0 F 5
+SkOpAngle::afterPart {{{1,2}, {0.833333373,3.5}, {-0.333333343,3.33333325}, {0,3}}} id=3
+SkOpAngle::afterPart {{{1,2}, {0,3}}} id=4
+SkOpAngle::afterPart {{{1,2}, {0.833333373,3.5}}} id=2
+SkOpAngle::after [2/4] 21/21 tStart=1 tEnd=0 < [4/2] 19/19 tStart=0 tEnd=1 < [1/3] 20/21 tStart=0 tEnd=1 T 5
+SkOpAngle::afterPart {{{1,2}, {0.833333373,3.5}}} id=2
+SkOpAngle::afterPart {{{1,2}, {0,3}}} id=4
+SkOpAngle::afterPart {{{1,2}, {0,3}, {-0.333333343,3.33333325}, {0.833333373,3.5}}} id=1
+SkOpSegment::sortAngles [4] tStart=0 [7]
+SkOpSegment::sortAngles [1] tStart=0 [1]
+SkOpSegment::sortAngles [2] tStart=1 [4]
+SkOpSegment::debugShowActiveSpans id=3 (0,3 -0.333333343,3.33333325 0.833333373,3.5 1,2) t=0 tEnd=1 windSum=? windValue=1
+SkOpSegment::debugShowActiveSpans id=4 (1,2 0,3) t=0 tEnd=1 windSum=? windValue=1
+SkOpSegment::debugShowActiveSpans id=1 (1,2 0,3 -0.333333343,3.33333325 0.833333373,3.5) t=0 tEnd=1 windSum=? windValue=1
+SkOpSegment::debugShowActiveSpans id=2 (0.833333373,3.5 1,2) t=0 tEnd=1 windSum=? windValue=1
+SkOpSpan::sortableTop dir=kTop seg=3 t=0.5 pt=(0.3125,3.1875)
+SkOpSpan::sortableTop [0] valid=1 operand=1 span=7 ccw=0 seg=4 {{{1, 2}, {0, 3}}} t=0.6875 pt=(0.3125,2.6875) slope=(-1,1)
+SkOpSpan::sortableTop [1] valid=1 operand=0 span=1 ccw=0 seg=1 {{{1, 2}, {0, 3}, {-0.333333343f, 3.33333325f}, {0.833333373f, 3.5f}}} t=0.293719533 pt=(0.3125,2.72128606) slope=(-1.60944396,1.95452854)
+SkOpSpan::sortableTop [2] valid=1 operand=1 span=5 ccw=1 seg=3 {{{0, 3}, {-0.333333343f, 3.33333325f}, {0.833333373f, 3.5f}, {1, 2}}} t=0.5 pt=(0.3125,3.1875) slope=(1.62500004,-0.62499994)
+SkOpSegment::markWinding id=4 (1,2 0,3) t=0 [7] (1,2) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
+SkOpSegment::markWinding id=3 (0,3 -0.333333343,3.33333325 0.833333373,3.5 1,2) t=0 [5] (0,3) tEnd=1 newWindSum=1 newOppSum=0 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markWinding id=4 (1,2 0,3) t=0 [7] (1,2) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
+SkOpSegment::markWinding id=1 (1,2 0,3 -0.333333343,3.33333325 0.833333373,3.5) t=0 [1] (1,2) tEnd=1 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=0
+SkOpSegment::markWinding id=2 (0.833333373,3.5 1,2) t=0 [3] (0.833333373,3.5) tEnd=1 newWindSum=1 newOppSum=1 oppSum=? windSum=? windValue=1 oppValue=0
+SkOpSegment::markWinding id=1 (1,2 0,3 -0.333333343,3.33333325 0.833333373,3.5) t=0 [1] (1,2) tEnd=1 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=0
+SkOpSegment::activeOp id=3 t=1 tEnd=0 op=sect miFrom=0 miTo=0 suFrom=1 suTo=0 result=0
+SkOpSegment::markDone id=3 (0,3 -0.333333343,3.33333325 0.833333373,3.5 1,2) t=0 [5] (0,3) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
+SkOpSegment::markDone id=4 (1,2 0,3) t=0 [7] (1,2) tEnd=1 newWindSum=1 newOppSum=0 oppSum=0 windSum=1 windValue=1 oppValue=0
+bridgeOp chase.append id=4 windSum=1
+SkOpSegment::debugShowActiveSpans id=1 (1,2 0,3 -0.333333343,3.33333325 0.833333373,3.5) t=0 tEnd=1 windSum=1 oppSum=1 windValue=1 oppValue=0
+SkOpSegment::debugShowActiveSpans id=2 (0.833333373,3.5 1,2) t=0 tEnd=1 windSum=1 oppSum=1 windValue=1 oppValue=0
+SkOpSegment::activeOp id=1 t=0 tEnd=1 op=sect miFrom=0 miTo=1 suFrom=1 suTo=1 result=1
+SkOpSegment::findNextOp simple
+SkOpSegment::markDone id=1 (1,2 0,3 -0.333333343,3.33333325 0.833333373,3.5) t=0 [1] (1,2) tEnd=1 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=0
+bridgeOp current id=1 from=(1,2) to=(0.833333373,3.5)
+path.moveTo(1,2);
+path.cubicTo(0,3, -0.333333343,3.33333325, 0.833333373,3.5);
+SkOpSegment::findNextOp
+SkOpAngle::dumpOne [2/4] next=4/2 sect=21/21 s=1 [4] e=0 [3] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=1
+SkOpAngle::dumpOne [4/2] next=1/3 sect=19/19 s=0 [7] e=1 [8] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=0 done operand
+SkOpAngle::dumpOne [1/3] next=3/1 sect=20/21 s=0 [1] e=1 [2] sgn=-1 windVal=1 windSum=1 oppVal=0 oppSum=1 done
+SkOpAngle::dumpOne [3/1] next=2/4 sect=21/20 s=1 [6] e=0 [5] sgn=1 windVal=1 windSum=1 oppVal=0 oppSum=0 done operand
+SkOpSegment::activeOp id=4 t=0 tEnd=1 op=sect miFrom=0 miTo=0 suFrom=1 suTo=1 result=0
+SkOpSegment::activeOp id=1 t=0 tEnd=1 op=sect miFrom=0 miTo=1 suFrom=1 suTo=1 result=1
+SkOpSegment::activeOp id=3 t=1 tEnd=0 op=sect miFrom=1 miTo=1 suFrom=1 suTo=1 result=0
+SkOpSegment::markDone id=2 (0.833333373,3.5 1,2) t=0 [3] (0.833333373,3.5) tEnd=1 newWindSum=1 newOppSum=1 oppSum=1 windSum=1 windValue=1 oppValue=0
+SkOpSegment::findNextOp from:[2] to:[1] start=20180984 end=20181096
+bridgeOp current id=2 from=(0.833333373,3.5) to=(1,2)
+path.lineTo(1,2);
+path.close();
</div>
</div>
@@ -91,7 +153,7 @@ path.lineTo(494.376129,224.682892);
<script type="text/javascript">
var testDivs = [
- tiger8b_h_1,
+ loop17,
];
var decimal_places = 3; // make this 3 to show more precision