visualizacao do exame fisico
This commit is contained in:
1 parent
be94073fbb
commit
38833147f8
3 files changed
+104
-15
No files matched your search
@@ -1,11 +1,17 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { useThree } from "@react-three/fiber";
|
import { useFrame, useThree } from "@react-three/fiber";
|
||||||
import { Html } from "@react-three/drei";
|
import { Html } from "@react-three/drei";
|
||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
import { useAtlasStore } from "../../store/useAtlasStore.js";
|
import { useAtlasStore } from "../../store/useAtlasStore.js";
|
||||||
import type { ExamPoint, ExamTechnique, ExamAnchor } from "../../data/physicalExam.js";
|
import type { ExamPoint, ExamTechnique, ExamAnchor, ExamSide } from "../../data/physicalExam.js";
|
||||||
import { TECHNIQUES } from "../../data/physicalExam.js";
|
import { TECHNIQUES } from "../../data/physicalExam.js";
|
||||||
|
|
||||||
|
// Mesma convenção usada em PlanesPage (AXES: "Anterior" aponta pra +Z) —
|
||||||
|
// assumimos que o corpo real do Z-Anatomy segue a mesma orientação. Se na
|
||||||
|
// prática ficar invertido (pontos anteriores só aparecem vendo de trás),
|
||||||
|
// é só trocar o sinal aqui.
|
||||||
|
const ANTERIOR_DIR = new THREE.Vector3(0, 0, 1);
|
||||||
|
|
||||||
// Os pontos de exame são ancorados no bounding box de OSSOS REAIS do
|
// Os pontos de exame são ancorados no bounding box de OSSOS REAIS do
|
||||||
// esqueleto (esterno, costelas, vértebras, bacia, crânio, rádio, tíbia) em
|
// esqueleto (esterno, costelas, vértebras, bacia, crânio, rádio, tíbia) em
|
||||||
// vez de uma fração do corpo inteiro — assim herdam a escala/posição
|
// vez de uma fração do corpo inteiro — assim herdam a escala/posição
|
||||||
@@ -130,10 +136,14 @@ export function ExamMarkers({
|
|||||||
points,
|
points,
|
||||||
selectedId,
|
selectedId,
|
||||||
onSelect,
|
onSelect,
|
||||||
|
onSideChange,
|
||||||
}: {
|
}: {
|
||||||
points: ExamPoint[];
|
points: ExamPoint[];
|
||||||
selectedId: string | null;
|
selectedId: string | null;
|
||||||
onSelect: (id: string) => void;
|
onSelect: (id: string) => void;
|
||||||
|
// Avisa a página (fora do Canvas) de que lado o usuário está vendo agora
|
||||||
|
// — só pra mostrar uma dica textual, opcional.
|
||||||
|
onSideChange?: (side: ExamSide) => void;
|
||||||
}) {
|
}) {
|
||||||
const { scene } = useThree();
|
const { scene } = useThree();
|
||||||
// As mesmas CameraControls registradas pelo Scene.tsx (makeDefault) —
|
// As mesmas CameraControls registradas pelo Scene.tsx (makeDefault) —
|
||||||
@@ -206,9 +216,31 @@ export function ExamMarkers({
|
|||||||
return bodyBox;
|
return bodyBox;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Só mostra os pontos do lado que a câmera está encarando (anterior ou
|
||||||
|
// posterior) — senão um ponto da frente e um das costas ficam colados no
|
||||||
|
// mesmo lugar aparente na tela, e não dá pra saber em qual se está
|
||||||
|
// clicando. Atualiza a cada frame, mas só dispara re-render quando o
|
||||||
|
// lado realmente muda (não a cada frame).
|
||||||
|
const [visibleSide, setVisibleSide] = useState<ExamSide>("anterior");
|
||||||
|
const visibleSideRef = useRef<ExamSide>("anterior");
|
||||||
|
useFrame(({ camera }) => {
|
||||||
|
const center = bodyBox?.getCenter(new THREE.Vector3()) ?? anchors.thorax?.getCenter(new THREE.Vector3());
|
||||||
|
if (!center) return;
|
||||||
|
const toCamera = camera.position.clone().sub(center);
|
||||||
|
if (toCamera.lengthSq() < 1e-8) return;
|
||||||
|
const side: ExamSide = toCamera.dot(ANTERIOR_DIR) >= 0 ? "anterior" : "posterior";
|
||||||
|
if (side !== visibleSideRef.current) {
|
||||||
|
visibleSideRef.current = side;
|
||||||
|
setVisibleSide(side);
|
||||||
|
onSideChange?.(side);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{points.map((p) => {
|
{points
|
||||||
|
.filter((p) => p.side === visibleSide)
|
||||||
|
.map((p) => {
|
||||||
const box = resolveBox(p.anchor);
|
const box = resolveBox(p.anchor);
|
||||||
if (!box) return null;
|
if (!box) return null;
|
||||||
const [fx, fy, fz] = p.fraction;
|
const [fx, fy, fz] = p.fraction;
|
||||||
|
|||||||
@@ -19,6 +19,11 @@
|
|||||||
// reais a partir daqui, o lado esquerdo/direito (fx) é uma estimativa —
|
// reais a partir daqui, o lado esquerdo/direito (fx) é uma estimativa —
|
||||||
// se aparecer trocado no app, é só inverter o fx do ponto (1 - fx).
|
// se aparecer trocado no app, é só inverter o fx do ponto (1 - fx).
|
||||||
export type ExamTechnique = "inspecao" | "palpacao" | "percussao" | "ausculta";
|
export type ExamTechnique = "inspecao" | "palpacao" | "percussao" | "ausculta";
|
||||||
|
// De que lado do corpo o ponto fica (usado pra só mostrar o marcador
|
||||||
|
// quando a câmera está olhando pro lado certo — ver ExamMarkers.tsx —
|
||||||
|
// senão um ponto da frente e um das costas no mesmo lugar aparente
|
||||||
|
// confundiriam qual está sendo clicado).
|
||||||
|
export type ExamSide = "anterior" | "posterior";
|
||||||
export type ExamAnchor =
|
export type ExamAnchor =
|
||||||
| "thorax"
|
| "thorax"
|
||||||
| "abdomen"
|
| "abdomen"
|
||||||
@@ -43,6 +48,7 @@ export interface ExamPoint {
|
|||||||
system: string;
|
system: string;
|
||||||
technique: ExamTechnique;
|
technique: ExamTechnique;
|
||||||
anchor: ExamAnchor;
|
anchor: ExamAnchor;
|
||||||
|
side: ExamSide;
|
||||||
fraction: [number, number, number];
|
fraction: [number, number, number];
|
||||||
howTo: string;
|
howTo: string;
|
||||||
whatFor: string;
|
whatFor: string;
|
||||||
@@ -56,6 +62,7 @@ export const EXAM_POINTS: ExamPoint[] = [
|
|||||||
system: "Geral",
|
system: "Geral",
|
||||||
technique: "inspecao",
|
technique: "inspecao",
|
||||||
anchor: "head",
|
anchor: "head",
|
||||||
|
side: "anterior",
|
||||||
fraction: [0.5, 0.6, 0.8],
|
fraction: [0.5, 0.6, 0.8],
|
||||||
howTo: "Observe o paciente por completo antes de tocar: estado geral, nível de consciência, postura, fácies, coloração da pele e mucosas, hidratação.",
|
howTo: "Observe o paciente por completo antes de tocar: estado geral, nível de consciência, postura, fácies, coloração da pele e mucosas, hidratação.",
|
||||||
whatFor: "Primeira etapa de qualquer exame físico — muitas pistas diagnósticas (icterícia, cianose, palidez, dispneia) aparecem só de olhar, antes de qualquer manobra.",
|
whatFor: "Primeira etapa de qualquer exame físico — muitas pistas diagnósticas (icterícia, cianose, palidez, dispneia) aparecem só de olhar, antes de qualquer manobra.",
|
||||||
@@ -68,6 +75,7 @@ export const EXAM_POINTS: ExamPoint[] = [
|
|||||||
system: "Cardiovascular",
|
system: "Cardiovascular",
|
||||||
technique: "ausculta",
|
technique: "ausculta",
|
||||||
anchor: "thorax",
|
anchor: "thorax",
|
||||||
|
side: "anterior",
|
||||||
fraction: [0.42, 0.88, 0.85],
|
fraction: [0.42, 0.88, 0.85],
|
||||||
howTo: "2º espaço intercostal, à direita do esterno. Ausculte com o diafragma do estetoscópio, paciente sentado ou deitado.",
|
howTo: "2º espaço intercostal, à direita do esterno. Ausculte com o diafragma do estetoscópio, paciente sentado ou deitado.",
|
||||||
whatFor: "Melhor foco para a valva aórtica — sopros de estenose/insuficiência aórtica costumam ser mais audíveis aqui.",
|
whatFor: "Melhor foco para a valva aórtica — sopros de estenose/insuficiência aórtica costumam ser mais audíveis aqui.",
|
||||||
@@ -78,6 +86,7 @@ export const EXAM_POINTS: ExamPoint[] = [
|
|||||||
system: "Cardiovascular",
|
system: "Cardiovascular",
|
||||||
technique: "ausculta",
|
technique: "ausculta",
|
||||||
anchor: "thorax",
|
anchor: "thorax",
|
||||||
|
side: "anterior",
|
||||||
fraction: [0.58, 0.88, 0.85],
|
fraction: [0.58, 0.88, 0.85],
|
||||||
howTo: "2º espaço intercostal, à esquerda do esterno.",
|
howTo: "2º espaço intercostal, à esquerda do esterno.",
|
||||||
whatFor: "Melhor foco para a valva pulmonar — sopros de estenose/insuficiência pulmonar e desdobramento de B2.",
|
whatFor: "Melhor foco para a valva pulmonar — sopros de estenose/insuficiência pulmonar e desdobramento de B2.",
|
||||||
@@ -88,6 +97,7 @@ export const EXAM_POINTS: ExamPoint[] = [
|
|||||||
system: "Cardiovascular",
|
system: "Cardiovascular",
|
||||||
technique: "ausculta",
|
technique: "ausculta",
|
||||||
anchor: "thorax",
|
anchor: "thorax",
|
||||||
|
side: "anterior",
|
||||||
fraction: [0.58, 0.78, 0.85],
|
fraction: [0.58, 0.78, 0.85],
|
||||||
howTo: "3º espaço intercostal, à esquerda do esterno.",
|
howTo: "3º espaço intercostal, à esquerda do esterno.",
|
||||||
whatFor: "Bom ponto para captar sopros diastólicos de insuficiência aórtica, que às vezes irradiam melhor pra cá do que pro foco aórtico clássico.",
|
whatFor: "Bom ponto para captar sopros diastólicos de insuficiência aórtica, que às vezes irradiam melhor pra cá do que pro foco aórtico clássico.",
|
||||||
@@ -98,6 +108,7 @@ export const EXAM_POINTS: ExamPoint[] = [
|
|||||||
system: "Cardiovascular",
|
system: "Cardiovascular",
|
||||||
technique: "ausculta",
|
technique: "ausculta",
|
||||||
anchor: "thorax",
|
anchor: "thorax",
|
||||||
|
side: "anterior",
|
||||||
fraction: [0.56, 0.68, 0.85],
|
fraction: [0.56, 0.68, 0.85],
|
||||||
howTo: "4º-5º espaço intercostal, na borda esternal esquerda baixa.",
|
howTo: "4º-5º espaço intercostal, na borda esternal esquerda baixa.",
|
||||||
whatFor: "Melhor foco para a valva tricúspide — sopros de insuficiência/estenose tricúspide.",
|
whatFor: "Melhor foco para a valva tricúspide — sopros de insuficiência/estenose tricúspide.",
|
||||||
@@ -108,6 +119,7 @@ export const EXAM_POINTS: ExamPoint[] = [
|
|||||||
system: "Cardiovascular",
|
system: "Cardiovascular",
|
||||||
technique: "ausculta",
|
technique: "ausculta",
|
||||||
anchor: "thorax",
|
anchor: "thorax",
|
||||||
|
side: "anterior",
|
||||||
fraction: [0.68, 0.58, 0.85],
|
fraction: [0.68, 0.58, 0.85],
|
||||||
howTo: "5º espaço intercostal esquerdo, na linha hemiclavicular (região do ictus cordis).",
|
howTo: "5º espaço intercostal esquerdo, na linha hemiclavicular (região do ictus cordis).",
|
||||||
whatFor: "Melhor foco para a valva mitral — sopro de estenose mitral (ruflar diastólico) e insuficiência mitral (sopro holossistólico).",
|
whatFor: "Melhor foco para a valva mitral — sopro de estenose mitral (ruflar diastólico) e insuficiência mitral (sopro holossistólico).",
|
||||||
@@ -118,6 +130,7 @@ export const EXAM_POINTS: ExamPoint[] = [
|
|||||||
system: "Cardiovascular",
|
system: "Cardiovascular",
|
||||||
technique: "palpacao",
|
technique: "palpacao",
|
||||||
anchor: "thorax",
|
anchor: "thorax",
|
||||||
|
side: "anterior",
|
||||||
fraction: [0.69, 0.58, 0.87],
|
fraction: [0.69, 0.58, 0.87],
|
||||||
howTo: "Palpe com a polpa dos dedos (ou a região tenar) o 5º espaço intercostal esquerdo, linha hemiclavicular.",
|
howTo: "Palpe com a polpa dos dedos (ou a região tenar) o 5º espaço intercostal esquerdo, linha hemiclavicular.",
|
||||||
whatFor: "Localiza o ápice do coração; desvio lateral ou impulso muito forte sugere cardiomegalia/hipertrofia ventricular.",
|
whatFor: "Localiza o ápice do coração; desvio lateral ou impulso muito forte sugere cardiomegalia/hipertrofia ventricular.",
|
||||||
@@ -128,6 +141,7 @@ export const EXAM_POINTS: ExamPoint[] = [
|
|||||||
system: "Cardiovascular",
|
system: "Cardiovascular",
|
||||||
technique: "palpacao",
|
technique: "palpacao",
|
||||||
anchor: "thorax",
|
anchor: "thorax",
|
||||||
|
side: "anterior",
|
||||||
fraction: [0.6, 0.73, 0.85],
|
fraction: [0.6, 0.73, 0.85],
|
||||||
howTo: "Apoie a palma da mão sobre o precórdio e sinta uma vibração (\"gato ronronando\").",
|
howTo: "Apoie a palma da mão sobre o precórdio e sinta uma vibração (\"gato ronronando\").",
|
||||||
whatFor: "Frêmito = sopro cardíaco intenso o bastante para ser sentido, geralmente indica lesão valvar significativa.",
|
whatFor: "Frêmito = sopro cardíaco intenso o bastante para ser sentido, geralmente indica lesão valvar significativa.",
|
||||||
@@ -140,6 +154,7 @@ export const EXAM_POINTS: ExamPoint[] = [
|
|||||||
system: "Respiratório",
|
system: "Respiratório",
|
||||||
technique: "ausculta",
|
technique: "ausculta",
|
||||||
anchor: "thorax",
|
anchor: "thorax",
|
||||||
|
side: "anterior",
|
||||||
fraction: [0.22, 0.92, 0.75],
|
fraction: [0.22, 0.92, 0.75],
|
||||||
howTo: "Ausculte logo acima da clavícula direita, pedindo ao paciente para respirar fundo pela boca.",
|
howTo: "Ausculte logo acima da clavícula direita, pedindo ao paciente para respirar fundo pela boca.",
|
||||||
whatFor: "Murmúrio vesicular reduzido/ausente ou ruídos adventícios (estertores, sibilos) localizados aqui sugerem acometimento do ápice pulmonar direito.",
|
whatFor: "Murmúrio vesicular reduzido/ausente ou ruídos adventícios (estertores, sibilos) localizados aqui sugerem acometimento do ápice pulmonar direito.",
|
||||||
@@ -150,6 +165,7 @@ export const EXAM_POINTS: ExamPoint[] = [
|
|||||||
system: "Respiratório",
|
system: "Respiratório",
|
||||||
technique: "ausculta",
|
technique: "ausculta",
|
||||||
anchor: "thorax",
|
anchor: "thorax",
|
||||||
|
side: "anterior",
|
||||||
fraction: [0.78, 0.92, 0.75],
|
fraction: [0.78, 0.92, 0.75],
|
||||||
howTo: "Mesma manobra do lado esquerdo, logo acima da clavícula esquerda.",
|
howTo: "Mesma manobra do lado esquerdo, logo acima da clavícula esquerda.",
|
||||||
whatFor: "Comparação bilateral é essencial — assimetria entre os dois ápices é o achado mais importante.",
|
whatFor: "Comparação bilateral é essencial — assimetria entre os dois ápices é o achado mais importante.",
|
||||||
@@ -160,6 +176,7 @@ export const EXAM_POINTS: ExamPoint[] = [
|
|||||||
system: "Respiratório",
|
system: "Respiratório",
|
||||||
technique: "ausculta",
|
technique: "ausculta",
|
||||||
anchor: "thorax",
|
anchor: "thorax",
|
||||||
|
side: "anterior",
|
||||||
fraction: [0.18, 0.6, 0.7],
|
fraction: [0.18, 0.6, 0.7],
|
||||||
howTo: "Ausculte na linha hemiclavicular/axilar direita, altura do 4º espaço intercostal.",
|
howTo: "Ausculte na linha hemiclavicular/axilar direita, altura do 4º espaço intercostal.",
|
||||||
whatFor: "Zona onde sopros tubários e estertores de pneumonia em lobo médio costumam aparecer primeiro.",
|
whatFor: "Zona onde sopros tubários e estertores de pneumonia em lobo médio costumam aparecer primeiro.",
|
||||||
@@ -170,6 +187,7 @@ export const EXAM_POINTS: ExamPoint[] = [
|
|||||||
system: "Respiratório",
|
system: "Respiratório",
|
||||||
technique: "ausculta",
|
technique: "ausculta",
|
||||||
anchor: "thorax",
|
anchor: "thorax",
|
||||||
|
side: "anterior",
|
||||||
fraction: [0.82, 0.6, 0.7],
|
fraction: [0.82, 0.6, 0.7],
|
||||||
howTo: "Mesma altura, do lado esquerdo.",
|
howTo: "Mesma altura, do lado esquerdo.",
|
||||||
whatFor: "Comparação bilateral do murmúrio vesicular e de ruídos adventícios.",
|
whatFor: "Comparação bilateral do murmúrio vesicular e de ruídos adventícios.",
|
||||||
@@ -180,7 +198,8 @@ export const EXAM_POINTS: ExamPoint[] = [
|
|||||||
system: "Respiratório",
|
system: "Respiratório",
|
||||||
technique: "ausculta",
|
technique: "ausculta",
|
||||||
anchor: "thorax",
|
anchor: "thorax",
|
||||||
fraction: [0.16, 0.2, 0.65],
|
side: "posterior",
|
||||||
|
fraction: [0.16, 0.2, 0.15],
|
||||||
howTo: "Ausculte nas bases (região inferior do tórax, de preferência também pelas costas).",
|
howTo: "Ausculte nas bases (região inferior do tórax, de preferência também pelas costas).",
|
||||||
whatFor: "Local clássico de estertores crepitantes (insuficiência cardíaca, pneumonia de base) e de derrame pleural (murmúrio abolido).",
|
whatFor: "Local clássico de estertores crepitantes (insuficiência cardíaca, pneumonia de base) e de derrame pleural (murmúrio abolido).",
|
||||||
},
|
},
|
||||||
@@ -190,7 +209,8 @@ export const EXAM_POINTS: ExamPoint[] = [
|
|||||||
system: "Respiratório",
|
system: "Respiratório",
|
||||||
technique: "ausculta",
|
technique: "ausculta",
|
||||||
anchor: "thorax",
|
anchor: "thorax",
|
||||||
fraction: [0.84, 0.2, 0.65],
|
side: "posterior",
|
||||||
|
fraction: [0.84, 0.2, 0.15],
|
||||||
howTo: "Mesma região, do lado esquerdo.",
|
howTo: "Mesma região, do lado esquerdo.",
|
||||||
whatFor: "Comparação bilateral das bases — assimetria é o achado mais valioso.",
|
whatFor: "Comparação bilateral das bases — assimetria é o achado mais valioso.",
|
||||||
},
|
},
|
||||||
@@ -200,6 +220,7 @@ export const EXAM_POINTS: ExamPoint[] = [
|
|||||||
system: "Respiratório",
|
system: "Respiratório",
|
||||||
technique: "palpacao",
|
technique: "palpacao",
|
||||||
anchor: "thorax",
|
anchor: "thorax",
|
||||||
|
side: "posterior",
|
||||||
fraction: [0.5, 0.45, 0.05],
|
fraction: [0.5, 0.45, 0.05],
|
||||||
howTo: "Coloque as mãos espalmadas nas costas do paciente, polegares próximos à linha média, e peça para respirar fundo — observe se os polegares se afastam simetricamente.",
|
howTo: "Coloque as mãos espalmadas nas costas do paciente, polegares próximos à linha média, e peça para respirar fundo — observe se os polegares se afastam simetricamente.",
|
||||||
whatFor: "Redução da expansibilidade de um lado sugere derrame pleural, atelectasia ou pneumotórax naquele hemitórax.",
|
whatFor: "Redução da expansibilidade de um lado sugere derrame pleural, atelectasia ou pneumotórax naquele hemitórax.",
|
||||||
@@ -210,6 +231,7 @@ export const EXAM_POINTS: ExamPoint[] = [
|
|||||||
system: "Respiratório",
|
system: "Respiratório",
|
||||||
technique: "palpacao",
|
technique: "palpacao",
|
||||||
anchor: "thorax",
|
anchor: "thorax",
|
||||||
|
side: "anterior",
|
||||||
fraction: [0.68, 0.55, 0.8],
|
fraction: [0.68, 0.55, 0.8],
|
||||||
howTo: "Apoie a borda ulnar das mãos no tórax e peça ao paciente para dizer \"trinta e três\" repetidamente, comparando os dois lados.",
|
howTo: "Apoie a borda ulnar das mãos no tórax e peça ao paciente para dizer \"trinta e três\" repetidamente, comparando os dois lados.",
|
||||||
whatFor: "Aumentado em condensações (pneumonia); diminuído/abolido em derrame pleural, pneumotórax ou DPOC.",
|
whatFor: "Aumentado em condensações (pneumonia); diminuído/abolido em derrame pleural, pneumotórax ou DPOC.",
|
||||||
@@ -220,7 +242,8 @@ export const EXAM_POINTS: ExamPoint[] = [
|
|||||||
system: "Respiratório",
|
system: "Respiratório",
|
||||||
technique: "percussao",
|
technique: "percussao",
|
||||||
anchor: "thorax",
|
anchor: "thorax",
|
||||||
fraction: [0.25, 0.55, 0.8],
|
side: "posterior",
|
||||||
|
fraction: [0.4, 0.75, 0.15],
|
||||||
howTo: "Percuta comparando os dois hemitóraxes, de cima para baixo, com o dedo plexímetro bem apoiado entre os espaços intercostais.",
|
howTo: "Percuta comparando os dois hemitóraxes, de cima para baixo, com o dedo plexímetro bem apoiado entre os espaços intercostais.",
|
||||||
whatFor: "Som claro pulmonar normal; hipertimpanismo sugere pneumotórax; macicez/submacicez sugere derrame pleural ou consolidação.",
|
whatFor: "Som claro pulmonar normal; hipertimpanismo sugere pneumotórax; macicez/submacicez sugere derrame pleural ou consolidação.",
|
||||||
},
|
},
|
||||||
@@ -232,6 +255,7 @@ export const EXAM_POINTS: ExamPoint[] = [
|
|||||||
system: "Abdominal",
|
system: "Abdominal",
|
||||||
technique: "inspecao",
|
technique: "inspecao",
|
||||||
anchor: "abdomen",
|
anchor: "abdomen",
|
||||||
|
side: "anterior",
|
||||||
fraction: [0.5, 0.7, 0.85],
|
fraction: [0.5, 0.7, 0.85],
|
||||||
howTo: "Com o paciente deitado e relaxado, observe forma, simetria, distensão, cicatrizes, circulação colateral e peristaltismo visível.",
|
howTo: "Com o paciente deitado e relaxado, observe forma, simetria, distensão, cicatrizes, circulação colateral e peristaltismo visível.",
|
||||||
whatFor: "Abdome distendido, assimétrico ou com peristaltismo visível pode indicar obstrução, massa ou ascite.",
|
whatFor: "Abdome distendido, assimétrico ou com peristaltismo visível pode indicar obstrução, massa ou ascite.",
|
||||||
@@ -242,6 +266,7 @@ export const EXAM_POINTS: ExamPoint[] = [
|
|||||||
system: "Abdominal",
|
system: "Abdominal",
|
||||||
technique: "ausculta",
|
technique: "ausculta",
|
||||||
anchor: "abdomen",
|
anchor: "abdomen",
|
||||||
|
side: "anterior",
|
||||||
fraction: [0.5, 0.5, 0.8],
|
fraction: [0.5, 0.5, 0.8],
|
||||||
howTo: "Ausculte ANTES de palpar ou percutir (essas manobras alteram o peristaltismo) — um ponto já basta, ouça por 1-2 minutos se estiver avaliando ausência de ruídos.",
|
howTo: "Ausculte ANTES de palpar ou percutir (essas manobras alteram o peristaltismo) — um ponto já basta, ouça por 1-2 minutos se estiver avaliando ausência de ruídos.",
|
||||||
whatFor: "Ruídos aumentados sugerem obstrução inicial; ausência de ruídos (\"silêncio abdominal\") é sinal de íleo paralítico/abdome agudo.",
|
whatFor: "Ruídos aumentados sugerem obstrução inicial; ausência de ruídos (\"silêncio abdominal\") é sinal de íleo paralítico/abdome agudo.",
|
||||||
@@ -252,6 +277,7 @@ export const EXAM_POINTS: ExamPoint[] = [
|
|||||||
system: "Abdominal",
|
system: "Abdominal",
|
||||||
technique: "percussao",
|
technique: "percussao",
|
||||||
anchor: "abdomen",
|
anchor: "abdomen",
|
||||||
|
side: "anterior",
|
||||||
fraction: [0.4, 0.4, 0.8],
|
fraction: [0.4, 0.4, 0.8],
|
||||||
howTo: "Percuta os 4 quadrantes — o timpanismo (som mais alto, de tambor) é normal, pela presença de gás nas alças intestinais.",
|
howTo: "Percuta os 4 quadrantes — o timpanismo (som mais alto, de tambor) é normal, pela presença de gás nas alças intestinais.",
|
||||||
whatFor: "Macicez onde deveria haver timpanismo sugere massa, ascite ou visceromegalia; timpanismo excessivo sugere distensão gasosa.",
|
whatFor: "Macicez onde deveria haver timpanismo sugere massa, ascite ou visceromegalia; timpanismo excessivo sugere distensão gasosa.",
|
||||||
@@ -262,6 +288,7 @@ export const EXAM_POINTS: ExamPoint[] = [
|
|||||||
system: "Abdominal",
|
system: "Abdominal",
|
||||||
technique: "percussao",
|
technique: "percussao",
|
||||||
anchor: "abdomen",
|
anchor: "abdomen",
|
||||||
|
side: "anterior",
|
||||||
fraction: [0.2, 0.75, 0.8],
|
fraction: [0.2, 0.75, 0.8],
|
||||||
howTo: "Percuta de cima para baixo na linha hemiclavicular direita, do som claro pulmonar até encontrar macicez (borda superior do fígado), depois do timpanismo abdominal até a macicez (borda inferior).",
|
howTo: "Percuta de cima para baixo na linha hemiclavicular direita, do som claro pulmonar até encontrar macicez (borda superior do fígado), depois do timpanismo abdominal até a macicez (borda inferior).",
|
||||||
whatFor: "Estima o tamanho do fígado; uma loja hepática maior que o esperado sugere hepatomegalia.",
|
whatFor: "Estima o tamanho do fígado; uma loja hepática maior que o esperado sugere hepatomegalia.",
|
||||||
@@ -272,6 +299,7 @@ export const EXAM_POINTS: ExamPoint[] = [
|
|||||||
system: "Abdominal",
|
system: "Abdominal",
|
||||||
technique: "palpacao",
|
technique: "palpacao",
|
||||||
anchor: "abdomen",
|
anchor: "abdomen",
|
||||||
|
side: "anterior",
|
||||||
fraction: [0.6, 0.55, 0.78],
|
fraction: [0.6, 0.55, 0.78],
|
||||||
howTo: "Com a mão relaxada, palpe levemente todos os quadrantes, avaliando tensão da parede e sensibilidade — sempre deixando a área dolorosa por último.",
|
howTo: "Com a mão relaxada, palpe levemente todos os quadrantes, avaliando tensão da parede e sensibilidade — sempre deixando a área dolorosa por último.",
|
||||||
whatFor: "Detecta defesa muscular voluntária/involuntária e localiza dor antes de aprofundar a palpação.",
|
whatFor: "Detecta defesa muscular voluntária/involuntária e localiza dor antes de aprofundar a palpação.",
|
||||||
@@ -282,6 +310,7 @@ export const EXAM_POINTS: ExamPoint[] = [
|
|||||||
system: "Abdominal",
|
system: "Abdominal",
|
||||||
technique: "palpacao",
|
technique: "palpacao",
|
||||||
anchor: "abdomen",
|
anchor: "abdomen",
|
||||||
|
side: "anterior",
|
||||||
fraction: [0.6, 0.4, 0.78],
|
fraction: [0.6, 0.4, 0.78],
|
||||||
howTo: "Com as duas mãos sobrepostas, palpe mais profundamente para identificar massas, visceromegalias e pontos dolorosos específicos.",
|
howTo: "Com as duas mãos sobrepostas, palpe mais profundamente para identificar massas, visceromegalias e pontos dolorosos específicos.",
|
||||||
whatFor: "Identifica massas abdominais, contornos de vísceras e sinais de irritação peritoneal (dor à descompressão brusca).",
|
whatFor: "Identifica massas abdominais, contornos de vísceras e sinais de irritação peritoneal (dor à descompressão brusca).",
|
||||||
@@ -292,6 +321,7 @@ export const EXAM_POINTS: ExamPoint[] = [
|
|||||||
system: "Abdominal",
|
system: "Abdominal",
|
||||||
technique: "palpacao",
|
technique: "palpacao",
|
||||||
anchor: "abdomen",
|
anchor: "abdomen",
|
||||||
|
side: "anterior",
|
||||||
fraction: [0.2, 0.12, 0.78],
|
fraction: [0.2, 0.12, 0.78],
|
||||||
howTo: "Localize o ponto entre o terço lateral e os dois terços mediais da linha que liga a espinha ilíaca ântero-superior direita ao umbigo; palpe e avalie a descompressão brusca.",
|
howTo: "Localize o ponto entre o terço lateral e os dois terços mediais da linha que liga a espinha ilíaca ântero-superior direita ao umbigo; palpe e avalie a descompressão brusca.",
|
||||||
whatFor: "Dor à palpação (e principalmente à descompressão brusca) neste ponto é clássica de apendicite aguda.",
|
whatFor: "Dor à palpação (e principalmente à descompressão brusca) neste ponto é clássica de apendicite aguda.",
|
||||||
@@ -302,6 +332,7 @@ export const EXAM_POINTS: ExamPoint[] = [
|
|||||||
system: "Abdominal",
|
system: "Abdominal",
|
||||||
technique: "palpacao",
|
technique: "palpacao",
|
||||||
anchor: "abdomen",
|
anchor: "abdomen",
|
||||||
|
side: "anterior",
|
||||||
fraction: [0.22, 0.78, 0.78],
|
fraction: [0.22, 0.78, 0.78],
|
||||||
howTo: "Palpe sob o rebordo costal direito e peça ao paciente para inspirar fundo.",
|
howTo: "Palpe sob o rebordo costal direito e peça ao paciente para inspirar fundo.",
|
||||||
whatFor: "Sinal positivo = parada súbita da inspiração por dor — sugere colecistite aguda.",
|
whatFor: "Sinal positivo = parada súbita da inspiração por dor — sugere colecistite aguda.",
|
||||||
@@ -312,6 +343,7 @@ export const EXAM_POINTS: ExamPoint[] = [
|
|||||||
system: "Abdominal",
|
system: "Abdominal",
|
||||||
technique: "palpacao",
|
technique: "palpacao",
|
||||||
anchor: "abdomen",
|
anchor: "abdomen",
|
||||||
|
side: "anterior",
|
||||||
fraction: [0.2, 0.7, 0.8],
|
fraction: [0.2, 0.7, 0.8],
|
||||||
howTo: "Com a mão em garra sob o rebordo costal direito, peça para o paciente inspirar fundo e sinta a borda hepática \"escapar\" sob os dedos.",
|
howTo: "Com a mão em garra sob o rebordo costal direito, peça para o paciente inspirar fundo e sinta a borda hepática \"escapar\" sob os dedos.",
|
||||||
whatFor: "Avalia tamanho, consistência e borda do fígado — borda romba/endurecida sugere hepatopatia crônica.",
|
whatFor: "Avalia tamanho, consistência e borda do fígado — borda romba/endurecida sugere hepatopatia crônica.",
|
||||||
@@ -322,6 +354,7 @@ export const EXAM_POINTS: ExamPoint[] = [
|
|||||||
system: "Abdominal",
|
system: "Abdominal",
|
||||||
technique: "palpacao",
|
technique: "palpacao",
|
||||||
anchor: "abdomen",
|
anchor: "abdomen",
|
||||||
|
side: "anterior",
|
||||||
fraction: [0.82, 0.78, 0.75],
|
fraction: [0.82, 0.78, 0.75],
|
||||||
howTo: "Com o paciente em decúbito lateral direito, palpe sob o rebordo costal esquerdo durante a inspiração profunda.",
|
howTo: "Com o paciente em decúbito lateral direito, palpe sob o rebordo costal esquerdo durante a inspiração profunda.",
|
||||||
whatFor: "O baço normal não é palpável — se for palpável, geralmente indica esplenomegalia.",
|
whatFor: "O baço normal não é palpável — se for palpável, geralmente indica esplenomegalia.",
|
||||||
@@ -334,6 +367,7 @@ export const EXAM_POINTS: ExamPoint[] = [
|
|||||||
system: "Vascular",
|
system: "Vascular",
|
||||||
technique: "palpacao",
|
technique: "palpacao",
|
||||||
anchor: "neck",
|
anchor: "neck",
|
||||||
|
side: "anterior",
|
||||||
fraction: [0.4, 0.5, 0.6],
|
fraction: [0.4, 0.5, 0.6],
|
||||||
howTo: "Palpe suavemente (nunca os dois lados ao mesmo tempo) na borda anterior do músculo esternocleidomastóideo, no pescoço.",
|
howTo: "Palpe suavemente (nunca os dois lados ao mesmo tempo) na borda anterior do músculo esternocleidomastóideo, no pescoço.",
|
||||||
whatFor: "Avalia amplitude e ritmo do pulso central; útil também pra avaliar sopros carotídeos com a ausculta.",
|
whatFor: "Avalia amplitude e ritmo do pulso central; útil também pra avaliar sopros carotídeos com a ausculta.",
|
||||||
@@ -344,6 +378,7 @@ export const EXAM_POINTS: ExamPoint[] = [
|
|||||||
system: "Vascular",
|
system: "Vascular",
|
||||||
technique: "palpacao",
|
technique: "palpacao",
|
||||||
anchor: "radiusR",
|
anchor: "radiusR",
|
||||||
|
side: "anterior",
|
||||||
fraction: [0.5, 0.05, 0.6],
|
fraction: [0.5, 0.05, 0.6],
|
||||||
howTo: "Palpe com 2-3 dedos na face anterior do punho, lateralmente (lado do polegar).",
|
howTo: "Palpe com 2-3 dedos na face anterior do punho, lateralmente (lado do polegar).",
|
||||||
whatFor: "Pulso periférico mais usado na prática — avalia frequência, ritmo, amplitude e simetria entre os dois lados.",
|
whatFor: "Pulso periférico mais usado na prática — avalia frequência, ritmo, amplitude e simetria entre os dois lados.",
|
||||||
@@ -354,6 +389,7 @@ export const EXAM_POINTS: ExamPoint[] = [
|
|||||||
system: "Vascular",
|
system: "Vascular",
|
||||||
technique: "palpacao",
|
technique: "palpacao",
|
||||||
anchor: "pelvis",
|
anchor: "pelvis",
|
||||||
|
side: "anterior",
|
||||||
fraction: [0.25, 0.15, 0.75],
|
fraction: [0.25, 0.15, 0.75],
|
||||||
howTo: "Palpe na região inguinal, no ponto médio entre a espinha ilíaca ântero-superior e a sínfise púbica.",
|
howTo: "Palpe na região inguinal, no ponto médio entre a espinha ilíaca ântero-superior e a sínfise púbica.",
|
||||||
whatFor: "Assimetria ou atraso entre pulso femoral e radial (\"pulso em atraso\") sugere coarctação de aorta.",
|
whatFor: "Assimetria ou atraso entre pulso femoral e radial (\"pulso em atraso\") sugere coarctação de aorta.",
|
||||||
@@ -364,6 +400,7 @@ export const EXAM_POINTS: ExamPoint[] = [
|
|||||||
system: "Vascular",
|
system: "Vascular",
|
||||||
technique: "palpacao",
|
technique: "palpacao",
|
||||||
anchor: "tibiaR",
|
anchor: "tibiaR",
|
||||||
|
side: "anterior",
|
||||||
fraction: [0.5, 0.02, 0.6],
|
fraction: [0.5, 0.02, 0.6],
|
||||||
howTo: "Palpe no dorso do pé, lateralmente ao tendão do extensor longo do hálux.",
|
howTo: "Palpe no dorso do pé, lateralmente ao tendão do extensor longo do hálux.",
|
||||||
whatFor: "Ausência sugere doença arterial periférica — compare sempre os dois pés.",
|
whatFor: "Ausência sugere doença arterial periférica — compare sempre os dois pés.",
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { Scene } from "../components/viewer/Scene.js";
|
|||||||
import { ExamMarkers } from "../components/viewer/ExamMarkers.js";
|
import { ExamMarkers } from "../components/viewer/ExamMarkers.js";
|
||||||
import { LayerToggle } from "../components/LayerToggle.js";
|
import { LayerToggle } from "../components/LayerToggle.js";
|
||||||
import { QuickRegionNav } from "../components/QuickRegionNav.js";
|
import { QuickRegionNav } from "../components/QuickRegionNav.js";
|
||||||
import { EXAM_POINTS, TECHNIQUES, type ExamTechnique } from "../data/physicalExam.js";
|
import { EXAM_POINTS, TECHNIQUES, type ExamTechnique, type ExamSide } from "../data/physicalExam.js";
|
||||||
|
|
||||||
// Módulo de estudo pro exame físico, sobre o corpo 3D REAL do Z-Anatomy
|
// Módulo de estudo pro exame físico, sobre o corpo 3D REAL do Z-Anatomy
|
||||||
// (mesmo visualizador do Atlas — camadas, navegação por região, câmera
|
// (mesmo visualizador do Atlas — camadas, navegação por região, câmera
|
||||||
@@ -17,9 +17,15 @@ import { EXAM_POINTS, TECHNIQUES, type ExamTechnique } from "../data/physicalExa
|
|||||||
// ExamMarkers.tsx) mesmo que o usuário não tenha marcado essa camada —
|
// ExamMarkers.tsx) mesmo que o usuário não tenha marcado essa camada —
|
||||||
// por isso é sempre buscado/carregado aqui, independente do toggle.
|
// por isso é sempre buscado/carregado aqui, independente do toggle.
|
||||||
const ALWAYS_LOAD = ["esqueletico"];
|
const ALWAYS_LOAD = ["esqueletico"];
|
||||||
|
// Visualmente, um corpo com a pele/regiões de superfície faz muito mais
|
||||||
|
// sentido pra exame físico do que o esqueleto nu (é na pele que se
|
||||||
|
// ausculta/palpa/percute) — esse é o layer mostrado por padrão ao entrar
|
||||||
|
// nesta página; o usuário pode trocar/adicionar outras camadas no painel.
|
||||||
|
const DEFAULT_VISIBLE = ["regioes"];
|
||||||
|
|
||||||
export default function PhysicalExamPage() {
|
export default function PhysicalExamPage() {
|
||||||
const visibleSystems = useAtlasStore((s) => s.visibleSystems);
|
const visibleSystems = useAtlasStore((s) => s.visibleSystems);
|
||||||
|
const setVisibleSystems = useAtlasStore((s) => s.setVisibleSystems);
|
||||||
const fetchSystems = useMemo(
|
const fetchSystems = useMemo(
|
||||||
() => new Set([...visibleSystems, ...ALWAYS_LOAD]),
|
() => new Set([...visibleSystems, ...ALWAYS_LOAD]),
|
||||||
[visibleSystems],
|
[visibleSystems],
|
||||||
@@ -31,9 +37,13 @@ export default function PhysicalExamPage() {
|
|||||||
() => new Set(TECHNIQUES.map((t) => t.key)),
|
() => new Set(TECHNIQUES.map((t) => t.key)),
|
||||||
);
|
);
|
||||||
const [selectedId, setSelectedId] = useState<string | null>(null);
|
const [selectedId, setSelectedId] = useState<string | null>(null);
|
||||||
|
const [viewSide, setViewSide] = useState<ExamSide>("anterior");
|
||||||
const [leftOpen, setLeftOpen] = useState(false);
|
const [leftOpen, setLeftOpen] = useState(false);
|
||||||
const [rightOpen, setRightOpen] = useState(false);
|
const [rightOpen, setRightOpen] = useState(false);
|
||||||
|
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
useEffect(() => setVisibleSystems(DEFAULT_VISIBLE), []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedStructureId) {
|
if (selectedStructureId) {
|
||||||
setRightOpen(true);
|
setRightOpen(true);
|
||||||
@@ -95,9 +105,10 @@ export default function PhysicalExamPage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p className="text-[11px] text-slate-500 mt-4 leading-relaxed">
|
<p className="text-[11px] text-slate-500 mt-4 leading-relaxed">
|
||||||
Ligue uma camada (ex: Esquelético) como referência, marque as
|
Marque as técnicas que quer estudar e clique nos pontos coloridos
|
||||||
técnicas que quer estudar e clique nos pontos coloridos sobre o
|
sobre o corpo. Use o menu de regiões pra focar rápido numa parte
|
||||||
corpo. Use o menu de regiões pra focar rápido numa parte do corpo.
|
do corpo, e gire o modelo pra ver os pontos da frente ou de trás
|
||||||
|
— só aparecem os do lado que você está olhando.
|
||||||
</p>
|
</p>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
@@ -113,13 +124,22 @@ export default function PhysicalExamPage() {
|
|||||||
|
|
||||||
<div className="relative h-full min-h-0">
|
<div className="relative h-full min-h-0">
|
||||||
<Scene bySlug={bySlug} alwaysLoadSystems={ALWAYS_LOAD}>
|
<Scene bySlug={bySlug} alwaysLoadSystems={ALWAYS_LOAD}>
|
||||||
<ExamMarkers points={visiblePoints} selectedId={selectedId} onSelect={(id) => {
|
<ExamMarkers
|
||||||
setSelectedId(id);
|
points={visiblePoints}
|
||||||
setRightOpen(true);
|
selectedId={selectedId}
|
||||||
}} />
|
onSelect={(id) => {
|
||||||
|
setSelectedId(id);
|
||||||
|
setRightOpen(true);
|
||||||
|
}}
|
||||||
|
onSideChange={setViewSide}
|
||||||
|
/>
|
||||||
</Scene>
|
</Scene>
|
||||||
<QuickRegionNav />
|
<QuickRegionNav />
|
||||||
|
|
||||||
|
<div className="absolute bottom-3 left-3 z-10 bg-panel/90 border border-white/10 rounded-lg px-3 py-1.5 text-xs text-slate-300 shadow-lg">
|
||||||
|
Vista: <span className="font-semibold text-white">{viewSide === "anterior" ? "Anterior" : "Posterior"}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
onClick={() => setLeftOpen(true)}
|
onClick={() => setLeftOpen(true)}
|
||||||
className="md:hidden absolute top-3 left-3 z-10 bg-panel/90 border border-white/10 rounded-lg px-3 py-2 text-xs shadow-lg"
|
className="md:hidden absolute top-3 left-3 z-10 bg-panel/90 border border-white/10 rounded-lg px-3 py-2 text-xs shadow-lg"
|
||||||
|
|||||||
Reference in new issue
Block a user