jsketcher/modules/geom/curves/cubicHermiteIntepolation.js
2022-08-15 23:47:20 -07:00

86 lines
2.3 KiB
JavaScript

import * as vec from 'math/vec';
import {cubicBezierDer1, cubicBezierDer2, cubicBezierPoint} from './bezierCubic';
import {closestToCurveParam} from './closestPoint';
import InvertedCurve from './invertedCurve';
export default function CubicHermiteInterpolation(points, tangents) {
const n = points.length;
const knots = new Array(n).fill().map((e,i) => i);
const beziers = [];
for (let i = 1; i < n; i++) {
const p0 = points[i - 1];
const p3 = points[i];
const tangent1 = tangents[i - 1];
const tangent2 = tangents[i];
const length = vec.length(vec.sub(p3, p0)) * 0.5;
const p1 = vec.add(p0, vec.mul(tangent1, length));
const p2 = vec.sub(p3, vec.mul(tangent2, length));
beziers.push({p0, p1, p2, p3});
}
function evalPatch(p0, p1, p2, p3, u, num) {
switch (num) {
case 0: return cubicBezierPoint(p0, p1, p2, p3, u);
case 1: return cubicBezierDer1(p0, p1, p2, p3, u);
case 2: return cubicBezierDer2(p0, p1, p2, p3, u);
default: throw 'illegal derivative order for cubic bezier curve';
}
}
function localizeParam(u) {
let pieceIndex;
if (u >= n - 1) {
pieceIndex = beziers.length - 1;
u = 1;
} else {
pieceIndex = Math.floor(u);
u = u % 1;
}
if (!beziers[pieceIndex]) {
throw 'parameter out of bounds: ' + u;
}
return [pieceIndex, u];
}
function evaluate(u, num) {
const [pieceIndex, uL] = localizeParam(u);
const {p0, p1, p2, p3} = beziers[pieceIndex];
const out = [];
for (let i = 0; i <= num; ++i) {
out.push(evalPatch(p0, p1, p2, p3, uL, i));
}
return out;
}
function point(u) {
const [pieceIndex, uL] = localizeParam(u);
const {p0, p1, p2, p3} = beziers[pieceIndex];
return cubicBezierPoint(p0, p1, p2, p3, uL);
}
function param(point) {
return closestToCurveParam(this, point);
}
function transform(tr) {
return new CubicHermiteInterpolation(
points.map(p => vec.dotVM(p, tr)),
tangents.map(p => vec.dotVM(p, tr)));
}
function invert() {
return new InvertedCurve(this);
}
Object.assign(this, {
domain: () => [0, n - 1],
degree: () => 3,
eval: evaluate,
point,
param,
transform,
knots: () => knots,
invert,
points, tangents
});
}