bezeval = {
const {abs} = Math;
const onethird = 1/3;
const chebpt7_1 = 1/2 - Math.sqrt(3)/4;
const chebpt7_5 = 1/2 + Math.sqrt(3)/4;
const _bezeval = function _bezeval
(func, t0, t6, viewx0, viewx1, viewy0, viewy1, tolerance,
x0, x3, x6, y0, y3, y6) {
const td = (t6 - t0);
const [x1, y1] = func(t0 + td * chebpt7_1);
const [x2, y2] = func(t0 + td * 0.25);
const [x4, y4] = func(t0 + td * 0.75);
const [x5, y5] = func(t0 + td * chebpt7_5);
const xcoeffs = vals2coeffs7([x0, x1, x2, x3, x4, x5, x6]);
const ycoeffs = vals2coeffs7([y0, y1, y2, y3, y4, y5, y6]);
let [xc0, xc1, xc2, xc3, xc4, xc5, xc6] = xcoeffs;
let [yc0, yc1, yc2, yc3, yc4, yc5, yc6] = ycoeffs;
const xresid = abs(xc4) + abs(xc5) + abs(xc6);
const yresid = abs(yc4) + abs(yc5) + abs(yc6);
const xspread = abs(xc1) + abs(xc2) + abs(xc3) + xresid;
const yspread = abs(yc1) + abs(yc2) + abs(yc3) + yresid;
if ((xc0 + xspread < viewx0) || (xc0 - xspread > viewx1) ||
(yc0 + yspread < viewy0) || (yc0 - yspread > viewy1)) {
return [];
}
// to be more careful about detecting the edges of the viewport.
if ((xspread > viewx1 - viewx0) || (yspread > viewy1 - viewy0)) {
const xmax = Math.max(x0, x1, x2, x3, x4, x5, x6);
const xmin = Math.min(x0, x1, x2, x3, x4, x5, x6);
const ymax = Math.max(y0, y1, y2, y3, y4, y5, y6);
const ymin = Math.min(y0, y1, y2, y3, y4, y5, y6);
if ((xmax < viewx0) || (xmin > viewx1) ||
(ymax < viewy0) || (ymin > viewy1)) {
return [];
}
}
// If we hit the desired tolerance, return a single bezier segment:
if ((xresid < tolerance) && (yresid < tolerance)) {
// Alias degree 6 polynomial to degree 3:
xc0 += xc6, xc1 += xc5, xc2 += xc4;
yc0 += yc6, yc1 += yc5, yc2 += yc4;
// Convert from Chebyshev to Bernstein basis, and return:
const xt0 = (3*xc0 - 5*xc2) * onethird, xt1 = (15*xc3 - xc1) * onethird;
const yt0 = (3*yc0 - 5*yc2) * onethird, yt1 = (15*yc3 - yc1) * onethird;
return [x0, y0, xt0 + xt1, yt0 + yt1, xt0 - xt1, yt0 - yt1, x6, y6];
}
// If we don't hit the tolerance, recursively bisect the domain:
const left = _bezeval(
func, t0, 0.5*(t0 + t6), viewx0, viewx1, viewy0, viewy1, tolerance,
x0, x2, x3, y0, y2, y3);
const right = _bezeval(
func, 0.5*(t0 + t6), t6, viewx0, viewx1, viewy0, viewy1, tolerance,
x3, x4, x6, y3, y4, y6);
// Combine Bezier path sections from the left and right halves:
left.push(...right);
return left;
}
return function bezeval(func, domain, viewport, tolerance) {
const [t0, t6] = domain;
// Evaluate function at endpoints and midpoint:
const [x0, y0] = func(t0);
const [x3, y3] = func(0.5*(t0 + t6));
const [x6, y6] = func(t6);
const [viewx0, viewx1, viewy0, viewy1] = viewport;
return _bezeval(
func, t0, t6, viewx0, viewx1, viewy0, viewy1, tolerance,
x0, x3, x6, y0, y3, y6);
}
}