Index: src/pathops/SkDCubicLineIntersection.cpp |
diff --git a/src/pathops/SkDCubicLineIntersection.cpp b/src/pathops/SkDCubicLineIntersection.cpp |
index f86a21ccc1baf1d8de1559a26f9efcb2d70b9595..dc80479f602072fd1c365923264a01bf540bee3c 100644 |
--- a/src/pathops/SkDCubicLineIntersection.cpp |
+++ b/src/pathops/SkDCubicLineIntersection.cpp |
@@ -80,7 +80,12 @@ public: |
LineCubicIntersections(const SkDCubic& c, const SkDLine& l, SkIntersections& i) |
: cubic(c) |
, line(l) |
- , intersections(i) { |
+ , intersections(i) |
+ , fAllowNear(true) { |
+} |
+ |
+void allowNear(bool allow) { |
+ fAllowNear = allow; |
} |
// see parallel routine in line quadratic intersections |
@@ -97,7 +102,7 @@ int intersectRay(double roots[3]) { |
} |
int intersect() { |
- addEndPoints(); |
+ addExactEndPoints(); |
double rootVals[3]; |
int roots = intersectRay(rootVals); |
for (int index = 0; index < roots; ++index) { |
@@ -113,6 +118,9 @@ int intersect() { |
intersections.insert(cubicT, lineT, pt); |
} |
} |
+ if (fAllowNear) { |
+ addNearEndPoints(); |
+ } |
return intersections.used(); |
} |
@@ -124,7 +132,7 @@ int horizontalIntersect(double axisIntercept, double roots[3]) { |
} |
int horizontalIntersect(double axisIntercept, double left, double right, bool flipped) { |
- addHorizontalEndPoints(left, right, axisIntercept); |
+ addExactHorizontalEndPoints(left, right, axisIntercept); |
double rootVals[3]; |
int roots = horizontalIntersect(axisIntercept, rootVals); |
for (int index = 0; index < roots; ++index) { |
@@ -135,6 +143,9 @@ int horizontalIntersect(double axisIntercept, double left, double right, bool fl |
intersections.insert(cubicT, lineT, pt); |
} |
} |
+ if (fAllowNear) { |
+ addNearHorizontalEndPoints(left, right, axisIntercept); |
+ } |
if (flipped) { |
intersections.flip(); |
} |
@@ -149,7 +160,7 @@ int verticalIntersect(double axisIntercept, double roots[3]) { |
} |
int verticalIntersect(double axisIntercept, double top, double bottom, bool flipped) { |
- addVerticalEndPoints(top, bottom, axisIntercept); |
+ addExactVerticalEndPoints(top, bottom, axisIntercept); |
double rootVals[3]; |
int roots = verticalIntersect(axisIntercept, rootVals); |
for (int index = 0; index < roots; ++index) { |
@@ -160,6 +171,9 @@ int verticalIntersect(double axisIntercept, double top, double bottom, bool flip |
intersections.insert(cubicT, lineT, pt); |
} |
} |
+ if (fAllowNear) { |
+ addNearVerticalEndPoints(top, bottom, axisIntercept); |
+ } |
if (flipped) { |
intersections.flip(); |
} |
@@ -168,65 +182,81 @@ int verticalIntersect(double axisIntercept, double top, double bottom, bool flip |
protected: |
-void addEndPoints() { |
+void addExactEndPoints() { |
for (int cIndex = 0; cIndex < 4; cIndex += 3) { |
- bool foundEnd = false; |
- for (int lIndex = 0; lIndex < 2; lIndex++) { |
- if (cubic[cIndex] == line[lIndex]) { |
- intersections.insert(cIndex >> 1, lIndex, line[lIndex]); |
- foundEnd = true; |
- } |
- } |
- // for the test case this was written for, the dist / error ratio was 170.6667 |
- // it looks like the cubic stops short of touching the line, but this fixed it. |
- if (foundEnd) { |
+ double lineT = line.exactPoint(cubic[cIndex]); |
+ if (lineT < 0) { |
continue; |
} |
- // See if the cubic end touches the line. |
- double dist = line.isLeft(cubic[cIndex]); // 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 cubicT = (double) (cIndex >> 1); |
+ intersections.insert(cubicT, lineT, cubic[cIndex]); |
+ } |
+} |
+ |
+void addNearEndPoints() { |
+ for (int cIndex = 0; cIndex < 4; cIndex += 3) { |
+ double cubicT = (double) (cIndex >> 1); |
+ if (intersections.hasT(cubicT)) { |
continue; |
} |
- double lineT = findLineT(cIndex >> 1); |
- if (!between(0, lineT, 1)) { |
+ double lineT = line.nearPoint(cubic[cIndex]); |
+ if (lineT < 0) { |
continue; |
} |
- SkDPoint linePt = line.xyAtT(lineT); |
- if (linePt.approximatelyEqual(cubic[cIndex])) { |
- intersections.insert(cIndex >> 1, lineT, cubic[cIndex]); |
- } |
+ intersections.insert(cubicT, lineT, cubic[cIndex]); |
} |
} |
-void addHorizontalEndPoints(double left, double right, double y) { |
+void addExactHorizontalEndPoints(double left, double right, double y) { |
for (int cIndex = 0; cIndex < 4; cIndex += 3) { |
- if (cubic[cIndex].fY != y) { |
+ double lineT = SkDLine::ExactPointH(cubic[cIndex], left, right, y); |
+ if (lineT < 0) { |
continue; |
} |
- if (cubic[cIndex].fX == left) { |
- intersections.insert(cIndex >> 1, 0, cubic[cIndex]); |
+ double cubicT = (double) (cIndex >> 1); |
+ intersections.insert(cubicT, lineT, cubic[cIndex]); |
+ } |
+} |
+ |
+void addNearHorizontalEndPoints(double left, double right, double y) { |
+ for (int cIndex = 0; cIndex < 4; cIndex += 3) { |
+ double cubicT = (double) (cIndex >> 1); |
+ if (intersections.hasT(cubicT)) { |
+ continue; |
} |
- if (cubic[cIndex].fX == right) { |
- intersections.insert(cIndex >> 1, 1, cubic[cIndex]); |
+ double lineT = SkDLine::NearPointH(cubic[cIndex], left, right, y); |
+ if (lineT < 0) { |
+ continue; |
} |
+ intersections.insert(cubicT, lineT, cubic[cIndex]); |
} |
+ // FIXME: see if line end is nearly on cubic |
} |
-void addVerticalEndPoints(double top, double bottom, double x) { |
+void addExactVerticalEndPoints(double top, double bottom, double x) { |
for (int cIndex = 0; cIndex < 4; cIndex += 3) { |
- if (cubic[cIndex].fX != x) { |
+ double lineT = SkDLine::ExactPointV(cubic[cIndex], top, bottom, x); |
+ if (lineT < 0) { |
continue; |
} |
- if (cubic[cIndex].fY == top) { |
- intersections.insert(cIndex >> 1, 0, cubic[cIndex]); |
+ double cubicT = (double) (cIndex >> 1); |
+ intersections.insert(cubicT, lineT, cubic[cIndex]); |
+ } |
+} |
+ |
+void addNearVerticalEndPoints(double top, double bottom, double x) { |
+ for (int cIndex = 0; cIndex < 4; cIndex += 3) { |
+ double cubicT = (double) (cIndex >> 1); |
+ if (intersections.hasT(cubicT)) { |
+ continue; |
} |
- if (cubic[cIndex].fY == bottom) { |
- intersections.insert(cIndex >> 1, 1, cubic[cIndex]); |
+ double lineT = SkDLine::NearPointV(cubic[cIndex], top, bottom, x); |
+ if (lineT < 0) { |
+ continue; |
} |
+ intersections.insert(cubicT, lineT, cubic[cIndex]); |
} |
+ // FIXME: see if line end is nearly on cubic |
} |
double findLineT(double t) { |
@@ -264,6 +294,7 @@ private: |
const SkDCubic& cubic; |
const SkDLine& line; |
SkIntersections& intersections; |
+bool fAllowNear; |
}; |
int SkIntersections::horizontal(const SkDCubic& cubic, double left, double right, double y, |
@@ -280,6 +311,7 @@ int SkIntersections::vertical(const SkDCubic& cubic, double top, double bottom, |
int SkIntersections::intersect(const SkDCubic& cubic, const SkDLine& line) { |
LineCubicIntersections c(cubic, line, *this); |
+ c.allowNear(fAllowNear); |
return c.intersect(); |
} |