| 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 "SkOpAngle.h" | 7 #include "SkOpAngle.h" |
| 8 #include "SkOpSegment.h" | 8 #include "SkOpSegment.h" |
| 9 #include "SkPathOpsCurve.h" | 9 #include "SkPathOpsCurve.h" |
| 10 #include "SkTSort.h" | 10 #include "SkTSort.h" |
| (...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 353 ? checkEnd->upCast()->next() : NULL | 353 ? checkEnd->upCast()->next() : NULL |
| 354 : checkEnd->prev(); | 354 : checkEnd->prev(); |
| 355 } while (checkEnd); | 355 } while (checkEnd); |
| 356 recomputeSector: | 356 recomputeSector: |
| 357 SkOpSpanBase* computedEnd = stepUp ? checkEnd ? checkEnd->prev() : fEnd->seg
ment()->head() | 357 SkOpSpanBase* computedEnd = stepUp ? checkEnd ? checkEnd->prev() : fEnd->seg
ment()->head() |
| 358 : checkEnd ? checkEnd->upCast()->next() : fEnd->segment()->tail(); | 358 : checkEnd ? checkEnd->upCast()->next() : fEnd->segment()->tail(); |
| 359 if (checkEnd == fEnd || computedEnd == fEnd || computedEnd == fStart) { | 359 if (checkEnd == fEnd || computedEnd == fEnd || computedEnd == fStart) { |
| 360 fUnorderable = true; | 360 fUnorderable = true; |
| 361 return false; | 361 return false; |
| 362 } | 362 } |
| 363 if (stepUp != (fStart->t() < computedEnd->t())) { |
| 364 fUnorderable = true; |
| 365 return false; |
| 366 } |
| 363 SkOpSpanBase* saveEnd = fEnd; | 367 SkOpSpanBase* saveEnd = fEnd; |
| 364 fComputedEnd = fEnd = computedEnd; | 368 fComputedEnd = fEnd = computedEnd; |
| 365 setSpans(); | 369 setSpans(); |
| 366 setSector(); | 370 setSector(); |
| 367 fEnd = saveEnd; | 371 fEnd = saveEnd; |
| 368 return !fUnorderable; | 372 return !fUnorderable; |
| 369 } | 373 } |
| 370 | 374 |
| 371 int SkOpAngle::convexHullOverlaps(const SkOpAngle* rh) const { | 375 int SkOpAngle::convexHullOverlaps(const SkOpAngle* rh) const { |
| 372 const SkDVector* sweep = this->fSweep; | 376 const SkDVector* sweep = this->fSweep; |
| (...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 590 SkDVector vLeft = *endPt - start; | 594 SkDVector vLeft = *endPt - start; |
| 591 SkDVector vRight = oppPt - start; | 595 SkDVector vRight = oppPt - start; |
| 592 double dir = vLeft.crossCheck(vRight); | 596 double dir = vLeft.crossCheck(vRight); |
| 593 if (!dir) { | 597 if (!dir) { |
| 594 return false; | 598 return false; |
| 595 } | 599 } |
| 596 *inside = dir < 0; | 600 *inside = dir < 0; |
| 597 return true; | 601 return true; |
| 598 } | 602 } |
| 599 | 603 |
| 600 // Most of the time, the first one can be found trivially by detecting the small
est sector value. | |
| 601 // If all angles have the same sector value, actual sorting is required. | |
| 602 SkOpAngle* SkOpAngle::findFirst() { | |
| 603 SkOpAngle* best = this; | |
| 604 int bestStart = SkTMin(fSectorStart, fSectorEnd); | |
| 605 SkOpAngle* angle = this; | |
| 606 while ((angle = angle->fNext) != this) { | |
| 607 int angleEnd = SkTMax(angle->fSectorStart, angle->fSectorEnd); | |
| 608 if (angleEnd < bestStart) { | |
| 609 return angle; // we wrapped around | |
| 610 } | |
| 611 int angleStart = SkTMin(angle->fSectorStart, angle->fSectorEnd); | |
| 612 if (bestStart > angleStart) { | |
| 613 best = angle; | |
| 614 bestStart = angleStart; | |
| 615 } | |
| 616 } | |
| 617 // back up to the first possible angle | |
| 618 SkOpAngle* firstBest = best; | |
| 619 angle = best; | |
| 620 int bestEnd = SkTMax(best->fSectorStart, best->fSectorEnd); | |
| 621 while ((angle = angle->previous()) != firstBest) { | |
| 622 if (angle->fStop) { | |
| 623 break; | |
| 624 } | |
| 625 int angleStart = SkTMin(angle->fSectorStart, angle->fSectorEnd); | |
| 626 // angles that are smaller by one aren't necessary better, since the lar
ger may be a line | |
| 627 // and the smaller may be a curve that curls to the other side of the li
ne. | |
| 628 if (bestEnd + 1 < angleStart) { | |
| 629 return best; | |
| 630 } | |
| 631 best = angle; | |
| 632 bestEnd = SkTMax(angle->fSectorStart, angle->fSectorEnd); | |
| 633 } | |
| 634 // in the case where all angles are nearly in the same sector, check the ord
er to find the best | |
| 635 firstBest = best; | |
| 636 angle = best; | |
| 637 do { | |
| 638 angle = angle->fNext; | |
| 639 if (angle->fStop) { | |
| 640 return firstBest; | |
| 641 } | |
| 642 bool orderable = best->orderable(angle); // note: may return an unorder
able angle | |
| 643 if (orderable == 0) { | |
| 644 return angle; | |
| 645 } | |
| 646 best = angle; | |
| 647 } while (angle != firstBest); | |
| 648 // if the angles are equally ordered, fall back on the initial tangent | |
| 649 bool foundBelow = false; | |
| 650 while ((angle = angle->fNext)) { | |
| 651 SkDVector scratch[2]; | |
| 652 const SkDVector* sweep; | |
| 653 if (!angle->fUnorderedSweep) { | |
| 654 sweep = angle->fSweep; | |
| 655 } else { | |
| 656 scratch[0] = angle->fCurvePart[1] - angle->fCurvePart[0]; | |
| 657 sweep = &scratch[0]; | |
| 658 } | |
| 659 bool isAbove = sweep->fY <= 0; | |
| 660 if (isAbove && foundBelow) { | |
| 661 return angle; | |
| 662 } | |
| 663 foundBelow |= !isAbove; | |
| 664 if (angle == firstBest) { | |
| 665 return NULL; // should not loop around | |
| 666 } | |
| 667 } | |
| 668 SkASSERT(0); // should never get here | |
| 669 return NULL; | |
| 670 } | |
| 671 | |
| 672 /* y<0 y==0 y>0 x<0 x==0 x>0 xy<0 xy==0 xy>0 | 604 /* y<0 y==0 y>0 x<0 x==0 x>0 xy<0 xy==0 xy>0 |
| 673 0 x x x | 605 0 x x x |
| 674 1 x x x | 606 1 x x x |
| 675 2 x x x | 607 2 x x x |
| 676 3 x x x | 608 3 x x x |
| 677 4 x x x | 609 4 x x x |
| 678 5 x x x | 610 5 x x x |
| 679 6 x x x | 611 6 x x x |
| 680 7 x x x | 612 7 x x x |
| 681 8 x x x | 613 8 x x x |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 809 int count = 0; | 741 int count = 0; |
| 810 const SkOpAngle* first = this; | 742 const SkOpAngle* first = this; |
| 811 const SkOpAngle* next = this; | 743 const SkOpAngle* next = this; |
| 812 do { | 744 do { |
| 813 next = next->fNext; | 745 next = next->fNext; |
| 814 ++count; | 746 ++count; |
| 815 } while (next && next != first); | 747 } while (next && next != first); |
| 816 return count; | 748 return count; |
| 817 } | 749 } |
| 818 | 750 |
| 819 // OPTIMIZATION: can this be done better in after when angles are sorted? | |
| 820 bool SkOpAngle::markStops() { | |
| 821 SkOpAngle* angle = this; | |
| 822 int lastEnd = SkTMax(fSectorStart, fSectorEnd); | |
| 823 do { | |
| 824 angle = angle->fNext; | |
| 825 if (!angle) { | |
| 826 return false; | |
| 827 } | |
| 828 int angleStart = SkTMin(angle->fSectorStart, angle->fSectorEnd); | |
| 829 // angles that are smaller by one aren't necessary better, since the lar
ger may be a line | |
| 830 // and the smaller may be a curve that curls to the other side of the li
ne. | |
| 831 if (lastEnd + 1 < angleStart) { | |
| 832 angle->fStop = true; | |
| 833 } | |
| 834 lastEnd = SkTMax(angle->fSectorStart, angle->fSectorEnd); | |
| 835 } while (angle != this); | |
| 836 return true; | |
| 837 } | |
| 838 | |
| 839 bool SkOpAngle::merge(SkOpAngle* angle) { | 751 bool SkOpAngle::merge(SkOpAngle* angle) { |
| 840 SkASSERT(fNext); | 752 SkASSERT(fNext); |
| 841 SkASSERT(angle->fNext); | 753 SkASSERT(angle->fNext); |
| 842 SkOpAngle* working = angle; | 754 SkOpAngle* working = angle; |
| 843 do { | 755 do { |
| 844 if (this == working) { | 756 if (this == working) { |
| 845 return false; | 757 return false; |
| 846 } | 758 } |
| 847 working = working->fNext; | 759 working = working->fNext; |
| 848 } while (working != angle); | 760 } while (working != angle); |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 961 SkOpSegment* SkOpAngle::segment() const { | 873 SkOpSegment* SkOpAngle::segment() const { |
| 962 return fStart->segment(); | 874 return fStart->segment(); |
| 963 } | 875 } |
| 964 | 876 |
| 965 void SkOpAngle::set(SkOpSpanBase* start, SkOpSpanBase* end) { | 877 void SkOpAngle::set(SkOpSpanBase* start, SkOpSpanBase* end) { |
| 966 fStart = start; | 878 fStart = start; |
| 967 fComputedEnd = fEnd = end; | 879 fComputedEnd = fEnd = end; |
| 968 SkASSERT(start != end); | 880 SkASSERT(start != end); |
| 969 fNext = NULL; | 881 fNext = NULL; |
| 970 fComputeSector = fComputedSector = fCheckCoincidence = false; | 882 fComputeSector = fComputedSector = fCheckCoincidence = false; |
| 971 fStop = false; | |
| 972 setSpans(); | 883 setSpans(); |
| 973 setSector(); | 884 setSector(); |
| 974 SkDEBUGCODE(fID = start ? start->globalState()->nextAngleID() : -1); | 885 SkDEBUGCODE(fID = start ? start->globalState()->nextAngleID() : -1); |
| 975 } | 886 } |
| 976 | 887 |
| 977 void SkOpAngle::setCurveHullSweep() { | 888 void SkOpAngle::setCurveHullSweep() { |
| 978 fUnorderedSweep = false; | 889 fUnorderedSweep = false; |
| 979 fSweep[0] = fCurvePart[1] - fCurvePart[0]; | 890 fSweep[0] = fCurvePart[1] - fCurvePart[0]; |
| 980 const SkOpSegment* segment = fStart->segment(); | 891 const SkOpSegment* segment = fStart->segment(); |
| 981 if (SkPath::kLine_Verb == segment->verb()) { | 892 if (SkPath::kLine_Verb == segment->verb()) { |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1150 crossesZero = this->checkCrossesZero(); | 1061 crossesZero = this->checkCrossesZero(); |
| 1151 start = SkTMin(fSectorStart, fSectorEnd); | 1062 start = SkTMin(fSectorStart, fSectorEnd); |
| 1152 int end = SkTMax(fSectorStart, fSectorEnd); | 1063 int end = SkTMax(fSectorStart, fSectorEnd); |
| 1153 if (!crossesZero) { | 1064 if (!crossesZero) { |
| 1154 fSectorMask = (unsigned) -1 >> (31 - end + start) << start; | 1065 fSectorMask = (unsigned) -1 >> (31 - end + start) << start; |
| 1155 } else { | 1066 } else { |
| 1156 fSectorMask = (unsigned) -1 >> (31 - start) | (-1 << end); | 1067 fSectorMask = (unsigned) -1 >> (31 - start) | (-1 << end); |
| 1157 } | 1068 } |
| 1158 } | 1069 } |
| 1159 | 1070 |
| 1160 int SkOpAngle::sign() const { | |
| 1161 SkASSERT(fStart->t() != fEnd->t()); | |
| 1162 return fStart->t() < fEnd->t() ? -1 : 1; | |
| 1163 } | |
| 1164 | |
| 1165 SkOpSpan* SkOpAngle::starter() { | 1071 SkOpSpan* SkOpAngle::starter() { |
| 1166 return fStart->starter(fEnd); | 1072 return fStart->starter(fEnd); |
| 1167 } | 1073 } |
| 1168 | 1074 |
| 1169 bool SkOpAngle::tangentsDiverge(const SkOpAngle* rh, double s0xt0) const { | 1075 bool SkOpAngle::tangentsDiverge(const SkOpAngle* rh, double s0xt0) const { |
| 1170 if (s0xt0 == 0) { | 1076 if (s0xt0 == 0) { |
| 1171 return false; | 1077 return false; |
| 1172 } | 1078 } |
| 1173 // if the ctrl tangents are not nearly parallel, use them | 1079 // if the ctrl tangents are not nearly parallel, use them |
| 1174 // solve for opposite direction displacement scale factor == m | 1080 // solve for opposite direction displacement scale factor == m |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1186 return true; | 1092 return true; |
| 1187 } | 1093 } |
| 1188 SkASSERT(s0dt0 != 0); | 1094 SkASSERT(s0dt0 != 0); |
| 1189 double m = s0xt0 / s0dt0; | 1095 double m = s0xt0 / s0dt0; |
| 1190 double sDist = sweep[0].length() * m; | 1096 double sDist = sweep[0].length() * m; |
| 1191 double tDist = tweep[0].length() * m; | 1097 double tDist = tweep[0].length() * m; |
| 1192 bool useS = fabs(sDist) < fabs(tDist); | 1098 bool useS = fabs(sDist) < fabs(tDist); |
| 1193 double mFactor = fabs(useS ? this->distEndRatio(sDist) : rh->distEndRatio(tD
ist)); | 1099 double mFactor = fabs(useS ? this->distEndRatio(sDist) : rh->distEndRatio(tD
ist)); |
| 1194 return mFactor < 2400; // empirically found limit | 1100 return mFactor < 2400; // empirically found limit |
| 1195 } | 1101 } |
| OLD | NEW |