@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,7 +1,7 @@
|
|
|
1
1
|
import { useViewer } from '@pascal-app/viewer'
|
|
2
|
+
import { useBelowGrade, useGroundWindowBox } from '@pascal-app/viewer/ui'
|
|
2
3
|
import { useEffect } from 'react'
|
|
3
4
|
import useEditor, { type CaptureMode } from '../store/use-editor'
|
|
4
|
-
import { useBelowGrade, useGroundWindowBox } from './below-grade'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Whether the editor shows every level. Preview and the walkthrough show the
|
|
@@ -154,12 +154,27 @@ export function collectElevationSnapTargets(
|
|
|
154
154
|
anchor: center,
|
|
155
155
|
label: 'Wall base',
|
|
156
156
|
})
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
157
|
+
if (node.endHeightOffset) {
|
|
158
|
+
targets.push({
|
|
159
|
+
id: `${node.id}:top-start`,
|
|
160
|
+
elevation: base + getWallEffectiveHeightForNodes(node, nodes, 0),
|
|
161
|
+
anchor: node.start,
|
|
162
|
+
label: 'Wall top start',
|
|
163
|
+
})
|
|
164
|
+
targets.push({
|
|
165
|
+
id: `${node.id}:top-end`,
|
|
166
|
+
elevation: base + getWallEffectiveHeightForNodes(node, nodes, 1),
|
|
167
|
+
anchor: node.end,
|
|
168
|
+
label: 'Wall top end',
|
|
169
|
+
})
|
|
170
|
+
} else {
|
|
171
|
+
targets.push({
|
|
172
|
+
id: `${node.id}:top`,
|
|
173
|
+
elevation: base + getWallEffectiveHeightForNodes(node, nodes, 0.5),
|
|
174
|
+
anchor: center,
|
|
175
|
+
label: 'Wall top',
|
|
176
|
+
})
|
|
177
|
+
}
|
|
163
178
|
continue
|
|
164
179
|
}
|
|
165
180
|
|
|
@@ -1,26 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type AnyNode,
|
|
3
|
-
type AnyNodeId,
|
|
4
|
-
type BuildingNode,
|
|
5
|
-
type ElevatorNode,
|
|
6
|
-
type LevelNode,
|
|
7
|
-
spatialGridManager,
|
|
8
|
-
useScene,
|
|
9
|
-
} from '@pascal-app/core'
|
|
10
|
-
|
|
11
|
-
function getBuildingLevels(
|
|
12
|
-
buildingId: string | null | undefined,
|
|
13
|
-
nodes: Record<string, AnyNode>,
|
|
14
|
-
): LevelNode[] {
|
|
15
|
-
if (!buildingId) return []
|
|
16
|
-
const building = nodes[buildingId as AnyNodeId]
|
|
17
|
-
if (building?.type !== 'building') return []
|
|
18
|
-
|
|
19
|
-
return building.children
|
|
20
|
-
.map((childId) => nodes[childId as AnyNodeId])
|
|
21
|
-
.filter((entry): entry is LevelNode => entry?.type === 'level')
|
|
22
|
-
.sort((left, right) => left.level - right.level)
|
|
23
|
-
}
|
|
1
|
+
import type { AnyNode, AnyNodeId, BuildingNode, LevelNode } from '@pascal-app/core'
|
|
24
2
|
|
|
25
3
|
export function resolveCurrentBuildingId({
|
|
26
4
|
buildingId,
|
|
@@ -45,52 +23,3 @@ export function resolveCurrentBuildingId({
|
|
|
45
23
|
|
|
46
24
|
return null
|
|
47
25
|
}
|
|
48
|
-
|
|
49
|
-
export function resolveElevatorSupportLevelId({
|
|
50
|
-
buildingId,
|
|
51
|
-
preferredLevelId,
|
|
52
|
-
}: {
|
|
53
|
-
buildingId: string | null | undefined
|
|
54
|
-
preferredLevelId?: string | null
|
|
55
|
-
}): LevelNode['id'] | null {
|
|
56
|
-
const nodes = useScene.getState().nodes
|
|
57
|
-
const preferred = preferredLevelId ? nodes[preferredLevelId as AnyNodeId] : undefined
|
|
58
|
-
const levels = getBuildingLevels(buildingId, nodes)
|
|
59
|
-
const preferredInBuilding = preferredLevelId
|
|
60
|
-
? levels.find((level) => level.id === preferredLevelId)
|
|
61
|
-
: undefined
|
|
62
|
-
|
|
63
|
-
if (preferredInBuilding) return preferredInBuilding.id
|
|
64
|
-
if (levels.length === 0) return preferred?.type === 'level' ? preferred.id : null
|
|
65
|
-
|
|
66
|
-
return levels[0]?.id ?? null
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export function resolveElevatorSupportY({
|
|
70
|
-
buildingId,
|
|
71
|
-
preferredLevelId,
|
|
72
|
-
x,
|
|
73
|
-
z,
|
|
74
|
-
}: {
|
|
75
|
-
buildingId: string | null | undefined
|
|
76
|
-
preferredLevelId?: string | null
|
|
77
|
-
x: number
|
|
78
|
-
z: number
|
|
79
|
-
}): number {
|
|
80
|
-
const levelId = resolveElevatorSupportLevelId({ buildingId, preferredLevelId })
|
|
81
|
-
if (!levelId) return 0
|
|
82
|
-
|
|
83
|
-
return Math.max(0, spatialGridManager.getSlabElevationAt(levelId, x, z))
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export function resolveElevatorNodeSupportY(
|
|
87
|
-
node: ElevatorNode,
|
|
88
|
-
position: [number, number, number] = node.position,
|
|
89
|
-
): number {
|
|
90
|
-
return resolveElevatorSupportY({
|
|
91
|
-
buildingId: node.parentId,
|
|
92
|
-
preferredLevelId: node.fromLevelId ?? node.defaultLevelId,
|
|
93
|
-
x: position[0],
|
|
94
|
-
z: position[2],
|
|
95
|
-
})
|
|
96
|
-
}
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
ItemNode,
|
|
12
12
|
initSpaceDetectionSync,
|
|
13
13
|
LevelNode,
|
|
14
|
+
levelFootprints,
|
|
14
15
|
type SceneCommit,
|
|
15
16
|
type SlabNode,
|
|
16
17
|
SlabNode as SlabSchema,
|
|
@@ -18,6 +19,8 @@ import {
|
|
|
18
19
|
useScene,
|
|
19
20
|
ZoneNode,
|
|
20
21
|
} from '@pascal-app/core'
|
|
22
|
+
import type { RoomSelectionRecord } from '@pascal-app/viewer/ui'
|
|
23
|
+
import { resolveRoomAssemblyHeights } from '@pascal-app/viewer/ui'
|
|
21
24
|
import { moveTogetherLabel } from '../components/ui/panels/floor-foundation-panel'
|
|
22
25
|
import {
|
|
23
26
|
applyFloorFoundation,
|
|
@@ -29,13 +32,11 @@ import {
|
|
|
29
32
|
footprintsToMoveTogether,
|
|
30
33
|
foundationHeight,
|
|
31
34
|
isFootprintConstructionHit,
|
|
32
|
-
levelFootprints,
|
|
33
35
|
presetPatch,
|
|
34
36
|
roomFloorOwner,
|
|
35
37
|
roomFootprint,
|
|
36
38
|
roomOwnedPlateDrillTarget,
|
|
37
39
|
} from './floor-footprints'
|
|
38
|
-
import { resolveRoomAssemblyHeights } from './room-assembly-overlay'
|
|
39
40
|
import { roomConstructionState } from './room-construction'
|
|
40
41
|
import {
|
|
41
42
|
addRoomConstruction,
|
|
@@ -43,7 +44,6 @@ import {
|
|
|
43
44
|
roomRelativeFloorHeight,
|
|
44
45
|
setRoomRelativeFloorHeight,
|
|
45
46
|
} from './room-construction-commands'
|
|
46
|
-
import type { RoomSelectionRecord } from './room-selection'
|
|
47
47
|
import { applyRoomPlan } from './room-structure-commands'
|
|
48
48
|
|
|
49
49
|
const LEVEL = 'level_footprints'
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
getRoomBaseElevation,
|
|
11
11
|
groundFloorConstruction,
|
|
12
12
|
intersection,
|
|
13
|
+
levelFootprints,
|
|
13
14
|
roomDrawnFloor,
|
|
14
15
|
type SlabNode,
|
|
15
16
|
setFloorFoundation,
|
|
@@ -39,15 +40,6 @@ const ON_GROUND = 0.0005
|
|
|
39
40
|
const isBase = (node: AnyNode | undefined): node is SlabNode =>
|
|
40
41
|
node?.type === 'slab' && node.plateRole === 'base'
|
|
41
42
|
|
|
42
|
-
const footprintArea = (plate: SlabNode) => area([{ outer: plate.polygon, holes: plate.holes }])
|
|
43
|
-
|
|
44
|
-
/** The level's footprints, largest first (ties by id, so the order is stable). */
|
|
45
|
-
export function levelFootprints(nodes: Record<string, AnyNode>, levelId: string): SlabNode[] {
|
|
46
|
-
return Object.values(nodes)
|
|
47
|
-
.filter((node): node is SlabNode => isBase(node) && node.parentId === levelId)
|
|
48
|
-
.sort((a, b) => footprintArea(b) - footprintArea(a) || a.id.localeCompare(b.id))
|
|
49
|
-
}
|
|
50
|
-
|
|
51
43
|
/**
|
|
52
44
|
* The drawn slab a room's floor is: the one it visibly stands on (a legacy
|
|
53
45
|
* floor can show a hand-drawn slab over the one it was taken from), else the
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
getLevelElevations,
|
|
12
12
|
initSpaceDetectionSync,
|
|
13
13
|
LevelNode,
|
|
14
|
+
levelFootprints,
|
|
14
15
|
type SlabNode,
|
|
15
16
|
upperFloorHeightControl,
|
|
16
17
|
useScene,
|
|
@@ -30,7 +31,6 @@ import {
|
|
|
30
31
|
footprintHeightMinimum,
|
|
31
32
|
footprintHeightPatch,
|
|
32
33
|
footprintHeightValue,
|
|
33
|
-
levelFootprints,
|
|
34
34
|
presetPatch,
|
|
35
35
|
setFootprintHeight,
|
|
36
36
|
thickFloorAdvice,
|
|
@@ -169,7 +169,6 @@ describe('Upper-floor height drag release (round-final item 6)', () => {
|
|
|
169
169
|
test(`a drag of ${delta} m lands on release`, () => {
|
|
170
170
|
const bedroom = plateOf(UPPER, 'Bedroom')
|
|
171
171
|
const start = footprintHeightValue(nodes(), bedroom)
|
|
172
|
-
const past = useScene.temporal.getState().pastStates.length
|
|
173
172
|
const preview = beginFootprintHeightPreview(bedroom.id)
|
|
174
173
|
expect(preview.preview(start + delta / 2)).toBeNull()
|
|
175
174
|
expect(preview.preview(start + delta)).toBeNull()
|
|
@@ -177,7 +176,13 @@ describe('Upper-floor height drag release (round-final item 6)', () => {
|
|
|
177
176
|
const after = nodes()[bedroom.id] as SlabNode
|
|
178
177
|
expect(after.thickness).toBeCloseTo(bedroom.thickness + delta, 6)
|
|
179
178
|
expect(footprintHeightValue(nodes(), after)).toBeCloseTo(start + delta, 6)
|
|
180
|
-
|
|
179
|
+
useScene.temporal.getState().undo()
|
|
180
|
+
expect(footprintHeightValue(nodes(), nodes()[bedroom.id] as SlabNode)).toBeCloseTo(start, 6)
|
|
181
|
+
useScene.temporal.getState().redo()
|
|
182
|
+
expect(footprintHeightValue(nodes(), nodes()[bedroom.id] as SlabNode)).toBeCloseTo(
|
|
183
|
+
start + delta,
|
|
184
|
+
6,
|
|
185
|
+
)
|
|
181
186
|
})
|
|
182
187
|
}
|
|
183
188
|
})
|
|
@@ -7,11 +7,13 @@ import {
|
|
|
7
7
|
generateId,
|
|
8
8
|
type LevelNode,
|
|
9
9
|
type MultiPolygon,
|
|
10
|
+
roomFloorElevation,
|
|
10
11
|
type StructurePlan,
|
|
11
12
|
structureChangeBatch,
|
|
12
13
|
useScene,
|
|
13
14
|
} from '@pascal-app/core'
|
|
14
15
|
import { useViewer } from '@pascal-app/viewer'
|
|
16
|
+
import { resolveRoomAssemblyHeights } from '@pascal-app/viewer/ui'
|
|
15
17
|
import { create } from 'zustand'
|
|
16
18
|
import { getRoomSelectionIndex } from '../hooks/use-selected-room'
|
|
17
19
|
import useEditor from '../store/use-editor'
|
|
@@ -30,8 +32,6 @@ import {
|
|
|
30
32
|
} from './floor-region-session'
|
|
31
33
|
import { type FloorRegionPoint, floorRegionSnapTargets } from './floor-region-snap'
|
|
32
34
|
import { beginGesture, type GestureHandle } from './gesture-lifecycle'
|
|
33
|
-
import { resolveRoomAssemblyHeights } from './room-assembly-overlay'
|
|
34
|
-
import { roomFloorElevation } from './room-handle-drag'
|
|
35
35
|
import { sfxEmitter } from './sfx-bus'
|
|
36
36
|
|
|
37
37
|
// "Cut opening": draws an opening on a room's floor (or its ceiling) with the
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
ceilingRegionsOwner,
|
|
8
8
|
type MultiPolygon,
|
|
9
9
|
resolveCeilingHeight,
|
|
10
|
+
roomFloorElevation,
|
|
10
11
|
union,
|
|
11
12
|
useScene,
|
|
12
13
|
} from '@pascal-app/core'
|
|
@@ -32,7 +33,6 @@ import { beginGesture, type GestureHandle } from './gesture-lifecycle'
|
|
|
32
33
|
import { hasActivePaintMaterial } from './material-paint'
|
|
33
34
|
import { isPaintErasing, usePaintRegionMode } from './paint-region-mode'
|
|
34
35
|
import { addCeilingRegion, addFloorRegion } from './paint-regions'
|
|
35
|
-
import { roomFloorElevation } from './room-handle-drag'
|
|
36
36
|
|
|
37
37
|
// An outline drawn on one room's floor: a rectangle (press, drag, release; a
|
|
38
38
|
// persistent tool also takes two clicks) or a polygon (click points, close on
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { describe, expect, test } from 'bun:test'
|
|
2
2
|
import type { FloorplanGeometry } from '@pascal-app/core'
|
|
3
|
+
import { floorplanGeometryMetadata, withFloorplanGeometryMetadata } from '@pascal-app/core'
|
|
3
4
|
import {
|
|
4
5
|
DEFAULT_FLOORPLAN_ANNOTATION_VISIBILITY,
|
|
5
6
|
filterFloorplanAnnotationGeometry,
|
|
6
7
|
normalizeFloorplanAnnotationVisibility,
|
|
7
8
|
} from './annotation-visibility'
|
|
8
|
-
import { floorplanGeometryMetadata, withFloorplanGeometryMetadata } from './floorplan-extension'
|
|
9
9
|
|
|
10
10
|
describe('floor-plan annotation visibility', () => {
|
|
11
11
|
test('fills missing persisted categories with visible defaults', () => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { FloorplanGeometry } from '@pascal-app/core'
|
|
2
|
-
import { type FloorplanAnnotationRole, readFloorplanGeometryMetadata } from '
|
|
2
|
+
import { type FloorplanAnnotationRole, readFloorplanGeometryMetadata } from '@pascal-app/core'
|
|
3
3
|
|
|
4
4
|
export type FloorplanAnnotationCategory =
|
|
5
5
|
| 'automaticDimensions'
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
type AnyNodeDefinition,
|
|
5
5
|
BuildingNode,
|
|
6
6
|
type FloorplanGeometry,
|
|
7
|
+
floorplanGeometryMetadata,
|
|
7
8
|
type GeometryContext,
|
|
8
9
|
LevelNode,
|
|
9
10
|
loadPlugin,
|
|
@@ -36,7 +37,6 @@ import {
|
|
|
36
37
|
resolveFloorplanScreenUnitsPerPixel,
|
|
37
38
|
rotateFloorplanExportBounds,
|
|
38
39
|
} from './floorplan-export'
|
|
39
|
-
import { floorplanGeometryMetadata } from './floorplan-extension'
|
|
40
40
|
import { FloorplanPdfDocument, loadFloorplanPdfFonts } from './floorplan-pdfkit-document'
|
|
41
41
|
import { renderFloorplanGeometryToPdfKit } from './floorplan-pdfkit-renderer'
|
|
42
42
|
|
|
@@ -4,23 +4,28 @@ import {
|
|
|
4
4
|
type AnyNode,
|
|
5
5
|
type AnyNodeId,
|
|
6
6
|
type ConstructionDrawingType,
|
|
7
|
+
FLOORPLAN_VIEW_ROTATION_DEG,
|
|
7
8
|
type FloorplanGeometry,
|
|
9
|
+
type FloorplanMetricNotation,
|
|
8
10
|
type FloorplanPalette,
|
|
9
11
|
type FloorplanPoint,
|
|
12
|
+
type FloorplanSchedule,
|
|
13
|
+
type FloorplanWallDimensionFaces,
|
|
10
14
|
getLevelDisplayName,
|
|
11
15
|
isNodeKindEnabled,
|
|
12
16
|
type LiveNodeOverrides,
|
|
13
17
|
type NodeCategory,
|
|
14
18
|
nodeRegistry,
|
|
19
|
+
readFloorplanGeometryMetadata,
|
|
15
20
|
resolveBuildingForLevel,
|
|
16
21
|
useScene,
|
|
17
22
|
} from '@pascal-app/core'
|
|
18
23
|
import { useViewer } from '@pascal-app/viewer'
|
|
24
|
+
import { FloorplanGeometryRenderer, navigationSyncPoseStore } from '@pascal-app/viewer/ui'
|
|
19
25
|
import { createElement } from 'react'
|
|
20
26
|
import { flushSync } from 'react-dom'
|
|
21
27
|
import { createRoot } from 'react-dom/client'
|
|
22
28
|
import { resolveSvgAnnotationCollisions } from '../../components/editor-2d/renderers/floorplan-annotation-layout'
|
|
23
|
-
import { FloorplanGeometryRenderer } from '../../components/editor-2d/renderers/floorplan-geometry-renderer'
|
|
24
29
|
import {
|
|
25
30
|
buildContext,
|
|
26
31
|
collectDirectFloorplanScopeNodes,
|
|
@@ -33,7 +38,6 @@ import {
|
|
|
33
38
|
splitFloorplanOverlay,
|
|
34
39
|
} from '../../components/editor-2d/renderers/floorplan-registry-layer'
|
|
35
40
|
import useDrawingView, { DRAWING_TYPE_OPTIONS } from '../../store/use-drawing-view'
|
|
36
|
-
import useEditor from '../../store/use-editor'
|
|
37
41
|
import useFloorplanAnnotationVisibility from '../../store/use-floorplan-annotation-visibility'
|
|
38
42
|
import useFloorplanMode from '../../store/use-floorplan-mode'
|
|
39
43
|
import {
|
|
@@ -41,17 +45,10 @@ import {
|
|
|
41
45
|
filterFloorplanAnnotationGeometry,
|
|
42
46
|
} from './annotation-visibility'
|
|
43
47
|
import { resolveNodeForDrawingType } from './drawing-coordination'
|
|
44
|
-
import {
|
|
45
|
-
type FloorplanMetricNotation,
|
|
46
|
-
type FloorplanSchedule,
|
|
47
|
-
type FloorplanWallDimensionFaces,
|
|
48
|
-
getFloorplanNodeExtension,
|
|
49
|
-
readFloorplanGeometryMetadata,
|
|
50
|
-
} from './floorplan-extension'
|
|
48
|
+
import { getFloorplanNodeExtension } from './floorplan-extension'
|
|
51
49
|
import { type FloorplanMode, resolveFloorplanAnnotationVisibility } from './floorplan-mode'
|
|
52
50
|
import { createFloorplanPdfDocument, type FloorplanPdfDocument } from './floorplan-pdfkit-document'
|
|
53
51
|
import { renderFloorplanGeometryToPdfKit } from './floorplan-pdfkit-renderer'
|
|
54
|
-
import { FLOORPLAN_VIEW_ROTATION_DEG } from './geometry'
|
|
55
52
|
|
|
56
53
|
/**
|
|
57
54
|
* Floorplan PDF export.
|
|
@@ -193,7 +190,7 @@ export async function exportFloorplanPdf(scope: FloorplanExportScope): Promise<v
|
|
|
193
190
|
expertAnnotationState.visibility,
|
|
194
191
|
expertAnnotationState.showDimensions,
|
|
195
192
|
)
|
|
196
|
-
const navigationAzimuth =
|
|
193
|
+
const navigationAzimuth = navigationSyncPoseStore.getState().pose?.azimuth
|
|
197
194
|
const drawingType = useDrawingView.getState().drawingType
|
|
198
195
|
const annotationLayoutOverrides = useDrawingView.getState().annotationLayoutOverrides
|
|
199
196
|
const drawingLabel =
|
|
@@ -2,7 +2,11 @@ import type {
|
|
|
2
2
|
AnyNode,
|
|
3
3
|
AnyNodeId,
|
|
4
4
|
ConstructionDrawingType,
|
|
5
|
+
FloorplanAnnotationRole,
|
|
5
6
|
FloorplanGeometry,
|
|
7
|
+
FloorplanMetricNotation,
|
|
8
|
+
FloorplanSchedule,
|
|
9
|
+
FloorplanWallDimensionFaces,
|
|
6
10
|
GeometryContext,
|
|
7
11
|
NodeDefinition,
|
|
8
12
|
SceneApi,
|
|
@@ -11,57 +15,8 @@ import type { ComponentType } from 'react'
|
|
|
11
15
|
import type { WallSelectionDimension } from '../room-push-dimensions'
|
|
12
16
|
|
|
13
17
|
export const FLOORPLAN_NODE_EXTENSION_KEY = 'pascal:editor/floorplan'
|
|
14
|
-
export const FLOORPLAN_GEOMETRY_METADATA_KEY = 'pascal:editor/floorplan'
|
|
15
|
-
export const FLOORPLAN_CONTEXT_EXTENSION_KEY = 'pascal:editor/floorplan'
|
|
16
18
|
|
|
17
|
-
export type FloorplanRenderPurpose = 'edit' | 'document'
|
|
18
|
-
export type FloorplanMetricNotation = 'meters' | 'millimeters'
|
|
19
19
|
export type FloorplanToolMode = 'default' | 'expert'
|
|
20
|
-
/**
|
|
21
|
-
* Display → Measure walls: which finished faces wall dimensions measure to —
|
|
22
|
-
* the interior faces (ID, the room sizes), the exterior faces (OD, the
|
|
23
|
-
* outside size) or both. Read by a selected wall's temporary dimensions in 2D
|
|
24
|
-
* and 3D and by the Expert plan's automatic dimension strings.
|
|
25
|
-
*/
|
|
26
|
-
export type FloorplanWallDimensionFaces = 'interior' | 'exterior' | 'both'
|
|
27
|
-
export const DEFAULT_FLOORPLAN_WALL_DIMENSION_FACES: FloorplanWallDimensionFaces = 'both'
|
|
28
|
-
|
|
29
|
-
export function normalizeFloorplanWallDimensionFaces(value: unknown): FloorplanWallDimensionFaces {
|
|
30
|
-
return value === 'interior' || value === 'exterior'
|
|
31
|
-
? value
|
|
32
|
-
: DEFAULT_FLOORPLAN_WALL_DIMENSION_FACES
|
|
33
|
-
}
|
|
34
|
-
export type FloorplanAnnotationRole =
|
|
35
|
-
| 'automatic-dimension'
|
|
36
|
-
| 'contextual-dimension'
|
|
37
|
-
| 'manual-dimension'
|
|
38
|
-
| 'measurement'
|
|
39
|
-
| 'opening-mark'
|
|
40
|
-
| 'structural-grid'
|
|
41
|
-
| 'column-center'
|
|
42
|
-
| 'room-label'
|
|
43
|
-
/** A room's finish / ceiling-height lines — detail under the name, off in the clean plan. */
|
|
44
|
-
| 'room-detail'
|
|
45
|
-
/** The roof plan proper: outline, ridges, hips, slope arrows. Off over a floor plan unless asked. */
|
|
46
|
-
| 'roof-plan'
|
|
47
|
-
| 'roof-pitch'
|
|
48
|
-
| 'stair-annotation'
|
|
49
|
-
|
|
50
|
-
export type FloorplanSchedule = {
|
|
51
|
-
id: string
|
|
52
|
-
title: string
|
|
53
|
-
columns: ReadonlyArray<{
|
|
54
|
-
key: string
|
|
55
|
-
label: string
|
|
56
|
-
weight?: number
|
|
57
|
-
}>
|
|
58
|
-
rows: ReadonlyArray<{
|
|
59
|
-
id: string
|
|
60
|
-
cells: Readonly<Record<string, string>>
|
|
61
|
-
}>
|
|
62
|
-
issues?: readonly string[]
|
|
63
|
-
}
|
|
64
|
-
|
|
65
20
|
export type FloorplanToolContext = {
|
|
66
21
|
sceneApi: SceneApi
|
|
67
22
|
activeLevelId: AnyNodeId | null
|
|
@@ -124,7 +79,6 @@ export type FloorplanNodeExtension<N extends AnyNode = AnyNode> = {
|
|
|
124
79
|
/** A drafted sheet's schedule: marks match the sheet's tags. */
|
|
125
80
|
drafting?: boolean
|
|
126
81
|
}) => FloorplanSchedule | null
|
|
127
|
-
linkedLevelIds?: (node: N) => readonly AnyNodeId[]
|
|
128
82
|
resolveForDrawing?: (args: {
|
|
129
83
|
node: N
|
|
130
84
|
nodes: Record<string, AnyNode>
|
|
@@ -132,38 +86,6 @@ export type FloorplanNodeExtension<N extends AnyNode = AnyNode> = {
|
|
|
132
86
|
}) => AnyNode | null
|
|
133
87
|
}
|
|
134
88
|
|
|
135
|
-
type FloorplanGeometryMetadata = {
|
|
136
|
-
annotationRole?: FloorplanAnnotationRole
|
|
137
|
-
annotationObstacle?: 'bounds' | 'outline'
|
|
138
|
-
renderPass?: 'overlay'
|
|
139
|
-
/**
|
|
140
|
-
* Annotation text only: the size to print at, in paper points, instead of
|
|
141
|
-
* the size its role implies. Lets a sheet set a room tag's name larger than
|
|
142
|
-
* its number without inventing a role per size.
|
|
143
|
-
*/
|
|
144
|
-
textSizePt?: number
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
type FloorplanContextExtension = {
|
|
148
|
-
automaticDimensions: boolean
|
|
149
|
-
purpose: FloorplanRenderPurpose
|
|
150
|
-
/**
|
|
151
|
-
* Sheet drafting (the Sheets plan viewports): kinds draw the permit-set
|
|
152
|
-
* convention — fixtures as labelled linework, furniture as light outlines,
|
|
153
|
-
* no raster sprites. Only `collectSheetGeometry` sets it; the editor and the
|
|
154
|
-
* read-only viewer never do, so their plans keep today's look.
|
|
155
|
-
*/
|
|
156
|
-
drafting: boolean
|
|
157
|
-
/**
|
|
158
|
-
* The editor canvas draws room labels as screen pills over the plan
|
|
159
|
-
* (`RoomLabels2D`), so zones skip their drawn tags and wash there. Exports,
|
|
160
|
-
* sheets and the read-only viewer keep the drawn tags.
|
|
161
|
-
*/
|
|
162
|
-
roomLabelOverlay: boolean
|
|
163
|
-
metricNotation: FloorplanMetricNotation
|
|
164
|
-
wallDimensionFaces: FloorplanWallDimensionFaces
|
|
165
|
-
}
|
|
166
|
-
|
|
167
89
|
export function getFloorplanNodeExtension(
|
|
168
90
|
definition: NodeDefinition<any> | undefined,
|
|
169
91
|
): FloorplanNodeExtension | undefined {
|
|
@@ -171,78 +93,3 @@ export function getFloorplanNodeExtension(
|
|
|
171
93
|
| FloorplanNodeExtension
|
|
172
94
|
| undefined
|
|
173
95
|
}
|
|
174
|
-
|
|
175
|
-
export function floorplanGeometryMetadata(
|
|
176
|
-
values: FloorplanGeometryMetadata,
|
|
177
|
-
): Readonly<Record<string, unknown>> {
|
|
178
|
-
return { [FLOORPLAN_GEOMETRY_METADATA_KEY]: values }
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
export function withFloorplanGeometryMetadata<T extends FloorplanGeometry | null>(
|
|
182
|
-
geometry: T,
|
|
183
|
-
values: FloorplanGeometryMetadata,
|
|
184
|
-
): T {
|
|
185
|
-
if (!geometry) return geometry
|
|
186
|
-
const existing = readFloorplanGeometryMetadata(geometry)
|
|
187
|
-
return {
|
|
188
|
-
...geometry,
|
|
189
|
-
metadata: floorplanGeometryMetadata({ ...existing, ...values }),
|
|
190
|
-
} as T
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
export function readFloorplanGeometryMetadata(geometry: unknown): FloorplanGeometryMetadata {
|
|
194
|
-
const metadata = (geometry as { metadata?: Readonly<Record<string, unknown>> } | null)?.metadata
|
|
195
|
-
const value = metadata?.[FLOORPLAN_GEOMETRY_METADATA_KEY]
|
|
196
|
-
return value && typeof value === 'object' && !Array.isArray(value)
|
|
197
|
-
? (value as FloorplanGeometryMetadata)
|
|
198
|
-
: {}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
export function createFloorplanContextExtensions(
|
|
202
|
-
values: Partial<FloorplanContextExtension>,
|
|
203
|
-
): Readonly<Record<string, unknown>> {
|
|
204
|
-
return {
|
|
205
|
-
[FLOORPLAN_CONTEXT_EXTENSION_KEY]: {
|
|
206
|
-
automaticDimensions: values.automaticDimensions !== false,
|
|
207
|
-
purpose: values.purpose === 'document' ? 'document' : 'edit',
|
|
208
|
-
drafting: values.drafting === true,
|
|
209
|
-
roomLabelOverlay: values.roomLabelOverlay === true,
|
|
210
|
-
metricNotation: values.metricNotation === 'millimeters' ? 'millimeters' : 'meters',
|
|
211
|
-
wallDimensionFaces: normalizeFloorplanWallDimensionFaces(values.wallDimensionFaces),
|
|
212
|
-
} satisfies FloorplanContextExtension,
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
export function readFloorplanContext(ctx: GeometryContext): FloorplanContextExtension {
|
|
217
|
-
const value = ctx.extensions?.[FLOORPLAN_CONTEXT_EXTENSION_KEY]
|
|
218
|
-
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
219
|
-
const extension = value as Partial<FloorplanContextExtension>
|
|
220
|
-
return {
|
|
221
|
-
automaticDimensions: extension.automaticDimensions !== false,
|
|
222
|
-
purpose: extension.purpose === 'document' ? 'document' : 'edit',
|
|
223
|
-
drafting: extension.drafting === true,
|
|
224
|
-
roomLabelOverlay: extension.roomLabelOverlay === true,
|
|
225
|
-
metricNotation: extension.metricNotation === 'millimeters' ? 'millimeters' : 'meters',
|
|
226
|
-
wallDimensionFaces: normalizeFloorplanWallDimensionFaces(extension.wallDimensionFaces),
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
return {
|
|
230
|
-
automaticDimensions: true,
|
|
231
|
-
purpose: 'edit',
|
|
232
|
-
drafting: false,
|
|
233
|
-
roomLabelOverlay: false,
|
|
234
|
-
metricNotation: 'meters',
|
|
235
|
-
wallDimensionFaces: DEFAULT_FLOORPLAN_WALL_DIMENSION_FACES,
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
export function readFloorplanMetricNotationOverride(
|
|
240
|
-
ctx: GeometryContext,
|
|
241
|
-
): FloorplanMetricNotation | undefined {
|
|
242
|
-
const value = ctx.extensions?.[FLOORPLAN_CONTEXT_EXTENSION_KEY]
|
|
243
|
-
if (!value || typeof value !== 'object' || Array.isArray(value)) return undefined
|
|
244
|
-
const metricNotation = (value as { metricNotation?: unknown }).metricNotation
|
|
245
|
-
return metricNotation === 'meters' || metricNotation === 'millimeters'
|
|
246
|
-
? metricNotation
|
|
247
|
-
: undefined
|
|
248
|
-
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import type { FloorplanAnnotationRole } from '@pascal-app/core'
|
|
1
2
|
import {
|
|
2
3
|
type FloorplanAnnotationVisibility,
|
|
3
4
|
revealFloorplanAnnotationRole,
|
|
4
5
|
} from './annotation-visibility'
|
|
5
|
-
import type {
|
|
6
|
+
import type { FloorplanToolMode } from './floorplan-extension'
|
|
6
7
|
|
|
7
8
|
export const FLOORPLAN_MODES = ['default', 'expert'] as const
|
|
8
9
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { describe, expect, test } from 'bun:test'
|
|
2
2
|
import type { FloorplanGeometry } from '@pascal-app/core'
|
|
3
|
+
import { floorplanGeometryMetadata } from '@pascal-app/core'
|
|
3
4
|
import PDFDocument from 'pdfkit'
|
|
4
|
-
import { floorplanGeometryMetadata } from './floorplan-extension'
|
|
5
5
|
import { FloorplanPdfDocument, loadFloorplanPdfFonts } from './floorplan-pdfkit-document'
|
|
6
6
|
import { renderFloorplanGeometryToPdfKit } from './floorplan-pdfkit-renderer'
|
|
7
7
|
|
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type FloorplanGeometry,
|
|
3
|
+
type FloorplanPoint,
|
|
4
|
+
loadAssetUrl,
|
|
5
|
+
readFloorplanGeometryMetadata,
|
|
6
|
+
} from '@pascal-app/core'
|
|
2
7
|
import {
|
|
3
8
|
type ArchitecturalDimensionLayout,
|
|
4
9
|
computeArchitecturalDimensionLayout,
|
|
5
|
-
} from '../../components/editor-2d/renderers/floorplan-dimension-renderer'
|
|
6
|
-
import {
|
|
7
10
|
documentCircleGeometryAttrs,
|
|
8
11
|
documentRectGeometryAttrs,
|
|
9
12
|
resolveDocumentAnnotationGroupChildren,
|
|
10
|
-
|
|
11
|
-
|
|
13
|
+
resolveFloorplanLabelAngle,
|
|
14
|
+
} from '@pascal-app/viewer/ui'
|
|
12
15
|
import type { FloorplanExportBounds } from './floorplan-export'
|
|
13
|
-
import { readFloorplanGeometryMetadata } from './floorplan-extension'
|
|
14
16
|
import type { FloorplanPdfBaseline, FloorplanPdfDocument } from './floorplan-pdfkit-document'
|
|
15
17
|
|
|
16
18
|
const DIMENSION_LINE_WIDTH_PT = 0.5
|
|
@@ -6,12 +6,11 @@ import {
|
|
|
6
6
|
loadPlugin,
|
|
7
7
|
nodeRegistry,
|
|
8
8
|
} from '@pascal-app/core'
|
|
9
|
+
import { FloorplanPreview } from '@pascal-app/viewer/ui'
|
|
9
10
|
import { renderToStaticMarkup } from 'react-dom/server'
|
|
10
11
|
import { z } from 'zod'
|
|
11
|
-
import { FloorplanPreview } from '../../components/viewer/floorplan-preview'
|
|
12
12
|
import { DEFAULT_FLOORPLAN_ANNOTATION_VISIBILITY } from './annotation-visibility'
|
|
13
13
|
import { collectFloorplanGeometry, floorplanExportInstalledPlugins } from './floorplan-export'
|
|
14
|
-
import { FLOORPLAN_NODE_EXTENSION_KEY } from './floorplan-extension'
|
|
15
14
|
|
|
16
15
|
// Plugin API v1, no-install case: a plugin kind's floor-plan output appears in
|
|
17
16
|
// the read-only preview and the PDF export only while the project has the
|
|
@@ -31,7 +30,7 @@ const bed = {
|
|
|
31
30
|
visible: true,
|
|
32
31
|
metadata: {},
|
|
33
32
|
} as unknown as AnyNode
|
|
34
|
-
// Lives on the upper level but draws on this one through `
|
|
33
|
+
// Lives on the upper level but draws on this one through `floorplanLinkedLevelIds`.
|
|
35
34
|
const upper = LevelNode.parse({ id: 'level_plugin_upper', level: 1, children: ['fxshaft_plan'] })
|
|
36
35
|
const shaft = {
|
|
37
36
|
object: 'node',
|
|
@@ -70,7 +69,7 @@ beforeEach(async () => {
|
|
|
70
69
|
category: 'structure',
|
|
71
70
|
defaults: () => ({}),
|
|
72
71
|
capabilities: {},
|
|
73
|
-
|
|
72
|
+
floorplanLinkedLevelIds: () => [level.id],
|
|
74
73
|
floorplan: () => ({ kind: 'rect', x: 3, y: 0, width: 1, height: 1 }),
|
|
75
74
|
} as unknown as AnyNodeDefinition,
|
|
76
75
|
],
|