typescript-cubic-spline
Version:
129 lines (128 loc) • 4.01 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var Spline = /** @class */ (function () {
function Spline(xs, ys) {
this.xs = xs;
this.ys = ys;
this.ks = this.getNaturalKs(new Float64Array(this.xs.length));
}
Spline.prototype.getNaturalKs = function (ks) {
var n = this.xs.length - 1;
var A = zerosMat(n + 1, n + 2);
for (var i = 1; i < n; i++ // rows
) {
A[i][i - 1] = 1 / (this.xs[i] - this.xs[i - 1]);
A[i][i] =
2 *
(1 / (this.xs[i] - this.xs[i - 1]) + 1 / (this.xs[i + 1] - this.xs[i]));
A[i][i + 1] = 1 / (this.xs[i + 1] - this.xs[i]);
A[i][n + 1] =
3 *
((this.ys[i] - this.ys[i - 1]) /
((this.xs[i] - this.xs[i - 1]) * (this.xs[i] - this.xs[i - 1])) +
(this.ys[i + 1] - this.ys[i]) /
((this.xs[i + 1] - this.xs[i]) * (this.xs[i + 1] - this.xs[i])));
}
A[0][0] = 2 / (this.xs[1] - this.xs[0]);
A[0][1] = 1 / (this.xs[1] - this.xs[0]);
A[0][n + 1] =
(3 * (this.ys[1] - this.ys[0])) /
((this.xs[1] - this.xs[0]) * (this.xs[1] - this.xs[0]));
A[n][n - 1] = 1 / (this.xs[n] - this.xs[n - 1]);
A[n][n] = 2 / (this.xs[n] - this.xs[n - 1]);
A[n][n + 1] =
(3 * (this.ys[n] - this.ys[n - 1])) /
((this.xs[n] - this.xs[n - 1]) * (this.xs[n] - this.xs[n - 1]));
return solve(A, ks);
};
/**
* inspired by https://stackoverflow.com/a/40850313/4417327
*/
Spline.prototype.getIndexBefore = function (target) {
var low = 0;
var high = this.xs.length;
var mid = 0;
while (low < high) {
mid = Math.floor((low + high) / 2);
if (this.xs[mid] < target && mid !== low) {
low = mid;
}
else if (this.xs[mid] >= target && mid !== high) {
high = mid;
}
else {
high = low;
}
}
return low + 1;
};
Spline.prototype.at = function (x) {
var i = this.getIndexBefore(x);
var t = (x - this.xs[i - 1]) / (this.xs[i] - this.xs[i - 1]);
var a = this.ks[i - 1] * (this.xs[i] - this.xs[i - 1]) -
(this.ys[i] - this.ys[i - 1]);
var b = -this.ks[i] * (this.xs[i] - this.xs[i - 1]) +
(this.ys[i] - this.ys[i - 1]);
var q = (1 - t) * this.ys[i - 1] +
t * this.ys[i] +
t * (1 - t) * (a * (1 - t) + b * t);
return q;
};
return Spline;
}());
function solve(A, ks) {
var m = A.length;
var h = 0;
var k = 0;
while (h < m && k <= m) {
var i_max = 0;
var max = -Infinity;
for (var i = h; i < m; i++) {
var v_1 = Math.abs(A[i][k]);
if (v_1 > max) {
i_max = i;
max = v_1;
}
}
if (A[i_max][k] === 0) {
k++;
}
else {
swapRows(A, h, i_max);
for (var i = h + 1; i < m; i++) {
var f = A[i][k] / A[h][k];
A[i][k] = 0;
for (var j = k + 1; j <= m; j++)
A[i][j] -= A[h][j] * f;
}
h++;
k++;
}
}
for (var i = m - 1; i >= 0; i-- // rows = columns
) {
var v = 0;
if (A[i][i]) {
v = A[i][m] / A[i][i];
}
ks[i] = v;
for (var j = i - 1; j >= 0; j-- // rows
) {
A[j][m] -= A[j][i] * v;
A[j][i] = 0;
}
}
return ks;
}
function zerosMat(r, c) {
var A = [];
for (var i = 0; i < r; i++)
A.push(new Float64Array(c));
return A;
}
function swapRows(m, k, l) {
var p = m[k];
m[k] = m[l];
m[l] = p;
}
exports.default = Spline;