OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 #include "SkIntersections.h" | 7 #include "SkIntersections.h" |
8 #include "SkOpContour.h" | 8 #include "SkOpContour.h" |
9 #include "SkOpSegment.h" | 9 #include "SkOpSegment.h" |
10 #include "SkPathWriter.h" | 10 #include "SkPathWriter.h" |
(...skipping 3072 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3083 SkASSERT(end != -1); | 3083 SkASSERT(end != -1); |
3084 } | 3084 } |
3085 // if the topmost T is not on end, or is three-way or more, find left | 3085 // if the topmost T is not on end, or is three-way or more, find left |
3086 // look for left-ness from tLeft to firstT (matching y of other) | 3086 // look for left-ness from tLeft to firstT (matching y of other) |
3087 SkASSERT(firstT - end != 0); | 3087 SkASSERT(firstT - end != 0); |
3088 SkOpAngle* markAngle = spanToAngle(firstT, end); | 3088 SkOpAngle* markAngle = spanToAngle(firstT, end); |
3089 if (!markAngle) { | 3089 if (!markAngle) { |
3090 markAngle = addSingletonAngles(step); | 3090 markAngle = addSingletonAngles(step); |
3091 } | 3091 } |
3092 markAngle->markStops(); | 3092 markAngle->markStops(); |
3093 const SkOpAngle* baseAngle = markAngle->findFirst(); | 3093 const SkOpAngle* baseAngle = markAngle->next() == markAngle && !isVertical()
? markAngle |
| 3094 : markAngle->findFirst(); |
3094 if (!baseAngle) { | 3095 if (!baseAngle) { |
3095 return NULL; // nothing to do | 3096 return NULL; // nothing to do |
3096 } | 3097 } |
3097 SkScalar top = SK_ScalarMax; | 3098 SkScalar top = SK_ScalarMax; |
3098 const SkOpAngle* firstAngle = NULL; | 3099 const SkOpAngle* firstAngle = NULL; |
3099 const SkOpAngle* angle = baseAngle; | 3100 const SkOpAngle* angle = baseAngle; |
3100 do { | 3101 do { |
3101 if (!angle->unorderable()) { | 3102 if (!angle->unorderable()) { |
3102 SkOpSegment* next = angle->segment(); | 3103 SkOpSegment* next = angle->segment(); |
3103 SkPathOpsBounds bounds; | 3104 SkPathOpsBounds bounds; |
(...skipping 26 matching lines...) Expand all Loading... |
3130 } | 3131 } |
3131 angle = angle->next(); | 3132 angle = angle->next(); |
3132 looped = true; | 3133 looped = true; |
3133 } while (angle != firstAngle); | 3134 } while (angle != firstAngle); |
3134 if (angle == firstAngle && looped) { | 3135 if (angle == firstAngle && looped) { |
3135 return NULL; | 3136 return NULL; |
3136 } | 3137 } |
3137 if (leftSegment->verb() >= SkPath::kQuad_Verb) { | 3138 if (leftSegment->verb() >= SkPath::kQuad_Verb) { |
3138 const int tIndex = *tIndexPtr; | 3139 const int tIndex = *tIndexPtr; |
3139 const int endIndex = *endIndexPtr; | 3140 const int endIndex = *endIndexPtr; |
3140 if (!leftSegment->clockwise(tIndex, endIndex)) { | 3141 bool swap; |
3141 bool swap = !leftSegment->monotonicInY(tIndex, endIndex) | 3142 if (!leftSegment->clockwise(tIndex, endIndex, &swap)) { |
3142 && !leftSegment->serpentine(tIndex, endIndex); | |
3143 #if DEBUG_SWAP_TOP | 3143 #if DEBUG_SWAP_TOP |
3144 SkDebugf("%s swap=%d inflections=%d serpentine=%d controlledbyends=%
d monotonic=%d\n", | 3144 SkDebugf("%s swap=%d inflections=%d serpentine=%d controlledbyends=%
d monotonic=%d\n", |
3145 __FUNCTION__, | 3145 __FUNCTION__, |
3146 swap, leftSegment->debugInflections(tIndex, endIndex), | 3146 swap, leftSegment->debugInflections(tIndex, endIndex), |
3147 leftSegment->serpentine(tIndex, endIndex), | 3147 leftSegment->serpentine(tIndex, endIndex), |
3148 leftSegment->controlsContainedByEnds(tIndex, endIndex), | 3148 leftSegment->controlsContainedByEnds(tIndex, endIndex), |
3149 leftSegment->monotonicInY(tIndex, endIndex)); | 3149 leftSegment->monotonicInY(tIndex, endIndex)); |
3150 #endif | 3150 #endif |
3151 if (swap) { | 3151 if (swap) { |
3152 // FIXME: I doubt it makes sense to (necessarily) swap if the edge was not t
he first | 3152 // FIXME: I doubt it makes sense to (necessarily) swap if the edge was not t
he first |
(...skipping 461 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3614 SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding); | 3614 SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding); |
3615 #if DEBUG_LIMIT_WIND_SUM | 3615 #if DEBUG_LIMIT_WIND_SUM |
3616 SkASSERT(abs(oppWinding) <= DEBUG_LIMIT_WIND_SUM); | 3616 SkASSERT(abs(oppWinding) <= DEBUG_LIMIT_WIND_SUM); |
3617 #endif | 3617 #endif |
3618 span.fOppSum = oppWinding; | 3618 span.fOppSum = oppWinding; |
3619 debugValidate(); | 3619 debugValidate(); |
3620 return &span; | 3620 return &span; |
3621 } | 3621 } |
3622 | 3622 |
3623 // from http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of
-polygon-points-are-in-clockwise-order | 3623 // from http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of
-polygon-points-are-in-clockwise-order |
3624 bool SkOpSegment::clockwise(int tStart, int tEnd) const { | 3624 bool SkOpSegment::clockwise(int tStart, int tEnd, bool* swap) const { |
3625 SkASSERT(fVerb != SkPath::kLine_Verb); | 3625 SkASSERT(fVerb != SkPath::kLine_Verb); |
3626 SkPoint edge[4]; | 3626 SkPoint edge[4]; |
3627 subDivide(tStart, tEnd, edge); | 3627 subDivide(tStart, tEnd, edge); |
3628 int points = SkPathOpsVerbToPoints(fVerb); | 3628 int points = SkPathOpsVerbToPoints(fVerb); |
3629 double sum = (edge[0].fX - edge[points].fX) * (edge[0].fY + edge[points].fY)
; | 3629 double sum = (edge[0].fX - edge[points].fX) * (edge[0].fY + edge[points].fY)
; |
| 3630 bool sumSet = false; |
3630 if (fVerb == SkPath::kCubic_Verb) { | 3631 if (fVerb == SkPath::kCubic_Verb) { |
| 3632 SkDCubic cubic; |
| 3633 cubic.set(edge); |
| 3634 double inflectionTs[2]; |
| 3635 int inflections = cubic.findInflections(inflectionTs); |
| 3636 // FIXME: this fixes cubicOp114 and breaks cubicOp58d |
| 3637 // the trouble is that cubics with inflections confuse whether the curve
breaks towards |
| 3638 // or away, which in turn is used to determine if it is on the far right
or left. |
| 3639 // Probably a totally different approach is in order. At one time I trie
d to project a |
| 3640 // horizontal ray to determine winding, but was confused by how to map t
he vertically |
| 3641 // oriented winding computation over. |
| 3642 if (0 && inflections) { |
| 3643 double tLo = this->span(tStart).fT; |
| 3644 double tHi = this->span(tEnd).fT; |
| 3645 double tLoStart = tLo; |
| 3646 for (int index = 0; index < inflections; ++index) { |
| 3647 if (between(tLo, inflectionTs[index], tHi)) { |
| 3648 tLo = inflectionTs[index]; |
| 3649 } |
| 3650 } |
| 3651 if (tLo != tLoStart && tLo != tHi) { |
| 3652 SkDPoint sub[2]; |
| 3653 sub[0] = cubic.ptAtT(tLo); |
| 3654 sub[1].set(edge[3]); |
| 3655 SkDPoint ctrl[2]; |
| 3656 SkDCubic::SubDivide(fPts, sub[0], sub[1], tLo, tHi, ctrl); |
| 3657 edge[0] = sub[0].asSkPoint(); |
| 3658 edge[1] = ctrl[0].asSkPoint(); |
| 3659 edge[2] = ctrl[1].asSkPoint(); |
| 3660 sum = (edge[0].fX - edge[3].fX) * (edge[0].fY + edge[3].fY); |
| 3661 } |
| 3662 } |
3631 SkScalar lesser = SkTMin<SkScalar>(edge[0].fY, edge[3].fY); | 3663 SkScalar lesser = SkTMin<SkScalar>(edge[0].fY, edge[3].fY); |
3632 if (edge[1].fY < lesser && edge[2].fY < lesser) { | 3664 if (edge[1].fY < lesser && edge[2].fY < lesser) { |
3633 SkDLine tangent1 = {{ {edge[0].fX, edge[0].fY}, {edge[1].fX, edge[1]
.fY} }}; | 3665 SkDLine tangent1 = {{ {edge[0].fX, edge[0].fY}, {edge[1].fX, edge[1]
.fY} }}; |
3634 SkDLine tangent2 = {{ {edge[2].fX, edge[2].fY}, {edge[3].fX, edge[3]
.fY} }}; | 3666 SkDLine tangent2 = {{ {edge[2].fX, edge[2].fY}, {edge[3].fX, edge[3]
.fY} }}; |
3635 if (SkIntersections::Test(tangent1, tangent2)) { | 3667 if (SkIntersections::Test(tangent1, tangent2)) { |
3636 SkPoint topPt = cubic_top(fPts, fTs[tStart].fT, fTs[tEnd].fT); | 3668 SkPoint topPt = cubic_top(fPts, fTs[tStart].fT, fTs[tEnd].fT); |
3637 sum += (topPt.fX - edge[0].fX) * (topPt.fY + edge[0].fY); | 3669 sum += (topPt.fX - edge[0].fX) * (topPt.fY + edge[0].fY); |
3638 sum += (edge[3].fX - topPt.fX) * (edge[3].fY + topPt.fY); | 3670 sum += (edge[3].fX - topPt.fX) * (edge[3].fY + topPt.fY); |
3639 return sum <= 0; | 3671 sumSet = true; |
3640 } | 3672 } |
3641 } | 3673 } |
3642 } | 3674 } |
3643 for (int idx = 0; idx < points; ++idx){ | 3675 if (!sumSet) { |
3644 sum += (edge[idx + 1].fX - edge[idx].fX) * (edge[idx + 1].fY + edge[idx]
.fY); | 3676 for (int idx = 0; idx < points; ++idx){ |
| 3677 sum += (edge[idx + 1].fX - edge[idx].fX) * (edge[idx + 1].fY + edge[
idx].fY); |
| 3678 } |
| 3679 } |
| 3680 if (fVerb == SkPath::kCubic_Verb) { |
| 3681 SkDCubic cubic; |
| 3682 cubic.set(edge); |
| 3683 *swap = sum > 0 && !cubic.monotonicInY() && !cubic.serpentine(); |
| 3684 } else { |
| 3685 SkDQuad quad; |
| 3686 quad.set(edge); |
| 3687 *swap = sum > 0 && !quad.monotonicInY(); |
3645 } | 3688 } |
3646 return sum <= 0; | 3689 return sum <= 0; |
3647 } | 3690 } |
3648 | 3691 |
3649 bool SkOpSegment::monotonicInY(int tStart, int tEnd) const { | 3692 bool SkOpSegment::monotonicInY(int tStart, int tEnd) const { |
3650 SkASSERT(fVerb != SkPath::kLine_Verb); | 3693 SkASSERT(fVerb != SkPath::kLine_Verb); |
3651 if (fVerb == SkPath::kQuad_Verb) { | 3694 if (fVerb == SkPath::kQuad_Verb) { |
3652 SkDQuad dst = SkDQuad::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT); | 3695 SkDQuad dst = SkDQuad::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT); |
3653 return dst.monotonicInY(); | 3696 return dst.monotonicInY(); |
3654 } | 3697 } |
(...skipping 638 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4293 SkASSERT(span->fWindValue > 0 || span->fOppValue != 0); | 4336 SkASSERT(span->fWindValue > 0 || span->fOppValue != 0); |
4294 span->fWindValue = 0; | 4337 span->fWindValue = 0; |
4295 span->fOppValue = 0; | 4338 span->fOppValue = 0; |
4296 if (span->fTiny || span->fSmall) { | 4339 if (span->fTiny || span->fSmall) { |
4297 return; | 4340 return; |
4298 } | 4341 } |
4299 SkASSERT(!span->fDone); | 4342 SkASSERT(!span->fDone); |
4300 span->fDone = true; | 4343 span->fDone = true; |
4301 ++fDoneSpans; | 4344 ++fDoneSpans; |
4302 } | 4345 } |
OLD | NEW |