Move item dimensions into local item overlays
This commit is contained in:
@@ -4137,6 +4137,7 @@ const FloorplanNodeLayer = memo(function FloorplanNodeLayer({
|
|||||||
palette,
|
palette,
|
||||||
selectedIdSet,
|
selectedIdSet,
|
||||||
stairEntries,
|
stairEntries,
|
||||||
|
unit,
|
||||||
}: {
|
}: {
|
||||||
canFocusItems: boolean
|
canFocusItems: boolean
|
||||||
canFocusStairs: boolean
|
canFocusStairs: boolean
|
||||||
@@ -4161,12 +4162,15 @@ const FloorplanNodeLayer = memo(function FloorplanNodeLayer({
|
|||||||
palette: FloorplanPalette
|
palette: FloorplanPalette
|
||||||
selectedIdSet: ReadonlySet<string>
|
selectedIdSet: ReadonlySet<string>
|
||||||
stairEntries: FloorplanStairEntry[]
|
stairEntries: FloorplanStairEntry[]
|
||||||
|
unit: 'metric' | 'imperial'
|
||||||
}) {
|
}) {
|
||||||
if (itemEntries.length === 0 && stairEntries.length === 0) {
|
if (itemEntries.length === 0 && stairEntries.length === 0) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
const itemNodes = itemEntries.map(({ item, points, polygon }) => {
|
const itemNodes = itemEntries.map((itemEntry) => {
|
||||||
|
const { item, points, polygon } = itemEntry
|
||||||
|
const itemDimensionMeasurements = getItemDimensionMeasurementOverlays(itemEntry, unit)
|
||||||
const isSelected = selectedIdSet.has(item.id)
|
const isSelected = selectedIdSet.has(item.id)
|
||||||
const isHighlighted = highlightedIdSet.has(item.id)
|
const isHighlighted = highlightedIdSet.has(item.id)
|
||||||
const isHovered = hoveredItemId === item.id
|
const isHovered = hoveredItemId === item.id
|
||||||
@@ -4309,6 +4313,13 @@ const FloorplanNodeLayer = memo(function FloorplanNodeLayer({
|
|||||||
y2={toSvgY(diagonalBEnd.y)}
|
y2={toSvgY(diagonalBEnd.y)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{itemDimensionMeasurements.length > 0 ? (
|
||||||
|
<FloorplanMeasurementsLayer
|
||||||
|
className="item-dimension-measurement"
|
||||||
|
measurements={itemDimensionMeasurements}
|
||||||
|
palette={palette}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
</g>
|
</g>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -6776,15 +6787,6 @@ export function FloorplanPanel() {
|
|||||||
isFenceEndpointMoveActive ||
|
isFenceEndpointMoveActive ||
|
||||||
isFloorItemBuildActive ||
|
isFloorItemBuildActive ||
|
||||||
isFloorItemMoveActive
|
isFloorItemMoveActive
|
||||||
const itemPlacementDimensionMeasurements = useMemo(() => {
|
|
||||||
if (!isItemPlacementPreviewActive) {
|
|
||||||
return [] as LinearMeasurementOverlay[]
|
|
||||||
}
|
|
||||||
|
|
||||||
return floorplanItemEntries.flatMap((itemEntry) =>
|
|
||||||
getItemDimensionMeasurementOverlays(itemEntry, unit),
|
|
||||||
)
|
|
||||||
}, [floorplanItemEntries, isItemPlacementPreviewActive, unit])
|
|
||||||
const floorplanPreviewStairSegment = useMemo(
|
const floorplanPreviewStairSegment = useMemo(
|
||||||
() =>
|
() =>
|
||||||
StairSegmentNodeSchema.parse({
|
StairSegmentNodeSchema.parse({
|
||||||
@@ -11988,6 +11990,7 @@ export function FloorplanPanel() {
|
|||||||
palette={palette}
|
palette={palette}
|
||||||
selectedIdSet={selectedIdSet}
|
selectedIdSet={selectedIdSet}
|
||||||
stairEntries={renderedFloorplanStairEntries}
|
stairEntries={renderedFloorplanStairEntries}
|
||||||
|
unit={unit}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FloorplanRoofLayer
|
<FloorplanRoofLayer
|
||||||
@@ -11996,12 +11999,6 @@ export function FloorplanPanel() {
|
|||||||
selectedIdSet={selectedIdSet}
|
selectedIdSet={selectedIdSet}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FloorplanMeasurementsLayer
|
|
||||||
className="item-dimension-measurement"
|
|
||||||
measurements={itemPlacementDimensionMeasurements}
|
|
||||||
palette={palette}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<FloorplanMeasurementsLayer
|
<FloorplanMeasurementsLayer
|
||||||
className="opening-placement-dimension"
|
className="opening-placement-dimension"
|
||||||
measurements={movingOpeningPlacementMeasurements}
|
measurements={movingOpeningPlacementMeasurements}
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ import {
|
|||||||
} from '@pascal-app/core'
|
} from '@pascal-app/core'
|
||||||
import { useViewer } from '@pascal-app/viewer'
|
import { useViewer } from '@pascal-app/viewer'
|
||||||
import { Html } from '@react-three/drei'
|
import { Html } from '@react-three/drei'
|
||||||
import { useFrame } from '@react-three/fiber'
|
import { createPortal, useFrame } from '@react-three/fiber'
|
||||||
import { useEffect, useRef } from 'react'
|
import { useEffect, useRef, useState } from 'react'
|
||||||
import {
|
import {
|
||||||
BoxGeometry,
|
BoxGeometry,
|
||||||
Box3,
|
Box3,
|
||||||
@@ -221,6 +221,10 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|||||||
const previewBoundsSignatureRef = useRef<string | null>(null)
|
const previewBoundsSignatureRef = useRef<string | null>(null)
|
||||||
const meshPreviewAppliedRef = useRef(false)
|
const meshPreviewAppliedRef = useRef(false)
|
||||||
const dimensionBoundsRef = useRef<PreviewBounds | null>(null)
|
const dimensionBoundsRef = useRef<PreviewBounds | null>(null)
|
||||||
|
const [measurementTargetState, setMeasurementTargetState] = useState<{
|
||||||
|
id: string
|
||||||
|
object: Object3D
|
||||||
|
} | null>(null)
|
||||||
|
|
||||||
// Store config callbacks in refs to avoid re-running effect when they change
|
// Store config callbacks in refs to avoid re-running effect when they change
|
||||||
const configRef = useRef(config)
|
const configRef = useRef(config)
|
||||||
@@ -1172,6 +1176,12 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|||||||
if (!draftNode.current) return
|
if (!draftNode.current) return
|
||||||
const mesh = sceneRegistry.nodes.get(draftNode.current.id)
|
const mesh = sceneRegistry.nodes.get(draftNode.current.id)
|
||||||
if (!mesh) return
|
if (!mesh) return
|
||||||
|
if (
|
||||||
|
measurementTargetState?.id !== draftNode.current.id ||
|
||||||
|
measurementTargetState.object !== mesh
|
||||||
|
) {
|
||||||
|
setMeasurementTargetState({ id: draftNode.current.id, object: mesh })
|
||||||
|
}
|
||||||
|
|
||||||
if (!meshPreviewAppliedRef.current) {
|
if (!meshPreviewAppliedRef.current) {
|
||||||
const previewBounds = getPreviewBoundsFromObject(mesh)
|
const previewBounds = getPreviewBoundsFromObject(mesh)
|
||||||
@@ -1207,10 +1217,6 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|||||||
draftNode.current.rotation,
|
draftNode.current.rotation,
|
||||||
)
|
)
|
||||||
mesh.position.y = slabElevation
|
mesh.position.y = slabElevation
|
||||||
// Cursor group is at the world root (not inside a level group), so add the
|
|
||||||
// level group's current world Y to convert from level-local to world space.
|
|
||||||
const levelGroup = sceneRegistry.nodes.get(levelId as AnyNodeId)
|
|
||||||
cursorGroupRef.current.position.y = slabElevation + (levelGroup?.position.y ?? 0)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -1247,11 +1253,12 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|||||||
initialDimensionBounds.center[2] - initialDimensionBounds.dimensions[2] / 2,
|
initialDimensionBounds.center[2] - initialDimensionBounds.dimensions[2] / 2,
|
||||||
]
|
]
|
||||||
|
|
||||||
return (
|
const measurementTarget =
|
||||||
<group ref={cursorGroupRef}>
|
draftNode.current && measurementTargetState?.id === draftNode.current.id
|
||||||
<lineSegments layers={EDITOR_LAYER} material={edgeMaterial} ref={edgesRef} renderOrder={999}>
|
? measurementTargetState.object
|
||||||
<edgesGeometry args={[initialBoxGeometry]} />
|
: null
|
||||||
</lineSegments>
|
const measurementContent = (
|
||||||
|
<>
|
||||||
<lineSegments
|
<lineSegments
|
||||||
layers={EDITOR_LAYER}
|
layers={EDITOR_LAYER}
|
||||||
material={measurementMaterial}
|
material={measurementMaterial}
|
||||||
@@ -1330,6 +1337,15 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea
|
|||||||
{heightLabel}
|
{heightLabel}
|
||||||
</div>
|
</div>
|
||||||
</Html>
|
</Html>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<group ref={cursorGroupRef}>
|
||||||
|
<lineSegments layers={EDITOR_LAYER} material={edgeMaterial} ref={edgesRef} renderOrder={999}>
|
||||||
|
<edgesGeometry args={[initialBoxGeometry]} />
|
||||||
|
</lineSegments>
|
||||||
|
{measurementTarget ? createPortal(measurementContent, measurementTarget) : measurementContent}
|
||||||
<mesh
|
<mesh
|
||||||
geometry={basePlaneGeometry}
|
geometry={basePlaneGeometry}
|
||||||
layers={EDITOR_LAYER}
|
layers={EDITOR_LAYER}
|
||||||
|
|||||||
Reference in New Issue
Block a user