-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmath.ts
86 lines (69 loc) · 2.23 KB
/
math.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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
export function clamp(x: number, lowerLimit: number, upperLimit: number): number {
if (x < lowerLimit) {
return lowerLimit;
} else if (x > upperLimit) {
return upperLimit;
}
return x;
}
export function scale(
t: number,
x1: number,
x2: number,
y1: number = 0,
y2: number = 1,
) {
const m = (y2 - y1) / (x2 - x1);
return (t - x1) * m + y1;
}
export function lerp(t: number, from: number, to: number) {
return (1 - t) * from + t * to;
}
export function logerp(t: number, from: number, to: number) {
from = from === 0 ? 1e-9 : from;
const tt = from * Math.pow(to / from, t);
return tt;
}
export function deCasteljau(t: number, points: number[]) {
const n = points.length - 1;
const b = [...points];
for (let i = 1; i <= n; i++) {
for (let j = 0; j <= n - i; j++) {
b[j] = lerp(t, b[j], b[j + 1]);
}
}
return b[0];
}
export function cubicBezier(t: number, x1: number, y1: number, x2: number, y2: number) {
return [deCasteljau(t, [0, x1, x2, 1]), deCasteljau(t, [0, y1, y2, 1])];
}
export function interpBezier(t: number, points: number[][]) {
const x = points.map((xy) => xy[0]);
const y = points.map((xy) => xy[1]);
return [deCasteljau(t, x), deCasteljau(t, y)];
}
export function cubicBezierToSVG(x1: number, y1: number, x2: number, y2: number) {
let path = `M${0} ${0}`;
let points = `
<circle cx="${x1}" cy="${y1}"/>
<circle cx="${0}" cy="${0}"/>
<circle cx="${x2}" cy="${y2}"/>
<circle cx="${1}" cy="${1}"/>`;
for (let t = 0; t <= 1; t += 0.001) {
const [x, y] = cubicBezier(t, x1, y1, x2, y2);
path += ` L${x} ${y}`;
}
return `<path d="${path}"/>`;
}
export function cubicBezierToString(x1: number, y1: number, x2: number, y2: number) {
const HTML_SPACE = "\u00A0";
const formatNumber = (n: number) => {
let s = n.toFixed(2);
// // replace trailing 0's with  :
// s = s.replace(/\.0+$/g, HTML_SPACE);
// remove trailing . with another  :
// s = s.replace(/\.$/g, HTML_SPACE);
return s;
};
return `cubic-bezier(${formatNumber(x1)}, ${formatNumber(y1)}, ${formatNumber(x2)}, ${formatNumber(y2)})`;
}