@pascal-app/editor 0.9.1 → 1.0.0-beta.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 +14 -9
- package/src/components/editor/alignment-3d-guide-layer.tsx +10 -2
- package/src/components/editor/bake-exporter.tsx +49 -0
- package/src/components/editor/bake-thumbnail.tsx +95 -0
- package/src/components/editor/camera-dragging-lifecycle.test.ts +49 -0
- package/src/components/editor/camera-dragging-lifecycle.ts +41 -0
- package/src/components/editor/custom-camera-controls.tsx +332 -199
- package/src/components/editor/delete-confirmation-dialog.tsx +54 -0
- package/src/components/editor/editor-layout-mobile.tsx +5 -0
- package/src/components/editor/editor-layout-v2.tsx +18 -0
- package/src/components/editor/elevation-3d-guide-layer.tsx +120 -0
- package/src/components/editor/export-manager.tsx +71 -63
- package/src/components/editor/fence-tangent-lines-3d.tsx +87 -0
- package/src/components/editor/first-person/build-collider-world.test.ts +102 -5
- package/src/components/editor/first-person/build-collider-world.ts +52 -5
- package/src/components/editor/first-person/terrain-collider.test.ts +132 -0
- package/src/components/editor/first-person/terrain-collider.ts +212 -0
- package/src/components/editor/first-person-controls.tsx +410 -136
- package/src/components/editor/floating-action-menu.tsx +435 -64
- package/src/components/editor/floating-building-action-menu.tsx +1 -1
- package/src/components/editor/floorplan-background-selection.test.ts +72 -0
- package/src/components/editor/floorplan-background-selection.ts +7 -20
- package/src/components/editor/floorplan-camera-sync.test.ts +249 -0
- package/src/components/editor/floorplan-camera-sync.ts +213 -0
- package/src/components/editor/floorplan-mode-coordinator.tsx +82 -0
- package/src/components/editor/floorplan-navigation-presentation.test.ts +142 -0
- package/src/components/editor/floorplan-navigation-presentation.ts +156 -0
- package/src/components/editor/floorplan-panel.tsx +2517 -1492
- package/src/components/editor/grid.tsx +166 -39
- package/src/components/editor/group-actions.ts +597 -0
- package/src/components/editor/group-floating-action-menu.tsx +130 -0
- package/src/components/editor/group-move-3d.ts +397 -0
- package/src/components/editor/group-rotate-handle.tsx +102 -64
- package/src/components/editor/group-selection-box-3d.tsx +173 -0
- package/src/components/editor/group-transform-shared.test.ts +192 -1
- package/src/components/editor/group-transform-shared.ts +240 -7
- package/src/components/editor/handles/handle-arrow.tsx +81 -23
- package/src/components/editor/handles/handle-drag-history.test.ts +96 -0
- package/src/components/editor/handles/handle-drag-history.ts +14 -0
- package/src/components/editor/handles/preview-overrides.test.ts +26 -0
- package/src/components/editor/handles/preview-overrides.ts +13 -0
- package/src/components/editor/handles/resize-snap.test.ts +52 -0
- package/src/components/editor/handles/resize-snap.ts +23 -0
- package/src/components/editor/handles/use-handle-drag.ts +49 -6
- package/src/components/editor/index.tsx +289 -35
- package/src/components/editor/measurement-pill.tsx +68 -23
- package/src/components/editor/node-action-menu.tsx +14 -1
- package/src/components/editor/node-arrow-handles.tsx +409 -180
- package/src/components/editor/opening-guides-3d-layer.tsx +144 -0
- package/src/components/editor/quick-measurement-card.tsx +76 -0
- package/src/components/editor/quick-measurement-hud.tsx +34 -0
- package/src/components/editor/riser-diagram-panel.tsx +137 -0
- package/src/components/editor/selection-manager.tsx +814 -466
- package/src/components/editor/site-edge-labels.tsx +28 -6
- package/src/components/editor/slab-hole-highlights.tsx +13 -5
- package/src/components/editor/snapshot-capture-overlay.tsx +258 -115
- package/src/components/editor/three-context-bridge.ts +22 -0
- package/src/components/editor/thumbnail-generator.tsx +118 -253
- package/src/components/editor/use-floorplan-background-placement.ts +113 -45
- package/src/components/editor/use-floorplan-hit-testing.test.ts +82 -0
- package/src/components/editor/use-floorplan-hit-testing.ts +144 -161
- package/src/components/editor/use-floorplan-scene-data.ts +5 -5
- package/src/components/editor/use-mesh-settle-epoch.ts +27 -0
- package/src/components/editor/wall-measurement-label.tsx +10 -28
- package/src/components/editor/wall-move-side-handles.tsx +229 -39
- package/src/components/editor/wall-opening-highlights.tsx +63 -32
- package/src/components/editor/wall-snap-beacon-layer.tsx +162 -6
- package/src/components/editor-2d/floorplan-action-menu-layer.tsx +9 -5
- package/src/components/editor-2d/floorplan-alignment-guide-layer.tsx +2 -1
- package/src/components/editor-2d/floorplan-cursor-indicator-overlay.tsx +40 -9
- package/src/components/editor-2d/floorplan-cursor-indicator-position.test.ts +31 -0
- package/src/components/editor-2d/floorplan-cursor-indicator-position.ts +39 -0
- package/src/components/editor-2d/floorplan-group-action-menu.tsx +87 -0
- package/src/components/editor-2d/floorplan-group-move.tsx +744 -0
- package/src/components/editor-2d/floorplan-measurement-tool-layer.test.ts +113 -0
- package/src/components/editor-2d/floorplan-measurement-tool-layer.tsx +1672 -0
- package/src/components/editor-2d/floorplan-quick-measure-layer.tsx +212 -0
- package/src/components/editor-2d/floorplan-registered-tool-layer.tsx +72 -0
- package/src/components/editor-2d/floorplan-registry-action-menu.tsx +219 -20
- package/src/components/editor-2d/floorplan-registry-move-overlay.tsx +327 -59
- package/src/components/editor-2d/floorplan-render-context.test.ts +27 -0
- package/src/components/editor-2d/floorplan-render-context.tsx +113 -8
- package/src/components/editor-2d/floorplan-snap-beacon-layer.tsx +5 -3
- package/src/components/editor-2d/renderers/floorplan-annotation-layout.test.ts +285 -0
- package/src/components/editor-2d/renderers/floorplan-annotation-layout.ts +516 -0
- package/src/components/editor-2d/renderers/floorplan-dimension-renderer.test.tsx +236 -0
- package/src/components/editor-2d/renderers/floorplan-dimension-renderer.tsx +618 -0
- package/src/components/editor-2d/renderers/floorplan-geometry-renderer.test.tsx +369 -0
- package/src/components/editor-2d/renderers/floorplan-geometry-renderer.tsx +431 -32
- package/src/components/editor-2d/renderers/floorplan-label-angle.test.ts +89 -0
- package/src/components/editor-2d/renderers/floorplan-label-angle.ts +106 -0
- package/src/components/editor-2d/renderers/floorplan-placement-preview-layer.tsx +94 -26
- package/src/components/editor-2d/renderers/floorplan-registry-layer.test.ts +587 -0
- package/src/components/editor-2d/renderers/floorplan-registry-layer.tsx +2280 -578
- package/src/components/editor-2d/renderers/floorplan-stair-layer.tsx +20 -10
- package/src/components/editor-2d/renderers/floorplan-voronoi-layer.tsx +128 -0
- package/src/components/systems/ceiling/ceiling-selection-affordance-system.tsx +425 -61
- package/src/components/systems/ceiling/ceiling-system.tsx +97 -4
- package/src/components/systems/roof/roof-edit-system.tsx +1768 -13
- package/src/components/systems/selection-affordance-manager.tsx +38 -0
- package/src/components/systems/zone/zone-label-editor-system.tsx +14 -1
- package/src/components/systems/zone/zone-system.tsx +42 -13
- package/src/components/tools/elevator/elevator-tool.tsx +34 -8
- package/src/components/tools/elevator/move-elevator-tool.tsx +13 -2
- package/src/components/tools/fence/fence-drafting.ts +107 -8
- package/src/components/tools/item/move-tool.tsx +17 -13
- package/src/components/tools/item/placement-math.test.ts +13 -1
- package/src/components/tools/item/placement-math.ts +28 -2
- package/src/components/tools/item/placement-strategies.ts +246 -5
- package/src/components/tools/item/placement-types.ts +13 -1
- package/src/components/tools/item/use-draft-node.ts +146 -57
- package/src/components/tools/item/use-placement-coordinator.tsx +813 -125
- package/src/components/tools/registry/move-registry-node-tool.tsx +636 -103
- package/src/components/tools/roof/roof-tool.tsx +336 -94
- package/src/components/tools/select/box-select-state.ts +18 -7
- package/src/components/tools/select/box-select-tool.tsx +176 -40
- package/src/components/tools/select/marquee-geometry.test.ts +161 -0
- package/src/components/tools/select/marquee-geometry.ts +155 -0
- package/src/components/tools/select/plane-box-select-tool.tsx +1 -8
- package/src/components/tools/select/select-candidates.ts +1 -1
- package/src/components/tools/shared/cursor-sphere.tsx +62 -26
- package/src/components/tools/shared/drag-bounding-box.tsx +28 -4
- package/src/components/tools/shared/facing-indicator.tsx +87 -0
- package/src/components/tools/shared/facing-pose-indicator.tsx +54 -0
- package/src/components/tools/shared/floor-stack-preview.ts +4 -0
- package/src/components/tools/shared/horizontal-construction-plane.ts +123 -0
- package/src/components/tools/shared/placement-box.tsx +183 -1
- package/src/components/tools/shared/pointer-support-cap.test.ts +98 -0
- package/src/components/tools/shared/pointer-support-cap.ts +273 -0
- package/src/components/tools/shared/polygon-editor.tsx +276 -35
- package/src/components/tools/site/site-boundary-editor.tsx +101 -42
- package/src/components/tools/site/stroke-pointer-ownership.test.ts +91 -0
- package/src/components/tools/site/stroke-pointer-ownership.ts +57 -0
- package/src/components/tools/site/terrain-brush-cursor.tsx +247 -0
- package/src/components/tools/site/terrain-sculpt-grid.tsx +192 -0
- package/src/components/tools/site/terrain-sculpt-tool.tsx +356 -0
- package/src/components/tools/stair/stair-click-guard.test.ts +58 -0
- package/src/components/tools/stair/stair-click-guard.ts +72 -0
- package/src/components/tools/stair/stair-defaults.ts +1 -0
- package/src/components/tools/stair/stair-tool.tsx +164 -42
- package/src/components/tools/tool-manager.tsx +149 -30
- package/src/components/tools/wall/wall-drafting.test.ts +447 -0
- package/src/components/tools/wall/wall-drafting.ts +304 -108
- package/src/components/tools/wall/wall-snap-geometry.test.ts +52 -0
- package/src/components/tools/wall/wall-snap-geometry.ts +137 -9
- package/src/components/tools/zone/zone-boundary-editor.tsx +5 -1
- package/src/components/tools/zone/zone-tool.tsx +98 -88
- package/src/components/ui/action-menu/camera-actions.tsx +24 -17
- package/src/components/ui/action-menu/control-modes.tsx +44 -94
- package/src/components/ui/action-menu/furnish-tools.tsx +5 -5
- package/src/components/ui/action-menu/index.tsx +2 -4
- package/src/components/ui/action-menu/measurement-control.tsx +267 -0
- package/src/components/ui/action-menu/structure-tools.tsx +22 -13
- package/src/components/ui/action-menu/view-toggles.tsx +42 -90
- package/src/components/ui/command-palette/editor-commands.tsx +16 -3
- package/src/components/ui/command-palette/index.tsx +4 -3
- package/src/components/ui/controls/material-paint-panel.tsx +93 -18
- package/src/components/ui/controls/material-picker.tsx +162 -152
- package/src/components/ui/controls/material-properties-editor.tsx +108 -0
- package/src/components/ui/controls/metric-control.tsx +118 -44
- package/src/components/ui/controls/scene-material-list.tsx +247 -0
- package/src/components/ui/controls/slider-control.tsx +88 -38
- package/src/components/ui/controls/terrain-sculpt-panel.tsx +193 -0
- package/src/components/ui/floating-level-selector.tsx +74 -20
- package/src/components/ui/helpers/building-helper.tsx +10 -23
- package/src/components/ui/helpers/contextual-helper-panel.tsx +428 -0
- package/src/components/ui/helpers/helper-manager.tsx +273 -14
- package/src/components/ui/helpers/item-helper.tsx +28 -32
- package/src/components/ui/helpers/registered-tool-helper.tsx +45 -11
- package/src/components/ui/helpers/roof-helper.tsx +10 -12
- package/src/components/ui/icon-ref.tsx +47 -0
- package/src/components/ui/item-catalog/catalog-items.tsx +39 -1
- package/src/components/ui/item-catalog/item-catalog.tsx +13 -36
- package/src/components/ui/level-duplicate-dialog.tsx +1 -1
- package/src/components/ui/panels/multi-selection-panel.tsx +57 -0
- package/src/components/ui/panels/node-display.ts +17 -17
- package/src/components/ui/panels/panel-manager.tsx +36 -14
- package/src/components/ui/panels/panel-wrapper.tsx +24 -3
- package/src/components/ui/panels/parametric-inspector.tsx +19 -4
- package/src/components/ui/panels/reference-panel.tsx +54 -19
- package/src/components/ui/panels/selection-breakdown.test.ts +24 -0
- package/src/components/ui/panels/selection-breakdown.ts +20 -0
- package/src/components/ui/primitives/shortcut-token.tsx +39 -3
- package/src/components/ui/primitives/sidebar.tsx +1 -0
- package/src/components/ui/sidebar/app-sidebar.tsx +5 -1
- package/src/components/ui/sidebar/icon-rail.tsx +50 -31
- package/src/components/ui/sidebar/panels/plugins-panel.tsx +218 -0
- package/src/components/ui/sidebar/panels/settings-panel/index.tsx +82 -41
- package/src/components/ui/sidebar/panels/settings-panel/keyboard-shortcuts-dialog.tsx +76 -6
- package/src/components/ui/sidebar/panels/settings-panel/load-build-dialog.tsx +12 -4
- package/src/components/ui/sidebar/panels/site-panel/building-tree-node.tsx +2 -1
- package/src/components/ui/sidebar/panels/site-panel/ceiling-tree-node.tsx +4 -3
- package/src/components/ui/sidebar/panels/site-panel/chimney-tree-node.tsx +10 -7
- package/src/components/ui/sidebar/panels/site-panel/column-tree-node.tsx +1 -1
- package/src/components/ui/sidebar/panels/site-panel/door-tree-node.tsx +7 -2
- package/src/components/ui/sidebar/panels/site-panel/dormer-tree-node.tsx +10 -7
- package/src/components/ui/sidebar/panels/site-panel/elevator-tree-node.tsx +1 -1
- package/src/components/ui/sidebar/panels/site-panel/fence-tree-node.tsx +1 -1
- package/src/components/ui/sidebar/panels/site-panel/gutter-tree-node.tsx +10 -7
- package/src/components/ui/sidebar/panels/site-panel/index.tsx +42 -17
- package/src/components/ui/sidebar/panels/site-panel/item-tree-node.tsx +31 -17
- package/src/components/ui/sidebar/panels/site-panel/level-tree-node.tsx +1 -1
- package/src/components/ui/sidebar/panels/site-panel/registry-tree-node.tsx +72 -25
- package/src/components/ui/sidebar/panels/site-panel/roof-tree-node.tsx +7 -3
- package/src/components/ui/sidebar/panels/site-panel/shelf-tree-node.tsx +12 -8
- package/src/components/ui/sidebar/panels/site-panel/slab-tree-node.tsx +4 -3
- package/src/components/ui/sidebar/panels/site-panel/solar-panel-tree-node.tsx +10 -7
- package/src/components/ui/sidebar/panels/site-panel/spawn-tree-node.tsx +1 -1
- package/src/components/ui/sidebar/panels/site-panel/stair-tree-node.tsx +2 -2
- package/src/components/ui/sidebar/panels/site-panel/tree-node.tsx +44 -3
- package/src/components/ui/sidebar/panels/site-panel/tree-structure.ts +36 -0
- package/src/components/ui/sidebar/panels/site-panel/wall-tree-node.tsx +1 -1
- package/src/components/ui/sidebar/panels/site-panel/window-tree-node.tsx +7 -2
- package/src/components/ui/sidebar/panels/site-panel/zone-tree-node.tsx +3 -3
- package/src/components/ui/sidebar/tab-bar.tsx +42 -28
- package/src/components/ui/sidebar/use-plugin-panels.tsx +132 -0
- package/src/components/ui/snap-target-badge.test.tsx +40 -0
- package/src/components/ui/snap-target-badge.tsx +88 -0
- package/src/components/viewer/viewer-controls-bar.tsx +466 -0
- package/src/components/viewer/viewer-scene-header.tsx +235 -0
- package/src/components/viewer-overlay.tsx +36 -596
- package/src/components/viewer-zone-system.tsx +6 -1
- package/src/components/walkthrough-hud.tsx +111 -0
- package/src/hooks/use-auto-save.test.ts +14 -0
- package/src/hooks/use-auto-save.ts +54 -7
- package/src/hooks/use-ceiling-events.ts +3 -2
- package/src/hooks/use-drag-action.ts +4 -1
- package/src/hooks/use-grid-events.ts +24 -0
- package/src/hooks/use-keyboard.ts +438 -70
- package/src/index.tsx +355 -9
- package/src/lib/active-placement-surface.test.ts +24 -0
- package/src/lib/active-placement-surface.ts +42 -0
- package/src/lib/camera-pose.test.ts +237 -0
- package/src/lib/camera-pose.ts +172 -0
- package/src/lib/ceiling-plan-snap.ts +24 -0
- package/src/lib/contextual-help.test.ts +112 -0
- package/src/lib/contextual-help.ts +144 -0
- package/src/lib/continuation.ts +64 -0
- package/src/lib/direct-manipulation.test.ts +275 -0
- package/src/lib/direct-manipulation.ts +118 -0
- package/src/lib/door-interaction.ts +1 -1
- package/src/lib/editor-api.ts +23 -35
- package/src/lib/elevation-guides.test.ts +107 -0
- package/src/lib/elevation-guides.ts +236 -0
- package/src/lib/floorplan/annotation-visibility.test.ts +327 -0
- package/src/lib/floorplan/annotation-visibility.ts +133 -0
- package/src/lib/floorplan/apply-alignment.test.ts +25 -0
- package/src/lib/floorplan/apply-alignment.ts +18 -12
- package/src/lib/floorplan/drawing-coordination.test.ts +46 -0
- package/src/lib/floorplan/drawing-coordination.ts +13 -0
- package/src/lib/floorplan/floorplan-export.test.ts +319 -0
- package/src/lib/floorplan/floorplan-export.tsx +978 -0
- package/src/lib/floorplan/floorplan-extension.test.ts +43 -0
- package/src/lib/floorplan/floorplan-extension.ts +181 -0
- package/src/lib/floorplan/floorplan-mode.test.ts +120 -0
- package/src/lib/floorplan/floorplan-mode.ts +73 -0
- package/src/lib/floorplan/floorplan-pdfkit-document.ts +194 -0
- package/src/lib/floorplan/floorplan-pdfkit-renderer.test.ts +107 -0
- package/src/lib/floorplan/floorplan-pdfkit-renderer.ts +680 -0
- package/src/lib/floorplan/geometry.ts +52 -0
- package/src/lib/floorplan/index.ts +3 -0
- package/src/lib/floorplan/items.ts +5 -2
- package/src/lib/floorplan/plan-coords.ts +21 -0
- package/src/lib/fresh-planar-placement.test.ts +283 -3
- package/src/lib/fresh-planar-placement.ts +85 -1
- package/src/lib/glb-export.test.ts +556 -0
- package/src/lib/glb-export.ts +1071 -0
- package/src/lib/ground-surface.ts +95 -0
- package/src/lib/history.test.ts +96 -0
- package/src/lib/history.ts +31 -0
- package/src/lib/interaction/hot-set.test.ts +133 -0
- package/src/lib/interaction/hot-set.ts +67 -0
- package/src/lib/interaction/overlay-policy.test.ts +52 -0
- package/src/lib/interaction/overlay-policy.ts +59 -0
- package/src/lib/interaction/scope.ts +243 -0
- package/src/lib/level-duplication.test.ts +2 -1
- package/src/lib/level-selection.ts +2 -2
- package/src/lib/material-paint.ts +36 -49
- package/src/lib/measurement-kind.test.ts +30 -0
- package/src/lib/measurement-kind.ts +19 -0
- package/src/lib/measurement-label.test.ts +47 -0
- package/src/lib/measurement-label.ts +68 -0
- package/src/lib/measurement-parser.ts +116 -0
- package/src/lib/measurements.test.ts +188 -0
- package/src/lib/measurements.ts +210 -0
- package/src/lib/paint-scope.test.ts +454 -0
- package/src/lib/paint-scope.ts +461 -0
- package/src/lib/placement-drag-release.ts +23 -0
- package/src/lib/planar-cursor-placement.test.ts +57 -0
- package/src/lib/plugin-panels.test.ts +19 -0
- package/src/lib/plugin-panels.ts +91 -0
- package/src/lib/quick-action-feedback.ts +33 -0
- package/src/lib/quick-action-nodes.test.ts +94 -0
- package/src/lib/quick-action-nodes.ts +47 -0
- package/src/lib/quick-measurement.test.ts +77 -0
- package/src/lib/quick-measurement.ts +109 -0
- package/src/lib/roof-duplication.ts +6 -6
- package/src/lib/roof-hover-outline-proxy.ts +22 -0
- package/src/lib/roof-wall-hit.ts +164 -0
- package/src/lib/scene-clipboard.test.ts +325 -0
- package/src/lib/scene-clipboard.ts +310 -21
- package/src/lib/scene.ts +28 -5
- package/src/lib/selection-routing.test.ts +313 -0
- package/src/lib/selection-routing.ts +180 -0
- package/src/lib/sfx/index.ts +1 -0
- package/src/lib/sfx/movement-tick.test.ts +65 -0
- package/src/lib/sfx/movement-tick.ts +18 -0
- package/src/lib/sfx-bus.ts +82 -14
- package/src/lib/sfx-player.test.ts +266 -0
- package/src/lib/sfx-player.ts +262 -69
- package/src/lib/site-boundary.test.ts +53 -0
- package/src/lib/site-boundary.ts +27 -0
- package/src/lib/slab-plan-snap.test.ts +93 -0
- package/src/lib/slab-plan-snap.ts +108 -0
- package/src/lib/snapping-mode.test.ts +165 -0
- package/src/lib/snapping-mode.ts +191 -0
- package/src/lib/stair-duplication.test.ts +103 -0
- package/src/lib/stair-duplication.ts +58 -86
- package/src/lib/stair-levels.ts +2 -0
- package/src/lib/surface-plan-snap.test.ts +71 -0
- package/src/lib/surface-plan-snap.ts +256 -0
- package/src/lib/terrain-sculpt.test.ts +429 -0
- package/src/lib/terrain-sculpt.ts +301 -0
- package/src/lib/terrain-verb-color.test.ts +51 -0
- package/src/lib/terrain-verb-color.ts +58 -0
- package/src/lib/touch-gesture-priority.test.ts +45 -0
- package/src/lib/touch-gesture-priority.ts +30 -0
- package/src/lib/use-linear-display.ts +40 -0
- package/src/lib/window-interaction.ts +1 -1
- package/src/lib/world-grid-snap.ts +37 -5
- package/src/store/camera-pose-store.test.ts +29 -0
- package/src/store/camera-pose-store.ts +27 -0
- package/src/store/live-draft-preview-stores.test.ts +136 -0
- package/src/store/navigation-sync-pose-store.test.ts +34 -0
- package/src/store/navigation-sync-pose-store.ts +27 -0
- package/src/store/terrain-sculpt-mode.test.ts +223 -0
- package/src/store/use-delete-confirmation.ts +27 -0
- package/src/store/use-direct-manipulation-feedback.ts +20 -0
- package/src/store/use-drawing-view.test.ts +23 -0
- package/src/store/use-drawing-view.ts +84 -0
- package/src/store/use-editor.tsx +665 -126
- package/src/store/use-elevation-guides.ts +40 -0
- package/src/store/use-facing-pose.ts +44 -0
- package/src/store/use-fence-curve-draft.ts +51 -0
- package/src/store/use-first-person-hud.ts +40 -0
- package/src/store/use-floorplan-annotation-visibility.ts +60 -0
- package/src/store/use-floorplan-draft-preview.ts +151 -0
- package/src/store/use-floorplan-marquee.ts +50 -0
- package/src/store/use-floorplan-mode.ts +110 -0
- package/src/store/use-interaction-scope.test.ts +206 -0
- package/src/store/use-interaction-scope.ts +140 -0
- package/src/store/use-measurement-draft.test.ts +559 -0
- package/src/store/use-measurement-draft.ts +570 -0
- package/src/store/use-opening-guides.ts +41 -0
- package/src/store/use-path-draft-preview.ts +90 -0
- package/src/store/use-placement-preview.ts +11 -3
- package/src/store/use-quick-measurement-hud.test.ts +53 -0
- package/src/store/use-quick-measurement-hud.ts +77 -0
- package/src/store/use-segment-draft-chain.ts +28 -0
- package/src/store/use-stair-build-preview.ts +53 -0
- package/src/store/use-wall-snap-indicator.ts +2 -0
- package/src/components/editor/first-person/bvh-ecctrl.tsx +0 -860
- package/src/components/editor/group-move-handle.tsx +0 -316
- package/src/components/ui/panels/paint-panel.tsx +0 -163
- package/src/lib/floorplan/selection-tool.ts +0 -271
- package/src/lib/level-name.ts +0 -11
|
@@ -6,24 +6,45 @@ import { furnishTools } from '../../../components/ui/action-menu/furnish-tools'
|
|
|
6
6
|
import { tools } from '../../../components/ui/action-menu/structure-tools'
|
|
7
7
|
import { EDITOR_LAYER } from '../../../lib/constants'
|
|
8
8
|
import useEditor from '../../../store/use-editor'
|
|
9
|
+
import useWallSnapIndicator from '../../../store/use-wall-snap-indicator'
|
|
9
10
|
|
|
10
11
|
interface CursorSphereProps extends Omit<ThreeElements['group'], 'ref'> {
|
|
11
12
|
color?: string
|
|
12
13
|
depthWrite?: boolean
|
|
13
14
|
showTooltip?: boolean
|
|
14
15
|
height?: number
|
|
16
|
+
/**
|
|
17
|
+
* Put the bright marker dot at the TIP of the vertical line (y = height)
|
|
18
|
+
* instead of on the ground ring. Used when the point being placed hangs
|
|
19
|
+
* above the floor (e.g. duct drawn against the ceiling): the dot rides at
|
|
20
|
+
* the cursor / placement point while the line drops to a floor ring that
|
|
21
|
+
* keeps the plan position readable.
|
|
22
|
+
*/
|
|
23
|
+
dotAtTip?: boolean
|
|
15
24
|
/** Custom tooltip content — overrides the auto-detected build tool icon */
|
|
16
25
|
tooltipContent?: React.ReactNode
|
|
17
26
|
}
|
|
18
27
|
|
|
19
28
|
export const CursorSphere = forwardRef<Group, CursorSphereProps>(function CursorSphere(
|
|
20
|
-
{
|
|
29
|
+
{
|
|
30
|
+
color = '#818cf8',
|
|
31
|
+
showTooltip = true,
|
|
32
|
+
height = 2.5,
|
|
33
|
+
dotAtTip = false,
|
|
34
|
+
visible = true,
|
|
35
|
+
tooltipContent,
|
|
36
|
+
...props
|
|
37
|
+
},
|
|
21
38
|
ref,
|
|
22
39
|
) {
|
|
23
40
|
const tool = useEditor((s) => s.tool)
|
|
24
41
|
const mode = useEditor((s) => s.mode)
|
|
25
42
|
const catalogCategory = useEditor((s) => s.catalogCategory)
|
|
26
43
|
const isFloorplanHovered = useEditor((s) => s.isFloorplanHovered)
|
|
44
|
+
// While a wall snap is active the beacon layer already marks the point
|
|
45
|
+
// (green square at a corner); hide the cursor's ground dot/ring so it
|
|
46
|
+
// doesn't sit on top of that glyph.
|
|
47
|
+
const isSnapping = useWallSnapIndicator((s) => s.point !== null)
|
|
27
48
|
|
|
28
49
|
// Find the icon for the current tool
|
|
29
50
|
let activeToolConfig = null
|
|
@@ -39,32 +60,38 @@ export const CursorSphere = forwardRef<Group, CursorSphereProps>(function Cursor
|
|
|
39
60
|
|
|
40
61
|
return (
|
|
41
62
|
<group ref={ref} {...props} visible={isVisible}>
|
|
42
|
-
{/* Flat marker on the ground
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
63
|
+
{/* Flat marker on the ground. The bright center dot moves to the tip
|
|
64
|
+
of the line in `dotAtTip` mode (the placement point hangs above the
|
|
65
|
+
floor), leaving a faint ring here so the plan position stays read. */}
|
|
66
|
+
{!isSnapping && (
|
|
67
|
+
<group rotation={[-Math.PI / 2, 0, 0]}>
|
|
68
|
+
{/* Center dot — at the ground unless the placement point is elevated */}
|
|
69
|
+
{!dotAtTip && (
|
|
70
|
+
<mesh layers={EDITOR_LAYER} renderOrder={2}>
|
|
71
|
+
<circleGeometry args={[0.06, 32]} />
|
|
72
|
+
<meshBasicMaterial
|
|
73
|
+
color={color}
|
|
74
|
+
depthTest={false}
|
|
75
|
+
depthWrite={false}
|
|
76
|
+
opacity={0.9}
|
|
77
|
+
transparent
|
|
78
|
+
/>
|
|
79
|
+
</mesh>
|
|
80
|
+
)}
|
|
55
81
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
82
|
+
{/* Outer ring / glow */}
|
|
83
|
+
<mesh layers={EDITOR_LAYER} renderOrder={2}>
|
|
84
|
+
<circleGeometry args={[0.2, 32]} />
|
|
85
|
+
<meshBasicMaterial
|
|
86
|
+
color={color}
|
|
87
|
+
depthTest={false}
|
|
88
|
+
depthWrite={false}
|
|
89
|
+
opacity={dotAtTip ? 0.2 : 0.25}
|
|
90
|
+
transparent
|
|
91
|
+
/>
|
|
92
|
+
</mesh>
|
|
93
|
+
</group>
|
|
94
|
+
)}
|
|
68
95
|
|
|
69
96
|
{/* Vertical line */}
|
|
70
97
|
{height > 0 && (
|
|
@@ -80,6 +107,15 @@ export const CursorSphere = forwardRef<Group, CursorSphereProps>(function Cursor
|
|
|
80
107
|
</mesh>
|
|
81
108
|
)}
|
|
82
109
|
|
|
110
|
+
{/* Bright marker dot at the tip of the line — the actual placement
|
|
111
|
+
point, riding at the cursor while the line drops to the floor. */}
|
|
112
|
+
{dotAtTip && height > 0 && (
|
|
113
|
+
<mesh layers={EDITOR_LAYER} position={[0, height, 0]} renderOrder={2}>
|
|
114
|
+
<sphereGeometry args={[0.08, 20, 14]} />
|
|
115
|
+
<meshBasicMaterial color={color} depthTest={false} depthWrite={false} />
|
|
116
|
+
</mesh>
|
|
117
|
+
)}
|
|
118
|
+
|
|
83
119
|
{/* Tool Icon Tooltip at the top of the line */}
|
|
84
120
|
{isVisible && showTooltip && (activeToolConfig || tooltipContent) && (
|
|
85
121
|
<Html
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
-
import { sceneRegistry } from '@pascal-app/core'
|
|
3
|
+
import { type AnyNodeId, resolveFacingIndicator, sceneRegistry, useScene } from '@pascal-app/core'
|
|
4
4
|
import { useEffect, useMemo } from 'react'
|
|
5
5
|
import {
|
|
6
6
|
Box3,
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
import { distance, smoothstep, uv, vec2 } from 'three/tsl'
|
|
16
16
|
import { LineBasicNodeMaterial, MeshBasicNodeMaterial } from 'three/webgpu'
|
|
17
17
|
import { EDITOR_LAYER } from '../../../lib/constants'
|
|
18
|
+
import useFacingPose from '../../../store/use-facing-pose'
|
|
18
19
|
|
|
19
20
|
const NO_RAYCAST = () => null
|
|
20
21
|
|
|
@@ -71,6 +72,8 @@ interface DragBoundingBoxProps {
|
|
|
71
72
|
* includes per-level landings outside the shaft footprint).
|
|
72
73
|
*/
|
|
73
74
|
size?: [number, number, number]
|
|
75
|
+
/** Local center of `size`. Defaults to the node origin plus half-height. */
|
|
76
|
+
center?: [number, number, number]
|
|
74
77
|
/** Y center of the box in the node's local frame. Defaults to `size[1] / 2`. */
|
|
75
78
|
centerY?: number
|
|
76
79
|
color?: number
|
|
@@ -90,9 +93,13 @@ export function DragBoundingBox({
|
|
|
90
93
|
rotationY = 0,
|
|
91
94
|
fallbackSize = [0, 0, 0],
|
|
92
95
|
size,
|
|
96
|
+
center,
|
|
93
97
|
centerY,
|
|
94
98
|
color = DEFAULT_COLOR,
|
|
95
99
|
}: DragBoundingBoxProps) {
|
|
100
|
+
const nodeType = useScene((state) => state.nodes[nodeId as AnyNodeId]?.type)
|
|
101
|
+
const facing = nodeType ? resolveFacingIndicator(nodeType) : null
|
|
102
|
+
|
|
96
103
|
const measured = useMemo(() => {
|
|
97
104
|
if (size) return null
|
|
98
105
|
const obj = sceneRegistry.nodes.get(nodeId)
|
|
@@ -101,9 +108,10 @@ export function DragBoundingBox({
|
|
|
101
108
|
|
|
102
109
|
const [w, h, d] = size ?? measured?.size ?? fallbackSize
|
|
103
110
|
const [cx, cy, cz] = size
|
|
104
|
-
? [0, centerY ?? size[1] / 2, 0]
|
|
111
|
+
? (center ?? [0, centerY ?? size[1] / 2, 0])
|
|
105
112
|
: (measured?.center ?? [0, fallbackSize[1] / 2, 0])
|
|
106
113
|
const minY = cy - h / 2
|
|
114
|
+
const groundY = minY + 0.01
|
|
107
115
|
|
|
108
116
|
const edgeGeometry = useMemo(() => {
|
|
109
117
|
const box = new BoxGeometry(w, h, d)
|
|
@@ -117,9 +125,9 @@ export function DragBoundingBox({
|
|
|
117
125
|
const planeGeometry = useMemo(() => {
|
|
118
126
|
const plane = new PlaneGeometry(w, d)
|
|
119
127
|
plane.rotateX(-Math.PI / 2)
|
|
120
|
-
plane.translate(cx,
|
|
128
|
+
plane.translate(cx, groundY, cz)
|
|
121
129
|
return plane
|
|
122
|
-
}, [w, d, cx,
|
|
130
|
+
}, [w, d, cx, groundY, cz])
|
|
123
131
|
|
|
124
132
|
const edgeMaterial = useMemo(
|
|
125
133
|
() => new LineBasicNodeMaterial({ color, linewidth: 3, depthTest: false, depthWrite: false }),
|
|
@@ -147,6 +155,22 @@ export function DragBoundingBox({
|
|
|
147
155
|
[edgeGeometry, planeGeometry, edgeMaterial, planeMaterial],
|
|
148
156
|
)
|
|
149
157
|
|
|
158
|
+
// Publish the facing pose to the editor-side overlay (the single triangle
|
|
159
|
+
// renderer) rather than drawing it here. The node origin is `position`; the
|
|
160
|
+
// footprint centre is `[cx, cz]` in the node's local frame. Runs each drag
|
|
161
|
+
// frame so the triangle follows; a separate mount/unmount effect clears it.
|
|
162
|
+
useEffect(() => {
|
|
163
|
+
if (!facing || d <= 0) return
|
|
164
|
+
useFacingPose.getState().set({
|
|
165
|
+
position: [position[0], position[1] + groundY, position[2]],
|
|
166
|
+
rotationY,
|
|
167
|
+
depth: d,
|
|
168
|
+
center: [cx, cz],
|
|
169
|
+
reversed: facing.reversed,
|
|
170
|
+
})
|
|
171
|
+
}, [facing, position, rotationY, d, cx, cz, groundY])
|
|
172
|
+
useEffect(() => () => useFacingPose.getState().clear(), [])
|
|
173
|
+
|
|
150
174
|
if (w <= 0 || h <= 0 || d <= 0) return null
|
|
151
175
|
|
|
152
176
|
return (
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { useEffect, useMemo } from 'react'
|
|
2
|
+
import { BufferGeometry, DoubleSide, Float32BufferAttribute } from 'three'
|
|
3
|
+
import { MeshBasicNodeMaterial } from 'three/webgpu'
|
|
4
|
+
import { EDITOR_LAYER } from '../../../lib/constants'
|
|
5
|
+
|
|
6
|
+
// A flat forward-pointing triangle drawn on the floor just in front of a
|
|
7
|
+
// placement ghost, so the direction the node will face is obvious. Tip at local
|
|
8
|
+
// +Z (every kind's forward face); render it inside the ghost's rotated group so
|
|
9
|
+
// it inherits the node's yaw. Matches the item coordinator / drag-bounding-box
|
|
10
|
+
// indicators (same size, colour, double-sided so it shows from above).
|
|
11
|
+
const FACING_INDICATOR_WIDTH = 0.4
|
|
12
|
+
const FACING_INDICATOR_LENGTH = 0.46
|
|
13
|
+
const FACING_INDICATOR_GAP = 0.45
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @param depth bbox depth (along local Z) of the ghost — positions the
|
|
17
|
+
* triangle just past the front edge.
|
|
18
|
+
* @param center optional [x, z] of the bbox centre in the ghost's local frame.
|
|
19
|
+
* @param reversed point along local -Z (the front is the -Z side, e.g. a stair
|
|
20
|
+
* entry) instead of +Z.
|
|
21
|
+
* @param y small lift off the floor to avoid z-fighting.
|
|
22
|
+
*/
|
|
23
|
+
export function FacingIndicator({
|
|
24
|
+
depth,
|
|
25
|
+
center = [0, 0],
|
|
26
|
+
reversed = false,
|
|
27
|
+
y = 0.02,
|
|
28
|
+
}: {
|
|
29
|
+
depth: number
|
|
30
|
+
center?: [number, number]
|
|
31
|
+
reversed?: boolean
|
|
32
|
+
y?: number
|
|
33
|
+
}) {
|
|
34
|
+
const dir = reversed ? -1 : 1
|
|
35
|
+
// Per-instance geometry/material (not module singletons) so this works no
|
|
36
|
+
// matter which package mounts it (the tools live in `nodes`, imported via
|
|
37
|
+
// `@pascal-app/editor`). Disposed on unmount.
|
|
38
|
+
const geometry = useMemo(() => {
|
|
39
|
+
const g = new BufferGeometry()
|
|
40
|
+
g.setAttribute(
|
|
41
|
+
'position',
|
|
42
|
+
new Float32BufferAttribute(
|
|
43
|
+
[
|
|
44
|
+
0,
|
|
45
|
+
0,
|
|
46
|
+
dir * FACING_INDICATOR_LENGTH,
|
|
47
|
+
FACING_INDICATOR_WIDTH / 2,
|
|
48
|
+
0,
|
|
49
|
+
0,
|
|
50
|
+
-FACING_INDICATOR_WIDTH / 2,
|
|
51
|
+
0,
|
|
52
|
+
0,
|
|
53
|
+
],
|
|
54
|
+
3,
|
|
55
|
+
),
|
|
56
|
+
)
|
|
57
|
+
return g
|
|
58
|
+
}, [dir])
|
|
59
|
+
const material = useMemo(
|
|
60
|
+
() =>
|
|
61
|
+
new MeshBasicNodeMaterial({
|
|
62
|
+
color: 0x22_c5_5e, // green-500 (forward)
|
|
63
|
+
depthTest: false,
|
|
64
|
+
depthWrite: false,
|
|
65
|
+
side: DoubleSide,
|
|
66
|
+
}),
|
|
67
|
+
[],
|
|
68
|
+
)
|
|
69
|
+
useEffect(
|
|
70
|
+
() => () => {
|
|
71
|
+
geometry.dispose()
|
|
72
|
+
material.dispose()
|
|
73
|
+
},
|
|
74
|
+
[geometry, material],
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<mesh
|
|
79
|
+
frustumCulled={false}
|
|
80
|
+
geometry={geometry}
|
|
81
|
+
layers={EDITOR_LAYER}
|
|
82
|
+
material={material}
|
|
83
|
+
position={[center[0], y, center[1] + dir * (depth / 2 + FACING_INDICATOR_GAP)]}
|
|
84
|
+
renderOrder={1001}
|
|
85
|
+
/>
|
|
86
|
+
)
|
|
87
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from 'react'
|
|
2
|
+
import type { Group } from 'three'
|
|
3
|
+
import useFacingPose, { type FacingPose } from '../../../store/use-facing-pose'
|
|
4
|
+
import { FacingIndicator } from './facing-indicator'
|
|
5
|
+
|
|
6
|
+
// The single editor-side renderer for the placement/move facing triangle.
|
|
7
|
+
// Mounted once inside ToolManager's building-local group; every tool publishes
|
|
8
|
+
// its ghost pose to `useFacingPose` and this draws the triangle. The pose
|
|
9
|
+
// (position/yaw) is applied imperatively to a ref so the per-frame cursor
|
|
10
|
+
// updates don't re-render React — only a change in footprint shape (depth /
|
|
11
|
+
// centre), which is constant per tool session, triggers a re-render.
|
|
12
|
+
export function FacingPoseIndicator() {
|
|
13
|
+
const groupRef = useRef<Group>(null)
|
|
14
|
+
const [shape, setShape] = useState<Pick<FacingPose, 'depth' | 'center' | 'reversed'> | null>(null)
|
|
15
|
+
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
const apply = (pose: FacingPose | null) => {
|
|
18
|
+
const group = groupRef.current
|
|
19
|
+
if (group) {
|
|
20
|
+
if (pose) {
|
|
21
|
+
group.visible = true
|
|
22
|
+
group.position.set(...pose.position)
|
|
23
|
+
group.rotation.y = pose.rotationY
|
|
24
|
+
} else {
|
|
25
|
+
group.visible = false
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
setShape((prev) => {
|
|
29
|
+
if (!pose) return null
|
|
30
|
+
const center = pose.center ?? [0, 0]
|
|
31
|
+
if (
|
|
32
|
+
prev &&
|
|
33
|
+
prev.depth === pose.depth &&
|
|
34
|
+
prev.reversed === pose.reversed &&
|
|
35
|
+
(prev.center ?? [0, 0])[0] === center[0] &&
|
|
36
|
+
(prev.center ?? [0, 0])[1] === center[1]
|
|
37
|
+
) {
|
|
38
|
+
return prev
|
|
39
|
+
}
|
|
40
|
+
return { depth: pose.depth, center, reversed: pose.reversed }
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
apply(useFacingPose.getState().pose)
|
|
44
|
+
return useFacingPose.subscribe((state) => apply(state.pose))
|
|
45
|
+
}, [])
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<group ref={groupRef} visible={false}>
|
|
49
|
+
{shape ? (
|
|
50
|
+
<FacingIndicator center={shape.center} depth={shape.depth} reversed={shape.reversed} />
|
|
51
|
+
) : null}
|
|
52
|
+
</group>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
@@ -6,6 +6,8 @@ type FloorStackPreviewArgs = {
|
|
|
6
6
|
rotation?: unknown
|
|
7
7
|
levelId?: string | null
|
|
8
8
|
nodes?: Record<AnyNodeId, AnyNode>
|
|
9
|
+
/** Pointer-decided support cap — see `FloorPlacedElevationArgs.maxElevation`. */
|
|
10
|
+
maxElevation?: number | null
|
|
9
11
|
}
|
|
10
12
|
|
|
11
13
|
export function getFloorStackPreviewPosition({
|
|
@@ -14,6 +16,7 @@ export function getFloorStackPreviewPosition({
|
|
|
14
16
|
rotation,
|
|
15
17
|
levelId,
|
|
16
18
|
nodes,
|
|
19
|
+
maxElevation,
|
|
17
20
|
}: FloorStackPreviewArgs): [number, number, number] {
|
|
18
21
|
return getFloorStackedPosition({
|
|
19
22
|
node,
|
|
@@ -21,5 +24,6 @@ export function getFloorStackPreviewPosition({
|
|
|
21
24
|
position,
|
|
22
25
|
rotation,
|
|
23
26
|
levelId,
|
|
27
|
+
maxElevation,
|
|
24
28
|
})
|
|
25
29
|
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type AnyNodeId,
|
|
3
|
+
GROUND_SUPPORT_ID,
|
|
4
|
+
type GridEvent,
|
|
5
|
+
sceneRegistry,
|
|
6
|
+
terrainSupportLift,
|
|
7
|
+
useScene,
|
|
8
|
+
} from '@pascal-app/core'
|
|
9
|
+
import { useViewer } from '@pascal-app/viewer'
|
|
10
|
+
import { Vector3 } from 'three'
|
|
11
|
+
import { publishPlacementSurface } from '../../../lib/active-placement-surface'
|
|
12
|
+
import type { PointerSupportSurface } from './pointer-support-cap'
|
|
13
|
+
|
|
14
|
+
const SURFACE_UP = new Vector3(0, 1, 0)
|
|
15
|
+
const worldScratch = new Vector3()
|
|
16
|
+
const localScratch = new Vector3()
|
|
17
|
+
const surfacePointScratch = new Vector3()
|
|
18
|
+
|
|
19
|
+
export type HorizontalConstructionPlane = {
|
|
20
|
+
/** Building-local Y used by the cursor and draft preview. */
|
|
21
|
+
localY: number
|
|
22
|
+
/** World Y used by the shared placement grid. */
|
|
23
|
+
worldY: number
|
|
24
|
+
/** Level-local base elevation used when the node is committed. */
|
|
25
|
+
elevation: number | null
|
|
26
|
+
/** Support source selected at the first click. */
|
|
27
|
+
supportSlabId: string | null
|
|
28
|
+
/** Optional scene node from which this frozen plane was derived. */
|
|
29
|
+
sourceNodeId: AnyNodeId | null
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function resolveEventConstructionPlane(
|
|
33
|
+
event: GridEvent,
|
|
34
|
+
pointed: PointerSupportSurface | null,
|
|
35
|
+
): HorizontalConstructionPlane {
|
|
36
|
+
if (pointed) {
|
|
37
|
+
return {
|
|
38
|
+
localY: pointed.localPoint?.[1] ?? event.localPosition[1],
|
|
39
|
+
worldY: pointed.worldY,
|
|
40
|
+
elevation: pointed.elevation,
|
|
41
|
+
supportSlabId: pointed.supportSlabId,
|
|
42
|
+
sourceNodeId: pointed.sourceNodeId,
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
let elevation: number | null = null
|
|
47
|
+
const levelId = useViewer.getState().selection.levelId
|
|
48
|
+
const levelMesh = levelId ? sceneRegistry.nodes.get(levelId as AnyNodeId) : undefined
|
|
49
|
+
if (levelMesh) {
|
|
50
|
+
localScratch.set(event.position[0], event.position[1], event.position[2])
|
|
51
|
+
levelMesh.worldToLocal(localScratch)
|
|
52
|
+
elevation = localScratch.y
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
localY: event.localPosition[1],
|
|
57
|
+
worldY: event.position[1],
|
|
58
|
+
elevation,
|
|
59
|
+
supportSlabId: null,
|
|
60
|
+
sourceNodeId: null,
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function resolveLevelConstructionPlane(): HorizontalConstructionPlane | null {
|
|
65
|
+
const { buildingId, levelId } = useViewer.getState().selection
|
|
66
|
+
if (!levelId) return null
|
|
67
|
+
|
|
68
|
+
const levelMesh = sceneRegistry.nodes.get(levelId as AnyNodeId)
|
|
69
|
+
worldScratch.set(0, 0, 0)
|
|
70
|
+
if (levelMesh) levelMesh.localToWorld(worldScratch)
|
|
71
|
+
|
|
72
|
+
const buildingMesh = buildingId ? sceneRegistry.nodes.get(buildingId as AnyNodeId) : undefined
|
|
73
|
+
localScratch.copy(worldScratch)
|
|
74
|
+
if (buildingMesh) buildingMesh.worldToLocal(localScratch)
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
localY: localScratch.y,
|
|
78
|
+
worldY: worldScratch.y,
|
|
79
|
+
elevation: 0,
|
|
80
|
+
supportSlabId: null,
|
|
81
|
+
sourceNodeId: null,
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function resampleTerrainConstructionPlane(
|
|
86
|
+
plane: HorizontalConstructionPlane,
|
|
87
|
+
point: readonly [number, number],
|
|
88
|
+
): HorizontalConstructionPlane {
|
|
89
|
+
if (plane.supportSlabId !== GROUND_SUPPORT_ID || plane.sourceNodeId) return plane
|
|
90
|
+
|
|
91
|
+
const levelId = useViewer.getState().selection.levelId
|
|
92
|
+
if (!levelId) return plane
|
|
93
|
+
const elevation = terrainSupportLift(useScene.getState().nodes, levelId, point[0], point[1])
|
|
94
|
+
if (elevation == null) return plane
|
|
95
|
+
|
|
96
|
+
const levelMesh = sceneRegistry.nodes.get(levelId as AnyNodeId)
|
|
97
|
+
worldScratch.set(point[0], elevation, point[1])
|
|
98
|
+
if (levelMesh) levelMesh.localToWorld(worldScratch)
|
|
99
|
+
|
|
100
|
+
const buildingId = useViewer.getState().selection.buildingId
|
|
101
|
+
const buildingMesh = buildingId ? sceneRegistry.nodes.get(buildingId as AnyNodeId) : undefined
|
|
102
|
+
localScratch.copy(worldScratch)
|
|
103
|
+
if (buildingMesh) buildingMesh.worldToLocal(localScratch)
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
localY: localScratch.y,
|
|
107
|
+
worldY: worldScratch.y,
|
|
108
|
+
elevation,
|
|
109
|
+
supportSlabId: GROUND_SUPPORT_ID,
|
|
110
|
+
sourceNodeId: null,
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function publishHorizontalConstructionPlane(
|
|
115
|
+
event: GridEvent,
|
|
116
|
+
plane: HorizontalConstructionPlane,
|
|
117
|
+
): void {
|
|
118
|
+
publishPlacementSurface(
|
|
119
|
+
surfacePointScratch.set(event.position[0], plane.worldY, event.position[2]),
|
|
120
|
+
SURFACE_UP,
|
|
121
|
+
'fixed-plane',
|
|
122
|
+
)
|
|
123
|
+
}
|