Index: src/pathops/SkOpSegment.cpp |
diff --git a/src/pathops/SkOpSegment.cpp b/src/pathops/SkOpSegment.cpp |
index 090173fe967f94b7e57b18d3921dd9e937aa6d9d..4e8b5d28d9d80c14597ab8ddad9a2199ad21d145 100644 |
--- a/src/pathops/SkOpSegment.cpp |
+++ b/src/pathops/SkOpSegment.cpp |
@@ -3090,7 +3090,8 @@ SkOpSegment* SkOpSegment::findTop(int* tIndexPtr, int* endIndexPtr, bool* unsort |
markAngle = addSingletonAngles(step); |
} |
markAngle->markStops(); |
- const SkOpAngle* baseAngle = markAngle->findFirst(); |
+ const SkOpAngle* baseAngle = markAngle->next() == markAngle && !isVertical() ? markAngle |
+ : markAngle->findFirst(); |
if (!baseAngle) { |
return NULL; // nothing to do |
} |
@@ -3137,9 +3138,8 @@ SkOpSegment* SkOpSegment::findTop(int* tIndexPtr, int* endIndexPtr, bool* unsort |
if (leftSegment->verb() >= SkPath::kQuad_Verb) { |
const int tIndex = *tIndexPtr; |
const int endIndex = *endIndexPtr; |
- if (!leftSegment->clockwise(tIndex, endIndex)) { |
- bool swap = !leftSegment->monotonicInY(tIndex, endIndex) |
- && !leftSegment->serpentine(tIndex, endIndex); |
+ bool swap; |
+ if (!leftSegment->clockwise(tIndex, endIndex, &swap)) { |
#if DEBUG_SWAP_TOP |
SkDebugf("%s swap=%d inflections=%d serpentine=%d controlledbyends=%d monotonic=%d\n", |
__FUNCTION__, |
@@ -3621,13 +3621,45 @@ SkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int windi |
} |
// from http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of-polygon-points-are-in-clockwise-order |
-bool SkOpSegment::clockwise(int tStart, int tEnd) const { |
+bool SkOpSegment::clockwise(int tStart, int tEnd, bool* swap) const { |
SkASSERT(fVerb != SkPath::kLine_Verb); |
SkPoint edge[4]; |
subDivide(tStart, tEnd, edge); |
int points = SkPathOpsVerbToPoints(fVerb); |
double sum = (edge[0].fX - edge[points].fX) * (edge[0].fY + edge[points].fY); |
+ bool sumSet = false; |
if (fVerb == SkPath::kCubic_Verb) { |
+ SkDCubic cubic; |
+ cubic.set(edge); |
+ double inflectionTs[2]; |
+ int inflections = cubic.findInflections(inflectionTs); |
+ // FIXME: this fixes cubicOp114 and breaks cubicOp58d |
+ // the trouble is that cubics with inflections confuse whether the curve breaks towards |
+ // or away, which in turn is used to determine if it is on the far right or left. |
+ // Probably a totally different approach is in order. At one time I tried to project a |
+ // horizontal ray to determine winding, but was confused by how to map the vertically |
+ // oriented winding computation over. |
+ if (0 && inflections) { |
+ double tLo = this->span(tStart).fT; |
+ double tHi = this->span(tEnd).fT; |
+ double tLoStart = tLo; |
+ for (int index = 0; index < inflections; ++index) { |
+ if (between(tLo, inflectionTs[index], tHi)) { |
+ tLo = inflectionTs[index]; |
+ } |
+ } |
+ if (tLo != tLoStart && tLo != tHi) { |
+ SkDPoint sub[2]; |
+ sub[0] = cubic.ptAtT(tLo); |
+ sub[1].set(edge[3]); |
+ SkDPoint ctrl[2]; |
+ SkDCubic::SubDivide(fPts, sub[0], sub[1], tLo, tHi, ctrl); |
+ edge[0] = sub[0].asSkPoint(); |
+ edge[1] = ctrl[0].asSkPoint(); |
+ edge[2] = ctrl[1].asSkPoint(); |
+ sum = (edge[0].fX - edge[3].fX) * (edge[0].fY + edge[3].fY); |
+ } |
+ } |
SkScalar lesser = SkTMin<SkScalar>(edge[0].fY, edge[3].fY); |
if (edge[1].fY < lesser && edge[2].fY < lesser) { |
SkDLine tangent1 = {{ {edge[0].fX, edge[0].fY}, {edge[1].fX, edge[1].fY} }}; |
@@ -3636,12 +3668,23 @@ bool SkOpSegment::clockwise(int tStart, int tEnd) const { |
SkPoint topPt = cubic_top(fPts, fTs[tStart].fT, fTs[tEnd].fT); |
sum += (topPt.fX - edge[0].fX) * (topPt.fY + edge[0].fY); |
sum += (edge[3].fX - topPt.fX) * (edge[3].fY + topPt.fY); |
- return sum <= 0; |
+ sumSet = true; |
} |
} |
} |
- for (int idx = 0; idx < points; ++idx){ |
- sum += (edge[idx + 1].fX - edge[idx].fX) * (edge[idx + 1].fY + edge[idx].fY); |
+ if (!sumSet) { |
+ for (int idx = 0; idx < points; ++idx){ |
+ sum += (edge[idx + 1].fX - edge[idx].fX) * (edge[idx + 1].fY + edge[idx].fY); |
+ } |
+ } |
+ if (fVerb == SkPath::kCubic_Verb) { |
+ SkDCubic cubic; |
+ cubic.set(edge); |
+ *swap = sum > 0 && !cubic.monotonicInY() && !cubic.serpentine(); |
+ } else { |
+ SkDQuad quad; |
+ quad.set(edge); |
+ *swap = sum > 0 && !quad.monotonicInY(); |
} |
return sum <= 0; |
} |