I'm trying to draw an ellipse using Turtle module in Python, my plan is as follow:
Let the starting point be the focal point of the ellipse
Set the initial theta value to 0
Let the turtle forward, let the distance of the forwarding be a*(1-ee)/(1-emath.cos(theta))
Let it turn around and back to the original spot
Make a very small turn, update the theta value
Repeat the above process
Here's my actual code:
import turtle
import math
wn = turtle.getscreen()
wn.bgcolor("red")
My_Turtle = turtle.Turtle()
My_Turtle.penup()
My_Turtle.speed(9)
i=0
j=0
a=200
e=0.5
x_0 = 20
theta = 0
while(i<5000):
#Plotting squares
My_Turtle.penup()
ellipse = a*(1-e*e)/(1-e*math.cos(theta))
My_Turtle.forward(ellipse)
My_Turtle.pendown()
My_Turtle.forward(1)
My_Turtle.left(180)
My_Turtle.penup()
My_Turtle.forward(ellipse+1)
However, the results were really off like this:(Not the complete image but can see that it's already off)
enter image description here
Can anyone explain to me where I get it wrong ? Thank you very much!
I'm used to drawing ellipses from the center, not from one focal point so I read up on ellipse math to get my head around this. Your key formula appears to be correct:
ellipse = a*(1-e*e)/(1-e*math.cos(theta))
The issue is how you do your drawing. First you need to add setheading() to point your turtle in the correct direction. (Remember that by default it's in degrees so we need to either convert or change turtle's default). Second, how you bridge between steps in your drawing isn't sufficient.
I've reworked your code below, and have compared it to a center-based solution to confirm it generates the same ellipse:
import math
from turtle import Turtle, Screen
my_screen = Screen()
my_turtle = Turtle(visible=False)
my_turtle.speed('fastest')
my_turtle.radians()
my_turtle.penup()
e = 0.5 # linear eccentricity
a = 200 # semi major axis
c = e * a # distance from center to focal point
my_turtle.goto(-c, 0) # starting at a focal point
there = (2 * c, 0) # initialize previous point visited
step = 0.1
theta = step # already at starting point, so calculate next point
while theta < math.pi * 2 + step: # overshoot to close curve
# draw ellipse from one focus point
my_turtle.setheading(theta)
distance = a * (1 - e * e) / (1 - e * math.cos(theta))
my_turtle.forward(distance)
here = my_turtle.position()
my_turtle.pendown()
my_turtle.goto(there) # draw line from last position to this one
my_turtle.penup() # comment out to demonstrate algorithm
my_turtle.goto(-c, 0) # return to focal point
there = here
theta += step
my_screen.exitonclick()
OUTPUT
I left the pen down for this illustrution so it's obvious that it's forming the ellipse from one focal point.
Related
I'm trying to write a script in python, to automatically force the movement of the mouse pointer without the user's input (it quits through the keyboard), and experimenting with PyAutoGUI, PyUserInput and ctypes, I've been figuring out ways to move the pointer with constant speed, instead of having it teleport across the screen(I need the user to be able to see the path it makes). However, I need it to be able to perform curves, and particularly, circles, and I haven't found a way to do so with the aforementioned libraries. Does anybody know of a way to code them into making the mouse describe circles across the screen at constant speed, instead of just straight lines? Thank you beforehand for any input or help you may provide.
This is my attempt at making circle at the center of the screen of radius R - also note if I don't pass parameter duration then the mouse pointer moves to the next coordinates instantly. So for a circle divided into 360 parts you can set the pace using a modulus.
import pyautogui
import math
# Radius
R = 400
# measuring screen size
(x,y) = pyautogui.size()
# locating center of the screen
(X,Y) = pyautogui.position(x/2,y/2)
# offsetting by radius
pyautogui.moveTo(X+R,Y)
for i in range(360):
# setting pace with a modulus
if i%6==0:
pyautogui.moveTo(X+R*math.cos(math.radians(i)),Y+R*math.sin(math.radians(i)))
There is a way to do this using sin, cos, and tan. (I haven't been able to test this code yet, It might not work.)
Import math
Import pyautogui
def circle(radius = 5, accuracy = 360, xpos=0, ypos=0, speed = 5):
local y
local x
local angle
angle = 360/accuracy
local CurAngle
CurAngle = 0
x = []
y = []
sped = speed/accuracy
for i in range(accuracy):
x.append(xpos + radius*math.sin(math.radians(CurAngle)))
y.append(ypos + radius*math.cos(math.radians(CurAngle)))
CurAngle += angle
for i in len(x):
pyautogui.moveTo(x[i], y[i], duration = sped)
You put this near the top of your script, and pass arguments like this:
circle(radius, accuracy, xpos, ypos, speed)
Radius controls the width of the circle
Accuracy controls how many equi-distant points the circle is to be broken up into, setting accuracy to 4 will put 4 invisible points along the circle for the mouse to travel tom which will make a square, not a circle, 5 makes a pentagon, 6 a hexagon, etc.. the bigger the radius, the bigger you will want the accuracy
Xpos controls the x position of where the circle is centered
Ypos controls the y position of where the circle is centered
Speed controls how many seconds you want it to take to draw the circle.
Hope this helps :) Would you mind elaborating what you are wanting when you say 'curves'
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!
I'm struggling to work out how I move point A to B in an arc motion in 3D. The duration of the movement doesn't matter so much. I have found a load of wikipedia pages on it but am having no luck understanding them as its been a long time since I was in college. Any code examples would be really useful for me to understand. Thank you, I would really appreciate your help. Here is an image that sort of shows what I am looking to achieve, although the image only represents the points in 2d, I am looking for a 3d solution.
Assuming your problem statement is:
Given points a and b, trace the circular path along the plane which lies tangent to the up vector:
And that you have the appropriate vector algebra libraries:
def interp(a, b, up, t):
""" 0 <= t <= 1"""
# find center and radius vector
center = (a + b) / 2
radius = a - center
# split path into upwards and downwards section
omega = math.acos(radius.dot(up)) # angle between center-a and center-top
t_top = omega / math.pi # time taken to reach the top
# redefine 0 as A, 1 as the top, and B as whatever remains linear
t = t / t_top
#slerp, with t intentionally > 1
sin = math.sin
return (
center +
sin((1 - t) * omega) / sin(omega) * radius +
sin(t * omega) / sin(omega) * up
)
it doesnt matter if its 2d or 3d .
you take the position of each dot and find the center beetwean them .
the distance beetwean the center and each dot is the radius .
after that give the object a moving direction and tell it to be always in a distance of radius from center . which a moving vector you can give it any direction you want .
Please forgive me, but I only really know how to somewhat code in VB, and python is not what I'm used to. I did try to see if other people have made and or shown an algorithm that I'm trying to accomplish.
I have a visualizer design in my head and What I have been trying to do is get a number of cubes (variable input for now) to be placed a certain distance (maybe 5-10 blender units) from the center of the scene and angle the faces so that there will be one face pointing to the center and one face pointing the opposite direction. I'm trying to just start with 10 cubes because I feel like it will be a fair number to hopefully show a circle shape.
I made an image to help describe what I am trying to do:
All I have been able to figure out so far is that I need to add a cube with a certain rotation, and that rotation needs to be stepped for each cube. so a small equation is needed, something like this.
(10) (36)
360 / numberOfCubes = steppedAngle
That's all I have been able to figure out because I don't know how to program python to do such.
Any help is greatly appreciated, and will be credited in the final render.
Update: 1
Thanks to the help from the answer below, I finally got it to work how i wanted.
img http://vvcap.net/db/bKKUz3Uw4WUqL_WVDU0j.png
and here is the code written in help from the answer below.
'
import bpy
import math
##num of cubes
n = 10
##distange from center
radius = 7
for i in range(1, n + 1):
angle = (i - 1) * math.pi * 2 / n
xcoord=(radius * math.cos(angle))
ycoord=(radius * math.sin(angle))
bpy.ops.mesh.primitive_cube_add(location=(xcoord,ycoord,0),rotation=(0,0,angle))
'
Let's start with cubes in a circle, and we will work our way from there.
You have N cubes, and you want to place them in a circle of radius R around the center of the universe (0,0,0).
Applying basic trigonometry:
Each cube is on one of the radius of the circle, when you divide the circle by N. Therefore, your first cube is at 0 rad, your second cube is at 2*pi/N rad, your third cube is at 2 * 360/N rad, ... your N cube is at (N-1) * 2*pi/N rad. Now we have a formula:
Location of the cube in the circle = (i - 1) * 2*pi/N in radians, for each i from 1 to N.
Now, the location in space coordinates is (r*cos(angle), r*sin(angle), 0) for a circle that is placed on the XY plane and it's center is on (0,0,0).
My Blender Python is very rusty, so I won't provide you a complete solution, but it should be this way:
import math
for i in range(1, N + 1):
angle = (i - 1) * math.pi * 2 / N
x_coord = radius * math.cos(angle)
y_coord = radius * math.sin(angle)
z_coord = 0
cube = place_cube(x_coord, y_coord, z_coord)
This will place the cubes on the right coordinates, but it won't turn them the right way. Fortunately, you can rotate each cube by angle, and get it in the right orientation. So you can do:
import math
for i in range(1, N + 1):
angle = (i - 1) * math.pi * 2 / N
x_coord = radius * math.cos(angle)
y_coord = radius * math.sin(angle)
z_coord = 0
cube = place_cube(x_coord, y_coord, z_coord)
cube.rotate_around_z(angle)
I have not provided the place_cube and rotate_around_z functions because I hardly remember the Blender Python api, but it shouldn't be too hard.
I am writing a game in Python with Pygame.
The co-ords (of my display window) are
( 0 , 0 ) at the top left and
(640,480) at the bottom right.
The angle is
0° when pointing up,
90° when pointing to the right.
I have a player sprite with a centre position and I want the turret on a gun to point towards the player. How do I do it?
Say,
x1,y1 are the turret co-ords
x2,y2 are the player co-ords
a is the angle's measure
First, math has a handy atan2(denominator, numerator) function. Normally, you'd use atan2(dy,dx) but because Pygame flips the y-axis relative to Cartesian coordinates (as you know), you'll need to make dy negative and then avoid negative angles. ("dy" just means "the change in y".)
from math import atan2, degrees, pi
dx = x2 - x1
dy = y2 - y1
rads = atan2(-dy,dx)
rads %= 2*pi
degs = degrees(rads)
degs ought to be what you're looking for.
Considering a triangle
sin(angle)=opposed side / hypotenuse
You'll probably want something like this - you may need to fiddle a bit - I may be off by 180 degrees. You'll also need to special-case the situation where dy==0, which I didn't do for you.
import math
# Compute x/y distance
(dx, dy) = (x2-x1, y2-y1)
# Compute the angle
angle = math.atan(float(dx)/float(dy))
# The angle is in radians (-pi/2 to +pi/2). If you want degrees, you need the following line
angle *= 180/math.pi
# Now you have an angle from -90 to +90. But if the player is below the turret,
# you want to flip it
if dy < 0:
angle += 180
OK, using a combination of your answers and some other websites I have found the working code:
dx,dy = x2-x1,y2-y1
rads = math.atan2(dx/dy)
degs = math.degrees(rads)
The rest of my code isn't fussy about a negative value of degs; anyway, it works now and I'd like to say thanks for your help.