CyclicCubicSpline = function CyclicCubicSpline(knots, values, domain=[0,1]) {
const
n = knots.length - 1,
scale = 1 / (domain[1] - domain[0]),
t = new Float64Array(n+3),
y = new Float64Array(n+3),
s = new Float64Array(n+2),
m = new Float64Array(n+3),
d = new Float64Array(n+2),
z = new Float64Array(n+2),
coeffs = new Float64Array(4*(n+2));
y.set(values, 1);
for (let i = n; i >= 0; i--) {
t[i+1] = (knots[i] - domain[0]) * scale; }
t[0] = t[n+1] - 1; t[n+2] = t[1] + 1;
y[0] = y[n+1]; y[n+2] = y[1];
for (let i = 1; i < n+1; i++) {
s[i] = 1 / (t[i+1] - t[i]);
m[i] += (m[i+1] += 3*s[i]*s[i]*(y[i+1] - y[i])); }
s[n+1] = 1 / (t[1] + 1 - t[n+1]);
const bn = 3*s[n+1]*s[n+1]*(y[1] - y[n+1]);
m[1] += bn; m[n+1] += bn;
d[1] = 1 / (2*s[1] + s[n+1]);
m[1] = d[1] * m[1];
z[1] = d[1] * s[n+1];
for (let i = 2; i < n+1; i++) {
d[i] = 1 / (2*(s[i] + s[i-1]) - s[i-1]*s[i-1]*d[i-1]);
m[i] = d[i]*(m[i] - s[i-1]*m[i-1]);
z[i] = d[i]*(0 - s[i-1]*z[i-1]); }
d[n+1] = 1 / (s[n+1] + 2*s[n] - s[n]*s[n]*d[n]);
m[n+1] = d[n+1]*(m[n+1] - s[n]*m[n]);
z[n+1] = d[n+1]*(s[n+1] - s[n]*z[n]);
for (let i = n; i >= 1; i--) {
m[i] -= d[i]*s[i]*m[i+1];
z[i] -= d[i]*s[i]*z[i+1]; }
const zscale = (m[1] + m[n+1]) / (1 + z[1] + z[n+1]);
for (let i = 1; i <= n+1; i++) {
m[i] -= zscale * z[i]; }
s[0] = s[n+1] = 1 / (t[1] - t[0]);
m[0] = m[n+1]; m[n+2] = m[1];
for (let i = 0; i < n+2; i++) {
const h = t[i+1] - t[i];
const y0 = y[i], y1 = y[i+1], m0 = h*m[i], m1 = h*m[i+1], j = 4*i;
coeffs[j] = 0.5*(y0 + y1 + 0.125*(m0 - m1));
coeffs[j+1] = 0.03125*(18*(y1 - y0) - m0 - m1);
coeffs[j+2] = 0.0625*(m1 - m0);
coeffs[j+3] = 0.03125*(2*(y0 - y1) + m0 + m1); }
return Object.assign(
function eval_spline(u) {
u = ((u - domain[0]) * scale) % 1
let nn = t.length - 1, low = 0, half;
while ((half = (nn/2)|0) > 0) {
low += half * (t[low + half] <= u);
nn -= half; }
const i = low, j = 4*i;
u = (2*u - t[i] - t[i+1]) * s[i];
let b1 = coeffs[j+3], b2 = coeffs[j+2] + 2 * u * b1;
b1 = coeffs[j+1] + 2 * u * b2 - b1;
return coeffs[j] + u * b1 - b2; },
{ knots: t, values: y, dvalues: m, scales: s, coeffs: coeffs });
}