@bokeh/bokehjs
Version:
Interactive, novel data visualization
97 lines • 3.01 kB
JavaScript
import { minmax2 } from "./arrayable";
const { abs, sqrt, min, max } = Math;
/**
* Formula from: http://pomax.nihongoresources.com/pages/bezier/
*
* if segment is quadratic bezier do:
* for both directions do:
* if control between start and end, compute linear bounding box
* otherwise, compute
* bound = u(1-t)^2 + 2v(1-t)t + wt^2
* (with t = ((u-v) / (u-2v+w)), with {u = start, v = control, w = end})
* if control precedes start, min = bound, otherwise max = bound
*/
export function qbb(x0, y0, cx, cy, x1, y1) {
function _qbb(u, v, w) {
if (v == (u + w) / 2) {
return [u, w];
}
else {
const t = (u - v) / (u - 2 * v + w);
const bd = u * (1 - t) ** 2 + 2 * v * (1 - t) * t + w * t ** 2;
return [min(u, w, bd), max(u, w, bd)];
}
}
const [x_min, x_max] = _qbb(x0, cx, x1);
const [y_min, y_max] = _qbb(y0, cy, y1);
return {
x0: x_min, x1: x_max,
y0: y_min, y1: y_max,
};
}
// algorithm adapted from http://stackoverflow.com/a/14429749/3406693
export function cbb(x0, y0, cx0, cy0, cx1, cy1, x1, y1) {
const x3 = x1;
const y3 = y1;
x1 = cx0;
y1 = cy0;
const x2 = cx1;
const y2 = cy1;
const tvalues = [];
for (let i = 0; i <= 2; i++) {
let a, b, c;
if (i == 0) {
b = 6 * x0 - 12 * x1 + 6 * x2;
a = -3 * x0 + 9 * x1 - 9 * x2 + 3 * x3;
c = 3 * x1 - 3 * x0;
}
else {
b = 6 * y0 - 12 * y1 + 6 * y2;
a = -3 * y0 + 9 * y1 - 9 * y2 + 3 * y3;
c = 3 * y1 - 3 * y0;
}
// Numerical robustness
if (abs(a) < 1e-12) {
if (abs(b) < 1e-12) {
continue;
}
const t = -c / b;
if (0 < t && t < 1) {
tvalues.push(t);
}
continue;
}
const b2ac = b ** 2 - 4 * c * a;
const sqrtb2ac = sqrt(b2ac);
if (b2ac < 0) {
continue;
}
const t1 = (-b + sqrtb2ac) / (2 * a);
if (0 < t1 && t1 < 1) {
tvalues.push(t1);
}
const t2 = (-b - sqrtb2ac) / (2 * a);
if (0 < t2 && t2 < 1) {
tvalues.push(t2);
}
}
const n = tvalues.length;
let j = n;
const x_bounds = Array(n + 2);
const y_bounds = Array(n + 2);
while (j-- > 0) {
const t = tvalues[j];
const mt = 1 - t;
const x = mt ** 3 * x0 + 3 * mt ** 2 * t * x1 + 3 * mt * t ** 2 * x2 + t ** 3 * x3;
const y = mt ** 3 * y0 + 3 * mt ** 2 * t * y1 + 3 * mt * t ** 2 * y2 + t ** 3 * y3;
x_bounds[j] = x;
y_bounds[j] = y;
}
x_bounds[n] = x0;
y_bounds[n] = y0;
x_bounds[n + 1] = x3;
y_bounds[n + 1] = y3;
const [x_min, x_max, y_min, y_max] = minmax2(x_bounds, y_bounds);
return { x0: x_min, x1: x_max, y0: y_min, y1: y_max };
}
//# sourceMappingURL=algorithms.js.map