I want to draw a smily using python turtle. Circle extent will be 120.
I am trying following
import turtle
turtle.circle(100)
turtle.up()
turtle.goto(0, 30)
turtle.down()
turtle.circle(40, 120)
Problem is smile part. How to draw a face smile?
You can do the smile (and smiley face) with the commands that the turtle module provides. The key to getting your arc (of a circle) drawn correctly lies in the combination of goto() and setheading(), see below:
import turtle
turtle.up()
turtle.goto(0, -100) # center circle around origin
turtle.down()
turtle.begin_fill()
turtle.fillcolor("yellow") # draw head
turtle.circle(100)
turtle.end_fill()
turtle.up()
turtle.goto(-67, -40)
turtle.setheading(-60)
turtle.width(5)
turtle.down()
turtle.circle(80, 120) # draw smile
turtle.fillcolor("black")
for i in range(-35, 105, 70):
turtle.up()
turtle.goto(i, 35)
turtle.setheading(0)
turtle.down()
turtle.begin_fill()
turtle.circle(10) # draw eyes
turtle.end_fill()
turtle.hideturtle()
turtle.done()
I'm not going to claim to have mastered positioning arcs, I'm still doing too much trial and error, but it is possible if you take the time to learn how the turtle operators work.
The turtle module does not provide advanced methods to drow arcs of circles or parabolas, however it isn't hard to come up with the right equations.
A circle C with origin at (x0, y0) and radius r is described by the equation:
(x-x0)^2 + (y-y0)^2 = r^2
We can expand this to get:
x^2 -2x·x0 + x0^2 + y^2 -2y·y0 + y0^2 - r^2 = 0
Now we can take for example the y as variable and obtain the second degree equation:
y^2 -2y0·y +(x^2-2x0·x+x0^2+y0^2-r^2) = 0
Let d = x^2-2x0·x+x0^2+y0^2-r^2. We can solve this using the usual formula:
y1 = (2y0 + sqrt(4y0^2 - 4d))/2 = y0 + sqrt(y0^2 - d)
y2 = (2y0 - sqrt(4y0^2 - 4d))/2 = y0 - sqrt(y0^2 - d)
So now you can write down a function that, given the coordinates of the center of the circle and the radius, and the value for x it returns the coordinate y and use these coordinates to move the turtle:
def find_circle_coord(x0, y0, r, x):
d = x**2 - 2*x0*x + x0**2 + y0**2 - r**2
D = y0**2 - d
if D < 0:
raise ValueError("Value for x is outside the circle!")
return y0 - D**.5, y0 + D**.5
As in:
>>> # bob is a turtle
>>> bob.pendown()
>>> for x in range(-50, 50):
... y1, _ = find_circle_coord(0, 0, 100, x)
... bob.goto(x, y1)
By choosing one of the two coordinates returned you choose whether to draw the "upper" or "lower" arc.
to draw a smile you simply have to come up with two circles one smaller and a larger one but with the center slightly above the previous one so that they have that kind of intersection.
So you have to choose a circle C1 centered in x0, y0 with radius r and a circle C2 centered in x0, y0+K with radius R > r.
Note that C2's center is vertically aligned with C1 center (hence the same x coordinate for the center) but it is above it (note: I'm not sure of y-axis orientation so the +K might be -K...)
To find the intersections you have to solve the system of their equations:
(x-x0)^2 + (y-y0)^2-r^2 = 0
(x-x0^2) + (y-y0-K)^2-R^2 = 0
Now subtracting the second equation from the first you get:
(y-y0)^2 - (y-y0-K)^2 -r^2 + R^2 = 0
y^2 -2y·y0 +y0^2 - y^2 -y0^2 -K^2 +2y·y0 +2K·y -2K·y0 -r^2 + R^2 = 0
-K^2 +2K·y -2K·y0 -r^2 + R^2 = 0
Where you get:
y = (K^2 +2K·y0 +r^2 -R^2)/(2K)
And you can substitute the y in one of the circle equations to obtain the xs corresponding to such y. Then you know which x to draw using find_circle_coord.
If you want to make the mouth more open you could use a circle and a parabola. To find the y value of a point on a parabole it's easy:
def find_parabola_coord(a, b, c, x):
return a*x**2 + b*x + c
Or you could use the form of equation of a parabola given its vertex V = (xv, yv):
y - yv = a(x - xv)^2
where a controls how steep the parabola is.
import turtle
bob = turtle.Turtle()
bob.circle(100)
bob.penup()
bob.goto(50,100)
bob.pendown()
bob.circle(10)
bob.penup()
bob.goto(-50,100)
bob.pendown()
bob.circle(10)
bob.penup()
bob.goto(0,50)
bob.pendown()
bob.circle(100,30)
bob.penup()
bob.goto(0,50)
bob.pendown()
bob.circle(0,-30)
bob.circle(100,-30)
Related
I'm trying to draw a cloud background but the code I have found and used adds a line at the end that I don't need, anyone know how to fix this?
This code works perfectly otherwise I've made a few modifications but none have fixed the problem and threw errors so they are removed from this bit of code.
Here's where I got the original code from:
https://pythonturtle.academy/tutorial-drawing-clouds-with-python-turtle/
Here's the code:
import math
import random
turtle.speed(0)
turtle.hideturtle()
turtle.up()
turtle.fillcolor('white')
turtle.pensize(2)
n = 500*size # number of points on each ellipse
# X,Y is the center of ellipse, a is radius on x-axis, b is radius on y-axis
# ts is the starting angle of the ellipse, te is the ending angle of the ellipse
# P is the list of coordinates of the points on the ellipse
def ellipse(X,Y,a,b,ts,te,P):
t = ts
for i in range(n):
x = a*math.cos(t)
y = b*math.sin(t)
P.append((x+X,y+Y))
t += (te-ts)/(n-1)
# computes Euclidean distance between p1 and p2
def dist(p1,p2):
return ((p1[0]-p2[0])**2 + (p1[1]-p2[1])**2)**0.5
# draws an arc from p1 to p2 with extent value ext
def draw_arc(p1,p2,ext):
turtle.up()
turtle.goto(p1)
turtle.seth(turtle.towards(p2))
a = turtle.heading()
b = 360-ext
c = (180-b)/2
d = a-c
e = d-90
r = dist(p1,p2)/2/math.sin(math.radians(b/2)) # r is the radius of the arc
turtle.seth(e) # e is initial heading of the circle
turtle.down()
turtle.circle(r,ext,100)
return (turtle.xcor(),turtle.ycor()) # returns the landing position of the circle
# this position should be extremely close to p2 but may not be exactly the same
# return this for continuous drawing to the next point
def cloud(P):
step = n//10 # draw about 10 arcs on top and bottom part of cloud
a = 0 # a is index of first point
b = a + random.randint(step//2,step*2) # b is index of second point
p1 = P[a] # p1 is the position of the first point
p2 = P[b] # p2 is the position of the second point
turtle.fillcolor('white')
turtle.begin_fill()
p3 = draw_arc(p1,p2,random.uniform(70,180)) # draws the arc with random extention
while b < len(P)-1:
p1 = p3 # start from the end of the last arc
if b < len(P)/2: # first half is top, more ragged
ext = random.uniform(70,180)
b += random.randint(step//2,step*2)
else: # second half is bottom, more smooth
ext = random.uniform(30,70)
b += random.randint(step,step*2)
b = min(b,len(P)-1) # make sure to not skip past the last point
p2 = P[b] # second point
p3 = draw_arc(p1,p2,ext) # draws an arc and return the end position
turtle.end_fill()
P = [] # starting from empty list
ellipse(x,y,15*size,10*size,0,math.pi,P) # taller top half
ellipse(x,y,15*size,2.5*size,math.pi,math.pi*2,P) # shorter bottom half
cloud(P)
This code works perfectly
The code doesn't work perfectly as posted: turtle module isn't imported; size isn't defined; the window closes immediately after drawing. Adding back missing bits, I don't get the problematic extra line you describe. (Though most likely a penup() / pendown() issue.)
I've rewritten the code below to run. And I've simplified it by using object-oriented turtle instead of the functional turtle API, made use of turtle vectors and switched the mix of radians and degrees to all radians instead:
from math import sin, cos, pi
from random import randint, uniform
from turtle import Screen, Turtle, Vec2D
N = 50 # number of points on each ellipse
# point is the center of ellipse, a is radius on x-axis, b is radius on y-axis
# ts is the starting angle of the ellipse, te is the ending angle of the ellipse
# P is the list of coordinates of the points on the ellipse
def ellipse(origin, a, b, ts, te):
t = ts
positions = []
increment = (te - ts) / (N - 1)
for _ in range(N):
position = Vec2D(a * cos(t), b * sin(t))
positions.append(position + origin)
t += increment
return positions
# draws an arc from p1 to p2 with extent
def draw_arc(p1, p2, extent):
turtle.penup()
turtle.goto(p1)
a = turtle.towards(p2)
b = pi*2 - extent
c = (pi - b) / 2
d = a - c
heading = d - pi/2
radius = turtle.distance(p2) / 2 / sin(b / 2)
turtle.setheading(heading)
turtle.pendown()
turtle.circle(radius, extent, 100)
# return the landing position of the circle
# this position should be extremely close to p2 but may not be exactly the same
# return this for continuous drawing to the next point
return turtle.position()
def cloud(P):
step = N//10 # draw about 10 arcs on top and bottom part of cloud
a = 0 # a is index of first point
b = a + randint(step//2, step*2) # b is index of second point
p1 = P[a] # p1 is the position of the first point
p2 = P[b] # p2 is the position of the second point
p3 = draw_arc(p1, p2, uniform(1.25, pi)) # draws the arc with random extent
turtle.fillcolor('white')
turtle.begin_fill()
while b < len(P) - 1:
p1 = p3 # start from the end of the last arc
if b < len(P) / 2: # first half is top, more ragged
ext = uniform(1.25, pi)
b += randint(step//2, step*2)
else: # second half is bottom, more smooth
ext = uniform(0.05, 1.25)
b += randint(step, step*2)
b = min(b, len(P) - 1) # make sure to not skip past the last point
p2 = P[b] # second point
p3 = draw_arc(p1, p2, ext) # draws an arc and return the end position
turtle.end_fill()
screen = Screen()
turtle = Turtle()
turtle.hideturtle()
turtle.speed('fastest')
turtle.radians()
turtle.pensize(2)
origin = Vec2D(0, 200)
size = 10
points = [] # starting from empty list
points += ellipse(origin, size*15, size*10, 0, pi) # taller top half
points += ellipse(origin, size*15, size*2.5, pi, pi*2) # shorter bottom half
cloud(points)
screen.exitonclick()
I'm currently working on a section of a program that moves the mouse in an arc.
I'm given three points that define the arc: a starting point p1, a intermediate point on the arc p2 , and the end point p3. I'm also given length of the arc. If length is greater than the actual length of the arc subtended by p1 and p3, then p3 will not be the end point of the arc, but the mouse will continue moving in a circle until it has traveled distance length.
I have worked out the center of the circle (x, y), its radius r, and angle sweeped.
To move the mouse, am hoping to divide angle into smaller intervals each with angle dAngle and moving the mouse between its current position and the new position after sweeping dAngle. What I have in mind is in the pseudocode below:
for i in range(intervals):
x = center.x + r * cos(i * dAngle)
y = center.y + r * sin(i * dAngle)
Move mouse to (x, y)
Sleep 1
However, I've encountered some problems while trying to parametrically find the new point on the arc.
My mouse does not start at p1, but at what I assume is at the point where the line from the mouse to the center and the horizontal line subtends 0 degees, as I haven't factored into the parameters the initial angle. How do I find the initial angle of the mouse?
How do I determine whether to rotate clockwise or anticlockwise, i.e. whether x = center.x + r * cos(i * dAngle) or x = center.x - r * cos(i * dAngle)
If there is a more efficient way of moving in an arc please suggest it.
You can calculate starting angle as
a1 = math.atan2(p1.y-center.y, p1.x-center.x)
then use it in
x = center.x + r * cos(a1 + i * dAngle)
y = center.y + r * sin(a1 + i * dAngle)
About direction - perhaps you can determine direction when arc center is calculated. If no, and arc sweep angle is less than Pi (180 degrees), just find sign of expression
sg = math.sign((p1.x-center.x) * (p3.y-center.y) - (p1.y-center.y) * (p3.x-center.x))
and use it with dAngle
x = center.x + r * cos(a1 + i * sg * dAngle)
similar for y
P.S. note that minus in x = center.x - r * cos(i * dAngle) is wrong way to change direction
Im working on a python turtle game where the turtle can move with commands but it has to be able to detect collision with rectangles and circles on the screen as well as the border. I have no idea how to do this can anyone help?
Collision is easy! Before the nitty gritty, you need to understand how to obtain the distance between two points. If you have not done this before it is just pythag!
If you picture two points on a plane (red points on the picture), the shortest distance to travel between them, is directly from one point to another, without needing to make any turns, this is the distance between the points. In the picture above, let y be the vertical axis and x the horizontal axis. The horizontal distance between points d and e is represented by the value b. The vertical distance between points d and e is represented by the value a. As such...
a = d.y - e.y
b = d.x - e.x
Although a and be might be negative, it doesn't matter, because we sqaure them in a the next step.
To get the value of c, we then have to get the square root of the sum of the squares of a and b. Might sound tricky at first, but very easy!
Python code
To do this in python is simple.
c = ((a**2)+(b**2))**0.5
# a**2 is a squared
# anything to the power of 0.5 is square rooted, test it in console
# 25**0.5 = 5.0
# 5**2 = 25
We now have the distance between the two points d and e. Lets say d and e have the radius rd and re. We can then check if the circle d is colliding with circle e, by subtracting each radius from the distance between the centre of the circles. So c becomes...
c -= rd - re
If c is less than or equal to zero, then you have a collision between circles!
def collision(d, e, rd, re):
a = d.y-e.y
b = d.x-e.x
c = ((a**2)+(b**2))**0.5
if c > 0:
# no collision
return False
return True
Rectangles
Rectangles are a little easier, to check if a point is inside a rectangle all you need is some if statements. Let these variables represent the rectangle x = x location, y = y location, w = width, h = height. Suppose you want to check if point p is colliding with the rectangle.
def check_rect_collision(p, x, y, w, h):
if p.x >= x and p.x <= x+w and p.y >= y and p.y <= y+h:
# collision between p and rectangle
return True
return False
To test collision against a circle is trivial -- use the distance() method which measures from the center of the cursor to a position or center of another turtle. Given a circle's center position and its radius:
def circle_collision(the_turtle, center, radius):
return the_turtle.distance(center) <= radius
If you need to know if the turtle's nose has touched the circle, you could add half the turtle's size to the radius, for a (possibly resized) cursor which would be very roughly:
def circle_collision(the_turtle, center, radius):
dx, dy, border = the_turtle.shapesize()
return the_turtle.distance(center) <= radius + 5 * (dx + dy) + border
I.e. half the default turtle size of 20 pixels times the average of dx and dy plus the width of the border around the turtle. Or some such approximation.
To detect rectangle collision is also reasonably simple:
def rectangle_collision(the_turtle, x, y, width, height):
tx, ty = the_turtle.position()
return x <= tx <= x + width and y <= ty <= y + height
Adjust to whatever rectangle measure you're using:
def rectangle_collision(the_turtle, llx, lly, urx, ury):
x, y = the_turtle.position()
return llx <= x <= urx and lly <= y <= ury
a la the coordinate arguments for setworldcoordinates().
I am trying to plot a curved path for a robot to follow using the following as a guide: http://rossum.sourceforge.net/papers/CalculationsForRobotics/CirclePath.htm
The code i have does not create a path that ends at the destination. I am expecting the path to curve left or right depending on the quadrant the destination is in (+x+y,+x-y,-x+y,-x-y)
import math
start = [400,500]
dest = [200,300]
speed = 10
startangle = 0
rc =0
rotv =0
rads =0
def getPos(t):
ang = (rotv*t)+rads
x = start[0] - rc * math.sin(rads) + rc * math.sin(rotv*(t)+rads)
y = start[1] + rc * math.cos(rads) - rc * math.cos(rotv*(t)+rads)
return (int(x),int(y), ang)
dx = dest[0] - start[0]
dy = dest[1] - start[1]
rads = math.atan2(-dy,dx)
rads %= 2*math.pi
distance = (dx**2 + dy**2)**.5 #rg
bangle = 2*rads
rc = distance /(2 * math.sin(rads))
if rads > (math.pi/2):
bangle = 2*(rads-math.pi)
rc= -rc
if rads < -(math.pi/2):
bangle = 2*(rads+math.pi)
rc= -rc
pathlength = rc * bangle
xc = start[0] - rc * math.sin(rads)
yc = start[1] + rc * math.cos(rads)
rotcenter = [xc,yc]
traveltime = pathlength/speed
rotv = bangle/traveltime
for p in range(int(traveltime)):
pos = getPos(p)
Start: Blue, End: Red, Rotation Point: Purple
UPDATE:
I have added code to allow positive and negative x/y values. I have updated the image.
To answer your question I first read through the article you linked. I think it is very interesting and explains the ideas behind the formulas pretty well, althought it lacks the formulas for when the starting position is not at the origin and when the starting angle is not 0.
It took a little while to come up with these formulas, but now it works for every case I could think of. To be able to use the formulas given in the linked article, I used the names of the variables given there. Notice that I also used the notation with t_0 as the starting time, which you just ignored. You can easily remove any instance of t_0 or set t_0 = 0.
The last part of the following code is used for testing and creates a little red turtle that traces the path of the computed arc in the specified direction. The black turtle indicates the goal position. Both turtles are close to each other at the end of the animation, but they are not directly above each other, because I am only iterating over integers and it is possible that t_1 is not an integer.
from math import pi, hypot, sin, cos, atan2, degrees
def norm_angle(a):
# Normalize the angle to be between -pi and pi
return (a+pi)%(2*pi) - pi
# Given values
# named just like in http://rossum.sourceforge.net/papers/CalculationsForRobotics/CirclePath.htm
x_0, y_0 = [400,500] # initial position of robot
theta_0 = -pi/2 # initial orientation of robot
s = 10 # speed of robot
x_1, y_1 = [200,300] # goal position of robot
t_0 = 0 # starting time
# To be computed:
r_G = hypot(x_1 - x_0, y_1 - y_0) # relative polar coordinates of the goal
phi_G = atan2(y_1 - y_0, x_1 - x_0)
phi = 2*norm_angle(phi_G - theta_0) # angle and
r_C = r_G/(2*sin(phi_G - theta_0)) # radius (sometimes negative) of the arc
L = r_C*phi # length of the arc
if phi > pi:
phi -= 2*pi
L = -r_C*phi
elif phi < -pi:
phi += 2*pi
L = -r_C*phi
t_1 = L/s + t_0 # time at which the robot finishes the arc
omega = phi/(t_1 - t_0) # angular velocity
x_C = x_0 - r_C*sin(theta_0) # center of rotation
y_C = y_0 + r_C*cos(theta_0)
def position(t):
x = x_C + r_C*sin(omega*(t - t_0) + theta_0)
y = y_C - r_C*cos(omega*(t - t_0) + theta_0)
return x, y
def orientation(t):
return omega*(t - t_0) + theta_0
#--------------------------------------------
# Just used for debugging
#--------------------------------------------
import turtle
screen = turtle.Screen()
screen.setup(600, 600)
screen.setworldcoordinates(0, 0, 600, 600)
turtle.hideturtle()
turtle.shape("turtle")
turtle.penup()
turtle.goto(x_1, y_1)
turtle.setheading(degrees(orientation(t_1)))
turtle.stamp()
turtle.goto(x_0, y_0)
turtle.color("red")
turtle.showturtle()
turtle.pendown()
for t in range(t_0, int(t_1)+1):
turtle.goto(*position(t))
turtle.setheading(degrees(orientation(t)))
I am not sure at which point your code failed, but I hope this works for you. If you intend to use this snippet multiple times in you code consider encapsulating it in a function that takes in the given values as parameters and returns the position function (and if you like rotation function as well).
I am new to Python, and currently having a rough time with turtle graphics. This is what I am trying to solve
On Turtellini (the planet where Python turtles live) the
transportation system propels turtles with a giant slingshot. A
particular turtle's original location (x0, y0) is (-180, -100). He is
then shot upward at an initial vertical velocity (vy) of 88 units per
second and a horizontal velocity (vx) of 20 units per second to the
right. He travels for 16 seconds. The acceleration due to gravity (g)
is 11 units per second squared. The the location of the turtle at a
given second (t) is calculated as follows: x = x0 + vx * t and y = y0
+ vy * t - g/2 * t2 . This program is to show how a turtle travels over this period of time.
The output should be like this:
Here is what I should do;
set up the constants (vertical velocity, horizontal velocity,
gravity) and variables (x and y coordinates) set up the turtle by
giving him a proper shape, putting his tail up, moving him to the
initial position, putting his tail down make a loop that repeats for
seconds 1 through 16 inclusive. in each iteration of the loop display
the the values of the x and y variables (in the shell window), move
the turtle to those coordinates, have the turtle stamp his shape,
calculate the new values for the x and y variables after the loop
terminates, move the turtle to the last calculated coordinates,
change his color, and stamp his shape, then wait for a mouse click
My code so far:
import turtle
def main():
wn = turtle.Screen()
turtellini = turtle.Turtle()
t = int(input("Blab blab blab: "))
x0 = -180
y0 = -100
vx = 20
vy = 88
g = 11
x = (float(x0 + vx * t))
y = (float(y0 + vy * t - g / 2 * t**2))
turtellini.color("black")
turtellini.shape("turtle")
turtellini.up()
turtellini.goto(-180,-100)
turtellini.down()
for i in range(1,16,1):
turtellini.stamp()
turtellini.forward(i)
turtellini.right(i)
print(x)
print(y)
if __name__ == "__main__":
main()
I know I am doing bad; but can anyone help me to solve this problem?
You seem to have most of the parts and pieces. The biggest issue I see is you didn't put your x,y calculation in the loop. The loop iteration variable i is really t in your motion equations. Each time you calculate a new x,y you simply move the turtle to that position:
import turtle
from math import pi, atan
x0, y0 = -180, -100 # initial location
vx, vy = 20.0, 88.0 # initial velocity in units per second
travel_time = 16 # seconds
g = 11.0 # acceleration due to gravity in units per second squared
turtellini = turtle.Turtle(shape='turtle', visible=False)
turtellini.penup()
turtellini.radians() # to make turtle compatible with math.atan()
turtellini.setheading(pi / 2) # straight up
turtellini.goto(x0, y0)
turtellini.pendown()
turtellini.showturtle()
turtellini.stamp()
for t in range(1, travel_time + 1):
x = x0 + vx * t
y = y0 + vy * t - g / 2 * t**2
turtellini.goto(x, y)
print(x, y)
angle = atan((vy * t - g * t**2) / (vx * t)) # a guess!
turtellini.setheading(angle)
turtellini.stamp()
turtle.exitonclick()
Unlike the gold standard image, I assumed the turtle was aerodynamic like a bullet and travelled head first through the flight. I don't know, and couldn't quickly find, the formula for the flight angle of a projectile so I guessed from the existing formulas: