fix6
This commit is contained in:
1 parent
0bc9708829
commit
d62f4a3227
2 files changed
+236
-4
No files matched your search
@@ -14,6 +14,7 @@ import { fileURLToPath } from "node:url";
|
|||||||
import { SOURCES, SOURCE_TARGETS, RESPIRATORY_KEYWORDS } from "./sources.mjs";
|
import { SOURCES, SOURCE_TARGETS, RESPIRATORY_KEYWORDS } from "./sources.mjs";
|
||||||
import { translateToPt } from "./translate-pt.mjs";
|
import { translateToPt } from "./translate-pt.mjs";
|
||||||
import { SYSTEMS } from "../seed/systems.mjs";
|
import { SYSTEMS } from "../seed/systems.mjs";
|
||||||
|
import { SKELETAL_BONES } from "./skeletal-whitelist.mjs";
|
||||||
|
|
||||||
await MeshoptSimplifier.ready;
|
await MeshoptSimplifier.ready;
|
||||||
|
|
||||||
@@ -40,6 +41,48 @@ function slugify(s) {
|
|||||||
.replace(/^-+|-+$/g, "");
|
.replace(/^-+|-+$/g, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// O arquivo esquelético real do Z-Anatomy mistura ossos de verdade com
|
||||||
|
// centenas de "acidentes ósseos" (pontos de referência NO osso, ex:
|
||||||
|
// "Deltoid tuberosity" — não são ossos) e marcadores de origem/inserção
|
||||||
|
// muscular (ex: "Pectoralis major muscle.ol" — pertencem ao músculo).
|
||||||
|
// Por isso usamos uma lista de INCLUSÃO com os 206 ossos reais em vez de
|
||||||
|
// aceitar tudo: só o que bate exatamente vira uma estrutura esquelética.
|
||||||
|
const SKELETAL_ALIASES = { atlas: "Atlas (C1)", axis: "Axis (C2)" };
|
||||||
|
const skeletalLookup = new Map(
|
||||||
|
Object.entries(SKELETAL_BONES).map(([key, info]) => [
|
||||||
|
key.toLowerCase(),
|
||||||
|
{ canonicalKey: key, ...info },
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
|
||||||
|
function stripSideSuffix(rawName) {
|
||||||
|
const m = rawName.match(/^(.*)\.([lrij])$/i);
|
||||||
|
if (m) return { base: m[1].trim(), suffix: m[2].toLowerCase() };
|
||||||
|
return { base: rawName.trim(), suffix: null };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retorna null se o nome bruto não corresponder a nenhum dos 206 ossos —
|
||||||
|
// nesse caso a malha é ignorada (não vira estrutura, mas continua no
|
||||||
|
// arquivo .glb; como não há "structure" apontando pra ela, o frontend já
|
||||||
|
// a mantém oculta automaticamente).
|
||||||
|
function resolveSkeletalBone(rawName) {
|
||||||
|
const { base, suffix } = stripSideSuffix(rawName);
|
||||||
|
const normBase = base.toLowerCase();
|
||||||
|
const aliasTarget = SKELETAL_ALIASES[normBase];
|
||||||
|
const lookupKey = (aliasTarget ?? base).toLowerCase();
|
||||||
|
const entry = skeletalLookup.get(lookupKey);
|
||||||
|
if (!entry) return null;
|
||||||
|
|
||||||
|
if (entry.paired) {
|
||||||
|
// Ignora variantes ".i"/".j"/sem sufixo para ossos pareados — o
|
||||||
|
// Z-Anatomy parece manter cópias duplicadas (visão isolada vs.
|
||||||
|
// esqueleto montado); ".l"/".r" é a marcação inequívoca de lado.
|
||||||
|
if (suffix !== "l" && suffix !== "r") return null;
|
||||||
|
return { canonicalKey: entry.canonicalKey, pt: entry.pt, side: suffix };
|
||||||
|
}
|
||||||
|
return { canonicalKey: entry.canonicalKey, pt: entry.pt, side: "single" };
|
||||||
|
}
|
||||||
|
|
||||||
function classifySystem(key, rawName) {
|
function classifySystem(key, rawName) {
|
||||||
const target = SOURCE_TARGETS[key];
|
const target = SOURCE_TARGETS[key];
|
||||||
if (target.system) return target.system;
|
if (target.system) return target.system;
|
||||||
@@ -81,6 +124,7 @@ for (const { fbx, key } of SOURCES) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const nameCounts = new Map(); // dedupe de nomes brutos duplicados no MESMO arquivo
|
const nameCounts = new Map(); // dedupe de nomes brutos duplicados no MESMO arquivo
|
||||||
|
const includedBones = new Set(); // dedupe de osso+lado no sistema esquelético
|
||||||
let countThisFile = 0;
|
let countThisFile = 0;
|
||||||
|
|
||||||
function visit(node) {
|
function visit(node) {
|
||||||
@@ -92,12 +136,32 @@ for (const { fbx, key } of SOURCES) {
|
|||||||
const uniqueMeshName = n === 1 ? rawName : `${rawName} (${n})`;
|
const uniqueMeshName = n === 1 ? rawName : `${rawName} (${n})`;
|
||||||
node.setName(uniqueMeshName);
|
node.setName(uniqueMeshName);
|
||||||
|
|
||||||
const systemSlug = classifySystem(key, rawName);
|
let systemSlug, namePt, nameEn;
|
||||||
|
|
||||||
|
if (key === "skeletal") {
|
||||||
|
const resolved = resolveSkeletalBone(rawName);
|
||||||
|
const dedupeKey = resolved ? `${resolved.canonicalKey}::${resolved.side}` : null;
|
||||||
|
if (!resolved || includedBones.has(dedupeKey)) {
|
||||||
|
for (const child of node.listChildren()) visit(child);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
includedBones.add(dedupeKey);
|
||||||
|
systemSlug = "esqueletico";
|
||||||
|
const sideLabel = resolved.side === "l" ? " Esquerdo" : resolved.side === "r" ? " Direito" : "";
|
||||||
|
const sideWord = resolved.side === "l" ? "Left " : resolved.side === "r" ? "Right " : "";
|
||||||
|
namePt = `${resolved.pt}${sideLabel}`;
|
||||||
|
nameEn = `${sideWord}${resolved.canonicalKey}`;
|
||||||
|
} else {
|
||||||
|
systemSlug = classifySystem(key, rawName);
|
||||||
|
namePt = translateToPt(rawName) + (n > 1 ? ` (${n})` : "");
|
||||||
|
nameEn = rawName + (n > 1 ? ` (${n})` : "");
|
||||||
|
}
|
||||||
|
|
||||||
const material = materialFor(systemSlug);
|
const material = materialFor(systemSlug);
|
||||||
for (const prim of mesh.listPrimitives()) prim.setMaterial(material);
|
for (const prim of mesh.listPrimitives()) prim.setMaterial(material);
|
||||||
|
|
||||||
const sys = systemBySlug.get(systemSlug);
|
const sys = systemBySlug.get(systemSlug);
|
||||||
const slugPart = slugify(uniqueMeshName) || `sem-nome-${totalStructures}`;
|
const slugPart = slugify(key === "skeletal" ? namePt : uniqueMeshName) || `sem-nome-${totalStructures}`;
|
||||||
const slug = `${systemSlug}-${slugPart}`;
|
const slug = `${systemSlug}-${slugPart}`;
|
||||||
|
|
||||||
// Gravamos o slug como "extras" do nó (→ vira object.userData no
|
// Gravamos o slug como "extras" do nó (→ vira object.userData no
|
||||||
@@ -109,8 +173,8 @@ for (const { fbx, key } of SOURCES) {
|
|||||||
manifest.push({
|
manifest.push({
|
||||||
system: systemSlug,
|
system: systemSlug,
|
||||||
slug,
|
slug,
|
||||||
namePt: translateToPt(rawName) + (n > 1 ? ` (${n})` : ""),
|
namePt,
|
||||||
nameEn: rawName + (n > 1 ? ` (${n})` : ""),
|
nameEn,
|
||||||
synonyms: [],
|
synonyms: [],
|
||||||
description: "",
|
description: "",
|
||||||
regionPath: [sys?.namePt ?? systemSlug],
|
regionPath: [sys?.namePt ?? systemSlug],
|
||||||
@@ -130,6 +194,21 @@ for (const { fbx, key } of SOURCES) {
|
|||||||
console.warn(` ⚠ nenhuma malha nomeada encontrada em ${fbx} — confira o log do assimp/conversão.`);
|
console.warn(` ⚠ nenhuma malha nomeada encontrada em ${fbx} — confira o log do assimp/conversão.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (key === "skeletal") {
|
||||||
|
const missing = [];
|
||||||
|
for (const [boneKey, info] of Object.entries(SKELETAL_BONES)) {
|
||||||
|
const sides = info.paired ? ["l", "r"] : ["single"];
|
||||||
|
for (const side of sides) {
|
||||||
|
if (!includedBones.has(`${boneKey}::${side}`)) missing.push(`${boneKey} (${side})`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(` → ${includedBones.size}/206 ossos da lista de referência encontrados.`);
|
||||||
|
if (missing.length > 0) {
|
||||||
|
console.warn(` ⚠ ${missing.length} ossos da lista NÃO encontrados no arquivo:`);
|
||||||
|
for (const m of missing) console.warn(` - ${m}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Malhas do Z-Anatomy vêm pensadas para um app desktop (Unity), com
|
// Malhas do Z-Anatomy vêm pensadas para um app desktop (Unity), com
|
||||||
// densidade de polígonos bem maior do que um visualizador web aguenta
|
// densidade de polígonos bem maior do que um visualizador web aguenta
|
||||||
// com dezenas de estruturas na tela ao mesmo tempo. MAS: muitas das
|
// com dezenas de estruturas na tela ao mesmo tempo. MAS: muitas das
|
||||||
|
|||||||
@@ -0,0 +1,153 @@
|
|||||||
|
// Lista de referência dos 206 ossos do corpo humano adulto, usada como
|
||||||
|
// FILTRO DE INCLUSÃO para o sistema esquelético: o arquivo real do
|
||||||
|
// Z-Anatomy mistura ossos de verdade com centenas de "acidentes ósseos"
|
||||||
|
// (ex: "Deltoid tuberosity", "Greater trochanter" — pontos de referência
|
||||||
|
// NO osso, não ossos em si) e marcadores de origem/inserção muscular
|
||||||
|
// (ex: "Pectoralis major muscle.ol") — só o que bate exatamente com um
|
||||||
|
// nome desta lista vira uma "estrutura" clicável no sistema esquelético;
|
||||||
|
// o resto é ignorado (mas a malha continua no arquivo, só não aparece).
|
||||||
|
//
|
||||||
|
// Chave = nome bruto (em inglês) como aparece no Z-Anatomy, JÁ SEM o
|
||||||
|
// sufixo de lateralidade/variante (.l/.r/.i/.j) — ver stripSuffix() em
|
||||||
|
// classify-skeletal.mjs. `paired: true` = existe versão esquerda/direita.
|
||||||
|
export const SKELETAL_BONES = {
|
||||||
|
// ---- Crânio: neurocrânio (8) ----
|
||||||
|
"Frontal bone": { pt: "Osso Frontal", paired: false },
|
||||||
|
"Parietal bone": { pt: "Osso Parietal", paired: true },
|
||||||
|
"Temporal bone": { pt: "Osso Temporal", paired: true },
|
||||||
|
"Occipital bone": { pt: "Osso Occipital", paired: false },
|
||||||
|
"Sphenoid bone": { pt: "Osso Esfenoide", paired: false },
|
||||||
|
"Ethmoid bone": { pt: "Osso Etmoide", paired: false },
|
||||||
|
|
||||||
|
// ---- Crânio: esqueleto facial (14) ----
|
||||||
|
"Nasal bone": { pt: "Osso Nasal", paired: true },
|
||||||
|
"Maxilla": { pt: "Maxila", paired: true },
|
||||||
|
"Zygomatic bone": { pt: "Osso Zigomático", paired: true },
|
||||||
|
"Lacrimal bone": { pt: "Osso Lacrimal", paired: true },
|
||||||
|
"Palatine bone": { pt: "Osso Palatino", paired: true },
|
||||||
|
"Inferior nasal concha bone": { pt: "Concha Nasal Inferior", paired: true },
|
||||||
|
"Vomer": { pt: "Vômer", paired: false },
|
||||||
|
"Mandible": { pt: "Mandíbula", paired: false },
|
||||||
|
|
||||||
|
// ---- Ossículos da audição (6) ----
|
||||||
|
"Malleus": { pt: "Martelo", paired: true },
|
||||||
|
"Incus": { pt: "Bigorna", paired: true },
|
||||||
|
"Stapes": { pt: "Estribo", paired: true },
|
||||||
|
|
||||||
|
// ---- Osso hioide (1) ----
|
||||||
|
"Hyoid bone": { pt: "Osso Hioide", paired: false },
|
||||||
|
|
||||||
|
// ---- Coluna vertebral (26) ----
|
||||||
|
"Atlas (C1)": { pt: "Atlas (C1)", paired: false },
|
||||||
|
"Axis (C2)": { pt: "Áxis (C2)", paired: false },
|
||||||
|
"Vertebra C3": { pt: "Vértebra C3", paired: false },
|
||||||
|
"Vertebra C4": { pt: "Vértebra C4", paired: false },
|
||||||
|
"Vertebra C5": { pt: "Vértebra C5", paired: false },
|
||||||
|
"Vertebra C6": { pt: "Vértebra C6", paired: false },
|
||||||
|
"Vertebra C7": { pt: "Vértebra C7", paired: false },
|
||||||
|
"Vertebra T1": { pt: "Vértebra T1", paired: false },
|
||||||
|
"Vertebra T2": { pt: "Vértebra T2", paired: false },
|
||||||
|
"Vertebra T3": { pt: "Vértebra T3", paired: false },
|
||||||
|
"Vertebra T4": { pt: "Vértebra T4", paired: false },
|
||||||
|
"Vertebra T5": { pt: "Vértebra T5", paired: false },
|
||||||
|
"Vertebra T6": { pt: "Vértebra T6", paired: false },
|
||||||
|
"Vertebra T7": { pt: "Vértebra T7", paired: false },
|
||||||
|
"Vertebra T8": { pt: "Vértebra T8", paired: false },
|
||||||
|
"Vertebra T9": { pt: "Vértebra T9", paired: false },
|
||||||
|
"Vertebra T10": { pt: "Vértebra T10", paired: false },
|
||||||
|
"Vertebra T11": { pt: "Vértebra T11", paired: false },
|
||||||
|
"Vertebra T12": { pt: "Vértebra T12", paired: false },
|
||||||
|
"Vertebra L1": { pt: "Vértebra L1", paired: false },
|
||||||
|
"Vertebra L2": { pt: "Vértebra L2", paired: false },
|
||||||
|
"Vertebra L3": { pt: "Vértebra L3", paired: false },
|
||||||
|
"Vertebra L4": { pt: "Vértebra L4", paired: false },
|
||||||
|
"Vertebra L5": { pt: "Vértebra L5", paired: false },
|
||||||
|
"Sacrum": { pt: "Sacro", paired: false },
|
||||||
|
"Coccyx": { pt: "Cóccix", paired: false },
|
||||||
|
|
||||||
|
// ---- Caixa torácica (25) ----
|
||||||
|
"Sternum": { pt: "Esterno", paired: false },
|
||||||
|
"First rib": { pt: "1ª Costela", paired: true },
|
||||||
|
"Second rib": { pt: "2ª Costela", paired: true },
|
||||||
|
"Third rib": { pt: "3ª Costela", paired: true },
|
||||||
|
"Fourth rib": { pt: "4ª Costela", paired: true },
|
||||||
|
"Fifth rib": { pt: "5ª Costela", paired: true },
|
||||||
|
"Sixth rib": { pt: "6ª Costela", paired: true },
|
||||||
|
"Seventh rib": { pt: "7ª Costela", paired: true },
|
||||||
|
"Eighth rib": { pt: "8ª Costela", paired: true },
|
||||||
|
"Ninth rib": { pt: "9ª Costela", paired: true },
|
||||||
|
"Tenth rib": { pt: "10ª Costela", paired: true },
|
||||||
|
"Eleventh rib": { pt: "11ª Costela", paired: true },
|
||||||
|
"Twelfth rib": { pt: "12ª Costela", paired: true },
|
||||||
|
|
||||||
|
// ---- Cíngulo do membro superior (4) ----
|
||||||
|
"Clavicle": { pt: "Clavícula", paired: true },
|
||||||
|
"Scapula": { pt: "Escápula", paired: true },
|
||||||
|
|
||||||
|
// ---- Membro superior livre (60) ----
|
||||||
|
"Humerus": { pt: "Úmero", paired: true },
|
||||||
|
"Radius": { pt: "Rádio", paired: true },
|
||||||
|
"Ulna": { pt: "Ulna", paired: true },
|
||||||
|
"Scaphoid bone": { pt: "Osso Escafoide", paired: true },
|
||||||
|
"Lunate bone": { pt: "Osso Semilunar", paired: true },
|
||||||
|
"Triquetrum bone": { pt: "Osso Piramidal", paired: true },
|
||||||
|
"Pisiform bone": { pt: "Osso Pisiforme", paired: true },
|
||||||
|
"Trapezium bone": { pt: "Osso Trapézio", paired: true },
|
||||||
|
"Trapezoid bone": { pt: "Osso Trapezoide", paired: true },
|
||||||
|
"Capitate bone": { pt: "Osso Capitato", paired: true },
|
||||||
|
"Hamate bone": { pt: "Osso Hamato", paired: true },
|
||||||
|
"First metacarpal bone": { pt: "1º Osso Metacarpal", paired: true },
|
||||||
|
"Second metacarpal bone": { pt: "2º Osso Metacarpal", paired: true },
|
||||||
|
"Third metacarpal bone": { pt: "3º Osso Metacarpal", paired: true },
|
||||||
|
"Fourth metacarpal bone": { pt: "4º Osso Metacarpal", paired: true },
|
||||||
|
"Fifth metacarpal bone": { pt: "5º Osso Metacarpal", paired: true },
|
||||||
|
"Proximal phalanx of first finger of hand": { pt: "Falange Proximal do Polegar", paired: true },
|
||||||
|
"Distal phalanx of first finger of hand": { pt: "Falange Distal do Polegar", paired: true },
|
||||||
|
"Proximal phalanx of second finger of hand": { pt: "Falange Proximal do 2º Dedo da Mão", paired: true },
|
||||||
|
"Middle phalanx of second finger of hand": { pt: "Falange Média do 2º Dedo da Mão", paired: true },
|
||||||
|
"Distal phalanx of second finger of hand": { pt: "Falange Distal do 2º Dedo da Mão", paired: true },
|
||||||
|
"Proximal phalanx of third finger of hand": { pt: "Falange Proximal do 3º Dedo da Mão", paired: true },
|
||||||
|
"Middle phalanx of third finger of hand": { pt: "Falange Média do 3º Dedo da Mão", paired: true },
|
||||||
|
"Distal phalanx of third finger of hand": { pt: "Falange Distal do 3º Dedo da Mão", paired: true },
|
||||||
|
"Proximal phalanx of fourth finger of hand": { pt: "Falange Proximal do 4º Dedo da Mão", paired: true },
|
||||||
|
"Middle phalanx of fourth finger of hand": { pt: "Falange Média do 4º Dedo da Mão", paired: true },
|
||||||
|
"Distal phalanx of fourth finger of hand": { pt: "Falange Distal do 4º Dedo da Mão", paired: true },
|
||||||
|
"Proximal phalanx of fifth finger of hand": { pt: "Falange Proximal do 5º Dedo da Mão", paired: true },
|
||||||
|
"Middle phalanx of fifth finger of hand": { pt: "Falange Média do 5º Dedo da Mão", paired: true },
|
||||||
|
"Distal phalanx of fifth finger of hand": { pt: "Falange Distal do 5º Dedo da Mão", paired: true },
|
||||||
|
|
||||||
|
// ---- Cíngulo do membro inferior (2) ----
|
||||||
|
"Hip bone": { pt: "Osso do Quadril", paired: true },
|
||||||
|
|
||||||
|
// ---- Membro inferior livre (60) ----
|
||||||
|
"Femur": { pt: "Fêmur", paired: true },
|
||||||
|
"Patella": { pt: "Patela", paired: true },
|
||||||
|
"Tibia": { pt: "Tíbia", paired: true },
|
||||||
|
"Fibula": { pt: "Fíbula", paired: true },
|
||||||
|
"Talus": { pt: "Tálus", paired: true },
|
||||||
|
"Calcaneus": { pt: "Calcâneo", paired: true },
|
||||||
|
"Navicular bone": { pt: "Osso Navicular", paired: true },
|
||||||
|
"Medial cuneiform bone": { pt: "Cuneiforme Medial", paired: true },
|
||||||
|
"Intermediate cuneiform bone": { pt: "Cuneiforme Intermédio", paired: true },
|
||||||
|
"Lateral cuneiform bone": { pt: "Cuneiforme Lateral", paired: true },
|
||||||
|
"Cuboid bone": { pt: "Osso Cuboide", paired: true },
|
||||||
|
"First metatarsal bone": { pt: "1º Osso Metatarsal", paired: true },
|
||||||
|
"Second metatarsal bone": { pt: "2º Osso Metatarsal", paired: true },
|
||||||
|
"Third metatarsal bone": { pt: "3º Osso Metatarsal", paired: true },
|
||||||
|
"Fourth metatarsal bone": { pt: "4º Osso Metatarsal", paired: true },
|
||||||
|
"Fifth metatarsal bone": { pt: "5º Osso Metatarsal", paired: true },
|
||||||
|
"Proximal phalanx of first finger of foot": { pt: "Falange Proximal do Hálux", paired: true },
|
||||||
|
"Distal phalanx of first finger of foot": { pt: "Falange Distal do Hálux", paired: true },
|
||||||
|
"Proximal phalanx of second finger of foot": { pt: "Falange Proximal do 2º Dedo do Pé", paired: true },
|
||||||
|
"Middle phalanx of second finger of foot": { pt: "Falange Média do 2º Dedo do Pé", paired: true },
|
||||||
|
"Distal phalanx of second finger of foot": { pt: "Falange Distal do 2º Dedo do Pé", paired: true },
|
||||||
|
"Proximal phalanx of third finger of foot": { pt: "Falange Proximal do 3º Dedo do Pé", paired: true },
|
||||||
|
"Middle phalanx of third finger of foot": { pt: "Falange Média do 3º Dedo do Pé", paired: true },
|
||||||
|
"Distal phalanx of third finger of foot": { pt: "Falange Distal do 3º Dedo do Pé", paired: true },
|
||||||
|
"Proximal phalanx of fourth finger of foot": { pt: "Falange Proximal do 4º Dedo do Pé", paired: true },
|
||||||
|
"Middle phalanx of fourth finger of foot": { pt: "Falange Média do 4º Dedo do Pé", paired: true },
|
||||||
|
"Distal phalanx of fourth finger of foot": { pt: "Falange Distal do 4º Dedo do Pé", paired: true },
|
||||||
|
"Proximal phalanx of fifth finger of foot": { pt: "Falange Proximal do 5º Dedo do Pé", paired: true },
|
||||||
|
"Middle phalanx of fifth finger of foot": { pt: "Falange Média do 5º Dedo do Pé", paired: true },
|
||||||
|
"Distal phalanx of fifth finger of foot": { pt: "Falange Distal do 5º Dedo do Pé", paired: true },
|
||||||
|
};
|
||||||
Reference in new issue
Block a user