Pipeline em Python para normalizar plantas CAD (DXF/DWG), filtrar layers por semântica, padronizar unidades e converter a geometria 2D em um grafo topológico (nós/arestas) para usos em IA/QA/validações.
- Suporte a DXF nativo (
ezdxf) - Suporte a DWG via conversão para DXF com uma CLI externa (configurável)
- Normalização de unidades (ex.: tudo para metros)
- Normalização de layers (uppercase, remoção de prefixos, limpeza)
- Mapeamento semântico de layers por regex (ex.:
WALL,DOOR,WINDOW,GRID…) - Filtros por semântica (incluir/excluir)
- Explosão virtual de blocos e discretização de arcos/círculos
- Construção de grafo topológico com snapping e interseções
- Exportações em GraphML e JSON (fácil integrar com Gephi, NetworkX, etc.)
cad-preproc/
├─ cad_preproc/
│ ├─ __init__.py
│ ├─ io.py # leitura DWG/DXF, conversão DWG->DXF (via CLI externa)
│ ├─ units.py # normalização de unidades (INSUNITS → metros)
│ ├─ layers.py # normalização e filtros semânticos (regex/whitelist/blacklist)
│ ├─ geometry.py # explode/discretiza entidades em segmentos LineString
│ ├─ graph.py # snapping, interseção e montagem do grafo (networkx)
│ ├─ pipeline.py # orquestra o fluxo ponta-a-ponta
│ └─ schemas.py # tipos/estruturas auxiliares
├─ configs/
│ └─ default.yml # tolerâncias, mapeamentos, exportação
├─ tests/
├─ cli.py # interface de linha de comando
├─ pyproject.toml
└─ README.md
-
Python ≥ 3.10
-
Dependências:
ezdxf(leitura DXF, entities e “itervirtualentities” para blocos)shapely(geometrias robustas e interseções)networkx(grafo)pyyaml(configuração YAML)
-
(Opcional) Conversor DWG → DXF (CLI) Para abrir DWG, o projeto usa um conversor externo para produzir um DXF equivalente. Você aponta o executável via
--dwg2dxf. Exemplos de categorias de conversores que costumam ser usados em pipelines:- ODA File Converter (ferramenta de linha de comando da Open Design Alliance / Teigha).
- Ferramentas CAD com modo batch/CLI que exportam DWG→DXF (por ex., versões com automação/script).
- Outros conversores DWG→DXF confiáveis com uso via terminal.
Observação: este repositório não inclui nenhum conversor DWG por questões de licença/redistribuição. Você deve instalar/configurar o seu e passar o caminho do binário via
--dwg2dxf.
python -m venv .venv
source .venv/bin/activate
pip install ezdxf shapely networkx pyyaml(Se for usar DWG: instale seu conversor CLI e anote o caminho do executável.)
units:
target: "m" # unidade final da pipeline (metros)
arc_segment_len: 0.05 # tamanho alvo do segmento para discretizar arcos (m)
snap_tolerance: 0.01 # tolerância para unir vértices (m)
intersect_tolerance: 1e-6
layers:
normalize:
remove_prefixes: ["A-", "E-", "S-", "ARQ-"]
uppercase: true
strip_chars: [" ", "\t"]
semantic_map:
- {match: "WALL|PAREDE|ALV|ALVENARIA", semantic: "WALL"}
- {match: "DOOR|PORTA", semantic: "DOOR"}
- {match: "WIN(DOW)?|JANELA", semantic: "WINDOW"}
- {match: "GRID|EIXO|AXIS", semantic: "GRID"}
- {match: "TEXT|MTEXT|ANNOT|NOTE", semantic: "TEXT"}
- {match: "DIM|COTA", semantic: "DIM"}
- {match: "HATCH|HACHURA", semantic: "HATCH"}
include_semantics: ["WALL", "DOOR", "WINDOW", "GRID"]
exclude_semantics: ["TEXT", "DIM", "HATCH"]
export:
formats: ["graphml", "json"]
out_basename: "graph"- Unidades: se o desenho estiver em polegadas/pés/mm, o pipeline lê
$INSUNITSdo DXF e faz a conversão para metros. - Semântica: edite/adicione regex para refletir a nomenclatura do seu escritório/projeto/cidade.
- Filtros: controle o que entra na análise (ex.: excluir
TEXT/DIM/HATCHpara reduzir ruído). - Tolerâncias:
snap_tolerancegoverna o “encaixe” de nós;arc_segment_lencontrola o detalhamento de arcos/círculos.
python cli.py /caminho/planta.dxf \
--config configs/default.yml \
--outdir out/python cli.py /caminho/planta.dwg \
--dwg2dxf "/caminho/para/seu/conversor" \
--config configs/default.yml \
--outdir out/Saídas padrão:
out/graph.graphml– grafo para Gephi/NetworkXout/graph.json– nós/arestas + WKT para debug/integração
-
Leitura & Conversão (io.py)
- Se for DWG, chamamos o binário configurado em
--dwg2dxfpara gerar um DXF temporário. - Para DXF, lemos com
ezdxfe iteramos o modelspace.
- Se for DWG, chamamos o binário configurado em
-
Unidades (units.py)
- Lemos
$INSUNITSdo header DXF e obtemos o fator de escala → metros. - Todos os vértices/segmentos são multiplicados pelo fator, padronizando a métrica.
- Lemos
-
Normalização de Layers (layers.py)
- Limpeza de string (espaços/tabs), uppercase, remoção de prefixos padrão.
- Cada layer é classificado contra um mapa semântico (regex →
WALL,DOORetc.).
-
Filtros Semânticos
- Mantemos apenas os layers cujo semântico esteja em
include_semanticse não esteja emexclude_semantics.
- Mantemos apenas os layers cujo semântico esteja em
-
Explosão & Discretização (geometry.py)
- Blocos (
INSERT) são lidos virtualmente viaitervirtualentities(sem alterar o arquivo). - ARC/CIRCLE são discretizados em segmentos lineares com passo definido por
arc_segment_len.
- Blocos (
-
Grafo Topológico (graph.py)
- Snapping: endpoints próximos se unem (grade por tolerância).
- Interseções: linhas são unidas/particionadas para produzir segmentos atômicos.
- Montamos o grafo (
networkx) com nós (x,y) e arestas (comprimento, WKT, semântica).
-
Exportação
- Salvamos GraphML e JSON com atributos úteis (comprimento, WKT, semântica → “MIXED/UNKNOWN” por padrão, pode evoluir).
from cad_preproc.pipeline import run_pipeline
G = run_pipeline(
input_path="exemplos/plantas/planta_teste.dxf",
config_path="configs/default.yml",
dwg2dxf_cmd=None, # ou "/caminho/ODAFileConverter" para DWG
)
print(G.number_of_nodes(), G.number_of_edges())
# -> use G para métricas, buscas de caminhos, conectividade, etc.-
Por que converter? Leitura de DWG diretamente em Python costuma exigir SDKs/licenças específicas. A conversão para DXF via CLI torna o pipeline reprodutível e portável.
-
Como configurar?
- Instale uma ferramenta que exporte DWG para DXF por linha de comando.
- Passe o caminho do binário na execução:
--dwg2dxf "/caminho/para/conversor". - O
io.pychama essa CLI e espera um arquivo.dxfcomo resultado ao lado do DWG.
-
Formatos DXF
- Caso o conversor permita, prefira DXF em versões amplamente compatíveis (ex.: R2010/R2007).
- Se seu desenho usa recursos mais novos (e.g., splines complexas), mantenha uma versão de DXF que preserve a geometria.
Importante: nós não distribuímos o conversor. Verifique licenças/termos de uso do conversor que você escolher.
- Relatórios de QA (CSV/HTML): contagens por layer/semântica, nós/arestas, comprimentos médios, alertas.
- Atribuição semântica por aresta: majoritária por sobreposição/interseção com as linhas filtradas.
- Export Geo: GeoJSON/GeoPackage (nós/arestas) para abrir no QGIS.
- 3D: incluir Z quando relevante.
- Índices espaciais: STRtree (Shapely) para acelerar operações em plantas muito grandes.
- Multiprocessamento com tiling espacial.
- Aumente
arc_segment_lenpara menos segmentos (menos detalhamento, mais rápido). - Ajuste
snap_tolerancecom cuidado: grandes demais podem fundir geometria que não deveria. - Pré-filtre layers cedo (evite carregar/guardar entidades que você sabe que serão descartadas).
- Em plantas enormes, divida por tiles (ex.: grade 50m×50m), processe em paralelo e depois una resultados.
1) Meu arquivo DWG não abre. → Confirme se o conversor DWG→DXF funciona no terminal e gere manualmente um DXF. Depois rode a pipeline com o DXF.
2) As unidades parecem erradas.
→ Verifique $INSUNITS no cabeçalho do DXF. Se o desenho veio “unitless” (0), defina um fator explícito no código/units.py ou padronize o CAD antes.
3) Há muita perda de detalhe em arcos.
→ Diminua arc_segment_len (ex.: 0.01 m). Isso aumenta o número de segmentos e a fidelidade.
4) O grafo está com nós “grudados” demais.
→ Reduza snap_tolerance para ser mais conservador no encaixe de vértices.
5) Quero manter textos/cotas para alguma análise específica.
→ Remova TEXT/DIM de exclude_semantics e/ou adicione regras dedicadas no semantic_map.
- Issues com exemplos mínimos (DXF recortado) ajudam muito.
- Pull requests: seguir o estilo PEP8/Black, adicionar testes quando possível.
- ezdxf – parsing DXF em Python.
- Shapely – operações geométricas robustas.
- NetworkX – grafos.
- Conversores DWG→DXF (não incluídos) – usar conforme suas licenças/ambiente.