review my circle creating code( turtle, python) - python-3.x

im new to python and just started touching turtle. I made this code of circle drawing and i have a few questions:
import turtle
jo = turtle.Turtle()
def polygon(t, r, n, l):
for i in range(30):
jo.fd(n * l)
jo.lt(r * 2 * 3.14)
print(polygon(jo, 2, 3, 4))
turtle.done()
1) i really dont understand how the code i wrote draw a circle.
2) are there any other ways to draw a circle in a similar sytax?
3) is this code is fine or I need to improve it?

i really dont understand how the code i wrote draw a circle.
By shear chance, perhaps. You'll notice that the radius of the circle you draw (~27) has nothing to do with the radius you passed into your polygon() function (2).
You pass radians to the left() function:
jo.lt(r * 2 * 3.14)
although it takes degrees unless told otherwise. You print the result of a function that doesn't return anything:
print(polygon(jo, 2, 3, 4))
Your turtle overshoots at the very end redrawing a small segment of the circle. Finally, you pass a turtle argument to the polygon() function but ignore it and uses the global one instead.
is this code is fine or I need to improve it?
I'd go with something more like:
from math import pi
from turtle import Turtle, Screen
TWO_PI = 2 * pi
def polygon(turtle, radius, sides):
circumference = radius * TWO_PI
for _ in range(sides):
turtle.fd(circumference / sides)
turtle.lt(TWO_PI / sides)
jo = Turtle()
jo.radians()
polygon(jo, 100, 30)
screen = Screen()
screen.mainloop()
are there any other ways to draw a circle in a similar sytax?
from turtle import Turtle, Screen
jo = Turtle()
jo.circle(100, steps=30)
screen = Screen()
screen.mainloop()

Related

Plotting y values of an arc

I am trying to plot the segment of a circle (2D) as an arc in matplotlib. I have written a class which will provide the maths for the segment such as chord length, height of arc etc. I wish to plot the x y values between (0,0) and (0, chord length).
I am currently representing the X values as numpy linspace array (0, chordLength, 200). I am a bit stumped as to how to plot the y values as a similar linspace array so that I can plot these points using matplotlib. The idea behind this is to display the curvature of the earth between two points of a known arc length (great circle distance). I have been reading around sine cosine etc however outside of using cookie cutter formulas for my geometry calculations, I am somewhat lost as to how to apply it to gain my y values.
First, the circle class
import numpy as np
class Circle:
def __init__(self,radiusOfCircle,lengthOfArc):
self.radius = radiusOfCircle
self.circumference = 2 * np.pi * self.radius
self.diameter = self.radius * 2
self.arcLength = lengthOfArc
self.degrees = self.calcDegrees()
self.radians = self.calcRadians()
self.chordLength = self.calcChordLength()
self.sagitta = self.calcSagitta()
self.segmentArea = self.calcSegmentArea()
self.arcHeight = self.calcArcHeight()
#Setters and getters for the Circle class (TODO: setters)
def getRadius(self):
return self.radius
def getCircumference(self):
return self.circumference
def getDiameter(self):
return self.diameter
def getArcLength(self):
return self.arcLength
def getRadians(self):
return self.radians
def getDegrees(self):
return self.degrees
def getChordLength(self):
return self.chordLength
def getSagitta(self):
return self.sagitta
def getSegmentArea(self):
return self.segmentArea
def getArcHeight(self):
return self.arcHeight
#Define Circle class methods
#Calculate the central angle, in degrees, by using the arcLength
def calcDegrees(self):
self.degrees = (self.arcLength / (np.pi * self.diameter)) * 360 #Gives angle in degrees at centre of the circle between the two points (beginning and end points of arcLength)
return self.degrees
#Calculate the central angle in radians, between two points on the circle
def calcRadians(self):#Where theta is the angle between both points at the centre of the circle
self.radians = np.radians(self.degrees) # Convert degrees to radians to work with ChordLength formula
return self.radians
#Returns the chord lengths of the arc, taking theta (angle in radians) as it's argument
#The chord is the horizontal line which separates the arc segment from the rest of the circle
def calcChordLength(self):
self.chordLength = 2*self.radius*np.sin(self.radians/2) #formula works for theta (radians) only, not degrees #confirmed using http://www.ambrsoft.com/TrigoCalc/Sphere/Arc_.htm
return self.chordLength
#Calculates the length of arc, taking theta (angle in radians) as its argument.
def calcArcLength(self):
self.arcLength = (self.degrees/360)*self.diameter*np.pi #confirmed using http://www.ambrsoft.com/TrigoCalc/Sphere/Arc_.htm
return self.arcLength
#Calculates the sagitta of the arc segment. The sagitta is the horizontal line which extends from the bottom
#of the circle to the chord of the segment
def calcSagitta(self):
self.sagitta = self.radius - (np.sqrt((self.radius**2)-((self.chordLength/2)**2))) #Confirmed correct against online calculator https://www.liutaiomottola.com/formulae/sag.htm
return self.sagitta
#Calculates the area of the circular segment/arc).
def calcSegmentArea(self):
self.segmentArea = (self.radians - np.sin(self.radians) / 2) * self.radius**2
return self.segmentArea
#Calculate the height of the arc
#Radius - sagitta of the segment
def calcArcHeight(self):
self.arcHeight = self.radius - self.sagitta
return self.arcHeight
I have not progressed very far with the main program as one of the first tasks im aiming to do is create the y values. This is what I have so far -
from circle import Circle
import numpy as np
import matplotlib.pyplot as plt
def main():
#define centre point
#Circle(radius,arc length)
c1 = Circle(3440.065,35) #Nautical miles radius with 35Nm arc length
chordLength = c1.getChordLength()
arcHeight = c1.getArcHeight()
centerX = chordLength/2
centerY = 0
if __name__ == "__main__":
main()
For context, I wish to use this 'arc' to add elevation data to, akin to - https://link.ui.com/#. I hope to simulate increased curvature over distance which I can use for rough line of sight analysis.
However, first step is getting the y values.
Here is the final solution, I'm not 100% about the maths and how it all works but if anyone is struggling with the same problem - I hope this helps.
The circle class can be found in the original question, located below. Find attached the final code which provides me with what I was after - simulating the curvature of the earth on a graph based upon the arc length (great circle distance).
Big thank you to all who took the time to answer me and help me along my way.
from circle import Circle
import numpy as np
import matplotlib.pyplot as plt
def calcStartAngle(startY,centreY,startX,centreX):
startAngle = np.arctan2(startY-centreY, startX-centreX)
return startAngle
def calcEndAngle(endY,centreY,endX,centreX):
endAngle = np.arctan2(endY-centreY, endX-centreX)
return endAngle
def main():
distance = 200
radius = 3440.065
#create circle object
c1 = Circle(radius,distance)
angle = c1.getDegrees()
xc = c1.getXc()
yc = c1.getYc()
#set start and end points
x1,y1 = 0,0
x2,y2 = distance,0
#get start and end angles
startAngle = calcStartAngle(y1,yc,x1,xc)
endAngle = calcEndAngle(y2,yc,x2,xc)
angleList = np.linspace(startAngle,endAngle,distance)
x_values = np.linspace(x1,x2,distance)
y_valuesList = []
for i in range(len(x_values)):
y = radius*np.sin(angleList[i]) - c1.getArcHeight()
y_valuesList.append(y)
#Create numpy array to hold y values
y_values = np.array(y_valuesList)
plt.ylim(0,50)
plt.plot(x_values,y_values)
plt.show()
if __name__ == "__main__":
main()
Here is an example of the finished product -

Colors are not filling in certain places

I am utilizing turtle to make a xmastree. The task is to color the individual pieces. The "trunk" portion of code works and will fill correctly. The Layer1(), Layer2(), and Layer3() do not fill with color as they should. Any help would be appreciated.
I have looked through the other problems on stack overflow. I have repositioned my variables. Still, nothing.
""" Lab 9 Exercise 3
Author: Jonathan Wheatley
Define a function drawXmasTree(t, blc, scale = 1) You may add further parameters beyond the first three if you wish (note: give any additional parameters default values!). Your
tree should resemble three filed, superimposed green triangles (containing colored ball ornamets) over a brown trunk.
blc and scale should work as in the preceding exercise. Show results at two different scales.
"""
from turtle import Turtle
scale = 1.25
def drawXmasTree():
a = trunk()
b = Layer1()
c = Layer2()
d = Layer3()
def trunk():
t = Turtle()
t.pencolor("brown")
t.fillcolor("brown")
t.shape("turtle")
t.up()
t.goto((scale * -100), (scale * -100))
t.down()
for count in range(2):
t.begin_fill()
t.forward(scale * 10)
t.left(90)
t.forward(scale *100)
t.left(90)
t.end_fill()
t.hideturtle()
def Layer1():
t = Turtle()
t.pencolor("green")
t.fillcolor("green")
t.shape("turtle")
t.up()
t.goto((scale * -150), 0)
t.down()
for count in range(3):
t.begin_fill()
t.forward(scale * 110)
t. left(120)
t.end_fill()
t.hideturtle()
def Layer2():
t = Turtle()
t.pencolor("green")
t.fillcolor("green")
t.shape("turtle")
t.up()
t.goto((scale * -147), 15)
t.down()
for count in range(3):
t.begin_fill()
t.forward(scale * 104)
t.left(120)
t.end_fill()
t.hideturtle()
def Layer3():
t = Turtle()
t.fillcolor("green")
t.pencolor("green")
t.shape("turtle")
t.up()
t.goto((scale * -145), 30)
t.down()
for count in range(3):
t.begin_fill()
t.forward(scale * 100)
t.left(120)
t.end_fill()
t.hideturtle()
def main():
u = drawXmasTree()
main()
When the code is run the turtle should display, draw in the correct colored line, and then the shape should fill.
So, in running so more tests, I seem to be getting positive results by breaking the begin_fill() and end_fill out of the for loop. I don't know why this was working in the Trunk() section but it does not work in the subsequent sections.
Please, if you find a way to make this code better let me know. I would love to learn something and improve my coding.
Thank you.

Python turtle program not drawing polygon properly

When I run the program using the turtle tool, it just makes one horizontal line and does not make a complete shape. I am not sure why this is happening. I have already made a working program that would draw a predetermined shape such as a square. I have already tested my computations and I believe my for-loop is correct. Am I making just some silly syntax error?
# polygon program
# get inputs
side_count = int(input( "How many sides does the polygon have?" ))
side_length = int(input( "How long is each side?" ))
# compute side angle
shape_angle = (side_count - 2) * 180
# import turtle modules
from turtle import *
# measure angles in
degrees()
# drawing speed
speed( 6 )
# square specs
color( 'green' )
width( 3 )
setheading( 0 )
# forloop to draw the polygon
for side in range ( side_count ):
forward ( side_length )
left ( shape_angle )
# all done drawing
done()
Although I agree with #TudorPopescu that this line is your primary issue:
shape_angle = (side_count - 2) * 180
That solution doesn't work for me, so I suggest something simpler to start:
shape_angle = 360 / side_count
Your code reworked with the above fix and style changes:
# polygon program
# import turtle modules
from turtle import *
# get inputs
side_count = int(input("How many sides does the polygon have? "))
side_length = int(input("How long is each side? "))
# compute side angle
shape_angle = 360 / side_count
# measure angles in
degrees() # the default
# drawing speed
speed('normal') # the default
# square specs
color('green')
width(3)
setheading(0) # the default initial heading
# for loop to draw the polygon
for side in range(side_count):
forward(side_length)
left(shape_angle)
# all done drawing
done()
First of all, import all your modules first, its not necessary until you have to use it, but it's a good habit. Also the shape_angle is the total of the whole shape.
To make it work you would have your original code:
shape_angle = (side_count - 2) * 180
Then put it in brackets and divide it by side_count to find the individual angle, the result:
shape_angle = ((side_count - 2) * 180) / side_count
Also get rid of the degrees
import turtle as *
side_count = int(input( "How many sides does the polygon have?" ))
side_length = int(input( "How long is each side?" ))
shape_angle = ((side_count - 2) * 180) / side_count
speed( 6 )
color( 'green' )
width( 3 )
setheading( 0 )
for side in range ( side_count ):
forward ( side_length )
left ( shape_angle )
done()
`

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.

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