So I'm reading a book to learn python and I got to a part about the module turtle.
So after explaining it, it gives you some exercises.
One of them is to define a function that creates regular polygons.
I got this to work.
import turtle
bob = turtle.Turtle()
def polygon(t, l, n):
angle = 360/n
for i in range(n):
t.fd(l)
t.lt(angle)
polygon(bob, 40, 5)
For example this draws a regular pentagon.
The next exercise asks you to draw a "circle" changing the number of sides of the polygon.
The problem is that sometimes it doesn't work and the polygon/circle doesn't close.
I tried to find the solution by changing lots of time both the lenght and the number of sides or only one of the two but I didn't succeed.
For example, lenght = 10 and n°sides = 140 doesn't work, instead lenght = 20 and n°sides = 120 works.
Can someone explain, please?
Found solution.
Being a beginner I forgot about integers and floats.
That's why the "circle" wasn't closing.
Your code works fine in Python 3 but didn't close the polygon in Python 2 due to the difference in how division works. The fix is to simply use 360.0 instead of 360 and then it works fine in both:
from turtle import Turtle, Screen
def polygon(t, l, n):
angle = 360.0 / n
for _ in range(n):
t.fd(l)
t.lt(angle)
bob = Turtle()
polygon(bob, 10, 140)
screen = Screen()
screen.exitonclick()
Python turtle's own circle() method actually draws polygons with the default assumption that 60 sides is sufficient to look like a circle on the screen. Unless the circle is very small (then it uses fewer sides) or the user insists on more (or less) sides via the steps argument.
Try putting 360.0 instead of 360, because the initial value of Python is in integers.
We want to convert it into decimals, that's why we put the .0 after the 360.
Related
Here is the code In the book Thinkpython 2e.
import turtle
import math
bob = turtle.Turtle()
def polygon(t, n, length):
angle = 360 / n
for i in range(n):
t.fd(length)
t.lt(angle)
def circle(t, r):
circumference = 2 * math.pi * r
n = 50
length = circumference / n
polygon(t, n, length)
circle(bob,50)
turtle.mainloop()
I don't understand how it is possible to be a circle, I think it will be a 50-sides polygon, am i right?
A circle has infinitely many points, a screen has finitely many pixels. You are correct that you can't draw true circles on a screen. This isn't to say that drawing a polygon is the only way to approximate a circle on the screen. As #Qwerty rightly points out in the comments you can also do so with trig functions.
Nevertheless, approximating circles by polygons is an ancient approach and was the classical way in which pi was approximated. Also -- it is a fun exercise for turtles.
I have not programmed in python in a while (specifically with the turtle libraries) but if I remember, there is a way easier
import turtle
circumfrence = 80
turtle = turtle.Turtle()
turtle.shape("circle")
turtle.circle(circumfrence / 2)
It's that Simple!
The odd part about your circle() function to me is that n is fixed at 50. At the extremes of large and small circles, this might not be optimal and maybe should be more dynamic. As far as a 50-sided polygon vs. a circle, let's test using the turtle.circle() command:
from turtle import Turtle, Screen
radius = 100
sides = 50
bob = Turtle(shape="turtle")
bob.width(2)
bob.pencolor("red")
bob.circle(radius)
bob.pencolor("green")
bob.circle(radius, steps=sides)
bob.hideturtle()
screen = Screen()
screen.exitonclick()
The turtle.circle() method uses a polygon approximation but it computes the number of sides as a function of the radius with a maxium of 60. For the radius of 100 above, it actually uses only 28 steps so our 50-sided polygon is potentially more accurate!
For a bit of background, this is the game I'm trying to draw in an isometric style.
I'm just trying to get the correct calculations instead of doing it in a hacky way, but one part isn't working, and I'm not quite sure about the other part (I'll save that for another question later on).
So, forgetting the little squares inbetween, the board is made up of n lenels. I'd like to be able to calculate the coordinates for these so I can do further calculations on them, but the trig isn't working, and to the best of my knowledge (bear in mind I last did it years ago), it should be.
This is the simple code to draw the first square:
import turtle
import math
iso_angle = 20
grid_length = 100
turtle.right(iso_angle)
turtle.forward(grid_length)
turtle.right(180 - iso_angle * 2)
turtle.forward(grid_length)
turtle.right(iso_angle * 2)
turtle.forward(grid_length)
turtle.right(180 - iso_angle * 2)
turtle.forward(grid_length)
Using sohcahtoa, I thought I'd be able to calculate the width and height of the resulting square, since it's effectively made up of 4 triangles, and I can double the height of one of the triangles.
#s = o / h
#sin(iso_angle) = o / grid_length
#o = sin(iso_angle) * grid_length
height = 2 * sin(iso_angle) * grid_length
width = 2 * cos(iso_angle) * grid_length
However, when I move the turtle down by height, it doesn't fall on the edge of the square. It doesn't even move in a multiple of the distance of the edge, it just seems to end up some random distance. Swapping with width doesn't work either.
Where abouts am I going wrong with this?
As stated in the comments you need to convert to radians which can be done with the
math.radians()
function. So in practice you would end with something like
height = 2 * sin(math.radians(iso_angle)) * grid_length
width = 2 * cos(math.radians(iso_angle)) * grid_length
The cursor module (turtle) takes angles in degrees.
The sin() and cos() math functions take angles in radians. You must convert them. Fortunetly, Python includes convenient functions to do that in the math module:
height = 2 * sin(radians(iso_angle)) * grid_length
Hope this helps.
I'm writing a python spirograph program, and I need some help with converting part of it into a function. The code is attempting to reproduce the result illustrated in the video I found here. One line rotates around the origin, and then another rotates off the end of that, etc.
With a little bit of research into (what I think is) trigonometry, I put together a function rotate(point, angle, center=(0, 0)). The user inputs a point to be rotated, the angle (clockwise) that it is to be rotated by, and the centerpoint for it to be rotated around.
Then, I implemented an initial test, whereby one line rotates around the other. The end of the second line draws as if it were holding a pen. The code's a little messy, but it looks like this.
x, y = 0, 0
lines = []
while 1:
point1 = rotate((0,50), x)
point2 = map(sum,zip(rotate((0, 50), y), point1))
if x == 0:
oldpoint2 = point2
else:
canvas.create_line(oldpoint2[0], oldpoint2[1], point2[0], point2[1])
lines.append( canvas.create_line(0, 0, point1[0], point1[1]) )
lines.append( canvas.create_line(point1[0], point1[1], point2[0], point2[1]) )
oldpoint2 = point2
tk.update()
x += 5
if x > 360 and y > 360:
x -= 360
canvas.delete("all")
time.sleep(1)
y += 8.8
if y > 360: y -= 360
for line in lines:
canvas.delete(line)
lines = []
Great, works perfectly. My ultimate goal is what's in the video, however. In the video, the user can input any arbitrary number of arms, then define the length and angular velocity for each arm. Mine only works with two arms. My question, ultimately, is how to put the code I posted into a function that looks like drawSpiral(arms, lenlist, velocitylist). It would take the number of arms, a list of the velocities for each arm, and a list of the length of each arm as arguments.
What I've Tried
I've already attempted this several times. Initially, I had something that didn't work at all. I got some cool shapes, but definitely not the desired output. I've worked for a few hours, and the closest I could get was this:
def drawSpiral(arms, lenlist, velocitylist):
if not arms == len(lenlist) == len(velocitylist):
raise ValueError("The lists don't match the provided number of arms")
iteration = 0
while 1:
tk.update()
iteration += 1
#Empty the list of points
pointlist = []
pointlist.append((0, 0))
#Create a list of the final rotation degrees for each point
rotations = []
for vel in velocitylist:
rotations.append(vel*iteration)
for n in range(arms):
point = tuple(map(sum,zip(rotate((0, lenlist[n]), rotations[n], pointlist[n]))))
pointlist.append(point)
for point in pointlist:
create_point(point)
for n in range(arms):
print pointlist[n], pointlist[n+1]
This is fairly close to my solution, I feel, but not quite there. Calling drawSpiral(2, [50, 75], [1, 5]) looks like it might be producing some of the right points, but not connecting the right sets. Staring at it for about an hour and trying a few things, I haven't made any progress. I've also gotten pretty confused looking at my own code. I'm stuck! The point rotating around the center is attached to a point that is just flying diagonally across the screen and back. The line attached to the center is stretching back and forth. Can someone point me in the right direction?
Results of further tests
I've set up both functions to plot points at the ends of each arm, and found some interesting results. The first arm, in both cases, is rotating at a speed of 5, and the second at a speed of -3. The loop, outside of the function, is producing the pattern:
The function, called with drawSpiral(2, [50, 50], [5, -3]), produces the result of
It seems to be stretching the top half. With both arms having a velocity of 5, the function would be expected to produce two circles, one larger than the other. However, it produces an upside-down cardioid shape, with the point connected to the center.
Now there's more evidence, can anyone who understands math more than me help me?
Your error is in
for n in range(arms):
point = tuple(map(sum,zip(rotate((0, lenlist[n]), rotations[n], pointlist[n]))))
pointlist.append(point)
Specifically,
rotate((0, lenlist[n])
replace it with
for n in range(arms):
point = tuple(map(sum,zip(rotate((pointlist[n][0], lenlist[n]), rotations[n], pointlist[n]))))
pointlist.append(point)
You go against the usual mathematical notation for polars (circular graphs) and that caused your confusion and eventual issues. As far as I can tell your function is plotting an (X,Y) point (0,length) and then finding the difference between that point and the center point (which is correctly defined as the last point you found) and rotating it around that center. The issue is that (0,length) is not 'length' away from the center. By replacing the (0,lenlist[n]) with (pointlist[n][0],lenlist[n]) makes the next point based upon the last point.
Also I would recommend editing your rotate function to be rotate(length,angle,centerpoint) which would simplify the inputs to a more traditional representation.
Write a function named fatLine(). The function fatLine() takes
three parameters:
a turtle, t
an integer, segments, that is the number of segments in the line that is drawn
an integer, increment, that is how much wider each successive segment of the line is
The function fatLine() should use the turtle t to draw a line
composed of connected segments. Each segment should be of length 50.
The width of the first line segment should be (the parameter)
increment, and each successive segment should be wider than the
preceding segment by increment. For example, if segments = 5 and
increment = 10, the following is correct output
I tried coding this with three parameters and i am not sure how else i would make it run. Any help would be great Thanks.
I am trying to code this in idle but i have no luck. Please help with any idea on how to execute.
Since it's been five years, it's time this question, despite not showing coding effort, had an answer:
from turtle import Screen, Turtle
def fatLine(t, segments, increment):
width = increment
for _ in range(segments):
t.width(width)
t.forward(50)
width += increment
screen = Screen()
turtle = Turtle(visible=False)
turtle.penup()
turtle.backward(200)
turtle.pendown()
fatLine(turtle, 8, 10)
screen.exitonclick()
I have a beginning star. Now, how would I make this into a fractal?
import turtle
turing = turtle.Turtle()
for i in range(5):
turing.forward(110)
turing.left(216)
A fractal is something that repeats with some variation. So put your star-loop code into a loop and repeat it several times. Change something after doing each star-loop. You could change where the turtle is, or what angle it is pointing at, or how long the side of the next star will be, or any or all of these.
Following #mgkrebbs general philosophy, with a simple fractal that deflects a line, we can make all the lines of the deflection smaller duplicates of the fractal. Your star is tricky to work with but since it has verticies, we can recursively put smaller stars at each vertex:
from turtle import Turtle, Screen
def star(turtle, length, depth):
turtle.left(90)
for _ in range(5):
turtle.forward(length)
heading = turtle.heading()
if depth > 1:
star(turtle, length / 2, depth - 1)
turtle.setheading(heading)
turtle.left(216)
turing = Turtle()
turing.speed("fastest")
star(turing, 180, 3)
turing.hideturtle()
screen = Screen()
screen.exitonclick()
As the depth increases, you can see the stars start to overlap -- making the image larger by increasing length, or making the recursions a smaller fraction of the length, may help.
OUTPUT