@weasel-js/core 1.5.1 → 1.6.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/CHANGELOG.md +273 -0
- package/dist/{autoPoseDescriptor-Dr6CwNZK.d.ts → autoPoseDescriptor-_XOyF7t4.d.ts} +2 -1
- package/dist/{chunk-P6MGECVO.js → chunk-44EWMJV2.js} +3 -3
- package/dist/{chunk-P6MGECVO.js.map → chunk-44EWMJV2.js.map} +1 -1
- package/dist/{chunk-XXQ6FLCJ.js → chunk-H6N2JSZ3.js} +3 -3
- package/dist/{chunk-XXQ6FLCJ.js.map → chunk-H6N2JSZ3.js.map} +1 -1
- package/dist/{chunk-HAGOFNP5.js → chunk-HPFJUUTF.js} +25 -20
- package/dist/chunk-HPFJUUTF.js.map +1 -0
- package/dist/{chunk-3LPQ2XZG.js → chunk-L5YNZYEG.js} +8 -13
- package/dist/chunk-L5YNZYEG.js.map +1 -0
- package/dist/{chunk-LXJDWBEL.js → chunk-PNNZSYRD.js} +2 -2
- package/dist/{chunk-LXJDWBEL.js.map → chunk-PNNZSYRD.js.map} +1 -1
- package/dist/{chunk-GREL4MVO.js → chunk-THCSDHII.js} +2084 -1344
- package/dist/chunk-THCSDHII.js.map +1 -0
- package/dist/clipboard.d.ts +2 -1
- package/dist/clone.d.ts +3 -2
- package/dist/{depSchema-BubKMv-2.d.ts → depSchema-BhgZc0-Q.d.ts} +79 -55
- package/dist/{grid-Z_Af3vTl.d.ts → grid-Dx2gQbNv.d.ts} +22 -6
- package/dist/index.d.ts +374 -92
- package/dist/index.js +6 -6
- package/dist/insert.d.ts +4 -3
- package/dist/insert.js +2 -2
- package/dist/{math-E3rZn4bR.d.ts → math-DRa6HBBs.d.ts} +7 -21
- package/dist/math.d.ts +5 -4
- package/dist/math.js +2 -2
- package/dist/move.d.ts +5 -4
- package/dist/move.js +3 -3
- package/dist/{options-BPcmwYk7.d.ts → options-CzjxFoYZ.d.ts} +1 -1
- package/dist/path-JEV2c5If.d.ts +48 -0
- package/dist/{pointSnapToGrid-CgcK2R_I.d.ts → pointSnapToGrid-7mCcm6qG.d.ts} +1 -1
- package/dist/{poseDescriptor-PgfVKfa0.d.ts → poseDescriptor-rZa9W5hJ.d.ts} +1 -48
- package/dist/renderer.d.ts +8 -7
- package/dist/renderer.js +6 -6
- package/dist/resize.d.ts +6 -5
- package/dist/resize.js +3 -3
- package/dist/{types-BdaK9PcP.d.ts → types-CxC8P6W0.d.ts} +27 -1
- package/dist/{types-BHGdrOcu.d.ts → types-D_74YlWs.d.ts} +1 -1
- package/package.json +10 -10
- package/dist/chunk-3LPQ2XZG.js.map +0 -1
- package/dist/chunk-GREL4MVO.js.map +0 -1
- package/dist/chunk-HAGOFNP5.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/units.ts","../src/interactions/gestures/shared/strategies/grid.ts","../src/core/viewport/pxExtent.ts","../src/interactions/gestures/shared/strategies/guides.ts"],"names":[],"mappings":"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","file":"chunk-HPFJUUTF.js","sourcesContent":["/**\n * Units — a tiny customizable unit system for canvas-kit APIs.\n *\n * The kit stores all coordinates as bare numbers in a single base unit\n * chosen by the consumer app. To make API call sites self-documenting,\n * the public surface accepts `UnitValue` — either a bare number (interpreted\n * as base units) or a `{ value, unit }` tag that's resolved against a\n * `UnitSystem` at the API boundary. Internals never see units.\n *\n * An entry is affine — `base = value * factor + offset` — so a scale that\n * puts zero somewhere else (degC against K) is expressible. No per-axis\n * units. No mixed-unit arithmetic.\n */\n\n/** A unit name (e.g. `'in'`, `'ft'`, `'mm'`). Looked up in a `UnitSystem`. */\nexport type Unit = string;\n\n/** What one unit is worth in base units: `base = value * factor + offset`. */\nexport interface UnitScale {\n factor: number;\n /** Where this unit puts zero, in base units. Absent is 0 — a pure scale. */\n offset?: number;\n}\n\n/** One unit's conversion. A bare number is the `{ factor }` shorthand. */\nexport type UnitEntry = number | UnitScale;\n\n/** Conversion table mapping unit names to their scale against a base unit. */\nexport interface UnitSystem {\n /** Name of the base unit, e.g. 'in'. All conversions resolve to this. */\n base: Unit;\n /** How to reach base units from each unit. The base unit's entry is 1. */\n units: Record<Unit, UnitEntry>;\n}\n\n/**\n * One unit's scale, with the bare-number shorthand widened and the offset\n * defaulted — what every conversion in the kit reads. Throws if the system\n * does not carry the unit.\n */\nexport function unitScale(unitSystem: UnitSystem, unit: Unit): Required<UnitScale> {\n const entry = unitSystem.units[unit];\n if (entry === undefined) {\n const known = Object.keys(unitSystem.units).join(', ') || '(none)';\n throw new Error(\n `unknown unit '${unit}' (system base: '${unitSystem.base}', known units: ${known})`,\n );\n }\n return typeof entry === 'number'\n ? { factor: entry, offset: 0 }\n : { factor: entry.factor, offset: entry.offset ?? 0 };\n}\n\n/** Value at a unit-aware API boundary: bare number (in base units) or `{ value, unit }` tag. */\nexport type UnitValue = number | { value: number; unit: Unit };\n\n/**\n * Resolve a UnitValue to a number in base units.\n * - bare number: returned as-is (assumed base)\n * - tagged: looks up factor; throws if unit not in unit system\n */\nexport function resolveUnit(v: UnitValue, unitSystem?: UnitSystem): number {\n if (typeof v === 'number') return v;\n if (!unitSystem) {\n throw new Error(\n `resolveUnit: tagged value { value: ${v.value}, unit: '${v.unit}' } requires a UnitSystem`,\n );\n }\n const { factor, offset } = scaleOrThrow('resolveUnit', unitSystem, v.unit);\n return v.value * factor + offset;\n}\n\n/**\n * Format a base-unit number as a string in the named display unit.\n * e.g. formatUnit(36, 'ft', IMPERIAL_INCHES) => '3ft'\n * Default precision: 2. Trailing zeros trimmed.\n */\nexport function formatUnit(\n baseValue: number,\n displayUnit: Unit,\n unitSystem: UnitSystem,\n opts?: { precision?: number; suffix?: boolean },\n): string {\n const { factor, offset } = scaleOrThrow('formatUnit', unitSystem, displayUnit);\n const precision = opts?.precision ?? 2;\n const suffix = opts?.suffix ?? true;\n const display = (baseValue - offset) / factor;\n // Trim trailing zeros (and a dangling decimal point) without losing precision.\n let s = display.toFixed(precision);\n if (s.includes('.')) {\n s = s.replace(/0+$/, '').replace(/\\.$/, '');\n }\n return suffix ? `${s}${displayUnit}` : s;\n}\n\n/** `unitScale`, with the caller's name in front of the message. */\nfunction scaleOrThrow(caller: string, unitSystem: UnitSystem, unit: Unit): Required<UnitScale> {\n try {\n return unitScale(unitSystem, unit);\n } catch (e) {\n throw new Error(`${caller}: ${e instanceof Error ? e.message : String(e)}`);\n }\n}\n\n/** Imperial unit system with base 'in'. */\nexport const IMPERIAL_INCHES: UnitSystem = {\n base: 'in',\n units: { in: 1, ft: 12, yd: 36, mi: 63360 },\n};\n\n/** Metric unit system with base 'mm'. */\nexport const METRIC_MM: UnitSystem = {\n base: 'mm',\n units: { mm: 1, cm: 10, m: 1000, km: 1_000_000 },\n};\n\n/** Angle unit system with base 'rad'. */\nexport const ANGLE_RADIANS: UnitSystem = {\n base: 'rad',\n units: { rad: 1, deg: Math.PI / 180, turn: Math.PI * 2 },\n};\n\n/** Pixel unit system — sole unit is the base. */\nexport const PIXELS: UnitSystem = {\n base: 'px',\n units: { px: 1 },\n};\n","import type { SnapStrategy } from '../../types';\nimport { resolveUnit, type UnitSystem, type UnitValue } from 'core/units';\nimport type { DebugSink } from '../../../../debug/types';\nimport { isPathLike } from 'interactions/actions/resize/autoPoseDescriptor';\nimport { boundsOfPath } from 'features/paths/bounds';\nimport { translatePath } from 'features/paths/transform';\nimport type { Path } from 'features/paths/types';\n\n/**\n * Projection used by `gridSnapStrategy` when `TPose` doesn't expose `{x,y}`\n * directly (Path, polygon, etc.). The strategy reads the snap point via\n * `getOrigin`, rounds it to the grid, then asks `translate` to move the\n * pose by the resulting delta.\n */\nexport interface OriginProjection<TPose> {\n getOrigin(pose: TPose): { x: number; y: number };\n translate(pose: TPose, dx: number, dy: number): TPose;\n}\n\n/** Identity projection for `TPose extends { x; y }`. */\nexport const RECT_ORIGIN_PROJECTION: OriginProjection<{ x: number; y: number }> = {\n getOrigin: (p) => ({ x: p.x, y: p.y }),\n translate: (p, dx, dy) => ({ ...p, x: p.x + dx, y: p.y + dy }),\n};\n\n/** Per-call dispatch: routes Path-shaped poses to the path origin/translate\n * helpers and everything else to `RECT_ORIGIN_PROJECTION`. Default for\n * `gridSnapStrategy` so consumers with Path TPose don't have to thread\n * `pathOriginProjection` explicitly. */\nexport const AUTO_ORIGIN_PROJECTION: OriginProjection<unknown> = {\n getOrigin: (p) => {\n if (isPathLike(p)) {\n const b = boundsOfPath(p as Path);\n return { x: b.x, y: b.y };\n }\n const r = p as { x: number; y: number };\n return { x: r.x, y: r.y };\n },\n translate: (p, dx, dy) => {\n if (isPathLike(p)) return translatePath(p as Path, dx, dy);\n const r = p as { x: number; y: number };\n return { ...r, x: r.x + dx, y: r.y + dy };\n },\n};\n\n/** Snap-strategy that rounds the pose's origin to the nearest multiple of\n * `spacing` (resolved through `unitSystem`). For non-rect TPose pass an\n * `OriginProjection` so the strategy knows how to read/write the origin. */\nexport function gridSnapStrategy<TPose>(\n spacing: UnitValue,\n unitSystem?: UnitSystem,\n): SnapStrategy<TPose>;\n/** As above, additionally reporting each candidate to a debug sink. */\nexport function gridSnapStrategy<TPose>(\n spacing: UnitValue,\n opts: { unitSystem?: UnitSystem; debug?: DebugSink },\n): SnapStrategy<TPose>;\n/** As above, for a `TPose` that is not a rect: `origin` tells the strategy how\n * to read and write the pose's origin. */\nexport function gridSnapStrategy<TPose>(\n spacing: UnitValue,\n opts: { unitSystem?: UnitSystem; origin: OriginProjection<TPose>; debug?: DebugSink },\n): SnapStrategy<TPose>;\n/** Snap-strategy that rounds the pose's origin to the nearest multiple of\n * `spacing` (resolved through `unitSystem`). For non-rect TPose pass an\n * `OriginProjection` so the strategy knows how to read/write the origin. */\nexport function gridSnapStrategy<TPose>(\n spacing: UnitValue,\n arg?: UnitSystem | { unitSystem?: UnitSystem; origin?: OriginProjection<TPose>; debug?: DebugSink },\n): SnapStrategy<TPose> {\n const isOpts =\n typeof arg === 'object' &&\n arg !== null &&\n ('origin' in arg || 'debug' in arg || 'unitSystem' in arg) &&\n !('base' in arg);\n const optsArg = isOpts\n ? (arg as { unitSystem?: UnitSystem; origin?: OriginProjection<TPose>; debug?: DebugSink })\n : null;\n const unitSystem = optsArg ? optsArg.unitSystem : (arg as UnitSystem | undefined);\n const proj: OriginProjection<TPose> = optsArg && optsArg.origin\n ? optsArg.origin\n : (AUTO_ORIGIN_PROJECTION as unknown as OriginProjection<TPose>);\n const debug: DebugSink | undefined = optsArg ? optsArg.debug : undefined;\n const c = resolveUnit(spacing, unitSystem);\n return {\n snap(pose) {\n const o = proj.getOrigin(pose);\n const sx = Math.round(o.x / c) * c;\n const sy = Math.round(o.y / c) * c;\n debug?.recordSnapCandidate({ x: sx, y: sy }, true);\n return proj.translate(pose, sx - o.x, sy - o.y);\n },\n };\n}\n\n/**\n * Compute the integer cell `{col, row}` that contains `point`, given a grid\n * `spacing` and optional `origin` and `unitSystem`. Pair with\n * `createCellHighlightLayer` (its `getCell` callback) to draw a snap-target\n * preview that uses the same spacing as `gridSnapStrategy` — so the visual\n * and behavioral grids stay in lockstep:\n *\n * const SPACING = 20;\n * const snap = gridSnapStrategy(SPACING);\n * // visual grid:\n * createGridLayer({ spacing: SPACING, bounds: () => ... });\n * // hover-preview overlay:\n * createCellHighlightLayer({\n * spacing: SPACING,\n * getCell: () => hoverPoint && pointToGridCell(hoverPoint, SPACING),\n * });\n */\nexport function pointToGridCell(\n point: { x: number; y: number },\n spacing: UnitValue,\n unitSystem?: UnitSystem,\n origin: { x: number; y: number } = { x: 0, y: 0 },\n): { col: number; row: number } {\n const s = resolveUnit(spacing, unitSystem);\n return {\n col: Math.floor((point.x - origin.x) / s),\n row: Math.floor((point.y - origin.y) / s),\n };\n}\n","/**\n * Screen-pixel lengths in world units, per axis.\n *\n * Chrome declares its hit zones in screen pixels — an 8px handle stays 8px at\n * every zoom, because it paints in screen space. Converting one such length to\n * world units with a single scalar (see `meanScale`) is exact only under\n * uniform zoom; per-axis it is too generous on one axis and too mean on the\n * other, so the pickable region stops matching the painted one.\n *\n * Prefer {@link withinPxBox} / {@link withinPxRadius}, which compare in screen\n * space and so can't drift from the paint at all. {@link pxExtent} is for the\n * cases that must stay in world units — a tolerance handed to geometry that\n * doesn't know about the view.\n */\n\nexport interface Scale2 {\n x: number;\n y: number;\n}\n\n/** One screen-pixel length as world-space extents, per axis. `scale` is a\n * view's, so neither axis is zero (see `View`). */\nexport function pxExtent(px: number, scale: Scale2): { x: number; y: number } {\n return {\n x: px / Math.abs(scale.x),\n y: px / Math.abs(scale.y),\n };\n}\n\n/** World delta → screen delta. Only the scale participates: translation\n * cancels in a difference, and the kit's views carry no skew. */\nexport function scaleDelta(dx: number, dy: number, scale: Scale2): { x: number; y: number } {\n return { x: dx * scale.x, y: dy * scale.y };\n}\n\n/**\n * Is a world-space delta inside a screen-space square of half-extent `px`?\n *\n * The square is axis-aligned **on screen**, which is what a handle painted in\n * screen space actually is — so this stays true under non-uniform zoom and\n * under a rotated target, where an axis-aligned world-space test is a rotated\n * rectangle on screen.\n */\nexport function withinPxBox(dx: number, dy: number, px: number, scale: Scale2): boolean {\n const s = scaleDelta(dx, dy, scale);\n return Math.abs(s.x) <= px && Math.abs(s.y) <= px;\n}\n\n/** Is a world-space delta inside a screen-space circle of radius `px`? */\nexport function withinPxRadius(dx: number, dy: number, px: number, scale: Scale2): boolean {\n const s = scaleDelta(dx, dy, scale);\n return s.x * s.x + s.y * s.y <= px * px;\n}\n","import type { SnapStrategy } from '../../types';\nimport type { Guide } from 'features/guides/types';\nimport type { View } from 'core/viewport/view';\nimport { pxExtent } from 'core/viewport/pxExtent';\nimport type { OriginProjection } from './grid';\nimport { RECT_ORIGIN_PROJECTION } from './grid';\n\n/** Default snap tolerance (screen pixels). */\nexport const DEFAULT_GUIDE_TOLERANCE_PX = 6;\n\n/** Options for `guideSnapStrategy`. */\nexport interface GuideSnapOptions<TPose> {\n /**\n * Tolerance, in screen pixels (CSS px) when `getView` is provided, or in\n * world units otherwise. Defaults to `DEFAULT_GUIDE_TOLERANCE_PX`.\n */\n tolerance?: number;\n /**\n * Read the active view transform. When supplied, `tolerance` is interpreted\n * in screen pixels and divided by `view.scale` so the trigger zone stays\n * the same on screen as the user zooms in/out. Without it, `tolerance`\n * is treated as world units.\n */\n getView?: () => View;\n /**\n * Projection used when `TPose` doesn't expose `{x, y}` directly (Path,\n * polygon, etc.) — same contract as `gridSnapStrategy`. Defaults to the\n * rect-pose identity projection.\n */\n origin?: OriginProjection<TPose>;\n}\n\n/**\n * Snap-strategy that snaps the pose's origin to the nearest guide line on\n * each axis when within tolerance. Each axis is considered independently:\n * a vertical guide (`axis: 'x'`) constrains X, a horizontal guide\n * (`axis: 'y'`) constrains Y. When multiple guides are within range on the\n * same axis, the closest wins.\n *\n * Pair with `useGuides` for storage and `createGuidesLayer` for rendering.\n *\n * **Composition:** combining with `gridSnapStrategy` is left to the\n * consumer in v1 — typically by picking one based on a modifier key, or\n * by stacking two move/resize/insert behaviors in priority order.\n */\nexport function guideSnapStrategy<TPose extends { x: number; y: number }>(\n getGuides: () => readonly Guide[],\n options?: Omit<GuideSnapOptions<TPose>, 'origin'>,\n): SnapStrategy<TPose>;\n/** As above, for a `TPose` that is not a rect: `origin` tells the strategy how\n * to read and write the pose's origin. */\nexport function guideSnapStrategy<TPose>(\n getGuides: () => readonly Guide[],\n options: GuideSnapOptions<TPose> & { origin: OriginProjection<TPose> },\n): SnapStrategy<TPose>;\n/** Snap a pose's origin to the nearest guide line within tolerance, per axis. */\nexport function guideSnapStrategy<TPose>(\n getGuides: () => readonly Guide[],\n options: GuideSnapOptions<TPose> = {},\n): SnapStrategy<TPose> {\n const tolerance = options.tolerance ?? DEFAULT_GUIDE_TOLERANCE_PX;\n const getView = options.getView;\n const proj: OriginProjection<TPose> =\n options.origin ?? (RECT_ORIGIN_PROJECTION as unknown as OriginProjection<TPose>);\n\n return {\n snap(pose) {\n const guides = getGuides();\n if (guides.length === 0) return null;\n\n // Convert tolerance to world units, per axis: a guide on the x axis is\n // matched by a horizontal distance, so it answers to `scale.x` alone.\n // With no view, treat tolerance as already-world.\n const tol = getView ? pxExtent(tolerance, getView().scale) : { x: tolerance, y: tolerance };\n\n const o = proj.getOrigin(pose);\n\n let bestDx = 0;\n let bestAbsDx = Infinity;\n let bestDy = 0;\n let bestAbsDy = Infinity;\n\n for (const g of guides) {\n if (g.axis === 'x') {\n const d = g.offset - o.x;\n const ad = Math.abs(d);\n if (ad <= tol.x && ad < bestAbsDx) {\n bestAbsDx = ad;\n bestDx = d;\n }\n } else {\n const d = g.offset - o.y;\n const ad = Math.abs(d);\n if (ad <= tol.y && ad < bestAbsDy) {\n bestAbsDy = ad;\n bestDy = d;\n }\n }\n }\n\n if (bestAbsDx === Infinity && bestAbsDy === Infinity) return null;\n const dx = bestAbsDx === Infinity ? 0 : bestDx;\n const dy = bestAbsDy === Infinity ? 0 : bestDy;\n if (dx === 0 && dy === 0) return null;\n return proj.translate(pose, dx, dy);\n },\n };\n}\n"]}
|
|
@@ -408,16 +408,6 @@ function translatePolygonCopy(path, dx, dy) {
|
|
|
408
408
|
});
|
|
409
409
|
return { kind: "polygon", commands: path.commands, coords: next, fillRule: path.fillRule };
|
|
410
410
|
}
|
|
411
|
-
function translatePolygonInPlace(path, dx, dy) {
|
|
412
|
-
const { commands, coords } = path;
|
|
413
|
-
forEachSegment(commands, coords, (cmd, ci) => {
|
|
414
|
-
for (let k = 0, len = pathCommandCoordCount(cmd); k < len; k += 2) {
|
|
415
|
-
coords[ci + k] += dx;
|
|
416
|
-
coords[ci + k + 1] += dy;
|
|
417
|
-
}
|
|
418
|
-
});
|
|
419
|
-
return path;
|
|
420
|
-
}
|
|
421
411
|
function scalePathToBounds(path, target) {
|
|
422
412
|
if (path.kind === "rect") {
|
|
423
413
|
return { kind: "rect", x: target.x, y: target.y, width: target.width, height: target.height };
|
|
@@ -531,6 +521,11 @@ var RECT_POSE_DESCRIPTOR = {
|
|
|
531
521
|
width: a.width + (b.width - a.width) * t,
|
|
532
522
|
height: a.height + (b.height - a.height) * t
|
|
533
523
|
}),
|
|
524
|
+
// `Bounds` carries an optional `rotation`, and `withRotation` writes into
|
|
525
|
+
// it — so reading it back has to be the same channel, or a pose reports
|
|
526
|
+
// itself unrotated to `useResize` and to port placement while painting
|
|
527
|
+
// rotated.
|
|
528
|
+
getRotation: (p) => p.rotation ?? 0,
|
|
534
529
|
withRotation: (p, rotation) => ({ ...p, rotation })
|
|
535
530
|
};
|
|
536
531
|
var ROTATED_POSE_DESCRIPTOR = {
|
|
@@ -648,6 +643,6 @@ var AUTO_POSE_DESCRIPTOR = {
|
|
|
648
643
|
withRotation: (p, rotation) => isPathLike(p) ? p : { ...p, rotation }
|
|
649
644
|
};
|
|
650
645
|
|
|
651
|
-
export { AUTO_POSE_DESCRIPTOR, PathBuilder, RECT_POSE_DESCRIPTOR, ROTATED_POSE_DESCRIPTOR, aabbIntersectsRect, axisAlignedBounds, boundsOfPath, ellipsePath, isPathLike, isRectPose, linePath, pathPoseDescriptor, pointInPath, polygonFromPoints, polylineFromPoints, poseDescriptorForNode, rectPath, regularPolygonPath, remapRotatedLeaf, scalePathToBounds, starPath, strokeHitTest, transformPath, translatePath,
|
|
652
|
-
//# sourceMappingURL=chunk-
|
|
653
|
-
//# sourceMappingURL=chunk-
|
|
646
|
+
export { AUTO_POSE_DESCRIPTOR, PathBuilder, RECT_POSE_DESCRIPTOR, ROTATED_POSE_DESCRIPTOR, aabbIntersectsRect, axisAlignedBounds, boundsOfPath, ellipsePath, isPathLike, isRectPose, linePath, pathPoseDescriptor, pointInPath, polygonFromPoints, polylineFromPoints, poseDescriptorForNode, rectPath, regularPolygonPath, remapRotatedLeaf, scalePathToBounds, starPath, strokeHitTest, transformPath, translatePath, translatePoseViaDescriptor, unionAABB, unionBounds, visualBoundsViaDescriptor };
|
|
647
|
+
//# sourceMappingURL=chunk-L5YNZYEG.js.map
|
|
648
|
+
//# sourceMappingURL=chunk-L5YNZYEG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/features/paths/bounds.ts","../src/features/paths/hitTest.ts","../src/features/paths/builder.ts","../src/features/paths/transformPath.ts","../src/features/paths/transform.ts","../src/core/geometry/unionBounds.ts","../src/core/geometry/poseDescriptor.ts","../src/features/paths/poseDescriptor.ts","../src/interactions/actions/resize/autoPoseDescriptor.ts"],"names":["forEachSegment","pathCommandCoordCount","boxToBox"],"mappings":";;;;AAmCO,SAAS,aAAa,IAAA,EAAsB;AACjD,EAAA,IAAI,IAAA,CAAK,IAAA,KAAS,MAAA,EAAQ,OAAO,IAAA;AAEjC,EAAA,MAAM,EAAE,QAAA,EAAU,MAAA,EAAO,GAAI,IAAA;AAC7B,EAAA,IAAI,QAAA,CAAS,WAAW,CAAA,EAAG;AACzB,IAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,CAAA,EAAG,CAAA,EAAG,GAAG,CAAA,EAAG,KAAA,EAAO,CAAA,EAAG,MAAA,EAAQ,CAAA,EAAE;AAAA,EACzD;AAEA,EAAA,IAAI,OAAO,QAAA,EAAU,IAAA,GAAO,QAAA,EAAU,IAAA,GAAO,WAAW,IAAA,GAAO,CAAA,QAAA;AAC/D,EAAA,IAAI,IAAA,GAAO,KAAA;AAEX,EAAA,MAAM,OAAA,GAAU,CAAC,CAAA,EAAW,CAAA,KAAc;AACxC,IAAA,IAAI,CAAA,GAAI,MAAM,IAAA,GAAO,CAAA;AACrB,IAAA,IAAI,CAAA,GAAI,MAAM,IAAA,GAAO,CAAA;AACrB,IAAA,IAAI,CAAA,GAAI,MAAM,IAAA,GAAO,CAAA;AACrB,IAAA,IAAI,CAAA,GAAI,MAAM,IAAA,GAAO,CAAA;AACrB,IAAA,IAAA,GAAO,IAAA;AAAA,EACT,CAAA;AAEA,EAAA,cAAA,CAAe,UAAU,MAAA,EAAQ,CAAC,GAAA,EAAK,EAAA,EAAI,IAAI,EAAA,KAAO;AACpD,IAAA,QAAQ,GAAA;AAAK,MACX,KAAK,MAAA;AAAA,MACL,KAAK,MAAA,EAAQ;AACX,QAAA,OAAA,CAAQ,OAAO,EAAE,CAAA,EAAG,MAAA,CAAO,EAAA,GAAK,CAAC,CAAC,CAAA;AAClC,QAAA;AAAA,MACF;AAAA,MACA,KAAK,MAAA,EAAQ;AACX,QAAA,MAAM,CAAC,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,KAAK,CAAA,GAAI,WAAA;AAAA,UACnC,EAAA;AAAA,UAAI,EAAA;AAAA,UACJ,OAAO,EAAE,CAAA;AAAA,UAAG,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,UACzB,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,UAAG,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,UAC7B,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,UAAG,MAAA,CAAO,KAAK,CAAC;AAAA,SAC/B;AACA,QAAA,OAAA,CAAQ,OAAO,KAAK,CAAA;AACpB,QAAA,OAAA,CAAQ,OAAO,KAAK,CAAA;AACpB,QAAA;AAAA,MACF;AAAA,MACA,KAAK,MAAA,EAAQ;AACX,QAAA,MAAM,GAAA,GAAM,OAAO,EAAA,GAAK,CAAC,GAAG,GAAA,GAAM,MAAA,CAAO,KAAK,CAAC,CAAA;AAC/C,QAAA,MAAM,CAAC,GAAA,EAAK,GAAA,EAAK,GAAA,EAAK,GAAG,IAAI,uBAAA,CAAwB,EAAA,EAAI,EAAA,EAAI,MAAA,CAAO,EAAE,CAAA,EAAG,MAAA,CAAO,KAAK,CAAC,CAAA,EAAG,KAAK,GAAG,CAAA;AACjG,QAAA,MAAM,CAAC,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,KAAK,CAAA,GAAI,WAAA,CAAY,EAAA,EAAI,EAAA,EAAI,GAAA,EAAK,GAAA,EAAK,GAAA,EAAK,GAAA,EAAK,KAAK,GAAG,CAAA;AACrF,QAAA,OAAA,CAAQ,OAAO,KAAK,CAAA;AACpB,QAAA,OAAA,CAAQ,OAAO,KAAK,CAAA;AACpB,QAAA;AAAA,MACF;AAAA,MACA,KAAK,MAAA;AACH,QAAA;AAAA,MACF;AACE,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,8BAAA,EAAiC,GAAG,CAAA,CAAE,CAAA;AAAA;AAC1D,EACF,CAAC,CAAA;AAED,EAAA,IAAI,CAAC,IAAA,EAAM,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,KAAA,EAAO,CAAA,EAAG,QAAQ,CAAA,EAAE;AAClE,EAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,CAAA,EAAG,IAAA,EAAM,CAAA,EAAG,IAAA,EAAM,KAAA,EAAO,IAAA,GAAO,IAAA,EAAM,MAAA,EAAQ,IAAA,GAAO,IAAA,EAAK;AACnF;AC1DO,SAAS,YACd,IAAA,EACA,CAAA,EACA,CAAA,EACA,IAAA,GAA2B,EAAC,EACnB;AACT,EAAA,IAAI,IAAA,CAAK,SAAS,MAAA,EAAQ;AACxB,IAAA,OAAO,CAAA,IAAK,IAAA,CAAK,CAAA,IAAK,CAAA,IAAK,KAAK,CAAA,GAAI,IAAA,CAAK,KAAA,IAAS,CAAA,IAAK,IAAA,CAAK,CAAA,IAAK,CAAA,IAAK,IAAA,CAAK,IAAI,IAAA,CAAK,MAAA;AAAA,EACtF;AACA,EAAA,OAAO,mBAAmB,IAAA,EAAM,CAAA,EAAG,CAAA,EAAG,IAAA,CAAK,aAAa,yBAAyB,CAAA;AACnF;AAEA,SAAS,kBAAA,CAAmB,IAAA,EAAmB,CAAA,EAAW,CAAA,EAAW,SAAA,EAA4B;AAC/F,EAAA,MAAM,EAAE,QAAA,EAAU,MAAA,EAAQ,QAAA,EAAS,GAAI,IAAA;AACvC,EAAA,IAAI,QAAA,CAAS,MAAA,KAAW,CAAA,EAAG,OAAO,KAAA;AAIlC,EAAA,IAAI,SAAA,GAAY,CAAA;AAChB,EAAA,IAAI,OAAA,GAAU,CAAA;AAEd,EAAA,IAAI,SAAA,GAAY,GAAG,SAAA,GAAY,CAAA;AAC/B,EAAA,IAAI,WAAqB,EAAC;AAC1B,EAAA,IAAI,OAAA,GAAU,KAAA;AAEd,EAAA,MAAM,YAAA,GAAe,CAAC,MAAA,KAAoB;AACxC,IAAA,IAAI,MAAA,IAAU,QAAA,CAAS,MAAA,IAAU,CAAA,EAAG;AAElC,MAAA,QAAA,CAAS,IAAA,CAAK,WAAW,SAAS,CAAA;AAElC,MAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,SAAS,MAAA,GAAS,CAAA,EAAG,KAAK,CAAA,EAAG;AAC/C,QAAA,MAAM,KAAK,QAAA,CAAS,CAAC,GAAO,EAAA,GAAK,QAAA,CAAS,IAAI,CAAC,CAAA;AAC/C,QAAA,MAAM,EAAA,GAAK,SAAS,CAAA,GAAI,CAAC,GAAG,EAAA,GAAK,QAAA,CAAS,IAAI,CAAC,CAAA;AAC/C,QAAA,IAAI,uBAAuB,CAAA,EAAG,CAAA,EAAG,IAAI,EAAA,EAAI,EAAA,EAAI,EAAE,CAAA,EAAG;AAChD,UAAA,SAAA,EAAA;AACA,UAAA,IAAI,EAAA,IAAM,CAAA,IAAK,EAAA,GAAK,CAAA,EAAG,OAAA,EAAA;AAAA,eAAA,IACd,EAAA,IAAM,CAAA,IAAK,EAAA,GAAK,CAAA,EAAG,OAAA,EAAA;AAAA,QAC9B;AAAA,MACF;AAAA,IACF;AACA,IAAA,QAAA,GAAW,EAAC;AACZ,IAAA,OAAA,GAAU,KAAA;AAAA,EACZ,CAAA;AAEA,EAAAA,eAAe,QAAA,EAAU,MAAA,EAAQ,CAAC,GAAA,EAAK,EAAA,EAAI,MAAM,IAAA,KAAS;AACxD,IAAA,QAAQ,GAAA;AAAK,MACX,KAAK,MAAA,EAAQ;AACX,QAAA,IAAI,OAAA,eAAsB,KAAK,CAAA;AAC/B,QAAA,SAAA,GAAY,OAAO,EAAE,CAAA;AAAG,QAAA,SAAA,GAAY,MAAA,CAAO,KAAK,CAAC,CAAA;AACjD,QAAA,QAAA,CAAS,IAAA,CAAK,WAAW,SAAS,CAAA;AAClC,QAAA,OAAA,GAAU,IAAA;AACV,QAAA;AAAA,MACF;AAAA,MACA,KAAK,MAAA;AACH,QAAA,QAAA,CAAS,KAAK,MAAA,CAAO,EAAE,GAAG,MAAA,CAAO,EAAA,GAAK,CAAC,CAAC,CAAA;AACxC,QAAA;AAAA,MACF,KAAK,MAAA;AACH,QAAA,YAAA;AAAA,UACE,IAAA;AAAA,UAAM,IAAA;AAAA,UACN,OAAO,EAAE,CAAA;AAAA,UAAG,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,UACzB,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,UAAG,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,UAC7B,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,UAAG,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,UAC7B,SAAA;AAAA,UAAW;AAAA,SACb;AACA,QAAA;AAAA,MACF,KAAK,MAAA;AACH,QAAA,gBAAA;AAAA,UACE,IAAA;AAAA,UAAM,IAAA;AAAA,UACN,OAAO,EAAE,CAAA;AAAA,UAAG,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,UACzB,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,UAAG,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,UAC7B,SAAA;AAAA,UAAW;AAAA,SACb;AACA,QAAA;AAAA,MACF,KAAK,MAAA;AACH,QAAA,YAAA,CAAa,IAAI,CAAA;AACjB,QAAA;AAAA,MACF;AACE,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,6BAAA,EAAgC,GAAG,CAAA,CAAE,CAAA;AAAA;AACzD,EACF,CAAC,CAAA;AACD,EAAA,IAAI,OAAA,eAAsB,KAAK,CAAA;AAE/B,EAAA,OAAO,QAAA,KAAa,SAAA,GAAA,CAAa,SAAA,GAAY,CAAA,MAAO,IAAI,OAAA,KAAY,CAAA;AACtE;AAOA,SAAS,uBACP,CAAA,EAAW,CAAA,EACX,EAAA,EAAY,EAAA,EACZ,IAAY,EAAA,EACH;AACT,EAAA,IAAK,EAAA,GAAK,CAAA,KAAQ,EAAA,GAAK,CAAA,EAAI,OAAO,KAAA;AAClC,EAAA,MAAM,SAAS,EAAA,GAAA,CAAO,CAAA,GAAI,EAAA,KAAO,EAAA,GAAK,OAAQ,EAAA,GAAK,EAAA,CAAA;AACnD,EAAA,OAAO,CAAA,GAAI,MAAA;AACb;AAyBO,SAAS,cACd,IAAA,EACA,CAAA,EACA,GACA,SAAA,EACA,IAAA,GAA6B,EAAC,EACrB;AACT,EAAA,MAAM,KAAK,SAAA,GAAY,SAAA;AACvB,EAAA,IAAI,IAAA,CAAK,SAAS,MAAA,EAAQ;AACxB,IAAA,MAAM,EAAE,GAAG,EAAA,EAAI,CAAA,EAAG,IAAI,KAAA,EAAO,CAAA,EAAG,MAAA,EAAQ,CAAA,EAAE,GAAI,IAAA;AAC9C,IAAA,OACE,kBAAkB,CAAA,EAAG,CAAA,EAAG,IAAI,EAAA,EAAI,EAAA,GAAK,GAAG,EAAE,CAAA,IAAK,MAC5C,iBAAA,CAAkB,CAAA,EAAG,GAAG,EAAA,GAAK,CAAA,EAAG,IAAI,EAAA,GAAK,CAAA,EAAG,KAAK,CAAC,CAAA,IAAK,EAAA,IACvD,iBAAA,CAAkB,GAAG,CAAA,EAAG,EAAA,GAAK,GAAG,EAAA,GAAK,CAAA,EAAG,IAAI,EAAA,GAAK,CAAC,KAAK,EAAA,IACvD,iBAAA,CAAkB,GAAG,CAAA,EAAG,EAAA,EAAI,KAAK,CAAA,EAAG,EAAA,EAAI,EAAE,CAAA,IAAK,EAAA;AAAA,EAEtD;AACA,EAAA,OAAO,wBAAwB,IAAA,EAAM,CAAA,EAAG,GAAG,EAAA,EAAI,IAAA,CAAK,aAAa,yBAAyB,CAAA;AAC5F;AAEA,SAAS,uBAAA,CACP,IAAA,EACA,EAAA,EAAY,EAAA,EACZ,IACA,SAAA,EACS;AACT,EAAA,MAAM,EAAE,QAAA,EAAU,MAAA,EAAO,GAAI,IAAA;AAC7B,EAAA,IAAI,QAAA,CAAS,MAAA,KAAW,CAAA,EAAG,OAAO,KAAA;AAIlC,EAAA,IAAI,SAAA,GAAY,GAAG,SAAA,GAAY,CAAA;AAC/B,EAAA,IAAI,WAAqB,EAAC;AAC1B,EAAA,IAAI,OAAA,GAAU,KAAA;AAEd,EAAA,MAAM,aAAA,GAAgB,CAAC,MAAA,KAA6B;AAClD,IAAA,IAAI,UAAU,QAAA,CAAS,MAAA,IAAU,GAAG,QAAA,CAAS,IAAA,CAAK,WAAW,SAAS,CAAA;AACtE,IAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,SAAS,MAAA,GAAS,CAAA,EAAG,KAAK,CAAA,EAAG;AAC/C,MAAA,IAAI,kBAAkB,EAAA,EAAI,EAAA,EAAI,SAAS,CAAC,CAAA,EAAG,SAAS,CAAA,GAAI,CAAC,GAAG,QAAA,CAAS,CAAA,GAAI,CAAC,CAAA,EAAG,QAAA,CAAS,IAAI,CAAC,CAAC,KAAK,EAAA,EAAI;AACnG,QAAA,OAAO,IAAA;AAAA,MACT;AAAA,IACF;AACA,IAAA,OAAO,KAAA;AAAA,EACT,CAAA;AAEA,EAAA,IAAI,GAAA,GAAM,KAAA;AACV,EAAAA,eAAe,QAAA,EAAU,MAAA,EAAQ,CAAC,GAAA,EAAK,EAAA,EAAI,MAAM,IAAA,KAAS;AACxD,IAAA,QAAQ,GAAA;AAAK,MACX,KAAK,MAAA,EAAQ;AACX,QAAA,IAAI,OAAA,EAAS;AACX,UAAA,IAAI,aAAA,CAAc,KAAK,CAAA,EAAG;AAAE,YAAA,GAAA,GAAM,IAAA;AAAM,YAAA,OAAO,KAAA;AAAA,UAAO;AACtD,UAAA,QAAA,GAAW,EAAC;AAAA,QACd;AACA,QAAA,SAAA,GAAY,OAAO,EAAE,CAAA;AAAG,QAAA,SAAA,GAAY,MAAA,CAAO,KAAK,CAAC,CAAA;AACjD,QAAA,QAAA,CAAS,IAAA,CAAK,WAAW,SAAS,CAAA;AAClC,QAAA,OAAA,GAAU,IAAA;AACV,QAAA;AAAA,MACF;AAAA,MACA,KAAK,MAAA;AACH,QAAA,QAAA,CAAS,KAAK,MAAA,CAAO,EAAE,GAAG,MAAA,CAAO,EAAA,GAAK,CAAC,CAAC,CAAA;AACxC,QAAA;AAAA,MACF,KAAK,MAAA;AACH,QAAA,YAAA;AAAA,UACE,IAAA;AAAA,UAAM,IAAA;AAAA,UACN,OAAO,EAAE,CAAA;AAAA,UAAG,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,UACzB,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,UAAG,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,UAC7B,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,UAAG,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,UAC7B,SAAA;AAAA,UAAW;AAAA,SACb;AACA,QAAA;AAAA,MACF,KAAK,MAAA;AACH,QAAA,gBAAA;AAAA,UACE,IAAA;AAAA,UAAM,IAAA;AAAA,UACN,OAAO,EAAE,CAAA;AAAA,UAAG,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,UACzB,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,UAAG,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,UAC7B,SAAA;AAAA,UAAW;AAAA,SACb;AACA,QAAA;AAAA,MACF,KAAK,MAAA;AACH,QAAA,IAAI,aAAA,CAAc,IAAI,CAAA,EAAG;AAAE,UAAA,GAAA,GAAM,IAAA;AAAM,UAAA,OAAO,KAAA;AAAA,QAAO;AACrD,QAAA,QAAA,GAAW,EAAC;AACZ,QAAA,OAAA,GAAU,KAAA;AACV,QAAA;AAAA,MACF;AACE,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,+BAAA,EAAkC,GAAG,CAAA,CAAE,CAAA;AAAA;AAE3D,IAAA,OAAO,IAAA;AAAA,EACT,CAAC,CAAA;AACD,EAAA,IAAI,KAAK,OAAO,IAAA;AAChB,EAAA,IAAI,OAAA,IAAW,aAAA,CAAc,KAAK,CAAA,EAAG,OAAO,IAAA;AAC5C,EAAA,OAAO,KAAA;AACT;;;AC7NO,IAAM,WAAA,GAAN,MAAM,YAAA,CAAY;AAAA,EACf,OAAiB,EAAC;AAAA,EAClB,KAAe,EAAC;AAAA,EAChB,QAAA,GAAyB,SAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWjC,OAAO,SAAS,IAAA,EAAgC;AAC9C,IAAA,MAAM,CAAA,GAAI,IAAI,YAAA,EAAY;AAC1B,IAAA,CAAA,CAAE,IAAA,GAAO,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,QAAQ,CAAA;AACjC,IAAA,CAAA,CAAE,EAAA,GAAK,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,MAAM,CAAA;AAC7B,IAAA,CAAA,CAAE,WAAW,IAAA,CAAK,QAAA;AAClB,IAAA,OAAO,CAAA;AAAA,EACT;AAAA,EAEA,YAAY,IAAA,EAA0B;AACpC,IAAA,IAAA,CAAK,QAAA,GAAW,IAAA;AAChB,IAAA,OAAO,IAAA;AAAA,EACT;AAAA,EAEA,MAAA,CAAO,GAAW,CAAA,EAAiB;AACjC,IAAA,IAAA,CAAK,IAAA,CAAK,KAAK,MAAM,CAAA;AACrB,IAAA,IAAA,CAAK,EAAA,CAAG,IAAA,CAAK,CAAA,EAAG,CAAC,CAAA;AACjB,IAAA,OAAO,IAAA;AAAA,EACT;AAAA,EAEA,MAAA,CAAO,GAAW,CAAA,EAAiB;AACjC,IAAA,IAAA,CAAK,IAAA,CAAK,KAAK,MAAM,CAAA;AACrB,IAAA,IAAA,CAAK,EAAA,CAAG,IAAA,CAAK,CAAA,EAAG,CAAC,CAAA;AACjB,IAAA,OAAO,IAAA;AAAA,EACT;AAAA;AAAA,EAGA,QAAQ,EAAA,EAAY,EAAA,EAAY,EAAA,EAAY,EAAA,EAAY,GAAW,CAAA,EAAiB;AAClF,IAAA,IAAA,CAAK,IAAA,CAAK,KAAK,MAAM,CAAA;AACrB,IAAA,IAAA,CAAK,GAAG,IAAA,CAAK,EAAA,EAAI,IAAI,EAAA,EAAI,EAAA,EAAI,GAAG,CAAC,CAAA;AACjC,IAAA,OAAO,IAAA;AAAA,EACT;AAAA;AAAA,EAGA,MAAA,CAAO,EAAA,EAAY,EAAA,EAAY,CAAA,EAAW,CAAA,EAAiB;AACzD,IAAA,IAAA,CAAK,IAAA,CAAK,KAAK,MAAM,CAAA;AACrB,IAAA,IAAA,CAAK,EAAA,CAAG,IAAA,CAAK,EAAA,EAAI,EAAA,EAAI,GAAG,CAAC,CAAA;AACzB,IAAA,OAAO,IAAA;AAAA,EACT;AAAA,EAEA,KAAA,GAAc;AACZ,IAAA,IAAA,CAAK,IAAA,CAAK,KAAK,MAAM,CAAA;AACrB,IAAA,OAAO,IAAA;AAAA,EACT;AAAA,EAEA,KAAA,GAAqB;AACnB,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,SAAA;AAAA,MACN,QAAA,EAAU,IAAI,UAAA,CAAW,IAAA,CAAK,IAAI,CAAA;AAAA,MAClC,MAAA,EAAQ,IAAI,YAAA,CAAa,IAAA,CAAK,EAAE,CAAA;AAAA,MAChC,UAAU,IAAA,CAAK;AAAA,KACjB;AAAA,EACF;AACF;AAGO,SAAS,QAAA,CAAS,CAAA,EAAW,CAAA,EAAW,KAAA,EAAe,MAAA,EAA0B;AACtF,EAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,CAAA,EAAG,CAAA,EAAG,OAAO,MAAA,EAAO;AAC7C;AAKO,SAAS,mBACd,MAAA,EACwB;AACxB,EAAA,MAAM,CAAA,GAAI,IAAI,WAAA,EAAY;AAC1B,EAAA,MAAM,KAAA,GAAQ,OAAO,CAAC,CAAA;AACtB,EAAA,IAAI,CAAC,KAAA,EAAO,OAAO,SAAS,CAAA,EAAG,CAAA,EAAG,GAAG,CAAC,CAAA;AACtC,EAAA,CAAA,CAAE,MAAA,CAAO,KAAA,CAAM,CAAA,EAAG,KAAA,CAAM,CAAC,CAAA;AACzB,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,CAAO,QAAQ,CAAA,EAAA,EAAK;AACtC,IAAA,MAAM,CAAA,GAAI,OAAO,CAAC,CAAA;AAClB,IAAA,IAAI,GAAG,CAAA,CAAE,MAAA,CAAO,CAAA,CAAE,CAAA,EAAG,EAAE,CAAC,CAAA;AAAA,EAC1B;AACA,EAAA,OAAO,EAAE,KAAA,EAAM;AACjB;AAGO,SAAS,iBAAA,CACd,MAAA,EACA,IAAA,GAAoC,EAAC,EACxB;AACb,EAAA,IAAI,MAAA,CAAO,WAAW,CAAA,EAAG;AACvB,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,SAAA;AAAA,MACN,QAAA,EAAU,IAAI,UAAA,EAAW;AAAA,MACzB,MAAA,EAAQ,IAAI,YAAA,EAAa;AAAA,MACzB,QAAA,EAAU,KAAK,QAAA,IAAY;AAAA,KAC7B;AAAA,EACF;AACA,EAAA,MAAM,CAAA,GAAI,IAAI,WAAA,EAAY;AAC1B,EAAA,IAAI,IAAA,CAAK,QAAA,EAAU,CAAA,CAAE,WAAA,CAAY,KAAK,QAAQ,CAAA;AAC9C,EAAA,CAAA,CAAE,MAAA,CAAO,OAAO,CAAC,CAAA,CAAE,GAAG,MAAA,CAAO,CAAC,EAAE,CAAC,CAAA;AACjC,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,CAAO,QAAQ,CAAA,EAAA,EAAK,CAAA,CAAE,MAAA,CAAO,MAAA,CAAO,CAAC,CAAA,CAAE,CAAA,EAAG,MAAA,CAAO,CAAC,EAAE,CAAC,CAAA;AACzE,EAAA,CAAA,CAAE,KAAA,EAAM;AACR,EAAA,OAAO,EAAE,KAAA,EAAM;AACjB;AAGA,IAAM,aAAA,GAAgB,kBAAA;AAIf,SAAS,YACd,MAAA,EACa;AACb,EAAA,MAAM,EAAA,GAAK,MAAA,CAAO,CAAA,GAAI,MAAA,CAAO,KAAA,GAAQ,CAAA;AACrC,EAAA,MAAM,EAAA,GAAK,MAAA,CAAO,CAAA,GAAI,MAAA,CAAO,MAAA,GAAS,CAAA;AACtC,EAAA,MAAM,EAAA,GAAK,OAAO,KAAA,GAAQ,CAAA;AAC1B,EAAA,MAAM,EAAA,GAAK,OAAO,MAAA,GAAS,CAAA;AAC3B,EAAA,MAAM,KAAK,EAAA,GAAK,aAAA;AAChB,EAAA,MAAM,KAAK,EAAA,GAAK,aAAA;AAChB,EAAA,MAAM,CAAA,GAAI,IAAI,WAAA,EAAY;AAC1B,EAAA,CAAA,CAAE,MAAA,CAAO,EAAA,GAAK,EAAA,EAAI,EAAE,CAAA;AACpB,EAAA,CAAA,CAAE,OAAA,CAAQ,EAAA,GAAK,EAAA,EAAI,EAAA,GAAK,EAAA,EAAI,EAAA,GAAK,EAAA,EAAI,EAAA,GAAK,EAAA,EAAI,EAAA,EAAI,EAAA,GAAK,EAAE,CAAA;AACzD,EAAA,CAAA,CAAE,OAAA,CAAQ,EAAA,GAAK,EAAA,EAAI,EAAA,GAAK,EAAA,EAAI,EAAA,GAAK,EAAA,EAAI,EAAA,GAAK,EAAA,EAAI,EAAA,GAAK,EAAA,EAAI,EAAE,CAAA;AACzD,EAAA,CAAA,CAAE,OAAA,CAAQ,EAAA,GAAK,EAAA,EAAI,EAAA,GAAK,EAAA,EAAI,EAAA,GAAK,EAAA,EAAI,EAAA,GAAK,EAAA,EAAI,EAAA,EAAI,EAAA,GAAK,EAAE,CAAA;AACzD,EAAA,CAAA,CAAE,OAAA,CAAQ,EAAA,GAAK,EAAA,EAAI,EAAA,GAAK,EAAA,EAAI,EAAA,GAAK,EAAA,EAAI,EAAA,GAAK,EAAA,EAAI,EAAA,GAAK,EAAA,EAAI,EAAE,CAAA;AACzD,EAAA,CAAA,CAAE,KAAA,EAAM;AACR,EAAA,OAAO,EAAE,KAAA,EAAM;AACjB;AAIO,SAAS,kBAAA,CACd,MAAA,EACA,MAAA,EACA,KAAA,EACA,WAAW,CAAA,EACE;AACb,EAAA,MAAM,CAAA,GAAI,IAAI,WAAA,EAAY;AAC1B,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,EAAO,CAAA,EAAA,EAAK;AAC9B,IAAA,MAAM,CAAA,GAAI,QAAA,GAAY,CAAA,GAAI,KAAA,GAAS,KAAK,EAAA,GAAK,CAAA;AAC7C,IAAA,MAAM,IAAI,MAAA,CAAO,CAAA,GAAI,MAAA,GAAS,IAAA,CAAK,IAAI,CAAC,CAAA;AACxC,IAAA,MAAM,IAAI,MAAA,CAAO,CAAA,GAAI,MAAA,GAAS,IAAA,CAAK,IAAI,CAAC,CAAA;AACxC,IAAA,IAAI,CAAA,KAAM,CAAA,EAAG,CAAA,CAAE,MAAA,CAAO,GAAG,CAAC,CAAA;AAAA,SAAQ,CAAA,CAAE,MAAA,CAAO,CAAA,EAAG,CAAC,CAAA;AAAA,EACjD;AACA,EAAA,CAAA,CAAE,KAAA,EAAM;AACR,EAAA,OAAO,EAAE,KAAA,EAAM;AACjB;AAIO,SAAS,QAAA,CACd,QACA,WAAA,EACA,MAAA,GAAS,GACT,WAAA,GAAsB,WAAA,GAAc,CAAA,EACpC,QAAA,GAAW,CAAA,EACE;AACb,EAAA,MAAM,CAAA,GAAI,IAAI,WAAA,EAAY;AAC1B,EAAA,MAAM,IAAI,MAAA,GAAS,CAAA;AACnB,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,EAAG,CAAA,EAAA,EAAK;AAC1B,IAAA,MAAM,CAAA,GAAI,QAAA,GAAY,CAAA,GAAI,CAAA,GAAK,KAAK,EAAA,GAAK,CAAA;AACzC,IAAA,MAAM,CAAA,GAAI,CAAA,GAAI,CAAA,KAAM,CAAA,GAAI,WAAA,GAAc,WAAA;AACtC,IAAA,MAAM,IAAI,MAAA,CAAO,CAAA,GAAI,CAAA,GAAI,IAAA,CAAK,IAAI,CAAC,CAAA;AACnC,IAAA,MAAM,IAAI,MAAA,CAAO,CAAA,GAAI,CAAA,GAAI,IAAA,CAAK,IAAI,CAAC,CAAA;AACnC,IAAA,IAAI,CAAA,KAAM,CAAA,EAAG,CAAA,CAAE,MAAA,CAAO,GAAG,CAAC,CAAA;AAAA,SAAQ,CAAA,CAAE,MAAA,CAAO,CAAA,EAAG,CAAC,CAAA;AAAA,EACjD;AACA,EAAA,CAAA,CAAE,KAAA,EAAM;AACR,EAAA,OAAO,EAAE,KAAA,EAAM;AACjB;AAGO,SAAS,QAAA,CACd,GACA,CAAA,EACa;AACb,EAAA,MAAM,EAAA,GAAK,IAAI,WAAA,EAAY;AAC3B,EAAA,EAAA,CAAG,MAAA,CAAO,CAAA,CAAE,CAAA,EAAG,CAAA,CAAE,CAAC,CAAA;AAClB,EAAA,EAAA,CAAG,MAAA,CAAO,CAAA,CAAE,CAAA,EAAG,CAAA,CAAE,CAAC,CAAA;AAClB,EAAA,OAAO,GAAG,KAAA,EAAM;AAClB;ACjMO,SAAS,aAAA,CAAc,MAAY,CAAA,EAAe;AACvD,EAAA,MAAM,CAAC,CAAA,EAAG,CAAA,EAAG,GAAG,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA,GAAI,CAAA;AAC3B,EAAA,IAAI,IAAA,CAAK,SAAS,MAAA,EAAQ;AACxB,IAAA,IAAI,CAAA,KAAM,CAAA,IAAK,CAAA,KAAM,CAAA,EAAG;AAEtB,MAAA,MAAM,EAAA,GAAK,CAAA,GAAI,IAAA,CAAK,CAAA,GAAI,CAAA;AACxB,MAAA,MAAM,EAAA,GAAK,CAAA,GAAI,IAAA,CAAK,CAAA,GAAI,CAAA;AACxB,MAAA,MAAM,EAAA,GAAK,CAAA,IAAK,IAAA,CAAK,CAAA,GAAI,KAAK,KAAA,CAAA,GAAS,CAAA;AACvC,MAAA,MAAM,EAAA,GAAK,CAAA,IAAK,IAAA,CAAK,CAAA,GAAI,KAAK,MAAA,CAAA,GAAU,CAAA;AACxC,MAAA,OAAO;AAAA,QACL,IAAA,EAAM,MAAA;AAAA,QACN,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,EAAA,EAAI,EAAE,CAAA;AAAA,QAClB,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,EAAA,EAAI,EAAE,CAAA;AAAA,QAClB,KAAA,EAAO,IAAA,CAAK,GAAA,CAAI,EAAA,GAAK,EAAE,CAAA;AAAA,QACvB,MAAA,EAAQ,IAAA,CAAK,GAAA,CAAI,EAAA,GAAK,EAAE;AAAA,OAC1B;AAAA,IACF;AAEA,IAAA,MAAM,OAAO,IAAI,WAAA,EAAY,CAC1B,MAAA,CAAO,KAAK,CAAA,EAAG,IAAA,CAAK,CAAC,CAAA,CACrB,OAAO,IAAA,CAAK,CAAA,GAAI,KAAK,KAAA,EAAO,IAAA,CAAK,CAAC,CAAA,CAClC,MAAA,CAAO,IAAA,CAAK,CAAA,GAAI,KAAK,KAAA,EAAO,IAAA,CAAK,CAAA,GAAI,IAAA,CAAK,MAAM,CAAA,CAChD,MAAA,CAAO,IAAA,CAAK,CAAA,EAAG,KAAK,CAAA,GAAI,IAAA,CAAK,MAAM,CAAA,CACnC,KAAA,GACA,KAAA,EAAM;AACT,IAAA,OAAO,gBAAA,CAAiB,MAAM,CAAC,CAAA;AAAA,EACjC;AACA,EAAA,OAAO,gBAAA,CAAiB,MAAM,CAAC,CAAA;AACjC;AAEA,SAAS,gBAAA,CAAiB,MAAmB,CAAA,EAAsB;AAEjE,EAAA,MAAM,MAAA,GAAS,eAAA,CAAgB,IAAA,CAAK,MAAA,EAAQ,CAAC,CAAA;AAC7C,EAAA,OAAO,EAAE,GAAG,IAAA,EAAM,QAAQ,YAAA,CAAa,IAAA,CAAK,MAAM,CAAA,EAAE;AACtD;AC9BO,SAAS,aAAA,CAAc,IAAA,EAAY,EAAA,EAAY,EAAA,EAAkB;AACtE,EAAA,IAAI,IAAA,CAAK,SAAS,MAAA,EAAQ;AACxB,IAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,CAAA,EAAG,IAAA,CAAK,IAAI,EAAA,EAAI,CAAA,EAAG,IAAA,CAAK,CAAA,GAAI,IAAI,KAAA,EAAO,IAAA,CAAK,KAAA,EAAO,MAAA,EAAQ,KAAK,MAAA,EAAO;AAAA,EAChG;AACA,EAAA,OAAO,oBAAA,CAAqB,IAAA,EAAM,EAAA,EAAI,EAAE,CAAA;AAC1C;AAEA,SAAS,oBAAA,CAAqB,IAAA,EAAmB,EAAA,EAAY,EAAA,EAAyB;AACpF,EAAA,MAAM,IAAA,GAAO,IAAI,YAAA,CAAa,IAAA,CAAK,OAAO,MAAM,CAAA;AAChD,EAAA,MAAM,EAAE,QAAA,EAAU,MAAA,EAAO,GAAI,IAAA;AAC7B,EAAAA,cAAAA,CAAe,QAAA,EAAU,MAAA,EAAQ,CAAC,KAAK,EAAA,KAAO;AAC5C,IAAA,KAAA,IAAS,CAAA,GAAI,GAAG,GAAA,GAAMC,qBAAAA,CAAsB,GAAG,CAAA,EAAG,CAAA,GAAI,GAAA,EAAK,CAAA,IAAK,CAAA,EAAG;AACjE,MAAA,IAAA,CAAK,KAAK,CAAC,CAAA,GAAI,MAAA,CAAO,EAAA,GAAK,CAAC,CAAA,GAAI,EAAA;AAChC,MAAA,IAAA,CAAK,EAAA,GAAK,IAAI,CAAC,CAAA,GAAI,OAAO,EAAA,GAAK,CAAA,GAAI,CAAC,CAAA,GAAI,EAAA;AAAA,IAC1C;AAAA,EACF,CAAC,CAAA;AACD,EAAA,OAAO,EAAE,IAAA,EAAM,SAAA,EAAW,QAAA,EAAU,IAAA,CAAK,UAAU,MAAA,EAAQ,IAAA,EAAM,QAAA,EAAU,IAAA,CAAK,QAAA,EAAS;AAC3F;AAUO,SAAS,iBAAA,CAAkB,MAAY,MAAA,EAAwB;AACpE,EAAA,IAAI,IAAA,CAAK,SAAS,MAAA,EAAQ;AACxB,IAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,CAAA,EAAG,OAAO,CAAA,EAAG,CAAA,EAAG,MAAA,CAAO,CAAA,EAAG,KAAA,EAAO,MAAA,CAAO,KAAA,EAAO,MAAA,EAAQ,OAAO,MAAA,EAAO;AAAA,EAC9F;AACA,EAAA,MAAM,GAAA,GAAM,aAAa,IAAI,CAAA;AAC7B,EAAA,OAAO,YAAA,CAAa,IAAA,EAAM,GAAA,EAAK,MAAM,CAAA;AACvC;AAEA,SAAS,YAAA,CAAa,IAAA,EAAmB,GAAA,EAAe,GAAA,EAA4B;AAClF,EAAA,MAAM,IAAI,QAAA,CAAS,GAAA,CAAI,CAAA,EAAG,GAAA,CAAI,GAAG,GAAA,CAAI,KAAA,EAAO,GAAA,CAAI,MAAA,EAAQ,IAAI,CAAA,EAAG,GAAA,CAAI,GAAG,GAAA,CAAI,KAAA,EAAO,IAAI,MAAM,CAAA;AAE3F,EAAA,OAAO,aAAA,CAAc,MAAM,CAAC,CAAA;AAC9B;;;ACzCO,SAAS,YAAoC,KAAA,EAAyC;AAC3F,EAAA,IAAI,IAAA,GAAO,QAAA;AACX,EAAA,IAAI,IAAA,GAAO,QAAA;AACX,EAAA,IAAI,IAAA,GAAO,CAAA,QAAA;AACX,EAAA,IAAI,IAAA,GAAO,CAAA,QAAA;AACX,EAAA,IAAI,GAAA,GAAM,KAAA;AACV,EAAA,KAAA,MAAW,KAAK,KAAA,EAAO;AACrB,IAAA,GAAA,GAAM,IAAA;AACN,IAAA,IAAI,CAAA,CAAE,CAAA,GAAI,IAAA,EAAM,IAAA,GAAO,CAAA,CAAE,CAAA;AACzB,IAAA,IAAI,CAAA,CAAE,CAAA,GAAI,IAAA,EAAM,IAAA,GAAO,CAAA,CAAE,CAAA;AACzB,IAAA,MAAM,KAAA,GAAQ,CAAA,CAAE,CAAA,GAAI,CAAA,CAAE,KAAA;AACtB,IAAA,MAAM,MAAA,GAAS,CAAA,CAAE,CAAA,GAAI,CAAA,CAAE,MAAA;AACvB,IAAA,IAAI,KAAA,GAAQ,MAAM,IAAA,GAAO,KAAA;AACzB,IAAA,IAAI,MAAA,GAAS,MAAM,IAAA,GAAO,MAAA;AAAA,EAC5B;AACA,EAAA,IAAI,CAAC,KAAK,OAAO,IAAA;AACjB,EAAA,OAAO,EAAE,CAAA,EAAG,IAAA,EAAM,CAAA,EAAG,IAAA,EAAM,OAAO,IAAA,GAAO,IAAA,EAAM,MAAA,EAAQ,IAAA,GAAO,IAAA,EAAK;AACrE;AASO,SAAS,kBAA0C,CAAA,EAAoB;AAC5E,EAAA,MAAM,WAAW,CAAA,CAAE,QAAA;AACnB,EAAA,IAAI,CAAC,QAAA,EAAU;AAGb,IAAA,OAAO,EAAE,CAAA,EAAG,CAAA,CAAE,CAAA,EAAG,CAAA,EAAG,CAAA,CAAE,CAAA,EAAG,KAAA,EAAO,CAAA,CAAE,KAAA,EAAO,MAAA,EAAQ,CAAA,CAAE,MAAA,EAAO;AAAA,EAC5D;AACA,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,CAAI,QAAQ,CAAA;AAC7B,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,CAAI,QAAQ,CAAA;AAC7B,EAAA,MAAM,EAAA,GAAK,CAAA,CAAE,CAAA,GAAI,CAAA,CAAE,KAAA,GAAQ,CAAA;AAC3B,EAAA,MAAM,EAAA,GAAK,CAAA,CAAE,CAAA,GAAI,CAAA,CAAE,MAAA,GAAS,CAAA;AAC5B,EAAA,IAAI,IAAA,GAAO,QAAA;AACX,EAAA,IAAI,IAAA,GAAO,QAAA;AACX,EAAA,IAAI,IAAA,GAAO,CAAA,QAAA;AACX,EAAA,IAAI,IAAA,GAAO,CAAA,QAAA;AACX,EAAA,MAAM,OAAA,GAAoD;AAAA,IACxD,CAAC,CAAA,CAAE,CAAA,EAAG,CAAA,CAAE,CAAC,CAAA;AAAA,IACT,CAAC,CAAA,CAAE,CAAA,GAAI,CAAA,CAAE,KAAA,EAAO,EAAE,CAAC,CAAA;AAAA,IACnB,CAAC,EAAE,CAAA,GAAI,CAAA,CAAE,OAAO,CAAA,CAAE,CAAA,GAAI,EAAE,MAAM,CAAA;AAAA,IAC9B,CAAC,CAAA,CAAE,CAAA,EAAG,CAAA,CAAE,CAAA,GAAI,EAAE,MAAM;AAAA,GACtB;AACA,EAAA,KAAA,MAAW,CAAC,EAAA,EAAI,EAAE,CAAA,IAAK,OAAA,EAAS;AAC9B,IAAA,MAAM,KAAK,EAAA,GAAK,EAAA;AAChB,IAAA,MAAM,KAAK,EAAA,GAAK,EAAA;AAChB,IAAA,MAAM,EAAA,GAAK,EAAA,GAAK,EAAA,GAAK,GAAA,GAAM,EAAA,GAAK,GAAA;AAChC,IAAA,MAAM,EAAA,GAAK,EAAA,GAAK,EAAA,GAAK,GAAA,GAAM,EAAA,GAAK,GAAA;AAChC,IAAA,IAAI,EAAA,GAAK,MAAM,IAAA,GAAO,EAAA;AACtB,IAAA,IAAI,EAAA,GAAK,MAAM,IAAA,GAAO,EAAA;AACtB,IAAA,IAAI,EAAA,GAAK,MAAM,IAAA,GAAO,EAAA;AACtB,IAAA,IAAI,EAAA,GAAK,MAAM,IAAA,GAAO,EAAA;AAAA,EACxB;AACA,EAAA,OAAO,EAAE,CAAA,EAAG,IAAA,EAAM,CAAA,EAAG,IAAA,EAAM,OAAO,IAAA,GAAO,IAAA,EAAM,MAAA,EAAQ,IAAA,GAAO,IAAA,EAAK;AACrE;AAUO,SAAS,UACd,KAAA,EACiB;AACjB,EAAA,IAAI,IAAA,GAAO,QAAA;AACX,EAAA,IAAI,IAAA,GAAO,QAAA;AACX,EAAA,IAAI,IAAA,GAAO,CAAA,QAAA;AACX,EAAA,IAAI,IAAA,GAAO,CAAA,QAAA;AACX,EAAA,IAAI,GAAA,GAAM,KAAA;AACV,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,IAAA,IAAI,CAAC,IAAA,EAAM;AACX,IAAA,MAAM,CAAA,GAAI,kBAAkB,IAAI,CAAA;AAChC,IAAA,GAAA,GAAM,IAAA;AACN,IAAA,IAAI,CAAA,CAAE,CAAA,GAAI,IAAA,EAAM,IAAA,GAAO,CAAA,CAAE,CAAA;AACzB,IAAA,IAAI,CAAA,CAAE,CAAA,GAAI,IAAA,EAAM,IAAA,GAAO,CAAA,CAAE,CAAA;AACzB,IAAA,MAAM,KAAA,GAAQ,CAAA,CAAE,CAAA,GAAI,CAAA,CAAE,KAAA;AACtB,IAAA,MAAM,MAAA,GAAS,CAAA,CAAE,CAAA,GAAI,CAAA,CAAE,MAAA;AACvB,IAAA,IAAI,KAAA,GAAQ,MAAM,IAAA,GAAO,KAAA;AACzB,IAAA,IAAI,MAAA,GAAS,MAAM,IAAA,GAAO,MAAA;AAAA,EAC5B;AACA,EAAA,IAAI,CAAC,KAAK,OAAO,IAAA;AACjB,EAAA,OAAO,EAAE,CAAA,EAAG,IAAA,EAAM,CAAA,EAAG,IAAA,EAAM,OAAO,IAAA,GAAO,IAAA,EAAM,MAAA,EAAQ,IAAA,GAAO,IAAA,EAAK;AACrE;;;ACnCO,SAAS,qBAAA,CACd,YACA,IAAA,EAC8B;AAC9B,EAAA,OAAO,UAAA,CAAW,OAAA,GAAU,IAAI,CAAA,IAAK,UAAA;AACvC;AAIO,SAAS,kBAAA,CAAmB,GAAW,CAAA,EAAoB;AAChE,EAAA,OAAO,CAAA,CAAE,IAAI,CAAA,CAAE,CAAA,GAAI,EAAE,KAAA,IAAS,CAAA,CAAE,CAAA,GAAI,CAAA,CAAE,KAAA,GAAQ,CAAA,CAAE,KAAK,CAAA,CAAE,CAAA,GAAI,EAAE,CAAA,GAAI,CAAA,CAAE,UAAU,CAAA,CAAE,CAAA,GAAI,CAAA,CAAE,MAAA,GAAS,CAAA,CAAE,CAAA;AAClG;AAIO,IAAM,oBAAA,GAA+C;AAAA,EAC1D,SAAA,EAAW,CAAC,CAAA,KAAM,CAAA;AAAA,EAClB,WAAA,EAAa,CAAC,CAAA,EAAG,GAAA,EAAK,GAAA,KAAQ;AAC5B,IAAA,MAAM,KAAK,GAAA,CAAI,KAAA,KAAU,IAAI,CAAA,GAAI,GAAA,CAAI,QAAQ,GAAA,CAAI,KAAA;AACjD,IAAA,MAAM,KAAK,GAAA,CAAI,MAAA,KAAW,IAAI,CAAA,GAAI,GAAA,CAAI,SAAS,GAAA,CAAI,MAAA;AACnD,IAAA,OAAO;AAAA,MACL,GAAG,CAAA;AAAA,MACH,GAAG,GAAA,CAAI,CAAA,GAAA,CAAK,CAAA,CAAE,CAAA,GAAI,IAAI,CAAA,IAAK,EAAA;AAAA,MAC3B,GAAG,GAAA,CAAI,CAAA,GAAA,CAAK,CAAA,CAAE,CAAA,GAAI,IAAI,CAAA,IAAK,EAAA;AAAA,MAC3B,KAAA,EAAO,EAAE,KAAA,GAAQ,EAAA;AAAA,MACjB,MAAA,EAAQ,EAAE,MAAA,GAAS;AAAA,KACrB;AAAA,EACF,CAAA;AAAA,EACA,UAAA,EAAY,CAAC,CAAA,MAAO,EAAE,GAAG,CAAA,CAAE,CAAA,EAAG,CAAA,EAAG,CAAA,CAAE,GAAG,KAAA,EAAO,CAAA,CAAE,KAAA,EAAO,MAAA,EAAQ,EAAE,MAAA,EAAO,CAAA;AAAA,EACvE,SAAA,EAAW,CAAC,CAAA,EAAG,EAAA,EAAI,QAAQ,EAAE,GAAG,CAAA,EAAG,CAAA,EAAG,EAAE,CAAA,GAAI,EAAA,EAAI,CAAA,EAAG,CAAA,CAAE,IAAI,EAAA,EAAG,CAAA;AAAA,EAC5D,gBAAgB,CAAC,CAAA,EAAG,CAAA,KAAM,kBAAA,CAAmB,GAAG,CAAC,CAAA;AAAA,EACjD,IAAA,EAAM,CAAC,CAAA,EAAG,CAAA,EAAG,CAAA,MAAO;AAAA,IAClB,GAAG,CAAA;AAAA,IACH,GAAG,CAAA,CAAE,CAAA,GAAA,CAAK,CAAA,CAAE,CAAA,GAAI,EAAE,CAAA,IAAK,CAAA;AAAA,IACvB,GAAG,CAAA,CAAE,CAAA,GAAA,CAAK,CAAA,CAAE,CAAA,GAAI,EAAE,CAAA,IAAK,CAAA;AAAA,IACvB,OAAO,CAAA,CAAE,KAAA,GAAA,CAAS,CAAA,CAAE,KAAA,GAAQ,EAAE,KAAA,IAAS,CAAA;AAAA,IACvC,QAAQ,CAAA,CAAE,MAAA,GAAA,CAAU,CAAA,CAAE,MAAA,GAAS,EAAE,MAAA,IAAU;AAAA,GAC7C,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,WAAA,EAAa,CAAC,CAAA,KAAM,CAAA,CAAE,QAAA,IAAY,CAAA;AAAA,EAClC,cAAc,CAAC,CAAA,EAAG,cAAc,EAAE,GAAG,GAAG,QAAA,EAAS;AACnD;AAOO,IAAM,uBAAA,GAAuD;AAAA,EAClE,WAAW,oBAAA,CAAqB,SAAA;AAAA,EAChC,aAAa,oBAAA,CAAqB,WAAA;AAAA,EAClC,WAAW,oBAAA,CAAqB,SAAA;AAAA,EAChC,gBAAgB,oBAAA,CAAqB,cAAA;AAAA,EACrC,MAAM,oBAAA,CAAqB,IAAA;AAAA,EAC3B,YAAY,CAAC,CAAA,MAAO,EAAE,CAAA,EAAG,EAAE,CAAA,EAAG,CAAA,EAAG,CAAA,CAAE,CAAA,EAAG,OAAO,CAAA,CAAE,KAAA,EAAO,QAAQ,CAAA,CAAE,MAAA,EAAQ,UAAU,CAAA,EAAE,CAAA;AAAA,EACpF,WAAA,EAAa,CAAC,CAAA,KAAM,CAAA,CAAE,QAAA;AAAA,EACtB,cAAc,CAAC,CAAA,EAAG,cAAc,EAAE,GAAG,GAAG,QAAA,EAAS;AACnD;AAuBO,SAAS,gBAAA,CACd,IAAA,EACA,GAAA,EACA,GAAA,EACO;AACP,EAAA,MAAM,KAAK,GAAA,CAAI,KAAA,KAAU,IAAI,CAAA,GAAI,GAAA,CAAI,QAAQ,GAAA,CAAI,KAAA;AACjD,EAAA,MAAM,KAAK,GAAA,CAAI,MAAA,KAAW,IAAI,CAAA,GAAI,GAAA,CAAI,SAAS,GAAA,CAAI,MAAA;AACnD,EAAA,MAAM,KAAA,GAAQ,KAAK,QAAA,IAAY,CAAA;AAC/B,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,CAAI,KAAK,CAAA;AAC1B,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,GAAA,CAAI,KAAK,CAAA;AAG1B,EAAA,MAAM,EAAA,GAAK,EAAA,GAAK,GAAA,EAAK,EAAA,GAAK,EAAA,GAAK,GAAA;AAC/B,EAAA,MAAM,EAAA,GAAK,CAAC,EAAA,GAAK,GAAA,EAAK,KAAK,EAAA,GAAK,GAAA;AAEhC,EAAA,MAAM,QAAQ,IAAA,CAAK,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,IAAI,EAAE,CAAA;AAC5C,EAAA,MAAM,SAAS,IAAA,CAAK,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,IAAI,EAAE,CAAA;AAC9C,EAAA,MAAM,QAAA,GAAW,IAAA,CAAK,KAAA,CAAM,EAAA,EAAI,EAAE,CAAA;AAGlC,EAAA,MAAM,KAAA,GAAQ,IAAI,CAAA,GAAA,CAAK,IAAA,CAAK,IAAI,IAAA,CAAK,KAAA,GAAQ,CAAA,GAAI,GAAA,CAAI,CAAA,IAAK,EAAA;AAC1D,EAAA,MAAM,KAAA,GAAQ,IAAI,CAAA,GAAA,CAAK,IAAA,CAAK,IAAI,IAAA,CAAK,MAAA,GAAS,CAAA,GAAI,GAAA,CAAI,CAAA,IAAK,EAAA;AAE3D,EAAA,OAAO;AAAA,IACL,GAAG,IAAA;AAAA,IACH,CAAA,EAAG,QAAQ,KAAA,GAAQ,CAAA;AAAA,IACnB,CAAA,EAAG,QAAQ,MAAA,GAAS,CAAA;AAAA,IACpB,KAAA;AAAA,IACA,MAAA;AAAA,IACA;AAAA,GACF;AACF;AAIO,SAAS,yBAAA,CACd,MACA,QAAA,EACQ;AACR,EAAA,MAAM,CAAA,GAAI,QAAA,CAAS,SAAA,CAAU,IAAI,CAAA;AACjC,EAAA,MAAM,WACJ,QAAA,CAAS,WAAA,GAAc,IAAI,CAAA,IAAM,EAA4B,QAAA,IAAY,CAAA;AAC3E,EAAA,OAAO,iBAAA,CAAkB,EAAE,CAAA,EAAG,CAAA,CAAE,GAAG,CAAA,EAAG,CAAA,CAAE,CAAA,EAAG,KAAA,EAAO,EAAE,KAAA,EAAO,MAAA,EAAQ,CAAA,CAAE,MAAA,EAAQ,UAAU,CAAA;AACzF;AAIO,SAAS,0BAAA,CACd,IAAA,EACA,EAAA,EACA,EAAA,EACA,QAAA,EACO;AACP,EAAA,IAAI,SAAS,SAAA,EAAW,OAAO,SAAS,SAAA,CAAU,IAAA,EAAM,IAAI,EAAE,CAAA;AAC9D,EAAA,MAAM,GAAA,GAAM,QAAA,CAAS,SAAA,CAAU,IAAI,CAAA;AACnC,EAAA,MAAM,GAAA,GAAM,EAAE,CAAA,EAAG,GAAA,CAAI,IAAI,EAAA,EAAI,CAAA,EAAG,GAAA,CAAI,CAAA,GAAI,IAAI,KAAA,EAAO,GAAA,CAAI,KAAA,EAAO,MAAA,EAAQ,IAAI,MAAA,EAAO;AACjF,EAAA,OAAO,QAAA,CAAS,WAAA,CAAY,IAAA,EAAM,GAAA,EAAK,GAAG,CAAA;AAC5C;AClMO,IAAM,kBAAA,GAA2C;AAAA,EACtD,SAAA,EAAW,CAAC,IAAA,KAAS,YAAA,CAAa,IAAI,CAAA;AAAA,EACtC,WAAA,EAAa,CAAC,IAAA,EAAM,GAAA,EAAK,GAAA,KAAQ,aAAA;AAAA,IAC/B,IAAA;AAAA,IACAC,SAAS,GAAA,CAAI,CAAA,EAAG,GAAA,CAAI,CAAA,EAAG,IAAI,KAAA,EAAO,GAAA,CAAI,MAAA,EAAQ,GAAA,CAAI,GAAG,GAAA,CAAI,CAAA,EAAG,GAAA,CAAI,KAAA,EAAO,IAAI,MAAM;AAAA,GACnF;AAAA,EACA,YAAY,CAAC,CAAA,MAAO,EAAE,IAAA,EAAM,QAAQ,CAAA,EAAG,CAAA,CAAE,CAAA,EAAG,CAAA,EAAG,EAAE,CAAA,EAAG,KAAA,EAAO,EAAE,KAAA,EAAO,MAAA,EAAQ,EAAE,MAAA,EAAO,CAAA;AAAA,EACrF,SAAA,EAAW,CAAC,IAAA,EAAM,EAAA,EAAI,OAAO,aAAA,CAAc,IAAA,EAAM,IAAI,EAAE,CAAA;AAAA;AAAA;AAAA,EAGvD,cAAA,EAAgB,CAAC,IAAA,EAAM,IAAA,KAAS;AAC9B,IAAA,MAAM,CAAA,GAAI,aAAa,IAAI,CAAA;AAC3B,IAAA,IAAI,CAAC,kBAAA,CAAmB,CAAA,EAAG,IAAI,GAAG,OAAO,KAAA;AACzC,IAAA,IAAI,IAAA,CAAK,IAAA,KAAS,MAAA,EAAQ,OAAO,IAAA;AAEjC,IAAA,IACE,YAAY,IAAA,EAAM,IAAA,CAAK,CAAA,EAAG,IAAA,CAAK,CAAC,CAAA,IAChC,WAAA,CAAY,IAAA,EAAM,IAAA,CAAK,IAAI,IAAA,CAAK,KAAA,EAAO,IAAA,CAAK,CAAC,KAC7C,WAAA,CAAY,IAAA,EAAM,IAAA,CAAK,CAAA,EAAG,KAAK,CAAA,GAAI,IAAA,CAAK,MAAM,CAAA,IAC9C,YAAY,IAAA,EAAM,IAAA,CAAK,CAAA,GAAI,IAAA,CAAK,OAAO,IAAA,CAAK,CAAA,GAAI,IAAA,CAAK,MAAM,GAC3D,OAAO,IAAA;AAGT,IAAA,OAAO,IAAA;AAAA,EACT,CAAA;AAAA,EACA,IAAA,EAAM,CAAC,CAAA,EAAG,CAAA,EAAG,CAAA,KAAM;AACjB,IAAA,IAAI,CAAA,CAAE,IAAA,KAAS,MAAA,IAAU,CAAA,CAAE,SAAS,MAAA,EAAQ;AAC1C,MAAA,OAAO;AAAA,QACL,IAAA,EAAM,MAAA;AAAA,QACN,GAAG,CAAA,CAAE,CAAA,GAAA,CAAK,CAAA,CAAE,CAAA,GAAI,EAAE,CAAA,IAAK,CAAA;AAAA,QACvB,GAAG,CAAA,CAAE,CAAA,GAAA,CAAK,CAAA,CAAE,CAAA,GAAI,EAAE,CAAA,IAAK,CAAA;AAAA,QACvB,OAAO,CAAA,CAAE,KAAA,GAAA,CAAS,CAAA,CAAE,KAAA,GAAQ,EAAE,KAAA,IAAS,CAAA;AAAA,QACvC,QAAQ,CAAA,CAAE,MAAA,GAAA,CAAU,CAAA,CAAE,MAAA,GAAS,EAAE,MAAA,IAAU;AAAA,OAC7C;AAAA,IACF;AACA,IAAA,IAAI,CAAA,CAAE,IAAA,KAAS,SAAA,IAAa,CAAA,CAAE,IAAA,KAAS,SAAA,IAAa,CAAA,CAAE,MAAA,CAAO,MAAA,KAAW,CAAA,CAAE,MAAA,CAAO,MAAA,EAAQ;AACvF,MAAA,MAAM,IAAA,GAAO,IAAI,YAAA,CAAa,CAAA,CAAE,OAAO,MAAM,CAAA;AAC7C,MAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,CAAA,CAAE,MAAA,CAAO,QAAQ,CAAA,EAAA,EAAK;AACxC,QAAA,IAAA,CAAK,CAAC,CAAA,GAAI,CAAA,CAAE,MAAA,CAAO,CAAC,CAAA,GAAA,CAAK,CAAA,CAAE,MAAA,CAAO,CAAC,CAAA,GAAI,CAAA,CAAE,MAAA,CAAO,CAAC,CAAA,IAAK,CAAA;AAAA,MACxD;AACA,MAAA,OAAO,EAAE,IAAA,EAAM,SAAA,EAAW,QAAA,EAAU,CAAA,CAAE,UAAU,MAAA,EAAQ,IAAA,EAAM,QAAA,EAAU,CAAA,CAAE,QAAA,EAAS;AAAA,IACrF;AACA,IAAA,MAAM,IAAI,MAAM,mDAAmD,CAAA;AAAA,EACrE,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,kBAAkB,MAAM;AAC1B;;;AC3DO,SAAS,WAAW,CAAA,EAAuB;AAChD,EAAA,OAAO,CAAC,CAAC,CAAA,IAAK,OAAO,CAAA,KAAM,QAAA,IAAY,MAAA,IAAU,CAAA,KAC1C,CAAA,CAAwB,IAAA,KAAS,SAAA,IAAc,CAAA,CAAwB,IAAA,KAAS,MAAA,CAAA;AACzF;AAIO,SAAS,WAAW,CAAA,EAA6F;AACtH,EAAA,IAAI,CAAC,CAAA,IAAK,OAAO,CAAA,KAAM,UAAU,OAAO,KAAA;AACxC,EAAA,MAAM,CAAA,GAAI,CAAA;AACV,EAAA,OAAO,OAAO,CAAA,CAAE,CAAA,KAAM,QAAA,IAAY,OAAO,CAAA,CAAE,CAAA,KAAM,QAAA,IAC5C,OAAO,CAAA,CAAE,KAAA,KAAU,QAAA,IAAY,OAAO,EAAE,MAAA,KAAW,QAAA;AAC1D;AASO,IAAM,oBAAA,GAAgD;AAAA,EAC3D,SAAA,EAAW,CAAC,CAAA,KAAM,UAAA,CAAW,CAAC,CAAA,GAC1B,kBAAA,CAAmB,SAAA,CAAU,CAAC,CAAA,GAC9B,oBAAA,CAAqB,SAAA,CAAU,CAA4D,CAAA;AAAA,EAC/F,aAAa,CAAC,CAAA,EAAG,KAAK,GAAA,KAAQ,UAAA,CAAW,CAAC,CAAA,GACtC,kBAAA,CAAmB,WAAA,CAAY,CAAA,EAAG,KAAK,GAAG,CAAA,GAC1C,qBAAqB,WAAA,CAAY,CAAA,EAA8D,KAAK,GAAG,CAAA;AAAA,EAC3G,UAAA,EAAY,CAAC,CAAA,EAAG,QAAA,KAAa,WAAW,QAAQ,CAAA,GAC5C,kBAAA,CAAmB,UAAA,CAAW,GAAG,QAAQ,CAAA,GACzC,oBAAA,CAAqB,UAAA,CAAW,GAAG,QAAkB,CAAA;AAAA,EACzD,WAAW,CAAC,CAAA,EAAG,IAAI,EAAA,KAAO,UAAA,CAAW,CAAC,CAAA,GAClC,kBAAA,CAAmB,SAAA,CAAW,CAAA,EAAG,IAAI,EAAE,CAAA,GACvC,qBAAqB,SAAA,CAAW,CAAA,EAA8D,IAAI,EAAE,CAAA;AAAA,EACxG,cAAA,EAAgB,CAAC,CAAA,EAAG,IAAA,KAAS,WAAW,CAAC,CAAA,GACrC,kBAAA,CAAmB,cAAA,CAAgB,GAAG,IAAI,CAAA,GAC1C,oBAAA,CAAqB,cAAA,CAAgB,GAA8D,IAAI,CAAA;AAAA,EAC3G,WAAA,EAAa,CAAC,CAAA,KAAM;AAClB,IAAA,IAAI,UAAA,CAAW,CAAC,CAAA,EAAG,OAAO,CAAA;AAC1B,IAAA,MAAM,IAAK,CAAA,CAA6B,QAAA;AACxC,IAAA,OAAO,OAAO,CAAA,KAAM,QAAA,GAAW,CAAA,GAAI,CAAA;AAAA,EACrC,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAA,EAAkB,CAAC,CAAA,KAAM,CAAC,WAAW,CAAC,CAAA;AAAA,EACtC,YAAA,EAAc,CAAC,CAAA,EAAG,QAAA,KAAa,UAAA,CAAW,CAAC,CAAA,GAAI,CAAA,GAAI,EAAE,GAAI,CAAA,EAAc,QAAA;AACzE","file":"chunk-L5YNZYEG.js","sourcesContent":["/**\n * AABB bounds of a `Path`. Returned as `RectPath` for direct reuse with the\n * rect fast path machinery (selection AABB, area-select intersection).\n *\n * `RectPath` is its own bounds — O(1). For `PolygonPath`, walk segment by\n * segment, computing the tight bound per segment:\n *\n * - `M` / `L`: just the endpoint.\n * - `Q`: quadratic Bezier — endpoints plus axis-aligned extrema (one\n * possible inflection per axis).\n * - `C`: cubic Bezier — endpoints plus axis-aligned extrema (up to two\n * possible inflections per axis, found via the quadratic formula on\n * the derivative).\n *\n * Control points are NOT included directly; they're used only to compute\n * extrema that actually lie on the curve. This avoids the classic \"AABB\n * extends past where the curve visibly reaches\" bug for curved paths whose\n * control points poke outside the visible extent.\n *\n * Empty paths (no commands) return a zero-size rect anchored at the\n * origin — the convention used elsewhere in the kit for missing geometry.\n */\n\nimport { cubicBounds, elevateQuadraticToCubic, forEachSegment } from '@weasel-js/geom';\nimport {\n PATH_C,\n PATH_L,\n PATH_M,\n PATH_Q,\n PATH_Z,\n type Path,\n type RectPath,\n} from './types';\n\n/** AABB of a `Path`, returned as a `RectPath` for direct reuse with rect-fast-path machinery. */\nexport function boundsOfPath(path: Path): RectPath {\n if (path.kind === 'rect') return path;\n\n const { commands, coords } = path;\n if (commands.length === 0) {\n return { kind: 'rect', x: 0, y: 0, width: 0, height: 0 };\n }\n\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n let seen = false;\n\n const include = (x: number, y: number) => {\n if (x < minX) minX = x;\n if (x > maxX) maxX = x;\n if (y < minY) minY = y;\n if (y > maxY) maxY = y;\n seen = true;\n };\n\n forEachSegment(commands, coords, (cmd, ci, px, py) => {\n switch (cmd) {\n case PATH_M:\n case PATH_L: {\n include(coords[ci], coords[ci + 1]);\n break;\n }\n case PATH_C: {\n const [bMinX, bMinY, bMaxX, bMaxY] = cubicBounds(\n px, py,\n coords[ci], coords[ci + 1],\n coords[ci + 2], coords[ci + 3],\n coords[ci + 4], coords[ci + 5],\n );\n include(bMinX, bMinY);\n include(bMaxX, bMaxY);\n break;\n }\n case PATH_Q: {\n const qx2 = coords[ci + 2], qy2 = coords[ci + 3];\n const [c1x, c1y, c2x, c2y] = elevateQuadraticToCubic(px, py, coords[ci], coords[ci + 1], qx2, qy2);\n const [bMinX, bMinY, bMaxX, bMaxY] = cubicBounds(px, py, c1x, c1y, c2x, c2y, qx2, qy2);\n include(bMinX, bMinY);\n include(bMaxX, bMaxY);\n break;\n }\n case PATH_Z:\n break;\n default:\n throw new Error(`boundsOfPath: unknown command ${cmd}`);\n }\n });\n\n if (!seen) return { kind: 'rect', x: 0, y: 0, width: 0, height: 0 };\n return { kind: 'rect', x: minX, y: minY, width: maxX - minX, height: maxY - minY };\n}\n\n","/**\n * Point-in-path hit-testing. `RectPath` short-circuits to AABB compare\n * (O(1)). `PolygonPath` walks the command stream, flattening any bezier\n * segments to line segments, then runs ray-casting (even-odd) or\n * winding-number (non-zero) per the path's `fillRule`.\n *\n * Open subpaths (no `Z`) are skipped for filled hit-testing — they have\n * no enclosed area. For open polylines (strokes), use `strokeHitTest`\n * which computes point-to-segment distance against the flattened\n * polyline and returns true within a configurable threshold.\n */\n\nimport { forEachSegment, pointSegmentDist2 } from '@weasel-js/geom';\nimport { flattenCubic, flattenQuadratic, DEFAULT_FLATTEN_TOLERANCE } from './flatten';\nimport {\n PATH_C,\n PATH_L,\n PATH_M,\n PATH_Q,\n PATH_Z,\n type Path,\n type PolygonPath,\n} from './types';\n\n/** Options for `pointInPath`. */\nexport interface PointInPathOptions {\n /** Bezier flattening tolerance in world units. Default 0.5. */\n tolerance?: number;\n}\n\n/** Filled-region hit-test for a `Path`. Rect short-circuits to AABB; polygons run ray-cast / winding per `fillRule`. */\nexport function pointInPath(\n path: Path,\n x: number,\n y: number,\n opts: PointInPathOptions = {},\n): boolean {\n if (path.kind === 'rect') {\n return x >= path.x && x <= path.x + path.width && y >= path.y && y <= path.y + path.height;\n }\n return pointInPolygonPath(path, x, y, opts.tolerance ?? DEFAULT_FLATTEN_TOLERANCE);\n}\n\nfunction pointInPolygonPath(path: PolygonPath, x: number, y: number, tolerance: number): boolean {\n const { commands, coords, fillRule } = path;\n if (commands.length === 0) return false;\n\n // Walk the command stream; flatten beziers into per-subpath vertex arrays.\n // For each closed subpath, accumulate winding/crossings against (x, y).\n let crossings = 0;\n let winding = 0;\n\n let subStartX = 0, subStartY = 0;\n let subVerts: number[] = []; // flat [x, y, x, y, ...] for current subpath\n let subOpen = false;\n\n const flushSubpath = (closed: boolean) => {\n if (closed && subVerts.length >= 4) {\n // Close the subpath back to its start.\n subVerts.push(subStartX, subStartY);\n // Now subVerts is a closed polyline; tally crossings/winding.\n for (let i = 0; i < subVerts.length - 2; i += 2) {\n const ax = subVerts[i], ay = subVerts[i + 1];\n const bx = subVerts[i + 2], by = subVerts[i + 3];\n if (segmentCrossesRayRight(x, y, ax, ay, bx, by)) {\n crossings++;\n if (ay <= y && by > y) winding++;\n else if (by <= y && ay > y) winding--;\n }\n }\n }\n subVerts = [];\n subOpen = false;\n };\n\n forEachSegment(commands, coords, (cmd, ci, curX, curY) => {\n switch (cmd) {\n case PATH_M: {\n if (subOpen) flushSubpath(false);\n subStartX = coords[ci]; subStartY = coords[ci + 1];\n subVerts.push(subStartX, subStartY);\n subOpen = true;\n break;\n }\n case PATH_L:\n subVerts.push(coords[ci], coords[ci + 1]);\n break;\n case PATH_C:\n flattenCubic(\n curX, curY,\n coords[ci], coords[ci + 1],\n coords[ci + 2], coords[ci + 3],\n coords[ci + 4], coords[ci + 5],\n tolerance, subVerts,\n );\n break;\n case PATH_Q:\n flattenQuadratic(\n curX, curY,\n coords[ci], coords[ci + 1],\n coords[ci + 2], coords[ci + 3],\n tolerance, subVerts,\n );\n break;\n case PATH_Z:\n flushSubpath(true);\n break;\n default:\n throw new Error(`pointInPath: unknown command ${cmd}`);\n }\n });\n if (subOpen) flushSubpath(false);\n\n return fillRule === 'evenodd' ? (crossings & 1) === 1 : winding !== 0;\n}\n\n/**\n * Does the rightward horizontal ray from (x, y) cross segment (ax,ay)→(bx,by)?\n * Standard half-open rule (segments touching from above count, from below\n * don't) — avoids double-counting at shared vertices.\n */\nfunction segmentCrossesRayRight(\n x: number, y: number,\n ax: number, ay: number,\n bx: number, by: number,\n): boolean {\n if ((ay > y) === (by > y)) return false;\n const xCross = ax + ((y - ay) / (by - ay)) * (bx - ax);\n return x < xCross;\n}\n\n/** Options for {@link strokeHitTest}. */\nexport interface StrokeHitTestOptions {\n /** Bezier flattening tolerance in world units. Default 0.5. */\n tolerance?: number;\n}\n\n/**\n * Stroke-distance hit-test. Returns true when (x, y) lies within\n * `threshold` world units of the path's outline — i.e. when a stroke\n * of total width `2 * threshold` drawn along the path would cover the\n * point.\n *\n * Works for both closed and open subpaths — unlike {@link pointInPath},\n * which only tests filled regions. Use this for picking on open\n * polylines / curves and for adding stroke-clickability to closed\n * shapes (logical OR with `pointInPath` when both behaviors are\n * desired).\n *\n * `threshold` is typically the stroke's half-width plus a small slop\n * (e.g. `strokeWidth / 2 + 4`). Cap segments are approximated by the\n * threshold radius around each anchor — the test treats every flattened\n * segment as a capsule of width `2 * threshold`.\n */\nexport function strokeHitTest(\n path: Path,\n x: number,\n y: number,\n threshold: number,\n opts: StrokeHitTestOptions = {},\n): boolean {\n const t2 = threshold * threshold;\n if (path.kind === 'rect') {\n const { x: rx, y: ry, width: w, height: h } = path;\n return (\n pointSegmentDist2(x, y, rx, ry, rx + w, ry) <= t2\n || pointSegmentDist2(x, y, rx + w, ry, rx + w, ry + h) <= t2\n || pointSegmentDist2(x, y, rx + w, ry + h, rx, ry + h) <= t2\n || pointSegmentDist2(x, y, rx, ry + h, rx, ry) <= t2\n );\n }\n return polylineWithinThreshold(path, x, y, t2, opts.tolerance ?? DEFAULT_FLATTEN_TOLERANCE);\n}\n\nfunction polylineWithinThreshold(\n path: PolygonPath,\n px: number, py: number,\n t2: number,\n tolerance: number,\n): boolean {\n const { commands, coords } = path;\n if (commands.length === 0) return false;\n\n // Reuse pointInPath's command-stream + flatten walk; check distance from\n // (px, py) to each emitted segment instead of accumulating crossings.\n let subStartX = 0, subStartY = 0;\n let subVerts: number[] = [];\n let subOpen = false;\n\n const checkSegments = (closed: boolean): boolean => {\n if (closed && subVerts.length >= 4) subVerts.push(subStartX, subStartY);\n for (let i = 0; i < subVerts.length - 2; i += 2) {\n if (pointSegmentDist2(px, py, subVerts[i], subVerts[i + 1], subVerts[i + 2], subVerts[i + 3]) <= t2) {\n return true;\n }\n }\n return false;\n };\n\n let hit = false;\n forEachSegment(commands, coords, (cmd, ci, curX, curY) => {\n switch (cmd) {\n case PATH_M: {\n if (subOpen) {\n if (checkSegments(false)) { hit = true; return false; }\n subVerts = [];\n }\n subStartX = coords[ci]; subStartY = coords[ci + 1];\n subVerts.push(subStartX, subStartY);\n subOpen = true;\n break;\n }\n case PATH_L:\n subVerts.push(coords[ci], coords[ci + 1]);\n break;\n case PATH_C:\n flattenCubic(\n curX, curY,\n coords[ci], coords[ci + 1],\n coords[ci + 2], coords[ci + 3],\n coords[ci + 4], coords[ci + 5],\n tolerance, subVerts,\n );\n break;\n case PATH_Q:\n flattenQuadratic(\n curX, curY,\n coords[ci], coords[ci + 1],\n coords[ci + 2], coords[ci + 3],\n tolerance, subVerts,\n );\n break;\n case PATH_Z:\n if (checkSegments(true)) { hit = true; return false; }\n subVerts = [];\n subOpen = false;\n break;\n default:\n throw new Error(`strokeHitTest: unknown command ${cmd}`);\n }\n return true;\n });\n if (hit) return true;\n if (subOpen && checkSegments(false)) return true;\n return false;\n}\n","/**\n * Fluent builder for `PolygonPath`. Hides the `Uint8Array` / `Float32Array`\n * encoding behind move/line/curve/close calls and a final `build()`. Use\n * this to construct paths in tests and demos; production callers that need\n * to mutate large paths in place should reach for the raw arrays directly.\n *\n * Numeric capacity grows by doubling — typical for amortized O(1) push.\n *\n * Also exposes `rectPath` / `polygonFromPoints` shortcuts for the common\n * cases. `rectPath` returns the lighter `RectPath` subtype, not a polygon.\n */\n\nimport {\n PATH_C,\n PATH_L,\n PATH_M,\n PATH_Q,\n PATH_Z,\n type PathFillRule,\n type PolygonPath,\n type RectPath,\n} from './types';\n\n/** Fluent builder for `PolygonPath`; hides the `Uint8Array`/`Float32Array` encoding behind move/line/curve/close calls. */\nexport class PathBuilder {\n private cmds: number[] = [];\n private xs: number[] = [];\n private fillRule: PathFillRule = 'nonzero';\n\n /** Seed a builder with an existing `PolygonPath`. Useful for extending\n * an in-flight path with another segment (e.g. appending a cubic to\n * the end of a curve in response to a user action) without hand-\n * reaching into the `commands` / `coords` typed arrays.\n *\n * ```ts\n * const next = PathBuilder.fromPath(current).curveTo(...).build();\n * ```\n */\n static fromPath(path: PolygonPath): PathBuilder {\n const b = new PathBuilder();\n b.cmds = Array.from(path.commands);\n b.xs = Array.from(path.coords);\n b.fillRule = path.fillRule;\n return b;\n }\n\n setFillRule(rule: PathFillRule): this {\n this.fillRule = rule;\n return this;\n }\n\n moveTo(x: number, y: number): this {\n this.cmds.push(PATH_M);\n this.xs.push(x, y);\n return this;\n }\n\n lineTo(x: number, y: number): this {\n this.cmds.push(PATH_L);\n this.xs.push(x, y);\n return this;\n }\n\n /** Cubic bezier to (x, y) with control points (x1, y1) and (x2, y2). */\n curveTo(x1: number, y1: number, x2: number, y2: number, x: number, y: number): this {\n this.cmds.push(PATH_C);\n this.xs.push(x1, y1, x2, y2, x, y);\n return this;\n }\n\n /** Quadratic bezier to (x, y) with control point (x1, y1). */\n quadTo(x1: number, y1: number, x: number, y: number): this {\n this.cmds.push(PATH_Q);\n this.xs.push(x1, y1, x, y);\n return this;\n }\n\n close(): this {\n this.cmds.push(PATH_Z);\n return this;\n }\n\n build(): PolygonPath {\n return {\n kind: 'polygon',\n commands: new Uint8Array(this.cmds),\n coords: new Float32Array(this.xs),\n fillRule: this.fillRule,\n };\n }\n}\n\n/** Construct a `RectPath` (the fast-path subtype). */\nexport function rectPath(x: number, y: number, width: number, height: number): RectPath {\n return { kind: 'rect', x, y, width, height };\n}\n\n/** Build an open polyline from a flat list of points — the same geometry as\n * {@link polygonFromPoints} without the closing edge. A freehand stroke and a\n * measurement line want this; a region wants the closed one. */\nexport function polylineFromPoints(\n points: readonly { x: number; y: number }[],\n): PolygonPath | RectPath {\n const b = new PathBuilder();\n const first = points[0];\n if (!first) return rectPath(0, 0, 0, 0);\n b.moveTo(first.x, first.y);\n for (let i = 1; i < points.length; i++) {\n const p = points[i];\n if (p) b.lineTo(p.x, p.y);\n }\n return b.build();\n}\n\n/** Build a closed polygon from a flat list of points. */\nexport function polygonFromPoints(\n points: readonly { x: number; y: number }[],\n opts: { fillRule?: PathFillRule } = {},\n): PolygonPath {\n if (points.length === 0) {\n return {\n kind: 'polygon',\n commands: new Uint8Array(),\n coords: new Float32Array(),\n fillRule: opts.fillRule ?? 'nonzero',\n };\n }\n const b = new PathBuilder();\n if (opts.fillRule) b.setFillRule(opts.fillRule);\n b.moveTo(points[0].x, points[0].y);\n for (let i = 1; i < points.length; i++) b.lineTo(points[i].x, points[i].y);\n b.close();\n return b.build();\n}\n\n/** Cubic-Bezier kappa for circular-quadrant approximation (<1% max error). */\nconst ELLIPSE_KAPPA = 0.5522847498307936;\n\n/** Closed ellipse inscribed in `bounds`, as a 4-cubic-Bezier `PolygonPath`.\n * Matches the geometry `useEllipseTool`'s overlay paints. */\nexport function ellipsePath(\n bounds: { x: number; y: number; width: number; height: number },\n): PolygonPath {\n const cx = bounds.x + bounds.width / 2;\n const cy = bounds.y + bounds.height / 2;\n const rx = bounds.width / 2;\n const ry = bounds.height / 2;\n const ox = rx * ELLIPSE_KAPPA;\n const oy = ry * ELLIPSE_KAPPA;\n const b = new PathBuilder();\n b.moveTo(cx + rx, cy);\n b.curveTo(cx + rx, cy + oy, cx + ox, cy + ry, cx, cy + ry);\n b.curveTo(cx - ox, cy + ry, cx - rx, cy + oy, cx - rx, cy);\n b.curveTo(cx - rx, cy - oy, cx - ox, cy - ry, cx, cy - ry);\n b.curveTo(cx + ox, cy - ry, cx + rx, cy - oy, cx + rx, cy);\n b.close();\n return b.build();\n}\n\n/** Closed regular n-gon centered at `center`, circumscribed by `radius`.\n * `rotation` is in radians; default 0 puts the first vertex on the +x axis. */\nexport function regularPolygonPath(\n center: { x: number; y: number },\n radius: number,\n sides: number,\n rotation = 0,\n): PolygonPath {\n const b = new PathBuilder();\n for (let i = 0; i < sides; i++) {\n const a = rotation + (i / sides) * Math.PI * 2;\n const x = center.x + radius * Math.cos(a);\n const y = center.y + radius * Math.sin(a);\n if (i === 0) b.moveTo(x, y); else b.lineTo(x, y);\n }\n b.close();\n return b.build();\n}\n\n/** Closed n-pointed star centered at `center`, alternating `outerRadius` and\n * `innerRadius` (default `outerRadius / 2`). `rotation` is in radians. */\nexport function starPath(\n center: { x: number; y: number },\n outerRadius: number,\n points = 5,\n innerRadius: number = outerRadius / 2,\n rotation = 0,\n): PolygonPath {\n const b = new PathBuilder();\n const n = points * 2;\n for (let i = 0; i < n; i++) {\n const a = rotation + (i / n) * Math.PI * 2;\n const r = i % 2 === 0 ? outerRadius : innerRadius;\n const x = center.x + r * Math.cos(a);\n const y = center.y + r * Math.sin(a);\n if (i === 0) b.moveTo(x, y); else b.lineTo(x, y);\n }\n b.close();\n return b.build();\n}\n\n/** Open 2-vertex polyline from `a` to `b` — strokeable, not fillable. */\nexport function linePath(\n a: { x: number; y: number },\n b: { x: number; y: number },\n): PolygonPath {\n const pb = new PathBuilder();\n pb.moveTo(a.x, a.y);\n pb.lineTo(b.x, b.y);\n return pb.build();\n}\n","import { type Mat3, transformCoords } from '@weasel-js/geom';\nimport { PathBuilder } from './builder';\nimport { type Path, type PolygonPath } from './types';\n\n/** Apply an affine `Mat3` to a path's geometry.\n *\n * Axis-aligned maps (no rotation/shear, i.e. `m[1] === 0 && m[2] === 0`) keep a\n * `RectPath` a rect — the four corners stay axis-aligned, so we transform the\n * two diagonal corners and normalize negative extent (mirror). Rotation or\n * shear promotes the rect's four corners to a `PolygonPath`. Polygon paths map\n * every coord via the kernel's `transformCoords`, preserving the command stream\n * and `fillRule`. Never mutates the input.\n *\n * `Mat3` here is the 6-tuple `number[]` from `@weasel-js/geom` (DOMMatrix order:\n * `[a, b, c, d, e, f]` where `x' = a·x + c·y + e`, `y' = b·x + d·y + f`),\n * not the renderer's 9-element `Float32Array`. */\nexport function transformPath(path: Path, m: Mat3): Path {\n const [a, b, c, d, e, f] = m;\n if (path.kind === 'rect') {\n if (b === 0 && c === 0) {\n // Pure scale + translate — corners remain axis-aligned.\n const x0 = a * path.x + e;\n const y0 = d * path.y + f;\n const x1 = a * (path.x + path.width) + e;\n const y1 = d * (path.y + path.height) + f;\n return {\n kind: 'rect',\n x: Math.min(x0, x1),\n y: Math.min(y0, y1),\n width: Math.abs(x1 - x0),\n height: Math.abs(y1 - y0),\n };\n }\n // Rotation / shear — promote to polygon with the four rect corners.\n const poly = new PathBuilder()\n .moveTo(path.x, path.y)\n .lineTo(path.x + path.width, path.y)\n .lineTo(path.x + path.width, path.y + path.height)\n .lineTo(path.x, path.y + path.height)\n .close()\n .build();\n return transformPolygon(poly, m);\n }\n return transformPolygon(path, m);\n}\n\nfunction transformPolygon(path: PolygonPath, m: Mat3): PolygonPath {\n // transformCoords returns Float64Array; PolygonPath.coords is Float32Array.\n const mapped = transformCoords(path.coords, m);\n return { ...path, coords: Float32Array.from(mapped) };\n}\n","/**\n * In-place and copy-out path transforms. Translation is the most common —\n * called every pointermove during a drag — so the polygon variant mutates\n * the float buffer directly to keep allocation pressure off the GC.\n *\n * `scalePathToBounds` is for the resize interaction: given the path's\n * current AABB and the desired new AABB, scales every coordinate\n * proportionally.\n */\n\nimport { boxToBox, forEachSegment, pathCommandCoordCount } from '@weasel-js/geom';\nimport { boundsOfPath } from './bounds';\nimport { transformPath } from './transformPath';\nimport type { Path, PolygonPath, RectPath } from './types';\n\n/**\n * Translate a path by (dx, dy). Returns a new instance — the kit's pose\n * model treats poses as immutable to keep React state-update semantics\n * predictable. Polygon coords are copied into a fresh `Float32Array`.\n */\nexport function translatePath(path: Path, dx: number, dy: number): Path {\n if (path.kind === 'rect') {\n return { kind: 'rect', x: path.x + dx, y: path.y + dy, width: path.width, height: path.height };\n }\n return translatePolygonCopy(path, dx, dy);\n}\n\nfunction translatePolygonCopy(path: PolygonPath, dx: number, dy: number): PolygonPath {\n const next = new Float32Array(path.coords.length);\n const { commands, coords } = path;\n forEachSegment(commands, coords, (cmd, ci) => {\n for (let k = 0, len = pathCommandCoordCount(cmd); k < len; k += 2) {\n next[ci + k] = coords[ci + k] + dx;\n next[ci + k + 1] = coords[ci + k + 1] + dy;\n }\n });\n return { kind: 'polygon', commands: path.commands, coords: next, fillRule: path.fillRule };\n}\n\n/**\n * Scale a path's coords so its current AABB maps to `target`. Resize\n * interactions use this to make a polygon follow a corner-handle drag.\n *\n * A degenerate source axis (zero width or height) has no ratio to scale by,\n * so `boxToBox` translates that axis instead — a zero scale is not\n * invertible and would discard what is left on it.\n */\nexport function scalePathToBounds(path: Path, target: RectPath): Path {\n if (path.kind === 'rect') {\n return { kind: 'rect', x: target.x, y: target.y, width: target.width, height: target.height };\n }\n const src = boundsOfPath(path);\n return scalePolygon(path, src, target);\n}\n\nfunction scalePolygon(path: PolygonPath, src: RectPath, dst: RectPath): PolygonPath {\n const m = boxToBox(src.x, src.y, src.width, src.height, dst.x, dst.y, dst.width, dst.height);\n // src/dst are axis-aligned, so the polygon stays a polygon after this pure scale+translate.\n return transformPath(path, m) as PolygonPath;\n}\n","/**\n * Union math over rect-shaped poses.\n *\n * Two answers, deliberately distinct. `unionBounds` folds the *unrotated*\n * boxes and is what commit-time actions want, because they go on to write\n * poses back in that same frame. `unionAABB` expands each rotated member to\n * the extent of its ink first, and is what anything a user looks at or clicks\n * wants — selection chrome, gesture bounds, an export viewBox. Folding the\n * unrotated box there under-reports the extent of a rotated member exactly\n * when the consumer is watching it move.\n */\n\nimport type { RectPose } from 'core/scene/types';\nexport type { RectPose };\n\n/** Compute the AABB envelope of a set of rect-shaped poses, ignoring any\n * rotation they carry. See the module docstring before reaching for this\n * over {@link unionAABB}. */\nexport function unionBounds<TPose extends RectPose>(poses: Iterable<TPose>): RectPose | null {\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n let any = false;\n for (const p of poses) {\n any = true;\n if (p.x < minX) minX = p.x;\n if (p.y < minY) minY = p.y;\n const right = p.x + p.width;\n const bottom = p.y + p.height;\n if (right > maxX) maxX = right;\n if (bottom > maxY) maxY = bottom;\n }\n if (!any) return null;\n return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };\n}\n\n/**\n * Axis-align a pose that carries a `rotation`: returns the AABB of the\n * rotated rectangle, with `rotation` dropped. Follows the kit's rotation\n * convention (`poseRotationOf`): rotate about the unrotated AABB center.\n *\n * Unrotated input is returned as-is.\n */\nexport function axisAlignedBounds<TPose extends RectPose>(b: TPose): RectPose {\n const rotation = b.rotation;\n if (!rotation) {\n // Strip an explicit `rotation: 0` so callers can rely on the absence of\n // the field meaning \"axis-aligned\".\n return { x: b.x, y: b.y, width: b.width, height: b.height };\n }\n const cos = Math.cos(rotation);\n const sin = Math.sin(rotation);\n const cx = b.x + b.width / 2;\n const cy = b.y + b.height / 2;\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n const corners: ReadonlyArray<readonly [number, number]> = [\n [b.x, b.y],\n [b.x + b.width, b.y],\n [b.x + b.width, b.y + b.height],\n [b.x, b.y + b.height],\n ];\n for (const [px, py] of corners) {\n const dx = px - cx;\n const dy = py - cy;\n const rx = cx + dx * cos - dy * sin;\n const ry = cy + dx * sin + dy * cos;\n if (rx < minX) minX = rx;\n if (rx > maxX) maxX = rx;\n if (ry < minY) minY = ry;\n if (ry > maxY) maxY = ry;\n }\n return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };\n}\n\n/**\n * Fold every part into one world-space AABB, skipping `null` / `undefined`\n * entries. Rotated parts are expanded via {@link axisAlignedBounds} first;\n * the result never carries a `rotation` (a union of several oriented boxes\n * has no single orientation to report).\n *\n * Returns `null` when nothing was contributed.\n */\nexport function unionAABB<TPose extends RectPose>(\n parts: Iterable<TPose | null | undefined>,\n): RectPose | null {\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n let any = false;\n for (const part of parts) {\n if (!part) continue;\n const b = axisAlignedBounds(part);\n any = true;\n if (b.x < minX) minX = b.x;\n if (b.y < minY) minY = b.y;\n const right = b.x + b.width;\n const bottom = b.y + b.height;\n if (right > maxX) maxX = right;\n if (bottom > maxY) maxY = bottom;\n }\n if (!any) return null;\n return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };\n}\n","import type { Bounds } from 'core/viewport/fitViewToBounds';\nimport { axisAlignedBounds } from 'core/geometry/unionBounds';\n\n/** `Bounds` with a required rotation angle (radians). Pivot is the AABB\n * center of the unrotated `{x, y, width, height}`. */\nexport interface RotatedPose extends Bounds {\n rotation: number;\n}\n\n/**\n * Bridges arbitrary `TPose` shapes into the resize hook's bounds-driven math.\n * The hook reads bounds via `getBounds`, runs anchor-relative math on those\n * bounds, then asks `remapBounds` to project the result back into TPose.\n *\n * `remapBounds(pose, src, dst)` is a single operation that subsumes both\n * \"set my own AABB to dst\" (single-leaf resize) and \"scale me as a leaf\n * inside parent's src→dst rect\" (group resize) — they're the same affine\n * map. For rect-shaped poses the default geometry interprets the pose as\n * its own bounds; for Path or polygon poses the consumer supplies a\n * projection that knows how to read and rewrite the underlying geometry.\n */\nexport interface PoseDescriptor<TPose, TNode = unknown> {\n getBounds(pose: TPose): Bounds;\n remapBounds(pose: TPose, src: Bounds, dst: Bounds): TPose;\n /** A pose occupying `bounds`, of the same kind as `template`. Unlike\n * `remapBounds`, the result carries none of the template's shape. */\n fromBounds(bounds: Bounds, template: TPose): TPose;\n /** Translate the pose by (dx, dy). Optional — when omitted, callers fall\n * back to a translation derived from `remapBounds` (origin shifted, no\n * scale). Path-shaped poses should provide this for performance. */\n translate?(pose: TPose, dx: number, dy: number): TPose;\n /** True iff any portion of the pose's geometry intersects `rect`. Optional\n * — when omitted, area-select and similar callers test against `getBounds`\n * AABB (looser, but correct for axis-aligned rect poses). */\n intersectsRect?(pose: TPose, rect: Bounds): boolean;\n /** Interpolate between two poses. Optional — animation helpers fall back to\n * rect-shape lerp when omitted (which fails for non-rect poses). */\n lerp?(a: TPose, b: TPose, t: number): TPose;\n /** Read the pose's rotation in radians. Pivot is the AABB center\n * (`getBounds(pose)` center). Default 0 when omitted — descriptor\n * declares \"this pose has no rotation.\" When supplied and non-zero,\n * `useResize` projects the drag delta into the leaf's local frame,\n * runs anchor math there, and translates the resulting pose so the\n * diagonally opposite world-space corner is pinned. */\n getRotation?(pose: TPose): number;\n /** True iff this pose shape can carry a rotation. Consulted by the\n * rotation affordance to decide whether to render the rotate cursor /\n * drag-band over a selection. When omitted, the kit assumes `true` for\n * back-compat — descriptors whose poses lack `x/y/width/height/rotation`\n * fields (e.g. polygon Paths) should return `false` so the affordance\n * hides instead of exposing a non-functional rotate cursor. */\n supportsRotation?(pose: TPose): boolean;\n /** Write a rotation (radians) into the pose, bounds unchanged. Absent means\n * the pose cannot carry one, and the rotate action leaves it alone. */\n withRotation?(pose: TPose, rotation: number): TPose;\n /**\n * A descriptor specialized to one node. Every other method here sees only\n * the pose, so shapes sharing a pose type — a sphere and a box both posed by\n * position/rotation/scale — are indistinguishable to them. Implement this to\n * read `node.data` once and hand back a descriptor that knows which shape it\n * is describing.\n *\n * Callers reach it through {@link poseDescriptorForNode}, at whichever site\n * holds the node; the specialized descriptor then travels into the bounds and\n * hit-test helpers in place of this one. Sites with only an id keep using the\n * unspecialized descriptor, which is why this is optional on both ends.\n */\n forNode?(node: TNode): PoseDescriptor<TPose, TNode>;\n}\n\n/** The descriptor `node` should be read through: its own specialization when\n * it declares one, and otherwise the descriptor unchanged. */\nexport function poseDescriptorForNode<TPose, TNode>(\n descriptor: PoseDescriptor<TPose, TNode>,\n node: TNode,\n): PoseDescriptor<TPose, TNode> {\n return descriptor.forNode?.(node) ?? descriptor;\n}\n\n/** AABB-vs-AABB overlap. Exported for callers building a default\n * `intersectsRect` from `getBounds`. */\nexport function aabbIntersectsRect(b: Bounds, r: Bounds): boolean {\n return b.x < r.x + r.width && b.x + b.width > r.x && b.y < r.y + r.height && b.y + b.height > r.y;\n}\n\n/** Identity geometry for `TPose extends Bounds`. Treats the pose as its\n * own bounds and remaps via affine scale against `src`/`dst`. */\nexport const RECT_POSE_DESCRIPTOR: PoseDescriptor<Bounds> = {\n getBounds: (p) => p,\n remapBounds: (p, src, dst) => {\n const sx = src.width === 0 ? 1 : dst.width / src.width;\n const sy = src.height === 0 ? 1 : dst.height / src.height;\n return {\n ...p,\n x: dst.x + (p.x - src.x) * sx,\n y: dst.y + (p.y - src.y) * sy,\n width: p.width * sx,\n height: p.height * sy,\n };\n },\n fromBounds: (b) => ({ x: b.x, y: b.y, width: b.width, height: b.height }),\n translate: (p, dx, dy) => ({ ...p, x: p.x + dx, y: p.y + dy }),\n intersectsRect: (p, r) => aabbIntersectsRect(p, r),\n lerp: (a, b, t) => ({\n ...a,\n x: a.x + (b.x - a.x) * t,\n y: a.y + (b.y - a.y) * t,\n width: a.width + (b.width - a.width) * t,\n height: a.height + (b.height - a.height) * t,\n }),\n // `Bounds` carries an optional `rotation`, and `withRotation` writes into\n // it — so reading it back has to be the same channel, or a pose reports\n // itself unrotated to `useResize` and to port placement while painting\n // rotated.\n getRotation: (p) => p.rotation ?? 0,\n withRotation: (p, rotation) => ({ ...p, rotation }),\n};\n\n/** Identity geometry for `RotatedPose`. Inherits rect-shape projection\n * from `RECT_POSE_DESCRIPTOR` (the `RotatedPose extends Bounds`\n * subtype lets the rect descriptor's methods apply directly; `remapBounds`\n * preserves the `rotation` field via `...p` spread). Adds `getRotation` so\n * `useResize` knows to take the rotation-aware math path. */\nexport const ROTATED_POSE_DESCRIPTOR: PoseDescriptor<RotatedPose> = {\n getBounds: RECT_POSE_DESCRIPTOR.getBounds as PoseDescriptor<RotatedPose>['getBounds'],\n remapBounds: RECT_POSE_DESCRIPTOR.remapBounds as PoseDescriptor<RotatedPose>['remapBounds'],\n translate: RECT_POSE_DESCRIPTOR.translate as PoseDescriptor<RotatedPose>['translate'],\n intersectsRect: RECT_POSE_DESCRIPTOR.intersectsRect as PoseDescriptor<RotatedPose>['intersectsRect'],\n lerp: RECT_POSE_DESCRIPTOR.lerp as PoseDescriptor<RotatedPose>['lerp'],\n fromBounds: (b) => ({ x: b.x, y: b.y, width: b.width, height: b.height, rotation: 0 }),\n getRotation: (p) => p.rotation,\n withRotation: (p, rotation) => ({ ...p, rotation }),\n};\n\n/**\n * Remap a **rotated** leaf inside a group resize.\n *\n * The naive `remapBounds` scales a leaf's axis-aligned `width`/`height` by the\n * group's per-axis factors and carries `rotation` through untouched. That is\n * right when `src`/`dst` are already expressed in the leaf's own frame — the\n * single-leaf resize path, where the drag delta was projected into that frame\n * before the anchor math ran. In a group resize they are world-frame, so the\n * leaf's local axes do not line up with the axes being scaled: at 90° a\n * horizontal stretch should grow the leaf's `height`, and the naive map grows\n * its `width`.\n *\n * What this computes is the group affine applied to the leaf's local frame,\n * with the shear dropped — the pose model is `{x, y, width, height, rotation}`\n * and cannot represent the parallelogram a non-uniform scale of a rotated box\n * actually produces. The center moves exactly; each local axis takes the\n * length of its own image; the rotation follows the image of the local x-axis.\n *\n * Degenerates to the naive map at `rotation === 0`, and to a plain uniform\n * scale when `sx === sy`, both exactly.\n */\nexport function remapRotatedLeaf<TPose extends RotatedPose>(\n pose: TPose,\n src: Bounds,\n dst: Bounds,\n): TPose {\n const sx = src.width === 0 ? 1 : dst.width / src.width;\n const sy = src.height === 0 ? 1 : dst.height / src.height;\n const theta = pose.rotation ?? 0;\n const cos = Math.cos(theta);\n const sin = Math.sin(theta);\n\n // Images of the leaf's local unit axes under the group's diagonal scale.\n const ux = sx * cos, uy = sy * sin;\n const vx = -sx * sin, vy = sy * cos;\n\n const width = pose.width * Math.hypot(ux, uy);\n const height = pose.height * Math.hypot(vx, vy);\n const rotation = Math.atan2(uy, ux);\n\n // The center is a point, so it takes the group affine directly.\n const cxNew = dst.x + (pose.x + pose.width / 2 - src.x) * sx;\n const cyNew = dst.y + (pose.y + pose.height / 2 - src.y) * sy;\n\n return {\n ...pose,\n x: cxNew - width / 2,\n y: cyNew - height / 2,\n width,\n height,\n rotation,\n };\n}\n\n/** The pose's visual bounds: its frame expanded to cover the rotated\n * rectangle, so a turned shape reports the extent of its ink. */\nexport function visualBoundsViaDescriptor<TPose>(\n pose: TPose,\n geometry: PoseDescriptor<TPose>,\n): Bounds {\n const b = geometry.getBounds(pose);\n const rotation =\n geometry.getRotation?.(pose) ?? (b as { rotation?: number }).rotation ?? 0;\n return axisAlignedBounds({ x: b.x, y: b.y, width: b.width, height: b.height, rotation });\n}\n\n/** Translate through `geometry.translate`, or via `remapBounds` onto a shifted\n * copy of the pose's own bounds when the descriptor has none. */\nexport function translatePoseViaDescriptor<TPose>(\n pose: TPose,\n dx: number,\n dy: number,\n geometry: PoseDescriptor<TPose>,\n): TPose {\n if (geometry.translate) return geometry.translate(pose, dx, dy);\n const src = geometry.getBounds(pose);\n const dst = { x: src.x + dx, y: src.y + dy, width: src.width, height: src.height };\n return geometry.remapBounds(pose, src, dst);\n}\n","import { boxToBox } from '@weasel-js/geom';\nimport { boundsOfPath } from './bounds';\nimport { pointInPath } from './hitTest';\nimport { translatePath } from './transform';\nimport { transformPath } from './transformPath';\nimport type { Path } from './types';\nimport { aabbIntersectsRect, type PoseDescriptor } from 'interactions/actions/resize/geometry';\n\n/**\n * `PoseDescriptor` for `Path` poses — wires `useResize` to operate\n * on `Path` directly. `getBounds` defers to the same `boundsOfPath` kernel\n * the rest of the kit uses.\n *\n * `remapBounds` mirrors `scalePathToBounds` but takes `src` explicitly: the\n * resize hook knows the group's origin AABB and uses it for every leaf,\n * instead of each leaf scaling against its own AABB (which would ignore\n * group context).\n */\nexport const pathPoseDescriptor: PoseDescriptor<Path> = {\n getBounds: (path) => boundsOfPath(path),\n remapBounds: (path, src, dst) => transformPath(\n path,\n boxToBox(src.x, src.y, src.width, src.height, dst.x, dst.y, dst.width, dst.height),\n ),\n fromBounds: (b) => ({ kind: 'rect', x: b.x, y: b.y, width: b.width, height: b.height }),\n translate: (path, dx, dy) => translatePath(path, dx, dy),\n // WHY: AABB pre-test is cheap; only fall through to per-corner pointInPath\n // when the rect is fully inside the AABB (silhouette test).\n intersectsRect: (path, rect) => {\n const b = boundsOfPath(path);\n if (!aabbIntersectsRect(b, rect)) return false;\n if (path.kind === 'rect') return true;\n // Sample the rect's four corners; any inside the polygon ⇒ overlap.\n if (\n pointInPath(path, rect.x, rect.y) ||\n pointInPath(path, rect.x + rect.width, rect.y) ||\n pointInPath(path, rect.x, rect.y + rect.height) ||\n pointInPath(path, rect.x + rect.width, rect.y + rect.height)\n ) return true;\n // Conservative fallback: AABB overlap counts. Tighter edge-vs-edge test\n // would be the next step; defer until a demo demands it.\n return true;\n },\n lerp: (a, b, t) => {\n if (a.kind === 'rect' && b.kind === 'rect') {\n return {\n kind: 'rect',\n x: a.x + (b.x - a.x) * t,\n y: a.y + (b.y - a.y) * t,\n width: a.width + (b.width - a.width) * t,\n height: a.height + (b.height - a.height) * t,\n };\n }\n if (a.kind === 'polygon' && b.kind === 'polygon' && a.coords.length === b.coords.length) {\n const next = new Float32Array(a.coords.length);\n for (let i = 0; i < a.coords.length; i++) {\n next[i] = a.coords[i] + (b.coords[i] - a.coords[i]) * t;\n }\n return { kind: 'polygon', commands: a.commands, coords: next, fillRule: a.fillRule };\n }\n throw new Error('pathPoseDescriptor.lerp: incompatible path shapes');\n },\n // Path poses carry no x/y/width/height/rotation fields — the kit's\n // `wrapWithPoseRotation` helper has nothing to bind a rotation to, and\n // `remapBounds` would drop a synthetic rotation field on every commit.\n // Returning false here hides the rotation affordance for Path consumers\n // so the rotate cursor doesn't appear without a working interaction.\n supportsRotation: () => false,\n};\n","import type { Path } from 'features/paths/types';\nimport { pathPoseDescriptor } from 'features/paths/poseDescriptor';\nimport { RECT_POSE_DESCRIPTOR, type PoseDescriptor } from './geometry';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\n\n/** True for Path-shaped poses (`{kind: 'polygon' | 'rect'}`). Useful for\n * callers that need to fork between `pathPoseDescriptor` and\n * `RECT_POSE_DESCRIPTOR` without forcing the consumer to wire\n * `poseDescriptor` explicitly. */\nexport function isPathLike(p: unknown): p is Path {\n return !!p && typeof p === 'object' && 'kind' in p\n && ((p as { kind: unknown }).kind === 'polygon' || (p as { kind: unknown }).kind === 'rect');\n}\n\n/** True for a pose with numeric top-level `x`/`y`/`width`/`height` — the only\n * shape the rect descriptor and the kit's built-in painters can read. */\nexport function isRectPose(p: unknown): p is { x: number; y: number; width: number; height: number; rotation?: number } {\n if (!p || typeof p !== 'object') return false;\n const r = p as Record<string, unknown>;\n return typeof r.x === 'number' && typeof r.y === 'number'\n && typeof r.width === 'number' && typeof r.height === 'number';\n}\n\n/** Per-call dispatch: if the pose looks like a Path, route to\n * `pathPoseDescriptor`; otherwise treat as a plain rect pose. Avoids forcing\n * demos with Path TPose to wire `poseDescriptor={pathPoseDescriptor}`\n * explicitly. `getRotation` surfaces a `pose.rotation` field on non-Path poses\n * so demos using rect-with-rotation shapes (e.g. `RotatedPose`) don't have to\n * wire `poseDescriptor={ROTATED_POSE_DESCRIPTOR}` just to get rotated\n * selection chrome and rotation-aware corner hit-tests. */\nexport const AUTO_POSE_DESCRIPTOR: PoseDescriptor<unknown> = {\n getBounds: (p) => isPathLike(p)\n ? pathPoseDescriptor.getBounds(p)\n : RECT_POSE_DESCRIPTOR.getBounds(p as { x: number; y: number; width: number; height: number }),\n remapBounds: (p, src, dst) => isPathLike(p)\n ? pathPoseDescriptor.remapBounds(p, src, dst)\n : RECT_POSE_DESCRIPTOR.remapBounds(p as { x: number; y: number; width: number; height: number }, src, dst),\n fromBounds: (b, template) => isPathLike(template)\n ? pathPoseDescriptor.fromBounds(b, template)\n : RECT_POSE_DESCRIPTOR.fromBounds(b, template as Bounds),\n translate: (p, dx, dy) => isPathLike(p)\n ? pathPoseDescriptor.translate!(p, dx, dy)\n : RECT_POSE_DESCRIPTOR.translate!(p as { x: number; y: number; width: number; height: number }, dx, dy),\n intersectsRect: (p, rect) => isPathLike(p)\n ? pathPoseDescriptor.intersectsRect!(p, rect)\n : RECT_POSE_DESCRIPTOR.intersectsRect!(p as { x: number; y: number; width: number; height: number }, rect),\n getRotation: (p) => {\n if (isPathLike(p)) return 0;\n const r = (p as { rotation?: unknown }).rotation;\n return typeof r === 'number' ? r : 0;\n },\n // Path-shaped poses can't carry rotation (see `pathPoseDescriptor`).\n // Everything else flows through `wrapWithPoseRotation`'s x/y/w/h gate at\n // paint time, so report `true` and let the wrapper no-op for poses\n // missing AABB fields.\n supportsRotation: (p) => !isPathLike(p),\n withRotation: (p, rotation) => isPathLike(p) ? p : { ...(p as object), rotation },\n};\n"]}
|
|
@@ -314,5 +314,5 @@ function pointAlongPath(path, t, opts = {}) {
|
|
|
314
314
|
}
|
|
315
315
|
|
|
316
316
|
export { DEFAULT_ALPHA_DECAY, DEFAULT_ALPHA_MIN, DEFAULT_VELOCITY_DECAY, aabbCenter, createSimulation, extractPolylines, pointAlongPath, pointInRotatedRect, rectCorners, rotatePoint, rotatedRectCorners };
|
|
317
|
-
//# sourceMappingURL=chunk-
|
|
318
|
-
//# sourceMappingURL=chunk-
|
|
317
|
+
//# sourceMappingURL=chunk-PNNZSYRD.js.map
|
|
318
|
+
//# sourceMappingURL=chunk-PNNZSYRD.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/features/simulation/types.ts","../src/features/simulation/createSimulation.ts","../src/interactions/actions/rotate/geometry.ts","../src/features/paths/tessellate/polyline.ts","../src/features/paths/pathAt.ts"],"names":["last"],"mappings":"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","file":"chunk-LXJDWBEL.js","sourcesContent":["/**\n * Minimal node interface for the simulation primitive. Matches d3-force's\n * node shape exactly so d3-force's bundled forces work without translation.\n *\n * Consumers extend this with arbitrary additional fields (id, label, etc.).\n */\nexport interface SimulationNode {\n x: number;\n y: number;\n vx?: number;\n vy?: number;\n /** Pin x to this value when non-null. The integrator skips x/vx for the node. */\n fx?: number | null;\n fy?: number | null;\n /** Array index, written by `initialize`. Some forces (e.g. forceLink) rely on it. */\n index?: number;\n}\n\n/**\n * Force protocol — contract-compatible with d3-force. A force is a function\n * called once per tick with the current alpha; it mutates `vx`/`vy` on nodes.\n * Optional `initialize` lets the force compute setup (link indices, etc.).\n */\nexport interface SimulationForce<TNode extends SimulationNode = SimulationNode> {\n (alpha: number): void;\n initialize?(nodes: TNode[], random?: () => number): void;\n}\n\n/** Options for `useSimulation`: everything {@link SimulationOptions} carries,\n * plus the loop's own callbacks and clock. */\nexport interface UseSimulationOptions<TNode extends SimulationNode>\n extends SimulationOptions<TNode> {\n /** Fired after each integration step. */\n onTick?: (nodes: TNode[]) => void;\n /** Fired once when the sim settles (alpha < alphaMin && alphaTarget === 0). */\n onEnd?: () => void;\n\n // Test injection (mirrors useAnimator):\n /** Optional rAF injection. Defaults to window.requestAnimationFrame. */\n requestFrame?: (cb: (t: number) => void) => number;\n cancelFrame?: (handle: number) => void;\n}\n\n/**\n * A force simulation over a set of nodes, with no clock of its own.\n *\n * Each tick applies every force and then integrates velocities, scaled by\n * `alpha` — a temperature that decays toward `alphaTarget` so the layout\n * settles instead of jittering forever. Raise `alphaTarget` to reheat it,\n * which is what a drag does.\n *\n * Nodes are mutated in place; the simulation holds the array, not a copy.\n *\n * Nothing here advances time. {@link Simulation} adds the frame loop; a caller\n * that wants the whole relaxation at once — a layout pass, a pre-warm, a test\n * — drives {@link SimulationCore.tick} itself.\n */\nexport interface SimulationCore<TNode extends SimulationNode> {\n readonly nodes: TNode[];\n\n setNodes(nodes: TNode[]): this;\n setForces(forces: SimulationForce<TNode>[]): this;\n\n alpha(): number;\n alpha(value: number): this;\n alphaTarget(): number;\n alphaTarget(value: number): this;\n alphaDecay(): number;\n alphaDecay(value: number): this;\n alphaMin(): number;\n alphaMin(value: number): this;\n velocityDecay(): number;\n velocityDecay(value: number): this;\n\n /**\n * Run the tick body synchronously `iterations` times. Does NOT fire\n * onTick or onEnd (matches d3-force). Used for offscreen pre-warm and tests.\n */\n tick(iterations?: number): this;\n\n isSettled(): boolean;\n}\n\n/** A {@link SimulationCore} running on a frame loop. */\nexport interface Simulation<TNode extends SimulationNode> extends SimulationCore<TNode> {\n /** Resume the RAF loop. If alpha < alphaMin, reset alpha to 1. */\n restart(): this;\n /** Cancel the RAF loop. Does not change alpha. */\n stop(): this;\n}\n\n/** What {@link SimulationCore} needs: the nodes, the forces acting on them,\n * and the cooling schedule. {@link UseSimulationOptions} adds the loop's. */\nexport interface SimulationOptions<TNode extends SimulationNode> {\n /** Mutable array of nodes. Kit + forces mutate vx/vy/x/y in place. */\n nodes: TNode[];\n /** Forces applied per tick. Each may implement `initialize` for setup. */\n forces?: SimulationForce<TNode>[];\n\n /** Initial alpha. Default 1. */\n alpha?: number;\n /** Settle threshold. When alpha drops below and alphaTarget is 0, onEnd fires. Default 0.001. */\n alphaMin?: number;\n /** Per-tick decay rate toward alphaTarget. Default 1 - 0.001^(1/300) ≈ 0.0228. */\n alphaDecay?: number;\n /** Target alpha. Set above alphaMin to keep sim warm (e.g. during drag). Default 0. */\n alphaTarget?: number;\n /** Friction multiplier on velocity per tick: vx *= (1 - velocityDecay). Default 0.4. */\n velocityDecay?: number;\n /** Handed to each force's `initialize`. Default `Math.random`; pass a seeded\n * source to make a run reproducible. */\n random?: () => number;\n}\n\n/** Default alpha decay: such that alpha drops from 1 to alphaMin (0.001) in 300 ticks. */\nexport const DEFAULT_ALPHA_DECAY = 1 - Math.pow(0.001, 1 / 300);\n/** Alpha below which a cooling simulation is considered settled. */\nexport const DEFAULT_ALPHA_MIN = 0.001;\n/** Fraction of velocity shed each tick — friction. Higher settles sooner and\n * overshoots less. */\nexport const DEFAULT_VELOCITY_DECAY = 0.4;\n","/**\n * The integrator, with no clock attached.\n *\n * Velocity-Verlet over a pluggable force list, contract-compatible with\n * d3-force so d3's own bundled forces drop in untranslated. Nothing here\n * advances time: `tick()` is the only thing that moves a node, and the caller\n * decides how often to call it. `useSimulation` calls it once a frame; a\n * layout pass calls it a few hundred times in one go and reads the result.\n *\n * Splitting it out is what lets a *pure* function run a relaxation — a React\n * hook cannot, and the alternative was a second integrator drifting away from\n * this one.\n */\nimport {\n DEFAULT_ALPHA_DECAY,\n DEFAULT_ALPHA_MIN,\n DEFAULT_VELOCITY_DECAY,\n type SimulationCore,\n type SimulationForce,\n type SimulationNode,\n type SimulationOptions,\n} from './types';\n\nexport function createSimulation<TNode extends SimulationNode>(\n opts: SimulationOptions<TNode>,\n): SimulationCore<TNode> {\n let nodes = opts.nodes;\n let forces = opts.forces ?? [];\n let alpha = opts.alpha ?? 1;\n let alphaMin = opts.alphaMin ?? DEFAULT_ALPHA_MIN;\n let alphaDecay = opts.alphaDecay ?? DEFAULT_ALPHA_DECAY;\n let alphaTarget = opts.alphaTarget ?? 0;\n let velocityDecay = opts.velocityDecay ?? DEFAULT_VELOCITY_DECAY;\n const random = opts.random ?? Math.random;\n\n /** `index` is what `forceLink` and friends address nodes by, and a d3 force\n * does `n.vx += …` without checking, so both must exist before the first\n * tick or the first tick produces NaN. */\n function prime(list: TNode[]): void {\n list.forEach((n, i) => {\n n.index = i;\n if (n.vx == null) n.vx = 0;\n if (n.vy == null) n.vy = 0;\n });\n }\n\n prime(nodes);\n for (const f of forces) f.initialize?.(nodes, random);\n\n function step(): void {\n alpha += (alphaTarget - alpha) * alphaDecay;\n for (const f of forces) f(alpha);\n\n const friction = 1 - velocityDecay;\n for (const n of nodes) {\n if (n.fx == null) {\n n.vx = (n.vx ?? 0) * friction;\n // A non-finite velocity — force overflow, or two nodes exactly\n // coincident — would reach the renderer as geometry and cost\n // pathological tessellation work without throwing anywhere.\n if (!Number.isFinite(n.vx)) n.vx = 0;\n n.x += n.vx;\n if (!Number.isFinite(n.x)) n.x = 0;\n } else {\n n.x = n.fx;\n n.vx = 0;\n }\n if (n.fy == null) {\n n.vy = (n.vy ?? 0) * friction;\n if (!Number.isFinite(n.vy)) n.vy = 0;\n n.y += n.vy;\n if (!Number.isFinite(n.y)) n.y = 0;\n } else {\n n.y = n.fy;\n n.vy = 0;\n }\n }\n }\n\n /* eslint-disable @typescript-eslint/no-explicit-any */\n const core: any = {\n get nodes() {\n return nodes;\n },\n setNodes(next: TNode[]) {\n nodes = next;\n prime(nodes);\n for (const f of forces) f.initialize?.(nodes, random);\n return core;\n },\n setForces(next: SimulationForce<TNode>[]) {\n const old = forces;\n forces = next;\n for (const f of next) {\n if (!old.includes(f)) f.initialize?.(nodes, random);\n }\n return core;\n },\n alpha(value?: number) {\n if (value === undefined) return alpha;\n alpha = value;\n return core;\n },\n alphaTarget(value?: number) {\n if (value === undefined) return alphaTarget;\n alphaTarget = value;\n return core;\n },\n alphaDecay(value?: number) {\n if (value === undefined) return alphaDecay;\n alphaDecay = value;\n return core;\n },\n alphaMin(value?: number) {\n if (value === undefined) return alphaMin;\n alphaMin = value;\n return core;\n },\n velocityDecay(value?: number) {\n if (value === undefined) return velocityDecay;\n velocityDecay = value;\n return core;\n },\n tick(iterations: number = 1) {\n for (let i = 0; i < iterations; i++) step();\n return core;\n },\n isSettled() {\n return alpha < alphaMin && alphaTarget === 0;\n },\n };\n /* eslint-enable @typescript-eslint/no-explicit-any */\n return core as SimulationCore<TNode>;\n}\n","import type { RotatedPose } from '../../gestures/types';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\n\n/** AABB center of an unrotated rect — the canonical rotation pivot. */\nexport function aabbCenter(bounds: Bounds): { x: number; y: number } {\n return { x: bounds.x + bounds.width / 2, y: bounds.y + bounds.height / 2 };\n}\n\n/** Rotate `(px, py)` by `angle` (radians) around `(cx, cy)`. */\nexport function rotatePoint(\n px: number,\n py: number,\n cx: number,\n cy: number,\n angle: number,\n): { x: number; y: number } {\n const c = Math.cos(angle);\n const s = Math.sin(angle);\n const dx = px - cx;\n const dy = py - cy;\n return { x: cx + dx * c - dy * s, y: cy + dx * s + dy * c };\n}\n\n/** Four corners of an unrotated rect, in TL/TR/BR/BL order. */\nexport function rectCorners(bounds: Bounds): { x: number; y: number }[] {\n return [\n { x: bounds.x, y: bounds.y },\n { x: bounds.x + bounds.width, y: bounds.y },\n { x: bounds.x + bounds.width, y: bounds.y + bounds.height },\n { x: bounds.x, y: bounds.y + bounds.height },\n ];\n}\n\n/** Four corners of a rotated rect (rotation around AABB center), in\n * TL/TR/BR/BL order. Useful for selection-overlay rendering. */\nexport function rotatedRectCorners(pose: RotatedPose): { x: number; y: number }[] {\n const c = aabbCenter(pose);\n return rectCorners(pose).map((p) => rotatePoint(p.x, p.y, c.x, c.y, pose.rotation));\n}\n\n/** Hit-test a world point against a rotated rect (rotation around AABB\n * center). Standard pattern: invert the rotation and AABB-test in the\n * rect's local frame. */\nexport function pointInRotatedRect(\n pose: RotatedPose,\n worldX: number,\n worldY: number,\n): boolean {\n const c = aabbCenter(pose);\n const local = rotatePoint(worldX, worldY, c.x, c.y, -pose.rotation);\n return (\n local.x >= pose.x &&\n local.x <= pose.x + pose.width &&\n local.y >= pose.y &&\n local.y <= pose.y + pose.height\n );\n}\n","import { forEachSegment, rectToContour } from '@weasel-js/geom';\nimport {\n PATH_M,\n PATH_L,\n PATH_Z,\n PATH_C,\n PATH_Q,\n DEFAULT_FLATTEN_TOLERANCE,\n flattenCubicWithArcLen,\n flattenQuadraticWithArcLen,\n} from '@weasel-js/geom';\nimport type { Path, PolygonPath, RectPath } from '../../../core/geometry/path';\n\nexport interface Polyline {\n /** Interleaved x,y vertices (length = 2 × point count). */\n points: number[];\n /** Whether the contour was closed (ends with Z, or is a RectPath). */\n closed: boolean;\n /** For each point, the previous anchor index. Anchor-aligned points set A === B. */\n anchorA?: Uint32Array;\n /** For each point, the next anchor index. */\n anchorB?: Uint32Array;\n /** For each point, the arc-length fraction along (A, B). 0 at anchor A; for anchor-aligned, set to 0. */\n anchorT?: Float32Array;\n /** Per-point stroke width, populated by the tessellator when the Stroke\n * carries `vertexWidths`. Undefined means uniform `Stroke.width`. */\n widths?: Float32Array;\n}\n\nexport interface ExtractOptions {\n flattenTolerance?: number;\n}\n\nexport function extractPolylines(path: Path, opts: ExtractOptions = {}): Polyline[] {\n if (path.kind === 'rect') return [extractRect(path)];\n return extractPolygon(path, opts);\n}\n\nfunction extractRect(p: RectPath): Polyline {\n const { x, y, width: w, height: h } = p;\n return {\n points: Array.from(rectToContour(x, y, w, h)),\n closed: true,\n anchorA: new Uint32Array([0, 1, 2, 3]),\n anchorB: new Uint32Array([0, 1, 2, 3]),\n anchorT: new Float32Array([0, 0, 0, 0]),\n };\n}\n\nfunction extractPolygon(p: PolygonPath, opts: ExtractOptions): Polyline[] {\n const tolerance = opts.flattenTolerance ?? DEFAULT_FLATTEN_TOLERANCE;\n const { commands, coords } = p;\n const out: Polyline[] = [];\n // Anchors are numbered globally (across all contours) in command-stream order.\n let anchorCounter = 0;\n\n // Builders for the current polyline.\n let pts: number[] | null = null;\n let aA: number[] | null = null;\n let aB: number[] | null = null;\n let aT: number[] | null = null;\n let current: Polyline | null = null;\n\n let prevAnchor = -1;\n\n const beginContour = (): Polyline => {\n pts = [];\n aA = [];\n aB = [];\n aT = [];\n const next: Polyline = { points: pts, closed: false };\n out.push(next);\n return next;\n };\n\n /**\n * A closed contour's last point repeating its first is redundant — Z already\n * says \"return to the start\" — and it is *harmful*: it leaves a zero-length\n * closing segment, which the stroker discards along with the wrap-around\n * join it should have carried, notching the ribbon at the contour's start.\n *\n * Every font outline serialized by opentype.js is written this way, as is a\n * great deal of hand-written and exported SVG, so this is the common case\n * rather than a defensive edge. Exact equality is the right test: the\n * duplicate is a re-emission of the same number, not an approach to it, and\n * a near-miss is a genuine (if tiny) segment the author asked for.\n */\n const dropDuplicateClosingPoint = (): void => {\n if (!pts || !aA || !aB || !aT) return;\n const n = pts.length / 2;\n if (n < 2) return;\n if (pts[0] !== pts[(n - 1) * 2] || pts[1] !== pts[(n - 1) * 2 + 1]) return;\n pts.length -= 2;\n aA.length -= 1;\n aB.length -= 1;\n aT.length -= 1;\n };\n\n const commit = (target: Polyline): void => {\n if (!pts || !aA || !aB || !aT) return;\n target.anchorA = new Uint32Array(aA);\n target.anchorB = new Uint32Array(aB);\n target.anchorT = new Float32Array(aT);\n };\n\n // Fill anchorA/B/T for each point a curve just appended: interior points\n // interpolate (prevAnchor → target), and the final point is pinned to the\n // target so the draw-time lerp returns anchor B's color exactly.\n const pushCurveAnchors = (segStart: number, arcAccum: number[], total: number, target: number): void => {\n for (let k = 0; k < arcAccum.length; k++) {\n aA!.push(prevAnchor);\n aB!.push(target);\n aT!.push(total > 0 ? arcAccum[k] / total : 0);\n }\n const lastIdx = (segStart + arcAccum.length) - 1;\n aA![lastIdx] = target;\n aB![lastIdx] = target;\n aT![lastIdx] = 0;\n };\n\n forEachSegment(commands, coords, (cmd, coordIdx, prevX, prevY) => {\n switch (cmd) {\n case PATH_M:\n case PATH_L: {\n if (cmd === PATH_M) {\n if (current) commit(current);\n current = beginContour();\n }\n pts!.push(coords[coordIdx], coords[coordIdx + 1]);\n aA!.push(anchorCounter);\n aB!.push(anchorCounter);\n aT!.push(0);\n prevAnchor = anchorCounter;\n anchorCounter++;\n break;\n }\n case PATH_Q: {\n const target = anchorCounter;\n const segStart = pts!.length / 2;\n const arcAccum: number[] = [];\n const total = flattenQuadraticWithArcLen(\n prevX, prevY,\n coords[coordIdx], coords[coordIdx + 1],\n coords[coordIdx + 2], coords[coordIdx + 3],\n tolerance, pts!, arcAccum,\n );\n pushCurveAnchors(segStart, arcAccum, total, target);\n prevAnchor = target;\n anchorCounter++;\n break;\n }\n case PATH_C: {\n const target = anchorCounter;\n const segStart = pts!.length / 2;\n const arcAccum: number[] = [];\n const total = flattenCubicWithArcLen(\n prevX, prevY,\n coords[coordIdx], coords[coordIdx + 1],\n coords[coordIdx + 2], coords[coordIdx + 3],\n coords[coordIdx + 4], coords[coordIdx + 5],\n tolerance, pts!, arcAccum,\n );\n pushCurveAnchors(segStart, arcAccum, total, target);\n prevAnchor = target;\n anchorCounter++;\n break;\n }\n case PATH_Z: {\n if (current) {\n current.closed = true;\n dropDuplicateClosingPoint();\n }\n break;\n }\n default:\n throw new Error(`extractPolylines: unknown command code ${cmd}`);\n }\n });\n\n if (current) commit(current);\n return out;\n}\n","/**\n * A station along a path: where it is at a fraction of its length, and which\n * way it is heading there.\n *\n * For anything positioned *along* geometry rather than beside it — a label on a\n * routed edge, a tick on a curve, a badge near an arrowhead. Curves are\n * flattened first, so the fraction is arc length along the drawn shape rather\n * than a curve parameter, which is what makes 0.5 look like the middle.\n */\nimport type { Vec2 } from 'core/geometry/polygonHitTestRect';\nimport type { Path } from 'core/geometry/path';\nimport { extractPolylines } from './tessellate/polyline';\n\nexport interface PathStation {\n point: Vec2;\n /** Unit vector along the path at `point`, pointing toward the end. */\n tangent: Vec2;\n}\n\nexport interface PointAlongPathOptions {\n /** Curve flattening tolerance, in world units. Default 0.5. */\n flattenTolerance?: number;\n}\n\n/**\n * Where `path` is at `t` of its total length, and its heading there.\n *\n * `t` is clamped to 0..1. Subpaths are measured in order and treated as one\n * run, the way a browser measures a whole `<path>`. Returns `null` for a path\n * with no points at all; a path of zero length answers at its single point,\n * heading along +X.\n */\nexport function pointAlongPath(\n path: Path,\n t: number,\n opts: PointAlongPathOptions = {},\n): PathStation | null {\n const polylines = extractPolylines(\n path,\n opts.flattenTolerance === undefined ? {} : { flattenTolerance: opts.flattenTolerance },\n );\n\n /** Every segment, in order, with the length it contributes. */\n const segments: { ax: number; ay: number; bx: number; by: number; len: number }[] = [];\n let total = 0;\n let first: Vec2 | undefined;\n for (const pl of polylines) {\n const count = pl.points.length / 2;\n if (count === 0) continue;\n first ??= { x: pl.points[0]!, y: pl.points[1]! };\n const last = pl.closed ? count : count - 1;\n for (let i = 0; i < last; i++) {\n const j = (i + 1) % count;\n const ax = pl.points[i * 2]!;\n const ay = pl.points[i * 2 + 1]!;\n const bx = pl.points[j * 2]!;\n const by = pl.points[j * 2 + 1]!;\n const len = Math.hypot(bx - ax, by - ay);\n if (len === 0) continue;\n segments.push({ ax, ay, bx, by, len });\n total += len;\n }\n }\n\n if (first === undefined) return null;\n if (segments.length === 0) return { point: first, tangent: { x: 1, y: 0 } };\n\n const target = Math.min(Math.max(t, 0), 1) * total;\n let walked = 0;\n for (const seg of segments) {\n if (walked + seg.len < target) {\n walked += seg.len;\n continue;\n }\n const u = (target - walked) / seg.len;\n return {\n point: { x: seg.ax + (seg.bx - seg.ax) * u, y: seg.ay + (seg.by - seg.ay) * u },\n tangent: { x: (seg.bx - seg.ax) / seg.len, y: (seg.by - seg.ay) / seg.len },\n };\n }\n\n // Float drift can leave `target` a hair past the last segment.\n const last = segments[segments.length - 1]!;\n return {\n point: { x: last.bx, y: last.by },\n tangent: { x: (last.bx - last.ax) / last.len, y: (last.by - last.ay) / last.len },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/features/simulation/types.ts","../src/features/simulation/createSimulation.ts","../src/interactions/actions/rotate/geometry.ts","../src/features/paths/tessellate/polyline.ts","../src/features/paths/pathAt.ts"],"names":["last"],"mappings":"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","file":"chunk-PNNZSYRD.js","sourcesContent":["/**\n * Minimal node interface for the simulation primitive. Matches d3-force's\n * node shape exactly so d3-force's bundled forces work without translation.\n *\n * Consumers extend this with arbitrary additional fields (id, label, etc.).\n */\nexport interface SimulationNode {\n x: number;\n y: number;\n vx?: number;\n vy?: number;\n /** Pin x to this value when non-null. The integrator skips x/vx for the node. */\n fx?: number | null;\n fy?: number | null;\n /** Array index, written by `initialize`. Some forces (e.g. forceLink) rely on it. */\n index?: number;\n}\n\n/**\n * Force protocol — contract-compatible with d3-force. A force is a function\n * called once per tick with the current alpha; it mutates `vx`/`vy` on nodes.\n * Optional `initialize` lets the force compute setup (link indices, etc.).\n */\nexport interface SimulationForce<TNode extends SimulationNode = SimulationNode> {\n (alpha: number): void;\n initialize?(nodes: TNode[], random?: () => number): void;\n}\n\n/** Options for `useSimulation`: everything {@link SimulationOptions} carries,\n * plus the loop's own callbacks and clock. */\nexport interface UseSimulationOptions<TNode extends SimulationNode>\n extends SimulationOptions<TNode> {\n /** Fired after each integration step. */\n onTick?: (nodes: TNode[]) => void;\n /** Fired once when the sim settles (alpha < alphaMin && alphaTarget === 0). */\n onEnd?: () => void;\n\n // Test injection (mirrors useAnimator):\n /** Optional rAF injection. Defaults to window.requestAnimationFrame. */\n requestFrame?: (cb: (t: number) => void) => number;\n cancelFrame?: (handle: number) => void;\n}\n\n/**\n * A force simulation over a set of nodes, with no clock of its own.\n *\n * Each tick applies every force and then integrates velocities, scaled by\n * `alpha` — a temperature that decays toward `alphaTarget` so the layout\n * settles instead of jittering forever. Raise `alphaTarget` to reheat it,\n * which is what a drag does.\n *\n * Nodes are mutated in place; the simulation holds the array, not a copy.\n *\n * Nothing here advances time. {@link Simulation} adds the frame loop; a caller\n * that wants the whole relaxation at once — a layout pass, a pre-warm, a test\n * — drives {@link SimulationCore.tick} itself.\n */\nexport interface SimulationCore<TNode extends SimulationNode> {\n readonly nodes: TNode[];\n\n setNodes(nodes: TNode[]): this;\n setForces(forces: SimulationForce<TNode>[]): this;\n\n alpha(): number;\n alpha(value: number): this;\n alphaTarget(): number;\n alphaTarget(value: number): this;\n alphaDecay(): number;\n alphaDecay(value: number): this;\n alphaMin(): number;\n alphaMin(value: number): this;\n velocityDecay(): number;\n velocityDecay(value: number): this;\n\n /**\n * Run the tick body synchronously `iterations` times. Does NOT fire\n * onTick or onEnd (matches d3-force). Used for offscreen pre-warm and tests.\n */\n tick(iterations?: number): this;\n\n isSettled(): boolean;\n}\n\n/** A {@link SimulationCore} running on a frame loop. */\nexport interface Simulation<TNode extends SimulationNode> extends SimulationCore<TNode> {\n /** Resume the RAF loop. If alpha < alphaMin, reset alpha to 1. */\n restart(): this;\n /** Cancel the RAF loop. Does not change alpha. */\n stop(): this;\n}\n\n/** What {@link SimulationCore} needs: the nodes, the forces acting on them,\n * and the cooling schedule. {@link UseSimulationOptions} adds the loop's. */\nexport interface SimulationOptions<TNode extends SimulationNode> {\n /** Mutable array of nodes. Kit + forces mutate vx/vy/x/y in place. */\n nodes: TNode[];\n /** Forces applied per tick. Each may implement `initialize` for setup. */\n forces?: SimulationForce<TNode>[];\n\n /** Initial alpha. Default 1. */\n alpha?: number;\n /** Settle threshold. When alpha drops below and alphaTarget is 0, onEnd fires. Default 0.001. */\n alphaMin?: number;\n /** Per-tick decay rate toward alphaTarget. Default 1 - 0.001^(1/300) ≈ 0.0228. */\n alphaDecay?: number;\n /** Target alpha. Set above alphaMin to keep sim warm (e.g. during drag). Default 0. */\n alphaTarget?: number;\n /** Friction multiplier on velocity per tick: vx *= (1 - velocityDecay). Default 0.4. */\n velocityDecay?: number;\n /** Handed to each force's `initialize`. Default `Math.random`; pass a seeded\n * source to make a run reproducible. */\n random?: () => number;\n}\n\n/** Default alpha decay: such that alpha drops from 1 to alphaMin (0.001) in 300 ticks. */\nexport const DEFAULT_ALPHA_DECAY = 1 - Math.pow(0.001, 1 / 300);\n/** Alpha below which a cooling simulation is considered settled. */\nexport const DEFAULT_ALPHA_MIN = 0.001;\n/** Fraction of velocity shed each tick — friction. Higher settles sooner and\n * overshoots less. */\nexport const DEFAULT_VELOCITY_DECAY = 0.4;\n","/**\n * The integrator, with no clock attached.\n *\n * Velocity-Verlet over a pluggable force list, contract-compatible with\n * d3-force so d3's own bundled forces drop in untranslated. Nothing here\n * advances time: `tick()` is the only thing that moves a node, and the caller\n * decides how often to call it. `useSimulation` calls it once a frame; a\n * layout pass calls it a few hundred times in one go and reads the result.\n *\n * Splitting it out is what lets a *pure* function run a relaxation — a React\n * hook cannot, and the alternative was a second integrator drifting away from\n * this one.\n */\nimport {\n DEFAULT_ALPHA_DECAY,\n DEFAULT_ALPHA_MIN,\n DEFAULT_VELOCITY_DECAY,\n type SimulationCore,\n type SimulationForce,\n type SimulationNode,\n type SimulationOptions,\n} from './types';\n\nexport function createSimulation<TNode extends SimulationNode>(\n opts: SimulationOptions<TNode>,\n): SimulationCore<TNode> {\n let nodes = opts.nodes;\n let forces = opts.forces ?? [];\n let alpha = opts.alpha ?? 1;\n let alphaMin = opts.alphaMin ?? DEFAULT_ALPHA_MIN;\n let alphaDecay = opts.alphaDecay ?? DEFAULT_ALPHA_DECAY;\n let alphaTarget = opts.alphaTarget ?? 0;\n let velocityDecay = opts.velocityDecay ?? DEFAULT_VELOCITY_DECAY;\n const random = opts.random ?? Math.random;\n\n /** `index` is what `forceLink` and friends address nodes by, and a d3 force\n * does `n.vx += …` without checking, so both must exist before the first\n * tick or the first tick produces NaN. */\n function prime(list: TNode[]): void {\n list.forEach((n, i) => {\n n.index = i;\n if (n.vx == null) n.vx = 0;\n if (n.vy == null) n.vy = 0;\n });\n }\n\n prime(nodes);\n for (const f of forces) f.initialize?.(nodes, random);\n\n function step(): void {\n alpha += (alphaTarget - alpha) * alphaDecay;\n for (const f of forces) f(alpha);\n\n const friction = 1 - velocityDecay;\n for (const n of nodes) {\n if (n.fx == null) {\n n.vx = (n.vx ?? 0) * friction;\n // A non-finite velocity — force overflow, or two nodes exactly\n // coincident — would reach the renderer as geometry and cost\n // pathological tessellation work without throwing anywhere.\n if (!Number.isFinite(n.vx)) n.vx = 0;\n n.x += n.vx;\n if (!Number.isFinite(n.x)) n.x = 0;\n } else {\n n.x = n.fx;\n n.vx = 0;\n }\n if (n.fy == null) {\n n.vy = (n.vy ?? 0) * friction;\n if (!Number.isFinite(n.vy)) n.vy = 0;\n n.y += n.vy;\n if (!Number.isFinite(n.y)) n.y = 0;\n } else {\n n.y = n.fy;\n n.vy = 0;\n }\n }\n }\n\n /* eslint-disable @typescript-eslint/no-explicit-any */\n const core: any = {\n get nodes() {\n return nodes;\n },\n setNodes(next: TNode[]) {\n nodes = next;\n prime(nodes);\n for (const f of forces) f.initialize?.(nodes, random);\n return core;\n },\n setForces(next: SimulationForce<TNode>[]) {\n const old = forces;\n forces = next;\n for (const f of next) {\n if (!old.includes(f)) f.initialize?.(nodes, random);\n }\n return core;\n },\n alpha(value?: number) {\n if (value === undefined) return alpha;\n alpha = value;\n return core;\n },\n alphaTarget(value?: number) {\n if (value === undefined) return alphaTarget;\n alphaTarget = value;\n return core;\n },\n alphaDecay(value?: number) {\n if (value === undefined) return alphaDecay;\n alphaDecay = value;\n return core;\n },\n alphaMin(value?: number) {\n if (value === undefined) return alphaMin;\n alphaMin = value;\n return core;\n },\n velocityDecay(value?: number) {\n if (value === undefined) return velocityDecay;\n velocityDecay = value;\n return core;\n },\n tick(iterations: number = 1) {\n for (let i = 0; i < iterations; i++) step();\n return core;\n },\n isSettled() {\n return alpha < alphaMin && alphaTarget === 0;\n },\n };\n /* eslint-enable @typescript-eslint/no-explicit-any */\n return core as SimulationCore<TNode>;\n}\n","import type { RotatedPose } from '../../gestures/types';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\n\n/** AABB center of an unrotated rect — the canonical rotation pivot. */\nexport function aabbCenter(bounds: Bounds): { x: number; y: number } {\n return { x: bounds.x + bounds.width / 2, y: bounds.y + bounds.height / 2 };\n}\n\n/** Rotate `(px, py)` by `angle` (radians) around `(cx, cy)`. */\nexport function rotatePoint(\n px: number,\n py: number,\n cx: number,\n cy: number,\n angle: number,\n): { x: number; y: number } {\n const c = Math.cos(angle);\n const s = Math.sin(angle);\n const dx = px - cx;\n const dy = py - cy;\n return { x: cx + dx * c - dy * s, y: cy + dx * s + dy * c };\n}\n\n/** Four corners of an unrotated rect, in TL/TR/BR/BL order. */\nexport function rectCorners(bounds: Bounds): { x: number; y: number }[] {\n return [\n { x: bounds.x, y: bounds.y },\n { x: bounds.x + bounds.width, y: bounds.y },\n { x: bounds.x + bounds.width, y: bounds.y + bounds.height },\n { x: bounds.x, y: bounds.y + bounds.height },\n ];\n}\n\n/** Four corners of a rotated rect (rotation around AABB center), in\n * TL/TR/BR/BL order. Useful for selection-overlay rendering. */\nexport function rotatedRectCorners(pose: RotatedPose): { x: number; y: number }[] {\n const c = aabbCenter(pose);\n return rectCorners(pose).map((p) => rotatePoint(p.x, p.y, c.x, c.y, pose.rotation));\n}\n\n/** Hit-test a world point against a rotated rect (rotation around AABB\n * center). Standard pattern: invert the rotation and AABB-test in the\n * rect's local frame. */\nexport function pointInRotatedRect(\n pose: RotatedPose,\n worldX: number,\n worldY: number,\n): boolean {\n const c = aabbCenter(pose);\n const local = rotatePoint(worldX, worldY, c.x, c.y, -pose.rotation);\n return (\n local.x >= pose.x &&\n local.x <= pose.x + pose.width &&\n local.y >= pose.y &&\n local.y <= pose.y + pose.height\n );\n}\n","import { forEachSegment, rectToContour } from '@weasel-js/geom';\nimport {\n PATH_M,\n PATH_L,\n PATH_Z,\n PATH_C,\n PATH_Q,\n DEFAULT_FLATTEN_TOLERANCE,\n flattenCubicWithArcLen,\n flattenQuadraticWithArcLen,\n} from '@weasel-js/geom';\nimport type { Path, PolygonPath, RectPath } from '../../../core/geometry/path';\n\nexport interface Polyline {\n /** Interleaved x,y vertices (length = 2 × point count). */\n points: number[];\n /** Whether the contour was closed (ends with Z, or is a RectPath). */\n closed: boolean;\n /** For each point, the previous anchor index. Anchor-aligned points set A === B. */\n anchorA?: Uint32Array;\n /** For each point, the next anchor index. */\n anchorB?: Uint32Array;\n /** For each point, the arc-length fraction along (A, B). 0 at anchor A; for anchor-aligned, set to 0. */\n anchorT?: Float32Array;\n /** Per-point stroke width, populated by the tessellator when the Stroke\n * carries `vertexWidths`. Undefined means uniform `Stroke.width`. */\n widths?: Float32Array;\n}\n\nexport interface ExtractOptions {\n flattenTolerance?: number;\n}\n\nexport function extractPolylines(path: Path, opts: ExtractOptions = {}): Polyline[] {\n if (path.kind === 'rect') return [extractRect(path)];\n return extractPolygon(path, opts);\n}\n\nfunction extractRect(p: RectPath): Polyline {\n const { x, y, width: w, height: h } = p;\n return {\n points: Array.from(rectToContour(x, y, w, h)),\n closed: true,\n anchorA: new Uint32Array([0, 1, 2, 3]),\n anchorB: new Uint32Array([0, 1, 2, 3]),\n anchorT: new Float32Array([0, 0, 0, 0]),\n };\n}\n\nfunction extractPolygon(p: PolygonPath, opts: ExtractOptions): Polyline[] {\n const tolerance = opts.flattenTolerance ?? DEFAULT_FLATTEN_TOLERANCE;\n const { commands, coords } = p;\n const out: Polyline[] = [];\n // Anchors are numbered globally (across all contours) in command-stream order.\n let anchorCounter = 0;\n\n // Builders for the current polyline.\n let pts: number[] | null = null;\n let aA: number[] | null = null;\n let aB: number[] | null = null;\n let aT: number[] | null = null;\n let current: Polyline | null = null;\n\n let prevAnchor = -1;\n\n const beginContour = (): Polyline => {\n pts = [];\n aA = [];\n aB = [];\n aT = [];\n const next: Polyline = { points: pts, closed: false };\n out.push(next);\n return next;\n };\n\n /**\n * A closed contour's last point repeating its first is redundant — Z already\n * says \"return to the start\" — and it is *harmful*: it leaves a zero-length\n * closing segment, which the stroker discards along with the wrap-around\n * join it should have carried, notching the ribbon at the contour's start.\n *\n * Every font outline serialized by opentype.js is written this way, as is a\n * great deal of hand-written and exported SVG, so this is the common case\n * rather than a defensive edge. Exact equality is the right test: the\n * duplicate is a re-emission of the same number, not an approach to it, and\n * a near-miss is a genuine (if tiny) segment the author asked for.\n */\n const dropDuplicateClosingPoint = (): void => {\n if (!pts || !aA || !aB || !aT) return;\n const n = pts.length / 2;\n if (n < 2) return;\n if (pts[0] !== pts[(n - 1) * 2] || pts[1] !== pts[(n - 1) * 2 + 1]) return;\n pts.length -= 2;\n aA.length -= 1;\n aB.length -= 1;\n aT.length -= 1;\n };\n\n const commit = (target: Polyline): void => {\n if (!pts || !aA || !aB || !aT) return;\n target.anchorA = new Uint32Array(aA);\n target.anchorB = new Uint32Array(aB);\n target.anchorT = new Float32Array(aT);\n };\n\n // Fill anchorA/B/T for each point a curve just appended: interior points\n // interpolate (prevAnchor → target), and the final point is pinned to the\n // target so the draw-time lerp returns anchor B's color exactly.\n const pushCurveAnchors = (segStart: number, arcAccum: number[], total: number, target: number): void => {\n for (let k = 0; k < arcAccum.length; k++) {\n aA!.push(prevAnchor);\n aB!.push(target);\n aT!.push(total > 0 ? arcAccum[k] / total : 0);\n }\n const lastIdx = (segStart + arcAccum.length) - 1;\n aA![lastIdx] = target;\n aB![lastIdx] = target;\n aT![lastIdx] = 0;\n };\n\n forEachSegment(commands, coords, (cmd, coordIdx, prevX, prevY) => {\n switch (cmd) {\n case PATH_M:\n case PATH_L: {\n if (cmd === PATH_M) {\n if (current) commit(current);\n current = beginContour();\n }\n pts!.push(coords[coordIdx], coords[coordIdx + 1]);\n aA!.push(anchorCounter);\n aB!.push(anchorCounter);\n aT!.push(0);\n prevAnchor = anchorCounter;\n anchorCounter++;\n break;\n }\n case PATH_Q: {\n const target = anchorCounter;\n const segStart = pts!.length / 2;\n const arcAccum: number[] = [];\n const total = flattenQuadraticWithArcLen(\n prevX, prevY,\n coords[coordIdx], coords[coordIdx + 1],\n coords[coordIdx + 2], coords[coordIdx + 3],\n tolerance, pts!, arcAccum,\n );\n pushCurveAnchors(segStart, arcAccum, total, target);\n prevAnchor = target;\n anchorCounter++;\n break;\n }\n case PATH_C: {\n const target = anchorCounter;\n const segStart = pts!.length / 2;\n const arcAccum: number[] = [];\n const total = flattenCubicWithArcLen(\n prevX, prevY,\n coords[coordIdx], coords[coordIdx + 1],\n coords[coordIdx + 2], coords[coordIdx + 3],\n coords[coordIdx + 4], coords[coordIdx + 5],\n tolerance, pts!, arcAccum,\n );\n pushCurveAnchors(segStart, arcAccum, total, target);\n prevAnchor = target;\n anchorCounter++;\n break;\n }\n case PATH_Z: {\n if (current) {\n current.closed = true;\n dropDuplicateClosingPoint();\n }\n break;\n }\n default:\n throw new Error(`extractPolylines: unknown command code ${cmd}`);\n }\n });\n\n if (current) commit(current);\n return out;\n}\n","/**\n * A station along a path: where it is at a fraction of its length, and which\n * way it is heading there.\n *\n * For anything positioned *along* geometry rather than beside it — a label on a\n * routed edge, a tick on a curve, a badge near an arrowhead. Curves are\n * flattened first, so the fraction is arc length along the drawn shape rather\n * than a curve parameter, which is what makes 0.5 look like the middle.\n */\nimport type { Vec2 } from 'core/geometry/vec2';\nimport type { Path } from 'core/geometry/path';\nimport { extractPolylines } from './tessellate/polyline';\n\nexport interface PathStation {\n point: Vec2;\n /** Unit vector along the path at `point`, pointing toward the end. */\n tangent: Vec2;\n}\n\nexport interface PointAlongPathOptions {\n /** Curve flattening tolerance, in world units. Default 0.5. */\n flattenTolerance?: number;\n}\n\n/**\n * Where `path` is at `t` of its total length, and its heading there.\n *\n * `t` is clamped to 0..1. Subpaths are measured in order and treated as one\n * run, the way a browser measures a whole `<path>`. Returns `null` for a path\n * with no points at all; a path of zero length answers at its single point,\n * heading along +X.\n */\nexport function pointAlongPath(\n path: Path,\n t: number,\n opts: PointAlongPathOptions = {},\n): PathStation | null {\n const polylines = extractPolylines(\n path,\n opts.flattenTolerance === undefined ? {} : { flattenTolerance: opts.flattenTolerance },\n );\n\n /** Every segment, in order, with the length it contributes. */\n const segments: { ax: number; ay: number; bx: number; by: number; len: number }[] = [];\n let total = 0;\n let first: Vec2 | undefined;\n for (const pl of polylines) {\n const count = pl.points.length / 2;\n if (count === 0) continue;\n first ??= { x: pl.points[0]!, y: pl.points[1]! };\n const last = pl.closed ? count : count - 1;\n for (let i = 0; i < last; i++) {\n const j = (i + 1) % count;\n const ax = pl.points[i * 2]!;\n const ay = pl.points[i * 2 + 1]!;\n const bx = pl.points[j * 2]!;\n const by = pl.points[j * 2 + 1]!;\n const len = Math.hypot(bx - ax, by - ay);\n if (len === 0) continue;\n segments.push({ ax, ay, bx, by, len });\n total += len;\n }\n }\n\n if (first === undefined) return null;\n if (segments.length === 0) return { point: first, tangent: { x: 1, y: 0 } };\n\n const target = Math.min(Math.max(t, 0), 1) * total;\n let walked = 0;\n for (const seg of segments) {\n if (walked + seg.len < target) {\n walked += seg.len;\n continue;\n }\n const u = (target - walked) / seg.len;\n return {\n point: { x: seg.ax + (seg.bx - seg.ax) * u, y: seg.ay + (seg.by - seg.ay) * u },\n tangent: { x: (seg.bx - seg.ax) / seg.len, y: (seg.by - seg.ay) / seg.len },\n };\n }\n\n // Float drift can leave `target` a hair past the last segment.\n const last = segments[segments.length - 1]!;\n return {\n point: { x: last.bx, y: last.by },\n tangent: { x: (last.bx - last.ax) / last.len, y: (last.by - last.ay) / last.len },\n };\n}\n"]}
|