Help Needed lisp Routine for Creating 3D Polylines with Specified Slope"

Help Needed lisp Routine for Creating 3D Polylines with Specified Slope"

libarraSCXGZ
Contributor Contributor
8,292 Views
89 Replies
Message 1 of 90

Help Needed lisp Routine for Creating 3D Polylines with Specified Slope"

libarraSCXGZ
Contributor
Contributor

Hi everyone,

I need to develop a LISP routine that allows creating a 3D polyline with a user-specified slope. The goal is for the user to select a starting point, and then the polyline should continue along the surface, following the slope until it reaches a point where the maximum slope at that point is less than the design slope.

I have to carry out feasibility studies for roads and irrigation canals, and it is tedious to do it manually.

Here is a reference of what I need to do:


https://filesnj.carlsonsw.com/mirror/manuals/Carlson_2007/online/index.html?page=source%2FSite_Road_...

 

Could you help me with some basic LISP code to help me study and move forward with this? My knowledge of LISP is basic, but any help would be appreciated.

0 Likes
8,293 Views
89 Replies
Replies (89)
Message 41 of 90

autoid374ceb4990
Collaborator
Collaborator

The link posted above is just for the LISP code which will loads with a "null function" error  on my version (too old I suppose).

However I backtracked and found his "C" code here: "https://paulbourke.net/geometry/pointlineplane/ ", perhaps some helpful code there, so thanks for the link.

 

0 Likes
Message 42 of 90

leeminardi
Mentor
Mentor

I’m a bit late with a response but I’ve been tied up with other activities. The geometry challenge interested me so I thought I’d give it a try. There are two major tasks to address:


   1. Determine the line on a 3dface that starts at a specified point on the 3dface,has a specified slope and ends at the uphill edge f the 3dface.


  2. Determine the series of lines that define a path across an array of 3dfaces that have a specified slope.


I decided to tackle task 1 first. If the maximum slope of a 3dface is greater than the design slope there are two possible lines that meet requirement.  The program below creates the line for task 1. The slope vector is the cross product of the face normal with the result of the cross product of the face normal and the z axis. A vector with a slope equal to the design slope but with an XY direction of the slope vector is rotated by an angle gamma about the z axis to get a vector in the correct direction for the task. Three intersections points (q1, q2, and q3) are determined and are defined by a line passing through p and in the direction of the solution vector with the three sides of the face. Points that are not on a line segment of the 3dface, or are not at a higher z value than p, or are not coincident with p are eliminated leaving one valid solution point.
In the example below q3 satisfies the three requirements.

leeminardi_0-1724287132528.png

 

Here's a plan view showing the angle gamma.  Note that q2 is on line infinite line BC but not on the edge of the 3dface.

leeminardi_1-1724287328731.png

If the sign of gamma is negative then we have the solution below.

leeminardi_2-1724287382805.png

q1 is on a line passing through line AB.  q2 is the solution from p.

 

With a valid method for determining the design slope line the next challenge is task #2. Once a point Q is determined that lies on a edge of a 3dface, a brute force method can be used to search through the array of 3dfaces until one is found that has point q on an edge. A new point Q is calculated and the search is continued until no solution is found. To speed the search of very large collections of 3ds faces it might be beneficial to sort the 3dfaces into sub-groups. Each sub-group would only contain 3dfaces within a rectangular boundary. A search for a 3dface with a known value of Qx, Qy on an edge would only look at the group where the coordinates are within the minimum and maximum x and y coordinates for that group.

 

Run the program slopeLine then select a 3dface, specify a slope and then specify a point within the boundary of the 3dface or along one of its edges.

(defun c:SlopeLine (/ ss faceName faceData designSlope p A B C Normal slopeVector
		    slopeFace gamma q )
; Calculates the line from a given point on a 3dface to its edge at a specified slope.
; The specified slope should be less than the maximum slope of the 3dface.
; L. Minardi  8/21/2024
  
  (princ "\nSelect faces.")
  (setq	ss	 (ssget '((0 . "3DFACE"))) ; get data for 3Dface
	faceName (ssname ss 0)
	faceData (entget faceName)
  )
  (setq designSlope (getreal "\nEnter slope, (e.g. .2 = 20%): "))
  (setq p (getpoint "\nEnter start point on face. "))
  (command "point" "_non" p)
  (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))
  )
  (if  ; test if 3dface is parallel to XY plane
    (and
      (equal (car normal) 0.0 1e-5)
      (equal (cadr normal) 0.0 1e-5)
    )
     (princ "No solution, 3dFace slope = 0")
     (progn				; face slope not zero, calculate slope
       (setq slopeVector
	      (unitvec (cross Normal (cross Normal '(0 0 1))))
       )
       (if (< (caddr slopevector) 0.0) ; make sure slope is uphill
	 (setq slopeVector (mapcar '* slopeVector '(-1 -1 -1)))
       )
       (setq slopeFace
	      (/ (caddr slopeVector)
		 (distance '(0 0 0)
			   (list (car slopeVector) (cadr slopeVector) 0.0)
		 )
	      )
       )
       (if (< slopeface designSlope)
	 (princ
	   "\nNoSolution, 3dFace slope is less than maximum slope."
	 )
	 (progn
	   (setq gamma (acos (/ designSlope slopeFace)))

;	(setq gamma (* -1. gamma))  ; Change sign of gamma to get other solution.
	   (setq q (FindQ p a b c slopeVector designSlope gamma))
	   (if q
	     (command "_line" "_non" p "_non" q "")
	     (princ "\nNo Solution.")
	   )
	 )				; end progn, face slope too small
       )				; enf if
     )					; end progn, face slope not zero
  )					; end if  
  (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))
	   )
	)
      )
    )
)

(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)
)

; 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)) ; q1 on line segment
(setq q2 nil))
(if   (not (equal (distance v3 v1) (+ (distance v3 q3) (distance q3 v1)) 1e-5)) ; q1 on line segment
(setq q3 nil))

  
;set q to nil if q coincident with p
; or if q(z) coordinate less than p(z)  
(if q1
  (if (or
	(< (distance p q1) 0.00001)
	(< (caddr q1)
	   (caddr p)
	)
      )
    (setq q1 nil)
  )
)
(if q2
  (if (or
	(< (distance p q2) 0.00001)
	(< (caddr q2)
	   (caddr p)
	)
      )
    (setq q2 nil)
  )
)
(if q3
  (if (or
	(< (distance p q3) 0.00001)
	(< (caddr q3)
	   (caddr p)
	)
      )
    (setq q3 nil)
  )
)
; set q to the only non nil point
(cond
  (q1 (setq q q1))
  (q2 (setq q q2))
  (q3 (setq q q3))
)
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; 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))
    )
)

 

 

lee.minardi
0 Likes
Message 43 of 90

john.uhden
Mentor
Mentor

@autoid374ceb4990 ,

Attached is an AutoLisp file that contains two commands that I tested on your LIDAR.dwg:

c:3DFaces2Profile (c:3DF2P) and c:Grade.

The first one creates a profile along a LWpolyline alignment across the sea of 3DFaces.

The second one helps you to draw a profile tangent and reports its grade as you are moving the cursor to pick the second point.

I don't think this solves the OP's problem, but it could be helpful in some regard.

John F. Uhden

Message 44 of 90

autoid374ceb4990
Collaborator
Collaborator

John:

Your routines sound really interesting, but unfortunately my AutoLISP is too old for me to try them. I will try to find someone with a newer AutoCAD version to try them out. Do you have any idea when the "vl" functions were introduced? I have a routine that I wrote many years ago to draw the profile of a polyline drawn across my "sea" of 3DFACES, and I almost had finished the code for drawing the constant slope line, and my hard drive crashed. I normally back up my hard drive every month, but for some reason I skipped last month so I lost all my work.  Oh well!

 

Thanks again - good work.

0 Likes
Message 45 of 90

john.uhden
Mentor
Mentor

@autoid374ceb4990 ,

Just what release is your AutoCAD?  I'm using 2002.

I remember that I was using Vital Lisp by Peter Petrov of Basis Software in R14 before Autodesk bought it to make Visual Lisp.

John F. Uhden

0 Likes
Message 46 of 90

leeminardi
Mentor
Mentor

Hi @john.uhden ,

 

Impressive program.

It is unclear to me  how in 3DFACES2PROFILE you determine which 3DFACE a point on the LWPOLYLINE is projected to.  I would think that you would need to search 3DFACE by 3DFACE to find it.  Can you elaborate?

Thanks,

 

Lee

 

P.S. How's the sailing?  I got my first HG flight in yesterday in 2 years (full recovery frrom knee replacements take awhile). The air was rowdy but with thermals aplenty. 

lee.minardi
0 Likes
Message 47 of 90

john.uhden
Mentor
Mentor

Hi, @leeminardi ,

I'm glad you are interested.

Yeah, what a pain.  Turns out that 3DFaces are not curves, so you can't use any vlax-curve functions on them.

I get the objects by Fence along the path of the LWPoly and convert them to 3DPolys (which are later erased).

Then I use ssnamex to get the intersection points and make sure they are in order and remove any duplicates.

But now I have to obtain the Z value of each 3DPoly at each point of intersection.  Maybe I coulda done it as part of the ssnamex data, but it seemed too daunting to me 'cause they might be out of order, so I instead grabbed a small Window-Crossing of 3Dpolys at each intersection and used getclosestpointtoprojection to obtain X,Y,Z.  Then I convert the X,Y to the distance along the LWPoly as X.  When combined with the Z you have the profile data (X,Z).

 

Happy to hear about your hang-gliding.  No sailing for me.  I managed to get avascular necrosis (AVN) in my right hip which hurts and limits my mobility (like to get from one side of the boat to the other).

Guess it doesn't matter though, because the yacht club relocated all the boats and lost everything of mine except the hull (or it was theft).

John F. Uhden

0 Likes
Message 48 of 90

autoid374ceb4990
Collaborator
Collaborator

John:

I am using R14.  Do you know if the Vital LISP is still available for R14?  I did a quick search, but about all I could find was that AutoDESK bought it.

Regards,

Charles

0 Likes
Message 49 of 90

john.uhden
Mentor
Mentor

@autoid374ceb4990 ,

Since Autodesk bought the product from Basis, it is most likely that Basis had to hand over all the code and an agreement to not produce or sell or license or lend or even give away any of it.  They don't own it anymore.

I think mine went to the graveyard with my Win98 machine, but I'll have to check my Win7 machine.  Back in those days I was pretty diligent about saving everything.

So, your challenge could be to make old-style functions that emulate what Vital Lisp does.  You know, "got along without it before I met it; gonna get along without it now."  Skeeter Davis, 1964

John F. Uhden

0 Likes
Message 50 of 90

john.uhden
Mentor
Mentor

@leeminardi ,

I dreamed up a better way over night.

Via selection by fence and ssnamex you get both the 3DFace entity name and point(s) of intersection (2D).

So...

You test each edge to see if a vertical line (p1 and p2) intersects the edge (p3 and p4)...

(inters p1 p2 p3 p4) gives you the intersection point with the elevation of the 3DFace.  No need to make 3DPolys.

 

John F. Uhden

0 Likes
Message 51 of 90

autoid374ceb4990
Collaborator
Collaborator

John:

I guess great minds run in the same (small) circles.

For anyone interested in this problem I thought I would tell how I solved it.

First pick a 3DFACE from which to start. Get the information for the 3DFACE to include the X,Y,Z coordinates for the three vertices (A,B,C) and get the name of the 3DFACE (N1).

Next pick a point inside the 3DFACE (P) and calculate the slope of the lines from P to A, B, and C. Call these slope AS,BS,CS. The desired slope (S) will lie on one (or perhaps two) of the triangle sides. Compare S to AS, BS, and CS to see which side the slope will intersect. In the attached picture, assuming the desired slope is 2%, the desired slope crosses side C-A and also A-B. Calculate the midpoint (M) of the triangle side and calculate the slope from P to M. From this information you can tell if the desired slope (S) lies to the right or left of the line from P to M. In the attached picture the 2% slope lies between M and C. Divide this line segment in half and repeat the process until the distance from M to the previous M is very small. I used 0.001.

 

To find the adjacent triangle extend the first calculated midpoint line from P to M by 0.01 (or some small increment), call the new point X, and use SSGET with a crossing option to select entities crossing points M and X. You should now have two 3DFACEs in the selection set. Ignore N1 and the remaining 3DFACE should be the adjoining 3DFACE (N2). If you have more than two 3DFACES in the selection set you may have duplicate 3DFACE’s or some other problem.

 

This worked for me, but I am programming in ‘C’, creating ARX files, but I think it should be easily transferable to LISP.  I got back from vacation yesterday and my hard drive crashed before I had completely finished the routine and I did not have a backup, so I will probably pursue this any further.

0 Likes
Message 52 of 90

john.uhden
Mentor
Mentor

Um, those pictures were worth zero words.

John F. Uhden

0 Likes
Message 53 of 90

leeminardi
Mentor
Mentor

@autoid374ceb4990 

Charles, 

The direction of the slope vector and the direction of the required maximum slope (I call it the design slope) can be directly calculated. It is not necessary to use a numerical solution (i.e., trial and error).
As I note in post #42, the slope vector is the cross product of the face normal with the result of the cross product of the face normal and the z axis. In LISP we have:

(setq slopeVector (unitvec (cross Normal (cross Normal '(0 0 1)))))


Where unitvec makes it a unit vector.


We can create a vector at the design angle under the slope vector as shown in red in the image below.

leeminardi_0-1724787724451.png

 

We want to rotate this vector about the z axis by an angle gamma that will make it flush with the plane of the 3dface. This angle is:

(setq gamma (acos (/ designSlope slopeFace)))

where slopeFace is:

		(setq slopeFace
		       (/ (caddr slopeVector)
			  (distance '(0 0 0)
				    (list (car slopeVector) (cadr slopeVector) 0.0)
			  )
		       )
		)


This is one solution that yields the green design slope vector. The other solution is to rotate the slope vector by an angle of minus gamma. Programmatically you can set it up to either always take the “+” or “-“option.
Knowing point P (the start point) and the design slope vector that lies on the face plane, point Q , the exit point (your point M) can be determined by calculating the three intersection points of the lines defined by P and the Deign Slope vector with the infinite lines defined by the three sides of the 3dface.
Try out my code from post #42 on a single 3Dface.
I’m in the middle of writing the code to create PQ lines for a group of 3dfaces. I was going to search the list of faces looking for a face that has point Q on its edge but I like your approach of using “… SSGET with a crossing option to select entities crossing points M and X…” to find the two adjacent faces. I’ll look into that approach.

 

 

Note, in my previous post I incorrectly showed the slope vector for the negative gamma solution.  Hoefully the following will help to clarify the angle gamma.

leeminardi_1-1724788170713.png

 

Lee

lee.minardi
0 Likes
Message 54 of 90

john.uhden
Mentor
Mentor

@leeminardi ,

You mother should have named you Vector.

John F. Uhden

0 Likes
Message 55 of 90

autoid374ceb4990
Collaborator
Collaborator

 @leeminardi

I tried your code from post #42 and got a "bad argument" error.  I traced the error down to your "FindQ" function, but could not see anything there that might cause an error.  I am not a great LISP programmer, so any ideas as what might cause this error?  Remember I am using r14.

Also if you try using the idea I posted about using ssget to find the adjacent 3DFACE, you can use just the M point with no need to calculate the X point, just enter the M point twice for the crossing points.

0 Likes
Message 56 of 90

leeminardi
Mentor
Mentor

Yeah, it's not as bulletproof as I had hoped. I've more debugging to do. 

I've had some success with a group of faces which I will post when it's more reliable.

lee.minardi
0 Likes
Message 57 of 90

Sea-Haven
Mentor
Mentor

It may be useful to be added to "TriangV0.6.7.lsp" as an extra function. Just google for more info.

 

 

0 Likes
Message 58 of 90

leeminardi
Mentor
Mentor

@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.

leeminardi_0-1724942455868.png

 

(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
0 Likes
Message 59 of 90

Sea-Haven
Mentor
Mentor

Just draw the 1st line as a pline then as you add a line just use pedit join (entlast) via the lisp. Or add each entity name to a list then use join at end.

0 Likes
Message 60 of 90

autoid374ceb4990
Collaborator
Collaborator

@leeminardi

I tried out the program you posted in post #58 and it works very well, with the few exceptions you mentioned.

I was trying to enter a design slope of 0.02 (2%) and I noticed that your code would always default to 0.2 (20%), so I changed the input for that variable. 

As far as creating a POLYLINE, what I have done in my 'C' code is write each point to a file as they are created, and when the the program ends, read the points in the file to create the pline. Don't know if that is feasible in LISP???

0 Likes