Python Turtle draw centered square - python

I need to draw a square given a center point using the turtle module.
def drawCentSq(t,center,side):
xPt=center[0]
yPt=center[1]
xPt-=int(side/side)
yPt+=int(side/side)
t.up()
t.goto(xPt,yPt)
t.down()
for i in range(4):
t.forward(side)
t.right(90)
def main():
import turtle
mad=turtle.Turtle()
wn=mad.getscreen()
print(drawCentSq(mad,(0,0),50))
main()
I'm having a hard time making my turtle go to the right starting point.

You need:
xPt-=int(side/2.0)
yPt+=int(side/2.0)
As it was you were just += and -= 1.

I need to draw a square given a center point using the turtle module.
As #seth notes, you can do this by fixing the center calculation in your code:
from turtle import Turtle, Screen
def drawCentSq(turtle, center, side):
""" A square is a series of perpendicular sides """
xPt, yPt = center
xPt -= side / 2
yPt += side / 2
turtle.up()
turtle.goto(xPt, yPt)
turtle.down()
for _ in range(4):
turtle.forward(side)
turtle.right(90)
yertle = Turtle()
drawCentSq(yertle, (0, 0), 50)
screen = Screen()
screen.exitonclick()
But let's step back and consider how else we can draw a square at a given point of a given size. Here's a completely different solution:
def drawCentSq(turtle, center, side):
""" A square is a circle drawn at a rough approximation """
xPt, yPt = center
xPt -= side / 2
yPt -= side / 2
turtle.up()
turtle.goto(xPt, yPt)
turtle.right(45)
turtle.down()
turtle.circle(2**0.5 * side / 2, steps=4)
turtle.left(45) # return cursor to original orientation
And here's yet another:
STAMP_UNIT = 20
def drawCentSq(turtle, center, side):
""" A square can be stamped directly from a square cursor """
mock = turtle.clone() # clone turtle to avoid cleaning up changes
mock.hideturtle()
mock.shape("square")
mock.fillcolor("white")
mock.shapesize(side / STAMP_UNIT)
mock.up()
mock.goto(center)
return mock.stamp()
Note that this solution returns a stamp ID that you can pass to yertle's clearstamp() method to remove the square from the screen if/when you wish.

Related

How to make the center point the center of my square?

How to make the center point the center of my square? Right now it becomes the corner:
def draw_square(t, center_x, center_y, side_length):
"""
Function draw_square draws a square
Parameters:
t = reference to turtle
center_x = x coordinate of the center of square
center_y = y coordinate of the center of square
side_length = the length of each side
Returns:
Nothing
"""
t.up() #picks up tail of turtle
t.goto(center_x, center_y) #tells turtle to go to center of command
t.down() #puts tail down
for sides in range(4): #creates loop to repeat 4 times
t.left(90) #turns left 90 degrees
t.forward(side_length) #move forward the length given
def main(): #defines main function
import turtle #imports turtle module
t = turtle.Turtle() #attaches turtle to t
draw_square(t, 100, 100, 75) #uses the value to make square
main() #calls function
The solution is simple geometry, no sines nor secants involved. Simply calculate half of your side_length then add it to the X coordinate, and subtract it from your Y coordinate:
from turtle import Screen, Turtle # import turtle module
def draw_square(t, center_x, center_y, side_length):
"""
Function draw_square draws a square
Parameters:
t = reference to turtle
center_x = x coordinate of the center of square
center_y = y coordinate of the center of square
side_length = the length of each side
Returns:
None
"""
offset = side_length/2
t.penup() # picks up pen of turtle
t.goto(center_x, center_y) # tell turtle to go to center of drawing
t.dot() # visualize center of square (for debugging)
t.goto(center_x + offset, center_y - offset) # adjust for drawing from corner
t.pendown() # put pen down
for _ in range(4): # create loop to repeat 4 times
t.left(90) # turn left 90 degrees
t.forward(side_length) # move forward the length given
def main(): # define main function
t = Turtle() # attach turtle to t
draw_square(t, 100, 100, 75) # use the values to make a square
screen = Screen()
main() # call function
screen.exitonclick()

Python Turtle Checkerboard

import turtle
def main():
t=turtle
s=int(input("Enter the length of each square: "))
t.screensize(2000,2000,"lightblue")
for row in range(0,5):
for column in range(0,5):
if (row+column)%2==0:
t.pendown()
t.fillcolor("black")
t.begin_fill()
square(s,row,column)
else:
t.pendown()
t.fillcolor("white")
t.begin_fill()
square(s,row,column)
t.goto(s+row*s,s+column*s)
def square(s,row,column):
t=turtle
t.penup()
n=0
for count in range(4):
t.pendown()
t.forward(s)
t.left(90)
t.end_fill()
t.penup()
main()
So today I was given an assignment that asked me to create a 5 by 5 checkerboard. So far, I have this code which manages to create most of the checkerboard. However, I still have a mistake somewhere or I am missing some key information.
The attached picture shows what the program looks like with the error.
The program started by creating the black square, which can be seen on the bottom left corner. Then it worked up until the top right corner, where the empty space can be seen.
Please help.
Let's try stamping instead of drawing. This gains us speed while simplifying our logic. We stamp one large black square to represent the board, then stamp the white squares onto it:
from turtle import Turtle, Screen
SQUARES_PER_SIDE = 5
CURSOR_SIZE = 20
def main():
length = int(input("Enter the length of each square: "))
screen = Screen()
screen.bgcolor("lightblue")
turtle = Turtle('square', visible=False)
turtle.shapesize(SQUARES_PER_SIDE * length / CURSOR_SIZE)
turtle.speed('fastest')
turtle.stamp() # black background
turtle.shapesize(length / CURSOR_SIZE)
turtle.fillcolor("white")
turtle.penup()
edge = (1 - SQUARES_PER_SIDE) / 2 * length # center of left or bottom square
turtle.goto(edge, edge)
for row in range(SQUARES_PER_SIDE):
for column in range(SQUARES_PER_SIDE):
if (row + column) % 2 == 0:
turtle.stamp() # white square
turtle.forward(length)
turtle.goto(edge, edge + (row + 1) * length)
screen.exitonclick()
main()
OUTPUT
Moving t.goto(s+row*s,s+column*s) to beginning of inner for loop does the trick.
Basically we need to move turtle to starting position first and then start drawing.
I also cleaned up the code to put redundant lines inside square function.
Also, added t.penup() so that turtle doesn't show draw until it has reached starting position and start drawing.
import turtle
def main():
t=turtle
t.penup()
s=int(input("Enter the length of each square: "))
t.screensize(2000,2000,"lightblue")
for row in range(0,5):
for column in range(0,5):
t.goto(s+row*s,s+column*s)
if (row+column)%2==0:
square(s,row,column,"black")
else:
square(s,row,column,"white")
def square(s,row,column,color):
t=turtle
t.pendown()
t.fillcolor(color)
t.begin_fill()
t.penup()
n=0
for count in range(4):
t.pendown()
t.forward(s)
t.left(90)
t.end_fill()
t.penup()
main()
Anil_M beat me to it by a few minutes; but I wanted to offer some additional code clean-up, as you've got too many needless penups, pendowns and unnecessary parameter passing going on.
Try this:
import turtle
t = turtle.Turtle()
t.speed(0)
def main():
s=int(input("Enter the length of each square: "))
for row in range(5):
for column in range(5):
if (row+column)%2==0:
color = "black"
else:
color = "white"
t.penup()
t.goto(row*s,column*s)
t.pendown()
filled_square(s, color)
def filled_square(s, color):
t.fillcolor(color)
t.begin_fill()
for count in range(4):
t.forward(s)
t.left(90)
t.end_fill()
main()

Writing a function that asks a user to input a color and then fills a shape with that color

My task is to write a function, drawCircle(radius,fillColor), that asks a user for the specific radius of the circle and which color they'd like the circle to be filled.
I have the circle-drawing down, but I'm struggling with getting the circle to fill with the user-defined color. Any help would be greatly appreciated.
import turtle
def drawCircle(radius, fillColor):
x=360/300 #This gives the angle
r=radius#This is the radius of the circle.
c=fillColor
c=str("")
z=1 #Placeholder for the while loop.
win=turtle.Screen()
tom=turtle.Turtle()
fillColor=tom.color()
tom.begin_fill()
while (z<=300):
tom.forward(r)
tom.right(x)
tom.forward(r)
z=z+1
win.exitonclick()
tom.end_fill()
This is my function call: drawCircle(1,"red")
There are several problems with your code:
You call win.exitonclick before tom.end_fill, so programm exits before filling (as it happens on end_fill)
You do "fillColor=tom.color()" with gets you current color. Instead use "tom.fillcolor(fillColor)"
Unnecessary copying of variables radius->r and fillColor->c
This is python. Use for whenever possible. Instead of counting using z use:
for _ in range(300):
My final code:
import turtle
def drawCircle(radius, fillColor):
x = 360/300 # This gives the angle
win = turtle.Screen()
tom = turtle.Turtle()
tom.fillcolor(fillColor)
tom.begin_fill()
for _ in range(300):
tom.forward(radius)
tom.right(x)
tom.forward(radius)
tom.end_fill()
win.exitonclick()
drawCircle(1, "red")
I have the circle-drawing down
Before addressing your fill issue, I'd argue that your premise isn't true, you don't have circle-drawing down. As #Mysak0CZ shows, your circle of radius 1 is huge -- 1 what? You're drawing a circle but have no real control over its size.
As a professional turtle wrangler, I'd go about the problem as follows. Not only your angle needs to be divided by the number of segments you plan to draw, but you need to compute a circumference based on the requested radius and chop that up as well. I do so below and include a call to turtle's own .circle() method to show that we're in the right ballpark. And I fix your minor fill issue:
import math
from turtle import Turtle, Screen # force object-oriented turtles
SEGMENTS = 60 # how many lines make up the circle
def drawCircle(radius, fillColor):
distance = math.pi * radius * 2 / SEGMENTS # circumference / SEGMENTS
angle = 360 / SEGMENTS
turtle.fillcolor(fillColor)
turtle.begin_fill()
for _ in range(SEGMENTS):
turtle.forward(distance)
turtle.left(angle) # left for .circle() compatibility
turtle.end_fill()
screen = Screen()
turtle = Turtle()
drawCircle(100, 'red')
turtle.circle(100) # for comparison
screen.exitonclick()
Here is my code for a pink circle if you are going through the same Python learning resource. I think the original code was missing an argument.
import turtle
def drawPolygon(t, sideLength, numSides):
t.goto(0, 0)
turnAngle = 360 / numSides
for i in range(numSides):
t.forward(sideLength)
t.right(turnAngle)
def drawCircle(anyTurtle, radius):
circumference = 2 * 3.1415 * radius
sideLength = circumference / 360
drawPolygon(anyTurtle, sideLength, 360)
def drawFilledCircle(anyTurtle, radius, color):
anyTurtle.fillcolor(color)
anyTurtle.begin_fill()
drawCircle(anyTurtle, radius)
anyTurtle.end_fill()
anyTurtle.hideturtle()
wn = turtle.Screen()
wheel = turtle.Turtle()
drawFilledCircle(wheel, 80, "pink")
wn.exitonclick()

Python turtle concentric circles

I'm being really bugged by a task:
User inputs radius r and then turtle draws the circle then proceeds to draw another circle with the same center but 10 px smaller until the radius is 0
First let us approximate a circle as a regular polygon with 36 sides/segments.
To draw this shape given a radius r we need to know;
The length of each segment
The angle to turn between each segment
To calculate the length, we first need the circumference, which is 2πr (we will approximate pi as 3.1415), giving us
circumference = 2 * 3.1415 * radius
Next we divide this by the number of segments we are approximating, giving
circumference = 2 * 3.1415 * radius
seg_lenght = circumferece/36
Now we need the angle difference between the segments, or the external angle. This is simply 360/n for a regular n-gon(polygon with n sides), so we do 360/36 = 10
We can now define a function to generate the segment length and draw the circle:
def circle_around_point(radius):
circumference = 2 * 3.1415 * radius
seg_length = circumference/36
penup()
fd(radius) #Move from the centre to the circumference
right(90) #Face ready to start drawing the circle
pendown()
for i in range(36): #Draw each segment
fd(seg_length)
right(10)
penup()
right(90) #Face towards the centre of the circle
fd(radius) #Go back to the centre of the circle
right(180) #Restore original rotation
pendown()
Now for the concentric circles:
def concentric_circles(radius):
while radius > 0:
circle_around_point(radius)
radius -= 10
It's not clear why #IbraheemRodrigues felt the need to recode turtle's circle() function based on your problem description, but we can simplify his solution by not reinventing the wheel:
def circle_around_point(turtle, radius):
is_down = turtle.isdown()
if is_down:
turtle.penup()
turtle.forward(radius) # move from the center to the circumference
turtle.left(90) # face ready to start drawing the circle
turtle.pendown()
turtle.circle(radius)
turtle.penup()
turtle.right(90) # face awary from the center of the circle
turtle.backward(radius) # go back to the center of the circle
if is_down:
turtle.pendown() # restore original pen state
def concentric_circles(turtle, radius):
for r in range(radius, 0, -10):
circle_around_point(turtle, r)
The key to circle() is that the current position is on the edge of the circle so you need to shift your position by the radius to make a specific point the center of the circle.
However, to solve this problem, I might switch from drawing to stamping and do it this way to speed it up and simplify the code:
import turtle
STAMP_SIZE = 20
radius = int(input("Please input a radius: "))
turtle.shape('circle')
turtle.fillcolor('white')
for r in range(radius, 0, -10):
turtle.shapesize(r * 2 / STAMP_SIZE)
turtle.stamp()
turtle.mainloop()
However, this draws crude circles as it's blowing up a small one:
To fix that, I might compromise between the two solutions above and do:
import turtle
radius = int(input("Please input a radius: "))
turtle.penup()
turtle.forward(radius)
turtle.left(90)
turtle.pendown()
turtle.begin_poly()
turtle.circle(radius)
turtle.penup()
turtle.end_poly()
turtle.addshape('round', turtle.get_poly()) # 'circle' is already taken
turtle.right(90)
turtle.backward(radius)
turtle.shape('round')
turtle.fillcolor('white')
for r in range(radius - 10, 0, -10):
turtle.shapesize(r / radius)
turtle.stamp()
turtle.mainloop()
This improves circle quality by shrinking a large one instead of enlarging a small one:
Where quality of the circle can be controlled using the steps= argument to the call to circle().
But, if I really wanted to minimize code while keeping quality high and speed fast, I might do:
import turtle
radius = int(input("Please input a radius: "))
for diameter in range(radius * 2, 0, -20):
turtle.dot(diameter, 'black')
turtle.dot(diameter - 2, 'white')
turtle.hideturtle()
turtle.mainloop()
The dot() method draws from the center instead of the edge, uses diameters instead of radii, draws only filled circles, and seems our best solution to this particular exercise:
import turtle
#### ##### #### Below class draws concentric circles.
class Circle:
def __init__(self, pen, cx, cy, radius):
self.pen = pen
self.cx = cx
self.cy = cy
self.radius = radius
def drawCircle(self):
self.pen.up()
self.pen.setposition( self.cx, self.cy - self.radius )
self.pen.down()
self.pen.circle(self.radius)
def drawConCircle(self, minRadius = 10, delta = 10):
if( self.radius > minRadius ) :
self.drawCircle()
self.radius -= delta # reduce radius of next circle
self.drawConCircle()
#### End class circle #######
win = turtle.Screen()
win.bgcolor("white")
s = Circle( turtle.Turtle(), 0, 0, 200 )
s.drawConCircle()
win.exitonclick()

turtle drawing automatic centering

I'm looking for best way to automatically find starting position for new turtle drawing so that it would be centered in graphics window regardless of its size and shape.
So far I've developed a function that checks with each drawn element turtle position to find extreme values for left, right, top and bottom and that way I find picture size and can use it to adjust starting position before releasing my code. This is example of simple shape drawing with my picture size detection added:
from turtle import *
Lt=0
Rt=0
Top=0
Bottom=0
def chkPosition():
global Lt
global Rt
global Top
global Bottom
pos = position()
if(Lt>pos[0]):
Lt = pos[0]
if(Rt<pos[0]):
Rt= pos[0]
if(Top<pos[1]):
Top = pos[1]
if(Bottom>pos[1]):
Bottom = pos[1]
def drawShape(len,angles):
for i in range(angles):
chkPosition()
forward(len)
left(360/angles)
drawShape(80,12)
print(Lt,Rt,Top,Bottom)
print(Rt-Lt,Top-Bottom)
This method does work however it seems very clumsy to me so I would like to ask more experiences turtle programmers is there a better way to find starting position for turtle drawings to make them centered?
Regards
There is no universal method to center every shape (before you draw it and find all your max, min points).
For your shape ("almost" circle) you can calculate start point using geometry.
alpha + alpha + 360/repeat = 180
so
alpha = (180 - 360/repeat)/2
but I need 180-alpha to move right (and later to move left)
beta = 180 - aplha = 180 - (180 - 360/repeat)/2
Now width
cos(alpha) = (lengt/2) / width
so
width = (lengt/2) / cos(alpha)
Because Python use radians in cos() so I need
width = (length/2) / math.cos(math.radians(alpha))
Now I have beta and width so I can move start point and shape will be centered.
from turtle import *
import math
# --- functions ---
def draw_shape(length, repeat):
angle = 360/repeat
# move start point
alpha = (180-angle)/2
beta = 180 - alpha
width = (length/2) / math.cos(math.radians(alpha))
#color('red')
penup()
right(beta)
forward(width)
left(beta)
pendown()
#color('black')
# draw "almost" circle
for i in range(repeat):
forward(length)
left(angle)
# --- main ---
draw_shape(80, 12)
penup()
goto(0,0)
pendown()
draw_shape(50, 36)
penup()
goto(0,0)
pendown()
draw_shape(70, 5)
penup()
goto(0,0)
pendown()
exitonclick()
I left red width on image.
I admire #furas' explanation and code, but I avoid math. To illustrate that there's always another way to go about a problem here's a math-free solution that produces the same concentric polygons:
from turtle import Turtle, Screen
def draw_shape(turtle, radius, sides):
# move start point
turtle.penup()
turtle.sety(-radius)
turtle.pendown()
# draw "almost" circle
turtle.circle(radius, steps=sides)
turtle = Turtle()
shapes = [(155, 12), (275, 36), (50, 5)]
for shape in shapes:
draw_shape(turtle, *shape)
turtle.penup()
turtle.home()
turtle.pendown()
screen = Screen()
screen.exitonclick()

Categories

Resources