| 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 "SkIntersections.h" | 7 #include "SkIntersections.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 1253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1264 | 1264 |
| 1265 // FIXME: need to test this case: | 1265 // FIXME: need to test this case: |
| 1266 // contourA has two segments that are coincident | 1266 // contourA has two segments that are coincident |
| 1267 // contourB has two segments that are coincident in the same place | 1267 // contourB has two segments that are coincident in the same place |
| 1268 // each ends up with +2/0 pairs for winding count | 1268 // each ends up with +2/0 pairs for winding count |
| 1269 // since logic below doesn't transfer count (only increments/decrements) can thi
s be | 1269 // since logic below doesn't transfer count (only increments/decrements) can thi
s be |
| 1270 // resolved to +4/0 ? | 1270 // resolved to +4/0 ? |
| 1271 | 1271 |
| 1272 // set spans from start to end to increment the greater by one and decrement | 1272 // set spans from start to end to increment the greater by one and decrement |
| 1273 // the lesser | 1273 // the lesser |
| 1274 void SkOpSegment::addTCoincident(const SkPoint& startPt, const SkPoint& endPt, d
ouble endT, | 1274 bool SkOpSegment::addTCoincident(const SkPoint& startPt, const SkPoint& endPt, d
ouble endT, |
| 1275 SkOpSegment* other) { | 1275 SkOpSegment* other) { |
| 1276 bool binary = fOperand != other->fOperand; | 1276 bool binary = fOperand != other->fOperand; |
| 1277 int index = 0; | 1277 int index = 0; |
| 1278 while (startPt != fTs[index].fPt) { | 1278 while (startPt != fTs[index].fPt) { |
| 1279 SkASSERT(index < fTs.count()); | 1279 SkASSERT(index < fTs.count()); |
| 1280 ++index; | 1280 ++index; |
| 1281 } | 1281 } |
| 1282 double startT = fTs[index].fT; | 1282 double startT = fTs[index].fT; |
| 1283 while (index > 0 && precisely_equal(fTs[index - 1].fT, startT)) { | 1283 while (index > 0 && precisely_equal(fTs[index - 1].fT, startT)) { |
| 1284 --index; | 1284 --index; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1296 SkSTArray<kOutsideTrackedTCount, SkPoint, true> oOutsidePts; | 1296 SkSTArray<kOutsideTrackedTCount, SkPoint, true> oOutsidePts; |
| 1297 SkOpSpan* test = &fTs[index]; | 1297 SkOpSpan* test = &fTs[index]; |
| 1298 const SkPoint* testPt = &test->fPt; | 1298 const SkPoint* testPt = &test->fPt; |
| 1299 double testT = test->fT; | 1299 double testT = test->fT; |
| 1300 SkOpSpan* oTest = &other->fTs[oIndex]; | 1300 SkOpSpan* oTest = &other->fTs[oIndex]; |
| 1301 const SkPoint* oTestPt = &oTest->fPt; | 1301 const SkPoint* oTestPt = &oTest->fPt; |
| 1302 // paths with extreme data will fail this test and eject out of pathops alto
gether later on | 1302 // paths with extreme data will fail this test and eject out of pathops alto
gether later on |
| 1303 // SkASSERT(AlmostEqualUlps(*testPt, *oTestPt)); | 1303 // SkASSERT(AlmostEqualUlps(*testPt, *oTestPt)); |
| 1304 do { | 1304 do { |
| 1305 SkASSERT(test->fT < 1); | 1305 SkASSERT(test->fT < 1); |
| 1306 SkASSERT(oTest->fT < 1); | 1306 if (oTest->fT == 1) { |
| 1307 // paths with extreme data may be so mismatched that we fail here |
| 1308 return false; |
| 1309 } |
| 1307 | 1310 |
| 1308 // consolidate the winding count even if done | 1311 // consolidate the winding count even if done |
| 1309 if ((test->fWindValue == 0 && test->fOppValue == 0) | 1312 if ((test->fWindValue == 0 && test->fOppValue == 0) |
| 1310 || (oTest->fWindValue == 0 && oTest->fOppValue == 0)) { | 1313 || (oTest->fWindValue == 0 && oTest->fOppValue == 0)) { |
| 1311 SkDEBUGCODE(int firstWind = test->fWindValue); | 1314 SkDEBUGCODE(int firstWind = test->fWindValue); |
| 1312 SkDEBUGCODE(int firstOpp = test->fOppValue); | 1315 SkDEBUGCODE(int firstOpp = test->fOppValue); |
| 1313 do { | 1316 do { |
| 1314 SkASSERT(firstWind == fTs[index].fWindValue); | 1317 SkASSERT(firstWind == fTs[index].fWindValue); |
| 1315 SkASSERT(firstOpp == fTs[index].fOppValue); | 1318 SkASSERT(firstOpp == fTs[index].fOppValue); |
| 1316 ++index; | 1319 ++index; |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1402 } | 1405 } |
| 1403 int outCount = outsidePts.count(); | 1406 int outCount = outsidePts.count(); |
| 1404 if (!done() && outCount) { | 1407 if (!done() && outCount) { |
| 1405 addCoinOutsides(outsidePts[0], endPt, other); | 1408 addCoinOutsides(outsidePts[0], endPt, other); |
| 1406 } | 1409 } |
| 1407 if (!other->done() && oOutsidePts.count()) { | 1410 if (!other->done() && oOutsidePts.count()) { |
| 1408 other->addCoinOutsides(oOutsidePts[0], endPt, this); | 1411 other->addCoinOutsides(oOutsidePts[0], endPt, this); |
| 1409 } | 1412 } |
| 1410 setCoincidentRange(startPt, endPt, other); | 1413 setCoincidentRange(startPt, endPt, other); |
| 1411 other->setCoincidentRange(startPt, endPt, this); | 1414 other->setCoincidentRange(startPt, endPt, this); |
| 1415 return true; |
| 1412 } | 1416 } |
| 1413 | 1417 |
| 1414 // FIXME: this doesn't prevent the same span from being added twice | 1418 // FIXME: this doesn't prevent the same span from being added twice |
| 1415 // fix in caller, SkASSERT here? | 1419 // fix in caller, SkASSERT here? |
| 1416 // FIXME: this may erroneously reject adds for cubic loops | 1420 // FIXME: this may erroneously reject adds for cubic loops |
| 1417 const SkOpSpan* SkOpSegment::addTPair(double t, SkOpSegment* other, double other
T, bool borrowWind, | 1421 const SkOpSpan* SkOpSegment::addTPair(double t, SkOpSegment* other, double other
T, bool borrowWind, |
| 1418 const SkPoint& pt, const SkPoint& pt2) { | 1422 const SkPoint& pt, const SkPoint& pt2) { |
| 1419 int tCount = fTs.count(); | 1423 int tCount = fTs.count(); |
| 1420 for (int tIndex = 0; tIndex < tCount; ++tIndex) { | 1424 for (int tIndex = 0; tIndex < tCount; ++tIndex) { |
| 1421 const SkOpSpan& span = fTs[tIndex]; | 1425 const SkOpSpan& span = fTs[tIndex]; |
| (...skipping 993 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2415 missing.fPt)) { | 2419 missing.fPt)) { |
| 2416 continue; | 2420 continue; |
| 2417 } | 2421 } |
| 2418 int otherTIndex = missingOther->findT(missing.fOtherT, missing.fPt, miss
ing.fSegment); | 2422 int otherTIndex = missingOther->findT(missing.fOtherT, missing.fPt, miss
ing.fSegment); |
| 2419 const SkOpSpan& otherSpan = missingOther->span(otherTIndex); | 2423 const SkOpSpan& otherSpan = missingOther->span(otherTIndex); |
| 2420 if (otherSpan.fSmall) { | 2424 if (otherSpan.fSmall) { |
| 2421 const SkOpSpan* nextSpan = &otherSpan; | 2425 const SkOpSpan* nextSpan = &otherSpan; |
| 2422 do { | 2426 do { |
| 2423 ++nextSpan; | 2427 ++nextSpan; |
| 2424 } while (nextSpan->fSmall); | 2428 } while (nextSpan->fSmall); |
| 2425 missing.fSegment->addTCoincident(missing.fPt, nextSpan->fPt, nextSpa
n->fT, | 2429 SkAssertResult(missing.fSegment->addTCoincident(missing.fPt, nextSpa
n->fPt, |
| 2426 missingOther); | 2430 nextSpan->fT, missingOther)); |
| 2427 } else if (otherSpan.fT > 0) { | 2431 } else if (otherSpan.fT > 0) { |
| 2428 const SkOpSpan* priorSpan = &otherSpan; | 2432 const SkOpSpan* priorSpan = &otherSpan; |
| 2429 do { | 2433 do { |
| 2430 --priorSpan; | 2434 --priorSpan; |
| 2431 } while (priorSpan->fT == otherSpan.fT); | 2435 } while (priorSpan->fT == otherSpan.fT); |
| 2432 if (priorSpan->fSmall) { | 2436 if (priorSpan->fSmall) { |
| 2433 missing.fSegment->addTCancel(missing.fPt, priorSpan->fPt, missin
gOther); | 2437 missing.fSegment->addTCancel(missing.fPt, priorSpan->fPt, missin
gOther); |
| 2434 } | 2438 } |
| 2435 } | 2439 } |
| 2436 } | 2440 } |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2487 } | 2491 } |
| 2488 } | 2492 } |
| 2489 // FIXME: again, be overly conservative to avoid breaking existing tests | 2493 // FIXME: again, be overly conservative to avoid breaking existing tests |
| 2490 const SkOpSpan& oSpan = oStartIndex < oEndIndex ? other->fTs[oStartIndex] | 2494 const SkOpSpan& oSpan = oStartIndex < oEndIndex ? other->fTs[oStartIndex] |
| 2491 : other->fTs[oEndIndex]; | 2495 : other->fTs[oEndIndex]; |
| 2492 if (checkMultiple && !oSpan.fSmall) { | 2496 if (checkMultiple && !oSpan.fSmall) { |
| 2493 return; | 2497 return; |
| 2494 } | 2498 } |
| 2495 // SkASSERT(oSpan.fSmall); | 2499 // SkASSERT(oSpan.fSmall); |
| 2496 if (oStartIndex < oEndIndex) { | 2500 if (oStartIndex < oEndIndex) { |
| 2497 addTCoincident(span.fPt, next->fPt, next->fT, other); | 2501 SkAssertResult(addTCoincident(span.fPt, next->fPt, next->fT, other)); |
| 2498 } else { | 2502 } else { |
| 2499 addTCancel(span.fPt, next->fPt, other); | 2503 addTCancel(span.fPt, next->fPt, other); |
| 2500 } | 2504 } |
| 2501 if (!checkMultiple) { | 2505 if (!checkMultiple) { |
| 2502 return; | 2506 return; |
| 2503 } | 2507 } |
| 2504 // check to see if either segment is coincident with a third segment -- if i
t is, and if | 2508 // check to see if either segment is coincident with a third segment -- if i
t is, and if |
| 2505 // the opposite segment is not already coincident with the third, make it so | 2509 // the opposite segment is not already coincident with the third, make it so |
| 2506 // OPTIMIZE: to make this check easier, add coincident and cancel could set
a coincident bit | 2510 // OPTIMIZE: to make this check easier, add coincident and cancel could set
a coincident bit |
| 2507 if (span.fWindValue != 1 || span.fOppValue != 0) { | 2511 if (span.fWindValue != 1 || span.fOppValue != 0) { |
| (...skipping 24 matching lines...) Expand all Loading... |
| 2532 SkPoint oMid = other->ptAtT((oTest->fOtherT + tTest->fT) / 2
); | 2536 SkPoint oMid = other->ptAtT((oTest->fOtherT + tTest->fT) / 2
); |
| 2533 if (!SkDPoint::ApproximatelyEqual(mid, oMid)) { | 2537 if (!SkDPoint::ApproximatelyEqual(mid, oMid)) { |
| 2534 continue; | 2538 continue; |
| 2535 } | 2539 } |
| 2536 } | 2540 } |
| 2537 #if DEBUG_CONCIDENT | 2541 #if DEBUG_CONCIDENT |
| 2538 SkDebugf("%s coincident found=%d %1.9g %1.9g\n", __FUNCTION__, t
estOther->fID, | 2542 SkDebugf("%s coincident found=%d %1.9g %1.9g\n", __FUNCTION__, t
estOther->fID, |
| 2539 oTest->fOtherT, tTest->fT); | 2543 oTest->fOtherT, tTest->fT); |
| 2540 #endif | 2544 #endif |
| 2541 if (tTest->fT < oTest->fOtherT) { | 2545 if (tTest->fT < oTest->fOtherT) { |
| 2542 addTCoincident(span.fPt, next->fPt, next->fT, testOther); | 2546 SkAssertResult(addTCoincident(span.fPt, next->fPt, next->fT,
testOther)); |
| 2543 } else { | 2547 } else { |
| 2544 addTCancel(span.fPt, next->fPt, testOther); | 2548 addTCancel(span.fPt, next->fPt, testOther); |
| 2545 } | 2549 } |
| 2546 MissingSpan missing; | 2550 MissingSpan missing; |
| 2547 missing.fSegment = testOther; | 2551 missing.fSegment = testOther; |
| 2548 checkMultiple->push_back(missing); | 2552 checkMultiple->push_back(missing); |
| 2549 break; | 2553 break; |
| 2550 } | 2554 } |
| 2551 } | 2555 } |
| 2552 oTest = &oSpan; | 2556 oTest = &oSpan; |
| (...skipping 868 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3421 if (test->fOther == other || test->fOtherT != 1) { | 3425 if (test->fOther == other || test->fOtherT != 1) { |
| 3422 continue; | 3426 continue; |
| 3423 } | 3427 } |
| 3424 SkPoint startPt, endPt; | 3428 SkPoint startPt, endPt; |
| 3425 double endT; | 3429 double endT; |
| 3426 if (findCoincidentMatch(test, other, otherTIndex, next, step, &startPt,
&endPt, &endT)) { | 3430 if (findCoincidentMatch(test, other, otherTIndex, next, step, &startPt,
&endPt, &endT)) { |
| 3427 SkOpSegment* match = test->fOther; | 3431 SkOpSegment* match = test->fOther; |
| 3428 if (cancel) { | 3432 if (cancel) { |
| 3429 match->addTCancel(startPt, endPt, other); | 3433 match->addTCancel(startPt, endPt, other); |
| 3430 } else { | 3434 } else { |
| 3431 match->addTCoincident(startPt, endPt, endT, other); | 3435 SkAssertResult(match->addTCoincident(startPt, endPt, endT, other
)); |
| 3432 } | 3436 } |
| 3433 return true; | 3437 return true; |
| 3434 } | 3438 } |
| 3435 } while (fTs[++tIndex].fT == 0); | 3439 } while (fTs[++tIndex].fT == 0); |
| 3436 return false; | 3440 return false; |
| 3437 } | 3441 } |
| 3438 | 3442 |
| 3439 // this span is excluded by the winding rule -- chase the ends | 3443 // this span is excluded by the winding rule -- chase the ends |
| 3440 // as long as they are unambiguous to mark connections as done | 3444 // as long as they are unambiguous to mark connections as done |
| 3441 // and give them the same winding value | 3445 // and give them the same winding value |
| (...skipping 999 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4441 SkASSERT(span->fWindValue > 0 || span->fOppValue != 0); | 4445 SkASSERT(span->fWindValue > 0 || span->fOppValue != 0); |
| 4442 span->fWindValue = 0; | 4446 span->fWindValue = 0; |
| 4443 span->fOppValue = 0; | 4447 span->fOppValue = 0; |
| 4444 if (span->fTiny || span->fSmall) { | 4448 if (span->fTiny || span->fSmall) { |
| 4445 return; | 4449 return; |
| 4446 } | 4450 } |
| 4447 SkASSERT(!span->fDone); | 4451 SkASSERT(!span->fDone); |
| 4448 span->fDone = true; | 4452 span->fDone = true; |
| 4449 ++fDoneSpans; | 4453 ++fDoneSpans; |
| 4450 } | 4454 } |
| OLD | NEW |