cubic-beziers-through-points
Version:
A function to fit fair (bending energy minimizing) cubic bezier curves through a set of given ordered points in the plane.
1,483 lines (1,428 loc) • 115 kB
JavaScript
/******/ // The require scope
/******/ var __webpack_require__ = {};
/******/
/************************************************************************/
/******/ /* webpack/runtime/define property getters */
/******/ (() => {
/******/ // define getter functions for harmony exports
/******/ __webpack_require__.d = (exports, definition) => {
/******/ for(var key in definition) {
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ }
/******/ }
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/hasOwnProperty shorthand */
/******/ (() => {
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ })();
/******/
/************************************************************************/
var __webpack_exports__ = {};
// EXPORTS
__webpack_require__.d(__webpack_exports__, {
r: () => (/* reexport */ cubicBeziersThroughPoints),
B6: () => (/* reexport */ cubicBeziersThroughPoints_C2),
RX: () => (/* reexport */ cubicsAndEnergyThroughPoints),
nV: () => (/* reexport */ energyThroughPoints)
});
;// ./node_modules/flo-vector2d/node/affine-transformations/translate/translate.js
// From: https://en.wikipedia.org/wiki/Affine_transformation
// "If X is the point set of an affine space, then every affine transformation
// on X can be represented as the composition of a linear transformation on X
// and a translation of X"
function translate(a, b) {
function f(b) {
return [a[0] + b[0], a[1] + b[1]];
}
// Curry the function
return b === undefined ? f : f(b);
}
//# sourceMappingURL=translate.js.map
;// ./node_modules/flo-vector2d/node/affine-transformations/linear/reverse.js
/**
* Returns the given 2-vector reversed (i.e. scaled by -1).
* @param p a vector
*/
function reverse(p) {
return [-p[0], -p[1]];
}
//# sourceMappingURL=reverse.js.map
;// ./node_modules/flo-vector2d/node/affine-transformations/linear/rotate.js
function rotate(sinθ, cosθ, p) {
function rotateByθ(p) {
return [
p[0] * cosθ - p[1] * sinθ,
p[0] * sinθ + p[1] * cosθ
];
}
// Curry the function
return p === undefined ? rotateByθ : rotateByθ(p);
}
//# sourceMappingURL=rotate.js.map
;// ./node_modules/flo-vector2d/node/affine-transformations/linear/scale.js
/**
* Returns a scaled version of the given 2-vector.
* @param p a vector
* @param c a scale factor
*/
function scale(p, c) {
return [c * p[0], c * p[1]];
}
//# sourceMappingURL=scale.js.map
;// ./node_modules/flo-vector2d/node/distance-and-length/len.js
/**
* Returns the length of the given 2-vector.
* @param p a 2d vector
*/
function len(p) {
return Math.sqrt(p[0] * p[0] + p[1] * p[1]);
}
//# sourceMappingURL=len.js.map
;// ./node_modules/flo-bezier3/node/angles-and-speeds/bezier-by-angles-and-speeds/cubic-to-angles-and-speeds.js
const { cos, sin, atan2 } = Math;
/**
* For the given bernstein cubic bezier curve basis return the angles-and-speeds
* basis coefficients, i.e.
* * α -> initial tangent angle in degrees
* * β -> terminal tangent angle in degrees
* * s0 -> inital speed
* * s1 -> terminal speed
* * L -> distance between initial and final point (cannot be 0)
* * rot -> rotation of entire curve
* * p -> initial position offset
*
* @param ps an order 3 (cubic) bezier curve given as an ordered array of its
* control point coordinates, e.g. `[[0,0], [1,1], [2,1], [2,0]]`
*/
function cubicToAnglesAndSpeeds(ps) {
// [_x1,_y1],[_x2,_y2],[_x3,_y3]
const p = ps[0];
// move ps to origin
ps = ps.map(translate(reverse(p)));
const [x, y] = [ps[3][0], ps[3][1]];
const rot = atan2(y, x);
ps = ps.map(rotate(sin(-rot), cos(-rot)));
const L = ps[3][0];
ps = ps.map(p => scale(p, 1 / L));
// TS -> tangent vector at `t === 0`
const TS = ps[1];
// TE -> tangent vector at `t === 1`
const TE = [1 - ps[2][0], -ps[2][1]];
// const h2 = sqrt(x1**2 + y1**2);
const α = atan2(TS[1], TS[0]);
const β = atan2(TE[1], TE[0]);
const s0 = 3 * len(TS);
const s1 = 3 * len(TE);
return { α, β, s0, s1, L, rot, p };
}
//# sourceMappingURL=cubic-to-angles-and-speeds.js.map
;// ./node_modules/flo-gauss-quadrature/node/index.js
// TODO A future improvement can be to use the Gauss–Kronrod rules
// to estimate the error and thus choose a number of constants based
// on the error. Maybe not.
// TODO In future, the constants can be calculated and cached so we can
// choose any value for the order.
// TODO - to limit rounding error do pairwise addition of terms
// TODO order abscissas
// TODO - auto calc abscissas and weights (on first call to function only)
/**
* Numerically integrates the given function using the Gaussian Quadrature
* method.
*
* See https://en.wikipedia.org/wiki/Gaussian_quadrature
* See http://pomax.github.io/bezierinfo/#arclength
* @param f The univariate function to be integrated
* @param interval The integration interval
* @param order Can be 2, 4, 8, or 16. Higher values give more accurate results
* but is slower - defaults to 16.
*/
function gaussQuadrature(f, interval, order = 16) {
if (interval[0] === interval[1]) {
return 0;
}
const { weights, abscissas } = GAUSS_CONSTANTS[order];
const [a, b] = interval;
let result = 0;
const m1 = (b - a) / 2;
const m2 = (b + a) / 2;
for (let i = 0; i <= order - 1; i++) {
result += weights[i] * f(m1 * abscissas[i] + m2);
}
return m1 * result;
}
// The Gaussian Legendre Quadrature method constants.
const GAUSS_CONSTANTS = {
2: {
weights: [1, 1],
abscissas: [-0.5773502691896257, 0.5773502691896257]
},
4: {
weights: [
0.6521451548625461, 0.6521451548625461,
0.3478548451374538, 0.3478548451374538
],
abscissas: [
-0.3399810435848563, 0.3399810435848563,
-0.8611363115940526, 0.8611363115940526
]
},
8: {
weights: [
0.3626837833783620, 0.3626837833783620,
0.3137066458778873, 0.3137066458778873,
0.2223810344533745, 0.2223810344533745,
0.1012285362903763, 0.1012285362903763
],
abscissas: [
-0.1834346424956498, 0.1834346424956498,
-0.5255324099163290, 0.5255324099163290,
-0.7966664774136267, 0.7966664774136267,
-0.9602898564975363, 0.9602898564975363
]
},
// Taken from http://keisan.casio.com/exec/system/1330940731
16: {
weights: [
0.0271524594117540948518,
0.062253523938647892863,
0.0951585116824927848099,
0.1246289712555338720525,
0.1495959888165767320815,
0.169156519395002538189,
0.182603415044923588867,
0.189450610455068496285,
0.1894506104550684962854,
0.182603415044923588867,
0.1691565193950025381893,
0.149595988816576732081,
0.124628971255533872053,
0.095158511682492784809,
0.062253523938647892863,
0.027152459411754094852
],
abscissas: [
-0.989400934991649932596,
-0.944575023073232576078,
-0.86563120238783174388,
-0.7554044083550030338951,
-0.6178762444026437484467,
-0.4580167776572273863424,
-0.28160355077925891323,
-0.0950125098376374401853,
0.0950125098376374401853,
0.28160355077925891323,
0.4580167776572273863424,
0.617876244402643748447,
0.755404408355003033895,
0.8656312023878317438805,
0.944575023073232576078,
0.989400934991649932596
],
},
64: {
weights: [
0.048690957009139724,
0.048690957009139724,
0.04857546744150343,
0.04857546744150343,
0.048344762234802954,
0.048344762234802954,
0.04799938859645831,
0.04799938859645831,
0.04754016571483031,
0.04754016571483031,
0.04696818281621002,
0.04696818281621002,
0.046284796581314416,
0.046284796581314416,
0.04549162792741814,
0.04549162792741814,
0.044590558163756566,
0.044590558163756566,
0.04358372452932345,
0.04358372452932345,
0.04247351512365359,
0.04247351512365359,
0.04126256324262353,
0.04126256324262353,
0.03995374113272034,
0.03995374113272034,
0.038550153178615626,
0.038550153178615626,
0.03705512854024005,
0.03705512854024005,
0.035472213256882386,
0.035472213256882386,
0.033805161837141606,
0.033805161837141606,
0.03205792835485155,
0.03205792835485155,
0.030234657072402478,
0.030234657072402478,
0.028339672614259483,
0.028339672614259483,
0.02637746971505466,
0.02637746971505466,
0.024352702568710874,
0.024352702568710874,
0.022270173808383253,
0.022270173808383253,
0.02013482315353021,
0.02013482315353021,
0.017951715775697343,
0.017951715775697343,
0.015726030476024718,
0.015726030476024718,
0.013463047896718643,
0.013463047896718643,
0.011168139460131128,
0.011168139460131128,
0.008846759826363947,
0.008846759826363947,
0.006504457968978363,
0.006504457968978363,
0.004147033260562468,
0.004147033260562468,
0.001783280721696433,
0.001783280721696433
],
abscissas: [
-0.024350292663424433,
0.024350292663424433,
-0.07299312178779904,
0.07299312178779904,
-0.12146281929612056,
0.12146281929612056,
-0.16964442042399283,
0.16964442042399283,
-0.21742364374000708,
0.21742364374000708,
-0.2646871622087674,
0.2646871622087674,
-0.31132287199021097,
0.31132287199021097,
-0.3572201583376681,
0.3572201583376681,
-0.4022701579639916,
0.4022701579639916,
-0.4463660172534641,
0.4463660172534641,
-0.48940314570705296,
0.48940314570705296,
-0.5312794640198946,
0.5312794640198946,
-0.571895646202634,
0.571895646202634,
-0.6111553551723933,
0.6111553551723933,
-0.6489654712546573,
0.6489654712546573,
-0.6852363130542333,
0.6852363130542333,
-0.7198818501716109,
0.7198818501716109,
-0.7528199072605319,
0.7528199072605319,
-0.7839723589433414,
0.7839723589433414,
-0.8132653151227975,
0.8132653151227975,
-0.8406292962525803,
0.8406292962525803,
-0.8659993981540928,
0.8659993981540928,
-0.8893154459951141,
0.8893154459951141,
-0.9105221370785028,
0.9105221370785028,
-0.9295691721319396,
0.9295691721319396,
-0.9464113748584028,
0.9464113748584028,
-0.9610087996520538,
0.9610087996520538,
-0.973326827789911,
0.973326827789911,
-0.983336253884626,
0.983336253884626,
-0.9910133714767443,
0.9910133714767443,
-0.9963401167719553,
0.9963401167719553,
-0.9993050417357722,
0.9993050417357722
]
}
};
//# sourceMappingURL=index.js.map
;// ./node_modules/double-double/node/basic/two-diff.js
/**
* Returns the exact result of subtracting b from a.
*
* @param a minuend - a double-double precision floating point number
* @param b subtrahend - a double-double precision floating point number
*/
function twoDiff(a, b) {
const x = a - b;
const bvirt = a - x;
const y = (a - (x + bvirt)) + (bvirt - b);
return [y, x];
}
//# sourceMappingURL=two-diff.js.map
;// ./node_modules/double-double/node/basic/two-sum.js
/**
* Returns the exact result of adding two doubles.
*
* * the resulting array is the reverse of the standard twoSum in the literature.
*
* Theorem 7 (Knuth): Let a and b be p-bit floating-point numbers. Then the
* following algorithm will produce a nonoverlapping expansion x + y such that
* a + b = x + y, where x is an approximation to a + b and y is the roundoff
* error in the calculation of x.
*
* See https://people.eecs.berkeley.edu/~jrs/papers/robustr.pdf
*/
function two_sum_twoSum(a, b) {
const x = a + b;
const bv = x - a;
return [(a - (x - bv)) + (b - bv), x];
}
// inlined
//const R = a + b; const _ = R - a; const r = (a - (R - _)) + (b - _); return [r,R]
//# sourceMappingURL=two-sum.js.map
;// ./node_modules/big-float-ts/node/double-expansion/fast-expansion-sum.js
// import { eCompress } from "./e-compress.js";
// We *have* to do the below❗ The assignee is a getter❗ The assigned is a pure function❗
// const compress = eCompress;
/**
* Returns the result of adding two expansions.
*
* Theorem 13: Let e = sum_(i=1)^m(e_i) and f = sum_(i=1)^n(f_i) be strongly
* nonoverlapping expansions of m and n p-bit components, respectively, where
* p >= 4. Suppose that the components of both e and f are sorted in order of
* increasing magnitude, except that any of the e_i or f_i may be zero. On a
* machine whose arithmetic uses the round-to-even rule, the following algorithm
* will produce a strongly nonoverlapping expansion h such that
* sum_(i=1)^(m+n)(e_i + f_i) = e + f, where the components of h are also in
* order of increasing magnitude, except that any of the h_i may be zero.
*
* See https://people.eecs.berkeley.edu/~jrs/papers/robustr.pdf
*/
function fastExpansionSum(e, f) {
//const g = merge(e,f);
// inlined (above line)
const lenE = e.length;
const lenF = f.length;
let i = 0;
let j = 0;
const g = [];
while (i < lenE && j < lenF) {
if (e[i] === 0) {
i++;
continue;
}
if (f[j] === 0) {
j++;
continue;
}
if (Math.abs(e[i]) <= Math.abs(f[j])) {
g.push(e[i]);
i++;
}
else {
g.push(f[j]);
j++;
}
}
while (i < lenE) {
g.push(e[i]);
i++;
}
while (j < lenF) {
g.push(f[j]);
j++;
}
if (g.length === 0) {
return [0];
}
// end inlined
const len = g.length;
if (len === 1) {
return g;
}
//const h: number[] = new Array(len);
const h = [];
//const q: number;
//[h[0], q] = fastTwoSum(g[1], g[0]);
// inlined (above line)
const a = g[1];
const b = g[0];
let q = a + b;
//h[0] = b - (q - a);
const hh = b - (q - a);
if (hh !== 0) {
h.push(hh);
}
//let j = 0;
j = 0;
for (let i = 2; i < len; i++) {
//[h[i-1], q] = twoSum(q, g[i]);
// inlined (above line)
const b = g[i];
const R = q + b;
const _ = R - q;
//h[i-1] = (q - (R - _)) + (b - _);
const hh = (q - (R - _)) + (b - _);
if (hh !== 0) {
h.push(hh);
}
q = R;
}
//h[len-1] = q;
//h.push(q);
if (q !== 0 || h.length === 0) {
h.push(q);
}
//return compress(h);
return h;
}
/**
* Returns the result of merging an expansion e and f into a single expansion,
* in order of nondecreasing magnitude (possibly with interspersed zeros).
* (This function is zero-eliminating)
*
* * see [Shewchuk](https://people.eecs.berkeley.edu/~jrs/papers/robustr.pdf)
*
* @param e a floating point expansion
* @param f another floating point expansion
*/
function merge(e, f) {
const lenE = e.length;
const lenF = f.length;
let i = 0;
let j = 0;
const merged = [];
while (i < lenE && j < lenF) {
if (e[i] === 0) {
i++;
continue;
}
if (f[j] === 0) {
j++;
continue;
}
if (Math.abs(e[i]) <= Math.abs(f[j])) {
merged.push(e[i]);
i++;
}
else {
merged.push(f[j]);
j++;
}
}
while (i < lenE) {
merged.push(e[i]);
i++;
}
while (j < lenF) {
merged.push(f[j]);
j++;
}
if (merged.length === 0) {
return [0];
}
return merged;
}
//# sourceMappingURL=fast-expansion-sum.js.map
;// ./node_modules/big-float-ts/node/double-expansion/e-negative-of.js
/**
* Returns the negative of the given floating point expansion.
* * see [Shewchuk](https://people.eecs.berkeley.edu/~jrs/papers/robustr.pdf)
*
* @param e a floating point expansion
*/
function eNegativeOf(e) {
const m = e.length;
const h = new Array(m);
for (let i = 0; i < m; i++) {
h[i] = -e[i];
}
return h;
}
//# sourceMappingURL=e-negative-of.js.map
;// ./node_modules/big-float-ts/node/double-expansion/e-diff.js
// We *have* to do the below❗ The assignee is a getter❗ The assigned is a pure function❗
const negativeOf = eNegativeOf;
const add = fastExpansionSum;
/**
* Returns the difference between two floating point expansions, i.e. e - f.
*
* * see [Shewchuk](https://people.eecs.berkeley.edu/~jrs/papers/robustr.pdf)
*
* @param e a floating point expansion
* @param f another floating point expansion
*/
function eDiff(e, f) {
const g = negativeOf(f);
return add(e, g);
}
//# sourceMappingURL=e-diff.js.map
;// ./node_modules/big-float-ts/node/double-expansion/scale-expansion.js
const f = 134217729; // 2**27 + 1;
// We *have* to do the below❗ The assignee is a getter❗ The assigned is a pure function❗
const tp = (/* unused pure expression or super */ null && (twoProduct));
const ts = (/* unused pure expression or super */ null && (twoSum));
const fts = (/* unused pure expression or super */ null && (fastTwoSum));
const compress = (/* unused pure expression or super */ null && (eCompress));
/**
* Returns the result of multiplying an expansion by a double.
*
* * see [Shewchuk](https://people.eecs.berkeley.edu/~jrs/papers/robustr.pdf)
*
* Theorem 19 (Shwechuk): Let e = sum_(i=1)^m(e_i) be a nonoverlapping expansion
* of m p-bit components, and const b be a p-bit value where p >= 4. Suppose that
* the components of e are sorted in order of increasing magnitude, except that
* any of the e_i may be zero. Then the following algorithm will produce a
* nonoverlapping expansion h such that h = sum_(i=1)^(2m)(h_i) = be, where the
* components of h are also in order of increasing magnitude, except that any of
* the h_i may be zero. Furthermore, if e is nonadjacent and round-to-even
* tiebreaking is used, then h is non-adjacent.
*
* @param e a double floating point expansion
* @param b a double
*/
function scaleExpansion(e, b) {
const m = e.length;
//const h: number[] = new Array(2*m);
let q_;
//[h[0], q] = tp(e[0], b);
// inlined (above line)
const a = e[0];
let q = a * b;
const c = f * a;
const ah = c - (c - a);
const al = a - ah;
const d = f * b;
const bh = d - (d - b);
const bl = b - bh;
const h = [];
//h[0] = (al*bl) - ((q - (ah*bh)) - (al*bh) - (ah*bl));
const hh = (al * bl) - ((q - (ah * bh)) - (al * bh) - (ah * bl));
if (hh !== 0) {
h.push(hh);
}
for (let i = 1; i < m; i++) {
//const [t, T] = tp(e[i], b);
// inlined (above line)
const a = e[i];
const T = a * b;
const c = f * a;
const ah = c - (c - a);
const al = a - ah;
const d = f * b;
const bh = d - (d - b);
const bl = b - bh;
const t = (al * bl) - ((T - (ah * bh)) - (al * bh) - (ah * bl));
//[h[2*i-1], q_] = ts(q, t);
// inlined (above line)
const x = q + t;
const bv = x - q;
//h[2*i-1] = (q - (x - bv)) + (t - bv);
//h.push((q - (x - bv)) + (t - bv));
const hh = (q - (x - bv)) + (t - bv);
if (hh !== 0) {
h.push(hh);
}
q_ = x;
//[h[2*i], q] = fts(T, q_);
// inlined (above line)
const xx = T + q_;
//h[2*i] = q_ - (xx - T);
//h.push(q_ - (xx - T));
const hhh = q_ - (xx - T);
if (hhh !== 0) {
h.push(hhh);
}
q = xx;
}
//h[2*m - 1] = q;
//h.push(q);
if (q !== 0 || h.length === 0) {
h.push(q);
}
//return eCompress(h);
return h;
}
/**
* Returns the result of multiplying an expansion by a double.
*
* * see [Shewchuk](https://people.eecs.berkeley.edu/~jrs/papers/robustr.pdf)
*
* Theorem 19 (Shwechuk): Let e = sum_(i=1)^m(e_i) be a nonoverlapping expansion
* of m p-bit components, and const b be a p-bit value where p >= 4. Suppose that
* the components of e are sorted in order of increasing magnitude, except that
* any of the e_i may be zero. Then the following algorithm will produce a
* nonoverlapping expansion h such that h = sum_(i=1)^(2m)(h_i) = be, where the
* components of h are also in order of increasing magnitude, except that any of
* the h_i may be zero. Furthermore, if e is nonadjacent and round-to-even
* tiebreaking is used, then h is non-adjacent.
*
* @param e a double floating point expansion
* @param b a double
*/
function scaleExpansion2(b, e) {
const m = e.length;
//const h: number[] = new Array(2*m);
let q_;
//[h[0], q] = tp(e[0], b);
// inlined (above line)
const a = e[0];
let q = a * b;
const c = f * a;
const ah = c - (c - a);
const al = a - ah;
const d = f * b;
const bh = d - (d - b);
const bl = b - bh;
const h = [];
//h[0] = (al*bl) - ((q - (ah*bh)) - (al*bh) - (ah*bl));
const hh = (al * bl) - ((q - (ah * bh)) - (al * bh) - (ah * bl));
if (hh !== 0) {
h.push(hh);
}
for (let i = 1; i < m; i++) {
//const [t, T] = tp(e[i], b);
// inlined (above line)
const a = e[i];
const T = a * b;
const c = f * a;
const ah = c - (c - a);
const al = a - ah;
const d = f * b;
const bh = d - (d - b);
const bl = b - bh;
const t = (al * bl) - ((T - (ah * bh)) - (al * bh) - (ah * bl));
//[h[2*i-1], q_] = ts(q, t);
// inlined (above line)
const x = q + t;
const bv = x - q;
//h[2*i-1] = (q - (x - bv)) + (t - bv);
//h.push((q - (x - bv)) + (t - bv));
const hh = (q - (x - bv)) + (t - bv);
if (hh !== 0) {
h.push(hh);
}
q_ = x;
//[h[2*i], q] = fts(T, q_);
// inlined (above line)
const xx = T + q_;
//h[2*i] = q_ - (xx - T);
//h.push(q_ - (xx - T));
const hhh = q_ - (xx - T);
if (hhh !== 0) {
h.push(hhh);
}
q = xx;
}
//h[2*m - 1] = q;
//h.push(q);
if (q !== 0 || h.length === 0) {
h.push(q);
}
//return eCompress(h);
return h;
}
//# sourceMappingURL=scale-expansion.js.map
;// ./node_modules/big-float-ts/node/double-expansion/expansion-product.js
// We *have* to do the below❗ The assignee is a getter❗ The assigned is a pure function❗
const multByDouble = scaleExpansion;
const expansion_product_add = fastExpansionSum;
const expansion_product_compress = (/* unused pure expression or super */ null && (eCompress));
/**
* Returns the product of two double floating point expansions.
*
* * see [Shewchuk](https://people.eecs.berkeley.edu/~jrs/papers/robustr.pdf)
*
* As per Shewchuk in the above paper: "To find the product of two expansions
* e and f, use SCALE-EXPANSION (with zero elimination) to form the expansions
* ef_1, ef_2, ..., then sum these using a distillation tree."
*
* A distillation tree used with fastExpansionSum will give O(k*log k) vs O(k^2)
* operations.
*
* Implemented naively and not as described by Shewchuk (i.e. the algorithm
* takes O(k^2) operations).
* @param e a double floating point expansion
* @param f another double floating point expansion
*/
function expansionProduct(e, f) {
let sum = [0];
for (let i = 0; i < e.length; i++) {
sum = expansion_product_add(sum, multByDouble(f, e[i]));
}
//return compress(sum);
return sum;
}
//# sourceMappingURL=expansion-product.js.map
;// ./node_modules/big-float-ts/node/double-expansion/grow-expansion.js
// We *have* to do the below❗ The assignee is a getter❗ The assigned is a pure function❗
const grow_expansion_compress = (/* unused pure expression or super */ null && (eCompress));
/**
* Returns the result of adding a double to an expansion.
*
* Let e be a nonoverlapping expansion of m p-bit components, and let b be a
* p-bit value where p >= 3. Suppose that the components e_1, ..., e_m are
* sorted in order of *increasing* magnitude, except that any of the ei may be
* zero.
* Then the following algorithm will produce a nonoverlapping expansion such
* that h = sum_i(h_i) = e + b, where the components h_1, ..., h_(m+1) are also
* in order of increasing magnitude, except that any of the h_i may be zero.
* Furthermore, if e is nonadjacent and round-to-even tiebreaking is used, then
* h is nonadjacent.
* See https://people.eecs.berkeley.edu/~jrs/papers/robustr.pdf
* @param e A floating point expansion
* @param b Another floating point expansion
*/
function growExpansion(e, b) {
const m = e.length;
let q = b;
//const h: number[] = new Array(m+1);
const h = [];
//let j = 0;
for (let i = 0; i < m; i++) {
// Note the use of twoSum and not fastTwoSum.
//[h[i], q] = ts(q, e[i]);
const ee = e[i];
const x = q + ee;
const bv = x - q;
const hh = (q - (x - bv)) + (ee - bv);
if (hh !== 0) {
h.push(hh);
}
q = x;
}
//h[j] = q;
if (q !== 0 || h.length === 0) {
h.push(q);
}
//return compress(h);
return h;
}
//# sourceMappingURL=grow-expansion.js.map
;// ./node_modules/big-float-ts/node/double-expansion/e-sign.js
/**
* Returns the sign of the given expansion such that a negative value means a
* negative sign and a positive value means a positive sign, 0 meaning 0 of
* course.
*
* * see [Shewchuk](https://people.eecs.berkeley.edu/~jrs/papers/robustr.pdf)
*
* From Shewchuk: "A nonoverlapping expansion is desirable because it is easy to
* determine its sign (take the sign of the largest component) ... "
*
* @param e A floating point expansion with zeroes eliminated.
*/
function eSign(e) {
return e[e.length - 1];
}
//# sourceMappingURL=e-sign.js.map
;// ./node_modules/big-float-ts/node/double-expansion/e-compare.js
/**
* Returns 0 if a === b, a +tive value if a > b or a negative value if a < b.
*
* * see [Shewchuk](https://people.eecs.berkeley.edu/~jrs/papers/robustr.pdf)
*
* "The easiest way to compare two expansions is to subtract one from the other,
* and test the sign of the result. An expansion’s sign can be easily tested
* because of the nonoverlapping property; simply check the sign of the
* expansion's most significant nonzero component..."
*
* @param a a floating point expansion
* @param b another floating point expansion
*/
function eCompare(a, b) {
return eSign(eDiff(a, b));
}
//# sourceMappingURL=e-compare.js.map
;// ./node_modules/flo-bezier3/node/error-analysis/error-analysis.js
const u = Number.EPSILON / 2;
const uu = u * u;
/** @internal */
function γ(n) {
const nu = n * u;
return nu / (1 - nu);
}
/** @internal */
function γγ(n) {
const nuu = n * uu;
return nuu / (1 - nuu);
}
γ(1); //=> 1.1102230246251568e-16
γγ(3); //=> 3.697785493223493e-32
//# sourceMappingURL=error-analysis.js.map
;// ./node_modules/flo-bezier3/node/global-properties/classification/is-really-point.js
/**
* Returns `true` if the given bezier curve has all control points coincident,
* `false` otherwise.
*
* @param ps an order 0,1,2 or 3 bezier curve given as an array of its control
* points, e.g. `[[0,0],[1,1],[2,1],[2,0]]`
*
* @doc
*/
function isReallyPoint(ps) {
const x = ps[0][0];
const y = ps[0][1];
for (let i = 1; i < ps.length; i++) {
if (x !== ps[i][0] || y !== ps[i][1]) {
return false;
}
}
return true;
}
//# sourceMappingURL=is-really-point.js.map
;// ./node_modules/big-float-ts/node/basic/two-sum.js
/**
* Returns the exact result of adding two doubles.
*
* * the resulting array is the reverse of the standard twoSum in the literature.
*
* Theorem 7 (Knuth): Let a and b be p-bit floating-point numbers. Then the
* following algorithm will produce a nonoverlapping expansion x + y such that
* a + b = x + y, where x is an approximation to a + b and y is the roundoff
* error in the calculation of x.
*
* See https://people.eecs.berkeley.edu/~jrs/papers/robustr.pdf
*/
function basic_two_sum_twoSum(a, b) {
const x = a + b;
const bv = x - a;
return [(a - (x - bv)) + (b - bv), x];
}
// inlined
//const R = a + b; const _ = R - a; const r = (a - (R - _)) + (b - _); return [r,R]
//# sourceMappingURL=two-sum.js.map
;// ./node_modules/flo-bezier3/node/global-properties/classification/is-quad-really-line.js
// We *have* to do the below❗ The assignee is a getter❗ The assigned is a pure function❗
const ediff = eDiff;
const esign = eSign;
const is_quad_really_line_ts = basic_two_sum_twoSum;
const { abs } = Math;
/**
* Returns `true` if the given quadratic bezier curve is really a linear curve
* (or a point), i.e. if all control points collinear *and* it can be converted
* to an order 1 bezier curve (a line) such that the
* same `(x,y)` point is returned for the same `t` value, `false` otherwise.
*
* * the required condition is met if: `x0 + x2 = 2*x1` and `y0 + y2 = 2*y1`
* * **exact**: not susceptible to floating point round-off
*
* @param ps a quadratic bezier curve given as an array of its control
* points, e.g. `[[1,2],[5,6],[7,8]]`
*
* @doc mdx
*/
function isQuadReallyLine(ps) {
const [[x0, y0], [x1, y1], [x2, y2]] = ps;
//if (x0 + x2 === 2*x1) && (y0 + y2 === 2*y1)
// Calculate an approximation of the above with error bounds and use it as
// a fast filter.
const q = x0 + x2;
const _q_ = abs(q); // the absolute error bound in q (after multipliciation by `u`)
const w = q - 2 * x1;
const w_ = _q_ + abs(w); // the absolute error bound in w
// if w cannot possibly be zero, i.e. if the error is smaller than the value
if (abs(w) - w_ > 0) {
// fast filter passed
return false;
}
const r = y0 + y2;
const _r_ = abs(r); // the absolute error bound in r (after multipliciation by `u`)
const z = r - 2 * y1;
const z_ = _r_ + abs(z); // the absolute error bound in w
// if the error is smaller than the value
if (abs(z) - z_ > 0) {
// fast filter passed
return false;
}
// unable to filter - go slow and exact
return (esign(ediff(is_quad_really_line_ts(x0, x2), [2 * x1])) === 0 &&
esign(ediff(is_quad_really_line_ts(y0, y2), [2 * y1])) === 0);
}
//# sourceMappingURL=is-quad-really-line.js.map
;// ./node_modules/big-float-ts/node/basic/two-product.js
const two_product_f = 134217729; // 2**27 + 1;
/**
* Returns the exact result of multiplying two doubles.
*
* * the resulting array is the reverse of the standard twoSum in the literature.
*
* Theorem 18 (Shewchuk): Let a and b be p-bit floating-point numbers, where
* p >= 6. Then the following algorithm will produce a nonoverlapping expansion
* x + y such that ab = x + y, where x is an approximation to ab and y
* represents the roundoff error in the calculation of x. Furthermore, if
* round-to-even tiebreaking is used, x and y are non-adjacent.
*
* See https://people.eecs.berkeley.edu/~jrs/papers/robustr.pdf
* @param a A double
* @param b Another double
*/
function two_product_twoProduct(a, b) {
const x = a * b;
//const [ah, al] = split(a);
const c = two_product_f * a;
const ah = c - (c - a);
const al = a - ah;
//const [bh, bl] = split(b);
const d = two_product_f * b;
const bh = d - (d - b);
const bl = b - bh;
const y = (al * bl) - ((x - (ah * bh)) - (al * bh) - (ah * bl));
//const err1 = x - (ah * bh);
//const err2 = err1 - (al * bh);
//const err3 = err2 - (ah * bl);
//const y = (al * bl) - err3;
return [y, x];
}
//# sourceMappingURL=two-product.js.map
;// ./node_modules/flo-bezier3/node/global-properties/classification/is-cubic-really-quad.js
// We *have* to do the below❗ The assignee is a getter❗ The assigned is a pure function❗
const is_cubic_really_quad_tp = two_product_twoProduct;
const fes = fastExpansionSum;
const is_cubic_really_quad_esign = eSign;
const is_cubic_really_quad_ediff = eDiff;
const is_cubic_really_quad_u = Number.EPSILON / 2;
const is_cubic_really_quad_abs = Math.abs;
/**
* Returns `true` if the given cubic bezier curve is really a quadratic (or
* lower order) curve in disguise, i.e. it can be represent by a quadratic
* bezier curve, `false` otherwise.
*
* * **exact**: not susceptible to floating point round-off
*
* @param ps an order 0,1,2 or 3 bezier curve given as an array of its control
* points, e.g. `[[1,2],[3,4],[5,6],[7,8]]`
*
* @doc mdx
*/
function isCubicReallyQuad(ps) {
const [[x0, y0], [x1, y1], [x2, y2], [x3, y3]] = ps;
// The line below is unrolled (uses a toHybridQuadratic condition (points same?))
//if ((x3 + 3*x1) - (x0 + 3*x2) === 0 &&
// (y3 + 3*y1) - (y0 + 3*y2) === 0) {
// Calculate an approximation of the above with error bounds and use it as
// a fast filter.
const u1 = 3 * x1;
const u1_ = is_cubic_really_quad_abs(3 * x1); // the absolute error in u1
const u2 = x3 + u1;
const u2_ = u1_ + is_cubic_really_quad_abs(u2); // the absolute error in u2
const v1 = 3 * x2;
const v1_ = is_cubic_really_quad_abs(3 * x2); // the absolute error in v1
const v2 = x0 + v1;
const v2_ = v1_ + is_cubic_really_quad_abs(v2); // the absolute error in v2
const w = u2 - v2;
const w_ = u2_ + v2_ + is_cubic_really_quad_abs(w); // the absolute error in w
// if w cannot possibly be zero, i.e. if the error is smaller than the value
if (is_cubic_really_quad_abs(w) - is_cubic_really_quad_u * w_ > 0) {
// fast filter 1 passed
return false;
}
const q1 = 3 * y1;
const q1_ = is_cubic_really_quad_abs(3 * y1); // the absolute error in q1
const q2 = y3 + q1;
const q2_ = q1_ + is_cubic_really_quad_abs(q2); // the absolute error in q2
const r1 = 3 * y2;
const r1_ = is_cubic_really_quad_abs(3 * y2); // the absolute error in r1
const r2 = y0 + r1;
const r2_ = r1_ + is_cubic_really_quad_abs(r2); // the absolute error in r2
const s = q2 - r2;
const s_ = q2_ + r2_ + is_cubic_really_quad_abs(s); // the absolute error in s
if (is_cubic_really_quad_abs(s) - is_cubic_really_quad_u * s_ > 0) {
// fast filter 2 passed
return false;
}
// unable to filter - go slow and exact
return (is_cubic_really_quad_esign(is_cubic_really_quad_ediff(fes([x3], is_cubic_really_quad_tp(3, x1)), fes([x0], is_cubic_really_quad_tp(3, x2)))) === 0 &&
is_cubic_really_quad_esign(is_cubic_really_quad_ediff(fes([y3], is_cubic_really_quad_tp(3, y1)), fes([y0], is_cubic_really_quad_tp(3, y2)))) === 0);
}
//# sourceMappingURL=is-cubic-really-quad.js.map
;// ./node_modules/big-float-ts/node/double-expansion/e-estimate.js
/**
* Returns the result of the given floating point expansion rounded to a double
* floating point number.
*
* The result is within 1 ulps of the actual value, e.g. imagine the worst case
* situation where we add (in 4dot4) 1111.1000 + 0.000011111111... The result
* will be 1111.1000 whereas as the correct result should be 1111.1001 and we
* thus lost 1 ulp of accuracy. It does not matter that the expansion contain
* several floats since none is overlapping.
*
* See Shewchuk https://people.eecs.berkeley.edu/~jrs/papers/robustr.pdf
*
* @param e a floating point expansion
*/
function eEstimate(e) {
let Q = e[0];
for (let i = 1; i < e.length; i++) {
Q += e[i];
}
return Q;
}
//# sourceMappingURL=e-estimate.js.map
;// ./node_modules/big-float-ts/node/basic/two-diff.js
/**
* Returns the exact result of subtracting b from a (as a floating point
* expansion).
* @param a
* @param b
*/
function two_diff_twoDiff(a, b) {
const x = a - b;
const bvirt = a - x;
const y = (a - (x + bvirt)) + (bvirt - b);
return [y, x];
}
//# sourceMappingURL=two-diff.js.map
;// ./node_modules/big-float-ts/node/double-expansion/e-compress.js
/**
* Returns the result of compressing the given floating point expansion.
*
* * primarily for internal library use
*
* * see [Shewchuk](https://people.eecs.berkeley.edu/~jrs/papers/robustr.pdf)
*
* Theorem 23 (Shewchuck): Let e = sum_(i=1)^m(e_i) be a nonoverlapping
* expansion of m p-bit components, where m >= 3. Suppose that the components of
* e are sorted in order of increasing magnitude, except that any of the e_i may
* be zero. Then the following algorithm will produce a nonoverlapping expansion
* (nonadjacent if round-to even tiebreaking is used) such that
* h = sum_(i=1)^n(h_i) = e, where the components h_i are in order of increasing
* magnitude. If h != 0, none of the h_i will be zero. Furthermore, the largest
* component h_n approximates h with an error smaller than ulp(h_n).
*/
function e_compress_eCompress(e) {
//return e;
const e_ = e.slice();
const m = e_.length;
if (m === 1) {
return e_;
}
let Q = e_[m - 1];
let bottom = m;
for (let i = m - 2; i >= 0; --i) {
const a = Q;
const b = e_[i];
Q = a + b;
const bv = Q - a;
const q = b - bv;
if (q) {
e_[--bottom] = Q;
Q = q;
}
}
let top = 0;
for (let i = bottom; i < m; ++i) {
const a = e_[i];
const b = Q;
Q = a + b;
const bv = Q - a;
const q = b - bv;
if (q) {
e_[top++] = q;
}
}
e_[top++] = Q;
e_.length = top;
return e_;
}
//# sourceMappingURL=e-compress.js.map
;// ./node_modules/big-float-ts/node/geometric-primitives/orient2d.js
const ccwerrboundA = 3.330669073875472e-16;
const ccwerrboundB = 2.220446049250315e-16;
const ccwerrboundC = 1.109335647967049e-31;
const resulterrbound = 3.330669073875471e-16;
/**
* * Ported from [Shewchuk](http://docs.ros.org/kinetic/api/asr_approx_mvbb/html/Predicates_8cpp_source.html)
* * see also https://people.eecs.berkeley.edu/~jrs/papers/robustr.pdf
*
* * Adaptive exact 2d orientation test.
*
* * Robust.
*
* Return a positive value if the points pa, pb, and pc occur in
* counterclockwise order; a negative value if they occur in clockwise order;
* and zero if they are collinear. The result is also a rough approximation of
* twice the signed area of the triangle defined by the three points.
*
* The result returned is the determinant of a matrix. This determinant is
* computed adaptively, in the sense that exact arithmetic is used only to the
* degree it is needed to ensure that the returned value has the correct sign.
* Hence, orient2d() is usually quite fast, but will run more slowly when the
* input points are collinear or nearly so.
*/
function orient2d(A, B, C) {
const detleft = (A[0] - C[0]) * (B[1] - C[1]);
const detright = (A[1] - C[1]) * (B[0] - C[0]);
const det = detleft - detright;
let detsum;
if (detleft > 0) {
if (detright <= 0) {
// Anti-clockwise
return det;
}
else {
detsum = detleft + detright;
}
}
else if (detleft < 0) {
if (detright >= 0) {
// Clockwise
return det;
}
else {
detsum = -detleft - detright;
}
}
else {
// Anti-clockwise, clockwise or straight
return det;
}
if (Math.abs(det) >= ccwerrboundA * detsum) {
// Anti-clockwise or clockwise
return det;
}
return orient2dAdapt(A, B, C, detsum);
}
function orient2dAdapt(A, B, C, detsum) {
const acx = A[0] - C[0];
const bcx = B[0] - C[0];
const acy = A[1] - C[1];
const bcy = B[1] - C[1];
const b = eDiff(two_product_twoProduct(acx, bcy), two_product_twoProduct(acy, bcx));
let det = eEstimate(b);
if (Math.abs(det) >= ccwerrboundB * detsum) {
// Anti-clockwise or clockwise
return det;
}
const acxtail = two_diff_twoDiff(A[0], C[0])[0];
const bcxtail = two_diff_twoDiff(B[0], C[0])[0];
const acytail = two_diff_twoDiff(A[1], C[1])[0];
const bcytail = two_diff_twoDiff(B[1], C[1])[0];
if (acxtail === 0 && acytail === 0 &&
bcxtail === 0 && bcytail === 0) {
// Straight
return det;
}
const errbound = ccwerrboundC * detsum + resulterrbound * Math.abs(det);
det += (acx * bcytail + bcy * acxtail) - (acy * bcxtail + bcx * acytail);
if (Math.abs(det) >= errbound) {
return det;
}
const a = eDiff(two_product_twoProduct(acxtail, bcy), two_product_twoProduct(acytail, bcx));
const c = fastExpansionSum(b, a);
const d = eDiff(two_product_twoProduct(acx, bcytail), two_product_twoProduct(acy, bcxtail));
const e = fastExpansionSum(c, d);
const f = eDiff(two_product_twoProduct(acxtail, bcytail), two_product_twoProduct(acytail, bcxtail));
let D = fastExpansionSum(e, f);
D = e_compress_eCompress(D);
return D[D.length - 1];
}
//# sourceMappingURL=orient2d.js.map
;// ./node_modules/flo-bezier3/node/global-properties/classification/is-collinear.js
// We *have* to do the below❗ The assignee is a getter❗ The assigned is a pure function❗
const is_collinear_orient2d = orient2d;
/**
* Returns `true` if the given bezier curve has all control points collinear,
* `false` otherwise.
*
* * if you need to know whether a given bezier curve can be converted to an
* order 1 bezier curve (a line) such that the same `(x,y)` point is returned
* for the same `t` value then use e.g. [[isQuadReallyLine]] instead.
*
* * **exact** not susceptible to floating point round-off
*
* @param ps an order 0,1,2 or 3 bezier curve given as an array of its control
* points, e.g. `[[1,2],[3,4],[5,6],[7,8]]`
*
* @doc mdx
*/
function isCollinear(ps) {
if (ps.length === 4) {
// Cubic bezier
return (is_collinear_orient2d(ps[0], ps[1], ps[2]) === 0 &&
is_collinear_orient2d(ps[1], ps[2], ps[3]) === 0 &&
// The below check is necessary for if ps[1] === ps[2]
is_collinear_orient2d(ps[0], ps[2], ps[3]) === 0);
}
if (ps.length === 3) {
// Quadratic bezier
return is_collinear_orient2d(ps[0], ps[1], ps[2]) === 0;
}
if (ps.length <= 2) {
// Line (or point)
return true;
}
throw new Error('The given bezier curve must be of order <= 3.');
}
/**
* Returns `true` if the given bezier curve has all control points the
* same `y` value (possibly self-overlapping), `false` otherwise.
*
* @param ps An order 0, 1, 2 or 3 bezier curve.
*
* @doc
*/
function isHorizontal(ps) {
const y = ps[0][1];
for (let i = 1; i < ps.length; i++) {
if (ps[i][1] !== y) {
return false;
}
}
return true;
}
/**
* Returns `true` if the given bezier curve has all control points the
* same `x` value (possibly self-overlapping), `false` otherwise.
*
* @param ps An order 0, 1, 2 or 3 bezier curve.
*
* @doc
*/
function isVertical(ps) {
const x = ps[0][0];
for (let i = 1; i < ps.length; i++) {
if (ps[i][0] !== x) {
return false;
}
}
return true;
}
//# sourceMappingURL=is-collinear.js.map
;// ./node_modules/flo-bezier3/node/global-properties/classification/is-cubic-really-line.js
// We *have* to do the below to improve performance with bundlers❗ The assignee is a getter❗ The assigned is a pure function❗
const sce = scaleExpansion;
const is_cubic_really_line_ediff = eDiff;
const is_cubic_really_line_ts = basic_two_sum_twoSum;
const is_cubic_really_line_esign = eSign;
/**
* Returns `true` if the given bezier curve has all control points collinear
* *and* it can be converted to an order 1 bezier curve (a line) such that the
* same `(x,y)` point is returned for the same `t` value, `false` otherwise.
*
* * **exact**: not susceptible to floating point round-off
*
* @param ps a cubic bezier curve given as an array of its control
* points, e.g. `[[1,2],[3,4],[5,6],[7,8]]`
*
* @doc mdx
*/
function isCubicReallyLine(ps) {
// note: if cubic is really a quad then
// x3 + 3*(x1 - x2) === x0 &&
// y3 + 3*(y1 - y2) === y0
if (!isCollinear(ps)) {
return false;
}
const [p0, p1, p2, p3] = ps;
const [x0, y0] = p0;
const [x1, y1] = p1;
const [x2, y2] = p2;
const [x3, y3] = p3;
// convert middle two control points to single quad point
// [
// (3*(x1 + x2) - (x0 + x3)) / 4,
// (3*(y1 + y2) - (y0 + y3)) / 4
// ]
const qx1 = is_cubic_really_line_ediff(sce(is_cubic_really_line_ts(x1 / 4, x2 / 4), 3), is_cubic_really_line_ts(x0 / 4, x3 / 4));
const qy1 = is_cubic_really_line_ediff(sce(is_cubic_really_line_ts(y1 / 4, y2 / 4), 3), is_cubic_really_line_ts(y0 / 4, y3 / 4));
// is quad really line:
// if (x0 + x2 === 2*x1) && (y0 + y2 === 2*y1) OR
// if ((x0 + x2)/2 === x1) && ((y0 + y2)/2 === y1)
return (is_cubic_really_line_esign(is_cubic_really_line_ediff(is_cubic_really_line_ts(x0 / 2, x3 / 2), qx1)) === 0 &&
is_cubic_really_line_esign(is_cubic_really_line_ediff(is_cubic_really_line_ts(y0 / 2, y3 / 2), qy1)) === 0);
}
//# sourceMappingURL=is-cubic-really-line.js.map
;// ./node_modules/flo-bezier3/node/to-power-basis/to-power-basis/double/to-power-basis-with-running-error.js
const to_power_basis_with_running_error_abs = Math.abs;
/**
* Returns the power basis representation of a bezier curve of order cubic or
* less including a coefficient-wise absolute error bound.
*
* * intermediate calculations are done in double precision
* * the error bound need to be multiplied by `γ(1) === u/(1-u)`
* where `u = Number.EPSILON/2` before use
* * returns the resulting power basis x and y coordinate polynomials from
* highest power to lowest, e.g. if `x(t) = at^2 + bt + c`
* and `y(t) = dt^2 + et + f` then the result is returned
* as `[[a,b,c],[d,e,f]]`
*
* @param ps an order 0,1,2 or 3 bezier curve given by an ordered array of its
* control points, e.g. `[[0,0],[1,1],[2,1],[2,0]]`
*
* @doc
*/
function toPowerBasisWithRunningError(ps) {
if (ps.length === 4) {
return toPowerBasis3WithRunningError(ps);
}
if (ps.length === 3) {
return toPowerBasis2WithRunningError(ps);
}
if (ps.length === 2) {
return toPowerBasis1WithRunningError(ps);
}
if (ps.length === 1) {
return toPowerBasis0WithRunningError(ps);
}
throw new Error('The given bezier curve must be of order <= 3.');
}
/** @internal */
function toPowerBasis3WithRunningError(ps) {
const [[x0, y0], [x1, y1], [x2, y2], [x3, y3]] = ps;
// ----------------------------
// xx3 = (x3 - x0) + 3*(x1 - x2)
// ----------------------------
const xa = x3 - x0;
const _xa_ = to_power_basis_with_running_error_abs(xa);
const xb = x1 - x2;
const _xb_ = to_power_basis_with_running_error_abs(xb);
const xc = 3 * xb;
const xc_ = 6 * _xb_; // === 3*_xb_ + 3*abs(xc)
const xx3 = xa + xc;
const xx3_ = _xa_ + xc_ + to_power_basis_with_running_error_abs(xx3);
// ----------------------------
// xx2 = 3*((x2 + x0) - 2*x1)
// ----------------------------
const xd = x2 + x0;
const _xd_ = to_power_basis_with_running_error_abs(xd);
const xe = xd - 2 * x1;
const _xe_ = _xd_ + to_power_basis_with_running_error_abs(xe);
const xx2 = 3 * xe;
const xx2_ = 6 * _xe_; // 3*_xe_ + abs(xx2)
// ----------------------------
// xx1 = 3*(x1 - x0)
// ----------------------------
const xg = x1 - x0;
const _xg_ = to_power_basis_with_running_error_abs(xg);
const xx1 = 3 * xg;
const xx1_ = 6 * _xg_; // 3*_xg_ + abs(3*xg)
// ------------------------------
// yy3 = (y3 - y0) + 3*(y1 - y2)
// ------------------------------
const ya = y3 - y0;
const _ya_ = to_power_basis_with_running_error_abs(ya);
const yb = y1 - y2;
const _yb_ = to_power_basis_with_running_error_abs(yb);
const yc = 3 * yb;
const yc_ = 6 * _yb_; // === 3*_yb_ + 3*abs(yc)
const yy3 = ya + yc;
const yy3_ = _ya_ + yc_ + to_power_basis_with_running_error_abs(yy3);
// ----------------------------
// yy2 = 3*((y2 + y0) - 2*y1)
// ----------------------------
const yd = y2 + y0;
const _yd_ = to_power_basis_w