Visual LISP, AutoLISP and General Customization
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

How to interface with AutoCAD from Python?

29 REPLIES 29
SOLVED
Reply
Message 1 of 30
Anonymous
13418 Views, 29 Replies

How to interface with AutoCAD from Python?

I've the following AutoLISP code

(defun graph ( pts sls tls )
(   (lambda ( l )
        (foreach x l (text (cdr x) (itoa (car x)) 0.0 1))
        (mapcar
           '(lambda ( a b / p q r )
                (setq p (cdr (assoc a l))
                      q (cdr (assoc b l))
                      r (angle p q)
                )
                (entmake (list '(0 . "LINE") (cons 10 p) (cons 11 q) '(62 . 8)))
                (text
                    (mapcar '(lambda ( x y ) (/ (+ x y) 2.0)) p q)
                    (rtos (distance p q) 2)
                    (if (and (< (* pi 0.5) r) (<= r (* pi 1.5))) (+ r pi) r)
                    2
                )
            )            sls tls
        )
    )
    (mapcar 'cons (vl-sort (append sls tls) '<) pts)
)
)
(defun text ( p s a c )
    (entmake
        (list
           '(0 . "TEXT")
            (cons 10 p)
            (cons 11 p)
            (cons 50 a)
            (cons 01 s)
            (cons 62 c)
           '(40 . 2)
           '(72 . 1)
           '(73 . 2)
        )
    )
)

and the input is

(graph
   '((75 25) (115 45) (90 60) (10 5) (45 0) (45 55) (0 25))
   '(1 1 1 1 2 2 3 4 4 5 6)
   '(2 3 4 5 3 6 6 5 7 7 7)
)

The 2D geometry created from the above is exported as a dxf file from AutoCAD.

The actual input is generated in Python

pts = [(75, 25), (115, 45), (90, 60), (10, 5), (45, 0), (45, 55), (0, 25)]sls = [1 1 1 1 2 2 3 4 4 5 6]  
tls = [2 3 4 5 3 6 6 5 7 7 7]

I would like to know how to use the python data types as input and directly interface with AutoCAD from Python, save the AutoCAD output as a dxf file.

29 REPLIES 29
Message 2 of 30
Sea-Haven
in reply to: Anonymous

Did you google ? I dont use Python. But found examples.

 

#Get running instance of the AutoCAD applicationacad = comtypes.client.GetActiveObject("AutoCAD.Application")

 

Message 3 of 30
Anonymous
in reply to: Sea-Haven

Yes, I did.

 

I found this library https://pyautocad.readthedocs.io/en/latest/usage.html

 

But I don't understand how to run the above code after doing pip install pyautocad

Message 4 of 30
hak_vz
in reply to: Anonymous

You have to rewrite your script how is stated in your link.

Miljenko Hatlak

EESignature

Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.
Message 5 of 30
Anonymous
in reply to: hak_vz

Thank you.

 

After installing pyautocad I did

from pyautocad import Autocad, APoint

Now I am not sure how to evaluate these AutoCAD expressions in Python.

For instance, the inputs are Python tuples

(graph
   '((75 25) (115 45) (90 60) (10 5) (45 0) (45 55) (0 25))
   '(1 1 1 1 2 2 3 4 4 5 6)
   '(2 3 4 5 3 6 6 5 7 7 7)
)

. Should I convert each tuple to AutoCAD point using

p = APoint(x, y)

 And I am not sure how to proceed from here after generating the input data as autocad points. It's not clear to me how the commands in function 

defun graph ( pts sls tls )

 have to be modified. Could you please elaborate a bit on this? 

 

 

Message 6 of 30
hak_vz
in reply to: Anonymous

Sorry I cant help you with this. Whole function has to be written in pyautocad.

 

Miljenko Hatlak

EESignature

Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.
Message 7 of 30
Anonymous
in reply to: Anonymous

I'd be happy to know if there are other suggestions

Message 8 of 30
hak_vz
in reply to: Anonymous

https://stackoverflow.com/questions/48794935/batch-run-autolisp-with-python 

Miljenko Hatlak

EESignature

Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.
Message 9 of 30
Anonymous
in reply to: hak_vz

Thank you, the python code is helpful. I'd like to ask for a few clarifications

 

acad = GetActiveObject("AutoCAD.Application.20")

I would like to know if the AutoCAD application (GUI) must be open beforehand for GetActiveObject to work.

 

I understand 

#4- Construct the AutoLISP expression that loads AutoLISP files
    command_str = '(load ' + '"' + lispfile + '")' + " "

    #5-Execute the AutoLISP expression
    print "Sending AutoLISP Expression ..."
    print "Expression: " + command_str
    doc.SendCommand("(setq *LOAD_SECURITY_STATE* (getvar 'SECURELOAD)) ")
    doc.SendCommand("(setvar \"SECURELOAD\" 0) ")
    doc.SendCommand(command_str)
    doc.SendCommand("(setvar \"SECURELOAD\" *LOAD_SECURITY_STATE*) ")
    print "AutoLISP Expression is successfuly sent"
    print "########"

loads lisp file . But I don't understand how the input arguments have to  be passed

Message 10 of 30
Anonymous
in reply to: Anonymous

input:

(graph
'((75 25) (115 45) (90 60) (10 5) (45 0) (45 55) (0 25))
'(1 1 1 1 2 2 3 4 4 5 6)
'(2 3 4 5 3 6 6 5 7 7 7)
)

 

I'd like to request for clarifications on the same.

Message 11 of 30
hak_vz
in reply to: Anonymous

As I told before, have no experience with it.

I guess Acad should be started.

After you load a script try to add

doc.SendCommand("
(graph
'((75 25) (115 45) (90 60) (10 5) (45 0) (45 55) (0 25))
'(1 1 1 1 2 2 3 4 4 5 6)
'(2 3 4 5 3 6 6 5 7 7 7)
)
 ")

Miljenko Hatlak

EESignature

Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.
Message 12 of 30
Anonymous
in reply to: Anonymous

Generate a script file and launch it in AutoCAD.

For each drawing, in python write the following lines into a .scr-file (with your files, pts, sls and such of course):

open
c:\files\drawing.dwg
(load "c:\\lisps\\graph.lsp")
(graph 
'((75 25) (115 45) (90 60) (10 5) (45 0) (45 55) (0 25)) 
'(1 1 1 1 2 2 3 4 4 5 6)
'(2 3 4 5 3 6 6 5 7 7 7)
)
saveas dxf 16
c:\files\drawing.dxf
close

 
Just concatenate all into same .scr-file.
To convert tuples and lists to string:

def iter_to_lisp_string (list_or_tuple):
  return "(" + " ".join(map(str,list_or_tuple)) + ")"

pts_string = "'" + iter_to_lisp_string(map(iter_to_lisp_string , [(75, 25), (115, 45), (90, 60), (10, 5), (45, 0), (45, 55), (0, 25)]))
sls_string = "'" + iter_to_lisp_string([1, 1, 1, 1, 2, 2, 3, 4, 4, 5, 6])
tls_string = "'" + iter_to_lisp_string([2, 3, 4, 5, 3, 6, 6, 5, 7, 7, 7])

graph_command_string = iter_to_lisp_string(["graph", pts_string, sls_string, tls_string])


To launch script from powershell, issue command

<path to acad.exe> /b <path to script.scr>

For example (question marks in place of spaces):

C:\Program?files\AutoDesk\AutoCAD?2018\acad.exe /b c:\files\script.scr

To launch from python, I believe you have to call subprocess similarly to above, but I'm not sure.

Message 13 of 30
Anonymous
in reply to: Anonymous

Thank you, but I am really looking for a way to do launch it from python

Message 14 of 30
Sea-Haven
in reply to: Anonymous

This is VBA but would be similar for python if Autocad is not running then open it.

 

Look at post #2 also.

 

 

'Check if AutoCAD application is open. If is not opened create a new instance and make it visible.
    On Error Resume Next
    Set acadApp = GetObject(, "AutoCAD.Application")
    If acadApp Is Nothing Then
        Set acadApp = CreateObject("AutoCAD.Application")
        acadApp.Visible = True
    End If

 

 

Message 15 of 30
Anonymous
in reply to: Anonymous

Hi, 

 

could you please explain a bit on 

def iter_to_lisp_string (list_or_tuple):
  return "(" + " ".join(map(str,list_or_tuple)) + ")"

It is not clear to me why this function is used. I've written the rest to .scr file from python 

Message 16 of 30
Anonymous
in reply to: Anonymous

It is just a helper function to convert python tuples and lists into a format that autolisp understands. [(75,25),...] into "((75 25) ...)", [1,1,...] into "(1 1 ...)"

 

graph_command_string is the "(graph ... ... ...)" part of the .scr, you may write it to the script or send the command to autocad, I think that would also work.

 

You don't need to use it if you like to do the conversion from tuples and lists into lisp lists any other way.

Message 17 of 30
Anonymous
in reply to: Anonymous

@Anonymous  @Sea-Haven 

 

I've put together the following based on the suggestions

 

"""
This code passes inputs from python to autocad
ref: https://stackoverflow.com/questions/48794935/batch-run-autolisp-with-python
ref: https://forums.autodesk.com/t5/visual-lisp-autolisp-and-general/how-to-interface-with-autocad-from-python/m-p/9768816/highlight/false#M404952
"""

import comtypes.client
from comtypes import COMError
from comtypes.client import CreateObject, GetModule, GetActiveObject

from settings import\
GRAPH_LISP_FILE,\
GRAPH_SRC_FILE,\
GRAPH_DWG_FILE,\
GRAPH_DXF_FILE


def write_src(graph):
with open(GRAPH_SRC_FILE, 'w') as outfile:
outfile.write("open\n" +
f"{GRAPH_DWG_FILE}" + "\n"
rf'(load "{GRAPH_LISP_FILE}")' + "\n"
f"{graph}\n" +
"saveas dxf 16\n" +
rf"{GRAPH_DXF_FILE}" +"\n"+
"close"
)
pass


def iter_to_lisp_string (list_or_tuple):
return "(" + " ".join(map(str, list_or_tuple)) + ")"


if __name__ == '__main__':

pts_string = "'" + iter_to_lisp_string(map(iter_to_lisp_string, [(75, 25), (115, 45), (90, 60), (10, 5), (45, 0), (45, 55), (0, 25)]))
sls_string = "'" + iter_to_lisp_string([1, 1, 1, 1, 2, 2, 3, 4, 4, 5, 6])
tls_string = "'" + iter_to_lisp_string([2, 3, 4, 5, 3, 6, 6, 5, 7, 7, 7])

graph_command_string = iter_to_lisp_string(["graph", pts_string, sls_string, tls_string])
write_src(graph=graph_command_string)

try:
acad = GetActiveObject("AutoCAD.Application")
print("AutoCAD is Active")
except(OSError, COMError): # If AutoCAD isn't running, run it
acad = CreateObject("AutoCAD.Application", dynamic=True)
print("AutoCAD is successfuly Opened")

 

But the following error occurs

_ole32.CoCreateInstance(byref(clsid), punkouter, clsctx, byref(iid), byref(p))
File "_ctypes/callproc.c", line 935, in GetResult
OSError: [WinError -2146959355] Server execution failed

 

I'd like to know how to solve this error and how to proceed after this and send commands to AutoCAD.

 

Many thanks,

Deepa

 

Message 18 of 30
Anonymous
in reply to: Anonymous

Hi All, The error doesn't occur if I manually lauch the AutoCAD application.

Message 19 of 30
Anonymous
in reply to: Anonymous

I checked now, AutoCAD script can be launched without com by using subprocess:

import subprocess

subprocess.run(["C:\\Program Files\\Autodesk\\AutoCAD 2018\\acad.exe", "/b", "D:\\test\\asdf.scr"])

# or prior to python 3.5

subprocess.call(["C:\\Program Files\\Autodesk\\AutoCAD 2018\\acad.exe", "/b", "D:\\test\\asdf.scr"])

 

Path to acad.exe, /b is commandline switch for running a script and after that is your script file.


Python will resume after AutoCAD is closed, so for the last file you want to process, write "quit" instead of "close" to the .scr. Otherwise AutoCAD will stay open and python cannot resume, because it sees the subprocess is still running.  If you always process one drawing at a time, just replace "close" with "quit" in write_scr.

Message 20 of 30
Anonymous
in reply to: Anonymous

Thank you, I tried


pts_string = "'" + iter_to_lisp_string(map(iter_to_lisp_string, [(75, 25), (115, 45), (90, 60), (10, 5), (45, 0), (45, 55), (0, 25)]))
sls_string = "'" + iter_to_lisp_string([1, 1, 1, 1, 2, 2, 3, 4, 4, 5, 6])
tls_string = "'" + iter_to_lisp_string([2, 3, 4, 5, 3, 6, 6, 5, 7, 7, 7])

graph_command_string = iter_to_lisp_string(["graph", pts_string, sls_string, tls_string])
write_src(graph=graph_command_string)

import subprocess

subprocess.run(["C:\\Program Files\\Autodesk\\AutoCAD 2019\\acad.exe", "/b", "E:\\df\\graph.scr"])


This opens the AutoCAD application, but the command in .src isn't sent. It just opens the drawing file. I
also tried via com

 

pts_string = "'" + iter_to_lisp_string(map(iter_to_lisp_string, [(75, 25), (115, 45), (90, 60), (10, 5), (45, 0), (45, 55), (0, 25)]))
sls_string = "'" + iter_to_lisp_string([1, 1, 1, 1, 2, 2, 3, 4, 4, 5, 6])
tls_string = "'" + iter_to_lisp_string([2, 3, 4, 5, 3, 6, 6, 5, 7, 7, 7])

graph_command_string = iter_to_lisp_string(["graph", pts_string, sls_string, tls_string])
write_src(graph=graph_command_string)

try:
acad = GetActiveObject("AutoCAD.Application")
print("AutoCAD is Active")
except(OSError, COMError): # If AutoCAD isn't running, run it
acad = CreateObject("AutoCAD.Application", dynamic=True)
print("AutoCAD is successfuly Opened")

#3- Open the drawing file
print("Opening Drawing File ...")
doc = acad.Documents.Open(GRAPH_DWG_FILE)
print("Drawing is successsfuly Opened")

# 4- Construct the AutoLISP expression that loads AutoLISP files
command_str = graph_command_string # '(load ' + '"' + graph_command_string + '")' + " "

# 5-Execute the AutoLISP expression
print("Sending AutoLISP Expression ...")
print("Expression: " + command_str)
doc.SendCommand("(setq *LOAD_SECURITY_STATE* (getvar 'SECURELOAD)) ")
doc.SendCommand("(setvar \"SECURELOAD\" 0) ")
doc.SendCommand(command_str)
doc.SendCommand("(setvar \"SECURELOAD\" *LOAD_SECURITY_STATE*) ")
print("AutoLISP Expression is successfuly sent")

#6- Save and Close the drawing file and AutoCAD application
doc.Save()
doc.Close()
acad.Quit()

print("Process Finished")

 This sends the command, I can view the command in the command line but creates the drawing only after I manually hit enter. I don't want to do this manually.

 

Could you please let me know how to create the dxf file with drawing automatically?

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Forma Design Contest


AutoCAD Beta