Author Topic: Closest point to Polyline vertice  (Read 5742 times)

0 Members and 1 Guest are viewing this topic.

Tharwat

  • Swamp Rat
  • Posts: 707
  • Hypersensitive
Closest point to Polyline vertice
« on: July 01, 2011, 04:17:20 PM »
Hello everyone .

I looking forward to get the closest point (vertices of the selected polyline) to the one that I selected on a polyline entity .

Code: [Select]
(setq pol (entsel "\n select polyline :"))
(setq vla-obj (vlax-ename->vla-object (car pol)))
(setq p1 (vlax-curve-getclosestpointto vla-obj (cadr pol)))

So how can I get the point of the polyline that is the closest ?

many thanks.

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: Closest point to Polyline vertice
« Reply #1 on: July 01, 2011, 04:34:04 PM »
Hi,

vlax-curve-getClosestPointTo  returns the closest point on the curve to the specified point.

If you want the closest polyline vertex to this point, you can use the polyline parameters:

Code: [Select]
(defun gc:GetClosestVertexTo (pl pt / pa)
  (setq pa (vlax-curve-getParamAtPoint
     pl
     (vlax-curve-getClosestPointTo pl pt)
   )
  )
  (if (< (rem pa 1) 0.5)
    (vlax-curve-getPointAtParam pl (fix pa))
    (vlax-curve-getPointAtParam pl (1+ (fix pa)))
  )
)

Note: the vlax-curve-* functions work with both enames or vla-objects
Speaking English as a French Frog

BlackBox

  • King Gator
  • Posts: 3770
Re: Closest point to Polyline vertice
« Reply #2 on: July 01, 2011, 04:43:08 PM »
Gile beat me to it.  :-(

Here's what I had:

Code: [Select]
(defun c:GetClosestPointTo ( / ss pt)
  (vl-load-com)
  (if (and (setq ss (ssget "_:L:S:E" '((0 . "LINE,*POLYLINE"))))
           (setq pt (getpoint "\nSpecifiy point: ")))
    (setq pt (vlax-curve-getclosestpointto (vlax-ename->vla-object (ssname ss 0)) pt T))
  (cond (ss (prompt "\n** Invalid point ** "))
        ((prompt "\n** Nothing selected ** "))))
  (print pt)
  (princ))
"How we think determines what we do, and what we do determines what we get."

BlackBox

  • King Gator
  • Posts: 3770
Re: Closest point to Polyline vertice
« Reply #3 on: July 01, 2011, 04:48:20 PM »
Technically, this line:

Code: [Select]
    (setq pt (vlax-curve-getclosestpointto (vlax-ename->vla-object (ssname ss 0)) pt T))

... Can be changed to this, and still work just the same:

Code: [Select]
    (setq pt (vlax-curve-getclosestpointto (ssname ss 0) pt T))

LoL
"How we think determines what we do, and what we do determines what we get."

Lee Mac

  • Seagull
  • Posts: 12905
  • London, England
Re: Closest point to Polyline vertice
« Reply #4 on: July 01, 2011, 05:35:32 PM »
My variant:

Code: [Select]
(defun LM:GetClosestVertexTo ( pl pt )
  (vlax-curve-getpointatparam pl
    (fix
      (+ 0.5
        (vlax-curve-getparamatpoint pl
          (vlax-curve-getclosestpointto pl pt)
        )
      )
    )
  )
)

highflyingbird

  • Bull Frog
  • Posts: 415
  • Later equals never.
Re: Closest point to Polyline vertice
« Reply #5 on: July 01, 2011, 08:26:19 PM »
I think  :  ClosetVertexTo is not equal to ClosetPointTo
so here is my code:

Code: [Select]
(vl-load-com)
(defun GetClosestVertexTo (pline pt / endpar i minD p d pMin)
  (setq endpar (vlax-curve-getEndParam pline))           
  (setq i 0.0)
  (setq minD 1e308)
  (if (vlax-curve-isClosed pline)
    (setq n (fix endpar))
    (setq n (1+ (fix endpar)))
  )
  (repeat n
    (setq p (vlax-curve-getPointAtParam pline i))
    (setq d (distance p pt))
    (if (< d minD)
      (setq minD d pMin p)
    )
    (setq i (1+ i))
  )
  pMin
)
;;;for test
(defun c:test(/ sel cur pCV ret pnt)
  (prompt "\nPick a polyline(2D or 3D):")
  (if (and (setq sel (ssget ":E:S" '((0 . "*POLYLINE"))))
   (setq pnt (getpoint  "\nSpecify a point:"))
      )
    (setq cur (ssname sel 0)
  pCV (GetClosestVertexTo cur pnt)
  ret (entmake (list '(0 . "LINE") (cons 10 pnt) (cons 11 pCV)))
    )
  )
)

did I misunderstand?
« Last Edit: July 02, 2011, 07:25:43 AM by HighflyingBird »
I am a bilingualist,Chinese and Chinglish.

Lee Mac

  • Seagull
  • Posts: 12905
  • London, England
Re: Closest point to Polyline vertice
« Reply #6 on: July 02, 2011, 07:32:27 AM »
I think  :  ClosetVertexTo is not equal to ClosetPointTo

Correct, the ClosestVertex will not always be the ClosestPoint, however, the methods implemented by gile and I are correct since there are effectively four cases to consider:

1) Trivial Case in which the vertex is the closest point, i.e. the Parameter of the Closest Point is an Integer and no rounding occurs.

2) The Closest Point lies above the midpoint of the Polyline Segment, and hence the Parameter at that point is greater than a half and will be rounded up (Polyline Segment shown in Green, Arbitrary Point shown in Cyan):



3) The Closest Point lies below the midpoint of the Polyline Segment, and hence the Parameter at that point is less than a half and will be rounded down:



4) The Closest Point lies on the midpoint of the Polyline Segment, and hence the Parameter at that point is equal to a half and, by rounding convention, will be rounded up:



highflyingbird

  • Bull Frog
  • Posts: 415
  • Later equals never.
Re: Closest point to Polyline vertice
« Reply #7 on: July 02, 2011, 07:44:16 AM »
Maybe I didn't get Tharwat's meaning.


take a look at this picture:
I am a bilingualist,Chinese and Chinglish.

highflyingbird

  • Bull Frog
  • Posts: 415
  • Later equals never.
Re: Closest point to Polyline vertice
« Reply #8 on: July 02, 2011, 08:14:45 AM »
Like this? :
Sorry for my poor English.
Code: [Select]
(defun GetClosestVertexToPline (pline1 pline2 / endpar n i minD p q d pMin qMin)
  (setq endpar (vlax-curve-getEndParam pline1))           
  (setq i 0.0)
  (setq minD 1e308)
  (if (vlax-curve-isClosed pline1)
    (setq n (fix endpar))
    (setq n (1+ (fix endpar)))
  )
  (repeat n
    (setq p (vlax-curve-getPointAtParam pline1 i))
    (setq q (vlax-curve-getclosestpointto pline2 p))
    (setq d (distance p q))
    (if (< d minD)
      (setq minD d pMin p qMin q)
    )
    (setq i (1+ i))
  )
  (list pMin qMin)
)
;;;for test
(defun c:doit(/ ss1 ss2 pline1 pline2 ret pairPt)
  (prompt "\nPick a polyline(2D or 3D):")
  (if (and (setq ss1 (ssget ":E:S" '((0 . "*POLYLINE"))))
   (setq ss2 (ssget ":E:S" '((0 . "*POLYLINE"))))
      )
    (setq pline1 (ssname ss1 0)
  pline2 (ssname ss2 0)
  pairPt (GetClosestVertexToPline pline1 pline2)
  ret (entmake (list '(0 . "LINE") (cons 10 (car pairPt)) (cons 11 (cadr pairPt))))
    )
  )
)
I am a bilingualist,Chinese and Chinglish.

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: Closest point to Polyline vertice
« Reply #9 on: July 02, 2011, 09:07:39 AM »
You're right HighflyingBird.

This should work in your picture example:

Functional style
Code: [Select]
(defun gc:GetPolylineVertices (pl / foo)
  (defun foo (p n a)
    (if (zerop n)
      (cons (vlax-curve-getPointAtParam pl 0) a)
      (foo p (1- n) (cons (vlax-curve-getPointAtParam p n) a))
    )
  )
  (foo pl
       (fix (if (vlax-curve-isClosed pl)
      (1- (vlax-curve-getendParam pl))
      (vlax-curve-getendParam pl)
    )
       )
       nil
  )
)

(defun gc:GetClosestVertex (pl pt / foo)
  (defun foo (l v d)
    (if l
      ((lambda (x)
(if (< d x)
   (foo (cdr l) v d)
   (foo (cdr l) (car l) x)
)
       )
(distance (car l) pt)
      )
      v
    )
  )
  ((lambda (l)
     (foo (cdr l) (car l) (distance (car l) pt))
   )
    (gc:GetPolylineVertices pl)
  )
)

Imperative style
Code: [Select]
(defun gc:GetPolylineVertices (pl / n p l)
  (setq n (fix (vlax-curve-getEndParam pl)))
  (or (vlax-curve-IsClosed pl) (setq n (1+ n)))
  (while (setq p (vlax-curve-getPointAtParam pl (setq n (1- n))))
    (setq l (cons p l))
  )
)

(defun gc:GetClosestVertex (pl pt / l v d)
  (setq l (gc:GetPolylineVertices pl)
v (car l)
d (distance v pt)
  )
  (foreach x (cdr l)
    (if (< (distance (car l) pt) d)
      (setq v (car l)
    d (distance (car l) pt)
      )
    )
  )
  v
)

But it seems to me that Tharwat was talking about a point on (or very closed to) the selected polyline:
(vlax-curve-getclosestpointto vla-obj (cadr pol))
where pol is a list returned by entsel.

If that, this can be done using the osnap function too:
Code: [Select]
(setq pol (entsel))
(setq pl (car pol))
(setq pt (trans (osnap (cadr pol) "_nea") 1 0))
(setq closestVetex
       (vlax-curve-getPointAtParam
pl
(fix (+ 0.5 (vlax-curve-getParamAtPoint pl pt)))
       )
)

Speaking English as a French Frog

Lee Mac

  • Seagull
  • Posts: 12905
  • London, England
Re: Closest point to Polyline vertice
« Reply #10 on: July 02, 2011, 09:29:23 AM »
Maybe I didn't get Tharwat's meaning.

Ah! I see what you were referring to - I hadn't considered that case  :|

But it seems to me that Tharwat was talking about a point on (or very closed to) the selected polyline:
(vlax-curve-getclosestpointto vla-obj (cadr pol))
where pol is a list returned by entsel.

^ This is how I understood it  :-)

Tharwat

  • Swamp Rat
  • Posts: 707
  • Hypersensitive
Re: Closest point to Polyline vertice
« Reply #11 on: July 02, 2011, 10:54:28 AM »
Perfect work Gentlemen . :kewl:

All of you are correct , gile , Renderman, and Lee gave me the perfect example about how to do it , but HighFlyBird
gave me the example that I wanted in a very excellent way too .

The solution that was given by Highflybird were considered my second question after getting opinions if the following code would work
or not because I had doubts that the (cadr (entsel "\n select polyline:")) may not be considered as the correct point
Code: [Select]
(setq pol (entsel "\n select polyline :"))
(setq p1 (vlax-curve-getclosestpointto vla-obj [b](cadr pol)[/b]))

Thank you all , Highly appreciated .

Lee Mac

  • Seagull
  • Posts: 12905
  • London, England
Re: Closest point to Polyline vertice
« Reply #12 on: July 02, 2011, 11:01:09 AM »
Consider using:

Code: [Select]
(if (setq sel (entsel))
  (setq pt (vlax-curve-getclosestpointto (car sel) (trans (cadr sel) 1 0)))
)

Since the vlax-curve* functions work much faster with entities than VLA-Objects, and furthermore the point returned by entsel is defined relative to the UCS, whereas the point argument for vlax-curve-getclosestpointto is defined relative to WCS.