Delete everything outside the circle in Lisp.

Delete everything outside the circle in Lisp.

Anonymous
Not applicable
2,152 Views
16 Replies
Message 1 of 17

Delete everything outside the circle in Lisp.

Anonymous
Not applicable

Hello,

My task is to create circle, then create some triangles inside and outside that circle. Program should let me draw only triangles inside the circle, and delete ones outside the circle.

Here is the code I've done so far. It works fine through X-axis and Y-axis, but sometimes it draws triangle outside the circle.

What is wrong, and how to make everything deleted outside the circle.

 

(setq center nil)
(setq radius nil)
(setq l_t nil)
(setq h nil)
(setq x_max nil)
(setq x_min nil)
(setq y_max nil)
(setq y_min nil)
(setq triangle nil)
(setq center (getpoint "Circle center"))
(setq radius (getpoint "Circle radius"))
(command "circle" center radius)
(setq circle (entlast))
(setq center_r (cdr(assoc 40 (entget circle)))) ;getting radius
(setq x_max (+(nth 0 center) center_r))
(setq x_min (-(nth 0 center) center_r))
(setq y_max (+(nth 1 center) center_r))
(setq y_min (-(nth 1 center) center_r))
(repeat (getint "How many triangles?")
(setq center_t (getpoint "Set the center"))
(setq h (getpoint "Set the height"))
(command "._polygon" "3" center_t "I" h)
(setq h nil)
(if (AND(<(nth 0 center_t) x_max)(>(nth 0 center_t) x_min)) 
  (progn
  (princ "inside"));progn
  (entdel (entlast))
  );if
(if (AND(<(nth 1 center_t) y_max)(>(nth 1 center_t) y_min))
  (progn
  (princ "inside"));progn
  (entdel (entlast))
  );if
(setq triangle (append triangle (list (entlast)))) 
  );repeat
0 Likes
2,153 Views
16 Replies
Replies (16)
Message 2 of 17

DannyNL
Advisor
Advisor

You are checking the center point of your triangle to a max and min X, Y of the circle and these 4 values form a rectangle and not a circle. So all coordinates at lower left, lower right, upper left and upper right, but between the min/max of the X,Y will be drawn.

 

So instead of checking to a min/max X,Y you can better check the distance from the center point of the circle. As long as it is less than the radius it is within the circle. Something like:

 

(< (distance center center_t) center_r)

 

 

Another thing I notice is that you draw to polygon and then start checking for the coordinate. Why not first check if it is within the boundaries before drawing the polygon? It makes to code easier and you do not have to delete wrong triangles.

0 Likes
Message 3 of 17

ActivistInvestor
Mentor
Mentor

@Anonymous wrote:

Hello,

My task is to create circle, then create some triangles inside and outside that circle. Program should let me draw only triangles inside the circle, and delete ones outside the circle.

Here is the code I've done so far. It works fine through X-axis and Y-axis, but sometimes it draws triangle outside the circle.

What is wrong, and how to make everything deleted outside the circle.

 

(setq center nil)
(setq radius nil)
(setq l_t nil)
(setq h nil)
(setq x_max nil)
(setq x_min nil)
(setq y_max nil)
(setq y_min nil)
(setq triangle nil)
(setq center (getpoint "Circle center"))
(setq radius (getpoint "Circle radius"))
(command "circle" center radius)
(setq circle (entlast))
(setq center_r (cdr(assoc 40 (entget circle)))) ;getting radius
(setq x_max (+(nth 0 center) center_r))
(setq x_min (-(nth 0 center) center_r))
(setq y_max (+(nth 1 center) center_r))
(setq y_min (-(nth 1 center) center_r))
(repeat (getint "How many triangles?")
(setq center_t (getpoint "Set the center"))
(setq h (getpoint "Set the height"))
(command "._polygon" "3" center_t "I" h)
(setq h nil)
(if (AND(<(nth 0 center_t) x_max)(>(nth 0 center_t) x_min)) 
  (progn
  (princ "inside"));progn
  (entdel (entlast))
  );if
(if (AND(<(nth 1 center_t) y_max)(>(nth 1 center_t) y_min))
  (progn
  (princ "inside"));progn
  (entdel (entlast))
  );if
(setq triangle (append triangle (list (entlast)))) 
  );repeat

Your method of testing for containment is not correct.

 

For a triangle, or any convex polygon, the polygon is entirely within a circle only if all of its vertices are within the circle.

 

So, the simplest test is to compare the distance of each of the three vertices of the triangle to the center point with the circle's radius. 

 

0 Likes
Message 4 of 17

DannyNL
Advisor
Advisor

Try this code.

It still only checks if the center of the polygon is inside the circle.

 

(defun c:Test (/ varlist oldvars center radius h triangle center_t)
   
   (setq varlist '("CMDECHO" "OSMODE"))
   (setq oldvars (mapcar 'getvar varlist))
   (mapcar 'setvar varlist '(0 0))
   
   (setq center (getpoint "\nCircle center"))
   (setq radius (getdist center "\nCircle radius"))
   (command "circle" center radius) 
   (repeat (getint "\nHow many triangles?")
      (setq center_t (getpoint "\nSet the center"))                 
      (if
         (< (distance center center_t) radius)
         (progn
            (princ "\nInside")
            (setq h (getpoint center_t "\nSet the height"))
            (command "._polygon" "3" center_t "I" h)
            (setq triangle (append triangle (list (entlast))))
         )                              ;progn
      )                                 ;if            
   )                                    ;repeat

   (mapcar 'setvar varlist oldvars)
   triangle
   
)

 

0 Likes
Message 5 of 17

martti.halminen
Collaborator
Collaborator

 

A style point:

(setq triangle (append triangle (list (entlast))))

is rather inefficient for long lists.

The traditional way to collect stuff in a loop would be

(setq triangle (cons (entlast) triangle))

- if the order is significant, add a REVERSE call outside the loop.

 

0 Likes
Message 6 of 17

DannyNL
Advisor
Advisor

But since this isn't a long list but only a list containing the entity names of the created polygons, your point in this case is not really valid Smiley Happy

 

0 Likes
Message 7 of 17

Ranjit_Singh
Advisor
Advisor

@Anonymous wrote:

Hello,

My task is to create circle, then create some triangles inside and outside that circle. Program should let me draw only triangles inside the circle, and delete ones outside the circle.

Here is the code I've done so far. It works fine through X-axis and Y-axis, but sometimes it draws triangle outside the circle.

What is wrong, and how to make everything deleted outside the circle. 


You need to check every single vertex of the drawn polygon against the circle perimeter. If any of the vertex is outside then delete the triangle. See below example. Minimal testing.

(defun c:somefunc  (/ center center_t circle curosmode h radius)
 (setq center (getpoint "\nCircle center: ")
       radius (getpoint "\nCircle radius: ")
       radius (distance center radius))
 (command "circle" center radius)
 (setq circle (entlast))
 (setq curosmode (getvar 'osmode))
 (setvar 'osmode 0)
 (repeat (getint "\nHow many triangles? :")
  (setq center_t (getpoint "\nSet the center: ")
        h        (getpoint "\nSet the height: "))
  (command "._polygon" "3" center_t "I" h)
  (if (apply 'or
             (mapcar '(lambda (x) (> (distance center x) radius))
                     (cdr (reverse (vl-remove-if-not 'listp (mapcar 'cdr (entget (entlast))))))))
   (progn (princ "\nTriangle not contained within circle.") (entdel (entlast)))))
 (setvar 'osmode curosmode)
 (princ))

tri_circ.gif

 

0 Likes
Message 8 of 17

Kent1Cooper
Consultant
Consultant

Some questions:

 

Do you mean to eliminate [or prevent from being drawn in the first place] all triangles that extend outside the Circle at all, or only those that are completely outside the Circle?

 

This line:


  (setq h (getpoint "Set the height"))

 

gives very peculiar results if I type in  values for the heights of the triangles, rather than pick points on-screen.  Is it your intent that the height must always be set by a point pick [in which case I suggest changing the wording of the prompt, and/or adding center_t as a reference point for rubber-banding], or should the User have the option to type in a value [in which case I suggest using (getdist ) rather than (getpoint )]?

 

[EDIT:  Sorry, this should be in response to @Anonymous -- I picked Reply under a Reply to the original, but should have under the original itself.]

Kent Cooper, AIA
0 Likes
Message 9 of 17

Kent1Cooper
Consultant
Consultant

@Kent1Cooper wrote:

.... 

This line:


  (setq h (getpoint "Set the height"))

 

....  Is it your intent that the height must always be set by a point pick ..., or should the User have the option to type in a value ...?

....


And springing from that....  The word "height" in relation to a triangle in geometry has a meaning, and it's not  the radius of the triangle's Circumcircle.  For an equilateral triangle, it's 1.5 times that.  Should the prompt be something like "Pick a corner of the triangle: "?

 

In your routine, the picking of the second point determines both the size  and the orientation  of the triangle, whereas with a pure-number circle radius for it to be inscribed in, the triangle always gets a horizontal base and a corner pointing straight up.  Is that a reason to do it by point pick and not  by typing in a value?  If so, and if any triangle that extends outside the Circle at all is to be eliminated, I would suggest you leave command echoing on, and even Osnap if you might want it for some point or other, and do something like this:

 

(defun C:TIC ; = Triangles Inside Circle
  (/ cdata ctr-c rad-c)
  (command "_.circle")
  (while (> (getvar 'cmdactive) 0) (command pause))
  (setq
    cdata (entget (entlast))
    ctr-c (cdr (assoc 10 cdata))
    rad-c (cdr (assoc 40 cdata))
  ); setq
  (initget 6); no zero, no negative
  (repeat (getint "\nHow many triangles? ")
    (command "_.polygon" 3 pause "_inscribed" pause)
    (if
      (<
        rad-c
        (apply 'max
          (mapcar '(lambda (x) (distance x ctr-c))
            (mapcar 'cdr (vl-remove-if-not '(lambda (y) (= (car y) 10)) (entget (entlast))))
          )
        )
      )
      (progn ; then
        (prompt "\nTriangle extended outside circle.")
        (entdel (entlast))
      )
(setq triangles (cons (entlast) triangles)); else ) ) (princ) )

 

That allows any  of the possible ways of drawing the Circle [pick-point or Diameter/2P/3P/Ttr options], and you can see it dynamically as you draw it.  And it lets you see the triangles forming as you draw them, which could prevent drawing a bad one in the first place.  By leaving the commands to supply their own prompts and operating within the commands instead of before-hand, you not only get the dynamic drawing aspect, but also a number of your variables are no longer needed.

 

Another question arises in trying that out:  If you draw any that violate the Circle, do you want to still be able to draw the number of triangles you asked for originally?  The above and your original give you that many tries, but if any of them are no good, you end up with fewer than you wanted.  To get another try for any that fail, it would need to use something like a (while) loop and a counter, rather than that (repeat) function, which would be an easy adjustment.

 

[EDIT:  If used more than once in a drawing session, consider whether you want triangles inside multiple  Circles to all  be added into one collective 'triangles' list variable, or whether you want to put  (setq triangles nil)  near the top to start the list over with each running of the command.  It would even be possible to make them separate lists for each running, with variable names like triangles1, triangles2, etc., if you need that.]

Kent Cooper, AIA
0 Likes
Message 10 of 17

john.uhden
Mentor
Mentor

@ActivistInvestor wrote "For a triangle, or any convex polygon, the polygon is entirely within a circle only if all of its vertices are within the circle."

 

That ain't necessarily so.  While all vertices may be inside the circle, there may be bulged segments that go outside.

But if the definition of a polygon says that all sides are straight, then you are correct.

 

To be safe, I think I would compare the closestpointto (center to polylon) to the radius.  But of course then we need clarification... if a polygon touches the circle, does that disqualify it or include it.  In tennis and baseball, if a ball hits any part of the the white line it is in.  I don't know about soccer or volleyball.  In football I think the ball carrier is out if he touches any part of the white side line.

John F. Uhden

0 Likes
Message 11 of 17

ActivistInvestor
Mentor
Mentor

@john.uhden wrote:

@ActivistInvestor wrote "For a triangle, or any convex polygon, the polygon is entirely within a circle only if all of its vertices are within the circle."

 

That ain't necessarily so.  While all vertices may be inside the circle, there may be bulged segments that go outside.

But if the definition of a polygon says that all sides are straight, then you are correct.

 

 


Polygons don't have "bulged segments".

0 Likes
Message 12 of 17

john.uhden
Mentor
Mentor

That definition may help.  But I still recommend the method I described of comparing the radius to the distance from the circle's center to the closest point on the polygon.  Even if the bulge is 0.0, a piece of a straight segment could be inside the the circle even if its vertices are outside.

John F. Uhden

0 Likes
Message 13 of 17

ActivistInvestor
Mentor
Mentor

@john.uhden wrote:

That definition may help.  But I still recommend the method I described of comparing the radius to the distance from the circle's center to the closest point on the polygon.  Even if the bulge is 0.0, a piece of a straight segment could be inside the the circle even if its vertices are outside.


I'm not sure why this conversation is deteriorating into a debate of semantics and the definitions of common terms like 'polygon', and what 'inside/outside/within' mean, but I find it quite boring. A polygon is a closed figure with straight edges. It does not have curved edges.

 

In the case of your use of the term 'outside', if you go back and read what I wrote, and you quoted, I used the words 'entirely within'.

 

According to what I read, the OP wants to know if a triangle is [entirely] within a circle, and wants to reject any triangle that is not [entirely] within a circle, regardless of whether it is entirely outside, or partially inside/outside the circle.

 

So what is the point to all of this?

 

0 Likes
Message 14 of 17

Kent1Cooper
Consultant
Consultant

@Kent1Cooper wrote:
.... If you draw any that violate the Circle, do you want to still be able to draw the number of triangles you asked for originally?  The above and your original give you that many tries, but if any of them are no good, you end up with fewer than you wanted.  To get another try for any that fail, it would need to use something like a (while) loop and a counter, rather than that (repeat) function, which would be an easy adjustment. ....

Like this:

(defun C:TIC ; = Triangles Inside Circle
  (/ cdata ctr-c rad-c n)
  (command "_.circle")
  (while (> (getvar 'cmdactive) 0) (command pause))
  (setq
    cdata (entget (entlast))
    ctr-c (cdr (assoc 10 cdata))
    rad-c (cdr (assoc 40 cdata))
  ); setq
  (initget 6); no zero, no negative
  (setq n (getint "\nHow many triangles? "))
  (while (> n 0)
    (command "_.polygon" 3 pause "_inscribed" pause)
    (if
      (<
        rad-c
        (apply 'max
          (mapcar '(lambda (x) (distance x ctr-c))
            (mapcar 'cdr (vl-remove-if-not '(lambda (y) (= (car y) 10)) (entget (entlast))))
          )
        )
      )
      (progn ; then
        (prompt "\nTriangle extended outside circle.")
        (entdel (entlast))
      )
      (setq ; else
        triangles (cons (entlast) triangles)
        n (1- n)
      )        
    )
  )
  (princ)
)
Kent Cooper, AIA
0 Likes
Message 15 of 17

Kent1Cooper
Consultant
Consultant

@ActivistInvestor wrote:
.... According to what I read, the OP wants to know if a triangle is [entirely] within a circle, and wants to reject any triangle that is not [entirely] within a circle, regardless of whether it is entirely outside, or partially inside/outside the circle. ....

I've been wondering all along whether or not that's what they want, and hoping to hear answers from the OP to various questions raised.

 

Their original code, though it's mistakenly checking within a square  that wraps the Circle rather than within the Circle alone, checks only for whether the center-point  of each triangle is within the test area, not for whether all  of it is.  By that criterion, it would keep  many potential triangles that are partially inside/outside the circle [as well as many that are entirely  outside by surrounding  the Circle while having no part that falls inside it].  But it wouldn't keep all  that cross the Circle -- it would reject any whose center-point is outside, even if some part extends inside.

 

@Anonymous, can you clarify what you're after?  [And, incidentally, I'm curious about the purpose  of such a thing.]

Kent Cooper, AIA
0 Likes
Message 16 of 17

john.uhden
Mentor
Mentor

I guess I owe everyone an apology for being so stupid.  Yes, of course if all the polygon vertices are entirely within the circle then the polygon is entirely within the circles.  But again, if a polygon vertex is on the circle is it within or without?  Is it like tennis sidelines or like football sidelines?

John F. Uhden

0 Likes
Message 17 of 17

ActivistInvestor
Mentor
Mentor

@john.uhden wrote:

I guess I owe everyone an apology for being so stupid.  Yes, of course if all the polygon vertices are entirely within the circle then the polygon is entirely within the circles.  But again, if a polygon vertex is on the circle is it within or without?  Is it like tennis sidelines or like football sidelines?


How edge-cases are handled is mostly application-specific. For example, AutoCAD allows inner-loops to be subtracted from a region in cases where one or more of the inner-loop's vertices lie on the region's boundary. 

0 Likes