Chapter 8. AutoLISP by Example: Getting Started

I don't know why more users don't write programs in AutoLISP; perhaps the very notion of programming is too intimidating. And yet nothing has more potential to expand your AutoCAD efficiency than programming new commands. Of all the programming tools out there, AutoLISP is the most accessible to AutoCAD users; but do I really think every user should know how to program in AutoLISP? Yes, I do—and you'll see why as you work through this chapter.

If the prospect of programming leaves you a bit daunted, I've got good news: If you can use AutoCAD, you can program in AutoLISP. To show you how easy it is, let's write a program right now. Just follow these steps:

  1. At the AutoCAD command line, type this: (defun C:OO()(setvar "osmode" 4143))

    AutoLISP by Example: Getting Started
  2. Clear your osnap settings in the Object Snap tab of the Drafting Settings dialog box.

  3. Type OO

    AutoLISP by Example: Getting Started

Congratulations, you've just written an AutoLISP program. To see what it did, check the settings for running object snaps again. We'll get back to this program after I give you a little background. When you finish this chapter, you'll be thinking up—and creating—all kinds of useful new AutoLISP functions of your own.

  • Background

  • Writing AutoLISP Programs

  • AutoLISP Examples

  • Automatic Loading

Background

AutoLISP is a powerful customizing tool with which you can write useful new AutoCAD commands in minutes. Although other programming languages are often used with AutoCAD (most notably Visual Basic for Applications [VBA] and C++), AutoLISP is an especially good choice for AutoCAD users because it relies heavily on native AutoCAD commands. It may not be the most sophisticated programming language, but what do you care as long as it's easy to use? Every accomplished VBA programmer I know still uses AutoLISP for some AutoCAD-related programming.

The AutoLISP programming language first appeared in AutoCAD R2.18. Its early appearance is one of the reasons AutoCAD is the most widely used CAD program today. The existence of a programming language made it possible for savvy users to dramatically improve AutoCAD by adding new functions. Those functions often became commands in later releases, but even when they didn't, they made AutoCAD much more useful than competing applications. Despite the appearance of other programming languages since its inception, AutoLISP is still the primary means by which users customize AutoCAD.

AutoLISP is a subset of LISP (List Processing), which goes back to the late 1950s. I've often seen LISP referred to as the second-oldest programming language still in use, Fortran being the oldest. In addition to its use in AutoCAD, LISP is still used widely in Artificial Intelligence programming.

Visual LISP (VLISP or VLIDE) appeared in AutoCAD 2000 as a major enhancement to AutoLISP. It adds a development environment with debugging tools and a compiler, as well as a set of new functions, including some known as reactors. Although I'll introduce some features of the Visual LISP editor in this book, I can't do it justice here. Once you get the AutoLISP bug, you can learn more about special Visual LISP editing features and the extensive collection of Visual LISP functions by consulting AutoCAD's help system for more information or using your favorite search engine to find Visual LISP references.

Note

You can access the AutoLISP, Visual LISP, and Drawing Interchange File (DXF) documentation by choosing Help → Additional Resources → Developer Help from the AutoCAD menu.

AutoCAD Commands

Because some commands and many Express tools are written in AutoLISP, most of us use AutoLISP programs on a regular basis without knowing it. The C:Program FilesAutoCAD 2007Express directory contains 70 AutoLISP programs, including the following programs that are so useful you might think they're native commands.

  • aliasedit.lsp

  • aspace.lsp

  • attout.lsp

  • breakl.lsp

  • bscale.lsp

  • burst.lsp

  • dimassoc.lsp

  • flatten.lsp

  • layoutmerge.lsp

  • lman.lsp

  • overkill.lsp

  • saveall.lsp

  • tcase.lsp

  • textmask.lsp

Finding AutoLISP Programs

You can find other AutoLISP programs at countless websites, in books, in magazines, and on the computers of your friends and colleagues. For a great place to start, visit the Autodesk User Group International website at www.AUGI.com. Other sites come and go, so I won't list them here, but a web search will turn up millions of AutoLISP programs on hundreds of thousands of sites. Many of them are free, because AutoLISP programmers are generous with their work. (Remember this when you become good enough to create useful programs.) Check the copyright information of any program you find, and always follow the author's requirements. After all, an AutoLISP program is the intellectual property of its author.

AutoLISP programs range from simple to complex, and they require a thorough knowledge of AutoCAD commands. Because you already know the AutoCAD command structure, you're ready to start programming in AutoLISP.

Writing AutoLISP Programs

I call this chapter "AutoLISP by Example" because I use code examples to demonstrate key features of programming. This chapter isn't for experienced programmers; it's for AutoCAD users. When I first decided to try AutoLISP, the reference I consulted began with a discussion about atoms, lists, Lambda expressions, cons, and Mapcar, with one-line examples that were out of context and meant nothing to me. I had a specific goal: to write a command that would automatically insert one drawing into another. I didn't solve my problem until I looked at actual programs to see how they worked. With that experience in mind, I'm going to give you sample programs and explain how they work. All you have to do is type them in correctly, try them, and read the explanations. It's that simple.

Program Structure

I want you to get started writing programs, but to avoid some common pitfalls, you should understand something about the structure of AutoLISP programs. These rules for program structure apply to all AutoLISP programs. They have the same importance to programming that the rules for sentence structure have to writing:

  • Every program contains one or more AutoLISP functions, such as DEFUN, GETPOINT, +, and -.

  • Each function name is preceded by an opening parenthesis.

  • Every opening parenthesis must have a balancing closing parenthesis somewhere.

  • Spaces or quotation marks are used to separate components within parentheses.

  • Functions are followed by arguments to the function, if they're necessary.

Let's take a computational function as an example. Because the division function in AutoLISP is represented by the forward slash, the syntax for dividing two numbers is as follows: (/ 4.0 2).

An open parenthesis is followed by the function / which is followed by at least one space, which is followed by at least two arguments separated by spaces—the numerator 4.0 and the divisor 2—followed by a closing parenthesis. This function would be translated into English as "divide 4.0 by 2." Other functions, such as (* 4.0 2), (+ 4.0 2), and (− 4.0 2) are formatted the same way. This isn't the same structure you may expect from having studied math, so don't try using (2 + 2). It won't work, because the first element after the parenthesis is an integer, not a function.

Entering Programs in AutoCAD

You can do all the programming you want in your mind, but until you enter your programs into AutoCAD they won't do anything. Unfortunately, there is no way to dump the contents of your head directly into AutoCAD, so you have to do some typing. There are three ways to get AutoCAD to use an AutoLISP program:

  • Type it at the command line.

  • Load a text file that contains AutoLISP code.

  • Use the load function of the Visual LISP editor.

Typing at the command line is generally used only for testing short lines of code. However, I often write a very short program this way when I need to do something that's so specific to the current drawing that there's no reason to save it. I did that recently to create polyline circles. I didn't think I'd need to do it again, so I just wrote a program at the command line. When I exited AutoCAD, the program ceased to exist.

Let's get the command-line procedure out of the way first.

Command-Line Entry

Go back to the program introduced in the introduction to this chapter. To enter that AutoLISP program at the command line, you did this:

  1. You typed (defun C:OO()(setvar "osmode" 4143))

    Command-Line Entry
  2. To test the program, you cleared your existing running osnaps.

  3. To use the new command you created, you typed OO at the command line. You should have seen "4143" returned.

  4. When you checked again, you should have had the following object snap settings: End, Mid, Cen, Nod, Int, Ext.

You just defined a new AutoCAD command with the name OO. When you type it, the setting for OSMODE, which controls your object snap settings, is changed to 4143. That happens to be the value of my standard running osnaps. I like this little command, because I often change to a single running object snap for a series of actions. When I want my old settings back, typing OO is much quicker than opening the Drafting Settings dialog box.

Note

AutoCAD uses system variables (sometimes referred to as setvars) to control many aspects of the program. All of AutoCAD's system variables (there are nearly 550 of them in AutoCAD 2007) can be read from AutoLISP using the GETVAR function, and many of them can be changed using the SETVAR function. OSMODE is such a setvar, for example. The more familiar you are with system variables, the more effectively you can use AutoLISP. You can view all setvars by typing setvar

Command-Line Entry

There's one problem. This nifty new command is stored in RAM, so it won't be available if you open another drawing, and it will disappear if you close the current drawing. If you want to use it again, you have to save it.

Command-Line Entry

Creating and Saving AutoLISP Text Files

To create reusable programs, you must save them in a text file with an .lsp extension. Like the acad.pgp file, AutoLISP files are American Standard Code for Information Interchange (ASCII) text files and can be created in Notepad or any other text editor. However, I far prefer AutoCAD's Visual LISP text editor, which you can start from the command line by typing VLISP or by selecting it from Tools → AutoLISP → Visual LISP Editor.

Load/Unload Applications Startup Suite

Figure 8.1. Load/Unload Applications Startup Suite

Once you've saved an AutoLISP file, you can load it using the APPLOAD (AP) command in AutoCAD. If you want it loaded every time you start AutoCAD, put the file in the Startup Suite of the Load/Unload Applications dialog box shown in Figure 8.1.

The Visual LISP Editor

Visual LISP has a couple of quirks. You can start Visual LISP by typing VLISP at the command line, but VLISP is actually an alias for Visual LISP Integrated Development Environment (VLIDE). It differs significantly from programs like Notepad. Because it's integrated into AutoCAD itself, it won't run on its own and must be started from an active AutoCAD drawing. While you're using it, it interacts with the AutoCAD drawing, so you should have an empty or dummy drawing open, not one that matters to you.

Unlike Notepad, the Visual LISP editor uses more than one window while you're editing a file:

  • The text editor in which you type your program (more than one can be open)

  • The Visual LISP Console, where you can type variable names or try small pieces of code

  • The Trace window, which can be used while debugging

  • The Build Output window, which shows the results of using the Check Edit Window button to check the program, including warnings and error messages

Four windows of the Visual LISP editor

Figure 8.2. Four windows of the Visual LISP editor

The four different windows are shown in Figure 8.2. Note that in the lower-right corner of the Visual LISP editor window is a report of both the line you're on and the character within that line (L00004 C 00001 in the illustration).

Although this illustration shows the four windows that can be open, they don't normally appear in this form. They may be minimized, placed on top of each other, or otherwise arranged. To keep them straight, notice that the three bottom windows have names that don't change: Visual LISP Console, Trace, and Build Output. You can minimize the Trace window and the Build Output window until you need them. The Visual LISP Console can be used for testing, but be careful—it's not where you type your program. That happens in the text editor, which in the illustration is the top window with the name TXTSCALE.LSP.

The text used in the text editor is displayed using different colors. The default colors are described in Table 8.1.

One more thing before you try your next AutoLISP text program. The tools I think you'll use most often are illustrated in Figure 8.3 on the Visual LISP toolbar. The Load Active Edit Window, Check Edit Window, and Format Edit Window tools apply to the entire file, but each of these buttons has a tool button to its right. These buttons have the same functions but apply only to text you've selected. They're helpful when you're testing only a portion of the file.

Selected toolbar buttons from the Visual LISP editor

Figure 8.3. Selected toolbar buttons from the Visual LISP editor

Table 8.1. Colors Used in the Visual LISP Text Editor

COLOR

USED FOR

Blue

AutoLISP functions like /, DEFUN, and SETQ

Magenta

Strings, which are always between quotation marks

Black

User-created items, such as program variables and function names

Green

Integer values

Teal

Real numbers, which must have a decimal point

Maroon on gray

Comments, which are preceded by a semicolon

Continue Continues running a program that you're testing after it stops at a break point.

Quit Stops the process when you're testing your program by executing it in a controlled fashion.

Colors Used in the Visual LISP Text Editor

Note

You'll also see this button if you switch from AutoCAD to the Visual LISP editor while a command is still active. The Reset button won't be available then. You have to go back to AutoCAD and exit the command.

Toggle Breakpoint Stops (breaks) the program at the cursor location as it runs so you can check for errors. A breakpoint is denoted by a red parenthesis.

Activate AutoCAD Switches from the Visual LISP editor to the AutoCAD drawing editor.

Watch Window Opens a window in which you can keep track of the value of your program variables, even local program variables, while debugging your program.

Load Active Edit Window Loads every line of code in the edit window—unless there are errors. The button to its right loads only text in the window that's been selected.

Check Edit Window Checks the structure (balanced parentheses, proper number of arguments, and so on) of the entire contents of the window. The results are displayed in the Build Output window. If an error is detected, place your cursor on the highlighted area in the Build Output window, and double-click to find the error in your program. The button to its right checks only highlighted text in the window.

Format Edit Window Formats the text in the entire window using rules that you can modify if you choose. Formatting doesn't affect how the code runs; it only affects how it looks. Until you have some experience writing AutoLISP programs, you should probably use the default settings. Like the two prior buttons, this one has a version to its right that you can use to format only highlighted text.

Comment Block Adds semicolons in front of the highlighted lines of text so AutoLISP won't try to execute them as part of the program. This is how you annotate your code.

I'll return to some of these tools in the debugging section.

AutoLISP Examples

Throughout this chapter, I'll use a number of programs to illustrate specific AutoLISP concepts. Neither this chapter nor the next is meant to cover all AutoLISP functions. In particular, I've omitted all discussion of the newer vl- prefixed functions. After you've digested the material in the next two chapters, I hope you'll develop programming skills that go well beyond what I'm covering here. In that process, don't overlook the Help system in the Visual LISP editor. It should be your first stop for answers to syntax questions about any particular function.

Note

You'll notice that many of the AutoCAD commands used in the programs in this chapter have a period and an underscore in front of their names. The period instructs AutoCAD to use the named command even if you've undefined it. The underscore tells AutoCAD to use the command, even if your version of AutoCAD is a non-English language version. Neither is necessary, but adding both is prudent.

At the beginning of this chapter, I showed you a simple AutoLISP program. Let's try another, so you can see how easy it is to define a new AutoCAD command. The two AutoLISP functions you need are DEFUN and COMMAND. But first, you need a problem whose solution requires a new command.

ZX Command

When you double-click the scroll wheel on your mouse, AutoCAD ZOOMs to the extents of your drawing, but that often puts entities too close to the edge of the screen. So, you roll the scroll wheel to zoom out just a little, but the screen zooms out too far. If only there were a command that would zoom to 95 percent of the extents, no matter what the current zoom magnification. Why not create one?

First, you have to identify the steps for performing the task manually. Then you can write an AutoLISP program that will execute the steps automatically.

To do a 95 percent zoom at the keyboard, you would have to go through the following steps:

  1. Type ZOOM

    ZX Command
  2. Type E for Extents and

    ZX Command
  3. Type ZOOM again, or

    ZX Command
  4. Type .95X

    ZX Command

The solution here is to combine all four steps into a single new AutoCAD command named ZX. To create the program, use the following steps:

  1. Start AutoCAD.

  2. Start the Visual LISP environment by typing VLISP or VLIDE, or by choosing Tools → AutoLISP → Visual LISP Editor.

  3. Start a new file using the New File option of the File pull-down menu in the Visual LISP editor.

  4. Add the following three lines to your new file:

    (defun C:ZX ()
      (command "._ZOOM" "_E" "._ZOOM" ".95x")
    )
  5. Pick the Load Active Edit Window button as shown in Figure 8.3.

    ZX program in the Visual LISP editor

    Figure 8.4. ZX program in the Visual LISP editor

  6. Switch back to AutoCAD, and draw some objects.

  7. Type ZX at the command line.

That's it. These three lines compose an entire AutoLISP program, which creates a new command named ZX that can be typed at the command line like any other command. By duplicating this basic format, you can create hundreds of other new commands. Make sure you review and understand the following explanations for each line:

(defun C:ZX () This line begins with an opening parenthesis, indicating to AutoCAD that an AutoLISP function will follow. You must enclose all elements in parentheses, and you must have a closing parenthesis for every opening parenthesis. Notice that this line has two opening, but only one closing, parenthesis. The second closing parenthesis appears at the end of the program on line 3, all by itself.

An AUTOLISP expression name must appear first after an opening parenthesis. The word DEFUN is an AutoLISP expression, which stands for define function. It's blue when you type it in the Visual LISP editor.

The C:ZX means that the AutoLISP function you're defining will operate as if it were an AutoCAD command. This code is black when typed in the Visual LISP editor. The C: means new AutoCAD command. ZX is the name of the new AutoCAD command you're creating, which can be called like any native command—typed, assigned to a toolbar button, assigned to a key, added to a cursor menu, or assigned to a mouse button. You can name your new command nearly anything you want except an existing command name. Well, you could use an existing command name if you undefined the command first, but let's avoid using existing commands or aliases for now. ZX makes sense to me—your command names should make sense to you.

The two parentheses () at the end of the line are empty for this program, but they must be there. In other programs, they may contain arguments or user-defined local program variables—more on that later.

Note

One confusing aspect of AutoLISP is the C: that appears before a new function name that will act as an AutoCAD command. People automatically think "hard drive." Get that thought out of your head. The C: stands for AutoCAD command.

(command "._ZOOM" "_E" "._ZOOM" ".95x") Once again, you start with an open parenthesis, so the first thing to appear must be the AutoLISP function. The COMMAND AutoLISP function allows you to use any native AutoCAD command within a new AutoLISP program. Use a command here, not an alias. "ZOOM" will work, but "Z" won't. Placing the dot and the underscore before the command name is optional.

This line of the code controls what happens on the screen when you use the ZX command. It issues the AutoCAD ZOOM command, followed by the E option. Then, it issues the ZOOM command again, followed by the scale option .95x. The entire line must be enclosed in parentheses. Anything you would normally type at the keyboard must be enclosed in quotes. In AutoLISP, anything in quotes is known as a string. Spaces between a closing quote and the next opening quote aren't necessary, but they make it easier to read your code.

Note

When you place a command like "ZOOM" in quotes, it's the same as typing it at the command line in AutoCAD followed by a

ZX program in the Visual LISP editor

) This line is simple: It closes the first parenthesis in the program. Placing it by itself at the end of a program makes it easier for you to see where each program ends and to match it with its opening parenthesis. When you're trying to debug a program, formatting parentheses in this way is very helpful.

The Visual LISP editor does some formatting of your code as you type, and most AutoLISP programmers do even more as they're writing (or coding). Use the Format Edit Window button to clean up the whole program when it's done.

Note

Despite what many people think, computers do only what they're told. You must be specific about what you want a program to do. Before writing any new command, go through the process at the keyboard to make sure you remember each step. Do you need the second ZOOM in this program? Yes you do, but you may overlook it if you don't go through the steps at the keyboard first.

Using the new ZX command

After you create a new command, you have to load it. Then you can type the command name at the keyboard, add it to a toolbar button, or even assign it so that right-clicking the mouse while holding down the Ctrl key will execute the command.

Defining Other New Commands

A cardinal rule of programming is to reuse code (either yours or someone else's) whenever possible. With these three lines, you have the basic syntax to write dozens of new commands. ZA and ZP require only that you simplify the command by replacing E with A and removing the second call to the ZOOM command. Other commands can be substituted for ZOOM, with their own options. Once you understand the format for creating these commands, the sky is the limit.

Improving the CIRCLE command

Try this small improvement in the way a circle is created in AutoCAD (see Listing 8.1). As all designers know, a circle is normally defined by its diameter, not its radius. This program introduces the PAUSE function. For the remainder of this chapter, you can add new programs to one file (make sure each program is enclosed in parentheses) or start a new file for each one. That's up to you.

Each line of this program is described in Table 8.2.

Example 8.1. Listing 8.1

circle-dia.lsp
        (defun C:C()
          (command "._CIRCLE" pause "D")
        )

Note

If you're wondering why the computer keeps printing the term nil at the end of your programs, don't worry—it's not a statement about your programming ability. Every program has to return a value. If no other value results from running your program, the value nil is returned. The solution is to add a (princ) function just before the last parenthesis of a program. You'll see that line in most AutoLISP programs. After all, who wants to be called "nil" every time they run a program?

Table 8.2. circle-dia.lsp

LINE OF CODE

PURPOSE

(defun C:C()

This line defines a new AutoCAD command named C. Note that this is the alias for CIRCLE, but a loaded AutoLISP function takes precedent over a command alias of the same name.

(command "._CIRCLE" pause "D")

This line executes the AutoCAD CIRCLE command, pauses so the user can select the center point for the circle, enters the option D for diameter, and stops.

)

This closing parenthesis matches the opening parenthesis and ends the DEFUN function.

Inserting Drawing Files

Now let's apply what you've learned to a new command that will automatically insert an existing title block drawing into the current drawing (see Listing 8.2). You've already seen almost everything you need in order to understand this. In order to try the program as it's written, you have to place a title block drawing with the name tbinch.dwg in C:locks. When you're done typing, select the Load Active Edit Window tool again.

Each line of this code is described in Table 8.3.

Example 8.2. Listing 8.2

ITB.lsp
        (defun C:ITB()
          (command "._INSERT" "c:/blocks/tbinch.dwg" "0,0" "" "" "")
        )

Table 8.3. ITB.lsp

LINE OF CODE

PURPOSE

(defun C:ITB()

This line defines a new command named ITB. I use uppercase for command names, but that isn't necessary.

(command "._INSERT" "c:/blocks/ tbinch.dwg" "0,0" "" "" "")

This line executes the AutoCAD INSERT command, gives the path and name of a file to insert, places it at 0,0, and accepts the next three default settings for X-scale, Y-scale, and rotation.

 

Notice anything about the path? You can't use a backslash to separate folders in AutoLISP. You can use a double backslash or a single forward slash.

 

The other thing to notice is that using the three pairs of double quotes is equivalent to entering

ITB.lsp

)

This closing parenthesis matches the opening parenthesis and ends the DEFUN function.

Note

When you try the steps of this program at the command line in AutoCAD, suppress the dialog box that normally pops up by placing a minus in front of the command. -INSERT is the command-line version of INSERT. Do the same for the LAYER command. You don't have to include the dash within your program. AutoLISP understands when not to open a dialog box.

Using Variables

Let's clear up any potential confusion about the term variables. AutoCAD has something called system variables; these are values that control the appearance or behavior of AutoCAD in some way. OSMODE is a system variable. You can determine the current setting for any system variable using the GETVAR function with the format (getvar "osmode").

You can also define your own program variables. You create these using the SETQ function of AutoLISP. The program variable you define can be used to represent almost anything: numbers, entities, anything typed by the user lists of coordinates, and so on.

To further complicate this distinction, the program variables that you define can be either global or local. If they're global, then once they're assigned a value of some kind, they keep that value even when your program is finished running. If the same variable name shows up again, it already has a value. To avoid unintended consequences, most users define program variables in AutoLISP programs as local—but not until they finish testing the program to make sure it works.

The program that created ZX required no additional information, either from the drawing or from the user. The ITB program you just wrote doesn't either, but maybe you can improve it. Wouldn't it be nice if the program automatically placed the title block on a particular layer? And wouldn't it be nice if it created the layer automatically after asking the user for a layer name and color? Although you'd probably prefer to put a standard layer name and color into the program by using a template, I'll show you the program in Listing 8.3 anyway, so you'll know how to get input from the user and save it to a program variable.

Example 8.3. Listing 8.3

InsertTB.lsp
        (defun C:InsertTB (/ lname lcolor ss1)
          (setq lname (getstring T "
Destination layer: "))
          (setq lcolor (getstring "
Layer Color: "))
          (command "._INSERT" "c:/blocks/tbinch.dwg" "0,0" "" "" "")
          (setq ss1 (entlast))
          (command "._LAYER" "N" lname "C" lcolor lname ""
                    "_CHPROP" ss1 "" "LA"      lname "")
        )

Each line of this code is described in Table 8.4. An explanation of the new functions follows.

Table 8.4. InsertTB.lsp

LINE OF CODE

PURPOSE

(defun C:InsertTB(/ lname lcolor ss1)

This line defines the new function that will act as a command named InsertTB with three local program variables. Local program variables are added here when you've finished the program and you know it works. Until you place them in this location, they're global program variables, not local.

(setq lname (getstring T " Destination layer: "))

This line sets the variable lname equal to whatever the user types in response to the prompt Destination Layer:. The T after getstring allows spaces to be included in the name. The is a control character meaning new line that tells AutoCAD to display the prompt on its own line. It must be lowercase.

(setq lcolor (getstring " Layer Color: "))

This sets the variable lcolor equal to what the user types in response to the prompt that follows.

(command "._INSERT" "c:/blocks/ tbinch.dwg" "0,0" "" "" "")

This executes INSERT, identifies the path and name of the drawing to insert, gives 0,0 as the insertion point, and accepts the default values of 1, 1, and 0 for the options X-scale, Y-scale, and rotation.

(setq ss1 (entlast))

This line uses the function ENTLAST to set variable ss1 equal to the last object created, which is the inserted title block.

(command "_LAYER" "N" lname "C" lcolor lname "" "_CHPROP" ss1 "" "LA" lname "")

This line creates a new layer if it doesn't already exist, giving it the name stored as a string in lname and the color saved in lcolor. Then it executes another AutoCAD command, CHPROP, selects the object represented by the variable named ss1, issues

InsertTB.lsp

)

This line closes the DEFUN statement.

This program is a little more involved and introduces three new functions:

  • SETQ creates program variables so values can be saved and used later in the program. There's a more involved discussion of the SETQ function later in the chapter, but you don't need to know anything else about it for now. Just use it as shown to store data.

  • GETSTRING is a function that returns anything the user types at the keyboard. If you want users to be able to type something that contains spaces, you must include the letter T as one argument—(getstring T " Name of layer: "). The T can be either uppercase or lowercase, but the must be lowercase.

  • ENTLAST selects the last entity created. Then, that entity can be assigned to a program variable.

Three program variables are created by the program: lname, lcolor, and ss1. I just made up their names. You can give program variables nearly any name, but here are some things to keep in mind:

  • Use variable names that will make sense to you a month from now when you may be trying to understand what your program does. I use a consistent naming convention for similar types of program variables. If I have multiple program variables representing selection sets, strings points, angles, distances, radiuses, diameter, and so on, I try to use program variables names like ss1, st1, pt1, ang1, dist1, rad1, and dia1. However, this system works only on relatively simple programs. On longer programs, you should use more descriptive names.

  • Don't use existing AutoLISP functions as variable names. You'll know you've done so when the name is colored blue instead of black when you type it into the Visual LISP editor. For example, PI, SET, and SETQ are AutoLISP functions and shouldn't be redefined as program variables. Once you've redefined a built-in function, it's no longer interpreted as a function.

  • You can use numbers in variable names, but a variable name can't be all numbers. The name must include at least one letter and no spaces; the only other characters allowed are $, _, <, >, and -.

GET Functions

GETSTRING isn't the only GET function. Table 8.5 shows all the functions designed to get information, with a brief description of each. These functions get information from the user, the drawing, or the environment (operating system).

Let's use some GET functions in another program to demonstrate how you can take points apart and put them back together.

Table 8.5. GET functions in AutoLISP

FUNCTION

PURPOSE

GETANGLE

Asks the user for an angle in radians, to be entered by typing or picking two points.

GETCORNER

Asks the user to pick or enter coordinates for the opposite corner of a rectangle.

GETDIST

Returns a real number provided by the user by typing or picking two points.

GETENV

Asks theregistry for the value of an environmental variable, like "username." OS variables aren't case sensitive, but AutoCAD environmental variables are: for example, "MaxHatch," and "MaxArray."

GETFILED

Asks the user to select a file using a dialog box.

GETINT

Asks the user for an integer, to be entered by typing or through the transparent use of 'CAL or 'QUICKCALC.

GETKWORD

Asks the user for a string that must match a previously defined keyword.

GETORIENT

Similar to GETANGLE, but is always based on a default 0 angle of east.

GETPOINT

Asks the user for a point, to be entered by typing or selecting a point.

GETREAL

Asks the user for a real number, to be entered by typing or through the transparent use of 'CAL or 'QUICKCALC.

GETSTRING

Asks the user for a string—any characters that can be typed.

GETVAR

Asks the drawing or registry for the value of an AutoCAD system variable, such as OSMODE.

INITGET

Establishes acceptable responses to other requests, particularly GETKWORD.

SSGET

Asks the user or the drawing for a selection set of objects.

Creating New Points

Two methods are especially useful for creating new points from user input. The first is to construct new points by calculating an X, a Y, and a Z coordinate, and then putting them into a list of three values using the LIST function. The second is to determine how far and at what angle a point is from another point, using the POLAR function.

Creating Points from Coordinates

In this next program, the user is prompted for two points. The program draws a rectangle using those points as corners and then adds lines across the corners to create an end-section symbol for a piece of structural lumber.

Creating Points from Coordinates

Example 8.4. Listing 8.4

SSECT.lsp
        (defun C:SSECT (/ pt1 pt2 pt3 pt4)
          (setq pt1 (getpoint "
First corner of rectangle: "))
          (setq pt2 (getcorner "
Diagonal corner of rectangle: " pt1))
          (setq pt3 (list (nth 0 pt1) (nth 1 pt2)))
          (setq pt4 (list (nth 0 pt2) (nth 1 pt1)))
          (command "._RECTANG" pt1 pt2 "._LINE" pt1 pt2 "" "._LINE" pt3 pt4 "")
        )

Each line of this code is described in Table 8.6.

Table 8.6. SSECT.lsp

LINE OF CODE

PURPOSE

(defun C:SSECT (/ pt1 pt2 pt3 pt4)

This line creates a new command named SSECT and identifies the program variables as local. Local variables retain the value given to them only while the program is running. If you hadn't placed them in the parentheses, they would be global program variables and would retain their values after the program ended. Note the space after the forward slash.

(setq pt1 (getpoint " First corner of rectangle: "))

This line sets the variable pt1 equal to a point supplied by the user. The quoted string will be displayed at the command line. The (must be lowercase) is a control character that means new line. If you leave it out, the prompt is placed on the same line in the AutoCAD command window as the last information printed there.

(setq pt2 (getcorner " Diagonal corner of rectangle " pt1))

This line sets the variable pt2 equal to the point supplied by the user in response to the prompt for the GETCORNER function. GETCORNER differs from GETPOINT because it displays a rectangle on the screen as the user moves the cursor to select the second point. Note that the first point (pt1) must be referenced in this line either before or after the prompt.

(setq pt3 (list (nth 0 pt1) (nth 1 pt2)))

Working from the inside out, you can say that this line takes the X value of pt1 and the Y value of pt2 and combines them into a new point.

 

In AutoLISP, a coordinate point is a list of three values. To create a new point, you need to create a list of at least two values. The function LIST is used to create a new list.

 

To create pt3, you use the X coordinate of pt1 using (nth 0 pt1) and the Y coordinate of pt2 using (nth 1 pt2). The list of two values is assigned to the variable pt3 by the SETQ function.

(setq pt4 (list (nth 0 pt2) (nth 1 pt1)))

This line sets the variable pt4 equal to the X value of pt2 (nth 0 pt2) and the Y value of pt1 (nth 1 pt1) and combines them using LIST to create a new list, which is assigned to variable pt3 using the SETQ function.

(command "._RECTANG" pt1 pt2 "._LINE" pt1 pt2 "" "._LINE" pt3 pt4 "")

Now that you have program variables representing the four points, the rest is easy. The COMMAND function is used to call up the RECTANG command and feed it pt1 and pt2, which draws a rectangle. While the COMMAND function is open, you can call another AutoCAD command, LINE, and use your four points to create the two lines of the section symbol.

)

This closes the DEFUN function, as you've seen before.

Creating Points with Distances and Angles

The POLAR function lets you create a new point from an existing point when you know, or can calculate, how far and at what angle from the existing point you want the next point to appear. The example in Listing 8.5 uses the POLAR function to calculate a point halfway between any two points selected by the user. It then uses the AutoCAD POINT command to place a point at that location. The purpose of the program is to provide a convenient means of adding dimensions to floor plans when the location of walls is determined to their center. Because there's nothing that you can snap to between the lines representing walls, dimensioning them can be tricky. But if you place points there, the Node object snap can be used as the origin of dimensions. If you want a better view of the points, set a new point style by choosing Fomat → Point Style and picking one you like.

This program uses the SETVAR function seen in the first program you wrote; it demonstrates how to change existing system variables and then politely return them to their original form. This program, like all programs, should have error trapping, but I'm leaving that subject for Chapter 9, "AutoLISP by Example: Getting Better."

Each line of this program is described in Table 8.7.

Example 8.5. Listing 8.5

mid.lsp
        (defun C:MID (/ pt1 pt2 os ap mid)
          (setq os (getvar "osmode")
                ap (getvar "aperture"))
          (setvar "osmode" 512)
          (setvar "aperture" 3)
          (initget 1)
(setq pt1 (getpoint "
First point: "))
 (initget 1)
 (setq pt2 (getpoint "
Second point: " pt1))
 (setq mid (polar pt1
           (angle pt1 pt2)
           (/ (distance pt1 pt2) 2.0)))
 (command "._POINT" "non" mid)
 (setvar "osmode" os)
 (setvar "aperture" ap)
 (princ)
)

Table 8.7. mid.lsp

LINE OF CODE

PURPOSE

(defun C:MID (/ pt1 pt2 os ap mid)

Defines the new function that will act as an AutoCAD command. Each variable is made local.

(setq os (getvar "osmode")

Gets the current value of the OSMODE variable from the drawing and stores it by assigning it to variable os. You do this because the program will change OSMODE, and you want to change it back when the program is complete.

ap (getvar "aperture"))

Gets the current value of the APERTURE variable from the drawing and stores it by assigning it to variable ap. If the aperture is too large, it can be difficult for the user to snap to a line in a cluttered area. Because the program will change the setting for this variable, you need to save the current setting so you can change that back also.

(setvar "osmode" 512)

Sets OSMODE to 512, which is the Nearest osnap.

(setvar "aperture" 3)

Sets APERTURE to 3 pixels to make it small enough to prevent snapping to the wrong line on the drawing.

(initget 1)

Prevents the user from using a

mid.lsp

(setq pt2 (getpoint " Second point: "))

Prompts the user to select the first point, and then assigns the point they selected to the variable pt1 as a list of three values: X, Y, Z of the point.

(initget 1)

Prevents

mid.lsp

(setq pt2 (getpoint " Second point: " pt1))

Prompts the user to select the second point, and then assigns the point they selected to the variable pt2 as a list. Referencing pt1 after the prompt causes a rubber-band line to be used from pt1 during the selection.

(setq mid (polar pt1

Assigns a value to the variable mid using the POLAR function. That function requires a starting point, which is given in this line as pt1. The next two lines complete the SETQ function that is started here.

(angle pt1 pt2)

Provides the angle needed by the POLAR function by using the ANGLE function to determine the angle from pt1 to pt2.

(/ (distance pt1 pt2) 2.0)))

Provides the last piece of information needed by the POLAR function. The distance is calculated so that variable mid can be assigned a point halfway between pt1 and pt2. To calculate that distance, the / function is used to divide the distance between pt1 and pt2 by the real number 2.0.

(command "._POINT" "non" mid)

Uses the AutoCAD command POINT to place a point at the location assigned to the variable mid. "non" is used to temporarily turn off the running osnap so it can't override the location by snapping to an object.

(setvar "osmode" os)

Resets the AutoCAD variable OSMODE to the value it had at the beginning of the program.

(setvar "aperture" ap)

Resets the AutoCAD variable APERTURE to the value it had at the beginning of the program.

(princ)

Prints a clear line at the command prompt to prevent the program from returning the value nil.

)

Ends the DEFUN function.

Performing Calculations

AutoLISP programs often require mathematical calculations, so this is a good time to reiterate the syntax of all AutoLISP functions. The function always comes first, immediately after the opening parenthesis in AutoLISP. The function is then followed by arguments. AutoLISP uses two kinds of numbers: integers, which have no decimal point; and real numbers (also known as floating-point decimals), which have a decimal point but no other characters. $1.00 isn't a real number, but 1.00 is.

Computational Basics

Let's look at several attempts you might make to write code for performing basic calculations, to see what kinds of pitfalls await you:

  • (3 + 3) returns error: bad function: 3, because 3 isn't a function. Start with the + function.

  • (/ 3 2) returns the integer 1, because both arguments are integers.

  • (/ 3.0 2) returns the real number 1.5, because one of the arguments is a real number.

  • (* .5 2) returns error: misplaced dot on input, because there is no leading zero.

  • (* 0.5 2) returns the real number 1.0, because the leading zero is used.

Math Functions

The following functions perform calculations or conversions with AutoLISP:

  • - subtracts from the first number those that follow.

  • * multiplies all numbers listed.

  • + adds all numbers listed.

  • /divides the first number by those that follow.

  • 1+ adds 1 to a number. It can be used when indexing a list.

  • 1- subtracts 1 from a number. It can be used when indexing a list.

  • ABS returns the absolute value of a number. (abs −3) returns 3.

  • ATAN returns the arc tangent of an angle in radians.

  • COS returns the cosine of an angle in radians.

  • CVUNIT converts from one system of units to another. (cvunit 25.4 "mm" "inches") returns 1.

  • EXPT raises a root to a power. (expt 10 3) returns 10 cubed, or 1000.

  • FIX converts a real number to an integer—(fix 34.9) returns 34.

  • FLOAT converts an integer into a real number —(float 3) returns 3.0.

  • MIN returns the smallest number in a list.

  • MAX returns the largest number in a list.

  • PI returns the value of ω. Don't redefine this variable.

  • REM returns the remainder after dividing two numbers. (rem 10 3) returns 1.

  • SIN returns the sine of an angle in radians. (sin 45) returns 0.850904.

  • SQRT calculates the square root of a number. (sqrt 10) returns 3.16228.

Calculating Within a Program

The program in Listing 8.6 converts from inches to millimeters. As you know, 25.4 millimeters equals 1 inch. After trying this program, see if you can write a program that does the conversion in the other direction—from millimeters to inches.

Using an alert box in AutoLISP

Figure 8.5. Using an alert box in AutoLISP

Each line of this code is described in Table 8.8.

The result of using this program to convert 126.78″ into millimeters is shown in Figure 8.5.

Example 8.6. Listing 8.6

I2M.lsp
        (defun C:I2M (/ in mm st1 st2)
          (setq in (getdist "
Value in inches: "))
          (setq mm (* in 25.4))
          (setq st1 (rtos in 2 3))
          (setq st2 (rtos mm 2 2))
          (alert (strcat "Value of " st1 " inches is " st2 " mm"))
          (princ)
        )

Table 8.8. I2M.lsp

LINE OF CODE

PURPOSE

(defun C:I2M (/ in mm st1 st2)

Defines a new command function, and identifies local program variables.

(setq in (getdist " Value in inches: "))

Sets the variable in equal to a real number that's either typed or returned by picking two points.

(setq mm (* in 25.4))

Sets the variable mm equal to the result of multiplying the variable in by 25.4.

(setq st1 (rtos in 2 3))

Converts a real number into a string using the AutoLISP function RTOS. The value is reported in an alert box. The integers 2 and 3 used here control the format in which the numerical string is displayed. In this case, it will be in decimal format to a precision of three decimal places. The string is assigned to variable st1.

(setq st2 (rtos mm 2 2))

Performs the same conversion as the previous line for the metric value stored in mm. It's also in decimal format, but only to two decimal places, which is more likely when using metric. This string is assigned to variable st2.

(alert (strcat "Value of " st1 " inches is " st2 " mm"))

Displays a string in a dialog box using the ALERT function. In this case, you have several strings that you want displayed. Because ALERT accepts only a single string as an argument, all the pieces must be added together into one long string. That is what STRCAT does: It concatenates the strings that follow it into one string.

(princ)

Prints a clear line.

)

Closes the DEFUN function.

Note

The values used with the RTOS function to format units are the same values used for the LUNITS system variable in AutoCAD. They're shown in the next section.

String and Number Conversions

A number of functions convert between numbers and strings, in addition to the RTOS function used in the last program. Let's look at the ones you're most likely to use:

  • ANGTOS converts an angle, in radians, to a string. I'll address the question "why radians?" in the next section. For now, just accept that ω radians = 180 degrees. Like RTOS, this function has modes and precision. The modes are the five kinds of angles you can set under units, starting with the 0 item. Here's the syntax:

    • (angtos pi 0 3) uses the decimal degrees mode and returns "180.000".

    • (angtos pi 1 3) uses the degrees/minutes/seconds mode and returns "180d0'0"". (The " is necessary to return the literal quotation mark used to represent inches because AutoLISP would interpret a quote as the end of the string otherwise.)

    • (angtos pi 2 3) uses the grads mode and returns "200.000g".

    • (angtos pi 3 15) uses the radian mode and returns "3.141592653589793r".

    • (angtos pi 4 3) uses the surveying mode and returns "W".

  • ATOF converts ASCII text into a floating decimal real number. (atof "3.144") returns 3.144.

  • ATOI converts ASCII text into an integer. (atoi "3.144") returns 3.

  • ITOA converts an integer into ASCII text. (itoa 3) returns "3".

  • RTOS converts a real number to string. As I pointed out earlier, both modes and precision can be specified. The modes are the five kinds of units you can set under units, starting with the 1 item (I know, it should have been the 0 item). Here's the syntax:

    • (rtos 6.56 1 3) uses the scientific mode and returns "6.560E+00".

    • (rtos 6.56 2 3) uses the degrees mode and returns "6.560".

    • (rtos 6.56 3 3) uses the engineering mode and returns "6.560"".

    • (rtos 6.56 4 3) uses the architectural mode and returns "6 1/2"".

    • (rtos 6.56 5 3) uses the fractional mode and returns "6 1/2".

Converting Between Radians and Degrees

Why do computers use radians? It's faster and more accurate to do complex computations when using radians, so that's what computers use to compute angles. Table 8.9 shows how radians compare to degrees.

WHAT'S A RADIAN?

Geometrically, a radian is the angle between two lines drawn from the center of a circle that create an arc with an arc length equal to the radius. One radian is a little less than 57.30 degrees. Why do you have to know this? Because if you think you're giving your AutoLISP program an angular measurement in degrees, but the program interprets it as radians, you can get some odd results.

What do you do when you have a program that rotates objects, but it doesn't give you the results you expect? First, recognize that if you think an object should rotate 90°, and it appears to rotate about 117°, you're probably feeding a value in degrees (90) into a function that expects radians (approximately 1.507). Rotating something 90 radians would require 14.3239 full revolutions. That 0.3239 of a revolution lands at about 117°. Likewise, if you thought you were feeding radians into your program but the result is a rotation of a few degrees, you should probably be using degrees instead.

Table 8.9. Degrees and Radians Compared

DEGREES

RADIANS

0

0

90

ω/2

180

ω

270

3ω/2

360

The sample program in Listing 8.7 rotates a copy of a selection set using a base point and rotation angle provided by the user. You can rotate and copy with grips, but it involves several steps. In AutoCAD 2006, the ROTATE command has a Copy option, but if you need this function often, a dedicated command would be helpful.

The following code illustrates the problems new programmers often have with angles. You may think it looks like it will work, but it won't give you the results you probably expect. Try it. When you type 90, hoping to rotate a copy of the object 90°, you'll get the results shown on the right in Figure 8.6 instead. What's wrong?

Example 8.7. Listing 8.7

rc_broken_version.lsp

        (defun c:rc(/ ss1 pt1 ang1)
          (setq ss1 (ssget))
          (setq pt1 (getpoint "
Basepoint: "))
          (setq ang1 (getangle "
Angle of rotation: "))
          (command "._COPY" ss1 "" pt1 pt1
                   "._ROTATE" ss1 "" pt1 ang1)
        )

Each line is described in Table 8.10.

There's a clue in the command line shown with the object in Figure 8.6. When prompted for a rotation angle, I typed in 90, but the command line shows 1.570796326794897. That looks like ½ of ω. If you look at Table 8.9, 90 = ω/2. AutoLISP must have converted the 90 into radians. It did, because I used the GETANGLE function.

Table 8.10. rc_broken_version.lsp

LINE OF CODE

PURPOSE

(defun c:rc( ss1 pt1 ang1)

The new command is named RC.

(setq ss1 (ssget))

The SSGET function prompts the user to make a selection set. The selection in this case is assigned to the variable ss1.

(setq pt1 (getpoint " Basepoint: "))

The point provided in response to GETPOINT is saved as variable pt1.

(setq ang1 (getangle " Angle of rotation: "))

The angle provided in response to GETANGLE is saved as variable ang1. This creates a problem, because the value is returned in radians. If 90 is typed or selected, 1.570796326794896 is returned. Your objects rotates only about 1.6 degrees when the value is fed to the ROTATE command.

(command "._COPY" ss1 "" pt1 pt1

The selected objects are copied directly on top of themselves. Note that there is no closing parenthesis, so the next line is part of this one.

"._ROTATE" ss1 "" pt1 ang1)

This line is part of the COMMAND function in the previous line. Your original selection set is rotated at the base point by ang1. You expect the results on the left in Figure 8.6, but you get the results on the right.

)

This line ends the DEFUN function.

Results of using degrees instead of radians

Figure 8.6. Results of using degrees instead of radians

Oddly enough, this program would have worked fine if I'd used GETSTRING instead of GETANGLE, because the value is supplied to the ROTATE command literally. I didn't use GETSTRING, however, because it doesn't allow the user to pick two points at the prompt. That would make this program behave differently from every other AutoCAD program, which is something you should make every effort to avoid.

Now that you know why your program may be acting up, let's see how you can fix it by creating a new function that can be called in other functions.

CREATING AUTOLISP FUNCTIONS: RTD AND DTR

Before we look at the code required to fix this problem, let's clarify one important AutoLISP concept. There are two different kinds of functions. The kind you've been writing act like AutoCAD commands. Without the C: as part of the function name, it doesn't act like an AutoCAD command, but it can be used as an AutoLISP function. This is pretty potent stuff: You can create your own AutoCAD commands using AutoLISP functions, and you can define your own AutoLISP functions too. Now that's power! Let's solve the conflict between radians and degrees with a new AutoLISP function or two.

You'll find the code in Listing 8.8 in virtually every AutoLISP reference book, because every AutoLISP programmer runs into the radians/degrees problem at some point. Notice that the two new functions are a little different from the programs you've been writing, in two ways: They don't have a C: in front of the function name, and they have a single argument in the parentheses after the function name instead of the name of local program variables. RTD converts radians into degrees, and DTR converts degrees into radians.

Example 8.8. Listing 8.8

angconv.lsp
        (defun rtd (r)
           (* 180.0(/ r pi))
        )  ;end defun

        (defun dtr (d)
           (* pi (/ d 180.0))
        )  ;end defun

Table 8.11 describes this program.

Because 180° = ω radians, the math here is easy. Degrees = (180 × radians)/ω. Using the structure of AutoLISP, you'd say "multiply 180 times the result of dividing radians by ω." Because functions always come first, the AutoLISP code reads (* 180 (/ r pi)) where r = radians. Once you write these two conversion functions, they must be loaded before you can use them. You could load them manually each time you want to use them, but there are some automatic ways to load AutoLISP programs so they're always available. In this case, I'd place the functions in a file named acaddoc.lsp, which is discussed later in this chapter.

Note

For clarity, I display most of the programs in this chapter as individual LSP files. It's also possible to combine many AutoLISP programs into a single LSP file. Each one starts and ends with a DEFUN function.

Table 8.11. angconv.lsp

LINE OF CODE

PURPOSE

(defun rtd (r)

This line defines a function named RTD. The r is the argument necessary for this function. Any letter can be used. Notice that there's no C: and no /

(* 180.0(/ r pi))

The value provided, r, is divided by ω and multiplied by 180.

);end defun

This line ends the DEFUN function and places a note to that effect to make it easier to find the end of each function in a file that contains multiple AutoLISP programs.

 

This is a blank space for clarity, which is OK anywhere in an AutoLISP program.

(defun dtr (d)

This line defines a function named DTR. The d is the argument necessary for this function. Any letter can be used. Notice that there's no C: and no /.

(* pi (/ d 180.0))

The value provided as an argument is divided by 180 and multiplied by ω.

);end defun

This line ends the DEFUN function and places a note to that effect to make it easier to find the end of each function in a file that contains multiple AutoLISP programs.

The two angular conversion functions can be executed at the AutoCAD command prompt using the same format you use in a program: (rtd 2) converts 2 radians into degrees and returns 114.592; (dtr 30) converts 30° into radians and returns 0.523599.

Listing 8.9 shows how the rc.lsp program looks if you use the RTD function to convert the angle from radians to degrees before using it. The RTD function must be loaded before it can be used.

Example 8.9. Listing 8.9

rc.lsp
       (defun c:rc(/ ss1 pt1 ang1)
         (setq ss1 (ssget))
         (setq pt1 (getpoint "
Basepoint: "))
         (setq ang1 (rtd (getangle "
Angle of rotation: ")))
         (command "._COPY" ss1 "" pt1 pt1
                  "._ROTATE" ss1 "" pt1 ang1)
       )

It's a subtle difference. In the fourth line, the RTD function is used before the GETANGLE function, requiring one more set of parentheses. You may find it easier to understand how the RTD function works if I rewrite it to add an additional step. Listing 8.10 adds one more line that redefines the variable ang1. Note the inline annotation that follows the ; in line 5. Don't be surprised to see the program variable ang1 appear twice on that line. That's how program variables are assigned a new value that's based on their existing value. It's very logical.

Example 8.10. Listing 8.10

rc2.lsp
         (defun c:rc(/ ss1 pt1 ang1)
           (setq ss1 (ssget))
           (setq pt1 (getpoint "
Basepoint: "))
           (setq ang1 (getangle "
Angle of rotation: "))
           (setq ang1 (rtd ang1));converts ang1 from radians to degrees
           (command "._COPY" ss1 "" pt1 pt1
                    "._ROTATE" ss1 "" pt1 ang1)
         )

Note

A point about multiple releases: If you think this program could be simplified by using the Copy option of the ROTATE command, you're right. However, prior to AutoCAD 2006, ROTATE had no Copy option. The code as written here (command "._COPY" ss1 "" pt1 pt1 "._ROTATE" ss1 "" pt1 ang1) works in any release, not just those since AUTOCAD 2006. That's good practice when writing code.

Using AutoLISP Functions Transparently

You know that you can execute AutoLISP functions directly from the command line, but you may wonder if the command line has to be empty. It doesn't. You can run an AutoLISP function transparently while you're in a command. Let's create an AutoLISP function that converts inches into millimeters and that you can use on the fly when drawing or editing in AutoCAD. You already created an AutoCAD command to do this earlier, so creating a function requires only that you modify the program with a little editing; see Listing 8.11.

Example 8.11. Listing 8.11

ii.lsp
       (defun ii (in)
         (* in 25.4)
        )

Let's say you're using the LINE command, and you've selected a start point and established a polar tracking line. You know the length of the line in inches, but you're in a metric drawing. Can you have AutoCAD convert into millimeters while you're drawing the line? Here's how. Once you've loaded the II function, use it in response to a request for input. Just remember to type the parentheses. And if the number is smaller than 1, you must include the leading 0, as shown in Figure 8.7.

Note

You can't use this system in a dialog box, nor can it follow the @ symbol. But it works great for values that can be entered at the command line; particularly direct distances.

Using AutoLISP functions transparently

Figure 8.7. Using AutoLISP functions transparently

Combining AutoLISP Functions

When you're writing a new program, don't overlook programs that you or others have already written. One of the reasons I use so many examples in this chapter is to provide sample code for you to copy into other programs for a variety of situations.

Let's take an element from rc2.lsp, the Rotate/Copy program, and add it to the structural section program ssect.lsp so the symbol can be drawn at any angle. You'll borrow lines 4 and 5 from rc2.lsp and use them to get an angle for rotating the UCS before calculating the points for the other two corners of the rectangle, as shown in Figure 8.8.

First, copy the RTD function and both programs into a new file—you don't want to mess up programs that already work. Next, open a space in the C:SSECT program and copy the key lines from the C:RC function, which is below it. Delete the entire C:RC function so none of that code interferes with your new program. Then, make a few more changes so you can use the new angle to rotate the UCS; see Listing 8.12. Of course, if your program changes a system variable, don't forget to change it back—see the error-checking section in Chapter 9.

Borrowing code

Figure 8.8. Borrowing code

Example 8.12. Listing 8.12

structural_section.lsp

         (defun C:SSECT (/ ang1 pt1 pt2 pt3 pt4)
           (setq ang1 (getangle "
Angle of structural section: "))
           (setq ang1 (rtd ang1))
           (command "._UCS" "Z" ang1)
           (setq pt1 (getpoint "
First corner of rectangle: "))
           (setq pt2 (getcorner "
Diagonal corner of rectangle " pt1))
           (setq pt3 (list (nth 0 pt1) (nth 1 pt2)))
           (setq pt4 (list (nth 0 pt2) (nth 1 pt1)))
           (command "._RECTANG" pt1 pt2 "._LINE" pt1 pt2 "" "._LINE" pt3 pt4 "")
           (command "._UCS" "P")
         )

Figure 8.9 shows the command in action. It would be nice if the rubber-band rectangle rotated with the UCS, but I want to keep this program simple for now. As you can see in Figure 8.10, when the command is used to place the two structural section symbols, you get the result you want.

You may also be thinking that the user should be able to press

Listing 8.12
Using C:SSECT

Figure 8.9. Using C:SSECT

Result of C:SSECT

Figure 8.10. Result of C:SSECT

Automatic Loading

Defining functions like RTD and DTR for converting angles—functions that you want always available—brings up the issue of automatic loading. So far, you've been using the Visual LISP editor to both create your programs and load them. Users can automatically load AutoLISP programs by three primary means: add them to the Startup Suite in the APPLOAD dialog box, place the programs in an acaddoc.lsp file, or place the programs in an acad.lsp file. All of these require that you save the programs in an LSP file.

APPLOAD

We looked briefly at the Load/Unload Applications dialog box earlier in the chapter. It can be used to load all kinds of programs, not just AutoLISP. The file extensions don't always tell you exactly what kind programming language was used to create them, so let's look at them in Table 8.12.

Table 8.12. File Types Used by the Load/Unload Applications Dialog Box

FILE EXTENSION

TYPE OF PROGAM

.lsp

AutoLISP source code. This is the code you've been writing in this chapter. It's open code that can be easily read and altered by anyone.

.fas

Fast-opening machine language code compiled from AutoLISP source code. These files can be created with the Visual LISP editor. Their two advantages over AutoLISP source code are that they load more quickly than text-based LSP files and they're more secure if you want to protect the work you did from being taken by someone else.

.vlx

Files that can also be created from the Visual LISP editor and that are designed to place multiple file types into a single file. These can include Dialog Control Language (DCL) files in addition to compiled AutoLISP code. The Help system indicates that they can include VBA, but I'm not certain that works.

.arx

AutoCAD Runtime Extension. These programs are written in the C++ programming language. They often contain the code for specific commands or groups of commands and are much more sophisticated than AutoLISP.

.dbx

Database Extension. C++ and .NET developers sometimes use these programs to develop third-party applications to read and write to DWG and DXF format.

.dvb

AutoCAD VBA source file written in VBA, another programming language.

Any programs with these file types can be placed in the Startup Suite, but think about what you put in there. You should place program files in the Startup Suite only if you want constant access to them. Suppose you have a complex stair-design program that you use only once in a while. You can use the APPLOAD command to load it only when you want to use it. If you have a complex program to help you design cams, on the other hand, and you use it every day, it should be in the Startup Suite.

Acaddoc.lsp and Acad.lsp Files

AutoCAD doesn't ship with either an acaddoc.lsp file or an acad.lsp file, but if you create either one, AutoCAD recognizes them and automatically loads them on startup. It's like using the Startup Suite, with a difference: The Startup Suite is loaded only for the user who puts files in it. If either an acaddoc.lsp or an acad.lsp file is placed in the AutoCAD search path, its programs load for all users.

Note

If you want all the users in an office or a company to have the same AutoLISP programs available all the time, put an acaddoc.lsp file in a shared folder and make sure that folder is in the search path for all users. See Chapter 2, "Managing Your System," for more information on adding locations to the AutoCAD search path.

What's the difference between an acaddoc.lsp file and an acad.lsp file, and why are there two of them? Well, for historical reasons. For as long as I've used AutoCAD, it's been possible to place programs in a file named acad.lsp, put the file in the search path of AutoCAD, and have the file automatically load when AutoCAD starts up. But when AutoCAD was updated in AutoCAD 2000 to allow multiple drawings to be opened in a single session, acad.lsp was assigned the behavior of loading only for the first drawing opened or created in any one session. The acaddoc.lsp file became an alternative to the acad.lsp file because it loads in each new drawing as it's opened or created.

If you have a file named acad.lsp from an earlier era and want it loaded with every drawing, either rename it acaddoc.lsp or set the variable ACADLSPASDOC to 1. Doing so forces AutoCAD to treat an acad.lsp file as though it's an acaddoc.lsp file.

There is another file that loads AutoLISP programs automatically if you're using a release prior to AutoCAD 2006. The acad.mnl file contains AutoLISP code that is loaded whenever the acad.mns file is loaded. It contains a number of functions that work in conjunction with the menu file. Now, with the CUI, that file exists but contains no code. In its place is a file name acad2007doc.lsp, which loads automatically in each drawing and defines a number of command functions using AutoLISP. I suggest that you avoid editing this file so you don't inadvertently change the behavior of the commands it contains. If you want programs to load automatically, add them to an acaddoc.lsp file.

Managing Your Programs

I hope that after reading this chapter, you want to develop some of your own LSP files. If so, you'll have to decide how to manage them. Do you want them loaded all the time, only once, or only when you need them? As you develop more AutoLISP programs, I recommend you use the following steps:

  1. Work on any new program in its own working file in the Visual LISP editor until you've tested it thoroughly, and it works.

  2. Decide whether you want to have it available all the time. If not, put it in a folder as a single program and load it using APPLOAD whenever you need it.

  3. If you have a program that only you want access to, place it in the Startup Suite of the APPLOAD dialog box or in a folder that appears only in your support path.

  4. Once you know they work, place all general-access programs into a single file named acaddoc.lsp. That file should be saved in a network folder that's in everyone's support path or in C:Program FilesAutoCAD 2007support.

  5. If you want a message to be displayed on startup or a program to be loaded only once when a user first starts AutoCAD, place the code for that in an acad.lsp file and place that file in the same path as the acaddoc.lsp file.

S::STARTUP

While we're on the subject of automatic loading, let's look at one special AutoLISP function that is often placed at the beginning of the acaddoc.lsp file. The S::STARTUP function runs an AutoLISP program as soon as acaddoc.lsp is loaded. The user doesn't have to do anything. This can be handy for setting system variables, creating automatic layouts, and adding layers—processes that can also be completed with template files and profiles, of course; but that you may want to automate. The S::STARTUP function is occasionally used for undefining commands so they can be replaced with your own definitions.

Why replace an existing command with a new definition? Maybe you don't like the new-fangled version of a command, and you want it to behave like the old command it replaced. You can undefine the new one and create a new definition that just calls up the old one. The Help system in the Visual LISP editor uses the HATCH and BHATCH commands as an example.

You may also want certain things to happen whenever someone uses a particular command. Perhaps you want all text to be placed on a specific layer. You can undefine the MTEXT command and then define a new one that sets a text layer current. If you want to keep yourself from accidentally placing dimensions in Paper Space, you can replace the standard dimension commands with ones that check to see whether a layout is active before placing dimensions.

Note

You didn't know that AutoCAD commands can be undefined? Just use the UNDEFINE command followed by the command name you want to undefine. And yes, there is a REDEFINE command.

Listing 8.13 shows an example of how you can use the S::STARTUP function if you want to force yourself to use polylines instead of lines, and you want to make sure polylines are always drawn on the OBJ layer. Note that the REDEFINE command can be used to redefine a native command that has been turned off with UNDEFINE. Note also that placing a period in front of a native command name calls that command even if it's been undefined. That's why you often see the leading period in front of AutoCAD command names in AutoLISP programs.

Note

The DEFUN-Q function is used only with the S::STARTUP function, although you can use DEFUN instead. DEFUN-Q is a slightly modified version of DEFUN. It permits a startup program to be appended to another startup program, just in case you've used S::STARTUP in more than one automatically loaded file. You won't use DEFUN-Q in any other situation that I'm aware of.

Example 8.13. Listing 8.13

startupexample.lsp

        (defun-q S::STARTUP ()
          (command "._UNDEFINE" "._LINE")
          (Alert
            "The LINE command will draw polylines on Layer OBJ.
            
Type ".LINE" to use the native LINE command.
            
Use the REDEFINE command to redefine LINE"
        )
      )
      (defun c:LINE()
        (setvar "cmdecho" 0)
        (command ".LAYER" "M" "obj" "C" "white" "" "LW" "0.5" "" ""
            ".PLINE")
        (setvar "cmdecho" 1)
      )
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.227.92