checkpoint for shape ops
at minimum, the unit tests in SimplyNew_Test pass git-svn-id: http://skia.googlecode.com/svn/trunk@5860 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
9598f4256d
commit
6aea33f92c
@ -82,6 +82,7 @@ inline bool approximately_equal(double x, double y) {
|
||||
if (approximately_zero(x - y)) {
|
||||
return true;
|
||||
}
|
||||
// FIXME: since no other function uses ULPS, this one shouldn't either
|
||||
return AlmostEqualUlps((float) x, (float) y, UlpsEpsilon);
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,35 @@
|
||||
#import "SkCanvas.h"
|
||||
#import "SkPaint.h"
|
||||
|
||||
extern void showPath(const SkPath& path, const char* str);
|
||||
|
||||
static bool drawPaths(SkCanvas* canvas, const SkPath& path, bool useOld)
|
||||
{
|
||||
SkPath out;
|
||||
#define SHOW_PATH 0
|
||||
#if SHOW_PATH
|
||||
showPath(path, "original:");
|
||||
#endif
|
||||
if (useOld) {
|
||||
simplify(path, true, out);
|
||||
} else {
|
||||
simplifyx(path, out);
|
||||
}
|
||||
#if SHOW_PATH
|
||||
showPath(out, "simplified:");
|
||||
#endif
|
||||
SkPaint paint;
|
||||
paint.setAntiAlias(true);
|
||||
paint.setStyle(SkPaint::kStroke_Style);
|
||||
// paint.setStrokeWidth(6);
|
||||
// paint.setColor(0x1F003f7f);
|
||||
// canvas->drawPath(path, paint);
|
||||
paint.setColor(0xFF305F00);
|
||||
paint.setStrokeWidth(1);
|
||||
canvas->drawPath(out, paint);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Three circles bounce inside a rectangle. The circles describe three, four
|
||||
// or five points which in turn describe a polygon. The polygon points
|
||||
// bounce inside the circles. The circles rotate and scale over time. The
|
||||
@ -26,7 +55,7 @@ static bool drawCircles(SkCanvas* canvas, int step, bool useOld)
|
||||
pts[c * 8 + p * 2 + 1] = abs(110 - ((step + c * 223 + p * 17) % 230));
|
||||
}
|
||||
}
|
||||
SkPath path, out;
|
||||
SkPath path;
|
||||
for (c = 0; c < circles; ++c) {
|
||||
for (p = 0; p < 4; ++p) {
|
||||
SkScalar x = pts[c * 8 + p * 2];
|
||||
@ -49,23 +78,7 @@ static bool drawCircles(SkCanvas* canvas, int step, bool useOld)
|
||||
}
|
||||
path.close();
|
||||
}
|
||||
showPath(path, "original:");
|
||||
if (useOld) {
|
||||
simplify(path, true, out);
|
||||
} else {
|
||||
simplifyx(path, out);
|
||||
}
|
||||
showPath(out, "simplified:");
|
||||
SkPaint paint;
|
||||
paint.setAntiAlias(true);
|
||||
paint.setStyle(SkPaint::kStroke_Style);
|
||||
paint.setStrokeWidth(3);
|
||||
paint.setColor(0x3F007fbF);
|
||||
canvas->drawPath(path, paint);
|
||||
paint.setColor(0xFF60FF00);
|
||||
paint.setStrokeWidth(1);
|
||||
canvas->drawPath(out, paint);
|
||||
return true;
|
||||
return drawPaths(canvas, path, useOld);
|
||||
}
|
||||
|
||||
static void createStar(SkPath& path, SkScalar innerRadius, SkScalar outerRadius,
|
||||
@ -89,7 +102,7 @@ static void createStar(SkPath& path, SkScalar innerRadius, SkScalar outerRadius,
|
||||
|
||||
static bool drawStars(SkCanvas* canvas, int step, bool useOld)
|
||||
{
|
||||
SkPath path, out;
|
||||
SkPath path;
|
||||
const int stars = 25;
|
||||
int pts[stars];
|
||||
// static bool initialize = true;
|
||||
@ -134,43 +147,171 @@ static bool drawStars(SkCanvas* canvas, int step, bool useOld)
|
||||
createStar(path, innerRadius[s] / 4.0f, outerRadius[s] / 4.0f,
|
||||
angles[s], pts[s], locs[s]);
|
||||
}
|
||||
#define SHOW_PATH 0
|
||||
#if SHOW_PATH
|
||||
showPath(path, "original:");
|
||||
#endif
|
||||
#define TEST_SIMPLIFY 01
|
||||
#if TEST_SIMPLIFY
|
||||
if (useOld) {
|
||||
simplify(path, true, out);
|
||||
return drawPaths(canvas, path, useOld);
|
||||
}
|
||||
|
||||
static void tryRoncoOnce(const SkPath& path, const SkRect& target, bool show) {
|
||||
// capture everything in a desired rectangle
|
||||
SkPath tiny;
|
||||
bool closed = true;
|
||||
SkPath::Iter iter(path, false);
|
||||
SkPoint pts[4];
|
||||
SkPath::Verb verb;
|
||||
int count = 0;
|
||||
SkPoint lastPt;
|
||||
while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
|
||||
switch (verb) {
|
||||
case SkPath::kMove_Verb:
|
||||
count = 0;
|
||||
break;
|
||||
case SkPath::kLine_Verb:
|
||||
count = 1;
|
||||
break;
|
||||
case SkPath::kQuad_Verb:
|
||||
count = 2;
|
||||
break;
|
||||
case SkPath::kCubic_Verb:
|
||||
count = 3;
|
||||
break;
|
||||
case SkPath::kClose_Verb:
|
||||
if (!closed) {
|
||||
tiny.close();
|
||||
closed = true;
|
||||
}
|
||||
count = 0;
|
||||
break;
|
||||
default:
|
||||
SkDEBUGFAIL("bad verb");
|
||||
}
|
||||
if (!count) {
|
||||
continue;
|
||||
}
|
||||
SkRect bounds;
|
||||
bounds.set(pts[0].fX, pts[0].fY, pts[0].fX, pts[0].fY);
|
||||
for (int i = 1; i <= count; ++i) {
|
||||
bounds.growToInclude(pts[i].fX + 0.1f, pts[i].fY + 0.1f);
|
||||
}
|
||||
if (!SkRect::Intersects(target, bounds)) {
|
||||
continue;
|
||||
}
|
||||
if (closed) {
|
||||
tiny.moveTo(pts[0].fX, pts[0].fY);
|
||||
closed = false;
|
||||
} else if (pts[0] != lastPt) {
|
||||
tiny.lineTo(pts[0].fX, pts[0].fY);
|
||||
}
|
||||
switch (verb) {
|
||||
case SkPath::kLine_Verb:
|
||||
tiny.lineTo(pts[1].fX, pts[1].fY);
|
||||
lastPt = pts[1];
|
||||
break;
|
||||
case SkPath::kQuad_Verb:
|
||||
tiny.quadTo(pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY);
|
||||
lastPt = pts[2];
|
||||
break;
|
||||
case SkPath::kCubic_Verb:
|
||||
tiny.cubicTo(pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY, pts[3].fX, pts[3].fY);
|
||||
lastPt = pts[3];
|
||||
break;
|
||||
default:
|
||||
SkDEBUGFAIL("bad verb");
|
||||
}
|
||||
}
|
||||
if (!closed) {
|
||||
tiny.close();
|
||||
}
|
||||
if (show) {
|
||||
showPath(tiny, NULL);
|
||||
SkDebugf("simplified:\n");
|
||||
}
|
||||
SkPath out;
|
||||
simplifyx(tiny, out);
|
||||
}
|
||||
|
||||
static void tryRonco(const SkPath& path) {
|
||||
const SkRect& overall = path.getBounds();
|
||||
const int divs = 50;
|
||||
SkScalar cellWidth = overall.width() / divs * 2;
|
||||
SkScalar cellHeight = overall.height() / divs * 2;
|
||||
SkRect target;
|
||||
if (true) {
|
||||
int xDiv = 21;
|
||||
int yDiv = 9;
|
||||
target.setXYWH(overall.fLeft + (overall.width() - cellWidth) * xDiv / divs,
|
||||
overall.fTop + (overall.height() - cellHeight) * yDiv / divs,
|
||||
cellWidth, cellHeight);
|
||||
tryRoncoOnce(path, target, true);
|
||||
} else {
|
||||
for (int xDiv = 0; xDiv < divs; ++xDiv) {
|
||||
for (int yDiv = 0; yDiv < divs; ++yDiv) {
|
||||
target.setXYWH(overall.fLeft + (overall.width() - cellWidth) * xDiv / divs,
|
||||
overall.fTop + (overall.height() - cellHeight) * yDiv / divs,
|
||||
cellWidth, cellHeight);
|
||||
tryRoncoOnce(path, target, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool drawLetters(SkCanvas* canvas, int step, bool useOld)
|
||||
{
|
||||
SkPath path;
|
||||
const int width = 640;
|
||||
const int height = 480;
|
||||
const char testStr[] = "Merge";
|
||||
const int testStrLen = sizeof(testStr) - 1;
|
||||
SkPoint textPos[testStrLen];
|
||||
SkScalar widths[testStrLen];
|
||||
SkPaint paint;
|
||||
paint.setTextSize(40);
|
||||
paint.setAntiAlias(true);
|
||||
paint.getTextWidths(testStr, testStrLen, widths, NULL);
|
||||
SkScalar running = 0;
|
||||
for (int x = 0; x < testStrLen; ++x) {
|
||||
SkScalar width = widths[x];
|
||||
widths[x] = running;
|
||||
running += width;
|
||||
}
|
||||
SkScalar bias = (width - widths[testStrLen - 1]) / 2;
|
||||
for (int x = 0; x < testStrLen; ++x) {
|
||||
textPos[x].fX = bias + widths[x];
|
||||
textPos[x].fY = height / 2;
|
||||
}
|
||||
paint.setTextSize(40 + step / 100.0f);
|
||||
#if 0
|
||||
for (int mask = 0; mask < 1 << testStrLen; ++mask) {
|
||||
char maskStr[testStrLen];
|
||||
// mask = 26;
|
||||
for (int letter = 0; letter < testStrLen; ++letter) {
|
||||
maskStr[letter] = mask & (1 << letter) ? testStr[letter] : ' ';
|
||||
}
|
||||
paint.getPosTextPath(maskStr, testStrLen, textPos, &path);
|
||||
showPath(path, NULL);
|
||||
SkDebugf("%d simplified:\n", mask);
|
||||
SkPath out;
|
||||
simplifyx(path, out);
|
||||
}
|
||||
#endif
|
||||
#if SHOW_PATH
|
||||
showPath(out, "simplified:");
|
||||
paint.getPosTextPath(testStr, testStrLen, textPos, &path);
|
||||
#if 1
|
||||
tryRonco(path);
|
||||
#endif
|
||||
SkPaint paint;
|
||||
paint.setAntiAlias(true);
|
||||
paint.setStyle(SkPaint::kStroke_Style);
|
||||
paint.setStrokeWidth(6);
|
||||
paint.setColor(0x1F003f7f);
|
||||
canvas->drawPath(path, paint);
|
||||
paint.setColor(0xFF305F00);
|
||||
paint.setStrokeWidth(1);
|
||||
#if TEST_SIMPLIFY
|
||||
canvas->drawPath(out, paint);
|
||||
#if 1
|
||||
showPath(path, NULL);
|
||||
SkDebugf("simplified:\n");
|
||||
#endif
|
||||
return true;
|
||||
return drawPaths(canvas, path, false);
|
||||
}
|
||||
|
||||
static bool (*drawDemos[])(SkCanvas* , int , bool ) = {
|
||||
drawStars,
|
||||
drawCircles
|
||||
drawCircles,
|
||||
drawLetters,
|
||||
};
|
||||
|
||||
static size_t drawDemosCount = sizeof(drawDemos) / sizeof(drawDemos[0]);
|
||||
|
||||
static bool (*firstTest)(SkCanvas* , int , bool) = 0;
|
||||
static bool (*firstTest)(SkCanvas* , int , bool) = drawLetters;
|
||||
|
||||
|
||||
bool DrawEdgeDemo(SkCanvas* canvas, int step, bool useOld) {
|
||||
|
@ -16,7 +16,8 @@ public:
|
||||
};
|
||||
protected:
|
||||
virtual void onDraw(SkCanvas* canvas) {
|
||||
static int step = 0; // useNew triggers error at 23275
|
||||
static int step = 15064; // drawLetters first error
|
||||
// drawStars triggers error at 23275
|
||||
// error is not easy to debug in its current state
|
||||
static double seconds;
|
||||
if (step == -1) {
|
||||
|
@ -40,6 +40,7 @@ static bool gShowOutputProgress = false;
|
||||
static bool gShowAsciiPaths = true;
|
||||
static bool gComparePathsAssert = false;
|
||||
static bool gPathStrAssert = true;
|
||||
static bool gUsePhysicalFiles = false;
|
||||
|
||||
void showPath(const SkPath& path, const char* str) {
|
||||
SkDebugf("%s\n", !str ? "original:" : str);
|
||||
@ -291,7 +292,7 @@ static int threadIndex;
|
||||
State4 threadState[maxThreadsAllocated];
|
||||
static int testNumber;
|
||||
static const char* testName;
|
||||
static bool debugThreads = true;
|
||||
static bool debugThreads = false;
|
||||
|
||||
State4* State4::queue = NULL;
|
||||
pthread_mutex_t State4::addQueue = PTHREAD_MUTEX_INITIALIZER;
|
||||
@ -421,12 +422,17 @@ void outputProgress(const State4& state, const char* pathStr, SkPath::FillType p
|
||||
}
|
||||
SkDebugf("%s\n", pathStr);
|
||||
}
|
||||
if (gUsePhysicalFiles) {
|
||||
SkFILEWStream outFile(state.filename);
|
||||
if (!outFile.isValid()) {
|
||||
SkASSERT(0);
|
||||
return;
|
||||
}
|
||||
outputToStream(state, pathStr, pathFillType, outFile);
|
||||
return;
|
||||
}
|
||||
SkFILEWStream outRam(state.filename);
|
||||
outputToStream(state, pathStr, pathFillType, outRam);
|
||||
}
|
||||
|
||||
static void writeTestName(SkPath::FillType pathFillType, SkWStream& outFile) {
|
||||
|
@ -14,9 +14,11 @@ void cubecode_test(int test);
|
||||
|
||||
void Intersection_Tests() {
|
||||
int testsRun = 0;
|
||||
SimplifyNew_Test();
|
||||
QuadraticIntersection_Test();
|
||||
SimplifyAngle_Test();
|
||||
QuarticRoot_Test();
|
||||
// QuadraticIntersection_Test();
|
||||
SimplifyNew_Test();
|
||||
Simplify4x4QuadraticsThreaded_Test(testsRun);
|
||||
QuadLineIntersectThreaded_Test(testsRun);
|
||||
LineQuadraticIntersection_Test();
|
||||
@ -25,12 +27,10 @@ void Intersection_Tests() {
|
||||
SimplifyDegenerate4x4TrianglesThreaded_Test(testsRun);
|
||||
Simplify4x4QuadralateralsThreaded_Test(testsRun);
|
||||
SkDebugf("%s total testsRun=%d\n", __FUNCTION__, testsRun);
|
||||
SimplifyAngle_Test();
|
||||
QuadraticBezierClip_Test();
|
||||
SimplifyFindNext_Test();
|
||||
SimplifyFindTop_Test();
|
||||
QuadraticReduceOrder_Test();
|
||||
QuadraticIntersection_Test();
|
||||
SimplifyAddIntersectingTs_Test();
|
||||
|
||||
cubecode_test(1);
|
||||
|
@ -16,6 +16,7 @@ public:
|
||||
, fUsed2(0)
|
||||
, fCoincidentUsed(0)
|
||||
, fSwap(0)
|
||||
, fFlip(0)
|
||||
{
|
||||
// OPTIMIZE: don't need to be initialized in release
|
||||
bzero(fT, sizeof(fT));
|
||||
@ -188,6 +189,7 @@ public:
|
||||
int fUsed;
|
||||
int fUsed2;
|
||||
int fCoincidentUsed;
|
||||
int fFlip;
|
||||
private:
|
||||
int fSwap;
|
||||
};
|
||||
|
@ -64,7 +64,55 @@ static void addValidRoots(const double roots[4], const int count, const int side
|
||||
}
|
||||
}
|
||||
|
||||
static bool onlyEndPtsInCommon(const Quadratic& q1, const Quadratic& q2, Intersections& i) {
|
||||
// the idea here is to see at minimum do a quick reject by rotating all points
|
||||
// to either side of the line formed by connecting the endpoints
|
||||
// if the opposite curves points are on the line or on the other side, the
|
||||
// curves at most intersect at the endpoints
|
||||
for (int oddMan = 0; oddMan < 3; ++oddMan) {
|
||||
const _Point* endPt[2];
|
||||
for (int opp = 1; opp < 3; ++opp) {
|
||||
int end = oddMan ^ opp;
|
||||
if (end == 3) {
|
||||
end = opp;
|
||||
}
|
||||
endPt[opp - 1] = &q1[end];
|
||||
}
|
||||
double origX = endPt[0]->x;
|
||||
double origY = endPt[0]->y;
|
||||
double adj = endPt[1]->x - origX;
|
||||
double opp = endPt[1]->y - origY;
|
||||
double sign = (q1[oddMan].y - origY) * adj - (q1[oddMan].x - origX) * opp;
|
||||
assert(!approximately_zero(sign));
|
||||
for (int n = 0; n < 3; ++n) {
|
||||
double test = (q2[n].y - origY) * adj - (q2[n].x - origX) * opp;
|
||||
if (test * sign > 0) {
|
||||
goto tryNextHalfPlane;
|
||||
}
|
||||
}
|
||||
for (int i1 = 0; i1 < 3; i1 += 2) {
|
||||
for (int i2 = 0; i2 < 3; i2 += 2) {
|
||||
if (q1[i1] == q2[i2]) {
|
||||
i.insertOne(i1 >> 1, 0);
|
||||
i.insertOne(i2 >> 1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(i.fUsed < 3);
|
||||
return true;
|
||||
tryNextHalfPlane:
|
||||
;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool intersect2(const Quadratic& q1, const Quadratic& q2, Intersections& i) {
|
||||
// if the quads share an end point, check to see if they overlap
|
||||
|
||||
if (onlyEndPtsInCommon(q1, q2, i)) {
|
||||
assert(i.insertBalanced());
|
||||
return i.intersected();
|
||||
}
|
||||
QuadImplicitForm i1(q1);
|
||||
QuadImplicitForm i2(q2);
|
||||
if (i1.implicit_match(i2)) {
|
||||
@ -100,7 +148,9 @@ bool intersect2(const Quadratic& q1, const Quadratic& q2, Intersections& i) {
|
||||
addValidRoots(roots2, rootCount, 1, i);
|
||||
_Point pts[4];
|
||||
bool matches[4];
|
||||
int flipCheck[4];
|
||||
int index, ndex2;
|
||||
int flipIndex = 0;
|
||||
for (ndex2 = 0; ndex2 < i.fUsed2; ++ndex2) {
|
||||
xy_at_t(q2, i.fT[1][ndex2], pts[ndex2].x, pts[ndex2].y);
|
||||
matches[ndex2] = false;
|
||||
@ -110,6 +160,8 @@ bool intersect2(const Quadratic& q1, const Quadratic& q2, Intersections& i) {
|
||||
xy_at_t(q1, i.fT[0][index], xy.x, xy.y);
|
||||
for (ndex2 = 0; ndex2 < i.fUsed2; ++ndex2) {
|
||||
if (approximately_equal(pts[ndex2].x, xy.x) && approximately_equal(pts[ndex2].y, xy.y)) {
|
||||
assert(flipIndex < 4);
|
||||
flipCheck[flipIndex++] = ndex2;
|
||||
matches[ndex2] = true;
|
||||
goto next;
|
||||
}
|
||||
@ -131,6 +183,7 @@ bool intersect2(const Quadratic& q1, const Quadratic& q2, Intersections& i) {
|
||||
}
|
||||
++ndex2;
|
||||
}
|
||||
i.fFlip = i.fUsed >= 2 && flipCheck[0] > flipCheck[1];
|
||||
assert(i.insertBalanced());
|
||||
return i.intersected();
|
||||
}
|
||||
|
@ -59,6 +59,10 @@ static void standardTestCases() {
|
||||
}
|
||||
|
||||
static const Quadratic testSet[] = {
|
||||
{{400.121704, 149.468719}, {391.949493, 161.037186}, {391.949493, 181.202423}},
|
||||
{{391.946747, 181.839218}, {391.946747, 155.62442}, {406.115479, 138.855438}},
|
||||
{{360.048828125, 229.2578125}, {360.048828125, 224.4140625}, {362.607421875, 221.3671875}},
|
||||
{{362.607421875, 221.3671875}, {365.166015625, 218.3203125}, {369.228515625, 218.3203125}},
|
||||
{{8, 8}, {10, 10}, {8, -10}},
|
||||
{{8, 8}, {12, 12}, {14, 4}},
|
||||
{{8, 8}, {9, 9}, {10, 8}}
|
||||
@ -71,12 +75,13 @@ static void oneOffTest() {
|
||||
for (size_t inner = outer + 1; inner < testSetCount; ++inner) {
|
||||
const Quadratic& quad1 = testSet[outer];
|
||||
const Quadratic& quad2 = testSet[inner];
|
||||
double tt1, tt2;
|
||||
#if 0 // enable to test bezier clip style intersection
|
||||
Intersections intersections;
|
||||
intersect(quad1, quad2, intersections);
|
||||
if (!intersections.intersected()) {
|
||||
SkDebugf("%s no intersection!\n", __FUNCTION__);
|
||||
}
|
||||
double tt1, tt2;
|
||||
for (int pt = 0; pt < intersections.used(); ++pt) {
|
||||
tt1 = intersections.fT[0][pt];
|
||||
double tx1, ty1;
|
||||
@ -97,8 +102,10 @@ static void oneOffTest() {
|
||||
SkDebugf("%s [%d][%d] t1=%1.9g (%1.9g, %1.9g) t2=%1.9g\n", __FUNCTION__,
|
||||
outer, inner, tt1, tx1, tx2, tt2);
|
||||
}
|
||||
#endif
|
||||
Intersections intersections2;
|
||||
intersect2(quad1, quad2, intersections2);
|
||||
#if 0
|
||||
SkASSERT(intersections.used() == intersections2.used());
|
||||
for (int pt = 0; pt < intersections2.used(); ++pt) {
|
||||
tt1 = intersections2.fT[0][pt];
|
||||
@ -106,6 +113,28 @@ static void oneOffTest() {
|
||||
tt2 = intersections2.fT[1][pt];
|
||||
SkASSERT(approximately_equal(intersections.fT[1][pt], tt2));
|
||||
}
|
||||
#endif
|
||||
for (int pt = 0; pt < intersections2.used(); ++pt) {
|
||||
tt1 = intersections2.fT[0][pt];
|
||||
double tx1, ty1;
|
||||
xy_at_t(quad1, tt1, tx1, ty1);
|
||||
int pt2 = intersections2.fFlip ? intersections2.used() - pt - 1 : pt;
|
||||
tt2 = intersections2.fT[1][pt2];
|
||||
double tx2, ty2;
|
||||
xy_at_t(quad2, tt2, tx2, ty2);
|
||||
if (!approximately_equal(tx1, tx2)) {
|
||||
SkDebugf("%s [%d,%d] x!= t1=%g (%g,%g) t2=%g (%g,%g)\n",
|
||||
__FUNCTION__, (int)index, pt, tt1, tx1, ty1, tt2, tx2, ty2);
|
||||
SkASSERT(0);
|
||||
}
|
||||
if (!approximately_equal(ty1, ty2)) {
|
||||
SkDebugf("%s [%d,%d] y!= t1=%g (%g,%g) t2=%g (%g,%g)\n",
|
||||
__FUNCTION__, (int)index, pt, tt1, tx1, ty1, tt2, tx2, ty2);
|
||||
SkASSERT(0);
|
||||
}
|
||||
SkDebugf("%s [%d][%d] t1=%1.9g (%1.9g, %1.9g) t2=%1.9g\n", __FUNCTION__,
|
||||
outer, inner, tt1, tx1, tx2, tt2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -148,7 +177,7 @@ static void coincidentTest() {
|
||||
}
|
||||
|
||||
void QuadraticIntersection_Test() {
|
||||
coincidentTest();
|
||||
oneOffTest();
|
||||
coincidentTest();
|
||||
standardTestCases();
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ static int cubicRootsX(double A, double B, double C, double D, double s[3]) {
|
||||
if (approximately_zero(A)) { // we're just a quadratic
|
||||
return quadraticRootsX(B, C, D, s);
|
||||
}
|
||||
if (approximately_zero(D)) {
|
||||
if (approximately_zero(D)) { // 0 is one root
|
||||
int num = quadraticRootsX(A, B, C, s);
|
||||
for (int i = 0; i < num; ++i) {
|
||||
if (approximately_zero(s[i])) {
|
||||
@ -130,6 +130,16 @@ static int cubicRootsX(double A, double B, double C, double D, double s[3]) {
|
||||
s[num++] = 0;
|
||||
return num;
|
||||
}
|
||||
if (approximately_zero(A + B + C + D)) { // 1 is one root
|
||||
int num = quadraticRootsX(A, A + B, -D, s);
|
||||
for (int i = 0; i < num; ++i) {
|
||||
if (approximately_equal(s[i], 1)) {
|
||||
return num;
|
||||
}
|
||||
}
|
||||
s[num++] = 1;
|
||||
return num;
|
||||
}
|
||||
double a, b, c;
|
||||
{
|
||||
double invA = 1 / A;
|
||||
@ -197,7 +207,7 @@ int quarticRoots(const double A, const double B, const double C, const double D,
|
||||
}
|
||||
int num;
|
||||
int i;
|
||||
if (approximately_zero(E)) {
|
||||
if (approximately_zero(E)) { // 0 is one root
|
||||
num = cubicRootsX(A, B, C, D, s);
|
||||
for (i = 0; i < num; ++i) {
|
||||
if (approximately_zero(s[i])) {
|
||||
@ -207,6 +217,16 @@ int quarticRoots(const double A, const double B, const double C, const double D,
|
||||
s[num++] = 0;
|
||||
return num;
|
||||
}
|
||||
if (approximately_zero(A + B + C + D + E)) { // 1 is one root
|
||||
num = cubicRootsX(A, A + B, -(D + E), -E, s); // note that -C==A+B+D+E
|
||||
for (i = 0; i < num; ++i) {
|
||||
if (approximately_equal(s[i], 1)) {
|
||||
return num;
|
||||
}
|
||||
}
|
||||
s[num++] = 1;
|
||||
return num;
|
||||
}
|
||||
double u, v;
|
||||
/* normal form: x^4 + Ax^3 + Bx^2 + Cx + D = 0 */
|
||||
const double invA = 1 / A;
|
||||
|
@ -25,17 +25,9 @@ int gDebugMaxWindSum = SK_MaxS32;
|
||||
int gDebugMaxWindValue = SK_MaxS32;
|
||||
#endif
|
||||
|
||||
#define HIGH_DEF_ANGLES 1
|
||||
|
||||
#if HIGH_DEF_ANGLES
|
||||
typedef double AngleValue;
|
||||
#else
|
||||
typedef SkScalar AngleValue;
|
||||
#endif
|
||||
|
||||
#define DEBUG_UNUSED 0 // set to expose unused functions
|
||||
|
||||
#if 1 // set to 1 for multiple thread -- no debugging
|
||||
#if 0 // set to 1 for multiple thread -- no debugging
|
||||
|
||||
const bool gRunTestsInOneThread = false;
|
||||
|
||||
@ -45,9 +37,8 @@ const bool gRunTestsInOneThread = false;
|
||||
#define DEBUG_ANGLE 0
|
||||
#define DEBUG_CONCIDENT 0
|
||||
#define DEBUG_CROSS 0
|
||||
#define DEBUG_DUMP 0
|
||||
#define DEBUG_MARK_DONE 0
|
||||
#define DEBUG_PATH_CONSTRUCTION 0
|
||||
#define DEBUG_PATH_CONSTRUCTION 1
|
||||
#define DEBUG_SORT 0
|
||||
#define DEBUG_WIND_BUMP 0
|
||||
#define DEBUG_WINDING 0
|
||||
@ -57,12 +48,11 @@ const bool gRunTestsInOneThread = false;
|
||||
const bool gRunTestsInOneThread = true;
|
||||
|
||||
#define DEBUG_ACTIVE_SPANS 1
|
||||
#define DEBUG_ADD_INTERSECTING_TS 0
|
||||
#define DEBUG_ADD_T_PAIR 0
|
||||
#define DEBUG_ADD_INTERSECTING_TS 1
|
||||
#define DEBUG_ADD_T_PAIR 1
|
||||
#define DEBUG_ANGLE 1
|
||||
#define DEBUG_CONCIDENT 1
|
||||
#define DEBUG_CROSS 0
|
||||
#define DEBUG_DUMP 1
|
||||
#define DEBUG_MARK_DONE 1
|
||||
#define DEBUG_PATH_CONSTRUCTION 1
|
||||
#define DEBUG_SORT 1
|
||||
@ -71,10 +61,7 @@ const bool gRunTestsInOneThread = true;
|
||||
|
||||
#endif
|
||||
|
||||
#if (DEBUG_ACTIVE_SPANS || DEBUG_CONCIDENT || DEBUG_SORT) && !DEBUG_DUMP
|
||||
#undef DEBUG_DUMP
|
||||
#define DEBUG_DUMP 1
|
||||
#endif
|
||||
#define DEBUG_DUMP (DEBUG_ACTIVE_SPANS | DEBUG_CONCIDENT | DEBUG_SORT | DEBUG_PATH_CONSTRUCTION)
|
||||
|
||||
#if DEBUG_DUMP
|
||||
static const char* kLVerbStr[] = {"", "line", "quad", "cubic"};
|
||||
@ -198,6 +185,11 @@ static void QuadXYAtT(const SkPoint a[3], double t, SkPoint* out) {
|
||||
out->fY = SkDoubleToScalar(y);
|
||||
}
|
||||
|
||||
static void QuadXYAtT(const SkPoint a[3], double t, _Point* out) {
|
||||
MAKE_CONST_QUAD(quad, a);
|
||||
xy_at_t(quad, t, out->x, out->y);
|
||||
}
|
||||
|
||||
static void CubicXYAtT(const SkPoint a[4], double t, SkPoint* out) {
|
||||
MAKE_CONST_CUBIC(cubic, a);
|
||||
double x, y;
|
||||
@ -460,15 +452,35 @@ static SkScalar (* const SegmentLeftMost[])(const SkPoint [], double , double) =
|
||||
CubicLeftMost
|
||||
};
|
||||
|
||||
#if 0 // currently unused
|
||||
static int QuadRayIntersect(const SkPoint a[3], const SkPoint b[2],
|
||||
Intersections& intersections) {
|
||||
MAKE_CONST_QUAD(aQuad, a);
|
||||
MAKE_CONST_LINE(bLine, b);
|
||||
return intersectRay(aQuad, bLine, intersections);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int QuadRayIntersect(const SkPoint a[3], const _Line& bLine,
|
||||
Intersections& intersections) {
|
||||
MAKE_CONST_QUAD(aQuad, a);
|
||||
return intersectRay(aQuad, bLine, intersections);
|
||||
}
|
||||
|
||||
class Segment;
|
||||
|
||||
struct Span {
|
||||
Segment* fOther;
|
||||
mutable SkPoint fPt; // lazily computed as needed
|
||||
double fT;
|
||||
double fOtherT; // value at fOther[fOtherIndex].fT
|
||||
int fOtherIndex; // can't be used during intersection
|
||||
int fWindSum; // accumulated from contours surrounding this one
|
||||
int fWindValue; // 0 == canceled; 1 == normal; >1 == coincident
|
||||
int fWindValueOpp; // opposite value, if any (for binary ops with coincidence)
|
||||
bool fDone; // if set, this span to next higher T has been processed
|
||||
};
|
||||
|
||||
// sorting angles
|
||||
// given angles of {dx dy ddx ddy dddx dddy} sort them
|
||||
class Angle {
|
||||
@ -490,7 +502,7 @@ public:
|
||||
the shorter tangent. If the tangents are equal, choose the better second
|
||||
tangent angle
|
||||
|
||||
maybe I set up LineParameters lazily
|
||||
maybe I could set up LineParameters lazily
|
||||
*/
|
||||
bool operator<(const Angle& rh) const {
|
||||
double y = dy();
|
||||
@ -503,9 +515,9 @@ public:
|
||||
if (y == 0 && ry == 0 && x * rx < 0) {
|
||||
return x < rx;
|
||||
}
|
||||
AngleValue x_ry = x * ry;
|
||||
AngleValue rx_y = rx * y;
|
||||
AngleValue cmp = x_ry - rx_y;
|
||||
double x_ry = x * ry;
|
||||
double rx_y = rx * y;
|
||||
double cmp = x_ry - rx_y;
|
||||
if (!approximately_zero(cmp)) {
|
||||
return cmp < 0;
|
||||
}
|
||||
@ -513,55 +525,23 @@ public:
|
||||
&& !approximately_zero_squared(cmp)) {
|
||||
return cmp < 0;
|
||||
}
|
||||
// see if either curve can be lengthened and try the tangent compare again
|
||||
if (cmp && (*fSpans)[fEnd].fOther != rh.fSegment // tangents not absolutely identical
|
||||
&& (*rh.fSpans)[rh.fEnd].fOther != fSegment) { // and not intersecting
|
||||
Angle longer = *this;
|
||||
Angle rhLonger = rh;
|
||||
if (longer.lengthen() | rhLonger.lengthen()) {
|
||||
return longer < rhLonger;
|
||||
}
|
||||
}
|
||||
// at this point, the initial tangent line is coincident
|
||||
#if !HIGH_DEF_ANGLES // old way
|
||||
AngleValue dy = approximately_pin(fDy + fDDy);
|
||||
AngleValue rdy = approximately_pin(rh.fDy + rh.fDDy);
|
||||
if (dy * rdy < 0) {
|
||||
return dy < 0;
|
||||
}
|
||||
AngleValue dx = approximately_pin(fDx + fDDx);
|
||||
AngleValue rdx = approximately_pin(rh.fDx + rh.fDDx);
|
||||
if (dy == 0 && rdy == 0 && dx * rdx < 0) {
|
||||
return dx < rdx;
|
||||
}
|
||||
cmp = dx * rdy - rdx * dy;
|
||||
if (!approximately_zero(cmp)) {
|
||||
return cmp < 0;
|
||||
}
|
||||
dy = approximately_pin(dy + fDDDy);
|
||||
rdy = approximately_pin(rdy + rh.fDDDy);
|
||||
if (dy * rdy < 0) {
|
||||
return dy < 0;
|
||||
}
|
||||
dx = approximately_pin(dx + fDDDx);
|
||||
rdx = approximately_pin(rdx + rh.fDDDx);
|
||||
if (dy == 0 && rdy == 0 && dx * rdx < 0) {
|
||||
return dx < rdx;
|
||||
}
|
||||
return dx * rdy < rdx * dy;
|
||||
#else // new way
|
||||
if (fSide * rh.fSide <= 0) {
|
||||
// FIXME: running demo will trigger this assertion
|
||||
// (don't know if commenting out will trigger further assertion or not)
|
||||
// commenting it out allows demo to run in release, though
|
||||
SkASSERT(fSide != rh.fSide);
|
||||
// SkASSERT(fSide != rh.fSide);
|
||||
return fSide < rh.fSide;
|
||||
}
|
||||
#if 0 // the following code is a bust. In particular, tangent length doesn't provide a sort
|
||||
if (y != ry) {
|
||||
return (fabs(y) < fabs(ry)) ^ (fSide > 0);
|
||||
}
|
||||
if (x != rx) {
|
||||
return (fabs(x) < fabs(rx)) ^ (fSide > 0);
|
||||
}
|
||||
// sort by second tangent angle
|
||||
cmp = fD2x * rh.fD2y - rh.fD2x * fD2y;
|
||||
if (!approximately_zero(cmp)) {
|
||||
return cmp < 0;
|
||||
}
|
||||
SkASSERT(0); // add code for cubic case
|
||||
#else
|
||||
SkASSERT(fVerb == SkPath::kQuad_Verb); // worry about cubics later
|
||||
SkASSERT(rh.fVerb == SkPath::kQuad_Verb);
|
||||
// FIXME: until I can think of something better, project a ray from the
|
||||
@ -570,7 +550,7 @@ public:
|
||||
// FIXME: some of this setup can be moved to set() if it works, or cached if it's expensive
|
||||
double len = fTangent1.normalSquared();
|
||||
double rlen = rh.fTangent1.normalSquared();
|
||||
SkPoint ray[2];
|
||||
_Line ray;
|
||||
Intersections i, ri;
|
||||
int roots, rroots;
|
||||
bool flip = false;
|
||||
@ -578,30 +558,23 @@ public:
|
||||
const Quadratic& q = (len < rlen) ^ flip ? fQ : rh.fQ;
|
||||
double midX = (q[0].x + q[2].x) / 2;
|
||||
double midY = (q[0].y + q[2].y) / 2;
|
||||
// FIXME: Ugh! this feels like a huge hack, not sure what else to do
|
||||
while (approximately_equal(q[1].x, midX) && approximately_equal(q[1].y, midY)) {
|
||||
SkASSERT(midX - q[1].x || midY - q[1].y);
|
||||
midX += midX - q[1].x;
|
||||
midY += midY - q[1].y;
|
||||
}
|
||||
ray[0].fX = SkDoubleToScalar(q[1].x);
|
||||
ray[0].fY = SkDoubleToScalar(q[1].y);
|
||||
ray[1].fX = SkDoubleToScalar(midX);
|
||||
ray[1].fY = SkDoubleToScalar(midY);
|
||||
ray[0] = q[1];
|
||||
ray[1].x = midX;
|
||||
ray[1].y = midY;
|
||||
SkASSERT(ray[0] != ray[1]);
|
||||
roots = QuadRayIntersect(fPts, ray, i);
|
||||
rroots = QuadRayIntersect(rh.fPts, ray, ri);
|
||||
} while ((roots == 0 || rroots == 0) && (flip ^= true));
|
||||
SkASSERT(roots > 0);
|
||||
SkASSERT(rroots > 0);
|
||||
SkPoint loc;
|
||||
SkScalar best = SK_ScalarInfinity;
|
||||
SkScalar dx, dy, dist;
|
||||
_Point loc;
|
||||
double best = SK_ScalarInfinity;
|
||||
double dx, dy, dist;
|
||||
int index;
|
||||
for (index = 0; index < roots; ++index) {
|
||||
QuadXYAtT(fPts, i.fT[0][index], &loc);
|
||||
dx = loc.fX - ray[0].fX;
|
||||
dy = loc.fY - ray[0].fY;
|
||||
dx = loc.x - ray[0].x;
|
||||
dy = loc.y - ray[0].y;
|
||||
dist = dx * dx + dy * dy;
|
||||
if (best > dist) {
|
||||
best = dist;
|
||||
@ -609,32 +582,22 @@ public:
|
||||
}
|
||||
for (index = 0; index < rroots; ++index) {
|
||||
QuadXYAtT(rh.fPts, ri.fT[0][index], &loc);
|
||||
dx = loc.fX - ray[0].fX;
|
||||
dy = loc.fY - ray[0].fY;
|
||||
dx = loc.x - ray[0].x;
|
||||
dy = loc.y - ray[0].y;
|
||||
dist = dx * dx + dy * dy;
|
||||
if (best > dist) {
|
||||
return fSide < 0;
|
||||
}
|
||||
}
|
||||
return fSide > 0;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
double dx() const {
|
||||
#if HIGH_DEF_ANGLES
|
||||
return fTangent1.dx();
|
||||
#else
|
||||
return fDx;
|
||||
#endif
|
||||
}
|
||||
|
||||
double dy() const {
|
||||
#if HIGH_DEF_ANGLES
|
||||
return fTangent1.dy();
|
||||
#else
|
||||
return fDy;
|
||||
#endif
|
||||
}
|
||||
|
||||
int end() const {
|
||||
@ -642,122 +605,57 @@ public:
|
||||
}
|
||||
|
||||
bool isHorizontal() const {
|
||||
#if HIGH_DEF_ANGLES
|
||||
return dy() == 0 && fVerb == SkPath::kLine_Verb;
|
||||
#else
|
||||
return fDy == 0 && fDDy == 0 && fDDDy == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
// high precision version
|
||||
#if HIGH_DEF_ANGLES
|
||||
bool lengthen() {
|
||||
int newEnd = fEnd;
|
||||
if (fStart < fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) {
|
||||
fEnd = newEnd;
|
||||
setSpans();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void set(const SkPoint* orig, SkPath::Verb verb, const Segment* segment,
|
||||
int start, int end, double startT, double endT) {
|
||||
int start, int end, const SkTDArray<Span>& spans) {
|
||||
fSegment = segment;
|
||||
fStart = start;
|
||||
fEnd = end;
|
||||
fPts = orig;
|
||||
fVerb = verb;
|
||||
switch (verb) {
|
||||
fSpans = &spans;
|
||||
setSpans();
|
||||
}
|
||||
|
||||
void setSpans() {
|
||||
double startT = (*fSpans)[fStart].fT;
|
||||
double endT = (*fSpans)[fEnd].fT;
|
||||
switch (fVerb) {
|
||||
case SkPath::kLine_Verb:
|
||||
_Line l;
|
||||
LineSubDivideHD(orig, startT, endT, l);
|
||||
LineSubDivideHD(fPts, startT, endT, l);
|
||||
// OPTIMIZATION: for pure line compares, we never need fTangent1.c
|
||||
fTangent1.lineEndPoints(l);
|
||||
fSide = 0;
|
||||
break;
|
||||
case SkPath::kQuad_Verb:
|
||||
QuadSubDivideHD(orig, startT, endT, fQ);
|
||||
QuadSubDivideHD(fPts, startT, endT, fQ);
|
||||
fTangent1.quadEndPoints(fQ, 0, 1);
|
||||
fSide = -fTangent1.pointDistance(fQ[2]); // not normalized -- compare sign only
|
||||
break;
|
||||
case SkPath::kCubic_Verb:
|
||||
Cubic c;
|
||||
CubicSubDivideHD(orig, startT, endT, c);
|
||||
CubicSubDivideHD(fPts, startT, endT, c);
|
||||
fTangent1.cubicEndPoints(c, 0, 1);
|
||||
fSide = -fTangent1.pointDistance(c[2]); // not normalized -- compare sign only
|
||||
break;
|
||||
default:
|
||||
SkASSERT(0);
|
||||
}
|
||||
// OPTIMIZATION: don't need these, access fTangent1 directly
|
||||
}
|
||||
|
||||
#else
|
||||
// since all angles share a point, this needs to know which point
|
||||
// is the common origin, i.e., whether the center is at pts[0] or pts[verb]
|
||||
// practically, this should only be called by addAngle
|
||||
void set(const SkPoint* pts, SkPath::Verb verb, const Segment* segment,
|
||||
int start, int end) {
|
||||
SkASSERT(start != end);
|
||||
fSegment = segment;
|
||||
fStart = start;
|
||||
fEnd = end;
|
||||
fDx = approximately_pin(pts[1].fX - pts[0].fX); // b - a
|
||||
fDy = approximately_pin(pts[1].fY - pts[0].fY);
|
||||
if (verb == SkPath::kLine_Verb) {
|
||||
fDDx = fDDy = fDDDx = fDDDy = 0;
|
||||
return;
|
||||
}
|
||||
fDDx = approximately_pin(pts[2].fX - pts[1].fX - fDx); // a - 2b + c
|
||||
fDDy = approximately_pin(pts[2].fY - pts[1].fY - fDy);
|
||||
if (verb == SkPath::kQuad_Verb) {
|
||||
fDDDx = fDDDy = 0;
|
||||
return;
|
||||
}
|
||||
fDDDx = approximately_pin(pts[3].fX + 3 * (pts[1].fX - pts[2].fX) - pts[0].fX);
|
||||
fDDDy = approximately_pin(pts[3].fY + 3 * (pts[1].fY - pts[2].fY) - pts[0].fY);
|
||||
}
|
||||
|
||||
// noncoincident quads/cubics may have the same initial angle
|
||||
// as lines, so must sort by derivatives as well
|
||||
// if flatness turns out to be a reasonable way to sort, use the below:
|
||||
void setFlat(const SkPoint* pts, SkPath::Verb verb, Segment* segment,
|
||||
int start, int end) {
|
||||
fSegment = segment;
|
||||
fStart = start;
|
||||
fEnd = end;
|
||||
fDx = pts[1].fX - pts[0].fX; // b - a
|
||||
fDy = pts[1].fY - pts[0].fY;
|
||||
if (verb == SkPath::kLine_Verb) {
|
||||
fDDx = fDDy = fDDDx = fDDDy = 0;
|
||||
return;
|
||||
}
|
||||
if (verb == SkPath::kQuad_Verb) {
|
||||
int uplsX = FloatAsInt(pts[2].fX - pts[1].fY - fDx);
|
||||
int uplsY = FloatAsInt(pts[2].fY - pts[1].fY - fDy);
|
||||
int larger = std::max(abs(uplsX), abs(uplsY));
|
||||
int shift = 0;
|
||||
double flatT;
|
||||
SkPoint ddPt; // FIXME: get rid of copy (change fDD_ to point)
|
||||
LineParameters implicitLine;
|
||||
MAKE_CONST_LINE(tangent, pts);
|
||||
implicitLine.lineEndPoints(tangent);
|
||||
implicitLine.normalize();
|
||||
while (larger > UlpsEpsilon * 1024) {
|
||||
larger >>= 2;
|
||||
++shift;
|
||||
flatT = 0.5 / (1 << shift);
|
||||
QuadXYAtT(pts, flatT, &ddPt);
|
||||
_Point _pt = {ddPt.fX, ddPt.fY};
|
||||
double distance = implicitLine.pointDistance(_pt);
|
||||
if (approximately_zero(distance)) {
|
||||
SkDebugf("%s ulps too small %1.9g\n", __FUNCTION__, distance);
|
||||
break;
|
||||
}
|
||||
}
|
||||
flatT = 0.5 / (1 << shift);
|
||||
QuadXYAtT(pts, flatT, &ddPt);
|
||||
fDDx = ddPt.fX - pts[0].fX;
|
||||
fDDy = ddPt.fY - pts[0].fY;
|
||||
SkASSERT(fDDx != 0 || fDDy != 0);
|
||||
fDDDx = fDDDy = 0;
|
||||
return;
|
||||
}
|
||||
SkASSERT(0); // FIXME: add cubic case
|
||||
}
|
||||
#endif
|
||||
|
||||
Segment* segment() const {
|
||||
return const_cast<Segment*>(fSegment);
|
||||
}
|
||||
@ -771,56 +669,30 @@ public:
|
||||
}
|
||||
|
||||
#if DEBUG_ANGLE
|
||||
const SkPoint* pts() const {
|
||||
return fPts;
|
||||
}
|
||||
|
||||
const SkTDArray<Span>* spans() const {
|
||||
return fSpans;
|
||||
}
|
||||
|
||||
SkPath::Verb verb() const {
|
||||
return fVerb;
|
||||
}
|
||||
|
||||
void debugShow(const SkPoint& a) const {
|
||||
#if HIGH_DEF_ANGLES
|
||||
SkDebugf(" d=(%1.9g,%1.9g) side=%1.9g\n",
|
||||
dx(), dy(), fSide);
|
||||
#else
|
||||
SkDebugf(" d=(%1.9g,%1.9g) dd=(%1.9g,%1.9g) ddd=(%1.9g,%1.9g)\n",
|
||||
fDx, fDy, fDDx, fDDy, fDDDx, fDDDy);
|
||||
AngleValue ax = (AngleValue) a.fX;
|
||||
AngleValue ay = (AngleValue) a.fY;
|
||||
AngleValue bx, by, cx, cy, dx, dy;
|
||||
bx = ax + fDx; // add b - a
|
||||
by = ay + fDy;
|
||||
cx = ax + 2 * fDx + fDDx; // add a + 2(b - a) to a - 2b + c
|
||||
cy = ay + 2 * fDy + fDDy;
|
||||
if (fDDDx == 0 && fDDDy == 0) {
|
||||
if (fDDx == 0 && fDDy == 0) {
|
||||
SkDebugf(
|
||||
" {SkPath::kLine_Verb, {{%1.9g, %1.9g}, {%1.9g, %1.9g} }},\n",
|
||||
ax, ay, bx, by);
|
||||
} else {
|
||||
SkDebugf(
|
||||
" {SkPath::kQuad_Verb, {{%1.9g, %1.9g}, {%1.9g, %1.9g}, {%1.9g, %1.9g}}},\n",
|
||||
ax, ay, bx, by, cx, cy);
|
||||
}
|
||||
} else {
|
||||
dx = fDDDx - ax - 3 * (cx - bx);
|
||||
dy = fDDDy - ay - 3 * (cy - by);
|
||||
SkDebugf(
|
||||
" {SkPath::kCubic_Verb, {{%1.9g, %1.9g}, {%1.9g, %1.9g}, {%1.9g, %1.9g}, {%1.9g, %1.9g}}},\n",
|
||||
ax, ay, bx, by, cx, cy, dx, dy);
|
||||
}
|
||||
#endif
|
||||
SkDebugf(" d=(%1.9g,%1.9g) side=%1.9g\n", dx(), dy(), fSide);
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
#if HIGH_DEF_ANGLES
|
||||
const SkPoint* fPts;
|
||||
Quadratic fQ;
|
||||
SkPath::Verb fVerb;
|
||||
double fSide;
|
||||
LineParameters fTangent1;
|
||||
#else
|
||||
AngleValue fDx;
|
||||
AngleValue fDy;
|
||||
AngleValue fDDx;
|
||||
AngleValue fDDy;
|
||||
AngleValue fDDDx;
|
||||
AngleValue fDDDy;
|
||||
#endif
|
||||
const SkTDArray<Span>* fSpans;
|
||||
const Segment* fSegment;
|
||||
int fStart;
|
||||
int fEnd;
|
||||
@ -900,18 +772,6 @@ static bool useInnerWinding(int outerWinding, int innerWinding) {
|
||||
return result;
|
||||
}
|
||||
|
||||
struct Span {
|
||||
Segment* fOther;
|
||||
mutable SkPoint fPt; // lazily computed as needed
|
||||
double fT;
|
||||
double fOtherT; // value at fOther[fOtherIndex].fT
|
||||
int fOtherIndex; // can't be used during intersection
|
||||
int fWindSum; // accumulated from contours surrounding this one
|
||||
int fWindValue; // 0 == canceled; 1 == normal; >1 == coincident
|
||||
int fWindValueOpp; // opposite value, if any (for binary ops with coincidence)
|
||||
bool fDone; // if set, this span to next higher T has been processed
|
||||
};
|
||||
|
||||
static const bool opLookup[][2][2] = {
|
||||
// ==0 !=0
|
||||
// b a b a
|
||||
@ -1010,13 +870,17 @@ public:
|
||||
void addAngle(SkTDArray<Angle>& angles, int start, int end) const {
|
||||
SkASSERT(start != end);
|
||||
Angle* angle = angles.append();
|
||||
#if HIGH_DEF_ANGLES==0 // old way
|
||||
SkPoint edge[4];
|
||||
(*SegmentSubDivide[fVerb])(fPts, fTs[start].fT, fTs[end].fT, edge);
|
||||
angle->set(edge, fVerb, this, start, end);
|
||||
#else // new way : compute temp edge in higher precision
|
||||
angle->set(fPts, fVerb, this, start, end, fTs[start].fT, fTs[end].fT);
|
||||
#if DEBUG_ANGLE
|
||||
if (angles.count() > 1) {
|
||||
SkPoint angle0Pt, newPt;
|
||||
(*SegmentXYAtT[angles[0].verb()])(angles[0].pts(),
|
||||
(*angles[0].spans())[angles[0].start()].fT, &angle0Pt);
|
||||
(*SegmentXYAtT[fVerb])(fPts, fTs[start].fT, &newPt);
|
||||
SkASSERT(approximately_equal(angle0Pt.fX, newPt.fX));
|
||||
SkASSERT(approximately_equal(angle0Pt.fY, newPt.fY));
|
||||
}
|
||||
#endif
|
||||
angle->set(fPts, fVerb, this, start, end, fTs);
|
||||
}
|
||||
|
||||
void addCancelOutsides(double tStart, double oStart, Segment& other,
|
||||
@ -1140,15 +1004,15 @@ public:
|
||||
(*SegmentSubDivide[fVerb])(fPts, fTs[start].fT, fTs[end].fT, edge);
|
||||
if (active) {
|
||||
#if DEBUG_PATH_CONSTRUCTION
|
||||
SkDebugf("%s %s (%1.9g,%1.9g)", __FUNCTION__,
|
||||
SkDebugf("path.%sTo(%1.9g,%1.9g",
|
||||
kLVerbStr[fVerb], edge[1].fX, edge[1].fY);
|
||||
if (fVerb > 1) {
|
||||
SkDebugf(" (%1.9g,%1.9g)", edge[2].fX, edge[2].fY);
|
||||
SkDebugf(", %1.9g,%1.9g", edge[2].fX, edge[2].fY);
|
||||
}
|
||||
if (fVerb > 2) {
|
||||
SkDebugf(" (%1.9g,%1.9g)", edge[3].fX, edge[3].fY);
|
||||
SkDebugf(", %1.9g,%1.9g", edge[3].fX, edge[3].fY);
|
||||
}
|
||||
SkDebugf("\n");
|
||||
SkDebugf(");\n");
|
||||
#endif
|
||||
switch (fVerb) {
|
||||
case SkPath::kLine_Verb:
|
||||
@ -1177,7 +1041,7 @@ public:
|
||||
const SkPoint& pt = xyAtT(tIndex);
|
||||
if (active) {
|
||||
#if DEBUG_PATH_CONSTRUCTION
|
||||
SkDebugf("%s (%1.9g,%1.9g)\n", __FUNCTION__, pt.fX, pt.fY);
|
||||
SkDebugf("path.moveTo(%1.9g, %1.9g);\n", pt.fX, pt.fY);
|
||||
#endif
|
||||
path.moveTo(pt.fX, pt.fY);
|
||||
}
|
||||
@ -1440,7 +1304,8 @@ public:
|
||||
if (!approximately_negative(span.fT - t)) {
|
||||
break;
|
||||
}
|
||||
if (approximately_negative(span.fT - t) && span.fOther == &other && span.fOtherT == otherT) {
|
||||
if (approximately_negative(span.fT - t) && span.fOther == &other
|
||||
&& approximately_equal(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);
|
||||
@ -1518,6 +1383,61 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
// FIXME may not need this at all
|
||||
// FIXME once I figure out the logic, merge this and too close to call
|
||||
// NOTE not sure if tiny triangles can ever form at the edge, so until we
|
||||
// see one, only worry about triangles that happen away from 0 and 1
|
||||
void collapseTriangles(bool isXor) {
|
||||
if (fTs.count() < 3) { // require t=0, x, 1 at minimum
|
||||
return;
|
||||
}
|
||||
int lastIndex = 1;
|
||||
double lastT;
|
||||
while (approximately_less_than_zero((lastT = fTs[lastIndex].fT))) {
|
||||
++lastIndex;
|
||||
}
|
||||
if (approximately_greater_than_one(lastT)) {
|
||||
return;
|
||||
}
|
||||
int matchIndex = lastIndex;
|
||||
do {
|
||||
Span& match = fTs[++matchIndex];
|
||||
double matchT = match.fT;
|
||||
if (approximately_greater_than_one(matchT)) {
|
||||
return;
|
||||
}
|
||||
if (matchT == lastT) {
|
||||
goto nextSpan;
|
||||
}
|
||||
if (approximately_negative(matchT - lastT)) {
|
||||
Span& last = fTs[lastIndex];
|
||||
Segment* lOther = last.fOther;
|
||||
double lT = last.fOtherT;
|
||||
if (approximately_less_than_zero(lT) || approximately_greater_than_one(lT)) {
|
||||
goto nextSpan;
|
||||
}
|
||||
Segment* mOther = match.fOther;
|
||||
double mT = match.fOtherT;
|
||||
if (approximately_less_than_zero(mT) || approximately_greater_than_one(mT)) {
|
||||
goto nextSpan;
|
||||
}
|
||||
// add new point to connect adjacent spurs
|
||||
int count = lOther->fTs.count();
|
||||
for (int index = 0; index < count; ++index) {
|
||||
Span& span = lOther->fTs[index];
|
||||
if (span.fOther == mOther && approximately_zero(span.fOtherT - mT)) {
|
||||
goto nextSpan;
|
||||
}
|
||||
}
|
||||
mOther->addTPair(mT, *lOther, lT, false);
|
||||
// FIXME ? this could go on to detect that spans on mOther, lOther are now coincident
|
||||
}
|
||||
nextSpan:
|
||||
lastIndex = matchIndex;
|
||||
lastT = matchT;
|
||||
} while (true);
|
||||
}
|
||||
|
||||
int computeSum(int startIndex, int endIndex) {
|
||||
SkTDArray<Angle> angles;
|
||||
addTwoAngles(startIndex, endIndex, angles);
|
||||
@ -2639,6 +2559,23 @@ public:
|
||||
return -1;
|
||||
}
|
||||
|
||||
// FIXME
|
||||
// this returns at any difference in T, vs. a preset minimum. It may be
|
||||
// that all callers to nextSpan should use this instead.
|
||||
int nextExactSpan(int from, int step) const {
|
||||
const Span& fromSpan = fTs[from];
|
||||
int count = fTs.count();
|
||||
int to = from;
|
||||
while (step > 0 ? ++to < count : --to >= 0) {
|
||||
const Span& span = fTs[to];
|
||||
if (span.fT == fromSpan.fT) {
|
||||
continue;
|
||||
}
|
||||
return to;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool operand() const {
|
||||
return fOperand;
|
||||
}
|
||||
@ -2865,6 +2802,40 @@ public:
|
||||
SkDebugf(" windValue=%d\n", fTs[i].fWindValue);
|
||||
}
|
||||
}
|
||||
|
||||
// This isn't useful yet -- but leaving it in for now in case i think of something
|
||||
// to use it for
|
||||
void validateActiveSpans() const {
|
||||
if (done()) {
|
||||
return;
|
||||
}
|
||||
int tCount = fTs.count();
|
||||
for (int index = 0; index < tCount; ++index) {
|
||||
if (fTs[index].fDone) {
|
||||
continue;
|
||||
}
|
||||
// count number of connections which are not done
|
||||
int first = index;
|
||||
double baseT = fTs[index].fT;
|
||||
while (first > 0 && approximately_equal(fTs[first - 1].fT, baseT)) {
|
||||
--first;
|
||||
}
|
||||
int last = index;
|
||||
while (last < tCount - 1 && approximately_equal(fTs[last + 1].fT, baseT)) {
|
||||
++last;
|
||||
}
|
||||
int connections = 0;
|
||||
connections += first > 0 && !fTs[first - 1].fDone;
|
||||
for (int test = first; test <= last; ++test) {
|
||||
connections += !fTs[test].fDone;
|
||||
const Segment* other = fTs[test].fOther;
|
||||
int oIndex = fTs[test].fOtherIndex;
|
||||
connections += !other->fTs[oIndex].fDone;
|
||||
connections += oIndex > 0 && !other->fTs[oIndex - 1].fDone;
|
||||
}
|
||||
// SkASSERT(!(connections & 1));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DEBUG_MARK_DONE
|
||||
@ -2917,7 +2888,7 @@ public:
|
||||
segment.yAtT(&eSpan), angle.sign(), mSpan.fWindValue,
|
||||
lastSum, windSum, useInnerWinding(lastSum, windSum)
|
||||
? windSum : lastSum, mSpan.fDone);
|
||||
#if DEBUG_ANGLE
|
||||
#if false && DEBUG_ANGLE
|
||||
angle.debugShow(segment.xyAtT(&sSpan));
|
||||
#endif
|
||||
++index;
|
||||
@ -3045,6 +3016,13 @@ public:
|
||||
return fBounds;
|
||||
}
|
||||
|
||||
void collapseTriangles() {
|
||||
int segmentCount = fSegments.count();
|
||||
for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
|
||||
fSegments[sIndex].collapseTriangles(fXor);
|
||||
}
|
||||
}
|
||||
|
||||
void complete() {
|
||||
setBounds();
|
||||
fContainsIntercepts = false;
|
||||
@ -3290,6 +3268,12 @@ public:
|
||||
fSegments[index].debugShowActiveSpans();
|
||||
}
|
||||
}
|
||||
|
||||
void validateActiveSpans() {
|
||||
for (int index = 0; index < fSegments.count(); ++index) {
|
||||
fSegments[index].validateActiveSpans();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
@ -3854,13 +3838,20 @@ static bool addIntersectTs(Contour* test, Contour* next) {
|
||||
}
|
||||
|
||||
}
|
||||
int pt2 = 0;
|
||||
int pt2inc = 1;
|
||||
if (ts.fFlip) {
|
||||
pt2 = pts - 1;
|
||||
pt2inc = -1;
|
||||
}
|
||||
for (int pt = 0; pt < pts; ++pt) {
|
||||
SkASSERT(ts.fT[0][pt] >= 0 && ts.fT[0][pt] <= 1);
|
||||
SkASSERT(ts.fT[1][pt] >= 0 && ts.fT[1][pt] <= 1);
|
||||
int testTAt = wt.addT(ts.fT[swap][pt], wn);
|
||||
int nextTAt = wn.addT(ts.fT[!swap][pt], wt);
|
||||
wt.addOtherT(testTAt, ts.fT[!swap][pt], nextTAt);
|
||||
wn.addOtherT(nextTAt, ts.fT[swap][pt], testTAt);
|
||||
wt.addOtherT(testTAt, ts.fT[!swap][pt ^ ts.fFlip], nextTAt);
|
||||
wn.addOtherT(nextTAt, ts.fT[swap][pt ^ ts.fFlip], testTAt);
|
||||
pt2 += pt2inc;
|
||||
}
|
||||
} while (wn.advance());
|
||||
} while (wt.advance());
|
||||
@ -3879,6 +3870,13 @@ static void coincidenceCheck(SkTDArray<Contour*>& contourList) {
|
||||
Contour* contour = contourList[cIndex];
|
||||
contour->findTooCloseToCall();
|
||||
}
|
||||
#if 0
|
||||
// OPTIMIZATION: this check could be folded in with findTooClose -- maybe
|
||||
for (int cIndex = 0; cIndex < contourCount; ++cIndex) {
|
||||
Contour* contour = contourList[cIndex];
|
||||
contour->collapseTriangles();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// project a ray from the top of the contour up and see if it hits anything
|
||||
@ -4183,9 +4181,13 @@ static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex,
|
||||
|
||||
#if DEBUG_ACTIVE_SPANS
|
||||
static void debugShowActiveSpans(SkTDArray<Contour*>& contourList) {
|
||||
for (int index = 0; index < contourList.count(); ++ index) {
|
||||
int index;
|
||||
for (index = 0; index < contourList.count(); ++ index) {
|
||||
contourList[index]->debugShowActiveSpans();
|
||||
}
|
||||
for (index = 0; index < contourList.count(); ++ index) {
|
||||
contourList[index]->validateActiveSpans();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -4286,7 +4288,7 @@ static void bridgeWinding(SkTDArray<Contour*>& contourList, SkPath& simple) {
|
||||
} while (*firstPt != lastPt && (active || !current->done()));
|
||||
if (firstPt && active) {
|
||||
#if DEBUG_PATH_CONSTRUCTION
|
||||
SkDebugf("%s close\n", __FUNCTION__);
|
||||
SkDebugf("path.close();\n");
|
||||
#endif
|
||||
simple.close();
|
||||
}
|
||||
@ -4349,6 +4351,9 @@ static void bridgeXor(SkTDArray<Contour*>& contourList, SkPath& simple) {
|
||||
#endif
|
||||
simple.close();
|
||||
}
|
||||
#if DEBUG_ACTIVE_SPANS
|
||||
debugShowActiveSpans(contourList);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,27 +93,12 @@ static void testSegments(bool testFlat) {
|
||||
int index = 0;
|
||||
do {
|
||||
int next = index + 1;
|
||||
#if HIGH_DEF_ANGLES==0
|
||||
if (testFlat) {
|
||||
lesser.setFlat(segPtr[index].pts, segPtr[index].verb, 0, index, next);
|
||||
} else {
|
||||
lesser.set(segPtr[index].pts, segPtr[index].verb, 0, index, next);
|
||||
}
|
||||
#else
|
||||
lesser.set(segPtr[index].pts, segPtr[index].verb, 0, index, next, 0, 1);
|
||||
#endif
|
||||
SkTDArray<SimplifyAngleTest::Span> dummy;
|
||||
lesser.set(segPtr[index].pts, segPtr[index].verb, NULL, index, next, dummy);
|
||||
if (segPtr[next].verb == SkPath::kMove_Verb) {
|
||||
break;
|
||||
}
|
||||
#if HIGH_DEF_ANGLES==0
|
||||
if (testFlat) {
|
||||
greater.setFlat(segPtr[next].pts, segPtr[next].verb, 0, index, next);
|
||||
} else {
|
||||
greater.set(segPtr[next].pts, segPtr[next].verb, 0, index, next);
|
||||
}
|
||||
#else
|
||||
greater.set(segPtr[next].pts, segPtr[next].verb, 0, index, next, 0, 1);
|
||||
#endif
|
||||
greater.set(segPtr[next].pts, segPtr[next].verb, NULL, index, next, dummy);
|
||||
bool result = lesser < greater;
|
||||
SkASSERT(result);
|
||||
index = next;
|
||||
@ -129,15 +114,8 @@ static void testLines(bool testFlat) {
|
||||
size_t x;
|
||||
for (x = 0; x < lineCount; ++x) {
|
||||
SimplifyAngleTest::Angle* angle = angles.append();
|
||||
#if HIGH_DEF_ANGLES==0
|
||||
if (testFlat) {
|
||||
angle->setFlat(lines[x], SkPath::kLine_Verb, 0, x, x + 1);
|
||||
} else {
|
||||
angle->set(lines[x], SkPath::kLine_Verb, 0, x, x + 1);
|
||||
}
|
||||
#else
|
||||
angle->set(lines[x], SkPath::kLine_Verb, 0, x, x + 1, 0, 1);
|
||||
#endif
|
||||
SkTDArray<SimplifyAngleTest::Span> dummy;
|
||||
angle->set(lines[x], SkPath::kLine_Verb, 0, x, x + 1, dummy);
|
||||
double arcTan = atan2(lines[x][0].fX - lines[x][1].fX,
|
||||
lines[x][0].fY - lines[x][1].fY);
|
||||
arcTans.push(arcTan);
|
||||
@ -184,15 +162,8 @@ static void testQuads(bool testFlat) {
|
||||
size_t x;
|
||||
for (x = 0; x < quadCount; ++x) {
|
||||
SimplifyAngleTest::Angle* angle = angles.append();
|
||||
#if HIGH_DEF_ANGLES==0
|
||||
if (testFlat) {
|
||||
angle->setFlat(quads[x], SkPath::kQuad_Verb, 0, x, x + 1);
|
||||
} else {
|
||||
angle->set(quads[x], SkPath::kQuad_Verb, 0, x, x + 1);
|
||||
}
|
||||
#else
|
||||
angle->set(quads[x], SkPath::kQuad_Verb, 0, x, x + 1, 0, 1);
|
||||
#endif
|
||||
SkTDArray<SimplifyAngleTest::Span> dummy;
|
||||
angle->set(quads[x], SkPath::kQuad_Verb, 0, x, x + 1, dummy);
|
||||
}
|
||||
for (x = 0; x < quadCount; ++x) {
|
||||
angleList.push(&angles[x]);
|
||||
@ -214,15 +185,8 @@ static void testCubics(bool testFlat) {
|
||||
SkTDArray<SimplifyAngleTest::Angle* > angleList;
|
||||
for (size_t x = 0; x < cubicCount; ++x) {
|
||||
SimplifyAngleTest::Angle* angle = angles.append();
|
||||
#if HIGH_DEF_ANGLES==0
|
||||
if (testFlat) {
|
||||
angle->setFlat(cubics[x], SkPath::kCubic_Verb, 0, x, x + 1);
|
||||
} else {
|
||||
angle->set(cubics[x], SkPath::kCubic_Verb, 0, x, x + 1);
|
||||
}
|
||||
#else
|
||||
angle->set(cubics[x], SkPath::kCubic_Verb, 0, x, x + 1, 0, 1);
|
||||
#endif
|
||||
SkTDArray<SimplifyAngleTest::Span> dummy;
|
||||
angle->set(cubics[x], SkPath::kCubic_Verb, 0, x, x + 1, dummy);
|
||||
angleList.push(angle);
|
||||
}
|
||||
QSort<SimplifyAngleTest::Angle>(angleList.begin(), angleList.end() - 1);
|
||||
@ -235,7 +199,68 @@ static void testCubics(bool testFlat) {
|
||||
}
|
||||
}
|
||||
|
||||
struct segmentWithT {
|
||||
SkPath::Verb verb;
|
||||
SkPoint pts[4];
|
||||
double ts[2];
|
||||
};
|
||||
|
||||
|
||||
static const segmentWithT oneOffTest1[] = {
|
||||
{SkPath::kQuad_Verb, {{391.653534f, 183.286819f}, {391.653534f, 157.724487f}, {405.469604f, 141.372879f}},
|
||||
{0.62346946335026932, 0.62344389027237135}},
|
||||
{SkPath::kQuad_Verb, {{399.365234f, 171.695801f}, {399.365234f, 140.337967f}, {375.976227f, 140.337967f}},
|
||||
{0.31638302676995866, 0.31637992418411398}},
|
||||
{SkPath::kMove_Verb }
|
||||
};
|
||||
|
||||
static const segmentWithT oneOffTest2[] = {
|
||||
{SkPath::kQuad_Verb, {{399.070374f, 151.722f}, {391.101532f, 163.002533f}, {391.101532f, 182.665863f}},
|
||||
{0.13793711854916513, 0.13790171160614006}},
|
||||
{SkPath::kQuad_Verb, {{391.653534f, 183.286819f}, {391.653534f, 157.724487f}, {405.469604f, 141.372879f}},
|
||||
{0.62344389027237135, 0.62346946335026932}},
|
||||
{SkPath::kMove_Verb }
|
||||
};
|
||||
|
||||
static const segmentWithT oneOffTest3[] = {
|
||||
{SkPath::kQuad_Verb, {{399.365234f, 171.695801f}, {399.365234f, 140.337967f}, {375.976227f, 140.337967f}},
|
||||
{0.31637992418411398, 0.31638302676995866, }},
|
||||
{SkPath::kQuad_Verb, {{399.070374f, 151.722f}, {391.101532f, 163.002533f}, {391.101532f, 182.665863f}},
|
||||
{0.13790171160614006, 0.13793711854916513}},
|
||||
{SkPath::kMove_Verb }
|
||||
};
|
||||
|
||||
static const segmentWithT* oneOffTests[] = {
|
||||
oneOffTest1,
|
||||
oneOffTest2,
|
||||
oneOffTest3,
|
||||
};
|
||||
|
||||
static const size_t oneOffTestCount = sizeof(oneOffTests) / sizeof(oneOffTests[0]);
|
||||
|
||||
static void oneOffTest(bool testFlat) {
|
||||
for (size_t testIndex = 0; testIndex < oneOffTestCount; ++testIndex) {
|
||||
const segmentWithT* segPtr = oneOffTests[testIndex];
|
||||
SimplifyAngleTest::Angle lesser, greater;
|
||||
int index = 0;
|
||||
do {
|
||||
int next = index + 1;
|
||||
SkTDArray<SimplifyAngleTest::Span> dummy; // FIXME
|
||||
lesser.set(segPtr[index].pts, segPtr[index].verb, 0, index, next, dummy); // FIXME: segPtr[index].ts[0], segPtr[index].ts[1]);
|
||||
if (segPtr[next].verb == SkPath::kMove_Verb) {
|
||||
break;
|
||||
}
|
||||
greater.set(segPtr[next].pts, segPtr[next].verb, 0, index, next, dummy); // FIXME: segPtr[next].ts[0], segPtr[next].ts[1]);
|
||||
bool result = lesser < greater;
|
||||
SkASSERT(result);
|
||||
index = next;
|
||||
} while (true);
|
||||
}
|
||||
SkDebugf("%s finished\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
static void (*tests[])(bool) = {
|
||||
oneOffTest,
|
||||
testSegments,
|
||||
testLines,
|
||||
testQuads,
|
||||
|
@ -2828,7 +2828,7 @@ static void testQuadratic38() {
|
||||
testSimplifyx(path);
|
||||
}
|
||||
|
||||
static void (*firstTest)() = testQuadratic38;
|
||||
static void (*firstTest)() = testLine73x;
|
||||
|
||||
static struct {
|
||||
void (*fun)();
|
||||
|
@ -109,11 +109,18 @@ $3 = {{
|
||||
(gdb)
|
||||
</div>
|
||||
|
||||
<div id="quad37">
|
||||
{{x = 360.048828125, y = 229.2578125}, {x = 360.048828125, y = 224.4140625}, {x = 362.607421875, y = 221.3671875}}
|
||||
{{x = 362.607421875, y = 221.3671875}, {x = 365.166015625, y = 218.3203125}, {x = 369.228515625, y = 218.3203125}}
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var testDivs = [
|
||||
quad37,
|
||||
quad36,
|
||||
quad21g,
|
||||
quad21a,
|
||||
|
@ -1556,11 +1556,555 @@ path.quadTo(40.8951759, 17.8140678, 40.5937271, 17.4687576);
|
||||
path.close();
|
||||
</div>
|
||||
|
||||
<div id="testQuadratic40x">
|
||||
path.setFillType(SkPath::kEvenOdd_FillType);
|
||||
path.moveTo(2, 0);
|
||||
path.quadTo(3, 0, 2, 2);
|
||||
path.lineTo(3, 2);
|
||||
path.close();
|
||||
path.moveTo(3, 1);
|
||||
path.lineTo(0, 2);
|
||||
path.quadTo(0, 2, 1, 2);
|
||||
path.close();
|
||||
</div>
|
||||
|
||||
<div id="testQuadratic40xa">
|
||||
path.moveTo(31, 0);
|
||||
path.quadTo(41.3333359, 0, 37.8888893, 13.7777777);
|
||||
path.lineTo(31, 0);
|
||||
path.close();
|
||||
path.moveTo(37.8888893, 13.7777777);
|
||||
path.quadTo(37.2993202, 16.1360455, 36.3061028, 18.8979664);
|
||||
path.lineTo(0, 31);
|
||||
path.lineTo(15.5, 31);
|
||||
path.lineTo(35.5182915, 20.9908543);
|
||||
path.quadTo(33.7454262, 25.5091457, 31, 31);
|
||||
path.lineTo(46.5, 31);
|
||||
path.lineTo(40.2999992, 18.6000004);
|
||||
path.lineTo(46.5, 15.5);
|
||||
path.lineTo(39.8571434, 17.7142868);
|
||||
path.lineTo(37.8888893, 13.7777777);
|
||||
path.close();
|
||||
path.moveTo(36.3061028, 18.8979664);
|
||||
path.quadTo(35.9396667, 19.9169388, 35.5182915, 20.9908543);
|
||||
path.lineTo(40.2999992, 18.6000004);
|
||||
path.lineTo(39.8571434, 17.7142868);
|
||||
path.lineTo(36.3061028, 18.8979664);
|
||||
</div>
|
||||
|
||||
<div id="testQuadratic40xb">
|
||||
path.moveTo(31, 0);
|
||||
path.quadTo(46.5, 0, 31, 31);
|
||||
path.lineTo(46.5, 31);
|
||||
path.lineTo(31, 0);
|
||||
path.close();
|
||||
path.moveTo(46.5, 15.5);
|
||||
path.lineTo(0, 31);
|
||||
path.quadTo(0, 31, 15.5, 31);
|
||||
path.lineTo(46.5, 15.5);
|
||||
path.close();
|
||||
</div>
|
||||
|
||||
<div id="testQuadratic41o">
|
||||
path.moveTo(419.33905, 236.377808);
|
||||
path.quadTo(398.847778, 242.58728, 384.255524, 242.58728);
|
||||
path.quadTo(359.417633, 242.58728, 343.738708, 226.080429);
|
||||
path.quadTo(328.059784, 209.573578, 328.059784, 183.286819);
|
||||
path.quadTo(328.059784, 157.724487, 341.875854, 141.372879);
|
||||
path.quadTo(355.691956, 125.021263, 377.218109, 125.021263);
|
||||
path.quadTo(397.605896, 125.021263, 408.731201, 139.51004);
|
||||
path.quadTo(419.856506, 153.99881, 419.856506, 180.699539);
|
||||
path.lineTo(419.752991, 187.012497);
|
||||
path.lineTo(348.861511, 187.012497);
|
||||
path.quadTo(353.311646, 227.063599, 388.084686, 227.063599);
|
||||
path.quadTo(400.814117, 227.063599, 419.33905, 220.233185);
|
||||
path.lineTo(419.33905, 236.377808);
|
||||
path.close();
|
||||
path.moveTo(349.792938, 171.695801);
|
||||
path.lineTo(399.365234, 171.695801);
|
||||
path.quadTo(399.365234, 140.337967, 375.976227, 140.337967);
|
||||
path.quadTo(352.483704, 140.337967, 349.792938, 171.695801);
|
||||
path.close();
|
||||
path.moveTo(378.682587, 277.360321);
|
||||
path.lineTo(381.062897, 259.66333);
|
||||
path.quadTo(398.759888, 268.046112, 415.939423, 268.046112);
|
||||
path.quadTo(450.402008, 268.046112, 450.402008, 231.513718);
|
||||
path.lineTo(450.402008, 213.816727);
|
||||
path.quadTo(439.12146, 237.41272, 413.352142, 237.41272);
|
||||
path.quadTo(393.171356, 237.41272, 381.269867, 222.716965);
|
||||
path.quadTo(369.368378, 208.02121, 369.368378, 183.079834);
|
||||
path.quadTo(369.368378, 157.414017, 382.92572, 141.269379);
|
||||
path.quadTo(396.483093, 125.124756, 418.009247, 125.124756);
|
||||
path.quadTo(436.844666, 125.124756, 450.402008, 140.441467);
|
||||
path.lineTo(450.402008, 127.608543);
|
||||
path.lineTo(470.89325, 127.608543);
|
||||
path.lineTo(470.89325, 209.366608);
|
||||
path.quadTo(470.89325, 235.756866, 468.150757, 248.43454);
|
||||
path.quadTo(465.408234, 261.112213, 457.853363, 269.184509);
|
||||
path.quadTo(444.502991, 283.362823, 416.353394, 283.362823);
|
||||
path.quadTo(396.690063, 283.362823, 378.682587, 277.360321);
|
||||
path.close();
|
||||
path.moveTo(450.402008, 201.087311);
|
||||
path.lineTo(450.402008, 154.412781);
|
||||
path.quadTo(436.948151, 140.441467, 421.113983, 140.441467);
|
||||
path.quadTo(407.039185, 140.441467, 399.070374, 151.722);
|
||||
path.quadTo(391.101532, 163.002533, 391.101532, 182.665863);
|
||||
path.quadTo(391.101532, 219.612228, 417.07782, 219.612228);
|
||||
path.quadTo(434.774841, 219.612228, 450.402008, 201.087311);
|
||||
path.close();
|
||||
path.moveTo(482.9328, 236.377808);
|
||||
path.quadTo(462.441528, 242.58728, 447.849274, 242.58728);
|
||||
path.quadTo(423.011383, 242.58728, 407.332458, 226.080429);
|
||||
path.quadTo(391.653534, 209.573578, 391.653534, 183.286819);
|
||||
path.quadTo(391.653534, 157.724487, 405.469604, 141.372879);
|
||||
path.quadTo(419.285706, 125.021263, 440.811859, 125.021263);
|
||||
path.quadTo(461.199646, 125.021263, 472.324951, 139.51004);
|
||||
path.quadTo(483.450256, 153.99881, 483.450256, 180.699539);
|
||||
path.lineTo(483.346741, 187.012497);
|
||||
path.lineTo(412.455261, 187.012497);
|
||||
path.quadTo(416.905396, 227.063599, 451.678436, 227.063599);
|
||||
path.quadTo(464.407867, 227.063599, 482.9328, 220.233185);
|
||||
path.lineTo(482.9328, 236.377808);
|
||||
path.close();
|
||||
path.moveTo(413.386688, 171.695801);
|
||||
path.lineTo(462.958984, 171.695801);
|
||||
path.quadTo(462.958984, 140.337967, 439.569977, 140.337967);
|
||||
path.quadTo(416.077454, 140.337967, 413.386688, 171.695801);
|
||||
path.close();
|
||||
</div>
|
||||
|
||||
<div id="testQuadratic41s">
|
||||
path.moveTo(341.875854, 141.372879);
|
||||
path.quadTo(355.691956,125.021263, 377.218109,125.021263);
|
||||
path.quadTo(388.787811,125.021263, 397.374664,129.687164);
|
||||
path.quadTo(406.565979,125.124756, 418.009247,125.124756);
|
||||
path.quadTo(423.583374,125.124756, 428.695251,126.466187);
|
||||
path.quadTo(434.412903,125.021263, 440.811859,125.021263);
|
||||
path.quadTo(449.427277,125.021263, 456.388672,127.608543);
|
||||
path.lineTo(470.89325,127.608543);
|
||||
path.lineTo(470.89325,137.749908);
|
||||
path.quadTo(471.627319,138.601486, 472.324951,139.51004);
|
||||
path.quadTo(483.450256,153.99881, 483.450256,180.699539);
|
||||
path.lineTo(483.346741,187.012497);
|
||||
path.lineTo(470.89325,187.012497);
|
||||
path.lineTo(470.89325,209.366608);
|
||||
path.quadTo(470.89325,217.414856, 470.638184,224.187729);
|
||||
path.quadTo(476.428223,222.631516, 482.9328,220.233185);
|
||||
path.lineTo(482.9328,236.377808);
|
||||
path.quadTo(475.87207,238.517426, 469.511749,239.919785);
|
||||
path.quadTo(468.946777,244.754791, 468.150757,248.43454);
|
||||
path.quadTo(465.408234,261.112213, 457.853363,269.184509);
|
||||
path.quadTo(444.502991,283.362823, 416.353394,283.362823);
|
||||
path.quadTo(396.690063,283.362823, 378.682587,277.360321);
|
||||
path.lineTo(381.062897,259.66333);
|
||||
path.quadTo(398.759888,268.046112, 415.939423,268.046112);
|
||||
path.quadTo(444.719147,268.046112, 449.464905,242.568665);
|
||||
path.quadTo(448.648254,242.58728, 447.849274,242.58728);
|
||||
path.quadTo(433.084625,242.58728, 421.556366,236.754425);
|
||||
path.quadTo(418.89566,237.203537, 416.046783,237.346252);
|
||||
path.quadTo(397.661652,242.58728, 384.255524,242.58728);
|
||||
path.quadTo(359.417633,242.58728, 343.738708,226.080429);
|
||||
path.quadTo(328.059784,209.573578, 328.059784,183.286819);
|
||||
path.quadTo(328.059784,157.724487, 341.875854,141.372879);
|
||||
path.close();
|
||||
path.moveTo(442.014923, 226.179474);
|
||||
path.quadTo(445.951935,226.953491, 450.402008,227.049881);
|
||||
path.lineTo(450.402008,213.816727);
|
||||
path.quadTo(446.904755,221.132065, 442.014923,226.179474);
|
||||
path.close();
|
||||
path.moveTo(395.347717, 206.501785);
|
||||
path.quadTo(392.200165,197.593536, 391.734406,187.012497);
|
||||
path.lineTo(391.197113,187.012497);
|
||||
path.quadTo(391.738647,198.938644, 395.347717,206.501785);
|
||||
path.close();
|
||||
path.moveTo(391.808533, 171.695801);
|
||||
path.lineTo(392.428436,171.695801);
|
||||
path.quadTo(393.693451,162.656265, 397.02359,154.9935);
|
||||
path.quadTo(397.023804,154.992996, 397.024048,154.992493);
|
||||
path.quadTo(393.175995,143.845093, 383.003235,141.177292);
|
||||
path.quadTo(382.964447,141.223267, 382.92572,141.269379);
|
||||
</div>
|
||||
|
||||
<div id="testQuadratic42o">
|
||||
path.moveTo(421.962158, 236.285355);
|
||||
path.quadTo(400.947845, 242.65332, 385.983124, 242.65332);
|
||||
path.quadTo(360.511261, 242.65332, 344.432129, 225.725143);
|
||||
path.quadTo(328.352997, 208.796951, 328.352997, 181.839218);
|
||||
path.quadTo(328.352997, 155.62442, 342.521729, 138.855438);
|
||||
path.quadTo(356.69046, 122.086449, 378.766083, 122.086449);
|
||||
path.quadTo(399.674255, 122.086449, 411.083527, 136.945038);
|
||||
path.quadTo(422.492798, 151.803635, 422.492798, 179.185898);
|
||||
path.lineTo(422.386688, 185.660004);
|
||||
path.lineTo(349.685699, 185.660004);
|
||||
path.quadTo(354.24942, 226.733398, 389.910034, 226.733398);
|
||||
path.quadTo(402.964386, 226.733398, 421.962158, 219.728638);
|
||||
path.lineTo(421.962158, 236.285355);
|
||||
path.close();
|
||||
path.moveTo(350.6409, 169.952347);
|
||||
path.lineTo(401.478516, 169.952347);
|
||||
path.quadTo(401.478516, 137.794098, 377.492493, 137.794098);
|
||||
path.quadTo(353.40036, 137.794098, 350.6409, 169.952347);
|
||||
path.close();
|
||||
path.moveTo(379.213562, 278.313934);
|
||||
path.lineTo(381.654602, 260.165222);
|
||||
path.quadTo(399.803314, 268.761993, 417.421356, 268.761993);
|
||||
path.quadTo(452.763611, 268.761993, 452.763611, 231.297104);
|
||||
path.lineTo(452.763611, 213.148392);
|
||||
path.quadTo(441.195129, 237.34668, 414.768036, 237.34668);
|
||||
path.quadTo(394.072144, 237.34668, 381.866882, 222.275818);
|
||||
path.quadTo(369.661591, 207.204956, 369.661591, 181.626953);
|
||||
path.quadTo(369.661591, 155.306015, 383.565002, 138.749298);
|
||||
path.quadTo(397.468384, 122.192581, 419.544037, 122.192581);
|
||||
path.quadTo(438.860199, 122.192581, 452.763611, 137.900238);
|
||||
path.lineTo(452.763611, 124.739769);
|
||||
path.lineTo(473.777893, 124.739769);
|
||||
path.lineTo(473.777893, 208.584686);
|
||||
path.quadTo(473.777893, 235.64856, 470.965363, 248.649826);
|
||||
path.quadTo(468.152863, 261.651093, 460.405151, 269.929443);
|
||||
path.quadTo(446.71402, 284.469666, 417.845886, 284.469666);
|
||||
path.quadTo(397.680664, 284.469666, 379.213562, 278.313934);
|
||||
path.close();
|
||||
path.moveTo(452.763611, 200.094055);
|
||||
path.lineTo(452.763611, 152.228165);
|
||||
path.quadTo(438.966339, 137.900238, 422.727997, 137.900238);
|
||||
path.quadTo(408.293945, 137.900238, 400.121704, 149.468719);
|
||||
path.quadTo(391.949493, 161.037186, 391.949493, 181.202423);
|
||||
path.quadTo(391.949493, 219.091827, 418.588837, 219.091827);
|
||||
path.quadTo(436.737549, 219.091827, 452.763611, 200.094055);
|
||||
path.close();
|
||||
path.moveTo(485.555908, 236.285355);
|
||||
path.quadTo(464.541595, 242.65332, 449.576874, 242.65332);
|
||||
path.quadTo(424.105011, 242.65332, 408.025879, 225.725143);
|
||||
path.quadTo(391.946747, 208.796951, 391.946747, 181.839218);
|
||||
path.quadTo(391.946747, 155.62442, 406.115479, 138.855438);
|
||||
path.quadTo(420.28421, 122.086449, 442.359833, 122.086449);
|
||||
path.quadTo(463.268005, 122.086449, 474.677277, 136.945038);
|
||||
path.quadTo(486.086548, 151.803635, 486.086548, 179.185898);
|
||||
path.lineTo(485.980438, 185.660004);
|
||||
path.lineTo(413.279449, 185.660004);
|
||||
path.quadTo(417.84317, 226.733398, 453.503784, 226.733398);
|
||||
path.quadTo(466.558136, 226.733398, 485.555908, 219.728638);
|
||||
path.lineTo(485.555908, 236.285355);
|
||||
path.close();
|
||||
path.moveTo(414.23465, 169.952347);
|
||||
path.lineTo(465.072266, 169.952347);
|
||||
path.quadTo(465.072266, 137.794098, 441.086243, 137.794098);
|
||||
path.quadTo(416.99411, 137.794098, 414.23465, 169.952347);
|
||||
path.close();
|
||||
</div>
|
||||
|
||||
<div id="testQuadratic42s">
|
||||
path.moveTo(342.521729, 138.855438);
|
||||
path.quadTo(356.69046,122.086449, 378.766083,122.086449);
|
||||
path.quadTo(390.293488,122.086449, 398.933502,126.603004);
|
||||
path.quadTo(408.150299,122.192581, 419.544037,122.192581);
|
||||
path.quadTo(425.108429,122.192581, 430.223633,123.496056);
|
||||
path.quadTo(435.959412,122.086449, 442.359833,122.086449);
|
||||
path.quadTo(451.19516,122.086449, 458.334229,124.739769);
|
||||
path.lineTo(473.777893,124.739769);
|
||||
path.lineTo(473.777893,135.814713);
|
||||
path.quadTo(474.234741,136.368698, 474.677277,136.945038);
|
||||
path.quadTo(486.086548,151.803635, 486.086548,179.185898);
|
||||
path.lineTo(485.980438,185.660004);
|
||||
path.lineTo(473.777893,185.660004);
|
||||
path.lineTo(473.777893,208.584686);
|
||||
path.quadTo(473.777893,216.745773, 473.522156,223.628113);
|
||||
path.quadTo(479.207153,222.069519, 485.555908,219.728638);
|
||||
path.lineTo(485.555908,236.285355);
|
||||
path.quadTo(478.638306,238.381592, 472.376221,239.787796);
|
||||
path.quadTo(471.792389,244.826782, 470.965363,248.649826);
|
||||
path.quadTo(468.152863,261.651093, 460.405151,269.929443);
|
||||
path.quadTo(446.71402,284.469666, 417.845886,284.469666);
|
||||
path.quadTo(397.680664,284.469666, 379.213562,278.313934);
|
||||
path.lineTo(381.654602,260.165222);
|
||||
path.quadTo(399.803314,268.761993, 417.421356,268.761993);
|
||||
path.quadTo(446.944275,268.761993, 451.80542,242.619034);
|
||||
path.quadTo(450.674866,242.65332, 449.576874,242.65332);
|
||||
path.quadTo(434.524628,242.65332, 422.75238,236.741913);
|
||||
path.quadTo(420.864227,237.041901, 418.884674,237.193085);
|
||||
path.quadTo(399.840271,242.65332, 385.983124,242.65332);
|
||||
path.quadTo(360.511261,242.65332, 344.432129,225.725143);
|
||||
path.quadTo(328.352997,208.796951, 328.352997,181.839218);
|
||||
path.quadTo(328.352997,155.62442, 342.521729,138.855438);
|
||||
path.close();
|
||||
path.moveTo(383.823944, 138.443222);
|
||||
path.quadTo(380.900299,137.794098, 377.492493,137.794098);
|
||||
path.quadTo(353.40036,137.794098, 350.6409,169.952347);
|
||||
path.lineTo(370.408203,169.952347);
|
||||
path.quadTo(372.883484,151.469254, 383.565002,138.749298);
|
||||
path.quadTo(383.694122,138.595551, 383.823944,138.443222);
|
||||
path.close();
|
||||
path.moveTo(369.740021, 185.660004);
|
||||
path.lineTo(349.685699,185.660004);
|
||||
path.quadTo(353.983734,224.342361, 385.863525,226.594208);
|
||||
path.quadTo(383.762756,224.616837, 381.866882,222.275818);
|
||||
path.quadTo(370.639954,208.41301, 369.740021,185.660004);
|
||||
path.close();
|
||||
path.moveTo(413.279449, 185.660004);
|
||||
path.quadTo(415.737305,207.780716, 427.214905,217.987976);
|
||||
path.quadTo(440.600586,214.512451, 452.763611,200.094055);
|
||||
path.lineTo(452.763611,185.660004);
|
||||
</div>
|
||||
|
||||
<div id="testQuadratic43o">
|
||||
path.moveTo(288.755981, 240);
|
||||
path.lineTo(288.755981, 102.232819);
|
||||
path.lineTo(315.843994, 102.232819);
|
||||
path.lineTo(354.009216, 208.816208);
|
||||
path.lineTo(393.291473, 102.232819);
|
||||
path.lineTo(417.493835, 102.232819);
|
||||
path.lineTo(417.493835, 240);
|
||||
path.lineTo(399.248962, 240);
|
||||
path.lineTo(399.248962, 127.92453);
|
||||
path.lineTo(361.269928, 230.784485);
|
||||
path.lineTo(342.373474, 230.784485);
|
||||
path.lineTo(305.511444, 127.645271);
|
||||
path.lineTo(305.511444, 240);
|
||||
path.lineTo(288.755981, 240);
|
||||
path.close();
|
||||
path.moveTo(397.864014, 236.741989);
|
||||
path.quadTo(379.433014, 242.327148, 366.307892, 242.327148);
|
||||
path.quadTo(343.967255, 242.327148, 329.864746, 227.479935);
|
||||
path.quadTo(315.762238, 212.632736, 315.762238, 188.988907);
|
||||
path.quadTo(315.762238, 165.996674, 328.189209, 151.289093);
|
||||
path.quadTo(340.61618, 136.581512, 359.978058, 136.581512);
|
||||
path.quadTo(378.315979, 136.581512, 388.322723, 149.613556);
|
||||
path.quadTo(398.329468, 162.645584, 398.329468, 186.661758);
|
||||
path.lineTo(398.236359, 192.339996);
|
||||
path.lineTo(334.472504, 192.339996);
|
||||
path.quadTo(338.475189, 228.364258, 369.752075, 228.364258);
|
||||
path.quadTo(381.20163, 228.364258, 397.864014, 222.220581);
|
||||
path.lineTo(397.864014, 236.741989);
|
||||
path.close();
|
||||
path.moveTo(335.310272, 178.563278);
|
||||
path.lineTo(379.898438, 178.563278);
|
||||
path.quadTo(379.898438, 150.358246, 358.861023, 150.358246);
|
||||
path.quadTo(337.730499, 150.358246, 335.310272, 178.563278);
|
||||
path.close();
|
||||
path.moveTo(346.052765, 240);
|
||||
path.lineTo(346.052765, 138.908661);
|
||||
path.lineTo(364.390686, 138.908661);
|
||||
path.lineTo(364.390686, 157.898193);
|
||||
path.quadTo(375.281769, 136.674606, 396.039917, 136.674606);
|
||||
path.quadTo(398.832489, 136.674606, 401.904327, 137.140045);
|
||||
path.lineTo(401.904327, 154.267853);
|
||||
path.quadTo(397.156952, 152.685394, 393.526611, 152.685394);
|
||||
path.quadTo(376.119537, 152.685394, 364.390686, 173.350464);
|
||||
path.lineTo(364.390686, 240);
|
||||
path.lineTo(346.052765, 240);
|
||||
path.close();
|
||||
path.moveTo(362.792297, 273.604034);
|
||||
path.lineTo(364.933289, 257.68634);
|
||||
path.quadTo(380.850983, 265.226288, 396.303253, 265.226288);
|
||||
path.quadTo(427.300842, 265.226288, 427.300842, 232.366959);
|
||||
path.lineTo(427.300842, 216.449265);
|
||||
path.quadTo(417.15448, 237.672852, 393.976105, 237.672852);
|
||||
path.quadTo(375.824341, 237.672852, 365.119446, 224.454651);
|
||||
path.quadTo(354.414581, 211.23645, 354.414581, 188.802734);
|
||||
path.quadTo(354.414581, 165.717422, 366.608826, 151.196014);
|
||||
path.quadTo(378.803101, 136.674606, 398.164948, 136.674606);
|
||||
path.quadTo(415.106598, 136.674606, 427.300842, 150.451324);
|
||||
path.lineTo(427.300842, 138.908661);
|
||||
path.lineTo(445.731873, 138.908661);
|
||||
path.lineTo(445.731873, 212.446564);
|
||||
path.quadTo(445.731873, 236.183472, 443.265106, 247.586502);
|
||||
path.quadTo(440.798309, 258.989532, 434.003052, 266.250244);
|
||||
path.quadTo(421.994965, 279.002991, 396.675598, 279.002991);
|
||||
path.quadTo(378.989258, 279.002991, 362.792297, 273.604034);
|
||||
path.close();
|
||||
path.moveTo(427.300842, 204.999695);
|
||||
path.lineTo(427.300842, 163.017929);
|
||||
path.quadTo(415.199677, 150.451324, 400.95755, 150.451324);
|
||||
path.quadTo(388.297852, 150.451324, 381.130249, 160.597687);
|
||||
path.quadTo(373.962616, 170.744064, 373.962616, 188.430389);
|
||||
path.quadTo(373.962616, 221.662079, 397.327179, 221.662079);
|
||||
path.quadTo(413.244873, 221.662079, 427.300842, 204.999695);
|
||||
path.close();
|
||||
path.moveTo(461.457764, 236.741989);
|
||||
path.quadTo(443.026764, 242.327148, 429.901642, 242.327148);
|
||||
path.quadTo(407.561005, 242.327148, 393.458496, 227.479935);
|
||||
path.quadTo(379.355988, 212.632736, 379.355988, 188.988907);
|
||||
path.quadTo(379.355988, 165.996674, 391.782959, 151.289093);
|
||||
path.quadTo(404.20993, 136.581512, 423.571808, 136.581512);
|
||||
path.quadTo(441.909729, 136.581512, 451.916473, 149.613556);
|
||||
path.quadTo(461.923218, 162.645584, 461.923218, 186.661758);
|
||||
path.lineTo(461.830109, 192.339996);
|
||||
path.lineTo(398.066254, 192.339996);
|
||||
path.quadTo(402.068939, 228.364258, 433.345825, 228.364258);
|
||||
path.quadTo(444.79538, 228.364258, 461.457764, 222.220581);
|
||||
path.lineTo(461.457764, 236.741989);
|
||||
path.close();
|
||||
path.moveTo(398.904022, 178.563278);
|
||||
path.lineTo(443.492188, 178.563278);
|
||||
path.quadTo(443.492188, 150.358246, 422.454773, 150.358246);
|
||||
path.quadTo(401.324249, 150.358246, 398.904022, 178.563278);
|
||||
path.close();
|
||||
</div>
|
||||
|
||||
<div id="testQuadratic43s">
|
||||
path.moveTo(288.755981, 240);
|
||||
path.lineTo(288.755981,102.232819);
|
||||
path.lineTo(315.843994,102.232819);
|
||||
path.lineTo(331.979736,147.294876);
|
||||
path.quadTo(343.453125,136.581512, 359.978058,136.581512);
|
||||
path.quadTo(370.869446,136.581512, 378.822021,141.178574);
|
||||
path.quadTo(378.893585,141.140915, 378.965302,141.103577);
|
||||
path.lineTo(393.291473,102.232819);
|
||||
path.lineTo(417.493835,102.232819);
|
||||
path.lineTo(417.493835,136.965759);
|
||||
path.quadTo(420.44223,136.581512, 423.571808,136.581512);
|
||||
path.quadTo(431.320984,136.581512, 437.582458,138.908661);
|
||||
path.lineTo(445.731873,138.908661);
|
||||
path.lineTo(445.731873,143.392502);
|
||||
path.quadTo(449.143951,146.002823, 451.916473,149.613556);
|
||||
path.quadTo(461.923218,162.645584, 461.923218,186.661758);
|
||||
path.lineTo(461.830109,192.339996);
|
||||
path.lineTo(445.731873,192.339996);
|
||||
path.lineTo(445.731873,212.446564);
|
||||
path.quadTo(445.731873,220.39856, 445.455017,226.966339);
|
||||
path.quadTo(452.7435,225.43367, 461.457764,222.220581);
|
||||
path.lineTo(461.457764,236.741989);
|
||||
path.quadTo(452.250824,239.531982, 444.367889,240.928268);
|
||||
path.quadTo(443.897583,244.662796, 443.265106,247.586502);
|
||||
path.quadTo(440.798309,258.989532, 434.003052,266.250244);
|
||||
path.quadTo(421.994965,279.002991, 396.675598,279.002991);
|
||||
path.quadTo(378.989258,279.002991, 362.792297,273.604034);
|
||||
path.lineTo(364.933289,257.68634);
|
||||
path.quadTo(380.850983,265.226288, 396.303253,265.226288);
|
||||
path.quadTo(422.230743,265.226288, 426.471558,242.237076);
|
||||
path.quadTo(419.570892,241.869324, 413.503387,240);
|
||||
path.lineTo(399.248962,240);
|
||||
path.lineTo(399.248962,237.37915);
|
||||
path.quadTo(397.047638,237.633072, 394.711517,237.667465);
|
||||
path.quadTo(378.296356,242.327148, 366.307892,242.327148);
|
||||
path.quadTo(357.463165,242.327148, 349.909637,240);
|
||||
path.lineTo(346.052765,240);
|
||||
path.lineTo(346.052765,238.625916);
|
||||
path.quadTo(336.926056,234.914124, 329.864746,227.479935);
|
||||
path.quadTo(315.762238,212.632736, 315.762238,188.988907);
|
||||
path.quadTo(315.762238,176.540054, 319.405273,166.519882);
|
||||
path.lineTo(305.511444,127.645271);
|
||||
path.lineTo(305.511444,240);
|
||||
path.lineTo(288.755981,240);
|
||||
path.close();
|
||||
path.moveTo(375.464813, 192.339996);
|
||||
path.lineTo(374.267029,195.583939);
|
||||
path.quadTo(375.987579,214.575378, 387.432068,219.736267);
|
||||
path.quadTo(380.122528,208.101486, 379.428741,192.339996);
|
||||
path.lineTo(375.464813,192.339996);
|
||||
path.close();
|
||||
path.moveTo(427.300842, 178.563278);
|
||||
path.lineTo(427.300842,163.017929);
|
||||
path.quadTo(422.561523,158.096329, 417.493835,155.102234);
|
||||
path.lineTo(417.493835,178.563278);
|
||||
path.lineTo(427.300842,178.563278);
|
||||
path.close();
|
||||
path.moveTo(427.300842, 192.339996);
|
||||
path.lineTo(417.493835,192.339996);
|
||||
path.lineTo(417.493835,214.429169);
|
||||
path.quadTo(422.505676,210.684036, 427.300842,204.999695);
|
||||
path.lineTo(427.300842,192.339996);
|
||||
path.close();
|
||||
path.moveTo(420.700134, 226.556015);
|
||||
path.quadTo(423.794342,227.54834, 427.300842,227.996094);
|
||||
path.lineTo(427.300842,216.449265);
|
||||
path.quadTo(424.497772,222.312531, 420.700134,226.556015);
|
||||
path.close();
|
||||
path.moveTo(368.744965, 228.354782);
|
||||
path.quadTo(366.836426,226.574738, 365.119446,224.454651);
|
||||
path.quadTo(364.748657,223.996796, 364.390686,223.527878);
|
||||
path.lineTo(364.390686,228.077774);
|
||||
path.quadTo(366.495239,228.312164, 368.744965,228.354782);
|
||||
path.close();
|
||||
path.moveTo(399.248962, 199.701065);
|
||||
path.lineTo(399.248962,192.339996);
|
||||
path.lineTo(398.236359,192.339996);
|
||||
path.lineTo(398.066254,192.339996);
|
||||
path.quadTo(398.498535,196.230621, 399.248962,199.701065);
|
||||
path.close();
|
||||
path.moveTo(399.248962, 178.563278);
|
||||
path.lineTo(399.248962,175.376892);
|
||||
path.quadTo(399.04483,176.922348, 398.904022,178.563278);
|
||||
path.lineTo(399.248962,178.563278);
|
||||
path.close();
|
||||
path.moveTo(399.248962, 136.688828);
|
||||
path.lineTo(399.248962,127.92453);
|
||||
path.lineTo(396.018158,136.674606);
|
||||
path.quadTo(396.029053,136.674606, 396.039917,136.674606);
|
||||
path.quadTo(396.513672,136.674606, 396.995453,136.688004);
|
||||
path.quadTo(397.576904,136.674606, 398.164948,136.674606);
|
||||
path.quadTo(398.709412,136.674606, 399.248962,136.688828);
|
||||
path.close();
|
||||
path.moveTo(346.052765, 178.563278);
|
||||
path.lineTo(346.052765,154.02713);
|
||||
path.quadTo(340.97113,157.621338, 338.22525,164.736588);
|
||||
path.lineTo(343.1763,178.563278);
|
||||
path.lineTo(346.052765,178.563278);
|
||||
path.close();
|
||||
path.moveTo(364.390686, 150.922379);
|
||||
path.lineTo(364.390686,154.048065);
|
||||
path.quadTo(365.340851,152.726639, 366.38147,151.468765);
|
||||
path.quadTo(365.420258,151.14975, 364.390686,150.922379);
|
||||
path.close();
|
||||
path.moveTo(367.863586, 152.032623);
|
||||
path.quadTo(367.144043,151.721848, 366.38147,151.468765);
|
||||
</div>
|
||||
|
||||
<div id="testQuadratic44o">
|
||||
path.moveTo(354.009216, 208.816208);
|
||||
path.lineTo(393.291473, 102.232819);
|
||||
path.lineTo(399.248962, 127.92453);
|
||||
path.lineTo(361.269928, 230.784485);
|
||||
path.lineTo(354.009216, 208.816208);
|
||||
path.close();
|
||||
path.moveTo(328.189209, 151.289093);
|
||||
path.quadTo(340.61618, 136.581512, 359.978058, 136.581512);
|
||||
path.quadTo(378.315979, 136.581512, 388.322723, 149.613556);
|
||||
path.lineTo(328.189209, 151.289093);
|
||||
path.close();
|
||||
path.moveTo(346.052765, 138.908661);
|
||||
path.lineTo(364.390686, 138.908661);
|
||||
path.lineTo(364.390686, 157.898193);
|
||||
path.quadTo(375.281769, 136.674606, 396.039917, 136.674606);
|
||||
path.lineTo(346.052765, 138.908661);
|
||||
path.close();
|
||||
</div>
|
||||
|
||||
<div id="testQuadratic44s">
|
||||
path.moveTo(380.33902, 137.376312);
|
||||
path.lineTo(393.291473,102.232819);
|
||||
path.lineTo(399.248962,127.92453);
|
||||
path.lineTo(396.018158,136.674606);
|
||||
path.quadTo(396.029053,136.674606, 396.039917,136.674606);
|
||||
path.lineTo(396.017792,136.675598);
|
||||
path.lineTo(361.269928,230.784485);
|
||||
path.lineTo(354.009216,208.816208);
|
||||
path.lineTo(375.699249,149.965286);
|
||||
path.lineTo(369.22699,150.14563);
|
||||
path.quadTo(373.524384,144.511566, 378.917297,141.233871);
|
||||
path.lineTo(380.33902,137.376312);
|
||||
path.close();
|
||||
path.moveTo(392.55661, 136.830276);
|
||||
path.quadTo(385.032623,137.51709, 378.917297,141.233856);
|
||||
path.quadTo(378.917297,141.233856, 378.917297,141.233856);
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var testDivs = [
|
||||
testQuadratic44o,
|
||||
testQuadratic44s,
|
||||
testQuadratic43o,
|
||||
testQuadratic43s,
|
||||
testQuadratic42o,
|
||||
testQuadratic42s,
|
||||
testQuadratic41o,
|
||||
testQuadratic41s,
|
||||
testQuadratic40xb,
|
||||
testQuadratic40xa,
|
||||
testQuadratic40x,
|
||||
testQuadratic39,
|
||||
testQuadratic39a,
|
||||
testQuadratic38,
|
||||
@ -1729,6 +2273,7 @@ var tests = [];
|
||||
var testTitles = [];
|
||||
var testIndex = 0;
|
||||
var hasXor = false;
|
||||
var draw_labels = true;
|
||||
|
||||
var ctx;
|
||||
|
||||
@ -1939,6 +2484,9 @@ function draw(test, title, _at_x, _at_y, scale) {
|
||||
ctx.fillStyle="rgba(192,192,255, 0.3)";
|
||||
ctx.fill();
|
||||
|
||||
if (!draw_labels) {
|
||||
return;
|
||||
}
|
||||
ctx.fillStyle="blue";
|
||||
for (contours in test) {
|
||||
var contour = test[contours];
|
||||
@ -2025,6 +2573,10 @@ function doKeyPress(evt) {
|
||||
case '+':
|
||||
drawTop();
|
||||
break;
|
||||
case 'x':
|
||||
draw_labels ^= true;
|
||||
drawTop();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
45
gyp/shapeops_tool.gyp
Normal file
45
gyp/shapeops_tool.gyp
Normal file
@ -0,0 +1,45 @@
|
||||
# GYP file to build unit tests.
|
||||
{
|
||||
'includes': [
|
||||
'apptype_console.gypi',
|
||||
'common.gypi',
|
||||
],
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'addTest',
|
||||
'type': 'executable',
|
||||
'include_dirs' : [
|
||||
'../src/core',
|
||||
],
|
||||
'sources': [
|
||||
'../experimental/Intersection/AddTestOutput/main.cpp',
|
||||
],
|
||||
'dependencies': [
|
||||
'core.gyp:core',
|
||||
'effects.gyp:effects',
|
||||
'experimental.gyp:experimental',
|
||||
'images.gyp:images',
|
||||
'ports.gyp:ports',
|
||||
'pdf.gyp:pdf',
|
||||
'utils.gyp:utils',
|
||||
],
|
||||
'conditions': [
|
||||
[ 'skia_gpu == 1', {
|
||||
'include_dirs': [
|
||||
'../src/gpu',
|
||||
],
|
||||
'dependencies': [
|
||||
'gpu.gyp:gr',
|
||||
'gpu.gyp:skgr',
|
||||
],
|
||||
}],
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:2
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=2 shiftwidth=2:
|
Loading…
Reference in New Issue
Block a user