shape ops work in progress
git-svn-id: http://skia.googlecode.com/svn/trunk@6961 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
6c406146ee
commit
10227bf467
@ -1927,127 +1927,94 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
int crossedSpanY(const SkPoint& basePt, SkScalar& bestY, double& hitT, bool& hitSomething,
|
int crossedSpanY(const SkPoint& basePt, SkScalar& bestY, double& hitT, bool& hitSomething,
|
||||||
bool opp) const {
|
double mid, bool opp, bool current) const {
|
||||||
SkScalar bottom = fBounds.fBottom;
|
SkScalar bottom = fBounds.fBottom;
|
||||||
int bestT = -1;
|
int bestTIndex = -1;
|
||||||
if (bottom <= bestY) {
|
if (bottom <= bestY) {
|
||||||
return bestT;
|
return bestTIndex;
|
||||||
}
|
}
|
||||||
SkScalar top = fBounds.fTop;
|
SkScalar top = fBounds.fTop;
|
||||||
if (top >= basePt.fY) {
|
if (top >= basePt.fY) {
|
||||||
return bestT;
|
return bestTIndex;
|
||||||
}
|
}
|
||||||
if (fBounds.fLeft > basePt.fX) {
|
if (fBounds.fLeft > basePt.fX) {
|
||||||
return bestT;
|
return bestTIndex;
|
||||||
}
|
}
|
||||||
if (fBounds.fRight < basePt.fX) {
|
if (fBounds.fRight < basePt.fX) {
|
||||||
return bestT;
|
return bestTIndex;
|
||||||
}
|
}
|
||||||
if (fBounds.fLeft == fBounds.fRight) {
|
if (fBounds.fLeft == fBounds.fRight) {
|
||||||
return bestT;
|
return bestTIndex;
|
||||||
}
|
}
|
||||||
int end = 0;
|
// intersect ray starting at basePt with edge
|
||||||
int xbestT = -1;
|
Intersections intersections;
|
||||||
double xhitT;
|
// OPTIMIZE: use specialty function that intersects ray with curve,
|
||||||
bool xhitSomething = false;
|
// returning t values only for curve (we don't care about t on ray)
|
||||||
SkScalar xbestY = bestY;
|
int pts = (*VSegmentIntersect[fVerb])(fPts, top, bottom, basePt.fX, false, intersections);
|
||||||
bool expectNoDx = false;
|
if (pts == 0 || (current && pts == 1)) {
|
||||||
do {
|
return bestTIndex;
|
||||||
int start = end;
|
}
|
||||||
end = nextSpan(start, 1);
|
if (current) {
|
||||||
if ((opp ? fTs[start].fOppValue : fTs[start].fWindValue) == 0) {
|
SkASSERT(pts > 1);
|
||||||
|
int closestIdx = 0;
|
||||||
|
double closest = fabs(intersections.fT[0][0] - mid);
|
||||||
|
for (int idx = 1; idx < pts; ++idx) {
|
||||||
|
double test = fabs(intersections.fT[0][idx] - mid);
|
||||||
|
if (closest > test) {
|
||||||
|
closestIdx = idx;
|
||||||
|
closest = test;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (closestIdx < pts - 1) {
|
||||||
|
intersections.fT[0][closestIdx] = intersections.fT[0][pts - 1];
|
||||||
|
}
|
||||||
|
--pts;
|
||||||
|
}
|
||||||
|
double bestT = -1;
|
||||||
|
for (int index = 0; index < pts; ++index) {
|
||||||
|
double foundT = intersections.fT[0][index];
|
||||||
|
SkScalar testY = (*SegmentYAtT[fVerb])(fPts, foundT);
|
||||||
|
if (approximately_negative(testY - bestY)
|
||||||
|
|| approximately_negative(basePt.fY - testY)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
SkPoint edge[4];
|
if (pts > 1 && fVerb == SkPath::kLine_Verb) {
|
||||||
double startT = fTs[start].fT;
|
// if the intersection is edge on, wait for another one
|
||||||
double endT = fTs[end].fT;
|
hitSomething = true;
|
||||||
(*SegmentSubDivide[fVerb])(fPts, startT, endT, edge);
|
return bestTIndex;
|
||||||
// intersect ray starting at basePt with edge
|
}
|
||||||
Intersections intersections, intersectionsX;
|
if (fVerb > SkPath::kLine_Verb && !approximately_less_than_zero(foundT)
|
||||||
// FIXME: always use original and limit results to T values within
|
&& !approximately_greater_than_one(foundT)) {
|
||||||
// start t and end t.
|
SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, foundT);
|
||||||
// OPTIMIZE: use specialty function that intersects ray with curve,
|
if (approximately_zero(dx)) {
|
||||||
// returning t values only for curve (we don't care about t on ray)
|
|
||||||
int pts = (*VSegmentIntersect[fVerb])(edge, top, bottom, basePt.fX,
|
|
||||||
false, intersections);
|
|
||||||
int ptsX = (*VSegmentIntersect[fVerb])(fPts, top, bottom, basePt.fX,
|
|
||||||
false, intersectionsX);
|
|
||||||
int index;
|
|
||||||
for (index = 0; index < ptsX; ++index) {
|
|
||||||
double xfoundT = intersectionsX.fT[0][index];
|
|
||||||
SkScalar xtestY = (*SegmentYAtT[fVerb])(fPts, xfoundT);
|
|
||||||
if (approximately_negative(xtestY - bestY)
|
|
||||||
|| approximately_negative(basePt.fY - xtestY)) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
xhitSomething = true;
|
|
||||||
if (pts > 1 && fVerb == SkPath::kLine_Verb) {
|
|
||||||
// if the intersection is edge on, wait for another one
|
|
||||||
expectNoDx = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (fVerb > SkPath::kLine_Verb
|
|
||||||
&& !approximately_negative(xfoundT - startT)
|
|
||||||
&& !approximately_negative(endT - xfoundT)) {
|
|
||||||
SkScalar xdx = (*SegmentDXAtT[fVerb])(fPts, xfoundT);
|
|
||||||
if (approximately_zero(xdx)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
xbestY = xtestY;
|
|
||||||
while (start + 1 < end && fTs[start].fDone) {
|
|
||||||
++start;
|
|
||||||
}
|
|
||||||
xbestT = xfoundT < 1 ? start : end;
|
|
||||||
xhitT = xfoundT;
|
|
||||||
}
|
}
|
||||||
for (index = 0; index < pts; ++index) {
|
bestY = testY;
|
||||||
double foundT = intersections.fT[0][index];
|
bestT = foundT;
|
||||||
SkScalar testY = (*SegmentYAtT[fVerb])(edge, foundT);
|
|
||||||
if (bestY < testY && testY < basePt.fY) {
|
|
||||||
hitSomething = true;
|
|
||||||
if (pts > 1 && fVerb == SkPath::kLine_Verb) {
|
|
||||||
// if the intersection is edge on, wait for another one
|
|
||||||
SkASSERT(expectNoDx);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (fVerb > SkPath::kLine_Verb
|
|
||||||
&& !approximately_less_than_zero(foundT)
|
|
||||||
&& !approximately_greater_than_one(foundT)) {
|
|
||||||
SkScalar dx = (*SegmentDXAtT[fVerb])(edge, foundT);
|
|
||||||
if (approximately_zero(dx)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bestY = testY;
|
|
||||||
while (start + 1 < end && fTs[start].fDone) {
|
|
||||||
++start;
|
|
||||||
}
|
|
||||||
bestT = foundT < 1 ? start : end;
|
|
||||||
hitT = startT + (endT - startT) * foundT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (fTs[end].fT != 1);
|
|
||||||
SkASSERT(!expectNoDx);
|
|
||||||
if (bestT != xbestT) {
|
|
||||||
SkDebugf("%s mismatch bestT=%d xbestT=%d\n", __FUNCTION__, bestT, xbestT);
|
|
||||||
bestT = xbestT;
|
|
||||||
}
|
}
|
||||||
if (bestY != xbestY) {
|
if (bestT < 0) {
|
||||||
SkDebugf("%s mismatch bestY=%1.9g xbestY=%1.9g\n", __FUNCTION__, bestY, xbestY);
|
return bestTIndex;
|
||||||
bestY = xbestY;
|
|
||||||
}
|
}
|
||||||
if (hitT != xhitT) {
|
SkASSERT(bestT >= 0);
|
||||||
SkDebugf("%s mismatch hitT=%1.9g xhitT=%1.9g\n", __FUNCTION__, hitT, xhitT);
|
SkASSERT(bestT <= 1);
|
||||||
hitT = xhitT;
|
int start;
|
||||||
|
int end = 0;
|
||||||
|
do {
|
||||||
|
start = end;
|
||||||
|
end = nextSpan(start, 1);
|
||||||
|
} while (fTs[end].fT < bestT);
|
||||||
|
// FIXME: see next candidate for a better pattern to find the next start/end pair
|
||||||
|
while (start + 1 < end && fTs[start].fDone) {
|
||||||
|
++start;
|
||||||
}
|
}
|
||||||
if (hitSomething != xhitSomething) {
|
int testTIndex = bestT < 1 ? start : end;
|
||||||
SkDebugf("%s mismatch hitSomething=%d xhitSomething=%d\n", __FUNCTION__, hitSomething,
|
if (!isCanceled(testTIndex)) {
|
||||||
xhitSomething);
|
hitT = bestT;
|
||||||
hitSomething = xhitSomething;
|
bestTIndex = testTIndex;
|
||||||
|
hitSomething = true;
|
||||||
}
|
}
|
||||||
|
return bestTIndex;
|
||||||
return bestT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void decrementSpan(Span* span) {
|
void decrementSpan(Span* span) {
|
||||||
@ -2965,6 +2932,10 @@ the same winding is shared by both.
|
|||||||
return fTs.count() > 0;
|
return fTs.count() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isCanceled(int tIndex) const {
|
||||||
|
return fTs[tIndex].fWindValue == 0 && fTs[tIndex].fOppValue == 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool isConnected(int startIndex, int endIndex) const {
|
bool isConnected(int startIndex, int endIndex) const {
|
||||||
return fTs[startIndex].fWindSum != SK_MinS32
|
return fTs[startIndex].fWindSum != SK_MinS32
|
||||||
|| fTs[endIndex].fWindSum != SK_MinS32;
|
|| fTs[endIndex].fWindSum != SK_MinS32;
|
||||||
@ -3452,13 +3423,14 @@ the same winding is shared by both.
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool nextCandidate(int& start, int& end) const {
|
bool nextCandidate(int& start, int& end) const {
|
||||||
do {
|
while (fTs[end].fDone) {
|
||||||
start = end;
|
if (fTs[end].fT == 1) {
|
||||||
if (fTs[start].fT == 1) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
end = nextExactSpan(start, 1);
|
++end;
|
||||||
} while (fTs[start].fDone);
|
}
|
||||||
|
start = end;
|
||||||
|
end = nextExactSpan(start, 1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3646,6 +3618,10 @@ the same winding is shared by both.
|
|||||||
return fTs[tIndex].fT;
|
return fTs[tIndex].fT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double tAtMid(int start, int end, double mid) const {
|
||||||
|
return fTs[start].fT * (1 - mid) + fTs[end].fT * mid;
|
||||||
|
}
|
||||||
|
|
||||||
bool tiny(const Angle* angle) const {
|
bool tiny(const Angle* angle) const {
|
||||||
int start = angle->start();
|
int start = angle->start();
|
||||||
int end = angle->end();
|
int end = angle->end();
|
||||||
@ -3735,17 +3711,6 @@ the same winding is shared by both.
|
|||||||
return fVerb;
|
return fVerb;
|
||||||
}
|
}
|
||||||
|
|
||||||
int windingAtTX(double tHit, int tIndex, bool crossOpp) const {
|
|
||||||
if (approximately_zero(tHit - t(tIndex))) { // if we hit the end of a span, disregard
|
|
||||||
return SK_MinS32;
|
|
||||||
}
|
|
||||||
int endIndex = nextSpan(tIndex, 1);
|
|
||||||
if (crossOpp) {
|
|
||||||
return updateOppWinding(tIndex, endIndex);
|
|
||||||
}
|
|
||||||
return updateWinding(tIndex, endIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
int windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar& dx) const {
|
int windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar& dx) const {
|
||||||
if (approximately_zero(tHit - t(tIndex))) { // if we hit the end of a span, disregard
|
if (approximately_zero(tHit - t(tIndex))) { // if we hit the end of a span, disregard
|
||||||
return SK_MinS32;
|
return SK_MinS32;
|
||||||
@ -3825,9 +3790,8 @@ the same winding is shared by both.
|
|||||||
}
|
}
|
||||||
|
|
||||||
// used only by right angle winding finding
|
// used only by right angle winding finding
|
||||||
void xyAtT(int start, int end, double mid, SkPoint& pt) const {
|
void xyAtT(double mid, SkPoint& pt) const {
|
||||||
double t = fTs[start].fT * (1 - mid) + fTs[end].fT * mid;
|
(*SegmentXYAtT[fVerb])(fPts, mid, &pt);
|
||||||
(*SegmentXYAtT[fVerb])(fPts, t, &pt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SkScalar yAtT(int index) const {
|
SkScalar yAtT(int index) const {
|
||||||
@ -4316,25 +4280,6 @@ public:
|
|||||||
fContainsIntercepts = true;
|
fContainsIntercepts = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
const Segment* crossedSegmentY(const SkPoint& basePt, SkScalar& bestY,
|
|
||||||
int &tIndex, double& hitT, bool opp) {
|
|
||||||
int segmentCount = fSegments.count();
|
|
||||||
const Segment* bestSegment = NULL;
|
|
||||||
for (int test = 0; test < segmentCount; ++test) {
|
|
||||||
Segment* testSegment = &fSegments[test];
|
|
||||||
double testHitT;
|
|
||||||
int testT = testSegment->crossedSpanY(basePt, bestY, testHitT, opp);
|
|
||||||
if (testT >= 0) {
|
|
||||||
bestSegment = testSegment;
|
|
||||||
tIndex = testT;
|
|
||||||
hitT = testHitT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return bestSegment;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool crosses(const Contour* crosser) const {
|
bool crosses(const Contour* crosser) const {
|
||||||
for (int index = 0; index < fCrosses.count(); ++index) {
|
for (int index = 0; index < fCrosses.count(); ++index) {
|
||||||
if (fCrosses[index] == crosser) {
|
if (fCrosses[index] == crosser) {
|
||||||
@ -4522,48 +4467,6 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0 // FIXME: obsolete, remove
|
|
||||||
// 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
|
|
||||||
// segments' top, and not a true sort, so it could be ameniable to regular
|
|
||||||
// sorting instead of linear searching. Still feel like I'm missing something
|
|
||||||
Segment* topSegment(SkScalar& bestY) {
|
|
||||||
int segmentCount = fSegments.count();
|
|
||||||
SkASSERT(segmentCount > 0);
|
|
||||||
int best = -1;
|
|
||||||
Segment* bestSegment = NULL;
|
|
||||||
while (++best < segmentCount) {
|
|
||||||
Segment* testSegment = &fSegments[best];
|
|
||||||
if (testSegment->done()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
bestSegment = testSegment;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!bestSegment) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
SkScalar bestTop = bestSegment->activeTop();
|
|
||||||
for (int test = best + 1; test < segmentCount; ++test) {
|
|
||||||
Segment* testSegment = &fSegments[test];
|
|
||||||
if (testSegment->done()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (testSegment->bounds().fTop > bestTop) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
SkScalar testTop = testSegment->activeTop();
|
|
||||||
if (bestTop > testTop) {
|
|
||||||
bestTop = testTop;
|
|
||||||
bestSegment = testSegment;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bestY = bestTop;
|
|
||||||
return bestSegment;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void topSortableSegment(const SkPoint& topLeft, SkPoint& bestXY, Segment*& topStart) {
|
void topSortableSegment(const SkPoint& topLeft, SkPoint& bestXY, Segment*& topStart) {
|
||||||
int segmentCount = fSortedSegments.count();
|
int segmentCount = fSortedSegments.count();
|
||||||
SkASSERT(segmentCount > 0);
|
SkASSERT(segmentCount > 0);
|
||||||
@ -5377,7 +5280,8 @@ static void coincidenceCheck(SkTDArray<Contour*>& contourList, int total) {
|
|||||||
static int contourRangeCheckY(SkTDArray<Contour*>& contourList, Segment*& current, int& index,
|
static int contourRangeCheckY(SkTDArray<Contour*>& contourList, Segment*& current, int& index,
|
||||||
int& endIndex, double& bestHit, SkScalar& bestDx, bool& tryAgain, double& mid, bool opp) {
|
int& endIndex, double& bestHit, SkScalar& bestDx, bool& tryAgain, double& mid, bool opp) {
|
||||||
SkPoint basePt;
|
SkPoint basePt;
|
||||||
current->xyAtT(index, endIndex, mid, basePt);
|
double tAtMid = current->tAtMid(index, endIndex, mid);
|
||||||
|
current->xyAtT(tAtMid, basePt);
|
||||||
int contourCount = contourList.count();
|
int contourCount = contourList.count();
|
||||||
SkScalar bestY = SK_ScalarMin;
|
SkScalar bestY = SK_ScalarMin;
|
||||||
Segment* bestSeg = NULL;
|
Segment* bestSeg = NULL;
|
||||||
@ -5398,7 +5302,8 @@ static int contourRangeCheckY(SkTDArray<Contour*>& contourList, Segment*& curre
|
|||||||
Segment* testSeg = &contour->segments()[test];
|
Segment* testSeg = &contour->segments()[test];
|
||||||
SkScalar testY = bestY;
|
SkScalar testY = bestY;
|
||||||
double testHit;
|
double testHit;
|
||||||
int testTIndex = testSeg->crossedSpanY(basePt, testY, testHit, hitSomething, testOpp);
|
int testTIndex = testSeg->crossedSpanY(basePt, testY, testHit, hitSomething, tAtMid,
|
||||||
|
testOpp, testSeg == current);
|
||||||
if (testTIndex < 0) {
|
if (testTIndex < 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -5408,8 +5313,10 @@ static int contourRangeCheckY(SkTDArray<Contour*>& contourList, Segment*& curre
|
|||||||
double newMid = (testHit - baseT) / (endT - baseT);
|
double newMid = (testHit - baseT) / (endT - baseT);
|
||||||
#if DEBUG_WINDING
|
#if DEBUG_WINDING
|
||||||
SkPoint midXY, newXY;
|
SkPoint midXY, newXY;
|
||||||
current->xyAtT(index, endIndex, mid, midXY);
|
double midT = current->tAtMid(index, endIndex, mid);
|
||||||
current->xyAtT(index, endIndex, newMid, newXY);
|
current->xyAtT(midT, midXY);
|
||||||
|
double newMidT = current->tAtMid(index, endIndex, newMid);
|
||||||
|
current->xyAtT(newMidT, newXY);
|
||||||
SkDebugf("%s [%d] mid=%1.9g->%1.9g s=%1.9g (%1.9g,%1.9g) m=%1.9g (%1.9g,%1.9g)"
|
SkDebugf("%s [%d] mid=%1.9g->%1.9g s=%1.9g (%1.9g,%1.9g) m=%1.9g (%1.9g,%1.9g)"
|
||||||
" n=%1.9g (%1.9g,%1.9g) e=%1.9g (%1.9g,%1.9g)\n", __FUNCTION__,
|
" n=%1.9g (%1.9g,%1.9g) e=%1.9g (%1.9g,%1.9g)\n", __FUNCTION__,
|
||||||
current->debugID(), mid, newMid,
|
current->debugID(), mid, newMid,
|
||||||
@ -5428,214 +5335,27 @@ static int contourRangeCheckY(SkTDArray<Contour*>& contourList, Segment*& curre
|
|||||||
bestY = testY;
|
bestY = testY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
int result;
|
||||||
if (!bestSeg) {
|
if (!bestSeg) {
|
||||||
return hitSomething ? SK_MinS32 : 0;
|
result = hitSomething ? SK_MinS32 : 0;
|
||||||
}
|
} else {
|
||||||
if (bestSeg->windSum(bestTIndex) == SK_MinS32) {
|
if (bestSeg->windSum(bestTIndex) == SK_MinS32) {
|
||||||
current = bestSeg;
|
current = bestSeg;
|
||||||
index = bestTIndex;
|
index = bestTIndex;
|
||||||
endIndex = bestSeg->nextSpan(bestTIndex, 1);
|
endIndex = bestSeg->nextSpan(bestTIndex, 1);
|
||||||
tryAgain = true;
|
SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
|
||||||
return 0;
|
tryAgain = true;
|
||||||
}
|
return 0;
|
||||||
int tryAnother = bestSeg->windingAtTX(bestHit, bestTIndex, bestOpp);
|
}
|
||||||
int result = bestSeg->windingAtT(bestHit, bestTIndex, bestOpp, bestDx);
|
result = bestSeg->windingAtT(bestHit, bestTIndex, bestOpp, bestDx);
|
||||||
if (result != tryAnother) {
|
SkASSERT(bestDx);
|
||||||
SkDebugf("%s result=%d tryAnother=%d\n", __FUNCTION__, result,
|
|
||||||
tryAnother);
|
|
||||||
}
|
}
|
||||||
double baseT = current->t(index);
|
double baseT = current->t(index);
|
||||||
double endT = current->t(endIndex);
|
double endT = current->t(endIndex);
|
||||||
bestHit = baseT + mid * (endT - baseT);
|
bestHit = baseT + mid * (endT - baseT);
|
||||||
SkASSERT(bestDx);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// project a ray from the top of the contour up and see if it hits anything
|
|
||||||
// note: when we compute line intersections, we keep track of whether
|
|
||||||
// two contours touch, so we need only look at contours not touching this one.
|
|
||||||
// OPTIMIZATION: sort contourList vertically to avoid linear walk
|
|
||||||
#if 0
|
|
||||||
static int innerContourCheck(SkTDArray<Contour*>& contourList,
|
|
||||||
const Segment* current, int index, int endIndex, bool opp) {
|
|
||||||
const SkPoint& basePt = current->xyAtT(endIndex);
|
|
||||||
int contourCount = contourList.count();
|
|
||||||
SkScalar bestY = SK_ScalarMin;
|
|
||||||
const Segment* test = NULL;
|
|
||||||
int tIndex;
|
|
||||||
double tHit;
|
|
||||||
bool crossOpp;
|
|
||||||
for (int cTest = 0; cTest < contourCount; ++cTest) {
|
|
||||||
Contour* contour = contourList[cTest];
|
|
||||||
bool testOpp = contour->operand() ^ current->operand() ^ opp;
|
|
||||||
if (basePt.fY < contour->bounds().fTop) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (bestY > contour->bounds().fBottom) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const Segment* next = contour->crossedSegmentY(basePt, bestY, tIndex, tHit, testOpp);
|
|
||||||
if (next) {
|
|
||||||
test = next;
|
|
||||||
crossOpp = testOpp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!test) {
|
|
||||||
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 (approximately_zero(tHit - test->t(tIndex))) {
|
|
||||||
SkTDArray<Angle> angles;
|
|
||||||
int end = test->nextSpan(tIndex, 1);
|
|
||||||
if (end < 0) {
|
|
||||||
end = test->nextSpan(tIndex, -1);
|
|
||||||
}
|
|
||||||
test->addTwoAngles(end, tIndex, angles);
|
|
||||||
SkASSERT(angles.count() > 0);
|
|
||||||
if (angles[0].segment()->yAtT(angles[0].start()) >= basePt.fY) {
|
|
||||||
#if DEBUG_SORT
|
|
||||||
SkDebugf("%s early return\n", __FUNCTION__);
|
|
||||||
#endif
|
|
||||||
return SK_MinS32;
|
|
||||||
}
|
|
||||||
test->buildAngles(tIndex, angles, false);
|
|
||||||
SkTDArray<Angle*> sorted;
|
|
||||||
// OPTIMIZATION: call a sort that, if base point is the leftmost,
|
|
||||||
// returns the first counterclockwise hour before 6 o'clock,
|
|
||||||
// or if the base point is rightmost, returns the first clockwise
|
|
||||||
// hour after 6 o'clock
|
|
||||||
bool sortable = Segment::SortAngles(angles, sorted);
|
|
||||||
if (!sortable) {
|
|
||||||
return SK_MinS32;
|
|
||||||
}
|
|
||||||
#if DEBUG_SORT
|
|
||||||
sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 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
|
|
||||||
// is 12 noon or an earlier hour (the next counterclockwise)
|
|
||||||
int count = sorted.count();
|
|
||||||
int left = -1;
|
|
||||||
int mid = -1;
|
|
||||||
int right = -1;
|
|
||||||
bool baseMatches = test->yAtT(tIndex) == basePt.fY;
|
|
||||||
for (int index = 0; index < count; ++index) {
|
|
||||||
angle = sorted[index];
|
|
||||||
if (angle->unsortable()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (baseMatches && angle->isHorizontal()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
double indexDx = angle->dx();
|
|
||||||
test = angle->segment();
|
|
||||||
if (test->verb() > SkPath::kLine_Verb && approximately_zero(indexDx)) {
|
|
||||||
const SkPoint* pts = test->pts();
|
|
||||||
indexDx = pts[2].fX - pts[1].fX - indexDx;
|
|
||||||
}
|
|
||||||
if (indexDx < 0) {
|
|
||||||
left = index;
|
|
||||||
} else if (indexDx > 0) {
|
|
||||||
right = index;
|
|
||||||
int previous = index - 1;
|
|
||||||
if (previous < 0) {
|
|
||||||
previous = count - 1;
|
|
||||||
}
|
|
||||||
const Angle* prev = sorted[previous];
|
|
||||||
if (prev->dy() >= 0 && prev->dx() > 0 && angle->dy() < 0) {
|
|
||||||
#if DEBUG_SORT
|
|
||||||
SkDebugf("%s use prev\n", __FUNCTION__);
|
|
||||||
#endif
|
|
||||||
right = previous;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
mid = index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((left < 0 || right < 0) && mid >= 0) {
|
|
||||||
angle = sorted[mid];
|
|
||||||
Segment* midSeg = angle->segment();
|
|
||||||
int end = angle->end();
|
|
||||||
if (midSeg->unsortable(end)) {
|
|
||||||
return SK_MinS32;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (left < 0 && right < 0) {
|
|
||||||
left = mid;
|
|
||||||
}
|
|
||||||
if (left < 0 && right < 0) {
|
|
||||||
SkASSERT(0);
|
|
||||||
return SK_MinS32; // unsortable
|
|
||||||
}
|
|
||||||
if (left < 0) {
|
|
||||||
left = right;
|
|
||||||
} else if (left >= 0 && mid >= 0 && right >= 0
|
|
||||||
&& sorted[mid]->sign() == sorted[right]->sign()) {
|
|
||||||
left = right;
|
|
||||||
}
|
|
||||||
angle = sorted[left];
|
|
||||||
test = angle->segment();
|
|
||||||
winding = crossOpp ? test->oppSum(angle) : test->windSum(angle);
|
|
||||||
SkASSERT(winding != SK_MinS32);
|
|
||||||
windValue = crossOpp ? test->oppValue(angle) : test->windValue(angle);
|
|
||||||
#if DEBUG_WINDING
|
|
||||||
SkDebugf("%s angle winding=%d windValue=%d sign=%d\n", __FUNCTION__, winding,
|
|
||||||
windValue, angle->sign());
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
// start here;
|
|
||||||
/*
|
|
||||||
FIXME: fails because the span found by findTop is not the span closest to vertical
|
|
||||||
intersecting the found point. Because the most vertical span could be done, and the
|
|
||||||
span found undone, findTop should not be changed. Instead, the spans at the found
|
|
||||||
point need to be sorted again, and the winding found below needs to be adjusted by
|
|
||||||
the span signs of the spans walking from vertical to the findTop span
|
|
||||||
findTop could but probably shouldn't compute this adjustment, since if the found span
|
|
||||||
already has computed winding, we won't get to innerContourCheck --
|
|
||||||
best solution -- findTop could check to see if found span already has computed winding
|
|
||||||
before returning adjustment
|
|
||||||
*/
|
|
||||||
#if 0
|
|
||||||
int windingTx = test->windingAtTX(tHit, tIndex, crossOpp);
|
|
||||||
SkScalar dx;
|
|
||||||
int windingT = test->windingAtT(tHit, tIndex, crossOpp, dx);
|
|
||||||
SkDebugf("%s windingTx=%d windingT=%d\n", __FUNCTION__, windingTx, windingT);
|
|
||||||
#endif
|
|
||||||
winding = crossOpp ? test->oppSum(tIndex) : test->windSum(tIndex);
|
|
||||||
if (winding == SK_MinS32) {
|
|
||||||
return SK_MinS32; // unsortable
|
|
||||||
}
|
|
||||||
windValue = crossOpp ? test->oppValue(tIndex) : test->windValue(tIndex);
|
|
||||||
#if DEBUG_WINDING
|
|
||||||
SkDebugf("%s single winding=%d windValue=%d\n", __FUNCTION__, winding,
|
|
||||||
windValue);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
// see if a + change in T results in a +/- change in X (compute x'(T))
|
|
||||||
SkScalar dx = (*SegmentDXAtT[test->verb()])(test->pts(), tHit);
|
|
||||||
if (test->verb() > SkPath::kLine_Verb && approximately_zero(dx)) {
|
|
||||||
const SkPoint* pts = test->pts();
|
|
||||||
dx = pts[2].fX - pts[1].fX - dx;
|
|
||||||
}
|
|
||||||
#if DEBUG_WINDING
|
|
||||||
SkDebugf("%s dx=%1.9g winding=%d\n", __FUNCTION__, dx, winding);
|
|
||||||
#endif
|
|
||||||
SkASSERT(dx != 0);
|
|
||||||
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
|
|
||||||
}
|
|
||||||
return winding;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static Segment* findUndone(SkTDArray<Contour*>& contourList, int& start, int& end) {
|
static Segment* findUndone(SkTDArray<Contour*>& contourList, int& start, int& end) {
|
||||||
int contourCount = contourList.count();
|
int contourCount = contourList.count();
|
||||||
Segment* result;
|
Segment* result;
|
||||||
@ -5794,14 +5514,6 @@ static void debugShowActiveSpans(SkTDArray<Contour*>& contourList) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if 0
|
|
||||||
static bool windingIsActive(int winding, int spanWinding) {
|
|
||||||
// FIXME: !spanWinding test must be superflorous, true?
|
|
||||||
return winding * spanWinding <= 0 && abs(winding) <= abs(spanWinding)
|
|
||||||
&& (!winding || !spanWinding || winding == -spanWinding);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static Segment* findSortableTop(SkTDArray<Contour*>& contourList, int& index,
|
static Segment* findSortableTop(SkTDArray<Contour*>& contourList, int& index,
|
||||||
int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool onlySortable) {
|
int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool onlySortable) {
|
||||||
Segment* result;
|
Segment* result;
|
||||||
@ -5838,27 +5550,6 @@ static Segment* findSortableTop(SkTDArray<Contour*>& contourList, int& index,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
static int updateWindings(const Segment* current, int index, int endIndex, int& spanWinding) {
|
|
||||||
int lesser = SkMin32(index, endIndex);
|
|
||||||
spanWinding = current->spanSign(index, endIndex);
|
|
||||||
int winding = current->windSum(lesser);
|
|
||||||
bool inner = useInnerWinding(winding - spanWinding, winding);
|
|
||||||
#if DEBUG_WINDING
|
|
||||||
SkDebugf("%s id=%d t=%1.9g spanWinding=%d winding=%d sign=%d"
|
|
||||||
" inner=%d result=%d\n",
|
|
||||||
__FUNCTION__, current->debugID(), current->t(lesser),
|
|
||||||
spanWinding, winding, SkSign32(index - endIndex),
|
|
||||||
useInnerWinding(winding - spanWinding, winding),
|
|
||||||
inner ? winding - spanWinding : winding);
|
|
||||||
#endif
|
|
||||||
if (inner) {
|
|
||||||
winding -= spanWinding;
|
|
||||||
}
|
|
||||||
return winding;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int rightAngleWinding(SkTDArray<Contour*>& contourList,
|
static int rightAngleWinding(SkTDArray<Contour*>& contourList,
|
||||||
Segment*& current, int& index, int& endIndex, double& tHit, SkScalar& hitDx, bool& tryAgain,
|
Segment*& current, int& index, int& endIndex, double& tHit, SkScalar& hitDx, bool& tryAgain,
|
||||||
bool opp) {
|
bool opp) {
|
||||||
@ -5917,18 +5608,6 @@ static Segment* findSortableTop(SkTDArray<Contour*>& contourList, bool& firstCon
|
|||||||
}
|
}
|
||||||
int contourWinding;
|
int contourWinding;
|
||||||
int oppContourWinding = 0;
|
int oppContourWinding = 0;
|
||||||
#if 0
|
|
||||||
contourWinding = innerContourCheck(contourList, current, index, endIndex, false);
|
|
||||||
if (contourWinding != SK_MinS32) {
|
|
||||||
if (binary) {
|
|
||||||
oppContourWinding = innerContourCheck(contourList, current, index, endIndex, true);
|
|
||||||
}
|
|
||||||
if (!binary || oppContourWinding != SK_MinS32) {
|
|
||||||
current->initWinding(index, endIndex, contourWinding, oppContourWinding);
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
// the simple upward projection of the unresolved points hit unsortable angles
|
// the simple upward projection of the unresolved points hit unsortable angles
|
||||||
// shoot rays at right angles to the segment to find its winding, ignoring angle cases
|
// shoot rays at right angles to the segment to find its winding, ignoring angle cases
|
||||||
bool tryAgain;
|
bool tryAgain;
|
||||||
@ -5938,7 +5617,9 @@ static Segment* findSortableTop(SkTDArray<Contour*>& contourList, bool& firstCon
|
|||||||
do {
|
do {
|
||||||
// if current is vertical, find another candidate which is not
|
// if current is vertical, find another candidate which is not
|
||||||
// if only remaining candidates are vertical, then they can be marked done
|
// if only remaining candidates are vertical, then they can be marked done
|
||||||
|
SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
|
||||||
skipVertical(contourList, current, index, endIndex);
|
skipVertical(contourList, current, index, endIndex);
|
||||||
|
SkASSERT(index != endIndex && index >= 0 && endIndex >= 0);
|
||||||
tryAgain = false;
|
tryAgain = false;
|
||||||
contourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, hitDx,
|
contourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, hitDx,
|
||||||
tryAgain, false);
|
tryAgain, false);
|
||||||
@ -6003,7 +5684,8 @@ static bool bridgeWinding(SkTDArray<Contour*>& contourList, PathWrapper& simple)
|
|||||||
current = next;
|
current = next;
|
||||||
index = nextStart;
|
index = nextStart;
|
||||||
endIndex = nextEnd;
|
endIndex = nextEnd;
|
||||||
} while (!simple.isClosed() && ((!unsortable) || !current->done()));
|
} while (!simple.isClosed() && ((!unsortable)
|
||||||
|
|| !current->done(SkMin32(index, endIndex))));
|
||||||
if (current->activeWinding(index, endIndex) && !simple.isClosed()) {
|
if (current->activeWinding(index, endIndex) && !simple.isClosed()) {
|
||||||
SkASSERT(unsortable);
|
SkASSERT(unsortable);
|
||||||
int min = SkMin32(index, endIndex);
|
int min = SkMin32(index, endIndex);
|
||||||
@ -6113,6 +5795,9 @@ static bool approximatelyEqual(const SkPoint& a, const SkPoint& b) {
|
|||||||
return AlmostEqualUlps(a.fX, b.fX) && AlmostEqualUlps(a.fY, b.fY);
|
return AlmostEqualUlps(a.fX, b.fX) && AlmostEqualUlps(a.fY, b.fY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool lessThan(SkTDArray<double>& distances, const int one, const int two) {
|
||||||
|
return distances[one] < distances[two];
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
check start and end of each contour
|
check start and end of each contour
|
||||||
if not the same, record them
|
if not the same, record them
|
||||||
@ -6157,67 +5842,64 @@ static void assemble(const PathWrapper& path, PathWrapper& simple) {
|
|||||||
SkTDArray<int> sLink, eLink;
|
SkTDArray<int> sLink, eLink;
|
||||||
sLink.setCount(count);
|
sLink.setCount(count);
|
||||||
eLink.setCount(count);
|
eLink.setCount(count);
|
||||||
SkTDArray<double> sBest, eBest;
|
int rIndex, iIndex;
|
||||||
sBest.setCount(count);
|
|
||||||
eBest.setCount(count);
|
|
||||||
int rIndex;
|
|
||||||
for (rIndex = 0; rIndex < count; ++rIndex) {
|
for (rIndex = 0; rIndex < count; ++rIndex) {
|
||||||
outer = runs[rIndex];
|
sLink[rIndex] = eLink[rIndex] = INT_MAX;
|
||||||
const Contour& oContour = contours[outer];
|
|
||||||
const SkPoint& oStart = oContour.start();
|
|
||||||
const SkPoint& oEnd = oContour.end();
|
|
||||||
double dx = oEnd.fX - oStart.fX;
|
|
||||||
double dy = oEnd.fY - oStart.fY;
|
|
||||||
double dist = dx * dx + dy * dy;
|
|
||||||
sBest[rIndex] = eBest[rIndex] = dist;
|
|
||||||
sLink[rIndex] = eLink[rIndex] = rIndex;
|
|
||||||
}
|
}
|
||||||
for (rIndex = 0; rIndex < count - 1; ++rIndex) {
|
SkTDArray<double> distances;
|
||||||
outer = runs[rIndex];
|
const int ends = count * 2; // all starts and ends
|
||||||
|
const int entries = (ends - 1) * count; // folded triangle : n * (n - 1) / 2
|
||||||
|
distances.setCount(entries);
|
||||||
|
for (rIndex = 0; rIndex < ends - 1; ++rIndex) {
|
||||||
|
outer = runs[rIndex >> 1];
|
||||||
const Contour& oContour = contours[outer];
|
const Contour& oContour = contours[outer];
|
||||||
const SkPoint& oStart = oContour.start();
|
const SkPoint& oPt = rIndex & 1 ? oContour.end() : oContour.start();
|
||||||
const SkPoint& oEnd = oContour.end();
|
const int row = rIndex < count - 1 ? rIndex * ends : (ends - rIndex - 2)
|
||||||
double bestStartDist = sBest[rIndex];
|
* ends - rIndex - 1;
|
||||||
double bestEndDist = eBest[rIndex];
|
for (iIndex = rIndex + 1; iIndex < ends; ++iIndex) {
|
||||||
for (int iIndex = rIndex + 1; iIndex < count; ++iIndex) {
|
int inner = runs[iIndex >> 1];
|
||||||
int inner = runs[iIndex];
|
|
||||||
const Contour& iContour = contours[inner];
|
const Contour& iContour = contours[inner];
|
||||||
const SkPoint& iStart = iContour.start();
|
const SkPoint& iPt = iIndex & 1 ? iContour.end() : iContour.start();
|
||||||
const SkPoint& iEnd = iContour.end();
|
double dx = iPt.fX - oPt.fX;
|
||||||
double dx = iStart.fX - oStart.fX;
|
double dy = iPt.fY - oPt.fY;
|
||||||
double dy = iStart.fY - oStart.fY;
|
|
||||||
double dist = dx * dx + dy * dy;
|
double dist = dx * dx + dy * dy;
|
||||||
if (bestStartDist > dist && sBest[iIndex] > dist) {
|
distances[row + iIndex] = dist; // oStart distance from iStart
|
||||||
sBest[iIndex] = bestStartDist = dist;
|
}
|
||||||
sLink[rIndex] = ~iIndex;
|
|
||||||
sLink[iIndex] = ~rIndex;
|
|
||||||
}
|
|
||||||
dx = iEnd.fX - oStart.fX;
|
|
||||||
dy = iEnd.fY - oStart.fY;
|
|
||||||
dist = dx * dx + dy * dy;
|
|
||||||
if (bestStartDist > dist && eBest[iIndex] > dist) {
|
|
||||||
eBest[iIndex] = bestStartDist = dist;
|
|
||||||
sLink[rIndex] = iIndex;
|
|
||||||
eLink[iIndex] = rIndex;
|
|
||||||
}
|
|
||||||
dx = iStart.fX - oEnd.fX;
|
|
||||||
dy = iStart.fY - oEnd.fY;
|
|
||||||
dist = dx * dx + dy * dy;
|
|
||||||
if (bestEndDist > dist && sBest[iIndex] > dist) {
|
|
||||||
sBest[iIndex] = bestEndDist = dist;
|
|
||||||
sLink[iIndex] = rIndex;
|
|
||||||
eLink[rIndex] = iIndex;
|
|
||||||
}
|
|
||||||
dx = iEnd.fX - oEnd.fX;
|
|
||||||
dy = iEnd.fY - oEnd.fY;
|
|
||||||
dist = dx * dx + dy * dy;
|
|
||||||
if (bestEndDist > dist && eBest[iIndex] > dist) {
|
|
||||||
eBest[iIndex] = bestEndDist = dist;
|
|
||||||
eLink[iIndex] = ~rIndex;
|
|
||||||
eLink[rIndex] = ~iIndex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
SkTDArray<int> sortedDist;
|
||||||
|
sortedDist.setCount(entries);
|
||||||
|
for (rIndex = 0; rIndex < entries; ++rIndex) {
|
||||||
|
sortedDist[rIndex] = rIndex;
|
||||||
|
}
|
||||||
|
QSort<SkTDArray<double>, int>(distances, sortedDist.begin(), sortedDist.end() - 1, lessThan);
|
||||||
|
int remaining = count; // number of start/end pairs
|
||||||
|
for (rIndex = 0; rIndex < entries; ++rIndex) {
|
||||||
|
int pair = sortedDist[rIndex];
|
||||||
|
int row = pair / ends;
|
||||||
|
int col = pair - row * ends;
|
||||||
|
int thingOne = row < col ? row : ends - row - 2;
|
||||||
|
int ndxOne = thingOne >> 1;
|
||||||
|
bool endOne = thingOne & 1;
|
||||||
|
int* linkOne = endOne ? eLink.begin() : sLink.begin();
|
||||||
|
if (linkOne[ndxOne] != INT_MAX) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int thingTwo = row < col ? col : ends - row + col - 1;
|
||||||
|
int ndxTwo = thingTwo >> 1;
|
||||||
|
bool endTwo = thingTwo & 1;
|
||||||
|
int* linkTwo = endTwo ? eLink.begin() : sLink.begin();
|
||||||
|
if (linkTwo[ndxTwo] != INT_MAX) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
SkASSERT(&linkOne[ndxOne] != &linkTwo[ndxTwo]);
|
||||||
|
bool flip = endOne == endTwo;
|
||||||
|
linkOne[ndxOne] = flip ? ~ndxTwo : ndxTwo;
|
||||||
|
linkTwo[ndxTwo] = flip ? ~ndxOne : ndxOne;
|
||||||
|
if (!--remaining) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SkASSERT(!remaining);
|
||||||
#if DEBUG_ASSEMBLE
|
#if DEBUG_ASSEMBLE
|
||||||
for (rIndex = 0; rIndex < count; ++rIndex) {
|
for (rIndex = 0; rIndex < count; ++rIndex) {
|
||||||
int s = sLink[rIndex];
|
int s = sLink[rIndex];
|
||||||
|
@ -3282,12 +3282,82 @@ static void testQuadratic83() {
|
|||||||
testSimplifyx(path);
|
testSimplifyx(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void (*firstTest)() = testQuadratic83;
|
static void testQuadratic84() {
|
||||||
|
SkPath path, pathB;
|
||||||
|
path.moveTo(0, 0);
|
||||||
|
path.quadTo(2, 0, 1, 1);
|
||||||
|
path.lineTo(2, 1);
|
||||||
|
path.close();
|
||||||
|
path.moveTo(1, 0);
|
||||||
|
path.lineTo(2, 0);
|
||||||
|
path.quadTo(0, 1, 2, 2);
|
||||||
|
path.close();
|
||||||
|
testSimplifyx(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testQuadratic85() {
|
||||||
|
SkPath path, pathB;
|
||||||
|
path.moveTo(0, 0);
|
||||||
|
path.quadTo(3, 0, 1, 1);
|
||||||
|
path.lineTo(1, 1);
|
||||||
|
path.close();
|
||||||
|
path.moveTo(1, 0);
|
||||||
|
path.lineTo(3, 0);
|
||||||
|
path.quadTo(0, 1, 1, 2);
|
||||||
|
path.close();
|
||||||
|
testSimplifyx(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testQuadratic86() {
|
||||||
|
SkPath path, pathB;
|
||||||
|
path.moveTo(0, 0);
|
||||||
|
path.quadTo(0, 1, 1, 1);
|
||||||
|
path.lineTo(2, 3);
|
||||||
|
path.close();
|
||||||
|
path.moveTo(0, 0);
|
||||||
|
path.lineTo(0, 0);
|
||||||
|
path.quadTo(1, 1, 1, 3);
|
||||||
|
path.close();
|
||||||
|
testSimplifyx(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testQuadratic87() {
|
||||||
|
SkPath path, pathB;
|
||||||
|
path.moveTo(0, 0);
|
||||||
|
path.quadTo(2, 1, 0, 2);
|
||||||
|
path.lineTo(2, 3);
|
||||||
|
path.close();
|
||||||
|
path.moveTo(0, 0);
|
||||||
|
path.lineTo(1, 1);
|
||||||
|
path.quadTo(0, 2, 3, 2);
|
||||||
|
path.close();
|
||||||
|
testSimplifyx(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testQuadratic88() {
|
||||||
|
SkPath path, pathB;
|
||||||
|
path.moveTo(0, 0);
|
||||||
|
path.quadTo(2, 1, 0, 2);
|
||||||
|
path.lineTo(2, 2);
|
||||||
|
path.close();
|
||||||
|
path.moveTo(1, 0);
|
||||||
|
path.lineTo(1, 1);
|
||||||
|
path.quadTo(0, 2, 2, 2);
|
||||||
|
path.close();
|
||||||
|
testSimplifyx(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void (*firstTest)() = testQuadratic88;
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
void (*fun)();
|
void (*fun)();
|
||||||
const char* str;
|
const char* str;
|
||||||
} tests[] = {
|
} tests[] = {
|
||||||
|
TEST(testQuadratic88),
|
||||||
|
TEST(testQuadratic87),
|
||||||
|
TEST(testQuadratic86),
|
||||||
|
TEST(testQuadratic85),
|
||||||
|
TEST(testQuadratic84),
|
||||||
TEST(testQuadratic83),
|
TEST(testQuadratic83),
|
||||||
TEST(testQuadratic82),
|
TEST(testQuadratic82),
|
||||||
TEST(testQuadratic81),
|
TEST(testQuadratic81),
|
||||||
|
@ -3101,11 +3101,71 @@ path.close();
|
|||||||
path.close();
|
path.close();
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="testQuadratic84">
|
||||||
|
path.moveTo(0, 0);
|
||||||
|
path.quadTo(2, 0, 1, 1);
|
||||||
|
path.lineTo(2, 1);
|
||||||
|
path.close();
|
||||||
|
path.moveTo(1, 0);
|
||||||
|
path.lineTo(2, 0);
|
||||||
|
path.quadTo(0, 1, 2, 2);
|
||||||
|
path.close();
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="testQuadratic85">
|
||||||
|
path.moveTo(0, 0);
|
||||||
|
path.quadTo(3, 0, 1, 1);
|
||||||
|
path.lineTo(1, 1);
|
||||||
|
path.close();
|
||||||
|
path.moveTo(1, 0);
|
||||||
|
path.lineTo(3, 0);
|
||||||
|
path.quadTo(0, 1, 1, 2);
|
||||||
|
path.close();
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="testQuadratic86">
|
||||||
|
path.moveTo(0, 0);
|
||||||
|
path.quadTo(0, 1, 1, 1);
|
||||||
|
path.lineTo(2, 3);
|
||||||
|
path.close();
|
||||||
|
path.moveTo(0, 0);
|
||||||
|
path.lineTo(0, 0);
|
||||||
|
path.quadTo(1, 1, 1, 3);
|
||||||
|
path.close();
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="testQuadratic87">
|
||||||
|
path.moveTo(0, 0);
|
||||||
|
path.quadTo(2, 1, 0, 2);
|
||||||
|
path.lineTo(2, 3);
|
||||||
|
path.close();
|
||||||
|
path.moveTo(0, 0);
|
||||||
|
path.lineTo(1, 1);
|
||||||
|
path.quadTo(0, 2, 3, 2);
|
||||||
|
path.close();
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="testQuadratic88">
|
||||||
|
path.moveTo(0, 0);
|
||||||
|
path.quadTo(2, 1, 0, 2);
|
||||||
|
path.lineTo(2, 2);
|
||||||
|
path.close();
|
||||||
|
path.moveTo(1, 0);
|
||||||
|
path.lineTo(1, 1);
|
||||||
|
path.quadTo(0, 2, 2, 2);
|
||||||
|
path.close();
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
||||||
var testDivs = [
|
var testDivs = [
|
||||||
|
testQuadratic88,
|
||||||
|
testQuadratic87,
|
||||||
|
testQuadratic86,
|
||||||
|
testQuadratic85,
|
||||||
|
testQuadratic84,
|
||||||
testQuadratic83,
|
testQuadratic83,
|
||||||
testQuadratic82,
|
testQuadratic82,
|
||||||
testQuadratic81,
|
testQuadratic81,
|
||||||
|
Loading…
Reference in New Issue
Block a user