@pascal-app/core 1.0.0 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/capture/index.d.ts +2 -2
- package/dist/capture/index.js +2 -2
- package/dist/capture/schema.d.ts.map +1 -1
- package/dist/capture/schema.js +2 -0
- package/dist/capture/source.d.ts +1 -1
- package/dist/capture/source.js +1 -1
- package/dist/events/bus.d.ts +6 -3
- package/dist/events/bus.d.ts.map +1 -1
- 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 +263 -84
- package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts.map +1 -1
- package/dist/hooks/spatial-grid/spatial-grid-sync.js +77 -13
- package/dist/hooks/spatial-grid/support-host-patch.d.ts +1 -1
- package/dist/hooks/spatial-grid/support-host-patch.js +6 -6
- 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 +77 -72
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +74 -69
- 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/node-visibility.d.ts +12 -0
- package/dist/lib/node-visibility.d.ts.map +1 -0
- package/dist/lib/node-visibility.js +12 -0
- 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/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 +2 -2
- package/dist/lib/slab-polygon.js +2 -2
- package/dist/lib/space-detection.d.ts +1 -1
- package/dist/lib/space-detection.d.ts.map +1 -1
- package/dist/lib/space-detection.js +16 -11
- 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 +51 -0
- package/dist/procedural-items/query.d.ts.map +1 -0
- package/dist/procedural-items/query.js +342 -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 +40 -5
- package/dist/registry/handles.d.ts.map +1 -1
- package/dist/registry/index.d.ts +6 -6
- package/dist/registry/index.d.ts.map +1 -1
- package/dist/registry/index.js +4 -4
- package/dist/registry/registry.d.ts +1 -1
- package/dist/registry/relations-resolver.d.ts +2 -2
- package/dist/registry/relations-resolver.js +1 -1
- package/dist/registry/scene-api.d.ts +2 -2
- package/dist/registry/scene-api.js +2 -2
- package/dist/registry/subtree.d.ts +1 -1
- package/dist/registry/subtree.d.ts.map +1 -1
- package/dist/registry/subtree.js +8 -2
- package/dist/registry/types.d.ts +32 -10
- 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.js +3 -3
- package/dist/schema/__fixtures__/node-fixtures.d.ts +1 -1
- package/dist/schema/__fixtures__/node-fixtures.d.ts.map +1 -1
- package/dist/schema/__fixtures__/node-fixtures.js +4 -2
- package/dist/schema/base.js +1 -1
- package/dist/schema/collections.d.ts +1 -1
- package/dist/schema/collections.js +1 -1
- package/dist/schema/compiled-node-parsers.d.ts +1 -1
- package/dist/schema/compiled-node-parsers.js +1 -1
- package/dist/schema/index.d.ts +74 -70
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +65 -61
- package/dist/schema/material.d.ts +1 -1
- package/dist/schema/material.js +1 -1
- package/dist/schema/nodes/automatic-downspout.d.ts +4 -4
- package/dist/schema/nodes/automatic-downspout.js +5 -5
- package/dist/schema/nodes/block.d.ts +3 -3
- package/dist/schema/nodes/block.d.ts.map +1 -1
- package/dist/schema/nodes/block.js +24 -12
- package/dist/schema/nodes/box-vent.js +2 -2
- package/dist/schema/nodes/building.d.ts +1 -1
- 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 +4 -4
- package/dist/schema/nodes/cabinet.js +4 -4
- package/dist/schema/nodes/ceiling.d.ts +1 -1
- package/dist/schema/nodes/ceiling.js +5 -5
- package/dist/schema/nodes/chimney.js +2 -2
- package/dist/schema/nodes/column.d.ts +1 -0
- 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 +3 -3
- package/dist/schema/nodes/construction-dimension.js +2 -2
- package/dist/schema/nodes/cupola.d.ts +1 -1
- package/dist/schema/nodes/cupola.js +2 -2
- package/dist/schema/nodes/curtain-wall.d.ts +129 -0
- package/dist/schema/nodes/curtain-wall.d.ts.map +1 -0
- package/dist/schema/nodes/curtain-wall.js +49 -0
- package/dist/schema/nodes/door.d.ts +2 -2
- package/dist/schema/nodes/door.js +2 -2
- package/dist/schema/nodes/dormer.d.ts +3 -3
- package/dist/schema/nodes/dormer.js +4 -4
- package/dist/schema/nodes/downspout.js +2 -2
- package/dist/schema/nodes/duct-fitting.js +1 -1
- package/dist/schema/nodes/duct-segment.js +2 -2
- package/dist/schema/nodes/duct-terminal.js +1 -1
- package/dist/schema/nodes/elevator.js +2 -2
- package/dist/schema/nodes/eyebrow-vent.js +2 -2
- package/dist/schema/nodes/fence.js +2 -2
- package/dist/schema/nodes/guide.js +2 -2
- package/dist/schema/nodes/gutter.d.ts +1 -1
- package/dist/schema/nodes/gutter.js +4 -4
- 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 -3
- package/dist/schema/nodes/item.js +3 -3
- package/dist/schema/nodes/lean-to-extension.js +4 -4
- package/dist/schema/nodes/level.d.ts +1 -1
- package/dist/schema/nodes/level.d.ts.map +1 -1
- package/dist/schema/nodes/level.js +1 -1
- package/dist/schema/nodes/lineset.js +1 -1
- package/dist/schema/nodes/liquid-line.js +1 -1
- package/dist/schema/nodes/measurement.js +2 -2
- package/dist/schema/nodes/pipe-fitting.d.ts +1 -1
- package/dist/schema/nodes/pipe-fitting.js +1 -1
- package/dist/schema/nodes/pipe-segment.d.ts +1 -1
- package/dist/schema/nodes/pipe-segment.js +2 -2
- package/dist/schema/nodes/pipe-trap.d.ts +1 -1
- package/dist/schema/nodes/pipe-trap.js +1 -1
- package/dist/schema/nodes/ridge-vent.d.ts +1 -1
- package/dist/schema/nodes/ridge-vent.js +3 -3
- package/dist/schema/nodes/roof-segment-shape.d.ts +1 -1
- package/dist/schema/nodes/roof-segment-shape.js +1 -1
- package/dist/schema/nodes/roof-segment-walls.d.ts +1 -1
- package/dist/schema/nodes/roof-segment-walls.js +1 -1
- package/dist/schema/nodes/roof-segment.d.ts +2 -2
- package/dist/schema/nodes/roof-segment.js +2 -2
- package/dist/schema/nodes/roof.d.ts +1 -1
- package/dist/schema/nodes/roof.js +3 -3
- package/dist/schema/nodes/scan.js +3 -3
- package/dist/schema/nodes/shelf.d.ts +1 -1
- package/dist/schema/nodes/shelf.d.ts.map +1 -1
- package/dist/schema/nodes/shelf.js +3 -4
- package/dist/schema/nodes/site.js +2 -2
- package/dist/schema/nodes/skylight.d.ts +4 -4
- package/dist/schema/nodes/skylight.js +2 -2
- package/dist/schema/nodes/slab.js +3 -3
- package/dist/schema/nodes/solar-panel.js +3 -3
- package/dist/schema/nodes/spawn.js +1 -1
- package/dist/schema/nodes/stair-segment.js +2 -2
- package/dist/schema/nodes/stair.d.ts +1 -1
- package/dist/schema/nodes/stair.js +3 -3
- package/dist/schema/nodes/structural-grid.js +1 -1
- package/dist/schema/nodes/turbine-vent.d.ts +1 -1
- package/dist/schema/nodes/turbine-vent.js +2 -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 +75 -2
- package/dist/schema/nodes/wall.d.ts.map +1 -1
- package/dist/schema/nodes/wall.js +10 -6
- package/dist/schema/nodes/window.js +2 -2
- package/dist/schema/nodes/zone.js +1 -1
- package/dist/schema/scene-material.js +2 -2
- package/dist/schema/types.d.ts +417 -22
- package/dist/schema/types.d.ts.map +1 -1
- package/dist/schema/types.js +56 -49
- package/dist/services/__fixtures__/hosting.d.ts +3 -0
- package/dist/services/__fixtures__/hosting.d.ts.map +1 -0
- package/dist/services/__fixtures__/hosting.js +9 -0
- package/dist/services/__fixtures__/shelf-surface-rows.d.ts +4 -0
- package/dist/services/__fixtures__/shelf-surface-rows.d.ts.map +1 -0
- package/dist/services/__fixtures__/shelf-surface-rows.js +18 -0
- 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 +5 -8
- package/dist/services/hosting.d.ts.map +1 -1
- package/dist/services/hosting.js +25 -18
- 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/snap.d.ts +3 -0
- package/dist/services/snap.d.ts.map +1 -1
- package/dist/services/snap.js +11 -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 +92 -0
- package/dist/services/surface-hosting.d.ts.map +1 -0
- package/dist/services/surface-hosting.js +305 -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 +2 -2
- package/dist/services/system-graph.js +2 -2
- 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 +2 -2
- package/dist/store/actions/node-actions.d.ts.map +1 -1
- package/dist/store/actions/node-actions.js +50 -104
- package/dist/store/history-control.d.ts +3 -3
- package/dist/store/history-invalidation.d.ts +1 -1
- package/dist/store/history-invalidation.js +1 -1
- 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 +4 -4
- package/dist/store/use-scene.d.ts.map +1 -1
- package/dist/store/use-scene.js +50 -32
- 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.js +3 -3
- package/dist/systems/roof/roof-elevation.d.ts +2 -2
- package/dist/systems/roof/roof-elevation.js +6 -6
- package/dist/systems/roof/roof-footprint.d.ts +1 -1
- package/dist/systems/roof/roof-footprint.js +3 -3
- 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 +2 -2
- package/dist/systems/stair/stair-flight.js +2 -2
- package/dist/systems/stair/stair-footprint.d.ts +1 -1
- package/dist/systems/stair/stair-opening-preview.d.ts +248 -87
- 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.js +8 -8
- package/dist/systems/stair/stair-rise.d.ts +1 -1
- package/dist/systems/stair/stair-rise.js +3 -3
- package/dist/systems/wall/wall-curve.d.ts +2 -2
- package/dist/systems/wall/wall-footprint.d.ts +3 -3
- package/dist/systems/wall/wall-footprint.js +3 -3
- package/dist/systems/wall/wall-merge.d.ts +38 -0
- package/dist/systems/wall/wall-merge.d.ts.map +1 -0
- package/dist/systems/wall/wall-merge.js +240 -0
- 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-operations.d.ts +28 -0
- package/dist/systems/wall/wall-operations.d.ts.map +1 -0
- package/dist/systems/wall/wall-operations.js +145 -0
- package/dist/systems/wall/wall-top.d.ts +1 -1
- package/dist/systems/wall/wall-topology.d.ts +9 -2
- package/dist/systems/wall/wall-topology.d.ts.map +1 -1
- package/dist/systems/wall/wall-topology.js +57 -9
- 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 +9 -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 +5 -2
- package/dist/validation/validate-build-json.d.ts.map +1 -1
- package/dist/validation/validate-build-json.js +57 -4
- package/package.json +15 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stair-opening-preview.d.ts","sourceRoot":"","sources":["../../../src/systems/stair/stair-opening-preview.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAC7E,OAA6B,EAAE,KAAK,iBAAiB,EAAE,MAAM,qCAAqC,CAAA;AAClG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAA;AAGpE,KAAK,oBAAoB,GAAG;IAC1B,EAAE,EAAE,SAAS,CAAA;IACb,IAAI,EAAE,OAAO,CAAC,QAAQ,GAAG,WAAW,CAAC,CAAA;CACtC,CAAA;AAoBD,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,cAAc,EAAE,WAAW,CAAC,MAAM,EAAE,aAAa,CAAC,EAClD,aAAa,EAAE,WAAW,CAAC,MAAM,EAAE,iBAAiB,CAAC,EACrD,iBAAiB,EAAE,WAAW,CAAC,MAAM,CAAC,WAYvC;AAED,wBAAgB,kCAAkC,CAChD,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,cAAc,EAAE,WAAW,CAAC,MAAM,EAAE,aAAa,CAAC,EAClD,aAAa,EAAE,WAAW,CAAC,MAAM,EAAE,iBAAiB,CAAC,EACrD,iBAAiB,EAAE,WAAW,CAAC,MAAM,CAAC
|
|
1
|
+
{"version":3,"file":"stair-opening-preview.d.ts","sourceRoot":"","sources":["../../../src/systems/stair/stair-opening-preview.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAC7E,OAA6B,EAAE,KAAK,iBAAiB,EAAE,MAAM,qCAAqC,CAAA;AAClG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAA;AAGpE,KAAK,oBAAoB,GAAG;IAC1B,EAAE,EAAE,SAAS,CAAA;IACb,IAAI,EAAE,OAAO,CAAC,QAAQ,GAAG,WAAW,CAAC,CAAA;CACtC,CAAA;AAoBD,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,cAAc,EAAE,WAAW,CAAC,MAAM,EAAE,aAAa,CAAC,EAClD,aAAa,EAAE,WAAW,CAAC,MAAM,EAAE,iBAAiB,CAAC,EACrD,iBAAiB,EAAE,WAAW,CAAC,MAAM,CAAC,WAYvC;AAED,wBAAgB,kCAAkC,CAChD,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,cAAc,EAAE,WAAW,CAAC,MAAM,EAAE,aAAa,CAAC,EAClD,aAAa,EAAE,WAAW,CAAC,MAAM,EAAE,iBAAiB,CAAC,EACrD,iBAAiB,EAAE,WAAW,CAAC,MAAM,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwBvC;AAED,wBAAgB,qCAAqC;;mBAUlC,oBAAoB,EAAE;;EAiCxC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import useLiveNodeOverrides, {} from '../../store/use-live-node-overrides';
|
|
2
|
-
import useScene from '../../store/use-scene';
|
|
1
|
+
import useLiveNodeOverrides, {} from '../../store/use-live-node-overrides.js';
|
|
2
|
+
import useScene from '../../store/use-scene.js';
|
|
3
3
|
const SURFACE_OPENING_FIELDS = ['holes', 'holeMetadata'];
|
|
4
4
|
function isSurface(node) {
|
|
5
5
|
return node?.type === 'slab' || node?.type === 'ceiling';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AnyNode, AnyNodeId, CeilingNode, SlabNode } from '../../schema';
|
|
1
|
+
import type { AnyNode, AnyNodeId, CeilingNode, SlabNode } from '../../schema/index.js';
|
|
2
2
|
export declare function syncAutoStairOpenings(nodes: Record<string, AnyNode>): {
|
|
3
3
|
id: AnyNodeId;
|
|
4
4
|
data: Partial<SlabNode | CeilingNode>;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { resolveBuildingForLevel, resolveLevelId } from '../../hooks/spatial-grid/spatial-grid-sync';
|
|
2
|
-
import { polygonContainsPolygon, polygonsOverlap } from '../../lib/polygon-relations';
|
|
3
|
-
import { resolveCeilingHeight } from '../../services/level-height';
|
|
4
|
-
import { getLevelElevations } from '../../services/storey';
|
|
5
|
-
import { computeSegmentTransforms, rotateXZ } from './stair-footprint';
|
|
6
|
-
import { resolveStairTotalRise } from './stair-rise';
|
|
1
|
+
import { resolveBuildingForLevel, resolveLevelId } from '../../hooks/spatial-grid/spatial-grid-sync.js';
|
|
2
|
+
import { polygonContainsPolygon, polygonsOverlap } from '../../lib/polygon-relations.js';
|
|
3
|
+
import { resolveCeilingHeight } from '../../services/level-height.js';
|
|
4
|
+
import { getLevelElevations } from '../../services/storey.js';
|
|
5
|
+
import { computeSegmentTransforms, rotateXZ } from './stair-footprint.js';
|
|
6
|
+
import { resolveStairTotalRise } from './stair-rise.js';
|
|
7
7
|
const CURVED_STAIR_SLAB_OPENING_RATIO = 0.8;
|
|
8
8
|
const STRAIGHT_STAIR_TARGET_THRESHOLD_MIN = 0.35;
|
|
9
9
|
const STAIR_SLAB_OPENING_TIGHTENING = 0;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { useEffect } from 'react';
|
|
3
|
-
import { pauseSceneHistory, resumeSceneHistory } from '../../store/history-control';
|
|
4
|
-
import { queueSceneNormalization } from '../../store/scene-hydration';
|
|
5
|
-
import useLiveNodeOverrides from '../../store/use-live-node-overrides';
|
|
6
|
-
import useLiveTransforms from '../../store/use-live-transforms';
|
|
7
|
-
import useScene from '../../store/use-scene';
|
|
8
|
-
import { createSurfaceOpeningPreviewController, getNodesWithLiveStairOpeningInputs, hasLiveStairOpeningInputs, } from './stair-opening-preview';
|
|
9
|
-
import { syncAutoStairOpenings } from './stair-opening-sync';
|
|
10
|
-
import { syncStairRises } from './stair-rise';
|
|
3
|
+
import { pauseSceneHistory, resumeSceneHistory } from '../../store/history-control.js';
|
|
4
|
+
import { queueSceneNormalization } from '../../store/scene-hydration.js';
|
|
5
|
+
import useLiveNodeOverrides from '../../store/use-live-node-overrides.js';
|
|
6
|
+
import useLiveTransforms from '../../store/use-live-transforms.js';
|
|
7
|
+
import useScene from '../../store/use-scene.js';
|
|
8
|
+
import { createSurfaceOpeningPreviewController, getNodesWithLiveStairOpeningInputs, hasLiveStairOpeningInputs, } from './stair-opening-preview.js';
|
|
9
|
+
import { syncAutoStairOpenings } from './stair-opening-sync.js';
|
|
10
|
+
import { syncStairRises } from './stair-rise.js';
|
|
11
11
|
function isOpeningRelevantNode(node) {
|
|
12
12
|
return (node?.type === 'building' ||
|
|
13
13
|
node?.type === 'ceiling' ||
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AnyNode, AnyNodeId, StairNode } from '../../schema';
|
|
1
|
+
import type { AnyNode, AnyNodeId, StairNode } from '../../schema/index.js';
|
|
2
2
|
export declare function resolveStairTotalRise(stair: StairNode, nodes: Record<string, AnyNode>): number;
|
|
3
3
|
/**
|
|
4
4
|
* Keeps straight stairs' flight segments in step with the resolved rise.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { getFloorStackedPosition } from '../../hooks/spatial-grid/floor-placed-elevation';
|
|
2
|
-
import { DEFAULT_LEVEL_HEIGHT } from '../../services/level-height';
|
|
3
|
-
import { getLevelFloorToFloorHeight } from '../../services/storey';
|
|
1
|
+
import { getFloorStackedPosition } from '../../hooks/spatial-grid/floor-placed-elevation.js';
|
|
2
|
+
import { DEFAULT_LEVEL_HEIGHT } from '../../services/level-height.js';
|
|
3
|
+
import { getLevelFloorToFloorHeight } from '../../services/storey.js';
|
|
4
4
|
export function resolveStairTotalRise(stair, nodes) {
|
|
5
5
|
if (stair.totalRise !== undefined)
|
|
6
6
|
return stair.totalRise;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { FenceNode, WallNode } from '../../schema';
|
|
2
|
-
import type { Point2D } from './wall-mitering';
|
|
1
|
+
import type { FenceNode, WallNode } from '../../schema/index.js';
|
|
2
|
+
import type { Point2D } from './wall-mitering.js';
|
|
3
3
|
type WallCurveLike = Pick<WallNode | FenceNode, 'start' | 'end' | 'curveOffset'>;
|
|
4
4
|
type CurveFrame = {
|
|
5
5
|
point: Point2D;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { WallNode } from '../../schema';
|
|
2
|
-
import { type Point2D, type WallMiterData } from './wall-mitering';
|
|
3
|
-
export { calculateLevelMiters, type Point2D, type WallMiterData } from './wall-mitering';
|
|
1
|
+
import type { WallNode } from '../../schema/index.js';
|
|
2
|
+
import { type Point2D, type WallMiterData } from './wall-mitering.js';
|
|
3
|
+
export { calculateLevelMiters, type Point2D, type WallMiterData } from './wall-mitering.js';
|
|
4
4
|
export declare const DEFAULT_WALL_THICKNESS = 0.1;
|
|
5
5
|
export declare const DEFAULT_WALL_HEIGHT = 2.5;
|
|
6
6
|
export declare function getWallThickness(wallNode: WallNode): number;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { getWallSurfacePolygon, isCurvedWall } from './wall-curve';
|
|
2
|
-
import { getWallMiterBoundaryPoints, pointToKey, } from './wall-mitering';
|
|
3
|
-
export { calculateLevelMiters } from './wall-mitering';
|
|
1
|
+
import { getWallSurfacePolygon, isCurvedWall } from './wall-curve.js';
|
|
2
|
+
import { getWallMiterBoundaryPoints, pointToKey, } from './wall-mitering.js';
|
|
3
|
+
export { calculateLevelMiters } from './wall-mitering.js';
|
|
4
4
|
export const DEFAULT_WALL_THICKNESS = 0.1;
|
|
5
5
|
export const DEFAULT_WALL_HEIGHT = 2.5;
|
|
6
6
|
const CURVED_WALL_SURFACE_SEGMENTS = 24;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type AnyNode, type AnyNodeId, type WallNode } from '../../schema/index.js';
|
|
2
|
+
import type { WallTopologyChanges } from './wall-topology.js';
|
|
3
|
+
export type WallAttachmentUpdate = {
|
|
4
|
+
id: AnyNodeId;
|
|
5
|
+
data: Partial<AnyNode>;
|
|
6
|
+
};
|
|
7
|
+
export declare function getWallEndpointAtPoint(wall: Pick<WallNode, 'start' | 'end'>, point: [number, number]): 'start' | 'end' | null;
|
|
8
|
+
/**
|
|
9
|
+
* The first thing two walls disagree on (for the merge's explanation), or null.
|
|
10
|
+
* The delete heal is strict: room sides must match, and a wall following the
|
|
11
|
+
* storey never joins one with an explicit height. An explicit merge compares
|
|
12
|
+
* what is visible instead — `heightOf` resolves each wall's actual height — and
|
|
13
|
+
* leaves the sides to room detection, which reclassifies the merged wall.
|
|
14
|
+
*/
|
|
15
|
+
export declare function wallStyleMismatch(a: WallNode, b: WallNode, options: {
|
|
16
|
+
sides: boolean;
|
|
17
|
+
heightOf?: (wall: WallNode) => number;
|
|
18
|
+
}): string | null;
|
|
19
|
+
export declare function areWallStylesCompatible(a: WallNode, b: WallNode): boolean;
|
|
20
|
+
export declare function areWallsCollinearAcrossPoint(a: WallNode, b: WallNode, sharedPoint: [number, number]): boolean;
|
|
21
|
+
export declare function resolveMergedWallEndpoints(primary: WallNode, secondary: WallNode, sharedPoint: [number, number]): {
|
|
22
|
+
start: [number, number];
|
|
23
|
+
end: [number, number];
|
|
24
|
+
};
|
|
25
|
+
export declare function buildMergedWallAttachmentUpdates(primary: WallNode, secondary: WallNode, mergedWallId: AnyNodeId, mergedStart: [number, number], mergedEnd: [number, number], nodes: Record<AnyNodeId, AnyNode>): WallAttachmentUpdate[];
|
|
26
|
+
/**
|
|
27
|
+
* Merges a straight run of adjoining walls into one — the inverse of a split.
|
|
28
|
+
* Every joint must hold exactly these walls (a T or a cross stays split), and
|
|
29
|
+
* neighbours must continue in line and look alike (`wallStyleMismatch`: same
|
|
30
|
+
* thickness, visible height and finish). The wall with the most attachments
|
|
31
|
+
* keeps its id and height mode; openings and wall items keep their world
|
|
32
|
+
* position on it.
|
|
33
|
+
*/
|
|
34
|
+
export declare function planWallMerge(nodes: Record<AnyNodeId, AnyNode>, wallIds: readonly AnyNodeId[]): {
|
|
35
|
+
changes: WallTopologyChanges;
|
|
36
|
+
wallId: WallNode['id'];
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=wall-merge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wall-merge.d.ts","sourceRoot":"","sources":["../../../src/systems/wall/wall-merge.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,SAAS,EAGd,KAAK,QAAQ,EACd,MAAM,cAAc,CAAA;AACrB,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAK1D,MAAM,MAAM,oBAAoB,GAAG;IAAE,EAAE,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;CAAE,CAAA;AAY5E,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,OAAO,GAAG,KAAK,CAAC,EACrC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,GACtB,OAAO,GAAG,KAAK,GAAG,IAAI,CAIxB;AAMD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,CAAC,EAAE,QAAQ,EACX,CAAC,EAAE,QAAQ,EACX,OAAO,EAAE;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,MAAM,CAAA;CAAE,GACjE,MAAM,GAAG,IAAI,CAuBf;AAED,wBAAgB,uBAAuB,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,WAE/D;AAED,wBAAgB,4BAA4B,CAC1C,CAAC,EAAE,QAAQ,EACX,CAAC,EAAE,QAAQ,EACX,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,WAgB9B;AAED,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,QAAQ,EACjB,SAAS,EAAE,QAAQ,EACnB,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,GAC5B;IAAE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAkBpD;AAyBD,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,QAAQ,EACjB,SAAS,EAAE,QAAQ,EACnB,YAAY,EAAE,SAAS,EACvB,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAC7B,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAC3B,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,GAChC,oBAAoB,EAAE,CAyDxB;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,EACjC,OAAO,EAAE,SAAS,SAAS,EAAE,GAC5B;IAAE,OAAO,EAAE,mBAAmB,CAAC;IAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAA;CAAE,CA4F1D"}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { getWallEffectiveHeightForNodes } from '../../hooks/spatial-grid/spatial-grid-manager.js';
|
|
2
|
+
import { getEffectiveWallSurfaceMaterial, getWallSurfaceMaterialSignature, } from '../../schema/index.js';
|
|
3
|
+
function pointsEqual(a, b, tolerance = 1e-6) {
|
|
4
|
+
const dx = a[0] - b[0];
|
|
5
|
+
const dz = a[1] - b[1];
|
|
6
|
+
return dx * dx + dz * dz <= tolerance * tolerance;
|
|
7
|
+
}
|
|
8
|
+
function wallLength(wall) {
|
|
9
|
+
return Math.hypot(wall.end[0] - wall.start[0], wall.end[1] - wall.start[1]);
|
|
10
|
+
}
|
|
11
|
+
export function getWallEndpointAtPoint(wall, point) {
|
|
12
|
+
if (pointsEqual(wall.start, point))
|
|
13
|
+
return 'start';
|
|
14
|
+
if (pointsEqual(wall.end, point))
|
|
15
|
+
return 'end';
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
function getWallFreeEndpoint(wall, sharedPoint) {
|
|
19
|
+
return pointsEqual(wall.start, sharedPoint) ? wall.end : wall.start;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The first thing two walls disagree on (for the merge's explanation), or null.
|
|
23
|
+
* The delete heal is strict: room sides must match, and a wall following the
|
|
24
|
+
* storey never joins one with an explicit height. An explicit merge compares
|
|
25
|
+
* what is visible instead — `heightOf` resolves each wall's actual height — and
|
|
26
|
+
* leaves the sides to room detection, which reclassifies the merged wall.
|
|
27
|
+
*/
|
|
28
|
+
export function wallStyleMismatch(a, b, options) {
|
|
29
|
+
if ((a.parentId ?? null) !== (b.parentId ?? null))
|
|
30
|
+
return 'floor';
|
|
31
|
+
if (Math.abs((a.curveOffset ?? 0) - (b.curveOffset ?? 0)) > 1e-6)
|
|
32
|
+
return 'curve';
|
|
33
|
+
if (Math.abs((a.thickness ?? 0.2) - (b.thickness ?? 0.2)) > 1e-6)
|
|
34
|
+
return 'thickness';
|
|
35
|
+
const { heightOf } = options;
|
|
36
|
+
if (heightOf
|
|
37
|
+
? Math.abs(heightOf(a) - heightOf(b)) > 1e-6
|
|
38
|
+
: (a.height == null) !== (b.height == null) ||
|
|
39
|
+
Math.abs((a.height ?? 0) - (b.height ?? 0)) > 1e-6)
|
|
40
|
+
return 'height';
|
|
41
|
+
for (const side of ['interior', 'exterior']) {
|
|
42
|
+
if (getWallSurfaceMaterialSignature(getEffectiveWallSurfaceMaterial(a, side)) !==
|
|
43
|
+
getWallSurfaceMaterialSignature(getEffectiveWallSurfaceMaterial(b, side)))
|
|
44
|
+
return `${side} finish`;
|
|
45
|
+
}
|
|
46
|
+
if (options.sides && (a.frontSide !== b.frontSide || a.backSide !== b.backSide))
|
|
47
|
+
return 'room sides';
|
|
48
|
+
if (a.visible !== b.visible)
|
|
49
|
+
return 'visibility';
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
export function areWallStylesCompatible(a, b) {
|
|
53
|
+
return wallStyleMismatch(a, b, { sides: true }) === null;
|
|
54
|
+
}
|
|
55
|
+
export function areWallsCollinearAcrossPoint(a, b, sharedPoint) {
|
|
56
|
+
const freeA = getWallFreeEndpoint(a, sharedPoint);
|
|
57
|
+
const freeB = getWallFreeEndpoint(b, sharedPoint);
|
|
58
|
+
const ax = freeA[0] - sharedPoint[0];
|
|
59
|
+
const az = freeA[1] - sharedPoint[1];
|
|
60
|
+
const bx = freeB[0] - sharedPoint[0];
|
|
61
|
+
const bz = freeB[1] - sharedPoint[1];
|
|
62
|
+
const lenA = Math.hypot(ax, az);
|
|
63
|
+
const lenB = Math.hypot(bx, bz);
|
|
64
|
+
if (lenA < 1e-6 || lenB < 1e-6)
|
|
65
|
+
return false;
|
|
66
|
+
const cross = (ax * bz - az * bx) / (lenA * lenB);
|
|
67
|
+
const dot = (ax * bx + az * bz) / (lenA * lenB);
|
|
68
|
+
return Math.abs(cross) <= 1e-4 && dot < -0.999;
|
|
69
|
+
}
|
|
70
|
+
export function resolveMergedWallEndpoints(primary, secondary, sharedPoint) {
|
|
71
|
+
const primaryEndpoint = getWallEndpointAtPoint(primary, sharedPoint);
|
|
72
|
+
const secondaryEndpoint = getWallEndpointAtPoint(secondary, sharedPoint);
|
|
73
|
+
if (primaryEndpoint === 'end' && secondaryEndpoint === 'start') {
|
|
74
|
+
return { start: primary.start, end: secondary.end };
|
|
75
|
+
}
|
|
76
|
+
if (primaryEndpoint === 'start' && secondaryEndpoint === 'end') {
|
|
77
|
+
return { start: secondary.start, end: primary.end };
|
|
78
|
+
}
|
|
79
|
+
// The kept wall never turns around: its sides, finishes and hosted faces stay
|
|
80
|
+
// where they are. Meeting start-to-start or end-to-end, the absorbed wall is
|
|
81
|
+
// the one read backwards.
|
|
82
|
+
if (primaryEndpoint === 'start' && secondaryEndpoint === 'start') {
|
|
83
|
+
return { start: secondary.end, end: primary.end };
|
|
84
|
+
}
|
|
85
|
+
return { start: primary.start, end: secondary.start };
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Hosted nodes live in the wall's local frame (+X along it, +Z its front, yaw
|
|
89
|
+
* 0 front / π back). A wall read backwards turns that frame by 180° about Y,
|
|
90
|
+
* so the face and the yaw swap and the caller mirrors depth. Hinges, handles
|
|
91
|
+
* and swing hang off the node's own yaw (the plan symbol flips them from it),
|
|
92
|
+
* so they stay as stored.
|
|
93
|
+
*/
|
|
94
|
+
function reversedWallChildPatch(child) {
|
|
95
|
+
const patch = {};
|
|
96
|
+
if ('side' in child && (child.side === 'front' || child.side === 'back')) {
|
|
97
|
+
patch.side = child.side === 'front' ? 'back' : 'front';
|
|
98
|
+
}
|
|
99
|
+
if ('rotation' in child && Array.isArray(child.rotation)) {
|
|
100
|
+
const yaw = child.rotation[1] + Math.PI;
|
|
101
|
+
patch.rotation = [
|
|
102
|
+
child.rotation[0],
|
|
103
|
+
Math.atan2(Math.sin(yaw), Math.cos(yaw)),
|
|
104
|
+
child.rotation[2],
|
|
105
|
+
];
|
|
106
|
+
}
|
|
107
|
+
return patch;
|
|
108
|
+
}
|
|
109
|
+
export function buildMergedWallAttachmentUpdates(primary, secondary, mergedWallId, mergedStart, mergedEnd, nodes) {
|
|
110
|
+
const mergedLength = Math.max(Math.hypot(mergedEnd[0] - mergedStart[0], mergedEnd[1] - mergedStart[1]), 1e-6);
|
|
111
|
+
const tangentX = (mergedEnd[0] - mergedStart[0]) / mergedLength;
|
|
112
|
+
const tangentZ = (mergedEnd[1] - mergedStart[1]) / mergedLength;
|
|
113
|
+
const updates = [];
|
|
114
|
+
const wallChildren = [...(primary.children ?? []), ...(secondary.children ?? [])];
|
|
115
|
+
for (const childId of wallChildren) {
|
|
116
|
+
const child = nodes[childId];
|
|
117
|
+
if (!child)
|
|
118
|
+
continue;
|
|
119
|
+
// Every child moves to the kept wall: deleting the absorbed wall would
|
|
120
|
+
// otherwise take a child left on it along. Only positioned ones re-place.
|
|
121
|
+
const rehost = { parentId: mergedWallId, wallId: mergedWallId };
|
|
122
|
+
if (!('position' in child && Array.isArray(child.position))) {
|
|
123
|
+
updates.push({ id: childId, data: rehost });
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
const sourceWall = child.parentId === secondary.id ? secondary : primary;
|
|
127
|
+
const sourceLength = Math.max(wallLength(sourceWall), 1e-6);
|
|
128
|
+
const reversed = (sourceWall.end[0] - sourceWall.start[0]) * tangentX +
|
|
129
|
+
(sourceWall.end[1] - sourceWall.start[1]) * tangentZ <
|
|
130
|
+
0;
|
|
131
|
+
const mirrored = reversed ? reversedWallChildPatch(child) : {};
|
|
132
|
+
const localX = typeof child.position[0] === 'number' ? child.position[0] : 0;
|
|
133
|
+
const worldX = sourceWall.start[0] + ((sourceWall.end[0] - sourceWall.start[0]) * localX) / sourceLength;
|
|
134
|
+
const worldZ = sourceWall.start[1] + ((sourceWall.end[1] - sourceWall.start[1]) * localX) / sourceLength;
|
|
135
|
+
const nextLocalX = Math.max(0, Math.min(mergedLength, (worldX - mergedStart[0]) * tangentX + (worldZ - mergedStart[1]) * tangentZ));
|
|
136
|
+
updates.push({
|
|
137
|
+
id: childId,
|
|
138
|
+
data: {
|
|
139
|
+
...rehost,
|
|
140
|
+
...mirrored,
|
|
141
|
+
position: [
|
|
142
|
+
nextLocalX,
|
|
143
|
+
child.position[1],
|
|
144
|
+
reversed ? -child.position[2] : child.position[2],
|
|
145
|
+
],
|
|
146
|
+
...('wallT' in child ? { wallT: nextLocalX / mergedLength } : {}),
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
return updates;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Merges a straight run of adjoining walls into one — the inverse of a split.
|
|
154
|
+
* Every joint must hold exactly these walls (a T or a cross stays split), and
|
|
155
|
+
* neighbours must continue in line and look alike (`wallStyleMismatch`: same
|
|
156
|
+
* thickness, visible height and finish). The wall with the most attachments
|
|
157
|
+
* keeps its id and height mode; openings and wall items keep their world
|
|
158
|
+
* position on it.
|
|
159
|
+
*/
|
|
160
|
+
export function planWallMerge(nodes, wallIds) {
|
|
161
|
+
const walls = [...new Set(wallIds)]
|
|
162
|
+
.map((id) => nodes[id])
|
|
163
|
+
.filter((node) => node?.type === 'wall');
|
|
164
|
+
if (walls.length < 2 || walls.length !== new Set(wallIds).size)
|
|
165
|
+
throw Error('Select two or more walls to merge.');
|
|
166
|
+
if (walls.some((wall) => (wall.curveOffset ?? 0) !== 0))
|
|
167
|
+
throw Error('Only straight walls can be merged.');
|
|
168
|
+
const levelId = walls[0].parentId ?? null;
|
|
169
|
+
if (walls.some((wall) => (wall.parentId ?? null) !== levelId))
|
|
170
|
+
throw Error('Merge walls on the same floor.');
|
|
171
|
+
const virtual = { ...nodes };
|
|
172
|
+
const [primary, ...rest] = [...walls].sort((a, b) => (b.children?.length ?? 0) - (a.children?.length ?? 0) || a.id.localeCompare(b.id));
|
|
173
|
+
let merged = primary;
|
|
174
|
+
let remaining = rest;
|
|
175
|
+
while (remaining.length > 0) {
|
|
176
|
+
let next;
|
|
177
|
+
let joint;
|
|
178
|
+
for (const wall of remaining) {
|
|
179
|
+
joint = [merged.start, merged.end].find((end) => getWallEndpointAtPoint(wall, end) !== null);
|
|
180
|
+
if (joint) {
|
|
181
|
+
next = wall;
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
if (!(next && joint))
|
|
186
|
+
throw Error('Merge walls that touch end to end.');
|
|
187
|
+
const atJoint = Object.values(virtual).filter((node) => node?.type === 'wall' &&
|
|
188
|
+
(node.parentId ?? null) === levelId &&
|
|
189
|
+
getWallEndpointAtPoint(node, joint) !== null);
|
|
190
|
+
if (atJoint.length !== 2)
|
|
191
|
+
throw Error('Another wall meets this joint, so merging would disconnect it.');
|
|
192
|
+
if (!areWallsCollinearAcrossPoint(merged, next, joint))
|
|
193
|
+
throw Error('Merge walls that continue in a straight line.');
|
|
194
|
+
const mismatch = wallStyleMismatch(merged, next, {
|
|
195
|
+
sides: false,
|
|
196
|
+
heightOf: (wall) => getWallEffectiveHeightForNodes(wall, virtual),
|
|
197
|
+
});
|
|
198
|
+
if (mismatch)
|
|
199
|
+
throw Error(`These walls have a different ${mismatch}.`);
|
|
200
|
+
const { start, end } = resolveMergedWallEndpoints(merged, next, joint);
|
|
201
|
+
for (const update of buildMergedWallAttachmentUpdates(merged, next, merged.id, start, end, virtual)) {
|
|
202
|
+
virtual[update.id] = { ...virtual[update.id], ...update.data };
|
|
203
|
+
}
|
|
204
|
+
merged = {
|
|
205
|
+
...merged,
|
|
206
|
+
start,
|
|
207
|
+
end,
|
|
208
|
+
// Ids without a node are dropped rather than carried onto the kept wall.
|
|
209
|
+
children: [
|
|
210
|
+
...new Set([
|
|
211
|
+
...(merged.children ?? []),
|
|
212
|
+
...(next.children ?? []).filter((id) => virtual[id]),
|
|
213
|
+
]),
|
|
214
|
+
],
|
|
215
|
+
};
|
|
216
|
+
virtual[merged.id] = merged;
|
|
217
|
+
delete virtual[next.id];
|
|
218
|
+
for (const node of Object.values(virtual)) {
|
|
219
|
+
if (node?.type !== 'zone' || !node.boundaryWallIds?.includes(next.id))
|
|
220
|
+
continue;
|
|
221
|
+
virtual[node.id] = {
|
|
222
|
+
...node,
|
|
223
|
+
boundaryWallIds: [
|
|
224
|
+
...new Set(node.boundaryWallIds.map((id) => (id === next.id ? merged.id : id))),
|
|
225
|
+
],
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
remaining = remaining.filter((wall) => wall !== next);
|
|
229
|
+
}
|
|
230
|
+
return {
|
|
231
|
+
changes: {
|
|
232
|
+
create: [],
|
|
233
|
+
update: Object.values(virtual)
|
|
234
|
+
.filter((node) => nodes[node.id] && node !== nodes[node.id])
|
|
235
|
+
.map((node) => ({ id: node.id, data: node })),
|
|
236
|
+
delete: walls.filter((wall) => !virtual[wall.id]).map((wall) => wall.id),
|
|
237
|
+
},
|
|
238
|
+
wallId: merged.id,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getWallCurveFrameAt, isCurvedWall } from './wall-curve';
|
|
1
|
+
import { getWallCurveFrameAt, isCurvedWall } from './wall-curve.js';
|
|
2
2
|
// ============================================================================
|
|
3
3
|
// UTILITY FUNCTIONS
|
|
4
4
|
// ============================================================================
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { AnyNode, AnyNodeId, WallNode } from '../../schema/index.js';
|
|
2
|
+
import type { WallPlanPoint } from './wall-move.js';
|
|
3
|
+
import { type WallTopologyChanges } from './wall-topology.js';
|
|
4
|
+
export declare function wallRectangleCorners(a: WallPlanPoint, b: WallPlanPoint): WallPlanPoint[];
|
|
5
|
+
/** Plan against a scratch graph so four sides commit atomically, including junction splits. */
|
|
6
|
+
export declare function planWallRectangle(nodes: Record<AnyNodeId, AnyNode>, args: {
|
|
7
|
+
levelId: AnyNodeId;
|
|
8
|
+
start: WallPlanPoint;
|
|
9
|
+
end: WallPlanPoint;
|
|
10
|
+
wallDefaults?: Partial<WallNode>;
|
|
11
|
+
}): {
|
|
12
|
+
changes: WallTopologyChanges;
|
|
13
|
+
walls: WallNode[];
|
|
14
|
+
};
|
|
15
|
+
/** Explicit split keeps the first wall's identity and reuses the junction planner's host migration. */
|
|
16
|
+
export declare function planWallDivision(nodes: Record<AnyNodeId, AnyNode>, wallId: WallNode['id'], distance: number): {
|
|
17
|
+
changes: WallTopologyChanges;
|
|
18
|
+
point: WallPlanPoint;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Several cuts as one edit. Cutting farthest first keeps the first wall's
|
|
22
|
+
* identity at every step, so the nearer distances stay valid on it.
|
|
23
|
+
*/
|
|
24
|
+
export declare function planWallDivisions(nodes: Record<AnyNodeId, AnyNode>, wallId: WallNode['id'], distances: readonly number[]): {
|
|
25
|
+
changes: WallTopologyChanges;
|
|
26
|
+
points: WallPlanPoint[];
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=wall-operations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wall-operations.d.ts","sourceRoot":"","sources":["../../../src/systems/wall/wall-operations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAEhE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAChD,OAAO,EAIL,KAAK,mBAAmB,EACzB,MAAM,iBAAiB,CAAA;AAExB,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,aAAa,GAAG,aAAa,EAAE,CAiBxF;AAED,+FAA+F;AAC/F,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,EACjC,IAAI,EAAE;IACJ,OAAO,EAAE,SAAS,CAAA;IAClB,KAAK,EAAE,aAAa,CAAA;IACpB,GAAG,EAAE,aAAa,CAAA;IAClB,YAAY,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAA;CACjC,GACA;IAAE,OAAO,EAAE,mBAAmB,CAAC;IAAC,KAAK,EAAE,QAAQ,EAAE,CAAA;CAAE,CAyCrD;AAED,uGAAuG;AACvG,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,EACjC,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,EACtB,QAAQ,EAAE,MAAM;;WAsD+B,aAAa;EAC7D;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,EACjC,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,EACtB,SAAS,EAAE,SAAS,MAAM,EAAE,GAC3B;IAAE,OAAO,EAAE,mBAAmB,CAAC;IAAC,MAAM,EAAE,aAAa,EAAE,CAAA;CAAE,CAyB3D"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { getWallCurveFrameAt, getWallCurveLength } from './wall-curve.js';
|
|
2
|
+
import { planWallInsertion, planWallSplitAtPoint, uncoveredWallSegments, } from './wall-topology.js';
|
|
3
|
+
export function wallRectangleCorners(a, b) {
|
|
4
|
+
if (![...a, ...b].every(Number.isFinite) ||
|
|
5
|
+
Math.abs(a[0] - b[0]) < 0.05 ||
|
|
6
|
+
Math.abs(a[1] - b[1]) < 0.05)
|
|
7
|
+
return [];
|
|
8
|
+
const x = Math.min(a[0], b[0]);
|
|
9
|
+
const z = Math.min(a[1], b[1]);
|
|
10
|
+
const right = Math.max(a[0], b[0]);
|
|
11
|
+
const top = Math.max(a[1], b[1]);
|
|
12
|
+
return [
|
|
13
|
+
[x, z],
|
|
14
|
+
[right, z],
|
|
15
|
+
[right, top],
|
|
16
|
+
[x, top],
|
|
17
|
+
];
|
|
18
|
+
}
|
|
19
|
+
/** Plan against a scratch graph so four sides commit atomically, including junction splits. */
|
|
20
|
+
export function planWallRectangle(nodes, args) {
|
|
21
|
+
if (nodes[args.levelId]?.type !== 'level')
|
|
22
|
+
throw Error('Select an editable floor.');
|
|
23
|
+
const corners = wallRectangleCorners(args.start, args.end);
|
|
24
|
+
if (!corners.length)
|
|
25
|
+
throw Error('Both rectangle dimensions must be at least 5 cm.');
|
|
26
|
+
const virtual = { ...nodes };
|
|
27
|
+
const added = new Set();
|
|
28
|
+
for (let i = 0; i < 4; i++) {
|
|
29
|
+
// A side that runs along existing walls only adds what they don't cover,
|
|
30
|
+
// so snapping to a wall and dragging past its end reuses it rather than
|
|
31
|
+
// doubling it.
|
|
32
|
+
const levelWalls = Object.values(virtual).filter((node) => node.type === 'wall' && node.parentId === args.levelId);
|
|
33
|
+
for (const [start, end] of uncoveredWallSegments(corners[i], corners[(i + 1) % 4], levelWalls)) {
|
|
34
|
+
const result = planWallInsertion(virtual, { ...args, start, end, joinRadius: 0 });
|
|
35
|
+
if (!result.ok)
|
|
36
|
+
throw Error('The rectangle cannot be drawn here.');
|
|
37
|
+
for (const id of result.plan.changes.delete)
|
|
38
|
+
delete virtual[id];
|
|
39
|
+
for (const { node, parentId } of result.plan.changes.create) {
|
|
40
|
+
virtual[node.id] = { ...node, ...(parentId ? { parentId } : {}) };
|
|
41
|
+
}
|
|
42
|
+
for (const wall of result.plan.insertedWalls)
|
|
43
|
+
added.add(wall.id);
|
|
44
|
+
for (const { id, data } of result.plan.changes.update) {
|
|
45
|
+
if (virtual[id])
|
|
46
|
+
virtual[id] = { ...virtual[id], ...data };
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const created = Object.values(virtual).filter((n) => !nodes[n.id]);
|
|
51
|
+
return {
|
|
52
|
+
changes: {
|
|
53
|
+
create: created.map((node) => ({ node, parentId: node.parentId })),
|
|
54
|
+
update: Object.values(virtual)
|
|
55
|
+
.filter((n) => nodes[n.id] && n !== nodes[n.id])
|
|
56
|
+
.map((n) => ({ id: n.id, data: n })),
|
|
57
|
+
delete: Object.keys(nodes).filter((id) => !virtual[id]),
|
|
58
|
+
},
|
|
59
|
+
walls: created.filter((n) => n.type === 'wall' && added.has(n.id)),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/** Explicit split keeps the first wall's identity and reuses the junction planner's host migration. */
|
|
63
|
+
export function planWallDivision(nodes, wallId, distance) {
|
|
64
|
+
const wall = nodes[wallId];
|
|
65
|
+
if (wall?.type !== 'wall' || !wall.parentId)
|
|
66
|
+
throw Error('Select a wall.');
|
|
67
|
+
const length = getWallCurveLength(wall);
|
|
68
|
+
if (!Number.isFinite(distance) || distance < 0.05 || distance > length - 0.05)
|
|
69
|
+
throw Error('Keep at least 5 cm on each side of the split.');
|
|
70
|
+
const point = getWallCurveFrameAt(wall, distance / length).point;
|
|
71
|
+
const result = planWallSplitAtPoint(nodes, {
|
|
72
|
+
levelId: wall.parentId,
|
|
73
|
+
point: [point.x, point.y],
|
|
74
|
+
radius: 0.001,
|
|
75
|
+
ignoreWallIds: Object.values(nodes)
|
|
76
|
+
.filter((n) => n.type === 'wall' && n.id !== wallId)
|
|
77
|
+
.map((n) => n.id),
|
|
78
|
+
});
|
|
79
|
+
if (!result.ok || result.plan.changes.create.length !== 2)
|
|
80
|
+
throw Error('Move the split away from doors, windows and mounted objects.');
|
|
81
|
+
const [first, second] = result.plan.changes.create;
|
|
82
|
+
const firstId = first.node.id;
|
|
83
|
+
const changes = {
|
|
84
|
+
create: [second],
|
|
85
|
+
delete: [],
|
|
86
|
+
update: [
|
|
87
|
+
{
|
|
88
|
+
id: wallId,
|
|
89
|
+
data: { ...first.node, id: wallId, parentId: wall.parentId },
|
|
90
|
+
},
|
|
91
|
+
...result.plan.changes.update.map((op) => ({
|
|
92
|
+
...op,
|
|
93
|
+
data: {
|
|
94
|
+
...op.data,
|
|
95
|
+
...(op.data.parentId === firstId ? { parentId: wallId } : {}),
|
|
96
|
+
...('wallId' in op.data && op.data.wallId === firstId ? { wallId } : {}),
|
|
97
|
+
},
|
|
98
|
+
})),
|
|
99
|
+
],
|
|
100
|
+
};
|
|
101
|
+
for (const node of Object.values(nodes)) {
|
|
102
|
+
if (node.type === 'zone' &&
|
|
103
|
+
node.parentId === wall.parentId &&
|
|
104
|
+
node.boundaryWallIds?.includes(wallId)) {
|
|
105
|
+
changes.update.push({
|
|
106
|
+
id: node.id,
|
|
107
|
+
data: {
|
|
108
|
+
boundaryWallIds: node.boundaryWallIds.flatMap((id) => id === wallId ? [wallId, second.node.id] : [id]),
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return { changes, point: [point.x, point.y] };
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Several cuts as one edit. Cutting farthest first keeps the first wall's
|
|
117
|
+
* identity at every step, so the nearer distances stay valid on it.
|
|
118
|
+
*/
|
|
119
|
+
export function planWallDivisions(nodes, wallId, distances) {
|
|
120
|
+
const virtual = { ...nodes };
|
|
121
|
+
const points = [];
|
|
122
|
+
for (const distance of [...distances].sort((a, b) => b - a)) {
|
|
123
|
+
const plan = planWallDivision(virtual, wallId, distance);
|
|
124
|
+
for (const { node, parentId } of plan.changes.create) {
|
|
125
|
+
virtual[node.id] = { ...node, ...(parentId ? { parentId } : {}) };
|
|
126
|
+
}
|
|
127
|
+
for (const { id, data } of plan.changes.update) {
|
|
128
|
+
if (virtual[id])
|
|
129
|
+
virtual[id] = { ...virtual[id], ...data };
|
|
130
|
+
}
|
|
131
|
+
points.push(plan.point);
|
|
132
|
+
}
|
|
133
|
+
return {
|
|
134
|
+
changes: {
|
|
135
|
+
create: Object.values(virtual)
|
|
136
|
+
.filter((n) => !nodes[n.id])
|
|
137
|
+
.map((node) => ({ node, parentId: node.parentId })),
|
|
138
|
+
update: Object.values(virtual)
|
|
139
|
+
.filter((n) => nodes[n.id] && n !== nodes[n.id])
|
|
140
|
+
.map((n) => ({ id: n.id, data: n })),
|
|
141
|
+
delete: [],
|
|
142
|
+
},
|
|
143
|
+
points: points.reverse(),
|
|
144
|
+
};
|
|
145
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type AnyNode, type AnyNodeId, type WallNode } from '../../schema';
|
|
2
|
-
import type { WallPlanPoint } from './wall-move';
|
|
1
|
+
import { type AnyNode, type AnyNodeId, type WallNode } from '../../schema/index.js';
|
|
2
|
+
import type { WallPlanPoint } from './wall-move.js';
|
|
3
3
|
export type WallTopologyChanges = {
|
|
4
4
|
create: Array<{
|
|
5
5
|
node: AnyNode;
|
|
@@ -37,6 +37,13 @@ export type WallPointSplitResult = {
|
|
|
37
37
|
ok: false;
|
|
38
38
|
reason: 'no-host';
|
|
39
39
|
};
|
|
40
|
+
/**
|
|
41
|
+
* The parts of `start→end` that no straight wall already runs along, in order.
|
|
42
|
+
* A side drawn along an existing wall and past its end yields the overhang
|
|
43
|
+
* only, so the existing wall is reused instead of doubled. Gaps too short to
|
|
44
|
+
* be a wall are treated as covered.
|
|
45
|
+
*/
|
|
46
|
+
export declare function uncoveredWallSegments(start: WallPlanPoint, end: WallPlanPoint, walls: WallNode[]): Array<[WallPlanPoint, WallPlanPoint]>;
|
|
40
47
|
export declare function planWallSplitAtPoint(nodes: Record<AnyNodeId, AnyNode>, args: {
|
|
41
48
|
levelId: AnyNodeId | null;
|
|
42
49
|
point: WallPlanPoint;
|