TheSwamp

Code Red => AutoLISP (Vanilla / Visual) => Topic started by: rayakmal on January 23, 2018, 03:12:53 PM

Title: Help. vlax-curve-getDistAtPoint Error (Real World Coordinate)
Post by: rayakmal on January 23, 2018, 03:12:53 PM
I need to find out a distance of a point from the start of a polyline by using vlax-curve-getDistAtPoint but always return nil. Please find the attached drawing, it's in real world coordinates (UTM) Autocad 2009. Is there a way to correct this situation? Thanks in advance.

(defun C:Try ( )
         
  (setq obj (vlax-ename->vla-object (car (entsel))))
  (setq pt1 (getpoint "\nSelect point: \n"))

  (setq stais (vlax-curve-getDistAtPoint obj pt1))

  (princ (strcat "\n. Station: " (rtos stais 2 3) " m"))
  (princ)
)
Title: Re: Help. vlax-curve-getDistAtPoint Error (Real World Coordinate)
Post by: ribarm on January 23, 2018, 03:46:00 PM
Code: [Select]
(defun C:Try ( / obj pt1 stais )
  (vl-load-com)
  (setq obj (vlax-ename->vla-object (car (entsel))))
  (setq pt1 (getpoint "\nSelect point: \n"))
  (setq stais (vlax-curve-getDistAtPoint obj (vlax-curve-getClosestPointTo obj (trans pt1 1 0))))
  (princ (strcat "\n. Station: " (rtos stais 2 3) " m"))
  (princ)
)

P.S. Use code tags : [ code ] Your code ... [/ code ] (inside [] no spaces...)
Title: Re: Help. vlax-curve-getDistAtPoint Error (Real World Coordinate)
Post by: rayakmal on January 23, 2018, 04:15:43 PM
Code: [Select]
(defun C:Try ( / obj pt1 stais )
  (vl-load-com)
  (setq obj (vlax-ename->vla-object (car (entsel))))
  (setq pt1 (getpoint "\nSelect point: \n"))
  (setq stais (vlax-curve-getDistAtPoint obj (vlax-curve-getClosestPointTo obj (trans pt1 1 0))))
  (princ (strcat "\n. Station: " (rtos stais 2 3) " m"))
  (princ)
)

Yay!!! Your code works. Thanks a lot.
Can you explain why I need to add (vlax-curve-getClosestPointTo obj (trans pt1 1 0)) ?

I still don't know how to utilize your code to fix my other Lisp routine, this time with my 2nd routine I wanna find a station of a point but the point IS not on a polyline. For instance, I need to find the station of a lamp post on a curb/sidewalk (not on the road centerline).

Here's my 2nd code. This routine will also return err if I use my attached drawing (I found out yesterday It only works if the UTM coordinates are not soo distant from 0,0)

Code: [Select]
(defun c:VIS-HOR-STAIS ( /  crvobj pt closestpt Stais)
  (vl-load-com)
  (setq crvobj (car (entsel "\n. Select Alignment: ")))
  (setq pt (getpoint "\n. Point: "))
  (setq closestpt (vlax-curve-getclosestpointto crvobj pt))
  (command "pline" pt closestpt "")
  (setq stais (vlax-curve-getDistAtPoint (vlax-ename->vla-object crvobj) closestpt))
  (princ (strcat "\n. Station: " (rtos stais 2 3) " m"))
  (princ)
)

I changed this line
  (setq closestpt (vlax-curve-getclosestpointto crvobj pt))
with
 (setq closestpt (vlax-curve-getclosestpointto crvobj (trans pt 1 0)))
still doesn't work.
Title: Re: Help. vlax-curve-getDistAtPoint Error (Real World Coordinate)
Post by: PKENEWELL on January 23, 2018, 05:14:00 PM

I still don't know how to utilize your code to fix my other Lisp routine, this time with my 2nd routine I wanna find a station of a point but the point IS not on a polyline. For instance, I need to find the station of a lamp post on a curb/sidewalk (not on the road centerline).

Here's my 2nd code. This routine will also return err if I use my attached drawing (I found out yesterday It only works if the UTM coordinates are not soo distant from 0,0)

Code: [Select]
(defun c:VIS-HOR-STAIS ( /  crvobj pt closestpt Stais)
  (vl-load-com)
  (setq crvobj (car (entsel "\n. Select Alignment: ")))
  (setq pt (getpoint "\n. Point: "))
  (setq closestpt (vlax-curve-getclosestpointto crvobj pt))
  (command "pline" pt closestpt "")
  (setq stais (vlax-curve-getDistAtPoint (vlax-ename->vla-object crvobj) closestpt))
  (princ (strcat "\n. Station: " (rtos stais 2 3) " m"))
  (princ)
)

I changed this line
  (setq closestpt (vlax-curve-getclosestpointto crvobj pt))
with
 (setq closestpt (vlax-curve-getclosestpointto crvobj (trans pt 1 0)))
still doesn't work.

For your 2nd question: Your need to convert the selected entity into a VLA object hence:
Code: [Select]
(setq obj (vlax-ename->vla-object (car (entsel)))) in ribarm's code.

change your line:
Code: [Select]
(setq crvobj (car (entsel "\n. Select Alignment: "))) to:
Code: [Select]
(setq crvobj (vlax-ename->vla-object (car (entsel "\n. Select Alignment: "))))
For your 1st question: (vlax-curve-getclosestpointto) ensures the selected point lies exactly on the curve with no fuzz error. When selecting using (entsel) the point the cursor picks may not be exactly on the curve. Also - (trans) converts the point from the current UCS to the WCS.

EDIT: Correction: Your not using the picked point in (entsel), but (getpoint). However - there may still be errors in the point location depending on object snap, etc.

That being said - your could shorten the picking by doing the following IF the object snap exact point is not needed (the user could still use an osnap override such as "nea" or "mid", etc.):
Code: [Select]
(if (setq sel (entsel "\nSelect Alignment at the point needed: "))
   (setq crvobj (vlax-ename->vlax-object (car sel))
            pt (cadr sel)
   )
)
Title: Re: Help. vlax-curve-getDistAtPoint Error (Real World Coordinate)
Post by: roy_043 on January 23, 2018, 05:42:37 PM
Two things:
1.
The vlax-curve-* functions also accept enames.
2.
To avoid unexpected results it can be a good idea to use (osnap pt "_nea") to ensure the selected point as actually on the entity before using vlax-curve-getclosestpointto.
Title: Re: Help. vlax-curve-getDistAtPoint Error (Real World Coordinate)
Post by: PKENEWELL on January 23, 2018, 06:03:19 PM
Two things:
1.
The vlax-curve-* functions also accept enames.
2.
To avoid unexpected results it can be a good idea to use (osnap pt "_nea") to ensure the selected point as actually on the entity before using vlax-curve-getclosestpointto.

1. Interesting - I did not realize that. guess I should read up on those a bit more. Makes me wonder what problem the OP is having then. Might be better just to have a sample drawing to work with.

2. I agree.
Title: Re: Help. vlax-curve-getDistAtPoint Error (Real World Coordinate)
Post by: rayakmal on January 23, 2018, 06:44:45 PM

Two things:
1. Interesting - I did not realize that. guess I should read up on those a bit more. Makes me wonder what problem the OP is having then. Might be better just to have a sample drawing to work with.

2. I agree.

The 1st problem was solved (Picked point is on the polyline). The 2nd problem is different, this time I pick a point not on the polyline, let's say 3 units away from the polyline and I need to find its station (projected to the polyline).
Title: Re: Help. vlax-curve-getDistAtPoint Error (Real World Coordinate)
Post by: PKENEWELL on January 24, 2018, 01:20:42 AM
The 2nd problem is different, this time I pick point not on the polyline, let's say 3 units away from the polyline and I need to find its station (projected to the polyline).

OK. A bit more information is needed then. What is the projection vector to the selected curve? Perpendicular (the closest point)? Orthographic? Nearest Vertex?

An idea for coding this to the perpendicular would be to get the closest intersect point perpendicular to the segment (note: I'm doing this without being able to test at the moment - so forgive any typos):

Code: [Select]
;; untested snippet
(if (and
         (setq sel (entsel "\nSelect Alignment: "))
         (setq  pt (getpoint "\nSelect Point: "))
   )
   (setq spt1 (osnap (cadr sel) "nea") ; get the nearest point to the entity pick
         spt2 (osnap spt1 "end") ; get the nearest endpoint to the entity pick
          ang (angle spt1 spt2) ; determine the angle of the segment
          int (inters spt1 spt2 pt (polar pt (+ ang (/ pi 2)) 1.0) nil) ; get the intersection with the point and the curve, at perp. angle.
          int (if (osnap int "nea") int spt2) ; If no intersection is found, set to the nearest endpoint found. NOTE this requires the user to select the curve at a location nearest to the projection.
          ent (car sel)
        stais (vlax-curve-getDistAtPoint ent (vlax-curve-getClosestPointTo ent (trans int 1 0)))
   )
)

This method would require the user to select the curve segment (and hence the point on the segment from "(cadr sel)") as close to the projection point as possible. It's late so I'll test this out tomorrow. Might be a better way to do this, but it is to much code than I have time for at the moment.

EDIT: Tested this and found a couple mistakes so I updated the code. Seems to work OK now.

EDIT2: Removed an extra parenthesis
Title: Re: Help. vlax-curve-getDistAtPoint Error (Real World Coordinate)
Post by: ribarm on January 24, 2018, 07:37:22 AM
@PKENEWELL

(polar) function needs 3 arguments : reference point, angle in radians and distance from point... You forgot to supply distance...
Title: Re: Help. vlax-curve-getDistAtPoint Error (Real World Coordinate)
Post by: PKENEWELL on January 24, 2018, 09:34:51 AM
@PKENEWELL

(polar) function needs 3 arguments : reference point, angle in radians and distance from point... You forgot to supply distance...

Thanks Mario. I was up too late last night doing that. Corrected.
Title: Re: Help. vlax-curve-getDistAtPoint Error (Real World Coordinate)
Post by: rayakmal on January 24, 2018, 05:56:27 PM
Thanks a lot Guys.
Sorry for the late reply. I'll test your code and let you know.
Btw. "Projected" = the closest distance to a polyline (and I always work with 2D Polyline).
Title: Re: Help. vlax-curve-getDistAtPoint Error (Real World Coordinate)
Post by: rayakmal on January 25, 2018, 08:36:08 AM

OK. A bit more information is needed then. What is the projection vector to the selected curve? Perpendicular (the closest point)? Orthographic? Nearest Vertex?

An idea for coding this to the perpendicular would be to get the closest intersect point perpendicular to the segment (note: I'm doing this without being able to test at the moment - so forgive any typos):

Code: [Select]
;; untested snippet
(if (and
         (setq sel (entsel "\nSelect Alignment: "))
         (setq  pt (getpoint "\nSelect Point: "))
   )
   (setq spt1 (osnap (cadr sel) "nea") ; get the nearest point to the entity pick
         spt2 (osnap spt1 "end") ; get the nearest endpoint to the entity pick
          ang (angle spt1 spt2) ; determine the angle of the segment
          int (inters spt1 spt2 pt (polar pt (+ ang (/ pi 2)) 1.0) nil) ; get the intersection with the point and the curve, at perp. angle.
          int (if (osnap int "nea") int spt2) ; If no intersection is found, set to the nearest endpoint found. NOTE this requires the user to select the curve at a location nearest to the projection.
          ent (car sel)
        stais (vlax-curve-getDistAtPoint ent (vlax-curve-getClosestPointTo ent (trans int 1 0))))
   )
)

This method would require the user to select the curve segment (and hence the point on the segment from "(cadr sel)") as close to the projection point as possible. It's late so I'll test this out tomorrow. Might be a better way to do this, but it is to much code than I have time for at the moment.

EDIT: Tested this and found a couple mistakes so I updated the code. Seems to work OK now.

I tried your code with my drawing, it won't work. Thanks anyway, I appreciate your help.

Here's I attached a new drawing to illustrate what I'm trying to accomplished with the 2nd code, what I want is to find the stations of sign posts along the road.
Title: Re: Help. vlax-curve-getDistAtPoint Error (Real World Coordinate)
Post by: PKENEWELL on January 26, 2018, 05:12:12 PM
I tried your code with my drawing, it won't work. Thanks anyway, I appreciate your help.

Here's I attached a new drawing to illustrate what I'm trying to accomplished with the 2nd code, what I want is to find the stations of sign posts along the road.

Hmmm . I opened you test drawing and chose a location about @ approx. 290 and below your alignment. The code returned a value of 291.083, which is correct to where I approximately picked. Then I stared a LINE using (command "._line" "_non" int pause) and it gave me the location I wanted. Are you sure you are using it correctly?
Title: Re: Help. vlax-curve-getDistAtPoint Error (Real World Coordinate)
Post by: PKENEWELL on January 26, 2018, 05:25:10 PM
I tried your code with my drawing, it won't work. Thanks anyway, I appreciate your help.

Here's I attached a new drawing to illustrate what I'm trying to accomplished with the 2nd code, what I want is to find the stations of sign posts along the road.

Hmmm . I opened you test drawing and chose a location about @ approx. 290 and below your alignment. The code returned a value of 291.083, which is correct to where I approximately picked. Then I stared a LINE using (command "._line" "_non" int pause) and it gave me the location I wanted. Are you sure you are using it correctly?

OOPS OK. I discovered I have an extra Parenthesis in my code, but somehow it was still working when I copied and pasted the snippet. I have corrected my above code.

Here - I have written a new version of your function:
Code: [Select]
(defun c:VIS-HOR-STAIS ( /  sel pt spt1 spt2 ang int ent stais)
   (vl-load-com)
   (if (and
         (setq sel (entsel "\nSelect Alignment: "))
         (setq  pt (getpoint "\nSelect Point: "))
      )
      (setq spt1 (osnap (cadr sel) "nea") ; get the nearest point to the entity pick
            spt2 (osnap spt1 "end") ; get the nearest endpoint to the entity pick
             ang (angle spt1 spt2) ; determine the angle of the segment
             int (inters spt1 spt2 pt (polar pt (+ ang (/ pi 2)) 1.0) nil) ; get the intersection with the point and the curve, at perp. angle.
             int (if (osnap int "nea") int spt2) ; If no intersection is found, set to the nearest endpoint found. NOTE this requires the user to select the curve at a location nearest to the projection.
             ent (car sel)
           stais (vlax-curve-getDistAtPoint ent (vlax-curve-getClosestPointTo ent (trans int 1 0)))
      )
   )
   (command "._line" "_non" int "_non" (polar int (+ ang (* pi 1.5)) (distance pt int)) "")
   (princ (strcat "\n. Station: " (rtos stais 2 3) " m"))
   (princ)
)

Give this a try - should work.

EDIT: I updated the line command so it connects a line back to the picked point.
Title: Re: Help. vlax-curve-getDistAtPoint Error (Real World Coordinate)
Post by: rayakmal on January 27, 2018, 12:10:58 AM
OOPS OK. I discovered I have an extra Parenthesis in my code, but somehow it was still working when I copied and pasted the snippet. I have corrected my above code.

Here - I have written a new version of your function:
Code: [Select]
(defun c:VIS-HOR-STAIS ( /  sel pt spt1 spt2 ang int ent stais)
   (vl-load-com)
   (if (and
         (setq sel (entsel "\nSelect Alignment: "))
         (setq  pt (getpoint "\nSelect Point: "))
      )
      (setq spt1 (osnap (cadr sel) "nea") ; get the nearest point to the entity pick
            spt2 (osnap spt1 "end") ; get the nearest endpoint to the entity pick
             ang (angle spt1 spt2) ; determine the angle of the segment
             int (inters spt1 spt2 pt (polar pt (+ ang (/ pi 2)) 1.0) nil) ; get the intersection with the point and the curve, at perp. angle.
             int (if (osnap int "nea") int spt2) ; If no intersection is found, set to the nearest endpoint found. NOTE this requires the user to select the curve at a location nearest to the projection.
             ent (car sel)
           stais (vlax-curve-getDistAtPoint ent (vlax-curve-getClosestPointTo ent (trans int 1 0)))
      )
   )
   (command "._line" "_non" int "_non" (polar int (+ ang (* pi 1.5)) (distance pt int)) "")
   (princ (strcat "\n. Station: " (rtos stais 2 3) " m"))
   (princ)
)

Give this a try - should work.

EDIT: I updated the line command so it connects a line back to the picked point.


YES, it works if I pick a point near a tangent (a straight line) but when I pick a point near a curve, it won't.
Title: Re: Help. vlax-curve-getDistAtPoint Error (Real World Coordinate)
Post by: PKENEWELL on January 27, 2018, 11:22:07 PM
Well. I've been playing around with this bit of code to correct the issue with arced segments. It ALMOST works. That is - it finds the correct intersect point on a polyline with straight and arc segments (evidenced by the line drawn). However - for some reason the curve distance is not always returned, but works only intermittently. I cannot figure out why yet.

Code: [Select]
(defun c:VIS-HOR-STAIS ( /  sel pt spt1 spt2 ang rad pds int ent stais)
   (vl-load-com)
   (if (and
          (setq sel (entsel "\nSelect Alignment: "))
          (setq  pt (getpoint "\nSelect Point: "))
       )
      (if (setq spt1 (osnap (cadr sel) "cen")) ; If it's an arc segment in the polyline
         (setq  rad  (distance (osnap (cadr sel) "nea") spt1)
                ang  (angle pt spt1)
                pds  (- (distance pt spt1) rad)
                int  (polar pt ang pds)
                int  (if (osnap int "nea") (osnap int "nea") (polar pt ang (+ (distance pt spt1) rad)))
                ent  (car sel)
               stais (vlax-curve-getDistAtPoint ent (vlax-curve-getClosestPointTo ent (trans int 1 0)))
         )
         (setq spt1 (osnap (cadr sel) "nea") ; get the nearest point to the entity pick
               spt2 (osnap spt1 "end") ; get the nearest endpoint to the entity pick
               ang  (angle spt1 spt2) ; determine the angle of the segment.
               ; get the intersection with the point and the curve, at perp. angle.
               int  (inters spt1 spt2 pt (polar pt (+ ang (/ pi 2)) 1.0) nil)
               int  (if (osnap int "nea") int spt2) ; If no object is found at the int, set to the nearest endpoint found.
               ent  (car sel)
              stais (vlax-curve-getDistAtPoint ent (vlax-curve-getClosestPointTo ent (trans int 1 0)))
         )
      )
   )
   (command "._line" "_non" int "_non" pt "")
   (if stais
       (princ (strcat "\n. Station: " (rtos stais 2 3) " m"))
       (princ "\nError: Distance not found.")
   )
   (princ)
)

I know there are probably more complicated and reliable ways to do this, but I was attempting to keep it simple. I'm sorry but I don't have the knowledge to write anything more complex in a reasonable time. :-( Perhaps one of the other Guru's here could write something faster than I could, or figure out why my above code is not getting the curve distance reliably.
Title: Re: Help. vlax-curve-getDistAtPoint Error (Real World Coordinate)
Post by: rayakmal on January 28, 2018, 01:48:21 AM
Well. I've been playing around with this bit of code to correct the issue with arced segments. It ALMOST works. That is - it finds the correct intersect point on a polyline with straight and arc segments (evidenced by the line drawn). However - for some reason the curve distance is not always returned, but works only intermittently. I cannot figure out why yet.

I know there are probably more complicated and reliable ways to do this, but I was attempting to keep it simple. I'm sorry but I don't have the knowledge to write anything more complex in a reasonable time. :-( Perhaps one of the other Guru's here could write something faster than I could, or figure out why my above code is not getting the curve distance reliably.

No worry and don't be sorry, buddy. Your help is very much appreciated.

I know AutoCAD behaves differently under this circumstances. Try to move any object on the testing drawing to 0,0, they won't move. Also you can try to copy, it won't work either. I tried several visual Lisp routine from John Burke and Lee Mac (*Polyline routine), their codes don't always work either. In this situation, where the real world coordinates are so big, I was forced to re-wrote my codes back to the 'standard lisp', involved some geometry, but I found out it's more robust and dependable. Once again, thanks for all your help.
Title: Re: Help. vlax-curve-getDistAtPoint Error (Real World Coordinate)
Post by: rayakmal on January 31, 2018, 10:08:27 AM
I think I've found the cuplrit. If I convert the Polyline into LwPolyline, no more error in my code.
Title: Re: Help. vlax-curve-getDistAtPoint Error (Real World Coordinate)
Post by: PKENEWELL on January 31, 2018, 10:16:11 AM
I think I've found the cuplrit. If I convert the Polyline into LwPolyline, no more error in my code.

Excellent. Yes - I just tested the code again after converting and it works perfectly. Great Catch!

Still is a bit annoying however that the "vlax-curve.." functions do not work consistently with Heavy Polylines.