@pascal-app/core 1.0.0-beta.5 → 1.0.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/LICENSE +21 -0
- package/README.md +23 -0
- package/dist/capture/index.d.ts +3 -0
- package/dist/capture/index.d.ts.map +1 -0
- package/dist/capture/index.js +2 -0
- package/dist/capture/schema.d.ts +417 -0
- package/dist/capture/schema.d.ts.map +1 -0
- package/dist/capture/schema.js +350 -0
- package/dist/capture/source.d.ts +60 -0
- package/dist/capture/source.d.ts.map +1 -0
- package/dist/capture/source.js +254 -0
- package/dist/events/bus.d.ts +58 -7
- package/dist/events/bus.d.ts.map +1 -1
- package/dist/events/hidden-wall-pointer-hold.d.ts +28 -0
- package/dist/events/hidden-wall-pointer-hold.d.ts.map +1 -0
- package/dist/events/hidden-wall-pointer-hold.js +37 -0
- package/dist/hooks/spatial-grid/floor-placed-elevation.d.ts +4 -4
- package/dist/hooks/spatial-grid/floor-placed-elevation.d.ts.map +1 -1
- package/dist/hooks/spatial-grid/floor-placed-elevation.js +7 -12
- package/dist/hooks/spatial-grid/floor-placed-footprints.d.ts +4 -0
- package/dist/hooks/spatial-grid/floor-placed-footprints.d.ts.map +1 -0
- package/dist/hooks/spatial-grid/floor-placed-footprints.js +7 -0
- package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts +5 -8
- package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts.map +1 -1
- package/dist/hooks/spatial-grid/spatial-grid-manager.js +23 -106
- package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts +2931 -2
- package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts.map +1 -1
- package/dist/hooks/spatial-grid/spatial-grid-sync.js +207 -30
- package/dist/hooks/spatial-grid/support-host-patch.d.ts +45 -1
- package/dist/hooks/spatial-grid/support-host-patch.d.ts.map +1 -1
- package/dist/hooks/spatial-grid/support-host-patch.js +174 -9
- package/dist/hooks/spatial-grid/use-spatial-query.d.ts +1 -1
- package/dist/hooks/spatial-grid/use-spatial-query.js +1 -1
- package/dist/index.d.ts +74 -64
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +74 -61
- package/dist/lib/asset-storage.d.ts.map +1 -1
- package/dist/lib/asset-storage.js +4 -1
- package/dist/lib/door-operation.d.ts +1 -1
- package/dist/lib/item-polygon-overlap.d.ts +6 -0
- package/dist/lib/item-polygon-overlap.d.ts.map +1 -0
- package/dist/lib/item-polygon-overlap.js +67 -0
- package/dist/lib/level-name.d.ts +1 -1
- package/dist/lib/measurement-geometry.d.ts +4 -4
- package/dist/lib/plan-footprint.d.ts +41 -0
- package/dist/lib/plan-footprint.d.ts.map +1 -0
- package/dist/lib/plan-footprint.js +58 -0
- package/dist/lib/polygon-union.d.ts +4 -0
- package/dist/lib/polygon-union.d.ts.map +1 -0
- package/dist/lib/polygon-union.js +306 -0
- package/dist/lib/roof-overlap.d.ts +32 -0
- package/dist/lib/roof-overlap.d.ts.map +1 -0
- package/dist/lib/roof-overlap.js +72 -0
- package/dist/lib/room-topology-index.d.ts +1 -1
- package/dist/lib/room-topology-index.js +1 -1
- package/dist/lib/selection-proxy.d.ts +1 -1
- package/dist/lib/slab-polygon.d.ts +36 -3
- package/dist/lib/slab-polygon.d.ts.map +1 -1
- package/dist/lib/slab-polygon.js +135 -29
- package/dist/lib/space-detection.d.ts +12 -1
- package/dist/lib/space-detection.d.ts.map +1 -1
- package/dist/lib/space-detection.js +58 -25
- package/dist/lib/terrain-brush.d.ts +1 -1
- package/dist/lib/terrain-brush.js +1 -1
- package/dist/lib/terrain-codec.d.ts +2 -2
- package/dist/lib/terrain-codec.js +1 -1
- package/dist/lib/terrain-raycast.d.ts +1 -1
- package/dist/lib/terrain-raycast.js +1 -1
- package/dist/lib/terrain-source.d.ts +3 -3
- package/dist/lib/terrain-source.js +3 -3
- package/dist/lib/terrain-support.d.ts +1 -1
- package/dist/lib/terrain-support.js +3 -3
- package/dist/lib/unit-containment.d.ts +19 -0
- package/dist/lib/unit-containment.d.ts.map +1 -0
- package/dist/lib/unit-containment.js +158 -0
- package/dist/lib/unit-report.d.ts +19 -0
- package/dist/lib/unit-report.d.ts.map +1 -0
- package/dist/lib/unit-report.js +36 -0
- package/dist/lib/wall-distance.d.ts +2 -2
- package/dist/lib/wall-distance.js +1 -1
- package/dist/lib/zone-quantities.d.ts +1 -1
- package/dist/lib/zone-quantities.js +7 -7
- package/dist/material-library.d.ts +1 -1
- package/dist/material-library.js +1 -1
- package/dist/procedural-items/fixtures.d.ts +261 -0
- package/dist/procedural-items/fixtures.d.ts.map +1 -0
- package/dist/procedural-items/fixtures.js +349 -0
- package/dist/procedural-items/index.d.ts +10 -0
- package/dist/procedural-items/index.d.ts.map +1 -0
- package/dist/procedural-items/index.js +9 -0
- package/dist/procedural-items/integration.d.ts +92 -0
- package/dist/procedural-items/integration.d.ts.map +1 -0
- package/dist/procedural-items/integration.js +19 -0
- package/dist/procedural-items/library-colors.d.ts +56 -0
- package/dist/procedural-items/library-colors.d.ts.map +1 -0
- package/dist/procedural-items/library-colors.js +84 -0
- package/dist/procedural-items/materials.d.ts +5 -0
- package/dist/procedural-items/materials.d.ts.map +1 -0
- package/dist/procedural-items/materials.js +47 -0
- package/dist/procedural-items/node.d.ts +280 -0
- package/dist/procedural-items/node.d.ts.map +1 -0
- package/dist/procedural-items/node.js +71 -0
- package/dist/procedural-items/placement.d.ts +7 -0
- package/dist/procedural-items/placement.d.ts.map +1 -0
- package/dist/procedural-items/placement.js +48 -0
- package/dist/procedural-items/query.d.ts +50 -0
- package/dist/procedural-items/query.d.ts.map +1 -0
- package/dist/procedural-items/query.js +298 -0
- package/dist/procedural-items/recipe.d.ts +144 -0
- package/dist/procedural-items/recipe.d.ts.map +1 -0
- package/dist/procedural-items/recipe.js +372 -0
- package/dist/procedural-items/spatial.d.ts +19 -0
- package/dist/procedural-items/spatial.d.ts.map +1 -0
- package/dist/procedural-items/spatial.js +39 -0
- package/dist/registry/__bench__/relations-resolver.bench.js +2 -2
- package/dist/registry/handles.d.ts +36 -7
- package/dist/registry/handles.d.ts.map +1 -1
- package/dist/registry/index.d.ts +6 -7
- package/dist/registry/index.d.ts.map +1 -1
- package/dist/registry/index.js +4 -5
- package/dist/registry/registry.d.ts +13 -6
- package/dist/registry/registry.d.ts.map +1 -1
- package/dist/registry/registry.js +37 -4
- package/dist/registry/relations-resolver.d.ts +2 -2
- package/dist/registry/relations-resolver.js +1 -1
- package/dist/registry/scene-api.d.ts +18 -2
- package/dist/registry/scene-api.d.ts.map +1 -1
- package/dist/registry/scene-api.js +50 -2
- package/dist/registry/subtree.d.ts +1 -1
- package/dist/registry/subtree.js +2 -2
- package/dist/registry/types.d.ts +246 -21
- package/dist/registry/types.d.ts.map +1 -1
- package/dist/registry/use-registry-version.js +1 -1
- package/dist/registry/validate-relations.d.ts +4 -0
- package/dist/registry/validate-relations.d.ts.map +1 -0
- package/dist/registry/validate-relations.js +22 -0
- package/dist/schema/__bench__/node-parsers.bench.d.ts +24 -0
- package/dist/schema/__bench__/node-parsers.bench.d.ts.map +1 -0
- package/dist/schema/__bench__/node-parsers.bench.js +314 -0
- package/dist/schema/__fixtures__/node-fixtures.d.ts +28 -0
- package/dist/schema/__fixtures__/node-fixtures.d.ts.map +1 -0
- package/dist/schema/__fixtures__/node-fixtures.js +127 -0
- package/dist/schema/base.d.ts +1 -1
- package/dist/schema/base.d.ts.map +1 -1
- package/dist/schema/base.js +9 -2
- package/dist/schema/collections.d.ts +1 -1
- package/dist/schema/collections.js +1 -1
- package/dist/schema/compiled-node-parsers.d.ts +40 -0
- package/dist/schema/compiled-node-parsers.d.ts.map +1 -0
- package/dist/schema/compiled-node-parsers.js +95 -0
- package/dist/schema/index.d.ts +73 -66
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +65 -57
- package/dist/schema/material.d.ts +1 -0
- package/dist/schema/material.d.ts.map +1 -1
- package/dist/schema/material.js +2 -1
- package/dist/schema/nodes/automatic-downspout.d.ts +17 -0
- package/dist/schema/nodes/automatic-downspout.d.ts.map +1 -0
- package/dist/schema/nodes/automatic-downspout.js +237 -0
- package/dist/schema/nodes/block.d.ts +107 -0
- package/dist/schema/nodes/block.d.ts.map +1 -0
- package/dist/schema/nodes/block.js +206 -0
- package/dist/schema/nodes/box-vent.d.ts +8 -2
- package/dist/schema/nodes/box-vent.d.ts.map +1 -1
- package/dist/schema/nodes/box-vent.js +4 -2
- package/dist/schema/nodes/building.d.ts +2 -2
- package/dist/schema/nodes/building.d.ts.map +1 -1
- package/dist/schema/nodes/building.js +8 -5
- package/dist/schema/nodes/cabinet.d.ts +26 -4
- package/dist/schema/nodes/cabinet.d.ts.map +1 -1
- package/dist/schema/nodes/cabinet.js +29 -8
- package/dist/schema/nodes/ceiling.d.ts +2 -2
- package/dist/schema/nodes/ceiling.js +5 -5
- package/dist/schema/nodes/chimney.d.ts +2 -2
- package/dist/schema/nodes/chimney.js +2 -2
- package/dist/schema/nodes/column.d.ts +7 -6
- package/dist/schema/nodes/column.d.ts.map +1 -1
- package/dist/schema/nodes/column.js +3 -2
- package/dist/schema/nodes/construction-dimension.d.ts +1 -1
- package/dist/schema/nodes/construction-dimension.js +2 -2
- package/dist/schema/nodes/cupola.d.ts +9 -1
- package/dist/schema/nodes/cupola.d.ts.map +1 -1
- package/dist/schema/nodes/cupola.js +4 -2
- package/dist/schema/nodes/door.d.ts +1 -1
- package/dist/schema/nodes/door.js +2 -2
- package/dist/schema/nodes/dormer.d.ts +45 -2
- package/dist/schema/nodes/dormer.d.ts.map +1 -1
- package/dist/schema/nodes/dormer.js +133 -9
- package/dist/schema/nodes/downspout.d.ts +11 -1
- package/dist/schema/nodes/downspout.d.ts.map +1 -1
- package/dist/schema/nodes/downspout.js +26 -2
- package/dist/schema/nodes/duct-fitting.d.ts +18 -1
- package/dist/schema/nodes/duct-fitting.d.ts.map +1 -1
- package/dist/schema/nodes/duct-fitting.js +26 -5
- package/dist/schema/nodes/duct-segment.d.ts +23 -1
- package/dist/schema/nodes/duct-segment.d.ts.map +1 -1
- package/dist/schema/nodes/duct-segment.js +21 -1
- package/dist/schema/nodes/duct-terminal.d.ts +1 -1
- package/dist/schema/nodes/duct-terminal.js +1 -1
- package/dist/schema/nodes/elevator.d.ts +1 -1
- package/dist/schema/nodes/elevator.js +2 -2
- package/dist/schema/nodes/eyebrow-vent.d.ts +8 -2
- package/dist/schema/nodes/eyebrow-vent.d.ts.map +1 -1
- package/dist/schema/nodes/eyebrow-vent.js +4 -2
- package/dist/schema/nodes/fence.d.ts +1 -1
- package/dist/schema/nodes/fence.js +2 -2
- package/dist/schema/nodes/guide.d.ts +1 -1
- package/dist/schema/nodes/guide.js +2 -2
- package/dist/schema/nodes/gutter.d.ts +36 -2
- package/dist/schema/nodes/gutter.d.ts.map +1 -1
- package/dist/schema/nodes/gutter.js +310 -3
- package/dist/schema/nodes/hanger-overrides.d.ts +7 -0
- package/dist/schema/nodes/hanger-overrides.d.ts.map +1 -0
- package/dist/schema/nodes/hanger-overrides.js +6 -0
- package/dist/schema/nodes/hvac-equipment.d.ts +1 -1
- package/dist/schema/nodes/hvac-equipment.js +1 -1
- package/dist/schema/nodes/imported-mesh.d.ts +40 -0
- package/dist/schema/nodes/imported-mesh.d.ts.map +1 -0
- package/dist/schema/nodes/imported-mesh.js +27 -0
- package/dist/schema/nodes/item.d.ts +3 -2
- package/dist/schema/nodes/item.d.ts.map +1 -1
- package/dist/schema/nodes/item.js +8 -3
- package/dist/schema/nodes/lean-to-extension.d.ts +212 -0
- package/dist/schema/nodes/lean-to-extension.d.ts.map +1 -0
- package/dist/schema/nodes/lean-to-extension.js +114 -0
- package/dist/schema/nodes/level.d.ts +2 -2
- package/dist/schema/nodes/level.d.ts.map +1 -1
- package/dist/schema/nodes/level.js +1 -1
- package/dist/schema/nodes/lineset.d.ts +1 -1
- package/dist/schema/nodes/lineset.js +1 -1
- package/dist/schema/nodes/liquid-line.d.ts +1 -1
- package/dist/schema/nodes/liquid-line.js +1 -1
- package/dist/schema/nodes/measurement.d.ts +1 -1
- package/dist/schema/nodes/measurement.js +2 -2
- package/dist/schema/nodes/pipe-fitting.d.ts +10 -2
- package/dist/schema/nodes/pipe-fitting.d.ts.map +1 -1
- package/dist/schema/nodes/pipe-fitting.js +7 -3
- package/dist/schema/nodes/pipe-segment.d.ts +24 -2
- package/dist/schema/nodes/pipe-segment.d.ts.map +1 -1
- package/dist/schema/nodes/pipe-segment.js +21 -1
- package/dist/schema/nodes/pipe-trap.d.ts +2 -2
- package/dist/schema/nodes/pipe-trap.js +1 -1
- package/dist/schema/nodes/ridge-vent.d.ts +2 -2
- package/dist/schema/nodes/ridge-vent.d.ts.map +1 -1
- package/dist/schema/nodes/ridge-vent.js +7 -4
- package/dist/schema/nodes/roof-segment-shape.d.ts +5 -1
- package/dist/schema/nodes/roof-segment-shape.d.ts.map +1 -1
- package/dist/schema/nodes/roof-segment-shape.js +65 -2
- package/dist/schema/nodes/roof-segment-walls.d.ts +4 -2
- package/dist/schema/nodes/roof-segment-walls.d.ts.map +1 -1
- package/dist/schema/nodes/roof-segment-walls.js +2 -2
- package/dist/schema/nodes/roof-segment.d.ts +42 -2
- package/dist/schema/nodes/roof-segment.d.ts.map +1 -1
- package/dist/schema/nodes/roof-segment.js +81 -4
- package/dist/schema/nodes/roof.d.ts +23 -2
- package/dist/schema/nodes/roof.d.ts.map +1 -1
- package/dist/schema/nodes/roof.js +17 -3
- package/dist/schema/nodes/scan.d.ts +19 -2
- package/dist/schema/nodes/scan.d.ts.map +1 -1
- package/dist/schema/nodes/scan.js +13 -3
- package/dist/schema/nodes/shelf.d.ts +3 -3
- package/dist/schema/nodes/shelf.d.ts.map +1 -1
- package/dist/schema/nodes/shelf.js +3 -4
- package/dist/schema/nodes/site.d.ts +1 -1
- package/dist/schema/nodes/site.js +2 -2
- package/dist/schema/nodes/skylight.d.ts +5 -5
- package/dist/schema/nodes/skylight.js +2 -2
- package/dist/schema/nodes/slab.d.ts +1 -1
- package/dist/schema/nodes/slab.js +3 -3
- package/dist/schema/nodes/solar-panel.d.ts +1 -1
- package/dist/schema/nodes/solar-panel.js +3 -3
- package/dist/schema/nodes/spawn.d.ts +1 -1
- package/dist/schema/nodes/spawn.js +1 -1
- package/dist/schema/nodes/stair-segment.d.ts +1 -1
- package/dist/schema/nodes/stair-segment.js +2 -2
- package/dist/schema/nodes/stair.d.ts +2 -2
- package/dist/schema/nodes/stair.js +3 -3
- package/dist/schema/nodes/structural-grid.d.ts +1 -1
- package/dist/schema/nodes/structural-grid.js +1 -1
- package/dist/schema/nodes/turbine-vent.d.ts +8 -2
- package/dist/schema/nodes/turbine-vent.d.ts.map +1 -1
- package/dist/schema/nodes/turbine-vent.js +4 -2
- package/dist/schema/nodes/unit.d.ts +33 -0
- package/dist/schema/nodes/unit.d.ts.map +1 -0
- package/dist/schema/nodes/unit.js +13 -0
- package/dist/schema/nodes/wall.d.ts +5 -5
- package/dist/schema/nodes/wall.d.ts.map +1 -1
- package/dist/schema/nodes/wall.js +13 -6
- package/dist/schema/nodes/window.d.ts +10 -3
- package/dist/schema/nodes/window.d.ts.map +1 -1
- package/dist/schema/nodes/window.js +6 -2
- package/dist/schema/nodes/zone.d.ts +2 -2
- package/dist/schema/nodes/zone.js +2 -2
- package/dist/schema/scene-material.js +2 -2
- package/dist/schema/types.d.ts +815 -118
- package/dist/schema/types.d.ts.map +1 -1
- package/dist/schema/types.js +79 -46
- package/dist/services/alignment-anchors.d.ts +6 -11
- package/dist/services/alignment-anchors.d.ts.map +1 -1
- package/dist/services/alignment-anchors.js +7 -34
- package/dist/services/drag-session.d.ts +4 -4
- package/dist/services/drag-session.js +1 -1
- package/dist/services/hosting.d.ts +4 -10
- package/dist/services/hosting.d.ts.map +1 -1
- package/dist/services/hosting.js +6 -16
- package/dist/services/index.d.ts +16 -13
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +16 -13
- package/dist/services/level-height.d.ts +2 -2
- package/dist/services/level-height.js +3 -3
- package/dist/services/movement.d.ts +3 -3
- package/dist/services/movement.js +2 -2
- package/dist/services/port-connectivity.d.ts +1 -1
- package/dist/services/port-connectivity.js +1 -1
- package/dist/services/riser-diagram.d.ts +1 -1
- package/dist/services/shelf-board.d.ts +5 -0
- package/dist/services/shelf-board.d.ts.map +1 -0
- package/dist/services/shelf-board.js +15 -0
- package/dist/services/storey.d.ts +2 -2
- package/dist/services/storey.js +2 -2
- package/dist/services/surface-hosting-procedural-parity.fixtures.d.ts +13 -0
- package/dist/services/surface-hosting-procedural-parity.fixtures.d.ts.map +1 -0
- package/dist/services/surface-hosting-procedural-parity.fixtures.js +4691 -0
- package/dist/services/surface-hosting-shelf-parity.fixtures.d.ts +1060 -0
- package/dist/services/surface-hosting-shelf-parity.fixtures.d.ts.map +1 -0
- package/dist/services/surface-hosting-shelf-parity.fixtures.js +3127 -0
- package/dist/services/surface-hosting.d.ts +88 -0
- package/dist/services/surface-hosting.d.ts.map +1 -0
- package/dist/services/surface-hosting.js +268 -0
- package/dist/services/surface-region.d.ts +8 -0
- package/dist/services/surface-region.d.ts.map +1 -0
- package/dist/services/surface-region.js +44 -0
- package/dist/services/system-graph.d.ts +12 -1
- package/dist/services/system-graph.d.ts.map +1 -1
- package/dist/services/system-graph.js +36 -6
- package/dist/services/validate-dwv.d.ts +1 -1
- package/dist/services/validate-dwv.js +1 -1
- package/dist/store/actions/node-actions.d.ts +9 -2
- package/dist/store/actions/node-actions.d.ts.map +1 -1
- package/dist/store/actions/node-actions.js +475 -24
- package/dist/store/history-control.d.ts +3 -3
- package/dist/store/history-invalidation.d.ts +3 -0
- package/dist/store/history-invalidation.d.ts.map +1 -0
- package/dist/store/history-invalidation.js +72 -0
- package/dist/store/scene-hydration.d.ts +5 -0
- package/dist/store/scene-hydration.d.ts.map +1 -0
- package/dist/store/scene-hydration.js +57 -0
- package/dist/store/use-interactive.d.ts +2 -2
- package/dist/store/use-live-terrain.d.ts +1 -1
- package/dist/store/use-scene.d.ts +7 -4
- package/dist/store/use-scene.d.ts.map +1 -1
- package/dist/store/use-scene.js +361 -87
- package/dist/systems/elevator/elevator-dispatch.d.ts +2 -2
- package/dist/systems/elevator/elevator-dispatch.js +1 -1
- package/dist/systems/elevator/elevator-geometry.d.ts +1 -1
- package/dist/systems/elevator/elevator-opening-sync.d.ts +1 -1
- package/dist/systems/elevator/elevator-opening-sync.js +2 -2
- package/dist/systems/elevator/elevator-opening-system.js +3 -3
- package/dist/systems/elevator/elevator-runtime.d.ts +3 -3
- package/dist/systems/elevator/elevator-runtime.js +3 -3
- package/dist/systems/elevator/elevator-service.d.ts +1 -1
- package/dist/systems/elevator/elevator-service.js +1 -1
- package/dist/systems/fence/fence-centerline.d.ts +2 -2
- package/dist/systems/fence/fence-centerline.js +2 -2
- package/dist/systems/fence/fence-spline.d.ts +2 -2
- package/dist/systems/roof/roof-elevation-system.d.ts +3 -0
- package/dist/systems/roof/roof-elevation-system.d.ts.map +1 -0
- package/dist/systems/roof/roof-elevation-system.js +94 -0
- package/dist/systems/roof/roof-elevation.d.ts +4 -0
- package/dist/systems/roof/roof-elevation.d.ts.map +1 -0
- package/dist/systems/roof/roof-elevation.js +95 -0
- package/dist/systems/roof/roof-footprint.d.ts +17 -0
- package/dist/systems/roof/roof-footprint.d.ts.map +1 -0
- package/dist/systems/roof/roof-footprint.js +83 -0
- package/dist/systems/slab/slab-placement.d.ts +1 -1
- package/dist/systems/slab/slab-support.d.ts +1 -1
- package/dist/systems/slab/slab-support.js +4 -4
- package/dist/systems/stair/stair-flight.d.ts +17 -0
- package/dist/systems/stair/stair-flight.d.ts.map +1 -0
- package/dist/systems/stair/stair-flight.js +27 -0
- package/dist/systems/stair/stair-footprint.d.ts +1 -1
- package/dist/systems/stair/stair-opening-preview.d.ts +1621 -1267
- package/dist/systems/stair/stair-opening-preview.d.ts.map +1 -1
- package/dist/systems/stair/stair-opening-preview.js +2 -2
- package/dist/systems/stair/stair-opening-sync.d.ts +1 -1
- package/dist/systems/stair/stair-opening-sync.js +6 -6
- package/dist/systems/stair/stair-opening-system.d.ts +1 -0
- package/dist/systems/stair/stair-opening-system.d.ts.map +1 -1
- package/dist/systems/stair/stair-opening-system.js +100 -103
- package/dist/systems/stair/stair-rise.d.ts +1 -1
- package/dist/systems/stair/stair-rise.d.ts.map +1 -1
- package/dist/systems/stair/stair-rise.js +23 -24
- package/dist/systems/wall/wall-curve.d.ts +3 -2
- package/dist/systems/wall/wall-curve.d.ts.map +1 -1
- package/dist/systems/wall/wall-curve.js +73 -0
- package/dist/systems/wall/wall-footprint.d.ts +3 -2
- package/dist/systems/wall/wall-footprint.d.ts.map +1 -1
- package/dist/systems/wall/wall-footprint.js +3 -2
- package/dist/systems/wall/wall-mitering.d.ts +1 -1
- package/dist/systems/wall/wall-mitering.js +1 -1
- package/dist/systems/wall/wall-move.d.ts +1 -1
- package/dist/systems/wall/wall-top.d.ts +1 -1
- package/dist/systems/wall/wall-topology.d.ts +2 -2
- package/dist/systems/wall/wall-topology.js +4 -4
- package/dist/utils/clone-scene-graph.d.ts +3 -3
- package/dist/utils/clone-scene-graph.d.ts.map +1 -1
- package/dist/utils/clone-scene-graph.js +35 -3
- package/dist/utils/scene-migrations.d.ts +3 -3
- package/dist/utils/scene-migrations.js +3 -3
- package/dist/utils/vertical-scene-migration.js +5 -5
- package/dist/validation/validate-build-json.d.ts +7 -1
- package/dist/validation/validate-build-json.d.ts.map +1 -1
- package/dist/validation/validate-build-json.js +92 -4
- package/package.json +23 -5
- package/dist/systems/elevator/elevator-runtime-system.d.ts +0 -2
- package/dist/systems/elevator/elevator-runtime-system.d.ts.map +0 -1
- package/dist/systems/elevator/elevator-runtime-system.js +0 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spatial-grid-sync.d.ts","sourceRoot":"","sources":["../../../src/hooks/spatial-grid/spatial-grid-sync.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"spatial-grid-sync.d.ts","sourceRoot":"","sources":["../../../src/hooks/spatial-grid/spatial-grid-sync.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAY,QAAQ,EAAY,MAAM,cAAc,CAAA;AAY/F,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAmBpF;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,MAAM,GAAG,IAAI,CASf;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,SAAS,EAClB,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,GAChC,SAAS,GAAG,IAAI,CAgBlB;AAKD,wBAAgB,mBAAmB,IAAI,MAAM,IAAI,CAwNhD;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,0BAA0B,KAAK,CAAA;AAE5C,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,MAAM,CAmBR;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,SAAS,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,IAAI,QAgBnC;AAMD;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,SAAS,EAChB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,SAAS,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,IAAI,QAcnC;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,SAAS,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,IAAI,QAOnC;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,QAAQ,EACd,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,SAAS,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,IAAI,EAClC,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAAQ,QA6BtB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,SAAS,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,IAAI,QAgDnC;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CACzC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,SAAS,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,IAAI,QAUnC"}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
1
|
+
import { subtractPolygonsFromPolygon } from '../../lib/polygon-union.js';
|
|
2
|
+
import { getRenderableSlabPolygon } from '../../lib/slab-polygon.js';
|
|
3
|
+
import { isLevelAtSiteDatum, isLevelBaseConsumer } from '../../lib/terrain-support.js';
|
|
4
|
+
import { nodeRegistry } from '../../registry/index.js';
|
|
5
|
+
import { getLevelBelow } from '../../services/storey.js';
|
|
6
|
+
import useLiveTerrain from '../../store/use-live-terrain.js';
|
|
7
|
+
import useScene from '../../store/use-scene.js';
|
|
8
|
+
import { getFloorPlacedFootprints } from './floor-placed-elevation.js';
|
|
9
|
+
import { itemOverlapsPolygon, spatialGridManager, wallOverlapsPolygon, } from './spatial-grid-manager.js';
|
|
10
|
+
import { GROUND_SUPPORT_ID } from './support-host-id.js';
|
|
10
11
|
export function resolveLevelId(node, nodes) {
|
|
11
12
|
// If the node itself is a level
|
|
12
13
|
if (node.type === 'level')
|
|
@@ -98,13 +99,55 @@ export function initSpatialGridSync() {
|
|
|
98
99
|
const markDirty = (id) => store.getState().markDirty(id);
|
|
99
100
|
// Subscribe to all changes
|
|
100
101
|
const unsubscribeScene = store.subscribe((state, prevState) => {
|
|
102
|
+
if (state.nodes === prevState.nodes)
|
|
103
|
+
return;
|
|
104
|
+
// A bulk slab change (scene load/reload, paste, import) used to run
|
|
105
|
+
// markNodesOverlappingSlab per slab — two full node scans each, O(slabs ×
|
|
106
|
+
// nodes). Above the threshold, dirty every possible slab dependent once (a
|
|
107
|
+
// superset of the per-slab result) and skip the per-slab scans below.
|
|
108
|
+
const bulkSlabs = countBulkSlabChanges(state.nodes, prevState.nodes) >= BULK_SLAB_CHANGE_THRESHOLD;
|
|
109
|
+
if (bulkSlabs)
|
|
110
|
+
markAllSlabDependents(state.nodes, markDirty);
|
|
111
|
+
const changedSlabContextLevels = new Set();
|
|
112
|
+
const checkSlabContext = (id) => {
|
|
113
|
+
const previous = prevState.nodes[id];
|
|
114
|
+
const next = state.nodes[id];
|
|
115
|
+
if (previous === next)
|
|
116
|
+
return;
|
|
117
|
+
const wallChanged = (previous?.type === 'wall' || next?.type === 'wall') &&
|
|
118
|
+
(previous?.type !== 'wall' ||
|
|
119
|
+
next?.type !== 'wall' ||
|
|
120
|
+
previous.parentId !== next.parentId ||
|
|
121
|
+
previous.start !== next.start ||
|
|
122
|
+
previous.end !== next.end ||
|
|
123
|
+
previous.thickness !== next.thickness ||
|
|
124
|
+
previous.curveOffset !== next.curveOffset);
|
|
125
|
+
const slabChanged = (previous?.type === 'slab' || next?.type === 'slab') &&
|
|
126
|
+
(previous?.type !== 'slab' ||
|
|
127
|
+
next?.type !== 'slab' ||
|
|
128
|
+
previous.parentId !== next.parentId ||
|
|
129
|
+
previous.polygon !== next.polygon ||
|
|
130
|
+
previous.elevation !== next.elevation);
|
|
131
|
+
if (!(wallChanged || slabChanged))
|
|
132
|
+
return;
|
|
133
|
+
if (previous)
|
|
134
|
+
changedSlabContextLevels.add(resolveLevelId(previous, prevState.nodes));
|
|
135
|
+
if (next)
|
|
136
|
+
changedSlabContextLevels.add(resolveLevelId(next, state.nodes));
|
|
137
|
+
};
|
|
138
|
+
for (const id in prevState.nodes)
|
|
139
|
+
checkSlabContext(id);
|
|
140
|
+
for (const id in state.nodes) {
|
|
141
|
+
if (!prevState.nodes[id])
|
|
142
|
+
checkSlabContext(id);
|
|
143
|
+
}
|
|
101
144
|
// Detect added nodes
|
|
102
145
|
for (const [id, node] of Object.entries(state.nodes)) {
|
|
103
146
|
if (!prevState.nodes[id]) {
|
|
104
147
|
const levelId = resolveLevelId(node, state.nodes);
|
|
105
148
|
spatialGridManager.handleNodeCreated(node, levelId);
|
|
106
149
|
// When a slab is added, mark overlapping items/walls dirty
|
|
107
|
-
if (node.type === 'slab') {
|
|
150
|
+
if (node.type === 'slab' && !bulkSlabs) {
|
|
108
151
|
markNodesOverlappingSlab(node, state.nodes, markDirty);
|
|
109
152
|
markCoveringDependentsBelow(levelId, state.nodes, markDirty);
|
|
110
153
|
}
|
|
@@ -122,8 +165,8 @@ export function initSpatialGridSync() {
|
|
|
122
165
|
const levelId = resolveLevelId(node, prevState.nodes);
|
|
123
166
|
spatialGridManager.handleNodeDeleted(id, node.type, levelId);
|
|
124
167
|
// When a slab is removed, mark items/walls that were on it dirty (using current state)
|
|
125
|
-
if (node.type === 'slab') {
|
|
126
|
-
markNodesOverlappingSlab(node, state.nodes, markDirty);
|
|
168
|
+
if (node.type === 'slab' && !bulkSlabs) {
|
|
169
|
+
markNodesOverlappingSlab(node, state.nodes, markDirty, prevState.nodes);
|
|
127
170
|
markCoveringDependentsBelow(levelId, state.nodes, markDirty);
|
|
128
171
|
}
|
|
129
172
|
// Deleting a sculpted site drops the ground back to the datum, so its
|
|
@@ -160,7 +203,9 @@ export function initSpatialGridSync() {
|
|
|
160
203
|
const levelId = resolveLevelId(node, state.nodes);
|
|
161
204
|
spatialGridManager.handleNodeUpdated(node, levelId);
|
|
162
205
|
}
|
|
163
|
-
|
|
206
|
+
if (!bulkSlabs) {
|
|
207
|
+
markSlabChangeDependents(prev, node, state.nodes, markDirty, prevState.nodes);
|
|
208
|
+
}
|
|
164
209
|
}
|
|
165
210
|
else if (node.type === 'level' && prev.type === 'level') {
|
|
166
211
|
if (node.height !== prev.height) {
|
|
@@ -188,6 +233,38 @@ export function initSpatialGridSync() {
|
|
|
188
233
|
}
|
|
189
234
|
}
|
|
190
235
|
}
|
|
236
|
+
// Unchanged slabs can lose an adopted wall band or a sibling seam. Their
|
|
237
|
+
// stored polygons cannot identify objects standing on the former boundary.
|
|
238
|
+
if (changedSlabContextLevels.size === 0)
|
|
239
|
+
return;
|
|
240
|
+
const beforeContext = slabBoundaryContext(prevState.nodes, changedSlabContextLevels);
|
|
241
|
+
const afterContext = slabBoundaryContext(state.nodes, changedSlabContextLevels);
|
|
242
|
+
for (const context of afterContext.values()) {
|
|
243
|
+
for (const slab of context.slabs) {
|
|
244
|
+
const previous = prevState.nodes[slab.id];
|
|
245
|
+
if (previous?.type !== 'slab')
|
|
246
|
+
continue;
|
|
247
|
+
if (slab.parentId !== previous.parentId ||
|
|
248
|
+
slab.polygon !== previous.polygon ||
|
|
249
|
+
slab.elevation !== previous.elevation ||
|
|
250
|
+
slab.holes !== previous.holes)
|
|
251
|
+
continue;
|
|
252
|
+
const previousContext = beforeContext.get(resolveLevelId(previous, prevState.nodes));
|
|
253
|
+
const beforePolygon = cachedSlabPolygon(previous, previousContext);
|
|
254
|
+
const afterPolygon = cachedSlabPolygon(slab, context);
|
|
255
|
+
if (beforePolygon.length === afterPolygon.length &&
|
|
256
|
+
beforePolygon.every((point, i) => arraysEqual(point, afterPolygon[i])))
|
|
257
|
+
continue;
|
|
258
|
+
// Support only changed in the gained/lost bands, not across the slab interior.
|
|
259
|
+
const changedBands = [
|
|
260
|
+
...subtractPolygonsFromPolygon(beforePolygon, [afterPolygon]),
|
|
261
|
+
...subtractPolygonsFromPolygon(afterPolygon, [beforePolygon]),
|
|
262
|
+
];
|
|
263
|
+
for (const polygon of changedBands) {
|
|
264
|
+
markNodesOverlappingPolygon(resolveLevelId(slab, state.nodes), polygon, state.nodes, markDirty, context.consumers);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
191
268
|
});
|
|
192
269
|
// Live terrain is deliberately not written into `useScene` per dab: doing so
|
|
193
270
|
// would encode the whole field, flood history, and wake every scene subscriber.
|
|
@@ -202,6 +279,61 @@ export function initSpatialGridSync() {
|
|
|
202
279
|
unsubscribeLiveTerrain();
|
|
203
280
|
};
|
|
204
281
|
}
|
|
282
|
+
/**
|
|
283
|
+
* Bulk slab-change guard. A scene load, reload, paste or import changes tens to
|
|
284
|
+
* thousands of slabs in one store write, and scanning every node twice per slab
|
|
285
|
+
* is O(slabs × nodes): a 4,600-slab scene blocked the main thread for ~5 s on
|
|
286
|
+
* every load. When at least this many slabs are added, removed or reshaped in
|
|
287
|
+
* one write, `markAllSlabDependents` dirties every node any slab could affect,
|
|
288
|
+
* once, and the per-slab scans are skipped. The marks are a superset of the
|
|
289
|
+
* per-slab result — and `setScene` marks every node dirty right after `set()`
|
|
290
|
+
* regardless — so load-time behaviour is unchanged; the saving is the scans.
|
|
291
|
+
*/
|
|
292
|
+
export const BULK_SLAB_CHANGE_THRESHOLD = 32;
|
|
293
|
+
export function countBulkSlabChanges(nodes, prevNodes) {
|
|
294
|
+
let count = 0;
|
|
295
|
+
for (const id in nodes) {
|
|
296
|
+
const node = nodes[id];
|
|
297
|
+
if (node.type !== 'slab')
|
|
298
|
+
continue;
|
|
299
|
+
const prev = prevNodes[id];
|
|
300
|
+
if (prev?.type !== 'slab' ||
|
|
301
|
+
prev.polygon !== node.polygon ||
|
|
302
|
+
prev.elevation !== node.elevation ||
|
|
303
|
+
prev.holes !== node.holes) {
|
|
304
|
+
count++;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
for (const id in prevNodes) {
|
|
308
|
+
if (prevNodes[id].type === 'slab' && !nodes[id])
|
|
309
|
+
count++;
|
|
310
|
+
}
|
|
311
|
+
return count;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Every node a slab change can dirty, without looking at any slab: walls and
|
|
315
|
+
* ceilings (overlap and covering-below rules), stairs (deck attachment) and
|
|
316
|
+
* level-hosted floor-placed kinds (the generic re-elevation sweep).
|
|
317
|
+
*/
|
|
318
|
+
export function markAllSlabDependents(nodes, markDirty) {
|
|
319
|
+
for (const id in nodes) {
|
|
320
|
+
const node = nodes[id];
|
|
321
|
+
if (node.type === 'wall' || node.type === 'ceiling' || node.type === 'stair') {
|
|
322
|
+
markDirty(node.id);
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
const floorPlaced = nodeRegistry.get(node.type)?.capabilities?.floorPlaced;
|
|
326
|
+
if (!floorPlaced)
|
|
327
|
+
continue;
|
|
328
|
+
if (floorPlaced.applies && !floorPlaced.applies(node))
|
|
329
|
+
continue;
|
|
330
|
+
const parentId = node.parentId;
|
|
331
|
+
const parent = parentId ? nodes[parentId] : null;
|
|
332
|
+
if (parent && parent.type !== 'level')
|
|
333
|
+
continue;
|
|
334
|
+
markDirty(node.id);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
205
337
|
function arraysEqual(a, b) {
|
|
206
338
|
return a.length === b.length && a.every((v, i) => v === b[i]);
|
|
207
339
|
}
|
|
@@ -240,12 +372,13 @@ export function markDeckAttachedStairs(slabId, nodes, markDirty) {
|
|
|
240
372
|
* Dirty every consumer of a slab's top or underside. Kept pure so committed
|
|
241
373
|
* scene writes and live handle previews use the same dependency boundary.
|
|
242
374
|
*/
|
|
243
|
-
export function markSlabChangeDependents(previous, next, nodes, markDirty) {
|
|
244
|
-
const supportChanged = next.
|
|
375
|
+
export function markSlabChangeDependents(previous, next, nodes, markDirty, previousNodes = nodes) {
|
|
376
|
+
const supportChanged = next.parentId !== previous.parentId ||
|
|
377
|
+
next.polygon !== previous.polygon ||
|
|
245
378
|
next.elevation !== previous.elevation ||
|
|
246
379
|
next.holes !== previous.holes;
|
|
247
380
|
if (supportChanged) {
|
|
248
|
-
markNodesOverlappingSlab(previous, nodes, markDirty);
|
|
381
|
+
markNodesOverlappingSlab(previous, nodes, markDirty, previousNodes);
|
|
249
382
|
markNodesOverlappingSlab(next, nodes, markDirty);
|
|
250
383
|
}
|
|
251
384
|
if (next.elevation !== previous.elevation) {
|
|
@@ -254,7 +387,14 @@ export function markSlabChangeDependents(previous, next, nodes, markDirty) {
|
|
|
254
387
|
if (supportChanged ||
|
|
255
388
|
next.thickness !== previous.thickness ||
|
|
256
389
|
next.recessed !== previous.recessed) {
|
|
257
|
-
|
|
390
|
+
const nextLevelId = resolveLevelId(next, nodes);
|
|
391
|
+
markCoveringDependentsBelow(nextLevelId, nodes, markDirty);
|
|
392
|
+
if (next.parentId !== previous.parentId) {
|
|
393
|
+
const previousLevelId = resolveLevelId(previous, previousNodes);
|
|
394
|
+
if (previousLevelId !== nextLevelId) {
|
|
395
|
+
markCoveringDependentsBelow(previousLevelId, nodes, markDirty);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
258
398
|
}
|
|
259
399
|
}
|
|
260
400
|
/**
|
|
@@ -344,18 +484,8 @@ export function markCoveringDependentsBelow(slabLevelId, nodes, markDirty) {
|
|
|
344
484
|
}
|
|
345
485
|
}
|
|
346
486
|
}
|
|
347
|
-
|
|
348
|
-
* Mark all floor items and walls that may be affected by a slab change as dirty.
|
|
349
|
-
*/
|
|
350
|
-
function markNodesOverlappingSlab(slab, nodes, markDirty) {
|
|
351
|
-
if (slab.polygon.length < 3)
|
|
352
|
-
return;
|
|
487
|
+
function renderableSlabPolygon(slab, nodes) {
|
|
353
488
|
const slabLevelId = resolveLevelId(slab, nodes);
|
|
354
|
-
// Walls AND floor-placed nodes follow the slab's RENDERED footprint
|
|
355
|
-
// (band-adopted edges reach the wall's outer face), so the dirty gate
|
|
356
|
-
// must test the same polygon the support queries re-evaluate — a stored
|
|
357
|
-
// polygon that stops short of the wall body would otherwise never
|
|
358
|
-
// re-elevate nodes sitting over the adopted band.
|
|
359
489
|
const levelWalls = [];
|
|
360
490
|
const siblingSlabs = [];
|
|
361
491
|
for (const node of Object.values(nodes)) {
|
|
@@ -368,8 +498,20 @@ function markNodesOverlappingSlab(slab, nodes, markDirty) {
|
|
|
368
498
|
siblingSlabs.push(node);
|
|
369
499
|
}
|
|
370
500
|
}
|
|
371
|
-
|
|
372
|
-
|
|
501
|
+
return getRenderableSlabPolygon(slab, { walls: levelWalls, siblingSlabs });
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* Mark all floor items and walls that may be affected by a slab change as dirty.
|
|
505
|
+
*/
|
|
506
|
+
function markNodesOverlappingSlab(slab, nodes, markDirty, contextNodes = nodes) {
|
|
507
|
+
if (slab.polygon.length < 3)
|
|
508
|
+
return;
|
|
509
|
+
const slabLevelId = resolveLevelId(slab, contextNodes);
|
|
510
|
+
const renderedPolygon = renderableSlabPolygon(slab, contextNodes);
|
|
511
|
+
markNodesOverlappingPolygon(slabLevelId, renderedPolygon, nodes, markDirty);
|
|
512
|
+
}
|
|
513
|
+
function markNodesOverlappingPolygon(slabLevelId, renderedPolygon, nodes, markDirty, candidates = Object.values(nodes)) {
|
|
514
|
+
for (const node of candidates) {
|
|
373
515
|
if (node.type === 'wall') {
|
|
374
516
|
const wall = node;
|
|
375
517
|
if (resolveLevelId(node, nodes) !== slabLevelId)
|
|
@@ -412,3 +554,38 @@ function markNodesOverlappingSlab(slab, nodes, markDirty) {
|
|
|
412
554
|
}
|
|
413
555
|
}
|
|
414
556
|
}
|
|
557
|
+
function slabBoundaryContext(nodes, levels) {
|
|
558
|
+
const contexts = new Map();
|
|
559
|
+
for (const id in nodes) {
|
|
560
|
+
const node = nodes[id];
|
|
561
|
+
const floorPlaced = nodeRegistry.get(node.type)?.capabilities?.floorPlaced;
|
|
562
|
+
if (node.type !== 'wall' && node.type !== 'slab' && !floorPlaced)
|
|
563
|
+
continue;
|
|
564
|
+
const levelId = resolveLevelId(node, nodes);
|
|
565
|
+
if (!levels.has(levelId))
|
|
566
|
+
continue;
|
|
567
|
+
let context = contexts.get(levelId);
|
|
568
|
+
if (!context) {
|
|
569
|
+
context = { walls: [], slabs: [], consumers: [], polygons: new Map() };
|
|
570
|
+
contexts.set(levelId, context);
|
|
571
|
+
}
|
|
572
|
+
if (node.type === 'wall')
|
|
573
|
+
context.walls.push(node);
|
|
574
|
+
if (node.type === 'slab')
|
|
575
|
+
context.slabs.push(node);
|
|
576
|
+
if (node.type === 'wall' || floorPlaced)
|
|
577
|
+
context.consumers.push(node);
|
|
578
|
+
}
|
|
579
|
+
return contexts;
|
|
580
|
+
}
|
|
581
|
+
function cachedSlabPolygon(slab, context) {
|
|
582
|
+
let polygon = context.polygons.get(slab.id);
|
|
583
|
+
if (!polygon) {
|
|
584
|
+
polygon = getRenderableSlabPolygon(slab, {
|
|
585
|
+
walls: context.walls,
|
|
586
|
+
siblingSlabs: context.slabs.filter((sibling) => sibling.id !== slab.id),
|
|
587
|
+
});
|
|
588
|
+
context.polygons.set(slab.id, polygon);
|
|
589
|
+
}
|
|
590
|
+
return polygon;
|
|
591
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AnyNode, FenceNode, WallNode } from '../../schema';
|
|
1
|
+
import type { AnyNode, AnyNodeId, FenceNode, WallNode } from '../../schema/index.js';
|
|
2
2
|
export type SupportSlabPatch = {
|
|
3
3
|
supportSlabId: string | undefined;
|
|
4
4
|
};
|
|
@@ -13,8 +13,29 @@ export type SupportSlabPatchOptions = {
|
|
|
13
13
|
maxElevation?: number | null;
|
|
14
14
|
/** Pointer- or snap-decided host. Ground is a first-class support source. */
|
|
15
15
|
preferredSlabId?: string | null;
|
|
16
|
+
/** Persist even an unambiguous host so later overlapping slabs cannot re-elect it. */
|
|
17
|
+
pinSupport?: boolean;
|
|
18
|
+
};
|
|
19
|
+
export type FrozenFloorPlacementOptions = {
|
|
20
|
+
/** Canonical position before floor/support lift is applied. */
|
|
21
|
+
position: [number, number, number];
|
|
22
|
+
rotation?: unknown;
|
|
23
|
+
/** Exact level-local elevation hit on a non-slab construction surface. */
|
|
24
|
+
elevation: number;
|
|
25
|
+
/** Slab/ground supporting that construction surface, when known. */
|
|
26
|
+
preferredSlabId?: string | null;
|
|
16
27
|
};
|
|
17
28
|
export declare function resolveSupportSlabPatch(node: AnyNode, nodes: Record<string, AnyNode>, options?: SupportSlabPatchOptions): SupportSlabPatch;
|
|
29
|
+
/**
|
|
30
|
+
* Freeze an exact pointed node-top elevation into a floor-placed node's
|
|
31
|
+
* existing canonical Y offset, while pinning the slab/ground beneath that
|
|
32
|
+
* surface. This deliberately does not create a live hosting edge to the
|
|
33
|
+
* pointed node: arbitrary mesh faces can be edited or sloped, so placement
|
|
34
|
+
* captures the plane the user chose at commit time.
|
|
35
|
+
*/
|
|
36
|
+
export declare function resolveFrozenFloorPlacementPatch(node: AnyNode, nodes: Record<string, AnyNode>, options: FrozenFloorPlacementOptions): SupportSlabPatch & {
|
|
37
|
+
position: [number, number, number];
|
|
38
|
+
};
|
|
18
39
|
export declare function resolveWallSupportSlabPatch(wall: WallNode, nodes: Record<string, AnyNode>, options?: SupportSlabPatchOptions): SupportSlabPatch;
|
|
19
40
|
/**
|
|
20
41
|
* Re-elect a moved wall without discarding an explicit construction source.
|
|
@@ -48,4 +69,27 @@ export type FenceSupportInput = Pick<FenceNode, 'start' | 'end' | 'curveOffset'
|
|
|
48
69
|
* via the same absent-host default. Pure; exported for tests.
|
|
49
70
|
*/
|
|
50
71
|
export declare function resolveFenceSupportSlabPatch(fence: FenceSupportInput, nodes: Record<string, AnyNode>, options?: SupportSlabPatchOptions): SupportSlabPatch;
|
|
72
|
+
export type FenceConstructionOptions = {
|
|
73
|
+
supportCap?: number | null;
|
|
74
|
+
preferredSupportSlabId?: string | null;
|
|
75
|
+
constructionElevation?: number | null;
|
|
76
|
+
};
|
|
77
|
+
export declare function resolveFenceConstructionSupport(fence: FenceNode, levelId: string, nodes: Record<string, AnyNode>, options?: FenceConstructionOptions): FenceNode;
|
|
78
|
+
export type WallConstructionOptions = {
|
|
79
|
+
supportCap?: number | null;
|
|
80
|
+
preferredSupportSlabId?: string | null;
|
|
81
|
+
constructionElevation?: number | null;
|
|
82
|
+
constructionHeight?: number | null;
|
|
83
|
+
flatConstructionBase?: boolean;
|
|
84
|
+
constructionSourceNodeId?: AnyNodeId | null;
|
|
85
|
+
};
|
|
86
|
+
export declare function resolveTerrainWallConstructionOptions(nodes: Record<string, AnyNode>, levelId: string, point: readonly [number, number], defaults?: Record<string, unknown>): WallConstructionOptions | undefined;
|
|
87
|
+
export type WallConstructionResolution = {
|
|
88
|
+
walls: WallNode[];
|
|
89
|
+
sourceSupportUpdate: {
|
|
90
|
+
id: AnyNodeId;
|
|
91
|
+
data: SupportSlabPatch;
|
|
92
|
+
} | null;
|
|
93
|
+
};
|
|
94
|
+
export declare function resolveWallConstruction(nodes: Record<string, AnyNode>, levelId: string, walls: readonly WallNode[], options?: WallConstructionOptions): WallConstructionResolution;
|
|
51
95
|
//# sourceMappingURL=support-host-patch.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"support-host-patch.d.ts","sourceRoot":"","sources":["../../../src/hooks/spatial-grid/support-host-patch.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"support-host-patch.d.ts","sourceRoot":"","sources":["../../../src/hooks/spatial-grid/support-host-patch.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { levelBaseElevationAt, terrainSupportLift } from '../../lib/terrain-support.js';
|
|
2
|
+
import { nodeRegistry } from '../../registry/index.js';
|
|
3
|
+
import { DEFAULT_LEVEL_HEIGHT } from '../../services/level-height.js';
|
|
4
|
+
import { getWallCurveFrameAt, isCurvedWall } from '../../systems/wall/wall-curve.js';
|
|
5
|
+
import { GROUND_SUPPORT_ID, getFloorPlacedElevation, getFloorPlacedFootprints, } from './floor-placed-elevation.js';
|
|
6
|
+
import { SUPPORT_ELEVATION_EPSILON, spatialGridManager } from './spatial-grid-manager.js';
|
|
5
7
|
export function resolveSupportSlabPatch(node, nodes, options) {
|
|
6
8
|
const floorPlaced = nodeRegistry.get(node.type)?.capabilities?.floorPlaced;
|
|
7
9
|
if (!floorPlaced || (floorPlaced.applies && !floorPlaced.applies(node))) {
|
|
@@ -13,6 +15,21 @@ export function resolveSupportSlabPatch(node, nodes, options) {
|
|
|
13
15
|
return { supportSlabId: undefined };
|
|
14
16
|
const maxElevation = options?.maxElevation;
|
|
15
17
|
const footprints = getFloorPlacedFootprints(floorPlaced, node, { nodes });
|
|
18
|
+
if (options?.preferredSlabId === GROUND_SUPPORT_ID) {
|
|
19
|
+
return { supportSlabId: GROUND_SUPPORT_ID };
|
|
20
|
+
}
|
|
21
|
+
if (options?.preferredSlabId) {
|
|
22
|
+
for (const footprint of footprints) {
|
|
23
|
+
const position = footprint.position ?? node.position;
|
|
24
|
+
if (!Array.isArray(position) || position.length !== 3)
|
|
25
|
+
continue;
|
|
26
|
+
const elevation = spatialGridManager.getHostSlabElevationForFootprint(parent.id, options.preferredSlabId, position, footprint.dimensions, footprint.rotation);
|
|
27
|
+
if (elevation !== null &&
|
|
28
|
+
(maxElevation == null || elevation <= maxElevation + SUPPORT_ELEVATION_EPSILON)) {
|
|
29
|
+
return { supportSlabId: options.preferredSlabId };
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
16
33
|
const candidateElevations = new Set();
|
|
17
34
|
let winner = null;
|
|
18
35
|
let cappedOut = false;
|
|
@@ -32,12 +49,54 @@ export function resolveSupportSlabPatch(node, nodes, options) {
|
|
|
32
49
|
}
|
|
33
50
|
}
|
|
34
51
|
if (winner !== null) {
|
|
35
|
-
return {
|
|
52
|
+
return {
|
|
53
|
+
supportSlabId: options?.pinSupport || candidateElevations.size >= 2 ? winner.slabId : undefined,
|
|
54
|
+
};
|
|
36
55
|
}
|
|
37
56
|
// Capped election chose the ground while overlapping slabs sit above the
|
|
38
57
|
// cap: persist the ground host, or the uncapped per-frame election would
|
|
39
58
|
// lift the committed node back onto the deck.
|
|
40
|
-
return {
|
|
59
|
+
return {
|
|
60
|
+
supportSlabId: options?.pinSupport || cappedOut ? GROUND_SUPPORT_ID : undefined,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Freeze an exact pointed node-top elevation into a floor-placed node's
|
|
65
|
+
* existing canonical Y offset, while pinning the slab/ground beneath that
|
|
66
|
+
* surface. This deliberately does not create a live hosting edge to the
|
|
67
|
+
* pointed node: arbitrary mesh faces can be edited or sloped, so placement
|
|
68
|
+
* captures the plane the user chose at commit time.
|
|
69
|
+
*/
|
|
70
|
+
export function resolveFrozenFloorPlacementPatch(node, nodes, options) {
|
|
71
|
+
const effectiveNode = {
|
|
72
|
+
...node,
|
|
73
|
+
position: options.position,
|
|
74
|
+
...(options.rotation !== undefined ? { rotation: options.rotation } : {}),
|
|
75
|
+
};
|
|
76
|
+
const floorPlaced = nodeRegistry.get(effectiveNode.type)?.capabilities?.floorPlaced;
|
|
77
|
+
if (!floorPlaced || (floorPlaced.applies && !floorPlaced.applies(effectiveNode))) {
|
|
78
|
+
return { supportSlabId: undefined, position: options.position };
|
|
79
|
+
}
|
|
80
|
+
const supportPatch = resolveSupportSlabPatch(effectiveNode, nodes, {
|
|
81
|
+
maxElevation: options.elevation,
|
|
82
|
+
preferredSlabId: options.preferredSlabId,
|
|
83
|
+
pinSupport: true,
|
|
84
|
+
});
|
|
85
|
+
const pinnedNode = { ...effectiveNode, ...supportPatch };
|
|
86
|
+
const supportElevation = getFloorPlacedElevation({
|
|
87
|
+
node: pinnedNode,
|
|
88
|
+
nodes,
|
|
89
|
+
position: options.position,
|
|
90
|
+
rotation: options.rotation,
|
|
91
|
+
});
|
|
92
|
+
return {
|
|
93
|
+
...supportPatch,
|
|
94
|
+
position: [
|
|
95
|
+
options.position[0],
|
|
96
|
+
options.position[1] + options.elevation - supportElevation,
|
|
97
|
+
options.position[2],
|
|
98
|
+
],
|
|
99
|
+
};
|
|
41
100
|
}
|
|
42
101
|
export function resolveWallSupportSlabPatch(wall, nodes, options) {
|
|
43
102
|
const parent = wall.parentId ? nodes[wall.parentId] : null;
|
|
@@ -138,6 +197,9 @@ export function resolveFenceSupportSlabPatch(fence, nodes, options) {
|
|
|
138
197
|
const points = fenceCenterlinePoints(fence);
|
|
139
198
|
const candidateElevations = new Set();
|
|
140
199
|
let winner = null;
|
|
200
|
+
if (options?.preferredSlabId === GROUND_SUPPORT_ID) {
|
|
201
|
+
return { supportSlabId: GROUND_SUPPORT_ID };
|
|
202
|
+
}
|
|
141
203
|
for (let i = 1; i < points.length; i++) {
|
|
142
204
|
const [ax, az] = points[i - 1];
|
|
143
205
|
const [bx, bz] = points[i];
|
|
@@ -149,6 +211,13 @@ export function resolveFenceSupportSlabPatch(fence, nodes, options) {
|
|
|
149
211
|
// getItemFootprint's rotation convention: local +X maps to
|
|
150
212
|
// (cos yRot, sin yRot) in XZ, so the segment angle aligns the band.
|
|
151
213
|
const rotation = [0, Math.atan2(bz - az, bx - ax), 0];
|
|
214
|
+
if (options?.preferredSlabId) {
|
|
215
|
+
const preferredElevation = spatialGridManager.getHostSlabElevationForFootprint(parent.id, options.preferredSlabId, position, dimensions, rotation);
|
|
216
|
+
if (preferredElevation !== null &&
|
|
217
|
+
(maxElevation == null || preferredElevation <= maxElevation + SUPPORT_ELEVATION_EPSILON)) {
|
|
218
|
+
return { supportSlabId: options.preferredSlabId };
|
|
219
|
+
}
|
|
220
|
+
}
|
|
152
221
|
const candidates = spatialGridManager.getSupportCandidatesForFootprint(parent.id, position, dimensions, rotation);
|
|
153
222
|
for (const candidate of candidates)
|
|
154
223
|
candidateElevations.add(candidate.elevation);
|
|
@@ -157,8 +226,104 @@ export function resolveFenceSupportSlabPatch(fence, nodes, options) {
|
|
|
157
226
|
winner = { slabId: support.slabId, elevation: support.elevation };
|
|
158
227
|
}
|
|
159
228
|
}
|
|
160
|
-
if (winner === null)
|
|
161
|
-
return { supportSlabId: undefined };
|
|
229
|
+
if (winner === null) {
|
|
230
|
+
return { supportSlabId: options?.pinSupport ? GROUND_SUPPORT_ID : undefined };
|
|
231
|
+
}
|
|
162
232
|
const persist = candidateElevations.size >= 2 || winner.elevation > SUPPORT_ELEVATION_EPSILON;
|
|
163
|
-
return { supportSlabId: persist ? winner.slabId : undefined };
|
|
233
|
+
return { supportSlabId: options?.pinSupport || persist ? winner.slabId : undefined };
|
|
234
|
+
}
|
|
235
|
+
export function resolveFenceConstructionSupport(fence, levelId, nodes, options) {
|
|
236
|
+
const supportPatch = resolveFenceSupportSlabPatch({ ...fence, parentId: levelId }, nodes, {
|
|
237
|
+
maxElevation: options?.supportCap ?? null,
|
|
238
|
+
preferredSlabId: options?.preferredSupportSlabId ?? null,
|
|
239
|
+
pinSupport: options?.constructionElevation != null,
|
|
240
|
+
});
|
|
241
|
+
const host = supportPatch.supportSlabId ? nodes[supportPatch.supportSlabId] : null;
|
|
242
|
+
const baseElevation = host?.type === 'slab'
|
|
243
|
+
? host.elevation
|
|
244
|
+
: levelBaseElevationAt(nodes, levelId, fence.start[0], fence.start[1]);
|
|
245
|
+
const supportOffset = options?.constructionElevation == null
|
|
246
|
+
? fence.supportOffset
|
|
247
|
+
: options.constructionElevation - baseElevation;
|
|
248
|
+
return {
|
|
249
|
+
...fence,
|
|
250
|
+
...supportPatch,
|
|
251
|
+
supportOffset: supportOffset != null && Math.abs(supportOffset) > 1e-6 ? supportOffset : undefined,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
export function resolveTerrainWallConstructionOptions(nodes, levelId, point, defaults) {
|
|
255
|
+
const constructionElevation = terrainSupportLift(nodes, levelId, point[0], point[1]);
|
|
256
|
+
if (constructionElevation == null)
|
|
257
|
+
return undefined;
|
|
258
|
+
const level = nodes[levelId];
|
|
259
|
+
const constructionHeight = typeof defaults?.height === 'number'
|
|
260
|
+
? defaults.height
|
|
261
|
+
: level?.type === 'level'
|
|
262
|
+
? (level.height ?? DEFAULT_LEVEL_HEIGHT)
|
|
263
|
+
: DEFAULT_LEVEL_HEIGHT;
|
|
264
|
+
return {
|
|
265
|
+
constructionElevation,
|
|
266
|
+
constructionHeight,
|
|
267
|
+
supportCap: constructionElevation,
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
export function resolveWallConstruction(nodes, levelId, walls, options) {
|
|
271
|
+
let resolvedNodes = nodes;
|
|
272
|
+
let sourceSupportUpdate = null;
|
|
273
|
+
const constructionSourceNodeId = options?.constructionSourceNodeId;
|
|
274
|
+
const constructionSourceIsSlab = constructionSourceNodeId
|
|
275
|
+
? nodes[constructionSourceNodeId]?.type === 'slab'
|
|
276
|
+
: false;
|
|
277
|
+
if (constructionSourceNodeId) {
|
|
278
|
+
const sourceNode = nodes[constructionSourceNodeId];
|
|
279
|
+
const currentSupport = sourceNode && 'supportSlabId' in sourceNode
|
|
280
|
+
? sourceNode.supportSlabId
|
|
281
|
+
: undefined;
|
|
282
|
+
if (sourceNode && currentSupport == null) {
|
|
283
|
+
const data = resolveSupportSlabPatch(sourceNode, nodes, { pinSupport: true });
|
|
284
|
+
if (data.supportSlabId != null) {
|
|
285
|
+
sourceSupportUpdate = { id: constructionSourceNodeId, data };
|
|
286
|
+
resolvedNodes = {
|
|
287
|
+
...nodes,
|
|
288
|
+
[constructionSourceNodeId]: { ...sourceNode, ...data },
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
const resolvedWalls = walls.map((createdWall) => {
|
|
294
|
+
const wallWithParent = { ...createdWall, parentId: levelId };
|
|
295
|
+
const terrainBase = terrainSupportLift(resolvedNodes, levelId, createdWall.start[0], createdWall.start[1]);
|
|
296
|
+
const wallOptions = options?.preferredSupportSlabId === GROUND_SUPPORT_ID &&
|
|
297
|
+
terrainBase == null &&
|
|
298
|
+
!options.flatConstructionBase
|
|
299
|
+
? undefined
|
|
300
|
+
: options;
|
|
301
|
+
const flatConstructionBase = wallOptions?.flatConstructionBase === true && !constructionSourceIsSlab;
|
|
302
|
+
const preferredSupportSlabId = flatConstructionBase
|
|
303
|
+
? GROUND_SUPPORT_ID
|
|
304
|
+
: (wallOptions?.preferredSupportSlabId ??
|
|
305
|
+
(wallOptions?.constructionElevation != null && terrainBase != null
|
|
306
|
+
? GROUND_SUPPORT_ID
|
|
307
|
+
: null));
|
|
308
|
+
const supportPatch = resolveWallSupportSlabPatch(wallWithParent, resolvedNodes, {
|
|
309
|
+
maxElevation: wallOptions?.supportCap ?? null,
|
|
310
|
+
preferredSlabId: preferredSupportSlabId,
|
|
311
|
+
});
|
|
312
|
+
const sourceSupport = spatialGridManager.getSlabSupportForWall(levelId, createdWall.start, createdWall.end, createdWall.curveOffset, createdWall.thickness, supportPatch.supportSlabId, wallOptions?.supportCap ?? null);
|
|
313
|
+
const groundDraft = preferredSupportSlabId === GROUND_SUPPORT_ID && (terrainBase != null || flatConstructionBase);
|
|
314
|
+
const supportOffset = groundDraft && wallOptions?.constructionElevation != null
|
|
315
|
+
? wallOptions.constructionElevation - sourceSupport.elevation
|
|
316
|
+
: undefined;
|
|
317
|
+
const preserveDraftHeight = groundDraft &&
|
|
318
|
+
createdWall.height == null &&
|
|
319
|
+
wallOptions?.constructionHeight != null &&
|
|
320
|
+
wallOptions.constructionElevation != null;
|
|
321
|
+
return {
|
|
322
|
+
...wallWithParent,
|
|
323
|
+
...supportPatch,
|
|
324
|
+
height: preserveDraftHeight ? wallOptions.constructionHeight : createdWall.height,
|
|
325
|
+
supportOffset: supportOffset != null && Math.abs(supportOffset) > 1e-6 ? supportOffset : undefined,
|
|
326
|
+
};
|
|
327
|
+
});
|
|
328
|
+
return { walls: resolvedWalls, sourceSupportUpdate };
|
|
164
329
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CeilingNode, LevelNode, WallNode } from '../../schema';
|
|
1
|
+
import type { CeilingNode, LevelNode, WallNode } from '../../schema/index.js';
|
|
2
2
|
export declare function useSpatialQuery(): {
|
|
3
3
|
canPlaceOnFloor: (levelId: LevelNode["id"], position: [number, number, number], dimensions: [number, number, number], rotation: [number, number, number], ignoreIds?: string[]) => {
|
|
4
4
|
valid: boolean;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useCallback } from 'react';
|
|
2
|
-
import { spatialGridManager } from './spatial-grid-manager';
|
|
2
|
+
import { spatialGridManager } from './spatial-grid-manager.js';
|
|
3
3
|
export function useSpatialQuery() {
|
|
4
4
|
const canPlaceOnFloor = useCallback((levelId, position, dimensions, rotation, ignoreIds) => {
|
|
5
5
|
return spatialGridManager.canPlaceOnFloor(levelId, position, dimensions, rotation, ignoreIds);
|