Understanding turtle circle, and arc in "Think Python" - python

In the interface design section in "Think Python" I need help understanding the approach to the circle and arc functions, like this:
import turtle
import polygon
bob = turtle.Turtle()
print(bob)
def polygon(t, n, length):
angle = 360 / n
for i in range(n):
t.fd(length)
t.lt(angle)
And after that, the book introduces another approach to drawing a circle by using a polygon function:
def circle(t, r):
circumference = 2 * math.pi * r
n = int(circumference / 3 ) + 1
length = circumference / n
polygon(t, n, length)
What I don't understand:
I have no idea why they define circumference to draw circle and how it works to draw a circle.
If I call the function like circle(bob, 100) then it only draws a fraction of circle not the whole circle.
I don't understand why n is needed, and how that procedure can make a circle.

I have no idea why they define circumference to draw circle and how it
take a work to draw a circle
One way we can visualize a circle is by drawing a polygon with the number of sides equal to the (integer) circumference of the circle with each side being 1 in length. For a circle of radius = 100, that would be:
polygon(bob, 628, 1) # 628 = 2 * PI * 100
which draws a nice, but slow circle:
We can speed this up by using a rougher approximation. The circle() function above arbitrarily divides the number of sides the polygon will have by 3 but then increases the length of each side by 3:
polygon(bob, 209, 3)
This is just a sightly rougher circle but draws more quickly:
If I call the function like circle(bob, 100) then it only draws a
fraction of circle not the whole circle.
I believe you're mixing up the circle() function defined above with the circle() method that comes with turtle. It was confusing of the author to reuse the "circle" name this way. The second argument to the turtle circle() method is an extent:
extent - an angle - determines which part of the
circle is drawn. If extent is not given, draw the entire circle.
If extent is not a full circle, one endpoint of the arc is the
current pen position.
So the "Think Python" function call:
circle(bob, 100)
draws a circle of radius 100:
The turtle method:
bob.circle(100, 90)
draws an arc (1/4 circle) based on a radius of 100:
I don't understand why n is needed, and how that procedure can make a
circle.
The n is the number of sides on the polygon that approximates a circle:
n = int(circumference / 3 ) + 1
length = circumference / n
polygon(t, n, length)
Starting with a radius of 100, if we replace the '3' above with 1, we'd get a polygon with more (629) sides:
n = int(circumference / 1) + 1 # n = 629
length = circumference / n # length = 0.9989
or roughly:
polygon(t, 628, 1)
Illustrated above. But if we replace '3' with '27', we'd get a circle approximated by a polygon of 24 sides:
n = int(circumference / 27 ) + 1 # n = 24
length = circumference / n # length = 26.1799
The orignal '3' value should have been an additional argument -- in the turtle.circle() method, it's roughly equivalent to the steps argument:
As the circle is approximated by an inscribed regular polygon,
steps determines the number of steps to use. If not given,
it will be calculated automatically. May be used to draw regular
polygons.
bob.circle(100, steps=12)

Related

how to draw a line knowing the starting coordinate, line length x angle and y, angle

I am trying to draw a line knowing the starting coordinate, line length x angle and y, angle. I am trying to visualize the eye gaze direction of a human in a video.
For an example, I want to draw the blue lines here:
I already have the center point of the eye (start of the blue line), and I already have the x and y angle of the eye. How do I draw this line?
I've found a lot of tutorials on how to draw such lines (https://learnopencv.com/head-pose-estimation-using-opencv-and-dlib/), but they involve translation and rotation vectors. Is there a clean way to do this just using the known x/y angles?
Given a length r and an angle φ between the x-axis and your line to draw, you can calculate a coordinate for a point P(x, y) like this:
x = r * cos(φ)
y = r * sin(φ)
For example, a vertical line with r = 1; φ = 90° = π / 2 would return y = 1 * sin(π / 2) = 1
Then you can import your image in opencv and draw a line using cv2.line.
It’s basically just math:
As far as I know, the height of the triangle is height = math.sinus(h) * l and its width is width = math.cos(h) * l.
I hope this help.

How can you find the relative spherical coordinates of an object after changing the origin?

I have an algorithm question. I am currently working on a script that generates images of an object from various angles inside of Unreal engine and pairs these images with the coordinates of the object. The way it works is that I have the object at the origin, and I generate random spherical coordinates to place my camera at. I then rotate my camera to face the object and do an extra rotation so that the object can lie anywhere in my camera's FOV. I now want to consider my camera as the origin and find the spherical coordinates of the object relative to the graph.
Currently, I am trying to derive the coordinates as in the code below. I start by noting that the radial distance between the object and the camera is the same regardless of which one is the origin. Then, I use the fact that the angles between my camera and my object are determined entirely by the extra rotation at the end of my camera placement. Finally, I try to find a rotation that will orient the object the same way as in the image based on the angular coordinates of the camera (This is done because I want to encode information about points on the object besides the center. For example, I am currently using a 1 meter cube as a placeholder object, and I want to keep track of the coordinates of the corners. I chose to use rotations because I can use them to make a rotation matrix and use it to convert my coordinates). Below is the code I use to do this (the AirSim library is used here, but all you need to know is airsim.Pose() takes in a Euclidean position coordinate and a Quaternion rotation as arguments to position my camera).
PRECISION_ANGLE = 4 # Fractions of a degree used in generating random pitch, roll, and yaw values
PRECISION_METER = 100 # Fractions of a meter used in generating random distance values
RADIUS_MAX = 20 # Maximum distance from the obstacle to be expected
#TODO: Replace minimum distace with a test for detecting if the camera is inside the obstacle
RADIUS_MIN = 3 # Minimum distance from the obstacle to be expected. Set this value large enough so that the camera will not spawn inside the object
# Camera details should match settings.json
IMAGE_HEIGHT = 144
IMAGE_WIDTH = 256
FOV = 90
# TODO: Vertical FOV rounds down for generating random integers. Some pictures will not be created
VERT_FOV = FOV * IMAGE_HEIGHT // IMAGE_WIDTH
def polarToCartesian(r, theta, phi):
return [
r * math.sin(theta) * math.cos(phi),
r * math.sin(theta) * math.sin(phi),
r * math.cos(theta)]
while 1:
# generate a random position for our camera
r = random.randint(RADIUS_MIN * PRECISION_METER, RADIUS_MAX * PRECISION_METER) / PRECISION_METER
phi = random.randint(0, 360 * PRECISION_ANGLE) / PRECISION_ANGLE
theta = random.randint(0, 180 * PRECISION_ANGLE) / PRECISION_ANGLE
# Convert polar coordinates to cartesian for AirSim
pos = polarToCartesian(r, math.radians(theta), math.radians(phi))
# Generate a random offset for the camera angle
pitch = random.randint(0, VERT_FOV * PRECISION_ANGLE) / PRECISION_ANGLE - VERT_FOV / 2
# TODO: Rotating the drone causes the obstacle to be removed from the image because the camera is not square
#roll = random.randint(0, 360 * PRECISION_ANGLE) / PRECISION_ANGLE
roll = 0
yaw = random.randint(0, FOV * PRECISION_ANGLE) / PRECISION_ANGLE - FOV/2
# Calculate coordinates of the center of the obstacle relative to the drone's new position and orientation
obs_r = r
obs_phi = yaw
obs_theta = 90 - pitch
# Convert polar coordinates to cartesian for AirSim
obs_pos = polarToCartesian(obs_r, math.radians(obs_theta), math.radians(obs_phi))
# Record rotational transformation on obstacle for calculating coordinates of key locations relative to the center
obs_phi_offset = -phi
obs_theta_offset = 270 - theta
# Move the camera to our calculated position
camera_pose = airsim.Pose(airsim.Vector3r(pos[0], pos[1], pos[2]), airsim.to_quaternion(math.radians(90 - theta + pitch), math.radians(roll), math.radians(phi + 180 + yaw))) #radians
Is this algorithm implemented correctly? What other ways could I find the coordinates of my object? Should I be doing something in Unreal Engine to get my coordinates instead of doing this algorithmically (though it needs to be fast)?
A translation of the origin by Vector3(i,j,k) is simply the translation of the original output.
camera_pose = airsim.Pose(airsim.Vector3r(pos[0] + i, pos[1] + j, pos[2] + k), airsim.to_quaternion(math.radians(90 - theta + pitch), math.radians(roll), math.radians(phi + 180 + yaw))) #radians

Python Collision Detection with x and y coordinates for border

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().

Section 4.3 Exercise #5 - "Think Python" by Allen Downey

Link to the Exercises can be accessed here - Case Study: Interface Design, Exercise Section 4.3
Quoting the question, it seems I have to implement an arc() function:
Make a more general version of circle called arc that takes an additional parameter angle, which determines what fraction of a circle to draw. angle is in units of degrees, so when angle=360, arc should draw a complete circle.
The code I've written so far:
import turtle
import math
bob = turtle.Turtle()
def polygon(t, n, length):
for i in range(n):
t.fd(length)
t.lt(360/n)
def circle(t, r):
circumference = 2 * math.pi * r
n = int(circumference/3) + 1
length = circumference/n
polygon(t, n, length)
def arc(t, r, angle):
arc_length = 2 * math.pi * r * (angle/360)
n = (arc_length/4) + 1
arc(bob, 1000, 45)
turtle.mainloop()
I'm intending to call the circle() function within arc() just as polygon() was called within circle(), but I'm confused on how I should do that. Apart from that, the arc() function does not draw anything, rather just shows me a stationary Turtle.
I believe that the Turtle object bob isn't receiving any of the movement instructions assigned within polygon(). Thus all that it's doing is displaying the Turtle object!
I could be wrong, and this where I need clarification. Should I call circle() within arc() as well as make the Turtle object move? Are there easier alternatives? Calling functions within a function is still confusing for me, so more resources to learn about them would be great as well!
import turtle
bob=turtle.Turtle()
import math
def arc(t,radius,angle):
circumference = 2.0*math.pi*radius
frac = angle/360.0
arclength = circumference*frac
n = 50 # pick a number
len = arclength/n;
turnang = angle/n
for i in range(n):
t.fd(len)
t.lt(turnang)
arc(bob, 130,360)
turtle.done()
I'm trying to ... call the circle() function
within arc() just as polygon() was called within circle()
You've got this backward. The problem states:
Make a more general version of circle called arc
Just as you could draw a circle with the more general function polygon(), you should be able to draw a circle with the more general function arc(). Here's a skeletal program for thinking about this:
from turtle import Screen, Turtle
from math import pi
def polygon(turtle, sides, length):
outside_angle = 360 / sides
for _ in range(sides):
turtle.forward(length)
turtle.left(outside_angle)
def circle_using_polygon(turtle, radius):
circumference = 2 * pi * radius
sides = min(60, int(circumference / 3))
length = circumference / sides
polygon(turtle, sides, length)
def arc(turtle, radius, angle):
# implement arc not by calling *circle() nor by
# calling polygon() but rather by borrowing code
# from both and adding one more step to reduce
# the number of sides based on the arc angle
def circle_using_arc(turtle, radius):
arc(turtle, radius, 360)
bob = Turtle(visible=False)
# Draw overlapping circles three different ways:
bob.color("green")
circle_using_polygon(bob, 100)
for color in ['cyan', 'magenta', 'yellow', 'black']:
bob.color(color)
arc(bob, 100, 90)
bob.color("blue")
circle_using_arc(bob, 100)
screen = Screen()
screen.mainloop()
import tkinter
import swampy
from swampy.TurtleWorld import *
def polygon(n, t, length, angle):
print(t)
k= angle/360
for i in range(0,int(n*k)):
fd(t, length)
p= 360
lt(t,p/n)
t.delay
world = TurtleWorld()
bob = Turtle()
#def circle(r):
#l1= 2*3.14*r
#l= l1/60
#polygon(30, bob, l)
polygon(60, bob, 10, 180)

Write a function called circle that takes a turtle, t, and radius, r, as param

import turtle
bob = turtle.Turtle()
def polygon(t,length,n):
for i in range(n):
t.fd(length)
t.lt(360/n)
print(t)
polygon(bob,30,15)
turtle.mainloop()
How can I make a circle by calling polygon function?
You already have written the correct code to produce a circle. In the view of turtle's own circle() method, a circle is just a polygon with 60 sides (fewer if the circle is small.) I.e. it's about perception and how many sides do you need before you can't tell the difference.
import turtle
def polygon(t, length, n):
for _ in range(n):
t.fd(length)
t.lt(360 / n)
bob = turtle.Turtle()
bob.penup()
bob.sety(-270)
bob.pendown()
polygon(bob, 30, 60)
turtle.mainloop()
Your problem now is to control the drawing of the polygon/circle to produce it with a specific radius. Your length parameter doesn't map to a radius as the circle is coming out way too large. Here length represents 1/60 (1/n) of the circumference and we know that:
circumference = 2 * math.pi * radius
We can calculate, in our circle(t, radius) function, what length needs to be given radius (i.e. circumference/n), and call polygon(t, length, n) with these parameters. Here's a visual comparison drawing a radius 100 circle with turtle's circle() method (red) and drawing it with the solution I just described (blue):
import turtle
bob=turtle.Turtle()
bob.color('green', 'cyan')
bob.begin_fill()
def polygon(t,length, n):
for i in range(n):
bob.forward(length)
bob.left(360/n)
import math
def circle(t, r):
circum= 2*math.pi*r
n= int(circum/10)+1
length= circum/n
polygon(t,length, n)
circle(bob, 100)
bob.end_fill()
turtle.done()

Categories

Resources