@pascal-app/nodes 1.0.6 → 1.0.7
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 +1 -0
- package/dist/beam/actions/move-endpoint.d.ts +24 -0
- package/dist/beam/actions/move-endpoint.d.ts.map +1 -0
- package/dist/beam/actions/move-endpoint.js +54 -0
- package/dist/beam/definition.d.ts +14 -0
- package/dist/beam/definition.d.ts.map +1 -0
- package/dist/beam/definition.js +173 -0
- package/dist/beam/draft-settings.d.ts +17 -0
- package/dist/beam/draft-settings.d.ts.map +1 -0
- package/dist/beam/draft-settings.js +81 -0
- package/dist/beam/drafting.d.ts +35 -0
- package/dist/beam/drafting.d.ts.map +1 -0
- package/dist/beam/drafting.js +103 -0
- package/dist/beam/floorplan-affordances.d.ts +8 -0
- package/dist/beam/floorplan-affordances.d.ts.map +1 -0
- package/dist/beam/floorplan-affordances.js +40 -0
- package/dist/beam/floorplan-move.d.ts +11 -0
- package/dist/beam/floorplan-move.d.ts.map +1 -0
- package/dist/beam/floorplan-move.js +54 -0
- package/dist/beam/floorplan.d.ts +11 -0
- package/dist/beam/floorplan.d.ts.map +1 -0
- package/dist/beam/floorplan.js +91 -0
- package/dist/beam/geometry.d.ts +19 -0
- package/dist/beam/geometry.d.ts.map +1 -0
- package/dist/beam/geometry.js +63 -0
- package/dist/beam/index.d.ts +3 -0
- package/dist/beam/index.d.ts.map +1 -0
- package/dist/beam/index.js +2 -0
- package/dist/beam/move-endpoint-tool.d.ts +21 -0
- package/dist/beam/move-endpoint-tool.d.ts.map +1 -0
- package/dist/beam/move-endpoint-tool.js +49 -0
- package/dist/beam/move-tool.d.ts +12 -0
- package/dist/beam/move-tool.d.ts.map +1 -0
- package/dist/beam/move-tool.js +114 -0
- package/dist/beam/panel-model.d.ts +28 -0
- package/dist/beam/panel-model.d.ts.map +1 -0
- package/dist/beam/panel-model.js +123 -0
- package/dist/beam/panel.d.ts +13 -0
- package/dist/beam/panel.d.ts.map +1 -0
- package/dist/beam/panel.js +107 -0
- package/dist/beam/parametrics.d.ts +3 -0
- package/dist/beam/parametrics.d.ts.map +1 -0
- package/dist/beam/parametrics.js +4 -0
- package/dist/beam/renderer.d.ts +13 -0
- package/dist/beam/renderer.d.ts.map +1 -0
- package/dist/beam/renderer.js +36 -0
- package/dist/beam/schema.d.ts +2 -0
- package/dist/beam/schema.d.ts.map +1 -0
- package/dist/beam/schema.js +1 -0
- package/dist/beam/tool.d.ts +13 -0
- package/dist/beam/tool.d.ts.map +1 -0
- package/dist/beam/tool.js +152 -0
- package/dist/box-vent/panel.d.ts.map +1 -1
- package/dist/box-vent/panel.js +8 -7
- package/dist/cabinet/batchable.d.ts +10 -0
- package/dist/cabinet/batchable.d.ts.map +1 -0
- package/dist/cabinet/batchable.js +12 -0
- package/dist/cabinet/compartment-card.d.ts.map +1 -1
- package/dist/cabinet/compartment-card.js +142 -46
- package/dist/cabinet/countertop-layout.d.ts +5 -0
- package/dist/cabinet/countertop-layout.d.ts.map +1 -1
- package/dist/cabinet/definition.d.ts.map +1 -1
- package/dist/cabinet/definition.js +3 -0
- package/dist/cabinet/dimension-input.d.ts +6 -0
- package/dist/cabinet/dimension-input.d.ts.map +1 -0
- package/dist/cabinet/dimension-input.js +8 -0
- package/dist/cabinet/essential-controls.d.ts.map +1 -1
- package/dist/cabinet/essential-controls.js +82 -17
- package/dist/cabinet/index.d.ts +1 -1
- package/dist/cabinet/index.d.ts.map +1 -1
- package/dist/cabinet/index.js +1 -1
- package/dist/cabinet/kitchen-catalog.d.ts +17 -4
- package/dist/cabinet/kitchen-catalog.d.ts.map +1 -1
- package/dist/cabinet/kitchen-catalog.js +45 -7
- package/dist/cabinet/kitchen-collection.d.ts.map +1 -1
- package/dist/cabinet/kitchen-collection.js +21 -5
- package/dist/cabinet/kitchen-module-actions.d.ts.map +1 -1
- package/dist/cabinet/kitchen-module-actions.js +107 -14
- package/dist/cabinet/neighbor-placement.d.ts +10 -0
- package/dist/cabinet/neighbor-placement.d.ts.map +1 -1
- package/dist/cabinet/panel.d.ts.map +1 -1
- package/dist/cabinet/panel.js +127 -50
- package/dist/cabinet/run-finishing.d.ts +5 -0
- package/dist/cabinet/run-finishing.d.ts.map +1 -1
- package/dist/cabinet/run-ops.d.ts +5 -0
- package/dist/cabinet/run-ops.d.ts.map +1 -1
- package/dist/cabinet/run-panel.d.ts.map +1 -1
- package/dist/cabinet/run-panel.js +203 -52
- package/dist/cabinet/tool.d.ts.map +1 -1
- package/dist/cabinet/tool.js +8 -5
- package/dist/ceiling/build-up-section.d.ts +7 -0
- package/dist/ceiling/build-up-section.d.ts.map +1 -0
- package/dist/ceiling/build-up-section.js +57 -0
- package/dist/ceiling/definition.d.ts.map +1 -1
- package/dist/ceiling/definition.js +3 -1
- package/dist/ceiling/floorplan-affordances.d.ts +112 -0
- package/dist/ceiling/floorplan-affordances.d.ts.map +1 -1
- package/dist/ceiling/materials.d.ts +5 -0
- package/dist/ceiling/materials.d.ts.map +1 -1
- package/dist/ceiling/materials.js +17 -0
- package/dist/ceiling/panel-model.d.ts +13 -0
- package/dist/ceiling/panel-model.d.ts.map +1 -0
- package/dist/ceiling/panel-model.js +49 -0
- package/dist/ceiling/panel.d.ts.map +1 -1
- package/dist/ceiling/panel.js +82 -18
- package/dist/ceiling/renderer.d.ts.map +1 -1
- package/dist/ceiling/renderer.js +10 -4
- package/dist/ceiling/tool.d.ts.map +1 -1
- package/dist/ceiling/tool.js +24 -4
- package/dist/chimney/panel.d.ts.map +1 -1
- package/dist/chimney/panel.js +113 -41
- package/dist/column/definition.d.ts.map +1 -1
- package/dist/column/definition.js +3 -0
- package/dist/column/floorplan.d.ts.map +1 -1
- package/dist/column/floorplan.js +17 -0
- package/dist/column/hosted-resize.d.ts +28 -1
- package/dist/column/hosted-resize.d.ts.map +1 -1
- package/dist/column/panel.d.ts.map +1 -1
- package/dist/column/panel.js +125 -37
- package/dist/column/post-options.d.ts +10 -0
- package/dist/column/post-options.d.ts.map +1 -0
- package/dist/column/post-options.js +71 -0
- package/dist/column/post-placement.d.ts +78 -0
- package/dist/column/post-placement.d.ts.map +1 -0
- package/dist/column/post-placement.js +157 -0
- package/dist/column/post-section.d.ts +17 -0
- package/dist/column/post-section.d.ts.map +1 -0
- package/dist/column/post-section.js +95 -0
- package/dist/column/post-tool.d.ts +11 -0
- package/dist/column/post-tool.d.ts.map +1 -0
- package/dist/column/post-tool.js +94 -0
- package/dist/column/tool.d.ts +3 -10
- package/dist/column/tool.d.ts.map +1 -1
- package/dist/column/tool.js +13 -1
- package/dist/cupola/panel.d.ts.map +1 -1
- package/dist/cupola/panel.js +14 -7
- package/dist/door/actions.d.ts +7 -0
- package/dist/door/actions.d.ts.map +1 -0
- package/dist/door/actions.js +32 -0
- package/dist/door/contextual-dimensions.d.ts.map +1 -1
- package/dist/door/contextual-dimensions.js +11 -1
- package/dist/door/definition.d.ts.map +1 -1
- package/dist/door/definition.js +34 -7
- package/dist/door/floorplan-affordances.d.ts.map +1 -1
- package/dist/door/floorplan-affordances.js +5 -2
- package/dist/door/floorplan-move.d.ts.map +1 -1
- package/dist/door/floorplan-move.js +28 -6
- package/dist/door/floorplan.d.ts +2 -0
- package/dist/door/floorplan.d.ts.map +1 -1
- package/dist/door/floorplan.js +89 -16
- package/dist/door/move-tool.d.ts.map +1 -1
- package/dist/door/move-tool.js +60 -16
- package/dist/door/paint.d.ts +2 -7
- package/dist/door/paint.d.ts.map +1 -1
- package/dist/door/paint.js +26 -2
- package/dist/door/panel.d.ts.map +1 -1
- package/dist/door/panel.js +242 -90
- package/dist/door/parametrics.js +1 -1
- package/dist/door/placement.d.ts.map +1 -1
- package/dist/door/placement.js +9 -2
- package/dist/door/swing.d.ts +22 -0
- package/dist/door/swing.d.ts.map +1 -0
- package/dist/door/swing.js +36 -0
- package/dist/door/tool.d.ts.map +1 -1
- package/dist/door/tool.js +76 -29
- package/dist/dormer/panel-actions-section.d.ts.map +1 -1
- package/dist/dormer/panel-actions-section.js +3 -1
- package/dist/dormer/panel-position-section.d.ts.map +1 -1
- package/dist/dormer/panel-position-section.js +4 -3
- package/dist/dormer/panel-windows-section.d.ts.map +1 -1
- package/dist/dormer/panel-windows-section.js +38 -1
- package/dist/dormer/panel.d.ts.map +1 -1
- package/dist/dormer/panel.js +24 -18
- package/dist/downspout/inspector-editors.d.ts.map +1 -1
- package/dist/downspout/inspector-editors.js +3 -2
- package/dist/duct-fitting/inspector-editors.d.ts.map +1 -1
- package/dist/duct-fitting/inspector-editors.js +6 -1
- package/dist/duct-fitting/tool.d.ts.map +1 -1
- package/dist/duct-fitting/tool.js +11 -2
- package/dist/duct-terminal/tool.d.ts.map +1 -1
- package/dist/duct-terminal/tool.js +11 -2
- package/dist/elevator/panel.d.ts.map +1 -1
- package/dist/elevator/panel.js +41 -18
- package/dist/eyebrow-vent/panel.d.ts.map +1 -1
- package/dist/eyebrow-vent/panel.js +16 -6
- package/dist/fence/drafting.d.ts +2 -3
- package/dist/fence/drafting.d.ts.map +1 -1
- package/dist/fence/drafting.js +2 -3
- package/dist/fence/inspector-editors.d.ts.map +1 -1
- package/dist/fence/inspector-editors.js +64 -21
- package/dist/fence/move-endpoint-tool.d.ts.map +1 -1
- package/dist/fence/move-endpoint-tool.js +11 -2
- package/dist/fence/system.d.ts.map +1 -1
- package/dist/fence/system.js +13 -0
- package/dist/fence-feature/actions.d.ts.map +1 -1
- package/dist/fence-feature/actions.js +5 -2
- package/dist/fence-feature/inspector.d.ts.map +1 -1
- package/dist/fence-feature/inspector.js +150 -34
- package/dist/fence-feature/move-session.d.ts +1 -1
- package/dist/floor-opening/floorplan.d.ts +29 -6
- package/dist/floor-opening/floorplan.d.ts.map +1 -1
- package/dist/floor-opening/floorplan.js +172 -14
- package/dist/gutter/downspouts-panel.d.ts.map +1 -1
- package/dist/gutter/downspouts-panel.js +14 -2
- package/dist/hvac-equipment/tool.d.ts.map +1 -1
- package/dist/hvac-equipment/tool.js +3 -2
- package/dist/i18n/definition-messages.d.ts +5 -0
- package/dist/i18n/definition-messages.d.ts.map +1 -0
- package/dist/i18n/definition-messages.js +771 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/item/authored-params.d.ts.map +1 -1
- package/dist/item/authored-params.js +19 -4
- package/dist/item/floorplan.d.ts +1 -1
- package/dist/item/floorplan.d.ts.map +1 -1
- package/dist/item/panel.d.ts.map +1 -1
- package/dist/item/panel.js +9 -7
- package/dist/liquid-line/tool.d.ts.map +1 -1
- package/dist/liquid-line/tool.js +10 -3
- package/dist/measurement/tool.d.ts +1 -1
- package/dist/measurement/tool.d.ts.map +1 -1
- package/dist/measurement/tool.js +8 -8
- package/dist/pipe-fitting/tool.d.ts.map +1 -1
- package/dist/pipe-fitting/tool.js +3 -2
- package/dist/pipe-trap/tool.d.ts.map +1 -1
- package/dist/pipe-trap/tool.js +7 -2
- package/dist/procedural-item/renderer.d.ts.map +1 -1
- package/dist/procedural-item/renderer.js +8 -1
- package/dist/ridge-vent/panel.d.ts.map +1 -1
- package/dist/ridge-vent/panel.js +22 -9
- package/dist/roof/barrel-panel.d.ts.map +1 -1
- package/dist/roof/barrel-panel.js +7 -3
- package/dist/roof/definition.d.ts.map +1 -1
- package/dist/roof/definition.js +33 -3
- package/dist/roof/floorplan-overrides.d.ts +22 -0
- package/dist/roof/floorplan-overrides.d.ts.map +1 -0
- package/dist/roof/floorplan-overrides.js +46 -0
- package/dist/roof/floorplan-tool.d.ts +9 -0
- package/dist/roof/floorplan-tool.d.ts.map +1 -0
- package/dist/roof/floorplan-tool.js +168 -0
- package/dist/roof/floorplan.d.ts.map +1 -1
- package/dist/roof/floorplan.js +131 -41
- package/dist/roof/glazing-controls.d.ts +2 -1
- package/dist/roof/glazing-controls.d.ts.map +1 -1
- package/dist/roof/glazing-controls.js +51 -13
- package/dist/roof/glazing-panel-editor.d.ts.map +1 -1
- package/dist/roof/glazing-panel-editor.js +40 -13
- package/dist/roof/glazing-panel.d.ts.map +1 -1
- package/dist/roof/glazing-panel.js +73 -9
- package/dist/roof/paint.d.ts +19 -0
- package/dist/roof/paint.d.ts.map +1 -0
- package/dist/roof/paint.js +158 -0
- package/dist/roof/panel.d.ts.map +1 -1
- package/dist/roof/panel.js +90 -22
- package/dist/roof/renderer.d.ts.map +1 -1
- package/dist/roof/renderer.js +13 -2
- package/dist/roof/roof-footprint-source.d.ts +17 -0
- package/dist/roof/roof-footprint-source.d.ts.map +1 -1
- package/dist/roof/roof-footprint-source.js +14 -0
- package/dist/roof/roof-footprint.d.ts +36 -2
- package/dist/roof/roof-footprint.d.ts.map +1 -1
- package/dist/roof/roof-footprint.js +124 -2
- package/dist/roof/roof-materials.d.ts.map +1 -1
- package/dist/roof/roof-materials.js +10 -1
- package/dist/roof/roof-placement-mode.d.ts +0 -2
- package/dist/roof/roof-placement-mode.d.ts.map +1 -1
- package/dist/roof/roof-placement-mode.js +8 -6
- package/dist/roof/roof-plan-creases.d.ts +50 -0
- package/dist/roof/roof-plan-creases.d.ts.map +1 -0
- package/dist/roof/roof-plan-creases.js +194 -0
- package/dist/roof/roof-ridge-mode.d.ts +20 -0
- package/dist/roof/roof-ridge-mode.d.ts.map +1 -0
- package/dist/roof/roof-ridge-mode.js +16 -0
- package/dist/roof/tool.d.ts +17 -4
- package/dist/roof/tool.d.ts.map +1 -1
- package/dist/roof/tool.js +211 -113
- package/dist/roof/wall-catch.d.ts +106 -0
- package/dist/roof/wall-catch.d.ts.map +1 -0
- package/dist/roof/wall-catch.js +267 -0
- package/dist/roof-segment/build-up-section.d.ts +9 -0
- package/dist/roof-segment/build-up-section.d.ts.map +1 -0
- package/dist/roof-segment/build-up-section.js +191 -0
- package/dist/roof-segment/definition.d.ts.map +1 -1
- package/dist/roof-segment/definition.js +50 -5
- package/dist/roof-segment/floorplan-affordances.d.ts.map +1 -1
- package/dist/roof-segment/floorplan-affordances.js +68 -19
- package/dist/roof-segment/floorplan.d.ts.map +1 -1
- package/dist/roof-segment/floorplan.js +16 -12
- package/dist/roof-segment/paint.d.ts +3 -1
- package/dist/roof-segment/paint.d.ts.map +1 -1
- package/dist/roof-segment/paint.js +43 -2
- package/dist/roof-segment/panel-model.d.ts +23 -0
- package/dist/roof-segment/panel-model.d.ts.map +1 -0
- package/dist/roof-segment/panel-model.js +64 -0
- package/dist/roof-segment/panel.d.ts.map +1 -1
- package/dist/roof-segment/panel.js +96 -14
- package/dist/roof-segment/parametrics.d.ts.map +1 -1
- package/dist/roof-segment/parametrics.js +4 -0
- package/dist/roof-segment/renderer.d.ts.map +1 -1
- package/dist/roof-segment/renderer.js +26 -5
- package/dist/separator/definition.d.ts.map +1 -1
- package/dist/separator/definition.js +10 -12
- package/dist/separator/floorplan-affordances.d.ts +9 -0
- package/dist/separator/floorplan-affordances.d.ts.map +1 -0
- package/dist/separator/floorplan-affordances.js +23 -0
- package/dist/separator/floorplan.d.ts +9 -0
- package/dist/separator/floorplan.d.ts.map +1 -0
- package/dist/separator/floorplan.js +54 -0
- package/dist/separator/renderer.d.ts +4 -0
- package/dist/separator/renderer.d.ts.map +1 -1
- package/dist/separator/renderer.js +21 -6
- package/dist/separator/selection.d.ts +10 -0
- package/dist/separator/selection.d.ts.map +1 -0
- package/dist/separator/selection.js +35 -0
- package/dist/shared/build-up-controls.d.ts +88 -0
- package/dist/shared/build-up-controls.d.ts.map +1 -0
- package/dist/shared/build-up-controls.js +139 -0
- package/dist/shared/curtain-opening-limits.d.ts.map +1 -1
- package/dist/shared/curtain-opening-limits.js +44 -14
- package/dist/shared/item-interaction-actions.d.ts.map +1 -1
- package/dist/shared/item-interaction-actions.js +11 -2
- package/dist/shared/layer-thickness.d.ts +2 -0
- package/dist/shared/layer-thickness.d.ts.map +1 -0
- package/dist/shared/layer-thickness.js +3 -0
- package/dist/shared/move-roof-tool.d.ts.map +1 -1
- package/dist/shared/move-roof-tool.js +100 -5
- package/dist/shared/node-batch/batchable.d.ts +2 -0
- package/dist/shared/node-batch/batchable.d.ts.map +1 -1
- package/dist/shared/node-batch/batchable.js +4 -0
- package/dist/shared/node-batch/candidates.d.ts +21 -5
- package/dist/shared/node-batch/candidates.d.ts.map +1 -1
- package/dist/shared/node-batch/candidates.js +85 -50
- package/dist/shared/node-batch/system.d.ts.map +1 -1
- package/dist/shared/node-batch/system.js +24 -15
- package/dist/shared/opening-casing-move.d.ts +16 -0
- package/dist/shared/opening-casing-move.d.ts.map +1 -0
- package/dist/shared/opening-casing-move.js +33 -0
- package/dist/shared/opening-casing-section.d.ts +15 -0
- package/dist/shared/opening-casing-section.d.ts.map +1 -0
- package/dist/shared/opening-casing-section.js +38 -0
- package/dist/shared/opening-casing.d.ts +26 -0
- package/dist/shared/opening-casing.d.ts.map +1 -0
- package/dist/shared/opening-casing.js +80 -0
- package/dist/shared/opening-depth-position.d.ts +13 -0
- package/dist/shared/opening-depth-position.d.ts.map +1 -0
- package/dist/shared/opening-depth-position.js +34 -0
- package/dist/shared/opening-documentation.d.ts.map +1 -1
- package/dist/shared/opening-documentation.js +17 -8
- package/dist/shared/opening-guides-runtime.d.ts +2 -1
- package/dist/shared/opening-guides-runtime.d.ts.map +1 -1
- package/dist/shared/opening-guides-runtime.js +11 -7
- package/dist/shared/opening-labels.d.ts +11 -0
- package/dist/shared/opening-labels.d.ts.map +1 -0
- package/dist/shared/opening-labels.js +46 -0
- package/dist/shared/opening-placement-dimensions.d.ts.map +1 -1
- package/dist/shared/opening-placement-dimensions.js +11 -9
- package/dist/shared/opening-plane-offset.d.ts +4 -3
- package/dist/shared/opening-plane-offset.d.ts.map +1 -1
- package/dist/shared/opening-plane-offset.js +7 -4
- package/dist/shared/opening-swap.d.ts +8 -0
- package/dist/shared/opening-swap.d.ts.map +1 -0
- package/dist/shared/opening-swap.js +18 -0
- package/dist/shared/polygon-vertex-affordance.d.ts +19 -0
- package/dist/shared/polygon-vertex-affordance.d.ts.map +1 -1
- package/dist/shared/polygon-vertex-affordance.js +65 -6
- package/dist/shared/roof-opening-host.d.ts +2 -1
- package/dist/shared/roof-opening-host.d.ts.map +1 -1
- package/dist/shared/roof-opening-host.js +14 -5
- package/dist/shared/roof-wall-opening-cut.d.ts.map +1 -1
- package/dist/shared/roof-wall-opening-cut.js +14 -6
- package/dist/shared/roof-wall-opening-placement.d.ts +2 -1
- package/dist/shared/roof-wall-opening-placement.d.ts.map +1 -1
- package/dist/shared/roof-wall-opening-placement.js +6 -4
- package/dist/shared/run-hanger-inspector.d.ts.map +1 -1
- package/dist/shared/run-hanger-inspector.js +39 -5
- package/dist/shared/system-check-panel.d.ts.map +1 -1
- package/dist/shared/system-check-panel.js +94 -15
- package/dist/shared/wall-attach-target.d.ts.map +1 -1
- package/dist/shared/wall-attach-target.js +6 -3
- package/dist/shelf/definition.d.ts.map +1 -1
- package/dist/shelf/definition.js +2 -0
- package/dist/site/ground-hole.d.ts +3 -3
- package/dist/site/ground-hole.js +3 -3
- package/dist/site/ground-veil.d.ts +5 -12
- package/dist/site/ground-veil.d.ts.map +1 -1
- package/dist/site/ground-veil.js +9 -33
- package/dist/site/panel.d.ts.map +1 -1
- package/dist/site/panel.js +52 -12
- package/dist/site/renderer.d.ts.map +1 -1
- package/dist/site/renderer.js +52 -23
- package/dist/skylight/panel.d.ts.map +1 -1
- package/dist/skylight/panel.js +49 -19
- package/dist/slab/deck-geometry.d.ts +28 -0
- package/dist/slab/deck-geometry.d.ts.map +1 -0
- package/dist/slab/deck-geometry.js +320 -0
- package/dist/slab/definition.d.ts +2 -1
- package/dist/slab/definition.d.ts.map +1 -1
- package/dist/slab/definition.js +6 -1
- package/dist/slab/dependency-tracker.d.ts.map +1 -1
- package/dist/slab/dependency-tracker.js +3 -0
- package/dist/slab/floorplan-affordances.d.ts +500 -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 +46 -9
- package/dist/slab/panel.d.ts.map +1 -1
- package/dist/slab/panel.js +97 -21
- package/dist/slab/renderer.d.ts +11 -0
- package/dist/slab/renderer.d.ts.map +1 -0
- package/dist/slab/renderer.js +19 -0
- package/dist/slab/system.d.ts.map +1 -1
- package/dist/slab/system.js +12 -1
- package/dist/solar-panel/panel.d.ts.map +1 -1
- package/dist/solar-panel/panel.js +49 -14
- package/dist/stair/construction-controls.d.ts +3 -1
- package/dist/stair/construction-controls.d.ts.map +1 -1
- package/dist/stair/construction-controls.js +75 -12
- package/dist/stair/paint.d.ts +6 -0
- package/dist/stair/paint.d.ts.map +1 -1
- package/dist/stair/panel.d.ts.map +1 -1
- package/dist/stair/panel.js +243 -51
- package/dist/stair/parametrics.d.ts.map +1 -1
- package/dist/stair/parametrics.js +7 -0
- package/dist/stair/placement-defaults.d.ts +18 -0
- package/dist/stair/placement-defaults.d.ts.map +1 -0
- package/dist/stair/placement-defaults.js +27 -0
- package/dist/stair/railing-controls.d.ts.map +1 -1
- package/dist/stair/railing-controls.js +78 -18
- package/dist/stair/renderer.d.ts.map +1 -1
- package/dist/stair/renderer.js +16 -10
- package/dist/stair/structure-controls.d.ts +18 -0
- package/dist/stair/structure-controls.d.ts.map +1 -0
- package/dist/stair/structure-controls.js +275 -0
- package/dist/stair/tool.d.ts.map +1 -1
- package/dist/stair/tool.js +13 -9
- package/dist/stair/use-stair-render-data.d.ts +41 -0
- package/dist/stair/use-stair-render-data.d.ts.map +1 -1
- package/dist/stair-segment/panel.d.ts.map +1 -1
- package/dist/stair-segment/panel.js +65 -18
- package/dist/turbine-vent/panel.d.ts.map +1 -1
- package/dist/turbine-vent/panel.js +14 -5
- package/dist/unit/unit-panel.d.ts.map +1 -1
- package/dist/unit/unit-panel.js +28 -12
- package/dist/wall/actions.d.ts +1 -1
- package/dist/wall/actions.d.ts.map +1 -1
- package/dist/wall/actions.js +17 -13
- package/dist/wall/construction-dimensions.d.ts +6 -0
- package/dist/wall/construction-dimensions.d.ts.map +1 -1
- package/dist/wall/construction-dimensions.js +8 -0
- package/dist/wall/contextual-dimensions.d.ts +6 -0
- package/dist/wall/contextual-dimensions.d.ts.map +1 -1
- package/dist/wall/contextual-dimensions.js +104 -17
- package/dist/wall/curtain-opening-frame.d.ts.map +1 -1
- package/dist/wall/curtain-opening-frame.js +6 -4
- package/dist/wall/curtain-wall-layout.d.ts +1 -1
- package/dist/wall/curtain-wall-layout.d.ts.map +1 -1
- package/dist/wall/curtain-wall-layout.js +6 -4
- package/dist/wall/curtain-wall-materials.d.ts.map +1 -1
- package/dist/wall/curtain-wall-materials.js +8 -3
- package/dist/wall/curtain-wall-panel.d.ts.map +1 -1
- package/dist/wall/curtain-wall-panel.js +241 -37
- package/dist/wall/curve-tool.d.ts.map +1 -1
- package/dist/wall/curve-tool.js +2 -3
- package/dist/wall/definition.d.ts.map +1 -1
- package/dist/wall/definition.js +20 -5
- package/dist/wall/floorplan-affordances.d.ts.map +1 -1
- package/dist/wall/floorplan-affordances.js +9 -6
- package/dist/wall/floorplan-move.d.ts.map +1 -1
- package/dist/wall/floorplan-move.js +66 -16
- package/dist/wall/floorplan.d.ts +4 -5
- package/dist/wall/floorplan.d.ts.map +1 -1
- package/dist/wall/floorplan.js +62 -46
- package/dist/wall/move-endpoint-tool.d.ts.map +1 -1
- package/dist/wall/move-endpoint-tool.js +1 -0
- package/dist/wall/move-tool.d.ts.map +1 -1
- package/dist/wall/move-tool.js +77 -12
- package/dist/wall/paint.d.ts +2 -2
- package/dist/wall/paint.d.ts.map +1 -1
- package/dist/wall/paint.js +11 -4
- package/dist/wall/panel-model.d.ts +17 -2
- package/dist/wall/panel-model.d.ts.map +1 -1
- package/dist/wall/panel-model.js +158 -18
- package/dist/wall/panel.d.ts +8 -0
- package/dist/wall/panel.d.ts.map +1 -1
- package/dist/wall/panel.js +228 -156
- package/dist/wall/parametrics.d.ts +1 -1
- package/dist/wall/parametrics.d.ts.map +1 -1
- package/dist/wall/parametrics.js +14 -1
- package/dist/wall/railing-wall-adapter.d.ts +7 -0
- package/dist/wall/railing-wall-adapter.d.ts.map +1 -0
- package/dist/wall/railing-wall-adapter.js +38 -0
- package/dist/wall/railing-wall-floorplan.d.ts +8 -0
- package/dist/wall/railing-wall-floorplan.d.ts.map +1 -0
- package/dist/wall/railing-wall-floorplan.js +27 -0
- package/dist/wall/railing-wall-geometry.d.ts +12 -0
- package/dist/wall/railing-wall-geometry.d.ts.map +1 -0
- package/dist/wall/railing-wall-geometry.js +51 -0
- package/dist/wall/railing-wall-guard.d.ts +81 -0
- package/dist/wall/railing-wall-guard.d.ts.map +1 -0
- package/dist/wall/railing-wall-guard.js +435 -0
- package/dist/wall/railing-wall-materials.d.ts +11 -0
- package/dist/wall/railing-wall-materials.d.ts.map +1 -0
- package/dist/wall/railing-wall-materials.js +31 -0
- package/dist/wall/railing-wall-panel-model.d.ts +30 -0
- package/dist/wall/railing-wall-panel-model.d.ts.map +1 -0
- package/dist/wall/railing-wall-panel-model.js +117 -0
- package/dist/wall/railing-wall-panel.d.ts +17 -0
- package/dist/wall/railing-wall-panel.d.ts.map +1 -0
- package/dist/wall/railing-wall-panel.js +42 -0
- package/dist/wall/rectangle-command.d.ts +79 -1
- package/dist/wall/rectangle-command.d.ts.map +1 -1
- package/dist/wall/rectangle-tool.d.ts.map +1 -1
- package/dist/wall/rectangle-tool.js +2 -0
- package/dist/wall/renderer.d.ts.map +1 -1
- package/dist/wall/renderer.js +3 -1
- package/dist/wall/skirting-floor-gaps.d.ts +8 -0
- package/dist/wall/skirting-floor-gaps.d.ts.map +1 -0
- package/dist/wall/skirting-floor-gaps.js +36 -0
- package/dist/wall/system.d.ts +0 -14
- package/dist/wall/system.d.ts.map +1 -1
- package/dist/wall/system.js +6 -1
- package/dist/wall/tool.d.ts +16 -0
- package/dist/wall/tool.d.ts.map +1 -1
- package/dist/wall/tool.js +160 -47
- package/dist/wall/treatments.d.ts +3 -0
- package/dist/wall/treatments.d.ts.map +1 -1
- package/dist/wall/treatments.js +30 -7
- package/dist/window/actions.d.ts +7 -0
- package/dist/window/actions.d.ts.map +1 -0
- package/dist/window/actions.js +29 -0
- package/dist/window/definition.d.ts.map +1 -1
- package/dist/window/definition.js +11 -2
- package/dist/window/floorplan-move.d.ts.map +1 -1
- package/dist/window/floorplan-move.js +5 -0
- package/dist/window/floorplan.d.ts +2 -0
- package/dist/window/floorplan.d.ts.map +1 -1
- package/dist/window/floorplan.js +58 -1
- package/dist/window/mechanism.d.ts.map +1 -1
- package/dist/window/mechanism.js +21 -1
- package/dist/window/move-tool.d.ts.map +1 -1
- package/dist/window/move-tool.js +10 -3
- package/dist/window/paint.d.ts +2 -7
- package/dist/window/paint.d.ts.map +1 -1
- package/dist/window/paint.js +31 -3
- package/dist/window/panel.d.ts.map +1 -1
- package/dist/window/panel.js +311 -69
- package/dist/window/placement.d.ts.map +1 -1
- package/dist/window/placement.js +5 -1
- package/dist/window/swing.d.ts +13 -0
- package/dist/window/swing.d.ts.map +1 -0
- package/dist/window/swing.js +16 -0
- package/dist/window/tool.d.ts.map +1 -1
- package/dist/window/tool.js +19 -14
- package/dist/zone/floorplan-affordances.d.ts +136 -0
- package/dist/zone/floorplan-affordances.d.ts.map +1 -1
- package/dist/zone/quantities-panel.d.ts.map +1 -1
- package/dist/zone/quantities-panel.js +34 -9
- package/dist/zone/renderer.d.ts.map +1 -1
- package/dist/zone/renderer.js +9 -5
- package/package.json +14 -14
- package/dist/site/generic-foundation-geometry.d.ts +0 -16
- package/dist/site/generic-foundation-geometry.d.ts.map +0 -1
- package/dist/site/generic-foundation-geometry.js +0 -75
- package/dist/site/generic-foundation.d.ts +0 -4
- package/dist/site/generic-foundation.d.ts.map +0 -1
- package/dist/site/generic-foundation.js +0 -91
package/dist/roof/panel.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import {
|
|
4
|
-
import { ActionButton, ActionGroup, duplicateNodeAndPickUp, formatLinearMeasurement, PanelSection, PanelWrapper, parametricNodeUpdates, SegmentedControl, SliderControl, triggerSFX, useEditor, } from '@pascal-app/editor';
|
|
3
|
+
import { getRoofSegmentDeckReach, getSegmentSlopeFrame, isRoofOnStoreyWalls, planRoofsOffStorey, roofLevelAbove, roofTypeHasRakes, useLocale, usePascalI18n, useScene, } from '@pascal-app/core';
|
|
4
|
+
import { ActionButton, ActionGroup, duplicateNodeAndPickUp, formatLinearMeasurement, localizedLevelName, nodeLabel, PanelSection, PanelWrapper, parametricNodeUpdates, SegmentedControl, SliderControl, triggerSFX, useEditor, } from '@pascal-app/editor';
|
|
5
5
|
import { useViewer } from '@pascal-app/viewer';
|
|
6
6
|
import { Copy, Move, Plus, Trash2 } from 'lucide-react';
|
|
7
7
|
import { useCallback, useState } from 'react';
|
|
@@ -9,6 +9,8 @@ import { useShallow } from 'zustand/react/shallow';
|
|
|
9
9
|
import { RoofGlazingPanel } from '../roof/glazing-panel.js';
|
|
10
10
|
import { commitSeatedRoofEdit } from './roof-level-target.js';
|
|
11
11
|
export default function RoofPanel() {
|
|
12
|
+
const i18n = usePascalI18n();
|
|
13
|
+
const locale = useLocale();
|
|
12
14
|
const [ventType, setVentType] = useState('box-vent');
|
|
13
15
|
const selectedId = useViewer((s) => s.selection.selectedIds[0]);
|
|
14
16
|
const unit = useViewer((s) => s.unit);
|
|
@@ -110,10 +112,17 @@ export default function RoofPanel() {
|
|
|
110
112
|
const level = s.nodes[node.parentId];
|
|
111
113
|
const above = roofLevelAbove(s.nodes, level.id);
|
|
112
114
|
return {
|
|
113
|
-
storey:
|
|
115
|
+
storey: localizedLevelName(level, i18n, locale),
|
|
114
116
|
label: above.kind === 'roof'
|
|
115
|
-
?
|
|
116
|
-
|
|
117
|
+
? i18n._({
|
|
118
|
+
id: 'node.roof.panel.moveToTheRoofLevel',
|
|
119
|
+
message: 'Move to the roof level',
|
|
120
|
+
})
|
|
121
|
+
: i18n._({
|
|
122
|
+
id: 'node.roof.panel.moveToLevel',
|
|
123
|
+
message: 'Move to {level}',
|
|
124
|
+
values: { level: localizedLevelName(above.level, i18n, locale) },
|
|
125
|
+
}),
|
|
117
126
|
roofs: level.children.filter((id) => isRoofOnStoreyWalls(s.nodes, id)).length,
|
|
118
127
|
};
|
|
119
128
|
}));
|
|
@@ -143,6 +152,17 @@ export default function RoofPanel() {
|
|
|
143
152
|
// Moved or turned onto the walls that carry it, it goes to the level above them.
|
|
144
153
|
commitSeatedRoofEdit(parametricNodeUpdates(selectedId, updates), selectedId);
|
|
145
154
|
}, [selectedId]);
|
|
155
|
+
// The eaves are each segment's: the roof's sliders set them on all of its segments at once.
|
|
156
|
+
const handleSegmentsUpdate = useCallback((patch) => {
|
|
157
|
+
if (!selectedId)
|
|
158
|
+
return;
|
|
159
|
+
const update = segments.flatMap((segment) => {
|
|
160
|
+
const data = patch(segment);
|
|
161
|
+
return data ? [{ id: segment.id, data: data }] : [];
|
|
162
|
+
});
|
|
163
|
+
if (update.length > 0)
|
|
164
|
+
commitSeatedRoofEdit(update, selectedId);
|
|
165
|
+
}, [segments, selectedId]);
|
|
146
166
|
const handleClose = useCallback(() => {
|
|
147
167
|
setSelection({ selectedIds: [] });
|
|
148
168
|
}, [setSelection]);
|
|
@@ -194,14 +214,47 @@ export default function RoofPanel() {
|
|
|
194
214
|
}, []);
|
|
195
215
|
if (!(node && node.type === 'roof' && selectedId))
|
|
196
216
|
return null;
|
|
197
|
-
|
|
217
|
+
// Shown as the segment panel shows them: in plan, past the walls' outside faces.
|
|
218
|
+
const eaveSegment = segments.find((segment) => segment.roofType !== 'barrel');
|
|
219
|
+
const rakedSegment = segments.find((segment) => roofTypeHasRakes(segment.roofType));
|
|
220
|
+
const overhangPastWall = (segment, axis) => getRoofSegmentDeckReach(segment)[axis] - segment.wallThickness / 2;
|
|
221
|
+
return (_jsxs(PanelWrapper, { icon: "/icons/roof.webp", onClose: handleClose, title: node.name || i18n._({ id: 'node.roof.panel.roof', message: 'Roof' }), width: 300, children: [_jsx(RoofGlazingPanel, { segments: segments }), levelMove && (_jsx(PanelSection, { title: i18n._({ id: 'node.roof.panel.level', message: 'Level' }), children: _jsxs("div", { className: "flex flex-col gap-2 px-1 pb-1", children: [_jsx("p", { className: "text-muted-foreground text-xs", children: i18n._({
|
|
222
|
+
id: 'node.roof.panel.onStoreyWalls',
|
|
223
|
+
message: "On {storey} with its walls, so it hides that floor's plan in solo and exploded views.{roofs, plural, =0 {} =1 {} other { The floor's {roofCount} roofs move together.}}",
|
|
224
|
+
values: {
|
|
225
|
+
storey: levelMove.storey,
|
|
226
|
+
roofs: levelMove.roofs,
|
|
227
|
+
roofCount: String(levelMove.roofs),
|
|
228
|
+
},
|
|
229
|
+
}) }), _jsx("button", { className: "w-full rounded-full bg-foreground/[0.08] px-3 py-2 font-medium text-foreground text-xs transition-colors hover:bg-foreground/[0.14]", onClick: handleMoveOffStorey, type: "button", children: levelMove.label })] }) })), _jsxs(PanelSection, { title: i18n._({ id: 'node.roof.panel.segments', message: 'Segments' }), children: [_jsx("div", { className: "flex flex-col gap-1", children: segments.map((seg, i) => (_jsxs("button", { className: "flex items-center justify-between rounded-lg border border-border/50 bg-black/4 dark:bg-[#2C2C2E] px-3 py-2 text-foreground text-sm transition-colors hover:bg-black/8 dark:hover:bg-[#3e3e3e]", onClick: () => handleSelectSegment(seg.id), type: "button", children: [_jsx("span", { className: "truncate", children: seg.name ||
|
|
230
|
+
i18n._({
|
|
231
|
+
id: 'node.segmentNumber',
|
|
232
|
+
message: 'Segment {number}',
|
|
233
|
+
values: { number: i + 1 },
|
|
234
|
+
}) }), _jsx("span", { className: "text-muted-foreground text-xs", children: i18n._({
|
|
235
|
+
id: 'node.roof.panel.segmentType',
|
|
236
|
+
message: '{roofType, select, hip {Hip} gable {Gable} shed {Shed} gambrel {Gambrel} dutch {Dutch} mansard {Mansard} flat {Flat} conical {Conical} barrel {Barrel} other {Roof}}',
|
|
237
|
+
values: { roofType: seg.roofType },
|
|
238
|
+
}) })] }, seg.id))) }), _jsx(ActionGroup, { children: _jsx(ActionButton, { icon: _jsx(Plus, { className: "h-3.5 w-3.5" }), label: i18n._({ id: 'node.roof.panel.drawSegment', message: 'Draw Segment' }), onClick: handleAddSegment }) })] }), eaveSegment && (_jsxs(PanelSection, { title: i18n._({ id: 'node.roof.panel.eaves', message: 'Eaves' }), children: [_jsx(SliderControl, { label: i18n._({ id: 'node.roof.panel.eaveOverhang', message: 'Eave overhang' }), max: 1, min: 0, onChange: (v) => handleSegmentsUpdate((segment) => segment.roofType === 'barrel'
|
|
239
|
+
? null
|
|
240
|
+
: { overhang: v / getSegmentSlopeFrame(segment).cosTheta }), precision: 2, step: 0.05, unit: "m", value: overhangPastWall(eaveSegment, 'z') }), rakedSegment && (_jsx(SliderControl, { label: i18n._({ id: 'node.roof.panel.gableOverhang', message: 'Gable overhang' }), max: 3, min: 0, onChange: (v) => handleSegmentsUpdate((segment) => roofTypeHasRakes(segment.roofType) ? { gableOverhang: v } : null), precision: 2, step: 0.05, unit: "m", value: overhangPastWall(rakedSegment, 'x') }))] })), _jsxs(PanelSection, { title: i18n._({ id: 'node.roof.panel.position', message: 'Position' }), children: [_jsx(SliderControl, { label: "X", onChange: (v) => {
|
|
198
241
|
const pos = [...node.position];
|
|
199
242
|
pos[0] = v;
|
|
200
243
|
handleUpdate({ position: pos });
|
|
201
244
|
}, precision: 2, step: 0.05, unit: "m", value: node.position[0] }), node.support?.kind !== 'roof' && (_jsx(SegmentedControl, { onChange: (mode) => handleUpdate({ support: { kind: mode === 'walls' ? 'walls' : 'level' } }), options: [
|
|
202
|
-
{
|
|
203
|
-
|
|
204
|
-
|
|
245
|
+
{
|
|
246
|
+
label: i18n._({ id: 'node.roof.panel.followsWalls', message: 'Follows walls' }),
|
|
247
|
+
value: 'walls',
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
label: i18n._({ id: 'node.roof.panel.custom', message: 'Custom' }),
|
|
251
|
+
value: 'custom',
|
|
252
|
+
},
|
|
253
|
+
], value: node.support?.kind === 'walls' ? 'walls' : 'custom' })), node.support?.kind === 'walls' ? (_jsx("div", { className: "px-1 text-[11px] text-muted-foreground", children: i18n._({
|
|
254
|
+
id: 'node.panel.currently',
|
|
255
|
+
message: 'Currently {value}',
|
|
256
|
+
values: { value: formatLinearMeasurement(node.position[1], unit, metricNotation) },
|
|
257
|
+
}) })) : (_jsx(SliderControl, { label: "Y", onChange: (v) => {
|
|
205
258
|
const pos = [...node.position];
|
|
206
259
|
pos[1] = v;
|
|
207
260
|
const current = useScene.getState().nodes[node.id];
|
|
@@ -217,7 +270,7 @@ export default function RoofPanel() {
|
|
|
217
270
|
const pos = [...node.position];
|
|
218
271
|
pos[2] = v;
|
|
219
272
|
handleUpdate({ position: pos });
|
|
220
|
-
}, precision: 2, step: 0.05, unit: "m", value: node.position[2] }), _jsx(SliderControl, { label:
|
|
273
|
+
}, precision: 2, step: 0.05, unit: "m", value: node.position[2] }), _jsx(SliderControl, { label: i18n._({ id: 'node.roof.panel.rotation', message: 'Rotation' }), max: 180, min: -180, onChange: (degrees) => {
|
|
221
274
|
handleUpdate({ rotation: (degrees * Math.PI) / 180 });
|
|
222
275
|
}, precision: 0, step: 1, unit: "\u00B0", value: Math.round((node.rotation * 180) / Math.PI) }), _jsxs("div", { className: "flex gap-1.5 px-1 pt-2 pb-1", children: [_jsx(ActionButton, { label: "-45\u00B0", onClick: () => {
|
|
223
276
|
triggerSFX('sfx:item-rotate');
|
|
@@ -225,18 +278,33 @@ export default function RoofPanel() {
|
|
|
225
278
|
} }), _jsx(ActionButton, { label: "+45\u00B0", onClick: () => {
|
|
226
279
|
triggerSFX('sfx:item-rotate');
|
|
227
280
|
handleUpdate({ rotation: node.rotation + Math.PI / 4 });
|
|
228
|
-
} })] })] }), _jsx(PanelSection, { title:
|
|
229
|
-
(
|
|
230
|
-
|
|
281
|
+
} })] })] }), _jsx(PanelSection, { title: i18n._({ id: 'node.roof.panel.elements', message: 'Elements' }), children: _jsxs("div", { className: "flex flex-col gap-3", children: [_jsxs("div", { className: "flex flex-col gap-1", children: [chimneys.map((chimney, i) => (_jsxs("button", { className: "flex items-center justify-between rounded-lg border border-border/50 bg-black/4 dark:bg-[#2C2C2E] px-3 py-2 text-foreground text-sm transition-colors hover:bg-black/8 dark:hover:bg-[#3e3e3e]", onClick: () => handleSelectElement(chimney.id), type: "button", children: [_jsx("span", { className: "truncate", children: chimney.name || numberedName(nodeLabel('chimney', 'Chimney', i18n), i + 1, i18n) }), _jsx("span", { className: "text-muted-foreground text-xs", children: i18n._({ id: 'node.roof.panel.chimney', message: 'chimney' }) })] }, chimney.id))), _jsx(ActionGroup, { children: _jsx(ActionButton, { icon: _jsx(Plus, { className: "h-3.5 w-3.5" }), label: i18n._({ id: 'node.roof.panel.addChimney', message: 'Add Chimney' }), onClick: () => activateTool('chimney') }) })] }), _jsxs("div", { className: "flex flex-col gap-1", children: [dormers.map((dormer, i) => (_jsxs("button", { className: "flex items-center justify-between rounded-lg border border-border/50 bg-black/4 dark:bg-[#2C2C2E] px-3 py-2 text-foreground text-sm transition-colors hover:bg-black/8 dark:hover:bg-[#3e3e3e]", onClick: () => handleSelectElement(dormer.id), type: "button", children: [_jsx("span", { className: "truncate", children: dormer.name || numberedName(nodeLabel('dormer', 'Dormer', i18n), i + 1, i18n) }), _jsx("span", { className: "text-muted-foreground text-xs", children: i18n._({ id: 'node.roof.panel.dormer', message: 'dormer' }) })] }, dormer.id))), _jsx(ActionGroup, { children: _jsx(ActionButton, { icon: _jsx(Plus, { className: "h-3.5 w-3.5" }), label: i18n._({ id: 'node.roof.panel.addDormer', message: 'Add Dormer' }), onClick: () => activateTool('dormer') }) })] }), _jsxs("div", { className: "flex flex-col gap-1", children: [skylights.map((skylight, i) => (_jsxs("button", { className: "flex items-center justify-between rounded-lg border border-border/50 bg-black/4 dark:bg-[#2C2C2E] px-3 py-2 text-foreground text-sm transition-colors hover:bg-black/8 dark:hover:bg-[#3e3e3e]", onClick: () => handleSelectElement(skylight.id), type: "button", children: [_jsx("span", { className: "truncate", children: skylight.name ||
|
|
282
|
+
numberedName(nodeLabel('skylight', 'Skylight', i18n), i + 1, i18n) }), _jsx("span", { className: "text-muted-foreground text-xs", children: i18n._({ id: 'node.roof.panel.skylight', message: 'skylight' }) })] }, skylight.id))), _jsx(ActionGroup, { children: _jsx(ActionButton, { icon: _jsx(Plus, { className: "h-3.5 w-3.5" }), label: i18n._({ id: 'node.roof.panel.addSkylight', message: 'Add Skylight' }), onClick: () => activateTool('skylight') }) })] }), _jsxs("div", { className: "flex flex-col gap-1", children: [solarPanels.map((panel, i) => (_jsxs("button", { className: "flex items-center justify-between rounded-lg border border-border/50 bg-black/4 dark:bg-[#2C2C2E] px-3 py-2 text-foreground text-sm transition-colors hover:bg-black/8 dark:hover:bg-[#3e3e3e]", onClick: () => handleSelectElement(panel.id), type: "button", children: [_jsx("span", { className: "truncate", children: panel.name ||
|
|
283
|
+
numberedName(nodeLabel('solar-panel', 'Solar Panel', i18n), i + 1, i18n) }), _jsx("span", { className: "text-muted-foreground text-xs", children: i18n._({ id: 'node.roof.panel.solarPanel', message: 'solar panel' }) })] }, panel.id))), _jsx(ActionGroup, { children: _jsx(ActionButton, { icon: _jsx(Plus, { className: "h-3.5 w-3.5" }), label: i18n._({ id: 'node.roof.panel.addSolarPanel', message: 'Add Solar Panel' }), onClick: () => activateTool('solar-panel') }) })] }), _jsxs("div", { className: "flex flex-col gap-1", children: [vents.map((vent, i) => (_jsxs("button", { className: "flex items-center justify-between rounded-lg border border-border/50 bg-black/4 dark:bg-[#2C2C2E] px-3 py-2 text-foreground text-sm transition-colors hover:bg-black/8 dark:hover:bg-[#3e3e3e]", onClick: () => handleSelectElement(vent.id), type: "button", children: [_jsx("span", { className: "truncate", children: vent.name ||
|
|
284
|
+
numberedName(vent.type === 'box-vent'
|
|
285
|
+
? nodeLabel('box-vent', 'Box Vent', i18n)
|
|
231
286
|
: vent.type === 'ridge-vent'
|
|
232
|
-
?
|
|
233
|
-
:
|
|
234
|
-
? 'box vent'
|
|
287
|
+
? nodeLabel('ridge-vent', 'Ridge Vent', i18n)
|
|
288
|
+
: nodeLabel('turbine-vent', 'Turbine Vent', i18n), i + 1, i18n) }), _jsx("span", { className: "text-muted-foreground text-xs", children: vent.type === 'box-vent'
|
|
289
|
+
? i18n._({ id: 'node.roof.panel.boxVent', message: 'box vent' })
|
|
235
290
|
: vent.type === 'ridge-vent'
|
|
236
|
-
? 'ridge vent'
|
|
237
|
-
: 'turbine vent' })] }, vent.id))), _jsx(SegmentedControl, { onChange: setVentType, options: [
|
|
238
|
-
{ label: 'Box', value: 'box-vent' },
|
|
239
|
-
{
|
|
240
|
-
|
|
241
|
-
|
|
291
|
+
? i18n._({ id: 'node.roof.panel.ridgeVent', message: 'ridge vent' })
|
|
292
|
+
: i18n._({ id: 'node.roof.panel.turbineVent', message: 'turbine vent' }) })] }, vent.id))), _jsx(SegmentedControl, { onChange: setVentType, options: [
|
|
293
|
+
{ label: i18n._({ id: 'node.roof.panel.box', message: 'Box' }), value: 'box-vent' },
|
|
294
|
+
{
|
|
295
|
+
label: i18n._({ id: 'node.roof.panel.ridge', message: 'Ridge' }),
|
|
296
|
+
value: 'ridge-vent',
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
label: i18n._({ id: 'node.roof.panel.turbine', message: 'Turbine' }),
|
|
300
|
+
value: 'turbine-vent',
|
|
301
|
+
},
|
|
302
|
+
], value: ventType }), _jsx(ActionGroup, { children: _jsx(ActionButton, { icon: _jsx(Plus, { className: "h-3.5 w-3.5" }), label: i18n._({ id: 'node.roof.panel.addVent', message: 'Add Vent' }), onClick: () => activateTool(ventType) }) })] }), _jsx("div", { className: "flex flex-col gap-1", children: _jsx(ActionGroup, { children: _jsx(ActionButton, { icon: _jsx(Plus, { className: "h-3.5 w-3.5" }), label: i18n._({ id: 'node.roof.panel.addCupola', message: 'Add Cupola' }), onClick: () => activateTool('cupola') }) }) }), _jsx("div", { className: "flex flex-col gap-1", children: _jsx(ActionGroup, { children: _jsx(ActionButton, { icon: _jsx(Plus, { className: "h-3.5 w-3.5" }), label: i18n._({
|
|
303
|
+
id: 'node.roof.panel.addEyebrowVent',
|
|
304
|
+
message: 'Add Eyebrow Vent',
|
|
305
|
+
}), onClick: () => activateTool('eyebrow-vent') }) }) }), _jsxs("div", { className: "flex flex-col gap-1", children: [gutters.map((gutter, i) => (_jsxs("button", { className: "flex items-center justify-between rounded-lg border border-border/50 bg-black/4 dark:bg-[#2C2C2E] px-3 py-2 text-foreground text-sm transition-colors hover:bg-black/8 dark:hover:bg-[#3e3e3e]", onClick: () => handleSelectElement(gutter.id), type: "button", children: [_jsx("span", { className: "truncate", children: gutter.name || numberedName(nodeLabel('gutter', 'Gutter', i18n), i + 1, i18n) }), _jsx("span", { className: "text-muted-foreground text-xs", children: i18n._({ id: 'node.roof.panel.gutter', message: 'gutter' }) })] }, gutter.id))), _jsx(ActionGroup, { children: _jsx(ActionButton, { icon: _jsx(Plus, { className: "h-3.5 w-3.5" }), label: i18n._({ id: 'node.roof.panel.addGutter', message: 'Add Gutter' }), onClick: () => activateTool('gutter') }) })] })] }) }), _jsx(PanelSection, { title: i18n._({ id: 'node.roof.panel.actions', message: 'Actions' }), children: _jsxs(ActionGroup, { children: [_jsx(ActionButton, { icon: _jsx(Move, { className: "h-3.5 w-3.5" }), label: i18n._({ id: 'node.roof.panel.move', message: 'Move' }), onClick: handleMove }), _jsx(ActionButton, { icon: _jsx(Copy, { className: "h-3.5 w-3.5" }), label: i18n._({ id: 'node.roof.panel.duplicate', message: 'Duplicate' }), onClick: handleDuplicate }), _jsx(ActionButton, { className: "hover:bg-red-500/20", icon: _jsx(Trash2, { className: "h-3.5 w-3.5 text-red-600 dark:text-red-400" }), label: i18n._({ id: 'node.roof.panel.delete', message: 'Delete' }), onClick: handleDelete })] }) })] }));
|
|
306
|
+
}
|
|
307
|
+
/** "Chimney 2": a list row for an element without a name of its own. */
|
|
308
|
+
function numberedName(kind, number, i18n) {
|
|
309
|
+
return i18n._({ id: 'node.numberedName', message: '{kind} {number}', values: { kind, number } });
|
|
242
310
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/roof/renderer.tsx"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,QAAQ,EAKd,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/roof/renderer.tsx"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,QAAQ,EAKd,MAAM,kBAAkB,CAAA;AAiBzB,eAAO,MAAM,YAAY,sBAAuB;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,gCAqKjE,CAAA;eAEc,YAAY"}
|
package/dist/roof/renderer.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { hasSegmentMaterialOverride, isIndependentRoofSegment, useLiveNodeOverrides, useRegistry, useScene, } from '@pascal-app/core';
|
|
4
|
-
import { getRoofMaterialArray, isRevealAssembling, levelWallCladdingRef, NodeRenderer, subscribeRevealAssembling, useNodeEvents, useViewer, } from '@pascal-app/viewer';
|
|
4
|
+
import { getRoofMaterialArray, isRevealAssembling, levelWallCladdingRef, levelWallFaceRef, NodeRenderer, subscribeRevealAssembling, useNodeEvents, useViewer, } from '@pascal-app/viewer';
|
|
5
5
|
import { useEffect, useLayoutEffect, useMemo, useRef } from 'react';
|
|
6
6
|
import { useShallow } from 'zustand/react/shallow';
|
|
7
7
|
import { createPlaceholderGeometry } from '../shared/placeholder-geometry.js';
|
|
@@ -97,8 +97,19 @@ export const RoofRenderer = ({ node: rawNode }) => {
|
|
|
97
97
|
const placeholderGeometry = useMemo(() => createPlaceholderGeometry(4), []);
|
|
98
98
|
// The gable band is clad like the walls below it (their assemblies).
|
|
99
99
|
const wallCladdingRef = useScene((state) => levelWallCladdingRef(state.nodes, node));
|
|
100
|
+
// The heel band, under the eaves, is wall: it shows what the walls below show outside.
|
|
101
|
+
const wallFaceRef = useScene((state) => levelWallFaceRef(state.nodes, node));
|
|
100
102
|
const sceneMaterials = useScene((state) => state.materials);
|
|
101
|
-
const customMaterial = useMemo(() => getRoofMaterialArray(node, shading, textures, colorPreset, sceneTheme, wallCladdingRef, sceneMaterials), [
|
|
103
|
+
const customMaterial = useMemo(() => getRoofMaterialArray(node, shading, textures, colorPreset, sceneTheme, wallCladdingRef, sceneMaterials, wallFaceRef), [
|
|
104
|
+
node,
|
|
105
|
+
shading,
|
|
106
|
+
textures,
|
|
107
|
+
colorPreset,
|
|
108
|
+
sceneTheme,
|
|
109
|
+
wallCladdingRef,
|
|
110
|
+
sceneMaterials,
|
|
111
|
+
wallFaceRef,
|
|
112
|
+
]);
|
|
102
113
|
const material = debugColors
|
|
103
114
|
? getRoofDebugMaterials(shading)
|
|
104
115
|
: customMaterial || getRoofMaterials(shading, textures, colorPreset);
|
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
export type RoofFootprintSourceChoice = 'draw' | 'room';
|
|
2
|
+
/**
|
|
3
|
+
* What a Room pick finds under the cursor: a room it can roof, a room that is
|
|
4
|
+
* not a rectangle (Room roofs only rectangles), or no closed room at all.
|
|
5
|
+
*/
|
|
6
|
+
export type RoofRoomPick = 'room' | 'irregular' | 'none';
|
|
2
7
|
type RoofFootprintSourceState = {
|
|
3
8
|
source: RoofFootprintSourceChoice;
|
|
4
9
|
setSource: (source: RoofFootprintSourceChoice) => void;
|
|
10
|
+
/** The hovered Room pick, for the HUD to say why a click would do nothing; null off Room. */
|
|
11
|
+
roomPick: RoofRoomPick | null;
|
|
12
|
+
setRoomPick: (roomPick: RoofRoomPick | null) => void;
|
|
5
13
|
};
|
|
6
14
|
/**
|
|
7
15
|
* How the user wants the next roof footprint made — draw two corners, or pick
|
|
@@ -12,5 +20,14 @@ type RoofFootprintSourceState = {
|
|
|
12
20
|
* tool clears on unmount — both used to wipe the user's choice.
|
|
13
21
|
*/
|
|
14
22
|
declare const useRoofFootprintSource: import("zustand").UseBoundStore<import("zustand").StoreApi<RoofFootprintSourceState>>;
|
|
23
|
+
declare const subscribeToRoomPick: (onChange: () => void) => () => void;
|
|
24
|
+
export declare const irregularRoomHintVisibility: {
|
|
25
|
+
subscribe: typeof subscribeToRoomPick;
|
|
26
|
+
value: () => boolean;
|
|
27
|
+
};
|
|
28
|
+
export declare const noRoomHintVisibility: {
|
|
29
|
+
subscribe: typeof subscribeToRoomPick;
|
|
30
|
+
value: () => boolean;
|
|
31
|
+
};
|
|
15
32
|
export default useRoofFootprintSource;
|
|
16
33
|
//# sourceMappingURL=roof-footprint-source.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"roof-footprint-source.d.ts","sourceRoot":"","sources":["../../src/roof/roof-footprint-source.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,yBAAyB,GAAG,MAAM,GAAG,MAAM,CAAA;AAEvD,KAAK,wBAAwB,GAAG;IAC9B,MAAM,EAAE,yBAAyB,CAAA;IACjC,SAAS,EAAE,CAAC,MAAM,EAAE,yBAAyB,KAAK,IAAI,CAAA;
|
|
1
|
+
{"version":3,"file":"roof-footprint-source.d.ts","sourceRoot":"","sources":["../../src/roof/roof-footprint-source.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,yBAAyB,GAAG,MAAM,GAAG,MAAM,CAAA;AAEvD;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,WAAW,GAAG,MAAM,CAAA;AAExD,KAAK,wBAAwB,GAAG;IAC9B,MAAM,EAAE,yBAAyB,CAAA;IACjC,SAAS,EAAE,CAAC,MAAM,EAAE,yBAAyB,KAAK,IAAI,CAAA;IACtD,6FAA6F;IAC7F,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAA;IAC7B,WAAW,EAAE,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI,KAAK,IAAI,CAAA;CACrD,CAAA;AAED;;;;;;;GAOG;AACH,QAAA,MAAM,sBAAsB,uFAKzB,CAAA;AAEH,QAAA,MAAM,mBAAmB,aAAc,MAAM,IAAI,eAG7C,CAAA;AAEJ,eAAO,MAAM,2BAA2B;IACtC,SAAS;IACT,KAAK;CACN,CAAA;AAED,eAAO,MAAM,oBAAoB;IAC/B,SAAS;IACT,KAAK;CACN,CAAA;eAEc,sBAAsB"}
|
|
@@ -10,5 +10,19 @@ import { create } from 'zustand';
|
|
|
10
10
|
const useRoofFootprintSource = create((set) => ({
|
|
11
11
|
source: 'draw',
|
|
12
12
|
setSource: (source) => set({ source }),
|
|
13
|
+
roomPick: null,
|
|
14
|
+
setRoomPick: (roomPick) => set({ roomPick }),
|
|
13
15
|
}));
|
|
16
|
+
const subscribeToRoomPick = (onChange) => useRoofFootprintSource.subscribe((state, previous) => {
|
|
17
|
+
if (state.roomPick !== previous.roomPick)
|
|
18
|
+
onChange();
|
|
19
|
+
});
|
|
20
|
+
export const irregularRoomHintVisibility = {
|
|
21
|
+
subscribe: subscribeToRoomPick,
|
|
22
|
+
value: () => useRoofFootprintSource.getState().roomPick === 'irregular',
|
|
23
|
+
};
|
|
24
|
+
export const noRoomHintVisibility = {
|
|
25
|
+
subscribe: subscribeToRoomPick,
|
|
26
|
+
value: () => useRoofFootprintSource.getState().roomPick === 'none',
|
|
27
|
+
};
|
|
14
28
|
export default useRoofFootprintSource;
|
|
@@ -1,8 +1,42 @@
|
|
|
1
|
-
import { type AnyNode, type LevelNode, type RoofFootprintTarget, type RoofType, type WallNode } from '@pascal-app/core';
|
|
1
|
+
import { type AlignmentAnchor, type AnyNode, type LevelNode, type RoofFootprintTarget, type RoofType, type WallNode } from '@pascal-app/core';
|
|
2
|
+
import type { RoofRoomPick } from './roof-footprint-source.js';
|
|
2
3
|
export type RoofFootprintSource = 'room' | 'walls' | 'draw';
|
|
3
|
-
export declare function isStandardRoofWallEligible(wall: WallNode): boolean;
|
|
4
|
+
export declare function isStandardRoofWallEligible(wall: Pick<WallNode, 'start' | 'end' | 'curveOffset'>): boolean;
|
|
5
|
+
/**
|
|
6
|
+
* The rooms' edges on `levelIds` a drawn roof snaps to, as it snaps to walls (their corners,
|
|
7
|
+
* middles, crossings and runs): each invisible wall's line, and each railing round a porch, deck
|
|
8
|
+
* or patio at its outside face, from post corner to post corner (`outdoorRoomRoofOutline`), so a
|
|
9
|
+
* roof drawn over the room reaches its outside edge as one drawn over the house reaches its walls'.
|
|
10
|
+
* `faced` holds those railings: their faces stand in for their centre lines. Kept per scene, so a
|
|
11
|
+
* pointer move asks once.
|
|
12
|
+
*/
|
|
13
|
+
export declare function roofSnapEdges(nodes: Readonly<Record<string, AnyNode>>, levelIds: readonly string[]): {
|
|
14
|
+
references: WallNode[];
|
|
15
|
+
faced: Set<string>;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* The rooms' edges on `levelIds` as alignment anchors for a roof drawn over them: each straight
|
|
19
|
+
* invisible wall's ends and middle (as a wall's), and each porch's, deck's or patio's outside
|
|
20
|
+
* corners, railings' post corners included.
|
|
21
|
+
*/
|
|
22
|
+
export declare function roofEdgeAnchors(nodes: Readonly<Record<string, AnyNode>>, levelIds: readonly string[]): AlignmentAnchor[];
|
|
23
|
+
/** What a Room pick lights up while it hovers a room: its walls, a porch's edges with them. */
|
|
24
|
+
export declare function roofFootprintPreviewIds(target: RoofFootprintTarget | null): string[];
|
|
4
25
|
export declare function isConicalRoofWallEligible(targetLevelId: LevelNode['id'], wall: WallNode, nodes: Readonly<Record<string, AnyNode>>): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* The curved wall a cone would be built over from a plan point: the nearest one in reach on the
|
|
28
|
+
* level or the level below. The plan raises no wall events, so its tool picks the wall itself.
|
|
29
|
+
*/
|
|
30
|
+
export declare function pickConicalRoofWall(levelId: LevelNode['id'], nodes: Readonly<Record<string, AnyNode>>, point: [number, number]): WallNode | null;
|
|
5
31
|
export declare function parseRoofFootprintSource(value: unknown, roofType: RoofType): RoofFootprintSource;
|
|
32
|
+
/**
|
|
33
|
+
* The room a Room pick at `point` roofs (the smallest one on the level, else on the level below),
|
|
34
|
+
* and what the pick found: a rectangle it roofs, a room it can't (not a rectangle), or none.
|
|
35
|
+
*/
|
|
36
|
+
export declare function pickRoofRoom(levelId: LevelNode['id'], nodes: Readonly<Record<string, AnyNode>>, point: [number, number]): {
|
|
37
|
+
target: RoofFootprintTarget | null;
|
|
38
|
+
pick: RoofRoomPick;
|
|
39
|
+
};
|
|
6
40
|
export declare function subscribeToConicalRoofWallClicks(options: {
|
|
7
41
|
footprintSource: RoofFootprintSource;
|
|
8
42
|
currentLevelId: LevelNode['id'] | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"roof-footprint.d.ts","sourceRoot":"","sources":["../../src/roof/roof-footprint.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,
|
|
1
|
+
{"version":3,"file":"roof-footprint.d.ts","sourceRoot":"","sources":["../../src/roof/roof-footprint.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,OAAO,EASZ,KAAK,SAAS,EAGd,KAAK,mBAAmB,EACxB,KAAK,QAAQ,EAMb,KAAK,QAAQ,EAGd,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAE3D,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAA;AAI3D,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,OAAO,GAAG,KAAK,GAAG,aAAa,CAAC,GACpD,OAAO,CAKT;AAgED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACxC,QAAQ,EAAE,SAAS,MAAM,EAAE,GAC1B;IAAE,UAAU,EAAE,QAAQ,EAAE,CAAC;IAAC,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CAAE,CAYhD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACxC,QAAQ,EAAE,SAAS,MAAM,EAAE,GAC1B,eAAe,EAAE,CAOnB;AAED,+FAA+F;AAC/F,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,mBAAmB,GAAG,IAAI,GAAG,MAAM,EAAE,CAEpF;AAED,wBAAgB,yBAAyB,CACvC,aAAa,EAAE,SAAS,CAAC,IAAI,CAAC,EAC9B,IAAI,EAAE,QAAQ,EACd,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACvC,OAAO,CAMT;AAKD;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,SAAS,CAAC,IAAI,CAAC,EACxB,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACxC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,GACtB,QAAQ,GAAG,IAAI,CAajB;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,mBAAmB,CAGhG;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,SAAS,CAAC,IAAI,CAAC,EACxB,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACxC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,GACtB;IAAE,MAAM,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAAC,IAAI,EAAE,YAAY,CAAA;CAAE,CAI5D;AAED,wBAAgB,gCAAgC,CAAC,OAAO,EAAE;IACxD,eAAe,EAAE,mBAAmB,CAAA;IACpC,cAAc,EAAE,SAAS,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IACtC,QAAQ,EAAE,MAAM,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IACjD,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,KAAK,IAAI,CAAA;IAC3C,QAAQ,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,CAAA;IAClC,QAAQ,EAAE,QAAQ,CAAA;CACnB,GAAG,MAAM,IAAI,CA0Cb;AAED,wBAAgB,6BAA6B,CAC3C,aAAa,EAAE,SAAS,CAAC,IAAI,CAAC,EAC9B,MAAM,EAAE,mBAAmB,EAC3B,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACvC,MAAM,CAWR;AAED,wBAAgB,kCAAkC,CAChD,aAAa,EAAE,SAAS,CAAC,IAAI,CAAC,EAC9B,MAAM,EAAE,mBAAmB,EAC3B,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACvC,MAAM,CAOR;AAED;;;;;;;GAOG;AACH,wBAAgB,gCAAgC,CAC9C,aAAa,EAAE,SAAS,CAAC,IAAI,CAAC,EAC9B,IAAI,EAAE,QAAQ,EACd,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACxC,UAAU,yDAAuD,GAChE,MAAM,CAKR"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { emitter, getLevelBelow, getLevelElevations, isCurvedWall, resolveLevelId, resolveRoofWallTopElevation, } from '@pascal-app/core';
|
|
1
|
+
import { emitter, getLevelBelow, getLevelElevations, getWallCurveFrameAt, getWallCurveStationAtPoint, isCurvedWall, isOutdoorRoomType, isRailingWall, outdoorRoomRoofOutline, polygonAnchors, resolveLevelId, resolveRoofWallTopElevation, resolveRoomRoofFootprint, wallSegmentAnchors, } from '@pascal-app/core';
|
|
2
2
|
const ROOF_AXIS_ALIGNMENT_EPSILON = 1e-4;
|
|
3
3
|
export function isStandardRoofWallEligible(wall) {
|
|
4
4
|
if (isCurvedWall(wall))
|
|
@@ -7,6 +7,94 @@ export function isStandardRoofWallEligible(wall) {
|
|
|
7
7
|
const deltaZ = Math.abs(wall.end[1] - wall.start[1]);
|
|
8
8
|
return deltaX <= ROOF_AXIS_ALIGNMENT_EPSILON || deltaZ <= ROOF_AXIS_ALIGNMENT_EPSILON;
|
|
9
9
|
}
|
|
10
|
+
/** A room's edge as the wall snap reads a wall: its ends, its middle and its run catch a point. */
|
|
11
|
+
function edgeReference(id, parentId, start, end) {
|
|
12
|
+
return {
|
|
13
|
+
object: 'node',
|
|
14
|
+
id: id,
|
|
15
|
+
type: 'wall',
|
|
16
|
+
parentId,
|
|
17
|
+
visible: true,
|
|
18
|
+
metadata: {},
|
|
19
|
+
children: [],
|
|
20
|
+
start,
|
|
21
|
+
end,
|
|
22
|
+
frontSide: 'unknown',
|
|
23
|
+
backSide: 'unknown',
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/** The levels' invisible walls, and their porches', decks' and patios' outside edges. */
|
|
27
|
+
function levelEdges(nodes, levelIds) {
|
|
28
|
+
return levelIds.flatMap((levelId) => {
|
|
29
|
+
const level = nodes[levelId];
|
|
30
|
+
if (level?.type !== 'level')
|
|
31
|
+
return [];
|
|
32
|
+
const children = level.children.map((id) => nodes[id]);
|
|
33
|
+
const walls = children.filter((node) => node?.type === 'wall');
|
|
34
|
+
const separators = children.filter((node) => node?.type === 'separator');
|
|
35
|
+
const rooms = children
|
|
36
|
+
.filter((node) => node?.type === 'zone' && isOutdoorRoomType(node.roomType) && node.polygon.length >= 3)
|
|
37
|
+
.map((zone) => ({ zone, ...outdoorRoomRoofOutline(zone, walls, separators) }));
|
|
38
|
+
return [{ levelId, separators, rooms }];
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
const snapEdgesMemo = new WeakMap();
|
|
42
|
+
function computeRoofSnapEdges(nodes, levelIds) {
|
|
43
|
+
const references = [];
|
|
44
|
+
const faced = new Set();
|
|
45
|
+
for (const { levelId, separators, rooms } of levelEdges(nodes, levelIds)) {
|
|
46
|
+
for (const separator of separators)
|
|
47
|
+
references.push(edgeReference(separator.id, levelId, separator.start, separator.end));
|
|
48
|
+
for (const { polygon, edges } of rooms)
|
|
49
|
+
edges.forEach((edge, index) => {
|
|
50
|
+
if (edge?.kind !== 'railing')
|
|
51
|
+
return;
|
|
52
|
+
faced.add(edge.id);
|
|
53
|
+
const next = polygon[(index + 1) % polygon.length];
|
|
54
|
+
references.push(edgeReference(edge.id, levelId, polygon[index], next));
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
return { references, faced };
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* The rooms' edges on `levelIds` a drawn roof snaps to, as it snaps to walls (their corners,
|
|
61
|
+
* middles, crossings and runs): each invisible wall's line, and each railing round a porch, deck
|
|
62
|
+
* or patio at its outside face, from post corner to post corner (`outdoorRoomRoofOutline`), so a
|
|
63
|
+
* roof drawn over the room reaches its outside edge as one drawn over the house reaches its walls'.
|
|
64
|
+
* `faced` holds those railings: their faces stand in for their centre lines. Kept per scene, so a
|
|
65
|
+
* pointer move asks once.
|
|
66
|
+
*/
|
|
67
|
+
export function roofSnapEdges(nodes, levelIds) {
|
|
68
|
+
const key = levelIds.join('|');
|
|
69
|
+
let byKey = snapEdgesMemo.get(nodes);
|
|
70
|
+
if (!byKey) {
|
|
71
|
+
byKey = new Map();
|
|
72
|
+
snapEdgesMemo.set(nodes, byKey);
|
|
73
|
+
}
|
|
74
|
+
const cached = byKey.get(key);
|
|
75
|
+
if (cached)
|
|
76
|
+
return cached;
|
|
77
|
+
const edges = computeRoofSnapEdges(nodes, levelIds);
|
|
78
|
+
byKey.set(key, edges);
|
|
79
|
+
return edges;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* The rooms' edges on `levelIds` as alignment anchors for a roof drawn over them: each straight
|
|
83
|
+
* invisible wall's ends and middle (as a wall's), and each porch's, deck's or patio's outside
|
|
84
|
+
* corners, railings' post corners included.
|
|
85
|
+
*/
|
|
86
|
+
export function roofEdgeAnchors(nodes, levelIds) {
|
|
87
|
+
return levelEdges(nodes, levelIds).flatMap(({ separators, rooms }) => [
|
|
88
|
+
...separators
|
|
89
|
+
.filter((separator) => isStandardRoofWallEligible(separator))
|
|
90
|
+
.flatMap((separator) => wallSegmentAnchors(separator.id, separator.start, separator.end)),
|
|
91
|
+
...rooms.flatMap(({ zone, polygon }) => polygonAnchors(zone.id, polygon)),
|
|
92
|
+
]);
|
|
93
|
+
}
|
|
94
|
+
/** What a Room pick lights up while it hovers a room: its walls, a porch's edges with them. */
|
|
95
|
+
export function roofFootprintPreviewIds(target) {
|
|
96
|
+
return target ? [...target.wallIds, ...(target.edgeIds ?? [])] : [];
|
|
97
|
+
}
|
|
10
98
|
export function isConicalRoofWallEligible(targetLevelId, wall, nodes) {
|
|
11
99
|
const completeNodes = nodes;
|
|
12
100
|
const sourceLevelId = resolveLevelId(wall, completeNodes);
|
|
@@ -16,11 +104,44 @@ export function isConicalRoofWallEligible(targetLevelId, wall, nodes) {
|
|
|
16
104
|
return true;
|
|
17
105
|
return getLevelBelow(targetLevelId, completeNodes)?.id === sourceLevelId;
|
|
18
106
|
}
|
|
107
|
+
// As far off the wall's centreline as the plan reaches for a wall a door or window goes in.
|
|
108
|
+
const CONICAL_WALL_PICK_DISTANCE = 0.5;
|
|
109
|
+
/**
|
|
110
|
+
* The curved wall a cone would be built over from a plan point: the nearest one in reach on the
|
|
111
|
+
* level or the level below. The plan raises no wall events, so its tool picks the wall itself.
|
|
112
|
+
*/
|
|
113
|
+
export function pickConicalRoofWall(levelId, nodes, point) {
|
|
114
|
+
let picked = null;
|
|
115
|
+
let pickedDistance = CONICAL_WALL_PICK_DISTANCE;
|
|
116
|
+
for (const node of Object.values(nodes)) {
|
|
117
|
+
if (!(node.type === 'wall' && isCurvedWall(node)))
|
|
118
|
+
continue;
|
|
119
|
+
if (!isConicalRoofWallEligible(levelId, node, nodes))
|
|
120
|
+
continue;
|
|
121
|
+
const nearest = getWallCurveFrameAt(node, getWallCurveStationAtPoint(node, point)).point;
|
|
122
|
+
const distance = Math.hypot(point[0] - nearest.x, point[1] - nearest.y);
|
|
123
|
+
if (distance > pickedDistance)
|
|
124
|
+
continue;
|
|
125
|
+
picked = node;
|
|
126
|
+
pickedDistance = distance;
|
|
127
|
+
}
|
|
128
|
+
return picked;
|
|
129
|
+
}
|
|
19
130
|
export function parseRoofFootprintSource(value, roofType) {
|
|
20
131
|
if (roofType === 'conical')
|
|
21
132
|
return 'walls';
|
|
22
133
|
return value === 'room' ? 'room' : 'draw';
|
|
23
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* The room a Room pick at `point` roofs (the smallest one on the level, else on the level below),
|
|
137
|
+
* and what the pick found: a rectangle it roofs, a room it can't (not a rectangle), or none.
|
|
138
|
+
*/
|
|
139
|
+
export function pickRoofRoom(levelId, nodes, point) {
|
|
140
|
+
const found = resolveRoomRoofFootprint(levelId, nodes, point);
|
|
141
|
+
if (!found)
|
|
142
|
+
return { target: null, pick: 'none' };
|
|
143
|
+
return found.rectangular ? { target: found, pick: 'room' } : { target: null, pick: 'irregular' };
|
|
144
|
+
}
|
|
24
145
|
export function subscribeToConicalRoofWallClicks(options) {
|
|
25
146
|
if (!(options.roofType === 'conical' && options.footprintSource === 'walls'))
|
|
26
147
|
return () => { };
|
|
@@ -66,9 +187,10 @@ export function subscribeToConicalRoofWallClicks(options) {
|
|
|
66
187
|
export function resolveRoofFootprintElevation(targetLevelId, target, nodes) {
|
|
67
188
|
const completeNodes = nodes;
|
|
68
189
|
const elevations = getLevelElevations(completeNodes);
|
|
190
|
+
// A railing is a guard round a deck or a porch, not a wall: the roof never sits on its top.
|
|
69
191
|
const tops = target.wallIds.flatMap((id) => {
|
|
70
192
|
const wall = nodes[id];
|
|
71
|
-
return wall?.type === 'wall'
|
|
193
|
+
return wall?.type === 'wall' && !isRailingWall(wall)
|
|
72
194
|
? [resolveRoofWallTopElevation(targetLevelId, wall, completeNodes, elevations)]
|
|
73
195
|
: [];
|
|
74
196
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"roof-materials.d.ts","sourceRoot":"","sources":["../../src/roof/roof-materials.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,WAAW,EAGhB,KAAK,aAAa,EAEnB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAM9B,wBAAgB,gBAAgB,CAC9B,OAAO,GAAE,aAA0B,EACnC,QAAQ,UAAO,EACf,WAAW,GAAE,WAAoB,GAChC,KAAK,CAAC,QAAQ,EAAE,
|
|
1
|
+
{"version":3,"file":"roof-materials.d.ts","sourceRoot":"","sources":["../../src/roof/roof-materials.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,WAAW,EAGhB,KAAK,aAAa,EAEnB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAM9B,wBAAgB,gBAAgB,CAC9B,OAAO,GAAE,aAA0B,EACnC,QAAQ,UAAO,EACf,WAAW,GAAE,WAAoB,GAChC,KAAK,CAAC,QAAQ,EAAE,CA4BlB;AAKD,wBAAgB,qBAAqB,CAAC,OAAO,GAAE,aAA0B,GAAG,KAAK,CAAC,QAAQ,EAAE,CAe3F"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createDefaultMaterial, createSurfaceRoleMaterial, resolveSlotDefaultMaterial, } from '@pascal-app/viewer';
|
|
2
2
|
import * as THREE from 'three';
|
|
3
3
|
// Production materials — match the rest of the scene (white walls, light-gray slabs).
|
|
4
|
-
// Indices: 0 = Wall/Trim, 1 = Deck, 2 = Interior, 3 = Shingle
|
|
4
|
+
// Indices: 0 = Wall/Trim, 1 = Deck, 2 = Interior, 3 = Shingle, 4 = Heel band, 5/6 = Gables
|
|
5
5
|
const roofMaterialsCache = new Map();
|
|
6
6
|
export function getRoofMaterials(shading = 'rendered', textures = true, colorPreset = 'clay') {
|
|
7
7
|
const cacheKey = `${shading}-${textures}-${colorPreset}`;
|
|
@@ -16,12 +16,18 @@ export function getRoofMaterials(shading = 'rendered', textures = true, colorPre
|
|
|
16
16
|
resolveSlotDefaultMaterial('library:preset-softwhite', shading), // 1: Deck
|
|
17
17
|
resolveSlotDefaultMaterial('library:preset-softwhite', shading), // 2: Interior
|
|
18
18
|
resolveSlotDefaultMaterial('library:roof-terracottatiles', shading), // 3: Shingle
|
|
19
|
+
resolveSlotDefaultMaterial('library:concrete-drywall', shading), // 4: Heel band
|
|
20
|
+
resolveSlotDefaultMaterial('library:concrete-drywall', shading), // 5: Left gable
|
|
21
|
+
resolveSlotDefaultMaterial('library:concrete-drywall', shading), // 6: Right gable
|
|
19
22
|
]
|
|
20
23
|
: [
|
|
21
24
|
createSurfaceRoleMaterial('roof', colorPreset),
|
|
22
25
|
createSurfaceRoleMaterial('ceiling', colorPreset),
|
|
23
26
|
createSurfaceRoleMaterial('ceiling', colorPreset),
|
|
24
27
|
createSurfaceRoleMaterial('roof', colorPreset),
|
|
28
|
+
createSurfaceRoleMaterial('wall', colorPreset),
|
|
29
|
+
createSurfaceRoleMaterial('roof', colorPreset),
|
|
30
|
+
createSurfaceRoleMaterial('roof', colorPreset),
|
|
25
31
|
];
|
|
26
32
|
roofMaterialsCache.set(cacheKey, materials);
|
|
27
33
|
return materials;
|
|
@@ -37,6 +43,9 @@ export function getRoofDebugMaterials(shading = 'rendered') {
|
|
|
37
43
|
createDefaultMaterial('#000000', 0.9, shading, THREE.FrontSide), // 1: Deck
|
|
38
44
|
createDefaultMaterial('#dddddd', 0.9, shading, THREE.DoubleSide), // 2: Interior
|
|
39
45
|
createDefaultMaterial('#4ade80', 0.9, shading, THREE.FrontSide), // 3: Shingle
|
|
46
|
+
createDefaultMaterial('#f5d0a9', 0.8, shading, THREE.DoubleSide), // 4: Heel band
|
|
47
|
+
createDefaultMaterial('#93c5fd', 0.8, shading, THREE.DoubleSide), // 5: Left gable
|
|
48
|
+
createDefaultMaterial('#c4b5fd', 0.8, shading, THREE.DoubleSide), // 6: Right gable
|
|
40
49
|
];
|
|
41
50
|
roofDebugMaterialsCache.set(shading, materials);
|
|
42
51
|
return materials;
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
export type RoofPlacementMode = 'auto' | 'ground' | 'roof';
|
|
2
2
|
type RoofPlacementModeState = {
|
|
3
|
-
conical: boolean;
|
|
4
3
|
mode: RoofPlacementMode;
|
|
5
4
|
cycleMode: () => void;
|
|
6
|
-
setConical: (conical: boolean) => void;
|
|
7
5
|
};
|
|
8
6
|
declare const useRoofPlacementMode: import("zustand").UseBoundStore<import("zustand").StoreApi<RoofPlacementModeState>>;
|
|
9
7
|
declare const subscribeToRoofKind: (onChange: () => void) => () => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"roof-placement-mode.d.ts","sourceRoot":"","sources":["../../src/roof/roof-placement-mode.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"roof-placement-mode.d.ts","sourceRoot":"","sources":["../../src/roof/roof-placement-mode.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAA;AAI1D,KAAK,sBAAsB,GAAG;IAC5B,IAAI,EAAE,iBAAiB,CAAA;IACvB,SAAS,EAAE,MAAM,IAAI,CAAA;CACtB,CAAA;AAED,QAAA,MAAM,oBAAoB,qFAMvB,CAAA;AAOH,QAAA,MAAM,mBAAmB,aAAc,MAAM,IAAI,eAG7C,CAAA;AAEJ,eAAO,MAAM,6BAA6B;IACxC,SAAS;IACT,KAAK;CACN,CAAA;AAED,eAAO,MAAM,8BAA8B;IACzC,SAAS;IACT,KAAK;CACN,CAAA;eAEc,oBAAoB"}
|
|
@@ -1,24 +1,26 @@
|
|
|
1
|
+
import { useEditor } from '@pascal-app/editor';
|
|
1
2
|
import { create } from 'zustand';
|
|
2
3
|
const MODES = ['auto', 'ground', 'roof'];
|
|
3
4
|
const useRoofPlacementMode = create((set, get) => ({
|
|
4
|
-
conical: false,
|
|
5
5
|
mode: 'auto',
|
|
6
6
|
cycleMode: () => {
|
|
7
7
|
const current = MODES.indexOf(get().mode);
|
|
8
8
|
set({ mode: MODES[(current + 1) % MODES.length] ?? 'auto' });
|
|
9
9
|
},
|
|
10
|
-
setConical: (conical) => set({ conical }),
|
|
11
10
|
}));
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
// Read from the roof type the tool is armed with, not from whichever roof tool mounted: in a
|
|
12
|
+
// 2D-only session the 3D tool never mounts, and the HUD showed a cone the standard rows.
|
|
13
|
+
const isConicalRoof = (state) => state.toolDefaults.roof?.roofType === 'conical';
|
|
14
|
+
const subscribeToRoofKind = (onChange) => useEditor.subscribe((state, previous) => {
|
|
15
|
+
if (isConicalRoof(state) !== isConicalRoof(previous))
|
|
14
16
|
onChange();
|
|
15
17
|
});
|
|
16
18
|
export const conicalRoofToolHintVisibility = {
|
|
17
19
|
subscribe: subscribeToRoofKind,
|
|
18
|
-
value: () =>
|
|
20
|
+
value: () => isConicalRoof(useEditor.getState()),
|
|
19
21
|
};
|
|
20
22
|
export const standardRoofToolHintVisibility = {
|
|
21
23
|
subscribe: subscribeToRoofKind,
|
|
22
|
-
value: () => !
|
|
24
|
+
value: () => !isConicalRoof(useEditor.getState()),
|
|
23
25
|
};
|
|
24
26
|
export default useRoofPlacementMode;
|