planos anatomicos
Signed-off-by: Rodrigo Bertoldo de Sousa Martins <rodrigo@MacBook-Air-de-Rodrigo.local>
This commit is contained in:
1 parent
06ace7505c
commit
19bc92356f
1 file changed
+141
-30
@@ -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] },
|
||||
];
|
||||
|
||||
const AXES: { label: string; from: [number, number, number]; to: [number, number, number]; color: string }[] = [
|
||||
{ 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: "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: "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" },
|
||||
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: "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: "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: "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 }[] = [
|
||||
{ term: "Anterior / Posterior", def: "Em direção à frente (ventral) ou para trás (dorsal) do corpo." },
|
||||
{ term: "Superior / Inferior", def: "Em direção à cabeça (cranial) ou aos pés (caudal)." },
|
||||
{ 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." },
|
||||
{ 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: "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." },
|
||||
interface GlossaryEntry {
|
||||
term: string;
|
||||
def: string;
|
||||
}
|
||||
|
||||
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: "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 Transversal (Axial)", def: "Divide o corpo em partes superior e inferior." },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default function PlanesPage() {
|
||||
@@ -45,7 +132,12 @@ export default function PlanesPage() {
|
||||
coronal: 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 [rightOpen, setRightOpen] = useState(false);
|
||||
|
||||
@@ -78,10 +170,23 @@ export default function PlanesPage() {
|
||||
</label>
|
||||
))}
|
||||
|
||||
<label className="flex items-center gap-2 text-sm cursor-pointer pt-2 border-t border-white/10 mt-3">
|
||||
<input type="checkbox" checked={showAxes} onChange={() => setShowAxes((v) => !v)} className="accent-accent" />
|
||||
Eixos e termos de direção
|
||||
</label>
|
||||
<h3 className="text-xs uppercase tracking-wide text-slate-400 pt-3 border-t border-white/10 mt-3">
|
||||
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>
|
||||
))}
|
||||
</aside>
|
||||
|
||||
{(leftOpen || rightOpen) && (
|
||||
@@ -121,9 +226,9 @@ export default function PlanesPage() {
|
||||
</mesh>
|
||||
))}
|
||||
|
||||
{showAxes &&
|
||||
AXES.map((a) => (
|
||||
<group key={a.label}>
|
||||
{AXIS_GROUPS.filter((g) => visibleAxisGroups[g.key]).flatMap((g) =>
|
||||
g.axes.map((a) => (
|
||||
<group key={`${g.key}-${a.label}`}>
|
||||
<Line points={[a.from, a.to]} color={a.color} lineWidth={2} />
|
||||
<Html position={a.to} center distanceFactor={4}>
|
||||
<div
|
||||
@@ -134,7 +239,8 @@ export default function PlanesPage() {
|
||||
</div>
|
||||
</Html>
|
||||
</group>
|
||||
))}
|
||||
)),
|
||||
)}
|
||||
|
||||
<CameraControls makeDefault />
|
||||
</Canvas>
|
||||
@@ -142,7 +248,7 @@ export default function PlanesPage() {
|
||||
|
||||
<aside
|
||||
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
|
||||
${rightOpen ? "translate-x-0" : "translate-x-full"}`}
|
||||
>
|
||||
@@ -154,10 +260,15 @@ export default function PlanesPage() {
|
||||
✕ Fechar
|
||||
</button>
|
||||
<h3 className="text-xs uppercase tracking-wide text-slate-400">Glossário de Direções</h3>
|
||||
{GLOSSARY.map((g) => (
|
||||
<div key={g.term}>
|
||||
<p className="text-sm font-medium text-white">{g.term}</p>
|
||||
<p className="text-xs text-slate-400">{g.def}</p>
|
||||
{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}>
|
||||
<p className="text-sm font-medium text-white">{g.term}</p>
|
||||
<p className="text-xs text-slate-400">{g.def}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</aside>
|
||||
|
||||
Reference in new issue
Block a user