Jump to content

How to check if objects are inside closed Polylines


gsc

Recommended Posts

Hi,

 

In a lisp routine want to check 3 Cases with a (sub)function if :

 

  1. One of the black Circles is crossing of the red closed Polylines (already found an intersect solution)
  2. One of the Circles is fully inside closed red Polylines
  3. One of the red closed Polylines are fully inside of one of the black Circles.

 

The 4 black circles are itterated (different locations and headings) to many positions in the field.

Keep in mind the red polylines are a clipped example, this can be a whole field of closed polygons

 

Example.thumb.PNG.d41b37cf9c7c182de8a1c3469266b08c.PNG

Does anyone has an example how to check (by itteration) if a Circle is fully inside one of the red polygons or the other way around?

The only goal of the function(s) is that the result of the 4 black circles itteration is TRUE or NIL

 

Greetzzz!

 

 

Link to comment
Share on other sites

17 minutes ago, Tharwat said:

The following functions are your fiends in this case:

 

1- vla-intersectwith

2- ssget "_WP"

 

Hi,

 

To test vla-intersectwith  and all the ExtendOption parameters, i found this page: https://www.afralisp.net/archive/methods/lista/intersectwith_method.htm

I have created a small test lisp:

(defun c:test ()

    (vl-load-com)
    (setq util (vla-get-utility (vla-get-activedocument (vlax-get-acad-object))))

    (vla-getentity util 'obj1 'ip "\nSelect First Object: ")
    (vla-getentity util 'obj2 'ip "\nSelect Second Object: ")

    (setq int1 (vla-IntersectWith obj1 obj2 acExtendNone))
    (setq int2 (vla-IntersectWith obj1 obj2 acExtendThisEntity))
    (setq int3 (vla-IntersectWith obj1 obj2 acExtendOtherEntity))
    (setq int4 (vla-IntersectWith obj1 obj2 acExtendBoth))

    (princ int1)
    (princ int2)
    (princ int3)
    (princ int4)
    (princ)
)

As a test I have drawn a CIRCLE and a closed LWPOLYLINE
But for all 3 Cases I have described in my first post, the result is a Variant (array of doubles):

 

#<variant 8197 ...>

#<variant 8197 ...>

#<variant 8197 ...>

#<variant 8197 ...>

 

I have 2 questions:

  1. How can I get the values out of the variant object?
  2. Does this also work for Case 2 and 3, where no intersection is between the objects??

 

 

Link to comment
Share on other sites

3 hours ago, gsc said:

 

Hi,

 

To test vla-intersectwith  and all the ExtendOption parameters, i found this page: https://www.afralisp.net/archive/methods/lista/intersectwith_method.htm

I have created a small test lisp:


(defun c:test ()

    (vl-load-com)
    (setq util (vla-get-utility (vla-get-activedocument (vlax-get-acad-object))))

    (vla-getentity util 'obj1 'ip "\nSelect First Object: ")
    (vla-getentity util 'obj2 'ip "\nSelect Second Object: ")

    (setq int1 (vla-IntersectWith obj1 obj2 acExtendNone))
    (setq int2 (vla-IntersectWith obj1 obj2 acExtendThisEntity))
    (setq int3 (vla-IntersectWith obj1 obj2 acExtendOtherEntity))
    (setq int4 (vla-IntersectWith obj1 obj2 acExtendBoth))

    (princ int1)
    (princ int2)
    (princ int3)
    (princ int4)
    (princ)
)

As a test I have drawn a CIRCLE and a closed LWPOLYLINE
But for all 3 Cases I have described in my first post, the result is a Variant (array of doubles):

 

#<variant 8197 ...>

#<variant 8197 ...>

#<variant 8197 ...>

#<variant 8197 ...>

 

I have 2 questions:

  1. How can I get the values out of the variant object?
  2. Does this also work for Case 2 and 3, where no intersection is between the objects??

 

 

 

Use the snippet from  @Tharwat above and put it into an if statement and test if there is a return or not. If there is an intersection it will return a list. If not then nil is returned so either test for nil (not) or test length of returned list

 

(if (not (vlax-invoke obj1 'intersectwith obj2 acextendnone))
	(doesn't intersect)
	(intersects)
);end_if

 

This should result in a list or nil being returned

Link to comment
Share on other sites

Partly, it will only tell you if one intersects the other. In cases 2 and 3 (completely inside or outside) you would need to do additional checks using a raycasting method (not 100% effective) or a winding method. 

 

2. check, is the center of the circle inside the polyline. If there is no intersection and the center of the circle is inside then the whole circle is inside

 

3. Is the distance from every vertex of the polyline to the center of the circle less than the radius, then if there is no intersection, the polyline is completely inside the circle.

Link to comment
Share on other sites

the 2nd option I do the same

The 3rd, (most of them are small polylines in a cluster)...I list the points of all closed polylines, each list is a polyline, then I do the same method as the 2nd, check if all points of one list are inside a Circle...itterative I do the rest of the lists

 

 

Link to comment
Share on other sites

For 3 within a circle as already stated you struggle to us ssget as circle is not directly supported as a polygon to search within, you can make a polygon with lots of sides get the the co-ordinates and use that with "WP". It can be an advantage to make the polygon a fraction bigger than the circel.

 

 

Link to comment
Share on other sites

I had in mind to make a squared selection window around each circle and add all found objects to the selection set.
A square around the Circle is narrow enough.

 

Another idea is, since the selection set will be quit small (average radius of the circles is 4 to 10 m), to create a merged REGION of Circles and a merged REGION of the Selection Set in a temporary layer, perform an INTERSECT command....if there is an Intersect, there is a resulting REGION shape, if not both REGIONS disappear i.o.w. Layer is empty or not, this would replace all 3 cases described. The advantage would also be that you can create REGIONS with holes
How should I approach that?

 

(defun ssExclusionSS ( lyr lst rad / pt1 pt2 ss1 ss2 ent )
    
    ; lyr is layer with possible closed polylines, circles or ellipses
    ; lst are 4 circle center coordinats
    ; rad is radius of circles
    
    (setq ss1 (ssadd))
    (foreach itm lst
        (setq num 0)
        ;Set search window boundary
        (setq pt1 (polar itm (DTR 225) rad))
        (setq pt2 (polar itm (DTR 45) rad))
        
        ;Get objects within search window
        (setq ss2 (ssget "_WP" (list (car pt1) (cadr pt1)) (list (car pt2) (cadr pt2)) (list (cons 8 lyr))))
        
        (if ss2
            (progn
                 (repeat (sslength ss2)
                    (setq ent (ssname ss2 num))
                    (cond
                        ((= (cdr (assoc 0 (entget ent))) "LWPOLYLINE")
                            (ssadd ent ss1)
                        )
                        ((= (cdr (assoc 0 (entget ent))) "CIRCLE")
                            (ssadd ent ss1)
                        )
                        ((= (cdr (assoc 0 (entget ent))) "ELLIPSE")
                            (ssadd ent ss1)
                        )
                    )            
                )
            )
        )
        (setq num (1+ num))
    )
    ss1
)

 

Edited by gsc
Link to comment
Share on other sites

Using polygon is easy as with a circle you have a center point and a radius, please note Bricscad uses a different method.

 

pt centre of circle 
rad is obvius radius

(command "polygon" 10 pt "I" rad) ; make a polygon 10 sides
(setq co-ord (mapcar 'cdr (vl-remove-if-not '(lambda (x) (= (car x) 10)) (entget (entlast)))))
(command "erase" (entlast) "") ; polygon not needed

(setq ss (ssget "wP" co-ord ))

 

Link to comment
Share on other sites

3 hours ago, BIGAL said:

Using polygon is easy as with a circle you have a center point and a radius, please note Bricscad uses a different method.

 


pt centre of circle 
rad is obvius radius

(command "polygon" 10 pt "I" rad) ; make a polygon 10 sides
(setq co-ord (mapcar 'cdr (vl-remove-if-not '(lambda (x) (= (car x) 10)) (entget (entlast)))))
(command "erase" (entlast) "") ; polygon not needed

(setq ss (ssget "wP" co-ord ))

 

 

 

That is a good option! How about the following approach?:

 

I already have a function (ssExclusionSS) which creates a (narrowed down) selection set of a squared window of objects inside the 4 Circles:

(defun ssExclusionSS ( lyr lst rad / pt1 pt2 ss1 ss2 ent )
    
    ; lyr is layer with closed polylines
    ; lst are 4 circles coordinates
    ; rad is radius of circles
    
    (setq ss1 (ssadd))
    (foreach itm lst
        ;Set search window boundary
        (setq pt1 (polar itm (DTR 225) (sqrt (+ (* rad rad) (* rad rad)))))
        (setq pt2 (polar itm (DTR 45) (sqrt (+ (* rad rad) (* rad rad)))))
        
        ;Get objects within search window
        (setq ss2 (ssget "_W" (list (car pt1) (cadr pt1)) (list (car pt2) (cadr pt2)) (list (cons 8 lyr))))
        
        ;Add all found objects to ss1
        (if ss2
            (progn
                (setq num 0)
                (repeat (sslength ss2)
                    (setq ent (ssname ss2 num))
                    (cond
                        ((= (cdr (assoc 0 (entget ent))) "LWPOLYLINE")
                            (ssadd ent ss1)
                        )
                        ((= (cdr (assoc 0 (entget ent))) "CIRCLE")
                            (ssadd ent ss1)
                        )
                        ((= (cdr (assoc 0 (entget ent))) "ELLIPSE")
                            (ssadd ent ss1)
                        )
                    )
                    (setq num (1+ num))
                )
            )
        )
    )
    ss1
)

 

The returned selection set, selected with above subroutine (ssExclusionSS) may still have objects outside the circle because it searches with a squared window around a circle.

The (inCircles) function below must return whether this object is inside or outside the Circle.

 

But instead of one object (obj), as the example shows, I want to feed it with the selection set which is returned with the above subroutine (ssExclusionSS), and itterate the objects:

  • If one (or more) objects are inside Circle then it must return T
  • If all objects are outside the circle then return must be NIL
(defun inCircles (obj CirObj / Mi Ma cen rad)
    (mapcar (function set) '(obj CirObj)
        (mapcar
            (function
                (lambda (x) (if (eq 'VLA-OBJECT (type x)) x
                                            (vlax-ename->vla-object x)
                                        )
                )
            )
            (list obj CirObj)
        )
    )
    (vla-getBoundingBox obj 'Mi 'Ma)
    (mapcar (function set) '(Mi Ma) (mapcar (function vlax-safearray->list) (list Mi Ma)))
    (setq cen (vlax-get CirObj 'Center)
                rad (vla-get-Radius CirObj))
    (and
        (<= (distance Mi cen) rad)
        (<= (distance Ma cen) rad)
        (<= (distance (list (car Mi) (cadr Ma)) cen) rad)
        (<= (distance (list (car Ma) (cadr Mi)) cen) rad)
    )
)

 

I got a bit stuck with the subroutine (ssExclusionSS)

The AND returns T or NIL for one object, how do I itterate the rest of the objects and still have T or NIL as return?

The requirement is:

  • If one (or more) objects are inside the Circle then it must return T
  • If ALL objects are outside the circle then it must return NIL

How do I program this?

 

Link to comment
Share on other sites

Poor you. Here, I'll guide you a bit.

 

;; In all functions, obj and circ are VLA Objects

(defun Circle:Case1 (obj circ)
    (and (vlax-invoke obj 'IntersectWith circ acExtendNone))
    )

(defun Circle:Case2 (obj circ / cen ry int)
    (setq cen (vlax-get circ 'Center)
	  ry (entmakex
		 (list
		     '(0 . "RAY")
		     '(100 . "AcDbEntity")
		     '(100 . "AcDbRay")
		     (cons 10 cen)
		     '(11 1.0 0.0 0.0)
		     )
		 )
	  int (vlax-invoke obj 'IntersectWith (vlax-ename->vla-object ry) acExtendNone)
	  )
    (entdel ry)
    (and
	(not (vlax-invoke obj 'IntersectWith circ acExtendNone))
	(= (rem (length int) 6) 3)
	)
    )

(defun Circle:Case3 (obj circ / cen rd)
    (setq cen (vlax-get circ 'Center)
	  rd (vlax-get circ 'Radius)
	  )
    (and
	(not (vlax-invoke obj 'IntersectWith circ acExtendNone))
	(vl-every
	    '(lambda (x) (<= (distance (cdr x) cen) rd))
	    (vl-remove-if-not
		'(lambda (a)
		     (= (car a) 10)
		     )
		(entget (vlax-vla-object->ename obj))
		)
	    )
	)
    )

 

So where all objects within a selection set is outside the circle, it will return nil. Where at least one is inside, it returns T:

 

(defun OneInside (ss circ / i lst)
    (repeat (setq i (sslength ss))
	(setq lst (cons (vlax-ename->vla-object (ssname ss (setq i (1- i)))) lst))
	)
    (vl-some '(lambda (x) (Circle:Case2 x circ)) lst)
    )

 

Edited by Jonathan Handojo
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...