diff --git a/frontend/src/components/viewer/Scene.tsx b/frontend/src/components/viewer/Scene.tsx index 72753c3..7bb249e 100644 --- a/frontend/src/components/viewer/Scene.tsx +++ b/frontend/src/components/viewer/Scene.tsx @@ -24,11 +24,38 @@ function useClippingPlanes(): THREE.Plane[] { }, [enabled, axis, position]); } -function FocusController() { +function CameraController({ modelFiles }: { modelFiles: string[] }) { const controlsRef = useRef(null); - const { scene } = useThree(); + const { scene, camera } = useThree(); const focusRequest = useAtlasStore((s) => s.focusRequest); + // Malhas reais (Z-Anatomy) não seguem a mesma escala/origem que os + // modelos esquemáticos antigos (podem vir em cm, ou centralizadas em + // outro ponto) — em vez de assumir uma posição de câmera fixa, sempre + // que o conjunto de arquivos carregados muda, enquadra a câmera no + // bounding box real de tudo que está na cena. + useEffect(() => { + if (!controlsRef.current || modelFiles.length === 0) return; + const id = requestAnimationFrame(() => { + const box = new THREE.Box3().setFromObject(scene); + if (box.isEmpty()) return; + const size = box.getSize(new THREE.Vector3()).length(); + // Ajusta os planos de corte da câmera ao tamanho real do conteúdo — + // um "far" fixo pequeno cortaria (tornaria invisível) um modelo bem + // maior do que o esperado. + camera.near = Math.max(size / 1000, 0.001); + camera.far = size * 100; + if (camera instanceof THREE.PerspectiveCamera) camera.updateProjectionMatrix(); + controlsRef.current?.fitToBox(box, true, { + paddingLeft: 0.2, + paddingRight: 0.2, + paddingTop: 0.2, + paddingBottom: 0.2, + }); + }); + return () => cancelAnimationFrame(id); + }, [modelFiles, scene, camera]); + useEffect(() => { if (!focusRequest || !controlsRef.current) return; const obj = scene.getObjectByName(focusRequest.slug); @@ -47,8 +74,8 @@ function FocusController() { ); } @@ -89,7 +116,7 @@ export function Scene({ bySlug }: { bySlug: Map }) { return ( @@ -120,7 +147,7 @@ export function Scene({ bySlug }: { bySlug: Map }) { fadeDistance={6} infiniteGrid /> - + ); }