'Python / graphics.py - Points on a circle, looking to stop object from being drawn if outside the drawing area?
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 researched the formula for determining all the points on the circumference of a circle
- Included the formula in a "for loop" to check through all 360 points
- Using test code program, I plotted out the points to ensure the formula worked properly and it drew a circle with all 360 points. A working model is complete.
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()
Solution 1:[1]
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.
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.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |