@weasel-js/geom 1.7.0 → 1.7.2

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/index.js CHANGED
@@ -1,7 +1,17 @@
1
- import { cubicEvalAt, elevateQuadraticToCubic, forEachSegment, PATH_M, PATH_L, PATH_Q, PATH_C, PATH_Z } from './chunk-36DHVSOV.js';
2
- export { DEFAULT_FLATTEN_TOLERANCE, PATH_C, PATH_CMD_LENGTHS, PATH_COMMANDS, PATH_L, PATH_M, PATH_Q, PATH_Z, cubicBounds, cubicEvalAt, elevateQuadraticToCubic, flattenCubic, flattenCubicWithArcLen, flattenQuadratic, flattenQuadraticWithArcLen, forEachSegment, pathCommandCoordCount, quadraticEvalAt, splitCubicAt, splitLineAt, splitQuadraticAt } from './chunk-36DHVSOV.js';
3
- import { PORT_REACH, SINGULAR_RATIO, portControls, cubicAt, sign, len2, dot } from './chunk-3GFNUO4N.js';
4
- export { EPS, PORT_REACH, approxEq, cross, dot, len2, sign, sub } from './chunk-3GFNUO4N.js';
1
+ import { PORT_REACH, portControls, cubicAt } from './chunk-TXEGHCJ4.js';
2
+ export { PORT_REACH } from './chunk-TXEGHCJ4.js';
3
+ import { cubicPointAt } from './chunk-HPVINMOM.js';
4
+ export { cubicPointAt, fitCubicThroughDeletion, splitCubicAtT } from './chunk-HPVINMOM.js';
5
+ import { cubicEvalAt, elevateQuadraticToCubic, cubicBounds } from './chunk-URQMDR6Q.js';
6
+ export { cubicBounds, cubicEvalAt, elevateQuadraticToCubic, quadraticEvalAt, splitCubicAt, splitLineAt, splitQuadraticAt } from './chunk-URQMDR6Q.js';
7
+ import { extractPolylines } from './chunk-6T5I3PR5.js';
8
+ export { boundsOfCoords, boxContainsBox, boxContainsPoint, rectToContour, unionBox } from './chunk-6T5I3PR5.js';
9
+ import { DEFAULT_FLATTEN_TOLERANCE, pointInPolygon, pointSegmentDist2, flattenQuadratic, flattenCubic, segmentsCross } from './chunk-RQYCDPU5.js';
10
+ export { DEFAULT_FLATTEN_TOLERANCE, flattenCubic, flattenCubicWithArcLen, flattenQuadratic, flattenQuadraticWithArcLen, pointInPolygon, pointSegmentDist2, segmentsCross } from './chunk-RQYCDPU5.js';
11
+ import { SINGULAR_RATIO } from './chunk-7ROQRYOA.js';
12
+ export { EPS, approxEq, cross, dot, len2, sign, sub } from './chunk-7ROQRYOA.js';
13
+ import { forEachSegment, PATH_M, PATH_L, PATH_Q, PATH_C, PATH_Z, pathCommandCoordCount } from './chunk-HEZTRG2M.js';
14
+ export { PATH_C, PATH_CMD_LENGTHS, PATH_COMMANDS, PATH_L, PATH_M, PATH_Q, PATH_Z, forEachSegment, pathCommandCoordCount } from './chunk-HEZTRG2M.js';
5
15
 
6
16
  // src/mat3.ts
7
17
  function identity() {
@@ -51,34 +61,6 @@ function rotateAboutPoint(cx, cy, rad) {
51
61
  return multiply(translate(cx, cy), multiply(rotate(rad), translate(-cx, -cy)));
52
62
  }
53
63
 
54
- // src/box.ts
55
- function boundsOfCoords(coords) {
56
- if (coords.length < 2) return null;
57
- let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
58
- for (let i = 0; i + 1 < coords.length; i += 2) {
59
- const x = coords[i], y = coords[i + 1];
60
- if (x < minX) minX = x;
61
- if (y < minY) minY = y;
62
- if (x > maxX) maxX = x;
63
- if (y > maxY) maxY = y;
64
- }
65
- return [minX, minY, maxX, maxY];
66
- }
67
- function unionBox(a, b) {
68
- return [
69
- Math.min(a[0], b[0]),
70
- Math.min(a[1], b[1]),
71
- Math.max(a[2], b[2]),
72
- Math.max(a[3], b[3])
73
- ];
74
- }
75
- function boxContainsPoint(b, x, y) {
76
- return x >= b[0] && x <= b[2] && y >= b[1] && y <= b[3];
77
- }
78
- function rectToContour(x, y, w, h) {
79
- return Float64Array.of(x, y, x + w, y, x + w, y + h, x, y + h);
80
- }
81
-
82
64
  // src/nearest.ts
83
65
  function nearestOnLine(px, py, x0, y0, x1, y1) {
84
66
  const vx = x1 - x0, vy = y1 - y0;
@@ -198,33 +180,221 @@ function portCurvePoints(ax, ay, bx, by, outNormal, inNormal, samples, reach = P
198
180
  return out;
199
181
  }
200
182
 
201
- // src/polyline.ts
202
- function pointInPolygon(coords, px, py, start = 0, end = coords.length >> 1) {
203
- if (end - start < 3) return false;
204
- let inside = false;
205
- for (let i = start, j = end - 1; i < end; j = i++) {
206
- const xi = coords[i * 2], yi = coords[i * 2 + 1];
207
- const xj = coords[j * 2], yj = coords[j * 2 + 1];
208
- const crosses = yi > py !== yj > py && px < (xj - xi) * (py - yi) / (yj - yi) + xi;
209
- if (crosses) inside = !inside;
210
- }
211
- return inside;
212
- }
213
- function segmentsCross(ax, ay, bx, by, cx, cy, dx, dy) {
214
- const d1 = sign((dx - cx) * (ay - cy) - (dy - cy) * (ax - cx));
215
- const d2 = sign((dx - cx) * (by - cy) - (dy - cy) * (bx - cx));
216
- const d3 = sign((bx - ax) * (cy - ay) - (by - ay) * (cx - ax));
217
- const d4 = sign((bx - ax) * (dy - ay) - (by - ay) * (dx - ax));
218
- return d1 !== d2 && d3 !== d4;
219
- }
220
- function pointSegmentDist2(px, py, ax, ay, bx, by) {
221
- const vx = bx - ax, vy = by - ay;
222
- const wx = px - ax, wy = py - ay;
223
- const vv = len2(vx, vy);
224
- let t = vv === 0 ? 0 : dot(wx, wy, vx, vy) / vv;
225
- t = t < 0 ? 0 : t > 1 ? 1 : t;
226
- const dx = px - (ax + t * vx), dy = py - (ay + t * vy);
227
- return len2(dx, dy);
183
+ // src/paths/builder.ts
184
+ var PathBuilder = class _PathBuilder {
185
+ cmds = [];
186
+ xs = [];
187
+ fillRule = "nonzero";
188
+ /** Seed a builder with an existing `PolygonPath`. Useful for extending
189
+ * an in-flight path with another segment (e.g. appending a cubic to
190
+ * the end of a curve in response to a user action) without hand-
191
+ * reaching into the `commands` / `coords` typed arrays.
192
+ *
193
+ * ```ts
194
+ * const next = PathBuilder.fromPath(current).curveTo(...).build();
195
+ * ```
196
+ */
197
+ static fromPath(path) {
198
+ const b = new _PathBuilder();
199
+ b.cmds = Array.from(path.commands);
200
+ b.xs = Array.from(path.coords);
201
+ b.fillRule = path.fillRule;
202
+ return b;
203
+ }
204
+ setFillRule(rule) {
205
+ this.fillRule = rule;
206
+ return this;
207
+ }
208
+ moveTo(x, y) {
209
+ this.cmds.push(PATH_M);
210
+ this.xs.push(x, y);
211
+ return this;
212
+ }
213
+ lineTo(x, y) {
214
+ this.cmds.push(PATH_L);
215
+ this.xs.push(x, y);
216
+ return this;
217
+ }
218
+ /** Cubic bezier to (x, y) with control points (x1, y1) and (x2, y2). */
219
+ curveTo(x1, y1, x2, y2, x, y) {
220
+ this.cmds.push(PATH_C);
221
+ this.xs.push(x1, y1, x2, y2, x, y);
222
+ return this;
223
+ }
224
+ /** Quadratic bezier to (x, y) with control point (x1, y1). */
225
+ quadTo(x1, y1, x, y) {
226
+ this.cmds.push(PATH_Q);
227
+ this.xs.push(x1, y1, x, y);
228
+ return this;
229
+ }
230
+ close() {
231
+ this.cmds.push(PATH_Z);
232
+ return this;
233
+ }
234
+ build() {
235
+ return {
236
+ kind: "polygon",
237
+ commands: new Uint8Array(this.cmds),
238
+ coords: new Float32Array(this.xs),
239
+ fillRule: this.fillRule
240
+ };
241
+ }
242
+ };
243
+ function rectPath(x, y, width, height) {
244
+ return { kind: "rect", x, y, width, height };
245
+ }
246
+ function polylineFromPoints(points) {
247
+ const b = new PathBuilder();
248
+ const first = points[0];
249
+ if (!first) return rectPath(0, 0, 0, 0);
250
+ b.moveTo(first.x, first.y);
251
+ for (let i = 1; i < points.length; i++) {
252
+ const p = points[i];
253
+ if (p) b.lineTo(p.x, p.y);
254
+ }
255
+ return b.build();
256
+ }
257
+ function polygonFromPoints(points, opts = {}) {
258
+ if (points.length === 0) {
259
+ return {
260
+ kind: "polygon",
261
+ commands: new Uint8Array(),
262
+ coords: new Float32Array(),
263
+ fillRule: opts.fillRule ?? "nonzero"
264
+ };
265
+ }
266
+ const b = new PathBuilder();
267
+ if (opts.fillRule) b.setFillRule(opts.fillRule);
268
+ b.moveTo(points[0].x, points[0].y);
269
+ for (let i = 1; i < points.length; i++) b.lineTo(points[i].x, points[i].y);
270
+ b.close();
271
+ return b.build();
272
+ }
273
+ var ELLIPSE_KAPPA = 0.5522847498307936;
274
+ function ellipsePath(bounds) {
275
+ const cx = bounds.x + bounds.width / 2;
276
+ const cy = bounds.y + bounds.height / 2;
277
+ const rx = bounds.width / 2;
278
+ const ry = bounds.height / 2;
279
+ const ox = rx * ELLIPSE_KAPPA;
280
+ const oy = ry * ELLIPSE_KAPPA;
281
+ const b = new PathBuilder();
282
+ b.moveTo(cx + rx, cy);
283
+ b.curveTo(cx + rx, cy + oy, cx + ox, cy + ry, cx, cy + ry);
284
+ b.curveTo(cx - ox, cy + ry, cx - rx, cy + oy, cx - rx, cy);
285
+ b.curveTo(cx - rx, cy - oy, cx - ox, cy - ry, cx, cy - ry);
286
+ b.curveTo(cx + ox, cy - ry, cx + rx, cy - oy, cx + rx, cy);
287
+ b.close();
288
+ return b.build();
289
+ }
290
+ function regularPolygonPath(center, radius, sides, rotation = 0) {
291
+ const b = new PathBuilder();
292
+ for (let i = 0; i < sides; i++) {
293
+ const a = rotation + i / sides * Math.PI * 2;
294
+ const x = center.x + radius * Math.cos(a);
295
+ const y = center.y + radius * Math.sin(a);
296
+ if (i === 0) b.moveTo(x, y);
297
+ else b.lineTo(x, y);
298
+ }
299
+ b.close();
300
+ return b.build();
301
+ }
302
+ function starPath(center, outerRadius, points = 5, innerRadius = outerRadius / 2, rotation = 0) {
303
+ const b = new PathBuilder();
304
+ const n = points * 2;
305
+ for (let i = 0; i < n; i++) {
306
+ const a = rotation + i / n * Math.PI * 2;
307
+ const r = i % 2 === 0 ? outerRadius : innerRadius;
308
+ const x = center.x + r * Math.cos(a);
309
+ const y = center.y + r * Math.sin(a);
310
+ if (i === 0) b.moveTo(x, y);
311
+ else b.lineTo(x, y);
312
+ }
313
+ b.close();
314
+ return b.build();
315
+ }
316
+ function linePath(a, b) {
317
+ const pb = new PathBuilder();
318
+ pb.moveTo(a.x, a.y);
319
+ pb.lineTo(b.x, b.y);
320
+ return pb.build();
321
+ }
322
+
323
+ // src/paths/bounds.ts
324
+ function boundsOfPath(path) {
325
+ if (path.kind === "rect") return path;
326
+ const { commands, coords } = path;
327
+ if (commands.length === 0) {
328
+ return { kind: "rect", x: 0, y: 0, width: 0, height: 0 };
329
+ }
330
+ let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
331
+ let seen = false;
332
+ const include = (x, y) => {
333
+ if (x < minX) minX = x;
334
+ if (x > maxX) maxX = x;
335
+ if (y < minY) minY = y;
336
+ if (y > maxY) maxY = y;
337
+ seen = true;
338
+ };
339
+ forEachSegment(commands, coords, (cmd, ci, px, py) => {
340
+ switch (cmd) {
341
+ case PATH_M:
342
+ case PATH_L: {
343
+ include(coords[ci], coords[ci + 1]);
344
+ break;
345
+ }
346
+ case PATH_C: {
347
+ const [bMinX, bMinY, bMaxX, bMaxY] = cubicBounds(
348
+ px,
349
+ py,
350
+ coords[ci],
351
+ coords[ci + 1],
352
+ coords[ci + 2],
353
+ coords[ci + 3],
354
+ coords[ci + 4],
355
+ coords[ci + 5]
356
+ );
357
+ include(bMinX, bMinY);
358
+ include(bMaxX, bMaxY);
359
+ break;
360
+ }
361
+ case PATH_Q: {
362
+ const qx2 = coords[ci + 2], qy2 = coords[ci + 3];
363
+ const [c1x, c1y, c2x, c2y] = elevateQuadraticToCubic(px, py, coords[ci], coords[ci + 1], qx2, qy2);
364
+ const [bMinX, bMinY, bMaxX, bMaxY] = cubicBounds(px, py, c1x, c1y, c2x, c2y, qx2, qy2);
365
+ include(bMinX, bMinY);
366
+ include(bMaxX, bMaxY);
367
+ break;
368
+ }
369
+ case PATH_Z:
370
+ break;
371
+ default:
372
+ throw new Error(`boundsOfPath: unknown command ${cmd}`);
373
+ }
374
+ });
375
+ if (!seen) return { kind: "rect", x: 0, y: 0, width: 0, height: 0 };
376
+ return { kind: "rect", x: minX, y: minY, width: maxX - minX, height: maxY - minY };
377
+ }
378
+
379
+ // src/paths/unionBoundsPath.ts
380
+ function unionBoundsPath(paths) {
381
+ let minX = Infinity;
382
+ let minY = Infinity;
383
+ let maxX = -Infinity;
384
+ let maxY = -Infinity;
385
+ let any = false;
386
+ for (const p of paths) {
387
+ any = true;
388
+ const b = boundsOfPath(p);
389
+ if (b.x < minX) minX = b.x;
390
+ if (b.y < minY) minY = b.y;
391
+ const right = b.x + b.width;
392
+ const bottom = b.y + b.height;
393
+ if (right > maxX) maxX = right;
394
+ if (bottom > maxY) maxY = bottom;
395
+ }
396
+ if (!any) return null;
397
+ return { kind: "rect", x: minX, y: minY, width: maxX - minX, height: maxY - minY };
228
398
  }
229
399
 
230
400
  // src/affine.ts
@@ -239,6 +409,1146 @@ function transformCoords(coords, m) {
239
409
  return out;
240
410
  }
241
411
 
412
+ // src/paths/transformPath.ts
413
+ function transformPath(path, m) {
414
+ const [a, b, c, d, e, f] = m;
415
+ if (path.kind === "rect") {
416
+ if (b === 0 && c === 0) {
417
+ const x0 = a * path.x + e;
418
+ const y0 = d * path.y + f;
419
+ const x1 = a * (path.x + path.width) + e;
420
+ const y1 = d * (path.y + path.height) + f;
421
+ return {
422
+ kind: "rect",
423
+ x: Math.min(x0, x1),
424
+ y: Math.min(y0, y1),
425
+ width: Math.abs(x1 - x0),
426
+ height: Math.abs(y1 - y0)
427
+ };
428
+ }
429
+ const poly = new PathBuilder().moveTo(path.x, path.y).lineTo(path.x + path.width, path.y).lineTo(path.x + path.width, path.y + path.height).lineTo(path.x, path.y + path.height).close().build();
430
+ return transformPolygon(poly, m);
431
+ }
432
+ return transformPolygon(path, m);
433
+ }
434
+ function transformPolygon(path, m) {
435
+ const mapped = transformCoords(path.coords, m);
436
+ return { ...path, coords: Float32Array.from(mapped) };
437
+ }
438
+
439
+ // src/paths/transform.ts
440
+ function translatePath(path, dx, dy) {
441
+ if (path.kind === "rect") {
442
+ return { kind: "rect", x: path.x + dx, y: path.y + dy, width: path.width, height: path.height };
443
+ }
444
+ return translatePolygonCopy(path, dx, dy);
445
+ }
446
+ function translatePolygonCopy(path, dx, dy) {
447
+ const next = new Float32Array(path.coords.length);
448
+ const { commands, coords } = path;
449
+ forEachSegment(commands, coords, (cmd, ci) => {
450
+ for (let k = 0, len = pathCommandCoordCount(cmd); k < len; k += 2) {
451
+ next[ci + k] = coords[ci + k] + dx;
452
+ next[ci + k + 1] = coords[ci + k + 1] + dy;
453
+ }
454
+ });
455
+ return { kind: "polygon", commands: path.commands, coords: next, fillRule: path.fillRule };
456
+ }
457
+ function scalePathToBounds(path, target) {
458
+ if (path.kind === "rect") {
459
+ return { kind: "rect", x: target.x, y: target.y, width: target.width, height: target.height };
460
+ }
461
+ const src = boundsOfPath(path);
462
+ return scalePolygon(path, src, target);
463
+ }
464
+ function scalePolygon(path, src, dst) {
465
+ const m = boxToBox(src.x, src.y, src.width, src.height, dst.x, dst.y, dst.width, dst.height);
466
+ return transformPath(path, m);
467
+ }
468
+
469
+ // src/paths/compose.ts
470
+ function composePath(parent, child) {
471
+ const origin = pathOrigin(parent);
472
+ return translatePath(child, origin.x, origin.y);
473
+ }
474
+ function decomposePath(parent, world) {
475
+ const origin = pathOrigin(parent);
476
+ return translatePath(world, -origin.x, -origin.y);
477
+ }
478
+ function pathOrigin(path) {
479
+ if (path.kind === "rect") return { x: path.x, y: path.y };
480
+ let minX = Infinity;
481
+ let minY = Infinity;
482
+ const { coords } = path;
483
+ for (let i = 0; i < coords.length; i += 2) {
484
+ if (coords[i] < minX) minX = coords[i];
485
+ if (coords[i + 1] < minY) minY = coords[i + 1];
486
+ }
487
+ if (minX === Infinity) return { x: 0, y: 0 };
488
+ return { x: minX, y: minY };
489
+ }
490
+
491
+ // src/paths/splitSubpaths.ts
492
+ function splitSubpaths(path) {
493
+ const { commands, coords, fillRule } = path;
494
+ const out = [];
495
+ let cmdStart = 0;
496
+ let coordStart = 0;
497
+ forEachSegment(commands, coords, (cmd, ci, _px, _py, i) => {
498
+ if (cmd !== PATH_M || i <= cmdStart) return;
499
+ out.push({
500
+ kind: "polygon",
501
+ commands: commands.slice(cmdStart, i),
502
+ coords: coords.slice(coordStart, ci),
503
+ fillRule
504
+ });
505
+ cmdStart = i;
506
+ coordStart = ci;
507
+ });
508
+ out.push({
509
+ kind: "polygon",
510
+ commands: commands.slice(cmdStart),
511
+ coords: coords.slice(coordStart),
512
+ fillRule
513
+ });
514
+ return out;
515
+ }
516
+
517
+ // src/paths/winding.ts
518
+ var GL_T = [0.5 - Math.sqrt(15) / 10, 0.5, 0.5 + Math.sqrt(15) / 10];
519
+ var GL_W = [5 / 18, 8 / 18, 5 / 18];
520
+ function pathSignedArea(path) {
521
+ if (path.kind === "rect") return path.width * path.height;
522
+ const { commands, coords } = path;
523
+ let twice = 0;
524
+ let startX = 0, startY = 0;
525
+ let open = false;
526
+ let endX = 0, endY = 0;
527
+ const close = () => {
528
+ if (open) twice += endX * startY - startX * endY;
529
+ open = false;
530
+ };
531
+ forEachSegment(commands, coords, (cmd, ci, px, py) => {
532
+ if (cmd === PATH_M) {
533
+ close();
534
+ startX = endX = coords[ci];
535
+ startY = endY = coords[ci + 1];
536
+ open = true;
537
+ return;
538
+ }
539
+ if (cmd === PATH_Z) {
540
+ close();
541
+ endX = startX;
542
+ endY = startY;
543
+ return;
544
+ }
545
+ if (!open) {
546
+ startX = px;
547
+ startY = py;
548
+ open = true;
549
+ }
550
+ if (cmd === PATH_L) {
551
+ endX = coords[ci];
552
+ endY = coords[ci + 1];
553
+ twice += px * endY - endX * py;
554
+ return;
555
+ }
556
+ const cubic = cmd === PATH_C;
557
+ const x1 = coords[ci], y1 = coords[ci + 1];
558
+ const x2 = coords[ci + 2], y2 = coords[ci + 3];
559
+ const x3 = cubic ? coords[ci + 4] : x2, y3 = cubic ? coords[ci + 5] : y2;
560
+ for (let k = 0; k < 3; k++) {
561
+ const t = GL_T[k], u = 1 - t;
562
+ let x, y, dx, dy;
563
+ if (cubic) {
564
+ x = u * u * u * px + 3 * u * u * t * x1 + 3 * u * t * t * x2 + t * t * t * x3;
565
+ y = u * u * u * py + 3 * u * u * t * y1 + 3 * u * t * t * y2 + t * t * t * y3;
566
+ dx = 3 * (u * u * (x1 - px) + 2 * u * t * (x2 - x1) + t * t * (x3 - x2));
567
+ dy = 3 * (u * u * (y1 - py) + 2 * u * t * (y2 - y1) + t * t * (y3 - y2));
568
+ } else {
569
+ x = u * u * px + 2 * u * t * x1 + t * t * x2;
570
+ y = u * u * py + 2 * u * t * y1 + t * t * y2;
571
+ dx = 2 * (u * (x1 - px) + t * (x2 - x1));
572
+ dy = 2 * (u * (y1 - py) + t * (y2 - y1));
573
+ }
574
+ twice += GL_W[k] * (x * dy - y * dx);
575
+ }
576
+ endX = x3;
577
+ endY = y3;
578
+ });
579
+ close();
580
+ return twice / 2;
581
+ }
582
+ function reversePath(path) {
583
+ const cmds = [];
584
+ const out = [];
585
+ let segs = [];
586
+ let sx = 0, sy = 0;
587
+ let started = false;
588
+ const flush = (closed) => {
589
+ if (!started) return;
590
+ const last = segs[segs.length - 1];
591
+ const ex = last ? last.args[last.args.length - 2] : sx;
592
+ const ey = last ? last.args[last.args.length - 1] : sy;
593
+ if (closed) {
594
+ cmds.push(PATH_M);
595
+ out.push(sx, sy);
596
+ if (ex !== sx || ey !== sy) {
597
+ cmds.push(PATH_L);
598
+ out.push(ex, ey);
599
+ }
600
+ } else {
601
+ cmds.push(PATH_M);
602
+ out.push(ex, ey);
603
+ }
604
+ for (let i = segs.length - 1; i >= 0; i--) {
605
+ const s = segs[i];
606
+ cmds.push(s.cmd);
607
+ if (s.cmd === PATH_C) out.push(s.args[2], s.args[3], s.args[0], s.args[1]);
608
+ else if (s.cmd === PATH_Q) out.push(s.args[0], s.args[1]);
609
+ out.push(s.fromX, s.fromY);
610
+ }
611
+ if (closed) cmds.push(PATH_Z);
612
+ segs = [];
613
+ started = false;
614
+ };
615
+ const { commands, coords } = path;
616
+ forEachSegment(commands, coords, (cmd, ci, px, py) => {
617
+ if (cmd === PATH_M) {
618
+ flush(false);
619
+ sx = coords[ci];
620
+ sy = coords[ci + 1];
621
+ started = true;
622
+ return;
623
+ }
624
+ if (cmd === PATH_Z) {
625
+ flush(true);
626
+ return;
627
+ }
628
+ if (!started) {
629
+ sx = px;
630
+ sy = py;
631
+ started = true;
632
+ }
633
+ const n = cmd === PATH_C ? 6 : cmd === PATH_Q ? 4 : 2;
634
+ segs.push({ cmd, args: Array.from(coords.subarray(ci, ci + n)), fromX: px, fromY: py });
635
+ });
636
+ flush(false);
637
+ return {
638
+ kind: "polygon",
639
+ commands: new Uint8Array(cmds),
640
+ coords: new Float32Array(out),
641
+ fillRule: path.fillRule
642
+ };
643
+ }
644
+
645
+ // src/paths/pathFromD.ts
646
+ var NUM_RE = /[+-]?(?:\d*\.\d+|\d+\.?)(?:[eE][+-]?\d+)?/g;
647
+ var NUM_RE_AT = /[+-]?(?:\d*\.\d+|\d+\.?)(?:[eE][+-]?\d+)?/y;
648
+ function isCommandLetter(d, j) {
649
+ const c = d[j];
650
+ if (!/[A-Za-z]/.test(c)) return false;
651
+ if (c !== "e" && c !== "E") return true;
652
+ if (!/[\d.]/.test(d[j - 1] ?? "")) return true;
653
+ const k = d[j + 1] === "+" || d[j + 1] === "-" ? j + 2 : j + 1;
654
+ return !/\d/.test(d[k] ?? "");
655
+ }
656
+ function tokenize(d) {
657
+ const out = [];
658
+ let i = 0;
659
+ while (i < d.length) {
660
+ if (isCommandLetter(d, i)) {
661
+ let j = i + 1;
662
+ while (j < d.length && !isCommandLetter(d, j)) j++;
663
+ const argSlice = d.slice(i + 1, j);
664
+ const cmd = d[i];
665
+ out.push({
666
+ cmd,
667
+ args: cmd === "A" || cmd === "a" ? readArcArgs(argSlice) : readNumbers(argSlice)
668
+ });
669
+ i = j;
670
+ } else {
671
+ i++;
672
+ }
673
+ }
674
+ return out;
675
+ }
676
+ function readNumbers(s) {
677
+ const out = [];
678
+ let m;
679
+ NUM_RE.lastIndex = 0;
680
+ while ((m = NUM_RE.exec(s)) !== null) {
681
+ const n = Number(m[0]);
682
+ if (Number.isFinite(n)) out.push(n);
683
+ }
684
+ return out;
685
+ }
686
+ function readArcArgs(s) {
687
+ const out = [];
688
+ let i = 0;
689
+ while (i < s.length) {
690
+ const c = s[i];
691
+ if (c === "," || c === " " || c === " " || c === "\n" || c === "\r") {
692
+ i++;
693
+ continue;
694
+ }
695
+ const slot = out.length % 7;
696
+ if (slot === 3 || slot === 4) {
697
+ if (c !== "0" && c !== "1") return out;
698
+ out.push(c === "1" ? 1 : 0);
699
+ i++;
700
+ continue;
701
+ }
702
+ NUM_RE_AT.lastIndex = i;
703
+ const m = NUM_RE_AT.exec(s);
704
+ if (!m) return out;
705
+ out.push(Number(m[0]));
706
+ i = NUM_RE_AT.lastIndex;
707
+ }
708
+ return out;
709
+ }
710
+ var ARG_COUNTS = {
711
+ M: 2,
712
+ L: 2,
713
+ H: 1,
714
+ V: 1,
715
+ C: 6,
716
+ S: 4,
717
+ Q: 4,
718
+ T: 2,
719
+ A: 7,
720
+ Z: 0
721
+ };
722
+ function pathFromD(d, onWarn) {
723
+ const tokens = tokenize(d);
724
+ const b = new PathBuilder();
725
+ const st = {
726
+ x: 0,
727
+ y: 0,
728
+ startX: 0,
729
+ startY: 0,
730
+ lastCubicCtrl: null,
731
+ lastQuadCtrl: null
732
+ };
733
+ for (const { cmd, args } of tokens) {
734
+ const upper = cmd.toUpperCase();
735
+ const relative = cmd !== upper;
736
+ const argCount = ARG_COUNTS[upper];
737
+ if (argCount === void 0) {
738
+ onWarn?.(`unknown path command: ${cmd}`);
739
+ continue;
740
+ }
741
+ if (upper === "Z") {
742
+ b.close();
743
+ st.x = st.startX;
744
+ st.y = st.startY;
745
+ st.lastCubicCtrl = null;
746
+ st.lastQuadCtrl = null;
747
+ continue;
748
+ }
749
+ const groups = argCount === 0 ? 1 : Math.floor(args.length / argCount);
750
+ for (let g = 0; g < groups; g++) {
751
+ const a = args.slice(g * argCount, (g + 1) * argCount);
752
+ const effectiveUpper = upper === "M" && g > 0 ? "L" : upper;
753
+ runCommand(effectiveUpper, relative, a, st, b);
754
+ }
755
+ }
756
+ return b.build();
757
+ }
758
+ function runCommand(upper, relative, a, st, b) {
759
+ const rx = relative ? st.x : 0;
760
+ const ry = relative ? st.y : 0;
761
+ switch (upper) {
762
+ case "M": {
763
+ const x = a[0] + rx;
764
+ const y = a[1] + ry;
765
+ b.moveTo(x, y);
766
+ st.x = x;
767
+ st.y = y;
768
+ st.startX = x;
769
+ st.startY = y;
770
+ st.lastCubicCtrl = null;
771
+ st.lastQuadCtrl = null;
772
+ return;
773
+ }
774
+ case "L": {
775
+ const x = a[0] + rx;
776
+ const y = a[1] + ry;
777
+ b.lineTo(x, y);
778
+ st.x = x;
779
+ st.y = y;
780
+ st.lastCubicCtrl = null;
781
+ st.lastQuadCtrl = null;
782
+ return;
783
+ }
784
+ case "H": {
785
+ const x = a[0] + (relative ? st.x : 0);
786
+ b.lineTo(x, st.y);
787
+ st.x = x;
788
+ st.lastCubicCtrl = null;
789
+ st.lastQuadCtrl = null;
790
+ return;
791
+ }
792
+ case "V": {
793
+ const y = a[0] + (relative ? st.y : 0);
794
+ b.lineTo(st.x, y);
795
+ st.y = y;
796
+ st.lastCubicCtrl = null;
797
+ st.lastQuadCtrl = null;
798
+ return;
799
+ }
800
+ case "C": {
801
+ const x1 = a[0] + rx, y1 = a[1] + ry;
802
+ const x2 = a[2] + rx, y2 = a[3] + ry;
803
+ const x = a[4] + rx, y = a[5] + ry;
804
+ b.curveTo(x1, y1, x2, y2, x, y);
805
+ st.x = x;
806
+ st.y = y;
807
+ st.lastCubicCtrl = { x: x2, y: y2 };
808
+ st.lastQuadCtrl = null;
809
+ return;
810
+ }
811
+ case "S": {
812
+ const ref = st.lastCubicCtrl ?? { x: st.x, y: st.y };
813
+ const x1 = 2 * st.x - ref.x;
814
+ const y1 = 2 * st.y - ref.y;
815
+ const x2 = a[0] + rx, y2 = a[1] + ry;
816
+ const x = a[2] + rx, y = a[3] + ry;
817
+ b.curveTo(x1, y1, x2, y2, x, y);
818
+ st.x = x;
819
+ st.y = y;
820
+ st.lastCubicCtrl = { x: x2, y: y2 };
821
+ st.lastQuadCtrl = null;
822
+ return;
823
+ }
824
+ case "Q": {
825
+ const x1 = a[0] + rx, y1 = a[1] + ry;
826
+ const x = a[2] + rx, y = a[3] + ry;
827
+ b.quadTo(x1, y1, x, y);
828
+ st.x = x;
829
+ st.y = y;
830
+ st.lastQuadCtrl = { x: x1, y: y1 };
831
+ st.lastCubicCtrl = null;
832
+ return;
833
+ }
834
+ case "T": {
835
+ const ref = st.lastQuadCtrl ?? { x: st.x, y: st.y };
836
+ const x1 = 2 * st.x - ref.x;
837
+ const y1 = 2 * st.y - ref.y;
838
+ const x = a[0] + rx, y = a[1] + ry;
839
+ b.quadTo(x1, y1, x, y);
840
+ st.x = x;
841
+ st.y = y;
842
+ st.lastQuadCtrl = { x: x1, y: y1 };
843
+ st.lastCubicCtrl = null;
844
+ return;
845
+ }
846
+ case "A": {
847
+ const rxA = Math.abs(a[0]);
848
+ const ryA = Math.abs(a[1]);
849
+ const xRot = a[2];
850
+ const largeArc = a[3] !== 0;
851
+ const sweep = a[4] !== 0;
852
+ const ex = a[5] + rx;
853
+ const ey = a[6] + ry;
854
+ arcToCubics(st.x, st.y, ex, ey, rxA, ryA, xRot, largeArc, sweep, b);
855
+ st.x = ex;
856
+ st.y = ey;
857
+ st.lastCubicCtrl = null;
858
+ st.lastQuadCtrl = null;
859
+ return;
860
+ }
861
+ default:
862
+ return;
863
+ }
864
+ }
865
+ function arcToCubics(x1, y1, x2, y2, rx, ry, xAxisRotationDeg, largeArc, sweep, b) {
866
+ if (x1 === x2 && y1 === y2) return;
867
+ if (rx === 0 || ry === 0) {
868
+ b.lineTo(x2, y2);
869
+ return;
870
+ }
871
+ const phi = xAxisRotationDeg * Math.PI / 180;
872
+ const cosPhi = Math.cos(phi);
873
+ const sinPhi = Math.sin(phi);
874
+ const dx = (x1 - x2) / 2;
875
+ const dy = (y1 - y2) / 2;
876
+ const x1p = cosPhi * dx + sinPhi * dy;
877
+ const y1p = -sinPhi * dx + cosPhi * dy;
878
+ let rxs = rx * rx;
879
+ let rys = ry * ry;
880
+ const x1ps = x1p * x1p;
881
+ const y1ps = y1p * y1p;
882
+ const lambda = x1ps / rxs + y1ps / rys;
883
+ let rxFixed = rx;
884
+ let ryFixed = ry;
885
+ if (lambda > 1) {
886
+ const sqrtLambda = Math.sqrt(lambda);
887
+ rxFixed = sqrtLambda * rx;
888
+ ryFixed = sqrtLambda * ry;
889
+ rxs = rxFixed * rxFixed;
890
+ rys = ryFixed * ryFixed;
891
+ }
892
+ const sign2 = largeArc === sweep ? -1 : 1;
893
+ const num = rxs * rys - rxs * y1ps - rys * x1ps;
894
+ const den = rxs * y1ps + rys * x1ps;
895
+ const factor = sign2 * Math.sqrt(Math.max(0, num / den));
896
+ const cxp = factor * (rxFixed * y1p) / ryFixed;
897
+ const cyp = factor * -(ryFixed * x1p) / rxFixed;
898
+ const cx = cosPhi * cxp - sinPhi * cyp + (x1 + x2) / 2;
899
+ const cy = sinPhi * cxp + cosPhi * cyp + (y1 + y2) / 2;
900
+ const angle = (ux, uy, vx, vy) => {
901
+ const dot2 = ux * vx + uy * vy;
902
+ const len = Math.sqrt((ux * ux + uy * uy) * (vx * vx + vy * vy));
903
+ let a = Math.acos(Math.max(-1, Math.min(1, dot2 / len)));
904
+ if (ux * vy - uy * vx < 0) a = -a;
905
+ return a;
906
+ };
907
+ const theta1 = angle(1, 0, (x1p - cxp) / rxFixed, (y1p - cyp) / ryFixed);
908
+ let dTheta = angle(
909
+ (x1p - cxp) / rxFixed,
910
+ (y1p - cyp) / ryFixed,
911
+ (-x1p - cxp) / rxFixed,
912
+ (-y1p - cyp) / ryFixed
913
+ );
914
+ if (!sweep && dTheta > 0) dTheta -= 2 * Math.PI;
915
+ else if (sweep && dTheta < 0) dTheta += 2 * Math.PI;
916
+ const segCount = Math.max(1, Math.ceil(Math.abs(dTheta) / (Math.PI / 2)));
917
+ const segAngle = dTheta / segCount;
918
+ const t = 4 / 3 * Math.tan(segAngle / 4);
919
+ let prevX = x1;
920
+ let prevY = y1;
921
+ let prevDx = -Math.sin(theta1) * rxFixed;
922
+ let prevDy = Math.cos(theta1) * ryFixed;
923
+ for (let i = 1; i <= segCount; i++) {
924
+ const theta = theta1 + i * segAngle;
925
+ const cosT = Math.cos(theta);
926
+ const sinT = Math.sin(theta);
927
+ const px = cosPhi * (cosT * rxFixed) - sinPhi * (sinT * ryFixed) + cx;
928
+ const py = sinPhi * (cosT * rxFixed) + cosPhi * (sinT * ryFixed) + cy;
929
+ const dxNew = -sinT * rxFixed;
930
+ const dyNew = cosT * ryFixed;
931
+ const c1x = prevX + cosPhi * (t * prevDx) - sinPhi * (t * prevDy);
932
+ const c1y = prevY + sinPhi * (t * prevDx) + cosPhi * (t * prevDy);
933
+ const c2x = px - cosPhi * (t * dxNew) + sinPhi * (t * dyNew);
934
+ const c2y = py - sinPhi * (t * dxNew) - cosPhi * (t * dyNew);
935
+ b.curveTo(c1x, c1y, c2x, c2y, px, py);
936
+ prevX = px;
937
+ prevY = py;
938
+ prevDx = dxNew;
939
+ prevDy = dyNew;
940
+ }
941
+ }
942
+
943
+ // src/paths/pathAt.ts
944
+ function pointAlongPath(path, t, opts = {}) {
945
+ const polylines = extractPolylines(
946
+ path,
947
+ opts.flattenTolerance === void 0 ? {} : { flattenTolerance: opts.flattenTolerance }
948
+ );
949
+ const segments = [];
950
+ let total = 0;
951
+ let first;
952
+ for (const pl of polylines) {
953
+ const count = pl.points.length / 2;
954
+ if (count === 0) continue;
955
+ first ??= { x: pl.points[0], y: pl.points[1] };
956
+ const last2 = pl.closed ? count : count - 1;
957
+ for (let i = 0; i < last2; i++) {
958
+ const j = (i + 1) % count;
959
+ const ax = pl.points[i * 2];
960
+ const ay = pl.points[i * 2 + 1];
961
+ const bx = pl.points[j * 2];
962
+ const by = pl.points[j * 2 + 1];
963
+ const len = Math.hypot(bx - ax, by - ay);
964
+ if (len === 0) continue;
965
+ segments.push({ ax, ay, bx, by, len });
966
+ total += len;
967
+ }
968
+ }
969
+ if (first === void 0) return null;
970
+ if (segments.length === 0) return { point: first, tangent: { x: 1, y: 0 } };
971
+ const target = Math.min(Math.max(t, 0), 1) * total;
972
+ let walked = 0;
973
+ for (const seg of segments) {
974
+ if (walked + seg.len < target) {
975
+ walked += seg.len;
976
+ continue;
977
+ }
978
+ const u = (target - walked) / seg.len;
979
+ return {
980
+ point: { x: seg.ax + (seg.bx - seg.ax) * u, y: seg.ay + (seg.by - seg.ay) * u },
981
+ tangent: { x: (seg.bx - seg.ax) / seg.len, y: (seg.by - seg.ay) / seg.len }
982
+ };
983
+ }
984
+ const last = segments[segments.length - 1];
985
+ return {
986
+ point: { x: last.bx, y: last.by },
987
+ tangent: { x: (last.bx - last.ax) / last.len, y: (last.by - last.ay) / last.len }
988
+ };
989
+ }
990
+
991
+ // src/paths/pathDistance.ts
992
+ function pointToRectPerimeterDist(px, py, rx, ry, rw, rh) {
993
+ const dx = Math.max(rx - px, px - (rx + rw), 0);
994
+ const dy = Math.max(ry - py, py - (ry + rh), 0);
995
+ if (dx > 0 || dy > 0) return Math.hypot(dx, dy);
996
+ const left = px - rx, right = rx + rw - px;
997
+ const top = py - ry, bottom = ry + rh - py;
998
+ return Math.min(left, right, top, bottom);
999
+ }
1000
+ function pathDistanceToPoint(path, px, py) {
1001
+ if (path.kind === "rect") {
1002
+ return pointToRectPerimeterDist(px, py, path.x, path.y, path.width, path.height);
1003
+ }
1004
+ return nearestOnPath(path.commands, path.coords, px, py)?.dist ?? Infinity;
1005
+ }
1006
+
1007
+ // src/paths/schneiderFit.ts
1008
+ function schneiderFit(samples, errorTolerance) {
1009
+ if (samples.length === 0) {
1010
+ return {
1011
+ kind: "polygon",
1012
+ commands: new Uint8Array(),
1013
+ coords: new Float32Array(),
1014
+ fillRule: "nonzero"
1015
+ };
1016
+ }
1017
+ const b = new PathBuilder();
1018
+ b.moveTo(samples[0].x, samples[0].y);
1019
+ if (samples.length === 1) {
1020
+ return b.build();
1021
+ }
1022
+ if (samples.length === 2) {
1023
+ emitStraightCubic(b, samples[0], samples[1]);
1024
+ return b.build();
1025
+ }
1026
+ fitRecursive(samples, errorTolerance, b);
1027
+ return b.build();
1028
+ }
1029
+ function fitRecursive(samples, errorTolerance, b) {
1030
+ if (samples.length === 2) {
1031
+ const fit2 = fitOneCubic(samples);
1032
+ b.curveTo(fit2.cp1.x, fit2.cp1.y, fit2.cp2.x, fit2.cp2.y, fit2.end.x, fit2.end.y);
1033
+ return;
1034
+ }
1035
+ const fit = fitOneCubic(samples);
1036
+ const { worstIndex, worstError } = measureError(samples, fit);
1037
+ if (worstError <= errorTolerance * errorTolerance) {
1038
+ b.curveTo(fit.cp1.x, fit.cp1.y, fit.cp2.x, fit.cp2.y, fit.end.x, fit.end.y);
1039
+ return;
1040
+ }
1041
+ const left = samples.slice(0, worstIndex + 1);
1042
+ const right = samples.slice(worstIndex);
1043
+ fitRecursive(left, errorTolerance, b);
1044
+ fitRecursive(right, errorTolerance, b);
1045
+ }
1046
+ function measureError(samples, fit) {
1047
+ let worstIndex = 1;
1048
+ let worstError = 0;
1049
+ const a = samples[0];
1050
+ for (let i = 1; i < samples.length - 1; i++) {
1051
+ const t = i / (samples.length - 1);
1052
+ const q = cubicPointAt(a, fit.cp1, fit.cp2, fit.end, t);
1053
+ const dx = samples[i].x - q.x;
1054
+ const dy = samples[i].y - q.y;
1055
+ const sq = dx * dx + dy * dy;
1056
+ if (sq > worstError) {
1057
+ worstError = sq;
1058
+ worstIndex = i;
1059
+ }
1060
+ }
1061
+ return { worstIndex, worstError };
1062
+ }
1063
+ function fitOneCubic(samples) {
1064
+ const n = samples.length;
1065
+ const a = samples[0];
1066
+ const e = samples[n - 1];
1067
+ const tStart = unit(sub2(samples[1], a));
1068
+ const tEnd = unit(sub2(samples[n - 2], e));
1069
+ const ts = chordLengthParam(samples);
1070
+ if (ts === null) return { cp1: { ...a }, cp2: { ...e }, end: e };
1071
+ let fit = solveLS(samples, ts, a, e, tStart, tEnd);
1072
+ for (let pass = 0; pass < 4; pass++) {
1073
+ reparameterize(samples, ts, a, e, fit);
1074
+ fit = solveLS(samples, ts, a, e, tStart, tEnd);
1075
+ }
1076
+ return fit;
1077
+ }
1078
+ function chordLengthParam(samples) {
1079
+ const n = samples.length;
1080
+ const ts = new Array(n);
1081
+ ts[0] = 0;
1082
+ let total = 0;
1083
+ for (let i = 1; i < n; i++) {
1084
+ total += dist(samples[i - 1], samples[i]);
1085
+ ts[i] = total;
1086
+ }
1087
+ if (total === 0) return null;
1088
+ for (let i = 0; i < n; i++) ts[i] /= total;
1089
+ return ts;
1090
+ }
1091
+ function solveLS(samples, ts, a, e, tStart, tEnd) {
1092
+ const n = samples.length;
1093
+ let c11 = 0, c12 = 0, c22 = 0, x1 = 0, x2 = 0;
1094
+ for (let i = 0; i < n; i++) {
1095
+ const t = ts[i];
1096
+ const u = 1 - t;
1097
+ const b0 = u * u * u;
1098
+ const b1 = 3 * u * u * t;
1099
+ const b2 = 3 * u * t * t;
1100
+ const b3 = t * t * t;
1101
+ const A1x = b1 * tStart.x;
1102
+ const A1y = b1 * tStart.y;
1103
+ const A2x = b2 * tEnd.x;
1104
+ const A2y = b2 * tEnd.y;
1105
+ c11 += A1x * A1x + A1y * A1y;
1106
+ c12 += A1x * A2x + A1y * A2y;
1107
+ c22 += A2x * A2x + A2y * A2y;
1108
+ const targetX = samples[i].x - (b0 + b1) * a.x - (b2 + b3) * e.x;
1109
+ const targetY = samples[i].y - (b0 + b1) * a.y - (b2 + b3) * e.y;
1110
+ x1 += A1x * targetX + A1y * targetY;
1111
+ x2 += A2x * targetX + A2y * targetY;
1112
+ }
1113
+ const det = c11 * c22 - c12 * c12;
1114
+ let alpha1;
1115
+ let alpha2;
1116
+ if (Math.abs(det) < 1e-12) {
1117
+ const chord = dist(a, e);
1118
+ alpha1 = alpha2 = chord / 3;
1119
+ } else {
1120
+ alpha1 = (c22 * x1 - c12 * x2) / det;
1121
+ alpha2 = (c11 * x2 - c12 * x1) / det;
1122
+ if (alpha1 < 1e-6 || alpha2 < 1e-6) {
1123
+ const chord = dist(a, e);
1124
+ alpha1 = alpha2 = chord / 3;
1125
+ }
1126
+ }
1127
+ return {
1128
+ cp1: { x: a.x + tStart.x * alpha1, y: a.y + tStart.y * alpha1 },
1129
+ cp2: { x: e.x + tEnd.x * alpha2, y: e.y + tEnd.y * alpha2 },
1130
+ end: e
1131
+ };
1132
+ }
1133
+ function reparameterize(samples, ts, a, e, fit) {
1134
+ for (let i = 1; i < samples.length - 1; i++) {
1135
+ ts[i] = newtonRefineT(samples[i], ts[i], samples[0], fit.cp1, fit.cp2, samples[samples.length - 1]);
1136
+ }
1137
+ }
1138
+ function newtonRefineT(p, t, p0, p1, p2, p3) {
1139
+ const u = 1 - t;
1140
+ const { x: qx, y: qy } = cubicPointAt(p0, p1, p2, p3, t);
1141
+ const qpx = 3 * u * u * (p1.x - p0.x) + 6 * u * t * (p2.x - p1.x) + 3 * t * t * (p3.x - p2.x);
1142
+ const qpy = 3 * u * u * (p1.y - p0.y) + 6 * u * t * (p2.y - p1.y) + 3 * t * t * (p3.y - p2.y);
1143
+ const qppx = 6 * u * (p2.x - 2 * p1.x + p0.x) + 6 * t * (p3.x - 2 * p2.x + p1.x);
1144
+ const qppy = 6 * u * (p2.y - 2 * p1.y + p0.y) + 6 * t * (p3.y - 2 * p2.y + p1.y);
1145
+ const dx = qx - p.x;
1146
+ const dy = qy - p.y;
1147
+ const numerator = dx * qpx + dy * qpy;
1148
+ const denominator = qpx * qpx + qpy * qpy + dx * qppx + dy * qppy;
1149
+ if (Math.abs(denominator) < 1e-12) return t;
1150
+ const next = t - numerator / denominator;
1151
+ if (next < 0) return 0;
1152
+ if (next > 1) return 1;
1153
+ return next;
1154
+ }
1155
+ function sub2(a, b) {
1156
+ return { x: a.x - b.x, y: a.y - b.y };
1157
+ }
1158
+ function dist(a, b) {
1159
+ return Math.hypot(a.x - b.x, a.y - b.y);
1160
+ }
1161
+ function unit(v) {
1162
+ const m = Math.hypot(v.x, v.y);
1163
+ if (m === 0) return { x: 0, y: 0 };
1164
+ return { x: v.x / m, y: v.y / m };
1165
+ }
1166
+ function emitStraightCubic(b, a, c) {
1167
+ const cp1x = a.x + (c.x - a.x) / 3;
1168
+ const cp1y = a.y + (c.y - a.y) / 3;
1169
+ const cp2x = a.x + 2 * (c.x - a.x) / 3;
1170
+ const cp2y = a.y + 2 * (c.y - a.y) / 3;
1171
+ b.curveTo(cp1x, cp1y, cp2x, cp2y, c.x, c.y);
1172
+ }
1173
+
1174
+ // src/screenBand.ts
1175
+ function stretchOf(m) {
1176
+ const e = (m.a + m.d) / 2;
1177
+ const f = (m.a - m.d) / 2;
1178
+ const g = (m.b + m.c) / 2;
1179
+ const h = (m.b - m.c) / 2;
1180
+ const q = Math.hypot(e, h);
1181
+ const r = Math.hypot(f, g);
1182
+ const phi = (Math.atan2(h, e) + Math.atan2(g, f)) / 2;
1183
+ return { s1: q + r, s2: Math.abs(q - r), phi };
1184
+ }
1185
+ function isSimilarity(s) {
1186
+ return s.s1 - s.s2 <= 1e-9 * s.s1;
1187
+ }
1188
+ function capsuleWithinPx(px0, py0, ax, ay, bx, by, r, slop, m, st) {
1189
+ const sax = m.a * ax + m.c * ay, say = m.b * ax + m.d * ay;
1190
+ const sbx = m.a * bx + m.c * by, sby = m.b * bx + m.d * by;
1191
+ const slop2 = slop * slop;
1192
+ const dCenter2 = pointSegmentDist2(px0, py0, sax, say, sbx, sby);
1193
+ if (dCenter2 <= slop2) return true;
1194
+ if (r <= 0) return false;
1195
+ const reach = slop + r * st.s1;
1196
+ if (dCenter2 > reach * reach) return false;
1197
+ const wx = bx - ax, wy = by - ay;
1198
+ const wl = Math.hypot(wx, wy);
1199
+ if (wl > 0) {
1200
+ const nx = -wy / wl * r, ny = wx / wl * r;
1201
+ const ox = m.a * nx + m.c * ny, oy = m.b * nx + m.d * ny;
1202
+ if (quadWithinPx(px0, py0, [
1203
+ sax + ox,
1204
+ say + oy,
1205
+ sbx + ox,
1206
+ sby + oy,
1207
+ sbx - ox,
1208
+ sby - oy,
1209
+ sax - ox,
1210
+ say - oy
1211
+ ], slop2)) return true;
1212
+ }
1213
+ return ellipseWithinPx(px0 - sax, py0 - say, r, slop, st) || ellipseWithinPx(px0 - sbx, py0 - sby, r, slop, st);
1214
+ }
1215
+ function quadWithinPx(x, y, q, slop2) {
1216
+ let pos = 0, neg = 0;
1217
+ for (let i = 0; i < 8; i += 2) {
1218
+ const j = (i + 2) % 8;
1219
+ const cr = (q[j] - q[i]) * (y - q[i + 1]) - (q[j + 1] - q[i + 1]) * (x - q[i]);
1220
+ if (cr > 0) pos++;
1221
+ else if (cr < 0) neg++;
1222
+ }
1223
+ if (pos === 0 || neg === 0) return true;
1224
+ for (let i = 0; i < 8; i += 2) {
1225
+ const j = (i + 2) % 8;
1226
+ if (pointSegmentDist2(x, y, q[i], q[i + 1], q[j], q[j + 1]) <= slop2) return true;
1227
+ }
1228
+ return false;
1229
+ }
1230
+ function ellipseWithinPx(dx, dy, r, slop, st) {
1231
+ const cos = Math.cos(st.phi), sin = Math.sin(st.phi);
1232
+ const u = Math.abs(cos * dx + sin * dy);
1233
+ const v = Math.abs(-sin * dx + cos * dy);
1234
+ const e0 = r * st.s1, e1 = r * st.s2;
1235
+ if (e1 <= 0) {
1236
+ const over = Math.max(0, u - e0);
1237
+ return over * over + v * v <= slop * slop;
1238
+ }
1239
+ return distToEllipse(e0, e1, u, v) <= slop;
1240
+ }
1241
+ function distToEllipse(e0, e1, y0, y1) {
1242
+ const z0 = y0 / e0, z1 = y1 / e1;
1243
+ const g = z0 * z0 + z1 * z1 - 1;
1244
+ if (g <= 0) return 0;
1245
+ if (y1 > 0) {
1246
+ if (y0 > 0) {
1247
+ const r0 = e0 / e1 * (e0 / e1);
1248
+ const n0 = r0 * z0;
1249
+ let s0 = z1 - 1;
1250
+ let s1 = Math.hypot(n0, z1) - 1;
1251
+ let s = 0;
1252
+ for (let i = 0; i < 100; i++) {
1253
+ s = (s0 + s1) / 2;
1254
+ if (s === s0 || s === s1) break;
1255
+ const a = n0 / (s + r0), b = z1 / (s + 1);
1256
+ const gs = a * a + b * b - 1;
1257
+ if (gs > 0) s0 = s;
1258
+ else if (gs < 0) s1 = s;
1259
+ else break;
1260
+ }
1261
+ const x0 = r0 * y0 / (s + r0);
1262
+ const x1 = y1 / (s + 1);
1263
+ return Math.hypot(x0 - y0, x1 - y1);
1264
+ }
1265
+ return y1 - e1;
1266
+ }
1267
+ const numer = e0 * y0, denom = e0 * e0 - e1 * e1;
1268
+ if (numer < denom) {
1269
+ const t = numer / denom;
1270
+ const x0 = e0 * t, x1 = e1 * Math.sqrt(1 - t * t);
1271
+ return Math.hypot(x0 - y0, x1);
1272
+ }
1273
+ return y0 - e0;
1274
+ }
1275
+
1276
+ // src/pathHitTest.ts
1277
+ function flatSubpaths(path, tolerance) {
1278
+ const { commands, coords } = path;
1279
+ const closed = [];
1280
+ const open = [];
1281
+ let sub3 = [];
1282
+ forEachSegment(commands, coords, (cmd, ci, curX, curY) => {
1283
+ switch (cmd) {
1284
+ case PATH_M:
1285
+ if (sub3.length >= 2) open.push(sub3);
1286
+ sub3 = [coords[ci], coords[ci + 1]];
1287
+ break;
1288
+ case PATH_L:
1289
+ sub3.push(coords[ci], coords[ci + 1]);
1290
+ break;
1291
+ case PATH_C:
1292
+ flattenCubic(
1293
+ curX,
1294
+ curY,
1295
+ coords[ci],
1296
+ coords[ci + 1],
1297
+ coords[ci + 2],
1298
+ coords[ci + 3],
1299
+ coords[ci + 4],
1300
+ coords[ci + 5],
1301
+ tolerance,
1302
+ sub3
1303
+ );
1304
+ break;
1305
+ case PATH_Q:
1306
+ flattenQuadratic(
1307
+ curX,
1308
+ curY,
1309
+ coords[ci],
1310
+ coords[ci + 1],
1311
+ coords[ci + 2],
1312
+ coords[ci + 3],
1313
+ tolerance,
1314
+ sub3
1315
+ );
1316
+ break;
1317
+ case PATH_Z:
1318
+ if (sub3.length >= 6) closed.push(sub3);
1319
+ else if (sub3.length >= 2) open.push(sub3);
1320
+ sub3 = [];
1321
+ break;
1322
+ default:
1323
+ throw new Error(`pathHitTest: unknown command ${cmd}`);
1324
+ }
1325
+ });
1326
+ if (sub3.length >= 2) open.push(sub3);
1327
+ return { closed, open };
1328
+ }
1329
+ function closedSubpaths(path, opts) {
1330
+ return flatSubpaths(path, opts.tolerance ?? DEFAULT_FLATTEN_TOLERANCE).closed;
1331
+ }
1332
+ function pointInPath(path, x, y, opts = {}) {
1333
+ if (path.kind === "rect") {
1334
+ return x >= path.x && x <= path.x + path.width && y >= path.y && y <= path.y + path.height;
1335
+ }
1336
+ let crossings = 0;
1337
+ let winding = 0;
1338
+ for (const sub3 of closedSubpaths(path, opts)) {
1339
+ const n = sub3.length;
1340
+ for (let i = 0; i < n; i += 2) {
1341
+ const j = (i + 2) % n;
1342
+ const ay = sub3[i + 1], by = sub3[j + 1];
1343
+ if (ay > y === by > y) continue;
1344
+ const ax = sub3[i], bx = sub3[j];
1345
+ if (x >= ax + (y - ay) / (by - ay) * (bx - ax)) continue;
1346
+ crossings++;
1347
+ winding += ay <= y ? 1 : -1;
1348
+ }
1349
+ }
1350
+ return path.fillRule === "evenodd" ? (crossings & 1) === 1 : winding !== 0;
1351
+ }
1352
+ function strokeHitTest(path, x, y, threshold, opts = {}) {
1353
+ const slop = opts.slop;
1354
+ if (slop && slop.px > 0) {
1355
+ const [a, b, c, d] = slop.transform;
1356
+ const m = { a, b, c, d };
1357
+ const st = stretchOf(m);
1358
+ if (isSimilarity(st)) {
1359
+ return strokeHitTest(path, x, y, threshold + slop.px / st.s1, { tolerance: opts.tolerance });
1360
+ }
1361
+ const sx = a * x + c * y, sy = b * x + d * y;
1362
+ return someSegment(path, opts.tolerance, (ax, ay, bx, by) => capsuleWithinPx(sx, sy, ax, ay, bx, by, threshold, slop.px, m, st));
1363
+ }
1364
+ const t2 = threshold * threshold;
1365
+ return someSegment(path, opts.tolerance, (ax, ay, bx, by) => pointSegmentDist2(x, y, ax, ay, bx, by) <= t2);
1366
+ }
1367
+ function someSegment(path, tolerance, visit) {
1368
+ if (path.kind === "rect") {
1369
+ const { x: rx, y: ry, width: w, height: h } = path;
1370
+ return visit(rx, ry, rx + w, ry) || visit(rx + w, ry, rx + w, ry + h) || visit(rx + w, ry + h, rx, ry + h) || visit(rx, ry + h, rx, ry);
1371
+ }
1372
+ const { closed, open } = flatSubpaths(path, tolerance ?? DEFAULT_FLATTEN_TOLERANCE);
1373
+ const run = (sub3, wrap) => {
1374
+ const n = sub3.length;
1375
+ const last = wrap ? n : n - 2;
1376
+ for (let i = 0; i < last; i += 2) {
1377
+ const j = (i + 2) % n;
1378
+ if (visit(sub3[i], sub3[i + 1], sub3[j], sub3[j + 1])) return true;
1379
+ }
1380
+ return false;
1381
+ };
1382
+ return closed.some((sub3) => run(sub3, true)) || open.some((sub3) => run(sub3, false));
1383
+ }
1384
+ function rectToVerts(r) {
1385
+ return [
1386
+ { x: r.x, y: r.y },
1387
+ { x: r.x + r.width, y: r.y },
1388
+ { x: r.x + r.width, y: r.y + r.height },
1389
+ { x: r.x, y: r.y + r.height }
1390
+ ];
1391
+ }
1392
+ function flattenVerts(poly) {
1393
+ const flat = new Array(poly.length * 2);
1394
+ for (let i = 0; i < poly.length; i++) {
1395
+ flat[i * 2] = poly[i].x;
1396
+ flat[i * 2 + 1] = poly[i].y;
1397
+ }
1398
+ return flat;
1399
+ }
1400
+ function polygonsIntersect(a, b) {
1401
+ if (a.length === 0 || b.length === 0) return false;
1402
+ if (pointInPolygon(flattenVerts(a), b[0].x, b[0].y)) return true;
1403
+ if (pointInPolygon(flattenVerts(b), a[0].x, a[0].y)) return true;
1404
+ for (let i = 0; i < a.length; i++) {
1405
+ const a0 = a[i], a1 = a[(i + 1) % a.length];
1406
+ for (let j = 0; j < b.length; j++) {
1407
+ const b0 = b[j], b1 = b[(j + 1) % b.length];
1408
+ if (segmentsCross(a0.x, a0.y, a1.x, a1.y, b0.x, b0.y, b1.x, b1.y)) return true;
1409
+ }
1410
+ }
1411
+ return false;
1412
+ }
1413
+ function anyEdge(subpaths, visit) {
1414
+ for (const sub3 of subpaths) {
1415
+ const n = sub3.length;
1416
+ for (let i = 0; i < n; i += 2) {
1417
+ const j = (i + 2) % n;
1418
+ if (visit(sub3[i], sub3[i + 1], sub3[j], sub3[j + 1])) return true;
1419
+ }
1420
+ }
1421
+ return false;
1422
+ }
1423
+ function anyEdgeCrossesRect(subpaths, r) {
1424
+ const x0 = r.x, y0 = r.y, x1 = r.x + r.width, y1 = r.y + r.height;
1425
+ return anyEdge(
1426
+ subpaths,
1427
+ (ax, ay, bx, by) => segmentsCross(ax, ay, bx, by, x0, y0, x1, y0) || segmentsCross(ax, ay, bx, by, x1, y0, x1, y1) || segmentsCross(ax, ay, bx, by, x1, y1, x0, y1) || segmentsCross(ax, ay, bx, by, x0, y1, x0, y0)
1428
+ );
1429
+ }
1430
+ function anyEdgeCrossesPolygon(subpaths, poly) {
1431
+ if (poly.length === 0) return false;
1432
+ return anyEdge(subpaths, (ax, ay, bx, by) => {
1433
+ for (let i = 0; i < poly.length; i++) {
1434
+ const p0 = poly[i], p1 = poly[(i + 1) % poly.length];
1435
+ if (segmentsCross(ax, ay, bx, by, p0.x, p0.y, p1.x, p1.y)) return true;
1436
+ }
1437
+ return false;
1438
+ });
1439
+ }
1440
+ function anyOpenEdgeCrossesPolygon(runs, poly) {
1441
+ for (const run of runs) {
1442
+ for (let i = 0; i + 3 < run.length; i += 2) {
1443
+ const ax = run[i], ay = run[i + 1], bx = run[i + 2], by = run[i + 3];
1444
+ for (let k = 0; k < poly.length; k++) {
1445
+ const p0 = poly[k], p1 = poly[(k + 1) % poly.length];
1446
+ if (segmentsCross(ax, ay, bx, by, p0.x, p0.y, p1.x, p1.y)) return true;
1447
+ }
1448
+ }
1449
+ }
1450
+ return false;
1451
+ }
1452
+ function anyVertexInRect(subpaths, r) {
1453
+ for (const sub3 of subpaths) {
1454
+ for (let i = 0; i < sub3.length; i += 2) {
1455
+ const x = sub3[i], y = sub3[i + 1];
1456
+ if (x >= r.x && x <= r.x + r.width && y >= r.y && y <= r.y + r.height) return true;
1457
+ }
1458
+ }
1459
+ return false;
1460
+ }
1461
+ function anyVertexInPolygon(subpaths, flatPoly) {
1462
+ for (const sub3 of subpaths) {
1463
+ for (let i = 0; i < sub3.length; i += 2) {
1464
+ if (pointInPolygon(flatPoly, sub3[i], sub3[i + 1])) return true;
1465
+ }
1466
+ }
1467
+ return false;
1468
+ }
1469
+ function pathContainsPoint(path, x, y, opts = {}) {
1470
+ return pointInPath(path, x, y, opts);
1471
+ }
1472
+ function pathContainsRect(path, rect, opts = {}) {
1473
+ if (path.kind === "rect") {
1474
+ return rect.x >= path.x && rect.y >= path.y && rect.x + rect.width <= path.x + path.width && rect.y + rect.height <= path.y + path.height;
1475
+ }
1476
+ const subpaths = closedSubpaths(path, opts);
1477
+ if (subpaths.length === 0) return false;
1478
+ for (const c of rectToVerts(rect)) {
1479
+ if (!pointInPath(path, c.x, c.y, opts)) return false;
1480
+ }
1481
+ return !anyVertexInRect(subpaths, rect) && !anyEdgeCrossesRect(subpaths, rect);
1482
+ }
1483
+ function pathIntersectsRect(path, rect, opts = {}) {
1484
+ if (path.kind === "rect") {
1485
+ return rect.x < path.x + path.width && rect.x + rect.width > path.x && rect.y < path.y + path.height && rect.y + rect.height > path.y;
1486
+ }
1487
+ const subpaths = closedSubpaths(path, opts);
1488
+ if (subpaths.length === 0) return false;
1489
+ for (const c of rectToVerts(rect)) {
1490
+ if (pointInPath(path, c.x, c.y, opts)) return true;
1491
+ }
1492
+ if (anyVertexInRect(subpaths, rect)) return true;
1493
+ return anyEdgeCrossesRect(subpaths, rect);
1494
+ }
1495
+ function pathContainsPolygon(path, polygon, opts = {}) {
1496
+ if (polygon.length === 0) return false;
1497
+ if (path.kind === "rect") {
1498
+ return polygon.every(
1499
+ (p) => p.x >= path.x && p.x <= path.x + path.width && p.y >= path.y && p.y <= path.y + path.height
1500
+ );
1501
+ }
1502
+ const subpaths = closedSubpaths(path, opts);
1503
+ if (subpaths.length === 0) return false;
1504
+ for (const p of polygon) {
1505
+ if (!pointInPath(path, p.x, p.y, opts)) return false;
1506
+ }
1507
+ return !anyVertexInPolygon(subpaths, flattenVerts(polygon)) && !anyEdgeCrossesPolygon(subpaths, polygon);
1508
+ }
1509
+ function pathIntersectsPolygon(path, polygon, opts = {}) {
1510
+ if (polygon.length === 0) return false;
1511
+ if (path.kind === "rect") {
1512
+ return polygonsIntersect(rectToVerts(path), polygon);
1513
+ }
1514
+ const subpaths = closedSubpaths(path, opts);
1515
+ if (subpaths.length === 0) return false;
1516
+ for (const p of polygon) {
1517
+ if (pointInPath(path, p.x, p.y, opts)) return true;
1518
+ }
1519
+ if (anyVertexInPolygon(subpaths, flattenVerts(polygon))) return true;
1520
+ return anyEdgeCrossesPolygon(subpaths, polygon);
1521
+ }
1522
+ function polygonContainsPath(polygon, path, opts = {}) {
1523
+ if (polygon.length < 3) return false;
1524
+ let subpaths;
1525
+ if (path.kind === "rect") {
1526
+ subpaths = [flattenVerts(rectToVerts(path))];
1527
+ } else {
1528
+ const { closed, open } = flatSubpaths(path, opts.tolerance ?? DEFAULT_FLATTEN_TOLERANCE);
1529
+ subpaths = [...closed, ...open];
1530
+ }
1531
+ if (subpaths.length === 0) return false;
1532
+ const flatPoly = flattenVerts(polygon);
1533
+ for (const sub3 of subpaths) {
1534
+ for (let i = 0; i < sub3.length; i += 2) {
1535
+ if (!pointInPolygon(flatPoly, sub3[i], sub3[i + 1])) return false;
1536
+ }
1537
+ }
1538
+ return !anyEdgeCrossesPolygon(subpaths, polygon);
1539
+ }
1540
+ function polygonIntersectsPath(polygon, path, opts = {}) {
1541
+ if (polygon.length < 3) return false;
1542
+ if (path.kind === "rect") return polygonsIntersect(rectToVerts(path), polygon);
1543
+ const { closed, open } = flatSubpaths(path, opts.tolerance ?? DEFAULT_FLATTEN_TOLERANCE);
1544
+ const flatPoly = flattenVerts(polygon);
1545
+ if (anyVertexInPolygon(closed, flatPoly) || anyVertexInPolygon(open, flatPoly)) return true;
1546
+ if (anyEdgeCrossesPolygon(closed, polygon) || anyOpenEdgeCrossesPolygon(open, polygon)) {
1547
+ return true;
1548
+ }
1549
+ return closed.length > 0 && pointInPath(path, polygon[0].x, polygon[0].y, opts);
1550
+ }
1551
+
242
1552
  // src/place.ts
243
1553
  function alignAlong(start, extent, size, align) {
244
1554
  if (align === "start") return start;
@@ -304,6 +1614,186 @@ function placeRect(options) {
304
1614
  return { rect: shiftAcross(rect, boundary, resolved.side, padding), placement: resolved };
305
1615
  }
306
1616
 
307
- export { applyToPoint, boundsOfCoords, boxContainsPoint, boxToBox, clampRectWithin, identity, invert, multiply, nearestOnCubic, nearestOnLine, nearestOnPath, nearestOnQuadratic, placeRect, pointInPolygon, pointSegmentDist2, portControls2 as portControls, portCurvePoints, rectToContour, rotate, rotateAboutPoint, scale, segmentsCross, transformCoords, translate, unionBox };
1617
+ // src/easings.ts
1618
+ var linear = (t) => t;
1619
+ var easeInQuad = (t) => t * t;
1620
+ var easeOutQuad = (t) => 1 - (1 - t) * (1 - t);
1621
+ var easeInOutQuad = (t) => t < 0.5 ? 2 * t * t : 1 - 2 * (1 - t) * (1 - t);
1622
+ var easeInCubic = (t) => t * t * t;
1623
+ var easeOutCubic = (t) => 1 - Math.pow(1 - t, 3);
1624
+ var easeInOutCubic = (t) => t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
1625
+ var easeInQuart = (t) => t * t * t * t;
1626
+ var easeOutQuart = (t) => 1 - Math.pow(1 - t, 4);
1627
+ var easeInOutQuart = (t) => t < 0.5 ? 8 * t * t * t * t : 1 - Math.pow(-2 * t + 2, 4) / 2;
1628
+ var easeInQuint = (t) => t * t * t * t * t;
1629
+ var easeOutQuint = (t) => 1 - Math.pow(1 - t, 5);
1630
+ var easeInOutQuint = (t) => t < 0.5 ? 16 * t * t * t * t * t : 1 - Math.pow(-2 * t + 2, 5) / 2;
1631
+ var easeInSine = (t) => 1 - Math.cos(t * Math.PI / 2);
1632
+ var easeOutSine = (t) => Math.sin(t * Math.PI / 2);
1633
+ var easeInOutSine = (t) => -(Math.cos(Math.PI * t) - 1) / 2;
1634
+ var easeInExpo = (t) => t === 0 ? 0 : Math.pow(2, 10 * t - 10);
1635
+ var easeOutExpo = (t) => t === 1 ? 1 : 1 - Math.pow(2, -10 * t);
1636
+ var easeInOutExpo = (t) => {
1637
+ if (t === 0) return 0;
1638
+ if (t === 1) return 1;
1639
+ return t < 0.5 ? Math.pow(2, 20 * t - 10) / 2 : (2 - Math.pow(2, -20 * t + 10)) / 2;
1640
+ };
1641
+ var easeInCirc = (t) => 1 - Math.sqrt(1 - t * t);
1642
+ var easeOutCirc = (t) => Math.sqrt(1 - Math.pow(t - 1, 2));
1643
+ var easeInOutCirc = (t) => t < 0.5 ? (1 - Math.sqrt(1 - Math.pow(2 * t, 2))) / 2 : (Math.sqrt(1 - Math.pow(-2 * t + 2, 2)) + 1) / 2;
1644
+ var C1 = 1.70158;
1645
+ var C2 = C1 * 1.525;
1646
+ var C3 = C1 + 1;
1647
+ var C4 = 2 * Math.PI / 3;
1648
+ var C5 = 2 * Math.PI / 4.5;
1649
+ var easeInBack = (t) => C3 * t * t * t - C1 * t * t;
1650
+ var easeOutBack = (t) => 1 + C3 * Math.pow(t - 1, 3) + C1 * Math.pow(t - 1, 2);
1651
+ var easeInOutBack = (t) => t < 0.5 ? Math.pow(2 * t, 2) * ((C2 + 1) * 2 * t - C2) / 2 : (Math.pow(2 * t - 2, 2) * ((C2 + 1) * (2 * t - 2) + C2) + 2) / 2;
1652
+ var easeInElastic = (t) => {
1653
+ if (t === 0) return 0;
1654
+ if (t === 1) return 1;
1655
+ return -Math.pow(2, 10 * t - 10) * Math.sin((t * 10 - 10.75) * C4);
1656
+ };
1657
+ var easeOutElastic = (t) => {
1658
+ if (t === 0) return 0;
1659
+ if (t === 1) return 1;
1660
+ return Math.pow(2, -10 * t) * Math.sin((t * 10 - 0.75) * C4) + 1;
1661
+ };
1662
+ var easeInOutElastic = (t) => {
1663
+ if (t === 0) return 0;
1664
+ if (t === 1) return 1;
1665
+ return t < 0.5 ? -(Math.pow(2, 20 * t - 10) * Math.sin((20 * t - 11.125) * C5)) / 2 : Math.pow(2, -20 * t + 10) * Math.sin((20 * t - 11.125) * C5) / 2 + 1;
1666
+ };
1667
+ var easeOutBounce = (t) => {
1668
+ const n1 = 7.5625;
1669
+ const d1 = 2.75;
1670
+ if (t < 1 / d1) return n1 * t * t;
1671
+ if (t < 2 / d1) {
1672
+ t -= 1.5 / d1;
1673
+ return n1 * t * t + 0.75;
1674
+ }
1675
+ if (t < 2.5 / d1) {
1676
+ t -= 2.25 / d1;
1677
+ return n1 * t * t + 0.9375;
1678
+ }
1679
+ t -= 2.625 / d1;
1680
+ return n1 * t * t + 0.984375;
1681
+ };
1682
+ var easeInBounce = (t) => 1 - easeOutBounce(1 - t);
1683
+ var easeInOutBounce = (t) => t < 0.5 ? (1 - easeOutBounce(1 - 2 * t)) / 2 : (1 + easeOutBounce(2 * t - 1)) / 2;
1684
+ var easeIn = easeInQuad;
1685
+ var easeOut = easeOutQuad;
1686
+ var easeInOut = easeInOutQuad;
1687
+ var EASINGS = {
1688
+ linear,
1689
+ easeInQuad,
1690
+ easeOutQuad,
1691
+ easeInOutQuad,
1692
+ easeInCubic,
1693
+ easeOutCubic,
1694
+ easeInOutCubic,
1695
+ easeInQuart,
1696
+ easeOutQuart,
1697
+ easeInOutQuart,
1698
+ easeInQuint,
1699
+ easeOutQuint,
1700
+ easeInOutQuint,
1701
+ easeInSine,
1702
+ easeOutSine,
1703
+ easeInOutSine,
1704
+ easeInExpo,
1705
+ easeOutExpo,
1706
+ easeInOutExpo,
1707
+ easeInCirc,
1708
+ easeOutCirc,
1709
+ easeInOutCirc,
1710
+ easeInBack,
1711
+ easeOutBack,
1712
+ easeInOutBack,
1713
+ easeInElastic,
1714
+ easeOutElastic,
1715
+ easeInOutElastic,
1716
+ easeInBounce,
1717
+ easeOutBounce,
1718
+ easeInOutBounce
1719
+ };
1720
+ var SPRING_PRESETS = {
1721
+ gentle: { stiffness: 120, damping: 14, mass: 1 },
1722
+ wobbly: { stiffness: 180, damping: 12, mass: 1 },
1723
+ stiff: { stiffness: 210, damping: 20, mass: 1 },
1724
+ slow: { stiffness: 80, damping: 20, mass: 1 }
1725
+ };
1726
+
1727
+ // src/easingSpec.ts
1728
+ var NEWTON_ITERATIONS = 8;
1729
+ var NEWTON_MIN_SLOPE = 1e-3;
1730
+ var SUBDIVISION_EPSILON = 1e-7;
1731
+ var SUBDIVISION_MAX = 12;
1732
+ function bezierAt(t, a1, a2) {
1733
+ const c = 3 * a1;
1734
+ const b = 3 * (a2 - a1) - c;
1735
+ const a = 1 - c - b;
1736
+ return ((a * t + b) * t + c) * t;
1737
+ }
1738
+ function bezierSlope(t, a1, a2) {
1739
+ const c = 3 * a1;
1740
+ const b = 3 * (a2 - a1) - c;
1741
+ const a = 1 - c - b;
1742
+ return (3 * a * t + 2 * b) * t + c;
1743
+ }
1744
+ function solveForX(x, x1, x2) {
1745
+ let t = x;
1746
+ for (let i = 0; i < NEWTON_ITERATIONS; i++) {
1747
+ const slope = bezierSlope(t, x1, x2);
1748
+ if (slope < NEWTON_MIN_SLOPE) break;
1749
+ t -= (bezierAt(t, x1, x2) - x) / slope;
1750
+ }
1751
+ let lo = 0;
1752
+ let hi = 1;
1753
+ t = Math.min(1, Math.max(0, t));
1754
+ for (let i = 0; i < SUBDIVISION_MAX; i++) {
1755
+ const err = bezierAt(t, x1, x2) - x;
1756
+ if (Math.abs(err) < SUBDIVISION_EPSILON) return t;
1757
+ if (err > 0) hi = t;
1758
+ else lo = t;
1759
+ t = (lo + hi) / 2;
1760
+ }
1761
+ return t;
1762
+ }
1763
+ function cubicBezierEasing(x1, y1, x2, y2) {
1764
+ const cx1 = Math.min(1, Math.max(0, x1));
1765
+ const cx2 = Math.min(1, Math.max(0, x2));
1766
+ return (t) => {
1767
+ if (t <= 0) return 0;
1768
+ if (t >= 1) return 1;
1769
+ return bezierAt(solveForX(t, cx1, cx2), y1, y2);
1770
+ };
1771
+ }
1772
+ var bezierCache = /* @__PURE__ */ new Map();
1773
+ function isBezier(spec) {
1774
+ return typeof spec === "object" && spec !== null && "bezier" in spec;
1775
+ }
1776
+ function resolveEasing(spec) {
1777
+ if (spec === void 0) return EASINGS.linear;
1778
+ if (typeof spec === "function") return spec;
1779
+ if (typeof spec === "string") {
1780
+ const fn = EASINGS[spec];
1781
+ if (!fn) throw new Error(`resolveEasing: unknown easing name "${spec}"`);
1782
+ return fn;
1783
+ }
1784
+ if (isBezier(spec)) {
1785
+ const [x1, y1, x2, y2] = spec.bezier;
1786
+ const key = `${x1},${y1},${x2},${y2}`;
1787
+ let fn = bezierCache.get(key);
1788
+ if (!fn) {
1789
+ fn = cubicBezierEasing(x1, y1, x2, y2);
1790
+ bezierCache.set(key, fn);
1791
+ }
1792
+ return fn;
1793
+ }
1794
+ throw new Error("resolveEasing: unrecognized easing spec");
1795
+ }
1796
+
1797
+ export { EASINGS, PathBuilder, SPRING_PRESETS, applyToPoint, boundsOfPath, boxToBox, clampRectWithin, composePath, cubicBezierEasing, decomposePath, easeIn, easeInBack, easeInBounce, easeInCirc, easeInCubic, easeInElastic, easeInExpo, easeInOut, easeInOutBack, easeInOutBounce, easeInOutCirc, easeInOutCubic, easeInOutElastic, easeInOutExpo, easeInOutQuad, easeInOutQuart, easeInOutQuint, easeInOutSine, easeInQuad, easeInQuart, easeInQuint, easeInSine, easeOut, easeOutBack, easeOutBounce, easeOutCirc, easeOutCubic, easeOutElastic, easeOutExpo, easeOutQuad, easeOutQuart, easeOutQuint, easeOutSine, ellipsePath, identity, invert, linePath, linear, multiply, nearestOnCubic, nearestOnLine, nearestOnPath, nearestOnQuadratic, pathContainsPoint, pathContainsPolygon, pathContainsRect, pathDistanceToPoint, pathFromD, pathIntersectsPolygon, pathIntersectsRect, pathSignedArea, placeRect, pointAlongPath, pointInPath, polygonContainsPath, polygonFromPoints, polygonIntersectsPath, polylineFromPoints, portControls2 as portControls, portCurvePoints, rectPath, regularPolygonPath, resolveEasing, reversePath, rotate, rotateAboutPoint, scale, scalePathToBounds, schneiderFit, splitSubpaths, starPath, strokeHitTest, transformCoords, transformPath, translate, translatePath, unionBoundsPath };
308
1798
  //# sourceMappingURL=index.js.map
309
1799
  //# sourceMappingURL=index.js.map