@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
|
@@ -6,7 +6,7 @@ import { readFileSync } from 'node:fs'
|
|
|
6
6
|
// draft instead, so it only has to stay clear of drei fat lines.
|
|
7
7
|
for (const [file, drawsLines] of [
|
|
8
8
|
['./room-controls.tsx', false],
|
|
9
|
-
['
|
|
9
|
+
['../../../../viewer/src/ui/components/rooms/room-highlight.tsx', true],
|
|
10
10
|
['../../../../nodes/src/separator/renderer.tsx', true],
|
|
11
11
|
] as const) {
|
|
12
12
|
test(`${file} uses WebGPU node materials instead of drei fat lines`, () => {
|
|
@@ -35,6 +35,11 @@ import {
|
|
|
35
35
|
tintEmissive,
|
|
36
36
|
useViewer,
|
|
37
37
|
} from '@pascal-app/viewer'
|
|
38
|
+
import {
|
|
39
|
+
type SelectionModifierKeys,
|
|
40
|
+
sameRoom,
|
|
41
|
+
selectionModifiersFromEvent,
|
|
42
|
+
} from '@pascal-app/viewer/ui'
|
|
38
43
|
import { useThree } from '@react-three/fiber'
|
|
39
44
|
import { useCallback, useEffect, useRef } from 'react'
|
|
40
45
|
import { type BufferGeometry, Color, type Material, type Mesh, type Object3D, Vector3 } from 'three'
|
|
@@ -105,7 +110,6 @@ import {
|
|
|
105
110
|
usePaintOutline,
|
|
106
111
|
} from '../../lib/plate-paint-affected'
|
|
107
112
|
import { getHoveredRoofSegmentOutlineProxy } from '../../lib/roof-hover-outline-proxy'
|
|
108
|
-
import { sameRoom } from '../../lib/room-selection'
|
|
109
113
|
import { selectRoom, shouldInterceptRoom } from '../../lib/room-selection-commands'
|
|
110
114
|
import { roomKeyForZone } from '../../lib/room-zone-routing'
|
|
111
115
|
import {
|
|
@@ -114,8 +118,6 @@ import {
|
|
|
114
118
|
resolveCanvasBuildingId,
|
|
115
119
|
resolveCanvasSelectionNode,
|
|
116
120
|
resolveSelectedIdsForNodeClick,
|
|
117
|
-
type SelectionModifierKeys,
|
|
118
|
-
selectionModifiersFromEvent,
|
|
119
121
|
shouldPreserveSelectedRoofHostTarget,
|
|
120
122
|
} from '../../lib/selection-routing'
|
|
121
123
|
import { emitDeleteSFX, sfxEmitter } from '../../lib/sfx-bus'
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
3
|
import type { SiteNode } from '@pascal-app/core'
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
formatLinearMeasurement,
|
|
6
|
+
sceneRegistry,
|
|
7
|
+
useLiveNodeOverrides,
|
|
8
|
+
useScene,
|
|
9
|
+
} from '@pascal-app/core'
|
|
5
10
|
import { getSceneTheme, useViewer } from '@pascal-app/viewer'
|
|
11
|
+
import { LocalizedHtml as Html } from '@pascal-app/viewer/ui'
|
|
6
12
|
import { createPortal, useFrame, useThree } from '@react-three/fiber'
|
|
7
13
|
import { useCallback, useMemo, useRef, useState } from 'react'
|
|
8
14
|
import { type Camera, type Object3D, Vector3 } from 'three'
|
|
9
15
|
import { groundHeightAt } from '../../lib/ground-surface'
|
|
10
|
-
import { formatLinearMeasurement } from '../../lib/measurements'
|
|
11
16
|
import { SITE_BOUNDARY_DRAG_LABEL } from '../../lib/site-boundary'
|
|
12
17
|
import { useActiveHandleDrag } from '../../store/use-interaction-scope'
|
|
13
|
-
import { Html } from './localized-html'
|
|
14
18
|
|
|
15
19
|
type ViewportSize = {
|
|
16
20
|
width: number
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
3
|
import { emitter, type SnapshotSavedEvent } from '@pascal-app/core'
|
|
4
|
-
import { SNAPSHOT_MAX_EDGE } from '@pascal-app/viewer'
|
|
4
|
+
import { isTypingTarget, SNAPSHOT_MAX_EDGE } from '@pascal-app/viewer'
|
|
5
|
+
import { useFirstPersonHud, useIsMobile, WalkthroughCrosshair } from '@pascal-app/viewer/ui'
|
|
5
6
|
import {
|
|
6
7
|
Check,
|
|
7
8
|
Crop,
|
|
@@ -16,9 +17,7 @@ import {
|
|
|
16
17
|
} from 'lucide-react'
|
|
17
18
|
import { useCallback, useEffect, useRef, useState } from 'react'
|
|
18
19
|
import { flushSync } from 'react-dom'
|
|
19
|
-
import { useIsMobile } from '../../hooks/use-mobile'
|
|
20
20
|
import { triggerSFX } from '../../lib/sfx-bus'
|
|
21
|
-
import { isTypingTarget } from '../../lib/typing-target'
|
|
22
21
|
import { requestWalkthroughPointerLock } from '../../lib/walkthrough-pointer-lock'
|
|
23
22
|
import useEditor, {
|
|
24
23
|
CAPTURE_FOV_MAX,
|
|
@@ -27,9 +26,7 @@ import useEditor, {
|
|
|
27
26
|
type SnapshotCropMode,
|
|
28
27
|
type SnapshotStandardAspect,
|
|
29
28
|
} from '../../store/use-editor'
|
|
30
|
-
import { useFirstPersonHud } from '../../store/use-first-person-hud'
|
|
31
29
|
import { Slider } from '../ui/slider'
|
|
32
|
-
import { WalkthroughCrosshair } from '../walkthrough-hud'
|
|
33
30
|
import { CaptureLevelPicker } from './capture-level-picker'
|
|
34
31
|
import { isOverlaySnapshotSave } from './snapshot-capture'
|
|
35
32
|
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import {
|
|
4
4
|
emitter,
|
|
5
5
|
type FenceNode,
|
|
6
|
+
getPlanPointDistance,
|
|
6
7
|
isCurvedWall,
|
|
7
8
|
nodeRegistry,
|
|
8
9
|
type WallNode,
|
|
@@ -14,7 +15,7 @@ import {
|
|
|
14
15
|
useSyncExternalStore,
|
|
15
16
|
} from 'react'
|
|
16
17
|
import { resolveCeilingPlanPointSnap } from '../../lib/ceiling-plan-snap'
|
|
17
|
-
import { alignFloorplanDraftPoint
|
|
18
|
+
import { alignFloorplanDraftPoint } from '../../lib/floorplan'
|
|
18
19
|
import { resolveGenericFloorplanGridEventPoint } from '../../lib/floorplan-grid-event-point'
|
|
19
20
|
import { snapRegisteredDraftPoint } from '../../lib/registered-draft-snap'
|
|
20
21
|
import { resolveSlabPlanPointSnap } from '../../lib/slab-plan-snap'
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
3
|
import { useScene } from '@pascal-app/core'
|
|
4
|
+
import { Button } from '@pascal-app/viewer/ui'
|
|
4
5
|
import {
|
|
5
6
|
Check,
|
|
6
7
|
ChevronRight,
|
|
@@ -31,7 +32,6 @@ import { cn } from '../../../lib/utils'
|
|
|
31
32
|
import useEditor from '../../../store/use-editor'
|
|
32
33
|
import { IconRefGlyph } from '../../ui/icon-ref'
|
|
33
34
|
import { Badge } from '../../ui/primitives/badge'
|
|
34
|
-
import { Button } from '../../ui/primitives/button'
|
|
35
35
|
import { PLUGINS_VIEW_ID } from './use-editor-views'
|
|
36
36
|
|
|
37
37
|
const PLUGIN_AUTHORING_URL = 'https://editor.pascal.app/docs/developers/plugins'
|
|
@@ -2,14 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
import { type MessageDescriptor, type PascalI18n, usePascalI18n } from '@pascal-app/core'
|
|
4
4
|
import { type GroundMode, useViewer } from '@pascal-app/viewer'
|
|
5
|
-
import { ArrowLeftRight, Check, Columns2, MoreHorizontal, Pin, PinOff, X } from 'lucide-react'
|
|
6
|
-
import { type ReactNode, useEffect, useRef } from 'react'
|
|
7
|
-
import { useIsMobile } from '../../../hooks/use-mobile'
|
|
8
|
-
import { type EditorViewDescriptor, isSceneView, isViewPinned } from '../../../lib/editor-views'
|
|
9
|
-
import { cn } from '../../../lib/utils'
|
|
10
|
-
import useEditor from '../../../store/use-editor'
|
|
11
|
-
import { VIEW_2D, VIEW_3D, type ViewPaneIndex } from '../../../store/view-layout'
|
|
12
|
-
import { IconRefGlyph } from '../../ui/icon-ref'
|
|
13
5
|
import {
|
|
14
6
|
DropdownMenu,
|
|
15
7
|
DropdownMenuContent,
|
|
@@ -17,7 +9,15 @@ import {
|
|
|
17
9
|
DropdownMenuLabel,
|
|
18
10
|
DropdownMenuSeparator,
|
|
19
11
|
DropdownMenuTrigger,
|
|
20
|
-
|
|
12
|
+
useIsMobile,
|
|
13
|
+
} from '@pascal-app/viewer/ui'
|
|
14
|
+
import { ArrowLeftRight, Check, Columns2, MoreHorizontal, Pin, PinOff, X } from 'lucide-react'
|
|
15
|
+
import { type ReactNode, useEffect, useRef } from 'react'
|
|
16
|
+
import { type EditorViewDescriptor, isSceneView, isViewPinned } from '../../../lib/editor-views'
|
|
17
|
+
import { cn } from '../../../lib/utils'
|
|
18
|
+
import useEditor from '../../../store/use-editor'
|
|
19
|
+
import { VIEW_2D, VIEW_3D, type ViewPaneIndex } from '../../../store/view-layout'
|
|
20
|
+
import { IconRefGlyph } from '../../ui/icon-ref'
|
|
21
21
|
import { PLUGINS_VIEW_ID, useActiveViewLayout, useEditorViews } from './use-editor-views'
|
|
22
22
|
|
|
23
23
|
const GROUP = cn(
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
type AnyNode,
|
|
5
5
|
type AnyNodeId,
|
|
6
6
|
calculateLevelMiters,
|
|
7
|
+
formatLinearMeasurement,
|
|
7
8
|
getWallCurveLength,
|
|
8
9
|
getWallEffectiveHeightForNodes,
|
|
9
10
|
getWallMiterBoundaryPoints,
|
|
@@ -20,11 +21,10 @@ import {
|
|
|
20
21
|
type WallNode,
|
|
21
22
|
} from '@pascal-app/core'
|
|
22
23
|
import { getSceneTheme, useViewer } from '@pascal-app/viewer'
|
|
24
|
+
import { LocalizedHtml as Html } from '@pascal-app/viewer/ui'
|
|
23
25
|
import { createPortal, useFrame } from '@react-three/fiber'
|
|
24
26
|
import { useMemo, useState } from 'react'
|
|
25
27
|
import * as THREE from 'three'
|
|
26
|
-
import { formatLinearMeasurement } from '../../lib/measurements'
|
|
27
|
-
import { Html } from './localized-html'
|
|
28
28
|
|
|
29
29
|
const GUIDE_Y_OFFSET = 0.08
|
|
30
30
|
const LABEL_LIFT = 0.08
|
|
@@ -315,16 +315,25 @@ function buildMeasurementGuide(
|
|
|
315
315
|
const measurementPoints = measurementLine ?? fallbackMiddlePoints
|
|
316
316
|
if (!measurementPoints) return null
|
|
317
317
|
|
|
318
|
-
const
|
|
318
|
+
const heightStart = getWallEffectiveHeightForNodes(wall, nodes, 0)
|
|
319
|
+
const heightEnd = getWallEffectiveHeightForNodes(wall, nodes, 1)
|
|
319
320
|
const startLocal = worldPointToWallLocal(wall, measurementPoints.start)
|
|
320
321
|
const endLocal = worldPointToWallLocal(wall, measurementPoints.end)
|
|
321
322
|
const curvedMeasurementPath = isCurvedWall(wall)
|
|
322
323
|
? getCurvedWallMeasurementPath(wall, miterData, levelWalls)
|
|
323
324
|
: null
|
|
325
|
+
const dx = wall.end[0] - wall.start[0]
|
|
326
|
+
const dz = wall.end[1] - wall.start[1]
|
|
327
|
+
const wallChordLength = Math.hypot(dx, dz)
|
|
328
|
+
const getChordT = (localX: number) =>
|
|
329
|
+
wallChordLength > 1e-6 ? Math.max(0, Math.min(1, localX / wallChordLength)) : 0
|
|
330
|
+
|
|
324
331
|
const guidePath: Vec3[] = curvedMeasurementPath
|
|
325
332
|
? curvedMeasurementPath.map((point) => {
|
|
326
333
|
const localPoint = worldPointToWallLocal(wall, point)
|
|
327
|
-
|
|
334
|
+
const t = getChordT(localPoint[0])
|
|
335
|
+
const h = getWallEffectiveHeightForNodes(wall, nodes, t)
|
|
336
|
+
return [localPoint[0], h + GUIDE_Y_OFFSET, localPoint[2]]
|
|
328
337
|
})
|
|
329
338
|
: isCurvedWall(wall)
|
|
330
339
|
? sampleWallCenterline(wall, 24).map((point, index, points) => {
|
|
@@ -334,12 +343,14 @@ function buildMeasurementGuide(
|
|
|
334
343
|
: index === points.length - 1
|
|
335
344
|
? endLocal
|
|
336
345
|
: worldPointToWallLocal(wall, point)
|
|
346
|
+
const t = getChordT(localPoint[0])
|
|
347
|
+
const h = getWallEffectiveHeightForNodes(wall, nodes, t)
|
|
337
348
|
|
|
338
|
-
return [localPoint[0],
|
|
349
|
+
return [localPoint[0], h + GUIDE_Y_OFFSET, localPoint[2]]
|
|
339
350
|
})
|
|
340
351
|
: [
|
|
341
|
-
[startLocal[0],
|
|
342
|
-
[endLocal[0],
|
|
352
|
+
[startLocal[0], heightStart + GUIDE_Y_OFFSET, startLocal[2]],
|
|
353
|
+
[endLocal[0], heightEnd + GUIDE_Y_OFFSET, endLocal[2]],
|
|
343
354
|
]
|
|
344
355
|
|
|
345
356
|
if (guidePath.length < 2) return null
|
|
@@ -397,26 +408,30 @@ function buildMeasurementGuide(
|
|
|
397
408
|
],
|
|
398
409
|
})
|
|
399
410
|
const bottomHeightTick = getHorizontalHeightTick(0)
|
|
400
|
-
const topHeightTick = getHorizontalHeightTick(
|
|
411
|
+
const topHeightTick = getHorizontalHeightTick(heightEnd)
|
|
401
412
|
|
|
402
413
|
return {
|
|
403
414
|
guidePath,
|
|
404
|
-
extStartStart: [extensionStartBase[0],
|
|
415
|
+
extStartStart: [extensionStartBase[0], heightStart, extensionStartBase[2]],
|
|
405
416
|
extStartEnd: [
|
|
406
417
|
extensionStartBase[0],
|
|
407
|
-
|
|
418
|
+
heightStart + GUIDE_Y_OFFSET + extOvershoot,
|
|
408
419
|
extensionStartBase[2],
|
|
409
420
|
],
|
|
410
|
-
extEndStart: [extensionEndBase[0],
|
|
411
|
-
extEndEnd: [
|
|
421
|
+
extEndStart: [extensionEndBase[0], heightEnd, extensionEndBase[2]],
|
|
422
|
+
extEndEnd: [
|
|
423
|
+
extensionEndBase[0],
|
|
424
|
+
heightEnd + GUIDE_Y_OFFSET + extOvershoot,
|
|
425
|
+
extensionEndBase[2],
|
|
426
|
+
],
|
|
412
427
|
labelPosition: [midpoint[0], midpoint[1] + LABEL_LIFT, midpoint[2]],
|
|
413
428
|
heightStart: [heightGuidePosition[0], 0, heightGuidePosition[2]],
|
|
414
|
-
heightEnd: [heightGuidePosition[0],
|
|
429
|
+
heightEnd: [heightGuidePosition[0], heightEnd, heightGuidePosition[2]],
|
|
415
430
|
heightBottomTickStart: bottomHeightTick.start,
|
|
416
431
|
heightBottomTickEnd: bottomHeightTick.end,
|
|
417
432
|
heightTopTickStart: topHeightTick.start,
|
|
418
433
|
heightTopTickEnd: topHeightTick.end,
|
|
419
|
-
heightLabelPosition: [heightGuidePosition[0],
|
|
434
|
+
heightLabelPosition: [heightGuidePosition[0], heightEnd / 2, heightGuidePosition[2]],
|
|
420
435
|
}
|
|
421
436
|
}
|
|
422
437
|
|
|
@@ -530,7 +545,8 @@ function WallMeasurementAnnotation({ wall }: { wall: WallNode }) {
|
|
|
530
545
|
return total
|
|
531
546
|
}, [guide, wall])
|
|
532
547
|
const label = formatLinearMeasurement(length, unit, metricNotation)
|
|
533
|
-
|
|
548
|
+
// Height annotation uses t=1 (wall end) because the vertical guide is drawn at the endpoint
|
|
549
|
+
const height = useMemo(() => getWallEffectiveHeightForNodes(wall, nodes, 1), [nodes, wall])
|
|
534
550
|
const heightLabel = `H ${formatLinearMeasurement(height, unit, metricNotation)}`
|
|
535
551
|
|
|
536
552
|
if (!(guide && Number.isFinite(length) && length >= 0.01)) return null
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
type WallNode,
|
|
20
20
|
} from '@pascal-app/core'
|
|
21
21
|
import { useViewer } from '@pascal-app/viewer'
|
|
22
|
+
import { LocalizedHtml as Html } from '@pascal-app/viewer/ui'
|
|
22
23
|
import { createPortal, type ThreeEvent, useFrame, useThree } from '@react-three/fiber'
|
|
23
24
|
import { useEffect, useMemo, useRef, useState } from 'react'
|
|
24
25
|
import {
|
|
@@ -60,7 +61,6 @@ import useInteractionScope, {
|
|
|
60
61
|
import { suppressBoxSelectForPointer } from '../tools/select/box-select-state'
|
|
61
62
|
import { resolveResizeSnapValue } from './handles/resize-snap'
|
|
62
63
|
import { type HandleDragControls, useHandleDrag } from './handles/use-handle-drag'
|
|
63
|
-
import { Html } from './localized-html'
|
|
64
64
|
import { MeasurementPill } from './measurement-pill'
|
|
65
65
|
import {
|
|
66
66
|
createArrowHitAreaGeometry,
|
|
@@ -301,7 +301,7 @@ function StructureThicknessHandle({
|
|
|
301
301
|
const structureHeight =
|
|
302
302
|
node.type === 'fence'
|
|
303
303
|
? (node.height ?? 1.8)
|
|
304
|
-
: getWallEffectiveHeightForNodes(node, useScene.getState().nodes)
|
|
304
|
+
: getWallEffectiveHeightForNodes(node, useScene.getState().nodes, 0.5)
|
|
305
305
|
const outward = new Vector2(frame.normal.x * side, frame.normal.y * side)
|
|
306
306
|
const faceOffset = getWallLocalFaceZ({ ...node, thickness }, side > 0 ? 'a' : 'b') * side + 0.006
|
|
307
307
|
const position: [number, number, number] = [
|
|
@@ -375,7 +375,7 @@ function StructureThicknessHandle({
|
|
|
375
375
|
const initialStructureHeight =
|
|
376
376
|
initialNode.type === 'fence'
|
|
377
377
|
? (initialNode.height ?? 1.8)
|
|
378
|
-
: getWallEffectiveHeightForNodes(initialNode, useScene.getState().nodes)
|
|
378
|
+
: getWallEffectiveHeightForNodes(initialNode, useScene.getState().nodes, 0.5)
|
|
379
379
|
const initialStructureThickness =
|
|
380
380
|
initialNode.type === 'fence'
|
|
381
381
|
? (initialNode.thickness ?? 0.08)
|
|
@@ -578,7 +578,11 @@ function WallCornerLeaderHandle({ wall, endpoint }: { wall: WallNode; endpoint:
|
|
|
578
578
|
const corner = endpoint === 'start' ? wall.start : wall.end
|
|
579
579
|
const x = corner[0]
|
|
580
580
|
const z = corner[1]
|
|
581
|
-
const wallHeight = getWallEffectiveHeightForNodes(
|
|
581
|
+
const wallHeight = getWallEffectiveHeightForNodes(
|
|
582
|
+
wall,
|
|
583
|
+
useScene.getState().nodes,
|
|
584
|
+
endpoint === 'start' ? 0 : 1,
|
|
585
|
+
)
|
|
582
586
|
|
|
583
587
|
const dashedGeometry = useMemo(() => buildDashedVerticalGeometry(wallHeight), [wallHeight])
|
|
584
588
|
const hitGeometry = useMemo(() => createEndpointHitAreaGeometry(CORNER_HEX_RADIUS), [])
|
|
@@ -784,7 +788,7 @@ function WallBaseElevationHandle({
|
|
|
784
788
|
levelObject.updateWorldMatrix(true, false)
|
|
785
789
|
const initialBase = getWallBaseElevationForNodes(initialNode, sceneApi.nodes())
|
|
786
790
|
const supportBase = initialBase - (initialNode.supportOffset ?? 0)
|
|
787
|
-
const initialHeight = getWallEffectiveHeightForNodes(initialNode, sceneApi.nodes())
|
|
791
|
+
const initialHeight = getWallEffectiveHeightForNodes(initialNode, sceneApi.nodes(), 0)
|
|
788
792
|
const midpointWorld = new Vector3(midpoint[0], initialBase, midpoint[1]).applyMatrix4(
|
|
789
793
|
levelObject.matrixWorld,
|
|
790
794
|
)
|
|
@@ -920,7 +924,7 @@ function WallHeightArrowHandle({ wall }: { wall: WallNode }) {
|
|
|
920
924
|
const wallAngle = Math.atan2(-dirZ, dirX)
|
|
921
925
|
// `wall` is the override-merged effective wall (see
|
|
922
926
|
// WallMoveSideHandlesForWall), so this height is already live during a drag.
|
|
923
|
-
const wallHeight = getWallEffectiveHeightForNodes(wall, useScene.getState().nodes)
|
|
927
|
+
const wallHeight = getWallEffectiveHeightForNodes(wall, useScene.getState().nodes, 0.5)
|
|
924
928
|
const handleY = wallHeight + HEIGHT_HANDLE_OFFSET
|
|
925
929
|
|
|
926
930
|
const activateHeightResize = (event: ThreeEvent<PointerEvent>) => {
|
|
@@ -973,7 +977,7 @@ function WallHeightArrowHandle({ wall }: { wall: WallNode }) {
|
|
|
973
977
|
|
|
974
978
|
// Dragging the top makes the wall custom-height; seed from the resolved
|
|
975
979
|
// effective height so a plane-bound wall's drag starts at its real top.
|
|
976
|
-
const initialHeight = getWallEffectiveHeightForNodes(wall, useScene.getState().nodes)
|
|
980
|
+
const initialHeight = getWallEffectiveHeightForNodes(wall, useScene.getState().nodes, 0)
|
|
977
981
|
const wallId = wall.id as AnyNodeId
|
|
978
982
|
let pendingHeight = initialHeight
|
|
979
983
|
let releaseSpatialCapture: (() => void) | null = null
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
-
import { nodeRegistry, type WallNode } from '@pascal-app/core'
|
|
3
|
+
import { nodeRegistry, WALL_PULL_GRIP_TITLE, type WallNode, wallPullSeed } from '@pascal-app/core'
|
|
4
4
|
import { type ThreeEvent, useThree } from '@react-three/fiber'
|
|
5
5
|
import { useEffect, useMemo, useState } from 'react'
|
|
6
6
|
import { Color, DoubleSide, ExtrudeGeometry, OrthographicCamera, Shape } from 'three'
|
|
7
7
|
import { MeshBasicNodeMaterial } from 'three/webgpu'
|
|
8
8
|
import { EDITOR_LAYER } from '../../lib/constants'
|
|
9
9
|
import { sfxEmitter } from '../../lib/sfx-bus'
|
|
10
|
-
import { startWallPull
|
|
10
|
+
import { startWallPull } from '../../lib/wall-pull'
|
|
11
11
|
import { suppressBoxSelectForPointer } from '../tools/select/box-select-state'
|
|
12
12
|
import {
|
|
13
13
|
createEndpointHitAreaGeometry,
|
|
@@ -203,7 +203,7 @@ function WallRegionHandlesForWall({ wall }: { wall: WallNode }) {
|
|
|
203
203
|
const frame: WallFrame = {
|
|
204
204
|
wall: effectiveWall,
|
|
205
205
|
baseElevation: getWallBaseElevationForNodes(effectiveWall, nodes),
|
|
206
|
-
wallHeight: getWallEffectiveHeightForNodes(effectiveWall, nodes),
|
|
206
|
+
wallHeight: getWallEffectiveHeightForNodes(effectiveWall, nodes, 0.5),
|
|
207
207
|
angle: Math.atan2(
|
|
208
208
|
effectiveWall.end[1] - effectiveWall.start[1],
|
|
209
209
|
effectiveWall.end[0] - effectiveWall.start[0],
|
|
@@ -426,7 +426,7 @@ function RegionEdgeHandle({
|
|
|
426
426
|
const face = region.face
|
|
427
427
|
const faceSurface = getWallFaceSurface(initialNode, face)
|
|
428
428
|
const baseAt = faceBaseSampler(initialNode.id, face)
|
|
429
|
-
const wallHeight = getWallEffectiveHeightForNodes(initialNode, nodes)
|
|
429
|
+
const wallHeight = getWallEffectiveHeightForNodes(initialNode, nodes, 0.5)
|
|
430
430
|
const faceHeight = regionFaceHeight(region, faceSurface.length, wallHeight, baseAt)
|
|
431
431
|
const bounds = resolveRegionBounds(region, faceSurface.length, faceHeight)
|
|
432
432
|
const midU = (bounds.u0 + bounds.u1) / 2
|
|
@@ -165,9 +165,10 @@ type WallTopHighlightSegment = {
|
|
|
165
165
|
angle: number
|
|
166
166
|
center: [number, number]
|
|
167
167
|
length: number
|
|
168
|
+
tCenter: number
|
|
168
169
|
}
|
|
169
170
|
|
|
170
|
-
function getWallTopY(wall: WallNode, nodes: Readonly<Record<string, AnyNode
|
|
171
|
+
function getWallTopY(wall: WallNode, nodes: Readonly<Record<string, AnyNode>>, t = 0.5): number {
|
|
171
172
|
const levelId = resolveLevelId(wall, nodes as Record<string, AnyNode>)
|
|
172
173
|
const support = spatialGridManager.getSlabSupportForWall(
|
|
173
174
|
levelId,
|
|
@@ -181,12 +182,16 @@ function getWallTopY(wall: WallNode, nodes: Readonly<Record<string, AnyNode>>) {
|
|
|
181
182
|
wall.justification,
|
|
182
183
|
)
|
|
183
184
|
return (
|
|
184
|
-
getWallTop(wall, levelId, nodes as Record<string, AnyNode>, support.elevation) +
|
|
185
|
+
getWallTop(wall, levelId, nodes as Record<string, AnyNode>, support.elevation, t) +
|
|
185
186
|
WALL_TOP_HIGHLIGHT_LIFT
|
|
186
187
|
)
|
|
187
188
|
}
|
|
188
189
|
|
|
189
|
-
function buildHighlightSegment(
|
|
190
|
+
function buildHighlightSegment(
|
|
191
|
+
start: [number, number],
|
|
192
|
+
end: [number, number],
|
|
193
|
+
tCenter = 0.5,
|
|
194
|
+
): WallTopHighlightSegment | null {
|
|
190
195
|
const dx = end[0] - start[0]
|
|
191
196
|
const dz = end[1] - start[1]
|
|
192
197
|
const length = Math.hypot(dx, dz)
|
|
@@ -196,15 +201,20 @@ function buildHighlightSegment(start: [number, number], end: [number, number]) {
|
|
|
196
201
|
angle: -Math.atan2(dz, dx),
|
|
197
202
|
center: [(start[0] + end[0]) / 2, (start[1] + end[1]) / 2] as [number, number],
|
|
198
203
|
length,
|
|
204
|
+
tCenter,
|
|
199
205
|
}
|
|
200
206
|
}
|
|
201
207
|
|
|
202
208
|
function buildWallTopHighlightSegments(wall: WallNode): WallTopHighlightSegment[] {
|
|
203
209
|
if (!isCurvedWall(wall)) {
|
|
204
|
-
const segment = buildHighlightSegment(wall.start, wall.end)
|
|
210
|
+
const segment = buildHighlightSegment(wall.start, wall.end, 0.5)
|
|
205
211
|
return segment ? [segment] : []
|
|
206
212
|
}
|
|
207
213
|
|
|
214
|
+
const dx = wall.end[0] - wall.start[0]
|
|
215
|
+
const dz = wall.end[1] - wall.start[1]
|
|
216
|
+
const chordLenSq = dx * dx + dz * dz
|
|
217
|
+
|
|
208
218
|
const sampleCount = Math.max(
|
|
209
219
|
8,
|
|
210
220
|
Math.ceil(getWallCurveLength(wall) / CURVED_WALL_HIGHLIGHT_SEGMENT_LENGTH),
|
|
@@ -213,7 +223,16 @@ function buildWallTopHighlightSegments(wall: WallNode): WallTopHighlightSegment[
|
|
|
213
223
|
let previous = getWallCurveFrameAt(wall, 0).point
|
|
214
224
|
for (let index = 1; index <= sampleCount; index += 1) {
|
|
215
225
|
const current = getWallCurveFrameAt(wall, index / sampleCount).point
|
|
216
|
-
const
|
|
226
|
+
const midX = (previous.x + current.x) / 2
|
|
227
|
+
const midY = (previous.y + current.y) / 2
|
|
228
|
+
const tCenter =
|
|
229
|
+
chordLenSq > 1e-12
|
|
230
|
+
? Math.max(
|
|
231
|
+
0,
|
|
232
|
+
Math.min(1, ((midX - wall.start[0]) * dx + (midY - wall.start[1]) * dz) / chordLenSq),
|
|
233
|
+
)
|
|
234
|
+
: 0.5
|
|
235
|
+
const segment = buildHighlightSegment([previous.x, previous.y], [current.x, current.y], tCenter)
|
|
217
236
|
if (segment) segments.push(segment)
|
|
218
237
|
previous = current
|
|
219
238
|
}
|
|
@@ -228,38 +247,40 @@ function WallTopHighlight({
|
|
|
228
247
|
wall: WallNode
|
|
229
248
|
}) {
|
|
230
249
|
const segments = useMemo(() => buildWallTopHighlightSegments(wall), [wall])
|
|
231
|
-
const y = getWallTopY(wall, nodes)
|
|
232
250
|
const width = Math.max(getWallThickness(wall) + WALL_TOP_HIGHLIGHT_OVERHANG, 0.24)
|
|
233
251
|
const glowWidth = Math.max(getWallThickness(wall) + WALL_TOP_GLOW_OVERHANG, 0.42)
|
|
234
252
|
|
|
235
253
|
return (
|
|
236
254
|
<>
|
|
237
|
-
{segments.map((segment, index) =>
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
255
|
+
{segments.map((segment, index) => {
|
|
256
|
+
const y = getWallTopY(wall, nodes, segment.tCenter)
|
|
257
|
+
return (
|
|
258
|
+
<group key={`${wall.id}:${index}`}>
|
|
259
|
+
<mesh
|
|
260
|
+
frustumCulled={false}
|
|
261
|
+
geometry={WALL_TOP_HIGHLIGHT_GEOMETRY}
|
|
262
|
+
layers={EDITOR_LAYER}
|
|
263
|
+
material={wallTopHighlightGlowMaterial}
|
|
264
|
+
position={[segment.center[0], y - 0.003, segment.center[1]]}
|
|
265
|
+
raycast={NO_RAYCAST}
|
|
266
|
+
renderOrder={1003}
|
|
267
|
+
rotation={[0, segment.angle, 0]}
|
|
268
|
+
scale={[segment.length + WALL_TOP_END_OVERHANG, WALL_TOP_GLOW_HEIGHT, glowWidth]}
|
|
269
|
+
/>
|
|
270
|
+
<mesh
|
|
271
|
+
frustumCulled={false}
|
|
272
|
+
geometry={WALL_TOP_HIGHLIGHT_GEOMETRY}
|
|
273
|
+
layers={EDITOR_LAYER}
|
|
274
|
+
material={wallTopHighlightMaterial}
|
|
275
|
+
position={[segment.center[0], y + 0.002, segment.center[1]]}
|
|
276
|
+
raycast={NO_RAYCAST}
|
|
277
|
+
renderOrder={1004}
|
|
278
|
+
rotation={[0, segment.angle, 0]}
|
|
279
|
+
scale={[segment.length + WALL_TOP_END_OVERHANG, WALL_TOP_HIGHLIGHT_HEIGHT, width]}
|
|
280
|
+
/>
|
|
281
|
+
</group>
|
|
282
|
+
)
|
|
283
|
+
})}
|
|
263
284
|
</>
|
|
264
285
|
)
|
|
265
286
|
}
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
DEFAULT_ANGLE_STEP,
|
|
9
9
|
type FloorplanGeometry,
|
|
10
10
|
type FloorplanPalette,
|
|
11
|
+
formatLinearMeasurement,
|
|
11
12
|
pauseSceneHistory,
|
|
12
13
|
pauseSpaceDetection,
|
|
13
14
|
resumeSceneHistory,
|
|
@@ -16,18 +17,17 @@ import {
|
|
|
16
17
|
useLiveTransforms,
|
|
17
18
|
useScene,
|
|
18
19
|
} from '@pascal-app/core'
|
|
19
|
-
import { useViewer } from '@pascal-app/viewer'
|
|
20
|
+
import { isTypingTarget, useViewer } from '@pascal-app/viewer'
|
|
21
|
+
import { FloorplanDimensionRenderer } from '@pascal-app/viewer/ui'
|
|
20
22
|
import { memo, type PointerEvent as ReactPointerEvent, useEffect, useMemo, useState } from 'react'
|
|
21
23
|
import { create } from 'zustand'
|
|
22
24
|
import { GROUP_MOVE_DRAG_LABEL, GROUP_ROTATE_DRAG_LABEL } from '../../lib/contextual-help'
|
|
23
25
|
import { applyFloorplanAlignment } from '../../lib/floorplan/apply-alignment'
|
|
24
26
|
import { clientToPlan } from '../../lib/floorplan/plan-coords'
|
|
25
27
|
import { isHistoryShortcut } from '../../lib/history'
|
|
26
|
-
import { formatLinearMeasurement } from '../../lib/measurements'
|
|
27
28
|
import type { WallGroupPush } from '../../lib/room-handle-drag'
|
|
28
29
|
import { useRoomHandleDrag } from '../../lib/room-handle-drag'
|
|
29
30
|
import { sfxEmitter } from '../../lib/sfx-bus'
|
|
30
|
-
import { isTypingTarget } from '../../lib/typing-target'
|
|
31
31
|
import useAlignmentGuides from '../../store/use-alignment-guides'
|
|
32
32
|
import useEditor, {
|
|
33
33
|
isAlignmentGuideActive,
|
|
@@ -55,7 +55,6 @@ import {
|
|
|
55
55
|
import { swallowNextClick } from '../editor/handles/use-handle-drag'
|
|
56
56
|
import { useMeshSettleEpoch } from '../editor/use-mesh-settle-epoch'
|
|
57
57
|
import { useFloorplanSceneRotation } from './floorplan-render-context'
|
|
58
|
-
import { FloorplanDimensionRenderer } from './renderers/floorplan-dimension-renderer'
|
|
59
58
|
|
|
60
59
|
// 2D sibling of the 3D body-drag group move (`group-move-3d.ts`): dragging
|
|
61
60
|
// any selected element of a multi-selection slides the whole selection
|
|
@@ -3,11 +3,17 @@
|
|
|
3
3
|
import {
|
|
4
4
|
type AnyNode,
|
|
5
5
|
type AnyNodeId,
|
|
6
|
+
buildMeasurementAngleArcPoints,
|
|
6
7
|
closestMeasurementFeatureBinding,
|
|
7
8
|
collectAlignmentAnchors,
|
|
8
9
|
emitter,
|
|
10
|
+
formatAngleRadians,
|
|
11
|
+
formatAreaLabel,
|
|
12
|
+
formatLinearMeasurement,
|
|
9
13
|
formatNumber,
|
|
14
|
+
formatVolumeLabel,
|
|
10
15
|
type GeometryContext,
|
|
16
|
+
getLinearUnitLabel,
|
|
11
17
|
type MeasurementFeatureAnchor,
|
|
12
18
|
type MeasurementSnapKind,
|
|
13
19
|
measurementAngle,
|
|
@@ -16,23 +22,19 @@ import {
|
|
|
16
22
|
measurementFeatureLength,
|
|
17
23
|
measurementPerimeter,
|
|
18
24
|
measurementPrismVolume,
|
|
25
|
+
metersToLinearUnit,
|
|
19
26
|
nodeRegistry,
|
|
27
|
+
parseLinearMeasurementInput,
|
|
20
28
|
useLocale,
|
|
21
29
|
useScene,
|
|
22
30
|
} from '@pascal-app/core'
|
|
23
|
-
import { useViewer } from '@pascal-app/viewer'
|
|
24
|
-
import { useEffect, useMemo, useRef, useState } from 'react'
|
|
25
|
-
import { measurementPolygonLabelAnchor } from '../../lib/measurement-label'
|
|
26
31
|
import {
|
|
27
|
-
buildMeasurementAngleArcPoints,
|
|
28
|
-
formatAreaLabel,
|
|
29
|
-
formatLinearMeasurement,
|
|
30
|
-
formatVolumeLabel,
|
|
31
|
-
getLinearUnitLabel,
|
|
32
32
|
MEASUREMENT_ACTIVE_COLOR,
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
} from '
|
|
33
|
+
measurementPolygonLabelAnchor,
|
|
34
|
+
useViewer,
|
|
35
|
+
} from '@pascal-app/viewer'
|
|
36
|
+
import { resolveFloorplanLabelAngle } from '@pascal-app/viewer/ui'
|
|
37
|
+
import { useEffect, useMemo, useRef, useState } from 'react'
|
|
36
38
|
import {
|
|
37
39
|
clearSurfacePlanSnapFeedback,
|
|
38
40
|
resolveSurfacePlanPointSnap,
|
|
@@ -45,10 +47,8 @@ import {
|
|
|
45
47
|
measurementPolygonMidpoints,
|
|
46
48
|
useMeasurementDraft,
|
|
47
49
|
} from '../../store/use-measurement-draft'
|
|
48
|
-
import { formatAngleRadians } from '../tools/shared/segment-angle'
|
|
49
50
|
import { FloorplanQuickMeasureLayer } from './floorplan-quick-measure-layer'
|
|
50
51
|
import { useFloorplanRender } from './floorplan-render-context'
|
|
51
|
-
import { resolveFloorplanLabelAngle } from './renderers/floorplan-label-angle'
|
|
52
52
|
|
|
53
53
|
const DRAFT_COLOR = MEASUREMENT_ACTIVE_COLOR
|
|
54
54
|
const X_AXIS_COLOR = '#ef4444'
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
3
|
import type { AnyNodeId, OpenWallEnd } from '@pascal-app/core'
|
|
4
|
-
import { useViewer } from '@pascal-app/viewer'
|
|
4
|
+
import { MEASUREMENT_DANGLING_COLOR, useViewer } from '@pascal-app/viewer'
|
|
5
|
+
import { resolveFloorplanLabelAngle } from '@pascal-app/viewer/ui'
|
|
5
6
|
import { memo, useEffect, useState } from 'react'
|
|
6
7
|
import { createPortal } from 'react-dom'
|
|
7
8
|
import {
|
|
@@ -10,13 +11,11 @@ import {
|
|
|
10
11
|
useOpenWallEndsSuppressed,
|
|
11
12
|
} from '../../hooks/use-open-wall-ends'
|
|
12
13
|
import { openWallEndKey, openWallEndLabel } from '../../lib/floorplan/open-wall-ends'
|
|
13
|
-
import { MEASUREMENT_DANGLING_COLOR } from '../../lib/measurements'
|
|
14
14
|
import useEditor from '../../store/use-editor'
|
|
15
15
|
import { isViewVisible, VIEW_2D } from '../../store/view-layout'
|
|
16
16
|
import { JoinWallsPill } from '../editor/join-walls-pill'
|
|
17
17
|
import { OpenWallEndsHint } from '../editor/open-wall-ends-hint'
|
|
18
18
|
import { useFloorplanRender } from './floorplan-render-context'
|
|
19
|
-
import { resolveFloorplanLabelAngle } from './renderers/floorplan-label-angle'
|
|
20
19
|
|
|
21
20
|
function sceneScreenPoint(point: [number, number]): { left: number; top: number } | null {
|
|
22
21
|
const scene = document.querySelector<SVGGElement>('[data-floorplan-scene]')
|