okay, i have a circle and i want get the point on circle in 90 degree of origin.
def point_on_circle():
'''
Finding the x,y coordinates on circle, based on given angle
'''
from math import cos, sin
#center of circle, angle in degree and radius of circle
center = [0,0]
angle = 90
radius = 100
#x = offsetX + radius * Cosine(Degree)
x = center[0] + (radius * cos(angle))
#y = offsetY + radius * Sine(Degree)
y = center[1] + (radius * sin(angle))
return x,y
>>> print point_on_circle()
[-44.8073616129 , 89.3996663601]
since pi start from 3 o'clock, i expected to get x=0 and y=100but i have no idea why i'm getting that.
what am i doing wrong?
Edit: even i convert to radians, still i get weird result.
def point_on_circle():
'''
Finding the x,y coordinates on circle, based on given angle
'''
from math import cos, sin, radians
#center of circle, angle in degree and radius of circle
center = [0,0]
angle = radians(90)
radius = 100
#x = offsetX + radius * Cosine(radians)
x = center[0] + (radius * cos(angle))
#y = offsetY + radius * Sine(radians)
y = center[1] + (radius * sin(angle))
return x,y
>>> print point_on_circle()
[6.12323399574e-15 , 100.0]
any idea how to get accurate number?
math.cos and math.sin expect radians, not degrees. Simply replace 90 by pi/2:
def point_on_circle():
'''
Finding the x,y coordinates on circle, based on given angle
'''
from math import cos, sin, pi
#center of circle, angle in degree and radius of circle
center = [0,0]
angle = pi / 2
radius = 100
x = center[0] + (radius * cos(angle))
y = center[1] + (radius * sin(angle))
return x,y
You'll get (6.123233995736766e-15, 100.0) which is close to (0, 100).
If you want better precision, you can try SymPy online before installing it yourself:
>>> from sympy import pi, mpmath
>>> mpmath.cos(pi/2)
6.12323399573677e−17
We're getting closer, but this is still using floating-point. However, mpmath.cospi gets you the correct result:
>>> mpmath.cospi(1/2)
0.0
The sin() & cos() expect radians use:
x = center[0] + (radius * cos(angle*pi/180));
Two things need to be changed.
First, you need to change range = 90 to range = radians(90) which means you need to import radians.
Second you need to subtract the range from radian(360) so you get it starting in quadrant I instead of quadrant IV. Once you are done, your should have changed range = 90 to range = radians(360 - 90) and have imported radians.
Then if you want to stop your answer from having floating-point, you have return int(x), int(y) instead of return x,y at the end of your function. I made these changes and it worked.
Related
I'm trying to get the dot to start rotating at an angle of 330 degrees, but it starts at that point, jumps to 0 degrees, and does a full turn from 0 degrees to 360 degrees.
I'm trying to make it start at 330 degrees and end at 330 degrees.
Can anybody help me?
from manim import *
import numpy as np
class Turn( Scene ):
def construct( self ):
radius = 1
origin = ORIGIN
e1dir = RIGHT
e2dir = UP
x1 = origin + radius * e1dir * np.cos(np.deg2rad(330)) + radius * e2dir * np.sin(np.deg2rad(330))
r = lambda t: origin + radius * e1dir * np.cos(t * 1 * 2*PI) + radius * e2dir * np.sin(t * 1 * 2*PI)
def rmove(a, t):
p = r(t)
a.move_to(p)
def u1(mob):
t = t_parameter.get_value()
rmove(mob, t)
t_parameter = ValueTracker(0)
dot = Dot(point=x1, color=BLUE).add_updater(u1)
g1 = ParametricFunction(r, t_range=[0, 1], color=YELLOW)
self.add(VGroup(g1, dot))
self.wait(1)
self.play(UpdateFromAlphaFunc(t_parameter, lambda mob, alpha: mob.set_value(alpha)), run_time=3)
self.wait(1)
I am trying to randomly generate points along the curved surface of a cylinder that has a y up-axis. Following a SO question of creating points along a 2D circle, I have
def point(h, k, r):
theta = random.random() * 2 * pi
global x
global y
x = h + cos(theta) * r
y = k + sin(theta) * r
given the cylinder's (h,k) origin point (0, -21.56462) and r (radius = 7.625). I then made these points 3D by generating a z point within my range (-2.35, 12.31). However, this got me half the way there because the final result was a cylinder but rotated 90 degrees clockwise.
Image of generated cylinder
What formula can I use that will generate the points in the correct direction? I am not that familiar with trigonometry, unfortunately. Thanks in advance!
THE SOLUTION:
def point(h, k, r):
theta = random.random() * 2 * pi
global x
global z
x = h + cos(theta) * r
z = k + sin(theta) * r
The new (h,k) origin is now (x,z) where x and z are the coordinates for the center of the cylinder and y is randomly generated within its appropriate height range. The vector is still (x,y,z).
Updated generated cylinder
THE SOLUTION:
(thanks to David Huculak)
def point(h, k, r):
theta = random.random() * 2 * pi
global x
global z
x = h + cos(theta) * r
z = k + sin(theta) * r
The new (h,k) origin is now (x,z) where x and z are the coordinates for the center of the cylinder and y is randomly generated within its appropriate height range. The vector is still (x,y,z).
Updated Generated cylinder
I am making a game with some bouncing elements IN a circle (I use pygame) ,
My elements have 2 attributes , one for the angle and one for the speed
Here is how elements moves :
mvx = math.sin(self.angle) * self.speed
mvy = -math.cos(self.angle) * self.speed
self.x += mvx
self.y += mvy
My problem is this : I know the angle at the top (99.6°) , I have the collision point (x and y ) , but I'm unable to find the angle at the bottom(42.27°)
Does someones can make a relation between the first angle and the second ?
Picture is better ...
I recommend do calculate the reflection vector to the incident vector on the circular surface.
In the following formula N is the normal vector of the circle, I is the incident vector (the current direction vector of the bouncing ball) and R is the reflection vector (outgoing direction vector of the bouncing ball):
R = I - 2.0 * dot(N, I) * N.
Use the pygame.math.Vector2.
To calculate the normal vector, you' ve to know the "hit" point (dvx, dvy) and the center point of the circle (cptx, cpty):
circN = (pygame.math.Vector2(cptx - px, cpty - py)).normalize()
Calculate the reflection:
vecR = vecI - 2 * circN.dot(vecI) * circN
The new angle can be calculated by math.atan2(y, x):
self.angle = math.atan2(vecR[1], vecR[0])
Code listing:
import math
import pygame
px = [...] # x coordinate of the "hit" point on the circle
py = [...] # y coordinate of the "hit" point on the circle
cptx = [...] # x coordinate of the center point of the circle
cpty = [...] # y coordinate of the center point of the circle
circN = (pygame.math.Vector2(cptx - px, cpty - py)).normalize()
vecI = pygame.math.Vector2(math.cos(self.angle), math.sin(self.angle))
vecR = vecI - 2 * circN.dot(vecI) * circN
self.angle = math.pi + math.atan2(vecR[1], vecR[0])
The inner angles of a triangle need to sum up to 180°. Also, the angle 99.96° is supplementary to the triangle's angle next to it (calling it by A), i.e. 99.96° + A = 180° so A = 180° - 99.96°. Calling of B = 42.27° the bottom angle. And for the last angle C, we can use that it is opposed by the vertex with the other angle that is equal to 2 * 28.85 = 57.7°.
Then:
A + B + C = 180°
180° - 99.96° + 42.27° + 2 * 28.85° = 180°
180° - 99.96° + 42.27° + 2 * 28.85° = 180°
-99.96° + 42.27° + 2 * 28.85° = 0°
42.27° + 2 * 28.85° = 99.96°
B + C = Top angle
P.S.: I know that the values are not exactly equal, but it must be because of the decimal places rounding
I have dataframe with measurements coordinates and cell coordinates.
I need to find for each row angle (azimuth angle) between a line that connects these two points and the north pole.
df:
id cell_lat cell_long meas_lat meas_long
1 53.543643 11.636235 53.44758 11.03720
2 52.988823 10.0421645 53.03501 9.04165
3 54.013442 9.100981 53.90384 10.62370
I have found some code online, but none if that really helps me get any closer to the solution.
I have used this function but not sure if get it right and I guess there is simplier solution.
Any help or hint is welcomed, thanks in advance.
The trickiest part of this problem is converting geodetic (latitude, longitude) coordinates to Cartesian (x, y, z) coordinates. If you look at https://en.wikipedia.org/wiki/Geographic_coordinate_conversion you can see how to do this, which involves choosing a reference system. Assuming we choose ECEF (https://en.wikipedia.org/wiki/ECEF), the following code calculates the angles you are looking for:
def vector_calc(lat, long, ht):
'''
Calculates the vector from a specified point on the Earth's surface to the North Pole.
'''
a = 6378137.0 # Equatorial radius of the Earth
b = 6356752.314245 # Polar radius of the Earth
e_squared = 1 - ((b ** 2) / (a ** 2)) # e is the eccentricity of the Earth
n_phi = a / (np.sqrt(1 - (e_squared * (np.sin(lat) ** 2))))
x = (n_phi + ht) * np.cos(lat) * np.cos(long)
y = (n_phi + ht) * np.cos(lat) * np.sin(long)
z = ((((b ** 2) / (a ** 2)) * n_phi) + ht) * np.sin(lat)
x_npole = 0.0
y_npole = 6378137.0
z_npole = 0.0
v = ((x_npole - x), (y_npole - y), (z_npole - z))
return v
def angle_calc(lat1, long1, lat2, long2, ht1=0, ht2=0):
'''
Calculates the angle between the vectors from 2 points to the North Pole.
'''
# Convert from degrees to radians
lat1_rad = (lat1 / 180) * np.pi
long1_rad = (long1 / 180) * np.pi
lat2_rad = (lat2 / 180) * np.pi
long2_rad = (long2 / 180) * np.pi
v1 = vector_calc(lat1_rad, long1_rad, ht1)
v2 = vector_calc(lat2_rad, long2_rad, ht2)
# The angle between two vectors, vect1 and vect2 is given by:
# arccos[vect1.vect2 / |vect1||vect2|]
dot = np.dot(v1, v2) # The dot product of the two vectors
v1_mag = np.linalg.norm(v1) # The magnitude of the vector v1
v2_mag = np.linalg.norm(v2) # The magnitude of the vector v2
theta_rad = np.arccos(dot / (v1_mag * v2_mag))
# Convert radians back to degrees
theta = (theta_rad / np.pi) * 180
return theta
angles = []
for row in range(df.shape[0]):
cell_lat = df.iloc[row]['cell_lat']
cell_long = df.iloc[row]['cell_long']
meas_lat = df.iloc[row]['meas_lat']
meas_long = df.iloc[row]['meas_long']
angle = angle_calc(cell_lat, cell_long, meas_lat, meas_long)
angles.append(angle)
This will read each row out of your dataframe, calculate the angle and append it to the list angles. Obviously you can do what you like with those angles after they've been calculated.
Hope that helps!
I've been trying to rotate a bunch of lines by 90 degrees (that together form a polyline). Each line contains two vertices, say (x1, y1) and (x2, y2). What I'm currently trying to do is rotate around the center point of the line, given center points |x1 - x2| and |y1 - y2|. For some reason (I'm not very mathematically savvy) I can't get the lines to rotate correctly.
Could someone verify that the math here is correct? I'm thinking that it could be correct, however, when I set the line's vertices to the new rotated vertices, the next line may not be grabbing the new (x2, y2) vertex from the previous line, causing the lines to rotate incorrectly.
Here's what I've written:
def rotate_lines(self, deg=-90):
# Convert from degrees to radians
theta = math.radians(deg)
for pl in self.polylines:
self.curr_pl = pl
for line in pl.lines:
# Get the vertices of the line
# (px, py) = first vertex
# (ox, oy) = second vertex
px, ox = line.get_xdata()
py, oy = line.get_ydata()
# Get the center of the line
cx = math.fabs(px-ox)
cy = math.fabs(py-oy)
# Rotate line around center point
p1x = cx - ((px-cx) * math.cos(theta)) - ((py-cy) * math.sin(theta))
p1y = cy - ((px-cx) * math.sin(theta)) + ((py-cy) * math.cos(theta))
p2x = cx - ((ox-cx) * math.cos(theta)) - ((oy-cy) * math.sin(theta))
p2y = cy - ((ox-cx) * math.sin(theta)) + ((oy-cy) * math.cos(theta))
self.curr_pl.set_line(line, [p1x, p2x], [p1y, p2y])
The coordinates of the center point (cx,cy) of a line segment between points (x1,y1) and (x2,y2) are:
cx = (x1 + x2) / 2
cy = (y1 + y2) / 2
In other words it's just the average, or arithmetic mean, of the two pairs of x and y coordinate values.
For a multi-segmented line, or polyline, its logical center point's x and y coordinates are just the corresponding average of x and y values of all the points. An average is just the sum of the values divided by the number of them.
The general formulas to rotate a 2D point (x,y) θ radians around the origin (0,0) are:
x′ = x * cos(θ) - y * sin(θ)
y′ = x * sin(θ) + y * cos(θ)
To perform a rotation about a different center (cx, cy), the x and y values of the point need to be adjusted by first subtracting the coordinate of the desired center of rotation from the point's coordinate, which has the effect of moving (known in geometry as translating) it is expressed mathematically like this:
tx = x - cx
ty = y - cy
then rotating this intermediate point by the angle desired, and finally adding the x and y values of the point of rotation back to the x and y of each coordinate. In geometric terms, it's the following sequence of operations: Tʀᴀɴsʟᴀᴛᴇ ─► Rᴏᴛᴀᴛᴇ ─► Uɴᴛʀᴀɴsʟᴀᴛᴇ.
This concept can be extended to allow rotating a whole polyline about any arbitrary point—such as its own logical center—by just applying the math described to each point of each line segment within it.
To simplify implementation of this computation, the numerical result of all three sets of calculations can be combined and expressed with a pair of mathematical formulas which perform them all simultaneously. So a new point (x′,y′) can be obtained by rotating an existing point (x,y), θ radians around the point (cx, cy) by using:
x′ = ( (x - cx) * cos(θ) + (y - cy) * sin(θ) ) + cx
y′ = ( -(x - cx) * sin(θ) + (y - cy) * cos(θ) ) + cy
Incorporating this mathematical/geometrical concept into your function produces the following:
from math import sin, cos, radians
def rotate_lines(self, deg=-90):
""" Rotate self.polylines the given angle about their centers. """
theta = radians(deg) # Convert angle from degrees to radians
cosang, sinang = cos(theta), sin(theta)
for pl in self.polylines:
# Find logical center (avg x and avg y) of entire polyline
n = len(pl.lines)*2 # Total number of points in polyline
cx = sum(sum(line.get_xdata()) for line in pl.lines) / n
cy = sum(sum(line.get_ydata()) for line in pl.lines) / n
for line in pl.lines:
# Retrieve vertices of the line
x1, x2 = line.get_xdata()
y1, y2 = line.get_ydata()
# Rotate each around whole polyline's center point
tx1, ty1 = x1-cx, y1-cy
p1x = ( tx1*cosang + ty1*sinang) + cx
p1y = (-tx1*sinang + ty1*cosang) + cy
tx2, ty2 = x2-cx, y2-cy
p2x = ( tx2*cosang + ty2*sinang) + cx
p2y = (-tx2*sinang + ty2*cosang) + cy
# Replace vertices with updated values
pl.set_line(line, [p1x, p2x], [p1y, p2y])
Your center point is going to be:
centerX = (x2 - x1) / 2 + x1
centerY = (y2 - y1) / 2 + y1
because you take half the length (x2 - x1) / 2 and add it to where your line starts to get to the middle.
As an exercise, take two lines:
line1 = (0, 0) -> (5, 5)
then: |x1 - x2| = 5, when the center x value is at 2.5.
line2 = (2, 2) -> (7, 7)
then: |x1 - x2| = 5, which can't be right because that's the center for
the line that's parallel to it but shifted downwards and to the left