Rough bounds checking for _addBounds()

Performance of `_addBounds()` can be improved significantly by performing a rough bounds checking first. This is a cheap way to check if the curve can extend the current min or max values at all. Only if the check is passed, further Only if the current bounds can be extended by the curve's bounds, further calculation needs to be done.
Also, if the values of a curve are sorted, the extrema are simply the start and end point.
This commit is contained in:
Jan 2016-06-16 12:46:12 +02:00 committed by GitHub
parent eb752a43cd
commit c217e963b8

View file

@ -785,42 +785,54 @@ statics: /** @lends Curve */{
*/ */
_addBounds: function(v0, v1, v2, v3, coord, padding, min, max, roots) { _addBounds: function(v0, v1, v2, v3, coord, padding, min, max, roots) {
padding /= 2; // strokePadding is in width, not radius padding /= 2; // strokePadding is in width, not radius
// Code ported and further optimised from: var minPad = min[coord] - padding,
// http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html maxPad = max[coord] + padding;
function add(value, padding) { // The curve can only extend the current bounds if at least one value
var left = value - padding, // is outside the min-max range.
right = value + padding; if (v0 < minPad || v1 < minPad || v2 < minPad || v3 < minPad
if (left < min[coord]) || v0 > maxPad || v1 > maxPad || v2 > maxPad || v3 > maxPad) {
min[coord] = left; // Code ported and further optimised from:
if (right > max[coord]) // http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html
max[coord] = right; function add(value, padding) {
} var left = value - padding,
// Calculate derivative of our bezier polynomial, divided by 3. right = value + padding;
// Doing so allows for simpler calculations of a, b, c and leads to the if (left < min[coord])
// same quadratic roots. min[coord] = left;
var a = 3 * (v1 - v2) - v0 + v3, if (right > max[coord])
b = 2 * (v0 + v2) - 4 * v1, max[coord] = right;
c = v1 - v0, }
count = Numerical.solveQuadratic(a, b, c, roots), if (v1 < v0 != v1 < v3 && v2 < v0 != v2 < v3) {
// Add some tolerance for good roots, as t = 0, 1 are added // If values are sorted, the curve's extrema are v0 and v3
// separately anyhow, and we don't want joins to be added with radii add(v0, padding);
// in getStrokeBounds() add(v3, padding);
tMin = /*#=*/Numerical.CURVETIME_EPSILON, } else {// Calculate derivative of our bezier polynomial, divided by 3.
tMax = 1 - tMin; // Doing so allows for simpler calculations of a, b, c and leads to the
// Only add strokeWidth to bounds for points which lie within 0 < t < 1 // same quadratic roots.
// The corner cases for cap and join are handled in getStrokeBounds() var a = 3 * (v1 - v2) - v0 + v3,
add(v3, 0); b = 2 * (v0 + v2) - 4 * v1,
for (var i = 0; i < count; i++) { c = v1 - v0,
var t = roots[i], count = Numerical.solveQuadratic(a, b, c, roots),
u = 1 - t; // Add some tolerance for good roots, as t = 0, 1 are added
// Test for good roots and only add to bounds if good. // separately anyhow, and we don't want joins to be added with radii
if (tMin < t && t < tMax) // in getStrokeBounds()
// Calculate bezier polynomial at t. tMin = /*#=*/Numerical.CURVETIME_EPSILON,
add(u * u * u * v0 tMax = 1 - tMin;
+ 3 * u * u * t * v1 // Only add strokeWidth to bounds for points which lie within 0 < t < 1
+ 3 * u * t * t * v2 // The corner cases for cap and join are handled in getStrokeBounds()
+ t * t * t * v3, add(v3, 0);
padding); for (var i = 0; i < count; i++) {
var t = roots[i],
u = 1 - t;
// Test for good roots and only add to bounds if good.
if (tMin < t && t < tMax)
// Calculate bezier polynomial at t.
add(u * u * u * v0
+ 3 * u * u * t * v1
+ 3 * u * t * t * v2
+ t * t * t * v3,
padding);
}
}
} }
} }
}}, Base.each( }}, Base.each(