@pascal-app/core 0.9.1 → 1.0.0-beta.1
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/README.md +17 -10
- package/dist/events/bus.d.ts +49 -2
- package/dist/events/bus.d.ts.map +1 -1
- package/dist/hooks/scene-registry/item-clip-registry.d.ts +18 -0
- package/dist/hooks/scene-registry/item-clip-registry.d.ts.map +1 -0
- package/dist/hooks/scene-registry/item-clip-registry.js +10 -0
- package/dist/hooks/scene-registry/scene-registry.d.ts +8 -1
- package/dist/hooks/scene-registry/scene-registry.d.ts.map +1 -1
- package/dist/hooks/scene-registry/scene-registry.js +27 -1
- package/dist/hooks/spatial-grid/floor-placed-elevation.d.ts +17 -1
- package/dist/hooks/spatial-grid/floor-placed-elevation.d.ts.map +1 -1
- package/dist/hooks/spatial-grid/floor-placed-elevation.js +61 -8
- package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts +135 -28
- package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts.map +1 -1
- package/dist/hooks/spatial-grid/spatial-grid-manager.js +427 -271
- package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts +46 -1
- package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts.map +1 -1
- package/dist/hooks/spatial-grid/spatial-grid-sync.js +208 -9
- package/dist/hooks/spatial-grid/support-host-id.d.ts +3 -0
- package/dist/hooks/spatial-grid/support-host-id.d.ts.map +1 -0
- package/dist/hooks/spatial-grid/support-host-id.js +2 -0
- package/dist/hooks/spatial-grid/support-host-patch.d.ts +51 -0
- package/dist/hooks/spatial-grid/support-host-patch.d.ts.map +1 -0
- package/dist/hooks/spatial-grid/support-host-patch.js +164 -0
- package/dist/index.d.ts +33 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +32 -10
- package/dist/lib/level-name.d.ts +4 -0
- package/dist/lib/level-name.d.ts.map +1 -0
- package/dist/lib/level-name.js +10 -0
- package/dist/lib/measurement-geometry.d.ts +23 -0
- package/dist/lib/measurement-geometry.d.ts.map +1 -0
- package/dist/lib/measurement-geometry.js +249 -0
- package/dist/lib/polygon-geometry.d.ts +0 -1
- package/dist/lib/polygon-geometry.d.ts.map +1 -1
- package/dist/lib/polygon-geometry.js +0 -18
- package/dist/lib/selection-proxy.d.ts +4 -0
- package/dist/lib/selection-proxy.d.ts.map +1 -0
- package/dist/lib/selection-proxy.js +12 -0
- package/dist/lib/slab-polygon.d.ts +31 -2
- package/dist/lib/slab-polygon.d.ts.map +1 -1
- package/dist/lib/slab-polygon.js +557 -31
- package/dist/lib/slots.d.ts +14 -0
- package/dist/lib/slots.d.ts.map +1 -0
- package/dist/lib/slots.js +26 -0
- package/dist/lib/space-detection.d.ts +40 -6
- package/dist/lib/space-detection.d.ts.map +1 -1
- package/dist/lib/space-detection.js +574 -192
- package/dist/lib/terrain-brush.d.ts +163 -0
- package/dist/lib/terrain-brush.d.ts.map +1 -0
- package/dist/lib/terrain-brush.js +359 -0
- package/dist/lib/terrain-codec.d.ts +51 -0
- package/dist/lib/terrain-codec.d.ts.map +1 -0
- package/dist/lib/terrain-codec.js +167 -0
- package/dist/lib/terrain-field.d.ts +150 -0
- package/dist/lib/terrain-field.d.ts.map +1 -0
- package/dist/lib/terrain-field.js +248 -0
- package/dist/lib/terrain-raycast.d.ts +44 -0
- package/dist/lib/terrain-raycast.d.ts.map +1 -0
- package/dist/lib/terrain-raycast.js +188 -0
- package/dist/lib/terrain-source.d.ts +60 -0
- package/dist/lib/terrain-source.d.ts.map +1 -0
- package/dist/lib/terrain-source.js +90 -0
- package/dist/lib/terrain-support.d.ts +60 -0
- package/dist/lib/terrain-support.d.ts.map +1 -0
- package/dist/lib/terrain-support.js +150 -0
- package/dist/lib/wall-distance.d.ts +60 -0
- package/dist/lib/wall-distance.d.ts.map +1 -0
- package/dist/lib/wall-distance.js +85 -0
- package/dist/lib/zone-quantities.d.ts +21 -0
- package/dist/lib/zone-quantities.d.ts.map +1 -0
- package/dist/lib/zone-quantities.js +428 -0
- package/dist/material-library.d.ts +28 -1
- package/dist/material-library.d.ts.map +1 -1
- package/dist/material-library.js +2233 -441
- package/dist/registry/handles.d.ts +91 -3
- package/dist/registry/handles.d.ts.map +1 -1
- package/dist/registry/index.d.ts +3 -3
- package/dist/registry/index.d.ts.map +1 -1
- package/dist/registry/index.js +1 -1
- package/dist/registry/registry.d.ts +46 -3
- package/dist/registry/registry.d.ts.map +1 -1
- package/dist/registry/registry.js +82 -1
- package/dist/registry/subtree.d.ts.map +1 -1
- package/dist/registry/subtree.js +8 -1
- package/dist/registry/types.d.ts +781 -39
- package/dist/registry/types.d.ts.map +1 -1
- package/dist/schema/index.d.ts +27 -8
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +23 -6
- package/dist/schema/material.d.ts +3 -2
- package/dist/schema/material.d.ts.map +1 -1
- package/dist/schema/material.js +7 -5
- package/dist/schema/nodes/box-vent.d.ts +2 -2
- package/dist/schema/nodes/cabinet.d.ts +536 -0
- package/dist/schema/nodes/cabinet.d.ts.map +1 -0
- package/dist/schema/nodes/cabinet.js +139 -0
- package/dist/schema/nodes/ceiling.d.ts +4 -3
- package/dist/schema/nodes/ceiling.d.ts.map +1 -1
- package/dist/schema/nodes/ceiling.js +11 -1
- package/dist/schema/nodes/chimney.d.ts +4 -4
- package/dist/schema/nodes/column.d.ts +4 -2
- package/dist/schema/nodes/column.d.ts.map +1 -1
- package/dist/schema/nodes/column.js +5 -0
- package/dist/schema/nodes/construction-dimension.d.ts +195 -0
- package/dist/schema/nodes/construction-dimension.d.ts.map +1 -0
- package/dist/schema/nodes/construction-dimension.js +151 -0
- package/dist/schema/nodes/cupola.d.ts +2 -2
- package/dist/schema/nodes/door.d.ts +42 -5
- package/dist/schema/nodes/door.d.ts.map +1 -1
- package/dist/schema/nodes/door.js +32 -0
- package/dist/schema/nodes/dormer.d.ts +8 -8
- package/dist/schema/nodes/dormer.js +1 -1
- package/dist/schema/nodes/downspout.d.ts +2 -2
- package/dist/schema/nodes/duct-fitting.d.ts +91 -0
- package/dist/schema/nodes/duct-fitting.d.ts.map +1 -0
- package/dist/schema/nodes/duct-fitting.js +92 -0
- package/dist/schema/nodes/duct-segment.d.ts +61 -0
- package/dist/schema/nodes/duct-segment.d.ts.map +1 -0
- package/dist/schema/nodes/duct-segment.js +73 -0
- package/dist/schema/nodes/duct-terminal.d.ts +58 -0
- package/dist/schema/nodes/duct-terminal.d.ts.map +1 -0
- package/dist/schema/nodes/duct-terminal.js +53 -0
- package/dist/schema/nodes/elevator.d.ts +3 -2
- package/dist/schema/nodes/elevator.d.ts.map +1 -1
- package/dist/schema/nodes/elevator.js +3 -0
- package/dist/schema/nodes/eyebrow-vent.d.ts +2 -2
- package/dist/schema/nodes/fence.d.ts +20 -2
- package/dist/schema/nodes/fence.d.ts.map +1 -1
- package/dist/schema/nodes/fence.js +33 -2
- package/dist/schema/nodes/gutter.d.ts +2 -2
- package/dist/schema/nodes/hvac-equipment.d.ts +64 -0
- package/dist/schema/nodes/hvac-equipment.d.ts.map +1 -0
- package/dist/schema/nodes/hvac-equipment.js +57 -0
- package/dist/schema/nodes/item.d.ts +9 -0
- package/dist/schema/nodes/item.d.ts.map +1 -1
- package/dist/schema/nodes/item.js +24 -0
- package/dist/schema/nodes/level.d.ts +2 -1
- package/dist/schema/nodes/level.d.ts.map +1 -1
- package/dist/schema/nodes/level.js +12 -31
- package/dist/schema/nodes/lineset.d.ts +42 -0
- package/dist/schema/nodes/lineset.d.ts.map +1 -0
- package/dist/schema/nodes/lineset.js +38 -0
- package/dist/schema/nodes/liquid-line.d.ts +34 -0
- package/dist/schema/nodes/liquid-line.d.ts.map +1 -0
- package/dist/schema/nodes/liquid-line.js +24 -0
- package/dist/schema/nodes/measurement.d.ts +306 -0
- package/dist/schema/nodes/measurement.d.ts.map +1 -0
- package/dist/schema/nodes/measurement.js +87 -0
- package/dist/schema/nodes/pipe-fitting.d.ts +56 -0
- package/dist/schema/nodes/pipe-fitting.d.ts.map +1 -0
- package/dist/schema/nodes/pipe-fitting.js +45 -0
- package/dist/schema/nodes/pipe-segment.d.ts +48 -0
- package/dist/schema/nodes/pipe-segment.d.ts.map +1 -0
- package/dist/schema/nodes/pipe-segment.js +36 -0
- package/dist/schema/nodes/pipe-trap.d.ts +43 -0
- package/dist/schema/nodes/pipe-trap.d.ts.map +1 -0
- package/dist/schema/nodes/pipe-trap.js +36 -0
- package/dist/schema/nodes/ridge-vent.d.ts +18 -3
- package/dist/schema/nodes/ridge-vent.d.ts.map +1 -1
- package/dist/schema/nodes/ridge-vent.js +221 -3
- package/dist/schema/nodes/roof-segment-shape.d.ts +90 -0
- package/dist/schema/nodes/roof-segment-shape.d.ts.map +1 -0
- package/dist/schema/nodes/roof-segment-shape.js +318 -0
- package/dist/schema/nodes/roof-segment-walls.d.ts +101 -0
- package/dist/schema/nodes/roof-segment-walls.d.ts.map +1 -0
- package/dist/schema/nodes/roof-segment-walls.js +330 -0
- package/dist/schema/nodes/roof-segment.d.ts +84 -8
- package/dist/schema/nodes/roof-segment.d.ts.map +1 -1
- package/dist/schema/nodes/roof-segment.js +290 -5
- package/dist/schema/nodes/roof.d.ts +8 -8
- package/dist/schema/nodes/shelf.d.ts +4 -2
- package/dist/schema/nodes/shelf.d.ts.map +1 -1
- package/dist/schema/nodes/shelf.js +8 -0
- package/dist/schema/nodes/site.d.ts +9 -0
- package/dist/schema/nodes/site.d.ts.map +1 -1
- package/dist/schema/nodes/site.js +8 -6
- package/dist/schema/nodes/skylight.d.ts +10 -10
- package/dist/schema/nodes/slab.d.ts +8 -2
- package/dist/schema/nodes/slab.d.ts.map +1 -1
- package/dist/schema/nodes/slab.js +18 -2
- package/dist/schema/nodes/solar-panel.d.ts +4 -4
- package/dist/schema/nodes/spawn.d.ts +1 -0
- package/dist/schema/nodes/spawn.d.ts.map +1 -1
- package/dist/schema/nodes/spawn.js +2 -0
- package/dist/schema/nodes/stair-segment.d.ts +4 -4
- package/dist/schema/nodes/stair.d.ts +16 -13
- package/dist/schema/nodes/stair.d.ts.map +1 -1
- package/dist/schema/nodes/stair.js +11 -1
- package/dist/schema/nodes/structural-grid.d.ts +27 -0
- package/dist/schema/nodes/structural-grid.d.ts.map +1 -0
- package/dist/schema/nodes/structural-grid.js +17 -0
- package/dist/schema/nodes/turbine-vent.d.ts +2 -2
- package/dist/schema/nodes/wall.d.ts +248 -6
- package/dist/schema/nodes/wall.d.ts.map +1 -1
- package/dist/schema/nodes/wall.js +266 -0
- package/dist/schema/nodes/window.d.ts +40 -3
- package/dist/schema/nodes/window.d.ts.map +1 -1
- package/dist/schema/nodes/window.js +30 -0
- package/dist/schema/nodes/zone.d.ts +22 -0
- package/dist/schema/nodes/zone.d.ts.map +1 -1
- package/dist/schema/nodes/zone.js +21 -0
- package/dist/schema/scene-material.d.ts +41 -0
- package/dist/schema/scene-material.d.ts.map +1 -0
- package/dist/schema/scene-material.js +9 -0
- package/dist/schema/terrain.d.ts +28 -0
- package/dist/schema/terrain.d.ts.map +1 -0
- package/dist/schema/terrain.js +30 -0
- package/dist/schema/types.d.ts +1300 -97
- package/dist/schema/types.d.ts.map +1 -1
- package/dist/schema/types.js +27 -0
- package/dist/services/__fixtures__/wall-plane-top-boundary-repro.d.ts +80 -0
- package/dist/services/__fixtures__/wall-plane-top-boundary-repro.d.ts.map +1 -0
- package/dist/services/__fixtures__/wall-plane-top-boundary-repro.js +89 -0
- package/dist/services/alignment-anchors.d.ts.map +1 -1
- package/dist/services/alignment-anchors.js +30 -1
- package/dist/services/alignment.d.ts +5 -0
- package/dist/services/alignment.d.ts.map +1 -1
- package/dist/services/alignment.js +2 -0
- package/dist/services/hosting.d.ts +8 -0
- package/dist/services/hosting.d.ts.map +1 -1
- package/dist/services/hosting.js +13 -4
- package/dist/services/index.d.ts +9 -2
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +9 -2
- package/dist/services/level-height.d.ts +27 -0
- package/dist/services/level-height.d.ts.map +1 -0
- package/dist/services/level-height.js +94 -0
- package/dist/services/opening-guides.d.ts +141 -0
- package/dist/services/opening-guides.d.ts.map +1 -0
- package/dist/services/opening-guides.js +267 -0
- package/dist/services/port-connectivity.d.ts +115 -0
- package/dist/services/port-connectivity.d.ts.map +1 -0
- package/dist/services/port-connectivity.js +300 -0
- package/dist/services/riser-diagram.d.ts +40 -0
- package/dist/services/riser-diagram.d.ts.map +1 -0
- package/dist/services/riser-diagram.js +110 -0
- package/dist/services/snap.d.ts +9 -1
- package/dist/services/snap.d.ts.map +1 -1
- package/dist/services/snap.js +21 -1
- package/dist/services/storey.d.ts +103 -0
- package/dist/services/storey.d.ts.map +1 -0
- package/dist/services/storey.js +296 -0
- package/dist/services/system-graph.d.ts +30 -0
- package/dist/services/system-graph.d.ts.map +1 -0
- package/dist/services/system-graph.js +164 -0
- package/dist/services/validate-dwv.d.ts +32 -0
- package/dist/services/validate-dwv.d.ts.map +1 -0
- package/dist/services/validate-dwv.js +118 -0
- package/dist/store/actions/node-actions.d.ts.map +1 -1
- package/dist/store/actions/node-actions.js +141 -4
- package/dist/store/history-control.d.ts +31 -0
- package/dist/store/history-control.d.ts.map +1 -1
- package/dist/store/history-control.js +130 -0
- package/dist/store/use-live-terrain.d.ts +65 -0
- package/dist/store/use-live-terrain.d.ts.map +1 -0
- package/dist/store/use-live-terrain.js +31 -0
- package/dist/store/use-live-transforms.d.ts +8 -0
- package/dist/store/use-live-transforms.d.ts.map +1 -1
- package/dist/store/use-scene.d.ts +47 -3
- package/dist/store/use-scene.d.ts.map +1 -1
- package/dist/store/use-scene.js +992 -55
- package/dist/systems/elevator/elevator-opening-system.d.ts +1 -0
- package/dist/systems/elevator/elevator-opening-system.d.ts.map +1 -1
- package/dist/systems/elevator/elevator-opening-system.js +27 -21
- package/dist/systems/elevator/elevator-service.d.ts +0 -2
- package/dist/systems/elevator/elevator-service.d.ts.map +1 -1
- package/dist/systems/elevator/elevator-service.js +2 -24
- package/dist/systems/fence/fence-centerline.d.ts +12 -0
- package/dist/systems/fence/fence-centerline.d.ts.map +1 -0
- package/dist/systems/fence/fence-centerline.js +37 -0
- package/dist/systems/fence/fence-spline.d.ts +39 -0
- package/dist/systems/fence/fence-spline.d.ts.map +1 -0
- package/dist/systems/fence/fence-spline.js +196 -0
- package/dist/systems/slab/slab-placement.d.ts +11 -0
- package/dist/systems/slab/slab-placement.d.ts.map +1 -0
- package/dist/systems/slab/slab-placement.js +14 -0
- package/dist/systems/slab/slab-support.d.ts +137 -0
- package/dist/systems/slab/slab-support.d.ts.map +1 -0
- package/dist/systems/slab/slab-support.js +557 -0
- package/dist/systems/stair/stair-footprint.d.ts.map +1 -1
- package/dist/systems/stair/stair-footprint.js +21 -11
- package/dist/systems/stair/stair-opening-preview.d.ts +1300 -505
- package/dist/systems/stair/stair-opening-preview.d.ts.map +1 -1
- package/dist/systems/stair/stair-opening-sync.d.ts.map +1 -1
- package/dist/systems/stair/stair-opening-sync.js +19 -33
- package/dist/systems/stair/stair-opening-system.d.ts.map +1 -1
- package/dist/systems/stair/stair-opening-system.js +32 -4
- package/dist/systems/stair/stair-rise.d.ts +22 -0
- package/dist/systems/stair/stair-rise.d.ts.map +1 -0
- package/dist/systems/stair/stair-rise.js +79 -0
- package/dist/systems/wall/wall-curve.d.ts +10 -0
- package/dist/systems/wall/wall-curve.d.ts.map +1 -1
- package/dist/systems/wall/wall-curve.js +1 -1
- package/dist/systems/wall/wall-mitering.d.ts.map +1 -1
- package/dist/systems/wall/wall-mitering.js +44 -8
- package/dist/systems/wall/wall-top.d.ts +40 -0
- package/dist/systems/wall/wall-top.d.ts.map +1 -0
- package/dist/systems/wall/wall-top.js +46 -0
- package/dist/utils/clone-scene-graph.d.ts +1 -0
- package/dist/utils/clone-scene-graph.d.ts.map +1 -1
- package/dist/utils/clone-scene-graph.js +56 -5
- package/dist/utils/heal-scene-graph.d.ts +18 -0
- package/dist/utils/heal-scene-graph.d.ts.map +1 -0
- package/dist/utils/heal-scene-graph.js +106 -0
- package/dist/validation/validate-build-json.d.ts +3 -0
- package/dist/validation/validate-build-json.d.ts.map +1 -1
- package/dist/validation/validate-build-json.js +90 -5
- package/package.json +4 -4
- package/dist/hooks/spatial-grid/floor-placed-elevation.test.d.ts +0 -2
- package/dist/hooks/spatial-grid/floor-placed-elevation.test.d.ts.map +0 -1
- package/dist/hooks/spatial-grid/floor-placed-elevation.test.js +0 -273
- package/dist/lib/space-detection-pause.test.d.ts +0 -2
- package/dist/lib/space-detection-pause.test.d.ts.map +0 -1
- package/dist/lib/space-detection-pause.test.js +0 -42
- package/dist/lib/space-detection.test.d.ts +0 -2
- package/dist/lib/space-detection.test.d.ts.map +0 -1
- package/dist/lib/space-detection.test.js +0 -77
- package/dist/registry/registry.test.d.ts +0 -2
- package/dist/registry/registry.test.d.ts.map +0 -1
- package/dist/registry/registry.test.js +0 -183
- package/dist/registry/relations-resolver.test.d.ts +0 -2
- package/dist/registry/relations-resolver.test.d.ts.map +0 -1
- package/dist/registry/relations-resolver.test.js +0 -183
- package/dist/registry/scene-api.test.d.ts +0 -2
- package/dist/registry/scene-api.test.d.ts.map +0 -1
- package/dist/registry/scene-api.test.js +0 -183
- package/dist/registry/subtree.test.d.ts +0 -2
- package/dist/registry/subtree.test.d.ts.map +0 -1
- package/dist/registry/subtree.test.js +0 -133
- package/dist/schema/asset-url.test.d.ts +0 -2
- package/dist/schema/asset-url.test.d.ts.map +0 -1
- package/dist/schema/asset-url.test.js +0 -134
- package/dist/services/alignment-anchors.test.d.ts +0 -2
- package/dist/services/alignment-anchors.test.d.ts.map +0 -1
- package/dist/services/alignment-anchors.test.js +0 -383
- package/dist/services/alignment.test.d.ts +0 -2
- package/dist/services/alignment.test.d.ts.map +0 -1
- package/dist/services/alignment.test.js +0 -92
- package/dist/services/drag-session.test.d.ts +0 -2
- package/dist/services/drag-session.test.d.ts.map +0 -1
- package/dist/services/drag-session.test.js +0 -219
- package/dist/services/hosting.test.d.ts +0 -2
- package/dist/services/hosting.test.d.ts.map +0 -1
- package/dist/services/hosting.test.js +0 -199
- package/dist/services/movement.test.d.ts +0 -2
- package/dist/services/movement.test.d.ts.map +0 -1
- package/dist/services/movement.test.js +0 -133
- package/dist/services/single-undo-dance.test.d.ts +0 -2
- package/dist/services/single-undo-dance.test.d.ts.map +0 -1
- package/dist/services/single-undo-dance.test.js +0 -210
- package/dist/services/snap.test.d.ts +0 -2
- package/dist/services/snap.test.d.ts.map +0 -1
- package/dist/services/snap.test.js +0 -95
- package/dist/store/actions/node-mutation-sanitize.test.d.ts +0 -2
- package/dist/store/actions/node-mutation-sanitize.test.d.ts.map +0 -1
- package/dist/store/actions/node-mutation-sanitize.test.js +0 -147
- package/dist/store/actions/reparent.test.d.ts +0 -2
- package/dist/store/actions/reparent.test.d.ts.map +0 -1
- package/dist/store/actions/reparent.test.js +0 -212
- package/dist/store/use-scene-elevator-migration.test.d.ts +0 -2
- package/dist/store/use-scene-elevator-migration.test.d.ts.map +0 -1
- package/dist/store/use-scene-elevator-migration.test.js +0 -109
- package/dist/systems/elevator/elevator-opening-sync.test.d.ts +0 -2
- package/dist/systems/elevator/elevator-opening-sync.test.d.ts.map +0 -1
- package/dist/systems/elevator/elevator-opening-sync.test.js +0 -146
- package/dist/systems/elevator/elevator-runtime.test.d.ts +0 -2
- package/dist/systems/elevator/elevator-runtime.test.d.ts.map +0 -1
- package/dist/systems/elevator/elevator-runtime.test.js +0 -64
- package/dist/systems/stair/stair-opening-preview.test.d.ts +0 -2
- package/dist/systems/stair/stair-opening-preview.test.d.ts.map +0 -1
- package/dist/systems/stair/stair-opening-preview.test.js +0 -80
- package/dist/systems/stair/stair-opening-sync.test.d.ts +0 -2
- package/dist/systems/stair/stair-opening-sync.test.d.ts.map +0 -1
- package/dist/systems/stair/stair-opening-sync.test.js +0 -446
- package/dist/utils/clone-scene-graph.test.d.ts +0 -2
- package/dist/utils/clone-scene-graph.test.d.ts.map +0 -1
- package/dist/utils/clone-scene-graph.test.js +0 -59
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
import { nodeRegistry } from '../registry';
|
|
2
|
+
/** Distance (meters) under which two ports count as the same joint. Joints
|
|
3
|
+
* formed by placement snapping coincide to sub-millimeter; 5 cm leaves
|
|
4
|
+
* generous slack for grid-snapped hand placement without false matches. */
|
|
5
|
+
const COINCIDENT_EPS_M = 0.05;
|
|
6
|
+
/** Below this (meters) a propagated delta is treated as zero — stops the
|
|
7
|
+
* walk from chasing sub-millimeter perpendicular residue. */
|
|
8
|
+
const DELTA_EPS_M = 1e-4;
|
|
9
|
+
const PROPAGATION_EPS_M = 1e-9;
|
|
10
|
+
function portsOf(node) {
|
|
11
|
+
return nodeRegistry.get(node.type)?.ports?.(node);
|
|
12
|
+
}
|
|
13
|
+
/** A node's distribution role from the registry (run / fitting / …). */
|
|
14
|
+
function roleOf(node) {
|
|
15
|
+
return nodeRegistry.get(node.type)?.distributionRole;
|
|
16
|
+
}
|
|
17
|
+
function distSq(a, b) {
|
|
18
|
+
const dx = a[0] - b[0];
|
|
19
|
+
const dy = a[1] - b[1];
|
|
20
|
+
const dz = a[2] - b[2];
|
|
21
|
+
return dx * dx + dy * dy + dz * dz;
|
|
22
|
+
}
|
|
23
|
+
/** Two ports mate when they coincide AND don't cross incompatible systems
|
|
24
|
+
* (a supply duct and a waste pipe that merely touch must not fuse). */
|
|
25
|
+
function portsMate(a, b, epsSq) {
|
|
26
|
+
if (distSq(a.position, b.position) > epsSq)
|
|
27
|
+
return false;
|
|
28
|
+
if (a.system && b.system && a.system !== b.system)
|
|
29
|
+
return false;
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Snapshot the joint graph reachable from `movedNode`'s ports, taken at the
|
|
34
|
+
* start of a move/resize. Call once before the drag; feed the result to
|
|
35
|
+
* `resolveConnectivityUpdates` on every frame.
|
|
36
|
+
*
|
|
37
|
+
* Only `run`-role partners (segments) and `fitting`-role partners are walked —
|
|
38
|
+
* terminals and equipment usually mount to a surface and shouldn't be yanked
|
|
39
|
+
* off it when an adjacent fitting nudges. Fittings that declare
|
|
40
|
+
* `portConnectivityFollow: false` are anchored fixtures (e.g. pipe-trap) and
|
|
41
|
+
* are skipped, so a connected run stretches against them instead.
|
|
42
|
+
*/
|
|
43
|
+
export function analyzePortConnectivity(movedNode, nodes) {
|
|
44
|
+
const epsSq = COINCIDENT_EPS_M * COINCIDENT_EPS_M;
|
|
45
|
+
const movedPorts = portsOf(movedNode) ?? [];
|
|
46
|
+
const startMovedPorts = {};
|
|
47
|
+
for (const p of movedPorts)
|
|
48
|
+
startMovedPorts[p.id] = p.position;
|
|
49
|
+
// Candidate partners: every run + every following fitting in the scene.
|
|
50
|
+
const candidates = [];
|
|
51
|
+
for (const other of Object.values(nodes)) {
|
|
52
|
+
if (!other || other.id === movedNode.id)
|
|
53
|
+
continue;
|
|
54
|
+
const role = roleOf(other);
|
|
55
|
+
if (role !== 'run' && role !== 'fitting')
|
|
56
|
+
continue;
|
|
57
|
+
if (role === 'fitting' && nodeRegistry.get(other.type)?.portConnectivityFollow === false) {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
const ports = portsOf(other);
|
|
61
|
+
if (!ports)
|
|
62
|
+
continue;
|
|
63
|
+
const startPath = role === 'run'
|
|
64
|
+
? other.path?.map((p) => [...p])
|
|
65
|
+
: undefined;
|
|
66
|
+
if (role === 'run' && (!startPath || startPath.length < 2))
|
|
67
|
+
continue;
|
|
68
|
+
const startPosition = role === 'fitting'
|
|
69
|
+
? (() => {
|
|
70
|
+
const pos = other.position;
|
|
71
|
+
return pos ? [pos[0], pos[1], pos[2]] : undefined;
|
|
72
|
+
})()
|
|
73
|
+
: undefined;
|
|
74
|
+
if (role === 'fitting' && !startPosition)
|
|
75
|
+
continue;
|
|
76
|
+
candidates.push({ id: other.id, role, ports, startPath, startPosition });
|
|
77
|
+
}
|
|
78
|
+
// Walk outward from the moved node, collecting every node reachable through
|
|
79
|
+
// coincident ports. The adjacency records each port's mates so the resolver
|
|
80
|
+
// can replay the same edges with live deltas.
|
|
81
|
+
const adjacency = {};
|
|
82
|
+
const addEdge = (nodeId, portId, mate) => {
|
|
83
|
+
const byPort = adjacency[nodeId] ?? {};
|
|
84
|
+
adjacency[nodeId] = byPort;
|
|
85
|
+
const mates = byPort[portId] ?? [];
|
|
86
|
+
byPort[portId] = mates;
|
|
87
|
+
mates.push(mate);
|
|
88
|
+
};
|
|
89
|
+
const graph = {};
|
|
90
|
+
const visited = new Set([movedNode.id]);
|
|
91
|
+
// Seed: the moved node's own ports.
|
|
92
|
+
const queue = [{ id: movedNode.id, ports: movedPorts }];
|
|
93
|
+
while (queue.length > 0) {
|
|
94
|
+
const { id, ports } = queue.shift();
|
|
95
|
+
for (const port of ports) {
|
|
96
|
+
for (const cand of candidates) {
|
|
97
|
+
if (cand.id === id)
|
|
98
|
+
continue;
|
|
99
|
+
for (const cp of cand.ports) {
|
|
100
|
+
if (!portsMate(port, cp, epsSq))
|
|
101
|
+
continue;
|
|
102
|
+
addEdge(id, port.id, { nodeId: cand.id, portId: cp.id });
|
|
103
|
+
addEdge(cand.id, cp.id, { nodeId: id, portId: port.id });
|
|
104
|
+
if (!visited.has(cand.id)) {
|
|
105
|
+
visited.add(cand.id);
|
|
106
|
+
graph[cand.id] = cand;
|
|
107
|
+
queue.push({ id: cand.id, ports: cand.ports });
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
const connections = Object.values(graph).map((g) => g.role === 'fitting'
|
|
114
|
+
? { kind: 'rigid-node', nodeId: g.id, startPosition: g.startPosition }
|
|
115
|
+
: { kind: 'run', nodeId: g.id, startPath: g.startPath });
|
|
116
|
+
return {
|
|
117
|
+
movedNodeId: movedNode.id,
|
|
118
|
+
startMovedPorts,
|
|
119
|
+
graph,
|
|
120
|
+
adjacency,
|
|
121
|
+
connections,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
function add(a, b) {
|
|
125
|
+
return [a[0] + b[0], a[1] + b[1], a[2] + b[2]];
|
|
126
|
+
}
|
|
127
|
+
function sub(a, b) {
|
|
128
|
+
return [a[0] - b[0], a[1] - b[1], a[2] - b[2]];
|
|
129
|
+
}
|
|
130
|
+
function lenSq(v) {
|
|
131
|
+
return v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
|
|
132
|
+
}
|
|
133
|
+
/** Split `delta` into the component along unit `axis` and the remainder. */
|
|
134
|
+
function decompose(delta, axis) {
|
|
135
|
+
const dot = delta[0] * axis[0] + delta[1] * axis[1] + delta[2] * axis[2];
|
|
136
|
+
const parallel = [axis[0] * dot, axis[1] * dot, axis[2] * dot];
|
|
137
|
+
return { parallel, perp: sub(delta, parallel) };
|
|
138
|
+
}
|
|
139
|
+
function scale(v, scalar) {
|
|
140
|
+
return [v[0] * scalar, v[1] * scalar, v[2] * scalar];
|
|
141
|
+
}
|
|
142
|
+
function average(deltas) {
|
|
143
|
+
const sum = deltas.reduce((acc, delta) => add(acc, delta), [0, 0, 0]);
|
|
144
|
+
return scale(sum, 1 / deltas.length);
|
|
145
|
+
}
|
|
146
|
+
function nearlyEqual(a, b) {
|
|
147
|
+
return lenSq(sub(a, b)) <= DELTA_EPS_M * DELTA_EPS_M;
|
|
148
|
+
}
|
|
149
|
+
function propagationEqual(a, b) {
|
|
150
|
+
return lenSq(sub(a, b)) <= PROPAGATION_EPS_M * PROPAGATION_EPS_M;
|
|
151
|
+
}
|
|
152
|
+
function effectivePortDeltas(constraints) {
|
|
153
|
+
return Object.fromEntries(Object.entries(constraints).map(([portId, bySource]) => [
|
|
154
|
+
portId,
|
|
155
|
+
average(Object.values(bySource)),
|
|
156
|
+
]));
|
|
157
|
+
}
|
|
158
|
+
/** Unit direction of the run's segment adjacent to its `start` / `end` tip. */
|
|
159
|
+
function endpointAxis(path, portId) {
|
|
160
|
+
const n = path.length;
|
|
161
|
+
const [a, b] = portId === 'start' ? [path[1], path[0]] : [path[n - 2], path[n - 1]];
|
|
162
|
+
const dir = sub(b, a);
|
|
163
|
+
const l2 = lenSq(dir);
|
|
164
|
+
if (l2 < 1e-12)
|
|
165
|
+
return [0, 0, 0];
|
|
166
|
+
const l = Math.sqrt(l2);
|
|
167
|
+
return [dir[0] / l, dir[1] / l, dir[2] / l];
|
|
168
|
+
}
|
|
169
|
+
function runPathFromSinglePortDelta(startPath, portId, delta) {
|
|
170
|
+
const nearIdx = portId === 'start' ? 0 : startPath.length - 1;
|
|
171
|
+
const axis = endpointAxis(startPath, portId);
|
|
172
|
+
const { parallel, perp } = decompose(delta, axis);
|
|
173
|
+
const path = startPath.map((p) => add(p, perp));
|
|
174
|
+
path[nearIdx] = add(path[nearIdx], parallel);
|
|
175
|
+
return path;
|
|
176
|
+
}
|
|
177
|
+
function runEndpointDeltas(startPath, path) {
|
|
178
|
+
return {
|
|
179
|
+
start: sub(path[0], startPath[0]),
|
|
180
|
+
end: sub(path[path.length - 1], startPath[startPath.length - 1]),
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
function runPathFromPortDeltas(startPath, portDeltas) {
|
|
184
|
+
const startDelta = portDeltas.start;
|
|
185
|
+
const endDelta = portDeltas.end;
|
|
186
|
+
if (startDelta && endDelta) {
|
|
187
|
+
if (startPath.length === 2) {
|
|
188
|
+
return [add(startPath[0], startDelta), add(startPath[1], endDelta)];
|
|
189
|
+
}
|
|
190
|
+
if (nearlyEqual(startDelta, endDelta)) {
|
|
191
|
+
return startPath.map((p) => add(p, startDelta));
|
|
192
|
+
}
|
|
193
|
+
const startParts = decompose(startDelta, endpointAxis(startPath, 'start'));
|
|
194
|
+
const endParts = decompose(endDelta, endpointAxis(startPath, 'end'));
|
|
195
|
+
const commonPerp = average([startParts.perp, endParts.perp]);
|
|
196
|
+
const path = startPath.map((p) => add(p, commonPerp));
|
|
197
|
+
path[0] = add(path[0], startParts.parallel);
|
|
198
|
+
path[path.length - 1] = add(path[path.length - 1], endParts.parallel);
|
|
199
|
+
return path;
|
|
200
|
+
}
|
|
201
|
+
return runPathFromSinglePortDelta(startPath, startDelta ? 'start' : 'end', (startDelta ?? endDelta));
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Given the moved node in its live (in-drag) transform, produce the patches
|
|
205
|
+
* that keep every connected node attached. `previewNode` is the moved node
|
|
206
|
+
* with its current drag position/rotation applied so its ports recompute.
|
|
207
|
+
*
|
|
208
|
+
* Walks the snapshotted graph, propagating each port delta outward: fittings
|
|
209
|
+
* translate rigidly, runs stretch along their axis and translate across it
|
|
210
|
+
* (never skew when driven from one end), and effective port movement carries on
|
|
211
|
+
* to neighbouring joints. Port-level output guards bound cycles while still
|
|
212
|
+
* allowing a looped/shared run to accept constraints at both endpoints.
|
|
213
|
+
*/
|
|
214
|
+
export function resolveConnectivityUpdates(connectivity, previewNode) {
|
|
215
|
+
const { graph, adjacency, startMovedPorts, movedNodeId } = connectivity;
|
|
216
|
+
if (Object.keys(graph).length === 0)
|
|
217
|
+
return [];
|
|
218
|
+
const newPorts = portsOf(previewNode) ?? [];
|
|
219
|
+
const newMovedPos = {};
|
|
220
|
+
for (const p of newPorts)
|
|
221
|
+
newMovedPos[p.id] = p.position;
|
|
222
|
+
// Each queue item drives a node's port by a delta ("this collar / endpoint
|
|
223
|
+
// must move by this much").
|
|
224
|
+
const queue = [];
|
|
225
|
+
const results = {};
|
|
226
|
+
const constrainedPorts = {};
|
|
227
|
+
const propagatedPorts = {};
|
|
228
|
+
const enqueueMates = (nodeId, portId, delta) => {
|
|
229
|
+
const byPort = propagatedPorts[nodeId] ?? {};
|
|
230
|
+
propagatedPorts[nodeId] = byPort;
|
|
231
|
+
const previous = byPort[portId];
|
|
232
|
+
if (previous && propagationEqual(previous, delta))
|
|
233
|
+
return;
|
|
234
|
+
byPort[portId] = delta;
|
|
235
|
+
for (const mate of adjacency[nodeId]?.[portId] ?? []) {
|
|
236
|
+
if (mate.nodeId === movedNodeId)
|
|
237
|
+
continue;
|
|
238
|
+
queue.push({
|
|
239
|
+
nodeId: mate.nodeId,
|
|
240
|
+
portId: mate.portId,
|
|
241
|
+
delta,
|
|
242
|
+
sourceKey: `${nodeId}:${portId}`,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
const acceptPortDelta = (nodeId, portId, sourceKey, delta) => {
|
|
247
|
+
const byPort = constrainedPorts[nodeId] ?? {};
|
|
248
|
+
constrainedPorts[nodeId] = byPort;
|
|
249
|
+
const bySource = byPort[portId] ?? {};
|
|
250
|
+
byPort[portId] = bySource;
|
|
251
|
+
const existing = bySource[sourceKey];
|
|
252
|
+
if (existing && propagationEqual(existing, delta)) {
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
255
|
+
bySource[sourceKey] = delta;
|
|
256
|
+
return true;
|
|
257
|
+
};
|
|
258
|
+
// Seed from the moved node's live port deltas.
|
|
259
|
+
for (const [portId, start] of Object.entries(startMovedPorts)) {
|
|
260
|
+
const now = newMovedPos[portId];
|
|
261
|
+
if (!now)
|
|
262
|
+
continue;
|
|
263
|
+
const delta = sub(now, start);
|
|
264
|
+
if (lenSq(delta) <= DELTA_EPS_M * DELTA_EPS_M)
|
|
265
|
+
continue;
|
|
266
|
+
enqueueMates(movedNodeId, portId, delta);
|
|
267
|
+
}
|
|
268
|
+
while (queue.length > 0) {
|
|
269
|
+
const { nodeId, portId, delta, sourceKey } = queue.shift();
|
|
270
|
+
const node = graph[nodeId];
|
|
271
|
+
if (!node)
|
|
272
|
+
continue;
|
|
273
|
+
if (!acceptPortDelta(nodeId, portId, sourceKey, delta))
|
|
274
|
+
continue;
|
|
275
|
+
const portDeltas = effectivePortDeltas(constrainedPorts[nodeId]);
|
|
276
|
+
if (node.role === 'fitting') {
|
|
277
|
+
const start = node.startPosition;
|
|
278
|
+
const effectiveDelta = average(Object.values(portDeltas));
|
|
279
|
+
results[nodeId] = {
|
|
280
|
+
id: nodeId,
|
|
281
|
+
data: { position: add(start, effectiveDelta) },
|
|
282
|
+
};
|
|
283
|
+
// Rigid: every collar carries the effective body translation onward.
|
|
284
|
+
for (const p of node.ports) {
|
|
285
|
+
enqueueMates(nodeId, p.id, effectiveDelta);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
else {
|
|
289
|
+
const startPath = node.startPath;
|
|
290
|
+
const path = runPathFromPortDeltas(startPath, portDeltas);
|
|
291
|
+
results[nodeId] = { id: nodeId, data: { path } };
|
|
292
|
+
for (const [nextPortId, nextDelta] of Object.entries(runEndpointDeltas(startPath, path))) {
|
|
293
|
+
if (lenSq(nextDelta) <= DELTA_EPS_M * DELTA_EPS_M)
|
|
294
|
+
continue;
|
|
295
|
+
enqueueMates(nodeId, nextPortId, nextDelta);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return Object.values(results);
|
|
300
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { AnyNode, AnyNodeId } from '../schema';
|
|
2
|
+
/** A 3D level-local point (meters) projected to 2D iso screen space.
|
|
3
|
+
* Screen Y grows DOWNWARD (SVG convention), so higher elevation → lower
|
|
4
|
+
* screen Y. */
|
|
5
|
+
export declare function projectIso(x: number, y: number, z: number): [number, number];
|
|
6
|
+
export type RiserLine = {
|
|
7
|
+
/** Projected endpoints in iso screen space. */
|
|
8
|
+
from: [number, number];
|
|
9
|
+
to: [number, number];
|
|
10
|
+
system: 'waste' | 'vent';
|
|
11
|
+
/** Nominal size in inches. */
|
|
12
|
+
diameter: number;
|
|
13
|
+
/** True for a (near-)vertical run — drawn solid/bold as a stack. */
|
|
14
|
+
vertical: boolean;
|
|
15
|
+
/** Source node, so the editor can link selection. */
|
|
16
|
+
nodeId: AnyNodeId;
|
|
17
|
+
};
|
|
18
|
+
export type RiserMarker = {
|
|
19
|
+
point: [number, number];
|
|
20
|
+
kind: 'trap' | 'vent-termination' | 'fitting';
|
|
21
|
+
label: string;
|
|
22
|
+
nodeId: AnyNodeId;
|
|
23
|
+
};
|
|
24
|
+
export type RiserDiagram = {
|
|
25
|
+
lines: RiserLine[];
|
|
26
|
+
markers: RiserMarker[];
|
|
27
|
+
/** Bounding box of all projected geometry, screen space. */
|
|
28
|
+
bounds: {
|
|
29
|
+
minX: number;
|
|
30
|
+
minY: number;
|
|
31
|
+
maxX: number;
|
|
32
|
+
maxY: number;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Build the riser diagram for the whole scene. Returns null when there's
|
|
37
|
+
* no DWV geometry to draw.
|
|
38
|
+
*/
|
|
39
|
+
export declare function buildRiserDiagram(nodes: Readonly<Record<AnyNodeId, AnyNode>>): RiserDiagram | null;
|
|
40
|
+
//# sourceMappingURL=riser-diagram.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"riser-diagram.d.ts","sourceRoot":"","sources":["../../src/services/riser-diagram.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAiBnD;;gBAEgB;AAChB,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAI5E;AAED,MAAM,MAAM,SAAS,GAAG;IACtB,+CAA+C;IAC/C,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACtB,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACpB,MAAM,EAAE,OAAO,GAAG,MAAM,CAAA;IACxB,8BAA8B;IAC9B,QAAQ,EAAE,MAAM,CAAA;IAChB,oEAAoE;IACpE,QAAQ,EAAE,OAAO,CAAA;IACjB,qDAAqD;IACrD,MAAM,EAAE,SAAS,CAAA;CAClB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACvB,IAAI,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS,CAAA;IAC7C,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,SAAS,CAAA;CAClB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,SAAS,EAAE,CAAA;IAClB,OAAO,EAAE,WAAW,EAAE,CAAA;IACtB,4DAA4D;IAC5D,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CACnE,CAAA;AAcD;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,GAC1C,YAAY,GAAG,IAAI,CAuErB"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Riser diagram (plumbing isometric) — the conventional way DWV systems
|
|
3
|
+
* are drawn for permit: the drain/vent tree projected to a 30° iso so
|
|
4
|
+
* vertical stacks read as vertical and horizontal runs lean off at 30°,
|
|
5
|
+
* annotated with size + slope and vent terminations.
|
|
6
|
+
*
|
|
7
|
+
* This is a pure projector: it turns the scene's DWV nodes into 2D
|
|
8
|
+
* drawables (level-independent, no rendering). The editor draws the
|
|
9
|
+
* result as SVG. Air/refrigerant nodes are ignored — riser diagrams are
|
|
10
|
+
* a plumbing convention.
|
|
11
|
+
*/
|
|
12
|
+
const COS30 = Math.cos(Math.PI / 6);
|
|
13
|
+
const SIN30 = Math.sin(Math.PI / 6);
|
|
14
|
+
/** A 3D level-local point (meters) projected to 2D iso screen space.
|
|
15
|
+
* Screen Y grows DOWNWARD (SVG convention), so higher elevation → lower
|
|
16
|
+
* screen Y. */
|
|
17
|
+
export function projectIso(x, y, z) {
|
|
18
|
+
const sx = (x - z) * COS30;
|
|
19
|
+
const sy = (x + z) * SIN30 - y;
|
|
20
|
+
return [sx, sy];
|
|
21
|
+
}
|
|
22
|
+
/** Elevation gain per horizontal meter under which a leg is "vertical". */
|
|
23
|
+
const VERTICAL_EPS = 4; // dy/dxz ratio: steeper than this reads as a stack
|
|
24
|
+
function legIsVertical(a, b) {
|
|
25
|
+
const horizontal = Math.hypot(b[0] - a[0], b[2] - a[2]);
|
|
26
|
+
const vertical = Math.abs(b[1] - a[1]);
|
|
27
|
+
if (horizontal < 1e-4)
|
|
28
|
+
return true;
|
|
29
|
+
return vertical / horizontal > VERTICAL_EPS;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Build the riser diagram for the whole scene. Returns null when there's
|
|
33
|
+
* no DWV geometry to draw.
|
|
34
|
+
*/
|
|
35
|
+
export function buildRiserDiagram(nodes) {
|
|
36
|
+
const lines = [];
|
|
37
|
+
const markers = [];
|
|
38
|
+
let minX = Infinity;
|
|
39
|
+
let minY = Infinity;
|
|
40
|
+
let maxX = -Infinity;
|
|
41
|
+
let maxY = -Infinity;
|
|
42
|
+
const grow = (p) => {
|
|
43
|
+
if (p[0] < minX)
|
|
44
|
+
minX = p[0];
|
|
45
|
+
if (p[1] < minY)
|
|
46
|
+
minY = p[1];
|
|
47
|
+
if (p[0] > maxX)
|
|
48
|
+
maxX = p[0];
|
|
49
|
+
if (p[1] > maxY)
|
|
50
|
+
maxY = p[1];
|
|
51
|
+
};
|
|
52
|
+
for (const node of Object.values(nodes)) {
|
|
53
|
+
if (!node)
|
|
54
|
+
continue;
|
|
55
|
+
if (node.type === 'pipe-segment') {
|
|
56
|
+
const path = node.path;
|
|
57
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
58
|
+
const a = path[i];
|
|
59
|
+
const b = path[i + 1];
|
|
60
|
+
const from = projectIso(a[0], a[1], a[2]);
|
|
61
|
+
const to = projectIso(b[0], b[1], b[2]);
|
|
62
|
+
grow(from);
|
|
63
|
+
grow(to);
|
|
64
|
+
lines.push({
|
|
65
|
+
from,
|
|
66
|
+
to,
|
|
67
|
+
system: node.system,
|
|
68
|
+
diameter: node.diameter,
|
|
69
|
+
vertical: legIsVertical(a, b),
|
|
70
|
+
nodeId: node.id,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
// Vent runs that end above everything are vent terminations
|
|
74
|
+
// (through-roof). Tag the highest endpoint of a vent run.
|
|
75
|
+
if (node.system === 'vent') {
|
|
76
|
+
const top = path.reduce((hi, p) => (p[1] > hi[1] ? p : hi), path[0]);
|
|
77
|
+
const pt = projectIso(top[0], top[1], top[2]);
|
|
78
|
+
markers.push({
|
|
79
|
+
point: pt,
|
|
80
|
+
kind: 'vent-termination',
|
|
81
|
+
label: `${node.diameter}" VTR`,
|
|
82
|
+
nodeId: node.id,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
else if (node.type === 'pipe-trap') {
|
|
87
|
+
const pt = projectIso(node.position[0], node.position[1], node.position[2]);
|
|
88
|
+
grow(pt);
|
|
89
|
+
markers.push({
|
|
90
|
+
point: pt,
|
|
91
|
+
kind: 'trap',
|
|
92
|
+
label: `${node.diameter}" P-trap`,
|
|
93
|
+
nodeId: node.id,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
else if (node.type === 'pipe-fitting') {
|
|
97
|
+
const pt = projectIso(node.position[0], node.position[1], node.position[2]);
|
|
98
|
+
grow(pt);
|
|
99
|
+
markers.push({
|
|
100
|
+
point: pt,
|
|
101
|
+
kind: 'fitting',
|
|
102
|
+
label: node.fittingType,
|
|
103
|
+
nodeId: node.id,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (lines.length === 0 && markers.length === 0)
|
|
108
|
+
return null;
|
|
109
|
+
return { lines, markers, bounds: { minX, minY, maxX, maxY } };
|
|
110
|
+
}
|
package/dist/services/snap.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ export type Vec2 = readonly [number, number];
|
|
|
12
12
|
export type Vec3 = readonly [number, number, number];
|
|
13
13
|
/** Default planar grid spacing in meters. Matches the editor's wall tool. */
|
|
14
14
|
export declare const DEFAULT_GRID_STEP = 0.25;
|
|
15
|
-
/** Default angle-snap step — π/12 = 15°.
|
|
15
|
+
/** Default angle-snap step — π/12 = 15°. */
|
|
16
16
|
export declare const DEFAULT_ANGLE_STEP: number;
|
|
17
17
|
/** Snaps a single scalar to the nearest multiple of `step`. */
|
|
18
18
|
export declare function snapScalar(value: number, step?: number): number;
|
|
@@ -45,6 +45,14 @@ export declare function snapWorldXZToBuildingLocal(worldX: number, worldZ: numbe
|
|
|
45
45
|
* — keeps endpoints landing on grid intersections.
|
|
46
46
|
*/
|
|
47
47
|
export declare function snapPointToAngle(from: Vec2, cursor: Vec2, angleStep?: number, gridStep?: number): Vec2;
|
|
48
|
+
/**
|
|
49
|
+
* Snaps a cursor point onto the nearest angle ray from `from` (multiples of
|
|
50
|
+
* `angleStep`), projecting the cursor onto that ray, then snaps the distance
|
|
51
|
+
* ALONG the ray to `distanceStep`. Unlike `snapPointToAngle` with a
|
|
52
|
+
* `gridStep`, the result stays exactly on the snapped ray — grid-snapping
|
|
53
|
+
* after the angle projection pulls points off non-axis rays.
|
|
54
|
+
*/
|
|
55
|
+
export declare function snapPointAlongAngleRay(from: Vec2, cursor: Vec2, angleStep?: number, distanceStep?: number): Vec2;
|
|
48
56
|
/**
|
|
49
57
|
* Snaps an angle (in radians) to the nearest entry in `snapAngles` (also in
|
|
50
58
|
* radians). Returns the original angle if no entry is within `toleranceRad`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"snap.d.ts","sourceRoot":"","sources":["../../src/services/snap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;AAC5C,MAAM,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;AAEpD,6EAA6E;AAC7E,eAAO,MAAM,iBAAiB,OAAO,CAAA;AAErC,
|
|
1
|
+
{"version":3,"file":"snap.d.ts","sourceRoot":"","sources":["../../src/services/snap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;AAC5C,MAAM,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;AAEpD,6EAA6E;AAC7E,eAAO,MAAM,iBAAiB,OAAO,CAAA;AAErC,4CAA4C;AAC5C,eAAO,MAAM,kBAAkB,QAAe,CAAA;AAI9C,+DAA+D;AAC/D,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,GAAE,MAA0B,GAAG,MAAM,CAGlF;AAED,iDAAiD;AACjD,wBAAgB,eAAe,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,GAAE,MAA0B,GAAG,IAAI,CAEnF;AAED,yEAAyE;AACzE,wBAAgB,cAAc,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,GAAE,MAA0B,GAAG,IAAI,CAElF;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,gBAAgB,EAAE,IAAI,EACtB,iBAAiB,EAAE,MAAM,EACzB,IAAI,GAAE,MAA0B,GAC/B;IAAE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CA2BtD;AAID;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,IAAI,EACV,MAAM,EAAE,IAAI,EACZ,SAAS,GAAE,MAA2B,EACtC,QAAQ,CAAC,EAAE,MAAM,GAChB,IAAI,CAWN;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,IAAI,EACV,MAAM,EAAE,IAAI,EACZ,SAAS,GAAE,MAA2B,EACtC,YAAY,CAAC,EAAE,MAAM,GACpB,IAAI,CAYN;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,YAAY,GAAE,MAAqB,GAClC,MAAM,CAcR;AAID;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE;QACJ,IAAI,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;QAC1C,QAAQ,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;QAC9C,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;KACrD,CAAA;IACD,KAAK,EAAE;QACL,MAAM,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;QACjF,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,YAAY,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;KACtF,CAAA;CACF,CAAA;AAED,eAAO,MAAM,YAAY,EAAE,YAU1B,CAAA"}
|
package/dist/services/snap.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
/** Default planar grid spacing in meters. Matches the editor's wall tool. */
|
|
12
12
|
export const DEFAULT_GRID_STEP = 0.25;
|
|
13
|
-
/** Default angle-snap step — π/12 = 15°.
|
|
13
|
+
/** Default angle-snap step — π/12 = 15°. */
|
|
14
14
|
export const DEFAULT_ANGLE_STEP = Math.PI / 12;
|
|
15
15
|
// ─── Grid snap ────────────────────────────────────────────────────────
|
|
16
16
|
/** Snaps a single scalar to the nearest multiple of `step`. */
|
|
@@ -88,6 +88,26 @@ export function snapPointToAngle(from, cursor, angleStep = DEFAULT_ANGLE_STEP, g
|
|
|
88
88
|
];
|
|
89
89
|
return gridStep == null ? projected : snapPointToGrid(projected, gridStep);
|
|
90
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* Snaps a cursor point onto the nearest angle ray from `from` (multiples of
|
|
93
|
+
* `angleStep`), projecting the cursor onto that ray, then snaps the distance
|
|
94
|
+
* ALONG the ray to `distanceStep`. Unlike `snapPointToAngle` with a
|
|
95
|
+
* `gridStep`, the result stays exactly on the snapped ray — grid-snapping
|
|
96
|
+
* after the angle projection pulls points off non-axis rays.
|
|
97
|
+
*/
|
|
98
|
+
export function snapPointAlongAngleRay(from, cursor, angleStep = DEFAULT_ANGLE_STEP, distanceStep) {
|
|
99
|
+
const dx = cursor[0] - from[0];
|
|
100
|
+
const dz = cursor[1] - from[1];
|
|
101
|
+
if (dx === 0 && dz === 0)
|
|
102
|
+
return [from[0], from[1]];
|
|
103
|
+
const angle = Math.atan2(dz, dx);
|
|
104
|
+
const snappedAngle = angleStep > 0 ? Math.round(angle / angleStep) * angleStep : angle;
|
|
105
|
+
const dirX = Math.cos(snappedAngle);
|
|
106
|
+
const dirZ = Math.sin(snappedAngle);
|
|
107
|
+
const projected = dx * dirX + dz * dirZ;
|
|
108
|
+
const distance = distanceStep != null && distanceStep > 0 ? snapScalar(projected, distanceStep) : projected;
|
|
109
|
+
return [from[0] + dirX * distance, from[1] + dirZ * distance];
|
|
110
|
+
}
|
|
91
111
|
/**
|
|
92
112
|
* Snaps an angle (in radians) to the nearest entry in `snapAngles` (also in
|
|
93
113
|
* radians). Returns the original angle if no entry is within `toleranceRad`.
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type { LevelNode, WallNode } from '../schema';
|
|
2
|
+
import type { AnyNode, AnyNodeId } from '../schema/types';
|
|
3
|
+
/**
|
|
4
|
+
* Gap kept between a ceiling's stored height and its clamp bound (storey
|
|
5
|
+
* plane or covering-slab underside), so the ceiling surface never
|
|
6
|
+
* coincides with the solid above it.
|
|
7
|
+
*/
|
|
8
|
+
export declare const CEILING_CLAMP_MARGIN = 0.01;
|
|
9
|
+
/**
|
|
10
|
+
* Stored storey height in meters (floor-to-floor). Falls back to
|
|
11
|
+
* {@link DEFAULT_LEVEL_HEIGHT} for unmigrated legacy levels whose `height`
|
|
12
|
+
* field is absent.
|
|
13
|
+
*/
|
|
14
|
+
export declare function getStoredLevelHeight(level: Pick<LevelNode, 'height'>): number;
|
|
15
|
+
export type LevelElevation = {
|
|
16
|
+
/** World Y of the level's floor: prefix sum of the storey heights below it. */
|
|
17
|
+
baseY: number;
|
|
18
|
+
/** Stored storey height of this level (fallback applied). */
|
|
19
|
+
height: number;
|
|
20
|
+
buildingId: string | null;
|
|
21
|
+
ordinal: number;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Per-building stacked elevations from stored storey heights: levels are
|
|
25
|
+
* sorted by ordinal ascending within each building, the lowest level's floor
|
|
26
|
+
* sits at 0, and each next floor sits on top of the previous storey height.
|
|
27
|
+
* Levels with no resolvable building share one legacy stack from 0.
|
|
28
|
+
*
|
|
29
|
+
* Pure — operates on the serialized nodes record only.
|
|
30
|
+
*/
|
|
31
|
+
export declare function getLevelElevations(nodes: Record<AnyNodeId, AnyNode>): Map<string, LevelElevation>;
|
|
32
|
+
/**
|
|
33
|
+
* The id of the level directly above `levelId` in its own stack (same
|
|
34
|
+
* resolved building, or the shared legacy stack for building-less levels):
|
|
35
|
+
* the level with the lowest ordinal strictly greater than the queried
|
|
36
|
+
* level's. `null` when the level is topmost or unresolvable.
|
|
37
|
+
*/
|
|
38
|
+
export declare function findLevelAboveId(levelId: string, elevations: Map<string, LevelElevation>): string | null;
|
|
39
|
+
/**
|
|
40
|
+
* The level directly above `levelId` — see {@link findLevelAboveId}.
|
|
41
|
+
* `null` when topmost or unresolvable. Pure.
|
|
42
|
+
*/
|
|
43
|
+
export declare function getLevelAbove(levelId: string, nodes: Record<AnyNodeId, AnyNode>): LevelNode | null;
|
|
44
|
+
/**
|
|
45
|
+
* The id of the level directly below `levelId` in its own stack — mirror of
|
|
46
|
+
* {@link findLevelAboveId}: the level with the highest ordinal strictly less
|
|
47
|
+
* than the queried level's. `null` when the level is lowest or unresolvable.
|
|
48
|
+
*/
|
|
49
|
+
export declare function findLevelBelowId(levelId: string, elevations: Map<string, LevelElevation>): string | null;
|
|
50
|
+
/**
|
|
51
|
+
* The level directly below `levelId` — see {@link findLevelBelowId}.
|
|
52
|
+
* `null` when lowest or unresolvable. Pure.
|
|
53
|
+
*/
|
|
54
|
+
export declare function getLevelBelow(levelId: string, nodes: Record<AnyNodeId, AnyNode>): LevelNode | null;
|
|
55
|
+
/**
|
|
56
|
+
* Underside of the LOWEST slab from the level above that covers
|
|
57
|
+
* level-local point `[x, z]`, expressed in the queried level's local Y:
|
|
58
|
+
* `storeyHeight + (slab.elevation - slab.thickness)`. `recessed` slabs
|
|
59
|
+
* (pools) never cover. `null` when no covering slab (or no level above).
|
|
60
|
+
*
|
|
61
|
+
* Coordinate spaces: levels stack in Y only (`LevelNode` carries no XZ
|
|
62
|
+
* transform and the viewer's LevelSystem writes only `position.y`), so a
|
|
63
|
+
* level-local `[x, z]` is valid in every level of the stack unchanged.
|
|
64
|
+
*/
|
|
65
|
+
export declare function getCoveringSlabUndersideAt(levelId: string, nodes: Record<AnyNodeId, AnyNode>, x: number, z: number): number | null;
|
|
66
|
+
/**
|
|
67
|
+
* Top plane for a plane-bound wall on `levelId`, in level-local Y:
|
|
68
|
+
* `min(stored storey height, lowest covering-slab underside over the wall's
|
|
69
|
+
* span)` — a thick or flush slab on the level above SHORTENS the walls below
|
|
70
|
+
* instead of colliding with them (Revit-style automatic attach).
|
|
71
|
+
*
|
|
72
|
+
* Coverage: the wall's thickness band (centerline + face lines, arc-aware)
|
|
73
|
+
* is clipped against each covering slab's stored polygon minus holes via
|
|
74
|
+
* {@link wallOverlapsSlabFootprint} — the same overlap machinery as the
|
|
75
|
+
* support election. Point sampling is deliberately avoided: auto-slab
|
|
76
|
+
* polygons derive from wall CENTERLINES, so perimeter walls sit exactly ON
|
|
77
|
+
* the polygon boundary, where ray-cast point-in-polygon flips with the
|
|
78
|
+
* edge's orientation (one wall clamped, its neighbor didn't). Boundary
|
|
79
|
+
* contact counts as covered on every side of the slab.
|
|
80
|
+
*
|
|
81
|
+
* This is THE plane for a plane-bound wall (`height` absent). Explicit-height
|
|
82
|
+
* walls ignore the value (`resolveWallTop` returns their stored height), so
|
|
83
|
+
* passing it wherever a raw storey height feeds `resolveWallTop` /
|
|
84
|
+
* `resolveWallEffectiveHeight` is always safe. Falls back to
|
|
85
|
+
* {@link DEFAULT_LEVEL_HEIGHT} when `levelId` doesn't resolve to a level.
|
|
86
|
+
*/
|
|
87
|
+
export declare function getWallPlaneTop(wall: Pick<WallNode, 'start' | 'end'> & Partial<Pick<WallNode, 'thickness' | 'curveOffset'>>, levelId: string, nodes: Record<AnyNodeId, AnyNode>): number;
|
|
88
|
+
/**
|
|
89
|
+
* Upper bound for a ceiling's stored height over `polygon` on `levelId`:
|
|
90
|
+
* `min(storey plane, lowest covering-slab underside) - CEILING_CLAMP_MARGIN`.
|
|
91
|
+
* The covering underside is sampled at every polygon vertex plus the
|
|
92
|
+
* centroid — cheap, and a slab overlapping a convex-ish ceiling almost
|
|
93
|
+
* always covers one of those points; exact polygon-vs-polygon overlap is
|
|
94
|
+
* not worth its cost for a clamp bound. Ceiling outlines share footprint
|
|
95
|
+
* edges with the slabs above them the same way walls do, so vertices
|
|
96
|
+
* sitting exactly on a slab's boundary count as covered on every side
|
|
97
|
+
* (see `slabCoversPoint`) instead of flipping with the edge orientation.
|
|
98
|
+
*
|
|
99
|
+
* Returns `Infinity` when `levelId` doesn't resolve, so callers clamp
|
|
100
|
+
* against nothing rather than a garbage plane.
|
|
101
|
+
*/
|
|
102
|
+
export declare function getCeilingClampBound(levelId: string, nodes: Record<AnyNodeId, AnyNode>, polygon: ReadonlyArray<[number, number]>): number;
|
|
103
|
+
//# sourceMappingURL=storey.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storey.d.ts","sourceRoot":"","sources":["../../src/services/storey.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAgB,SAAS,EAAY,QAAQ,EAAE,MAAM,WAAW,CAAA;AAC5E,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAQzD;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,OAAO,CAAA;AAExC;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,GAAG,MAAM,CAE7E;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,+EAA+E;IAC/E,KAAK,EAAE,MAAM,CAAA;IACb,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAkBD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAgCjG;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,GACtC,MAAM,GAAG,IAAI,CAef;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,GAChC,SAAS,GAAG,IAAI,CAKlB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,GACtC,MAAM,GAAG,IAAI,CAef;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,GAChC,SAAS,GAAG,IAAI,CAKlB;AAuFD;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,EACjC,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,GACR,MAAM,GAAG,IAAI,CAIf;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,OAAO,GAAG,KAAK,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,GAAG,aAAa,CAAC,CAAC,EAC5F,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,GAChC,MAAM,CAYR;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,EACjC,OAAO,EAAE,aAAa,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GACvC,MAAM,CAuBR"}
|