Index: src/pathops/SkDQuadLineIntersection.cpp |
diff --git a/src/pathops/SkDQuadLineIntersection.cpp b/src/pathops/SkDQuadLineIntersection.cpp |
index 98e38621e07944afb71bedc31fdc8c4abd84574a..9df2dc248ab01e37b123f7b9da2dd4d408d89b12 100644 |
--- a/src/pathops/SkDQuadLineIntersection.cpp |
+++ b/src/pathops/SkDQuadLineIntersection.cpp |
@@ -92,7 +92,12 @@ public: |
LineQuadraticIntersections(const SkDQuad& q, const SkDLine& l, SkIntersections* i) |
: quad(q) |
, line(l) |
- , intersections(i) { |
+ , intersections(i) |
+ , fAllowNear(true) { |
+ } |
+ |
+ void allowNear(bool allow) { |
+ fAllowNear = allow; |
} |
int intersectRay(double roots[2]) { |
@@ -126,7 +131,7 @@ public: |
} |
int intersect() { |
- addEndPoints(); |
+ addExactEndPoints(); |
double rootVals[2]; |
int roots = intersectRay(rootVals); |
for (int index = 0; index < roots; ++index) { |
@@ -137,6 +142,9 @@ public: |
intersections->insert(quadT, lineT, pt); |
} |
} |
+ if (fAllowNear) { |
+ addNearEndPoints(); |
+ } |
return intersections->used(); |
} |
@@ -151,7 +159,7 @@ public: |
} |
int horizontalIntersect(double axisIntercept, double left, double right, bool flipped) { |
- addHorizontalEndPoints(left, right, axisIntercept); |
+ addExactHorizontalEndPoints(left, right, axisIntercept); |
double rootVals[2]; |
int roots = horizontalIntersect(axisIntercept, rootVals); |
for (int index = 0; index < roots; ++index) { |
@@ -162,6 +170,9 @@ public: |
intersections->insert(quadT, lineT, pt); |
} |
} |
+ if (fAllowNear) { |
+ addNearHorizontalEndPoints(left, right, axisIntercept); |
+ } |
if (flipped) { |
intersections->flip(); |
} |
@@ -179,7 +190,7 @@ public: |
} |
int verticalIntersect(double axisIntercept, double top, double bottom, bool flipped) { |
- addVerticalEndPoints(top, bottom, axisIntercept); |
+ addExactVerticalEndPoints(top, bottom, axisIntercept); |
double rootVals[2]; |
int roots = verticalIntersect(axisIntercept, rootVals); |
for (int index = 0; index < roots; ++index) { |
@@ -190,6 +201,9 @@ public: |
intersections->insert(quadT, lineT, pt); |
} |
} |
+ if (fAllowNear) { |
+ addNearVerticalEndPoints(top, bottom, axisIntercept); |
+ } |
if (flipped) { |
intersections->flip(); |
} |
@@ -198,73 +212,88 @@ public: |
protected: |
// add endpoints first to get zero and one t values exactly |
- void addEndPoints() { |
+ void addExactEndPoints() { |
for (int qIndex = 0; qIndex < 3; qIndex += 2) { |
- bool foundEnd = false; |
- for (int lIndex = 0; lIndex < 2; lIndex++) { |
- if (quad[qIndex] == line[lIndex]) { |
- intersections->insert(qIndex >> 1, lIndex, line[lIndex]); |
- foundEnd = true; |
- } |
- } |
- if (foundEnd) { |
+ double lineT = line.exactPoint(quad[qIndex]); |
+ if (lineT < 0) { |
continue; |
} |
- // See if the quad end touches the line. |
- double dist = line.isLeft(quad[qIndex]); // this distance isn't cartesian |
- SkDVector lineLen = line[1] - line[0]; // the x/y magnitudes of the line |
- // compute the ULPS of the larger of the x/y deltas |
- double larger = SkTMax(SkTAbs(lineLen.fX), SkTAbs(lineLen.fY)); |
- if (!RoughlyEqualUlps(larger, larger + dist)) { // is the dist within ULPS tolerance? |
+ double quadT = (double) (qIndex >> 1); |
+ intersections->insert(quadT, lineT, quad[qIndex]); |
+ } |
+ } |
+ |
+ void addNearEndPoints() { |
+ for (int qIndex = 0; qIndex < 3; qIndex += 2) { |
+ double quadT = (double) (qIndex >> 1); |
+ if (intersections->hasT(quadT)) { |
continue; |
} |
- double lineT = findLineT(qIndex >> 1); |
- if (!between(0, lineT, 1)) { |
+ double lineT = line.nearPoint(quad[qIndex]); |
+ if (lineT < 0) { |
continue; |
} |
- SkDPoint linePt = line.xyAtT(lineT); |
- if (linePt.approximatelyEqual(quad[qIndex])) { |
- intersections->insert(qIndex >> 1, lineT, quad[qIndex]); |
+ intersections->insert(quadT, lineT, quad[qIndex]); |
+ } |
+ // FIXME: see if line end is nearly on quad |
+ } |
+ |
+ void addExactHorizontalEndPoints(double left, double right, double y) { |
+ for (int qIndex = 0; qIndex < 3; qIndex += 2) { |
+ double lineT = SkDLine::ExactPointH(quad[qIndex], left, right, y); |
+ if (lineT < 0) { |
+ continue; |
} |
+ double quadT = (double) (qIndex >> 1); |
+ intersections->insert(quadT, lineT, quad[qIndex]); |
} |
} |
- void addHorizontalEndPoints(double left, double right, double y) { |
+ void addNearHorizontalEndPoints(double left, double right, double y) { |
for (int qIndex = 0; qIndex < 3; qIndex += 2) { |
- if (!AlmostEqualUlps(quad[qIndex].fY, y)) { |
+ double quadT = (double) (qIndex >> 1); |
+ if (intersections->hasT(quadT)) { |
continue; |
} |
- double x = quad[qIndex].fX; |
- if (between(left, x, right)) { |
- double t = (x - left) / (right - left); |
- intersections->insert(qIndex >> 1, t, quad[qIndex]); |
+ double lineT = SkDLine::NearPointH(quad[qIndex], left, right, y); |
+ if (lineT < 0) { |
+ continue; |
} |
+ intersections->insert(quadT, lineT, quad[qIndex]); |
} |
+ // FIXME: see if line end is nearly on quad |
} |
- void addVerticalEndPoints(double top, double bottom, double x) { |
+ void addExactVerticalEndPoints(double top, double bottom, double x) { |
for (int qIndex = 0; qIndex < 3; qIndex += 2) { |
- if (!AlmostEqualUlps(quad[qIndex].fX, x)) { |
+ double lineT = SkDLine::ExactPointV(quad[qIndex], top, bottom, x); |
+ if (lineT < 0) { |
continue; |
} |
- double y = quad[qIndex].fY; |
- if (between(top, y, bottom)) { |
- double t = (y - top) / (bottom - top); |
- intersections->insert(qIndex >> 1, t, quad[qIndex]); |
+ double quadT = (double) (qIndex >> 1); |
+ intersections->insert(quadT, lineT, quad[qIndex]); |
+ } |
+ } |
+ |
+ void addNearVerticalEndPoints(double top, double bottom, double x) { |
+ for (int qIndex = 0; qIndex < 3; qIndex += 2) { |
+ double quadT = (double) (qIndex >> 1); |
+ if (intersections->hasT(quadT)) { |
+ continue; |
+ } |
+ double lineT = SkDLine::NearPointV(quad[qIndex], top, bottom, x); |
+ if (lineT < 0) { |
+ continue; |
} |
+ intersections->insert(quadT, lineT, quad[qIndex]); |
} |
+ // FIXME: see if line end is nearly on quad |
} |
double findLineT(double t) { |
SkDPoint xy = quad.xyAtT(t); |
double dx = line[1].fX - line[0].fX; |
double dy = line[1].fY - line[0].fY; |
-#if 0 |
- if (fabs(dx) > fabs(dy)) { |
- return (xy.fX - line[0].fX) / dx; |
- } |
- return (xy.fY - line[0].fY) / dy; |
-#else |
double dxT = (xy.fX - line[0].fX) / dx; |
double dyT = (xy.fY - line[0].fY) / dy; |
if (!between(FLT_EPSILON, dxT, 1 - FLT_EPSILON) && between(0, dyT, 1)) { |
@@ -274,7 +303,6 @@ protected: |
return dxT; |
} |
return fabs(dx) > fabs(dy) ? dxT : dyT; |
-#endif |
} |
static bool PinTs(double* quadT, double* lineT) { |
@@ -284,16 +312,8 @@ protected: |
if (!approximately_zero_or_more(*lineT)) { |
return false; |
} |
- if (precisely_less_than_zero(*quadT)) { |
- *quadT = 0; |
- } else if (precisely_greater_than_one(*quadT)) { |
- *quadT = 1; |
- } |
- if (precisely_less_than_zero(*lineT)) { |
- *lineT = 0; |
- } else if (precisely_greater_than_one(*lineT)) { |
- *lineT = 1; |
- } |
+ *quadT = SkPinT(*quadT); |
+ *lineT = SkPinT(*lineT); |
return true; |
} |
@@ -301,6 +321,7 @@ private: |
const SkDQuad& quad; |
const SkDLine& line; |
SkIntersections* intersections; |
+ bool fAllowNear; |
}; |
// utility for pairs of coincident quads |
@@ -355,6 +376,7 @@ int SkIntersections::vertical(const SkDQuad& quad, double top, double bottom, do |
int SkIntersections::intersect(const SkDQuad& quad, const SkDLine& line) { |
LineQuadraticIntersections q(quad, line, this); |
+ q.allowNear(fAllowNear); |
return q.intersect(); |
} |