mudanca de camera

This commit is contained in:
Rodrigo Bertoldo de Sousa Martins committed 2026-09-08 20:12:08 -03:00
1 parent b7facab432
commit c9fc1ad6c7
4 files changed
+95 -1

No files matched your search

+41 -1
View File
@@ -2,7 +2,7 @@ import { Suspense, useEffect, useMemo, useRef } from "react";
import { Canvas, useThree } from "@react-three/fiber";
import { CameraControls, Grid } from "@react-three/drei";
import * as THREE from "three";
import { useAtlasStore, type ClipAxis } from "../../store/useAtlasStore.js";
import { useAtlasStore, type BodyRegion, type ClipAxis } from "../../store/useAtlasStore.js";
import { SystemModel } from "./SystemModel.js";
import type { Structure } from "../../lib/api.js";
@@ -47,10 +47,36 @@ function computeVisibleBoundingBox(root: THREE.Object3D): THREE.Box3 {
return union;
}
// Faixas aproximadas de altura (0 = pés, 1 = topo da cabeça) usadas pela
// navegação rápida por região — proporções corporais padrão de um adulto
// em pé. Regiões dos membros usam a largura toda (os braços ficam nas
// bordas laterais dessa faixa de altura).
const BODY_REGION_Y_RANGES: Record<Exclude<BodyRegion, "corpo_inteiro">, [number, number]> = {
cabeca: [0.85, 1.0],
pescoco: [0.8, 0.87],
torax: [0.62, 0.83],
abdome: [0.52, 0.65],
pelve: [0.42, 0.55],
membros_superiores: [0.55, 0.88],
membros_inferiores: [0.0, 0.45],
};
function regionSubBox(total: THREE.Box3, region: BodyRegion): THREE.Box3 {
if (region === "corpo_inteiro") return total;
const [t0, t1] = BODY_REGION_Y_RANGES[region];
const yMin = THREE.MathUtils.lerp(total.min.y, total.max.y, t0);
const yMax = THREE.MathUtils.lerp(total.min.y, total.max.y, t1);
return new THREE.Box3(
new THREE.Vector3(total.min.x, yMin, total.min.z),
new THREE.Vector3(total.max.x, yMax, total.max.z),
);
}
function CameraController({ modelFiles }: { modelFiles: string[] }) {
const controlsRef = useRef<CameraControls>(null);
const { scene, camera } = useThree();
const focusRequest = useAtlasStore((s) => s.focusRequest);
const regionFocusRequest = useAtlasStore((s) => s.regionFocusRequest);
// Malhas reais (Z-Anatomy) não seguem a mesma escala/origem que os
// modelos esquemáticos antigos (podem vir em cm, ou centralizadas em
@@ -93,6 +119,20 @@ function CameraController({ modelFiles }: { modelFiles: string[] }) {
});
}, [focusRequest, scene]);
useEffect(() => {
if (!regionFocusRequest || !controlsRef.current) return;
const total = computeVisibleBoundingBox(scene);
if (total.isEmpty()) return;
const box = regionSubBox(total, regionFocusRequest.region);
if (box.isEmpty()) return;
controlsRef.current.fitToBox(box, true, {
paddingLeft: 0.3,
paddingRight: 0.3,
paddingTop: 0.3,
paddingBottom: 0.3,
});
}, [regionFocusRequest, scene]);
return (
<CameraControls
ref={controlsRef}