netrate
netrate

Reputation: 443

Python / graphics.py - Points on a circle, looking to stop object from being drawn if outside the drawing area?

enter image description here

I am creating a simple drawing program using Zelle's graphics.py in Python

I have a rectangular drawing area and I am trying to get my drawing to stay within the confines of the rectangle without overlap. One of the challenges is that any drawn object is close to the line of the boundaries of the rectangle (although not technically not outside the drawing area) will draw anyway and cause overlap (see attached image)

Here is what I worked on (NOTE : I have not included this practice code because it is included in the main code):

PRACTICE and TESTING

I then took the formula into my drawing program to test if it would work. Right away, I had to use a clone() for the circle because the "for loop" was drawing the same object in the same place over and over giving an error.

After that was fixed, I still could not get the "for loop" and circle formula to work for me. I then thought about removing all items from the win.items[:] list IF the drawing was outside of the boundary of the rectangle. I tried this and still could not get it to work. Here is the code of the attempt.

from graphics import *
import random
import math
win = GraphWin("DRAG", 500, 500)
win.master.attributes('-topmost', True)
drawrect=Rectangle(Point(50,50),Point(450,300))
drawrect.setFill("white")
drawrect.draw(win)
testlist=[]

def motion(event):
    global radius
    x1, y1 = event.x, event.y
    if (x1 > 50 and x1 < 450) and (y1 > 50 and y1 < 300):
        circ = Circle(Point(x1, y1), radius)
        circ.setFill("black")
        circ1 = circ.clone()
        cx = circ.getCenter().getX()
        cy = circ.getCenter().getY()
        for i in range(0, 360):
            x = radius * math.cos(i) + cx
            y = radius * math.sin(i) + cy
            if (x > 50 and x < 450) and (y > 50 and y < 300):
                circ1 = circ.clone()
                circ1.draw(win)
                print("drawing")
            else:
                circ1 = circ.clone()
                testlist.append(circ1)
                print(testlist)
                print(win.items)
                for item in win.items[1:]:
                    print("This is ITEM in win.items list:", item)
                    if item in testlist:
                        input("YES -  input waiting for enter")
                        for i in win.items[1:]:
                            circ.undraw()
                            circ1.undraw()
                            win.update()
                    else:
                        input("NO  -  input waiting for enter")
radius = 40
win.bind('<B1-Motion>', motion)
win.mainloop()

Upvotes: 0

Views: 854

Answers (1)

furas
furas

Reputation: 142681

If you want only full circles then you need only

    if (50+radius < x1 < 450-radius) and (50+radius < y1 < 300-radius):

like

def motion(event):

    x1, y1 = event.x, event.y
    
    if (50+radius < x1 < 450-radius) and (50+radius < y1 < 300-radius):
        circ = Circle(Point(x1, y1), radius)
        circ.setFill("black")
        circ.draw(win)

Full code:

from graphics import *

# --- functions ---

def motion(event):

    x1, y1 = event.x, event.y
    
    if (50+radius < x1 < 450-radius) and (50+radius < y1 < 300-radius):
        circ = Circle(Point(x1, y1), radius)
        circ.setFill("black")
        circ.draw(win)
        
# --- main ---

radius = 40

win = GraphWin("DRAG", 500, 500)
#win.master.attributes('-topmost', True)

drawrect = Rectangle(Point(50, 50), Point(450, 300))
drawrect.setFill("white")
drawrect.draw(win)

win.bind('<B1-Motion>', motion)

win.mainloop()

EDIT:

If you would to crop circles then it would be problem.

My first idea was to use directly tkinter.Canvas() and it will crop elements. But it would need to write all code for drawing Circle and other objects.

So I took code from GraphicWin() which is tkinter.Canvas() with all functions to draw Circle and other objects and little modify - and now you can put in window similar to other objects.

enter image description here

from graphics import *

# --- functions ---

class Canvas(GraphWin):

    """A GraphWin is a toplevel window for displaying graphics."""

    def __init__(self, master, x, y, width=200, height=200, autoflush=True, **kwarg):
        tk.Canvas.__init__(self, master, width=width, height=height,
                           highlightthickness=0, bd=0,  **kwarg)
        
        self.x = x
        self.y = y
        
        #self.foreground = "black"
        self.items = []
        self.mouseX = None
        self.mouseY = None
        self.bind("<Button-1>", self._onClick)
        self.bind_all("<Key>", self._onKey)
        self.height = int(height)
        self.width = int(width)
        self.autoflush = autoflush
        self._mouseCallback = None
        self.trans = None
        self.closed = False

        self.lastKey = ""
        if autoflush: update()   # it needs to use `import *`

    def draw(self, canvas):
        self.id = canvas.create_window((self.x, self.y), window=self._w, anchor='nw')
        
# --- functions ---

def motion1(event):
    
    x1, y1 = event.x, event.y
    
    circ = Circle(Point(x1, y1), radius)
    circ.setFill("black")
    #circ.setOutline("red")
    circ.draw(canvas1)

def motion2(event):
    
    x1, y1 = event.x, event.y
    
    circ = Circle(Point(x1, y1), radius)
    circ.setFill("red")
    circ.setOutline("red")
    circ.draw(canvas2)

# --- main ---

radius = 40

win = GraphWin("DRAG", 500, 700)
#win.master.attributes('-topmost', True)

# Canvas(win, x, y, width, height, ...)
canvas1 = Canvas(win, 50, 50, 400, 250, bg='white')
canvas1.draw(win)
canvas1.bind('<B1-Motion>', motion1)

canvas2 = Canvas(win, 50, 350, 400, 250, bg='white')
canvas2.draw(win)
canvas2.bind('<B1-Motion>', motion2)

# draw on canvas
r = Rectangle(Point(100, 100), Point(150, 150))
r.setFill('red')
r.setOutline("red")
r.draw(canvas1)

win.mainloop()

EDIT:

This better shows that circles are croped.

enter image description here

Upvotes: 1

Related Questions