How to interface with AutoCAD from Python?

How to interface with AutoCAD from Python?

Anonymous
Not applicable
19,688 Views
30 Replies
Message 1 of 31

How to interface with AutoCAD from Python?

Anonymous
Not applicable

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.

0 Likes
Accepted solutions (2)
19,689 Views
30 Replies
Replies (30)
Message 2 of 31

Sea-Haven
Mentor
Mentor

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

 

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

 

0 Likes
Message 3 of 31

Anonymous
Not applicable

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

0 Likes
Message 4 of 31

hak_vz
Advisor
Advisor

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.
0 Likes
Message 5 of 31

Anonymous
Not applicable

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? 

 

 

0 Likes
Message 6 of 31

hak_vz
Advisor
Advisor

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.
0 Likes
Message 7 of 31

Anonymous
Not applicable

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

0 Likes
Message 8 of 31

hak_vz
Advisor
Advisor

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.
0 Likes
Message 9 of 31

Anonymous
Not applicable

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

0 Likes
Message 10 of 31

Anonymous
Not applicable

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.

0 Likes
Message 11 of 31

hak_vz
Advisor
Advisor

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.
0 Likes
Message 12 of 31

Anonymous
Not applicable

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.

0 Likes
Message 13 of 31

Anonymous
Not applicable

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

0 Likes
Message 14 of 31

Sea-Haven
Mentor
Mentor

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 31

Anonymous
Not applicable

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 

0 Likes
Message 16 of 31

Anonymous
Not applicable

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.

0 Likes
Message 17 of 31

Anonymous
Not applicable

@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

 

0 Likes
Message 18 of 31

Anonymous
Not applicable

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

0 Likes
Message 19 of 31

Anonymous
Not applicable

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.

0 Likes
Message 20 of 31

Anonymous
Not applicable

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?

0 Likes