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" |
(...skipping 10 matching lines...) Expand all Loading... |
21 return false; | 21 return false; |
22 } | 22 } |
23 SkCoincidence& coincidence = fCoincidences.push_back(); | 23 SkCoincidence& coincidence = fCoincidences.push_back(); |
24 coincidence.fOther = other; | 24 coincidence.fOther = other; |
25 coincidence.fSegments[0] = index; | 25 coincidence.fSegments[0] = index; |
26 coincidence.fSegments[1] = otherIndex; | 26 coincidence.fSegments[1] = otherIndex; |
27 coincidence.fTs[swap][0] = ts[0][0]; | 27 coincidence.fTs[swap][0] = ts[0][0]; |
28 coincidence.fTs[swap][1] = ts[0][1]; | 28 coincidence.fTs[swap][1] = ts[0][1]; |
29 coincidence.fTs[!swap][0] = ts[1][0]; | 29 coincidence.fTs[!swap][0] = ts[1][0]; |
30 coincidence.fTs[!swap][1] = ts[1][1]; | 30 coincidence.fTs[!swap][1] = ts[1][1]; |
31 coincidence.fPts[0] = pt0; | 31 coincidence.fPts[swap][0] = pt0; |
32 coincidence.fPts[1] = pt1; | 32 coincidence.fPts[swap][1] = pt1; |
| 33 bool nearStart = ts.nearlySame(0); |
| 34 bool nearEnd = ts.nearlySame(1); |
| 35 coincidence.fPts[!swap][0] = nearStart ? ts.pt2(0).asSkPoint() : pt0; |
| 36 coincidence.fPts[!swap][1] = nearEnd ? ts.pt2(1).asSkPoint() : pt1; |
| 37 coincidence.fNearly[0] = nearStart; |
| 38 coincidence.fNearly[1] = nearEnd; |
33 return true; | 39 return true; |
34 } | 40 } |
35 | 41 |
36 SkOpSegment* SkOpContour::nonVerticalSegment(int* start, int* end) { | 42 SkOpSegment* SkOpContour::nonVerticalSegment(int* start, int* end) { |
37 int segmentCount = fSortedSegments.count(); | 43 int segmentCount = fSortedSegments.count(); |
38 SkASSERT(segmentCount > 0); | 44 SkASSERT(segmentCount > 0); |
39 for (int sortedIndex = fFirstSorted; sortedIndex < segmentCount; ++sortedInd
ex) { | 45 for (int sortedIndex = fFirstSorted; sortedIndex < segmentCount; ++sortedInd
ex) { |
40 SkOpSegment* testSegment = fSortedSegments[sortedIndex]; | 46 SkOpSegment* testSegment = fSortedSegments[sortedIndex]; |
41 if (testSegment->done()) { | 47 if (testSegment->done()) { |
42 continue; | 48 continue; |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
86 } | 92 } |
87 } | 93 } |
88 SkASSERT(!approximately_negative(endT - startT)); | 94 SkASSERT(!approximately_negative(endT - startT)); |
89 double oStartT = coincidence.fTs[1][0]; | 95 double oStartT = coincidence.fTs[1][0]; |
90 double oEndT = coincidence.fTs[1][1]; | 96 double oEndT = coincidence.fTs[1][1]; |
91 if ((oStartSwapped = oStartT > oEndT)) { | 97 if ((oStartSwapped = oStartT > oEndT)) { |
92 SkTSwap(oStartT, oEndT); | 98 SkTSwap(oStartT, oEndT); |
93 cancelers ^= true; | 99 cancelers ^= true; |
94 } | 100 } |
95 SkASSERT(!approximately_negative(oEndT - oStartT)); | 101 SkASSERT(!approximately_negative(oEndT - oStartT)); |
| 102 const SkPoint& startPt = coincidence.fPts[0][startSwapped]; |
96 if (cancelers) { | 103 if (cancelers) { |
97 // make sure startT and endT have t entries | 104 // make sure startT and endT have t entries |
98 const SkPoint& startPt = coincidence.fPts[startSwapped]; | |
99 if (startT > 0 || oEndT < 1 | 105 if (startT > 0 || oEndT < 1 |
100 || thisOne.isMissing(startT, startPt) || other.isMissing(oEn
dT, startPt)) { | 106 || thisOne.isMissing(startT, startPt) || other.isMissing(oEn
dT, startPt)) { |
101 thisOne.addTPair(startT, &other, oEndT, true, startPt); | 107 thisOne.addTPair(startT, &other, oEndT, true, startPt, |
| 108 coincidence.fPts[1][startSwapped]); |
102 } | 109 } |
103 const SkPoint& oStartPt = coincidence.fPts[oStartSwapped]; | 110 const SkPoint& oStartPt = coincidence.fPts[1][oStartSwapped]; |
104 if (oStartT > 0 || endT < 1 | 111 if (oStartT > 0 || endT < 1 |
105 || thisOne.isMissing(endT, oStartPt) || other.isMissing(oSta
rtT, oStartPt)) { | 112 || thisOne.isMissing(endT, oStartPt) || other.isMissing(oSta
rtT, oStartPt)) { |
106 other.addTPair(oStartT, &thisOne, endT, true, oStartPt); | 113 other.addTPair(oStartT, &thisOne, endT, true, oStartPt, |
| 114 coincidence.fPts[0][oStartSwapped]); |
107 } | 115 } |
108 } else { | 116 } else { |
109 const SkPoint& startPt = coincidence.fPts[startSwapped]; | |
110 if (startT > 0 || oStartT > 0 | 117 if (startT > 0 || oStartT > 0 |
111 || thisOne.isMissing(startT, startPt) || other.isMissing(oSt
artT, startPt)) { | 118 || thisOne.isMissing(startT, startPt) || other.isMissing(oSt
artT, startPt)) { |
112 thisOne.addTPair(startT, &other, oStartT, true, startPt); | 119 thisOne.addTPair(startT, &other, oStartT, true, startPt, |
| 120 coincidence.fPts[1][startSwapped]); |
113 } | 121 } |
114 const SkPoint& oEndPt = coincidence.fPts[!oStartSwapped]; | 122 const SkPoint& oEndPt = coincidence.fPts[1][!oStartSwapped]; |
115 if (endT < 1 || oEndT < 1 | 123 if (endT < 1 || oEndT < 1 |
116 || thisOne.isMissing(endT, oEndPt) || other.isMissing(oEndT,
oEndPt)) { | 124 || thisOne.isMissing(endT, oEndPt) || other.isMissing(oEndT,
oEndPt)) { |
117 other.addTPair(oEndT, &thisOne, endT, true, oEndPt); | 125 other.addTPair(oEndT, &thisOne, endT, true, oEndPt, |
| 126 coincidence.fPts[0][!oStartSwapped]); |
118 } | 127 } |
119 } | 128 } |
120 #if DEBUG_CONCIDENT | 129 #if DEBUG_CONCIDENT |
121 thisOne.debugShowTs("+"); | 130 thisOne.debugShowTs("+"); |
122 other.debugShowTs("o"); | 131 other.debugShowTs("o"); |
123 #endif | 132 #endif |
124 } | 133 } |
| 134 // if there are multiple pairs of coincidence that share an edge, see if the
opposite |
| 135 // are also coincident |
| 136 for (int index = 0; index < count - 1; ++index) { |
| 137 const SkCoincidence& coincidence = fCoincidences[index]; |
| 138 int thisIndex = coincidence.fSegments[0]; |
| 139 SkOpContour* otherContour = coincidence.fOther; |
| 140 int otherIndex = coincidence.fSegments[1]; |
| 141 for (int idx2 = 1; idx2 < count; ++idx2) { |
| 142 const SkCoincidence& innerCoin = fCoincidences[idx2]; |
| 143 int innerThisIndex = innerCoin.fSegments[0]; |
| 144 if (thisIndex == innerThisIndex) { |
| 145 checkCoincidentPair(coincidence, 1, innerCoin, 1, false); |
| 146 } |
| 147 if (this == otherContour && otherIndex == innerThisIndex) { |
| 148 checkCoincidentPair(coincidence, 0, innerCoin, 1, false); |
| 149 } |
| 150 SkOpContour* innerOtherContour = innerCoin.fOther; |
| 151 innerThisIndex = innerCoin.fSegments[1]; |
| 152 if (this == innerOtherContour && thisIndex == innerThisIndex) { |
| 153 checkCoincidentPair(coincidence, 1, innerCoin, 0, false); |
| 154 } |
| 155 if (otherContour == innerOtherContour && otherIndex == innerThisInde
x) { |
| 156 checkCoincidentPair(coincidence, 0, innerCoin, 0, false); |
| 157 } |
| 158 } |
| 159 } |
125 } | 160 } |
126 | 161 |
127 bool SkOpContour::addPartialCoincident(int index, SkOpContour* other, int otherI
ndex, | 162 bool SkOpContour::addPartialCoincident(int index, SkOpContour* other, int otherI
ndex, |
128 const SkIntersections& ts, int ptIndex, bool swap) { | 163 const SkIntersections& ts, int ptIndex, bool swap) { |
129 SkPoint pt0 = ts.pt(ptIndex).asSkPoint(); | 164 SkPoint pt0 = ts.pt(ptIndex).asSkPoint(); |
130 SkPoint pt1 = ts.pt(ptIndex + 1).asSkPoint(); | 165 SkPoint pt1 = ts.pt(ptIndex + 1).asSkPoint(); |
131 if (SkDPoint::ApproximatelyEqual(pt0, pt1)) { | 166 if (SkDPoint::ApproximatelyEqual(pt0, pt1)) { |
132 // FIXME: one could imagine a case where it would be incorrect to ignore
this | 167 // 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 -- | 168 // 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 | 169 // 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 | 170 // this is exceptional enough to ignore for now |
136 return false; | 171 return false; |
137 } | 172 } |
138 SkCoincidence& coincidence = fPartialCoincidences.push_back(); | 173 SkCoincidence& coincidence = fPartialCoincidences.push_back(); |
139 coincidence.fOther = other; | 174 coincidence.fOther = other; |
140 coincidence.fSegments[0] = index; | 175 coincidence.fSegments[0] = index; |
141 coincidence.fSegments[1] = otherIndex; | 176 coincidence.fSegments[1] = otherIndex; |
142 coincidence.fTs[swap][0] = ts[0][ptIndex]; | 177 coincidence.fTs[swap][0] = ts[0][ptIndex]; |
143 coincidence.fTs[swap][1] = ts[0][ptIndex + 1]; | 178 coincidence.fTs[swap][1] = ts[0][ptIndex + 1]; |
144 coincidence.fTs[!swap][0] = ts[1][ptIndex]; | 179 coincidence.fTs[!swap][0] = ts[1][ptIndex]; |
145 coincidence.fTs[!swap][1] = ts[1][ptIndex + 1]; | 180 coincidence.fTs[!swap][1] = ts[1][ptIndex + 1]; |
146 coincidence.fPts[0] = pt0; | 181 coincidence.fPts[0][0] = coincidence.fPts[1][0] = pt0; |
147 coincidence.fPts[1] = pt1; | 182 coincidence.fPts[0][1] = coincidence.fPts[1][1] = pt1; |
| 183 coincidence.fNearly[0] = 0; |
| 184 coincidence.fNearly[1] = 0; |
148 return true; | 185 return true; |
149 } | 186 } |
150 | 187 |
| 188 void SkOpContour::align(const SkOpSegment::AlignedSpan& aligned, bool swap, |
| 189 SkCoincidence* coincidence) { |
| 190 for (int idx2 = 0; idx2 < 2; ++idx2) { |
| 191 if (coincidence->fPts[0][idx2] == aligned.fOldPt |
| 192 && coincidence->fTs[swap][idx2] == aligned.fOldT) { |
| 193 SkASSERT(SkDPoint::RoughlyEqual(coincidence->fPts[0][idx2], aligned.
fPt)); |
| 194 coincidence->fPts[0][idx2] = aligned.fPt; |
| 195 SkASSERT(way_roughly_equal(coincidence->fTs[swap][idx2], aligned.fT)
); |
| 196 coincidence->fTs[swap][idx2] = aligned.fT; |
| 197 } |
| 198 } |
| 199 } |
| 200 |
| 201 void SkOpContour::alignCoincidence(const SkOpSegment::AlignedSpan& aligned, |
| 202 SkTArray<SkCoincidence, true>* coincidences) { |
| 203 int count = coincidences->count(); |
| 204 for (int index = 0; index < count; ++index) { |
| 205 SkCoincidence& coincidence = (*coincidences)[index]; |
| 206 int thisIndex = coincidence.fSegments[0]; |
| 207 const SkOpSegment* thisOne = &fSegments[thisIndex]; |
| 208 const SkOpContour* otherContour = coincidence.fOther; |
| 209 int otherIndex = coincidence.fSegments[1]; |
| 210 const SkOpSegment* other = &otherContour->fSegments[otherIndex]; |
| 211 if (thisOne == aligned.fOther1 && other == aligned.fOther2) { |
| 212 align(aligned, false, &coincidence); |
| 213 } else if (thisOne == aligned.fOther2 && other == aligned.fOther1) { |
| 214 align(aligned, true, &coincidence); |
| 215 } |
| 216 } |
| 217 } |
| 218 |
| 219 void SkOpContour::alignTPt(int segmentIndex, const SkOpContour* other, int other
Index, |
| 220 bool swap, int tIndex, SkIntersections* ts, SkPoint* point) const { |
| 221 int zeroPt; |
| 222 if ((zeroPt = alignT(swap, tIndex, ts)) >= 0) { |
| 223 alignPt(segmentIndex, point, zeroPt); |
| 224 } |
| 225 if ((zeroPt = other->alignT(!swap, tIndex, ts)) >= 0) { |
| 226 other->alignPt(otherIndex, point, zeroPt); |
| 227 } |
| 228 } |
| 229 |
| 230 void SkOpContour::alignPt(int index, SkPoint* point, int zeroPt) const { |
| 231 const SkOpSegment& segment = fSegments[index]; |
| 232 if (0 == zeroPt) { |
| 233 *point = segment.pts()[0]; |
| 234 } else { |
| 235 *point = segment.pts()[SkPathOpsVerbToPoints(segment.verb())]; |
| 236 } |
| 237 } |
| 238 |
| 239 int SkOpContour::alignT(bool swap, int tIndex, SkIntersections* ts) const { |
| 240 double tVal = (*ts)[swap][tIndex]; |
| 241 if (tVal != 0 && precisely_zero(tVal)) { |
| 242 ts->set(swap, tIndex, 0); |
| 243 return 0; |
| 244 } |
| 245 if (tVal != 1 && precisely_equal(tVal, 1)) { |
| 246 ts->set(swap, tIndex, 1); |
| 247 return 1; |
| 248 } |
| 249 return -1; |
| 250 } |
| 251 |
151 bool SkOpContour::calcAngles() { | 252 bool SkOpContour::calcAngles() { |
152 int segmentCount = fSegments.count(); | 253 int segmentCount = fSegments.count(); |
153 for (int test = 0; test < segmentCount; ++test) { | 254 for (int test = 0; test < segmentCount; ++test) { |
154 if (!fSegments[test].calcAngles()) { | 255 if (!fSegments[test].calcAngles()) { |
155 return false; | 256 return false; |
156 } | 257 } |
157 } | 258 } |
158 return true; | 259 return true; |
159 } | 260 } |
160 | 261 |
(...skipping 12 matching lines...) Expand all Loading... |
173 | 274 |
174 void SkOpContour::calcPartialCoincidentWinding() { | 275 void SkOpContour::calcPartialCoincidentWinding() { |
175 int count = fPartialCoincidences.count(); | 276 int count = fPartialCoincidences.count(); |
176 #if DEBUG_CONCIDENT | 277 #if DEBUG_CONCIDENT |
177 if (count > 0) { | 278 if (count > 0) { |
178 SkDebugf("%s count=%d\n", __FUNCTION__, count); | 279 SkDebugf("%s count=%d\n", __FUNCTION__, count); |
179 } | 280 } |
180 #endif | 281 #endif |
181 for (int index = 0; index < count; ++index) { | 282 for (int index = 0; index < count; ++index) { |
182 SkCoincidence& coincidence = fPartialCoincidences[index]; | 283 SkCoincidence& coincidence = fPartialCoincidences[index]; |
183 calcCommonCoincidentWinding(coincidence); | 284 calcCommonCoincidentWinding(coincidence); |
| 285 } |
| 286 // if there are multiple pairs of partial coincidence that share an edge, se
e if the opposite |
| 287 // are also coincident |
| 288 for (int index = 0; index < count - 1; ++index) { |
| 289 const SkCoincidence& coincidence = fPartialCoincidences[index]; |
| 290 int thisIndex = coincidence.fSegments[0]; |
| 291 SkOpContour* otherContour = coincidence.fOther; |
| 292 int otherIndex = coincidence.fSegments[1]; |
| 293 for (int idx2 = 1; idx2 < count; ++idx2) { |
| 294 const SkCoincidence& innerCoin = fPartialCoincidences[idx2]; |
| 295 int innerThisIndex = innerCoin.fSegments[0]; |
| 296 if (thisIndex == innerThisIndex) { |
| 297 checkCoincidentPair(coincidence, 1, innerCoin, 1, true); |
| 298 } |
| 299 if (this == otherContour && otherIndex == innerThisIndex) { |
| 300 checkCoincidentPair(coincidence, 0, innerCoin, 1, true); |
| 301 } |
| 302 SkOpContour* innerOtherContour = innerCoin.fOther; |
| 303 innerThisIndex = innerCoin.fSegments[1]; |
| 304 if (this == innerOtherContour && thisIndex == innerThisIndex) { |
| 305 checkCoincidentPair(coincidence, 1, innerCoin, 0, true); |
| 306 } |
| 307 if (otherContour == innerOtherContour && otherIndex == innerThisInde
x) { |
| 308 checkCoincidentPair(coincidence, 0, innerCoin, 0, true); |
| 309 } |
| 310 } |
184 } | 311 } |
185 } | 312 } |
186 | 313 |
| 314 void SkOpContour::checkCoincidentPair(const SkCoincidence& oneCoin, int oneIdx, |
| 315 const SkCoincidence& twoCoin, int twoIdx, bool partial) { |
| 316 SkASSERT((oneIdx ? this : oneCoin.fOther) == (twoIdx ? this : twoCoin.fOther
)); |
| 317 SkASSERT(oneCoin.fSegments[!oneIdx] == twoCoin.fSegments[!twoIdx]); |
| 318 // look for common overlap |
| 319 double min = SK_ScalarMax; |
| 320 double max = SK_ScalarMin; |
| 321 double min1 = oneCoin.fTs[!oneIdx][0]; |
| 322 double max1 = oneCoin.fTs[!oneIdx][1]; |
| 323 double min2 = twoCoin.fTs[!twoIdx][0]; |
| 324 double max2 = twoCoin.fTs[!twoIdx][1]; |
| 325 bool cancelers = (min1 < max1) != (min2 < max2); |
| 326 if (min1 > max1) { |
| 327 SkTSwap(min1, max1); |
| 328 } |
| 329 if (min2 > max2) { |
| 330 SkTSwap(min2, max2); |
| 331 } |
| 332 if (between(min1, min2, max1)) { |
| 333 min = min2; |
| 334 } |
| 335 if (between(min1, max2, max1)) { |
| 336 max = max2; |
| 337 } |
| 338 if (between(min2, min1, max2)) { |
| 339 min = SkTMin(min, min1); |
| 340 } |
| 341 if (between(min2, max1, max2)) { |
| 342 max = SkTMax(max, max1); |
| 343 } |
| 344 if (min >= max) { |
| 345 return; // no overlap |
| 346 } |
| 347 // look to see if opposite are different segments |
| 348 int seg1Index = oneCoin.fSegments[oneIdx]; |
| 349 int seg2Index = twoCoin.fSegments[twoIdx]; |
| 350 if (seg1Index == seg2Index) { |
| 351 return; |
| 352 } |
| 353 SkOpContour* contour1 = oneIdx ? oneCoin.fOther : this; |
| 354 SkOpContour* contour2 = twoIdx ? twoCoin.fOther : this; |
| 355 SkOpSegment* segment1 = &contour1->fSegments[seg1Index]; |
| 356 SkOpSegment* segment2 = &contour2->fSegments[seg2Index]; |
| 357 // find opposite t value ranges corresponding to reference min/max range |
| 358 const SkOpContour* refContour = oneIdx ? this : oneCoin.fOther; |
| 359 const int refSegIndex = oneCoin.fSegments[!oneIdx]; |
| 360 const SkOpSegment* refSegment = &refContour->fSegments[refSegIndex]; |
| 361 int seg1Start = segment1->findOtherT(min, refSegment); |
| 362 int seg1End = segment1->findOtherT(max, refSegment); |
| 363 int seg2Start = segment2->findOtherT(min, refSegment); |
| 364 int seg2End = segment2->findOtherT(max, refSegment); |
| 365 // if the opposite pairs already contain min/max, we're done |
| 366 if (seg1Start >= 0 && seg1End >= 0 && seg2Start >= 0 && seg2End >= 0) { |
| 367 return; |
| 368 } |
| 369 double loEnd = SkTMin(min1, min2); |
| 370 double hiEnd = SkTMax(max1, max2); |
| 371 // insert the missing coincident point(s) |
| 372 double missingT1 = -1; |
| 373 double otherT1 = -1; |
| 374 if (seg1Start < 0) { |
| 375 if (seg2Start < 0) { |
| 376 return; |
| 377 } |
| 378 missingT1 = segment1->calcMissingTStart(refSegment, loEnd, min, max, hiE
nd, |
| 379 segment2, seg1End); |
| 380 if (missingT1 < 0) { |
| 381 return; |
| 382 } |
| 383 const SkOpSpan* missingSpan = &segment2->span(seg2Start); |
| 384 otherT1 = missingSpan->fT; |
| 385 } else if (seg2Start < 0) { |
| 386 SkASSERT(seg1Start >= 0); |
| 387 missingT1 = segment2->calcMissingTStart(refSegment, loEnd, min, max, hiE
nd, |
| 388 segment1, seg2End); |
| 389 if (missingT1 < 0) { |
| 390 return; |
| 391 } |
| 392 const SkOpSpan* missingSpan = &segment1->span(seg1Start); |
| 393 otherT1 = missingSpan->fT; |
| 394 } |
| 395 SkPoint missingPt1; |
| 396 SkOpSegment* addTo1 = NULL; |
| 397 SkOpSegment* addOther1 = seg1Start < 0 ? segment2 : segment1; |
| 398 int minTIndex = refSegment->findExactT(min, addOther1); |
| 399 SkASSERT(minTIndex >= 0); |
| 400 if (missingT1 >= 0) { |
| 401 missingPt1 = refSegment->span(minTIndex).fPt; |
| 402 addTo1 = seg1Start < 0 ? segment1 : segment2; |
| 403 } |
| 404 double missingT2 = -1; |
| 405 double otherT2 = -1; |
| 406 if (seg1End < 0) { |
| 407 if (seg2End < 0) { |
| 408 return; |
| 409 } |
| 410 missingT2 = segment1->calcMissingTEnd(refSegment, loEnd, min, max, hiEnd
, |
| 411 segment2, seg1Start); |
| 412 if (missingT2 < 0) { |
| 413 return; |
| 414 } |
| 415 const SkOpSpan* missingSpan = &segment2->span(seg2End); |
| 416 otherT2 = missingSpan->fT; |
| 417 } else if (seg2End < 0) { |
| 418 SkASSERT(seg1End >= 0); |
| 419 missingT2 = segment2->calcMissingTEnd(refSegment, loEnd, min, max, hiEnd
, |
| 420 segment1, seg2Start); |
| 421 if (missingT2 < 0) { |
| 422 return; |
| 423 } |
| 424 const SkOpSpan* missingSpan = &segment1->span(seg1End); |
| 425 otherT2 = missingSpan->fT; |
| 426 } |
| 427 SkPoint missingPt2; |
| 428 SkOpSegment* addTo2 = NULL; |
| 429 SkOpSegment* addOther2 = seg1End < 0 ? segment2 : segment1; |
| 430 int maxTIndex = refSegment->findExactT(max, addOther2); |
| 431 SkASSERT(maxTIndex >= 0); |
| 432 if (missingT2 >= 0) { |
| 433 missingPt2 = refSegment->span(maxTIndex).fPt; |
| 434 addTo2 = seg1End < 0 ? segment1 : segment2; |
| 435 } |
| 436 if (missingT1 >= 0) { |
| 437 addTo1->pinT(missingPt1, &missingT1); |
| 438 addTo1->addTPair(missingT1, addOther1, otherT1, false, missingPt1); |
| 439 } else { |
| 440 SkASSERT(minTIndex >= 0); |
| 441 missingPt1 = refSegment->span(minTIndex).fPt; |
| 442 } |
| 443 if (missingT2 >= 0) { |
| 444 addTo2->pinT(missingPt2, &missingT2); |
| 445 addTo2->addTPair(missingT2, addOther2, otherT2, false, missingPt2); |
| 446 } else { |
| 447 SkASSERT(minTIndex >= 0); |
| 448 missingPt2 = refSegment->span(maxTIndex).fPt; |
| 449 } |
| 450 if (!partial) { |
| 451 return; |
| 452 } |
| 453 if (cancelers) { |
| 454 if (missingT1 >= 0) { |
| 455 addTo1->addTCancel(missingPt1, missingPt2, addOther1); |
| 456 } else { |
| 457 addTo2->addTCancel(missingPt1, missingPt2, addOther2); |
| 458 } |
| 459 } else if (missingT1 >= 0) { |
| 460 addTo1->addTCoincident(missingPt1, missingPt2, addTo1 == addTo2 ? missin
gT2 : otherT2, |
| 461 addOther1); |
| 462 } else { |
| 463 addTo2->addTCoincident(missingPt2, missingPt1, addTo2 == addTo1 ? missin
gT1 : otherT1, |
| 464 addOther2); |
| 465 } |
| 466 } |
| 467 |
187 void SkOpContour::joinCoincidence(const SkTArray<SkCoincidence, true>& coinciden
ces, bool partial) { | 468 void SkOpContour::joinCoincidence(const SkTArray<SkCoincidence, true>& coinciden
ces, bool partial) { |
188 int count = coincidences.count(); | 469 int count = coincidences.count(); |
189 #if DEBUG_CONCIDENT | 470 #if DEBUG_CONCIDENT |
190 if (count > 0) { | 471 if (count > 0) { |
191 SkDebugf("%s count=%d\n", __FUNCTION__, count); | 472 SkDebugf("%s count=%d\n", __FUNCTION__, count); |
192 } | 473 } |
193 #endif | 474 #endif |
194 // look for a lineup where the partial implies another adjoining coincidence | 475 // look for a lineup where the partial implies another adjoining coincidence |
195 for (int index = 0; index < count; ++index) { | 476 for (int index = 0; index < count; ++index) { |
196 const SkCoincidence& coincidence = coincidences[index]; | 477 const SkCoincidence& coincidence = coincidences[index]; |
197 int thisIndex = coincidence.fSegments[0]; | 478 int thisIndex = coincidence.fSegments[0]; |
198 SkOpSegment& thisOne = fSegments[thisIndex]; | 479 SkOpSegment& thisOne = fSegments[thisIndex]; |
| 480 if (thisOne.done()) { |
| 481 continue; |
| 482 } |
199 SkOpContour* otherContour = coincidence.fOther; | 483 SkOpContour* otherContour = coincidence.fOther; |
200 int otherIndex = coincidence.fSegments[1]; | 484 int otherIndex = coincidence.fSegments[1]; |
201 SkOpSegment& other = otherContour->fSegments[otherIndex]; | 485 SkOpSegment& other = otherContour->fSegments[otherIndex]; |
| 486 if (other.done()) { |
| 487 continue; |
| 488 } |
202 double startT = coincidence.fTs[0][0]; | 489 double startT = coincidence.fTs[0][0]; |
203 double endT = coincidence.fTs[0][1]; | 490 double endT = coincidence.fTs[0][1]; |
204 if (startT == endT) { // this can happen in very large compares | 491 if (startT == endT) { // this can happen in very large compares |
205 continue; | 492 continue; |
206 } | 493 } |
207 double oStartT = coincidence.fTs[1][0]; | 494 double oStartT = coincidence.fTs[1][0]; |
208 double oEndT = coincidence.fTs[1][1]; | 495 double oEndT = coincidence.fTs[1][1]; |
209 if (oStartT == oEndT) { | 496 if (oStartT == oEndT) { |
210 continue; | 497 continue; |
211 } | 498 } |
212 bool swapStart = startT > endT; | 499 bool swapStart = startT > endT; |
213 bool swapOther = oStartT > oEndT; | 500 bool swapOther = oStartT > oEndT; |
214 const SkPoint* startPt = &coincidence.fPts[0]; | 501 const SkPoint* startPt = &coincidence.fPts[0][0]; |
215 const SkPoint* endPt = &coincidence.fPts[1]; | 502 const SkPoint* endPt = &coincidence.fPts[0][1]; |
216 if (swapStart) { | 503 if (swapStart) { |
217 SkTSwap(startT, endT); | 504 SkTSwap(startT, endT); |
218 SkTSwap(oStartT, oEndT); | 505 SkTSwap(oStartT, oEndT); |
219 SkTSwap(startPt, endPt); | 506 SkTSwap(startPt, endPt); |
220 } | 507 } |
221 bool cancel = swapOther != swapStart; | 508 bool cancel = swapOther != swapStart; |
222 int step = swapStart ? -1 : 1; | 509 int step = swapStart ? -1 : 1; |
223 int oStep = swapOther ? -1 : 1; | 510 int oStep = swapOther ? -1 : 1; |
224 double oMatchStart = cancel ? oEndT : oStartT; | 511 double oMatchStart = cancel ? oEndT : oStartT; |
225 if (partial ? startT != 0 || oMatchStart != 0 : (startT == 0) != (oMatch
Start == 0)) { | 512 if (partial ? startT != 0 || oMatchStart != 0 : (startT == 0) != (oMatch
Start == 0)) { |
(...skipping 10 matching lines...) Expand all Loading... |
236 if (partial ? endT != 1 || oMatchEnd != 1 : (endT == 1) != (oMatchEnd ==
1)) { | 523 if (partial ? endT != 1 || oMatchEnd != 1 : (endT == 1) != (oMatchEnd ==
1)) { |
237 bool added = false; | 524 bool added = false; |
238 if (cancel && endT != 1 && !added) { | 525 if (cancel && endT != 1 && !added) { |
239 (void) other.joinCoincidence(&thisOne, endT, *endPt, -step, canc
el); | 526 (void) other.joinCoincidence(&thisOne, endT, *endPt, -step, canc
el); |
240 } | 527 } |
241 } | 528 } |
242 } | 529 } |
243 } | 530 } |
244 | 531 |
245 void SkOpContour::calcCommonCoincidentWinding(const SkCoincidence& coincidence)
{ | 532 void SkOpContour::calcCommonCoincidentWinding(const SkCoincidence& coincidence)
{ |
| 533 if (coincidence.fNearly[0] && coincidence.fNearly[1]) { |
| 534 return; |
| 535 } |
246 int thisIndex = coincidence.fSegments[0]; | 536 int thisIndex = coincidence.fSegments[0]; |
247 SkOpSegment& thisOne = fSegments[thisIndex]; | 537 SkOpSegment& thisOne = fSegments[thisIndex]; |
248 if (thisOne.done()) { | 538 if (thisOne.done()) { |
249 return; | 539 return; |
250 } | 540 } |
251 SkOpContour* otherContour = coincidence.fOther; | 541 SkOpContour* otherContour = coincidence.fOther; |
252 int otherIndex = coincidence.fSegments[1]; | 542 int otherIndex = coincidence.fSegments[1]; |
253 SkOpSegment& other = otherContour->fSegments[otherIndex]; | 543 SkOpSegment& other = otherContour->fSegments[otherIndex]; |
254 if (other.done()) { | 544 if (other.done()) { |
255 return; | 545 return; |
256 } | 546 } |
257 double startT = coincidence.fTs[0][0]; | 547 double startT = coincidence.fTs[0][0]; |
258 double endT = coincidence.fTs[0][1]; | 548 double endT = coincidence.fTs[0][1]; |
259 const SkPoint* startPt = &coincidence.fPts[0]; | 549 const SkPoint* startPt = &coincidence.fPts[0][0]; |
260 const SkPoint* endPt = &coincidence.fPts[1]; | 550 const SkPoint* endPt = &coincidence.fPts[0][1]; |
261 bool cancelers; | 551 bool cancelers; |
262 if ((cancelers = startT > endT)) { | 552 if ((cancelers = startT > endT)) { |
263 SkTSwap<double>(startT, endT); | 553 SkTSwap<double>(startT, endT); |
264 SkTSwap<const SkPoint*>(startPt, endPt); | 554 SkTSwap<const SkPoint*>(startPt, endPt); |
265 } | 555 } |
266 if (startT == endT) { // if span is very large, the smaller may have collaps
ed to nothing | 556 if (startT == endT) { // if span is very large, the smaller may have collaps
ed to nothing |
267 if (endT <= 1 - FLT_EPSILON) { | 557 if (endT <= 1 - FLT_EPSILON) { |
268 endT += FLT_EPSILON; | 558 endT += FLT_EPSILON; |
269 SkASSERT(endT <= 1); | 559 SkASSERT(endT <= 1); |
270 } else { | 560 } else { |
(...skipping 13 matching lines...) Expand all Loading... |
284 thisOne.addTCancel(*startPt, *endPt, &other); | 574 thisOne.addTCancel(*startPt, *endPt, &other); |
285 } else { | 575 } else { |
286 thisOne.addTCoincident(*startPt, *endPt, endT, &other); | 576 thisOne.addTCoincident(*startPt, *endPt, endT, &other); |
287 } | 577 } |
288 #if DEBUG_CONCIDENT | 578 #if DEBUG_CONCIDENT |
289 thisOne.debugShowTs("p"); | 579 thisOne.debugShowTs("p"); |
290 other.debugShowTs("o"); | 580 other.debugShowTs("o"); |
291 #endif | 581 #endif |
292 } | 582 } |
293 | 583 |
| 584 void SkOpContour::resolveNearCoincidence() { |
| 585 int count = fCoincidences.count(); |
| 586 for (int index = 0; index < count; ++index) { |
| 587 SkCoincidence& coincidence = fCoincidences[index]; |
| 588 if (!coincidence.fNearly[0] || !coincidence.fNearly[1]) { |
| 589 continue; |
| 590 } |
| 591 int thisIndex = coincidence.fSegments[0]; |
| 592 SkOpSegment& thisOne = fSegments[thisIndex]; |
| 593 SkOpContour* otherContour = coincidence.fOther; |
| 594 int otherIndex = coincidence.fSegments[1]; |
| 595 SkOpSegment& other = otherContour->fSegments[otherIndex]; |
| 596 if ((thisOne.done() || other.done()) && thisOne.complete() && other.comp
lete()) { |
| 597 // OPTIMIZATION: remove from coincidence array |
| 598 continue; |
| 599 } |
| 600 #if DEBUG_CONCIDENT |
| 601 thisOne.debugShowTs("-"); |
| 602 other.debugShowTs("o"); |
| 603 #endif |
| 604 double startT = coincidence.fTs[0][0]; |
| 605 double endT = coincidence.fTs[0][1]; |
| 606 bool cancelers; |
| 607 if ((cancelers = startT > endT)) { |
| 608 SkTSwap<double>(startT, endT); |
| 609 } |
| 610 if (startT == endT) { // if span is very large, the smaller may have col
lapsed to nothing |
| 611 if (endT <= 1 - FLT_EPSILON) { |
| 612 endT += FLT_EPSILON; |
| 613 SkASSERT(endT <= 1); |
| 614 } else { |
| 615 startT -= FLT_EPSILON; |
| 616 SkASSERT(startT >= 0); |
| 617 } |
| 618 } |
| 619 SkASSERT(!approximately_negative(endT - startT)); |
| 620 double oStartT = coincidence.fTs[1][0]; |
| 621 double oEndT = coincidence.fTs[1][1]; |
| 622 if (oStartT > oEndT) { |
| 623 SkTSwap<double>(oStartT, oEndT); |
| 624 cancelers ^= true; |
| 625 } |
| 626 SkASSERT(!approximately_negative(oEndT - oStartT)); |
| 627 if (cancelers) { |
| 628 thisOne.blindCancel(coincidence, &other); |
| 629 } else { |
| 630 thisOne.blindCoincident(coincidence, &other); |
| 631 } |
| 632 } |
| 633 } |
| 634 |
294 void SkOpContour::sortAngles() { | 635 void SkOpContour::sortAngles() { |
295 int segmentCount = fSegments.count(); | 636 int segmentCount = fSegments.count(); |
296 for (int test = 0; test < segmentCount; ++test) { | 637 for (int test = 0; test < segmentCount; ++test) { |
297 fSegments[test].sortAngles(); | 638 fSegments[test].sortAngles(); |
298 } | 639 } |
299 } | 640 } |
300 | 641 |
301 void SkOpContour::sortSegments() { | 642 void SkOpContour::sortSegments() { |
302 int segmentCount = fSegments.count(); | 643 int segmentCount = fSegments.count(); |
303 fSortedSegments.push_back_n(segmentCount); | 644 fSortedSegments.push_back_n(segmentCount); |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
400 SkDebugf("%s empty contour\n", __FUNCTION__); | 741 SkDebugf("%s empty contour\n", __FUNCTION__); |
401 SkASSERT(0); | 742 SkASSERT(0); |
402 // FIXME: delete empty contour? | 743 // FIXME: delete empty contour? |
403 return; | 744 return; |
404 } | 745 } |
405 fBounds = fSegments.front().bounds(); | 746 fBounds = fSegments.front().bounds(); |
406 for (int index = 1; index < count; ++index) { | 747 for (int index = 1; index < count; ++index) { |
407 fBounds.add(fSegments[index].bounds()); | 748 fBounds.add(fSegments[index].bounds()); |
408 } | 749 } |
409 } | 750 } |
OLD | NEW |