Angle between 3D points (polyline vertices)

Angle between 3D points (polyline vertices)

Browning_Zed
Advocate Advocate
2,347 Views
14 Replies
Message 1 of 15

Angle between 3D points (polyline vertices)

Browning_Zed
Advocate
Advocate

Hello everyone,
The routine posted below should return a list in which:
1st item - coordinates of the nearest vertex of the polyline relative to the picked location on the polyline
2nd item - coordinates of the second vertex of the picked polyline segment
3rd item - the angle between the first and second obtained points.

 

(defun c:Test ( / s e pr p a b pt1 pt2 )
	(if (and (setq s (entsel)) (wcmatch (cdr (assoc 0 (entget (setq e (car s))))) "*POLYLINE"))
		(progn
			(setq
				pr
				(vlax-curve-getparamatpoint e (setq p (vlax-curve-getclosestpointto e (cadr s))))
			)
			(if (< 	(distance p (setq a (vlax-curve-getpointatparam e (fix pr))))
					(distance p (setq b (vlax-curve-getpointatparam e (1+ (fix pr)))))
				)
				(setq pt1 a pt2 b)
				(setq pt1 b pt2 a)
			)
			(list pt1 pt2 (angle '(0 0) (mapcar '- a b)))
		)
		(princ "\n Nothing selected or not a Polyline <!>")
	)
)
(vl-load-com)

 

The problem is that the function returns the wrong angle value. Here  I found a way to determine the angle between the obtained 3D points, but the expression

(angle '(0 0) (mapcar '- a b))

does not return the correct angle value.
How can this issue be resolved?

0 Likes
Accepted solutions (1)
2,348 Views
14 Replies
Replies (14)
Message 2 of 15

CADaSchtroumpf
Advisor
Advisor

Hi,

Try to change this?

(vlax-curve-getparamatpoint e (setq p (vlax-curve-getclosestpointto e (cadr s))))

by

(vlax-curve-getparamatpoint e (setq p (vlax-curve-getclosestpointto e (osnap (cadr s) "_near"))))

or if you use in UCS

(vlax-curve-getparamatpoint e (setq p (vlax-curve-getclosestpointto e (trans (osnap (cadr s) "_near") 1 0))))

for have angle in WCS...

0 Likes
Message 3 of 15

hak_vz
Advisor
Advisor

You are receiving wrong result since function angle works in 2d plane. To receive correct result you would have to change drawing plane. Also to work with 3d your points need three coordinates i.e '(0 0 0). Otherwise mapcar will cut of z coordinate.  

If I understood your request you are looking for something like this.

Untitled.png

 

To calculate angle between points you need two vectors between three points. If you have single vector between two points then we talk about vector angles, and you have three components.

So if situation from image is your case, we have three points, p1 = 0,0,0 p2 = 10,10,10 p3 = 20,0,0. To calculate angle between vectors v1 = p2-p1 and v2 = p2-p3 function is

(setq p1 '(0 0 0))
(setq p2 '(10 10 10))
(setq p3 '(20 0 0))
(setq v1 (mapcar '- p2 p1))
(setq v2 (mapcar '' p2 p3))
(defun rad_to_deg (rad)(* 180.0 (/ rad pi)))

(defun angles_two_vect (v1 v2 / ang xa ya za xb yb zb acos asin)
(defun acos (x) (cond ((and(>= x -1.0)(<= x 1.0)) (-(* pi 0.5) (asin x)))))
(defun asin (x) (cond ((and(> x -1.0)(< x 1.0)) (atan (/ x (sqrt (- 1.0 (* x x)))))) ((= x -1.0) (* -1.0 (/ pi 2))) ((= x  1) (/ pi 2)) ) ) 
	(mapcar 'set '(xa ya za) v1)
	(mapcar 'set '(xb yb zb) v2)
	(setq ang 
		(acos 
			(/
				(+ (* xa xb)(* ya yb)(* za zb)) 
				(* (sqrt (+(* xa xa)(* ya ya)(* za za)))(sqrt (+(* xb xb)(* yb yb)(* zb zb))))
			)
		)
	)
	(if (< zb za) (setq ang (- (* pi 2.0) ang))) ; to test angle relative to horizontal vector in plane givs angle in full circle
	ang
)
Command: (rad_to_deg(angles_two_vect  v1  v2))
70.5288

Miljenko Hatlak

EESignature

Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.
0 Likes
Message 4 of 15

Browning_Zed
Advocate
Advocate

I tried both of these options, but it doesn't work in my case. The function still returns the wrong angle.

0 Likes
Message 5 of 15

Browning_Zed
Advocate
Advocate

Three points are needed to plot two vectors. But the routine I posted only returns two points. In addition, I need an angle in radians but not in degrees.

0 Likes
Message 6 of 15

Kent1Cooper
Consultant
Consultant

@Browning_Zed wrote:

....
3rd item - the angle between the first and second obtained points.

....


First question:  which angle?  As already pointed out, the (angle) function operates only in 2D.  From Help about it:

The angle is measured from the X axis of the current construction plane, in radians, with angles increasing in the counterclockwise direction. If 3D points are supplied, they are projected onto the current construction plane.

 

Between two points at different Z coordinates there are two angles -- the one in the XY plane and the one from the XY plane.  Draw a LINE with ends at different Z coordinates, and LIST it, or use DIST from end to end, to see both angles.  Which of those do you want, or do you mean something else?

Kent Cooper, AIA
0 Likes
Message 7 of 15

hak_vz
Advisor
Advisor

@Browning_Zed  Function angles_two_vect returns angle in vectors. Conversion to degrees is for easier checkup. @Kent1Cooper  has given you good explanation. Extract point from 3dpolyline and create angles between segments. If you want something else, post a sample drawing.

For two points you have vector between them you have three angle components, and you have to separate which one you want. You can check this post in regards vector calculus

 

Miljenko Hatlak

EESignature

Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.
0 Likes
Message 8 of 15

Kent1Cooper
Consultant
Consultant

@CADaSchtroumpf wrote:

Hi,

Try to change this?

(vlax-curve-getparamatpoint e (setq p (vlax-curve-getclosestpointto e (cadr s))))

by

(vlax-curve-getparamatpoint e (setq p (vlax-curve-getclosestpointto e (osnap (cadr s) "_near"))))

....


I think that has to be the key, somehow, because if done in the WCS, the Z coordinate of (cadr s) will be 0.0 whatever the Z coordinate of the 3DPolyline at the selection.  So the closest point to there on the 3DPolyline will often be somewhere else in XY terms, how far away depending on the configuration of it.

 

But I would think including both (getclosestpointto) and "nearest" Osnap is redundant -- this much should do the same:

 

(vlax-curve-getparamatpoint e (setq p (osnap (cadr s) "_near")))

 

Or maybe the (vlax-curve-getClosestPointToProjection) function would be in order?

 

(vlax-curve-getClosestPointToProjection e (cadr s) '(0 0 1))

 

Kent Cooper, AIA
0 Likes
Message 9 of 15

Browning_Zed
Advocate
Advocate

I need an angle in 2D projection. The angle value is the same can get using your function from this post.

0 Likes
Message 10 of 15

CADaSchtroumpf
Advisor
Advisor

Yes Kent you are right! Is redundant...

For my part, I would make simply this: return coordinate of vertex and angle always in WCS

(defun c:test ( / s e pt_sel pr pt_n pt_n+1 deriv alpha)
  (if (and (setq s (entsel)) (wcmatch (cdr (assoc 0 (entget (setq e (car s))))) "*POLYLINE"))
    (progn
      (setq
        pt_sel (osnap (cadr s) "_near")
        pr (vlax-curve-getparamatpoint e (trans pt_sel 1 0))
        pt_n (vlax-curve-getpointatparam e (fix pr))
        pt_n+1 (vlax-curve-getpointatparam e (1+ (fix pr)))
        deriv (vlax-curve-getfirstderiv e pr)
        alpha (atan (cadr deriv) (car deriv))
      )
      (princ (list pt_n pt_n+1 alpha))
    )
    (princ "\n Nothing selected or not a Polyline <!>")
  )
  (prin1)
)
0 Likes
Message 11 of 15

Kent1Cooper
Consultant
Consultant

@Browning_Zed wrote:

I need an angle in 2D projection. The angle value is the same can get using your function from this post.


Would

 

(list pt1 pt2 (angle b a))

 

work?  [Or maybe (angle a b) -- I haven't dug too deep into what's happening.]

Kent Cooper, AIA
0 Likes
Message 12 of 15

Browning_Zed
Advocate
Advocate

Thanks. Now the function returns the desired angle, but the order of points (items) in the list has changed. I need:
1st item - coordinates of the nearest vertex of the polyline relative to the picked location on the polyline
2nd item - coordinates of the second vertex of the picked polyline segment.

 

0 Likes
Message 13 of 15

Browning_Zed
Advocate
Advocate

This is the first thing I tried to do, but it returns the wrong angle.

0 Likes
Message 14 of 15

CADaSchtroumpf
Advisor
Advisor
Accepted solution

Reintroduce your condition !

(defun c:test ( / s e pt_sel pr pt_n pt_n+1 deriv alpha)
  (if (and (setq s (entsel)) (wcmatch (cdr (assoc 0 (entget (setq e (car s))))) "*POLYLINE"))
    (progn
      (setq
        pt_sel (osnap (cadr s) "_near")
        pr (vlax-curve-getparamatpoint e (trans pt_sel 1 0))
        pt_n (vlax-curve-getpointatparam e (fix pr))
        pt_n+1 (vlax-curve-getpointatparam e (1+ (fix pr)))
        deriv (vlax-curve-getfirstderiv e pr)
        alpha (atan (cadr deriv) (car deriv))
      )
      (if (< (distance pt_sel pt_n) (distance pt_sel pt_n+1))
        (princ (list pt_n pt_n+1 alpha))
        (princ (list pt_n+1 pt_n alpha))
      )
    )
    (princ "\n Nothing selected or not a Polyline <!>")
  )
  (prin1)
)

 

 

Message 15 of 15

Browning_Zed
Advocate
Advocate

Many thanks. Now it works as it should.

0 Likes