Conditionals & Getkword |
![]() |
AutoLISP has two conditional functions -- cond and if. (See "5 - Conditionals" in the Catalog of function definitions.)
The cond function is the main conditional function, and it will do everything that if will do, plus more. However, the syntax of the if function is a little simpler, and every programming language has an if function. Thus, we start with if.
Function definitions for the tests used in both the if function and the cond function are given in "6 - Arithmetic tests" and "7 - Logic & category tests" in the "Catalog of function definitions."
The if function
In simple terms, the if function decides what to do based on a certain condition. It performs a test, then executes certain instructions (the then-portion) if the test returns T, or other instructions (the else-portion) if the test returns nil. The else portion is optional. The syntax of the if function includes either two or three arguments (the third argument is optional):
( IF-FUNCTION TEST THEN-PORTION ELSE-PORTION )
Here are some examples with only two arguments (the test and the then-portion). In each of the following examples, if the test returns T (that is, if the test is non-nil) then the then-portion is executed. If the test is nil, then the then-portion is not executed.
(if (= letter "A") (princ "\nLetter is A."))
(if (> pct 100.0) (princ "\nPercent too high."))
(if (< 0.5 len 9.5) (princ "\nLength is within
range."))
(if (not (< 0.5 len 9.5)) (princ "\nLength is
out of range."))
(if (= (type var1) 'INT) (setq var1 (+ 10 var1)))
(if (or (> rad len1) (> rad len2)) (princ "\nRadius
is two large."))
(if (minusp num) (setq num (- num)))
(if (= answer "Single") (progn (setq count (1+
count)) (tally 1)))
In the last example above, the progn function at the beginning of the then-portion groups the two functions (setq and tally) into a single larger function so they will both be executed when the test returns T. (The tally function is a user-defined function.)
Here are some examples with all three arguments (the test, the then-portion, and the else-portion). In each of the following examples, if the test returns T, then the then-portion is executed; but if the test returns nil, then the else-portion is executed.
(if (= letter "A") (princ "\nLetter is A.") (princ
"\nLetter is not A."))
(if (< 0.5 len 9.5) (princ "\nLength is within
range.") (princ "\nLength is out of range."))
(if (= answer "Single")
(progn (setq count (1+ count))
(tally 1))
(progn (setq count (+ count 2))
(tally 2))
)
The test does not need to be one of the formal tests such as "=" or "minusp." It can simply be a variable. The variable will be evaluated just like a formal test would and will return either some non-nil value (considered T) or nil. Any value, such as an integer, real, or string is non-nil. Even zero and a null string ("") are non-nil. Thus, you will sometimes see if statements that look like this:
(if var1 (setq var2 var1))
In the above statement, the first argument, var1, is a variable which serves as the test.
The if function has already been illustrated in several of the sample programs from previous lessons:
Lesson 3, BA program, Line 9
Lesson 5, TABLE program, Section 50
Lesson 6, BALLOON program, Sections
20 & 30
Lesson 7, RIGHTSA program, Section 20
Lesson 7, BCTABLE program, Section 40
The cond function
The cond function can apply many different tests, each test having a particular set of expressions to execute if the test returns T (non-nil).
The syntax of the cond function is rather unique because it can take one or many arguments. Each argument is a list. The first item in each list is the test, which is followed by one or more expressions to execute if the test returns T.
( COND-FUNCTION
( ( TEST ) ( EXPRESSIONS
) )
( ( TEST ) ( EXPRESSIONS
) )
( ( TEST ) ( EXPRESSIONS
) )
. . . . (as many lists as
needed)
)
The AutoLISP interpreter considers each argument in sequence — the first list, then the second, etc. When if finds a list whose test returns T, the expressions following that test (within the same list) are executed, and the rest of the lists are ignored. In other words, if the first test returns T, then the expressions which follow it are executed, and no more tests are performed. But if the first test returns nil, its expressions are not executed; rather, the second test is performed. This process continues until a list is found whose test returns T, then its expressions are executed, then the cond function ceases.
A common use of the cond function is to determine which option to execute after a menu has been displayed. For example, suppose a program has displayed the following menu
1 - Display answer as millimeters
2 - Display answer as centimeters
3 - Display answer as meters
4 - Display answer as kilometers
Enter number:
and saved the number entered by the user in variable ch. The following cond function will execute the appropriate subroutine.
(cond
((= ch 1) (disp-mill))
((= ch 2) (disp-cent))
((= ch 3) (disp-met))
((= ch 4) (disp-kilo))
)
Besides the use of formal tests and variables as the first argument, occasionally you will use a T or a constant (such as the number 1) because you want to force the test to pass. In that case the syntax will appear as follows:
( COND-FUNCTION
( ( TEST ) ( EXPRESSIONS
) )
( ( TEST ) ( EXPRESSIONS
) )
( 1 ( EXPRESSIONS ) )
)
The above form of the cond function is illustrated in the sample lesson below called rf.
Practice session
At the AutoCAD command prompt, or in a file, use several of the if-expressions illustrated above. In order to get a good feel for the cond function, re-program each of the if-expressions as cond-expressions.
The getkword function
The getkword function is somewhat similar to getstring, discussed earlier. However, getkword is specially designed to get a keyword, that is, one of several options available at a prompt.
For example, when you run the PLINE command in AutoCAD, after picking the first point, you can enter "A" for arc, "W" for width, etc. These additional options are selected by entering the appropriate keyword (or its abbreviation, which is the portion of the word that appears capitalized in the prompt).
In order to establish which keywords and abbreviations are allowed, the getkword function must be initialized by the initget function. Each of the options is included in a string argument with each option separated from the others by a space. In the following example, the initget function establishes two options, Left and Right. Since only the first letters of each word are capitalized, that is all that the user needs to enter as an abbreviation.
(initget "Left Right")
(setq direc (getkword "\nEnter direction (Left/Right):
"))
If the user enters just letter "L" (upper or lower case) then getkword returns the full word "Left" because of the way it was initialized. The user can enter additional letters such a "le" or "lef" or "left." If additional letters are entered, they must match those in the initget expression. The user can enter either the single letter abbreviation, or additional letters in any combination of upper and lower case letters. Whether the user enters the minimum (usually one letter), several letters, or the full word, getkword returns the full word capitalized like it is in the initget function. So, in the above example, if the user enters "riG," getkword returns "Right."
If the user enters a letter that is not a valid option (such as "J" in response to the above prompt), then getkword displays the message "invalid option keyword" and prompts the user to try again.
When two options begin with the same letter, then enough letters must be required to denote one option or the other. For example, if the two options are "lift" or "lower," then the initget function would need a string that included additional capitalized letters, as follows:
(initget "LIft LOwer")
In this case, if the user entered only the single letter "l," getkword would display a message indicating an ambiguous response and ask for clarification.
In the above example, the user could simply press 'Enter' instead of entering a direction. But that might make a program crash. Integers can be combined with the keywords in order to disallow null input, zero, negative numbers, etc. (See The initget function with an integer argument in Lesson 5 and initget in "4 - User input" in the "Catalog of function definitions.") For example, the following would keep the user from entering a null response.
(initget 1 "Left Right")
(setq direc (getkword "\nEnter direction (Left/Right):
"))
The getkword function can be initialized to accept integers, as illustrated below in the sample program called solids, section 20. Whether initialized with words or numbers, getkword always returns a string.
Another practice session
At the command prompt, enter each of the following pairs of lines, then respond to the prompt by entering inappropriate information, just to see how the initialized getkword function responds. Also make up some of your own. Notice in each case what the getkword function returns. In the third pair of lines below, be sure to try entering just letter "M" to see how getkword responds.
(initget "Yes No")
(getkword "\nYes or No? ")
(initget 1 "Yes No")
(getkword "\nYes or No? ")
(initget 1 "MInimum Small MEdium Large MAximum")
(getkword "\nSize (MInimum, Small, MEdium, Large,
or MAximum): ")
Sample program 1, solids
This program, called solids, calculates the volume and surface area of five solids -- box, cylinder, cone, sphere, and torus. After you study the program you might want to add sections which make the same calculations on other solids, such as the cube, wedge, hollow cylinder, square frustum, circular frustum, etc.
The menu displayed by section 20 includes five numbered lines and the user is expected to enter a number. That is why the initget function has "1 2 3 4 5" in the string. As an alternative, the menu could be presented without numbers and the user prompted to enter the first one or two letters of each solid. In that case, the initget function would appear something like this
(initget 1 "Box CYlinder COne Sphere Torus")
and the user would, at a minimum, have to enter "B" or "CY" or "CO" or "S" or "T".
By the way, we have violated the usual rule of indentation in section 30. Each of the initget expressions is on the same level as the following "(setq ... (getreal ..." expression which it initializes, and normally both would start in the same column (the same number of spaces from the left). However, in order to conserve vertical space, both are placed on the same line.
------ marker ------ beginning of working program ------ try it out ------
;| SOLIDS
Copyright © 1998 Ronald W. Leigh
Input: Type of solid, then its dimensions
Output: Volume and surface area of solid
Variables:
ch Choice of type of solid
hei Height
len Length
r1/r2 Radii of torus
rad Radius
sarea Surface area
sol Name of solid
vol Volume
wid Width
|;
;10====PROGRAM SETUP
(defun c:solids (/ ch hei len r1 r2 rad sarea sol vol wid)
(setq pi 3.1415926535897932385)
;20====DISPLAY MENU TO SELECT TYPE OF SOLID
(textscr)
(princ "\n\n======= CALCULATE VOLUME AND SURFACE AREA ========\n")
(princ "\n 1 - Box")
(princ "\n 2 - Cylinder (right, circular)")
(princ "\n 3 - Cone (right, circular)")
(princ "\n 4 - Sphere")
(princ "\n 5 - Torus")
(initget 1 "1 2 3 4 5")
(setq ch (getkword "\n\nEnter choice (1-5): "))
;30====DETERMINE SOLID AND CALCULATE
(cond
((= ch "1")
(setq sol "BOX")
(initget 7) (setq len (getreal "\nLength: "))
(initget 7) (setq wid (getreal "\nWidth: "))
(initget 7) (setq hei (getreal "\nHeight: "))
(setq vol (* len wid hei))
(setq sarea (+ (* 2 len wid) (* 2 len hei) (*
2 wid hei))))
((= ch "2")
(setq sol "CYLINDER")
(initget 7) (setq rad (getreal "\nRadius: "))
(initget 7) (setq hei (getreal "\nHeight: "))
(setq vol (* pi rad rad hei))
(setq sarea (+ (* pi rad rad 2) (* 2 rad pi
hei))))
((= ch "3")
(setq sol "CONE")
(initget 7) (setq rad (getreal "\nRadius of
base: "))
(initget 7) (setq hei (getreal "\nHeight: "))
(setq vol (/ (* pi rad rad hei) 3))
(setq sarea (+ (* rad pi (sqrt (+ (* rad rad)
(* hei hei))))
(* pi rad rad))))
((= ch "4")
(setq sol "SPHERE")
(initget 7) (setq rad (getreal "\nRadius: "))
(setq vol (/ (* 4 pi rad rad rad) 3))
(setq sarea (* 4 pi rad rad)))
((= ch "5")
(setq sol "TORUS")
(initget 7) (setq r1 (getreal "\nRadius of torus:
"))
(initget 7) (setq r2 (getreal "\nRadius of tube:
"))
(setq vol (* 2 pi pi r1 r2 r2))
(setq sarea (* 4 pi pi r1 r2)))
)
;40====DISPLAY ANSWERS
(terpri)
(princ sol)
(princ ": Volume = ")
(princ vol)
(princ " Surface area = ")
(princ sarea)
(princ "\n\n==================================================\n")
(princ)
)
-------- marker
-------- end of working program -------- try it out --------
Sample program 2, rf
This program also illustrates the cond function. It displays two types of reference files
_____________________ | ______________DECIMAL | EQUIV._______________ | _____________________ |
1/64 = .015625 | 17/64 = .265625 | 33/64 = .515625 | 49/64 = .765625 |
1/32 = .03125 | 9/32 = .28125 | 17/32 = .53125 | 25/32 = .78125 |
3/64 = .046875 | 19/64 = .296875 | 35/64 = .546875 | 51/64 = .796875 |
1/16 ===== .0625 | 5/16 ===== .3125 | 9/16 ===== .5625 | 13/16 ===== .8125 |
5/64 = .078125 | 21/64 = .328125 | 37/64 = .578125 | 53/64 = .828125 |
3/32 = .09375 | 11/32 = .34375 | 19/32 = .59375 | 27/32 = .84375 |
7/64 = .109375 | 23/64 = .359375 | 39/64 = .609375 | 55/64 = .859375 |
1/8 ====== .125 | 3/8 ====== .375 | 5/8 ====== .625 | 7/8 ====== .875 |
9/64 = .140625 | 25/64 = .390625 | 41/64 = .640625 | 57/64 = .890625 |
5/32 = .15625 | 13/32 = .40625 | 21/32 = .65625 | 29/32 = .90625 |
11/64 = .171875 | 27/64 = .421875 | 43/64 = .671875 | 59/64 = .921875 |
3/16 ===== .1875 | 7/16 ===== .4375 | 11/16 ===== .6875 | 15/16 ===== .9375 |
13/64 = .203125 | 29/64 = .453125 | 45/64 = .703125 | 61/64 = .953125 |
7/32 = .21875 | 15/32 = .46875 | 23/32 = .71875 | 31/32 = .96875 |
15/64 = .234375 | 31/64 = .484375 | 47/64 = .734375 | 63/64 = .984375 |
1/4 ====== .25 | 1/2 ====== .5 | 3/4 ====== .75 | 1 ======= 1.0 |
The user enters RF at the command prompt. Then, when prompted, enters the name of the reference file without any extension. If the reference file has a "TXT" extension, the program displays it within Windows Notepad. It can be removed simply by closing the Notepad window. If the file has an "SLD" extension, the program shows the slide within the current viewport. It can be cleared from the viewport by using the REDRAW command, or by pressing F7 once or twice.
If the reference file is located on the AutoCAD search path, all that is needed is the primary part of the file name. If the file is located somewhere outside the search path, then the full path is needed (all except the extension).
Notice the first list in the cond function. The setq expression is the test; the startapp expression is executed if the test returns non-nil. Inside the test, the strcat function adds the ".txt" extension to the reference file name and the findfile function returns the full path of the file if it is found anywhere on the AutoCAD search path.
The third list begins with "1," which serves as the test because it is the first item in the list. Since it is an integer, it is non-nil. So this test always returns T if the previous tests fail.
In order to make the RF "command" available at all times within AutoCAD,
you could place this program in an ACAD.LSP file located on the AutoCAD
search path so it is loaded automatically every time AutoCAD is opened.
------ marker ------ beginning of working program ------ try it out ------
;| RF, short for Reference File
Copyright © 1998 Ronald W. Leigh
Input: Name of reference file (.sld or .txt)
to display
Output: Displays file
Variables:
rfn Reference file name
rffn Reference file full name (with path & extension)
|;
(defun c:rf (/ rfn rffn)
(setq rfn (getstring "\nReference file name (do not include extension):
"))
(cond
((setq rffn (findfile (strcat rfn ".txt")))
(startapp "notepad" rffn))
((setq rffn (findfile (strcat rfn ".sld")))
(graphscr)
(command ".vslide" rffn)
(princ "\nRedraw screen to remove slide."))
(1 (princ "\n** Reference file not found."))
)
(princ)
)
-------- marker
-------- end of working program -------- try it out --------