зеркало из https://github.com/mozilla/moz-skia.git
shape ops work in progress
git-svn-id: http://skia.googlecode.com/svn/trunk@7788 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
Родитель
76bf70d38f
Коммит
5e0500fb5f
|
@ -113,10 +113,10 @@ bool convex_x_hull(const Cubic& cubic, char connectTo0[2], char connectTo3[2]) {
|
|||
int lower0Index = 1;
|
||||
int upper0Index = 1;
|
||||
for (index = 2; index < 4; ++index) {
|
||||
if (approximately_greater(projectedY[lower0Index], projectedY[index])) {
|
||||
if (approximately_greater_or_equal(projectedY[lower0Index], projectedY[index])) {
|
||||
lower0Index = index;
|
||||
}
|
||||
if (approximately_lesser(projectedY[upper0Index], projectedY[index])) {
|
||||
if (approximately_lesser_or_equal(projectedY[upper0Index], projectedY[index])) {
|
||||
upper0Index = index;
|
||||
}
|
||||
}
|
||||
|
@ -129,10 +129,10 @@ bool convex_x_hull(const Cubic& cubic, char connectTo0[2], char connectTo3[2]) {
|
|||
int lower3Index = 2;
|
||||
int upper3Index = 2;
|
||||
for (index = 1; index > -1; --index) {
|
||||
if (approximately_greater(projectedY[lower3Index], projectedY[index])) {
|
||||
if (approximately_greater_or_equal(projectedY[lower3Index], projectedY[index])) {
|
||||
lower3Index = index;
|
||||
}
|
||||
if (approximately_lesser(projectedY[upper3Index], projectedY[index])) {
|
||||
if (approximately_lesser_or_equal(projectedY[upper3Index], projectedY[index])) {
|
||||
upper3Index = index;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,17 +54,17 @@ bool bezier_clip(const Cubic& cubic1, const Cubic& cubic2, double& minT, double&
|
|||
endLine.cubicDistanceY(cubic2, distance2y);
|
||||
|
||||
int flags = 0;
|
||||
if (approximately_lesser(distance2y[0].y, top)) {
|
||||
if (approximately_lesser_or_equal(distance2y[0].y, top)) {
|
||||
flags |= kFindTopMin;
|
||||
} else if (approximately_greater(distance2y[0].y, bottom)) {
|
||||
} else if (approximately_greater_or_equal(distance2y[0].y, bottom)) {
|
||||
flags |= kFindBottomMin;
|
||||
} else {
|
||||
minT = 0;
|
||||
}
|
||||
|
||||
if (approximately_lesser(distance2y[3].y, top)) {
|
||||
if (approximately_lesser_or_equal(distance2y[3].y, top)) {
|
||||
flags |= kFindTopMax;
|
||||
} else if (approximately_greater(distance2y[3].y, bottom)) {
|
||||
} else if (approximately_greater_or_equal(distance2y[3].y, bottom)) {
|
||||
flags |= kFindBottomMax;
|
||||
} else {
|
||||
maxT = 1;
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include "QuadraticUtilities.h"
|
||||
|
||||
#if ONE_OFF_DEBUG
|
||||
static const double tLimits[2][2] = {{0.516980827, 0.516981209}, {0.647714088, 0.64771447}};
|
||||
static const double tLimits[2][2] = {{0.599274754, 0.599275135}, {0.599274754, 0.599275135}};
|
||||
#endif
|
||||
|
||||
#define DEBUG_QUAD_PART 0
|
||||
|
@ -358,6 +358,19 @@ static bool intersect3(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 ONE_OFF_DEBUG
|
||||
if (tLimits[0][0] >= t1Start && tLimits[0][1] <= t1
|
||||
&& tLimits[1][0] >= t2Start && tLimits[1][1] <= 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);
|
||||
double coStart[2] = { -1 };
|
||||
|
|
|
@ -134,6 +134,12 @@ static const Cubic testSet[] = {
|
|||
const size_t testSetCount = sizeof(testSet) / sizeof(testSet[0]);
|
||||
|
||||
static const Cubic newTestSet[] = {
|
||||
{{1,2},{5,6},{1,0},{1,0}},
|
||||
{{0,1},{0,1},{2,1},{6,5}},
|
||||
|
||||
{{0,6},{1,2},{1,0},{1,0}},
|
||||
{{0,1},{0,1},{6,0},{2,1}},
|
||||
|
||||
{{0,2},{0,1},{3,0},{1,0}},
|
||||
{{0,3},{0,1},{2,0},{1,0}},
|
||||
};
|
||||
|
@ -544,10 +550,10 @@ void CubicIntersection_IntersectionFinder() {
|
|||
const Cubic& cubic1 = newTestSet[0];
|
||||
const Cubic& cubic2 = newTestSet[1];
|
||||
|
||||
double t1Seed = 0.99;
|
||||
double t2Seed = 0.99;
|
||||
double t1Step = 0.01;
|
||||
double t2Step = 0.01;
|
||||
double t1Seed = 0.599;
|
||||
double t2Seed = 0.599;
|
||||
double t1Step = 0.1;
|
||||
double t2Step = 0.1;
|
||||
_Point t1[3], t2[3];
|
||||
bool toggle = true;
|
||||
do {
|
||||
|
|
|
@ -112,6 +112,10 @@ int cubicRootsReal(double A, double B, double C, double D, double s[3]) {
|
|||
char str[1024];
|
||||
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);
|
||||
mathematica_ize(str, sizeof(str));
|
||||
#if ONE_OFF_DEBUG
|
||||
SkDebugf("%s\n", str);
|
||||
#endif
|
||||
#endif
|
||||
if (approximately_zero(A)
|
||||
&& approximately_zero_when_compared_to(A, B)
|
||||
|
|
|
@ -65,3 +65,22 @@ int UlpsDiff(float A, float B)
|
|||
return abs(uA.i - uB.i);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SK_DEBUG
|
||||
void mathematica_ize(char* str, size_t bufferLen) {
|
||||
size_t len = strlen(str);
|
||||
bool num = false;
|
||||
for (size_t idx = 0; idx < len; ++idx) {
|
||||
if (num && str[idx] == 'e') {
|
||||
if (len + 2 >= bufferLen) {
|
||||
return;
|
||||
}
|
||||
memmove(&str[idx + 2], &str[idx + 1], len - idx);
|
||||
str[idx] = '*';
|
||||
str[idx + 1] = '^';
|
||||
++len;
|
||||
}
|
||||
num = str[idx] >= '0' && str[idx] <= '9';
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -120,11 +120,19 @@ inline bool approximately_equal_squared(double x, double y) {
|
|||
}
|
||||
|
||||
inline bool approximately_greater(double x, double y) {
|
||||
return approximately_equal(x, y) ? false : x > y;
|
||||
return x - FLT_EPSILON >= y;
|
||||
}
|
||||
|
||||
inline bool approximately_greater_or_equal(double x, double y) {
|
||||
return x + FLT_EPSILON > y;
|
||||
}
|
||||
|
||||
inline bool approximately_lesser(double x, double y) {
|
||||
return approximately_equal(x, y) ? false : x < y;
|
||||
return x + FLT_EPSILON <= y;
|
||||
}
|
||||
|
||||
inline bool approximately_lesser_or_equal(double x, double y) {
|
||||
return x - FLT_EPSILON < y;
|
||||
}
|
||||
|
||||
inline double approximately_pin(double x) {
|
||||
|
@ -286,6 +294,9 @@ struct _Point {
|
|||
return x * x + y * y;
|
||||
}
|
||||
|
||||
double roughlyEqual(const _Point& a) const {
|
||||
return roughly_equal(a.y, y) && roughly_equal(a.x, x);
|
||||
}
|
||||
};
|
||||
|
||||
typedef _Point _Line[2];
|
||||
|
@ -361,4 +372,8 @@ struct QuadraticPair {
|
|||
|
||||
#define sk_double_isnan(a) sk_float_isnan(a)
|
||||
|
||||
#if SK_DEBUG
|
||||
void mathematica_ize(char* str, size_t bufferSize);
|
||||
#endif
|
||||
|
||||
#endif // __DataTypes_h__
|
||||
|
|
|
@ -15,15 +15,15 @@ void parseSVG();
|
|||
void Intersection_Tests() {
|
||||
int testsRun = 0;
|
||||
#if 0
|
||||
#endif
|
||||
QuadraticIntersection_IntersectionFinder();
|
||||
QuadraticIntersection_OneOffTest();
|
||||
CubicIntersection_IntersectionFinder();
|
||||
CubicIntersection_NewOneOffTest();
|
||||
#endif
|
||||
SimplifyNew_Test();
|
||||
CubicsToQuadratics_OneOffTest();
|
||||
CubicIntersection_OneOffTest();
|
||||
CubicIntersection_OneOffTests();
|
||||
// CubicIntersection_OneOffTests();
|
||||
#if 0
|
||||
parseSVG();
|
||||
#endif
|
||||
|
|
|
@ -41,17 +41,17 @@ bool bezier_clip(const Quadratic& q1, const Quadratic& q2, double& minT, double&
|
|||
endLine.quadDistanceY(q2, distance2y);
|
||||
|
||||
int flags = 0;
|
||||
if (approximately_lesser(distance2y[0].y, top)) {
|
||||
if (approximately_lesser_or_equal(distance2y[0].y, top)) {
|
||||
flags |= kFindTopMin;
|
||||
} else if (approximately_greater(distance2y[0].y, bottom)) {
|
||||
} else if (approximately_greater_or_equal(distance2y[0].y, bottom)) {
|
||||
flags |= kFindBottomMin;
|
||||
} else {
|
||||
minT = 0;
|
||||
}
|
||||
|
||||
if (approximately_lesser(distance2y[2].y, top)) {
|
||||
if (approximately_lesser_or_equal(distance2y[2].y, top)) {
|
||||
flags |= kFindTopMax;
|
||||
} else if (approximately_greater(distance2y[2].y, bottom)) {
|
||||
} else if (approximately_greater_or_equal(distance2y[2].y, bottom)) {
|
||||
flags |= kFindBottomMax;
|
||||
} else {
|
||||
maxT = 1;
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
*/
|
||||
|
||||
static int findRoots(const QuadImplicitForm& i, const Quadratic& q2, double roots[4],
|
||||
bool oneHint) {
|
||||
bool oneHint, int firstCubicRoot) {
|
||||
double a, b, c;
|
||||
set_abc(&q2[0].x, a, b, c);
|
||||
double d, e, f;
|
||||
|
@ -56,7 +56,7 @@ static int findRoots(const QuadImplicitForm& i, const Quadratic& q2, double root
|
|||
if (rootCount >= 0) {
|
||||
return rootCount;
|
||||
}
|
||||
return quarticRootsReal(t4, t3, t2, t1, t0, roots);
|
||||
return quarticRootsReal(firstCubicRoot, t4, t3, t2, t1, t0, roots);
|
||||
}
|
||||
|
||||
static int addValidRoots(const double roots[4], const int count, double valid[4]) {
|
||||
|
@ -334,6 +334,87 @@ static void unsortableExpanse(const Quadratic& q1, const Quadratic& q2, Intersec
|
|||
}
|
||||
#endif
|
||||
|
||||
// each time through the loop, this computes values it had from the last loop
|
||||
// if i == j == 1, the center values are still good
|
||||
// otherwise, for i != 1 or j != 1, four of the values are still good
|
||||
// and if i == 1 ^ j == 1, an additional value is good
|
||||
static bool binarySearch(const Quadratic& quad1, const Quadratic& quad2, double& t1Seed,
|
||||
double& t2Seed, _Point& pt) {
|
||||
double tStep = ROUGH_EPSILON;
|
||||
_Point t1[3], t2[3];
|
||||
int calcMask = ~0;
|
||||
do {
|
||||
if (calcMask & (1 << 1)) t1[1] = xy_at_t(quad1, t1Seed);
|
||||
if (calcMask & (1 << 4)) t2[1] = xy_at_t(quad2, t2Seed);
|
||||
if (t1[1].approximatelyEqual(t2[1])) {
|
||||
pt = t1[1];
|
||||
#if ONE_OFF_DEBUG
|
||||
SkDebugf("%s t1=%1.9g t2=%1.9g (%1.9g,%1.9g) == (%1.9g,%1.9g)\n", __FUNCTION__,
|
||||
t1Seed, t2Seed, t1[1].x, t1[1].y, t1[2].x, t1[2].y);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
if (calcMask & (1 << 0)) t1[0] = xy_at_t(quad1, t1Seed - tStep);
|
||||
if (calcMask & (1 << 2)) t1[2] = xy_at_t(quad1, t1Seed + tStep);
|
||||
if (calcMask & (1 << 3)) t2[0] = xy_at_t(quad2, t2Seed - tStep);
|
||||
if (calcMask & (1 << 5)) t2[2] = xy_at_t(quad2, t2Seed + tStep);
|
||||
double dist[3][3];
|
||||
// OPTIMIZE: using calcMask value permits skipping some distance calcuations
|
||||
// if prior loop's results are moved to correct slot for reuse
|
||||
dist[1][1] = t1[1].distanceSquared(t2[1]);
|
||||
int best_i = 1, best_j = 1;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
if (i == 1 && j == 1) {
|
||||
continue;
|
||||
}
|
||||
dist[i][j] = t1[i].distanceSquared(t2[j]);
|
||||
if (dist[best_i][best_j] > dist[i][j]) {
|
||||
best_i = i;
|
||||
best_j = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (best_i == 1 && best_j == 1) {
|
||||
tStep /= 2;
|
||||
if (tStep < FLT_EPSILON_HALF) {
|
||||
break;
|
||||
}
|
||||
calcMask = (1 << 0) | (1 << 2) | (1 << 3) | (1 << 5);
|
||||
continue;
|
||||
}
|
||||
if (best_i == 0) {
|
||||
t1Seed -= tStep;
|
||||
t1[2] = t1[1];
|
||||
t1[1] = t1[0];
|
||||
calcMask = 1 << 0;
|
||||
} else if (best_i == 2) {
|
||||
t1Seed += tStep;
|
||||
t1[0] = t1[1];
|
||||
t1[1] = t1[2];
|
||||
calcMask = 1 << 2;
|
||||
} else {
|
||||
calcMask = 0;
|
||||
}
|
||||
if (best_j == 0) {
|
||||
t2Seed -= tStep;
|
||||
t2[2] = t2[1];
|
||||
t2[1] = t2[0];
|
||||
calcMask |= 1 << 3;
|
||||
} else if (best_j == 2) {
|
||||
t2Seed += tStep;
|
||||
t2[0] = t2[1];
|
||||
t2[1] = t2[2];
|
||||
calcMask |= 1 << 5;
|
||||
}
|
||||
} while (true);
|
||||
#if ONE_OFF_DEBUG
|
||||
SkDebugf("%s t1=%1.9g t2=%1.9g (%1.9g,%1.9g) != (%1.9g,%1.9g) %s\n", __FUNCTION__,
|
||||
t1Seed, t2Seed, t1[1].x, t1[1].y, t1[2].x, t1[2].y);
|
||||
#endif
|
||||
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
|
||||
|
||||
|
@ -378,7 +459,7 @@ bool intersect2(const Quadratic& q1, const Quadratic& q2, Intersections& i) {
|
|||
int index;
|
||||
bool useCubic = q1[0] == q2[0] || q1[0] == q2[2] || q1[2] == q2[0];
|
||||
double roots1[4];
|
||||
int rootCount = findRoots(i2, q1, roots1, useCubic);
|
||||
int rootCount = findRoots(i2, q1, roots1, useCubic, 0);
|
||||
// OPTIMIZATION: could short circuit here if all roots are < 0 or > 1
|
||||
double roots1Copy[4];
|
||||
int r1Count = addValidRoots(roots1, rootCount, roots1Copy);
|
||||
|
@ -387,7 +468,7 @@ bool intersect2(const Quadratic& q1, const Quadratic& q2, Intersections& i) {
|
|||
xy_at_t(q1, roots1Copy[index], pts1[index].x, pts1[index].y);
|
||||
}
|
||||
double roots2[4];
|
||||
int rootCount2 = findRoots(i1, q2, roots2, useCubic);
|
||||
int rootCount2 = findRoots(i1, q2, roots2, useCubic, 0);
|
||||
double roots2Copy[4];
|
||||
int r2Count = addValidRoots(roots2, rootCount2, roots2Copy);
|
||||
_Point pts2[4];
|
||||
|
@ -398,6 +479,39 @@ bool intersect2(const Quadratic& q1, const Quadratic& q2, Intersections& i) {
|
|||
if (r1Count == 1) {
|
||||
if (pts1[0].approximatelyEqualHalf(pts2[0])) {
|
||||
i.insert(roots1Copy[0], roots2Copy[0], pts1[0]);
|
||||
} else if (pts1[0].roughlyEqual(pts2[0])) {
|
||||
// experiment: see if a different cubic solution provides the correct quartic answer
|
||||
#if 0
|
||||
for (int cu1 = 0; cu1 < 3; ++cu1) {
|
||||
rootCount = findRoots(i2, q1, roots1, useCubic, cu1);
|
||||
r1Count = addValidRoots(roots1, rootCount, roots1Copy);
|
||||
if (r1Count == 0) {
|
||||
continue;
|
||||
}
|
||||
for (int cu2 = 0; cu2 < 3; ++cu2) {
|
||||
if (cu1 == 0 && cu2 == 0) {
|
||||
continue;
|
||||
}
|
||||
rootCount2 = findRoots(i1, q2, roots2, useCubic, cu2);
|
||||
r2Count = addValidRoots(roots2, rootCount2, roots2Copy);
|
||||
if (r2Count == 0) {
|
||||
continue;
|
||||
}
|
||||
SkASSERT(r1Count == 1 && r2Count == 1);
|
||||
SkDebugf("*** [%d,%d] (%1.9g,%1.9g) %s (%1.9g,%1.9g)\n", cu1, cu2,
|
||||
pts1[0].x, pts1[0].y, pts1[0].approximatelyEqualHalf(pts2[0])
|
||||
? "==" : "!=", pts2[0].x, pts2[0].y);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// experiment: try to find intersection by chasing t
|
||||
rootCount = findRoots(i2, q1, roots1, useCubic, 0);
|
||||
r1Count = addValidRoots(roots1, rootCount, roots1Copy);
|
||||
rootCount2 = findRoots(i1, q2, roots2, useCubic, 0);
|
||||
r2Count = addValidRoots(roots2, rootCount2, roots2Copy);
|
||||
if (binarySearch(q1, q2, roots1Copy[0], roots2Copy[0], pts1[0])) {
|
||||
i.insert(roots1Copy[0], roots2Copy[0], pts1[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return i.intersected();
|
||||
|
|
|
@ -54,6 +54,15 @@ static void standardTestCases() {
|
|||
}
|
||||
|
||||
static const Quadratic testSet[] = {
|
||||
{{2.7279999999999998, 3.024}, {2.5600000000000005, 2.5600000000000005}, {2.1520000000000001, 1.8560000000000001}},
|
||||
{{0.66666666666666652, 1.1481481481481481}, {1.3333333333333326, 1.3333333333333335}, {2.6666666666666665, 2.1851851851851851}},
|
||||
|
||||
{{2.728,3.024}, {2.56,2.56}, {2.152,1.856}},
|
||||
{{0.666666667,1.14814815}, {1.33333333,1.33333333}, {2.66666667,2.18518519}},
|
||||
|
||||
{{0.875,1.5}, {1.03125,1.11022302e-16}, {1,0}},
|
||||
{{0.875,0.859375}, {1.6875,0.73046875}, {2.5,0.625}},
|
||||
|
||||
{{1.64451042,0.0942001592}, {1.53635465,0.00152863961}, {1,0}},
|
||||
{{1.27672209,0.15}, {1.32143477,9.25185854e-17}, {1,0}},
|
||||
|
||||
|
@ -196,6 +205,7 @@ static void oneOffTest1(size_t outer, size_t inner) {
|
|||
|
||||
void QuadraticIntersection_OneOffTest() {
|
||||
oneOffTest1(0, 1);
|
||||
oneOffTest1(2, 3);
|
||||
}
|
||||
|
||||
static void oneOffTests() {
|
||||
|
@ -297,14 +307,14 @@ void QuadraticIntersection_PointFinder() {
|
|||
hullIntersect(pointFinderTestSet[0], pointFinderTestSet[6]);
|
||||
}
|
||||
|
||||
void QuadraticIntersection_IntersectionFinder() {
|
||||
const Quadratic& quad1 = testSet[0];
|
||||
const Quadratic& quad2 = testSet[1];
|
||||
static void intersectionFinder(int test1, int test2) {
|
||||
const Quadratic& quad1 = testSet[test1];
|
||||
const Quadratic& quad2 = testSet[test2];
|
||||
|
||||
double t1Seed = 0.98;
|
||||
double t2Seed = 0.97;
|
||||
double t1Step = 0.05;
|
||||
double t2Step = 0.05;
|
||||
double t1Seed = 0.989;
|
||||
double t2Seed = 0.800;
|
||||
double t1Step = 0.01;
|
||||
double t2Step = 0.01;
|
||||
_Point t1[3], t2[3];
|
||||
bool toggle = true;
|
||||
do {
|
||||
|
@ -388,3 +398,8 @@ void QuadraticIntersection_IntersectionFinder() {
|
|||
SkDebugf("%s p2=(%1.9g,%1.9g)<(%1.9g,%1.9g)<(%1.9g,%1.9g)\n", __FUNCTION__,
|
||||
p20.x, p20.y, p2Seed.x, p2Seed.y, p22.x, p22.y);
|
||||
}
|
||||
|
||||
void QuadraticIntersection_IntersectionFinder() {
|
||||
intersectionFinder(0, 1);
|
||||
intersectionFinder(2, 3);
|
||||
}
|
||||
|
|
|
@ -40,18 +40,23 @@ int reducedQuarticRoots(const double t4, const double t3, const double t2, const
|
|||
bzero(str, sizeof(str));
|
||||
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);
|
||||
mathematica_ize(str, sizeof(str));
|
||||
#if ONE_OFF_DEBUG
|
||||
SkDebugf("%s\n", str);
|
||||
#endif
|
||||
#endif
|
||||
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)) {
|
||||
&& approximately_zero_when_compared_to(t4, t2)) {
|
||||
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);
|
||||
}
|
||||
if (approximately_zero_when_compared_to(t4, t3)) {
|
||||
return cubicRootsReal(t3, t2, t1, t0, roots);
|
||||
}
|
||||
}
|
||||
if (approximately_zero_when_compared_to(t0, t1) // 0 is one root
|
||||
&& approximately_zero_when_compared_to(t0, t2)
|
||||
&& approximately_zero_when_compared_to(t0, t3)
|
||||
|
@ -79,8 +84,8 @@ int reducedQuarticRoots(const double t4, const double t3, const double t2, const
|
|||
return -1;
|
||||
}
|
||||
|
||||
int quarticRootsReal(const double A, const double B, const double C, const double D,
|
||||
const double E, double s[4]) {
|
||||
int quarticRootsReal(int firstCubicRoot, const double A, const double B, const double C,
|
||||
const double D, const double E, double s[4]) {
|
||||
double u, v;
|
||||
/* normal form: x^4 + Ax^3 + Bx^2 + Cx + D = 0 */
|
||||
const double invA = 1 / A;
|
||||
|
@ -149,7 +154,7 @@ int quarticRootsReal(const double A, const double B, const double C, const doubl
|
|||
double z;
|
||||
num = 0;
|
||||
int num2 = 0;
|
||||
for (index = 0; index < roots; ++index) {
|
||||
for (index = firstCubicRoot; index < roots; ++index) {
|
||||
z = cubicRoots[index];
|
||||
/* ... to build two quadric equations */
|
||||
u = z * z - r;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
int reducedQuarticRoots(const double t4, const double t3, const double t2, const double t1,
|
||||
const double t0, const bool oneHint, double s[4]);
|
||||
|
||||
int quarticRootsReal(const double A, const double B, const double C, const double D,
|
||||
const double E, double s[4]);
|
||||
int quarticRootsReal(int firstCubicRoot, const double A, const double B, const double C,
|
||||
const double D, const double E, double s[4]);
|
||||
|
|
|
@ -131,7 +131,7 @@ static void testOneQuartic(size_t aIndex, size_t bIndex, size_t cIndex, size_t d
|
|||
bool oneHint = approximately_zero(A + b + c + d + e);
|
||||
int rootCount = reducedQuarticRoots(A, b, c, d, e, oneHint, roots);
|
||||
if (rootCount < 0) {
|
||||
rootCount = quarticRootsReal(A, b, c, d, e, roots);
|
||||
rootCount = quarticRootsReal(0, A, b, c, d, e, roots);
|
||||
}
|
||||
const int expected = 1 + (B != C) + (B != D && C != D) + (B != E && C != E && D != E);
|
||||
SkASSERT(rootCount == expected);
|
||||
|
|
|
@ -32,7 +32,7 @@ int gDebugMaxWindValue = SK_MaxS32;
|
|||
|
||||
#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
|
||||
|
||||
|
@ -51,8 +51,8 @@ const bool gRunTestsInOneThread = false;
|
|||
#define DEBUG_MARK_DONE 0
|
||||
#define DEBUG_PATH_CONSTRUCTION 0
|
||||
#define DEBUG_SHOW_WINDING 0
|
||||
#define DEBUG_SORT 0
|
||||
#define DEBUG_SWAP_TOP 1
|
||||
#define DEBUG_SORT 1
|
||||
#define DEBUG_SWAP_TOP 0
|
||||
#define DEBUG_UNSORTABLE 0
|
||||
#define DEBUG_WIND_BUMP 0
|
||||
#define DEBUG_WINDING 0
|
||||
|
@ -88,13 +88,16 @@ const bool gRunTestsInOneThread = true;
|
|||
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;
|
||||
static int gSegmentID;
|
||||
#endif
|
||||
|
||||
#if DEBUG_ACTIVE_OP
|
||||
static const char* kShapeOpStr[] = {"diff", "sect", "union", "xor"};
|
||||
#endif
|
||||
|
||||
#ifndef DEBUG_TEST
|
||||
#define DEBUG_TEST 0
|
||||
#endif
|
||||
|
@ -1041,7 +1044,7 @@ static bool useInnerWinding(int outerWinding, int innerWinding) {
|
|||
int absIn = abs(innerWinding);
|
||||
bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn;
|
||||
if (outerWinding * innerWinding < 0) {
|
||||
#if DEBUG_WINDING
|
||||
#if 0 && DEBUG_WINDING
|
||||
SkDebugf("%s outer=%d inner=%d result=%s\n", __FUNCTION__,
|
||||
outerWinding, innerWinding, result ? "true" : "false");
|
||||
#endif
|
||||
|
@ -2822,14 +2825,24 @@ public:
|
|||
endIndex = angle->start();
|
||||
} while (leftSegment->fTs[SkMin32(tIndex, endIndex)].fDone);
|
||||
if (leftSegment->verb() >= SkPath::kQuad_Verb) {
|
||||
bool bumpsUp = leftSegment->bumpsUp(tIndex, endIndex);
|
||||
SkPoint xyE = leftSegment->xyAtT(endIndex);
|
||||
SkPoint xyS = leftSegment->xyAtT(tIndex);
|
||||
SkPoint dxyE = leftSegment->dxdy(endIndex);
|
||||
SkPoint dxyS = leftSegment->dxdy(tIndex);
|
||||
double cross = dxyE.cross(dxyS);
|
||||
bool bumpCheck = bumpsUp && xyE.fY < xyS.fY;
|
||||
#if DEBUG_SWAP_TOP
|
||||
SkDebugf("%s dxyE=(%1.9g,%1.9g) dxyS=(%1.9g,%1.9g) cross=%1.9g\n", __FUNCTION__,
|
||||
dxyE.fX, dxyE.fY, dxyS.fX, dxyS.fY, cross);
|
||||
SkDebugf("%s xyE=(%1.9g,%1.9g) xyS=(%1.9g,%1.9g)\n", __FUNCTION__,
|
||||
xyE.fX, xyE.fY, xyS.fX, xyS.fY);
|
||||
SkDebugf("%s dxyE=(%1.9g,%1.9g) dxyS=(%1.9g,%1.9g) cross=%1.9g bump=%s\n", __FUNCTION__,
|
||||
dxyE.fX, dxyE.fY, dxyS.fX, dxyS.fY, cross, bumpCheck ? "true" : "false");
|
||||
#endif
|
||||
if (cross >= 1) {
|
||||
if ((cross > 0) ^ bumpCheck) {
|
||||
leftSegment->bumpsUp(tIndex, endIndex);
|
||||
SkDebugf("%s cross bump disagree\n", __FUNCTION__);
|
||||
}
|
||||
if (bumpCheck) {
|
||||
#if DEBUG_SWAP_TOP
|
||||
SkDebugf("%s swap\n", __FUNCTION__);
|
||||
#endif
|
||||
|
@ -3298,6 +3311,27 @@ the same winding is shared by both.
|
|||
return &span;
|
||||
}
|
||||
|
||||
bool bumpsUp(int tStart, int tEnd) const {
|
||||
SkPoint edge[4];
|
||||
(*SegmentSubDivide[fVerb])(fPts, fTs[tStart].fT, fTs[tEnd].fT, edge);
|
||||
switch (fVerb) {
|
||||
case SkPath::kLine_Verb:
|
||||
SkASSERT(0); // shouldn't call in for lines
|
||||
return true;
|
||||
case SkPath::kQuad_Verb:
|
||||
return approximately_greater(edge[0].fY, edge[1].fY)
|
||||
&& approximately_lesser(edge[1].fY, edge[2].fY);
|
||||
case SkPath::kCubic_Verb:
|
||||
return (approximately_greater(edge[0].fY, edge[1].fY)
|
||||
&& approximately_lesser(edge[1].fY, edge[3].fY))
|
||||
|| (approximately_greater(edge[0].fY, edge[2].fY)
|
||||
&& approximately_lesser(edge[2].fY, edge[3].fY));
|
||||
default:
|
||||
SkASSERT(0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Span* verifyOneWinding(const char* funName, int tIndex) {
|
||||
Span& span = fTs[tIndex];
|
||||
if (span.fDone) {
|
||||
|
@ -3685,7 +3719,8 @@ the same winding is shared by both.
|
|||
int lesser = SkMin32(index, endIndex);
|
||||
int oppWinding = oppSum(lesser);
|
||||
int oppSpanWinding = oppSign(index, endIndex);
|
||||
if (oppSpanWinding && useInnerWinding(oppWinding - oppSpanWinding, oppWinding)) {
|
||||
if (oppSpanWinding && useInnerWinding(oppWinding - oppSpanWinding, oppWinding)
|
||||
&& oppWinding != SK_MaxS32) {
|
||||
oppWinding -= oppSpanWinding;
|
||||
}
|
||||
return oppWinding;
|
||||
|
@ -3707,7 +3742,7 @@ the same winding is shared by both.
|
|||
int lesser = SkMin32(index, endIndex);
|
||||
int winding = windSum(lesser);
|
||||
int spanWinding = spanSign(index, endIndex);
|
||||
if (winding && useInnerWinding(winding - spanWinding, winding)) {
|
||||
if (winding && useInnerWinding(winding - spanWinding, winding) && winding != SK_MaxS32) {
|
||||
winding -= spanWinding;
|
||||
}
|
||||
return winding;
|
||||
|
@ -4130,6 +4165,8 @@ the same winding is shared by both.
|
|||
start, segment.xAtT(&sSpan), segment.yAtT(&sSpan), end,
|
||||
segment.xAtT(&eSpan), segment.yAtT(&eSpan), angle.sign(),
|
||||
mSpan.fWindValue);
|
||||
start here;
|
||||
// create an inline to replace this conditional
|
||||
if (mSpan.fWindSum == SK_MinS32) {
|
||||
SkDebugf("?");
|
||||
} else {
|
||||
|
|
|
@ -3845,12 +3845,68 @@ static void cubicOp20d() {
|
|||
testShapeOp(path, pathB, kDifference_Op);
|
||||
}
|
||||
|
||||
static void (*firstTest)() = cubicOp20d;
|
||||
static void cubicOp21d() {
|
||||
SkPath path, pathB;
|
||||
path.setFillType(SkPath::kWinding_FillType);
|
||||
path.moveTo(0,1);
|
||||
path.cubicTo(0,1, 2,1, 6,5);
|
||||
path.close();
|
||||
pathB.setFillType(SkPath::kWinding_FillType);
|
||||
pathB.moveTo(1,2);
|
||||
pathB.cubicTo(5,6, 1,0, 1,0);
|
||||
pathB.close();
|
||||
testShapeOp(path, pathB, kDifference_Op);
|
||||
}
|
||||
|
||||
static void cubicOp22d() {
|
||||
SkPath path, pathB;
|
||||
path.setFillType(SkPath::kWinding_FillType);
|
||||
path.moveTo(0,1);
|
||||
path.cubicTo(2,3, 3,0, 2,1);
|
||||
path.close();
|
||||
pathB.setFillType(SkPath::kWinding_FillType);
|
||||
pathB.moveTo(0,3);
|
||||
pathB.cubicTo(1,2, 1,0, 3,2);
|
||||
pathB.close();
|
||||
testShapeOp(path, pathB, kDifference_Op);
|
||||
}
|
||||
|
||||
static void cubicOp23d() {
|
||||
SkPath path, pathB;
|
||||
path.setFillType(SkPath::kWinding_FillType);
|
||||
path.moveTo(0,1);
|
||||
path.cubicTo(1,2, 4,0, 2,1);
|
||||
path.close();
|
||||
pathB.setFillType(SkPath::kWinding_FillType);
|
||||
pathB.moveTo(0,4);
|
||||
pathB.cubicTo(1,2, 1,0, 2,1);
|
||||
pathB.close();
|
||||
testShapeOp(path, pathB, kDifference_Op);
|
||||
}
|
||||
|
||||
static void cubicOp24d() {
|
||||
SkPath path, pathB;
|
||||
path.setFillType(SkPath::kWinding_FillType);
|
||||
path.moveTo(0,1);
|
||||
path.cubicTo(1,2, 2,0, 3,2);
|
||||
path.close();
|
||||
pathB.setFillType(SkPath::kWinding_FillType);
|
||||
pathB.moveTo(0,2);
|
||||
pathB.cubicTo(2,3, 1,0, 2,1);
|
||||
pathB.close();
|
||||
testShapeOp(path, pathB, kDifference_Op);
|
||||
}
|
||||
|
||||
static void (*firstTest)() = 0;
|
||||
|
||||
static struct {
|
||||
void (*fun)();
|
||||
const char* str;
|
||||
} tests[] = {
|
||||
TEST(cubicOp24d),
|
||||
TEST(cubicOp23d),
|
||||
TEST(cubicOp22d),
|
||||
TEST(cubicOp21d),
|
||||
TEST(cubicOp20d),
|
||||
TEST(cubicOp19i),
|
||||
TEST(cubicOp18d),
|
||||
|
|
|
@ -3600,11 +3600,59 @@ path.addRect(4, 13, 13, 16, SkPath::kCCW_Direction);
|
|||
pathB.close();
|
||||
</div>
|
||||
|
||||
<div id="cubicOp21d">
|
||||
path.setFillType(SkPath::kWinding_FillType);
|
||||
path.moveTo(0,1);
|
||||
path.cubicTo(0,1, 2,1, 6,5);
|
||||
path.close();
|
||||
pathB.setFillType(SkPath::kWinding_FillType);
|
||||
pathB.moveTo(1,2);
|
||||
pathB.cubicTo(5,6, 1,0, 1,0);
|
||||
pathB.close();
|
||||
</div>
|
||||
|
||||
<div id="cubicOp22d">
|
||||
path.setFillType(SkPath::kWinding_FillType);
|
||||
path.moveTo(0,1);
|
||||
path.cubicTo(2,3, 3,0, 2,1);
|
||||
path.close();
|
||||
pathB.setFillType(SkPath::kWinding_FillType);
|
||||
pathB.moveTo(0,3);
|
||||
pathB.cubicTo(1,2, 1,0, 3,2);
|
||||
pathB.close();
|
||||
</div>
|
||||
|
||||
<div id="cubicOp23d">
|
||||
path.setFillType(SkPath::kWinding_FillType);
|
||||
path.moveTo(0,1);
|
||||
path.cubicTo(1,2, 4,0, 2,1);
|
||||
path.close();
|
||||
pathB.setFillType(SkPath::kWinding_FillType);
|
||||
pathB.moveTo(0,4);
|
||||
pathB.cubicTo(1,2, 1,0, 2,1);
|
||||
pathB.close();
|
||||
</div>
|
||||
|
||||
<div id="cubicOp24d">
|
||||
path.setFillType(SkPath::kWinding_FillType);
|
||||
path.moveTo(0,1);
|
||||
path.cubicTo(1,2, 2,0, 3,2);
|
||||
path.close();
|
||||
pathB.setFillType(SkPath::kWinding_FillType);
|
||||
pathB.moveTo(0,2);
|
||||
pathB.cubicTo(2,3, 1,0, 2,1);
|
||||
pathB.close();
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var testDivs = [
|
||||
cubicOp24d,
|
||||
cubicOp23d,
|
||||
cubicOp22d,
|
||||
cubicOp21d,
|
||||
cubicOp20d,
|
||||
cubicOp19i,
|
||||
cubicOp18d,
|
||||
|
|
|
@ -1998,11 +1998,47 @@ quad=(1.20573276,0.813456177 1.2679289,0.830085346 1.33333333,0.851851852)
|
|||
{{1.27672209,0.15}, {1.32143477,9.25185854e-17}, {1,0}},
|
||||
</div>
|
||||
|
||||
<div id="cubicOp20d">
|
||||
{{0,6},{1,2},{1,0},{1,0}},
|
||||
{{0,1},{0,1},{6,0},{2,1}},
|
||||
|
||||
{{0,6}, {0.71875,3}, {0.875,1.5}},
|
||||
{{0.875,1.5}, {1.03125,1.11022302e-16}, {1,0}},
|
||||
|
||||
{{0,1}, {0.0625,0.98828125}, {0.875,0.859375}},
|
||||
{{0.875,0.859375}, {1.6875,0.73046875}, {2.5,0.625}},
|
||||
{{2.5,0.625}, {3.3125,0.51953125}, {3.375,0.578125}},
|
||||
{{3.375,0.578125}, {3.4375,0.63671875}, {2,1}},
|
||||
</div>
|
||||
|
||||
<div id="cubicOp21d">
|
||||
{{1,2},{5,6},{1,0},{1,0}},
|
||||
{{0,1},{0,1},{2,1},{6,5}},
|
||||
|
||||
{{1,2}, {2.176,3.168}, {2.536,3.328}},
|
||||
{{2.536,3.328}, {2.896,3.488}, {2.728,3.024}},
|
||||
{{2.728,3.024}, {2.56,2.56}, {2.152,1.856}},
|
||||
{{2.152,1.856}, {1.744,1.152}, {1.384,0.592}},
|
||||
{{1.384,0.592}, {1.024,0.032}, {1,0}},
|
||||
|
||||
{{0,1}, {7.40148683e-17,0.962962963}, {0.666666667,1.14814815}},
|
||||
{{0.666666667,1.14814815}, {1.33333333,1.33333333}, {2.66666667,2.18518519}},
|
||||
{{2.66666667,2.18518519}, {4,3.03703704}, {6,5}},
|
||||
</div>
|
||||
|
||||
<div id="quadOp21d">
|
||||
{{2.728,3.024}, {2.56,2.56}, {2.152,1.856}},
|
||||
{{0.666666667,1.14814815}, {1.33333333,1.33333333}, {2.66666667,2.18518519}},
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var testDivs = [
|
||||
quadOp21d,
|
||||
cubicOp21d,
|
||||
cubicOp20d,
|
||||
quadOp16d,
|
||||
cubicOp16d,
|
||||
cubicTest7,
|
||||
|
|
Загрузка…
Ссылка в новой задаче