comp.cad.autocad.AutoLISP FAQ
Title: comp.cad.autocad AutoLISP FAQ
Archive-name: CAD/autolisp-faq
URL:
http://xarch.tu-graz.ac.at/autocad/news/faq/autolisp.html
Version:
2.24
Last-modified:
"2000-04-25 09:55:21"
Posted-By:
Reini Urban rurban@sbox.tu-graz.ac.at
Posting
Frequency: monthly
Copyright:
see Appendix [A]
Welcome
to the comp.cad.autocad AutoLISP FAQ!
AutoLISP is a scripting language for AutoCAD, a well known CAD package.
This AutoLISP FAQ is posted to comp.cad.autocad, alt.cad.autocad and the
*.answers groups monthly.
Some AutoCAD FAQ's are at http://www.autodesk.com/support/autocad/
but not posted to comp.cad.autocad.
The contents and the samples apply to all releases of AutoLISP since
Release 10, including Visual Lisp, Vital Lisp and ACOMP.
There's no special AutoLISP newsgroup. Best are comp.cad.autocad or
autodesk.autocad.customization. Please don't bother comp.lang.lisp!
Source code of all functions in this FAQ is in FAQ-CODE.LSP (for
location see [A.1]).
Table
of Contents
[0] The Future of
AutoLISP? Should I learn it or VB instead?
[0.1] What changed with AutoCAD
2000? [new]
[0.2] We cannot create ARX
anymore? [new]
[1] Where can I
find AutoLISP routines on the Internet? [changed]
[1.1] Are the comp.cad.autocad
articles stored somewhere?
[1.2] Autodesk's SDK
[2] What are the
best books to learn AutoLISP?
[2.1] Online AutoLISP documents, Winhelp
[deleted]
[2.2] AutoLISP Coding Style
[3] How do I debug AutoLISP programs?
[3.1] Native AutoLISP debuggers
[3.2] Modular style, TRACE
[3.3] BREAK function, debug-print
[4] How can I protect my AutoLISP programs? Security [changed]
[4.1] Kelvinate
[4.2] Protect
[4.3] Kelvinate and Protect
[4.4] Convert
[4.5] ACOMP
[4.6] Vital LISP Professional
[4.7] Lisp2C
[4.8] Visual Lisp by Autodesk [changed]
[5] AutoLISP compilers
[5.1] ACOMP
[5.2] Vital LISP Professional
[5.3] Visual Lisp by Autodesk
[5.4] Better ones: Common Lisp and Scheme [new]
[6] AutoLISP editors and other tools
[6.1] AutoLISP editors
[6.2] Analyzers, Packager
and Parenthesis checkers [added]
[6.3] Pretty Printers
+ [7] AutoLISP problems and bugs [added]
[8] Sorting with AutoLISP
[9] Recursion
[10] Iteration with MAPCAR,...
[11] My LISPs aren't loading at startup anymore
[12] How to AUTOLOAD my programs?
[13] How can I pass a variable number of arguments to a
LISP function?
[14] How can I avoid stack overflows?
[15] (command "ROTATE3D") does not work! Why?
[16] Lisp programs operating over multiple drawings
[17] How to export Visual Lisp functions to
AutoLISP/AutoCAD?
part
2: Samples, code
[20] General Helper functions
[20.1] List manipulation
[20.2] string manipulation
[20.3] symbol->string
[20.4] AutoCAD entity access [changes]
[21] Sample Lisp Programs:
[21.1] Globally change text, polylines, layer utils, date
stamp
[21.2] Plot dialog from within Lisp. Using DDE or ActiveX [fixed]
[21.3] (entmod) and (entmake) Layers, without (command
"_LAYER"...)
[21.4] How to select multiple files in Lisp? (as in FILES -
Unlock) [new]
[21.5] Replace multiple blocks
[21.6] (vports), VIEWPORT entity, pixel conversion
[21.7] Select all visible objects: zoom coordinates
[21.8] How to write XYZ data of selected objects to a file?
[22] Block Attributes
[22.1] How to access block attributes?
[22.2] How to MODIFY block attributes? DATESTAMP.LSP
[22.3] How to UPDATE block attributes?
[22.4] How to ENTMAKE a Block Complex Entity in AutoLISP
[23] Polylines
[23.1] How to access polyline VERTICES?
[23.2] How to JOIN multiple lines to polylines?
[23.3] Change WIDTH of multiple polylines?
[23.4] Create a polyline or spline: with ENTMAKE or COMMAND
[23.5] How to calculate the LENGTH of polylines?
[23.6] How to revert the polyline direction?
[24] Circle/Arc Geometry: BULGE conversion, some
trigonometry
[25] DCL: listboxes with tabs or monotext font
[26] EED Extended Entity Data: Get and Store
[26.1] Select objects on their EED with (ssget
"X")
[26.2] Get EED from an object
[27] How to break a command in Lisp?
[28] How to decode ACIS internal geometry with Lisp?
--
[A] Disclaimer, Notes from the authors
+ [A.1] FAQ Locations
[B] Acknowledgements
[C]
Recent Changes
\n
[0]
The Future of AutoLISP? Should I learn it or VB instead?
AutoLISP will be definitely supported in future releases. VB was
introduced to simplify Office Automation: ACAD <-> Excel/Access
Both languages have advantages and disadvantages. You should have a look
at both. VB seems to be more graphical and
AutoLISP more logical. The object concept of VBA seems to be easier to
learn, but you cannot run commands like in AutoLISP.
The new VBA (>= R14.01) is extremely fast. See also [5.2].
The future of AutoLISP already is Visual Lisp. URL's: <http://www.autodesk.com/vlisp>,
<http://www.autodesk.com/develop/devres/visual/faq.htm>,
also [0.1] below.
[0.1] What changed with AutoCAD 2000? [new]
The name :) No, there's much more, but you may call it Release 2000, R15
(though 15 is the version number and not the release number), A2000 or
abbrevated A2K.
The new Visual Lisp kernel replaced the old xlisp-based AutoLISP kernel.
What problems should you expect with Visual Lisp in R2000? (only the bad news)
At <http://xarch.tu-graz.ac.at/autocad/docs/r2000-news.txt>
I compiled a white paper. Use the LCA to
check your lisps.
The major points are:
·
Stricter error checking on loading,
·
ACAD.LSP vs ACADDOC.LSP,
·
You cannot/need not compile to ARX anymore,
·
Incompatibilities AutoLISP - Visual LISP:
·
Lisp functions are atoms no lists anymore,
·
Protected symbols,
·
Better exception handling,
·
Pathname of the loaded VLX?,
·
vl-export-symbol -> vl-doc-set ...,
·
long acad symbol table names: EXTNAMES
·
ActiveX automation, Variants and SAFEARRAYs
·
FAS4 cannot be loaded on R14.
[0.2]
We cannot create ARX anymore? [new]
With AutoCAD 2000 you cannot do that anymore as with ViLL
or VLISP 4. Instead you compile to VLX (Visual Lisp Extension), which has
basically the same functionality as the old Visual Lisp/Vital Lisp ARX, with the
following differences:
·
You'll have to (load) the app. Before you had to (arxload)
it.
Pro: Initialization is easier.
The VLX doesn't abort completely on any error while loading. Before the whole
ARX crashed with mysterious errors.
Pro: VLX are much smaller
because they don't carry the whole Lisp environment, the VLRTS along. Instead
there's only one environment, VL.ARX, distributed with acad itself. So you can
ship much smaller applications.
Contra: With loaded VLX there's
no easy way t get the pathname of the app. Before it was possible with (arx) or
(vl-exe-filename)
·
VLX has the option of seperate or common namespaces. With
seperate ARX you had only the option of seperate namespaces (in fact completely
seperate lisp environments).
Pro: This means that you can now
choose the fastest and most secure compilation mode (LINK, DROP) and still keep
common namespaces. (most of my apps benefit from this. I seperated my apps into
one main module and several smaller ones)
Pro: ARX is only compatible per
release, thus completely incompatible! VLX is new and therefore compatible only
to newer releases (R16,...) but as lisp application it is by far more compatible
than a ARX app.
·
Loaded ARX apps with (arx) return the pathname, loaded VLX
apps with (vl-list-loaded-vlx) only a symbol, no path. This is a design flaw.
You don't need ARX modules anymore. This is a feature, no
bug.
[1]Where
can I find AutoLISP routines on the Internet?
The big AutoCAD tools sites are:
AutoCAD
Plugin Store by beyond.com.
<http://www.cadplugins.com/>
This is the by AutoDESK "officially recommended" tools site.
CADalog
- The AutoCAD Shareware Clearinghouse (Mike Clark)
<http://www.cadalog.com/>
The CAD Depot Formerly known as CADSyst (David Whynot)
<http://www.caddepot.com/>,
recently <http://www.tenlinks.com/CAD/News/041800tenlinks.htm
> bought by TenLinks.
They are specialized in AutoCAD related software and have
a very good AutoLISP collection. Other professional AutoLISP shareware sites
post their URL's to the newsgroup too.
Other relevant portal sites are [new]:
TenLinks <http://www.tenlinks.com/CAD/cad_news.htm>
and the UpFront <http://www.upfrontezine.com/>
EZine are the best CAD news services.
Autodesk started the portal site Point A <http://www.autodesk.com/pointa>.
Some other sites with AutoLISP collections are:
xarch
AutoCAD Info & Tools (Reini Urban)
<http://xarch.tu-graz.ac.at/autocad/>
(with search)
CADalyst
magazine code (compiled by "Hot Tip Harry" Art Liddle) [fixed]
<http://www.cadonline.com/code/>
The
CADshack (Jeff Foster)
<http://www.cadshack.com/lispfile.htm>
Owen
Wengerd
<http://www.manusoft.com>
Terry
Dotson [new]
<http://www.dotsoft.com/>
Vladimir
Nesterowsky [new]
<http://members.tripod.com/~vnestr/>
UCCB
AutoCAD and AutoLISP page (Paul Standing)
<http://ucad1.uccb.ns.ca/acad/cad.htm>
Theo
L.A. Groenenberg
<http://members.xoom.com/acadvice/autolisp.htm>
Lisp
Factory (Jay Garnett) [changed]
<http://www.enteract.com/~jgarnett/>
Rakesh
Rao - AutoCAD Tech Center [changed]
<http://www.4d-technologies.com/techcenter>
Old or broken links are:
AutoCAD
Tech Journal code (Peter Sheerin) [old]
<http://www.atj.com>
CADENCE
magazine code (Peter Sheerin) [old,
broken]
<ftp://ftp.mfi.com/pub/cadence/>
Dr.Lisp
Utilities (Alexander Medwedew) [broken]
<http://tribeca.ios.com/~compvent/>
McNeel's
lisp archive [broken]
<ftp://ftp.mcneel.com/lisp/>
Desi
Moreno [broken]
<http://www.invsn.com/desmos/autolisp.htm>
PIRS
Online
<http://www.insa.com/>
Henry
Francis [broken]
<http://www.ez-sys.net/~coopfra/>
SimTel
- Coast To Coast - Archive [fixed, very
old]
<http://www.simtel.net/simtel.net/msdos/autocad.html>
At <http://www.autodesk.com/support/autocad/>
there are documents from the Autodesk Product Support answering technical
questions. (Their FAQ's)
[1.1]
Are the comp.cad.autocad articles stored somewhere?
There is no comp.cad.autocad archive or such a thing, but
there are some search engines which store news articles. In particular:
<http://deja.com/usenet> - The biggest news archive.
<http://www.altavista.com/>
<http://www.altavista.com/cgi-bin/query?pg=aq&what=news>
<http://www.excite.com/>
<http://www.excite.com/search.gw?collection=news>
Phoaks - People Helping One Another Know Stuff - Automatic
Links Extractor [new]
<http://www.phoaks.com/phoaks2/newsgroups/comp/cad/autocad/index.html>
Some specific older news postings are also stored at <http://xarch.tu-graz.ac.at/autocad/news/contents.html>
[1.2]
Autodesk's SDK
Up to Release 12 a Software Development Kit was available
directly at Autodesk. The SDK2 was shipped with the international R12 for free.
It included a lot of ADS and AutoLISP source code and libraries.
From R13 on Autodesk provides a special developers
network, comparable to Microsoft's, the ADN. The CD's are comparable to the old
SDK but are more targeted to ObjectARX developers.
Contact your nearest Autodesk headquarter for becoming a member.
Some LISPs are at <http://xarch.tu-graz.ac.at/autocad/code/adesk/SDK2/>
In the US, ADN membership costs $600.00 per year. The CDs don't include any SDK per se,
but most of the stuff in the original SDKs is included in one form or another. (Owen)
[2]
What are the best books to learn AutoLISP?
AutoLISP: Programming for Productivity,
William Kramer, Autodesk Press,
ISBN 0-8273-5832-6
Essential AutoLISP,
Roy Harkow, Springer-Verlag,
ISBN 0-387-94571-7
AutoLISP in Plain English; A Practical Guide for Non-Programmers,
George O. Head, Ventana Press,
ISBN: 1566041406
"Maximizing AutoLISP"
Rusty Gesner, Tony and Mark
Middlebrook, Tony Tanzillo.
More at <http://www.group-a.com/~rusty/>
"AutoLISP Reference Manual"
by Autodesk Press.
Up to R12 there was a separate AutoLISP Reference book. Then AutoLISP became a
part of the Customization Guide for R13. From R14 on this guide is compiled as
Winhelp.
There are a lot of more AutoLISP books around.
Recommended general LISP books (not AutoLISP!) are:
ANSI Common Lisp, (Common
Lisp primer)
Paul Graham, Prentice Hall, ISBN
0-13-370875-6
Structure and Interpretation of Computer Programs, (high-level
Scheme)
H.Abelson, GJ. Sussman, J.
Sussman, MIT Press, ISBN 0-262-01153-0
"This undoubtedly one of
the best general computer books ever written."
LISP, 3rd Edition,
Patrick Henry Winston and
Berthold Klaus Paul Horn, Addison-Wesley Publishing Company, ISBN 0-201-08319-1
Looking at LISP,
Tony Hasemer, Addison-Wesley
Publishing Company, ISBN 0-201-12080-1
[2.1] Online AutoLISP documents, Winhelp [deleted in the posted version]
R14 ships with the complete
manuals converted into Winhelp.
Available AutoLISP Winhelp files
come with:
·
R14 (the whole bookset)
·
the Visual Lisp by Autodesk preview, see [5.3]
·
the old Visual Lisp editor (1.0 is free), see [1]
·
Vital LISP, (help also included in the demo), see [6.1]
For DOS there exists a memory
resident program called LISPHLP.EXE <ftp://xarch.tu-graz.ac.at/pub/autocad/lsp_tools/lisphlp.zip>
(activates on Ctrl-RightShift-R, from 1988)
LSPDOC: At http://xarch.tu-graz.ac.at/autocad/lsp_tools/#lspdoc
<http://xarch.tu-graz.ac.at/autocad/lsp_tools/> is a tool
available which automatically creates a Winhelp for LISP files.
[2.2] AutoLISP Coding Style
Most of the samples being
published by magazines or at various websites are written badly making the
AutoLISP learning process even harder for newbies. LISP is hard to read anyway
because of it's briefness and countless parentheses. Everybody is enforced to
write clear, readable code. Autodesk's samples are quite well written but
sometimes overdone. :)
Automatic pretty printers, or so
called beautifiers (see [6.3])
automatically format the code according to the standard.
On the R12 CD-ROM in the SDK2
ACG.DOC or at <http://xarch.tu-graz.ac.at/autocad/docs/acg.txt>
is an excellent Autodesk documentation about coding, commenting and intentation
standards to keep lisp code readable.
The most important points are:
·
Comment
your code. using ";;;" at row 1, ";;" inside the
code (indented) and ";" for trailing comments (at row 39)
·
Follow the indenting
standards as given by the pretty printers to be able to write better
structured code, which is more readable.
esp. for SETQ, DEFUN, IF, COND,
PROGN
·
Try to avoid global
variables. If you use them (for efficiency), to clarify, place asterics
around them in uppercase, i.e: *GLOBAL*
·
Don't forget to localize
your variables (behind "/" in the DEFUN parameter list). Only for
debugging purposes you may want to undefine them temporarly.
·
Name
protection: since AutoLISP provides no protected name space it's easy
to overwrite even system functions. Please use unique short prefixes, at least
when you publish or give away your code.
I use UR- for functions and UR:
for variables. The ADGE and adesk forces even 4 letter prefixes. Then your names
are safe from being overwritten by other kamikaze functions.
·
Always use the leading
underscore with any string (commands and options) given to COMMAND and OSNAP.
There are even enough commercial programs which do not work on international
versions. (command "_PEDIT" ss "_J") is better than (command
"PEDIT" ss "J")
·
Don't
do too much SETQ's: LISP was originally a functional language,
without any variables. There are enough constructs which work efficiently with
lists without the need of storing values intermediatly in symbols. (see code
samples [21]...)
But for readablility and debugging purposes you should always set symbols.
·
An old LISP rule is: Any
good function is not longer than 6 lines. (LISP is the second oldest
computer language, invented by John McCarthy at the MIT at 1958)
·
Prefer
CONS over APPEND: three CONS and one REVERSE is better than one
APPEND. For tricks with APPEND (omitting NIL) see esp. Serge's samples: i.e.
REMOVE at [20.1] or the style comparison
at [23.1])
·
use English
symbols and comments
·
Don't use T, MIN, MAX or LAST as symbols! These are system functions!
[3]
How do I debug AutoLISP programs?
[3.1]
There were three native AutoLISP debuggers:
·
Visual
Lisp and Vital LISP
Professional have it in the IDE (the best).
·
ACOMP
for R10 had one, free, you can still use it but then you've got only the R10
lisp functions, i.e. no WCMATCH function
·
Ld,
AutoLISP Debugger for R14, R13c4 and R12/Dos from Cz (free)
at <http://www.cadstudio.cz/ftp.htm>
See [5]
AutoLISP compilers
[3.2]
Modular style, TRACE
The best support you can have for debugging is write your
code in a well designed, modular style, pulling out distinct tasks into separate
functions and then liberally using nested function calls. This will allow you to
use the TRACE function as needed to locate any errors.
[3.3]
You may include BREAK functions and debug-print into your source code.
Examples:
;;; Debugging functions (defun break (s) (if *BREAK* (progn
(princ "BREAK (stop with )\nBREAK ")(princ s) (while (/= (setq s (getstring
"\nBREAK ")) "") (print (eval (read s))))))) ;bugfix from
v1.3! (defun dbg-print (s) ;accepts atoms and lists (if *DEBUG* (if (listp s)
(MAPCAR 'print s) (print s)))) (defun C:DEBUG () (setq *DEBUG* (not *DEBUG*))) ;switch
it on and off (defun C:BREAK () (setq *BREAK* (not *BREAK*))) (defun CONT () (setq
*BREAK* nil)) ;continue without any interruption ;;;Example (setq *BREAK* T *DEBUG*
T) (defun C:TEST () (foreach x '("1" "1.0" "1e-3")
(break "in foreach") ; stops evaluation if *BREAK* is on, you can ;
enter x and the value of x is printed ; until you enter Enter (setq x (atof x))
; this is some code which manipulates x (dbg-print x) ; this prints the new
value of x ; if *DEBUG* is on ) ) Command: TEST BREAK (stop with ) BREAK in
foreach BREAK x 1.0 BREAK (CONT) ; turn off the break nil BREAK 1.0 1.0 0.001
You may also turn off the debugging output with BREAK (setq *DEBUG* nil) to
continue in larger loops.
[4]
How can I protect my AutoLISP programs?
"You
really have to protect it? If you just want to share routines with your friends,
why not give them the code? Your code is protected anyway by copyright, even
implictly. Working with others can be a great way to get new ideas and lead to a
better application.
Some of the best utilities were improved by my friends or I have improved some
of my friends utilities." (Dennis)
[4.1]
Kelvinate
with KELV.EXE (on the R12 CD-ROM
or at the AutoLISP sites [1])
De-Kelvinate lisp's with any pretty printer.
But symbol names (functions and variables) will stay garbled and comments are
lost.
[4.2]
Protect
with PROTECT.EXE (on the R12
CD-ROM or at the AutoLISP sites [1])
Note that unprotectors exist. Free.
[4.3]
Kelvinate and Protect
First kelvinate it to make it
unreadable, then protect it. Free.
[4.4]
Convert
Shareware Lisp En-/Decryptor by
Maciej Lukasiewicz
With Convert encrypted "Protected Lisps" cannot be decrypted by other
programs, but by Convert it can.
[4.5]
ACOMP
AutoLISP compiler ACOMP.EXE, on
the R12 international release or at the AutoLISP sites. Free. More docs about
ACOMP are at <http://xarch.tu-graz.ac.at/autocad/bi4/>
See also [5.1]
AutoLISP compilers
[4.6]
Vital LISP Professional
<http://www.basissoftware.com/vill.htm>
Say "ViLL". Outdated. See [5.2]
AutoLISP compilers
[4.7]
Lisp2C
LISP to C converter, for
R12/R13/R14 Dos/Win (Watcom, Metaware, MSVC Libs)
You need to own such a C/C++ compiler.
<http://www.basic.si>
[4.8]
Visual Lisp by Autodesk
say "VLISP". The
Future. see [5.3]
FAS
Security: [changed]
There was recently a lengthy discussion about FAS security at both newsgroups.
Apparently FAS can be decompiled to readable source code, but this tool is not
available on the net yet. Rumors say that MNC files can also be decompiled for
years now but this doesn't exist the net either. Linked and dropped FAS/VLX (compiled
with Optimized/Internal) is similar to Kelvination. Symbol names, strings and
numbers are more insecure than algorithms.
Summary:
Serious encryption is only done with Vital LISP and its successors. Kelvinating
[4.1] makes LISP files unreadable and load faster. Protected [4.2] lisp files
can be easily decrypted. With Convert
-e$GUARD
encrypted AutoLISPs can be unprotected only with Convert.
[5]
AutoLISP compilers
There are three AutoLISP compilers, better ones could
maybe used in the future. Some Lisp and Scheme platforms already
do or will support ActiveX or just a simple FFI.
[5.1]
ACOMP
ACOMP was supported up to R12
for the international releases only. It is free. It is free, and doesn't work
with R13 nor with domestic R12/Win. It produces *.BI4 files and needs special
ACADL.EXP supplied as ACADLC.EXP. See <http://xarch.tu-graz.ac.at/autocad/bi4/>
The compiler warnings are more explicit on local symbols than ViLL/VLisp.
[5.2]
Vital LISP Professional
by Basis Software Inc. USA.
License-free runtime modules for R12/R13/R14 DOS/Windows/NT
Basis doesn't continue developing Vital Lisp anymore. See also [6.1]
and [4.6]
[5.3]
Visual Lisp by Autodesk
VLISP 4 (for R14), the successor
of Vital Lisp, is basically the same as ViLL 3.2. Only the GUI, some function
names and the docs changed: vill-
=> vlisp-, vlx- => vl- prefixes. Some vlax-
funcs have more hyphens.
With AutoCAD 2000 VLISP replaced the old
AutoLISP engine. See [0.1] VLX files are
packaged FAS files with optional DCL resources, used by R14/R15.
R15 FAS/VLX are incompatible with previous releases (FAS2 -> FAS4) because of
added language features (seperate namespaces).
[5.4]
Better ones: Common Lisp and Scheme
Native ARX exists for Corman
Common Lisp (a simple console),
COM support for Allegro Common Lisp 5, Lisp Works for Windows and in the future
for GambitC.
Via a FFI <http://xarch.tu-graz.ac.at/autocad/lisp/ffis.html>
("Foreign Function Interface") almost every lisp or scheme can
communicate with AutoCAD.
Little work is done with Corman Lisp and ACL5, currently one commercial product
uses ACL5 ("Design++" <http://www.dp.com/>
by Design Power)
See <http://xarch.tu-graz.ac.at/autocad/bi4/>
for more.
Summary:
AutoLISP compilers are bytecode compilers needing a runtime system. AutoCAD 2000
uses VLISP now, so the runtime system is included. You cannot create standalone
programs, though ViLL/Vlisp (<= R14) creates a stand-alone ARX. The variables
are encrypted.
[6]
AutoLISP editors and other tools
[6.1]
AutoLISP editors
Visual
Lisp by Autodesk
see [5.3]. The best and most recommended
tool. With AutoCAD 2000 it is included for free.
Emacs
for NT
Huge editor and quite hard to
learn but it's written and customizable in elisp, which is very similar to
AutoLISP. The mother of all editors. Free, for all platforms. Comes in two
flavors, XEmacs or GNU ntemacs.
AutoLisp Mode at <http://xarch.tu-graz.ac.at/autocad/lsp_tools/ntemacs.html>
Vital
LISP outdated by Visual Lisp. Not available anymore. See [5.2]
AutoLISP compilers
LispPad
AutoLISP Editor by Tony Tanzillo.
<http://ourworld.compuserve.com/homepages/tonyt/LispPad.htm>
LispLink 2000 [changed]
Commercial AutoLISP Editor with
Syntax Highlight, Parenthesis Checking, Project Manager, Dialog Preview, and
Support for Visual LISP Functions and FAS Compilation. <http://www.caelink.com/>
CodeMagic [new]
Freeware text editor with
AutoLISP syntax highlighting.
Old Stuff:
Visual
Lisp by WSSW
Old small Windows Lisp Editor.
Version 1.0 was even free. Don't mix it up with Visual Lisp, the new AutoLISP.
This is just a small editor. See [1]
WCEDIT
2.02
ADS editor for DOS R12, can
evaluate lisp code from within the editor, free.
See [1]
CODEKEY
old commercial DOS IDE, internal
pretty printer, protect, unprotect, kelvinator, <availability?>
ALLY
3.0 and CADET
Shareware Lisp Analyzer and
Editor.
See [6.2]
pred
free, small dos editor which
provides parenthesis highlighting.
At <ftp://xarch.tu-graz.ac.at/pub/autocad/lsp_tools/pred.zip>
A similar editor is ADE.
General customizable programming editors like MultiEdit
Pro 7, WinEdit, E!, TextPad, UltraEdit or PFE are widely used also.
They usually don't provide Lisp
syntax checking or pretty printing, but (some even regular expression)
multi-file search/replace and customizable syntax highlighting.
[6.2]
Analyzers, Packager and Parenthesis checkers
Parenthesis checkers should not be used anymore. Editors
should do the job. Analyzers generate a function cross-reference, the calling
and the reverse callers tree. Packagers are used to generate libraries from
various source files, copying all the needed functions. There's currently no
code-walker which can internationalize command strings, but with R15 came a lisp
analyzer (LCA).
VLISP's
[5.3] compiler analyzes (compile with full messages) and checks parens (Ctrl-Alt-C).
Reini's
AutoLISP Packager [new]
http://xarch.tu-graz.ac.at/autocad/lsp_tools/#Packager
<http://xarch.tu-graz.ac.at/autocad/lsp_tools/> Browsable
function cross-referencer, reverse calling tree, creates a library from source
files. ("Packager" or "Function Shaker")
PEI's
Findvars [new]
Similar to the Packager above, but not only functions, additonally detects
symbols to be localized. <http://www.perceptual-eng.com>
I personally use this and my Packager.
RapidLisp
[new] v1.0c shareware lisp analyser for R14.
<http://www.cps.de/cad/rapidlisp/>
LCA
- Autodesk's AutoLISP Compatibility Analyzer [new]
On the Migration CD. Details AutoCAD 2000 compatibility issues found in
specified AutoLISP (LSP) or Menu LISP (MNL) files.
ALLY30.ZIP
(old)
Shareware LISP analyzer. Checks
syntax and prints statistics (function dependence tree), at [1]
lck21b.zip
(old)
LCK LISP Checker 2.1b (graphical)
paran.zip
(old)
Simple
PARNCH.ZIP
(old)
Simple
There are also some AutoLISP programs which count
parenthesis.
[6.3]
Pretty Printers
External:
FMT202S.ZIP
Lisp, DCL and FRM source code
formatter
LB.EXE
Autodesk's source code
beautifier.
In the SDK2 or at [1]. Has problems with longer
strings, and new-style in-line comments.
PPRINT.LSP
in the SDK2 or at [1]
Internal:
Visual Lisp, Vital LISP, Emacs and Codekey provide internal beautifiers as I'm
aware of it.
[7]
AutoLISP problems and bugs
For AutoCAD 2000 and unexperienced VLISP users see [0.1].
There are almost no known serious AutoLISP bugs. The language interpreter itself
(ACADL.EXE/.EXP, VLISP) works undoubtedly well. Some restrictions are based on
the AutoCAD, ActiveX or the Proteus (DCL) engine. Some support LISP programs
(i.e. DDMODIFY.LSP) are faulty sometimes. For Visual Lisp see the README.txt
which lists all known bugs and limitations. Crashes with reactors are acad bugs.
Two inofficial buglists are at: [new]
"http://www.cadonline.com/exclusive/bugs/bugwatchlist.htm
<http://www.cadonline.com/exclusive/bugs/bugwatchlist.htm</a>
(the big one)
<http://www.dotsoft.com/buglist.htm>
(a private and short one)
+ List Arguments with DOTTED PAIRS passed from AutoLISP to Visual LISP or
back may loose the outer parens.
See the Visual Lisp README (undocumented
in Vital Lisp)
+ SINGLE ATOM LISTS returned incorrectly from EXTERNAL APPS
Visual LISP can not distinguish
between a LIST of a single atom (element), and a single atom returned from an
external ObjectARX or ADS application.
ENTGET
used with LWPOLYLINE, HATCH
(r14 only)
The Z coordinate (caddr (getval 10 ele)) is a random number and
often causes a floating point exception because it may too low or too high.
Workaround: see part 2, Subject [23.1]
ENTMAKE
VERTEX by Terry Dotson
(r14 only)
A problem can occur during the
process of using (entmake) to create polylines, you must assign the layer to
each of the VERTEX definitions (which Autodesk has told us), but you must also
assign the layer to the ending SEQEND. Absence of this will cause the SEQEND to
end up on the current layer, which can be later frozen. Attempts to move this
piece of geometry will then cause a EREGEN error and crash in R14 (only).
ACAD_STRLSORT:
Strange sort order in Windows.
The chars in Windows are not
sorted on its ASCII representation! Instead according the actual codepage, (getvar
"SYSCODEPAGE") which is different.
Windows: (acad_strlsort
'("-1" "+1")) - ("-1" "+1"), DOS: (acad_strlsort
'("-1" "+1")) - ("+1" "-1") Both:
(mapcar 'ascii ("-" "+")) - (45 43) More at <http://xarch.tu-graz.ac.at/autocad/docs/strlsort-bug.html>
AI_PROPCHK
(ai_propchk) was renamed to (C:AI_PROP)
in the R13c3 update patch.
"The AutoLISP function ai_propchk has been changed to c:ai_prop so that
it behaves similarly to other commands. This allows pressing return to bring
back DDMODIFY if selected from toolbar."
Faulty
action callbacks in R13 DCL code crash AutoCAD
There is a bug in R13 where
AutoCAD crashes with a Fatal Error if an error occurs in AutoLISP code during an
action callback from a scroll bar in
a dialog box. For instance, if you
try to evaluate a null function during the callback, AutoCAD crashes instantly.
Technically, this isn't a bug in the AutoLISP interpreter, but we would still
call it an AutoLISP bug.
You cannot rely on bitvalue
64 in flag 70 in symbol tables anymore since R13, but in all previous
releases.
What else? See the unofficial AutoCAD buglist compiled by Steve Johnson for more faulty AutoLISP
programs and behaviours, at <http://www.cadonline.com/exclusive/bugs/bugwatchlist.htm>
(esp: 33, 124, 126, 127, 139, 153, 158, 165, 176, 182, 192, 193, 238, 240, 254,
272, 295)
Protected
lisp files
In pre-c4 R13 protected LISP
files didn't stay protected in memory. In our opinion, this problem needs to be
made known to all, so that developers don't inadvertently assume their protected
code is safe from prying eyes. This FAQ
topic caused a major problem in moderated CompuServe's AutoCAD Forum.
Limited
number of open selection sets
They are intermediatly stored in
temporary files. Get rid of not needed selection sets with setting the symbols
to nil and run (gc), the garbage collector, which actually closes those files
then.
The maximal number depends on the operating system, i.e. in DOS of the FILES=
value in CONFIG.SYS
R13 improved the number.
Numbers:
range, accuracy, numerical precision
Integer numbers are internal
long fixnums (signed, 32-bit), but the communication from AutoLISP to AutoCAD
accepts only 16-bit short fixnums, in the range -32768
.. +32767, because AutoCAD needs only short fixnums.
Floating point numbers are
doubles (64-bit IEEE). All internal AutoLISP and AutoCAD numerical calculations
work with this double format, which should be sufficient. At least the first 14
decimal places are exact.
[new]
A common problem is the confusion betwen the actual number (exact) and the
rounded string representation. The number which is shown on the command-line is
always the rounded string which takes care of LUPREC and DIMZIN.
However with geometric
comparisons there often occur unwanted round off errors, so that it's wise to
compare points with a small fuzz factor [1e-12 - 1e-6]. (equal pt1 pt2 1e-6) ; 0.000001 rounding error tolerance instead
of (equal pt1 pt2), esp. with angles.
See <http://www.autodesk.com/support/techdocs/td30/td301207.htm>
[new]It
was also reported lately, that with certain automation controllers loaded,
numerical accuracy and locale issues (`,´ vs `.´) had undesirable sideeffects.
A solution and explanation of this problem is pending. (Mostly in `,´ as decimal delimiter countries such as Germany)
ACOMP's
(EQ) strictness
With [5.1] ACOMP's compiled code you have to take care that the (EQ)
behaviour in BI4's is much stricter than in plain AutoLISP. In AutoLISP (eq
"1" "1") is T
where in acomp compiled code it's nil
The following are not real bugs, that make AutoLISP crash
or return false results. They are just bad language implementations.
AND
and OR should return the value of the
not-NIL argument instead of T.
See <http://xarch.tu-graz.ac.at/autocad/docs/and-bug.html>
MAX
and MIN should handle string types
too, because < and > accept and process strings too.
see ACAD_STRLSORT
above
For stack overflow errors see [14]
[8]
Sorting with AutoLISP
In short: use vl-sort (generic) or acad_strlsort (strings
only).
I've set up a sort overview at http://xarch.tu-graz.ac.at/autocad/lisp/#sort
<http://xarch.tu-graz.ac.at/autocad/lisp/>
In LISP mostly used sort method is merge sort (also used
in (str-sort) in AutoDesk's TABLES.LSP sample) because that's a natural method
for linked lists. Normally (e.g. in C) you use heap sort (for any data) or qsort
(for random data) and insertion sort for the small lists (< 7) or sublists
within the algorithm.
There is lisp code for shell-sort, bubble-sort,
insertion-sort, quick-sort available for any data, lists of lists and indeces to
lists. In lisp you can pass the predicate function to sort which is evaluated at
run-time. (here called "method").
That's why you need only one sort function for multiple data types (i.e. numbers,
points on x or y, strings, ...)
(sort data method) ;method: less-than-predicate ;default
for numbers: ' Some sample timings from <http://xarch.tu-graz.ac.at/autocad/lisp/sort/ur_sort.lsp>:
sorting 100 elements: bubble sort : 13.639008 sec/ 30.08% insertion sort:
13.368042 sec/ 29.48% (fast for sorted lists) shell sort : 13.478973 sec/ 29.73%
(poor implementation) merge sort : 2.232971 sec/ 4.92% quick sort : 2.433960
sec/ 5.37% vlx-sort : 0.099976 sec/ 0.22% (Vital LISP internal) acad_strlsort :
0.089996 sec/ 0.20% (AutoLISP's internal, just strings) Pending
are timings for vl-sort, vl-isort, STDLIB std-fast-sort, std-sort,
std-stable-sort and Vladimir's new merge-sort
[9]
Recursion
This is not a often asked question but a very interesting
one, because LISP itself is defined recursively and it's a the easiest way to
articulate hard problems.
There some fine documents about recursion at <http://xarch.tu-graz.ac.at/autocad/lisp>
especially the <http://xarch.tu-graz.ac.at/autocad/lisp/recursive.html>
Tutorial by Dennis Shinn.
It explains in great detail
(defun fact (n) (cond ((zerop n) 1) (T (* n (fact (1-
n))))))
Note:
There's also a self-modifying example of this function explained at <http://xarch.tu-graz.ac.at/autocad/lisp/self-mod.lsp>
[10]
Iteration with MAPCAR,...
Same as with recursion this is not a often asked question,
but it's quite hard to understand too.
Iterative statements in AutoLISP are: WHILE, REPEAT, FOREACH and MAPCAR. We use
them widely in this FAQ code because they allow brief code.
There's a short course in LAMBDA, QUOTE, MAPCAR... by
Vladimir Nesterowsky:
"There are 14 paths and 12 pigs. How can there be 24
ducks?" Is there a lisp command that will allow me to pick these lines of
text, and recognize the number(s) in each line, in order to, say, raise each
number by two? Leaving the sentence structure, etc, intact? This is one way. (I
am sure there are many other ways) (defun mult2 (strng) ; by Vladimir
Nesterowsky (strlgather (mapcar '(lambda (s / n) (if (zerop (setq n (atof s))) s
(rtos (* n 2)))) (strlparse strng " ")) ; parse by spaces "
")) ; gather back with spaces
is explained at <http://members.tripod.com/~vnestr/mapcar.txt>
;;; flip rows and columns in a matrix (defun transpose (l)
; by Doug Wilson (apply 'mapcar (cons 'list l)))
is explained at <http://xarch.tu-graz.ac.at/autocad/lisp/transpose.002.html>
[11]
My LISPs aren't loaded at startup anymore
LISP files can be loaded at the startup using LOAD in
ACAD.LSP. Some LISPs, required with a menu to work, should be loaded from the
corresponding <menu>.MNL file. The <menu>.MNL file - if different -
should load ACAD.MNL
LISP functions calling commands at the startup should be
defined in S::STARTUP
of ACAD.LSP. This function is called at the startup after the initialization
automatically. Otherwise you'll get the "Command
list interruption (6 . 2)" errors.
[new] Note: (command) may be safely called from within MNL files.
(S::STARTUP) is mainly used to check for partial menus now.
If the file name was provided without an extension, the
LOAD function assumes .LSP. If - without a path prefix, the usual AutoCAD
library path is used, which is, exactly in this order,
) The current directory
) The directory containing the current drawing file
) The directories defined in the ACAD environment variable (setup in the
Preferences box, SUPPORT paths)
) The acad.exe directory
If your program isn't loaded anymore automatically, check
your AutoCAD library path settings.
With ACADLC (of ACOMP) and the domestic release of AutoCAD
R12 ACAD.LSP is not loaded automatically. Therefore you must append (load "ACAD"
-1) to your ACAD.MNL.
Sample ACAD.LSP:
;;;ACAD.LSP ;;; Fred the Beaver, 12/12/94 (load "init"
-1) ; this loads some tools of mine (defun S::STARTUP () (load "new-end"
-1) ; this redefines the END command )
The -1 argument provides LOAD from interrupting the
startup process, if any LOAD failure (causing an AutoLISP error). If a failure
at load-time occurs, -1 is returned, but the evaluation does not stop. -1 can be
any expression as well.
Sample code to enhance S::STARTUP in your code. With VILL/VLISP
compiled code this will not work: it must be defined with DEFUNQ instead.
Functions are generally no lists anymore! Better than to
use DEFUNQ for S::STARTUP is to check for known hooks, a list of user-defined
functions which are inserted and evaluated at run-time. (defun MY::STARTUP () ;your
startup code goes here ;.. (princ) ) (setq S::STARTUP (if (and S::STARTUP (listp
S::STARTUP)) ;already defined in ACAD.LSP ; or elsewhere (append S::STARTUP (cdr
MY::STARTUP)) ;append your code MY:STARTUP)) ;just your code
or a simple one:
(if (and S::STARTUP (listp S::STARTUP)) (setq S::STARTUP (append
S::STARTUP (list func '(princ)))) (setq S::STARTUP (list nil func '(princ))))
See also [12]
How to AUTOLOAD my programs?
[12]
How to AUTOLOAD my programs?
How to load my programs automatically?
You can either load your whole program at startup (see [11] My Lisp doesn't load at startup anymore)
which needs more time and memory at startup time, or you can define them via the
autoloading mechanism.
From R14 on ARX programs use a new autoloading scheme (called "demand
loading") with some registry settings and not from ACADRxx.LSP anymore.
Look at the end of your ACADRxx.LSP how AutoCAD autoloads
its programs.
;;;===== AutoLoad LISP Applications ===== ... (autoload
"dline" '("dline" "dl")) ...
This defines the commands DLINE and DL in the list to be
loaded from the file DLINE.LSP when the user first calls the command DLINE or
DL. Before that the function is simply defined like this one:
(defun C:DL () (load "DLINE")(C:DL))
In
fact the definition is more complicated because of error handling: Ctrl-C,
loading errors, wrong file or path.
After the first call the function is overwritten with the
definition in the program.
Advantages
of autoloading:
Startup is faster, because you
dont have to load all your lisp files. You just define the simple wrapper
definition as above. This is done by the (autoload)
function
You need less memory
Disadvantages:
On errors in your program you
will fall into a never ending loop, which will only stop after a stack overflow
or Ctrl-C
Note: with acomp compiled code even Ctrl-C is impossible, insert a call to an
uncompiled (princ) somewhere.
You have to define and maintain
all command names from your program in the autoloader definition. Changes to the
lisp filename or the command name will cause the above error.
Where
to put your (autoload)
definitions?
Not to ACADR14.LSP. Well we
recommend putting it to an initialization file of yours and not to ACAD.LSP
because this is often changed by different applications and ACAD.LSP should be
kept rather small.
I.e. put it to a AUTOLOAD.LSP or
INIT.LSP, which is loaded from ACAD.LSP See [11] My Lisp doesn't load at startup anymore
It should be mentioned that users should *not* modify ACADRxx.LSP. Since
ACAD.LSP is not overwritten during upgrades, it is guaranteed to remain safe. In
addition (as we saw with the R13c4a patch) if the ACADR13.LSP file has been
modified, then the patch process may refuse to update it, thus resulting in
program malfunctions.
[13]
How can I pass a variable number of arguments to a lisp function?
With pure AutoLISP this is not possible.
You can either pass all your arguments in a list like
this: ;;; print a variable number of arguments (of any type) (defun my-princ (x)
;; simple version, for better stuff look at the SDK2: PRINTF.LLB (if (listp x) (mapcar
'princ x) (princ x)))
Or you have to define the function in ADS
or ARX and export it to AutoLISP. Then you are free to write: (ads-print
"Hello " "World " 1 2 3) or even (ads-printf "Hello %s
%i %i" "World" 2 3)
Look at Reini Urban's and Vladimir Nesterovsky's ADS
samples at <http://xarch.tu-graz.ac.at/autocad/ads/>
for implementations of the above examples.
Official wishes were pointed to AutoDesk regarding &optional as AutoLISP language
enhancement, but it was not implemented so far.
[14]
How can I avoid stack overflows?
In AutoLISP the stack size is hardcoded. It cannot be
extended, but its size should be sufficient for most purposes.
Most stack overflow errors occur on a program error of yours, preventing the
system from falling into an endless loop, or from using recursive functions on
large lists. Therefore you are limited to lists ~200 elements with recursive
functions in plain AutoLISP.
You cannot decrease your used stack size with using less
local parameters in your recursive function! However do not use APPLY, EVAL or
MAPCAR to call your function recursively, because they eat up the stack. Using
tail recursion doesn't help either.
You'll have to convert your recursive function to a
iterative one. (There is a mathematical theorem that says, that every recursive
function can be converted to a iterative one, tail-recursive ones even
automatically.) Iterative versions may use stack-like functions like (push) and
(pop), but those versions store the stack on the heap (AutoLISP node space),
which size is only limited by your amount of virtual memory available.
You can test the stack overflow with this simple function:
;;; create a list of n numbers (zero based) (defun intlst (l n) (cond ((zerop n)
l) (T (intlst (cons (1- n) l) (1- n))))) and try: (setq n 100)(while (intlst nil
(setq n (+ 10 n)))(print n)) In AutoLISP of R12/DOS you reach the stack limit
with (intlst nil 138), in A13/Win with (intlst nil 240), in acomp bi4's with
(intlst nil 1240), in Vital LISP IDE with (intlst nil 984). With Vital
LISP or Visual LISP RTS the stack size is unlimited.
With R10c10, the first dos extended lisp version, you could enhance the lisp
stack size with the environment variable LISPSTACK. acomp for R10 had COMPSTACK.
This is not possible anymore.
Conversion to an iterative version yields the required
results: (defun intlst (n / l) (repeat n (setq l (cons (setq n (1- n)) l))))
;this looks ugly but it works The only possibility to physically enhance the
stack size is to use VLISP, ViLL or the acomp interpreter ACADLC. See [5].
[15]
(command "ROTATE3D") does not work! Why?
Some commands are no internal AutoCAD commands, they are
simple AutoLISP programs beginning with C:
even if they are defined in ADS programs. Only native Rx applications (or now
with vlax-add-cmd) export true commands.
A list of all these commands are found in ACADR13.LSP in
the AUTOLOAD section. (see also "[12]")
All these commands have to be called with (C:ROTATE3D)
instead of (command "ROTATE3D").
However ADS functions may take optional arguments. See the
customization manual for more.
i.e. (c:rotate3d ss p1 p2 angle) is also valid, even (rotate3d ...)
[16]
LISP programs operating over multiple drawings
"I am having trouble
getting a lisp file that will open a drawing and continue running. Once the new
drawing is opened the Lisp file ceases to exist in the Autocads memory. It has
to be reloaded to recognise the commands."
LISP memory is reloaded on a per drawing basis. There are
some ways to execute a LISP on multiple drawings:
via a script that executes on multiple files. MYSCRIPT.SCR. (load
"mylisp") _QSAVE _OPEN !nextdwg (load "mylisp") _QSAVE _OPEN
!nextdwg ...
External 3rd party software such as RunLisp or DDSCRIPT automate step 1.
R14 has a new feature, called 'Persistent LISP'.
Set it in Preferences-Compatibility-Persistent Lisp
Vital LISP has a built-in variable to act as Persistent Lisp:
(setq *VILL-NEW-FULL-INIT* nil) ;keep symbols between sessions VLISP renamed it
to *VLISP-NEW-FULL-INIT*
[17]
How to export Visual Lisp functions to AutoLISP/AutoCAD?
C: functions are automatically exported to AutoLISP. Plain
vlisp/vill lisp functions must be exported either with (vl-acad-defun
'myx-funcname) or their symbols may be exported with a special compiler pragma,
defined either in the LSP file or in the GLD (global declarations) file. Better
use special prefixes for such functions. .GLD: (AUTOEXPORT-to-ACAD-PREFIX ;|
name prefixes for functions to be autoexported to AutoCAD: (strings) |;
"myx-*" ) or one by one .LSP: (pragma '((export-to-acad myx-func1
myx-func2))) Note: There may exist known bugs in vlisp and vill with lists of
atomic symbols and dotted pair lists in such functions arguments and return
values. See [7].
Functions exported by external apps which are used in your
application must be defined via XDF.
Symbols
(variables) whose values are updated in Visual Lisp and which values are also
used in AutoLISP or AutoCAD (the menu e.g.), first may be marked for the
compiler to be external with: (pragma
'((not-localize myx:symbol)))
but the value must be exported with
(vlisp-export-symbol 'myx:symbol)
each time the value is changed in Visual Lisp and control is returned to AutoCAD
to be able to get the latest value in AutoLISP or in AutoCAD with !myx:symbol
In AutoCAD 2000 it is much simplier, however you might
need to export your function from the protected namespace then with VL-DOC-SET.
See also <http://www.autodesk.com/support/techdocs/td17/td175363.htm>
part
2: samples, code
[20]
General helper functions
For more general AutoLISP functions please see the AutoLISP
Standard Library at <http://xarch.tu-graz.ac.at/autocad/stdlib/>
Other code is available at some AutoLISP sites [1]
or included in the SDK's by Autodesk [1.2]
I included here some very useful helper functions for
shorter samples in answers on the net.
You could rely on the fact that these functions are in common knowledge such as
the famous dxf function, which is defined as
(defun dxf (grp ele) (cdr (assoc grp ele))) and
the specific counterpart of (getval) which works with either an ename or entget
list.
[20.1]
List manipulation
See also <http://xarch.tu-graz.ac.at/autocad/stdlib/STDLIST.LSP>
Useful sample functions for list
manipulation are: ;;; CONSP - a not empty list (defun consp (x) (and x
(listp x))) ;;; POSITION - returns the index of the first element in the list,
;;; base 0, or nil if not found ;;; (position 'x '(a b c)) - nil, (position 'b
'(a b c d)) - 1 (defun position (x lst / ret) (if (not (zerop (setq ret (length
(member x lst))))) (- (length lst) ret))) ;;; REMOVE - Removes an item from a
list (double elements allowed) ;;; (remove 0 '(0 1 2 3 0)) - (1 2 3) (defun
remove (ele lst) ; (c) by Serge Volkov (apply 'append (subst nil (list ele)
(mapcar 'list lst)))) ;;; REMOVE-IF - Conditional remove from flat list ;;; fun
requires exactly 1 arg ;;; (remove-if 'zerop '(0 1 2 3 0)) - (1 2 3) ;;;
(remove-if 'numberp '(0 (0 1) "")) - ((0 1) "") (defun
remove-if (fun from) (cond ((atom from) from) ;nil or symbol (return that)
((apply fun (list (car from))) (remove-if fun (cdr from))) (t (cons (car from)
(remove-if fun (cdr from)))) ) ) ;;; REMOVE-IF-NOT - keeps all elements to which
the predicate applies ;;; say: "keep if". It need not be defined
recursively, also like this. ;;; [fixed, thanks to Serge Pashkov, in
FAQ-CODE.LSP it was okay] (defun remove-if-not (pred lst) ; by Vladimir
Nesterowsky (apply 'append (mapcar '(lambda (e) (if (apply pred (list e)) (list
e))) lst))) ;;; ADJOIN - conses ele to list if not already in list ;;; trick:
accepts quoted lists too such as ;;; (setq l '(1 2 3) (adjoin 0 'l) ;;; - !l (0
1 2 3) (defun adjoin (ele lst / tmp) (if (= (type lst) 'SYM) (setq tmp lst lst
(eval tmp))) (setq lst (cond ((member ele lst) lst) (t (cons ele lst)))) (if tmp
(set tmp lst) lst) ) ;;; ROT1 - put the first element to the end, simple version
;;; (rotate by one) (defun rot1 (lst) (append (cdr lst) (list (car lst)))) ;;;
BUTLAST - the list without the last element (defun butlast (lst) (reverse (cdr
(reverse lst))))
[20.2]
String manipulation
Please check <http://xarch.tu-graz.ac.at/autocad/stdlib/STDSTR.LSP>
Some useful string functions would
be:
·
Predicates:
(stringp expr)
- string predicate, is expr a
string? (defun stringp (s) (= (type s) 'STR))
(string-not-emptyp str)
- is str a not empty string?
(defun string-not-emptyp (s) (and (stringp s) (/= s "")))
·
Trimming:
(str-trim string)
- str without any whitespace, to
the right and left, defined in AI_UTILS.LSP, as well as:
(str-left-trim string),
(str-right-trim string),
(str-left-trim-bag string bag),
(str-right-trim-bag string bag)
- remove all chars in bag (=
STR)
·
Search:
(strpos string substr)
- position of substring in
string (1 based)
·
Parsing and gathering functions, (list<->string):
(strtok str tokens)
- string -> list delimited by
tokens
(strlcat lst delim)
- concat list -> string
seperated by delim
(string->list str)
- string -> list of chars
(list->string str)
- list of chars -> string
All of them and much more are in the Stdlib (see above).
Some are at <http://xarch.tu-graz.ac.at/autocad/code/vnestr/strtok.lsp>
or in your AI_UTILS.LSP. You'll need them esp. for DCL functions.
[20.3]
symbol -> string
The inverse function to (read) would be (symbol-name).
The following is the only general way, but there exist better special methods.
;;; SYMBOL-NAME returns the name of a symbol as string ;;; converts any valid
lisp expression to its printed representation ;;; (symbol-name a) -
"a", (symbol-name '(0 1 2 a)) - "(0 1 2 A)" (defun
symbol-name (sym / f str tmp) (setq tmp "$sym.tmp") ;temp. filename,
should be deleted (setq f (open tmp "w"))(princ sym f) (close f) (setq
f (open tmp "r") str (read-line f) f (close f)) str ) For plain
symbols exists a better trick explained by Christoph Candido at <http://xarch.tu-graz.ac.at/autocad/news/symbol-string.txt>
Vill/vlisp introduced a fast vl-symbol-name.
See also <http://xarch.tu-graz.ac.at/autocad/stdlib/STDINIT.LSP>
[20.4]
AutoCAD entity access [renamed SSAPPLY to SSMAP]
See also <http://xarch.tu-graz.ac.at/autocad/stdlib/STDENT.LSP>
;;; returns the first group value of an entity. ;;; like the wellknown (dxf)
function but accepts all kinds of ;;; entity representations (ename, entget
list, entsel list) ;;; NOTE: For getting 10 groups in LWPOLYLINE's not usable!
(defun GETVAL (grp ele) ;"dxf value" of any ent... (cond ((= (type
ele) 'ENAME) ;ENAME (cdr (assoc grp (entget ele)))) ((not ele) nil) ;empty value
((not (listp ele)) nil) ;invalid ele ((= (type (car ele)) 'ENAME) ;entsel-list
(cdr (assoc grp (entget (car ele))))) (T (cdr (assoc grp ele))))) ;entget-list
;;; Ex: (gettyp pline) = "POLYLINE" (defun GETTYP (ele) ;return type
(getval 0 ele)) ;;; assure ENAME ;;; convert the entity to type ENAME (to write
shorter code) (defun ENTITY (ele) ;convert to element name (cond ;accepts the
following types: ((= (type ele) 'ENAME) ele) ; ENAME ((not (listp ele)) nil) ;
error: no list ((= (type (car ele)) 'ENAME) (car ele)) ; entsel-list ((cdr
(assoc -1 ele))) ; entget-list or nil ) ) ;and now just: (defun getval (grp ele)
(cdr (assoc grp (entget (entity ele))))) ;;; Ex: (istypep ele "TEXT")
;;; is element a "SOLID"? (defun istypep (ele typ) ;check type (=
(gettyp ele) typ)) ;;; Ex: (istypep ele '("TEXT" "ATTDEF"))
;;; is element a "TEXT" or a "ATTDEF"? (defun ISTYPEP (ele
typ) ;better implementation to accept lists too (cond ((listp typ) (member
(gettyp ele) typ)) ;fixed ((stringp typ) (= (gettyp ele) typ)) ;assume typ
uppercase, wcmatch (T nil))) ; would be nice but slower ;;; Ex: (getpt (entsel))
= ( 0.1 10.0 24) (defun GETPT (ele) ;return the startpoint of any element
(getval 10 ele)) ;group 10 ;;; Ex: (getflag pline) = 1 if closed (defun GETFLAG
(ele) (getval 70 ele)) ;same with the entity flag ;;; bitvalue val in flag of
element set? ;;; Ex: (flagsetp 1 pline) = T if closed ;;; Ex: (flagsetp 16
vertex) = T if spline control point (defun FLAGSETP (val ele) (bitsetp val
(getflag ele))) ;;; Ex: (bitsetp 4 12) = T ;bitvalue 4 (=2.Bit) in 12 (=4+8) is
set (defun BITSETP (val flag) (= (logand val flag) val)) ;;; convert selection
set to list. slow, but easy to write. ;;; Note: it's also wise to use ai_ssget,
because some ents could be ;;; on locked layers ;;; Ex: (sslist (ai_ssget
(ssget))) = list of selected unlocked ents ;;; or (mapcar 'entupd (sslist (ssget
"X" '((8 . "TEMP"))))) ;;; - regens all entities on layer
TEMP (defun SSLIST (ss / n lst) (if (= 'PICKSET (type ss)) (repeat (setq n
(sslength ss)) (setq n (1- n) lst (cons (ssname ss n) lst))))) ;;; Map a
function over each entity in ss, in reversed order. ;;; Faster, but not so easy
to understand. see [22.2] | ;;; [renamed from SSAPPLY to SSMAP to match the
stdlib name] ;;; Ex: (ssmap 'entupd (ssget)) ; regenerate only some entities
(defun SSMAP (fun ss / n) (if (= 'PICKSET (type ss)) (repeat (setq n (sslength
ss)) (apply fun (list (ssname ss (setq n (1- n))))))))
[21]
Sample Lisp Programs:
[21.1]
Globally change texts, polylines, layer utils, datestamp
For globally changing text
attributes use CHTEXT.LSP in your sample directory.
For globally changing polyline
attributes, freeze layers by pick and other similar tasks search for free lisp
tools at any AutoLISP site. See also [1]
and some code at [22], [23],
and [24].
For putting a datestamp and
others onto your plots automatically first check out if your plotter supports
HPGL/2. Then use the internal HPGL/2 driver and configure the datestamp in
HPCONFIG.
DATESTAMP.LSP: Change the plot header attributes by yourself as
in [22.2]. A professional plotstamp
routine is here: <http://ourworld.compuserve.com/homepages/tonyt/plotstmp.htm>
[21.2]
Plot dialog from within Lisp. Using DDE or ActiveX
From R14 on use INITDIA
(initdia)(command "_PLOT")
Calling the PLOT dialogbox from
AutoLISP before R14 was possible only under Windows i.e. with LISPPLOT by Mike
Dickason. This fed the keyboard buffer with keystrokes. <http://www.cadalog.com/cadalog/files/lispd-l/lspplw.zip>
or also: <ftp://ftp.mcwi.com/pub/mcwi/lisp/winplt.lsp>
Otherwise create a script and call this at the end of your lisp, but this will
not show up the dialogbox.
Xiang Zhu: You can use
"ddelisp" under Windows to do something like the following: ;;; [fixed
for all releases] (defun DDECMD (str / tmp acadver ddestr) (if (not (boundp
'initiate)) (cond ((= 14 (setq acadver (atoi (getvar "ACADVER"))))
(setq ddestr "AutoCAD.R14.DDE") (arxload "ddelisp")) ((= 13
acadver) (setq ddestr "autocad.r13.dde") (xload "ddelisp"))
((= 12 acadver) (setq ddestr "autocad.dde") (xload
"ddelisp")) (T (princ "DDE not supported")(exit)))) (if (not
(zerop (setq tmp (initiate ddestr "system")))) (progn (execute tmp
(strcat "[" str "]")) (terminate tmp) str))) For R12 use "autocad.dde" as the server name.
Then, inside your lisp or script, you can do (ddecmd
"_plot "). Function DDECMD will return nil if something
wrong, or the string you passed if successful. The string is just like what you
type under the command prompt from keyboard, so you need put a space or a
return, which is "^13"
here, to end the string.
Besides, the function is very
useful in the following situation: If within a lisp, you need to call an AutoCAD
transparent command like LAYER, normally you will use (command "_layer"),
but after using this line, the lisp own will not be transparent. Using the
function, you will solve this problem.
Beware
that Acad accepts only DDE commands if the command line is active, that means no
dialogbox must be open.
With vlisp/ViLL ActiveX
methods can be used also: ;;; vlisp syntax: (setq vlax:ActiveDocument
(vla-get-ActiveDocument (vlax-get-Acad-Object))) (setq plt (vla-get-plot
vlax:ActiveDocument)) ;= plot object (vla-PlotWindow plt pt1 pt2) ; define
window (pts in WCS) (vla-PlotPreview plt 1) ; 0 for partial, 1 for full
(vla-PlotToDevice plt "Default System Printer") ; if it exists With
R14 INITDIA was introduced, which can be applied to most (but not all) dialogs:
(initdia)(command "_PLOT")
With A2000 use OLE (the VLA- methods) instead of DDE.
[21.3]
(entmod) and (entmake) Layers, without (command "_LAYER"...)
ENTMOD a layer
I try to change a layer property
without calling COMMAND function inside a lisp routine.
Under r13, using the following
lisp (setq tbl_lst (entget (tblobjname "LAYER" "ANY_LAYER"))
clr_grp (assoc 62 tbl_lst)) (entmod (subst (cons 62 (- (cdr clr_grp))) clr_grp
tbl_lst)) you can toggle "ANY_LAYER" On or Off, even it is the current
layer.
But AutoCAD doesn't know a table
entry has been changed until you click the Layer Control on the toolbar or
something similar. Besides, you can issue 'DDLMODES to see On/OFf property of
"ANY_LAYER" changed.
Doing the same way to freeze a layer, you will still see entities on that layer
shown on screen, but you can not select them, until you do something related to
layer settings, and AutoCAD will hide those entities.
ENTMAKE a layer
You must get your pattern with
entget, using the table object name as argument. This table object name can be
retrieved with the TBLOBJNAME function: (entget (tblobjname "LAYER"
"Any Layer Name")) ; R2000 can have spaces! ;;; This routine will
create a layer with any name you type: (defun c:mlay () ; by Reinaldo Togores
(setq laynam (getstring "\nLayer name: ")) (entmake (list '(0 .
"LAYER") '(5 . "28") '(100 .
"AcDbSymbolTableRecord") '(100 . "AcDbLayerTableRecord")
(cons 2 laynam) '(70 . 64) '(62 . 7) '(6 . "CONTINUOUS") ) ) )
[21.4]
How to select multiple files in Lisp? (as in FILES - Unlock)
[new]
·
DOSLIB v4.3 from McNeel contains dos_getfilem, http://www.mcneel.com/products.htm#Utilities
<http://www.mcneel.com/products.htm>
·
STDLIB contains std-getfilem
<http://xarch.tu-graz.ac.at/autocad/stdlib/GETFILEM.LSP>
·
At <http://xarch.tu-graz.ac.at/autocad/progs/MGETFILD.ZIP>
is another lisp helper routine to select multiple files with DCL. You will also
need VLISP, DOSLIB or the STDLIB for the directory functions. Another lisp
version is at <http://xarch.tu-graz.ac.at/autocad/stdlib/Reini_MFD.LSP>
[21.5]
Replace multiple blocks
A search at the lisp archives
yielded those hits:
Cadalyst: <http://www.cadonline.com/search.phtml>
=> 97code.htm and a question for your
username which can be obtained free and automatically
xarch: <http://xarch.tu-graz.ac.at/autocad/code>
and search for "BLOCK;REPLACE"
=> <http://xarch.tu-graz.ac.at/autocad/code/cadalyst/94-02/replace.lsp>
also at the Cadalog:
<http://www.cadalog.com/find.htm>
Keyword "Block Replace"
=> <http://www.cadalog.com/cadalog/files/lispr-z/replace.zip>
(this one is the best)
[21.6]
(vports), VIEWPORT entity, pixel conversion
VIEWPORT entity:
The answer to "I can do an (entget) on a VIEWPORT and get its lower left
(DXF group 10) and upper right (DXF group 11) corner. But it appears that these
coordinates are in the paper space system. What I'm interested in finding out is
what portion of the "real" drawing (the model space drawing) are
currently shown in that viewport." is at <http://xarch.tu-graz.ac.at/autocad/news/vports.lsp>
[new]:
http://www.ez-sys.net/~coopfra/lisp.htm#view
<http://www.ez-sys.net/~coopfra/lisp.htm> has also some tricks.
How to change viewports in
AutoLISP?
with (setvar "CVPORT" vport-id)
see <http://xarch.tu-graz.ac.at/autocad/news/change_vports.html>
With the following functions you
convert pixel<->drawing units:
;;; Conversion pixel to drawing units (defun PIX-UNITS (pix) (* pix (/ (getvar
"VIEWSIZE") (cadr (getvar "SCREENSIZE"))))) ;;; Conversion
drawing units to pixel (defun UNITS-PIX (units) (* units (/ (cadr (getvar
"SCREENSIZE"))(getvar "VIEWSIZE")))) Note also the
"Pixel Off by One" Errors in AutoCAD, written by Vibrant <http://xarch.tu-graz.ac.at/autocad/news/pixel-off-by-one-error.txt>
[21.7]
Select all visible objects: zoom coordinates
Beware that with (ssget) you
will only get visible objects, because all interface functions
(entsel,ssget,osnap) work with pixel, only (ssget "X") will select not
visible objects. ;;; returns a list of the actual viewport corners in WCS (defun
zoompts ( / ctr h screen ratio size size_2) (setq ctr (xy-of (getvar
"VIEWCTR")) ;3D - 2D h (getvar "VIEWSIZE") ;real screen
(getvar "SCREENSIZE") ;2D: Pixel x,y ratio (/ (float (car screen))
;aspect ratio (cadr screen)) size (list (* h ratio) h) ;screensize in coords
size_2 (mapcar '/ size '(2.0 2.0))) (list (mapcar '- ctr size_2) (mapcar '+ ctr
size_2))) (defun xy-of (pt) (list (car pt)(cadr pt))) ;assure 2D coords Note:
The points returned from the entity are in WCS but this is OK because the
"CP" "WP" and "P" options of ssget expect WCS
points ("W" and "C" require UCS points - why the difference
I don't know) ;;; one way to define this function (defun ssall-visible (/ l)
(ssget "C" (car (setq l (maptrans0-1 (zoompts)))) (cadr l))) ;;; or
another (defun ssall-visible-1 () ;combine "C" and (p1 p2) to one list
(apply 'ssget (append '("C") (maptrans0-1 (zoompts))))) ;;; map some
pts from WCS to UCS, easier with just one argument [doc fixed] (defun
maptrans0-1 (pts)(mapcar '(lambda (pt)(trans pt 0 1)) pts))
[21.8]
How to write XYZ data of selected objects to a file?
;;; CDF - comma delimited string (defun cdf-point (pt)
(strcat (car pt) ", " (cadr pt) ", " (caddr pt))) ;;; SDF -
space delimited, may easier be read back in to AutoCAD (defun sdf-point (pt)
(strcat (car pt) " " (cadr pt) " " (caddr pt))) ;;; convert
this SDF format back to a point with (defun str-point (s) (eval (read (strcat
"(" s ")")))) ;;; Write a XYZ file of all selected objects
(SDF see below) (defun C:XYZ (/ ss fname f) (if (and (setq ss (ssget)) (setq
fname (getfiled "Write XYZ to file" (strcat (getvar
"DWGNAME") ".XYZ") "XYZ" 7)) (setq f (open fname
"w"))) (foreach ele (sslist ss) ; - [20.4] (foreach pt (getpts ele) ;
- [23.1] (write-line (cdf-point pt) f) ) ) ) (if f (close f)) ) ;;; = .xyz ;;;
0.45, 12.3, -34.0 For a ASC file (SDF-format) simply change all XYZ to ASC and
cdf-point to sdf-point above.
For the other way 'round, creating PLINES from a ascii x,y
file best convert the file to a script like: PLINE 300.2,10 350.4,10.4
[22]
Block Attributes
[22.1]
How to access block attributes?
Check all subentities after the
INSERT until the attribute is found. See also <http://www.autodesk.com/support/techdocs/td30/td300518.htm>
-> "Retrieving Complex Entities
and Sub-entities with AutoLISP" ;;; returns entget-list of attribute s
(STRING) in element ele (ENAME) ;;; or nil if no found (defun ATTELE (ele
attname / rslt) (if (and (istypep ele "INSERT") (= (getval 66 ele) 1))
(progn (setq ele (entnext (entity ele))) (while (and ele (istypep ele
"ATTRIB")) (if (= (strcase (getval 2 ele)) (strcase attname)) (setq
rslt (entget ele) ele nil) ;break the loop (setq ele (entnext ele)) ) ) ) ) rslt
) ;;Example: (attele (entsel) "TEST") ; returns entget-list of ;
attribute "TEST" if the block has it BTW: Even trickier functions to
get entities DXF group codes are GET and EDLGETENT by Vladimir Nesterowsky.
;;;Sample calls: ;;; return list of 2,1 and -1 group values (defun
get-attribs-look-up (block-ename) (get '(2 1 -1) (cdr (edlgetent block-ename))))
(defun all-verticies-and-bulges (pline-ename) (get '(10 42) (cdr (edlgetent
pline-ename)))) available at <http://members.tripod.com/~vnestr/>
[22.2]
How to MODIFY block attributes? DATESTAMP
Simply entmod the entget-list retrieved from (attele) as above.
;;; change the attribute value to new, group 1 (defun ATTCHG (ele attname new /
b) (if (setq b (attele ele attname)) (entmod (subst (cons 1 new) (getval 1 b)
b)))) ;;; Change all DATESTAMP attributes in all inserted PLOT* blocks (defun
C:DATESTAMP () (ssmap ; fixed and renamed '(lambda (ele) (attchg ele
"DATESTAMP" (today)) (entupd ele) ) (ssget "X" '((0 .
"INSERT")(2 . "PLOT*"))) )) ;;;return todays date, could be
a DIESEL or this string conversion (defun TODAY (/ s) (setq s (rtos (getvar
"CDATE") 2)) ;gets the julian date (strcat (substr s 5 2)
"-" (substr s 7 2)"-"(substr s 3 2)))
[22.3]
How to UPDATE block attributes?
There exists a
SUPPORT\ATTREDEF.LSP to update attribute properties (position, layer, ...) for
already inserted blocks.
On complex entities you must entupd the header entity, to see the update on the screen
(it forces an element REGEN). ;;; Example: (setq s (getstring "Change
Attribute to: ")) (attchg (attele (setq b (entsel "of block: "))
s))) (entupd (car b)) ; the block, not the attribute ;;; some more helper funcs
to get the main entity of any attribute ;;; or vertex (defun MAIN-ENTITY (ele)
(setq b (entity b)) ;force ENAME (while (istypep b '("ATTRIB"
"ATTDEF" "VERTEX")) (setq b (entnext b))) ; loop until no
more sub-entities (if (istypep b '("SEQEND" "ENDBLK"))
(getval -2 b) ;complex entity - header b ;normal entity ) )
[22.4]
How to ENTMAKE a Block Complex Entity in AutoLISP>
see
<http://www.autodesk.com/support/techdocs/td30/td301515.htm>
There is an example how to use
multiple calls to (entmake) to create the block header, the entities, closes the
block and finally (entmake) the INSERT. For anonymous blocks beware that only (setq bn (entmake '((0 . "ENDBLK"))))
returns the blockname for (entmake
(list '(0 . "INSERT")'(70 . 1)(cons 2 bn) ...))
[23]
Polylines
R14 LWPOLYLINE's store the vertices in one entity as
multiple 10 groups!
[23.1]
How to access polyline VERTICES?
A polyline VERTEX is a subentity
of a POLYLINE (same as an ATTRIBUTE is a subentity of an INSERT element or a
ATTDEF of a BLOCK). Therefore the same functions as in [22.1]-[22.3]
can be used. ;;; return only some assoc values in the list (for LWPOLYLINE)
(defun group-only (grp lst) (mapcar 'cdr (remove-if-not '(lambda(pair)(= grp
(car pair))) lst))) ;;; return the vertex list of a polyline or of any other
element (defun GETPTS (ele / pts) (setq ele (entity ele)) ;force type ENAME
(cond ((istypep ele "POLYLINE") (while (istypep (setq ele (entnext
ele)) "VERTEX") ;; omit fit and spline points (conservative style) (if
(not (or (flagsetp 1 ele) (flagsetp 8 ele))) ;bugfix! (setq pts (cons (trans
(getpt ele) ele 0) pts))) (reverse pts))) ;; Special case: you have to map it,
assoc finds only the first. ;; Fix a LWPOLYLINE bug in R14: internally stored as
2d point, ;; (entget) returns fantasy z-values. ((istypep ele
"LWPOLYLINE") (mapcar '(lambda(pt)(trans (list (car pt)(cadr pt) 0.0)
ele 0)) (group-only 10 (entget ele)))) ;; insert here possible other types, such
as ((istypep ele '("TEXT" "CIRCLE")) (list (getpt ele))) ;;
more like this (serge's style). LWPOLYLINE code above. (T (apply 'append (mapcar
'(lambda (n / p) (if (setq p (getval n ele)) (list p))) '(10 11 12 13))) ) ;; or
like this (conservative style) ;;(T (foreach n '(10 11 12 13) ;; (if (setq p
(getval n ele)) (setq pts (cons p pts)))) ;; pts ;;) ) ) Suggestions by Vladimir
Nesteroswky for a different vertex structure: See [22.1]
(defun vertices-and-bulges( pline-ename ) (mapcar 'cdr (remove-if-not
'(lambda(ele) (bitsetp 9 x)) (get '(70 10 42) (cdr (edlgetent pline-ename)) =
list of (10 42) pairs of the pline ;;;which can also be written as: (defun
flag9p (ele) (flagsetp 9 ele))) ;true if fit or spline point (mapcar '(lambda
(ele) (remove-if-not 'flag9p (cdr (edlgetent pline-entname)))) see also [23.5]
for a different edge structure (segments) of plines.
[23.2]
How to JOIN multiple lines to polylines? [fixed]
Simply try to join each element
with all selected, but beware that a entity already joined cannot be entget'ed
anymore, because it's deleted. ;;; This sample converts all selected elements to
polylines and ;;; tries to join as much as possible. (defun C:JOINPOLY (/ ele
ss) (foreach ele (sslist (setq ss (ssget))) ;better process lists (if (entget
ele) ;not already joined (cond ;(then it would be nil) ((istypep ele
'("ARC" "LINE")) ;; but you should check Z of lines and UCS
here too (command "_PEDIT" ele "_y" "_j" ss
"" ""); convert and JOIN ) ((and (istypep ele
'("POLYLINE" "LWPOLYLINE")) ;fixed (not (flagsetp 1 ele))
;not closed (
[23.3]
Change WIDTH of multiple polylines
With the help of the above
defined helper function it's a short one: (defun C:POLYWID (/ wid ele) (initget
5)(setq wid (getdist "New Polyline Width: ")) ;not negative (foreach
ele (sslist (ssget '((0 . "*POLYLINE")))) ;only PLINES (command
"_PEDIT" ele "_W" wid "")))
[23.4]
Create a polyline or spline: with (ENTMAKE) or (COMMAND)
You can create a script-file with a LISP-program and then run it. It seems
to be the simpliest way, but I/O errors may occur when reading/writing the
script. If your soft is commercial, it must handle such errors.
The second way is to create the entities list and use ENTMAKE. Advantage:
fast, in WCS, independent of actual osnaps.
see <http://www.autodesk.com/support/techdocs/td30/td300510.htm>
The third solution is based on command and mapcar. It works with Polylines,
Splines or Lines. Disadvantage: UCS, Osnaps ;;; Draws a POLYLINE entity from a
list of points (same with SPLINE, ;;; or LINE), on the actual UCS, with actual
OSNAP settings (defun DRAW-PLINE (pts) (command "_PLINE") (mapcar
'command pts) (command "")) (defun DRAW-SPLINE (pts) (command
"_SPLINE") (mapcar 'command pts) ; the pts must be the fitpoints then
(command "" "" ""))
[23.5] How to calculate the LENGTH of polylines?
There
are two ways:
the obvious, using the AREA command which is quite "noisy" (prints
the result), but works even with splines. ;;; add up the LENGTH of all selected
objects, NOISY, you can do the ;;; same with AREAs: simply change the last line
to (getvar "AREA") (defun C:LEN-OF () (command "_AREA"
"_A" "_E") ;add up objects (works in R12+R13) (ssmap
'command (ssget)) ;renamed, pass all elements to AutoCAD (command ""
"") ;two returns (getvar "PERIMETER")) ;this is the length
Doing some math, but only for simple entities. Here is best to define some
helper functions again. This is also an introduction for the next chapter [24],
some bulge trigonometry for curved segments.
;;;
calculates length of pline, quiet (defun POLY-LENGTH (poly / seg) (apply '+ ;
the sum of all single segment lengths (mapcar '(lambda (seg) ;length of segment
(if (zerop (car seg)) (distance (cadr seg) (caddr seg)) ;line segment or (abs
(arclen seg seg)))) ;curved: see below at [24] (pline-segs poly)))) ;;; returns
all group codes of the complex element ;;; (vertices, attributes) as list,
similar to (edlgetent) (defun CPLX-LIST (grp ele / lst) (if (= 1 (getval 66
ele)) (progn (setq ele (entnext (entity ele))) (while (and ele (not (istypep ele
"SEQEND"))) (setq lst (cons (getval grp ele) lst) ele (entnext ele)))
(reverse lst)))) ;;; PLINE-SEGS - Creates a segment list for the polyline pname
;;; as a list of '(bulge p1 p2). A straight line has bulge 0.0 ;;; Compute pts
in ECS of pname. Accepts LWPOLYLINE's (defun pline-segs (pname / pts segs) (setq
segs (mapcar 'list (if (istypep pname "LWPOLYLINE") (group-only 42
(entget pname)) (cplx-list 42 pname)) (setq pts (getpts pname)) (rot1 pts))) ;
-[20.1] (if (flagsetp 1 pname) segs ;closed (butlast segs))) ;open: without the
last segment, -[20.1] ;;; Example: (a bit optimized for brevity :) ;;; add up
all the lengths of all polylines, QUIET ;;; To accept also other entities, add
those to pline-segs (defun C:POLYLEN () (apply '+ (ssmap 'poly-length (ssget
'((0 . "*POLYLINE")))))) ; renamed
For the sum of areas
use either the noisy AREA command or implement heron's formula for polygon areas
(just for simple closed polygons).
[23.6] How to revert a polyline direction?
Sergei
Komarov submitted a REVPOLY.LSP which takes care of bulges and widths too.
<http://xarch.tu-graz.ac.at/autocad/news/lisp_progs/revpoly.lsp>
[24] Circle/Arc Geometry: BULGE conversion, some trigonometry
What is the BULGE in a polyline?
The bulge is the tangent of one
forth of the included angle of a curved segment. A bulge 0.0 means a straight
segment. Together with the start- and endpoint it is sufficient information to
quickly calculate all other required information of a curved segment.
arclength =
radius*angle
bulge =
+-tan(ang)/4
(CCW: +, CW -)
angle =
atan(4*bulge)
bulge =
+-(2*altitude) / chord (CCW: +, CW
-)
See also <http://www.autodesk.com/support/techdocs/fax700/fax797.htm>
for a sample program or the book "Maximizing AutoLISP" [2]
(bugfixed,
wrong formula! Thanks to Sergei Komarov) ;;; SEG2CIR - converts a bulged
segment (bulge pt1 pt2) of a polyline ;;; to a circle (ctr rad). The start- and
endpoints are known ;;; therefore the angles too: (angle ctr pt1)(angle ctr pt2)
;;; returns nil on a straight segment! (defun SEG2CIR (seg / bulge p1 p2 cot x y
rad dummy) (if (zerop (car seg)) nil (setq bulge (car seg) p1 (cadr seg) p2
(caddr seg) cot (* 0.5 (- (/ 1.0 bf) bf)) x (/ (- (+ (car p1) (car p2)) (* (-
(cadr p2) (cadr p1)) cot)) 2.0) y (/ (+ (+ (cadr p1) (cadr p2)) (* (- (car p2)
(car p1)) cot)) 2.0) rad (distance (list (car p1) (cadr p1)) (list x y)) dummy
(list (list x y) rad) ; return this, I hate progn's ) ) ) ;;; ARC2SEG - inverse
conversion: ;;; calculates segment (bulge p1 p2) of arc ;;; with given circle
(ctr rad), start-angle, end-angle (defun ARC2SEG (cir ang1 ang2 / p1 p2) (setq
p1 (polar (car cir) ang1 (cadr cir)) p2 (polar (car cir) ang2 (cadr cir))) (list
(arc2bul p1 p2 cir) p1 p2) ) ;;; ARC2BUL - calculates bulge of arc given the arc
points and the ;;; circle (ctr rad) [fixed by Serge Pashkov] (defun arc2bul (p1
p2 cir / ang) (setq ang (- (angle (car cir) p2) (angle (car cir) p1))) (if
(minusp ang) (setq ang (+ (* 2.0 pi) ang))) (tan (/ ang 4.0))) ;;; BUL2ANG -
returns angle of arc (bulge) (defun bul2ang (seg / ctr) (- (angle (setq ctr (car
(seg2cir seg))) (cadr seg)) (angle ctr (caddr seg)))) ;;; ARC2ANG ;;; calculates
angle of arc given the chord distance and radius (defun arc2ang (chord rad) (*
2.0 (atan (/ chord 2.0 (sqrt (- (expt rad 2) (expt (/ chord 2.0) 2) ) ) ) ) ) )
;;; ARCLEN - length of arc = radius*angle, ;;; Note: +-, you'll need (abs
(arclen seg)) for the distance (defun arclen (seg) (* (cadr (seg2cir seg)) ;
radius 4.0 (atan (car seg)))) ; angle = 4*atan(bulge) (setq *INFINITY* 1.7e308)
; largest double (defun tan (z / cosz) ; [fixed] (if (zerop (setq cosz (cos z)))
*INFINITY* (/ (sin z) cosz))) (defun dtr (ang)(* pi (/ ang 180.0))) ; degree to
radian (defun rtd (ang)(/ (* ang 180.0) pi)) ; radian to degree
[25] DCL: listboxes with tabs or monotext font
Under Windows it's difficult to
layout texts because of non-monospaced fonts.
Try it with the tabs attribute
in the list_box tile, such as: tabs =
"0 20 40"; and (set_tile "listbox"
"Layer:\t0\twhite") or try the following to use monospaced characters:
: list_box { label = "Drawing"; key = "dwglist"; width = 50;
fixed_width_font = true; // Also have a look at the detab routine at <http://xarch.tu-graz.ac.at/autocad/news/detab.lsp>
[26] EED Extended Entity Data: Select, Get and Store
[26.1] Select objects on their EED with (ssget "X")
;;; defines your appname header and delimiter (4 char regapp name ;;; according
AAIG, the Autodesk Application Interoperation Guidelines) (setq appname
"HUBU-") ;;; defines * for all sub types (setq allappnames (strcat
appname "*")) ;;; eg: HUBU-LIST1, HUBU-LIST2 ;;; here is how to get
the eed list from one element (defun geteed-lst (ele) (cdadr (assoc -3 (entget
ele (list allappnames))))) ;;; this gets all elements of appnames typ (wildcards
allowed) (defun ssget-app (typ) (ssget "X" (list (list -3 (list
typ)))) ;;; this gets only your elements (defun ssget-hubu (typ) (ssget
"X" (list (list -3 (list (strcat appname typ))))) (ssget-hubu
"*") ; will get all your elements
[26.2] Get EED from an object
Check any XDATA with: (entget (car (entsel)) '("*"))
These functions return all XDATA
matching the regapp name or all matching XDATA code values. ;;; GETXDATA - get
all XDATA lists from an element ;;; i.e with XDATA: ;;; (-3 ("HUBU-1"
(1000 ."ASSHATCH")(1002 ."{") ;;; (1070 . 1)(1002
."}"))) ;;; =(("HUBU-1" (1000 ."ASSHATCH")(1002
."{")(1070 . 1)(1002 ."}"))) (defun getxdata (e apnlst) (cdr
(assoc -3 (entget e apnlst)))) ;;; GETXDATA-ALL - all lists without the regapp
name ;;; = ((1000 ."ASSHATCH")(1002 ."{")(1070 . 1)(1002
."}")) (defun getxdata-all (e apnlst) (apply 'append (mapcar 'cdr
(getxdata e apnlst)))) The regapp name is stripped here, because it's only used
for fast ssget access. The different apps are divided by different (1000 . name)
groups as it's used by Autodesk.
For storing XDATA in an element
see XDATA.LSP or XED.LSP though those examples are a bit disturbing.
For advanced EED tricks, esp.
converting the "{" "}" ADS resbuf style to Lisp lists and
back see <http://xarch.tu-graz.ac.at/autocad/news/eed_retrieval.txt>
[27] How do I send a Ctrl-C to a command?
Also: "How do I press Break
in AutoLISP?"
(COMMAND) without parameters
works just like hitting Ctrl-C under DOS or ESC under Windows at the command
prompt. But it does not mimic ESC in a dialog box. And it does not work within
SCRIPTS. (command nil) is the same as (COMMAND).
(command) breaks only the
command functions, e.g. if you use the command "DIM" inside AutoLISP,
you must interrupt it by (COMMAND) after dimensioning.
But it doesn't work, if you try
to interrupt a lisp loop. There is another function (EXIT) or (QUIT) -they do
the same-, which immediately break a Lisp program.
Example: (while T ; do ; a never
ending loop (princ "\nEnter a=") (setq a (getint)) (if (zerop
a)(exit)) ; Breaks Lisp and returns to the command mode. ) In this example
(COMMAND) doesn't work. (EXIT) works exactly as Ctrl-C. It prints "error:
quit / exit abort" and outputs all nested functions. To provide
"silent" break you must include this error message to an error
handling function, e.g.: (setq *olderr* *error* *error* my-error) (defun
my-error (s) (if (not (member s ; msgs of the english version: '("Function
cancelled" "console break" "quit / exit abort")))
(princ (strcat "\nError: " s)) ) (setq *error* *olderr*) )
For scripts use this workaround
by defining (cancel) in lisp, simply (defun cancel() (command) (command
"resume") ) and SCRIPT.SCR: .. [script commands] (cancel) [more script
commands] ..
[28] How to decode ACIS internal geometry with Lisp?
All the ACIS objects (3DSOLID)
have been documented by Spatial (SAT Format Description). However the internal
representation by (ENTGET) is still encrypted, but the encryption scheme was
hacked. (XOR 95)
Samples and code are at: <http://xarch.tu-graz.ac.at/autocad/stdlib/samples/ACIS-REGION.LSP>
[new]
[A] Disclaimer, Notes from the authors
If you think of questions that
are appropriate for this FAQ, or would like to improve an answer, please send
email to Reini Urban <rurban@sbox.tu-graz.ac.at
<MAILTO:rurban@sbox.tu-graz.ac.at?subject=FAQ: >> but don't
expect an reply.
This AutoLISP FAQ is Copyright
(c) 1996,97,98,99 by Reini Urban.
The sample code is, if not otherwise stated, (c) 1991-97 by Reini Urban and may
be freely used, but not sold.
The basic functions are, if not otherwise stated, (c) 1991-97 by Reini Urban and
may be freely used.
This FAQ may be freely
redistributed in its entirety without modification provided that this copyright
notice is not removed. It may not be sold for profit or incorporated in
commercial documents (e.g., published for sale on CD-ROM, floppy disks, books,
magazines, or other print form) without the prior written permission of the
copyright holder. Permission is expressly granted for this document to be made
available for file transfer from installations offering unrestricted anonymous
file transfer on the Internet and esp. to be included into the official AutoCAD
FAQ.
If this FAQ is reproduced in
offline media (e.g., CD-ROM, print form, etc.), a complimentary copy should be
sent to Reini Urban, X-RAY, Nibelungeng. 3, 8010 Graz, Austria
This article, the contents and
the sample code, is provided AS IS without any expressed or implied warranty.
[A.1] FAQ Locations
Homepage of the HTML'ified version:
<http://xarch.tu-graz.ac.at/autocad/news/faq/autolisp.html>
The posted ascii versions (and always latest versions)
are at
<http://xarch.tu-graz.ac.at/autocad/news/faq/autolisp.1>
<http://xarch.tu-graz.ac.at/autocad/news/faq/autolisp.2>
The Winhelp version (zipped with faq-code.lsp) is at
<ftp://xarch.tu-graz.ac.at/pub/autocad/news/faq/autolisp.zip>
The FAQ usenet archive is at
<ftp://rtfm.mit.edu/pub/usenet-by-hierarchy/comp/cad/autocad/comp.cad.autocad_AutoLISP_FAQ>
or at <http://www.faqs.org/faqs/CAD/autolisp-faq/part1/>
The Lisp code from this FAQ is at
<ftp://xarch.tu-graz.ac.at/pub/autocad/news/faq/FAQ-CODE.LSP>
A french translation of the FAQ
was made by Roger Rosec
<http://www.newz.net/acadplus/page5101.htm>
A japanese translation of the
FAQ was made by MASAMI Chikahiro
<http://www.page.sannet.ne.jp/chestnutsburr/autolisp-j.html>
A russian
translation by Igor Orellana
<http://www.cad.dp.ua/stats/alfaq_ru.htm>
[fixed]
A partial german
translation by Reini Urban
<http://xarch.tu-graz.ac.at/autocad/news/faq/autolisp.html.de>
A spanish
translation is in progress.
Contact
Eduardo Magdalena.
Relevant AutoDesk FAQ's
<http://www.autodesk.com/support/autocad/faq2000.htm>
<http://www.autodesk.com/support/techdocs/td10/td105129.htm>
AutoDesk news
groups
[changed] news:autodesk.autocad.customization
<news://discussion.autodesk.com/autodesk.autocad.customization>
or the new web interface at Autodesk
<http://discussion.autodesk.com/> and Deja
<http://www.deja.com/group/autodesk.autocad.customization>
[B] Acknowledgements
This FAQ is based on great
efforts of the comp.cad.autocad
<news:comp.cad.autocad> community, in particular:
Adi Buturovic, Christoph
Candido, Mike Clark, Miles Constable, Cara Denko, T.J. DiTullio, Chris Ehly,
Jeff Foster, Rusty Gesner, William Kiernan, Paul Kohut, Sergei M. Komarov,
Joseph M. Liston, Lu, Masami Chikahiro Georg Mischler, Desi Moreno, Vladimir
Nesterovsky, Roger Rosec, Serge Pashkov, Dennis Shinn, Tony Tanzillo, Eugene
Tenenbaum, Reinaldo Togores, Reini Urban, Serge Volkov, Morten Warankov, Owen
Wengerd, Alan Williams, Doug Wilson, Ian A. White, David Whynot, Darren Young,
Xiang Zhu and others.
[C] Recent Changes
25.Apr 2000
added
Point A [1.1], shortened the DDE example
in [21.2]
24.Apr 2000
Vladimir
fixed www.deja.com to deja.com/usenet [1.1]
v2.24 20.Apr 2000
renamed
cadsyst.com to caddepot.com [1], added
cadplugins.com [1], added rapidlisp [6.2],
(added emacs folding)
30.Mar 2000
renamed
adesknews.autodesk.com to discussion.autodesk.com
9.Mar 2000
added
CodeMagic editor at [6.1], thanks to Nir
Sullam
29.Feb 2000
Masami
Chikahiro fixed numeric ranges [7]:
-32766 => -32768
23.Feb 2000
Phil
Kenewell updated LispLink 2000 [6.1].
17.Feb 2000
Added
the dotsoft biglist url [7].
Mike Tuersley fixed [11] for MNL files.
v2.23 14.Feb 2000
Chris
Ehly fixed all broken links.
v2.22 13.Jan 2000
additions
to numerical precision. adesk techdocs
links are broken again. compiled S::STARTUP hooks
v2.216.Dec 99
adesk
faq link, removed peoples urls/emails, minor fixes.
7.Oct 99
wording
in [0.1], german
translation <autolisp.html.de>, link in [28]
v2.2 13.Jul 99
added
topics [0.1] What changed with AutoCAD
2000?, [0.2] Why cannot I create ARX
anymore?, [5.4] Better ones: Common Lisp
and Scheme.
additions
to [6.2] Analyzers, Packagers..., [5.3]
R15 VLISP info, [4] FAS Security, [21.4],
[20.4]: renamed SSAPPLY to SSMAP
13.Apr 99
fixed
a link [1]
v2.1 3.Jan 99
fixed
and added some links: [22.4], [A.1],
[B], [27],
[1], [2],
[20], [22.1]
21.Dec 98
found
a russian translation, bob jones' and masami chikahiro's links are broken
12.Jul 98
changed
posting frequency to monthly. Some minor fixes concerning the now available
Visual Lisp and other cosmetics. cadsyst url
6.Jun 98
changed
Eugene's email (and back at 18.Jul)
13.May 98
added
R14 plotdialog [21.2]
11.May 98
bugfixes
by Serge Pashkov <xrs@aha.ru> in [24]
arc2bul, [20.1] remove-if-not (but
correct in faq-code.lsp), [21.7] doc of
maptrans0-1, [24] tan, [21.2]
DDECMD and some vlisp beta1 fixes in faq-code.lsp
v2.0 7.May 98
lots
of Visual Lisp based changes: [0],[4],[5],[6.1],[7]
[17] new, [2]
new books, [21.2] ActiveX sample, [A.1]better
official R14 FAQ
27.Feb 98
[0]
Visual Lisp available.
24.Feb 98
[6.1]
lspedit.exe, [0] Visual Lisp news and [7] entmake vertex
v1.12 12.Feb 98
Eugene
Tenenbaum <et119@columbia.edu> send me huge list of corrections, mostly
improving the english language. This time only up to [11].
15.Jan 98
[7] HATCH added to entget problem,
[0] more specific now, [22.4]
url change [A.1] Japanese translation
12.Jan.98
[2]
The R13 lisp manual is in the cust. manual not only on the cd. sorry
8.Jan.98
Vladimir
Nesterowsky's new web url
24.Nov.97
fixed
some typos
v1.11 15.Nov.97
changed
header.
Autodesk AutoCAD FAQ URL's. see [A.1]
LispLink editor. see [6.1]
Zoomer rumors: [0]
23.Oct.97
Roger
Rosec provided a french translation of the entire FAQ. see [A.1]
13.Sep 97
Alan
Williams detected a stupid error in DATESTAMP in [22.2]
but in FAQ-CODE.LSP it was okay.
28.Aug 97
added
the (entget) LWPLOYLINE bug to [7],
changed my mail address to rurban@xarch.tu-graz.ac.at to be prepared for the
after-student area. :)
v1.10 22.Jul 97
some
LWPOLYLINE fixes, R14 Lisp debugger Vital
LISP 3.0 shipped, Convert 3.3 update [4.4],
fixed cronjob for bi-weekly posting: every 2nd Monday, 11.30 MET
20.Jul 97
Vital
LISP 3.0 shipped
12.Jul 97
Convert
3.3 update [4.4], fixed cronjob for
bi-weekly posting: every 2nd Monday, 18.00 MET
2.July 97
fixed
URL in [10],
30.June 97
fixed
(istypep) in [20.4], changed title of [16],
light changes in (getpts) in [23.1]
v1.9 26.June 97
[5.2] confirmed Vill3 release date, added DDE sample from Xiang
Zhu to [21.2], provided detab.lsp [25]
17.June 97
bugfix
in [20.4]: short (getval), [12]
R14 ARX autoloading, [23.5] (pline-segs)
is now R14-save but still not compatible, new [23.6]
revpoly.lsp, [A.1], [5.2]
Vill 3 will have reactor support.
9.June 97
new
symbol-string trick by Christoph Candido [20.3]
21.May 97
some
minor corrections.
v1.8 15.May 97
added
[0] Future of AutoLISP?
changed VERTECES to VERTICES, fixed mail address of af.buturovic@berwanger.com,
added SSAPPLY: [20.4], [23.5],
started to R14'ify some code for LWPOLYLINE's [23],
not finished yet, (pline-segs) is missing
9.May 97
[2.1] R14 Winhelps, [5.2]:
new basis url, Vill Lite [6.1]
added [16]: Lisp over mult. dwg's
added some short comments to [6.1](ntemacs),
[14], [21.8]
21.April 97
added
[[28] ACIS decryption
v1.7 9.April 97
added
[[21.8] C:XYZ,
added [[15] (command
"ROTATE3D") does not work! Why?
HTML version chapter numbers match the posted version,
added [27]: (command) as ctrl-c, Sergei
Komarov improved [27], Adi Buturovic improved [27] for scripts.
v1.6 13.Feb 97
moved
the intro to the very beginning for the curious.
another lisp plot lisp [21.2], a third lisp debugger [3.1], [A.1]: the gd.tuwien
uunet mirror is faster than the official ones, fixed cadence FAQ url, applied
digest format partially, html will be created automatically soon, wrong (old)
chapter numbering from the v1.5 version, [7] 64 in flag 70 in symbol tables,
v1.5 5.Feb 97
added
get and edlgetent samples by Vladimir, removed the sort code instead,
changed [11] title and added string funcnames,
bugfix in getpts [23.1], basic funcs should be free [A],
added DATESTAMP to [22.2], added a "s" to [A] title,
added [20] DCL, [21] EED, [21.1-21.7] samples,
Serguei Komarov found a bug in seg2cir,arclen,arc2bul [24],
added arc2ang and (corrected) arclen,
bugfixes in sslist, getval, all predicates with "p" postfix now,
prepared a FAQ-CODE.LSP, Convert supercedes Decrypt [4.4], added scripts and
(command) to [23.4], AREA to [23.5],
v1.4 24.Jan 97
important
news with Decrypt [4.4],
moved [11] "bugs" to [7] "problems",
added [11] "How do I (sym, list)" instead,
added the "Approved" header for news.answers processing,
added [22]-[24]: some examples for subentities and bulge stuff,
Serge found a bug/feature in acad_strlsort [7],
added number accuracy and ss limitation to [7],
added break code and samples to [3.3],
added a short lisp style guide at [2.2], instead of [6.4]
v1.3 17.Jan 97
added
[16] stack overflow (thanks Serge), [4.7] Lisp2C,
updated [8] fastest sort (sample, benches),
received the news.anwsers approval
v1.2 11.Jan 97
added
Phoaks to news archive
fixed (break) in [3.3] (Thanks Tony),
added a sorting example to [8], improved (my-princ) in [15]
changed posting frequency from weekly to bi-weekly
v1.1
4.Jan 97
R13
bugs, S::STARTUP code by Owen Wengerd,
homepages instead of e-mail adresses where appropriate, (people get enough junk
mail these days)
more links, and some bugfixes
v1.0
22.Dec 96
First
version, posted on 28.Dec 96
as a discussion basis