@pascal-app/editor 1.0.7 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +9 -15
- package/src/components/editor/action-menu-button.tsx +1 -1
- package/src/components/editor/alignment-3d-guide-layer.tsx +1 -1
- package/src/components/editor/custom-camera-controls.tsx +101 -45
- package/src/components/editor/duplicate-node.ts +2 -1
- package/src/components/editor/editor-layout-v2.tsx +1 -1
- package/src/components/editor/elevation-3d-guide-layer.tsx +1 -1
- package/src/components/editor/first-person-controls.tsx +20 -1983
- package/src/components/editor/fit-scene-framing.test.ts +318 -0
- package/src/components/editor/fit-scene-framing.ts +142 -0
- package/src/components/editor/floating-action-menu.tsx +5 -3
- package/src/components/editor/floating-building-action-menu.tsx +1 -1
- package/src/components/editor/floor-openings-overlay.tsx +1 -1
- package/src/components/editor/floor-region-controls.tsx +8 -4
- package/src/components/editor/floorplan-navigation-presentation.test.ts +0 -40
- package/src/components/editor/floorplan-navigation-presentation.ts +0 -66
- package/src/components/editor/floorplan-panel.tsx +199 -30
- package/src/components/editor/floorplan-wall-typing-keys.test.tsx +152 -0
- package/src/components/editor/floorplan-wall-typing-keys.ts +79 -0
- package/src/components/editor/follow-pascal.test.tsx +1 -2
- package/src/components/editor/follow-pascal.tsx +1 -1
- package/src/components/editor/footprint-height-handle.tsx +2 -2
- package/src/components/editor/group-actions.ts +1 -2
- package/src/components/editor/group-floating-action-menu.tsx +1 -1
- package/src/components/editor/group-move-3d.ts +1 -2
- package/src/components/editor/group-rotate-handle.tsx +1 -2
- package/src/components/editor/group-transform-shared.ts +3 -1
- package/src/components/editor/handles/use-handle-drag.ts +1 -2
- package/src/components/editor/index.tsx +43 -13
- package/src/components/editor/inspector-extension-actions.tsx +1 -1
- package/src/components/editor/measurement-pill.tsx +1 -1
- package/src/components/editor/node-arrow-handles.tsx +2 -2
- package/src/components/editor/open-wall-ends-3d-layer.tsx +2 -3
- package/src/components/editor/open-wall-ends-hint.tsx +1 -1
- package/src/components/editor/opening-guides-3d-layer.tsx +1 -1
- package/src/components/editor/quick-measurement-card.tsx +1 -1
- package/src/components/editor/room-controls.tsx +10 -6
- package/src/components/editor/room-handles-2d.tsx +3 -3
- package/src/components/editor/room-handles.tsx +4 -5
- package/src/components/editor/room-highlight.tsx +6 -105
- package/src/components/editor/room-labels.test.ts +8 -822
- package/src/components/editor/room-labels.tsx +41 -1670
- package/src/components/editor/room-webgpu-materials.test.ts +1 -1
- package/src/components/editor/selection-manager.tsx +5 -3
- package/src/components/editor/site-edge-labels.tsx +7 -3
- package/src/components/editor/snapshot-capture-overlay.tsx +2 -5
- package/src/components/editor/use-floorplan-background-placement.ts +2 -1
- package/src/components/editor/views/plugins-view.tsx +1 -1
- package/src/components/editor/views/view-bar.tsx +9 -9
- package/src/components/editor/wall-measurement-label.tsx +31 -15
- package/src/components/editor/wall-move-side-handles.tsx +11 -7
- package/src/components/editor/wall-pull-grip.tsx +2 -2
- package/src/components/editor/wall-region-handles.tsx +2 -2
- package/src/components/editor/wall-snap-beacon-layer.tsx +53 -32
- package/src/components/editor-2d/floorplan-group-move.tsx +3 -4
- package/src/components/editor-2d/floorplan-measurement-tool-layer.tsx +13 -13
- package/src/components/editor-2d/floorplan-open-wall-ends-layer.tsx +2 -3
- package/src/components/editor-2d/floorplan-registry-action-menu.tsx +2 -1
- package/src/components/editor-2d/floorplan-registry-move-overlay.tsx +23 -6
- package/src/components/editor-2d/renderers/floorplan-annotation-layout.test.ts +0 -37
- package/src/components/editor-2d/renderers/floorplan-annotation-layout.ts +0 -30
- package/src/components/editor-2d/renderers/floorplan-dimension-edit-overlay.tsx +13 -3
- package/src/components/editor-2d/renderers/floorplan-draft-measurement.tsx +7 -1
- package/src/components/editor-2d/renderers/floorplan-placement-preview-layer.tsx +14 -3
- package/src/components/editor-2d/renderers/floorplan-placement-typing-hud.test.tsx +35 -0
- package/src/components/editor-2d/renderers/floorplan-placement-typing-hud.tsx +65 -0
- package/src/components/editor-2d/renderers/floorplan-registry-layer.test.ts +30 -10
- package/src/components/editor-2d/renderers/floorplan-registry-layer.tsx +39 -35
- package/src/components/systems/roof/roof-edit-system.test.tsx +15 -1
- package/src/components/systems/roof/roof-edit-system.tsx +33 -21
- package/src/components/tools/distribution/distribution-run-tool.test.tsx +371 -3
- package/src/components/tools/distribution/distribution-run-tool.tsx +151 -33
- package/src/components/tools/item/move-tool.tsx +1 -6
- package/src/components/tools/item/placement-history.test.tsx +1 -1
- package/src/components/tools/item/use-placement-coordinator.tsx +3 -4
- package/src/components/tools/paint-region/wall-paint-region-tool.tsx +7 -3
- package/src/components/tools/registry/move-registry-node-tool.test.ts +42 -1
- package/src/components/tools/registry/move-registry-node-tool.tsx +39 -16
- package/src/components/tools/shared/cursor-sphere.tsx +1 -1
- package/src/components/tools/shared/draft-measurement-label.tsx +1 -1
- package/src/components/tools/shared/placement-box.tsx +2 -6
- package/src/components/tools/shared/placement-coordinate-input.tsx +94 -0
- package/src/components/tools/shared/placement-dimension-guides.tsx +1 -1
- package/src/components/tools/shared/segment-angle.ts +0 -4
- package/src/components/tools/site/terrain-brush-cursor.tsx +1 -1
- package/src/components/tools/tool-manager.tsx +1 -24
- package/src/components/tools/wall/wall-typed-entry.test.ts +99 -0
- package/src/components/tools/wall/wall-typed-entry.ts +70 -0
- package/src/components/ui/action-menu/camera-actions.tsx +2 -2
- package/src/components/ui/action-menu/control-modes.tsx +1 -1
- package/src/components/ui/action-menu/follow-pascal-pill.tsx +1 -1
- package/src/components/ui/action-menu/index.tsx +3 -3
- package/src/components/ui/action-menu/measurement-control.tsx +3 -3
- package/src/components/ui/action-menu/placement.ts +0 -18
- package/src/components/ui/action-menu/point-ask-button.tsx +1 -1
- package/src/components/ui/action-menu/view-toggles.tsx +5 -5
- package/src/components/ui/controls/finish-swatch.tsx +1 -1
- package/src/components/ui/controls/material-paint-panel.tsx +2 -2
- package/src/components/ui/controls/scene-material-list.tsx +2 -2
- package/src/components/ui/controls/select-control.tsx +1 -1
- package/src/components/ui/controls/slider-control.tsx +18 -6
- package/src/components/ui/controls/terrain-sculpt-panel.tsx +1 -1
- package/src/components/ui/controls/tool-options-panel.tsx +74 -44
- package/src/components/ui/floating-level-selector.tsx +3 -3
- package/src/components/ui/helpers/contextual-helper-panel.tsx +1 -1
- package/src/components/ui/helpers/helper-manager.test.tsx +54 -1
- package/src/components/ui/helpers/helper-manager.tsx +55 -1
- package/src/components/ui/level-duplicate-dialog.tsx +1 -1
- package/src/components/ui/panels/collections/collections-popover.tsx +2 -2
- package/src/components/ui/panels/floor-foundation-panel.tsx +3 -3
- package/src/components/ui/panels/floor-opening-panel.tsx +5 -5
- package/src/components/ui/panels/mobile-selection-bar.tsx +28 -24
- package/src/components/ui/panels/multi-height-mode.tsx +3 -3
- package/src/components/ui/panels/multi-selection-panel.tsx +1 -1
- package/src/components/ui/panels/node-display.ts +1 -1
- package/src/components/ui/panels/panel-manager.tsx +5 -3
- package/src/components/ui/panels/panel-wrapper.tsx +42 -19
- package/src/components/ui/panels/parametric-inspector.tsx +1 -1
- package/src/components/ui/panels/room-construction-rows.tsx +7 -7
- package/src/components/ui/panels/room-name-options.ts +1 -5
- package/src/components/ui/panels/room-openings-field.tsx +1 -1
- package/src/components/ui/panels/room-panel.tsx +7 -9
- package/src/components/ui/primitives/color-dot.tsx +2 -2
- package/src/components/ui/primitives/opacity-control.tsx +2 -2
- package/src/components/ui/primitives/sidebar.tsx +3 -3
- package/src/components/ui/right-stack.test.ts +13 -6
- package/src/components/ui/right-stack.tsx +22 -11
- package/src/components/ui/sidebar/icon-rail.tsx +1 -1
- package/src/components/ui/sidebar/panels/items-panel/function-tree-panel.tsx +1 -1
- package/src/components/ui/sidebar/panels/settings-panel/audio-settings-dialog.tsx +2 -2
- package/src/components/ui/sidebar/panels/settings-panel/construction-animation-setting.tsx +1 -1
- package/src/components/ui/sidebar/panels/settings-panel/index.tsx +2 -2
- package/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +1 -1
- package/src/components/ui/sidebar/panels/settings-panel/load-build-dialog.tsx +2 -6
- package/src/components/ui/sidebar/panels/settings-panel/print-export-button.tsx +1 -1
- package/src/components/ui/sidebar/panels/site-panel/building-tree-node.tsx +1 -1
- package/src/components/ui/sidebar/panels/site-panel/ceiling-tree-node.tsx +1 -1
- package/src/components/ui/sidebar/panels/site-panel/index.tsx +3 -10
- package/src/components/ui/sidebar/panels/site-panel/inline-rename-input.tsx +1 -1
- package/src/components/ui/sidebar/panels/site-panel/level-tree-node.tsx +1 -1
- package/src/components/ui/sidebar/panels/site-panel/roof-tree-node.tsx +46 -7
- package/src/components/ui/sidebar/panels/site-panel/slab-tree-node.tsx +1 -1
- package/src/components/ui/sidebar/panels/site-panel/tree-node-actions.tsx +1 -1
- package/src/components/ui/sidebar/panels/site-panel/tree-node-drag.tsx +14 -5
- package/src/components/ui/sidebar/panels/site-panel/unit-tree-node.tsx +2 -2
- package/src/components/ui/sidebar/panels/site-panel/zone-tree-node.tsx +1 -1
- package/src/components/ui/sidebar/panels/zone-panel/index.tsx +3 -3
- package/src/components/ui/sidebar/tab-bar.tsx +1 -1
- package/src/components/ui/wall-type/wall-type-editor-dialog.tsx +2 -2
- package/src/components/ui/wall-type/wall-type-menu.tsx +1 -1
- package/src/components/viewer-overlay.tsx +1 -2
- package/src/hooks/use-auto-frame.ts +1 -2
- package/src/hooks/use-keyboard.ts +1 -2
- package/src/hooks/use-selected-room.ts +5 -7
- package/src/i18n/floor-footprint-name.ts +1 -1
- package/src/i18n/locales/en/messages.po +1036 -306
- package/src/i18n/locales/en/messages.ts +1 -1
- package/src/i18n/locales/en-XA/messages.ts +1 -1
- package/src/i18n/locales/es/messages.po +2267 -439
- package/src/i18n/locales/fr/messages.po +2267 -439
- package/src/i18n/locales/ja/messages.po +2267 -439
- package/src/i18n/locales/zh-CN/messages.po +2267 -439
- package/src/i18n/locales.test.ts +1 -1
- package/src/index.tsx +183 -178
- package/src/lib/below-grade.test.tsx +4 -4
- package/src/lib/camera-facing.test.ts +1 -1
- package/src/lib/camera-facing.ts +2 -3
- package/src/lib/contextual-help.ts +6 -0
- package/src/lib/editor-level-display.ts +1 -1
- package/src/lib/elevation-guides.ts +21 -6
- package/src/lib/elevator-support.ts +1 -72
- package/src/lib/floor-footprints.test.ts +3 -3
- package/src/lib/floor-footprints.ts +1 -9
- package/src/lib/floor-foundation-support.test.ts +8 -3
- package/src/lib/floor-opening-draft.ts +2 -2
- package/src/lib/floor-region-session.ts +1 -1
- package/src/lib/floorplan/annotation-visibility.test.ts +1 -1
- package/src/lib/floorplan/annotation-visibility.ts +1 -1
- package/src/lib/floorplan/floorplan-export.test.ts +1 -1
- package/src/lib/floorplan/floorplan-export.tsx +8 -11
- package/src/lib/floorplan/floorplan-extension.ts +4 -157
- package/src/lib/floorplan/floorplan-mode.ts +2 -1
- package/src/lib/floorplan/floorplan-pdfkit-renderer.test.ts +1 -1
- package/src/lib/floorplan/floorplan-pdfkit-renderer.ts +8 -6
- package/src/lib/floorplan/floorplan-plugin-install.test.tsx +3 -4
- package/src/lib/floorplan/geometry.ts +2 -112
- package/src/lib/floorplan/index.ts +0 -9
- package/src/lib/floorplan/items.ts +2 -1
- package/src/lib/floorplan/open-wall-ends.ts +2 -1
- package/src/lib/floorplan/schedules.ts +6 -3
- package/src/lib/floorplan/sheet-export.ts +7 -3
- package/src/lib/floorplan/site-plan/site-parts.ts +7 -1
- package/src/lib/floorplan/site-plan/site-plan-layer.tsx +1 -1
- package/src/lib/follow-pascal-presentation.ts +1 -1
- package/src/lib/gesture-lifecycle.ts +3 -1
- package/src/lib/glb-export.ts +1 -1
- package/src/lib/interaction/scope.ts +1 -0
- package/src/lib/layer-thickness.ts +1 -1
- package/src/lib/level-selection.test.ts +18 -2
- package/src/lib/level-selection.ts +31 -8
- package/src/lib/linear-display.ts +1 -1
- package/src/lib/live-gesture-round-trip.test.ts +1 -1
- package/src/lib/material-paint.ts +1 -1
- package/src/lib/measurement-label.test.ts +1 -1
- package/src/lib/measurements.test.ts +7 -5
- package/src/lib/mezzanine-selection.test.ts +1 -1
- package/src/lib/node-action-movement.test.tsx +115 -0
- package/src/lib/node-action-movement.ts +2 -0
- package/src/lib/paint-region-mode.ts +1 -1
- package/src/lib/placement-metadata.ts +4 -0
- package/src/lib/point-ask/describe-target.ts +6 -8
- package/src/lib/point-ask/region.ts +1 -1
- package/src/lib/point-ask/session.ts +1 -2
- package/src/lib/print-shell-compiler.ts +12 -1
- package/src/lib/print-wall-solids.test.ts +11 -0
- package/src/lib/print-wall-solids.ts +9 -0
- package/src/lib/roof-duplication.test.ts +100 -0
- package/src/lib/roof-duplication.ts +30 -5
- package/src/lib/room-built-on.test.ts +2 -5
- package/src/lib/room-built-on.ts +1 -15
- package/src/lib/room-construction-commands.ts +3 -2
- package/src/lib/room-controls-phase6.test.ts +1 -1
- package/src/lib/room-handle-drag.ts +8 -37
- package/src/lib/room-name-catalog.test.ts +2 -1
- package/src/lib/room-name-messages.test.ts +2 -1
- package/src/lib/room-name-messages.ts +1 -118
- package/src/lib/room-name-storage.test.ts +2 -1
- package/src/lib/room-push-dimensions.test.ts +1 -1
- package/src/lib/room-selection-commands.ts +2 -2
- package/src/lib/room-selection.test.ts +6 -6
- package/src/lib/room-transform-session.ts +1 -2
- package/src/lib/room-zone-routing.ts +2 -2
- package/src/lib/scene-clipboard.ts +2 -1
- package/src/lib/selection-routing.test.ts +0 -28
- package/src/lib/selection-routing.ts +1 -40
- package/src/lib/sfx-bus.ts +8 -32
- package/src/lib/sfx-player.test.ts +72 -1
- package/src/lib/sfx-player.ts +49 -337
- package/src/lib/snapping-mode.test.ts +23 -1
- package/src/lib/viewer-selection.test.ts +38 -10
- package/src/lib/wall-pull.test.ts +1 -1
- package/src/lib/wall-pull.ts +1 -27
- package/src/lib/wall-region-list.ts +3 -1
- package/src/lib/window-interaction.test.ts +4 -2
- package/src/store/use-editor.tsx +22 -26
- package/src/store/use-floorplan-annotation-visibility.ts +5 -5
- package/src/store/use-placement-typing.test.ts +165 -0
- package/src/store/use-placement-typing.ts +186 -0
- package/src/store/use-wall-region-handles-selection.ts +1 -2
- package/src/components/editor/__bench__/room-label-placement.bench.ts +0 -108
- package/src/components/editor/first-person/build-collider-world.test.ts +0 -596
- package/src/components/editor/first-person/build-collider-world.ts +0 -549
- package/src/components/editor/first-person/ground-holes.test.ts +0 -128
- package/src/components/editor/first-person/ground-holes.ts +0 -130
- package/src/components/editor/first-person/mechanism-targets.test.ts +0 -162
- package/src/components/editor/first-person/mechanism-targets.ts +0 -88
- package/src/components/editor/first-person/terrain-collider.test.ts +0 -132
- package/src/components/editor/first-person/terrain-collider.ts +0 -212
- package/src/components/editor/floorplan-camera-sync.test.ts +0 -249
- package/src/components/editor/floorplan-camera-sync.ts +0 -213
- package/src/components/editor/localized-html.tsx +0 -22
- package/src/components/editor-2d/renderers/floorplan-dimension-renderer.test.tsx +0 -236
- package/src/components/editor-2d/renderers/floorplan-dimension-renderer.tsx +0 -708
- package/src/components/editor-2d/renderers/floorplan-geometry-renderer.test.tsx +0 -385
- package/src/components/editor-2d/renderers/floorplan-geometry-renderer.tsx +0 -670
- package/src/components/editor-2d/renderers/floorplan-label-angle.test.ts +0 -89
- package/src/components/editor-2d/renderers/floorplan-label-angle.ts +0 -106
- package/src/components/editor-2d/svg-paths.ts +0 -124
- package/src/components/tools/elevator/elevator-defaults.ts +0 -8
- package/src/components/tools/elevator/elevator-tool.tsx +0 -372
- package/src/components/tools/elevator/move-elevator-tool.tsx +0 -262
- package/src/components/ui/action-menu/action-button.tsx +0 -89
- package/src/components/ui/action-menu/follow-pascal-toggle.tsx +0 -42
- package/src/components/ui/primitives/button.tsx +0 -69
- package/src/components/ui/primitives/dropdown-menu.tsx +0 -232
- package/src/components/ui/primitives/popover.tsx +0 -42
- package/src/components/ui/primitives/switch.tsx +0 -29
- package/src/components/ui/primitives/tooltip.tsx +0 -57
- package/src/components/ui/scene-loader.tsx +0 -73
- package/src/components/viewer/floorplan-compass-button.tsx +0 -67
- package/src/components/viewer/floorplan-preview-geometry.test.ts +0 -107
- package/src/components/viewer/floorplan-preview-geometry.ts +0 -281
- package/src/components/viewer/floorplan-preview-navigation.test.ts +0 -43
- package/src/components/viewer/floorplan-preview-navigation.ts +0 -62
- package/src/components/viewer/floorplan-preview-visibility.test.ts +0 -35
- package/src/components/viewer/floorplan-preview-visibility.ts +0 -19
- package/src/components/viewer/floorplan-preview.tsx +0 -1065
- package/src/components/viewer/render-settings-menu.tsx +0 -294
- package/src/components/viewer/sky-control.tsx +0 -710
- package/src/components/viewer/use-viewer-camera-navigation-sync.ts +0 -140
- package/src/components/viewer/use-viewer-ui-sounds.test.ts +0 -15
- package/src/components/viewer/use-viewer-ui-sounds.ts +0 -46
- package/src/components/viewer/viewer-controls-bar.tsx +0 -496
- package/src/components/viewer/viewer-hover-label.tsx +0 -42
- package/src/components/viewer/viewer-rooms.tsx +0 -248
- package/src/components/viewer/viewer-scene-header.tsx +0 -286
- package/src/components/viewer/viewer-selection-manager.tsx +0 -124
- package/src/components/viewer/viewer-stage-modes.test.ts +0 -38
- package/src/components/viewer/viewer-stage-modes.ts +0 -49
- package/src/components/viewer/viewer-stage-switcher.tsx +0 -97
- package/src/components/viewer/viewer-stage.test.tsx +0 -47
- package/src/components/viewer/viewer-stage.tsx +0 -221
- package/src/components/walkthrough-hud.tsx +0 -193
- package/src/hooks/use-mobile.ts +0 -19
- package/src/i18n/level-name.ts +0 -39
- package/src/i18n/scene-theme-name.ts +0 -16
- package/src/lib/below-grade.ts +0 -133
- package/src/lib/camera-pose.test.ts +0 -237
- package/src/lib/camera-pose.ts +0 -172
- package/src/lib/door-interaction.ts +0 -102
- package/src/lib/floorplan/floorplan-extension.test.ts +0 -42
- package/src/lib/floorplan/floorplan-readonly.test.ts +0 -47
- package/src/lib/floorplan/floorplan-readonly.ts +0 -95
- package/src/lib/floorplan/marks.test.ts +0 -213
- package/src/lib/floorplan/marks.ts +0 -238
- package/src/lib/measurement-label.ts +0 -68
- package/src/lib/measurements.ts +0 -225
- package/src/lib/node-display-label.ts +0 -37
- package/src/lib/room-assembly-overlay.test.ts +0 -275
- package/src/lib/room-assembly-overlay.ts +0 -265
- package/src/lib/room-selection.ts +0 -417
- package/src/lib/scene-bounds.test.ts +0 -183
- package/src/lib/scene-bounds.ts +0 -169
- package/src/lib/typing-target.ts +0 -9
- package/src/lib/viewer-selection.ts +0 -595
- package/src/lib/window-interaction.ts +0 -142
- package/src/lib/zone-content.ts +0 -133
- package/src/store/camera-pose-store.test.ts +0 -29
- package/src/store/camera-pose-store.ts +0 -27
- package/src/store/navigation-sync-pose-store.test.ts +0 -34
- package/src/store/navigation-sync-pose-store.ts +0 -27
- package/src/store/use-audio.test.ts +0 -146
- package/src/store/use-audio.tsx +0 -169
- package/src/store/use-first-person-hud.ts +0 -40
- package/src/store/use-follow-pascal.test.ts +0 -62
- package/src/store/use-follow-pascal.ts +0 -53
|
@@ -1,25 +1,23 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type AnyNode,
|
|
3
3
|
area,
|
|
4
|
+
formatLinearMeasurement,
|
|
5
|
+
getAreaUnitLabel,
|
|
4
6
|
getScaledDimensions,
|
|
5
7
|
getWallCurveLength,
|
|
6
8
|
getWallEffectiveHeightForNodes,
|
|
7
9
|
getWallThickness,
|
|
8
10
|
type ItemNode,
|
|
11
|
+
type LinearUnit,
|
|
12
|
+
type MetricNotation,
|
|
9
13
|
resolveLevelId,
|
|
10
14
|
type SlabNode,
|
|
11
15
|
type StairNode,
|
|
16
|
+
squareMetersToAreaUnit,
|
|
12
17
|
type WallNode,
|
|
13
18
|
type WindowNode,
|
|
14
19
|
type ZoneNode,
|
|
15
20
|
} from '@pascal-app/core'
|
|
16
|
-
import {
|
|
17
|
-
formatLinearMeasurement,
|
|
18
|
-
getAreaUnitLabel,
|
|
19
|
-
type LinearUnit,
|
|
20
|
-
type MetricNotation,
|
|
21
|
-
squareMetersToAreaUnit,
|
|
22
|
-
} from '../measurements'
|
|
23
21
|
import type { PointKind, PointTarget } from './types'
|
|
24
22
|
|
|
25
23
|
// Point and ask names what the finger is on (the owner, 8 October): the label chip and the
|
|
@@ -115,7 +113,7 @@ const roomOfWall = (nodes: Nodes, levelId: string, wallId: string) =>
|
|
|
115
113
|
|
|
116
114
|
function wallHeight(wall: WallNode, nodes: Nodes): number {
|
|
117
115
|
try {
|
|
118
|
-
const height = getWallEffectiveHeightForNodes(wall, nodes as Record<string, AnyNode
|
|
116
|
+
const height = getWallEffectiveHeightForNodes(wall, nodes as Record<string, AnyNode>, 0)
|
|
119
117
|
if (Number.isFinite(height) && height > 0) return height
|
|
120
118
|
} catch {
|
|
121
119
|
// No slab election to consult in a bare scene: the wall's own height stands.
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
} from '@pascal-app/core'
|
|
19
19
|
import { sceneViewBounds, sceneViewPose } from '@pascal-app/core/agent-operations'
|
|
20
20
|
import { retractNodes, useViewer } from '@pascal-app/viewer'
|
|
21
|
+
import { cameraPoseStore, useFollowPascal } from '@pascal-app/viewer/ui'
|
|
21
22
|
import { type Object3D, Vector2, Vector3 } from 'three'
|
|
22
23
|
import {
|
|
23
24
|
resolveRoofSegmentSelectionTarget,
|
|
@@ -25,9 +26,7 @@ import {
|
|
|
25
26
|
} from '../../components/editor/selection-manager'
|
|
26
27
|
import { getEditorThreeContext } from '../../components/editor/three-context-bridge'
|
|
27
28
|
import { resolveEditorRoomHit } from '../../hooks/use-selected-room'
|
|
28
|
-
import { cameraPoseStore } from '../../store/camera-pose-store'
|
|
29
29
|
import useEditor, { getActiveContinuationContext } from '../../store/use-editor'
|
|
30
|
-
import useFollowPascal from '../../store/use-follow-pascal'
|
|
31
30
|
import useInteractionScope from '../../store/use-interaction-scope'
|
|
32
31
|
import {
|
|
33
32
|
type BubbleTarget,
|
|
@@ -148,8 +148,19 @@ function preparedWallHeight(
|
|
|
148
148
|
},
|
|
149
149
|
}
|
|
150
150
|
}
|
|
151
|
+
if (Math.abs(node.endHeightOffset ?? 0) > 1e-5) {
|
|
152
|
+
return {
|
|
153
|
+
height: null,
|
|
154
|
+
diagnostic: {
|
|
155
|
+
severity: 'error',
|
|
156
|
+
code: 'unsupported_wall_print_slope',
|
|
157
|
+
message: `Wall ${node.id} has a sloped top that does not yet have a canonical printable solid.`,
|
|
158
|
+
nodeIds: [node.id],
|
|
159
|
+
},
|
|
160
|
+
}
|
|
161
|
+
}
|
|
151
162
|
|
|
152
|
-
const height = getWallEffectiveHeightForNodes(node, nodes)
|
|
163
|
+
const height = getWallEffectiveHeightForNodes(node, nodes, 0)
|
|
153
164
|
if (!Number.isFinite(height) || height <= 1e-7) {
|
|
154
165
|
return {
|
|
155
166
|
height: null,
|
|
@@ -155,6 +155,11 @@ describe('buildPrintableWallSolids', () => {
|
|
|
155
155
|
{ effectiveHeight: 2.5 },
|
|
156
156
|
{ [shaped.id]: shaped },
|
|
157
157
|
)
|
|
158
|
+
const sloped = buildPrintableWallSolids(
|
|
159
|
+
{ ...wall, endHeightOffset: 1.0 },
|
|
160
|
+
{ effectiveHeight: 2.5 },
|
|
161
|
+
{ [shaped.id]: shaped },
|
|
162
|
+
)
|
|
158
163
|
const terrain = buildPrintableWallSolids(
|
|
159
164
|
{ ...wall, children: [], fillToTerrain: true },
|
|
160
165
|
{ effectiveHeight: 2.5 },
|
|
@@ -172,6 +177,12 @@ describe('buildPrintableWallSolids', () => {
|
|
|
172
177
|
diagnostics: [expect.objectContaining({ code: 'unsupported_wall_print_curve' })],
|
|
173
178
|
}),
|
|
174
179
|
)
|
|
180
|
+
expect(sloped).toEqual(
|
|
181
|
+
expect.objectContaining({
|
|
182
|
+
status: 'blocked',
|
|
183
|
+
diagnostics: [expect.objectContaining({ code: 'unsupported_wall_print_slope' })],
|
|
184
|
+
}),
|
|
185
|
+
)
|
|
175
186
|
expect(terrain).toEqual(
|
|
176
187
|
expect.objectContaining({
|
|
177
188
|
status: 'blocked',
|
|
@@ -27,6 +27,7 @@ export type PrintWallSolidDiagnostic = {
|
|
|
27
27
|
code:
|
|
28
28
|
| 'invalid_wall_print_dimensions'
|
|
29
29
|
| 'unsupported_wall_print_curve'
|
|
30
|
+
| 'unsupported_wall_print_slope'
|
|
30
31
|
| 'unsupported_wall_print_terrain'
|
|
31
32
|
| 'unsupported_wall_print_opening_shape'
|
|
32
33
|
| 'invalid_wall_print_opening'
|
|
@@ -258,6 +259,14 @@ export function buildPrintableWallSolids(
|
|
|
258
259
|
nodeIds: [node.id],
|
|
259
260
|
})
|
|
260
261
|
}
|
|
262
|
+
if (Math.abs(node.endHeightOffset ?? 0) > DIMENSION_EPSILON) {
|
|
263
|
+
diagnostics.push({
|
|
264
|
+
severity: 'error',
|
|
265
|
+
code: 'unsupported_wall_print_slope',
|
|
266
|
+
message: `Sloped wall ${node.id} does not yet have a canonical printable solid.`,
|
|
267
|
+
nodeIds: [node.id],
|
|
268
|
+
})
|
|
269
|
+
}
|
|
261
270
|
if (node.fillToTerrain) {
|
|
262
271
|
diagnostics.push({
|
|
263
272
|
severity: 'error',
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, test } from 'bun:test'
|
|
2
|
+
import {
|
|
3
|
+
type AnyNode,
|
|
4
|
+
type AnyNodeDefinition,
|
|
5
|
+
type AnyNodeId,
|
|
6
|
+
BaseNode,
|
|
7
|
+
LevelNode,
|
|
8
|
+
nodeRegistry,
|
|
9
|
+
nodeType,
|
|
10
|
+
objectId,
|
|
11
|
+
RoofNode,
|
|
12
|
+
RoofSegmentNode,
|
|
13
|
+
registerNode,
|
|
14
|
+
useScene,
|
|
15
|
+
} from '@pascal-app/core'
|
|
16
|
+
import { useViewer } from '@pascal-app/viewer'
|
|
17
|
+
import { z } from 'zod'
|
|
18
|
+
import { duplicateRoofSubtree } from './roof-duplication'
|
|
19
|
+
|
|
20
|
+
// A plugin's solved roof plane: a face of the roof holding it (`capabilities.roofs`).
|
|
21
|
+
const RoofPlane = BaseNode.extend({
|
|
22
|
+
id: objectId('roofplane'),
|
|
23
|
+
type: nodeType('test:roof-plane'),
|
|
24
|
+
polygon: z.array(z.tuple([z.number(), z.number()])),
|
|
25
|
+
})
|
|
26
|
+
const roofPlanes = {
|
|
27
|
+
kind: 'test:roof-plane',
|
|
28
|
+
schemaVersion: 1,
|
|
29
|
+
schema: RoofPlane,
|
|
30
|
+
category: 'structure',
|
|
31
|
+
defaults: () => ({}),
|
|
32
|
+
capabilities: {
|
|
33
|
+
roofs: {
|
|
34
|
+
outline: (node: AnyNode) => (node as unknown as z.infer<typeof RoofPlane>).polygon,
|
|
35
|
+
heightAt: () => 2.9,
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
} as unknown as AnyNodeDefinition
|
|
39
|
+
|
|
40
|
+
const LEVEL_ID = 'level_roof-duplicate' as AnyNodeId
|
|
41
|
+
const ROOF_ID = 'roof_original' as AnyNodeId
|
|
42
|
+
const SEGMENT_ID = 'rseg_original' as AnyNodeId
|
|
43
|
+
const PLANE_ID = 'roofplane_original' as AnyNodeId
|
|
44
|
+
const POLYGON: [number, number][] = [
|
|
45
|
+
[0, 0],
|
|
46
|
+
[8, 0],
|
|
47
|
+
[8, 3],
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
let restoreRegistry = () => {}
|
|
51
|
+
const previousScene = useScene.getState()
|
|
52
|
+
|
|
53
|
+
beforeEach(() => {
|
|
54
|
+
restoreRegistry = nodeRegistry._snapshot()
|
|
55
|
+
registerNode(roofPlanes)
|
|
56
|
+
useScene.setState({
|
|
57
|
+
nodes: {
|
|
58
|
+
[LEVEL_ID]: LevelNode.parse({ id: LEVEL_ID, children: [ROOF_ID] }) as AnyNode,
|
|
59
|
+
[ROOF_ID]: RoofNode.parse({
|
|
60
|
+
id: ROOF_ID,
|
|
61
|
+
parentId: LEVEL_ID,
|
|
62
|
+
children: [SEGMENT_ID, PLANE_ID],
|
|
63
|
+
}) as AnyNode,
|
|
64
|
+
[SEGMENT_ID]: RoofSegmentNode.parse({ id: SEGMENT_ID, parentId: ROOF_ID }) as AnyNode,
|
|
65
|
+
[PLANE_ID]: RoofPlane.parse({
|
|
66
|
+
id: PLANE_ID,
|
|
67
|
+
parentId: ROOF_ID,
|
|
68
|
+
polygon: POLYGON,
|
|
69
|
+
}) as unknown as AnyNode,
|
|
70
|
+
},
|
|
71
|
+
rootNodeIds: [LEVEL_ID],
|
|
72
|
+
collections: {},
|
|
73
|
+
dirtyNodes: new Set(),
|
|
74
|
+
} as never)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
afterEach(() => {
|
|
78
|
+
restoreRegistry()
|
|
79
|
+
useViewer.getState().setSelection({ selectedIds: [] })
|
|
80
|
+
useScene.setState(previousScene)
|
|
81
|
+
useScene.temporal.getState().clear()
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
describe('duplicateRoofSubtree', () => {
|
|
85
|
+
test("copies the roof's faces of other kinds with it, as they stand in its frame", () => {
|
|
86
|
+
const { roof } = duplicateRoofSubtree(ROOF_ID, { mode: 'select' })
|
|
87
|
+
const nodes = useScene.getState().nodes
|
|
88
|
+
const copied = (nodes[roof.id as AnyNodeId] as RoofNode).children.map(
|
|
89
|
+
(id) => nodes[id as AnyNodeId]!,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
expect(copied.map((node): string => node.type)).toEqual(['roof-segment', 'test:roof-plane'])
|
|
93
|
+
const plane = copied[1] as unknown as z.infer<typeof RoofPlane>
|
|
94
|
+
expect(plane.id).not.toBe(PLANE_ID)
|
|
95
|
+
expect(plane.id.startsWith('roofplane_')).toBe(true)
|
|
96
|
+
expect(plane.parentId).toBe(roof.id)
|
|
97
|
+
expect(plane.polygon).toEqual(POLYGON)
|
|
98
|
+
expect((nodes[ROOF_ID] as RoofNode).children).toEqual([SEGMENT_ID, PLANE_ID])
|
|
99
|
+
})
|
|
100
|
+
})
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
|
+
type AnyNode,
|
|
4
5
|
type AnyNodeId,
|
|
5
6
|
collectionIdsOf,
|
|
6
7
|
generateId,
|
|
8
|
+
nodeRegistry,
|
|
7
9
|
type RoofNode,
|
|
8
10
|
RoofNode as RoofNodeSchema,
|
|
9
11
|
type RoofSegmentNode,
|
|
10
12
|
RoofSegmentNode as RoofSegmentNodeSchema,
|
|
13
|
+
roofFaceOf,
|
|
11
14
|
sceneRegistry,
|
|
12
15
|
useScene,
|
|
13
16
|
} from '@pascal-app/core'
|
|
@@ -121,6 +124,23 @@ export function duplicateRoofSubtree(
|
|
|
121
124
|
segmentSourceIds.push(childNode.id)
|
|
122
125
|
}
|
|
123
126
|
|
|
127
|
+
// Its faces of other kinds (`capabilities.roofs`) are copied by their own schema, in the copy's
|
|
128
|
+
// frame as in the source's; a face that does not parse fails the copy, as a segment does.
|
|
129
|
+
const faceClones: { node: AnyNode; sourceId: AnyNodeId }[] = []
|
|
130
|
+
for (const childId of sourceRoof.children ?? []) {
|
|
131
|
+
const childNode = scene.nodes[childId as AnyNodeId]
|
|
132
|
+
const schema =
|
|
133
|
+
childNode && roofFaceOf(childNode) ? nodeRegistry.get(childNode.type)?.schema : undefined
|
|
134
|
+
if (!(childNode && schema)) continue
|
|
135
|
+
const { id: _id, ...fields } = structuredClone(childNode)
|
|
136
|
+
const node = schema.parse({
|
|
137
|
+
...fields,
|
|
138
|
+
parentId: roofClone.id,
|
|
139
|
+
metadata: buildDuplicateMetadata(childNode.metadata),
|
|
140
|
+
}) as AnyNode
|
|
141
|
+
faceClones.push({ node, sourceId: childNode.id })
|
|
142
|
+
}
|
|
143
|
+
|
|
124
144
|
// Each copy is in the collections its source is in.
|
|
125
145
|
scene.createNodes([
|
|
126
146
|
{ node: roofClone, parentId, collectionIds: collectionIdsOf(scene.collections, sourceRoofId) },
|
|
@@ -129,6 +149,11 @@ export function duplicateRoofSubtree(
|
|
|
129
149
|
parentId: roofClone.id as AnyNodeId,
|
|
130
150
|
collectionIds: collectionIdsOf(scene.collections, segmentSourceIds[index]!),
|
|
131
151
|
})),
|
|
152
|
+
...faceClones.map(({ node, sourceId }) => ({
|
|
153
|
+
node,
|
|
154
|
+
parentId: roofClone.id as AnyNodeId,
|
|
155
|
+
collectionIds: collectionIdsOf(scene.collections, sourceId),
|
|
156
|
+
})),
|
|
132
157
|
])
|
|
133
158
|
|
|
134
159
|
const nextScene = useScene.getState()
|
|
@@ -148,12 +173,12 @@ export function duplicateRoofSubtree(
|
|
|
148
173
|
|
|
149
174
|
const segmentIds = segmentClones.map((segment) => segment.id)
|
|
150
175
|
const createdChildIds = (createdRoof.children ?? []) as AnyNodeId[]
|
|
151
|
-
const
|
|
152
|
-
(
|
|
176
|
+
const missingChildId = [...segmentIds, ...faceClones.map(({ node }) => node.id)].find(
|
|
177
|
+
(childId) => !createdChildIds.includes(childId as AnyNodeId),
|
|
153
178
|
)
|
|
154
|
-
if (
|
|
179
|
+
if (missingChildId) {
|
|
155
180
|
throw new Error(
|
|
156
|
-
`Duplicated roof "${createdRoof.id}" is missing cloned
|
|
181
|
+
`Duplicated roof "${createdRoof.id}" is missing cloned child "${missingChildId}"`,
|
|
157
182
|
)
|
|
158
183
|
}
|
|
159
184
|
|
|
@@ -206,7 +231,7 @@ export function clearRoofDuplicateMetadata(
|
|
|
206
231
|
|
|
207
232
|
for (const childId of roofNode.children ?? []) {
|
|
208
233
|
const childNode = scene.nodes[childId as AnyNodeId]
|
|
209
|
-
if (childNode
|
|
234
|
+
if (!childNode) {
|
|
210
235
|
continue
|
|
211
236
|
}
|
|
212
237
|
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
generateId,
|
|
9
9
|
initSpaceDetectionSync,
|
|
10
10
|
LevelNode,
|
|
11
|
+
roomFloorElevation,
|
|
11
12
|
SlabNode,
|
|
12
13
|
type SlabNode as SlabNodeType,
|
|
13
14
|
useScene,
|
|
@@ -24,11 +25,7 @@ import {
|
|
|
24
25
|
setRoomRelativeFloorHeight,
|
|
25
26
|
stepRoomFloorElevation,
|
|
26
27
|
} from './room-construction-commands'
|
|
27
|
-
import {
|
|
28
|
-
commitRoomElevation,
|
|
29
|
-
ownFloorElevationBounds,
|
|
30
|
-
roomFloorElevation,
|
|
31
|
-
} from './room-handle-drag'
|
|
28
|
+
import { commitRoomElevation, ownFloorElevationBounds } from './room-handle-drag'
|
|
32
29
|
import { applyRoomPlan } from './room-structure-commands'
|
|
33
30
|
import { showRoomNotice, useRoomTransform } from './room-transform-session'
|
|
34
31
|
|
package/src/lib/room-built-on.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type AnyNode,
|
|
3
3
|
roomFloorChoices as coreRoomFloorChoices,
|
|
4
|
+
levelFootprints,
|
|
4
5
|
type PascalI18n,
|
|
5
6
|
roomDrawnFloor,
|
|
6
7
|
type SlabNode,
|
|
7
8
|
type ZoneNode,
|
|
8
9
|
} from '@pascal-app/core'
|
|
9
|
-
import { levelFootprints } from './floor-footprints'
|
|
10
10
|
|
|
11
11
|
// "Built on": which floor a room stands on. By default a room is part of its
|
|
12
12
|
// connected footprint's shared floor (`floor.footprint` absent); a floor key
|
|
@@ -61,20 +61,6 @@ export function roomFloorChoices(nodes: Nodes, zoneId: string): PlateChoice[] {
|
|
|
61
61
|
.map(({ key, plateId, name }) => ({ key, plateId, name }))
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
/**
|
|
65
|
-
* The plate a room on a separate floor stands on alone: its height is that
|
|
66
|
-
* plate's floor height (nothing else stands on it). Null for a room on the
|
|
67
|
-
* shared floor or sharing its separate floor with other rooms.
|
|
68
|
-
*/
|
|
69
|
-
export function roomOwnPlate(nodes: Nodes, zoneId: string): SlabNode | null {
|
|
70
|
-
const zone = nodes[zoneId]
|
|
71
|
-
if (!isRoom(zone) || !zone.floor?.footprint || zone.floor.support === 'open') return null
|
|
72
|
-
const plate = listingPlate(nodes, zone)
|
|
73
|
-
if (!plate) return null
|
|
74
|
-
const alone = !(plate.zoneIds ?? []).some((id) => id !== zoneId && isGroundRoom(nodes[id]))
|
|
75
|
-
return alone ? plate : null
|
|
76
|
-
}
|
|
77
|
-
|
|
78
64
|
/**
|
|
79
65
|
* The shared floor beside a room on a separate floor, where it goes back to.
|
|
80
66
|
* For a room on the shared floor, its own plate.
|
|
@@ -17,7 +17,9 @@ import {
|
|
|
17
17
|
type NodeChange,
|
|
18
18
|
planWallJustification,
|
|
19
19
|
resolveCeilingHeight,
|
|
20
|
+
roomFloorElevation,
|
|
20
21
|
roomFloorElevationFromRelative,
|
|
22
|
+
roomOwnPlate,
|
|
21
23
|
roomSideFaces,
|
|
22
24
|
runAsSingleSceneHistoryStep,
|
|
23
25
|
type StructureConflict,
|
|
@@ -32,13 +34,12 @@ import useDeleteConfirmation, {
|
|
|
32
34
|
} from '../store/use-delete-confirmation'
|
|
33
35
|
import useEditor from '../store/use-editor'
|
|
34
36
|
import { footprintHeightValue } from './floor-footprints'
|
|
35
|
-
import {
|
|
37
|
+
import { roomSharedFootprint } from './room-built-on'
|
|
36
38
|
import { roomClearPolygon, roomConstructionState, roomFloorContents } from './room-construction'
|
|
37
39
|
import {
|
|
38
40
|
mezzanineElevationBounds,
|
|
39
41
|
ownFloorElevationBounds,
|
|
40
42
|
planRoomElevation,
|
|
41
|
-
roomFloorElevation,
|
|
42
43
|
} from './room-handle-drag'
|
|
43
44
|
import { applyRoomPlan } from './room-structure-commands'
|
|
44
45
|
import { showRoomNotice } from './room-transform-session'
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
generateId,
|
|
10
10
|
initSpaceDetectionSync,
|
|
11
11
|
LevelNode,
|
|
12
|
+
roomFloorElevation,
|
|
12
13
|
structureChangeBatch,
|
|
13
14
|
useLiveNodeOverrides,
|
|
14
15
|
useScene,
|
|
@@ -33,7 +34,6 @@ import {
|
|
|
33
34
|
getActiveRoomHandleDrag,
|
|
34
35
|
planRoomPush,
|
|
35
36
|
previewRoomPush,
|
|
36
|
-
roomFloorElevation,
|
|
37
37
|
roomPushHandles,
|
|
38
38
|
runRoomHandleDrag,
|
|
39
39
|
selectedWallDimensions,
|
|
@@ -16,12 +16,15 @@ import {
|
|
|
16
16
|
type Point,
|
|
17
17
|
planWallDivision,
|
|
18
18
|
resolveMovedWallSupportSlabPatch,
|
|
19
|
+
roomFloorElevation,
|
|
20
|
+
roomOwnPlate,
|
|
19
21
|
runAsSingleSceneHistoryStep,
|
|
20
22
|
SEPARATOR_JOIN_REACH,
|
|
21
23
|
type SeparatorNode,
|
|
22
24
|
type SeparatorSpan,
|
|
23
25
|
type StructureNodes,
|
|
24
26
|
type StructurePlan,
|
|
27
|
+
separatorFloorElevation,
|
|
25
28
|
setRoomFloorConstruction,
|
|
26
29
|
setWallGeometry,
|
|
27
30
|
setZoneEdges,
|
|
@@ -31,8 +34,9 @@ import {
|
|
|
31
34
|
useLiveNodeOverrides,
|
|
32
35
|
useScene,
|
|
33
36
|
type WallNode,
|
|
37
|
+
type WallPushArrowPayload,
|
|
34
38
|
} from '@pascal-app/core'
|
|
35
|
-
import { useViewer } from '@pascal-app/viewer'
|
|
39
|
+
import { isTypingTarget, useViewer } from '@pascal-app/viewer'
|
|
36
40
|
import type { Ray } from 'three'
|
|
37
41
|
import { create } from 'zustand'
|
|
38
42
|
import { ARROW_COLOR } from '../components/editor/handles/handle-arrow'
|
|
@@ -46,7 +50,6 @@ import { clientToPlan } from './floorplan/plan-coords'
|
|
|
46
50
|
import { beginGesture } from './gesture-lifecycle'
|
|
47
51
|
import { isHistoryShortcut } from './history'
|
|
48
52
|
import { MEZZANINE_FAILED_MESSAGE, mezzanineConflictMessage } from './mezzanine-messages'
|
|
49
|
-
import { roomOwnPlate } from './room-built-on'
|
|
50
53
|
import {
|
|
51
54
|
mezzanineEdgeDimensions,
|
|
52
55
|
type RoomDimension,
|
|
@@ -62,7 +65,6 @@ import { applyRoomPlan } from './room-structure-commands'
|
|
|
62
65
|
import { levelSeparatorLines, separatorWallLine } from './separator-lines'
|
|
63
66
|
import { sfxEmitter } from './sfx-bus'
|
|
64
67
|
import { type SpatialPointerId, spatialPointerInput } from './spatial-pointer-input'
|
|
65
|
-
import { isTypingTarget } from './typing-target'
|
|
66
68
|
import {
|
|
67
69
|
nearestWallParallelTarget,
|
|
68
70
|
publishWallParallelGuide,
|
|
@@ -146,19 +148,6 @@ export const useRoomHandleDrag = create<{ drag: RoomHandleDrag | null }>(() => (
|
|
|
146
148
|
|
|
147
149
|
type Nodes = Record<string, AnyNode>
|
|
148
150
|
|
|
149
|
-
/** The walking surface of a room: its own elevation, else its plate's. */
|
|
150
|
-
export function roomFloorElevation(nodes: Nodes, zoneId: string): number {
|
|
151
|
-
const zone = nodes[zoneId]
|
|
152
|
-
if (zone?.type !== 'zone') return 0
|
|
153
|
-
const own = roomOwnPlate(nodes, zoneId)
|
|
154
|
-
if (own) return own.elevation
|
|
155
|
-
if (typeof zone.floor?.elevation === 'number') return zone.floor.elevation
|
|
156
|
-
const plate = Object.values(nodes).find(
|
|
157
|
-
(node) => node.type === 'slab' && node.zoneIds?.includes(zoneId),
|
|
158
|
-
)
|
|
159
|
-
return plate?.type === 'slab' ? (plate.elevation ?? 0.05) : 0.05
|
|
160
|
-
}
|
|
161
|
-
|
|
162
151
|
/**
|
|
163
152
|
* The stretch of a wall a push moves: `[0, 1]` is the whole wall (its
|
|
164
153
|
* neighbours follow through the junction planner), anything shorter is split
|
|
@@ -206,7 +195,7 @@ function wallPushHandle(
|
|
|
206
195
|
const offsets = getWallFaceOffsets(wall)
|
|
207
196
|
const face = side === 'a' ? offsets.a : -offsets.b
|
|
208
197
|
const offset = Math.max(face + HANDLE_OFFSET, HANDLE_MIN_OFFSET)
|
|
209
|
-
const wallHeight = getWallEffectiveHeightForNodes(wall, nodes)
|
|
198
|
+
const wallHeight = getWallEffectiveHeightForNodes(wall, nodes, 0.5)
|
|
210
199
|
return {
|
|
211
200
|
key,
|
|
212
201
|
wallId: wall.id,
|
|
@@ -396,14 +385,6 @@ export function separatorPushHandles(separator: SeparatorNode, floor = 0): WallP
|
|
|
396
385
|
})
|
|
397
386
|
}
|
|
398
387
|
|
|
399
|
-
/** The floor an invisible wall lies on: the walking surface of a room it closes, else 0. */
|
|
400
|
-
export function separatorFloorElevation(nodes: Nodes, separatorId: string): number {
|
|
401
|
-
const zone = Object.values(nodes).find(
|
|
402
|
-
(node) => node.type === 'zone' && node.boundarySeparatorIds.includes(separatorId),
|
|
403
|
-
)
|
|
404
|
-
return zone ? roomFloorElevation(nodes, zone.id) : 0
|
|
405
|
-
}
|
|
406
|
-
|
|
407
388
|
/**
|
|
408
389
|
* Snaps a push the way the wall move always has: the wall's reference line
|
|
409
390
|
* (not the travel) lands on the grid lattice along its normal, so an off-grid
|
|
@@ -642,7 +623,7 @@ function previewPushPlan(
|
|
|
642
623
|
start: change.node.start,
|
|
643
624
|
end: change.node.end,
|
|
644
625
|
thickness: change.node.thickness ?? 0.1,
|
|
645
|
-
height: getWallEffectiveHeightForNodes(change.node, nodes),
|
|
626
|
+
height: getWallEffectiveHeightForNodes(change.node, nodes, 0),
|
|
646
627
|
},
|
|
647
628
|
]
|
|
648
629
|
: []
|
|
@@ -1403,7 +1384,7 @@ export function beginWallGroupPush(wallIds: readonly string[], levelId: string):
|
|
|
1403
1384
|
{
|
|
1404
1385
|
wall,
|
|
1405
1386
|
base,
|
|
1406
|
-
top: base + getWallEffectiveHeightForNodes(wall, nodes),
|
|
1387
|
+
top: base + getWallEffectiveHeightForNodes(wall, nodes, 0),
|
|
1407
1388
|
normal: wallPushNormal(wall),
|
|
1408
1389
|
rooms: pushDimensionRooms(nodes, levelId, { wallId: wall.id, t0: 0, t1: 1 }, base),
|
|
1409
1390
|
},
|
|
@@ -1488,16 +1469,6 @@ export function wallPointAt(wall: WallNode, t: number): Point {
|
|
|
1488
1469
|
return [frame.point.x, frame.point.y]
|
|
1489
1470
|
}
|
|
1490
1471
|
|
|
1491
|
-
/**
|
|
1492
|
-
* The affordance a floor-plan `move-arrow` carries to be a wall push arrow;
|
|
1493
|
-
* its payload is a `WallPushArrowPayload`. The floor plan starts
|
|
1494
|
-
* `runFloorplanWallPush` for it instead of a registry affordance session.
|
|
1495
|
-
*/
|
|
1496
|
-
export const WALL_PUSH_AFFORDANCE = 'wall-push'
|
|
1497
|
-
|
|
1498
|
-
/** A wall's or an invisible wall's side arrow: `wallId` is either. */
|
|
1499
|
-
export type WallPushArrowPayload = { wallId: string; side: 'a' | 'b' }
|
|
1500
|
-
|
|
1501
1472
|
type PlanPointer = (clientX: number, clientY: number) => readonly [number, number] | null
|
|
1502
1473
|
|
|
1503
1474
|
/** The pointer's plan position measured along an arrow's outward normal from its spot. */
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { describe, expect, test } from 'bun:test'
|
|
2
2
|
import { type AnyNode, ZoneNode } from '@pascal-app/core'
|
|
3
|
+
import { ROOM_NAME_MESSAGES } from '@pascal-app/viewer/ui'
|
|
3
4
|
import {
|
|
4
5
|
MEZZANINE_NAME_SECTION,
|
|
5
6
|
numberedRoomName,
|
|
@@ -8,7 +9,7 @@ import {
|
|
|
8
9
|
roomNameSections,
|
|
9
10
|
roomNameUseCount,
|
|
10
11
|
} from './room-name-catalog'
|
|
11
|
-
import {
|
|
12
|
+
import { ROOM_NAME_SECTION_TITLES } from './room-name-messages'
|
|
12
13
|
|
|
13
14
|
const square: [number, number][] = [
|
|
14
15
|
[0, 0],
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { describe, expect, test } from 'bun:test'
|
|
2
2
|
import { type AnyNode, type MessageDescriptor, ZoneNode } from '@pascal-app/core'
|
|
3
|
+
import { displayRoomName, editedRoomName } from '@pascal-app/viewer/ui'
|
|
3
4
|
import { roomNameOptions } from '../components/ui/panels/room-name-options'
|
|
4
5
|
import { roomNameSections } from './room-name-catalog'
|
|
5
|
-
import {
|
|
6
|
+
import { localizedRoomNameSections } from './room-name-messages'
|
|
6
7
|
|
|
7
8
|
const FRENCH: Record<string, string> = {
|
|
8
9
|
'editor.roomName.bedroom': 'Chambre',
|