Convert 3D Polylines to 2D31 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.
HOW TO USE PLINE-3D-2D.LSP
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.
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.
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 CodeDownload 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 email@example.com or visit his web site.
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
(setq no-ent 1)
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.