1 /* 2 * Copyright 2013 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 #include "SkIntersections.h" 8 #include "SkOpContour.h" 9 #include "SkPathWriter.h" 10 #include "SkTSort.h" 11 12 bool SkOpContour::addCoincident(int index, SkOpContour* other, int otherIndex, 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 } 23 SkCoincidence& coincidence = fCoincidences.push_back(); 24 coincidence.fOther = other; 25 coincidence.fSegments[0] = index; 26 coincidence.fSegments[1] = otherIndex; 27 coincidence.fTs[swap][0] = ts[0][0]; 28 coincidence.fTs[swap][1] = ts[0][1]; 29 coincidence.fTs[!swap][0] = ts[1][0]; 30 coincidence.fTs[!swap][1] = ts[1][1]; 31 coincidence.fPts[swap][0] = pt0; 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; 39 return true; 40 } 41 42 SkOpSegment* SkOpContour::nonVerticalSegment(int* start, int* end) { 43 int segmentCount = fSortedSegments.count(); 44 SkASSERT(segmentCount > 0); 45 for (int sortedIndex = fFirstSorted; sortedIndex < segmentCount; ++sortedIndex) { 46 SkOpSegment* testSegment = fSortedSegments[sortedIndex]; 47 if (testSegment->done()) { 48 continue; 49 } 50 *start = *end = 0; 51 while (testSegment->nextCandidate(start, end)) { 52 if (!testSegment->isVertical(*start, *end)) { 53 return testSegment; 54 } 55 } 56 } 57 return NULL; 58 } 59 60 // if one is very large the smaller may have collapsed to nothing 61 static void bump_out_close_span(double* startTPtr, double* endTPtr) { 62 double startT = *startTPtr; 63 double endT = *endTPtr; 64 if (approximately_negative(endT - startT)) { 65 if (endT <= 1 - FLT_EPSILON) { 66 *endTPtr += FLT_EPSILON; 67 SkASSERT(*endTPtr <= 1); 68 } else { 69 *startTPtr -= FLT_EPSILON; 70 SkASSERT(*startTPtr >= 0); 71 } 72 } 73 } 74 75 // first pass, add missing T values 76 // second pass, determine winding values of overlaps 77 void SkOpContour::addCoincidentPoints() { 78 int count = fCoincidences.count(); 79 for (int index = 0; index < count; ++index) { 80 SkCoincidence& coincidence = fCoincidences[index]; 81 int thisIndex = coincidence.fSegments[0]; 82 SkOpSegment& thisOne = fSegments[thisIndex]; 83 SkOpContour* otherContour = coincidence.fOther; 84 int otherIndex = coincidence.fSegments[1]; 85 SkOpSegment& other = otherContour->fSegments[otherIndex]; 86 if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) { 87 // OPTIMIZATION: remove from array 88 continue; 89 } 90 #if DEBUG_CONCIDENT 91 thisOne.debugShowTs("-"); 92 other.debugShowTs("o"); 93 #endif 94 double startT = coincidence.fTs[0][0]; 95 double endT = coincidence.fTs[0][1]; 96 bool startSwapped, oStartSwapped, cancelers; 97 if ((cancelers = startSwapped = startT > endT)) { 98 SkTSwap(startT, endT); 99 } 100 bump_out_close_span(&startT, &endT); 101 SkASSERT(!approximately_negative(endT - startT)); 102 double oStartT = coincidence.fTs[1][0]; 103 double oEndT = coincidence.fTs[1][1]; 104 if ((oStartSwapped = oStartT > oEndT)) { 105 SkTSwap(oStartT, oEndT); 106 cancelers ^= true; 107 } 108 bump_out_close_span(&oStartT, &oEndT); 109 SkASSERT(!approximately_negative(oEndT - oStartT)); 110 const SkPoint& startPt = coincidence.fPts[0][startSwapped]; 111 if (cancelers) { 112 // make sure startT and endT have t entries 113 if (startT > 0 || oEndT < 1 114 || thisOne.isMissing(startT, startPt) || other.isMissing(oEndT, startPt)) { 115 thisOne.addTPair(startT, &other, oEndT, true, startPt, 116 coincidence.fPts[1][startSwapped]); 117 } 118 const SkPoint& oStartPt = coincidence.fPts[1][oStartSwapped]; 119 if (oStartT > 0 || endT < 1 120 || thisOne.isMissing(endT, oStartPt) || other.isMissing(oStartT, oStartPt)) { 121 other.addTPair(oStartT, &thisOne, endT, true, oStartPt, 122 coincidence.fPts[0][oStartSwapped]); 123 } 124 } else { 125 if (startT > 0 || oStartT > 0 126 || thisOne.isMissing(startT, startPt) || other.isMissing(oStartT, startPt)) { 127 thisOne.addTPair(startT, &other, oStartT, true, startPt, 128 coincidence.fPts[1][startSwapped]); 129 } 130 const SkPoint& oEndPt = coincidence.fPts[1][!oStartSwapped]; 131 if (endT < 1 || oEndT < 1 132 || thisOne.isMissing(endT, oEndPt) || other.isMissing(oEndT, oEndPt)) { 133 other.addTPair(oEndT, &thisOne, endT, true, oEndPt, 134 coincidence.fPts[0][!oStartSwapped]); 135 } 136 } 137 #if DEBUG_CONCIDENT 138 thisOne.debugShowTs("+"); 139 other.debugShowTs("o"); 140 #endif 141 } 142 // if there are multiple pairs of coincidence that share an edge, see if the opposite 143 // are also coincident 144 for (int index = 0; index < count - 1; ++index) { 145 const SkCoincidence& coincidence = fCoincidences[index]; 146 int thisIndex = coincidence.fSegments[0]; 147 SkOpContour* otherContour = coincidence.fOther; 148 int otherIndex = coincidence.fSegments[1]; 149 for (int idx2 = 1; idx2 < count; ++idx2) { 150 const SkCoincidence& innerCoin = fCoincidences[idx2]; 151 int innerThisIndex = innerCoin.fSegments[0]; 152 if (thisIndex == innerThisIndex) { 153 checkCoincidentPair(coincidence, 1, innerCoin, 1, false); 154 } 155 if (this == otherContour && otherIndex == innerThisIndex) { 156 checkCoincidentPair(coincidence, 0, innerCoin, 1, false); 157 } 158 SkOpContour* innerOtherContour = innerCoin.fOther; 159 innerThisIndex = innerCoin.fSegments[1]; 160 if (this == innerOtherContour && thisIndex == innerThisIndex) { 161 checkCoincidentPair(coincidence, 1, innerCoin, 0, false); 162 } 163 if (otherContour == innerOtherContour && otherIndex == innerThisIndex) { 164 checkCoincidentPair(coincidence, 0, innerCoin, 0, false); 165 } 166 } 167 } 168 } 169 170 bool SkOpContour::addPartialCoincident(int index, SkOpContour* other, int otherIndex, 171 const SkIntersections& ts, int ptIndex, bool swap) { 172 SkPoint pt0 = ts.pt(ptIndex).asSkPoint(); 173 SkPoint pt1 = ts.pt(ptIndex + 1).asSkPoint(); 174 if (SkDPoint::ApproximatelyEqual(pt0, pt1)) { 175 // FIXME: one could imagine a case where it would be incorrect to ignore this 176 // suppose two self-intersecting cubics overlap to form a partial coincidence -- 177 // although it isn't clear why the regular coincidence could wouldn't pick this up 178 // this is exceptional enough to ignore for now 179 return false; 180 } 181 SkCoincidence& coincidence = fPartialCoincidences.push_back(); 182 coincidence.fOther = other; 183 coincidence.fSegments[0] = index; 184 coincidence.fSegments[1] = otherIndex; 185 coincidence.fTs[swap][0] = ts[0][ptIndex]; 186 coincidence.fTs[swap][1] = ts[0][ptIndex + 1]; 187 coincidence.fTs[!swap][0] = ts[1][ptIndex]; 188 coincidence.fTs[!swap][1] = ts[1][ptIndex + 1]; 189 coincidence.fPts[0][0] = coincidence.fPts[1][0] = pt0; 190 coincidence.fPts[0][1] = coincidence.fPts[1][1] = pt1; 191 coincidence.fNearly[0] = 0; 192 coincidence.fNearly[1] = 0; 193 return true; 194 } 195 196 void SkOpContour::align(const SkOpSegment::AlignedSpan& aligned, bool swap, 197 SkCoincidence* coincidence) { 198 for (int idx2 = 0; idx2 < 2; ++idx2) { 199 if (coincidence->fPts[0][idx2] == aligned.fOldPt 200 && coincidence->fTs[swap][idx2] == aligned.fOldT) { 201 SkASSERT(SkDPoint::RoughlyEqual(coincidence->fPts[0][idx2], aligned.fPt)); 202 coincidence->fPts[0][idx2] = aligned.fPt; 203 SkASSERT(way_roughly_equal(coincidence->fTs[swap][idx2], aligned.fT)); 204 coincidence->fTs[swap][idx2] = aligned.fT; 205 } 206 } 207 } 208 209 void SkOpContour::alignCoincidence(const SkOpSegment::AlignedSpan& aligned, 210 SkTArray<SkCoincidence, true>* coincidences) { 211 int count = coincidences->count(); 212 for (int index = 0; index < count; ++index) { 213 SkCoincidence& coincidence = (*coincidences)[index]; 214 int thisIndex = coincidence.fSegments[0]; 215 const SkOpSegment* thisOne = &fSegments[thisIndex]; 216 const SkOpContour* otherContour = coincidence.fOther; 217 int otherIndex = coincidence.fSegments[1]; 218 const SkOpSegment* other = &otherContour->fSegments[otherIndex]; 219 if (thisOne == aligned.fOther1 && other == aligned.fOther2) { 220 align(aligned, false, &coincidence); 221 } else if (thisOne == aligned.fOther2 && other == aligned.fOther1) { 222 align(aligned, true, &coincidence); 223 } 224 } 225 } 226 227 void SkOpContour::alignTPt(int segmentIndex, const SkOpContour* other, int otherIndex, 228 bool swap, int tIndex, SkIntersections* ts, SkPoint* point) const { 229 int zeroPt; 230 if ((zeroPt = alignT(swap, tIndex, ts)) >= 0) { 231 alignPt(segmentIndex, point, zeroPt); 232 } 233 if ((zeroPt = other->alignT(!swap, tIndex, ts)) >= 0) { 234 other->alignPt(otherIndex, point, zeroPt); 235 } 236 } 237 238 void SkOpContour::alignPt(int index, SkPoint* point, int zeroPt) const { 239 const SkOpSegment& segment = fSegments[index]; 240 if (0 == zeroPt) { 241 *point = segment.pts()[0]; 242 } else { 243 *point = segment.pts()[SkPathOpsVerbToPoints(segment.verb())]; 244 } 245 } 246 247 int SkOpContour::alignT(bool swap, int tIndex, SkIntersections* ts) const { 248 double tVal = (*ts)[swap][tIndex]; 249 if (tVal != 0 && precisely_zero(tVal)) { 250 ts->set(swap, tIndex, 0); 251 return 0; 252 } 253 if (tVal != 1 && precisely_equal(tVal, 1)) { 254 ts->set(swap, tIndex, 1); 255 return 1; 256 } 257 return -1; 258 } 259 260 bool SkOpContour::calcAngles() { 261 int segmentCount = fSegments.count(); 262 for (int test = 0; test < segmentCount; ++test) { 263 if (!fSegments[test].calcAngles()) { 264 return false; 265 } 266 } 267 return true; 268 } 269 270 bool SkOpContour::calcCoincidentWinding() { 271 int count = fCoincidences.count(); 272 #if DEBUG_CONCIDENT 273 if (count > 0) { 274 SkDebugf("%s count=%d\n", __FUNCTION__, count); 275 } 276 #endif 277 for (int index = 0; index < count; ++index) { 278 SkCoincidence& coincidence = fCoincidences[index]; 279 if (!calcCommonCoincidentWinding(coincidence)) { 280 return false; 281 } 282 } 283 return true; 284 } 285 286 void SkOpContour::calcPartialCoincidentWinding() { 287 int count = fPartialCoincidences.count(); 288 #if DEBUG_CONCIDENT 289 if (count > 0) { 290 SkDebugf("%s count=%d\n", __FUNCTION__, count); 291 } 292 #endif 293 for (int index = 0; index < count; ++index) { 294 SkCoincidence& coincidence = fPartialCoincidences[index]; 295 calcCommonCoincidentWinding(coincidence); 296 } 297 // if there are multiple pairs of partial coincidence that share an edge, see if the opposite 298 // are also coincident 299 for (int index = 0; index < count - 1; ++index) { 300 const SkCoincidence& coincidence = fPartialCoincidences[index]; 301 int thisIndex = coincidence.fSegments[0]; 302 SkOpContour* otherContour = coincidence.fOther; 303 int otherIndex = coincidence.fSegments[1]; 304 for (int idx2 = 1; idx2 < count; ++idx2) { 305 const SkCoincidence& innerCoin = fPartialCoincidences[idx2]; 306 int innerThisIndex = innerCoin.fSegments[0]; 307 if (thisIndex == innerThisIndex) { 308 checkCoincidentPair(coincidence, 1, innerCoin, 1, true); 309 } 310 if (this == otherContour && otherIndex == innerThisIndex) { 311 checkCoincidentPair(coincidence, 0, innerCoin, 1, true); 312 } 313 SkOpContour* innerOtherContour = innerCoin.fOther; 314 innerThisIndex = innerCoin.fSegments[1]; 315 if (this == innerOtherContour && thisIndex == innerThisIndex) { 316 checkCoincidentPair(coincidence, 1, innerCoin, 0, true); 317 } 318 if (otherContour == innerOtherContour && otherIndex == innerThisIndex) { 319 checkCoincidentPair(coincidence, 0, innerCoin, 0, true); 320 } 321 } 322 } 323 } 324 325 void SkOpContour::checkCoincidentPair(const SkCoincidence& oneCoin, int oneIdx, 326 const SkCoincidence& twoCoin, int twoIdx, bool partial) { 327 SkASSERT((oneIdx ? this : oneCoin.fOther) == (twoIdx ? this : twoCoin.fOther)); 328 SkASSERT(oneCoin.fSegments[!oneIdx] == twoCoin.fSegments[!twoIdx]); 329 // look for common overlap 330 double min = SK_ScalarMax; 331 double max = SK_ScalarMin; 332 double min1 = oneCoin.fTs[!oneIdx][0]; 333 double max1 = oneCoin.fTs[!oneIdx][1]; 334 double min2 = twoCoin.fTs[!twoIdx][0]; 335 double max2 = twoCoin.fTs[!twoIdx][1]; 336 bool cancelers = (min1 < max1) != (min2 < max2); 337 if (min1 > max1) { 338 SkTSwap(min1, max1); 339 } 340 if (min2 > max2) { 341 SkTSwap(min2, max2); 342 } 343 if (between(min1, min2, max1)) { 344 min = min2; 345 } 346 if (between(min1, max2, max1)) { 347 max = max2; 348 } 349 if (between(min2, min1, max2)) { 350 min = SkTMin(min, min1); 351 } 352 if (between(min2, max1, max2)) { 353 max = SkTMax(max, max1); 354 } 355 if (min >= max) { 356 return; // no overlap 357 } 358 // look to see if opposite are different segments 359 int seg1Index = oneCoin.fSegments[oneIdx]; 360 int seg2Index = twoCoin.fSegments[twoIdx]; 361 if (seg1Index == seg2Index) { 362 return; 363 } 364 SkOpContour* contour1 = oneIdx ? oneCoin.fOther : this; 365 SkOpContour* contour2 = twoIdx ? twoCoin.fOther : this; 366 SkOpSegment* segment1 = &contour1->fSegments[seg1Index]; 367 SkOpSegment* segment2 = &contour2->fSegments[seg2Index]; 368 // find opposite t value ranges corresponding to reference min/max range 369 const SkOpContour* refContour = oneIdx ? this : oneCoin.fOther; 370 const int refSegIndex = oneCoin.fSegments[!oneIdx]; 371 const SkOpSegment* refSegment = &refContour->fSegments[refSegIndex]; 372 int seg1Start = segment1->findOtherT(min, refSegment); 373 int seg1End = segment1->findOtherT(max, refSegment); 374 int seg2Start = segment2->findOtherT(min, refSegment); 375 int seg2End = segment2->findOtherT(max, refSegment); 376 // if the opposite pairs already contain min/max, we're done 377 if (seg1Start >= 0 && seg1End >= 0 && seg2Start >= 0 && seg2End >= 0) { 378 return; 379 } 380 double loEnd = SkTMin(min1, min2); 381 double hiEnd = SkTMax(max1, max2); 382 // insert the missing coincident point(s) 383 double missingT1 = -1; 384 double otherT1 = -1; 385 if (seg1Start < 0) { 386 if (seg2Start < 0) { 387 return; 388 } 389 missingT1 = segment1->calcMissingTStart(refSegment, loEnd, min, max, hiEnd, 390 segment2, seg1End); 391 if (missingT1 < 0) { 392 return; 393 } 394 const SkOpSpan* missingSpan = &segment2->span(seg2Start); 395 otherT1 = missingSpan->fT; 396 } else if (seg2Start < 0) { 397 SkASSERT(seg1Start >= 0); 398 missingT1 = segment2->calcMissingTStart(refSegment, loEnd, min, max, hiEnd, 399 segment1, seg2End); 400 if (missingT1 < 0) { 401 return; 402 } 403 const SkOpSpan* missingSpan = &segment1->span(seg1Start); 404 otherT1 = missingSpan->fT; 405 } 406 SkPoint missingPt1; 407 SkOpSegment* addTo1 = NULL; 408 SkOpSegment* addOther1 = seg1Start < 0 ? segment2 : segment1; 409 int minTIndex = refSegment->findExactT(min, addOther1); 410 SkASSERT(minTIndex >= 0); 411 if (missingT1 >= 0) { 412 missingPt1 = refSegment->span(minTIndex).fPt; 413 addTo1 = seg1Start < 0 ? segment1 : segment2; 414 } 415 double missingT2 = -1; 416 double otherT2 = -1; 417 if (seg1End < 0) { 418 if (seg2End < 0) { 419 return; 420 } 421 missingT2 = segment1->calcMissingTEnd(refSegment, loEnd, min, max, hiEnd, 422 segment2, seg1Start); 423 if (missingT2 < 0) { 424 return; 425 } 426 const SkOpSpan* missingSpan = &segment2->span(seg2End); 427 otherT2 = missingSpan->fT; 428 } else if (seg2End < 0) { 429 SkASSERT(seg1End >= 0); 430 missingT2 = segment2->calcMissingTEnd(refSegment, loEnd, min, max, hiEnd, 431 segment1, seg2Start); 432 if (missingT2 < 0) { 433 return; 434 } 435 const SkOpSpan* missingSpan = &segment1->span(seg1End); 436 otherT2 = missingSpan->fT; 437 } 438 SkPoint missingPt2; 439 SkOpSegment* addTo2 = NULL; 440 SkOpSegment* addOther2 = seg1End < 0 ? segment2 : segment1; 441 int maxTIndex = refSegment->findExactT(max, addOther2); 442 SkASSERT(maxTIndex >= 0); 443 if (missingT2 >= 0) { 444 missingPt2 = refSegment->span(maxTIndex).fPt; 445 addTo2 = seg1End < 0 ? segment1 : segment2; 446 } 447 if (missingT1 >= 0) { 448 addTo1->pinT(missingPt1, &missingT1); 449 addTo1->addTPair(missingT1, addOther1, otherT1, false, missingPt1); 450 } else { 451 SkASSERT(minTIndex >= 0); 452 missingPt1 = refSegment->span(minTIndex).fPt; 453 } 454 if (missingT2 >= 0) { 455 addTo2->pinT(missingPt2, &missingT2); 456 addTo2->addTPair(missingT2, addOther2, otherT2, false, missingPt2); 457 } else { 458 SkASSERT(minTIndex >= 0); 459 missingPt2 = refSegment->span(maxTIndex).fPt; 460 } 461 if (!partial) { 462 return; 463 } 464 if (cancelers) { 465 if (missingT1 >= 0) { 466 if (addTo1->reversePoints(missingPt1, missingPt2)) { 467 SkTSwap(missingPt1, missingPt2); 468 } 469 addTo1->addTCancel(missingPt1, missingPt2, addOther1); 470 } else { 471 if (addTo2->reversePoints(missingPt1, missingPt2)) { 472 SkTSwap(missingPt1, missingPt2); 473 } 474 addTo2->addTCancel(missingPt1, missingPt2, addOther2); 475 } 476 } else if (missingT1 >= 0) { 477 SkAssertResult(addTo1->addTCoincident(missingPt1, missingPt2, 478 addTo1 == addTo2 ? missingT2 : otherT2, addOther1)); 479 } else { 480 SkAssertResult(addTo2->addTCoincident(missingPt2, missingPt1, 481 addTo2 == addTo1 ? missingT1 : otherT1, addOther2)); 482 } 483 } 484 485 void SkOpContour::joinCoincidence(const SkTArray<SkCoincidence, true>& coincidences, bool partial) { 486 int count = coincidences.count(); 487 #if DEBUG_CONCIDENT 488 if (count > 0) { 489 SkDebugf("%s count=%d\n", __FUNCTION__, count); 490 } 491 #endif 492 // look for a lineup where the partial implies another adjoining coincidence 493 for (int index = 0; index < count; ++index) { 494 const SkCoincidence& coincidence = coincidences[index]; 495 int thisIndex = coincidence.fSegments[0]; 496 SkOpSegment& thisOne = fSegments[thisIndex]; 497 if (thisOne.done()) { 498 continue; 499 } 500 SkOpContour* otherContour = coincidence.fOther; 501 int otherIndex = coincidence.fSegments[1]; 502 SkOpSegment& other = otherContour->fSegments[otherIndex]; 503 if (other.done()) { 504 continue; 505 } 506 double startT = coincidence.fTs[0][0]; 507 double endT = coincidence.fTs[0][1]; 508 if (startT == endT) { // this can happen in very large compares 509 continue; 510 } 511 double oStartT = coincidence.fTs[1][0]; 512 double oEndT = coincidence.fTs[1][1]; 513 if (oStartT == oEndT) { 514 continue; 515 } 516 bool swapStart = startT > endT; 517 bool swapOther = oStartT > oEndT; 518 const SkPoint* startPt = &coincidence.fPts[0][0]; 519 const SkPoint* endPt = &coincidence.fPts[0][1]; 520 if (swapStart) { 521 SkTSwap(startT, endT); 522 SkTSwap(oStartT, oEndT); 523 SkTSwap(startPt, endPt); 524 } 525 bool cancel = swapOther != swapStart; 526 int step = swapStart ? -1 : 1; 527 int oStep = swapOther ? -1 : 1; 528 double oMatchStart = cancel ? oEndT : oStartT; 529 if (partial ? startT != 0 || oMatchStart != 0 : (startT == 0) != (oMatchStart == 0)) { 530 bool added = false; 531 if (oMatchStart != 0) { 532 const SkPoint& oMatchStartPt = cancel ? *endPt : *startPt; 533 added = thisOne.joinCoincidence(&other, oMatchStart, oMatchStartPt, oStep, cancel); 534 } 535 if (!cancel && startT != 0 && !added) { 536 (void) other.joinCoincidence(&thisOne, startT, *startPt, step, cancel); 537 } 538 } 539 double oMatchEnd = cancel ? oStartT : oEndT; 540 if (partial ? endT != 1 || oMatchEnd != 1 : (endT == 1) != (oMatchEnd == 1)) { 541 bool added = false; 542 if (cancel && endT != 1 && !added) { 543 (void) other.joinCoincidence(&thisOne, endT, *endPt, -step, cancel); 544 } 545 } 546 } 547 } 548 549 bool SkOpContour::calcCommonCoincidentWinding(const SkCoincidence& coincidence) { 550 if (coincidence.fNearly[0] && coincidence.fNearly[1]) { 551 return true; 552 } 553 int thisIndex = coincidence.fSegments[0]; 554 SkOpSegment& thisOne = fSegments[thisIndex]; 555 if (thisOne.done()) { 556 return true; 557 } 558 SkOpContour* otherContour = coincidence.fOther; 559 int otherIndex = coincidence.fSegments[1]; 560 SkOpSegment& other = otherContour->fSegments[otherIndex]; 561 if (other.done()) { 562 return true; 563 } 564 double startT = coincidence.fTs[0][0]; 565 double endT = coincidence.fTs[0][1]; 566 const SkPoint* startPt = &coincidence.fPts[0][0]; 567 const SkPoint* endPt = &coincidence.fPts[0][1]; 568 bool cancelers; 569 if ((cancelers = startT > endT)) { 570 SkTSwap<double>(startT, endT); 571 SkTSwap<const SkPoint*>(startPt, endPt); 572 } 573 bump_out_close_span(&startT, &endT); 574 SkASSERT(!approximately_negative(endT - startT)); 575 double oStartT = coincidence.fTs[1][0]; 576 double oEndT = coincidence.fTs[1][1]; 577 if (oStartT > oEndT) { 578 SkTSwap<double>(oStartT, oEndT); 579 cancelers ^= true; 580 } 581 bump_out_close_span(&oStartT, &oEndT); 582 SkASSERT(!approximately_negative(oEndT - oStartT)); 583 bool success = true; 584 if (cancelers) { 585 thisOne.addTCancel(*startPt, *endPt, &other); 586 } else { 587 success = thisOne.addTCoincident(*startPt, *endPt, endT, &other); 588 } 589 #if DEBUG_CONCIDENT 590 thisOne.debugShowTs("p"); 591 other.debugShowTs("o"); 592 #endif 593 return success; 594 } 595 596 void SkOpContour::resolveNearCoincidence() { 597 int count = fCoincidences.count(); 598 for (int index = 0; index < count; ++index) { 599 SkCoincidence& coincidence = fCoincidences[index]; 600 if (!coincidence.fNearly[0] || !coincidence.fNearly[1]) { 601 continue; 602 } 603 int thisIndex = coincidence.fSegments[0]; 604 SkOpSegment& thisOne = fSegments[thisIndex]; 605 SkOpContour* otherContour = coincidence.fOther; 606 int otherIndex = coincidence.fSegments[1]; 607 SkOpSegment& other = otherContour->fSegments[otherIndex]; 608 if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) { 609 // OPTIMIZATION: remove from coincidence array 610 continue; 611 } 612 #if DEBUG_CONCIDENT 613 thisOne.debugShowTs("-"); 614 other.debugShowTs("o"); 615 #endif 616 double startT = coincidence.fTs[0][0]; 617 double endT = coincidence.fTs[0][1]; 618 bool cancelers; 619 if ((cancelers = startT > endT)) { 620 SkTSwap<double>(startT, endT); 621 } 622 if (startT == endT) { // if span is very large, the smaller may have collapsed to nothing 623 if (endT <= 1 - FLT_EPSILON) { 624 endT += FLT_EPSILON; 625 SkASSERT(endT <= 1); 626 } else { 627 startT -= FLT_EPSILON; 628 SkASSERT(startT >= 0); 629 } 630 } 631 SkASSERT(!approximately_negative(endT - startT)); 632 double oStartT = coincidence.fTs[1][0]; 633 double oEndT = coincidence.fTs[1][1]; 634 if (oStartT > oEndT) { 635 SkTSwap<double>(oStartT, oEndT); 636 cancelers ^= true; 637 } 638 SkASSERT(!approximately_negative(oEndT - oStartT)); 639 if (cancelers) { 640 thisOne.blindCancel(coincidence, &other); 641 } else { 642 thisOne.blindCoincident(coincidence, &other); 643 } 644 } 645 } 646 647 void SkOpContour::sortAngles() { 648 int segmentCount = fSegments.count(); 649 for (int test = 0; test < segmentCount; ++test) { 650 fSegments[test].sortAngles(); 651 } 652 } 653 654 void SkOpContour::sortSegments() { 655 int segmentCount = fSegments.count(); 656 fSortedSegments.push_back_n(segmentCount); 657 for (int test = 0; test < segmentCount; ++test) { 658 fSortedSegments[test] = &fSegments[test]; 659 } 660 SkTQSort<SkOpSegment>(fSortedSegments.begin(), fSortedSegments.end() - 1); 661 fFirstSorted = 0; 662 } 663 664 void SkOpContour::toPath(SkPathWriter* path) const { 665 int segmentCount = fSegments.count(); 666 const SkPoint& pt = fSegments.front().pts()[0]; 667 path->deferredMove(pt); 668 for (int test = 0; test < segmentCount; ++test) { 669 fSegments[test].addCurveTo(0, 1, path, true); 670 } 671 path->close(); 672 } 673 674 void SkOpContour::topSortableSegment(const SkPoint& topLeft, SkPoint* bestXY, 675 SkOpSegment** topStart) { 676 int segmentCount = fSortedSegments.count(); 677 SkASSERT(segmentCount > 0); 678 int sortedIndex = fFirstSorted; 679 fDone = true; // may be cleared below 680 for ( ; sortedIndex < segmentCount; ++sortedIndex) { 681 SkOpSegment* testSegment = fSortedSegments[sortedIndex]; 682 if (testSegment->done()) { 683 if (sortedIndex == fFirstSorted) { 684 ++fFirstSorted; 685 } 686 continue; 687 } 688 fDone = false; 689 SkPoint testXY = testSegment->activeLeftTop(NULL); 690 if (*topStart) { 691 if (testXY.fY < topLeft.fY) { 692 continue; 693 } 694 if (testXY.fY == topLeft.fY && testXY.fX < topLeft.fX) { 695 continue; 696 } 697 if (bestXY->fY < testXY.fY) { 698 continue; 699 } 700 if (bestXY->fY == testXY.fY && bestXY->fX < testXY.fX) { 701 continue; 702 } 703 } 704 *topStart = testSegment; 705 *bestXY = testXY; 706 } 707 } 708 709 SkOpSegment* SkOpContour::undoneSegment(int* start, int* end) { 710 int segmentCount = fSegments.count(); 711 for (int test = 0; test < segmentCount; ++test) { 712 SkOpSegment* testSegment = &fSegments[test]; 713 if (testSegment->done()) { 714 continue; 715 } 716 testSegment->undoneSpan(start, end); 717 return testSegment; 718 } 719 return NULL; 720 } 721 722 #if DEBUG_SHOW_WINDING 723 int SkOpContour::debugShowWindingValues(int totalSegments, int ofInterest) { 724 int count = fSegments.count(); 725 int sum = 0; 726 for (int index = 0; index < count; ++index) { 727 sum += fSegments[index].debugShowWindingValues(totalSegments, ofInterest); 728 } 729 // SkDebugf("%s sum=%d\n", __FUNCTION__, sum); 730 return sum; 731 } 732 733 void SkOpContour::debugShowWindingValues(const SkTArray<SkOpContour*, true>& contourList) { 734 // int ofInterest = 1 << 1 | 1 << 5 | 1 << 9 | 1 << 13; 735 // int ofInterest = 1 << 4 | 1 << 8 | 1 << 12 | 1 << 16; 736 int ofInterest = 1 << 5 | 1 << 8; 737 int total = 0; 738 int index; 739 for (index = 0; index < contourList.count(); ++index) { 740 total += contourList[index]->segments().count(); 741 } 742 int sum = 0; 743 for (index = 0; index < contourList.count(); ++index) { 744 sum += contourList[index]->debugShowWindingValues(total, ofInterest); 745 } 746 // SkDebugf("%s total=%d\n", __FUNCTION__, sum); 747 } 748 #endif 749 750 void SkOpContour::setBounds() { 751 int count = fSegments.count(); 752 if (count == 0) { 753 SkDebugf("%s empty contour\n", __FUNCTION__); 754 SkASSERT(0); 755 // FIXME: delete empty contour? 756 return; 757 } 758 fBounds = fSegments.front().bounds(); 759 for (int index = 1; index < count; ++index) { 760 fBounds.add(fSegments[index].bounds()); 761 } 762 } 763