@Kent1Cooper wrote:
.....
[As for the centerline, .... I don't know of a way to automate it.]
Well, I thought of something, though it may not be quite what you need. This traces along the shorter of the two 3DPolylines selected, and at each vertex, finds the closest point on the other one, calculates the point halfway between them, and it draws a 3DPolyline through the halfway-between locations. It doesn't account for places where there isn't a vertex on the shorter one approximately "lined up with" or "across from" one on the longer one, but in the sample drawing, there's only one such location, and in a pretty straight stretch, so the effect on the result is minimal. At the left end, it does this because of the little perpendicular leg:

And since it finds the closest point on the across-the-road 3DPolyline, not necessarily the closest vertex across the road [since in some places there isn't one roughly across the road], this kind of thing happens:

where the shorter one that it's stepping along is the lower red one, the dotted line is reaching across to the closest point on the longer one above, and the vertex on the new 3DPolyline is the midpoint between those locations, not the midpoint between roughly-across-from-each-other vertices. I thought of having it find the nearest vertex, but that could cause trouble where there isn't one close to across-the-road.
But if that's close enough for you, it does follow the Z-coordinate variability in the 3D-ness of the source Polylines.
(vl-load-com)
(defun C:3DCL (/ ss 3DplA 3DplB lenA lenB 3Dpl1 3Dpl2 n vert1 pt2)
(prompt "\nTo draw a Center-Line between two 3D Polylines,")
(if
(and
(setq ss (ssget '((0 . "POLYLINE"))))
(= (sslength ss) 2)
(= (cdr (assoc 100 (reverse (entget (ssname ss 0))))) "AcDb3dPolyline")
(= (cdr (assoc 100 (reverse (entget (ssname ss 1))))) "AcDb3dPolyline")
); and
(progn ; then
(setq
3DplA (ssname ss 0)
3DplB (ssname ss 1)
lenA (vlax-curve-getDistAtParam 3DplA (vlax-curve-getEndParam 3DplA))
lenB (vlax-curve-getDistAtParam 3DplB (vlax-curve-getEndParam 3DplB))
3Dpl1 (if (< lenA lenB) 3DplA 3DplB); shorter one
3Dpl2 (ssname (ssdel 3Dpl1 ss) 0); longer one
n -1
); setq
(command "_.3dpoly")
(repeat (+ (fix (vlax-curve-getEndParam 3Dpl1)) (if (vlax-curve-isClosed 3Dpl1) 0 1))
(setq
vert1 (vlax-curve-getPointAtParam 3Dpl1 (setq n (1+ n))); vertex on shorter
pt2 (vlax-curve-getClosestPointTo 3Dpl2 vert1); closest point to it on longer
); setq
(command "_none" (mapcar '/ (mapcar '+ vert1 pt2) '(2 2 2))); midway between
); repeat
(command (if (vlax-curve-isClosed 3Dpl1) "_close" ""))
); progn
(prompt "\nYou must select two and only two 3DPolylines."); else
); if
(princ)
); defun
(prompt "\nType 3DCL to draw a Center-Line between two 3DPolylines.")
(princ)
If you could get them to always have the same number of vertices, and to both cover about the same extent without one stretching well beyond the end(s) of the other, a variant on SplineAverage.lsp, >here<, could be made for 3DPolylines.
Kent Cooper, AIA