Fix imprecision in Numerical.findRoot()

Results can be slightly outside of the range.
Close #1149
This commit is contained in:
Jürg Lehni 2016-09-24 15:39:09 -04:00
parent 80f6dbb5e3
commit 6dd7cc5b6a
2 changed files with 26 additions and 17 deletions

View file

@ -216,8 +216,10 @@ var Numerical = new function() {
nx = x - dx; nx = x - dx;
// See if we can trust the Newton-Raphson result. If not we use // See if we can trust the Newton-Raphson result. If not we use
// bisection to find another candidate for Newton's method. // bisection to find another candidate for Newton's method.
if (abs(dx) < tolerance) if (abs(dx) < tolerance) {
return nx; x = nx;
break;
}
// Update the root-bounding interval and test for containment of // Update the root-bounding interval and test for containment of
// the candidate. If candidate is outside the root-bounding // the candidate. If candidate is outside the root-bounding
// interval, use bisection instead. // interval, use bisection instead.
@ -234,7 +236,8 @@ var Numerical = new function() {
} }
// Return the best result even though we haven't gotten close // Return the best result even though we haven't gotten close
// enough to the root... (In paper.js this never seems to happen). // enough to the root... (In paper.js this never seems to happen).
return x; // But make sure, that it actually is within the given range [a, b]
return clamp(x, a, b);
}, },
/** /**

View file

@ -192,6 +192,25 @@ test('Curve#getTimeAt() with straight curve', function() {
equals(t, 0.3869631475722452); equals(t, 0.3869631475722452);
}); });
test('Curve#getTimeAt() with straight curve', function() {
// #1000:
var curve = new Curve([
1584.4999999999998, 1053.2499999999995,
1584.4999999999998,1053.2499999999995,
1520.5,1053.2499999999995,
1520.5,1053.2499999999995
]);
var offset = 63.999999999999716;
equals(function() { return offset < curve.length; }, true);
equals(function() { return curve.getTimeAt(offset); }, 1);
});
test('Curve#getTimeAt() with offset at end of curve', function() {
// #1149:
var curve = [-7500, 0, -7500, 4142.135623730952, -4142.135623730952, 7500, 0, 7500];
equals(Curve.getTimeAt(curve, 11782.625235553916), 1);
});
test('Curve#getLocationAt()', function() { test('Curve#getLocationAt()', function() {
var curve = new Path([ var curve = new Path([
[[0, 0], [0, 0], [100, 0]], [[0, 0], [0, 0], [100, 0]],
@ -248,7 +267,7 @@ test('Curve#isLinear()', function() {
}); });
test('Curve#getTimeOf()', function() { test('Curve#getTimeOf()', function() {
// For issue #708: // #708:
var path = new Path.Rectangle({ var path = new Path.Rectangle({
center: new Point(300, 100), center: new Point(300, 100),
size: new Point(100, 100), size: new Point(100, 100),
@ -275,19 +294,6 @@ test('Curve#getTimeOf()', function() {
} }
}); });
test('Curve#getTimeAt() with straight curve', function() {
// #1000:
var curve = new Curve([
1584.4999999999998, 1053.2499999999995,
1584.4999999999998,1053.2499999999995,
1520.5,1053.2499999999995,
1520.5,1053.2499999999995
]);
var offset = 63.999999999999716;
equals(function() { return offset < curve.length; }, true);
equals(function() { return curve.getTimeAt(offset); }, 1);
});
test('Curve#getPartLength() with straight curve', function() { test('Curve#getPartLength() with straight curve', function() {
var curve = new Curve([0, 0, 0, 0, 64, 0, 64, 0]); var curve = new Curve([0, 0, 0, 0, 64, 0, 64, 0]);
equals(function() { return curve.getPartLength(0.0, 0.25); }, 10); equals(function() { return curve.getPartLength(0.0, 0.25); }, 10);