Respect unit preference in alignment guides
This commit is contained in:
@@ -1,7 +1,9 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { useAlignmentGuides } from '@pascal-app/core'
|
import { useAlignmentGuides } from '@pascal-app/core'
|
||||||
|
import { useViewer } from '@pascal-app/viewer'
|
||||||
import { memo } from 'react'
|
import { memo } from 'react'
|
||||||
|
import { formatMeasurement } from '../editor/measurement-pill'
|
||||||
import { useFloorplanRender } from './floorplan-render-context'
|
import { useFloorplanRender } from './floorplan-render-context'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -23,6 +25,7 @@ import { useFloorplanRender } from './floorplan-render-context'
|
|||||||
*/
|
*/
|
||||||
export const FloorplanAlignmentGuideLayer = memo(function FloorplanAlignmentGuideLayer() {
|
export const FloorplanAlignmentGuideLayer = memo(function FloorplanAlignmentGuideLayer() {
|
||||||
const guides = useAlignmentGuides((s) => s.guides)
|
const guides = useAlignmentGuides((s) => s.guides)
|
||||||
|
const unit = useViewer((s) => s.unit)
|
||||||
const ctx = useFloorplanRender()
|
const ctx = useFloorplanRender()
|
||||||
|
|
||||||
if (guides.length === 0) return null
|
if (guides.length === 0) return null
|
||||||
@@ -56,7 +59,7 @@ export const FloorplanAlignmentGuideLayer = memo(function FloorplanAlignmentGuid
|
|||||||
// offset along X.
|
// offset along X.
|
||||||
const pillX = axis === 'x' ? midX + pillOffset : midX
|
const pillX = axis === 'x' ? midX + pillOffset : midX
|
||||||
const pillZ = axis === 'z' ? midZ + pillOffset : midZ
|
const pillZ = axis === 'z' ? midZ + pillOffset : midZ
|
||||||
const distLabel = formatMeters(distMeters)
|
const distLabel = formatMeasurement(distMeters, unit)
|
||||||
const charWidth = pillFontSize * 0.55
|
const charWidth = pillFontSize * 0.55
|
||||||
const pillWidth = distLabel.length * charWidth + pillPadX * 2
|
const pillWidth = distLabel.length * charWidth + pillPadX * 2
|
||||||
const pillHeight = pillFontSize + pillPadY * 2
|
const pillHeight = pillFontSize + pillPadY * 2
|
||||||
@@ -135,10 +138,3 @@ function XCap({
|
|||||||
</g>
|
</g>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatMeters(meters: number): string {
|
|
||||||
// Sub-centimetre = "0". Otherwise show with up to 2 decimals, trimmed.
|
|
||||||
if (meters < 0.005) return '0'
|
|
||||||
const fixed = meters.toFixed(2)
|
|
||||||
return `${fixed.replace(/\.?0+$/, '')}m`
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { memo, useMemo, useRef } from 'react'
|
|||||||
import { BoxGeometry, CircleGeometry, type Group } from 'three'
|
import { BoxGeometry, CircleGeometry, type Group } from 'three'
|
||||||
import { MeshBasicNodeMaterial } from 'three/webgpu'
|
import { MeshBasicNodeMaterial } from 'three/webgpu'
|
||||||
import { EDITOR_LAYER } from '../../lib/constants'
|
import { EDITOR_LAYER } from '../../lib/constants'
|
||||||
|
import { formatMeasurement } from './measurement-pill'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Figma-style alignment guides for the 3D editor — the spatial twin of
|
* Figma-style alignment guides for the 3D editor — the spatial twin of
|
||||||
@@ -53,6 +54,7 @@ type Vec3 = [number, number, number]
|
|||||||
export const Alignment3DGuideLayer = memo(function Alignment3DGuideLayer() {
|
export const Alignment3DGuideLayer = memo(function Alignment3DGuideLayer() {
|
||||||
const guides = useAlignmentGuides((s) => s.guides)
|
const guides = useAlignmentGuides((s) => s.guides)
|
||||||
const levelId = useViewer((s) => s.selection.levelId)
|
const levelId = useViewer((s) => s.selection.levelId)
|
||||||
|
const unit = useViewer((s) => s.unit)
|
||||||
const groupRef = useRef<Group>(null)
|
const groupRef = useRef<Group>(null)
|
||||||
|
|
||||||
// Guides carry only XZ (building-local plan coords); their Y has to track
|
// Guides carry only XZ (building-local plan coords); their Y has to track
|
||||||
@@ -71,16 +73,16 @@ export const Alignment3DGuideLayer = memo(function Alignment3DGuideLayer() {
|
|||||||
return (
|
return (
|
||||||
<group ref={groupRef}>
|
<group ref={groupRef}>
|
||||||
{guides.map((guide, i) => (
|
{guides.map((guide, i) => (
|
||||||
<GuideLine guide={guide} key={i} />
|
<GuideLine guide={guide} key={i} unit={unit} />
|
||||||
))}
|
))}
|
||||||
</group>
|
</group>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
function GuideLine({ guide }: { guide: AlignmentGuide }) {
|
function GuideLine({ guide, unit }: { guide: AlignmentGuide; unit: 'metric' | 'imperial' }) {
|
||||||
const { x: fx, z: fz } = guide.from
|
const { x: fx, z: fz } = guide.from
|
||||||
const { x: tx, z: tz } = guide.to
|
const { x: tx, z: tz } = guide.to
|
||||||
const distLabel = formatMeters(guide.distance)
|
const distLabel = formatMeasurement(guide.distance, unit)
|
||||||
|
|
||||||
// Lay out the dash centres along the from→to direction. The ribbon
|
// Lay out the dash centres along the from→to direction. The ribbon
|
||||||
// stretches the dash period up if the line is long enough to exceed the
|
// stretches the dash period up if the line is long enough to exceed the
|
||||||
@@ -152,11 +154,3 @@ function Dot({ position }: { position: Vec3 }) {
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatMeters(meters: number): string {
|
|
||||||
// Sub-centimetre = "0"; otherwise up to 2 decimals, trimmed. Matches the
|
|
||||||
// 2D floor-plan guide layer's pill formatting.
|
|
||||||
if (meters < 0.005) return '0'
|
|
||||||
const fixed = meters.toFixed(2)
|
|
||||||
return `${fixed.replace(/\.?0+$/, '')}m`
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user