The Visual LISP Editor
The Visual LISP Editor
The Visual LISP Editor
id=EOrpBwAAQBAJ&pg=PA180&lpg=PA180&dq=how+to+int
erpreting+the+autocad+command+to+autolisp&source=bl&ots
=ZiMzAwQsWL&sig=ACfU3U18hajT-Cqv4iOP-ZQ0KzBoj-
1Irw&hl=vi&sa=X&ved=2ahUKEwj2_dPLwt3hAhUKpo8KHerh
A-UQ6AEwC3oECAcQAQ#v=onepage&q=how%20to
%20interpreting%20the%20autocad%20command%20to
%20autolisp&f=false
https://forums.autodesk.com/t5/visual-lisp-autolisp-and-
general/autolisp-books/td-p/846456
http://doannghiep.tk/download/c49QAAAAMAAJ-essential-
autolisp
https://knowledge.autodesk.com/search-
result/caas/CloudHelp/cloudhelp/2016/ENU/AutoCAD-
AutoLISP/files/GUID-234D7B54-1972-4E84-9CFB-
1057DE3D10EB-htm.html
https://www.afralisp.net/autolisp
https://www.afralisp.net/visual-lisp/tutorials/beginning-
visual-lisp-part-1.php
http://www.jefferypsanders.com/autolisptut.html
https://www.pdfdrive.com/autolisp-books.html
http://www.jefferypsanders.com/autolispbeg.html
https://knowledge.autodesk.com/search-
result/caas/CloudHelp/cloudhelp/2016/ENU/AutoCAD-
AutoLISP/files/GUID-38D0244E-C0C7-4FF0-A4B9-
DE6E05635BD6-htm.html
http://www.perthcadservices.com.au/index.php/cad-bim-3d-
printing-blog/55-the-best-5-auto-lisp-routines-that-every-
autocad-drafter-must-know-about
- https://forums.autodesk.com/t5/visual-lisp-autolisp-and-
general/convert-autolisp-commands-to-cad-
commands/td-p/1649416
- https://forums.autodesk.com/t5/visual-lisp-autolisp-and-
general/converting-macro-to-lisp/td-p/2395139
- https://knowledge.autodesk.com/search-
result/caas/CloudHelp/cloudhelp/2016/ENU/Auto
CAD-AutoLISP/files/GUID-75F19C76-78D0-443B-
BC39-EB9FEB4650B1-htm.html
- https://www.cadtutor.net/tutorials/autolisp/quic
k-start.php
- https://www.scribd.com/document/12318800/Aut
oLisp
- https://www.scribd.com/search?
content_type=documents&page=1&query=Essenti
al%20AutoLISP
- http://www.4d-technologies.com/techcenter/
-
- https://www.google.com.vn/search?
sa=N&biw=1242&bih=547&q=how+to+interpreting+the+
autocad+command+to+autolisp&tbm=isch&source=univ
&ved=2ahUKEwimtbfowt3hAhUIYo8KHWlrCMI4ChCwB
HoECAkQAQ
-
https://www.youtube.com/watch?v=cBTQ0uHaI4Y
https://www.afralisp.net/visual-lisp/
http://www.theswamp.org/index.php?topic=41040.0
https://stackoverflow.com/questions/17964480/build-
automation-for-autocad-lisp-files
https://www.youtube.com/watch?v=Jlw3UgFSiKM
https://www.youtube.com/watch?v=cBTQ0uHaI4Y
http://ntdh.warriorcry.fun/g5zckL1EtWc/Tutorial_Visual_Lisp
_Autocad_0007_Programando_DCL/
https://news.ycombinator.com/item?id=19677292
(:Region2Polyline ss)
(princ)
)
5 AUTO LISP routines
that every AutoCAD
drafter must know
about.
What is AutoLISP? AutoLISP is a dialect of the LISP
programming language built specifically for use with the full
version of AutoCAD. It is used to create programs to use in
Autocad that are not built in with the software. Almost all
manual commands you use can be automated to increase
productivity, Lisp routines can do all sorts of weird and
wonderful things. Below are my top 5 favorite LISPs programs
that if introduced will save you lots of time.
5) Block count
Lee Mac’s Block count this program enables the user to record
the quantities of a selection or all standard or dynamic blocks in
the working drawing. The results of the block count may be
displayed at the AutoCAD command-line, written to a Text or
CSV file, or displayed in an AutoCAD Table, where available.
3) Trim around
Trim around Text by Yuqun Lian This routine writes a text string
to the drawing and then breaks any lines, polylines, etc. that
intersect an imaginary box around the text. The text is placed on
the current layer using the current style. The default input and
repeat capabilities of TB.LSP make multiple labeling very
convenient.
2) Double offset
Back to Lee Mac again for the double offset, if you find you start
all your drawings in the center line then this one is for you. This
program operates in much the same way as the standard offset
command, however will perform an offset to both sides of the
selected object.
I hope you will find these new Lisp programs useful and
productive in your everyday Autocad drafting life, please feel
free to share your own in the comments.
Below are some more useful links for more LISP programs.
http://www.lee-mac.com/programs.html
http://paulogilsoto.blogspot.com.au/2009/10/links-to-lisp-
routines.html
http://www.simplecad.com/autolisp-files
http://web2.airmail.net/terrycad/AutoLISP-Code.htm
http://www.perthcadservices.com.au/index.php/cad-bim-3d-
printing-blog/47-more-productive-cad-drafting
AutoLISP Quick Start
by Kenny Ramage
Introduction
This tutorial is aimed at the AutoCAD users who would like to start learning AutoLisp. I suggest that
you go through this tutorial along with the AutoCAD Programmers Reference Guide. You can then
lookup the relevant AutoLisp commands for a more detailed explanation. Hope this helps you and
Good Luck in your Lisping - Kenny Ramage
Principles of Programming
All AutoLisp programs must contain the suffix ".LSP" otherwise AutoCAD will not access them when
loading. (eg. CHTEXT.LSP).
Use a simple text processor such as Notepad to create and edit your lisp files.
Is a pre-defined set of instructions that describes a set of actions that AutoLisp is to perform, divided
into three sections:
Charting
Draw out or write out in English what you want your program to do.
Variables
These are like empty boxes in which to store data, to be used later. In AutoLisp, variables may be a
collection of letters or numbers as long as they begin with the letters.
A
ARC1
POINT1
PNT1
D3
An AutoLisp variable may contain more than one value in a single variable. A value can be anything,
such as :
Real number
String
Integer
Pickset
Structuring
Structure your program in such a way that it is easy to understand, by yourself and everyone else. e.g.
Keep input statements together. Keep your arguments together. Keep your commands together. Track
your work with the semicolon. When you begin a line with a semicolon, anything you write after will be
ignored by AutoLisp. It is used for documentation and explanation of your program. Write notes about
your program, what you are doing and what the variables are. A semicolon does not have to begin the
line.
(prompt "This line will print"); This is a comment
From where the semicolon begins, the remainder of the line is a comment statement.
Parentheses ( )
Parentheses are vital to writing AutoLisp programs. All commands are surrounded by parentheses.
AutoLisp uses parentheses to nest, allowing you to write a command that acts on (evaluates) another
command. In turn, that command can act on another. As you add parentheses, you're nesting
commands become deeper and deeper. Remember to come out of the nest with an equal number of
parentheses.
(defun functionname ()
body of program
Defun is the first actual command and is followed by the name of the function (or program). Defun
encloses the entire program and its closing bracket comes after the main body of the program There
are different ways of starting a function for example:
1. (defun drawline ()
The first way, you are saying that all variables you plan to use in the program are GLOBAL,
which are variables that do not lose their value after the program ends.
2. (defun drawline (/ pntl pnt2)
The second way, you are saying that the variables you are using are LOCAL variables, which
are variables that have value only for that program and while that program is running.
3. (defun C:drawline ()
The third way, as the first BUT the C: tells AutoCAD to treat that function as any other
AutoCAD command.
4. (defun C:drawline (/ pntl pnt2)
Data Types
Integers
Are numbers ranging between -32768 and +32767 without decimal points eg: 1
Reals
Are numbers with a decimal point eg: 1.0
Strings
Strings are bits of text and can be up to a maximum length of 100 characters eg: Point 1
Lists
A list is a variable that has more than one element. A point in your drawing is described by the value of
the X co-ordinate and the value of the Y co-ordinate. In AutoLisp, that point can be described by a
single variable, a list of two elements, the first being the X value and the second being the Y value
eg: ( 7 10 ). The following are also examples of lists: ( 5 9 7 2 ) and ( 1.5 2.3 4.9 ).
Atoms
If a variable has a single indivisible value it is an atom. For example, each element in the lists above is
an atom e.g. 6 or A
The type function will return the data type of a variable. For example:
(type "My name")
Will return STR meaning "string". In fact, you can try this for yourself now. Type the code above at the
AutoCAD command prompt and hit enter.
Input Commands
getcorner Needs a second point on the screen and draws an elastic window from a previous point.
getdist Needs a value either by picking on the screen or a number from the keyboard.
getangle Needs an angle either by pointing on the screen or by typing an angle, which will be returned
in radians.
initget Establishes various options for use by the next getxxx function.
getorient Is similar to the GETANGLE but is affected by the zero-degree base and the direction. It will
always give you the absolute angle using 0 degree base as EAST.
Tip: \n is a special escaped character that takes you to the next line (like a carriage return).
The forward slash character tells AutoLisp to interpret the following character as a special
character rather than just as a letter "n". The "n" must be always be lower case. The use of "\n"
is purely cosmetic (it doesn't change the way the program works) but it does make everything
much easier to read for the user by starting each prompt on a new line.
Caution: Your prompt must always be between quotes, "prompt" otherwise you will get an
error.
that number.
that text.
Or…
(getstring T "\nWhat is your full name? :") This prompt allows you to enter a
string of words separated by spaces. Ordinarily, AutoCAD will interpret a space in the same
way it interprets a carriage return. The T is a special AutoLisp symbol that means "true" it is
used to allow spaces in string input. In fact, you can use any positive integer (such as 1) in
place of T but the T symbol helps to make the code more understandable.
6. (getdist "\nHow long is the line? :") Pick two points or type a length and
function and is used to specify a list of valid options or keywords, getkword will accept only
one of the words specifies using initget. In this case, the options are "Yes" or "No". The 1 is an
initget bitcode and it means that a null response is not allowed. See the section below for
more details.
Tip: Just as in native AutoCAD commands, any valid option keyword can be entered simply by
typing the upper case part of the keyword. So, in the example above, to answer Yes to the
prompt, you need only type "y" but to answer NO, you must type "no". This is used to avoid
potential ambiguities when 2 or more options begin with the same letter.
9. (getvar "FILLETRAD") Would return the set value of the FILLETRAD system variable
(fillet radius) eg : 0. 5
angle and AutoLisp will return an angle in radians relative to 0 degrees at East.
(initget (+ 1 2 4))
(getint "\nHow old are you?:")
Setq Command
Short for (Set Equal) or make one thing equal to another.
(setq) is an assignment command, eg : it assigns the value of one variable or constant to another
variable.
Note: (setq) is the primary assignment command in AutoLisp. The "=" (equals character) is not used
as an assignment in AutoLisp. The equals character is used, but only as a non assignment statement.
It does not have the ability to make one variable equal to another as it does in some other
programming languages (it is used for a comparison of variables, numbers or strings).
(setq a b)
This statement assigns the value of b to the variable a so that a becomes the same as b and b is
unchanged.
Note: The first variable after the (setq) is the one that receives the value. Watch out for this because it
is a potential cause of confusion.
Print Commands
Prompt
(prompt "Maybe you need a rest")
This command is used simply to print a message on the command line. A line feed (\n) is not included
so two consecutive prompt commands will print both messages on the same line and without any
spaces between them. Therefore, any printing after the prompt must be preceeded by
the (terpri) function or \n.
Terpri
This is a line feed that causes the next printed text to appear on the next line. It generally follows the
prompt command. eg:
(prompt "Hello, how are you?")(terpri)
or
(prompt "\nHello, how are you?")
Prin1
This function prints the expression on the screen and returns the expression. It can be any expression
and need not only be a string. The expression can also be written to a file and will appear in the file
exactly as it would on the screen.
(prin1 a f) would print the value of variable a to an open file named in variable f.
Princ
Is the same as prin1 except that the control characters ("") are not printed. Can also be used to print a
blank line by using no statement after princ.
Same as prin1 except that a new line is printed before the expression and a space is printed after the
expression.
Setvar
This function sets an AutoCAD system variable to a given value and returns that value. The variable
name must be in double quotes. eg:
(setvar "blipmode" 0) returns 0 and will switch blipmode off. 1 would switch it on again.
Doing Arithmetic
AutoLisp provides a number of arithmetic functions and although the format of these functions is
consistent with other AutoLisp functions (function first, followed by values), it is not one we are familiar
with from school. The important thing to remember is that the order of the values is consistent with
what we already know. In other words (/ 27 3) is the same as 27 divided by 3.
(+ 1 1) returns 2.
( 2 1) returns 1.
(* 2 2) returns 4.
(/ 2 1) returns 2.
Polar
This function returns the point at an angle (in radians) and distance from a given point.
(polar pnt1 ang1 dist1) where pnt1, ang1 and dist1 are 3 previously assigned variables.
Inters
Examines two lines and returns the point where they intersect even if they do not physically cross one
another.
(inters pnt1 pnt2 pnt3 pnt4) where pnt1 and pnt2 are the end points of one line and pnt3
(command "line" pnt1 pnt2 "") draws a line from pnt1 to pnt2 and the "" acts as a return to
Not all commands require termination since some, like circle are self terminating.
(command "circle" cen cir) where cen is the centre of the circle and cir is a point on the
circumference.
You can try this out using some values at the command prompt to see how this works:
(command "circle" "100,100" "150,150")
Note: values in expressions must be enclosed in quotes whereas variable names are not.
The following code will draw a square using a polyline, specifying 4 points and then C to close:
(command "pline" "50,50" "50,70" "70,70" "70,50" "c")
Elements from a List
When you used (setq a (getpoint)) you assigned the X and Y coordinate numbers to
variable a. That Variable now is a list that may look like (5 10). If you want to look at the list in
variable a, AutoLISP gives you a convenient way to do that from the command line.
!a Placing the ! (exclamation mark character) in front of the variable will display the value or values of
that variable.
(setq b (car a)) would assign to the variable b the value of the first element in a which is 5.
(setq b (cdr a)) would assign to variable b the second and remaining elements of the list in
variable a which is (5 7 9 11).
then:
5) then:
Example Programs
Drawing things
This program draws a rectangle by pointing to two points
(defun c:retan (/ pl p2 p3 p4)
(setq pl (getpoint "\nfirst corner of rectangle: "))
(setq p3 (getcorner "\nsecond corner of rectangle: "))
(setq p2 (list (car pl)(cadr p3)))
(setq p4 (list (car p3)(cadr pl)))
(command "line" pl p2 p3 p4 "c")
(princ)
)
Converting data
(dtr) converts degrees to radians
(defun dtr (a)
(* pi (/ a 180)) )
(defun rtd (a)
(/ (* a 180) pi)
Things to strings
strcase (string case)
Changes a string of text from lower case to upper case, leaving upper case characters as they are. eg:
(strcase a) returns the alphabetic characters in variable a from lower case to upper case.
strcat (string cat)
strlen (string length)
Returns the length, of the characters of a string. eg:
(strlen "hello") returns 5.
substr (substitute string)
Returns a part of a string, from a specified position, ending either at the end or another specified
position. eg:
List Manipulation
The apostrophe character, ' serves a special function in AutoLISP. For example, if a group of items is
Angle
Returns an angle between two points in radians. To use that angle in AutoCAD you have to convert it
back to decimal degrees. eg: (setq a (angle pnt1 pnt2)) sets the angle
between pnt1 and pnt2 to the variable a.
To use a:
is in radians.
Append
Takes any number of specified lists and joins them together as one list. eg:
(append a b) returns the list in variable a and the list in variable b as one.
Distance
Measures the distance from two known points. eg:
Length
Returns the number of elements in a list. eg:
(length '(a b c d)) returns 4.
Member
Looks for a match and returns that and the rest of the list eg:
Nth
Returns the nth element in a list, where n is the number of the element to return. (Zero is the first
element). eg:
(nth 3 '(a b c d)) returns d.
Assoc (associative)
Often used with the (subst) function; the (assoc) function lets you search for a specific element,
Lets assume variable b is the list ((10 5.5 2.7)(40 5)) and you are looking for a value 40. You want to
pull out the entire element and assign it to a variable c. eg:
(setq c (assoc 40 b))
This assigns the entire element containing the 40 in the list b to variable c. Now c is a list that looks
Subst (subsitute)
Allows you to substitute one aspect for another. When substituting ALWAYS substitute the new item for
the old in the list. Now lets substitute 20 for the 5 in the variable c.
(setq b1 (subst '(40 20) c b))
Now b1 is the new list.
'(40 20) is the new element substituted for the old element (40 5) c, found in list b.
(setq bl (subst '(40 h) c b)) … looks like it should work, but it does not. The new element
(subst) cannot interpret variables. You need to construct a new variable containing the entire list
element, then use the new variable in the (subst)function.
Cons (construct)
Constructs a new list with the new element placed at the begining. Assume variable c contains the
following list: (40 5). Also, assume variable h contains the real number 20.0 then:
(setq d (cons (car c) h)) Remember, (car c) gives you 40. Therefore, (car c) is the new
first element, followed by the value of h. Thus it produces a new list d (40 20.0).
Now we substitute:
(setq b1 (subst d c b)) That substitutes the new element found in variable d for the old
element found in variable c. (In the list found in variable b) and assigns the new list to b1.
Conversions
Angtos (angle to string)
Takes an angle in radians and converts it into a string, using a specific format. Angtos has two
arguments, the first controls the format and the second controls the precision.
0 Degrees
1 Degrees/minutes/seconds
2 Grads
3 Radians
4 Surveyor's units
Fix
This function returns the convertion of a real number to an integer and drops the remainder. eg:
(fix 8) returns 8
(fix 8.6) returns 8
Float
This function returns the convertion of an integer to a real number. (One can use either real or an
integer.) eg:
Ascii
Returns the convertion of the first character of a string into its ASCII character code. (an integer) eg:
(ascii "a") returns 97
(ascii "A") returns 65, upper and lower case characters have different ascii character codes.
(ascii "BLUE") returns 66
(ascii "BALL") returns 66, only the first character is evaluated.
Chr
Returns the convertion of an Integer representing an ASCII character code into a single character
string. eg:
1 Scientific
2 Decimal
The real number can be set according to mode and precision. eg:
(atoi "25") returns 25
Conditionals
In AutoLisp, the equals character (=) is not an assignment function. In other words, it is not used to
equal, it does not make them equal. This is very useful if we are trying to test certain conditions. For
example, we can begin to construct tests with an outcome such as "if one thing is equal to another
thing, do something". That's what conditionals are all about; they allow your program to make
decisions.
If
(if) is the standard if-then-else statement. In AutoLISP you may only match one if statement with a
(if (= a b) (setq b 5 (setq b 6))
If a is equal to b, then b will be assigned the value 5. If it is not, then b will be assigned the value 6.
Cond (conditional)
This function accepts any number of lists as arguments. It evaluates the first item in each list (in order
supplied) until one of these items is a value other than nil. eg: A user's response string is variable s.
(cond
((= s "Y") 1)
((= s "y") 1)
((= s "N") 0)
((= s "n") 0)
(t nil)
)
This function tests the response and returns 1 if it is "Y" or "y", and 0 if it is "N" or "n",
and nil otherwise.
Repeat
Similar to a loop but repeat will only go through the commands as many times as is told. eg:
(setq a 10)
(setq b 100)
(repeat 3
(setq a (+ a 10))
)
(setq b (+ b a))
)
Returns 140.
While
Is another loop control command available in AutoLISP. A loop is necessary if you want to repeat a
command. However, unless you have a way of controlling it, the program will run forever and hang you
up. eg:
to nil.
(…some functions…) Are the functions that are performed in the loop.
(if (= c d) (setq a nil)) Evaluates if c is equal to d, and if so, sets the loop controlling
variable a to nil to end the loop.
) A closing parenthesis closes the loop, and program will continue with the commands after this.
Entities
An entity is the smallest object you can place on your screen. The following are entities: LINE,
CIRCLE, ARC, TEXT, POLYLINES, etc. Entities are stored and referenced in the drawing database.
They can be changed and manipulated using AutoLISP to suit your needs. Each entity has a massive
definition in AutoCAD's database. eg: The data for a single line contains the following info:
Entity name, Entity type, Layer, Color, Beginning X Y coordinate, Ending X Y coordinate, Line type,
etc. You can modify any of the above aspects. An example of an entity list:
( 1 <Entity name: 60000014) (0 "CIRCLE") (8 . "LAYER1")
(10 . 50.000 100.000) (40 . 60.000)
It is an entity list of a circle on layer LAYER1, center point relative to 0,0 of 50.0,100.0 , and a radius of
60.0
(setq a (ssget)) will prompt you to select objects. You have now created a selection set with a
specific name, <Selection set:l> ,assigned to variable a, or use filter option (setq a (ssget "X"
'((0 . "TEXT")))) to search database for certain entities or codes.
Ssname (get entity name)
Lets you secure the name of the entity. The name of the entity is realy a hexadecimal number,
therefore don't expect to see a name like LINE, or CIRCLE etc. The name of your entity might be
60000018.
Lets assume variable a is the selection set and variable i is set to 0. (setq i 0) To set Counter
variable. (setq na (ssname a i)). This assigns nathe entity name found in the selection set a at
index number i. Remember that a selection set may contain more than one entity name. You can
point to each entity by using its relative number in the selection set. eg: Entity 1 is Index 0 , Entity 2 is
Index 1 , etc.
Sslength
Gives you the length or number of selections made.
More Examples
Change Cross Hair Angle
This program permits you to draw lines perpendicular to other lines. The program measures the angle
of the line chosen, and shifts the SNAP ANGLE to the angle of that line. Use ORTHO ON and draw
perpendicular to your chosen line.
(defun c:perpdon (/ a b pntl pnt2 angl) (graphscr)
(setq a (entsel))
(setq b (entget (car a)))
(setq pntl (cdr (assoc 10 b)))
(setq pnt2 (cdr (assoc 11 b)))
(setq angl (angle pntl pnt2))
(setvar "snapang" ang1)
(princ)
)
(defun c:perpdoff (setvar "snapang" 0)
(princ)
)
Erase Screen
Erases everything on the drawing screen. If you are in a ZOOM ALL position, the program erases
everything within the limits of the drawing.
Note: if you accidentally invoke this command, you can recover with OOPS.
(defun c:erasescr (/ l u)
(setq l (getvar "limmin"))
(setq u (getvar "limmax"))
(command "erase" "w" l u "")
(princ)
)
Change Layer
Lets you select objects by any selection method and change their layer. The target layer is chosen by
simply pointing to an object on the desired layer. All objects selected will then change to that target
layer. To test this program, you will need to create a drawing with objects on different layers.
(defun c:chlayer (/ a1 a2 n index b1 b2 d1 d2 b3)
(graphscr)
(prompt "\nselect entities to be changed: ")
(setq a1 (ssget))
(prompt "\npoint to entity on target layer: ")
(setq a2 (entsel))
(setq n (sslength a1))
(setq index 0)
(setq b2 (entget (car a2)))
(setq d2 (assoc 8 b2))
(repeat n
(setq b1 (entget (ssname a1 index)))
(setq d1 (assoc 8 b1))
(setq b3 (subst d2 d1 b1))
(entmod b3)
(setq index (+ index 1))
)
(princ)
)
(defun c:chlayer (/ a1 a2 n index b1 b2 d1 d2 b3)
(graphscr)
(prompt "\nSelect entities to be changed: ")
(setq a1 (ssget))
Allows you to select the objects to be changed. The selection set is assigned to variable al.
(prompt "\npoint to entity on target layer: ")
(setq a2 (entsel))
This is a special type of selection statement that allows you to select only one entity.
(setq n (sslength a1))
(setq b2 (entget (car a2)))
This statement gets the entity list from a2. Thus, a2 is assigned the entity list.
(setq d2 (assoc 8 b2))
This looks for the code 8 in entity list a2, then assigns the sublist to d2.
(repeat n
This begins the loop that pages through the selection set.
(setq bl (entget (ssname a1 index)))
(setq d1 (assoc 8 b1))
(setq b3 (subst d2 d1 b1))
Substitutes the new d2 layer for the old d1 layer in the entity list a1, and assigns it to the new entity
list b3.
(entmod b3)
(setq index (+ index 1))
Increases the index variable by 1, making it ready for the next loop. The first ) closes the repeat
loop. (princ) exits quietly. The second ) closes the function.
Substitute text
This program lets you choose a line of text and substitute another line at exactly the same place.
(defun c:subtext (/ a b d e d1 b1 y)
(prompt "\nSelect text line: ")
(setq a (entsel))
(setq b (entget (car a)))
(setq d (assoc 1 b))
(prompt (cdr d))(terpri)
(setq e (getstring 1))
(setq d1 (cons (car d) e))
(setq b1 (subst d1 d b))
(entmod b1)
(setq y (getstring "\nIs this correct Y : "))
(if (= (srtcase y) "N") (entmod b))
(princ)
)
(defun tex (/ p1 a b c d e f)
(setq pl (getpoint "\nStarting point: "))
(setq a (getdist p1 "\nEnter height: "))
(setq c (getdist p1 "\nline spacing: "))
(setq d "T")
(while d
(setq e (getstring 1 "Text: "))
(command "text" pl a "0" e)
(setq pl (list (car p1)( (cadr p1) c)))
(setq f (getstring))
(if (= f "*")(setq d nil))
)
(princ)
)
(defun chtext (/ a ts n index b1 b c d b2)
(setq a (ssget))
(setq ts (getreal "\nEnter new text size"))
(setq n (sslength a))
(setq index 0)
(repeat n
(setq b1 (entget (ssname a index)))
(setq index (1+ index))
(setq b (assoc 0 b1))
(if (= "TEXT" (cdr b))
(progn
(setq c (assoc 40 b1))
(setq d (cons (car c) ts))
(setq b2 (subst d c b1))
(entmod b2))))
(princ)
)
Topic này được mở để thảo luận và chia sẽ những kinh nghiệm sử dụng trình
soạn Visual LISP Editor với các bạn mới bắt đầu và những ai có nhu cầu. Chúng
tôi chân thành đón nhận những hướng dẫn; góp ý và các câu hỏi, vướng mắc
được đặt ra trong quá trình sử dụng VLIDE, từ đó anh em thảo luận để có hướng
giải quyết vấn đề, ngỏ hầu phục vụ anh em được tốt hơn. Chúng tôi không mong
đợi những comment không mang tính đóng gốp; ly khai và cực đoan, xin lỗi vì
chúng tôi chưa được rèn luyện công phu "né đá". Chân thành cám ơn sự quan
tâm và mong chờ sự chia sẽ, đóng gốp của tất cả các bạn trong diễn đàn. Cầu
chúc niềm vui; sức khỏe và thành công cho các bạn!
Một chương trình AutoLISP có thể được viết bằng bất cứ chương trình soạn thảo
văn bản nào (Notepad; WordPad; MS.Word; Notepad++), sau đó lưu lại với đuôi
*.LSP. Tuy nhiên, với các trình soạn thảo này, chúng ta chỉ thuần túy vi ết code
mà không hề được hỗ trợ các công cụ để có thể chạy thử, tìm lỗi và gỡ lỗi.
AutoCAD chính nó đã cung cấp một trình soạn thảo Visual LISP, thỏa mãn được
các đòi hỏi trên.
Chân thành cám ơn các bạn đã tham gia thảo luận trong
topic: Gia_Bach; Tue_NV; Doan Van Ha; Song Nhi : ndtnv ;
Mục lục tổng kết một số tiện ích của Visual LISP Editor đã được thảo luận trong
topic
1/- Kiểm tra và gỡ lỗi code, tham khảo tại: [#6] và [#49].
2/- Giải phóng bộ nhớ bằng cách chuyển danh sách biến toàn cục thành biến cục
bộ, tham khảo tại: [#19]; [#21]; [#22] và [#50].
3/- Quản lý lisp bằng tiện ích Project, tham khảo tại: [#20] và [#24].
6/- Xem cú pháp hàm trực tiếp trong VLIDE, tham khảo tại: [#38].
7/- Xem trước giao diện DCL, tham khảo tại: [#40].
9/- Và các tiện ích khác, đang chờ các bạn bổ xung ...
Báo cáo bài đăng
Topic này được mở để thảo luận và chia sẽ những kinh nghiệm sử dụng trình
soạn Visual LISP Editor với các bạn mới bắt đầu và những ai có nhu cầu. Chúng
tôi chân thành đón nhận những hướng dẫn; góp ý và các câu hỏi, vướng mắc
được đặt ra trong quá trình sử dụng VLIDE, từ đó anh em thảo luận để có hướng
giải quyết vấn đề, ngỏ hầu phục vụ anh em được tốt hơn. Chúng tôi không mong
đợi những comment không mang tính đóng gốp; ly khai và cực đoan, xin lỗi vì
chúng tôi chưa được rèn luyện công phu "né đá". Chân thành cám ơn sự quan
tâm và mong chờ sự chia sẽ, đóng gốp của tất cả các bạn trong diễn đàn. Cầu
chúc niềm vui; sức khỏe và thành công cho các bạn!
Một chương trình AutoLISP có thể được viết bằng bất cứ chương trình soạn thảo
văn bản nào (Notepad; WordPad; MS.Word; Notepad++), sau đó lưu lại với đuôi
*.LSP. Tuy nhiên, với các trình soạn thảo này, chúng ta chỉ thuần túy vi ết code
mà không hề được hỗ trợ các công cụ để có thể chạy thử, tìm lỗi và gỡ lỗi.
AutoCAD chính nó đã cung cấp một trình soạn thảo Visual LISP, thỏa mãn được
các đòi hỏi trên.
Chân thành cám ơn các bạn đã tham gia thảo luận trong
topic: Gia_Bach; Tue_NV; Doan Van Ha; Song Nhi : ndtnv ;
Mục lục tổng kết một số tiện ích của Visual LISP Editor đã được thảo luận trong
topic
1/- Kiểm tra và gỡ lỗi code, tham khảo tại: [#6] và [#49].
2/- Giải phóng bộ nhớ bằng cách chuyển danh sách biến toàn cục thành biến cục
bộ, tham khảo tại: [#19]; [#21]; [#22] và [#50].
3/- Quản lý lisp bằng tiện ích Project, tham khảo tại: [#20] và [#24].
6/- Xem cú pháp hàm trực tiếp trong VLIDE, tham khảo tại: [#38].
7/- Xem trước giao diện DCL, tham khảo tại: [#40].
9/- Và các tiện ích khác, đang chờ các bạn bổ xung ...
Mời các Bác tiếp tục chia sẽ những kinh nghiệm sử dụng Visual LISP Editor!
Similar topics from web:
Chapters 3, 4 and 5. Using AutoLISP/Visual LISP functions
Autodesk
Chapters 1 and 2. Introduction to AutoLISP/Visual LISP
Can anyone explain the design decisions behind Autolisp/visual lisp ...
Visual Lisp: how to call functions in external C++ DLL
AutoLISP: Select block by name | AutoCAD Tips
Beginning Visual LISP
AutoLISP
LISP for AutoCAD
Plain and Simple AutoLISP Routines | Facebook
Help: Lesson 2: Using Visual LISP Debugging Tools (AutoLISP)
Determine in which line of AutoLISP code an error exists
Sử dụng AutoLisp trong AutoCad
Em là người mới bắt đầu học LISP, món này rất cần thiết đây!
@ Bác Thaistreetz ơi, Bác là một trong các cao thủ trong ngành này, bác chia
sẽ những kinh nghiệm của mình để hướng dẫn tụi em với, tựa đề bằng tiếng Anh
thế mọi người cũng hiểu được mà, như Slogen của Bác đấy thôi, cũng toàn tiếng
Anh cả đấy chứ!
Em xin trình bày lại yêu cầu của bạn ấy: Nhập vào 2 điểm và một khoảng offset,
vẽ hình chữ nhật nhận 2 đỉnh ấy làm 2 đỉnh chéo, kết quả là HCN được offset từ
HCN chuẩn ra hay vào trong một khoảng bằng khoảng nhập vào. Code của
em đây:
(defun pxy(d x y) (polar (polar d 0 x) (* 0.5 pi) x))
(defun SN(id / )
(setq D1 (getpoint "\nVui long pick diem Bottom Left\n")
D3 (getcorner D1 "\nVui long pick diem Top Right\n"))
(setq an (getint "\nVui long nhap khoang offset: <110>\n")) (if (= an
nil) (setq an 110))
(setq bn (- 0 an))
(setq D2 (list (car D1) (cadr D3))
D4 (list (car D3) (cadr D1)))
(cond
((= id 1) (setq D11 (pxy D1 bn bn)
D22 (pxy D2 bn an)
D33 (pxy D3 an an)
D44 (pxy D4 an bn))
((= id 2) (setq D11 (pxy D1 an an)
D22 (pxy D2 an bn)
D33 (pxy D3 bn bn)
D44 (pxy D4 bn an)))))
(Command "_pline" D11 D22 D33 D44 "C")
(princ))
(defun C:SN+() (SN 1))
(defun C:SN-() (SN 2))
Song Nhi đọc thêm cái này để tham khảo. Viết bằng Visual lisp hay Notepad++
đều có những ưu/nhược điểm riêng.
Tôi thì mê Notepad++ hơn.
Trong link này các comments còn bỏ sót rất nhiều điều hay của N++, tự tìm hiểu
dần sẽ thấy thôi.
http://www.cadviet.com/forum/topic/5795-dung-chuong-trinh-nao-de-viet-lisp/
Tất nhiên, với kiến thức và kinh nghiệm của các bạn, các bạn có thể đọc và gỡ
lỗi một cách thủ công. Tuy nhiên, trong bài này chúng tôi trình bày cách dùng
công cụ của Visual LISP IDE để xác định vị trí lỗi và gỡ lỗi đó.
Trước tiên, bạn khởi động AutoCAD và nhập lệnh VLIDE (hoặc VLISP) để mở
chương trình Visual LISP IDE, mở một file mới, copy đoạn code mẫu trên vào.
Vẽ một vài line trong CAD để kiểm tra, Trở lại VLIDE load code bằng biểu tượng
load hoặc tổ hợp phím: Ctrl+Alt+E
Chạy thử bằng cách nhập lệnh: TEST tại command line, chúng ta sẽ nhận được
thông báo lỗi như sau:
; error: bad argument type: lentityp nil
Và trở lại VLIDE, kiểm tra: Debug » Break on Error tùy chọn này đã được check,
nghĩa là VLIDE đã đặt một điểm break tại vị trí lỗi.
Reset lại điểm break bằng cách: Debug » Reset to Top Level (hoặc tổ hợp phím:
Ctrl+R). Vậy chúng ta đã xác định được vị trí lỗi, nhưng còn phải xác định vì sao
lỗi tại đó nữa?!!
3.1/- Adding Break Points: Ta chèn thêm những điểm break để kiểm soát từng
đoạn code nhỏ. Trong trường hợp này lỗi xảy ra trong vòng lặp (while, cách
chèn: Đặt nháy tại vị trí chèn và Debug » Toggle Break Point (hoặc nhấn phím:
F9)
3.2/- Watching Variables: VLIDE cũng cho phép chúng ta theo dõi biến được sử
dụng trong các code, hiển thị giá trị của nó và giá trị của những biến liên đới với
nó. Double-click vào một biến nào đó và View » Watch Window (hoặc tổ hợp
phím: Ctrl+Shift+W) để xem giá trị, theo dõi thêm một biến liên đới với nó bằng
cách tô chọn biến đó và Debug » Add Watch (hoặc nhấn phím: Ctrl+W). Trong
trường hợp này ta chọn 2 biến “i” và “entity”.
3.3/- Animating the Code: Trong CAD, chạy thử đoạn code một lần nữa, chúng ta
nhập: TEST tại command line. Sau khi trở lại VLIDE chúng ta
vào Debug » Animate và đánh dấu tùy chọn này check. Sau đó
vào Debug » Continue (hoặc chọn biểu tượng mũi tên xanh trên thanh Debug,
hoặc tổ hợp phím Ctrl+F8)
Các giá trị của các biến trong cửa sổ Watch giúp chúng ta điều tra được nguyên
nhân lỗi. Trong trường hợp này, giá trị của “entity → nil” khi “i → 3”, điều này cho
thấy với i=3 đã thoát khỏi điều kiện kiểm tra của vòng lặp, do đó “entity → nil”.
Reset lại điểm break bằng cách: Debug » Reset to Top Level (hoặc tổ hợp phím:
Ctrl+R) và xóa tất cả các điểm break bằng cách Debug » Clear all Break
Points (hoặc tổ hợp phím Ctrl+Shift+F9). Sau đó vào Debug » Animate và hủy
đánh dấu tùy chọn này uncheck.
5/- Tham khảo thêm tài liệu trợ giúp của VLIDE
Các bác so sánh nhiều e e khập khiễng. Có đến mấy topic bàn về cái ni r ồi
- Về các tiện ích về cách thức sử dụng, trình bày ... N++ chắc chắn sẽ có thể ăn
đứt VL, đơn giản là vì N++ code mở, các bác thấy thiếu cái j thì xắn tay lên vi ết
cho nó. Từ khóa thiếu thì thêm, k nhận in hoa thì xử, màu mè chán thì chỉnh ...
nói chung là thiên biến vạn hóa, plug addin vô số ...
- Về các chức năng liên quan đến chất lượng sản phẩm, check hàng, đì búc đì
biếc các thứ thì vl chuyên về nó rồi, cãi j
Em thì viết = N++, sửa lỗi mò, nhưng vote dùng cả 2, mở file = N++ và VL cùng
lúc, qua lại chớp nhoáng, xuất chiêu nhẹ nhàng mà khí lực vô biên
@TL : bác Thái đường cũng hứa viết giúp mình cái tut đó, rồi mất hút ^^. Bạn làm
cùng chỗ a Thái ?
Quản lý LISP bằng Project
Vừa tiện dụng cho Autoload, vừa tiện dụng cho Find trong VLIDE rất hiệu quả,
ứng dụng cho việc test LISP bằng một project: Vault thì thật mau chóng!
@ Bác Gia_Bach: Cám ơn Bác! Bác hướng dẫn bằng hình ảnh thật cụ thể và dễ
hiểu, tuy nhiên, Bác đã để lại một vài “sơ xuất” lyky đã đánh dấu trên hình này
nè! Lyky đã nhận ra Bác rồi?!
Một lần nữa xin cám ơn Bác đã quan tâm đến vấn đề và nhiệt tình hướng dẫn anh
em! Chúc Bác thật nhiều SK và nhiều thật nhiều thành công trong công vi ệc n ữa
nhé!
@ ThuyLinh: Tiếp thu ý kiến, hôm sau nhất định không ghi tiếng Anh nữa!
Đã đăng Tháng 5 16, 2013
Vào lúc 16/5/2013 tại 17:21, Doan Van Ha đã nói:
[CHECKING TEXT <Untitled-0> loading...]
.
; Check done.
Bác thử làm thế này xem sao: Tools >> Environment Options >> General
Options ---> Check buttom đầu tiên, như hình vẽ sau là okei!
Ý nghĩa các buttom khác tham khảo tại: Diagnostic Tab (General Options
Dialog Box)/Help
Chúc các bạn buổi tối thật vui!
Bác thử làm thế này xem sao: Tools >> Environment Options >> General
Options ---> Check buttom đầu tiên, như hình vẽ sau là okei!
Ý nghĩa các buttom khác tham khảo tại: Diagnostic Tab (General Options
Dialog Box)/Help
Nếu sửa như trên mà vẫn không xuất hiện Global variables, bạn vui lòng kiểm
tra trang sau:
Chúc các bạn buổi tối thật vui!
Hề hề hề.
Bác này có nhẽ phải đổi nick thành Song ..... Phi mất thôi. Chơi nhiều cước độc
quá. Cánh đi mót như tui thiệt khó đỡ.
Hề hề hề,
Cám ơn bác Song .....(phi) Nhi vì qua các chiêu của bác t ụi này mót đ ược thêm
mấy miếng phòng thân và tránh đòn khi đi mót trên đồng lạ bác ạ....
Hề hề hề,....
Khi bạn mở một Project, VLISP sẽ hiển thị một cửa sổ liệt kê các Lisp trong
Project đó:
Mặc định, VLISP liệt kê các Lisp theo thứ tự các bạn đã nạp nó vào Project,
hoặc bạn có thể vào Project Properties để thay đổi thứ tự này theo ý bạn.
Các bạn nghiên cứu thêm ở: Using the Project Window to Work with Project
Files
P/S:
@ Song Nhi: Hảo Song Nhi! Đối với những Lisp đã check rồi và "dọn rác" theo
cách anh Gia_Bach đã hướng dẫn, sau khi check lại sẽ không còn Global Var, trừ
trường hợp vì ý đồ khác của người viết!
@ Phamthanhbinh: Cám ơn bác đã quan tâm đến vấn đề, mong chờ sự hướng dẫn
từ Bác - Chúc Bác thật nhiều sức khoẻ nhé! Ah, Song Nhi (trong Lộc đỉnh ký) thì
giỏi môn điểm huyệt chứ Bác, con gái ai người ta đi phi cước - mốt nữa ế chồng
chết! ^-^
Tue_NV còn hay thường dùng chức năng AutoComplex của VL (Có thể là các
hàm của Lisp hoặc khi đã Load Project thì có thể sử dụng bộ hàm con do mình
viết sẵn trong Project để coding nhanh chóng
Đơn giản viết vài chữ rồi Control+Shift+Spacebar
Vào lúc 17/5/2013 tại 14:34, Tue_NV đã nói:
Tue_NV còn hay thường dùng chức năng AutoComplex của VL (Có thể là các
hàm của Lisp hoặc khi đã Load Project thì có thể sử dụng bộ hàm con do mình
viết sẵn trong Project để coding nhanh chóng
Đơn giản viết vài chữ rồi Control+Shift+Spacebar
Xin hỏi anh Tuệ một chút, khi dùng Apropos (Control+Shift+Spacebar) thì phải
nhấp chột phải vào hàm rồi copy to clipboard rồi lại paste hay sao. Nếu như vậy
thì bất tiện hơn nhiều so với Backup/Auto-completion của N++.
Nó tùy thuộc vào mức độ hoàn thiện của từ khóa gợi ý của bạn.
Chức năng này không chỉ có tác dụng với hàm mà còn có tác dụng với cả bi ến
trong cửa sổ soạn thảo. Với các hàm và biến đã sử dụng trong cửa sổ soạn thảo
thì bạn chỉ cần nhấn tổ hợp Ctrl_space, nếu từ khóa gợi ý đến nhiều hàm hoặc
biến thì cứ nhấn thêm 1 vài lần đến khi ra được hàm hoặc biến cần vi ết.
Xin hỏi anh Tuệ một chút, khi dùng Apropos (Control+Shift+Spacebar) thì phải
nhấp chột phải vào hàm rồi copy to clipboard rồi lại paste hay sao. Nếu như vậy
thì bất tiện hơn nhiều so với Backup/Auto-completion của N++.
AutoComplete : Nó cũng giống như N++. Khi bạn đã có bộ hàm con trong
Project. Bạn bấm nút Load nó lên và sử dụng từ khoá gợi ý là nó Complete cho
mình. Nhưng ưu điểm hơn N++, vì N++ có thể bạn phải viết thêm các hàm để
Complex, nhưng với VL thì tất cả hàm con được load, tất cả các hàm Lisp đã có
thể Complete được rồi. Không phải copy paste đâu bạn
Mặc dù, đây chỉ là một vấn đề rất nhỏ, em cũng xin được trình bày, nhằm
mục đích phục vụ cho các bạn mới bắt đầu như em! Vấn đề Visual LISP Code
Formatting
VLISP có thể phân loại được các thành phần trong code và gán cho m ỗi lo ại đó
một màu sắc (có thể hiểu chỉnh lại theo thị hiếu cá nhân). Điều này, giúp cho
chúng ta có thể trực quan phát hiện một điều bất thường nhỏ nào đó, ví dụ đơn
giản, nếu bỏ lỡ một dấu " (quotes) thì phần code tiếp theo sau sẽ hiển thị bằng
một màu hồng (theo mặc định màu text string là màu hồng - bạn có thể hiệu
chỉnh thành màu khác). Hoặc, nếu bạn viết chưa đúng tên hàm, tên hàm sẽ
không chuyển sang màu xanh (Blue), giúp bạn nhận biết và sửa lại...
Một số LISP trong diễn đàn / mục Viết lisp theo yêu cầu, sau khi down về, nó
không còn giữ được format ban đầu mà chỉ đơn thuần nằm trên một dòng, Tuy
nhiên, điều này không hề là "lisp bị lỗi như thế" như các bạn nói, một cách
format đơn giản bằng VLISP, như sau: Tools » Format Code in Editor (Ctrl-Alt-
F) hoặc: Tools » Format Code in Selection (Ctrl-Shift-F). Hoặc chỉ đơn giản là
bạn hãy chọn vào các biểu tượng trên thanh công cụ: TOOLS, mô tả trong hình
sau:
Mặc dù chỉ là một vấn đề rất nhỏ, em cũng hi vọng là nó có thể giúp ích cho một
số ít các bạn mới bắt đầu học LISP giống như em!
Chúc anh chị em trên diễn đàn một ngày cuối tuần thật ý nghĩa và nhiều niềm
vui!
Về ý thứ 2 của Song Nhi thì không phải bao giờ cũng có thể format các lisp bị lỗi
nằm trên 1 dòng trở về 1 lisp đúng.
Điều này chỉ làm được khi trong dòng đó không chứa các string giải thích. VD
đơn giản dưới đây thì không thể format được, mà yêu cầu người format phải hiểu
bản chất code lisp nữa.
(defun HA();Test1 (setq a 1);Test2 (setq b 2))
AutoComplete : Nó cũng giống như N++. Khi bạn đã có bộ hàm con trong
Project. Bạn bấm nút Load nó lên và sử dụng từ khoá gợi ý là nó Complete cho
mình. Nhưng ưu điểm hơn N++, vì N++ có thể bạn phải viết thêm các hàm để
Complex, nhưng với VL thì tất cả hàm con được load, tất cả các hàm Lisp đã có
thể Complete được rồi. Không phải copy paste đâu bạn
Anh Tuệ có thể giải thích một chút(hoặc hướng dẫn cách làm) làm sao VL hiểu
được các hàm mà không cần copy paste không. Thanks.
Làm sao VL hiểu được các hàm mà không cần copy paste không. Thanks.
VLISP sẽ tự động hiểu và gợi ý cho bạn những hàm đã load: " Tuỳ thuộc vào mức
độ hoàn thiện của từ khoá bạn nhập", giống như chức năng Auto-
Correction của điện thoại khi bạn viết tin nhắn vậy đó, đối với tiếng latin thì bạn
có thể tắt chức năng này đi, vì không mấy hiệu quả, đối với tiếng Hoa (nói chung
là Hán tự), chức năng này là mặc định, và ngược lại, nó tỏ ra rất hiệu quả!
Có cần phải copy - paste gì đâu bạn?! Sau khi VLISP hiển thị dãy hàm gợi ý lên,
bạn dùng chuột chọn đúng hàm bạn muốn là được! Thực sự không hiểu bạn nói
copy/paste như thế nào nữa, vì có muốn copy/paste cũng đâu có cách nào làm
được?!! Bạn cứ mở trình Visual LISP Editor lên, vọc thử là sẽ hiểu được mà! Đối
với mọi hàm có sẵn khác, cũng đều ứng dụng được!
@ Doan Van Ha: Cám ơn bác đã nhắt nhở! Khi có chú thích thì sau khi format
xong chúng ta phải làm thủ công lại mới được ạ!
@ duy267: Bác có thể nói cụ thể hơn là bạn đã copy -paste như thế nào không?
ó cần phải copy - paste gì đâu bạn?! Bạn cứ mở trình Visual LISP Editor lên, vọc
thử là sẽ hiểu được mà! Đối với mọi hàm có sẵn khác, cũng đều ứng dụng được!
Mình đã thử nhưng vẫn phải copy-paste. Mình đã làm sai chăng? Ví dụ khi mình
gõ "(get", nhấn Cltr+Shift+Space thì hiện ra một đống hàm bắt đầu bằng "get".
Bây giờ mình muốn chọn hàm "getint" thì phải làm thế nào?
Với N++ thì khi bạn gõ tới đâu nó sẽ hiểu tới đó và bạn có thể dùng phím mũi tên
để chọn hàm rất tiện. Thanks.
Có 1 số TH ngoại lệ như hàm get hiện ra hộp thoại Apropos result. Sao bạn
không gợi nhớ thêm từ cho nó để nó hiện ra danh sách xổ xuống như trên hình
vẽ mình post.
Bạn đã xem hình mình post ở bài viết trên thì thấy sau khi bấm chữ -> có 1 danh
sách xổ xuống và chọn thôi (giống N++)
Từ danh sách xổ xuống thì chọn bằng chuột. Nếu hàm đã hoàn chỉnh tất nhiên
sẽ tự complete
VLISP cái này ưu điểm hơn N++ nhiều. Tue_NV dùng các hàm VL, VLA ..... và
các hàm trong bộ project của mình thì coding nhanh, gọn và nhàn hơn r ất
nhiều. N++ dẫu có thêm hàm cho chức năng Complete thì sao đủ bằng VL được?
Trong quá trình coding, nhiều lúc không nhớ chính xác cú pháp c ủa hàm, chúng
ta sẽ làm cách nào?
Đối với MS. Excel; VBA … Sau khi các bạn nhập hàm, sẽ xuất hiện một dòng
nhắc cú pháp, ví dụ:
Đối với Visual LISP IDE, mặc dù không trực quan như vậy, nhưng khi cần thiết –
chúng ta không cần thiết phải phải truy cập một cách gián tiếp – bằng cách vào
Help hoặc vào Internet để tìm kiếm. Một cách trực tiếp là chúng ta tô chọn đối
tượng muốn tìm hiểu, vào Help trên thanh Tools (hoặc tổ hợp phím Ctrl+F1)
Chúc các bạn thật nhiều niềm vui! Mong chờ sự chia sẽ kinh nghiệm sử dụng
trình VLISP của các bạn!
P/S: @ Tue_NV: Cám ơn Bác đã hướng dẫn chúng tôi chức năng AutoComplex,
vote Bác. Xin được hỏi thêm Bác là sau khi chọn, các hàm được in ra dưới dạng
chữ IN HOA, làm sao để sau khi chọn, hàm in ra với dạng chữ thường vậy Bác?
Chúc Bác thật nhiều sức khỏe và thành công trong công vi ệc!
Chuyển qua lại giữa chữ thường và chữ in hoa ở đây:
Ở đây chúng ta không nói về kiến thức để thiết kế một giao diện DCL, chúng ta
chỉ đơn thuần xét đến chức năng xem trước giao diện DCL trong VLISP. Các bạn
có thể tham khảo thêm về DCL: Tại đây
Trước tiên, các bạn copy đoạn code sau, paste vào cửa sổ soạn thảo (Ctrl+N)
của VLISP, lưu lại với tên là: *.DCL
LAYER:dialog {
label="Chuc nang xem truoc DCL";
spacer_1;
:boxed_radio_column{
label="Cai dat Layer";
:radio_button{
label="Su dung Layer hien
huu";
key="IsCuLA";
}
:radio_button{
label="Cai dat Layer";
key="IsSetLA";
}
:popup_list{
key="La";
}
}
ok_cancel;
}
Vào Tools » Interface Tools » Preview DCL in Editor (Preview DCL in Selection) .
VLISP chuyển sang cửa sổ ACAD và hiển thị hộp thoại xem trước như sau:
Chúng ta sử dụng chức năng này để thiết kế hộp thoại DCL, bởi DCL được vi ết
toàn bằng code, trong khi hộp thoại của các ngôn ngữ lập trình hướng đối t ượng
khác, được thiết kế trực quan!
Không cần phải save as. Muốn chuyển đổi định dạng code trong một cửa sổ soạn
thảo chỉ cần vào tool, window attributes, rồi cái gì đó (dòng thứ hai thì phải),
lựa chọn định dạng code muốn đổi
Bác Thaistreetz đang hướng dẫn anh em tiện ích gì của VLISP vậy ạ? Em có làm
theo hướng dẫn trên: Vào Tools / Window Attributes / Configure Current ... (dòng
thứ 2)
Em không hiểu chuyển đổi định dạng code là ntn? Bác Thaistreetz làm ơn giải
thích rõ vấn đề này được không ạ?
Bạn muốn đóng gói một ứng dụng bao gồm LSP và hộp thoại DCL, Visual LISP
có thể giúp bạn điều này qua các bước sau đây:
1. Trong menu file VLISP chọn: Make Application>New Application Wizard.
2. Trong trang đầu tiên: nếu không kèm theo DCL --> chọn: Simple, ngược lại
chọn: Expert.
3. Trong Application Location, tìm đến đường dẫn chứ file LISP. Và đặt tên ứng
dụng tại Application Name.
4. Xác định các tập tin LSP mà bạn cần tạo ứng dụng.
5. Thêm các tập tin DCL.
2) Giới hạn là bao nhiêu bác? Tue_NV đóng gói nhiều 30 file lsp mà chẳng th ấy
giới hạn??????
Có 2 lần tôi đóng gói nhiều file. Nhớ như thế này:
- 1 lần tầm 10 files (không nhớ chính xác lắm).
- 1 lần đúng 13 files. Đóng 12 thì OK, đóng 13 thì NO.
Không tìm ra quy luật. Chẳng hiểu do số file hay dung lượng file hay gì gì n ữa,
mà sự việc là thế.
Sự việc là thế, là chưa chắc chắn, bác lại đưa ra câu khẳng định thế :lol:
Có 1 cách khử quy luật chưa biết này là gom tất cả file Lisp vào 1 file Lsp duy
nhất rồi đóng gói
@bạn Nhacotung : Phiền bạn post bài sang topic khác nhé. Mình tạm xoá bài
viết của bạn trong topic này.
Ở topic này đang thảo luận đến việc sử dụng VL.
Hôm nay SN xin được trình bày cách chạy Debug bán tự động, không dùng ti ện
ích Animate, nghĩa là khi chạy debug chúng ta không check chọn Animate
trong tab Debug. Vẫn chạy trên đoạn code cũ trong #6, như sau:
(defun c:test ( / ss i sl total entity elist )
(if (setq ss (ssget '((0 . "LINE"))))
(progn
(setq i -1 sl (sslength ss) total 0)
(while (<= (setq i (1+ i)) sl)
(setq entity (ssname ss i)
elist (entget entity)
total (+ total (distance (cdr (assoc 10 elist)) (cdr
(assoc 11 elist))))))
(princ (strcat "\nTotal Length: " (rtos total)))))
(princ))
1. Trước tiên, SN liệt kê một số phím nóng cần dùng:
Step Into : F8
Step Over : Sh-F8
Step Out : Ct-Sh-F8
Continue : Ct-F8
Reset to Top Level : Ct-R
Quit Current Level : Ct-Q
Toggle Breakpoint : F9
Last Breakpoint : Ct-F9
Clear All Breakpoint: Ct-Sh-F9
2. Các bước 1; 2; 3.1 Adding Break Points và 3.2 Watching Variables thực hiện
như hướng dẫn #6. Đến 3.3 chúng ta không dùng tiện ích Animate, thực hiện như
sau: Cho chạy lại đoạn code đến khi gặp "điểm dừng" đầu tiên dùng F8
(Continue) để chạy dần từng bước một (hoặc Sh-F8) và theo dõi sự thay đổi giá
trị của 2 biến “i” và “entity” trên cửa sổ Watch Window. Việc sửa lỗi sau khi xác
định nguyên nhân lỗi - thực hiện như cũ.
Thật ra, không phải do tốc độ chạy Debug bằng Animate quá nhanh làm các bạn
không theo dõi kịp! Bạn có thể tuỳ chỉnh tốc độ này tại:
Đơn vị là mili giây (10-3 giây). Tuy nhiên, với các làm bán tự động này, các bạn có
thể kiểm tra giá trị của bất kỳ biến nào (mặc dù chưa được add vào Watch
Window) tại mỗi vị trí dừng, bằng cách: tô chọn biến đó chọn: Load Selection
(hoặc: Ct-Sh-E). Giá trị sẽ hiển thị trên Visual LISP Console.
Ngoài ra, SN còn muốn liệt kê thêm một số phím nóng giúp bạn kiểm tra nhanh
từng cụm ()
Ct-[: Chuyển dấu nháy đến ( mở đầu khối hoàn chỉnh phía trước.
Ct-]: Chuyển dấu nháy đến ) kết thúc khối hoàn chỉnh phía sau.
Ct- Sh-[: Tô chọn khối hoàn chỉnh (...) phía trước vị trí dấu nháy hiện tại.
Ct- Sh-]: Tô chọn khối hoàn chỉnh (...) phía sau vị trí dấu nháy hiện tại.
Mời các Bác tiếp tục chia sẽ những kinh nghiệm sử dụng trình soạn thảo VLISP
IDE!
Vào lúc 16/5/2013 tại 15:15, gia_bach đã nói:
Thêm chức năng "thu gom rác" : biến toàn cục -> biến cục bộ
Trong vấn đề giải phóng bộ nhớ sau khi chạy LISP cũng còn nhiều vấn đề khác,
cần được quan tâm, trước tiên bạn cần nắm các khái niệm biến cục bộ; biến toàn
cục và các tính chất của nó, nếu cần thiết các bạn có thể tham khảo tại đây,
hoặc tìm kiếm trên diễn đàn.
Danh sách trả về trong tiện ích kiểm tra của VLIDE sẽ liệt kê tất cả các đối
tượng được xác định trong code. Danh sách này có thể bao gồm: Các ký hiệu
bảo vệ (chẳng hạn như các hàm hoặc các hằng số được bảo vệ). Nếu các đối
tượng đó đều vô tình cục bộ hóa, chương trình của bạn có thể không chạy như
mong đợi ...
Vì vậy, các bạn cần lưu ý thêm, khi thanh lọc bộ nhớ bằng cách chép danh sách
xuất ra của biến toàn cục vào phía sau: (defun( /, cần loại ra các đối tượng sau
đây, không thanh lọc chúng, như sau:
1. Ký hiệu bảo vệ (được đánh dấu màu xanh), chẳng hạn như các hàm hoặc các
hằng số được bảo vệ (ví dụ: Vlax-true).
2. Đối tượng trong DCL được xác định tại thời gian chạy (chẳng hạn như: $key,
$reason, $value, $data).
4. Biến mà bạn muốn giữ lại giá trị sau khi chạy vì mục đích khác (nào đó!?),
danh sách các biến trả về bởi các tiện ích kiểm tra được sắp xếp theo thứ tự
abc, cho nên bằng cách đặt trước tên biến toàn cục với dấu sao (*) hoặc ... , làm
cho nó xuất hiện ở đầu của danh sách để chúng ta có thể dễ dàng loại bỏ ra.
Không nhất nhiết check đối với một LISP đầy đủ, đối với một file tổng hợp nhiều
LISP, bạn cũng có thể Check toàn bộ, bằng cách chọn Check edit window trên
thanh công cụ Tools. Danh sách trả ra tổng hợp như sau:
Đối với danh sách trả về sau khi check, các biến ở dạng chữ in hoa, về mặt hình
thức nếu bạn muốn chuyển về chữ thường, hãy chạy list đó qua hàm sau:
(defun VarList (lst) (vl-princ-to-string (mapcar '(lambda ( x )
(strcase (vl-princ-to-string x) t)) lst)))
;;; Vi du:
(VarList '( C a d V i e t. c o m)) ---> "(c a d v i e t. c o m)"
Sau đó, bạn hãy lựa chọn những đối tượng mà bạn muốn cục bộ hóa, chép vào
phía sau: (defun( / để giải phóng bộ nhớ, tiết kiệm dung lượng và hạn chế tương
tác giữa các LISP với nhau!
Đối với danh sách trả về sau khi check, các biến ở dạng chữ in hoa, nếu bạn
muốn chuyển về chữ thường, hãy chạy list đó qua hàm sau:
(defun VarList (lst) (vl-princ-to-string (mapcar '(lambda ( x )
(strcase (vl-princ-to-string x) t)) lst)))
;;; Vi du:
(VarList '( C a d V i e tt)) ---> "(c a d v i e tt)"
........
Visual LISP Editor đã có sẳn các công cụ
này :
Hôm nay SN xin được trình bày cách chạy Debug bán tự động, không dùng ti ện
ích Animate, nghĩa là khi chạy debug chúng ta không check chọn Animate
trong tab Debug.
Thực ra, chúng ta có thể linh động hơn một chút xíu - bằng cách, trong lúc chạy
thủ công, đang ở một bước nào đó, bạn cũng có thể gọi tiện ích animate lên và
Ctrl+F8 để tiếp tục chạy tự động. Tuy nhiên, điều ngược lại không thực hiện được,
nghĩa là nếu đã bắt đầu chuyển qua chạy bằng animate, chúng ta chỉ có thể
thoát ra: abort evaluation, thoát lệnh và trả sang màn hình acad.
Ngoài ra, chức năng watching variables xem như tiện dụng để theo dõi sự liên
đới của các biến. Tuy nhiên, có thể là sẽ rất khó xem đầy đủ với các list dài,
chẳng hạn ... Do đó, nếu chỉ xem và theo dõi sự thay đổi giá trị của một biến nào
đó, chúng ta có thể sử dụng console window để xem giá trị sau mỗi thay đổi.
Một điều nhỏ nữa là bạn cần lưu ý, uncheck tiện ích animate sau khi chạy xong,
nếu không, khi bạn trở lại acad, sử dụng một lệnh nào đó liên quan đến file LISP
hiện hành, sẽ vấp phải sự "delay" vì y cứ tưởng bạn đạng chạy debug
(animate chỉ dùng để chạy debug mà thôi!).
Trở lại một vấn đề quen thuộc là Autoload LISP, chúng ta có rất nhiều cách như
sau:
Tuy nhiên, đối với những cách này, file LISP mà bạn muốn đặt Autoload cần phải
nằm trong Support (Trừ phi bạn biên đầy đủ đường dẫn của nó!), Có thể là bất
tiện và khó khăn trong việc trao đổi (Share - Copy – Move…). Chúng ta có th ể
dùng một cách khác, cách này phù hợp với các bạn xài trình soạn Visual LISP
IDE để coding và test LISP, ứng dụng Project vào vi ệc Autoload. Khi đó, Folder
chứa các file LISP bạn cần Autoload, có thể đặt ở một nơi nào tùy thích, miễn là
thuận tiện cho bạn!
2.3 Move Up lên đầu, để được load trước (chuyện này không cần thiết lắm!)
Từ nay, bạn muốn thêm bớt file LISP cần Autoload vào Project rất dễ dàng
(tương tự như Startup Suite). Tuy nhiên, khi máy (hoặc Acad) bị sự cố đột ngột –
chúng ta cũng không sợ mất LISP (vì bạn có thể tạo Project trên các ổ đ ĩa khác
C).
https://www.cadviet.com/forum/topic/1793-giao-di%E1%BB%87n-h
%E1%BB%99p-tho%E1%BA%A1i-trong-autolisp/
The Visual LISP Editor - Part 1
by Kenny Ramage
See also:
This tutorial is a crash course in using the Visual LISP Editor, and is not intended to be detailed or fully
comprehensive. The aim is to show you the main functions of the Editor with the intention of getting you up
Right, enough waffle, let's get started. Fire up AutoCAD and open a new drawing. Now choose Tools
AutoLISP Visual LISP Editor from the pull-down menu. If you don't see the pull-down menu,
The Visual Lisp Editor will open and should look like this :
Let's start off by having a look at the Visual LISP Console window :
The VLISP Console window is similar in some respects to the AutoCAD Command window, but has a few
extra features. You enter text into the Console window following the Console prompt which looks like this :
_$
_$ (setq a "Test")
_$ a
To view the value of a variable at the AutoCAD Command prompt, you must precede the variable name with
Unlike the AutoCAD Command window, where pressing SPACEBAR causes expression evaluation, text
input at the VLISP Console prompt is not processed until you press ENTER. This permits you to do the
Input more than one expression before pressing ENTER. VLISP evaluates each expression before
If you select text in the Console window (for example, the result of a previous command or a
previously entered expression), then press ENTER, VLISP copies the selected text at the Console
prompt.
The VLISP Console window and the AutoCAD Command window differ in the way they process the
SPACEBAR and TAB keys. In the VLISP Console window, a space plays no special role and serves only as
a separator. In the AutoCAD Command window, pressing the SPACEBAR outside an expression causes
prompt. Each time you press TAB, the previously entered text replaces the text at the Console prompt. You
can repeatedly press TAB until you cycle through all the text entered at the Console prompt during your
VLISP session. After you’ve scrolled to the first entered line, VLISP starts again by retrieving the last
command entered in the Console window, and the cycle repeats. Press SHIFT + TAB to scroll the input
history in the opposite direction. For example, assume you entered the following commands at the Console
prompt:
1. Press TAB once. VLISP retrieves the last command entered and places it at the Console prompt :
_$ (command "_.CIRCLE" origin radius)
2. Press TAB again. The following command displays at the Console prompt :
4. Now press SHIFT+ TAB . VLISP reverses direction and retrieves the command you entered after
This was the last command you entered at the Console prompt.
6. Press SHIFT+ TAB again. Because the previous command retrieved was the last command you
entered during this VLISP session, VLISP starts again by command you entered in the Console
window :
Note : If you enter the same expression more than once, it appears only once as you cycle through the
Console window input history. You can perform an associative search in the input history to retrieve a
specific command that you previously entered. To perform an associative search of the Console input
history :
1. Enter the text you want to locate. For example, enter (command at the Console prompt :
_$ (command
2. Press TAB. VLISP searches for the last text you entered that began with (command :
reverse the direction of the associative search and find progressively less-recent inputs.
((_>
Pressing SHIFT + ESC interrupts the command, and VLISP displays an "input discarded" message like the
following :
_$
If you type text at the Console prompt, but do not press <Enter>, then pressing ESC clears the text you
typed. If you press SHIFT + ESC, VLISP leaves the text you entered in the Console window but displays a
If you type part of a command at the Console prompt, but activate the AutoCAD window before pressing
<Enter>, VLISP displays a new prompt when you next activate the VLISP window. The text you typed is
visible in the Console window history, so you can copy and paste it, but you cannot retrieve the text by
pressing TAB , because it was not added to the Console history buffer.
See also:
The Visual LISP Editor - Part 1
Right, enough messing about. Let's load some coding. Choose File New File and then copy and paste
(defun C:SLOT ( )
(setvar "CMDECHO" 0)
(setvar "BLIPMODE" 0)
(while
Before we go any further, let's have a wee chat about the colors. As soon as you
enter text in the VLISP Console or text editor windows, VLISP attempts to
determine if the entered word is a built-in AutoLISP function, a number, a string,
or some other language element. VLISP assigns every type of element its own
color. This helps you detect missing quotes or misspelled function names. The
default color scheme is shown in the following table.
Selecting Text
The simplest method to select text is to double-click your left mouse button. The amount of text selected
If the cursor immediately precedes an open parenthesis, VLISP selects all the following text up to
If the cursor immediately follows a close parenthesis, VLISP selects all preceding text up to the
If the cursor immediately precedes or follows a word, or is within a word, VLISP selects that word.
Hint : Would you like help on any AutoLisp function? Double-click on the function name to select it, and
then select the "Help" toolbar button. Help for the specific function will be displayed.
To load the "Slot" lisp routine, select the "Load active edit window" toolbar button :
This loads your coding into memory. To run the routine, type this at the Console prompt :
_$ (c:slot)
The program should now run, switching over to the AutoCAD screen when required. You can also just run a
selection of code if you desire. Select the lines of code you would like to run and choose the "Load
Talking about debugging, Place the cursor in front of the (defun C:SLOT () statement and press "F9". This
places a "Breakpoint" into your program. Now run the program again. Execution should stop at the
Breakpoint mark. Now press "F8". By continuously pressing "F8" you can "single step" through your whole
program :
Let's go one step further. Select the "diam" variable and then select the "Add Watch" toolbar button :
Note how the variable "diam" is listed along with it's present value. Repeat this process for all the other
OK let's liven things up a bit. Select "Ctrl-Shift-F9" to clear all breakpoints. Now select the "Debug" pull
down menu and then "Animate". Now run the program again.
Hey, it's running automatically! Take note of the variables changing in the "Watch" window as the program
Well that's about it in regards to the Visual LISP Editor. The editor has a lot more functions than I've shown
you here, but these I feel, are some of the more important ones to get you started.
An Introduction to the Visual
LISP IDE
The Visual LISP IDE (rather, more precisely: Visual LISP Integrated Development
Environment (VLIDE) - but that's a bit of a mouthful), is an excellent developer tool &
resource supplied as standard with the majority of full versions of AutoCAD.
Even if you are just starting to program in LISP, in my opinion, the VLIDE is essential
and can be a great learning aid.
This tutorial will demonstrate how to get started with the VLIDE, and, to keep things
relatively clear, I won't be delving too deeply into the multitude of tools available to
the developer.
Introduction
To begin, open AutoCAD to a blank drawing and type VLIDE at the command line.
A window should appear, containing two or more smaller windows including the
Console Window & Trace Window (more on these later).
Let's begin by opening a New File in which we can start to construct a program. To do
this, go to File » New File (alternatively using the shortcut: Ctrl+N).
In the window that appears, we can start to construct our LISP program. As an
example, copy or type the following code into the blank editor window:
(defun c:test ( )
You will notice that the functions, brackets, strings and other items are highlighted
accordingly:
The syntax highlighting is a great visual aid, and also helps prevent protected symbols
such as function names being used as names for variables, as they are highlighted
accordingly.
At this point, we can study the code in more detail, and, if not sure about how a
function is to be used, we can immediately get information about that function using
the VLIDE Help Documentation. A tutorial on how to do this can be found here.
Also, we can open an existing LISP file to edit the contents in the VLIDE Editor
Window - to do this, either go to File » Open File or use the shortcut Ctrl+O.
Loading a Program
OK, so we've just constructed a program in the Visual LISP IDE, now to test it out!
As you may know, loading a program into AutoCAD can sometimes be tedious, as the
LISP file needs to be saved, then either loaded using the Appload command, or maybe
the ACADDOC.lsp. But, you'll be pleased to know, loading programs in the VLIDE
is much simpler.
There are three equivalent ways to load a program: by going to Tools » Load Text in
Editor; by clicking on the relevant toolbar icon on the Tools toolbar; or simply by
using the shortcut Ctrl+Alt+E.
Upon loading the program, the Visual LISP Console window will appear indicating
whether the code has been loaded successfully.
Now, having loaded the example code above, we can go back to the AutoCAD window,
and at the command line type: test to start the program.
A Few Examples
Evaluating a LISP Expression
_$ (+ 2 2)
4
Variable Evaluation
_$ (setq var 1.4142)
1.4142
_$ var
1.4142
Protected Symbol Evaluation
_$ actrue
1
_$ defun
#<SUBR @0fbfaaf0 DEFUN>
Calling a Function (using the example code from earlier)
_$ (c:test)
Further Information
This tutorial has covered the basics of the Visual LISP Integrated Development
Environment (VLIDE) - the Editor offers many essential debugging tools to get you out
of a fix when code goes wrong, and furthermore other tools to format code at the
touch of a button. Be sure to explore the VLIDE Help Documentation detailing how to
get the most out of the VLIDE.
Note that the filename used to save the source code is arbitrary and will not affect the
program in any way - however, the majority of users use the function syntax (and
perhaps include the program version) for convenience.
The command line should display whether the program has indeed loaded
successfully, and any loading messages the author may have decided to include.
First we must check that an ACADDOC.lsp file exists - to do this type at the AutoCAD
command line:
(findfile "ACADDOC.lsp")
If this returns a filepath, navigate to the existing ACADDOC.lsp file and in the steps
that follow, amend its contents.
Else, you can create a new ACADDOC.lsp file by opening a new Notepad document (or
other plain text editor) and saving it as ACADDOC.lsp in an AutoCAD Support Path
(ensuring the Save As Type panel is once again set to All Files).
When finished, open a new drawing and the LISP files should load.
Note: if using this method to load many LISP files on startup is causing drawings to
open slower, refer to my tutorial on the use of AutoLoad to demand load LISP files.
The syntax (command name) to call the program may be displayed in the author's
loading messages, or perhaps noted in the program header. If it cannot be found in
either of these locations, you can inspect the source code itself to determine the
command to use.
The syntax will be located after the c: in a defun function call, for example:
(defun c:MyCommand ( )
...
In the above example, the command would be MyCommand.
If the c: does not appear after the defun function, this indicates that the function is a
subfunction and is designed to be called from another program.
When the command syntax is known, it may be typed at the AutoCAD command line
to invoke the program.
Loading Programs
Automatically
This tutorial aims to guide you through the various methods which can be used to load
a program automatically on startup.
If you have a toolbox of LISP programs that you use regularly, it would be tedious to
have to load each and every program whenever a drawing is opened. Thankfully, I
shall introduce two methods to accomplish this task, each with their own advantages
in different situations.
All programs listed in the above panel will be loaded every time a drawing is opened.
The method of using the Startup Suite to load programs automatically does have a
few disadvantages however: should the user wish to migrate his or her programs to
another computer, all programs will need to be added to the Startup Suite on the new
computer.
There have also been a few known bugs surrounding the Startup Suite in past
versions of AutoCAD. For these reasons, I shall introduce another method which,
although requires the user to have some basic knowledge of AutoLISP, overcomes
these difficulties.
With this knowledge one can edit or create an ACADDOC.lsp to include any AutoLISP
expressions to be evaluated upon startup.
Things get a little complicated should there exist more than one ACADDOC.lsp file, so,
to check if such a file already exists, type or copy the following line to the AutoCAD
command line:
(findfile "ACADDOC.lsp")
Should a filepath be returned, in the steps that follow, navigate to this file and amend
its contents. Else, if the above line returns nil, you can create your
own ACADDOC.lsp in Notepad or the VLIDE and save it in an AutoCAD Support Path.
One clear advantage to using the ACADDOC.lsp to automatically load programs is that,
upon migration, it may easily be copied from computer to computer, or indeed reside
on a network to load programs on many computers simultaneously.
If the program file resides in an AutoCAD Support Path, the filename need only be the
name of the file to load; else a full filepath is required to locate the file, for example:
Using this knowledge we can populate our ACADDOC.lsp file with load statements to
be evaluated when the ACADDOC.lsp file is loaded on startup.
This method is best demonstrated with an example. Consider the following LISP
program:
(defun c:DrawLine ( / p q )
Further Information
Further information about the functions I have demonstrated in this tutorial may be
found in the VLIDE Help Documentation. Struggling to access the help? See my
tutorial here.
An Introduction to Script
Writing
Scripts are very different to AutoLISP programs - a Script is merely a list of AutoCAD
commands to be executed one after the other, as if the user were typing them at the
command-line.
The following code represents the above Script line with spaces shown for clarity:
_.circle•_non•0,0,0•5•
Note the space after the 5 representing the user pressing Enter to submit the entered
radius to complete the command (a new blank line could also have been used in the
script file for the same result).
At this point, you may be slightly confused by some of the prefixes & command
parameters used in the above example, so here is a short explanation of the purpose
of each item:
o _ (underscore)
Non-localised command prefix: this prefix ensures that the English name of a
command is used, irrelevant of the language of the version in which it is
invoked. For example, if we have a Script calling the LINE command, by prefixing
the command name with an underscore (i.e. _line) the same Script can be used
in, say, a French version of AutoCAD, without needing to replace every
occurrence of 'line' with 'ligne'.
Note that this prefix should also be used with command keywords to allow for
cases in which the keyword does not use the the same 'key letter' when
translated to another language.
o . (period)
Non-redefined command prefix: this prefix is used to account for commands that
have been redefined, ensuring that the original standard command is used and
not a redefined version.
o non (or 'none')
This is an Object Snap modifier (similar to end or mid) which instructs the
command to ignore any active Object Snap modes for the next point input. The
modifier keyword is prefixed with an underscore to account for non-English
versions of AutoCAD, as described above.
For English versions of AutoCAD in which no commands have been redefined, the
underscore & period prefixes are not absolutely necessary, however, it is good
practice to include them to enable compatibility with all versions without any effect on
the performance or operation of the Script.
Now, this all seems pretty clever so far, but huge amounts of time can be saved if we
extend this idea to more than one drawing.
You can also load & call AutoLISP programs from within scripts, and so, to make the
scripting more robust, you might consider creating an AutoLISP program to execute
all operations on the drawing, and then merely use the script to open each drawing,
load & evaluate the AutoLISP program, then finally save and close the drawing.
Upon viewing the above example, you can probably already see where the next time
saving can be made: in the writing of the script. After all, who would want to type all
those filenames manually? The Solution: Script Writer.
Script Writer
Function Syntax WScript
Current Version 1.2
Download ScriptWriterV1-2.lsp
View HTML Version ScriptWriterV1-2.html
Program Description
The aim of this program is to reduce the
construction of an AutoCAD Script to a single
line.
The program assumes the user is conversant in writing scripts for AutoCAD, if not,
refer to my tutorial: An Introduction to Script Writing.
This program is designed to greatly reduce the time involved in writing scripts as an
alternative to the usual scripting programs available.
Upon starting the program, the user is presented with a dialog interface. Near the top,
the user may enter a Script Line - this is the list of commands that will be performed
on each drawing in the selected directory (and subdirectories).
The user only needs to write the first line of the script, which will be performed on
every drawing in the selected directory; this is achieved through the use of a special
token string to represent the drawing filename in the line of script operations.
Example
Consider the example from my script writing tutorial:
To avoid having to construct the whole script, we can convert the first line for use with
the Script Writer program, as follows:
The program will then replace this token with the filename of each drawing in the
selected directory (and subdirectories), and subsequently run the constructed script.
Additional Controls
The programs provides additional buttons to save even more time in writing the script
line operations: the user may quickly insert the *file* token or clear the existing line
by pressing the Filename and Clear buttons respectively.
Scripts may also be saved for later use, or existing scripts may be loaded into the
program using the Load / Save buttons.
Preview
Localising Variables
This is a practice that, in my experience, many new AutoLISP programmers overlook -
sometimes resulting in elusive bugs in their programs.
This tutorial will give a brief overview of the defun function and moreover explain why
localising variables is a good habit to get into. I have tried not to go into the small
details in this tutorial to keep things clear.
Here,
o symbol is the name of the function (if prefixed with 'c:' the function may be called
from the command line).
o arguments are symbols representing data that the function requires when called
(more about these some other time).
o variables are the symbols used to hold data within the function.
o expressions are all the statements that make up the function itself.
Examples
(defun test ( arg1 arg2 / var1 var2 ) ;; Function taking two
arguments, with two local variables
;; Expressions
(setq var1 (* arg1 2.0) var2 (+ arg2 3))
) ;; End of defun
(defun c:MyCommand ( / a b c ) ;; Function with three local variables
(setq a 1.0 b 2 c 3)
(print (- b (/ a c)))
(princ)
)
(defun myfunc ( x y ) ... ) ;; Function takes two arguments
(defun myfunc ( / a b ) ... ) ;; Function has two local
variables
(defun myfunc ( x / temp ) ... ) ;; One argument, one local
variable
(defun myfunc ( ) ... ) ;; No arguments or local
variables
All else aside, this is certainly a 'cleaner' method, as, any variables set within the
function are 'cleaned up' afterwards, and hence cannot interfere with other programs
using the same symbols for variable names, or indeed waste space in the memory.
(defun c:test ( )
(foreach x '(1 2 3 4 5)
(setq lst (cons x lst))
)
(print lst)
(princ)
)
Upon running the above code, the following will be displayed at the command line (be
sure you know why it is reversed):
(5 4 3 2 1)
Now, in the same AutoCAD session, if we run the code again, we receive:
(5 4 3 2 1 5 4 3 2 1)
The list has doubled! This is because the variable lst still holds the list data even after
the function has completed. Hence, when evaluated for the second time, new values
are added the existing list.
This certainly highlights one major issue, but what if we had another function, also
without localised variables, using the same symbol for a variable name?
(defun c:test ( )
(print lst)
(princ)
)
Upon running the above code, we now have a list containing a mixture of data types -
this is getting really messy!
(foreach x '(1 2 3 4 5)
(setq lst (cons x lst))
)
(print lst)
(princ)
)
Now we can be confident that everytime we run the program, the value of lst will be
consistent everytime:
(5 4 3 2 1)
Introduction
This tutorial describes various ways in which to prompt for user input whilst offering a
default option available for selection by the user pressing ENTER , SPACE or right-
clicking at the prompt.
I would note that the prefixes are used for no other purpose: in AutoLISP, they
constitute standard variable names.
Version 1
(initget "Alpha Beta Gamma")
(setq ans (cond ((getkword "\nChoose [Alpha/Beta/Gamma] <Alpha>: "))
("Alpha")))
In the above code, the option Alpha is hard-coded as the default option.
If the user presses ENTER at the prompt, the getkword expression returns nil and so
the cond function moves on to evaluate the next test condition: this is the default
string "Alpha" which is a non-nil value and is hence returned by the cond function.
Version 2
(initget "Alpha Beta Gamma")
(if (null (setq ans (getkword "\nChoose [Alpha/Beta/Gamma] <Alpha>:
")))
(setq ans "Alpha")
)
This second version uses the same logic as the first, however the conditional
operator cond is replaced by an if statement. Hence, if the variable ans is nil, the
default option is bound to it.
The only additional consideration when generalising to other functions is the required
conversion from the data type of the default value to the string which is used to
display the user prompt.
For example, when prompting the user to specify an integer value, the itoa (integer-
to-ASCII) function must be used so that the default value may be concatenated with
the user prompt using the strcat (string concatenation) function:
(if (null global:int)
(setq global:int 1)
)
(initget 6)
(if (setq tmp (getint (strcat "\nEnter a positive non-zero integer <"
(itoa global:int) ">: ")))
(setq global:int tmp)
)
Similarly, in the following example, the numerical value of the global variable is
converted to a string formatted in decimal format to 3 decimal places using
the rtos(real to string) function:
(if (null global:dis)
(setq global:dis (+ pi pi))
)
(initget 4)
(if (setq tmp (getdist (strcat "\nSpecify circumference <" (rtos
global:dis 2 3) ">: ")))
(setq global:dis tmp)
)
Error Handling
Ever used a program only to discover some time later that your Object Snaps have
been mysteriously cleared? Or maybe AutoCAD is suddenly behaving differently?
These are tell-tale signs that you have aborted a program that is not equipped with an
appropriate error handler.
This tutorials aims to teach you how to create an error handler for your programs to
deal with the clean-up operation when something in the code goes wrong.
The standard error handler used by AutoCAD will simply print this argument to the
command line; you can see this behaviour first hand by typing at the command line
something like:
(itoa nil)
This will in turn cause the standard error handler to evaluate and print the following
message at the command line:
To achieve this, we can define the *error* function in the following way:
(defun c:test ( / *error* )
We can reset any settings changed by the program through the use of a user-defined
error handler, as the following example demonstrates:
(itoa nil)
The previously defined error handler will evaluate, to display the message:
*error* outside of test program.
To reset to the default error handler, we can clear the value of the *error* symbol:
(setq *error* nil)
If AutoCAD encounters an error during program execution and the *error* symbol
is nil, the default, in-built error handler will be evaluated to print the error message
as mentioned earlier in this tutorial.
I'm sure that you would concur that the above alternative method is far less succinct
than a simple symbol localisation; however, let us dissect the code to reveal the
process that is occurring.
First, we define a function myerr taking a single string argument: msg. This function
will act as our redefined error handler.
Further Information
The Visual LISP IDE Help Documentation offers further information regarding error
handling in AutoLISP - be sure to read the following topics:
Suppose that we wish to convert each string to 'Titlecase' such that the first letter of
each word is capitalised, for example:
Further Examples
The mapcar and lambda functions are best illustrated and understood using examples,
so here are a few more for you to study:
Example 3
Adding one to each element of a list:
Example 4
Adding two to each element of a list, using a defined function:
Example 5
Concatenating a string with an integer, using a defined function taking two
arguments:
Further Reading
If this tutorial has sparked your interest in all things mapcar and lambda, the following
publication from the Autodesk University written by Darren Young also provides an
outline of mapcar, lambda and the apply function:
LISP: Advance Yourself Beyond A Casual Programmer
Below I will provide some examples to demonstrate a variety of different methods and
I'll try my best to give a brief explanation on how each method works and the
efficiency of its operation.
In all of the following examples, the user will be prompted to make a selection of
objects and the example program will iterate over the selection set, printing the entity
type of each entity, (or object name of the VLA-Object in the case of the Visual LISP
example).
Many of the examples have been expanded to use several variables for simplicity and
readability and could subsequently be shortened by nesting expressions, but that is
not the intention of this tutorial.
Contents
Method 1: while
Method 1a: Reverse while
Method 2: repeat
Method 2a: Reverse repeat
Method 3: ssnamex
Method 4: ssdel
Method 4a: Reverse ssdel
Method 5: Visual LISP ActiveX
Method 1: while
SELECT ALL
(defun c:test1 ( / e i n s x )
(if (setq s (ssget))
(progn
(setq i 0
n (sslength s)
)
(while (< i n)
(setq e (ssname s i)
x (cdr (assoc 0 (entget e)))
i (1+ i)
)
(print x)
)
)
)
(princ)
)
The above function utilises a while loop to iterate over the selection set. A counter
variable i is initialised at 0, and a limiting variable n is assigned the size of the
selection set, i.e. the number of items in the set.
The test condition for the while loop will evaluate to T (true) providing the counter is
less than the number of items in the set.
The counter variable is then sequentially incremented within the while loop, ensuring
termination of the loop when all entities have been processed.
Note that all selection sets have a zero-based index, and hence the first entity in the
selection resides at index 0, with the last entity at index sslength - 1 (i.e. the
number of items in the selection set minus one).
This example uses the same logic as the preceding example, except the counter
variable is initialised at the last index in the set, and decremented within the loop until
it reaches zero.
This approach removes the need for the 'restricting variable' as required by the
previous example.
Method 2: repeat
SELECT ALL
(defun c:test2 ( / e i s x )
(if (setq s (ssget))
(progn
(setq i 0)
(repeat (sslength s)
(setq e (ssname s i)
x (cdr (assoc 0 (entget e)))
i (1+ i)
)
(print x)
)
)
)
(princ)
)
The above function also uses a counter variable i which is incremented within
the repeat loop to iterate over the set, however, since the number of items in the set
can be determined before the loop is executed (using sslength), this more
efficient repeat loop may be utilised to iterate over the set a number of times equal to
the number of items in the set.
This example has a negligible difference in efficiency to the previous example, but is
more concise.
Method 3: ssnamex
SELECT ALL
(defun c:test3 ( / s )
(if (setq s (ssget))
(foreach e (ssnamex s)
(if (= 'ename (type (cadr e)))
(print (cdr (assoc 0 (entget (cadr e)))))
)
)
)
(princ)
)
The ssnamex function can be used to return information about how a selection set was
collected. This information also includes all of the entity names in the selection.
The above example will iterate over the list returned by ssnamex and process the
entities contained therein.
However, do not be deceived into thinking that this method is efficient simply because
it looks more concise than the previous examples...
Method 4: ssdel
SELECT ALL
(defun c:test4 ( / e s )
(if (setq s (ssget))
(while (setq e (ssname s 0))
(print (cdr (assoc 0 (entget e))))
(ssdel e s)
)
)
(princ)
)
This method iterates over a selection set by sequentially removing the first entity from
the set and exploiting the inherent behaviour of the selection set.
A selection set may be viewed as an array of entities. Each entity occupies a position,
or index, in the array, with the first entity occupying index 0.
When an entity is removed from the selection set, so as not to have a 'gap' in the
array, all entities occupying the positions above the removed entity are shifted down
to occupying the lower positions, thus filling the 'gap' created by the removed entity.
In this way, there will always be an entity occupying index 0 for as long as the
selection set is not empty.
However, the process of continually shifting the entities to new indexes in the
selection set is unnecessary and largely inefficient and so this method should be
avoided when processing selection sets containing many objects.
Note however, that when using this method, the VLA SelectionSet Object should be
deleted from the SelectionSets Collection after use, as there is a limit to the number
of SelectionSets permitted in this Collection.
Introduction
In my experience, very little documentation exists describing the purpose of the
apostrophe symbol in AutoLISP, and the explanations that I have encountered in
existing tutorials are usually quite brief and almost bypass the main purpose of this
operator.
Consequently, I have found that many novice AutoLISP programmers are often
confused when faced with this symbol in existing code, and can also be unaware of
when the apostrophe may and may not be used when writing code.
I have therefore put together an explanation that is hopefully comprehensible,
detailing the purpose of both the apostrophe operator and the
AutoLISP quote function, and the consequences of their use.
The Apostrophe
The apostrophe or single-quote character marks an expression or symbol as a literal
expression, to be taken at 'face-value' and not to be evaluated by the AutoLISP
interpreter.
The quoted expression may be any form of AutoLISP data, though the apostrophe is
usually used with lists or symbols, since most other forms of AutoLISP data (strings,
integers, reals) are already literal constants and hence do not require its use.
Constant Data
Expressions that contain constant or fixed data (that is, data that is unchanged when
evaluated) may be quoted as literal expressions, as there are no symbols within the
expression to be evaluated and consequently change the data content.
_$ (list 1 2 3 4 5)
(1 2 3 4 5)
The above list is constructed by passing each integer as an argument to
the list function. The list function will then evaluate each of the supplied arguments
and will return a list containing all arguments in the order in which they were passed
to the function.
However, since each integer is a constant, there is no need for the data to be
evaluated by the list function, as the result will be unchanged.
Therefore, this list may quoted as a literal expression using the apostrophe to yield
the same result:
_$ '(1 2 3 4 5)
(1 2 3 4 5)
The list of dotted pairs of constant data could equivalently be quoted as a literal
expression using the apostrophe to yield the same result without the evaluation of
three functions:
To offer a practical example, consider the list of dotted pairs which may be supplied to
the ssget function as the filter list argument.
The following example will retrieve a selection set of all Closed LWPolyline objects in
the drawing database:
Since the above filter list contains only constant data, the list may be quoted as a
literal expression using the apostrophe.
More information on the arguments available for use with the ssget function and the
filter list operators as used in this example can be found in my ssget Function
Reference.
Variable Data
There are of course limitations on when the apostrophe may be used to quote
AutoLISP data. One such limitation is when the data is not constant, but contains
symbols or expressions which, when evaluated, will yield different resulting data.
_$ (setq x 5)
5
_$ (list 1 2 3 4 x)
(1 2 3 4 5)
Here, the symbol x is assigned an integer value of 5; this symbol and the integers 1 to
4 are then passed as arguments to the list function.
Since each supplied argument is evaluated by the list function, the symbol x is
evaluated to yield the value 5, and the list is returned containing the evaluated value
of the symbol, as shown above.
However, observe the result when the list is quoted using the apostrophe:
_$ (setq x 5)
5
_$ '(1 2 3 4 x)
(1 2 3 4 X)
Since the apostrophe marks the list as a literal expression, the content of the list is
not evaluated by the AutoLISP interpreter, and the symbol x remains as a symbol in
the list.
Expanding on our previous practical example, let's say that we wish to prompt the
user to specify the name of a layer containing the Closed LWPolylines to be selected
by the ssget expression:
(if (snvalid (setq lay (getstring t "\nSpecify layer: ")))
(ssget "_X" (list '(0 . "LWPOLYLINE") '(-4 . "&=") '(70 . 1)
(cons 8 lay)))
)
Since the filter list now contains variable data as a result of the lay variable, the list
can no longer be quoted as a literal expression, but must be constructed using
the list function.
However, since three of the four dotted pairs contained in the filter list still contain
constant data, these dotted pairs may be quoted as literal expressions using the
apostrophe, with the final dotted pair constructed by passing the
two evaluated arguments to the cons function.
Function Arguments
Note that in the above examples the quoted lists would almost always be supplied as
arguments to other functions: whether that function is setq, to assign the data to a
variable; list, when constructing a list containing lists of constant data (as per the
last example); or perhaps ssget, as shown in the first selection example supplying
the ssget function with a quoted filter list argument; to name a few.
However, in general, the quoted argument need not necessary be a list, as the
following example demonstrates:
Finally, observe the following expression which invokes the Visual LISP
ActiveX getboundingbox method (for example, as used by my Bounding
Box & Selection Set Bounding Box functions):
(if (setq ent (car (entsel)))
(vla-getboundingbox (vlax-ename->vla-object ent) 'pt1 'pt2)
)
The getboundingbox method requires three parameters: the VLA-Object whose
bounding box is to be calculated, and two symbol parameters to hold the values
output by the method.
The utilisation of output parameters enables the method to return multiple values, as
opposed to the single value returned following function evaluation (which happens to
be nil for this method).
When invoking the method, the symbol parameters are quoted to ensure that the
symbol itself is supplied as an argument to the method, rather than the value
obtained when such symbol is evaluated. Following successful evaluation of the
method, the supplied symbols are assigned the lower-left & upper-right WCS
coordinates describing the bounding box of the supplied VLA-Object.
Similarly, the mapcar expressions from our previous examples could also be rewritten
using the quote function in place of the apostrophe:
_$ (mapcar (quote +) (quote (1 2 3 4 5)) (quote (6 7 8 9 10)))
(7 9 11 13 15)
However, where the second mapcar example is concerned, the lambda function may be
optimised when the code is compiled to a VLX or FAS file by substituting
the function function in place of the apostrophe or quote function:
_$ (mapcar (function (lambda ( a b ) (/ (+ a b) 2.0))) (quote (12.3
45.6 78.9)) (quote (32.1 65.4 98.7)))
(22.2 55.5 88.8)
The function function is identical to the quote function with the exception that it
instructs the Visual LISP compiler that the enclosed symbol or lambda expression is a
function argument which may be linked & optimised during compilation.
Since lambda expressions are defined at run-time, the Visual LISP compiler cannot
optimise these expressions during compilation, as is possible with built-in AutoLISP
functions or named functions defined with defun. Similarly, when quoted using the
apostrophe or quote function, the compiler treats the quoted lambda expression simply
as literal data, without linking or optimising the function.
However, by using function, the compiler is instructed to optimise the lambda function
during compilation to yield similar performance to built-in or named functions during
evaluation.
The function function can also be used with symbols defining any built-in or named
function, however, since these functions are already optimised when compiled, there
is very little gain in performance, if any.
Run-time Evaluation
Since the quote function operates in an identical manner to the apostrophe, it may
appear that this function is redundant since apparently the apostrophe could be used
in its place with far fewer keystrokes.
However, there are situations in which the quote function must be used in place of the
apostrophe to obtain the desired result.
One such example is literal expressions that are defined at run-time. (another
is quines...)
_$ (eval (list 'defun-q 'fun '( / lst ) (list 'setq 'lst (list 'quote
(list 0.0 (* pi 0.5) pi (* pi 1.5))))))
FUN
When evaluated, the above expression will define the function fun which contains a
single setq expression assigning a list of four numerical items (multiples of π) to the
local variable lst.
I have intentionally defined the above function using a defun-q expression so that the
result of the function definition may be revealed when the symbol fun is evaluated:
_$ fun
((/ LST) (SETQ LST (QUOTE (0.0 1.5708 3.14159 4.71239))))
Following definition of the function, observe that the setq expression is now assigning
a literal list to the symbol lst, without repeated calculation of the list items, and more
importantly, without any loss of precision of each item (the displayed values are
truncated when displayed at the console for ease of viewing, however, these values
are still stored to the maximum level of precision available).
Consider that in order to obtain the same result using a quoted literal list, each
irrational multiple of π would need to be expressed in the code to around 15 decimal
places to achieve the same precision.
Alternatively, the function could be defined such that the arithmetic expressions are
included in the function definition:
_$ fun
((/ LST) (SETQ LST (LIST 0.0 (* PI 0.5) PI (* PI 1.5))))
However, with the function defined in this way, the multiples of π are calculated and
re-calculated unnecessarily every time the function is evaluated, introducing
inefficiency. For the above example, this loss in performance is of course negligible
and one must also consider the negative effect on the readability of the code when
opting to define the function at run-time; however, if the list were to contain
potentially thousands of entries, the repeated calculation would soon become
noticeable.
Hence, this construct allows large literal lists which could be unmanageable to include
directly in the program source code to be constructed at run-time whilst
simultaneously retaining accuracy and improving efficiency.
To offer a concrete example of the quote function being used in this manner, consider
my GrText function. The quoted vector list which appears at the top of this function
definition is already quite large, but without the use of the run-time redefinition, the
literal list would be twice as large!
Function References
Below are links to the formal documentation for the various functions described
above.
As far as I am aware, there is no formal documentation for the apostrophe.
Quote Reference
Function Reference
quote (AutoLISP)
Signature
(quote expr)
expr
Type: Integer, Real, String, List, Symbol, File, Subroutine, Ename (entity name), T, or nil
An AutoLISP expression.
Return Values
Type: Integer, Real, String, List, Symbol, File, Subroutine, Ename (entity name), T, or nil
Examples
(quote a)
(quote (a b))
(A B)
Related Concepts
Related Reference
list (AutoLISP)
Tells the Visual LISP compiler to link and optimize an argument as if it were a built-in function
Signature
symbol
Type: Symbol
lambda-expr
Type: Subroutine or List
Return Values
The result of the evaluated expression.
Remarks
The function function is identical to the quote function, except it tells the Visual LISP
compiler to link and optimize the argument as if it were a built-in function or defun.
Compiled lambda expressions that are quoted by function will contain debugging
information when loaded into the Visual LISP IDE.
Examples
The Visual LISP compiler cannot optimize the quoted lambda expression in the following
code:
(mapcar
'(1 2 3))
After adding the function function to the expression, the compiler can optimize
the lambda expression. For example:
(mapcar
'(1 2 3))
Related Concepts
Related Reference
apply (AutoLISP)
defun (AutoLISP)
lambda (AutoLISP)
Introduction
This tutorial provides a step-by-step explanation of how to construct a simple block
counter program in AutoLISP, which will prompt the user for a selection of block
references and will output the quantities of each block in the selection to the AutoCAD
command-line.
The tutorial will demonstrate how to count the blocks by building an appropriate
association list to record the block names and their associated quantities - this
concept may then be applied to other applications which involve recording & updating
items of data.
The tutorial is aimed at those with a basic understanding of the AutoLISP language
and syntax, and, unlike most other tutorials written for beginners, the end result may
actually prove useful in real-world drafting work.
A Basic Framework
In the following steps, we shall first construct a basic framework for the block counter
program: defining a function which may be invoked from the AutoCAD command-line,
obtaining a selection of blocks to be counted, and constructing a means of iterating
over the selection.
Defining a Function
As the very first step, we shall define a function c:myblockcounter which will perform
all of the operations of the block counter:
SELECT ALL
(defun c:myblockcounter ( / ) ;; Define function
) ;; end defun
By prefixing the function name with c: the function may be evaluated directly at the
AutoCAD command-line using the command which follows this c: prefix,
i.e. myblockcounter.
A defun expression cannot be empty, so let us now include the expressions to be
evaluated when the function is invoked.
Obtaining a Selection
The first operation to be performed by the function is to obtain a selection of blocks to
be counted - for this we will use the ssget function.
The ssget function is a general selection function which may be used to obtain a
selection of multiple objects either from a user or automatically (a full reference
detailing all of the options offered by this function may be found here).
SELECT ALL
(defun c:myblockcounter ( / ) ;; Define function
(ssget) ;; Prompt the user to make a selection and return the
selection set if successful
) ;; end defun
Upon running the above program the user is prompted for a selection of objects, and,
if a valid selection is made, the function will return a pointer to the selection set,
otherwise, the function will return nil.
Notice that these values are returned at the command-line because
the ssget expression is the last expression evaluated within the defun expression and
therefore any value returned by the ssget function is then returned by
the defun expression.
However, as it stands, we cannot use the selection set returned by ssget, as the value
is not currently assigned to a variable and so cannot be referenced elsewhere in the
program. So we will now assign the value returned by ssget to a local variable sel.
SELECT ALL
(defun c:myblockcounter ( / sel ) ;; Define function
(setq sel ;; Assign the value returned by the following
expression to the symbol 'sel'
(ssget) ;; Prompt the user to make a selection and return the
selection set if successful
) ;; end setq
) ;; end defun
Note that the symbol sel has also been declared as a variable local to the
function c:myblockcounter within the symbol list for the defun expression - to
understand why this is important, see my tutorial on Localising Variables.
The current code still allows the user to select any object, so we can refine this
selection to only permit block references using an appropriate ssget filter list
argument:
SELECT ALL
(defun c:myblockcounter ( / sel ) ;; Define function
(setq sel ;; Assign the value returned by the following
expression to the symbol 'sel'
(ssget ;; Prompt the user to make a selection and return the
selection set if successful
'((0 . "INSERT")) ;; Filter the selection to block
references only (INSERTs)
) ;; end ssget
) ;; end setq
) ;; end defun
Finally, before we continue to attempt to process the selection of blocks, we should
first check whether the user has actually made a valid selection, or whether the user
has simply dimissed the prompt without selecting any block references.
Aside: you will note that, in AutoLISP, a conditional expression (such an if statement)
will be validated if the test expression returns any non-nil value - that is, the test
expression doesn't necessarily need to return T or True explicitly for the if statement
to be validated, for example consider the following:
(setq var 1)
(if var
(princ "Do this.")
(princ "Else do this.")
)
Here, the test expression is simply the symbol var - this symbol is evaluated by
the if function to yield any value it may have been assigned. In the above example,
the symbol var is a variable which has been assigned a value of 1. Since 1 is not equal
to nil, the if statement is validated and the 'then' argument will be evaluated.
Only if the test expression returns a value equivalent to nil will the 'else' expression
(if supplied) be evaluated.
Processing the Selection
Now that the function has been defined and we have obtained a selection of blocks
from the user, the program now needs to iterate over the selection to count the
number of occurrences of each distinct block.
For this, we can use Method 2a from my Selection Set Processing tutorial, which uses
a repeat expression to process each item in the set, starting with the item at the
highest index.
So, let us start by incorporating the repeat function into our existing code:
SELECT ALL
(defun c:myblockcounter ( / sel ) ;; Define function, declare local
variables
(if ;; If the following expression returns a non-nil value
(setq sel ;; Assign the value returned by the following
expression to the symbol 'sel'
(ssget ;; Prompt the user to make a selection and return
the selection set if successful
'((0 . "INSERT")) ;; Filter the selection to block
references only (INSERTs)
) ;; end ssget
) ;; end setq
(repeat ;; Repeat the enclosed expressions the following
number of times:
(sslength sel) ;; Return the number of items in the
selection set
) ;; end repeat
) ;; end if
) ;; end defun
Here, the repeat expression constitutes the 'then' argument for the if function; I
have omitted the 'else' argument, as it is not necessary to inform the user that no
objects were selected (they already know this!).
The sslength expression will return the number of items in our selection set sel and
will therefore cause the repeat expression to evaluate any enclosed expressions a
number of times equal to the number of objects selected by the user, hence
processing every selected block reference.
At this point it is worth noting that the sslength expression is the reason that
the if statement must be used: if the variable sel was nil, then (sslength
sel) would return an error (specifically, bad argument type: lselsetp nil), therefore,
the if statement ensures that the expression (sslength sel) is only evaluated if the
variable sel is non-nil and therefore contains a valid selection set.
Continuing with the 'Method 2a' structure, we can define an index variable idx and
access the block reference entity at each index in the selection set:
SELECT ALL
(defun c:myblockcounter ( / idx sel ) ;; Define function, declare
local variables
(if ;; If the following expression returns a non-nil value
(setq sel ;; Assign the value returned by the following
expression to the symbol 'sel'
(ssget ;; Prompt the user to make a selection and return
the selection set if successful
'((0 . "INSERT")) ;; Filter the selection to block
references only (INSERTs)
) ;; end ssget
) ;; end setq
(repeat ;; Repeat the enclosed expressions the following
number of times:
(setq idx ;; Assign the value returned by the following
expression to the symbol 'idx'
(sslength sel) ;; Return the number of items in the
selection set
) ;; end setq
(print ;; Print the following expression to the command-
line (just for testing)
(ssname sel ;; Retrieve the entity at the following
index
(setq idx (1- idx)) ;; Decrement the index
variable (since selection set indexes are zero-based)
) ;; end ssname
) ;; end print
) ;; end repeat
) ;; end if
) ;; end defun
To understand how this structure works, please read the Method 2a section of
my Selection Set Processing tutorial.
If we run the above program, selecting a set of blocks will cause each entity name in
the selection to be printed to the AutoCAD command-line, however, you will notice
something curious: selecting three block references will result in four entity names
being printed to the command-line, with the last entity name repeated e.g.:
SELECT ALL
Command: myblockcounter
Select objects: Specify opposite corner: 3 found
Select objects:
As a final step before we construct the association list to record the occurrences of
each block in the selection, we first need to obtain the name of each block.
The block name will be used as the 'key' for each item in the association list, with an
associated integer value corresponding to the number of occurrences of the block
name in the selection.
To obtain any property of an entity, we can query the DXF data stored in the drawing
database for the entity (the entity name is simply a pointer to this DXF data) - to
obtain this data, we use the entget function.
The DXF data returned by entget is itself an association list: a list containing any
number of sublists, with each sublist containing two items of data: a 'key' and its
associated value. Such sublists are known as 'dotted pairs'.
The block name for a block reference entity is the value associated with DXF group 2,
that is, the value associated with the sublist whose first element is the integer 2.
To obtain this item from the DXF data association list, we can use the assoc function
coupled with the cdr to obtain the associated value, which is then assigned to a local
variable blk:
SELECT ALL
(defun c:myblockcounter ( / blk idx sel ) ;; Define function, declare
local variables
(if ;; If the following expression returns a non-nil value
(setq sel ;; Assign the value returned by the following
expression to the symbol 'sel'
(ssget ;; Prompt the user to make a selection and return
the selection set if successful
'((0 . "INSERT")) ;; Filter the selection to block
references only (INSERTs)
) ;; end ssget
) ;; end setq
(repeat ;; Repeat the enclosed expressions the following
number of times:
(setq idx ;; Assign the value returned by the following
expression to the symbol 'idx'
(sslength sel) ;; Return the number of items in the
selection set
) ;; end setq
(setq blk ;; Assign the block name to the variable 'blk'
(cdr ;; Retrieve the value associated with DXF group
2 (the block name)
(assoc 2 ;; Retrieve the DXF group 2 dotted pair
from the following DXF data
(entget ;; Retrieve the list of DXF data for
the following entity
(ssname sel ;; Retrieve the entity at the
following index
(setq idx (1- idx)) ;; Decrement the
index variable (since selection set indexes are zero-based)
) ;; end ssname
) ;; end entget
) ;; end assoc
) ;; end cdr
) ;; end setq
(print blk) ;; Print the block name to the command-line
(just for testing)
) ;; end repeat
) ;; end if
(princ) ;; Suppress the return of the last evaluated expression
(if)
) ;; end defun
Upon testing the above, you will see the block name for each selected block reference
printed to the command-line.
Note that this may return anonymous block names for dynamic block references in the
selection: this is because a dynamic block reference will reference an anonymous
block definition when its dynamic block parameters are altered from those defined in
its original block definition. To convert these anonymous block names to the true
name of the dynamic block, we could use my Effective Block Name functions,
however, this is beyond the scope of this tutorial.
Note that the keys and associated values need not necessarily be strings - since
AutoLISP is dynamically typed, these may be any AutoLISP data type, and
furthermore, items within the association list may also contain data of varying types.
The keys within an association list also do not need to be unique (as an example,
consider the vertex DXF data for an LWPOLYLINE entity), however, it is usually far more
useful if the keys are unique.
An association list may be constructed in the same way as a standard list or dotted
pair: using the cons function. When the second argument supplied to the consfunction
is a list, the cons function will add (push) the first argument onto the front of the list:
_$ (cons 1 '(2 3 4 5))
(1 2 3 4 5)
In this way, we can construct an association list by repeatedly pushing dotted pairs
onto a list:
Before we count the occurrences of each block, let us first demonstrate how we are
going to construct the dotted pairs and association list which will record the block
count data.
SELECT ALL
(defun c:myblockcounter ( / blk idx lst sel ) ;; Define function,
declare local variables
(if ;; If the following expression returns a non-nil value
(setq sel ;; Assign the value returned by the following
expression to the symbol 'sel'
(ssget ;; Prompt the user to make a selection and return
the selection set if successful
'((0 . "INSERT")) ;; Filter the selection to block
references only (INSERTs)
) ;; end ssget
) ;; end setq
(repeat ;; Repeat the enclosed expressions the following
number of times:
(setq idx ;; Assign the value returned by the following
expression to the symbol 'idx'
(sslength sel) ;; Return the number of items in the
selection set
) ;; end setq
(setq blk ;; Assign the block name to the variable 'blk'
(cdr ;; Retrieve the value associated with DXF group
2 (the block name)
(assoc 2 ;; Retrieve the DXF group 2 dotted pair
from the following DXF data
(entget ;; Retrieve the list of DXF data for
the following entity
(ssname sel ;; Retrieve the entity at the
following index
(setq idx (1- idx)) ;; Decrement the
index variable (since selection set indexes are zero-based)
) ;; end ssname
) ;; end entget
) ;; end assoc
) ;; end cdr
) ;; end setq
(setq lst ;; Redefine the 'lst' variable with the
following updated list data
(cons ;; 'Push' a new item onto the front of the list
(cons blk 1) ;; Construct a dotted pair whose
first key is the block name and value is 1
lst ;; The list to which the item should be added
(may be nil)
) ;; end cons
) ;; end setq
) ;; end repeat
) ;; end if
(print lst) ;; Print the association list to the command-line
(just for testing)
(princ) ;; Suppress the return of the last evaluated expression
(print)
) ;; end defun
Most importantly at this stage is to remember to declare our list variable lst as a local
variable to our function c:myblockcounter - since the setq expression is redefining
the lst variable with each iteration, it is vital that the value of this variable is null
before the loop is evaluated, else the data will be compounded for every use of the
function.
Upon testing the above program, we will receive an output similar to the following:
Therefore we have now demonstrated how to construct a dotted pair for each block
name, and how to build an association list containing such dotted pairs.
To construct the block counter, it only remains to test whether the association list
already contains a dotted pair whose key is equal to the block name being processed,
and if so, increment the associated value, else add the new dotted pair to the
association list.
To achieve this, we will use the assoc and subst functions as described above:
SELECT ALL
(defun c:myblockcounter ( / blk idx itm lst sel ) ;; Define function,
declare local variables
(if ;; If the following expression returns a non-nil value
(setq sel ;; Assign the value returned by the following
expression to the symbol 'sel'
(ssget ;; Prompt the user to make a selection and return
the selection set if successful
'((0 . "INSERT")) ;; Filter the selection to block
references only (INSERTs)
) ;; end ssget
) ;; end setq
(repeat ;; Repeat the enclosed expressions the following
number of times:
(setq idx ;; Assign the value returned by the following
expression to the symbol 'idx'
(sslength sel) ;; Return the number of items in the
selection set
) ;; end setq
(setq blk ;; Assign the block name to the variable 'blk'
(cdr ;; Retrieve the value associated with DXF group
2 (the block name)
(assoc 2 ;; Retrieve the DXF group 2 dotted pair
from the following DXF data
(entget ;; Retrieve the list of DXF data for
the following entity
(ssname sel ;; Retrieve the entity at the
following index
(setq idx (1- idx)) ;; Decrement the
index variable (since selection set indexes are zero-based)
) ;; end ssname
) ;; end entget
) ;; end assoc
) ;; end cdr
) ;; end setq
;; If the block is already recorded in the list:
(if ;; If the following expression returns a non-nil
value
(setq itm ;; Assign the value returned by the
following expression to the symbol 'itm'
(assoc blk lst) ;; Attempt to retrieve a list
item whose first element is equal to the block name
) ;; end setq
;; Update the existing list entry:
(setq lst ;; Redefine the 'lst' variable with the
updated list data
(subst ;; Substitute the following list item in
the list
(cons blk (1+ (cdr itm))) ;; Increment the
number of occurrences recorded for this item in the list
itm ;; The existing item to be substituted
lst ;; The list in which to perform the
substitution
) ;; end subst
) ;; end setq
;; Else add a new entry to the list:
(setq lst ;; Redefine the 'lst' variable with the
following updated list data
(cons ;; 'Push' a new item onto the front of the
list
(cons blk 1) ;; Construct a dotted pair whose
first key is the block name and value is 1
lst ;; The list to which the item should be
added (may be nil)
) ;; end cons
) ;; end setq
) ;; end if
) ;; end repeat
) ;; end if
(print lst) ;; Print the association list to the command-line
(just for testing)
(princ) ;; Suppress the return of the last evaluated expression
(print)
) ;; end defun
To understand how this works, we can evaluate the expressions from the inside out
for a single iteration of the loop:
Let us assume that at some point in the process the variable lst contains the
following data:
(("Block 1" . 3) ("Block 2" . 1) ("Block 3" . 1))
Now let us observe what happens when the program encounters another block in the
selection with block name Block 2 by evaluating the various expressions from the
inside-out:
_$ (setq lst '(("Block 1" . 3) ("Block 2" . 1) ("Block 3" . 1)))
(("Block 1" . 3) ("Block 2" . 1) ("Block 3" . 1))
_$ (setq blk "Block 2")
"Block 2"
_$ (setq itm (assoc blk lst))
("Block 2" . 1)
_$ (cdr itm)
1
_$ (1+ (cdr itm))
2
_$ (cons blk (1+ (cdr itm)))
("Block 2" . 2)
_$ (subst (cons blk (1+ (cdr itm))) itm lst)
(("Block 1" . 3) ("Block 2" . 2) ("Block 3" . 1))
This is exactly how my Assoc++ function operates.
Upon testing the above program, we should now receive an association list detailing
the quantities of each block in the selection:
To achieve this, we can use a simple foreach loop to iterate over our association list
and print the data held by each dotted pair:
SELECT ALL
(defun c:myblockcounter ( / blk idx itm lst sel ) ;; Define function,
declare local variables
(if ;; If the following expression returns a non-nil value
(setq sel ;; Assign the value returned by the following
expression to the symbol 'sel'
(ssget ;; Prompt the user to make a selection and return
the selection set if successful
'((0 . "INSERT")) ;; Filter the selection to block
references only (INSERTs)
) ;; end ssget
) ;; end setq
(repeat ;; Repeat the enclosed expressions the following
number of times:
(setq idx ;; Assign the value returned by the following
expression to the symbol 'idx'
(sslength sel) ;; Return the number of items in the
selection set
) ;; end setq
(setq blk ;; Assign the block name to the variable 'blk'
(cdr ;; Retrieve the value associated with DXF group
2 (the block name)
(assoc 2 ;; Retrieve the DXF group 2 dotted pair
from the following DXF data
(entget ;; Retrieve the list of DXF data for
the following entity
(ssname sel ;; Retrieve the entity at the
following index
(setq idx (1- idx)) ;; Decrement the
index variable (since selection set indexes are zero-based)
) ;; end ssname
) ;; end entget
) ;; end assoc
) ;; end cdr
) ;; end setq
;; If the block is already recorded in the list:
(if ;; If the following expression returns a non-nil
value
(setq itm ;; Assign the value returned by the
following expression to the symbol 'itm'
(assoc blk lst) ;; Attempt to retrieve a list
item whose first element is equal to the block name
) ;; end setq
;; Update the existing list entry:
(setq lst ;; Redefine the 'lst' variable with the
updated list data
(subst ;; Substitute the following list item in
the list
(cons blk (1+ (cdr itm))) ;; Increment the
number of occurrences recorded for this item in the list
itm ;; The existing item to be substituted
lst ;; The list in which to perform the
substitution
) ;; end subst
) ;; end setq
;; Else add a new entry to the list:
(setq lst ;; Redefine the 'lst' variable with the
following updated list data
(cons ;; 'Push' a new item onto the front of the
list
(cons blk 1) ;; Construct a dotted pair whose
first key is the block name and value is 1
lst ;; The list to which the item should be
added (may be nil)
) ;; end cons
) ;; end setq
) ;; end if
) ;; end repeat
) ;; end if
;; Print the results (if they exist)
(foreach itm lst ;; For every 'itm' in the list given by 'lst'
(princ ;; Print the following to the command-line
(strcat ;; Concatenate the following strings
"\n" ;; (New-line character)
(car itm) ;; The block name
": " ;; An arbitrary separator for the data
(itoa (cdr itm)) ;; The number of occurrences of the
block, converted to a string
) ;; end strcat
) ;; end princ
) ;; end foreach
(princ) ;; Suppress the return of the last evaluated expression
(foreach)
) ;; end defun
You may have noticed that the foreach expression lies outside of the if statement,
and so the list variable lst may be nil when the foreach expression is evaluated.
This is not a problem since, as noted above, a nil value may be interpreted as an
empty list and so the foreach function will merely return nil without throwing an
error if the list argument is empty.
The foreach expression could alternatively be included as part of the 'then' argument
for the if function, which would also require the use of a progn expression so that
multiple expressions may be evaluated, but still supplied as a single argument for
the if function.
Testing the final program we will now receive an output similar to the following:
Block 1: 3
Block 2: 2
Block 3: 1
SELECT ALL
(defun c:myblockcounter ( / blk idx itm lst sel )
(if (setq sel (ssget '((0 . "INSERT"))))
(repeat (setq idx (sslength sel))
(setq blk (cdr (assoc 2 (entget (ssname sel (setq idx (1-
idx)))))))
(if (setq itm (assoc blk lst))
(setq lst (subst (cons blk (1+ (cdr itm))) itm lst))
(setq lst (cons (cons blk 1) lst))
)
)
)
(foreach itm lst (princ (strcat "\n" (car itm) ": " (itoa (cdr
itm)))))
(princ)
)
I hope you have enjoyed following this tutorial and writing the program for yourself!
Error Message
Troubleshooter
This page provides a brief guide detailing the possible causes of a selection of
common error messages received when executing an AutoLISP program.
malformed list
on input The code is missing one or more right parentheses.
extra right
paren on input The code has too many right parentheses.
malformed
string on The code contains a string which is missing a string delimiter ( " ).
input
too many
arguments A function has been evaluated with too many parameters.
too few
arguments A function has been evaluated with too few required parameters.
Function
cancelled The user has pressed the Esc key whilst running an AutoLISP function.
quit / exit
abort Either the (exit) or (quit) AutoLISP functions have been evaluated.
Application The user has pressed the Esc key whilst the program is evaluating
ERROR: Console
break the grread function without bit 3 (8) set in the allkeys parameter.
bad argument
type: fixnump: A function requiring an integer argument has been passed an argument
<value> of incorrect data type with the value noted in the error message.
bad argument
type: stringp A function requiring a string argument has been passed an argument of
<value> incorrect data type with the value noted in the error message.
Error Message Possible Cause
bad argument A function requiring an entity argument has been passed an argument
type: lentityp of incorrect data type with the value noted in the error message.
<value>
Usually a result of passing the entgetfunction a null entity argument.
bad argument
type: listp A function requiring a list argument has been passed an argument of
<value> incorrect data type with the value noted in the error message.
bad argument A function requiring either a string or symbol argument has been
type: (or passed an argument of incorrect data type with the value noted in the
stringp
symbolp): error message. Usually a result of passing
<value> the getvar or setvar AutoLISP functions an invalid first argument.
bad argument Most likely the result of supplying either the vl-string-search or vl-
value: string
position out string-positionfunctions a character index which is outside of the
of range range of characters available for the supplied string argument, e.g. (vl-
<index> string-search "a" "abc" 4)
bad argument A function requiring a positive numerical value has been passed a
value: non-
Error Message Possible Cause
The mode string argument (such as "_X") passed to the ssget function
bad ssget mode
string is invalid. See my ssget Function Reference for a list of valid mode
string arguments.
bad point The ssget function has been passed an invalid point list argument, or
argument none at all.
bad SSGET list One or more items in a filter list supplied to the ssget function is
value invalid.
Unknown The command you are attempting to call is not defined. This could be
command the result of a LISP program not being loaded, a command not being
"example".
Press F1 for available in the AutoCAD version you are running, or by including too
help. many 'enter' calls ("") in a command expression.
no function
definition: The Visual LISP ActiveX(COM) extensions for AutoLISP have not been
VLAX-GET-ACAD-
OBJECT loaded using the (vl-load-com) function. Add (vl-load-com) to
no function
definition:
your acaddoc.lsp or to the code you are trying to run, outside of any
VLAX-ENAME- function definition.
>VLA-OBJECT
ActiveX Server The program is attempting to access a ActiveX Property or Method with
returned the
error: unknown the name as noted in the error message which is not available for the
name: <name> supplied VLA-Object.
ActiveX Server
returned an The program is attempting to use the vlax-safearray->list function to
error: Invalid convert an empty safearray to a list.
index
Error Message Possible Cause
Automation The program is attempting to use the Item method of a VLA Collection
Error. Key not
found Object to access an item not present in that collection.
vlax-
safearray-fill
failed. The program is attempting to use the vlax-safearray-fill function to
Invalid populate a safearray with an incorrect number of items.
initialization
list.
function A function has been passed an argument of correct data type, but an
undefined for invalid value for the parameter. Usually caused by a mathematical
argument: function being passed an argument for which the operation is not
<value>
defined, e.g. supplying the sqrt function with a negative argument.
An Introduction to the Visual
LISP IDE
The Visual LISP IDE (rather, more precisely: Visual LISP Integrated Development
Environment (VLIDE) - but that's a bit of a mouthful), is an excellent developer tool &
resource supplied as standard with the majority of full versions of AutoCAD.
Even if you are just starting to program in LISP, in my opinion, the VLIDE is essential
and can be a great learning aid.
This tutorial will demonstrate how to get started with the VLIDE, and, to keep things
relatively clear, I won't be delving too deeply into the multitude of tools available to
the developer.
Introduction
To begin, open AutoCAD to a blank drawing and type VLIDE at the command line.
A window should appear, containing two or more smaller windows including the
Console Window & Trace Window (more on these later).
Let's begin by opening a New File in which we can start to construct a program. To do
this, go to File » New File (alternatively using the shortcut: Ctrl+N).
In the window that appears, we can start to construct our LISP program. As an
example, copy or type the following code into the blank editor window:
(defun c:test ( )
You will notice that the functions, brackets, strings and other items are highlighted
accordingly:
The syntax highlighting is a great visual aid, and also helps prevent protected symbols
such as function names being used as names for variables, as they are highlighted
accordingly.
At this point, we can study the code in more detail, and, if not sure about how a
function is to be used, we can immediately get information about that function using
the VLIDE Help Documentation. A tutorial on how to do this can be found here.
Also, we can open an existing LISP file to edit the contents in the VLIDE Editor
Window - to do this, either go to File » Open File or use the shortcut Ctrl+O.
Loading a Program
OK, so we've just constructed a program in the Visual LISP IDE, now to test it out!
As you may know, loading a program into AutoCAD can sometimes be tedious, as the
LISP file needs to be saved, then either loaded using the Appload command, or maybe
the ACADDOC.lsp. But, you'll be pleased to know, loading programs in the VLIDE
is much simpler.
There are three equivalent ways to load a program: by going to Tools » Load Text in
Editor; by clicking on the relevant toolbar icon on the Tools toolbar; or simply by
using the shortcut Ctrl+Alt+E.
Upon loading the program, the Visual LISP Console window will appear indicating
whether the code has been loaded successfully.
Now, having loaded the example code above, we can go back to the AutoCAD window,
and at the command line type: test to start the program.
A Few Examples
Evaluating a LISP Expression
_$ (+ 2 2)
4
Variable Evaluation
_$ (setq var 1.4142)
1.4142
_$ var
1.4142
Protected Symbol Evaluation
_$ actrue
1
_$ defun
#<SUBR @0fbfaaf0 DEFUN>
Calling a Function (using the example code from earlier)
_$ (c:test)
Further Information
This tutorial has covered the basics of the Visual LISP Integrated Development
Environment (VLIDE) - the Editor offers many essential debugging tools to get you out
of a fix when code goes wrong, and furthermore other tools to format code at the
touch of a button. Be sure to explore the VLIDE Help Documentation detailing how to
get the most out of the VLIDE.
Retrieving Information
About a Function
This tutorial details how to quickly retrieve information about an AutoLISP function
using the Visual LISP IDE.
To begin, open the Visual LISP IDE in an AutoCAD drawing by typing VLIDE at the
command line.
Either open the relevant AutoLISP file containing a function to query (Ctrl+O), or
create a New File (Ctrl+N) and type a function into the window.
To retrieve information about a function, highlight the function (double-click on it),
then click on the beige help button on the Tools toolbar.
Alternatively, highlight the function and press Ctrl+F1, then Enter.
If available, the relevant help documentation for the highlighted function will
subsequently be displayed:
Debugging Code with the
Visual LISP IDE
Ever spent a few hours writing a fantastic program only to find that it crashes the first
time it is run?
Now where could that error have come from...?
If you've ever delved into the world of AutoLISP, (or any programming language for
that matter) I can almost guarantee that you will have, at some point, encountered an
error when writing & running a program - it's almost inevitable:
As soon as we started programming, we found out to our surprise that it wasn't as easy to get
programs right as we had thought. Debugging had to be discovered. I can remember the exact
instant when I realized that a large part of my life from then on was going to be spent in finding
mistakes in my own programs.
- Sir Maurice Wilkes
At this point most users will find themselves scouring the code for typos and other
such mistakes - a process which could take just as long as writing the program itself.
This tutorial aims to teach you how to use the debugging facilities offered by the
Visual LISP IDE (VLIDE) to immediately detect the point at which a program has
crashed and furthermore show you the steps you can take to determine why the code
has crashed at that particular point.
This tutorial assumes the user has a basic knowledge of how to use the Visual LISP
IDE. If you are not one of these users, I would suggest that you give this a read: An
Introduction to the Visual LISP IDE.
Contents
Introduction
An Example Program
Where did the Code Fail?
Why did the Code Fail?
Adding Break Points
Watching Variables
Animating the Code
Resetting the Environment
Fixing the Code
Further Information
An Example Program
Throughout this tutorial I shall demonstrate various debugging methods using the
following test code which simply prompts the user for a selection of line entities and
proceeds to print the combined total length of the lines to the AutoCAD command-
line.
SELECT ALL
(defun c:linelen ( / ent enx idx sel ssl tot )
(if (setq sel (ssget '((0 . "LINE"))))
(progn
(setq ssl (sslength sel)
tot 0.0
idx 0
)
(while (<= idx ssl)
(setq ent (ssname sel idx)
enx (entget ent)
tot (+ tot (distance (cdr (assoc 10 enx)) (cdr
(assoc 11 enx))))
idx (1+ idx)
)
)
(princ (strcat "\nTotal length of lines: " (rtos tot)))
)
)
(princ)
)
(Can you spot the error in the code already?)
Begin by opening AutoCAD and typing VLIDE at the command-line to open the Visual
LISP IDE. Open a New File (File » New File or Ctrl+N) and either type or copy the
above code into the editor window.
Draw a few lines in AutoCAD with which to test the program. Now load the code in the
editor window (Tools » Load Text in Editor or Ctrl+Alt+E), and run it in AutoCAD by
typing the command syntax 'linelen' at the command-line.
After selecting a few lines, you will receive this error message at the command-line:
; error: bad argument type: lentityp nil
To answer this question, navigate back to the VLIDE and go to Debug » Break on
Error. Ensure this option is ticked.
By setting this option, the VLIDE will set a break point at the AutoLISP expression at
which the code fails. A break point is similar to a 'bookmark' in the code and will
cause the program to pause evaluation at the expression marked by the break point.
By instructing the VLIDE to automatically set a break point when the program
encounters an error, we can later return to this break point and quickly identify the
source of the error.
Be aware that assigning break points in the Visual LISP IDE does not modify the
AutoLISP file in any way, and such break points are not stored after the AutoLISP file
is closed.
Now, in AutoCAD, run the program again. When the code errors, navigate back to the
VLIDE window and go to Debug » Last Break Source (Ctrl+F9).
The expression at which the code has encountered an error should be highlighted in
the VLIDE Editor window:
Finally, reset the break point by going to Debug » Reset to Top Level (Ctrl+R); this
removes the break point and resets the paused interpreter (the object that evaluates
the AutoLISP code) to the start of the program.
So, now we know where the code fails, but why does it fail at that point?
Since we know that the error occurs within the while loop, we shall focus our
debugging efforts on that section of the code.
By pausing the AutoLISP interpreter, we can take control of the flow of evaluation,
starting & stopping the code when and where we like.
To do this, in the VLIDE Editor window, place your cursor in front of the opening
bracket of the while expression, click, and go to Debug » Toggle Break Point (F9).
The opening bracket of the while expression should be highlighted red.
Now place your cursor behind the closing bracket of the while expression and add
another break point following the same method as above.
Watching Variables
The Visual LISP IDE also allows us to 'watch' variables used in the code, displaying
their values as the code is evaluated. With this in mind, let's add a watch to the index
variable idx and the variable holding each line entity: ent.
To do this, double-click on any instance of the idx variable to highlight it and open the
Watch Window by going to View » Watch Window (Ctrl+Shift+W).
The variable idx should now appear in the Watch Window list, with a value
of nil (since it is local to the program and does not hold a value until the
relevant setqexpression is evaluated in the code).
With the Watch Window still open, double-click on any instance on the ent variable
and click on the Add Watch button in the Watch Window (the button with the glasses
symbol):
This variable should also now appear in the list, also with a value of nil.
When the code evaluation reaches our first break point, code evaluation will be
paused and the VLIDE Editor window will appear, highlighting the code between the
two break points. From here, we have complete control over the code evaluation. We
can step into and out of expressions and evaluate them as we please.
The code should now start to evalute, expression by expression from the break point
set earlier:
Notice how the variables in the Watch Window will change their values as the
various setq expressions within the while loop are evaluated.
The values shown in the Watch Window reveal the cause of our error: the value of
the ent variable becomes nil when our integer selection set index variable idxreaches
2.
This indicates that no entity is found in the selection set sel at the index 2, meaning
that the test condition for the while loop is allowing the counter to get too high before
the test condition returns nil and hence ceases evaluation of the while loop.
Finally, go to Debug » Animate and Debug » Break on Error and uncheck these
options.
With this knowledge, we can fix the code in the following way:
SELECT ALL
(defun c:linelen ( / ent enx idx sel ssl tot )
(if (setq sel (ssget '((0 . "LINE"))))
(progn
(setq ssl (sslength sel)
tot 0.0
idx 0
)
(while (< idx ssl) ;; Changed <= to <
(setq ent (ssname sel idx)
enx (entget ent)
tot (+ tot (distance (cdr (assoc 10 enx)) (cdr
(assoc 11 enx))))
idx (1+ idx)
)
)
(princ (strcat "\nTotal length of lines: " (rtos tot)))
)
)
(princ)
)
Further Information
For more information about the debugging capabilities of the Visual LISP IDE (VLIDE),
refer to the VLIDE Help Documentation:
A Shortcut to Localising
Variables
Introduction
When writing AutoLISP programs, declaring variables local to a program, or
colloquially, 'localising variables' is an important practice to follow.
Failure to declare a variable local to a program can, in some cases, lead to unforeseen
consequences as described in my tutorial on Localising Variables.
However, those who have written programs of reasonable length will know that
variable localisation can be a long and tedious process, often resulting in some
variables being mistyped or omitted completely.
Thankfully, the Visual LISP IDE (VLIDE) offers a much quicker way to declare
variables local. This tutorial will demonstrate a method to automatically report a list of
symbols defined in your program code, reducing the task of localisation to a simple
copy & paste operation.
Preliminary Setup
Before using the Checking utility offered by the Visual LISP IDE to report a list of
variables, first ensure the following settings are enabled in your environment. This
procedure will only need to be performed once.
First, open the Visual LISP IDE by typing 'VLIDE' at the AutoCAD command-line.
In the VLIDE, go to Tools » Environment Options » General Options
To serve as an example for this tutorial, open a New File in the VLIDE (File » New
File or Ctrl+N) and copy the following code into the editor window:
(defun c:test ( / )
(setq var1 1.0
var2 "abc"
var3 '(0 1 2 3 4)
)
(princ)
)
This very simple code defines three global variables, (var1, var2 & var3), which we
intend to declare local to the function c:test.
In the VLIDE, go to Tools » Check Text in Editor (alternatively, click the Check Edit
Window button on the Tools toolbar, or press Ctrl+Alt+C).
This utility will check the code for syntax errors and also return a list of global
variables defined in the code, the output may look something like this:
Warning!
The list returned by the VLIDE checking utility will list all defined symbols in the code.
This list may include protected symbols, such as functions or protected constants. If
such symbols are inadvertently localised, your program may not run as expected.
When copying the list of global variables ensure you remove the following items:
Finishing Touches
If, like me, you are obsessed with the look and layout of your code, you may not like
to have a capitalised list of local variables.
If you fall into this category of individuals, consider the following function:
Much nicer.
Further Information
The Checking utility available in the Visual LISP IDE has many more uses than merely
listing global variables; for more information about the full power of this tool, read the
following section of the Visual LISP IDE Help Documentation:
The Code
DCL File
Save this code in an AutoCAD Support Path as: listboxexample.dcl
SELECT ALL
// DCL File to be saved as listboxexample.dcl
// Example courtesy of Lee Mac © 2010 (www.lee-mac.com)
LISP File
This may be saved using an arbitrary filename, for loading instructions see How to
Run an AutoLISP Program.
When loaded, start the program using ListBoxExample at the command line.
SELECT ALL
(defun c:listboxexample ( / *error* UpdateList data dclfile dclhandle
)
(start_list key)
(mapcar 'add_list lst)
(end_list)
)
(setq Data
'(
("Audi" ("TTS Quattro" "TT RS" "S3 Quattro" "S4 Quattro" "S5
Quattro" "RS5 Quattro" "RS6 Quattro"))
("BMW" ("M3" "M5" "M6" "X5" "Z3" "Z4"))
("Porsche" ("911" "924" "928" "930" "944" "Boxster" "Cayenne"
"Cayman"))
("Jaguar" ("XF" "XJ6" "XJR" "XKR" "X-Type" "S-Type"))
)
)
(cond
( (<= (setq dclHandle (load_dialog dclFile)) 0)
;; List_Box 'lst1'
(UpdateList "lst1" (mapcar 'car Data))
(set_tile "lst1" *Make*)
;; List_Box 'lst2'
;; Action_tile Statements:
;; These control what happens when the user interacts with a
tile in the dialog.
(action_tile "lst1"
(strcat
"(UpdateList \"lst2\" (setq lst2 (cadr (nth (atoi (setq
*Make* $value)) Data))))"
"(setq *Model*"
" (set_tile \"lst2\""
" (if (< (atoi *Model*) (length lst2)) *Model* \"0\")"
" )"
")"
)
)
(start_dialog)
(setq dclHandle (unload_dialog dclHandle))
)
)
(princ)
)
The Result
Remembering Dialog
Position
This tutorial demonstrates how to 'remember' the position of a DCL dialog so that it
may appear in that position the next time the program is used.
This tutorial assumes the reader knows how to work with DCL using LISP to a basic level.
The example code shown below uses a global variable (namely *screenpoint*) to
store the position of the dialog. This data is stored as a 2D list representing the
position of the dialog on the screen. Alternatively, the positional data could be
converted to a string and stored in the registry to remember the dialog position
between drawing sessions.
To better understand how this screen coordinate is used to position the dialog, refer
to the VLIDE Help Documentation on the new_dialog & done_dialog functions -
seehere if you are unsure how to find this information.
The Code
DCL File
Save this code in an AutoCAD Support Path as: test.dcl
SELECT ALL
// DCL File to be saved as test.dcl
// Example courtesy of Lee Mac © 2011 (www.lee-mac.com)
LISP File
This may be saved using an arbitrary filename, for loading instructions see How to
Run an AutoLISP Program.
When loaded, start the program using test at the command line.
SELECT ALL
(defun c:test ( / *error* dcl dch )
(cond
(
(not
(and
(setq dcl (findfile "test.dcl")) ;; Check for DCL file
(< 0 (setq dch (load_dialog dcl))) ;; Attempt to load it
if found
)
)
(start_dialog)
Result
Function Format
(ssget [mode-string] [pt1 [pt2]] [pt-list] [filter-
list])
This mode string must be combined with other mode strings and
its own.
Example:
W (ssget "_W" '(3 2) '(5 4) '((0 . "TEXT")))
Selects all text objects residing entirely inside the rectangle with
Caution: only objects visible in the drawing area at the time of s
Consider temporarily zooming to the selection window before pe
to restore the original screen position.
o The following relational operators are only valid for use with groups containing
integer or real values; the bitwise operators are limited to integer values only.
Use wildcard patterns for testing strings.
o For point groups, the X, Y, and Z tests can be combined into a single string, with
each operator separated by commas (for example, ">,>,*"). If an operator is
omitted from the string (for example, "=,<>" leaves out the Z test), then the
'anything goes' operator, "*", is assumed.
o Direction vectors (DXF Group code 210) can be compared only with the
operators "*", "=", and "!=" (or one of the equivalent 'not equal' strings).
Equal
= Example:
(ssget '((0 . "CIRCLE") (-4 . "*,*,=") (10 0.0 0.0 4.0)))
Select circles with a center at an elevation of 4.0 units
Not Equal
!= All three listed operators are equivalent.
/=
<> Example:
(ssget '((0 . "CIRCLE") (-4 . "<>") (40 . 5.0)))
Select circles with a radius not equal to 5.0
Less Than
< Example:
(ssget '((0 . "ARC") (-4 . "<") (40 . 2.0)))
Select arcs with a radius less than 2.0
Less Than or Equal to
<= Example:
(ssget '((0 . "TEXT") (-4 . "*,<=") (11 0.0 10.0 0.0)))
Select text with alignment point with Y-coordinate less than or equal to 10.
Greater Than
> Example:
(ssget '((0 . "LINE") (-4 . ">,>") (11 3.0 3.0 0.0)))
Select lines with end point passing through a point with X & Y coordinate g
value.
>= Example:
(ssget '((0 . "POINT") (-4 . "<,>=,=") (10 5.0 7.0 0.0)))
Select points with X-coordinate less than 5.0, Y-coordinate greater than or
to 0.0
Logical Operators
<AND...AND>
Logical And
Since the ssget filter list has an implied AND operator (matching
used in conjunction with other logical operators to form compo
Example:
(ssget
'(
(-4 . "<OR")
(-4 . "<AND") (0 . "ARC") (40 . 1.5) (-4 .
(-4 . "<AND") (0 . "CIRCLE") (40 . 2.0) (-4 .
(-4 . "OR>")
)
)
Selects arcs with radius 1.5 or circles with radius 2.0.
Logical Inclusive Or
Logical Exclusive Or
Logical Not
System Variables
PICKADD
Controls whether subsequent selections replace the current selection set or add to it.
Turns on PICKADD.
1 Each object and subobject selected, either individually or by windowing, is ad
objects or subobjects from the set, press SHIFT while selecting.
Turns on PICKADD.
2
Same as PICKADD=1, but keeps objects selected after the SELECT command en
PICKAUTO
Controls automatic windowing at the Select Objects prompt.
Turns on PICKAUTO.
1 Draws a selection window (for either a window or a crossing selection) autom
user clicks in an empty drawing area.
PICKDRAG
Controls the method of drawing a selection window.
PICKFIRST
Controls whether you select objects before (noun-verb selection) or after you issue a
command.
0 Turns off PICKFIRST, you select objects after you issue a command
PICKSTYLE
Controls the use of group selection and associative hatch selection.
0 No group selection or associative hatch selection
1 Group selection
Existing Documentation
Below you will find various links to existing documentation referencing
the ssget function.
Standard ssget Function Reference
Selecting Objects and Selection Sets
Selection Set Filter Lists
Wildcard Patterns in Filter Lists
Filtering for Extended Data
Relational Tests
Logical Grouping of Filter Tests
Selection Set Manipulation Functions Reference
ssget (AutoLISP)
Signature
(ssget [sel-method] [pt1 [pt2]] [pt-list] [filter-list])
sel-method
Type: String
Object selection method.
Valid selection methods are
C -- Crossing selection.
CP -- Cpolygon selection (all objects crossing and inside of the specified
polygon).
F -- Fence selection.
I -- Implied selection (objects selected while the AutoCAD PICKFIRST system
variable is in effect).
L -- Last visible object added to the database.
P -- Last selection set created.
W -- Window selection.
WP -- WPolygon (all objects within the specified polygon).
X -- Entire database. If you specify the X selection method and do not provide
a filter-list, ssget selects all entities in the database, including entities on layers
that are off, frozen, and out of the visible screen.
:E -- Everything within the cursor's object selection pickbox.
:N -- Call ssnamex for additional information on container blocks and
transformation matrices for any entities selected during the ssget operation. This
additional information is available only for entities selected through graphical
selection methods such as Window, Crossing, and point picks.
Unlike the other object selection methods, :N may return multiple entities with the
same entity name in the selection set. For example, if the user selects a subentity
of a complex entity such as a BlockReference, PolygonMesh, or old style
polyline, ssgetlooks at the subentity that is selected when determining if it has
already been selected. However, ssget actually adds the main entity
(BlockReference, PolygonMesh, and so on) to the selection set. The result could
be multiple entries with the same entity name in the selection set (each will have
different subentity information for ssnamex to report).
pt1
Type: List
A point relative to the selection.
pt2
Type: List
A point relative to the selection.
pt-list
Type: List
A list of points.
filter-list
Type: List
An association list that specifies object properties. Objects that match the filter-
list are added to the selection set.
Return Values
Type: ads_name or nil
The name of the created selection set if successful; otherwise nil if no objects
were selected.
Remarks
Selection sets can contain objects from both paper and model space, but when
the selection set is used in an operation, ssget filters out objects from the space
not currently in effect. Selection sets returned by ssget contain main entities only
(no attributes or polyline vertices).
If you omit all arguments, ssget prompts the user with the Select Objects
prompt, allowing interactive construction of a selection set.
If you supply a point but do not specify an object selection method, AutoCAD
assumes the user is selecting an object by picking a single point.
When using the :N selection method, if the user selects a subentity of a complex
entity such as a BlockReference, PolygonMesh, or old style polyline, ssget looks
at the subentity that is selected when determining if it has already been selected.
However, ssget actually adds the main entity (BlockReference, PolygonMesh,
etc.) to the selection set. It is therefore possible to have multiple entries with the
same entity name in the selection set (each will have different subentity
information for ssnamex to report). Because the :N method does not guarantee
that each entry will be unique, code that relies on uniqueness should not use
selection sets created using this option.
When using the L selection method in an MDI environment, you cannot always
count on the last object drawn to remain visible. For example, if your application
draws a line, and the user subsequently minimizes or cascades the AutoCAD
drawing window, the line may no longer be visible. If this occurs, ssget with
the "L" option will return nil.
Examples
Prompt the user to select the objects to be placed in a selection set:
(ssget)
nil
Create a selection set of the objects crossing the box from (0,0) to (1,1):
(ssget "_C" '(0 0) '(1 1))
Create a selection set of the objects inside the window from (0,0):
(ssget "_W" '(0 0) '(5 5))
By specifying filters, you can obtain a selection set that includes all objects of a
given type, on a given layer, or of a given color. The following example returns a
selection set that consists only of blue lines that are part of the implied selection
set (those objects selected while the AutoCAD PICKFIRST system variable is in
effect):
(ssget "_I" '((0 . "LINE") (62 . 5)))
The following examples of ssget require that a list of points be passed to the
function. The pt_list variable cannot contain points that define zero-length
segments.
Create a list of points:
(setq pt_list '((1 1)(3 1)(5 2)(2 4)))
((1 1) (3 1) (5 2) (2 4))
Create a selection set of all objects crossing and inside the polygon defined
by pt_list:
(ssget "_CP" pt_list)
Create a selection set of all blue lines inside the polygon defined by pt_list:
(ssget "_WP" pt_list '((0 . "LINE") (62 . 5)))
The selected objects are highlighted only when ssget is used with no
arguments. Selection sets consume AutoCAD temporary file slots, so AutoLISP is
not permitted to have more than 128 open at one time. If this limit is reached,
AutoCAD cannot create any more selection sets and returns nil to
all ssget calls. To close an unnecessary selection set variable, set it to nil.
Related Concepts
Related Reference
ssgetfirst (AutoLISP)
ssadd (AutoLISP)
ssdel (AutoLISP)
You can interactively add objects to, remove objects from, or list objects in a selection
set. The following example code uses the ssget function to return a selection set
containing all the objects in a drawing.
(ssget "X")
AutoLISP provides a number of functions for handling selection sets. The following lists
some of the functions available for working with selection sets:
ssget - Prompts the user to select objects (entities), and returns a selection set.
ssadd - Adds an object (entity) to a selection set, or creates a new selection set.
ssdel - Removes an object (entity) from a selection set.
ssname - Returns the object (entity) name of the indexed element of a selection
set.
sslength - Returns an integer containing the number of objects (entities) in a
selection set.
The ssget function provides the most general means of creating a selection set. It can
create a selection set in one of the following ways:
Explicitly specifying the objects to select, using the Last, Previous, Window,
Implied, Window Polygon, Crossing, Crossing Polygon, or Fence options
Specifying a single point
Selecting all objects in the database
Prompting the user to select objects
With any option, you can use filtering to specify a list of properties and conditions that the
selected objects must match.
Note: Selection set and entity names do not remain the same between drawing
sessions.
The first argument to ssget is a string that describes which selection option to use. The
next two arguments, pt1 and pt2, specify point values for the relevant options (they
should be left out if they do not apply). A point list, pt-list, must be provided as an
argument to the selection methods that allow selection by polygons (that is, Fence,
Crossing Polygon, and Window Polygon). The last argument, filter-list, is optional. If filter-
list is supplied, it specifies the list of entity field values used in filtering. For example, you
can obtain a selection set that includes all objects of a given type, on a given layer, or of
a given color.
SSGET Examples
(setq ss1 (ssget)) Prompts the user for a general object selection
and places those items in a selection set
(setq ss1 (ssget "P")) Creates a selection set from the most recently
created selection set
(setq ss1 (ssget "L")) Creates a selection set of the last object added
to the database that is visible on the screen
SSGET Examples
(setq ss1 (ssget "W" pt1 pt2)) Creates a selection set of the objects inside the
window from (0,0) to (5,5)
(setq ss1 (ssget "F" (list pt2 pt3 Creates a selection set of the objects crossing
pt4))) the fence and defined by the points (5,5), (4,1),
and (2,6)
(setq ss1 (ssget "WP" (list pt1 pt2 Creates a selection set of the objects inside the
pt3))) polygon defined by the points (0,0), (5,5), and
(4,1)
(setq ss1 (ssget "X")) Creates a selection set of all objects in the
database
When an application has finished using a selection set, it is important to release it from
memory. This can be done by setting it to nil:
(setq ss1 nil)
Remember: You can also release the memory used by the values stored in a variable by
defining it as a local variable in a function.
Attempting to manage a large number of selection sets simultaneously is not
recommended. An AutoLISP application cannot have more than 128 selection sets open
at once. (The limit may be lower on your system.) When the limit is reached, AutoCAD
will not create more selection sets. Keep a minimum number of sets open at a time, and
set unneeded selection sets to nil as soon as possible. If the maximum number of
selection sets is reached, you must call the gc function to free unused memory before
another ssget will work.
Related Concepts
An entity filter list is an association list that uses DXF group codes in the same format as
a list returned by entget.
The ssget function recognizes all group codes except entity names (group code -1),
handles (group code 5), and xdata (group codes greater than 1000). If an invalid group
code is used in a filter-list, it is ignored by ssget. Use the group code -3 to search for
objects with xdata. When a filter-list is provided as the last argument to ssget, the
function scans the selected objects and creates a selection set containing the names of
all main entities matching the specified criteria. The filter-list specifies which property (or
properties) of the entities are to be checked and which values constitute a match.
For example, you can obtain a selection set that includes all objects of a given type, on a
given layer, or of a given color.
The following examples demonstrate different methods of using a filter-list with various
object selection options.
(setq ss1 Prompts for general object selection but adds only
(ssget '((0 . "TEXT"))) text objects to the selection set.
)
(setq ss1 Creates a selection set of all blue Line objects that
(ssget "I" '((0 . "LINE") (62 . 5))) are part of the Implied selection set (those objects
) selected while the AutoCAD PICKFIRST system
variable is in effect).
Note that this filter picks up lines that have been
assigned color 5 (blue), but not blue lines that
have had their color applied by the ByLayer or
ByBlock properties.
If both the group code and the desired value are known, the list may be quoted as shown
previously. If either is specified by a variable, the list must be constructed using
the list and cons function. For example, the following code creates a selection set of
all objects in the database that are on layer FLOOR3:
(setq lay_name "FLOOR3")
(setq ss1
(ssget "X"
If the filter-list specifies more than one property, an entity is included in the selection set
only if it matches all specified conditions, as in the following example code:
(ssget "X" (list (cons 0 "CIRCLE")(cons 8 lay_name)(cons 62 3)))
This code selects only Circle objects on layer FLOOR3 that are colored green. This type
of test performs a Boolean “AND” operation.
The ssget function filters a selection set by scanning the selected entities and
comparing the fields of each main entity against the specified filtering list. If an entity's
properties match all specified fields in the filtering list, it is included in the returned
selection set. Otherwise, the entity is not included in the selection set.
The ssget function returns nil if none of the selected entities match the specified
filtering criteria.
Note: The meaning of certain group codes can differ from entity to entity, and not all
group codes are present in all entities. If a particular group code is specified in a filter,
entities not containing that group code are excluded from the selection set
that ssgetreturns.
When ssget filters a selection set, the selected objects it retrieves might include entities
from both paper space and model space. However, when the selection set is passed to
an AutoCAD command, only entities from the space that is currently in effect are used.
(The space to which an entity belongs is specified by the value of its 67 group code.)
Related Concepts
The wild-card patterns recognized by ssget are the same as those recognized by
the wcmatch function. When filtering for anonymous blocks, you must precede the *
character with a reverse single quotation mark ( ` ), also known as an escape character,
because the * is read by ssget as a wild-card character.
For example, you can retrieve an anonymous block named *U2 with the following:
(ssget "X" '((2 . "`*U2")))
Related Concepts
You can select all entities containing extended data for a particular application using
the filter-list argument of ssget.
The filter-list argument must be a list that contains -3 as its first element. The following
example code selects all the objects in a drawing that include extended data for the
"APPNAME" application:
(ssget "X" '((-3 ("APPNAME"))))
You can also expand the scope of the filter to filter specific types of objects. The following
example code selects all the circles in a drawing that include extended data for the
"APPNAME" application:
(ssget "X" '((0 . "CIRCLE") (-3 ("APPNAME"))))
If more than one application name is included in the -3 group's list, an AND operation is
implied and the entity must contain extended data for all of the specified applications. So,
the following statement would select all the objects with extended data for both the
"APP1" and "APP2" applications:
(ssget "X" '((-3 ("APP1")("APP2"))))
Wild-card matching is also permitted, so either of the following statements will select all
the objects with extended data for either or both of these applications.
(ssget "X" '((-3 ("APP[12]"))))
Related Concepts
Unless otherwise specified, an equivalency is implied for each item in the filter-list.
For numeric group codes (integers, reals, points, and vectors), you can specify other
relations by including a special -4 group code that specifies a relational operator. The
value of a -4 group code is a string indicating the test operator to be applied to the next
group in the filter-list.
The following selects all circles with a radius (group code 40) greater than or equal to
2.0:
(ssget "X" '((0 . "CIRCLE") (-4 . ">=") (40 . 2.0)))
Operator Description
"=" Equals
The use of relational operators depends on the kind of group code value you are testing:
All relational operators except for the bitwise operators ("&" and "&=") are valid
for both real- and integer-valued groups.
The bitwise operators "&" and "&=" are valid only for integer-valued groups. The
bitwise AND, "&", is true if ((integer_group & filter) /= 0)—that is, if any of
the bits set in the mask are also set in the integer group code. The bitwise masked
equals, "&=", is true if ((integer_group & filter) = filter)—that is, if all bits
set in the mask are also set in the integer_group(other bits might be set in
the integer_group but are not checked).
For point group codes, the X, Y, and Z tests can be combined into a single string,
with each operator separated by commas (for example, ">,>,*"). If an operator is
omitted from the string (for example, "=,<>" leaves out the Z test), then the “anything
goes” operator, "*", is assumed.
Direction vectors (group code 210) can be compared only with the
operators "*", "=", and "!=" (or one of the equivalent “not equal” strings).
You cannot use the relational operators with string group codes; use wild-card
tests instead.
Related Concepts
You can define test groups with nested Boolean expressions to filter objects from a
selection set created with ssget.
The following table lists the grouping operators that you can use to filter selection sets:
The grouping operators are specified by -4 dxf group codes, like the relational operators.
They are paired and must be balanced correctly in the filter list or the ssget call will fail.
(ssget "X"
'(
(-4 . "<OR")
(-4 . "<AND")
(0 . "CIRCLE")
(40 . 1.0)
(-4 . "AND>")
(-4 . "<AND")
(0 . "LINE")
(8 . "ABC")
(-4 . "AND>")
(-4 . "OR>")
This filter list allows the selection of all circles with a radius of 1.0 plus all lines on layer
"ABC". The grouping operators are not case-sensitive; for example, you can
specify "and>", "<or", instead of "AND>", "<OR". Grouping operators are not allowed
within the -3 dxf group code. Multiple application names specified in a -3 dxf group code
use an implied AND operator. If you want to test for extended data using other grouping
operators, specify separate -3 dxf group codes and group them as desired.
The following example code demonstrates how to select all circles having extended data
for either application "APP1" or "APP2" but not both:
(ssget "X"
'((0 . "CIRCLE")
(-4 . "<XOR")
(-3 ("APP1"))
(-3 ("APP2"))
(-4 . "XOR>")
You can simplify the coding of frequently used grouping operators by setting them equal
to a symbol. The previous example could be rewritten as follows (notice that in this
example you must explicitly quote each list):
(setq <xor '(-4 . "<XOR")
(ssget "X"
(list
'(0 . "CIRCLE")
<xor
'(-3 ("APP1"))
'(-3 ("APP2"))
xor>
Related Concepts
The following table provides summary descriptions of the AutoLISP selection set
manipulation functions.
Function Description
(ssadd [ename [ss]]) Adds an object (entity) to a selection set, or creates a new
selection set
(ssget [mode] [pt1 [pt2]] [pt-list] [filter-list]) Prompts the user to select objects (entities), and returns a
selection set
(ssmemb ename ss) Tests whether an object (entity) is a member of a selection set
(ssname ss index) Returns the object (entity) name of the indexed element of a
selection set
(ssnamex ss index) Retrieves information about how a selection set was created
(sssetfirst gripset [pickset]) Sets which objects are selected and gripped
Related Reference
ssadd (AutoLISP)
ssdel (AutoLISP)
ssget (AutoLISP)
ssgetfirst (AutoLISP)
sslength (AutoLISP)
ssmemb (AutoLISP)
ssname (AutoLISP)
ssnamex (AutoLISP)
sssetfirst (AutoLISP)
AutoLISP Functions By Name and Feature Reference (AutoLISP)
The DXF™ format is a tagged data representation of all the information contained in an
AutoCAD ® drawing file. Tagged data means that each data element in the file is preceded by an
integer number that is called a group code. A group code's value indicates what type of data
element follows. This value also indicates the meaning of a data element for a given object (or
record) type. Virtually all user-specified information in a drawing file can be represented in DXF
format.
Related Concepts
Related Reference
Alphabetic List
ABCDEFGHIJKLMNOPQRSTUVWXYZ
Non-alphabetic
External
Feature List
Basic
Core functions that are used to perform mathematical calculations, manipulate list and
strings, provide error handling for programs, and much more.
Application-Handling
Arithmetic
Error-Handling
Function-Handling
List Manipulation
String-Handling
Symbol-Handling
Utility
Functions that are used to convert between data types, work with standard AutoCAD
commands, get input from the user at the command prompt, and much more.
Data Conversion
Device Access
Display Control
File-Handling
Geometric
User Input
Memory Management
Extended Data-Handling
Object-Handling
Image Tile-Handling
Application-Specific Data-Handling
ActiveX Object-Handling
ActiveX Property-Handling
Curve Measurement
Dictionary
Reactors
VLX Namespace
Namespace Communication
Related Concepts
Related Reference
All functions have a limit of 10 parameters, including the function name itself.
Function Description/Example
If the current thickness is set to 5, the following DIESEL string returns 15.
- (subtraction) Returns the result of subtracting the numbers val2 through val9 from val1
* (multiplication) Returns the result of multiplying the numbers val1 , val2 , …, val9 .
/ (division) Returns the result of dividing the number val1 by val2 , …, val9 .
= (equal to) If the numbers val1 and val2 are equal, the string returns 1; otherwise, it retu
< (less Than) If the number val1 is less than val2 , the string returns 1; otherwise, it return
The following expression gets the current value of HPANG; if the value is less th
variable USERR1, it returns 1. If the value 10.0 is stored in USERR1 and the cur
Function Description/Example
> (greater Than) If the number val1 is greater than val2 , the string returns 1; otherwise, it ret
!= (not Equal to) If the numbers val1 and val2 are not equal, the string returns 1; otherwise, it
<= (less Than or Equal to) If the number val1 is less than or equal to val2 , the string returns 1; otherwi
>= (greater Than or Equal to) If the number val1 is greater than or equal to val2 , the string returns 1; othe
and Returns the bitwise logical AND of the integers val1 through val9 .
angtos Returns the angular value in the format and precision specified.
Edits the given value as an angle in the format specified by the mode and pr
analogous AutoLISP function. If mode and precision are omitted, it uses th
UNITS command.
Note: AutoLISP is not available in AutoCAD LT.
The following mode values can be applied:
0, for Degrees
1, for Degrees/Minutes/Seconds
Function Description/Example
2, for Grads
3, for Radians
Edits the Julian date given by time (obtained, for example, from $(getvar,d
given picture ). The picture consists of format phrases replaced by specif
time. Characters not interpretable as format phrases are copied literally into the re
phrases are defined as shown in the following table.
For example, assume that the date and time are Saturday, 5 September 1998 4:53
phrases and output examples for edtime are as follows:
D-5
DD - 05
DDD - Sat
DDDD - Saturday
M-9
MO - 09
MON - Sep
MONTH - September
YY - 98
YYYY - 1998
H-4
HH - 04
MM - 53
SS - 17
MSEC - 506
AM/PM - AM
am/pm - am
A/P - A
a/p - a
Enter the entire AM/PM phrase as shown in the preceding table; if AM is used alon
the M will return the current month.
If any AM/PM phrases appear in the picture, the H and HH phrases edit the time ac
(12:00-12:59 1:00-11:59) instead of the 24-hour clock (00:00-23:59).
The following example uses the date and time from the preceding table. Notice th
quotation marks because it is read as an argument separator.
If time is 0, the time and date at the moment that the outermost macro was exec
and time-consuming multiple calls on $(getvar,date) and guarantees that s
(edtime) macros all use the same time.
eq If the strings val1 and val2 are identical, the string returns 1; otherwise, it re
The following expression gets the name of the current layer; if the name matches
USERS1 (USERS1-5) system variable, it returns 1. Assume the string "PART12
current layer is the same.
Note: The USERS1-5 system variables are not available in AutoCAD LT.
Eval Passes the string str to the DIESEL evaluator and returns the result of evaluatin
$(eval, str)
fix Truncates the real number value to an integer by discarding any fractional part
$(fix, value)
$(getenv, varname)
Getvar Returns the value of the system variable with the given varname .
$(getvar, varname)
Assumes that the string argument contains one or more values delimited by th
character, the comma. The which argument selects one of these values to be ex
numbered 0. This function is most frequently used to extract X, Y, or Z coordinate
returned by $(getvar).
Applications can use this function to retrieve values stored as comma-delimited s
variables.
Note: The USERS1-5 system variables are not available in AutoCAD LT.
If which is 0, nth returns arg0 , and so on. Note the difference between $(n
(nth) returns one of a series of arguments to the function, while $(index)
delimited string passed as a single argument. Arguments not selected by whicha
Rtos Returns the real value in the format and precision specified.
$(strlen, string)
Function Description/Example
Substr Returns the substring of string , starting at character start and extending f
Upper Returns the string converted to uppercase according to the rules of the curren
$(upper, string)
xor Returns the bitwise logical XOR of the integers val1 through val9 .
Related Concepts
Related Reference