117 lines
9.6 KiB
Markdown
117 lines
9.6 KiB
Markdown
# Atlas 3D de Anatomia
|
|
|
|
Plataforma web dockerizada para estudo de anatomia com um visualizador 3D interativo, camadas por sistema, dissecção virtual (plano de corte), busca/navegação por região e um modo quiz com repetição espaçada (SM-2).
|
|
|
|
## Conteúdo 3D: modelos reais do projeto Z-Anatomy
|
|
|
|
Os modelos 3D vêm do **Z-Anatomy-Sample** (github.com/LluisV/Z-Anatomy-Sample), um reempacotamento aberto do dataset BodyParts3D/FMA (Database Center for Life Science, Univ. de Tóquio) em malhas segmentadas e nomeadas por estrutura, organizadas por sistema. Ao contrário do site oficial do BodyParts3D (que só permite download manual, estrutura por estrutura, por uma aplicação legada), o Z-Anatomy-Sample publica os arquivos FBX diretamente no GitHub, permitindo baixar e converter tudo via script.
|
|
|
|
**Licença: CC BY-SA 4.0.** Isso significa: (1) é obrigatório dar crédito ao projeto original — já incluído no rodapé da aplicação e aqui; (2) qualquer redistribuição das malhas (mesmo modificadas, como as recolorizações que fazemos aqui) deve continuar sob a mesma licença CC BY-SA 4.0. Se for redistribuir este projeto publicamente, mantenha essa nota.
|
|
|
|
O pipeline (`data-pipeline/`) baixa os `.fbx` reais, converte para `.glb` via `assimp`, recolore cada malha por sistema (para um visual consistente, já que o FBX não carrega a paleta de cores usada no app Unity original do Z-Anatomy) e gera o manifesto do banco automaticamente a partir dos milhares de nomes de estrutura reais contidos nos arquivos — sem geometria placeholder, exceto pelo sistema tegumentar (veja abaixo).
|
|
|
|
**Tradução dos nomes**: como isso é uma ferramenta de estudo para prova, uma tradução errada de termo médico é pior do que nenhuma tradução — por isso só traduzimos para PT-BR quando o nome bate exatamente com um dicionário curado (`data-pipeline/scripts/translate-pt.mjs`, ~120 termos comuns). Estruturas fora desse dicionário aparecem com o nome original em inglês/latim, que também é nomenclatura anatômica padrão usada no ensino de anatomia.
|
|
|
|
**O que não veio do Z-Anatomy-Sample**: a amostra pública não inclui camadas de pele — por isso o sistema **tegumentar** continua usando geometria esquemática simples (`data-pipeline/seed/build-manifest.mjs`), como um placeholder claramente sinalizado. Também não importamos (ainda) os arquivos "Regions of human body" e "Reference lines, planes and movements" do mesmo repositório — dá para adicionar depois seguindo o mesmo padrão em `data-pipeline/scripts/sources.mjs`.
|
|
|
|
## Arquitetura
|
|
|
|
Este compose foi adaptado para rodar como um stack **separado** dentro da infraestrutura existente do host `cloud-lua-net`, que já tem uma rede Docker externa `dockernet` e um container `nginx` central (com HTTP/3) que lê vhosts manuais em `docker/nginx/sites/*.conf`, mais um par `nginx-gen` + `acme-companion` que emite certificados Let's Encrypt via `LETSENCRYPT_HOST`.
|
|
|
|
```
|
|
container "nginx" (proxy principal do host, HTTP/3, já existente)
|
|
│ vhost manual: docker/nginx/sites/30-atlas.conf
|
|
│ proxy_pass → IP fixo do container anatomia-web em dockernet
|
|
▼
|
|
container "anatomia-web" (nginx interno deste projeto)
|
|
├─ serve o build estático do frontend (SPA)
|
|
├─ /api/* → proxy → container "anatomia-api"
|
|
└─ /models/* → proxy → container "anatomia-api"
|
|
container "anatomia-api" (Fastify + Prisma) ──▶ container "anatomia-db" (Postgres)
|
|
```
|
|
|
|
Não é publicada nenhuma porta no host — `anatomia-web` só é alcançável dentro da rede `dockernet`, no mesmo padrão já usado para outros apps desse compose (ex: `frontend`/`backend` do ticketz, `nextcloud`). Isso significa que **este projeto roda como um `docker compose` próprio, independente do compose gigante do host** — ele só precisa se conectar à mesma rede externa `dockernet`, o que já é suportado nativamente pelo Docker (containers de projetos Compose diferentes na mesma rede se enxergam normalmente).
|
|
|
|
## Como rodar
|
|
|
|
```bash
|
|
# no host cloud-lua-net, dentro da pasta deste projeto (ex: /home/docker/anatomia)
|
|
cp .env.example .env
|
|
# Confirme que o IP escolhido está livre antes de subir:
|
|
docker network inspect dockernet | grep -A2 IPv4Address
|
|
# ajuste ANATOMIA_WEB_IP no .env se 10.15.0.93 já estiver em uso
|
|
|
|
docker compose up -d --build anatomia-db anatomia-api anatomia-web
|
|
docker compose build anatomia-pipeline
|
|
docker compose run --rm anatomia-pipeline # baixa+converte os modelos reais e popula o banco
|
|
```
|
|
|
|
O `anatomia-pipeline` baixa ~230MB de arquivos FBX do GitHub e os converte com `assimp` — a primeira execução pode levar alguns minutos. Acompanhe com `docker compose run --rm anatomia-pipeline` mesmo (ele já roda em foreground) ou olhe os logs se rodar em background.
|
|
|
|
Depois, no host, copie `deploy/nginx-vhost-atlas.conf` para `/home/docker/docker/nginx/sites/30-atlas.conf` (ajustando o nome do arquivo para não colidir com os já existentes) e garanta que o DNS de `atlas.martinsevieira.adv.br` aponte para este servidor. O container `anatomia-web` já sobe com `LETSENCRYPT_HOST=atlas.martinsevieira.adv.br`, então o `acme-companion` existente no host emite o certificado automaticamente assim que o vhost estiver ativo e respondendo ao desafio ACME (veja os comentários no próprio arquivo `deploy/nginx-vhost-atlas.conf` para os detalhes/pré-requisitos).
|
|
|
|
Para reprocessar o dataset depois de mudar `data-pipeline/scripts/sources.mjs`, `translate-pt.mjs` ou `seed/build-manifest.mjs` (tegumentar), rode `docker compose run --rm anatomia-pipeline` novamente — ele reaproveita os `.fbx`/`.glb` já baixados/convertidos se ainda existirem no container (perdidos ao término do `--rm`, então uma nova execução sempre rebaixa/reconverte do zero; isso é intencional para manter o serviço fora do stack "sempre ligado", mas significa que cada execução leva alguns minutos).
|
|
|
|
### Rodando fora desse host (dev local, sem "dockernet")
|
|
|
|
O `docker-compose.yml` deste projeto depende da rede externa `dockernet` e de um IP fixo, então para testar localmente em outra máquina crie a rede primeiro e ajuste/remova o `ipv4_address`, ou publique uma porta temporária no serviço `anatomia-web`, por exemplo:
|
|
|
|
```bash
|
|
docker network create dockernet # numa máquina onde ela ainda não existe
|
|
```
|
|
|
|
E adicione temporariamente ao serviço `anatomia-web` no `docker-compose.yml`:
|
|
|
|
```yaml
|
|
ports:
|
|
- "8080:80"
|
|
```
|
|
|
|
Depois `docker compose up -d --build anatomia-db anatomia-api anatomia-web && docker compose run --rm anatomia-pipeline` e acesse `http://localhost:8080`.
|
|
|
|
## Estrutura do projeto
|
|
|
|
- `frontend/` — React + TypeScript + Vite + react-three-fiber (visualizador 3D), Zustand, Tailwind.
|
|
- `backend/` — Fastify + TypeScript + Prisma (API REST + arquivos `.glb` estáticos).
|
|
- `data-pipeline/` — scripts que geram os modelos 3D semente e populam o banco (roda como serviço Docker *one-off*, não fica sempre ligado).
|
|
- `nginx/nginx.conf` — nginx interno que serve o frontend e faz proxy para a API.
|
|
|
|
## Funcionalidades
|
|
|
|
- **Camadas por sistema**: esquelético, muscular, nervoso, cardiovascular, respiratório, órgãos viscerais (digestório/urinário/endócrino/reprodutor), articulações, linfático, tegumentar — ligar/desligar independentemente.
|
|
- **Labels clicáveis**: clique em qualquer estrutura no modelo 3D para ver nome, sistema, região e descrição.
|
|
- **Busca e navegação**: busca fuzzy + árvore por sistema/região; selecionar uma estrutura move a câmera até ela.
|
|
- **Dissecção virtual**: plano de corte deslizante nos três planos anatômicos (sagital, coronal, transversal).
|
|
- **Módulo de planos e eixos anatômicos** (`/planos-anatomicos`): manequim simples com os três planos de secção, eixos de direção rotulados e glossário de termos (anterior/posterior, medial/lateral, proximal/distal etc.).
|
|
- **Quiz com repetição espaçada** (`/quiz`): pede para localizar a estrutura no modelo 3D; usa o algoritmo SM-2 para agendar revisões.
|
|
|
|
## Expandindo o dataset
|
|
|
|
1. **Mais arquivos do Z-Anatomy-Sample** (ex: "Regions of human body", "Reference lines, planes and movements"): adicione a entrada em `data-pipeline/scripts/sources.mjs` (`SOURCES` + `SOURCE_TARGETS`), rode o pipeline de novo.
|
|
2. **Melhorar a tradução PT-BR**: acrescente entradas em `data-pipeline/scripts/translate-pt.mjs` (`EXACT_PT`) — é correspondência exata de propósito, para não arriscar tradução errada de termo médico.
|
|
3. **Sistema tegumentar com malha real**: se aparecer uma fonte aberta com camadas de pele, substitua a geração esquemática em `data-pipeline/seed/build-manifest.mjs` pelo mesmo padrão de extração usado em `scripts/extract-manifest.mjs`.
|
|
4. **Novos sistemas anatômicos**: adicione em `data-pipeline/seed/systems.mjs` — o schema (`backend/prisma/schema.prisma`) já suporta qualquer sistema sem mudar código.
|
|
|
|
## Créditos
|
|
|
|
Modelos 3D derivados do projeto **Z-Anatomy** (github.com/LluisV/Z-Anatomy-Sample), com base no dataset BodyParts3D/FMA (Database Center for Life Science, Universidade de Tóquio) — licença **CC BY-SA 4.0**. As malhas foram convertidas de FBX para glTF e recoloridas por sistema anatômico para este atlas.
|
|
|
|
## Desenvolvimento local (sem Docker)
|
|
|
|
```bash
|
|
# Backend
|
|
cd backend && npm install
|
|
export DATABASE_URL=postgresql://anatomia:anatomia@localhost:5432/anatomia
|
|
npx prisma migrate deploy
|
|
npm run dev
|
|
|
|
# Frontend (em outro terminal)
|
|
cd frontend && npm install
|
|
npm run dev # http://localhost:5173, faz proxy de /api e /models para :3333
|
|
|
|
# Dataset (em outro terminal, com DATABASE_URL exportada)
|
|
# Requer o binário "assimp" instalado localmente (ex: apt/brew install assimp).
|
|
cd data-pipeline && npm install
|
|
npm run run:all
|
|
```
|