From 921fb8f12e66f8dee4f760f83dc286148a28b02a Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Thu, 21 May 2026 12:55:31 +0000 Subject: [PATCH] Changes Co-authored-by: Reifonas <211114984+Reifonas@users.noreply.github.com> --- src/components/three/ModelViewer.tsx | 99 +++++++++++++++++++++------- 1 file changed, 75 insertions(+), 24 deletions(-) diff --git a/src/components/three/ModelViewer.tsx b/src/components/three/ModelViewer.tsx index 2a1061e..dd1f5ad 100644 --- a/src/components/three/ModelViewer.tsx +++ b/src/components/three/ModelViewer.tsx @@ -167,26 +167,82 @@ function SceneModels() { ); } -/** Sphere marker at a 3D point */ +/** Sphere marker at a 3D point — scaled per-frame to keep constant screen size */ function PointMarker({ position, color = '#e8a838' }: { position: [number, number, number]; color?: string }) { + const ref = useRef(null); + const { camera, size } = useThree(); + useFrame(() => { + if (!ref.current) return; + const dist = camera.position.distanceTo(ref.current.position); + const perspCam = camera as THREE.PerspectiveCamera; + const fov = (perspCam.fov ?? 50) * (Math.PI / 180); + const worldPerPixel = (2 * dist * Math.tan(fov / 2)) / size.height; + // Target: ~6 px radius (radius = 1 in base geometry → scale = 6*wpp) + const s = Math.max(0.0005, 6 * worldPerPixel); + ref.current.scale.setScalar(s); + }); return ( - - - + + + ); } -/** Snap ring indicator */ -function SnapRing({ position }: { position: [number, number, number] }) { +/** Snap ring indicator — scaled per-frame */ +function SnapRing({ position, color = '#eab308' }: { position: [number, number, number]; color?: string }) { + const ref = useRef(null); + const { camera, size } = useThree(); + useFrame(() => { + if (!ref.current) return; + ref.current.lookAt(camera.position); + const dist = camera.position.distanceTo(ref.current.position); + const perspCam = camera as THREE.PerspectiveCamera; + const fov = (perspCam.fov ?? 50) * (Math.PI / 180); + const worldPerPixel = (2 * dist * Math.tan(fov / 2)) / size.height; + const s = Math.max(0.0008, 10 * worldPerPixel); + ref.current.scale.setScalar(s); + }); return ( - - - + + + ); } +/** Computes a distanceFactor that keeps an Html label roughly constant on screen */ +function useLabelDistanceFactor(position: [number, number, number]): number { + const { camera, size } = useThree(); + const v = useMemo(() => new THREE.Vector3(), []); + const ref = useRef(1); + useFrame(() => { + v.set(position[0], position[1], position[2]); + const dist = camera.position.distanceTo(v); + const perspCam = camera as THREE.PerspectiveCamera; + const fov = (perspCam.fov ?? 50) * (Math.PI / 180); + const worldPerPixel = (2 * dist * Math.tan(fov / 2)) / size.height; + // distanceFactor scales the html so it stays ~140 px tall at this distance + ref.current = Math.max(0.05, worldPerPixel * 140); + }); + return ref.current; +} + +function MeasurementLabel({ position, text, variant }: { position: [number, number, number]; text: string; variant: 'success' | 'primary' }) { + const df = useLabelDistanceFactor(position); + const borderClass = variant === 'success' ? 'border-success/60' : 'border-primary/60'; + const textClass = variant === 'success' ? 'text-success' : 'text-primary'; + return ( + +
+ + {text} + +
+ + ); +} + /** Renders all measurements, snap point, and hover info */ function MeasurementOverlay() { const measurements = useModelStore((s) => s.measurements); @@ -194,6 +250,8 @@ function MeasurementOverlay() { const snapPoint = useModelStore((s) => s.snapPoint); const hoverInfo = useModelStore((s) => s.hoverInfo); const measureMode = useModelStore((s) => s.measureMode); + const scaleRatio = useModelStore((s) => s.scaleRatio); + const factor = scaleRatio?.factor ?? 1; return ( <> @@ -204,14 +262,11 @@ function MeasurementOverlay() { {/* Hover auto-detect tooltip */} {hoverInfo && ( - -
- - {hoverInfo.type === 'hole' ? '⌀ ' : ''} - {hoverInfo.value.toFixed(1)} mm - -
- + )} {/* Pending first point */} @@ -237,14 +292,9 @@ function MeasurementOverlay() { points={[a, b]} color="#22c55e" lineWidth={2} + depthTest={false} /> - -
- - {m.distanceMM.toFixed(1)} mm - -
- + ); })} @@ -252,6 +302,7 @@ function MeasurementOverlay() { ); } + /** Smart vertex snap on pointer move */ function SmartSnapHandler() { const { camera, scene, gl } = useThree();