CERCON / modules /cad_assistant.py
carlosh10's picture
feat: Adiciona assistente CAD/BIM scripts AutoCAD e Dynamo
7dafa38 verified
"""
Assistente CAD/BIM - Geracao de Scripts AutoCAD e Dynamo/Revit
Para posicionamento de sistemas de prevencao de incendio - NT-01/2025
"""
import math
import json
from datetime import datetime
from typing import Dict, List, Tuple
class CADAssistant:
"""
Gera scripts .scr (AutoCAD) e Python (Dynamo/Revit API)
para posicionamento automatico de sistemas de incendio.
"""
BLOCOS = {
"extintor": "EXTINTOR_PSCIP",
"hidrante": "HIDRANTE_PSCIP",
"saida_emerg": "SAIDA_EMERG_PSCIP",
"detector": "DETECTOR_FUMACA_PSCIP",
"acionador": "ACIONADOR_MANUAL_PSCIP",
"ilum_emerg": "BLOCO_AUTONOMO_PSCIP",
}
LAYERS = {
"extintores": "INCENDIO-EXTINTORES",
"hidrantes": "INCENDIO-HIDRANTES",
"sinalizacao": "INCENDIO-SINALIZACAO",
"deteccao": "INCENDIO-DETECCAO",
"iluminacao": "INCENDIO-ILUMINACAO",
}
CORES = {"extintores":"1","hidrantes":"5","sinalizacao":"3","deteccao":"2","iluminacao":"6"}
def calcular_posicoes_extintores(self, larg, comp, qtd):
posicoes, dist_max = [], 14.0
if qtd <= 0: return posicoes
cols = max(1, math.ceil(larg / dist_max))
rows = max(1, math.ceil(comp / dist_max))
while cols * rows < qtd:
if larg / (cols+1) >= comp / (rows+1): cols += 1
else: rows += 1
px, py = larg / cols, comp / rows
for row in range(rows):
for col in range(cols):
posicoes.append((round(px*(col+0.5),2), round(py*(row+0.5),2)))
if len(posicoes) >= qtd: break
if len(posicoes) >= qtd: break
return posicoes[:qtd]
def calcular_posicoes_saidas(self, larg, comp, num_saidas):
pos = []
if num_saidas >= 1: pos.append((larg/2, 0.0, "SUL"))
if num_saidas >= 2: pos.append((larg/2, comp, "NORTE"))
if num_saidas >= 3: pos.append((0.0, comp/2, "OESTE"))
if num_saidas >= 4: pos.append((larg, comp/2, "LESTE"))
return pos[:num_saidas]
def calcular_posicoes_detectores(self, larg, comp):
posicoes, passo = [], 8.0
cols, rows = max(1, math.ceil(larg/passo)), max(1, math.ceil(comp/passo))
px, py = larg/cols, comp/rows
return [(round(px*(c+0.5),2), round(py*(r+0.5),2))
for r in range(rows) for c in range(cols)]
def gerar_script_autocad(self, dados):
larg = dados.get("largura_m", 30.0)
comp = dados.get("comprimento_m", 30.0)
qtd_ext = dados.get("qtd_extintores", 4)
num_saidas = dados.get("num_saidas_emergencia", 2)
tem_det = dados.get("tem_deteccao", False)
escala = dados.get("escala", 100)
f = escala
linhas = [
"; ===================================================",
"; Script AutoCAD - Agente CBMGO - NT-01/2025",
f"; Gerado em: {datetime.now().strftime('%d/%m/%Y %H:%M')}",
"; ===================================================", "",
"; Criando layers PSCIP...",
]
for nome, layer in self.LAYERS.items():
linhas.append(f"-LAYER N {layer} C {self.CORES[nome]} {layer} L CONTINUOUS {layer} ")
linhas += ["", f"; --- EXTINTORES ({qtd_ext} un.) - Distancia max. 15m ---",
f"-LAYER SET {self.LAYERS['extintores']} "]
for i, (x, y) in enumerate(self.calcular_posicoes_extintores(larg, comp, qtd_ext), 1):
xc, yc = round(x*f), round(y*f)
linhas.append(f"INSERT {self.BLOCOS['extintor']} {xc},{yc} 1 1 0 ")
linhas += ["", f"; --- SAIDAS DE EMERGENCIA ({num_saidas} un.) ---",
f"-LAYER SET {self.LAYERS['sinalizacao']} "]
for i, (x, y, d) in enumerate(self.calcular_posicoes_saidas(larg, comp, num_saidas), 1):
xc, yc = round(x*f), round(y*f)
ang = {"SUL":90,"NORTE":270,"LESTE":180,"OESTE":0}.get(d, 0)
linhas.append(f"INSERT {self.BLOCOS['saida_emerg']} {xc},{yc} 1 1 {ang} ")
if tem_det:
linhas += ["", "; --- DETECTORES DE FUMACA ---",
f"-LAYER SET {self.LAYERS['deteccao']} "]
for x, y in self.calcular_posicoes_detectores(larg, comp):
linhas.append(f"INSERT {self.BLOCOS['detector']} {round(x*f)},{round(y*f)} 1 1 0 ")
linhas += ["", "QSAVE ", "", "; FIM DO SCRIPT"]
return "\n".join(linhas)
def gerar_relatorio_posicionamento(self, dados):
larg = dados.get("largura_m", 30.0)
comp = dados.get("comprimento_m", 30.0)
qtd_ext = dados.get("qtd_extintores", 4)
num_saidas = dados.get("num_saidas_emergencia", 2)
pos_ext = self.calcular_posicoes_extintores(larg, comp, qtd_ext)
pos_saidas = self.calcular_posicoes_saidas(larg, comp, num_saidas)
linhas = [
"=" * 50, "RELATORIO DE POSICIONAMENTO - SISTEMAS PSCIP",
f"Data: {datetime.now().strftime('%d/%m/%Y %H:%M')}",
f"Planta: {larg:.1f}m x {comp:.1f}m = {larg*comp:.0f}m2",
"=" * 50, f"\nEXTINTORES ({qtd_ext} unidades):",
]
for i, (x, y) in enumerate(pos_ext, 1):
linhas.append(f" EXT-{i:02d}: X={x:.2f}m, Y={y:.2f}m")
linhas.append(f"\nSAIDAS DE EMERGENCIA ({num_saidas} unidades):")
for i, (x, y, d) in enumerate(pos_saidas, 1):
linhas.append(f" SAIDA-{i:02d}: X={x:.2f}m, Y={y:.2f}m (parede {d})")
linhas += ["", "Notas:", "- Posicoes calculadas pelo Agente CBMGO",
"- Distancia maxima ao extintor: 14m (NT-01/2025 Anexo B)",
"- Validar com projeto arquitetonico", "=" * 50]
return "\n".join(linhas)
_cad_instance = None
def get_cad_assistant():
global _cad_instance
if _cad_instance is None:
_cad_instance = CADAssistant()
return _cad_instance
if __name__ == "__main__":
cad = CADAssistant()
dados = {"largura_m": 25.0, "comprimento_m": 40.0,
"qtd_extintores": 5, "num_saidas_emergencia": 3,
"tem_deteccao": True, "escala": 100}
print(cad.gerar_relatorio_posicionamento(dados))