Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(56)

Side by Side Diff: src/pathops/SkOpSegment.cpp

Issue 52653002: pathops work in progress (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: add raster vs gpu test Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/pathops/SkOpSegment.h ('k') | src/pathops/SkPathOpsCommon.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 1280 matching lines...) Expand 10 before | Expand all | Expand 10 after
1291 return bestTIndex; 1291 return bestTIndex;
1292 } 1292 }
1293 if (fBounds.fLeft == fBounds.fRight) { 1293 if (fBounds.fLeft == fBounds.fRight) {
1294 // if vertical, and directly above test point, wait for another one 1294 // if vertical, and directly above test point, wait for another one
1295 return AlmostEqualUlps(basePt.fX, fBounds.fLeft) ? SK_MinS32 : bestTInde x; 1295 return AlmostEqualUlps(basePt.fX, fBounds.fLeft) ? SK_MinS32 : bestTInde x;
1296 } 1296 }
1297 // intersect ray starting at basePt with edge 1297 // intersect ray starting at basePt with edge
1298 SkIntersections intersections; 1298 SkIntersections intersections;
1299 // OPTIMIZE: use specialty function that intersects ray with curve, 1299 // OPTIMIZE: use specialty function that intersects ray with curve,
1300 // returning t values only for curve (we don't care about t on ray) 1300 // returning t values only for curve (we don't care about t on ray)
1301 intersections.allowNear(false);
1301 int pts = (intersections.*CurveVertical[SkPathOpsVerbToPoints(fVerb)]) 1302 int pts = (intersections.*CurveVertical[SkPathOpsVerbToPoints(fVerb)])
1302 (fPts, top, bottom, basePt.fX, false); 1303 (fPts, top, bottom, basePt.fX, false);
1303 if (pts == 0 || (current && pts == 1)) { 1304 if (pts == 0 || (current && pts == 1)) {
1304 return bestTIndex; 1305 return bestTIndex;
1305 } 1306 }
1306 if (current) { 1307 if (current) {
1307 SkASSERT(pts > 1); 1308 SkASSERT(pts > 1);
1308 int closestIdx = 0; 1309 int closestIdx = 0;
1309 double closest = fabs(intersections[0][0] - mid); 1310 double closest = fabs(intersections[0][0] - mid);
1310 for (int idx = 1; idx < pts; ++idx) { 1311 for (int idx = 1; idx < pts; ++idx) {
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
1413 ; 1414 ;
1414 int otherCount = other->fTs.count(); 1415 int otherCount = other->fTs.count();
1415 int peekLast = span.fOtherIndex; 1416 int peekLast = span.fOtherIndex;
1416 while (++peekLast < otherCount && other->fTs[peekLast].fT == otherT) 1417 while (++peekLast < otherCount && other->fTs[peekLast].fT == otherT)
1417 ; 1418 ;
1418 if (++peekStart == --peekLast) { // if there isn't a range, there's noth ing to do 1419 if (++peekStart == --peekLast) { // if there isn't a range, there's noth ing to do
1419 continue; 1420 continue;
1420 } 1421 }
1421 // t start/last describe the range of spans that match the t of this spa n 1422 // t start/last describe the range of spans that match the t of this spa n
1422 double t = span.fT; 1423 double t = span.fT;
1423 int tStart = index; 1424 double tBottom = -1;
1424 while (--tStart >= 0 && (t == fTs[tStart].fT || fTs[tStart].fTiny)) 1425 int tStart = -1;
1425 ; 1426 int tLast = count;
1426 int tLast = index; 1427 bool lastSmall = false;
1427 while (fTs[tLast].fTiny) { 1428 double afterT = t;
1428 ++tLast; 1429 for (int inner = 0; inner < count; ++inner) {
1430 double innerT = fTs[inner].fT;
1431 if (innerT <= t && innerT > tBottom) {
1432 if (innerT < t || !lastSmall) {
1433 tStart = inner - 1;
1434 }
1435 tBottom = innerT;
1436 }
1437 if (innerT > afterT) {
1438 if (t == afterT && lastSmall) {
1439 afterT = innerT;
1440 } else {
1441 tLast = inner;
1442 break;
1443 }
1444 }
1445 lastSmall = innerT <= t ? fTs[inner].fSmall : false;
1429 } 1446 }
1430 while (++tLast < count && t == fTs[tLast].fT)
1431 ;
1432 for (int peekIndex = peekStart; peekIndex <= peekLast; ++peekIndex) { 1447 for (int peekIndex = peekStart; peekIndex <= peekLast; ++peekIndex) {
1433 if (peekIndex == span.fOtherIndex) { // skip the other span pointed to by this span 1448 if (peekIndex == span.fOtherIndex) { // skip the other span pointed to by this span
1434 continue; 1449 continue;
1435 } 1450 }
1436 const SkOpSpan& peekSpan = other->fTs[peekIndex]; 1451 const SkOpSpan& peekSpan = other->fTs[peekIndex];
1437 SkOpSegment* match = peekSpan.fOther; 1452 SkOpSegment* match = peekSpan.fOther;
1438 if (match->done()) { 1453 if (match->done()) {
1439 continue; // if the edge has already been eaten (likely coincid ence), ignore it 1454 continue; // if the edge has already been eaten (likely coincid ence), ignore it
1440 } 1455 }
1441 const double matchT = peekSpan.fOtherT; 1456 const double matchT = peekSpan.fOtherT;
(...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after
1689 MissingSpan& missing = missingSpans[index]; 1704 MissingSpan& missing = missingSpans[index];
1690 missing.fSegment->addTPair(missing.fT, missing.fOther, missing.fOtherT, false, missing.fPt); 1705 missing.fSegment->addTPair(missing.fT, missing.fOther, missing.fOtherT, false, missing.fPt);
1691 } 1706 }
1692 for (int index = 0; index < missingCount; ++index) { 1707 for (int index = 0; index < missingCount; ++index) {
1693 MissingSpan& missing = missingSpans[index]; 1708 MissingSpan& missing = missingSpans[index];
1694 missing.fSegment->fixOtherTIndex(); 1709 missing.fSegment->fixOtherTIndex();
1695 missing.fOther->fixOtherTIndex(); 1710 missing.fOther->fixOtherTIndex();
1696 } 1711 }
1697 } 1712 }
1698 1713
1714 bool SkOpSegment::findCoincidentMatch(const SkOpSpan* span, const SkOpSegment* o ther, int oStart,
1715 int oEnd, int step, SkPoint* startPt, SkPoint* endPt, double* endT) cons t {
1716 SkASSERT(span->fT == 0 || span->fT == 1);
1717 SkASSERT(span->fOtherT == 0 || span->fOtherT == 1);
1718 const SkOpSpan* otherSpan = &other->span(oEnd);
1719 double refT = otherSpan->fT;
1720 const SkPoint& refPt = otherSpan->fPt;
1721 const SkOpSpan* lastSpan = &other->span(step > 0 ? other->count() - 1 : 0);
1722 do {
1723 const SkOpSegment* match = span->fOther;
1724 if (match == otherSpan->fOther) {
1725 // find start of respective spans and see if both have winding
1726 int startIndex, endIndex;
1727 if (span->fOtherT == 1) {
1728 endIndex = span->fOtherIndex;
1729 startIndex = match->nextExactSpan(endIndex, -1);
1730 } else {
1731 startIndex = span->fOtherIndex;
1732 endIndex = match->nextExactSpan(startIndex, 1);
1733 }
1734 const SkOpSpan& startSpan = match->span(startIndex);
1735 if (startSpan.fWindValue != 0) {
1736 // draw ray from endSpan.fPt perpendicular to end tangent and me asure distance
1737 // to other segment.
1738 const SkOpSpan& endSpan = match->span(endIndex);
1739 SkDLine ray;
1740 SkVector dxdy;
1741 if (span->fOtherT == 1) {
1742 ray.fPts[0].set(startSpan.fPt);
1743 dxdy = match->dxdy(startIndex);
1744 } else {
1745 ray.fPts[0].set(endSpan.fPt);
1746 dxdy = match->dxdy(endIndex);
1747 }
1748 ray.fPts[1].fX = ray.fPts[0].fX + dxdy.fY;
1749 ray.fPts[1].fY = ray.fPts[0].fY - dxdy.fX;
1750 SkIntersections i;
1751 int roots = (i.*CurveRay[SkPathOpsVerbToPoints(other->verb())])( other->pts(), ray);
1752 for (int index = 0; index < roots; ++index) {
1753 if (ray.fPts[0].approximatelyEqual(i.pt(index))) {
1754 double matchMidT = (match->span(startIndex).fT
1755 + match->span(endIndex).fT) / 2;
1756 SkPoint matchMidPt = match->ptAtT(matchMidT);
1757 double otherMidT = (i[0][index] + other->span(oStart).fT ) / 2;
1758 SkPoint otherMidPt = other->ptAtT(otherMidT);
1759 if (SkDPoint::ApproximatelyEqual(matchMidPt, otherMidPt) ) {
1760 *startPt = startSpan.fPt;
1761 *endPt = endSpan.fPt;
1762 *endT = endSpan.fT;
1763 return true;
1764 }
1765 }
1766 }
1767 }
1768 return false;
1769 }
1770 if (otherSpan == lastSpan) {
1771 break;
1772 }
1773 otherSpan += step;
1774 } while (otherSpan->fT == refT || otherSpan->fPt == refPt);
1775 return false;
1776 }
1777
1699 /* 1778 /*
1700 The M and S variable name parts stand for the operators. 1779 The M and S variable name parts stand for the operators.
1701 Mi stands for Minuend (see wiki subtraction, analogous to difference) 1780 Mi stands for Minuend (see wiki subtraction, analogous to difference)
1702 Su stands for Subtrahend 1781 Su stands for Subtrahend
1703 The Opp variable name part designates that the value is for the Opposite operat or. 1782 The Opp variable name part designates that the value is for the Opposite operat or.
1704 Opposite values result from combining coincident spans. 1783 Opposite values result from combining coincident spans.
1705 */ 1784 */
1706 SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart , int* nextEnd, 1785 SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart , int* nextEnd,
1707 bool* unsortable, SkPathOp op, const int xo rMiMask, 1786 bool* unsortable, SkPathOp op, const int xo rMiMask,
1708 const int xorSuMask) { 1787 const int xorSuMask) {
(...skipping 360 matching lines...) Expand 10 before | Expand all | Expand 10 after
2069 const SkOpAngle* angle = sorted[angleIndex]; 2148 const SkOpAngle* angle = sorted[angleIndex];
2070 if (angle->segment() == this && angle->start() == end && 2149 if (angle->segment() == this && angle->start() == end &&
2071 angle->end() == start) { 2150 angle->end() == start) {
2072 firstIndex = angleIndex; 2151 firstIndex = angleIndex;
2073 break; 2152 break;
2074 } 2153 }
2075 } 2154 }
2076 return firstIndex; 2155 return firstIndex;
2077 } 2156 }
2078 2157
2158 int SkOpSegment::findT(double t, const SkOpSegment* match) const {
2159 int count = this->count();
2160 for (int index = 0; index < count; ++index) {
2161 const SkOpSpan& span = fTs[index];
2162 if (span.fT == t && span.fOther == match) {
2163 return index;
2164 }
2165 }
2166 SkASSERT(0);
2167 return -1;
2168 }
2169
2079 // FIXME: either: 2170 // FIXME: either:
2080 // a) mark spans with either end unsortable as done, or 2171 // a) mark spans with either end unsortable as done, or
2081 // b) rewrite findTop / findTopSegment / findTopContour to iterate further 2172 // b) rewrite findTop / findTopSegment / findTopContour to iterate further
2082 // when encountering an unsortable span 2173 // when encountering an unsortable span
2083 2174
2084 // OPTIMIZATION : for a pair of lines, can we compute points at T (cached) 2175 // OPTIMIZATION : for a pair of lines, can we compute points at T (cached)
2085 // and use more concise logic like the old edge walker code? 2176 // and use more concise logic like the old edge walker code?
2086 // FIXME: this needs to deal with coincident edges 2177 // FIXME: this needs to deal with coincident edges
2087 SkOpSegment* SkOpSegment::findTop(int* tIndexPtr, int* endIndexPtr, bool* unsort able, 2178 SkOpSegment* SkOpSegment::findTop(int* tIndexPtr, int* endIndexPtr, bool* unsort able,
2088 bool onlySortable) { 2179 bool onlySortable) {
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after
2292 double t = fTs[end].fT; 2383 double t = fTs[end].fT;
2293 if (approximately_less_than_zero(t)) { 2384 if (approximately_less_than_zero(t)) {
2294 return !approximately_less_than_zero(fTs[1].fT); 2385 return !approximately_less_than_zero(fTs[1].fT);
2295 } 2386 }
2296 if (approximately_greater_than_one(t)) { 2387 if (approximately_greater_than_one(t)) {
2297 return !approximately_greater_than_one(fTs[count - 2].fT); 2388 return !approximately_greater_than_one(fTs[count - 2].fT);
2298 } 2389 }
2299 return false; 2390 return false;
2300 } 2391 }
2301 2392
2393 bool SkOpSegment::isTiny(const SkOpAngle* angle) const {
2394 int start = angle->start();
2395 int end = angle->end();
2396 const SkOpSpan& mSpan = fTs[SkMin32(start, end)];
2397 return mSpan.fTiny;
2398 }
2399
2400 bool SkOpSegment::isTiny(int index) const {
2401 return fTs[index].fTiny;
2402 }
2403
2404 // look pair of active edges going away from coincident edge
2405 // one of them should be the continuation of other
2406 // if both are active, look to see if they both the connect to another coinciden t pair
2407 // if one at least one is a line, then make the pair coincident
2408 // if neither is a line, test for coincidence
2409 bool SkOpSegment::joinCoincidence(bool end, SkOpSegment* other, double otherT, i nt step,
2410 bool cancel) {
2411 int otherTIndex = other->findT(otherT, this);
2412 int next = other->nextExactSpan(otherTIndex, step);
2413 int otherMin = SkTMin(otherTIndex, next);
2414 int otherWind = other->span(otherMin).fWindValue;
2415 if (otherWind == 0) {
2416 return false;
2417 }
2418 SkASSERT(next >= 0);
2419 if (end) {
2420 int tIndex = count() - 1;
2421 do {
2422 SkOpSpan* test = &fTs[tIndex];
2423 SkASSERT(test->fT == 1);
2424 if (test->fOther == other || test->fOtherT != 0) {
2425 continue;
2426 }
2427 SkPoint startPt, endPt;
2428 double endT;
2429 if (findCoincidentMatch(test, other, otherTIndex, next, step, &start Pt, &endPt, &endT)) {
2430 SkOpSegment* match = test->fOther;
2431 if (cancel) {
2432 match->addTCancel(startPt, endPt, other);
2433 } else {
2434 match->addTCoincident(startPt, endPt, endT, other);
2435 }
2436 return true;
2437 }
2438 } while (fTs[--tIndex].fT == 1);
2439 } else {
2440 int tIndex = 0;
2441 do {
2442 SkOpSpan* test = &fTs[tIndex];
2443 SkASSERT(test->fT == 0);
2444 if (test->fOther == other || test->fOtherT != 1) {
2445 continue;
2446 }
2447 SkPoint startPt, endPt;
2448 double endT;
2449 if (findCoincidentMatch(test, other, otherTIndex, next, step, &start Pt, &endPt, &endT)) {
2450 SkOpSegment* match = test->fOther;
2451 if (cancel) {
2452 match->addTCancel(startPt, endPt, other);
2453 } else {
2454 match->addTCoincident(startPt, endPt, endT, other);
2455 }
2456 return true;
2457 }
2458 } while (fTs[++tIndex].fT == 0);
2459 }
2460 return false;
2461 }
2462
2302 // this span is excluded by the winding rule -- chase the ends 2463 // this span is excluded by the winding rule -- chase the ends
2303 // as long as they are unambiguous to mark connections as done 2464 // as long as they are unambiguous to mark connections as done
2304 // and give them the same winding value 2465 // and give them the same winding value
2305 SkOpSpan* SkOpSegment::markAndChaseDone(int index, int endIndex, int winding) { 2466 SkOpSpan* SkOpSegment::markAndChaseDone(int index, int endIndex, int winding) {
2306 int step = SkSign32(endIndex - index); 2467 int step = SkSign32(endIndex - index);
2307 int min = SkMin32(index, endIndex); 2468 int min = SkMin32(index, endIndex);
2308 markDone(min, winding); 2469 markDone(min, winding);
2309 SkOpSpan* last; 2470 SkOpSpan* last;
2310 SkOpSegment* other = this; 2471 SkOpSegment* other = this;
2311 while ((other = other->nextChase(&index, step, &min, &last))) { 2472 while ((other = other->nextChase(&index, step, &min, &last))) {
(...skipping 699 matching lines...) Expand 10 before | Expand all | Expand 10 after
3011 } 3172 }
3012 return true; 3173 return true;
3013 } 3174 }
3014 3175
3015 void SkOpSegment::subDivideBounds(int start, int end, SkPathOpsBounds* bounds) c onst { 3176 void SkOpSegment::subDivideBounds(int start, int end, SkPathOpsBounds* bounds) c onst {
3016 SkPoint edge[4]; 3177 SkPoint edge[4];
3017 subDivide(start, end, edge); 3178 subDivide(start, end, edge);
3018 (bounds->*SetCurveBounds[SkPathOpsVerbToPoints(fVerb)])(edge); 3179 (bounds->*SetCurveBounds[SkPathOpsVerbToPoints(fVerb)])(edge);
3019 } 3180 }
3020 3181
3021 bool SkOpSegment::isTiny(const SkOpAngle* angle) const {
3022 int start = angle->start();
3023 int end = angle->end();
3024 const SkOpSpan& mSpan = fTs[SkMin32(start, end)];
3025 return mSpan.fTiny;
3026 }
3027
3028 bool SkOpSegment::isTiny(int index) const {
3029 return fTs[index].fTiny;
3030 }
3031
3032 void SkOpSegment::TrackOutsidePair(SkTArray<SkPoint, true>* outsidePts, const Sk Point& endPt, 3182 void SkOpSegment::TrackOutsidePair(SkTArray<SkPoint, true>* outsidePts, const Sk Point& endPt,
3033 const SkPoint& startPt) { 3183 const SkPoint& startPt) {
3034 int outCount = outsidePts->count(); 3184 int outCount = outsidePts->count();
3035 if (outCount == 0 || endPt != (*outsidePts)[outCount - 2]) { 3185 if (outCount == 0 || endPt != (*outsidePts)[outCount - 2]) {
3036 outsidePts->push_back(endPt); 3186 outsidePts->push_back(endPt);
3037 outsidePts->push_back(startPt); 3187 outsidePts->push_back(startPt);
3038 } 3188 }
3039 } 3189 }
3040 3190
3041 void SkOpSegment::TrackOutside(SkTArray<SkPoint, true>* outsidePts, const SkPoin t& startPt) { 3191 void SkOpSegment::TrackOutside(SkTArray<SkPoint, true>* outsidePts, const SkPoin t& startPt) {
(...skipping 509 matching lines...) Expand 10 before | Expand all | Expand 10 after
3551 SkASSERT(done == fDoneSpans); 3701 SkASSERT(done == fDoneSpans);
3552 #endif 3702 #endif
3553 } 3703 }
3554 3704
3555 #ifdef SK_DEBUG 3705 #ifdef SK_DEBUG
3556 void SkOpSegment::dumpPts() const { 3706 void SkOpSegment::dumpPts() const {
3557 int last = SkPathOpsVerbToPoints(fVerb); 3707 int last = SkPathOpsVerbToPoints(fVerb);
3558 SkDebugf("{{"); 3708 SkDebugf("{{");
3559 int index = 0; 3709 int index = 0;
3560 do { 3710 do {
3561 SkDPoint::DumpSkPoint(fPts[index]); 3711 SkDPoint::dump(fPts[index]);
3562 SkDebugf(", "); 3712 SkDebugf(", ");
3563 } while (++index < last); 3713 } while (++index < last);
3564 SkDPoint::DumpSkPoint(fPts[index]); 3714 SkDPoint::dump(fPts[index]);
3565 SkDebugf("}}\n"); 3715 SkDebugf("}}\n");
3566 } 3716 }
3567 3717
3568 void SkOpSegment::dumpDPts() const { 3718 void SkOpSegment::dumpDPts() const {
3569 int count = SkPathOpsVerbToPoints(fVerb); 3719 int count = SkPathOpsVerbToPoints(fVerb);
3570 SkDebugf("{{"); 3720 SkDebugf("{{");
3571 int index = 0; 3721 int index = 0;
3572 do { 3722 do {
3573 SkDPoint dPt = {fPts[index].fX, fPts[index].fY}; 3723 SkDPoint dPt = {fPts[index].fX, fPts[index].fY};
3574 dPt.dump(); 3724 dPt.dump();
3575 if (index != count) { 3725 if (index != count) {
3576 SkDebugf(", "); 3726 SkDebugf(", ");
3577 } 3727 }
3578 } while (++index <= count); 3728 } while (++index <= count);
3579 SkDebugf("}}\n"); 3729 SkDebugf("}}\n");
3580 } 3730 }
3581 3731
3582 void SkOpSegment::dumpSpans() const { 3732 void SkOpSegment::dumpSpans() const {
3583 int count = this->count(); 3733 int count = this->count();
3584 for (int index = 0; index < count; ++index) { 3734 for (int index = 0; index < count; ++index) {
3585 const SkOpSpan& span = this->span(index); 3735 const SkOpSpan& span = this->span(index);
3586 SkDebugf("[%d] ", index); 3736 SkDebugf("[%d] ", index);
3587 span.dump(); 3737 span.dump();
3588 } 3738 }
3589 } 3739 }
3590 #endif 3740 #endif
OLDNEW
« no previous file with comments | « src/pathops/SkOpSegment.h ('k') | src/pathops/SkPathOpsCommon.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698