diff --git a/src/path/Curve.js b/src/path/Curve.js index 56360668..a7cad223 100644 --- a/src/path/Curve.js +++ b/src/path/Curve.js @@ -667,23 +667,35 @@ statics: { }, getParameterOf: function(v, point) { + // Before solving cubics, compare the beginning and end of the curve + // with zero epsilon: + var p1 = new Point(v[0], v[1]), + p2 = new Point(v[6], v[7]), + epsilon = /*#=*/Numerical.EPSILON, + t = point.isClose(p1, epsilon) ? 0 + : point.isClose(p2, epsilon) ? 1 + : null; + if (t !== null) + return t; + // Solve the cubic for both x- and y-coordinates and consider all found + // solutions, testing with the larger / looser geometric epsilon. var coords = [point.x, point.y], roots = [], - epsilon = /*#=*/Numerical.GEOMETRIC_EPSILON; + geomEpsilon = /*#=*/Numerical.GEOMETRIC_EPSILON; for (var c = 0; c < 2; c++) { var count = Curve.solveCubic(v, c, coords[c], roots, 0, 1); for (var i = 0; i < count; i++) { - var t = roots[i]; - if (point.isClose(Curve.getPoint(v, t), epsilon)) + t = roots[i]; + if (point.isClose(Curve.getPoint(v, t), geomEpsilon)) return t; } } // For very short curves (length ~ 1e-13), the above code will not // necessarily produce any valid roots. As a fall-back, just check the // beginnings and ends at the end so we can still return a valid result. - return point.isClose(new Point(v[0], v[1]), epsilon) ? 0 - : point.isClose(new Point(v[6], v[7]), epsilon) ? 1 - : null; + return point.isClose(p1, geomEpsilon) ? 0 + : point.isClose(p2, geomEpsilon) ? 1 + : null; }, // TODO: Find better name