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 "SkOpSegment.h" | 8 #include "SkOpSegment.h" |
9 #include "SkPathWriter.h" | 9 #include "SkPathWriter.h" |
10 #include "SkTSort.h" | 10 #include "SkTSort.h" |
(...skipping 432 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
443 SkOpSpan* span; | 443 SkOpSpan* span; |
444 if (insertedAt >= 0) { | 444 if (insertedAt >= 0) { |
445 span = fTs.insert(insertedAt); | 445 span = fTs.insert(insertedAt); |
446 } else { | 446 } else { |
447 insertedAt = tCount; | 447 insertedAt = tCount; |
448 span = fTs.append(); | 448 span = fTs.append(); |
449 } | 449 } |
450 span->fT = newT; | 450 span->fT = newT; |
451 span->fOther = other; | 451 span->fOther = other; |
452 span->fPt = pt; | 452 span->fPt = pt; |
| 453 #if 0 |
| 454 // cubics, for instance, may not be exact enough to satisfy this check (e.g.
, cubicOp69d) |
| 455 SkASSERT(approximately_equal(xyAtT(newT).fX, pt.fX) |
| 456 && approximately_equal(xyAtT(newT).fY, pt.fY)); |
| 457 #endif |
453 span->fWindSum = SK_MinS32; | 458 span->fWindSum = SK_MinS32; |
454 span->fOppSum = SK_MinS32; | 459 span->fOppSum = SK_MinS32; |
455 span->fWindValue = 1; | 460 span->fWindValue = 1; |
456 span->fOppValue = 0; | 461 span->fOppValue = 0; |
457 span->fTiny = false; | 462 span->fTiny = false; |
458 span->fLoop = false; | 463 span->fLoop = false; |
459 if ((span->fDone = newT == 1)) { | 464 if ((span->fDone = newT == 1)) { |
460 ++fDoneSpans; | 465 ++fDoneSpans; |
461 } | 466 } |
462 span->fUnsortableStart = false; | 467 span->fUnsortableStart = false; |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
526 } | 531 } |
527 } | 532 } |
528 ++fDoneSpans; | 533 ++fDoneSpans; |
529 ++more; | 534 ++more; |
530 } | 535 } |
531 return insertedAt; | 536 return insertedAt; |
532 } | 537 } |
533 | 538 |
534 // set spans from start to end to decrement by one | 539 // set spans from start to end to decrement by one |
535 // note this walks other backwards | 540 // note this walks other backwards |
536 // FIMXE: there's probably an edge case that can be constructed where | 541 // FIXME: there's probably an edge case that can be constructed where |
537 // two span in one segment are separated by float epsilon on one span but | 542 // two span in one segment are separated by float epsilon on one span but |
538 // not the other, if one segment is very small. For this | 543 // not the other, if one segment is very small. For this |
539 // case the counts asserted below may or may not be enough to separate the | 544 // case the counts asserted below may or may not be enough to separate the |
540 // spans. Even if the counts work out, what if the spans aren't correctly | 545 // spans. Even if the counts work out, what if the spans aren't correctly |
541 // sorted? It feels better in such a case to match the span's other span | 546 // sorted? It feels better in such a case to match the span's other span |
542 // pointer since both coincident segments must contain the same spans. | 547 // pointer since both coincident segments must contain the same spans. |
| 548 // FIXME? It seems that decrementing by one will fail for complex paths that |
| 549 // have three or more coincident edges. Shouldn't this subtract the difference |
| 550 // between the winding values? |
543 void SkOpSegment::addTCancel(double startT, double endT, SkOpSegment* other, | 551 void SkOpSegment::addTCancel(double startT, double endT, SkOpSegment* other, |
544 double oStartT, double oEndT) { | 552 double oStartT, double oEndT) { |
545 SkASSERT(!approximately_negative(endT - startT)); | 553 SkASSERT(!approximately_negative(endT - startT)); |
546 SkASSERT(!approximately_negative(oEndT - oStartT)); | 554 SkASSERT(!approximately_negative(oEndT - oStartT)); |
547 bool binary = fOperand != other->fOperand; | 555 bool binary = fOperand != other->fOperand; |
548 int index = 0; | 556 int index = 0; |
549 while (!approximately_negative(startT - fTs[index].fT)) { | 557 while (!approximately_negative(startT - fTs[index].fT)) { |
550 ++index; | 558 ++index; |
551 } | 559 } |
552 int oIndex = other->fTs.count(); | 560 int oIndex = other->fTs.count(); |
553 while (approximately_positive(other->fTs[--oIndex].fT - oEndT)) | 561 while (approximately_positive(other->fTs[--oIndex].fT - oEndT)) |
554 ; | 562 ; |
555 double tRatio = (oEndT - oStartT) / (endT - startT); | 563 double tRatio = (oEndT - oStartT) / (endT - startT); |
556 SkOpSpan* test = &fTs[index]; | 564 SkOpSpan* test = &fTs[index]; |
557 SkOpSpan* oTest = &other->fTs[oIndex]; | 565 SkOpSpan* oTest = &other->fTs[oIndex]; |
558 SkTDArray<double> outsideTs; | 566 SkTDArray<double> outsideTs; |
559 SkTDArray<double> oOutsideTs; | 567 SkTDArray<double> oOutsideTs; |
560 do { | 568 do { |
561 bool decrement = test->fWindValue && oTest->fWindValue && !binary; | 569 bool decrement = test->fWindValue && oTest->fWindValue; |
562 bool track = test->fWindValue || oTest->fWindValue; | 570 bool track = test->fWindValue || oTest->fWindValue; |
| 571 bool bigger = test->fWindValue >= oTest->fWindValue; |
563 double testT = test->fT; | 572 double testT = test->fT; |
564 double oTestT = oTest->fT; | 573 double oTestT = oTest->fT; |
565 SkOpSpan* span = test; | 574 SkOpSpan* span = test; |
566 do { | 575 do { |
567 if (decrement) { | 576 if (decrement) { |
568 decrementSpan(span); | 577 if (binary && bigger) { |
| 578 span->fOppValue--; |
| 579 } else { |
| 580 decrementSpan(span); |
| 581 } |
569 } else if (track && span->fT < 1 && oTestT < 1) { | 582 } else if (track && span->fT < 1 && oTestT < 1) { |
570 TrackOutside(&outsideTs, span->fT, oTestT); | 583 TrackOutside(&outsideTs, span->fT, oTestT); |
571 } | 584 } |
572 span = &fTs[++index]; | 585 span = &fTs[++index]; |
573 } while (approximately_negative(span->fT - testT)); | 586 } while (approximately_negative(span->fT - testT)); |
574 SkOpSpan* oSpan = oTest; | 587 SkOpSpan* oSpan = oTest; |
575 double otherTMatchStart = oEndT - (span->fT - startT) * tRatio; | 588 double otherTMatchStart = oEndT - (span->fT - startT) * tRatio; |
576 double otherTMatchEnd = oEndT - (test->fT - startT) * tRatio; | 589 double otherTMatchEnd = oEndT - (test->fT - startT) * tRatio; |
577 SkDEBUGCODE(int originalWindValue = oSpan->fWindValue); | 590 SkDEBUGCODE(int originalWindValue = oSpan->fWindValue); |
578 while (approximately_negative(otherTMatchStart - oSpan->fT) | 591 while (approximately_negative(otherTMatchStart - oSpan->fT) |
579 && !approximately_negative(otherTMatchEnd - oSpan->fT)) { | 592 && !approximately_negative(otherTMatchEnd - oSpan->fT)) { |
580 #ifdef SK_DEBUG | 593 #ifdef SK_DEBUG |
581 SkASSERT(originalWindValue == oSpan->fWindValue); | 594 SkASSERT(originalWindValue == oSpan->fWindValue); |
582 #endif | 595 #endif |
583 if (decrement) { | 596 if (decrement) { |
584 other->decrementSpan(oSpan); | 597 if (binary && !bigger) { |
| 598 oSpan->fOppValue--; |
| 599 } else { |
| 600 other->decrementSpan(oSpan); |
| 601 } |
585 } else if (track && oSpan->fT < 1 && testT < 1) { | 602 } else if (track && oSpan->fT < 1 && testT < 1) { |
586 TrackOutside(&oOutsideTs, oSpan->fT, testT); | 603 TrackOutside(&oOutsideTs, oSpan->fT, testT); |
587 } | 604 } |
588 if (!oIndex) { | 605 if (!oIndex) { |
589 break; | 606 break; |
590 } | 607 } |
591 oSpan = &other->fTs[--oIndex]; | 608 oSpan = &other->fTs[--oIndex]; |
592 } | 609 } |
593 test = span; | 610 test = span; |
594 oTest = oSpan; | 611 oTest = oSpan; |
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
751 int otherInsertedAt = other->addT(this, pt, otherT); | 768 int otherInsertedAt = other->addT(this, pt, otherT); |
752 addOtherT(insertedAt, otherT, otherInsertedAt); | 769 addOtherT(insertedAt, otherT, otherInsertedAt); |
753 other->addOtherT(otherInsertedAt, t, insertedAt); | 770 other->addOtherT(otherInsertedAt, t, insertedAt); |
754 matchWindingValue(insertedAt, t, borrowWind); | 771 matchWindingValue(insertedAt, t, borrowWind); |
755 other->matchWindingValue(otherInsertedAt, otherT, borrowWind); | 772 other->matchWindingValue(otherInsertedAt, otherT, borrowWind); |
756 } | 773 } |
757 | 774 |
758 void SkOpSegment::addTwoAngles(int start, int end, SkTDArray<SkOpAngle>* angles)
const { | 775 void SkOpSegment::addTwoAngles(int start, int end, SkTDArray<SkOpAngle>* angles)
const { |
759 // add edge leading into junction | 776 // add edge leading into junction |
760 int min = SkMin32(end, start); | 777 int min = SkMin32(end, start); |
761 if (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0) { | 778 if (fTs[min].fWindValue > 0 || fTs[min].fOppValue != 0) { |
762 addAngle(angles, end, start); | 779 addAngle(angles, end, start); |
763 } | 780 } |
764 // add edge leading away from junction | 781 // add edge leading away from junction |
765 int step = SkSign32(end - start); | 782 int step = SkSign32(end - start); |
766 int tIndex = nextExactSpan(end, step); | 783 int tIndex = nextExactSpan(end, step); |
767 min = SkMin32(end, tIndex); | 784 min = SkMin32(end, tIndex); |
768 if (tIndex >= 0 && (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0)) { | 785 if (tIndex >= 0 && (fTs[min].fWindValue > 0 || fTs[min].fOppValue != 0)) { |
769 addAngle(angles, end, tIndex); | 786 addAngle(angles, end, tIndex); |
770 } | 787 } |
771 } | 788 } |
772 | 789 |
773 int SkOpSegment::advanceCoincidentThis(const SkOpSpan* oTest, bool opp, int inde
x) { | 790 int SkOpSegment::advanceCoincidentThis(const SkOpSpan* oTest, bool opp, int inde
x) { |
774 SkOpSpan* const test = &fTs[index]; | 791 SkOpSpan* const test = &fTs[index]; |
775 SkOpSpan* end; | 792 SkOpSpan* end; |
776 do { | 793 do { |
777 end = &fTs[++index]; | 794 end = &fTs[++index]; |
778 } while (approximately_negative(end->fT - test->fT)); | 795 } while (approximately_negative(end->fT - test->fT)); |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
905 } | 922 } |
906 } | 923 } |
907 if (segment->windSum(angle) == SK_MinS32) { | 924 if (segment->windSum(angle) == SK_MinS32) { |
908 if (opp) { | 925 if (opp) { |
909 if (UseInnerWinding(oMaxWinding, oWinding)) { | 926 if (UseInnerWinding(oMaxWinding, oWinding)) { |
910 oMaxWinding = oWinding; | 927 oMaxWinding = oWinding; |
911 } | 928 } |
912 if (oppoSign && UseInnerWinding(maxWinding, winding)) { | 929 if (oppoSign && UseInnerWinding(maxWinding, winding)) { |
913 maxWinding = winding; | 930 maxWinding = winding; |
914 } | 931 } |
| 932 #ifdef SK_DEBUG |
| 933 SkASSERT(abs(maxWinding) <= gDebugMaxWindSum); |
| 934 SkASSERT(abs(oMaxWinding) <= gDebugMaxWindSum); |
| 935 #endif |
915 (void) segment->markAndChaseWinding(angle, oMaxWinding, maxWindi
ng); | 936 (void) segment->markAndChaseWinding(angle, oMaxWinding, maxWindi
ng); |
916 } else { | 937 } else { |
917 if (UseInnerWinding(maxWinding, winding)) { | 938 if (UseInnerWinding(maxWinding, winding)) { |
918 maxWinding = winding; | 939 maxWinding = winding; |
919 } | 940 } |
920 if (oppoSign && UseInnerWinding(oMaxWinding, oWinding)) { | 941 if (oppoSign && UseInnerWinding(oMaxWinding, oWinding)) { |
921 oMaxWinding = oWinding; | 942 oMaxWinding = oWinding; |
922 } | 943 } |
| 944 #ifdef SK_DEBUG |
| 945 SkASSERT(abs(maxWinding) <= gDebugMaxWindSum); |
| 946 SkASSERT(abs(binary ? oMaxWinding : 0) <= gDebugMaxWindSum); |
| 947 #endif |
923 (void) segment->markAndChaseWinding(angle, maxWinding, | 948 (void) segment->markAndChaseWinding(angle, maxWinding, |
924 binary ? oMaxWinding : 0); | 949 binary ? oMaxWinding : 0); |
925 } | 950 } |
926 } | 951 } |
927 } while (++nextIndex != lastIndex); | 952 } while (++nextIndex != lastIndex); |
928 int minIndex = SkMin32(startIndex, endIndex); | 953 int minIndex = SkMin32(startIndex, endIndex); |
929 return windSum(minIndex); | 954 return windSum(minIndex); |
930 } | 955 } |
931 | 956 |
932 int SkOpSegment::crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hi
tT, | 957 int SkOpSegment::crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hi
tT, |
(...skipping 1301 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2234 *last = &fTs[end]; | 2259 *last = &fTs[end]; |
2235 return NULL; | 2260 return NULL; |
2236 } | 2261 } |
2237 const SkOpSpan& endSpan = fTs[end]; | 2262 const SkOpSpan& endSpan = fTs[end]; |
2238 SkOpSegment* other = endSpan.fOther; | 2263 SkOpSegment* other = endSpan.fOther; |
2239 *index = endSpan.fOtherIndex; | 2264 *index = endSpan.fOtherIndex; |
2240 SkASSERT(*index >= 0); | 2265 SkASSERT(*index >= 0); |
2241 int otherEnd = other->nextExactSpan(*index, step); | 2266 int otherEnd = other->nextExactSpan(*index, step); |
2242 SkASSERT(otherEnd >= 0); | 2267 SkASSERT(otherEnd >= 0); |
2243 *min = SkMin32(*index, otherEnd); | 2268 *min = SkMin32(*index, otherEnd); |
| 2269 if (other->fTs[*min].fTiny) { |
| 2270 *last = NULL; |
| 2271 return NULL; |
| 2272 } |
2244 return other; | 2273 return other; |
2245 } | 2274 } |
2246 | 2275 |
2247 // This has callers for two different situations: one establishes the end | 2276 // This has callers for two different situations: one establishes the end |
2248 // of the current span, and one establishes the beginning of the next span | 2277 // of the current span, and one establishes the beginning of the next span |
2249 // (thus the name). When this is looking for the end of the current span, | 2278 // (thus the name). When this is looking for the end of the current span, |
2250 // coincidence is found when the beginning Ts contain -step and the end | 2279 // coincidence is found when the beginning Ts contain -step and the end |
2251 // contains step. When it is looking for the beginning of the next, the | 2280 // contains step. When it is looking for the beginning of the next, the |
2252 // first Ts found can be ignored and the last Ts should contain -step. | 2281 // first Ts found can be ignored and the last Ts should contain -step. |
2253 // OPTIMIZATION: probably should split into two functions | 2282 // OPTIMIZATION: probably should split into two functions |
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2482 for (int index = 0; index < count; ++index) { | 2511 for (int index = 0; index < count; ++index) { |
2483 if (fTs[index].fT == t) { | 2512 if (fTs[index].fT == t) { |
2484 return fTs[index].fWindValue; | 2513 return fTs[index].fWindValue; |
2485 } | 2514 } |
2486 } | 2515 } |
2487 SkASSERT(0); | 2516 SkASSERT(0); |
2488 return 0; | 2517 return 0; |
2489 } | 2518 } |
2490 | 2519 |
2491 void SkOpSegment::zeroSpan(SkOpSpan* span) { | 2520 void SkOpSegment::zeroSpan(SkOpSpan* span) { |
2492 SkASSERT(span->fWindValue > 0 || span->fOppValue > 0); | 2521 SkASSERT(span->fWindValue > 0 || span->fOppValue != 0); |
2493 span->fWindValue = 0; | 2522 span->fWindValue = 0; |
2494 span->fOppValue = 0; | 2523 span->fOppValue = 0; |
2495 SkASSERT(!span->fDone); | 2524 SkASSERT(!span->fDone); |
2496 span->fDone = true; | 2525 span->fDone = true; |
2497 ++fDoneSpans; | 2526 ++fDoneSpans; |
2498 } | 2527 } |
2499 | 2528 |
2500 #if DEBUG_SWAP_TOP | 2529 #if DEBUG_SWAP_TOP |
2501 bool SkOpSegment::controlsContainedByEnds(int tStart, int tEnd) const { | 2530 bool SkOpSegment::controlsContainedByEnds(int tStart, int tEnd) const { |
2502 if (fVerb != SkPath::kCubic_Verb) { | 2531 if (fVerb != SkPath::kCubic_Verb) { |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2550 if (fOperand) { | 2579 if (fOperand) { |
2551 SkDebugf(" operand"); | 2580 SkDebugf(" operand"); |
2552 } | 2581 } |
2553 if (done()) { | 2582 if (done()) { |
2554 SkDebugf(" done"); | 2583 SkDebugf(" done"); |
2555 } | 2584 } |
2556 SkDebugf("\n"); | 2585 SkDebugf("\n"); |
2557 } | 2586 } |
2558 #endif | 2587 #endif |
2559 | 2588 |
2560 #if DEBUG_ACTIVE_SPANS | 2589 #if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY |
2561 void SkOpSegment::debugShowActiveSpans() const { | 2590 void SkOpSegment::debugShowActiveSpans() const { |
2562 if (done()) { | 2591 if (done()) { |
2563 return; | 2592 return; |
2564 } | 2593 } |
2565 #if DEBUG_ACTIVE_SPANS_SHORT_FORM | 2594 #if DEBUG_ACTIVE_SPANS_SHORT_FORM |
2566 int lastId = -1; | 2595 int lastId = -1; |
2567 double lastT = -1; | 2596 double lastT = -1; |
2568 #endif | 2597 #endif |
2569 for (int i = 0; i < fTs.count(); ++i) { | 2598 for (int i = 0; i < fTs.count(); ++i) { |
2570 SkASSERT(&fTs[i] == &fTs[i].fOther->fTs[fTs[i].fOtherIndex].fOther-> | 2599 SkASSERT(&fTs[i] == &fTs[i].fOther->fTs[fTs[i].fOtherIndex].fOther-> |
2571 fTs[fTs[i].fOther->fTs[fTs[i].fOtherIndex].fOtherIndex]); | 2600 fTs[fTs[i].fOther->fTs[fTs[i].fOtherIndex].fOtherIndex]); |
2572 if (fTs[i].fDone) { | 2601 if (fTs[i].fDone) { |
2573 continue; | 2602 continue; |
2574 } | 2603 } |
| 2604 SkASSERT(i < fTs.count() - 1); |
2575 #if DEBUG_ACTIVE_SPANS_SHORT_FORM | 2605 #if DEBUG_ACTIVE_SPANS_SHORT_FORM |
2576 if (lastId == fID && lastT == fTs[i].fT) { | 2606 if (lastId == fID && lastT == fTs[i].fT) { |
2577 continue; | 2607 continue; |
2578 } | 2608 } |
2579 lastId = fID; | 2609 lastId = fID; |
2580 lastT = fTs[i].fT; | 2610 lastT = fTs[i].fT; |
2581 #endif | 2611 #endif |
2582 SkDebugf("%s id=%d", __FUNCTION__, fID); | 2612 SkDebugf("%s id=%d", __FUNCTION__, fID); |
2583 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY); | 2613 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY); |
2584 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) { | 2614 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) { |
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2790 sum += fTs[i].fWindValue; | 2820 sum += fTs[i].fWindValue; |
2791 slots[fTs[i].fOther->fID - 1] = as_digit(fTs[i].fWindValue); | 2821 slots[fTs[i].fOther->fID - 1] = as_digit(fTs[i].fWindValue); |
2792 sum += fTs[i].fOppValue; | 2822 sum += fTs[i].fOppValue; |
2793 slots[slotCount + fTs[i].fOther->fID - 1] = as_digit(fTs[i].fOppValue); | 2823 slots[slotCount + fTs[i].fOther->fID - 1] = as_digit(fTs[i].fOppValue); |
2794 } | 2824 } |
2795 SkDebugf("%s id=%2d %.*s | %.*s\n", __FUNCTION__, fID, slotCount, slots.begi
n(), slotCount, | 2825 SkDebugf("%s id=%2d %.*s | %.*s\n", __FUNCTION__, fID, slotCount, slots.begi
n(), slotCount, |
2796 slots.begin() + slotCount); | 2826 slots.begin() + slotCount); |
2797 return sum; | 2827 return sum; |
2798 } | 2828 } |
2799 #endif | 2829 #endif |
OLD | NEW |