cortes anatomicos
This commit is contained in:
1 parent
ff1b344ad1
commit
baf749caa8
4 files changed
+137
-38
No files matched your search
@@ -6,22 +6,47 @@ import { useAtlasStore, type BodyRegion, type ClipAxis } from "../../store/useAt
|
||||
import { SystemModel } from "./SystemModel.js";
|
||||
import type { Structure } from "../../lib/api.js";
|
||||
|
||||
const AXIS_CONFIG: Record<ClipAxis, { normal: [number, number, number]; min: number; max: number }> = {
|
||||
sagittal: { normal: [1, 0, 0], min: -0.4, max: 0.4 },
|
||||
coronal: { normal: [0, 0, 1], min: -0.3, max: 0.3 },
|
||||
transverse: { normal: [0, -1, 0], min: -1.8, max: 0 },
|
||||
// Normais de referência em anatomia: sagital separa esq./dir., coronal
|
||||
// (= frontal) separa ant./post., transversal separa sup./inf.
|
||||
const AXIS_NORMAL: Record<ClipAxis, [number, number, number]> = {
|
||||
sagittal: [1, 0, 0],
|
||||
coronal: [0, 0, 1],
|
||||
transverse: [0, -1, 0],
|
||||
};
|
||||
|
||||
// Corte oblíquo = pega a normal de um dos 3 planos-base e inclina em torno
|
||||
// dos outros dois eixos (em graus) — cobre qualquer ângulo, não só os 3
|
||||
// puros. A posição do corte é sempre relativa ao bounding box REAL do
|
||||
// conteúdo carregado (não a um intervalo fixo chutado), então o corte
|
||||
// atravessa a parte do corpo certa não importa a escala/origem dos dados.
|
||||
function useClippingPlanes(): THREE.Plane[] {
|
||||
const { enabled, axis, position } = useAtlasStore((s) => s.clipping);
|
||||
const { enabled, axis, position, tiltX, tiltZ } = useAtlasStore((s) => s.clipping);
|
||||
const contentBox = useAtlasStore((s) => s.contentBox);
|
||||
|
||||
return useMemo(() => {
|
||||
if (!enabled) return [];
|
||||
const cfg = AXIS_CONFIG[axis];
|
||||
const t = (position + 1) / 2; // normalize -1..1 -> 0..1
|
||||
const constant = cfg.min + t * (cfg.max - cfg.min);
|
||||
const normal = new THREE.Vector3(...cfg.normal);
|
||||
return [new THREE.Plane(normal, -constant)];
|
||||
}, [enabled, axis, position]);
|
||||
if (!enabled || !contentBox) return [];
|
||||
|
||||
const normal = new THREE.Vector3(...AXIS_NORMAL[axis]);
|
||||
const euler = new THREE.Euler(
|
||||
THREE.MathUtils.degToRad(tiltX),
|
||||
0,
|
||||
THREE.MathUtils.degToRad(tiltZ),
|
||||
);
|
||||
normal.applyEuler(euler).normalize();
|
||||
|
||||
const box = new THREE.Box3(
|
||||
new THREE.Vector3(...contentBox.min),
|
||||
new THREE.Vector3(...contentBox.max),
|
||||
);
|
||||
const center = box.getCenter(new THREE.Vector3());
|
||||
const size = box.getSize(new THREE.Vector3());
|
||||
const halfExtent =
|
||||
(Math.abs(normal.x) * size.x + Math.abs(normal.y) * size.y + Math.abs(normal.z) * size.z) / 2;
|
||||
|
||||
const pointOnPlane = center.clone().addScaledVector(normal, position * halfExtent);
|
||||
const constant = -normal.dot(pointOnPlane);
|
||||
return [new THREE.Plane(normal, constant)];
|
||||
}, [enabled, axis, position, tiltX, tiltZ, contentBox]);
|
||||
}
|
||||
|
||||
function isFiniteVec3(v: THREE.Vector3): boolean {
|
||||
@@ -77,6 +102,7 @@ function CameraController({ modelFiles }: { modelFiles: string[] }) {
|
||||
const { scene, camera } = useThree();
|
||||
const focusRequest = useAtlasStore((s) => s.focusRequest);
|
||||
const regionFocusRequest = useAtlasStore((s) => s.regionFocusRequest);
|
||||
const setContentBox = useAtlasStore((s) => s.setContentBox);
|
||||
|
||||
// Malhas reais (Z-Anatomy) não seguem a mesma escala/origem que os
|
||||
// modelos esquemáticos antigos (podem vir em cm, ou centralizadas em
|
||||
@@ -88,6 +114,10 @@ function CameraController({ modelFiles }: { modelFiles: string[] }) {
|
||||
const id = requestAnimationFrame(() => {
|
||||
const box = computeVisibleBoundingBox(scene);
|
||||
if (box.isEmpty()) return;
|
||||
setContentBox({
|
||||
min: [box.min.x, box.min.y, box.min.z],
|
||||
max: [box.max.x, box.max.y, box.max.z],
|
||||
});
|
||||
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
|
||||
@@ -103,7 +133,7 @@ function CameraController({ modelFiles }: { modelFiles: string[] }) {
|
||||
});
|
||||
});
|
||||
return () => cancelAnimationFrame(id);
|
||||
}, [modelFiles, scene, camera]);
|
||||
}, [modelFiles, scene, camera, setContentBox]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!focusRequest || !controlsRef.current) return;
|
||||
|
||||
Reference in new issue
Block a user