Hello everyone,
I recently managded to create my very first Lisp routine, a little simple but I would have not been able to do this without all of your help.
Now that I have created this lisp and I have a command alias for it, I thought why should I open every single file and run the command? When there should be a way to have my Routine run on a full set of drawings...
Now... Does anybody here know what the best way to do this is? Your help is very much appreciated.
Here is my code pretty much all it does is run other custom commands in my start up suite.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QuickPlot
(defun c:QP ( / )
(command "-vbarun" "SavedPath" "-XREF" "RELOAD" "*")
(command "Purge" "All" "*" "no")
(command "AUDIT" "Y")
(c:XS_AD)
(c:XS_plotprep)
(c:XS_PF)
(command "QSAVE" "Close")
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;End of command
Thanks,
Victor
There are two different ways to batch run a LISP on multiple drawings.
The most advanced way is through ObjectDBX, but in short and without going into detail that means your LISP should've been written with VL* commands and using the application and document ActiveX objects.
Your LISP isn't, so in this case the only way to run it on multiple drawings would be to build and use a SCRIPT.
Your script would look something like this (assuming your LISP is in the startup suite):
.OPEN drawing1.dwg C:QP .OPEN drawing2.dwg C:QP ... ...
https://www.google.nl/search?q=autocad+script&oq=autocad+script
There are also multiple tools available to help you generate script files based on file and/or folder selection.
c:QP will possibly fail (c:QP) will work. There are vairious ways to make a file list using old fashioned DOS commands from windows CMD option
Dir *.dwg /s /b > dwglist.txt
Then I use Word and take advantage of the ability to replace end of line which is ^p so
replace ^p with Open ^p
then ^p ^p(c:QP)^p
dwg1 .. dwg2 etc becomes
open dwg1
(c:qp)
open dwg2
(c:qp)
Hello,
I don't have the knowledge to translate this from lisp to any other language.
Actually I'm trying to figure this one out which seems to be pointed in the right direction 🙂
Is there anything that I would need to edit on this one?
Dir *.dwg /s /b > dwglist.txt *Should I replace Dir with the folder path*
Then I use Word and take advantage of the ability to replace end of line which is ^p so *I would delete this*
replace ^p with Open ^p
then ^p ^p(c:QP)^p
dwg1 .. dwg2 etc becomes*And delete this*
open dwg1
(c:qp)
open dwg2
(c:qp)
I'm thinking this dwg 1 and dwg 2 will be a loop so that it will process all files within a folder?
So mine would be something like this?
Dir *.dwg /s /b > dwglist.txt
replace ^p with Open ^p
then ^p ^p(c:QP)^p
open dwg1
(c:qp)
open dwg2
(c:qp)
And finally what extension will this file be? would it be a .bat file?
Thanks for your help! 🙂
That ain't necessarily so.
With SDI off you can have a blank drawing find and open an unlimited number of other drawings (just one at a time will do) and have acaddoc.lsp do all the grunt work. I did it years ago for over 13,000 drawings in various branches of a directory tree for Philadelphia Gas Works.
John F. Uhden
Hello,
That sounds more complex that would know how to handle.
What do you mean by SDI off and where could I find information on acaddoc.lsp to run this lisp on multiple drawings?
Thanks,
Victor
SDI is a term we use for "Single Document Interface." It is the opposite of MDI ("Mutiple Document Interface").
With SDI off (0), AutoCAD can open multiple documents in the same session.
A recursive function can call (vl-directory files ...) to find all the drawings in a folder with subfolders and store them in a list, and then each one is opened, which automatically loads acaddoc.lsp which can perform a plethora of operations and save and close, which reverts focus to the original drawing so it can continue to process the list of drawings.
John F. Uhden
Give SmartPurge from JTB World a shot. You'll need a script, but it should be an easy one, just two lines:
(c:qp) qsave <blank line>
Save it as qp.scr
or lose the function and save it as a new lisp, load that one into SmartPurge:
(command "-vbarun" "SavedPath" "-XREF" "RELOAD" "*") (command "Purge" "All" "*" "no") (command "AUDIT" "Y") (c:XS_AD) (c:XS_plotprep) (c:XS_PF) (command "QSAVE" "Close")
That was it'll load the list and run it since there is no need to invoke the command.
Hi,
Thanks again for your help.
working with a script would require to load every time manually right? I will look into the smart purge application you have mentioned.
Victor.
The SmartPurge application allows you to select a group of drawings, then run a script or lisp on them all one after another automating the process. You can even set a timer so that the process kicks off at a time you specify so that you can leave the office and let it do it's thing running your script/lisp on all of the selected drawings.
I agree with @john.uhden I batch process files using a temporary acaddoc.lsp file in a working directory.
@DannyNL, no, there's a third way easier way.
Create a list of files
Set SDI to 1
Make sure LISPINIT is off (0)
& (file)open, edit & save each drawing inside the list. (or load a lisp with each to do the 'edit')
See the other topic for my example code:
edit: I'll just add it here, too...
(defun C:MF (/ filelist file) (setq filelist (list "C:/Lisp/TestDWG/TT049-1ARK03-SET.dwg" "C:/Lisp/TestDWG/TT049-1ARK04-SET.dwg" "C:/Lisp/TestDWG/TT049-1ARK05-SET.dwg" "C:/Lisp/TestDWG/TT049-1ARK06-SET.dwg" ) ) (setvar "SDI" 1) (setvar "LISPINIT" 0) (foreach file filelist (command "_.fileopen" file) (command "Zoom" "e") (command "Qsave") ) )
This will do the job.
Of course there are many ways to create the list with filenames, and the (command ...) functions are just for example. you can run ANY lisp code on each drawing.
Hi Roland.r71
What you have shared seems very interesting, however I have a question. When you say create a list of files would I have to manually enter the names on the code?
Also this portion of the code I don't really understand if it is written in a template way to replace with real paths and drawing names?
I believe since I have standard drawing names I could add them all to the list but when I need to plot 10 drawings I don't want to get an error because the one of the drawing names was not found,
Again thanks for all the help and I'm sorry about all the questions! 🙂
@AVFx1410 wrote:Hi Roland.r71
What you have shared seems very interesting, however I have a question. When you say create a list of files would I have to manually enter the names on the code?
Only if you want to
As I said, there are many ways to create such a list.
Especially if you use DOSlib (a very usefull Autocad Runtime eXtention)
The easiest way would be to read all files from a single directory.
I have a function that does just that, optionally includes sub-directories. However, it requires DOSlib.
note: you will still need to ask for a directory first (unless its always the same) & suply this directory to the function.
(defun get_files ( dr rc / dt tl fp i l filelist) ; Takes a path and 1 for recursive (nil or 0 if not), returns list of files ; dr = Directory [ Drive: | \\server] \path\to\files ; rc = Recursive [ 1 = yes ] ; filelist = List of files (including full path) to be returned (setq filelist nil) (if (= rc 1) ; Include subdirs (progn ; Get the directory tree (setq dt (DOS_DIRTREE dr)) (setq i 0) (while (< i (length dt)) ; get the drawings for each (sub)directory' (setq tl (DOS_DIR (strcat (nth i dt) "*.dwg"))) (setq l 0) (while (< l (length tl)) (setq fp (strcat (parse_path (nth i dt)) (nth l tl))) (setq filelist (append filelist (list fp))) (setq l (1+ l)) ) (setq i (1+ i)) ) ) ; Current dir only (progn ; get the drawings for current directory (setq tl (DOS_DIR (strcat dr "*.dwg"))) (setq i 0) (while (< i (length tl)) (setq fp (strcat (parse_path dr)(nth i tl))) (setq filelist (append filelist (list fp))) (setq i (1+ i)) ) ) ) filelist )
(defun parse_path (path2Filename / temp i)
; takes path, changes \ to /
(setq i 1 temp "")
(repeat (strlen path2Filename)
(if (= (substr path2Filename i 1) "\\")
(setq temp (strcat temp "/"))
(setq temp (strcat temp (substr path2Filename i 1)))
)
(setq i (1+ i))
)
temp
)
Also this portion of the code I don't really understand if it is written in a template way to replace with real paths and drawing names?
Yes, it is just an example you need to replace with 'hardcoded' paths & filenames, -OR- code like above, that will allow the user to select the files/directories to process (& create a list of those)
I believe since I have standard drawing names I could add them all to the list but when I need to plot 10 drawings I don't want to get an error because the one of the drawing names was not found,
Besides not being found, files can be read-only or open by another user. You might need to check all that to properly close & open files to prevent errors.
I have a function for that too, but I've been working on that part of code for a while, to rewrite it for easier sharing. Still need to finnish that.
Again thanks for all the help and I'm sorry about all the questions! 🙂
No problem. Happy to help
It turned out to be easy to find the file-finding function (because I use ZTree).
I'm sure it could be a lot sleeker, but though it's about 14 years old, I'm pretty sure it still works.
It creates a list of all DWG files in a given path including subdirectories.
;;------------------------------------------------------------------------------------- ;; Function to build a list of drawings found in the specified path and subdirectories:
;; By John Uhden, c.2004 (defun @find_dwgs (path / spec files spaces dirs @dirs)
(vl-load-com) (cond ((or (/= (type path) 'STR)(= path "")) (setq path (strcase (vl-filename-directory (findfile (car (vl-directory-files "" "*.*" 1)) ) ) ) ) ) ((wcmatch path ",*/,*\\")) (1 (setq path (strcat path "\\"))) ) (setq spec "*.dwg") (setq spaces " ") (defun @dirs (path / dirs found) (princ (strcat "\rSearching " path (substr spaces (strlen path)))) (princ) (and (setq found (vl-directory-files path spec 1)) (setq found (mapcar (function (lambda (x)(strcat path x))) found)) (setq files (append files found)) ) (and (setq dirs (vl-directory-files path "*.*" -1)) (setq dirs (vl-remove-if (function (lambda (x)(vl-position x '("." "..")))) dirs) dirs (mapcar (function (lambda (x)(strcat path x "\\"))) dirs) ) ) (foreach dir dirs (@dirs dir)) ) (terpri) (@dirs path) (reverse files) )
Example: (@find_dwgs "c:/projects")
John F. Uhden
@roland.r71 wrote:@DannyNL, no, there's a third way easier way.
Create a list of files
Set SDI to 1
Make sure LISPINIT is off (0)
& (file)open, edit & save each drawing inside the list. (or load a lisp with each to do the 'edit')
Oops....yes, of course you are right.
Sometimes you take some things for granted that you forget
As its probably going to take a while (before i find the little time i need to finnish rewriting)
I might as well share the old files, as far as they work on their own (i did use a modular approach)
& on the selection part i hardly had to change a thing, and i did recently update some of the files, so...
I have a function (scrGenFiles) to create a list of files to process, in prety much any way possible.
It uses a global variable to store the list, instead of returning it. I did that to preserve memory (on BIG lists) amongst others.
As it can save/load a list, you can even edit the list with notepad, or read a directory to a file (using DOS (cmd)) make a few changes and load that for further use.
I did my best to make it as flexible and complete as possible.
...for that i did need to use DOSlib though. In fact, this is what it was made for
I don't have many functions requiring DOSlib, but this is definately their "mother". I've tried to do without on several attempts, but although some can be replaced using ACET or ActiveX and such there are no alternatives for all of its functions. (afaik)
I'll attach the lisp & dcl files etc. to do the selection in my next post.
It should be noted that it does require a few other (common) functions, i'll need to collect & a INI file + a few globals (for locations / directories).
These files come from what used to be my scriptGenerator, as i used to do this by using scripts in the past.
(as i was unaware it could be done without)
The first step in the process would be to ask the user what lisp file should be loaded with each drawing.
& what to do in various situations. (skip read-only files or not, save changes or not, log files or not, etc.)
& where to save the *.scr file
That part is not included here, as it is specific for using a script.
The second step would be to select the files. The part we are talking about.
In the finall step it would ask for confirmation to start. At which point it would generate & execute the script. Again, this part is specific for using a script.
During the first part, a few globals get set which are important for the file selection.
I'll add that code right here:
; By default it is set to use subdirectories of the main scrGen path set. ; In case this is a shared network location, you should set the location of ; the DATA directory and scrGen.ini file to a local path, or use a user specific ; network location, to avoid conflicts. ; Set path to this script - NOTE: use either \\ or / instead of \ (setq *scrGen_files* "c:/Lisp/scrGen/") ; Paths to the scrGen.ini config file. Must be writeable (setq *scrGen_ini* (strcat *scrGen_files* "scrGen.ini")) ; Paths to the scrGen.dcl dialog file. (setq *scrGen_dcl* (strcat *scrgen_files* "scrGen.dcl")) ; Set path for data files. Must be writeable (see Note in header!) ; Used for storing logfile & filelist (setq *scrGen_data* (strcat *scrGen_files* "DATA/")) ; set path to scrGen modules (setq *scrGen_mods* (strcat *scrGen_files* "MODULES/")) ; Optional path to be used to find/load doslib (setq *DLpath* "C:/Lisp/DOSLIB/")
Next you need a few common functions, for loading DOSlib (on any version of acad (each has it's own .arx name!)), changing paths ( \ to /) & to get the read-only attribute. (the DOSlib function used changed its output from one version to the next. This will work with both) - these are inside "scrGenCommon.lsp"
Then you'll need the "scrGenFiles.lsp" for selecting the files,
Which in turn needs the "scrGen.dcl" file for the scrGenFiles dialog.
Last but not least, you need a scrGen.ini file, for storing settings.
Here you can set the options for filehandling manually (as i did not include the first part where these can be set using a dialog)
As i can attach only 3 files, i'll add the ini as code.
Note: Some of it is obsolete, as there's no script generator in this case, but i just added the complete thing.
; ============================================================================== ; *** AutoCAD scrGen v3.0 *** ; Copyleft ;) 2004-2018 | Roland Rothenhöfer ; ============================================================================== ; Configuration file ; ------------------------------------------------------------------------------ [config] ; ------------------------------------------------------------------------------ ; Last used *.lsp file, to run on selection ; STRING : [Drive: | //Network]/path/to/file.ext lispFile=C:/Lisp/test/zea.lsp ; logfile for skipped files ; STRING : [Drive: | //Network]/path/to/file.ext logFile=C:/Lisp/scrGen/DATA/scrGen_log.csv ; Location of lisp file with fileopen function ; STRING : [Drive: | //Network]/path/to/file.ext openFun=C:/Lisp/scrGen/MODULES/scrGenOpen.lsp ; Location to create the script ; STRING : [Drive: | //Network]/path/ scrPath=C:/Lisp/scrGen/DATA/ ; Show progression bar ; BOOLEAN : 0 = no, 1 = yes progBar=1 ; log skipped filenames ; BOOLEAN : 0 = no, 1 = yes logSkip=1 ; number of skipped files ; INTEGER NumSkip=0 ; warn user when file not found ; BOOLEAN : 0 = no, 1 = yes warn_notfound=1 ; warn user when file open (network) ; BOOLEAN : 0 = no, 1 = yes warn_fileopen=1 ; warn user when file Read-Only ; BOOLEAN : 0 = no, 1 = yes warn_readonly=1 ; don't open files (as) read-only ; BOOLEAN : 0 = no, 1 = yes skip_readonly=0 ; don't save changes to file ; BOOLEAN : 0 = no, 1 = yes skip_savefile=0 ; Initial Single Document Mode ; BOOLEAN : 0 = off, 1 = on SDI =0 ; Initial FILEDIA mode ; BOOLEAN : 0 = off, 1 = on FILEDIA =1 ; ------------------------------------------------------------------------------ [scrGenFiles] ; ------------------------------------------------------------------------------ ; Last used directory to add file(s) ; STRING : [Drive: | Network]\path\to\files\ lastdir=C:\acad_test\dwg\ztm2\ ; Last used directory to add files in directory (tree) ; STRING : [Drive: | \\Network]\path\to\files\ userpath=C:\acad_test\dwg\ztm2\ ; DOS style wildcard for filenames, when adding files in directory (tree) ; STRING : DOS style filename filter. *=all files ( with the extension : .DWG and/or .DXF ) wildcard=* ; Whether to include files inside sub-directories ; BOOLEAN : 0 = no, 1 = yes recursive=0 ; Whether to automatically order files (alphanumeric) ; BOOLEAN : 0 = no, 1 = yes autosort=0 ; Whether to "remember" the list. This will save the list on exit to DATA\scrGenFiles.lst ; the next time scrGenFiles is called, this list will be (re)loaded ; BOOLEAN : 0 = no, 1 = yes autosave=1 ; Whether to allow duplicate (2 or more times the same) file names ; BOOLEAN : 0 = no, 1 = yes noDuplicate=1 ; Whether to allow '_recover' files ; BOOLEAN : 0 = no, 1 = yes noRecover=1 ; Which filetype(s) to include ; INTEGER : 1 = DWG, 2 = DXF, 3 = Both filetype=1
It looks like you've gotten some good answers. If you could recode the VBA parts, a better option than all of the previous suggestions, however is for you to download ScriptPro from Autodesk and to use it to run the AutoCAD Core Console. ObjectDBX is not as good as the core console at processing drawings. ObjectDBX was as good as it got 6 years ago. The core console is much faster than batch processing via the user interface. Scriptpro provides an easy interface to pick which files to process, and to select a simple command script that contains the code to process for each drawing.
Here is a link that contains a download package for scriptpro:
Here is a link that contains an explanation of the core console:
@dbroad wrote:It looks like you've gotten some good answers. If you could recode the VBA parts, a better option than all of the previous suggestions, however is for you to download ScriptPro from Autodesk and to use it to run the AutoCAD Core Console. ObjectDBX is not as good as the core console at processing drawings. ObjectDBX was as good as it got 6 years ago. The core console is much faster than batch processing via the user interface. Scriptpro provides an easy interface to pick which files to process, and to select a simple command script that contains the code to process for each drawing.
Here is a link that contains a download package for scriptpro:
Here is a link that contains an explanation of the core console:
If only it was still supported/updated & the installer would be compatible with modern day windows ... yes