Thanks for the link @drdownload18 but David's code hung my ACAD.
I found a fn to use a trim method and get the apparent intersection that way. The benefit at least for my limited knowledge is that it will work for lines, 2d polylines and 3d polylines too.
Here's the GIF and code. Thanks to Kh.mbkh for the trim intersection function which I've shoehorned into this.
I sorted the points by x values to draw them correctly. As always, not pretty code but best I can do.
(vl-load-com)
;; -------------------------=={ Section_Profile }==---------------------------
;; -----------------------------------------------------------------------
;; AUTHOR & ADDITIONAL CODE
;; Author 3dwannab, 2023
;; Thanks to Kh.mbkhs' for the apparent intersection code found at the link below:
;; https://forums.autodesk.com/t5/visual-lisp-autolisp-and-general/projected-intersection-between-a-line-and-3dPolyline/m-p/9435434#M398330
;; ABOUT / NOTES
;; - Takes lines, 2d Poylines and 3d Polylines and allows the user to select a
;; section line to create a profile in 2d.
;; - This profile will get the Z value of the intersection and create a polyline
;; profile. And 3d rotate it and move it to where the Z value is now the Y value.
;; So a point 100,1000,333 will be now 100,333,0.
;; - Points are also created at this location, that match that of the profile
;; lines. This means they are easily identifiable, should you have them in
;; layers.
;; FUNCTION SYNTAX
;; Short-cut SECP
;; Long-cut Section_Profile
;; VERSION DATE INFO
;; Version 1.0 2023.06.25 Initial
;; TO-DO LIST
;; - Try to fix bugs below.
;; BUGS
;; (command "_.matchprop" ...) Outputs to the commandline even though cmdecho is 0.
;; (command "_.rotate3d" ...) Outputs to the commandline even though cmdecho is 0.
;; -----------------------------------------------------------------------
;; -------------------=={ Section_Profile START }==-----------------------
(defun c:SECP () (C:Section_Profile))
(defun C:Section_Profile (/ *error* 3dPolObj acDoc basept idx lastEnt lstPts newPos pfpline proLines ptFinal ptInterSec secLine ssSel var_angbase var_angdir var_cmdecho var_peditaccept)
(defun *error* (errmsg)
(and acDoc (vla-EndUndoMark acDoc))
(and errmsg
(not (wcmatch (strcase errmsg) "*CANCEL*,*EXIT*"))
(princ (strcat "\n<< Error: " errmsg " >>\n"))
)
(setvar 'cmdecho var_cmdecho)
(setvar 'peditaccept var_peditaccept)
(setvar 'angbase var_angbase)
(setvar 'angdir var_angdir)
(princ)
)
(setq acDoc (vla-get-ActiveDocument (vlax-get-acad-object)))
(or (vla-EndUndoMark acDoc) (vla-StartUndoMark acDoc))
(setq var_angbase (getvar 'angbase))
(setq var_angdir (getvar 'angdir))
(setq var_cmdecho (getvar 'cmdecho))
(setq var_peditaccept (getvar 'peditaccept))
(setvar 'angbase 0)
(setvar 'angdir 0)
(setvar 'cmdecho 0)
(setvar 'peditaccept 1)
if
(and
(setq secLine (car (entsel "\nSelect Section Line (Line or Polyline)...")))
(princ "\nSelect Lines or Polylines (2D or 3D)...")
(setq proLines (ssget '((0 . "LINE,*POLYLINE"))))
)
(progn
(repeat (setq idx (sslength proLines))
(setq idx (1- idx)
ent (ssname proLines idx)
)
;; Code to get the apparent intersection of the section line and profile line
(setq ptFinal (vlax-curve-getEndPoint secLine)) ; end point of the pline
(command "_trim" ent "" ptFinal "")
(setq 3dPolObj (vlax-ename->vla-object ent))
(setq pfpline (vlax-curve-getEndPoint secLine))
(setq ptInterSec (vlax-curve-getclosestpointtoprojection 3dPolObj pfpline '(0 0 1)))
(command "_.point" ptInterSec)
(command "_.matchprop" "_non" ent "_non" (entlast) "")
(setq newPos (list (car ptInterSec) (caddr ptInterSec) 0))
(command "_.move" (entlast) "" "_NONE" ptInterSec "_NONE" newPos)
(setq lstPts (cons ptInterSec lstPts))
)
)
(if lstPts
(progn
;; Sort the list by the X value. Means the lines are drawn correctly along the X axis
(setq lstPts (vl-sort lstPts '(lambda (x y) (if (= (car x) (car y)) (< (cadr x) (cadr y)) (< (car x) (car y))))))
; Get the last entity created. This helps to get the newly created objects
(setq lastEnt (entlast))
;; Draw the lines
(if (> (length lstPts) 1)
(mapcar '(lambda (a b) (entmakex (list '(0 . "line") (cons 10 a) (cons 11 b)))) lstPts (cdr lstPts))
)
;; Select all entities created in function code above
(setq ssSel (ssadd))
(while (setq lastEnt (entnext lastEnt))
(ssadd lastEnt ssSel)
)
;; Rotate the selection so it appears correct in the top view
(command "_.rotate3d" ssSel "" "_X" (car lstPts) "270")
;; Sample of the lstPts variable (For testing)
;; (setq lstPts '((-11246.5 34919.5 550.0) (-8782.5 34919.5 150.0) (-6782.5 34919.5 150.0) (-6716.0 34919.5 0.05) (-3716.0 34919.5 100.0) (-716.0 34919.5 0.05) (-649.5 34919.5 150.0) (1350.5 34919.5 150.0) (3814.5 34919.5 550.0)))
;; Set basePt and newPos. Sets the new profile from its Z values to according Y values.
(setq basept (car lstPts))
(setq newPos (list (car basept) (caddr basept) 0))
(command "_.move" ssSel "" "_NONE" basept "_NONE" newPos)
;; Flatten the new objects for good measure
(vl-cmdf "move" ssSel "" "0,0,0" "0,0,1e99")
(vl-cmdf "move" ssSel "" "0,0,0" "0,0,-1e99")
;; Join the new profile lines together to create a polyline
(command "_.pedit" "_M" ssSel "" "_J" "" "")
; (command "_.zoom" "_o" (ssget "_L") "") ;; Optional to zoom to created objects
(sssetfirst nil (ssget "_L"))
(princ "\nA profile has been created and selected.. Message me if problemo. Signed: 3dwannab.")
(princ)
)
)
(vla-EndUndoMark acDoc)
(*error* nil)
) ;; end Section_Profile
(princ "\n: ------------------------------\n\"3dwannab_Section_Profile.lsp\" locked and loaded | Version 1.0 by 3dwannab. Type \"Section_Profile\" OR \"SECP\" to run.\n: ------------------------------\n")
(princ)
;; -----------------------------------------------------------------------
;; ------------------=={ Section_Profile END }==--------------------------
;; EOL
;;(C:Section_Profile) ;; Unblock for testing in VSCode
Road Profile 3d Polys, 2d Polys And Lines.dwg