@autoid374ceb4990
I've got some promising results for calculating a path of a specified slope along a collection of 3dfaces. It is still a work-in-progress however.
To focus on the slope line calculation I've kept the user input requiring the following:
1. User specified slope, the default is 20%
2. The start point must be on the edge of a 3dface (use osnap nearest).
3. The user must select the 3dface that has the point on its edge.
The program does not terminate gracefully. Note that P is the beginning point on the edge of a face and Q the departing point. Q is used to find the next 3dface to work with. The main problem now is finding a reliable process for identifying the two adjacent faces at Q. I tried several configurations of using ssget "_c" to find the two faces that are adjacent at Q. Just using Q twice as you suggested sometimes works. I had better luck with two points (lower left, upper right) as with this code. I'm not sure if it helps or hurts to use 2D rather than 3D points.
(setq Q2D (list (car Q) (cadr Q)))
(setq pLL (mapcar '- Q2D '(0.005 0.005 )))
(setq pUR (mapcar '+ Q2D '(0.005 0.005 )))
(setq ss (ssget "_c" pLL pUR '((0 . "3dface" ))))
It occasionally fails. When a selection set was not created the program creates a small circle at Q and outputs "No selection at Q."
The program does not create a single 3dpoly. I found it better for debugging reasons to just create lines with this version.
Here's a sample of constant slope paths that were created on your LIDAR drawing.

(defun c:SpecSlope (/)
; Creates a path along a collection of 3d faces of user defined slope.
; The path is defined by individual line segments.
; User input:
; Design slope, default = 0.2 (20%)
; Point on edge of a 3dface
; Selection of the 3dface with the point
; Known problems:
; 1. Does not terminate gracefully!
; 2. Sometimes the selection of 2 adjacent faces at Q is not successful.
; 3. Does not handle case of path leading to the vertex of several 3dfaces.
; 4. User control of which of 2 valid directions to take is not provided.
; L. Minardi 8/29/2024 v1
(setq designSlope (getreal "\nEnter slope, (e.g. .2 = 20%): "))
(if (/= designslope)
(setq designslope 0.2)
)
(setq p (getpoint "\nEnter start point on the edge of a face. "))
(command "point" "_non" p)
(princ "\n Select the 3dface of the stating point: ")
(setq ss (ssget '((0 . "3DFACE"))) ; get data for 3Dface
faceName (ssname ss 0)
)
(while faceName
(setq faceData (get_face_data faceName)
A (nth 0 faceData)
B (nth 1 faceData)
C (nth 2 faceData)
Normal (nth 3 faceData)
slopeVector (nth 4 faceData)
slopeFace (nth 5 faceData)
err (nth 6 faceData)
)
(if (= err 1)
(progn
(princ
"\nNoSolution, 3dFace slope is less than maximum slope.\n
Slope = "
)
(princ slopeface)
(setq faceName nil)
)
(progn
(setq gamma (acos (/ designSlope slopeFace)))
(setq q (FindQ p A B C slopeVector designSlope gamma))
(if (< (caddr q) (caddr p)) ; is q lower
(progn ; try minus gamma
(setq gamma (- gamma))
(setq q (FindQ p A B C slopeVector designSlope gamma))
)
)
(command "_point" "_non" Q)
(command "_line" "_non" P "_non" Q "")
;;; (setq ss (ssget "_c" q q '((0 . "3dface"))))
(setq Q2D (list (car Q) (cadr Q)))
(setq pLL (mapcar '- Q2D '(0.005 0.005 )))
(setq pUR (mapcar '+ Q2D '(0.005 0.005 )))
(setq ss (ssget "_c" pLL pUR '((0 . "3dface" ))))
(if (not ss)
(progn
(princ "\nNo selection at Q.")
(command "_circle" q 0.2) ; draw circle to show error location
)
)
(setq face1 (ssname ss 0)
face2 (ssname ss 1)
)
(if (equal face1 facename)
(setq faceName face2)
(setq faceName face1)
)
(setq p q)
) ; end progn no errors
) ; end if
) ; end while
(princ)
)
(defun FindQ ( p v1 v2 v3 slopeVector designSlope gamma / q s q1 q2 q3 )
; determine up hill point at slope = designSlope
; p = start point
; v1, v2, v3 = 3dface vertices
; slopeVector = slope vector of 3dface that points in the uphill direction
; designSlope = desired slope of line (e.g., 0.2 = 20%)
; gamma = angle between the projection of slopeVector to xy plane and the
; direction of the designSlope line projected to the XY plane
(setq Q
(mapcar
'+
p
(list
(-
(* (car slopevector) (cos gamma))
(* (cadr slopevector) (sin gamma))
)
(+
(* (car slopevector) (sin gamma))
(* (cadr slopevector) (cos gamma))
)
(* designSlope
(sqrt
(+ (expt (car slopevector) 2) (expt (cadr slopevector) 2))
)
)
)
)
)
; get the three intersections of design slope vector with face edges
(setq S (mapcar '+ p (mapcar '- q p)); point in direction of slopevector from p
q1 (inters v1 v2 p s nil)
q2 (inters v2 v3 p s nil)
q3 (inters v3 v1 p s nil)
)
; check if q1, q2, q3, are on an edge segment of face
; set q to nil if not on line segment
(if (not (equal (distance v1 v2)
(+ (distance v1 q1) (distance q1 v2))
1e-5
)
) ; q1 on line segment?
(setq q1 nil)
)
(if (not (equal (distance v2 v3)
(+ (distance v2 q2) (distance q2 v3))
1e-5
)
) ; q2 on line segment?
(setq q2 nil)
)
(if (not (equal (distance v3 v1)
(+ (distance v3 q3) (distance q3 v1))
1e-5
)
) ; q3 on line segment?
(setq q3 nil)
)
;set q to nil if q coincident with p
(if (equal q1 p 0.001)
(setq q1 nil)
)
(if (equal q2 p 0.001)
(setq q2 nil)
)
(if (equal q3 p 0.001)
(setq q3 nil)
)
; set q to only non-nil q
(cond
(q1 (setq q q1))
(q2 (setq q q2))
(q3 (setq q q3))
)
)
;;;;;;;;;;;;;;;;;;;
(defun get_face_data (faceName / A B C Normal slopeVector data)
; Given a face name determine its vertices, normal vector, slope vector, slope, and error if any.
; Returns a list with the data
; err = nil, no errors
; err = 1, no solution, the slope of the face is less than the design slope
(setq faceData (entget faceName))
(setq A (cdr (assoc 10 faceData)) ;three corners of the 3DFACE
B (cdr (assoc 11 faceData))
C (cdr (assoc 12 faceData))
Normal (cross (mapcar '- B A) (mapcar '- C B))
err nil
)
(setq slopeVector (cross Normal (cross Normal '(0 0 1))))
(if (< (caddr slopeVector) 0.) ; make sure normal has a + z coorindate
(setq slopeVector (mapcar '* '(-1 -1 -1) slopeVector))
)
(setq slopeFace
(/
(caddr slopeVector)
(distance '(0 0 0)
(list (car slopeVector) (cadr slopeVector) 0.0)
)
)
)
(if (< slopeface designSlope)
(setq err 1)
)
(setq data (list A B C Normal slopeVector slopeFace err))
)
; Unit vector of v
(defun unitvec (v / x)
(setq x (distance '(0 0 0) v)
x (mapcar '/ v (list x x x))
)
)
;; ArcCosine - Lee Mac
;; Args: -1 <= x <= 1
(defun acos ( x )
(if (<= -1.0 x 1.0)
(atan (sqrt (- 1.0 (* x x))) x)
)
)
(defun dot (a b / dd)
(setq dd (mapcar '* a b))
(setq dd (+ (nth 0 dd) (nth 1 dd) (nth 2 dd)))
);end of dot
;;; Compute the cross product of vectors a and b
(defun cross (a b / crs)
(setq crs (list
(- (* (nth 1 a) (nth 2 b))
(* (nth 1 b) (nth 2 a))
)
(- (* (nth 0 b) (nth 2 a))
(* (nth 0 a) (nth 2 b))
)
(- (* (nth 0 a) (nth 1 b))
(* (nth 0 b) (nth 1 a))
)
) ;end list
) ;end setq c
) ;end cross
;; Tangent - Lee Mac
;; Args: x - real
(defun tan ( x )
(if (not (equal 0.0 (cos x) 1e-10))
(/ (sin x) (cos x))
)
)
; test if 3 points are collinear.
;; Collinear-p - Lee Mac
;; Returns T if p1,p2,p3 are collinear
(defun Collinear-p (p1 p2 p3)
(
(lambda (a b c)
(or
(equal (+ a b) c 1e-8)
(equal (+ b c) a 1e-8)
(equal (+ c a) b 1e-8)
)
)
(distance p1 p2)
(distance p2 p3)
(distance p1 p3)
)
)
; some function to help debugginh
(defun c:faceName (/)
(setq ss (ssget '((0 . "3DFACE"))) ; get data for 3Dface
faceName (ssname ss 0)
)
(entget faceName)
(princ facename)
(princ)
)
(defun c:GetSlope (/ s p1 p2 data d slope)
(setq s (ssget '((0 . "line")))
data (entget (ssname s 0))
p1 (cdr (assoc 10 data))
p2 (cdr (assoc 11 data))
d (distance (list (car p1) (cadr p1))
(list (car p2) (cadr p2))
)
slope (/ (- (caddr p2) (caddr p1)) d)
)
(princ "\nSlope = ")
(princ slope)
(princ)
)
lee.minardi