General Software

AutoLISP Solutions: Create Long Intermediate Terrain Contours

14 Sep, 2005 By: Tony Hotchkiss Cadalyst

AutoLISP can form an intermediate contour that assumes a linear interpolation between the contour heights

Rami Mann e-mailed a request to draw a polyline between two existing polylines representing terrain contours. His project is missing some contours, and he wants to form an intermediate contour assuming a linear interpolation between the contour heights.

The AutoLISP solution is CONTOURS.LSP, which allows the user to select any two polylines (lightweight or 2D) and enter a precision number (default 100) for the number of segments in the resulting polyline. If the terrain changes height rapidly in some places and is flatter in others, then the contours will be close together in parts and may be far apart in other sections (figure 1). A bonus file I wrote, RPL.LSP, will come in handy to reverse the direction of any selected polyline.


Figure 1. Terrain contours with varying distances between them.

The lengths of the polylines in figure 1 are about 6,500 units and 5,300 units for the outer and inner contours, respectively. Applying CONTOURS.LSP to the parts of the contours that are somewhat parallel shows better results than those that vary wildly (figure 2). The precision (number of segments) gave good results for anything over 200 but did not improve much between 300 and 2,000. It took about 1 second for 200 points and about 5 seconds for 1,000 points to generate the curve.


Figure 2. A contour generated between two existing contours.

Get the Code
Download the CONTOURS.LSP and RPL.LSP files from Cadalyst's CAD Tips site and save them in AutoCAD's Support directory. Use the Appload facility by selecting Tools / Load Application. Then select the CONTOURS.LSP and RPL.LSP programs from where you stored them.

How to Use the CONTOURS Code
After you load the code, the system prompts you to enter CT to start the program. To see this prompt, you may need to set your Command window size to 3 lines by dragging the Command window splitter bar appropriately. If you are using AutoCAD 2006 and you are not using the Command line area, you can still enter CT to start. Then AutoCAD will prompt you to select two polylines. How the prompts are displayed will depend on the version of AutoCAD. I tested the code for AutoCAD 2004 and 2006.

After you select the polylines, the Precision <100>: prompt is displayed, and you can select Enter to accept the default value shown of 100 points. The intermediate contour is then automatically displayed. It is assumed that the polylines (contours) run in the same direction, so they are logically parallel, and you do not therefore select any particular end of the chosen contours. The result is a polyline made up of line segments only, and you may want to convert it to a fit curve.

If you encounter a problem in which the resulting intermediate contour bears no resemblance to the mid boundary, the selected polylines may not run in the same direction. To correct this problem, you need to enter RPL and select one of the contours to reverse its direction. I wrote RPL many years ago so the code is quite ancient, but it still works in AutoCAD 2004 and 2006. It probably works for any version of AutoCAD from R13 onward.

When you use RPL, a prompt tells you that the selected polyline was reversed in direction, but you will see absolutely no difference in its appearance.

Programming Notes
The number of segments in each contour polyline may vary greatly, and so it would not be possible to try to use the polyline segment endpoints as a way of interpolating the curves.

Another approach that I tested and later rejected was attempting to divide the lengths of the polylines into an equal number of parts, and then find the midpoint between each successive pair of such points. That approach gave inaccurate results, so I finally used the start and end parametric values for each curve, and divided those numbers equally by the precision number. I then interpolated between each successive pair of points to form the midpoint that made up the resulting polyline. I used only straight line segments for the result, and for a reasonable precision the appearance is indistinguishable from arc segments.

CONTOURS.LSP starts with my error handler and system variable manager functions, followed by CONTOUR, which sets up some initial conditions and calls GET-PLINES and the main function CONTOURS.

GET-PLINES uses the SelectionSets collection and the SelectOnScreen method to allow the user to select entities. There are tests to ensure that polylines (lightweight or 2D polylines) are selected.

CONTOURS starts by setting some parametric information using the (vlax-curve-getStartParam) and (vlax-curve-getEndParam) functions as follows:


(setq	pl1	  (car plobjs)
pl2 (cadr plobjs)
lyr (vla-get-Layer pl1)
start-pl1 (vlax-curve-getStartParam pl1)
end-pl1 (vlax-curve-getEndParam pl1)
start-pl2 (vlax-curve-getStartParam pl2)
end-pl2 (vlax-curve-getEndParam pl2)
param1 (/ (- end-pl1 start-pl1) prec)
param2 (/ (- end-pl2 start-pl2) prec)
i 0
2Dpoint-list nil
) ;_ end of setq

This is immediately followed by a repeat loop that is used to create a list of vertex points for the resulting polyline contour:


(repeat (1+ prec)
(setq p1 (vlax-curve-getPointAtParam pl1 (* i param1)))
(setq p2 (vlax-curve-getPointAtParam pl2 (* i param2)))
(if (and (/= p1 nil) (/= p2 nil))
(setq dist (distance p1 p2)
ang (angle p1 p2)
p3 (polar p1 ang (/ dist 2))
) ;_ end of setq
(setq 2Dp (list (car p3) (cadr p3))
2Dpoint-list (append 2Dpoint-list 2Dp)
) ;_ end of setq
) ;_ end of progn
) ;_ end of if
(setq i (1+ i))
) ;_ end of repeat

The function ends by creating a vertex array in the appropriate format for the AddLightWeightPolyline method, after which the resulting object is put on the same layer as the original first polyline that was selected. The two lines of code to achieve this are:


  (setq obj (vla-AddLightWeightPolyline
*modelspace* vertex-array))
(vla-put-Layer obj lyr)

The Lyr variable was set up by the (vla-getLayer) method shown earlier in the first few lines above.

Compare this method of making polylines with the ENTMAKE version used in RPL as follows (note the use of the dxf code 8 for assigning the layer):


(setq	enlist (list '(0 . "LWPOLYLINE")
'(100 . "AcDbEntity")
'(100 . "AcDbPolyline")
(cons 90 (length p-list))
(cons 70 (dxf 70 x-ent))
(cons 8 (dxf 8 x-ent))
) ; list
) ; setq
(setq elst nil)
(repeat (length p-list)
elst (append elst
(list (cons 10 (car p-list)))
) ;_ end of append
) ; setq
elst (append elst
(list (cons 42 (car b-list)))
) ;_ end of append
) ; setq
(setq p-list (cdr p-list))
(setq b-list (cdr b-list))
) ; repeat
(setq enlist (append enlist elst))
(entdel x-ent)
(entmake enlist)

Here, as in the CONTOURS object-oriented version, the list of vertices was already established, and the rest of the code is necessary to complete the ENTMAKE AutoLISP function. This really shows the great convenience of using the more modern approach to LISP programming.

As always, I look forward to receiving your requests for AutoLISP Solutions. Contact me using the links below.

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!