planos e eixos camera
Signed-off-by: Rodrigo Bertoldo de Sousa Martins <rodrigo@martinsevieira.adv.br>
This commit is contained in:
1 parent
1d875ace2c
commit
64793922af
5 files changed
+103
-52
No files matched your search
@@ -2,9 +2,10 @@ import { Suspense, useEffect, useMemo, useRef, type ReactNode } from "react";
|
||||
import { Canvas, useThree } from "@react-three/fiber";
|
||||
import { CameraControls, Grid } from "@react-three/drei";
|
||||
import * as THREE from "three";
|
||||
import { useAtlasStore, type BodyRegion, type ClipAxis } from "../../store/useAtlasStore.js";
|
||||
import { useAtlasStore, type ClipAxis } from "../../store/useAtlasStore.js";
|
||||
import { SystemModel } from "./SystemModel.js";
|
||||
import type { Structure } from "../../lib/api.js";
|
||||
import { computeVisibleBoundingBox, regionSubBox } from "../../lib/bodyRegionBox.js";
|
||||
|
||||
// Sistemas sem .glb pra carregar — tegumentar/histologia são
|
||||
// fotomicrografias 2D reais com hotspots (ver SkinDiagram.tsx e
|
||||
@@ -56,53 +57,6 @@ function useClippingPlanes(): THREE.Plane[] {
|
||||
}, [enabled, axis, position, tiltX, tiltZ, contentBox]);
|
||||
}
|
||||
|
||||
function isFiniteVec3(v: THREE.Vector3): boolean {
|
||||
return Number.isFinite(v.x) && Number.isFinite(v.y) && Number.isFinite(v.z);
|
||||
}
|
||||
|
||||
// Une o bounding box só das malhas VISÍVEIS e com geometria válida —
|
||||
// alguns objetos do dataset real (anotações/curvas do Z-Anatomy) podem ter
|
||||
// vértices degenerados/NaN, e Box3.setFromObject(scene) ingenuamente
|
||||
// incluiria isso, distorcendo o enquadramento (ou escondendo tudo o mais
|
||||
// fora do "zoom" resultante).
|
||||
function computeVisibleBoundingBox(root: THREE.Object3D): THREE.Box3 {
|
||||
const union = new THREE.Box3();
|
||||
const tmp = new THREE.Box3();
|
||||
root.traverse((obj) => {
|
||||
const mesh = obj as THREE.Mesh;
|
||||
if (!mesh.isMesh || !mesh.visible) return;
|
||||
tmp.setFromObject(mesh);
|
||||
if (tmp.isEmpty()) return;
|
||||
if (!isFiniteVec3(tmp.min) || !isFiniteVec3(tmp.max)) return;
|
||||
union.union(tmp);
|
||||
});
|
||||
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);
|
||||
|
||||
Reference in new issue
Block a user