Convert 3D Polylines to 2D

31 Aug, 2003 By: Tony Hotchkiss

AutoLISP Solutions: See how Visual LISP saves serious coding time.

George Anderson of Eugene, Oregon, e-mailed a request to turn 3D polylines into 2D polylines. Several routines he downloaded from the Internet claimed to perform this function, but all failed to set the z coordinate to zero. This month's solution is PLINE-3D-2D.LSP. I sent it to George, and he reports that it works for him. I wrote the code using the version of AutoLISP that comes with AutoCAD 2004, but it should work with 2002 also.

Download the AutoLISP file from Cadalyst's CAD Tips site and save it in the AutoCAD support directory. From the AutoCAD Tools menu, choose Load Applications, or enter Appload at the AutoCAD Command prompt. In the Load/Unload Applications dialog box, select the PLINE-3D-2D.LSP file from the support directory where you installed it, click the Load button, and then click Close. After you load the program, AutoCAD prompts you to type PL32 to start.

Figure 1. 3D polylines highlight as you select them.
After you enter PL32, AutoCAD prompts you to select 3D polylines, shown highlighted in figure 1. Press to complete your selection, at which time the routine converts the polylines to 2D (figure 2). Note that the 2D polylines retain their layer dependence.

I took an easy way out for programming the code-I used the object-oriented capabilities of AutoLISP to automate some activities that otherwise might have taken many more lines of code. For instance, the main function, (pline-3d-2d), begins by defining the global variables *thisdrawing* and *modelspace*, as recommended in the programming documentation that is a very useful feature of AutoCAD 2004. The code that creates these global variables is:

(setq *thisdrawing* (vla-get-activedocument
) ;_ end of vla-get-activedocument
*modelspace* (vla-get-ModelSpace *thisdrawing*)
) ;_ end of setq

Figure 2. You’re left with 2D polylines once pline-3d-2d.lsp goes to work.
This lets programmers refer to the model space when creating entities. In this case, I added new 2D polylines to the drawing in model space to take the place of the 3D polylines.

The (pline-3d-2d) function then calls the (get-3d-pline) function, which returns a list of all selected 3D polylines. The 3D polyline list is supplied as an argument to the (make-list) function that returns arrays of vertex points for each of the 3D polylines. A (repeat) loop finishes the job of adding the 2D polylines. The loop ensures that the 2D polylines are placed on the same layers as the original 3D polylines, as shown in the following code fragment:

(setq n (- 1))
(repeat (length vert-array-list)
(setq vert-array (nth (setq n (1+ n)) vert-array-list))
(setq lyr (vlax-get-property (nth n 3d-pl-list) 'Layer))
(setq obj (vla-AddPolyline *modelspace* vert-array))
(vlax-put-property obj 'Layer lyr)
) ;_ end of repeat

I used AutoLISP standard functions to get the Layer property of a 3D polyline and then used the Addpolyline method to create a new 2D polyline in model space using the array of 3D vertex coordinates that was previously extracted from the 3D polyline. The routine can

Get the Code
Download the code for this and all articles from Cadalyst's CAD Tips site. Or get the routines directly from author Tony Hotchkiss at CAD/CAM Technologies, 42 15th St., Buffalo, NY 14213, 716.883.8790, e-mail or visit his web site.
use the array of 3D coordinates in this case because the Addpolyline method ignores the z coordinate and creates an old-style 2D polyline, not a lightweight polyline. Stripping the z coordinate from the array required for lightweight polylines would have been more complicated. This is where I elected to take the easy way out and add the regular polylines. Incidentally, this method is retained in AutoCAD 2004 for backward compatibility only, and I don't know if it will appear in future versions. The last item in the code fragment above puts the new objects on the same layers as the old objects.

The routine calls the Visual LISP delete method to delete the 3D polyline objects:

(foreach obj 3d-pl-list (vla-delete obj))

The (make-list) function is a good example of the use of object-oriented programming in Visual LISP. The vertex coordinates of the 3D polylines are extracted with two lines of code instead of the more complicated techniques required by AutoLISP. Here, the standard (vlax-get-property) function is paired with the (vlax-variant-value) function to easily obtain the array of vertex points. These lines of code appear here in a (repeat) loop that does the job for each of the selected 3D polylines:

(repeat (length p-list)
(setq obj (nth (setq i (1+ i)) p-list)
coords (vlax-get-property obj "coordinates")
ca (vlax-variant-value coords)
) ;_ end-of setq
(setq calist (append calist (list ca)))
) ;_ end-of repeat

The coordinates returned as the variable COORDS in the above code take the form of a variant, which is a type of object used in many programming languages, including C11 and Visual LISP. A variant is used when the object property can assume any of a number of forms depending on the type of object under consideration. The value of the variant in this case is a one-dimensional array of double-precision floating point numbers, and that array is equivalent to (and actually is) a list in Visual LISP that the above code assigns to the variable CA. The list CA is divisible by three because it represents successive x,y,z coordinates of the vertex points of a 3D polyline.

The (get-3d-pline) function uses object-oriented techniques to add a selection set to the drawing and then to add objects to the new selection set using the Selectonscreen method. The following code fragment shows Visual LISP functions for adding the selection set:

(setq selsets (vla-get-selectionsets *thisdrawing*))
(setq ss1 (vlax-make-variant "ss1"))
(if (= (vla-get-count selsets) 0)
(setq ssobj (vla-add selsets ss1))
) ;_ end of if
(vla-clear ssobj)
(setq no-ent 1)
(while no-ent
(vla-Selectonscreen ssobj)

The documentation for the Selectonscreen method says that it supports filters just as the old (ssget) function does. The filter list uses the conventional DXF codes for the tests, and because my aim is to avoid DXF codes, I chose not to use a filter directly but instead to test whether objects are 3D polylines before adding them to a list of objects. After I made the list of 3D polyline objects, I deleted the selection set with the following method. Note that the objects in the selection set are not deleted, but exist as ungrouped objects in the drawing.

(vla-delete (vla-item selsets 0))

For interest, I also include an old version of the (get-3d-pline) function. That function uses the more traditional (ssget) function and then converts the entities to objects before adding their object names to a list.

As usual, good programming, and keep those requests coming in.

About the Author: Tony Hotchkiss

More News and Resources from Cadalyst Partners

For Mold Designers! Cadalyst has an area of our site focused on technologies and resources specific to the mold design professional. Sponsored by Siemens NX.  Visit the Equipped Mold Designer here!

For Architects! Cadalyst has an area of our site focused on technologies and resources specific to the building design professional. Sponsored by HP.  Visit the Equipped Architect here!