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 399 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
410 int SkOpSegment::addT(SkOpSegment* other, const SkPoint& pt, double newT, bool i
sNear) { | 410 int SkOpSegment::addT(SkOpSegment* other, const SkPoint& pt, double newT, bool i
sNear) { |
411 if (precisely_zero(newT)) { | 411 if (precisely_zero(newT)) { |
412 newT = 0; | 412 newT = 0; |
413 } else if (precisely_equal(newT, 1)) { | 413 } else if (precisely_equal(newT, 1)) { |
414 newT = 1; | 414 newT = 1; |
415 } | 415 } |
416 // FIXME: in the pathological case where there is a ton of intercepts, | 416 // FIXME: in the pathological case where there is a ton of intercepts, |
417 // binary search? | 417 // binary search? |
418 int insertedAt = -1; | 418 int insertedAt = -1; |
419 size_t tCount = fTs.count(); | 419 size_t tCount = fTs.count(); |
| 420 const SkPoint& firstPt = fPts[0]; |
| 421 const SkPoint& lastPt = fPts[SkPathOpsVerbToPoints(fVerb)]; |
420 for (size_t index = 0; index < tCount; ++index) { | 422 for (size_t index = 0; index < tCount; ++index) { |
421 // OPTIMIZATION: if there are three or more identical Ts, then | 423 // OPTIMIZATION: if there are three or more identical Ts, then |
422 // the fourth and following could be further insertion-sorted so | 424 // the fourth and following could be further insertion-sorted so |
423 // that all the edges are clockwise or counterclockwise. | 425 // that all the edges are clockwise or counterclockwise. |
424 // This could later limit segment tests to the two adjacent | 426 // This could later limit segment tests to the two adjacent |
425 // neighbors, although it doesn't help with determining which | 427 // neighbors, although it doesn't help with determining which |
426 // circular direction to go in. | 428 // circular direction to go in. |
427 if (newT < fTs[index].fT) { | 429 const SkOpSpan& span = fTs[index]; |
| 430 if (newT < span.fT) { |
428 insertedAt = index; | 431 insertedAt = index; |
429 break; | 432 break; |
430 } | 433 } |
| 434 if (newT == span.fT) { |
| 435 if (pt == span.fPt) { |
| 436 insertedAt = index; |
| 437 break; |
| 438 } |
| 439 if ((pt == firstPt && newT == 0) || (span.fPt == lastPt && newT == 1
)) { |
| 440 insertedAt = index; |
| 441 break; |
| 442 } |
| 443 } |
431 } | 444 } |
432 SkOpSpan* span; | 445 SkOpSpan* span; |
433 if (insertedAt >= 0) { | 446 if (insertedAt >= 0) { |
434 span = fTs.insert(insertedAt); | 447 span = fTs.insert(insertedAt); |
435 } else { | 448 } else { |
436 insertedAt = tCount; | 449 insertedAt = tCount; |
437 span = fTs.append(); | 450 span = fTs.append(); |
438 } | 451 } |
439 span->fT = newT; | 452 span->fT = newT; |
440 span->fOther = other; | 453 span->fOther = other; |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
495 ++fDoneSpans; | 508 ++fDoneSpans; |
496 --less; | 509 --less; |
497 } | 510 } |
498 int more = 1; | 511 int more = 1; |
499 while (fTs.end() - &span[more - 1] > 1 && AlmostEqualUlps(span[more].fPt, sp
an->fPt)) { | 512 while (fTs.end() - &span[more - 1] > 1 && AlmostEqualUlps(span[more].fPt, sp
an->fPt)) { |
500 if (span[more - 1].fDone) { | 513 if (span[more - 1].fDone) { |
501 break; | 514 break; |
502 } | 515 } |
503 double tEndInterval = span[more].fT - newT; | 516 double tEndInterval = span[more].fT - newT; |
504 if (precisely_negative(tEndInterval)) { | 517 if (precisely_negative(tEndInterval)) { |
| 518 if ((span->fTiny = span[more].fTiny)) { |
| 519 span->fDone = true; |
| 520 ++fDoneSpans; |
| 521 } |
505 break; | 522 break; |
506 } | 523 } |
507 if (fVerb == SkPath::kCubic_Verb) { | 524 if (fVerb == SkPath::kCubic_Verb) { |
508 double tMid = newT - tEndInterval / 2; | 525 double tMid = newT - tEndInterval / 2; |
509 SkDPoint midEndPt = dcubic_xy_at_t(fPts, tMid); | 526 SkDPoint midEndPt = dcubic_xy_at_t(fPts, tMid); |
510 if (!midEndPt.approximatelyEqual(xyAtT(span))) { | 527 if (!midEndPt.approximatelyEqual(xyAtT(span))) { |
511 break; | 528 break; |
512 } | 529 } |
513 } | 530 } |
514 span[more - 1].fSmall = true; | 531 span[more - 1].fSmall = true; |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
549 ^ ^ <--| <--| | 566 ^ ^ <--| <--| |
550 startPt endPt test/oTest first pos test/oTest final po
s | 567 startPt endPt test/oTest first pos test/oTest final po
s |
551 */ | 568 */ |
552 void SkOpSegment::addTCancel(const SkPoint& startPt, const SkPoint& endPt, SkOpS
egment* other) { | 569 void SkOpSegment::addTCancel(const SkPoint& startPt, const SkPoint& endPt, SkOpS
egment* other) { |
553 bool binary = fOperand != other->fOperand; | 570 bool binary = fOperand != other->fOperand; |
554 int index = 0; | 571 int index = 0; |
555 while (startPt != fTs[index].fPt) { | 572 while (startPt != fTs[index].fPt) { |
556 SkASSERT(index < fTs.count()); | 573 SkASSERT(index < fTs.count()); |
557 ++index; | 574 ++index; |
558 } | 575 } |
| 576 while (index > 0 && fTs[index].fT == fTs[index - 1].fT) { |
| 577 --index; |
| 578 } |
559 int oIndex = other->fTs.count(); | 579 int oIndex = other->fTs.count(); |
560 while (startPt != other->fTs[--oIndex].fPt) { // look for startPt match | 580 while (startPt != other->fTs[--oIndex].fPt) { // look for startPt match |
561 SkASSERT(oIndex > 0); | 581 SkASSERT(oIndex > 0); |
562 } | 582 } |
563 while (startPt == other->fTs[--oIndex].fPt) { // look for first point beyon
d match | 583 double oStartT = other->fTs[oIndex].fT; |
| 584 // look for first point beyond match |
| 585 while (startPt == other->fTs[--oIndex].fPt || oStartT == other->fTs[oIndex].
fT) { |
564 SkASSERT(oIndex > 0); | 586 SkASSERT(oIndex > 0); |
565 } | 587 } |
566 SkOpSpan* test = &fTs[index]; | 588 SkOpSpan* test = &fTs[index]; |
567 SkOpSpan* oTest = &other->fTs[oIndex]; | 589 SkOpSpan* oTest = &other->fTs[oIndex]; |
568 SkSTArray<kOutsideTrackedTCount, SkPoint, true> outsidePts; | 590 SkSTArray<kOutsideTrackedTCount, SkPoint, true> outsidePts; |
569 SkSTArray<kOutsideTrackedTCount, SkPoint, true> oOutsidePts; | 591 SkSTArray<kOutsideTrackedTCount, SkPoint, true> oOutsidePts; |
570 do { | 592 do { |
571 SkASSERT(test->fT < 1); | 593 SkASSERT(test->fT < 1); |
572 SkASSERT(oTest->fT < 1); | 594 SkASSERT(oTest->fT < 1); |
573 bool decrement = test->fWindValue && oTest->fWindValue; | 595 bool decrement = test->fWindValue && oTest->fWindValue; |
574 bool track = test->fWindValue || oTest->fWindValue; | 596 bool track = test->fWindValue || oTest->fWindValue; |
575 bool bigger = test->fWindValue >= oTest->fWindValue; | 597 bool bigger = test->fWindValue >= oTest->fWindValue; |
576 const SkPoint& testPt = test->fPt; | 598 const SkPoint& testPt = test->fPt; |
| 599 double testT = test->fT; |
577 const SkPoint& oTestPt = oTest->fPt; | 600 const SkPoint& oTestPt = oTest->fPt; |
| 601 double oTestT = oTest->fT; |
578 do { | 602 do { |
579 if (decrement) { | 603 if (decrement) { |
580 if (binary && bigger) { | 604 if (binary && bigger) { |
581 test->fOppValue--; | 605 test->fOppValue--; |
582 } else { | 606 } else { |
583 decrementSpan(test); | 607 decrementSpan(test); |
584 } | 608 } |
585 } else if (track) { | 609 } else if (track) { |
586 TrackOutsidePair(&outsidePts, testPt, oTestPt); | 610 TrackOutsidePair(&outsidePts, testPt, oTestPt); |
587 } | 611 } |
588 SkASSERT(index < fTs.count() - 1); | 612 SkASSERT(index < fTs.count() - 1); |
589 test = &fTs[++index]; | 613 test = &fTs[++index]; |
590 } while (testPt == test->fPt); | 614 } while (testPt == test->fPt || testT == test->fT); |
591 SkDEBUGCODE(int originalWindValue = oTest->fWindValue); | 615 SkDEBUGCODE(int originalWindValue = oTest->fWindValue); |
592 do { | 616 do { |
593 SkASSERT(oTest->fT < 1); | 617 SkASSERT(oTest->fT < 1); |
594 SkASSERT(originalWindValue == oTest->fWindValue); | 618 SkASSERT(originalWindValue == oTest->fWindValue); |
595 if (decrement) { | 619 if (decrement) { |
596 if (binary && !bigger) { | 620 if (binary && !bigger) { |
597 oTest->fOppValue--; | 621 oTest->fOppValue--; |
598 } else { | 622 } else { |
599 other->decrementSpan(oTest); | 623 other->decrementSpan(oTest); |
600 } | 624 } |
601 } else if (track) { | 625 } else if (track) { |
602 TrackOutsidePair(&oOutsidePts, oTestPt, testPt); | 626 TrackOutsidePair(&oOutsidePts, oTestPt, testPt); |
603 } | 627 } |
604 if (!oIndex) { | 628 if (!oIndex) { |
605 break; | 629 break; |
606 } | 630 } |
607 oTest = &other->fTs[--oIndex]; | 631 oTest = &other->fTs[--oIndex]; |
608 } while (oTestPt == oTest->fPt); | 632 } while (oTestPt == oTest->fPt || oTestT == oTest->fT); |
609 SkASSERT(endPt != test->fPt || oTestPt == endPt); | 633 } while (endPt != test->fPt && test->fT < 1); |
610 } while (endPt != test->fPt); | |
611 // FIXME: determine if canceled edges need outside ts added | 634 // FIXME: determine if canceled edges need outside ts added |
612 int outCount = outsidePts.count(); | 635 int outCount = outsidePts.count(); |
613 if (!done() && outCount) { | 636 if (!done() && outCount) { |
614 addCancelOutsides(outsidePts[0], outsidePts[1], other); | 637 addCancelOutsides(outsidePts[0], outsidePts[1], other); |
615 if (outCount > 2) { | 638 if (outCount > 2) { |
616 addCancelOutsides(outsidePts[outCount - 2], outsidePts[outCount - 1]
, other); | 639 addCancelOutsides(outsidePts[outCount - 2], outsidePts[outCount - 1]
, other); |
617 } | 640 } |
618 } | 641 } |
619 if (!other->done() && oOutsidePts.count()) { | 642 if (!other->done() && oOutsidePts.count()) { |
620 other->addCancelOutsides(oOutsidePts[0], oOutsidePts[1], this); | 643 other->addCancelOutsides(oOutsidePts[0], oOutsidePts[1], this); |
(...skipping 17 matching lines...) Expand all Loading... |
638 SkTSwap<int>(oWindValue, oOppValue); | 661 SkTSwap<int>(oWindValue, oOppValue); |
639 } | 662 } |
640 SkOpSpan* const test = &fTs[index]; | 663 SkOpSpan* const test = &fTs[index]; |
641 SkOpSpan* end = test; | 664 SkOpSpan* end = test; |
642 const SkPoint& oStartPt = oTest.fPt; | 665 const SkPoint& oStartPt = oTest.fPt; |
643 do { | 666 do { |
644 if (bumpSpan(end, oWindValue, oOppValue)) { | 667 if (bumpSpan(end, oWindValue, oOppValue)) { |
645 TrackOutside(outsideTs, oStartPt); | 668 TrackOutside(outsideTs, oStartPt); |
646 } | 669 } |
647 end = &fTs[++index]; | 670 end = &fTs[++index]; |
648 } while (end->fPt == test->fPt); | 671 } while ((end->fPt == test->fPt || end->fT == test->fT) && end->fT < 1); |
649 *indexPtr = index; | 672 *indexPtr = index; |
650 } | 673 } |
651 | 674 |
652 bool SkOpSegment::bumpCoincident(SkOpSpan* test, bool bigger, bool binary) { | 675 bool SkOpSegment::bumpCoincident(SkOpSpan* test, bool bigger, bool binary) { |
653 if (bigger) { | 676 if (bigger) { |
654 if (binary) { | 677 if (binary) { |
655 if (fOppXor) { | 678 if (fOppXor) { |
656 test->fOppValue ^= 1; | 679 test->fOppValue ^= 1; |
657 } else { | 680 } else { |
658 test->fOppValue++; | 681 test->fOppValue++; |
(...skipping 19 matching lines...) Expand all Loading... |
678 // may not have the same intermediate points. Compute the corresponding | 701 // may not have the same intermediate points. Compute the corresponding |
679 // intermediate T values (using this as the master, other as the follower) | 702 // intermediate T values (using this as the master, other as the follower) |
680 // and walk other conditionally -- hoping that it catches up in the end | 703 // and walk other conditionally -- hoping that it catches up in the end |
681 void SkOpSegment::bumpCoincidentOther(const SkOpSpan& test, int* oIndexPtr, | 704 void SkOpSegment::bumpCoincidentOther(const SkOpSpan& test, int* oIndexPtr, |
682 SkTArray<SkPoint, true>* oOutsidePts) { | 705 SkTArray<SkPoint, true>* oOutsidePts) { |
683 int oIndex = *oIndexPtr; | 706 int oIndex = *oIndexPtr; |
684 SkOpSpan* const oTest = &fTs[oIndex]; | 707 SkOpSpan* const oTest = &fTs[oIndex]; |
685 SkOpSpan* oEnd = oTest; | 708 SkOpSpan* oEnd = oTest; |
686 const SkPoint& startPt = test.fPt; | 709 const SkPoint& startPt = test.fPt; |
687 const SkPoint& oStartPt = oTest->fPt; | 710 const SkPoint& oStartPt = oTest->fPt; |
688 if (oStartPt == oEnd->fPt) { | 711 double oStartT = oTest->fT; |
| 712 if (oStartPt == oEnd->fPt || oStartT == oEnd->fT) { |
689 TrackOutside(oOutsidePts, startPt); | 713 TrackOutside(oOutsidePts, startPt); |
690 } | 714 } |
691 while (oStartPt == oEnd->fPt) { | 715 while (oStartPt == oEnd->fPt || oStartT == oEnd->fT) { |
692 zeroSpan(oEnd); | 716 zeroSpan(oEnd); |
693 oEnd = &fTs[++oIndex]; | 717 oEnd = &fTs[++oIndex]; |
694 } | 718 } |
695 *oIndexPtr = oIndex; | 719 *oIndexPtr = oIndex; |
696 } | 720 } |
697 | 721 |
698 // FIXME: need to test this case: | 722 // FIXME: need to test this case: |
699 // contourA has two segments that are coincident | 723 // contourA has two segments that are coincident |
700 // contourB has two segments that are coincident in the same place | 724 // contourB has two segments that are coincident in the same place |
701 // each ends up with +2/0 pairs for winding count | 725 // each ends up with +2/0 pairs for winding count |
702 // since logic below doesn't transfer count (only increments/decrements) can thi
s be | 726 // since logic below doesn't transfer count (only increments/decrements) can thi
s be |
703 // resolved to +4/0 ? | 727 // resolved to +4/0 ? |
704 | 728 |
705 // set spans from start to end to increment the greater by one and decrement | 729 // set spans from start to end to increment the greater by one and decrement |
706 // the lesser | 730 // the lesser |
707 void SkOpSegment::addTCoincident(const SkPoint& startPt, const SkPoint& endPt, | 731 void SkOpSegment::addTCoincident(const SkPoint& startPt, const SkPoint& endPt, d
ouble endT, |
708 SkOpSegment* other) { | 732 SkOpSegment* other) { |
709 bool binary = fOperand != other->fOperand; | 733 bool binary = fOperand != other->fOperand; |
710 int index = 0; | 734 int index = 0; |
711 while (startPt != fTs[index].fPt) { | 735 while (startPt != fTs[index].fPt) { |
712 SkASSERT(index < fTs.count()); | 736 SkASSERT(index < fTs.count()); |
713 ++index; | 737 ++index; |
714 } | 738 } |
| 739 double startT = fTs[index].fT; |
| 740 while (index > 0 && fTs[index - 1].fT == startT) { |
| 741 --index; |
| 742 } |
715 int oIndex = 0; | 743 int oIndex = 0; |
716 while (startPt != other->fTs[oIndex].fPt) { | 744 while (startPt != other->fTs[oIndex].fPt) { |
717 SkASSERT(oIndex < other->fTs.count()); | 745 SkASSERT(oIndex < other->fTs.count()); |
718 ++oIndex; | 746 ++oIndex; |
719 } | 747 } |
| 748 double oStartT = other->fTs[oIndex].fT; |
| 749 while (oIndex > 0 && other->fTs[oIndex - 1].fT == oStartT) { |
| 750 --oIndex; |
| 751 } |
720 SkSTArray<kOutsideTrackedTCount, SkPoint, true> outsidePts; | 752 SkSTArray<kOutsideTrackedTCount, SkPoint, true> outsidePts; |
721 SkSTArray<kOutsideTrackedTCount, SkPoint, true> oOutsidePts; | 753 SkSTArray<kOutsideTrackedTCount, SkPoint, true> oOutsidePts; |
722 SkOpSpan* test = &fTs[index]; | 754 SkOpSpan* test = &fTs[index]; |
723 const SkPoint* testPt = &test->fPt; | 755 const SkPoint* testPt = &test->fPt; |
| 756 double testT = test->fT; |
724 SkOpSpan* oTest = &other->fTs[oIndex]; | 757 SkOpSpan* oTest = &other->fTs[oIndex]; |
725 const SkPoint* oTestPt = &oTest->fPt; | 758 const SkPoint* oTestPt = &oTest->fPt; |
726 SkASSERT(AlmostEqualUlps(*testPt, *oTestPt)); | 759 SkASSERT(AlmostEqualUlps(*testPt, *oTestPt)); |
727 do { | 760 do { |
728 SkASSERT(test->fT < 1); | 761 SkASSERT(test->fT < 1); |
729 SkASSERT(oTest->fT < 1); | 762 SkASSERT(oTest->fT < 1); |
730 #if 0 | 763 #if 0 |
731 if (test->fDone || oTest->fDone) { | 764 if (test->fDone || oTest->fDone) { |
732 #else // consolidate the winding count even if done | 765 #else // consolidate the winding count even if done |
733 if ((test->fWindValue == 0 && test->fOppValue == 0) | 766 if ((test->fWindValue == 0 && test->fOppValue == 0) |
(...skipping 19 matching lines...) Expand all Loading... |
753 if (!binary || test->fWindValue + oTest->fOppValue >= 0) { | 786 if (!binary || test->fWindValue + oTest->fOppValue >= 0) { |
754 bumpCoincidentThis(*oTest, binary, &index, &outsidePts); | 787 bumpCoincidentThis(*oTest, binary, &index, &outsidePts); |
755 other->bumpCoincidentOther(*test, &oIndex, &oOutsidePts); | 788 other->bumpCoincidentOther(*test, &oIndex, &oOutsidePts); |
756 } else { | 789 } else { |
757 other->bumpCoincidentThis(*test, binary, &oIndex, &oOutsidePts); | 790 other->bumpCoincidentThis(*test, binary, &oIndex, &oOutsidePts); |
758 bumpCoincidentOther(*oTest, &index, &outsidePts); | 791 bumpCoincidentOther(*oTest, &index, &outsidePts); |
759 } | 792 } |
760 } | 793 } |
761 test = &fTs[index]; | 794 test = &fTs[index]; |
762 testPt = &test->fPt; | 795 testPt = &test->fPt; |
763 if (endPt == *testPt) { | 796 testT = test->fT; |
| 797 if (endPt == *testPt || endT == testT) { |
764 break; | 798 break; |
765 } | 799 } |
766 oTest = &other->fTs[oIndex]; | 800 oTest = &other->fTs[oIndex]; |
767 oTestPt = &oTest->fPt; | 801 oTestPt = &oTest->fPt; |
768 SkASSERT(AlmostEqualUlps(*testPt, *oTestPt)); | 802 SkASSERT(AlmostEqualUlps(*testPt, *oTestPt)); |
769 } while (endPt != *oTestPt); | 803 } while (endPt != *oTestPt); |
| 804 if (endPt != *testPt && endT != testT) { // in rare cases, one may have end
ed before the other |
| 805 int lastWind = test[-1].fWindValue; |
| 806 int lastOpp = test[-1].fOppValue; |
| 807 bool zero = lastWind == 0 && lastOpp == 0; |
| 808 do { |
| 809 if (test->fWindValue || test->fOppValue) { |
| 810 test->fWindValue = lastWind; |
| 811 test->fOppValue = lastOpp; |
| 812 if (zero) { |
| 813 test->fDone = true; |
| 814 ++fDoneSpans; |
| 815 } |
| 816 } |
| 817 test = &fTs[++index]; |
| 818 testPt = &test->fPt; |
| 819 } while (endPt != *testPt); |
| 820 } |
770 int outCount = outsidePts.count(); | 821 int outCount = outsidePts.count(); |
771 if (!done() && outCount) { | 822 if (!done() && outCount) { |
772 addCoinOutsides(outsidePts[0], endPt, other); | 823 addCoinOutsides(outsidePts[0], endPt, other); |
773 } | 824 } |
774 if (!other->done() && oOutsidePts.count()) { | 825 if (!other->done() && oOutsidePts.count()) { |
775 other->addCoinOutsides(oOutsidePts[0], endPt, this); | 826 other->addCoinOutsides(oOutsidePts[0], endPt, this); |
776 } | 827 } |
777 } | 828 } |
778 | 829 |
779 // FIXME: this doesn't prevent the same span from being added twice | 830 // FIXME: this doesn't prevent the same span from being added twice |
(...skipping 538 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1318 if (!span->fOppValue && !span->fDone) { | 1369 if (!span->fOppValue && !span->fDone) { |
1319 span->fDone = true; | 1370 span->fDone = true; |
1320 ++fDoneSpans; | 1371 ++fDoneSpans; |
1321 return true; | 1372 return true; |
1322 } | 1373 } |
1323 } | 1374 } |
1324 return false; | 1375 return false; |
1325 } | 1376 } |
1326 | 1377 |
1327 bool SkOpSegment::bumpSpan(SkOpSpan* span, int windDelta, int oppDelta) { | 1378 bool SkOpSegment::bumpSpan(SkOpSpan* span, int windDelta, int oppDelta) { |
1328 SkASSERT(!span->fDone || span->fTiny); | 1379 SkASSERT(!span->fDone || span->fTiny || span->fSmall); |
1329 span->fWindValue += windDelta; | 1380 span->fWindValue += windDelta; |
1330 SkASSERT(span->fWindValue >= 0); | 1381 SkASSERT(span->fWindValue >= 0); |
1331 span->fOppValue += oppDelta; | 1382 span->fOppValue += oppDelta; |
1332 SkASSERT(span->fOppValue >= 0); | 1383 SkASSERT(span->fOppValue >= 0); |
1333 if (fXor) { | 1384 if (fXor) { |
1334 span->fWindValue &= 1; | 1385 span->fWindValue &= 1; |
1335 } | 1386 } |
1336 if (fOppXor) { | 1387 if (fOppXor) { |
1337 span->fOppValue &= 1; | 1388 span->fOppValue &= 1; |
1338 } | 1389 } |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1377 ++tLast; | 1428 ++tLast; |
1378 } | 1429 } |
1379 while (++tLast < count && t == fTs[tLast].fT) | 1430 while (++tLast < count && t == fTs[tLast].fT) |
1380 ; | 1431 ; |
1381 for (int peekIndex = peekStart; peekIndex <= peekLast; ++peekIndex) { | 1432 for (int peekIndex = peekStart; peekIndex <= peekLast; ++peekIndex) { |
1382 if (peekIndex == span.fOtherIndex) { // skip the other span pointed
to by this span | 1433 if (peekIndex == span.fOtherIndex) { // skip the other span pointed
to by this span |
1383 continue; | 1434 continue; |
1384 } | 1435 } |
1385 const SkOpSpan& peekSpan = other->fTs[peekIndex]; | 1436 const SkOpSpan& peekSpan = other->fTs[peekIndex]; |
1386 SkOpSegment* match = peekSpan.fOther; | 1437 SkOpSegment* match = peekSpan.fOther; |
| 1438 if (match->done()) { |
| 1439 continue; // if the edge has already been eaten (likely coincid
ence), ignore it |
| 1440 } |
1387 const double matchT = peekSpan.fOtherT; | 1441 const double matchT = peekSpan.fOtherT; |
1388 // see if any of the spans match the other spans | 1442 // see if any of the spans match the other spans |
1389 for (int tIndex = tStart + 1; tIndex < tLast; ++tIndex) { | 1443 for (int tIndex = tStart + 1; tIndex < tLast; ++tIndex) { |
1390 const SkOpSpan& tSpan = fTs[tIndex]; | 1444 const SkOpSpan& tSpan = fTs[tIndex]; |
1391 if (tSpan.fOther == match) { | 1445 if (tSpan.fOther == match) { |
1392 if (tSpan.fOtherT == matchT) { | 1446 if (tSpan.fOtherT == matchT) { |
1393 goto nextPeeker; | 1447 goto nextPeekIndex; |
1394 } | 1448 } |
1395 double midT = (tSpan.fOtherT + matchT) / 2; | 1449 double midT = (tSpan.fOtherT + matchT) / 2; |
1396 if (match->betweenPoints(midT, tSpan.fPt, peekSpan.fPt)) { | 1450 if (match->betweenPoints(midT, tSpan.fPt, peekSpan.fPt)) { |
1397 goto nextPeeker; | 1451 goto nextPeekIndex; |
1398 } | 1452 } |
1399 } | 1453 } |
1400 } | 1454 } |
1401 if (missingSpans.count() > 0) { | 1455 if (missingSpans.count() > 0) { |
1402 const MissingSpan& lastMissing = missingSpans.back(); | 1456 const MissingSpan& lastMissing = missingSpans.back(); |
1403 if (lastMissing.fCommand == MissingSpan::kAddMissing | 1457 if (lastMissing.fCommand == MissingSpan::kAddMissing |
1404 && lastMissing.fT == t | 1458 && lastMissing.fT == t |
1405 && lastMissing.fOther == match | 1459 && lastMissing.fOther == match |
1406 && lastMissing.fOtherT == matchT) { | 1460 && lastMissing.fOtherT == matchT) { |
1407 SkASSERT(lastMissing.fPt == peekSpan.fPt); | 1461 SkASSERT(lastMissing.fPt == peekSpan.fPt); |
1408 continue; | 1462 continue; |
1409 } | 1463 } |
1410 } | 1464 } |
1411 #if DEBUG_CHECK_ENDS | 1465 #if DEBUG_CHECK_ENDS |
1412 SkDebugf("%s id=%d missing t=%1.9g other=%d otherT=%1.9g pt=(%1.9g,%
1.9g)\n", | 1466 SkDebugf("%s id=%d missing t=%1.9g other=%d otherT=%1.9g pt=(%1.9g,%
1.9g)\n", |
1413 __FUNCTION__, fID, t, match->fID, matchT, peekSpan.fPt.fX, p
eekSpan.fPt.fY); | 1467 __FUNCTION__, fID, t, match->fID, matchT, peekSpan.fPt.fX, p
eekSpan.fPt.fY); |
1414 #endif | 1468 #endif |
1415 // this segment is missing a entry that the other contains | 1469 // this segment is missing a entry that the other contains |
1416 // remember so we can add the missing one and recompute the indices | 1470 // remember so we can add the missing one and recompute the indices |
1417 MissingSpan& missing = missingSpans.push_back(); | 1471 { |
1418 SkDEBUGCODE(sk_bzero(&missing, sizeof(missing))); | 1472 MissingSpan& missing = missingSpans.push_back(); |
1419 missing.fCommand = MissingSpan::kAddMissing; | 1473 SkDEBUGCODE(sk_bzero(&missing, sizeof(missing))); |
1420 missing.fT = t; | 1474 missing.fCommand = MissingSpan::kAddMissing; |
1421 missing.fOther = match; | 1475 missing.fT = t; |
1422 missing.fOtherT = matchT; | 1476 missing.fOther = match; |
1423 missing.fPt = peekSpan.fPt; | 1477 missing.fOtherT = matchT; |
| 1478 missing.fPt = peekSpan.fPt; |
| 1479 } |
| 1480 break; |
| 1481 nextPeekIndex: |
| 1482 ; |
1424 } | 1483 } |
1425 nextPeeker: | |
1426 ; | |
1427 } | 1484 } |
1428 if (missingSpans.count() == 0) { | 1485 if (missingSpans.count() == 0) { |
| 1486 debugValidate(); |
1429 return; | 1487 return; |
1430 } | 1488 } |
1431 // if one end is near the other point, look for a coincident span | 1489 // if one end is near the other point, look for a coincident span |
1432 for (int index = 0; index < count; ++index) { | 1490 for (int index = 0; index < count; ++index) { |
1433 const SkOpSpan& span = fTs[index]; | 1491 const SkOpSpan& span = fTs[index]; |
1434 if (span.fT > 0) { | 1492 if (span.fT > 0) { |
1435 break; | 1493 break; |
1436 } | 1494 } |
1437 const SkOpSpan& otherSpan = span.fOther->span(span.fOtherIndex); | 1495 const SkOpSpan& otherSpan = span.fOther->span(span.fOtherIndex); |
1438 if (span.fNear) { | 1496 if (span.fNear) { |
(...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1683 } | 1741 } |
1684 return other; | 1742 return other; |
1685 } | 1743 } |
1686 // more than one viable candidate -- measure angles to find best | 1744 // more than one viable candidate -- measure angles to find best |
1687 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles; | 1745 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle, true> angles; |
1688 SkASSERT(startIndex - endIndex != 0); | 1746 SkASSERT(startIndex - endIndex != 0); |
1689 SkASSERT((startIndex - endIndex < 0) ^ (step < 0)); | 1747 SkASSERT((startIndex - endIndex < 0) ^ (step < 0)); |
1690 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted; | 1748 SkSTArray<SkOpAngle::kStackBasedCount, SkOpAngle*, true> sorted; |
1691 int calcWinding = computeSum(startIndex, end, SkOpAngle::kBinaryOpp, &angles
, &sorted); | 1749 int calcWinding = computeSum(startIndex, end, SkOpAngle::kBinaryOpp, &angles
, &sorted); |
1692 bool sortable = calcWinding != SK_NaN32; | 1750 bool sortable = calcWinding != SK_NaN32; |
| 1751 if (sortable && sorted.count() == 0) { |
| 1752 // if no edge has a computed winding sum, we can go no further |
| 1753 *unsortable = true; |
| 1754 return NULL; |
| 1755 } |
1693 int angleCount = angles.count(); | 1756 int angleCount = angles.count(); |
1694 int firstIndex = findStartingEdge(sorted, startIndex, end); | 1757 int firstIndex = findStartingEdge(sorted, startIndex, end); |
1695 SkASSERT(!sortable || firstIndex >= 0); | 1758 SkASSERT(!sortable || firstIndex >= 0); |
1696 #if DEBUG_SORT | 1759 #if DEBUG_SORT |
1697 debugShowSort(__FUNCTION__, sorted, firstIndex, sortable); | 1760 debugShowSort(__FUNCTION__, sorted, firstIndex, sortable); |
1698 #endif | 1761 #endif |
1699 if (!sortable) { | 1762 if (!sortable) { |
1700 *unsortable = true; | 1763 *unsortable = true; |
1701 return NULL; | 1764 return NULL; |
1702 } | 1765 } |
(...skipping 494 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2197 int oppWindVal = oppValue(SkMin32(start, end)); | 2260 int oppWindVal = oppValue(SkMin32(start, end)); |
2198 if (!oppWind) { | 2261 if (!oppWind) { |
2199 oppWind = dx < 0 ? oppWindVal : -oppWindVal; | 2262 oppWind = dx < 0 ? oppWindVal : -oppWindVal; |
2200 } else if (hitOppDx * dx >= 0) { | 2263 } else if (hitOppDx * dx >= 0) { |
2201 int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal); | 2264 int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal); |
2202 if (abs(oppWind) < abs(oppSideWind)) { | 2265 if (abs(oppWind) < abs(oppSideWind)) { |
2203 oppWind = oppSideWind; | 2266 oppWind = oppSideWind; |
2204 } | 2267 } |
2205 } | 2268 } |
2206 (void) markAndChaseWinding(start, end, winding, oppWind); | 2269 (void) markAndChaseWinding(start, end, winding, oppWind); |
| 2270 // OPTIMIZATION: the reverse mark and chase could skip the first marking |
| 2271 (void) markAndChaseWinding(end, start, winding, oppWind); |
2207 } | 2272 } |
2208 | 2273 |
2209 // OPTIMIZE: successive calls could start were the last leaves off | 2274 // OPTIMIZE: successive calls could start were the last leaves off |
2210 // or calls could specialize to walk forwards or backwards | 2275 // or calls could specialize to walk forwards or backwards |
2211 bool SkOpSegment::isMissing(double startT) const { | 2276 bool SkOpSegment::isMissing(double startT, const SkPoint& pt) const { |
2212 size_t tCount = fTs.count(); | 2277 size_t tCount = fTs.count(); |
2213 for (size_t index = 0; index < tCount; ++index) { | 2278 for (size_t index = 0; index < tCount; ++index) { |
2214 if (approximately_zero(startT - fTs[index].fT)) { | 2279 const SkOpSpan& span = fTs[index]; |
| 2280 if (approximately_zero(startT - span.fT) && pt == span.fPt) { |
2215 return false; | 2281 return false; |
2216 } | 2282 } |
2217 } | 2283 } |
2218 return true; | 2284 return true; |
2219 } | 2285 } |
2220 | 2286 |
2221 bool SkOpSegment::isSimple(int end) const { | 2287 bool SkOpSegment::isSimple(int end) const { |
2222 int count = fTs.count(); | 2288 int count = fTs.count(); |
2223 if (count == 2) { | 2289 if (count == 2) { |
2224 return true; | 2290 return true; |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2345 maxWinding = sumWinding; | 2411 maxWinding = sumWinding; |
2346 } | 2412 } |
2347 SkOpSpan* last; | 2413 SkOpSpan* last; |
2348 if (activeAngle) { | 2414 if (activeAngle) { |
2349 last = markAndChaseWinding(angle, maxWinding); | 2415 last = markAndChaseWinding(angle, maxWinding); |
2350 } else { | 2416 } else { |
2351 last = markAndChaseDoneUnary(angle, maxWinding); | 2417 last = markAndChaseDoneUnary(angle, maxWinding); |
2352 } | 2418 } |
2353 #if DEBUG_WINDING | 2419 #if DEBUG_WINDING |
2354 if (last) { | 2420 if (last) { |
2355 SkDebugf("%s last id=%d windSum=%d small=%d\n", __FUNCTION__, | 2421 SkDebugf("%s last id=%d windSum=", __FUNCTION__, |
2356 last->fOther->fTs[last->fOtherIndex].fOther->debugID(), last->fW
indSum, | 2422 last->fOther->fTs[last->fOtherIndex].fOther->debugID()); |
2357 last->fSmall); | 2423 SkPathOpsDebug::WindingPrintf(last->fWindSum); |
| 2424 SkDebugf(" small=%d\n", last->fSmall); |
2358 } | 2425 } |
2359 #endif | 2426 #endif |
2360 return last; | 2427 return last; |
2361 } | 2428 } |
2362 | 2429 |
2363 SkOpSpan* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWindi
ng, | 2430 SkOpSpan* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWindi
ng, |
2364 int oppSumWinding, bool activeAngle, const SkOp
Angle* angle) { | 2431 int oppSumWinding, bool activeAngle, const SkOp
Angle* angle) { |
2365 SkASSERT(angle->segment() == this); | 2432 SkASSERT(angle->segment() == this); |
2366 if (UseInnerWinding(maxWinding, sumWinding)) { | 2433 if (UseInnerWinding(maxWinding, sumWinding)) { |
2367 maxWinding = sumWinding; | 2434 maxWinding = sumWinding; |
2368 } | 2435 } |
2369 if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumW
inding)) { | 2436 if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumW
inding)) { |
2370 oppMaxWinding = oppSumWinding; | 2437 oppMaxWinding = oppSumWinding; |
2371 } | 2438 } |
2372 SkOpSpan* last; | 2439 SkOpSpan* last; |
2373 if (activeAngle) { | 2440 if (activeAngle) { |
2374 last = markAndChaseWinding(angle, maxWinding, oppMaxWinding); | 2441 last = markAndChaseWinding(angle, maxWinding, oppMaxWinding); |
2375 } else { | 2442 } else { |
2376 last = markAndChaseDoneBinary(angle, maxWinding, oppMaxWinding); | 2443 last = markAndChaseDoneBinary(angle, maxWinding, oppMaxWinding); |
2377 } | 2444 } |
2378 #if DEBUG_WINDING | 2445 #if DEBUG_WINDING |
2379 if (last) { | 2446 if (last) { |
2380 SkDebugf("%s last id=%d windSum=%d small=%d\n", __FUNCTION__, | 2447 SkDebugf("%s last id=%d windSum=", __FUNCTION__, |
2381 last->fOther->fTs[last->fOtherIndex].fOther->debugID(), last->fW
indSum, | 2448 last->fOther->fTs[last->fOtherIndex].fOther->debugID()); |
2382 last->fSmall); | 2449 SkPathOpsDebug::WindingPrintf(last->fWindSum); |
| 2450 SkDebugf(" small=%d\n", last->fSmall); |
2383 } | 2451 } |
2384 #endif | 2452 #endif |
2385 return last; | 2453 return last; |
2386 } | 2454 } |
2387 | 2455 |
2388 // FIXME: this should also mark spans with equal (x,y) | 2456 // FIXME: this should also mark spans with equal (x,y) |
2389 // This may be called when the segment is already marked done. While this | 2457 // This may be called when the segment is already marked done. While this |
2390 // wastes time, it shouldn't do any more than spin through the T spans. | 2458 // wastes time, it shouldn't do any more than spin through the T spans. |
2391 // OPTIMIZATION: abort on first done found (assuming that this code is | 2459 // OPTIMIZATION: abort on first done found (assuming that this code is |
2392 // always called to mark segments done). | 2460 // always called to mark segments done). |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2484 #endif | 2552 #endif |
2485 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding); | 2553 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding); |
2486 SkASSERT(abs(winding) <= SkPathOpsDebug::gMaxWindSum); | 2554 SkASSERT(abs(winding) <= SkPathOpsDebug::gMaxWindSum); |
2487 span.fWindSum = winding; | 2555 span.fWindSum = winding; |
2488 return &span; | 2556 return &span; |
2489 } | 2557 } |
2490 | 2558 |
2491 SkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int windi
ng, | 2559 SkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int windi
ng, |
2492 int oppWinding) { | 2560 int oppWinding) { |
2493 SkOpSpan& span = fTs[tIndex]; | 2561 SkOpSpan& span = fTs[tIndex]; |
2494 if (span.fDone) { | 2562 if (span.fDone && !span.fSmall) { |
2495 return NULL; | 2563 return NULL; |
2496 } | 2564 } |
2497 #if DEBUG_MARK_DONE | 2565 #if DEBUG_MARK_DONE |
2498 debugShowNewWinding(funName, span, winding, oppWinding); | 2566 debugShowNewWinding(funName, span, winding, oppWinding); |
2499 #endif | 2567 #endif |
2500 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding); | 2568 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding); |
2501 SkASSERT(abs(winding) <= SkPathOpsDebug::gMaxWindSum); | 2569 SkASSERT(abs(winding) <= SkPathOpsDebug::gMaxWindSum); |
2502 span.fWindSum = winding; | 2570 span.fWindSum = winding; |
2503 SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding); | 2571 SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding); |
2504 SkASSERT(abs(oppWinding) <= SkPathOpsDebug::gMaxWindSum); | 2572 SkASSERT(abs(oppWinding) <= SkPathOpsDebug::gMaxWindSum); |
(...skipping 622 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3127 } | 3195 } |
3128 } | 3196 } |
3129 SkASSERT(0); | 3197 SkASSERT(0); |
3130 return 0; | 3198 return 0; |
3131 } | 3199 } |
3132 | 3200 |
3133 void SkOpSegment::zeroSpan(SkOpSpan* span) { | 3201 void SkOpSegment::zeroSpan(SkOpSpan* span) { |
3134 SkASSERT(span->fWindValue > 0 || span->fOppValue != 0); | 3202 SkASSERT(span->fWindValue > 0 || span->fOppValue != 0); |
3135 span->fWindValue = 0; | 3203 span->fWindValue = 0; |
3136 span->fOppValue = 0; | 3204 span->fOppValue = 0; |
| 3205 if (span->fTiny || span->fSmall) { |
| 3206 return; |
| 3207 } |
3137 SkASSERT(!span->fDone); | 3208 SkASSERT(!span->fDone); |
3138 span->fDone = true; | 3209 span->fDone = true; |
3139 ++fDoneSpans; | 3210 ++fDoneSpans; |
3140 } | 3211 } |
3141 | 3212 |
3142 #if DEBUG_SWAP_TOP | 3213 #if DEBUG_SWAP_TOP |
3143 bool SkOpSegment::controlsContainedByEnds(int tStart, int tEnd) const { | 3214 bool SkOpSegment::controlsContainedByEnds(int tStart, int tEnd) const { |
3144 if (fVerb != SkPath::kCubic_Verb) { | 3215 if (fVerb != SkPath::kCubic_Verb) { |
3145 return false; | 3216 return false; |
3146 } | 3217 } |
3147 SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT); | 3218 SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT); |
3148 return dst.controlsContainedByEnds(); | 3219 return dst.controlsContainedByEnds(); |
3149 } | 3220 } |
3150 #endif | 3221 #endif |
3151 | 3222 |
3152 #if DEBUG_CONCIDENT | 3223 #if DEBUG_CONCIDENT |
3153 // SkASSERT if pair has not already been added | 3224 // SkASSERT if pair has not already been added |
3154 void SkOpSegment::debugAddTPair(double t, const SkOpSegment& other, double other
T) const { | 3225 void SkOpSegment::debugAddTPair(double t, const SkOpSegment& other, double other
T) const { |
3155 for (int i = 0; i < fTs.count(); ++i) { | 3226 for (int i = 0; i < fTs.count(); ++i) { |
3156 if (fTs[i].fT == t && fTs[i].fOther == &other && fTs[i].fOtherT == other
T) { | 3227 if (fTs[i].fT == t && fTs[i].fOther == &other && fTs[i].fOtherT == other
T) { |
3157 return; | 3228 return; |
3158 } | 3229 } |
3159 } | 3230 } |
3160 SkASSERT(0); | 3231 SkASSERT(0); |
3161 } | 3232 } |
3162 #endif | 3233 #endif |
3163 | 3234 |
3164 #if DEBUG_CONCIDENT | 3235 #if DEBUG_CONCIDENT |
3165 void SkOpSegment::debugShowTs() const { | 3236 void SkOpSegment::debugShowTs(const char* prefix) const { |
3166 SkDebugf("%s id=%d", __FUNCTION__, fID); | 3237 SkDebugf("%s %s id=%d", __FUNCTION__, prefix, fID); |
3167 int lastWind = -1; | 3238 int lastWind = -1; |
3168 int lastOpp = -1; | 3239 int lastOpp = -1; |
3169 double lastT = -1; | 3240 double lastT = -1; |
3170 int i; | 3241 int i; |
3171 for (i = 0; i < fTs.count(); ++i) { | 3242 for (i = 0; i < fTs.count(); ++i) { |
3172 bool change = lastT != fTs[i].fT || lastWind != fTs[i].fWindValue | 3243 bool change = lastT != fTs[i].fT || lastWind != fTs[i].fWindValue |
3173 || lastOpp != fTs[i].fOppValue; | 3244 || lastOpp != fTs[i].fOppValue; |
3174 if (change && lastWind >= 0) { | 3245 if (change && lastWind >= 0) { |
3175 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]", | 3246 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]", |
3176 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp); | 3247 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp); |
(...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3510 | 3581 |
3511 void SkOpSegment::dumpSpans() const { | 3582 void SkOpSegment::dumpSpans() const { |
3512 int count = this->count(); | 3583 int count = this->count(); |
3513 for (int index = 0; index < count; ++index) { | 3584 for (int index = 0; index < count; ++index) { |
3514 const SkOpSpan& span = this->span(index); | 3585 const SkOpSpan& span = this->span(index); |
3515 SkDebugf("[%d] ", index); | 3586 SkDebugf("[%d] ", index); |
3516 span.dump(); | 3587 span.dump(); |
3517 } | 3588 } |
3518 } | 3589 } |
3519 #endif | 3590 #endif |
OLD | NEW |