/
hermite.ts
55 lines (52 loc) · 1.7 KB
/
hermite.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import { mix, mixCubicHermite, norm, tangentCardinal } from "@thi.ng/math";
import {
comp,
extendSides,
iterator,
map,
mapcat,
normRange,
partition,
} from "@thi.ng/transducers";
import type { Vec } from "@thi.ng/vectors";
import { ARamp } from "./aramp";
export const hermite = (stops?: Vec[]) => new HermiteRamp(stops);
export class HermiteRamp extends ARamp {
at(t: number) {
const stops = this.stops;
const n = stops.length - 1;
const i = this.timeIndex(t);
if (i < 0) {
return stops[0][1];
} else if (i >= n) {
return stops[n][1];
} else {
const a = stops[Math.max(i - 1, 0)];
const [bx, by] = stops[Math.max(i, 0)];
const [cx, cy] = stops[Math.min(i + 1, n)];
const d = stops[Math.min(i + 2, n)];
const t1 = tangentCardinal(a[1], cy, 0, a[0], cx);
const t2 = tangentCardinal(by, d[1], 0, bx, d[0]);
return mixCubicHermite(by, t1, cy, t2, norm(t, bx, cx));
}
}
interpolatedPoints(res = 20) {
return iterator(
comp(
partition(4, 1),
mapcat(([a, [bx, by], [cx, cy], d]) => {
const t1 = tangentCardinal(a[1], cy, 0, a[0], cx);
const t2 = tangentCardinal(by, d[1], 0, bx, d[0]);
return map(
(t) => [
mix(bx, cx, t),
mixCubicHermite(by, t1, cy, t2, t),
],
normRange(res, false)
);
})
),
extendSides(this.stops, 1, 2)
);
}
}