git-svn-id: http://skia.googlecode.com/svn/trunk@7788 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
caryclark@google.com 2013-02-20 12:51:37 +00:00
Родитель 76bf70d38f
Коммит 5e0500fb5f
18 изменённых файлов: 421 добавлений и 53 удалений

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

@ -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) {
@ -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__

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

@ -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,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;

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

@ -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,