AutoCAD Services & Support

Visual LISP: Entity Data Lists

Watching a drawing magically appear before your eyes can be quite pleasing. Especially if you wrote the program that makes the magic happen. This time we are going to look at the Visual LISP® entity data list, the primary tool used in making magic of that kind. Once you understand the entity data list and see how easy it is to exploit, you are well on your way to creating applications that magically create drawings given just the simplest of input.

Entity Data Lists, What Are They?

The graphics in an AutoCAD® drawing are exposed through what is known as an entity data list. Entity data lists contain all the parameters used to define the entity objects graphically on the screen.

Consider a basic entity object such as a circle. The geometric parameters of a circle are the center point and the radius. You can use Visual LISP to extract the values (in list form) for these parameters from a drawing, along with other essential drawing-related information. From the entity data list of a circle object you can calculate points on the circle, the area, or other properties involving the base parameters. You can use Visual LISP to obtain an entity data list for every entity object in a drawing. Entity data lists can be used for input to your application. Instead of the operator selecting two points to show the center and radius of a circle, they can select the circle entity object. This is the type of input AutoCAD operators expect from well written applications.

The entity data list contains the geometric parameters used to define the object along with any other drawing parameters essential to the definition of that object (layer name, for example). Obviously, this sort of data structure has the potential to become quite confusing. If you don’t know what the entity data list contains, how do you extract the information it contains for your application?

Using DXF and Association Lists

Fortunately, the early AutoCAD programmers were aware of this potential for confusion. In AutoCAD release 2 (before AutoLISP®!), they devised a clever format, DXF™ group codes, with which present-day programmers can figure out what’s in an entity data list. You can find the DXF group codes in DXF (drawing interchange format) files; the codes define the type of entity data that follows. DXF group codes are integers; you must learn what codes go with specific data. That information is well documented in the AutoCAD Help system. (Look for developer information and for sections about DXF.)

Since DXF was initially created to provide a mechanism by which other programs could read AutoCAD drawing data, it was only logical to exploit this feature when Autodesk developed the AutoLISP programming language. The system is somewhat intimidating at first, but with a little practice you will become quite familiar with the codes used to define drawing entity objects. And with the powerful Visual LISP language, the programming is quite elegant.

The DXF system is implemented using a nested list structure known as an association list, which is a list containing nothing but lists. (You’ll use the Visual LISP ASSOC and CDR subrs to get at data in DXF files. More on this later.) Lists inside the association list must all start with the same type of data. For a numerically coded system like DXF, this is a perfect match. The first member of each list inside the association list is a group code. The rest of the list is the entity data associated with that particular number.

You just have to get your hands on the entity data list. That’s covered next as is changing the list and updating the data back to the drawing. Then you learn how to create a new entity using an entity data list.

Getting an Entity List?

The easiest place to get an entity data list is from an existing entity object. Open up AutoCAD and draw a line or an arc. Press the F2 key, which makes the AutoCAD text screen visible. Then type the Visual LISP expression (entget (entlast)) at the AutoCAD command prompt.

When you press the Enter key, information about that entity object displays. This information is an entity data list. For example, the following shows an AutoCAD session where a line is created from (1,1) to (10,10) and then displays the associated entity data list. Operator input is in bold.

Command: line Specify first point: 1,1
Specify next point or [Undo]: 10,10

Specify next point or [Undo]:

Command: (entget (entlast))
((-1 . <Entity name: 40069408>) (0 . "LINE") (330 . <Entity name: 40077cf8>) (5 . "F1") (100 . "AcDbEntity") (67 . 0) (410 . "Model") (8 . "0") (100 . "AcDbLine") (10 1.0 1.0 0.0) (11 10.0 10.0 0.0) (210 0.0 0.0 1.0))

At first glance, the entity data list seems to contain a lot of confusing stuff. But you’ll quickly learn to seek out the primary group codes (the first digit in the sublists is called a group code) in the list and use them in your programming. Here are the most common group codes:

  • 0, which is followed by the type of entity about which this list has information.
  • 10, which is followed by the primary point, followed by 11, 12, and so on for other points that the entity may contain.
  • 8, which is followed by the layer name.

Of course, different entity objects have additional codes, for angle and scalar values, for example. As previously mentioned, you can find a complete list of group codes in the AutoCAD Help system (search the Index for developer information and DXF).

Entity data lists are returned as a result of the ENTGET subr in Visual LISP. ENTGET has only one parameter, the entity object name. If the entity object has been deleted, ENTGET returns NIL; otherwise, it returns the entity data list for the object referenced. You can obtain entity names from selection sets using ENTSEL, or from the drawing database using ENTNEXT and ENTLAST. You can explore those subrs on your own if they are new to you. Now we’re going to look at how to find only the entity data you need and at how to manage entity object data.

Finding the Data You Want

An entity data list looks pretty chaotic and unwieldy. But if you use two Visual LISP subrs, ASSOC and CDR, you can greatly simplify the process of finding the exact data you need and managing it effectively. To use these routines, you must know the group code for the parameter you’re after. ASSOC searches a DXF association list based on the group code. If ASSOC finds a match, it returns the sublist inside the association list. If ASSOC fails to find a match, it returns NIL. Any sublist that ASSOC returns contains the group code followed by the entity object data. To get just the data for the parameter you’re interested in, you must use both the ASSOC and the CDR subr. CDR returns the tail of a list. It “decapitates” a list by taking the first member off and returning the remainder.

Let’s look at some examples to clarify the use of ASSOC and its companion CDR. The following code sets the result of the ENTGET into the variable EL (for entity data list) and then accesses EL using different group codes.

Command: (setq EL (entget (entlast)))
((-1 . <Entity name:40069408>) (0 . "LINE") (330 . <Entity name: 40077cf8>) (5 . "F1") (100 . "AcDbEntity") (67 . 0) (410 . "Model") (8 . "0") (100 . "AcDbLine") (10 1.0 1.0 0.0) (11 10.0 10.0 0.0) (210 0.0 0.0 1.0))

Command: (cdr (assoc 0 EL))
"LINE"

Command: (cdr (assoc 10 EL))
(1.0 1.0 0.0)

Command: (cdr (assoc 11 EL))
(10.0 10.0 0.0)

The 0 group code returns the string "LINE." Group codes 10 and 11 return the From and To points of the LINE object, respectively. The points are returned as lists. But because a special type of list, called dotted pair, is used in the DXF association list, the entity type is returned as a string. You can see the dots in the EL shown again below. Note the bold text. A dotted pair exists for the entry for "LINE but not for the 10 and 11 group codes. When a dot is present, CDR returns a basic data type such as a string or a number. When the dot is not present, CDR returns a list.

((-1 . <Entity name: 40069408>) (0 . "LINE") (330 . <Entity name: 40077cf8>) (5 . "F1") (100 . "AcDbEntity") (67 . 0) (410 . "Model") (8 . "0") (100 . "AcDbLine") (10 1.0 1.0 0.0) (11 10.0 10.0 0.0) (210 0.0 0.0 1.0))

There are two ways to create dotted pairs. The easier is to use quotation marks as in '(8 . "0"). The single quotation mark in Visual LISP indicates that the expression or symbol that follows is not to be evaluated, but just used as presented. Since the dot by itself indicates a dotted-pair structure, the quoted list is stored as a dotted pair. The other way to create a dotted pair is to use the CONS subr as in (cons 8 "0"). Normally CONS adds elements to a list. But when used with two atoms or primitive data types such as numbers and strings, CONS produces a dotted pair.

The manipulation of entity data lists almost always involves the CDR and ASSOC subr pair. Armed with the AutoCAD online Help to guide you through the DXF code numbers, you can find all the parameters of any AutoCAD drawing object and extract them. You’ll use that extracted data as input to other processes you are creating or you may need to change it and return it to the entity data list.

Modifying and Creating New Entity Data Lists

You’ve already seen that you can use entity data list data as input in your applications. But you can also modify the data in any entity sublist and return it to the association list to programmatically change the graphics in a drawing. To do that, you use the SUBST subr. You can also use SUBST in conjunction with ASSOC to retrieve the item you want to replace and to create a new sublist with your modified data.

Using SUBST and ASSOC you can change specific group codes. For example, to change the layer name in an entity to "MYLAYER" in the entity data list EL, use the following expression:

(setq EL (subst '(8 . "MYLAYER") (assoc 8 EL) EL))

When the above expression completes, the value for group code 8 will have been changed in the entity data list.

To update the entity in the drawing, use ENTMOD with the revised entity data list. ENTMOD accepts a valid entity data list and changes the object in the database.

For most AutoCAD objects, the ENTMOD subr immediately redraws the object on the screen. However, for some objects you must pass the entity name of the object to the ENTUPD subr to generate the update. Objects requiring an update request are typically complex and involve multiple entity lists. Examples are block inserts with attributes and traditional polyline objects made up of a group of vertex objects.

Use the subrs ENTGET, ENTMOD, and ENTUPD to work with existing AutoCAD entity objects.

To create a new entity object, use ENTMAKE, which means that you must supply all the data for the object’s entity data list. The entity data list you create and use in conjunction with ENTMAKE is not as complete as an entity data list that you obtain using ENTGET. Obviously when you’re using ENTMAKE, you can’t data-reference the entity name because you are creating a new entity and thus a new entity name has not yet been assigned by AutoCAD. But you must supply all the other data for the new entity.

When I am programming an application and need to create a new entity data list for use with ENTMAKE, I have trick that saves a lot of typing. Suppose I want to make a LINE entity data list. I start by creating a LINE object in AutoCAD and then use (ENTGET (ENTLAST)) to retrieve the entity data list for the LINE. Next, I highlight the list in the AutoCAD text screen (press the F2 key to show the text screen if it is not visible) and copy the text to the clipboard. I then paste the text into an editor window of the Visual LISP environment, and voilà, I have a prototype for the entity data list I want to create. All I need to do is adjust the data to reflect the variables I want to use.

Here are the steps in detail:

1. Create the desired entity using AutoCAD commands.

2. Display the entity data list with (entget (entlast)).

3. Switch to the AutoCAD text screen by pressing Function key F2.

4. Use your mouse to highlight all of the text in the entity data list.

5. Right-click to display a shortcut menu, and select the Copy option. Or you can press Ctrl+C to copy the text to the clipboard.

6. Switch to the Visual LISP editor window

7. Place the cursor at the point where you want the entity data list to appear and either right-click and select Paste from the shortcut menu that displays or press Ctrl+V.

8. Edit the data list to fit the data. Remove the object reference group codes (-1, 5).

To effectively edit the data list you need to consider how you are going to use it. You can declare everything as a constant in the initial definition and use SUBST to change data in the list as needed. This works well when you are continually repeating the entity data list and changing only the values of key parameters. If you have many variables to plug in, define the entity data list using the LIST subr. You will have to quote each l group code or turn it into a valid expression.

You’ll find an example of this kind of programming as a scroll at the end of this article. This example inserts two blocks into the drawing, creating the blocks if needed. It shows the creation of entity data lists for the purpose of defining new entities and further manipulates entity data lists for repeated uses of the same basic information. The following section describes in detail what the program accomplishes.

Wall Frame

The example program draws a 3D wall frame in an AutoCAD drawing. The program prompts the operator to select a LINE object in the drawing to serve as the boundary of the wall and to indicate on which side of the line studs are to be placed. The program then generates a 3D image of the frame. The basic input and output are shown in Figures 1 and 2. In Figure 1 the frame is drawn with lines (the scale is 1 drawing unit equals 1 inch). Figure 2 shows the result of running the program’s C:STUDS command for each of the lines.

Figure 1: Wall plan as lines.
Figure 2: Wall plan with studs.

The program, named STUDS, is defined in Visual LISP as a function with the name C:STUDS. Once the operator selects a LINE object, the program retrieves the entity data list holding the LINE object’s ending points. The From and To points provide the direction of the line. The program then shows the operator the default side of the line on which the studs will be drawn given the current direction. A Yes or No prompt displays at the same time. If the operator selects No, the program flips the line direction by reversing the From and To lines in the line’s entity data list, redisplays the line on which the studs are to be placed, and again prompts the operator to select Yes or No. When the operator selects Yes, the program then determines the length of the frame.

Note: You would not really update the LINE object in the database; I added this function just to demonstrate the ease of changing the data.

Next, the program determines the location of the first stud and creates a prototype entity data list for the block insert of the stud graphic. If the block does not exist, the function calls another function (also in the source-code listing) that creates the block definition.

After all the data is ready, the program starts a loop (called WHILE) down the line. A running distance (DD) is compared to the length of the wall line (LL). When DD is greater than LL, the loop stops. While DD is less than LL, the expressions inside the WHILE loop are evaluated. These expressions manipulate the block insert points in the prototype entity data list and then call ENTMAKE to create an insert of the entity. At that point, another loop, which works along the same principles as the WHILE loop, starts up. This loop draws the top and bottom of the frame (called beams in this example).

Use this example to learn how to manipulate entity data lists. Don’t use it for actual design work because, in most cases, you would not use a stud layout to create a frame. You could use it, however, to get a rough estimate of how many studs are required for a frame. See the function defined as C:HOWMANY included in the scroll to learn how easy it is to extract information of this nature from a “smart drawing.” And all AutoCAD drawings are smart.

Conclusion

Entity manipulation is powerful magic! I hope I have opened the door for you to see some potential uses for this magic in your own application environment. If entity data list manipulation all seems a bit much, that is because it is very deep and complex. AutoCAD software is a deep product with many things inside it waiting to be discovered by even experienced operators and programmers. The entity data list is a window into that depth. And the limits are only defined by your imagination. My only advice is to explore the graphical parameters first and then explore other parameters as you become comfortable swimming in these magical waters.

The Scroll

 

Download Scroll (txt - 7Kb)

Extra Tidbit: Handling Lightweight Polylines

Perhaps I should note that some entity objects confound the simple CDR and ASSOC approach. The first that comes to mind is the lightweight polyline. In the entity data list of a lightweight polyline, the group codes repeat. Using (CDR (ASSOC 10 EL)) with EL containing the entity data list of a lightweight polyline always returns the first sublist containing the group code 10. This means that you must incorporate a way to get to the subsequent points with the same group code 10.

You can solve this list manipulation problem in a couple of ways. The easier way is to reduce the list as you go. The less easy way is to write your own function that reduces the list until it repeats down to the point you want. Look at the entity data list produced by the following command sequence to see the repeating group code entries (codes 10, 40, 41, and 42).

Command: rectang
Specify first corner point or [Chamfer/Elevation/Fillet/Thickness/Width]: 2,3

Specify other corner point or [Dimensions]: 4,6

Command: (setq el (entget (entlast)))
((-1 . ) (0 . "LWPOLYLINE") (330 . ) (5 . "F3") (100 . "AcDbEntity") (67 . 0) (410 . "Model") (8 . "0") (100 . "AcDbPolyline") (90 . 4) (70 . 1) (43 . 0.0) (38 . 0.0) (39 . 0.0) (10 2.0 3.0) (40 . 0.0) (41 . 0.0) (42 . 0.0) (10 4.0 3.0) (40 . 0.0) (41 . 0.0) (42 . 0.0) (10 4.0 6.0) (40 . 0.0) (41 . 0.0) (42 . 0.0) (10 2.0 6.0) (40 . 0.0)(41 . 0.0) (42 . 0.0) (210 0.0 0.0 1.0))

Two tools for working with lightweight polylines are presented in Listing 1 below. Both demonstrate that you can use the powerful list manipulation tools in Visual LISP to write short programs that accomplish great things. The first function, GET_LWPOLYLINE_PTS, returns a list of just the points stored inside a polyline entity data list. The second function replaces the point at offset position (zero based) NN in the entity data list EL with a new point stored in nPT. The second function, a simple recursive function, calls itself with simplified versions of the problem. Recursion is is a very powerful tool in the Visual LISP magician’s toolbox.

 

Listing 1: Lightweight Polyline Utilities

;;
;;--- Return list of points in LWPOLYLINE
(defun Get_LWPOLYLINE_PTS (EL / PTS)
  (while (and EL (assoc 10 EL))
    (setq PTS (cons (assoc 10 EL)
      PTS)
   EL (cdr (member (car PTS) EL))))
  (mapcar 'cdr (reverse PTS))
  )
;;
;;--- Update point value in LWPOLYLINE
(defun Put_LWPOLYLINE_PT (EL nPT NN)
  (cond
    ((null EL) nil)
    ((zerop NN)
     (subst (cons 10 nPT) (assoc 10 EL) EL))
    ((/= (caar EL) 10)
     (cons (car EL)
    (Put_LWPOLYLINE_PT (cdr EL) nPT NN)))
    (t
     (cons (car EL)
    (Put_LWPOLYLINE_PT (cdr EL) nPT (1- NN)))
     )
    ))