# TheSwamp

## Code Red => AutoLISP (Vanilla / Visual) => Topic started by: donnieworld on January 24, 2020, 02:21:32 PM

Title: vlax-curve-getClosestPointTo, vlax-curve-getDistatPoint Left or Right?
Post by: donnieworld on January 24, 2020, 02:21:32 PM
How can I determine if a point is left or right of a polyline. I'm creating a couple of station offset routines that are working pretty well. I am having trouble determining the side, left or right?

I am using vlax-curve-getClosestPointTo and vlax-curve-getDistatPoint to get the station and offset.
Title: Re: vlax-curve-getClosestPointTo, vlax-curve-getDistatPoint Left or Right?
Post by: Lee Mac on January 24, 2020, 03:30:51 PM
You could obtain the first derivative vector at the point returned by vlax-curve-getclosestpointto using the vlax-curve-getfirstderiv function, and then calculate the sign of the sine of the angle between your given point, the closest point and the first derivative vector from the closest point.
Title: Re: vlax-curve-getClosestPointTo, vlax-curve-getDistatPoint Left or Right?
Post by: Dlanor on January 24, 2020, 03:32:06 PM
You need to test the relation of the point to the polyline using one of the clockwise functions  HERE (https://www.theswamp.org/index.php?topic=46612.msg516186#msg516186)

Left and Right are determined by the direction the polyline was constructed

You need to feed it three points, your point, the closestto point and the next whole parameter point

Code - Auto/Visual Lisp: [Select]
1. ;;if ent is the polyline entity and i_pt is the point to test then
2.
3. ;; Using Gile's clockwise-p
4.
5.   (defun clockwise-p (p1 p2 p3)
6.       (- (* (- (car p2) (car p1)) (- (cadr p3) (cadr p1)))
7.          (* (- (car p3) (car p1)) (- (cadr p2) (cadr p1)))
8.       )
9.     )
10.   )
11.
12.   (setq i_pt .... ;;the point to test
13.         c_pt (vlax-curve-getclosestpointto ent i_pt)
14.         pt3 (vlax-curve-getpointatparam ent (1+ (fix (vlax-curve-getparamatpoint ent c_pt))))
15.   )
16.
17.   (if (clockwise-p i_pt c_pt pt3) (princ "Right") (princ "Left"))
18.
19.

I would also pre test that the point to be tested isn't on the polyline

Title: Re: vlax-curve-getClosestPointTo, vlax-curve-getDistatPoint Left or Right?
Post by: Lee Mac on January 24, 2020, 03:42:22 PM
You could obtain the first derivative vector at the point returned by vlax-curve-getclosestpointto using the vlax-curve-getfirstderiv function, and then calculate the sign of the sine of the angle between your given point, the closest point and the first derivative vector from the closest point.

In code, this might be:
Code - Auto/Visual Lisp: [Select]
1. (defun test ( ent pnt / cpt der )
2.     (setq cpt (vlax-curve-getclosestpointto ent pnt)
3.           der (vlax-curve-getfirstderiv ent (vlax-curve-getparamatpoint ent cpt))
4.     )
5.     (if (minusp (sin (- (angle cpt pnt) (angle '(0.0 0.0) der))))
6.         (princ "\nPoint is on the right.")
7.         (princ "\nPoint is on the left.")
8.     )
9.     (princ)
10. )
Code - Auto/Visual Lisp: [Select]
1. (defun c:test ( / ent pnt )
2.     (if (and (setq ent (car (entsel)))
3.              (setq pnt (getpoint "\nPoint: "))
4.         )
5.         (test ent (trans pnt 1 0))
6.     )
7.     (princ)
8. )
Title: Re: vlax-curve-getClosestPointTo, vlax-curve-getDistatPoint Left or Right?
Post by: donnieworld on January 25, 2020, 09:00:37 PM
Thanks to both of you for the help. Thanks Lee. I was able to easy implement your recommendation :-)

Title: Re: vlax-curve-getClosestPointTo, vlax-curve-getDistatPoint Left or Right?
Post by: dexus on June 23, 2022, 10:43:59 AM
You could obtain the first derivative vector at the point returned by vlax-curve-getclosestpointto using the vlax-curve-getfirstderiv function, and then calculate the sign of the sine of the angle between your given point, the closest point and the first derivative vector from the closest point.

In code, this might be:
Code - Auto/Visual Lisp: [Select]
1. (defun test ( ent pnt / cpt der )
2.     (setq cpt (vlax-curve-getclosestpointto ent pnt)
3.           der (vlax-curve-getfirstderiv ent (vlax-curve-getparamatpoint ent cpt))
4.     )
5.     (if (minusp (sin (- (angle cpt pnt) (angle '(0.0 0.0) der))))
6.         (princ "\nPoint is on the right.")
7.         (princ "\nPoint is on the left.")
8.     )
9.     (princ)
10. )
Code - Auto/Visual Lisp: [Select]
1. (defun c:test ( / ent pnt )
2.     (if (and (setq ent (car (entsel)))
3.              (setq pnt (getpoint "\nPoint: "))
4.         )
5.         (test ent (trans pnt 1 0))
6.     )
7.     (princ)
8. )
A couple of months ago I found a function which determines the side here: https://autocadtips1.com/2011/07/04/autolisp-offset-polyline-segments/
Stripped out all the lines I didn't need and ended up with 55 lines to calculate it.
With your example I can do it in 3 lines! So much easier.

Thank you so much Lee.
Title: Re: vlax-curve-getClosestPointTo, vlax-curve-getDistatPoint Left or Right?
Post by: Lee Mac on June 25, 2022, 11:17:42 AM
Good stuff! You're welcome  :-)
Title: Re: vlax-curve-getClosestPointTo, vlax-curve-getDistatPoint Left or Right?
Post by: Stefan on June 25, 2022, 07:04:18 PM
Hi all

The first deriv is not enough to clearly say a point is left or right.
If the angle of 2 consecutive segments is acute, then you might find an area wrongly reported.
The next test function check every point against the polyline.
Code - Auto/Visual Lisp: [Select]
1. (defun test ( ent pnt / cpt der )
2.     (setq cpt (vlax-curve-getclosestpointto ent pnt)
3.           der (vlax-curve-getfirstderiv ent (vlax-curve-getparamatpoint ent cpt))
4.     )
5.     (if
6.       (minusp (sin (- (angle cpt pnt) (angle '(0.0 0.0) der))))
7.       1;(princ "\nPoint is on the right.")
8.       3;(princ "\nPoint is on the left.")
9.     )
10. ;;;    (princ)
11. )
12.
13. (defun c:test ( / pl ss e c)
14.   (if
15.     (and
16.       (setq pl (car (entsel "\nSelect polyline: ")))
17.       (princ "\nSelect points: ")
18.       (setq ss (ssget "_:L" '((0 . "POINT"))))
19.     )
20.     (repeat (setq i (sslength ss))
21.       (setq e (ssname ss (setq i (1- i))))
22.       (if
23.         (setq c (test pl (cdr (assoc 10 (entget e)))))
24.         ;(setq c (left_right pl (cdr (assoc 10 (entget e)))))
25.           (list
26.             (cons -1 e)
27.             (cons 62 c)
28.           )
29.         )
30.       )
31.     )
32.   )
33.   (princ)
34. )
See the result in the image. Red points are on right side, green are on left.

I've changed left-right function a little bit, trying to solve any of these situations.
The idea is that, on corners, the first deriv is calculated as the bisector of the 2 neighbor segments direction.

Code - Auto/Visual Lisp: [Select]
1. (defun left_right ( e p / q a b c f )
2.           f (if
3.               (and
4.                 (equal c (fix c) 1e-8)
5.                 (or
6.                   (and
7.                     (not (equal a c 1e-8))
8.                     (not (equal b c 1e-8))
9.                   )
10.                 )
11.               )
12.               (mapcar '-
13.                  (polar q (angle '(0 0) (vlax-curve-getfirstderiv e (rem (+ c 1e-3) b))) 1.0)
14.                  (polar q (angle (vlax-curve-getfirstderiv e (rem (+ (- c 1e-3) b) b)) '(0 0)) 1.0)
15.               )
16.             )
17.     )
18.     (if
19.       (minusp (sin (- (angle q p) (angle '(0.0 0.0) f))))
20.       1;(princ "\nPoint is on the right.")
21.       3;(princ "\nPoint is on the left.")
22.     )
23. ;;;    (princ)
24. )
25.
Title: Re: vlax-curve-getClosestPointTo, vlax-curve-getDistatPoint Left or Right?
Post by: dexus on June 28, 2022, 03:29:13 AM
Thanks for the addition Stefan and what a great way of testing the function.

I noticed you can make a small change which doesn't change any of the calculations:
You can remove the last two "(setq f" parts because the value already is send back by the if function.
Title: Re: vlax-curve-getClosestPointTo, vlax-curve-getDistatPoint Left or Right?
Post by: Stefan on June 28, 2022, 04:41:50 AM
Thanks for the addition Stefan and what a great way of testing the function.

I noticed you can make a small change which doesn't change any of the calculations:
You can remove the last two "(setq f" parts because the value already is send back by the if function.

Done. Thanks