shape ops work in progress

git-svn-id: http://skia.googlecode.com/svn/trunk@6537 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
caryclark@google.com 2012-11-21 21:36:34 +00:00
parent f74dd16e9a
commit 729e1c46ce
4 changed files with 94 additions and 38 deletions

View File

@ -304,12 +304,12 @@ void operate(const SkPath& one, const SkPath& two, ShapeOp op, SkPath& result) {
for (index = 0; index < contourList.count(); ++index) {
total += contourList[index]->segments().count();
}
#if DEBUG_WINDING
#if DEBUG_SHOW_WINDING
Op::Contour::debugShowWindingValues(contourList);
#endif
coincidenceCheck(contourList, (aXorMask == kEvenOdd_Mask)
^ (bXorMask == kEvenOdd_Mask), total);
#if DEBUG_WINDING
#if DEBUG_SHOW_WINDING
Op::Contour::debugShowWindingValues(contourList);
#endif
fixOtherTIndex(contourList);

View File

@ -43,6 +43,7 @@ const bool gRunTestsInOneThread = false;
#define DEBUG_CROSS 0
#define DEBUG_MARK_DONE 0
#define DEBUG_PATH_CONSTRUCTION 0
#define DEBUG_SHOW_WINDING 0
#define DEBUG_SORT 0
#define DEBUG_WIND_BUMP 0
#define DEBUG_WINDING 0
@ -59,6 +60,7 @@ const bool gRunTestsInOneThread = true;
#define DEBUG_CROSS 0
#define DEBUG_MARK_DONE 1
#define DEBUG_PATH_CONSTRUCTION 1
#define DEBUG_SHOW_WINDING 0
#define DEBUG_SORT 1
#define DEBUG_WIND_BUMP 0
#define DEBUG_WINDING 1
@ -1470,8 +1472,8 @@ public:
}
int bumpCoincidentThis(const Span* oTest, const bool transfer, const bool decrementThis,
const bool thisXor, const bool opp, int index, SkTDArray<double>& outsideTs,
SkTDArray<double>& xOutsideTs)
const bool thisXor, const int oXorMask, const bool opp, int index,
SkTDArray<double>& outsideTs, SkTDArray<double>& xOutsideTs)
{
Span* const test = &fTs[index];
Span* end = test;
@ -1481,11 +1483,18 @@ public:
if (transfer) {
if (opp) {
if (decrementThis) {
zeroSpan(end);
zeroSpan(end, oStartT);
TrackOutside(outsideTs, end->fT, oStartT);
} else {
end->fWindValue += oTest->fOppValue;
end->fOppValue += oTest->fWindValue;
end->fOppValue = (end->fOppValue + oTest->fWindValue) & oXorMask;
if (thisXor) {
SkASSERT(end->fWindValue);
if (!(end->fWindValue & 1)) {
zeroSpan(end, oStartT);
TrackOutside(outsideTs, end->fT, oStartT);
}
}
}
} else if (!decrementThis & !thisXor) {
#ifdef SK_DEBUG
@ -1511,8 +1520,8 @@ public:
// intermediate T values (using this as the master, other as the follower)
// and walk other conditionally -- hoping that it catches up in the end
int bumpCoincidentOther(const Span* test, const bool transfer, const bool decrementThis,
const bool otherXor, const bool opp, const double tRatio, const double oEndT,
int& oIndex, SkTDArray<double>& oOutsideTs)
const bool otherXor, const int xorMask, const bool opp, const double tRatio,
const double oEndT, int& oIndex, SkTDArray<double>& oOutsideTs)
{
Span* const oTest = &fTs[oIndex];
Span* oEnd = oTest;
@ -1526,12 +1535,19 @@ public:
if (opp) {
if (decrementThis) {
oEnd->fWindValue += test->fOppValue;
oEnd->fOppValue += test->fWindValue;
oEnd->fOppValue = (oEnd->fOppValue + test->fWindValue) & xorMask;
if (otherXor) {
SkASSERT(oEnd->fWindValue);
if (!(oEnd->fWindValue & 1)) {
zeroSpan(oEnd, startT);
TrackOutside(oOutsideTs, oEnd->fT, startT);
}
}
} else {
zeroSpan(oEnd);
zeroSpan(oEnd, startT);
TrackOutside(oOutsideTs, oEnd->fT, startT);
}
} else if (decrementThis & !otherXor & !opp) {
} else if (decrementThis & !otherXor) {
#ifdef SK_DEBUG
SkASSERT(abs(oEnd->fWindValue) < gDebugMaxWindValue);
#endif
@ -1581,19 +1597,22 @@ public:
SkTDArray<double> outsideTs;
SkTDArray<double> xOutsideTs;
SkTDArray<double> oOutsideTs;
int xorMask = thisXor ? 1 : -1;
int oXorMask = otherXor ? 1 : -1;
do {
bool transfer = test->fWindValue && oTest->fWindValue;
bool decrementThis = test->fWindValue < oTest->fWindValue;
bool decrementThis = test->fWindValue < oTest->fWindValue ||
(test->fWindValue == oTest->fWindValue && thisXor);
if (decrementThis) {
oIndex = other.bumpCoincidentOther(test, transfer, decrementThis, otherXor, opp,
tRatio, oEndT, oIndex, oOutsideTs);
index = bumpCoincidentThis(oTest, transfer, decrementThis, thisXor, opp,
oIndex = other.bumpCoincidentOther(test, transfer, decrementThis, otherXor, xorMask,
opp, tRatio, oEndT, oIndex, oOutsideTs);
index = bumpCoincidentThis(oTest, transfer, decrementThis, thisXor, oXorMask, opp,
index, outsideTs, xOutsideTs);
} else {
index = bumpCoincidentThis(oTest, transfer, decrementThis, thisXor, opp,
index = bumpCoincidentThis(oTest, transfer, decrementThis, thisXor, oXorMask, opp,
index, outsideTs, xOutsideTs);
oIndex = other.bumpCoincidentOther(test, transfer, decrementThis, otherXor, opp,
tRatio, oEndT, oIndex, oOutsideTs);
oIndex = other.bumpCoincidentOther(test, transfer, decrementThis, otherXor, xorMask,
opp, tRatio, oEndT, oIndex, oOutsideTs);
}
test = &fTs[index];
oTest = &other.fTs[oIndex];
@ -1735,9 +1754,11 @@ public:
if (inner) {
winding += spanWinding;
}
int oppoWinding = base->oppSign(angle);
if (useInnerWinding(oWinding + oppoWinding, oWinding)) {
oWinding += oppoWinding;
if (oppoSum) {
int oppoWinding = base->oppSign(angle);
if (useInnerWinding(oWinding + oppoWinding, oWinding)) {
oWinding += oppoWinding;
}
}
#if DEBUG_SORT
base->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, oWinding);
@ -1759,15 +1780,15 @@ public:
if (opp) {
oMaxWinding = oWinding;
oWinding -= spanSign;
maxWinding = winding;
if (oppoSign) {
maxWinding = winding;
winding -= oppoSign;
}
} else {
maxWinding = winding;
winding -= spanSign;
oMaxWinding = oWinding;
if (oppoSign) {
oMaxWinding = oWinding;
oWinding -= oppoSign;
}
}
@ -1787,7 +1808,7 @@ public:
if (oppoSign && useInnerWinding(oMaxWinding, oWinding)) {
oMaxWinding = oWinding;
}
segment->markAndChaseWinding(angle, maxWinding, oMaxWinding);
segment->markAndChaseWinding(angle, maxWinding, oppoSum ? oMaxWinding : 0);
}
}
} while (++nextIndex != lastIndex);
@ -2079,7 +2100,7 @@ public:
foundFlipped = altFlipped;
foundSum = 0;
foundOpp = angleIsOp;
foundOppWinding = oMaxWinding;
foundOppWinding = oSumWinding;
}
continue;
}
@ -3135,7 +3156,7 @@ public:
fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
fTs.reset();
}
// This marks all spans unsortable so that this info is available for early
// exclusion in find top and others. This could be optimized to only mark
// adjacent spans that unsortable. However, this makes it difficult to later
@ -3288,14 +3309,21 @@ public:
return xyAtT(span).fY;
}
void zeroSpan(Span* span) {
void zeroSpan(Span* span, double otherT) {
SkASSERT(span->fWindValue > 0);
span->fWindValue = 0;
span->fOppValue = 0;
if (!span->fDone) {
span->fDone = true;
++fDoneSpans;
}
int oppValue = span->fOppValue;
if (!oppValue) {
return;
}
span->fOppValue = 0;
Segment* other = span->fOther;
Span& oSpan = other->fTs[span->fOtherIndex];
SkASSERT(0);
}
#if DEBUG_DUMP
@ -3563,7 +3591,9 @@ public:
static char as_digit(int value) {
return value < 0 ? '?' : value <= 9 ? '0' + value : '+';
}
#endif
#if DEBUG_SHOW_WINDING
int debugShowWindingValues(int slotCount, int ofInterest) const {
if (!(1 << fID & ofInterest)) {
return 0;
@ -3585,7 +3615,9 @@ public:
slots.begin() + slotCount);
return sum;
}
#endif
#if DEBUG_WINDING
bool debugVerifyWinding(int start, int end, int winding) const {
const Span& span = fTs[SkMin32(start, end)];
int spanWinding = span.fWindSum;
@ -3786,13 +3818,12 @@ public:
fContainsCurves = fContainsIntercepts = false;
}
// FIXME: for binary ops, need to keep both ops winding contributions separately
// in edge array
void resolveCoincidence(SkTDArray<Contour*>& contourList) {
int count = fCoincidences.count();
for (int index = 0; index < count; ++index) {
Coincidence& coincidence = fCoincidences[index];
Contour* thisContour = coincidence.fContours[0];
SkASSERT(thisContour == this);
Contour* otherContour = coincidence.fContours[1];
int thisIndex = coincidence.fSegments[0];
int otherIndex = coincidence.fSegments[1];
@ -3845,7 +3876,7 @@ public:
thisOne.debugShowTs();
other.debugShowTs();
#endif
#if DEBUG_WINDING
#if DEBUG_SHOW_WINDING
debugShowWindingValues(contourList);
#endif
}
@ -4037,7 +4068,7 @@ public:
}
#endif
#if DEBUG_WINDING
#if DEBUG_SHOW_WINDING
int debugShowWindingValues(int totalSegments, int ofInterest) {
int count = fSegments.count();
int sum = 0;
@ -4116,7 +4147,7 @@ EdgeBuilder(const SkPath& path, SkTArray<Contour>& contours)
void init() {
fCurrentContour = NULL;
fOperand = false;
fXorMask = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
fXorMask[0] = fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
#if DEBUG_DUMP
gContourID = 0;
gSegmentID = 0;
@ -4128,7 +4159,7 @@ void addOperand(const SkPath& path) {
SkASSERT(fPathVerbs.count() > 0 && fPathVerbs.end()[-1] == SkPath::kDone_Verb);
fPathVerbs.pop();
fPath = &path;
fXorMask = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask;
preFetch();
}
@ -4158,7 +4189,7 @@ void finish() {
}
ShapeOpMask xorMask() const {
return fXorMask;
return fXorMask[fOperand];
}
protected:
@ -4202,7 +4233,7 @@ void walk() {
if (!fCurrentContour) {
fCurrentContour = fContours.push_back_n(1);
fCurrentContour->setOperand(fOperand);
fCurrentContour->setXor(fXorMask == kEvenOdd_Mask);
fCurrentContour->setXor(fXorMask[fOperand] == kEvenOdd_Mask);
*fExtra.append() = -1; // start new contour
}
finalCurveEnd = pointsPtr++;
@ -4277,7 +4308,7 @@ private:
SkTArray<Contour>& fContours;
SkTDArray<SkPoint> fReducePts; // segments created on the fly
SkTDArray<int> fExtra; // -1 marks new contour, > 0 offsets into contour
ShapeOpMask fXorMask;
ShapeOpMask fXorMask[2];
int fSecondHalf;
bool fOperand;
};

View File

@ -2618,6 +2618,28 @@ static void testOp1d() {
testShapeOp(path, pathB, kDifference_Op);
}
static void testOp2d() {
SkPath path, pathB;
path.setFillType((SkPath::FillType) 0);
path.addRect(0, 0, 1, 1, (SkPath::Direction) 0);
path.addRect(0, 0, 2, 2, (SkPath::Direction) 0);
pathB.setFillType((SkPath::FillType) 1);
pathB.addRect(0, 0, 1, 1, (SkPath::Direction) 0);
pathB.addRect(0, 0, 1, 1, (SkPath::Direction) 0);
testShapeOp(path, pathB, kDifference_Op);
}
static void testOp3d() {
SkPath path, pathB;
path.setFillType((SkPath::FillType) 0);
path.addRect(0, 0, 1, 1, (SkPath::Direction) 0);
path.addRect(1, 1, 2, 2, (SkPath::Direction) 0);
pathB.setFillType((SkPath::FillType) 0);
pathB.addRect(0, 0, 1, 1, (SkPath::Direction) 0);
pathB.addRect(0, 0, 1, 1, (SkPath::Direction) 0);
testShapeOp(path, pathB, kDifference_Op);
}
static void testQuadratic22() {
SkPath path;
path.moveTo(0, 0);
@ -3231,11 +3253,13 @@ static struct {
TEST(testUnion2),
TEST(testXor2),
TEST(testOp1d),
TEST(testOp2d),
TEST(testOp3d),
};
static const size_t subTestCount = sizeof(subTests) / sizeof(subTests[0]);
static void (*firstBinaryTest)() = testOp1d;
static void (*firstBinaryTest)() = testOp3d;
static bool skipAll = false;
static bool runBinaryTestsFirst = true;

View File

@ -73,6 +73,7 @@
'../experimental/Intersection/QuarticRoot.cpp',
'../experimental/Intersection/QuarticRoot_Test.cpp',
'../experimental/Intersection/ShapeOps.cpp',
'../experimental/Intersection/ShapeOpRect4x4_Test.cpp',
'../experimental/Intersection/Simplify.cpp',
'../experimental/Intersection/SimplifyAddIntersectingTs_Test.cpp',
'../experimental/Intersection/SimplifyAngle_Test.cpp',