| 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 "SkAddIntersections.h" | 7 #include "SkAddIntersections.h" |
| 8 #include "SkOpCoincidence.h" |
| 8 #include "SkPathOpsBounds.h" | 9 #include "SkPathOpsBounds.h" |
| 9 | 10 |
| 10 #if DEBUG_ADD_INTERSECTING_TS | 11 #if DEBUG_ADD_INTERSECTING_TS |
| 11 | 12 |
| 12 static void debugShowLineIntersection(int pts, const SkIntersectionHelper& wt, | 13 static void debugShowLineIntersection(int pts, const SkIntersectionHelper& wt, |
| 13 const SkIntersectionHelper& wn, const SkIn
tersections& i) { | 14 const SkIntersectionHelper& wn, const SkIn
tersections& i) { |
| 14 SkASSERT(i.used() == pts); | 15 SkASSERT(i.used() == pts); |
| 15 if (!pts) { | 16 if (!pts) { |
| 16 SkDebugf("%s no intersect " LINE_DEBUG_STR " " LINE_DEBUG_STR "\n", | 17 SkDebugf("%s no intersect " LINE_DEBUG_STR " " LINE_DEBUG_STR "\n", |
| 17 __FUNCTION__, LINE_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts(
))); | 18 __FUNCTION__, LINE_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts(
))); |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 123 for (int n = 1; n < pts; ++n) { | 124 for (int n = 1; n < pts; ++n) { |
| 124 SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i[0][n], PT_DEBUG_D
ATA(i, n)); | 125 SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i[0][n], PT_DEBUG_D
ATA(i, n)); |
| 125 } | 126 } |
| 126 SkDebugf(" wnTs[0]=%g " CUBIC_DEBUG_STR, i[1][0], CUBIC_DEBUG_DATA(wn.pts())
); | 127 SkDebugf(" wnTs[0]=%g " CUBIC_DEBUG_STR, i[1][0], CUBIC_DEBUG_DATA(wn.pts())
); |
| 127 for (int n = 1; n < pts; ++n) { | 128 for (int n = 1; n < pts; ++n) { |
| 128 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i[1][n]); | 129 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i[1][n]); |
| 129 } | 130 } |
| 130 SkDebugf("\n"); | 131 SkDebugf("\n"); |
| 131 } | 132 } |
| 132 | 133 |
| 133 static void debugShowCubicIntersection(int pts, const SkIntersectionHelper& wt, | |
| 134 const SkIntersections& i) { | |
| 135 SkASSERT(i.used() == pts); | |
| 136 if (!pts) { | |
| 137 SkDebugf("%s no self intersect " CUBIC_DEBUG_STR "\n", __FUNCTION__, | |
| 138 CUBIC_DEBUG_DATA(wt.pts())); | |
| 139 return; | |
| 140 } | |
| 141 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __
FUNCTION__, | |
| 142 i[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0)); | |
| 143 SkDebugf(" " T_DEBUG_STR(wtTs, 1), i[1][0]); | |
| 144 SkDebugf("\n"); | |
| 145 } | |
| 146 | |
| 147 #else | 134 #else |
| 148 static void debugShowLineIntersection(int , const SkIntersectionHelper& , | 135 static void debugShowLineIntersection(int , const SkIntersectionHelper& , |
| 149 const SkIntersectionHelper& , const SkIntersections& ) { | 136 const SkIntersectionHelper& , const SkIntersections& ) { |
| 150 } | 137 } |
| 151 | 138 |
| 152 static void debugShowQuadLineIntersection(int , const SkIntersectionHelper& , | 139 static void debugShowQuadLineIntersection(int , const SkIntersectionHelper& , |
| 153 const SkIntersectionHelper& , const SkIntersections& ) { | 140 const SkIntersectionHelper& , const SkIntersections& ) { |
| 154 } | 141 } |
| 155 | 142 |
| 156 static void debugShowQuadIntersection(int , const SkIntersectionHelper& , | 143 static void debugShowQuadIntersection(int , const SkIntersectionHelper& , |
| 157 const SkIntersectionHelper& , const SkIntersections& ) { | 144 const SkIntersectionHelper& , const SkIntersections& ) { |
| 158 } | 145 } |
| 159 | 146 |
| 160 static void debugShowCubicLineIntersection(int , const SkIntersectionHelper& , | 147 static void debugShowCubicLineIntersection(int , const SkIntersectionHelper& , |
| 161 const SkIntersectionHelper& , const SkIntersections& ) { | 148 const SkIntersectionHelper& , const SkIntersections& ) { |
| 162 } | 149 } |
| 163 | 150 |
| 164 static void debugShowCubicQuadIntersection(int , const SkIntersectionHelper& , | 151 static void debugShowCubicQuadIntersection(int , const SkIntersectionHelper& , |
| 165 const SkIntersectionHelper& , const SkIntersections& ) { | 152 const SkIntersectionHelper& , const SkIntersections& ) { |
| 166 } | 153 } |
| 167 | 154 |
| 168 static void debugShowCubicIntersection(int , const SkIntersectionHelper& , | 155 static void debugShowCubicIntersection(int , const SkIntersectionHelper& , |
| 169 const SkIntersectionHelper& , const SkIntersections& ) { | 156 const SkIntersectionHelper& , const SkIntersections& ) { |
| 170 } | 157 } |
| 171 | |
| 172 static void debugShowCubicIntersection(int , const SkIntersectionHelper& , | |
| 173 const SkIntersections& ) { | |
| 174 } | |
| 175 #endif | 158 #endif |
| 176 | 159 |
| 177 bool AddIntersectTs(SkOpContour* test, SkOpContour* next) { | 160 bool AddIntersectTs(SkOpContour* test, SkOpContour* next, SkOpCoincidence* coinc
idence, |
| 161 SkChunkAlloc* allocator) { |
| 178 if (test != next) { | 162 if (test != next) { |
| 179 if (AlmostLessUlps(test->bounds().fBottom, next->bounds().fTop)) { | 163 if (AlmostLessUlps(test->bounds().fBottom, next->bounds().fTop)) { |
| 180 return false; | 164 return false; |
| 181 } | 165 } |
| 182 // OPTIMIZATION: outset contour bounds a smidgen instead? | 166 // OPTIMIZATION: outset contour bounds a smidgen instead? |
| 183 if (!SkPathOpsBounds::Intersects(test->bounds(), next->bounds())) { | 167 if (!SkPathOpsBounds::Intersects(test->bounds(), next->bounds())) { |
| 184 return true; | 168 return true; |
| 185 } | 169 } |
| 186 } | 170 } |
| 187 SkIntersectionHelper wt; | 171 SkIntersectionHelper wt; |
| 188 wt.init(test); | 172 wt.init(test); |
| 189 bool foundCommonContour = test == next; | |
| 190 do { | 173 do { |
| 191 SkIntersectionHelper wn; | 174 SkIntersectionHelper wn; |
| 192 wn.init(next); | 175 wn.init(next); |
| 176 test->debugValidate(); |
| 177 next->debugValidate(); |
| 193 if (test == next && !wn.startAfter(wt)) { | 178 if (test == next && !wn.startAfter(wt)) { |
| 194 continue; | 179 continue; |
| 195 } | 180 } |
| 196 do { | 181 do { |
| 197 if (!SkPathOpsBounds::Intersects(wt.bounds(), wn.bounds())) { | 182 if (!SkPathOpsBounds::Intersects(wt.bounds(), wn.bounds())) { |
| 198 continue; | 183 continue; |
| 199 } | 184 } |
| 200 int pts = 0; | 185 int pts = 0; |
| 201 SkIntersections ts; | 186 SkIntersections ts; |
| 202 bool swap = false; | 187 bool swap = false; |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 299 pts = ts.quadVertical(wt.pts(), wn.top(), | 284 pts = ts.quadVertical(wt.pts(), wn.top(), |
| 300 wn.bottom(), wn.x(), wn.yFlipped()); | 285 wn.bottom(), wn.x(), wn.yFlipped()); |
| 301 debugShowQuadLineIntersection(pts, wt, wn, ts); | 286 debugShowQuadLineIntersection(pts, wt, wn, ts); |
| 302 break; | 287 break; |
| 303 case SkIntersectionHelper::kLine_Segment: { | 288 case SkIntersectionHelper::kLine_Segment: { |
| 304 pts = ts.quadLine(wt.pts(), wn.pts()); | 289 pts = ts.quadLine(wt.pts(), wn.pts()); |
| 305 debugShowQuadLineIntersection(pts, wt, wn, ts); | 290 debugShowQuadLineIntersection(pts, wt, wn, ts); |
| 306 break; | 291 break; |
| 307 } | 292 } |
| 308 case SkIntersectionHelper::kQuad_Segment: { | 293 case SkIntersectionHelper::kQuad_Segment: { |
| 309 pts = ts.quadQuad(wt.pts(), wn.pts()); | 294 SkDQuad quad1; |
| 310 ts.alignQuadPts(wt.pts(), wn.pts()); | 295 quad1.set(wt.pts()); |
| 296 SkDQuad quad2; |
| 297 quad2.set(wn.pts()); |
| 298 pts = ts.intersect(quad1, quad2); |
| 311 debugShowQuadIntersection(pts, wt, wn, ts); | 299 debugShowQuadIntersection(pts, wt, wn, ts); |
| 312 break; | 300 break; |
| 313 } | 301 } |
| 314 case SkIntersectionHelper::kCubic_Segment: { | 302 case SkIntersectionHelper::kCubic_Segment: { |
| 315 swap = true; | 303 swap = true; |
| 316 pts = ts.cubicQuad(wn.pts(), wt.pts()); | 304 SkDQuad quad1; |
| 305 quad1.set(wt.pts()); |
| 306 SkDCubic cubic1 = quad1.toCubic(); |
| 307 SkDCubic cubic2; |
| 308 cubic2.set(wn.pts()); |
| 309 pts = ts.intersect(cubic2, cubic1); |
| 317 debugShowCubicQuadIntersection(pts, wn, wt, ts); | 310 debugShowCubicQuadIntersection(pts, wn, wt, ts); |
| 318 break; | 311 break; |
| 319 } | 312 } |
| 320 default: | 313 default: |
| 321 SkASSERT(0); | 314 SkASSERT(0); |
| 322 } | 315 } |
| 323 break; | 316 break; |
| 324 case SkIntersectionHelper::kCubic_Segment: | 317 case SkIntersectionHelper::kCubic_Segment: |
| 325 switch (wn.segmentType()) { | 318 switch (wn.segmentType()) { |
| 326 case SkIntersectionHelper::kHorizontalLine_Segment: | 319 case SkIntersectionHelper::kHorizontalLine_Segment: |
| 327 pts = ts.cubicHorizontal(wt.pts(), wn.left(), | 320 pts = ts.cubicHorizontal(wt.pts(), wn.left(), |
| 328 wn.right(), wn.y(), wn.xFlipped()); | 321 wn.right(), wn.y(), wn.xFlipped()); |
| 329 debugShowCubicLineIntersection(pts, wt, wn, ts); | 322 debugShowCubicLineIntersection(pts, wt, wn, ts); |
| 330 break; | 323 break; |
| 331 case SkIntersectionHelper::kVerticalLine_Segment: | 324 case SkIntersectionHelper::kVerticalLine_Segment: |
| 332 pts = ts.cubicVertical(wt.pts(), wn.top(), | 325 pts = ts.cubicVertical(wt.pts(), wn.top(), |
| 333 wn.bottom(), wn.x(), wn.yFlipped()); | 326 wn.bottom(), wn.x(), wn.yFlipped()); |
| 334 debugShowCubicLineIntersection(pts, wt, wn, ts); | 327 debugShowCubicLineIntersection(pts, wt, wn, ts); |
| 335 break; | 328 break; |
| 336 case SkIntersectionHelper::kLine_Segment: { | 329 case SkIntersectionHelper::kLine_Segment: { |
| 337 pts = ts.cubicLine(wt.pts(), wn.pts()); | 330 pts = ts.cubicLine(wt.pts(), wn.pts()); |
| 338 debugShowCubicLineIntersection(pts, wt, wn, ts); | 331 debugShowCubicLineIntersection(pts, wt, wn, ts); |
| 339 break; | 332 break; |
| 340 } | 333 } |
| 341 case SkIntersectionHelper::kQuad_Segment: { | 334 case SkIntersectionHelper::kQuad_Segment: { |
| 342 pts = ts.cubicQuad(wt.pts(), wn.pts()); | 335 SkDCubic cubic1; |
| 336 cubic1.set(wt.pts()); |
| 337 SkDQuad quad2; |
| 338 quad2.set(wn.pts()); |
| 339 SkDCubic cubic2 = quad2.toCubic(); |
| 340 pts = ts.intersect(cubic1, cubic2); |
| 343 debugShowCubicQuadIntersection(pts, wt, wn, ts); | 341 debugShowCubicQuadIntersection(pts, wt, wn, ts); |
| 344 break; | 342 break; |
| 345 } | 343 } |
| 346 case SkIntersectionHelper::kCubic_Segment: { | 344 case SkIntersectionHelper::kCubic_Segment: { |
| 347 pts = ts.cubicCubic(wt.pts(), wn.pts()); | 345 SkDCubic cubic1; |
| 346 cubic1.set(wt.pts()); |
| 347 SkDCubic cubic2; |
| 348 cubic2.set(wn.pts()); |
| 349 pts = ts.intersect(cubic1, cubic2); |
| 348 debugShowCubicIntersection(pts, wt, wn, ts); | 350 debugShowCubicIntersection(pts, wt, wn, ts); |
| 349 break; | 351 break; |
| 350 } | 352 } |
| 351 default: | 353 default: |
| 352 SkASSERT(0); | 354 SkASSERT(0); |
| 353 } | 355 } |
| 354 break; | 356 break; |
| 355 default: | 357 default: |
| 356 SkASSERT(0); | 358 SkASSERT(0); |
| 357 } | 359 } |
| 358 if (!foundCommonContour && pts > 0) { | 360 int coinIndex = -1; |
| 359 test->addCross(next); | 361 SkOpPtT* coinPtT[2]; |
| 360 next->addCross(test); | |
| 361 foundCommonContour = true; | |
| 362 } | |
| 363 // in addition to recording T values, record matching segment | |
| 364 if (pts == 2) { | |
| 365 if (wn.segmentType() <= SkIntersectionHelper::kLine_Segment | |
| 366 && wt.segmentType() <= SkIntersectionHelper::kLine_Segme
nt) { | |
| 367 if (wt.addCoincident(wn, ts, swap)) { | |
| 368 continue; | |
| 369 } | |
| 370 pts = ts.cleanUpCoincidence(); // prefer (t == 0 or t == 1) | |
| 371 } else if (wn.segmentType() >= SkIntersectionHelper::kQuad_Segme
nt | |
| 372 && wt.segmentType() >= SkIntersectionHelper::kQuad_Segme
nt | |
| 373 && ts.isCoincident(0)) { | |
| 374 SkASSERT(ts.coincidentUsed() == 2); | |
| 375 if (wt.addCoincident(wn, ts, swap)) { | |
| 376 continue; | |
| 377 } | |
| 378 pts = ts.cleanUpCoincidence(); // prefer (t == 0 or t == 1) | |
| 379 } | |
| 380 } | |
| 381 if (pts >= 2) { | |
| 382 for (int pt = 0; pt < pts - 1; ++pt) { | |
| 383 const SkDPoint& point = ts.pt(pt); | |
| 384 const SkDPoint& next = ts.pt(pt + 1); | |
| 385 if (wt.isPartial(ts[swap][pt], ts[swap][pt + 1], point, next
) | |
| 386 && wn.isPartial(ts[!swap][pt], ts[!swap][pt + 1], po
int, next)) { | |
| 387 if (!wt.addPartialCoincident(wn, ts, pt, swap)) { | |
| 388 // remove extra point if two map to same float value
s | |
| 389 pts = ts.cleanUpCoincidence(); // prefer (t == 0 or
t == 1) | |
| 390 } | |
| 391 } | |
| 392 } | |
| 393 } | |
| 394 for (int pt = 0; pt < pts; ++pt) { | 362 for (int pt = 0; pt < pts; ++pt) { |
| 395 SkASSERT(ts[0][pt] >= 0 && ts[0][pt] <= 1); | 363 SkASSERT(ts[0][pt] >= 0 && ts[0][pt] <= 1); |
| 396 SkASSERT(ts[1][pt] >= 0 && ts[1][pt] <= 1); | 364 SkASSERT(ts[1][pt] >= 0 && ts[1][pt] <= 1); |
| 397 SkPoint point = ts.pt(pt).asSkPoint(); | 365 wt.segment()->debugValidate(); |
| 398 wt.alignTPt(wn, swap, pt, &ts, &point); | 366 SkOpPtT* testTAt = wt.segment()->addT(ts[swap][pt], SkOpSegment:
:kAllowAlias, |
| 399 int testTAt = wt.addT(wn, point, ts[swap][pt]); | 367 allocator); |
| 400 int nextTAt = wn.addT(wt, point, ts[!swap][pt]); | 368 wn.segment()->debugValidate(); |
| 401 wt.addOtherT(testTAt, ts[!swap][pt], nextTAt); | 369 SkOpPtT* nextTAt = wn.segment()->addT(ts[!swap][pt], SkOpSegment
::kAllowAlias, |
| 402 wn.addOtherT(nextTAt, ts[swap][pt], testTAt); | 370 allocator); |
| 371 testTAt->addOpp(nextTAt); |
| 372 if (testTAt->fPt != nextTAt->fPt) { |
| 373 testTAt->span()->unaligned(); |
| 374 nextTAt->span()->unaligned(); |
| 375 } |
| 376 wt.segment()->debugValidate(); |
| 377 wn.segment()->debugValidate(); |
| 378 if (!ts.isCoincident(pt)) { |
| 379 continue; |
| 380 } |
| 381 if (coinIndex < 0) { |
| 382 coinPtT[0] = testTAt; |
| 383 coinPtT[1] = nextTAt; |
| 384 coinIndex = pt; |
| 385 continue; |
| 386 } |
| 387 if (coinPtT[0]->span() == testTAt->span()) { |
| 388 coinIndex = -1; |
| 389 continue; |
| 390 } |
| 391 if (coinPtT[1]->span() == nextTAt->span()) { |
| 392 coinIndex = -1; // coincidence span collapsed |
| 393 continue; |
| 394 } |
| 395 if (swap) { |
| 396 SkTSwap(coinPtT[0], coinPtT[1]); |
| 397 SkTSwap(testTAt, nextTAt); |
| 398 } |
| 399 SkASSERT(coinPtT[0]->span()->t() < testTAt->span()->t()); |
| 400 coincidence->add(coinPtT[0], testTAt, coinPtT[1], nextTAt, alloc
ator); |
| 401 wt.segment()->debugValidate(); |
| 402 wn.segment()->debugValidate(); |
| 403 coinIndex = -1; |
| 403 } | 404 } |
| 405 SkASSERT(coinIndex < 0); // expect coincidence to be paired |
| 404 } while (wn.advance()); | 406 } while (wn.advance()); |
| 405 } while (wt.advance()); | 407 } while (wt.advance()); |
| 406 return true; | 408 return true; |
| 407 } | 409 } |
| 408 | |
| 409 void AddSelfIntersectTs(SkOpContour* test) { | |
| 410 SkIntersectionHelper wt; | |
| 411 wt.init(test); | |
| 412 do { | |
| 413 if (wt.segmentType() != SkIntersectionHelper::kCubic_Segment) { | |
| 414 continue; | |
| 415 } | |
| 416 SkIntersections ts; | |
| 417 int pts = ts.cubic(wt.pts()); | |
| 418 debugShowCubicIntersection(pts, wt, ts); | |
| 419 if (!pts) { | |
| 420 continue; | |
| 421 } | |
| 422 SkASSERT(pts == 1); | |
| 423 SkASSERT(ts[0][0] >= 0 && ts[0][0] <= 1); | |
| 424 SkASSERT(ts[1][0] >= 0 && ts[1][0] <= 1); | |
| 425 SkPoint point = ts.pt(0).asSkPoint(); | |
| 426 int testTAt = wt.addSelfT(point, ts[0][0]); | |
| 427 int nextTAt = wt.addSelfT(point, ts[1][0]); | |
| 428 wt.addOtherT(testTAt, ts[1][0], nextTAt); | |
| 429 wt.addOtherT(nextTAt, ts[0][0], testTAt); | |
| 430 } while (wt.advance()); | |
| 431 } | |
| 432 | |
| 433 // resolve any coincident pairs found while intersecting, and | |
| 434 // see if coincidence is formed by clipping non-concident segments | |
| 435 bool CoincidenceCheck(SkTArray<SkOpContour*, true>* contourList, int total) { | |
| 436 int contourCount = (*contourList).count(); | |
| 437 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { | |
| 438 SkOpContour* contour = (*contourList)[cIndex]; | |
| 439 contour->resolveNearCoincidence(); | |
| 440 } | |
| 441 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { | |
| 442 SkOpContour* contour = (*contourList)[cIndex]; | |
| 443 contour->addCoincidentPoints(); | |
| 444 } | |
| 445 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { | |
| 446 SkOpContour* contour = (*contourList)[cIndex]; | |
| 447 if (!contour->calcCoincidentWinding()) { | |
| 448 return false; | |
| 449 } | |
| 450 } | |
| 451 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { | |
| 452 SkOpContour* contour = (*contourList)[cIndex]; | |
| 453 contour->calcPartialCoincidentWinding(); | |
| 454 } | |
| 455 return true; | |
| 456 } | |
| OLD | NEW |