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 "SkOpCoincidence.h" | 7 #include "SkOpCoincidence.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 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
100 SkOpSegment* other = oPtT->segment(); | 100 SkOpSegment* other = oPtT->segment(); |
101 SkOpSpanBase* oSpan = oPtT->span(); | 101 SkOpSpanBase* oSpan = oPtT->span(); |
102 return other->activeAngleInner(oSpan, startPtr, endPtr, done, sortable); | 102 return other->activeAngleInner(oSpan, startPtr, endPtr, done, sortable); |
103 } | 103 } |
104 | 104 |
105 SkPoint SkOpSegment::activeLeftTop(SkOpSpanBase** firstSpan) { | 105 SkPoint SkOpSegment::activeLeftTop(SkOpSpanBase** firstSpan) { |
106 SkASSERT(!done()); | 106 SkASSERT(!done()); |
107 SkPoint topPt = {SK_ScalarMax, SK_ScalarMax}; | 107 SkPoint topPt = {SK_ScalarMax, SK_ScalarMax}; |
108 // see if either end is not done since we want smaller Y of the pair | 108 // see if either end is not done since we want smaller Y of the pair |
109 bool lastDone = true; | 109 bool lastDone = true; |
110 double lastT = -1; | |
111 SkOpSpanBase* span = &fHead; | 110 SkOpSpanBase* span = &fHead; |
| 111 SkOpSpanBase* lastSpan = NULL; |
112 do { | 112 do { |
113 if (lastDone && (span->final() || span->upCast()->done())) { | 113 if (!lastDone || (!span->final() && !span->upCast()->done())) { |
114 goto next; | |
115 } | |
116 { | |
117 const SkPoint& xy = span->pt(); | 114 const SkPoint& xy = span->pt(); |
118 if (topPt.fY > xy.fY || (topPt.fY == xy.fY && topPt.fX > xy.fX)) { | 115 if (topPt.fY > xy.fY || (topPt.fY == xy.fY && topPt.fX > xy.fX)) { |
119 topPt = xy; | 116 topPt = xy; |
120 if (firstSpan) { | 117 if (firstSpan) { |
121 *firstSpan = span; | 118 *firstSpan = span; |
122 } | 119 } |
123 } | 120 } |
124 if (fVerb != SkPath::kLine_Verb && !lastDone) { | 121 if (fVerb != SkPath::kLine_Verb && !lastDone |
125 SkPoint curveTop = (*CurveTop[fVerb])(fPts, fWeight, lastT, span
->t()); | 122 && fCubicType != SkDCubic::kSplitAtMaxCurvature_SkDCubicType
) { |
126 if (topPt.fY > curveTop.fY || (topPt.fY == curveTop.fY | 123 double curveTopT; |
127 && topPt.fX > curveTop.fX)) { | 124 SkPoint curveTop = (*CurveTop[fVerb])(fPts, fWeight, lastSpan->t
(), span->t(), |
| 125 &curveTopT); |
| 126 if (topPt.fY > curveTop.fY || (topPt.fY == curveTop.fY && topPt.
fX > curveTop.fX)) { |
128 topPt = curveTop; | 127 topPt = curveTop; |
129 if (firstSpan) { | 128 if (firstSpan) { |
130 *firstSpan = span; | 129 const SkPoint& lastXY = lastSpan->pt(); |
| 130 *firstSpan = lastXY.fY > xy.fY || (lastXY.fY == xy.fY &&
lastXY.fX > xy.fX) |
| 131 ? span : lastSpan; |
131 } | 132 } |
132 } | 133 } |
133 } | 134 } |
134 lastT = span->t(); | 135 lastSpan = span; |
135 } | 136 } |
136 next: | |
137 if (span->final()) { | 137 if (span->final()) { |
138 break; | 138 break; |
139 } | 139 } |
140 lastDone = span->upCast()->done(); | 140 lastDone = span->upCast()->done(); |
141 } while ((span = span->upCast()->next())); | 141 } while ((span = span->upCast()->next())); |
142 return topPt; | 142 return topPt; |
143 } | 143 } |
144 | 144 |
145 bool SkOpSegment::activeOp(SkOpSpanBase* start, SkOpSpanBase* end, int xorMiMask
, int xorSuMask, | 145 bool SkOpSegment::activeOp(SkOpSpanBase* start, SkOpSpanBase* end, int xorMiMask
, int xorSuMask, |
146 SkPathOp op) { | 146 SkPathOp op) { |
(...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
483 angle = span->toAngle(); | 483 angle = span->toAngle(); |
484 if (angle && angle->fCheckCoincidence) { | 484 if (angle && angle->fCheckCoincidence) { |
485 angle->checkNearCoincidence(); | 485 angle->checkNearCoincidence(); |
486 } | 486 } |
487 } while ((base = span->next())); | 487 } while ((base = span->next())); |
488 } | 488 } |
489 | 489 |
490 // from http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of
-polygon-points-are-in-clockwise-order | 490 // from http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of
-polygon-points-are-in-clockwise-order |
491 bool SkOpSegment::clockwise(const SkOpSpanBase* start, const SkOpSpanBase* end,
bool* swap) const { | 491 bool SkOpSegment::clockwise(const SkOpSpanBase* start, const SkOpSpanBase* end,
bool* swap) const { |
492 SkASSERT(fVerb != SkPath::kLine_Verb); | 492 SkASSERT(fVerb != SkPath::kLine_Verb); |
493 SkOpCurve edge; | 493 if (fVerb != SkPath::kCubic_Verb) { |
494 if (fVerb == SkPath::kCubic_Verb) { | 494 SkOpCurve edge; |
495 double startT = start->t(); | 495 this->subDivide(start, end, &edge); |
496 double endT = end->t(); | 496 return SkDQuad::Clockwise(edge, swap); |
497 bool flip = startT > endT; | |
498 SkDCubic cubic; | |
499 cubic.set(fPts); | |
500 double inflectionTs[2]; | |
501 int inflections = cubic.findInflections(inflectionTs); | |
502 for (int index = 0; index < inflections; ++index) { | |
503 double inflectionT = inflectionTs[index]; | |
504 if (between(startT, inflectionT, endT)) { | |
505 if (flip) { | |
506 if (!roughly_equal(inflectionT, endT)) { | |
507 startT = inflectionT; | |
508 } | |
509 } else { | |
510 if (!roughly_equal(inflectionT, startT)) { | |
511 endT = inflectionT; | |
512 } | |
513 } | |
514 } | |
515 } | |
516 SkDCubic part = cubic.subDivide(startT, endT); | |
517 edge.set(part); | |
518 } else { | |
519 subDivide(start, end, &edge); | |
520 } | 497 } |
521 bool sumSet = false; | 498 return SkDCubic::Clockwise(fPts, start->t(), end->t(), swap); |
522 int points = SkPathOpsVerbToPoints(fVerb); | |
523 double sum = (edge[0].fX - edge[points].fX) * (edge[0].fY + edge[points].fY)
; | |
524 if (!sumSet) { | |
525 for (int idx = 0; idx < points; ++idx){ | |
526 sum += (edge[idx + 1].fX - edge[idx].fX) * (edge[idx + 1].fY + edge[
idx].fY); | |
527 } | |
528 } | |
529 if (fVerb == SkPath::kCubic_Verb) { | |
530 SkDCubic cubic; | |
531 cubic.set(edge.fPts); | |
532 *swap = sum > 0 && !cubic.monotonicInY(); | |
533 } else { | |
534 SkDQuad quad; | |
535 quad.set(edge.fPts); | |
536 *swap = sum > 0 && !quad.monotonicInY(); | |
537 } | |
538 return sum <= 0; | |
539 } | 499 } |
540 | 500 |
541 void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle
, | 501 void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle
, |
542 SkOpAngle::IncludeType includeType) { | 502 SkOpAngle::IncludeType includeType) { |
543 const SkOpSegment* baseSegment = baseAngle->segment(); | 503 const SkOpSegment* baseSegment = baseAngle->segment(); |
544 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle); | 504 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle); |
545 int sumSuWinding; | 505 int sumSuWinding; |
546 bool binary = includeType >= SkOpAngle::kBinarySingle; | 506 bool binary = includeType >= SkOpAngle::kBinarySingle; |
547 if (binary) { | 507 if (binary) { |
548 sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle); | 508 sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle); |
(...skipping 560 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1109 return NULL; | 1069 return NULL; |
1110 } | 1070 } |
1111 const SkOpAngle* baseAngle = markAngle->next() == markAngle && !isVertical()
? markAngle | 1071 const SkOpAngle* baseAngle = markAngle->next() == markAngle && !isVertical()
? markAngle |
1112 : markAngle->findFirst(); | 1072 : markAngle->findFirst(); |
1113 if (!baseAngle) { | 1073 if (!baseAngle) { |
1114 return NULL; // nothing to do | 1074 return NULL; // nothing to do |
1115 } | 1075 } |
1116 SkScalar top = SK_ScalarMax; | 1076 SkScalar top = SK_ScalarMax; |
1117 const SkOpAngle* firstAngle = NULL; | 1077 const SkOpAngle* firstAngle = NULL; |
1118 const SkOpAngle* angle = baseAngle; | 1078 const SkOpAngle* angle = baseAngle; |
| 1079 #if DEBUG_SWAP_TOP |
| 1080 SkDebugf("-%s- baseAngle\n", __FUNCTION__); |
| 1081 baseAngle->debugLoop(); |
| 1082 #endif |
1119 do { | 1083 do { |
1120 if (!angle->unorderable()) { | 1084 if (!angle->unorderable()) { |
1121 const SkOpSegment* next = angle->segment(); | 1085 const SkOpSegment* next = angle->segment(); |
1122 SkPathOpsBounds bounds; | 1086 SkPathOpsBounds bounds; |
1123 next->subDivideBounds(angle->end(), angle->start(), &bounds); | 1087 next->subDivideBounds(angle->end(), angle->start(), &bounds); |
1124 bool nearSame = AlmostEqualUlps(top, bounds.top()); | 1088 bool nearSame = AlmostEqualUlps(top, bounds.top()); |
1125 bool lowerSector = !firstAngle || angle->sectorEnd() < firstAngle->s
ectorStart(); | 1089 bool lowerSector = !firstAngle || angle->sectorEnd() < firstAngle->s
ectorStart(); |
1126 bool lesserSector = top > bounds.fTop; | 1090 bool lesserSector = top > bounds.fTop; |
1127 if (lesserSector && (!nearSame || lowerSector)) { | 1091 if (lesserSector && (!nearSame || lowerSector)) { |
1128 top = bounds.fTop; | 1092 top = bounds.fTop; |
1129 firstAngle = angle; | 1093 firstAngle = angle; |
1130 } | 1094 } |
1131 } | 1095 } |
1132 angle = angle->next(); | 1096 angle = angle->next(); |
1133 } while (angle != baseAngle); | 1097 } while (angle != baseAngle); |
1134 if (!firstAngle) { | 1098 if (!firstAngle) { |
1135 return NULL; // if all are unorderable, give up | 1099 return NULL; // if all are unorderable, give up |
1136 } | 1100 } |
1137 #if DEBUG_SORT | 1101 #if DEBUG_SWAP_TOP |
1138 SkDebugf("%s\n", __FUNCTION__); | 1102 SkDebugf("-%s- firstAngle\n", __FUNCTION__); |
1139 firstAngle->debugLoop(); | 1103 firstAngle->debugLoop(); |
1140 #endif | 1104 #endif |
1141 // skip edges that have already been processed | 1105 // skip edges that have already been processed |
1142 angle = firstAngle; | 1106 angle = firstAngle; |
1143 SkOpSegment* leftSegment = NULL; | 1107 SkOpSegment* leftSegment = NULL; |
1144 bool looped = false; | 1108 bool looped = false; |
1145 do { | 1109 do { |
1146 *unsortable = angle->unorderable(); | 1110 *unsortable = angle->unorderable(); |
1147 if (firstPass || !*unsortable) { | 1111 if (firstPass || !*unsortable) { |
1148 leftSegment = angle->segment(); | 1112 leftSegment = angle->segment(); |
1149 *startPtr = angle->end(); | 1113 *startPtr = angle->end(); |
1150 *endPtr = angle->start(); | 1114 *endPtr = angle->start(); |
1151 const SkOpSpan* firstSpan = (*startPtr)->starter(*endPtr); | 1115 const SkOpSpan* firstSpan = (*startPtr)->starter(*endPtr); |
1152 if (!firstSpan->done()) { | 1116 if (!firstSpan->done()) { |
1153 break; | 1117 break; |
1154 } | 1118 } |
1155 } | 1119 } |
1156 angle = angle->next(); | 1120 angle = angle->next(); |
1157 looped = true; | 1121 looped = true; |
1158 } while (angle != firstAngle); | 1122 } while (angle != firstAngle); |
1159 if (angle == firstAngle && looped) { | 1123 if (angle == firstAngle && looped) { |
1160 return NULL; | 1124 return NULL; |
1161 } | 1125 } |
1162 if (leftSegment->verb() >= SkPath::kQuad_Verb) { | 1126 if (leftSegment->verb() >= SkPath::kQuad_Verb) { |
1163 SkOpSpanBase* start = *startPtr; | 1127 SkOpSpanBase* start = *startPtr; |
1164 SkOpSpanBase* end = *endPtr; | 1128 SkOpSpanBase* end = *endPtr; |
1165 bool swap; | 1129 bool swap; |
1166 if (!leftSegment->clockwise(start, end, &swap)) { | 1130 bool cw = leftSegment->clockwise(start, end, &swap); |
1167 #if DEBUG_SWAP_TOP | 1131 #if DEBUG_SWAP_TOP |
1168 SkDebugf("%s swap=%d inflections=%d monotonic=%d\n", | 1132 SkDebugf("%s id=%d s=%1.9g e=%1.9g (%c) cw=%d swap=%d inflections=%d mon
otonic=%d\n", |
1169 __FUNCTION__, | 1133 __FUNCTION__, leftSegment->debugID(), start->t(), end->t(), |
1170 swap, leftSegment->debugInflections(start, end), | 1134 start->t() < end->t() ? '-' : '+', cw, |
1171 leftSegment->monotonicInY(start, end)); | 1135 swap, leftSegment->debugInflections(start, end), |
1172 #endif | 1136 leftSegment->monotonicInY(start, end)); |
1173 if (swap) { | 1137 #endif |
| 1138 if (!cw && swap) { |
1174 // FIXME: I doubt it makes sense to (necessarily) swap if the edge was not t
he first | 1139 // FIXME: I doubt it makes sense to (necessarily) swap if the edge was not t
he first |
1175 // sorted but merely the first not already processed (i.e., not done) | 1140 // sorted but merely the first not already processed (i.e., not done) |
1176 SkTSwap(*startPtr, *endPtr); | 1141 SkTSwap(*startPtr, *endPtr); |
1177 } | |
1178 } | 1142 } |
1179 // FIXME: clockwise isn't reliable -- try computing swap from tangent ? | 1143 // FIXME: clockwise isn't reliable -- try computing swap from tangent ? |
| 1144 } else { |
| 1145 #if DEBUG_SWAP_TOP |
| 1146 SkDebugf("%s id=%d s=%1.9g e=%1.9g (%c) cw=%d swap=%d inflections=%d mon
otonic=%d\n", |
| 1147 __FUNCTION__, leftSegment->debugID(), (*startPtr)->t(), (*endPtr
)->t(), |
| 1148 (*startPtr)->t() < (*endPtr)->t() ? '-' : '+', -1, -1, -1, 1); |
| 1149 #endif |
1180 } | 1150 } |
1181 return leftSegment; | 1151 return leftSegment; |
1182 } | 1152 } |
1183 | 1153 |
1184 SkOpGlobalState* SkOpSegment::globalState() const { | 1154 SkOpGlobalState* SkOpSegment::globalState() const { |
1185 return contour()->globalState(); | 1155 return contour()->globalState(); |
1186 } | 1156 } |
1187 | 1157 |
1188 void SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkP
ath::Verb verb) { | 1158 void SkOpSegment::init(SkPoint pts[], SkScalar weight, SkOpContour* contour, SkP
ath::Verb verb) { |
1189 fContour = contour; | 1159 fContour = contour; |
1190 fNext = NULL; | 1160 fNext = NULL; |
1191 fPts = pts; | 1161 fPts = pts; |
1192 fWeight = weight; | 1162 fWeight = weight; |
1193 fVerb = verb; | 1163 fVerb = verb; |
| 1164 fCubicType = SkDCubic::kUnsplit_SkDCubicType; |
1194 fCount = 0; | 1165 fCount = 0; |
1195 fDoneCount = 0; | 1166 fDoneCount = 0; |
1196 fVisited = false; | 1167 fVisited = false; |
1197 SkOpSpan* zeroSpan = &fHead; | 1168 SkOpSpan* zeroSpan = &fHead; |
1198 zeroSpan->init(this, NULL, 0, fPts[0]); | 1169 zeroSpan->init(this, NULL, 0, fPts[0]); |
1199 SkOpSpanBase* oneSpan = &fTail; | 1170 SkOpSpanBase* oneSpan = &fTail; |
1200 zeroSpan->setNext(oneSpan); | 1171 zeroSpan->setNext(oneSpan); |
1201 oneSpan->initBase(this, zeroSpan, 1, fPts[SkPathOpsVerbToPoints(fVerb)]); | 1172 oneSpan->initBase(this, zeroSpan, 1, fPts[SkPathOpsVerbToPoints(fVerb)]); |
1202 SkDEBUGCODE(fID = globalState()->nextSegmentID()); | 1173 SkDEBUGCODE(fID = globalState()->nextSegmentID()); |
1203 } | 1174 } |
(...skipping 853 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2057 #if DEBUG_WINDING_AT_T | 2028 #if DEBUG_WINDING_AT_T |
2058 SkDebugf(" dx=%c winding=%d\n", *dx > 0 ? '+' : '-', winding); | 2029 SkDebugf(" dx=%c winding=%d\n", *dx > 0 ? '+' : '-', winding); |
2059 #endif | 2030 #endif |
2060 return winding; | 2031 return winding; |
2061 } | 2032 } |
2062 | 2033 |
2063 int SkOpSegment::windSum(const SkOpAngle* angle) const { | 2034 int SkOpSegment::windSum(const SkOpAngle* angle) const { |
2064 const SkOpSpan* minSpan = angle->start()->starter(angle->end()); | 2035 const SkOpSpan* minSpan = angle->start()->starter(angle->end()); |
2065 return minSpan->windSum(); | 2036 return minSpan->windSum(); |
2066 } | 2037 } |
OLD | NEW |