aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar caryclark@google.com <caryclark@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-02-20 12:51:37 +0000
committerGravatar caryclark@google.com <caryclark@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-02-20 12:51:37 +0000
commit5e0500fb5f17fe14db42fc3e0aad08e6b41ccc5f (patch)
tree44dc49df87ca6ee505c59bdb24ee5d43a02481dd
parent76bf70d38fd109a09ee44d074cfd392e1884afff (diff)
shape ops work in progress
git-svn-id: http://skia.googlecode.com/svn/trunk@7788 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r--experimental/Intersection/ConvexHull.cpp8
-rw-r--r--experimental/Intersection/CubicBezierClip.cpp8
-rw-r--r--experimental/Intersection/CubicIntersection.cpp15
-rw-r--r--experimental/Intersection/CubicIntersection_Test.cpp14
-rw-r--r--experimental/Intersection/CubicUtilities.cpp4
-rw-r--r--experimental/Intersection/DataTypes.cpp19
-rw-r--r--experimental/Intersection/DataTypes.h21
-rw-r--r--experimental/Intersection/Intersection_Tests.cpp4
-rw-r--r--experimental/Intersection/QuadraticBezierClip.cpp8
-rw-r--r--experimental/Intersection/QuadraticImplicit.cpp122
-rw-r--r--experimental/Intersection/QuadraticIntersection_Test.cpp29
-rw-r--r--experimental/Intersection/QuarticRoot.cpp17
-rw-r--r--experimental/Intersection/QuarticRoot.h4
-rw-r--r--experimental/Intersection/QuarticRoot_Test.cpp2
-rw-r--r--experimental/Intersection/Simplify.cpp57
-rw-r--r--experimental/Intersection/SimplifyNew_Test.cpp58
-rw-r--r--experimental/Intersection/op.htm48
-rw-r--r--experimental/Intersection/qc.htm36
18 files changed, 421 insertions, 53 deletions
diff --git a/experimental/Intersection/ConvexHull.cpp b/experimental/Intersection/ConvexHull.cpp
index e9a08c299a..86cb2dc6f5 100644
--- a/experimental/Intersection/ConvexHull.cpp
+++ b/experimental/Intersection/ConvexHull.cpp
@@ -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;
}
}
diff --git a/experimental/Intersection/CubicBezierClip.cpp b/experimental/Intersection/CubicBezierClip.cpp
index 378e45f227..d4c50fb41c 100644
--- a/experimental/Intersection/CubicBezierClip.cpp
+++ b/experimental/Intersection/CubicBezierClip.cpp
@@ -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;
diff --git a/experimental/Intersection/CubicIntersection.cpp b/experimental/Intersection/CubicIntersection.cpp
index f4a7ef7859..fe146714a9 100644
--- a/experimental/Intersection/CubicIntersection.cpp
+++ b/experimental/Intersection/CubicIntersection.cpp
@@ -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 };
diff --git a/experimental/Intersection/CubicIntersection_Test.cpp b/experimental/Intersection/CubicIntersection_Test.cpp
index 9dea332441..08bffd61bf 100644
--- a/experimental/Intersection/CubicIntersection_Test.cpp
+++ b/experimental/Intersection/CubicIntersection_Test.cpp
@@ -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 {
diff --git a/experimental/Intersection/CubicUtilities.cpp b/experimental/Intersection/CubicUtilities.cpp
index 1c9b9e486c..11d4e6cdb3 100644
--- a/experimental/Intersection/CubicUtilities.cpp
+++ b/experimental/Intersection/CubicUtilities.cpp
@@ -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)
diff --git a/experimental/Intersection/DataTypes.cpp b/experimental/Intersection/DataTypes.cpp
index dc4fea1b82..698f497434 100644
--- a/experimental/Intersection/DataTypes.cpp
+++ b/experimental/Intersection/DataTypes.cpp
@@ -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
diff --git a/experimental/Intersection/DataTypes.h b/experimental/Intersection/DataTypes.h
index ed3ec218f6..ae8d44d6ed 100644
--- a/experimental/Intersection/DataTypes.h
+++ b/experimental/Intersection/DataTypes.h
@@ -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) {
@@ -285,7 +293,10 @@ struct _Point {
double lengthSquared() const {
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__
diff --git a/experimental/Intersection/Intersection_Tests.cpp b/experimental/Intersection/Intersection_Tests.cpp
index f55bab7764..2db5d316fb 100644
--- a/experimental/Intersection/Intersection_Tests.cpp
+++ b/experimental/Intersection/Intersection_Tests.cpp
@@ -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
diff --git a/experimental/Intersection/QuadraticBezierClip.cpp b/experimental/Intersection/QuadraticBezierClip.cpp
index 0e948a0934..5b15fe51c6 100644
--- a/experimental/Intersection/QuadraticBezierClip.cpp
+++ b/experimental/Intersection/QuadraticBezierClip.cpp
@@ -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;
diff --git a/experimental/Intersection/QuadraticImplicit.cpp b/experimental/Intersection/QuadraticImplicit.cpp
index 937bb6ad98..2aed06f8fe 100644
--- a/experimental/Intersection/QuadraticImplicit.cpp
+++ b/experimental/Intersection/QuadraticImplicit.cpp
@@ -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();
diff --git a/experimental/Intersection/QuadraticIntersection_Test.cpp b/experimental/Intersection/QuadraticIntersection_Test.cpp
index a9d5060349..d2be492742 100644
--- a/experimental/Intersection/QuadraticIntersection_Test.cpp
+++ b/experimental/Intersection/QuadraticIntersection_Test.cpp
@@ -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);
+}
diff --git a/experimental/Intersection/QuarticRoot.cpp b/experimental/Intersection/QuarticRoot.cpp
index 50f85b59e9..ea786e4407 100644
--- a/experimental/Intersection/QuarticRoot.cpp
+++ b/experimental/Intersection/QuarticRoot.cpp
@@ -40,17 +40,22 @@ 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);
}
- return cubicRootsReal(t3, 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)
@@ -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;
diff --git a/experimental/Intersection/QuarticRoot.h b/experimental/Intersection/QuarticRoot.h
index 3692caa1b6..3089d59c88 100644
--- a/experimental/Intersection/QuarticRoot.h
+++ b/experimental/Intersection/QuarticRoot.h
@@ -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]);
diff --git a/experimental/Intersection/QuarticRoot_Test.cpp b/experimental/Intersection/QuarticRoot_Test.cpp
index 18a3a8d5ab..48431c8f0a 100644
--- a/experimental/Intersection/QuarticRoot_Test.cpp
+++ b/experimental/Intersection/QuarticRoot_Test.cpp
@@ -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);
diff --git a/experimental/Intersection/Simplify.cpp b/experimental/Intersection/Simplify.cpp
index 2c7103950f..70038e640e 100644
--- a/experimental/Intersection/Simplify.cpp
+++ b/experimental/Intersection/Simplify.cpp
@@ -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 {
diff --git a/experimental/Intersection/SimplifyNew_Test.cpp b/experimental/Intersection/SimplifyNew_Test.cpp
index 78b815ac89..39cf5a8dac 100644
--- a/experimental/Intersection/SimplifyNew_Test.cpp
+++ b/experimental/Intersection/SimplifyNew_Test.cpp
@@ -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),
diff --git a/experimental/Intersection/op.htm b/experimental/Intersection/op.htm
index 9c2ce8e472..21c315de67 100644
--- a/experimental/Intersection/op.htm
+++ b/experimental/Intersection/op.htm
@@ -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,
diff --git a/experimental/Intersection/qc.htm b/experimental/Intersection/qc.htm
index f22921a7da..0264b3ddb6 100644
--- a/experimental/Intersection/qc.htm
+++ b/experimental/Intersection/qc.htm
@@ -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,