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 |