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
+128
-17
@@ -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>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in new issue
Block a user