Turtle inner circle boundary in python - python-3.x

Okay, I've been at this all day and haven't a clue. I need to get my turtle object to draw random lines outside of a circle.
I've made code that restricts the random lines within the boundaries before, so I thought all I had to do was change the sign, but that didn't work. I'm not allowed to use coordinate geometry - it has to be something more basic...
Here's my code in it's current format:
import turtle, random
mRoshi = turtle.Turtle()
def draw_any_shape(myTurtle, sideLength, numSides):
turnAng = 360/numSides
for i in range(numSides):
myTurtle.forward(sideLength)
myTurtle.right(turnAng)
def drawCircle(myTurtle, radius, startX, startY):
circumference = 2*3.1415*radius
sideLength = circumference/360
myTurtle.penup()
myTurtle.goto(startX, startY)
#myTurtle.dot()
myTurtle.goto(startX, startY+radius)
myTurtle.pendown()
draw_any_shape(myTurtle, sideLength, 360)
def stumblingTurtle(myTurtle, radius, startX, startY, paramN5):
circumference = 2*3.1415*radius
myTurtle.speed(6)
drawCircle(myTurtle, radius, startX, startY)
myTurtle.penup()
for i in range(paramN5):
drx = random.randint(-800, 800)
drw = random.randint(-800, 800)
if (drx**2 + drw**2) > radius**2:
myTurtle.goto(drx,drw)
crx = random.randint(-800, 800)
crw = random.randint(-800, 800)
xdif = crx-drx
ydif = crw-drw
for j in range(drx, crx):
for k in range(drw, crw):
if (xdif**2 + ydif**2) > radius**2:
myTurtle.goto(crx,crw)

Does this do what you want? It's also based on code that originally kept the turtle within a circle. It uses Python3 turtle's undo capability to allow the turtle to accidentally wander into the circle and then undo that accident as if it never happened:
import turtle
import random
RADIUS = 50
MAXIMUM_TURN = 45
STEP_SIZE = 10
BORDER = 20
def bounded_random_move():
yertle.forward(STEP_SIZE)
x, y = yertle.position()
if (x * x + y * y) < RADIUS * RADIUS or x < -window_width/2 or x > window_width/2 or y < -window_height/2 or y > window_height/2:
yertle.undo() # undo misstep
turn = random.randint(180 - MAXIMUM_TURN, 180 + MAXIMUM_TURN)
yertle.left(turn)
turtle.ontimer(bounded_random_move, 100)
turtle.setup(RADIUS * 10, RADIUS * 10)
window_width = turtle.window_width() - BORDER
window_height = turtle.window_height() - BORDER
magic_marker = turtle.Turtle(visible=False)
magic_marker.penup()
magic_marker.color("red")
magic_marker.sety(-RADIUS)
magic_marker.pendown()
magic_marker.circle(RADIUS)
yertle = turtle.Turtle(shape="turtle", visible=False)
yertle.speed("fastest")
yertle.penup()
yertle.goto(RADIUS * 2, RADIUS * 2) # start outside circle
yertle.pendown()
yertle.showturtle()
turtle.ontimer(bounded_random_move, 100)
turtle.exitonclick()
My undo trick might not be rigorous enough for everyone, however.

Related

Animating multiple Circles in each frames in Python

I am trying to create the animation in this video using Python. But I stuck on the very first step. Till now I've created a Circle and a point rotating around its circumference. My code is given below. Now I want to plot the y values corresponding to x=np.arange(0, I*np.pi, 0.01) along the x-axis (as shown in update() function in the code). For this I have to define another function to plot these x and y and pass that function inside a new animation.FuncAnimation().
Is there any way to plot everything using only the update() function?
Note I have found a code of this animation in here. But it is written in Java!
My Code
import matplotlib.pyplot as plt
from matplotlib import animation
import numpy as np
W = 6.5
H = 2
radius = 1
I = 2
T = 3
N = 2
plt.style.use(['ggplot', 'dark_background'])
def create_circle(x, y, r):
circle = plt.Circle((x, y), radius=r, fill=False, alpha=0.7, color='w')
return circle
def create_animation():
fig = plt.figure()
ax = plt.axes(xlim=(-2, W + 2), ylim=(-H, H))
circle = create_circle(0, 0, radius)
ax.add_patch(circle)
line1, = ax.plot(0, 1, marker='o', markersize=3, color='pink', alpha=0.7)
def update(theta):
x = radius * np.cos(theta)
y = radius * np.sin(theta)
line1.set_data([0, x], [0, y])
return line1,
anim = []
anim.append(animation.FuncAnimation(fig, update,
frames=np.arange(0, I * np.pi, 0.01),
interval=10, repeat=True))
# anim.append(animation.FuncAnimation(fig, update_line, len(x),
# fargs=[x, y, line, line1], interval=10))
plt.grid(False)
plt.gca().set_aspect('equal')
plt.gca().spines['left'].set_visible(False)
plt.gca().spines['top'].set_visible(False)
plt.gca().spines['right'].set_visible(False)
plt.gca().spines['bottom'].set_visible(False)
plt.gca().set_xticks([])
plt.gca().set_yticks([])
plt.show()
if __name__ == '__main__':
create_animation()
Edit. I've improved the task by defining a global variable pos and changing the update() function in the following manner ...The animation now looks better but still having bugs!
Improved Portion
plot, = ax.plot([], [], color='w', alpha=0.7)
level = np.arange(0, I * np.pi, 0.01)
num = []
frames = []
for key, v in enumerate(level):
num.append(key)
frames.append(v)
def update(theta):
global pos
x = radius * np.cos(theta)
y = radius * np.sin(theta)
wave.append(y)
plot.set_data(np.flip(level[:pos] + T), wave[:pos])
line1.set_data([0, x], [0, y])
pos += 1
return line1, plot,
Edit Till now I've done the following:
def update(theta):
global pos
x, y = 0, 0
for i in range(N):
prev_x = x
prev_y = y
n = 2 * i + 1
rad = radius * (4 / (n * np.pi))
x += rad * np.cos(n * theta)
y += rad * np.sin(n * theta)
wave.append(y)
circle = create_circle(prev_x, prev_y, rad)
ax.add_patch(circle)
plot.set_data(np.flip(level[:pos] + T), wave[:pos])
line2.set_data([x, T], [y, y])
line1.set_data([prev_x, x], [prev_y, y])
pos += 1
return line1, plot, line2,
Output
Please help to correct this animation. Or, is there any efficient way to do this animation?
Edit Well, now the animation is partially working. But there is a little issue: In my code (inside the definition of update()) I have to add circles centered at (prev_x, prev_y) of radius defined as rad for each frame. For this reason I try to use a for loop in the definition of update() but then all the circles remains in the figure (see the output below). But I want one circle in each frame with the centre and radius as mentioned above. Also the same problem is with the plot. I try to use ax.clear() inside the for loop but it didn't work.

Why's the red polygon goes out of plane, then returns to its specified place again?

I want to put the red polygon in place of the empty one. But it goes above it first before returning again to it. Can someone help me with that?
Why's the red polygon goes out of plane, then returns to its specified place again?
def Rotating(Rotating_angle, polygon_points): # Drawing the rotated figure
my_points = (re.findall("\(\-?\d*\.?\d*\,\-?\d*\.?\d*\)", polygon_points))
sleep_time = .5
my_new_points = [] # Scale_points
for point in my_points:
new_point = str(point).replace(")", "").replace("(", "").split(",")
# creating a list with all coordinates components
all_coordinates_components = []
all_coordinates_components.append(abs(eval(new_point[0])))
all_coordinates_components.append(abs(eval(new_point[1])))
point = (scale * eval(new_point[0]), scale * eval(new_point[1]))
my_new_points.append(point)
rotated_points = []
for point in my_new_points:
new_point = str(point).replace(")", "").replace("(", "").split(",")
theta = Rotating_angle
X = (eval(new_point[0]) * cos(theta * pi / 180)) - (eval(new_point[1]) * sin(theta * pi / 180))
Y = (eval(new_point[0]) * sin(theta * pi / 180)) + (eval(new_point[1]) * cos(theta * pi / 180))
# length = sqrt((X) ** 2 + (Y) ** 2)
point = (X, Y)
rotated_points.append(point)
# draw steps
time.sleep(sleep_time)
draw_rotation_steps(my_new_points, theta) # draw steps ((((( 3 )))))
# drawing rotated polygon
draw_polygon(rotated_points) # draw rotated polygon ((((( 4 )))))
s = Shape('compound')
poly1 = (my_new_points)
s.addcomponent(poly1, fill="red")
register_shape('myshape', s)
shape('myshape')
polygon = Turtle(visible=False)
polygon.setheading(90)
polygon.speed('slowest')
polygon.penup()
polygon.shape('myshape')
polygon.st()
polygon.circle(0, theta)
pen_dot = Turtle(visible=False)
pen_dot.speed('fastest')
for point in rotated_points:
pen_dot.penup()
pen_dot.goto(point)
pen_dot.pendown()
pen_dot.dot(5, 'blue violet')
I can't reproduce the behaviour you describe. But your code is riddled with issues that should be addressed so perhaps fixing those might also fix the positioning issue:
These loops are nested, but they shouldn't be:
my_new_points = []
for point in my_points:
...
rotated_points = []
for point in my_new_points:
They both should be at the same level.
You shouldn't use eval(). In this situation, use float():
point = (scale * eval(new_point[0]), scale * eval(new_point[1]))
Here, you've already converted the points but you turn them back into strings and reconvert them:
new_point = str(point).replace(")", "").replace("(", "").split(",")
X = (eval(new_point[0]) * cos(theta * pi / 180)) - (eval(new_point[1]) * sin(theta * pi / 180))
when you can simply do:
X = point[0] * cos(theta * pi / 180) - point[1] * sin(theta * pi / 180)
You don't have to put the pen down for the .dot() method to work:
pen_dot.goto(point)
pen_dot.pendown()
pen_dot.dot(5, 'blue violet')
so you can move the penup() out of the loop.
Below is my rework of your example code. I've added just enough code to make it runnable and removed anything that had nothing to do with the problem. See if this gives you any ideas of how to simplify and fix your own code:
import re
from math import sin, cos, pi
from turtle import *
scale = 20
def draw_rotation_steps(points, theta):
''' Not supplied by OP '''
pass
def draw_polygon(rotated_points):
''' Simple replacement since not supplied by OP '''
hideturtle()
penup()
goto(rotated_points[-1])
pendown()
for point in rotated_points:
goto(point)
def Rotating(theta, polygon_points): # Drawing the rotated figure
my_points = re.findall(r"\(\-?\d*\.?\d*\,\-?\d*\.?\d*\)", polygon_points)
my_new_points = [] # Scaled points
for point in my_points:
X, Y = point.replace(")", "").replace("(", "").split(",")
point = (scale * float(X), scale * float(Y))
my_new_points.append(point)
rotated_points = []
for point in my_new_points:
X = point[0] * cos(theta * pi / 180) - point[1] * sin(theta * pi / 180)
Y = point[0] * sin(theta * pi / 180) + point[1] * cos(theta * pi / 180)
point = (X, Y)
rotated_points.append(point)
# draw steps
draw_rotation_steps(my_new_points, theta) # draw steps
# drawing rotated polygon
draw_polygon(rotated_points) # draw rotated polygon
s = Shape('compound')
s.addcomponent(my_new_points, fill="red")
register_shape('myshape', s)
polygon = Turtle('myshape', visible=False)
polygon.setheading(90)
polygon.showturtle()
polygon.circle(0, theta, steps=100) # added steps to visually slow it down
pen_dot = Turtle(visible=False)
pen_dot.penup()
for point in rotated_points:
pen_dot.goto(point)
pen_dot.dot(5, 'blue violet')
Rotating(180, "(-8,-6) (-6,-3) (-3,-4)")
mainloop()

TkInter python - creating points on a canvas to obtain a Sierpinsky triangle

I want to make a program which plots a Sierpinsky triangle (of any modulo). In order to do it I've used TkInter. The program generates the fractal by moving a point randomly, always keeping it in the sides. After repeating the process many times, the fractal appears.
However, there's a problem. I don't know how to plot points on a canvas in TkInter. The rest of the program is OK, but I had to "cheat" in order to plot the points by drawing small lines instead of points. It works more or less, but it doesn't have as much resolution as it could have.
Is there a function to plot points on a canvas, or another tool to do it (using Python)? Ideas for improving the rest of the program are also welcome.
Thanks. Here's what I have:
from tkinter import *
import random
import math
def plotpoint(x, y):
global canvas
point = canvas.create_line(x-1, y-1, x+1, y+1, fill = "#000000")
x = 0 #Initial coordinates
y = 0
#x and y will always be in the interval [0, 1]
mod = int(input("What is the modulo of the Sierpinsky triangle that you want to generate? "))
points = int(input("How many points do you want the triangle to have? "))
tkengine = Tk() #Window in which the triangle will be generated
window = Frame(tkengine)
window.pack()
canvas = Canvas(window, height = 700, width = 808, bg = "#FFFFFF") #The dimensions of the canvas make the triangle look equilateral
canvas.pack()
for t in range(points):
#Procedure for placing the points
while True:
#First, randomly choose one of the mod(mod+1)/2 triangles of the first step. a and b are two vectors which point to the chosen triangle. a goes one triangle to the right and b one up-right. The algorithm gives the same probability to every triangle, although it's not efficient.
a = random.randint(0,mod-1)
b = random.randint(0,mod-1)
if a + b < mod:
break
#The previous point is dilated towards the origin of coordinates so that the big triangle of step 0 becomes the small one at the bottom-left of step one (divide by modulus). Then the vectors are added in order to move the point to the same place in another triangle.
x = x / mod + a / mod + b / 2 / mod
y = y / mod + b / mod
#Coordinates [0,1] converted to pixels, for plotting in the canvas.
X = math.floor(x * 808)
Y = math.floor((1-y) * 700)
plotpoint(X, Y)
tkengine.mainloop()
If you are wanting to plot pixels, a canvas is probably the wrong choice. You can create a PhotoImage and modify individual pixels. It's a little slow if you plot each individual pixel, but you can get dramatic speedups if you only call the put method once for each row of the image.
Here's a complete example:
from tkinter import *
import random
import math
def plotpoint(x, y):
global the_image
the_image.put(('#000000',), to=(x,y))
x = 0
y = 0
mod = 3
points = 100000
tkengine = Tk() #Window in which the triangle will be generated
window = Frame(tkengine)
window.pack()
the_image = PhotoImage(width=809, height=700)
label = Label(window, image=the_image, borderwidth=2, relief="raised")
label.pack(fill="both", expand=True)
for t in range(points):
while True:
a = random.randint(0,mod-1)
b = random.randint(0,mod-1)
if a + b < mod:
break
x = x / mod + a / mod + b / 2 / mod
y = y / mod + b / mod
X = math.floor(x * 808)
Y = math.floor((1-y) * 700)
plotpoint(X, Y)
tkengine.mainloop()
You can use canvas.create_oval with the same coordinates for the two corners of the bounding box:
from tkinter import *
import random
import math
def plotpoint(x, y):
global canvas
# point = canvas.create_line(x-1, y-1, x+1, y+1, fill = "#000000")
point = canvas.create_oval(x, y, x, y, fill="#000000", outline="#000000")
x = 0 #Initial coordinates
y = 0
#x and y will always be in the interval [0, 1]
mod = int(input("What is the modulo of the Sierpinsky triangle that you want to generate? "))
points = int(input("How many points do you want the triangle to have? "))
tkengine = Tk() #Window in which the triangle will be generated
window = Frame(tkengine)
window.pack()
canvas = Canvas(window, height = 700, width = 808, bg = "#FFFFFF") #The dimensions of the canvas make the triangle look equilateral
canvas.pack()
for t in range(points):
#Procedure for placing the points
while True:
#First, randomly choose one of the mod(mod+1)/2 triangles of the first step. a and b are two vectors which point to the chosen triangle. a goes one triangle to the right and b one up-right. The algorithm gives the same probability to every triangle, although it's not efficient.
a = random.randint(0,mod-1)
b = random.randint(0,mod-1)
if a + b < mod:
break
#The previous point is dilated towards the origin of coordinates so that the big triangle of step 0 becomes the small one at the bottom-left of step one (divide by modulus). Then the vectors are added in order to move the point to the same place in another triangle.
x = x / mod + a / mod + b / 2 / mod
y = y / mod + b / mod
#Coordinates [0,1] converted to pixels, for plotting in the canvas.
X = math.floor(x * 808)
Y = math.floor((1-y) * 700)
plotpoint(X, Y)
tkengine.mainloop()
with a depth of 3 and 100,000 points, this gives:
Finally found a solution: if a 1x1 point is to be placed in pixel (x,y), a command which does it exactly is:
point = canvas.create_line(x, y, x+1, y+1, fill = "colour")
The oval is a good idea for 2x2 points.
Something remarkable about the original program is that it uses a lot of RAM if every point is treated as a separate object.

I want to create a 90 degree curve

I have gotten as far as making a set of rays, but I need to connect them. Any help? My code is as follows
from math import *
from graphics import *
i = 1
segments = 15
lastPoint = Point(100,0)
print("Begin")
win = GraphWin("Trigonometry", 1500, 1500)
while i<=segments:
angle =i*pi/segments
y = int(sin(angle)*100)
x = int(cos(angle)*100)
i = i+1
p = Point(x,y)
l = Line(p, lastPoint)
l.draw(win)
print(p.x, p.y)
print("End")
OP code draws only "rays" because, while point p lays on the circle, lastPoint doesn't change between iterations.
We have to update the value of lastPoint to literally the last point calculated in order to draw the arc as a series of consecutive segments.
Here is a modified code, with further explanations as asked by OP in his comment:
from math import *
from graphics import *
# Function to calculate the integer coordinates of a Point on a circle
# given the center (c, a Point), the radius (r) and the angle (a, radians)
def point_on_circle( c, r, a ) :
return Point( int(round(c.x + r*cos(a))), int(round(c.y + r*sin(a))) )
# Define the graphical output window, I'll set the coordinates system so
# that the origin is the bottom left corner of the windows, y axis is going
# upwards and 1 unit corresponds to 1 pixel
win = GraphWin("Trigonometry", 800, 600)
win.setCoords(0,0,800,600)
# Arc data. Angles are in degrees (more user friendly, but later will be
# transformed in radians for calculations), 0 is East, positive values
# are counterclockwise. A value of 360 for angle_range_deg gives a complete
# circle (polygon).
angle_start_deg = 0
angle_range_deg = 90
center = Point(10,10)
radius = 200
segments = 16
angle_start = radians(angle_start_deg)
angle_step = radians(angle_range_deg) / segments
# Initialize lastPoint with the position corresponding to angle_start
# (or i = 0). Try different values of all the previous variables
lastPoint = point_on_circle(center, radius, angle_start)
print("Begin")
i = 1
while i <= segments :
# update the angle to calculate a new point on the circle
angle = angle_start + i * angle_step
p = point_on_circle(center, radius, angle)
# draw a line between the last two points
l = Line(p, lastPoint)
l.draw(win)
print(p.x, p.y)
# update the variables to move on to the next segment which share an edge
# (the last point) with the previous segment
i = i + 1
lastPoint = p
print("End")

How to get a rectangle to move along X axis using checkMouse()?

I'm trying to get a rectangle to move along the X axis but checkMouse() isn't working. What needs to be done to make it work?
from graphics import*
import time
from random import randrange
wd=GraphWin("Catch A Ball",500,500)
wd.setBackground("lightblue")
p1=220 #size of rectangle
p2=250
for i in range(1):
spt1=Point(p1,480)
spt2=Point(p2,500)
rct=Rectangle(spt1,spt2)
rct.setOutline("black")
rct.setFill("black")
rct.draw(wd)
p=wd.checkMouse()
c=rct.getCenter()
dx=p.getX() - c.getX()
dy=p.getY() - c.getY()
rct.move(dx,0)
You're missing a loop and I recommend working with getMouse() initially until you've a need to switch to checkMouse():
from graphics import *
window = GraphWin("Catch A Ball", 500, 500)
window.setBackground("lightblue")
point1 = Point(220, 480) # size of rectangle
point2 = Point(250, 500)
rectangle = Rectangle(point1, point2)
rectangle.setFill("black")
rectangle.draw(window)
while True:
point = window.getMouse()
if point is not None: # so we can switch to checkMouse() if desired
center = rectangle.getCenter()
dx = point.getX() - center.getX()
dy = point.getY() - center.getY()
rectangle.move(dx, 0)
You need to add some sort of action/event to break out of the while True: infinite loop.

Resources