mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-06-02 08:14:57 -04:00
Implement new root finding algorithm, combining Newton-Raphson Method with Bisection, and update Curve#getParameter() to use it.
This commit is contained in:
parent
7868bc1bdc
commit
6609dc2307
2 changed files with 21 additions and 41 deletions
src
|
@ -382,6 +382,7 @@ var Curve = this.Curve = Base.extend({
|
||||||
len = 0;
|
len = 0;
|
||||||
if (length >= rangeLength)
|
if (length >= rangeLength)
|
||||||
return forward ? b : a;
|
return forward ? b : a;
|
||||||
|
|
||||||
// Iteratively calculate curve range lengths, and add them up,
|
// Iteratively calculate curve range lengths, and add them up,
|
||||||
// using integration precision depending on the size of the
|
// using integration precision depending on the size of the
|
||||||
// range. This is much faster and also more precise than not
|
// range. This is much faster and also more precise than not
|
||||||
|
@ -396,10 +397,9 @@ var Curve = this.Curve = Base.extend({
|
||||||
start = t;
|
start = t;
|
||||||
return len - length;
|
return len - length;
|
||||||
}
|
}
|
||||||
return Numerical.findRootNewton(f, ds,
|
return Numerical.findRoot(f, ds,
|
||||||
forward ? a : b - guess, // a
|
forward ? a + guess : b - guess, // Initial guess for x
|
||||||
forward ? a + guess : b, // b
|
a, b, 16, Numerical.TOLERANCE);
|
||||||
16, Numerical.TOLERANCE);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
subdivide: function(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) {
|
subdivide: function(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) {
|
||||||
|
|
|
@ -77,50 +77,30 @@ var Numerical = new function() {
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Newton-Raphson Method Using Derivative. This is a special version
|
* Root finding using Newton-Raphson Method combined with Bisection.
|
||||||
* that clips results to 0 .. 1, as required by Paper.js iterative
|
|
||||||
* approach for curve time parametrization: Ending up far outside
|
|
||||||
* the bezier curve boundaries resulted in inprecision of added up
|
|
||||||
* curve lengths.
|
|
||||||
*/
|
*/
|
||||||
findRootNewton: function(f, fd, a, b, n, tol) {
|
findRoot: function(f, df, x, a, b, n, tol) {
|
||||||
var x = 0.5 * (a + b);
|
|
||||||
for (var i = 0; i < n; i++) {
|
for (var i = 0; i < n; i++) {
|
||||||
var dx = f(x) / fd(x);
|
var fx = f(x),
|
||||||
x -= dx;
|
dx = fx / df(x);
|
||||||
// Clip to 0 .. t .. 1. See comment above
|
|
||||||
if (x < 0) x = 0;
|
|
||||||
else if (x > 1) x = 1;
|
|
||||||
if (Math.abs(dx) < tol)
|
if (Math.abs(dx) < tol)
|
||||||
return x;
|
return x;
|
||||||
}
|
// Generate a candidate for Newton's method.
|
||||||
// If we did not succeed, fall back on False Position method for
|
var nx = x - dx;
|
||||||
// accurate results.
|
// Update the root-bounding interval and test for containment of
|
||||||
return Numerical.findRootFalsePosition(f, a, b, n, tol);
|
// the candidate. If candidate is outside the root-bounding
|
||||||
},
|
// interval, use bisection instead.
|
||||||
|
// There is no need to compare to lower / upper because the
|
||||||
findRootFalsePosition: function(f, a, b, n, tol) {
|
// tangent line has positive slope, guaranteeing that the x-axis
|
||||||
var fa = f(a),
|
// intercept is larger than lower / smaller than upper.
|
||||||
fb = f(b),
|
if (fx > 0) {
|
||||||
dx = b - a,
|
|
||||||
del, x;
|
|
||||||
for (var i = 0; i < n; i++) {
|
|
||||||
x = a + dx * fa / (fa - fb);
|
|
||||||
var fx = f(x);
|
|
||||||
if (fx < 0) {
|
|
||||||
del = a - x;
|
|
||||||
a = x;
|
|
||||||
fa = fx;
|
|
||||||
} else {
|
|
||||||
del = b - x;
|
|
||||||
b = x;
|
b = x;
|
||||||
fb = fx;
|
x = nx <= a ? 0.5 * (a + b) : nx;
|
||||||
|
} else {
|
||||||
|
a = x;
|
||||||
|
x = nx >= b ? 0.5 * (a + b) : nx;
|
||||||
}
|
}
|
||||||
dx = b - a;
|
|
||||||
if (Math.abs(del) < tol || fx == 0)
|
|
||||||
return x;
|
|
||||||
}
|
}
|
||||||
return x;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue