planos anatomicos

Signed-off-by: Rodrigo Bertoldo de Sousa Martins <rodrigo@MacBook-Air-de-Rodrigo.local>
This commit is contained in:
Rodrigo Bertoldo de Sousa Martins committed 2026-09-14 21:06:47 -03:00
1 parent 06ace7505c
commit 19bc92356f
1 file changed
+128 -17
+128 -17
View File
@@ -19,24 +19,111 @@ const PLANES: PlaneDef[] = [
{ key: "transverse", label: "Plano Transversal (Axial)", color: "#f2c14e", args: [1.2, 1.2], position: [0, 0.9, 0], rotation: [Math.PI / 2, 0, 0] }, { key: "transverse", label: "Plano Transversal (Axial)", color: "#f2c14e", args: [1.2, 1.2], position: [0, 0.9, 0], rotation: [Math.PI / 2, 0, 0] },
]; ];
const AXES: { label: string; from: [number, number, number]; to: [number, number, number]; color: string }[] = [ interface AxisDef {
label: string;
from: [number, number, number];
to: [number, number, number];
color: string;
}
interface AxisGroup {
key: string;
label: string;
hint: string;
axes: AxisDef[];
}
// Cada grupo é ancorado numa região reconhecível do boneco (tronco, braço,
// perna) — como pedido, usando o modelo de regiões do corpo como base pras
// setas em vez de setas soltas no espaço. Ficam com toggle independente
// porque mostrar todos os pares de uma vez deixaria o modelo ilegível.
const AXIS_GROUPS: AxisGroup[] = [
{
key: "principal",
label: "Eixos principais do corpo",
hint: "Superior/Inferior, Anterior/Posterior, Direita/Esquerda",
axes: [
{ label: "Superior", from: [0, 0.9, 0], to: [0, 1.9, 0], color: "#f87171" }, { label: "Superior", from: [0, 0.9, 0], to: [0, 1.9, 0], color: "#f87171" },
{ label: "Inferior", from: [0, 0.9, 0], to: [0, -0.1, 0], color: "#f87171" }, { label: "Inferior", from: [0, 0.9, 0], to: [0, -0.1, 0], color: "#f87171" },
{ label: "Anterior", from: [0, 0.9, 0], to: [0, 0.9, 0.9], color: "#34d399" }, { label: "Anterior", from: [0, 0.9, 0], to: [0, 0.9, 0.9], color: "#34d399" },
{ label: "Posterior", from: [0, 0.9, 0], to: [0, 0.9, -0.9], color: "#34d399" }, { label: "Posterior", from: [0, 0.9, 0], to: [0, 0.9, -0.9], color: "#34d399" },
{ label: "Direita (do paciente)", from: [0, 0.9, 0], to: [-0.7, 0.9, 0], color: "#a78bfa" }, { label: "Direita (do paciente)", from: [0, 0.9, 0], to: [-0.7, 0.9, 0], color: "#a78bfa" },
{ label: "Esquerda (do paciente)", from: [0, 0.9, 0], to: [0.7, 0.9, 0], color: "#a78bfa" }, { label: "Esquerda (do paciente)", from: [0, 0.9, 0], to: [0.7, 0.9, 0], color: "#a78bfa" },
],
},
{
key: "medial-lateral",
label: "Medial / Lateral (no braço)",
hint: "Em relação à linha média do corpo",
axes: [
{ label: "Medial", from: [-0.28, 1.1, 0.06], to: [-0.04, 1.1, 0.06], color: "#f2c14e" },
{ label: "Lateral", from: [-0.28, 1.1, 0.06], to: [-0.58, 1.1, 0.06], color: "#f2c14e" },
],
},
{
key: "proximal-distal",
label: "Proximal / Distal (na perna)",
hint: "Em relação à raiz do membro (tronco)",
axes: [
{ label: "Proximal", from: [-0.11, 0.32, 0], to: [-0.11, 0.62, 0], color: "#60a5fa" },
{ label: "Distal", from: [-0.11, 0.32, 0], to: [-0.11, -0.02, 0], color: "#60a5fa" },
],
},
{
key: "superficial-profundo",
label: "Superficial / Profundo (no abdome)",
hint: "Em relação à superfície do corpo",
axes: [
{ label: "Superficial", from: [0, 0.75, 0], to: [0, 0.75, 0.32], color: "#f472b6" },
{ label: "Profundo", from: [0, 0.75, 0.32], to: [0, 0.75, -0.18], color: "#f472b6" },
],
},
]; ];
const GLOSSARY: { term: string; def: string }[] = [ interface GlossaryEntry {
{ term: "Anterior / Posterior", def: "Em direção à frente (ventral) ou para trás (dorsal) do corpo." }, term: string;
{ term: "Superior / Inferior", def: "Em direção à cabeça (cranial) ou aos pés (caudal)." }, def: string;
{ term: "Medial / Lateral", def: "Mais próximo (medial) ou mais distante (lateral) do plano mediano/sagital." }, }
{ term: "Proximal / Distal", def: "Mais próximo (proximal) ou mais distante (distal) do tronco/raiz do membro." },
interface GlossaryGroup {
heading: string;
entries: GlossaryEntry[];
}
const GLOSSARY_GROUPS: GlossaryGroup[] = [
{
heading: "Eixos principais",
entries: [
{ term: "Anterior / Posterior", def: "Em direção à frente (ventral) ou para trás (dorsal) do corpo. Em quadrúpedes e embriologia usa-se \"Ventral/Dorsal\" com o mesmo sentido." },
{ term: "Superior / Inferior", def: "Em direção à cabeça (cranial) ou aos pés (caudal). \"Cranial/Caudal\" é usado sobretudo em neuroanatomia e no tronco." },
{ term: "Direita / Esquerda", def: "Sempre referidas ao lado do PACIENTE, não de quem observa — por isso é comum escrever \"direita do paciente\" pra evitar confusão em imagens." },
],
},
{
heading: "Relação entre partes",
entries: [
{ term: "Medial / Lateral", def: "Mais próximo (medial) ou mais distante (lateral) do plano mediano (o plano sagital que passa exatamente pelo centro do corpo)." },
{ term: "Superficial / Profundo", def: "Mais próximo (superficial) ou mais distante (profundo) da superfície do corpo." }, { term: "Superficial / Profundo", def: "Mais próximo (superficial) ou mais distante (profundo) da superfície do corpo." },
{ term: "Plano Sagital", def: "Divide o corpo em partes esquerda e direita (é 'mediano' quando passa exatamente pelo centro)." }, { term: "Externo / Interno", def: "Mais distante (externo) ou mais próximo (interno) do centro de um órgão oco ou cavidade — ex.: camada externa vs. interna da parede do intestino." },
{ term: "Ipsilateral / Contralateral", def: "Duas estruturas do MESMO lado do corpo (ipsilateral) ou de lados OPOSTOS (contralateral) — ex.: o nervo frênico direito é ipsilateral ao pulmão direito e contralateral ao esquerdo." },
],
},
{
heading: "Nos membros",
entries: [
{ term: "Proximal / Distal", def: "Mais próximo (proximal) ou mais distante (distal) da raiz do membro (onde ele se une ao tronco)." },
{ term: "Palmar / Dorsal (mão)", def: "Face da palma da mão (palmar, também chamada volar) ou face do dorso da mão (dorsal)." },
{ term: "Plantar / Dorsal (pé)", def: "Face da sola do pé (plantar) ou face de cima do pé (dorsal)." },
],
},
{
heading: "Planos de secção",
entries: [
{ term: "Plano Sagital", def: "Divide o corpo em partes esquerda e direita (é \"mediano\" quando passa exatamente pelo centro)." },
{ term: "Plano Coronal (Frontal)", def: "Divide o corpo em partes anterior e posterior." }, { term: "Plano Coronal (Frontal)", def: "Divide o corpo em partes anterior e posterior." },
{ term: "Plano Transversal (Axial)", def: "Divide o corpo em partes superior e inferior." }, { term: "Plano Transversal (Axial)", def: "Divide o corpo em partes superior e inferior." },
],
},
]; ];
export default function PlanesPage() { export default function PlanesPage() {
@@ -45,7 +132,12 @@ export default function PlanesPage() {
coronal: false, coronal: false,
transverse: false, transverse: false,
}); });
const [showAxes, setShowAxes] = useState(true); const [visibleAxisGroups, setVisibleAxisGroups] = useState<Record<string, boolean>>({
principal: true,
"medial-lateral": false,
"proximal-distal": false,
"superficial-profundo": false,
});
const [leftOpen, setLeftOpen] = useState(false); const [leftOpen, setLeftOpen] = useState(false);
const [rightOpen, setRightOpen] = useState(false); const [rightOpen, setRightOpen] = useState(false);
@@ -78,10 +170,23 @@ export default function PlanesPage() {
</label> </label>
))} ))}
<label className="flex items-center gap-2 text-sm cursor-pointer pt-2 border-t border-white/10 mt-3"> <h3 className="text-xs uppercase tracking-wide text-slate-400 pt-3 border-t border-white/10 mt-3">
<input type="checkbox" checked={showAxes} onChange={() => setShowAxes((v) => !v)} className="accent-accent" /> Termos de Direção
Eixos e termos de direção </h3>
{AXIS_GROUPS.map((g) => (
<label key={g.key} className="flex items-start gap-2 text-sm cursor-pointer">
<input
type="checkbox"
checked={visibleAxisGroups[g.key]}
onChange={() => setVisibleAxisGroups((v) => ({ ...v, [g.key]: !v[g.key] }))}
className="accent-accent mt-0.5"
/>
<span>
{g.label}
<span className="block text-[11px] text-slate-500">{g.hint}</span>
</span>
</label> </label>
))}
</aside> </aside>
{(leftOpen || rightOpen) && ( {(leftOpen || rightOpen) && (
@@ -121,9 +226,9 @@ export default function PlanesPage() {
</mesh> </mesh>
))} ))}
{showAxes && {AXIS_GROUPS.filter((g) => visibleAxisGroups[g.key]).flatMap((g) =>
AXES.map((a) => ( g.axes.map((a) => (
<group key={a.label}> <group key={`${g.key}-${a.label}`}>
<Line points={[a.from, a.to]} color={a.color} lineWidth={2} /> <Line points={[a.from, a.to]} color={a.color} lineWidth={2} />
<Html position={a.to} center distanceFactor={4}> <Html position={a.to} center distanceFactor={4}>
<div <div
@@ -134,7 +239,8 @@ export default function PlanesPage() {
</div> </div>
</Html> </Html>
</group> </group>
))} )),
)}
<CameraControls makeDefault /> <CameraControls makeDefault />
</Canvas> </Canvas>
@@ -142,7 +248,7 @@ export default function PlanesPage() {
<aside <aside
className={`fixed md:static inset-y-0 right-0 z-30 w-[86vw] max-w-[320px] md:w-auto className={`fixed md:static inset-y-0 right-0 z-30 w-[86vw] max-w-[320px] md:w-auto
border-l border-white/10 bg-panel p-4 overflow-y-auto space-y-3 border-l border-white/10 bg-panel p-4 overflow-y-auto space-y-4
transition-transform duration-200 md:translate-x-0 transition-transform duration-200 md:translate-x-0
${rightOpen ? "translate-x-0" : "translate-x-full"}`} ${rightOpen ? "translate-x-0" : "translate-x-full"}`}
> >
@@ -154,12 +260,17 @@ export default function PlanesPage() {
✕ Fechar ✕ Fechar
</button> </button>
<h3 className="text-xs uppercase tracking-wide text-slate-400">Glossário de Direções</h3> <h3 className="text-xs uppercase tracking-wide text-slate-400">Glossário de Direções</h3>
{GLOSSARY.map((g) => ( {GLOSSARY_GROUPS.map((group) => (
<div key={group.heading} className="space-y-2">
<p className="text-[11px] uppercase tracking-wide text-slate-500">{group.heading}</p>
{group.entries.map((g) => (
<div key={g.term}> <div key={g.term}>
<p className="text-sm font-medium text-white">{g.term}</p> <p className="text-sm font-medium text-white">{g.term}</p>
<p className="text-xs text-slate-400">{g.def}</p> <p className="text-xs text-slate-400">{g.def}</p>
</div> </div>
))} ))}
</div>
))}
</aside> </aside>
</div> </div>
); );