| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2013 Google Inc. | 2 * Copyright 2013 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 "SkPathWriter.h" | 9 #include "SkPathWriter.h" |
| 10 #include "SkTSort.h" | 10 #include "SkTSort.h" |
| 11 | 11 |
| 12 void SkOpContour::addCoincident(int index, SkOpContour* other, int otherIndex, | 12 bool SkOpContour::addCoincident(int index, SkOpContour* other, int otherIndex, |
| 13 const SkIntersections& ts, bool swap) { | 13 const SkIntersections& ts, bool swap) { |
| 14 SkPoint pt0 = ts.pt(0).asSkPoint(); |
| 15 SkPoint pt1 = ts.pt(1).asSkPoint(); |
| 16 if (pt0 == pt1) { |
| 17 // FIXME: one could imagine a case where it would be incorrect to ignore
this |
| 18 // suppose two self-intersecting cubics overlap to be coincident -- |
| 19 // this needs to check that by some measure the t values are far enough
apart |
| 20 // or needs to check to see if the self-intersection bit was set on the
cubic segment |
| 21 return false; |
| 22 } |
| 14 SkCoincidence& coincidence = fCoincidences.push_back(); | 23 SkCoincidence& coincidence = fCoincidences.push_back(); |
| 15 coincidence.fOther = other; | 24 coincidence.fOther = other; |
| 16 coincidence.fSegments[0] = index; | 25 coincidence.fSegments[0] = index; |
| 17 coincidence.fSegments[1] = otherIndex; | 26 coincidence.fSegments[1] = otherIndex; |
| 18 coincidence.fTs[swap][0] = ts[0][0]; | 27 coincidence.fTs[swap][0] = ts[0][0]; |
| 19 coincidence.fTs[swap][1] = ts[0][1]; | 28 coincidence.fTs[swap][1] = ts[0][1]; |
| 20 coincidence.fTs[!swap][0] = ts[1][0]; | 29 coincidence.fTs[!swap][0] = ts[1][0]; |
| 21 coincidence.fTs[!swap][1] = ts[1][1]; | 30 coincidence.fTs[!swap][1] = ts[1][1]; |
| 22 coincidence.fPts[0] = ts.pt(0).asSkPoint(); | 31 coincidence.fPts[0] = pt0; |
| 23 coincidence.fPts[1] = ts.pt(1).asSkPoint(); | 32 coincidence.fPts[1] = pt1; |
| 33 return true; |
| 24 } | 34 } |
| 25 | 35 |
| 26 SkOpSegment* SkOpContour::nonVerticalSegment(int* start, int* end) { | 36 SkOpSegment* SkOpContour::nonVerticalSegment(int* start, int* end) { |
| 27 int segmentCount = fSortedSegments.count(); | 37 int segmentCount = fSortedSegments.count(); |
| 28 SkASSERT(segmentCount > 0); | 38 SkASSERT(segmentCount > 0); |
| 29 for (int sortedIndex = fFirstSorted; sortedIndex < segmentCount; ++sortedInd
ex) { | 39 for (int sortedIndex = fFirstSorted; sortedIndex < segmentCount; ++sortedInd
ex) { |
| 30 SkOpSegment* testSegment = fSortedSegments[sortedIndex]; | 40 SkOpSegment* testSegment = fSortedSegments[sortedIndex]; |
| 31 if (testSegment->done()) { | 41 if (testSegment->done()) { |
| 32 continue; | 42 continue; |
| 33 } | 43 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 50 int thisIndex = coincidence.fSegments[0]; | 60 int thisIndex = coincidence.fSegments[0]; |
| 51 SkOpSegment& thisOne = fSegments[thisIndex]; | 61 SkOpSegment& thisOne = fSegments[thisIndex]; |
| 52 SkOpContour* otherContour = coincidence.fOther; | 62 SkOpContour* otherContour = coincidence.fOther; |
| 53 int otherIndex = coincidence.fSegments[1]; | 63 int otherIndex = coincidence.fSegments[1]; |
| 54 SkOpSegment& other = otherContour->fSegments[otherIndex]; | 64 SkOpSegment& other = otherContour->fSegments[otherIndex]; |
| 55 if ((thisOne.done() || other.done()) && thisOne.complete() && other.comp
lete()) { | 65 if ((thisOne.done() || other.done()) && thisOne.complete() && other.comp
lete()) { |
| 56 // OPTIMIZATION: remove from array | 66 // OPTIMIZATION: remove from array |
| 57 continue; | 67 continue; |
| 58 } | 68 } |
| 59 #if DEBUG_CONCIDENT | 69 #if DEBUG_CONCIDENT |
| 60 thisOne.debugShowTs(); | 70 thisOne.debugShowTs("-"); |
| 61 other.debugShowTs(); | 71 other.debugShowTs("o"); |
| 62 #endif | 72 #endif |
| 63 double startT = coincidence.fTs[0][0]; | 73 double startT = coincidence.fTs[0][0]; |
| 64 double endT = coincidence.fTs[0][1]; | 74 double endT = coincidence.fTs[0][1]; |
| 65 bool startSwapped, oStartSwapped, cancelers; | 75 bool startSwapped, oStartSwapped, cancelers; |
| 66 if ((cancelers = startSwapped = startT > endT)) { | 76 if ((cancelers = startSwapped = startT > endT)) { |
| 67 SkTSwap(startT, endT); | 77 SkTSwap(startT, endT); |
| 68 } | 78 } |
| 79 if (startT == endT) { // if one is very large the smaller may have colla
psed to nothing |
| 80 if (endT <= 1 - FLT_EPSILON) { |
| 81 endT += FLT_EPSILON; |
| 82 SkASSERT(endT <= 1); |
| 83 } else { |
| 84 startT -= FLT_EPSILON; |
| 85 SkASSERT(startT >= 0); |
| 86 } |
| 87 } |
| 69 SkASSERT(!approximately_negative(endT - startT)); | 88 SkASSERT(!approximately_negative(endT - startT)); |
| 70 double oStartT = coincidence.fTs[1][0]; | 89 double oStartT = coincidence.fTs[1][0]; |
| 71 double oEndT = coincidence.fTs[1][1]; | 90 double oEndT = coincidence.fTs[1][1]; |
| 72 if ((oStartSwapped = oStartT > oEndT)) { | 91 if ((oStartSwapped = oStartT > oEndT)) { |
| 73 SkTSwap(oStartT, oEndT); | 92 SkTSwap(oStartT, oEndT); |
| 74 cancelers ^= true; | 93 cancelers ^= true; |
| 75 } | 94 } |
| 76 SkASSERT(!approximately_negative(oEndT - oStartT)); | 95 SkASSERT(!approximately_negative(oEndT - oStartT)); |
| 77 if (cancelers) { | 96 if (cancelers) { |
| 78 // make sure startT and endT have t entries | 97 // make sure startT and endT have t entries |
| 98 const SkPoint& startPt = coincidence.fPts[startSwapped]; |
| 79 if (startT > 0 || oEndT < 1 | 99 if (startT > 0 || oEndT < 1 |
| 80 || thisOne.isMissing(startT) || other.isMissing(oEndT)) { | 100 || thisOne.isMissing(startT, startPt) || other.isMissing(oEn
dT, startPt)) { |
| 81 thisOne.addTPair(startT, &other, oEndT, true, coincidence.fPts[s
tartSwapped]); | 101 thisOne.addTPair(startT, &other, oEndT, true, startPt); |
| 82 } | 102 } |
| 103 const SkPoint& oStartPt = coincidence.fPts[oStartSwapped]; |
| 83 if (oStartT > 0 || endT < 1 | 104 if (oStartT > 0 || endT < 1 |
| 84 || thisOne.isMissing(endT) || other.isMissing(oStartT)) { | 105 || thisOne.isMissing(endT, oStartPt) || other.isMissing(oSta
rtT, oStartPt)) { |
| 85 other.addTPair(oStartT, &thisOne, endT, true, coincidence.fPts[o
StartSwapped]); | 106 other.addTPair(oStartT, &thisOne, endT, true, oStartPt); |
| 86 } | 107 } |
| 87 } else { | 108 } else { |
| 109 const SkPoint& startPt = coincidence.fPts[startSwapped]; |
| 88 if (startT > 0 || oStartT > 0 | 110 if (startT > 0 || oStartT > 0 |
| 89 || thisOne.isMissing(startT) || other.isMissing(oStartT)) { | 111 || thisOne.isMissing(startT, startPt) || other.isMissing(oSt
artT, startPt)) { |
| 90 thisOne.addTPair(startT, &other, oStartT, true, coincidence.fPts
[startSwapped]); | 112 thisOne.addTPair(startT, &other, oStartT, true, startPt); |
| 91 } | 113 } |
| 114 const SkPoint& oEndPt = coincidence.fPts[!oStartSwapped]; |
| 92 if (endT < 1 || oEndT < 1 | 115 if (endT < 1 || oEndT < 1 |
| 93 || thisOne.isMissing(endT) || other.isMissing(oEndT)) { | 116 || thisOne.isMissing(endT, oEndPt) || other.isMissing(oEndT,
oEndPt)) { |
| 94 other.addTPair(oEndT, &thisOne, endT, true, coincidence.fPts[!oS
tartSwapped]); | 117 other.addTPair(oEndT, &thisOne, endT, true, oEndPt); |
| 95 } | 118 } |
| 96 } | 119 } |
| 97 #if DEBUG_CONCIDENT | 120 #if DEBUG_CONCIDENT |
| 98 thisOne.debugShowTs(); | 121 thisOne.debugShowTs("+"); |
| 99 other.debugShowTs(); | 122 other.debugShowTs("o"); |
| 100 #endif | 123 #endif |
| 101 } | 124 } |
| 102 } | 125 } |
| 103 | 126 |
| 104 void SkOpContour::addPartialCoincident(int index, SkOpContour* other, int otherI
ndex, | 127 bool SkOpContour::addPartialCoincident(int index, SkOpContour* other, int otherI
ndex, |
| 105 const SkIntersections& ts, int ptIndex, bool swap) { | 128 const SkIntersections& ts, int ptIndex, bool swap) { |
| 129 SkPoint pt0 = ts.pt(ptIndex).asSkPoint(); |
| 130 SkPoint pt1 = ts.pt(ptIndex + 1).asSkPoint(); |
| 131 if (SkDPoint::ApproximatelyEqual(pt0, pt1)) { |
| 132 // FIXME: one could imagine a case where it would be incorrect to ignore
this |
| 133 // suppose two self-intersecting cubics overlap to form a partial coinci
dence -- |
| 134 // although it isn't clear why the regular coincidence could wouldn't pi
ck this up |
| 135 // this is exceptional enough to ignore for now |
| 136 return false; |
| 137 } |
| 106 SkCoincidence& coincidence = fPartialCoincidences.push_back(); | 138 SkCoincidence& coincidence = fPartialCoincidences.push_back(); |
| 107 coincidence.fOther = other; | 139 coincidence.fOther = other; |
| 108 coincidence.fSegments[0] = index; | 140 coincidence.fSegments[0] = index; |
| 109 coincidence.fSegments[1] = otherIndex; | 141 coincidence.fSegments[1] = otherIndex; |
| 110 coincidence.fTs[swap][0] = ts[0][index]; | 142 coincidence.fTs[swap][0] = ts[0][ptIndex]; |
| 111 coincidence.fTs[swap][1] = ts[0][index + 1]; | 143 coincidence.fTs[swap][1] = ts[0][ptIndex + 1]; |
| 112 coincidence.fTs[!swap][0] = ts[1][index]; | 144 coincidence.fTs[!swap][0] = ts[1][ptIndex]; |
| 113 coincidence.fTs[!swap][1] = ts[1][index + 1]; | 145 coincidence.fTs[!swap][1] = ts[1][ptIndex + 1]; |
| 114 coincidence.fPts[0] = ts.pt(index).asSkPoint(); | 146 coincidence.fPts[0] = pt0; |
| 115 coincidence.fPts[1] = ts.pt(index + 1).asSkPoint(); | 147 coincidence.fPts[1] = pt1; |
| 148 return true; |
| 116 } | 149 } |
| 117 | 150 |
| 118 void SkOpContour::calcCoincidentWinding() { | 151 void SkOpContour::calcCoincidentWinding() { |
| 119 int count = fCoincidences.count(); | 152 int count = fCoincidences.count(); |
| 120 #if DEBUG_CONCIDENT | 153 #if DEBUG_CONCIDENT |
| 121 if (count > 0) { | 154 if (count > 0) { |
| 122 SkDebugf("%s count=%d\n", __FUNCTION__, count); | 155 SkDebugf("%s count=%d\n", __FUNCTION__, count); |
| 123 } | 156 } |
| 124 #endif | 157 #endif |
| 125 for (int index = 0; index < count; ++index) { | 158 for (int index = 0; index < count; ++index) { |
| (...skipping 29 matching lines...) Expand all Loading... |
| 155 } | 188 } |
| 156 double startT = coincidence.fTs[0][0]; | 189 double startT = coincidence.fTs[0][0]; |
| 157 double endT = coincidence.fTs[0][1]; | 190 double endT = coincidence.fTs[0][1]; |
| 158 const SkPoint* startPt = &coincidence.fPts[0]; | 191 const SkPoint* startPt = &coincidence.fPts[0]; |
| 159 const SkPoint* endPt = &coincidence.fPts[1]; | 192 const SkPoint* endPt = &coincidence.fPts[1]; |
| 160 bool cancelers; | 193 bool cancelers; |
| 161 if ((cancelers = startT > endT)) { | 194 if ((cancelers = startT > endT)) { |
| 162 SkTSwap<double>(startT, endT); | 195 SkTSwap<double>(startT, endT); |
| 163 SkTSwap<const SkPoint*>(startPt, endPt); | 196 SkTSwap<const SkPoint*>(startPt, endPt); |
| 164 } | 197 } |
| 198 if (startT == endT) { // if span is very large, the smaller may have collaps
ed to nothing |
| 199 if (endT <= 1 - FLT_EPSILON) { |
| 200 endT += FLT_EPSILON; |
| 201 SkASSERT(endT <= 1); |
| 202 } else { |
| 203 startT -= FLT_EPSILON; |
| 204 SkASSERT(startT >= 0); |
| 205 } |
| 206 } |
| 165 SkASSERT(!approximately_negative(endT - startT)); | 207 SkASSERT(!approximately_negative(endT - startT)); |
| 166 double oStartT = coincidence.fTs[1][0]; | 208 double oStartT = coincidence.fTs[1][0]; |
| 167 double oEndT = coincidence.fTs[1][1]; | 209 double oEndT = coincidence.fTs[1][1]; |
| 168 if (oStartT > oEndT) { | 210 if (oStartT > oEndT) { |
| 169 SkTSwap<double>(oStartT, oEndT); | 211 SkTSwap<double>(oStartT, oEndT); |
| 170 cancelers ^= true; | 212 cancelers ^= true; |
| 171 } | 213 } |
| 172 SkASSERT(!approximately_negative(oEndT - oStartT)); | 214 SkASSERT(!approximately_negative(oEndT - oStartT)); |
| 173 if (cancelers) { | 215 if (cancelers) { |
| 174 thisOne.addTCancel(*startPt, *endPt, &other); | 216 thisOne.addTCancel(*startPt, *endPt, &other); |
| 175 } else { | 217 } else { |
| 176 thisOne.addTCoincident(*startPt, *endPt, &other); | 218 thisOne.addTCoincident(*startPt, *endPt, endT, &other); |
| 177 } | 219 } |
| 178 #if DEBUG_CONCIDENT | 220 #if DEBUG_CONCIDENT |
| 179 thisOne.debugShowTs(); | 221 thisOne.debugShowTs("p"); |
| 180 other.debugShowTs(); | 222 other.debugShowTs("o"); |
| 181 #endif | 223 #endif |
| 182 } | 224 } |
| 183 | 225 |
| 184 void SkOpContour::sortSegments() { | 226 void SkOpContour::sortSegments() { |
| 185 int segmentCount = fSegments.count(); | 227 int segmentCount = fSegments.count(); |
| 186 fSortedSegments.push_back_n(segmentCount); | 228 fSortedSegments.push_back_n(segmentCount); |
| 187 for (int test = 0; test < segmentCount; ++test) { | 229 for (int test = 0; test < segmentCount; ++test) { |
| 188 fSortedSegments[test] = &fSegments[test]; | 230 fSortedSegments[test] = &fSegments[test]; |
| 189 } | 231 } |
| 190 SkTQSort<SkOpSegment>(fSortedSegments.begin(), fSortedSegments.end() - 1); | 232 SkTQSort<SkOpSegment>(fSortedSegments.begin(), fSortedSegments.end() - 1); |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 283 SkDebugf("%s empty contour\n", __FUNCTION__); | 325 SkDebugf("%s empty contour\n", __FUNCTION__); |
| 284 SkASSERT(0); | 326 SkASSERT(0); |
| 285 // FIXME: delete empty contour? | 327 // FIXME: delete empty contour? |
| 286 return; | 328 return; |
| 287 } | 329 } |
| 288 fBounds = fSegments.front().bounds(); | 330 fBounds = fSegments.front().bounds(); |
| 289 for (int index = 1; index < count; ++index) { | 331 for (int index = 1; index < count; ++index) { |
| 290 fBounds.add(fSegments[index].bounds()); | 332 fBounds.add(fSegments[index].bounds()); |
| 291 } | 333 } |
| 292 } | 334 } |
| OLD | NEW |