From 6c6ad76c94190e6eca0ef87a83393f9ee005f769 Mon Sep 17 00:00:00 2001 From: hkrish Date: Sat, 17 May 2014 13:43:46 +0200 Subject: [PATCH] Handle overlapping intercepts in getIntersection, In a more robust way. Restricting ranges in parameter is not a nice way to handle endpoint intersections. --- src/path/PathItem.Boolean.js | 45 +++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/src/path/PathItem.Boolean.js b/src/path/PathItem.Boolean.js index 30d56f5e..16b4fbb6 100644 --- a/src/path/PathItem.Boolean.js +++ b/src/path/PathItem.Boolean.js @@ -229,7 +229,8 @@ PathItem.inject(new function() { windRight = 0, roots = [], abs = Math.abs, - MAX = 1 - TOLERANCE; + tMin = TOLERANCE, + tMax = 1 - TOLERANCE; // Absolutely horizontal curves may return wrong results, since // the curves are monotonic in y direction and this is an // indeterminate state. @@ -270,7 +271,8 @@ PathItem.inject(new function() { var curve = curves[i], values = curve.values, winding = curve.winding, - next = curve.next; + next = curve.next, + lastT, lastX0; // Since the curves are monotone in y direction, we can just // compare the endpoints of the curve to determine if the // ray from query point along +-x direction will intersect @@ -278,30 +280,35 @@ PathItem.inject(new function() { if (winding && (winding === 1 && y >= values[1] && y <= values[7] || y >= values[7] && y <= values[1]) - && Curve.solveCubic(values, 1, y, roots, 0, - // If the next curve is horizontal, we have to include - // the end of this curve to make sure we won't miss an - // intercept. - !next.winding && next.values[1] === y ? 1 : MAX) === 1){ + && Curve.solveCubic(values, 1, y, roots, 0, 1) === 1){ var t = roots[0], x0 = Curve.evaluate(values, t, 0).x, slope = Curve.evaluate(values, t, 1).y; - // Take care of cases where the curve and the preceding - // curve merely touches the ray towards +-x direction, but - // proceeds to the same side of the ray. This essentially is - // not a crossing. - if (abs(slope) < TOLERANCE && !Curve.isLinear(values) + // Due to numerical precision issues, two consecutive curves + // may register an intercept twice, at t = 1 and 0, if y is + // almost equal to one of the endpoints of the curves. + if (!(lastT && abs(lastX0 - x0) < TOLERANCE + && ((lastT <= tMin && t >= tMax) + || (t <= tMin && lastT >= tMax)))) { + // Take care of cases where the curve and the preceding + // curve merely touches the ray towards +-x direction, but + // proceeds to the same side of the ray. This essentially is + // not a crossing. + if (abs(slope) < TOLERANCE && !Curve.isLinear(values) || t < TOLERANCE && slope * Curve.evaluate( curve.previous.values, t, 1).y < 0) { - if (testContains && x0 >= xBefore && x0 <= xAfter) { - ++windLeft; - ++windRight; + if (testContains && x0 >= xBefore && x0 <= xAfter) { + ++windLeft; + ++windRight; + } + } else if (x0 <= xBefore) { + windLeft += winding; + } else if (x0 >= xAfter) { + windRight += winding; } - } else if (x0 <= xBefore) { - windLeft += winding; - } else if (x0 >= xAfter) { - windRight += winding; } + lastT = t; + lastX0 = x0; } } }