curvy 2.0.0-alpha.2 → 2.0.0-alpha.4

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.
Files changed (63) hide show
  1. package/dist/characteristic/index.d.mts +9 -9
  2. package/dist/characteristic/index.mjs +1 -1
  3. package/dist/curve/index.d.mts +10 -2
  4. package/dist/curve/index.mjs +1 -1
  5. package/dist/interval/index.d.mts +9 -3
  6. package/dist/interval/index.mjs +2 -2
  7. package/dist/matrix/index.d.mts +9 -2
  8. package/dist/path/index.d.mts +15 -223
  9. package/dist/path/index.mjs +6 -6
  10. package/dist/path/index.mjs.map +1 -1
  11. package/dist/polynomial/index.d.mts +9 -2
  12. package/dist/polynomial/index.mjs +2 -2
  13. package/dist/shared/{characteristic-B9nCh_cx.mjs → characteristic-DLlhja-I.mjs} +9 -9
  14. package/dist/shared/{characteristic-B9nCh_cx.mjs.map → characteristic-DLlhja-I.mjs.map} +1 -1
  15. package/dist/shared/{cubic-CpHAx8cC.mjs → cubic-CMonq6bg.mjs} +26 -5
  16. package/dist/shared/cubic-CMonq6bg.mjs.map +1 -0
  17. package/dist/shared/cubic-DkBqcZf-.d.mts +121 -0
  18. package/dist/shared/interval-Bhzeqp8M.d.mts +62 -0
  19. package/dist/shared/{interval-05CR6eBf.mjs → interval-X1EYuf-T.mjs} +2 -2
  20. package/dist/shared/{interval-05CR6eBf.mjs.map → interval-X1EYuf-T.mjs.map} +1 -1
  21. package/dist/shared/interval2d-BMk5UYXD.d.mts +29 -0
  22. package/dist/shared/{interval2d-8IBZnUOq.mjs → interval2d-ca0J1NMr.mjs} +8 -8
  23. package/dist/shared/{interval2d-8IBZnUOq.mjs.map → interval2d-ca0J1NMr.mjs.map} +1 -1
  24. package/dist/shared/matrix4x4-CaytTaB_.d.mts +168 -0
  25. package/dist/shared/{quadratic-CamozcFc.mjs → quadratic-DyeMtvET.mjs} +20 -2
  26. package/dist/shared/quadratic-DyeMtvET.mjs.map +1 -0
  27. package/dist/shared/rationalCubic2d-D-UevGKu.d.mts +60 -0
  28. package/dist/shared/{rationalCubic2d-Bys2Uory.mjs → rationalCubic2d-D658ltUM.mjs} +17 -17
  29. package/dist/shared/{rationalCubic2d-Bys2Uory.mjs.map → rationalCubic2d-D658ltUM.mjs.map} +1 -1
  30. package/dist/shared/rationalCubic2d-MgMSJaAU.d.mts +104 -0
  31. package/dist/shared/{rationalCubic2d-BEgUGSFf.mjs → rationalCubic2d-Vw4qGPZj.mjs} +9 -9
  32. package/dist/shared/{rationalCubic2d-BEgUGSFf.mjs.map → rationalCubic2d-Vw4qGPZj.mjs.map} +1 -1
  33. package/dist/shared/{solution-CrtLfqEq.mjs → solution-3TDATEMn.mjs} +28 -2
  34. package/dist/shared/solution-3TDATEMn.mjs.map +1 -0
  35. package/dist/shared/solution-DInDT2Hq.d.mts +60 -0
  36. package/dist/shared/{vector2-CL1HDdPr.mjs → vector2-CCuJx1rX.mjs} +6 -6
  37. package/dist/shared/{vector2-CL1HDdPr.mjs.map → vector2-CCuJx1rX.mjs.map} +1 -1
  38. package/dist/shared/vector2-euuV_bNQ.d.mts +58 -0
  39. package/dist/shared/vector3-3Xx7GVk7.d.mts +37 -0
  40. package/dist/shared/{vector3-D-tv_aKL.mjs → vector3-C-qgKAjR.mjs} +2 -2
  41. package/dist/shared/{vector3-D-tv_aKL.mjs.map → vector3-C-qgKAjR.mjs.map} +1 -1
  42. package/dist/shared/{vector4-5KbjoHVj.mjs → vector4-BhOKDhD5.mjs} +2 -2
  43. package/dist/shared/{vector4-5KbjoHVj.mjs.map → vector4-BhOKDhD5.mjs.map} +1 -1
  44. package/dist/solution/index.d.mts +7 -2
  45. package/dist/solution/index.mjs +1 -1
  46. package/dist/splines/index.d.mts +37 -606
  47. package/dist/splines/index.mjs +193 -35
  48. package/dist/splines/index.mjs.map +1 -1
  49. package/dist/vector/index.d.mts +10 -3
  50. package/dist/vector/index.mjs +3 -3
  51. package/package.json +1 -1
  52. package/dist/shared/cubic-BajUY0JT.d.mts +0 -1100
  53. package/dist/shared/cubic-CpHAx8cC.mjs.map +0 -1
  54. package/dist/shared/interval-Dy-RMEE3.d.mts +0 -533
  55. package/dist/shared/interval2d-C2id9u31.d.mts +0 -172
  56. package/dist/shared/matrix4x4-Dm_tSiH1.d.mts +0 -1183
  57. package/dist/shared/quadratic-CamozcFc.mjs.map +0 -1
  58. package/dist/shared/rationalCubic2d-B6g97ryJ.d.mts +0 -308
  59. package/dist/shared/rationalCubic2d-DlQfBURs.d.mts +0 -818
  60. package/dist/shared/solution-CrtLfqEq.mjs.map +0 -1
  61. package/dist/shared/solution-sNQ-ZVhN.d.mts +0 -251
  62. package/dist/shared/vector2-DPUY3_eA.d.mts +0 -470
  63. package/dist/shared/vector3-DqeOZtOB.d.mts +0 -703
@@ -1,14 +1,14 @@
1
1
  import { t as __exportAll } from "../shared/chunk-25Hzd3z8.mjs";
2
2
  import { Pipeable, dual, invariant } from "../utils.mjs";
3
3
  import { epsEquals } from "../number.mjs";
4
- import { a as makeWeighted, i as make$10, o as scale, s as subtract, t as add } from "../shared/vector2-CL1HDdPr.mjs";
5
- import { t as make$11 } from "../shared/vector3-D-tv_aKL.mjs";
6
- import { n as transpose, t as make$12 } from "../shared/vector4-5KbjoHVj.mjs";
4
+ import { a as make$10, c as subtract, i as magnitude, o as makeWeighted, r as isVector2, s as scale, t as add } from "../shared/vector2-CCuJx1rX.mjs";
5
+ import { t as make$11 } from "../shared/vector3-C-qgKAjR.mjs";
6
+ import { n as transpose, t as make$12 } from "../shared/vector4-BhOKDhD5.mjs";
7
7
  import { a as vectorProductLeft, i as multiply, t as inverse } from "../shared/matrix4x4-Ck2WROK-.mjs";
8
- import { o as none, s as one } from "../shared/solution-CrtLfqEq.mjs";
9
- import { n as fromBezierPoints, s as fromPolynomials } from "../shared/rationalCubic2d-Bys2Uory.mjs";
10
- import { a as cubicCardinal, i as cubicBezier, o as cubicHermite, r as cubicBasisSpline, t as apply } from "../shared/characteristic-B9nCh_cx.mjs";
11
- import { i as make$13, t as fromArray$10 } from "../shared/rationalCubic2d-BEgUGSFf.mjs";
8
+ import { o as none, s as one } from "../shared/solution-3TDATEMn.mjs";
9
+ import { c as fromPolynomials, n as fromBezierPoints, s as fromCoefficients } from "../shared/rationalCubic2d-D658ltUM.mjs";
10
+ import { a as cubicHermite, i as cubicBezier, r as cubicBasisSpline, t as apply } from "../shared/characteristic-DLlhja-I.mjs";
11
+ import { i as make$13, t as fromArray$10 } from "../shared/rationalCubic2d-Vw4qGPZj.mjs";
12
12
  //#region src/splines/rationalBezier2d.internal.ts
13
13
  const RationalBezier2dTypeId = Symbol("curvy/splines/rationalBezier2d");
14
14
  var RationalBezier2dImpl = class extends Pipeable {
@@ -33,6 +33,7 @@ const make$9 = (p0, p1, p2, p3) => new RationalBezier2dImpl([
33
33
  lift(p3)
34
34
  ]);
35
35
  const fromArray$9 = (points) => new RationalBezier2dImpl(points.map(lift));
36
+ const fromTuples$9 = (tuples) => new RationalBezier2dImpl(tuples.map(([x, y, weight]) => make$11(x * weight, y * weight, weight)));
36
37
  const fromPoints$1 = (p0, p1, p2, p3) => new RationalBezier2dImpl([
37
38
  make$11(p0.x, p0.y, 1),
38
39
  make$11(p1.x, p1.y, 1),
@@ -197,6 +198,7 @@ const make$8 = (p0, p1, p2, p3) => new Bezier2dImpl([
197
198
  p3
198
199
  ]);
199
200
  const fromArray$8 = (points) => new Bezier2dImpl(points);
201
+ const fromTuples$8 = (tuples) => new Bezier2dImpl(tuples.map(([x, y]) => make$10(x, y)));
200
202
  const append$7 = dual(4, (p, p1, p2, p3) => new Bezier2dImpl((p instanceof Bezier2dImpl ? p.points : Array.from(p)).concat(p1, p2, p3)));
201
203
  const fromBasis = (p, matrix, stride) => {
202
204
  const conversion = getConversionMatrix(matrix);
@@ -291,6 +293,7 @@ var bezier2d_exports = /* @__PURE__ */ __exportAll({
291
293
  appendVelocityAligned: () => appendVelocityAligned,
292
294
  fromArray: () => fromArray$7,
293
295
  fromRational: () => fromRational,
296
+ fromTuples: () => fromTuples$7,
294
297
  isCubicBezier2d: () => isCubicBezier2d,
295
298
  make: () => make$7,
296
299
  subdivide: () => subdivide$1,
@@ -316,6 +319,15 @@ const make$7 = make$8;
316
319
  */
317
320
  const fromArray$7 = fromArray$8;
318
321
  /**
322
+ * Creates a new `Bezier2d` from an array of `[x, y]` tuples. Convenient for
323
+ * data sourced from JSON, CSV, or other tuple-shaped formats.
324
+ *
325
+ * @param tuples - The control points as `[x, y]` tuples.
326
+ * @returns A new `Bezier2d` instance.
327
+ * @since 2.0.0
328
+ */
329
+ const fromTuples$7 = fromTuples$8;
330
+ /**
319
331
  * Checks if a value is a `Bezier2d`.
320
332
  *
321
333
  * @param p - The value to check.
@@ -346,38 +358,61 @@ const toPath$7 = toPath$8;
346
358
  *
347
359
  * @param r - The rational bezier to convert.
348
360
  * @returns Either a `Bezier2d` instance or `Solution.none`.
349
- * @since 2.1.0
361
+ * @since 2.0.0
350
362
  */
351
363
  const fromRational = fromRational$1;
352
364
  const subdivide$1 = subdivide$2;
353
365
  //#endregion
354
366
  //#region src/splines/cardinal2d.internal.ts
355
367
  const Cardinal2dTypeId = Symbol.for("curvy/splines/cardinal2d");
368
+ const DEFAULT_TENSION = .5;
369
+ const DEFAULT_ALPHA = .5;
356
370
  var Cardinal2dImpl = class extends Pipeable {
357
371
  [Cardinal2dTypeId] = Cardinal2dTypeId;
358
372
  points;
359
- constructor(points) {
373
+ tension;
374
+ alpha;
375
+ constructor(points, tension, alpha) {
360
376
  invariant(points.length >= 2, "cardinal splines requires 2 or more points");
361
377
  super();
362
378
  this.points = points;
379
+ this.tension = tension;
380
+ this.alpha = alpha;
363
381
  }
364
382
  [Symbol.iterator]() {
365
383
  return this.points[Symbol.iterator]();
366
384
  }
367
385
  };
368
386
  const isCardinal2d$1 = (p) => typeof p === "object" && p !== null && Cardinal2dTypeId in p;
369
- const make$6 = (...points) => new Cardinal2dImpl(points);
370
- const fromArray$6 = (points) => new Cardinal2dImpl(points);
371
- const append$5 = dual((args) => isCardinal2d$1(args[0]), (p, ...points) => new Cardinal2dImpl([...p, ...points]));
372
- const prepend$5 = dual((args) => isCardinal2d$1(args[0]), (p, ...points) => new Cardinal2dImpl([...points, ...p]));
387
+ const resolveOptions = (options) => ({
388
+ tension: options?.tension ?? DEFAULT_TENSION,
389
+ alpha: options?.alpha ?? DEFAULT_ALPHA
390
+ });
391
+ const make$6 = (...args) => {
392
+ if (isVector2(args[0])) return new Cardinal2dImpl(args, DEFAULT_TENSION, DEFAULT_ALPHA);
393
+ const [options, ...points] = args;
394
+ const { tension, alpha } = resolveOptions(options);
395
+ return new Cardinal2dImpl(points, tension, alpha);
396
+ };
397
+ const fromArray$6 = (points, options) => {
398
+ const { tension, alpha } = resolveOptions(options);
399
+ return new Cardinal2dImpl(points, tension, alpha);
400
+ };
401
+ const fromTuples$6 = (tuples, options) => {
402
+ const { tension, alpha } = resolveOptions(options);
403
+ return new Cardinal2dImpl(tuples.map(([x, y]) => make$10(x, y)), tension, alpha);
404
+ };
405
+ const append$5 = dual((args) => isCardinal2d$1(args[0]), (p, ...points) => new Cardinal2dImpl([...p, ...points], p.tension, p.alpha));
406
+ const prepend$5 = dual((args) => isCardinal2d$1(args[0]), (p, ...points) => new Cardinal2dImpl([...points, ...p], p.tension, p.alpha));
373
407
  const withDuplicatedEndpoints$1 = (p) => {
374
408
  const points = p instanceof Cardinal2dImpl ? p.points : [...p];
375
409
  return new Cardinal2dImpl([
376
410
  points[0],
377
411
  ...points,
378
412
  points[points.length - 1]
379
- ]);
413
+ ], p.tension, p.alpha);
380
414
  };
415
+ const withInterpolatedEndpoints$1 = (p) => withDuplicatedEndpoints$1(p);
381
416
  const withReflectedEndpoints$1 = dual((args) => isCardinal2d$1(args[0]), (p, scale$1 = 1) => {
382
417
  if (scale$1 === 0) return withDuplicatedEndpoints$1(p);
383
418
  const points = p instanceof Cardinal2dImpl ? p.points : [...p];
@@ -389,22 +424,72 @@ const withReflectedEndpoints$1 = dual((args) => isCardinal2d$1(args[0]), (p, sca
389
424
  subtract(p1, p0).pipe(scale(scale$1), add(p0)),
390
425
  ...points,
391
426
  subtract(p2, p3).pipe(scale(scale$1), add(p3))
392
- ]);
427
+ ], p.tension, p.alpha);
393
428
  });
394
- const toPath$6 = dual((args) => isCardinal2d$1(args[0]), (p, scale = .5) => make$13(...toCurves(p, cubicCardinal(scale), 1)));
395
- const toBezier$5 = (p, scale = .5) => fromBasis(p, cubicCardinal(scale), 1);
429
+ const withTension$1 = dual(2, (p, tension) => new Cardinal2dImpl(p.points, tension, p.alpha));
430
+ const withAlpha$1 = dual(2, (p, alpha) => new Cardinal2dImpl(p.points, p.tension, alpha));
431
+ const withOptions$1 = dual(2, (p, options) => new Cardinal2dImpl(p.points, options.tension ?? p.tension, options.alpha ?? p.alpha));
432
+ const buildCardinalSegment = (p0, p1, p2, p3, tension, alpha) => {
433
+ const d01 = magnitude(subtract(p1, p0)) ** alpha;
434
+ const d12 = magnitude(subtract(p2, p1)) ** alpha;
435
+ const d23 = magnitude(subtract(p3, p2)) ** alpha;
436
+ invariant(Number.isFinite(d01) && Number.isFinite(d12) && Number.isFinite(d23), "cardinal: non-finite chord length");
437
+ const factor = 2 * tension;
438
+ const lead = d01 === 0 ? 0 : d12 / d01;
439
+ const trail = d23 === 0 ? 0 : d12 / d23;
440
+ const mid01 = d01 + d12 === 0 ? 0 : d12 / (d01 + d12);
441
+ const mid23 = d12 + d23 === 0 ? 0 : d12 / (d12 + d23);
442
+ const v1x = factor * ((p1.x - p0.x) * lead - (p2.x - p0.x) * mid01 + (p2.x - p1.x));
443
+ const v1y = factor * ((p1.y - p0.y) * lead - (p2.y - p0.y) * mid01 + (p2.y - p1.y));
444
+ const v2x = factor * (p2.x - p1.x - (p3.x - p1.x) * mid23 + (p3.x - p2.x) * trail);
445
+ const v2y = factor * (p2.y - p1.y - (p3.y - p1.y) * mid23 + (p3.y - p2.y) * trail);
446
+ const dx = p2.x - p1.x;
447
+ const dy = p2.y - p1.y;
448
+ return fromCoefficients(make$10(p1.x, p1.y), make$10(v1x, v1y), make$10(3 * dx - 2 * v1x - v2x, 3 * dy - 2 * v1y - v2y), make$10(-2 * dx + v1x + v2x, -2 * dy + v1y + v2y));
449
+ };
450
+ function* cardinalCurves(p) {
451
+ for (const [p0, p1, p2, p3] of toPointQuads(p, 1)) yield buildCardinalSegment(p0, p1, p2, p3, p.tension, p.alpha);
452
+ }
453
+ const toPath$6 = (p) => make$13(...cardinalCurves(p));
454
+ const toBezier$5 = (p) => {
455
+ const points = [];
456
+ let first = true;
457
+ for (const curve of cardinalCurves(p)) {
458
+ const c0x = curve.x.c0;
459
+ const c0y = curve.y.c0;
460
+ const c1x = curve.x.c1;
461
+ const c1y = curve.y.c1;
462
+ const c2x = curve.x.c2;
463
+ const c2y = curve.y.c2;
464
+ const c3x = curve.x.c3;
465
+ const c3y = curve.y.c3;
466
+ if (first) {
467
+ points.push(make$10(c0x, c0y));
468
+ first = false;
469
+ }
470
+ points.push(make$10(c0x + c1x / 3, c0y + c1y / 3));
471
+ points.push(make$10(c0x + 2 * c1x / 3 + c2x / 3, c0y + 2 * c1y / 3 + c2y / 3));
472
+ points.push(make$10(c0x + c1x + c2x + c3x, c0y + c1y + c2y + c3y));
473
+ }
474
+ return fromArray$8(points);
475
+ };
396
476
  //#endregion
397
477
  //#region src/splines/cardinal2d.ts
398
478
  var cardinal2d_exports = /* @__PURE__ */ __exportAll({
399
479
  append: () => append$4,
400
480
  fromArray: () => fromArray$5,
481
+ fromTuples: () => fromTuples$5,
401
482
  isCardinal2d: () => isCardinal2d,
402
483
  make: () => make$5,
403
484
  prepend: () => prepend$4,
404
485
  toBezier: () => toBezier$4,
405
486
  toPath: () => toPath$5,
487
+ withAlpha: () => withAlpha,
406
488
  withDuplicatedEndpoints: () => withDuplicatedEndpoints,
407
- withReflectedEndpoints: () => withReflectedEndpoints
489
+ withInterpolatedEndpoints: () => withInterpolatedEndpoints,
490
+ withOptions: () => withOptions,
491
+ withReflectedEndpoints: () => withReflectedEndpoints,
492
+ withTension: () => withTension
408
493
  });
409
494
  /**
410
495
  * Checks if a value is a `Cardinal2d`.
@@ -414,36 +499,76 @@ var cardinal2d_exports = /* @__PURE__ */ __exportAll({
414
499
  * @since 1.0.0
415
500
  */
416
501
  const isCardinal2d = isCardinal2d$1;
502
+ const make$5 = make$6;
417
503
  /**
418
- * Creates a new `Cardinal2d` instance.
504
+ * Creates a new `Cardinal2d` from an array of control points.
419
505
  *
420
- * @param p0 - The first control point.
421
- * @param p1 - The second control point.
422
- * @param points - The remaining control points.
506
+ * @param points - The control points.
507
+ * @param options - Tension and alpha. See {@link Options}. Defaults to centripetal Catmull-Rom.
423
508
  * @returns A new `Cardinal2d` instance.
424
509
  * @since 1.0.0
425
510
  */
426
- const make$5 = make$6;
511
+ const fromArray$5 = fromArray$6;
427
512
  /**
428
- * Creates a new `Cardinal2d` instance from an array of control points.
513
+ * Creates a new `Cardinal2d` from an array of `[x, y]` tuples.
429
514
  *
430
- * @param points - The control points.
515
+ * @param tuples - The control points as `[x, y]` tuples.
516
+ * @param options - Tension and alpha. See {@link Options}. Defaults to centripetal Catmull-Rom.
431
517
  * @returns A new `Cardinal2d` instance.
432
- * @since 1.0.0
518
+ * @since 2.0.0
433
519
  */
434
- const fromArray$5 = fromArray$6;
520
+ const fromTuples$5 = fromTuples$6;
435
521
  const append$4 = append$5;
436
522
  const prepend$4 = prepend$5;
437
523
  /**
438
- * Doubles the endpoints of a `Cardinal2d` spline.
524
+ * Doubles the endpoints of a `Cardinal2d` spline. Tension and alpha are
525
+ * preserved.
439
526
  *
440
527
  * @param c - The `Cardinal2d` to duplicate the endpoints of.
441
- * @returns A new `Cardinal2d` instance with the duplicated endpoints.
528
+ * @returns A new `Cardinal2d` instance with duplicated endpoints.
442
529
  * @since 1.0.0
443
530
  */
444
531
  const withDuplicatedEndpoints = withDuplicatedEndpoints$1;
532
+ /**
533
+ * Pads the spline so that it interpolates its first and last control points.
534
+ * The resulting path passes through `points[0]` at `u = 0` and `points[points.length - 1]`
535
+ * at `u = 1`. Equivalent to {@link withReflectedEndpoints} called with
536
+ * `scale = 0` (and to {@link withDuplicatedEndpoints}), but reads more
537
+ * directly as the user-facing intent.
538
+ *
539
+ * Tension and alpha are preserved.
540
+ *
541
+ * @param c - The `Cardinal2d` to pad.
542
+ * @returns A new `Cardinal2d` instance whose first and last control points are interpolated.
543
+ * @since 2.0.0
544
+ */
545
+ const withInterpolatedEndpoints = withInterpolatedEndpoints$1;
445
546
  const withReflectedEndpoints = withReflectedEndpoints$1;
547
+ const withTension = withTension$1;
548
+ const withAlpha = withAlpha$1;
549
+ const withOptions = withOptions$1;
550
+ /**
551
+ * Converts a `Cardinal2d` to a `CubicPath2d` using the spline's `tension` and
552
+ * `alpha`. With the default options (`{ tension: 0.5, alpha: 0.5 }`) the
553
+ * result is a centripetal Catmull-Rom path — the canonical recommended
554
+ * Catmull-Rom variant, which avoids the cusps and self-intersections that
555
+ * uniform Catmull-Rom can produce when control points cluster.
556
+ *
557
+ * @param c - The Cardinal spline.
558
+ * @returns A new `CubicPath2d` representing the spline.
559
+ * @since 1.0.0
560
+ */
446
561
  const toPath$5 = toPath$6;
562
+ /**
563
+ * Converts a `Cardinal2d` to a `Bezier2d`. Equivalent to {@link toPath}
564
+ * followed by per-segment monomial-to-Bernstein conversion — same underlying
565
+ * curve, expressed in cubic Bézier control-point form. Uses the spline's
566
+ * `tension` and `alpha`.
567
+ *
568
+ * @param c - The Cardinal spline.
569
+ * @returns A new `Bezier2d` representing the spline.
570
+ * @since 1.0.0
571
+ */
447
572
  const toBezier$4 = toBezier$5;
448
573
  //#endregion
449
574
  //#region src/splines/hermite2d.internal.ts
@@ -469,6 +594,7 @@ const make$4 = (p0, v0, p1, v1) => new Hermite2dImpl([
469
594
  v1
470
595
  ]);
471
596
  const fromArray$4 = (points) => new Hermite2dImpl(points);
597
+ const fromTuples$4 = (tuples) => new Hermite2dImpl(tuples.map(([x, y]) => make$10(x, y)));
472
598
  const append$3 = dual(3, (p, p1, v1) => {
473
599
  return new Hermite2dImpl((p instanceof Hermite2dImpl ? p.points : Array.from(p)).concat(p1, v1));
474
600
  });
@@ -483,6 +609,7 @@ const toBezier$3 = (p) => fromBasis(p, cubicHermite, 2);
483
609
  var hermite2d_exports = /* @__PURE__ */ __exportAll({
484
610
  append: () => append$2,
485
611
  fromArray: () => fromArray$3,
612
+ fromTuples: () => fromTuples$3,
486
613
  isHermite2d: () => isHermite2d,
487
614
  make: () => make$3,
488
615
  prepend: () => prepend$2,
@@ -516,6 +643,15 @@ const make$3 = make$4;
516
643
  * @since 1.0.0
517
644
  */
518
645
  const fromArray$3 = fromArray$4;
646
+ /**
647
+ * Creates a new `Hermite2d` from an array of `[x, y]` tuples, alternating
648
+ * `[position, velocity]` pairs.
649
+ *
650
+ * @param tuples - The point/velocity pairs as `[x, y]` tuples.
651
+ * @returns A new `Hermite2d` instance.
652
+ * @since 2.0.0
653
+ */
654
+ const fromTuples$3 = fromTuples$4;
519
655
  const append$2 = append$3;
520
656
  const prepend$2 = prepend$3;
521
657
  /**
@@ -557,6 +693,7 @@ const make$2 = (p0, p1, p2, p3) => new Basis2dImpl([
557
693
  p3
558
694
  ]);
559
695
  const fromArray$2 = (points) => new Basis2dImpl(points);
696
+ const fromTuples$2 = (tuples) => new Basis2dImpl(tuples.map(([x, y]) => make$10(x, y)));
560
697
  const append$1 = dual((args) => isBasis2d$1(args[0]), (p, ...points) => new Basis2dImpl([...p, ...points]));
561
698
  const prepend$1 = dual((args) => isBasis2d$1(args[0]), (p, ...points) => new Basis2dImpl([...points, ...p]));
562
699
  const withTriplicatedEndpoints$1 = (p) => {
@@ -576,6 +713,7 @@ const toBezier$1 = (p) => fromBasis(p, cubicBasisSpline, 1);
576
713
  var basis2d_exports = /* @__PURE__ */ __exportAll({
577
714
  append: () => append,
578
715
  fromArray: () => fromArray$1,
716
+ fromTuples: () => fromTuples$1,
579
717
  isBasis2d: () => isBasis2d,
580
718
  make: () => make$1,
581
719
  prepend: () => prepend,
@@ -610,6 +748,14 @@ const make$1 = make$2;
610
748
  * @since 1.0.0
611
749
  */
612
750
  const fromArray$1 = fromArray$2;
751
+ /**
752
+ * Creates a new `Basis2d` from an array of `[x, y]` tuples.
753
+ *
754
+ * @param tuples - The control points as `[x, y]` tuples.
755
+ * @returns A new `Basis2d` instance.
756
+ * @since 2.0.0
757
+ */
758
+ const fromTuples$1 = fromTuples$2;
613
759
  const append = append$1;
614
760
  const prepend = prepend$1;
615
761
  /**
@@ -644,6 +790,7 @@ var rationalBezier2d_exports = /* @__PURE__ */ __exportAll({
644
790
  fromArray: () => fromArray,
645
791
  fromBezier: () => fromBezier,
646
792
  fromPoints: () => fromPoints,
793
+ fromTuples: () => fromTuples,
647
794
  isRationalBezier2d: () => isRationalBezier2d,
648
795
  make: () => make,
649
796
  subdivide: () => subdivide,
@@ -654,7 +801,7 @@ var rationalBezier2d_exports = /* @__PURE__ */ __exportAll({
654
801
  *
655
802
  * @param p - The value to check.
656
803
  * @returns `true` if the value is a `RationalBezier2d`, `false` otherwise.
657
- * @since 2.1.0
804
+ * @since 2.0.0
658
805
  */
659
806
  const isRationalBezier2d = isRationalBezier2d$1;
660
807
  /**
@@ -669,7 +816,7 @@ const isRationalBezier2d = isRationalBezier2d$1;
669
816
  * @param p2 - The third weighted control point (end handle).
670
817
  * @param p3 - The fourth weighted control point (curve end).
671
818
  * @returns A new `RationalBezier2d` instance.
672
- * @since 2.1.0
819
+ * @since 2.0.0
673
820
  */
674
821
  const make = make$9;
675
822
  /**
@@ -680,10 +827,21 @@ const make = make$9;
680
827
  *
681
828
  * @param points - The weighted control points.
682
829
  * @returns A new `RationalBezier2d` instance.
683
- * @since 2.1.0
830
+ * @since 2.0.0
684
831
  */
685
832
  const fromArray = fromArray$9;
686
833
  /**
834
+ * Creates a new `RationalBezier2d` from an array of `[x, y, weight]` tuples.
835
+ * Weight is the projective denominator at each control point — `1` everywhere
836
+ * yields the polynomial Bézier; varying weights bend the curve toward the
837
+ * heavier control points.
838
+ *
839
+ * @param tuples - The weighted control points as `[x, y, weight]` tuples.
840
+ * @returns A new `RationalBezier2d` instance.
841
+ * @since 2.0.0
842
+ */
843
+ const fromTuples = fromTuples$9;
844
+ /**
687
845
  * Creates a new single-segment `RationalBezier2d` from four points with all
688
846
  * weights equal to one.
689
847
  *
@@ -698,7 +856,7 @@ const fromArray = fromArray$9;
698
856
  * @param p2 - The third control point (end handle).
699
857
  * @param p3 - The fourth control point (curve end).
700
858
  * @returns A new `RationalBezier2d` with unit weights.
701
- * @since 2.1.0
859
+ * @since 2.0.0
702
860
  */
703
861
  const fromPoints = fromPoints$1;
704
862
  /**
@@ -707,7 +865,7 @@ const fromPoints = fromPoints$1;
707
865
  *
708
866
  * @param b - The non-rational bezier to lift.
709
867
  * @returns A new `RationalBezier2d` with unit weights.
710
- * @since 2.1.0
868
+ * @since 2.0.0
711
869
  */
712
870
  const fromBezier = fromBezier$1;
713
871
  /**
@@ -724,7 +882,7 @@ const fromBezier = fromBezier$1;
724
882
  *
725
883
  * @param r - The rational bezier to convert.
726
884
  * @returns A new `RationalCubicPath2d` instance representing the same curve.
727
- * @since 2.1.0
885
+ * @since 2.0.0
728
886
  */
729
887
  const toPath = toPath$9;
730
888
  const subdivide = subdivide$3;