mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-05 20:32:00 -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);
|
||||
},
|
||||
|
||||
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,
|
||||
|
|
|
@ -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;
|
||||
},
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue