Index: src/pathops/SkOpSegment.cpp |
diff --git a/src/pathops/SkOpSegment.cpp b/src/pathops/SkOpSegment.cpp |
index 161eb33765de35bec78cc85ba9dbb736ced84480..b14be78d06fed2d17cbc9bacf26090314f6972f8 100644 |
--- a/src/pathops/SkOpSegment.cpp |
+++ b/src/pathops/SkOpSegment.cpp |
@@ -107,13 +107,10 @@ SkPoint SkOpSegment::activeLeftTop(SkOpSpanBase** firstSpan) { |
SkPoint topPt = {SK_ScalarMax, SK_ScalarMax}; |
// see if either end is not done since we want smaller Y of the pair |
bool lastDone = true; |
- double lastT = -1; |
SkOpSpanBase* span = &fHead; |
+ SkOpSpanBase* lastSpan = NULL; |
do { |
- if (lastDone && (span->final() || span->upCast()->done())) { |
- goto next; |
- } |
- { |
+ 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; |
@@ -121,19 +118,22 @@ SkPoint SkOpSegment::activeLeftTop(SkOpSpanBase** firstSpan) { |
*firstSpan = span; |
} |
} |
- if (fVerb != SkPath::kLine_Verb && !lastDone) { |
- SkPoint curveTop = (*CurveTop[fVerb])(fPts, fWeight, lastT, span->t()); |
- if (topPt.fY > curveTop.fY || (topPt.fY == curveTop.fY |
- && topPt.fX > curveTop.fX)) { |
+ if (fVerb != SkPath::kLine_Verb && !lastDone |
+ && fCubicType != SkDCubic::kSplitAtMaxCurvature_SkDCubicType) { |
+ double curveTopT; |
+ SkPoint curveTop = (*CurveTop[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) { |
- *firstSpan = span; |
+ const SkPoint& lastXY = lastSpan->pt(); |
+ *firstSpan = lastXY.fY > xy.fY || (lastXY.fY == xy.fY && lastXY.fX > xy.fX) |
+ ? span : lastSpan; |
} |
} |
} |
- lastT = span->t(); |
+ lastSpan = span; |
} |
-next: |
if (span->final()) { |
break; |
} |
@@ -490,52 +490,12 @@ void SkOpSegment::checkAngleCoin(SkOpCoincidence* coincidences, SkChunkAlloc* al |
// 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); |
- SkOpCurve edge; |
- if (fVerb == SkPath::kCubic_Verb) { |
- double startT = start->t(); |
- double endT = end->t(); |
- bool flip = startT > endT; |
- SkDCubic cubic; |
- cubic.set(fPts); |
- double inflectionTs[2]; |
- int inflections = cubic.findInflections(inflectionTs); |
- for (int index = 0; index < inflections; ++index) { |
- double inflectionT = inflectionTs[index]; |
- if (between(startT, inflectionT, endT)) { |
- if (flip) { |
- if (!roughly_equal(inflectionT, endT)) { |
- startT = inflectionT; |
- } |
- } else { |
- if (!roughly_equal(inflectionT, startT)) { |
- endT = inflectionT; |
- } |
- } |
- } |
- } |
- SkDCubic part = cubic.subDivide(startT, endT); |
- edge.set(part); |
- } else { |
- subDivide(start, end, &edge); |
+ if (fVerb != SkPath::kCubic_Verb) { |
+ SkOpCurve edge; |
+ this->subDivide(start, end, &edge); |
+ return SkDQuad::Clockwise(edge, swap); |
} |
- bool sumSet = false; |
- int points = SkPathOpsVerbToPoints(fVerb); |
- double sum = (edge[0].fX - edge[points].fX) * (edge[0].fY + edge[points].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.fPts); |
- *swap = sum > 0 && !cubic.monotonicInY(); |
- } else { |
- SkDQuad quad; |
- quad.set(edge.fPts); |
- *swap = sum > 0 && !quad.monotonicInY(); |
- } |
- return sum <= 0; |
+ return SkDCubic::Clockwise(fPts, start->t(), end->t(), swap); |
} |
void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle, |
@@ -1116,6 +1076,10 @@ SkOpSegment* SkOpSegment::findTop(bool firstPass, SkOpSpanBase** startPtr, SkOpS |
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(); |
@@ -1134,8 +1098,8 @@ SkOpSegment* SkOpSegment::findTop(bool firstPass, SkOpSpanBase** startPtr, SkOpS |
if (!firstAngle) { |
return NULL; // if all are unorderable, give up |
} |
-#if DEBUG_SORT |
- SkDebugf("%s\n", __FUNCTION__); |
+#if DEBUG_SWAP_TOP |
+ SkDebugf("-%s- firstAngle\n", __FUNCTION__); |
firstAngle->debugLoop(); |
#endif |
// skip edges that have already been processed |
@@ -1163,20 +1127,26 @@ SkOpSegment* SkOpSegment::findTop(bool firstPass, SkOpSpanBase** startPtr, SkOpS |
SkOpSpanBase* start = *startPtr; |
SkOpSpanBase* end = *endPtr; |
bool swap; |
- if (!leftSegment->clockwise(start, end, &swap)) { |
- #if DEBUG_SWAP_TOP |
- SkDebugf("%s swap=%d inflections=%d monotonic=%d\n", |
- __FUNCTION__, |
- swap, leftSegment->debugInflections(start, end), |
- leftSegment->monotonicInY(start, end)); |
- #endif |
- if (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); |
- } |
+ 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; |
} |
@@ -1191,6 +1161,7 @@ void SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkP |
fPts = pts; |
fWeight = weight; |
fVerb = verb; |
+ fCubicType = SkDCubic::kUnsplit_SkDCubicType; |
fCount = 0; |
fDoneCount = 0; |
fVisited = false; |