aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/pathops/SkDQuadIntersection.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/pathops/SkDQuadIntersection.cpp')
-rw-r--r--src/pathops/SkDQuadIntersection.cpp70
1 files changed, 66 insertions, 4 deletions
diff --git a/src/pathops/SkDQuadIntersection.cpp b/src/pathops/SkDQuadIntersection.cpp
index 239711c321..fcb9171f32 100644
--- a/src/pathops/SkDQuadIntersection.cpp
+++ b/src/pathops/SkDQuadIntersection.cpp
@@ -73,6 +73,7 @@ static int addValidRoots(const double roots[4], const int count, double valid[4]
} else if (approximately_greater_than_one(t)) {
t = 1;
}
+ SkASSERT(t >= 0 && t <= 1);
valid[result++] = t;
}
return result;
@@ -242,10 +243,18 @@ static double flat_measure(const SkDQuad& q) {
// FIXME ? should this measure both and then use the quad that is the flattest as the line?
static bool is_linear(const SkDQuad& q1, const SkDQuad& q2, SkIntersections* i) {
- double measure = flat_measure(q1);
- // OPTIMIZE: (get rid of sqrt) use approximately_zero
- if (!approximately_zero_sqrt(measure)) {
- return false;
+ if (i->flatMeasure()) {
+ // for backward compatibility, use the old method when called from cubics
+ // FIXME: figure out how to fix cubics when it calls the new path
+ double measure = flat_measure(q1);
+ // OPTIMIZE: (get rid of sqrt) use approximately_zero
+ if (!approximately_zero_sqrt(measure)) { // approximately_zero_sqrt
+ return false;
+ }
+ } else {
+ if (!q1.isLinear(0, 2)) {
+ return false;
+ }
}
return is_linear_inner(q1, 0, 1, q2, 0, 1, i, NULL);
}
@@ -305,6 +314,16 @@ static bool binary_search(const SkDQuad& quad1, const SkDQuad& quad2, double* t1
SkDebugf("%s t1=%1.9g t2=%1.9g (%1.9g,%1.9g) == (%1.9g,%1.9g)\n", __FUNCTION__,
t1Seed, t2Seed, t1[1].fX, t1[1].fY, t2[1].fX, t2[1].fY);
#endif
+ if (*t1Seed < 0) {
+ *t1Seed = 0;
+ } else if (*t1Seed > 1) {
+ *t1Seed = 1;
+ }
+ if (*t2Seed < 0) {
+ *t2Seed = 0;
+ } else if (*t2Seed > 1) {
+ *t2Seed = 1;
+ }
return true;
}
if (calcMask & (1 << 0)) t1[0] = quad1.ptAtT(SkTMax(0., *t1Seed - tStep));
@@ -398,11 +417,13 @@ static void lookNearEnd(const SkDQuad& q1, const SkDQuad& q2, int testT,
int SkIntersections::intersect(const SkDQuad& q1, const SkDQuad& q2) {
fMax = 4;
+ bool exactMatch = false;
// if the quads share an end point, check to see if they overlap
for (int i1 = 0; i1 < 3; i1 += 2) {
for (int i2 = 0; i2 < 3; i2 += 2) {
if (q1[i1].asSkPoint() == q2[i2].asSkPoint()) {
insert(i1 >> 1, i2 >> 1, q1[i1]);
+ exactMatch = true;
}
}
}
@@ -469,6 +490,7 @@ int SkIntersections::intersect(const SkDQuad& q1, const SkDQuad& q2) {
int rootCount = findRoots(i2, q1, roots1, useCubic, flip1, 0);
// OPTIMIZATION: could short circuit here if all roots are < 0 or > 1
double roots1Copy[4];
+ SkDEBUGCODE(sk_bzero(roots1Copy, sizeof(roots1Copy)));
int r1Count = addValidRoots(roots1, rootCount, roots1Copy);
SkDPoint pts1[4];
for (index = 0; index < r1Count; ++index) {
@@ -482,12 +504,14 @@ int SkIntersections::intersect(const SkDQuad& q1, const SkDQuad& q2) {
for (index = 0; index < r2Count; ++index) {
pts2[index] = q2.ptAtT(roots2Copy[index]);
}
+ bool triedBinary = false;
if (r1Count == r2Count && r1Count <= 1) {
if (r1Count == 1 && used() == 0) {
if (pts1[0].approximatelyEqual(pts2[0])) {
insert(roots1Copy[0], roots2Copy[0], pts1[0]);
} else {
// find intersection by chasing t
+ triedBinary = true;
if (binary_search(q1, q2, roots1Copy, roots2Copy, pts1)) {
insert(roots1Copy[0], roots2Copy[0], pts1[0]);
}
@@ -528,7 +552,18 @@ int SkIntersections::intersect(const SkDQuad& q1, const SkDQuad& q2) {
}
}
if (r1Count && r2Count && !foundSomething) {
+ if (exactMatch) {
+ SkASSERT(fUsed > 0);
+ return fUsed;
+ }
relaxed_is_linear(&q1, 0, 1, &q2, 0, 1, this);
+ if (fUsed) {
+ return fUsed;
+ }
+ // maybe the curves are nearly coincident
+ if (!triedBinary && binary_search(q1, q2, roots1Copy, roots2Copy, pts1)) {
+ insert(roots1Copy[0], roots2Copy[0], pts1[0]);
+ }
return fUsed;
}
int used = 0;
@@ -553,3 +588,30 @@ int SkIntersections::intersect(const SkDQuad& q1, const SkDQuad& q2) {
} while (++used < r1Count);
return fUsed;
}
+
+void SkIntersections::alignQuadPts(const SkPoint q1[3], const SkPoint q2[3]) {
+ for (int index = 0; index < used(); ++index) {
+ const SkPoint result = pt(index).asSkPoint();
+ if (q1[0] == result || q1[2] == result || q2[0] == result || q2[2] == result) {
+ continue;
+ }
+ if (SkDPoint::ApproximatelyEqual(q1[0], result)) {
+ fPt[index].set(q1[0]);
+// SkASSERT(way_roughly_zero(fT[0][index])); // this value can be bigger than way rough
+ fT[0][index] = 0;
+ } else if (SkDPoint::ApproximatelyEqual(q1[2], result)) {
+ fPt[index].set(q1[2]);
+// SkASSERT(way_roughly_equal(fT[0][index], 1));
+ fT[0][index] = 1;
+ }
+ if (SkDPoint::ApproximatelyEqual(q2[0], result)) {
+ fPt[index].set(q2[0]);
+// SkASSERT(way_roughly_zero(fT[1][index]));
+ fT[1][index] = 0;
+ } else if (SkDPoint::ApproximatelyEqual(q2[2], result)) {
+ fPt[index].set(q2[2]);
+// SkASSERT(way_roughly_equal(fT[1][index], 1));
+ fT[1][index] = 1;
+ }
+ }
+}