diff --git a/frontend/components/model/ModelViewer.tsx b/frontend/components/model/ModelViewer.tsx index 96c8e25..853b6dc 100644 --- a/frontend/components/model/ModelViewer.tsx +++ b/frontend/components/model/ModelViewer.tsx @@ -21,13 +21,13 @@ import { ImportMeshAsync, PointerEventTypes, PointerInfo, + Matrix, } from '@babylonjs/core' import '@babylonjs/loaders' import SceneToolbar from './SceneToolbar'; import LoadingSpinner from '../ui/LoadingSpinner' - - + export interface ModelViewerProps { modelPath: string onSelectModel: (path: string) => void; @@ -201,8 +201,7 @@ const ModelViewer: React.FC = ({ ); } }; - - + useEffect(() => { isDisposedRef.current = false isInitializedRef.current = false @@ -548,6 +547,49 @@ const ModelViewer: React.FC = ({ } }, [focusSensorId, modelReady]) + // Расчет позиции оверлея + const computeOverlayPosition = React.useCallback((mesh: AbstractMesh | null) => { + if (!sceneRef.current || !mesh) return null + const scene = sceneRef.current + try { + const bbox = (typeof mesh.getHierarchyBoundingVectors === 'function') + ? mesh.getHierarchyBoundingVectors() + : { min: mesh.getBoundingInfo().boundingBox.minimumWorld, max: mesh.getBoundingInfo().boundingBox.maximumWorld } + const center = bbox.min.add(bbox.max).scale(0.5) + + const viewport = scene.activeCamera?.viewport.toGlobal(engineRef.current!.getRenderWidth(), engineRef.current!.getRenderHeight()) + if (!viewport) return null + + const projected = Vector3.Project(center, Matrix.Identity(), scene.getTransformMatrix(), viewport) + if (!projected) return null + + return { left: projected.x, top: projected.y } + } catch (error) { + console.error('[ModelViewer] Error computing overlay position:', error) + return null + } + }, []) + + // Позиция оверлея изначально + useEffect(() => { + if (!chosenMeshRef.current || !overlayData) return + const pos = computeOverlayPosition(chosenMeshRef.current) + setOverlayPos(pos) + }, [overlayData, computeOverlayPosition]) + + // Позиция оверлея при движущейся камере + useEffect(() => { + if (!sceneRef.current || !chosenMeshRef.current || !overlayData) return + const scene = sceneRef.current + + const updateOverlayPosition = () => { + const pos = computeOverlayPosition(chosenMeshRef.current) + setOverlayPos(pos) + } + scene.registerBeforeRender(updateOverlayPosition) + return () => scene.unregisterBeforeRender(updateOverlayPosition) + }, [overlayData, computeOverlayPosition]) + return (
{!modelPath ? ( @@ -603,16 +645,9 @@ const ModelViewer: React.FC = ({ /> )} - {renderOverlay + {renderOverlay && overlayPos && overlayData ? renderOverlay({ anchor: overlayPos, info: overlayData }) - : (overlayData && overlayPos && ( -
-
-
{overlayData.name || 'Sensor'}
- {overlayData.sensorId &&
ID: {overlayData.sensorId}
} -
-
- )) + : null }
)