plano3d/prototipo/lizette/conversion.py

60 lines
1.9 KiB
Python

"""Prueba de concepto: DXF 2D -> modelo 3D (STEP y STL) por extrusion.
Uso: python conversion.py placa.dxf 10 (DXF y espesor en mm)
"""
import sys
import cadquery as cq
import ezdxf
def area(puntos):
"""Area de un poligono con la formula del area de Gauss (shoelace)."""
s = 0.0
for (x1, y1), (x2, y2) in zip(puntos, puntos[1:] + puntos[:1]):
s += x1 * y2 - x2 * y1
return abs(s) / 2
def leer_perfiles(ruta):
"""Devuelve las polilineas cerradas y los circulos del DXF."""
doc = ezdxf.readfile(ruta)
msp = doc.modelspace()
poligonos = []
for e in msp.query("LWPOLYLINE"):
if e.closed:
poligonos.append([(p[0], p[1]) for p in e.get_points()])
circulos = [(c.dxf.center.x, c.dxf.center.y, c.dxf.radius)
for c in msp.query("CIRCLE")]
return poligonos, circulos
def construir_solido(poligonos, circulos, altura):
"""El perfil de mayor area es el exterior; el resto se restan como agujeros."""
if not poligonos:
raise ValueError("El DXF no contiene ningun perfil cerrado")
exterior = max(poligonos, key=area)
solido = cq.Workplane("XY").polyline(exterior).close().extrude(altura)
for p in poligonos:
if p is not exterior:
hueco = cq.Workplane("XY").polyline(p).close().extrude(altura)
solido = solido.cut(hueco)
for x, y, r in circulos:
taladro = cq.Workplane("XY").center(x, y).circle(r).extrude(altura)
solido = solido.cut(taladro)
return solido
def main():
ruta, altura = sys.argv[1], float(sys.argv[2])
poligonos, circulos = leer_perfiles(ruta)
print(f"Perfiles cerrados: {len(poligonos)} · Circulos: {len(circulos)}")
solido = construir_solido(poligonos, circulos, altura)
cq.exporters.export(solido, "resultado.step")
cq.exporters.export(solido, "resultado.stl")
print("Generados resultado.step y resultado.stl")
if __name__ == "__main__":
main()