Author Topic: vlax-curve-getClosestPointTo, vlax-curve-getDistatPoint Left or Right?  (Read 1578 times)

0 Members and 1 Guest are viewing this topic.

donnieworld

  • Mosquito
  • Posts: 20
  • Moving from AutoCAD to BricsCAD
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.
Donald Broussard
Hunsaker & Associates San Diego

Lee Mac

  • Seagull
  • Posts: 12696
  • London, England
Re: vlax-curve-getClosestPointTo, vlax-curve-getDistatPoint Left or Right?
« Reply #1 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.

Dlanor

  • Bull Frog
  • Posts: 263
Re: vlax-curve-getClosestPointTo, vlax-curve-getDistatPoint Left or Right?
« Reply #2 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

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.     (minusp
  7.       (- (* (- (car p2) (car p1)) (- (cadr p3) (cadr p1)))
  8.          (* (- (car p3) (car p1)) (- (cadr p2) (cadr p1)))
  9.       )
  10.     )
  11.   )
  12.  
  13.   (setq i_pt .... ;;the point to test
  14.         c_pt (vlax-curve-getclosestpointto ent i_pt)
  15.         pt3 (vlax-curve-getpointatparam ent (1+ (fix (vlax-curve-getparamatpoint ent c_pt))))
  16.   )
  17.  
  18.   (if (clockwise-p i_pt c_pt pt3) (princ "Right") (princ "Left"))
  19.  
  20.  

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

 
« Last Edit: January 24, 2020, 03:36:38 PM by Dlanor »

Lee Mac

  • Seagull
  • Posts: 12696
  • London, England
Re: vlax-curve-getClosestPointTo, vlax-curve-getDistatPoint Left or Right?
« Reply #3 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. )

donnieworld

  • Mosquito
  • Posts: 20
  • Moving from AutoCAD to BricsCAD
Re: vlax-curve-getClosestPointTo, vlax-curve-getDistatPoint Left or Right?
« Reply #4 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 :-)

Donald Broussard
Hunsaker & Associates San Diego

dexus

  • Newt
  • Posts: 75
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.

Lee Mac

  • Seagull
  • Posts: 12696
  • London, England
Good stuff! You're welcome  :-)

Stefan

  • Bull Frog
  • Posts: 303
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.         (entmod
  26.           (list
  27.             (cons -1 e)
  28.             (cons 62 c)
  29.           )
  30.         )
  31.       )
  32.     )
  33.   )
  34.   (princ)
  35. )
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.           a (vlax-curve-getstartparam e)
  3.           b (vlax-curve-getendparam e)
  4.           c (vlax-curve-getparamatpoint e q)
  5.           f (if
  6.               (and
  7.                 (equal c (fix c) 1e-8)
  8.                 (or
  9.                   (vlax-curve-isclosed e)
  10.                   (and
  11.                     (not (equal a c 1e-8))
  12.                     (not (equal b c 1e-8))
  13.                   )
  14.                 )
  15.               )
  16.               (mapcar '-
  17.                  (polar q (angle '(0 0) (vlax-curve-getfirstderiv e (rem (+ c 1e-3) b))) 1.0)
  18.                  (polar q (angle (vlax-curve-getfirstderiv e (rem (+ (- c 1e-3) b) b)) '(0 0)) 1.0)
  19.               )
  20.               (vlax-curve-getfirstderiv e c)
  21.             )
  22.     )
  23.     (if
  24.       (minusp (sin (- (angle q p) (angle '(0.0 0.0) f))))
  25.       1;(princ "\nPoint is on the right.")
  26.       3;(princ "\nPoint is on the left.")
  27.     )
  28. ;;;    (princ)
  29. )
  30.  
« Last Edit: June 28, 2022, 04:41:12 AM by Stefan »

dexus

  • Newt
  • Posts: 75
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.

Stefan

  • Bull Frog
  • Posts: 303
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