@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/fence/definition.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { getFenceControlHandle, isSplineFence, } from '@pascal-app/core';
|
|
2
|
+
import { clearStructuralElevationGuide, publishStructuralElevationGuide, resolveStructuralElevationSnap, } from '@pascal-app/editor';
|
|
2
3
|
import { buildFenceFloorplan } from './floorplan';
|
|
3
4
|
import { fenceControlPointAffordance, fenceCurveAffordance, fenceMoveEndpointAffordance, fenceTangentAffordance, } from './floorplan-affordances';
|
|
4
5
|
import { fenceFloorplanMoveTarget } from './floorplan-move';
|
|
5
6
|
import { buildFenceGeometry } from './geometry';
|
|
7
|
+
import { resolveFenceLiftElevation, resolveFenceLiftElevationForNodes } from './lift';
|
|
6
8
|
import { fencePaint } from './paint';
|
|
7
9
|
import { fenceParametrics } from './parametrics';
|
|
8
10
|
import { FenceNode } from './schema';
|
|
@@ -13,6 +15,12 @@ const SIDE_HANDLE_TOP_INSET = 0.08;
|
|
|
13
15
|
const SIDE_HANDLE_MIN_HEIGHT = 0.4;
|
|
14
16
|
const HEIGHT_HANDLE_OFFSET = 0.45;
|
|
15
17
|
const MIN_FENCE_HEIGHT = 0.3;
|
|
18
|
+
function fenceBaseElevation(n, sceneApi) {
|
|
19
|
+
const nodes = sceneApi?.nodes();
|
|
20
|
+
return nodes
|
|
21
|
+
? resolveFenceLiftElevationForNodes(n, nodes)
|
|
22
|
+
: resolveFenceLiftElevation(n, () => undefined);
|
|
23
|
+
}
|
|
16
24
|
function fenceMidpointFrame(n) {
|
|
17
25
|
const dx = n.end[0] - n.start[0];
|
|
18
26
|
const dz = n.end[1] - n.start[1];
|
|
@@ -24,6 +32,14 @@ function fenceMidpointFrame(n) {
|
|
|
24
32
|
normalZ: dx / len,
|
|
25
33
|
};
|
|
26
34
|
}
|
|
35
|
+
function fenceElevationGuideSource(n) {
|
|
36
|
+
const { midX, midZ } = fenceMidpointFrame(n);
|
|
37
|
+
return {
|
|
38
|
+
nodeId: n.id,
|
|
39
|
+
levelId: n.parentId,
|
|
40
|
+
anchor: [midX, midZ],
|
|
41
|
+
};
|
|
42
|
+
}
|
|
27
43
|
// Side-move arrows: click to hand the fence to its move tool. Same shape
|
|
28
44
|
// as wall — front + back faces, positioned past the fence thickness near
|
|
29
45
|
// the top so they don't compete with endpoint pickers in the floating
|
|
@@ -34,11 +50,12 @@ function fenceSideMoveHandle(side) {
|
|
|
34
50
|
kind: 'tap-action',
|
|
35
51
|
onActivate: (node, _scene, editor) => editor.engageMove(node),
|
|
36
52
|
placement: {
|
|
37
|
-
position: (n) => {
|
|
53
|
+
position: (n, sceneApi) => {
|
|
38
54
|
const { midX, midZ, normalX, normalZ } = fenceMidpointFrame(n);
|
|
39
55
|
const offset = Math.max((n.thickness ?? 0.1) / 2 + SIDE_HANDLE_OFFSET, SIDE_HANDLE_MIN_OFFSET);
|
|
40
56
|
const h = n.height ?? 1.8;
|
|
41
|
-
const handleY =
|
|
57
|
+
const handleY = fenceBaseElevation(n, sceneApi) +
|
|
58
|
+
Math.max(h - SIDE_HANDLE_TOP_INSET, SIDE_HANDLE_MIN_HEIGHT);
|
|
42
59
|
return [midX + sign * normalX * offset, handleY, midZ + sign * normalZ * offset];
|
|
43
60
|
},
|
|
44
61
|
rotationY: (n) => {
|
|
@@ -69,9 +86,13 @@ function fenceHeightHandle() {
|
|
|
69
86
|
currentValue: (n) => n.height ?? 1.8,
|
|
70
87
|
apply: (_n, newHeight) => ({ height: newHeight }),
|
|
71
88
|
placement: {
|
|
72
|
-
position: (n) => {
|
|
89
|
+
position: (n, sceneApi) => {
|
|
73
90
|
const { midX, midZ } = fenceMidpointFrame(n);
|
|
74
|
-
return [
|
|
91
|
+
return [
|
|
92
|
+
midX,
|
|
93
|
+
fenceBaseElevation(n, sceneApi) + (n.height ?? 1.8) + HEIGHT_HANDLE_OFFSET,
|
|
94
|
+
midZ,
|
|
95
|
+
];
|
|
75
96
|
},
|
|
76
97
|
rotationY: (n) => {
|
|
77
98
|
const { normalX, normalZ } = fenceMidpointFrame(n);
|
|
@@ -80,6 +101,36 @@ function fenceHeightHandle() {
|
|
|
80
101
|
},
|
|
81
102
|
};
|
|
82
103
|
}
|
|
104
|
+
function fenceElevationHandle(currentBase) {
|
|
105
|
+
return {
|
|
106
|
+
kind: 'linear-resize',
|
|
107
|
+
axis: 'y',
|
|
108
|
+
anchor: 'min',
|
|
109
|
+
shape: 'tracker',
|
|
110
|
+
gridSnap: true,
|
|
111
|
+
currentValue: () => currentBase,
|
|
112
|
+
magneticSnap: (n, newValue, sceneApi) => resolveStructuralElevationSnap(fenceElevationGuideSource(n), newValue, sceneApi.nodes()),
|
|
113
|
+
onDrag: (n, sceneApi) => publishStructuralElevationGuide(fenceElevationGuideSource(n), fenceBaseElevation(n, sceneApi), sceneApi.nodes()),
|
|
114
|
+
onDragEnd: (n) => clearStructuralElevationGuide(n.id),
|
|
115
|
+
apply: (initial, newBase, sceneApi) => {
|
|
116
|
+
// The offset is measured from the support WITHOUT the current offset —
|
|
117
|
+
// including the ground, so dragging a fence's base to an absolute height
|
|
118
|
+
// on a hillside stores the delta from that hillside and the fence keeps
|
|
119
|
+
// following it.
|
|
120
|
+
const supportBase = resolveFenceLiftElevationForNodes({ ...initial, supportOffset: undefined }, sceneApi.nodes());
|
|
121
|
+
const nextOffset = newBase - supportBase;
|
|
122
|
+
return {
|
|
123
|
+
supportOffset: Math.abs(nextOffset) < 1e-6 ? undefined : nextOffset,
|
|
124
|
+
};
|
|
125
|
+
},
|
|
126
|
+
placement: {
|
|
127
|
+
position: (n, sceneApi) => {
|
|
128
|
+
const { midX, midZ } = fenceMidpointFrame(n);
|
|
129
|
+
return [midX, fenceBaseElevation(n, sceneApi), midZ];
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
}
|
|
83
134
|
// Corner picker — dashed vertical leader + billboarded hex disc at the
|
|
84
135
|
// endpoint. Tap engages the endpoint-move flow (sister to the wall
|
|
85
136
|
// pickers). nodeHeight controls the leader's vertical reach so the
|
|
@@ -92,9 +143,9 @@ function fenceCornerPicker(endpoint) {
|
|
|
92
143
|
nodeHeight: (n) => n.height ?? 1.8,
|
|
93
144
|
onActivate: (node, _scene, editor) => editor.engageEndpointMove(node, endpoint),
|
|
94
145
|
placement: {
|
|
95
|
-
position: (n) => {
|
|
146
|
+
position: (n, sceneApi) => {
|
|
96
147
|
const corner = endpoint === 'start' ? n.start : n.end;
|
|
97
|
-
return [corner[0],
|
|
148
|
+
return [corner[0], fenceBaseElevation(n, sceneApi), corner[1]];
|
|
98
149
|
},
|
|
99
150
|
},
|
|
100
151
|
};
|
|
@@ -108,9 +159,9 @@ function fenceControlPointPicker(index) {
|
|
|
108
159
|
nodeHeight: (n) => n.height ?? 1.8,
|
|
109
160
|
onActivate: (node, _scene, editor) => editor.engageControlPointMove(node, index),
|
|
110
161
|
placement: {
|
|
111
|
-
position: (n) => {
|
|
162
|
+
position: (n, sceneApi) => {
|
|
112
163
|
const point = n.path?.[index] ?? n.start;
|
|
113
|
-
return [point[0],
|
|
164
|
+
return [point[0], fenceBaseElevation(n, sceneApi), point[1]];
|
|
114
165
|
},
|
|
115
166
|
},
|
|
116
167
|
};
|
|
@@ -125,23 +176,26 @@ function fenceTangentPicker(index, side) {
|
|
|
125
176
|
nodeHeight: (n) => (n.height ?? 1.8) * 0.6,
|
|
126
177
|
onActivate: (node, _scene, editor) => editor.engageTangentMove(node, index, side),
|
|
127
178
|
placement: {
|
|
128
|
-
position: (n) => {
|
|
179
|
+
position: (n, sceneApi) => {
|
|
129
180
|
const point = n.path?.[index] ?? n.start;
|
|
181
|
+
const baseElevation = fenceBaseElevation(n, sceneApi);
|
|
130
182
|
if (!n.path)
|
|
131
|
-
return [point[0],
|
|
183
|
+
return [point[0], baseElevation, point[1]];
|
|
132
184
|
const handle = getFenceControlHandle(n.path, n.tangents, index);
|
|
133
185
|
return [
|
|
134
186
|
point[0] + sign * handle.x * TANGENT_HANDLE_ARM_SCALE,
|
|
135
|
-
|
|
187
|
+
baseElevation,
|
|
136
188
|
point[1] + sign * handle.y * TANGENT_HANDLE_ARM_SCALE,
|
|
137
189
|
];
|
|
138
190
|
},
|
|
139
191
|
},
|
|
140
192
|
};
|
|
141
193
|
}
|
|
142
|
-
const fenceHandles = (node) => {
|
|
194
|
+
const fenceHandles = (node, sceneApi) => {
|
|
195
|
+
const elevationHandle = fenceElevationHandle(fenceBaseElevation(node, sceneApi));
|
|
143
196
|
if (isSplineFence(node) && node.path) {
|
|
144
197
|
return [
|
|
198
|
+
elevationHandle,
|
|
145
199
|
fenceHeightHandle(),
|
|
146
200
|
...node.path.flatMap((_, index) => [
|
|
147
201
|
fenceControlPointPicker(index),
|
|
@@ -153,6 +207,7 @@ const fenceHandles = (node) => {
|
|
|
153
207
|
return [
|
|
154
208
|
fenceSideMoveHandle('front'),
|
|
155
209
|
fenceSideMoveHandle('back'),
|
|
210
|
+
elevationHandle,
|
|
156
211
|
fenceHeightHandle(),
|
|
157
212
|
fenceCornerPicker('start'),
|
|
158
213
|
fenceCornerPicker('end'),
|
|
@@ -174,7 +229,7 @@ const fenceHandles = (node) => {
|
|
|
174
229
|
export const fenceDefinition = {
|
|
175
230
|
kind: 'fence',
|
|
176
231
|
snapProfile: 'structural',
|
|
177
|
-
schemaVersion:
|
|
232
|
+
schemaVersion: 2,
|
|
178
233
|
schema: FenceNode,
|
|
179
234
|
category: 'structure',
|
|
180
235
|
surfaceRole: 'wall',
|
|
@@ -226,8 +281,13 @@ export const fenceDefinition = {
|
|
|
226
281
|
tool: () => import('./tool'),
|
|
227
282
|
// Stage B: pure geometry function. Generic <GeometrySystem> rebuilds
|
|
228
283
|
// on dirtyNodes; <ParametricNodeRenderer> mounts the empty group.
|
|
229
|
-
// `renderer` + `system` fields dropped along with their files.
|
|
230
284
|
geometry: buildFenceGeometry,
|
|
285
|
+
// Dependency tracker only — a hosted railing (`supportSlabId`) renders at
|
|
286
|
+
// its slab's elevation, so host elevation edits must re-dirty the fence.
|
|
287
|
+
system: {
|
|
288
|
+
module: () => import('./system'),
|
|
289
|
+
priority: 4,
|
|
290
|
+
},
|
|
231
291
|
// Stage C: floor-plan rendering. FloorplanRegistryLayer iterates kinds
|
|
232
292
|
// with `floorplan` set and renders via FloorplanGeometryRenderer.
|
|
233
293
|
// Legacy `floorplanFenceEntries` short-circuits to [] when fence is
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"floorplan-affordances.d.ts","sourceRoot":"","sources":["../../src/fence/floorplan-affordances.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,mBAAmB,
|
|
1
|
+
{"version":3,"file":"floorplan-affordances.d.ts","sourceRoot":"","sources":["../../src/fence/floorplan-affordances.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,mBAAmB,EASzB,MAAM,kBAAkB,CAAA;AAoFzB;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,EAAE,mBAAmB,CAAC,SAAS,CAsC/D,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,EAAE,mBAAmB,CAAC,SAAS,CAqCtE,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,EAAE,mBAAmB,CAAC,SAAS,CAoDjE,CAAA;AAED,eAAO,MAAM,2BAA2B,EAAE,mBAAmB,CAAC,SAAS,CA4HtE,CAAA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getMaxWallCurveOffset, getWallChordFrame, normalizeWallCurveOffset, useLiveNodeOverrides, useScene, } from '@pascal-app/core';
|
|
1
|
+
import { getMaxWallCurveOffset, getWallChordFrame, normalizeWallCurveOffset, resolveFenceSupportSlabPatch, useLiveNodeOverrides, useScene, } from '@pascal-app/core';
|
|
2
2
|
import { alignFloorplanDraftPoint, getSegmentGridStep, isAlignmentGuideActive, isAngleSnapActive, isGridSnapActive, isMagneticSnapActive, isSegmentLongEnough, snapBuildingLocalToWorldGrid, snapFenceDraftPoint, snapScalarToGrid, useAlignmentGuides, } from '@pascal-app/editor';
|
|
3
3
|
/**
|
|
4
4
|
* Floor-plan 2D drag affordances for fence — sister to the 3D
|
|
@@ -204,6 +204,9 @@ export const fenceMoveEndpointAffordance = {
|
|
|
204
204
|
const { walls, fences } = collectLevel(nodes, parentId);
|
|
205
205
|
const linkedOriginals = collectLinkedFences(fences, node.id, originalMovingPoint);
|
|
206
206
|
const affectedIds = [node.id, ...linkedOriginals.map((l) => l.id)];
|
|
207
|
+
let lastPatches = new Map();
|
|
208
|
+
let lastStart = originalStart;
|
|
209
|
+
let lastEnd = originalEnd;
|
|
207
210
|
return {
|
|
208
211
|
affectedIds,
|
|
209
212
|
apply({ planPoint, modifiers }) {
|
|
@@ -249,22 +252,56 @@ export const fenceMoveEndpointAffordance = {
|
|
|
249
252
|
start: pointsNearlyEqual(l.start, originalMovingPoint) ? aligned : l.start,
|
|
250
253
|
end: pointsNearlyEqual(l.end, originalMovingPoint) ? aligned : l.end,
|
|
251
254
|
}));
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
})),
|
|
255
|
+
lastStart = nextStart;
|
|
256
|
+
lastEnd = nextEnd;
|
|
257
|
+
const nextPatches = new Map([
|
|
258
|
+
[node.id, { start: nextStart, end: nextEnd }],
|
|
259
|
+
...linkedUpdates.map((update) => [update.id, { start: update.start, end: update.end }]),
|
|
258
260
|
]);
|
|
261
|
+
// Re-elect the slab lift host as the endpoint drags (uncapped max
|
|
262
|
+
// election — 2D has no camera ray). Fences run no per-frame
|
|
263
|
+
// election: `supportSlabId` IS the lift.
|
|
264
|
+
const patchedNodes = { ...sceneNodes };
|
|
265
|
+
for (const [id, patch] of nextPatches) {
|
|
266
|
+
patchedNodes[id] = { ...patchedNodes[id], ...patch };
|
|
267
|
+
}
|
|
268
|
+
for (const id of nextPatches.keys()) {
|
|
269
|
+
const fence = patchedNodes[id];
|
|
270
|
+
if (fence?.type !== 'fence')
|
|
271
|
+
continue;
|
|
272
|
+
const patch = resolveFenceSupportSlabPatch(fence, patchedNodes);
|
|
273
|
+
if (patch.supportSlabId !== fence.supportSlabId) {
|
|
274
|
+
nextPatches.set(id, { ...nextPatches.get(id), ...patch });
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
const overrides = useLiveNodeOverrides.getState();
|
|
278
|
+
const scene = useScene.getState();
|
|
279
|
+
for (const linked of linkedOriginals) {
|
|
280
|
+
if (!nextPatches.has(linked.id)) {
|
|
281
|
+
overrides.clear(linked.id);
|
|
282
|
+
scene.markDirty(linked.id);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
for (const [id, patch] of nextPatches) {
|
|
286
|
+
overrides.set(id, patch);
|
|
287
|
+
scene.markDirty(id);
|
|
288
|
+
}
|
|
289
|
+
lastPatches = nextPatches;
|
|
259
290
|
},
|
|
260
291
|
canCommit() {
|
|
261
292
|
// Pointer-up always runs canCommit — drop the alignment guide here
|
|
262
293
|
// so it doesn't linger after a commit / reject.
|
|
263
294
|
useAlignmentGuides.getState().clear();
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
295
|
+
return isSegmentLongEnough(lastStart, lastEnd);
|
|
296
|
+
},
|
|
297
|
+
commit() {
|
|
298
|
+
useScene.getState().updateNodes(Array.from(lastPatches, ([id, data]) => ({
|
|
299
|
+
id,
|
|
300
|
+
data,
|
|
301
|
+
})));
|
|
302
|
+
const overrides = useLiveNodeOverrides.getState();
|
|
303
|
+
for (const id of affectedIds)
|
|
304
|
+
overrides.clear(id);
|
|
268
305
|
},
|
|
269
306
|
};
|
|
270
307
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"floorplan-move.d.ts","sourceRoot":"","sources":["../../src/fence/floorplan-move.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,mBAAmB,
|
|
1
|
+
{"version":3,"file":"floorplan-move.d.ts","sourceRoot":"","sources":["../../src/fence/floorplan-move.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,mBAAmB,EAKzB,MAAM,kBAAkB,CAAA;AAuDzB;;;;;;GAMG;AACH,eAAO,MAAM,wBAAwB,EAAE,mBAAmB,CAAC,SAAS,CA4LnE,CAAA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useLiveNodeOverrides, useScene, } from '@pascal-app/core';
|
|
1
|
+
import { resolveFenceSupportSlabPatch, useLiveNodeOverrides, useScene, } from '@pascal-app/core';
|
|
2
2
|
import { getSegmentGridStep, isGridSnapActive, isSegmentLongEnough, snapPointToGrid, } from '@pascal-app/editor';
|
|
3
3
|
import { useViewer } from '@pascal-app/viewer';
|
|
4
4
|
function pointsEqual(a, b) {
|
|
@@ -125,6 +125,27 @@ export const fenceFloorplanMoveTarget = ({ node }) => {
|
|
|
125
125
|
// tracked change. Drop the override AFTER the scene write so
|
|
126
126
|
// mid-commit reads still see the new position (override wins until
|
|
127
127
|
// cleared; scene wins after).
|
|
128
|
+
// The re-elected slab lift host rides in the same write (uncapped max
|
|
129
|
+
// election — 2D has no camera ray): a fence moved onto / off an
|
|
130
|
+
// elevated deck must land on the right surface, since fences run no
|
|
131
|
+
// per-frame election (`supportSlabId` IS the lift). One updateNodes
|
|
132
|
+
// keeps the whole move a single tracked change. Election runs on the
|
|
133
|
+
// committed endpoints against the pre-write store (the patch only
|
|
134
|
+
// reads the parent level + the slab grid).
|
|
135
|
+
const baselineNodes = useScene.getState().nodes;
|
|
136
|
+
const supportFor = (start, end, path, id) => {
|
|
137
|
+
const fence = baselineNodes[id];
|
|
138
|
+
return fence?.type === 'fence'
|
|
139
|
+
? resolveFenceSupportSlabPatch({
|
|
140
|
+
start,
|
|
141
|
+
end,
|
|
142
|
+
path,
|
|
143
|
+
curveOffset: fence.curveOffset,
|
|
144
|
+
thickness: fence.thickness,
|
|
145
|
+
parentId: fence.parentId,
|
|
146
|
+
}, baselineNodes)
|
|
147
|
+
: {};
|
|
148
|
+
};
|
|
128
149
|
const fenceUpdate = isNew
|
|
129
150
|
? {
|
|
130
151
|
id: fenceId,
|
|
@@ -133,9 +154,18 @@ export const fenceFloorplanMoveTarget = ({ node }) => {
|
|
|
133
154
|
end: lastNextEnd,
|
|
134
155
|
path: lastNextPath,
|
|
135
156
|
metadata: { ...originalMetadata, isNew: false },
|
|
157
|
+
...supportFor(lastNextStart, lastNextEnd, lastNextPath, fenceId),
|
|
136
158
|
},
|
|
137
159
|
}
|
|
138
|
-
: {
|
|
160
|
+
: {
|
|
161
|
+
id: fenceId,
|
|
162
|
+
data: {
|
|
163
|
+
start: lastNextStart,
|
|
164
|
+
end: lastNextEnd,
|
|
165
|
+
path: lastNextPath,
|
|
166
|
+
...supportFor(lastNextStart, lastNextEnd, lastNextPath, fenceId),
|
|
167
|
+
},
|
|
168
|
+
};
|
|
139
169
|
const linkedUpdates = linkedOriginals.map((l) => ({
|
|
140
170
|
id: l.id,
|
|
141
171
|
...projectLinked(l, lastNextStart, lastNextEnd, lastDelta[0], lastDelta[1]),
|
|
@@ -144,7 +174,12 @@ export const fenceFloorplanMoveTarget = ({ node }) => {
|
|
|
144
174
|
fenceUpdate,
|
|
145
175
|
...linkedUpdates.map((u) => ({
|
|
146
176
|
id: u.id,
|
|
147
|
-
data: {
|
|
177
|
+
data: {
|
|
178
|
+
start: u.start,
|
|
179
|
+
end: u.end,
|
|
180
|
+
path: u.path,
|
|
181
|
+
...supportFor(u.start, u.end, u.path, u.id),
|
|
182
|
+
},
|
|
148
183
|
})),
|
|
149
184
|
]);
|
|
150
185
|
const overrides = useLiveNodeOverrides.getState();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"geometry.d.ts","sourceRoot":"","sources":["../../src/fence/geometry.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"geometry.d.ts","sourceRoot":"","sources":["../../src/fence/geometry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,eAAe,EAA0B,MAAM,kBAAkB,CAAA;AAC/F,OAAO,EAEL,KAAK,WAAW,EAKhB,KAAK,aAAa,EAGnB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAAa,KAAK,EAAqC,MAAM,OAAO,CAAA;AAE3E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAwFzC,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,SAAS,EACf,GAAG,CAAC,EAAE,eAAe,EACrB,OAAO,GAAE,aAA0B,EACnC,QAAQ,UAAO,EACf,WAAW,GAAE,WAAoB,EACjC,UAAU,CAAC,EAAE,MAAM,GAClB,KAAK,CA0CP"}
|
package/dist/fence/geometry.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getMaterialPresetByRef } from '@pascal-app/core';
|
|
2
2
|
import { applyMaterialPresetToMaterials, createDefaultMaterial, createMaterial, createSurfaceRoleMaterial, generateFenceSlotGeometries, resolveMaterialRef, resolveSlotDefaultMaterial, } from '@pascal-app/viewer';
|
|
3
3
|
import { FrontSide, Group, Mesh } from 'three';
|
|
4
|
+
import { resolveFenceLiftElevation } from './lift';
|
|
4
5
|
import { FENCE_SLOT_DEFAULTS } from './slots';
|
|
5
6
|
const FENCE_SLOT_ORDER = ['posts', 'infill', 'base', 'rail'];
|
|
6
7
|
const fenceMaterialCache = new Map();
|
|
@@ -50,6 +51,19 @@ function getLegacyFenceMaterial(node, shading) {
|
|
|
50
51
|
export function buildFenceGeometry(node, ctx, shading = 'rendered', textures = true, colorPreset = 'clay', sceneTheme) {
|
|
51
52
|
const group = new Group();
|
|
52
53
|
const geometries = generateFenceSlotGeometries(node);
|
|
54
|
+
// A hosted railing (`supportSlabId`) stands on its slab's walking surface;
|
|
55
|
+
// an unhosted one stands on the ground, which `ctx.levelBaseAt` resolves at
|
|
56
|
+
// the fence's own start point — the anchor its plan geometry is measured
|
|
57
|
+
// from, so the resolver and the mesh cannot disagree about where the ground
|
|
58
|
+
// is under this fence. The builder emits local-space children, so the lift
|
|
59
|
+
// lives on an inner group rather than the registered (React-transformed)
|
|
60
|
+
// root.
|
|
61
|
+
const lift = ctx
|
|
62
|
+
? resolveFenceLiftElevation(node, (id) => ctx.resolve(id), ctx.levelBaseAt?.(node.start[0], node.start[1]) ?? 0)
|
|
63
|
+
: 0;
|
|
64
|
+
const meshParent = new Group();
|
|
65
|
+
meshParent.position.y = lift;
|
|
66
|
+
group.add(meshParent);
|
|
53
67
|
for (const slotId of FENCE_SLOT_ORDER) {
|
|
54
68
|
const geometry = geometries[slotId];
|
|
55
69
|
if (geometry.getAttribute('position') === undefined)
|
|
@@ -59,7 +73,7 @@ export function buildFenceGeometry(node, ctx, shading = 'rendered', textures = t
|
|
|
59
73
|
mesh.castShadow = true;
|
|
60
74
|
mesh.receiveShadow = true;
|
|
61
75
|
mesh.userData.slotId = slotId;
|
|
62
|
-
|
|
76
|
+
meshParent.add(mesh);
|
|
63
77
|
}
|
|
64
78
|
return group;
|
|
65
79
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type AnyNode } from '@pascal-app/core';
|
|
2
|
+
import type { FenceNode } from './schema';
|
|
3
|
+
/**
|
|
4
|
+
* Elevation (meters above the level plane) a hosted fence stands at.
|
|
5
|
+
*
|
|
6
|
+
* A fence carrying `supportSlabId` is a railing on that slab's walking
|
|
7
|
+
* surface (drawn onto a deck, or placed by a deck preset). The
|
|
8
|
+
* host pins the lift only while it still exists as a slab on the fence's
|
|
9
|
+
* own level — a stale host (deleted slab, reparented fence) silently
|
|
10
|
+
* falls back to the level floor, mirroring the read-path rules of the
|
|
11
|
+
* other `supportSlabId` carriers. Pure so it is unit-testable and
|
|
12
|
+
* callable from the geometry builder with `ctx.resolve`.
|
|
13
|
+
*
|
|
14
|
+
* `levelBase` is what "the level floor" means here — the sculpted ground
|
|
15
|
+
* under the fence (`levelBaseElevationAt`, reached through `ctx.levelBaseAt`
|
|
16
|
+
* in the builder and {@link resolveFenceLiftElevationForNodes} everywhere
|
|
17
|
+
* else), or 0 for a level with no terrain under it. A caller-resolved scalar
|
|
18
|
+
* rather than a terrain lookup inside, so this stays pure and the sample stays
|
|
19
|
+
* at the caller's chosen point; it substitutes for the literal `0` this used to
|
|
20
|
+
* return in every unhosted branch, and nowhere else — a host slab that still
|
|
21
|
+
* exists wins outright, so a railing on a deck pad keeps the pad's elevation
|
|
22
|
+
* instead of following the hillside around it.
|
|
23
|
+
*/
|
|
24
|
+
export declare function resolveFenceLiftElevation(node: Pick<FenceNode, 'supportSlabId' | 'supportOffset' | 'parentId'>, resolve: (id: string) => AnyNode | undefined, levelBase?: number): number;
|
|
25
|
+
/**
|
|
26
|
+
* {@link resolveFenceLiftElevation} against a nodes record, with the level base
|
|
27
|
+
* resolved from the terrain under the fence's start point — the same anchor the
|
|
28
|
+
* geometry builder samples, so a handle, a snap guide and the rendered rail all
|
|
29
|
+
* agree about where the ground is.
|
|
30
|
+
*
|
|
31
|
+
* Exists so the callers that already hold the whole scene (handles via
|
|
32
|
+
* `sceneApi.nodes()`, the dependency tracker, the editor's elevation guides)
|
|
33
|
+
* don't each re-derive the level walk and the sample point. The builder keeps
|
|
34
|
+
* using the pure form, since `GeometryContext` deliberately exposes the ground
|
|
35
|
+
* as a closure rather than the store.
|
|
36
|
+
*/
|
|
37
|
+
export declare function resolveFenceLiftElevationForNodes(node: Pick<FenceNode, 'id' | 'start' | 'supportSlabId' | 'supportOffset' | 'parentId'>, nodes: Record<string, AnyNode>): number;
|
|
38
|
+
//# sourceMappingURL=lift.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lift.d.ts","sourceRoot":"","sources":["../../src/fence/lift.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,EAKb,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAEzC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,eAAe,GAAG,eAAe,GAAG,UAAU,CAAC,EACrE,OAAO,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,GAAG,SAAS,EAC5C,SAAS,SAAI,GACZ,MAAM,CAQR;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iCAAiC,CAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,GAAG,OAAO,GAAG,eAAe,GAAG,eAAe,GAAG,UAAU,CAAC,EACtF,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,MAAM,CAIR"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { findLevelAncestorId, levelBaseElevationAt, } from '@pascal-app/core';
|
|
2
|
+
/**
|
|
3
|
+
* Elevation (meters above the level plane) a hosted fence stands at.
|
|
4
|
+
*
|
|
5
|
+
* A fence carrying `supportSlabId` is a railing on that slab's walking
|
|
6
|
+
* surface (drawn onto a deck, or placed by a deck preset). The
|
|
7
|
+
* host pins the lift only while it still exists as a slab on the fence's
|
|
8
|
+
* own level — a stale host (deleted slab, reparented fence) silently
|
|
9
|
+
* falls back to the level floor, mirroring the read-path rules of the
|
|
10
|
+
* other `supportSlabId` carriers. Pure so it is unit-testable and
|
|
11
|
+
* callable from the geometry builder with `ctx.resolve`.
|
|
12
|
+
*
|
|
13
|
+
* `levelBase` is what "the level floor" means here — the sculpted ground
|
|
14
|
+
* under the fence (`levelBaseElevationAt`, reached through `ctx.levelBaseAt`
|
|
15
|
+
* in the builder and {@link resolveFenceLiftElevationForNodes} everywhere
|
|
16
|
+
* else), or 0 for a level with no terrain under it. A caller-resolved scalar
|
|
17
|
+
* rather than a terrain lookup inside, so this stays pure and the sample stays
|
|
18
|
+
* at the caller's chosen point; it substitutes for the literal `0` this used to
|
|
19
|
+
* return in every unhosted branch, and nowhere else — a host slab that still
|
|
20
|
+
* exists wins outright, so a railing on a deck pad keeps the pad's elevation
|
|
21
|
+
* instead of following the hillside around it.
|
|
22
|
+
*/
|
|
23
|
+
export function resolveFenceLiftElevation(node, resolve, levelBase = 0) {
|
|
24
|
+
const offset = node.supportOffset ?? 0;
|
|
25
|
+
if (!node.supportSlabId)
|
|
26
|
+
return levelBase + offset;
|
|
27
|
+
const host = resolve(node.supportSlabId);
|
|
28
|
+
if (host?.type !== 'slab')
|
|
29
|
+
return levelBase + offset;
|
|
30
|
+
if ((host.parentId ?? null) !== (node.parentId ?? null))
|
|
31
|
+
return levelBase + offset;
|
|
32
|
+
const elevation = host.elevation;
|
|
33
|
+
return (Number.isFinite(elevation) ? elevation : 0) + offset;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* {@link resolveFenceLiftElevation} against a nodes record, with the level base
|
|
37
|
+
* resolved from the terrain under the fence's start point — the same anchor the
|
|
38
|
+
* geometry builder samples, so a handle, a snap guide and the rendered rail all
|
|
39
|
+
* agree about where the ground is.
|
|
40
|
+
*
|
|
41
|
+
* Exists so the callers that already hold the whole scene (handles via
|
|
42
|
+
* `sceneApi.nodes()`, the dependency tracker, the editor's elevation guides)
|
|
43
|
+
* don't each re-derive the level walk and the sample point. The builder keeps
|
|
44
|
+
* using the pure form, since `GeometryContext` deliberately exposes the ground
|
|
45
|
+
* as a closure rather than the store.
|
|
46
|
+
*/
|
|
47
|
+
export function resolveFenceLiftElevationForNodes(node, nodes) {
|
|
48
|
+
const levelId = findLevelAncestorId(node.id, nodes);
|
|
49
|
+
const levelBase = levelId ? levelBaseElevationAt(nodes, levelId, node.start[0], node.start[1]) : 0;
|
|
50
|
+
return resolveFenceLiftElevation(node, (id) => nodes[id], levelBase);
|
|
51
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"move-tool.d.ts","sourceRoot":"","sources":["../../src/fence/move-tool.tsx"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,SAAS,
|
|
1
|
+
{"version":3,"file":"move-tool.d.ts","sourceRoot":"","sources":["../../src/fence/move-tool.tsx"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,SAAS,EAWf,MAAM,kBAAkB,CAAA;AAsHzB,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAgSvD,CAAA;AAED,eAAe,aAAa,CAAA"}
|
package/dist/fence/move-tool.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
-
import { constrainWallMoveDeltaToAxis, emitter, getPerpendicularWallMoveAxis, isCurvedWall, isSplineFence, useLiveNodeOverrides, useScene, } from '@pascal-app/core';
|
|
3
|
+
import { constrainWallMoveDeltaToAxis, emitter, getPerpendicularWallMoveAxis, isCurvedWall, isSplineFence, resolveFenceSupportSlabPatch, useLiveNodeOverrides, useScene, } from '@pascal-app/core';
|
|
4
4
|
import { CursorSphere, consumePlacementDragRelease, getSegmentGridStep, isGridSnapActive, isMagneticSnapActive, markToolCancelConsumed, snapFenceDraftPoint, triggerSFX, useEditor, } from '@pascal-app/editor';
|
|
5
5
|
import { useViewer } from '@pascal-app/viewer';
|
|
6
6
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
@@ -132,10 +132,30 @@ export const MoveFenceTool = ({ node }) => {
|
|
|
132
132
|
}
|
|
133
133
|
};
|
|
134
134
|
const applyCommittedUpdates = (updates) => {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
135
|
+
// Fold the re-elected slab lift host into the same write — a fence
|
|
136
|
+
// moved onto / off an elevated deck must land on the right surface
|
|
137
|
+
// (fences run no per-frame election; `supportSlabId` IS the lift),
|
|
138
|
+
// and one updateNodes keeps the whole move a single undo step.
|
|
139
|
+
// Election runs on the committed endpoints against the pre-write
|
|
140
|
+
// store (the patch only reads the parent level + the slab grid).
|
|
141
|
+
const baselineNodes = useScene.getState().nodes;
|
|
142
|
+
useScene.getState().updateNodes(updates.map((entry) => {
|
|
143
|
+
const fence = baselineNodes[entry.id];
|
|
144
|
+
const support = fence?.type === 'fence'
|
|
145
|
+
? resolveFenceSupportSlabPatch({
|
|
146
|
+
start: entry.start,
|
|
147
|
+
end: entry.end,
|
|
148
|
+
path: entry.path,
|
|
149
|
+
curveOffset: fence.curveOffset,
|
|
150
|
+
thickness: fence.thickness,
|
|
151
|
+
parentId: fence.parentId,
|
|
152
|
+
}, baselineNodes)
|
|
153
|
+
: {};
|
|
154
|
+
return {
|
|
155
|
+
id: entry.id,
|
|
156
|
+
data: { start: entry.start, end: entry.end, path: entry.path, ...support },
|
|
157
|
+
};
|
|
158
|
+
}));
|
|
139
159
|
for (const entry of updates) {
|
|
140
160
|
useScene.getState().markDirty(entry.id);
|
|
141
161
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"system.d.ts","sourceRoot":"","sources":["../../src/fence/system.tsx"],"names":[],"mappings":"AAiCA,QAAA,MAAM,YAAY,YAgBjB,CAAA;AAED,eAAe,YAAY,CAAA"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useScene } from '@pascal-app/core';
|
|
3
|
+
import { useEffect } from 'react';
|
|
4
|
+
import { resolveFenceLiftElevationForNodes } from './lift';
|
|
5
|
+
/**
|
|
6
|
+
* Hosted-railing dependency tracker. A fence with `supportSlabId` renders at
|
|
7
|
+
* its host slab's elevation, but a store update only dirties the node that
|
|
8
|
+
* changed — editing the slab's elevation (or restoring a deleted host) would
|
|
9
|
+
* leave the railing floating at the stale height. Watch each hosted fence's
|
|
10
|
+
* resolved lift and dirty the fence when it moves; `GeometrySystem` rebuilds
|
|
11
|
+
* through `def.geometry` as usual. (Deleting the host needs no help here:
|
|
12
|
+
* `deleteNodesAction` strips `supportSlabId` and dirties the fence itself.)
|
|
13
|
+
*/
|
|
14
|
+
function fenceLiftSignatures(nodes) {
|
|
15
|
+
const signatures = new Map();
|
|
16
|
+
for (const node of Object.values(nodes)) {
|
|
17
|
+
if (node.type !== 'fence')
|
|
18
|
+
continue;
|
|
19
|
+
const fence = node;
|
|
20
|
+
// Unhosted fences are covered too, and by a different mechanism: their lift
|
|
21
|
+
// is the ground, which only a sculpt moves, and `markTerrainSupportDependents`
|
|
22
|
+
// dirties them from the terrain change itself. Tracking them here would
|
|
23
|
+
// resolve every fence in the scene on every store update to catch an event
|
|
24
|
+
// this subscription never sees.
|
|
25
|
+
if (!fence.supportSlabId)
|
|
26
|
+
continue;
|
|
27
|
+
signatures.set(fence.id, resolveFenceLiftElevationForNodes(fence, nodes));
|
|
28
|
+
}
|
|
29
|
+
return signatures;
|
|
30
|
+
}
|
|
31
|
+
const FenceSystems = () => {
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
let previous = fenceLiftSignatures(useScene.getState().nodes);
|
|
34
|
+
return useScene.subscribe((state) => {
|
|
35
|
+
const current = fenceLiftSignatures(state.nodes);
|
|
36
|
+
for (const [fenceId, lift] of current.entries()) {
|
|
37
|
+
if (previous.get(fenceId) !== lift) {
|
|
38
|
+
state.markDirty(fenceId);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
previous = current;
|
|
42
|
+
});
|
|
43
|
+
}, []);
|
|
44
|
+
return null;
|
|
45
|
+
};
|
|
46
|
+
export default FenceSystems;
|
package/dist/fence/tool.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../src/fence/tool.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../src/fence/tool.tsx"],"names":[],"mappings":"AAycA,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EAM7B,CAAA;AAweD,eAAe,SAAS,CAAA"}
|