Count objects at a specific distance

Count objects at a specific distance

adaptacad
Advocate Advocate
1,266 Views
11 Replies
Message 1 of 12

Count objects at a specific distance

adaptacad
Advocate
Advocate
Hello everyone, Is there a way to count only objects at a specific distance?
Example I have several blocks in my drawing and I want to count only those that are at the maximum distance X, from a RED, CIAN polyline ... and delete all others, How to do this?
In the attached dwg example, I want to delete only those with the green circle.
Thanks in advance for the help you are giving me !!
0 Likes
Accepted solutions (1)
1,267 Views
11 Replies
Replies (11)
Message 2 of 12

dlanorh
Advisor
Advisor

In your drawing there is only one block at the "MAXIMUM" distance, and two that are close; unless you mean at a distance greater than a supplied distance.

I am not one of the robots you're looking for

0 Likes
Message 3 of 12

doaiena
Collaborator
Collaborator

Here is a quick and dirty. You can easily edit it to suit your exact needs.

(defun c:test ( / ent poly sel maxDist ctr blocks)

(while (not ent) (setq ent (entsel "\nSelect a Polyline")))
(setq poly (vlax-ename->vla-object (car ent)))
(setq sel (ssget "X" '((0 . "INSERT"))))
(setq maxDist 2)
(setq blocks (ssadd))

(setq ctr 0)
(repeat (sslength sel)
(setq pt (cdr (assoc 10 (entget (ssname sel ctr)))))
(if (< (distance (vlax-curve-getclosestpointto poly pt) pt) maxDist)
(ssadd (ssname sel ctr) blocks)
)

(setq ctr (1+ ctr))
)

(princ (strcat "\n" (itoa (sslength blocks)) " blocks are in range."))
(princ)
)
Message 4 of 12

adaptacad
Advocate
Advocate

@doaiena wrote:

Here is a quick and dirty. You can easily edit it to suit your exact needs.

(defun c:test ( / ent poly sel maxDist ctr blocks)

(while (not ent) (setq ent (entsel "\nSelect a Polyline")))
(setq poly (vlax-ename->vla-object (car ent)))
(setq sel (ssget "X" '((0 . "INSERT"))))
(setq maxDist 2)
(setq blocks (ssadd))

(setq ctr 0)
(repeat (sslength sel)
(setq pt (cdr (assoc 10 (entget (ssname sel ctr)))))
(if (< (distance (vlax-curve-getclosestpointto poly pt) pt) maxDist)
(ssadd (ssname sel ctr) blocks)
)

(setq ctr (1+ ctr))
)

(princ (strcat "\n" (itoa (sslength blocks)) " blocks are in range."))
(princ)
)

 

This is almost !!
How to use the selection set? and how to delete objects not being counted?

0 Likes
Message 5 of 12

doaiena
Collaborator
Collaborator
Accepted solution

Give this a try.

(defun c:test ( / ssPoly ssBlocks maxDist polyColors blocks ssDelete ctr poly ctr2 pt)

(setq ssPoly (ssget "X" '((0 . "LWPOLYLINE"))))
(setq ssBlocks (ssget "X" '((0 . "INSERT"))))
(setq maxDist 2)
(setq polyColors (list 1 4))
(setq blocks (ssadd))
(setq ssDelete (ssadd))

(setq ctr 0)
(repeat (sslength ssPoly)
(setq poly (vlax-ename->vla-object (ssname ssPoly ctr)))

(if (member (vla-get-color poly) polyColors)
(progn

(setq ctr2 0)
(repeat (sslength ssBlocks)
(setq pt (cdr (assoc 10 (entget (ssname ssBlocks ctr2)))))
(if (< (distance (vlax-curve-getclosestpointto poly pt) pt) maxDist)
(ssadd (ssname ssBlocks ctr2) blocks)
)

(setq ctr2 (1+ ctr2))
);repeat blocks

));if red or teal

(setq ctr (1+ ctr))
);repeat polys



(setq ctr 0)
(repeat (sslength ssBlocks)
(if (not (ssmemb (ssname ssBlocks ctr) blocks))
(ssadd (ssname ssBlocks ctr) ssDelete)
)
(setq ctr (1+ ctr))
)

(princ (strcat "\n" (itoa (sslength ssDelete)) " blocks are deleted."))
(command "erase" ssDelete "")
(princ)
)
Message 6 of 12

adaptacad
Advocate
Advocate

This looks like it will work !! thank you very much! @doaiena 

0 Likes
Message 7 of 12

Scottu2
Advocate
Advocate

Hi @doaiena,

 

Remove the objects found from the initial selection set.

 

(setq sel (ssget "X" '((0 . "INSERT"))))

This create a selection set with all objects in the drawing with the (0 . "INSERT") filter to select only blocks.

adaptacad's routine creates a new selection set, called blocks, to add blocks that are in range.

Then displays how many.

 

(princ (strcat "\n" (itoa (sslength blocks)) " blocks are in range."))

 

Add this line of code after the PRINC to erase all the other blocks.

(command "erase" "previous" "r" blocks")

 

PS: Nice routines adaptacad

 

0 Likes
Message 8 of 12

JamesMaeding
Advisor
Advisor

note that this is brute force. It tests the distance on every item.

If running on large amounts of items over and over, you can speed things up by doing bounding box elimination.

That is, you make a list of the points to look at, sort by their x coord, then skip the ones before and after the bounding box. Do same for Y once narrowed down.

That sort approach is how you do things fast like "delete duplicate objects" and so on.


internal protected virtual unsafe Human() : mostlyHarmless
I'm just here for the Shelties

Message 9 of 12

ronjonp
Mentor
Mentor

This was also answered HERE too. A few simple changes for speed could also include using vl-some when checking distance of points to lines, use an ename rather than vla object for the closest point check and filter the colored plines directly:

(setq sspoly (ssget "X" '((0 . "LWPOLYLINE") (-4 . "<OR") (62 . 1) (62 . 4) (-4 . "OR>"))))

 

Message 10 of 12

adaptacad
Advocate
Advocate

@JamesMaeding  You are very right. I tested on a file with many objects and behaved slowly!

0 Likes
Message 11 of 12

adaptacad
Advocate
Advocate

@doaiena  and @JamesMaeding  Is there a way to improve performance? make it faster?

0 Likes
Message 12 of 12

doaiena
Collaborator
Collaborator

As mentioned above, this is a brute force approach and as such, it gets exponentially slower, with the increase in entity count.

Both @JamesMaeding  and @ronjonp  gave suggestions on how to improve the performance. You can use a boundingbox elimination approach, filter the polylines at the selection stage, skip the ename->object convertion and so on. You should at least give it a try on your own, to implement these changes.

0 Likes