Saltar al contenido

← Blog

Automatizar dibujos DWG con Python (y con AutoLISP o MCP)

· Guías

Dibujar la misma rejilla de ejes en cada proyecto, contar bloques en cien planos o poner en capa lo que alguien dejó en la capa 0 son tareas que se repiten. LinceCAD se puede manejar desde fuera con una API local: un script de Python abre dibujos, crea entidades, cambia capas, ejecuta comandos y guarda en DWG. Todo va por canales del propio equipo; nada sale a internet.

Cuatro caminos, según lo que necesites

VíaQué esCuándo usarla
API local (JSON-RPC)Un mensaje JSON por línea por una tubería con nombre (Windows) o un socket (Linux). Funciona desde cualquier lenguaje.Manejar LinceCAD, con la ventana abierta o sin ella, desde tus propios programas.
Cliente lince de PythonUna biblioteca sin dependencias sobre esa API: dib.linea(…), dib.guardar_como(…)…Scripts de Python más cortos y legibles.
Rueda lince_nucleoUn módulo de Python compilado que lee, modifica y guarda DWG/DXF sin abrir LinceCAD.Lotes de archivos, servidores o Jupyter.
AutoLISPEl intérprete incorporado, con unas 200 funciones.Comandos propios dentro del programa, o rutinas LISP que ya tengas.

Además, LinceCAD trae un servidor MCP para conectar asistentes de IA, del que hablamos al final.

Paso 1: activar la automatización

La API está desactivada por defecto. Hay dos formas de usarla:

Los programas se identifican con una ficha (una contraseña de 64 caracteres) que está en api.toml, en %APPDATA%\lince en Windows o ~/.config/lince en Linux. Solo tu usuario puede leerla.

Paso 2: un script con la biblioteca estándar

Este ejemplo no necesita instalar nada más que Python. Arranca antes lince --servidor --canal blogpy (o usa el canal de la ventana abierta). El script se presenta con la ficha, crea un dibujo, una capa y una parcela de 30 × 20 y la guarda en DWG:

import json, os

# La ficha (contraseña de la API) está en %APPDATA%\lince\api.toml
toml = os.path.join(os.environ["APPDATA"], "lince", "api.toml")
ficha = next(l.split("=", 1)[1].strip().strip('"')
             for l in open(toml, encoding="utf-8") if l.startswith("ficha"))

canal = open(r"\\.\pipe\blogpy", "r+b", buffering=0)  # lince --servidor --canal blogpy
n = 0

def llamar(metodo, **params):
    global n
    n += 1
    msg = {"jsonrpc": "2.0", "id": n, "method": metodo, "params": params}
    canal.write((json.dumps(msg) + "\n").encode("utf-8"))
    r = json.loads(canal.readline())
    if "error" in r:
        raise RuntimeError(r["error"]["message"])
    return r["result"]

llamar("session.hello", token=ficha)
llamar("document.new")
llamar("layer.create", name="PARCELA", color=1)
llamar("entity.create", entity={"type": "LWPOLYLINE", "layer": "PARCELA", "closed": True,
                                "vertices": [[0, 0], [30, 0], [30, 20], [0, 20]]})
print(llamar("document.summary")["byType"])         # {'LWPOLYLINE': 1}
print(llamar("document.saveAs", path=r"C:\planos\parcela.dwg"))

La primera petición de cada conexión tiene que ser session.hello; si no, la conexión se cierra. En Linux, en vez de open(), conecta un socket.AF_UNIX a la ruta del socket y usa s.makefile("rwb", buffering=0); el resto es igual.

La API tiene métodos para dibujos (document.open, save, saveAs, summary…), entidades (entity.query, get, create, set, delete, como objetos o como listas DXF de entget), capas, bloques, estilos, variables, designación, deshacer, comandos (command.run), AutoLISP (lisp.eval), trazado a PDF, PNG y SVG, captura de la vista y eventos. document.saveAs guarda en DWG o DXF según la extensión, en versión 2018 por defecto o en 2013, 2010, 2007, 2004, 2000 y R14.

Paso 3: lo mismo con el cliente de Python

El cliente lince envuelve esa API en objetos. Este script, con lince.iniciar(), arranca LinceCAD sin ventana, dibuja una rejilla de ejes con sus rótulos y doce pilares de 30 × 30 cm, y guarda el DWG, un PDF y una imagen:

import lince

ejes_x = [0, 5.0, 10.5, 16.0]      # posición de los ejes, en metros
ejes_y = [0, 4.5, 9.0]
h = 0.15                            # medio lado de un pilar de 30 x 30 cm

with lince.iniciar() as s:          # arranca LinceCAD sin ventana
    dib = s.nuevo()
    dib.crear_capa("EJES", color=1)
    dib.crear_capa("PILARES", color=7)
    dib.crear_capa("ROTULOS", color=3)
    with dib.transaccion():         # todo queda en un solo paso de deshacer
        for i, x in enumerate(ejes_x):
            dib.linea([x, -1.5], [x, ejes_y[-1] + 1.5], layer="EJES")
            dib.texto([x - 0.15, ejes_y[-1] + 2], str(i + 1), altura=0.4, layer="ROTULOS")
        for j, y in enumerate(ejes_y):
            dib.linea([-1.5, y], [ejes_x[-1] + 1.5, y], layer="EJES")
            dib.texto([-2.3, y - 0.2], "ABC"[j], altura=0.4, layer="ROTULOS")
        for x in ejes_x:
            for y in ejes_y:
                dib.polilinea([[x - h, y - h], [x + h, y - h], [x + h, y + h], [x - h, y + h]],
                              cerrada=True, layer="PILARES")
    print(dib.resumen()["byType"])  # {'LINE': 7, 'LWPOLYLINE': 12, 'TEXT': 7}
    dib.trazar_pdf(r"C:\planos\ejes.pdf")
    dib.guardar_como(r"C:\planos\ejes.dwg")
    dib.captura(r"C:\planos\ejes.png", ancho=1280)
Rejilla de cuatro ejes verticales (1 a 4) y tres horizontales (A a C) en rojo, con doce pilares cuadrados en los cruces y los rótulos de los ejes en verde, sobre fondo blanco.
La imagen que guarda el script con dib.captura.

Para trabajar con la ventana ya abierta se usa lince.conectar() y s.dibujo (el dibujo activo). Hay también .circulo, .arco, .mtexto, .insertar (bloques), .consultar (por tipo, capa, caja o filtro), .comando, .lisp y .trazar_png/.trazar_svg.

Sin abrir LinceCAD: la rueda lince_nucleo

Para procesar muchos archivos, la rueda lince_nucleo trabaja dentro del propio proceso de Python. Este fragmento, de la documentación, lista los círculos de un plano y lo guarda en DWG 2018:

import lince_nucleo as ln
dib = ln.abrir("plano.dwg")
for e in dib.consultar(tipo="CIRCLE"):
    print(e["handle"], e["radius"])
dib.guardar("salida.dwg", "2018")

La alternativa sin Python: AutoLISP

Si ya trabajas con LISP, puedes seguir haciéndolo. El intérprete de LinceCAD admite defun C:, ssget con filtros, entget, entmod, entmake y command, entre otras; las rutinas se cargan con APPLOAD o automáticamente desde acaddoc.lsp. Este comando cuenta los pilares del plano anterior:

(defun C:CONTARPILARES (/ ss)
  (setq ss (ssget "X" '((0 . "LWPOLYLINE") (8 . "PILARES"))))
  (princ (strcat "\nPilares: " (itoa (if ss (sslength ss) 0))))
  (princ)
)

Sobre ejes.dwg responde «Pilares: 12». Para secuencias fijas de órdenes también están los guiones (SCRIPT).

Asistentes de IA con MCP

lince --mcp es un servidor MCP (Model Context Protocol) por la entrada y la salida estándar, para los asistentes que lo arrancan ellos. Con la ventana abierta se puede activar además un servidor MCP por HTTP, solo en 127.0.0.1. El asistente ve herramientas para abrir, consultar, crear, acotar, insertar bloques, trazar a PDF, capturar la vista y deshacer, y la ayuda de LinceCAD como documentación. Por ejemplo, para darlo de alta en Claude Code:

claude mcp add --scope project lince -- "C:\Program Files\lince\lince.exe" --mcp

Con la confirmación activada, cada cambio que pide el asistente espera en la paleta ACCIONESIA hasta que lo aceptas o lo rechazas, y todo lo que hace una llamada se deshace con un solo DESHACER. La lista completa de herramientas y una sesión real están en qué es MCP y cómo usarlo con LinceCAD.

Limitaciones

Preguntas frecuentes

¿Y si el plano de partida es un escaneo? Primero hay que pasarlo a vectores: lo explicamos en cómo vectorizar un plano escaneado y pasarlo a DWG.

¿Y en Linux? La API funciona igual, con un socket Unix. Lee cómo abrir y editar DWG en Linux.

¿Y para topografía? El proceso con la ficha Topografía está en curvas de nivel a partir de una nube de puntos LAS/LAZ.

La API local, AutoLISP y el servidor MCP vienen en LinceCAD, con licencia perpetua. Descargas · Ver precios · AutoLISP, automatización y el resto de funciones.