@weasel-js/geom 1.11.1 → 1.13.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,21 +1,21 @@
1
- import { carryCorners, evalSeg, parseSubpaths, keepCorners, anchorRange, subSeg, writePath, derivSeg } from './chunk-4Y67BZL5.js';
2
- export { CORNER_RESTORE_TOLERANCE, cornerTraces, keepCorners, restoreCorners } from './chunk-4Y67BZL5.js';
1
+ import { carryCorners, evalSeg, parseSubpaths, keepCorners, anchorRange, subSeg, writePath, derivSeg } from './chunk-YPWFGFQX.js';
2
+ export { CORNER_RESTORE_TOLERANCE, cornerTraces, keepCorners, restoreCorners } from './chunk-YPWFGFQX.js';
3
3
  import { PORT_REACH, portControls, portCurvePoints } from './chunk-YQADYJJ7.js';
4
4
  export { PORT_REACH } from './chunk-YQADYJJ7.js';
5
5
  import { cubicDerivativeAt, cubicCurvatureAt } from './chunk-UI3FUWXM.js';
6
6
  export { SPIRO_KINDS, combTeeth, cubicCurvatureAt, cubicCurvatureSource, cubicDerivativeAt, curvatureComb, eulerAngleAt, eulerCurvatureAt, eulerCurvatureDerivativesAt, eulerPointAt, fitEulerSegment, isSpiroKind, placeEulerSegment, solveSpiro, spiroContoursFromControl, spiroContoursOf, spiroControlPath, spiroToPath } from './chunk-UI3FUWXM.js';
7
- import { extractPolylines } from './chunk-7F66PQCJ.js';
8
- import { boundsOfPath, fitPointRun, keepCorner } from './chunk-6FGQML7D.js';
9
- export { boundsOfPath } from './chunk-6FGQML7D.js';
7
+ import { extractPolylines } from './chunk-VHXOCDZ2.js';
8
+ import { boundsOfPath, fitPointRun, keepCorner } from './chunk-STGSBIOL.js';
9
+ export { boundsOfPath } from './chunk-STGSBIOL.js';
10
10
  import { countPathAnchors, pathToAnchors, anchorsToPath, isAnchorSmooth, segmentEnds, isStraightSegment, nearestSegmentT } from './chunk-Q66NA2FU.js';
11
11
  export { anchorsToPath, countPathAnchors, isAnchorSmooth, isStraightSegment, nearestSegmentT, pathToAnchors, segmentEnds } from './chunk-Q66NA2FU.js';
12
- import { nearestOnPath, nearestOnLine, nearestOnQuadratic, nearestOnCubic } from './chunk-CE7IY7TB.js';
12
+ import { nearestOnLine, nearestOnPath, nearestOnQuadratic, nearestOnCubic } from './chunk-CE7IY7TB.js';
13
13
  export { nearestOnCubic, nearestOnLine, nearestOnPath, nearestOnQuadratic } from './chunk-CE7IY7TB.js';
14
- import { pointInPolygon, resolveCorners, cornerCuts, fillsOpenSubpaths, schneiderFit, fitCubicWithTangents, flattenCubic, pointSegmentDist2, flattenQuadratic, DEFAULT_FLATTEN_TOLERANCE, segmentsCross } from './chunk-EAKE3N7W.js';
15
- export { CORNER_FIT_TOLERANCE, CORNER_KEYWORDS, DEFAULT_FLATTEN_TOLERANCE, cornerCenter, cornerCuts, cornerFrameAt, cornerFrames, cornerKeywordOf, cornerShapeK, cornerShapePieces, cornerShapePoint, defaultOpenFill, fillsOpenSubpaths, fitCubicWithTangents, flattenCubic, flattenCubicWithArcLen, flattenQuadratic, flattenQuadraticWithArcLen, isCornerShape, nextCornerShape, pointInPolygon, pointSegmentDist2, remapPerAnchor, resolveCorners, resolveCornersWithSources, schneiderFit, segmentsCross, setDefaultOpenFill } from './chunk-EAKE3N7W.js';
16
- import { SINGULAR_RATIO } from './chunk-755Y4YZS.js';
14
+ import { resolveCorners, pointInPolygon, cornerCuts, fillsOpenSubpaths, schneiderFit, fitCubicWithTangents, flattenCubic, pointSegmentDist2, flattenQuadratic, DEFAULT_FLATTEN_TOLERANCE, segmentsCross } from './chunk-2PKPKU4P.js';
15
+ export { CORNER_FIT_TOLERANCE, CORNER_KEYWORDS, DEFAULT_FLATTEN_TOLERANCE, cornerCenter, cornerCuts, cornerFrameAt, cornerFrames, cornerKeywordOf, cornerShapeK, cornerShapePieces, cornerShapePoint, defaultOpenFill, fillsOpenSubpaths, fitCubicWithTangents, flattenCubic, flattenCubicWithArcLen, flattenQuadratic, flattenQuadraticWithArcLen, isCornerShape, nextCornerShape, pointInPolygon, pointSegmentDist2, remapPerAnchor, resolveCorners, resolveCornersWithSources, schneiderFit, segmentsCross, setDefaultOpenFill } from './chunk-2PKPKU4P.js';
16
+ import { SINGULAR_RATIO, clamp } from './chunk-755Y4YZS.js';
17
17
  export { EPS, approxEq, clamp, cross, dot, len2, sign, sub } from './chunk-755Y4YZS.js';
18
- import { PathBuilder, withCorner, scaleCorners, forEachSegment, pathCommandCoordCount, withoutCorners, PATH_M, PATH_Z, PATH_L, PATH_C, PATH_Q, elevateQuadraticToCubic, cubicEvalAt, cubicPointAt, splitCubicAtT, cubicAxisExtremaTs, rectToContour, splitCubicAt } from './chunk-B53BERKG.js';
18
+ import { PATH_M, PATH_L, PATH_C, PATH_Q, PATH_Z, PathBuilder, withCorner, scaleCorners, forEachSegment, pathCommandCoordCount, withoutCorners, elevateQuadraticToCubic, cubicEvalAt, cubicPointAt, splitCubicAtT, cubicAxisExtremaTs, rectToContour, splitCubicAt } from './chunk-B53BERKG.js';
19
19
  export { PATH_C, PATH_CMD_LENGTHS, PATH_COMMANDS, PATH_L, PATH_M, PATH_Q, PATH_Z, PathBuilder, asPolygonPath, boundsOfCoords, boxContainsBox, boxContainsPoint, compactCorners, cornerAt, cornerSpecAt, cubicAxisExtremaTs, cubicBounds, cubicEvalAt, cubicPointAt, elevateQuadraticToCubic, ellipsePath, forEachSegment, hasCorners, lerpCorners, linePath, pathCommandCoordCount, polygonFromPoints, polylineFromPoints, quadraticEvalAt, rectPath, rectToContour, regularPolygonPath, scaleCorners, splitCubicAt, splitCubicAtT, splitLineAt, splitQuadraticAt, starPath, unionBox, withCorner, withoutCorners } from './chunk-B53BERKG.js';
20
20
 
21
21
  // src/view.ts
@@ -82,6 +82,640 @@ function transformCoords(coords, m) {
82
82
  return out;
83
83
  }
84
84
 
85
+ // src/track/shape.ts
86
+ function lineShape(from, to) {
87
+ const dx2 = to.x - from.x;
88
+ const dy2 = to.y - from.y;
89
+ const length2 = Math.hypot(dx2, dy2);
90
+ const tangent = length2 === 0 ? { x: 1, y: 0 } : { x: dx2 / length2, y: dy2 / length2 };
91
+ const normal2 = { x: tangent.y, y: -tangent.x };
92
+ return {
93
+ kind: "line",
94
+ length: length2,
95
+ closed: false,
96
+ at(f, options) {
97
+ const t = options?.open ? f : clamp(f, 0, 1);
98
+ return {
99
+ point: { x: from.x + t * dx2, y: from.y + t * dy2 },
100
+ tangent: { ...tangent },
101
+ normal: { ...normal2 }
102
+ };
103
+ },
104
+ nearest(p, options) {
105
+ const n = nearestOnLine(p.x, p.y, from.x, from.y, to.x, to.y);
106
+ if (!options?.open || length2 === 0) return { f: n.t, dist: n.dist };
107
+ const f = ((p.x - from.x) * dx2 + (p.y - from.y) * dy2) / (length2 * length2);
108
+ return { f, dist: n.dist };
109
+ }
110
+ };
111
+ }
112
+
113
+ // src/track/arc.ts
114
+ var RAD = Math.PI / 180;
115
+ var mod360 = (a) => (a % 360 + 360) % 360;
116
+ function arcShape(spec) {
117
+ const { center, radius, start } = spec;
118
+ const sign2 = spec.direction === "ccw" ? -1 : 1;
119
+ const raw = mod360(sign2 * (spec.end - start));
120
+ const sweep = raw === 0 ? 360 : raw;
121
+ const length2 = radius * sweep * RAD;
122
+ const at2 = (f, options) => {
123
+ const t = options?.open ? f : clamp(f, 0, 1);
124
+ const theta = (start + sign2 * t * sweep) * RAD;
125
+ const s = Math.sin(theta);
126
+ const c = Math.cos(theta);
127
+ return {
128
+ point: { x: center.x + radius * s, y: center.y - radius * c },
129
+ tangent: { x: sign2 * c, y: sign2 * s },
130
+ normal: { x: s, y: -c }
131
+ };
132
+ };
133
+ const shape = {
134
+ kind: "arc",
135
+ length: length2,
136
+ closed: raw === 0,
137
+ at: at2,
138
+ nearest(p, options) {
139
+ const dx2 = p.x - center.x;
140
+ const dy2 = p.y - center.y;
141
+ const angle = dx2 === 0 && dy2 === 0 ? 0 : Math.atan2(dx2, -dy2) / RAD;
142
+ const offset2 = mod360(sign2 * (angle - start));
143
+ let f;
144
+ if (offset2 <= sweep) f = offset2 / sweep;
145
+ else f = 360 - offset2 < offset2 - sweep ? 0 : 1;
146
+ const q = at2(f).point;
147
+ const dist = Math.hypot(p.x - q.x, p.y - q.y);
148
+ if (!options?.open) return { f, dist };
149
+ const mid = (options.about ?? 0.5) * sweep;
150
+ const unwrapped = mid + mod360(offset2 - mid + 180) - 180;
151
+ return { f: unwrapped / sweep, dist };
152
+ }
153
+ };
154
+ Object.defineProperty(shape, "arc", { value: spec, enumerable: false });
155
+ return shape;
156
+ }
157
+
158
+ // src/track/ellipse.ts
159
+ var RAD2 = Math.PI / 180;
160
+ var mod3602 = (a) => (a % 360 + 360) % 360;
161
+ var PIECES = 128;
162
+ var PANELS = 4;
163
+ var RING = 256;
164
+ var pointAt = ({ center, a, b, t0, sign: sign2 }, u) => {
165
+ const t = (t0 + sign2 * u) * RAD2;
166
+ return { x: center.x + a * Math.sin(t), y: center.y - b * Math.cos(t) };
167
+ };
168
+ var speed = ({ a, b, t0, sign: sign2 }, u) => {
169
+ const t = (t0 + sign2 * u) * RAD2;
170
+ return Math.hypot(a * Math.cos(t), b * Math.sin(t)) * RAD2;
171
+ };
172
+ function lengthTable(e, sweep) {
173
+ const simpson = (u0, u1) => {
174
+ const h = (u1 - u0) / PANELS;
175
+ let sum = speed(e, u0) + speed(e, u1);
176
+ for (let i = 1; i < PANELS; i++) sum += speed(e, u0 + i * h) * (i % 2 ? 4 : 2);
177
+ return sum * h / 3;
178
+ };
179
+ const du = sweep / PIECES;
180
+ const table = [0];
181
+ for (let i = 0; i < PIECES; i++) table.push(table[i] + simpson(i * du, (i + 1) * du));
182
+ const length2 = table[PIECES];
183
+ const lengthTo = (u) => {
184
+ if (u >= 0 && u <= sweep) {
185
+ const i = Math.min(PIECES - 1, Math.floor(u / du));
186
+ return table[i] + simpson(i * du, u);
187
+ }
188
+ const n = Math.max(1, Math.ceil(Math.abs(u) / du));
189
+ let s = 0;
190
+ for (let i = 0; i < n; i++) s += simpson(u * i / n, u * (i + 1) / n);
191
+ return s;
192
+ };
193
+ const offsetAt = (f) => {
194
+ if (length2 === 0) return f * sweep;
195
+ const s = f * length2;
196
+ let lo = 0;
197
+ let hi = PIECES;
198
+ while (hi - lo > 1) {
199
+ const mid = lo + hi >> 1;
200
+ if (table[mid] <= s) lo = mid;
201
+ else hi = mid;
202
+ }
203
+ const piece = table[lo + 1] - table[lo];
204
+ let u = (lo + (piece === 0 ? 0 : (s - table[lo]) / piece)) * du;
205
+ for (let i = 0; i < 3; i++) {
206
+ const v = speed(e, u);
207
+ if (!(v > 0)) break;
208
+ u -= (lengthTo(u) - s) / v;
209
+ }
210
+ return u;
211
+ };
212
+ return { length: length2, lengthTo, offsetAt };
213
+ }
214
+ var dist2 = (e, p, u) => {
215
+ const q = pointAt(e, u);
216
+ return (p.x - q.x) ** 2 + (p.y - q.y) ** 2;
217
+ };
218
+ function footBetween(e, p, lo, hi, n, late) {
219
+ let best = lo;
220
+ let bestD = dist2(e, p, lo);
221
+ const step = (hi - lo) / n;
222
+ for (let i = 1; i <= n; i++) {
223
+ const v = i === n ? hi : lo + i * step;
224
+ const d = dist2(e, p, v);
225
+ if (late ? d <= bestD * (1 + 1e-12) : d < bestD * (1 - 1e-12)) [best, bestD] = [v, d];
226
+ }
227
+ const { a, b, t0, sign: sign2 } = e;
228
+ const dx2 = p.x - e.center.x;
229
+ const dy2 = p.y - e.center.y;
230
+ let u = best;
231
+ for (let i = 0; i < 12; i++) {
232
+ const t = (t0 + sign2 * u) * RAD2;
233
+ const s = Math.sin(t);
234
+ const c = Math.cos(t);
235
+ const g = (a * a - b * b) * s * c - dx2 * a * c - dy2 * b * s;
236
+ const g1 = (a * a - b * b) * (c * c - s * s) + dx2 * a * s - dy2 * b * c;
237
+ if (!(g1 > 0)) break;
238
+ const next = clamp(u - sign2 * g / g1 / RAD2, Math.max(lo, best - step), Math.min(hi, best + step));
239
+ if (Math.abs(next - u) < 1e-12) break;
240
+ u = next;
241
+ }
242
+ return dist2(e, p, u) <= bestD ? u : best;
243
+ }
244
+ function ellipseShape(spec) {
245
+ const { center, radiusX: a, radiusY: b } = spec;
246
+ const sign2 = spec.direction === "ccw" ? -1 : 1;
247
+ const param = (seenDeg) => Math.atan2(b * Math.sin(seenDeg * RAD2), a * Math.cos(seenDeg * RAD2)) / RAD2;
248
+ const e = { center, a, b, t0: param(spec.start), sign: sign2 };
249
+ const raw = mod3602(sign2 * (param(spec.end) - e.t0));
250
+ const sweep = raw === 0 ? 360 : raw;
251
+ const { length: length2, lengthTo, offsetAt } = lengthTable(e, sweep);
252
+ const offsetPast = (f) => {
253
+ if (raw === 0) return offsetAt((f % 1 + 1) % 1);
254
+ let u = f * sweep;
255
+ for (let i = 0; i < 8; i++) {
256
+ const v = speed(e, u);
257
+ if (!(v > 0)) break;
258
+ u -= (lengthTo(u) - f * length2) / v;
259
+ }
260
+ return u;
261
+ };
262
+ const at2 = (f, options) => {
263
+ const u = options?.open && (f < 0 || f > 1) ? offsetPast(f) : offsetAt(clamp(f, 0, 1));
264
+ const t = (e.t0 + sign2 * u) * RAD2;
265
+ const s = Math.sin(t);
266
+ const c = Math.cos(t);
267
+ const k = Math.hypot(a * c, b * s);
268
+ const tangent = k === 0 ? { x: sign2 * c, y: sign2 * s } : { x: sign2 * a * c / k, y: sign2 * b * s / k };
269
+ const normal2 = k === 0 ? { x: s, y: -c } : { x: b * s / k, y: -a * c / k };
270
+ return { point: pointAt(e, u), tangent, normal: normal2 };
271
+ };
272
+ const shape = {
273
+ kind: "ellipse",
274
+ length: length2,
275
+ closed: raw === 0,
276
+ at: at2,
277
+ nearest(p, options) {
278
+ const u = footBetween(e, p, 0, sweep, PIECES, true);
279
+ const f = length2 === 0 ? 0 : clamp(lengthTo(u) / length2, 0, 1);
280
+ const dist = Math.sqrt(dist2(e, p, u));
281
+ if (!options?.open || length2 === 0) return { f, dist };
282
+ const mid = offsetAt(options.about ?? 0.5);
283
+ return { f: lengthTo(footBetween(e, p, mid - 180, mid + 180, RING, false)) / length2, dist };
284
+ }
285
+ };
286
+ Object.defineProperty(shape, "ellipse", { value: spec, enumerable: false });
287
+ return shape;
288
+ }
289
+
290
+ // src/paths/pathMeasure.ts
291
+ function measurePath(path, opts = {}) {
292
+ const polylines = extractPolylines(
293
+ path,
294
+ opts.flattenTolerance === void 0 ? {} : { flattenTolerance: opts.flattenTolerance }
295
+ );
296
+ const segments = [];
297
+ let total = 0;
298
+ let first;
299
+ let contours = 0;
300
+ let lastClosed = false;
301
+ for (const pl of polylines) {
302
+ const count = pl.points.length / 2;
303
+ if (count === 0) continue;
304
+ contours++;
305
+ lastClosed = pl.closed;
306
+ first ??= { x: pl.points[0], y: pl.points[1] };
307
+ const startIndex = segments.length;
308
+ const last = pl.closed ? count : count - 1;
309
+ for (let i = 0; i < last; i++) {
310
+ const j = (i + 1) % count;
311
+ const ax = pl.points[i * 2];
312
+ const ay = pl.points[i * 2 + 1];
313
+ const bx = pl.points[j * 2];
314
+ const by = pl.points[j * 2 + 1];
315
+ const len = Math.hypot(bx - ax, by - ay);
316
+ if (len === 0) continue;
317
+ const tx = (bx - ax) / len;
318
+ const ty = (by - ay) / len;
319
+ segments.push({ ax, ay, bx, by, start: total, len, tx, ty, t0x: tx, t0y: ty, t1x: tx, t1y: ty });
320
+ total += len;
321
+ }
322
+ smoothVertexHeadings(segments, startIndex, pl.closed, opts.keepCorners ? opts.flattenTolerance ?? 0.5 : null);
323
+ }
324
+ if (first === void 0) return null;
325
+ const origin = first;
326
+ const closed = contours === 1 && lastClosed;
327
+ if (segments.length === 0) {
328
+ return {
329
+ length: 0,
330
+ closed,
331
+ at: () => ({ point: { ...origin }, tangent: { x: 1, y: 0 } }),
332
+ nearest: (p) => ({
333
+ s: 0,
334
+ dist: Math.hypot(p.x - origin.x, p.y - origin.y),
335
+ point: { ...origin },
336
+ tangent: { x: 1, y: 0 }
337
+ })
338
+ };
339
+ }
340
+ return {
341
+ length: total,
342
+ closed,
343
+ at(s, smooth = false) {
344
+ const target = Math.min(Math.max(s, 0), total);
345
+ const seg = segments[segmentAt(segments, target)];
346
+ const u = Math.min(Math.max((target - seg.start) / seg.len, 0), 1);
347
+ const point = { x: seg.ax + (seg.bx - seg.ax) * u, y: seg.ay + (seg.by - seg.ay) * u };
348
+ if (!smooth) return { point, tangent: { x: seg.tx, y: seg.ty } };
349
+ const x = seg.t0x + (seg.t1x - seg.t0x) * u;
350
+ const y = seg.t0y + (seg.t1y - seg.t0y) * u;
351
+ const l = Math.hypot(x, y);
352
+ return { point, tangent: l === 0 ? { x: seg.tx, y: seg.ty } : { x: x / l, y: y / l } };
353
+ },
354
+ nearest(p) {
355
+ let best = segments[0];
356
+ let bestU = 0;
357
+ let bestDist = Infinity;
358
+ for (const seg of segments) {
359
+ const u = Math.min(Math.max(((p.x - seg.ax) * seg.tx + (p.y - seg.ay) * seg.ty) / seg.len, 0), 1);
360
+ const d = Math.hypot(p.x - (seg.ax + (seg.bx - seg.ax) * u), p.y - (seg.ay + (seg.by - seg.ay) * u));
361
+ if (d < bestDist) {
362
+ best = seg;
363
+ bestU = u;
364
+ bestDist = d;
365
+ }
366
+ }
367
+ return {
368
+ s: best.start + best.len * bestU,
369
+ dist: bestDist,
370
+ point: { x: best.ax + (best.bx - best.ax) * bestU, y: best.ay + (best.by - best.ay) * bestU },
371
+ tangent: { x: best.tx, y: best.ty }
372
+ };
373
+ }
374
+ };
375
+ }
376
+ function smoothVertexHeadings(segments, from, closed, cornerTolerance) {
377
+ const n = segments.length - from;
378
+ if (n < 2) return;
379
+ const pairs = closed ? n : n - 1;
380
+ for (let k = 0; k < pairs; k++) {
381
+ const a = segments[from + k];
382
+ const b = segments[from + (k + 1) % n];
383
+ if (cornerTolerance !== null && isCorner(a, b, cornerTolerance)) continue;
384
+ let x = a.tx + b.tx;
385
+ let y = a.ty + b.ty;
386
+ const l = Math.hypot(x, y);
387
+ if (l < 1e-9) continue;
388
+ x /= l;
389
+ y /= l;
390
+ a.t1x = x;
391
+ a.t1y = y;
392
+ b.t0x = x;
393
+ b.t0y = y;
394
+ }
395
+ }
396
+ function isCorner(a, b, tolerance) {
397
+ const turn = Math.acos(Math.min(1, Math.max(-1, a.tx * b.tx + a.ty * b.ty)));
398
+ return turn > 16 * tolerance / Math.min(a.len, b.len);
399
+ }
400
+ function segmentAt(segments, s) {
401
+ let lo = 0;
402
+ let hi = segments.length - 1;
403
+ while (lo < hi) {
404
+ const mid = lo + hi + 1 >> 1;
405
+ if (segments[mid].start <= s) lo = mid;
406
+ else hi = mid - 1;
407
+ }
408
+ return lo;
409
+ }
410
+
411
+ // src/track/path.ts
412
+ function pathShape(path, options = {}) {
413
+ const measure2 = measurePath(path, { ...options, keepCorners: true });
414
+ if (!measure2) return null;
415
+ const { length: length2, closed } = measure2;
416
+ const shape = {
417
+ kind: "path",
418
+ length: length2,
419
+ closed,
420
+ at(f, options2) {
421
+ const open = options2?.open === true && (f < 0 || f > 1);
422
+ const g = open && closed ? (f % 1 + 1) % 1 : clamp(f, 0, 1);
423
+ const { point, tangent } = measure2.at(g * length2, true);
424
+ const past = open && !closed ? (f - g) * length2 : 0;
425
+ return { point: { x: point.x + past * tangent.x, y: point.y + past * tangent.y }, tangent, normal: { x: tangent.y, y: -tangent.x } };
426
+ },
427
+ nearest(p, opts) {
428
+ const n = measure2.nearest(p);
429
+ const f = length2 === 0 ? 0 : n.s / length2;
430
+ if (!opts?.open || !closed || length2 === 0) return { f, dist: n.dist };
431
+ const about = opts.about ?? 0.5;
432
+ const unwrapped = [f - 1, f + 1].reduce((best, g) => Math.abs(g - about) < Math.abs(best - about) ? g : best, f);
433
+ return { f: unwrapped, dist: n.dist };
434
+ }
435
+ };
436
+ Object.defineProperty(shape, "path", { value: path, enumerable: false });
437
+ return shape;
438
+ }
439
+
440
+ // src/track/run.ts
441
+ var pointsDown = (normal2) => normal2.y > 1e-9;
442
+ function trackRun(shape, from = 0, to = 1, options = {}) {
443
+ const { side = "auto", about = (from + to) / 2 } = options;
444
+ const mid = shape.at(about);
445
+ const flipped = side === "auto" ? pointsDown(mid.normal) : side === "flipped";
446
+ const sgn = flipped ? -1 : 1;
447
+ const reading = (n) => ({ x: -(sgn * n.y), y: sgn * n.x });
448
+ const r0 = reading(mid.normal);
449
+ const reversed3 = r0.x * mid.tangent.x + r0.y * mid.tangent.y < 0;
450
+ const span = to - from;
451
+ const lo = Math.min(from, to);
452
+ const hi = Math.max(from, to);
453
+ const toF = (g) => reversed3 ? to - g * span : from + g * span;
454
+ const at2 = (g, options2) => {
455
+ const s = options2?.open ? shape.at(toF(g), options2) : shape.at(toF(clamp(g, 0, 1)));
456
+ const dir = reading(s.normal);
457
+ const angle = Math.atan2(dir.y, dir.x) * 180 / Math.PI;
458
+ const normal2 = { x: sgn * s.normal.x, y: sgn * s.normal.y };
459
+ return {
460
+ point: s.point,
461
+ tangent: dir,
462
+ normal: normal2,
463
+ angle: angle === 0 ? 0 : angle === -180 ? 180 : angle,
464
+ turned: pointsDown(normal2)
465
+ };
466
+ };
467
+ const toG = (f) => span === 0 ? 0 : reversed3 ? (to - f) / span : (f - from) / span;
468
+ const nearest = (p, options2) => {
469
+ const f = clamp(shape.nearest(p).f, lo, hi);
470
+ const q = shape.at(f).point;
471
+ const dist = Math.hypot(p.x - q.x, p.y - q.y);
472
+ if (!options2?.open) return { f: toG(f), dist };
473
+ return { f: toG(shape.nearest(p, { open: true, about: toF(options2.about ?? 0.5) }).f), dist };
474
+ };
475
+ return {
476
+ kind: shape.kind,
477
+ length: shape.length * Math.abs(span),
478
+ closed: shape.closed && Math.abs(span) === 1,
479
+ shape,
480
+ from,
481
+ to,
482
+ flipped,
483
+ reversed: reversed3,
484
+ at: at2,
485
+ nearest
486
+ };
487
+ }
488
+
489
+ // src/paths/pathToD.ts
490
+ var num = (n) => Number.isFinite(n) ? String(Math.round(n * 1e6) / 1e6) : "0";
491
+ function pathToD(given) {
492
+ const path = resolveCorners(given);
493
+ if (path.kind === "rect") {
494
+ const { x, y, width, height } = path;
495
+ return `M${num(x)} ${num(y)}h${num(width)}v${num(height)}h${num(-width)}Z`;
496
+ }
497
+ const cmds = path.commands;
498
+ const xs = path.coords;
499
+ const out = [];
500
+ let ci = 0;
501
+ for (let i = 0; i < cmds.length; i++) {
502
+ const c = cmds[i];
503
+ if (c === PATH_M) {
504
+ out.push(`M${num(xs[ci])} ${num(xs[ci + 1])}`);
505
+ ci += 2;
506
+ } else if (c === PATH_L) {
507
+ out.push(`L${num(xs[ci])} ${num(xs[ci + 1])}`);
508
+ ci += 2;
509
+ } else if (c === PATH_C) {
510
+ out.push(
511
+ `C${num(xs[ci])} ${num(xs[ci + 1])} ${num(xs[ci + 2])} ${num(xs[ci + 3])} ${num(xs[ci + 4])} ${num(xs[ci + 5])}`
512
+ );
513
+ ci += 6;
514
+ } else if (c === PATH_Q) {
515
+ out.push(`Q${num(xs[ci])} ${num(xs[ci + 1])} ${num(xs[ci + 2])} ${num(xs[ci + 3])}`);
516
+ ci += 4;
517
+ } else if (c === PATH_Z) {
518
+ out.push("Z");
519
+ }
520
+ }
521
+ return out.join("");
522
+ }
523
+
524
+ // src/track/pathData.ts
525
+ var SAMPLES = 64;
526
+ var num2 = (v) => {
527
+ const r = Math.round(v * 1e4) / 1e4;
528
+ return String(r === 0 ? 0 : r);
529
+ };
530
+ var pt = (p) => `${num2(p.x)} ${num2(p.y)}`;
531
+ var isArc = (s) => s.kind === "arc" && "arc" in s;
532
+ var isPath = (s) => s.kind === "path" && "path" in s;
533
+ var isEllipse = (s) => s.kind === "ellipse" && "ellipse" in s;
534
+ function arcsD(a, b, m, rx, ry, turn, sweep) {
535
+ const r = `${num2(rx)} ${num2(ry)}`;
536
+ if (turn >= 2 * Math.PI - 1e-9) return `M ${pt(a)} A ${r} 0 0 ${sweep} ${pt(m())} A ${r} 0 0 ${sweep} ${pt(b)}`;
537
+ return `M ${pt(a)} A ${r} 0 ${turn > Math.PI + 1e-9 ? 1 : 0} ${sweep} ${pt(b)}`;
538
+ }
539
+ function trackShapeD(shape, from = 0, to = 1) {
540
+ if (isPath(shape) && from === 0 && to === 1) return pathToD(shape.path);
541
+ const a = shape.at(from).point;
542
+ const b = shape.at(to).point;
543
+ if (shape.kind === "line") return `M ${pt(a)} L ${pt(b)}`;
544
+ const m = () => shape.at((from + to) / 2).point;
545
+ if (isArc(shape)) {
546
+ const { radius, direction } = shape.arc;
547
+ const turn = shape.length * Math.abs(to - from) / radius;
548
+ return arcsD(a, b, m, radius, radius, turn, direction === "ccw" === to < from ? 1 : 0);
549
+ }
550
+ if (isEllipse(shape)) {
551
+ const { radiusX, radiusY, direction, center } = shape.ellipse;
552
+ const param = (p) => Math.atan2((p.x - center.x) / radiusX, (center.y - p.y) / radiusY);
553
+ const sign2 = direction === "ccw" ? -1 : 1;
554
+ const whole = (shape.ellipse.start - shape.ellipse.end) % 360 === 0 && Math.abs(to - from) >= 1 - 1e-12;
555
+ const raw = (sign2 * Math.sign(to - from) * (param(b) - param(a)) + 4 * Math.PI) % (2 * Math.PI);
556
+ return arcsD(a, b, m, radiusX, radiusY, whole ? 2 * Math.PI : raw, direction === "ccw" === to < from ? 1 : 0);
557
+ }
558
+ let d = `M ${pt(a)}`;
559
+ for (let i = 1; i <= SAMPLES; i++)
560
+ d += ` L ${pt(shape.at(from + (to - from) * i / SAMPLES).point)}`;
561
+ return d;
562
+ }
563
+
564
+ // src/track/shift.ts
565
+ var SAMPLES2 = 256;
566
+ var dot2 = (a, b) => a.x * b.x + a.y * b.y;
567
+ function bendSide(shape) {
568
+ let turn = 0;
569
+ let prev = shape.at(0);
570
+ for (let i = 1; i <= SAMPLES2; i++) {
571
+ const next = shape.at(i / SAMPLES2);
572
+ turn += dot2({ x: next.tangent.x - prev.tangent.x, y: next.tangent.y - prev.tangent.y }, prev.normal);
573
+ prev = next;
574
+ }
575
+ return Math.abs(turn) < 1e-9 ? 0 : turn > 0 ? 1 : -1;
576
+ }
577
+ function shiftTrack(shape, shift) {
578
+ if (shift === 0) return shape;
579
+ const moved2 = (s) => ({ ...s, point: { x: s.point.x + shift * s.normal.x, y: s.point.y + shift * s.normal.y } });
580
+ const table = new Float64Array(SAMPLES2 + 1);
581
+ let prev = moved2(shape.at(0));
582
+ for (let i = 1; i <= SAMPLES2; i++) {
583
+ const next = moved2(shape.at(i / SAMPLES2));
584
+ const step = { x: next.point.x - prev.point.x, y: next.point.y - prev.point.y };
585
+ const tangent = { x: prev.tangent.x + next.tangent.x, y: prev.tangent.y + next.tangent.y };
586
+ if (shape.length > 0 && dot2(step, tangent) <= 0) return null;
587
+ table[i] = table[i - 1] + Math.hypot(step.x, step.y);
588
+ prev = next;
589
+ }
590
+ const length2 = table[SAMPLES2];
591
+ const per = shape.length / SAMPLES2;
592
+ const startRatio = table[1] > 0 ? per / table[1] : 1;
593
+ const endRatio = table[SAMPLES2] - table[SAMPLES2 - 1] > 0 ? per / (table[SAMPLES2] - table[SAMPLES2 - 1]) : 1;
594
+ const toBase = (f) => {
595
+ const d = f * length2;
596
+ if (length2 <= 0 || shape.length <= 0) return f;
597
+ if (d < 0) return d * startRatio / shape.length;
598
+ if (d > length2) return 1 + (d - length2) * endRatio / shape.length;
599
+ let lo = 0;
600
+ let hi = SAMPLES2;
601
+ while (hi - lo > 1) {
602
+ const mid = lo + hi >> 1;
603
+ if (table[mid] <= d) lo = mid;
604
+ else hi = mid;
605
+ }
606
+ const span = table[hi] - table[lo];
607
+ return (lo + (span > 0 ? (d - table[lo]) / span : 0)) / SAMPLES2;
608
+ };
609
+ const fromBase = (g) => {
610
+ if (length2 <= 0 || shape.length <= 0) return g;
611
+ if (g < 0) return g * shape.length / startRatio / length2;
612
+ if (g > 1) return (length2 + (g - 1) * shape.length / endRatio) / length2;
613
+ const x = g * SAMPLES2;
614
+ const i = Math.min(SAMPLES2 - 1, Math.floor(x));
615
+ return (table[i] + (x - i) * (table[i + 1] - table[i])) / length2;
616
+ };
617
+ const at2 = (f, options) => moved2(shape.at(toBase(options?.open ? f : clamp(f, 0, 1)), options));
618
+ return {
619
+ kind: shape.kind,
620
+ length: length2,
621
+ closed: shape.closed,
622
+ at: at2,
623
+ nearest(p, options) {
624
+ const base = shape.nearest(p, options?.open ? { open: true, about: toBase(options.about ?? 0.5) } : void 0);
625
+ const f = fromBase(base.f);
626
+ const q = at2(f, options).point;
627
+ return { f, dist: Math.hypot(p.x - q.x, p.y - q.y) };
628
+ }
629
+ };
630
+ }
631
+
632
+ // src/track/slice.ts
633
+ var RAD3 = Math.PI / 180;
634
+ var seen = (c, p) => Math.atan2(p.x - c.x, c.y - p.y) / RAD3;
635
+ function trackSlice(shape, from, to) {
636
+ const lo = clamp(Math.min(from, to), 0, 1);
637
+ const hi = clamp(Math.max(from, to), 0, 1);
638
+ if (lo === 0 && hi === 1) return shape;
639
+ const a = shape.at(lo).point;
640
+ const b = shape.at(hi).point;
641
+ if (shape.kind === "line") return lineShape(a, b);
642
+ if (shape.kind === "arc" && "arc" in shape) {
643
+ const { center, radius, direction } = shape.arc;
644
+ if (hi === lo) return arcShape({ center, radius: 0, start: 0, end: 0 });
645
+ return arcShape({ center, radius, start: seen(center, a), end: seen(center, b), direction });
646
+ }
647
+ if (shape.kind === "ellipse" && "ellipse" in shape) {
648
+ const { center, radiusX, radiusY, direction } = shape.ellipse;
649
+ if (hi === lo) return ellipseShape({ center, radiusX: 0, radiusY: 0, start: 0, end: 0 });
650
+ return ellipseShape({ center, radiusX, radiusY, start: seen(center, a), end: seen(center, b), direction });
651
+ }
652
+ const span = hi - lo;
653
+ return {
654
+ kind: shape.kind,
655
+ length: shape.length * span,
656
+ closed: false,
657
+ at: (f, options) => shape.at(lo + (options?.open ? f : clamp(f, 0, 1)) * span, options),
658
+ nearest(p) {
659
+ const n = shape.nearest(p);
660
+ const f = clamp(n.f, lo, hi);
661
+ const q = shape.at(f).point;
662
+ return { f: span === 0 ? 0 : (f - lo) / span, dist: Math.hypot(p.x - q.x, p.y - q.y) };
663
+ }
664
+ };
665
+ }
666
+
667
+ // src/track/place.ts
668
+ var clipOf = (lo, hi, start, end, hair = 0) => lo >= start - hair && hi <= end + hair ? "none" : hi <= start + hair || lo >= end - hair ? "past" : "part";
669
+ function runPlaces(lengths, gap, room, align, offset2, at2) {
670
+ const total = runLength(lengths, gap);
671
+ const fits = at2 === void 0 && total <= room;
672
+ const lead = align === "start" ? 0 : align === "end" ? total : total / 2;
673
+ let lo = at2 !== void 0 ? at2 - offset2 - lead : !fits ? -offset2 : align === "start" ? 0 : align === "end" ? room - total : (room - total) / 2;
674
+ return lengths.map((length2) => {
675
+ const start = lo;
676
+ const hi = start + length2;
677
+ lo = hi + gap;
678
+ return { center: start + length2 / 2, clipped: fits ? "none" : clipOf(start, hi, 0, room) };
679
+ });
680
+ }
681
+ function runLength(lengths, gap) {
682
+ return lengths.reduce((sum, length2, i) => sum + length2 + (i > 0 ? gap : 0), 0);
683
+ }
684
+ function runStationAt(run2, distance, shift = 0, past = "extend") {
685
+ const { length: length2 } = run2;
686
+ if (past === "follow" && length2 > 0) {
687
+ const place2 = run2.at(distance / length2, { open: true });
688
+ const { point: point2, normal: normal3 } = place2;
689
+ return { ...place2, point: { x: point2.x + shift * normal3.x, y: point2.y + shift * normal3.y } };
690
+ }
691
+ const place = run2.at(length2 === 0 ? 0 : distance / length2);
692
+ const beyond = distance < 0 ? distance : distance > length2 ? distance - length2 : 0;
693
+ const { point, tangent, normal: normal2 } = place;
694
+ return {
695
+ ...place,
696
+ point: { x: point.x + beyond * tangent.x + shift * normal2.x, y: point.y + beyond * tangent.y + shift * normal2.y }
697
+ };
698
+ }
699
+ function placeAlongRun(run2, lengths, options = {}) {
700
+ const { gap = 0, align = "center", offset: offset2 = 0, at: at2, shift = 0, wrap = false, past = "extend", order = "reading" } = options;
701
+ const { length: length2 } = run2;
702
+ const mirror = order === "track" && run2.reversed;
703
+ const spots = runPlaces(lengths, gap, length2, align, offset2, at2);
704
+ const lap = wrap && run2.closed && spots.length > 0 ? wrapWindow(spots[0], lengths[0], length2) : null;
705
+ return spots.map((spot, i) => {
706
+ const half = lengths[i] / 2;
707
+ const clipped = lap ? clipOf(spot.center - half, spot.center + half, lap.start, lap.end, lap.hair) : spot.clipped;
708
+ let distance = spot.center;
709
+ if (past === "hold" && clipped === "past") distance = clamp(distance, lap?.start ?? 0, lap?.end ?? length2);
710
+ if (lap && length2 > 0) distance = (distance % length2 + length2) % length2;
711
+ return { ...runStationAt(run2, mirror ? length2 - distance : distance, shift, past === "extend" ? "extend" : "follow"), center: spot.center, clipped };
712
+ });
713
+ }
714
+ function wrapWindow(first, firstLength, length2) {
715
+ const start = first.center - firstLength / 2;
716
+ return { start, end: start + length2, hair: 1e-9 * Math.max(1, length2) };
717
+ }
718
+
85
719
  // src/portCurve2.ts
86
720
  function portControls2(ax, ay, bx, by, outNormal, inNormal, reach = PORT_REACH) {
87
721
  const [c1, c2] = portControls([ax, ay], [bx, by], outNormal, inNormal, reach);
@@ -1074,17 +1708,17 @@ function arcToCubics(x1, y1, x2, y2, rx, ry, xAxisRotationDeg, largeArc, sweep,
1074
1708
  rys = ryFixed * ryFixed;
1075
1709
  }
1076
1710
  const sign2 = largeArc === sweep ? -1 : 1;
1077
- const num2 = rxs * rys - rxs * y1ps - rys * x1ps;
1711
+ const num3 = rxs * rys - rxs * y1ps - rys * x1ps;
1078
1712
  const den = rxs * y1ps + rys * x1ps;
1079
- const factor = sign2 * Math.sqrt(Math.max(0, num2 / den));
1713
+ const factor = sign2 * Math.sqrt(Math.max(0, num3 / den));
1080
1714
  const cxp = factor * (rxFixed * y1p) / ryFixed;
1081
1715
  const cyp = factor * -(ryFixed * x1p) / rxFixed;
1082
1716
  const cx = cosPhi * cxp - sinPhi * cyp + (x1 + x2) / 2;
1083
1717
  const cy = sinPhi * cxp + cosPhi * cyp + (y1 + y2) / 2;
1084
1718
  const angle = (ux, uy, vx, vy) => {
1085
- const dot2 = ux * vx + uy * vy;
1719
+ const dot3 = ux * vx + uy * vy;
1086
1720
  const len = Math.sqrt((ux * ux + uy * uy) * (vx * vx + vy * vy));
1087
- let a = Math.acos(Math.max(-1, Math.min(1, dot2 / len)));
1721
+ let a = Math.acos(Math.max(-1, Math.min(1, dot3 / len)));
1088
1722
  if (ux * vy - uy * vx < 0) a = -a;
1089
1723
  return a;
1090
1724
  };
@@ -1124,157 +1758,6 @@ function arcToCubics(x1, y1, x2, y2, rx, ry, xAxisRotationDeg, largeArc, sweep,
1124
1758
  }
1125
1759
  }
1126
1760
 
1127
- // src/paths/pathToD.ts
1128
- var num = (n) => Number.isFinite(n) ? String(Math.round(n * 1e6) / 1e6) : "0";
1129
- function pathToD(given) {
1130
- const path = resolveCorners(given);
1131
- if (path.kind === "rect") {
1132
- const { x, y, width, height } = path;
1133
- return `M${num(x)} ${num(y)}h${num(width)}v${num(height)}h${num(-width)}Z`;
1134
- }
1135
- const cmds = path.commands;
1136
- const xs = path.coords;
1137
- const out = [];
1138
- let ci = 0;
1139
- for (let i = 0; i < cmds.length; i++) {
1140
- const c = cmds[i];
1141
- if (c === PATH_M) {
1142
- out.push(`M${num(xs[ci])} ${num(xs[ci + 1])}`);
1143
- ci += 2;
1144
- } else if (c === PATH_L) {
1145
- out.push(`L${num(xs[ci])} ${num(xs[ci + 1])}`);
1146
- ci += 2;
1147
- } else if (c === PATH_C) {
1148
- out.push(
1149
- `C${num(xs[ci])} ${num(xs[ci + 1])} ${num(xs[ci + 2])} ${num(xs[ci + 3])} ${num(xs[ci + 4])} ${num(xs[ci + 5])}`
1150
- );
1151
- ci += 6;
1152
- } else if (c === PATH_Q) {
1153
- out.push(`Q${num(xs[ci])} ${num(xs[ci + 1])} ${num(xs[ci + 2])} ${num(xs[ci + 3])}`);
1154
- ci += 4;
1155
- } else if (c === PATH_Z) {
1156
- out.push("Z");
1157
- }
1158
- }
1159
- return out.join("");
1160
- }
1161
-
1162
- // src/paths/pathMeasure.ts
1163
- function measurePath(path, opts = {}) {
1164
- const polylines = extractPolylines(
1165
- path,
1166
- opts.flattenTolerance === void 0 ? {} : { flattenTolerance: opts.flattenTolerance }
1167
- );
1168
- const segments = [];
1169
- let total = 0;
1170
- let first;
1171
- let contours = 0;
1172
- let lastClosed = false;
1173
- for (const pl of polylines) {
1174
- const count = pl.points.length / 2;
1175
- if (count === 0) continue;
1176
- contours++;
1177
- lastClosed = pl.closed;
1178
- first ??= { x: pl.points[0], y: pl.points[1] };
1179
- const startIndex = segments.length;
1180
- const last = pl.closed ? count : count - 1;
1181
- for (let i = 0; i < last; i++) {
1182
- const j = (i + 1) % count;
1183
- const ax = pl.points[i * 2];
1184
- const ay = pl.points[i * 2 + 1];
1185
- const bx = pl.points[j * 2];
1186
- const by = pl.points[j * 2 + 1];
1187
- const len = Math.hypot(bx - ax, by - ay);
1188
- if (len === 0) continue;
1189
- const tx = (bx - ax) / len;
1190
- const ty = (by - ay) / len;
1191
- segments.push({ ax, ay, bx, by, start: total, len, tx, ty, t0x: tx, t0y: ty, t1x: tx, t1y: ty });
1192
- total += len;
1193
- }
1194
- smoothVertexHeadings(segments, startIndex, pl.closed);
1195
- }
1196
- if (first === void 0) return null;
1197
- const origin = first;
1198
- const closed = contours === 1 && lastClosed;
1199
- if (segments.length === 0) {
1200
- return {
1201
- length: 0,
1202
- closed,
1203
- at: () => ({ point: { ...origin }, tangent: { x: 1, y: 0 } }),
1204
- nearest: (p) => ({
1205
- s: 0,
1206
- dist: Math.hypot(p.x - origin.x, p.y - origin.y),
1207
- point: { ...origin },
1208
- tangent: { x: 1, y: 0 }
1209
- })
1210
- };
1211
- }
1212
- return {
1213
- length: total,
1214
- closed,
1215
- at(s, smooth = false) {
1216
- const target = Math.min(Math.max(s, 0), total);
1217
- const seg = segments[segmentAt(segments, target)];
1218
- const u = Math.min(Math.max((target - seg.start) / seg.len, 0), 1);
1219
- const point = { x: seg.ax + (seg.bx - seg.ax) * u, y: seg.ay + (seg.by - seg.ay) * u };
1220
- if (!smooth) return { point, tangent: { x: seg.tx, y: seg.ty } };
1221
- const x = seg.t0x + (seg.t1x - seg.t0x) * u;
1222
- const y = seg.t0y + (seg.t1y - seg.t0y) * u;
1223
- const l = Math.hypot(x, y);
1224
- return { point, tangent: l === 0 ? { x: seg.tx, y: seg.ty } : { x: x / l, y: y / l } };
1225
- },
1226
- nearest(p) {
1227
- let best = segments[0];
1228
- let bestU = 0;
1229
- let bestDist = Infinity;
1230
- for (const seg of segments) {
1231
- const u = Math.min(Math.max(((p.x - seg.ax) * seg.tx + (p.y - seg.ay) * seg.ty) / seg.len, 0), 1);
1232
- const d = Math.hypot(p.x - (seg.ax + (seg.bx - seg.ax) * u), p.y - (seg.ay + (seg.by - seg.ay) * u));
1233
- if (d < bestDist) {
1234
- best = seg;
1235
- bestU = u;
1236
- bestDist = d;
1237
- }
1238
- }
1239
- return {
1240
- s: best.start + best.len * bestU,
1241
- dist: bestDist,
1242
- point: { x: best.ax + (best.bx - best.ax) * bestU, y: best.ay + (best.by - best.ay) * bestU },
1243
- tangent: { x: best.tx, y: best.ty }
1244
- };
1245
- }
1246
- };
1247
- }
1248
- function smoothVertexHeadings(segments, from, closed) {
1249
- const n = segments.length - from;
1250
- if (n < 2) return;
1251
- const pairs = closed ? n : n - 1;
1252
- for (let k = 0; k < pairs; k++) {
1253
- const a = segments[from + k];
1254
- const b = segments[from + (k + 1) % n];
1255
- let x = a.tx + b.tx;
1256
- let y = a.ty + b.ty;
1257
- const l = Math.hypot(x, y);
1258
- if (l < 1e-9) continue;
1259
- x /= l;
1260
- y /= l;
1261
- a.t1x = x;
1262
- a.t1y = y;
1263
- b.t0x = x;
1264
- b.t0y = y;
1265
- }
1266
- }
1267
- function segmentAt(segments, s) {
1268
- let lo = 0;
1269
- let hi = segments.length - 1;
1270
- while (lo < hi) {
1271
- const mid = lo + hi + 1 >> 1;
1272
- if (segments[mid].start <= s) lo = mid;
1273
- else hi = mid - 1;
1274
- }
1275
- return lo;
1276
- }
1277
-
1278
1761
  // src/paths/pathAt.ts
1279
1762
  function pointAlongPath(path, t, opts = {}) {
1280
1763
  const measure2 = measurePath(path, opts);
@@ -1836,17 +2319,17 @@ var GL_W2 = [
1836
2319
  0.2223810344533745,
1837
2320
  0.1012285362903763
1838
2321
  ];
1839
- var speed = (s, t) => {
2322
+ var speed2 = (s, t) => {
1840
2323
  const d = derivSeg(s, t);
1841
2324
  return Math.hypot(d.x, d.y);
1842
2325
  };
1843
2326
  function segmentLength(s, a = 0, b = 1) {
1844
- if (s.length === 2) return speed(s, 0) * (b - a);
2327
+ if (s.length === 2) return speed2(s, 0) * (b - a);
1845
2328
  const panels = 8, h = (b - a) / panels;
1846
2329
  let sum = 0;
1847
2330
  for (let k = 0; k < panels; k++) {
1848
2331
  const mid = a + (k + 0.5) * h;
1849
- for (let i = 0; i < GL_X.length; i++) sum += GL_W2[i] * speed(s, mid + GL_X[i] * h / 2);
2332
+ for (let i = 0; i < GL_X.length; i++) sum += GL_W2[i] * speed2(s, mid + GL_X[i] * h / 2);
1850
2333
  }
1851
2334
  return sum * h / 2;
1852
2335
  }
@@ -1861,7 +2344,7 @@ function segmentTAtLength(s, length2) {
1861
2344
  if (Math.abs(err) < 1e-10 * Math.max(1, total)) break;
1862
2345
  if (err > 0) hi = t;
1863
2346
  else lo = t;
1864
- const v = speed(s, t);
2347
+ const v = speed2(s, t);
1865
2348
  let next = v > 0 ? t - err / v : NaN;
1866
2349
  if (!(next > lo && next < hi)) next = (lo + hi) / 2;
1867
2350
  t = next;
@@ -1952,12 +2435,12 @@ function createPathSnapIndex(paths, extra = []) {
1952
2435
  if (kind === "center") return out;
1953
2436
  if (kind === "anchor") {
1954
2437
  segments.forEach((segs, path) => {
1955
- const seen = /* @__PURE__ */ new Set();
2438
+ const seen2 = /* @__PURE__ */ new Set();
1956
2439
  for (const s of segs) {
1957
2440
  for (const p of [s.pts[0], s.pts[s.pts.length - 1]]) {
1958
2441
  const key = `${p.x},${p.y}`;
1959
- if (seen.has(key)) continue;
1960
- seen.add(key);
2442
+ if (seen2.has(key)) continue;
2443
+ seen2.add(key);
1961
2444
  out.push({ kind: "anchor", x: p.x, y: p.y, paths: [path] });
1962
2445
  }
1963
2446
  }
@@ -2868,7 +3351,7 @@ function breaksOf(sub3, closed, cosCorner) {
2868
3351
  const n = sub3.length;
2869
3352
  const breaks = /* @__PURE__ */ new Set();
2870
3353
  for (let i = 0; i < n; i++) {
2871
- if (isCorner(sub3, i, closed, cosCorner)) breaks.add(i);
3354
+ if (isCorner2(sub3, i, closed, cosCorner)) breaks.add(i);
2872
3355
  if (isLongStraight(sub3, i, closed)) {
2873
3356
  breaks.add(i);
2874
3357
  breaks.add((i + 1) % n);
@@ -2888,7 +3371,7 @@ function fitStops(sub3, stops, tol, out, closing) {
2888
3371
  if (!last) keepCorner(out[out.length - 1], sub3[stops[k + 1] % n]);
2889
3372
  }
2890
3373
  }
2891
- function isCorner(sub3, i, closed, cosCorner) {
3374
+ function isCorner2(sub3, i, closed, cosCorner) {
2892
3375
  const n = sub3.length;
2893
3376
  const a = sub3[i];
2894
3377
  const prev = sub3[(i - 1 + n) % n];
@@ -2945,7 +3428,7 @@ function unit(p) {
2945
3428
 
2946
3429
  // src/paths/growRegion.ts
2947
3430
  var MAX_DEPTH2 = 6;
2948
- var SAMPLES = [0.2, 0.35, 0.5, 0.65, 0.8];
3431
+ var SAMPLES3 = [0.2, 0.35, 0.5, 0.65, 0.8];
2949
3432
  function growRegion(path, distance, opts = {}) {
2950
3433
  const b = new PathBuilder();
2951
3434
  if (!(distance > 0)) return b.build();
@@ -2984,15 +3467,15 @@ function joinPieces(prev, next, v, tin, tout, ctx) {
2984
3467
  const gap = Math.hypot(b[0] - a[0], b[1] - a[1]);
2985
3468
  if (gap <= ctx.tol * 1e-3) return [];
2986
3469
  const cross2 = tin[0] * tout[1] - tin[1] * tout[0];
2987
- const dot2 = tin[0] * tout[0] + tin[1] * tout[1];
2988
- const convex = ctx.sigma * cross2 > 0 || Math.abs(cross2) < 1e-9 && dot2 < 0;
3470
+ const dot3 = tin[0] * tout[0] + tin[1] * tout[1];
3471
+ const convex = ctx.sigma * cross2 > 0 || Math.abs(cross2) < 1e-9 && dot3 < 0;
2989
3472
  if (gap <= ctx.tol) return snap(prev, next, a);
2990
3473
  if (!convex) {
2991
3474
  if (trimAtCrossing(prev, next)) return [];
2992
3475
  return [lineSegment(a[0], a[1], v[0], v[1]), lineSegment(v[0], v[1], b[0], b[1])];
2993
3476
  }
2994
3477
  const nin = normal(tin, ctx.sigma), nout = normal(tout, ctx.sigma);
2995
- if (ctx.join === "round") return arc(v, ctx.d, nin, Math.atan2(cross2, dot2));
3478
+ if (ctx.join === "round") return arc(v, ctx.d, nin, Math.atan2(cross2, dot3));
2996
3479
  const cos = nin[0] * nout[0] + nin[1] * nout[1];
2997
3480
  if (1 + cos < 1e-9 || Math.sqrt(2 / (1 + cos)) > ctx.miterLimit) return [lineSegment(a[0], a[1], b[0], b[1])];
2998
3481
  const k = ctx.d / (1 + cos);
@@ -3118,7 +3601,7 @@ function offsetSeg(seg, ctx, depth) {
3118
3601
  }
3119
3602
  function offsetError(c, q, ctx) {
3120
3603
  let worst2 = 0;
3121
- for (const t of SAMPLES) {
3604
+ for (const t of SAMPLES3) {
3122
3605
  const [dx2, dy2] = derivative(c, t);
3123
3606
  const len = Math.hypot(dx2, dy2);
3124
3607
  if (len < 1e-12) continue;
@@ -6304,6 +6787,6 @@ function typedArrayReplacer(_key, value) {
6304
6787
  return tagTypedArray(value) ?? value;
6305
6788
  }
6306
6789
 
6307
- export { ANCHOR_FIELDS, CONSTRAINT_TOLERANCE, EASINGS, PATH_SNAP_KINDS, SPRING_PRESETS, TYPED_ARRAY_CONSTRUCTORS, ZOOM_FLOOR, addExtremaAnchors, anchorAt, anchorCount, anchorOriginsOf, anchorSymmetries, anchorSymmetry, anchorsBefore, anchorsInRect, anchorsUnderBrush, anchorsWhere, applyToPoint, averageAnchorsAt, balanceFactorToward, bendAlongPath, bendSegment, blendPaths, boxToBox, circlePath, clampRectWithin, closestOpenEnds, composePath, conflictingConstraints, constrainPathEdit, constrainPathsEdit, constraintAnchors, constraintApplies, constraintFits, convertSegments, cornerAnchors, createPathSnapIndex, cubicBezierEasing, cubicContoursToPath, decomposePath, deleteAnchorsAt, directionMarks, 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, editAnchorSet, editAnchorSetTracked, equalizeSegmentHandles, everyNthAnchor, extendToMeet, findPathSnap, findPathSnaps, fitAffine, fitCubicThroughDeletion, flatAnchorIndex, flatIndexesAfterReverse, growAnchorSelection, growRegion, handleAlongItsAngle, handleAtItsLength, handleBalances, harmonizeAnchors, hasOpenSubpath, identity, insertAnchorOnSegment, intersectSegments, invert, invertAnchorSelection, isSegmentStraight, joinAnchorsAt, joinSubpathEnds, lengthToward, lengthenOpenEnd, lengthenPathEnd, linear, locateAnchor, makeHandlesSymmetric, mapConstraintAnchors, mat3, meanScale, measureAnchorPath, measurePath, mergeRegion, moveHandleSymmetric, moveHandleTo, multiply, nearestPathAnchor, normalizeZoom, offsetCornerTraces, openEndAt, openEndRay, openPathEnds, openSubpathAt, pathAnchorPoints, pathAwayFromAnchors, pathContainsPoint, pathContainsPolygon, pathContainsRect, pathCrossings, pathDistanceToPoint, pathEndAnchorIndex, pathEndFrame, pathFromD, pathInPoseFrame, pathInWorld, pathIntersectsPolygon, pathIntersectsRect, pathSegments, pathSignedArea, pathThroughPoseFrame, pathToCubicContours, pathToD, placeRect, pointAlongPath, pointInPath, polygonContainsPath, polygonIntersectsPath, portControls2 as portControls, portCurvePoints2 as portCurvePoints, poseFrameInverseOf, poseFrameOf, poseLinearOf, poseRotationOf, prepareBlend, pxExtent, readAnchorFields, rectMarkerPath, remapAnchorValues, remapConstraints, remapPointValues, repeatAlongPath, resamplePath, resolveEasing, retractHandles, reverseAnchors, reversePath, reverseSubpaths, reviveTypedArrays, rotate, rotateAboutPoint, rotatePathAround, roundRectPath, scale, scaleDelta, scalePathToBounds, scaleSegmentHandles, screenAngleOf, segmentAt2 as segmentAt, segmentBetween, segmentExtremaTs, segmentsBetweenAnchors, setSubpathStart, shrinkAnchorSelection, simplifyAnchorsAt, simplifyPath, simplifySpan, simplifySubpath, smoothAnchors, smudgePath, softFalloff, softSelectionBand, softSelectionWeights, solveConstraints, solvePathConstraints, splitByClosure, splitSubpaths, squarePath, standoff, stationsAlongPath, strokeHitTest, subpathEndAt, subpathsOfAnchors, tagTypedArray, tagTypedArrays, transformCoords, transformPath, translate, translateAnchorBy, translateAnchorsSymmetric, translatePath, trimPathAt, typedArrayReplacer, unionBoundsPath, unsatisfiedConstraints, untagTypedArray, viewToMat3, withAnchorPoints, withinPxBox, withinPxRadius, worldEditToStorage, writeAnchorField };
6790
+ export { ANCHOR_FIELDS, CONSTRAINT_TOLERANCE, EASINGS, PATH_SNAP_KINDS, SPRING_PRESETS, TYPED_ARRAY_CONSTRUCTORS, ZOOM_FLOOR, addExtremaAnchors, anchorAt, anchorCount, anchorOriginsOf, anchorSymmetries, anchorSymmetry, anchorsBefore, anchorsInRect, anchorsUnderBrush, anchorsWhere, applyToPoint, arcShape, averageAnchorsAt, balanceFactorToward, bendAlongPath, bendSegment, bendSide, blendPaths, boxToBox, circlePath, clampRectWithin, closestOpenEnds, composePath, conflictingConstraints, constrainPathEdit, constrainPathsEdit, constraintAnchors, constraintApplies, constraintFits, convertSegments, cornerAnchors, createPathSnapIndex, cubicBezierEasing, cubicContoursToPath, decomposePath, deleteAnchorsAt, directionMarks, 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, editAnchorSet, editAnchorSetTracked, ellipseShape, equalizeSegmentHandles, everyNthAnchor, extendToMeet, findPathSnap, findPathSnaps, fitAffine, fitCubicThroughDeletion, flatAnchorIndex, flatIndexesAfterReverse, growAnchorSelection, growRegion, handleAlongItsAngle, handleAtItsLength, handleBalances, harmonizeAnchors, hasOpenSubpath, identity, insertAnchorOnSegment, intersectSegments, invert, invertAnchorSelection, isSegmentStraight, joinAnchorsAt, joinSubpathEnds, lengthToward, lengthenOpenEnd, lengthenPathEnd, lineShape, linear, locateAnchor, makeHandlesSymmetric, mapConstraintAnchors, mat3, meanScale, measureAnchorPath, measurePath, mergeRegion, moveHandleSymmetric, moveHandleTo, multiply, nearestPathAnchor, normalizeZoom, offsetCornerTraces, openEndAt, openEndRay, openPathEnds, openSubpathAt, pathAnchorPoints, pathAwayFromAnchors, pathContainsPoint, pathContainsPolygon, pathContainsRect, pathCrossings, pathDistanceToPoint, pathEndAnchorIndex, pathEndFrame, pathFromD, pathInPoseFrame, pathInWorld, pathIntersectsPolygon, pathIntersectsRect, pathSegments, pathShape, pathSignedArea, pathThroughPoseFrame, pathToCubicContours, pathToD, placeAlongRun, placeRect, pointAlongPath, pointInPath, polygonContainsPath, polygonIntersectsPath, portControls2 as portControls, portCurvePoints2 as portCurvePoints, poseFrameInverseOf, poseFrameOf, poseLinearOf, poseRotationOf, prepareBlend, pxExtent, readAnchorFields, rectMarkerPath, remapAnchorValues, remapConstraints, remapPointValues, repeatAlongPath, resamplePath, resolveEasing, retractHandles, reverseAnchors, reversePath, reverseSubpaths, reviveTypedArrays, rotate, rotateAboutPoint, rotatePathAround, roundRectPath, runLength, runPlaces, runStationAt, scale, scaleDelta, scalePathToBounds, scaleSegmentHandles, screenAngleOf, segmentAt2 as segmentAt, segmentBetween, segmentExtremaTs, segmentsBetweenAnchors, setSubpathStart, shiftTrack, shrinkAnchorSelection, simplifyAnchorsAt, simplifyPath, simplifySpan, simplifySubpath, smoothAnchors, smudgePath, softFalloff, softSelectionBand, softSelectionWeights, solveConstraints, solvePathConstraints, splitByClosure, splitSubpaths, squarePath, standoff, stationsAlongPath, strokeHitTest, subpathEndAt, subpathsOfAnchors, tagTypedArray, tagTypedArrays, trackRun, trackShapeD, trackSlice, transformCoords, transformPath, translate, translateAnchorBy, translateAnchorsSymmetric, translatePath, trimPathAt, typedArrayReplacer, unionBoundsPath, unsatisfiedConstraints, untagTypedArray, viewToMat3, withAnchorPoints, withinPxBox, withinPxRadius, worldEditToStorage, writeAnchorField };
6308
6791
  //# sourceMappingURL=index.js.map
6309
6792
  //# sourceMappingURL=index.js.map