| 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 |