git-svn-id: http://skia.googlecode.com/svn/trunk@7637 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
caryclark@google.com 2013-02-07 13:13:41 +00:00
Родитель 709906b74d
Коммит beda389e64
27 изменённых файлов: 703 добавлений и 118 удалений

Просмотреть файл

@ -26,6 +26,8 @@ static bool replace(const char* fun, const char* dir, const char* filename, cons
char* opInsert = strstr(opData.begin(), marker);
if (!opInsert) {
SkDebugf("%s missing marker in %s\n", fun, outFileStr.c_str());
opStreamOut.write(opData.begin(), opLen);
opStreamOut.flush();
return false;
}
const char* opInsertEnd = opInsert + strlen(marker);
@ -33,6 +35,8 @@ static bool replace(const char* fun, const char* dir, const char* filename, cons
char* opInsert2 = strstr(opInsert, marker2);
if (!opInsert2) {
SkDebugf("%s missing marker second half in %s\n", fun, outFileStr.c_str());
opStreamOut.write(opData.begin(), opLen);
opStreamOut.flush();
return false;
}
opInsertEnd = opInsert2 + strlen(marker2);
@ -98,10 +102,10 @@ int main (int argc, char * const argv[]) {
return 0;
}
const char simplifyMarker[] =
"#if 1 // set to 1 for multiple thread -- no debugging"
"#define FORCE_RELEASE 1 // set force release to 1 for multiple thread -- no debugging"
;
const char simplifyReplace[] =
"#if 0 // set to 1 for multiple thread -- no debugging"
"#define FORCE_RELEASE 0 // set force release to 1 for multiple thread -- no debugging"
;
if (!replace(argv[0], dir, "Simplify.cpp", simplifyMarker, NULL, simplifyReplace,
sizeof(simplifyReplace) - 1)) {

Просмотреть файл

@ -14,6 +14,7 @@
#define DEBUG_COMPUTE_DELTA 1
#define COMPUTE_DELTA 0
#define DEBUG_QUAD_PART 0
static const double tClipLimit = 0.8; // http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf see Multiple intersections
@ -256,6 +257,24 @@ static int quadPart(const Cubic& cubic, double tStart, double tEnd, Quadratic& s
// FIXME: should reduceOrder be looser in this use case if quartic is going to blow up on an
// extremely shallow quadratic?
int order = reduceOrder(quad, simple);
#if DEBUG_QUAD_PART
SkDebugf("%s cubic=(%1.17g,%1.17g %1.17g,%1.17g %1.17g,%1.17g %1.17g,%1.17g) t=(%1.17g,%1.17g)\n",
__FUNCTION__, cubic[0].x, cubic[0].y, cubic[1].x, cubic[1].y, cubic[2].x, cubic[2].y,
cubic[3].x, cubic[3].y, tStart, tEnd);
SkDebugf("%s part=(%1.17g,%1.17g %1.17g,%1.17g %1.17g,%1.17g %1.17g,%1.17g)"
" quad=(%1.17g,%1.17g %1.17g,%1.17g %1.17g,%1.17g)\n", __FUNCTION__, part[0].x, part[0].y,
part[1].x, part[1].y, part[2].x, part[2].y, part[3].x, part[3].y, quad[0].x, quad[0].y,
quad[1].x, quad[1].y, quad[2].x, quad[2].y);
SkDebugf("%s simple=(%1.17g,%1.17g", __FUNCTION__, simple[0].x, simple[0].y);
if (order > 1) {
SkDebugf(" %1.17g,%1.17g", simple[1].x, simple[1].y);
}
if (order > 2) {
SkDebugf(" %1.17g,%1.17g", simple[2].x, simple[2].y);
}
SkDebugf(")\n");
SkASSERT(order < 4 && order > 0);
#endif
return order;
}
@ -276,8 +295,33 @@ static void intersectWithOrder(const Quadratic& simple1, int order1, const Quadr
}
}
static void doIntersect(const Cubic& cubic1, double t1s, double t1m, double t1e,
static double distanceFromEnd(double t) {
return t > 0.5 ? 1 - t : t;
}
// OPTIMIZATION: this used to try to guess the value for delta, and that may still be worthwhile
static void bumpForRetry(double t1, double t2, double& s1, double& e1, double& s2, double& e2) {
double dt1 = distanceFromEnd(t1);
double dt2 = distanceFromEnd(t2);
double delta = 1.0 / precisionUnit;
if (dt1 < dt2) {
if (t1 == dt1) {
s1 = SkTMax(s1 - delta, 0.);
} else {
e1 = SkTMin(e1 + delta, 1.);
}
} else {
if (t2 == dt2) {
s2 = SkTMax(s2 - delta, 0.);
} else {
e2 = SkTMin(e2 + delta, 1.);
}
}
}
static bool doIntersect(const Cubic& cubic1, double t1s, double t1m, double t1e,
const Cubic& cubic2, double t2s, double t2m, double t2e, Intersections& i) {
bool result = false;
i.upDepth();
// divide the quadratics at the new t value and try again
double p1s = t1s;
@ -292,8 +336,8 @@ static void doIntersect(const Cubic& cubic1, double t1s, double t1m, double t1e,
int o2a = quadPart(cubic2, p2s, p2e, s2a);
Intersections locals;
#if 0 && SK_DEBUG
if (0.366025505 >= p1s && 0.366025887 <= p1e
&& 0.633974342 >= p2s && 0.633975487 <= p2e) {
if (0.497026154 >= p1s && 0.497026535 <= p1e
&& 0.710440575 >= p2s && 0.710440956 <= p2e) {
SkDebugf("t1=(%1.9g,%1.9g) o1=%d t2=(%1.9g,%1.9g) o2=%d\n",
p1s, p1e, o1a, p2s, p2e, o2a);
if (o1a == 2) {
@ -312,7 +356,8 @@ static void doIntersect(const Cubic& cubic1, double t1s, double t1m, double t1e,
}
Intersections xlocals;
intersectWithOrder(s1a, o1a, s2a, o2a, xlocals);
}
SkDebugf("xlocals.fUsed=%d\n", xlocals.used());
}
#endif
intersectWithOrder(s1a, o1a, s2a, o2a, locals);
for (int tIdx = 0; tIdx < locals.used(); ++tIdx) {
@ -325,12 +370,26 @@ static void doIntersect(const Cubic& cubic1, double t1s, double t1m, double t1e,
#if 0 && SK_DEBUG
SkDebugf("to1=%1.9g p1=(%1.9g,%1.9g) to2=%1.9g p2=(%1.9g,%1.9g) d=%1.9g\n",
to1, p1.x, p1.y, to2, p2.x, p2.y, p1.distance(p2));
#endif
if (p1.approximatelyEqual(p2)) {
i.insert(i.swapped() ? to2 : to1, i.swapped() ? to1 : to2);
result = true;
} else {
doIntersect(cubic1, p1s, to1, p1e, cubic2, p2s, to2, p2e, i);
result = doIntersect(cubic1, p1s, to1, p1e, cubic2, p2s, to2, p2e, i);
// if both cubics curve in the same direction, the quadratic intersection
// may mark a range that does not contain the cubic intersection. If no
// intersection is found, look again including the t distance of the
// of the quadratic intersection nearest a quadratic end (which in turn is
// nearest the actual cubic)
if (!result) {
double b1s = p1s;
double b1e = p1e;
double b2s = p2s;
double b2e = p2e;
bumpForRetry(locals.fT[0][tIdx], locals.fT[1][tIdx], b1s, b1e, b2s, b2e);
result = doIntersect(cubic1, b1s, to1, b1e, cubic2, b2s, to2, b2e, i);
}
}
}
p2s = p2e;
@ -340,6 +399,7 @@ static void doIntersect(const Cubic& cubic1, double t1s, double t1m, double t1e,
p1e = t1e;
}
i.downDepth();
return result;
}
// this flavor approximates the cubics with quads to find the intersecting ts
@ -371,9 +431,22 @@ static bool intersect2(const Cubic& cubic1, double t1s, double t1e, const Cubic&
const double t2 = t2s + (t2e - t2s) * tEnd2;
Quadratic s2;
int o2 = quadPart(cubic2, t2Start, t2, s2);
#if 0 && SK_DEBUG
if (0.497026154 >= t1Start && 0.497026535 <= t1
&& 0.710440575 + 0.0004 >= t2Start && 0.710440956 <= t2) {
Cubic cSub1, cSub2;
sub_divide(cubic1, t1Start, tEnd1, cSub1);
sub_divide(cubic2, t2Start, tEnd2, cSub2);
SkDebugf("t1=(%1.9g,%1.9g) t2=(%1.9g,%1.9g)\n",
t1Start, t1, t2Start, t2);
Intersections xlocals;
intersectWithOrder(s1, o1, s2, o2, xlocals);
SkDebugf("xlocals.fUsed=%d\n", xlocals.used());
}
#endif
Intersections locals;
intersectWithOrder(s1, o1, s2, o2, locals);
for (int tIdx = 0; tIdx < locals.used(); ++tIdx) {
double to1 = t1Start + (t1 - t1Start) * locals.fT[0][tIdx];
double to2 = t2Start + (t2 - t2Start) * locals.fT[1][tIdx];
@ -404,10 +477,34 @@ static bool intersect2(const Cubic& cubic1, double t1s, double t1e, const Cubic&
--debugDepth;
#endif
#else
doIntersect(cubic1, t1Start, to1, t1, cubic2, t2Start, to2, t2, i);
#if 0 && SK_DEBUG
if (0.497026154 >= t1Start && 0.497026535 <= t1
&& 0.710440575 >= t2Start && 0.710440956 <= t2) {
SkDebugf("t1=(%1.9g,%1.9g) t2=(%1.9g,%1.9g)\n",
t1Start, t1, t2Start, t2);
}
#endif
bool found = doIntersect(cubic1, t1Start, to1, t1, cubic2, t2Start, to2, t2, i);
if (!found) {
double b1s = t1Start;
double b1e = t1;
double b2s = t2Start;
double b2e = t2;
bumpForRetry(locals.fT[0][tIdx], locals.fT[1][tIdx], b1s, b1e, b2s, b2e);
doIntersect(cubic1, b1s, to1, b1e, cubic2, b2s, to2, b2e, i);
}
#endif
}
}
if (locals.coincidentUsed()) {
SkASSERT(locals.coincidentUsed() == 2);
double coTs[2][2];
for (int tIdx = 0; tIdx < locals.coincidentUsed(); ++tIdx) {
coTs[0][tIdx] = t1Start + (t1 - t1Start) * locals.fCoincidentT[0][tIdx];
coTs[1][tIdx] = t2Start + (t2 - t2Start) * locals.fCoincidentT[1][tIdx];
}
i.addCoincident(coTs[0][0], coTs[0][1], coTs[1][0], coTs[1][1]);
}
t2Start = t2;
}
t1Start = t1;

Просмотреть файл

@ -92,12 +92,38 @@ static void oneOff(const Cubic& cubic1, const Cubic& cubic2) {
#if ONE_OFF_DEBUG
SkDebugf("%s t1=%1.9g (%1.9g, %1.9g) (%1.9g, %1.9g) t2=%1.9g\n", __FUNCTION__,
tt1, xy1.x, xy1.y, xy2.x, xy2.y, tt2);
#endif
SkASSERT(xy1.approximatelyEqual(xy2));
}
for (int pt = 0; pt < intersections2.coincidentUsed(); ++pt) {
double tt1 = intersections2.fCoincidentT[0][pt];
_Point xy1, xy2;
xy_at_t(cubic1, tt1, xy1.x, xy1.y);
int pt2 = intersections2.fFlip ? intersections2.used() - pt - 1 : pt;
double tt2 = intersections2.fCoincidentT[1][pt2];
xy_at_t(cubic2, tt2, xy2.x, xy2.y);
#if ONE_OFF_DEBUG
SkDebugf("%s t1=%1.9g (%1.9g, %1.9g) (%1.9g, %1.9g) t2=%1.9g\n", __FUNCTION__,
tt1, xy1.x, xy1.y, xy2.x, xy2.y, tt2);
#endif
SkASSERT(xy1.approximatelyEqual(xy2));
}
}
static const Cubic testSet[] = {
{{0,1}, {3,4}, {1,0}, {3,0}},
{{0,1}, {0,3}, {1,0}, {4,3}},
{{0, 0}, {1, 2}, {3, 4}, {4, 4}},
{{0, 0}, {1, 2}, {3, 4}, {4, 4}},
{{4, 4}, {3, 4}, {1, 2}, {0, 0}},
{{0,1}, {2,3}, {1,0}, {1,0}},
{{0,1}, {0,1}, {1,0}, {3,2}},
{{0,2}, {0,1}, {1,0}, {1,0}},
{{0,1}, {0,1}, {2,0}, {1,0}},
{{0, 0}, {0, 1}, {1, 1}, {1, 0}},
{{1, 0}, {0, 0}, {0, 1}, {1, 1}},
@ -374,12 +400,12 @@ void CubicIntersection_RandTest() {
}
void CubicIntersection_IntersectionFinder() {
Cubic cubic1 = {{0, 1}, {0, 2}, {1, 0}, {1, 0}};
Cubic cubic2 = {{0, 1}, {0, 2}, {1, 0}, {6, 1}};
double t1Seed = 0.19923954998177532;
double t2Seed = 0.17140596934291233;
double t1Step = 0.00035501449125494022;
double t2Step = 0.00020896171344569892;
Cubic cubic1 = {{0,1}, {3,4}, {1,0}, {3,0}};
Cubic cubic2 = {{0,1}, {0,3}, {1,0}, {4,3}};
double t1Seed = 0.496;
double t2Seed = 0.711;
double t1Step = 0.1;
double t2Step = 0.1;
_Point t1[3], t2[3];
bool toggle = true;
do {

Просмотреть файл

@ -112,7 +112,9 @@ int cubicRootsReal(double A, double B, double C, double D, double s[3]) {
bzero(str, sizeof(str));
sprintf(str, "Solve[%1.19g x^3 + %1.19g x^2 + %1.19g x + %1.19g == 0, x]", A, B, C, D);
#endif
if (approximately_zero(A)) { // we're just a quadratic
if (approximately_zero_when_compared_to(A, B)
&& approximately_zero_when_compared_to(A, C)
&& approximately_zero_when_compared_to(A, D)) { // we're just a quadratic
return quadraticRootsReal(B, C, D, s);
}
if (approximately_zero_when_compared_to(D, A)

Просмотреть файл

@ -32,4 +32,5 @@ void sub_divide(const Cubic& src, double t1, double t2, Cubic& dst);
void xy_at_t(const Cubic& , double t, double& x, double& y);
extern const int precisionUnit;
#endif

Просмотреть файл

@ -12,6 +12,19 @@
#include "SkTypes.h"
// FIXME: move these into SkTypes.h
template <typename T> inline T SkTMax(T a, T b) {
if (a < b)
a = b;
return a;
}
template <typename T> inline T SkTMin(T a, T b) {
if (a > b)
a = b;
return a;
}
extern bool AlmostEqualUlps(float A, float B);
inline bool AlmostEqualUlps(double A, double B) { return AlmostEqualUlps((float) A, (float) B); }
@ -55,8 +68,9 @@ inline bool approximately_zero_inverse(double x) {
return fabs(x) > FLT_EPSILON_INVERSE;
}
// FIXME: if called multiple times with the same denom, we want to pass 1/y instead
inline bool approximately_zero_when_compared_to(double x, double y) {
return fabs(x / y) < FLT_EPSILON;
return x == 0 || fabs(x / y) < FLT_EPSILON;
}
// Use this for comparing Ts in the range of 0 to 1. For general numbers (larger and smaller) use
@ -144,7 +158,6 @@ inline bool approximately_zero_or_more(double x) {
}
inline bool approximately_between(double a, double b, double c) {
SkASSERT(a <= c);
return a <= c ? approximately_negative(a - b) && approximately_negative(b - c)
: approximately_negative(b - a) && approximately_negative(c - b);
}
@ -196,8 +209,17 @@ struct _Point {
// return approximately_equal(a.y, y) && approximately_equal(a.x, x);
// because that will not take the magnitude of the values
bool approximatelyEqual(const _Point& a) const {
#if 0
return AlmostEqualUlps((float) x, (float) a.x)
&& AlmostEqualUlps((float) y, (float) a.y);
#else
double denom = SkTMax(fabs(x), SkTMax(fabs(y), SkTMax(fabs(a.x), fabs(a.y))));
if (denom == 0) {
return true;
}
double inv = 1 / denom;
return approximately_equal(x * inv, a.x * inv) && approximately_equal(y * inv, a.y * inv);
#endif
}
bool approximatelyZero() const {
@ -213,6 +235,11 @@ struct _Point {
return temp.length();
}
double distanceSquared(const _Point& a) const {
_Point temp = *this - a;
return temp.lengthSquared();
}
double dot(const _Point& a) const {
return x * a.x + y * a.y;
}
@ -229,6 +256,7 @@ struct _Point {
typedef _Point _Line[2];
typedef _Point Quadratic[3];
typedef _Point Triangle[3];
typedef _Point Cubic[4];
struct _Rect {
@ -294,17 +322,9 @@ struct QuadraticPair {
_Point pts[5];
};
// FIXME: move these into SkTypes.h
template <typename T> inline T SkTMax(T a, T b) {
if (a < b)
a = b;
return a;
}
// FIXME: move these into SkFloatingPoint.h
#include "SkFloatingPoint.h"
template <typename T> inline T SkTMin(T a, T b) {
if (a > b)
a = b;
return a;
}
#define sk_double_isnan(a) sk_float_isnan(a)
#endif // __DataTypes_h__

Просмотреть файл

@ -58,19 +58,18 @@ static void showPathContour(SkPath::Iter& iter) {
while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
switch (verb) {
case SkPath::kMove_Verb:
SkDebugf("path.moveTo(%1.9g, %1.9g);\n", pts[0].fX, pts[0].fY);
SkDebugf("path.moveTo(%1.9g,%1.9g);\n", pts[0].fX, pts[0].fY);
continue;
case SkPath::kLine_Verb:
SkDebugf("path.lineTo(%1.9g, %1.9g);\n", pts[1].fX, pts[1].fY);
SkDebugf("path.lineTo(%1.9g,%1.9g);\n", pts[1].fX, pts[1].fY);
break;
case SkPath::kQuad_Verb:
SkDebugf("path.quadTo(%1.9g, %1.9g, %1.9g, %1.9g);\n",
SkDebugf("path.quadTo(%1.9g,%1.9g, %1.9g,%1.9g);\n",
pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY);
break;
case SkPath::kCubic_Verb:
SkDebugf("path.cubicTo(%1.9g, %1.9g, %1.9g, %1.9g);\n",
pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY,
pts[3].fX, pts[3].fY);
SkDebugf("path.cubicTo(%1.9g,%1.9g, %1.9g,%1.9g, %1.9g,%1.9g);\n",
pts[1].fX, pts[1].fY, pts[2].fX, pts[2].fY, pts[3].fX, pts[3].fY);
break;
case SkPath::kClose_Verb:
SkDebugf("path.close();\n");

Просмотреть файл

@ -8,15 +8,20 @@
#include "Intersection_Tests.h"
void cubecode_test(int test);
void parseSVG();
#define TEST_QUADS_FIRST 0
void Intersection_Tests() {
int testsRun = 0;
QuadraticIntersection_OneOffTest();
CubicIntersection_IntersectionFinder();
CubicIntersection_OneOffTest();
#if 0
parseSVG();
#endif
SimplifyNew_Test();
QuadraticIntersection_PointFinder();
ShapeOps4x4CubicsThreaded_Test(testsRun);
CubicToQuadratics_Test();
QuadraticIntersection_Test();

Просмотреть файл

@ -27,6 +27,8 @@ void LineIntersection_Test();
void LineParameter_Test();
void LineQuadraticIntersection_Test();
void MiniSimplify_Test();
void QuadraticIntersection_OneOffTest();
void QuadraticIntersection_PointFinder();
void QuadLineIntersectThreaded_Test(int& );
void QuadraticBezierClip_Test();
void QuadraticCoincidence_Test();

Просмотреть файл

@ -22,32 +22,32 @@ void Intersections::addCoincident(double s1, double e1, double s2, double e2) {
if ((s1in | e1in) & (s2in | e2in)) {
double lesser1 = SkTMin(cs1, ce1);
index += cs1 > ce1;
if (s1in < lesser1) {
fCoincidentT[fSwap][index] = s1in;
} else if (e1in < lesser1) {
fCoincidentT[fSwap][index] = e1in;
if (s1 < lesser1) {
fCoincidentT[fSwap][index] = s1;
} else if (e1 < lesser1) {
fCoincidentT[fSwap][index] = e1;
}
index ^= 1;
double greater1 = fCoincidentT[fSwap][index];
if (s1in > greater1) {
fCoincidentT[fSwap][index] = s1in;
} else if (e1in > greater1) {
fCoincidentT[fSwap][index] = e1in;
if (s1 > greater1) {
fCoincidentT[fSwap][index] = s1;
} else if (e1 > greater1) {
fCoincidentT[fSwap][index] = e1;
}
index &= ~1;
double lesser2 = SkTMin(cs2, ce2);
index += cs2 > ce2;
if (s2in < lesser2) {
fCoincidentT[fSwap ^ 1][index] = s2in;
} else if (e2in < lesser2) {
fCoincidentT[fSwap ^ 1][index] = e2in;
if (s2 < lesser2) {
fCoincidentT[fSwap ^ 1][index] = s2;
} else if (e2 < lesser2) {
fCoincidentT[fSwap ^ 1][index] = e2;
}
index ^= 1;
double greater2 = fCoincidentT[fSwap ^ 1][index];
if (s2in > greater2) {
fCoincidentT[fSwap ^ 1][index] = s2in;
} else if (e2in > greater2) {
fCoincidentT[fSwap ^ 1][index] = e2in;
if (s2 > greater2) {
fCoincidentT[fSwap ^ 1][index] = s2;
} else if (e2 > greater2) {
fCoincidentT[fSwap ^ 1][index] = e2;
}
return;
}
@ -59,6 +59,9 @@ void Intersections::addCoincident(double s1, double e1, double s2, double e2) {
fCoincidentT[fSwap][fCoincidentUsed] = e1;
fCoincidentT[fSwap ^ 1][fCoincidentUsed] = e2;
++fCoincidentUsed;
// FIXME: assert that no entries in normal range lie between s and e
remove(s1, e1);
remove(s2, e2);
}
void Intersections::cleanUp() {
@ -72,6 +75,12 @@ void Intersections::cleanUp() {
void Intersections::insert(double one, double two) {
SkASSERT(fUsed <= 1 || fT[0][0] < fT[0][1]);
int index;
for (index = 0; index < fCoincidentUsed; ++index ) {
if (approximately_equal(fCoincidentT[0][index], one)
&& approximately_equal(fCoincidentT[1][index], two)) {
return;
}
}
for (index = 0; index < fUsed; ++index) {
if (approximately_equal(fT[0][index], one)
&& approximately_equal(fT[1][index], two)) {
@ -114,3 +123,25 @@ void Intersections::insertOne(double t, int side) {
fT[side][index] = t;
side ? ++fUsed2 : ++fUsed;
}
void Intersections::remove(double one, double two) {
int index;
for (index = 0; index < fUsed; ++index) {
if (approximately_equal(fT[0][index], one)
&& approximately_equal(fT[1][index], two)) {
goto foundIt;
}
if (fT[0][index] > one) {
return;
}
}
return;
foundIt:
SkASSERT(fUsed > 0);
int remaining = fUsed - index;
if (remaining > 0) {
memmove(&fT[0][index], &fT[0][index - 1], sizeof(fT[0][0]) * remaining);
memmove(&fT[1][index], &fT[1][index - 1], sizeof(fT[1][0]) * remaining);
}
--fUsed;
}

Просмотреть файл

@ -132,6 +132,9 @@ public:
#if SK_DEBUG
int fDepth;
#endif
protected:
// used by addCoincident to remove ordinary intersections in range
void remove(double one, double two);
private:
int fSwap;
};

Просмотреть файл

@ -51,8 +51,9 @@ int intersect(const _Line& a, const _Line& b, double aRange[2], double bRange[2]
|| (numerB < 0 && denom > numerB) || (numerB > 0 && denom < numerB);
numerA /= denom;
numerB /= denom;
if (!approximately_zero(denom) || (!approximately_zero_inverse(numerA) &&
!approximately_zero_inverse(numerB))) {
if ((!approximately_zero(denom) || (!approximately_zero_inverse(numerA)
&& !approximately_zero_inverse(numerB))) && !sk_double_isnan(numerA)
&& !sk_double_isnan(numerB)) {
if (mayNotOverlap) {
return 0;
}

Просмотреть файл

@ -57,12 +57,12 @@ void sub_divide(const _Line& line, double t1, double t2, _Line& dst) {
// =0 for P2 on the line
// <0 for P2 right of the line
// See: the January 2001 Algorithm on Area of Triangles
#if 0
float isLeft( _Point P0, _Point P1, _Point P2 )
{
return (float) ((P1.x - P0.x)*(P2.y - P0.y) - (P2.x - P0.x)*(P1.y - P0.y));
// return (float) ((P1.x - P0.x)*(P2.y - P0.y) - (P2.x - P0.x)*(P1.y - P0.y));
double is_left(const _Line& line, const _Point& pt) {
_Point P0 = line[1] - line[0];
_Point P2 = pt - line[0];
return P0.cross(P2);
}
#endif
double t_at(const _Line& line, const _Point& pt) {
double dx = line[1].x - line[0].x;

Просмотреть файл

@ -8,6 +8,7 @@
bool implicitLine(const _Line& line, double& slope, double& axisIntercept);
int reduceOrder(const _Line& line, _Line& reduced);
double is_left(const _Line& line, const _Point& pt);
void sub_divide(const _Line& src, double t1, double t2, _Line& dst);
double t_at(const _Line&, const _Point& );
void xy_at_t(const _Line& , double t, double& x, double& y);

Просмотреть файл

@ -118,33 +118,6 @@ tryNextHalfPlane:
return false;
}
// http://www.blackpawn.com/texts/pointinpoly/default.html
static bool pointInTriangle(const _Point& pt, const _Line* testLines[]) {
const _Point& A = (*testLines[0])[0];
const _Point& B = (*testLines[1])[0];
const _Point& C = (*testLines[2])[0];
// Compute vectors
_Point v0 = C - A;
_Point v1 = B - A;
_Point v2 = pt - A;
// Compute dot products
double dot00 = v0.dot(v0);
double dot01 = v0.dot(v1);
double dot02 = v0.dot(v2);
double dot11 = v1.dot(v1);
double dot12 = v1.dot(v2);
// Compute barycentric coordinates
double invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
double u = (dot11 * dot02 - dot01 * dot12) * invDenom;
double v = (dot00 * dot12 - dot01 * dot02) * invDenom;
// Check if point is in triangle
return (u >= 0) && (v >= 0) && (u + v < 1);
}
// returns false if there's more than one intercept or the intercept doesn't match the point
// returns true if the intercept was successfully added or if the
// original quads need to be subdivided
@ -221,12 +194,12 @@ static bool isLinearInner(const Quadratic& q1, double t1s, double t1e, const Qua
}
_Point end;
xy_at_t(q2, t2s, end.x, end.y);
bool startInTriangle = pointInTriangle(end, testLines);
bool startInTriangle = point_in_hull(hull, end);
if (startInTriangle) {
tMin = t2s;
}
xy_at_t(q2, t2e, end.x, end.y);
bool endInTriangle = pointInTriangle(end, testLines);
bool endInTriangle = point_in_hull(hull, end);
if (endInTriangle) {
tMax = t2e;
}

Просмотреть файл

@ -8,7 +8,9 @@
#include "CurveUtilities.h"
#include "Intersection_Tests.h"
#include "Intersections.h"
#include "LineIntersection.h"
#include "QuadraticIntersection_TestData.h"
#include "QuadraticUtilities.h"
#include "TestUtilities.h"
const int firstQuadIntersectionTest = 9;
@ -58,6 +60,20 @@ static void standardTestCases() {
}
static const Quadratic testSet[] = {
{{1.7465749139282332,1.9930452039527999}, {1.8320006564080331,1.859481345189089}, {1.8731035127758437,1.6344055934266613}},
{{1.8731035127758437,1.6344055934266613}, {1.89928170345231,1.5006405518943067}, {1.9223833226085514,1.3495796165215643}},
{{1.74657491,1.9930452}, {1.87407679,1.76762853}, {1.92238332,1.34957962}},
{{0.60797907,1.68776977}, {1.0447864,1.50810914}, {1.87464474,1.63655092}},
{{1.87464474,1.63655092}, {2.70450308,1.76499271}, {4,3}},
{{1.2071879545809394,0.82163474041730045}, {1.1534203513372994,0.52790870069930229}, {1.0880000000000001,0.29599999999999982}}, //t=0.63155333662549329,0.80000000000000004
{{0.33333333333333326,0.81481481481481488}, {0.63395173631977997,0.68744136726313931}, {1.205684411948591,0.81344322326274499}},
{{0.33333333333333326,0.81481481481481488}, {0.63396444791444551,0.68743368362444768}, {1.205732763658403,0.81345617746834109}},//t=0.33333333333333331,0.63396444791444551
{{1.205684411948591,0.81344322326274499}, {1.2057085875611198,0.81344969999329253}, {1.205732763658403,0.81345617746834109}},
{{1.20718795,0.82163474}, {1.15342035,0.527908701}, {1.088,0.296}},
{{1.20568441,0.813443223}, {1.20570859,0.8134497}, {1.20573276,0.813456177}},
{{41.5072916,87.1234036}, {28.2747836,80.9545395}, {23.5780771,69.3344126}},
{{72.9633878,95.6593007}, {42.7738746,88.4730382}, {31.1932785,80.2458029}},
@ -133,7 +149,7 @@ static const Quadratic testSet[] = {
const size_t testSetCount = sizeof(testSet) / sizeof(testSet[0]);
#define ONE_OFF_DEBUG 0
#define ONE_OFF_DEBUG 1
static void oneOffTest1(size_t outer, size_t inner) {
const Quadratic& quad1 = testSet[outer];
@ -164,13 +180,19 @@ static void oneOffTest1(size_t outer, size_t inner) {
}
#if ONE_OFF_DEBUG
SkDebugf("%s [%d][%d] t1=%1.9g (%1.9g, %1.9g) t2=%1.9g\n", __FUNCTION__,
outer, inner, tt1, tx1, tx2, tt2);
outer, inner, tt1, tx1, ty1, tt2);
#endif
}
}
static void oneOffTest() {
// oneOffTest1(0, 1);
void QuadraticIntersection_OneOffTest() {
oneOffTest1(0, 3);
oneOffTest1(0, 4);
oneOffTest1(1, 3);
oneOffTest1(1, 4);
}
static void oneOffTests() {
for (size_t outer = 0; outer < testSetCount - 1; ++outer) {
for (size_t inner = outer + 1; inner < testSetCount; ++inner) {
oneOffTest1(outer, inner);
@ -204,7 +226,66 @@ static void coincidentTest() {
}
void QuadraticIntersection_Test() {
oneOffTest();
oneOffTests();
coincidentTest();
standardTestCases();
}
static int floatSign(double x) {
return x < 0 ? -1 : x > 0 ? 1 : 0;
}
static const Quadratic pointFinderTestSet[] = {
//>=0.633974464 0.633974846 <=
{{1.2071879545809394,0.82163474041730045}, {1.1534203513372994,0.52790870069930229}, {1.0880000000000001,0.29599999999999982}}, //t=0.63155333662549329,0.80000000000000004
{{1.2071879545809394,0.82163474041730045}, {1.2065040319428038,0.81766753259119995}, {1.2058123269101506,0.81370135061854221}}, //t=0.63155333662549329,0.6339049773632347
{{1.2058123269101506,0.81370135061854221}, {1.152376363978022,0.5244097415381026}, {1.0880000000000001,0.29599999999999982}}, //t=0.6339049773632347, 0.80000000000000004
//>=0.633974083 0.633975227 <=
{{0.33333333333333326,0.81481481481481488}, {0.63395173631977997,0.68744136726313931}, {1.205684411948591,0.81344322326274499}},//t=0.33333333333333331,0.63395173631977986
{{0.33333333333333326,0.81481481481481488}, {0.63396444791444551,0.68743368362444768}, {1.205732763658403,0.81345617746834109}},//t=0.33333333333333331,0.63396444791444551
{{1.205684411948591,0.81344322326274499}, {1.2057085875611198,0.81344969999329253}, {1.205732763658403,0.81345617746834109}}, //t=0.63395173631977986,0.63396444791444551
{{1.205732763658403,0.81345617746834109}, {1.267928895828891,0.83008534558465619}, {1.3333333333333333,0.85185185185185175}}, //t=0.63396444791444551,0.66666666666666663
};
static void pointFinder(const Quadratic& q1, const Quadratic& q2) {
for (int index = 0; index < 3; ++index) {
double t = nearestT(q1, q2[index]);
_Point onQuad;
xy_at_t(q1, t, onQuad.x, onQuad.y);
SkDebugf("%s t=%1.9g (%1.9g,%1.9g) dist=%1.9g\n", __FUNCTION__, t, onQuad.x, onQuad.y,
onQuad.distance(q2[index]));
double left[3];
left[0] = is_left((const _Line&) q1[0], q2[index]);
left[1] = is_left((const _Line&) q1[1], q2[index]);
_Line diag = {q1[0], q1[2]};
left[2] = is_left(diag, q2[index]);
SkDebugf("%s left=(%d, %d, %d) inHull=%s\n", __FUNCTION__, floatSign(left[0]),
floatSign(left[1]), floatSign(left[2]),
point_in_hull(q1, q2[index]) ? "true" : "false");
}
SkDebugf("\n");
}
static void hullIntersect(const Quadratic& q1, const Quadratic& q2) {
SkDebugf("%s", __FUNCTION__);
double aRange[2], bRange[2];
for (int i1 = 0; i1 < 3; ++i1) {
_Line l1 = {q1[i1], q1[(i1 + 1) % 3]};
for (int i2 = 0; i2 < 3; ++i2) {
_Line l2 = {q2[i2], q2[(i2 + 1) % 3]};
if (intersect(l1, l2, aRange, bRange)) {
SkDebugf(" [%d,%d]", i1, i2);
}
}
}
SkDebugf("\n");
}
void QuadraticIntersection_PointFinder() {
pointFinder(pointFinderTestSet[0], pointFinderTestSet[4]);
pointFinder(pointFinderTestSet[4], pointFinderTestSet[0]);
pointFinder(pointFinderTestSet[0], pointFinderTestSet[6]);
pointFinder(pointFinderTestSet[6], pointFinderTestSet[0]);
hullIntersect(pointFinderTestSet[0], pointFinderTestSet[4]);
hullIntersect(pointFinderTestSet[0], pointFinderTestSet[6]);
}

Просмотреть файл

@ -4,23 +4,54 @@
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "CubicUtilities.h"
#include "QuadraticUtilities.h"
#include <math.h>
#include "TriangleUtilities.h"
// from http://blog.gludion.com/2009/08/distance-to-quadratic-bezier-curve.html
double nearestT(const Quadratic& quad, const _Point& pt) {
_Point pos = quad[0] - pt;
// search points P of bezier curve with PM.(dP / dt) = 0
// a calculus leads to a 3d degree equation :
_Point A = quad[1] - quad[0];
_Point B = quad[2] - quad[1];
B -= A;
double a = B.dot(B);
double b = 3 * A.dot(B);
double c = 2 * A.dot(A) + pos.dot(B);
double d = pos.dot(A);
double ts[3];
int roots = cubicRootsValidT(a, b, c, d, ts);
double d0 = pt.distanceSquared(quad[0]);
double d2 = pt.distanceSquared(quad[2]);
double distMin = SkTMin(d0, d2);
int bestIndex = -1;
for (int index = 0; index < roots; ++index) {
_Point onQuad;
xy_at_t(quad, ts[index], onQuad.x, onQuad.y);
double dist = pt.distanceSquared(onQuad);
if (distMin > dist) {
distMin = dist;
bestIndex = index;
}
}
if (bestIndex >= 0) {
return ts[bestIndex];
}
return d0 < d2 ? 0 : 1;
}
bool point_in_hull(const Quadratic& quad, const _Point& pt) {
return pointInTriangle((const Triangle&) quad, pt);
}
/*
Numeric Solutions (5.6) suggests to solve the quadratic by computing
Q = -1/2(B + sgn(B)Sqrt(B^2 - 4 A C))
and using the roots
t1 = Q / A
t2 = C / Q
*/
int add_valid_ts(double s[], int realRoots, double* t) {
int foundRoots = 0;
for (int index = 0; index < realRoots; ++index) {

Просмотреть файл

@ -15,6 +15,8 @@ void chop_at(const Quadratic& src, QuadraticPair& dst, double t);
double dx_at_t(const Quadratic& , double t);
double dy_at_t(const Quadratic& , double t);
void dxdy_at_t(const Quadratic& , double t, _Point& xy);
double nearestT(const Quadratic& , const _Point& );
bool point_in_hull(const Quadratic& , const _Point& );
/* Parameterization form, given A*t*t + 2*B*t*(1-t) + C*(1-t)*(1-t)
*

Просмотреть файл

@ -41,8 +41,13 @@ int reducedQuarticRoots(const double t4, const double t3, const double t2, const
sprintf(str, "Solve[%1.19g x^4 + %1.19g x^3 + %1.19g x^2 + %1.19g x + %1.19g == 0, x]",
t4, t3, t2, t1, t0);
#endif
if (approximately_zero(t4)) {
if (approximately_zero(t3)) {
if (approximately_zero_when_compared_to(t4, t0) // 0 is one root
&& approximately_zero_when_compared_to(t4, t1)
&& approximately_zero_when_compared_to(t4, t2)
&& approximately_zero_when_compared_to(t4, t3)) {
if (approximately_zero_when_compared_to(t3, t0)
&& approximately_zero_when_compared_to(t3, t1)
&& approximately_zero_when_compared_to(t3, t2)) {
return quadraticRootsReal(t2, t1, t0, roots);
}
return cubicRootsReal(t3, t2, t1, t0, roots);

Просмотреть файл

@ -31,12 +31,13 @@ int gDebugMaxWindValue = SK_MaxS32;
#define APPROXIMATE_CUBICS 1
#define DEBUG_UNUSED 0 // set to expose unused functions
#define FORCE_RELEASE 0 // set force release to 1 for multiple thread -- no debugging
#define FORCE_RELEASE 1 // set force release to 1 for multiple thread -- no debugging
#if FORCE_RELEASE || defined SK_RELEASE
const bool gRunTestsInOneThread = false;
#define DEBUG_ACTIVE_OP 0
#define DEBUG_ACTIVE_SPANS 0
#define DEBUG_ACTIVE_SPANS_SHORT_FORM 0
#define DEBUG_ADD_INTERSECTING_TS 0
@ -59,6 +60,7 @@ const bool gRunTestsInOneThread = false;
const bool gRunTestsInOneThread = true;
#define DEBUG_ACTIVE_OP 1
#define DEBUG_ACTIVE_SPANS 1
#define DEBUG_ACTIVE_SPANS_SHORT_FORM 1
#define DEBUG_ADD_INTERSECTING_TS 1
@ -79,9 +81,11 @@ const bool gRunTestsInOneThread = true;
#endif
#define DEBUG_DUMP (DEBUG_ACTIVE_SPANS | DEBUG_CONCIDENT | DEBUG_SORT | DEBUG_PATH_CONSTRUCTION)
#define DEBUG_DUMP (DEBUG_ACTIVE_OP | DEBUG_ACTIVE_SPANS | DEBUG_CONCIDENT | DEBUG_SORT | \
DEBUG_PATH_CONSTRUCTION)
#if DEBUG_DUMP
static const char* kShapeOpStr[] = {"diff", "sect", "union", "xor"};
static const char* kLVerbStr[] = {"", "line", "quad", "cubic"};
// static const char* kUVerbStr[] = {"", "Line", "Quad", "Cubic"};
static int gContourID;
@ -152,7 +156,7 @@ static int CubicIntersect(const SkPoint a[4], const SkPoint b[4], Intersections&
#else
intersect(aCubic, bCubic, intersections);
#endif
return intersections.fUsed;
return intersections.fUsed ? intersections.fUsed : intersections.fCoincidentUsed;
}
static int HLineIntersect(const SkPoint a[2], SkScalar left, SkScalar right,
@ -800,7 +804,7 @@ public:
fTangent1.quadEndPoints(quad, 0, 1);
#if 1 // FIXME: try enabling this and see if a) it's called and b) does it break anything
if (dx() == 0 && dy() == 0) {
SkDebugf("*** %s quad is line\n", __FUNCTION__);
// SkDebugf("*** %s quad is line\n", __FUNCTION__);
fTangent1.quadEndPoints(quad);
}
#endif
@ -955,8 +959,8 @@ struct Bounds : public SkRect {
bool isEmpty() {
return fLeft > fRight || fTop > fBottom
|| (fLeft == fRight && fTop == fBottom)
|| isnan(fLeft) || isnan(fRight)
|| isnan(fTop) || isnan(fBottom);
|| sk_double_isnan(fLeft) || sk_double_isnan(fRight)
|| sk_double_isnan(fTop) || sk_double_isnan(fBottom);
}
void setCubicBounds(const SkPoint a[4]) {
@ -1316,6 +1320,10 @@ public:
suTo = (oppSumWinding & xorSuMask) != 0;
}
bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo];
#if DEBUG_ACTIVE_OP
SkDebugf("%s op=%s miFrom=%d miTo=%d suFrom=%d suTo=%d result=%d\n", __FUNCTION__,
kShapeOpStr[op], miFrom, miTo, suFrom, suTo, result);
#endif
SkASSERT(result != -1);
return result;
}
@ -4175,8 +4183,8 @@ public:
coincidence.fTs[swap][1] = ts.fT[0][1];
coincidence.fTs[!swap][0] = ts.fT[1][0];
coincidence.fTs[!swap][1] = ts.fT[1][1];
} else if (fSegments[index].verb() == SkPath::kQuad_Verb &&
other->fSegments[otherIndex].verb() == SkPath::kQuad_Verb) {
} else if (fSegments[index].verb() >= SkPath::kQuad_Verb &&
other->fSegments[otherIndex].verb() >= SkPath::kQuad_Verb) {
coincidence.fTs[swap][0] = ts.fCoincidentT[0][0];
coincidence.fTs[swap][1] = ts.fCoincidentT[0][1];
coincidence.fTs[!swap][0] = ts.fCoincidentT[1][0];
@ -5461,8 +5469,8 @@ static bool addIntersectTs(Contour* test, Contour* next) {
wt.addCoincident(wn, ts, swap);
continue;
}
if (wn.segmentType() == Work::kQuad_Segment
&& wt.segmentType() == Work::kQuad_Segment
if (wn.segmentType() >= Work::kQuad_Segment
&& wt.segmentType() >= Work::kQuad_Segment
&& ts.coincidentUsed() == 2) {
wt.addCoincident(wn, ts, swap);
continue;

Просмотреть файл

@ -3564,12 +3564,82 @@ static void cubicOp1d() {
testShapeOp(path, pathB, kDifference_Op);
}
static void (*firstTest)() = testCubic1;
static void cubicOp2d() {
SkPath path, pathB;
path.setFillType(SkPath::kWinding_FillType);
path.moveTo(0,2);
path.cubicTo(0,1, 1,0, 1,0);
path.close();
pathB.setFillType(SkPath::kWinding_FillType);
pathB.moveTo(0,1);
pathB.cubicTo(0,1, 2,0, 1,0);
pathB.close();
testShapeOp(path, pathB, kDifference_Op);
}
static void cubicOp3d() {
SkPath path, pathB;
path.setFillType(SkPath::kWinding_FillType);
path.moveTo(0,1);
path.cubicTo(2,3, 1,0, 1,0);
path.close();
pathB.setFillType(SkPath::kWinding_FillType);
pathB.moveTo(0,1);
pathB.cubicTo(0,1, 1,0, 3,2);
pathB.close();
testShapeOp(path, pathB, kDifference_Op);
}
static void cubicOp5d() {
SkPath path, pathB;
path.setFillType(SkPath::kWinding_FillType);
path.moveTo(0,1);
path.cubicTo(0,2, 1,0, 2,0);
path.close();
pathB.setFillType(SkPath::kWinding_FillType);
pathB.moveTo(0,1);
pathB.cubicTo(0,2, 1,0, 2,0);
pathB.close();
testShapeOp(path, pathB, kDifference_Op);
}
static void cubicOp6d() {
SkPath path, pathB;
path.setFillType(SkPath::kWinding_FillType);
path.moveTo(0,1);
path.cubicTo(0,6, 1,0, 3,0);
path.close();
pathB.setFillType(SkPath::kWinding_FillType);
pathB.moveTo(0,1);
pathB.cubicTo(0,3, 1,0, 6,0);
pathB.close();
testShapeOp(path, pathB, kDifference_Op);
}
static void cubicOp7d() {
SkPath path, pathB;
path.setFillType(SkPath::kWinding_FillType);
path.moveTo(0,1);
path.cubicTo(3,4, 1,0, 3,0);
path.close();
pathB.setFillType(SkPath::kWinding_FillType);
pathB.moveTo(0,1);
pathB.cubicTo(0,3, 1,0, 4,3);
pathB.close();
testShapeOp(path, pathB, kDifference_Op);
}
static void (*firstTest)() = 0;
static struct {
void (*fun)();
const char* str;
} tests[] = {
TEST(cubicOp7d),
TEST(cubicOp6d),
TEST(cubicOp5d),
TEST(cubicOp3d),
TEST(cubicOp2d),
TEST(cubicOp1d),
// TEST(testQuadratic93), // FIXME: gets stuck in a loop because top is unsortable
TEST(testCubic1),

Просмотреть файл

@ -0,0 +1,32 @@
/*
* Copyright 2012 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "TriangleUtilities.h"
// http://www.blackpawn.com/texts/pointinpoly/default.html
bool pointInTriangle(const Triangle& triangle, const _Point& pt) {
// Compute vectors
_Point v0 = triangle[2] - triangle[0];
_Point v1 = triangle[1] - triangle[0];
_Point v2 = pt - triangle[0];
// Compute dot products
double dot00 = v0.dot(v0);
double dot01 = v0.dot(v1);
double dot02 = v0.dot(v2);
double dot11 = v1.dot(v1);
double dot12 = v1.dot(v2);
// Compute barycentric coordinates
double invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
double u = (dot11 * dot02 - dot01 * dot12) * invDenom;
double v = (dot00 * dot12 - dot01 * dot02) * invDenom;
// Check if point is in triangle
return (u >= 0) && (v >= 0) && (u + v < 1);
}

Просмотреть файл

@ -0,0 +1,10 @@
/*
* Copyright 2012 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "DataTypes.h"
bool pointInTriangle(const Triangle& triangle, const _Point& pt);

Просмотреть файл

@ -3339,11 +3339,83 @@ path.addRect(4, 13, 13, 16, SkPath::kCCW_Direction);
pathB.close();
</div>
<div id="cubicOp2d">
path.setFillType(SkPath::kWinding_FillType);
path.moveTo(0,2);
path.cubicTo(0,1, 1,0, 1,0);
path.close();
pathB.setFillType(SkPath::kWinding_FillType);
pathB.moveTo(0,1);
pathB.cubicTo(0,1, 2,0, 1,0);
pathB.close();
</div>
<div id="cubicOp3d">
path.setFillType(SkPath::kWinding_FillType);
path.moveTo(0,1);
path.cubicTo(2,3, 1,0, 1,0);
path.close();
pathB.setFillType(SkPath::kWinding_FillType);
pathB.moveTo(0,1);
pathB.cubicTo(0,1, 1,0, 3,2);
pathB.close();
</div>
<div id="cubicOp4d">
path.setFillType(SkPath::kWinding_FillType);
path.moveTo(0,1);
path.cubicTo(0,2, 1,0, 2,0);
path.close();
pathB.setFillType(SkPath::kWinding_FillType);
pathB.moveTo(0,1);
pathB.cubicTo(0,2, 1,0, 2,0);
pathB.close();
</div>
<div id="cubicOp5d">
path.setFillType(SkPath::kWinding_FillType);
path.moveTo(0,1);
path.cubicTo(0,2, 1,0, 2,0);
path.close();
pathB.setFillType(SkPath::kWinding_FillType);
pathB.moveTo(0,1);
pathB.cubicTo(0,2, 1,0, 2,0);
pathB.close();
</div>
<div id="cubicOp6d">
path.setFillType(SkPath::kWinding_FillType);
path.moveTo(0,1);
path.cubicTo(0,6, 1,0, 3,0);
path.close();
pathB.setFillType(SkPath::kWinding_FillType);
pathB.moveTo(0,1);
pathB.cubicTo(0,3, 1,0, 6,0);
pathB.close();
</div>
<div id="cubicOp7d">
path.setFillType(SkPath::kWinding_FillType);
path.moveTo(0,1);
path.cubicTo(3,4, 1,0, 3,0);
path.close();
pathB.setFillType(SkPath::kWinding_FillType);
pathB.moveTo(0,1);
pathB.cubicTo(0,3, 1,0, 4,3);
pathB.close();
</div>
</div>
<script type="text/javascript">
var testDivs = [
cubicOp7d,
cubicOp6d,
cubicOp5d,
cubicOp4d,
cubicOp3d,
cubicOp2d,
cubicOp1d,
testQuadratic93,
testCubic1,

Просмотреть файл

@ -1795,11 +1795,115 @@ $7 = {{x = 24.006224853920855, y = 72.621119847810419}, {x = 29.758671200376888,
{{x = 0, y = 1}, {x = 0, y = 2}, {x = 1, y = 0}, {x = 6, y = 1}}
</div>
<div id="cubicOp2d">
{{0,2}, {0,1}, {1,0}, {1,0}},
{{0,1}, {0,1}, {2,0}, {1,0}},
{{0,2}, {0.0185185185,1.49074074}, {0.259259259,1.03703704}},
{{0.259259259,1.03703704}, {0.5,0.583333333}, {0.740740741,0.296296296}},
{{0.740740741,0.296296296}, {0.981481481,0.00925925926}, {1,0}},
{{0,1}, {0.01953125,0.9921875}, {0.296875,0.84375}},
{{0.296875,0.84375}, {0.57421875,0.6953125}, {0.875,0.5}},
{{0.875,0.5}, {1.17578125,0.3046875}, {1.265625,0.15625}},
{{1.265625,0.15625}, {1.35546875,0.0078125}, {1,0}},
</div>
<div id="cubicOp2da">
{{0.395593847,0.78966024}, {0.576287939,0.496887363}, {0.740740741,0.296296296}},
{{0.395098308,0.789538003}, {0.634357518,0.657581172}, {0.875,0.5}},
</div>
<div id="cubicOp3d">
{{0,1}, {2,3}, {1,0}, {1,0}},
{{0,1}, {0,1}, {1,0}, {3,2}},
{{0,1}, {0.592,1.584}, {0.872,1.664}},
{{0.872,1.664}, {1.152,1.744}, {1.216,1.512}},
{{1.216,1.512}, {1.28,1.28}, {1.224,0.928}},
{{1.224,0.928}, {1.168,0.576}, {1.088,0.296}},
{{1.088,0.296}, {1.008,0.016}, {1,0}},
{{0,1}, {0,0.962962963}, {0.333333333,0.814814815}},
{{0.333333333,0.814814815}, {0.666666667,0.666666667}, {1.33333333,0.851851852}},
{{1.33333333,0.851851852}, {2,1.03703704}, {3,2}},
</div>
<div id="cubicOp3da">
{{1.224,0.928}, {1.17328164,0.604609714}, {1.09894996,0.336624845}},
{{1.09895195,0.33662897}, {1.22307655,0.2359436}, {1.265625,0.15625}},
</div>
<div id="cubicOp3db">
{{x = 1.2071879545809394, y = 0.82163474041730045}, {x = 1.1534203513372994, y = 0.52790870069930229}, {x = 1.0880000000000001, y = 0.29599999999999982}}
{{x = 1.205732763658403, y = 0.81345617746834109}, {x = 1.267928895828891, y = 0.83008534558465619}, {x = 1.3333333333333333, y = 0.85185185185185175}}
</div>
<div id="cubicOp3dc">
part=(1.20718795,0.82163474 1.17452925,0.632190117 1.1284272,0.444233064 1.088,0.296)
quad=(1.20718795,0.82163474 1.15342035,0.527908701 1.088,0.296)
part=(1.20573276,0.813456177 1.24719685,0.824565605 1.28973037,0.837317532 1.33333333,0.851851852)
quad=(1.20573276,0.813456177 1.2679289,0.830085346 1.33333333,0.851851852)
</div>
<div id="cubicOp3dd">
{{1.20718795,0.82163474 1.17452925,0.632190117 1.1284272,0.444233064 1.088,0.296)
{{1.20718795,0.82163474 1.15342035,0.527908701 1.088,0.296)
{{1.20568441,0.813443223 1.20570053,0.813447541 1.20571665,0.813451859 1.20573276,0.813456177)
{{1.20568441,0.813443223 1.20570859,0.8134497 1.20573276,0.813456177)
{{0.33333333333333326, y = 0.81481481481481488}, {x = 0.63396444791444551, y = 0.68743368362444768}, {x = 1.205732763658403, y = 0.81345617746834109}}
</div>
<div id="cubicOp3de">
{{1.2071879545809394,0.82163474041730045}, {1.2065040319428038,0.81766753259119995}, {1.2058123269101506,0.81370135061854221}},
{{1.205684411948591,0.81344322326274499}, {1.2057085875611198,0.81344969999329253}, {1.205732763658403,0.81345617746834109}},
</div>
<div id="cubicOp7">
{{0,1}, {3,4}, {1,0}, {3,0}},
{{0,1}, {0,3}, {1,0}, {4,3}},
{{0,1}, {0.837764189,1.83435757}, {1.22841861,2.02640973}},
{{1.22841861,2.02640973}, {1.61907304,2.21846188}, {1.74657491,1.9930452}},
{{1.74657491,1.9930452}, {1.87407679,1.76762853}, {1.92238332,1.34957962}},
{{1.92238332,1.34957962}, {1.97220681,0.867804601}, {2.17393047,0.447689071}},
{{2.17393047,0.447689071}, {2.37565413,0.0275735418}, {3,0}},
{{0,1}, {-0.00234073071,1.60655471}, {0.142631845,1.70125304}},
{{0.142631845,1.70125304}, {0.28760442,1.79595137}, {0.60797907,1.68776977}},
{{0.60797907,1.68776977}, {1.0447864,1.50810914}, {1.87464474,1.63655092}},
{{1.87464474,1.63655092}, {2.70450308,1.76499271}, {4,3}},
</div>
<div id="cubicOp7a">
{{x = 1.7465749139282332, y = 1.9930452039527999}, {x = 1.8417960084006277, y = 1.8552583419678612}, {x = 1.8799591210677749, y = 1.6157879692142081}, {x = 1.9223833226085514, y = 1.3495796165215643}}
{{x = 0.6079790696638232, y = 1.6877697663020552}, {x = 0.90321659591661663, y = 1.6123550739533821}, {x = 1.3173732025571312, y = 1.5065640064343382}, {x = 1.8746447406062119, y = 1.636550924974228}}
{{x = 1.7465749139282332, y = 1.9930452039527999}, {x = 1.8740767879671056, y = 1.7676285282679607}, {x = 1.9223833226085514, y = 1.3495796165215643}}
{{x = 0.6079790696638232, y = 1.6877697663020552}, {x = 1.0447863962878021, y = 1.5081091374717195}, {x = 1.8746447406062119, y = 1.636550924974228}}
</div>
<div id="cubicOp7b">
{{x = 1.7465749139282332, y = 1.9930452039527999}, {x = 1.8417960084006277, y = 1.8552583419678612}, {x = 1.8799591210677749, y = 1.6157879692142081}, {x = 1.9223833226085514, y = 1.3495796165215643}}
{{x = 1.8746447406062119, y = 1.636550924974228}, {x = 2.4319162786552919, y = 1.7665378435141166}, {x = 3.1323027481129411, y = 2.1323027481129406}, {x = 4, y = 3}}
{{x = 1.7465749139282332, y = 1.9930452039527999}, {x = 1.8740767879671056, y = 1.7676285282679607}, {x = 1.9223833226085514, y = 1.3495796165215643}}
{{x = 1.8746447406062119, y = 1.636550924974228}, {x = 2.7045030849246219, y = 1.7649927124767357}, {x = 4, y = 3}}
</div>
</div>
<script type="text/javascript">
var testDivs = [
cubicOp7b,
cubicOp7a,
cubicOp7,
cubicOp3de,
cubicOp3dd,
cubicOp3dc,
cubicOp3db,
cubicOp3da,
cubicOp3d,
cubicOp2da,
cubicOp2d,
cubicX,
x1,
x2,
@ -2205,9 +2309,9 @@ function draw(test, title, scale) {
xoffset + curve[6] * unit, yoffset + curve[7] * unit);
break;
}
if (curves == 2) ctx.strokeStyle = curves ? "red" : "blue";
ctx.strokeStyle = drawQuads && drawCubics && curve.length == 6 ? "red" : "black";
ctx.stroke();
if (drawControlLines && curve.length >= 6) {
if (drawControlLines && (curve.length == 6 || curve.length == 8)) {
ctx.strokeStyle = "rgba(0,0,0, 0.3)";
ctx.beginPath();
ctx.moveTo(xoffset + curve[0] * unit, yoffset + curve[1] * unit);
@ -2215,6 +2319,7 @@ function draw(test, title, scale) {
ctx.lineTo(xoffset + curve[4] * unit, yoffset + curve[5] * unit);
if (curve.length == 8)
ctx.lineTo(xoffset + curve[6] * unit, yoffset + curve[7] * unit);
ctx.lineTo(xoffset + curve[0] * unit, yoffset + curve[1] * unit);
ctx.stroke();
}
if (curveT >= 0 && curveT <= 1) {

Просмотреть файл

@ -45,6 +45,7 @@
'../experimental/Intersection/QuarticRoot.cpp',
'../experimental/Intersection/ShapeOps.cpp',
'../experimental/Intersection/Simplify.cpp',
'../experimental/Intersection/TriangleUtilities.cpp',
'../experimental/Intersection/CubicParameterization.cpp',
'../experimental/Intersection/CubicReduceOrder.cpp',
'../experimental/Intersection/CubicSubDivide.cpp',
@ -65,7 +66,8 @@
'../experimental/Intersection/ShapeOps.h',
'../experimental/Intersection/Simplify.h',
'../experimental/Intersection/TSearch.h',
],
'../experimental/Intersection/TriangleUtilities.h',
],
'dependencies': [
'skia_base_libs.gyp:skia_base_libs',
'effects.gyp:effects',

Просмотреть файл

@ -85,6 +85,7 @@
'../experimental/Intersection/SimplifyNew_Test.cpp',
'../experimental/Intersection/SimplifyRect4x4_Test.cpp',
'../experimental/Intersection/TestUtilities.cpp',
'../experimental/Intersection/TriangleUtilities.cpp',
'../experimental/Intersection/CubicIntersection_TestData.h',
'../experimental/Intersection/CubicLineSegments.h',
'../experimental/Intersection/CubicUtilities.h',
@ -108,6 +109,7 @@
'../experimental/Intersection/ShapeOps.h',
'../experimental/Intersection/Simplify.h',
'../experimental/Intersection/TestUtilities.h',
'../experimental/Intersection/TriangleUtilities.h',
'../experimental/Intersection/TSearch.h',
'../experimental/Intersection/thingsToDo.txt',
],