curvy 0.3.1 → 0.3.3

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/dist/curve.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import invariant from 'tiny-invariant';
2
- import { createCurveAxis } from './axis.mjs';
2
+ import { c as computeCubicAntiderivative, a as createCurveAxis } from './shared/curvy.7876e09e.mjs';
3
3
  import { r as remap, a as round } from './shared/curvy.9cd8b44c.mjs';
4
4
  import { splines } from './splines.mjs';
5
5
 
@@ -61,42 +61,193 @@ function createIntervalTree(boundaries) {
61
61
  };
62
62
  }
63
63
 
64
+ function collectPointsOfInterest(axis) {
65
+ const samples = new Set(Array.from({ length: 33 }, (_, i) => i / 32));
66
+ const segmentToNormalized = 1 / axis.segments.length;
67
+ for (const [index, segment] of axis.segments.entries()) {
68
+ samples.add(index * segmentToNormalized);
69
+ samples.add((index + 1) * segmentToNormalized);
70
+ for (const t of segment.extrema) {
71
+ samples.add((index + t) * segmentToNormalized);
72
+ }
73
+ for (const root of segment.roots) {
74
+ samples.add((index + root) * segmentToNormalized);
75
+ }
76
+ for (const root of segment.derivative.roots) {
77
+ samples.add((index + root) * segmentToNormalized);
78
+ }
79
+ }
80
+ return Array.from(samples).sort((a, b) => a - b);
81
+ }
82
+ function takeLinearIntegral(x1, x2, y1, y2) {
83
+ const m = (y2 - y1) / (x2 - x1);
84
+ const b = y1 - m * x1;
85
+ const s1 = x1 ** 2 * m / 2 + b * x1;
86
+ const s2 = x2 ** 2 * m / 2 + b * x2;
87
+ return Math.abs(s2 - s1);
88
+ }
89
+ function takePolynomialIntegral(coefficients, start, end) {
90
+ let s1 = 0;
91
+ let s2 = 0;
92
+ for (let i = 0; i < coefficients.length; i++) {
93
+ const power = coefficients.length - i;
94
+ s1 += coefficients[i] * start ** power / power;
95
+ s2 += coefficients[i] * end ** power / power;
96
+ }
97
+ return Math.abs(s2 - s1);
98
+ }
99
+ function* createAxisSampler(key, axis) {
100
+ const queue = collectPointsOfInterest(axis);
101
+ let totalLength = 0;
102
+ const lengthLookup = /* @__PURE__ */ new Map();
103
+ while (queue.length > 0) {
104
+ const current = queue[0];
105
+ const next = queue[1];
106
+ if (next === void 0) {
107
+ yield current;
108
+ lengthLookup.set(totalLength, current);
109
+ break;
110
+ }
111
+ const segment = axis.segments[Math.floor(current * axis.segments.length)];
112
+ const currentPosition = axis.solvePosition(current);
113
+ const nextPosition = axis.solvePosition(next);
114
+ const currentVelocity = axis.solveVelocity(current);
115
+ const nextVelocity = axis.solveVelocity(next);
116
+ const lutPositionIntegral = takeLinearIntegral(
117
+ current,
118
+ next,
119
+ currentPosition,
120
+ nextPosition
121
+ );
122
+ const curvePositionIntegral = takePolynomialIntegral(
123
+ computeCubicAntiderivative(segment.coefficients, 0),
124
+ current,
125
+ next
126
+ );
127
+ const lutVelocityIntegral = takeLinearIntegral(
128
+ current,
129
+ next,
130
+ currentVelocity,
131
+ nextVelocity
132
+ );
133
+ const curveVelocityIntegral = takePolynomialIntegral(
134
+ segment.derivative.coefficients,
135
+ current,
136
+ next
137
+ );
138
+ const error = Math.max(
139
+ Math.abs(lutPositionIntegral - curvePositionIntegral),
140
+ Math.abs(lutVelocityIntegral - curveVelocityIntegral)
141
+ );
142
+ if (error > 1) {
143
+ queue.splice(1, 0, (current + next) / 2);
144
+ } else {
145
+ yield current;
146
+ lengthLookup.set(totalLength, current);
147
+ totalLength += Math.hypot(current - next, currentPosition - nextPosition);
148
+ queue.shift();
149
+ }
150
+ }
151
+ return [
152
+ key,
153
+ {
154
+ length: totalLength,
155
+ lookup: lengthLookup
156
+ }
157
+ ];
158
+ }
64
159
  function distance(a, b) {
65
- const keys = Object.keys(a);
66
- const deltas = keys.map((key) => a[key] - b[key]);
160
+ const deltas = [];
161
+ for (const key of Object.keys(a)) {
162
+ deltas.push(a[key] - b[key]);
163
+ }
67
164
  return Math.hypot(...deltas);
68
165
  }
69
- function createLengthLookup(positionAt) {
70
- const count = 512;
71
- const orderedSamples = Array.from({ length: count + 1 }, (_, i) => i / count);
166
+ function createSampleBuffer() {
167
+ const values = /* @__PURE__ */ new Map();
168
+ return {
169
+ get size() {
170
+ return values.size;
171
+ },
172
+ add(key, value) {
173
+ if (!values.has(key)) {
174
+ values.set(key, /* @__PURE__ */ new Set());
175
+ }
176
+ values.get(key)?.add(value);
177
+ },
178
+ get(key) {
179
+ return values.get(key);
180
+ },
181
+ remove(key, value) {
182
+ values.get(key)?.delete(value);
183
+ if (values.get(key)?.size === 0) {
184
+ values.delete(key);
185
+ }
186
+ },
187
+ keys() {
188
+ return Array.from(values.keys());
189
+ }
190
+ };
191
+ }
192
+ function createLengthLookup({
193
+ length: totalLength,
194
+ lookup
195
+ }) {
196
+ const { search } = createIntervalTree(Array.from(lookup.keys()));
197
+ return (normalized) => {
198
+ invariant(normalized >= 0 && normalized <= 1, "Length out of bounds");
199
+ const length = normalized * totalLength;
200
+ const result = search(length);
201
+ invariant(result, "Length not found");
202
+ return remap(
203
+ length,
204
+ result[0],
205
+ result[1],
206
+ lookup.get(result[0]),
207
+ lookup.get(result[1])
208
+ );
209
+ };
210
+ }
211
+ function createCurveLengthLookups(axes, positionAt) {
72
212
  const lengthLookup = /* @__PURE__ */ new Map();
213
+ const axesLookups = {};
214
+ const sampleBuffer = createSampleBuffer();
215
+ for (const [key, axis] of Object.entries(axes)) {
216
+ const sampler = createAxisSampler(key, axis);
217
+ const first = sampler.next();
218
+ if (first.done) {
219
+ axesLookups[first.value[0]] = createLengthLookup(first.value[1]);
220
+ } else {
221
+ sampleBuffer.add(first.value, sampler);
222
+ }
223
+ }
73
224
  let lastPoint = positionAt(0);
74
225
  let length = 0;
75
226
  lengthLookup.set(0, 0);
76
- for (const t of orderedSamples.slice(1)) {
227
+ while (sampleBuffer.size > 0) {
228
+ const t = Math.min(...sampleBuffer.keys());
77
229
  const point = positionAt(t);
78
230
  length = length + distance(lastPoint, point);
79
231
  lengthLookup.set(length, t);
80
232
  lastPoint = point;
233
+ const samplers = sampleBuffer.get(t);
234
+ for (const sampler of samplers) {
235
+ const next = sampler.next();
236
+ if (next.done) {
237
+ axesLookups[next.value[0]] = createLengthLookup(next.value[1]);
238
+ } else {
239
+ sampleBuffer.add(next.value, sampler);
240
+ }
241
+ sampleBuffer.remove(t, sampler);
242
+ }
81
243
  }
82
- const totalLength = length;
83
- const { search } = createIntervalTree(Array.from(lengthLookup.keys()));
84
- return (normalized) => {
85
- invariant(normalized >= 0 && normalized <= 1, "Length out of bounds");
86
- const length2 = normalized * totalLength;
87
- const result = search(length2);
88
- invariant(result, "Length not found");
89
- return remap(
90
- length2,
91
- result[0],
92
- result[1],
93
- lengthLookup.get(result[0]),
94
- lengthLookup.get(result[1])
95
- );
244
+ return {
245
+ curve: createLengthLookup({ length, lookup: lengthLookup }),
246
+ axes: axesLookups
96
247
  };
97
248
  }
98
249
 
99
- function createCurve(points, spline) {
250
+ function convertPointsToAxes(points, spline) {
100
251
  const axisKeys = Object.keys(points[0]);
101
252
  const axisPoints = {};
102
253
  for (const key of axisKeys) {
@@ -112,6 +263,10 @@ function createCurve(points, spline) {
112
263
  for (const key of axisKeys) {
113
264
  axes[key] = createCurveAxis(spline.chunkCoefficients(axisPoints[key]));
114
265
  }
266
+ return axes;
267
+ }
268
+ function createCurve(axes) {
269
+ const axisKeys = Object.keys(axes);
115
270
  const solveT = (t, precision = 12) => {
116
271
  const rounded = round(t);
117
272
  invariant(
@@ -124,7 +279,7 @@ function createCurve(points, spline) {
124
279
  }
125
280
  return position;
126
281
  };
127
- const lengthLookup = createLengthLookup(solveT);
282
+ const lengthLookups = createCurveLengthLookups(axes, solveT);
128
283
  const positionAt = (input, normalize = 1, precision = 12) => {
129
284
  invariant(
130
285
  input >= 0 && input <= 1,
@@ -132,7 +287,23 @@ function createCurve(points, spline) {
132
287
  );
133
288
  let t = input;
134
289
  if (normalize > 0) {
135
- const denormalizedT = lengthLookup(input);
290
+ const denormalizedT = lengthLookups.curve(input);
291
+ if (normalize === 1) {
292
+ t = denormalizedT;
293
+ } else {
294
+ t = (1 - normalize) * input + normalize * denormalizedT;
295
+ }
296
+ }
297
+ return solveT(t, precision);
298
+ };
299
+ const solveAlong = (axis, input, normalize = 1, precision = 12) => {
300
+ invariant(
301
+ input >= 0 && input <= 1,
302
+ `Input must be between 0 and 1, got ${input}`
303
+ );
304
+ let t = input;
305
+ if (normalize > 0) {
306
+ const denormalizedT = lengthLookups.axes[axis](input);
136
307
  if (normalize === 1) {
137
308
  t = denormalizedT;
138
309
  } else {
@@ -149,34 +320,35 @@ function createCurve(points, spline) {
149
320
  typeof t === "number",
150
321
  `Could not solve for ${axis} = ${position}`
151
322
  );
152
- const result = { [axis]: round(position, precision) };
153
- for (const key of axisKeys) {
154
- if (key !== axis) {
155
- result[key] = round(axes[key].solvePosition(t), precision);
156
- }
157
- }
158
- return result;
323
+ return positionAt(t, 0, precision);
159
324
  };
160
325
  return {
161
326
  axes,
162
327
  positionAt,
328
+ solveAlong,
163
329
  solveWhere
164
330
  };
165
331
  }
166
332
  function createBasisCurve(points, triplicateEndpoints = true) {
167
- return createCurve(points, splines.basis(triplicateEndpoints));
333
+ return createCurve(
334
+ convertPointsToAxes(points, splines.basis(triplicateEndpoints))
335
+ );
168
336
  }
169
337
  function createBezierCurve(points) {
170
- return createCurve(points, splines.bezier);
338
+ return createCurve(convertPointsToAxes(points, splines.bezier));
171
339
  }
172
340
  function createCardinalCurve(points, tension = 0.5, duplicateEndpoints = true) {
173
- return createCurve(points, splines.cardinal(tension, duplicateEndpoints));
341
+ return createCurve(
342
+ convertPointsToAxes(points, splines.cardinal(tension, duplicateEndpoints))
343
+ );
174
344
  }
175
345
  function createCatmullRomCurve(points, duplicateEndpoints = true) {
176
- return createCurve(points, splines.catmullRom(duplicateEndpoints));
346
+ return createCurve(
347
+ convertPointsToAxes(points, splines.catmullRom(duplicateEndpoints))
348
+ );
177
349
  }
178
350
  function createHermiteCurve(points) {
179
- return createCurve(points, splines.hermite);
351
+ return createCurve(convertPointsToAxes(points, splines.hermite));
180
352
  }
181
353
 
182
- export { createBasisCurve, createBezierCurve, createCardinalCurve, createCatmullRomCurve, createHermiteCurve };
354
+ export { createBasisCurve, createBezierCurve, createCardinalCurve, createCatmullRomCurve, createCurve, createHermiteCurve };
@@ -0,0 +1,323 @@
1
+ import invariant from 'tiny-invariant';
2
+ import { splines } from '../splines.mjs';
3
+
4
+ const UNIT_INTERVAL = [0, 1];
5
+ function createLinearPolynomial(coefficients, domain = UNIT_INTERVAL) {
6
+ const [a, b] = coefficients;
7
+ invariant(domain[0] <= domain[1], "invalid domain");
8
+ let root = a === 0 ? null : b === 0 ? 0 : -b / a;
9
+ if (root !== null && (root < domain[0] || root > domain[1])) {
10
+ root = null;
11
+ }
12
+ const range = a >= 0 ? [a * domain[0] + b, a * domain[1] + b] : [a * domain[1] + b, a * domain[0] + b];
13
+ const solve = (x) => {
14
+ invariant(x >= domain[0] && x <= domain[1], "x out of domain");
15
+ return a * x + b;
16
+ };
17
+ const solveInverse = (y) => {
18
+ invariant(y >= range[0] && y <= range[1], "y out of range");
19
+ return a === 0 ? 0 : (y - b) / a;
20
+ };
21
+ return {
22
+ domain,
23
+ range,
24
+ monotonicity: a === 0 ? "constant" : a > 0 ? "increasing" : "decreasing",
25
+ coefficients,
26
+ root,
27
+ solve,
28
+ solveInverse
29
+ };
30
+ }
31
+ function createQuadraticRootSolver(coefficients, defaultDomain, range) {
32
+ const [a, b, c] = coefficients;
33
+ if (a !== 0) {
34
+ return function solveInverse(y, domain = defaultDomain) {
35
+ invariant(domain[0] <= domain[1], "invalid domain");
36
+ invariant(y >= range[0] && y <= range[1], "y out of range");
37
+ const discriminant = b ** 2 - 4 * a * (c - y);
38
+ if (discriminant < 0) {
39
+ return [];
40
+ }
41
+ if (discriminant === 0) {
42
+ const root = -b / (2 * a);
43
+ return root < domain[0] || root > domain[1] ? [] : [root];
44
+ }
45
+ const sqrtDiscriminant = Math.sqrt(discriminant);
46
+ const denominator = 2 * a;
47
+ const left = (-b - sqrtDiscriminant) / denominator;
48
+ const right = (-b + sqrtDiscriminant) / denominator;
49
+ const leftInDomain = left >= domain[0] && left <= domain[1];
50
+ const rightInDomain = right >= domain[0] && right <= domain[1];
51
+ if (leftInDomain && rightInDomain) {
52
+ return left < right ? [left, right] : [right, left];
53
+ }
54
+ if (leftInDomain) {
55
+ return [left];
56
+ }
57
+ if (rightInDomain) {
58
+ return [right];
59
+ }
60
+ return [];
61
+ };
62
+ }
63
+ if (b !== 0) {
64
+ return function solveInverse(y, domain = defaultDomain) {
65
+ invariant(domain[0] <= domain[1], "invalid domain");
66
+ invariant(y >= range[0] && y <= range[1], "y out of range");
67
+ const root = -(c - y) / b;
68
+ return root < domain[0] || root > domain[1] ? [] : [root];
69
+ };
70
+ }
71
+ return function solveInverse() {
72
+ return [];
73
+ };
74
+ }
75
+ function createQuadraticPolynomial(coefficients, domain = UNIT_INTERVAL) {
76
+ const [a, b, c] = coefficients;
77
+ invariant(domain[0] <= domain[1], "invalid domain");
78
+ const derivative = createLinearPolynomial([2 * a, b], domain);
79
+ const extreme = derivative.root;
80
+ const solve = (x) => {
81
+ invariant(x >= domain[0] && x <= domain[1], "x out of domain");
82
+ return a * x ** 2 + b * x + c;
83
+ };
84
+ const rangeCandidates = extreme === null ? [solve(domain[0]), solve(domain[1])] : [solve(domain[0]), solve(extreme), solve(domain[1])];
85
+ const range = [
86
+ Math.min(...rangeCandidates),
87
+ Math.max(...rangeCandidates)
88
+ ];
89
+ const solveInverse = createQuadraticRootSolver(coefficients, domain, range);
90
+ const roots = range[0] > 0 || range[1] < 0 ? [] : solveInverse(0);
91
+ return {
92
+ domain,
93
+ range,
94
+ coefficients,
95
+ monotonicity: a !== 0 ? "none" : b === 0 ? "constant" : b > 0 ? "increasing" : "decreasing",
96
+ extreme,
97
+ roots,
98
+ derivative,
99
+ solve,
100
+ solveInverse
101
+ };
102
+ }
103
+ const TWO_THIRDS_PI = 2 * Math.PI / 3;
104
+ function createCubicRootSolver(coefficients, defaultDomain, range) {
105
+ if (coefficients[0] === 0) {
106
+ return createQuadraticRootSolver(
107
+ [coefficients[1], coefficients[2], coefficients[3]],
108
+ defaultDomain,
109
+ range
110
+ );
111
+ }
112
+ const oneOverA = 1 / coefficients[0];
113
+ const a0 = coefficients[1] * oneOverA;
114
+ const a1 = coefficients[2] * oneOverA;
115
+ const a2OverThree = a0 / 3;
116
+ const q = a1 / 3 - a0 ** 2 / 9;
117
+ const r0 = a1 * a0 / 6 - a0 ** 3 / 27;
118
+ return function solveInverse(y, domain = defaultDomain) {
119
+ invariant(domain[0] <= domain[1], "invalid domain");
120
+ invariant(y >= range[0] && y <= range[1], "y out of range");
121
+ const a02 = (coefficients[3] - y) * oneOverA;
122
+ const r = r0 - a02 * 0.5;
123
+ const discriminant = q ** 3 + r ** 2;
124
+ if (discriminant > 0) {
125
+ const a = Math.cbrt(Math.abs(r) + Math.sqrt(discriminant));
126
+ const root = (r < 0 ? q / a - a : a - q / a) - a2OverThree;
127
+ return root < domain[0] || root > domain[1] ? [] : [root];
128
+ }
129
+ const theta = Math.acos(r / Math.sqrt((-q) ** 3)) / 3;
130
+ const twoRootQ = 2 * Math.sqrt(-q);
131
+ const root1 = twoRootQ * Math.cos(theta - TWO_THIRDS_PI) - a2OverThree;
132
+ const root2 = twoRootQ * Math.cos(theta) - a2OverThree;
133
+ const root3 = twoRootQ * Math.cos(theta + TWO_THIRDS_PI) - a2OverThree;
134
+ const candidates = [root1, root2, root3];
135
+ const roots = [];
136
+ for (const candidate of candidates) {
137
+ if (candidate >= domain[0] && candidate <= domain[1] && !roots.includes(candidate)) {
138
+ roots.push(candidate);
139
+ }
140
+ }
141
+ roots.sort((a, b) => a - b);
142
+ return roots;
143
+ };
144
+ }
145
+ function getMonotonicity(extrema, derivative, domain) {
146
+ if (derivative.coefficients[0] === 0 && derivative.coefficients[1] === 0 && derivative.coefficients[2] === 0) {
147
+ return "constant";
148
+ }
149
+ let hasInnerExtrema = false;
150
+ for (const extreme of extrema) {
151
+ if (extreme > domain[0] && extreme > domain[1]) {
152
+ hasInnerExtrema = true;
153
+ break;
154
+ }
155
+ }
156
+ if (hasInnerExtrema) {
157
+ return "none";
158
+ }
159
+ let test = derivative.solve(domain[0]);
160
+ if (test === 0) {
161
+ test = derivative.solve((domain[0] + domain[1]) * 0.5);
162
+ }
163
+ return Math.sign(test) > 0 ? "increasing" : "decreasing";
164
+ }
165
+ function createCubicPolynomial(coefficients, domain = UNIT_INTERVAL) {
166
+ invariant(domain[0] <= domain[1], "invalid domain");
167
+ const [a, b, c, d] = coefficients;
168
+ const derivative = createQuadraticPolynomial([3 * a, 2 * b, c], domain);
169
+ const extrema = derivative.roots.length === 1 && derivative.coefficients[0] !== 0 ? [] : derivative.roots;
170
+ const solve = (x) => {
171
+ invariant(x >= domain[0] && x <= domain[1], "x out of domain");
172
+ return a * x ** 3 + b * x ** 2 + c * x + d;
173
+ };
174
+ const rangeCandidates = [
175
+ solve(domain[0]),
176
+ ...extrema.map((extreme) => solve(extreme)),
177
+ solve(domain[1])
178
+ ];
179
+ const range = [
180
+ Math.min(...rangeCandidates),
181
+ Math.max(...rangeCandidates)
182
+ ];
183
+ const solveInverse = createCubicRootSolver(coefficients, domain, range);
184
+ const roots = range[0] > 0 || range[1] < 0 ? [] : solveInverse(0, domain);
185
+ const monotonicity = getMonotonicity(extrema, derivative, domain);
186
+ return {
187
+ domain,
188
+ range,
189
+ monotonicity,
190
+ coefficients,
191
+ extrema,
192
+ roots,
193
+ derivative,
194
+ solve,
195
+ solveInverse
196
+ };
197
+ }
198
+ function computeCubicAntiderivative(coefficients, integrationConstant) {
199
+ return [
200
+ coefficients[0] / 4,
201
+ coefficients[1] / 3,
202
+ coefficients[2] / 2,
203
+ coefficients[3],
204
+ integrationConstant
205
+ ];
206
+ }
207
+
208
+ function getCurveExtrema(lookup) {
209
+ const extremaLookup = new Map(lookup);
210
+ const extremaCandidates = Array.from(extremaLookup.keys());
211
+ for (const [index, t] of extremaCandidates.entries()) {
212
+ if (index === 0 || index === extremaCandidates.length - 1) {
213
+ continue;
214
+ }
215
+ const previous = extremaLookup.get(extremaCandidates[index - 1]);
216
+ const current = extremaLookup.get(t);
217
+ const next = extremaLookup.get(extremaCandidates[index + 1]);
218
+ if (previous <= current && current < next || previous >= current && current > next) {
219
+ extremaLookup.delete(t);
220
+ }
221
+ }
222
+ const extrema = Array.from(extremaLookup.keys());
223
+ return extrema;
224
+ }
225
+ function createCurveAxis(coefficients) {
226
+ invariant(coefficients.length > 0, "Curve must have at least one segment");
227
+ const segments = [];
228
+ const extremaLookup = /* @__PURE__ */ new Map();
229
+ let monotonicity = "none";
230
+ const normalizedToCurve = coefficients.length;
231
+ const curveToNormalized = 1 / coefficients.length;
232
+ for (let i = 0; i < coefficients.length; i++) {
233
+ const segment = createCubicPolynomial(coefficients[i], UNIT_INTERVAL);
234
+ segments.push(segment);
235
+ extremaLookup.set(i * curveToNormalized, segment.solve(0));
236
+ for (const extreme of segment.extrema) {
237
+ extremaLookup.set(
238
+ (i + extreme) * curveToNormalized,
239
+ segment.solve(extreme)
240
+ );
241
+ }
242
+ if (i === 0) {
243
+ monotonicity = segment.monotonicity;
244
+ } else if (monotonicity !== segment.monotonicity) {
245
+ monotonicity = "none";
246
+ }
247
+ }
248
+ extremaLookup.set(1, segments[segments.length - 1].solve(1));
249
+ const extrema = getCurveExtrema(extremaLookup);
250
+ const range = [
251
+ Math.min(...extremaLookup.values()),
252
+ Math.max(...extremaLookup.values())
253
+ ];
254
+ const getSegmentAndInput = (t) => {
255
+ invariant(t >= 0 && t <= 1, "t out of range");
256
+ if (t === 1) {
257
+ return { segment: segments[segments.length - 1], input: 1 };
258
+ }
259
+ const curveT = t * normalizedToCurve;
260
+ const index = Math.floor(curveT);
261
+ const segment = segments[index];
262
+ const input = curveT - index;
263
+ return { segment, input };
264
+ };
265
+ const solvePosition = (t) => {
266
+ const { segment, input } = getSegmentAndInput(t);
267
+ return segment.solve(input);
268
+ };
269
+ const solveVelocity = (t) => {
270
+ const { segment, input } = getSegmentAndInput(t);
271
+ return segment.derivative.solve(input);
272
+ };
273
+ const solveT = (position, domain) => {
274
+ invariant(
275
+ position >= range[0] && position <= range[1],
276
+ "position out of range"
277
+ );
278
+ invariant(domain[0] <= domain[1], "invalid domain");
279
+ const result = [];
280
+ for (const [index, segment] of segments.entries()) {
281
+ if (position >= segment.range[0] && position <= segment.range[1]) {
282
+ const t = segment.solveInverse(position, domain);
283
+ for (const tValue of t) {
284
+ result.push((index + tValue) * curveToNormalized);
285
+ }
286
+ }
287
+ }
288
+ return result;
289
+ };
290
+ return {
291
+ domain: UNIT_INTERVAL,
292
+ range,
293
+ monotonicity,
294
+ extrema,
295
+ segments,
296
+ solvePosition,
297
+ solveVelocity,
298
+ solveT
299
+ };
300
+ }
301
+ function createBasisAxis(parameters, triplicateEndpoints = true) {
302
+ return createCurveAxis(
303
+ splines.basis(triplicateEndpoints).chunkCoefficients(parameters)
304
+ );
305
+ }
306
+ function createBezierAxis(parameters) {
307
+ return createCurveAxis(splines.bezier.chunkCoefficients(parameters));
308
+ }
309
+ function createCardinalAxis(parameters, a = 0.5, duplicateEndpoints = true) {
310
+ return createCurveAxis(
311
+ splines.cardinal(a, duplicateEndpoints).chunkCoefficients(parameters)
312
+ );
313
+ }
314
+ function createCatmullRomAxis(parameters, duplicateEndpoints = true) {
315
+ return createCurveAxis(
316
+ splines.catmullRom(duplicateEndpoints).chunkCoefficients(parameters)
317
+ );
318
+ }
319
+ function createHermiteAxis(parameters) {
320
+ return createCurveAxis(splines.hermite.chunkCoefficients(parameters));
321
+ }
322
+
323
+ export { createCurveAxis as a, createBasisAxis as b, computeCubicAntiderivative as c, createBezierAxis as d, createCardinalAxis as e, createCatmullRomAxis as f, createHermiteAxis as g };