fix tegumentar

This commit is contained in:
Rodrigo Bertoldo de Sousa Martins committed 2026-09-10 18:57:05 -03:00
1 parent c422ccb05e
commit cd6d60cb20
2 files changed
+92 -54

No files matched your search

+5 -5
View File
@@ -533,9 +533,9 @@ const EXACT_PT = {
"anterior notch of auricle": "Incisura Anterior da Aurícula", "anterior notch of auricle": "Incisura Anterior da Aurícula",
"anterior region of ankle": "Região Anterior do Tornozelo", "anterior region of ankle": "Região Anterior do Tornozelo",
"anterior region of arm": "Região Anterior do Braço", "anterior region of arm": "Região Anterior do Braço",
"anterior region of elbow": "Região Anterior do Cotovelo", "anterior region of elbow": "Região Cubital Anterior",
"anterior region of forearm": "Região Anterior do Antebraço", "anterior region of forearm": "Região Anterior do Antebraço",
"anterior region of knee": "Região Anterior do Joelho", "anterior region of knee": "Região Genicular Anterior",
"anterior region of leg": "Região Anterior da Perna", "anterior region of leg": "Região Anterior da Perna",
"anterior region of neck": "Região Anterior do Pescoço", "anterior region of neck": "Região Anterior do Pescoço",
"anterior region of thigh": "Região Anterior da Coxa", "anterior region of thigh": "Região Anterior da Coxa",
@@ -646,9 +646,9 @@ const EXACT_PT = {
"posterior auricular groove": "Sulco Auricular Posterior", "posterior auricular groove": "Sulco Auricular Posterior",
"posterior region of ankle": "Região Posterior do Tornozelo", "posterior region of ankle": "Região Posterior do Tornozelo",
"posterior region of arm": "Região Posterior do Braço", "posterior region of arm": "Região Posterior do Braço",
"posterior region of elbow": "Região Posterior do Cotovelo", "posterior region of elbow": "Região Cubital Posterior",
"posterior region of forearm": "Região Posterior do Antebraço", "posterior region of forearm": "Região Posterior do Antebraço",
"posterior region of knee": "Região Posterior do Joelho", "posterior region of knee": "Região Genicular Posterior",
"posterior region of leg": "Região Posterior da Perna", "posterior region of leg": "Região Posterior da Perna",
"posterior region of neck": "Região Posterior do Pescoço (Nuca)", "posterior region of neck": "Região Posterior do Pescoço (Nuca)",
"posterior region of thigh": "Região Posterior da Coxa", "posterior region of thigh": "Região Posterior da Coxa",
@@ -685,7 +685,7 @@ const EXACT_PT = {
"triangle of auscultation": "Trígono de Ausculta", "triangle of auscultation": "Trígono de Ausculta",
"triangular fossa": "Fossa Triangular (Orelha)", "triangular fossa": "Fossa Triangular (Orelha)",
"tubercle of upper lip": "Tubérculo do Lábio Superior", "tubercle of upper lip": "Tubérculo do Lábio Superior",
"umbilical region": "Região Umbilical", "umbilical region": "Região Umbilical/Mesogástrica",
"umbilicus": "Umbigo", "umbilicus": "Umbigo",
"upper eyelid": "Pálpebra Superior", "upper eyelid": "Pálpebra Superior",
"upper lip": "Lábio Superior", "upper lip": "Lábio Superior",
+87 -49
View File
@@ -1,15 +1,28 @@
// Gera manifest-tegumentar.json: o Z-Anatomy-Sample não inclui camadas de // Gera manifest-tegumentar.json: o Z-Anatomy-Sample não inclui camadas de
// pele (epiderme/derme/hipoderme) nem seus anexos (folículo piloso, glândulas // pele (epiderme/derme/hipoderme) nem seus anexos (folículo piloso, glândulas
// etc.) — são estruturas microscópicas, nenhum dataset de corpo inteiro as // etc.) — são estruturas microscópicas, nenhum dataset de corpo inteiro as
// modela como malha. Por isso o sistema tegumentar usa um "bloco" esquemático // modela como malha. Por isso o sistema tegumentar (só ele — os demais
// (corte transversal de pele, como o diagrama clássico do Netter/Sobotta), // sistemas continuam vindo de malhas reais via scripts/extract-manifest.mjs,
// construído com geometria paramétrica simples (caixas/esferas/cilindros — // sem nenhuma mudança) usa um "bloco" esquemático construído com geometria
// ver scripts/geometry.mjs e scripts/build-seed-models.mjs). // paramétrica simples (ver scripts/geometry.mjs e scripts/build-seed-models.mjs,
// também exclusivos do tegumentar — só o script "build:tegumentar" os chama).
// //
// Como as outras estruturas do sistema tegumentar ficam ocultas quando só // MODELO EM DEGRAUS ("staircase cutaway"), como os blocos didáticos de pele
// esse sistema está visível, ativar "Tegumentar" sozinho na barra de camadas // usados em aula: cada camada mais profunda tem uma extensão maior no eixo Y
// já isola e centraliza a câmera neste bloco (ver computeVisibleBoundingBox // do que a camada acima dela, então a camada de cima NÃO cobre a de baixo
// em Scene.tsx) — funciona como um "zoom didático" na pele. // inteira — sobra um "degrau" onde a superfície da camada mais profunda fica
// exposta e visível de cima, em vez de tudo empilhado e escondido atrás da
// camada mais externa (o problema do modelo anterior, que empilhava 3 caixas
// finas exatamente uma sobre a outra).
// epiderme: ████ (degrau 1 — só ela)
// derme: ████ ████ (degraus 1+2 — expõe o degrau 2)
// hipoderme: ████ ████ ████ (degraus 1+2+3 — expõe o degrau 3)
// A parede vertical no degrau 1 (voltada para -Y) mostra as 3 camadas
// empilhadas de uma vez, como um corte transversal — é ali na frente que
// ficam os componentes (pelo, glândulas, vasos, corpúsculos), flutuando bem
// próximos da parede (fora do bloco opaco, pra nunca ficarem escondidos
// dentro dele) e alinhados em X e Z com a camada a que pertencem. Gire o
// modelo com o mouse pra ver o bloco de todos os ângulos.
import { writeFileSync } from "node:fs"; import { writeFileSync } from "node:fs";
import { fileURLToPath } from "node:url"; import { fileURLToPath } from "node:url";
import path from "node:path"; import path from "node:path";
@@ -36,24 +49,40 @@ function add(system, slug, namePt, nameEn, region, shape, position, opts = {}) {
}); });
} }
const TX = ["Sistema Tegumentar", "Corte Transversal da Pele"]; const TX = ["Sistema Tegumentar", "Corte Transversal da Pele (em Degraus)"];
// Centro do "bloco" de pele (coordenadas do mundo, mesma escala do corpo // Centro/âncora do bloco (coordenadas do mundo, mesma escala do corpo
// Z-Anatomy — colado na face do antebraço). x/y = plano da superfície da // Z-Anatomy — colado na face do antebraço, como antes).
// pele; z = profundidade (z maior = mais externo/superficial).
const CX = 0.24; const CX = 0.24;
const CY = 0.85; const CY = 0.85;
const Z_SURFACE = 0.0375; // topo da epiderme = superfície da pele
// Cilindros/caixas nascem com o eixo longo em Y; ROT_Z gira esse eixo para const BLOCK_W = 0.14; // extensão em X (largura do bloco)
// Z (perpendicular à pele, "entrando" no corpo) — usado por pelo, folículo, const STEP = 0.05; // profundidade em Y de cada degrau
// ducto sudoríparo e a alça capilar, que atravessam as camadas na vertical. const Y_FRONT = CY - 1.5 * STEP; // borda frontal do bloco (degrau 1), onde fica a parede de corte
const ROT_Z = [Math.PI / 2, 0, 0];
// ---- As 3 camadas da pele ---- // Espessura (eixo Z) de cada camada e a profundidade onde cada uma começa/
// termina — definidas uma vez aqui pra tudo (camadas E componentes) usar os
// mesmos números e não desalinhar.
const Z_TOP = 0.038; // superfície da epiderme
const D_EPI = 0.005;
const D_DERME = 0.012;
const D_HIPO = 0.016;
const Z_EPI_BOTTOM = Z_TOP - D_EPI; // 0.033 = limite epiderme/derme
const Z_DERME_BOTTOM = Z_EPI_BOTTOM - D_DERME; // 0.021 = limite derme/hipoderme
const Z_HIPO_BOTTOM = Z_DERME_BOTTOM - D_HIPO; // 0.005 = base do bloco
// Os componentes (pelo, glândulas, vasos, corpúsculos...) ficam flutuando
// bem à frente da parede de corte (fora do volume opaco do bloco, pra nunca
// serem encobertos por ele) — cada "coluna" X é um componente diferente,
// como um desenho de corte histológico visto de frente.
const FRONT_Y = Y_FRONT - 0.01;
const ROT_Z = [Math.PI / 2, 0, 0]; // deixa cilindros na vertical (eixo nasce em Y, isso gira pra Z)
// ---- As 3 camadas da pele, em degraus ----
add( add(
"tegumentar", "epiderme", "Epiderme", "Epidermis", [...TX], "tegumentar", "epiderme", "Epiderme", "Epidermis", [...TX],
{ type: "box", w: 0.09, h: 0.2, d: 0.005 }, [CX, CY, 0.035], { type: "box", w: BLOCK_W, h: STEP, d: D_EPI },
[CX, Y_FRONT + STEP / 2, Z_TOP - D_EPI / 2],
{ {
color: "#e0a96d", color: "#e0a96d",
description: description:
@@ -62,30 +91,37 @@ add(
); );
add( add(
"tegumentar", "derme", "Derme", "Dermis", [...TX], "tegumentar", "derme", "Derme", "Dermis", [...TX],
{ type: "box", w: 0.09, h: 0.2, d: 0.01 }, [CX, CY, 0.028], { type: "box", w: BLOCK_W, h: 2 * STEP, d: D_DERME },
[CX, Y_FRONT + STEP, Z_EPI_BOTTOM - D_DERME / 2],
{ {
color: "#c97b4a", color: "#c97b4a",
description: description:
"Camada de tecido conjuntivo rica em colágeno e elastina, vasos sanguíneos, terminações nervosas e os anexos cutâneos (folículos pilosos, glândulas); sustenta a epiderme e dá à pele resistência e elasticidade.", "Camada de tecido conjuntivo rica em colágeno e elastina, vasos sanguíneos, terminações nervosas e os anexos cutâneos (folículos pilosos, glândulas); sustenta a epiderme e dá à pele resistência e elasticidade. Repare no degrau exposto: é a derme aparecendo onde a epiderme já não cobre mais.",
}, },
); );
add( add(
"tegumentar", "hipoderme", "Hipoderme (Tecido Subcutâneo)", "Hypodermis (Subcutaneous Tissue)", [...TX], "tegumentar", "hipoderme", "Hipoderme (Tecido Subcutâneo)", "Hypodermis (Subcutaneous Tissue)", [...TX],
{ type: "box", w: 0.09, h: 0.2, d: 0.015 }, [CX, CY, 0.018], { type: "box", w: BLOCK_W, h: 3 * STEP, d: D_HIPO },
[CX, CY, Z_DERME_BOTTOM - D_HIPO / 2],
{ {
color: "#f2d4a3", color: "#f2d4a3",
description: description:
"Camada mais profunda, rica em tecido adiposo; isola termicamente, absorve impactos e serve de reserva de energia — não é tecnicamente parte da pele, mas a conecta aos músculos e ossos subjacentes.", "Camada mais profunda, rica em tecido adiposo; isola termicamente, absorve impactos e serve de reserva de energia — não é tecnicamente parte da pele, mas a conecta aos músculos e ossos subjacentes. É o degrau mais largo, exposto onde nem epiderme nem derme mais chegam.",
}, },
); );
// ---- Complexo pilossebáceo (pelo + folículo + músculo eretor + glândula sebácea) ---- // ---- 6 "colunas" de componentes, cada uma numa posição X própria, todas
const HX = CX - 0.015, HY = CY + 0.03; // flutuando no mesmo plano frontal (FRONT_Y) — a altura (Z) de cada peça
// já indica em qual camada ela vive. ----
const COL = (i) => CX - 0.06 + i * 0.024; // 6 colunas igualmente espaçadas
// ---- Coluna 1: complexo pilossebáceo (pelo + folículo + músculo eretor + glândula sebácea) ----
const HX = COL(0);
const HAIR_TILT = [Math.PI / 2 + 0.3, 0.2, 0]; const HAIR_TILT = [Math.PI / 2 + 0.3, 0.2, 0];
add( add(
"tegumentar", "pelo", "Pelo (Haste Capilar)", "Hair Shaft", [...TX, "Complexo Pilossebáceo"], "tegumentar", "pelo", "Pelo (Haste Capilar)", "Hair Shaft", [...TX, "Complexo Pilossebáceo"],
{ type: "cylinder", rt: 0.0006, rb: 0.001, h: 0.02 }, [HX, HY, Z_SURFACE + 0.01], { type: "cylinder", rt: 0.0006, rb: 0.001, h: 0.02 }, [HX, FRONT_Y, Z_TOP + 0.01],
{ {
color: "#4a3527", color: "#4a3527",
rotation: HAIR_TILT, rotation: HAIR_TILT,
@@ -95,7 +131,7 @@ add(
); );
add( add(
"tegumentar", "foliculo-piloso", "Folículo Piloso", "Hair Follicle", [...TX, "Complexo Pilossebáceo"], "tegumentar", "foliculo-piloso", "Folículo Piloso", "Hair Follicle", [...TX, "Complexo Pilossebáceo"],
{ type: "cylinder", rt: 0.0022, rb: 0.0022, h: 0.03 }, [HX, HY, 0.0225], { type: "cylinder", rt: 0.0022, rb: 0.0022, h: 0.03 }, [HX, FRONT_Y, 0.023],
{ {
color: "#8a6a52", color: "#8a6a52",
rotation: HAIR_TILT, rotation: HAIR_TILT,
@@ -105,7 +141,7 @@ add(
); );
add( add(
"tegumentar", "bulbo-piloso", "Bulbo Piloso", "Hair Bulb", [...TX, "Complexo Pilossebáceo"], "tegumentar", "bulbo-piloso", "Bulbo Piloso", "Hair Bulb", [...TX, "Complexo Pilossebáceo"],
{ type: "sphere", r: 0.003 }, [HX - 0.006, HY + 0.012, 0.008], { type: "sphere", r: 0.003 }, [HX - 0.004, FRONT_Y, 0.008],
{ {
color: "#6b4c38", color: "#6b4c38",
description: description:
@@ -114,17 +150,17 @@ add(
); );
add( add(
"tegumentar", "musculo-eretor-do-pelo", "Músculo Eretor do Pelo", "Arrector Pili Muscle", [...TX, "Complexo Pilossebáceo"], "tegumentar", "musculo-eretor-do-pelo", "Músculo Eretor do Pelo", "Arrector Pili Muscle", [...TX, "Complexo Pilossebáceo"],
{ type: "box", w: 0.0012, h: 0.014, d: 0.003 }, [HX + 0.004, HY - 0.006, 0.0295], { type: "box", w: 0.0012, h: 0.014, d: 0.003 }, [HX + 0.004, FRONT_Y, 0.0285],
{ {
color: "#b5433a", color: "#b5433a",
rotation: [1.05, 0, 0], rotation: [1.05, 0, 0],
description: description:
"Pequeno músculo liso ligado obliquamente ao folículo; ao se contrair (frio, medo), eleva o pelo e comprime a glândula sebácea — é o responsável pela 'pele arrepiada' (piloereção).", "Pequeno músculo liso ligado obliquamente ao folículo; ao se contrair (frio, medo), eleva o pelo e comprime a glândula sebácea — é o responsável pela pele arrepiada (piloereção).",
}, },
); );
add( add(
"tegumentar", "glandula-sebacea", "Glândula Sebácea", "Sebaceous Gland", [...TX, "Complexo Pilossebáceo"], "tegumentar", "glandula-sebacea", "Glândula Sebácea", "Sebaceous Gland", [...TX, "Complexo Pilossebáceo"],
{ type: "sphere", r: 0.004 }, [HX + 0.007, HY - 0.01, 0.031], { type: "sphere", r: 0.004 }, [HX + 0.007, FRONT_Y, 0.031],
{ {
color: "#f2c14e", color: "#f2c14e",
description: description:
@@ -132,11 +168,11 @@ add(
}, },
); );
// ---- Glândula sudorípara (écrina) + ducto + poro ---- // ---- Coluna 2: glândula sudorípara (écrina) + ducto + poro ----
const SX = CX + 0.02, SY = CY - 0.02; const SX = COL(1);
add( add(
"tegumentar", "glandula-sudoripara", "Glândula Sudorípara (Écrina)", "Eccrine Sweat Gland", [...TX, "Glândula Sudorípara"], "tegumentar", "glandula-sudoripara", "Glândula Sudorípara (Écrina)", "Eccrine Sweat Gland", [...TX, "Glândula Sudorípara"],
{ type: "sphere", r: 0.005 }, [SX, SY, 0.014], { type: "sphere", r: 0.005 }, [SX, FRONT_Y, 0.012],
{ {
color: "#4f7cff", color: "#4f7cff",
description: description:
@@ -145,7 +181,7 @@ add(
); );
add( add(
"tegumentar", "ducto-sudoriparo", "Ducto Sudoríparo", "Sweat Duct", [...TX, "Glândula Sudorípara"], "tegumentar", "ducto-sudoriparo", "Ducto Sudoríparo", "Sweat Duct", [...TX, "Glândula Sudorípara"],
{ type: "cylinder", rt: 0.0012, rb: 0.0012, h: 0.0235 }, [SX, SY, 0.0258], { type: "cylinder", rt: 0.0012, rb: 0.0012, h: 0.026 }, [SX, FRONT_Y, 0.025],
{ {
color: "#7ba6ff", color: "#7ba6ff",
rotation: ROT_Z, rotation: ROT_Z,
@@ -155,18 +191,18 @@ add(
); );
add( add(
"tegumentar", "poro-sudoriparo", "Poro Sudoríparo", "Sweat Pore", [...TX, "Glândula Sudorípara"], "tegumentar", "poro-sudoriparo", "Poro Sudoríparo", "Sweat Pore", [...TX, "Glândula Sudorípara"],
{ type: "sphere", r: 0.0012 }, [SX, SY, Z_SURFACE + 0.0005], { type: "sphere", r: 0.0012 }, [SX, FRONT_Y, Z_TOP + 0.0005],
{ {
color: "#a9c6ff", color: "#a9c6ff",
description: "Abertura do ducto sudoríparo na superfície da epiderme, por onde o suor é liberado.", description: "Abertura do ducto sudoríparo na superfície da epiderme, por onde o suor é liberado.",
}, },
); );
// ---- Plexo vascular dérmico ---- // ---- Coluna 3: plexo vascular dérmico ----
const VX = CX - 0.03, VY = CY - 0.05; const VX = COL(2);
add( add(
"tegumentar", "arteriola-dermica", "Arteríola Dérmica", "Dermal Arteriole", [...TX, "Plexo Vascular Dérmico"], "tegumentar", "arteriola-dermica", "Arteríola Dérmica", "Dermal Arteriole", [...TX, "Plexo Vascular Dérmico"],
{ type: "cylinder", rt: 0.0012, rb: 0.0012, h: 0.014 }, [VX - 0.003, VY, 0.026], { type: "cylinder", rt: 0.0012, rb: 0.0012, h: 0.01 }, [VX - 0.004, FRONT_Y, 0.026],
{ {
color: "#c1121f", color: "#c1121f",
rotation: ROT_Z, rotation: ROT_Z,
@@ -175,7 +211,7 @@ add(
); );
add( add(
"tegumentar", "venula-dermica", "Vênula Dérmica", "Dermal Venule", [...TX, "Plexo Vascular Dérmico"], "tegumentar", "venula-dermica", "Vênula Dérmica", "Dermal Venule", [...TX, "Plexo Vascular Dérmico"],
{ type: "cylinder", rt: 0.0012, rb: 0.0012, h: 0.014 }, [VX + 0.003, VY, 0.026], { type: "cylinder", rt: 0.0012, rb: 0.0012, h: 0.01 }, [VX + 0.004, FRONT_Y, 0.026],
{ {
color: "#3457d5", color: "#3457d5",
rotation: ROT_Z, rotation: ROT_Z,
@@ -184,7 +220,7 @@ add(
); );
add( add(
"tegumentar", "alca-capilar-dermica", "Alça Capilar Dérmica", "Dermal Capillary Loop", [...TX, "Plexo Vascular Dérmico"], "tegumentar", "alca-capilar-dermica", "Alça Capilar Dérmica", "Dermal Capillary Loop", [...TX, "Plexo Vascular Dérmico"],
{ type: "cylinder", rt: 0.0006, rb: 0.0006, h: 0.006 }, [VX, VY, 0.032], { type: "cylinder", rt: 0.0006, rb: 0.0006, h: 0.006 }, [VX, FRONT_Y, 0.033],
{ {
color: "#e0464f", color: "#e0464f",
rotation: ROT_Z, rotation: ROT_Z,
@@ -192,19 +228,21 @@ add(
}, },
); );
// ---- Corpúsculos sensoriais ---- // ---- Coluna 4: corpúsculo de Meissner (toque leve) ----
add( add(
"tegumentar", "corpusculo-de-meissner", "Corpúsculo de Meissner", "Meissner's Corpuscle", [...TX, "Receptores Sensoriais"], "tegumentar", "corpusculo-de-meissner", "Corpúsculo de Meissner", "Meissner's Corpuscle", [...TX, "Receptores Sensoriais"],
{ type: "sphere", r: 0.0022 }, [CX + 0.03, CY + 0.06, 0.0335], { type: "sphere", r: 0.0022 }, [COL(3), FRONT_Y, 0.033],
{ {
color: "#34d399", color: "#34d399",
description: description:
"Receptor sensorial encapsulado logo abaixo da epiderme; detecta toque leve e vibrações de baixa frequência — muito numeroso na ponta dos dedos e nos lábios.", "Receptor sensorial encapsulado logo abaixo da epiderme; detecta toque leve e vibrações de baixa frequência — muito numeroso na ponta dos dedos e nos lábios.",
}, },
); );
// ---- Coluna 5: corpúsculo de Pacini (pressão profunda) ----
add( add(
"tegumentar", "corpusculo-de-pacini", "Corpúsculo de Pacini", "Pacinian Corpuscle", [...TX, "Receptores Sensoriais"], "tegumentar", "corpusculo-de-pacini", "Corpúsculo de Pacini", "Pacinian Corpuscle", [...TX, "Receptores Sensoriais"],
{ type: "sphere", r: 0.006 }, [CX + 0.03, CY - 0.06, 0.012], { type: "sphere", r: 0.006 }, [COL(4), FRONT_Y, 0.012],
{ {
color: "#22d3ee", color: "#22d3ee",
description: description:
@@ -212,16 +250,16 @@ add(
}, },
); );
// ---- Tecido adiposo da hipoderme ---- // ---- Coluna 6: lóbulos de tecido adiposo da hipoderme ----
const FX = CX - 0.02, FY = CY - 0.075; const FX = COL(5);
const FAT_OFFSETS = [ const FAT_OFFSETS = [
[0, 0], [0.008, 0.004], [-0.006, 0.006], [0.003, -0.007], [0, 0.013], [0.007, 0.017], [-0.006, 0.010], [0.003, 0.019],
]; ];
FAT_OFFSETS.forEach(([dx, dy], i) => { FAT_OFFSETS.forEach(([dx, dz], i) => {
add( add(
"tegumentar", `adipocito-${i + 1}`, `Lóbulo de Tecido Adiposo ${i + 1}`, `Adipose Tissue Lobule ${i + 1}`, "tegumentar", `adipocito-${i + 1}`, `Lóbulo de Tecido Adiposo ${i + 1}`, `Adipose Tissue Lobule ${i + 1}`,
[...TX, "Tecido Adiposo"], [...TX, "Tecido Adiposo"],
{ type: "sphere", r: 0.006 }, [FX + dx, FY + dy, 0.015], { type: "sphere", r: 0.006 }, [FX + dx, FRONT_Y, dz],
{ {
color: "#f7e08c", color: "#f7e08c",
description: description: