VL Guide [PDF]

  • 0 0 0
  • Gefällt Ihnen dieses papier und der download? Sie können Ihre eigene PDF-Datei in wenigen Minuten kostenlos online veröffentlichen! Anmelden
Datei wird geladen, bitte warten...
Zitiervorschau

AutoCAD 14 ®

R E L E A S E

Visual LISP Guide

April 23, 1998

Copyright © 1998 Autodesk, Inc. All Rights Reserved This publication, or parts thereof, may not be reproduced in any form, by any method, for any purpose. AUTODESK, INC. MAKES NO WARRANTY, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, REGARDING THESE MATERIALS AND MAKES SUCH MATERIALS AVAILABLE SOLELY ON AN “AS-IS” BASIS. IN NO EVENT SHALL AUTODESK, INC. BE LIABLE TO ANYONE FOR SPECIAL, COLLATERAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES IN CONNECTION WITH OR ARISING OUT OF PURCHASE OR USE OF THESE MATERIALS. THE SOLE AND EXCLUSIVE LIABILITY TO AUTODESK, INC., REGARDLESS OF THE FORM OF ACTION, SHALL NOT EXCEED THE PURCHASE PRICE OF THE MATERIALS DESCRIBED HEREIN. Autodesk, Inc. reserves the right to revise and improve its products as it sees fit. This publication describes the state of this product at the time of its publication, and may not reflect the product at all times in the future.

Autodesk Trademarks The following are registered trademarks of Autodesk, Inc., in the USA and/or other countries: 3D Plan, 3D Props, 3D Studio, 3D Studio MAX, 3DSurfer, ADCADD, ADE, ADI, Advanced Modeling Extension, AEC AUTHORITY, AEC-X, AME, Animator Pro, Animator Studio, ATC, Auto-Architect, AutoCAD, AutoCAD Data Extension, AutoCAD Development System, AutoCAD LT, AutoCAD Map, Autodesk, Autodesk Animator, the Autodesk logo, Autodesk University, Autodesk View, AutoLISP, AutoShade, AutoSketch, AutoSolid, AutoSurf, AutoVision, CAD OVERLAY, DesignBlocks, Design Companion, DRAFIX, Education by Design, Generic, Generic CADD, Generic Software, Generic 3D Drafting, Geodyssey, Heidi, HOOPS, Inside Track, Kinetix, MaterialSpec, Mechanical Desktop, Multimedia Explorer, NAAUG, Office Series, Opus, Picture This Home!, PLANIX, RASTATION, Softdesk (goods), Softdesk (services), Solution 3000, STAR DESIGN, TECHTALK, Texture Universe, THE AEC AUTHORITY, THE AUTO ARCHITECT, TinkerTech, WHIP!, Woodbourne, WorkCenter, and WorldCreating Toolkit. The following are trademarks of Autodesk, Inc., in the USA and/or other countries: 3D for the PC, 3D Studio VIZ, ACAD, Advanced User Interface, AEC Office, AME Link, Animation Partner, Animation Player, Animation Pro Player, A Studio in Every Computer, ATLAST, Auto-Architect, AUGI, AutoCAD Learning Assistance, AutoCAD LT Learning Assistance, AutoCAD Simulator, AutoCAD SQL Extension, AutoCAD SQL Interface, AutoCDM, Autodesk Animator Clips, Autodesk Animator Theatre, Autodesk Device Interface, Autodesk MapGuide, Autodesk PhotoEDIT, Autodesk Software Developer’s Kit, Autodesk View DwgX, Autodesk WalkThrough, Autodesk World, AutoEDM, AutoFlix, AutoLathe, AutoSnap, Biped, bringing information down to earth, Built with ObjectARX, Carpe Datum, Character Studio, Concept Studio, Content Explorer, cornerStone Toolkit, DESIGNX, DesignScape, Designer’s Vision, Design Your World, DXF, DWG Unplugged, Exegis, FLI, FLIC, GDX Driver, Generic 3D, Home Series, HyperWire, MAX DWG, Multiped, NetHead, ObjectARX, ObjectDXF, Octoped, PeopleTracker, PHOTO LANDSCAPE, PHOTOSCAPE, Physique, PolarSnap, Power and Light, Powered with Autodesk Technology, Quadruped, QuickCAD, RadioRay, SchoolBox, SketchTools, Smoke and Mirrors, Suddenly Everything Clicks, Supportdesk, Total House, Transforms Ideas Into Reality, and Visual LISP.

Third Party Trademarks Microsoft, Visual Basic, and Windows are registered trademarks, and ActiveX, Windows NT, and Windows 95 are trademarks of Microsoft Corporation. Delphi is a trademark of Borland International. All other brand names, product names or trademarks belong to their respective holders.

GOVERNMENT USE Use, duplication, or disclosure by the U. S. Government is subject to restrictions as set forth in FAR 12.212 (Commercial Computer Software-Restricted Rights) and DFAR 267.7202 (Rights in Technical Data and Computer Software), as applicable.

Contents - Visual LISP Guide

Contents - Visual LISP Guide iv Introduction 14 AutoLISP and Visual LISP 15 AutoLISP 15 Visual LISP 15 What Visual LISP Offers 15 Working With Visual LISP and AutoCAD 16 How This Guide is Organized 17 Recommendations on Using This Guide 17 First: Read Chapter 1 18 Next: Are You Ready for the Tutorial, or...? Using the Heart of the Manual 18 Document Conventions 19 Chapter 1

Quick Tour

18

22

Getting Started 23 Before You Begin 23 Starting Visual LISP 23 Overview of the Visual LISP User Interface 24 The Visual LISP Text Editor 25 Other Visual LISP Windows 26 Menu Overview 26 Variable Menu Contents 26 Menu Summary 27 The Console 28 Text Editor Overview 29 Loading and Running AutoLISP Programs 30 Running Selected Lines of Code 32 Exiting the Visual LISP Environment 32

iv

Chapter 2

AutoLISP Basics

34

AutoLISP Expressions 35 AutoLISP Data Types 36 Integers 36 Reals 36 Strings 37 Lists 37 Selection Sets 37 Entity Names 38 VLA Objects 38 File Descriptors 38 Symbols and Variables 39 AutoLISP Function Syntax 39 AutoLISP Program Files 40 Formatting AutoLISP Code 40 Spaces in AutoLISP Code 41 Comments 41 Visual LISP Comment Styles 42 Color Coding 42 AutoLISP Variables 42 Displaying the Value of a Variable 43 Nil Variables 43 Predefined Variables 44 Number Handling 44 String Handling 45 Basic Output Functions 47 Displaying Messages 48 Exiting Quietly 48 Control Characters in Strings 49 Wild-Card Matching 50 Equality and Conditional 52 List Handling 52 Point Lists 54 Dotted Pairs 56 Symbol and Function Handling 57 C:XXX Functions 58 Adding Commands 60 Redefining AutoCAD Commands 60 Local Variables in Functions 62 Local Variables Versus Global Variables Example Using Local Variables 63 Functions with Arguments 64

Contents

v

62

Chapter 3

Using AutoLISP to Communicate with AutoCAD 66 Query and Command Functions 67 Command Submission 67 Foreign-Language Support 68 Pausing for User Input 68 Passing Pick Points to AutoCAD Commands 69 System and Environment Variables 69 Configuration Control 70 Display Control 70 Controlling Menus 70 Control of Graphics and Text Windows 73 Control of Low-level Graphics 74 Getting User Input 74 The getxxx Functions 75 Control of User-Input Function Conditions 77 Input Options for User-Input Functions 77 Key Word Options 78 Arbitrary Keyboard Input 79 Input Validation 79 Geometric Utilities 80 Object Snap 80 Text Extents 81 Conversions 84 String Conversions 85 Angular Conversion 87 ASCII Code Conversion 88 Unit Conversion 89 Converting from Inches to Meters 90 The Unit Definition File 90 Coordinate System Transformations 92 Point Transformations 94 File Handling 95 File Search 95 Accessing Help Files 96 Device Access and Control 97 Accessing User Input 97 Calibrating Tablets 98

Chapter 4

Using AutoLISP to Manipulate AutoCAD Objects 102 Selection Set Handling 103

Contents

vi

Selection Set Filter Lists 105 Wild-Card Patterns in Filter Lists 107 Filtering for Extended Data 107 Relational Tests 107 Logical Grouping of Filter Tests 108 Selection Set Manipulation 109 Passing Selection Sets Between AutoLISP and ObjectARX Applications 110 Object Handling 111 Entity Name Functions 111 Entity Handles and Their Uses 112 Entity Context and Coordinate Transform Data 113 Entity Access Functions 116 Entity Data Functions 116 Working with Blocks 120 Anonymous Blocks 120 Creating Complex Entities 121 Entity Data Functions and the Graphics Screen 123 Polylines and Lwpolylines 123 Processing Curve-Fit and Spline-Fit Polylines 124 Nongraphic Object Handling 124 Symbol Table Objects 125 Dictionary Objects 126 Extended Data—Xdata 126 Organization of Extended Data 127 Registration of an Application 130 Retrieval of Extended Data 130 Attachment of Extended Data to an Entity 131 Management of Extended Data Memory Use 132 Handles in Extended Data 132 Xrecord Objects 134 Symbol Table and Dictionary Access 134 Symbol Tables 135 Dictionary Entries 137 Accessing AutoCAD Groups 137 Chapter 5

Developing Programs With Visual LISP 138 Getting Organized 139 The System Console 139 System Console Behavior 140 The System Console Context Menu 141 Separators Processing 142 Color Coding of Console Input 143

Contents

vii

Context-Sensitive Help for Visual LISP Functions 143 Logging Console Activity 143 Accessing Native AutoLISP from Visual LISP 144 Bouncing Between AutoCAD and Visual LISP 145 Using the Text Editor 145 Working with Files 145 Entering Text 146 Undoing the Last Change You Made 146 Saving Your Changes 147 Automatic Backup Files 147 Editing an Existing File 147 Color Coding 148 Context-Sensitive Help for Functions 149 The Text Editor Context Menu 149 Words in the Visual LISP Text Editor 150 Text Editor Shortcuts 151 Complete Word by Match 151 Complete Word by Apropos 151 Formatting Shortcut Keys 154 Navigation Shortcuts 155 Text Correction Shortcuts 155 Text Selection Shortcuts 156 Moving and Copying Text 157 Indenting Text 157 Searching for Text 158 Replacing Text 160 Bookmarking Text 160 Formatting Code with the Visual LISP Formatter 162 Running the Formatter 162 Visual LISP Formatting Fundamentals 163 Basic Formatting Styles 163 Additional Formatting Options 165 Comment Styles 170 Indentation Rules 171 Saving and Restoring Formatting Options 171 Formatter Restrictions 171 Checking for Syntax Errors 172 Checking the Balance of Parentheses 172 Using Color Coding to Detect Syntax Errors 173 Using the Check Command to Look for Syntax Errors Running Your Program 175 Chapter 6

174

Debugging Programs 176 Debugging in Visual LISP 177

Contents

viii

Debugging Example 178 Setting a Breakpoint to Interrupt Program Execution 178 Stepping Through the Program 179 Tracing the Evaluation Results of an Expression 181 Tracing Variables During Program Execution 182 Continuing Program Execution 183 Debugging Features 183 Starting Debugging 184 The Break Loop 184 Continuable Break Loops 185 Non-continuable Break Loops 186 Breakpoints 186 Setting and Deleting Breakpoints 186 Disabling Breakpoints 187 Listing and Viewing the Breakpoints in Your Program 188 Life Cycle of a Breakpoint 188 Visual LISP Data Inspection Tools 189 The Watch Window 190 Adding a Variable to the Watch Window 190 Watch Toolbar 191 Using the Watch Item Context Menu 191 The Trace Stack Window 193 Stack Element Lists 194 Viewing the Current Trace Stack 195 Displaying Information on a Trace Stack Element 195 Frame Binding Window 196 Keyword Frames 196 Special Function Call Frames 198 Viewing an Error Trace Stack 198 Trace Stack Toolbar 199 The Symbol Service Dialog 199 Symbol Service Toolbar 200 Symbol Flags 201 Inspector Windows 201 Inspector Dialog Box 202 Object Element List Formats 202 Opening an Inspector Dialog 203 Handling Errors in the Inspect Command 203 Closing all Inspector Dialogs 204 Common Inspector Commands 204 Specific AutoLISP Datatype Inspectors 205 Viewing AutoCAD Drawing Entities 208 Viewing Entities in the Drawing Database 208 Viewing Tables in the Drawing Database 210 Viewing Blocks in the Drawing Database 211

Contents

ix

Viewing Selected Objects in a Drawing 211 Viewing Extended Data 212 Chapter 7

Building Applications

214

Compiling and Linking Programs 215 How to Use the Compiler 215 Compiling a Program from a File 216 Choosing a Compiler Mode 216 Identifying the Input File 216 Naming an Output File 217 Walking Through a Compile Example 218 Loading and Running a Compiled Program 218 Linking Function Calls 219 Building Stand-alone Applications 219 Making Functions Known to AutoCAD 220 Explicitly Exporting Function Names to AutoCAD 220 Implicitly Exporting Function Names to AutoCAD 221 Identifying Functions Defined in External Applications 221 Using the Visual LISP Run-Time System 223 Shipping the RTS With Your Application 224 Loading the Visual LISP RTS 224 Initializing the Run-time System 224 Using a Start-Up File 225 Functions Defined by the Sample Start-Up File 225 Using the RTS and Native AutoLISP Environments Concurrently 227 Controlling the Verbosity of RTS Initialization 228 Partial Reinitialization at AutoCAD New/Open Commands 228 Making Application Modules 228 Using the Application Wizard 229 Starting the Application Wizard 230 Wizard Step 1: Choosing an Application Type 230 Wizard Step 2: Naming the Executable File 231 Wizard Step 3: Identifying the Load Method 232 Wizard Step 4: Identifying the Program Files 233 Wizard Step 5: Identifying Dialog Control (DCL) Files 234 Wizard Step 6: Defining External Functions 235 Wizard Step 7: Setting Initialization Options 236 Wizard Step 8: Making the Application 238 Understanding the Output from the Make Application 239 Loading and Running Applications 240 Loading and Running an ARX Application 240 Loading and Running a VLX Application 242 Rebuilding an Application 242

Contents

x

Using the Application Wizard to Rebuild an Application 242 Rebuilding an Application from Its Make File 242 Chapter 8

Maintaining Visual LISP Applications

244

Managing Multiple LISP Files 245 Introducing Visual LISP Projects 245 LSP, FAS and other File Types 245 Defining a Project 247 Assigning Project Properties 248 Selecting the Files to Include in a Project 248 Changing the Order in Which Visual LISP Loads Files 251 Choosing Compiler Build Options 251 Using the Project Window to Work with Project Files 252 Selecting Multiple Project Members 254 Loading Project Files 254 Compiling and Recompiling Project Files 255 Editing Project Files 255 Saving and Closing the Project 256 Working With Existing Projects 256 Opening a Project 256 Finding a String in Project Source Files 257 Making an Application from a Project 258 Optimizing Application Code 260 Defining Build Options 260 Choosing a Compilation Mode 261 Analyzing for Optimization Correctness 262 Understanding Project Build Options 263 Link Mode 263 Dropping Functions 263 Localizing Variables 264 Safe Optimization 264 Compiler Checking of Optimizing Conditions 266 Chapter 9

Advanced Topics

268

Using ActiveX Objects with Visual LISP 269 Understanding the AutoCAD Object Model 270 Object Properties 270 Object Methods 271 Collections of Objects 271 Accessing AutoCAD Objects 271 Using the Inspect Tool to View Object Properties 272 Moving Forward From the Application Object 273 Summarizing the Process 274

Contents

xi

Using Visual LISP Functions with ActiveX Methods 275 Determining the Visual LISP Function You Need 275 Determining How to Call a Function 276 Translating Visual Basic Arguments to Visual LISP Arguments 278 Viewing and Updating Object Properties 279 Determining If an Object Can be Accessed 281 Using ActiveX Methods That Return Values in Arguments 282 Listing an Object’s Properties and Methods 283 Determining if a Method or Property Applies to an Object 283 Working With Collection Objects 284 Retrieving Member Objects in a Collection 287 Converting Arguments 287 Releasing Objects and Freeing Memory 288 Converting Object References 288 Attaching Reactors to AutoCAD Drawings 290 Reactor Types and Events 290 Defining Callback Functions 291 Defining Linker, Editor, and Database Reactors 292 Defining Object Reactor Callback Functions 292 Using Predefined Callback Functions 292 Creating Reactors 292 Using Object Reactors 294 Querying, Modifying and Removing Reactors 296 Inspecting Reactors 296 Querying Reactors Using Function Calls 297 Modifying Reactors 298 Disabling Reactors 299 Transient versus Persistent Reactors 300 Appendix A

AutoLISP Function Reference 302 Selection Set Filters 422 Relational Tests 422 Logical Grouping of Filter Tests

424

Contents

xii

Contents

xiii

Introduction

In this chapter For years, AutoLISP has set the standard for customizing



AutoLISP and Visual LISP

CAD. Visual LISP represents the next generation of LISP for



Working with Visual LISP and AutoCAD



How this Guide is Organized



Recommendations on Using this Guide



Document Conventions

AutoCAD. Visual LISP now adds significantly more capabilities to AutoLISP for AutoCAD. It extends the language to ™

interface with objects via the Microsoft ActiveX Automation interface, and adds the ability to have AutoLISP respond to events via object reactors. As a development tool, Visual LISP provides a complete integrated development environment (IDE), including a compiler, debugger, and other tools to increase productivity in rapidly customizing AutoCAD.

14

AutoLISP and Visual LISP AutoLISP AutoLISP is a programming language designed for extending and customizing AutoCAD functionality. It is based on the LISP programming language, whose origins date back to the late 1950s. LISP was originally designed for use in Artificial Intelligence (AI) applications, and is still the basis of many AI applications. AutoCAD introduced AutoLISP as an application programming interface (API) in release 2.1, in the mid-1980s. LISP was chosen as the initial AutoCAD API because it was uniquely suited for the unstructured design process of CAD projects, which involves iteratively trying different solutions to a problem.

Visual LISP Visual LISP(VLISP) is a software tool designed to expedite AutoLISP program development. VLISP’s integrated development environment provides features to help ease the tasks of source-code creation and modification, program testing, and debugging. In addition, VLISP provides a vehicle for delivering stand-alone ObjectARX applications written in AutoLISP. In the past, developing AutoLISP programs for AutoCAD meant working with some text editor (which you had to provide) to write your code, then loading the code into AutoCAD and running it. Debugging your program meant adding statements to print the contents of variables at strategic points in your program. You had to figure out what were good points in your program to do this, and what variables you needed to look at. If you discovered you still didn’t have enough information to determine the error, you had to go back and change the code again, adding more debugging points. And finally, when you got the program to work correctly, you needed to either comment out or remove the debugging code you added.

What Visual LISP Offers During the development cycle of an AutoLISP application or routine, the AutoLISP user performs a number of operations which are not available within the AutoCAD software. Some of these operations, like text editing, are available with other software tools. Others, such as full AutoLISP source-level debugging, are introduced only with Visual LISP. With Visual LISP the user can perform most of the necessary operations inside the single environment,

Introduction

15

which permits text editing, program debugging, and interaction with AutoCAD and other applications. Visual LISP is an integrated development environment (IDE) that combines several functional components to support major user requirements during the development cycle of AutoLISP programs. These components include: ■ ■ ■ ■

■ ■ ■

■ ■ ■ ■ ■

Complete AutoLISP emulation with transparent compile-during-load technology A Syntax Checker that recognizes erroneous AutoLISP constructs and improper arguments in calls to built-in functions A File Compiler that improves the execution speed and provides a secure and efficient delivery platform A source debugger, designed specifically for AutoLISP, that provides maximum flexibility through a powerful break loop. This feature also supports stepping through AutoLISP source code in one window while simultaneously displaying the code effect in an AutoCAD drawing window Text file editing with AutoLISP and DCL color coding, as well as other AutoLISP syntax support features An AutoLISP Formatter to restructure programs into an easily readable format Comprehensive Inspector and Watch facilities that provide convenient access to variable and expression values for data structure browsing and modification. These features may be used to explore AutoLISP data and AutoCAD drawing entities Context sensitive help for AutoLISP functions and a powerful Apropos feature for symbol name search A Project Management system that makes it easy to maintain multiple-file applications Packaging of compiled AutoLISP files into a single ADS or ARX module Desktop Save/Restore capabilities to preserve and reuse the windowing environment from any Visual LISP session An intelligent System Console that introduces a new level of convenience and efficiency for AutoLISP users. The basic functions of the Console correspond to the AutoCAD Text Screen functions and provide a number of interactive features, such as history scrolling and full-input line editing

Working With Visual LISP and AutoCAD Visual LISP is an integrated development environment for developing and running AutoLISP code. It contains its own set of windows and menus, distinct from AutoCAD. But Visual LISP does not run independently of AutoCAD. Whenever you work in Visual LISP, AutoCAD must be running as well. And when you run AutoLISP programs from the Visual LISP environ-

AutoLISP and Visual LISP

16

ment, you will need to interact with AutoCAD in order to work with graphics and, in some instances, to respond to prompts for input. TIP LISP.

Keep AutoCAD open on your desktop whenever you work with Visual

If AutoCAD is minimized when Visual LISP turns control over to it, you have to manually restore and activate the AutoCAD window in order to continue. Visual LISP will not restore the AutoCAD window for you. Instead, the following symbol appears in the Visual LISP window

and remains there until you activate AutoCAD and respond to the prompts at the AutoCAD Command prompt. The “Quick Tour” chapter shows an example of this; see “Loading and Running AutoLISP Programs” on page 30.

How This Guide is Organized The Visual LISP Guide explains how to use the Visual LISP interactive development environment, and how to build and run Visual LISP applications. The Guide also introduces the constructs of the AutoLISP language. This manual assumes that you have some experience with AutoCAD and have basic user-level skills with Microsoft Windows™. Prior experience with AutoLISP is not required, but will make your learning curve much smoother. The Visual LISP Guide is divided into 3 sections: ■

Part 1: Visual LISP and AutoLISP Guide. This is the core section of the manual, which details the use of Visual LISP and AutoLISP.



Part 2: Tutorial: Creating a Garden Path. This section contains step-by-step instructions guiding you toward building a working Visual LISP application.



Part 3: Function Reference. The Function Reference defines and briefly describes every AutoLISP and Visual LISP function.

Recommendations on Using This Guide This is a big book, and you are not expected to read it from beginning to end. Well, not in one sitting, anyway. Part 3 is a reference section, and is meant to

Introduction

17

be referred to when you need to look up the syntax of a function, or what that function returns. You can also browse the Function Reference to search for a function that meets a particular programming need. For Part 1 and Part 2 of the Visual LISP Guide, here are some guidelines to help you get the most out of the documentation.

First: Read Chapter 1 All readers should begin by reading Chapter 1, “Quick Tour.” This chapter gets you started using Visual LISP by telling you how to invoke it from AutoCAD, what you’ll see when Visual LISP first starts, and how you can load and run existing AutoLISP programs from Visual LISP. Chapter 1 introduces and briefly describes the windows you will be working with in the Visual LISP IDE. Use this chapter to orient you to the Visual LISP environment.

Next: Are You Ready for the Tutorial, or...? Part 2 of the Visual LISP Guide is a step-by-step tutorial that guides you to build a working Visual LISP application. ■



If you are already familiar with AutoLISP, you may want to go right to the tutorial after reading Chapter 1. This is a matter of personal comfort: if you feel you need to understand how everything works before using a tool, you might be better off reading some or all of chapters 5 through 9 before trying the tutorial. See “Using the Heart of the Manual” (below) for a brief description of each chapter. If you do not already know AutoLISP, read all of Chapter 2, “AutoLISP Basics,” and at least browse Chapters 3 and 4 (“Using AutoLISP to Communicate with AutoCAD” and “Using AutoLISP to Manipulate AutoCAD Objects.” After that, you can either work through the tutorial or choose from the chapters described below.

If you’re ready to tackle the tutorial, here is one more word of caution: the tutorial is somewhat irreverent -- well, for Autodesk, at least.

Using the Heart of the Manual The heart of the manual is Part 1, “Visual LISP and AutoLISP Guide.” Here, chapter by chapter, is how this section is organized: 1 Chapter 1 is the “Quick Tour,” which everyone should read in order to get oriented in Visual LISP. 2 Chapter 2, “AutoLISP Basics,” introduces basic AutoLISP concepts, such as how to use expressions and variables, handle numbers and strings, display output, build lists, and define functions.

How This Guide is Organized

18

3 Chapter 3, “Using AutoLISP to Communicate with AutoCAD,” describes AutoLISP functions you can use to issue AutoCAD commands and to interact with users in the AutoCAD environment. 4 Chapter 4, “Using AutoLISP to Manipulate AutoCAD Objects,” describes AutoLISP functions you can use to manipulate AutoCAD drawing entities, selections sets, extended data, and symbol tables. 5 Chapter 5, “Developing Programs With Visual LISP,” shows you how to use the Visual LISP text editor to enter AutoLISP program code, format the code, and check the code for AutoLISP syntax errors. It also shows you how to run the code you’ve developed, right from the Visual LISP editor window. 6 Chapter 6, “Debugging Programs,” shows you how to use Visual LISP to trace program execution, watch the value of variables change during program execution, see the sequence in which expressions are evaluated, and step through program execution one instruction at a time. 7 Chapter 7, “Building Applications,” introduces you to the Visual LISP file compiler and how you can use the Visual LISP Make Application Wizard to build stand-alone applications. 8 Chapter 8, “Maintaining Visual LISP Applications,” describes how to define Visual LISP projects and use them to simplify working with multi-file applications. This chapter also explains the Visual LISP compiler’s optimization features, and how to use them with a project. 9 Chapter 9, “Advanced Topics,” describes how to use ActiveX™objects with Visual LISP, and how to attach reactors to AutoCAD drawings and objects.

Document Conventions This document follows a number of stylistic and naming conventions when describing actions or defining terms. Often, distinct typefaces are used to distinguish items from the rest of the text. The following table lists some of the conventions used in the Visual LISP Guide: Typographical conventions Text element

Example

Program code examples are displayed (defun initfunc ( ) in an 8 pt Courier font (setq *GLOBAL-WARMING* 4.0)) Text you enter is shown in boldface At the Visual LISP prompt, enter shape

Introduction

19

Typographical conventions (continued) Text element

Example

File names and directory names are Double-click the file name drawline.lsp. shown in italics, when referred to in a The default install directory is C:\Program Files\AutoCAD R14\VLISP sentence In definitions that include variable text, the variable is in italics

A FAS file named appname-init.fas, where appname is the application module name... (vl-import-exsubrs ’(app-name {entry-name})) The function takes a list as an argument. The first argument is the application’s full name. The entry-name arguments are the application function names to be defined to Visual LISP.

AutoLISP and Visual LISP variable names are in courier type

Double-click on any occurrence of the variable name origin-y... The *LAST-VALUE* system variable...

Use the entget function... AutoLISP and Visual LISP function names are shown in bold courier Use VL-IMPORT-EXSUBRS to import... type in the context of a sentence

Document Conventions

20

Introduction

21

1 Quick Tour

In this chapter ■

Getting Started



User Interface Overview



Menu Overview



Console Overview

capabilities to LISP for CAD. It extends the language to



Text Editor Overview

interface with objects via the Microsoft ActiveX Automa-



Loading and Running AutoLISP Programs

Visual LISP represents the next generation of LISP for AutoCAD. For years, AutoLISP has set the standard for customizing CAD. Visual LISP now adds significantly more

tion interface, and adds the ability to have LISP respond to events via object reactors. As a development tool, Visual LISP provides a complete integrated development environment (IDE), including a compiler, debugger, and other tools to increase productivity in rapidly customizing AutoCAD.

22

Getting Started Before You Begin Before you start, note where the Visual LISP program files are installed on your computer. By default, it installs in a folder named VLISP, as a subdirectory of the AutoCAD install directory. For example: C:\PROGRAM FILES\AUTOCAD R14\VLISP

If you changed the default when you installed Visual LISP, substitute that directory path anywhere you see C:\PROGRAM FILES\AUTOCAD R14\VLISP referenced in this document.

Starting Visual LISP Visual LISP (VLISP) runs as an ObjectARX application within AutoCAD. To launch VLISP, start AutoCAD, then do the following: 1 From the AutoCAD menu bar, choose Tools>Load Application...

2 In the Load dialog box, click File... 3 In the file selection window, go to the folder containing your VLISP program files. Find the file named vlide.arx, and double-click the file name. By default, the file selection dialog box may list only LSP files when you first display it. If this is the case, you won’t see the vlide.arx file listed. You may have to click in the "Files of type" dropdown list box and select "ARX" in order to list vlide.arx. 4 In the Load dialog box, if the Save List checkbox does not contain a check mark, click in the box to select it. The next time you select Load Application

Chapter 1

23

Quick Tour

from the Tools menu, this file name will automatically be listed in the Load dialog box. 5 Click the Load button to start Visual LISP. As VLISP loads, one or more VLISP windows display momentarily, then the AutoCAD window returns. If the Visual LISP window is not the active window (that is, if AutoCAD is on top), type vlide in the AutoCAD command area, then press ENTER.

Overview of the Visual LISP User Interface The first time you start Visual LISP, it displays a screen like the following: Menu

Toolbars

Console

Status Bar The areas shown in the Visual LISP screen are: ■

Menu. You can issue VLISP commands by selecting from the various menus items. If you highlight an item on a menu, VLISP displays a brief description of the command’s function in the status bar at the bottom of the screen.

Overview of the Visual LISP User Interface

24







Toolbars. Click toolbar buttons to quickly issue VLISP commands. There are 5 toolbars (Debug, Edit, Find, Inspect, and Run), each representing a distinct functional group of VLISP commands. You can execute many, but not all, menu commands from the toolbars. If you move your mouse pointer over a toolbar button and leave it there for a couple of seconds, VLISP displays a tool tip (label) indicating the function of the button; a more descriptive explanation appears in the status bar at the bottom of the VLISP screen. Console window. This is a separate, scrollable window within the main Visual LISP window. In the Console window, you can type AutoLISP commands, similar to the way you do in the AutoCAD command window. You can also issue many Visual LISP commands from this window, instead of using the menu or toolbars. See “The Console” on page 28 for more information about the Console. Status bar. The information displayed in the status bar located at the bottom of the screen varies according to what you are currently doing in VLISP.

You may also see a minimized Trace window. At start-up, this window contains informational messages about the current release of Visual LISP, and may contain additional information if VLISP encounters errors during startup.

The Visual LISP Text Editor Most of the time spent working in a Visual LISP session will be spent creating or modifying AutoLISP programs. VLISP comes with an integrated text editor for you to use when working on AutoLISP code. To see what the text editor window looks like, open a sample AutoLISP program. Some sample programs are provided with VLISP. Open the sample program named drawline.lsp by taking the following steps: 1 From the Visual LISP menu, choose File>Open File... 2 Using the Open File dialog box, go to the \VLISP\Sample folder. 3 Double-click the file name drawline.lsp. Visual LISP opens the file in a new window, the text editor window, and displays the name of the file in the status bar. If you make a change to text in the editor, or add new text, VLISP places an asterisk (*) next to the file name in the status bar. The asterisk remains next to that file name until you either save your changes or close the file. You can work on more than one file at a time. Each time you open a file, VLISP displays the file in a new text editor window.

Chapter 1

25

Quick Tour

Other Visual LISP Windows Visual LISP displays some output in the Console window, but several VLISP functions create their own windows in which to display results. For example, when you are tracing the sequence of events as an AutoLISP program runs, the Trace function opens a window in which it displays program events. You can’t type in these output windows, but you can copy text from them and paste the text in the editor or Console window.

Menu Overview You can issue VLISP commands by selecting from the various menus items. For example, from the File menu you can create a new AutoLISP program file, select an existing program file to edit, and print the file you’re editing.

Variable Menu Contents Menu contents may vary depending on which VLISP window (for example, text editor, Console) is currently active. To activate a different window, click in the window's title bar, or in any empty area of that window.

Menu Overview

26

As an example, click in the text editor window containing drawline.lsp, then choose Edit from the Visual LISP menu. You’ll see the following list of items:

The last items on the menu are Parentheses Matching and Extra Commands. Now click in the title bar of the AutoLISP Console window, then select the Edit menu item again:

Notice that “Extra Commands” is no longer the last item on the menu. Parentheses Matching is followed by two new items, “Console History Up” and “Console History Down;” these items apply only to a Console window.

Menu Summary Here is a brief summary of the contents of each menu item; you will learn how to use the various menu commands as you proceed to learn Visual LISP: ■



Chapter 1

27

The File menu allows you to create a new AutoLISP program file for editing, open an existing file, save changes you make to program files, and print the program file. The Edit menu allows you to copy and paste text, undo the last change you made to text (or undo the last command entered in the Console window), select text in the editor or Console windows, match parentheses in

Quick Tour





■ ■







expressions, and redisplay previous commands you’ve entered at the Console prompt. The Search menu allows you to find and replace text strings, set bookmarks, and navigate among bookmarked text. See “Developing Programs With Visual LISP” for information on these topics. The View menu contains commands for finding and displaying the value of variables and symbols in your AutoLISP code. For more information on this topic, see “Debugging Programs.” The Project menu contains commands for working with projects and compiling programs. The Debug menu allows you to set and remove break points in your program, and to step through program execution one expression at a time. You can then check the state of variables and the results of expressions. See “Debugging Programs.” The Tools menu contains commands for setting Visual LISP options for text formatting, and for setting various environment options such as the placement of windows and toolbars. The Window menu allows you to organize the windows currently displayed in your VLISP session, and to activate another Visual LISP or AutoCAD window. The Help menu displays online Help.

The Console From the Console window, you can enter and run AutoLISP commands and see the results of those commands. This is similar to what you can do in the AutoCAD command window, but Visual LISP contains its own distinctive command interpreter for executing commands. As a result, there are a few differences -- some subtle -- in how you accomplish the same task in each interface. For example, to display the current value of an AutoLISP variable in Visual LISP, you simply type the variable name in the Console window and press ENTER. To view the value of a variable in AutoCAD, you must precede the variable name with an exclamation point (!) when you type it in the command window. The Console is also where Visual LISP displays AutoLISP diagnostic messages and displays the result of many AutoLISP functions. For example, output from the print and princ functions are displayed in the Console window. You can scroll through the Console window to view previously entered text and output.

The Console

28

In addition to executing AutoLISP commands and displaying messages, the Visual LISP interpreter supports the many debugging features that are unique to VLISP. Here is a brief summary of Console functions: ■

■ ■ ■



■ ■ ■

You can enter an AutoLISP expression for Visual LISP to read, evaluate, and display the results. If you need more than one line to type your expression, press CTRL+ENTER to continue it on a second line. You can enter more than one expression before pressing the ENTER key. You can copy and transfer text between the Console and the text editor window. Most text editor commands are also available in the Console. Pressing the TAB key retrieves the previous command you entered in the Console. You can press TAB repeatedly to retrieve earlier commands. Pressing SHIFT+TAB key retrieves commands in the opposite direction. The TAB key lets you perform an associative search in the input history. For example, if you begin an expression with “(+” and then press TAB, VLISP retrieves the last command you entered that begins with “(+”. To reverse the direction of the search, press SHIFT+TAB. The ESC key clears any text following the Console prompt. Pressing SHIFT+ESC leaves the text you typed at the Console prompt without interpreting it, and displays a new Console prompt. Clicking the right mouse button, or pressing SHIFT+F10 anywhere in the Console window, displays a menu of Visual LISP commands and options. For example, you can use this feature to copy and paste text in the Console command line, search for text, and initiate VLISP debugging features.

Note that if you type text at the Console prompt, but switch to the AutoCAD window before pressing ENTER, the text is lost from the prompt when you return to the Visual LISP window.

Text Editor Overview The Visual LISP text editor is much more than a writing tool: it’s a central component of the Visual LISP programming environment. To appreciate the versatility and value of the VLISP editor, you need to be familiar with the AutoLISP language.If you are not familiar with AutoLISP yet, you can learn the basics in the “AutoLISP Basics” chapter, and find additional information in the “Using AutoLISP to Communicate with AutoCAD” and “Using AutoLISP to Manipulate AutoCAD Objects” chapters. Here is a list of some major features of the text editor:

Chapter 1

29

Quick Tour







■ ■ ■

Color Coding. The editor identifies different parts of an AutoLISP program and assigns distinct colors to them. This allows you to easily find program components such as function calls and variable names, and can help you find typographical errors. Text Formatting. The editor can format AutoLISP code for you, making it easier to read. You can choose from a number of different formatting styles. Parenthesis Matching. AutoLISP code contains many parentheses. The editor can help you find the close parenthesis that goes with an open parenthesis, and help you detect missing parentheses. Execution of AutoLISP Expressions. You can test expressions and lines of code without leaving the text editor. Searching Through Multiple Files. You can search for a word or expression in several files with a single command. Syntax Checking. You can use Visual LISP syntax-checking features from within the editor.

Details on using the Visual LISP text editor are in “Developing Programs With Visual LISP”.

Loading and Running AutoLISP Programs Once you’ve opened an AutoLISP program file in Visual LISP’s text editor, you can load and run it. Loading is the process whereby text in a file is made available to VLISP’s command interpreter. 1 To load text from an editor window, first make sure that the window is active. If you’re not sure, click anywhere in the window to activate it. Try this with the drawline.lsp sample program. 2 After activating the editor window, click the Load Buffer button in the Run toolbar, or choose Tools>Load Text in Editor from the Visual LISP menu. Visual LISP responds by displaying a message in the Console window indicating that it has loaded the program. 3 Once loaded, you can run the program from the Console command line by typing the program name in parentheses:

and then pressing the ENTER key.

Loading and Running AutoLISP Programs

30

The drawline program doesn’t do much: it asks you to specify two points in an AutoCAD graphics window, and then it draws a straight line between those points. Because drawline asks for user input, Visual LISP turns control over to AutoCAD, where you have the option of specifying points in the graphics window or the command line. What you see next depends on whether or not the AutoCAD windows are currently displayed on your desktop. If they are, you’ll see the AutoCAD windows. But if AutoCAD is currently minimized on your desktop, it won’t automatically be restored and displayed. Instead, Visual LISP will remain visible and your mouse pointer will change to the following icon:

This indicates that the Visual LISP window is no longer active. If this is the case, you need to manually switch to the AutoCAD window. Click the AutoCAD icon on the Windows task bar to activate AutoCAD. Notice that prompts for input are displayed in the AutoCAD command window:

4 After you respond to all the prompts, control returns to Visual LISP and you’ll once again see the VLISP window. When you enter commands in the Visual LISP Console or run a program loaded from the text editor, you may frequently be switching back and forth between the Visual LISP and AutoCAD windows. Besides using the standard Windows methods of switching between applications, you have a couple of alternate methods of switching between Visual LISP and AutoCAD windows: ■

Chapter 1

31

From Visual LISP, you can activate the AutoCAD window by either choosing Window>Activate AutoCAD from the menu, or clicking on the Activate AutoCAD button on the Run toolbar.

Quick Tour



If you are in AutoCAD and want to return to the Visual LISP environment, you can enter the command vlide in the command window.

Running Selected Lines of Code Visual LISP allows you to select lines of code in the text window and run just that code, instead of the whole program. Using the drawline program as an example, highlight the following lines of code: (setq pt1(getpoint "\nEnter the start point for the line: ") pt2(getpoint pt1 "\nEnter the end point for the line: "))

Click the Load Selection button on the Run toolbar. VLISP immediately runs the code through its command interpreter, and turns control over to AutoCAD to prompt you for input.

Exiting the Visual LISP Environment When you are finished with your Visual LISP session, you can exit VLISP by either choosing File>Exit from the menu, or by clicking on the Windows close button. VLISP asks you to verify that you really want to exit. If you have made any changes to the text in any editor window, and have not saved those changes, Visual LISP will next ask if you want to save the changes:

You can either save all the changes you’ve made (Yes) or none of the changes (No). If you exit Visual LISP while there are still programs open in text windows, Visual LISP automatically opens those same programs the next time you start a VLISP session.

Exiting the Visual LISP Environment

32

Chapter 1

33

Quick Tour

2 AutoLISP Basics

In this chapter ■

AutoLISP Expressions



AutoLISP Program Files



AutoLISP Variables



Number Handling

line and see the results immediately. Some of the examples



String Handling

in this chapter are intended to be entered from the Visual



Basic Output Functions

LISP Console window, while others take advantage of the



Equality and Conditional

Visual LISP text editor.



List Handling



Symbol and Function Handling

This chapter introduces the basic concepts of the AutoLISP programming language. Because AutoLISP code does not need to be compiled, you can enter the code at a command

34

AutoLISP Expressions An AutoLISP program consists of a series of expressions. AutoLISP expressions have the following form: (function arguments)

Each expression begins with a left parenthesis and consists of a function name and, optionally, arguments to that function. Each argument can itself be an expression. The expression ends with a right parenthesis. Every expression returns a value that can be used by a surrounding expression. The value of the last interpreted expression is returned to the calling program. For example, the following code example involves three functions. (fun1 (fun2 arguments)(fun3 arguments))

If you enter this code at the Visual LISP Console prompt, Visual LISP invokes its AutoLISP interpreter to process the code. The first function, fun1, has two arguments, and the other functions, fun2 and fun3, have one argument each. The functions fun2 and fun3 are surrounded by function fun1, so their return values are passed to fun1 as arguments. Function fun1 evaluates those two arguments and returns the value to Visual LISP, which in this case was the calling function. Visual LISP displays the returned value in the Console window. The following example shows the use of the * (multiplication) function, which accepts one or more real numbers as arguments. _$ (* 2 27) 54 Because this code example has no surrounding expression, it returns the result to Visual LISP.

Chapter 2

35

AutoLISP Basics

Expressions nested within other expressions return their result to the surrounding expression. The following example uses the result from the + (addition) function as one of the arguments for the * (multiplication) function. _$ (* 2 (+ 5 10)) 30 If you enter the incorrect number of closing (right) parentheses, Visual LISP displays the following prompt: (_> The number of left parentheses in this prompt indicates how many levels of left parentheses remain unclosed. If this prompt appears, you must enter the required number of right parentheses for the expression to be evaluated. _$ (* 2 (+ 5 10 ((_> ) ) 30 A common mistake is to omit the closing quotation mark (") in a text string, in which case the right parentheses are interpreted as being part of the string and have no effect in resolving the open parentheses. To correct this condition, cancel the function by pressing SHIFT+ESC and re-enter it correctly.

AutoLISP Data Types AutoLISP expressions are processed according to the order and data type of the code within the parentheses. Before you can fully utilize AutoLISP, you must understand the differences between the data types and how to use them.

Integers Integers are whole numbers that do not contain a decimal point. AutoLISP integers are 32-bit signed numbers with values ranging from +2,147,483,648 to –2,147,483,647. When you explicitly use an integer in an AutoLISP expression, that value is known as a constant. Numbers such as 2, –56, and 1,200,196 are valid AutoLISP integers.

Reals A real is a number containing a decimal point. Numbers between –1 and 1 must contain a leading zero. Real numbers are stored in double-precision floating-point format, providing at least 14 significant digits of precision. Note that Visual LISP does not show you all of the significant digits.

AutoLISP Expressions

36

Reals can be expressed in scientific notation, which has an optional e or E followed by the exponent of the number (for example, 0.0000041 is the same as 4.1e-6). Numbers such as 3.1, 0.23, –56.123, and 21,000,000.0 are valid AutoLISP reals.

Strings A string is a group of characters surrounded by quotation marks. Within quoted strings the backslash (\) character allows control characters (or escape codes) to be included. When you explicitly use a quoted string in an AutoLISP expression, that value is known as a literal string or a string constant. Examples of valid strings are "string 1" and "\nEnter first point:".

Lists An AutoLISP list is a group of related values separated by spaces and enclosed in parentheses. Lists provide an efficient method of storing numerous related values. AutoCAD expresses 3D points as a list of three real numbers. Examples of lists are (1.0 1.0 0.0), ("this" "that" "the other"), and (1 "ONE").

Selection Sets Selection sets are groups of one or more objects (entities). You can interactively add objects to, or remove objects from, selection sets with AutoLISP routines.

Chapter 2

37

AutoLISP Basics

The following example uses the ssget function to return a selection set containing all of the objects in a drawing. _$ (ssget "X")

Entity Names An entity name is a numeric label assigned to objects in a drawing. It is actually a pointer into a file maintained by AutoCAD, and can be used to find the object’s database record and its vectors (if they are displayed). This label can be referenced by AutoLISP functions to allow selection of objects for processing in various ways. Internally, AutoCAD refers to objects as entities. The following example uses the entlast function to get the name of the last object entered into the drawing. _$ (entlast)

VLA Objects Objects in a drawing may be represented as VLA objects, a data type introduced with Visual LISP. (VLA stands for “Visual LISP ActiveX”.) When working with ActiveX functions, you must refer to VLA objects, not the ename pointer returned by functions such as entlast. For information on working with ActiveX objects, see “Using ActiveX Objects with Visual LISP” on page 269.

File Descriptors File descriptors are alphanumeric labels assigned to files opened by AutoLISP functions. When an AutoLISP function needs to read or write to a file, the label of the file must be referenced. The following example opens the file myinfo.dat for reading. The open function returns the file label: _$ (setq file1 (open "c:\\myinfo.dat" "r") ) # In this example, the file label is stored in variable file1. Files remain open until you explicitly close them in your AutoLISP program. The close function closes a file. The following code closes the file whose label is stored in variable file1: _$ nil

(close file1)

AutoLISP Expressions

38

Symbols and Variables AutoLISP uses symbols to refer to data. Symbol names are not case sensitive and can consist of any sequence of alphanumeric and notation characters except the following: ( (Open Parenthesis) ) (Close Parenthesis) . (Period) ’ (Apostrophe) " (Quote symbol) ; (Semicolon)

A symbol name cannot consist of only numeric characters. Technically, AutoLISP applications consist of either symbols or constant values, such as strings, reals, and integers. For the sake of clarity this guide uses the term symbol to refer to a symbol name that stores data that is static, such as built-in and user-defined functions. The term variable is used to refer to a symbol name that stores program data. The following example uses the setq function to assign the string value "this is a string" to the variable str1: _$ (setq str1 "this is a string") "this is a string" TIP Be kind to yourself and to others that need to read your code: choose meaningful names for your program symbols and variables.

AutoLISP Function Syntax In this guide, the following conventions describe the syntax for AutoLISP functions.

Chapter 2

39

AutoLISP Basics

In the preceding example, the function foo has one required argument, string, and one optional argument, number. Additional number arguments can be provided. Frequently, the name of the argument indicates the expected data type. The examples in the following table show both valid and invalid calls to the foo function. Valid and invalid calls to the foo function Valid calls

Invalid calls

(foo "catch")

(foo 44 13)

(foo "catch" 22)

(foo "fi" "foe" 44 13)

(foo "catch" 22 31)

(foo)

AutoLISP Program Files Although AutoLISP code can be entered at the Visual LISP Console, testing and debugging is considerably easier when you load the AutoLISP code from a file rather than re-entering it each time you make a refinement. The syntax is the same for AutoLISP expressions entered in files or at the Console prompt. AutoLISP code is usually stored in ASCII text files with a .lsp or .mnl extension. However, you can load AutoLISP code from any ASCII text file. From the File menu, choose Open..., and use the Open File dialog box to select your file. Visual LISP loads this file into its text editor and displays the contents in a new window.

Formatting AutoLISP Code The extensive use of parentheses in AutoLISP code can make it difficult to read. The traditional technique for combatting this confusion is indentation. The more deeply nested a line of code is, the farther to the right you start it. Visual LISP automatically formats your code as you type it. Visual LISP also includes tools that allow you to reformat a selection or an entire file. This can improve the appearance of your code, making it more readable. To format the entire text in an active Visual LISP edit window, select Tools>Format AutoLISP in Editor from the Visual LISP menu. To format just some of the text, highlight the portion of the code you want to format and choose Format AutoLISP in Selection from the Tools menu. The code format-

AutoLISP Program Files

40

ter issues an error message if the text you selected is not a sequence of valid AutoLISP expressions. You can set a number of options to customize the way the code formatter lays out your code. See “Formatting Code with the Visual LISP Formatter” on page 162 for more details on using the Visual LISP code formatter.

Spaces in AutoLISP Code In AutoLISP, multiple spaces between variable names, constants, and function names are equivalent to a single space. The end of a line is also treated as a single space. The following two expressions produce the same result. (setq test1 123 test2 456) (setq test1 123 test2 456 )

Comments It is a good practice to include comments in AutoLISP program files. Comments are useful to both the programmer and future users who may need to revise a program to suit their needs. Use comments to ■ ■ ■ ■ ■

Give a title, authorship, and creation date Provide instructions on using a routine Make explanatory notes throughout the body of a routine Make notes to yourself during debugging Allow for characters that provide visual aesthetics and organization

Comments begin with a semicolon (;) and continue through the end of the line. ; This entire line is a comment (setq area (* pi r r)) ; Compute area of circle

Any text within ;| ... |; is ignored; therefore, comments can be included within a line of code or extend for multiple lines. This type of comment is known as an in-line comment. (setq tmode ;|some note here|; (getvar "tilemode"))

The following example shows a comment that continues for multiple lines: (setvar "orthomode" 1) ;|comment starts here and continues to this line, but ends way down here|; (princ "\nORTHOMODE set On.")

Chapter 2

41

AutoLISP Basics

It is recommended that you use comments liberally when writing AutoLISP programs. Most of the .lsp files provided with Visual LISP contain good examples of commenting style. For instance, the file sym-exp.lsp is extensively commented and contains some interesting and useful AutoLISP routines. You can find this file in the Visual LISP \Sample directory.

Visual LISP Comment Styles The Visual LISP code formatter recognizes five types of comments, and positions each comment according to its type. Refer to “Comment Styles” on page 170 for a description of each comment style. Regardless of your commenting style, it is more important that comments be present than that they obey any particular layout rules.

Color Coding Visual LISP provides an additional solution to making AutoLISP text easier to read: color coding. Visual LISP looks at each word of text and tries to determine what type of AutoLISP language element it represents (for example, a built-in function, a number, a string). Every type of element is assigned its own color, so you can easily distinguish among them when viewing the code. Keep in mind that color coding is a Visual LISP editor feature, and it is possible that someone who does not have access to Visual LISP may need to read your code some day. For this reason, you should still use indentation and alignment to enhance your program’s readability.

AutoLISP Variables An AutoLISP variable assumes the data type of the value assigned to it. Until they are assigned new values, variables retain their original values. You use the AutoLISP setq function to assign values to variables. (setq variable_name1 value1 [variable_name2 value2 ...])

The setq function assigns the specified value to the variable name given. It returns the value as its function result. If you issue setq at the Visual LISP Console prompt, the result is displayed in the Console window: _$ (setq val 3 abc 3.875) 3.875 _$ (setq layr "EXTERIOR-WALLS") "EXTERIOR-WALLS" _$

AutoLISP Variables

42

Displaying the Value of a Variable To display the current value of a variable, just enter the variable name at the Console prompt: _$ abc 3.875 NOTE This behavior differs in the AutoCAD environment. If you set a variable from the AutoCAD Command prompt and want to display that variable’s value, you must precede the variable name with an exclamation point (!). For example: Command: !abc 3.875

Nil Variables An AutoLISP variable that has not been assigned any value is said to be nil. nil is different from blank, which is considered a character string, and 0, which is a number. So in addition to checking a variable for its current value, you can test to determine whether or not the variable has been assigned a value. Each variable consumes a small amount of memory, so it is good programming practice to reuse variable names or to set variables to nil when their values are no longer needed. Setting a variable to nil releases the memory used to store that variable’s value. If you no longer need the val variable, you can release its value from memory with the following expression: _$ nil

(setq val nil)

Another efficient programming practice is to use local variables whenever possible. See “Local Variables in Functions” on page 62 for more information on this topic.

Chapter 2

43

AutoLISP Basics

Predefined Variables The following predefined variables are commonly used in AutoLISP applications: PAUSE

Defined as a string consisting of a single backslash (\) character. This variable is used with the command function to pause for user input.

PI

Defined as the constant π (pi). It evaluates to approximately 3.1415926.

T

Defined as the constant T. This is used as a non-nil value.

NOTE You can change the value of these variables with the setq function. However, other applications might rely on their values being consistent; therefore, it is recommended that you do not modify these variables. Visual LISP, by default, protects these variables from redefinition. You must override this protection through the Symbol Service feature in order to modify a predefined variable.

Number Handling AutoLISP provides functions for working with integers and real numbers. The number-handling functions are as follows:

+ (addition)

abs

gcd

minusp

– (subtraction)

atan

log

rem

* (multiplication)

cos

logand

sin

/ (division)

exp

logior

sqrt

~ (bitwise NOT)

expt

lsh

zerop

1+ (increment)

fix

max

1– (decrement)

float

min

Each number-handling function is described in “AutoLISP Function Reference.” In addition to performing complex mathematical computations in applications, you can use the number-handling functions to help you in your daily use of AutoCAD. If you are drawing a steel connection detail that uses a 2.5"

Number Handling

44

bolt that is 0.5" in diameter, how many threads are there if this bolt has 13 threads per inch? Use the * (multiplication) function at the Console prompt. _$ (* 2.5 13) 32.5 The arithmetic functions that have a number argument (as opposed to num or angle, for example) return different values if you provide integers or reals as arguments. If all arguments are integers, the value returned is an integer. However, if one or all of the arguments are reals, the value returned is a real. To ensure that your application passes real values, make sure that at least one of the arguments is a real. _$ (/ 12 5) 2 _$ (/ 12.0 5) 2.4 NOTE In some cases, you can use integers and reals interchangeably. This is not the case, however, when using ActiveX function. See “Converting Arguments” on page 287 in chapter 9.

String Handling AutoLISP provides functions for working with string values. The string-handling functions are as follows:

strcase

strlen

strcat

substr

wcmatch

The following functions convert string values into numeric values and numeric values into string values.

Chapter 2

45

angtof

atof

distof

angtos

atoi

itoa

ascii

chr

rtos

AutoLISP Basics

AutoLISP provides numerous control characters for use in strings; for a complete listing, see “Control Characters in Strings” on page 49. The strcase function returns the conversion of all alphabetic characters in a string to upper or lower case. It accepts two arguments: a string, and an optional argument that specifies the case in which the characters are returned. If the optional second argument is omitted, it evaluates to nil and strcase returns the characters converted to upper case. _$ (strcase "This is a TEST.") "THIS IS A TEST." If the second argument is provided and has a non-nil value, the characters are returned as lower case. AutoLISP provides the predefined variable T to use in situations like this where a non-nil value is used as a type of true/false toggle. However, you don’t need to use T here; if it suits your application better, you can use any non-nil value. _$ (strcase "This is a TEST." T) "this is a test." The strcat function combines multiple strings into a single string value. This is useful for placing a variable string within a constant string. The following code sets a variable to a string value and then uses strcat to insert that string into the middle of another string. _$ (setq str "BIG") (setq bigstr (strcat "This is a " str " test.")) "This is a BIG test." If the variable bigstr is set to the preceding string value, you can use the strlen function to find out the number of characters (including spaces) in that string. _$ (strlen bigstr) 19 The substr function returns a substring of a string. It has two required arguments and one optional argument. The first argument is the string. The second argument is an integer that specifies the first character of the string that you want to include in the substring. If the third argument is provided, it specifies the number of characters to include in the substring. If the third argument is not provided, substr returns all characters including and following the specified start character. You can use the substr function to strip off the three-letter extension from a file name. First, set a variable to a file name. (Depending on the application,

String Handling

46

you would normally do this by querying a system variable or by requesting user input.) _$ (setq filnam "bigfile.txt") "bigfile.txt" You need to get a string that contains all characters except the last four (the period and the three-letter extension). Use strlen to get the length of the string, and subtract four from that value. Then use substr to specify the first character of the substring and its length. _$ (setq newlen (- (strlen filnam) 4)) 7 _$ (substr filnam 1 newlen) "bigfile" If your application has no need for the value of newlen, you can combine these two lines of code into one. _$ (substr filnam 1 (- (strlen filnam) 4)) "bigfile"

Basic Output Functions AutoLISP includes functions for controlling the AutoCAD display, including both text and graphics windows. Some of these functions also display information in the Visual LISP Console window. The major text display functions are

prin1

print

princ

prompt

The remaining display functions are covered in the “Using AutoLISP to Communicate with AutoCAD” chapter. The following file-handling functions can also display output to the command line area. read-char

Chapter 2

47

AutoLISP Basics

read-line

write-char

write-line

Displaying Messages The basic output functions are prompt, princ, prin1, and print. The prompt function displays a message (a string) on the AutoCAD command line and returns nil to the Visual LISP Console. The princ, prin1, and print functions all display an expression (not necessarily a string) at the AutoCAD command line and return the expression to the Visual LISP Console. Optionally, these functions can send output to a file. The differences are: displays strings without the enclosing quotation marks displays strings enclosed in quotation marks print also displays strings enclosed in quotation marks, but places a blank line before the expression and a space afterward.

■ princ ■ prin1 ■

The following example demonstrates the differences between the four basic output functions and how they handle the same string of text. The text following “prints” is what you would see at the AutoCAD Command prompt; text following returns would appear within the Visual LISP Console or within an application. See the following section for an explanation of the control characters used in the example. (setq str "The \"allowable\" tolerance is \261 \274\"") (prompt str)

prints The "allowable" tolerance is and returns nil

(princ str)

prints The "allowable" tolerance is 1/4" and returns "The \"allowable\" tolerance is

1/4""

prints "The \"allowable\" tolerance is 1/4"" and returns "The "\allowable\" tolerance is

1/4""

(prin1 str)

(print str)

prints

1/4"

"The \"allowable\" tolerance is 1/4"" and returns "The \"allowable\" tolerance is

1/4""

Exiting Quietly If you invoke the princ function without passing an expression to it, it displays nothing and has no value to return. So if you write an AutoLISP expression that ends with a call to princ without any arguments, the ending nil is suppressed (because it has nothing to return). This practice is called exiting quietly.

Basic Output Functions

48

Control Characters in Strings Within quoted strings, the backslash (\) character allows control characters (or escape codes) to be included. The following table shows the currently recognized control characters. Control characters Code

Description

\\

\ character

\"

" character

\e

Escape character

\n

Newline character

\r

Return character

\t

Tab character

\nnn

Character whose octal code is nnn

\U+xxxx

Unicode character sequence

\M+nxxxx

Multi-byte character sequence

The prompt and princ functions expand the control characters in a string and display the expanded string in the AutoCAD command window. If you need to use the backslash character (\) or quotation mark (") within a quoted string, it must be preceded by the backslash character (\). For example, if you enter _$

(princ "The \"filename\" is: D:\\ACAD\\TEST.TXT. ")

The following displays in the AutoCAD command window: The "filename" is: D:\ACAD\TEST.TXT You will also see this output in the Visual LISP Console window, along with the return value from the princ function (which is your original input, with the unexpanded control characters).

Chapter 2

49

AutoLISP Basics

To force a line break at a specific location in a string, use the newline character (\n). _$ (prompt "An example of the \nnewline character. ") An example of the newline character. The return character (\r) returns to the beginning of the current line. This is useful for displaying incremental information (such as the number of objects processed). The tab character (\t) can be used in strings to indent or to provide alignment with other tabbed text strings. In this example, note the use of the princ function to suppress the ending nil. _$ (prompt "\nName\tOffice\n– – – – –\t– – – – – 1> \nSue\t101\nJoe\t102\nSam\t103\n") (princ)

Name

Office

–––––

––––

Sue

101

Joe

102

Sam

103

Wild-Card Matching The wcmatch function enables applications to compare a string to a wild-card pattern. You can use this facility when you are building a selection set (in conjunction with ssget) and when you are retrieving extended entity data by application name (in conjunction with entget). The wcmatch function compares a single string to a pattern. It returns T if the string matches the pattern, and nil if it does not. The wild-card patterns are similar to the regular expressions used by many system and application programs. In the pattern, alphabetic characters and numerals are treated literally; brackets can be used to specify optional characters or a range of letters or digits; a question mark (?) matches a single character; an asterisk ( *) matches a sequence of characters; and certain other special characters have special meanings within the pattern. When you use the * character at the beginning and end of the search pattern, you can locate the desired portion

Basic Output Functions

50

anywhere in the string. For more information, see “wcmatch” in “AutoLISP Function Reference”. In the following examples, a string variable called matchme has been declared and initialized. _$ (setq matchme "this is a string - test1 test2 the end") "this is a string - test1 test2 the end" The following code checks whether matchme begins with the four characters "this". _$ T

(wcmatch matchme "this*")

The following code illustrates the use of brackets in the pattern. In this case, wcmatch returns T if matchme contains "test4", "test5", "test6", or "test9" (note the use of the * character).

_$ nil

(wcmatch matchme "*test[4-69]*")

However, _$ T

(wcmatch matchme "*test[4-61]*")

because the string contains "test1". The pattern string can specify multiple patterns, separated by commas. The following code returns T if matchme equals "ABC", or if it begins with "XYZ", or if it ends with "end". _$ T

Chapter 2

51

(wcmatch matchme "ABC,XYZ*,*end")

AutoLISP Basics

Equality and Conditional AutoLISP includes functions that provide equality verification as well as conditional branching and looping. The equality and conditional functions are as follows:

= (equal to)

and

or

/= (not equal to)

Boole

repeat

< (less than)

cond

while

(greater than)

equal

>= (greater than or equal to)

if

Each equality and conditional function is described in “AutoLISP Function Reference.”

List Handling AutoLISP provides functions for working with lists. The list-handling functions are as follows:

append

foreach

listp

reverse

assoc

last

mapcar

subst

car and cdr

length

member

cons

list

nth

This section provides examples of the append, assoc, car, cons, list, nth, and subst functions. Each list-handling function is described in “AutoLISP Function Reference.” Lists provide an efficient and powerful method of storing numerous related values. After all, LISP is so-named because it is the LISt Processing language.

Equality and Conditional

52

Once you understand the power of lists, you’ll find that you can create even more powerful and flexible applications. Several AutoLISP functions provide a basis for programming two-dimensional and three-dimensional graphics applications. These functions return point values in the form of a list. The list function provides a simple method of grouping related items. These items do not need to be of similar data types. The following code groups three related items as a list. _$ (setq lst1 (list 1.0 "One" 1)) (1.0 "One" 1) You can retrieve a specific item from the list in variable lst1 with the nth function. The nth function accepts two arguments. The first argument is an integer that specifies which item to return. A 0 specifies the first item in a list, 1 specifies the second item, and so on. The second argument is the list itself. The following code returns the second item in lst1. _$ (nth 1 lst1) “One” The car and cdr functions provide another way to extract items from a list. For examples on using car and cdr, and combinations of the two, see “Point Lists” on page 54. Three functions let you modify an existing list. The append function returns a list with new items added to the end of it, and the cons function returns a list with new items added to the beginning of the list. The subst function returns a list with a new item substituted for every occurrence of an old item. These functions do not modify the original list, they return a modified list. To modify the original list, you must explicitly replace the old list with the new list. The append function takes any number of lists and runs them together as one list. Therefore, all arguments to this function must be lists. The following code adds another "One" to the list lst1. Note the use of the quote (or ‘) function as an easy way to make the string "One" into a list. _$ (setq lst2 (append lst1 ‘(“One”))) (1.0 "One" 1 "One")

Chapter 2

53

AutoLISP Basics

The cons function combines a single element with a list. You can add another string "One" to the beginning of this new list, lst2, with the cons function. _$ (setq lst3 (cons "One" lst2 )) ("One" 1.0 "One" 1 "One") You can substitute all occurrences of an item in a list with a new item with the substr function. The following code replaces all strings "One" with the string "one". _$ (setq lst4 (subst "one" "One" lst3)) ("one" 1.0 "one" 1 "one")

Point Lists AutoLISP observes the following conventions for handling graphics coordinates. Points are expressed as lists of two or three numbers surrounded by parentheses. 2D points

Expressed as lists of two real numbers (X and Y respectively), as in (3.4 7.52)

3D points

Expressed as lists of three real numbers (X, Y, and Z respectively), as in (3.4 7.52 1.0)

Point variables contain X, Y, and (optionally) Z components. The first item in the list is the X component of the point, the second is the Y component, and the third (if present) is the Z component. You can use the list function to form such lists. _$ (list 3.875 1.23) (3.875 1.23) _$ (list 88.0 14.77 3.14) (88.0 14.77 3.14)

List Handling

54

To assign particular coordinates to a point variable, you can use one of the following expressions: _$ (setq pt1 (list 3.875 1.23)) (3.875 1.23) _$ (setq pt2 (list 88.0 14.77 3.14)) (88.0 14.77 3.14) _$ (setq abc 3.45) 3.45 _$ (setq pt3 (list abc 1.23)) (3.45 1.23) The latter uses the value of variable abc as the X component of the point. If all of the members of a list are constant values, you can use the quote function to explicitly define the list, rather than use the list function. The quote function returns an expression unevaluated. _$ (setq pt1 (quote (4.5 7.5))) (4.5 7.5) The single quotation mark (’) can be used as shorthand for the quote function. The following code produces the same result as the preceding code. _$ (setq pt1 ’(4.5 7.5)) (4.5 7.5) You can refer to X, Y, and Z components of a point individually, using three additional built-in functions called car, cadr, and caddr. The following examples show how to extract the X, Y, and Z coordinates from a 3D point list. The variable pt is set to the point (1.5 3.2 2.0). _$ (setq pt ’(1.5 3.2 2.0)) (1.5 3.2 2.0) The car function returns the first member of a list. In this example it returns the X value of point pt to the variable x_val. _$ (setq x_val (car pt)) 1.5

Chapter 2

55

AutoLISP Basics

The cadr function returns the second member of a list. In this example it returns the Y value of point pt to the variable y_val. _$ (setq y_val (cadr pt)) 3.2 The caddr function returns the third member of a list. In this example it returns the Z value of point pt to the variable z_val. _$ (setq z_val (caddr pt)) 2.0 You can use the following code to define the lower-left and upper-right (pt1 and pt2) corners of a rectangle. _$ (setq pt1 ’(1.0 2.0) pt2 ’ (3.0 4.0)) (3.0 4.0) You can use the car and cadr functions to set variable pt3 to the upper-left corner of the rectangle, by extracting the X component of pt1 and the Y component of pt2. _$ (setq pt3 (list (car pt1) (cadr pt2))) (1.0 4.0) The preceding expression sets pt3 equal to point (1.0,4.0).

Dotted Pairs Another way AutoCAD uses lists to organize data is with a special type of list called a dotted pair. A dotted pair is a list that must always contain two members. When representing a dotted pair, AutoLISP separates the members of the list with a period (.). Most list-handling functions will not accept a dotted pair as an argument, so you should be sure you are passing the right kind of list to a function. In addition to adding an item to the beginning of a list, the cons function can create a dotted pair. If the second argument to the cons function is a constant or quoted value, it creates a dotted pair. _$ (setq sublist (cons ‘lyr "WALLS")) (LYR . "WALLS") The car, cdr, and assoc functions are useful for handling dotted pairs. The following code creates an association list. An association list is a list of lists

List Handling

56

and is the method that AutoCAD uses to maintain entity definition data. The following code creates an association list of dotted pairs. _$ (setq wallinfo (list sublist(cons ‘len 240.0) (cons ‘hgt 96.0))) ( (LYR . “WALLS”) (LEN . 240.0) (HGT . 96.0) ) The assoc function returns a specified list from within an association list regardless of the specified list’s location within the association list. The assoc function searches for a specified key element in the lists. _$ (assoc ’len wallinfo) (LEN . 240.0) _$ (cdr (assoc ’lyr wallinfo)) "WALLS" _$ (nth 1 wallinfo) (LEN . 240.0) _$ (car(nth 1 wallinfo)) LEN

Symbol and Function Handling AutoLISP provides functions for handling symbols and variables. The symbol-handling functions are as follows:

atom

not

quote

atoms-family

null

set

boundp

numberp

setq

type

Each symbol-handling function is described in “AutoLISP Function Reference.” AutoLISP provides functions for handling one or more groups of functions. The function-handling functions are as follows:

apply

eval

progn

defun

lambda

trace

untrace

This section provides examples of the defun function. Each function-handling function is described in “AutoLISP Function Reference.”

Chapter 2

57

AutoLISP Basics

With AutoLISP you can define your own functions. Once they are defined, you can use these user-defined functions at the Visual LISP Console prompt or within other AutoLISP expressions just as you use the standard functions. You can also create your own AutoCAD commands, because commands are just a special type of function. The defun function (see “defun” in “AutoLISP Function Reference”) combines a group of expressions into a function or command. This function requires at least three arguments, the first of which is the name of the function (symbol name) to define. The second argument is the argument list (a list of arguments and local variables used by the function). The argument list can be nil or an empty list ( ). Argument lists are discussed in greater detail in “Functions with Arguments” on page 64. If local variables are provided, they are separated from the arguments by a slash ( / ). Local variables are discussed in “Local Variables in Functions” on page 62. Following these arguments are the expressions that make up the function; there must be at least one expression in a function definition. (defun symbol_name ( args / local_symbols ) expressions )

The following code defines a simple function that accepts no arguments and displays a message in the AutoCAD command line. Note that the argument list is defined as an empty list ( () ). _$ (defun DONE ( ) (prompt "\nbye! ")) DONE Now that the DONE function is defined, you can use it as you would any other function. Because it prints the message bye! to a new line at the command line, you might use the DONE function in the following manner: _$ (prompt "The value is 127. ")(DONE)(princ) The value is 127 bye! Functions that accept no arguments may seem useless. However, you might use this type of function to query the states of certain system variables or conditions and to return a value that indicates those values.

C:XXX Functions If an AutoLISP function is defined with a name of the form C:XXX, it can be issued at the AutoCAD Command prompt in the same manner as a built-in AutoCAD command. This is true regardless of whether you define and load the function in the Visual LISP environment or in the AutoCAD environ-

Symbol and Function Handling

58

ment. You can use this feature to add new commands to AutoCAD or to redefine existing commands. There are two important things to note about using functions named C:XXX in the Visual LISP environment: 1 When you execute a C:XXX-named function from within the Visual LISP environment, you cannot omit the c: or parentheses when you type the function name. 2 The ability to define a function named c:xxx in Visual LISP and have it automatically recognized as an AutoCAD command is controlled by a VLISP variable named *C-COLON-EXPORT*. By default, this feature is enabled. To use functions as AutoCAD commands, be sure that they adhere to the following rules: ■

The function name must use the form C:XXX (upper- or lowercase characters). The C: portion of the name must always be present; the XXX portion is a command name of your choice. C:XXX functions can be used to override built-in AutoCAD commands. (See “Redefining AutoCAD Commands” on page 60.)

NOTE In this case, C: is not a reference to a disk drive. It’s a special prefix that denotes a command line function. ■

The function must be defined with no arguments. However, local variables are permitted and it is a good programming practice to use them.

A function defined in this manner can be issued transparently from within any prompt of any built-in AutoCAD command, provided that the function issued transparently does not call the command function (the command function is the AutoLISP function you use to issue AutoCAD commands; see the entry on “command”). When issuing a C:XXX defined command transparently, you must precede the XXX portion with a single quotation mark (’). You can issue a built-in command transparently while a C:XXX command is active by preceding it with a single quotation mark (’), as you would with all commands that are issued transparently. However, you cannot issue a C:XXX command transparently while a C:XXX command is active. When calling a function defined as a command from the code of another AutoLISP function, you must use the whole name, including the parentheses; for example, (C:HELLO). You also must use the whole name when you invoke the function from the Visual LISP Console prompt, even though you can eliminate the parentheses at the AutoCAD Command prompt.

Chapter 2

59

AutoLISP Basics

Adding Commands Using the C:XXX feature, you can define a command that displays a simple message. _$ (defun C:HELLO () (princ "Hello world. \n") (princ)) C:HELLO HELLO is now defined as a command, in addition to being an AutoLISP function. This means that you can issue the command from the AutoCAD Command prompt.

Command: hello Hello world. This new command can be issued transparently because it does not call the command function itself. At the AutoCAD Command prompt, you could do the following: Command: line From point: ’hello Hello world. From point: Remember: to run this function from the Visual LISP Console prompt, you need to issue the function call using the parentheses, since the Visual LISP environment cannot execute AutoCAD commands: _$ (c:hello) Hello world. If you follow your function definition with a call to the setfunhelp function, you can associate a Help file and topic with a user-defined command. When a user calls help transparently (’help) at a prompt within the user-defined command the topic specified by setfunhelp displays. You cannot usually use an AutoLISP statement to respond to prompts from an AutoLISP-implemented command. However, if your AutoLISP routine makes use of the initget function, you can use arbitrary keyboard input with certain functions. This allows an AutoLISP-implemented command to accept an AutoLISP statement as a response.

Redefining AutoCAD Commands With AutoLISP, external commands, and the alias feature, you can define your own AutoCAD commands. You can use the UNDEFINE command to redefine a built-in AutoCAD command with a user-defined command of the same name. To restore the built-in definition of a command, use the

Symbol and Function Handling

60

REDEFINE command. The UNDEFINE command is in effect for the current editing session only.

You can always activate an undefined command by specifying its true name, which is the command name prefixed by a period. For example, if you undefine QUIT, you can still access the command by entering .quit at the AutoCAD Command prompt. This is also the syntax that should be used within the AutoLISP command function. Consider the following example. Whenever you use the LINE command, you want AutoCAD to remind you about using the PLINE command. You can define the AutoLISP function C:LINE to substitute for the normal LINE command as follows: _$ (defun C:LINE ( ) 1> (princ "Shouldn’t you be using PLINE?\n") 1> (command ".LINE") (princ) ) C:LINE In this example, the function C:LINE is designed to issue its message and then to execute the normal LINE command (using its true name, .LINE). Before AutoCAD will use your new definition for the LINE command, you must undefine the built-in LINE command. At the Visual LISP Console prompt, enter the following command: _$

(command "undefine" "line")

Now, if you enter line at the AutoCAD Command prompt, AutoCAD uses the C:LINE AutoLISP function:

Command: line Shouldn’t you be using PLINE? .LINE From point: From point: The previous code example assumes that the CMDECHO system variable is set to 1 (On). If CMDECHO is set to 0 (Off) AutoCAD does not display prompts

Chapter 2

61

AutoLISP Basics

that are the result of a command function call. The following code uses the CMDECHO system variable to control the display of command prompts. _$ (defun C:LINE (/ cmdsave ) (_> (setq cmdsave(setvar "cmdecho" 0)) (_> (princ "Shouldn’t you be using PLINE?\n") (_> (command ".LINE") (_> (setvar "cmdecho" cmdsave) (_> (princ) ) C:LINE You could use this feature in a drawing management system, for example. You could redefine the NEW, OPEN, QUIT, and END commands to write billing information to a log file before you terminate the editing session. NOTE It is recommended that you protect your menus, scripts, and AutoLISP programs by using the period-prefixed forms of all commands. This ensures that your applications use the built-in command definitions rather than a redefined command.

Local Variables in Functions AutoLISP provides a method for defining a list of symbols (variables) that are available only to your function. These are known as local variables. TIP later on!

Using local variables will save you from a lot of debugging headaches

Local Variables Versus Global Variables The use of local variables ensures that the variables in your functions are unaffected by the surrounding application and that your variables do not remain available after the calling function has completed its task. Many user-defined functions are used as utility functions within larger applications. User-defined functions also typically contain a number of variables whose values and use are specific to that function. The danger in using global variables, instead of local variables, is that you may inadvertently modify them outside of the function they were declared in and intended for. This can lead to unpredictable behavior. And it can be very difficult to identify the source of this type of problem. Another advantage of using local variables is that Visual LISP can recycle the memory space used by these variables, whereas global variables keep accumulating within AutoCAD memory space.

Symbol and Function Handling

62

There are some legitimate uses for global variables, but these should be kept to a minimum. It is also a good practice to indicate that you intend a variable to be global. A common way of doing this is to add an opening and closing asterisk to the variable name, for example, *default-layer*.

Example Using Local Variables The following example shows the use of local variables in a user-defined function (make sure that there is at least one space between the slash and the local variables). _$ (defun LOCAL ( / aaa bbb) 1> (setq aaa "A" bbb "B") 1> (princ (strcat "\naaa has the value " aaa )) 1> (princ (strcat "\nbbb has the value " bbb)) 1> (princ) ) LOCAL Before you test the new function, assign variables aaa and bbb to values other than those used in the LOCAL function. _$ (setq aaa 1 bbb 2) 2 You can verify that the variables aaa and bbb are actually set to those values. _$ 1 _$ 2

aaa bbb

Now test the LOCAL function. _$ (local) aaa has the value A bbb has the value B You will notice that the function used the values for aaa and bbb that are local to the function. You can verify that the current values for aaa and bbb are still set to their nonlocal values. _$ 1 _$ 2

Chapter 2

63

aaa bbb

AutoLISP Basics

In addition to ensuring that variables are local to a particular function, this technique also ensures that the memory used for those variables is available for other functions.

Functions with Arguments With AutoLISP you can define functions that accept arguments. Unlike many of the standard AutoLISP functions, user-defined functions cannot have optional arguments. When you call a user-defined function that accepts arguments, you must provide values for all of the arguments. The symbols to use as arguments are defined in the argument list before the local variables. Arguments are treated as a special type of local variable; argument variables are not available outside the function. You cannot define a function with multiple arguments of the same name. The following code defines a function that accepts two string arguments, combines them with another string, and returns the resulting string. _$ (defun ARGTEST ( arg1 arg2 / ccc ) 1> (setq ccc "Constant string") 1> (strcat ccc ", " arg1 ", " arg2) ) ARGTEST The ARGTEST function returns the desired value since AutoLISP always returns the results of the last expression it evaluates. The last line in ARGTEST uses strcat to concatenate the strings, and the resulting value is returned. This is one example where you should not use the princ function to suppress the return value from your program. This type of function can be used a number of times within an application to combine two variable strings with one constant string in a specific order. Because it returns a value, you can save the value to a variable for use later in the application. _$ (setq newstr (ARGTEST "String 1" "String 2") ) "Constant string, String 1, String 2" The variable newstr is now set to the value of the three strings combined. Note that the ccc variable was defined locally within the ARGTEST function. Once the function runs to completion, Visual LISP recycles the variable, recapturing the memory that had been allocated to it. To prove this, check from the Visual LISP Console to see if there is still a value assigned to ccc. _$ ccc nil

Symbol and Function Handling

64

Chapter 2

65

AutoLISP Basics

3 Using AutoLISP to Communicate with AutoCAD In this chapter

AutoLISP provides various functions for examining the contents of the currently loaded drawing. This chapter introduces these functions and describes how to use them in conjunction with other functions.



Query and Command Functions



Display Control



Getting User Input



Geometric Utilities



Conversions



File Handling



Device Access and Control

66

NOTE The AutoLISP examples in this chapter show code entered from the AutoCAD Command prompt, not the Visual LISP Console.

Query and Command Functions The query and command functions described in this section provide direct access to AutoCAD commands and drawing services. Their behavior depends on the current state of the AutoCAD system and environment variables, and on the drawing that is currently loaded. The query and command functions are as follows: acad_colordlg

getcfg

getvar

setvar

command

getenv

setcfg

ver

Examples of the command, getcfg, getvar, setcfg, and getvar functions are provided in this section. The help, getenv, and ver functions are described in the “AutoLISP Function Reference”. Access to the AutoCAD help system is implemented by the help function.

Command Submission The command function sends an AutoCAD command directly to the AutoCAD Command prompt. The command function has a variable-length argument list. These arguments must correspond to the types and values expected by that command’s prompt sequence; these may be strings, real values, integers, points, entity names, or selection set names. Data such as angles, distances, and points can be passed either as strings or as the values themselves (as integer or real values, or as point lists). An empty string ("") is equivalent to entering a space or ENTER on the keyboard. There are some restrictions on the commands that you can use with the command function. See the “AutoLISP Function Reference” definition of this function for more information. The following code fragment shows representative calls to command. (command "circle" "0,0" "3,3") (command "thickness" 1) (setq p1 ’(1.0 1.0 3.0)) (setq rad 4.5) (command "circle" p1 rad)

If AutoCAD is at the Command prompt when these functions are called, AutoCAD performs the following actions:

Chapter 3

67

Using AutoLISP to Communicate with AutoCAD

1 The first call to command passes points to the CIRCLE command as strings (draws a circle centered at (0.0,0.0) and passes through (3.0,3.0)). 2 The second call passes an integer to the THICKNESS command (changes the current thickness to 1.0). 3 The last call uses a 3D point and a real (floating-point) value, both of which are stored as variables and passed by reference to the CIRCLE command (draws another [extruded] circle centered at (1.0,1.0,3.0) with a radius of 4.5).

Foreign-Language Support If you develop AutoLISP programs that might be used with a foreign-language version of AutoCAD, the standard AutoCAD commands and key words are automatically translated if you precede each command or key word with an underscore (_). (command "_line" pt1 pt2 pt3 "_c")

If you are using the dot prefix (to avoid using redefined commands), you can place the dot and underscore in either order. Both "._line" and "_.line" are valid.

Pausing for User Input If an AutoCAD command is in progress and the predefined symbol PAUSE is encountered as an argument to command, the command waits (is suspended) to allow direct user input (usually point selection or dragging). This is similar to the backslash pause mechanism provided for menus. If you issue a transparent command while a command function is suspended, the command function remains suspended. Therefore, users can ’ZOOM and ’PAN while at a command pause. The pause remains in effect until AutoCAD gets valid input, and no transparent command is in progress. For example, the following code begins the CIRCLE command, sets the center point at (5,5), and then pauses to let the user drag the circle’s radius on screen. When the user specifies the desired point (or types in the desired radius), the function resumes, drawing a line from (5,5) to (7,5). (command "circle" "5,5" pause "line" "5,5" "7,5" "")

Menu input is not suspended by an AutoLISP pause. If a menu item is active when the command function pauses for input, that input request can be satisfied by the menu. If you want the menu item to be suspended as well, you must provide a backslash (\) in the menu item. When valid input is found, both the command function and the menu item resume.

Query and Command Functions

68

Passing Pick Points to AutoCAD Commands Some AutoCAD commands (such as TRIM, EXTEND, and FILLET) require the user to specify a pick point as well as the object itself. To pass such pairs of object and point data by means of the command function without the use of a PAUSE, you must first store them as variables. Points can be passed as strings within the command function or can be defined outside the function and passed as variables, as shown in the following example. This code fragment shows one method of passing an entity name and a pick point to the command function. (command "circle" "5,5" "2") (command "line" "3,5" "7,5" "") (setq el (entlast)) (setq pt ’(5 7)) (command "trim" el "" pt "")

Draws circle Draws line Gets last entity name Sets point pt Performs trim

If AutoCAD is at the Command prompt when these functions are called, AutoCAD performs the following actions: 1 Draws a circle centered at (5,5) with a radius of 2. 2 Draws a line from (3,5) to (7,5). 3 Creates a variable el that is the name of the last object added to the database. (See “Using AutoLISP to Manipulate AutoCAD Objects” for more discussion of objects and object handling functions.) 4 Creates a variable pt that is a point on the circle. (This point selects the portion of the circle to be trimmed.) 5 Performs the TRIM command by selecting the object el and by selecting the point specified by pt.

System and Environment Variables The functions getvar and setvar allow AutoLISP applications to inspect and change the value of AutoCAD system variables. These functions use a string to specify the variable name. The setvar function specifies a value of the type that the system variable expects. AutoCAD system variables come in various types: integers, real values, strings, 2D points, and 3D points. Values supplied as arguments to setvar must be of the expected type. If an invalid type is supplied, an AutoLISP error is generated. The following code fragment ensures that subsequent FILLET commands use a radius of at least 1: (if (< (getvar "filletrad") 1) (setvar "filletrad" 1) )

Chapter 3

69

Using AutoLISP to Communicate with AutoCAD

An additional function, getenv, provides AutoLISP routines access to the currently defined operating-system environment variables.

Configuration Control AutoCAD uses the acad14.cfg file to store configuration information. The AppData section of this file is provided for users and developers to store configuration information that pertains to their applications. The getcfg and setcfg functions allow AutoLISP applications to inspect and change the value of parameters in the AppData section.

Display Control AutoLISP includes functions for controlling the AutoCAD display, including both text and graphics windows. Some of these functions prompt for, or depend on, input from the AutoCAD user. The display-control functions are as follows: graphscr

menucmd

print

textpage

grdraw

menugroup

prompt

textscr

grtext

prin1

redraw

vports

grvecs

princ

terpri

The prin1, princ, print, and prompt functions are the primary text output functions and are described in “AutoLISP Basics.” The terpri and vports functions are described in the “AutoLISP Function Reference”.

Controlling Menus The menucmd function controls the display of the graphics window menus. It displays, modifies, or queries one of the submenus of the current menu, and accepts a string argument that specifies the submenu and the action to perform on that submenu. The menucmd function takes a string argument that consists of two fields, separated by an equal sign, in the following form: "menu_area=action"

Display Control

70

This syntax can load a submenu into a specified menu area, or perform an action on a menu item or a currently loaded menu area. The menu_area field specifies which part of the menu is to receive the action. This field can specify a menu area, such as P0 (for the cursor menu) or S (for the screen menu), or a specific menu item. The action field specifies the action to perform on the menu area or menu item, or a submenu to load into the menu area. The menu areas that can receive an action are the same as those used in menu file submenu references. Every menu area has a currently loaded submenu. By default the first submenu following a menu section label is loaded into that menu area. If menu_area specifies a pull-down menu or image tile menu, action can be an asterisk (*). This causes the menu to displayed (pull-down menus and image tile menus are not automatically displayed when they are called). On Windows, only the P0 (cursor) menu and image tile menus are displayed with the asterisk. NOTE Do not include the dollar sign that introduces the similar instructions in a menu file in the string argument. Also, do not include the asterisks that precede submenu labels in the menu file in the action field of the string argument. The following menucmd function call causes the **OSNAP screen submenu defined in the current menu file to be displayed (assuming that the screen menu is currently enabled). (menucmd "S=OSNAP")

In Windows, you can reference the menu group. This can be useful if there may be multiple menus loaded that contain the same submenu name. The following code displays the **OSNAP screen submenu in the ACAD menu group. (menucmd "S=ACAD.OSNAP")

The menucmd function can load submenus into the BUTTONS and AUX menu areas. You might want your digitizer buttons to function differently depending on whether Tablet mode is On or Off. You could have two submenus defined in the ***BUTTONS1 section, **DIG-BUTTONS and **TAB-BUTTONS, and switch between them with the following code. (menucmd "B1=DIG-BUTTONS") (menucmd "B1=TAB-BUTTONS")

Chapter 3

71

Enables the DIG-BUTTONS submenu Enables the TAB-BUTTONS submenu

Using AutoLISP to Communicate with AutoCAD

The following code loads the ***POP0 menu into the P0 (cursor) menu area and displays it. (menucmd "P0=POP0") (menucmd "P0=*")

Loads the ***POP0 menu into the P0 menu area Displays it

If you are sure that the correct menu is loaded into a particular menu area, you do not need to specifically load it each time you want to display it. The following call displays the pull-down menu currently loaded in the P1 (first pull-down menu) location. (menucmd "P1=*")

Using "P1=*" without previously loading the menu can result in unexpected behavior. Although you can load virtually any menu at a pull-down or cursor menu location, it is best to use only menus specifically designed for that menu area. For example, if you have a submenu called **MORESTUFF, you can load it at the P1 location with the following code: (menucmd "P1=MORESTUFF") (menucmd "P1=*")

Loads the **MORESTUFF menu in the P1 menu location Displays it

This menu remains in this location until you replace it by loading another menu, as in the following: (menucmd "P1=POP1")

If your menu uses the disabling (graying-out) and marking features, you can retrieve and change the state of a menu label with the menucmd function. The following call retrieves the current state of the fourth label in the pull-down menu P2. (menucmd "P2.4=#?")

If disabled returns

"P2.4=~"

These function calls enable and disable that same label: (menucmd "P2.4=") (menucmd "P2.4=~")

Enables the label Disables the label

You can also place and remove marks to the left of menu labels. The previously described method of menu item handling works relatively well with a single static menu. However, it becomes unreliable when menu item locations change when you load multiple partial menu files. You can make use of the menu-group and name-tag features to keep track of menu items. Instead of specifying a menu item by its location in the menu file, you specify the menu group and name tag associated with the menu item.

Display Control

72

When you use the menu group to enable, disable, and mark menu labels, you must precede the group name with a G, as shown in the following examples. (menucmd "Gacad.ID_New=~") (menucmd "Gacad.ID_New=")

Disables the label Enables the label

Not only can an AutoLISP function enable and disable menu labels, it can also modify the text displayed in the label by placing a DIESEL string expression in the label itself. Because DIESEL accepts only strings as input, you can pass information to the DIESEL expression through a USERS1–5 system variable that has been set to a value returned by your function. You can use the menucmd function also to evaluate DIESEL string expressions within an AutoLISP function. The following routine returns the current time: (defun C:CTIME ( / ctim) (setq ctim (menucmd "M=$(edtime,$(getvar,date),H:MMam/pm)")) (princ (strcat "\nThe current time is " ctim )) (princ) )

Control of Graphics and Text Windows You can control the display of the graphics and text windows from an AutoLISP application. On single-screen AutoCAD installations a call to graphscr displays the graphics window, or to textscr displays the text window. Using these functions is equivalent to toggling the Flip Screen function key. The function textpage is like textscr, but textpage clears the text window before displaying the text window (as the AutoCAD STATUS and LIST commands do). The redraw function is similar to the AutoCAD REDRAW command but provides more control over what is displayed: it not only redraws the entire graphics area but can also specify a single object to be redrawn or undrawn (that is, blanked out). If the object is a complex object such as a polyline or block, redraw can draw (or undraw) either the entire object or its header. The redraw function can also highlight and unhighlight specified objects.

Chapter 3

73

Using AutoLISP to Communicate with AutoCAD

Control of Low-level Graphics AutoLISP provides functions that control the low-level graphics and allow direct access to the AutoCAD graphics screen and input devices. The grtext function displays text directly in the status or menu areas, with or without highlighting. The grdraw function draws a vector in the current viewport with control over color and highlighting. The grvecs function draws multiple vectors. NOTE Because these functions depend on code in AutoCAD, their operation can be expected to change from release to release. There is no guarantee that applications calling these functions will be upward compatible. Also, they depend on the current hardware configuration: in particular, applications that call grtext are not likely to work the same on all configurations unless the developer is very careful to use them as described and to avoid hardware-specific features. Finally, because they are low-level functions, they do almost no error reporting and can alter the graphics screen display unexpectedly (see the following example for a way to fix this). The following sequence restores the default graphics window display caused by incorrect calls to grtext, grdraw, or grvecs: (grtext) (redraw)

Restores standard text

Getting User Input Several functions enable an AutoLISP application to prompt the user for input of data. The user-input functions are as follows: entsel

getfiled

getpoint

nentsel

getangle

getint

getreal

nentselp

getcorner

getkword

getstring

getdist

getorient

initget

Getting User Input

74

The getxxx Functions Each user-input getxxx function pauses for data entry of the indicated type and returns the value entered. The application can specify an optional prompt to display before the function pauses. The following table lists the getxxx functions and the type of user input requested. Allowable input to the getxxx user-input functions Function name

Type of user input

getint

An integer value on the command line

getreal

A real or integer value on the command line

getstring

A string on the command line

getpoint

A point value on the command line or selected from the screen

getcorner

A point value (the opposite corner of a box) on the command line or selected from the screen

getdist

A real or integer value (of distance) on the command line or determined by selecting points on the screen

getangle

An angle value (in the current angle format) on the command line or based on selected points on the screen

getorient

An angle value (in the current angle format) on the command line or based on selected points on the screen

getkword

A predefined key word or its abbreviation on the command line

NOTE Although the getvar, getcfg and getenv functions begin with the letters g, e, and t, they are not user-input functions. The functions getint, getreal, and getstring pause for user input on the AutoCAD command line. They return a value only of the same type as that requested. The getpoint, getcorner, and getdist functions pause for user input on the command line or from points selected on the graphics screen. The getpoint and getcorner functions return 3D point values, and getdist returns a real value. Both getangle and getorient pause for input of an angle value on the command line or as defined by points selected on the graphics screen. For the

Chapter 3

75

Using AutoLISP to Communicate with AutoCAD

getorient function, the zero angle is always to the right: “East” or “3 o’clock.” For getangle, the zero angle is the value of ANGBASE, which can be set to any angle. Both getangle and getorient return an angle value (a

real) in radians measured counterclockwise from a base (zero angle), for getangle equal to ANGBASE, and for getorient to the right.

For example, ANGBASE is set to 90 degrees (north), and ANGDIR is set to 1 (clockwise direction for increasing angles). The following table shows what getangle and getorient return (in radians) for representative input values (in degrees). Possible return values from getangle and getorient Input (degrees)

getangle

getorient

0

0.0

1.5708

–90

1.5708

3.14159

180

3.14159

4.71239

90

4.71239

0.0

The getangle function honors the settings of ANGDIR and ANGBASE when accepting input. You can use getangle to obtain a rotation amount for a block insertion, because input of 0 degrees always returns 0 radians. The getorient function honors only ANGDIR. You use getorient to obtain angles such as the baseline angle for a text object. For example, given the preceding settings of ANGBASE and ANGDIR, for a line of text created at an angle of 0, getorient returns an angle value of 90. The user-input functions take advantage of the error-checking capability of AutoCAD. Trivial errors are trapped by AutoCAD and are not returned by the user-input function. A prior call to initget provides additional filtering

Getting User Input

76

capabilities, lessening the need for error checking. The getkword function pauses for the input of a key word or its abbreviation. Key words must be defined with the initget function before the call to getkword. All user-input functions (except getstring) can accept key word values in addition to the values they normally return, provided that initget has been called to define the key words. All user-input functions allow for an optional prompt argument. It is recommended that you use this argument rather than a prior call to the prompt or princ functions. If a prompt argument is supplied with the call to the userinput function, that prompt is reissued in the case of invalid user input. If no prompt argument is supplied and the user enters incorrect information, the following message appears at the AutoCAD prompt line: Try again: This can be confusing, because the original prompt may have scrolled out of the Command prompt area. NOTE The AutoCAD user cannot typically respond to a user-input function by entering an AutoLISP expression. If your AutoLISP routine makes use of the initget function, arbitrary keyboard input is permitted to certain functions that can allow an AutoLISP statement as response to an AutoLISP-implemented command.

Control of User-Input Function Conditions The initget function provides a level of control over the next user-input function call. The initget function establishes various options for use by the next entsel, nentsel, nentselp, or getxxx function (except getstring, getvar, and getenv). This function accepts two arguments, bits and string, both of which are optional. The bits argument specifies one or more control bits that enable or disable certain input values to the following user-input function call. The string argument can specify key words that the following user-input function call will recognize. The control bits and key words established by initget apply only to the next user-input function call. They are discarded afterward. The application doesn’t have to call initget a second time to clear special conditions.

Input Options for User-Input Functions The value of the bits argument restricts the types of user input to the following user-input function call. This reduces error checking. These are some of the available bit values: 1 disallows null input, 2 disallows input of 0 (zero), and 4 disallows negative input. If these values are used with a following call

Chapter 3

77

Using AutoLISP to Communicate with AutoCAD

to the getint function, the user is forced to enter an integer value greater than 0. To set more than one condition at a time, add the values together (in any combination) to create a bits value between 0 and 255. If bits is not included or is set to 0, none of the control conditions apply to the next user-input function call. (For a complete listing of initget bit settings, see “initget” in “AutoLISP Function Reference.”) (initget (+ 1 2 4)) (getint "\nHow old are you? ")

This sequence requests the user’s age. AutoCAD displays an error message and repeats the prompt if the user attempts to enter a negative or zero value, press ENTER only, or enter a string (the getint function rejects attempts to enter a value that is not an integer).

Key Word Options The optional string argument specifies a list of key words recognized by the next user-input function call. The initget function allows key word abbreviations to be recognized in addition to the full key words. The user-input function returns a predefined key word if the input from the user matches the spelling of a key word (not case sensitive), or if the user enters the abbreviation of a key word. There are two methods for abbreviating key words; both are discussed in “Key Word Specifications.” The following user-defined function shows a call to getreal, preceded by a call to initget, that specifies two key words. The application checks for these key words and sets the input value accordingly. (defun C:GETNUM (/ num) (initget 1 "Pi Two-pi") (setq num (getreal "Pi/Two-pi/: ")) (cond ((eq num "Pi") pi) ((eq num "Two-pi") (* 2.0 pi)) (T num) ) )

This initget call inhibits null input (bits = 1) and establishes a list of two key words, "Pi" and "Two-pi". The getreal function is then used to obtain a real number, issuing the following prompt: Pi/Two-pi/: The result is placed in local symbol num. If the user enters a number, that number is returned by C:GETNUM. However, if the user enters the key word Pi

Getting User Input

78

(or simply P), getreal returns the key word Pi. The cond function detects this and returns the value of p in this case. The Two-pi key word is handled similarly. NOTE You can also use initget to enable entsel, nentsel, and nentselp to accept key word input. For more information on these functions, see “Object Handling” and “entsel”, “nentsel”, and “nentselp” in the “AutoLISP Function Reference.”

Arbitrary Keyboard Input The initget function also allows arbitrary keyboard input to most getxxx functions. This input is passed back to the application as a string. An application using this facility can be written to permit the user to call an AutoLISP function at a getxxx function prompt. These functions show a method for allowing AutoLISP response to a getxxx function call: (defun C:ARBENTRY ( / pt1) (initget 128) ; Sets arbitrary entry bit (setq pt1 (getpoint "\nPoint: ")) ; Gets value from user. (if (= ’STR (type pt1)) ; If it’s a string, convert it (setq pt1 (eval (read pt1))) ; to a symbol, try evaluating ; it as a function; otherwise, pt1 ; just return the value. ) ) (defun REF ( ) (setvar "LASTPOINT" (getpoint "\nReference point: ")) (getpoint "\nNext point: " (getvar "LASTPOINT")) )

If both the C:ARBENTRY and REF functions are loaded into the drawing, the following command sequence is acceptable. Command: arbentry Point: (ref) Reference point: Select a point Next point: @1,1,0

Input Validation You should protect your code from unintentional user errors. The AutoLISP user input getxxx functions do much of this for you. However, it’s dangerous to forget to check for adherence to other program requirements that the getxxx functions do not check for. If you neglect to check input validity, the program’s integrity can be seriously affected.

Chapter 3

79

Using AutoLISP to Communicate with AutoCAD

Geometric Utilities A group of functions allow applications to obtain pure geometric information and geometric data from the drawing. The geometric utility functions are as follows: angle

inters

polar

distance

osnap

textbox

The angle function finds the angle in radians between a line and the X axis (of the current UCS), distance finds the distance between two points, and polar finds a point by means of polar coordinates (relative to an initial point). The inters function finds the intersection of two lines. The osnap and textbox functions are described separately. The following code fragment shows calls to the geometric utility functions: (setq (setq (setq (setq

pt1 ’(3.0 6.0 0.0)) pt2 ’(5.0 2.0 0.0)) base ’(1.0 7.0 0.0)) rads (angle pt1 pt2))

(setq len (setq endpt

(distance pt1 pt2))

Angle in XY plane of current UCS (value is returned in radians) Distance in 3D space

(polar base rads len))

The call to polar sets endpt to a point that is the same distance from (1,7) as pt1 is from pt2, and at the same angle from the X axis as the angle between pt1 and pt2.

Object Snap The osnap function can find a point by using one of the AutoCAD Object Snap modes. The Snap modes are specified in a string argument. The following call to osnap looks for the midpoint of an object near pt1: (setq pt2 (osnap pt1 "midp"))

The following call looks for the midpoint, the endpoint, or the center of an object nearest pt1: (setq pt2 (osnap pt1 "midp,endp,center"))

In both examples, pt2 is set to the snap point if one is found that fulfills the osnap requirements. If more than one snap point fulfills the requirements, the point is selected based on the setting of the SORTENTS system variable. Otherwise, pt2 is set to nil.

Geometric Utilities

80

NOTE The APERTURE system variable determines the allowable proximity of a selected point to an object when you use Object Snap.

Text Extents The textbox function returns the diagonal coordinates of a box that encloses a text object. It takes an entity definition list of the type returned by entget (an association list of group codes and values) as its single argument. This list can contain a complete association list description of the text object or just a list describing the text string. The points returned by textbox describe the bounding box (an imaginary box that encloses the text object) of the text object as if its insertion point were located at (0,0,0) and its rotation angle were 0. The first list returned is the point (0.0 0.0 0.0) unless the text object is oblique or vertical or it contains letters with descenders (such as g and p). The value of the first point list specifies the offset distance from the text insertion point to the lower-left corner of the smallest rectangle enclosing the text. The second point list specifies the upper-right corner of that box. The returned point lists always describe the bottom-left and upper-right corners of this bounding box, regardless of the orientation of the text being measured. The following example shows the minimum allowable entity definition list that textbox accepts. Because no additional information is provided, textbox uses the current defaults for text style and height. Command: (textbox ’((1 . "Hello world")) ) ((0.0 0.0 0.0) (2.80952 1.0 0.0)) The actual values returned by textbox will vary depending on the current text style.

Chapter 3

81

Using AutoLISP to Communicate with AutoCAD

The following example demonstrates one method of providing the textbox function with an entity definition list. Command: dtext Justify/Style/: 1,1 Height : ENTER Rotation angle : ENTER Text: test Text: ENTER Command: (setq e (entget (entlast))) ((-1 . ) (0 . "TEXT") (8 . "0") (10 1.0 1.0 0.0) (40 . 1.0) (1 . "test") (50 . 0.0) (41 . 1.0)(51 . 0.0) (7 . "STANDARD") (71 . 0) (72 . 0) (11 0.0 0.0 0.0) (210 0.0 0.0 1.0) (73 . 0)) Command: (textbox e) ((0.0 0.0 0.0) (0.8 0.2 0.0)) The following figure shows the results of applying textbox to a text object with a height of 1.0. The figure also shows the baseline and insertion point of the text.

Points returned by textbox

If the text is vertical or rotated, pt1 is still the bottom-left corner and pt2 is the upper-right corner; the bottom-left point may have negative offsets if necessary. The following figure shows the point values (pt1 and pt2) that textbox returns for samples of vertical and aligned text. In both samples, the height of the letters is 1.0. (For the aligned text, the height is adjusted to fit the alignment points.)

Geometric Utilities

82

pt2 = 1.0,0.0

Vertical and aligned text

insertion point: (0,0)

When using vertical text styles, the points are still returned in left-to-right, bottom-to-top order as they are for horizontal styles, so the first point list will contain negative offsets from the text insertion point. Regardless of the text orientation or style, the points returned by textbox are such that the text insertion point (group code 10) directly translates to the origin point of the Object Coordinate System (OCS) for the associated text object. This point can be referenced when translating the coordinates returned from textbox into points that define the actual extents of the text. The two sample routines that follow use textbox to place a box around selected text regardless of its orientation. The first routine uses the textbox function to draw a box around a selected text object.

pt1 = –0.5,–20.0

(defun C:TBOX ( / textent tb ll ur ul lr) (setq textent (car (entsel "\nSelect text: "))) (command "ucs" "Object" textent) (setq tb (textbox (list (cons -1 textent))) ll (car tb) ur (cadr tb) ul (list (car ll) (cadr ur)) lr (list (car ur) (cadr ll)) ) (command "pline" ll lr ur ul "Close") (command "ucs" "p") (princ) )

The second routine, which follows, accomplishes the same task as the first routine by performing the geometric calculations with the sin and cos AutoLISP functions. The result is correct only if the current UCS is parallel to the plane of the text object.

Chapter 3

83

Using AutoLISP to Communicate with AutoCAD

(defun C:TBOX2 ( / textent ang sinrot cosrot t1 t2 p0 p1 p2 p3 p4) (setq textent (entget (car (entsel "\nSelect text: ")))) (setq p0 (cdr (assoc 10 textent)) ang (cdr (assoc 50 textent)) sinrot (sin ang) cosrot (cos ang) t1 (car (textbox textent)) t2 (cadr (textbox textent)) p1 (list (+ (car p0) (- (* (car t1) cosrot)(* (cadr t1) sinrot)) ) (+ (cadr p0) (+ (* (car t1) sinrot)(* (cadr t1) cosrot)) ) ) p2 (list (+ (car p0) (- (* (car t2) cosrot)(* (cadr t1) sinrot)) ) (+ (cadr p0) (+ (* (car t2) sinrot)(* (cadr t1) cosrot)) ) ) p3 (list (+ (car p0) (- (* (car t2) cosrot)(* (cadr t2) sinrot)) ) (+ (cadr p0) (+ (* (car t2) sinrot)(* (cadr t2) cosrot)) ) ) p4 (list (+ (car p0) (- (* (car t1) cosrot)(* (cadr t2) sinrot)) ) (+ (cadr p0) (+ (* (car t1) sinrot)(* (cadr t2) cosrot)) ) ) ) (command "pline" p1 p2 p3 p4 "c") (princ) )

Conversions The functions described in this section are utilities for converting data types and units. The conversion functions are as follows: angtof

atof

cvunit

rtos

Conversions

84

angtos

atoi

distof

ascii

chr

itoa

trans

String Conversions The functions rtos (real to string) and angtos (angle to string) convert numeric values used in AutoCAD to string values that can be used in output or as textual data. The rtos function converts a real value, and angtos converts an angle. The format of the result string is controlled by the value of AutoCAD system variables: the units and precision are specified by LUNITS and LUPREC for real (linear) values and by AUNITS and AUPREC for angular values. For both functions, the dimensioning variable DIMZIN controls how leading and trailing zeros are written to the result string. The following code fragments show calls to rtos and the values returned (assuming that the DIMZIN system variable equals 0). Precision (the third argument to rtos) is set to 4 places in the first call and 2 places in the others. (setq x 17.5) (setq str "\nValue formatted as ")

Chapter 3

85

(setq fmtval (rtos x 1 4)) (princ (strcat str fmtval))

Mode 1 = scientific displays Value formatted as 1.7500E+01

(setq fmtval (rtos x 2 2)) (princ (strcat str fmtval))

Mode 2 = decimal displays Value formatted as 17.50

(setq fmtval (rtos x 3 2)) (princ (strcat str fmtval))

Mode 3 = engineering displays Value formatted as 1’-5.50"

(setq fmtval (rtos x 4 2)) (princ (strcat str fmtval))

Mode 4 = architectural displays Value formatted as 1’-5 1/2"

(setq fmtval (rtos x 5 2)) (princ (strcat str fmtval))

Mode 5 = fractional displays Value formatted as 17 1/2

Using AutoLISP to Communicate with AutoCAD

When the UNITMODE system variable is set to 1, specifying that units are displayed as entered, the string returned by rtos differs for engineering (mode equals 3), architectural (mode equals 4), and fractional (mode equals 5) units. For example, the first two lines of the preceding sample output would be the same, but the last three lines would appear as follows: Value formatted as 1’5.50" Value formatted as 1’5-1/2" Value formatted as 17-1/2 Because the angtos function takes the ANGBASE system variable into account, the following code always returns "0". (angtos (getvar "angbase"))

There is no AutoLISP function that returns a string version (in the current mode/precision) of either the amount of rotation of ANGBASE from true zero (East) or an arbitrary angle in radians. To find the amount of rotation of ANGBASE from AutoCAD zero (East) or the size of an arbitrary angle, you can do one of the following: ■



Add the desired angle to the current ANGBASE, and then check to see if the absolute value of the result is greater than 2π (2 * pi). If so, subtract 2π; if the result is negative, add 2π. Then use the angtos function on the result. Store the value of ANGBASE in a temporary variable, set ANGBASE to 0, and evaluate the angtos function. Then set ANGBASE to its original value.

Subtracting the result of (atof (angtos 0)) from 360 degrees (2π radians or 400 grads) also yields the rotation of ANGBASE from 0. The distof (distance to floating point) function is the complement of rtos, so the following calls, which use the strings generated in the previous examples, all return the same value: 17.5. (Note the use of the backslash (\) with modes 3 and 4.) (distof "1.7500E+01" 1)

Mode 1 = scientific

(distof "17.50" 2)

Mode 2 = decimal

(distof "1’-5.50\"" 3)

Mode 3 = engineering

(distof "1’-5 1/2\"" 4)

Mode 4 = architectural

(distof "17 1/2" 5)

Mode 5 = fractional

Conversions

86

The following code fragments show similar calls to angtos and the values returned (still assuming that DIMZIN equals 0). Precision (the third argument to angtos) is set to 0 places in the first call, 4 places in the next three calls, and 2 places in the last. (setq ang 3.14159 str2 "\nAngle formatted as ") (setq fmtval (angtos ang 0 0)) (princ (strcat str2 fmtval))

Mode 0 = degrees displays Angle formatted as 180

(setq fmtval (angtos ang 1 4)) (princ (strcat str2 fmtval))

Mode 1 = deg/min/sec displays Angle formatted as 180d0’0"

(setq fmtval (angtos ang 2 4) (princ (strcat str2 fmtval))

Mode 2 = grads displays Angle formatted as 200.0000g

(setq fmtval (angtos ang 3 4) (princ (strcat str2 fmtval))

Mode 3 = radians displays Angle formatted as 3.1416r

(setq fmtval (angtos ang 4 2) (princ (strcat str2 fmtval))

Mode 4 = surveyor’s displays Angle formatted as W

The UNITMODE system variable also affects strings returned by angtos when it returns a string in surveyor’s units (mode equals 4). If UNITMODE equals 0, the string returned can include spaces (for example, "N 45d E"); if UNITMODE equals 1, the string contains no spaces (for example, "N45dE"). The angtof function complements angtos, so all of the following calls return the same value: 3.14159. (angtof (angtof (angtof (angtof (angtof

"180" 0) "180d0’0\"" 1) "200.0000g" 2) "3.14159r" 3) "W" 4)

Mode 0 = degrees Mode 1 = deg/min/sec Mode 2 = grads Mode 3 = radians Mode 4 = surveyor’s

When you have a string specifying a distance in feet and inches, or an angle in degrees, minutes, and seconds, you must precede the quotation mark with a backslash (\") so that it doesn’t look like the end of the string. The preceding examples of angtof and distof demonstrate this.

Angular Conversion If your application needs to convert angular values from radians to degrees, you could use the angtos function, which returns a string, and then convert that string into a floating point value with atof. (setq pt1 ’(1 1) pt2 ’(1 2)) (setq rad (angle pt1 pt2)) (setq deg (atof (angtos rad 0 2)))

Chapter 3

87

Using AutoLISP to Communicate with AutoCAD

returns

90.0

However, a more efficient method might be to include a Radian->Degrees function in your application. The following code shows this. ; Convert value in radians to degrees (defun Radian->Degrees (nbrOfRadians) (* 180.0 (/ nbrOfRadians pi)) )

After this function is defined, you can use the Radian->Degrees function throughout your application, as in (setq degrees (Radian->Degrees rad))

returns

90.0

You may also need to convert from degrees to radians. The following code shows this. ; Convert value in degrees to radians (defun Degrees->Radians (numberOfDegrees) (* pi (/ numberOfDegrees 180.0)) ) ;_ end of defun

ASCII Code Conversion AutoLISP provides the ascii and chr functions that handle decimal ASCII codes. The ascii function returns the ASCII decimal value associated with a string, and chr returns the character associated with an ASCII decimal value. To see your system’s characters with their codes in decimal, octal, and hexadecimal form, save the following AutoLISP code to a file named ascii.lsp. Then load the file and enter the new ASCII command at the Command prompt. This command prints the ASCII codes to the screen and to a file called ascii.txt. The C:ASCII function makes use of another function BASE. You may find this conversion utility useful in other applications. ; BASE converts from a decimal integer to a string in another base (defun BASE ( bas int / ret yyy zot ) (defun zot ( i1 i2 / xxx ) (if (> (setq xxx (rem i2 i1)) 9) (chr (+ 55 xxx)) (itoa xxx) ) ) (setq ret (zot bas int) yyy (/ int bas)) (while (>= yyy bas) (setq ret (strcat (zot bas yyy) ret)) (setq yyy (/ yyy bas)) ) (strcat (zot bas yyy) ret) )

Conversions

88

(defun C:ASCII ( / chk out ct code dec oct hex ) (initget "Yes") (setq chk (getstring "\nWriting to ASCII.TXT, continue? : ")) (if (or (= chk "Yes")(= chk "")) (progn (setq out (open "ascii.txt" "w") chk 1 code 0 ct 0) (princ "\n \n CHAR DEC OCT HEX \n") (princ "\n \n CHAR DEC OCT HEX \n" out) (while chk (setq dec (strcat " " (itoa code)) oct (base 8 code) hex (base 16 code)) (setq dec (substr dec (- (strlen dec) 2) 3)) (if (< (strlen oct) 3)(setq oct (strcat "0" oct))) (princ (strcat "\n " (chr code) " " dec " " oct " " hex ) ) (princ (strcat "\n " (chr code) " " dec " " oct " " hex ) out) (cond ((= code 255)(setq chk nil)) ((= ct 20) (setq xxx (getstring "\n \nPress ’X’ to eXit or any key to continue: ")) (if (= (strcase xxx) "X") (setq chk nil) (progn (setq ct 0) (princ "\n \n CHAR DEC OCT HEX \n") ) ) ) ) (setq ct (1+ ct) code (1+ code)) ) (close out) (setq out nil) ) ) (princ) )

Unit Conversion The file acad.unt defines various conversions between real-world units such as miles to kilometers, Fahrenheit to Celsius, and so on. The function cvunit takes a value expressed in one system of units and returns the equivalent value in another system. The two systems of units are specified by strings containing expressions of units defined in acad.unt. The cvunit function does not convert incompatible dimensions. For example, it does not convert inches into grams.

Chapter 3

89

Using AutoLISP to Communicate with AutoCAD

The first time that cvunit converts to or from a unit during a drawing editor session, it must look up the string that specifies the unit in acad.unt. If your application has many values to convert from one system of units to another, it is more efficient to convert the value 1.0 by a single call to cvunit and then use the returned value as a scale factor in subsequent conversions. This works for all units defined in acad.unt, except temperature scales, which involve an offset as well as a scale factor.

Converting from Inches to Meters If the current drawing units are engineering or architectural (feet and inches), the following routine converts a user-specified distance of inches into meters: (defun C:I2M ( / eng_len metric_len eng metric) (princ "\nConverting inches to meters. ") (setq eng_len (getdist "\nEnter a distance in inches: ")) (setq metric_len (cvunit eng_len "inches" "meters")) (setq eng (rtos eng_len 2 4) metric (rtos metric_len 2 4)) (princ (strcat "\n\t" eng " inches = " metric " meters.")) (princ) )

The Unit Definition File With the AutoCAD unit definition file acad.unt, you can define factors to convert data in one set of units to another set of units. The definitions in acad.unt are in ASCII format and are used by the unit-conversion function cvunit. You can make new units available by using a text editor to add their definitions to acad.unt. A definition consists of two lines in the file—the unit name and the unit definition. The first line must have an asterisk (*) in the first column, followed by the name of the unit. A unit name can have several abbreviations or alternate spellings, separated by commas. If a unit name has singular and plural forms, you can specify these using the following format: *[ [common] [ ( [singular.] plural) ] ]...

You can specify multiple expressions (singular and plural). They don’t have to be located at the end of the word, and a plural form isn’t required. *inch(es) *milleni(um.a) *f(oot.eet) or (foot.feet)

The line following the *unit name line defines the unit as either fundamental or derived.

Conversions

90

Fundamental Units A fundamental unit is an expression in constants. If the line following the *unit name line begins with something other than an equal sign (=), it defines fundamental units. It consists of five integers and two real numbers in the following form: c, e, h, k, m, r1, r2

The five integers correspond to the exponents of these five constants: c

velocity of light in a vacuum

e

electron charge

h

Planck’s constant

k

Boltzman’s constant

m

electron rest mass

As a group, these exponents define the dimensionality of the unit: length, mass, time, volume, and so on. The first real number (r1) is a multiplier, and the second (r2) is an additive offset (used only for temperature conversions). The fundamental unit definition allow for different spellings of the unit (for example, meter and metre); the case of the unit is ignored. An example of a fundamental unit definition is as follows. *meter(s),metre(s),m -1,0,1,0,-1,4.1214856408e11,0

In this example, the constants that make one meter are 1  1--- × h × ---- × ( 4.1214856 × 10 11 ) c m Derived Units A derived unit is defined in terms of other units. If the line following the *unit name line begins with an equal sign (=), it defines derived units. Valid operators in these definitions are * (multiplication), / (division), + (addition), – (subtraction), and ^ (exponentiation). You can specify a predefined unit by naming it, and you can use abbreviations (if provided). The items in a formula are multiplied together unless some other arithmetic operator is specified. For example, the units database defines the dimensionless multiple and submultiple names, so you can specify a unit such as “micro-inches” by entering micro inch. The following are examples of derived unit definitions.

Chapter 3

91

Using AutoLISP to Communicate with AutoCAD

; Units of area *township(s) =93239571.456 meter^2

The definition of a township is given as 93,239,571.456 square meters. ; Electromagnetic units *volt(s),v =watt/ampere

In this example, a volt is defined as a watt divided by an ampere. In the acad.unt, both watts and amperes are defined in terms of fundamental units. User Comments To include comments, begin the line with a semicolon. The comment continues to the end of the line. ; This entire line is a comment

List the acad.unt file itself for more information and examples.

Coordinate System Transformations The trans function translates a point or a displacement from one coordinate system into another. It takes a point argument, pt, that can be interpreted as either a three-dimensional (3D) point or a 3D displacement vector, distinguished by a displacement argument called disp. The disp argument must be nonzero if pt is to be treated as a displacement vector; otherwise, pt is treated as a point. A from argument specifies the coordinate system in which pt is expressed, and a to argument specifies the desired coordinate system. The following is the syntax for the trans function. (trans pt from to [disp])

The following AutoCAD coordinate systems can be specified by the from and to arguments. WCS

World Coordinate System: the “reference” coordinate system. All other coordinate systems are defined relative to the WCS, which never changes. Values measured relative to the WCS are stable across changes to other coordinate systems.

UCS

User Coordinate System: the “working” coordinate system. The user specifies a UCS to make drawing tasks easier. All points passed to AutoCAD commands, including those returned from AutoLISP routines and external functions, are points in the current UCS (unless the user precedes them with a * at the Command prompt). If you want your

Conversions

92

application to send coordinates in the WCS, OCS, or DCS to AutoCAD commands, you must first convert them to the UCS by calling the trans function. OCS

Object Coordinate System: point values returned by entget are expressed in this coordinate system, relative to the object itself. These points are usually converted into the WCS, current UCS, or current DCS, according to the intended use of the object. Conversely, points must be translated into an OCS before they are written to the database by means of entmod or entmake. This is also known as the Entity Coordinate System.

DCS

Display Coordinate System: the coordinate system into which objects are transformed before they are displayed. The origin of the DCS is the point stored in the AutoCAD system variable TARGET, and its Z axis is the viewing direction. In other words, a viewport is always a plan view of its DCS. These coordinates can be used to determine where something will be displayed to the AutoCAD user. When the from and to integer codes are 2 and 3, in either order, 2 indicates the DCS for the current model space viewport and 3 indicates the DCS for paper space (PSDCS). When the 2 code is used with an integer code other than 3 (or another means of specifying the coordinate system), it is assumed to indicate the DCS of the current space, whether paper space or model space. The other argument is also assumed to indicate a coordinate system in the current space.

PSDCS

Chapter 3

93

Paper Space DCS: this coordinate system can be transformed only to or from the DCS of the currently active model space viewport. This is essentially a 2D transformation, where the X and Y coordinates are always scaled and are offset if the disp argument is 0. The Z coordinate is scaled but is never translated; therefore, it can be used to find the scale factor between the two coordinate systems. The PSDCS (integer code 2) can be transformed only into the current model space viewport: if the from argument equals 3, the to argument must equal 2, and vice versa.

Using AutoLISP to Communicate with AutoCAD

Both the from and to arguments can specify a coordinate system in any of the following ways: ■ ■



As an integer code that specifies the WCS, current UCS, or current DCS (of either the current viewport or paper space). As an entity name returned by one of the entity name or selection set functions described in “Using AutoLISP to Manipulate AutoCAD Objects”. This specifies the OCS of the named object. For planar objects, the OCS can differ from the WCS, as described in the AutoCAD User’s Guide. If the OCS does not differ, conversion between OCS and WCS is an identity operation. As a 3D extrusion vector. Extrusion vectors are always represented in World coordinates; an extrusion vector of (0,0,1) specifies the WCS itself.

The following table lists the valid integer codes that can be used as the to and from arguments.

Coordinate system codes Code

Coordinate system

0

World (WCS)

1

User (current UCS)

2

Display; DCS of current viewport when used with code 0 or1 DCS of current model space viewport when used with code 3

3

Paper space DCS, PSDCS (used only with code 2)

The following example translates a point from the WCS into the current UCS. (setq pt ’(1.0 2.0 3.0)) (setq cs_from 0) (setq cs_to 1) (trans pt cs_from cs_to 0)

WCS UCS disp = 0 indicates that pt is a point

If the current UCS is rotated 90 degrees counterclockwise around the World Z axis, the call to trans returns a point (2.0,–1.0,3.0). However, if you swap the to and from values, the result differs as shown in the following code. (trans pt cs_to cs_from 0) ; the result is

(–2.0,1.0,3.0)

Point Transformations If you are doing point transformations with the trans function and you need to make that part of a program run faster, you can construct your own

Conversions

94

transformation matrix on the AutoLISP side by using trans once to transform each of the “basis vectors” (0 0 0), (1 0 0), (0 1 0), and (0 0 1). Writing matrix multiplication functions in AutoLISP can be difficult, so it might not be worthwhile unless your program is doing a lot of transformations.

File Handling AutoLISP provides functions for handling files and data I/O. The file-handling functions are as follows: close

help

read-line

findfile

open

setfunhelp

getfiled

read-char

write-char

write-line

Examples of the findfile, getfiled, and help functions are provided in this section. The other file handling functions are described in “AutoLISP Function Reference.”

File Search An application can use the findfile function to search for a particular file name. The application can specify the directory to search, or it can use the current AutoCAD library path. In the following code fragment, findfile searches for the requested file name according to the AutoCAD library path: (setq refname "refc.dwg") (setq fil (findfile refname)) (if fil (setq refname fil) (princ (strcat "\nCould not find file " refname ". " )) )

If the call to findfile is successful, the variable refname is set to a fully qualified path name string, such as "/home/work/ref/refc.dwg"

NOTE When specifying a path name, you must precede the backslash (\) with another backslash so that the path name will be recognized by AutoLISP. Alternatively, you can use the slash character (/) as a directory separator.

Chapter 3

95

Using AutoLISP to Communicate with AutoCAD

The getfiled function displays a dialog box containing a list of available files of a specified extension type in the specified directory. This gives AutoLISP routines access to the AutoCAD Get File dialog box. A call to getfiled takes four arguments that determine the appearance and functionality of the dialog box. The application must specify the following string values, each of which can be nil: a title, placed at the top of the dialog; a default file name, displayed in the edit box at the bottom of the dialog; and an extension type, which determines the initial files provided for selection in the list box. The final argument is an integer value that specifies how the dialog interacts with selected files. This simple routine uses getfiled to let you view your directory structure and select a file: (defun C:DDIR ( ) (setq dfil (getfiled "Directory Listing" "" "" 2)) (princ (strcat "\nVariable ’dfil’ set to selected file " dfil )) (princ) )

This is a useful utility command. The variable dfil is set to the file you select, which can then be used by other AutoLISP functions or as a response to a command line prompt for a file name. To use this variable in response to a command line prompt, enter !dfil. NOTE line.

You cannot use !dfil in a dialog box. It is valid only at the command

For more information, see “getfiled”.

Accessing Help Files The help function provides access to both AutoCAD help files (.ahp) and Windows Help files (.hlp). Depending on the Help file’s extension, the help function calls the AutoCAD or the Windows help viewer with the specified file. You can use this function to add a help facility to your applications. The following code fragment calls the default AutoCAD help file and provides information on the LINE command. (help "" "line")

You can create a help file that provides information about your applications or about procedures that you use in your business. The following userdefined command displays your help file morehelp.ahp.

File Handling

96

(defun C:MYHELP ( ) (help "morehelp.ahp") (princ) )

See the AutoCAD Customization Guide for information on creating and modifying help files. The setfunhelp function provides help for user-defined commands. After the definition of your new command, adding a call to setfunhelp associates a specific help file and topic with that command. The following example assigns the help topic Mycmd in the file morehelp.ahp to the user-defined command MYCMD. (defun C:MYCMD ( ) . . Command definition . ) (setfunhelp c:mycmd "morehelp.ahp" "mycmd")

Device Access and Control AutoLISP provides functions for accessing data from the various input devices. The device access and control functions are as follows: grread

tablet

The following file-handling functions can also read input from the keyboard input buffer. (See the AutoCAD Customization Guide for more information on these functions.) read-char

read-line

Accessing User Input The grread function returns “raw” user input, whether from the keyboard or from the pointing device (mouse or digitizer); if the call to grread enables tracking, the function returns a digitized coordinate that can be used for such things as dragging. NOTE There is no guarantee that applications calling grread will be upward compatible. Because it depends on the current hardware configuration, applications that call grread are not likely to work in the same way on all configurations.

Chapter 3

97

Using AutoLISP to Communicate with AutoCAD

Calibrating Tablets AutoCAD users can calibrate a digitizing tablet by using the TABLET command (see the AutoCAD Command Reference for a description of this command). The tablet function enables applications to manage calibration by setting the calibrations directly and by saving those settings for future use. The first argument to the tablet function is an integer code. If code is equal to 0, the function returns the current calibration. If code is equal to 1, the calibration is set according to the remaining arguments. Calibrations are expressed as four 3D points (in addition to the code). The first three points— row1, row2, and row3—are the three rows of the tablet’s transformation matrix. The fourth point, direction, is a vector that is normal to the plane in which the tablet’s surface is assumed to lie (expressed in WCS, the World Coordinate System). When the calibration is set with the TABLET command, the tablet’s surface is assumed to lie in the XY plane of the current UCS. NOTE The TABMODE system variable controls whether Tablet mode is turned on (1) or off (0). You can control it by using the setvar function. The following sample routine retrieves the current tablet calibration and stores it in the variable tcal. (defun C:TABGET ( ) (setq tcal (tablet 0)) (if tcal (princ (strcat "\nConfiguration saved, " "use TABSET to retrieve calibration.") ) (princ "\nCalibration not obtainable ") ) (princ) )

If the preceding routine was successful, the symbol tcal now contains the list returned by the tablet function. This list might appear as follows: (1 (0.00561717 -0.000978942 -7.5171) (0.000978942 0.00561717 -9.17308) (0.0 0.0 1.0) (0.0 0.0 1.0) )

Device Access and Control

98

To reset the calibration to the values retrieved by the preceding routine, you can use the C:TABSET routine. (defun C:TABSET ( ) (if (not (apply ’tablet tcal)) (princ "\nUnable to reset calibration. ") (progn (princ "\nTablet calibration reset. ") (setvar "tabmode" 1) (if (= (getvar "tabmode") 0) (princ "\nUnable to turn on tablet mode ") ) ) ) (princ) )

The transformation matrix passed as row1, row2, and row3 is a 3×3 transformation matrix that is meant to transform a two-dimensional point. The 2D point is expressed as a column vector in homogeneous coordinates (by appending 1.0 as the third element), so the transformation looks like this:

M 00 M 01 M 02 X X′ Y′ = M 10 M 11 M 12 ⋅ Y 1.0 D′ M 20 M 21 1.0 The calculation of a point is similar to the 3D case. AutoCAD transforms the point by using the following formulas:

X′ = M 00 X + M 01 Y + M 02 Y′ = M 10 X + M 11 Y + M 12 D′ = M 20 X + M 21 Y + 1.0 To turn the resulting vector back into a 2D point, the first two components are divided by the third component (the scale factor D’) yielding the point (X’/D’,Y’/D’). For projective transformations, the most general case, tablet does the full calculation. But for affine and orthogonal transformations, M20 and M21 are both 0, so D’ would be 1.0. The calculation of D’ and the division are omitted; the resulting 2D point is simply (X’,Y’).

Chapter 3

99

Using AutoLISP to Communicate with AutoCAD

As the previous paragraph implies, an affine transformation is a special, uniform case of a projective transformation. An orthogonal transformation is a special case of an affine transformation: not only are M20 and M21 zero, but M00 = M11 and M10 = –M01. NOTE When you set a calibration, the list returned does not equal the list provided if the direction isn’t normalized; AutoCAD normalizes the direction vector before it returns it. Also, it ensures that the third element in the third column (row3[Z]) is equal to 1. This situation should not arise if you set the calibration by using values retrieved from AutoCAD by means of tablet. However, it can happen if your program calculates the transformation itself.

Device Access and Control

100

Chapter 3

101

Using AutoLISP to Communicate with AutoCAD

4 Using AutoLISP to Manipulate AutoCAD Objects In this chapter

Most AutoLISP functions that handle selection sets and



Selection Set Handling



Object Handling



Extended Data— Xdata



Xrecord Objects



Symbol Table and Dictionary Access

objects identify a set or an object by its entity name. Before it can manipulate a selection set or object, an AutoLISP application must first obtain the current name by calling one of the functions that return a selection set or entity name. For selection sets, which are valid only in the current session, the volatility of names poses no problem, but it does for objects because they are saved in the drawing database. An application that must refer to the same objects in the same drawing (or drawings) at different times can use the objects’ handles.

102

AutoLISP uses symbol tables to maintain lists of graphic and nongraphic data related to a drawing, such as layers, linetypes, and block definitions. Each symbol table entry has a related entity name and handle and can be manipulated in a manner similar to the way that other AutoCAD entities are manipulated. NOTE The AutoLISP examples in this chapter show code entered from the AutoCAD Command prompt, not the Visual LISP Console.

Selection Set Handling AutoLISP provides functions for handling selection sets. The selection set–handling functions are as follows:

ssadd

ssget

ssmemb

ssdel

sslength

ssname

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: ■ ■ ■ ■

By explicitly specifying the objects to select, using the Last, Previous, Window, Implied, WPolygon, Crossing, CPolygon, or Fence options. By specifying a single point. By selecting the entire database. By prompting the user to select objects.

With either option, you can use filtering to specify a list of attributes and conditions that the selected objects must match. NOTE Selection set and entity names are volatile; that is, they apply only to the current drawing session. 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 don’t 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. The following table summarizes the available mode values and the arguments used with

Chapter 4

103

Using AutoLISP to Manipulate AutoCAD Objects

each. (A filter-list can be used as an additional argument to all of the selection methods listed.) Selection options for ssget Mode

Selection method

Prototypes

none

User selection or single-point selection (if pt1 is specified)

(ssget) or (ssget pt1)

"L"

Last created object visible on screen

(ssget "L")

NOTE If mode "X" is specified and a filter-list is not provided, ssget selects all entities in the database, including entities on layers that are off, frozen, and out of the visible screen. The following code shows calls to ssget. (setq pt1 pt2 pt3 pt4 ) (setq ss1

’(0.0 ’(5.0 ’(4.0 ’(2.0

0.0 5.0 1.0 6.0

0.0) 0.0) 0.0) 0.0)

(ssget))

Sets pt1, pt2, pt3, and pt4 to point values

Asks the user for a general object selection and places those items in a selection set

(setq ss1 (ssget "P"))

Creates a selection set of the most recently selected objects

(setq ss1 (ssget "L"))

Creates a selection set of the last object added to the database that is visible on the screen

(setq ss1 (ssget pt2))

Creates a selection set of an object passing through point (5,5)

(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 pt4))) Creates a selection set of the objects crossing the fence and defined by the points (4,1),

and (2,6) (setq ss1 (ssget "WP" (list pt1 pt2 pt3)))Creates a selection set of the objects inside the polygon defined by the point (0,0),(5,5), and (4,1) (setq ss1

(ssget "X"))

Creates a selection set of all objects in the database

Selection Set Handling

104

When an application has finished using a selection set, it is important to release it from memory. You can do this by setting it to nil. (setq ss1 nil)

NOTE 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 refuses to 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 gc before another ssget will work.

Selection Set Filter Lists 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 –1), handles (group 5), and xdata codes (groups greater than 1000). If an invalid group code is used in a filter-list, it is ignored by ssget. 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. 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 filter-list specifies which property (or properties) of the entities are to be checked and what values constitute a match. The following examples demonstrate methods of using a filter-list with various mode selection options. Prompts for general object selection but adds only text objects to the selection set

(setq ss1 (ssget ’((0 . "TEXT"))) )

Chapter 4

105

(setq ss1 (ssget "P" ’((0 . "LINE"))) )

Creates a selection set of the most recently selected objects that are also line objects

(setq ss1 (ssget "W" pt1 pt2 ’((8 . "FLOOR9"))) )

Creates a selection set of all objects inside the window that are also on layer FLOOR9

Using AutoLISP to Manipulate AutoCAD Objects

(setq ss1 (ssget "X" ’((0 . "CIRCLE"))) )

Creates a selection set of all objects in the database that are circle objects

If both the 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 functions). (setq lay_name "FLOOR3") (setq ss1 (ssget "X" (list (cons 8 lay_name)) ) )

Creates a selection set of all objects in the database that are on layer FLOOR3

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: (ssget "X"

(list

(cons 0 "CIRCLE")(cons 8 lay_name)(cons 62 1)))

This code selects only circle objects on layer FLOOR3 that are the color red. This type of test performs a Boolean AND operation. The ssget function filters a drawing 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 no entities from those selected 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 ssget returns. When ssget filters a drawing, the selection set 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.

Selection Set Handling

106

Wild-Card Patterns in Filter Lists Symbol names specified in filtering lists can include wild-card patterns. The wild-card patterns recognized by ssget are the same as those recognized by the function wcmatch, and are described in “Wild-Card Matching” on page 50 and under “wcmatch”. NOTE 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")))

Filtering for Extended Data Using the ssget filter-list, you can select all entities containing extended data for a particular application. To do this, use the –3 group code, as shown in the following example: (ssget "X" ’((0 . "CIRCLE") (-3 ("APPNAME"))))

This code would select all circles that include extended data for the "APPNAME" application. 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 circles with extended data for both the "APP1" and "APP2" applications. (ssget "X" ’((0 . "CIRCLE") (-3 ("APP1")("APP2"))))

Wild-card matching is permitted, so either of the following statements would select all circles with extended data for either or both of these applications. (ssget "X" ’((0 . "CIRCLE") (-3 ("APP[12]")))) (ssget "X" ’((0 . "CIRCLE") (-3 ("APP1,APP2"))))

Relational Tests Unless otherwise specified, an equivalency is implied for each item in the filter-list. For numeric groups (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 is a string indicating the test operator to be applied to the next group in the filter-list. For more information, see “Relational Tests” in “AutoLISP Function Reference.” 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)))

Chapter 4

107

Using AutoLISP to Manipulate AutoCAD Objects

Logical Grouping of Filter Tests You can also test groups by creating nested Boolean expressions that use the logical grouping operators shown under “Logical Grouping of Filter Tests” in the “AutoLISP Function Reference.” The grouping operators are specified by –4 groups, like the relational operators. They are paired and must be balanced correctly in the filter list or the ssget call will fail. An example of grouping operators in a filter list follows: (ssget "X" ’( (-4 . "") ) )

This code selects all circles with a radius of 1.0 plus all lines on layer "ABC". The grouping operators are not case sensitive. Grouping operators are not allowed within the –3 group itself. Multiple application names specified in a –3 group use an implied AND operator. If you want to test for extended data using other grouping operators, specify separate –3 groups and group them as desired. To select all circles having extended data for either application "APP1" or "APP2" but not both, enter the following: (ssget "X" ’((0 . "CIRCLE") (-4 . "") ) )

Selection Set Handling

108

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 ’(-4 . "XOR>") ) (ssget "X" (list ’(0 . "CIRCLE")

) )

As you can see, this method may not be sensible for short pieces of code but can be beneficial in larger applications.

Selection Set Manipulation Once a selection set has been created, you can add entities to it or remove entities from it with the functions ssadd and ssdel. You can use the ssadd function to create a new selection set, as shown in the following example. The following code fragment creates a selection set that includes the first and last entities in the current drawing (entnext and entlast are described later in this chapter). (setq fname (entnext)) (setq lname (entlast)) (if (not fname) (princ "\nNo entities in drawing. (progn (setq ourset (ssadd fname)) (ssadd lname ourset) ) )

Gets first entity in the drawing Gets last entity in the drawing ")

Creates a selection set of the first entity Adds the last entity to the selection set

The example runs correctly even if only one entity is in the database (in which case both entnext and entlast set their arguments to the same entity name). If ssadd is passed the name of an entity already in the selection set, it ignores the request and does not report an error. The following function removes the first entity from the selection set created in the previous example: (ssdel fname ourset)

If there is more than one entity in the drawing (that is, if fname and lname are not equal), then the selection set ourset contains only lname, the last entity in the drawing.

Chapter 4

109

Using AutoLISP to Manipulate AutoCAD Objects

The function sslength returns the number of entities in a selection set, and ssmemb tests whether a particular entity is a member of a selection set. Finally, the function ssname returns the name of a particular entity in a selection set, using an index to the set (entities in a selection set are numbered from 0). The following code shows calls to ssname: (setq sset (ssget)) Prompts the user to create a selection set (setq ent1 (ssname sset 0)) Gets the name of the first entity in sset (setq ent4 (ssname sset 3)) Gets the name of the fourth entity in sset (if (not ent4) (princ "\nNeed to select at least four entities. ") ) (setq ilast (sslength sset)) Finds index of the last entity in sset Gets the name of the last entity in sset (setq lastent (ssname sset (1- ilast)))

Regardless of how entities have been added to a selection set, the set never contains duplicate entities. If the same entity is added more than once, the later additions are ignored. Therefore, sslength accurately returns the number of distinct entities in the specified selection set.

Passing Selection Sets Between AutoLISP and ObjectARX Applications When passing selection sets between AutoLISP and ObjectARX applications, the following should be observed: If a selection set is created in AutoLISP and stored in an AutoLISP variable, then overwritten by a value returned from an ObjectARX application, the original selection set is eligible for garbage collection (it is freed at the next automatic or explicit garbage collection). This is true even if the value returned from the ObjectARX application was the original selection set. In the following example, if the adsfunc ObjectARX function returns the same selection set it was fed as an argument, then this selection set will be eligible for garbage collection even though it is still assigned to the same variable. (setq var1 (ssget)) (setq var1 (adsfunc var1))

If you want the original selection set to be protected from garbage collection, then you must not assign the return value of the ObjectARX application to the AutoLISP variable that already references the selection set. Changing the previous example as follows prevents the selection set referenced by var1 from being eligible for garbage collection: (setq var1 (ssget)) (setq var2 (adsfunc var1))

Selection Set Handling

110

Object Handling AutoLISP provides functions for handling objects. The object-handling functions are as follows:

entdel

entlast

entmod

entupd

entget

entmake

entnext

handent

The object-handling functions are organized into two categories: functions that retrieve the entity name of a particular object, and functions that retrieve or modify entity data.

Entity Name Functions To operate on an object, an AutoLISP application must obtain its entity name for use in subsequent calls to the entity data or selection set functions. Two of the functions described in this section, entsel and nentsel, return not only the entity’s name but also additional information for the application’s use. Both functions require the AutoCAD user to select an object interactively by picking a point on the graphics screen. All of the other entity name functions can retrieve an entity even if it is not visible on the screen or if it is on a frozen layer. The entsel function prompts the user to select an object by picking a point on the graphics screen, and entsel returns both the entity name and the value of the point selected. Some entity operations require knowledge of the point by which the object was selected. Examples from the set of existing AutoCAD commands include BREAK, TRIM, and EXTEND. These functions accept key words if they are preceded by a call to initget. The entnext function retrieves entity names sequentially. If entnext is called with no arguments, it returns the name of the first entity in the drawing database. If its argument is the name of an entity in the current drawing, entnext returns the name of the succeeding entity. The following code fragment illustrates how ssadd can be used in conjunction with entnext to create selection sets and add members to an existing set.

Chapter 4

111

Using AutoLISP to Manipulate AutoCAD Objects

(setq e1 (entnext)) (if (not e1) Sets e1 to name of first entity (princ "\nNo entities in drawing. ") (progn (setq ss (ssadd)) Sets ss to a null selection set (ssadd e1 ss) Returns selection set ss with e1 added (setq e2 (entnext e1)) Gets entity following e1 (ssadd e2 ss) Adds e2 to selection set ss ) )

The entlast function retrieves the name of the last entity in the database. The last entity is the most recently created main entity, so entlast can be called to obtain the name of an entity that has just been created with a call to command. You can set the entity name returned by entnext to the same variable name passed to this function. This “walks” a single entity name variable through the database, as shown in the following example: (setq one_ent (entnext))

Gets name of first entity

(while one_ent . . Processes new entity . (setq one_ent (entnext one_ent)) )

Value of one_ent is now nil

Entity Handles and Their Uses The handent function retrieves the name of an entity with a specific handle. As with entity names, handles are unique within a drawing; however, an entity’s handle is constant throughout its life. AutoLISP applications that manipulate a specific database can use handent to obtain the current name of an entity they must use. You can use the DDMODIFY command to get the handle of a selected object. The following code fragment uses handent to obtain and display an entity name. (if (not (setq e1 (handent "5a2"))) (princ "\nNo entity with that handle exists. ") (princ e1) )

In one particular editing session, this code fragment might display the following:

Object Handling

112

In another editing session with the same drawing, the fragment might display an entirely different number. But in both cases the code would be accessing the same entity. The handent function has an additional use. Entities that have been deleted from the database (with entdel, described in the following section) are not purged until the current drawing ends. This means that handent can recover the names of deleted entities, which can then be restored to the drawing by a second call to entdel. NOTE

Handles are provided for block definitions, including subentities.

Entities in drawings that are cross-referenced by way of XREF Attach are not actually part of the current drawing; their handles are unchanged but cannot be accessed by handent. However, when drawings are combined by means of INSERT, INSERT *, XREF Bind ( XBIND), or partial DXFIN, the handles of entities in the incoming drawing are lost, and incoming entities are assigned new handle values to ensure that each handle in the current drawing remains unique.

Entity Context and Coordinate Transform Data The nentsel and nentselp functions are similar to entsel, except that they return two additional values to handle entities nested within block references. Another difference between these functions is that when the user responds to a nentsel call by selecting a complex entity or a complex entity is selected by nentselp, these functions return the entity name of the selected subentity and not the complex entity’s header, as entsel does. For example, when the user selects a polyline, nentsel returns a vertex subentity instead of the polyline header. To retrieve the polyline header, the application must use entnext to walk forward to the seqend subentity, and then obtain the name of the header from the seqend subentity’s –2 group. The same applies when the user selects attributes in a nested block reference. The nentselp function is preferred to nentsel, because it returns a transformation matrix of the same format as that returned by grvecs. The first of the additional elements returned by nentsel is the Model to World Transformation Matrix. It is a list consisting of four sublists, each of which contains a set of coordinates. This matrix can be used to transform the entity definition data points from an internal coordinate system called the Model Coordinate System (MCS) to the WCS. The insertion point of the block (this refers to xrefs also) containing the selected object defines the origin of the MCS. The orientation of the UCS when the block is created determines the direction of the MCS axes.

Chapter 4

113

Using AutoLISP to Manipulate AutoCAD Objects

The second additional element is a list containing the entity name of the block that contains the selected object. If the selected object is contained in a nested block (a block within a block), the list also contains the entity names of all blocks in which the selected entity is nested, starting with the innermost block and continuing outward until the name of the outermost block that was inserted in the drawing is reported. ( (Px Py Pz) ( (X0 Y0 Z0) (X1 Y1 Z1) (X2 Y2 Z2) (X3 Y3 Z3) ) ( . . . ) )

Name of entity Pick point Model to World transformation matrix

Name of most deeply nested block containing selected object Name of outermost block containing selected object

In the following example, create a block to use with the nentsel function. Command: line From point: 1,1 to point: 3,1 to point: 3,3 to point: 1,3 to point: c Command: block Block name (or ?): square Insertion base point: 2,2 Select objects: Select the four lines you just drew Select objects: ENTER Then insert the block in a UCS rotated 45 degrees about the Z axis: Command: ucs Origin/ZAxis/3point/obJect/View/X/Y/Z/Prev/Restore/Save/Del/?/ : z Rotation angle about Z axis : 45 Command: insert Block name (or ?): square Insertion point: 7,0 X scale factor / Corner / XYZ: ENTER Y scale factor (default=X): ENTER Rotation angle: ENTER

Object Handling

114

Use nentsel to select the lower-left side of the square. (setq ndata (nentsel))

This code sets ndata equal to a list similar to the following: ( (6.46616 -1.0606 0.0) ((0.707107 0.707107 0.0) (-0.707107 0.707107 0.0) (0.0 -0.0 1.0) (4.94975 4.94975 0.0) ) () )

Entity name Pick point Model to World Transformation Matrix

Name of block containing selected object

Once you have obtained the entity name and the Model to World Transformation Matrix is obtained, you can transform the entity definition data points from the MCS to the WCS. Use entget and assoc on the entity name to obtain the desired definition points expressed in MCS coordinates. Then pass the points and the Model to World Transformation Matrix data (obtained in the first nentsel call) to the formulas that follow. If the selected entity is not a nested entity, the transformation matrix is set to the identity matrix. 1 0 0 0

0 1 0 0

0 0 1 0

The following equations show how to transform a point or vector.

X′ = XM 00 + YM 10 + ZM 20 + M 30 Y′ = XM 01 + YM 11 + ZM 21 + M 31 Z′ = XM 02 + YM 12 + ZM 22 + M 32 The Mij, where 0 ≤ i, j ≤ 2, are the Model to World Transformation Matrix coordinates; X, Y, and Z is the entity definition data point expressed in MCS coordinates; and X’, Y’, and Z’ is the resulting entity definition data point expressed in WCS coordinates. NOTE To transform a vector (rather than a point), do not add the translation vector [M30 M31 M32] (from the fourth column of the transformation matrix).

Chapter 4

115

Using AutoLISP to Manipulate AutoCAD Objects

The following example illustrates how to obtain the MCS start point of a line (group code 10) contained in a block definition. The statement stores the entity data (using the entity name obtained with nentsel earlier) in the symbol edata. It returns the following: (setq edata (assoc 10 (10 -1.0 1.0 0.0)

(entget

(car ndata))))

The following statement stores the Model to World Transformation Matrix sublist in the symbol matrix. (setq matrix (caddr ndata))

It returns the following: ((0.707107 0.707107 0.0) (-0.707107 0.707107 0.0) (0.0 -0.0 1.0) (4.94975 4.94975 0.0) )

X transformation Y transformation Z transformation Displacement from WCS origin

Apply the transformation formula for X’ to change the X coordinate of the start point of the line from an MCS coordinate to a WCS coordinate. Store the results in the symbol answer: (setq answer (+ (* (car (nth 0 matrix))(cadr edata)) (* (car (nth 1 matrix))(caddr edata)) (* (car (nth 2 matrix))(cadddr edata)) (car (nth 3 matrix)) ) )

add: M00 * X M10 * Y M20 * Z M30

This statement returns 3.53553, the WCS X coordinate of the start point of the selected line.

Entity Access Functions The entity access functions are relatively slow. It is best to get the contents of a particular entity (or symbol table entry) once and keep that information stored in memory, rather than repeatedly ask AutoCAD for the same data. Be sure that the data remains valid; if the user has an opportunity to alter the entity or symbol table entry, you should reissue the entity access function to ensure the validity of the data.

Entity Data Functions The functions described in this section operate on entity data and can be used to modify the current drawing database.

Object Handling

116

The entdel function deletes a specified entity. The entity is not purged from the database until the end of the current drawing session, so if the application calls entdel a second time during that session and specifies the same entity, the entity is undeleted. NOTE Attributes and polyline vertices cannot be deleted independently of their parent entities. The entdel function operates only on main entities. If you need to delete an attribute or vertex, you can use command to invoke the AutoCAD ATTEDIT or PEDIT commands. The entget function returns the definition data of a specified entity. The data is returned as a list. Each item in the list is specified by a DXF group code. The first item in the list contains the entity’s current name. In this example, the following (default) conditions apply to the current drawing: ■ ■ ■

Layer is 0 Linetype is CONTINUOUS Elevation is 0

The user has drawn a line with the following sequence of commands. Command: line From point: 1,2 To point: 6,6 To point: ENTER An AutoLISP application can retrieve and print the definition data for the line by using the following AutoLISP function: (defun C:PRINTDXF ( ) (setq ent (entlast)) (setq entl (entget ent)) (setq ct 0) (textpage) (princ "\nentget of last entity:") (repeat (length entl) (print (nth ct entl)) (setq ct (1+ ct)) ) (princ)

Sets ent to the last entity Sets entl to the last entity’s association list of the last entity Sets ct (a counter) to 0 Switches to the text screen Repeats for the number of members in the list Prints a newline and then each list member Increments the counter by one Exits quietly

)

Chapter 4

117

Using AutoLISP to Manipulate AutoCAD Objects

This would print the following: Results from entget of last entity: (–1 . ) (0 . "LINE") (8 . "0") (5 . "2D") (10 1.0 2.0 0.0) (11 6.0 6.0 0.0) (210 0.0 0.0 1.0) The first member of the list (–1) contains the name of the entity that this list represents. The entmod function, which is described in this section, uses it to identify the entity to be modified. The codes for the components of the entity are those used by DXF. As with DXF, the entity header items (color, linetype, thickness, the attributes-follow flag, and the entity handle) are returned only if they have values other than the default. Unlike DXF, optional entity definition fields are returned whether or not they equal their defaults and associated X, Y, and Z coordinates are returned as a single point variable rather than as separate X (10), Y (20), and Z (30) groups. The assoc function searches a list for a group of a specified type. The following code returns the object type "LINE" (0) from the list entl. (cdr (assoc 0 entl))

If the DXF group code specified is not present in the list (or if it is not a valid DXF group), assoc returns nil. The entmod function modifies an entity. It passes a list that has the same format as a list returned by entget but with some of the entity group values (presumably) modified by the application. This function complements entget. The primary mechanism by which an AutoLISP application updates the database is by retrieving an entity with entget, modifying its entity list, and then passing the list back to the database with entmod.

Object Handling

118

The following code fragment retrieves the definition data of the first entity in the drawing and changes its layer property to MYLAYER. (setq en (entnext)) Sets en to the first entity name in the drawing (setq ed (entget en)) Sets ed to the entity data for entity name en (setq ed (subst (cons 8 "MYLAYER") (assoc 8 ed) Changes the layer group in ed ed to layer MYLAYER ) ) (entmod ed) Modifies entity en’s layer in the drawing

There are restrictions on the changes to the database that entmod can make; entmode cannot change the following: ■ ■



The entity’s type or handle. Internal fields. (Internal fields are the values that AutoCAD assigns to certain group codes: –2, entity name reference; –1, entity name; 5, entity handle.) Any attempt to change an internal field—for example, the main entity name in a seqend subentity (group –2)—is ignored. Viewport entities. An attempt to change a viewport entity causes an error.

Other restrictions apply when modifying dimensions and hatch patterns. AutoCAD must recognize all objects (except layers) that the entity list refers to. The name of any text style, linetype, shape, or block that appears in an entity list must be defined in the current drawing before the entity list is passed to entmod. There is one exception: entmod accepts new layer names. If the entity list refers to a layer name that has not been defined in the current drawing, entmod creates a new layer. The attributes of the new layer are the standard default values used by the New option of the AutoCAD LAYER command. The entmod function can modify subentities such as polyline vertices and block attributes. NOTE If you use entmod to modify an entity in a block definition, this affects all INSERT or XREF references to that block. Also, entities in block definitions cannot be deleted by entdel. An application can also add an entity to the drawing database by calling the entmake function. Like that of entmod, the argument to entmake is a list whose format is similar to that returned by entget. The new entity that the list describes is appended to the drawing database (it becomes the last entity in the drawing). If the entity is a complex entity (a polyline or block), it is not appended to the database until it is complete.

Chapter 4

119

Using AutoLISP to Manipulate AutoCAD Objects

The following code fragment creates a circle on the layer MYLAYER. (entmake ’((0 . "CIRCLE") (8 . "MYLAYER") (10 5.0 7.0 0.0) (40 . 1.0) ) )

Object type Layer Center point Radius

The restrictions on entmake are similar to those for entmod: ■

■ ■ ■

The first or second member in the list must specify the object type. The type must be a valid DXF group code. If the first member does not specify the type, it can specify only the name of the entity: group –1 (the name is not saved in the database). AutoCAD must recognize all objects (except layers) that the entity list refers to. There is one exception: entmake accepts new layer names. Any internal fields passed to entmake are ignored. entmake cannot create viewport entities.

Both entmod and entmake perform the same consistency checks on the entity data passed to them as the DXFIN command performs when reading DXF files. They will fail if they cannot create valid drawing entities.

Working with Blocks There is no direct method for an application to check whether a block listed in the BLOCK table is actually referenced by an insert object in the drawing. You can use the following code to scan the drawing for instances of a block reference: (ssget "x" ’((2 . "BLOCKNAME")) )

You must also scan each block definition for instances of nested blocks.

Anonymous Blocks The block definitions (BLOCK) table in a drawing can contain anonymous blocks (also known as unnamed blocks), which AutoCAD creates to support hatch patterns and associative dimensioning. The entmake function can create anonymous blocks other than *Dnnn (dimensions) and *Xnnn (hatch patterns). Unreferenced anonymous blocks are purged from the BLOCK table at the beginning of each drawing session. Referenced anonymous blocks (those that have been inserted) are not purged. You can use entmake to create a block reference (insert object) to an anonymous block. (You cannot pass an anonymous block to the INSERT command.) Also, you can use entmake to redefine the block. You can modify the entities in a block (but not the block object itself) with entmod.

Object Handling

120

The name (group 2) of an anonymous block created by AutoLISP or ARX has the form *Unnn, where nnn is a number generated by AutoCAD. Also, the loworder bit of an anonymous block’s block type flag (group 70) is set to 1. When entmake creates a block whose name begins with * and whose anonymous bit is set, AutoCAD treats this as an anonymous block and assigns it a name. Any characters following the * in the name string passed to entmake are ignored. NOTE Anonymous block names do not remain constant. Although a referenced anonymous block becomes permanent, the numeric portion of its name can change between drawing sessions.

Creating Complex Entities To create a complex entity (a polyline or block), you make multiple calls to entmake, using a separate call for each subentity. When entmake first receives an initial component for a complex entity, it creates a temporary file in which to gather the definition data (and extended data, if that is present.). For each subsequent entmake call, the function checks to see if the temporary file exists. If it does, the new subentity is appended to the file. When the definition of the complex entity is complete (that is, when entmake receives an appropriate seqend or endblk subentity), the entity is checked for consistency; if it is valid, it is added to the drawing. The file is deleted when the complex entity is complete or when its creation has been cancelled. NOTE The entity does not appear in the drawing database until the final seqend or endblk subentity has been passed to entmake. Specifically, entlast cannot be used to retrieve the most recently created subentity for a complex entity that has not been completed. As the previous paragraphs imply, entmake can construct only one complex entity at a time. If a complex entity is being created and entmake receives invalid data or an entity that is not an appropriate subentity, both the invalid entity and the entire complex entity are rejected. You can explicitly cancel the creation of a complex entity by calling entmake with no arguments. The following example contains five entmake functions that create a single complex entity, a polyline. The polyline has a linetype of DASHED and a color of BLUE. It has three vertices located at coordinates (1,1,0), (4,6,0), and (3,2,0). All other optional definition data assume default values. (For this example to work properly, the linetype DASHED must be loaded.)

Chapter 4

121

Using AutoLISP to Manipulate AutoCAD Objects

(entmake ’((0 . "POLYLINE") (62 . 5) (6 . "dashed") (66 . 1) ) ) (entmake ’((0 . "VERTEX") (10 1.0 1.0 0.0) ) ) (entmake ’((0 . "VERTEX") (10 4.0 6.0 0.0) ) ) (entmake ’((0 . "VERTEX") (10 3.0 2.0 0.0) ) ) (entmake ’((0 . "SEQEND")))

Object type Color Linetype Vertices follow Object type Start point Object type Second point Object type Third point Sequence end

NOTE When defining dotted pairs, as in the above example, there must be a space on both sides of the dot. Otherwise you will get an invalid dotted pair error message. Block definitions begin with a block entity and end with an endblk subentity. Block definitions cannot be nested, nor can they reference themselves. A block definition can contain references to other block definitions. NOTE Before you use entmake to create a block, you should use tblsearch to ensure that the name of the new block is unique. The entmake function does not check for name conflicts in the block definitions table, so it can redefine existing blocks. Block references can include an attributes-follow flag (group 66). If present and equal to 1, a series of attribute (attrib) entities is expected to follow the insert object. The attribute sequence is terminated by a seqend subentity. Polyline entities always include a vertices-follow flag (also group 66). The value of this flag must be 1, and the flag must be followed by a sequence of vertex entities, terminated by a seqend subentity. Complex entities can exist in either model space or paper space but not both. If you have changed the current space by invoking either MSPACE or PSPACE (with command) while a complex entity is being constructed, a subsequent call to entmake cancels the complex entity. This can also occur if the subentity has a 67 group whose value does not match the 67 group of the entity header.

Object Handling

122

Entity Data Functions and the Graphics Screen Changes to the drawing made by the entity data functions are reflected on the graphics screen, provided that the entity being deleted, undeleted, modified, or made is in an area and on a layer that is currently visible. There is one exception to this: when entmod modifies a subentity, it does not update the image of the entire (complex) entity. If, for example, an application modifies 100 vertices of a complex polyline with 100 calls to entmod, the time required to recalculate and redisplay the entire polyline is unacceptably slow. Instead, an application can perform a series of subentity modifications and then redisplay the entire entity with a single call to the entupd function. Consider the following: If the first entity in the current drawing is a polyline with several vertices, the following code modifies the second vertex of the polyline and regenerates its screen image. (setq e1 (entnext)) (setq v1 (entnext e1)) (setq v2 (entnext v1)) (setq v2d (entget v2)) (setq v2d (subst ’(10 1.0 2.0 0.0) (assoc 10 v2d) v2d ) ) (entmod v2d) (entupd e1)

Sets e1 to the polyline’s entity name Sets v1 to its first vertex Sets v2 to its second vertex Sets v2d to the vertex data

Changes the vertex’s location in v2d to point (1,2,0) Moves the vertex in the drawing Regenerates the polyline entity e1

The argument to entupd can specify either a main entity or a subentity. In either case, entupd regenerates the entire entity. Although its primary use is for complex entities, entupd can regenerate any entity in the current drawing. NOTE To ensure that all instances of the block references are updated, you must regenerate the drawing by invoking the AutoCAD REGEN command (with command). The entupd function is not sufficient if the modified entity is in a block definition.

Polylines and Lwpolylines An lwpolyline is defined in the drawing database as a single graphic entity. This is different than a standard polyline, which is defined as a group of subentities. Lwpolylines display faster and consume less disk space and RAM.

Chapter 4

123

Using AutoLISP to Manipulate AutoCAD Objects

As of Release 14 of AutoCAD, 3D polylines are always created as standard polyline entities. 2D polylines are created as lwpolyline entities unless they have been curved or fitted with the PEDIT command. When a drawing from an earlier release is opened in Release 14 or a later release, all 2D polylines convert to lwpolylines automatically unless they have been curved or fitted or contain xdata.

Processing Curve-Fit and Spline-Fit Polylines When an AutoLISP application uses entnext to step through the vertices of a polyline, it might encounter vertices that were not created explicitly. Auxiliary vertices are inserted automatically by the PEDIT command’s Fit and Spline options. You can safely ignore them, because changes to these vertices will be discarded the next time the user uses PEDIT to fit or spline the polyline. The polyline entity’s group 70 flags indicate whether the polyline has been curve-fit (bit value 2) or spline-fit (bit value 4). If neither of these bits is set, all of the polyline’s vertices are regular user-defined vertices. However, if the curve-fit bit (2) is set, alternating vertices of the polyline have the bit value 1 set in their 70 group to indicate that they were inserted by the curve-fitting process. If you use entmod to move the vertices of such a polyline with the intent of refitting the curve by means of PEDIT, ignore these vertices. Likewise, if the polyline entity’s spline-fit flag bit (bit 4) is set, an assortment of vertices will be found—some with flag bit 1 (inserted by curve fitting if system variable SPLINESEGS was negative), some with bit value 8 (inserted by spline fitting), and all others with bit value 16 (spline frame-control point). Here again, if you use entmod to move the vertices and you intend to refit the spline afterward, move only the control-point vertices.

Nongraphic Object Handling AutoCAD uses two types of nongraphic objects, dictionary objects and symbol table objects. Although there are similarities between these object types, they are handled differently. All object types are supported by the entget, entmod, entdel and entmake functions, although object types individually dictate their participation in these functions and may refuse any or all processing. With respect to AutoCAD built-in objects, the following rules apply (all rules and restrictions that apply to graphic objects, apply to nongraphic objects as well). Nongraphic objects cannot be passed to the entupd function. When using entmake, the object type determines where the object will reside. For example, if a layer object is passed to entmake, it automatically goes to

Object Handling

124

the layer symbol table. If a graphic object is passed to entmake, it will reside in the current space (model or paper).

Symbol Table Objects The following rules apply to symbol tables: ■



■ ■ ■

Symbol table entries can be created through entmake with few restrictions other than being valid record representations, and name conflicts can only occur in the VPORT table. *ACTIVE entries can not be created. Symbol table and symbol table entry object state may be accessed with entget by passing the entity name. The tblobjname function can be used to retrieve the entity name of a symbol table entry. Symbol tables themselves can not be created with entmake, however, symbol table entries can be created with entmake. Handle groups (5, 105) may not be changed in entmod, nor specified in entmake. Symbol table entries can have many of their fields modified with entmod. To be passed to entmod, a symbol table record list must include its entity name, which can be obtained from entget but not from the tblsearch and tblnext functions. The 70 group of symbol table entries is ignored in entmod and entmake operations.

Renaming symbol table entries to duplicate names is not acceptable, except for the VPORT symbol table. The following entries may not be modified or renamed. Except that most LAYER entries can be renamed and xdata can be modified on all symbol table entries. Entries that cannot be modified or renamed table

entry name

VPORT

*ACTIVE

LINETYPE

CONTINUOUS

LAYER

Entries may not be modified, except for xdata, and renaming

The following entries may not be renamed, but are otherwise modifiable, subject to restriction Entries that cannot be renamed

Chapter 4

125

table

entry name

LAYER

0

Using AutoLISP to Manipulate AutoCAD Objects

Entries that cannot be renamed (continued) table

entry name

STYLE

STANDARD

DIMSTYLE

STANDARD

BLOCKS

*MODEL_SPACE

BLOCKS

*PAPER_SPACE

APPID

No entries may be renamed

Dictionary Objects The following rules apply to dictionary objects: ■

■ ■

Dictionary objects can be examined with entget and their xdata modified with entmod. Their entries cannot be altered with entmod. All access to their entries are made through the dictsearch and dictnext functions. Dictionary entry contents cannot be modified through entmod, although xdata can be modified. Dictionary entries that begin with ACAD* cannot be renamed.

Extended Data—Xdata Several AutoLISP functions are provided to handle extended data, which is created by applications written with ARX or Visual LISP. If an entity contains extended data, it follows the entity’s regular, definition data. The extended data-handling functions are as follows: regapp

xdroom

xdsize

You can retrieve an entity’s extended data by calling entget. The entget function retrieves an entity’s regular definition data and the extended data for those applications specified in the entget call.

Extended Data—Xdata

126

When extended data is retrieved with entget, the beginning of extended data is indicated by a –3 code. The –3 code is in a list that precedes the first 1001 group. The 1001 group contains the application name of the first application retrieved, as shown in the table and as described in the following sections.

Group Code

Field

(–1, –2 (0–239

Entity name) Regular definition data fields) . . .

Normal entity definition data

Extended data sentinel Registered application name 1)

Extended data

)

(–3 (1001 (1000, 1002–1071

XDATA fields) . . .

(1001 (1000, 1002–1071

Registered application name 2) XDATA fields) . . .

(1001

Registered application name 3) . .

Extended data

Organization of Extended Data Extended data consists of one or more 1001 groups, each of which begins with a unique application name. The extended data groups returned by entget follow the definition data in the order in which they are saved in the database.

Chapter 4

127

Using AutoLISP to Manipulate AutoCAD Objects

Within each application’s group, the contents, meaning, and organization of the data are defined by the application itself. AutoCAD maintains the information but doesn’t use it. The table also shows that the group codes for extended data are in the range 1000–1071. Many of these group codes are for familiar data types, as follows: String

1000. Strings in extended data can be up to 255 bytes long (with the 256th byte reserved for the null character).

Application name

1001 (also a string value). Application names can be up to 31 bytes long (the 32d byte is reserved for the null character) and must adhere to the rules for symbol table names (such as layer names). An application name can contain letters, digits, and the special characters $ (dollar sign), (hyphen), and _ (underscore). It cannot contain spaces. Letters in the name are converted to upper case.

Layer name

1003. Name of a layer associated with the extended data.

Database handle

1005. Handle of an entity in the drawing database.

3D point

1010. Three real values, contained in a point.

Real

1040. A real value.

Integer

1070. A 16-bit integer (signed or unsigned).

Long

1071. A 32-bit signed (long) integer. If the value that appears in a 1071 group is a short integer or real value, it is converted to a long integer; if it is invalid (for example, a string), it is converted to a long zero (0L).

NOTE AutoLISP manages 1071 groups as real values. If you use entget to retrieve an entity’s definition list that contains a 1071 group, the value is returned as a real, as shown in the following example: (1071 . 12.0) If you want to create a 1071 group in an entity with entmake or entmod, you can use either a real or an integer

value, as shown in the following example: (entmake (entmake (entmake (entmake

’((..... ’((..... ’((..... ’((.....

(1071 (1071 (1071 (1071

. . . .

12) .... ))) 12.0) .... ))) 65537.0) .... ))) 65537) .... )))

Extended Data—Xdata

128

But AutoLISP still returns the group value as a real: (entmake ’((..... (1071 . 65537) .... )))

The preceding statement returns the following: (1071 . 65537.0)

ARX always manages 1071 groups as long integers. Several other extended data groups have special meaning in this context (if the application chooses to use them): Control string

1002. An extended data control string can be either "{" or "}". These braces enable the application to organize its data by subdividing it into lists. The left brace begins a list, and the right brace terminates the most recent list. Lists can be nested.

NOTE If a 1001 group appears within a list, it is treated as a string and does not begin a new application group. Binary data

1004. Binary data that is organized into variable-length chunks, which can be handled in ObjectARX with the ads_binary structure. The maximum length of each chunk is 127 bytes.

NOTE AutoLISP cannot directly handle binary chunks, so the same precautions that apply to long (1071) groups apply to binary groups as well.

Chapter 4

129

World space position

1011. Unlike a simple 3D point, the WCS coordinates are moved, scaled, rotated, and mirrored along with the parent entity to which the extended data belongs. The WCS position is also stretched when the STRETCH command is applied to the parent entity and when this point lies within the select window.

World space displacement

1012. A 3D point that is scaled, rotated, or mirrored along with the parent, but not stretched or moved.

World direction

1013. A 3D point that is rotated or mirrored along with the parent, but not scaled, stretched or moved. The WCS direction is a normalized displacement that always has a unit length.

Distance

1041. A real value that is scaled along with the parent entity.

Scale factor

1042. Also a real value that is scaled along with the parent.

Using AutoLISP to Manipulate AutoCAD Objects

Registration of an Application To be recognized by AutoCAD an application must register the name or names that it uses. Application names are saved with the extended data of each entity that uses them, and also in the APPID table. Registration is done with the regapp function. The regapp function specifies a string to use as an application name. If it successfully adds the name to APPID, it returns the name of the application; otherwise it returns nil. A result of nil indicates that the name is already present in the symbol table. This is not an actual error condition but an expected return value, because the application name needs to be registered only once per drawing. To register itself, an application should first check that its name is not already in the APPID table. If the name is not there, the application must register it. Otherwise, it can simply go ahead and use the data, as described later in this section. The following fragment shows the typical use of regapp. (setq appname "MYAPP_2356") Unique application name (if (tblsearch "appid" appname) Checks if already registered (princ (strcat "\n" appname " already registered. ")) (if (= (regapp appname) nil) Some other problem (princ (strcat "\nCan’t register XDATA for " appname ". ")) ) )

NOTE The regapp function provides a measure of security, but it cannot guarantee that two separate applications have not chosen the same name. One way of ensuring this is to adopt a naming scheme that uses the company or product name and a unique number (like your telephone number or the current date and time).

Retrieval of Extended Data An application can call entget to obtain the extended data that it has registered. The entget function can return both the definition data and the extended data for the applications it requests. It requires an additional argument, application, that specifies the application names. The names passed to entget must correspond to applications registered by a previous call to regapp; they can also contain wild-card characters.

Extended Data—Xdata

130

By default, associative hatch patterns contain extended data. The following code shows the association list of this extended data. Command: (entget (car (entsel)) ’("ACAD")) Select object: Select an associative hatch Entering the preceding code at the command line returns a list that looks something like this: ((-1 . ) (0 . "INSERT") (8 . "0") (2 . "*X0") (10 0.0 0.0 0.0) (41 . 1.0) (42 . 1.0) (50 . 0.0) (43 . 1.0) (70 . 0) (71 . 0) (44 . 0.0) (45 . 0.0) (210 0.0 0.0 1.0) (-3 ("ACAD" (1000 . "HATCH") (1002 . "{") (1070 . 16) (1000 . "LINE") (1040 . 1.0) (1040 . 0.0) (1002 . "}")))) This fragment shows a typical sequence for retrieving extended data for two specified applications. Note that the application argument passes application names in list form. (setq working_elist (entget ent_name ’("MY_APP_1" "SOME_OTHER") ) ) (if working_elist (progn ... (entmod working_elist) ) )

Only extended data from "MY_APP_1" and "SOME_OTHER" is retrieved

Updates working entity groups Only extended data from registered applications still in the working_elist list are modified

As the sample code shows, you can modify extended data retrieved by entget by using a subsequent call to entmod, just as you use entmod to modify normal definition data. You can also create extended data by defining it in the entity list passed to entmake. Returning the extended data of only those applications specifically requested protects one application from corrupting another application’s data. It also controls the amount of memory that an application needs to use, and simplifies the extended data processing that an application needs to perform. NOTE Because the strings passed by application can include wild-card characters, an application name of "*" will cause entget to return all extended data attached to an entity.

Attachment of Extended Data to an Entity You can use extended data to store any type of information you want. The following is an example of attaching extended data to an entity.

Chapter 4

131

Using AutoLISP to Manipulate AutoCAD Objects

You must first draw an entity (such as a line or a circle) and then enter the following code: (setq lastent (entget (entlast)))Gets the association list of definition

data for the last entity (regapp "NEWDATA") Registers the application name (setq exdata Sets the variable exdata equal ’((-3 ("NEWDATA" to the new extended data— (1000 . "This is a new thing!")in this case a text string ))) ) (setq newent (append lastent exdata)) Appends the new data list to the entity’s list (entmod newent) Modifies the entity with the new

definition data To verify that your new extended data has been attached to the entity, enter the following code and select the object. (entget (car (entsel)) ’("NEWDATA"))

This example shows the basic method for attaching extended data to an entity.

Management of Extended Data Memory Use Extended data is currently limited to 16K per entity. Because the extended data of an entity can be created and maintained by multiple applications, problems can result when the size of the extended data approaches its limit. AutoLISP provides two functions, xdsize and xdroom, to assist in managing the memory that extended data occupies. When xdsize is passed a list of extended data, it returns the amount of memory (in bytes) that the data will occupy; when xdroom is passed the name of an entity, it returns the remaining number of free bytes that can still be appended to the entity. The xdsize function reads an extended data list, which can be large. This function can be slow, so it is not recommended that you call it frequently. A better approach is to use it (in conjunction with xdroom) in an error handler. If a call to entmod fails, you can use xdsize and xdroom to find out whether the call failed because the entity didn’t have enough room for the extended data.

Handles in Extended Data Extended data can contain handles (group 1005) to save relational structures within a drawing. One entity can reference another by saving the other’s handle in its extended data. The handle can later be retrieved from extended data and passed to handent to obtain the other entity. Because more than one entity can reference another, extended data handles are not necessarily

Extended Data—Xdata

132

unique. The AUDIT command does require that handles in extended data either be NULL or valid entity handles (within the current drawing). The best way to ensure that extended entity handles are valid is to obtain a referenced entity’s handle directly from its definition data by means of entget. The handle value is in group 5. When you reference entities in other drawings (for example, entities that are attached with XREF), you can avoid protests from AUDIT by using extended entity strings (group 1000) rather than handles (group 1005), because the handles of cross-referenced entities are either not valid in the current drawing or they conflict with valid handles. However, if an XREF Attach changes to an XREF Bind or is combined with the current drawing in some other way, it is up to the application to revise the entity references accordingly. When drawings are combined by means of INSERT, INSERT*, XREF Bind (XBIND), or partial DXFIN, handles are translated so that they become valid in the current drawing. (If the incoming drawing did not employ handles, new ones are assigned.) Extended entity handles that refer to incoming entities are also translated when these commands are invoked. When an entity is placed in a block definition (with the BLOCK command), the entity within the block is assigned new handles. (If the original entity is restored by means of OOPS, it retains its original handles.) The value of any extended data handles remain unchanged. When a block is exploded (with the EXPLODE command), extended data handles are translated, in a manner similar to the way they are translated when drawings are combined. If the extended data handle refers to an entity that is not within the block, it is unchanged. However, if the extended data handle refers to an entity that is within the block, the data handle is assigned the value of the new (exploded) entity’s handle.

Chapter 4

133

Using AutoLISP to Manipulate AutoCAD Objects

Xrecord Objects Xrecord objects are used to store and manage arbitrary data. They are composed of DXF group codes with "normal object" groups (that is, non-xdata group codes), ranging from 1 through 369 for supported ranges. This object is similar in concept to xdata but is not limited by size or order. Xrecord objects are designed to work in such a way as to not offend releases R13c0 through R13c3. However, if read into a pre-R13c4 level of AutoCAD, xrecord objects disappear. The following examples provide methods for creating and listing xrecord data. (defun C:MAKEXRECORD( / xrec xname ) ; create the xrecord’s data list (setq xrec ‘((0 . "XRECORD")(100 . "AcDbXrecord") (1 . "This is a test xrecord list") (10 1.0 2.0 0.0) (40 . 3.14159) (50 . 3.14159) (62 . 1) (70 . 180)) ) ; use entmakex to create the xrecord with no owner (setq xname (entmakex xrec)) ; add the new xrecord to the named object dictionary (dictadd (namedobjdict) "XRECLIST" xname) (princ) )

(defun C:LISTXRECORD ( / xlist ) ; find the xrecord in the named object dictionary (setq xlist (dictsearch (namedobjdict) "XRECLIST")) ; print out the xrecord’s data list (princ xlist) (princ) )

Symbol Table and Dictionary Access AutoLISP provides functions for accessing symbol table and dictionary entries. The symbol table and dictionary access functions are as follows:

dictsearch

namedobjdict

tblnext

tblsearch

Xrecord Objects

134

dictnext

snvalid

tblobjname

Examples of the tblnext and tblsearch functions are provided in this section. See “AutoLISP Function Reference” for information on the other symbol table and dictionary access functions.

Symbol Tables Symbol table entries can also be manipulated by the following functions:

entdel

entmake

entget

entmod

handent

The tblnext function sequentially scans symbol table entries, and the tblsearch function retrieves specific entries. Table names are specified by strings. The valid names are "LAYER", "LTYPE", "VIEW", "STYLE", "BLOCK", "UCS", "VPORT", "DIMSTYLE", and "APPID". Both functions return lists with DXF group codes that are similar to the entity data returned by entget. The first call to tblnext returns the first entry in the specified table. Subsequent calls that specify the same table return successive entries, unless the second argument to tblnext (rewind) is nonzero, in which case tblnext returns the first entry again. In the following example, the function GETBLOCK retrieves the symbol table entry for the first block (if any) in the current drawing, and then displays it in a list format.

Chapter 4

135

Using AutoLISP to Manipulate AutoCAD Objects

(defun C:GETBLOCK (/ blk ct) (setq blk (tblnext "BLOCK" 1)) Gets the first BLOCK entry (setq ct 0) Sets ct (a counter) to 0 (textpage) Switches to the text screen (princ "\nResults from GETBLOCK: ") (repeat (length blk) Repeats for the number of members in the list (print (nth ct blk)) Prints a new line and then each list member (setq ct (1+ ct)) Increments the counter by 1 ) (princ) Exits quietly )

Entries retrieved from the BLOCK table contain a –2 group that contains the name of the first entity in the block definition. If the block is empty, this is the name of the block’s ENDBLK entity, which is never seen on nonempty blocks. In a drawing with a single block named BOX, a call to GETBLOCK displays the following. (The name value varies from session to session). Results from GETBLOCK: (0 . "BLOCK") (2 . "BOX") (70 . 0) (10 9.0 2.0 0.0) (–2 . ) As with tblnext, the first argument to tblsearch is a string that names a table, but the second argument is a string that names a particular symbol in the table. If the symbol is found, tblsearch returns its data. This function has a third argument, setnext, that you can use to coordinate operations with tblnext. If setnext is nil, the tblsearch call has no effect on tblnext, but if setnext is non-nil, the next call to tblnext returns the table entry following the entry found by tblsearch. The setnext option is useful when you are handling the VPORT symbol table, because all viewports in a particular viewport configuration have the same name (such as *ACTIVE). If the VPORT symbol table is accessed when TILEMODE is turned off, any changes have no visible effect until TILEMODE turned on. Do not confuse VPORTS, which is described by the VPORT symbol table with paper space viewport entities.

Symbol Table and Dictionary Access

136

The following processes all viewports in the 4VIEW configuration. (setq v (tblsearch "VPORT" "4VIEW" T)) Finds first VPORT entry (while (and v (= (cdr (assoc 2 v)) "4VIEW")) . . ... Processes entry ... . (setq v (tblnext "VPORT")) Gets next VPORT entry )

Dictionary Entries A dictionary is a container object, similar to symbol tables in function. Dictionary entries can be queried with the dictsearch and dictnext functions. Each dictionary entry consists of a text name key plus a hard ownership handle reference to the entry object. Dictionary entries may be removed by directly passing entry object names to the entdel function. The text name key uses the same syntax and valid characters as symbol table names.

Accessing AutoCAD Groups The following is an example of one method for accessing the entities contained in a group. This example assumes that a group named G1 exists in the current drawing. (setq objdict (namedobjdict)) (setq grpdict (dictsearch objdict "ACAD_GROUP"))

This sets the variable grpdict to the entity definition list of the ACAD_GROUP dictionary and returns the following: ((-1 . ) (0 . "DICTIONARY") (5 . "D") (102 . "{ACAD_REACTORS") (330 . ) (102 . "}") (100 . "AcDbDictionary") (3 . "G1") (350 . )) The following code sets the variable group1 to the entity definition list of the G1 group. (setq group1 (dictsearch (cdar grpdict) "G1"))

It returns the following: ((-1 . ) (0 . "GROUP") (5 . "23") (102 . "{ACAD_REACTORS") (330 . ) (102 . "}") (100 . "AcDbGroup") (300 . "line and circle") (70 . 0) (71 . 1) (340 . )(340 . ) ) The 340 group codes are the entities that belongs to the group.

Chapter 4

137

Using AutoLISP to Manipulate AutoCAD Objects

5 Developing Programs With Visual LISP

In this chapter

Visual LISP provides a number of tools and features to help you develop AutoLISP programs. This chapter describes the features that help you enter AutoLISP text, format it to



The System Console



Using the Text Editor



Formatting Code



Checking for Syntax Errors



Running Your Program

improve readability, and detect syntax errors in your code.

138

Getting Organized Developing an AutoLISP program using Visual LISP involves the following tasks: 1 Thinking about what tasks you want to accomplish with your program, and how you might go about doing this 2 Designing the program 3 Writing the code 4 Formatting the code text for readability 5 Checking for errors in the program 6 Testing and debugging the program This chapter provides you with information you need in order to accomplish steps 3, 4 and 5. “Debugging Programs,” describes the debugging features of Visual LISP. “Building Applications,” and “Maintaining Visual LISP Applications,” describe how to package your programs into applications that can be run by other users, and how to organize application components to facilitate future updates.

The System Console Most of the programming you do in Visual LISP takes place within the confines of the VLISP text editor, but the ability to program interactively with AutoLISP provides some unique advantages to the development process. Using the Visual LISP System Console, you can enter AutoLISP code and immediately see the results of that code.

You enter text in the Console window following the Console prompt, which looks like the following: _$

Chapter 5

139

Developing Programs With Visual LISP

Visual LISP saves the text you enter, and any output it displays in response, so that you can scroll through the Console window and see what has previously transpired. You can copy any text in the window, and paste it following the Console prompt or in another Windows application.

System Console Behavior The Visual LISP System Console is similar in many respects to the AutoCAD command window, but it provides many additional features. And where the Console and the AutoCAD command window provide similar capabilities, you don’t always accomplish tasks in the same exact way. For example, to display the current value of an AutoLISP variable in Visual LISP, you simply type the variable name in the Console window and press ENTER. To view the value of a variable in AutoCAD, you must precede the variable name with an exclamation point (!) when you type it in the command window. A number of features are unique to the Console. For example: ■

You can continue an AutoLISP expression on a new line. To continue typing an expression on a new line, press CTRL+ENTER at the point you want to continue. In contrast, expressions entered from the AutoCAD Command prompt are interpreted as soon as you press the ENTER key. AutoCAD treats the incomplete expression as an error, although it does allow you fix the error by completing the expression at the Command prompt.



You can enter more than one expression before pressing the ENTER key, and Visual LISP will evaluate each expression before returning a value to the Console. If the cursor is in the Console window but not at the Console prompt, pressing the ENTER key positions the cursor at the prompt. If you select some text in the Console window before you press ENTER, (for example, the result of a previous command or a previously-entered expression), Visual LISP copies the selected text following the Console prompt. To retrieve text you previously entered from the Console, press the TAB key while at the Console prompt. Each time you press TAB, the previously entered text replaces the text at the Console prompt. You can repeat this until you’ve cycled through all the text entered at the Console prompt. If you repeatedly entered a specific expression, that expression appears only once in the cycle. After you scroll to the first entered line, the list jumps back to the last line entered and the cycle is repeated.





SHIFT+TAB acts like TAB, but scrolls the input history in the opposite direc-

tion.

The System Console

140





The TAB key lets you perform an associative search in the input history. For example, if you type “(+” at the Console prompt and then press TAB, Visual LISP searches for the last text you entered that began with the (+ characters. If it doesn’t find a match, VLISP does nothing (except possibly emit a beep). Use SHIFT+TAB to perform an associative search from earlier to later inputs. The ESC key clears the input area following the Console prompt. Pressing SHIFT+ESC leaves the text you typed in the Console window, but brings you to a new prompt without evaluating the text.

The System Console Context Menu The most important functions needed when working with the System Console are combined into a context menu for fastest execution. Click the right mouse button, or press SHIFT+F10 anywhere in the Console window to display the context menu:

Chapter 5

141

Developing Programs With Visual LISP

Depending on whether there is text highlighted in the Console window and depending on where the cursor position is, some commands may not be appropriate at the moment and are inactive.

Cut

Removes the selected text from the Console window and moves it to the Windows clipboard

Copy

Copies the selected text to the clipboard

Paste

Pastes the clipboard contents to the cursor location

Clear Console Window Empties the Console window Find

Finds a specified text in the Console window

Inspect

Opens the Inspector dialog

Add Watch

Opens the Watch window

Apropos Window

Opens the Apropos window

Symbol service

Opens the Symbol Service dialog

Undo

Reverses the last operation

Redo

Reverses the effects of the previous Undo

AutoCAD Mode

Transfers all input to the AutoCAD Command line for evaluation

Toggle Console Log

Copies the Console output to the log file

Note also that you can cut and paste text between the Visual LISP Console and the AutoCAD command window.

Separators Processing The Visual LISP System Console and the AutoCAD command window differ in the way they process the SPACE and TAB keys. In the Visual LISP Console, a space plays no special role and serves as a separator only. In the AutoCAD command window, if you press the SPACE bar outside of an expression, it causes termination of input and the processing of the text, as if you had pressed the ENTER key.

The System Console

142

Color Coding of Console Input As soon as you enter text at the Console prompt, Visual LISP determines if the entered word is a built-in AutoLISP function, a number, a string, or some other language element that it is aware of. Every type of element gets its own color. See “Color Coding” on page 148 for more information on how Visual LISP flags language elements with color coding.

Context-Sensitive Help for Visual LISP Functions If you enter and select a function name at the Console prompt, then press the Help button on the Tools toolbar, Visual LISP displays help for the function. This feature works for any AutoLISP, Visual LISP, or ActiveX function recognized by Visual LISP.

Logging Console Activity You can keep a record of all Console activity by logging the activity in a disk file. Later, you can view the file and review the activity that occurred at the Console. To create a log file, choose File>Toggle Console Log from the Visual LISP menu. Note that the Console window must be active within Visual LISP in order for the Toggle Console Log option to be available.

Choose a directory for the log file and then specify a filename for the log. If the file already exists, Visual LISP prompts you with the following:

Chapter 5

143

Developing Programs With Visual LISP

If you reply Yes, Visual LISP will append future Console information to the current contents of the file. If you reply No, Visual LISP overwrites the file and the original contents will be lost. Click Cancel to terminate the operation and specify a different file name. To close the log file and end logging, choose Toggle Console Log from the File menu again. The state of Console logging is indicated in the Console window’s title bar. If logging is in effect, Visual LISP displays the name of the log file in the title bar. If logging is off, no file name appears in the title bar. If you do not close the log file before exiting Visual LISP, Visual LISP closes it automatically upon exit. After a log file is closed, you can view its contents with any text editor, such as the Visual LISP text editor.

Accessing Native AutoLISP from Visual LISP Visual LISP enables you to interact directly with native AutoLISP through the Console window. To switch to this mode of Console operation, choose Tools>AutoCAD Mode from the Visual LISP menu, or use the Console context menu and choose AutoCAD mode. The prompt in the console window will change to: Command:

Any character sequence entered at this prompt will be transferred directly to the AutoCAD command line. In this way, you can enter AutoCAD commands from within Visual LISP and you can set variables in native AutoLISP. Remember that native AutoLISP and Visual LISP are separate environments. _$ (setq x 1) Command: (setq y 2) Command: !x $ y NIL $ x 1

; sets x to 1 in the Visual LISP environment ; sets y to 2 in the AutoLISP environment ; displays nil at the AutoCAD console_

To return to the standard Visual LISP Console mode of operation, choose AutoCAD Mode again, just as you did to turn the mode on. The AutoCAD Mode menu item works as an on/off toggle: if the mode is cur-

The System Console

144

rently turned on, choosing it turns it off; if AutoCAD mode is off, choosing it turns it on.

Bouncing Between AutoCAD and Visual LISP At times you may find yourself in a situation where the Visual LISP Console is waiting for input from AutoCAD, and AutoCAD thinks Visual LISP should be in control. When this occurs, you may try to interrupt an AutoCAD command and find control passed right back to Visual LISP. You may see something like the following in the Visual LISP Console: 1_$ ; entering keyboard break loop

If this occurs, you need to return control to AutoCAD and press the ESC key to reset your environment. To return control to AutoCAD, press the Activate AutoCAD button on the View toolbar:

After you press ESC in the AutoCAD window, you’ll be able to resume interaction with the Visual LISP Console.

Using the Text Editor If you just need to run a few simple AutoLISP expressions, entering the expressions in the Visual LISP System Console may suffice. For anything more than that, however, you will need to use the Visual LISP text editor and save your AutoLISP code in a file. The text editor is one of the basic components of Visual LISP. It is easy to use and, if you have some experience using Windows, you can begin using it after a quick review of this chapter. The Visual LISP text editor has a number of features designed to support AutoLISP programming, such as selection of complete AutoLISP expressions, matching of balanced parentheses, syntax coloring, and executing AutoLISP expressions without leaving the editor window. Most text editor commands can be called from the menu bar, and some of the most frequently used commands are also available from toolbar push buttons.

Working with Files To open a new file in the VLISP text editor, choose File>New File from the menu bar. An empty editor window appears on the screen:

Chapter 5

145

Developing Programs With Visual LISP

Entering Text To enter text, begin typing in the active editor window. To start a new line, press the ENTER key. The text editor does not wrap your text when it reaches the end of the visible editor window, so everything you type goes on the same line until you press ENTER. To indent a line of text, type some spaces or press the TAB key. Eventually, you’ll want to use the Visual LISP Code Formatter to automatically indent and space your code; see “Formatting Code with the Visual LISP Formatter” on page 162 for details. A couple of key combinations result in a new line with automatic indenting: ■ ■

Pressing SHIFT+ENTER clears trailing space and tab characters, inserts a new line, and indents using the previous non-empty line indent. Pressing CTRL+ENTER clears trailing space and tab characters, inserts a Newline character, and performs “smart” indent. The smart indent feature is described in “Indentation Rules” on page 171.

To insert new text into existing text, click at the place you want the text to begin and start typing. You can also use the arrow keys to move the cursor to the desired insertion point.

Undoing the Last Change You Made If you change your mind about text you just typed, you can reverse the last edit action by selecting Edit>Undo from the menu bar. The Undo command only works on the last change you made. For example, if you delete a paragraph, then issue the Undo command, Visual LISP restores the paragraph you deleted. But if you delete the paragraph, then start typing in a new line and issue the Undo command, Visual LISP only removes the new text you typed; it is too late to restore the paragraph. You can also reverse the effects of the Undo command, if you change your mind again. Select Edit>Redo from the menu to undo the undo (got that?). So if you delete a paragraph, issue the Undo command to restore it, then issue the Redo command, the paragraph is deleted again. Redo only works if you issue it immediately after Undo.

Using the Text Editor

146

Saving Your Changes Until you save the changes you’ve made to the text in the editor window, everything you typed exists only in the computer’s memory. If you turn off your PC, everything you’ve entered is lost. To save the changes in a file, where you can retrieve the text from one Visual LISP session to another, choose File>Save As from the Visual LISP menu, and specify a path and file name. If you attempt to exit Visual LISP before you’ve saved your file, VLISP will ask you whether to save the changes you’ve made before it will end your session.

Automatic Backup Files Visual LISP supports the automatic creation of backup copies of files loaded by the text editor. The actual backup creation occurs when you save the file for the first time. The backup file has the same name as the original file, except that the file extension begins with the underscore (_) character and is followed by the first 2 characters of the original extension. For example, the backup file for drawline.lsp would be drawline._ls. Automatic creation of backup files is an option you can set by choosing Tools>Environment>Options>General Options. Select the Editor option labeled “Backup the File Edited on First Save” in order to turn on automatic backup. By default, this option is already selected when you first install Visual LISP. Restoring From the Backup File If a backup file exists, you can restore the file you are editing to its original contents, reversing all the changes you made. From the File menu, choose Revert to restore the file. If there is no backup file for the text in the editor window, an error message results.

Editing an Existing File To load and edit an existing file, choose File>Open from the Visual LISP menu. This results in a standard Windows Open dialog box, from which you specify the file you want to edit. Visual LISP opens a new text editor window for the file you select. You can open any number of files and work on them simultaneously; Visual LISP places each file in its own editor window. TIP If you highlight (select) text in any Visual LISP window before choosing File>Open, the selected text is placed in the File name field of the Open dialog box. When you exit Visual LISP, it notes which files are open and saves this information for your next Visual LISP session. The next time you start Visual LISP, it automatically opens these files for you.

Chapter 5

147

Developing Programs With Visual LISP

Color Coding As soon as you enter text in the text editor window, Visual LISP determines if the entered word is a built-in AutoLISP function, a number, a string, or some other language element that it is aware of. Every type of element gets its own color. This helps you detect missing quotes or misspelled function names. The default color scheme is:

AutoLISP Language Element

Color

Built-in functions and protected symbols

Blue

Strings

Magenta

Integers

Green

Real numbers

Teal

Comments

Magenta, on gray background

Parentheses

Red

Unrecognized items (for example, user variables) Black

You can change the default colors from the dialog box displayed by choosing Tools>Window Attributes>Configure Current from the Visual LISP menu. NOTE Visual LISP may not recognize every function you use in your programs. Many commonly used functions are not defined as part of the AutoLISP language, but are instead defined in external applications. If an external function has not been made known to Visual LISP, it will not be identified and color coded. See “Identifying Functions Defined in External Applications” on page 221 for information on how external functions are defined to Visual LISP. The Visual LISP editor provides color coding for LISP files, DCL files, SQL files and C language source files (see “LSP, FAS and other File Types” on page 245 for a list of file types recognized by Visual LISP ). Visual LISP uses the file name extension to determine a file’s type, and selects the color coding accordingly. You can change the color coding style associated with a file type by choosing Tools>Window Attributes>Syntax Coloring from the Visual LISP menu.

Using the Text Editor

148

Context-Sensitive Help for Functions If you enter and select a function name in the text editor window, then press the Help button on the Tools toolbar, Visual LISP displays help for the function. This feature works for any AutoLISP, Visual LISP, or ActiveX function recognized by Visual LISP.

The Text Editor Context Menu As it did in the Console window, right-clicking your mouse in an active text editor window brings up a context menu for quick access to frequently-used commands:

Chapter 5

149

Developing Programs With Visual LISP

Depending on whether there is text highlighted in the editor window and depending on the position of the cursor, some commands may be inactive.

Cut

Moves the selected text to the clipboard

Copy

Copies the selected text to the clipboard

Paste

Pastes the clipboard contents to the cursor position

Find

Finds the specified text in one or more editor windows

Go to Last Edited Moves the cursor to the position you last edited Toggle Breakpoint Sets a breakpoint at the cursor position, or removes a breakpoint if one currently is set at that position Inspect

Opens the Inspector dialog

Add Watch

Opens the Watch window

Apropos Window Opens the Apropos window Symbol Service

Opens the Symbol Service dialog

Undo

Reverses the last operation

Redo

Reverses the effects of the previous Undo

Words in the Visual LISP Text Editor Some text editor commands rely on breaking the text into segments, called words. In the Visual LISP text editor, the term “word” means a sequence of characters separated by one or more of the following special characters:

space tab ’

single quote

(

left parenthesis

)

right parenthesis

"

double quote

Using the Text Editor

150

;

semicolon

\n

Newline

[]

Unprintable ASCII characters (for example, \001-\037)

Text Editor Shortcuts Two text editor features, Complete Word by Match and Complete Word by Apropos, allow you to type in part of a word and have Visual LISP complete the rest of the word for you.

Complete Word by Match Using Complete Word by Match, Visual LISP completes a partially-entered word by matching the part you’ve typed with another word in the same edit window. Press ALT+/ (ALT+slash) to invoke Complete Word by Match on a partially-entered word. The feature is case insensitive.

Complete Word by Apropos With the Complete Word by Apropos feature, Visual LISP completes a partially entered word with a matching symbol name from the Visual LISP symbol table. The VLISP symbol table lists the elements in an AutoLISP program; for example, the symbols, subroutines, and variables referenced by the program. Press CTRL+SHIFT+/ to invoke Complete Word by Apropos on a partially-entered word. If Visual LISP finds several matching names in the symbol table, it presents a context menu from which you can choose the name you want. If more than 15 names are found, the Apropos dialog box appears:

To insert a symbol from the dialog box: 1 Select a symbol from the list

Chapter 5

151

Developing Programs With Visual LISP

2 Right-click your mouse and select Copy to Clipboard from the list of options 3 Click in the editor window at the point you want to insert the symbol name 4 Right-click your mouse and select Paste from the context menu, or press CTRL+V to paste the text If no symbols match what you’ve entered, Visual LISP displays the Apropos options dialog box:

The message area of the Apropos options dialog box shows the value that Apropos could not match. In the input field of the Apropos options dialog, you change the text you want Apropos to match. The dialog box contains the following options: ■







Match by Prefix. If this option is turned on, Apropos searches for a match starting only from the first character of the symbol name. If the option is turned off, Apropos tries to match the text you entered starting at any position of a symbol name. Use WCMATCH (WildCard Match). If this option is turned on, Apropos treats asterisks as wildcard characters when searching. For example, if you specify fun* as the symbol you want matched, Apropos looks for all names that begin with “fun,” no matter what characters follow. In contrast, with Use WCMATCH turned off, the asterisk is treated as a string and Apropos only matches names that precisely match fun*. Downcase Symbols. If turned on, any symbols you copy to the clipboard with the Apropos service are converted to lower case characters. If you paste the symbol name in another window, it appears in lower case. Filter Value. Opens the Filter Value dialog, from which you can select a filter for Apropos to use in searching for matching symbols. You can choose one of the following]

All

No filter

Null value

Only nil-valued symbols are considered

Using the Text Editor

152

Nonull value

Only non-nil-valued symbols are considered

Functions

All function types are considered (user-defined, built-in, etc.)

User function

Only user-defined functions are considered

Built-in function Only built-in Visual LISP functions are considered for matching EXSUBR



Only external function names are matched

Filter Flags. Lets you choose symbols with matching flag settings. Visual LISP displays a list of check boxes that correspond to the symbol flags described in “The Symbol Service Dialog” on page 199. If the flag filter is on, only symbols set with the selected flags are considered.

If you specify a filter value or filter flag, the message area of the Apropos options dialog box indicates your selections.

Chapter 5

153

Developing Programs With Visual LISP

Formatting Shortcut Keys If you press CTRL+E while in an active Visual LISP text editor window, a list containing the following editor options displays:

Indent Block

Indents the selected block of text by adding a tab to the beginning of each line

Unindent

Unindents the selected block of text by removing a tab

Prefix With

Adds a text string to the beginning of the current line, or to each line in a block of selected lines, after prompting you for the string

Append With

Appends a text string to selected lines of text, after prompting you for the string

Comment Block

Converts a block of code to comments

Uncomment Block

Changes a block of comments to active text

Save Block As

Copy selected text to a new file

Upcase

Converts the selected text to all upper case

Downcase

Converts the selected text to all lower case

Capitalize

Capitalizes the first letter of each word in the selected text

Insert Date

Insert the current date (default format is MM/DD/YY)

Insert Time

Insert the current time (default format is HH:MM:SS)

Format Date/Time

Change the date and time format

Sort Block

Sort the selected block of code in alphabetical order

Insert File

Insert the contents of a text file into the current editor window at the cursor position

Delete to EOL

Erase everything from the cursor position to the end of the current line

Delete Blanks

Delete all blank spaces from the cursor position to the first nonblank character in the line

Using the Text Editor

154

Navigation Shortcuts In addition to using the cursor arrow keys, you can use the following Visual LISP editor shortcuts to navigate through your text.

To move

Press

One word to the left

CTRL+LEFT ARROW

One word to the right

CTRL+RIGHT ARROW

To the end of a line

END

To the beginning of a line

HOME

Down one window

PAGEDOWN

Up one window

PAGEUP

To the end of a document

CTRL+END

To the start of a document

CTRL+HOME

To the matching left parenthesis

CTRL+[

Before the innermost opening parenthesis

CTRL+[

To the matching right parenthesis

CTRL+]

After the innermost closing parenthesis

CTRL+]

Text Correction Shortcuts You can delete words, lines, or paragraphs using the following shortcuts:.

To

Press

Erase a word to the left of the cursor

CTRL+BACKSPACE

Erase a word to the right of the cursor

SHIFT+BACKSPACE

Delete characters from the cursor position to the end of CTRL+E and choose Delete the current line to EOL from the menu Delete the current line

Chapter 5

155

Developing Programs With Visual LISP

CTRL+E

You can also can use “overstrike” mode to insert text. Overstrike mode is toggled on and off by pressing the INSERT key. When in overstrike mode, each character you type replaces existing text. The cursor changes shape from vertical to horizontal when in overstrike mode.

Text Selection Shortcuts To select text using the keyboard, press and hold the SHIFT key while pressing the direction (arrow) keys on the keyboard. Other keyboard methods of text selection are listed below.

To

Press

Expand the selection to the next line, or to abandon selection SHIFT+Down Arrow of the next line if it is currently selected Expand the selection to the previous line, or to abandon selec-SHIFT+Up Arrow tion of the previous line if it is currently selected Expand the selection to the end of the line

SHIFT+END

Expand the selection to the beginning of the line

SHIFT+HOME

Expand the selection down one window, or to abandon selec-SHIFT+PAGEDOWN tion of the next window if it is currently selected Expand the selection up one window, or to abandon selection SHIFT+PAGEUP of the previous window if it is currently selected Expand the selection to the next word, or to abandon selec- CTRL+SHIFT+Right Arrow tion of the next word if it is currently selected Expand the selection to the previous word, or to abandon selection of the previous word if it is currently selected

CTRL+SHIFT+Left Arrow

Expand the selection up to the matching left parenthesis

CTRL+SHIFT+[

Expand the selection up to the innermost opening parenthesis CTRL+SHIFT+[ Expand the selection up to the matching right parenthesis

CTRL+SHIFT+]

Expand the selection up to the innermost closing parenthesis CTRL+SHIFT+] Move the cursor to the other side of the selection

ALT+ENTER

Using the Text Editor

156

Moving and Copying Text In addition to using the standard Windows Cut, Copy, and Paste functions, the Visual LISP editor allows you to drag text from one location to another within the edit window. To move text: 1 Highlight the text you want to move 2 Point anywhere inside the selected area, and press and hold the left mouse button 3 Using your mouse, drag the text to the new location 4 Release the mouse button To copy the text instead of move it, follow the same steps but press CTRL before releasing the mouse button in step 4. You can also take selected text and copy it into a new file. With the text selected, press CTRL+E to display a list of options, and choose Save Block As. Visual LISP replies by displaying a dialog box for you to specify where you want to save the text. Visual LISP uses the Windows clipboard for all cut and copy operations, so you can exchange text with any other Windows application that supports these functions. This also means that you can copy and paste text between the text editor and the Visual LISP Console window. Remember that immediately after moving or copying text, you can change your mind and reverse the action using the Undo function.

Indenting Text Most indenting of program code is best handled by running the Visual LISP Code Formatter and customizing the Formatter’s options (see “Formatting Code with the Visual LISP Formatter”). But there are some things you may want to do by yourself.

To

Do

Insert a Newline character and place the cursor at Press CTRL+ENTER the proper indent level on a new line Adjust the indent of a line according to the preceding AutoLISP text

Place the cursor anywhere in the line and press SHIFT+TAB

Adjust the indent of the current selection to that Press SHIFT+TAB of the preceding AutoLISP text

Chapter 5

157

Developing Programs With Visual LISP

To indent selected lines of code, press the TAB key or press CTRL+E and choose Indent Block. Visual LISP inserts a tab character at the beginning of each line you selected. You can control the indent amount of the tab character by choosing Tools>Window Attributes>Configure Current and setting the Tab Width value.

Searching for Text The Visual LISP text editor has extensive text searching capabilities. From the Search menu, choose Find to begin a search, or press the Find toolbar button. Visual LISP displays the Find dialog box:

In the data entry field labeled “Find What,” type the character string you want to search for. If there is text selected when you enter the Find command, this text is automatically placed in the Find What field. Under the Search heading, indicate the extent of the search you want Visual LISP to conduct. You can choose one of the following: ■ ■ ■



Current Selection. Visual LISP searches only the text you have highlighted in the editor window. Current File. Visual LISP searches through the entire file in the active editor window. Find in Project. With this option selected, Visual LISP prompts you to specify the name of the Visual LISP project you want to search. It will search all the files in this project and display all matches in a new output window. See “Finding a String in Project Source Files” on page 257 for more information on this option. Find in Files. If you select this option, Visual LISP allows you to specify a Windows directory (folder) to search for the text. Optionally, you can instruct VLISP to search all subdirectories of that directory as well. Visual LISP will search through all the files and display all matches in a new output window.

When searching for text within the current file, the Direction setting determines where Visual LISP looks next for the search text. Select Down to search

Using the Text Editor

158

forward (toward the end of the file) from the cursor position. Select Up to search backwards (toward the beginning of the file) from the cursor position. You can select any or all of the following options: ■





Match Whole Word Only. If selected, Visual LISP will only match complete words. For example, if the search term is “ent” and VLISP encounters the word “enter” in the text, VLISP does not consider this a match. However, if the Match Whole Word Only option is not selected, Visual LISP considers the “ent” within “enter” to be a match. Match Case. If selected, Visual LISP only matches text whose case matches. In this instance, “Ent” and “ent” are not considered a match. If Match Case is not selected, “Ent” and “ent” are considered a match. Mark Instances. If you select this option, the position of the located text will be added to the Mark Ring (see “Bookmarking Text” on page 160). This lets you quickly return to this code position at a later time. Searches that find all occurrences of a string add each position to the Mark Ring.

Click the Find button to start the search. When searching through a single file, press F3 to search for the next occurrence of your search string. Click the Cancel button to end the search. Visual LISP saves each search string you enter in a pull-down list on the toolbar:

Repeating an Earlier Search To repeat a search you made earlier, you can select a search term from the list on the toolbar:

Click the pull-down arrow and select a search term from the list. Click the Find Via Toolbar button to conduct the search.

Chapter 5

159

Developing Programs With Visual LISP

Replacing Text The Search menu contains a Replace function that allows you to replace search text with a text string that you specify.

The Replace dialog box is similar to the Find dialog box, but with fewer options. It contains an additional “Replace With” entry field, in which you specify the text you want Visual LISP to substitute for the search text. Specify the search text in the “Find what” field. You can take the following actions from the Replace dialog box: ■ ■

■ ■

Press the Find Next button to find the next occurrence of the search string. Press Replace to replace the found text with the replacement string. If you don’t want to replace this occurrence of the text, press Find Next to search for the next occurrence of the text, or Cancel to end the search. Press Replace All to replace all occurrences of the search string with the replacement string, depending on the search Direction. Press Cancel to end the Replace function.

Bookmarking Text The bookmark feature helps you navigate through editor, Console, and other text-based windows by letting you mark up to 32 positions (bookmarks) in each window. Each window maintains its own set of bookmarks, and the bookmark navigation tools let you walk through the marks within each window independently of the other windows. A set of bookmarks within a window is known as a bookmark ring. You can step either forward or backward through the ring, and eventually get back to the starting point. Whenever you step to a bookmark, Visual LISP automatically places a marker at the location you are stepping from. In effect, the marker for the place you are jumping to is moved to the place you jumped from. This makes it easy to return back to your original location, just by stepping back in the opposite direction, or by cycling through all of the bookmarks until you get back to the starting point.

Using the Text Editor

160

To add a bookmark, move the cursor to the location you want to mark, then press the Toggle Bookmark button on the toolbar or press ALT+. (ALT key plus period). Bookmarks may also be inserted automatically when using the Find command to search for text; see the discussion on search options in “Searching for Text” on page 158 for more information on this feature. When the current window contains bookmarks, you can: ■



Move the cursor to the previous bookmark in the ring by choosing Search>Bookmarks>Previous Bookmark, or by pressing the Previous bookmark toolbar icon. You can also accomplish this by pressing CTRL+, (the Ctrl and comma keys). Move the cursor to the next bookmark in the ring by choosing Search>Bookmarks>Next Bookmark, or by pressing the Next bookmark toolbar icon. You can also accomplish this by pressing CTRL+. (the Ctrl and period keys).

In addition to jumping between bookmarks, you can also jump and select (highlight) the text between two bookmarks: ■ ■

Press CTRL+SHIFT+, (Ctrl, SHIFT, and comma keys) to select the text between the current location and the previous bookmark. Press CTRL+SHIFT+. (Ctrl, SHIFT, and period keys) to select the text between the current location and the next bookmark.

Removing Bookmarks Remove a single bookmark the same way you set the bookmark: move the cursor to the bookmarked location, then press the Toggle bookmark button or press ALT+. (ALT key plus period). The Toggle Bookmark command works as an on/off switch. If you issue the command when a bookmark is set, Toggle Bookmark turns it off. Issue the same command when there is no bookmark set, and Toggle Bookmark inserts a bookmark. To remove all the bookmarks in your program, press the Clear all bookmarks button on the toolbar, or choose Search>Bookmarks>Clear All Bookmarks from the Visual LISP menu.

Chapter 5

161

Developing Programs With Visual LISP

Formatting Code with the Visual LISP Formatter The Visual LISP Code Formatter arranges the text of AutoLISP expressions in a so-called “pretty-print” style, which improves text appearance and readability. The Visual LISP Smart Indent helps to set better indentation during program code input. Note: The Formatter assumes that a fixed font is used to display or print the formatted text.

Running the Formatter To format all the text in an active editor window, choose Tools>Format AutoLISP in Editor from the Visual LISP menu, or click the Format Edit window button on the Tools toolbar. To format just part of your code, select a fragment of code text and choose Format AutoLISP in Selection from the Tools menu, or click the Format selection button on the Tools toolbar. The selection should contain a sequence of valid AutoLISP expressions. The Formatter issues an error diagnostic if the selected text is not a sequence of valid AutoLISP expressions. If the Formatter finds unbalanced parentheses in your code, it issues the following message:

Click Yes to have Visual LISP add parentheses where it thinks they belong; click No if you want to fix the parentheses on your own. NOTE The Formatter can balance the number of parentheses, but usually does not insert the additional parentheses in the right places. See “Checking the Balance of Parentheses” on page 172 for more information on detecting and correcting unmatched parentheses.

Formatting Code with the Visual LISP Formatter

162

Visual LISP Formatting Fundamentals The Visual LISP Formatter chooses the appropriate formatting style according to rules that are explained below. You can influence these rules through the AutoLISP Format Options dialog. To initiate the dialog, choose Tools>Environment Options>AutoLISP Format Options from the Visual LISP menu.

Basic Formatting Styles There are two main formatting style sets: ■ ■

A single-line formatting style: Plane Multiple-line formatting styles: Wide, Narrow, Column

The sample text below demonstrates the different formatting styles. Sample text initial appearance: (autoload "appload" ’("appload"))

For a general function call expression, the Formatter applies one of the styles listed below: Plane Style In the Plane style, all arguments are placed in the same line, separated by a single space: (autoload "appload" ’("appload"))

Chapter 5

163

Developing Programs With Visual LISP

The plane style is applied to an expression when all of the following conditions are met: ■ ■



The expression’s last character position does not exceed the value of the environment option Text right margin The expression’s printing length is less than the value of the environment option Maximum length for plane expression (that is, last character position minus starting indentation position is less then this value) The expression does not contain embedded comments with Newline characters

Wide Style In the Wide style, the first argument is placed in the same line as the function name, and other arguments are aligned in a column below the first argument. (autoload "appload" ’("appload") )

The Wide formatting style applies to an expression when the following conditions are met: ■ ■

The Plane style cannot be applied The first element is a symbol and the first element's length is less than the Maximum wide style car length environment option

Narrow Style In the Narrow style, the first argument is placed on the next line after the function name, and other arguments are aligned in a column below the first argument. The displacement of the first argument's starting position relative to the expression starting position is controlled by the value of the Narrow style indentation environment option (in the following example, this value is equal to 2): (autoload "appload" ’("appload") )

The Narrow formatting style applies for PROGN expressions, and for those instances when the Plane and Wide formatting styles can not be applied. The Narrow style indentation option (in AutoLISP Format Options) sets the standard indentation for function arguments that use the Narrow formatting style.

Formatting Code with the Visual LISP Formatter

164

Column Style In the Column style, all elements are positioned in a column. This style is appropriate for displaying quoted lists and COND-expression clauses. For example, the following text: ’((10 "{insertion}") (7 "{style}"))

(1 "{string}")

would be displayed as: ’((10 "{insertion}") (1 "{string}") (7 "{style}") )

Additional Formatting Options In addition to affecting the basic formatting styles, you can set the following AutoLISP Format Options: ■

Closing paren style This style controls the position of the closing parenthesis for multiple-line formatting styles. You can select one of the following options:

Close at the same line

Close parenthesis on the last line of each formatting expression

Close at the new line with inner Close parenthesis on the next line following the indentation last line of each formatting expression with the inner indent Close at the new line with outer Close parenthesis on the next line following the indentation last line of each formatting expression with the outer indent

Chapter 5

165

Developing Programs With Visual LISP

Examples: The initial expression is written as: (cond ((/= (logand mask flg) 0) (list (list txton))) )

Formatting result when Close at the same line option is selected: (cond ((/= (logand mask flg) 0) (list (list txton))))

Formatting result when Close at the new line with inner indentation option is selected: (cond ((/= (logand mask flg) 0) (list (list txton)) ) )

Formatting result when Close at the new line with outer indentation is selected: (cond ((/= (logand mask flg) 0) (list (list txton)) ) ) ■

Insert form-closing comment If you select this option, Visual LISP adds a comment following the close of an expression. However, the option takes effect only if the Closing parenthesis style format setting is either Close at the new line with inner indentation, or Close at the new line with outer indentation. When the Insert form-closing comment option is on, the Formatter inserts a comment of the form: ;_ end of

after each multiple-line function. This comment does not appear if an inline-comment, single-semicolon comment, or pasted-comment exists after the function call. You can change the comment text by entering a different comment in the Form-closing comment prefix field of the AutoLISP Format Options dialog box.

Formatting Code with the Visual LISP Formatter

166

Example Initial text: (autoxload "image" ’("gifin" "pcxin" "riaspect" "ribackg" "riedge" "rigamut" "rigrey" "rithresh" "tiffin"))

Formatted text: (autoxload "image" ’("gifin" "ribackg" "rigrey" ) ) ;_ end of autoxload ■

"pcxin" "riedge" "rithresh"

"riaspect" "rigamut" "tiffin"

Preserve existing line breaks When the Preserve existing line breaks option is on, the Formatter inserts new lines whenever a new line is detected in the text it is formatting. When the option is off, the formatter can squeeze a multiple-line expression to the plane style if it fits within the right margin. The Formatter also preserves all new lines between top-level expressions. The following example shows how the Preserve existing line breaks option works: Initial text: (if (/= s "Function canceled") "\nError: " s)) ;single semicolon cmt )

(princ (strcat

Formatting result if the option is on (default): (if (/= s "Function canceled") (princ (strcat "\nError: " s ) ) )

;single semicolon cmt

Formatting result when the option is off: (if (/= s "Function canceled") princ (strcat "\nError: " s)) )

;single semicolon cmt

Note that multiple-line PRINC and STRCAT expressions are compressed to a single line.

Chapter 5

167

Developing Programs With Visual LISP



Split Comments When the Split Comments option is on, the Formatter splits long comments that extend past the right margin. For the previous example, if the Text Right Margin setting is 60, and Single-semicolon comment indentation is 40, the Formatter will split the comment as follows: (if (/= s "Function canceled") (princ (strcat "\nError: " s))

;single ;semicolon cmt

) ■

Longlist format style Longlists are lists of formal arguments in DEFUN, LAMBDA, or quoted lists containing more than 5 elements. To specify a Longlist option, click the More Options button in the AutoLISP Format Options dialog box. This expands the dialog box window with additional formatting options:

Formatting Code with the Visual LISP Formatter

168

The available modes for Longlist format are listed below and illustrated with an example based on the following list elements: ’("aseadmin" "aserows" "aselinks" "aseexport" "aseselect" "asesqled") ■

Single-column formatting ’("aseadmin" "aserows" "aselinks" "aseexport" "aseselect" "asesqled" )



2-column formatting ’("aseadmin" "aselinks" "aseexport" )



Multi-column formatting ’("aseadmin" "aseselect" )



"aserows" "aseselect" "asesqled"

"aserows" "aseexport"

"aselinks" "asesqled"

Fill-the-string formatting (places as many quoted strings on one line as possible, up to the right margin) ’("aseadmin" "aserows" "aselinks" "aseselect" "aseexport" "asesqled"

) ■

Setting Case for symbols By default, The AutoLISP Formatter does not change the case of AutoLISP symbols. You can set the Formatter to change the case of symbols according to the Visual LISP protection state for symbols. The Protected options subgroup controls the case conversion of protected symbols (that is, built-in symbols or symbols with the ASSIGN-PROTECT flag set):

Chapter 5

169

None

Does not change the case

downcase

Forces all characters in a symbol’s name to lower case

UPCASE

Forces all characters in a symbol’s name to upper case

Developing Programs With Visual LISP

The Unprotected options subgroup controls case conversion of unprotected (user) AutoLISP symbols:

None

Does not change the case

downcase

Forces all characters in a symbol’s name to lower case

UPCASE

Forces all characters in a symbol’s name to upper case

Comment Styles The Visual LISP AutoLISP Formatter recognizes five types of comments, and positions each comment according to its type. Visual LISP Comment Formatting Comment

Formatted Appearance

;| Inline comment |;

The single-line comment appears after formatting as any other expression; the multiple-line comment appears starting at a new line.

; Single-semicolon comment

Starts at the comment-column position, as defined by the “Single-semicolon comment indentation” AutoLISP Format option.

;; Current-column comment

The comment appears starting on a new line, indented at the same level as the last line of program code.

;;; Heading or 0-column comment Appears on a new line, without indentation. ;_ Function-closing comment

Appears just after the previous expression

Formatting Code with the Visual LISP Formatter

170

The following example demonstrates each comment style: Initial text: (defun foo (x) ;|inline comment |; (list 1 2 3) ;comment-column comment ;;current-column comment ;;; heading or 0-column comment ) ;_ function-closing comment

Formatted text: (defun foo (x) ;|inline comment |; (list 1 2 3) ;;current-column comment ;;; heading or 0-column comment ) ;_ function-closing comment

;comment-column comment

Indentation Rules The Visual LISP “Smart Indent” feature works in the background as you type in the text editor. The indent is evaluated up to the current AutoLISP parenthesis nesting level. If before the current expression there is only a sequence of completed top-level AutoLISP expressions, the indentation will be zero. The indenting commands use formatting parameters consistently with the Formatter. Re-indenting after running the Formatter will not change the text if it was formatted using the same parameter values.

Saving and Restoring Formatting Options To save your Formatter options so that they remain in effect across Visual LISP sessions, choose Tools>Save Settings from the Visual LISP menu. Alternatively, you can save the current settings specifically for the program in the active text editor window. Visual LISP saves Formatter settings in a program when the Save formatting options in source file option is checked off. To turn this option on or off, choose Environment Options>AutoLISP Format Options from the Tools menu. If the option is in effect, Visual LISP adds formatting information as comments at the end of the program, when you run the Formatter. Each Formatter invocation checks for formatting options settings at the bottom of the selected text. If found, these settings override the session settings listed under Tools>Environment Options>AutoLISP Format options.

Formatter Restrictions The following restrictions apply to the Visual LISP AutoLISP Code Formatter: ■

Chapter 5

171

The formatter relies on a fixed window font and a particular Tabulation size. You can change these settings using the Window Attributes>Configure current option of the Tools menu.

Developing Programs With Visual LISP

■ ■

The Formatter is available only within Visual LISP Editor windows. Existing Space and Tab characters placed outside of inline comments and strings will not influence the formatting result.

Checking for Syntax Errors One of the main attractions of using Visual LISP is the extensive debugging tools it provides. These tools allow you to watch what your program is doing while it is executing, and to take a snapshot of your program at any point. But Visual LISP also provides a number of features designed to detect program errors before you even run the program.

Checking the Balance of Parentheses AutoLISP uses parentheses more frequently than most other computer languages. One of the most frequent syntax errors in AutoLISP is an unequal number of opening and closing parentheses. Visual LISP includes a number of tools to help you detect unbalanced or unmatched parentheses. As noted earlier in this chapter (“Running the Formatter” on page 162), the Visual LISP Code Formatter searches for unbalanced parentheses when it formats your code. If you allow it to, the Formatter will add parentheses where it thinks they are missing. Typically, though, the Formatter adds parentheses at the end of a program, not where you really need them. So if you let it add the parentheses, you will probably have to remove them later. NOTE At the current time, if you do not allow the Formatter to add the balancing parentheses, it won’t format your code either! In any event, you need to check the structure of your program to determine where the parentheses are really missing. You can use the Parentheses Matching items on the Edit menu to help you find unbalanced parentheses:

Match Forward

(CTRL+])

Moves the insertion point (marked by the cursor) just past the closing parenthesis that matches the next open parenthesis. If there is no nearby match, it moves you one step up in the nesting hierarchy.

Match Backward Moves the insertion point to just before the open parenthesis that matches the previous close parenthesis. If there is no nearby (CTRL+[) match, it moves you one step up in the nesting hierarchy. Select Forward

Moves the insertion point as the Match Forward command does,

(CTRL+SHIFT+]) but also selects all text in between the start and end positions.

Checking for Syntax Errors

172

Select Backward Moves the insertion point as the Match Backward command does, (CTRL+SHIFT+[) but also selects all text in between the start and end positions.

For example, look at the following code:

1 2 3 4 5

17

The line numbers are not part of the text; they are used to help explain the example. Here is what would happen if you loaded this code in Visual LISP and continually issued the Match Forward command, starting with the insertion point at the beginning of line 1: 1 Cursor moves to the end of line 1 2 Cursor moves to the end of line 2 3 Cursor moves to the end of line 3 4 Cursor jumps to the last right parenthesis in the program! (17) In other words, the close parenthesis that matches the open parenthesis on line 4 is all the way at the end of the program. Notice also that all the statements after line 4 are indented in a manner unlike that of the preceding program code. These are 2 clues that indicate something is amiss at this point of the program. In fact, the close parenthesis to the command on line 4 is missing.

Using Color Coding to Detect Syntax Errors The Visual LISP Sample directory contains a file named drawline-with-errors. It is similar to the drawline program introduced earlier in this manual, but it

Chapter 5

173

Developing Programs With Visual LISP

contains a couple of errors. Open the file in Visual LISP, so that you can see how color is used in the file: (defun drawline(/ pt1 pt2); local variables declared ;; get two points from the user (setq pt1 (getpoint "\nEnter the start point for the line: ")) (setq pt2 (getpoint pt1 "\nEnter the end point for the line: ")) ;; check to see that the two points exist (iff (and pt1 pt2) (command "_.line" pt1 pt2 "") (princ "\nInvalid or missing points!") (princ) ;; exit quietly ) )

The example above uses different fonts to substitute for the different colors. If you use the standard Visual LISP syntactic colorations, systems functions such as setq, defun, getdist, getpoint, and / are displayed in blue. Items Visual LISP does not recognize, such as user-defined variables, are printed in black. In this example, if you look at the unrecognized elements in the program, the word “iff” might easily catch your eye. Change it to the correct spelling, “if,” and the color immediately changes to that used for system functions.

Using the Check Command to Look for Syntax Errors You can perform additional syntax checking with the Visual LISP Check command. To check the syntax of all the text in an editor window, do the following: ■ ■

Switch to the editor window containing the code you want to check Choose Tools>Check Editor from the Visual LISP menu

You can also perform a syntax check on a selected piece of code, instead of the whole program, by using the Check Selection item on the Tools menu. Visual LISP displays error messages in a new output window, if it detects any. The sample code above results in the following error message:

The message indicates that an “IF” statement contains too many arguments.

Checking for Syntax Errors

174

Finding the Location of the Syntax Error in Your Program If you double-click on the error message in the output window, Visual LISP activates the editor window, places the cursor at the beginning of the statement that caused the error, and highlights the entire expression:

This error results from the last princ statement following the if. The if statement only allows two arguments: the statement to execute if the expression is true, and the statement to execute if the expression is false. The last princ statement, which is used in this program to cause a “quiet” exit, belongs after the close parenthesis that currently follows it. If you move the statement to the correct location and run Check again, the code should pass as error-free.

Running Your Program To run a program that is in an editor window, first activate the window containing the code. With the text editor window active, choose Tools>Load Text in Editor from the Visual LISP menu, or click the Load active edit window button (shown at left) in the Run toolbar. Visual LISP responds by displaying a message in the Console window indicating that the program has been loaded. To run the program, enter the function name (not the file name) at the Console prompt, in parentheses. For example: _1$ (drawline) Note that you can also choose to run just part of your code by selecting the text you want to run, then choosing Tools>Load Selection. If the program fails with an error message, or does not do what you expect it to do, Visual LISP can help you determine why. See “Debugging Programs” for information on using Visual LISP to analyze what your program is doing.

Chapter 5

175

Developing Programs With Visual LISP

6 Debugging Programs

In this chapter Programs do not always behave in the way they were intended to. When the results you get appear to be wrong,



Debugging Example



Debugging Features



Data Inspection Tools

or are causing the program to crash, it can be difficult to determine what is going wrong. Debugging is the process of finding and resolving program problems. Visual LISP provides many features that assist you in the debugging process.

176

Debugging in Visual LISP Debugging is usually the most time-consuming stage in the development of any program. For this reason, Visual LISP includes a powerful debugger that allows you, among other things, to do the following: ■ ■ ■ ■ ■ ■ ■

Trace program execution Trace variable values during program execution See the sequence in which various expressions are evaluated Inspect the values of parameters used within function calls Interrupt program execution Step through program execution one instruction at a time Inspect the stack

Visual LISP provides the following facilities to implement these features: ■









Chapter 6

177

Break Loop Mode allows you to halt program execution at specified points, and to look at and modify the value of objects during the break. Examples of AutoLISP objects are variables, symbols, functions, and expressions. Inspectors provide detailed information on an object in an Inspector dialog window. If the object being inspected is composed of nested objects (a list, for example), the Inspector allows you to inspect all the components, each one listed on its own line within the window. You can also recursively inspect any nested object until an atomic object (such as a number or a symbol) is reached. The Watch window allows you to watch the values of variables during program execution. The content of the Watch window is updated automatically. This means that if the value of a variable placed in the Watch window is changed, this change will automatically be reflected in the Watch window. The Trace Stack Facility allows you to view the function call stack. The call stack is a mechanism by which Visual LISP records the sequence of functions as they are executed by your program. You can view the stack during a debugging session (when the program is in a suspended state, such as stepping through after a breakpoint), or after your program has crashed. If viewed after your program crashes, the function call stack shows what Visual LISP was doing at the moment the application failed. The Trace Facility is a standard LISP facility that allows you to log the calls and return values of traced functions into the special Trace window.

Debugging Programs

Debugging Example This section takes you through a Visual LISP sample program, using many of the VLISP debugging facilities along the way. You can find the sample program, yinyang.lsp, in the VLISP \sample directory. Open the file in Visual LISP so that you can try the examples in this section. First, load the file and run the yinyang function in order to see what it does. The function draws the Yin-Yang symbol, which is used symbolically by a number of religions and philosophies, including Confucianism and Taoism:

When you run the program, Visual LISP passes control to AutoCAD and you need to respond to the prompts in the AutoCAD command window. Visual LISP evaluates AutoLISP programs by evaluating the expressions contained in parentheses (parenthetical expressions). Parenthetical expressions are similar to operators in other programming languages such as C++ and Visual Basic®. The Visual LISP debugger uses an expression-based approach, unlike the line-by-line debuggers of languages such as C. In this approach, the debugger can suspend program execution immediately before or after the evaluation of any expression. Debugging options are controlled from several different places within Visual LISP, including the text editor, the System Console, and various menus.

Setting a Breakpoint to Interrupt Program Execution Begin by entering some debugging information in the text editor window containing the yinyang.lsp program. Set a breakpoint to halt program execution: 1 Move the cursor in front of the opening parenthesis in the line of code that reads: (setq half-r (/ radius 2))

Debugging in Visual LISP

178

Breakpoint

2 Click the Toggle Breakpoint button in the Debug toolbar,

or choose Debug>Toggle Breakpoint from the Visual LISP menu. Toggle Breakpoint works as an on/off toggle: when no breakpoint exists, Toggle Breakpoint adds a break; if a breakpoint already exists at the cursor position, Toggle Breakpoint removes it. 3 Load the yinyang function, if you have not done so already, then run it from the Visual LISP Console prompt by entering the following command: (yinyang)

After you reply to the prompts the program displays at the AutoCAD command line, Visual LISP halts yinyang execution at the breakpoint you set, and displays the code in the text editor window:

Note how the statement following the cursor is highlighted.

Stepping Through the Program The Step commands allow you to move through a program by executing one or more expressions at a time. With your program stopped at the breakpoint:

Chapter 6

179

Debugging Programs

1 Click the Step Into button, or choose Debug>Step Into from the Visual LISP menu. You can also press F8 to issue the Step Into command. Execution begins and halts before evaluation of the inner parenthetical expression, that is, before the specified division occurs.

Now look at the Step Indicator button on the Debug toolbar; it is the last button on that toolbar:

Step Indicator Button The Step Indicator button is active when you are stepping through a program. It indicates where you are in relation to the expression at the breakpoint. The current symbol indicates that you are stopped just before an open parenthesis. 2 Click the Step Into button again. The cursor moves to a position directly after the evaluated expression, and the Step Indicator button indicates this with the following icon:

3 Click the Step Into button again.The cursor moves to the end of the entire statement (the expression and all nested expressions). 4 Click the Step Into button again and the cursor moves to a position just before the beginning of the statement on the next line:

Debugging in Visual LISP

180

5 Now take a bigger step. Click the Step Over button, or choose Debug>Step Over from the menu; you can also press SHIFT+F8 to issue this command:

With the Step Over command, Visual LISP evaluates an entire expression (and all nested expressions), then stops at the end of the overall expression. The cursor moves to the end of the expression.

Tracing the Evaluation Results of an Expression As you step through a program, you may want to trace the values resulting from the evaluation of individual expressions. Start by checking the value of

Chapter 6

181

Debugging Programs

the last evaluated expression. From the Debug menu, choose Watch Last Evaluation:

VLISP displays the Watch window, which shows the value of the *LAST-VALUE* system variable. Visual LISP always stores the value of the last evaluated expression in the *LAST-VALUE* variable.

Tracing Variables During Program Execution You can use the Watch window to trace variables during program execution. 1 In the text editor window containing yinyang.lsp, double-click on any occurrence of the variable name origin-y. 2 Click the Add Expr button in the Watch window: Visual LISP passes the origin-y variable name to the Watch window and displays the current value of the variable in the window:

If the Watch window were not already open and you wanted to view a variable’s value, you could open the window by choosing View>Watch Window from the Visual LISP menu. If you click the Watch window’s Add Expr button without double-clicking on a variable name first, the following window appears:

In this window, you can enter the name of the variable you want to view. Visual LISP anticipates you by copying the name of the variable nearest the

Debugging in Visual LISP

182

cursor into the window; if this is not the one you want to view, simply type over the name. Visual LISP updates the variables in the Watch window after each execution step. Click the Step Over button (or press SHIFT+F8) twice. In the Watch window, note how the value of ORIGIN-Y changes. It was nil at first, but after execution it took on the value corresponding to the point you clicked in the AutoCAD window:

Continuing Program Execution To continue running your program to the next break point, or to the end if there are no more break points, click the Continue button on the Debug toolbar, or choose Debug>Continue from the Visual LISP menu.

Debugging Features In addition to setting breakpoints as you saw in the Introduction section of this chapter, Visual LISP provides the following options for controlling program execution: ■







Chapter 6

183

Break on Error. This option activates the interactive break loop automatically whenever your program encounters a runtime error. You turn on this mode of operation by choosing Debug>Break On Error from the Visual LISP menu. Stop Once. This option causes Visual LISP to break unconditionally when it evaluates the very first LISP expression prepared for debugging. From the Debug menu, choose Stop Once to initiate this mode. Break on Function Entry. Setting the Debug-on-entry flag for a function’s name symbol causes a break to occur every time you invoke that function. At the break, the source code for the function will be shown in a special window. You can set or clear the Debug-on-entry flag interactively with the Symbol Service dialog. See “The Symbol Service Dialog” on page 199 for information on setting this flag. Debug Top-Level Mode allows you to control the loading of a program from a file or from an editor window. Breaks occur before evaluating every

Debugging Programs

top level expression (such as defun). The Debug Top-Level mode is turned on by switching off the Do not Debug Top Level option. To find the checkbox for this option, choose Tools>Environment Options>General Options from the Visual LISP menu, then click the Diagnostic tab. Note that if Top-Level debugging is turned on, and Stop Once mode is also turned on, Visual LISP will enter the debugging mode every time you load a file. This is due to the fact that Visual LISP is debugging defun, setq, and other functions defined within the file as they are loaded. This is usually not a helpful debugging technique and should only be required in rare instances. ■

Animate Mode operates as if a Step Into command is executed repeatedly with a specified delay. Editor windows in the Animate mode will highlight expressions being evaluated, and the Watch window will permanently update its data. To turn on Animate mode, choose Debug>Animate from the Visual LISP menu. When Animate mode is on, Stop Once mode is ignored. Animation speed is controlled by the value of the Animation delay environment option. To view and set this option, choose Tools>Environment Options>General Options from the VLISP menu, and click the Diagnostic tab.

Starting Debugging The easiest way to start debugging is to choose Debug>Stop Once from the Visual LISP menu. When this item is selected, the evaluation of the first LISP expression will be interrupted. After that you can resume program execution using various Debugger commands. Another way to enter into the debug mode is to set a breakpoint, as shown in “Setting a Breakpoint to Interrupt Program Execution” on page 178. When a break occurs, the corresponding Visual LISP text editor window will show the current LISP expression at the point which the break took place. A break loop marker will appear in the Console window. Using the Console window, you can access and manipulate the program environment in which the break occurred. You can also examine variables using the Watch window.

The Break Loop Expressions are the basic structural units of AutoLISP. Visual LISP works by repeatedly reading, evaluating, and printing expressions. In LISP terminology, this is a read-eval-print loop.

Debugging Features

184

When you are running an AutoLISP program without any debugging intervention by Visual LISP, you are running in the “Top Level” read-eval-print loop. When you evaluate an expression within the Visual LISP Console, and the normal prompt is displayed, you are also working at the Top Level. When a program’s evaluation is interrupted or suspended in the middle of execution, Visual LISP passes control to the Console and you enter a break loop. This break loop is a separate read-eval-print loop, and is nested underneath the original read-eval-print loop. It is possible to interrupt a break loop and start yet another read-eval-print loop beneath it. The nesting level of a break loop with respect to the Top Level is called the break level. When you enter a break loop, Visual LISP prefixes the Console prompt with a number indicating the level you are at. For example, when you first enter a break loop in a program, the prompt indicates this with the number 1: _1_$

While you are in a break loop, you cannot switch control to the AutoCAD window. On exiting from a break loop (for example, after issuing the Quit command), the current read-eval-print loop is terminated and the previous level loop is resumed. If you change the value of a variable in the break loop, this value will be used when the program resumes execution.

Continuable Break Loops There are continuable and noncontinuable break loops in Visual LISP. You can enter the continuable break loop at the very first break in program execution by: ■

■ ■ ■ ■

Turning on the Stop Once mode and reaching an expression with debugging information (that is, an expression that is loaded from source code, as opposed to from a compiled .exe file Reaching a function marked for Debug on Entry Reaching a breakpoint you set in the program Entering a break loop by pressing the Pause button Proceeding with a Step Over, Step Into or Step Out command from the previous break loop state

When the program is interrupted, you enter the break loop. This is apparent if the Visual LISP Console is active, since the prompt is changed to reflect the current level of the break loop. In this suspended state, you have read-write access to all variables in the environment in which the break occurred. For example, if the break occurred within a function containing several local variable declarations, those variables are accessible and you can change their values by issuing setq assignments at the Console prompt.

Chapter 6

185

Debugging Programs

When stopped at a breakpoint, you can control subsequent program execution by choosing one of the following items from the Debug menu, or by pressing the equivalent toolbar button: ■ ■



Reset to Top Level. This terminates all currently active break loops and returns to the Console top-level (the top read-eval-print loop). Quit Current Level. This option terminates the current break loop and returns to a break loop one level up. This may be another break loop or the top level read-eval-print loop. Continue resumes normal program execution from the breakpoint.

The Step commands evaluate portions of program code before resuming suspended mode: ■

■ ■

Step Over looks for the closing parenthesis matching the opening parenthesis where the program is currently paused, and evaluates the expressions in between. Step Into jumps into a nested expression, if any. If there are no nested expressions, it jumps to the next expression in sequence. Step Out searches for the end of the function where the program is currently paused, and evaluates all of the expressions up to that point.

After exiting the break loop to the Console top level, the Console prompt returns to its original form (without a number prefix).

Non-continuable Break Loops A non-continuable break loop is activated when an error causes program interruption and the Break on Error option is set. In a non-continuable break loop, you can access all variables in the error environment, but you cannot continue program execution or execute any of the Step commands. To leave a non-continuable break loop step, use either the Reset to Top Level command to jump to the Console top-level loop, or Quit Current Level to return to the previous break loop level. To distinguish between continuable and non-continuable break loops, check to see whether the Step and Continue toolbar buttons are active or not.

Breakpoints A breakpoint allows you to mark a position in a program at which program execution should be interrupted. You can set breaks to occur before or after parenthetical expressions.

Setting and Deleting Breakpoints Breakpoints can only be set from a Visual LISP text editor window. To set a breakpoint, move the cursor to the position at which you want to halt exe-

Debugging Features

186

cution. For example, to halt execution just before the open parenthesis of an expression, place the cursor just to the left of that open parenthesis. Then click the Toggle Breakpoint toolbar button or press F9 to set the breakpoint. (For variety, you can set a breakpoint by choosing Debug>Toggle Breakpoint from the Visual LISP menu, or by clicking the right mouse button and selecting Toggle Breakpoint from the resulting context menu.) To remove the breakpoint at a later time, follow the same exact procedure. The Toggle Breakpoint works as an on/off toggle: when no breakpoint exists, Toggle Breakpoint adds a break; if a breakpoint already exists at the cursor position, Toggle Breakpoint removes it. You can also use the Breakpoint service dialog to remove breakpoints; see “Listing and Viewing the Breakpoints in Your Program” on page 188 for information on this procedure. If you move the cursor to an ambiguous position, such as in the middle of an expression, Visual LISP will move the cursor to the nearest parenthesis and ask you if you agree with the breakpoint placement:

Click Yes to accept the breakpoint location, or No if that is not where you want to set the break. Breakpoint Highlighting Visual LISP marks each breakpoint position with a colored rectangle, so you can easily locate the breakpoints in your program. By default, active breakpoints are marked in red. You can change this color by setting the :BPT-ACTIVE option under Tools>Window Options>Configure Current.

Disabling Breakpoints When using multiple breakpoints within a source file, it may be useful to temporarily disable one or more breakpoints, but leave the breakpoint position defined for possible later use. This saves time over deleting and restoring the breakpoint. To disable a breakpoint, place the cursor at the breakpoint marker and press the right mouse button. From the resulting menu, choose Break point service. Visual LISP displays the following dialog box:

Chapter 6

187

Debugging Programs

Click the Disable button in the Breakpoint service dialog window to temporarily disable the breakpoint. Visual LISP changes the color of the breakpoint marker when it disables the breakpoint. By default, it marks disabled breakpoints in blue. You can change this color by setting the :BPT-DISABLE option.

Listing and Viewing the Breakpoints in Your Program From the View menu, choose Breakpoints Window to see a list of all breakpoints currently defined to Visual LISP:

The Breakpoints window lists the breakpoints in all programs you are editing in Visual LISP, not just the program in the active editor window. In the example above, only one program (yinyang) is listed, because that is the only one currently open. But you could be editing and setting breakpoints in any number of open files. Each entry in the Breakpoints window shows the name of the source file containing the breakpoint, and the location of the breakpoint in the source. A leading + or - sign differentiates between active and disabled breakpoints. The dialog box allows you to delete all breakpoints at once or to edit (or display) one breakpoint at a time. Pressing Show displays the source position of the breakpoint. The Edit button opens the Breakpoint service dialog, from which you can disable the breakpoint.

Life Cycle of a Breakpoint You can set breakpoints in a program either before or after you load the program. However, if you change the text in a program after loading the pro-

Debugging Features

188

gram, and then add a breakpoint, the breakpoint only takes effect after you reload the code. Breakpoints remain in effect during the Visual LISP editing session and will survive between sessions if you choose Save Settings from the Tools menu. In addition to removing breakpoints using the methods previously described in this chapter, program breakpoints are automatically lost when you do any of the following: ■ ■ ■

Delete the code fragment containing the breakpoint Modify the file outside of the Visual LISP editor (for example, edit and save it with Notepad) Apply Visual LISP formatting commands to code fragments containing breakpoints

Note also, that if you modify a program’s code and run it without reloading it (with the Load Active Edit Window command), the program will be interrupted when a breakpoint is reached, but the exact source position will not be shown. The following dialog box indicates that this situation has occurred:

To enable proper display of a source position, you need to reload the code and restart the program.

Visual LISP Data Inspection Tools Visual LISP gives you almost unlimited access to symbols, values, and functions at any stage of program execution. Visual LISP’s data inspection tools are implemented as modeless dialog windows (except for the Symbol Service), meaning that they stay on the screen as long as you need them, no matter what your program does: ■ ■

Chapter 6

189

The Watch window displays the current value of any set of variables. The Trace Stack window displays the most current call hierarchy. At any level of the stack you can view the corresponding code, the calling code, the local variables, and more.

Debugging Programs



■ ■

The Symbol Service window displays the current value of a symbol as well as its current flags. You can modify both the value and the flags from here. Inspector windows display any LISP object (from a string to an AutoCAD block definition) to any level of detail needed. Frame binding windows display the values of all local variables for their particular stack frame (that is, the specific function invocation in the call sequence).

The Watch Window The Watch window monitors the values of AutoLISP variables during program execution. Each Watch window element line displays the name of a variable and its current value:

The Watch window is updated at each step of a Visual LISP interactive session and always shows the current environment state. In debugger mode, the Watch window is refreshed automatically at the end of every expression evaluation. The Watch dialog retains its contents during a Visual LISP session. This means that if you open the Watch dialog and make it inactive, it will have the same contents the next time you invoke the Watch command during the current session.

Adding a Variable to the Watch Window To add a variable to the Watch window, simply highlight the variable name in any context (that is, in an editor window, Console, etc.) and press the Add Watch button, or choose Add Watch from the Debug menu. You can also select Add Watch from a context menu by clicking the right mouse button while the cursor is on a variable name. If the Watch window is already active, you can add additional variables to the watch list by clicking the Add Watch button on the toolbar in the Watch window. If Visual LISP cannot determine which variable you are interested in based on the cursor position or the text you’ve selected, it displays the Enter expression to watch window:

Visual LISP Data Inspection Tools

190

Specify the name of the variable to be watched in this window, then click OK. The introductory section of this chapter includes an example of using the Watch window; see “Tracing Variables During Program Execution” on page 182.

Watch Toolbar The toolbar on the Watch window contains the following buttons:

Add Watch

Invokes the Add Watch command to add a new variable to the Watch window; this variable can be selected at any active Text Window or typed in the Add Watch dialog

Clear Window

Removes all variables from the Watch window

Sort Expressions

Sort the variables in the Watch window alphabetically by name

Copy to Trace/Log Invokes the log command and copies the contents of the Watch dialog to the Trace window

Using the Watch Item Context Menu To display the Watch Item context menu, highlight the item from the watch list and right-click:

Chapter 6

191

Debugging Programs

On the Watch item menu: ■ ■ ■ ■ ■ ■

Inspect value invokes the Inspector dialog for the selected value. Copy value copies the value of the selected variable into system variable *obj*. Print value prints the selected variable value in the Console window, prefixed with a single quote (’). Symbol... calls the symbol service dialog for the selected variable. Apropos... calls the Apropos dialog using the selected symbol’s name as the Apropos argument. Remove from Watch removes the selected variable from the Watch window.

Visual LISP Data Inspection Tools

192

The Trace Stack Window Visual LISP has a special debugging tool called a trace stack. A trace stack is a historical record of the execution of functions within your program. It is called a stack because of the computer programming structure of the same name. The illustration below shows adding and removing items from a stack. You can see why a stack structure is often referred to as LIFO – Last In, First Out.

The trace stack is used by Visual LISP to “remember its way out” of a nested series of expressions. By viewing the stack you can see what is happening within your program as it is executing (within a suspended, break mode) or immediately after it crashed. Before you invoke a function at the Console window or from AutoCAD, the trace stack is empty. The action of invoking a function causes a record, or element, to be placed on the stack. As that function calls additional nested functions to perform the work of your program, additional elements may be added to the stack. Visual LISP only needs to place elements on the stack when it needs to remember its way out of nested functions. There are two conditions where it is useful to examine trace stacks. The first is when your program is in a suspended state, such as during a breakpoint pause. The second is after an error has occurred, causing your program to fail.

Chapter 6

193

Debugging Programs

Stack Element Lists A stack element is an individual record or “line-item history” within a trace stack. There are five kinds of elements that may appear within a stack: ■

Function call frames show one individual function invocation. Each function call frame appears in the following format: level (function-name {argument1}...)

Arguments within this listing are displayed not by their local parameter name, but by the values that were actually passed to the function. ■

Keyword frames are displayed at the very top and bottom of a trace stack. They are displayed in the form: level :keyword – {optional-data}

The keyword indicates the type of the frame. The optional-data displays additional information relating to the state of the program. ■

■ ■

Top forms indicate an action that was initiated by typing in an expression at the top level Console window, or from the invocation of a function that was triggered during the loading of a file or selection within a Visual LISP editor window. Lambda Forms are placed within a stack whenever a lambda function is encountered within your program. Special Forms display the invocation of the foreach and repeat functions. The arguments for these functions are not displayed. They appear as: level (function-form ...)

Function Call Frames and Keyword Frames are discussed in more detail in the following sections. These sections use the following code to demonstrate the trace stack. If you wish, you can copy this code into a Visual LISP editor window, set a breakpoint as indicated in the code comments, and run this sample: (defun stack-tracing (indexVal maxVal) (princ "At the top of the stack-tracing function, indexVal = ") (princ indexVal) (if (< indexVal maxVal) (stack-tracing (1+ indexVal) maxVal) (princ "Reached the maximum depth.") ; place a breakpoint at the ; beginning of this line ) ) (defun c:trace-10-deep () (terpri) (stack-tracing 1 10) )

Visual LISP Data Inspection Tools

194

Viewing the Current Trace Stack To see the state of a function call stack while your program is suspended at a break point, choose View>Trace Stack from the Visual LISP menu, or click the Trace stack toolbar button:

The Trace Stack window displayed above shows a Function Call Frame for the stack-tracing function. The second element, or frame, in the trace stack is highlighted: [2] (STACK-TRACING 10 10)

The number [2] simply identifies it as the second element in the stack. The numbers following the stack-tracing function name (10 10) indicate the actual values that were passed to the function.

Displaying Information on a Trace Stack Element To obtain more information about an element in the trace stack, select the element and right-click to display a context menu:

Active items available on the context menu depend on the type of stack element you selected before right-clicking. Possible menu commands include the following: ■ ■ ■

Chapter 6

195

Inspect calls the Inspector for the selected stack element. Print prints the stack element to the Console window. Function Symbol calls the Symbol Service dialog for the function call in the stack frame, if the function is called by the symbol.

Debugging Programs

■ ■





Copy copies the selected trace stack element to system variable *obj*. Local Variables displays the Frame Bindings dialog to allow browsing of local variable values at the time the function was called; see “Frame Binding Window” on page 196. Source Position checks whether the source text is available for the function called at the selected stack frame. If the source code is available, the text window with the source code is displayed, with the current position inside the function highlighted. Call Point Source shows the position of the caller expression, similar to Source Position.

Frame Binding Window Choose the Local Variables menu item to display the Frame Binding window:

The Frame Binding window displays information about the local variables in the frame. In the example above, it lists the parameter names (INDEXVAL, MAXVAL), along with the values assigned to these parameters. These are the values that were passed to the function. The parameters are listed in the order that they are defined within the function. If you right-click on an entry in the Frame binding window, Visual LISP displays a context menu:

The menu contains the following items: ■ ■ ■ ■ ■

Inspect calls the Inspector for the selected value. Print displays the selected value in the Console window. Symbol calls the Symbol Service dialog for the selected symbol. Copy copies the selected value into the system variable *obj*. Add to Watch adds the selected symbol to a Watch window.

Keyword Frames A Keyword Frame indicates a specific type of operation that has occurred within the Visual LISP environment. The keyword indicates the type of oper-

Visual LISP Data Inspection Tools

196

ation. Keyword frames will appear in only two locations: at the very top of the stack, or at the very bottom of the stack. The following types of Keyword Frames will appear only at the bottom of a stack: ■







■ ■ ■

:TOP-COMMAND indicates that the Visual LISP interactive environment requested the action resulting in the first element placed within the stack. This situation occurs, for example, when a function is invoked directly from loading a selection or a file. :USER-INPUT indicates that the character string shown in the frame was entered from the Visual LISP Console. The frame immediately above the keyword describes the expression as it was translated from the user input. If the input string is too long, right-click to open a context menu, and choose Show Message to view the entire text. You can also choose the Inspect command to inspect the entered string. :ACAD-REQUEST indicates that a call to the function shown in the frame immediately above the :ACAD-REQUEST keyword frame was invoked from the AutoCAD command prompt. :DCL-ACTION indicates that execution of a DCL tile or dialog action was requested from AutoCAD. The keyword :DCL-ACTION is followed by two strings: the DCL dialog name, and the value of the $KEY variable in the DCL action body. If a number appears, it is the value of the $REASON variable in the DCL action body. The frame immediately above the keyword describes the function call built from the action string. :INSPECT-EVAL indicates the evaluation of an Inspect command. :INSPECT-VERBOSE indicates entrance into a drawing Inspector hook function. :WATCH-EVAL indicates the evaluation of a watch expression.

The following types of keyword frames may appear at the top of a stack: :BREAK-POINT indicates a user-specified break point. :ERROR-BREAK indicates a general runtime error. The Show Message rightclick context menu selection allows you to view more specific error messages. :READ-ERROR indicates an error during a read operation. The Show Message right-click context menu selection provides additional information about the error. :SYNTAX-ERROR will appear when Visual LISP encounters incorrect AutoLISP program syntax. :FUNCTION-ENTRY indicates that the reason for program interruption is a debugger break upon entering the function. The stack element following this message contains the call frame for the function in which the break occurred.

Chapter 6

197

Debugging Programs

:BEFORE-EXP indicates that the reason for program interruption is a debugger break upon entering the function. This message will appear whenever you are stepping through using Step Into or Step Over, and the step is entering an expression (as opposed to just leaving an expression, which is indicated by the :AFTER-EXP keyword.) :AFTER-EXP like :BEFORE-EXP indicates that your program is interrupted in a debugging break mode, and that the Step Into or Step Over command just stepped out of an expression. :KBD-BREAK indicates that the PAUSE key was pressed, placing the program on hold. :PROTECT-ASSIGN indicates that the break was caused by assigning a value to a protected symbol. From the right-click context menu, you can choose Show Message to view the variable name, the current value, and the new value that was attempted to be assigned to the variable. You can also choose the Inspect command to view the list containing the symbol, and the new value indicated following :PROTECT-ASSIGN.

Special Function Call Frames The special function call forms are as follows: ■ ■

(FOREACH ...) Indicates a call to the foreach function. (REPEAT ...) Indicates a call to the repeat function. From the context menu, the Local variables command displays the special name counter and the current value of the repeat internal counter. The internal counter value is initially set to the integer value passed to repeat, indicating the number of iterations desired. The counter decreases by one at each loop iteration. It shows the number of iterations remaining, minus one. Note that each repeat expression possesses its own counter, but only one such counter can be added to the Watch window.

AutoLISP functions such as if, cond, and, and setq do not appear on the stack. They are not necessary because their call position may be viewed within the source file in the text editor window.

Viewing an Error Trace Stack If your program terminates due to an error, choose Error Trace from the View menu to see the state of function invocations up to the time your program crashed:

Visual LISP Data Inspection Tools

198

An error trace stack cannot display “live data,” since it is essentially a postmortem record of the events leading to your program’s failure.

Trace Stack Toolbar The toolbar on the Trace stack window contains two buttons:

Refresh Refresh contents of Trace stack window.

Copy to Trace/Log Copy the window contents to the Trace window or open log file.

The Symbol Service Dialog The Symbol Service dialog is designed to simplify access to the different debugger features provided for symbols. Most facilities available for symbols are also available through this dialog. To open the Symbol Service dialog box, first highlight any symbol (for example, a variable name in your program’s source code, or in the Console window). Then choose View>Symbol Service from the Visual LISP menu, or press the Symbol Service button on the Debug toolbar.

Chapter 6

199

Debugging Programs

The Symbol service dialog box contains the following components: ■ ■ ■ ■

A toolbar The Name field, where you can enter or change the symbol to work on A Value field displaying the symbol’s value or its initial substring Flags, a series of check boxes for symbol flags, which are described in the “Symbol Flags” topic.

To update the value of the displayed symbol, enter an expression in the Value field. When you press OK, Visual LISP evaluates the expression and assigns its value to the symbol. If the symbol is flagged “Assign protected,” this field will be read-only. To remove the flag, check the Protect Assign check box below the value field. Use the OK and Cancel buttons to close the dialog and to continue working in Visual LISP.

Symbol Service Toolbar The Symbol service toolbar contains the following buttons:

Watch Adds the symbol to the Watch window.

Inspect Opens the Inspector for the value of the symbol.

Show the function definition If the symbol names a user-defined function, this command opens the text editor window containing the function definition, and highlights the function.

Visual LISP Data Inspection Tools

200

Help

Displays information from the Visual LISP Help file, if the symbol refers to a built-in function.

Symbol Flags The Symbol Service dialog provides direct access to symbol flags and properties of functional objects that may be associated with them. The following symbol flag options are available: ■

Trace (Tr). The Trace flag activates the tracing of any user-defined function (shown as a symbol within the symbol service window). Tracing will only occur when the symbol is a function, and the expression being evaluated uses the symbol name as a function (not as a local variable name, for example.)



Protect Assign (Pa). This flag intercepts assignments to symbols. For instance, the symbol pi is an Assign-protected symbol. All symbols that are the names of built-in AutoLISP functions are Assign-protected by default. Note that this protection works only for explicit setq, set, or defun invocations. Binding a protected symbol in an argument list of a user-defined function is not intercepted.



Debug on Entry (De). If this flag is set, a breakpoint occurs at each function invocation, regardless of whether the function was loaded with debugging information. The De flag is tested at each function invocation, not during load or defun execution. Note that Visual LISP ignores the Debug on Entry flag for all SUBR, EXSUBR and EXRXSUBR symbols.



Export to ACAD (Ea). If the Ea flag is set, a function associated with the symbol is defined in native AutoLISP as an external subroutine.

Inspector Windows The Inspector is the component of Visual LISP that provides you with the ability to browse, examine and modify AutoLISP and AutoCAD objects. It is a powerful and easy to use tool. You can use the Inspector for the following purposes: ■ ■ ■

Chapter 6

201

To view any objects accessible in AutoLISP (for example, lists, numbers, strings, and variables) To view AutoCAD drawing entities To view AutoCAD selection sets

Debugging Programs

The Inspector also allows you to browse through complex data structures. The Inspector creates a separate dialog window for each object you inspect.

Inspector Dialog Box All Inspector dialog boxes have a similar appearance and contain a system menu box, a caption, an object line (just under the caption), and an object element list (possibly empty). ■ ■ ■

The Caption of an Inspector dialog box shows the type of the object being inspected. The Object Line shows a printed representation of the inspected object. The Element List displays the components of the inspected object. The list may vary in size and contents for different object types. Each element list is shown as a pair: name and contents. The name is enclosed in brackets. Square brackets ([ ]) denote that this item can be modified with a Modify command from the context menu associated with the item, and curly brackets ({ }) designate an unmodifiable item.

Both the object line and the element List lines have their own associated context menus.

Object Element List Formats The object element list formats for AutoLISP object types are: ■ ■ ■ ■ ■ ■

■ ■



INT (integer number) Inspector. The element list shows the various representations of integers. REAL (floating point number) Inspector. This element list is empty. STRING Inspector. This element list contains the sequence of characters in the string, which and may in turn be inspected as integers. SYMBOL Inspector. The symbol element list has 3 elements: value, print name, and flags. LIST Inspector for proper lists. This element list displays the items of the inspected list. LIST Inspector for improper lists. This list has 2 elements: the car and cdr fields. It serves for all cases that are not proper LISP lists, that is, the last cdr is not nil. FILE Inspector. The File Inspector shows the name of the corresponding file and the file’s opening attributes. SUBR, EXSUBR, and USUBR Inspectors. These Inspectors contain the name of the function (the name was specified in defun or at load time). ENAME (drawing entity) Inspector. The fields in this element list correspond to the AutoCAD DXF object list, as returned by the AutoLISP built-in function.

Visual LISP Data Inspection Tools

202



PICKSET (selection set) Inspector. This element list is simply the list of selected AutoCAD objects.

Opening an Inspector Dialog To inspect an object, highlight the object name in any context, then choose View>Inspect from the Visual LISP menu, or press the Inspect button on the Debug toolbar. The Inspect command is also available from a number of context menus, and from the windows displayed by tools such as Apropos and Symbol Service. For example, to inspect the definition of the yinyang function, select the name in the text editor window containing the function’s source code, then press the Inspect button on the Debug toolbar:

A new Inspector dialog box appears showing the value of the expression you selected. For example, if you want to inspect a symbol, you should see this symbol in the form of ’my-variable. If you invoke the Inspect command without selecting an object name, Visual LISP prompts you to specify the object you want to inspect:

Enter the object or expression you want to inspect, then press OK to open the Inspector window or press CANCEL to cancel the action. Visual LISP saves the last 15 items you enter in the Inspector prompt box. You can choose a previously-specified object for inspection by selecting it from the drop-down list.

Handling Errors in the Inspect Command In text editor windows it is not possible to inspect selected expressions longer than 256 characters. If you select a string longer than 256 symbols, you will be prompted to enter an object name. If you specify an object or expression that Visual LISP cannot evaluate, it issues a standard AutoLISP error message. Once the error message appears,

Chapter 6

203

Debugging Programs

you can correct the expression in the dialog box and try to evaluate it once more. Errors arising from evaluation of the object you entered cannot be investigated from a nested break loop, because all breaks are disabled during such evaluation. If you wish to examine the error, choose View>Error Trace from the Visual LISP menu, or copy the expression to the Console prompt and press ENTER.

Closing all Inspector Dialogs You can close all Inspector windows by choosing Window>Close Windows>Inspectors from the Visual LISP menu.

Common Inspector Commands The Inspector dialog boxes provide context menus with commands relevant to the data being inspected. Object Line Commands The object line (or Item) context menu appears after pressing Alt+O or by right-clicking the dialog’s object line. The following commands may be present in an object line menu: ■ ■ ■ ■ ■ ■

Symbol Service invokes the Symbol Service dialog. Print (ALT+P) prints the object to the Console. Pretty Print formats and prints the object to the Console. Copy copies the object to the *obj* variable. Log copies the current contents of the Inspector dialog to the Trace Frame window. Update (ALT+U) updates the Inspector dialog to show the most recent status of inspected object.

When the object line has the focus, these commands are also available as keyboard combinations. The frame status bar should read “Print (Alt+P) Update (Alt+U).“ Element Line Commands The element line (or item) context menu appears after highlighting the element line and right-clicking. ■ ■ ■

Inspect (ALT+I) calls the Inspector and gives it the element (field) value as an argument Descend (ALT+D) calls the Inspector and gives it the element (field) value as an argument and closes the current Inspector. Copy copies the value of the inspected element (field) to the *obj* variable.

Visual LISP Data Inspection Tools

204



View source activates a text editor window containing the selected text. If it was loaded from the Console or from a list representation, this command activates a new text editor window.

The default command for the element line, invoked by pressing ENTER, is the Inspect command. Other commands available as keyboard combinations can be seen from the frame status bar prompt field, when the element line has the focus. However, some lines in the Inspector do not correspond to any sub-objects, and as a result these lines have no joined pop-up menus. Clicking on these lines has no effect. Paging When inspecting long sequences, the Inspector does not show the whole sequence. Instead, it uses paging. For paging, the special paging element lines appear in the Element List. If a sequence is too long the special ">>> [Next page]" element line appears at the end of the Element list. To page the sequence, follow the same procedure that initiates the element line pop-up menu. ■ ■ ■

To page down, choose the ">>> [Next page]" element line and press Alt+E, double-click, or right-click in that element line. To page up, choose the "Load File from the Visual LISP menu, and use the Load Lisp File dialog box to select yinyang.lsp. Remember to use the Files of Type pull-down list in this dialog, and select “Compiled AutoLISP Files,” otherwise Visual LISP only lists LSP files in the dialog. 2 Run the program the same way you would a program loaded from the text editor window. Issue the following at the Console prompt: (yinyang)

Linking Function Calls The process of linking function calls results in Visual LISP creating a loadable module containing copies of AutoLISP built-in functions. This static linkage of built-in functions increases the efficiency of the resulting code, but may change the behavior of some tricky AutoLISP programs. For example, if your program makes calls to a built-in function that is statically linked, and that function is subsequently redefined, your program does not use the new function definition. A copy of the old definition is part of the program’s load module, and that version of the function is used. You must re-link your program in order to pick up the new function definition. Note also that if you include both linked and non-linked calls to this same function, your program could end up using different versions for different function calls. This is one reason why combining linked and non-linked calls within a single file is not recommended. When using multiple-file applications in conjunction with static linking, it is highly recommended that you use Visual LISP’s built-in project management system along with its functions to automatically optimize code. See “Managing Multiple LISP Files” on page 245 for details.

Building Stand-alone Applications Using Visual LISP, you can create commercial AutoLISP applications for distribution to customers. Compiling the programs in your application improves their performance and hides their source code from your customers. You can ship binary FAS files to customers, but in order to run these files, they must have available the Visual LISP Run-Time System (RTS). The RTS contains

Chapter 7

219

Building Applications

a subset of the Visual LISP environment and can load and run FAS files in AutoCAD. You can send customers individual FAS files, or create a single VLX module (Visual LISP executable) that contains all your FAS and DCL files. In both cases, though, you need to send the RTS executable along with your files. The executable is provided in the form of an ObjectARX program. See “Using the Visual LISP Run-Time System” on page 223 for more information about using the RTS. An alternative method of building applications is to package the RTS along with your FAS and DCL files into a single ARX module. This results in a much larger module then either FAS or VLX files, but it is self-contained and can be loaded and run in AutoCAD like any other ARX application. Whether you run your Visual LISP application from the Integrated Development Environment (IDE), or run the application from AutoCAD using the RTS, you are running an application in a Visual LISP environment.

Making Functions Known to AutoCAD To use functions created in Visual LISP in native AutoCAD, you must export the function names to AutoCAD. This is true whether you are delivering your application as FAS files or as a stand-alone ARX module. Only function names that are called directly from AutoCAD (from the Command prompt or a menu, for instance) need to be exported. For example, say your program contains functions yinyang and set-time. The user will issue the yinyang command in AutoCAD to draw yinyang symbols, so the yinyang name must be exported to AutoCAD. Internally, yinyang calls set-time to create a timestamp. AutoCAD does not need to know about set-time, because it is invoked only from within yinyang. Function names can be explicitly exported to AutoCAD, or implicitly exported.

Explicitly Exporting Function Names to AutoCAD Function names can be explicitly exported by using the vl-acad-defun function: (vl-acad-defun ‘symbol)

The yinyang.lsp sample program uses this method to make itself known to AutoCAD: (vl-acad-defun ‘yinyang)

In AutoCAD, the symbol yinyang will be defined as an external function and you can invoke it the way you would any other function: Command: (yinyang)

Building Stand-alone Applications

220

Implicitly Exporting Function Names to AutoCAD By default, any Visual LISP functions whose name begins with c: are automatically exported to AutoCAD. For example, if you change the defun statement in yinyang.lsp to: (defun C:yinyang (/ origin radius ....)

the function name is automatically exported to AutoCAD when you load the application in the AutoCAD environment. Remember that c: functions can be issued as AutoCAD commands from the AutoCAD Command prompt. Refer to “C:XXX Functions” on page 58 for more information on using c: functions in Visual LISP and in AutoCAD, including some limitations imposed on their use. The automatic export of c: functions by Visual LISP occurs if the VLISP system variable *C-COLON-EXPORT* is set to T. By default, the feature is enabled. You can disable the feature by setting *C-COLON-EXPORT* to NIL. If all function names intended for use as AutoCAD commands begin with c:, you can get by without explicitly exporting any functions.

Identifying Functions Defined in External Applications Visual LISP programs can call external subroutines defined by other ADS and ObjectARX applications. Visual LISP is aware of standard AutoLISP external functions, but to recognize other functions as ADS subroutines (EXSUBR) or ARX subroutines (EXRXSUBR), Visual LISP relies on information you supply in an Externally Defined Function (XDF) file. You only need to define an XDF file if you intend to call an ADS or ARX subroutine from code running within a Visual LISP environment. Visual LISP automatically retrieves information from an XDF file for ADS or ARX applications loaded before the Visual LISP IDE or RTS, or when an ARXLOAD or XLOAD function is called from a Visual LISP application. Visual LISP searches for an XDF file in the following sequence: ■ ■

In the application’s directory under the same name as the application (with an extension of .xdf) Ιn the directory containing the Visual LISP Run-Time System or Visual LISP IDE under the name xload.xdf or arxload.xdf

NOTE You must describe every external function defined in an external ADS or ARX module, if you call it from a Visual LISP environment (IDE or RTS). If a function description is missing, Visual LISP will be unable to call that function. If an application is loaded from the AutoCAD Command prompt or from another application after the Visual LISP IDE or RTS is loaded, Visual LISP will not be able to correctly recognize the application’s functions. If this happens,

Chapter 7

221

Building Applications

an explicit call to the Visual LISP vl-import-exsubrs function is necessary. The call format is (vl-import-exsubrs ’(app-name {entry-name}))

The function takes a list as an argument: (vl-import-exsubrs’("c:/Autocad R14/nirvana.arx" "C:ohm" "bliss"))

The first argument is the application’s full name. The remaining arguments are the application function names to be defined to Visual LISP. Creating XDF Files To assist you in the creation of an XDF file for a custom ADS or ARX application, Visual LISP provides the make-xdf utility function. This function attempts to load your application, so if the application is already loaded in AutoCAD, you need to unload it. The make-xdf function assumes that your application defines its function entries after loading, and it retrieves all those function symbols after the load. To start make-xdf, first load the make-xdf.lsp file found in the Visual LISP install directory. Use Tools>Load Application on the AutoCAD menu to load the file. Then enter the following at the AutoCAD Command prompt: Command: make-xdf

The command asks for the name of the external application to browse. Either enter the path name for the application module, or press ENTER without specifying a name and select the file from a dialog box. The make-xdf function loads your application, looks for new function symbols, and writes definitions for them in an XDF file it creates in your application directory. The XDF file has the same name as your application module, with an extension of .xdf. If you do not want to use the make-xdf function to build your externally defined functions file, you can use any text editor to create one from scratch. XDF File Format The XDF file is a plain ASCII file containing a LISP list for each AutoCAD version used. Blank lines and AutoLISP-style comments are allowed. Each entry requires the following syntax: (ACADver* ( application (symbol...) ) ...

)

The list contents are: ■

ACADver - the version of AutoCAD the external subroutine is being defined for. The asterisk must follow the version name, for example: 14*

Building Stand-alone Applications

222



application - a string containing the application’s file name, without the directory path and file extension. For example: “zoomer”



symbol - function symbol defined by this application

Here is a sample entry for an application named zoomer, which refers to 3 external subroutines: ("14*" ; ACAD version ("zoomer" ; module name yinyang ; function c:drawline ; function shakaree ; function ) )

Using the Visual LISP Run-Time System Visual LISP’s Run-Time System (RTS) is an ObjectARX program that loads and executes compiled or uncompiled AutoLISP files. Two versions of the RTS are provided with Visual LISP: ■ ■

vlrts.arx vlarts.arx

These files are in the Visual LISP install directory. The difference between the two versions is that vlarts employs ActiveX methodology, while vlrts does not. Which RTS you use depends on whether or not your programs call ActiveX functions. For a simple program like yinyang, which contains no external references or ActiveX function calls, running a compiled FAS or VLX version in AutoCAD can be accomplished with the following steps: 1 Load the vlrts.arx module (non-ARX version of the Visual LISP Run-Time System). Choose Tools>Load Application from the AutoCAD menu, or issue the arxload function at the Command prompt to load vlrts.arx. 2 Initialize the RTS. You can use the vlrts-init function, supplied with Visual LISP, to accomplish this. Invoke the vlrts-init function at the Command prompt. 3 Issue the vl-load command. This command is defined by vlrts-init, and loads compiled Visual LISP code into the RTS. When vl-load prompts for a file name, specify the file containing the compiled yinyang code. 4 Run the program.

Chapter 7

223

Building Applications

These steps, along with requirements for more complex applications, are explained in the following sections.

Shipping the RTS With Your Application You can ship the Visual LISP RTS modules with your applications, if necessary. Remember that if you build an ARX application from your program, you don’t need to send a separate RTS with your program files. See “Making Application Modules” on page 228 for more information on creating standalone ARX applications.

Loading the Visual LISP RTS To load the Visual LISP Run-Time System from AutoCAD, choose Tools>Load Application from the AutoCAD menu, or issue the arxload function from the AutoCAD Command prompt. For example: (arxload “c:/program files/autocad r14/vlisp/vlrts.arx”)

If the RTS file is in AutoCAD’s Support File Search Path, you can simply issue: (arxload “vlrts”)

AutoCAD assumes that the file name ends with .arx. NOTE Remember that there are two types of RTS modules, one for applications that reference ARX functions and one for applications that do not reference ARX functions. Specify the RTS that your application requires.

Initializing the Run-time System After the RTS is loaded, it needs to be initialized. Initialization may include definition of functions, loading of compiled LISP files, and initialization of global variables. You can accomplish this by running a Visual LISP supplied initialization command from the AutoCAD Command prompt, or by using instructions in an AutoLISP initialization file you create specifically for your application. Using the Visual LISP Supplied Initialization Command Visual LISP comes with functions you can use to initialize the RTS for your applications. The initialization routine for vlrts.arx is vlrts-init; for vlarts.arx, it is vlarts-init. These functions check to see which external applications are loaded into the current AutoCAD session, and define the corresponding LISP functions in the Visual LISP run-time environment. If your application calls functions defined by other applications, the RTS needs a list defining which function belongs to which application. Provide this list in a file of type XDF (Externally Defined Functions); see “Identifying Functions Defined in External Applications” on page 221 for details.

Building Stand-alone Applications

224

Using a Start-Up File For ARX and VLX applications built using the Application Wizard, the RTS looks for an application start-up file. Loading of the start-up file should initialize the application. The file may contain all your application code or just short sequences of LOAD statements. For example, you might include a set of initialization instructions in the same file that contains all your program’s function definitions, like the following: (defun initfunc ( ) (setq *GLOBAL-WARMING* 4.0) (strcat “Hello “ (getvar “username) ) ) (initfunc)

Or you might create a file to just load some applications and greet users: (load “karma.fas”) (arxload “nirvana.arx”) (princ “Hello Earthians”) (princ) )

If you do not supply a start-up file name to Visual LISP, the RTS looks for a FAS file named appname-init.fas, where appname is the name of your application’s executable file. If it finds a file with that name, the RTS executes the instructions in the file. If the RTS does not find a file with that name, it loads vlrts.fas (or vlarts.fas, if you’ve loaded the RTS for ActiveX applications). If VLISP does not find a FAS file of that name, it uses the LSP version of the file. In looking for the start-up file, the RTS first searches the Visual LISP install directory, then the AutoCAD Support File Search Path. If you renamed the RTS executable, you must also rename the FAS or LSP file accordingly. To avoid calling the vlrts-init function explicitly, you can provide any number of end user functions available immediately after loading the application. These functions are called initialization functions. On the first call to any of these functions, Visual LISP calls the vlrts-init function, which loads the start-up file. Then the original function definition will be executed. NOTE

The start-up file should export all initialization functions to AutoCAD.

Functions Defined by the Sample Start-Up File Visual LISP comes with a sample start-up file, VLRTS.LSP. You can use this file as-is, or modify it for your application. The supplied file defines four useful external functions that interact with the RTS environment. After initialization the following functions will be defined in native AutoLISP:

Chapter 7

225

Building Applications

■ ■ ■ ■

vl-eval-str c:vl-eval vl-load c:vl-load

Using VL-LOAD to Load Files into the RTS You can use the vl-load function or vl-load command to load AutoLISP source files (LSP), compiled files (FAS), or Visual LISP application modules (VLX) into the Visual LISP RTS. Any functions in those files that have been explicitly or implicitly exported to AutoCAD will be available in native AutoLISP, and can be invoked from AutoCAD. Issue vl-load at the AutoCAD Command prompt; it responds with the following prompt: VLISP/RTS load file:

If the file you want to load is in AutoCAD’s Support File Search Path, you can enter the file name without specifying a path. If you do not include the file extension, vl-load looks for files with either a .vlx, .fas, or .lsp extension, in that order. If you press ENTER without specifying a file name, vl-load opens a dialog box for you to indicate the file you want to load. If you issue vl-load for the yinyang.lsp file, which includes a vl-acad-defun call to export the function name, you can verify that yinyang is known to native AutoLISP. Use the AutoLISP type function to see how yinyang is defined in AutoLISP: Command: (type yinyang) EXRXSUBR

Using VL-EVAL-STR to Access Functions Not Exported to AutoCAD To access functions loaded but not exported to AutoCAD, use the vl-eval-str function or the vl-eval command. For example: Command: (vl-eval-str “(drawline)”) Enter the start point for the line:

The vl-eval-str function also gives you the ability to set variables in the Visual LISP RTS environment. For example, if applications test a global variable, you can set the variable with vl-eval-str: Command: (vl-eval-str "(setq *RUN-WILD* T)") T

Building Stand-alone Applications

226

To invoke a function and pass it a string, use the backslash (/) escape code for each quotation mark. For example to pass the following to vl-eval-str: (setq str "These are \"\" double quotes")

Use the backslash escape code for quotes, and add double escape codes before any escape codes in the string: Command: (vl-eval-str "(setq str \"These are \\\"\\\" double quotes\")") "These are "" double quotes"

Note that internal functions may not be available if the optimizing compiler dropped their names from the compiled files.

Using the RTS and Native AutoLISP Environments Concurrently When using native AutoLISP and the Visual LISP RTS in parallel you have access to two different LISP environments concurrently. You need to be aware of the scope of functions and variables in the these environments: ■





A load in native AutoLISP loads the LISP file into the native AutoCAD environment, while a vl-load integrates the file’s contents into the Visual LISP RTS environment. Functions known in the RTS environment are not visible in the native AutoLISP environment if they were not explicitly exported. Functions defined in native AutoLISP are not available in the RTS environment. A setq in native AutoLISP sets a variable in native AutoLISP only. This variable is unknown in the Visual LISP RTS environment (or worse: it may have a different value in the Visual LISP RTS). Similarly, any setq in a file loaded to the Visual LISP RTS or through vl-eval-str will set the variable in the Visual LISP RTS environment, leaving the AutoLISP environment unaffected.

Note that AutoCAD automatically loads acad.lsp, acadr*.lsp, and all files with a *.mnl extension during initialization of the native AutoLISP environment. Those files are not automatically loaded to the RTS environment during initialization. You can add the vl-init function call to your initialization file to mimic the AutoCAD initialization procedure and load the aforementioned LISP files. The vl-eval and vl-load functions give you access to the internals of the RTS environment. However supplying vl-eval or vl-load to users also provides a way for them to observe and change variables and symbols in the RTS environment, which may affect your application. If you are concerned about this, drop these functions before distributing your application to customers.

Chapter 7

227

Building Applications

Controlling the Verbosity of RTS Initialization The built-in variables *LOAD-VERBOSE*, *VLISP-XDF-VERBOSE*, and *LOAD-PRINT* control whether or not messages appear on the screen during RTS initialization, and which messages appear. By default these variables are NIL, which provides silent loading of the RTS. You can use the initialization file to set any of these variables to T.

Partial Reinitialization at AutoCAD New/Open Commands If your application loads many files during initialization, you can use the *VL-NEW-FULL-INIT* variable to speed up the loading process when AutoCAD opens a new drawing. If you set *VL-NEW-FULL-INIT* to NIL, Visual LISP will only provide partial initialization when a new drawing is opened. Partial initialization consists of: ■ ■ ■

Closing all dialogs Disabling all objects of type ENTITY (ENAME), in Visual LISP Re-exporting of all function names identified by vl-acad-defun

Partial initialization preserves Visual LISP function symbols and variable values, so your LISP application environment extends to the new drawing. If *VL-NEW-FULL-INIT* is set to T, which is the default setting, Visual LISP reloads completely when a new drawing is opened. NOTE When using partial initialization, your application is responsible for resetting data handles of global variables related to the previous drawing. Such handles may turn to “hanging” references for the new drawing, and using them may lead to unpredictable results.

Making Application Modules Visual LISP provides you with the ability to create a single, stand-alone, ARX executable module for your application. This module incorporates the RTS and all of your application’s compiled files. You also have the option of building a VLX file, which contains all your application compiled files, but does not include the RTS. This greatly reduces the size of the executable file, but you need to supply a copy of the RTS along with the VLX file, unless your customers already have Visual LISP installed. A “Wizard” guides you through the application building process in Visual LISP. The result of this process is a Make file, which is often referred to by its file extension, MKP. The Make file contains all the instructions Visual LISP needs to build the application executable.

Making Application Modules

228

As an alternative to the Application Wizard, advanced users can choose to use Visual LISP Application API functions, along with a custom MKP file, to build an executable module.

Using the Application Wizard The Application Wizard is a tool that guides you through the process of building a stand-alone Visual LISP application. It takes you step by step through the process, asking you questions at each step. At the completion of the process, the wizard produces a Make file. The Make file is an AutoLISP program containing the commands required to compile your application’s programs, export its functions to AutoCAD, and generate an initialization file to be run in the AutoCAD environment. Visual LISP names Make files with a .mkp extension. NOTE It is recommended that you build your application only after you have fully debugged it. Compiler errors during the Make process may prevent the Application Wizard from completing successfully. The examples that follow use some sample programs from the Visual LISP tutorial. You can find these files in the Lesson5 folder of the VLISP Tutorial directory. For AutoCAD Release 14, the default directory is: c:\Program Files\AutoCAD R14\Vlisp\Tutorial\Lesson5

The tutorial files are: ■ ■ ■ ■

Chapter 7

229

Gpmain.lsp Gpdraw.lsp Gp-io.lsp Utils.lsp

Building Applications

Starting the Application Wizard Choose File>Make Application>New Application Wizard from the Visual LISP menu to start the Application Wizard.

Choose the path for the output Make file, and enter a name for the file. For this example, give it the same name as the program, GardenPath. The Wizard automatically adds a .mkp extension to the file name. Press ENTER or click Save to proceed.

Wizard Step 1: Choosing an Application Type In step 1, the Application Wizard asks you to specify the type of application you want to create:

There are 3 choices available: ■

ARX Standard Application. Visual LISP produces a single ARX module that can be loaded and run in AutoCAD. This module includes a copy of the Visual LISP Run-time System (RTS), along with your program and any DCL files.

Making Application Modules

230

ARX Application with ActiveX Automation. Visual LISP also produces a single ARX module, similar to the Standard option, except that it employs ActiveX methodology in the module. WARNING! If any programs in your application use ActiveX methodology, you must choose this option in order to create an ARX application. If you choose the ARX Standard option instead, the program will not run in AutoCAD. ■



VLX. A VLX module contains your application and all supporting files, but it does not include the Visual LISP RTS. Because the RTS is not included, the resulting module size is smaller than ARX modules, and you can use a single RTS for all your VLX modules. However, you are responsible for setting up the run-time environment for VLX modules in AutoCAD. See “Using the Visual LISP Run-Time System” on page 223 for information on setting up the run-time environment for VLX modules.

The Executable prototype identified under the list of application types refers to the ARX RTS module on which Visual LISP models your executable module. The tutorial sample programs use ActiveX methodology, so you must choose the ARX with ActiveX Automation option if you are building an application from these programs. Press the NEXT button to continue to step 2.

Wizard Step 2: Naming the Executable File In step 2 you name the executable file the Wizard is helping you create:

You can type the full path name in the supplied field, or click the Browse button and use a standard Windows dialog to identify the output destination. By default, the Wizard assumes that you want the executable file created in

Chapter 7

231

Building Applications

the same directory as the Make file, with the same file name as the Make file and a file extension of .arx. If you need to go back to a previous Application Wizard step and change something, you can click the Previous button. Otherwise, click Next to continue.

Wizard Step 3: Identifying the Load Method Step 3 of the Application Wizard asks you to identify how you want application code loaded into the AutoCAD environment:

If you select the default option, Load all files automatically, Visual LISP creates a start-up file named VLI$prefix.$$$, where prefix is the first 4 characters of the executable file you named in Step 2. The start-up file loads all your application FAS files. Remember that you can include initialization functions in your FAS files. If you choose to supply an initialization file (such as VLARTS.LSP), clear the Load all files automatically check box and click the Browse button to identify the name of the initialization file you created. This file will be loaded at startup. Click Next to continue.

Making Application Modules

232

Wizard Step 4: Identifying the Program Files In step 4, you identify the program files in your application:

Pull-down list to select type of program file

You can specify AutoLISP source code files, compiled AutoLISP files, or a Visual LISP project file. If you specify a project file, all of the project’s FAS files are included in the output module. See chapter 8, “Managing Multiple LISP Files,” for information on creating and using project files. If you specify AutoLISP source files, Visual LISP compiles those program files when it builds the application. Click the pull-down button to choose the type of file you want to include. If you are building the tutorial application, there are no compiled program files available (unless you’ve gone ahead and compiled the source files on your own), so choose LISP Source Files. Then click Add:

You can only select one file at a time using this dialog box. After selecting a file name, click Open to add it to the application.

Chapter 7

233

Building Applications

For the tutorial application, you need to specify the Lesson5 folder of the VLISP Tutorial directory. Then add each of the following files from that folder: ■ ■ ■ ■

Gpmain.lsp Gpdraw.lsp Gp-io.lsp Utils.lsp

If you need to remove or replace files in the future, select the files you no longer want and click Remove. You can also select one or more files, rightclick, and choose Remove from the context menu. If you want to replace all the LSP files with FAS files, click [Un]Select All to select all the files in your application, then click Remove. Use the Add button to specify the new files. Using the Up and Down Buttons to Change Load Order Visual LISP loads the application’s files in the order they are listed. You may need to reorder the file list in this step of the Application Wizard. For example, if you call a function at load time, the function must be defined before it is used. In this case, you want to place the file defining that function first. The Wizard dialog box contains buttons you can use to move files around in the list. Select a file name, then click either: ■ ■ ■ ■

Top. Move to the top of the list Up. Move ahead of the file just above in the list Dn. Move behind the file just below in the list Btm. Move to the bottom of the list

You can also right-click and choose these actions from a context menu. Note that the load order of project files is specified when you define the project; see “Changing the Order in Which Visual LISP Loads Files” on page 251 of the “Maintaining Visual LISP Applications” chapter.

Wizard Step 5: Identifying Dialog Control (DCL) Files If your application includes Dialog Control Language (DCL) files, you can have Visual LISP compile them and include them in the output module:

Making Application Modules

234

DCL is a tag language that can be used to create custom windows for an application. The Visual LISP tutorial demonstrates how to use DCL in an application. Click the Add button to select the DCL file from the Lesson5 directory; the file name is Gpdialog.dcl. After selecting the DCL file and adding it to the application, click Next to continue.

Wizard Step 6: Defining External Functions If your application calls functions defined in other ARX or ADS applications, you need to create an External Definitions File (XDF) and specify it in this step:

If your application does not use any XDF files, click Next to continue. Otherwise, use the Add button to specify the XDF file you defined. Refer to “Identifying Functions Defined in External Applications” on page 221 for information on defining XDF files and calling other ARX or ADS applications.

Chapter 7

235

Building Applications

Wizard Step 7: Setting Initialization Options Your application can be initialized automatically at load time, or by calling an initialization function:

Initializing at Load Time If you select Initialize in load time, Visual LISP will automatically initialize the LISP environment when any of your application’s functions are invoked. Creating an Initialization List Automatically Visual LISP creates a function list for you if you select the Form the list automatically option. To choose this option, you must first clear the Initialize in load time option, if it is currently selected. NOTE You cannot choose this option if you specified compiled (FAS) files in step 4. Visual LISP cannot gather the information it needs to build a function list from FAS files. If you choose this option, Visual LISP scans your application files for all functions exported to AutoCAD either implicitly (C: functions) or explicitly (for example, by vl-export-to-acad function calls). It builds a list of these functions and defines them as initialization functions. If you choose Form the list automatically, you can click the Preview button to see the list that Visual LISP creates:

Making Application Modules

236

For the tutorial application, a single function is implicitly defined. This is the function you call to start the application. Defining Your Own List of Initialization Functions If you choose neither the Initialize in load time or Form the list automatically options, you can selectively choose the functions you want to define as initialization functions. An Add button appears where the Preview button previously appeared. 1 Click the Add button to begin the process of specifying initialization functions.

2 Click the Browse button to get a list of exported function names. You may receive the following message:

Chapter 7

237

Building Applications

This indicates that one or more of the source files in the application have been modified since their last compile. Click OK to allow Visual LISP to recompile the changed files.

3 In the tutorial application, there is only one exported function name. Select the name and click Add. 4 Click the Close button to return to the step 7 window. Click Next to continue to the final step.

Wizard Step 8: Making the Application In this final step, the Application Wizard summarizes the options you’ve chosen and allows you to build the application now:

If you do not elect to build the application now, Visual LISP saves the information in a Make (.mkp) file that you can use to build the application later. To run that Make file, choose File>Load File from the Visual LISP menu, and specify the Make file name (for this example, GardenPath.mkp).

Making Application Modules

238

If you are following along using the sample tutorial application, select Make the application now, then click Finish. Visual LISP builds a Make file and executes the instructions in that file. Output messages from this process appear in two VLISP windows. These messages are explained in the following section.

Understanding the Output from the Make Application When you run the Make file, Visual LISP automatically compiles any application source files for which either of the following are true: ■ ■

There is no compiled (FAS) version of the file There is a compiled version, but the source file has been modified since that compile

Visual LISP displays messages from the Make process in both the Console window and the window. Here are the Console messages from the tutorial:

The path and file names of all input and output files are identified in the Console messages. If Visual LISP compiles or recompiles any of the source files in the application, compiler messages appear in the window for the Make:

Chapter 7

239

Building Applications

You’ll see some compiler warning messages if you compile the tutorial code. You can safely ignore these message. The last group of messages in the window show compile messages for the automatically-generated initialization file Visual LISP builds for the application:

Note that Visual LISP generates the file name by appending the first 4 characters of the output file name (GardenPath.arx) to the prefix VLI$. The extension for the initialization source file is always $$$.

Loading and Running Applications The method you use to run a stand-alone Visual LISP application in AutoCAD depends on whether you created an ARX module or a VLX module. An ARX module just needs to be loaded before you can run it. A VLX module requires that the Visual LISP Run-time system (RTS) be loaded and initialized first.

Loading and Running an ARX Application To run an ARX application in AutoCAD, load the ARX file and invoke it from the Command prompt. You can load the file using the ARXLOAD function, or by choosing Tools>Load Application dialog from the AutoCAD menu. Using the ARXLOAD Function to Load the Application You can invoke the arxload function from either the AutoCAD Command prompt or the Visual LISP Console prompt. The function has the following syntax: (arxload filename)

For filename, specify the full path name of the ARX file, in quotes. For example: (arxload “c:/Program Files/AutoCAD R14/VLISP/Sample/Gardenpath.arx”)

If the load fails with no indication why, it is possible that the application is already loaded. You can issue the arx command at the AutoCAD Command to view a list of loaded ARX applications:

Making Application Modules

240

Use the arxunload function to unload the application, if it is currently loaded. The syntax is the same as for arxload; just substitute arxunload in the function name. The arxload function can accept an optional onfailure argument; see the “AutoLISP Function Reference” for further information. Using the Tools Menu to Load the Application To load the application from the Tools menu: 1 Choose Tools>Load Application from the AutoCAD menu.

2 If the file name is not listed, click the File button to open a dialog and select your ARX file. If you select the Save List option, AutoCAD saves the file name and includes it in this list for future references. 3 Click Load to load the ARX file. Running the Application Once the application is loaded, run it from the AutoCAD Command prompt as you would any AutoLISP function. For example: Command: (gpath)

Remember that if the function name begins with c:, you can issue it as an AutoCAD command; that is, without enclosing the name in parentheses. The gpath function that starts the GardenPath application does not begin with a c:, so you must include the parentheses. Review “C:XXX Functions” on page 58 for more information on this topic.

Chapter 7

241

Building Applications

Loading and Running a VLX Application To run a VLX application, you must first load the Visual LISP Run-time System (RTS). “Using the Visual LISP Run-Time System” on page 223 describes how to set up the run-time environment for the RTS. Once the RTS is initialized, use the vl-load function to load VLX modules. For example: (vl-load “c:/Program Files/AutoCAD R14/VLISP/Sample/Gpathvlx.vlx”)

Once the application is loaded, run it from the AutoCAD Command prompt as you would any AutoLISP function. Remember that if the name of the function you invoke to start the application begins with c:, you can issue it as an AutoCAD command; that is, without enclosing the name in parentheses.

Rebuilding an Application To rebuild your application after you have made changes to the code, either use the Application Wizard or load the application’s MKP file. NOTE Before you rebuild your application, make sure it is not currently loaded in AutoCAD. If it is loaded, unload it. For example, if your application is an ARX module, use ARXUNLOAD to unload it. The application building process will fail if the target application file is currently loaded, as Visual LISP will not overwrite the existing module.

Using the Application Wizard to Rebuild an Application To use the Wizard to rebuild an application, choose File>Make Application>Existing Application Wizard from the Visual LISP menu. Select the Make file for your application, and proceed with the Wizard as described in this chapter. You can make changes at any step of the process.

Rebuilding an Application from Its Make File If you do not need to change the way your application is defined, you can quickly rebuild the application by simply loading and running its Make file. If the application’s MKP file is loaded in a Visual LISP editor window, you can activate that window and click the Load active edit window button on the Run toolbar. Note that, when you load a Make file, Visual LISP automatically executes the instructions in the file.

Making Application Modules

242

Chapter 7

243

Building Applications

8 Maintaining Visual LISP Applications

In this chapter

This chapter describes how you can maintain large applica-



Managing Multiple LISP Files



Optimizing Application Code

tions containing multiple files by defining the application as a Visual LISP project. Besides defining the components in your application, you can use projects to define compiler options for the application. This chapter describes the various compiler options and the consequences of each, and tells you how to override these options for individual files in a project. Note that the functionality described in this chapter will be supported in future releases of Visual LISP, however the terminology and access to this functionality will change.

244

Managing Multiple LISP Files Many of the program examples you have seen so far in this document have been small, stand-alone AutoLISP files. Typically, however, AutoLISP applications consist of larger files with many lines of code, and functions in each file calling functions in the other files. The Garden Path tutorial application used to demonstrate the Application Wizard in the “Building Applications” chapter is a more typical AutoLISP application. It includes several source code files and a Dialog Control Language (DCL) file. After compiling the programs in this application, you also have a number of FAS files to keep track of. As the number of LISP and FAS files grows, it can become difficult to maintain an application. Simply determining when you need to re-compile files due to source code changes can be a challenge. Visual LISP provides functions that greatly simplify the process of management of multiple-file applications.

Introducing Visual LISP Projects To aid you in the process of maintaining multiple-file applications, Visual LISP recognizes constructs called projects. A project is basically a list of source files, and a set of rules on how to compile these files. Using the project definition, Visual LISP can do the following: ■ ■ ■ ■

Check which LSP files have changed and automatically re-compile only the modified files in your application. This procedure is known as “Make.” Simplify access to source files by listing all source files associated with a project, making them accessible with a single mouse click. Help you find code fragments by searching for strings when you do not know which source files contain the text you’re looking for. Optimize compiled code by directly linking the corresponding parts of multiple source files.

Before discussing how to define and use Visual LISP projects, it may help to introduce file types used in Visual LISP.

LSP, FAS and other File Types The basic file type in Visual LISP, as in native AutoLISP, is the LISP source file. Typically, LISP source files are named with a .lsp file extension. You’ve seen LSP files used frequently in previous chapters. The .fas file type was introduced in the previous chapter, “Building Applications.” FAS files are compiled LISP files. These files load faster and are more secure than LSP files, because the source code is not intelligible to users.

Chapter 8

245

Maintaining Applications

Here is a brief summary of the types of files recognized by Visual LISP project management functions:

File Ext.

Type of File

Function

dsk

Desktop Save

Contains Visual LISP environment and window settings. (Note: do not edit this file unless you are certain you know what you are doing.)

fas

Compiled AutoLISP Code

Compiled AutoLISP programs. May be loaded and run from Visual LISP RTS or IDE, or compiled into VLX or ARX modules.

lsp

AutoLISP Source Code

Program source files.

ob

Object Code

Used internally by Visual LISP, these files contain compiled LISP code used in building FAS files.

pdb

Project Database

Used internally by Visual LISP, these files contain symbol information used by the compiler.

prj

Project Definition

Contains the location and names of all source files that build the project as well as certain parameters and rules on how to create the final FAS files.

In addition to the files recognized by the project manager, Visual LISP either creates or can process a number of additional types of files, summarized below:

File Ext.

Type of File

Function

_xx

Backup files

Backup copies of edited files, maintained by the Visual LISP editor. Backup files contain the same name as the original, except that the file extension begins with the underline character (_) and is followed by the first two characters of the original file’s extension. For example, the backup file of a LISP source file is named *._LS; the backup of a DCL file has a *._DC extension.

arx, vlx

Stand-alone Applications

Stand-alone AutoCAD applications, which can be created using Visual LISP.

Managing Multiple LISP Files

246

File Ext.

Type of File

Function

c, cpp, Language Source Files cch, hpp, hh

Contain program source code. The Visual LISP editor recognizes the syntax of these files and color-codes reserved words, strings and numbers.

dcl

Dialog Control Language

Contain definitions of AutoCAD dialog boxes.

mkp

Make Application

Used by Visual LISP to create stand-alone application files (files you can run in native AutoCAD without Visual LISP). Describes contents of the application.

sql

Structured Query Language Contains SQL statements. The Visual LISP text editor recognizes this file type and colorcodes the text according to SQL syntax rules.

xdf

Externally Defined Functions Defines ADS and ARX functions to Visual LISP. XDF files provide information that allows Visual LISP applications to call ADS and ARX programs.

xdv

Exported LISP Functions

Used by the Visual LISP application builder and the Visual LISP run-time system to generate automatic init-functions lists. Generated by the compiler for each FAS file.

Defining a Project To demonstrate the use of projects in Visual LISP, you can use the sample programs that come with the Visual LISP tutorial. The files are in the \Lesson5 folder of the VLISP Tutorial directory: ■ ■ ■ ■

Gpmain.lsp Gpdraw.lsp Gp-io.lsp Utils.lsp

To create a Visual LISP project, choose Project>New Project from the Visual LISP menu:

Chapter 8

247

Maintaining Applications

Visual LISP displays a standard Windows dialog box for you to specify a file path and name. For this example, use the name Tutorial. Visual LISP assigns a .prj extension to the project file name.

Assigning Project Properties The Project Properties dialog box displays after you specify a project file name:

Project Home Directory List of Selected Files Displays in this Window Click to Change Source Directory

List of LSP Files in the Source Directory

Selecting the Files to Include in a Project There are two tabs in the Project Properties dialog box. Clicking on the Project Files tab displays the window shown above. In this window, you specify the source files for the project.

Managing Multiple LISP Files

248

The project’s home directory is identified just below the tabs. This is where the project file (tutorial.prj) resides. In this example, the home directory is c:\Program Files\AutoCAD R14\VLISP\Sample. That’s not the directory that contains the tutorial sample files, though. To identify the source directory, click the button:

Use the Browse for Folder window to identify the location of the project source files. If you select the Lesson5 directory, the Project Properties window should look like the following:

Visual LISP lists only files that have a .lsp extension to their name, but it does not display the extension in the list. To include all the source files in your

Chapter 8

249

Maintaining Applications

project, click the button labeled “(Un)Select all,” then click the right arrow button ( ); Visual LISP moves the file names to the window on the right:

This window is designed so that, by default, you can select multiple file names by just clicking each name; you do not have to press and hold CTRL to select more than one file. To clear a selected name, just click it again. To remove a file from the project, select it in the right window and click the left-arrow button( ). Identifying the Path Name of Project Files The list of included files does not identify the path name of each file (nor does the “Look In” field; this just identifies the path of the files listed in the left window). Since you can include files from multiple directories in your project, you need to be able to identify the path name of each file. You can do this by highlighting one or more file names and right-clicking to display a context menu:

To display the full path name and the size (in bytes) of source files in the project, choose Log Filename and Size from the context menu. The informa-

Managing Multiple LISP Files

250

tion appears in a small, scrollable window near the bottom of the Project Properties dialog box:

If a file is in the Home directory shown in the Project Properties dialog box, Visual LISP does not spell out its path name. Use the scroll bar to see information about all the files in the project. Note that you cannot include two files of the same name in a project, even though they are in different directory paths.

Changing the Order in Which Visual LISP Loads Files The context menu also provides commands to move files up and down in the list of included files, and to sort the list by file name or by full path name. Visual LISP loads the project’s files in the order in which they are listed. Sometimes the load order is important. For example, you might have an initialization file that defines global variables needed by all the other program files, and thus must be loaded first. You could select that file name and choose Move to Top to place it first in the project’s file list. You can also use buttons in the Project Properties dialog box to move files around in the list: “Top” (Move to Top), “Up” (Move Up), “Dn” (Move Down), and “Btm” (Move to Bottom). For the tutorial project, the gpmain.lsp file should be loaded last. It contains the following instructions at the end of the file: (princ "\nType GPATH to draw a garden path.") (princ)

This results in a prompt telling users how to invoke the application. If Visual LISP loads gpmain.lsp last, these instructions will display at the AutoCAD Command prompt. After you’ve moved any files you need to, click Apply.

Choosing Compiler Build Options The Build Options tab displays a dialog box in which you can specify compiler options to Visual LISP. This topic is covered in the “Choosing a Compilation Mode” section later in this chapter. For now, click OK to close the Project Properties dialog.

Chapter 8

251

Maintaining Applications

Using the Project Window to Work with Project Files Visual LISP displays a window containing a list of the project’s members:

By default, VLISP lists the project members in the order in which they will be loaded (as defined in the Project Properties window). You can change this order by choosing Arrange Files from the context menu for this window (see below). The project name appears in the window title bar. Below the title bar are 5 icons. Each icon is a button that performs a function. The button and their functions are:

Project Properties

Displays the Project Properties window for the project. This allows you to view the full path name of the files in the project, add, remove, and reorder project files, and view and change project compiler options.

Load Project FAS

Loads all compiled (FAS) files for the project.

Load Source Files

Loads all the projects source files, making them available to be run.

Build Project FAS

Compiles all project source files that have been modified since their last compile.

Rebuild Project FAS Recompiles all project source files, whether or not they have changed since their last compile.

Managing Multiple LISP Files

252

If you right-click within the file list of the Project window, Visual LISP displays the following context menu:

Many of the functions available from the project context menu can also be accomplished in other ways. For example, you’ve already seen how to add files to projects and remove files from projects. Choosing Remove File from the context menu is a quick way of removing a file from a project, while choosing Add File merely brings you to the Project Properties window. The following summarizes the commands on the context menu:

Chapter 8

253

Edit

Edit the source code of the selected project members.

Add File

Open the Project Properties dialog, in order to add files to the project.

Remove file

Remove the selected members from the project.

Load

Load the FAS file for the selected project members. If no FAS file exists for a member, load the LSP file.

Load source

Load the source LSP file for the selected project members.

Check syntax

Check AutoLISP syntax of the source code for the selected members.

Touch

Indicate that the selected source files have been updated, but make no change to the files. This causes Visual LISP to recompile these programs the next time you ask to compile all changed project files.

Arrange files

Sort the project member list, according to one of the available suboptions (load order, name, type, or date).

Multiple Selection

Tells Visual LISP whether or not to allow selection of multiple members from the list in the Project window. If this option is checked off, multiple selection is allowed.

Maintaining Applications

[Un]Select all

Selects all members of the project list, if none are currently selected. If any members are currently selected, this command un-selects them.

Close project

Close the project.

Save project as Save the project.

Selecting Multiple Project Members The Multiple Selector menu item is available only from the Project windows’s context menu. Choosing this option allows you to select multiple members from the list in the Project window. If the option is selected, a check mark appears next to the Multiple Selector item on the menu. Click on the menu item to toggle it on and off. If Multiple Selector is in effect, clicking a member name in the Project window acts as a toggle to select or deselect the member. For example, none of the members listed in the following window are selected:

If you click on the name GPIO, then click on the name GPDRAW, both are selected.

This is unlike the usual Windows behavior, where selecting the second list item cancels the first item’s selection, unless you press CTRL while selecting it. You can also use the Project window’s context menu to select all members of the project or cancel selection of all members. If no members are currently selected, right-click and choose [Un]Select all to select all the members. If any or all members are already selected, [Un]Select all cancels all selections.

Loading Project Files To load the project’s compiled program files, click the Load Project FAS button. This allows you to run the application in Visual LISP. If Visual LISP

Managing Multiple LISP Files

254

detects that some of the source files do not exist in compiled format, it displays a message and asks you if you want to compile those files:

If you click Yes, Visual LISP attempts to compile all LSP files that do not have a corresponding FAS file. If you click No, VLISP loads all FAS files it finds for the project, and loads the LSP file for the remaining project. Press Cancel to abort the load operation. To load all project source files, instead of their compiled versions, click the Load Source Files button. Remember that debugging breakpoints may be saved within source code files, but are removed from the compiled version of the code. You might want to the load source files in order to debug changes you’ve made to your programs. Using the Project window context menu, you can choose to load just selected files. Select the files you want to load, then right-click and choose Load to load FAS files, or Load Source to load the source code. Note that if you choose Load and a FAS file does not exist for a selected file, Visual LISP loads the source LSP for that file.

Compiling and Recompiling Project Files One of the key advantages in defining Visual LISP projects for your applications is that it provides an efficient method of updating compiled code. You can elect to have Visual LISP recompile all source files that have changed since the last time they were compiled. By choosing this option, you insure that all FAS files in your application correspond to the latest versions of the program source code. At the same time, you save time by avoiding unnecessary compiles. To invoke this feature, click the Build Project FAS button in the Project window. You can also choose to recompile all the programs in your project, whether or not they have changed; click the Rebuild Project FAS button to enable this feature.

Editing Project Files To edit the source file of a project member, select the member from the list in the Project window, then right-click and choose Edit. If the Multiple Selector option is on, you can select multiple members and Visual LISP will open a text editor window for each.

Chapter 8

255

Maintaining Applications

NOTE If the Multiple Selector option is not turned on, you can simply doubleclick a member name to edit it.

Saving and Closing the Project To save the project properties you defined or modified, right-click in the Project window and choose Save Project As from the context menu. Visual LISP displays a list of project files. You can either select the name of the current project file, to update its contents, or enter a new file name to save the changes as a new project. When you are finished working with a project, right-click in the Project window and choose Close Project. Note that this only closes the PRJ file; any project files that are open in Visual LISP editor windows remain open. NOTE If you close the Project window by clicking the window’s Close button, this does not close the project itself. The Project is still open, and you can reopen a Project window for it by choosing it from the Project menu, as described below in “Opening a Project.”

Working With Existing Projects Some of the Visual LISP features described in previous chapters have special application with Visual LISP projects. The features described in this section are the text editor search functions and the Make Application Wizard.

Opening a Project To open an existing project, choose Project>Open Project from the Visual LISP menu:

If the project file you want to open is in the current directory, you can simply enter the project name here. If it is not, or if you don’t know what the current directory is, click the Browse button to get a standard Open dialog box. Note that you can have more than one project open at a time. You can view a list of all open projects by choosing the Project menu and looking at the bottom of the menu displayed:

Managing Multiple LISP Files

256

At any time, one of the projects is the active one. You can determine which project is active by the check mark in front of the project name. The commands in the Project menu, such as Load and Build, apply to the active project. These commands work the same as they do when selected from a Project window, as described earlier in this chapter.

Finding a String in Project Source Files The Visual LISP text search function, described in “Searching for Text” on page 158, provides you with the ability to search all of a project’s source files for a string of text. For example, suppose that in reviewing gpmain.lsp you see calls to a function called gp:getPointInput, and you cannot remember which source file this function is defined in. To search for it, choose Search>Find from the Visual LISP menu. In the Find dialog box, select Find in project under the list of Search options:

A Project selection field now appears at the bottom of the Find dialog box. If the name of the project you want to search is not already displayed in this field, choose it from the pull-down list. Click the Find button to perform the search. Visual LISP displays the results in the window:

Chapter 8

257

Maintaining Applications

The output shows that 4 files were searched (there are 4 source files in the project), and that 4 occurrences of gp:getPointInput were found. The occurences were found in 2 files; the (defun) for the function is in gp-io.lsp. You can open an editor window for the file by double-clicking anywhere within the highlighted text in the window. You can also press SHIFT+F11 to display the first source location at which the text string was found, and then repeatedly press F11 to view subsequent occurrences in the source files.

Making an Application from a Project After you’ve made changes to an application’s source files, you’ll need to incorporate those changes to the application’s binary files. The topic “Using the Application Wizard,” in chapter 7, showed you how to keep individual application files in synch. Defining those files as members of a single project simplifies this process even further. For example, “Using the Application Wizard” created a Make file named GardenPath.mkp. The application was defined as 4 source files and a DCL file. You can instead define the application as 1 project file and a DCL file. If you add files to the project, you do not have to change the Make file to account for this. If you have already defined an application composed of source or FAS files, and want to change it to refer to a project instead, you can choose File>Make Application>Existing Application Wizard in order to modify it. For the tutorial application, you would use the existing Application Wizard options until you reached step 4, which lists the application’s source files:

Managing Multiple LISP Files

258

To remove the existing LISP source files from the application definition and replace them with the tutorial project file: 1 Click the [Un]Select All button. 2 Click Remove. 3 Click in the pull-down list that currently contains LISP Source Files, and choose Visual LISP Projects. 4 Click Add... 5 Select Tutorial.prj from the Open project dialog box. From this point forward, you can keep the existing application options. Refer to “Using the Application Wizard” in chapter 7 to review all the steps involved in making an application.

Chapter 8

259

Maintaining Applications

Optimizing Application Code Visual LISP provides a number of options for compiling and linking a project’s source code.

Defining Build Options To specify the build options for a project, open the project, then click the Project Properties button in the Project window. In the Project properties window, click the Build Options tab:

The Build Options dialog box contains a number of options. Some of these options require extensive background information, which is provided in the following sections: ■

■ ■

Compilation mode. Choose between standard and optimized compilation. Optimized compilation creates smaller and faster programs, but not every project is suited for optimized compilation. Merge files mode. Tell the compiler whether to create a separate FAS file for each source file, or to merge all compiled files into a single FAS file. Edit Global Declarations. Create or edit a global declarations file for the project. Note that this feature is provided for compatability with the Preview version of Visual LISP. The functionality provided by the Global Declarations file will be provided by other features in futures releases of Visual LISP.

Optimizing Application Code

260



■ ■ ■ ■ ■

FAS directory. Specify the directory for compiled files. If you indicate a relative path, Visual LISP applies it relative to the project’s home directory. If you leave the field blank, VLISP places compiled files in the same directory as the project definition file. Tmp directory. Specify the directory for project-related temporary files. A relative path is applied relative to the project’s home directory. Link mode. Specify how function calls are to be optimized. Localize variables. Choose whether or not to have the compiler remove the names of all local symbols from compiled files, where possible. Safe optimize. Directs the compiler to refuse some types of optimization if there is a chance it will result in incorrect code. Message Mode. Select the level of detail you want Visual LISP to produce in its compilation reports. You can choose to receive a report showing only fatal errors (those causing compilation failure), a report showing errors and warning messages, or a full report showing errors, warnings, and compiler statistics.

Merge files mode specifies whether the compiler will create a separate FAS file for each source file or whether all compiled files will be merged to create a single FAS-file. A single FAS file is faster to load and is required for certain types of optimization. Sometimes, however, you will prefer to load your code one file at a time. This is important if you have not completed the debugging or modification of the application’s code. FAS files do not allow source code debugging, so we recommend that you compile your code only after the initial debugging is done. The Link mode area determines how function calls will be optimized. It is only available if optimized compilation is on. Linking functions means that the compiler directly addresses the function definition and all calls where the function is referenced. The Internal mode additionally removes the function name from the resulting FAS file(s). If Localize variables is set, the compiler removes the names of all local symbols from the resulting file(s), if possible. Safe optimize lets the compiler refuse some types of optimization if there is a chance to create incorrect code. For more information on optimization see the corresponding section below. After closing the dialog the Project Desktop window automatically appears.

Choosing a Compilation Mode Combining compiled code from multiple files to a single binary file allows the compiler to add a high level of optimization. It also means you have more choices to make.

Chapter 8

261

Maintaining Applications

When producing standard, non-optimized binary code, the Visual LISP compiler preserves the symbol names associated with functions and global variables, since these symbols may be referenced from other files. When the symbol is referenced, Visual LISP looks in a table to determine what area in memory is assigned to the symbol. When optimizing code, the Visual LISP compiler assumes that all files in a project work together to form a complete application. This allows it to discard the symbol names and, when executing the code, jump directly to the memory region of the code.

Analyzing for Optimization Correctness Optimizing code may introduce bugs to software that runs perfectly when non-optimized. Also the level of performance gain depends highly on the internal structure of the source code. LISP is a language in which you can easily write programs that create or modify functions at run-time. It should be clear that this use of the language by definition contradicts compile-time optimization. The Visual LISP compiler analyzes the code it is compiling and linking, and creates a report pointing you to all source code segments that may cause problems when optimized. If you do not receive any optimization warning messages, you can assume that optimization did not introduce new problems to your code. The compiler is able to detect most problematic situations in AutoLISP code. However there are situations in which it is impossible to detect code that may become incorrect during the optimization. If your program uses one of the following constructs, the compiler will not able to definitively prove correctness of the optimized code: ■ ■

■ ■ ■

Interaction with external ARX applications that set or retrieve AutoLISP variables. Dynamic calls to functions defined by other ARX applications. You should list the name of these functions and their parent applications in an XDF file, if the application is to be loaded after the Visual LISP application is loaded. Dynamically built code, evaluated using eval, apply, mapcar, or load. Use of set to set dynamically supplied variables. Dynamic (program evaluated) action strings in action_tile and new_dialog.



Dynamic exporting or unexporting of functions to native AutoLISP using vl-acad-defun (or vl-acad-undefun).

Remember: Any optimization changes program semantics. The compiler intends to preserve the behavior of project components relative to one

Optimizing Application Code

262

another. The compiler cannot guarantee unchanged behavior between your project and external procedures. Typical effects are: ■ ■ ■

Outer applications and the AutoLISP console lose access to program functions and symbols. Functions available from the Console in interpreter mode are unknown in compiled mode. Functions are available from the Console, but redefining them does not change the program’s behavior.

Understanding Project Build Options There are a number of compilation options to choose from when you define your project. “Defining Build Options” on page 260 briefly noted the options available to you. To choose from among those options, you need more information as to what they mean.

Link Mode If you direct the Visual LISP compiler to link functions in your project, it tries to directly link all explicit function calls to the function definition, which may reside in a different source file. In contrast, when you do not link your functions, the compiler creates references to symbols that Visual LISP uses to look up the actual memory location of the function. Linking improves the performance of the compiled code and protects the code against function redefinition. However, if your application is designed so that it is necessary to redefine a function in order for it to work properly, you cannot statically link that function. The Build Options dialog lists 3 options for link mode: ■ ■ ■

Do Not Link. Do not link any functions. Link. Link all functions in the project. Internal. Link, then drop all functions. See “Dropping Functions,” below.

Dropping Functions Once function calls are statically linked, the compiler can optimize one level further by dropping the function name completely. By dropping the function name, the function becomes invisible to users. This feature is selected by choosing the Internal Link mode option. Symbols exported to ACAD (for example, function names starting with C:) will never be dropped.

Chapter 8

263

Maintaining Applications

Localizing Variables Similar to function symbols, local variables are also subject to optimization. If the Localize variables option is set, the compiler drops the names of all local variables and directly links their references. This means that the program code points to the address where a variable is stored, instead of to a symbol used to find the address of the variable.

Safe Optimization Choosing the Safe optimize option reduces the amount of compiler optimization but protects your code from compiler-induced errors. Conditions handled by Safe optimizing relate to uncertain effects that can take place at program run-time. They may lead to a failure of the optimized program even though the source code seems to be correct. For example: ■ ■

The function symbol fishlips is defined by defun and used somewhere in your code. This is a typical candidate for link optimization. In another segment of your code, a variable named fishlips is assigned using (setq fishlips ).

Now there are two possible conditions: if the value assigned through setq is intended to alter the definition of the function fishlips, static linking will prevent this from happening. The first definition will be linked and cannot be changed by the setq function. On the other hand, if the identical names are handled independently, fishlips can be linked without creating incorrect code. If Safe optimizing is on, the compiler will always stay on the safe side, even if the user explicitly requests linking fishlips. This may result in less efficient code, but it ensures code correctness. If Safe optimizing is off, you can override the compiler’s not-link recommendation for fishlips: you are responsible for the link. The Safe optimize mode is on by default. Be sure that you fully understand the consequences before you turn it off. LINK Conditions Ignored if Safe Optimizing is On If the compiler encounters the following situations while Safe optimize is on, it ignores any related LINK directive: ■ ■ ■

A symbol is bound as a parameter anywhere in the project A symbol is bound as an auxiliary variable and referenced by value anywhere in the project A symbol is explicitly assigned somewhere (by setq)

Optimizing Application Code

264

DROP Conditions Ignored if Safe Optimizing” is On If the compiler encounters a symbol referenced by value, it ignores any DROP directive for the symbol. LOCALIZE Conditions Ignored if Safe Optimizing” is On If the compiler encounters the following situations while Safe optimize is on, it ignores the LOCALIZE directive: ■ ■

A variable has a non-local reference or assignment to it within the project A variable is called by name

Safe Optimization Warning Messages If optimized compilation is on and the compiler finds a condition that forbids a certain level of optimization, it issues a warning message. For example, if the function fishlips cannot be linked because the compiler found two definitions for the function, you’ll see: ;*** WARNING: Cannot LINK fishlips; Two DEFUNs found. See Another DEFUN

Right-clicking on a warning message opens a menu. In addition to symbol commands, the menu allows you to view the source code associated with the message. Double-clicking on the highlighted message also shows the source code. To browse all source files related to the compiler messages, press F11 repeatedly, or press SHIFT+F11 to return to the first message. Each line of the warning message above guides you to a different code segment: ; *** WARNING: Cannot LINK fishlips

shows the function call that could not be linked. ; Two DEFUNs found

shows the first DEFUN found for function fishlips. ; See Another DEFUN

shows the second DEFUN found for function fishlips. When the compiler works in safe optimization mode and finds a problem condition, the warning starts with: ; *** WARNING: Safe: Cannot …

If Safe optimization is off, but message mode is set to Full report, the same warnings are prefixed by: ; *** WARNING: Dangerous …

Chapter 8

265

Maintaining Applications

If you disable Safe optimize mode, these problematic conditions result in compiler warnings.

Compiler Checking of Optimizing Conditions The compiler always checks for optimizing consistency. If you specify an optimization option that contradicts certain security rules, the compiler will issue warning messages. These are briefly listed below. LINK Requirements The compiler links LISP function calls only if the following conditions are met: ■ ■ ■ ■

The function is defined only once, or is system defined (and poses no defun). The function is not bound anywhere in the project. The function is not assigned anywhere in the project. The linking call appears in the same module (FAS file) as the defun.

DROP Requirements The compiler tries to drop a function name only if all corresponding function calls could be linked and are actually linked to the function definition. The compiler does not drop the function name for a function definition if the program calls a function by its symbol name. A function is called by name in the following cases: ■ ■ ■

The symbol appears in a vl-acad-defun declaration. The function was called from an ACTION_TILE action string. The function symbol is a quoted argument for apply or mapcar or eval somewhere in the project.

Note that for functions called from top-level expressions, the DROP declaration will be ignored without any warning messages. LOCALIZE Requirements The compiler does not localize a variable in bound lists of defun,lambda, and foreach expressions if: ■ ■ ■

The variable has a non-local reference (or assignment) to it within the outer top-level expression The variable is called as a function by name The variable symbol appears as a function call somewhere in the top-level read-eval loop

Besides these conditions, which always cancel the optimization and result in warning messages, there are other conditions which may or may not result in incorrect code. Choosing the Safe optimize option for the project disallows these conditions as well. Disabling of Safe optimization results in com-

Optimizing Application Code

266

piler warnings if these conditions are met. See “Safe Optimization” on page 264 for more information on this topic.

Chapter 8

267

Maintaining Applications

9 Advanced Topics

In this chapter Visual LISP not only makes program development easier



Using ActiveX Objects in AutoLISP

and faster, it also provides new functionality to AutoLISP



Attaching Reactors to AutoCAD Drawings

applications. For example, you can use Visual LISP to access ActiveX objects from AutoLISP code. And you can attach reactors to entities in the AutoCAD drawing window, allowing your application to respond to user actions on these entities.

268

Using ActiveX Objects with Visual LISP ActiveX Automation is a new way to programmatically work with the contents of an AutoCAD drawing. In many instances, ActiveX works faster than traditional AutoLISP functions in manipulating AutoCAD drawing objects. ActiveX functionality is a programming interface that is usable from a number of languages and environments, such as C++, Visual Basic™, and Delphi™. When you work with ActiveX objects in Visual LISP, you are working with the same object model, properties, and methods that can be manipulated from these other programming environments. Objects are the main building blocks of an ActiveX application. In some ways, you are already familiar with this notion. For example, AutoCAD drawing items such as lines, arcs, polylines, and circles have long been referred to as objects. But in the ActiveX schema, many other components of the AutoCAD interface are viewed as objects. For example, all of the following are represented as objects: ■ ■ ■ ■

Style settings, such as linetypes and dimension styles Organizational structures, such as layers, groups, and blocks The drawing display, such as the view and viewport The drawing’s model space and paper space

Even the drawing and the AutoCAD application itself are considered objects. In Visual LISP, ActiveX Automation includes much of the functionality provided by LISP functions such as entget, entmod, and setvar. Compared to these standard AutoLISP functions, ActiveX runs faster, provides easier access to object properties, and is more readable. For example, to access the radius of a circle with traditional AutoLISP function, you must use entget to obtain a list of entities, and assoc to find the property you are looking for. Furthermore, you must know the code number (DXF key value) associated with that property in order to obtain it with assoc: (setq radius (cdr (assoc 40 (entget circle-entity))))

With an ActiveX function, you simply ask for the radius of a circle: (setq radius (vla-get-radius circle-object))

Whether or not to use ActiveX Automation is not always a matter of choice. There are some things that you can only do using ActiveX. For example, to access drawing objects from reactor callback functions, you must use ActiveX. You’ll learn more about this in “Attaching Reactors to AutoCAD Drawings” on page 290.

Chapter 9

269

Advanced Topics

Understanding the AutoCAD Object Model Objects are structured in a hierarchical fashion, with the Application object at the root. The view of this hierarchical structure is referred to as the object model. The object model shows you which object provides access to the next level of objects. The AutoCAD object model is pictured below. The AutoCAD Object Model

Object Properties All objects in the AutoCAD object model have one or more properties. For example, a circle object can be described by its radius, area, or linetype; each of these are properties. An ellipse object also has area and linetype properties, but it cannot be described in terms of its radius. Rather, you describe it in terms of its major to minor axis ratio, a property named RadiusRatio in the

Using ActiveX Objects with Visual LISP

270

AutoCAD object model. You’ll use property names when accessing AutoCAD data through ActiveX functions.

Object Methods ActiveX objects also contain methods, which are simply the actions available for a particular kind of object. Some methods are applicable to most AutoCAD drawing objects. For example, the Mirror method (creating a mirror image copy of an object around a mirror axis), and the Move method (moving a drawing object along a specified vector) are among the methods that apply to most drawing objects. By contrast the Offset method, which creates a new object at a specified distance from an existing object, applies only to a few classes of AutoCAD objects, such as Arc, Circle, Ellipse, and Line. In Visual LISP, ActiveX methods are implemented as AutoLISP functions. You’ll see many references to "ActiveX functions" in Visual LISP documentation, but keep in mind that in native ActiveX terminology, these are always known as “methods.” To determine which methods and properties apply to a specific type of AutoCAD object, refer to the AutoCAD ActiveX Automation Reference. The Reference is available from the AutoCAD Help menu, or by opening the acadauto.hlp file in the AutoCAD Help directory. TIP You will probably want to have the ActiveX Automation Reference open at all times when you are developing Visual LISP programs that use ActiveX. If you open the acadauto.hlp file from the AutoCAD Help directory, you can keep the ActiveX Automation Reference open when you use Visual LISP online help. If you open the Automation Reference by selecting it from the AutoCAD Help menu, it closes when you choose an item from the Visual LISP Help menu.

Collections of Objects All objects in the AutoCAD object model are grouped in collections. For example, the Blocks collection is made up of all blocks in an AutoCAD drawing, and the ModelSpace collection is comprised of all graphical objects (circles, lines, polylines, etc.) in the drawing’s model space. Collections are labeled in the object model diagram.

Accessing AutoCAD Objects The Application object is the root object for the AutoCAD ActiveX Automation object model. From the Application object, you can access any of the other objects, or the properties or methods assigned to objects. The first thing you need to do to access AutoCAD objects with ActiveX is to establish a connection to the AutoCAD Application object. Use the

Chapter 9

271

Advanced Topics

vlax-get-acad-object function to establish this connection, as in the fol-

lowing example: (setq acadObject (vlax-get-acad-object))

The vlax-get-acad-object function returns a pointer to the AutoCAD Application object. In the example above, the pointer is stored in variable acadObject. This return value exists as a unique Visual LISP data type called VLA object (Visual LISP ActiveX object). When you refer to AutoCAD objects with ActiveX functions, you must specify a VLA object type. For this reason, you cannot use entget to access an object and then refer to that object with an ActiveX function. NOTE The entget function returns an object of data type ename. Although you cannot use this object directly with an ActiveX function, you can convert it to a VLA object using the vlax-ename->vla-object function. (See “Converting Object References” on page 288.)

Using the Inspect Tool to View Object Properties To view the properties associated with an Application object, you can select the variable that points to the object (acadobject, in the previous example), and click the Inspect button on the Visual LISP View toolbar:

You can readily identify many of the properties listed in the VLA Object Inspector window. For example, “FullName” is the file name of the AutoCAD executable file, “Version” is the current AutoCAD version, and “Caption” is the contents of the AutoCAD window title bar. An [RO] following a property name indicates that the property is read-only; you cannot change it. Any property identified as a # refers to another AutoCAD ActiveX object. The Application object has two such properties, “ActiveDocument” and “Preferences.” If you look at the diagram of the AutoCAD object model, you’ll see that these two objects are just below the Application object in the model hierarchy. To view the properties associated

Using ActiveX Objects with Visual LISP

272

with an object, double-click the object line in the Inspector window (or rightclick and choose Inspect). Here is the Inspector window for the Preferences object:

You may have noticed that the properties of the Preferences object correspond to the settings in the AutoCAD Preferences dialog box. This makes it easy for you to programmatically access Preferences information. For example, you can identify the AutoCAD configuration file with the following function call: $ (vla-get-ConfigFile acadPreferences) "C:\\Program Files\\AutoCAD R14\\acad14.cfg"

You’ll learn more about using ActiveX functions in “Using Visual LISP Functions with ActiveX Methods” on page 275.

Moving Forward From the Application Object Following the AutoCAD object model hierarchy, the ActiveDocument property of the Application object leads you to the Document object. This represents the current AutoCAD drawing: (setq acadDocument (vla-get-ActiveDocument acadObject))

The Document object has many properties. Access to non-graphical objects (layers, linetypes, and groups, for example) is provided through like-named properties such as Layers, Linetypes, and Groups. To get to the graphical objects in the AutoCAD drawing, you’ll need to access either the drawing’s

Chapter 9

273

Advanced Topics

model space (through the ModelSpace property) or paper space (through the PaperSpace property). For example: (setq mSpace (vla-get-ModelSpace acadDocument))

At this point, you have access to the AutoCAD drawing and can add objects to the drawing. For example, you can add a circle to the model space with the following command: (setq mycircle

(vla-addCircle mSpace ’(3.0 3.0 0.0) 2.0))

Summarizing the Process In this section, you saw code examples that led to the drawing of a circle object to an AutoCAD drawing, using ActiveX Automation. The following sequence of function calls was used: (setq (setq (setq (setq

acadObject acadDocument mSpace mycircle

(vlax-get-acad-object)) (vla-get-ActiveDocument acadObject)) (vla-get-ModelSpace acadDocument)) (vla-addCircle mSpace ’(3.0 3.0 0.0) 2.0))

The four statements in this example accomplished the following: 1 The first statement returned a pointer to the root AutoCAD object, the Application object. The pointer to the object was stored in variable acadObject. 2 The second statement obtained a pointer to the Document object, which is a property of the Application object. This provided access to the current AutoCAD drawing. The pointer to the Document object was stored in variable acadDocument. 3 The third statement obtained a pointer to the ModelSpace object, a property of the Document. The pointer to the ModelSpace object was stored in variable mSpace. 4 The last statement drew a circle in the ModelSpace. The hierarchical path traversed in the AutoCAD object model is pictured below:

Using ActiveX Objects with Visual LISP

274

Using Visual LISP Functions with ActiveX Methods Visual LISP contains an extensive set of functions to provide access to ActiveX objects. The function names are prefixed with vla-; for example, vla-addCircle, vla-get-ModelSpace, vla-getColor. Each vla- function corresponds to an ActiveX method or property. Visual LISP also contains ActiveX-related functions whose names are prefixed with vlax-. These are specialized ActiveX functions designed specifically for use within Visual LISP. There are vla- functions for all of the methods and properties described in the ActiveX Automation Reference. If your drawing contains custom ActiveX objects, you can use the vlax-invoke, vlax-get, and vlax-put functions to access their methods and properties. See the “AutoLISP Function Reference” for information on using these functions.

Determining the Visual LISP Function You Need The Visual LISP ActiveX functions actually provide access to ActiveX methods. For example, take another look at this AutoLISP statement, which adds a circle to a drawing: _$ (setq mycircle (vla-addCircle mSpace ’(3.0 3.0 0.0) 2.0)) #

The function that is called to draw the circle is vla-addCircle. If you did not know what function to use to add a circle to an AutoCAD drawing, you could figure it out by looking in the ActiveX Automation Reference. Look up the definition for a Circle object in the ActiveX Automation Reference. Here’s what the entry for a Circle object looks like:

Chapter 9

275

Advanced Topics

Sometimes, as in this Circle entry, there is descriptive text that identifies the method you need. Often, though, you’ll need to look through the list of Methods to find the one that matches the action you want to take. Once you’ve found the name of the method, add a vla- prefix to the method name in order to get the name of the Visual LISP function that implements the method. In this example, it is vla-AddCircle. Note that in Visual LISP the function name is not case sensitive; vla-addcircle is the same as vla-AddCircle.

Determining How to Call a Function Once you’ve identified the Visual LISP function you need, you still need to determine how to call the function. At the present time, there is no reference available defining the AutoLISP syntax for each function call. You need to look up the method in the ActiveX Automation Reference and derive the syntax from there. For example, from the reference page for the Circle object, click on the AddCircle hyperlink to view the definition of this method:

Using ActiveX Objects with Visual LISP

276

Note that you can also get to this page by clicking on the Methods button near the top of the Help window, and choosing AddCircle from a list of methods. The syntax definitions in the Automation Reference apply to the Visual Basic language. For AddCircle, the syntax is defined as: RetVal = object.AddCircle(Center, Radius)

Compare this to an equivalent function call in Visual LISP: (setq myCircle (vla-addCircle mSpace ’(3.0 3.0 0.0) 2.0))

The return value (RetVal, in Visual Basic) is straight-forward. The Automation Reference defines this as a Circle object. In Visual LISP, whenever an AutoCAD object is returned by an ActiveX function, it is stored as a VLA object data type. The object referred to before the method name (object.AddCircle) is always the first argument in a vla function call. This is the object you are viewing or modifying. For example, you add a circle to the drawing model space: (vla-addCircle

mSpace ...)

In this example, mspace refers to the ModelSpace object. Recall from the discussion on the AutoCAD object model (in “Accessing AutoCAD Objects” on page 271), that you use the properties of one AutoCAD object to access

Chapter 9

277

Advanced Topics

another object, in a hierarchical manner. The ModelSpace object provides access to the model space of the current drawing.

Translating Visual Basic Arguments to Visual LISP Arguments There are two parameters remaining to decipher. These are referred to as Center and Radius in the method definition. Center is said to be a Variant (3-element array of doubles) data type, and Radius is listed as a Double:

The ActiveX Automation Reference explains what these parameters are used for, but the data types it indicates for these parameters are Visual Basic data types. You need to convert these to Visual LISP data types. The following table shows how:

Visual Basic Data Type

Visual LISP Data Type

Boolean

INT (0 = False, Other = True)

Integer

INT

Integer

INT

Real

REAL

Double

REAL

String

STRING

Array

LIST

4 x 4 Array of Doubles

LIST of 4 LISTs = Transformation matrix

Object

VLA object

In looking up the Visual LISP data type for the Center argument, you need to convert the data type described in parentheses after the word Variant (3-element array of doubles). The table shows that an array in Visual Basic is a list in Visual LISP, and a double in Visual Basic is a real number in Visual

Using ActiveX Objects with Visual LISP

278

LISP. So the Center argument requires a list of real numbers. For example, a center point of 3.0 on the X and Y axes is: ’(3.0 3.0 0.0)

The Radius argument, a Double in Visual Basic, requires a real number in LISP. Here is a diagram of the translation from Visual Basic to Visual LISP:

When you use ActiveX functions within Visual LISP, you must always provide arguments that are of the data types specified in the ActiveX method definitions. Failure to do so (for example, passing an integer value when a real is required) may cause your program to crash. To convert points and matrices to the appropriate form, use the vlax-3D-point and vlax-tmatrix functions described in “Converting Arguments” on page 287.

Viewing and Updating Object Properties Visual LISP contains functions to read and update object properties. To demonstrate these functions, begin by entering the following at the Visual LISP Console prompt: (setq myCircle (vla-addcircle mspace (getpoint "\nPick the center point for a circle: ") 2.0))

Then pick a point in the AutoCAD drawing window. This will be the center point of the circle. You can use a Visual LISP function to identify the center point. Reading Object Properties Functions that read object properties are named with a vla-get prefix and require the following syntax: (vla-get-property object)

For example, vla-get-center returns the center point of a circle. You can use this function to draw a second circle concentric to the first: (vla-addCircle mSpace (vla-get-center myCircle) 1.0) #

The AutoCAD drawing window now contains the following objects:

Chapter 9

279

Advanced Topics

Updating Object Properties Functions that update properties are prefixed with vla-put and use the following syntax: (vla-put-property object new-value)

For example, vla-put-center changes the center point of a circle. The following sequence of function calls subtracts 1 unit from the X-axis of the original circle, then uses vla-put-center to update the circle with the new Xaxis: _$ (setq myCenter (vla-get-center myCircle)) (6.98607 4.52594 0.0) _$ (setq Xaxis (- (car myCenter) 1 )) ; 5.98607 _$ (setq newcenter (list Xaxis (cadr myCenter) (caddr myCenter))) (5.98607 4.52594 0.0) _$ (vla-put-center myCircle newcenter) nil

The AutoCAD drawing window shows the result:

Note that changing an object’s property may not immediately affect the display of the object in the AutoCAD drawing. AutoCAD delays property changes to allow you to change more than one property at a time. To explicitly update the drawing window, issue the vla-update function: (vla-update object)

Using ActiveX Objects with Visual LISP

280

Sometimes you can use pre-defined constants to update an object. For example, to set the fill color of a circle to red, you can use the constant “acRed“ instead of specifying a numeric index value: $ (vla-put-color myCircle acRed)

The AutoCAD ActiveX Automation Reference lists predefined constants in a section titled “Constants.“ You can use these constants in Visual LISP ActiveX function calls.

Determining If an Object Can be Accessed If other applications are working with AutoCAD objects at the same time your program is, those objects may not be accessible to your program. This is especially important to look out for if your application includes reactors, since reactors execute code segments in response to external events which cannot be predicted in advance (see “Attaching Reactors to AutoCAD Drawings” on page 290). But even a simple thing such as a locked layer can prevent you from changing an object’s properties. Visual LISP provides functions that allow you to test the accessibility of an object before you try to use it: ■ ■ ■

vlax-read-enabled-p tests whether you can read an object. vlax-write-enabled-p tests whether you can modify an object’s properties. vlax-erased-p check to see if an object has been erased. Erased objects may still exist in the drawing database.

These test functions return T if true, nil if false. The following examples test a line object: $ (vlax-read-enabled-p WhatsMyLine) T $ (vlax-write-enabled-p WhatsMyLine) T $ (vlax-erased-p WhatsMyLine) nil

After erasing the WhatsMyLine object: $ (vlax-read-enabled-p WhatsMyLine) nil $ (vlax-erased-p WhatsMyLine) T

Chapter 9

281

Advanced Topics

Using ActiveX Methods That Return Values in Arguments Some ActiveX methods require you to supply them with variables into which they can place values. The GetBoundingBox method is an example of this type of method. Here is how it is defined in the ActiveX Automation Reference:

Note that the MinPoint and MaxPoint parameters are described as output items of data type “3-element array of doubles.” In Visual LISP, this is a list data type. You need to provide these arguments as quoted variable names. The following example shows a Visual LISP function call to return the minimum and maximum bounding points of a circle, and the results of that call: _$ (vla-getboundingbox myCircle ’minpoint ’maxpoint) ((1.0 1.0 -1.0e-008) (5.0 5.0 1.0e-008)) _$ minpoint (1.0 1.0 -1.0e-008) _$ maxpoint (5.0 5.0 1.0e-008) _$

(Note that the quoted symbol parameters that you pass to the function become AutoLISP variables just like ones created through setq. Because of this, you should include them as local variables in your function definition so that they do not become global variables by default.)

Using ActiveX Objects with Visual LISP

282

Listing an Object’s Properties and Methods Earlier in this chapter, you saw how to use the Visual LISP Inspect tool to display an object’s properties. Another way to view an object’s properties is to call the vlax-dump-object function. You can invoke this function from the Visual LISP Console or in an application program. The vlax-dump-object function prints a list of the properties of the specified object. For example, the following code obtains an object from the model space and then issues vlax-dumpObject to print the object’s properties: _$ (setq WhatsMyLine (vla-item mSpace 2)) # _$ (vlax-dump-object WhatsMyLine) ; IAcadLWPolyline: AutoCAD Lightweight Polyline Interface ; Property values: ; Application (RO) = # ; Area (RO) = 15.6259 ; Closed = 0 ; Color = 256 ; Coordinates = (15.6022 6.26923 15.9361 3.73077 13.111 3.807 ... ) ; EntityName (RO) = "AcDbPolyline" ; EntityType (RO) = 24 ; Handle (RO) = "4E" ; Layer = "0" ; Linetype = "BYLAYER" ; LinetypeScale = 1.0 ; Normal = (0.0 0.0 1.0) ; ObjectID (RO) = 42009904 ; Thickness = 0.0 ; Visible = -1 T

There is an optional second argument you can supply to vlax-dump-object that causes it to also list all the methods that apply to the object. Simply specify “T” following the object name: (vlax-dump-object WhatsMyLine T)

Note that vlax-dump-object displays the information in the Console window or an AutoCAD text window, however the function returns either T or nil, not a list of strings containing the displayed information.

Determining if a Method or Property Applies to an Object Trying to use a method that does not apply to the specified object will result in an error. Trying to reference a property that does not apply to an object also results in an error. In instances where you are not sure what applies, use the vlax-method-applicable-p and vlax-property-available-p functions to test the objects. These functions return T if the method or property is available for the object, and nil if it is not. The syntax for vlax-method-applicable-p is:

Chapter 9

283

Advanced Topics

(vlax-method-applicable-p object method)

For example: _$ (vlax-method-applicable-p WhatsMyLine "copy") T _$ (vlax-method-applicable-p WhatsMyLine "AddBox") nil

For vlax-property-available-p, the syntax is: (vlax-property-available-p object property [T])

For example: _$ (vlax-property-available-p WhatsMyLine "Color") T _$ (vlax-property-available-p WhatsMyLine "center") nil

Supplying the optional “T” argument to vlax-property-available-p changes the meaning of the test. If you supply this argument, the function returns T only if the object has the property and the property can be modified. If the object has no such property or the property is read-only, vlax-property-available-p returns nil. For example, a circle contains an “area” property, but you cannot update it. If you check the property without specifying the optional argument, the result is T: _$ (vlax-property-available-p myCircle "area") T

If you supply the optional argument, the result is nil: _$ (vlax-property-available-p myCircle "area" T) nil

Working With Collection Objects The concept of collections was introduced in “Understanding the AutoCAD Object Model.” Recall that all ActiveX objects in the AutoCAD object model are grouped in collections. For example, the Blocks collection is made up of all blocks in an AutoCAD document. Visual LISP provides functions to help you work with collections of AutoCAD objects. These functions are vlax-map-collection and vlax-for. The vlax-map-collection function applies a function to every object in a collection. The syntax is: (vlax-map-collection collection-object function)

Using ActiveX Objects with Visual LISP

284

For example, to list all properties of every object in a drawing’s model space: $ (vlax-map-collection (vla-get-ModelSpace acadDocument) ’vlax-dumpObject) ; IAcadLWPolyline: AutoCAD Lightweight Polyline Interface ; Property values: ; Application (RO) = # ; Area (RO) = 3.67152 ; Closed = -1 ; Color = 256 ; Coordinates = (9.59247 4.44872 9.25814 5.34715 4.1991 5.679 ...) ; EntityName (RO) = "AcDbPolyline" ; EntityType (RO) = 24 ; Handle (RO) = "4C" ; Layer = "0" ; Linetype = "BYLAYER" ; LinetypeScale = 1.0 ; Normal = (0.0 0.0 1.0) ; ObjectID (RO) = 42009888 ; Thickness = 0.0 ; Visible = -1 ; IAcadCircle: AutoCAD Circle Interface ; Property values: ; Application (RO) = # ; Area (RO) = 0.661383 ; Center = (8.53948 4.91026 0.0) ; Color = 256 ; EntityName (RO) = "AcDbCircle" ; EntityType (RO) = 8 ; Handle (RO) = "4D" ; Layer = "0" ; Linetype = "BYLAYER" ; LinetypeScale = 1.0 ; Normal = (0.0 0.0 1.0) ; ObjectID (RO) = 42009896 ; Radius = 0.45883 ; Thickness = 0.0 ; Visible = -1

To evaluate a series of functions with each object in a collection, use vlax-for: (vlax-for symbol collection [expressions] ...)

Like the foreach function, vlax-for returns the result of the last expression evaluated inside the for loop. Note that modifying the collection (that is, adding or removing members) while iterating through it may cause an error.

Chapter 9

285

Advanced Topics

Here’s an example using vlax-for to show color statistics for each object in the active drawing: (defun show-Color-Statistics (/ objectColor colorSublist colorList) (setq modelSpace (vla-get-ModelSpace (vla-get-ActiveDocument (vlax-get-Acad-Object)) ) ) (vlax-for obj modelSpace (setq objectColor (vla-get-Color obj)) (if (setq colorSublist (assoc objectColor colorList)) (setq colorList (subst (cons objectColor (1+ (cdr colorSub list)))

colorSublist colorList ) ) (setq colorList (cons (cons objectColor 1) colorList)) ) ) (if colorList (progn (setq colorList (vl-sort colorList ’(lambda (lst1 lst2) (< (car lst1) (car lst2))) ) ) (princ "\nColorList = ") (princ colorList) (foreach subList colorList (princ "\nColor ") (princ (car subList)) (princ " is found in ") (princ (setq count (cdr subList))) (princ " object") (princ (if (= count 1) "." "s." ) ) ) ) ) (princ) )

Using ActiveX Objects with Visual LISP

286

Retrieving Member Objects in a Collection The Item method retrieves a member object in a collection. The Count property shows the number of items in a collection. Using the Item method and Count property, you can process each object in a collection individually. For example, you can test each object in a model space to determine what type of object it is, then process only the types you are interested in. The following code prints the start angle for each arc object in a model space: (setq index 0) (repeat (vla-get-count mspace) (if (= 4 (vla-get-entitytype (vla-item mspace index))) (progn (princ "\nThe start angle of the arc is ") (princ (vla-get-startangle (vla-item mspace index))) ) ) (setq index (+ index 1)) )

Note that Item and Count also apply to groups and selection sets.

Converting Arguments When creating AutoCAD entities using the command and entmake functions, AutoLISP allows a great deal of flexibility regarding the composition of coordinate data lists (that is, 2D or 3D points). When working with ActiveX functions, however, you must be very precise when passing these parameters. A 3D point must consist of three reals. To ensure that points are formatted correctly, you can use the vlax-3D-point function. The function syntax allows you to specify either a list representing a 2D or 3D point, or coordinate values: (vlax-3D-point ) (vlax-3D-point x y [z])

For example: _$ (setq aPoint(vlax-3D-point (list 1 2))) (1.0 2.0 0.0) $ (setq aPoint(vlax-3D-point 1 2)) (1.0 2.0 0.0)

The vlax-TMatrix function performs a similar task for transformation matrices, which are required by the vla-TransformBy function. It builds the transformation matrix from four lists of four numbers each, converting all numbers to reals, if necessary. For example: _$ (vlax-tmatrix (list(list 1 1 1 0)(list 1 2 3 0)(list 2 3 4 5)(list 2 9 8 3))) ((1.0 1.0 1.0 0.0) (1.0 2.0 3.0 0.0) (2.0 3.0 4.0 5.0) (2.0 9.0 8.0

Chapter 9

287

Advanced Topics

3.0))

Releasing Objects and Freeing Memory Just as you can have different symbols pointing to the same AutoCAD entity, you can have multiple VLA objects pointing to the same drawing object. As long as a VLA object points to a drawing object, AutoCAD keeps all the memory needed for the object. To free this memory when you no longer need to reference the object, use the vlax-release-object function: (vlax-release-object object)

After releasing an object, it is no longer accessible through the VLA object pointer. This is similar to closing a file. No memory is freed in Visual LISP when you issue vlax-release-object, but memory may be freed in AutoCAD when you have released all references to the object. To test whether an object has been released or not, use the vlax-object-released-p function: (vlax-object-released-p object)

This function returns T if the object has been released, nil if it has not. You can compare two VLA objects with the equal function. It returns T if both objects point to the same drawing object.

Converting Object References Visual LISP provides a function that allow you to convert entity names (enames) obtained through functions such as entget, to VLA objects you can use with ActiveX functions. VLISP also provides a function to convert a VLA object to an ename. To convert entity names to VLA objects, use the vlax-ename->vla-object function. For example: _$ (setq ename-circle (car (entsel "\nPick a Circle:")))

_$ (setq vlaobject-circle (vlax-ename->vla-object ename-circle)) #

To convert VLA objects to enames, use the vlax-vla-object->ename function. For example: $ (setq new-ename-circle (vlax-vla-object->ename vlaobject-circle))

Using ActiveX Objects with Visual LISP

288

You may find the same drawing object represented by different data types: a handle string, an ename, a VLA object, or an ARX Object ID integer. To convert between these types: ■

To find the handle associated with an ename, use the DXF 5 group of the ename’s association list: _$ (setq handle-circle (cdr (assoc 5 (entget ename-circle)))) "4F



To find the ename associated with a handle, use the handent function: _$ (handent handle-circle)



To find the VLA object associated with a handle, use the vla-handleToObject function:

$ (setq vla-circle (vla-handleToObject acadDocument handle-circle)) # ■

To find the handle associated with a VLA object, use vla-get-handle to obtain the handle property: $ (vla-get-handle vla-circle) "4F"



The ObjectID property identifies the ARX Object ID of a VLA object: _$ (setq 41878840

objid-Circle (vla-get-objectid vla-circle))

Finally, to translate from an ARX Object ID back to its VLA object, use the ObjectIDtoObject method on the AutoCAD Document object: _$ (vla-ObjectIDtoObject acadDocument objid-circle) #

Chapter 9

289

Advanced Topics

Attaching Reactors to AutoCAD Drawings A reactor is an object that you attach to AutoCAD drawing objects in order to have AutoCAD notify your application when events you are interested in occur. For example, if a user moves an entity that your application has attached a reactor to, your application will receive notification that the entity has moved. If you have designed it to do so, your application can react to this notification with appropriate actions, such as moving other entities associated with the one moved, or perhaps updating a text tag that records revision information on the drawing feature that was altered. A reactor communicates with your application by calling a function you have associated with the reactor. Such a function is referred to as a callback function. There isn’t anything particularly unusual about callback functions -- they are like other functions you write with Visual LISP. They become callback functions when you attach them to reactor events.

Reactor Types and Events There are several types of AutoCAD reactors, each corresponding to general categories of events your application can respond to: ■ ■





Linker Reactors notify your application every time an ARX application is loaded or unloaded. Editor Reactors notify you each time an AutoCAD command is invoked, a drawing opens, closes, or is saved, a DXF file is imported or exported, or a system variable changes value. Database Reactors notify your application when specific events occur to the drawing database, such as when an object has been added to the database. Object Reactors notify you each time a specific object is changed, copied, or deleted.

The function vlr-types returns a list of Visual LISP reactor types. Currently, the reactor types it returns are: ■ ■ ■ ■

:VLR-Linker-Reactor - linker reactor :VLR-Editor-Reactor - editor reactor :VLR-AcDb-Reactor - database reactor :VLR-Object-Reactor - object reactor

For each reactor type there are a number of callback events that notify your application under specific circumstances. For instance, when a drawing is saved, a :vlr-beginSave event occurs, the drawing is saved, and finally a

Attaching Reactors to AutoCAD Drawings

290

:vlr-saveComplete event occurs. In designing a reactor-based application, it is up to you to determine the events that you are interested in, and to write the callback functions to be triggered when these events occur.

The vlr-reaction-names function returns a list of all available events for a given reactor type: (vlr-reaction-names reactor type)

For example: $ (vlr-reaction-names :VLR-Editor-Reactor) (:vlr-unknownCommand :vlr-commandWillStart :vlr-commandEnded....

You can print out a list of all available reactor events, sorted by reactor type, by loading and running the following code in Visual LISP: (progn (foreach rtype (vlr-types) (terpri) (princ rtype) (foreach rname(vlr-reaction-names rtype) (terpri) (princ "\t") (princ rname ) ) ) (princ) )

The “AutoLISP Function Reference” lists the name and a brief description of each event available for a reactor type. For each reactor type, you can find this information by looking up the description of the function you use to define a reactor of that type. These functions are listed in “Creating Reactors” on page 292.

Defining Callback Functions A callback function is a regular AutoLISP function, which you define using defun. After you define a callback function, you link the function to an event by creating a reactor object. NOTE Some AutoLISP functions cannot be used within callback functions. You cannot call AutoCAD commands using the command function. Also note that to access drawing objects, you must use ActiveX functions (vla-*); entget and entmod are not allowed inside callback functions.

Chapter 9

291

Advanced Topics

Defining Linker, Editor, and Database Reactors Callback functions for linker, editor, and database reactors must be defined to accept two arguments. The first argument identifies the reactor object that called the function. The second argument is a list of parameters that is set by AutoCAD. The list of parameters is dependent on the type of event the function is associated with. For example, an event called :vlr-commandWillStart indicates that an AutoCAD command has been issued. A callback function that reacts to :vlr-commandWillStart will receive a parameter list containing the name of the AutoCAD command that triggered the event. A callback function that reacts on :vlr-sysVarChanged, on the other hand, receives a parameter list containing the name of a system variable (a string) and a flag indicating whether or not the change was successful. You can find a list of events for each reactor type, and the parameters associated with each event, in the “AutoLISP Function Reference.” The events are listed under the description of the functions used to define each type of reactor. These functions are listed in “Creating Reactors” on page 292

Defining Object Reactor Callback Functions Callback functions for object reactors must be defined to accept three arguments. The first argument identifies the object that fired the notification, the second identifies the reactor object that called the function, and the third is a list of parameters specific to the callback condition.

Using Predefined Callback Functions Visual LISP supplies you with two predefined callback functions: ■ ■

vlr-beep-reaction is a simple function that beeps your PC. vlr-trace-reaction prints a list of arguments to the Visual LISP Trace window each time a reactor fires this callback function.

Creating Reactors To add reactor functionality to your application, you first need to write a callback function that performs the tasks needed at the time of the reactor event. For example, here is a function named saveDrawingInfo that displays file

Attaching Reactors to AutoCAD Drawings

292

path and size information. This function will be attached to an editor reactor that will fire when an AutoCAD drawing is saved: (defun saveDrawingInfo (calling-reactor commandInfo / dwgname filesize) (setq dwgname (cadr commandInfo) filesize (vl-file-size dwgname) ) (alert (strcat "The file size of " dwgname " is " (itoa filesize) " bytes." ) ) (princ) )

The function retrieves the drawing name from the commandInfo parameter, then uses the vl-file-size function to retrieve the size of the drawing. The information is then displayed in an alert box in the AutoCAD window. NOTE After you activate a reactor and its callback function is executed, you may need to enter vlide at the AutoCAD Command prompt in order to return to Visual LISP. Simply switching focus to the Visual LISP window will not work. You link the callback function to an event when you create a reactor. There is a Visual LISP function to create each type of reactor. These functions are listed in the following table:

Function

Reactor Type

Arguments

vlr-acdb-reactor

Database

data - any AutoLISP data to be associated with a reactor object callbacks - a list of pairs (event-name . callback_function)

vlr-editor-reactor Editor

data - any AutoLISP data to be associated with the reactor object callbacks - a list of pairs(event-name . callback_function)

vlr-linker-reactor Linker

data - any AutoLISP data to be associated with the reactor object callbacks - a list of pairs (event-name . callback_function)

vlr-object-reactor Object

owners - AutoLISP list of VLA objects identifying valid drawing objects to be watched data - any AutoLISP data to be associated with the reactor object callbacks - a list of pairs (event-name . callback_function)

The table above indicates that the callbacks argument to these functions is a list of pairs naming the event and the callback function to be associated with

Chapter 9

293

Advanced Topics

that event. Possible events for each function are listed under the function’s entry in the “AutoLISP Function Reference.” All of these reactor construction functions return the reactor object. Editor reactors monitor AutoCAD commands such as the Save command. The following defines an editor reactor that responds to a user issuing a save by invoking the saveDrawingInfo function: (vlr-editor-reactor nil ’((:vlr-saveComplete . saveDrawingInfo)))

The first argument is nil because there is no application-specific data to attach to this reactor. The second argument is a list consisting of dotted pair lists. Each dotted pair list identifes an event the reactor is to be notified about, and the callback function to be run in response to that event. In this case only one event, :vlr-save-Complete, will be reacted to. Note that an editor reactor is notified each time the user issues a command, whether through the AutoCAD Command line, a menu, a toolbar, or through an AutoLISP program. So, the callback function for this editor reactor needs to determine precisely what it is responding to. In the current example, saveDrawingInfo simply checks for the Save command.

Using Object Reactors Unlike editor, database, and linker reactors, object reactors are attached to specific AutoCAD entities (objects). When you define an object reactor, you must identify the entity the reactor is to be attached to. The following code defines a callback function named print-radius. This function can be used to print the radius of a circle object. Note that the code uses the vlax-property-available-p function to verify that the drawing object that notified this function contains a “radius” property: (defun print-radius (notifier-object reactor-object parameter-list) (cond ( (vlax-property-available-p notifier-object "Radius" ) (princ "The radius is ") (princ (vla-get-radius notifier-object)) ) ) )

Attaching Reactors to AutoCAD Drawings

294

Here is some code to draw a circle: (setq myCircle ; Prompt the user for the center point and radius (progn (setq ctrPt (getpoint "\nCircle center point: ") radius (distance ctrPt (getpoint ctrpt "\nRadius: ") ) ) ; Add a circle to the drawing model space. Nest the function ; calls to obtain the path to the current drawing’s model ; space: AcadObject > ActiveDocument > ModelSpace (vla-addCircle (vla-get-ModelSpace (vla-get-ActiveDocument (vlax-get-acad-object)) ) ctrPt radius ) ) )

The code creates a variable called myCircle, which contains a pointer to the circle object that is drawn. Notice that an ActiveX method is used to draw the circle. This was not an arbitrary choice: you must use ActiveX methods to create or modify drawing objects from a callback function. ActiveX methods work with ActiveX (VLA) objects. To modify ename objects, such as those obtained through entlast and entsel functions, you must first convert them into VLA objects using the vlax-ename>vla-object function. The function that creates object reactors requires three arguments. The first argument is a list identifying the objects that are to fire notifications to the reactor. These objects are referred to as the owners of the reactor. The owners list must consist of VLA objects only; no enames are allowed. The second and third arguments are those accepted by all reactor types: application-specific data to attach to the reactor (if any), and a dotted pair list identifying the events to which to react and the callback function to be invoked by each event. Attaching a Reactor to Objects The following code attaches an object reactor to the myCircle object. It defines the reactor to respond whenever the object is modified (:vlr-modified) and to call the print-radius function in such an event: (setq circleReactor (vlr-object-reactor (list myCircle) “Circle Reactor” '((:vlr-modified . print-radius))))

Chapter 9

295

Advanced Topics

The reactor object is stored in variable circleReactor; you can refer to the reactor using this variable, as you’ll see below in “Querying, Modifying and Removing Reactors.” You may have noticed that the previous example included a string, “Circle Reactor,” in the call to vlr-object-reactor. You do not have to specify any data to be included with the reactor; you can specify nil instead. However, an object may have several reactors attached to it. Including an identifying text string, or other data that your application can use, allows you to distinguish among the different reactors attached to an object. If you load and run each of the code samples in this section in Visual LISP, you can test how the reactor works by altering the size of the circle drawn. NOTE If you do not disable all reactors before exiting AutoCAD, you may crash when you exit. See “Disabling Reactors” on page 299 for information on how to disable reactors.

Querying, Modifying and Removing Reactors There are various ways to obtain information about reactors. Visual LISP supplies functions to query reactors, and you can also use standard Visual LISP data inspection tools to view information on them. To receive a list of all reactors of a given type, use the vlr-reactors function: (vlr-reactors reactor-type)

For reactor-type, specify one of the values returned by the vlr-types function; these are listed in “Reactor Types and Events” on page 290. For example: _$ (setq reactorList (vlr-reactors :VLR-Object-Reactor)) (#)

In this case, the return value of the function, stored in variable reactorList, is a list containing a single object reactor pointer. This represents the reactor created using the functions in the previous section.

Inspecting Reactors You can examine reactors using the Visual LISP Inspector tool. For example, the object reactor defined in “Using Object Reactors” on page 294 was returned to a variable named “circleReactor”. If you open an Inspector window for this variable, Visual LISP displays the following information:

Attaching Reactors to AutoCAD Drawings

296

The object line indicates that the reactor is enabled (registered) in AutoCAD. The list items in the Inspector window show the following: ■ ■ ■

Event and associated callback function User data attached to the reactor Objects owning the reactor

Double-click on the item that begins with “{Owners}” to view a list of the owner objects:

Double-click on a list item to obtain detailed infomation about the object:

Querying Reactors Using Function Calls Visual LISP also provides functions to inspect a reactor definition from within an application program, or at the Console prompt: ■

vlr-type returns the type of the specified reactor. For example: $ (vlr-type circleReactor) :VLR-Object-Reactor



Chapter 9

297

vlr-current-reaction-name returns the name of the event that caused the callback function to be called.

Advanced Topics



vlr-data returns the application-specific data value attached to the reactor. You can use this to distinguish among multiple reactors that can fire the same callback function. $ (vlr-data circleReactor) "Circle Reactor"



vlr-owners returns a list of the objects in an AutoCAD drawing that fire notifications to an object reactor. _$ (vlr-owners circleReactor) (#)



vlr-reactions returns the callback list of condition-function pairs of the specified reactor. $ (vlr-reactions circleReactor) ((:vlr-modified . PRINT-RADIUS))

Modifying Reactors Visual LISP provides functions to modify reactor definitions: ■

vlr-reaction-set changes the callback function link for the specified reactor event. The function syntax is: (vlr-reaction-set reactor callback-condition ‘callback-function) For example, the following command changes the circleReactor reactor to call the print-area function when an object is modified: $ (vlr-reaction-set circleReactor :vlr-modified ’print-area) PRINT-AREA



vlr-data-set changes the application-specific data associated with the reactor. For example, the following call replaces the text string used to identify the circleReactor reactor: $ (vlr-data-set circleReactor "Circle Area Reactor") "Circle Area Reactor"

You can verify that the reactor has changed by using the Visual LISP Inspector feature. If the Inspector window shown in “Inspecting Reactors” on page 296 is still displayed in your Visual LISP session, right-click in the window’s object line and choose Update. If you’ve modified the circleReactor reactor as shown in this section, the updated Inspector window will look like the following:

Attaching Reactors to AutoCAD Drawings

298



vlr-owner-add adds a database object to the list of owners of the specified reactor. In the following example, an arc object named “archie” is added to the owner list of reactor circleReactor: $ (vlr-owner-add circleReactor archie) #

Now, if a user modifies the archie object, the callback function defined for reactor circleReactor is invoked. You can verify this by inspecting the reactor. Update the Inspector window for the circleReactor reactor, then right-click on the list item that begins with “{Owners}” and choose Inspect:

Both Arc and Circle objects are listed in the Inspector window. ■

vlr-owner-remove removes an owner object from the list of reactor owners. For example: $ (vlr-owner-remove circleReactor archie) #

Disabling Reactors If you want to disable a reactor, you need to remove it from AutoCAD. Note that the reactor object still exists. You can activate it again using the vlr-add function. To determine whether or not a reactor is active (registered to AutoCAD), use the vlr-added-p function: _$ (vlr-added-p circleReactor) T

The vlr-added-p function returns T, if the reactor is active, nil if it is not. ■

vlr-remove disables the specified reactor. For example, the following command disables reactor circleReactor: _$ (vlr-remove circleReactor) #

You can use vlr-added-p to verify that the circleReactor object reactor has been disabled: $ (vlr-added-p circleReactor) nil

To enable the circleReactor reactor, use vlr-add: $ (vlr-add circleReactor) #

Chapter 9

299

Advanced Topics



vlr-remove-all disables all reactors of the specified type. The following function call disables all object reactors: $ (vlr-remove-all :vlr-object-reactor) (#)

NOTE If you do not disable all reactors before exiting AutoCAD, you may crash upon exit.

Transient versus Persistent Reactors AutoCAD reactors may be transient or persistent. Transient reactors are lost when a drawing closes; this is the default reactor mode. Persistent reactors are saved with a drawing and exist when the drawing is next opened. NOTE Keep in mind that a reactor is only a link between an event and a callback function. While this link remains, the callback function itself is not part of the reactor and not part of the drawing. The reactors saved in the drawing are only usable if the callback functions are defined to Visual LISP. If you open a drawing containing Visual LISP reactor information and associated callback functions are not loaded, AutoCAD displays an error message. Visual LISP includes functions to make a reactor persistent, to release a persistent reactor, and to check if a reactor is persistent or not. ■ ■ ■

vlr-pers makes a reactor persistent. vlr-pers-release releases a persistent reactor. vlr-pers-p determines whether or not a reactor is persistent. It returns T if the reactor is persistent, nil if it is not.

Each function takes a reactor objects as its only argument. For example: _$ (vlr-pers-p circleReactor) nil

Attaching Reactors to AutoCAD Drawings

300

Chapter 9

301

Advanced Topics

A AutoLISP Function Reference

In this appendix The following is a catalog of all standard AutoLISP functions defined



Brief description of function’s use

by AutoCAD, along with additional functions supplied with Visual



Function syntax showing the order and type of arguments

LISP. The functions are listed alphabetically. In this chapter, each listing contains a brief description of the function’s use and a function syntax statement showing the order and the type of arguments required by the function. (For specific information on syntax statements, see AutoLISP Function Syntax.) Note that any functions, variables, or features not described here or in other parts of the documentation are subject to change in future releases.

302

The number argument needs additional information: a number can be a real number, an integer, or a symbol set to a real or integer value. If all arguments are integers, the result is an integer. If any of the arguments are real numbers, the integers are promoted to real numbers and the result is a real number. Most AutoLISP functions are always available; however, some are defined by a AutoLISP or ARX applications. The file that contains the externally defined functions is identified after the heading “Externally defined function.” Before you attempt to use these functions, you may want to test for their availability. The value returned by some functions is specified as indeterminate. This indicates that you cannot rely on using the value returned from this function.

+ (addition) Returns the sum of all numbers

(+ [number number] ...) If you supply only one number argument, this function returns the result of adding it to zero; it returns the number. Supplying no arguments returns 0. (+ 1 2) (+ 1 2 3 4.5) (+ 1 2 3 4.0)

returns 3 returns 10.5 returns 10.0

– (subtraction) Subtracts the second and following numbers from the first and returns the difference

(– [number number] ...) If you supply more than two number arguments, this function returns the result of subtracting the sum of the second through last numbers from the first number. If you supply

Appendix A AutoLISP Function Reference

303

only one number argument, this function returns the result of subtracting it from zero; it returns the number. Supplying no arguments returns 0. (- 50 40) (- 50 40.0) (- 50 40.0 2.5) (- 8)

returns 10 returns 10.0 returns 7.5 returns -8

* (multiplication) Returns the product of all numbers

(* [number number] ...) If you supply only one number argument, this function returns the result of multiplying it by one; it returns the number. Supplying no arguments returns 0. (* 2 3) (* 2 3.0) (* 2 3 4.0) (* 3 -4.5) (* 3)

returns 6 returns 6.0 returns 24.0 returns -13.5 returns 3

/ (division) Divides the first number by the product of the remaining numbers and returns the quotient

(/ [number number] ...) If you supply more than two number arguments, this function divides the first number by the product of the second through last numbers, and returns the final quotient. If you supply only one number argument, this function returns the result of dividing it by one; it returns the number. Supplying no arguments returns 0. (/ 100 2) (/ 100 2.0) (/ 100 20.0 2) (/ 100 20 2) (/ 4)

returns 50 returns 50.0 returns 2.5 returns 2 returns 4

* (multiplication)

304

= (equal to) Returns T if all arguments are numerically equal, and returns nil otherwise

(= numstr [numstr] ...) Each numstr argument can be a number or a string. (= 4 4.0) (= 20 388) (= 2.4 2.4 2.4) (= 499 499 500) (= "me" "me") (= "me" "you")

returns T returns nil returns T returns nil returns T returns nil

See also the eq and equal functions

/= (not equal to) Returns T if the arguments are not numerically equal, and nil if the arguments are numerically equal

(/= numstr [numstr] ...) Each numstr argument can be a number or a string. (/= 10 20) (/= "you" "you") (/= 5.43 5.44) (/= 10 20)

returns T returns nil returns T returns T

Appendix A AutoLISP Function Reference

305

< (less than) Returns T if each argument is numerically less than the argument to its right, and returns nil otherwise

(< numstr [numstr] ...) Each numstr argument can be a number or a string. (< 10 20) (< "b" "c") (< 357 33.2) (< 2 3 88) (< 2 3 4 4)

returns T returns T returns nil returns T returns nil

77 4 4)

returns T returns T returns nil returns T returns nil

>= (greater than or equal to) Returns T if each argument is numerically greater than or equal to the argument to its right, and returns nil otherwise

(>= numstr [numstr] ...) Each numstr argument can be a number or a string. (>= 120 17) (>= "c" "c") (>= 3.5 1792) (>= 77 4 4) (>= 77 4 9)

returns T returns T returns nil returns T returns nil

~ (bitwise NOT) Returns the bitwise NOT (1’s complement) of the argument

(~ int) (~ 3) (~ 100) (~ -4)

returns -4 returns -101 returns 3

Appendix A AutoLISP Function Reference

307

1+ (increment) Returns the argument increased by 1 (incremented)

(1+ number) (1+ 5) (1+ -17.5)

returns 6 returns -16.5

1– (decrement) Returns the argument reduced by 1 (decremented)

(1– number) (1- 5) (1- -17.5)

returns 4 returns -18.5

abs Returns the absolute value of the argument

(abs number) (abs 100) (abs -100) (abs -99.25)

returns 100 returns 100 returns 99.25

acad_colordlg Displays the standard AutoCAD color selection dialog box

(acad_colordlg colornum [flag]) The colornum argument is an integer in the range 0–256 (inclusive). It specifies the AutoCAD color number to display as the initial default. A colornum value of 0 defaults

1+ (increment)

308

to BYBLOCK, and a value of 256 defaults to BYLAYER. Setting the optional flag argument to nil disables the BYLAYER and BYBLOCK buttons. Omitting the flag argument or setting it to a non-nil value enables the BYLAYER and BYBLOCK buttons. The acad_colordlg function returns the user-selected color number. If the user cancels the dialog box, acad_colordlg returns nil. The following code prompts the user to select a color and specifies a default of green: (acad_colordlg 3)

Externally defined function acadapp ARX application

acad_helpdlg Invokes the help facility (obsolete)

(acad_helpdlg helpfile topic) This externally defined function has been replaced by the built-in function help. It is provided for compatibility with previous releases of AutoCAD. See “help” for a complete description of this function. Externally defined function acadr14.lsp AutoLISP function

acad_strlsort Sorts a list of strings by alphabetical order

(acad _strlsort list) The list argument is the list of strings to be sorted. The acad_strlsort function returns a list of the same strings in alphabetical order. If the list argument list is invalid or if there isn’t enough memory to do the sort, acad_strlsort returns nil. The following code sorts the list of abbreviated month names: (setq mos ’("Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec")) (acad_strlsort mos)

It returns the following list: ("Apr" "Aug" "Dec" "Feb" "Jan" "Jul"

Appendix A AutoLISP Function Reference

309

"Jun" "Mar" "May" "Nov" "Oct" "Sep")

Externally defined function acadapp ARX application

action_tile Assigns an action to evaluate when the user selects the specified tile in a dialog box

(action_tile key action-expression) The key and action-expression arguments are strings. The key argument is the name of the tile that triggers the action (specified as its key attribute). The key argument is case-sensitive. The action-expression is evaluated when the tile is selected. The action assigned by action_tile supersedes the dialog box’s default action (assigned by new_dialog) or the tile’s action attribute, if these are specified. The expression can refer to the tile’s current value (its value attribute) as $value, its name as $key, its application-specific data (as set by client_data_tile) as $data, its callback reason as $reason, and its image coordinates (if the tile is an image button) as $x and $y. You cannot call the AutoLISP command function from the action_tile function.

add_list Adds or modifies a string in the currently active dialog box list

(add_list string) Before using add_list, you must open the list and initialize it with a call to start_list. Depending on the operation specified in start_list, the string either is added to the current list or replaces the current list item. Assuming that the currently active DCL file has a popup_list or list_box with a key of longlist, the following code fragment initializes the list and adds to it the text strings in llist. (setq llist ’("first line" "second line" "third line")) (start_list "longlist") (mapcar ’add_list llist) (end_list)

action_tile

310

After the list has been defined, the following code fragment changes the text in the second line to "2nd line". (start_list "longlist" 1 0) (add_list "2nd line") (end_list)

See also the start_list and end_list functions

ads Returns a list of the currently loaded ADS applications

(ads) Each application and its path is a quoted string in the list. (ads) might return ("files/progs/PROG1" "PROG2")

See also the xload and xunload functions

alert Displays an alert box with the error or warning message passed as a string

(alert string) An alert box is a dialog box with a single OK button. (alert "That function is not available.")

You can display multiple lines by using the newline character in string. (alert "That function\nis not available.")

Line length and the number of lines in an alert box are platform, device, and window dependent. AutoCAD truncates any string that is too long to fit inside an alert box.

Appendix A AutoLISP Function Reference

311

alloc Sets the segment size to a given number of nodes

(alloc int) This function returns the previous segment size.

and Returns the logical AND of a list of expressions

(and expr ...) If any of the expressions evaluate to nil, this function ceases further evaluation and returns nil; otherwise it returns T. For example, given the assignments (setq a 103 b nil c "string")

then (and 1.4 a c) (and 1.4 a b c)

returns T returns nil

angle Returns an angle in radians of a line defined by two endpoints

(angle pt1 pt2) The angle is measured from the X axis of the current construction plane, in radians, with angles increasing in the counterclockwise direction. If 3D points are supplied, they are projected onto the current construction plane. (angle ’(1.0 1.0) ’(1.0 4.0)) returns 1.5708 (angle ’(5.0 1.33) ’(2.4 1.33) returns 3.14159

See also “Angular Conversion” on page 87.

alloc

312

angtof Converts a string representing an angle into a real (floating-point) value in radians

(angtof string [mode]) The string argument describes an angle based on the format specified by the mode argument. The mode argument, shown in the following table, specifies the units in which the string is formatted. The value should correspond to values allowed for the AutoCAD system variable AUNITS. If mode is omitted, angtof uses the current value of AUNITS. Angular units values Mode value

String format

0

Degrees

1

Degrees/minutes/seconds

2

Grads

3

Radians

4

Surveyor’s units

The string must be a string that angtof can parse correctly to the specified mode. It can be in the same form that angtos returns, or in a form that AutoCAD allows for keyboard entry. The angtof and angtos functions are complementary: if you pass angtof a string created by angtos, angtof is guaranteed to return a valid value, and vice versa (assuming the mode values match). If angtof succeeds, it returns a real value in radians; otherwise it returns nil.

Appendix A AutoLISP Function Reference

313

angtos Converts an angular value in radians into a string

(angtos angle [mode [precision]]) The angtos function takes angle (a real number, in radians) and returns it edited into a string according to the settings of mode, precision, the AutoCAD UNITMODE system variable, and the DIMZIN dimensioning variable. The mode and precision arguments are integers that specify the angular units mode and precision. Angular units values Mode value

String format

0

Degrees

1

Degrees/minutes/seconds

2

Grads

3

Radians

4

Surveyor’s units

The precision argument is an integer that selects the number of decimal places of precision desired. The mode and precision correspond to the AutoCAD system variables AUNITS and AUPREC. If you omit these arguments, angtos uses the current settings of AUNITS and AUPREC, respectively. The angtos function accepts a negative angle argument, but always reduces it to a positive value between zero and 2 pi radians before performing the specified conversion. (angtos 0.785398 0 4) returns "45.0000" (angtos -0.785398 0 4) returns "315.0000"

angtos

314

The UNITMODE variable affects the returned string when surveyor’s units are selected (a mode value of 4). If UNITMODE = 0, spaces are included in the string (for example, "N 45d E"); if UNITMODE = 1, no spaces are included in the string (for example, "N45dE"). Routines that use the angtos function to display arbitrary angles (those not relative to the value of ANGBASE) should check and consider the value of ANGBASE.

append Takes any number of lists and runs them together as one list

(append list ...) (append ’(a b) ’(c d)) returns (A B C D) (append ’((a)(b)) ’((c)(d))) returns ((A)(B)(C)(D))

apply Passes a list of arguments to a specified function

(apply ’function list) The apply function works with both built-in functions (subrs) and user-defined functions (those created with either defun or lambda). (apply ’+ ’(1 2 3)) returns 6 (apply ’strcat ’("a" "b" "c")) returns "abc"

Appendix A AutoLISP Function Reference

315

arx Returns a list of the currently loaded ARX applications

(arx) Each application and its path is a quoted string in the list. (arx) might return ("files/progs/PROG1" "PROG2")

See also the arxload and arxunload functions

arxload Loads an ARX application

(arxload application [onfailure]) The application argument is entered as a quoted string or as a variable that contains the name of an executable file. At the time the file is loaded, it is verified to be a valid ARX application. If the arxload operation fails, it normally causes an AutoLISP error. However, if the onfailure argument is supplied, arxload returns the value of this argument upon failure instead of an error message. If the application is successfully loaded, the application name is returned. (arxload "/myapps/appx") if successful, returns "/myapps/appx"

If you attempt to load an application that is already loaded, arxload issues the following message and returns the application name. Application "application" already loaded. You may want to check the currently loaded ARX applications with the arx function before using arxload.

arx

316

arxunload Unloads an ARX application

(arxunload application [onfailure]) If the application is successfully unloaded, the application name is returned, otherwise, an error message is issued. Enter application as a quoted string or as a variable containing the name of an application that was loaded with the arxload function. The application name must be entered exactly as it was entered for the arxload function. If a path (directory name) or extension was entered for the application in arxload, it can be omitted in the arxunload function. For example, the following code unloads the application appx, which was previously loaded with the arxload function: (arxunload "appx") if successful, returns "appx"

If the arxunload operation fails, it normally causes an AutoLISP error. However, if the onfailure argument is supplied, arxunload returns the value of this argument upon failure instead of issuing an error message. This feature of arxunload is similar to that in the arxload function.

ascii Returns the conversion of the first character of a string into its ASCII character code (an integer)

(ascii string) (ascii "A") (ascii "a") (ascii "BIG")

returns 65 returns 97 returns 66

This is similar to the ASC function in the BASIC language.

Appendix A AutoLISP Function Reference

317

assoc Searches an association list for an element and returns that association list entry

(assoc item alist) Searches the association list alist for item as the key element and returns the alist entry. If assoc does not find item as a key in alist, it returns nil. For example, given the code: (setq al ’((name box) (width 3) (size 4.7263) (depth 5)))

then (assoc ’size al) (assoc ’weight al)

returns (SIZE 4.7263) returns nil

Association lists are frequently used for storing data that can be accessed by a key. The subst function provides a convenient means of replacing the value associated with one key in an association list.

atan Returns the arctangent of a number in radians

(atan num1 [num2]) If you supply only one argument to atan, it returns the arctangent of num1, in radians. If you supply both num1 and num2 arguments, atan returns the arctangent of num1/num2, in radians. If num2 is zero, it returns an angle of plus or minus 1.570796 radians (+90 degrees× or –90 degrees), depending on the sign of num1. The range of angles returned is −pi/2 to +pi/2 radians. (atan 0.5) (atan 1.0) (atan -1.0) (atan 2.0 3.0) (atan 2.0 -3.0) (atan 1.0 0.0)

returns 0.463648 returns 0.785398 returns -0.785398 returns 0.588003 returns 2.55359 returns 1.5708

The angtos function converts the radian value returned from atan into a string value.

assoc

318

(angtos (atan -1.0) 0 4) returns "315.0000" (angtos (atan 2.0 3.0) 0 4) returns "33.6901" (angtos (atan 2.0 -3.0) 0 4) returns "146.3099" (angtos (atan 1.0 0.0) 0 4) returns "90.0000"

atof Returns the conversion of a string into a real number

(atof string) (atof "97.1") (atof "3") (atof "3.9")

returns 97.1 returns 3.0 returns 3.9

atoi Returns the conversion of a string into an integer

(atoi string) (atoi "97") (atoi "3") (atoi "3.9")

returns 97 returns 3 returns 3

atom Verifies that an item is an atom

(atom item) Returns nil if item is a list; returns T otherwise. Anything that’s not a list is considered an atom.

Appendix A AutoLISP Function Reference

319

For example, given the assignments (setq a ’(x y z)) (setq b ’a)

then (atom ’a) (atom a) (atom ’b) (atom b) (atom ’(a b c))

returns T returns nil returns T returns T returns nil

Some versions of LISP differ in their interpretation of atom, so take care when using converted code.

atoms-family Returns a list of the currently defined symbols

(atoms-family format [symlist]) The format argument is an integer value of 0 or 1. If the value of format is 0, atomsfamily returns the symbol names as a list. If format is 1, it returns the symbol names as a list of strings. The atoms-family function searches for a specific list of symbol names if you supply the symlist argument. The symlist argument is a list of strings that specify the symbol names. The atoms-family function returns a list of the type that is specified by format (symbols or strings) and that contains the names of the symbols that are defined. It returns nil for those that are not defined. (atoms-family 0)

returns a list of the currently defined symbols

The following code verifies that the symbols CAR, CDR, and XYZ have been defined, and returns the list as strings: (atoms-family 1 ’("CAR" "CDR" "XYZ"))

returns ("CAR" "CDR" nil)

The preceding return value shows that the symbol XYZ has not been defined.

atoms-family

320

autoarxload Predefines command names to load an associated ARX file

(autoarxload filename cmdlist) The filename argument is a string that specifies the .arx file that is loaded when one of the commands defined by the cmdlist argument is entered at the Command prompt. The cmdlist argument must be a list of strings. The autoarxload function returns nil. The following code defines the C:APP1, C:APP2, and C:APP3 functions to load the bounsapp.arx file. The first time one of the command, APP1, APP2, or APP3 are entered at the Command prompt the ARX application loads and the command continues. (autoarxload "BONUSAPP" ’("APP1" "APP2" "APP3"))

The commands listed by the cmdlst argument must be defined as commands by the file specified by filename.

Externally defined function acadr14.lsp AutoLISP function

autoload Predefines command names to load an associated AutoLISP file

(autoload filename cmdlist) The filename argument is a string that specifies the .lsp file that is loaded when one of the commands defined by the cmdlist argument is entered at the Command prompt. The cmdlist argument must be a list of strings. The autoload function returns nil.

Appendix A AutoLISP Function Reference

321

The following code defines the C:APP1, C:APP2, and C:APP3 functions to load the bounsapp.lsp file. The first time one of the command, APP1, APP2, or APP3 are entered at the Command prompt the AutoLISP file loads and the command continues. (autoload "BONUSAPP" ’("APP1" "APP2" "APP3"))

The commands listed by the cmdlst argument must be defined as commands by the file specified by filename.

Externally defined function acadr14.lsp AutoLISP function

autoxload Predefines command names to load an associated ADS application

(autoxload filename cmdlist) The filename argument is a string that specifies the ADS application that is loaded when one of the commands defined by the cmdlist argument is entered at the Command prompt. The cmdlist argument must be a list of strings. The autoxload function returns nil. The following code defines the C:APP1, C:APP2, and C:APP3 functions to load the bounsapp ADS application. The first time one of the command, APP1, APP2, or APP3 is entered at the Command prompt the ADS application loads and the command continues. (autoxload "BONUSAPP" ’("APP1" "APP2" "APP3"))

The commands listed by the cmdlst argument must be defined as commands by the file specified by filename.

Externally defined function acadr14.lsp AutoLISP function

autoxload

322

Boole Serves as a general bitwise Boolean function

(Boole func int1 int2 ...) The func argument is an integer between 0 and 15 representing one of the 16 possible Boolean functions in two variables. Successive integer arguments are bitwise (logically) combined based on this function and on the following truth table. Boolean truth table Int1

Int2

Func bit

0

0

8

0

1

4

1

0

2

1

1

1

Each bit of int1 is paired with the corresponding bit of int2, specifying one horizontal row of the truth table. The resulting bit is either 0 or 1, depending on the setting of the func bit that corresponds to this row of the truth table. If the appropriate bit is set in func, the resulting bit is 1; otherwise the resulting bit is 0. Some of the values for func are equivalent to the standard Boolean operations AND, OR, XOR, and NOT. Boole function bit values Func

Operation

Resulting bit is 1 if…

1

AND

Both input bits are 1

6

XOR

Only one of the two input bits is 1

7

OR

Either or both of the input bits are 1

8

NOR

Both input bits are 0 (1’s complement)

Appendix A AutoLISP Function Reference

323

The following specifies a logical AND of the values 12 and 5: returns 4

(Boole 1 12 5)

Similarly, the following specifies a logical XOR of the values 6 and 5: (Boole 6 6 5)

returns 3

You can use other values of func to perform other Boolean operations for which there are no standard names. For example, if func is 4, the resulting bits are set if the corresponding bits are set in int2 but not in int1. Thus (Boole 4 3 14)

returns 12

boundp Verifies if a value is bound to a symbol

(boundp sym) Returns T if sym has a value bound to it. If no value is bound to sym (or if it has been bound to nil), boundp returns nil. If sym is an undefined symbol, it is automatically created and is bound to nil. For example, given the assignments (setq a 2 b nil)

then (boundp ’a) (boundp ’b)

returns T returns nil

The atoms-family function provides an alternate method of determining the existence of a symbol without automatically creating the symbol.

boundp

324

car and cdr Returns the first element of a list or a list containing all but the first element of a list

(car list) and (cdr list) If list is empty, car returns nil. (car ’(a b c)) (car ’((a b) c)) (car ’())

returns A returns (A B) returns nil

If list is empty, cdr returns nil. (cdr ’(a b c)) (cdr ’((a b) c)) (cdr ’())

returns (B C) returns (C) returns nil

When the list argument is a dotted pair (see “cons”), cdr returns the second element without enclosing it in a list. (cdr ’(a . b)) (cdr ’(1 . "Text"))

returns B returns "Text"

AutoLISP supports concatenations of car and cdr up to four levels deep. The following are valid functions: caaaar

cadaar

cdaaar

cddaar

caaadr

cadadr

cdaadr

cddadr

caaar

cadar

cdaar

cddar

caadar

caddar

cdadar

cdddar

caaddr

cadddr

cdaddr

cddddr

caadr

caddr

cdadr

cdddr

caar

cadr

cdar

cddr

Appendix A AutoLISP Function Reference

325

These concatenations are the equivalent of nested calls to car and cdr. Each a represents a call to car, and each d represents a call to cdr. For example: (caar x) (cdar x) (cadar x) (cadr x) (cddr x) (caddr x)

is equivalent to (car (car x)) is equivalent to (cdr (car x)) is equivalent to (car (cdr (car x))) is equivalent to (car (cdr x)) is equivalent to (cdr (cdr x)) is equivalent to (car (cdr (cdr x)))

In AutoLISP, cadr is frequently used to obtain the Y coordinate of a 2D or 3D point (the second element of a list of two or three reals). Likewise, caddr can be used to obtain the Z coordinate of a 3D point. For instance, given the assignments (setq pt2 ’(5.25 1.0)) (setq pt3 ’(5.25 1.0 3.0))

a 2D point a 3D point

then (car pt2) (cadr pt2) (caddr pt2) (car pt3) (cadr pt3) (caddr pt3)

returns 5.25 returns 1.0 returns nil returns 5.25 returns 1.0 returns 3.0

chr Returns the conversion of an integer representing an ASCII character code into a single-character string

(chr integer) (chr 65) (chr 66) (chr 97)

returns "A" returns "B" returns "a"

This function is similar to the chr$ function in the BASIC language.

chr

326

client_data_tile Associates application-managed data with a dialog box tile

(client_data_tile key clientdata) The key argument is a string that specifies a tile. The key argument is case-sensitive. The data is a string specified by the clientdata argument. An action expression or callback function can refer to the string as $data.

close Closes an open file

(close file-desc) The file-desc argument is a file descriptor obtained from the open function. After a close, the file descriptor is unchanged but is no longer valid. Data added to an open file is not actually written until the file is closed. The close function returns nil if filedesc is valid, otherwise, it returns an error message. For example, the following code counts the number of lines in the file somefile.txt and sets the variable ct equal to that number. (setq fil "SOMEFILE.TXT") (setq x (open fil "r") ct 0) (while (read-line x) (setq ct (1+ ct)) ) (close x)

command Executes an AutoCAD command

(command [arguments] ...) The arguments argument represents AutoCAD commands and their options. The arguments to the command function can be strings, reals, integers, or points, as expected by the prompt sequence of the executed command. A null string ("") is equivalent to press-

Appendix A AutoLISP Function Reference

327

ing ENTER on the keyboard. Invoking command with no argument is equivalent to pressing Esc and cancels most AutoCAD commands. The command function returns nil. The command function evaluates each argument and sends it to AutoCAD in response to successive prompts. It submits command names and options as strings, 2D points as lists of two reals, and 3D points as lists of three reals. AutoCAD recognizes command names only when it issues a Command prompt. If you use the command function in an acad.lsp or MNL file, it should be called only from within a defun statement. Use the S::STARTUP function to define commands that need to be issued immediately when you begin a drawing session. The following example sets two variables pt1 and pt2 equal to two point values 1,1 and 1,5. It then uses the command function to issue the LINE command and pass the two point values. (setq pt1 ’(1 1) pt2 ’(1 5)) (command "line" pt1 pt2 "")

If your application is to be used with foreign language versions of AutoCAD, command names must be prefixed with an underscore (_) so they can be translated. If you are using the dot prefix (to avoid using redefined commands), you can place the dot and underscore in either order; both "._line" and "_.line" are valid. Commands executed from the command function are not echoed to the command line if the CMDECHO system variable (accessible from setvar and getvar) is set to 0. The getxxx user-input functions (getangle, getstring, getint, getpoint, and so on) cannot be used inside the command function. An attempt to do so results in the following message and terminates the function in progress. error: AutoCAD rejected function If user input is needed, issue the getxxx functions beforehand, or place them between successive command function calls. For AutoCAD commands that require the selection of an object (like the BREAK and TRIM commands), you can supply a list obtained with entsel instead of a point to select the object. The AutoCAD DTEXT and SKETCH commands read the keyboard and digitizer directly and therefore cannot be used with the AutoLISP command function. If the ’SCRIPT command is used with the command function, it should be the last function call in the AutoLISP routine. An UNDO Group is explicitly created around each command used with the command fucntion. If a user enters U (or UNDO) after running an AutoLISP routine, only the last command will be undone. Additional entries of UNDO will step backwards through the

command

328

commands used in that routine. If you want a group of commands to be considered a group (or the entire routine), use the UNDO Begin and UNDO End options. Using the PAUSE Symbol If an AutoCAD command is active and the predefined symbol PAUSE is encountered as an argument to the command function, the command function is suspended to allow direct user input. The PAUSE symbol is defined as a string consisting of a single backslash. You can use a backslash instead of the PAUSE symbol. However, if the command function is invoked from a menu item, the backslash suspends the reading of the menu item, which results in partial evaluation of the AutoLISP expression. Also, the pause mechanism might require a different trigger value in future versions of AutoLISP, so it is recommended that you always use the PAUSE symbol rather than an explicit backslash. When a backslash (\) is used in a string, it must be preceded by another backslash (\\). If PAUSE is encountered when a command is expecting input of a text string or an attribute value, AutoCAD pauses for input only if the TEXTEVAL system variable is nonzero. Otherwise, AutoCAD does not pause for user input but uses the value of the PAUSE symbol (a single backslash) text. When the command function pauses for user input, the function is considered active, so the user cannot enter another AutoLISP expression to be evaluated. The following is an example of using the PAUSE symbol (the layer NEW_LAY and the block MY_BLOCK must exist in the drawing prior to testing this code): (setq blk "MY_BLOCK") (setq old_lay (getvar "clayer")) (command "layer" "set" "NEW_LAY" "") (command "insert" blk pause "" "" pause) (command "layer" "set" old_lay "")

Appendix A AutoLISP Function Reference

329

The preceding code fragment sets the current layer to NEW_LAY, pauses for user selection of an insertion point for the block MY_BLOCK (which is inserted with X and Y scale factors of 1) and pauses again for user selection of a rotation angle. The current layer is then reset to the original layer. If the command function specifies a PAUSE to the SELECT command and a PICKFIRST set is active, the SELECT command obtains the PICKFIRST set without pausing for the user.

The Radius and Diameter subcommands of the Dim prompt issue additional prompts in some situations. This can cause a failure of AutoLISP programs written prior to Release 11 that use these commands.

cond Serves as the primary conditional function for AutoLISP

(cond (test1 result1 ...) ...) The cond function accepts any number of lists as arguments. It evaluates the first item in each list (in the order supplied) until one of these items returns a value other than nil. It then evaluates those expressions that follow the test that succeeded, and returns the value of the last expression in the sublist. If there is only one expression in the sublist (that is, if result is missing), the value of the test expression is returned. The following example uses cond to perform an absolute value calculation: (cond ((minusp a) (- a)) (t a) )

If the variable a is set to the value –10, this returns 10.

cond

330

As shown, cond can be used as a case type function. It is common to use T as the last (default) test expression. Here’s another simple example. Given a user response string in the variable s, this function tests the response and returns 1 if it is Y or y, 0 if it is N or n, and nil otherwise. (cond ((= s "Y") 1) ((= s "y") 1) ((= s "N") 0) ((= s "n") 0) (t nil) )

cons Constructs basic lists

(cons new-first-element list) The cons function takes an element (new-first-element) and a list, and returns the addition of that element to the beginning of the list. The first element can be an atom or a list. (cons ’a ’(b c d)) (cons ’(a) ’(b c d))

returns (A B C D) returns ((A) B C D)

The cons function also accepts an atom in place of the list argument, constructing a structure known as a dotted pair. When displaying a dotted pair, AutoLISP prints a period, or dot, between its first and second elements. You can use the cdr function to return the second atom of a dotted pair. (cons ’a 2) (car (cons ’a 2)) (cdr (cons ’a 2))

returns (A . 2) returns A returns 2

A dotted pair is a special kind of list and is not accepted as an argument by some functions that handle ordinary lists.

Appendix A AutoLISP Function Reference

331

cos Returns the cosine of an angle expressed in radians

(cos ang) (cos 0.0) (cos pi)

returns 1.0 returns -1.0

cvunit Converts a value from one unit of measurement to another

(cvunit value from to) The value argument is the numeric value that you want to convert. It can also be a list containing two or three numbers to be conrted (a 2D or 3D point). The from argument is the unit that the value is being converted from, and to is the unit that the value is being converted into. The from and to arguments can name any unit type found in the acad.unt file. If successful, cvunit returns the converted value. If either unit name is unknown (not found in the acad.unt file), or if the two units are dimensionally incompatible (as in converting grams into years), cvunit returns nil. (cvunit 1 "minute" "second") returns 60.0 (cvunit 1 "gallon" "furlong") returns nil (cvunit 1.0 "inch" "cm") returns 2.54 (cvunit 1.0 "acre" "sq yard") returns 4840.0 (cvunit ’(1.0 2.5) "ft" "in") returns (12.0 30.0) (cvunit ’(1 2 3) "ft" "in") returns (12.0 24.0 36.0)

If you have several values to convert in the same manner, it is more efficient to convert the value 1.0 once and then apply the resulting value as a scale factor in your own function or computation. This works for all predefined units except temperature, where an offset is involved as well.

cos

332

defun Defines a function

(defun sym argument-list expr ...) The defun function defines a function with the name sym (the function name is automatically quoted). Following the function name is a list of arguments (possibly void), optionally followed by a slash and the names of one or more local symbols for the function. The slash must be separated from the first local symbol and from the last argument, if any, by at least one space. If you don’t declare any arguments or local symbols, you must supply an empty set of parentheses after the function name. The following argument-list examples show valid and invalid values: (defun myfunc (x y) ...) Function takes two arguments (defun myfunc (/ a b) ...) Function has two local symbols (defun myfunc (x / temp) ...) One argument, one local symbol (defun myfunc () ...) No arguments or local symbols

You cannot define a function with multiple arguments of the same name. But you can have one argument that defines a local variable with the same name as another local variable or with the same name as one of the arguments: (defun fubar (a a / b) ...) Not legal (defun fubar (a b / a a b) ...) Legal, but useless

If the argument/symbol list contains duplicate entries, the first occurrence of each name is used and the following occurrences are ignored. One or more expressions following the list of arguments and local symbols are evaluated when the function is executed. The defun function returns the name of the function being defined. When the defined function is invoked, its arguments are evaluated and bound to the argument symbols. You can use the local symbols within the function without changing their bindings at outer levels. The function returns the result of the last expression evaluated. All previous expressions have only side effects.

Appendix A AutoLISP Function Reference

333

The following examples define new functions with defun and show the values returned by the new functions: (defun add10 (x) (+ 10 x) ) (add10 5) (add10 -7.4)

returns ADD10 returns 15 returns 2.6

and (defun dots (x y / temp) (setq temp (strcat x "...")) (strcat temp y) ) returns DOTS (dots "a" "b") returns "a...b" (dots "from" "to") returns "from...to"

Never use the name of a built-in function or symbol as sym. This makes the built-in function inaccessible. To get a list of built-in and previously defined functions, see “atomsfamily.”

See also “Symbol and Function Handling.”

dictadd Adds a nongraphical object to the specified dictionary

(dictadd ename symbol newobj) Adds the object newobj to the dictionary ename. The symbol argument is the key name of the object to be added to the dictionary; symbol must be a unique name that does not already exist in the dictionary. The object specified by newobj corresponds only to a nongraphical object. As a general rule, each object added to a dictionary must be unique to that dictionary. This is specifically a problem when adding group objects to the group dictionary. Adding the same group object using different key names results in duplicate group names which can send the dictnext function into an infinite loop.

dictadd

334

dictnext Finds the next item in a dictionary

(dictnext ename [rewind]) The ename argument is an entity name that specifies a dictionary object to search. When dictnext is used repeatedly, it returns the next entry in the specified dictionary each time. The dictsearch function specifies an entry to retrieve. If the rewind argument is present and evaluates to a non-nil value, the dictionary is rewound and the first entry in it is retrieved. When there are no more entries in the dictionary, nil is returned. Deleted dictionary entries are never returned. See “namedobjdict” for the master dictionary entity name. Once you have begun stepping through the contents of a dictionary, passing a different dictionary name to dictnext will cause the place to be lost in the original dictionary. In other words, only one global iterator is maintained for use in this function. If an entry is found, it is returned as a list of dotted pairs of DXF-type codes and values.

dictremove Removes an entry from the specified dictionary

(dictremove ename symbol) Removes the dictionary entry specified by symbol from the dictionary specified by ename. If ename is invalid or symbol is not found, dictremove returns nil. If successful, dictremove returns the entity name of the removed entry.

Appendix A AutoLISP Function Reference

335

By default, removing an entry from a dictionary does not delete it from the database. This must be done with a call to entdel. Currently the exceptions to this rule are groups and mlinestyles. The code that implements these features requires that the database and these dictionaries be up to date, and therefore automatically deletes the entity when it is removed (with dictremove) from the dictionary. The dictremove function disallows the removal of an mlinestyle from the mlinestyle dictionary if it is actively referenced by an mline in the database.

dictrename Renames a dictionary entry

(dictrename ename oldsym newsym) Renames a dictionary entry’s key name from oldsym to newsym. The dictionary is specified by ename. If the oldname is not present in the dictionary, ename is invalid, newname is invalid, or newname is already present in the dictionary. dictrename returns nil.

dictsearch Searches a dictionary for an item

(dictsearch ename symbol [setnext]) The ename argument is an entity name that specifies a dictionary object to search. The symbol argument is a string that specifies the item within the dictionary. If dictsearch finds an entry for the given item, it returns that entry in the format described for dictnext. If no such entry is found, it returns nil. Normally, dictsearch has no effect on the order of entries retrieved by dictnext. However, if dictsearch is successful and the setnext argument is present and nonnil, the dictnext entry counter is adjusted so that the following dictnext call returns the entry after the one returned by this dictsearch call. The following example uses dictsearch to retrieve the definition list of the G2 group (this code assumes that a group named G2 exists in the current drawing). (setq grp (dictsearch (namedobjdict) "ACAD_GROUP"))

dictrename

336

(setq g2 (dictsearch (cdr (assoc -1 grp)) "G2"))

See “namedobjdict” for the master entity name.

dimx_tile and dimy_tile Retrieves the dimensions of a tile in dialog box units

(dimx_tile key) and ( dimy_tile key) The dimx_tile function returns the width of the tile, and dimy_tile returns its height. For both functions, the key argument is a string that specifies the tile. The key argument is case-sensitive. The coordinates returned are the maximum allowed within the tile; because coordinates are zero based, these functions return one less than the total X or Y dimension (X–1 and Y–1). The dimx_tile and dimy_tile functions are provided for use with vector_image, fill_image, and slide_image, which require you to specify absolute tile coordinates.

distance Returns the 3D distance between two points

(distance pt1 pt2) (distance ’(1.0 2.5 3.0) ’(7.7 2.5 3.0)) returns 6.7 (distance ’(1.0 2.0 0.5) ’(3.0 4.0 0.5)) returns 2.82843

If one or both of the supplied points is a 2D point, then distance ignores the Z coordinates of any 3D points supplied and returns the 2D distance between the points as projected into the current construction plane.

Appendix A AutoLISP Function Reference

337

distof Converts a string that represents a real (floating-point) value into a real value

(distof string [mode]) The mode argument specifies the units in which the string is formatted. The value should correspond to values allowed for the AutoCAD system variable LUNITS, as shown in the following table. If mode is omitted, distof uses the current value of LUNITS. Linear units values Mode value

String format

1

Scientific

2

Decimal

3

Engineering (feet and decimal inches)

4

Architectural (feet and fractional inches)

5

Fractional

The argument string must be a string that distof can parse correctly to the mode specified by mode. It can be in the same form that rtos returns, or in a form that AutoCAD allows for keyboard entry. The distof and rtos functions are complementary. If you pass distof a string created by rtos, distof is guaranteed to return a valid value, and vice versa (assuming the mode values are the same). The distof function treats modes 3 and 4 the same. That is, if mode specifies 3 (engineering) or 4 (architectural) units, and string is in either of these formats, distof returns the correct real value. If distof succeeds, it returns a real number; otherwise it returns nil.

distof

338

done_dialog Terminates a dialog box

(done_dialog [status]) You must call done_dialog from within an action expression or callback function (see “action_tile”). If you specify the optional status argument, it must be a positive integer, which start_dialog will return instead of returning 1 for OK or 0 for Cancel. The meaning of any status value greater than 1 depends on your application. The done_dialog function returns a two-dimensional point list that is the (X,Y) location of the dialog box when the user exited it. You can pass this point to a subsequent new_dialog call to reopen the dialog box in the user-selected location. If you provide a callback for the button whose key is "accept" or "cancel" (usually the OK and Cancel buttons), the callback must call done_dialog explicitly. If it doesn’t, the user can be trapped in the dialog box. If you don’t provide an explicit callback for these buttons and use the standard exit buttons, AutoCAD handles them automatically. Also, an explicit AutoLISP action for the “accept” button must specify a status of 1 (or an application-defined value); otherwise, start_dialog returns the default value, 0, which makes it appear as if the dialog box was canceled.

end_image Ends creation of the currently active dialog box image

(end_image) This function is the complement of start_image.

Appendix A AutoLISP Function Reference

339

end_list Ends processing of the currently active dialog box list

(end_list) This function is the complement of start_list.

entdel Deletes objects (entities) or undeletes previously deleted objects

(entdel ename) The entity specified by ename is deleted if it is currently in the drawing. The entdel function undeletes the entity (restores it to the drawing) if it has been deleted previously in this editing session. Deleted entities are purged from the drawing when the drawing is exited. The entdel function can delete both graphical and non-graphical entities. (setq e1 (entnext)) ;Sets e1 to the name of the first ;entity in the drawing (entdel e1) ;Deletes entity e1 (entdel e1) ;Undeletes (restores) deleted entity e1

The entdel function operates only on main entities. Attributes and polyline vertices cannot be deleted independently of their parent entities. You can use the command function to operate the ATTEDIT or PEDIT commands to achieve modify subentities. You cannot delete entities within a block definition. However, you can completely redefine a block definition, minus the entity you want deleted, with entmake.

end_list

340

entget Retrieves an object’s (entity’s) definition data

(entget ename [applist]) The entget function returns a list containing the entity definition data of the entity ename. This applies to both graphical and non-graphical entities. If you supply applist, an optional list of registered application names, entget also returns the extended data associated with the specified applications. The data returned by entget is coded as an association list, from which you can extract items by using the assoc function. Objects in the list are assigned AutoCAD DXF group codes for each part of the entity data. Assume that the last object created in the drawing is a line drawn from point (1,2) to point (6,5). You can retrieve the entity name of the last object with the entlast function, and pass that name to entget. (entget (entlast))

This might return the following: ((-1 . ) Entity name (0 . "LINE") Object type (8 . "0") Layer (10 1.0 2.0 0.0) Start point (11 6.0 5.0 0.0) Endpoint )

The DXF group codes used by AutoLISP differ slightly from the group codes in a DXF file. As with DXF, entity header items (color, linetype, thickness, the attributes-follow flag, and the entity handle) are exported only if they have nondefault values. Unlike DXF, optional entity definition fields are exported whether they are equal to their defaults or not. This simplifies processing. Programs can always assume these fields to be present for general algorithms that operate on them. Also unlike DXF, associated X, Y, and Z coordinates are grouped together into one point list, as in (10 1.0 2.0 3.0), rather than appearing as separate 10, 20, and 30 groups.

Appendix A AutoLISP Function Reference

341

The –1 item at the start of the list contains the entity name of this entity. The individual dotted pairs that represent the values can be extracted by assoc, using cdr to pull out their values. The sublists for points are not dotted pairs like the rest. The convention is that the cdr of the sublist is the group’s value. Because a point is a list of two (or three) reals, the entire group is a three- (or four-) element list. The cdr of the group is the list representing the point, so the convention that cdr always returns the value is preserved. When writing functions to process these entity lists, be sure to make them insensitive to the order of the sublists. Use assoc to guarantee this. The –1 group containing the entity’s name allows modification operations to accept the entity list, and avoids the need to keep the entity name in a parallel structure. A seqend entity at the end of a polyline or a set of attributes contains a –2 group whose cdr is the entity name of the header of this entity. This allows the header to be found from a subentity by walking forward to the Seqend and then using the cdr of the –2 group as the entity name to retrieve the associated main entity.

Before performing an entget on vertex entities, you should read or write the polyline entity’s header. If the most recently processed polyline entity is different from the one to which the vertex belongs, width information (the 40 and 41 groups) can be lost.

All points associated with an object are expressed in terms of that object’s Object Coordinate System (OCS). For point, line, 3dline, 3dface, 3dpolyline, 3dmesh, and dimension objects, the OCS is equivalent to the WCS (the object points are World points). For all other objects, the OCS can be derived from the WCS and the object’s extrusion direction (its 210 group). When working with objects that have been drawn using coordinate systems other than the WCS, you might need to convert the points to the WCS or to the current UCS by using the trans function.

entget

342

entlast Returns the name of the last nondeleted main object (entity) in the drawing

(entlast) The entlast function is frequently used to obtain the name of a new entity that has just been added with the command function. The entity need not be on the screen or on a thawed layer to be selected. Sets e1 to the name of the last main entity in the drawing (setq e2 (entnext e1)) Sets e2 to nil (or to an attribute or vertex subentity name) (setq e1 (entlast))

If your application requires the name of the last nondeleted entity (main entity or subentity), define a function such as the following and call it instead of entlast. (defun lastent (/ a b) (if (setq a (entlast)) Gets last main entity (while (setq b (entnext a)) If subentities follow, loops (setq a b)

until there are no more subentities

) ) a )

Returns last main entity or subentity

entmake Creates a new entity (graphical object) in the drawing

(entmake [elist]) The elist argument must be a list of entity definition data in a format similar to that returned by the entget function. The elist argument must contain all of the information necessary to define the entity. The entmake function can define both graphical and nongraphical entities. If any required definition data is omitted, entmake returns nil and the entity is rejected. If you omit optional definition data (such as the layer), entmake uses the default value. If entmake successfully creates a new entity, it returns the entity’s list of definition data. If entmake is unable to create the entity, it returns nil. One method of creating a new entity is by obtaining an entity’s definition data with the entget function, modifying it, and then passing the revised data to the entmake func-

Appendix A AutoLISP Function Reference

343

tion. Before creating a new entity, entmake verifies that a valid layer name, linetype name, and color are supplied. If a new layer name is introduced, entmake automatically creates the new layer. The entmake function also checks for block names, dimension style names, text style names, and shape names if the entity type requires them. The entity type (for example, CIRCLE or LINE) must be the first or second field of the elist. If it is the second field, it can be preceded only by the entity name. This is the format returned by entget. In such cases, it ignores the entity name when the new entity is created. If the elist contains an entity handle, it also is ignored. The following code creates a red circle, centered at (4,4) with a radius of 1. The optional layer and linetype fields have been omitted and therefore assume default values. (entmake ’((0 . "CIRCLE") Entity type (62 . 1) Color (10 4.0 4.0 0.0) Center point (40 . 1.0) Radius ) )

Objects created on a frozen layer are not regenerated until the layer is thawed. Complex Entities A complex entity (a block definition, a polyline, or a block reference containing attributes) can be created by several entmake calls to define its subentities (attributes or vertices). When entmake sees that a complex entity is being created, it creates a temporary file to gather the definition data. For each entmake, a check is performed to see if the temporary file exists; if so, the new data is appended to the file. When the definition of the complex entity is complete (by appending the appropriate seqend or endblk entity), the supplied data is rechecked and the complex entity is added to the drawing. Completion of a block definition (entmake of an endblk) returns the block’s name rather than the entity data list normally returned. You cannot create viewport objects with entmake.

entmake

344

If data is received that is invalid for that entity type, the entity is rejected as well as the entire complex entity. A block definition cannot be nested, nor can it reference itself. However, it can contain references to other block definitions. All entities of a complex entity can exist in either model space or paper space, but not both. A group 66 code is honored only for insert objects (meaning attributes follow). For polyline entities, the group 66 code is forced to a value of 1 (meaning vertices follow), and for all other entities it takes a default of 0. The only entity that can follow a polyline entity is a vertex entity. No portion of a complex entity is displayed on your drawing until its definition is complete. You can cancel the creation of a complex entity by entering entmake with no arguments. This clears the temporary file and returns nil. The block and endblk entities can be used to create a new block definition. Newly created blocks are automatically entered into the symbol table where they can be referenced. Applications can represent polygons with an arbitrarily large number of sides in polyface meshes. However, the AutoCAD entity structure imposes a limit on the number of vertices that a given face entity can specify. You can represent more complex polygons by dividing them into triangular wedges. AutoCAD represents triangular wedges as four-vertex faces where two adjacent vertices have the same value. Their edges should be made invisible to prevent visible artifacts of this subdivision from being drawn. The PFACE command performs this subdivision automatically, but when applications generate polyface meshes directly, the applications must do this themselves. The number of vertices per face is the key parameter in this subdivision process. The PFACEVMAX system variable provides an application with the number of vertices per face entity. This value is read-only and is set to 4.

When entmake creates a block, it can overwrite an existing block. The entmake function does not check for name conflicts in the block definitions table, so before you use it, use the tblsearch function to ensure that the name of the new block is unique. However, using entmake to redefine anonymous blocks, as described in the following section, can be useful.

Anonymous Blocks The block definitions table in a drawing can contain anonymous blocks. Anonymous blocks are created to support hatch patterns and associative dimensioning. They can also be created by entmake for the application’s own purposes, usually to contain entities that the user cannot access directly. The group code 2 (block name) of a dimension entity is optional for the entmake function. If the block name is omitted from the entity definition list, AutoCAD creates a new one. Otherwise, AutoCAD creates the dimension using the name provided.

Appendix A AutoLISP Function Reference

345

The name (group 2) of an anonymous block is *Unnn, where nnn is a number generated by AutoCAD. Also, the low-order bit of an anonymous block’s Block type flag (group 70) is set to 1. When entmake creates a block whose name begins with * and whose anonymous bit is set, AutoCAD treats this as an anonymous block and assigns it a name. Characters following the * in the name string passed to entmake are ignored. After the block is created, entmake returns its name. If you are creating the block by multiple entmake calls, it returns the name after a successful call of (entmake "endblk")

Whenever a drawing is opened, all unreferenced anonymous blocks are purged from the block definitions table. Referenced (inserted) anonymous blocks are not purged. You can use entmake to create a block reference (Insert) to an anonymous block (you cannot pass an anonymous block to the INSERT command). You can also use entmake to redefine the block. The entities in a block (but not the block entity itself) can be modified with entmod. Although a referenced anonymous block becomes permanent, the numeric portion of its name can change between drawing sessions. Applications cannot rely on anonymous block names remaining constant.

entmakex Makes a new object or entity, gives it a handle and entity name (but, does not assign an owner), and then returns the new entity name

(entmakex [elist]) The elist argument must be a list of entity definition data in a format similar to that returned by the entget function. The elist argument must contain all of the information necessary to define the entity or object. The entmakex function can define both graphical and nongraphical objects. If any required definition data is omitted, entmakex returns nil and the object is rejected. If you omit optional definition data (such as the layer), entmakex uses the default values. If entmakex successfully creates a new entity, it returns the entity name. If entmakex is unable to create the entity, it returns nil.

Objects and entities without owners are not written out to .dwg or .dxf files. Be sure to set an owner at some point after using entmakex. For example, you can use dictadd to set a dictionary to own an object.

entmakex

346

entmod Modifies the definition data of an object (entity)

(entmod elist) The entmod function is passed a list (elist) in the format returned by entget, and it updates the database information for the entity name specified by the –1 group in elist. The primary mechanism through which AutoLISP updates the database is by retrieving entities with entget, modifying the list defining an entity, and updating the entity in the database with entmod. The entmod function can modify both graphical and nongraphical objects. (setq en (entnext)) (setq ed (entget en)) (setq ed (subst (cons 8 "0") (assoc 8 ed) ed ) ) (entmod ed)

Sets en to the name of the first entity in the drawing Sets ed to the entity data of entity en Changes the layer group in ed to layer 0

Modifies entity en’s layer in drawing

The entmod function imposes some restrictions on the changes it makes. First of all, an entity’s type and handle cannot be changed. If you want to do this, just entdel it and make a new entity with the command or entmake functions. All objects referenced by the entity list must be known to AutoCAD before the entmod is executed. Thus text style, linetype, shape, and block names must be defined in a drawing before they can be used in an entity list with entmod. An exception to this is layer names: entmod creates a new layer with the standard defaults used by the New option of LAYER if a previously undefined layer is named in an entity list. For entity fields with floating-point values (such as thickness), entmod accepts integer values and converts them to floating point. Similarly, if you supply a floating-point value for an integer entity field (such as color number), entmod truncates it and converts it to an integer. The entmod function performs consistency checking on the list supplied to it. If a serious error is detected, the database is not updated and nil is returned. Otherwise, entmod returns the list given to it as its argument. entmod cannot change internal fields such as the entity name in the –2 group of a seqend entity—attempts to change such fields are ignored. When entmod updates a main entity, it modifies the entity and updates its image on screen (including subentities). When entmod updates a subentity (a polyline vertex or a block

Appendix A AutoLISP Function Reference

347

attribute), the subentity is updated in the database but the image on the screen is not redisplayed. After all modifications are made to a given entity’s subentities, the entupd function can be used to update the image on the screen. You cannot use the entmod function to modify a viewport entity. You can change an entity’s space visibility field to 0 or 1 (except for viewport objects). If you use entmod to modify an entity within a block definition, the modification affects all instances of the block in the drawing. Before performing an entmod on vertex entities, you should read or write the polyline entity’s header. If the most recently processed polyline entity is different from the one to which the vertex belongs, width information (the 40 and 41 groups) can be lost.

You can use entmod to modify entities within a block definition, but doing so can create a self-referencing block, which will cause AutoCAD to stop.

entnext Returns the name of the next object (entity) in the drawing

(entnext [ename]) If entnext is called with no arguments, it returns the entity name of the first nondeleted entity in the database. If entnext is called with an entity name argument ename, it returns the entity name of the first nondeleted entity following ename in the database. If there is no next entity in the database, it returns nil. The entnext function returns both main entities and subentities. The entities selected by ssget are main entities, not attributes of blocks or vertices of polylines. You can access the internal structure of these complex entities by walking through the subentities with entnext. Once you obtain a subentity’s name, you can operate on it like any other entity. If you obtain the name of a subentity with entnext, you can find the parent entity by walking forward with entnext until a seqend entity is found, then extracting the –2 group from that entity, which is the main entity’s name. (setq e1 (entnext)) (setq e2 (entnext e1))

Sets e1 to the name of the first entity in the drawing Sets e2 to the name of the entity following e1

entnext

348

entsel Prompts the user to select a single object (entity) by specifying a point

(entsel [msg]) The entsel function returns a list whose first element is the entity name of the chosen object and whose second element is the coordinates (in terms of the current UCS) of the point used to pick the object. If a string is specified for msg, that string is used to ask the user for the object. Otherwise, the prompt defaults to Select object. The pick point returned by entsel does not represent a point that lies on the selected object. The point returned is the location of the crosshairs at the time of selection. The relationship between the pick point and the object will vary depending on the size of the pickbox and the current zoom scale. A list of the form returned by entsel can be supplied to AutoCAD in response to any of its object selection prompts. It is treated by AutoCAD as a pick of the designated object by pointing to the specified point. The following AutoCAD command sequence illustrates the use of the entsel function and the list returned: Command: line From point: 1,1 To point: 6,6 To point: ENTER Command: (setq e (entsel "Please choose an object: ")) Please choose an object: 3,3 ( (3.0 3.0 0.0)) Sometimes when operating on objects, you will want to simultaneously select an object and specify the point by which it was selected. Examples of this in AutoCAD can be found in Object Snap and in the BREAK, TRIM, and EXTEND commands. The entsel function allows AutoLISP programs to perform this operation. It selects a single object, requiring the selection to be by a point pick. The current Osnap setting is ignored by this function (no object snap) unless you specifically request it while you are in the function. The entsel function honors key words from a preceding call to initget.

Appendix A AutoLISP Function Reference

349

entupd Updates the screen image of an object (entity)

(entupd ename) When a polyline vertex or block attribute is modified with entmod, the entire complex entity is not updated on the screen. The entupd function can be used to cause a modified polyline or block to be updated on the screen. This function can be called with the entity name of any part of the polyline or block; it need not be the head entity. While entupd is intended for polylines and blocks with attributes, it can be called for any entity. It always regenerates the entity on the screen, including all subentities. If entupd is used on a nested entity (an entity within a block) or on a block that contains nested entities, some of the entities might not be regenerated. To ensure complete regeneration, you must invoke the REGEN command. Assuming that the first entity in the drawing is a polyline with several vertices, then (setq e1 (entnext)) Sets e1 to the polyline’s entity name (setq e2 (entnext e1)) Sets e2 to its first vertex (setq ed (entget e2)) Sets ed to the vertex data (setq ed (subst ’(10 1.0 2.0) (assoc 10 ed) Changes the vertex’s location in ed ed to point (1,2) ) ) (entmod ed) Moves the vertex in the drawing (entupd e1) Regenerates the polyline entity e1

eq Determines whether two expressions are identical

(eq expr1 expr2) The eq function determines whether expr1 and expr2 are bound to the same object (by setq, for example). Returns T if the two expressions are identical, and returns nil otherwise. You can use this function to determine whether two lists are the same. For example, given the assignments (setq f1 ’(a b c))

entupd

350

(setq f2 ’(a b c)) (setq f3 f2)

then (eq f1 f3) returns nil, f1 and f3 are not the same list (eq f3 f2) returns T, f3 and f2 are exactly the same list

See also the = (equal to) and equal functions

equal Determines whether two expressions are equal

(equal expr1 expr2 [fuzz]) The equal function determines whether expr1 and expr2 evaluate to the same thing. When comparing two real numbers (or two lists of real numbers, as in points), the two identical numbers can differ slightly if different methods are used to calculate them. Therefore, you can use an optional numeric argument, fuzz, to specify the maximum amount by which expr1 and expr2 can differ and still be considered equal. For example, given the assignments (setq f1 ’(a b c)) (setq f2 ’(a b c)) (setq f3 f2) (setq a 1.123456) (setq b 1.123457)

then (equal f1 f3) returns T (equal f3 f2) returns T (equal a b) returns nil (equal a b 0.000001) returns T

Although two lists that the equal function finds the same might not be found so using the eq function, atoms that are found to be the same using the equal function are always found to be the same if you use the eq function. However, if the eq function finds that the list or atoms are the same, the equal function also finds them to be the same.

See also the = (equal to)and eq functions

Appendix A AutoLISP Function Reference

351

*error* A user-definable error-handling function

(*error* string) If *error* is not nil, it is executed as a function whenever an AutoLISP error condition exists. AutoCAD passes one argument to *error*, which is a string containing a description of the error. The following function does the same thing that the AutoLISP standard error handler does. Print error and the description. (defun *error* (msg) (princ "error: ") (princ msg) (princ) )

Your *error* function can include calls to the command function without arguments (for example, (command)). This will cancel a previous AutoCAD command called with the command function.

eval Returns the result of evaluating an AutoLISP expression

(eval expr) For example, given the assignments (setq a 123) (setq b ’a)

then (eval 4.0) (eval (abs -10)) (eval a) (eval b)

returns 4.0 returns 10 returns 123 returns 123

*error*

352

exit Forces the current application to quit

(exit) If exit is called, it returns the error message quit/exit abort and returns to the AutoCAD Command prompt.

See also the quit function

exp Returns the constant e (a real number) raised to a specified power (the natural antilog)

(exp num) (exp 1.0) (exp 2.2) (exp -0.4)

returns 2.71828 returns 9.02501 returns 0.67032

expand Allocates node space by requesting a specified number of segments

(expand int)

Appendix A AutoLISP Function Reference

353

expt Returns a number raised to a specified power

(expt number power) If both arguments are integers, the result is an integer. Otherwise, the result is a real. These are examples: (expt 2 4) (expt 3.0 2.0)

returns 16 returns 9.0

fill_image Draws a filled rectangle in the currently active dialog box image tile

(fill_image x1 y1 wid hgt color) The fill_image function must be used between start_image and end_image calls. The color parameter is an AutoCAD color number or one of the logical color numbers shown in the following table. Symbolic names for the color attribute Color number

ADI mnemonic

Description

–2

BGLCOLOR

Current background of the AutoCAD graphics screen

–15

DBGLCOLOR

Current dialog box background color

–16

DFGLCOLOR

Current dialog box foreground color (text)

–18

LINELCOLOR

Current dialog box line color

The first (upper-left) corner of the rectangle is located at (x1,y1) and the second (lowerright) corner is located the relative distance (wid,hgt) from the first corner (wid and hgt must be positive values). The origin (0,0) is the upper-left corner of the image. You can obtain the coordinates of the lower-right corner by calling the dimension functions dimx_tile and dimy_tile.

expt

354

findfile Searches the AutoCAD library path for the specified file

(findfile filename) The findfile function makes no assumption about the file type or extension of filename. If filename does not specify a drive/directory prefix, findfile searches the AutoCAD library path. If a drive/directory prefix is supplied, findfile looks only in that directory. The findfile function always returns a fully qualified drive/directory/file name or nil if the specified file is not found. Consider the following examples. If the current directory is /acad and it contains the file abc.lsp. (findfile "abc.lsp") returns "/acad/abc.lsp"

If you are editing a drawing in the /acad/drawings directory, the ACAD environment variable is set to /acad/support, and the file xyz.txt exists only in the /acad/support directory. (findfile "xyz.txt") returns "/acad/support/xyz.txt"

Appendix A AutoLISP Function Reference

355

If the file nosuch is not present in any of the directories on the library search path. (findfile "nosuch") returns nil

The fully qualified name returned by findfile is suitable for use with the open function.

fix Returns the conversion of a real number into the nearest smaller integer

(fix num) The fix function truncates number to the nearest integer by discarding the fractional portion. (fix 3) (fix 3.7)

returns 3 returns 3

If number is larger than the largest possible integer (+2,147,483,647 or –2,147,483,648 on a 32-bit platform), fix returns a truncated real (although integers transferred between AutoLISP and AutoCAD are restricted to 16-bit values).

float Returns the conversion of a number into a real number

(float num) (float 3) (float 3.75)

returns 3.0 returns 3.75

fix

356

foreach Evaluates expressions for all members of a list

(foreach name lst expr...) Steps through lst, assigning each element to name, and evaluates each expr for every element in the list. Any number of exprs can be specified. The foreach function returns the result of the last expr evaluated. (foreach n ’(a b c) (print n))

is equivalent to (print a) (print b) (print c) and returns c

except that foreach returns the result of only the last expression evaluated.

gc Forces a garbage collection, which frees up unused nodes

(gc)

gcd Returns the greatest common denominator of two integers

(gcd int1 int2) The int1 and int2 arguments must be integers greater than 0. (gcd 81 57) (gcd 12 20)

returns 3 returns 4

Appendix A AutoLISP Function Reference

357

get_attr Retrieves the DCL value of a dialog box attribute

(get_attr key attribute) The key argument is a string that specifies the tile and is case-sensitive. The attribute argument specifies the name of the attribute as it appears in the tile’s DCL description. Both the key and attribute arguments are strings. The value returned is the attribute’s initial value as specified in its DCL description; it does not reflect changes to the state of the tile that come about with user input or set_tile calls. Returns the attribute value as a string.

get_tile Retrieves the current run-time value of a dialog box tile

(get_tile key) The key argument is a string that specifies the tile and is case-sensitive. It returns the tile’s value as a string.

getangle Pauses for user input of an angle, and returns that angle in radians

(getangle [pt] [msg]) The pt argument is a 2D base point in the current UCS, and msg is a string to be displayed as a prompt. The pt argument, if specified, is assumed to be the first of two points, so that the user can show AutoLISP the angle by pointing to one other point. You can supply a 3D base point, but the angle is always measured in the current construction plane. The getangle function measures angles with the zero-radian direction (set by the ANGBASE system variable) with angles increasing in the counterclockwise direction. The returned angle is expressed in radians with respect to the current construction plane (the XY plane of the current UCS, at the current elevation).

get_attr

358

The user can specify an angle by entering a number in the AutoCAD current angle units format. Although the current angle units format might be in degrees, grads, or some other unit, this function always returns the angle in radians. The user can also show AutoLISP the angle by pointing to two 2D locations on the graphics screen. AutoCAD draws a rubber-band line from the first point to the current crosshair position to help you visualize the angle. It is important to understand the difference between the input angle and the angle returned by getangle. Angles that are passed to getangle are based on the current settings of ANGDIR and ANGBASE. However, once an angle is provided, it is measured in a counterclockwise direction (ignoring ANGDIR) with zero radians as the current setting of ANGBASE. The following code examples show how different arguments can be used. (setq ang (getangle)) (setq ang (getangle ’(1.0 3.5))) (setq ang (getangle "Which way? ")) (setq ang (getangle ’(1.0 3.5) "Which way? "))

The user cannot enter another AutoLISP expression as the response to a getangle request.

See also the illustration and comparison to the getorient function

getcfg Retrieves application data from the AppData section of the acad.cfg file

(getcfg cfgname) The cfgname argument is a string (maximum length of 347 characters) naming the section and parameter value to retrieve. If cfgname is not valid, getcfg returns nil. The cfgname argument must be a string of this form: "AppData/application_name/section_name/.../param_name"

For example, assuming that the WallThk parameter in the AppData/ArchStuff section has a value of 8, (getcfg "AppData/ArchStuff/WallThk") returns "8"

Appendix A AutoLISP Function Reference

359

See also the setcfg function

getcname Retrieves the localized or English name of an AutoCAD command

(getcname cname) The cname argument specifies the localized or underscored English command name, which must be 64 characters or less in length. If cname is not preceded by an underscore (assumed to be the localized command name), getcname returns the underscored English command name. If cname is preceded by an underscore, getcname returns the localized command name. This function returns nil if cname is not a valid command name. For example, in a French version of AutoCAD, the following is true. (getcname "ETIRER") returns "_STRETCH" (getcname "_STRETCH") returns "ETIRER"

getcorner Pauses for user input of a rectangle’s second corner

(getcorner pt [msg]) The getcorner function requires a base point argument, pt, based on the current UCS, and draws a rectangle from that point as the user moves the crosshairs on the screen. The msg argument is a string to be displayed as a prompt. The getcorner function returns a point in the current UCS, similar to getpoint. If the user supplies a 3D point, its Z coordinate is ignored. The current elevation is used as the Z coordinate. The user cannot enter another AutoLISP expression as the response to a getcorner request.

getcname

360

getdist Pauses for user input of a distance

(getdist [pt] [msg]) The pt argument is a 2D or 3D base point in the current UCS. If provided, pt is used as the first of the two points and the user is prompted for only the second point. The msg argument is a string to be displayed as a prompt. The user can specify the distance by selecting two points, or the second point if a base point is provided. The user can also specify a distance by entering a number in the AutoCAD current distance units format. Although the current distance units format might be in feet and inches (architectural), the getdist function always returns the distance as a real. The getdist function draws a rubber-band line from the first point to the current crosshair position to help the user visualize the distance. If a 3D point is provided, the returned value is a 3D distance. However, setting the 64 bit of the initget function instructs getdist to ignore the Z component of 3D points and to return a 2D distance. (setq dist (getdist)) (setq dist (getdist ’(1.0 3.5))) (setq dist (getdist "How far ")) (setq dist (getdist ’(1.0 3.5) "How far? "))

The user cannot enter another AutoLISP expression as the response to a getdist request.

getenv Returns the string value assigned to a system environment variable

(getenv variable-name) The variable-name argument is a string specifying the name of the variable to be read. If this variable does not exist, getenv returns nil. You must enclose the variable name in quotation marks. Environment variable names must be spelled and cased exactly as they are stored in the system registry.

Appendix A AutoLISP Function Reference

361

For example, if the system environment variable ACAD is set to /acad/support and there is no variable named NOSUCH, then (getenv "ACAD") returns "/acad/support" (getenv "NOSUCH") returns nil

Assuming that the MaxArray environment variable was set to 10000, (getenv "MaxArray") returns "10000"

See also the setenv function

getfiled Prompts the user for a file name with the standard AutoCAD file dialog box, and returns that file name

(getfiled title default ext flags) The title argument specifies the dialog box label, default specifies a default file name to use (which can be a null string [""]), and ext is the default file name extension. If ext is passed as a null string [""], it defaults to * (all file types). If the file type dwg is included in the ext argument, the getfiled function displays an image preview in the dialog. The flags argument is an integer value (a bit-coded field) that controls the behavior of the dialog box. To set more than one condition at a time, add the values together to create a flags value between 0 and 15. Flag value = 1 (bit 0)

Set this bit when you prompt for the name of a new file to create. Do not set this bit when you prompt for the name of an existing file to open. In the latter case, if the user enters the name of a file that

getfiled

362

doesn’t exist, the dialog box displays an error message at the bottom of the box. If this bit is set and the user chooses a file that already exists, AutoCAD displays an alert box and offers the choice of proceeding with or canceling the operation. Flag value = 4 (bit 2)

Lets the user enter an arbitrary file name extension, or no extension at all. If this bit is not set, getfiled accepts only the extension specified in the ext argument and appends this extension to the file name if the user doesn’t enter it in the File text box.

Flag value = 8 (bit 3)

If this bit is set and bit 0 is not set, getfiled performs a library search for the file name entered. If it finds the file and its directory in the library search path, it strips the path and returns only the file name. (It doesn’t strip the path name if it finds that a file of the same name is in a different directory.) If this bit is not set, getfiled returns the entire file name, including the path name. Set this bit if you use the dialog box to open an existing file whose name you want to save in the drawing (or other database).

If the dialog box obtains a file name from the user, getfiled returns a string that specifies the file name; otherwise, it returns nil. The following call to getfiled displays the Select a Lisp File dialog box: (getfiled "Select a Lisp File" "/acadr14/support/" "lsp" 8)

Appendix A AutoLISP Function Reference

363

set by the title argument

set by the path name portion of the default argument (if default doesn’t specify a path, this is initially the current directory) set by the file name portion of the default argument

set by the ext argument Sample getfile dialog box

The getfiled function displays a dialog box containing a list of available files of a specified extension type. You can use this dialog box to browse through different drives and directories, select an existing file, or specify the name of a new file.

getint Pauses for user input of an integer, and returns that integer

(getint [msg]) The msg argument is an optional string to be displayed as a prompt. The getint function returns the integer value or nil. (setq num (getint)) (setq num (getint "Enter a number: "))

Values passed to getint can range from –32,768 to +32,767. The user cannot enter another AutoLISP expression as the response to a getint request.

See also the if function

getint

364

getkword Pauses for user input of a key word, and returns that key word

(getkword [msg]) Valid key words are set prior to the getkword call with the initget function. The msg argument is a string to be displayed as a prompt. The getkword function returns the key word matching the user input as a string. AutoCAD tries again if the input is not a key word. If the input is null ( ENTER ), getkword returns nil (if null input is allowed). This function also returns nil if it wasn’t preceded by a call to initget that established one or more key words. The following example shows an initial call to initget that sets up a list of key words (Yes and No) and disallows null input (bits value equal to 1) to the following getkword call: (initget 1 "Yes No") (setq x (getkword "Are you sure? (Yes or No) "))

This code prompts the user for input and sets the symbol x to either Yes or No, depending on the response. If the response does not match any of the key words, or if the user gives a null reply, AutoCAD prompts again with the string supplied in the msg argument. If no msg argument is provided, AutoCAD supplies this prompt: Try again: The user cannot enter another AutoLISP expression as the response to a getkword request.

See also the if function

getorient Pauses for user input of an angle, and returns that angle in radians

(getorient [pt] [msg]) This function is similar to the getangle function, except that the angle value returned by getorient is unaffected by the system variables ANGBASE and ANGDIR. However, the angle input by the user is still based on the current settings of ANGDIR and ANGBASE.

Appendix A AutoLISP Function Reference

365

The pt argument is a 2D base point in the current UCS, and msg is a string to be displayed as a prompt. The pt argument, if specified, is assumed to be the first of two points, allowing the user to show AutoLISP the angle by pointing to one other point. You can supply a 3D base point, but the angle is always measured in the current construction plane. The getorient function measures angles with the zero-radian direction to the right (east) and angles that are increasing in the counterclockwise direction. As with getangle, getorient expresses the returned angle in radians, with respect to the current construction plane. Angles input to getorient are based on the current settings of ANGDIR and ANGBASE. However, once an angle is provided, it is measured in a counterclockwise direction, with zero radians being to the right (ignoring ANGDIR and ANGBASE). Therefore, some conversion must take place if you select a different zero-degree base or a different direction for increasing angles by using the UNITS command or the ANGBASE and ANGDIR system variables. Use getangle when you need a rotation amount (a relative angle). Use getorient to obtain an orientation (an absolute angle). The user cannot enter another AutoLISP expression as the response to a getorient request.

See also the getangle and if functions

getpoint Pauses for user input of a point, and returns that point

(getpoint [pt] [msg]) The pt argument is a 2D or 3D base point in the current UCS, and msg is a string to be displayed as a prompt. The user can specify a point by pointing or by entering a coordinate in the current units format. If the pt argument is present, AutoCAD draws a rubber-band line from that point to the current crosshair position. The returned value is a 3D point expressed in terms of the current UCS. (setq p (getpoint)) (setq p (getpoint "Where? ")) (setq p (getpoint ’(1.5 2.0) "Second point: "))

The user cannot enter another AutoLISP expression as the response to a getpoint request.

getpoint

366

See also the getcorner and if functions

getreal Pauses for user input of a real number, and returns that real number

(getreal [msg]) The msg argument is a string to be displayed as a prompt. (setq val (getreal)) (setq val (getreal "Scale factor: "))

The user cannot enter another AutoLISP expression as the response to a getreal request.

getstring Pauses for user input of a string, and returns that string

(getstring [cr] [msg]) If the cr argument is supplied and is not nil, the input string can contain blanks (and must be terminated by ENTER ). Otherwise, the input string is terminated by space or ENTER . The msg argument is a string to be displayed as a prompt. If the string is longer than 132 characters, it returns only the first 132 characters of the string. If the input string contains the backslash character (\), it is converted to two backslash characters (\\). This is done so that the returned value can contain file name paths that can be used by other functions. (setq s (getstring "What’s your first name? "))

responding John sets s to "John" (setq s (getstring T "What’s your full name? "))

responding John Doe sets s to "John Doe" (setq s (getstring "Enter filename: "))

responding \acad\mydwg sets s to "\\acad\\mydwg" The user cannot enter another AutoLISP expression as the response to a getstring request.

Appendix A AutoLISP Function Reference

367

See also the getkword function for a routine that requires the user to enter one of several known options (key words).

getvar Retrieves the value of an AutoCAD system variable

(getvar varname) The varname argument is a string that names the system variable. If varname is not a valid system variable, getvar returns nil. For example, assuming that the fillet radius is set to 0.25 units, (getvar "FILLETRAD")

returns 0.25

You can find a list of the current AutoCAD system variables in the Command Reference.

See also the setvar function

graphscr Displays the AutoCAD graphics screen

(graphscr) The graphscr function always returns nil. This function is equivalent to the GRAPHSCR command or to pressing the Flip Screen function key. The textscr function is the complement of graphscr.

getvar

368

grclear Clears the current viewport (obsolete function)

(grclear) To preserve limited compatibility with previous releases, the grclear function returns nil.

grdraw Draws a vector between two points, in the current viewport

(grdraw from to color [highlight]) The from and to arguments are 2D or 3D points (lists of two or three reals) that specify the endpoints of the vector in terms of the current UCS. AutoCAD clips the vector to fit the screen. The grdraw function draws the vector with the color specified by the integer color argument, with –1 signifying XOR ink, which complements anything it draws over and which erases itself when overdrawn. If the integer highlight argument supplied is nonzero, the vector is drawn using the default highlighting method of the display device (usually dashed). If highlight is omitted or is zero, grdraw uses the normal display mode. This function always returns nil.

See also the grvecs function for a routine that draws multiple vectors

grread Reads values from any of the AutoCAD input devices

(grread [track] [allkeys [curtype]]) Only specialized AutoLISP routines need this function. Most input to AutoLISP should be obtained through the various getxxx functions.

Appendix A AutoLISP Function Reference

369

If the track argument is supplied and is not nil, it enables the return of coordinates from a pointing device as it is moved. If the allkeys argument is present, grread performs functions depending on the code supplied. The curtype argument can be used to control the type of cursor displayed. The allkeys and curtype arguments are both integers and are explained as follows: allkeys

The allkeys bit code values can be added together for combined functionality. 1 (bit 0) Return drag mode coordinates. If this bit is set and the user moves the pointing device instead of selecting a button or pressing a key, grread returns a list where the first member is a type 5 and the second member is the (X,Y) coordinates of the current pointing device (mouse or digitizer) location. This is how AutoCAD implements dragging. 2 (bit 1) Return all key values, including function and cursor key codes, and don’t move the cursor when the user presses a cursor key. 4 (bit 2) Use the value passed in the curtype argument to control the cursor display. 8 (bit 3) Don’t display the error: console break message when the user presses CTRL + C .

curtype

The allkeys value for bit 2 must be set for the curtype values to take effect. The curtype argument affects only the cursor type during the current grread function call. 0 Display the normal crosshairs. 1 Do not display a cursor (no crosshairs). 2 Display the object-selection “target” cursor.

Additional control bits might be defined in future AutoCAD releases.

grread

370

The grread function returns a list whose first element is a code specifying the type of input. The second element of the list is either an integer or a point, depending on the type of input. The return values are listed in the following table. grread return values First element

Second element

Value

Type of input

Value

Description

2

Keyboard input

varies

Character code

3

Selected point

3D point

Point coordinates

4

Screen/pull-down menu item (from pointing device)

0 to 999 1001 to 1999 2001 to 2999 3001 to 3999 … and so, to 16001 to 16999

Screen menu box no. POP1 menu box no. POP2 menu box no. POP3 menu box no. … POP16 menu box no.

5

Pointing device (returned only if tracking is enabled)

3D point

Drag mode coordinate

6

BUTTONS menu item

0 to 999 1000 to 1999 2000 to 2999 3000 to 3999

BUTTONS1 menu button no. BUTTONS2 menu button no. BUTTONS3 menu button no. BUTTONS4 menu button no.

7

TABLET1 menu item

0 to 32767

Digitized box no.

8

TABLET2 menu item

0 to 32767

Digitized box no.

9

TABLET3 menu item

0 to 32767

Digitized box no.

10

TABLET4 menu item

0 to 32767

Digitized box no.

11

AUX menu item

0 to 999 1000 to 1999 2000 to 2999 3000 to 3999

AUX1 menu button no. AUX2 menu button no. AUX3 menu button no. AUX4 menu button no.

12

Pointer button (follows a type 6 or type 11 return)

3D point

Point coordinates

Appendix A AutoLISP Function Reference

371

Entering Esc while a grread is active aborts the AutoLISP program with a keyboard break (unless the allkeys argument has disallowed this). Any other input is passed directly to grread, giving the application complete control over the input devices. If the user presses the pointer button within a screen menu or pull-down menu box, grread returns a type 6 or type 11 code, but in a subsequent call, it does not return a type

12 code: the type 12 code follows type 6 or type 11 only when the pointer button is pressed while it is in the graphics area of the screen. It is important to clear the code 12 data from the buffer before attempting another operation with a pointer button or with an auxiliary button. To accomplish this, perform a nested grread like this: (setq code_12 (grread (setq code (grread))))

This sequence captures the value of the code 12 list as streaming input from the device. Because input is handled differently on the various platforms supported by AutoCAD, the grread function may return unexpected results. ■ ■

The default pointing device on platforms that use a system mouse returns a code 11, not a code 6. On the Macintosh platform, the pop menus return a code 11, not a code 4. Also on the Macintosh, a double-click returns a code 11 (not a code 6) and is followed by a code 5 coordinate pair if selected in the current viewport. Conversely, a double-click in a viewport other than the current one returns a code 3 coordinate pair followed by a code 11.

grtext Writes text to the status line or to screen menu areas

(grtext [box text [highlight]]) The box argument is an integer that specifies the location in which to write the text. The text argument is a string that specifies the text to be written to the screen menu or status line location. The text argument is truncated if it is too long to fit in the available area. The highlight argument is an integer that selects or deselects a screen menu location. The values for these arguments vary depending on the screen location to which you are writing. This function displays the supplied text in the menu area; it does not change the underlying menu item. The grtext function can be called with no arguments to restore all text areas to their standard values. If successful, the grtext function returns the string passed in the text argument, and returns nil if unsuccessful.

grtext

372

Screen Menu Area Setting box to a positive or zero value specifies a screen menu location. Valid box values range from 0 to the highest-numbered screen menu box minus 1. The SCREENBOXES system variable reports the maximum number of screen menu boxes. If the highlight argument is supplied as a positive integer, grtext highlights the text in the designated box. Highlighting a box automatically dehighlights any other box already highlighted. If highlight is zero, the menu item is dehighlighted. If highlight is a negative number, it is ignored. On some platforms, the text must first be written without the highlight argument and then must be highlighted. Highlighting of a screen menu location works only when the cursor is not in that area. Status Line Area If grtext is called with a box value of –1, it writes the text into the mode status line area. The length of the mode status line differs from display to display (most allow at least 40 characters). The following code uses the $(linelen) DIESEL expression to report the length of the mode status area. (setq modelen (menucmd "M=$(linelen)"))

If a box value of –2 is used, grtext writes the text into the coordinate status line area. If coordinate tracking is turned on, values written into this field are overwritten as soon as the pointer sends another set of coordinates. For both –1 or –2 box values, the highlight argument is ignored.

grvecs Draws multiple vectors on the graphics screen

(grvecs vlist [trans]) The vlist argument is a vector list comprised of a series of optional color integers and two point lists. The trans argument is a transformation matrix that you can use to change the location or proportion of the vectors defined in your vector list. This matrix is a list of four lists of four real numbers.

Appendix A AutoLISP Function Reference

373

The format for vlist is as follows: ([color1] from1 to1 [color2] from2 to2 ...)

The color value applies to all succeeding vectors until vlist specifies another color. AutoCAD colors are in the range 0–255. If the color value is greater than 255, succeeding vectors are drawn in XOR ink, which complements anything it draws over and which erases itself when overdrawn. If the color value is less than zero, the vector is highlighted. Highlighting depends on the display device. Most display drivers indicate highlighting by a dashed line, but some indicate it by using a distinctive color. A pair of point lists, from and to, specify the endpoints of the vectors, expressed in the current UCS. These can be two-dimensional or three-dimensional points. You must pass these points as pairs—two successive point lists—or the grvecs call will fail. AutoCAD clips the vectors as required to fit on the screen. If the call to grvecs is successful, it returns nil. The following code draws five vertical lines on the graphics screen, each a different color: (grvecs ’(1 (1 2)(1 5) 2 (2 2)(2 5) 3 (3 2)(3 5) 4 (4 2)(4 5) 5 (5 2)(5 5) ))

Draws a red line from (1,2) to (1,5) Draws a yellow line from (2,2) to (2,5) Draws a green line from (3,2) to (3,5) Draws a cyan line from (4,2) to (4,5) Draws a blue line from (5,2) to (5,5)

The following matrix represents a uniform scale of 1.0 and a translation of 5.0,5.0,0.0. If this matrix is applied to the preceding list of vectors, they will be offset by 5.0,5.0,0.0. ’( (1.0 0.0 0.0 5.0) (0.0 1.0 0.0 5.0) (0.0 0.0 1.0 0.0) (0.0 0.0 0.0 1.0) )

See also the nentselp function for more information on transformation matrixes

handent Returns an object (entity) name based on its handle

(handent handle) Given an entity handle string as the handle argument, the handent function returns the entity name associated with that handle in the current editing session. The handent function returns the entity name of both graphic and nongraphic entities.

handent

374

If handent is passed an invalid handle or a handle not used by any entity in the current drawing, nil is returned. The handent function returns entities that have been deleted during the current editing session. You can undelete them with the entdel function. An entity’s name can change from one editing session to the next, but an entity’s handle remains constant. In a particular editing session, the code (handent "5A2") might return

Used with the same drawing but in another editing session, the same call might return a different entity name. Once the entity name is obtained, it can be used to manipulate the entity with any of the entity-related functions.

help Invokes the help facility

(help [helpfile [topic [command]]]) The helpfile argument is a string that specifies a help file. If you specify an AutoCAD Help file (.ahp), the help function uses the AutoCAD Help viewer to display the contents of that file. If you specify a Windows Help file (.hlp) the help function uses the WinHelp program to display the file. If the helpfile argument is an empty string ("") or is omitted, AutoCAD uses the default AutoCAD Help file. The topic argument is a key word that specifies the topic initially displayed by the help facility. If the topic argument is an empty string (""), the help facility displays the introductory part of the help file. The command argument is a string that specifies the initial state of the Help window, as described in the following table. Values for the command argument String

Description

HELP_CONTENTS

Displays the first topic in the Help file

HELP_HELPONHELP

Displays help on using help

HELP_PARTIALKEY

Displays the Search dialog using the string passed as the topic as the initial search text

If you are specifying a Windows Help file, the command argument can also be a string used by the fuCommand argument of the WinHelp() function as defined by the WinHelp API in the Microsoft Windows SDK.

Appendix A AutoLISP Function Reference

375

The file extension is not required with the helpfile argument. If a file extension is provided, AutoCAD looks only for that file. If no file extension is provided, the following search rules apply: append .hlp, else append .ahp. The only error condition that the help function returns to the application is the existence of the file specified by helpfile. All other error conditions are reported to the user through a dialog box. The help function returns the helpfile string if it succeeds and nil if it fails. If you use help without any arguments, it returns an empty string ("") if successful, and nil if it fails. The following code calls help to display the information on MYCOMMAND in the help file achelp.ahp: (help "achelp.ahp" "mycommand")

See also The setfunhelp function associates context-sensitive help (when the user presses F1 ) with a user-defined command.

help

376

if Conditionally evaluates expressions

(if testexpr thenexpr [elseexpr]) If testexpr is not nil, it evaluates thenexpr; otherwise it evaluates elseexpr. The if function returns the value of the selected expression. If elseexpr is missing and testexpr is nil, then the if function returns nil. (if (= 1 3) "YES!!" "no.") returns "no." (if (= 2 (+ 1 1)) "YES!!") returns "YES!!" (if (= 2 (+ 3 4)) "YES!!") returns nil

See also the progn function

Appendix A AutoLISP Function Reference

377

initdia Forces the display of the next command’s dialog box

(initdia [dialogflag]) The dialogflag argument is an integer. If this argument is not present or is present and nonzero, the next use (and next use only) of a command will display that command’s dialog box rather than its command line prompts. Currently, the only commands to make use of the initdia function are BHATCH, LAYER, IMAGE, IMAGEADJUST, LINETYPE, MTEXT, PLOT, STYLE, and TOOLBAR. If the dialogflag argument is zero, then any previous call to this function is cleared, which restores the default behavior of presenting the command line interface. This function returns no value. Externally defined function acadapp ARX application

initget Establishes key words for use by the next user-input function call

(initget [bits] [string]) The functions that honor key words are getint, getreal, getdist, getangle, getorient, getpoint, getcorner, getkword, entsel, nentsel, and nentselp. The getstring function is the only user-input function that does not honor key words. The bits argument is a bit-coded integer that allows or disallows certain types of user input. The string argument defines a list of key words. The key words are checked by the next user-input function call when the user does not enter the expected type of input (for example, a point to getpoint). If the user input matches a key word from the list, the function returns that key word as a string result. The application can test for the key words and perform the action associated with each one. If the user input is not of the expected type and does not match a key word, AutoCAD asks the user to try again. The initget bit values and key words apply only to the next user-input function call. The initget function always returns nil.

initdia

378

If initget sets a control bit and the application calls a user-input function for which the bit has no meaning, the bit is ignored. The bits can be added together in any combination to form a value between 0 and 255. If no bits argument is supplied, zero (no conditions) is assumed. If the user input fails one or more of the specified conditions (as in a zero value when zero values are not allowed), AutoCAD displays a message and asks the user to try again. Input options set by initget Bit value

Description

1 (bit 0)

Prevents the user from responding to the request by entering only ENTER .

2 (bit 1)

Prevents the user from responding to the request by entering zero.

4 (bit 2)

Prevents the user from responding to the request by entering a negative value.

8 (bit 3)

Allows the user to enter a point outside the current drawing limits. This condition applies to the next user-input function even if the AutoCAD system variable LIMCHECK is currently set.

16 (bit 4)

(Not currently used.)

32 (bit 5)

Uses dashed lines when drawing rubber-band line or box. For those functions with which the user can specify a point by selecting a location on the graphics screen, this bit value causes the rubber-band line or box to be dashed instead of solid. (Some display drivers use a distinctive color instead of dashed lines.) If the system variable POPUPS is 0, AutoCAD ignores this bit.

64 (bit 6)

Prohibits input of a Z coordinate to the getdist function; lets an application ensure that this function returns a 2D distance.

128 (bit 7)

Allows arbitrary input as if it is a key word, first honoring any other control bits and listed key words. This bit takes precedence over bit 0; if bits 7 and 0 are set and the user presses ENTER , a null string is returned.

Future versions of AutoLISP might use additional initget control bits, so avoid setting bits that aren’t shown in the table.

Appendix A AutoLISP Function Reference

379

The special control values are honored only by those getxxx functions for which they make sense. User-input functions and applicable control bits Honors Control bits values key words No No No No negative limits zero null (8) (4) (2) (1)

Function

Uses dashes (32)

2D distance (64)

Arbitrary Input (128)

getint











getreal











getdist









getangle











getorient











getpoint











getcorner











getkword





entsel



nentsel



nentselp











Key Word Specifications The string argument is interpreted according to these rules: Each key word is separated from the following key word by one or more spaces. For example, "Width Height Depth" defines three key words. Each key word can contain only letters, numbers, and hyphens (-). There are two methods for abbreviating key words: ■



The required portion of the key word is specified in uppercase characters, and the remainder of the key word is specified in lowercase characters. The uppercase abbreviation can be anywhere in the key word (for example, "LType", "eXit", or "toP"). The entire key word is specified in uppercase characters, and it is followed immediately by a comma, which is followed by the required characters (for example,

initget

380

"LTYPE,LT"). The key word characters in this case must include the first letter of the key word, which means that "EXIT,X" is not valid.

The two brief examples, "LType" and "LTYPE,LT", are equivalent: if the user types LT (in either upper case or lower case letters), this is sufficient to identify the key word. The user can enter characters that follow the required portion of the key word, provided they don’t conflict with the specification. In the example, the user could also enter LTY or LTYP, but L would not be sufficient. If string shows the key word entirely in uppercase or lowercase characters with no comma followed by a required part, AutoCAD recognizes the key word only if the user enters all of it. The initget function provides support for localized keywords. The following syntax for the keyword string allows input of the localized keyword while it returns the language independent keyword: "local1 local2 localn _indep1 indep2 indepn"

where local1 through localn are the localized keywords, and indep1 through indepn are the language-independent keywords. There must always be the same number of localized keywords as language-independent keywords, and the first language-independent keyword is prefixed by an underscore as shown in the following example: (initget "Abc Def _Ghi Jkl") (getkword "\nEnter an option (Abc/Def): ")

Entering A returns Ghi and entering _J returns Jkl.

Appendix A AutoLISP Function Reference

381

inters Finds the intersection of two lines

(inters pt1 pt2 pt3 pt4 [onseg]) The pt1 and pt2 arguments are the endpoints of the first line, and pt3 and pt4 are the endpoints of the second line. If the onseg argument is present and is nil, the lines defined by the four pt arguments are considered infinite in length, and inters returns the point where they intersect even if that point is off the end of one or both of the lines. If the onseg argument is omitted or is not nil, the intersection point must lie on both lines or inters returns nil. The inters function returns nil if the two lines do not intersect. All points are expressed in terms of the current UCS. If all four point arguments are 3D, inters checks for 3D intersection. If any of the points are 2D, inters projects the lines onto the current construction plane and checks only for 2D intersection. (setq a ’(1.0 1.0) b ’(9.0 9.0)) (setq c ’(4.0 1.0) d ’(4.0 2.0)) (inters a b c d) returns nil (inters a b c d T) returns nil (inters a b c d nil) returns (4.0 4.0)

itoa Returns the conversion of an integer into a string

(itoa int) The int argument specifies an integer. (itoa 33) (itoa -17)

returns "33" returns "-17"

inters

382

lambda Defines an anonymous function

(lambda arguments expr...) Use the lambda function when the overhead of defining a new function is not justified. It also makes the programmer’s intention more apparent by laying out the function at the spot where it is to be used. This function returns the value of its last expr, and is often used in conjunction with apply and/or mapcar to perform a function on a list. (apply ’(lambda (x y z) (* x (- y z)) ) ’(5 20 14) ) returns 30

and (setq counter 0) (mapcar ’(lambda (x) (setq counter (1+ counter)) (* x 5) ) ’(2 4 -6 10.2) ) returns (10 20 -30 51.0)

last Returns the last element in a list

(last lst) (last ’(a b c d e)) (last ’(a b c (d e)))

returns E returns (D E)

As shown, last can return an atom or a list. At first glance, last seems a perfect way to obtain the Y coordinate of a point. While this is true for 2D points (lists of two reals), last will return the Z coordinate of a 3D point. To let functions work properly with 2D or 3D points, use cadr to obtain Y coordinates, and caddr to obtain Z coordinates.

Appendix A AutoLISP Function Reference

383

length Returns an integer indicating the number of elements in a list

(length lst) (length ’(a b c d)) returns 4 (length ’(a b (c d))) returns 3 (length ’()) returns 0

list Takes any number of expressions, and combines them into one list

(list expr...) (list ’a ’b ’c) (list ’a ’(b c) ’d) (list 3.9 6.7)

returns (A B C) returns (A (B C) D) returns (3.9 6.7)

In AutoLISP, this function is frequently used to define a 2D or 3D point variable (a list of two or three reals). As an alternative to using the list function, you can explicitly quote a list with the quote function if there are no variables or undefined items in the list. The single quote character ( ’ ) is defined as the quote function. ’(3.9 6.7)

means the same as (list 3.9 6.7)

This can be useful for creating association lists and defining points.

See also the quote function

length

384

listp Verifies that an item is a list

(listp item) Returns T if item is a list, and returns nil otherwise. (listp ’(a b c)) (listp ’a) (listp 4.343)

returns T returns nil returns nil

Because nil is both an atom and a list, the listp function returns T when passed nil. (listp nil)

returns T

load_dialog Loads a DCL file

(load_dialog dclfile) The dclfile argument is a string that specifies the DCL file to load. If the dclfile argument does not specify a file extension, .dcl is assumed. Returns a positive integer value (dcl_id) if successful, and returns a negative integer if it can’t open the file. The dcl_id is used as a handle in subsequent new_dialog and unload_dialog calls. The load_dialog function searches for files according to the AutoCAD library search path. This function is the complement of unload_dialog. An application can load multiple DCL files with multiple load_dialog calls.

Appendix A AutoLISP Function Reference

385

load Evaluates the AutoLISP expressions in a file

(load filename [onfailure]) The filename argument is a string that represents the file name. If the filename argument does not specify a file extension, .lsp is assumed. If the load function fails, it returns the value of the onfailure argument. However, if onfailure is not provided, a load failure causes an AutoLISP error. If the operation is successful, load returns the value of the last expression in the file. The filename can include a directory prefix, as in “/function/test1”. On DOS systems, a drive letter is also permitted. A forward slash (/) or two backslashes (\\) are valid directory delimiters. If you don’t include a directory prefix in the filename string, load searches the AutoCAD library path for the specified file. If the file is found anywhere on this path, load then loads the file. If the onfailure argument is a valid AutoLISP function, it is evaluated. In most cases, the onfailure argument should be a string or an atom. This allows an AutoLISP application calling load to take alternative action upon failure. For example, assuming that file /fred/test1.lsp contains (defun MY-FUNC1 (x)

...function body... ) (defun MY-FUNC2 (x)

...function body... and that file test2.lsp does not exist, then (load "/fred/test1") returns MY-FUNC2 (load "\\fred\\test1") returns MY-FUNC2 (load "/fred/test1" "bad") returns MY-FUNC2 (load "test2" "bad") returns "bad" (load "test2") causes an AutoLISP error

The load function can be used from within another AutoLISP function, or even recursively (in the file being loaded).

See also the defun function and “Symbol and Function Handling.”

load

386

log Returns the natural log of a number as a real number

(log num) (log 4.5) (log 1.22)

returns 1.50408 returns 0.198851

logand Returns the result of the logical bitwise AND of a list of integers

(logand int int...) (logand 7 15 3) (logand 2 3 15) (logand 8 3 4)

returns 3 returns 2 returns 0

logior Returns the result of the logical bitwise inclusive OR of a list of integers

(logior int int...) (logior 1 2 4) (logior 9 3)

returns 7 returns 11

Appendix A AutoLISP Function Reference

387

lsh Returns the logical bitwise shift of an integer by a specified number of bits

(lsh int numbits) If numbits is positive, int is shifted to the left; if negative, to the right. In either case, zero bits are shifted in, and the bits shifted out are discarded. The returned value is positive if the significant bit (bit number 31) contains a 0 after the shift operator, otherwise it is negative. (lsh 2 1) (lsh 2 -1) (lsh 40 2)

returns 4 returns 1 returns 160

mapcar Returns a list of the result of executing a function with the individual elements of a list or lists supplied as arguments to the function

(mapcar function list1... listn) The number of lists must match the number of arguments required by function. (setq a 10 b 20 c 30) (mapcar ’1+ (list a b c)) returns (11 21 31)

is equivalent to (1+ a) (1+ b) (1+ c)

except that mapcar returns a list of the results.

lsh

388

The lambda function can specify an anonymous function to be performed by mapcar. This is useful when some of the function arguments are constant or are supplied by some other means. (mapcar

’(lambda (x) (+ x 3) ) ’(10 20 30)

returns (13 23 33)

)

max Returns the largest of the numbers given

(max number number...) (max 4.07 -144) (max -88 19 5 2) (max 2.1 4 8)

returns 4.07 returns 19 returns 8.0

mem Displays the current state of AutoLISP’s memory

(mem) Displays the current state of AutoLISP’s memory, and returns nil. It displays the following information: Nodes is the total number of nodes allocated so far, which should equal the node segment size multiplied by the number of segments. Free nodes is the number of nodes currently on the free list as a result of a garbage collection. Segments is the number of node segments allocated. Allocate is the current segment size. Collections is a count of garbage collections, whether automatic or forced.

Appendix A AutoLISP Function Reference

389

member Searches a list for an occurrence of an expression and returns the remainder of the list, starting with the first occurrence of the expression

(member expr lst) If there is no occurrence of expr in lst, member returns nil. (member ’c ’(a b c d e)) returns (C D E) (member ’q ’(a b c d e)) returns nil

menucmd Issues menu commands, or sets and retrieves menu item status

(menucmd string) The string argument is a string that specifies a menu area and the value to assign to that menu area. The string argument has the following parameters. "menu_area=value"

The allowed values of menu_area, shown in the following table, are the same as they are in menu file submenu references. Menu_area string values Menu_area string

Menu section

B1–B4

For BUTTONS menus 1 through 4

A1–A4

For AUX menus 1 through 4

P0–P16

For pull-down (POP) menus 0 through 16

I

For image tile menus

member

390

Menu_area string values (continued) Menu_area string

Menu section

S

For the SCREEN menu

T1–T4

For TABLET menus 1 through 4

M

For DIESEL string expressions

Gmenugroup.nametag

Specifies a menugroup and name tag

The value parameter specifies the value that is assigned to menu_area. The menucmd function can switch between subpages in an AutoCAD menu. This function can also force the display of menus. This allows AutoLISP programs to use image tile menus and to display other menus from which the user can make selections. AutoLISP programs can also enable, disable, and place marks in menu items. The following code displays the image tile menu MOREICONS. (menucmd "I=moreicons") Loads the MOREICONS image tile menu (menucmd "I=*") Displays the menu

The following code checks the status of the third menu item in the pull-down menu POP11. If the menu item is currently enabled, the menucmd function disables it. (setq s (menucmd "P11.3=?")) Gets the status of the menu item (if (= s "") If the status is an empty string, (menucmd "P11.3=~") disable the menu item )

The previous code is not foolproof. In addition to being enabled or disabled, menu items can also receive marks. The code (menucmd "P11.3=?") could return "!.", indicating that the menu item is currently checked. This code would make the assumption that the menu item is disabled and would continue without disabling it. If the code included a call to the wcmatch function, it could check the status for an occurrence of the tilde (~) character and then take appropriate action.

Appendix A AutoLISP Function Reference

391

The menucmd function also allows AutoLISP programs to take advantage of the DIESEL string expression language. Some things can be done much easier with DIESEL than with the equivalent AutoLISP code. The following code returns a string containing the current day and date: (menucmd "M=$(edtime,$(getvar,date),DDDD\",\" D MONTH YYYY)") returns "Sunday, 16 July 1995"

menugroup Verifies that a menugroup is loaded

(menugroup groupname) The groupname argument is a string that specifies the menugroup name. If groupname matches a loaded menugroup the function returns the groupname string; otherwise, it returns nil.

min Returns the smallest of the numbers given

(min number number...) (min 683 -10.0) (min 73 2 48 5) (min 2 4 6.7)

returns -10.0 returns 2 returns 2.0

menugroup

392

minusp Verifies that a number is negative

(minusp num) Returns T if number is negative, and returns nil otherwise. (minusp -1) (minusp -4.293) (minusp 830.2)

returns T returns T returns nil

mode_tile Sets the mode of a dialog box tile

(mode_tile key mode) The key argument is a string that specifies the tile and is case-sensitive. The mode argument is an integer value. The mode argument values are described in the following table. Mode argument values Value

Description

0

Enable tile

1

Disable tile

2

Set focus to tile

3

Select edit box contents

4

Flip image highlighting on or off

Appendix A AutoLISP Function Reference

393

namedobjdict Returns the entity name of the current drawing’s named object dictionary, which is the root of all nongraphical objects in the drawing

(namedobjdict) Using the name returned by this function and the dictionary access functions, an application can access the nongraphical objects in the drawing.

nentsel Prompts the user to select an object (entity) by specifying a point, and provides access to the definition data contained within a complex object

(nentsel [msg]) The msg argument is a string to be displayed as a prompt. If omitted, the Select objects prompt is issued. The nentsel function prompts the user to select an object. The current Object Snap mode is ignored unless the user specifically requests it. To provide additional support at the Command prompt, nentsel honors key words defined by a previous call to initget. When the selected object is not complex (i.e., not a polyline or block), nentsel returns the same information as entsel. However, if the selected object is a polyline, nentsel returns a list containing the name of the subentity (vertex) and the pick point. This is similar to the list returned by entsel, except that the name of the selected vertex is returned instead of the polyline header. The nentsel function always returns the starting vertex of the selected polyline segment. Picking the third segment of a polyline, for example, returns the third vertex. The Seqend subentity is never returned by nentsel for a polyline. An optimized polyline (lwpolyline entity) is defined in the drawing database as a single entity; it does not contain subentities. Selecting an attribute within a block reference returns the name of the attribute and the pick point. When the selected object is a component of a block reference other than an attribute, nentsel returns a list containing four elements.

namedobjdict

394

The first element of the list returned from picking an object within a block is the selected entity’s name. The second element is a list containing the coordinates of the point used to pick the object. The third element is called the Model to World Transformation Matrix. It is a list consisting of four sublists, each of which contains a set of coordinates. This matrix can be used to transform the entity definition data points from an internal coordinate system called the Model Coordinate System (MCS), to the World Coordinate System (WCS). The insertion point of the block that contains the selected entity defines the origin of the MCS. The orientation of the UCS when the block is created determines the direction of the MCS axes. The fourth element is a list containing the entity name of the block that contains the selected object. If the selected object is in a nested block (a block within a block), the list additionally contains the entity names of all blocks in which the selected object is nested, starting with the innermost block and continuing outward until the name of the block that was inserted in the drawing is reported. (

Name of entity

(Px Py Pz) Pick point ( (X0 Y0 Z0) Model to World Transformation Matrix (X1 Y1 Z1) (X2 Y2 Z2) (X3 Y3 Z3) ) ( Name of most deeply nested block . containing selected entity . . ) Name of outermost block )

containing selected entity

Once the entity name and the Model to World Transformation Matrix are obtained, you can transform the entity definition data points from the MCS to the WCS. Use entget and assoc on the entity name to obtain the definition points expressed in MCS coordinates. The Model to World Transformation Matrix returned by nentsel has the same purpose as that returned by nentselp, but it is a 4 × 3 matrix—passed as an array of four points—that uses the convention that a point is a row rather than a column. The transformation is described by the following matrix multiplication:

M 00 M 01 M 02 X′ Y′ Z′ 1.0 = X Y Z 1.0 ⋅

M 10 M 11 M 12 M 20 M 21 M 22 M 30 M 31 M 32

So the equations for deriving the new coordinates are as follows:

Appendix A AutoLISP Function Reference

395

X′ = XM 00 + YM 10 + ZM 20 + M 30 Y′ = XM 01 + YM 11 + ZM 21 + M 31 Z′ = XM 02 + YM 12 + ZM 22 + M 32 The Mij, where 0 ≤ i, j ≤ 2, are the Model to World Transformation Matrix coordinates; X, Y, Z is the entity definition data point expressed in MCS coordinates, and X’, Y’, Z’ is the resulting entity definition data point expressed in WCS coordinates. This is the only AutoLISP function that uses a matrix of this type; the nentselp function returns a matrix similar to those used by other AutoLISP and ADSRX functions.

See also “Entity Name Functions” and the entsel and if functions

nentselp Provides similar functionality to that of the nentsel function without the need for user input

(nentselp [msg] [pt]) In addition to the optional msg argument, nentselp accepts a selection point as an optional argument. This allows object selection without user input. The nentselp function returns a 4 × 4 transformation matrix, defined as follows:

M 00 M 01 M 02 M 03 M 10 M 11 M 12 M 13 M 20 M 21 M 22 M 23 M 30 M 31 M 32 M 33 The first three columns of the matrix specify scaling and rotation. The fourth column is a translation vector. The functions that use a matrix of this type treat a point as a column vector of dimension 4. The point is expressed in homogeneous coordinates, where the fourth element of the point vector is a scale factor that is normally set to 1.0. The final row of the matrix, the vector [M30 M31 M32 M33], has the nominal value of [0 0 0 1]; it is currently ignored by

nentselp

396

the functions that use this matrix format. In this convention, applying a transformation to a point is a matrix multiplication that appears as follows:

M 00 X′ M 10 Y′ = Z′ M 20 1.0 0.0

M 01 M 02 M 03

X M 11 M 12 M 13 Y ⋅ Z M 21 M 22 M 23 1.0 0.0 0.0 1.0

This multiplication gives us the individual coordinates of the point as follows:

X′ = XM 00 + YM 01 + ZM 02 + M 03 ( 1.0 ) Y′ = XM 10 + YM 11 + ZM 12 + M 13 ( 1.0 ) Z′ = XM 20 + YM 21 + ZM 22 + M 23 ( 1.0 ) As these equations show, the scale factor and the last row of the matrix have no effect and are ignored.

new_dialog Begins a new dialog box and displays it, and can also specify a default action

(new_dialog dlgname dcl_id [action [screen-pt]]) The dlgname argument is a string that specifies the dialog box, and dcl_id identifies the DCL file (you must have obtained its value from the load_dialog call). The action argument, which must be specified if you specify screen-pt, is a string that contains an AutoLISP expression to use as the default action. If you don’t want to define a default action, pass action as the empty string (""). The screen-pt argument is a 2D point list that specifies the X,Y location of the dialog box on the screen. The point usually specifies the upper-left corner of the dialog box, but this is platform dependent, as is the system of units in which the location is specified. If you pass the point as’(-1 -1), the dialog box is opened in the default position (the center of the AutoCAD graphics screen). If new_dialog succeeds, it returns T; otherwise it returns nil. Your application must call new_dialog before it calls start_dialog. All dialog box initialization—such as setting tile values, creating images or lists for list boxes, and associating actions with specific tiles (with the use of action_tile)—must take place after

Appendix A AutoLISP Function Reference

397

the new_dialog call and before the start_dialog call. The default action is evaluated when the user picks an active tile that doesn’t have an action or callback explicitly assigned to it by action_tile or in DCL. Always check the status new_dialog returns. Calling start_dialog when the new_dialog call failed can have unpredictable results.

new_dialog

398

not Verifies that an item evaluates to nil

(not item) Returns T if item evaluates to nil, and returns nil otherwise. (setq a 123 b "string" c nil) (not a) returns (not b) returns (not c) returns (not ’()) returns

nil nil T T

Typically, the null function is used for lists, and not is used for other data types along with some type of control function.

nth Returns the nth element of a list

(nth n lst) The n argument is the number of the element to return (zero is the first element). If n is greater than lst’s highest element number, nth returns nil. (nth 3 ’(a b c d e)) (nth 0 ’(a b c d e)) (nth 5 ’(a b c d e))

returns D returns A returns nil

Appendix A AutoLISP Function Reference

399

null Verifies that an item is bound to nil

(null item) Returns T if item is bound to nil, and returns nil otherwise. (setq a 123 b "string" c nil) (null a) returns (null b) returns (null c) returns (null ’()) returns

nil nil T T

numberp Verifies that an item is a real number or an integer

(numberp item) Returns T if item is a real or an integer, and returns nil otherwise. (setq a 123 b ’a) (numberp 4) (numberp 3.8348) (numberp "Howdy") (numberp a) (numberp b) (numberp (eval b))

returns T returns T returns nil returns T returns nil returns T

open Opens a file for access by the AutoLISP I/O functions

(open filename mode) The filename argument is a string that specifies the name and extension of the file to be opened. The mode argument is the read/write flag. It must be a string containing a single

null

400

lowercase letter. The following table describes the valid mode letters. Mode options for the open function Open mode

Description

"r"

Open for reading. If filename does not exist, open returns nil.

"w"

Open for writing. If filename does not exist, a new file is created and opened. If filename already exists, its existing data is overwritten.

"a"

Open for appending. If filename does not exist, a new file is created and opened. If filename already exists, it is opened and the pointer is positioned at the end of the existing data, so new data you write to the file is appended to the existing data.

Data passed to an open file is not actually written until th e file is closed with the close function. On DOS systems, some programs and text editors write text files with an end-of-file marker (CTRL Z, decimal ASCII code 26) at the end of the text. When reading a text file, DOS returns an end-of-file status if a CTRL Z marker is encountered, even if that marker is followed by more data. If you intend to use OPEN’s "a" mode to append data to files produced by another program, be sure that the other program does not insert CTRL Z markers at the end of its text files. The open function returns a file descriptor to be used by the other I/O functions. The file descriptor must be assigned to a symbol that uses the setq function. (setq a (open "file.ext" "r"))

Assuming that the files named in the following examples do not exist, (setq f (open "new.tst" "w")) returns (setq f (open "nosuch.fil" "r")) returns nil (setq f (open "logfile" "a")) returns

The filename argument can include a directory prefix, as in /test/func3. On DOS systems, a drive letter is also permitted, and you can use the backslash (\) instead of the forward slash (/), but remember that you must use two backslashes (\\) to obtain one backslash in a string. (setq f (open "/x/new.tst" "w")) returns (setq f (open "nosuch.fil" "r")) returns nil

Appendix A AutoLISP Function Reference

401

or Returns the logical OR of a list of expressions

(or expr...) The or function evaluates the expressions from left to right, looking for a non-nil expression. If one is found, or ceases further evaluation and returns T. If all of the expressions are nil, or returns nil. (or nil 45 ’()) (or nil ’())

returns T returns nil

osnap Returns a 3D point that is the result of applying an Object Snap mode to a specified point

(osnap pt mode) The mode argument is a string that consists of one or more valid Object Snap identifiers such as mid, cen, and so on, separated by commas. (setq pt1 (getpoint)) (setq pt2 (osnap pt1 "cen")) (setq pt3 (osnap pt1 "end,int"))

The point returned by osnap depends on the current 3D view and the setting of the APERTURE system variable.

polar Returns the UCS 3D point at a specified angle and distance from a point

(polar pt ang dist) The ang argument is expressed in radians relative to the X axis with angles increasing in the counterclockwise direction. Although pt can be a 3D point, ang is always with respect to the current construction plane.

or

402

(polar ’(1 1 3.5) 0.785398 1.414214) returns (2.0 2.0 3.5)

prin1 Prints an expression to the command line or writes an expression to an open file

(prin1 [expr [file-desc]]) The expr argument does not need to be a string. If file-desc is present and is a file descriptor for a file opened for writing, expr is written to the file exactly as it appears on the screen. Only the specified expr is printed; no newline or space is included. (setq a 123 b ’(a)) (prin1 ’a) prints A and returns A (prin1 a) prints 123 and returns 123 (prin1 b) prints (A) and returns (A) (prin1 "Hello") prints "Hello" and returns "Hello"

Each of the preceding examples is displayed on the screen because no file-desc was specified. Assuming that f is a valid file-descriptor for a file opened for writing, (prin1 "Hello" f)

will write "Hello" to the specified file and will return "Hello". If expr is a string containing control characters, prin1 expands these characters with a leading \, as shown in the following table. Control codes Code

Description

\\

\ character

\"

" character

\e

Escape character

\n

Newline character

\r

Return character

\t

Tab character

\nnn

Character whose octal code is nnn

Appendix A AutoLISP Function Reference

403

Control codes (continued) Code

Description

\U+XXXX

Unicode sequence; Note: not valid when running in a Visual LISP environment

\M+NXXXX

Unicode sequence; Note: not valid when running in a Visual LISP environment

The following examples show how to use control characters: (prin1 (chr 2)) prints "\002" and returns "\002" (prin1 (chr 10)) prints "\n" and returns "\n"

The prin1 function can be called with no arguments, in which case it returns (and prints) the null string. If you use prin1 (with no arguments) as the last expression in a userdefined function, only a blank line is printed when the function is complete, allowing the application to exit “quietly.”

princ Prints an expression to the command line, or writes an expression to an open file

(princ [expr [file-desc]]) This function is the same as prin1, except that control characters in expr are printed without expansion. In general, prin1 is designed to print expressions in a way that is compatible with load, while princ prints them in a way that is readable by functions such as read-line.

print Prints an expression to the command line, or writes an expression to an open file

(print [expr [file-desc]]) This function is the same as prin1, except that it prints a newline character before expr, and prints a space following expr.

princ

404

progn Evaluates each expression sequentially, and returns the value of the last expression

(progn [expr]...) You can use progn to evaluate several expressions where only one expression is expected. (if (= a b) (progn (princ "\nA = B ") (setq a (+ a 10) b (- b 10)) ) )

The if function normally evaluates one then expression if the test expression evaluates to anything but nil. In this example, we have used progn to cause two expressions to be evaluated instead.

Appendix A AutoLISP Function Reference

405

prompt Displays a string on your screen’s prompt area

(prompt msg) On dual-screen AutoCAD configurations, prompt displays msg on both screens and is, therefore, preferable to princ. (prompt "New value: ")

displays

New value:

on the screen(s)

The prompt function returns nil.

quit Forces the current application to quit

(quit) If quit is called, it returns the error message quit/exit abort and returns to the AutoCAD Command prompt.

See also the exit function

quote Returns an expression without evaluating it

(quote expr) This can also be written ’expr (quote a) (quote cat) (quote (a b)) ’a ’cat ’(a b)

returns A returns CAT returns (A B) returns A returns CAT returns (A B)

prompt

406

The last three examples don’t work if entered directly from the keyboard in response to an AutoCAD prompt. Remember that such input must begin with the character ( or ! to be recognized as an AutoLISP expression.

read Returns the first list or atom obtained from a string

(read [string]) The string argument cannot contain blanks except within a list or string. The read function returns its argument converted into the corresponding data type: (read "hello") returns the atom (read "hello there") returns the atom (read "\"Hi Y’all\"") returns the string (read "(a b c)") returns the list (read "(a b c) (d)") returns the list (read "1.2300") returns the real number (read "87") returns the integer (read "87 3.2") returns the integer

HELLO HELLO "Hi Y’all" (A B C) (A B C) 1.23 87 87

read-char Returns the decimal ASCII code representing the character read from the keyboard input buffer or from an open file

(read-char [file-desc]) If no file-desc is specified and there are no characters in the keyboard input buffer, read-char waits for keyboard entry (followed by ENTER ). For instance, assuming the keyboard input buffer is empty, (read-char)

waits for something to be entered. If you enter ABC followed by ENTER , read-char returns 65 (the decimal ASCII code for the letter A). The next three calls to read-char return 66, 67, and 10 (newline), respectively. If another read-char call is made, it again waits for input. The various operating systems under which AutoCAD runs use various conventions to signal the end of a line in an ASCII text file. UNIX systems, for example, use a single newline character (linefeed [LF], ASCII code 10), whereas DOS systems use a pair of

Appendix A AutoLISP Function Reference

407

characters (carriage-return [CR]/LF, ASCII codes 13 and 10) for the same purpose. To facilitate development of AutoLISP programs, read-char accepts all these conventions, returning a single newline character (ASCII code 10) whenever it detects an end-of-line character (or character sequence).

read-line Reads a string from the keyboard or from an open file

(read-line [file-desc]) If read-line encounters the end of the file, it returns nil; otherwise it returns the string that it read. For example, assuming that f is a valid open file pointer, (read-line f)

returns the next input line from the file, or returns nil if the end-of-file has been reached.

redraw Redraws the current viewport or a specified object (entity) in the current viewport

(redraw [ename [mode]]) The effect of the redraw function depends on the arguments supplied. If called with no arguments, it redraws the current viewport. If called with the ename (entity name) argument, it redraws the specified entity. The mode argument is an integer value that controls the visibility and highlighting of the entity. Modes for redraw Redraw mode

Action

1

Show entity

2

Hide entity (blank it out)

read-line

408

Modes for redraw (continued) Redraw mode

Action

3

Highlight entity

4

Unhighlight entity

If ename is the header of a complex entity (a polyline or a block reference with attributes), it processes the main entity and all its subentities if the mode argument is positive. If the mode argument is negative, redraw operates on only the header entity. The redraw function always returns nil. The use of entity highlighting (mode 3) must be balanced with entity unhighlighting (mode 4). The REDRAW command has no effect on highlighted or hidden entities; however, a REGEN forces the entities to redisplay in their normal manner.

regapp Registers an application name with the current AutoCAD drawing in preparation for using extended object data

(regapp application) The application argument is a string up to 31 characters long that adheres to the symbol-naming conventions. An application name can contain letters, digits, and the special characters dollar sign ($), hyphen (-), and underscore (_). It cannot contain spaces. Letters in the name are converted to upper case. If an application of the same name has already been registered, this function returns nil; otherwise it returns the name of the application. If registered successfully, the application name is entered into the APPID symbol table. This table maintains a list of the applications that are using extended data in the drawing. (regapp "ADESK_4153322344") (regapp "DESIGNER-v2.1-124753")

It is recommended that you pick a unique application name. One way of ensuring this is to adopt a naming scheme that uses the company or product name and a unique number (like your telephone number or the current date/time). The product version number can

Appendix A AutoLISP Function Reference

409

be included in the application name or stored by the application in a separate integer or real-number field; for example, (1040 2.1).

rem Divides the first number by the second, and returns the remainder

(rem number number...) If more than two numbers are provided, rem divides the result of dividing the first number by the second with the third, and so on. (rem 42 12) returns 6 (rem 12.0 16) returns 12.0 (rem 26 7) returns 5 (rem 5 2) returns 1 (rem 26 7 2) returns 1

repeat Evaluates each expression a specified number of times, and returns the value of the last expression

(repeat int expr...)

rem

410

The int argument must be positive. (setq a 10 b 100) (repeat 4 (setq a (+ a 10)) (setq b (+ b 100)) ) Sets a to 50, sets b to 500, and returns 500

reverse Returns a list with its elements reversed

(reverse lst) (reverse ’((a) b c))

returns (C B (A))

rtos Converts a number into a string

(rtos number [mode [precision]]) The rtos function returns a string that is the representation of number according to the settings of mode, precision, and the system variables UNITMODE and DIMZIN. The mode and precision arguments are integers that select the linear units mode and precision, as shown in the following table. Linear units values Mode value

String format

1

Scientific

2

Decimal

3

Engineering (feet and decimal inches)

4

Architectural (feet and fractional inches)

5

Fractional

Appendix A AutoLISP Function Reference

411

The mode and precision arguments correspond to the system variables LUNITS and LUPREC. If you omit the arguments, rtos uses the current settings of LUNITS and LUPREC. The UNITMODE variable affects the returned string when engineering, architectural, or fractional units are selected (a mode value of 3, 4, or 5).

set Sets the value of a quoted symbol name to an expression

(set sym expr) Returns the value of the expression. (set ’a 5.0) (set (quote b) ’a)

returns 5.0 and sets symbol A returns A and sets symbol B

If set is used with an unquoted symbol name, it can assign a new value to another symbol indirectly. For instance, given the previous examples (set b 640)

returns 640

and assigns the value 640 to symbol a, because that is what symbol b contains.

See also the setq function

set_tile Sets the value of a dialog box tile

(set_tile key value) The key argument is a string that specifies the tile, and value is a string that names the new value to assign (initially set by the value attribute).

set

412

setcfg Writes application data to the AppData section of the acad.cfg file

(setcfg cfgname cfgval) The cfgname argument is a string (132 characters maximum length) that specifies the section and parameter to set the value of cfgval (347 characters max. length). If cfgname is not valid, setcfg returns nil. The cfgname argument must be a string of the following form: "AppData/application_name/section_name/.../param_name"

The following code sets the WallThk parameter in the AppData/ArchStuff section to 8 and returns the string "8": (setcfg "AppData/ArchStuff/WallThk" "8") returns "8"

See also the getcfg function

setenv Sets a system environment variable to a specified value

(setenv varname value) The varname argument is a string specifying the name of the environment variable to be set. You must enclose the varname and value in quotation marks. Environment variable names must be spelled and cased exactly as they are stored in the system registry. Changes to settings might not take effect until the next time AutoCAD is started. For example, to set the value of the MaxArray environment variable to 10000, (setenv "MaxArray" "10000")

See also the getenv function

Appendix A AutoLISP Function Reference

413

setfunhelp Registers a user-defined command with the Help facility so that the appropriate help file and topic are called when the user requests help on that command

(setfunhelp c:fname [helpfile [topic [command]]]) The c:fname argument is a string that specifies the user-defined command (the C:XXX function) and must include the C: prefix. Unlike the function name passed to the defun function, the function argument for setfunhelp must be a quoted string. The remaining three optional arguments describe the help call to be made. They are also strings and are the same as the arguments passed to the help function. The setfunhelp function returns the string passes as c:fname if successful otherwise, it returns nil. The file extension is not required with the helpfile argument. If a file extension is provided, AutoCAD looks only for that file. If no file extension is provided, the following search rules apply: If this is AutoCAD for Windows/NT, append .hlp, else append .ahp. If no .ahp file is found, search for with no extension. Note that the file with no extension is searched last, so on UNIX, acad.ahp is searched before acad. It should be noted that this function verifies only that the c:fname argument has the c: prefix. It does not verify that the c:fname function exists or the correctness of the other arguments. When you use the defun function to define a C:XXX function, it removes that function’s name from those registered by setfunhelp (if one exists). Therefore, setfunhelp should only be called after the defun call, which defines the user-defined command. The following example uses defun to define the user-defined command MYFUN. The setfunhelp function registers the function name C:MYFUN and associates that name with the topic myfun in the file myhelp.ahp. (defun c:myfun () ... (getint "gimme: ") ... ) (setfunhelp "c:myfun" "myhelp.ahp" "myfun")

Command: myfun gimme: ’help Assuming that the AutoCAD Help file myhelp.ahp exists in the support path, AutoCAD displays the Help dialog with the topic myfun from the file myapp.ahp.

setfunhelp

414

See also the defun and help functions

setq Sets the value of a symbol or symbols to associated expressions

(setq sym1 expr1 [sym2 expr2]...) This is the basic assignment function in AutoLISP. The setq function can assign multiple symbols in one call to the function, but returns only the last expr. (setq a 5.0)

returns 5.0

Appendix A AutoLISP Function Reference

415

and sets the symbol a to 5.0. Whenever a is evaluated, it evaluates the real number 5.0. (setq b 123 c 4.7) (setq s "it") (setq x ’(a b))

returns 4.7 returns "it" returns (A B)

See also “AutoLISP Variables.”

setvar Sets an AutoCAD system variable to a specified value

(setvar varname value) If successful, setvar returns the value of the system variable. You must enclose the variable name in quotation marks. (setvar "FILLETRAD" 0.50) returns 0.5

and sets the AutoCAD fillet radius to 0.5 units. For system variables with integer values, the supplied value must be between –32,768 and +32,767. Some AutoCAD commands obtain the values of system variables before issuing any prompts. If you use setvar to set a new value while a command is in progress, the new value might not take effect until the next AutoCAD command. When using the setvar function to change the AutoCAD system variable ANGBASE, the value argument is interpreted as radians. This differs from the AutoCAD SETVAR command, which interprets this argument as degrees. When using the setvar function to change the AutoCAD system variable SNAPANG, the value argument is interpreted as radians relative to the AutoCAD default direction for angle 0, which is east or 3 o’clock. This also differs from the SETVAR command, which interprets this argument as degrees relative to the ANGBASE setting. The UNDO command does not undo changes made to the CVPORT system variable by the setvar function.

setvar

416

You can find a list of the current AutoCAD system variables in “System Variables,” in the Command Reference.

See also the getvar function

sin Returns the sine of an angle as a real number expressed in radians

(sin ang) The ang argument must be an angle expressed in radians. (sin 1.0) (sin 0.0)

returns 0.841471 returns 0.0

setview Establishes a view for a specified viewport

(setview view_descriptor [vport_id]) The view_descriptor argument is an entity definition list similar to that returned by tblsearch when applied to the VIEW symbol table. The optional argument vport_id identifies which viewport is to receive the new view. The vport_id number can be retrieved by the CVPORT system variable. If vport_id is 0, the current viewport receives the new view. If successful, the setview function returns the view_descriptor.

Appendix A AutoLISP Function Reference

417

slide_image Displays an AutoCAD slide in the currently active dialog box image tile

(slide_image x1 y1 wid hgt sldname) The slide can be a slide file (.sld) or a slide in a slide library file (.slb): the sldname argument specifies it as you would specify it for the VSLIDE command or for a menu file : sldname or libname(sldname)

The first (upper-left) corner of the slide—its insertion point—is located at (x1,y1), and the second (lower-right) corner is located at the relative distance (wid,hgt) from the first (wid and hgt must be positive values). The origin (0,0) is the upper-left corner of the image. You obtain the coordinates of the lower-right corner by calling the dimension functions (dimx_tile and dimy_tile).

snvalid Checks the symbol table name for valid characters

(snvalid sym_name [flag]) The sym_name argument is a string that specifies a symbol table name. The optional flag argument specifies whether the vertical bar character is allowed in sym_name. The flag argument can be 1 or 0 (default is 0). The snvalid function returns T if sym_name is a valid symbol table name, otherwise it returns nil. Symbol table names must consist of only alphanumeric characters and the special characters dollar sign ($), underscore (_), and hyphen (–). A null string is not a valid name.

slide_image

418

sqrt Returns the square root of a number as a real number

(sqrt num) (sqrt 4) (sqrt 2.0)

returns 2.0 returns 1.41421

ssadd Adds an object (entity) to a selection set, or creates a new selection set

(ssadd [ename [ss]]) If called with no arguments, ssadd constructs a new selection set with no members. If called with the single entity name argument ename, ssadd constructs a new selection set containing that single entity. If called with an entity name and the selection set ss, ssadd adds the named entity to the selection set. The ssadd function always returns the new or modified selection set. When adding an entity to a set, the new entity is added to the existing set, and the set passed as ss is returned as the result. Thus, if the set is assigned to other variables, they also reflect the addition. If the named entity is already in the set, the ssadd operation is ignored and no error is reported. (setq e1 (entnext)) Sets e1 to name of first entity in drawing (setq ss (ssadd)) Sets ss to a null selection set (ssadd e1 ss) Returns ss with entity name e1 added (setq e2 (entnext e1)) Gets entity following e1 (ssadd e2 ss) Returns ss with entity name e2 added

Appendix A AutoLISP Function Reference

419

ssdel Deletes an object (entity) from a selection set

(ssdel ename ss) The ssdel function deletes the entity ename from selection set ss and returns the name of selection set ss. Note that the entity is actually deleted from the selection set as opposed to a new set being returned with the element deleted. If the entity is not in the set, nil is returned. For example, given that entity name e1 is a member of selection set ss1 and entity name e2 is not, then (ssdel e1 ss1) Returns selection set ss with entity e1 removed (ssdel e2 ss1) Returns nil (does not change ss1)

ssget Prompts the user to select objects (entities), and returns a selection set

(ssget [mode] [pt1 [pt2]] [pt-list] [filter-list]) The mode argument is a string that specifies the object selection method. Valid modes are "W", "WP", "C", "CP", "L", "P", "I", and "F", corresponding to the Window, WPolygon, Crossing, CPolygon, Last, Previous, Implied, and Fence selection methods. Another optional mode value is "X", which selects the entire database. The pt1 and pt2 arguments specify points relevant to the selection. Supplying a point with no mode argument is equivalent to object selection by picking a single point. The current setting of Object Snap mode is ignored by this function unless you specifically request it while you are in the function. The filter-list argument is an association list that specifies object properties. Objects that match the filter-list are added to the selection set. If all arguments are omitted, ssget prompts the user with the Select objects prompt, allowing interactive construction of the selection set.

ssdel

420

Selection sets can contain objects from both paper and model space, but when the selection set is used in an operation, objects from the space not currently in effect are filtered out. Selection sets returned by ssget contain main entities only (no attributes or polyline vertices). Asks the user for a general object selection and places those objects in a selection set (ssget "P") Creates a selection set of the most recently selected objects (ssget "L") Creates a selection set of the last visible object added to the database (ssget "I") Creates a selection set of the objects in the implied selection set (those selected while PICKFIRST is in effect) (ssget ’(2 2)) Creates a selection set of the object passing through (2,2) (ssget "W" ’(0 0) ’(5 5)) Creates a selection set of the objects inside the window from (0,0) to (5,5) (ssget "C" ’(0 0) ’(1 1)) Creates a selection set of the objects crossing the box from (0,0) to (1,1) (ssget "X") Creates a selection set of all objects in the database (ssget "X" filter-list) Scans the database and creates a selection set of objects matching the filter-list (ssget filter-list) Asks the user for a general object selection and places only those objects matching the filter-list in a selection set (ssget "P" filter-list) Creates a selection set of the most recently selected objects that match the filter-list (ssget)

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. (setq pt_list ’((1 1)(3 1)(5 2)(2 4)) ) (ssget "WP" pt_list) (ssget "CP" pt_list) (ssget "F" pt_list) (ssget "WP" pt_list filter-list)

Creates a selection set of all objects inside the polygon defined by pt_list Creates a selection set of all objects crossing and inside the polygon defined by pt_list Creates a selection set of all objects intersecting the fence defined by pt_list Creates a selection set of all objects inside the polygon defined by pt_list that match

the filter-list 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 once. If this limit is reached, AutoCAD refuses to create any more selection sets and returns nil to all ssget calls. To close an unneeded selection set variable, set it to nil. A selection set variable can be passed to AutoCAD in response to any Select objects prompt at which selection by Last is valid. It selects all the objects in the selection set variable.

Appendix A AutoLISP Function Reference

421

Selection Set Filters Selection set filter lists can be used with any of the selection modes. 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 PICKFIRST is in effect): (ssget "I" ‘((0 . "LINE") (62 . 5)))

Using the ssget filter list, you can select all objects containing extended data for a particular application. You do this by using the –3 group code, as in (ssget "P" ’((0 . "CIRCLE") (-3 ("APPNAME"))))

This selects all circles containing data for the "APPNAME" application. For more information, see “Selection Set Filter Lists” and “Filtering for Extended Data”.

Relational Tests Unless otherwise specified, an “equals” test is implied for each item in the filter-list. For numeric groups (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 is a string that indicates the test operator to be applied to the next group in the filter list. (ssget "X" ’((0 . "CIRCLE") (-4 . ">=") (40 . 2.0)))

selects all circles whose radius (group code 40) is greater than or equal to 2.0. The following table shows the possible operators. Relational operators for selection set filter lists Operator

Description

"*"

Anything goes (always true)

"="

Equals

"!="

Not equal to

"/="

Not equal to

""

Not equal to

"="

Greater than or equal to

"&"

Bitwise AND (integer groups only)

"&="

Bitwise masked equals (integer groups only)

The use of relational operators depends on the kind of group 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. 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 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), the “anything goes” operator, "*", is assumed. Direction vectors (group type 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 groups; use wild-card tests instead.

Appendix A AutoLISP Function Reference

423

Logical Grouping of Filter Tests The relational operators described in the previous subsection are binary operators. You can also test groups by creating nested Boolean expressions that use the grouping operators shown in the following table. The grouping operators are specified by –4 groups, like the relational operators. They are paired, and must be balanced correctly in the filter list or the ssget call fails. The number of operands these operators can enclose depends on the operation. Grouping operators for selection set filter lists Starting operator

Encloses

Ending operator

""

""

""

""

With the grouping operators, an operand is an entity-field group, a relational operator followed by an entity-field group, or a nested expression created by these operators. The following is an example of grouping operators in a filter list: (ssget "X" ’((-4 . "")) )

This selects all circles with radius 1.0, plus all lines on layer "ABC". Because the grouping operators are not case-sensitive, you can also use their lowercase equivalents: "", "", "", "".

ssget

424

ssgetfirst Determines which objects are selected and gripped

(ssgetfirst) Returns a list of two selection sets similar to those passed to sssetfirst. The first element in the list is a selection set of entities that are gripped but not selected. The second element is a selection set of entities that are both gripped and selected. Either (or both) elements of the list can be nil. Only entities from the current drawing’s model space and paper space, not nongraphical objects or entities in other block definitions, can be analyzed by this function.

sslength Returns an integer containing the number of objects (entities) in a selection set

(sslength ss) The number is returned as a real if it is greater than 32,767. Selection sets never contain duplicate selections of the same entity. (setq sset (ssget "L")) Places the last object in selection set sset (sslength sset) returns 1

ssmemb Tests whether an object (entity) is a member of a selection set

(ssmemb ename ss) If it is, ssmemb returns the entity name (ename). If not, it returns nil. For example, given that entity name e1 is a member of selection set ss1 and entity name e2 is not, then (ssmemb e1 ss1) (ssmemb e2 ss1)

returns entity name e1 returns nil

Appendix A AutoLISP Function Reference

425

ssname Returns the object (entity) name of the indexed element of a selection set

(ssname ss index) The index argument must be an integer. If index is negative or greater than the highest numbered entity in the selection set, nil is returned. The first element in the set has an index of zero. Entity names in selection sets obtained with ssget always are names of main entities. Subentities (attributes and polyline vertices) are not returned. (The entnext function allows access to them. See “entnext.”) (setq sset (ssget)) Creates a selection set named sset (setq ent1 (ssname sset 0)) Gets name of first entity in sset (setq ent4 (ssname sset 3)) Gets name of fourth entity in sset

To access entities beyond the 32767th one in a selection set, you must supply the index argument as a real. For example: (setq entx (ssname sset 50843.0)) Gets name of 50844th entity in sset

ssnamex Retrieves information about how a selection set was created

(ssnamex ss [index]) This function returns the entity name of the element specified by index from the selection set ss along with data that describes how the entity was selected. If the index argument is not supplied, this function returns a list containing the entity names of all of the elements in the selection set along with data that describes how each of the entities was selected.

ssname

426

The data returned by ssnamex takes the form of a list of lists that contains information that either describes an entity and its selection method or a polygon that was used to select one or more entities. Each sub-list that describes the selection of a particular entity comprises three parts: the selection method ID (an integer >= 0), the entity name of the selected entity, and selection method specific data that describes how the entity was selected. ((sel_id1 ename1 (data))(sel_id2 ename2 (data)) ... )

The following table lists the selection method IDs. Selection method IDs ID

Description

0

non specific (i.e. Last All etc.)

1

Pick

2

Window or WPolygon

3

Crossing or CPolygon

4

Fence

Each sub-list that describes a polygon that’s used during entity selection takes the form of a polygon ID (an integer < 0), followed by point descriptions. (polygon_id point_description_1 point_description_n... )

Polygon ID numbering starts at –1 and each additional polygon ID is incremented by –1. Depending on the viewing location, a point is represented as one of the following: an infinite line, a ray, or a line segment. A point descriptor comprises three parts: a point descriptor ID (the type of item being described), the start point of the item, and an optional unit vector that describes either the direction in which the infinite line travels or a vector that describes the offset to the other side of the line segment. (point_descriptor_id base_point [unit_or_offset_vector])

Appendix A AutoLISP Function Reference

427

The following table lists the valid point descriptor IDs. Point descriptor IDs ID

Description

0

Infinite line

1

Ray

2

Line segment

The unit_or_offset_vector is returned when the view point is something other than 0,0,1. The data associated with Pick (type 1) entity selections is a single point description. For example, the following record is returned for the selection of an entity picked at 1,1 in plan view of the WCS: (1 (0 (1.0 1.0 0.0) ) ) The data associated with an entity selected with the Window, WPolygon, Crossing, or CPolygon method is the integer ID of the polygon that selected the entity. It is up to the application to associate the polygon identifiers and make the connection between the polygon and the entities it selected. For example, the following record is returned for an entity selected by Crossing (note that the polygon ID is –1). ((3 –1) (–1 (0 (5.14828 7.05067 0.0) ) (0 (7.13676 7.05067 0.0) ) (0 (7.13676 4.62785 0.0) ) (0 (5.14828 4.62785 0.0) ) ) ) The data associated with Fence selections is a list of points descriptions for the points where the fence and entity visually intersect. For example, the following record is returned for a nearly vertical line intersected three times by a Z-shaped fence. ((4 (0 (5.28135 6.25219 0.0) ) (0 (5.61868 2.81961 0.0) ) (0 (5.52688 3.75381 0.0) ) ) ) Only selection sets with entities from the current drawing’s model space and paper space—not nongraphical objects or entities in other block definitions—can be retrieved by this function.

ssnamex

428

sssetfirst Sets which objects are selected and gripped

(sssetfirst gripset [pickset]) The selection set of objects specified by the gripset argument are gripped, and the selection set of objects specified by pickset are both gripped and selected. If any objects are common to both selection sets, sssetfirst grips and selects the selection set specified by pickset only (it does not grip the gripset set). If gripset is nil sssetfirst grips and selects the pickset set. The sssetfirst function returns a list of the two variables passed as the selection sets. Do not call ads_ssetfirst() when AutoCAD is in the middle of executing a command.

startapp Starts a Windows application

(startapp appcmd [file]) The appcmd argument is a string that specifies the application to execute. If appcmd does not include a full path name, it searches the PATH environment variable for the application. The file argument is a string that specifies the file name to be opened. Returns an integer greater than 0 if successful; otherwise it returns 0. The following code starts the Windows Notepad and opens the acad.lsp file. (startapp "notepad" "acad.lsp")

If an argument has embedded spaces, it must be surrounded by literal double quotes. For example, to edit the file my stuff.txt with Notepad use the following syntax: (startapp "notepad.exe" "\"my stuff.txt\"")

Externally defined function acadapp ARX application

Appendix A AutoLISP Function Reference

429

start_dialog Displays a dialog box and begins accepting user input

(start_dialog) You must first initialize the dialog box by a previous new_dialog call. The dialog box remains active until an action expression or callback function calls done_dialog. Usually done_dialog is associated with the tile whose key is "accept" (typically the OK button) and the tile whose key is "cancel" (typically the Cancel button). The start_dialog function has no arguments. It returns the optional status passed to done_dialog. The default value is 1 if the user pressed OK, 0 if the user pressed Cancel, or -1 if all dialog boxes were terminated with term_dialog. But if done_dialog is passed an integer status greater than 1, start_dialog returns this value, whose meaning depends on the application.

start_image Starts the creation of an image in the dialog box tile

(start_image key) Subsequent calls to fill_image, slide_image, and vector_image affect this image until the application calls end_image. The key argument is a string that specifies the dialog box tile. The key argument is case-sensitive. Do not use the set_tile function between start_image and end_image function calls.

start_dialog

430

start_list Starts the processing of a list in the list box or in the pop-up list dialog box tile

(start_list key [operation [index]]) The key argument is a string that specifies the dialog box tile. The key argument is casesensitive. The operation argument is an integer value whose meaning is summarized in the following table. List box codes for start_list Value

Description

1

Change selected list contents

2

Append new list entry

3

Delete old list and create new list (the default)

The index argument is ignored unless the start_list call begins a change operation (1), in which case index indicates the list item to change by the subsequent add_list call. The index is zero based. If you don’t specify operation, it defaults to 3 (create new list), and if you specify operation but not index, the index defaults to 0. Subsequent calls to add_list affect the list started by start_list until the application calls end_list. Do not use the set_tile function between start_list and end_list function calls.

Appendix A AutoLISP Function Reference

431

strcase Returns a string where all alphabetic characters have been converted to upper case or lower case

(strcase string [which]) If which is omitted or evaluates to nil, all alphabetic characters in string are converted to upper case. If which is supplied and is not nil, all alphabetic characters in string are converted to lower case. (strcase "Sample") (strcase "Sample" T)

returns "SAMPLE" returns "sample"

The strcase function will correctly handle case mapping of the currently configured character set.

strcat Returns a string that is the concatenation of multiple strings

(strcat string1 [string2]...) (strcat "a" "bout") (strcat "a" "b" "c") (strcat "a" "" "c")

returns "about" returns "abc" returns "ac"

strlen Returns an integer that is the number of characters in a string

(strlen [string]...) If multiple string arguments are provided, it returns the sum of the lengths of all arguments. Omitting the arguments or entering an empty string returns 0 (zero). (strlen "abcd") returns 4 (strlen "ab") returns 2 (strlen "one" "two" "four" returns 10 (strlen) returns 0

strcase

432

(strlen "")

returns 0

subst Searches a list for an old item and returns a copy of the list with a new item substituted in place of every occurrence of the old item

(subst newitem olditem lst) If olditem is not found in lst, subst returns lst unchanged. (setq sample ’(a b (c d) b)) (subst ’qq ’b sample) returns (A QQ (C D) QQ) (subst ’qq ’z sample) returns (A B (C D) B) (subst ’qq ’(c d) sample) returns (A B QQ B) (subst ’(qq rr) ’(c d) sample) returns (A B (QQ RR) B) (subst ’(qq rr) ’z sample) returns (A B (C D) B)

When used in conjunction with assoc, subst provides a convenient means of replacing the value associated with one key in an association list. (setq who ’((first john) (mid q) (last public))) (setq old (assoc ’first who) sets old to (FIRST JOHN) new ’(first j) sets new to (FIRST J) ) (subst new old who) returns ((FIRST J)(MID Q)(LAST PUBLIC))

substr Returns a substring of a string

(substr string start [length]) The substr function starts at the start character position of string and continues for length characters. If length is not specified, the substring continues to the end of string. The start and length arguments must be positive integers.

Appendix A AutoLISP Function Reference

433

The first character of string is character number 1. This differs from other functions that process elements of a list (like nth and ssname) that count the first element as 0. (substr "abcde" 2) (substr "abcde" 2 1) (substr "abcde" 3 2)

returns "bcde" returns "b" returns "cd"

tablet Retrieves and sets digitizer (tablet) calibrations

(tablet code [row1 row2 row3 direction]) Depending on the integer specified by code, tablet either retrieves the current digitizer calibration or sets the calibration. If code is 0, tablet returns the current calibration. If code is 1, it must be followed by the new calibration settings: row1, row2, row3, and direction. code

An integer. If the code you pass equals 0, tablet returns the current calibration; in this case, the remaining arguments must be omitted. If the code you pass equals 1, tablet sets the calibration according to the arguments that follow; in this case, you must provide the other arguments.

row1, row2, row3

Three 3D points. These three arguments specify the three rows of the tablet’s transformation matrix.

direction

One 3D point. This is the vector (expressed in the World Coordinate System, or WCS) that is normal to the plane that represents the surface of the tablet.

If the direction specified isn’t normalized, tablet corrects it, so the direction it returns when you set the calibration may differ from the value you passed. In a similar way, the third element in row3 (Z) should always equal 1: tablet returns it as 1 even if the row3 in the list specified a different value. If tablet fails, it returns nil and sets the ERRNO system variable to a value that indicates the reason for the failure. This can happen if the digitizer is not a tablet. A very simple transformation that can be established with tablet is the identity transformation: (tablet 1 ’(1 0 0) ’(0 1 0) ’(0 0 1) ’(0 0 1))

With this transformation in effect, AutoCAD will receive, effectively, raw digitizer coordinates from the tablet. For example, if you pick the point with digitizer coordinates

tablet

434

(5000,15000), AutoCAD will see it as the point in your drawing with those same coordinates. The TABMODE system variable allows AutoLISP routines to toggle the tablet on and off.

tblnext Finds the next item in a symbol table

(tblnext table-name [rewind]) The table-name argument is a string the identifies the symbol table. Valid table-name values are "LAYER", "LTYPE", "VIEW", "STYLE", "BLOCK", "UCS", "APPID", "DIMSTYLE", and "VPORT". The string does not need to be upper case. Since the vports function returns current VPORT table information, it may be easier to use vports as opposed to tblnext to retrieve this information. When tblnext is used repeatedly, it normally returns the next entry in the specified table each time. The tblsearch function can set the next entry to be retrieved. However, if the rewind argument is present and evaluates to a non-nil value, the symbol table is rewound and the first entry in it is retrieved. If there are no more entries in the table, nil is returned. Deleted table entries are never returned. If an entry is found, it is returned as a list of dotted pairs of DXF-type codes and values. (tblnext "layer" T)

Retrieves first layer

might return ((0 . "LAYER") Symbol type (2 . "0") Symbol name (70 . 0) Flags (62 . 7) Color number, negative if off (6 . "CONTINUOUS") Linetype name )

Note that there is no –1 group. AutoCAD remembers the last entry returned from each table and returns the next one each time tblnext is called for that table. When you begin scanning a table, be sure to supply a non-nil second argument to rewind the table and to return the first entry. Entries retrieved from the block table include a –2 group with the entity name of the first entity in the block definition (if any). Thus, given a block called BOX, (tblnext "block")

Appendix A AutoLISP Function Reference

435

Retrieves block definition

might return ((0 . "BLOCK") (2 . "BOX") (70 . 0) (10 9.0 2.0 0.0) (-2 . ) )

Symbol type Symbol name Flags Origin X,Y,Z First entity

The entity name in the –2 group is accepted by entget and entnext, but not by other entity access functions. For example, you cannot use ssadd to put it in a selection set. By providing the –2 group entity name to entnext, you can scan the entities comprising a block definition; entnext returns nil after the last entity in the block definition. If a block contains no entities, the –2 group returned by tblnext is the entity name of its endblk entity.

tblobjname Returns the entity name of a specified symbol table entry

(tblobjname table-name symbol) The tblobjname function searches the symbol table, table-name, for the symbol name symbol and returns the entity name of that symbol table entry. The entity name returned by tblobjname can be used in entget and entmod operations.

tblsearch Searches a symbol table for a symbol name

(tblsearch table-name symbol [setnext]) The tblsearch function searches the symbol table, table-name, for the symbol name symbol. Both names are converted to upper case automatically. If tblsearch finds an entry for the given symbol name, it returns that entry in the format described for tblnext. If no such entry is found, it returns nil. (tblsearch "style" "standard") Retrieves text style

might return ((0 . "STYLE")

Symbol name

tblobjname

436

(70 . 0) (40 . 0.0) (41 . 1.0) (50 . 0.0) (71 . 0) (3 . "txt") (4 . "")

Flags Fixed height Width factor Obliquing angle Generation flags Primary font file Bigfont file

)

Normally, tblsearch has no effect on the order of entries retrieved by tblnext. However, if tblsearch is successful and the setnext argument is present and non-nil, the tblnext entry counter is adjusted so that the following tblnext call returns the entry after the one returned by this tblsearch call.

term_dialog Terminates all current dialog boxes as if the user had canceled each of them

(term_dialog) If an application is terminated while any DCL files are open, AutoCAD automatically calls term_dialog. This function is used mainly for aborting nested dialog boxes. The term_dialog function always returns nil.

terpri Prints a newline to the command line

(terpri) The terpri function is not used for file I/O. To write a newline to a file, use prin1, princ, or print.

Appendix A AutoLISP Function Reference

437

textbox Measures a specified text object, and returns the diagonal coordinates of a box that encloses the text

(textbox elist) The elist argument is an entity definition list in the form returned by entget. It must define a text object. If fields that define text parameters other than the text itself are omitted from elist, the current (or default) settings are used. If textbox is successful, it returns a list of two points; otherwise it returns nil. The minimum list accepted by textbox is that of the text itself. (textbox ’((1 . "Hello world.")))

might return ((0.0 0.0 0.0) (0.8 0.2 0.0))

In this case, textbox would use the current defaults for text to supply the remaining parameters. The points returned by textbox describe the bounding box of the text object as if its insertion point is located at (0,0,0) and its rotation angle is 0. The first list returned is generally the point (0.0 0.0 0.0) unless the text object is oblique or vertical, or it contains letters with descenders (such as g and p). The value of the first point list specifies the offset from the text insertion point to the lower-left corner of the smallest rectangle enclosing the text. The second point list specifies the upper-right corner of that box. Regardless of the orientation of the text being measured, the point list returned always describes the bottom-left and upper-right corners of this bounding box.

textpage Switches from the graphics screen to the text screen

(textpage) The textpage function is equivalent to textscr. This function always returns nil.

textbox

438

textscr Switches from the graphics screen to the text screen (like the AutoCAD Flip Screen function key)

(textscr) The textscr function always returns nil.

trace Aids in AutoLISP debugging

(trace function...) The trace function sets the trace flag for the specified functions. Each time a specified function is evaluated, a trace display appears showing the entry of the function (indented to the level of calling depth) and prints the result of the function. (trace my-func)

returns MY-FUNC

and sets the trace flag for function MY-FUNC. The trace function returns the last function name passed to it.

See also the untrace function

trans Translates a point (or a displacement) from one coordinate system to another

(trans pt from to [disp]) The pt argument is a list of three reals that can be interpreted as either a 3D point or a 3D displacement (vector). The from argument indicates the coordinate system in which pt is expressed, and to specifies the coordinate system of the returned point. The optional disp argument, if present and non-nil, specifies that pt is to be treated as a 3D displace-

Appendix A AutoLISP Function Reference

439

ment rather than as a point. The from and to arguments can be an integer code (as specified in the following table), an entity name, or a 3D extrusion vector. Coordinate system codes Code

Coordinate system

0

World (WCS)

1

User (current UCS)

2

Display: DCS of current viewport when used with code 0 or 1 DCS of current model space viewport when used with code 3

3

Paper space DCS (used only with code 2)

If you use an entity name for the from or to arguments it must be passed as returned by the entnext, entlast, entsel, nentsel, and ssname functions. This lets you translate a point to and from the Object Coordinate System (OCS) of a particular object. (For some objects, the OCS is equivalent to the WCS; for these objects, conversion between OCS and WCS is a null operation.) A 3D extrusion vector (a list of three reals) is another method of converting to and from an object’s OCS. However, this does not work for those objects whose OCS is equivalent to the WCS. The trans function returns a 3D point (or displacement) in the requested to coordinate system. For example, given a UCS that is rotated 90 degrees counterclockwise around the World Z axis, (trans ’(1.0 2.0 3.0) 0 1) (trans ’(1.0 2.0 3.0) 1 0)

returns (2.0 -1.0 3.0) returns (-2.0 1.0 3.0)

For example, to draw a line from the insertion point of a piece of text (without using Osnap), you convert the text object’s insertion point from the text object’s OCS to the UCS. (trans text-insert-point text-ename 1)

You can then pass the result to the From point prompt. Conversely, you must convert point (or displacement) values to their destination OCS before feeding them to entmod. For example, if you want to move a circle (without using the MOVE command) by the UCS-relative offset (1,2,3), you need to convert the displacement from the UCS to the circle’s OCS: (trans ’(1 2 3) 1 circle-ename)

Then you add the resulting displacement to the circle’s center point.

trans

440

For example, if you have a point entered by the user and want to find out which end of a line it looks closer to, you convert the user’s point from the UCS to the DCS. (trans user-point 1 2)

Then you convert each of the line’s endpoints from the OCS to the DCS. (trans endpoint line-ename 2)

From there you can compute the distance between the user’s point and each endpoint of the line (ignoring the Z coordinates) to determine which end looks closer. The trans function can also transform 2D points. It does this by filling in the Z coordinate with an appropriate value. The Z component used depends on the from coordinate system that was specified and on whether the value is to be converted as a point or as a displacement. If the value is to be converted as a displacement, the Z value is always 0.0; if the value is to be converted as a point, the filled-in Z value is determined as shown in the following table. Converted 2D point Z values From

Filled-in Z value

WCS

0.0

UCS

Current elevation

OCS

0.0

Appendix A AutoLISP Function Reference

441

Converted 2D point Z values (continued) From

Filled-in Z value

DCS

Projected to the current construction plane (UCS XY plane + current elevation)

PSDCS

Projected to the current construction plane (UCS XY plane + current elevation)

type Returns the type of a specified item

(type item) The types are returned as one of the atoms shown in the following table: Symbol types Type

Description

Type

Description

REAL

Floating-point numbers

SUBR

Internal functions

FILE

File descriptors

EXSUBR

External functions (ARX)

STR

Strings

PICKSET

Selection sets

INT

Integers

ENAME

Entity names

SYM

Symbols

PAGETB

Function paging table

LIST

Lists (and user functions)

Items that evaluate to nil (such as an unassigned symbol) return nil.

type

442

For example, given the assignments (setq a 123 r 3.45 s "Hello!" x ’(a b c)) (setq f (open "name" "r"))

then (type ’a) (type a) (type f) (type r) (type s) (type x) (type +) (type nil)

returns SYM returns INT returns FILE returns REAL returns STR returns LIST returns SUBR returns nil

The following example uses the type function: (defun isint (a) (if (= (type a) ’INT) is TYPE integer? T yes, return T nil no, return nil ) )

unload_dialog Unloads a DCL file

(unload_dialog dcl_id) Unloads the DCL file associated with dcl_id (which was obtained from a previous new_dialog call). Always returns nil.

untrace Clears the trace flag for the specified functions

(untrace function...) Returns the last function name.

Appendix A AutoLISP Function Reference

443

The following code clears the trace flag for function MY-FUNC: (untrace my-func)

returns MY-FUNC

See also the trace function

vector_image Draws a vector in the currently active dialog box image

(vector_image x1 y1 x2 y2 color) This function draws a vector in the currently active dialog box image (opened by start_image) from the point (x1,y1) to (x2,y2). The color parameter is an AutoCAD color number or one of the logical color numbers shown in the following table. Symbolic names for the color attribute Color number

ADI mnemonic

Description

–2

BGLCOLOR

Current background of the AutoCAD graphics screen

–15

DBGLCOLOR

Current dialog box background color

–16

DFGLCOLOR

Current dialog box foreground color (for text)

–18

LINELCOLOR

Current dialog box line color

The origin (0,0) is the upper-left corner of the image. You can obtain the coordinates of the lower-right corner by calling the dimension functions (dimx_tile and dimy_tile).

vector_image

444

ver Returns a string that contains the current AutoLISP version number

(ver) The ver function should be used (with equal) to check the compatibility of programs. The string takes the form "AutoLISP Release X.X (nn)"

where X.X is the current version number and nn is a two letter language description. (ver) might return "AutoLISP Release 14.0 (en)"

Examples of the two letter language descriptions are as follows: (en) US/UK

(es) Spanish

(de) German

(it) Italian

(fr) French

WARNING! Before using ver in a Visual LISP program, you must initialize the variable *al-ver* in native AutoLISP. Use (setq *al-ver* (ver)) to initialize the variable. An error will result if you try to use ver without initializing *al-ver*.

vl-acad-defun Defines a Visual LISP function symbol as a function in native AutoLISP (VLISP Function)

(vl-acad-defun ’symbol) symbol - function name. Returns: Indeterminate

Appendix A AutoLISP Function Reference

445

vl-acad-undefun Undefines a Visual LISP function symbol so that it is no longer recognized as a function in native AutoLISP (VLISP Function)

(vl-acad-undefun ’symbol) symbol - function name. Returns: T, if successful nil, if unsuccessful (for example, the function was not defined in AutoLISP)

vl-consp Determines whether or not a list is nil (VLISP Function)

(vl-consp list-variable) The vl-consp function determines whether a variable contains a valid list definition. It returns T if list-variable is a non-nil list, and nil if it is not. (vl-consp nil) returns (vl-consp t) returns (vl-consp (cons 0 "LINE"))returns

nil nil T

vl-directory-files Lists all files in a given directory (VLISP Function)

(vl-directory-files [directory pattern directories]) Lists all files in a given directory

directory - (string) directory to collect files for; if nil or absent, use current directory pattern - (string) DOS pattern for file name; if nil or absent, use "*.*" directories - (fixnum) specifies if returned list should include directory names: -1 - directories only 0 - files and directories (default) 1 - files only;

vl-acad-undefun

446

Returns a list of the files/sub-directories from the given directory which matches the pattern. Examples: _$ (vl-directory-files "c:/acadwin" "acad*.exe") ("ACAD.EXE" "ACADAPP.EXE" "ACADL.EXE" "ACADPS.EXE") _$ (vl-directory-files "e:/acadwin" nil -1) ("." ".." "SUPPORT" "SAMPLE" "ADS" "FONTS" "IGESFONT" "SOURCE" "ASE") _$ (vl-directory-files "E:/acad13c4" nil -1) ("." ".." "WIN" "COM" "DOS")

vl-every Checks whether the predicate is true for every element combination (VLISP Function)

(vl-every predicate-function list [more-lists]...) The vl-every function passes the first element of each supplied list as an argument to the test function, followed by the next element from each list, and so on. Evaluation stops as soon as one of the lists runs out. predicate-function - test function. May be any function that accepts as many arguments as there are lists provided with vl-every, and returns T on any user-specified condition. The predicate-function value should be: symbol (function name) or ’(LAMBDA (A1 A2) ...) form or (FUNCTION (LAMBDA (A1 A2) ...)) form. Returns: T, if predicate function returned non-nil for every element combination nil, otherwise.

Examples: Check whether there are any empty files in the current directory: _$ (vl-every ’(lambda (fnm) (> (vl-file-size fnm) 0)) (vl-directory-files nil nil 1) ) T

Check whether number list in NLST is ordered by ’string char-codes-list) char-codes-list - list of non-negative integers; integer must be less than 256 Returns: A string of characters, with each character based on one of the integers supplied in char-codes-list Examples: (vl-list->string nil) "" (vl-list->string ’(49 50)) "12"

vl-list-length Calculates list length of a true list (VLISP Function)

(vl-list-length list-or-cons-object) list-or-cons-object - a true or dotted list. Returns: An integer containing the list length, if the argument is a true list nil, if list-or-cons-object is a circular or dotted list

Compatibility note: The vl-list-length function returns nil for a dotted list, while the corresponding Common Lisp function issues an error message if the argument is a dotted list. Examples: (vl-list-length nil) 0 (vl-list-length ’(1 2))

2 (vl-list-length ’(1 2 . 3))

nil

Appendix A AutoLISP Function Reference

455

vl-member-if Determines if the predicate is true for one of the list members (VLISP Function)

(vl-member-if predicate-function list) predicate-function - test function. May be any function that accepts a single argument and returns T for any user-specified condition. The predicate-function value should be one of the following: symbol (function name) ’(LAMBDA (A1) ...) form (FUNCTION (LAMBDA (A1) ...)) form The vl-member-if function passes each element in list to the function specified in predicate-function. If the function returns a non-nil value, vl-member-if returns the rest of the list in the same manner as the member function. Returns: A list, starting with the first element that passes the test and containing all elements following this in the original argument nil, if none of the elements passes the test condition

Examples: (COMMAND "_.LINE" ’(0 50) ’(50 50) nil) nil (vl-member-if ’(lambda (x) (= (cdr x) "AcDbLine")) (entget (entlast))) ((100 . "AcDbLine") (10 0.0 50.0 0.0) (11 50.0 50.0 0.0) (210 0.0 0.0 1.0))

vl-member-if-not Determines if the predicate is nil for one of the list members (VLISP Function)

(vl-member-if-not predicate-function list) predicate-function - test function. May be any function that accepts a single argument and returns T for any user-specified condition. The predicate-function value should be one of the following: symbol (function name) ’(LAMBDA (A1) ...) form

vl-member-if

456

(FUNCTION (LAMBDA (A1) ...))form The vl-member-if-not function passes each element in list to the function specified in predicate-function. If the function returns nil, vl-member-if-not returns the rest of the list in the same manner as the member function. Returns: A list, starting with the first element that fails the test and containing all elements following this in the original argument nil, if none of the elements fails the test condition

Examples: _$ (vl-member-if-not ’atom ’(1 "Str" (0 . "line") nil t)) ((0 . "line") nil T)

vl-position Returns the index of the specified list item (VLISP Function)

(vl-position symbol list) symbol - any AutoLISP symbol list - a true list Returns: An integer containing the index position of the specified item in the list, or nil if the item does not exist in the list Note that the first list element is index 0, the second element is index 1, and so on. Example: _$ (setq stuff (list "a" "b" "c" "d" "e")) ("a" "b" "c" "d" "e") _$ (vl-position "c" stuff) 2

Appendix A AutoLISP Function Reference

457

vl-prin1-to-string Returns the string representation of any LISP object as if it were output by the prin1 function (VLISP Function)

(vl-prin1-to-string object) object - any LISP object Returns: String-printed representation of object, as output by prin1 Examples: _$ (vl-prin1-to-string "abc") "\"abc\"" _$ (vl-prin1-to-string "c:\\acadwin") "\"C:\\\\ACADWIN\"" _$ (vl-prin1-to-string ’my-var) "MY-VAR"

vl-princ-to-string Returns the string representation of any LISP object as if it were output by the princ function (VLISP Function)

(vl-princ-to-string object) object - any LISP object Returns: String-printed representation of object, as output by princ Examples: _$ (vl-princ-to-string "abc") "abc" _$ (vl-princ-to-string "c:\\acadwin") "C:\\ACADWIN" _$ (vl-princ-to-string ’my-var) "MY-VAR"

vl-prin1-to-string

458

vl-registry-delete Deletes the specified key or value from the Windows Registry (VLISP Function)

(vl-registry-delete reg-key [val-name]) reg-key - Registry key (string) val-name - Registry value (string) If val-name is supplied and is not nil, the specified value will be purged from the Registry. If val-name is absent or nil, the function deletes the specified key and all of its values. This function cannot delete a key that has subkeys. To delete a subtree you must use vl-registry-descendents to enumerate all subkeys and delete all of them.

Returns: T if successful, nil otherwise

Example: _$ (vl-registry-write "HKEY_CURRENT_USER\\Test" "" "test data") "test data" _$ (vl-registry-read "HKEY_CURRENT_USER\\Test") "test data" _$ (vl-registry-delete "HKEY_CURRENT_USER\\Test") T

vl-registry-descendents Returns a list of subkeys or value names for the specified Registry key (VLISP Function)

(vl-registry-descendents reg-key [val-names]) reg-key - Registry key (string) val-names - Registry values (string) If val-names is supplied and is not nil, the specified value names will be listed from the Registry. If val-name is absent or nil, the function displays all subkeys of reg-key. Returns: A list of strings, if successful, nil otherwise

Appendix A AutoLISP Function Reference

459

Example: $ (vl-registry-descendents "HKEY_LOCAL_MACHINE\\SOFTWARE") ("Description" "Program Groups" "ORACLE" "ODBC" "Netscape" "Microsoft")

vl-registry-read Returns data stored in the Windows Registry for the specified key/value pair (VLISP Function)

(vl-registry-read reg-key [val-name]) reg-key - Registry key (string) val-name - Registry value (string) If val-name is supplied and is not nil, the specified value will be read from the Registry. If val-name is absent or nil, the function reads the specified key and all of its values. Returns: Registry data (a string) if successful, nil otherwise Example: $ (vl-registry-read "HKEY_CURRENT_USER\\Test") nil _$ (vl-registry-write "HKEY_CURRENT_USER\\Test" "" "test data") "test data" _$ (vl-registry-read "HKEY_CURRENT_USER\\Test") "test data"

vl-registry-write Creates a key in the Windows Registry (VLISP Function)

(vl-registry-write reg-key [val-name val-data]) reg-key - Registry key (string) val-name - Registry value (string) val-data - Registry data (string) If val-name is not supplied or is nil, a default value for the key is written. If val-name is supplied and val-data is not specified, an empty string is stored.

vl-registry-read

460

Returns: val-data, if successful, nil otherwise Example: _$ (vl-registry-write "HKEY_CURRENT_USER\\Test" "" "test data") "test data" _$ (vl-registry-read "HKEY_CURRENT_USER\\Test") "test data"

vl-remove Removes elements from a list (VLISP Function)

(vl-remove element-to-remove list) element-to-remove - value of element to be removed; may be any LISP data type list - any list Returns: The list with all elements except those equal to element-to-remove Example: (vl-remove pi (list pi t 0 "abc"))

(T 0 "abc")

vl-remove-if Returns all elements of the supplied list which fail the test function (VLISP Function)

(vl-remove-if predicate-function list) predicate-function - test function. May be any function that accepts one argument and returns T on a user-specified condition. The predicate-function value should be one of the following: symbol (function name) ’(LAMBDA (A1 A2) ...) form (FUNCTION (LAMBDA (A1 A2) ...)) form

Returns: A list containing all elements of list for which predicate-function returns nil

Appendix A AutoLISP Function Reference

461

Examples: _$ (vl-remove-if ’vl-symbolp (list pi t 0 "abc"))

(3.14159 0 "abc")

vl-remove-if-not Returns all elements of the supplied list which pass the test function (VLISP Function)

(vl-remove-if-not predicate-function list) predicate-function - test function. May be any function that accepts one argument and returns a non-nil value for any user-specified condition. The predicate-function value should be one of the following: symbol (function name) ’(LAMBDA (A1) ...) form (FUNCTION (LAMBDA (A1) ...)) form

Returns: A list containing all elements of list for which predicate-function returns a non-nil value Examples: _$ (vl-remove-if-not ’vl-symbolp (list pi t 0 "abc")) (T)

vl-some Checks whether the predicate is not nil for one element combination (VLISP Function)

(vl-some predicate-function list [more-lists]...) predicate-function - test function. Can be any function that accepts as many arguments as there are lists provided with vl-some, and returns T on a user-specified condition. The predicate-function value should be one of the following: symbol (function name) ’(LAMBDA (A1 A2 ...) ...) form (FUNCTION (LAMBDA (A1 A2 ...) ...)) form

vl-remove-if-not

462

The vl-some function passes the first element of each supplied list as an argument to the test function, then the next element from each list, and so on. Evaluation stops as soon as the predicate function returns non-nil for an argument combination or one of the lists runs out. Returns: predicate value, if predicate function returned non-nil nil, otherwise

Examples: Check whether number list NLST has equal elements in sequence: (setq nlst (list 0 2 pi pi 4)) (0 2 3.14159 3.14159 4) (vl-some ’= nlst (cdr nlst)) T

vl-sort Sorts the elements in a list according to a given compare function (VLISP Function)

(vl-sort list less?-function) list - any list less?-function - compare function. Can be any function that accepts two arguments and returns T (or any non-nil value) if the first argument precedes the second in the sort order. The value of less?-function should be one of the following: symbol (function name) ’(LAMBDA (A1 A2) ...) form (FUNCTION (LAMBDA (A1 A2) ...)) form

Returns: A list containing the elements of list in the order specified by less?-function. Duplicate elements may be eliminated from the list. Examples: Sort a list of numbers: _$ (vl-sort ’(3 2 1 3) ’) (2 1 3 0)

The sorted list order is "f" "d" "c" "a"; "f" is the 3rd element (index 2) in the original list, "d" is the 2nd element (index 1) in the list, and so on. Sort a list of numbers in ascending order: _$ (vl-sort-i ’(3 2 1 3) ’list Converts a string into a list of character codes (VLISP Function)

(vl-string->list string) Returns: A list, each element of which is an integer representing the character code of the corresponding character in string Examples: _$ (vl-string->list "") nil _$ (vl-string->list "12") (49 50)

vl-string-elt Returns the ASCII representation of the character at a specified position in a string (VLISP Function)

(vl-string-elt string position) string - string to be inspected position - displacement in the string; first character is displacement 0 Note that an error occurs if position is outside of the range of the string Returns: An integer denoting the ascii representation of the character at the specified position

Appendix A AutoLISP Function Reference

465

Example: _$ (vl-string-elt "May the Force be with you" 8) 70

vl-string-left-trim Removes the specified characters from the beginning of a string (VLISP Function)

(vl-string-left-trim character-set string) character-set - a string listing the characters to be removed string - string to be stripped Returns: A string containing a substring of string with all leading characters in character-set removed Examples: _$ (vl-string-left-trim " \t\n" "\n\t STR ") "STR " _$ (vl-string-left-trim "12456789" "12463CPO is not R2D2") "3CPO is not R2D2" _$ (vl-string-left-trim " " " There are too many spaces here") "There are too many spaces here"

vl-string-mismatch Returns the length of the longest common prefix for two strings, starting at specified positions (VLISP Function)

(vl-string-mismatch str1 str2 [pos1 pos2 ignore-case-p]) str1 - first string str2 - second string pos1 - position to search from in the first string; 0 if omitted pos2 - position to search from in the second string; 0 if omitted ignore-case-p - if T is specified for this argument, case is ignored, otherwise case is considered

vl-string-left-trim

466

Returns: An integer Examples: _$ (vl-string-mismatch "VL-FUN" "VL-VAR") 3 _$ (vl-string-mismatch "vl-fun" "avl-var") 0 _$ (vl-string-mismatch "vl-fun" "avl-var" 0 1) 3 _$ (vl-string-mismatch "VL-FUN" "Vl-vAR") 1 _$ (vl-string-mismatch "VL-FUN" "Vl-vAR" 0 0 T) 3

vl-string-position Looks for a character with the specified ascii code in a string (VLISP Function)

(vl-string-position char-code str [start-pos1 from-end-p]) char-code - integer representation of the character to be searched for str - string to be searched pos - position to begin searching from in the string (first character is 0); 0 if omitted from-end-p - if T is specified for this argument, the search begins at the end of the string and continues backward to pos Returns: An integer representing the displacement in the string at which char-code was found; nil if the character is not found

Examples: _$ (vl-string-position (ascii "z") "azbzc") 1 _$ (vl-string-position 122 "azbzc") 1 _$ (vl-string-position (ascii "z") "azbzc" nil t) 3

Note in the previous example that vl-string-position returned the first occurrence of the letter "z," but indicated its displacement counting back from the end of the string

Appendix A AutoLISP Function Reference

467

_$ (vl-string-position (ascii "x") "azbzc") nil

vl-string-right-trim Removes the specified characters from the end of a string (VLISP Function)

(vl-string-right-trim character-set string) character-set - a string listing the characters to be removed string - string to be stripped Returns: A string containing a substring of string with all trailing characters in character-set removed Examples: _$ (vl-string-right-trim " \t\n" " STR \n\t ") " STR" _$ (vl-string-right-trim "1356789" "3CPO is not R2D267891") "3CPO is not R2D2" _$ (vl-string-right-trim " " "There are too many spaces at the end "There are too many spaces at the end"

")

vl-string-search Searches for the specified pattern in a string (VLISP Function)

(vl-string-search pattern string [start-pos]) pattern - string to be searched for within string - string to be searched for start-pos - starting position of search; 0, if omitted Returns: An integer representing the position in the string where the specified pattern was found, or nil if the pattern is not found; the first character of the string is position 0 Examples: _$ (vl-string-search "foo" "pfooyey on you") 1

vl-string-right-trim

468

_$ (vl-string-search "who" "pfooyey on you") nil _$ (vl-string-search "foo" "fooey-more-fooey" 1) 11

vl-string-subst Substitutes one string for another, within a string (VLISP Function)

(vl-string-subst new-str pattern string [start-pos]) new-str - string to be substituted for pattern pattern - string to be searched for within string string - string to be searched start-pos - starting position of search; 0, if omitted Note that the search is case sensitive. Returns: The value of string after any substitutions have been made Example: _$ (vl-string-subst "Obi-wan" "Ben" "Ben Kenobi") "Obi-wan Kenobi" _$ (vl-string-subst "Obi-wan" "Ben" "ben Kenobi") "ben Kenobi" _$ (vl-string-subst "Obi-wan" "Ben" "Ben \"Ben\" Kenobi" 3) "Ben \"Obi-wan\" Kenobi"

vl-string-translate Replaces characters in a string with a specified set of characters (VLISP Function)

(vl-string-translate source-set dest-set str) source-set - string of characters to be matched dest-set - string of characters to be substituted for those in source-set str - string to be searched and translated

Appendix A AutoLISP Function Reference

469

Returns: The value of str after any substitutions have been made Examples: _$ (vl-string-translate "abcABC" "123123" "A is a, B is b, C is C") "1 is 1, 2 is 2, 3 is 3" _$ (vl-string-translate "abc" "123" "A is a, B is b, C is C") "A is 1, B is 2, C is C"

vl-string-trim Removes the specified characters from the beginning and end of a string (VLISP Function)

(vl-string-trim char-set str) char-set - a string containing the list of characters to be removed from str str - string to be trimmed Returns: str, after any trimming has occurred Examples: _$ (vl-string-trim " \t\n" " \t\n STR \n\t ") "STR" _$ (vl-string-trim "this is junk" "this is junk Don’t call this junk! this is junk") "Don’t call this junk!" _$ (vl-string-trim " " " "Leave me alone"

Leave me alone

")

vl-symbol-name Returns a string containing the name of a symbol (VLISP Function)

(vl-symbol-name symbol) symbol - any LISP symbol Returns: A string containing the name of the supplied symbol argument Examples:

vl-string-trim

470

_$ (vl-symbol-name ’S::STARTUP) "S::STARTUP" _$ (progn (setq sym ’my-var) (vl-symbol-name sym)) "MY-VAR" _$ (vl-symbol-name 1) ; *** ERROR: bad argument type: symbolp 1

vl-symbol-value Returns the current value bound to a symbol (VLISP Function)

(vl-symbol-value symbol) symbol - any LISP symbol This function is equivalent to the AutoLISP EVAL function, but does not call the LISP evaluator. Examples: _$ (vl-symbol-value ’t) T _$ (vl-symbol-value ’PI) 3.14159 _$ (progn (setq sym ’PAUSE) (vl-symbol-value sym)) "\\"

vl-symbolp Identifies whether or not a specified object is a symbol (VLISP Function)

(vl-symbolp object) object - any LISP object Returns: T if object is a symbol nil if object is not a symbol

Examples: _$ (vl-symbolp t) T _$ (vl-symbolp nil)

Appendix A AutoLISP Function Reference

471

nil _$ (vl-symbolp 1) nil _$ (vl-symbolp (list 1)) nil

vlax-3D-point Creates ActiveX-compatible 3D point structure (VLISP Function)

(vlax-3D-point list) (vlax-3D-point x y [z]) list - a list of 2 or 3 numbers, representing points x, y - numbers representing X and Y coordinates of a point z - number (optional) representing Z coordinate of a point Returns: The structure created Examples: $ (vlax-3D-point 5 20) (5.0 20.0 0.0) _$ (vlax-3D-point ’(33.6 44.0 90.0)) (33.6 44.0 90.0)

vlax-add-cmd Adds commands to a group (VLISP Function)

(vlax-add-cmd global-name func-sym [local-name cmd-flags]) global-name - string func-sym - a symbol naming an AutoLISP function with zero arguments local-name - string (defaults to global-name) cmd-flags - integer (defaults to ACRX_CMD_MODAL | ACRX_CMD_REDRAW) Primary flags: ACRX_CMD_MODAL0x00 Command cannot be invoked while another command is active

vlax-3D-point

472

ACRX_CMD_TRANSPARENT0x01 Command can be invoked while another command is active Secondary flags: ACRX_CMD_USEPICKSET0x02 When the pickfirst set is retrieved it is cleared within AutoCAD. Command will be able to retrieve the pickfirst set. Command cannot retrieve nor set grips. ACRX_CMD_REDRAW0x04 When the pickfirst set or grip set is retrieved, neither will be cleared within AutoCAD. Command can retrieve the pickfirst set and the grip set. If both ACRX_CMD_USEPICKSET and ACRX_CMD_REDRAW are set, the effect is the same as if just ACRX_CMD_REDRAW is set. For more information on the flags, refer to ObjectARX documentation. Commands are added to VLC- group (this group is also used in the regapp function). No more than 50 commands can be added to a group. Example: The next function hello-autocad has no C: prefix, but we use vlax-add-cmd to make it visible as an ARX-style command at the Command: prompt >(defun hello-autocad () (hello "Visual LISP")) >(vlax-add-cmd "hello-autocad" ’hello-autocad)

vlax-curve-getArea Returns the area inside the curve (VLISP Function)

(vlax-curve-getArea curve-obj) curve-obj - VLA object to be measured Returns: Real number if successful, otherwise nil

Appendix A AutoLISP Function Reference

473

vlax-curve-getDistAtParam Returns the length of the curve’s segment from the curve’s beginning to the specified point (VLISP Function)

( vlax-curve-getDistAtParam curve-obj param) curve-obj - VLA object to be measured param - parameter specifying a point on the curve Returns: Real number if successful, otherwise nil

vlax-curve-getDistAtPoint Returns the length of the curve’s segment between the curve’s start point and the specified point (VLISP Function)

( vlax-curve-getDistAtPoint curve-obj point) curve-obj - VLA object to be measured point - 3-d point list (in WCS coordinates) on the curve Returns: Real number if successful, otherwise nil

vlax-curve-getEndParam Returns the parameter of the endpoint of the curve (VLISP Function)

(vlax-curve-getEndParam curve-obj) curve-obj - VLA object to be measured Returns: Real number if successful, otherwise nil

vlax-curve-getDistAtParam

474

vlax-curve-getEndPoint Returns the end point (in WCS coordinates) of the curve (VLISP Function)

(vlax-curve-getEndPoint curve-obj) curve-obj - VLA object to be measured Returns: 3-d point list if successful, otherwise nil

vlax-curve-getParamAtDist Distance along the curve from the beginning of the curve to the location of the specified parameter (VLISP Function)

(vlax-curve-getParamAtDist curve-obj param) curve-obj - VLA object to be measured param - parameter specifying a point on the curve Returns: Real number if successful, otherwise nil

vlax-curve-getParamAtPoint Returns the parameter of the curve at the point (VLISP Function)

(vlax-curve-getParamAtPoint curve-obj point) curve-obj - VLA object to be measured point - 3-d point list (in WCS coordinates) on the curve Returns: Real number if successful, otherwise nil

Appendix A AutoLISP Function Reference

475

vlax-curve-getPointAtDist Returns the point (in WCS coordinates) along a curve at the distance specified by the user (VLISP Function)

(vlax-curve-getPointAtDist curve-obj dist) curve-obj - VLA object to be measured dist - distance along the curve from the beginning of the curve to the location of the specified point Returns: 3-d point list if successful, nil otherwise

vlax-curve-getPointAtParam Determines the point on the curve that corresponds to the param parameter and returns the point (VLISP Function)

(vlax-curve-getPointAtParam curve-obj param) curve-obj - VLA object to be measured param - parameter on the curve at which the point is desired Returns: 3-d point list if successful, nil otherwise

vlax-curve-getStartParam Returns the start parameter on the curve (VLISP Function)

(vlax-curve-getStartParam curve-obj) curve-obj - VLA object to be measured Returns: Real number if successful, otherwise nil

vlax-curve-getPointAtDist

476

vlax-curve-getStartPoint Returns the start point (in WCS coordinates) of the curve (VLISP Function)

(vlax-curve-getStartPoint curve-obj) curve-obj - VLA object to be measured Returns: 3-d point list if successful, nil otherwise

vlax-curve-isClosed Determines if the specified curve is closed (i.e., start point is same as end point) (VLISP Function)

(vlax-curve-isClosed curve-obj) curve-obj - VLA object to be tested Returns: T if the curve is closed, nil otherwise

vlax-curve-isPeriodic Determines if the specified curve has an infinite range in both directions and there is a period value dT, such that there is a point on curve at (u + dT) = point on curve (u), for any parameter u. (VLISP Function)

(vlax-curve-isPeriodic curve-obj) curve-obj - VLA object to be tested Returns: T if the curve is periodic, nil otherwise

Appendix A AutoLISP Function Reference

477

vlax-curve-isPlanar Determines if there is a plane that contains the curve (VLISP Function)

(vlax-curve-isPlanar curve-obj) curve-obj - VLA object to be tested Returns: T if the there is a plane that contains the curve, nil otherwise

vlax-curve-getClosestPointTo Returns the point (in WCS coordinates) on a curve that is nearest to the specified point (VLISP Function)

(vlax-curve-getClosestPointTo curve-obj givenPnt [extend]) curve-obj - VLA object to be measured givenPnt - point (in WCS coordinates) for which to find the nearest point on the curve extend (optional) - boolean; if non-nil value is specified, vlax-curve-getClosestPointTo extends the curve when searching for the nearest point Returns: 3-d point list if successful, nil otherwise

vlax-curve-getClosestPointToProjection Returns the point (in WCS coordinates) on a curve that is nearest to the specified point (VLISP Function)

(vlax-curve-getClosestPointToProjection curve-obj givenPnt normal [extend]) curve-obj - VLA object to be measured givenPnt - point (in WCS coordinates) for which to find the nearest point on the curve normal - normal vector (in WCS coordinates) for the plane to project onto

vlax-curve-isPlanar

478

extend (optional) - boolean; if non-nil value is specified, vlax-curve-getClosestPointToProjection extends the curve when searching for the nearest point Returns: 3-d point list if successful, nil otherwise

vlax-curve-getFirstDeriv Returns the first derivative (in WCS coordinates) of a curve at the specified location (VLISP Function)

(vlax-curve-getFirstDeriv curve-obj param) curve-obj - VLA object to be measured param - parameter of the location on the curve at which to find the first derivative Returns: 3-d vector list if successful, nil otherwise

vlax-curve-getSecondDeriv Returns the second derivative (in WCS coordinates) of a curve at the specified location (VLISP Function)

(vlax-curve-getSecondDeriv curve-obj param) curve-obj - VLA object to be measured param - parameter of the location on the curve at which to find the second derivative Returns: 3-d vector list if successful, nil otherwise

Appendix A AutoLISP Function Reference

479

vlax-dump-object Lists an object’s methods and properties (VLISP Function)

(vlax-dump-object obj) obj - VLA object Returns: T, if successful, or an error message, if an invalid object name is supplied Example _$ (setq aa (vlax-get-acad-object)) # _$ (vlax-dump-object aa) ; IAcadApplication: AutoCAD Application Interface ; Property values: ; ActiveDocument (RO) = # ; Application (RO) = # ; Caption (RO) = "AutoCAD - [Drawing.dwg]" ; FullName (RO) = "C:\\Program Files\\AutoCAD R14\\acad.exe" ; Height = 638 ; Left = 264 ; LocaleId (RO) = 1033 ; Name (RO) = "AutoCAD" ; Path (RO) = "C:\\Program Files\\AutoCAD R14" ; Preferences (RO) = # ; Top = 312 ; Version (RO) = "14.01" ; Visible = -1 ; Width = 987 T

vlax-dump-object

480

vlax-ename->vla-object Transform entity to VLA object (VLISP Function)

(vlax-ename->vla-object entname) entname - entity name Returns: VLA object Example _$ (setq e (car (entsel)))

_$ (vlax-ename->vla-object e) #

vlax-erased-p Determines whether an object was erased (VLISP Function)

(vlax-erased-p obj) obj - VLA object Returns: T if the object was erased, nil otherwise

vlax-for Iterates through a collection of objects evaluating each expression (VLISP Function)

(vlax-for symbol collection [expression1 [expression2 ...]]) symbol - a symbol that will be assigned to each VLA object in a collection collection - VLA object representing a collection object expression1, expression2... expressions to be evaluated Returns: The value of the last expression evaluated for the last object in the collection

Appendix A AutoLISP Function Reference

481

vlax-get Low-level property get function. May be used for custom ActiveX object (VLISP Function)

(vlax-get obj property) obj - VLA object property - string indicating the name of the property to be retrieved Returns: The value of the property Example: (setq vlaobj (vlax-ename->vla-object e)) # $ (vlax-get vlaobj "Color") 256

vlax-get-acad-object Retrieves the top level AutoCAD application object for the current AutoCAD session (VLISP Function)

(vlax-get-acad-object) Example: _$ (setq aa (vlax-get-acad-object)) #

vlax-get

482

vlax-invoke Calls the specified method of an object (VLISP Function)

The vlax-invoke function can be used for a custom ActiveX object.

(vlax-invoke obj method list) obj - VLA object method - a string specifying the name of the method to be called list - list of arguments to be passed to the method called. No argument type checking is performed. All sub-lists are converted to Variant Arrays. Returns: The method (first argument) Examples: (vlax-invoke vla-object “update” nil)

This is equivalent to the standard VLA call: (vla-update vla-object)

vlax-ldata-delete Erases LISP data from a drawing dictionary (VLISP Function)

(vlax-ldata-delete dict key) dict - VLA object, AutoCAD drawing entity object, or string naming a global dictionary key - string specifying the dictionary key Returns: T, if successful nil, if unsuccessful (for example, the data did not exist)

Appendix A AutoLISP Function Reference

483

Examples: _$ (vlax-ldata-put "dict" "key" ’(1)) (1) _$ (vlax-ldata-delete "dict" "key") T _$ (vlax-ldata-delete "dict" "key") nil

vlax-ldata-get Retrieves LISP data from a drawing dictionary (VLISP Function)

(vlax-ldata-get dict key [default-data]) dict - VLA object or AutoCAD drawing entity object, or a string naming a global dictionary key - string specifying the dictionary key default-data (optional) - LISP data to be returned if no matching key exists in the dictionary Returns: Value of key item Example: _$ (vlax-ldata-get "dict" "key") (1)

vlax-ldata-list Lists LISP data in a drawing dictionary (VLISP Function)

(vlax-ldata-list dict) dict - VLA object or AutoCAD drawing entity object, or a string naming a global dictionary Returns:

An associative list consisting of pairs (key . value)

vlax-ldata-get

484

vlax-ldata-put Stores LISP data in a drawing dictionary (VLISP Function)

(vlax-ldata-put dict key data) dict - VLA object or AutoCAD drawing entity object, or a string naming a global dictionary key - string specifying the dictionary key data - LISP data to be stored in the dictionary Returns: The value of data Example: _$ (vlax-ldata-put "dict" "key" ’(1)) (1)

vlax-ldata-test Determines if data can be saved over a session boundary (VLISP Function)

(vlax-ldata-test data) data - any LISP data to be tested Returns: T, if the data can be saved and restored over the session boundary nil, if data cannot be saved and restored

Appendix A AutoLISP Function Reference

485

vlax-map-collection Applies a function to all objects in a collection (VLISP Function)

(vlax-map-collection obj function) obj - VLA object representing a collection function - symbol or lambda expression to be applied Returns: obj (the first argument) Example: (vlax-map-collection (vla-get-ModelSpace acadDocument) ’vlax-dump-object) ; IAcadLWPolyline: AutoCAD Lightweight Polyline Interface ; Property values: ; Application (RO) = # ; Area (RO) = 3.67152 ; Closed = -1 ; Color = 256 ; Coordinates = (9.59247 4.44872 9.25814 5.34715 4.19911 5.67949 ... ) ; EntityName (RO) = "AcDbPolyline" ; EntityType (RO) = 24 ; Handle (RO) = "4C" ; Layer = "0" ; Linetype = "BYLAYER" ; LinetypeScale = 1.0 ; Normal = (0.0 0.0 1.0) ; ObjectID (RO) = 42009888 ; Thickness = 0.0 ; Visible = -1 ; IAcadCircle: AutoCAD Circle Interface ; Property values: ; Application (RO) = # ; Area (RO) = 0.661383 ; Center = (8.53948 4.91026 0.0) ; Color = 256 ; EntityName (RO) = "AcDbCircle" ; EntityType (RO) = 8 ; Handle (RO) = "4D" ; Layer = "0" ; Linetype = "BYLAYER" ; LinetypeScale = 1.0 ; Normal = (0.0 0.0 1.0) ; ObjectID (RO) = 42009896 ; Radius = 0.45883 ; Thickness = 0.0 ; Visible = -1

vlax-map-collection

486

vlax-method-applicable-p Determines if an object supports a particular method (VLISP Function)

(vlax-method-applicable-p obj method) obj - VLA object method - a string containing the name of the method to check Returns: T, if the object supports the method nil, if the object does not support the method

Examples (applied to a LightweightPolyline object): _$ (vlax-method-applicable-p WhatsMyLine "copy") T _$ (vlax-method-applicable-p WhatsMyLine "AddBox") nil

vlax-object-released-p Determines if an object has been released (VLISP Function)

(vlax-object-released-p obj) obj - VLA object. Returns: T, if object is released (no AutoCAD drawing object is attached to obj) nil, if the object has not been released

vlax-product-key Returns AutoCAD’s registry path (VLISP Function)

This path can be used to register an application for demand loading. Returns: A string containing the registry path

Appendix A AutoLISP Function Reference

487

Example: (vlax-product-key) "Software\\Autodesk\\AutoCAD\\R14.0\\ACAD-2450999:99924631"

vlax-property-available-p Determines if an object has a specified property (VLISP Function)

(vlax-property-available-p obj prop [T]) obj - VLA object. property - a string naming the property to be checked T - if specified, tells vlax-property-available-p to also check that the property can be modified Returns: T, if the object has the specified property nil, if the object does not have the specified property. If the optional "T" argument is specified on the function call, nil will be returned either if the property is not avail-

able or if the property cannot be modified. Examples (applied to a LightweightPolyline object): _$ (vlax-property-available-p WhatsMyLine "Color") T _$ (vlax-property-available-p WhatsMyLine "center") nil

For a circle object: _$ (vlax-property-available-p myCircle "area") T

Note how supplying the optional third argument changes the result: _$ (vlax-property-available-p myCircle "area" T) nil

The funtion returns nil because, although the circle has an "area" property, that property cannot be modified.

vlax-property-available-p

488

vlax-put Low-level property set function (VLISP Function)

Can be used for custom ActiveX objects

(vlax-put obj property arg) obj - VLA object property - a string specifying the name of the property to be set arg - value to be set Returns: nil, if successful

Example: $ (vlax-put vlaobj "Color" 1) nil

which is equivalent to the standard VLA call: (vla-put-color vlaobj acRed)

vlax-read-enabled-p Determines if an object can be read (VLISP Function)

(vlax-read-enabled-p obj) obj - VLA object Returns: T, if the object is readable nil, if the object is not readable

Appendix A AutoLISP Function Reference

489

vlax-reg-app Registers an application (VLISP Function)

(vlax-reg-app app-reg-path cmds-alist loadctrls [appname [no-err-p]]) app-reg-path a string in the form of "SOFTWARE\\\\\\". cmds-alist - a list of command descriptions, each of which must be one of: ( . ) or . Every - string or symbol. loadctrls - INT, see ARX docs appname (optional) - a string that will be appended to AutoCAD’s Application subpath; default value is the base name of the application no-err-p (optional) - boolean flag that prevents fail on registry operations if not nil and returns nil; default value is nil Returns: a string containing the registry key path that was registered

vlax-release-object Releases a drawing object (VLISP Function)

(vlax-release-object obj) obj - VLA object After release, the drawing object is no longer accessible through obj. Returns: Indeterminate

vlax-reg-app

490

vlax-remove-cmd Removes a single command or a command group (VLISP Function)

Removes a single command or the whole command group for the current AutoCAD session.

(vlax-remove-cmd global-name) global-name - either a string or T. If global-name is T, the whole command group VLC-AppName (for example, VLC-VLIDE) is deleted.

vlax-tmatrix Returns a suitable representation for a 4x4 transformation matrix to be used in VLA methods (VLISP Function)

(vlax-tmatrix list) Returns a suitable representation (acceptable to ActiveX methods) for a 4x4 transformation matrix (namely: vla-TransformBy). list - a list of four lists, each containing four numbers, representing transformation matrix elements

vlax-typeinfo-available-p Deterines whether TypeLib information is present for the specified type of object (VLISP Function)

Visual LISP requires TypeLib information to determine whether a method or property is available for an object. Some objects may not have TypeLib information (for example, AcadDocument).

(vlax-typeinfo-available-p obj) obj - VLA object Returns: T, if TypeLib information is available nil, if TypeLib information is not available

Appendix A AutoLISP Function Reference

491

vlax-vla-object->ename Transforms a VLA object to an AutoLISP entity (VLISP Function)

(vlax-vla-object->ename obj) obj - VLA object Returns: An AutoLISP entity name Example: _$ (vlax-vla-object->ename vlaobj)

vlax-write-enabled-p Determines if an AutoCAD drawing object can be modified (VLISP Function)

(vlax-write-enabled-p obj) obj - VLA object or AutoLISP entity object Returns: T, if an AutoCAD drawing object can be modified nil, if the object cannot be modified

vlisp-export-symbol Assigns a native AutoLISP variable to the value it has in Visual LISP (VLISP Function)

(vlisp-export-symbol ’symbol-name) symbol-name - Visual LISP symbol or list of symbols Returns: The value of the exported symbol, or the last exported symbol, if a list was supplied

vlax-vla-object->ename

492

Examples: _$ (setq dd 1) 1 _$ (VLISP-EXPORT-SYMBOL ’dd) 1 _$ (setq zz "str") "str" $ (VLISP-EXPORT-SYMBOL ’(dd zz)) "str"

vlisp-import-exsubrs Registers the entry point of an ADS or ARX application within the Visual LISP environment (VLISP Function)

(vlisp-import-exsubrs ’("app-name" "entry-name" ["entry-name"...])) app-name - base name of the application load module entry-name - names of application functions to be defined in Visual LISP Returns: Indeterminate Examples: _$ (VLISP-IMPORT-EXSUBRS ’("acadapp.exe" "appload")) ("ACADAPP" "appload" "C:PSDRAG" "MTPROP" "MTEDIT" "C:PSFILL" "BHATCH" "BPOLY" "C:PSIN" "ACAD_COLORDLG" "STARTAPP" "ISMNUGRPLOADED" "INITDIA")

vlisp-import-symbol Assigns a Visual LISP symbol to the same value it has in native AutoLISP (VLISP Function)

(vlisp-import-symbol ’symbol-name) symbol-name - AutoLISP symbol or list of symbols Returns: The value of the imported symbol, or the last imported symbol in a list of symbols Examples: _$ (vlisp-import-symbol ’dd) 1

Appendix A AutoLISP Function Reference

493

_$ (vlisp-import-symbol ’xx) nil _$ (vlisp-import-symbol ’(xx dd)) 1

vlr-acdb-reactor Constructs a database (global) reactor object (VLISP Function)

The vlr-acdb-reactor function constructs a database (global) reactor object. The reactor object is added to the drawing database, but does not become persistent.

(vlr-acdb-reactor data callbacks) data - any AutoLISP data to be associated with a reactor object callbacks - a list of pairs ( . ) where event-name is one of the symbols listed in a Table AcDb I below, and callback_function is a symbol representing a function to be called when the event fires. Each callback function accepts two arguments: reactor_object - the VLR object that called the callback function obj - the database object (passed as an AutoLISP entity) associated with the event Table AcDb I Name

Event

:vlr-objectAppended

An object has been appended to the drawing database.

:vlr-objectUnAppended

An object has been detached from the drawing database, e.g. by using UNDO.

:vlr-objectReAppended

A detached object has been restored in the drawing database, e.g. by using REDO.

:vlr-objectOpenedForModify

An object is about to be changed.

:vlr-objectModified

An object has been changed.

:vlr-objectErased

An object has been flagged as being erased.

:vlr-objectUnErased

An object’s erased-flag has been removed.

vlr-acdb-reactor

494

vlr-add Enables a disabled reactor object (VLISP Function)

(vlr-add obj) obj -a VLR object, the reactor to be enabled Returns: obj (the argument)

vlr-added-p Tests to determine if a reactor object is enabled (VLISP Function)

(vlr-added-p obj) obj - a VLR object, the reactor to be tested Returns: T, if the specified reactor is enabled nil, if the reactor is disabled

vlr-beep-reaction Produces a beep sound (VLISP Function)

(vlr-beep-reaction [args]) This is a predefined callback function that accepts a variable number of arguments, depending on the reactor type. Can be assigned to an event handler for debugging. This function works in the Visual LISP IDE only.

Appendix A AutoLISP Function Reference

495

vlr-current-reaction-name Returns the name (symbol) of the current event, if called from within a reactor’s callback (VLISP Function)

(vlr-current-reaction-name) Returns: A symbol indicating the event that triggered the reactor

vlr-data Returns application-specific data associated with a reactor (VLISP Function)

(vlr-data obj) obj - a VLR object, the reactor object from which to extract data

vlr-data-set Overwrites application-specific data associated with a reactor (VLISP Function)

(vlr-data-set obj data) obj - a VLR object, the reactor object for setting the data data - any AutoLISP data The vlr-data-set function should be used with care to avoid creation of circular structures. Returns: data

vlr-current-reaction-name

496

vlr-editor-reactor Constructs an Editor (global) reactor object (VLISP Function)

The reactor object is added to the drawing database, but does not become persistent.

(vlr-editor-reactor data callbacks) data - any AutoLISP data to be associated with the reactor object callbacks - a list of pairs ( . ) where event-name is one of the symbols listed in “Table Editor Events”, and callback_function is a symbol representing a function to be called when the event fires. Each callback function accepts two arguments: reactor_object - the VLR object that called the callback function list - a list of extra data elements associated with the particular event. The contents of this list for particular events is shown in “Table Editor Callback Data”. Returns: The reactor_object argument Table Editor Events Table Editor Events Name

Event

:vlr-unknownCommand

The user has called a command unknown to AutoCAD.

:vlr-commandWillStart

The user has called a command known to AutoCAD.

:vlr-commandEnded

A command has completed.

:vlr-commandCancelled

A command has been cancelled by the user or another application.

:vlr-commandFailed

A command failed to complete.

:vlr-lispWillStart

An AutoLISP expression is to be evaluated inside the drawing editor.

:vlr-lispEnded

The evaluation of an AutoLISP expression has completed.

Appendix A AutoLISP Function Reference

497

Table Editor Events Name

Event

:vlr-lispCancelled

The evaluation of an AutoLISP expression has been cancelled. Next the :vlr-lispEnded event will be fired.

:vlr-beginClose

The drawing database is to be closed.

:vlr-beginDxfIn

The contents of a DXF file is to be appended to the drawing database.

:vlr-abortDxfIn

The drawing database has been changed, but the DXF import was not successful.

:vlr-dxfInComplete

The DXF import was successful.

:vlr-beginDxfOut

AutoCAD is about to export the drawing database into a DXF file.

:vlr-abortDxfOut

The DXF export operation failed.

:vlr-dxfOutComplete

The DXF export operation was successful.

:vlr-beginDwgOpen

AutoCAD is about to open a drawing.

:vlr-endDwgOpen

AutoCAD ended the open operation.

:vlr-dwgFileOpened

A new drawing has been loaded into the AutoCAD drawing editor.

:vlr-databaseToBeDestroyed

The contents of the drawing database is about to be deleted from memory.

:vlr-beginSave

AutoCAD is about to save the drawing file.

:vlr-SaveComplete

AutoCAD has saved the current drawing to disk.

:vlr-sysVarWillChange

AutoCAD is about to change a system variable.

:vlr-sysVarChanged

AutoCAD finished changing the system variable.

vlr-editor-reactor

498

Table Editor Callback Data Table Editor Callback Data Name

List length

:vlr-lispEnded, :vlr-lispCancelled, :vlr-beginClose, :vlr-beginDxfIn, :vlr-abortDxfIn, :vlr-dxfInComplete, :vlr-beginDxfOut, :vlr-abortDxfOut, :vlr-dxfOutComplete, :vlr-databaseToBeDestroyed

0

:vlr-unknownCommand :vlr-commandWillStart :vlr-commandEnded :vlr-commandCancelled :vlr-commandFailed

1

command name (string)

:vlr-lispWillStart

1

first line of AutoLISP expression to evaluate (string)

:vlr-beginDwgOpen, :vlr-endDwgOpen, :vlr-dwgFileOpened

1

filename to open (string)

:vlr-beginSave

1

default filename for save (string), may be changed by the user

:vlr-saveComplete

1

actual filename used for save (string)

:vlr-sysVarWillChange

1

system variable name (string)

:vlr-sysVarChanged

2

first parameter is the system variable name (string), second parameter is a change-successful flag (integer: 1 = success, 0 = failed)

Appendix A AutoLISP Function Reference

499

Parameters

vlr-linker-reactor Constructs a Linker (global) reactor object (VLISP Function)

The reactor object is added to the drawing database, but does not become persistent.

(vlr-linker-reactor data callbacks) data - any AutoLISP data to be associated with the reactor object callbacks - a list of pairs ( . ) where event-name is one of the symbols listed in “Table Linker Events” on page 500, and callback_function is a symbol representing a function to be called when the event fires. Each callback function accepts two arguments: reactor_object - the VLR object that called the callback function list - a list containing the name string of the ARX program loaded/unloaded. Returns: The reactor_object argument Table Linker Events Table Linker Events Name

Event

:vlr-rxAppLoaded

The dynamic linker has loaded a new ARX program. The program has finished its initialization.

:vlr-rxAppUnLoaded

The dynamic linker has unloaded an ARX program. The program already has done its clean-up.

vlr-object-reactor Constructs an object reactor object (VLISP Function)

The reactor object is added to the drawing database, but does not become persistent.

(vlr-object-reactor owners data callbacks) owners - AutoLISP list of VLA objects for valid drawing objects to be watched

vlr-linker-reactor

500

data - any AutoLISP data to be associated with the reactor object callbacks - a list of pairs ( . ) where event-name is one of the symbols listed in “Table: Object Events” on page 502, and callback_function is a symbol representing a function to be called when the event fires. Each callback function accepts three arguments: owner - owner of the VLA object the event applies to reactor_object - the VLR object that called the callback function list - a list of extra data elements associated with the particular

event. The contents of this list for particular events is shown in “Table: Object Callback Data” on page 503. Returns: The reactor_object argument

Appendix A AutoLISP Function Reference

501

Table: Object Events Table: Object Events Name

Event

:vlr-cancelled

The modification of the object has been cancelled.

:vlr-copied

The object has been copied.

:vlr-erased

Erase-flag of the object has been set.

:vlr-unerased

Erase-flag of the object has been reset.

:vlr-goodbye

The object is about to be deleted from memory.

:vlr-openedForModify

The object is about to be modified.

:vlr-modified

The object has been modified. If the modification was cancelled, also :vlr-cancelled and :vlr-modifyUndone will be fired.

:vlr-subObjModified

A sub-entity of the object has been modified.

:vlr-modifyUndone

The object’s modification was undone.

:vlr-modifiedXData

The object’s extended entity data have been modified.

:vlr-unappended

The object has been detached from the drawing database.

:vlr-reappended

The object has been re-attached to the drawing database.

:vlr-objectClosed

The object’s modification has been finished.

vlr-object-reactor

502

Table: Object Callback Data Table: Object Callback Data Name

List length

Parameters

:vlr-cancelled :vlr-erased, :vlr-unerased :vlr-goodbye :vlr-openedForModify :vlr-modified :vlr-modifyUndone :vlr-modifiedXData :vlr-unappended :vlr-reappended :vlr-objectClosed

0

:vlr-copied

1

The object created by the copy operation (ename).

:vlr-subObjModified

1

The sub-object (ename) that has been modified

vlr-owner-add Adds an object to the list of owners of an object reactor (VLISP Function)

(vlr-owner-add reactor owner) reactor - a VLR object owner - a VLA object to be added to the list of notifiers for this reactor Adds a new source of reactor events; reactor will receive events from the specified object. Returns: Indeterminate

Appendix A AutoLISP Function Reference

503

vlr-owner-remove Removes an object from the list of owners of an object reactor (VLISP Function)

(vlr-owner-remove reactor owner) reactor - a VLR object owner - a VLA object to be removed from the list of notifiers for this reactor Returns: Indeterminate

vlr-owners Returns the list of owners of an object reactor (VLISP Function)

Returns a list of objects that notify the specified reactor.

(vlr-owners reactor) reactor - a VLR object

vlr-pers Makes a reactor persistent (VLISP Function)

(vlr-pers reactor) reactor - a VLR object Returns: Indeterminate

vlr-pers-p Determines whether or not a reactor is persistent (VLISP Function)

(vlr-pers-p reactor) reactor - a VLR object

vlr-owner-remove

504

Returns: T, if the specified reactor is persistent nil, if the reactor is transient

vlr-pers-release Makes a reactor transient (VLISP Function)

(vlr-pers-release reactor) reactor - a VLR object Returns: Indeterminate

vlr-reaction-names Returns a list of all callback conditions for this reactor type (VLISP Function)

(vlr-reaction-names reactor-type) reactor-type - one of the following symbols: :VLR-AcDb-reactor :VLR-Editor-reactor :VLR-Linker-reactor :VLR-Object-reactor Returns: A list of symbols indicating the possible events for the specified reactor type

vlr-reaction-set Adds or replaces a callback function in a reactor (VLISP Function)

(vlr-reaction-set reactor event function) reactor - a VLR object event - a symbol denoting one of the event types available for this reactor type

Appendix A AutoLISP Function Reference

505

function - a symbol representing the AutoLISP function to be added or replaced Returns Indeterminate

vlr-reactions Returns a list of pairs (event-name . callback_function) for the reactor (VLISP Function)

(vlr-reactions reactor) reactor - a VLR object

vlr-reactors Returns a list of all reactors of a given type (VLISP Function)

(vlr-reactors reactor-type) reactor-type - one of the following symbols: :VLR-AcDb-reactor :VLR-Editor-reactor :VLR-Linker-reactor :VLR-Object-reactor

vlr-remove Disables a reactor (VLISP Function)

(vlr-remove reactor) reactor - a VLR object Returns Indeterminate

vlr-reactions

506

vlr-remove-all Disables all reactors of the specified type (VLISP Function)

(vlr-remove-all reactor-type) reactor-type - one of the following symbols: :VLR-AcDb-reactor :VLR-Editor-reactor :VLR-Linker-reactor :VLR-Object-reactor Returns Indeterminate

vlr-trace-reaction A pre-defined callback function that prints one or more callback arguments in the Trace window (VLISP Function)

(vlr-trace-reaction any number of arguments) This function can be used as a debugging tool to verify that your reactor has fired.

vlr-type Returns a symbol representing the reactor type (VLISP Function)

(vlr-type reactor) reactor - a VLR object

vlr-types Returns a list of all reactor types (VLISP Function)

(vlr-types) Returns:

Appendix A AutoLISP Function Reference

507

(:VLR-Linker-Reactor :VLR-Editor-Reactor :VLR-AcDb-Reactor :VLR-ObjectReactor)

vports Returns a list of viewport descriptors for the current viewport configuration

(vports) Each viewport descriptor is a list consisting of the viewport identification number and the coordinates of the viewport’s lower-left and upper-right corners. If the AutoCAD system variable TILEMODE is set to 1 (on), the returned list describes the viewport configuration created with the AutoCAD VPORTS command. The corners of the viewports are expressed in values between 0.0 and 1.0, with (0.0, 0.0) representing the lower-left corner of the display screen’s graphics area, and (1.0, 1.0) the upper-right corner. If TILEMODE is 0 (off), the returned list describes the viewport objects created with the MVIEW command. The viewport object corners are expressed in paper space coordinates. Viewport number 1 is always paper space when TILEMODE is off. For example, given a single-viewport configuration with TILEMODE on, the vports function might return this: ((1 (0.0 0.0) (1.0 1.0)))

Similarly, given four equal-sized viewports located in the four corners of the screen when TILEMODE is on, the vports function might return this: (

(5 (0.5 0.0) (1.0 0.5)) (2 (0.5 0.5) (1.0 1.0)) (3 (0.0 0.5) (0.5 1.0)) (4 (0.0 0.0) (0.5 0.5)) )

The current viewport’s descriptor is always first in the list. In the previous example, viewport number 5 is the current viewport.

wcmatch Performs a wild-card pattern match on a string

(wcmatch string pattern) The wcmatch function compares the string to the pattern to see if they match. If so, T is returned; otherwise, nil is returned. Both string and pattern can be either a

vports

508

quoted string or a variable. The pattern can contain the wild-card pattern-matching characters shown in the following table. Only the first 500 characters (approximately) of the string and pattern are compared; anything beyond that is ignored. Wild-card characters Character

Definition

#

(pound)

Matches any single numeric digit

@

(at)

Matches any single alphabetic character

.

(period)

Matches any single nonalphanumeric character

*

(asterisk)

Matches any character sequence, including an empty one, and it can be used anywhere in the search pattern: at the beginning, middle, or end

?

(question mark)

Matches any single character

~

(tilde)

If it is the first character in the pattern, it matches anything except the pattern

[...]

Matches any one of the characters enclosed

[~...]

Matches any single character not enclosed



(hyphen)

Used inside brackets to specify a range for a single character

,

(comma)

Separates two patterns

`

(reverse quote)

Escapes special characters (reads next character literally)

(wcmatch "Name" "N*")

returns T

This tests the string Name to see if it begins with the character N. You can use commas in a pattern to enter more than one pattern condition. This example performs three comparisons: (wcmatch "Name" "???,~*m*,N*") returns T

If any of the three pattern conditions is met, wcmatch returns T. In this case the tests are these: Name has three characters (false); Name does not contain an m (false); and Name begins with N (true). At least one condition was met, so this expression returns T. The comparison is case-sensitive, so upper- and lowercase characters must match. It is valid to use variables and values returned from AutoLISP functions for string and pattern values.

Appendix A AutoLISP Function Reference

509

To test for a wild-card character in a string, you can use the single reverse-quote character (‘) to escape the character. Escape means that the character following the single reverse quote is not read as a wild-card character; it is compared at its face value. For example, to search for a comma anywhere in the string Name, enter this: (wcmatch "Name" "*‘,*")

returns nil

Because other wild-card characters might be added in future releases of AutoLISP, it is a good idea to escape all nonalphanumeric characters in the pattern to ensure upward compatibility.

wcmatch

510

Both the C and AutoLISP programming languages use the backslash (\) as an escape character, so you need two backslashes (\\) to produce one backslash in a string. To test for a backslash character anywhere in Name, you enter this: (wcmatch "Name" "*‘\\*")

returns nil

All characters enclosed in brackets ([ . . . ]) are read literally, so there is no need to escape them, with the following exceptions: the tilde character (~) is read literally only when it is not the first bracketed character (as in "[A~BC]"); otherwise it is read as the negation character, meaning that wcmatch should match all characters except those following the tilde (as in "[~ABC]"). The dash character (–) is read literally only when it is the first or last bracketed character (as in "[–ABC]" or "[ABC–]") or when it follows a leading tilde (as in "[~-ABC]"). Otherwise, the dash character (–) is used within brackets to specify a range of values for a specific character. The range works only for single characters, so "STR[1–38]" matches STR1, STR2, STR3, and STR8, and "[A–Z]" matches any single uppercase letter. The closing bracket character ("]") is also read literally if it is the first bracketed character or if it follows a leading tilde (as in "[ ]ABC]" or "[~]ABC]").

while Evaluates a test expression, and if it is not nil, evaluates other expressions; repeats this process until the test expression evaluates to nil

(while testexpr expr...) The while function continues until testexpr is nil. It then returns the most recent value of the last expr. The following code calls user function SOME-FUNC ten times, with test set to 1 through 10. It then returns 11, which is the value of the last expression evaluated. (setq test 1) (while (