Author Topic: Minimum distance between two vlax-curve objects  (Read 42167 times)

0 Members and 2 Guests are viewing this topic.

VovKa

  • Water Moccasin
  • Posts: 1621
  • Ukraine
Re: Minimum distance between two vlax-curve objects
« Reply #30 on: May 22, 2008, 04:47:09 PM »
the weakest link in Alan's code is (setq step (/ len 1000)), to eleminate this i suggest stealing Joe's idea like this:
Code: [Select]
(defun 2ObjDist (obj1 obj2 pt / p d fuzz)
  (setq fuzz 1E-8)
  (while (not
   (minusp
     (- (distance pt (setq p (vlax-curve-GetClosestPointTo obj2 pt)))
(setq d (distance p (setq pt (vlax-curve-GetClosestPointTo obj1 p))))
fuzz
     )
   )
)
  )
  (list d pt p)
)
and placing it...
Code: [Select]
(t
     (while (and (<= idx len)
                 (setq p1 (vlax-curve-getpointatdist e1 idx))
                 (setq p2 (vlax-curve-getclosestpointto e2 p1))
            )
       (setq dis (distance p1 p2)
             idx  (+ idx step)
       )
       (if (or (null dlst) (< dis (car dlst)))
         (setq dlst (list dis p1 p2))
       )             
     )
     (setq dlst (2ObjDist e1 e2 (cadr dlst)));<----------- right here
     (if (and dlst (listp dlst))
       (grdraw (trans (cadr dlst)0 1)(trans (caddr dlst)0 1) 6 1)
     )
    )

Joe Burke

  • Guest
Re: Minimum distance between two vlax-curve objects
« Reply #31 on: May 23, 2008, 06:17:06 AM »
This is my version 2. Added grdraw

Alan,

I noticed a minor problem with your code. I'd suggest this change at the end.

;  (print dis)
  (print (car dlst))

While testing with two full ellipses I found it would return the right answer only if I picked the objects in a certain order. In the opposite order the answer was very different.

Joe Burke

  • Guest
Re: Minimum distance between two vlax-curve objects
« Reply #32 on: May 23, 2008, 06:26:45 AM »
more AI should be employed

VovKa,

Thanks for the example. Agreed, my latest code doesn't fix that one.

Joe Burke

  • Guest
Re: Minimum distance between two vlax-curve objects
« Reply #33 on: May 23, 2008, 06:43:23 AM »
the weakest link in Alan's code is (setq step (/ len 1000)), to eleminate this i suggest stealing Joe's idea like this:

VovKa,

I tried your function within Alan's code. Given the two ellipses example, I see a 5% increase in accuracy.

Thank you for your keen insights into the issues involved.

I think I'm going to have to do something similar to Alan's approach to ensure the correct point is passed to the function which sharpens accuracy with irregular curves like splines and ellipses.

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Re: Minimum distance between two vlax-curve objects
« Reply #34 on: May 23, 2008, 09:45:08 AM »
OK here is version 3 with the 2ObjDist subroutine.
Great subroutine by the way. Who get the credit for it? 8-)
Code: [Select]
;; CAB @ TheSwamp.org - 5/23/2008
;; Version 3
;; Returns the minimum distance between two objects.
;; Supported object types: any vlax-curve object
;;
(defun c:MD() (c:MinDist))
(defun c:MinDist (/ step e1 e2 p1 p2 len idx dis dlst
               curveOK getent)
  (vl-load-com)
  ;;  CAB test to see if vlax-curve can be used on an object
  (defun curveOK (ent) ; returns nil if not allowed
    (not (vl-catch-all-error-p
           (vl-catch-all-apply 'vlax-curve-getendparam (list ent))
         )
    )
  )
  ;; returns an entity which can be used with vlax-curve
  (defun getent (pmt / ent)
    (while (not (and (setq ent (car (entsel pmt)))
                (curveOK ent)
           ))
      (prompt "\nMissed or not a Curve object. Try again.")
    )
    ent
  )
  ;;  get the min distance between 2 objects nearest to pt
  ;;  pt should be a point on obj1
  (defun 2ObjDist (obj1 obj2 pt / p d fuzz)
    (setq fuzz 1E-8)
    (while (not
     (minusp
       (- (distance pt (setq p (vlax-curve-GetClosestPointTo obj2 pt)))
  (setq d (distance p (setq pt (vlax-curve-GetClosestPointTo obj1 p))))
  fuzz
       )
     )
  )
    )
    (list d pt p)
  )

  ;;=========================================================
  (setq e1 (getent "\nFirst entity."))
  (setq e2 (getent "\nSecond entity."))
  (setq len  (vlax-curve-getdistatparam e1 (vlax-curve-getendparam e1)))
  (setq idx  0.0
        step (/ len 100) ; 100 may need to increase for very large unit objects
  )
  (cond
    ((vlax-invoke
       (vlax-ename->vla-object e1) 'IntersectWith
                  (vlax-ename->vla-object e2) acExtendNone)
     (setq dis 0.0)
    )
    (t ; find the min distance within the steps. The accuracy is limited by the
     ;;  number of steps, then 2ObjDist is used to increase the accuracy
     (while (and (<= idx len)
                 (setq p1 (vlax-curve-getpointatdist e1 idx))
                 (setq p2 (vlax-curve-getclosestpointto e2 p1))
            )
       (setq dis (distance p1 p2)
             idx  (+ idx step)
       )
       (if (or (null dlst) (< dis (car dlst)))
         (setq dlst (list dis p1 p2))
       )             
     )
     
     (if (and dlst (listp dlst))
       (progn
         (setq dlst (2ObjDist e1 e2 (cadr dlst))
               dis (car dlst))
         (grdraw (trans (cadr dlst)0 1)(trans (caddr dlst)0 1) 6 1)
       )
     )
    )
  )
  (print dis)
  (princ)
)
(prompt "\nMinimum Distance Loaded, Enter MD to run.")
(princ)
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

VovKa

  • Water Moccasin
  • Posts: 1621
  • Ukraine
Re: Minimum distance between two vlax-curve objects
« Reply #35 on: May 23, 2008, 02:34:28 PM »
Alan i added some things to your code, hope you don't mind :)
Code: [Select]
(defun c:MinDist (/ step e1 e2 p1 p2 len idx dis dlst curveOK getent hasb e3)
  (vl-load-com)
  ;;  CAB test to see if vlax-curve can be used on an object
  (defun curveOK (ent)   ; returns nil if not allowed
    (not (vl-catch-all-error-p
   (vl-catch-all-apply 'vlax-curve-getendparam (list ent))
)
    )
  )
  ;; returns an entity which can be used with vlax-curve
  (defun getent (pmt / ent)
    (while (not (and (setq ent (car (entsel pmt))) (curveOK ent)))
      (prompt "\nMissed or not a Curve object. Try again.")
    )
    ent
  )
  ;;  get the min distance between 2 objects nearest to pt
  ;;  pt should be a point on obj1
  (defun 2ObjDist (e1 e2 p1 / p2 d fuzz)
    (setq fuzz 1E-8)
    (while (not
     (minusp
       (- (distance p1 (setq p2 (vlax-curve-GetClosestPointTo e2 p1)))
  (setq d (distance p2 (setq p1 (vlax-curve-GetClosestPointTo e1 p2))))
  fuzz
       )
     )
   )
    )
    (list d p1 p2)
  )
  (defun NoBulgeDist (e1 e2 / p1 p2 i d)
    (setq i (vlax-curve-getEndParam e1))
    (while (and (>= i 0))
      (setq p2 (vlax-curve-getClosestPointTo
   e2
   (setq p1 (vlax-curve-getPointAtParam e1 i))
)
    hasb (or hasb (not (equal (vlax-curve-getSecondDeriv e1 i) '(0 0 0))))
    i (1- i)
    d (distance p1 p2)
    dlst (if (or (< d (car dlst)) (null dlst))
   (list d p1 p2)
   dlst
)
      )
    )
  )
  ;;=========================================================
  (setq e1 (getent "\nFirst entity: "))
  (setq e2 (getent "\nSecond entity: "))
  (if (vlax-invoke
(vlax-ename->vla-object e1)
'IntersectWith
(vlax-ename->vla-object e2)
acExtendNone
      )
    (setq dis 0.0)
    (progn (NoBulgeDist e2 e1)
   (setq dlst (cons (car dlst) (reverse (cdr dlst))))
   (NoBulgeDist e1 e2)
   (if hasb
     (progn (if (> (vlax-curve-getDistAtParam e1 (vlax-curve-getEndParam e1))
   (vlax-curve-getDistAtParam e2 (vlax-curve-getEndParam e2))
)
      (setq e3 e1
    e1 e2
    e2 e3
    dlst (cons (car dlst) (reverse (cdr dlst)))
      )
    )
    ;| find the min distance within the steps. The accuracy is limited by the
   number of steps, then 2ObjDist is used to increase the accuracy|;
    (setq idx  0.0
  len  (vlax-curve-getdistatparam e1 (vlax-curve-getendparam e1))
  step (/ len 1000)   ; 100 may need to increase for very large unit objects
    )
    (while (and (<= idx len) (setq p1 (vlax-curve-getpointatdist e1 idx)))
      (setq p2 (vlax-curve-getclosestpointto e2 p1)
    dis (distance p1 p2)
    idx (+ idx step)
      )
      (if (< dis (car dlst))
(setq dlst (list dis p1 p2))
      )
    )
     )
   )
   (setq dlst (2ObjDist e1 e2 (cadr dlst)))
   (setq dis (car dlst))
   (grdraw (trans (cadr dlst) 0 1) (trans (caddr dlst) 0 1) 6 1)
    )
  )
  (print dis)
  (princ)
)

Joe Burke

  • Guest
Re: Minimum distance between two vlax-curve objects
« Reply #36 on: May 28, 2008, 08:30:28 AM »
My bells and whistles version attached. Check the header comments.

With thanks to Alan and VovKa.  :-)

ronjonp

  • Needs a day job
  • Posts: 7524
Re: Minimum distance between two vlax-curve objects
« Reply #37 on: May 28, 2008, 11:44:30 AM »
Here is my contribution...will prompt if objects except *polylines (no time right now to address) are parallel.

Code: [Select]
...
;;Adds distances gathered into dlst then divides by (1+ div)
;;to check if equal (+- 0.001) to middle item in list. Still need to
;;create function to account for polylines as well
(if (and (equal on1 on2)
(not (wcmatch on1 "*Polyline"))
(not (wcmatch on2 "*Polyline"))
(equal (/ (apply '+ dlst) (1+ div))
(nth (/ (length dlst) 2) dlst)
0.001
)
    )
  (setq m (strcat "\n(" (substr on1 5) "'s appear to be parallel)"))
  (setq m "")
)
...

Ron
« Last Edit: May 30, 2008, 10:24:01 AM by ronjonp »

Windows 11 x64 - AutoCAD /C3D 2023

Custom Build PC

VovKa

  • Water Moccasin
  • Posts: 1621
  • Ukraine
Re: Minimum distance between two vlax-curve objects
« Reply #38 on: May 28, 2008, 12:27:02 PM »
hi Joe
may i suggest 2 things that you've missed in my last post :pissed:  :-)
http://www.theswamp.org/index.php?topic=23170.msg280044#msg280044

if two polylines are selected it would be better to run NoBulgeDist on them, and if they do not have bulges we will have the desired distance right away (much faster)

we will get the desired distance faster if we step along the shortest of two selected objects

Joe Burke

  • Guest
Re: Minimum distance between two vlax-curve objects
« Reply #39 on: May 29, 2008, 05:48:57 AM »
Hi VovKa,

I ran speed tests while working on the latest code. They indicated the
core part of the routine, from IntersectWith to where the two points are
known, was already fast. Like 0.1 second or less and often half that.
This includes cases where the second calculation, the part you rewrote,
gets a good workout.

At that point I thought, rightly or wrongly, trying to make it faster
wasn't worth it. I'm sure you're right, it could be faster. I wonder
though whether the user would ever see the difference.

There could be a condition which tests for whether either objects is a
circle. Special case since there are no ends to deal with. Get the closest
point on the other object from center point of the circle. Get the closest
point on the circle from that point.

I found something interesting while speed testing. Check the attached
example file and the test routine which follows. The polylines have more
than 600 vertices, no bulges I believe. The IntersectWith method takes
about 0.35 second to compare the objects. It causes a noticeable lag in
the routine.

Code: [Select]
(defun StartTimer ()
  (setq *start* (getvar "date")))
(defun EndTimer (/ end)
  (setq end (* 86400 (- (getvar "date") *start*)))
  (princ (strcat "\nTimer: " (rtos end 2 8) " seconds\n")))

(defun c:test ( / obj1 obj2)
  (setq obj1 (car (entsel "\nSelect polyline: "))
        obj1 (vlax-ename->vla-object obj1)
        obj2 (car (entsel "\nSelect polyline: "))
        obj2 (vlax-ename->vla-object obj2)
  )
  (starttimer)
  (vlax-invoke obj1 'IntersectWith obj2 acExtendNone)
  (endtimer)
)

Joe Burke

  • Guest
Re: Minimum distance between two vlax-curve objects
« Reply #40 on: May 29, 2008, 06:29:16 AM »
Quote

we will get the desired distance faster if we step along the shortest of two selected objects

Do you mean faster because the test points along the shorter object are spaced closer together? And that may mean fewer iterations during the second calculation?

Joe Burke

  • Guest
Re: Minimum distance between two vlax-curve objects
« Reply #41 on: May 29, 2008, 07:14:30 AM »
Here is my contribution...will prompt if objects except *polylines (no time right now to address) are parallel.

Interesting idea. It would be nice to eliminate these two sub-functions, MD:NormalAngle and MD:ParallelLines, which only serve a limited purpose.

VovKa

  • Water Moccasin
  • Posts: 1621
  • Ukraine
Re: Minimum distance between two vlax-curve objects
« Reply #42 on: May 29, 2008, 02:07:56 PM »
Quote
Do you mean faster because the test points along the shorter object are spaced closer together? And that may mean fewer iterations during the second calculation?
i think in most cases it will be true
as for IntersectWith... it's doing 645*621 (inters)es, or whatever it's programmed to do, maybe it has to be slow :)

ronjonp

  • Needs a day job
  • Posts: 7524
Re: Minimum distance between two vlax-curve objects
« Reply #43 on: May 29, 2008, 04:34:00 PM »
Here is my contribution...will prompt if objects except *polylines (no time right now to address) are parallel.

Interesting idea. It would be nice to eliminate these two sub-functions, MD:NormalAngle and MD:ParallelLines, which only serve a limited purpose.

Done....I also changed the code a bit to compare the averaged distance to the midpoint distance. My previous function would fail if one object was longer than the other.

Windows 11 x64 - AutoCAD /C3D 2023

Custom Build PC

Joe Burke

  • Guest
Re: Minimum distance between two vlax-curve objects
« Reply #44 on: May 30, 2008, 05:45:18 AM »
Quote
Done....I also changed the code a bit to compare the averaged distance to the midpoint distance. My previous function would fail if one object was longer than the other.

I'm confused. Did you update the code posted before, or did you intend to post a new version?