shape ops work in progress

git-svn-id: http://skia.googlecode.com/svn/trunk@4939 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
caryclark@google.com 2012-08-02 20:08:21 +00:00
parent 795cd47342
commit 534aa5b946
4 changed files with 517 additions and 192 deletions

View File

@ -27,7 +27,7 @@ int gDebugMaxWindValue = SK_MaxS32;
#define DEBUG_UNUSED 0 // set to expose unused functions
#if 0 // set to 1 for multiple thread -- no debugging
#if 01 // set to 1 for multiple thread -- no debugging
const bool gRunTestsInOneThread = false;
@ -51,7 +51,7 @@ const bool gRunTestsInOneThread = true;
#define DEBUG_ADD_INTERSECTING_TS 0
#define DEBUG_ADD_T_PAIR 0
#define DEBUG_CONCIDENT 0
#define DEBUG_CROSS 1
#define DEBUG_CROSS 0
#define DEBUG_DUMP 1
#define DEBUG_MARK_DONE 1
#define DEBUG_PATH_CONSTRUCTION 1
@ -61,7 +61,7 @@ const bool gRunTestsInOneThread = true;
#endif
#if (DEBUG_ACTIVE_SPANS || DEBUG_CONCIDENT) && !DEBUG_DUMP
#if (DEBUG_ACTIVE_SPANS || DEBUG_CONCIDENT || DEBUG_SORT) && !DEBUG_DUMP
#undef DEBUG_DUMP
#define DEBUG_DUMP 1
#endif
@ -492,6 +492,7 @@ public:
}
bool firstBump(int sumWinding) const {
SkDebugf("%s sign=%d sumWinding=%d\n", __FUNCTION__, sign(), sumWinding);
return sign() * sumWinding > 0;
}
@ -1237,6 +1238,57 @@ public:
SkASSERT(0); // incomplete
return false;
}
int computeSum(int startIndex, int endIndex) {
SkTDArray<Angle> angles;
addTwoAngles(startIndex, endIndex, angles);
buildAngles(endIndex, angles);
SkTDArray<Angle*> sorted;
sortAngles(angles, sorted);
int angleCount = angles.count();
const Angle* angle;
const Segment* base;
int winding;
int firstIndex = 0;
do {
angle = sorted[firstIndex];
base = angle->segment();
winding = base->windSum(angle);
if (winding != SK_MinS32) {
break;
}
if (++firstIndex == angleCount) {
return SK_MinS32;
}
} while (true);
// turn winding into contourWinding
int spanWinding = base->spanSign(angle->start(), angle->end());
if (spanWinding * winding < 0) {
winding += spanWinding;
}
#if DEBUG_SORT
base->debugShowSort(sorted, firstIndex, winding);
#endif
int nextIndex = firstIndex + 1;
int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
winding -= base->windBump(angle);
do {
if (nextIndex == angleCount) {
nextIndex = 0;
}
angle = sorted[nextIndex];
Segment* segment = angle->segment();
int maxWinding = winding;
winding -= segment->windBump(angle);
if (segment->windSum(nextIndex) == SK_MinS32) {
if (abs(maxWinding) < abs(winding) || maxWinding * winding < 0) {
maxWinding = winding;
}
segment->markAndChaseWinding(angle, maxWinding);
}
} while (++nextIndex != lastIndex);
return windSum(SkMin32(startIndex, endIndex));
}
int crossedSpan(const SkPoint& basePt, SkScalar& bestY, double& hitT) const {
int bestT = -1;
@ -1277,6 +1329,40 @@ public:
return bestT;
}
bool crossedSpanHalves(const SkPoint& basePt, bool leftHalf, bool rightHalf) {
// if a segment is connected to this one, consider it crossing
int tIndex;
if (fPts[0].fX == basePt.fX) {
tIndex = 0;
do {
const Span& sSpan = fTs[tIndex];
const Segment* sOther = sSpan.fOther;
if (!sOther->fTs[sSpan.fOtherIndex].fWindValue) {
continue;
}
if (leftHalf ? sOther->fBounds.fLeft < basePt.fX
: sOther->fBounds.fRight > basePt.fX) {
return true;
}
} while (fTs[++tIndex].fT == 0);
}
if (fPts[fVerb].fX == basePt.fX) {
tIndex = fTs.count() - 1;
do {
const Span& eSpan = fTs[tIndex];
const Segment* eOther = eSpan.fOther;
if (!eOther->fTs[eSpan.fOtherIndex].fWindValue) {
continue;
}
if (leftHalf ? eOther->fBounds.fLeft < basePt.fX
: eOther->fBounds.fRight > basePt.fX) {
return true;
}
} while (fTs[--tIndex].fT == 1);
}
return false;
}
bool decrementSpan(Span* span) {
SkASSERT(span->fWindValue > 0);
if (--(span->fWindValue) == 0) {
@ -1327,19 +1413,16 @@ public:
Segment* findNext(SkTDArray<Span*>& chase, bool firstFind, bool active,
const int startIndex, const int endIndex, int& nextStart,
int& nextEnd, int& winding, int& spanWinding) {
int sumWinding = winding + spanWinding;
if (sumWinding == 0) {
sumWinding = spanWinding;
}
bool insideContour = active && winding && winding * sumWinding < 0;
if (insideContour) {
sumWinding = winding;
}
int outerWinding = winding;
int innerWinding = winding + spanWinding;
#if DEBUG_WINDING
SkDebugf("%s winding=%d spanWinding=%d sumWinding=%d\n",
__FUNCTION__, winding, spanWinding, sumWinding);
SkDebugf("%s winding=%d spanWinding=%d outerWinding=%d innerWinding=%d\n",
__FUNCTION__, winding, spanWinding, outerWinding, innerWinding);
#endif
if (abs(outerWinding) < abs(innerWinding)
|| outerWinding * innerWinding < 0) {
outerWinding = innerWinding;
}
SkASSERT(startIndex != endIndex);
int count = fTs.count();
SkASSERT(startIndex < endIndex ? startIndex < count - 1
@ -1352,7 +1435,10 @@ public:
if (isSimple(end)) {
// mark the smaller of startIndex, endIndex done, and all adjacent
// spans with the same T value (but not 'other' spans)
markDone(SkMin32(startIndex, endIndex), sumWinding);
#if DEBUG_WINDING
SkDebugf("%s simple\n", __FUNCTION__);
#endif
markDone(SkMin32(startIndex, endIndex), outerWinding);
other = endSpan->fOther;
nextStart = endSpan->fOtherIndex;
double startT = other->fTs[nextStart].fT;
@ -1375,25 +1461,19 @@ public:
int firstIndex = findStartingEdge(sorted, startIndex, end);
SkASSERT(firstIndex >= 0);
#if DEBUG_SORT
debugShowSort(sorted, firstIndex, winding, sumWinding);
debugShowSort(sorted, firstIndex, winding);
#endif
bool doBump = sorted[firstIndex]->firstBump(sumWinding);
SkASSERT(sorted[firstIndex]->segment() == this);
#if DEBUG_WINDING
SkDebugf("%s sumWinding=%d sign=%d (%sbump)\n", __FUNCTION__,
sumWinding, sorted[firstIndex]->sign(), doBump ? "" : "no ");
SkDebugf("%s sign=%d\n", __FUNCTION__, sorted[firstIndex]->sign());
#endif
bool innerSwap = active && (doBump || insideContour);
int startWinding = sumWinding;
// SkASSERT(SkSign32(sumWinding) == SkSign32(winding) || winding == 0);
if (doBump || insideContour) {
sumWinding -= windBump(sorted[firstIndex]);
}
int sumWinding = winding - windBump(sorted[firstIndex]);
int nextIndex = firstIndex + 1;
int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
const Angle* foundAngle = NULL;
bool foundDone = false;
// iterate through the angle, and compute everyone's winding
bool toggleWinding = false;
int toggleWinding = SK_MinS32;
bool flipFound = false;
int flipped = 1;
Segment* nextSegment;
@ -1413,13 +1493,13 @@ public:
if (maxWinding * sumWinding < 0) {
flipFound ^= true;
#if DEBUG_WINDING
SkDebugf("flipFound maxWinding=%d sumWinding=%d\n",
maxWinding, sumWinding);
SkDebugf("%s flipFound=%d maxWinding=%d sumWinding=%d\n",
__FUNCTION__, flipFound, maxWinding, sumWinding);
#endif
}
if (!sumWinding) {
if (!active) {
markDone(SkMin32(startIndex, endIndex), startWinding);
markDone(SkMin32(startIndex, endIndex), outerWinding);
nextSegment->markWinding(SkMin32(nextAngle->start(),
nextAngle->end()), maxWinding);
#if DEBUG_WINDING
@ -1430,30 +1510,42 @@ public:
if (!foundAngle || foundDone) {
foundAngle = nextAngle;
foundDone = nextSegment->done(*nextAngle);
if (flipFound || (maxWinding * startWinding < 0)) {
if (flipFound || (maxWinding * outerWinding < 0)) {
flipped = -flipped;
#if DEBUG_WINDING
SkDebugf("flipped flipFound=%d maxWinding=%d startWinding=%d\n",
flipFound, maxWinding, startWinding);
SkDebugf("%s flipped=%d flipFound=%d maxWinding=%d"
" outerWinding=%d\n", __FUNCTION__, flipped,
flipFound, maxWinding, outerWinding);
#endif
}
}
continue;
}
if (!maxWinding && innerSwap && !foundAngle) {
if (sumWinding * startWinding < 0 && flipped > 0) {
if (!maxWinding && !foundAngle) {
#if DEBUG_WINDING
SkDebugf("%s toggleWinding\n");
if (flipped > 0) {
SkDebugf("%s sumWinding=%d * outerWinding=%d < 0 (%s)\n",
__FUNCTION__, sumWinding, outerWinding,
sumWinding * outerWinding < 0 ? "true" : "false");
}
#endif
if (sumWinding * outerWinding < 0 && flipped > 0) {
#if DEBUG_WINDING
SkDebugf("%s toggleWinding=%d\n", __FUNCTION__, sumWinding);
#endif
toggleWinding = sumWinding;
} else if (outerWinding != sumWinding) {
#if DEBUG_WINDING
SkDebugf("%s outerWinding=%d != sumWinding=%d winding=%d\n",
__FUNCTION__, outerWinding, sumWinding, winding);
#endif
toggleWinding = true;
} else if (startWinding != sumWinding) {
winding = sumWinding;
}
foundAngle = nextAngle;
if (flipFound) {
flipped = -1;
flipped = -flipped;
#if DEBUG_WINDING
SkDebugf("flipped flipFound=%d\n", flipFound);
SkDebugf("%s flipped flipFound=%d\n", __FUNCTION__, flipFound);
#endif
}
}
@ -1465,11 +1557,12 @@ public:
// as done, record the winding value, and mark connected unambiguous
// segments as well.
if (nextSegment->windSum(nextAngle) == SK_MinS32) {
if (abs(maxWinding) < abs(sumWinding)) {
if (abs(maxWinding) < abs(sumWinding)
|| maxWinding * sumWinding < 0) {
maxWinding = sumWinding;
}
Span* last;
if (foundAngle || innerSwap) {
if (foundAngle) {
last = nextSegment->markAndChaseWinding(nextAngle, maxWinding);
} else {
last = nextSegment->markAndChaseDone(nextAngle, maxWinding);
@ -1480,7 +1573,7 @@ public:
}
} while (++nextIndex != lastIndex);
SkASSERT(sorted[firstIndex]->segment() == this);
markDone(SkMin32(startIndex, endIndex), startWinding);
markDone(SkMin32(startIndex, endIndex), outerWinding);
if (!foundAngle) {
return NULL;
}
@ -1489,20 +1582,10 @@ public:
nextSegment = foundAngle->segment();
spanWinding = SkSign32(spanWinding) * flipped * nextSegment->windValue(
SkMin32(nextStart, nextEnd));
if (toggleWinding) {
if (winding) {
winding = 0;
} else {
winding = -startWinding;
}
if (toggleWinding != SK_MinS32) {
winding = toggleWinding;
spanWinding = -spanWinding;
}
#if 0
int min = SkMin32(nextStart, nextEnd);
int sign = foundAngle->sign();
int windSum = nextSegment->windSum(min);
int windValue = nextSegment->windValue(min);
SkASSERT(winding + sign * windValue == windSum);
#endif
#if DEBUG_WINDING
SkDebugf("%s spanWinding=%d\n", __FUNCTION__, spanWinding);
#endif
@ -1694,6 +1777,17 @@ public:
} while (leftSegment->fTs[SkMin32(tIndex, endIndex)].fDone);
return leftSegment;
}
bool firstBump(const Angle* angle, int sumWinding) const {
int winding = spanSign(angle->start(), angle->end());
sumWinding -= winding;
if (sumWinding == 0) {
sumWinding = winding;
}
bool result = angle->sign() * sumWinding > 0;
SkASSERT(result == angle->firstBump(sumWinding));
return result;
}
// FIXME: not crazy about this
// when the intersections are performed, the other index is into an
@ -1862,7 +1956,7 @@ public:
}
#if DEBUG_MARK_DONE
const SkPoint& pt = xyAtT(&span);
SkDebugf("%s segment=%d index=%d t=%1.9g pt=(%1.9g,%1.9g) wind=%d\n",
SkDebugf("%s id=%d index=%d t=%1.9g pt=(%1.9g,%1.9g) wind=%d\n",
__FUNCTION__, fID, lesser, span.fT, pt.fX, pt.fY, winding);
#endif
span.fDone = true;
@ -1879,7 +1973,7 @@ public:
}
#if DEBUG_MARK_DONE
const SkPoint& pt = xyAtT(&span);
SkDebugf("%s segment=%d index=%d t=%1.9g pt=(%1.9g,%1.9g) wind=%d\n",
SkDebugf("%s id=%d index=%d t=%1.9g pt=(%1.9g,%1.9g) wind=%d\n",
__FUNCTION__, fID, index, span.fT, pt.fX, pt.fY, winding);
#endif
span.fDone = true;
@ -1903,7 +1997,7 @@ public:
SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
#if DEBUG_MARK_DONE
const SkPoint& pt = xyAtT(&span);
SkDebugf("%s segment=%d index=%d t=%1.9g pt=(%1.9g,%1.9g) wind=%d\n",
SkDebugf("%s id=%d index=%d t=%1.9g pt=(%1.9g,%1.9g) wind=%d\n",
__FUNCTION__, fID, lesser, span.fT, pt.fX, pt.fY, winding);
#endif
SkASSERT(abs(winding) <= gDebugMaxWindSum);
@ -1919,7 +2013,7 @@ public:
SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding);
#if DEBUG_MARK_DONE
const SkPoint& pt = xyAtT(&span);
SkDebugf("%s segment=%d index=%d t=%1.9g pt=(%1.9g,%1.9g) wind=%d\n",
SkDebugf("%s id=%d index=%d t=%1.9g pt=(%1.9g,%1.9g) wind=%d\n",
__FUNCTION__, fID, index, span.fT, pt.fX, pt.fY, winding);
#endif
SkASSERT(abs(winding) <= gDebugMaxWindSum);
@ -2081,7 +2175,7 @@ public:
#if DEBUG_CONCIDENT
// assert if pair has not already been added
void debugAddTPair(double t, const Segment& other, double otherT) {
void debugAddTPair(double t, const Segment& other, double otherT) const {
for (int i = 0; i < fTs.count(); ++i) {
if (fTs[i].fT == t && fTs[i].fOther == &other && fTs[i].fOtherT == otherT) {
return;
@ -2091,8 +2185,14 @@ public:
}
#endif
#if DEBUG_DUMP
int debugID() const {
return fID;
}
#endif
#if DEBUG_CONCIDENT
void debugShowTs() {
void debugShowTs() const {
SkDebugf("%s %d", __FUNCTION__, fID);
for (int i = 0; i < fTs.count(); ++i) {
SkDebugf(" [o=%d %1.9g (%1.9g,%1.9g) w=%d]", fTs[i].fOther->fID,
@ -2103,7 +2203,7 @@ public:
#endif
#if DEBUG_ACTIVE_SPANS
void debugShowActiveSpans(int contourID, int segmentIndex) {
void debugShowActiveSpans() const {
if (done()) {
return;
}
@ -2111,8 +2211,7 @@ public:
if (fTs[i].fDone) {
continue;
}
SkDebugf("%s contour=%d segment=%d (%d)", __FUNCTION__, contourID,
segmentIndex, fID);
SkDebugf("%s id=%d", __FUNCTION__, fID);
SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
for (int vIndex = 1; vIndex <= fVerb; ++vIndex) {
SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
@ -2121,27 +2220,26 @@ public:
SkDebugf(") fT=%d (%1.9g) (%1.9g,%1.9g)", i, fTs[i].fT,
xAtT(span), yAtT(i));
const Segment* other = fTs[i].fOther;
SkDebugf(" other=%d otherT=%1.9g otherIndex=%d", other->fID,
fTs[i].fOtherT, fTs[i].fOtherIndex);
SkDebugf(" windSum=%d windValue=%d\n", fTs[i].fWindSum,
fTs[i].fWindValue);
SkDebugf(" other=%d otherT=%1.9g otherIndex=%d windSum=",
other->fID, fTs[i].fOtherT, fTs[i].fOtherIndex);
if (fTs[i].fWindSum == SK_MinS32) {
SkDebugf("?");
} else {
SkDebugf("%d", fTs[i].fWindSum);
}
SkDebugf(" windValue=%d\n", fTs[i].fWindValue);
}
}
#endif
#if DEBUG_SORT
void debugShowSort(const SkTDArray<Angle*>& angles, int first,
int contourWinding, int sumWinding) {
const int contourWinding) const {
SkASSERT(angles[first]->segment() == this);
bool doBump = angles[first]->firstBump(sumWinding);
bool insideContour = contourWinding && contourWinding * sumWinding < 0;
int windSum = insideContour ? contourWinding : sumWinding;
int lastSum = windSum;
if (insideContour || doBump) {
windSum -= windBump(angles[first]);
} else {
lastSum += windBump(angles[first]);
}
int lastSum = contourWinding;
int windSum = lastSum - windBump(angles[first]);
SkDebugf("%s contourWinding=%d bump=%d\n", __FUNCTION__,
contourWinding, windBump(angles[first]));
int index = first;
bool firstTime = true;
do {
@ -2152,9 +2250,7 @@ public:
const Span& sSpan = segment.fTs[start];
const Span& eSpan = segment.fTs[end];
const Span& mSpan = segment.fTs[SkMin32(start, end)];
if (firstTime) {
firstTime = false;
} else {
if (!firstTime) {
lastSum = windSum;
windSum -= segment.windBump(&angle);
}
@ -2169,10 +2265,29 @@ public:
if (index == angles.count()) {
index = 0;
}
if (firstTime) {
firstTime = false;
}
} while (index != first);
}
#endif
#if DEBUG_WINDING
bool debugVerifyWinding(int start, int end, int winding) const {
const Span& span = fTs[SkMin32(start, end)];
int spanWinding = span.fWindSum;
if (spanWinding == SK_MinS32) {
return true;
}
int spanSign = SkSign32(start - end);
int signedVal = spanSign * span.fWindValue;
if (signedVal < 0) {
spanWinding -= signedVal;
}
return span.fWindSum == winding;
}
#endif
private:
const SkPoint* fPts;
SkPath::Verb fVerb;
@ -2274,10 +2389,10 @@ public:
for (int test = 0; test < segmentCount; ++test) {
Segment* testSegment = &fSegments[test];
const SkRect& bounds = testSegment->bounds();
if (bounds.fTop < bestY) {
if (bounds.fBottom <= bestY) {
continue;
}
if (bounds.fTop > basePt.fY) {
if (bounds.fTop >= basePt.fY) {
continue;
}
if (bounds.fLeft > basePt.fX) {
@ -2286,6 +2401,17 @@ public:
if (bounds.fRight < basePt.fX) {
continue;
}
if (bounds.fLeft == bounds.fRight) {
continue;
}
#if 0
bool leftHalf = bounds.fLeft == basePt.fX;
bool rightHalf = bounds.fRight == basePt.fX;
if ((leftHalf || rightHalf) && !testSegment->crossedSpanHalves(
basePt, leftHalf, rightHalf)) {
continue;
}
#endif
double testHitT;
int testT = testSegment->crossedSpan(basePt, bestY, testHitT);
if (testT >= 0) {
@ -2324,7 +2450,6 @@ public:
fSegments.reset();
fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
fContainsCurves = fContainsIntercepts = false;
fWindingSum = SK_MinS32;
}
void resolveCoincidence(int winding) {
@ -2382,11 +2507,6 @@ public:
return fSegments;
}
void setWinding(int winding) {
SkASSERT(fWindingSum < 0 || fWindingSum == winding);
fWindingSum = winding;
}
// OPTIMIZATION: feel pretty uneasy about this. It seems like once again
// we need to sort and walk edges in y, but that on the surface opens the
// same can of worms as before. But then, this is a rough sort based on
@ -2433,22 +2553,6 @@ public:
return segment.verb() + 1;
}
int windSum() {
if (fWindingSum >= 0) {
return fWindingSum;
}
// check peers
int count = fCrosses.count();
for (int index = 0; index < count; ++index) {
const Contour* crosser = fCrosses[index];
if (0 <= crosser->fWindingSum) {
fWindingSum = crosser->fWindingSum;
break;
}
}
return fWindingSum;
}
#if DEBUG_TEST
SkTArray<Segment>& debugSegments() {
return fSegments;
@ -2480,7 +2584,7 @@ public:
#if DEBUG_ACTIVE_SPANS
void debugShowActiveSpans() {
for (int index = 0; index < fSegments.count(); ++index) {
fSegments[index].debugShowActiveSpans(fID, index);
fSegments[index].debugShowActiveSpans();
}
}
#endif
@ -2507,7 +2611,6 @@ private:
Bounds fBounds;
bool fContainsIntercepts;
bool fContainsCurves;
int fWindingSum; // initial winding number outside
#if DEBUG_DUMP
int fID;
#endif
@ -3041,14 +3144,14 @@ static void coincidenceCheck(SkTDArray<Contour*>& contourList, int winding) {
// two contours touch, so we need only look at contours not touching this one.
// OPTIMIZATION: sort contourList vertically to avoid linear walk
static int innerContourCheck(SkTDArray<Contour*>& contourList,
Contour* baseContour, const Segment* current, int index, int endIndex) {
const Segment* current, int index, int endIndex) {
const SkPoint& basePt = current->xyAtT(endIndex);
int contourCount = contourList.count();
SkScalar bestY = SK_ScalarMin;
const Segment* test = NULL;
int tIndex;
double tHit;
bool checkCrosses = true;
// bool checkCrosses = true;
for (int cTest = 0; cTest < contourCount; ++cTest) {
Contour* contour = contourList[cTest];
if (basePt.fY < contour->bounds().fTop) {
@ -3057,6 +3160,7 @@ static int innerContourCheck(SkTDArray<Contour*>& contourList,
if (bestY > contour->bounds().fBottom) {
continue;
}
#if 0
// even though the contours crossed, if spans cancel through concidence,
// the contours may be not have any span links to chase, and the current
// segment may be isolated. Detect this by seeing if current has
@ -3071,19 +3175,20 @@ static int innerContourCheck(SkTDArray<Contour*>& contourList,
}
checkCrosses = false;
}
#endif
const Segment* next = contour->crossedSegment(basePt, bestY, tIndex, tHit);
if (next) {
test = next;
}
}
if (!test) {
baseContour->setWinding(0);
return 0;
}
int winding, windValue;
// If the ray hit the end of a span, we need to construct the wheel of
// angles to find the span closest to the ray -- even if there are just
// two spokes on the wheel.
const Angle* angle = NULL;
if (fabs(tHit - test->t(tIndex)) < FLT_EPSILON) {
SkTDArray<Angle> angles;
int end = test->nextSpan(tIndex, 1);
@ -3099,7 +3204,7 @@ static int innerContourCheck(SkTDArray<Contour*>& contourList,
// hour after 6 o'clock
sortAngles(angles, sorted);
#if DEBUG_SORT
sorted[0]->segment()->debugShowSort(sorted, 0, 0, 0);
sorted[0]->segment()->debugShowSort(sorted, 0, 0);
#endif
// walk the sorted angle fan to find the lowest angle
// above the base point. Currently, the first angle in the sorted array
@ -3130,20 +3235,18 @@ static int innerContourCheck(SkTDArray<Contour*>& contourList,
SkASSERT(left >= 0 || right >= 0);
if (left < 0) {
left = right;
} else if (left >= 0 && mid >= 0 && right >= 0
&& sorted[mid]->sign() == sorted[right]->sign()) {
left = right;
}
const Angle* angle = sorted[left];
angle = sorted[left];
test = angle->segment();
winding = test->windSum(angle);
SkASSERT(winding != SK_MinS32);
windValue = test->windValue(angle);
#if 0
if (angle->firstBump(winding)) {
winding -= test->windBump(angle);
}
#endif
#if DEBUG_WINDING
SkDebugf("%s angle winding=%d windValue=%d\n", __FUNCTION__, winding,
windValue);
SkDebugf("%s angle winding=%d windValue=%d sign=%d\n", __FUNCTION__, winding,
windValue, angle->sign());
#endif
} else {
winding = test->windSum(tIndex);
@ -3159,19 +3262,19 @@ static int innerContourCheck(SkTDArray<Contour*>& contourList,
#if DEBUG_WINDING
SkDebugf("%s dx=%1.9g\n", __FUNCTION__, dx);
#endif
SkASSERT(dx != 0);
if (winding * dx > 0) { // if same signs, result is negative
if (dx == 0) {
SkASSERT(angle);
if (test->firstBump(angle, winding)) {
winding -= test->windBump(angle);
}
} else if (winding * dx > 0) { // if same signs, result is negative
winding += dx > 0 ? -windValue : windValue;
#if DEBUG_WINDING
SkDebugf("%s final winding=%d\n", __FUNCTION__, winding);
#endif
}
start here;
// start here;
// we're broken because we find a vertical span
// also, does it make sense to compute a contour's winding? Won't it
// depend on coincidence and (e.g. a figure eight) self intersection?
// (hopefully no one uses this) so remove it
baseContour->setWinding(winding);
return winding;
}
@ -3181,8 +3284,7 @@ static int innerContourCheck(SkTDArray<Contour*>& contourList,
// Once the segment array is built, there's no reason I can think of not to
// sort it in Y. hmmm
// FIXME: return the contour found to pass to inner contour check
static Segment* findTopContour(SkTDArray<Contour*>& contourList,
Contour*& topContour) {
static Segment* findTopContour(SkTDArray<Contour*>& contourList) {
int contourCount = contourList.count();
int cIndex = 0;
Segment* topStart;
@ -3195,7 +3297,6 @@ static Segment* findTopContour(SkTDArray<Contour*>& contourList,
if (!topStart) {
return NULL;
}
topContour = contour;
while (++cIndex < contourCount) {
contour = contourList[cIndex];
if (bestY < contour->bounds().fTop) {
@ -3206,7 +3307,6 @@ static Segment* findTopContour(SkTDArray<Contour*>& contourList,
if (!test || bestY <= testY) {
continue;
}
topContour = contour;
topStart = test;
bestY = testY;
}
@ -3237,18 +3337,24 @@ static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex,
// find first angle, initialize winding to computed fWindSum
int firstIndex = -1;
const Angle* angle;
int spanWinding;
int winding;
do {
angle = sorted[++firstIndex];
spanWinding = angle->segment()->windSum(angle);
} while (spanWinding == SK_MinS32);
#if DEBUG_SORT
angle->segment()->debugShowSort(sorted, firstIndex, contourWinding,
spanWinding);
segment = angle->segment();
winding = segment->windSum(angle);
} while (winding == SK_MinS32);
int spanWinding = segment->spanSign(angle->start(), angle->end());
#if DEBUG_WINDING
SkDebugf("%s winding=%d spanWinding=%d contourWinding=%d\n",
__FUNCTION__, winding, spanWinding, contourWinding);
#endif
if (angle->firstBump(spanWinding)) {
spanWinding -= angle->segment()->windBump(angle);
// turn swinding into contourWinding
if (spanWinding * winding < 0) {
winding += spanWinding;
}
#if DEBUG_SORT
segment->debugShowSort(sorted, firstIndex, winding);
#endif
// we care about first sign and whether wind sum indicates this
// edge is inside or outside. Maybe need to pass span winding
// or first winding or something into this function?
@ -3257,30 +3363,35 @@ static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex,
int nextIndex = firstIndex + 1;
int angleCount = sorted.count();
int lastIndex = firstIndex != 0 ? firstIndex : angleCount;
angle = sorted[firstIndex];
winding -= angle->segment()->windBump(angle);
do {
SkASSERT(nextIndex != firstIndex);
if (nextIndex == angleCount) {
nextIndex = 0;
}
const Angle* angle = sorted[nextIndex];
angle = sorted[nextIndex];
segment = angle->segment();
int maxWinding = spanWinding;
spanWinding -= segment->windBump(angle);
if (maxWinding * spanWinding < 0) {
SkDebugf("%s flipped sign %d %d\n", __FUNCTION__, maxWinding, spanWinding);
}
int maxWinding = winding;
winding -= segment->windBump(angle);
#if DEBUG_SORT
SkDebugf("%s id=%d maxWinding=%d winding=%d\n", __FUNCTION__,
segment->debugID(), maxWinding, winding);
#endif
tIndex = angle->start();
endIndex = angle->end();
int lesser = SkMin32(tIndex, endIndex);
const Span& nextSpan = segment->span(lesser);
if (!nextSpan.fDone) {
#if 1
// FIXME: this be wrong. assign startWinding if edge is in
// same direction. If the direction is opposite, winding to
// assign is flipped sign or +/- 1?
if (abs(maxWinding) < abs(spanWinding)) {
maxWinding = spanWinding;
if (abs(maxWinding) < abs(winding)) {
maxWinding = winding;
}
segment->markWinding(lesser, maxWinding);
#endif
break;
}
} while (++nextIndex != lastIndex);
@ -3314,8 +3425,7 @@ static bool windingIsActive(int winding, int spanWinding) {
static void bridge(SkTDArray<Contour*>& contourList, SkPath& simple) {
bool firstContour = true;
do {
Contour* topContour;
Segment* topStart = findTopContour(contourList, topContour);
Segment* topStart = findTopContour(contourList);
if (!topStart) {
break;
}
@ -3328,9 +3438,17 @@ static void bridge(SkTDArray<Contour*>& contourList, SkPath& simple) {
contourWinding = 0;
firstContour = false;
} else {
contourWinding = innerContourCheck(contourList, topContour, current,
index, endIndex);
contourWinding = current->windSum(SkMin32(index, endIndex));
// FIXME: don't I have to adjust windSum to get contourWinding?
if (contourWinding == SK_MinS32) {
contourWinding = current->computeSum(index, endIndex);
if (contourWinding == SK_MinS32) {
contourWinding = innerContourCheck(contourList, current,
index, endIndex);
}
}
#if DEBUG_WINDING
// SkASSERT(current->debugVerifyWinding(index, endIndex, contourWinding));
SkDebugf("%s contourWinding=%d\n", __FUNCTION__, contourWinding);
#endif
}
@ -3338,16 +3456,6 @@ static void bridge(SkTDArray<Contour*>& contourList, SkPath& simple) {
bool firstTime = true;
int winding = contourWinding;
int spanWinding = current->spanSign(index, endIndex);
int spanWindSum = current->windSum(SkMin32(index, endIndex));
if (spanWindSum != SK_MinS32) {
int calcWinding = spanWindSum;
if (spanWinding > 0) {
// calcWinding -= spanWinding;
}
SkDebugf("%s *** winding=%d calcWinding=%d\n", __FUNCTION__,
winding, calcWinding);
winding = calcWinding;
}
// FIXME: needs work. While it works in limited situations, it does
// not always compute winding correctly. Active should be removed and instead
// the initial winding should be correctly passed in so that if the
@ -3395,32 +3503,12 @@ static void bridge(SkTDArray<Contour*>& contourList, SkPath& simple) {
break;
}
int lesser = SkMin32(index, endIndex);
spanWinding = current->windSum(lesser);
int spanValue = current->windValue(lesser);
SkASSERT(spanWinding != SK_MinS32);
#if DEBUG_WINDING
SkDebugf("%s spanWinding=%d winding=%d spanValue=%d\n",
__FUNCTION__, spanWinding, winding, spanValue);
#endif
if (abs(spanWinding) != spanValue) {
winding = spanWinding;
spanWinding = spanValue * SkSign32(spanWinding);
spanWinding = current->spanSign(index, endIndex);
winding = current->windSum(lesser);
if (spanWinding * winding > 0) {
winding -= spanWinding;
#if DEBUG_WINDING
SkDebugf("%s != spanWinding=%d winding=%d\n", __FUNCTION__,
spanWinding, winding);
#endif
active = windingIsActive(winding, spanWinding);
} else if (winding) {
#if DEBUG_WINDING
SkDebugf("%s ->0 contourWinding=%d winding=%d\n", __FUNCTION__,
contourWinding, winding);
#endif
// start here;
// set active=false if it was false when chase was created
active = abs(winding) <= abs(spanWinding);
winding = 0;
}
active = windingIsActive(winding, spanWinding);
} while (true);
} while (true);
}

View File

@ -27,8 +27,7 @@ static const SimplifyFindTopTest::Segment* testCommon(
addIntersectTs(contourList[1], contourList[1]);
}
fixOtherTIndex(contourList);
SimplifyFindTopTest::Contour* top;
SimplifyFindTopTest::Segment* topStart = findTopContour(contourList, top);
SimplifyFindTopTest::Segment* topStart = findTopContour(contourList);
const SimplifyFindTopTest::Segment* topSegment = topStart->findTop(index,
end);
return topSegment;

View File

@ -62,6 +62,20 @@ static void testLine3() {
testSimplifyx(path);
}
static void testLine3a() {
SkPath path, simple;
addInnerCWTriangle(path);
addOuterCCWTriangle(path);
testSimplifyx(path);
}
static void testLine3b() {
SkPath path, simple;
addInnerCCWTriangle(path);
addOuterCCWTriangle(path);
testSimplifyx(path);
}
static void testLine4() {
SkPath path, simple;
addOuterCCWTriangle(path);
@ -641,12 +655,127 @@ static void testLine66() {
testSimplifyx(path);
}
static void testLine67() {
SkPath path, simple;
path.addRect(0, 0, 60, 60, (SkPath::Direction) 0);
path.addRect(10, 40, 30, 30, (SkPath::Direction) 0);
path.addRect(24, 20, 36, 30, (SkPath::Direction) 0);
path.addRect(32, 0, 36, 41, (SkPath::Direction) 0);
testSimplifyx(path);
}
static void testLine68a() {
SkPath path, simple;
path.addRect(0, 0, 8, 8, (SkPath::Direction) 0);
path.addRect(2, 2, 6, 6, (SkPath::Direction) 0);
path.addRect(1, 2, 4, 2, (SkPath::Direction) 0);
testSimplifyx(path);
}
static void testLine68b() {
SkPath path, simple;
path.addRect(0, 0, 8, 8, (SkPath::Direction) 0);
path.addRect(2, 2, 6, 6, (SkPath::Direction) 1);
path.addRect(1, 2, 2, 2, (SkPath::Direction) 0);
testSimplifyx(path);
}
static void testLine68c() {
SkPath path, simple;
path.addRect(0, 0, 8, 8, (SkPath::Direction) 1);
path.addRect(2, 2, 6, 6, (SkPath::Direction) 0);
path.addRect(1, 2, 4, 2, (SkPath::Direction) 0);
testSimplifyx(path);
}
static void testLine68d() {
SkPath path, simple;
path.addRect(0, 0, 8, 8, (SkPath::Direction) 1);
path.addRect(2, 2, 6, 6, (SkPath::Direction) 1);
path.addRect(1, 2, 4, 2, (SkPath::Direction) 0);
testSimplifyx(path);
}
static void testLine68e() {
SkPath path, simple;
path.addRect(0, 0, 8, 8, (SkPath::Direction) 0);
path.addRect(0, 0, 8, 8, (SkPath::Direction) 0);
path.addRect(2, 2, 6, 6, (SkPath::Direction) 1);
path.addRect(1, 2, 2, 2, (SkPath::Direction) 0);
testSimplifyx(path);
}
static void testLine68f() {
SkPath path, simple;
path.addRect(0, 0, 8, 8, (SkPath::Direction) 0);
path.addRect(2, 2, 6, 6, (SkPath::Direction) 1);
path.addRect(2, 2, 6, 6, (SkPath::Direction) 1);
path.addRect(1, 2, 2, 2, (SkPath::Direction) 0);
testSimplifyx(path);
}
static void testLine68g() {
SkPath path, simple;
path.addRect(0, 0, 8, 8, (SkPath::Direction) 0);
path.addRect(0, 0, 8, 8, (SkPath::Direction) 0);
path.addRect(2, 2, 6, 6, (SkPath::Direction) 1);
path.addRect(2, 2, 6, 6, (SkPath::Direction) 1);
path.addRect(1, 2, 2, 2, (SkPath::Direction) 0);
testSimplifyx(path);
}
static void testLine68h() {
SkPath path, simple;
path.addRect(0, 0, 8, 8, (SkPath::Direction) 0);
path.addRect(2, 2, 6, 6, (SkPath::Direction) 1);
path.addRect(2, 2, 6, 6, (SkPath::Direction) 1);
path.addRect(2, 2, 6, 6, (SkPath::Direction) 1);
path.addRect(1, 2, 2, 2, (SkPath::Direction) 0);
testSimplifyx(path);
}
static void testLine69() {
SkPath path, simple;
path.addRect(0, 20, 20, 20, (SkPath::Direction) 0);
path.addRect(0, 20, 12, 30, (SkPath::Direction) 0);
path.addRect(12, 32, 21, 36, (SkPath::Direction) 0);
testSimplifyx(path);
}
static void testLine70() {
SkPath path, simple;
path.addRect(0, 0, 20, 20, (SkPath::Direction) 0);
path.addRect(0, 24, 12, 12, (SkPath::Direction) 0);
path.addRect(12, 32, 21, 36, (SkPath::Direction) 1);
testSimplifyx(path);
}
static void testLine71() {
SkPath path, simple;
path.addRect(0, 0, 20, 20, (SkPath::Direction) 0);
path.addRect(12, 0, 24, 24, (SkPath::Direction) 0);
path.addRect(12, 32, 21, 36, (SkPath::Direction) 0);
testSimplifyx(path);
}
static void (*firstTest)() = 0;
static struct {
void (*fun)();
const char* str;
} tests[] = {
TEST(testLine71),
TEST(testLine70),
TEST(testLine69),
TEST(testLine68h),
TEST(testLine68g),
TEST(testLine68f),
TEST(testLine68e),
TEST(testLine68d),
TEST(testLine68c),
TEST(testLine68b),
TEST(testLine68a),
TEST(testLine67),
TEST(testLine66),
TEST(testLine65),
TEST(testLine64),
@ -713,6 +842,8 @@ static struct {
TEST(testLine6),
TEST(testLine5),
TEST(testLine4),
TEST(testLine3b),
TEST(testLine3a),
TEST(testLine3),
TEST(testLine2),
TEST(testLine1),
@ -720,7 +851,24 @@ static struct {
static const size_t testCount = sizeof(tests) / sizeof(tests[0]);
static struct {
void (*fun)();
const char* str;
} subTests[] = {
TEST(testLine68h),
TEST(testLine68g),
TEST(testLine68f),
TEST(testLine68e),
TEST(testLine68d),
TEST(testLine68c),
TEST(testLine68b),
TEST(testLine68a),
};
static const size_t subTestCount = sizeof(subTests) / sizeof(subTests[0]);
static bool skipAll = false;
static bool runSubTests = false;
void SimplifyNew_Test() {
if (skipAll) {
@ -729,8 +877,16 @@ void SimplifyNew_Test() {
#ifdef SK_DEBUG
gDebugMaxWindSum = 4;
gDebugMaxWindValue = 4;
size_t index;
#endif
size_t index = testCount - 1;
if (runSubTests) {
index = subTestCount - 1;
do {
SkDebugf(" %s [%s]\n", __FUNCTION__, subTests[index].str);
(*subTests[index].fun)();
} while (index--);
}
index = testCount - 1;
if (firstTest) {
while (index > 0 && tests[index].fun != firstTest) {
--index;

View File

@ -632,11 +632,84 @@ path.close();
path.addRect(12, 20, 24, 30, (SkPath::Direction) 0);
</div>
<div id="testLine67">
path.addRect(0, 0, 60, 60, (SkPath::Direction) 0);
path.addRect(10, 40, 30, 30, (SkPath::Direction) 0);
path.addRect(24, 20, 36, 30, (SkPath::Direction) 0);
path.addRect(32, 0, 36, 41, (SkPath::Direction) 0);
</div>
<div id="testLine68a">
path.addRect(0, 0, 8, 8, (SkPath::Direction) 0);
path.addRect(2, 2, 6, 6, (SkPath::Direction) 0);
path.addRect(1, 2, 4, 2, (SkPath::Direction) 0);
</div>
<div id="testLine68b">
path.addRect(0, 0, 8, 8, (SkPath::Direction) 0);
path.addRect(2, 2, 6, 6, (SkPath::Direction) 1);
path.addRect(1, 2, 4, 2, (SkPath::Direction) 0);
</div>
<div id="testLine68c">
path.addRect(0, 0, 8, 8, (SkPath::Direction) 1);
path.addRect(2, 2, 6, 6, (SkPath::Direction) 0);
path.addRect(1, 2, 4, 2, (SkPath::Direction) 0);
</div>
<div id="testLine68d">
path.addRect(0, 0, 8, 8, (SkPath::Direction) 1);
path.addRect(2, 2, 6, 6, (SkPath::Direction) 1);
path.addRect(1, 2, 4, 2, (SkPath::Direction) 0);
</div>
<div id="testLine68e">
path.addRect(0, 0, 8, 8, (SkPath::Direction) 0);
path.addRect(0, 0, 8, 8, (SkPath::Direction) 0);
path.addRect(2, 2, 6, 6, (SkPath::Direction) 1);
path.addRect(1, 2, 2, 2, (SkPath::Direction) 0);
</div>
<div id="testLine68f">
path.addRect(0, 0, 8, 8, (SkPath::Direction) 0);
path.addRect(2, 2, 6, 6, (SkPath::Direction) 1);
path.addRect(2, 2, 6, 6, (SkPath::Direction) 1);
path.addRect(1, 2, 2, 2, (SkPath::Direction) 0);
</div>
<div id="testLine69">
path.addRect(0, 20, 20, 20, (SkPath::Direction) 0);
path.addRect(0, 20, 12, 30, (SkPath::Direction) 0);
path.addRect(12, 32, 21, 36, (SkPath::Direction) 0);
</div>
<div id="testLine70">
path.addRect(0, 0, 20, 20, (SkPath::Direction) 0);
path.addRect(0, 24, 12, 12, (SkPath::Direction) 0);
path.addRect(12, 32, 21, 36, (SkPath::Direction) 1);
</div>
<div id="testLine71">
path.addRect(0, 0, 20, 20, (SkPath::Direction) 0);
path.addRect(12, 0, 24, 24, (SkPath::Direction) 0);
path.addRect(12, 32, 21, 36, (SkPath::Direction) 0);
</div>
</div>
<script type="text/javascript">
var testDivs = [
testLine71,
testLine70,
testLine69,
testLine68f,
testLine68e,
testLine68d,
testLine68c,
testLine68b,
testLine68a,
testLine67,
testLine66,
testLine65,
testLine64,
@ -671,9 +744,9 @@ var testDivs = [
testLine35,
testLine34,
testLine33,
testLine30,
testLine32,
testLine31,
testLine30,
testLine29,
testLine28,
testLine24,
@ -805,8 +878,8 @@ function parseRect(test, title) {
function init(test) {
var canvas = document.getElementById('canvas');
if (!canvas.getContext) return;
canvas.width = document.width;
canvas.height = document.height;
canvas.width = window.innerWidth - at_x;
canvas.height = window.innerHeight - at_y;
ctx = canvas.getContext('2d');
var xmin = Infinity;
var xmax = -Infinity;
@ -982,6 +1055,7 @@ function doKeyPress(evt) {
var char = String.fromCharCode(evt.charCode);
switch (char) {
case 'N':
testIndex += 9;
case 'n':
if (++testIndex >= tests.length)
testIndex = 0;
@ -989,6 +1063,7 @@ function doKeyPress(evt) {
drawTop();
break;
case 'P':
testIndex -= 9;
case 'p':
if (--testIndex < 0)
testIndex = tests.length - 1;
@ -999,15 +1074,19 @@ function doKeyPress(evt) {
case 't':
break;
case '-':
redraw();
drawTop();
break;
case '=':
case '+':
redraw();
drawTop();
break;
}
}
function doResize(evt) {
drawTop();
}
function start() {
for (i = 0; i < testDivs.length; ++i) {
var title = testDivs[i].id.toString();
@ -1020,6 +1099,9 @@ function start() {
}
drawTop();
window.addEventListener('keypress', doKeyPress, true);
window.onresize = function() {
drawTop();
}
}
</script>