curvy 0.3.2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +21 -0
- package/dist/curve/cubic2d.d.mts +27 -0
- package/dist/curve/cubic2d.d.ts +27 -0
- package/dist/curve/cubic2d.mjs +85 -0
- package/dist/curve/linear2d.d.mts +27 -0
- package/dist/curve/linear2d.d.ts +27 -0
- package/dist/curve/linear2d.mjs +46 -0
- package/dist/curve/quadratic2d.d.mts +27 -0
- package/dist/curve/quadratic2d.d.ts +27 -0
- package/dist/curve/quadratic2d.mjs +74 -0
- package/dist/interval.d.mts +58 -0
- package/dist/interval.d.ts +58 -0
- package/dist/interval.mjs +88 -0
- package/dist/matrix/matrix2x2.d.mts +49 -0
- package/dist/matrix/matrix2x2.d.ts +49 -0
- package/dist/matrix/matrix2x2.mjs +23 -0
- package/dist/matrix/matrix3x3.d.mts +63 -0
- package/dist/matrix/matrix3x3.d.ts +63 -0
- package/dist/matrix/matrix3x3.mjs +26 -0
- package/dist/matrix/matrix4x4.d.mts +72 -0
- package/dist/matrix/matrix4x4.d.ts +72 -0
- package/dist/matrix/matrix4x4.mjs +214 -0
- package/dist/path/cubic2d.d.mts +29 -0
- package/dist/path/cubic2d.d.ts +29 -0
- package/dist/path/cubic2d.mjs +60 -0
- package/dist/path/linear2d.d.mts +29 -0
- package/dist/path/linear2d.d.ts +29 -0
- package/dist/path/linear2d.mjs +54 -0
- package/dist/path/quadratic2d.d.mts +29 -0
- package/dist/path/quadratic2d.d.ts +29 -0
- package/dist/path/quadratic2d.mjs +60 -0
- package/dist/polynomial/cubic.d.mts +7 -0
- package/dist/polynomial/cubic.d.ts +7 -0
- package/dist/polynomial/cubic.mjs +139 -0
- package/dist/polynomial/linear.d.mts +7 -0
- package/dist/polynomial/linear.d.ts +7 -0
- package/dist/polynomial/linear.mjs +19 -0
- package/dist/polynomial/quadratic.d.mts +7 -0
- package/dist/polynomial/quadratic.d.ts +7 -0
- package/dist/polynomial/quadratic.mjs +22 -0
- package/dist/shared/curvy.BAW_cKLu.mjs +123 -0
- package/dist/shared/curvy.BN-oFBsc.d.mts +26 -0
- package/dist/shared/curvy.BN-oFBsc.d.ts +26 -0
- package/dist/shared/curvy.Bxxwly94.d.mts +144 -0
- package/dist/shared/curvy.C-sUk7ux.mjs +119 -0
- package/dist/shared/curvy.CLzGuqek.mjs +124 -0
- package/dist/shared/curvy.CO0Wclt0.d.ts +144 -0
- package/dist/shared/curvy.CT38g_II.d.mts +22 -0
- package/dist/shared/curvy.CT38g_II.d.ts +22 -0
- package/dist/shared/curvy.ChkqgKuv.mjs +119 -0
- package/dist/shared/curvy.Cty3LrOR.mjs +70 -0
- package/dist/shared/curvy.D7bhnwZy.mjs +52 -0
- package/dist/shared/curvy.DOLqYbKE.mjs +48 -0
- package/dist/shared/curvy.DgRsieUW.mjs +76 -0
- package/dist/shared/curvy.DmVFTi0N.mjs +34 -0
- package/dist/splines/bezier2d.d.mts +35 -0
- package/dist/splines/bezier2d.d.ts +35 -0
- package/dist/splines/bezier2d.mjs +122 -0
- package/dist/vector/vector2.d.mts +37 -0
- package/dist/vector/vector2.d.ts +37 -0
- package/dist/vector/vector2.mjs +16 -0
- package/dist/vector/vector3.d.mts +38 -0
- package/dist/vector/vector3.d.ts +38 -0
- package/dist/vector/vector3.mjs +16 -0
- package/dist/vector/vector4.d.mts +39 -0
- package/dist/vector/vector4.d.ts +39 -0
- package/dist/vector/vector4.mjs +16 -0
- package/package.json +81 -38
- package/dist/axis.cjs +0 -325
- package/dist/axis.d.cts +0 -20
- package/dist/axis.d.mts +0 -20
- package/dist/axis.d.ts +0 -20
- package/dist/axis.mjs +0 -314
- package/dist/convert.cjs +0 -74
- package/dist/convert.d.cts +0 -6
- package/dist/convert.d.mts +0 -6
- package/dist/convert.d.ts +0 -6
- package/dist/convert.mjs +0 -68
- package/dist/curve.cjs +0 -194
- package/dist/curve.d.cts +0 -18
- package/dist/curve.d.mts +0 -18
- package/dist/curve.d.ts +0 -18
- package/dist/curve.mjs +0 -184
- package/dist/shared/curvy.262f6070.cjs +0 -16
- package/dist/shared/curvy.9cd8b44c.mjs +0 -13
- package/dist/shared/curvy.df73166c.d.cts +0 -38
- package/dist/shared/curvy.df73166c.d.mts +0 -38
- package/dist/shared/curvy.df73166c.d.ts +0 -38
- package/dist/splines.cjs +0 -150
- package/dist/splines.d.cts +0 -27
- package/dist/splines.d.mts +0 -27
- package/dist/splines.d.ts +0 -27
- package/dist/splines.mjs +0 -138
package/dist/curve.cjs
DELETED
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const invariant = require('tiny-invariant');
|
|
4
|
-
const axis = require('./axis.cjs');
|
|
5
|
-
const util = require('./shared/curvy.262f6070.cjs');
|
|
6
|
-
const splines = require('./splines.cjs');
|
|
7
|
-
|
|
8
|
-
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
|
9
|
-
|
|
10
|
-
const invariant__default = /*#__PURE__*/_interopDefaultCompat(invariant);
|
|
11
|
-
|
|
12
|
-
function createNode(interval) {
|
|
13
|
-
return {
|
|
14
|
-
interval,
|
|
15
|
-
left: null,
|
|
16
|
-
right: null
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
function takeCenterInterval(boundaries) {
|
|
20
|
-
const mid = Math.floor((boundaries.length - 1) / 2);
|
|
21
|
-
const left = mid > 0 ? boundaries.slice(0, mid + 1) : null;
|
|
22
|
-
const right = mid + 1 < boundaries.length - 1 ? boundaries.slice(mid + 1) : null;
|
|
23
|
-
return {
|
|
24
|
-
center: [boundaries[mid], boundaries[mid + 1]],
|
|
25
|
-
left,
|
|
26
|
-
right
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
function createIntervalTree(boundaries) {
|
|
30
|
-
const container = createNode([0, 0]);
|
|
31
|
-
const branches = [{ parent: container, direction: "left", boundaries }];
|
|
32
|
-
for (const branch of branches) {
|
|
33
|
-
const { parent, direction, boundaries: boundaries2 } = branch;
|
|
34
|
-
const { center, left, right } = takeCenterInterval(boundaries2);
|
|
35
|
-
const node = createNode(center);
|
|
36
|
-
if (direction === "left") {
|
|
37
|
-
parent.left = node;
|
|
38
|
-
} else {
|
|
39
|
-
parent.right = node;
|
|
40
|
-
}
|
|
41
|
-
if (left !== null) {
|
|
42
|
-
branches.push({ parent: node, direction: "left", boundaries: left });
|
|
43
|
-
}
|
|
44
|
-
if (right !== null) {
|
|
45
|
-
branches.push({ parent: node, direction: "right", boundaries: right });
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
const root = container.left;
|
|
49
|
-
function searchNode(node, query) {
|
|
50
|
-
if (node.interval[0] <= query && node.interval[1] >= query) {
|
|
51
|
-
return node.interval;
|
|
52
|
-
}
|
|
53
|
-
if (node.interval[0] > query && node.left) {
|
|
54
|
-
return searchNode(node.left, query);
|
|
55
|
-
}
|
|
56
|
-
if (node.interval[1] < query && node.right) {
|
|
57
|
-
return searchNode(node.right, query);
|
|
58
|
-
}
|
|
59
|
-
return null;
|
|
60
|
-
}
|
|
61
|
-
function search(query) {
|
|
62
|
-
return searchNode(root, query);
|
|
63
|
-
}
|
|
64
|
-
return {
|
|
65
|
-
root,
|
|
66
|
-
search
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function distance(a, b) {
|
|
71
|
-
const deltas = [];
|
|
72
|
-
for (const key of Object.keys(a)) {
|
|
73
|
-
deltas.push(a[key] - b[key]);
|
|
74
|
-
}
|
|
75
|
-
return Math.hypot(...deltas);
|
|
76
|
-
}
|
|
77
|
-
function createLengthLookup(positionAt) {
|
|
78
|
-
const count = 512;
|
|
79
|
-
const orderedSamples = Array.from({ length: count + 1 }, (_, i) => i / count);
|
|
80
|
-
const lengthLookup = /* @__PURE__ */ new Map();
|
|
81
|
-
let lastPoint = positionAt(0);
|
|
82
|
-
let length = 0;
|
|
83
|
-
lengthLookup.set(0, 0);
|
|
84
|
-
for (const t of orderedSamples.slice(1)) {
|
|
85
|
-
const point = positionAt(t);
|
|
86
|
-
length = length + distance(lastPoint, point);
|
|
87
|
-
lengthLookup.set(length, t);
|
|
88
|
-
lastPoint = point;
|
|
89
|
-
}
|
|
90
|
-
const totalLength = length;
|
|
91
|
-
const { search } = createIntervalTree(Array.from(lengthLookup.keys()));
|
|
92
|
-
return (normalized) => {
|
|
93
|
-
invariant__default(normalized >= 0 && normalized <= 1, "Length out of bounds");
|
|
94
|
-
const length2 = normalized * totalLength;
|
|
95
|
-
const result = search(length2);
|
|
96
|
-
invariant__default(result, "Length not found");
|
|
97
|
-
return util.remap(
|
|
98
|
-
length2,
|
|
99
|
-
result[0],
|
|
100
|
-
result[1],
|
|
101
|
-
lengthLookup.get(result[0]),
|
|
102
|
-
lengthLookup.get(result[1])
|
|
103
|
-
);
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
function createCurve(points, spline) {
|
|
108
|
-
const axisKeys = Object.keys(points[0]);
|
|
109
|
-
const axisPoints = {};
|
|
110
|
-
for (const key of axisKeys) {
|
|
111
|
-
axisPoints[key] = [];
|
|
112
|
-
}
|
|
113
|
-
for (const point of points) {
|
|
114
|
-
for (const key of axisKeys) {
|
|
115
|
-
invariant__default(key in point, `Point ${point} is missing axis "${key}"`);
|
|
116
|
-
axisPoints[key].push(point[key]);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
const axes = {};
|
|
120
|
-
for (const key of axisKeys) {
|
|
121
|
-
axes[key] = axis.createCurveAxis(spline.chunkCoefficients(axisPoints[key]));
|
|
122
|
-
}
|
|
123
|
-
const solveT = (t, precision = 12) => {
|
|
124
|
-
const rounded = util.round(t);
|
|
125
|
-
invariant__default(
|
|
126
|
-
rounded >= 0 && rounded <= 1,
|
|
127
|
-
`t must be between 0 and 1, got ${rounded}`
|
|
128
|
-
);
|
|
129
|
-
const position = {};
|
|
130
|
-
for (const key of axisKeys) {
|
|
131
|
-
position[key] = util.round(axes[key].solvePosition(rounded), precision);
|
|
132
|
-
}
|
|
133
|
-
return position;
|
|
134
|
-
};
|
|
135
|
-
const lengthLookup = createLengthLookup(solveT);
|
|
136
|
-
const positionAt = (input, normalize = 1, precision = 12) => {
|
|
137
|
-
invariant__default(
|
|
138
|
-
input >= 0 && input <= 1,
|
|
139
|
-
`Input must be between 0 and 1, got ${input}`
|
|
140
|
-
);
|
|
141
|
-
let t = input;
|
|
142
|
-
if (normalize > 0) {
|
|
143
|
-
const denormalizedT = lengthLookup(input);
|
|
144
|
-
if (normalize === 1) {
|
|
145
|
-
t = denormalizedT;
|
|
146
|
-
} else {
|
|
147
|
-
t = (1 - normalize) * input + normalize * denormalizedT;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
return solveT(t, precision);
|
|
151
|
-
};
|
|
152
|
-
const solveWhere = (axis, position, precision = 12) => {
|
|
153
|
-
const curveAxis = axes[axis];
|
|
154
|
-
invariant__default(curveAxis.monotonicity !== "none", "Axis is not monotonic");
|
|
155
|
-
const t = curveAxis.solveT(position, curveAxis.domain)[0];
|
|
156
|
-
invariant__default(
|
|
157
|
-
typeof t === "number",
|
|
158
|
-
`Could not solve for ${axis} = ${position}`
|
|
159
|
-
);
|
|
160
|
-
const result = { [axis]: util.round(position, precision) };
|
|
161
|
-
for (const key of axisKeys) {
|
|
162
|
-
if (key !== axis) {
|
|
163
|
-
result[key] = util.round(axes[key].solvePosition(t), precision);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
return result;
|
|
167
|
-
};
|
|
168
|
-
return {
|
|
169
|
-
axes,
|
|
170
|
-
positionAt,
|
|
171
|
-
solveWhere
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
function createBasisCurve(points, triplicateEndpoints = true) {
|
|
175
|
-
return createCurve(points, splines.splines.basis(triplicateEndpoints));
|
|
176
|
-
}
|
|
177
|
-
function createBezierCurve(points) {
|
|
178
|
-
return createCurve(points, splines.splines.bezier);
|
|
179
|
-
}
|
|
180
|
-
function createCardinalCurve(points, tension = 0.5, duplicateEndpoints = true) {
|
|
181
|
-
return createCurve(points, splines.splines.cardinal(tension, duplicateEndpoints));
|
|
182
|
-
}
|
|
183
|
-
function createCatmullRomCurve(points, duplicateEndpoints = true) {
|
|
184
|
-
return createCurve(points, splines.splines.catmullRom(duplicateEndpoints));
|
|
185
|
-
}
|
|
186
|
-
function createHermiteCurve(points) {
|
|
187
|
-
return createCurve(points, splines.splines.hermite);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
exports.createBasisCurve = createBasisCurve;
|
|
191
|
-
exports.createBezierCurve = createBezierCurve;
|
|
192
|
-
exports.createCardinalCurve = createCardinalCurve;
|
|
193
|
-
exports.createCatmullRomCurve = createCatmullRomCurve;
|
|
194
|
-
exports.createHermiteCurve = createHermiteCurve;
|
package/dist/curve.d.cts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { CurveAxis } from './axis.cjs';
|
|
2
|
-
import './shared/curvy.df73166c.cjs';
|
|
3
|
-
|
|
4
|
-
type Point<Axis extends string | number> = Readonly<{
|
|
5
|
-
[A in Axis]: number;
|
|
6
|
-
}>;
|
|
7
|
-
type Curve<Axis extends string | number> = {
|
|
8
|
-
readonly axes: Readonly<Record<Axis, CurveAxis>>;
|
|
9
|
-
readonly positionAt: (input: number, normalize?: number, precision?: number) => Point<Axis>;
|
|
10
|
-
readonly solveWhere: <SolveAxis extends Axis>(axis: SolveAxis, position: number, precision?: number) => Point<Axis>;
|
|
11
|
-
};
|
|
12
|
-
declare function createBasisCurve<Axis extends string | number>(points: ReadonlyArray<Point<Axis>>, triplicateEndpoints?: boolean): Curve<Axis>;
|
|
13
|
-
declare function createBezierCurve<Axis extends string | number>(points: ReadonlyArray<Point<Axis>>): Curve<Axis>;
|
|
14
|
-
declare function createCardinalCurve<Axis extends string | number>(points: ReadonlyArray<Point<Axis>>, tension?: number, duplicateEndpoints?: boolean): Curve<Axis>;
|
|
15
|
-
declare function createCatmullRomCurve<Axis extends string | number>(points: ReadonlyArray<Point<Axis>>, duplicateEndpoints?: boolean): Curve<Axis>;
|
|
16
|
-
declare function createHermiteCurve<Axis extends string | number>(points: ReadonlyArray<Point<Axis>>): Curve<Axis>;
|
|
17
|
-
|
|
18
|
-
export { type Curve, type Point, createBasisCurve, createBezierCurve, createCardinalCurve, createCatmullRomCurve, createHermiteCurve };
|
package/dist/curve.d.mts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { CurveAxis } from './axis.mjs';
|
|
2
|
-
import './shared/curvy.df73166c.mjs';
|
|
3
|
-
|
|
4
|
-
type Point<Axis extends string | number> = Readonly<{
|
|
5
|
-
[A in Axis]: number;
|
|
6
|
-
}>;
|
|
7
|
-
type Curve<Axis extends string | number> = {
|
|
8
|
-
readonly axes: Readonly<Record<Axis, CurveAxis>>;
|
|
9
|
-
readonly positionAt: (input: number, normalize?: number, precision?: number) => Point<Axis>;
|
|
10
|
-
readonly solveWhere: <SolveAxis extends Axis>(axis: SolveAxis, position: number, precision?: number) => Point<Axis>;
|
|
11
|
-
};
|
|
12
|
-
declare function createBasisCurve<Axis extends string | number>(points: ReadonlyArray<Point<Axis>>, triplicateEndpoints?: boolean): Curve<Axis>;
|
|
13
|
-
declare function createBezierCurve<Axis extends string | number>(points: ReadonlyArray<Point<Axis>>): Curve<Axis>;
|
|
14
|
-
declare function createCardinalCurve<Axis extends string | number>(points: ReadonlyArray<Point<Axis>>, tension?: number, duplicateEndpoints?: boolean): Curve<Axis>;
|
|
15
|
-
declare function createCatmullRomCurve<Axis extends string | number>(points: ReadonlyArray<Point<Axis>>, duplicateEndpoints?: boolean): Curve<Axis>;
|
|
16
|
-
declare function createHermiteCurve<Axis extends string | number>(points: ReadonlyArray<Point<Axis>>): Curve<Axis>;
|
|
17
|
-
|
|
18
|
-
export { type Curve, type Point, createBasisCurve, createBezierCurve, createCardinalCurve, createCatmullRomCurve, createHermiteCurve };
|
package/dist/curve.d.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { CurveAxis } from './axis.js';
|
|
2
|
-
import './shared/curvy.df73166c.js';
|
|
3
|
-
|
|
4
|
-
type Point<Axis extends string | number> = Readonly<{
|
|
5
|
-
[A in Axis]: number;
|
|
6
|
-
}>;
|
|
7
|
-
type Curve<Axis extends string | number> = {
|
|
8
|
-
readonly axes: Readonly<Record<Axis, CurveAxis>>;
|
|
9
|
-
readonly positionAt: (input: number, normalize?: number, precision?: number) => Point<Axis>;
|
|
10
|
-
readonly solveWhere: <SolveAxis extends Axis>(axis: SolveAxis, position: number, precision?: number) => Point<Axis>;
|
|
11
|
-
};
|
|
12
|
-
declare function createBasisCurve<Axis extends string | number>(points: ReadonlyArray<Point<Axis>>, triplicateEndpoints?: boolean): Curve<Axis>;
|
|
13
|
-
declare function createBezierCurve<Axis extends string | number>(points: ReadonlyArray<Point<Axis>>): Curve<Axis>;
|
|
14
|
-
declare function createCardinalCurve<Axis extends string | number>(points: ReadonlyArray<Point<Axis>>, tension?: number, duplicateEndpoints?: boolean): Curve<Axis>;
|
|
15
|
-
declare function createCatmullRomCurve<Axis extends string | number>(points: ReadonlyArray<Point<Axis>>, duplicateEndpoints?: boolean): Curve<Axis>;
|
|
16
|
-
declare function createHermiteCurve<Axis extends string | number>(points: ReadonlyArray<Point<Axis>>): Curve<Axis>;
|
|
17
|
-
|
|
18
|
-
export { type Curve, type Point, createBasisCurve, createBezierCurve, createCardinalCurve, createCatmullRomCurve, createHermiteCurve };
|
package/dist/curve.mjs
DELETED
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
import invariant from 'tiny-invariant';
|
|
2
|
-
import { createCurveAxis } from './axis.mjs';
|
|
3
|
-
import { r as remap, a as round } from './shared/curvy.9cd8b44c.mjs';
|
|
4
|
-
import { splines } from './splines.mjs';
|
|
5
|
-
|
|
6
|
-
function createNode(interval) {
|
|
7
|
-
return {
|
|
8
|
-
interval,
|
|
9
|
-
left: null,
|
|
10
|
-
right: null
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
function takeCenterInterval(boundaries) {
|
|
14
|
-
const mid = Math.floor((boundaries.length - 1) / 2);
|
|
15
|
-
const left = mid > 0 ? boundaries.slice(0, mid + 1) : null;
|
|
16
|
-
const right = mid + 1 < boundaries.length - 1 ? boundaries.slice(mid + 1) : null;
|
|
17
|
-
return {
|
|
18
|
-
center: [boundaries[mid], boundaries[mid + 1]],
|
|
19
|
-
left,
|
|
20
|
-
right
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
function createIntervalTree(boundaries) {
|
|
24
|
-
const container = createNode([0, 0]);
|
|
25
|
-
const branches = [{ parent: container, direction: "left", boundaries }];
|
|
26
|
-
for (const branch of branches) {
|
|
27
|
-
const { parent, direction, boundaries: boundaries2 } = branch;
|
|
28
|
-
const { center, left, right } = takeCenterInterval(boundaries2);
|
|
29
|
-
const node = createNode(center);
|
|
30
|
-
if (direction === "left") {
|
|
31
|
-
parent.left = node;
|
|
32
|
-
} else {
|
|
33
|
-
parent.right = node;
|
|
34
|
-
}
|
|
35
|
-
if (left !== null) {
|
|
36
|
-
branches.push({ parent: node, direction: "left", boundaries: left });
|
|
37
|
-
}
|
|
38
|
-
if (right !== null) {
|
|
39
|
-
branches.push({ parent: node, direction: "right", boundaries: right });
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
const root = container.left;
|
|
43
|
-
function searchNode(node, query) {
|
|
44
|
-
if (node.interval[0] <= query && node.interval[1] >= query) {
|
|
45
|
-
return node.interval;
|
|
46
|
-
}
|
|
47
|
-
if (node.interval[0] > query && node.left) {
|
|
48
|
-
return searchNode(node.left, query);
|
|
49
|
-
}
|
|
50
|
-
if (node.interval[1] < query && node.right) {
|
|
51
|
-
return searchNode(node.right, query);
|
|
52
|
-
}
|
|
53
|
-
return null;
|
|
54
|
-
}
|
|
55
|
-
function search(query) {
|
|
56
|
-
return searchNode(root, query);
|
|
57
|
-
}
|
|
58
|
-
return {
|
|
59
|
-
root,
|
|
60
|
-
search
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function distance(a, b) {
|
|
65
|
-
const deltas = [];
|
|
66
|
-
for (const key of Object.keys(a)) {
|
|
67
|
-
deltas.push(a[key] - b[key]);
|
|
68
|
-
}
|
|
69
|
-
return Math.hypot(...deltas);
|
|
70
|
-
}
|
|
71
|
-
function createLengthLookup(positionAt) {
|
|
72
|
-
const count = 512;
|
|
73
|
-
const orderedSamples = Array.from({ length: count + 1 }, (_, i) => i / count);
|
|
74
|
-
const lengthLookup = /* @__PURE__ */ new Map();
|
|
75
|
-
let lastPoint = positionAt(0);
|
|
76
|
-
let length = 0;
|
|
77
|
-
lengthLookup.set(0, 0);
|
|
78
|
-
for (const t of orderedSamples.slice(1)) {
|
|
79
|
-
const point = positionAt(t);
|
|
80
|
-
length = length + distance(lastPoint, point);
|
|
81
|
-
lengthLookup.set(length, t);
|
|
82
|
-
lastPoint = point;
|
|
83
|
-
}
|
|
84
|
-
const totalLength = length;
|
|
85
|
-
const { search } = createIntervalTree(Array.from(lengthLookup.keys()));
|
|
86
|
-
return (normalized) => {
|
|
87
|
-
invariant(normalized >= 0 && normalized <= 1, "Length out of bounds");
|
|
88
|
-
const length2 = normalized * totalLength;
|
|
89
|
-
const result = search(length2);
|
|
90
|
-
invariant(result, "Length not found");
|
|
91
|
-
return remap(
|
|
92
|
-
length2,
|
|
93
|
-
result[0],
|
|
94
|
-
result[1],
|
|
95
|
-
lengthLookup.get(result[0]),
|
|
96
|
-
lengthLookup.get(result[1])
|
|
97
|
-
);
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function createCurve(points, spline) {
|
|
102
|
-
const axisKeys = Object.keys(points[0]);
|
|
103
|
-
const axisPoints = {};
|
|
104
|
-
for (const key of axisKeys) {
|
|
105
|
-
axisPoints[key] = [];
|
|
106
|
-
}
|
|
107
|
-
for (const point of points) {
|
|
108
|
-
for (const key of axisKeys) {
|
|
109
|
-
invariant(key in point, `Point ${point} is missing axis "${key}"`);
|
|
110
|
-
axisPoints[key].push(point[key]);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
const axes = {};
|
|
114
|
-
for (const key of axisKeys) {
|
|
115
|
-
axes[key] = createCurveAxis(spline.chunkCoefficients(axisPoints[key]));
|
|
116
|
-
}
|
|
117
|
-
const solveT = (t, precision = 12) => {
|
|
118
|
-
const rounded = round(t);
|
|
119
|
-
invariant(
|
|
120
|
-
rounded >= 0 && rounded <= 1,
|
|
121
|
-
`t must be between 0 and 1, got ${rounded}`
|
|
122
|
-
);
|
|
123
|
-
const position = {};
|
|
124
|
-
for (const key of axisKeys) {
|
|
125
|
-
position[key] = round(axes[key].solvePosition(rounded), precision);
|
|
126
|
-
}
|
|
127
|
-
return position;
|
|
128
|
-
};
|
|
129
|
-
const lengthLookup = createLengthLookup(solveT);
|
|
130
|
-
const positionAt = (input, normalize = 1, precision = 12) => {
|
|
131
|
-
invariant(
|
|
132
|
-
input >= 0 && input <= 1,
|
|
133
|
-
`Input must be between 0 and 1, got ${input}`
|
|
134
|
-
);
|
|
135
|
-
let t = input;
|
|
136
|
-
if (normalize > 0) {
|
|
137
|
-
const denormalizedT = lengthLookup(input);
|
|
138
|
-
if (normalize === 1) {
|
|
139
|
-
t = denormalizedT;
|
|
140
|
-
} else {
|
|
141
|
-
t = (1 - normalize) * input + normalize * denormalizedT;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
return solveT(t, precision);
|
|
145
|
-
};
|
|
146
|
-
const solveWhere = (axis, position, precision = 12) => {
|
|
147
|
-
const curveAxis = axes[axis];
|
|
148
|
-
invariant(curveAxis.monotonicity !== "none", "Axis is not monotonic");
|
|
149
|
-
const t = curveAxis.solveT(position, curveAxis.domain)[0];
|
|
150
|
-
invariant(
|
|
151
|
-
typeof t === "number",
|
|
152
|
-
`Could not solve for ${axis} = ${position}`
|
|
153
|
-
);
|
|
154
|
-
const result = { [axis]: round(position, precision) };
|
|
155
|
-
for (const key of axisKeys) {
|
|
156
|
-
if (key !== axis) {
|
|
157
|
-
result[key] = round(axes[key].solvePosition(t), precision);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
return result;
|
|
161
|
-
};
|
|
162
|
-
return {
|
|
163
|
-
axes,
|
|
164
|
-
positionAt,
|
|
165
|
-
solveWhere
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
function createBasisCurve(points, triplicateEndpoints = true) {
|
|
169
|
-
return createCurve(points, splines.basis(triplicateEndpoints));
|
|
170
|
-
}
|
|
171
|
-
function createBezierCurve(points) {
|
|
172
|
-
return createCurve(points, splines.bezier);
|
|
173
|
-
}
|
|
174
|
-
function createCardinalCurve(points, tension = 0.5, duplicateEndpoints = true) {
|
|
175
|
-
return createCurve(points, splines.cardinal(tension, duplicateEndpoints));
|
|
176
|
-
}
|
|
177
|
-
function createCatmullRomCurve(points, duplicateEndpoints = true) {
|
|
178
|
-
return createCurve(points, splines.catmullRom(duplicateEndpoints));
|
|
179
|
-
}
|
|
180
|
-
function createHermiteCurve(points) {
|
|
181
|
-
return createCurve(points, splines.hermite);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
export { createBasisCurve, createBezierCurve, createCardinalCurve, createCatmullRomCurve, createHermiteCurve };
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
function round(value, precision = 12) {
|
|
4
|
-
const scale = 10 ** precision;
|
|
5
|
-
const result = Math.round(value * scale) / scale;
|
|
6
|
-
if (result === 0) {
|
|
7
|
-
return 0;
|
|
8
|
-
}
|
|
9
|
-
return result;
|
|
10
|
-
}
|
|
11
|
-
function remap(x, x1, x2, y1, y2) {
|
|
12
|
-
return y1 + (x - x1) / (x2 - x1) * (y2 - y1);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
exports.remap = remap;
|
|
16
|
-
exports.round = round;
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
function round(value, precision = 12) {
|
|
2
|
-
const scale = 10 ** precision;
|
|
3
|
-
const result = Math.round(value * scale) / scale;
|
|
4
|
-
if (result === 0) {
|
|
5
|
-
return 0;
|
|
6
|
-
}
|
|
7
|
-
return result;
|
|
8
|
-
}
|
|
9
|
-
function remap(x, x1, x2, y1, y2) {
|
|
10
|
-
return y1 + (x - x1) / (x2 - x1) * (y2 - y1);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export { round as a, remap as r };
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
type Monotonicity = 'none' | 'increasing' | 'decreasing' | 'constant';
|
|
2
|
-
type Interval = readonly [number, number];
|
|
3
|
-
type LinearCoefficients = readonly [number, number];
|
|
4
|
-
type LinearPolynomial = {
|
|
5
|
-
readonly domain: Interval;
|
|
6
|
-
readonly range: Interval;
|
|
7
|
-
readonly monotonicity: Monotonicity;
|
|
8
|
-
readonly coefficients: LinearCoefficients;
|
|
9
|
-
readonly root: number | null;
|
|
10
|
-
readonly solve: (x: number) => number;
|
|
11
|
-
readonly solveInverse: (y: number) => number;
|
|
12
|
-
};
|
|
13
|
-
type QuadraticCoefficients = readonly [number, number, number];
|
|
14
|
-
type QuadraticPolynomial = {
|
|
15
|
-
readonly domain: Interval;
|
|
16
|
-
readonly range: Interval;
|
|
17
|
-
readonly monotonicity: Monotonicity;
|
|
18
|
-
readonly coefficients: QuadraticCoefficients;
|
|
19
|
-
readonly extreme: number | null;
|
|
20
|
-
readonly roots: ReadonlyArray<number>;
|
|
21
|
-
readonly derivative: LinearPolynomial;
|
|
22
|
-
readonly solve: (x: number) => number;
|
|
23
|
-
readonly solveInverse: (y: number, domain?: Interval) => ReadonlyArray<number>;
|
|
24
|
-
};
|
|
25
|
-
type CubicCoefficients = readonly [number, number, number, number];
|
|
26
|
-
type CubicPolynomial = {
|
|
27
|
-
readonly domain: Interval;
|
|
28
|
-
readonly range: Interval;
|
|
29
|
-
readonly monotonicity: Monotonicity;
|
|
30
|
-
readonly coefficients: CubicCoefficients;
|
|
31
|
-
readonly extrema: ReadonlyArray<number>;
|
|
32
|
-
readonly roots: ReadonlyArray<number>;
|
|
33
|
-
readonly derivative: QuadraticPolynomial;
|
|
34
|
-
readonly solve: (x: number) => number;
|
|
35
|
-
readonly solveInverse: (y: number, domain?: Interval) => ReadonlyArray<number>;
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
export type { CubicPolynomial as C, Interval as I, Monotonicity as M, CubicCoefficients as a };
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
type Monotonicity = 'none' | 'increasing' | 'decreasing' | 'constant';
|
|
2
|
-
type Interval = readonly [number, number];
|
|
3
|
-
type LinearCoefficients = readonly [number, number];
|
|
4
|
-
type LinearPolynomial = {
|
|
5
|
-
readonly domain: Interval;
|
|
6
|
-
readonly range: Interval;
|
|
7
|
-
readonly monotonicity: Monotonicity;
|
|
8
|
-
readonly coefficients: LinearCoefficients;
|
|
9
|
-
readonly root: number | null;
|
|
10
|
-
readonly solve: (x: number) => number;
|
|
11
|
-
readonly solveInverse: (y: number) => number;
|
|
12
|
-
};
|
|
13
|
-
type QuadraticCoefficients = readonly [number, number, number];
|
|
14
|
-
type QuadraticPolynomial = {
|
|
15
|
-
readonly domain: Interval;
|
|
16
|
-
readonly range: Interval;
|
|
17
|
-
readonly monotonicity: Monotonicity;
|
|
18
|
-
readonly coefficients: QuadraticCoefficients;
|
|
19
|
-
readonly extreme: number | null;
|
|
20
|
-
readonly roots: ReadonlyArray<number>;
|
|
21
|
-
readonly derivative: LinearPolynomial;
|
|
22
|
-
readonly solve: (x: number) => number;
|
|
23
|
-
readonly solveInverse: (y: number, domain?: Interval) => ReadonlyArray<number>;
|
|
24
|
-
};
|
|
25
|
-
type CubicCoefficients = readonly [number, number, number, number];
|
|
26
|
-
type CubicPolynomial = {
|
|
27
|
-
readonly domain: Interval;
|
|
28
|
-
readonly range: Interval;
|
|
29
|
-
readonly monotonicity: Monotonicity;
|
|
30
|
-
readonly coefficients: CubicCoefficients;
|
|
31
|
-
readonly extrema: ReadonlyArray<number>;
|
|
32
|
-
readonly roots: ReadonlyArray<number>;
|
|
33
|
-
readonly derivative: QuadraticPolynomial;
|
|
34
|
-
readonly solve: (x: number) => number;
|
|
35
|
-
readonly solveInverse: (y: number, domain?: Interval) => ReadonlyArray<number>;
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
export type { CubicPolynomial as C, Interval as I, Monotonicity as M, CubicCoefficients as a };
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
type Monotonicity = 'none' | 'increasing' | 'decreasing' | 'constant';
|
|
2
|
-
type Interval = readonly [number, number];
|
|
3
|
-
type LinearCoefficients = readonly [number, number];
|
|
4
|
-
type LinearPolynomial = {
|
|
5
|
-
readonly domain: Interval;
|
|
6
|
-
readonly range: Interval;
|
|
7
|
-
readonly monotonicity: Monotonicity;
|
|
8
|
-
readonly coefficients: LinearCoefficients;
|
|
9
|
-
readonly root: number | null;
|
|
10
|
-
readonly solve: (x: number) => number;
|
|
11
|
-
readonly solveInverse: (y: number) => number;
|
|
12
|
-
};
|
|
13
|
-
type QuadraticCoefficients = readonly [number, number, number];
|
|
14
|
-
type QuadraticPolynomial = {
|
|
15
|
-
readonly domain: Interval;
|
|
16
|
-
readonly range: Interval;
|
|
17
|
-
readonly monotonicity: Monotonicity;
|
|
18
|
-
readonly coefficients: QuadraticCoefficients;
|
|
19
|
-
readonly extreme: number | null;
|
|
20
|
-
readonly roots: ReadonlyArray<number>;
|
|
21
|
-
readonly derivative: LinearPolynomial;
|
|
22
|
-
readonly solve: (x: number) => number;
|
|
23
|
-
readonly solveInverse: (y: number, domain?: Interval) => ReadonlyArray<number>;
|
|
24
|
-
};
|
|
25
|
-
type CubicCoefficients = readonly [number, number, number, number];
|
|
26
|
-
type CubicPolynomial = {
|
|
27
|
-
readonly domain: Interval;
|
|
28
|
-
readonly range: Interval;
|
|
29
|
-
readonly monotonicity: Monotonicity;
|
|
30
|
-
readonly coefficients: CubicCoefficients;
|
|
31
|
-
readonly extrema: ReadonlyArray<number>;
|
|
32
|
-
readonly roots: ReadonlyArray<number>;
|
|
33
|
-
readonly derivative: QuadraticPolynomial;
|
|
34
|
-
readonly solve: (x: number) => number;
|
|
35
|
-
readonly solveInverse: (y: number, domain?: Interval) => ReadonlyArray<number>;
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
export type { CubicPolynomial as C, Interval as I, Monotonicity as M, CubicCoefficients as a };
|