зеркало из https://github.com/mozilla/moz-skia.git
shape ops work in progress
git-svn-id: http://skia.googlecode.com/svn/trunk@4771 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
Родитель
777c3aab0a
Коммит
cc90505674
|
@ -487,7 +487,7 @@ public:
|
|||
return fEnd;
|
||||
}
|
||||
|
||||
bool firstBump(int contourWinding, int sumWinding) const {
|
||||
bool firstBump(int sumWinding) const {
|
||||
return sign() * sumWinding > 0;
|
||||
}
|
||||
|
||||
|
@ -755,6 +755,117 @@ public:
|
|||
angle->set(edge, fVerb, this, start, end);
|
||||
}
|
||||
|
||||
void addCancelOutsides(const SkTDArray<double>& outsideTs, Segment& other,
|
||||
double oEnd) {
|
||||
int tIndex = -1;
|
||||
int tCount = fTs.count();
|
||||
int oIndex = -1;
|
||||
int oCount = other.fTs.count();
|
||||
double tStart = outsideTs[0];
|
||||
double oStart = outsideTs[1];
|
||||
do {
|
||||
++tIndex;
|
||||
} while (tStart - fTs[tIndex].fT >= FLT_EPSILON && tIndex < tCount);
|
||||
int tIndexStart = tIndex;
|
||||
do {
|
||||
++oIndex;
|
||||
} while (oStart - other.fTs[oIndex].fT >= FLT_EPSILON && oIndex < oCount);
|
||||
int oIndexStart = oIndex;
|
||||
double nextT;
|
||||
do {
|
||||
nextT = fTs[++tIndex].fT;
|
||||
} while (nextT < 1 && nextT - tStart < FLT_EPSILON);
|
||||
double oNextT;
|
||||
do {
|
||||
oNextT = other.fTs[++oIndex].fT;
|
||||
} while (oNextT < 1 && oNextT - oStart < FLT_EPSILON);
|
||||
// at this point, spans before and after are at:
|
||||
// fTs[tIndexStart - 1], fTs[tIndexStart], fTs[tIndex]
|
||||
// if tIndexStart == 0, no prior span
|
||||
// if nextT == 1, no following span
|
||||
|
||||
// advance the span with zero winding
|
||||
// if the following span exists (not past the end, non-zero winding)
|
||||
// connect the two edges
|
||||
if (!fTs[tIndexStart].fWindValue) {
|
||||
if (tIndexStart > 0 && fTs[tIndexStart - 1].fWindValue) {
|
||||
#if DEBUG_CONCIDENT
|
||||
SkDebugf("%s 1 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
|
||||
__FUNCTION__, fID, other.fID, tIndexStart - 1,
|
||||
fTs[tIndexStart - 1].fT, xyAtT(tIndexStart - 1).fX,
|
||||
xyAtT(tIndexStart - 1).fY);
|
||||
#endif
|
||||
SkASSERT(0); // incomplete
|
||||
}
|
||||
if (nextT < 1 && fTs[tIndex].fWindValue) {
|
||||
#if DEBUG_CONCIDENT
|
||||
SkDebugf("%s 2 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
|
||||
__FUNCTION__, fID, other.fID, tIndex,
|
||||
fTs[tIndex].fT, xyAtT(tIndex).fX,
|
||||
xyAtT(tIndex).fY);
|
||||
#endif
|
||||
addTPair(fTs[tIndex].fT, other, other.fTs[oIndexStart].fT);
|
||||
}
|
||||
} else {
|
||||
SkASSERT(!other.fTs[oIndexStart].fWindValue);
|
||||
if (oIndexStart > 0 && other.fTs[oIndexStart - 1].fWindValue) {
|
||||
#if DEBUG_CONCIDENT
|
||||
SkDebugf("%s 3 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
|
||||
__FUNCTION__, fID, other.fID, oIndexStart - 1,
|
||||
other.fTs[oIndexStart - 1].fT, other.xyAtT(oIndexStart - 1).fX,
|
||||
other.xyAtT(oIndexStart - 1).fY);
|
||||
#endif
|
||||
SkASSERT(0); // incomplete
|
||||
}
|
||||
if (oNextT < 1 && other.fTs[oIndex].fWindValue) {
|
||||
#if DEBUG_CONCIDENT
|
||||
SkDebugf("%s 4 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n",
|
||||
__FUNCTION__, fID, other.fID, oIndex,
|
||||
other.fTs[oIndex].fT, other.xyAtT(oIndex).fX,
|
||||
other.xyAtT(oIndex).fY);
|
||||
other.debugAddTPair(other.fTs[oIndex].fT, *this, fTs[tIndexStart].fT);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void addCoinOutsides(const SkTDArray<double>& outsideTs, Segment& other,
|
||||
double oEnd) {
|
||||
// walk this to outsideTs[0]
|
||||
// walk other to outsideTs[1]
|
||||
// if either is > 0, add a pointer to the other, copying adjacent winding
|
||||
int tIndex = -1;
|
||||
int oIndex = -1;
|
||||
double tStart = outsideTs[0];
|
||||
double oStart = outsideTs[1];
|
||||
do {
|
||||
++tIndex;
|
||||
} while (tStart - fTs[tIndex].fT >= FLT_EPSILON);
|
||||
do {
|
||||
++oIndex;
|
||||
} while (oStart - other.fTs[oIndex].fT >= FLT_EPSILON);
|
||||
if (tIndex > 0 || oIndex > 0) {
|
||||
addTPair(tStart, other, oStart);
|
||||
}
|
||||
tStart = fTs[tIndex].fT;
|
||||
oStart = other.fTs[oIndex].fT;
|
||||
do {
|
||||
double nextT;
|
||||
do {
|
||||
nextT = fTs[++tIndex].fT;
|
||||
} while (nextT - tStart < FLT_EPSILON);
|
||||
tStart = nextT;
|
||||
do {
|
||||
nextT = other.fTs[++oIndex].fT;
|
||||
} while (nextT - oStart < FLT_EPSILON);
|
||||
oStart = nextT;
|
||||
if (tStart == 1 && oStart == 1) {
|
||||
break;
|
||||
}
|
||||
addTPair(tStart, other, oStart);
|
||||
} while (tStart < 1 && oStart < 1 && oEnd - oStart >= FLT_EPSILON);
|
||||
}
|
||||
|
||||
void addCubic(const SkPoint pts[4]) {
|
||||
init(pts, SkPath::kCubic_Verb);
|
||||
fBounds.setCubicBounds(pts);
|
||||
|
@ -889,13 +1000,14 @@ public:
|
|||
SkTDArray<double> oOutsideTs;
|
||||
do {
|
||||
bool decrement = test->fWindValue && oTest->fWindValue;
|
||||
bool track = test->fWindValue || oTest->fWindValue;
|
||||
Span* end = test;
|
||||
double startT = end->fT;
|
||||
double oStartT = oTest->fT;
|
||||
do {
|
||||
if (decrement) {
|
||||
decrementSpan(end);
|
||||
} else {
|
||||
} else if (track && end->fT < 1 && oStartT < 1) {
|
||||
TrackOutside(outsideTs, end->fT, oStartT);
|
||||
}
|
||||
end = &fTs[++index];
|
||||
|
@ -904,7 +1016,7 @@ public:
|
|||
do {
|
||||
if (decrement) {
|
||||
other.decrementSpan(oTestStart);
|
||||
} else {
|
||||
} else if (track && oTestStart->fT < 1 && startT < 1) {
|
||||
TrackOutside(oOutsideTs, oTestStart->fT, startT);
|
||||
}
|
||||
if (!oIndex) {
|
||||
|
@ -917,11 +1029,11 @@ public:
|
|||
} while (test->fT < endT - FLT_EPSILON);
|
||||
SkASSERT(!oIndex || oTest->fT <= oStartT - FLT_EPSILON);
|
||||
// FIXME: determine if canceled edges need outside ts added
|
||||
if (false && !done() && outsideTs.count()) {
|
||||
addTOutsides(outsideTs, other, oEndT);
|
||||
if (!done() && outsideTs.count()) {
|
||||
addCancelOutsides(outsideTs, other, oEndT);
|
||||
}
|
||||
if (false && !other.done() && oOutsideTs.count()) {
|
||||
other.addTOutsides(oOutsideTs, *this, endT);
|
||||
if (!other.done() && oOutsideTs.count()) {
|
||||
other.addCancelOutsides(oOutsideTs, *this, endT);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -942,13 +1054,17 @@ public:
|
|||
Span* test = &fTs[index];
|
||||
Span* oTest = &other.fTs[oIndex];
|
||||
SkTDArray<double> outsideTs;
|
||||
SkTDArray<double> xOutsideTs;
|
||||
SkTDArray<double> oOutsideTs;
|
||||
SkTDArray<double> oxOutsideTs;
|
||||
do {
|
||||
bool transfer = test->fWindValue && oTest->fWindValue;
|
||||
bool decrementOther = test->fWindValue >= oTest->fWindValue;
|
||||
Span* end = test;
|
||||
double startT = end->fT;
|
||||
int startIndex = index;
|
||||
double oStartT = oTest->fT;
|
||||
int oStartIndex = oIndex;
|
||||
do {
|
||||
if (transfer) {
|
||||
if (decrementOther) {
|
||||
|
@ -957,6 +1073,11 @@ public:
|
|||
} else if (decrementSpan(end)) {
|
||||
TrackOutside(outsideTs, end->fT, oStartT);
|
||||
}
|
||||
} else if (oTest->fWindValue) {
|
||||
SkASSERT(!decrementOther);
|
||||
if (startIndex > 0 && fTs[startIndex - 1].fWindValue) {
|
||||
TrackOutside(xOutsideTs, end->fT, oStartT);
|
||||
}
|
||||
}
|
||||
end = &fTs[++index];
|
||||
} while (end->fT - test->fT < FLT_EPSILON);
|
||||
|
@ -969,6 +1090,11 @@ public:
|
|||
} else if (other.decrementSpan(oEnd)) {
|
||||
TrackOutside(oOutsideTs, oEnd->fT, startT);
|
||||
}
|
||||
} else if (test->fWindValue) {
|
||||
SkASSERT(!decrementOther);
|
||||
if (oStartIndex > 0 && other.fTs[oStartIndex - 1].fWindValue) {
|
||||
SkASSERT(0); // track for later?
|
||||
}
|
||||
}
|
||||
oEnd = &other.fTs[++oIndex];
|
||||
} while (oEnd->fT - oTest->fT < FLT_EPSILON);
|
||||
|
@ -977,67 +1103,36 @@ public:
|
|||
} while (test->fT < endT - FLT_EPSILON);
|
||||
SkASSERT(oTest->fT < oEndT + FLT_EPSILON);
|
||||
SkASSERT(oTest->fT > oEndT - FLT_EPSILON);
|
||||
if (!done() && outsideTs.count()) {
|
||||
addTOutsides(outsideTs, other, oEndT);
|
||||
if (!done()) {
|
||||
if (outsideTs.count()) {
|
||||
addCoinOutsides(outsideTs, other, oEndT);
|
||||
}
|
||||
if (xOutsideTs.count()) {
|
||||
addCoinOutsides(xOutsideTs, other, oEndT);
|
||||
}
|
||||
}
|
||||
if (!other.done() && oOutsideTs.count()) {
|
||||
other.addTOutsides(oOutsideTs, *this, endT);
|
||||
other.addCoinOutsides(oOutsideTs, *this, endT);
|
||||
}
|
||||
}
|
||||
|
||||
void addTOutsides(const SkTDArray<double>& outsideTs, Segment& other,
|
||||
double oEnd) {
|
||||
// walk this to outsideTs[0]
|
||||
// walk other to outsideTs[1]
|
||||
// if either is > 0, add a pointer to the other, copying adjacent winding
|
||||
int tIndex = -1;
|
||||
int tCount = fTs.count();
|
||||
int oIndex = -1;
|
||||
int oCount = other.fTs.count();
|
||||
double tStart = outsideTs[0];
|
||||
double oStart = outsideTs[1];
|
||||
Span* tSpan;
|
||||
Span* oSpan;
|
||||
do {
|
||||
tSpan = &fTs[++tIndex];
|
||||
if (tStart - tSpan->fT < FLT_EPSILON) {
|
||||
break;
|
||||
}
|
||||
} while (tIndex < tCount);
|
||||
do {
|
||||
oSpan = &other.fTs[++oIndex];
|
||||
if (oStart - oSpan->fT < FLT_EPSILON) {
|
||||
break;
|
||||
}
|
||||
} while (oIndex < oCount);
|
||||
if (tIndex > 0 || oIndex > 0) {
|
||||
addTPair(tStart, other, oStart);
|
||||
// note: counts for fT, other.fT are one greater
|
||||
} else {
|
||||
--tCount;
|
||||
--oCount;
|
||||
}
|
||||
tStart = fTs[tIndex].fT;
|
||||
oStart = other.fTs[oIndex].fT;
|
||||
do {
|
||||
do {
|
||||
tSpan = &fTs[++tIndex];
|
||||
} while (tSpan->fT - tStart < FLT_EPSILON && tIndex < tCount);
|
||||
tStart = fTs[tIndex].fT;
|
||||
do {
|
||||
oSpan = &other.fTs[++oIndex];
|
||||
} while (oSpan->fT - oStart < FLT_EPSILON && oIndex < oCount);
|
||||
oStart = other.fTs[oIndex].fT;
|
||||
if (tStart == 1 && oStart == 1) {
|
||||
break;
|
||||
}
|
||||
addTPair(tStart, other, oStart);
|
||||
++tCount;
|
||||
++oCount;
|
||||
} while (tStart < 1 && oStart < 1 && oEnd - oSpan->fT >= FLT_EPSILON);
|
||||
}
|
||||
|
||||
// FIXME: this doesn't prevent the same span from being added twice
|
||||
// fix in caller, assert here?
|
||||
void addTPair(double t, Segment& other, double otherT) {
|
||||
int tCount = fTs.count();
|
||||
for (int tIndex = 0; tIndex < tCount; ++tIndex) {
|
||||
const Span& span = fTs[tIndex];
|
||||
if (span.fT > t) {
|
||||
break;
|
||||
}
|
||||
if (span.fT == t && span.fOther == &other && span.fOtherT == otherT) {
|
||||
#if DEBUG_ADD_T_PAIR
|
||||
SkDebugf("%s addTPair duplicate this=%d %1.9g other=%d %1.9g\n",
|
||||
__FUNCTION__, fID, t, other.fID, otherT);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
}
|
||||
#if DEBUG_ADD_T_PAIR
|
||||
SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n",
|
||||
__FUNCTION__, fID, t, other.fID, otherT);
|
||||
|
@ -1229,13 +1324,18 @@ public:
|
|||
int contourWinding, bool firstFind, bool active,
|
||||
const int startIndex, const int endIndex, int& nextStart,
|
||||
int& nextEnd, int& spanWinding) {
|
||||
|
||||
start here;
|
||||
// winding is a mess
|
||||
// try to simplify what we got
|
||||
|
||||
int flipped = 1;
|
||||
int sumWinding = winding + spanWinding;
|
||||
if (sumWinding == 0) {
|
||||
if (sumWinding == 0 || (false && contourWinding && !firstFind)) {
|
||||
sumWinding = spanWinding;
|
||||
}
|
||||
bool insideContour = contourWinding && contourWinding * sumWinding < 0;
|
||||
if (insideContour) {
|
||||
if (insideContour && (true || !firstFind)) {
|
||||
sumWinding = contourWinding;
|
||||
}
|
||||
|
||||
|
@ -1280,7 +1380,7 @@ public:
|
|||
#if DEBUG_SORT
|
||||
debugShowSort(sorted, firstIndex, contourWinding, sumWinding);
|
||||
#endif
|
||||
bool doBump = sorted[firstIndex]->firstBump(contourWinding, sumWinding);
|
||||
bool doBump = sorted[firstIndex]->firstBump(sumWinding);
|
||||
#if DEBUG_WINDING
|
||||
SkDebugf("%s sumWinding=%d sign=%d (%sbump)\n", __FUNCTION__,
|
||||
sumWinding, sorted[firstIndex]->sign(), doBump ? "" : "no ");
|
||||
|
@ -1343,6 +1443,10 @@ public:
|
|||
continue;
|
||||
}
|
||||
if (!maxWinding && innerSwap && !foundAngle) {
|
||||
if (sumWinding * startWinding < 0 && flipped > 0) {
|
||||
SkDebugf("%s flip?\n");
|
||||
// flipped = -flipped;
|
||||
}
|
||||
foundAngle = nextAngle;
|
||||
}
|
||||
if (nextSegment->done()) {
|
||||
|
@ -1950,6 +2054,18 @@ public:
|
|||
}
|
||||
#endif
|
||||
|
||||
#if DEBUG_CONCIDENT
|
||||
// assert if pair has not already been added
|
||||
void debugAddTPair(double t, const Segment& other, double otherT) {
|
||||
for (int i = 0; i < fTs.count(); ++i) {
|
||||
if (fTs[i].fT == t && fTs[i].fOther == &other && fTs[i].fOtherT == otherT) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
SkASSERT(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DEBUG_CONCIDENT
|
||||
void debugShowTs() {
|
||||
SkDebugf("%s %d", __FUNCTION__, fID);
|
||||
|
@ -1992,7 +2108,7 @@ public:
|
|||
void debugShowSort(const SkTDArray<Angle*>& angles, int first,
|
||||
int contourWinding, int sumWinding) {
|
||||
SkASSERT(angles[first]->segment() == this);
|
||||
bool doBump = angles[first]->firstBump(contourWinding, sumWinding);
|
||||
bool doBump = angles[first]->firstBump(sumWinding);
|
||||
bool insideContour = contourWinding && contourWinding * sumWinding < 0;
|
||||
int windSum = insideContour ? contourWinding : sumWinding;
|
||||
int lastSum = windSum;
|
||||
|
@ -2979,7 +3095,7 @@ static int innerContourCheck(SkTDArray<Contour*>& contourList,
|
|||
SkASSERT(winding != SK_MinS32);
|
||||
windValue = test->windValue(angle);
|
||||
#if 0
|
||||
if (angle->firstBump(0, winding)) {
|
||||
if (angle->firstBump(winding)) {
|
||||
winding -= test->windBump(angle);
|
||||
}
|
||||
#endif
|
||||
|
@ -3083,7 +3199,7 @@ static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex,
|
|||
angle->segment()->debugShowSort(sorted, firstIndex, contourWinding,
|
||||
spanWinding);
|
||||
#endif
|
||||
if (angle->firstBump(contourWinding, spanWinding)) {
|
||||
if (angle->firstBump(spanWinding)) {
|
||||
spanWinding -= angle->segment()->windBump(angle);
|
||||
}
|
||||
// we care about first sign and whether wind sum indicates this
|
||||
|
@ -3150,7 +3266,7 @@ static void bridge(SkTDArray<Contour*>& contourList, SkPath& simple) {
|
|||
Segment* topStart = findTopContour(contourList, topContour);
|
||||
if (!topStart) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Start at the top. Above the top is outside, below is inside.
|
||||
// follow edges to intersection by changing the index by direction.
|
||||
int index, endIndex;
|
||||
|
|
|
@ -566,12 +566,30 @@ static void testLine57() {
|
|||
testSimplifyx(path);
|
||||
}
|
||||
|
||||
static void (*firstTest)() = testLine57;
|
||||
static void testLine58() {
|
||||
SkPath path, simple;
|
||||
path.addRect(0, 0, 20, 20, (SkPath::Direction) 0);
|
||||
path.addRect(0, 0, 12, 12, (SkPath::Direction) 1);
|
||||
path.addRect(0, 12, 9, 9, (SkPath::Direction) 1);
|
||||
testSimplifyx(path);
|
||||
}
|
||||
|
||||
static void testLine59() {
|
||||
SkPath path, simple;
|
||||
path.addRect(0, 0, 20, 20, (SkPath::Direction) 0);
|
||||
path.addRect(6, 6, 18, 18, (SkPath::Direction) 1);
|
||||
path.addRect(4, 4, 13, 13, (SkPath::Direction) 1);
|
||||
testSimplifyx(path);
|
||||
}
|
||||
|
||||
static void (*firstTest)() = 0;
|
||||
|
||||
static struct {
|
||||
void (*fun)();
|
||||
const char* str;
|
||||
} tests[] = {
|
||||
TEST(testLine59),
|
||||
TEST(testLine58),
|
||||
TEST(testLine57),
|
||||
TEST(testLine56),
|
||||
TEST(testLine55),
|
||||
|
|
|
@ -325,6 +325,16 @@ path.close();
|
|||
testSimplifyx(path);
|
||||
</div>
|
||||
|
||||
<div id="testLine7b">
|
||||
path.moveTo(0,0);
|
||||
path.lineTo(4,0);
|
||||
path.close();
|
||||
path.moveTo(6,0);
|
||||
path.lineTo(2,0);
|
||||
path.lineTo(4,2);
|
||||
path.close();
|
||||
</div>
|
||||
|
||||
<div id="testLine9">
|
||||
SkPath path, simple;
|
||||
path.moveTo(0,4);
|
||||
|
@ -374,6 +384,11 @@ path.close();
|
|||
testSimplifyx(path);
|
||||
</div>
|
||||
|
||||
<div id="testLine22">
|
||||
path.addRect(0, 12, 12, 12, (SkPath::Direction) 0);
|
||||
path.addRect(4, 12, 13, 13, (SkPath::Direction) 0);
|
||||
</div>
|
||||
|
||||
<div id="testLine24">
|
||||
path.addRect(0, 18, 12, 12, (SkPath::Direction) 0);
|
||||
path.addRect(4, 12, 13, 13, (SkPath::Direction) 0);
|
||||
|
@ -560,11 +575,25 @@ path.close();
|
|||
path.addRect(12, 0, 21, 21, (SkPath::Direction) 1);
|
||||
</div>
|
||||
|
||||
<div id="testLine58">
|
||||
path.addRect(0, 0, 20, 20, (SkPath::Direction) 0);
|
||||
path.addRect(0, 0, 12, 12, (SkPath::Direction) 1);
|
||||
path.addRect(0, 12, 9, 9, (SkPath::Direction) 1);
|
||||
</div>
|
||||
|
||||
<div id="testLine59">
|
||||
path.addRect(0, 0, 20, 20, (SkPath::Direction) 0);
|
||||
path.addRect(6, 6, 18, 18, (SkPath::Direction) 1);
|
||||
path.addRect(4, 4, 13, 13, (SkPath::Direction) 1);
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var testDivs = [
|
||||
testLine59,
|
||||
testLine58,
|
||||
testLine57,
|
||||
testLine56,
|
||||
testLine55,
|
||||
|
@ -596,11 +625,13 @@ var testDivs = [
|
|||
testLine29,
|
||||
testLine28,
|
||||
testLine24,
|
||||
testLine22,
|
||||
testLine19,
|
||||
testLine17,
|
||||
testLine13,
|
||||
testLine12,
|
||||
testLine9,
|
||||
testLine7b,
|
||||
testLine7,
|
||||
testSimplifyQuadratic21,
|
||||
testSimplifyQuadratic20,
|
||||
|
|
Загрузка…
Ссылка в новой задаче