mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-08 05:42:07 -05:00
Change root solvers to not produce new arrays each time but fill a passed one that can be reused. Yields io impressive performance improvements.
This commit is contained in:
parent
839107d341
commit
833d4968ce
3 changed files with 36 additions and 31 deletions
|
@ -309,15 +309,15 @@ var Curve = this.Curve = Base.extend(/** @lends Curve# */{
|
||||||
return Curve.getParameter(this.getValues(), point.x, point.y);
|
return Curve.getParameter(this.getValues(), point.x, point.y);
|
||||||
},
|
},
|
||||||
|
|
||||||
getCrossings: function(point, matrix) {
|
getCrossings: function(point, matrix, roots) {
|
||||||
// Implement the crossing number algorithm:
|
// Implement the crossing number algorithm:
|
||||||
// http://en.wikipedia.org/wiki/Point_in_polygon
|
// http://en.wikipedia.org/wiki/Point_in_polygon
|
||||||
// Solve the y-axis cubic polynominal for point.y and count all
|
// Solve the y-axis cubic polynominal for point.y and count all
|
||||||
// solutions to the right of point.x as crossings.
|
// solutions to the right of point.x as crossings.
|
||||||
var vals = this.getValues(matrix),
|
var vals = this.getValues(matrix),
|
||||||
roots = Curve.solveCubic(vals, 1, point.y),
|
num = Curve.solveCubic(vals, 1, point.y, roots),
|
||||||
crossings = 0;
|
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];
|
var t = roots[i];
|
||||||
if (t >= 0 && t < 1 && Curve.evaluate(vals, t, 0).x > point.x) {
|
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
|
// 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
|
// Converts from the point coordinates (p1, c1, c2, p2) for one axis to
|
||||||
// the polynomial coefficients and solves the polynomial for val
|
// the polynomial coefficients and solves the polynomial for val
|
||||||
solveCubic: function (v, coord, val) {
|
solveCubic: function (v, coord, val, roots) {
|
||||||
var p1 = v[coord],
|
var p1 = v[coord],
|
||||||
c1 = v[coord + 2],
|
c1 = v[coord + 2],
|
||||||
c2 = v[coord + 4],
|
c2 = v[coord + 4],
|
||||||
|
@ -478,14 +478,15 @@ var Curve = this.Curve = Base.extend(/** @lends Curve# */{
|
||||||
c = 3 * (c1 - p1),
|
c = 3 * (c1 - p1),
|
||||||
b = 3 * (c2 - c1) - c,
|
b = 3 * (c2 - c1) - c,
|
||||||
a = p2 - p1 - c - b;
|
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) {
|
getParameter: function(v, x, y) {
|
||||||
var txs = Curve.solveCubic(v, 0, x),
|
var txs = [],
|
||||||
tys = Curve.solveCubic(v, 1, y),
|
tys = [],
|
||||||
sx = txs === Infinity ? -1 : txs.length,
|
sx = Curve.solveCubic(v, 0, x, txs),
|
||||||
sy = tys === Infinity ? -1 : tys.length,
|
sy = Curve.solveCubic(v, 1, y, tys),
|
||||||
tx, ty;
|
tx, ty;
|
||||||
// sx, sy == -1 means infinite solutions:
|
// sx, sy == -1 means infinite solutions:
|
||||||
// Loop through all solutions for x and match with solutions for y,
|
// Loop through all solutions for x and match with solutions for y,
|
||||||
|
|
|
@ -1191,9 +1191,11 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{
|
||||||
// number, meaning the starting point is inside the shape.
|
// number, meaning the starting point is inside the shape.
|
||||||
// http://en.wikipedia.org/wiki/Point_in_polygon
|
// http://en.wikipedia.org/wiki/Point_in_polygon
|
||||||
var curves = this.getCurves(),
|
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++)
|
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;
|
return (crossings & 1) == 1;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -117,32 +117,34 @@ var Numerical = new function() {
|
||||||
*
|
*
|
||||||
* a*x^2 + b*x + c = 0
|
* 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.,
|
// After Numerical Recipes in C, 2nd edition, Press et al.,
|
||||||
// 5.6, Quadratic and Cubic Equations
|
// 5.6, Quadratic and Cubic Equations
|
||||||
// If problem is actually linear, return 0 or 1 easy roots
|
// If problem is actually linear, return 0 or 1 easy roots
|
||||||
if (abs(a) < tolerance) {
|
if (abs(a) < tolerance) {
|
||||||
if (abs(b) >= tolerance)
|
if (abs(b) >= tolerance) {
|
||||||
return [ -c / b ];
|
roots[0] = -c / b;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
// If all the coefficients are 0, infinite values are
|
// If all the coefficients are 0, infinite values are
|
||||||
// possible!
|
// possible!
|
||||||
if (abs(c) < tolerance)
|
if (abs(c) < tolerance)
|
||||||
return Infinity; // Infinite solutions
|
return -1; // Infinite solutions
|
||||||
return []; // 0 solutions
|
return 0; // 0 solutions
|
||||||
}
|
}
|
||||||
var q = b * b - 4 * a * c;
|
var q = b * b - 4 * a * c;
|
||||||
if (q < 0)
|
if (q < 0)
|
||||||
return []; // 0 solutions
|
return 0; // 0 solutions
|
||||||
q = sqrt(q);
|
q = sqrt(q);
|
||||||
if (b < 0)
|
if (b < 0)
|
||||||
q = -q;
|
q = -q;
|
||||||
q = (b + q) * -0.5;
|
q = (b + q) * -0.5;
|
||||||
var roots = [];
|
var n = 0;
|
||||||
if (abs(q) >= tolerance)
|
if (abs(q) >= tolerance)
|
||||||
roots.push(c / q);
|
roots[n++] = c / q;
|
||||||
if (abs(a) >= tolerance)
|
if (abs(a) >= tolerance)
|
||||||
roots.push(q / a);
|
roots[n++] = q / a;
|
||||||
return roots; // 0, 1 or 2 solutions
|
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
|
* 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.,
|
// After Numerical Recipes in C, 2nd edition, Press et al.,
|
||||||
// 5.6, Quadratic and Cubic Equations
|
// 5.6, Quadratic and Cubic Equations
|
||||||
if (abs(a) < tolerance)
|
if (abs(a) < tolerance)
|
||||||
return Numerical.solveQuadratic(b, c, d, tolerance);
|
return Numerical.solveQuadratic(b, c, d, roots, tolerance);
|
||||||
// Normalize
|
// Normalize
|
||||||
b /= a;
|
b /= a;
|
||||||
c /= a;
|
c /= a;
|
||||||
|
@ -173,18 +175,18 @@ var Numerical = new function() {
|
||||||
var theta = Math.acos(R / sqrt(Q3)),
|
var theta = Math.acos(R / sqrt(Q3)),
|
||||||
// This sqrt is safe, since Q3 >= 0, and thus Q >= 0
|
// This sqrt is safe, since Q3 >= 0, and thus Q >= 0
|
||||||
q = -2 * sqrt(Q);
|
q = -2 * sqrt(Q);
|
||||||
return [
|
roots[0] = q * cos(theta / 3) - b;
|
||||||
q * cos(theta / 3) - b,
|
roots[1] = q * cos((theta + 2 * PI) / 3) - b;
|
||||||
q * cos((theta + 2 * PI) / 3) - b,
|
roots[2] = q * cos((theta - 2 * PI) / 3) - b;
|
||||||
q * cos((theta - 2 * PI) / 3) - b
|
return 3;
|
||||||
];
|
|
||||||
} else { // One real root
|
} else { // One real root
|
||||||
var A = -Math.pow(abs(R) + sqrt(R2 - Q3), 1 / 3);
|
var A = -Math.pow(abs(R) + sqrt(R2 - Q3), 1 / 3);
|
||||||
if (R < 0) A = -A;
|
if (R < 0) A = -A;
|
||||||
var B = (abs(A) < tolerance) ? 0 : Q / A;
|
var B = (abs(A) < tolerance) ? 0 : Q / A;
|
||||||
return [ (A + B) - b ];
|
roots[0] = (A + B) - b;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
return [];
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue