@pascal-app/nodes 0.1.1 → 1.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -0
- package/dist/building/definition.js +1 -1
- package/dist/cabinet/definition.d.ts.map +1 -1
- package/dist/cabinet/definition.js +809 -72
- package/dist/cabinet/geometry.d.ts.map +1 -1
- package/dist/cabinet/geometry.js +4 -0
- package/dist/cabinet/move-frame.js +3 -3
- package/dist/cabinet/panel.d.ts.map +1 -1
- package/dist/cabinet/panel.js +1 -0
- package/dist/cabinet/placement-snap.d.ts +8 -0
- package/dist/cabinet/placement-snap.d.ts.map +1 -0
- package/dist/cabinet/placement-snap.js +19 -0
- package/dist/cabinet/presets.js +8 -8
- package/dist/cabinet/quick-actions.d.ts.map +1 -1
- package/dist/cabinet/quick-actions.js +9 -3
- package/dist/cabinet/resize-limits.d.ts +11 -0
- package/dist/cabinet/resize-limits.d.ts.map +1 -0
- package/dist/cabinet/resize-limits.js +22 -0
- package/dist/cabinet/run-layout.d.ts +8 -2
- package/dist/cabinet/run-layout.d.ts.map +1 -1
- package/dist/cabinet/run-layout.js +59 -7
- package/dist/cabinet/run-ops.d.ts +44 -3
- package/dist/cabinet/run-ops.d.ts.map +1 -1
- package/dist/cabinet/run-ops.js +646 -110
- package/dist/cabinet/run-panel.d.ts +2 -1
- package/dist/cabinet/run-panel.d.ts.map +1 -1
- package/dist/cabinet/run-panel.js +38 -4
- package/dist/cabinet/stack-transitions.js +4 -4
- package/dist/cabinet/tool.d.ts.map +1 -1
- package/dist/cabinet/tool.js +95 -17
- package/dist/cabinet/wall-snap.d.ts.map +1 -1
- package/dist/cabinet/wall-snap.js +2 -6
- package/dist/ceiling/boundary-editor.d.ts.map +1 -1
- package/dist/ceiling/boundary-editor.js +2 -2
- package/dist/ceiling/definition.d.ts +1 -1
- package/dist/ceiling/definition.d.ts.map +1 -1
- package/dist/ceiling/definition.js +36 -5
- package/dist/ceiling/floorplan-affordances.d.ts +4 -4
- package/dist/ceiling/floorplan-move.d.ts +4 -4
- package/dist/ceiling/floorplan-move.d.ts.map +1 -1
- package/dist/ceiling/floorplan-move.js +5 -4
- package/dist/ceiling/hole-editor.d.ts.map +1 -1
- package/dist/ceiling/hole-editor.js +2 -2
- package/dist/ceiling/move-tool.d.ts.map +1 -1
- package/dist/ceiling/move-tool.js +4 -3
- package/dist/ceiling/panel.d.ts.map +1 -1
- package/dist/ceiling/panel.js +65 -3
- package/dist/ceiling/renderer.d.ts.map +1 -1
- package/dist/ceiling/renderer.js +6 -2
- package/dist/ceiling/tool.d.ts.map +1 -1
- package/dist/ceiling/tool.js +12 -1
- package/dist/chimney/definition.d.ts.map +1 -1
- package/dist/chimney/definition.js +1 -0
- package/dist/chimney/tool.d.ts.map +1 -1
- package/dist/chimney/tool.js +16 -1
- package/dist/column/definition.d.ts.map +1 -1
- package/dist/column/definition.js +14 -2
- package/dist/column/floorplan-affordances.d.ts.map +1 -1
- package/dist/column/floorplan-affordances.js +19 -14
- package/dist/column/floorplan-move.d.ts.map +1 -1
- package/dist/column/floorplan-move.js +7 -2
- package/dist/column/floorplan.d.ts +9 -1
- package/dist/column/floorplan.d.ts.map +1 -1
- package/dist/column/floorplan.js +59 -4
- package/dist/column/tool.d.ts.map +1 -1
- package/dist/column/tool.js +33 -7
- package/dist/construction-dimension/definition.d.ts +4 -0
- package/dist/construction-dimension/definition.d.ts.map +1 -0
- package/dist/construction-dimension/definition.js +83 -0
- package/dist/construction-dimension/drawing-coordination.d.ts +7 -0
- package/dist/construction-dimension/drawing-coordination.d.ts.map +1 -0
- package/dist/construction-dimension/drawing-coordination.js +54 -0
- package/dist/construction-dimension/floorplan-affordances.d.ts +4 -0
- package/dist/construction-dimension/floorplan-affordances.d.ts.map +1 -0
- package/dist/construction-dimension/floorplan-affordances.js +114 -0
- package/dist/construction-dimension/floorplan-tool.d.ts +21 -0
- package/dist/construction-dimension/floorplan-tool.d.ts.map +1 -0
- package/dist/construction-dimension/floorplan-tool.js +557 -0
- package/dist/construction-dimension/floorplan.d.ts +3 -0
- package/dist/construction-dimension/floorplan.d.ts.map +1 -0
- package/dist/construction-dimension/floorplan.js +457 -0
- package/dist/construction-dimension/geometry.d.ts +31 -0
- package/dist/construction-dimension/geometry.d.ts.map +1 -0
- package/dist/construction-dimension/geometry.js +144 -0
- package/dist/construction-dimension/index.d.ts +4 -0
- package/dist/construction-dimension/index.d.ts.map +1 -0
- package/dist/construction-dimension/index.js +3 -0
- package/dist/construction-dimension/panel.d.ts +2 -0
- package/dist/construction-dimension/panel.d.ts.map +1 -0
- package/dist/construction-dimension/panel.js +128 -0
- package/dist/construction-dimension/parametrics.d.ts +3 -0
- package/dist/construction-dimension/parametrics.d.ts.map +1 -0
- package/dist/construction-dimension/parametrics.js +4 -0
- package/dist/construction-dimension/schema.d.ts +2 -0
- package/dist/construction-dimension/schema.d.ts.map +1 -0
- package/dist/construction-dimension/schema.js +1 -0
- package/dist/door/contextual-dimensions.d.ts +3 -0
- package/dist/door/contextual-dimensions.d.ts.map +1 -0
- package/dist/door/contextual-dimensions.js +7 -0
- package/dist/door/definition.d.ts.map +1 -1
- package/dist/door/definition.js +13 -8
- package/dist/door/floorplan-affordances.d.ts +2 -5
- package/dist/door/floorplan-affordances.d.ts.map +1 -1
- package/dist/door/floorplan-affordances.js +9 -18
- package/dist/door/floorplan.d.ts +3 -4
- package/dist/door/floorplan.d.ts.map +1 -1
- package/dist/door/floorplan.js +88 -6
- package/dist/door/move-tool.d.ts.map +1 -1
- package/dist/door/move-tool.js +2 -2
- package/dist/door/panel.d.ts.map +1 -1
- package/dist/door/panel.js +3 -1
- package/dist/door/schema.d.ts +1 -1
- package/dist/door/schema.d.ts.map +1 -1
- package/dist/door/schema.js +1 -1
- package/dist/door/tool.d.ts.map +1 -1
- package/dist/door/tool.js +63 -6
- package/dist/dormer/definition.d.ts.map +1 -1
- package/dist/dormer/definition.js +1 -0
- package/dist/dormer/tool.d.ts.map +1 -1
- package/dist/dormer/tool.js +23 -1
- package/dist/duct-segment/tool.d.ts.map +1 -1
- package/dist/duct-segment/tool.js +20 -9
- package/dist/duct-terminal/tool.d.ts.map +1 -1
- package/dist/duct-terminal/tool.js +9 -6
- package/dist/elevator/floorplan-affordances.d.ts +2 -6
- package/dist/elevator/floorplan-affordances.d.ts.map +1 -1
- package/dist/elevator/floorplan-affordances.js +13 -12
- package/dist/fence/actions/move-endpoint.d.ts.map +1 -1
- package/dist/fence/actions/move-endpoint.js +29 -1
- package/dist/fence/definition.d.ts.map +1 -1
- package/dist/fence/definition.js +74 -14
- package/dist/fence/floorplan-affordances.d.ts.map +1 -1
- package/dist/fence/floorplan-affordances.js +48 -11
- package/dist/fence/floorplan-move.d.ts.map +1 -1
- package/dist/fence/floorplan-move.js +38 -3
- package/dist/fence/geometry.d.ts.map +1 -1
- package/dist/fence/geometry.js +15 -1
- package/dist/fence/lift.d.ts +38 -0
- package/dist/fence/lift.d.ts.map +1 -0
- package/dist/fence/lift.js +51 -0
- package/dist/fence/move-tool.d.ts.map +1 -1
- package/dist/fence/move-tool.js +25 -5
- package/dist/fence/system.d.ts +3 -0
- package/dist/fence/system.d.ts.map +1 -0
- package/dist/fence/system.js +46 -0
- package/dist/fence/tool.d.ts.map +1 -1
- package/dist/fence/tool.js +103 -32
- package/dist/hvac-equipment/tool.d.ts.map +1 -1
- package/dist/hvac-equipment/tool.js +8 -3
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/item/definition.d.ts.map +1 -1
- package/dist/item/definition.js +7 -1
- package/dist/item/floorplan-move.d.ts.map +1 -1
- package/dist/item/floorplan-move.js +50 -43
- package/dist/item/floorplan.d.ts +1 -0
- package/dist/item/floorplan.d.ts.map +1 -1
- package/dist/item/floorplan.js +49 -0
- package/dist/item/renderer.d.ts +3 -0
- package/dist/item/renderer.d.ts.map +1 -1
- package/dist/item/renderer.js +96 -8
- package/dist/level/definition.d.ts.map +1 -1
- package/dist/level/definition.js +7 -3
- package/dist/lineset/tool.d.ts.map +1 -1
- package/dist/lineset/tool.js +5 -1
- package/dist/liquid-line/tool.d.ts.map +1 -1
- package/dist/liquid-line/tool.js +7 -1
- package/dist/measurement/definition.d.ts.map +1 -1
- package/dist/measurement/definition.js +5 -0
- package/dist/measurement/floorplan.d.ts.map +1 -1
- package/dist/measurement/floorplan.js +11 -10
- package/dist/measurement/index.d.ts +1 -1
- package/dist/measurement/index.d.ts.map +1 -1
- package/dist/measurement/index.js +1 -1
- package/dist/measurement/resolve.d.ts +5 -0
- package/dist/measurement/resolve.d.ts.map +1 -1
- package/dist/measurement/resolve.js +2 -2
- package/dist/measurement/surface-query.js +5 -5
- package/dist/measurement/tool.d.ts +6 -1
- package/dist/measurement/tool.d.ts.map +1 -1
- package/dist/measurement/tool.js +7 -11
- package/dist/pipe-segment/tool.d.ts.map +1 -1
- package/dist/pipe-segment/tool.js +22 -19
- package/dist/roof-segment/floorplan-affordances.d.ts.map +1 -1
- package/dist/roof-segment/floorplan-affordances.js +14 -8
- package/dist/shared/construction-dimension-standards.d.ts +34 -0
- package/dist/shared/construction-dimension-standards.d.ts.map +1 -0
- package/dist/shared/construction-dimension-standards.js +18 -0
- package/dist/shared/construction-length.d.ts +10 -0
- package/dist/shared/construction-length.d.ts.map +1 -0
- package/dist/shared/construction-length.js +57 -0
- package/dist/shared/dimension-string.d.ts +20 -0
- package/dist/shared/dimension-string.d.ts.map +1 -0
- package/dist/shared/dimension-string.js +19 -0
- package/dist/shared/draft-axis-guides.d.ts +36 -0
- package/dist/shared/draft-axis-guides.d.ts.map +1 -0
- package/dist/shared/draft-axis-guides.js +107 -0
- package/dist/shared/move-roof-tool.d.ts.map +1 -1
- package/dist/shared/move-roof-tool.js +17 -3
- package/dist/shared/opening-documentation-fields.d.ts +16 -0
- package/dist/shared/opening-documentation-fields.d.ts.map +1 -0
- package/dist/shared/opening-documentation-fields.js +54 -0
- package/dist/shared/opening-documentation.d.ts +47 -0
- package/dist/shared/opening-documentation.d.ts.map +1 -0
- package/dist/shared/opening-documentation.js +300 -0
- package/dist/shared/opening-guides-runtime.d.ts.map +1 -1
- package/dist/shared/opening-guides-runtime.js +3 -2
- package/dist/shared/opening-placement-dimensions.d.ts.map +1 -1
- package/dist/shared/opening-placement-dimensions.js +14 -5
- package/dist/shared/wall-opening-ceiling.d.ts +30 -0
- package/dist/shared/wall-opening-ceiling.d.ts.map +1 -0
- package/dist/shared/wall-opening-ceiling.js +29 -0
- package/dist/shelf/floorplan-affordances.d.ts.map +1 -1
- package/dist/shelf/floorplan-affordances.js +10 -5
- package/dist/shelf/floorplan-move.d.ts +2 -16
- package/dist/shelf/floorplan-move.d.ts.map +1 -1
- package/dist/shelf/floorplan-move.js +19 -40
- package/dist/shelf/tool.d.ts.map +1 -1
- package/dist/shelf/tool.js +8 -3
- package/dist/site/recessed-slab-ground-holes.d.ts.map +1 -1
- package/dist/site/recessed-slab-ground-holes.js +1 -4
- package/dist/site/renderer.d.ts.map +1 -1
- package/dist/site/renderer.js +118 -28
- package/dist/site/terrain-drape.d.ts +91 -0
- package/dist/site/terrain-drape.d.ts.map +1 -0
- package/dist/site/terrain-drape.js +205 -0
- package/dist/site/terrain-geometry.d.ts +131 -0
- package/dist/site/terrain-geometry.d.ts.map +1 -0
- package/dist/site/terrain-geometry.js +259 -0
- package/dist/site/terrain-mesh.d.ts +49 -0
- package/dist/site/terrain-mesh.d.ts.map +1 -0
- package/dist/site/terrain-mesh.js +122 -0
- package/dist/site/terrain-renderer.d.ts +28 -0
- package/dist/site/terrain-renderer.d.ts.map +1 -0
- package/dist/site/terrain-renderer.js +69 -0
- package/dist/skylight/definition.d.ts.map +1 -1
- package/dist/skylight/definition.js +1 -0
- package/dist/skylight/tool.d.ts.map +1 -1
- package/dist/skylight/tool.js +16 -1
- package/dist/slab/definition.d.ts.map +1 -1
- package/dist/slab/definition.js +87 -10
- package/dist/slab/elevation-limit.d.ts +43 -0
- package/dist/slab/elevation-limit.d.ts.map +1 -0
- package/dist/slab/elevation-limit.js +124 -0
- package/dist/slab/floorplan-affordances.d.ts +16 -0
- package/dist/slab/floorplan-affordances.d.ts.map +1 -1
- package/dist/slab/geometry.d.ts.map +1 -1
- package/dist/slab/geometry.js +98 -5
- package/dist/slab/panel.d.ts.map +1 -1
- package/dist/slab/panel.js +82 -4
- package/dist/slab/parametrics.d.ts +1 -1
- package/dist/slab/parametrics.d.ts.map +1 -1
- package/dist/slab/parametrics.js +13 -1
- package/dist/slab/placement-ownership.d.ts +3 -0
- package/dist/slab/placement-ownership.d.ts.map +1 -0
- package/dist/slab/placement-ownership.js +3 -0
- package/dist/slab/quick-measurement.d.ts.map +1 -1
- package/dist/slab/quick-measurement.js +3 -2
- package/dist/slab/system.d.ts.map +1 -1
- package/dist/slab/system.js +14 -4
- package/dist/slab/tool.d.ts.map +1 -1
- package/dist/slab/tool.js +81 -23
- package/dist/solar-panel/definition.d.ts.map +1 -1
- package/dist/solar-panel/definition.js +1 -0
- package/dist/solar-panel/tool.d.ts.map +1 -1
- package/dist/solar-panel/tool.js +17 -1
- package/dist/spawn/definition.d.ts.map +1 -1
- package/dist/spawn/definition.js +1 -0
- package/dist/spawn/floorplan-affordances.d.ts.map +1 -1
- package/dist/spawn/floorplan-affordances.js +7 -4
- package/dist/spawn/floorplan-move.d.ts.map +1 -1
- package/dist/spawn/floorplan-move.js +8 -6
- package/dist/spawn/renderer.d.ts +4 -0
- package/dist/spawn/renderer.d.ts.map +1 -1
- package/dist/spawn/renderer.js +32 -18
- package/dist/spawn/tool.d.ts +2 -2
- package/dist/spawn/tool.d.ts.map +1 -1
- package/dist/spawn/tool.js +78 -11
- package/dist/stair/definition.d.ts.map +1 -1
- package/dist/stair/definition.js +15 -7
- package/dist/stair/destination.d.ts +16 -0
- package/dist/stair/destination.d.ts.map +1 -0
- package/dist/stair/destination.js +24 -0
- package/dist/stair/documentation.d.ts +8 -0
- package/dist/stair/documentation.d.ts.map +1 -0
- package/dist/stair/documentation.js +245 -0
- package/dist/stair/floor-stack.d.ts.map +1 -1
- package/dist/stair/floor-stack.js +38 -0
- package/dist/stair/floorplan-affordances.d.ts.map +1 -1
- package/dist/stair/floorplan-affordances.js +28 -9
- package/dist/stair/floorplan-move.d.ts +3 -5
- package/dist/stair/floorplan-move.d.ts.map +1 -1
- package/dist/stair/floorplan-move.js +14 -16
- package/dist/stair/floorplan.d.ts.map +1 -1
- package/dist/stair/floorplan.js +27 -14
- package/dist/stair/panel.d.ts.map +1 -1
- package/dist/stair/panel.js +35 -2
- package/dist/stair/renderer.d.ts.map +1 -1
- package/dist/stair/renderer.js +4 -3
- package/dist/structural-grid/coordination.d.ts +16 -0
- package/dist/structural-grid/coordination.d.ts.map +1 -0
- package/dist/structural-grid/coordination.js +105 -0
- package/dist/structural-grid/definition.d.ts +4 -0
- package/dist/structural-grid/definition.d.ts.map +1 -0
- package/dist/structural-grid/definition.js +51 -0
- package/dist/structural-grid/floorplan-tool.d.ts +16 -0
- package/dist/structural-grid/floorplan-tool.d.ts.map +1 -0
- package/dist/structural-grid/floorplan-tool.js +183 -0
- package/dist/structural-grid/floorplan.d.ts +3 -0
- package/dist/structural-grid/floorplan.d.ts.map +1 -0
- package/dist/structural-grid/floorplan.js +61 -0
- package/dist/structural-grid/index.d.ts +2 -0
- package/dist/structural-grid/index.d.ts.map +1 -0
- package/dist/structural-grid/index.js +1 -0
- package/dist/structural-grid/schema.d.ts +2 -0
- package/dist/structural-grid/schema.d.ts.map +1 -0
- package/dist/structural-grid/schema.js +1 -0
- package/dist/wall/construction-dimensions.d.ts +32 -0
- package/dist/wall/construction-dimensions.d.ts.map +1 -0
- package/dist/wall/construction-dimensions.js +1031 -0
- package/dist/wall/contextual-dimensions.d.ts +13 -0
- package/dist/wall/contextual-dimensions.d.ts.map +1 -0
- package/dist/wall/contextual-dimensions.js +221 -0
- package/dist/wall/definition.d.ts.map +1 -1
- package/dist/wall/definition.js +20 -1
- package/dist/wall/floorplan-affordances.d.ts.map +1 -1
- package/dist/wall/floorplan-affordances.js +23 -8
- package/dist/wall/floorplan-overrides.d.ts +9 -6
- package/dist/wall/floorplan-overrides.d.ts.map +1 -1
- package/dist/wall/floorplan-overrides.js +20 -11
- package/dist/wall/floorplan.d.ts +12 -3
- package/dist/wall/floorplan.d.ts.map +1 -1
- package/dist/wall/floorplan.js +121 -79
- package/dist/wall/measurement.d.ts.map +1 -1
- package/dist/wall/measurement.js +17 -4
- package/dist/wall/move-endpoint-tool.d.ts.map +1 -1
- package/dist/wall/move-endpoint-tool.js +74 -27
- package/dist/wall/move-shared.d.ts.map +1 -1
- package/dist/wall/move-shared.js +3 -2
- package/dist/wall/move-tool.d.ts.map +1 -1
- package/dist/wall/move-tool.js +15 -3
- package/dist/wall/paint.d.ts.map +1 -1
- package/dist/wall/paint.js +10 -6
- package/dist/wall/panel.d.ts.map +1 -1
- package/dist/wall/panel.js +32 -5
- package/dist/wall/parametrics.d.ts.map +1 -1
- package/dist/wall/parametrics.js +2 -0
- package/dist/wall/preview.d.ts +8 -0
- package/dist/wall/preview.d.ts.map +1 -0
- package/dist/wall/preview.js +39 -0
- package/dist/wall/quick-measurement.d.ts.map +1 -1
- package/dist/wall/quick-measurement.js +3 -2
- package/dist/wall/renderer.d.ts.map +1 -1
- package/dist/wall/renderer.js +7 -5
- package/dist/wall/system.d.ts +1 -1
- package/dist/wall/system.d.ts.map +1 -1
- package/dist/wall/system.js +37 -2
- package/dist/wall/tool.d.ts.map +1 -1
- package/dist/wall/tool.js +148 -96
- package/dist/wall/treatment-level-data.d.ts +14 -0
- package/dist/wall/treatment-level-data.d.ts.map +1 -0
- package/dist/wall/treatment-level-data.js +31 -0
- package/dist/wall/treatments.d.ts +8 -2
- package/dist/wall/treatments.d.ts.map +1 -1
- package/dist/wall/treatments.js +58 -15
- package/dist/window/contextual-dimensions.d.ts +3 -0
- package/dist/window/contextual-dimensions.d.ts.map +1 -0
- package/dist/window/contextual-dimensions.js +7 -0
- package/dist/window/definition.d.ts.map +1 -1
- package/dist/window/definition.js +15 -10
- package/dist/window/floorplan-affordances.d.ts +2 -5
- package/dist/window/floorplan-affordances.d.ts.map +1 -1
- package/dist/window/floorplan-affordances.js +9 -15
- package/dist/window/floorplan-move.d.ts.map +1 -1
- package/dist/window/floorplan-move.js +1 -1
- package/dist/window/floorplan.d.ts.map +1 -1
- package/dist/window/floorplan.js +7 -1
- package/dist/window/move-tool.d.ts.map +1 -1
- package/dist/window/move-tool.js +3 -3
- package/dist/window/panel.d.ts.map +1 -1
- package/dist/window/panel.js +4 -1
- package/dist/window/schema.d.ts +1 -1
- package/dist/window/schema.d.ts.map +1 -1
- package/dist/window/schema.js +1 -1
- package/dist/window/tool.d.ts.map +1 -1
- package/dist/window/tool.js +64 -7
- package/dist/window/window-math.d.ts +7 -3
- package/dist/window/window-math.d.ts.map +1 -1
- package/dist/window/window-math.js +8 -3
- package/dist/zone/contextual-dimensions.d.ts +3 -0
- package/dist/zone/contextual-dimensions.d.ts.map +1 -0
- package/dist/zone/contextual-dimensions.js +43 -0
- package/dist/zone/definition.d.ts.map +1 -1
- package/dist/zone/definition.js +9 -1
- package/dist/zone/floorplan-affordances.d.ts +36 -0
- package/dist/zone/floorplan-affordances.d.ts.map +1 -1
- package/dist/zone/floorplan.d.ts.map +1 -1
- package/dist/zone/floorplan.js +59 -3
- package/dist/zone/quantities-panel.d.ts.map +1 -1
- package/dist/zone/quantities-panel.js +48 -4
- package/dist/zone/room-clear-dimensions.d.ts +3 -0
- package/dist/zone/room-clear-dimensions.d.ts.map +1 -0
- package/dist/zone/room-clear-dimensions.js +406 -0
- package/dist/zone/room-documentation.d.ts +11 -0
- package/dist/zone/room-documentation.d.ts.map +1 -0
- package/dist/zone/room-documentation.js +97 -0
- package/package.json +7 -7
package/dist/cabinet/run-ops.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { calculateLevelMiters, getWallPlanFootprint, resolveLevelId, selectionProxyIdFromMetadata, } from '@pascal-app/core';
|
|
2
|
-
import {
|
|
2
|
+
import { MAX_CABINET_WIDTH, MIN_CABINET_WIDTH } from './resize-limits';
|
|
3
|
+
import { moduleMaxX, moduleMinX, planToRunLocal, runLocalToPlan, runLocalXExtent, sideInsertX, sortRunModules, } from './run-layout';
|
|
3
4
|
import { CabinetModuleNode as CabinetModuleNodeSchema, CabinetNode as CabinetNodeSchema, } from './schema';
|
|
4
5
|
import { backAnchoredModuleZ, hoodCompartmentHeight, newCabinetCompartment, stackForCabinet, } from './stack';
|
|
5
6
|
/**
|
|
@@ -10,8 +11,9 @@ import { backAnchoredModuleZ, hoodCompartmentHeight, newCabinetCompartment, stac
|
|
|
10
11
|
* per surface and had already drifted (gap checks, hood support, revision
|
|
11
12
|
* scope).
|
|
12
13
|
*/
|
|
13
|
-
export const CABINET_BASE_WIDTH = 0.
|
|
14
|
+
export const CABINET_BASE_WIDTH = 0.5;
|
|
14
15
|
export const CABINET_WALL_DEPTH = 0.32;
|
|
16
|
+
export const CABINET_BASE_DEPTH = 0.5;
|
|
15
17
|
export const CABINET_WALL_CARCASS_HEIGHT = 0.72;
|
|
16
18
|
export const CABINET_TALL_DEPTH = 0.58;
|
|
17
19
|
export const CABINET_TALL_PLINTH_HEIGHT = 0.1;
|
|
@@ -19,6 +21,7 @@ export const CABINET_TALL_CARCASS_HEIGHT = 2.07;
|
|
|
19
21
|
export const CABINET_EDGE_EPSILON = 1e-4;
|
|
20
22
|
const MIN_CORNER_CONNECTED_WIDTH = 0.3;
|
|
21
23
|
const MIN_TRIMMED_CORNER_CONNECTED_WIDTH = 0.05;
|
|
24
|
+
const MIN_CORNER_BRIDGE_WIDTH = 0.05;
|
|
22
25
|
const CORNER_WIDTH_SEARCH_STEP = 0.01;
|
|
23
26
|
const WALL_CLEARANCE_EPSILON = 1e-5;
|
|
24
27
|
export function cabinetMetadataRecord(metadata) {
|
|
@@ -70,6 +73,36 @@ function cornerDerivedRunLink(metadata) {
|
|
|
70
73
|
sourceRunId: sourceRunId,
|
|
71
74
|
};
|
|
72
75
|
}
|
|
76
|
+
export function buildWallCornerDepthIndex(nodes) {
|
|
77
|
+
const groups = new Map();
|
|
78
|
+
for (const node of Object.values(nodes)) {
|
|
79
|
+
if (node?.type !== 'cabinet')
|
|
80
|
+
continue;
|
|
81
|
+
const link = cornerDerivedRunLink(node.metadata);
|
|
82
|
+
if (!link)
|
|
83
|
+
continue;
|
|
84
|
+
const key = [link.sourceRunId, link.sourceModuleId, link.side, link.turnSide].join('\u0000');
|
|
85
|
+
const group = groups.get(key) ?? { link, runIdsByRole: {} };
|
|
86
|
+
group.runIdsByRole[link.role] = node.id;
|
|
87
|
+
groups.set(key, group);
|
|
88
|
+
}
|
|
89
|
+
return [...groups.values()].flatMap(({ link, runIdsByRole }) => {
|
|
90
|
+
const wallLegRunId = runIdsByRole['wall-leg'];
|
|
91
|
+
if (!wallLegRunId)
|
|
92
|
+
return [];
|
|
93
|
+
return [
|
|
94
|
+
{
|
|
95
|
+
baseLegRunId: runIdsByRole['base-leg'],
|
|
96
|
+
bridgeRunId: runIdsByRole.bridge,
|
|
97
|
+
side: link.side,
|
|
98
|
+
sourceModuleId: link.sourceModuleId,
|
|
99
|
+
sourceRunId: link.sourceRunId,
|
|
100
|
+
turnSide: link.turnSide,
|
|
101
|
+
wallLegRunId,
|
|
102
|
+
},
|
|
103
|
+
];
|
|
104
|
+
});
|
|
105
|
+
}
|
|
73
106
|
/**
|
|
74
107
|
* Deleting one member of an L-corner group removes ONLY that node (plus its
|
|
75
108
|
* normal descendants) — never the other corner runs. These patches keep the
|
|
@@ -200,6 +233,245 @@ export function cabinetModulesForRun(run, nodes) {
|
|
|
200
233
|
.map((id) => nodes[id])
|
|
201
234
|
.filter((child) => child?.type === 'cabinet-module');
|
|
202
235
|
}
|
|
236
|
+
export function backAlignedRunDepthOverrides(run, nodes, depth) {
|
|
237
|
+
const modules = cabinetModulesForRun(run, nodes);
|
|
238
|
+
if (modules.length === 0)
|
|
239
|
+
return [];
|
|
240
|
+
const backZ = runBackLineZ(modules);
|
|
241
|
+
const overrides = [];
|
|
242
|
+
for (const module of modules) {
|
|
243
|
+
const positionZ = backZ + depth / 2;
|
|
244
|
+
const parentShiftZ = positionZ - module.position[2];
|
|
245
|
+
overrides.push([
|
|
246
|
+
module.id,
|
|
247
|
+
{
|
|
248
|
+
depth,
|
|
249
|
+
position: [module.position[0], module.position[1], positionZ],
|
|
250
|
+
},
|
|
251
|
+
]);
|
|
252
|
+
for (const childId of module.children ?? []) {
|
|
253
|
+
const child = nodes[childId];
|
|
254
|
+
if (child?.type !== 'cabinet')
|
|
255
|
+
continue;
|
|
256
|
+
overrides.push([
|
|
257
|
+
child.id,
|
|
258
|
+
{
|
|
259
|
+
position: [child.position[0], child.position[1], child.position[2] - parentShiftZ],
|
|
260
|
+
},
|
|
261
|
+
]);
|
|
262
|
+
}
|
|
263
|
+
const wallChild = wallChildOf(module, nodes);
|
|
264
|
+
if (wallChild) {
|
|
265
|
+
overrides.push([
|
|
266
|
+
wallChild.id,
|
|
267
|
+
{
|
|
268
|
+
position: [
|
|
269
|
+
wallChild.position[0],
|
|
270
|
+
wallChild.position[1],
|
|
271
|
+
backAlignZ(depth, wallChild.depth),
|
|
272
|
+
],
|
|
273
|
+
},
|
|
274
|
+
]);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return overrides;
|
|
278
|
+
}
|
|
279
|
+
export function wallCornerWidthOverridesForDepthTargets({ clampWidths = true, cornerIndex, depth, nodes, targets, widthMode = 'bridge', }) {
|
|
280
|
+
const initialDepth = targets[0]?.depth;
|
|
281
|
+
if (typeof initialDepth !== 'number')
|
|
282
|
+
return [];
|
|
283
|
+
const depthDelta = depth - initialDepth;
|
|
284
|
+
const targetIds = new Set(targets.map((target) => target.id));
|
|
285
|
+
const indexedCorners = cornerIndex ?? buildWallCornerDepthIndex(nodes);
|
|
286
|
+
const overrides = new Map();
|
|
287
|
+
const setWidth = (node, requestedWidth, anchor) => {
|
|
288
|
+
if (!node)
|
|
289
|
+
return;
|
|
290
|
+
const existing = overrides.get(node.id);
|
|
291
|
+
const existingPosition = existing?.position;
|
|
292
|
+
const currentWidth = typeof existing?.width === 'number' ? existing.width : node.width;
|
|
293
|
+
const width = clampWidths ? Math.max(0, requestedWidth) : requestedWidth;
|
|
294
|
+
const appliedWidthDelta = width - currentWidth;
|
|
295
|
+
const centerDelta = anchor === 'min' ? appliedWidthDelta / 2 : -appliedWidthDelta / 2;
|
|
296
|
+
overrides.set(node.id, {
|
|
297
|
+
...existing,
|
|
298
|
+
width,
|
|
299
|
+
position: [
|
|
300
|
+
(existingPosition?.[0] ?? node.position[0]) + centerDelta,
|
|
301
|
+
existingPosition?.[1] ?? node.position[1],
|
|
302
|
+
existingPosition?.[2] ?? node.position[2],
|
|
303
|
+
],
|
|
304
|
+
});
|
|
305
|
+
};
|
|
306
|
+
for (const corner of indexedCorners) {
|
|
307
|
+
const wallLegRun = nodes[corner.wallLegRunId];
|
|
308
|
+
if (wallLegRun?.type !== 'cabinet')
|
|
309
|
+
continue;
|
|
310
|
+
const baseLegRun = corner.baseLegRunId ? nodes[corner.baseLegRunId] : undefined;
|
|
311
|
+
const bridgeRun = corner.bridgeRunId ? nodes[corner.bridgeRunId] : undefined;
|
|
312
|
+
const sourceModule = nodes[corner.sourceModuleId];
|
|
313
|
+
const sourceRun = nodes[corner.sourceRunId];
|
|
314
|
+
if (sourceModule?.type !== 'cabinet-module')
|
|
315
|
+
continue;
|
|
316
|
+
const sourceWall = wallChildOf(sourceModule, nodes);
|
|
317
|
+
const wallLegModules = cabinetModulesForRun(wallLegRun, nodes);
|
|
318
|
+
const cornerWallFiller = wallLegModules.find((module) => module.name === 'Corner Wall Filler') ?? null;
|
|
319
|
+
const connectedWallInRun = wallLegModules.find((module) => module.name === 'Wall Cabinet') ?? null;
|
|
320
|
+
const connectedBase = baseLegRun?.type === 'cabinet'
|
|
321
|
+
? (cabinetModulesForRun(baseLegRun, nodes).find((module) => module.name === 'Base Cabinet') ?? null)
|
|
322
|
+
: null;
|
|
323
|
+
const connectedWall = connectedWallInRun ?? (connectedBase ? wallChildOf(connectedBase, nodes) : null);
|
|
324
|
+
const bridgeModules = bridgeRun?.type === 'cabinet' ? cabinetModulesForRun(bridgeRun, nodes) : [];
|
|
325
|
+
const bridgeFiller = bridgeModules.find((module) => module.name === 'Wall Bridge Filler') ?? null;
|
|
326
|
+
const standaloneBridgeFiller = bridgeModules.length === 1 && bridgeModules[0] === bridgeFiller;
|
|
327
|
+
const anchor = bridgeFiller?.openSide === 'left'
|
|
328
|
+
? 'min'
|
|
329
|
+
: bridgeFiller?.openSide === 'right'
|
|
330
|
+
? 'max'
|
|
331
|
+
: corner.side === 'right'
|
|
332
|
+
? 'min'
|
|
333
|
+
: 'max';
|
|
334
|
+
const sourceDirectionChanged = (sourceWall && targetIds.has(sourceWall.id)) ||
|
|
335
|
+
(bridgeRun?.type === 'cabinet' && targetIds.has(bridgeRun.id));
|
|
336
|
+
const connectedDirectionChanged = (connectedWall && targetIds.has(connectedWall.id)) ||
|
|
337
|
+
targetIds.has(wallLegRun.id);
|
|
338
|
+
if (widthMode === 'bridge' && (sourceDirectionChanged || connectedDirectionChanged)) {
|
|
339
|
+
const depthReferenceRun = connectedDirectionChanged && baseLegRun?.type === 'cabinet'
|
|
340
|
+
? baseLegRun
|
|
341
|
+
: sourceRun?.type === 'cabinet'
|
|
342
|
+
? sourceRun
|
|
343
|
+
: null;
|
|
344
|
+
const requestedWidth = depthReferenceRun?.type === 'cabinet'
|
|
345
|
+
? depthReferenceRun.depth - depth
|
|
346
|
+
: (bridgeFiller?.width ?? 0) - depthDelta;
|
|
347
|
+
setWidth(bridgeFiller, requestedWidth, anchor);
|
|
348
|
+
if (standaloneBridgeFiller &&
|
|
349
|
+
bridgeRun?.type === 'cabinet' &&
|
|
350
|
+
bridgeFiller &&
|
|
351
|
+
sourceRun?.type === 'cabinet') {
|
|
352
|
+
const fillerPatch = overrides.get(bridgeFiller.id);
|
|
353
|
+
const bridgeWidth = fillerPatch?.width ?? bridgeFiller.width;
|
|
354
|
+
overrides.set(bridgeFiller.id, {
|
|
355
|
+
...fillerPatch,
|
|
356
|
+
position: [0, bridgeFiller.position[1], 0],
|
|
357
|
+
});
|
|
358
|
+
const bridgeSide = bridgeFiller.openSide === 'left'
|
|
359
|
+
? 'right'
|
|
360
|
+
: bridgeFiller.openSide === 'right'
|
|
361
|
+
? 'left'
|
|
362
|
+
: corner.side;
|
|
363
|
+
const bridgeWorldPosition = anchoredBridgeRunWorldPosition({
|
|
364
|
+
sourceWallTop: sourceWall,
|
|
365
|
+
sourceRun,
|
|
366
|
+
bridgeWidth,
|
|
367
|
+
side: bridgeSide,
|
|
368
|
+
fallbackPosition: resolveCabinetWorldTransform(bridgeRun, nodes).position,
|
|
369
|
+
nodes,
|
|
370
|
+
});
|
|
371
|
+
const frameParent = cabinetFrameParent(bridgeRun, nodes);
|
|
372
|
+
overrides.set(bridgeRun.id, {
|
|
373
|
+
...(overrides.get(bridgeRun.id) ?? {}),
|
|
374
|
+
position: frameParent
|
|
375
|
+
? worldToCabinetLocalPosition(frameParent, nodes, bridgeWorldPosition)
|
|
376
|
+
: bridgeWorldPosition,
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
if (widthMode === 'corner-pair' &&
|
|
381
|
+
(sourceDirectionChanged || connectedDirectionChanged) &&
|
|
382
|
+
cornerWallFiller &&
|
|
383
|
+
connectedWall) {
|
|
384
|
+
const cornerAnchor = corner.side === 'right' ? 'min' : 'max';
|
|
385
|
+
const connectedAnchor = corner.side === 'right' ? 'max' : 'min';
|
|
386
|
+
setWidth(cornerWallFiller, cornerWallFiller.width + depthDelta, cornerAnchor);
|
|
387
|
+
setWidth(connectedWall, connectedWall.width - depthDelta, connectedAnchor);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
return [...overrides];
|
|
391
|
+
}
|
|
392
|
+
export function cornerSourceWidthOverridesForDerivedDepth(run, nodes, depth) {
|
|
393
|
+
const link = cornerDerivedRunLink(run.metadata);
|
|
394
|
+
if (link?.role !== 'base-leg' || link.turnSide !== link.side)
|
|
395
|
+
return [];
|
|
396
|
+
const sourceModule = nodes[link.sourceModuleId];
|
|
397
|
+
const sourceRun = nodes[link.sourceRunId];
|
|
398
|
+
if (sourceModule?.type !== 'cabinet-module' || sourceRun?.type !== 'cabinet')
|
|
399
|
+
return [];
|
|
400
|
+
const width = Math.max(MIN_TRIMMED_CORNER_CONNECTED_WIDTH, sourceModule.width - (depth - run.depth));
|
|
401
|
+
const widthDelta = width - sourceModule.width;
|
|
402
|
+
const direction = link.side === 'right' ? 1 : -1;
|
|
403
|
+
const overrides = [
|
|
404
|
+
[
|
|
405
|
+
sourceModule.id,
|
|
406
|
+
{
|
|
407
|
+
width,
|
|
408
|
+
position: [
|
|
409
|
+
sourceModule.position[0] + (direction * widthDelta) / 2,
|
|
410
|
+
sourceModule.position[1],
|
|
411
|
+
sourceModule.position[2],
|
|
412
|
+
],
|
|
413
|
+
},
|
|
414
|
+
],
|
|
415
|
+
];
|
|
416
|
+
const wallChild = wallChildOf(sourceModule, nodes);
|
|
417
|
+
if (wallChild) {
|
|
418
|
+
overrides.push([
|
|
419
|
+
wallChild.id,
|
|
420
|
+
{
|
|
421
|
+
width,
|
|
422
|
+
position: [0, wallChild.position[1], backAlignZ(sourceModule.depth, wallChild.depth)],
|
|
423
|
+
},
|
|
424
|
+
]);
|
|
425
|
+
}
|
|
426
|
+
const sourceLink = cornerSourceLink(sourceModule.metadata);
|
|
427
|
+
for (const linkedRunId of sourceLink?.linkedRunIds ?? []) {
|
|
428
|
+
const linkedRun = nodes[linkedRunId];
|
|
429
|
+
if (linkedRun?.type !== 'cabinet')
|
|
430
|
+
continue;
|
|
431
|
+
const derivedLink = cornerDerivedRunLink(linkedRun.metadata);
|
|
432
|
+
if (derivedLink?.role !== 'bridge' ||
|
|
433
|
+
derivedLink.side !== link.side ||
|
|
434
|
+
derivedLink.sourceModuleId !== sourceModule.id) {
|
|
435
|
+
continue;
|
|
436
|
+
}
|
|
437
|
+
const bridge = cabinetModulesForRun(linkedRun, nodes).find((module) => module.name === 'Wall Bridge Filler');
|
|
438
|
+
if (!bridge)
|
|
439
|
+
continue;
|
|
440
|
+
const bridgeWidth = Math.max(0.01, bridge.width - widthDelta);
|
|
441
|
+
const bridgeWidthDelta = bridgeWidth - bridge.width;
|
|
442
|
+
overrides.push([
|
|
443
|
+
bridge.id,
|
|
444
|
+
{
|
|
445
|
+
width: bridgeWidth,
|
|
446
|
+
position: [
|
|
447
|
+
bridge.position[0] - (direction * bridgeWidthDelta) / 2,
|
|
448
|
+
bridge.position[1],
|
|
449
|
+
bridge.position[2],
|
|
450
|
+
],
|
|
451
|
+
},
|
|
452
|
+
]);
|
|
453
|
+
const linkedMetadata = cabinetMetadataRecord(linkedRun.metadata);
|
|
454
|
+
const linkedRevision = typeof linkedMetadata.cabinetLayoutRevision === 'number'
|
|
455
|
+
? linkedMetadata.cabinetLayoutRevision
|
|
456
|
+
: 0;
|
|
457
|
+
overrides.push([
|
|
458
|
+
linkedRun.id,
|
|
459
|
+
{
|
|
460
|
+
metadata: {
|
|
461
|
+
...linkedMetadata,
|
|
462
|
+
cabinetLayoutRevision: linkedRevision + 1,
|
|
463
|
+
},
|
|
464
|
+
},
|
|
465
|
+
]);
|
|
466
|
+
}
|
|
467
|
+
const metadata = cabinetMetadataRecord(sourceRun.metadata);
|
|
468
|
+
const revision = typeof metadata.cabinetLayoutRevision === 'number' ? metadata.cabinetLayoutRevision : 0;
|
|
469
|
+
overrides.push([
|
|
470
|
+
sourceRun.id,
|
|
471
|
+
{ metadata: { ...metadata, cabinetLayoutRevision: revision + 1 } },
|
|
472
|
+
]);
|
|
473
|
+
return overrides;
|
|
474
|
+
}
|
|
203
475
|
export function cornerSourceModulesForRun(run, nodes) {
|
|
204
476
|
return cabinetModulesForRun(run, nodes).filter((module) => cornerSourceLink(module.metadata) != null);
|
|
205
477
|
}
|
|
@@ -539,7 +811,7 @@ function resolveCornerSourceSideWallLimitedWidth({ desiredWidth, module, nodes,
|
|
|
539
811
|
if (side === 'right') {
|
|
540
812
|
if (overlap.maxX <= fixedEdge + WALL_CLEARANCE_EPSILON)
|
|
541
813
|
continue;
|
|
542
|
-
const maxSourceRight = overlap.minX -
|
|
814
|
+
const maxSourceRight = overlap.minX - module.depth;
|
|
543
815
|
if (maxSourceRight <= fixedEdge + desiredWidth + WALL_CLEARANCE_EPSILON) {
|
|
544
816
|
cappedWidth = Math.min(cappedWidth, Math.max(0, maxSourceRight - fixedEdge));
|
|
545
817
|
}
|
|
@@ -547,15 +819,19 @@ function resolveCornerSourceSideWallLimitedWidth({ desiredWidth, module, nodes,
|
|
|
547
819
|
}
|
|
548
820
|
if (overlap.minX >= fixedEdge - WALL_CLEARANCE_EPSILON)
|
|
549
821
|
continue;
|
|
550
|
-
const minSourceLeft = overlap.maxX +
|
|
822
|
+
const minSourceLeft = overlap.maxX + module.depth;
|
|
551
823
|
if (minSourceLeft >= fixedEdge - desiredWidth - WALL_CLEARANCE_EPSILON) {
|
|
552
824
|
cappedWidth = Math.min(cappedWidth, Math.max(0, fixedEdge - minSourceLeft));
|
|
553
825
|
}
|
|
554
826
|
}
|
|
555
827
|
return cappedWidth;
|
|
556
828
|
}
|
|
557
|
-
function computeCornerRunLayout({ module, run, nodes, side, turnSide = side, sourceModuleOverride, minConnectedWidth = MIN_CORNER_CONNECTED_WIDTH, }) {
|
|
829
|
+
function computeCornerRunLayout({ module, run, nodes, side, turnSide = side, sourceModuleOverride, baseLegDepthOverride, minConnectedWidth = MIN_CORNER_CONNECTED_WIDTH, }) {
|
|
558
830
|
const sourceModule = sourceModuleOverride ?? module;
|
|
831
|
+
const sourceDepth = sourceModule.depth;
|
|
832
|
+
const baseLegDepth = baseLegDepthOverride ?? CABINET_BASE_DEPTH;
|
|
833
|
+
const wallDepth = wallChildOf(sourceModule, nodes)?.depth ?? CABINET_WALL_DEPTH;
|
|
834
|
+
const wallCornerSpan = wallDepth;
|
|
559
835
|
const modules = cabinetModulesForRun(run, nodes).map((entry) => entry.id === sourceModule.id ? sourceModule : entry);
|
|
560
836
|
const extent = runLocalXExtent(modules);
|
|
561
837
|
if (!extent || modules.length === 0)
|
|
@@ -567,8 +843,8 @@ function computeCornerRunLayout({ module, run, nodes, side, turnSide = side, sou
|
|
|
567
843
|
const sourceAxis = [Math.cos(runWorld.rotation), -Math.sin(runWorld.rotation)];
|
|
568
844
|
const sign = side === 'right' ? 1 : -1;
|
|
569
845
|
const shiftedCorner = [
|
|
570
|
-
corner[0] + sign *
|
|
571
|
-
corner[2] + sign *
|
|
846
|
+
corner[0] + sign * baseLegDepth * sourceAxis[0],
|
|
847
|
+
corner[2] + sign * baseLegDepth * sourceAxis[1],
|
|
572
848
|
];
|
|
573
849
|
const legRotation = turnSide === 'right' ? runWorld.rotation - Math.PI / 2 : runWorld.rotation + Math.PI / 2;
|
|
574
850
|
const legAxis = [Math.cos(legRotation), -Math.sin(legRotation)];
|
|
@@ -576,12 +852,12 @@ function computeCornerRunLayout({ module, run, nodes, side, turnSide = side, sou
|
|
|
576
852
|
backLeft: side === 'right'
|
|
577
853
|
? shiftedCorner
|
|
578
854
|
: [
|
|
579
|
-
shiftedCorner[0] - legAxis[0] * (
|
|
580
|
-
shiftedCorner[1] - legAxis[1] * (
|
|
855
|
+
shiftedCorner[0] - legAxis[0] * (sourceDepth + sourceModule.width),
|
|
856
|
+
shiftedCorner[1] - legAxis[1] * (sourceDepth + sourceModule.width),
|
|
581
857
|
],
|
|
582
858
|
desiredWidth: sourceModule.width,
|
|
583
|
-
depth:
|
|
584
|
-
leadingOffset:
|
|
859
|
+
depth: baseLegDepth,
|
|
860
|
+
leadingOffset: sourceDepth,
|
|
585
861
|
nodes,
|
|
586
862
|
rotation: legRotation,
|
|
587
863
|
sourceNode: sourceModule,
|
|
@@ -589,8 +865,8 @@ function computeCornerRunLayout({ module, run, nodes, side, turnSide = side, sou
|
|
|
589
865
|
if (connectedWidth < minConnectedWidth - WALL_CLEARANCE_EPSILON)
|
|
590
866
|
return null;
|
|
591
867
|
const connectedShelfCount = inheritedShelfCount(module);
|
|
592
|
-
const baseLegLength =
|
|
593
|
-
const baseFirstWidth = side === 'right' ?
|
|
868
|
+
const baseLegLength = sourceDepth + connectedWidth;
|
|
869
|
+
const baseFirstWidth = side === 'right' ? sourceDepth : connectedWidth;
|
|
594
870
|
const baseBackLeft = side === 'right'
|
|
595
871
|
? shiftedCorner
|
|
596
872
|
: [
|
|
@@ -601,11 +877,11 @@ function computeCornerRunLayout({ module, run, nodes, side, turnSide = side, sou
|
|
|
601
877
|
backLeft: baseBackLeft,
|
|
602
878
|
rotation: legRotation,
|
|
603
879
|
firstWidth: baseFirstWidth,
|
|
604
|
-
depth:
|
|
880
|
+
depth: baseLegDepth,
|
|
605
881
|
y: runWorld.position[1],
|
|
606
882
|
});
|
|
607
|
-
const wallLegLength =
|
|
608
|
-
const wallFirstWidth = side === 'right' ?
|
|
883
|
+
const wallLegLength = wallCornerSpan + connectedWidth;
|
|
884
|
+
const wallFirstWidth = side === 'right' ? wallCornerSpan : connectedWidth;
|
|
609
885
|
const wallBackLeft = side === 'right'
|
|
610
886
|
? shiftedCorner
|
|
611
887
|
: [
|
|
@@ -619,7 +895,7 @@ function computeCornerRunLayout({ module, run, nodes, side, turnSide = side, sou
|
|
|
619
895
|
depth: CABINET_WALL_DEPTH,
|
|
620
896
|
y: runWorld.position[1] + wallBottomHeightForTallAlignment(),
|
|
621
897
|
});
|
|
622
|
-
const bridgeWidth = Math.max(0
|
|
898
|
+
const bridgeWidth = Math.max(0, baseLegDepth - CABINET_WALL_DEPTH);
|
|
623
899
|
const sourceCornerModule = side === 'right' ? modules.at(-1) : modules[0];
|
|
624
900
|
if (!sourceCornerModule)
|
|
625
901
|
return null;
|
|
@@ -650,6 +926,10 @@ function computeCornerRunLayout({ module, run, nodes, side, turnSide = side, sou
|
|
|
650
926
|
connectedWidth,
|
|
651
927
|
connectedShelfCount,
|
|
652
928
|
bridgeWidth,
|
|
929
|
+
sourceDepth,
|
|
930
|
+
baseLegDepth,
|
|
931
|
+
wallDepth,
|
|
932
|
+
wallCornerSpan,
|
|
653
933
|
sourceCornerWidth: sourceCornerModule.width,
|
|
654
934
|
};
|
|
655
935
|
}
|
|
@@ -845,13 +1125,17 @@ function cornerSelectionRootId(sourceRun, derivedRunId) {
|
|
|
845
1125
|
? derivedRunId
|
|
846
1126
|
: sourceRun.id;
|
|
847
1127
|
}
|
|
848
|
-
function syncDerivedCornerRun({ role, run, sourceModule, sourceRun, side, turnSide, sceneApi, }) {
|
|
1128
|
+
function syncDerivedCornerRun({ baseLayout, role, run, sourceModule, sourceRun, side, turnSide, sceneApi, }) {
|
|
1129
|
+
if (baseLayout !== 'full' && role === 'bridge')
|
|
1130
|
+
return;
|
|
1131
|
+
const sourceDepth = sourceModule.depth;
|
|
849
1132
|
const layout = computeCornerRunLayout({
|
|
850
1133
|
module: sourceModule,
|
|
851
1134
|
run: sourceRun,
|
|
852
1135
|
nodes: sceneApi.nodes(),
|
|
853
1136
|
side,
|
|
854
1137
|
turnSide,
|
|
1138
|
+
baseLegDepthOverride: role === 'base-leg' ? run.depth : undefined,
|
|
855
1139
|
});
|
|
856
1140
|
if (!layout)
|
|
857
1141
|
return;
|
|
@@ -861,22 +1145,22 @@ function syncDerivedCornerRun({ role, run, sourceModule, sourceRun, side, turnSi
|
|
|
861
1145
|
const fullSpecs = role === 'base-leg'
|
|
862
1146
|
? side === 'right'
|
|
863
1147
|
? [
|
|
864
|
-
['Corner Filler',
|
|
1148
|
+
['Corner Filler', sourceDepth, 'right', 'corner-filler', true],
|
|
865
1149
|
['Base Cabinet', layout.connectedWidth, 'left', 'standard', false],
|
|
866
1150
|
]
|
|
867
1151
|
: [
|
|
868
1152
|
['Base Cabinet', layout.connectedWidth, 'right', 'standard', false],
|
|
869
|
-
['Corner Filler',
|
|
1153
|
+
['Corner Filler', sourceDepth, 'left', 'corner-filler', true],
|
|
870
1154
|
]
|
|
871
1155
|
: role === 'wall-leg'
|
|
872
1156
|
? side === 'right'
|
|
873
1157
|
? [
|
|
874
|
-
['Corner Wall Filler',
|
|
1158
|
+
['Corner Wall Filler', layout.wallCornerSpan, 'right', 'corner-filler', true],
|
|
875
1159
|
['Wall Cabinet', layout.connectedWidth, 'left', 'standard', false],
|
|
876
1160
|
]
|
|
877
1161
|
: [
|
|
878
1162
|
['Wall Cabinet', layout.connectedWidth, 'right', 'standard', false],
|
|
879
|
-
['Corner Wall Filler',
|
|
1163
|
+
['Corner Wall Filler', layout.wallCornerSpan, 'left', 'corner-filler', true],
|
|
880
1164
|
]
|
|
881
1165
|
: side === 'right'
|
|
882
1166
|
? [
|
|
@@ -899,11 +1183,116 @@ function syncDerivedCornerRun({ role, run, sourceModule, sourceRun, side, turnSi
|
|
|
899
1183
|
cornerShelf: cornerShelf,
|
|
900
1184
|
},
|
|
901
1185
|
]));
|
|
902
|
-
const currentSpecs = modules
|
|
1186
|
+
const currentSpecs = modules
|
|
1187
|
+
.map((entry) => {
|
|
1188
|
+
const spec = specByName.get(entry.name);
|
|
1189
|
+
if (spec)
|
|
1190
|
+
return { ...spec };
|
|
1191
|
+
if (baseLayout === 'full')
|
|
1192
|
+
return null;
|
|
1193
|
+
return {
|
|
1194
|
+
width: entry.width,
|
|
1195
|
+
openSide: entry.openSide,
|
|
1196
|
+
moduleKind: entry.moduleKind,
|
|
1197
|
+
cornerShelf: entry.cornerShelf,
|
|
1198
|
+
};
|
|
1199
|
+
})
|
|
1200
|
+
.filter((entry) => entry != null);
|
|
903
1201
|
if (currentSpecs.length !== modules.length)
|
|
904
1202
|
return;
|
|
1203
|
+
if (baseLayout === 'preserve-connected-widths' && (role === 'base-leg' || role === 'wall-leg')) {
|
|
1204
|
+
const fillerName = role === 'base-leg' ? 'Corner Filler' : 'Corner Wall Filler';
|
|
1205
|
+
modules.forEach((entry, index) => {
|
|
1206
|
+
if (entry.name !== fillerName)
|
|
1207
|
+
currentSpecs[index].width = entry.width;
|
|
1208
|
+
});
|
|
1209
|
+
}
|
|
1210
|
+
if (baseLayout === 'width-only' && (role === 'base-leg' || role === 'wall-leg')) {
|
|
1211
|
+
const fillerName = role === 'base-leg' ? 'Corner Filler' : 'Corner Wall Filler';
|
|
1212
|
+
const connectedName = role === 'base-leg' ? 'Base Cabinet' : 'Wall Cabinet';
|
|
1213
|
+
const fillerIndex = modules.findIndex((entry) => entry.name === fillerName);
|
|
1214
|
+
const connectedIndex = modules.findIndex((entry) => entry.name === connectedName);
|
|
1215
|
+
if (fillerIndex >= 0 && connectedIndex >= 0) {
|
|
1216
|
+
const pairWidth = modules[fillerIndex].width + modules[connectedIndex].width;
|
|
1217
|
+
const currentConnectedWidth = modules[connectedIndex].width;
|
|
1218
|
+
const minConnectedWidth = Math.min(currentConnectedWidth, MIN_CABINET_WIDTH);
|
|
1219
|
+
const maxConnectedWidth = Math.max(currentConnectedWidth, MAX_CABINET_WIDTH);
|
|
1220
|
+
currentSpecs[connectedIndex].width = Math.min(maxConnectedWidth, Math.max(minConnectedWidth, pairWidth - currentSpecs[fillerIndex].width));
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
905
1223
|
const currentWidths = currentSpecs.map((entry) => entry.width);
|
|
906
1224
|
const currentCenters = chainModuleCenters(currentWidths);
|
|
1225
|
+
if (baseLayout !== 'full' && (role === 'base-leg' || role === 'wall-leg')) {
|
|
1226
|
+
const nextTotalWidth = currentWidths.reduce((sum, width) => sum + width, 0);
|
|
1227
|
+
const fixedEdge = side === 'right'
|
|
1228
|
+
? Math.min(...modules.map((entry) => entry.position[0] - entry.width / 2))
|
|
1229
|
+
: Math.max(...modules.map((entry) => entry.position[0] + entry.width / 2)) - nextTotalWidth;
|
|
1230
|
+
let cursor = fixedEdge;
|
|
1231
|
+
modules.forEach((entry, index) => {
|
|
1232
|
+
const spec = currentSpecs[index];
|
|
1233
|
+
if (!spec)
|
|
1234
|
+
return;
|
|
1235
|
+
const positionX = cursor + spec.width / 2;
|
|
1236
|
+
cursor += spec.width;
|
|
1237
|
+
sceneApi.update(entry.id, {
|
|
1238
|
+
width: spec.width,
|
|
1239
|
+
position: [positionX, entry.position[1], entry.position[2]],
|
|
1240
|
+
});
|
|
1241
|
+
const parentShiftX = positionX - entry.position[0];
|
|
1242
|
+
const sourceLink = cornerSourceLink(entry.metadata);
|
|
1243
|
+
const sourceEdgeShift = sourceLink?.side === 'right'
|
|
1244
|
+
? positionX + spec.width / 2 - (entry.position[0] + entry.width / 2)
|
|
1245
|
+
: sourceLink?.side === 'left'
|
|
1246
|
+
? positionX - spec.width / 2 - (entry.position[0] - entry.width / 2)
|
|
1247
|
+
: parentShiftX;
|
|
1248
|
+
for (const childId of entry.children ?? []) {
|
|
1249
|
+
const child = sceneApi.get(childId);
|
|
1250
|
+
if (child?.type !== 'cabinet')
|
|
1251
|
+
continue;
|
|
1252
|
+
const derivedLink = cornerDerivedRunLink(child.metadata);
|
|
1253
|
+
if (derivedLink?.sourceModuleId === entry.id && derivedLink.sourceRunId === run.id) {
|
|
1254
|
+
sceneApi.update(child.id, {
|
|
1255
|
+
position: [
|
|
1256
|
+
child.position[0] + sourceEdgeShift - parentShiftX,
|
|
1257
|
+
child.position[1],
|
|
1258
|
+
child.position[2],
|
|
1259
|
+
],
|
|
1260
|
+
});
|
|
1261
|
+
continue;
|
|
1262
|
+
}
|
|
1263
|
+
sceneApi.update(child.id, {
|
|
1264
|
+
position: [child.position[0] - parentShiftX, child.position[1], child.position[2]],
|
|
1265
|
+
});
|
|
1266
|
+
}
|
|
1267
|
+
const liveRun = sceneApi.get(run.id) ?? run;
|
|
1268
|
+
for (const childId of liveRun.children ?? []) {
|
|
1269
|
+
const child = sceneApi.get(childId);
|
|
1270
|
+
if (child?.type !== 'cabinet')
|
|
1271
|
+
continue;
|
|
1272
|
+
const derivedLink = cornerDerivedRunLink(child.metadata);
|
|
1273
|
+
if (derivedLink?.role !== 'base-leg' ||
|
|
1274
|
+
derivedLink.sourceModuleId !== entry.id ||
|
|
1275
|
+
derivedLink.sourceRunId !== run.id) {
|
|
1276
|
+
continue;
|
|
1277
|
+
}
|
|
1278
|
+
sceneApi.update(child.id, {
|
|
1279
|
+
position: [child.position[0] + sourceEdgeShift, child.position[1], child.position[2]],
|
|
1280
|
+
});
|
|
1281
|
+
}
|
|
1282
|
+
const wallChild = wallChildOf(entry, sceneApi.nodes());
|
|
1283
|
+
if (wallChild) {
|
|
1284
|
+
const offsetX = role === 'base-leg' && entry.name === 'Base Cabinet'
|
|
1285
|
+
? (side === 'right' ? 1 : -1) * (layout.wallCornerSpan - sourceDepth)
|
|
1286
|
+
: 0;
|
|
1287
|
+
sceneApi.update(wallChild.id, {
|
|
1288
|
+
width: spec.width,
|
|
1289
|
+
position: [offsetX, wallChild.position[1], wallChild.position[2]],
|
|
1290
|
+
});
|
|
1291
|
+
}
|
|
1292
|
+
});
|
|
1293
|
+
bumpCabinetRunLayoutRevision(sceneApi, sceneApi.get(run.id) ?? run);
|
|
1294
|
+
return;
|
|
1295
|
+
}
|
|
907
1296
|
const firstName = modules[0].name;
|
|
908
1297
|
const firstIndex = fullNames.indexOf(firstName);
|
|
909
1298
|
if (firstIndex < 0)
|
|
@@ -929,10 +1318,21 @@ function syncDerivedCornerRun({ role, run, sourceModule, sourceRun, side, turnSi
|
|
|
929
1318
|
: layout.bridgeRunPosition;
|
|
930
1319
|
const sourceRunWorld = resolveCabinetWorldTransform(sourceRun, sceneApi.nodes());
|
|
931
1320
|
const rotation = role === 'bridge' ? sourceRunWorld.rotation : layout.legRotation;
|
|
932
|
-
const depth = role === '
|
|
1321
|
+
const depth = role === 'bridge' ? layout.wallDepth : run.depth;
|
|
1322
|
+
const depthAdjustedAnchorPosition = role !== 'base-leg' && !isStandaloneBridgeFillerRun
|
|
1323
|
+
? runLocalToPlan({ position: anchorPosition, rotation }, [
|
|
1324
|
+
0,
|
|
1325
|
+
0,
|
|
1326
|
+
(depth - layout.wallDepth) / 2,
|
|
1327
|
+
])
|
|
1328
|
+
: anchorPosition;
|
|
933
1329
|
const runWorldPosition = isStandaloneBridgeFillerRun
|
|
934
|
-
?
|
|
935
|
-
: runLocalToPlan({ position:
|
|
1330
|
+
? depthAdjustedAnchorPosition
|
|
1331
|
+
: runLocalToPlan({ position: depthAdjustedAnchorPosition, rotation }, [
|
|
1332
|
+
fullCenters[firstIndex] ?? 0,
|
|
1333
|
+
0,
|
|
1334
|
+
0,
|
|
1335
|
+
]);
|
|
936
1336
|
// Place relative to the derived run's ACTUAL parent frame — source run for
|
|
937
1337
|
// new scenes, source module for legacy scenes that nested legs under it.
|
|
938
1338
|
const frameParent = cabinetFrameParent(run, sceneApi.nodes()) ?? sourceRun;
|
|
@@ -967,7 +1367,7 @@ function syncDerivedCornerRun({ role, run, sourceModule, sourceRun, side, turnSi
|
|
|
967
1367
|
position: [
|
|
968
1368
|
currentCenters[index] ?? 0,
|
|
969
1369
|
role === 'base-leg' ? runModuleBaseY(sourceRun) : 0,
|
|
970
|
-
0,
|
|
1370
|
+
role === 'base-leg' ? backAnchoredModuleZ(entry.position[2], entry.depth, depth) : 0,
|
|
971
1371
|
],
|
|
972
1372
|
toeKickDepth: role === 'base-leg' ? sourceRun.toeKickDepth : 0,
|
|
973
1373
|
countertopThickness: role === 'base-leg' ? sourceRun.countertopThickness : 0,
|
|
@@ -992,12 +1392,14 @@ function syncDerivedCornerRun({ role, run, sourceModule, sourceRun, side, turnSi
|
|
|
992
1392
|
sceneApi,
|
|
993
1393
|
shelfCount: layout.connectedShelfCount,
|
|
994
1394
|
openSide: connectedBaseModule.openSide,
|
|
1395
|
+
offsetX: (side === 'right' ? 1 : -1) * (layout.wallCornerSpan - layout.sourceDepth),
|
|
1396
|
+
wallDepth: CABINET_WALL_DEPTH,
|
|
995
1397
|
});
|
|
996
1398
|
}
|
|
997
1399
|
}
|
|
998
1400
|
bumpCabinetRunLayoutRevision(sceneApi, sceneApi.get(run.id) ?? run);
|
|
999
1401
|
}
|
|
1000
|
-
export function syncCornerRunsFromSourceModule({ module, run, sceneApi, }) {
|
|
1402
|
+
export function syncCornerRunsFromSourceModule({ baseLayout = 'full', module, run, sceneApi, }) {
|
|
1001
1403
|
const link = cornerSourceLink(module.metadata);
|
|
1002
1404
|
if (!link)
|
|
1003
1405
|
return;
|
|
@@ -1009,6 +1411,7 @@ export function syncCornerRunsFromSourceModule({ module, run, sceneApi, }) {
|
|
|
1009
1411
|
if (!derivedLink)
|
|
1010
1412
|
continue;
|
|
1011
1413
|
syncDerivedCornerRun({
|
|
1414
|
+
baseLayout,
|
|
1012
1415
|
role: derivedLink.role,
|
|
1013
1416
|
run: linkedRun,
|
|
1014
1417
|
sourceModule: module,
|
|
@@ -1019,6 +1422,45 @@ export function syncCornerRunsFromSourceModule({ module, run, sceneApi, }) {
|
|
|
1019
1422
|
});
|
|
1020
1423
|
}
|
|
1021
1424
|
}
|
|
1425
|
+
export function syncCornerRunsFromRunSources({ baseLayout = 'full', run, sceneApi, }) {
|
|
1426
|
+
const effectiveBaseLayout = baseLayout === 'width-only' && !cornerDerivedRunLink(run.metadata)
|
|
1427
|
+
? 'preserve-connected-widths'
|
|
1428
|
+
: baseLayout;
|
|
1429
|
+
for (const sourceModule of cornerSourceModulesForRun(run, sceneApi.nodes())) {
|
|
1430
|
+
syncCornerRunsFromSourceModule({
|
|
1431
|
+
baseLayout: effectiveBaseLayout,
|
|
1432
|
+
module: sourceModule,
|
|
1433
|
+
run,
|
|
1434
|
+
sceneApi,
|
|
1435
|
+
});
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
export function previewCornerRunsFromRunSources({ baseLayout = 'full', initialOverrides = [], run, sceneApi, }) {
|
|
1439
|
+
const overrides = new Map();
|
|
1440
|
+
for (const [id, patch] of initialOverrides) {
|
|
1441
|
+
overrides.set(id, { ...(overrides.get(id) ?? {}), ...patch });
|
|
1442
|
+
}
|
|
1443
|
+
const previewNodes = { ...sceneApi.nodes() };
|
|
1444
|
+
for (const [id, patch] of overrides) {
|
|
1445
|
+
const current = previewNodes[id];
|
|
1446
|
+
if (current)
|
|
1447
|
+
previewNodes[id] = { ...current, ...patch };
|
|
1448
|
+
}
|
|
1449
|
+
const previewSceneApi = {
|
|
1450
|
+
...sceneApi,
|
|
1451
|
+
get: (id) => previewNodes[id],
|
|
1452
|
+
nodes: () => previewNodes,
|
|
1453
|
+
update: (id, patch) => {
|
|
1454
|
+
overrides.set(id, { ...(overrides.get(id) ?? {}), ...patch });
|
|
1455
|
+
const current = previewNodes[id];
|
|
1456
|
+
if (current)
|
|
1457
|
+
previewNodes[id] = { ...current, ...patch };
|
|
1458
|
+
},
|
|
1459
|
+
markDirty: () => { },
|
|
1460
|
+
};
|
|
1461
|
+
syncCornerRunsFromRunSources({ baseLayout, run, sceneApi: previewSceneApi });
|
|
1462
|
+
return [...overrides];
|
|
1463
|
+
}
|
|
1022
1464
|
/**
|
|
1023
1465
|
* Insert a new base module flush against the anchor's side (or the run's
|
|
1024
1466
|
* outer edge with no anchor). Gap-checked — returns null when a flush
|
|
@@ -1035,10 +1477,10 @@ export function planCabinetModuleSideAddition({ anchorModule, nodes, run, side,
|
|
|
1035
1477
|
});
|
|
1036
1478
|
if (x == null)
|
|
1037
1479
|
return null;
|
|
1038
|
-
const
|
|
1039
|
-
const
|
|
1040
|
-
|
|
1041
|
-
|
|
1480
|
+
const sortedModules = sortRunModules(modules);
|
|
1481
|
+
const depthSource = anchorModule ?? (side === 'left' ? sortedModules[0] : sortedModules.at(-1)) ?? null;
|
|
1482
|
+
const depth = depthSource?.depth ?? run.depth;
|
|
1483
|
+
const z = depthSource ? backAnchoredModuleZ(depthSource.position[2], depthSource.depth, depth) : 0;
|
|
1042
1484
|
const width = resolveSideAddedModuleWidth({
|
|
1043
1485
|
centerX: x,
|
|
1044
1486
|
centerZ: z,
|
|
@@ -1047,7 +1489,7 @@ export function planCabinetModuleSideAddition({ anchorModule, nodes, run, side,
|
|
|
1047
1489
|
nodes,
|
|
1048
1490
|
run,
|
|
1049
1491
|
side,
|
|
1050
|
-
sourceNode:
|
|
1492
|
+
sourceNode: depthSource ?? run,
|
|
1051
1493
|
});
|
|
1052
1494
|
if (width < MIN_CORNER_CONNECTED_WIDTH - WALL_CLEARANCE_EPSILON)
|
|
1053
1495
|
return null;
|
|
@@ -1135,7 +1577,7 @@ export function addCornerRun({ module, run, sceneApi, side, }) {
|
|
|
1135
1577
|
});
|
|
1136
1578
|
if (!resolvedLayout)
|
|
1137
1579
|
return null;
|
|
1138
|
-
const { baseRunPosition, wallRunPosition, bridgeFillerRunPosition, legRotation, connectedWidth, connectedShelfCount, bridgeWidth, } = resolvedLayout;
|
|
1580
|
+
const { baseRunPosition, wallRunPosition, bridgeFillerRunPosition, legRotation, connectedWidth, connectedShelfCount, bridgeWidth, sourceDepth, baseLegDepth, wallDepth, wallCornerSpan, } = resolvedLayout;
|
|
1139
1581
|
const runWorld = resolveCabinetWorldTransform(sourceRun, sceneApi.nodes());
|
|
1140
1582
|
const sourceWallChildId = ensureWallCabinetAbove({
|
|
1141
1583
|
module: sourceModule,
|
|
@@ -1155,7 +1597,7 @@ export function addCornerRun({ module, run, sceneApi, side, }) {
|
|
|
1155
1597
|
? [
|
|
1156
1598
|
{
|
|
1157
1599
|
name: 'Corner Filler',
|
|
1158
|
-
width:
|
|
1600
|
+
width: sourceDepth,
|
|
1159
1601
|
moduleKind: 'corner-filler',
|
|
1160
1602
|
openSide: 'right',
|
|
1161
1603
|
cornerShelf: true,
|
|
@@ -1177,7 +1619,7 @@ export function addCornerRun({ module, run, sceneApi, side, }) {
|
|
|
1177
1619
|
},
|
|
1178
1620
|
{
|
|
1179
1621
|
name: 'Corner Filler',
|
|
1180
|
-
width:
|
|
1622
|
+
width: sourceDepth,
|
|
1181
1623
|
moduleKind: 'corner-filler',
|
|
1182
1624
|
openSide: 'left',
|
|
1183
1625
|
cornerShelf: true,
|
|
@@ -1185,7 +1627,7 @@ export function addCornerRun({ module, run, sceneApi, side, }) {
|
|
|
1185
1627
|
},
|
|
1186
1628
|
];
|
|
1187
1629
|
const baseLeg = upsertCabinetRunWithModules({
|
|
1188
|
-
depth:
|
|
1630
|
+
depth: baseLegDepth,
|
|
1189
1631
|
modulePatches: baseModules,
|
|
1190
1632
|
name: 'Corner Base Run',
|
|
1191
1633
|
parentId: sourceRun.id,
|
|
@@ -1218,61 +1660,63 @@ export function addCornerRun({ module, run, sceneApi, side, }) {
|
|
|
1218
1660
|
}
|
|
1219
1661
|
const baseLegRunNode = sceneApi.get(baseLeg.runId) ?? sourceRun;
|
|
1220
1662
|
const cornerFillerModule = childModuleByName(baseLegRunNode, 'Corner Filler', sceneApi.nodes()) ??
|
|
1221
|
-
sceneApi.get(baseLeg.moduleIds[0]);
|
|
1663
|
+
sceneApi.get(baseLeg.moduleIds[endSide === 'right' ? 0 : 1] ?? baseLeg.moduleIds[0]);
|
|
1222
1664
|
const connectedBaseModule = childModuleByName(baseLegRunNode, 'Base Cabinet', sceneApi.nodes()) ??
|
|
1223
|
-
sceneApi.get(baseLeg.moduleIds[1]);
|
|
1665
|
+
sceneApi.get(baseLeg.moduleIds[endSide === 'right' ? 1 : 0] ?? baseLeg.moduleIds[0]);
|
|
1224
1666
|
if (cornerFillerModule) {
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1667
|
+
if (bridgeWidth >= MIN_CORNER_BRIDGE_WIDTH) {
|
|
1668
|
+
const bridgeRunWorldPosition = anchoredBridgeRunWorldPosition({
|
|
1669
|
+
sourceWallTop: existingWallTop,
|
|
1670
|
+
sourceRun,
|
|
1671
|
+
bridgeWidth,
|
|
1672
|
+
side: endSide,
|
|
1673
|
+
fallbackPosition: bridgeFillerRunPosition,
|
|
1674
|
+
nodes: sceneApi.nodes(),
|
|
1675
|
+
});
|
|
1676
|
+
const bridgeRunLocalPosition = worldToCabinetLocalPosition(cornerFillerModule, sceneApi.nodes(), bridgeRunWorldPosition);
|
|
1677
|
+
const bridgeRunLocalRotation = worldToCabinetLocalRotation(cornerFillerModule, sceneApi.nodes(), runWorld.rotation);
|
|
1678
|
+
const bridgeRun = upsertCabinetRunWithModules({
|
|
1679
|
+
depth: wallDepth,
|
|
1680
|
+
modulePatches: [
|
|
1681
|
+
{
|
|
1682
|
+
name: 'Wall Bridge Filler',
|
|
1683
|
+
width: bridgeWidth,
|
|
1684
|
+
moduleKind: 'corner-filler',
|
|
1685
|
+
openSide: endSide === 'right' ? 'left' : 'right',
|
|
1686
|
+
cornerShelf: true,
|
|
1687
|
+
stack: doorStack(connectedShelfCount),
|
|
1688
|
+
},
|
|
1689
|
+
],
|
|
1690
|
+
name: 'Corner Wall Bridge',
|
|
1691
|
+
parentId: cornerFillerModule.id,
|
|
1692
|
+
position: bridgeRunLocalPosition,
|
|
1693
|
+
rotation: bridgeRunLocalRotation,
|
|
1694
|
+
runTier: 'wall',
|
|
1695
|
+
sceneApi,
|
|
1696
|
+
sourceRun,
|
|
1697
|
+
});
|
|
1698
|
+
linkedRunIds.push(bridgeRun.runId);
|
|
1699
|
+
const bridgeRunLiveMetadata = sceneApi.get(bridgeRun.runId)?.metadata ?? null;
|
|
1700
|
+
const bridgeRunMetadata = cabinetMetadataRecord(bridgeRunLiveMetadata);
|
|
1701
|
+
sceneApi.update(bridgeRun.runId, {
|
|
1702
|
+
metadata: {
|
|
1703
|
+
...(selectionRootId === bridgeRun.runId
|
|
1704
|
+
? bridgeRunMetadata
|
|
1705
|
+
: withSelectionProxyMetadata(bridgeRunLiveMetadata, selectionRootId)),
|
|
1706
|
+
cabinetCornerDerivedRun: {
|
|
1707
|
+
role: 'bridge',
|
|
1708
|
+
side: endSide,
|
|
1709
|
+
turnSide,
|
|
1710
|
+
sourceModuleId: sourceModule.id,
|
|
1711
|
+
sourceRunId: sourceRun.id,
|
|
1712
|
+
},
|
|
1269
1713
|
},
|
|
1270
|
-
}
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1714
|
+
});
|
|
1715
|
+
for (const moduleId of bridgeRun.moduleIds) {
|
|
1716
|
+
setCabinetSelectionProxy(sceneApi, moduleId, selectionRootId);
|
|
1717
|
+
}
|
|
1274
1718
|
}
|
|
1275
|
-
const wallModuleCenters = chainModuleCenters([
|
|
1719
|
+
const wallModuleCenters = chainModuleCenters([wallCornerSpan, connectedWidth]);
|
|
1276
1720
|
const cornerWallFillerCenter = endSide === 'right' ? (wallModuleCenters[0] ?? 0) : (wallModuleCenters[1] ?? 0);
|
|
1277
1721
|
const cornerWallFillerWorldPosition = runLocalToPlan({ position: wallRunPosition, rotation: legRotation }, [cornerWallFillerCenter, 0, 0]);
|
|
1278
1722
|
const wallFillerRun = upsertCabinetRunWithModules({
|
|
@@ -1280,7 +1724,7 @@ export function addCornerRun({ module, run, sceneApi, side, }) {
|
|
|
1280
1724
|
modulePatches: [
|
|
1281
1725
|
{
|
|
1282
1726
|
name: 'Corner Wall Filler',
|
|
1283
|
-
width:
|
|
1727
|
+
width: wallCornerSpan,
|
|
1284
1728
|
moduleKind: 'corner-filler',
|
|
1285
1729
|
openSide: endSide === 'right' ? 'right' : 'left',
|
|
1286
1730
|
cornerShelf: true,
|
|
@@ -1323,32 +1767,112 @@ export function addCornerRun({ module, run, sceneApi, side, }) {
|
|
|
1323
1767
|
sceneApi,
|
|
1324
1768
|
shelfCount: connectedShelfCount,
|
|
1325
1769
|
openSide: connectedBaseModule.openSide,
|
|
1770
|
+
offsetX: (endSide === 'right' ? 1 : -1) * (wallCornerSpan - sourceDepth),
|
|
1771
|
+
wallDepth: CABINET_WALL_DEPTH,
|
|
1326
1772
|
});
|
|
1327
1773
|
if (wallChildId) {
|
|
1328
1774
|
setCabinetSelectionProxy(sceneApi, wallChildId, selectionRootId);
|
|
1329
1775
|
}
|
|
1330
1776
|
}
|
|
1777
|
+
const liveSourceMetadata = sceneApi.get(sourceModule.id)?.metadata ?? null;
|
|
1778
|
+
const sourceMetadata = cabinetMetadataRecord(liveSourceMetadata);
|
|
1779
|
+
const existingSourceLink = cornerSourceLink(liveSourceMetadata);
|
|
1331
1780
|
sceneApi.update(sourceModule.id, {
|
|
1332
1781
|
metadata: {
|
|
1333
|
-
...
|
|
1782
|
+
...sourceMetadata,
|
|
1334
1783
|
cabinetCornerSourceLink: {
|
|
1335
1784
|
side: endSide,
|
|
1336
|
-
linkedRunIds
|
|
1785
|
+
linkedRunIds: [
|
|
1786
|
+
...new Set([...(existingSourceLink?.linkedRunIds ?? []), ...linkedRunIds]),
|
|
1787
|
+
],
|
|
1337
1788
|
},
|
|
1338
1789
|
},
|
|
1339
1790
|
});
|
|
1340
1791
|
bumpCabinetRunLayoutRevision(sceneApi, sourceRun);
|
|
1341
|
-
return
|
|
1792
|
+
return connectedBaseModule?.id ?? null;
|
|
1793
|
+
}
|
|
1794
|
+
function cabinetWorldBoxesOverlap(a, b) {
|
|
1795
|
+
const aTop = a.center[1] + a.height;
|
|
1796
|
+
const bTop = b.center[1] + b.height;
|
|
1797
|
+
if (Math.min(aTop, bTop) - Math.max(a.center[1], b.center[1]) <= CABINET_EDGE_EPSILON) {
|
|
1798
|
+
return false;
|
|
1799
|
+
}
|
|
1800
|
+
const axes = [
|
|
1801
|
+
[Math.cos(a.rotation), -Math.sin(a.rotation)],
|
|
1802
|
+
[Math.sin(a.rotation), Math.cos(a.rotation)],
|
|
1803
|
+
[Math.cos(b.rotation), -Math.sin(b.rotation)],
|
|
1804
|
+
[Math.sin(b.rotation), Math.cos(b.rotation)],
|
|
1805
|
+
];
|
|
1806
|
+
const aXAxis = axes[0];
|
|
1807
|
+
const aZAxis = axes[1];
|
|
1808
|
+
const bXAxis = axes[2];
|
|
1809
|
+
const bZAxis = axes[3];
|
|
1810
|
+
const dx = b.center[0] - a.center[0];
|
|
1811
|
+
const dz = b.center[2] - a.center[2];
|
|
1812
|
+
for (const axis of axes) {
|
|
1813
|
+
const centerDistance = Math.abs(dx * axis[0] + dz * axis[1]);
|
|
1814
|
+
const aRadius = (a.width / 2) * Math.abs(aXAxis[0] * axis[0] + aXAxis[1] * axis[1]) +
|
|
1815
|
+
(a.depth / 2) * Math.abs(aZAxis[0] * axis[0] + aZAxis[1] * axis[1]);
|
|
1816
|
+
const bRadius = (b.width / 2) * Math.abs(bXAxis[0] * axis[0] + bXAxis[1] * axis[1]) +
|
|
1817
|
+
(b.depth / 2) * Math.abs(bZAxis[0] * axis[0] + bZAxis[1] * axis[1]);
|
|
1818
|
+
if (centerDistance >= aRadius + bRadius - CABINET_EDGE_EPSILON)
|
|
1819
|
+
return false;
|
|
1820
|
+
}
|
|
1821
|
+
return true;
|
|
1822
|
+
}
|
|
1823
|
+
function isWallTierModule(module, nodes) {
|
|
1824
|
+
const parent = module.parentId ? nodes[module.parentId] : undefined;
|
|
1825
|
+
if (parent?.type === 'cabinet')
|
|
1826
|
+
return parent.runTier === 'wall';
|
|
1827
|
+
return parent?.type === 'cabinet-module' && wallChildOf(parent, nodes)?.id === module.id;
|
|
1828
|
+
}
|
|
1829
|
+
export function wallChildAdditionOverlaps(module, run, nodes, { depth = CABINET_WALL_DEPTH, offsetX = 0, } = {}) {
|
|
1830
|
+
const hostLevelId = resolveCabinetHostLevelId(run, nodes);
|
|
1831
|
+
const moduleWorld = resolveCabinetWorldTransform(module, nodes);
|
|
1832
|
+
const candidatePose = composePose(moduleWorld.position, moduleWorld.rotation, [
|
|
1833
|
+
offsetX,
|
|
1834
|
+
wallBottomHeightForTallAlignment() - module.position[1],
|
|
1835
|
+
backAlignZ(module.depth, depth),
|
|
1836
|
+
]);
|
|
1837
|
+
const candidate = {
|
|
1838
|
+
center: candidatePose.position,
|
|
1839
|
+
depth,
|
|
1840
|
+
height: CABINET_WALL_CARCASS_HEIGHT,
|
|
1841
|
+
rotation: candidatePose.rotation,
|
|
1842
|
+
width: module.width,
|
|
1843
|
+
};
|
|
1844
|
+
return Object.values(nodes).some((node) => {
|
|
1845
|
+
if (node?.type !== 'cabinet-module' || !isWallTierModule(node, nodes))
|
|
1846
|
+
return false;
|
|
1847
|
+
if (hostLevelId && resolveCabinetHostLevelId(node, nodes) !== hostLevelId)
|
|
1848
|
+
return false;
|
|
1849
|
+
const pose = resolveCabinetWorldTransform(node, nodes);
|
|
1850
|
+
return cabinetWorldBoxesOverlap(candidate, {
|
|
1851
|
+
center: pose.position,
|
|
1852
|
+
depth: node.depth,
|
|
1853
|
+
height: node.carcassHeight,
|
|
1854
|
+
rotation: pose.rotation,
|
|
1855
|
+
width: node.width,
|
|
1856
|
+
});
|
|
1857
|
+
});
|
|
1342
1858
|
}
|
|
1343
1859
|
/**
|
|
1344
1860
|
* Nest a wall cabinet (or chimney hood) above a base module. Returns the new
|
|
1345
1861
|
* node id, or null when the module already carries one / isn't a base unit.
|
|
1346
1862
|
*/
|
|
1347
|
-
export function addWallChildAbove({ kind, module, run, sceneApi, openSide, }) {
|
|
1348
|
-
|
|
1863
|
+
export function addWallChildAbove({ kind, module, run, sceneApi, openSide, frontOverlay = 'full', offsetX = 0, wallDepth = CABINET_WALL_DEPTH, }) {
|
|
1864
|
+
const liveModule = sceneApi.get(module.id) ?? module;
|
|
1865
|
+
const liveRun = sceneApi.get(run.id) ?? run;
|
|
1866
|
+
if (resolveCabinetType(liveModule, liveRun) !== 'base')
|
|
1349
1867
|
return null;
|
|
1350
|
-
if (wallChildOf(
|
|
1868
|
+
if (wallChildOf(liveModule, sceneApi.nodes()))
|
|
1351
1869
|
return null;
|
|
1870
|
+
if (wallChildAdditionOverlaps(liveModule, liveRun, sceneApi.nodes(), {
|
|
1871
|
+
depth: wallDepth,
|
|
1872
|
+
offsetX,
|
|
1873
|
+
})) {
|
|
1874
|
+
return null;
|
|
1875
|
+
}
|
|
1352
1876
|
const isHood = kind === 'hood';
|
|
1353
1877
|
const carcassHeight = isHood
|
|
1354
1878
|
? Math.max(0.4, hoodCompartmentHeight('hood-pyramid'))
|
|
@@ -1358,12 +1882,12 @@ export function addWallChildAbove({ kind, module, run, sceneApi, openSide, }) {
|
|
|
1358
1882
|
parentId: module.id,
|
|
1359
1883
|
// Wall cabinet top aligns with the default tall cabinet top.
|
|
1360
1884
|
position: [
|
|
1361
|
-
|
|
1362
|
-
wallBottomHeightForTallAlignment() -
|
|
1363
|
-
backAlignZ(
|
|
1885
|
+
offsetX,
|
|
1886
|
+
wallBottomHeightForTallAlignment() - liveModule.position[1],
|
|
1887
|
+
backAlignZ(liveModule.depth, wallDepth),
|
|
1364
1888
|
],
|
|
1365
|
-
width:
|
|
1366
|
-
depth:
|
|
1889
|
+
width: liveModule.width,
|
|
1890
|
+
depth: wallDepth,
|
|
1367
1891
|
carcassHeight,
|
|
1368
1892
|
plinthHeight: 0,
|
|
1369
1893
|
toeKickDepth: 0,
|
|
@@ -1372,27 +1896,28 @@ export function addWallChildAbove({ kind, module, run, sceneApi, openSide, }) {
|
|
|
1372
1896
|
showPlinth: false,
|
|
1373
1897
|
withCountertop: false,
|
|
1374
1898
|
stack: isHood ? [newCabinetCompartment('hood-pyramid')] : doorStack(1),
|
|
1375
|
-
frontStyle:
|
|
1376
|
-
frontOverlay
|
|
1377
|
-
handleStyle:
|
|
1378
|
-
handlePosition:
|
|
1899
|
+
frontStyle: liveModule.frontStyle,
|
|
1900
|
+
frontOverlay,
|
|
1901
|
+
handleStyle: liveModule.handleStyle,
|
|
1902
|
+
handlePosition: liveModule.handlePosition,
|
|
1379
1903
|
...(openSide ? { openSide } : {}),
|
|
1380
1904
|
});
|
|
1381
|
-
sceneApi.upsert(wall,
|
|
1382
|
-
sceneApi.markDirty(
|
|
1905
|
+
sceneApi.upsert(wall, liveModule.id);
|
|
1906
|
+
sceneApi.markDirty(liveModule.id);
|
|
1383
1907
|
return wall.id;
|
|
1384
1908
|
}
|
|
1385
|
-
function ensureWallCabinetAbove({ module, run, sceneApi, shelfCount, openSide, }) {
|
|
1909
|
+
function ensureWallCabinetAbove({ module, run, sceneApi, shelfCount, openSide, offsetX = 0, wallDepth, }) {
|
|
1386
1910
|
const existingWall = wallChildOf(module, sceneApi.nodes());
|
|
1387
1911
|
if (existingWall) {
|
|
1912
|
+
const depth = wallDepth ?? existingWall.depth;
|
|
1388
1913
|
sceneApi.update(existingWall.id, {
|
|
1389
1914
|
width: module.width,
|
|
1390
|
-
depth
|
|
1915
|
+
depth,
|
|
1391
1916
|
carcassHeight: CABINET_WALL_CARCASS_HEIGHT,
|
|
1392
1917
|
position: [
|
|
1393
|
-
|
|
1918
|
+
offsetX,
|
|
1394
1919
|
wallBottomHeightForTallAlignment() - module.position[1],
|
|
1395
|
-
backAlignZ(module.depth,
|
|
1920
|
+
backAlignZ(module.depth, depth),
|
|
1396
1921
|
],
|
|
1397
1922
|
frontStyle: module.frontStyle,
|
|
1398
1923
|
frontOverlay: module.frontOverlay,
|
|
@@ -1409,10 +1934,21 @@ function ensureWallCabinetAbove({ module, run, sceneApi, shelfCount, openSide, }
|
|
|
1409
1934
|
run,
|
|
1410
1935
|
sceneApi,
|
|
1411
1936
|
openSide,
|
|
1937
|
+
frontOverlay: module.frontOverlay,
|
|
1938
|
+
offsetX,
|
|
1939
|
+
wallDepth,
|
|
1412
1940
|
});
|
|
1413
1941
|
if (!wallChildId)
|
|
1414
1942
|
return null;
|
|
1943
|
+
const addedWall = sceneApi.get(wallChildId);
|
|
1944
|
+
const depth = wallDepth ?? addedWall?.depth ?? CABINET_WALL_DEPTH;
|
|
1415
1945
|
sceneApi.update(wallChildId, {
|
|
1946
|
+
depth,
|
|
1947
|
+
...(addedWall
|
|
1948
|
+
? {
|
|
1949
|
+
position: [offsetX, addedWall.position[1], backAlignZ(module.depth, depth)],
|
|
1950
|
+
}
|
|
1951
|
+
: {}),
|
|
1416
1952
|
stack: doorStack(shelfCount),
|
|
1417
1953
|
});
|
|
1418
1954
|
return wallChildId;
|