diff --git a/src/path/Curve.js b/src/path/Curve.js index afedb5a4..03c32e03 100644 --- a/src/path/Curve.js +++ b/src/path/Curve.js @@ -309,15 +309,15 @@ var Curve = this.Curve = Base.extend(/** @lends Curve# */{ return Curve.getParameter(this.getValues(), point.x, point.y); }, - getCrossings: function(point, matrix) { + getCrossings: function(point, matrix, roots) { // Implement the crossing number algorithm: // http://en.wikipedia.org/wiki/Point_in_polygon // Solve the y-axis cubic polynominal for point.y and count all // solutions to the right of point.x as crossings. var vals = this.getValues(matrix), - roots = Curve.solveCubic(vals, 1, point.y), + num = Curve.solveCubic(vals, 1, point.y, roots), crossings = 0; - for (var i = 0, l = roots != Infinity && roots.length; i < l; i++) { + for (var i = 0; i < num; i++) { var t = roots[i]; if (t >= 0 && t < 1 && Curve.evaluate(vals, t, 0).x > point.x) { // If we're close to 0 and are not changing y-direction from the @@ -470,7 +470,7 @@ var Curve = this.Curve = Base.extend(/** @lends Curve# */{ // Converts from the point coordinates (p1, c1, c2, p2) for one axis to // the polynomial coefficients and solves the polynomial for val - solveCubic: function (v, coord, val) { + solveCubic: function (v, coord, val, roots) { var p1 = v[coord], c1 = v[coord + 2], c2 = v[coord + 4], @@ -478,14 +478,15 @@ var Curve = this.Curve = Base.extend(/** @lends Curve# */{ c = 3 * (c1 - p1), b = 3 * (c2 - c1) - c, a = p2 - p1 - c - b; - return Numerical.solveCubic(a, b, c, p1 - val, Numerical.TOLERANCE); + return Numerical.solveCubic(a, b, c, p1 - val, roots, + Numerical.TOLERANCE); }, getParameter: function(v, x, y) { - var txs = Curve.solveCubic(v, 0, x), - tys = Curve.solveCubic(v, 1, y), - sx = txs === Infinity ? -1 : txs.length, - sy = tys === Infinity ? -1 : tys.length, + var txs = [], + tys = [], + sx = Curve.solveCubic(v, 0, x, txs), + sy = Curve.solveCubic(v, 1, y, tys), tx, ty; // sx, sy == -1 means infinite solutions: // Loop through all solutions for x and match with solutions for y, diff --git a/src/path/Path.js b/src/path/Path.js index cdac2bd9..8349231a 100644 --- a/src/path/Path.js +++ b/src/path/Path.js @@ -1191,9 +1191,11 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{ // number, meaning the starting point is inside the shape. // http://en.wikipedia.org/wiki/Point_in_polygon var curves = this.getCurves(), - crossings = 0; + crossings = 0, + // Reuse one array for root-finding, give garbage collector a break + roots = []; for (var i = 0, l = curves.length; i < l; i++) - crossings += curves[i].getCrossings(point, matrix); + crossings += curves[i].getCrossings(point, matrix, roots); return (crossings & 1) == 1; }, diff --git a/src/util/Numerical.js b/src/util/Numerical.js index f1325d47..9e4d80c5 100644 --- a/src/util/Numerical.js +++ b/src/util/Numerical.js @@ -117,32 +117,34 @@ var Numerical = new function() { * * a*x^2 + b*x + c = 0 */ - solveQuadratic: function(a, b, c, tolerance) { + solveQuadratic: function(a, b, c, roots, tolerance) { // After Numerical Recipes in C, 2nd edition, Press et al., // 5.6, Quadratic and Cubic Equations // If problem is actually linear, return 0 or 1 easy roots if (abs(a) < tolerance) { - if (abs(b) >= tolerance) - return [ -c / b ]; + if (abs(b) >= tolerance) { + roots[0] = -c / b; + return 1; + } // If all the coefficients are 0, infinite values are // possible! if (abs(c) < tolerance) - return Infinity; // Infinite solutions - return []; // 0 solutions + return -1; // Infinite solutions + return 0; // 0 solutions } var q = b * b - 4 * a * c; if (q < 0) - return []; // 0 solutions + return 0; // 0 solutions q = sqrt(q); if (b < 0) q = -q; q = (b + q) * -0.5; - var roots = []; + var n = 0; if (abs(q) >= tolerance) - roots.push(c / q); + roots[n++] = c / q; if (abs(a) >= tolerance) - roots.push(q / a); - return roots; // 0, 1 or 2 solutions + roots[n++] = q / a; + return n; // 0, 1 or 2 solutions }, /** @@ -151,11 +153,11 @@ var Numerical = new function() { * * a*x^3 + b*x^2 + c*x + d = 0 */ - solveCubic: function(a, b, c, d, tolerance) { + solveCubic: function(a, b, c, d, roots, tolerance) { // After Numerical Recipes in C, 2nd edition, Press et al., // 5.6, Quadratic and Cubic Equations if (abs(a) < tolerance) - return Numerical.solveQuadratic(b, c, d, tolerance); + return Numerical.solveQuadratic(b, c, d, roots, tolerance); // Normalize b /= a; c /= a; @@ -173,18 +175,18 @@ var Numerical = new function() { var theta = Math.acos(R / sqrt(Q3)), // This sqrt is safe, since Q3 >= 0, and thus Q >= 0 q = -2 * sqrt(Q); - return [ - q * cos(theta / 3) - b, - q * cos((theta + 2 * PI) / 3) - b, - q * cos((theta - 2 * PI) / 3) - b - ]; + roots[0] = q * cos(theta / 3) - b; + roots[1] = q * cos((theta + 2 * PI) / 3) - b; + roots[2] = q * cos((theta - 2 * PI) / 3) - b; + return 3; } else { // One real root var A = -Math.pow(abs(R) + sqrt(R2 - Q3), 1 / 3); if (R < 0) A = -A; - var B = (abs(A) < tolerance) ? 0 : Q / A; - return [ (A + B) - b ]; + var B = (abs(A) < tolerance) ? 0 : Q / A; + roots[0] = (A + B) - b; + return 1; } - return []; + return 0; } }; };