Angle between two pairs of azimuth and altitude? - python

I have a solar panel pointing (it's normal vector) in some direction. I want to calculate the angle between that and the current position of the sun. I am using pyephem and I have this information in two pairs of azimuth and altitude.
panel_az = ephem.degrees('180')
panel_alt = ephem.degrees('45')
sun_az = ephem.degrees('245')
sun_alt = ephem.degrees('22')
What is the easiest way to find the angle between the panel's normal vector and the vector pointing towards the sun?

The library offers a separation() function that gives the angle between two spherical coordinates; look near the bottom of this section of the Quick Reference:
http://rhodesmill.org/pyephem/quick.html#other-functions
I think you will get the angle you are seeking if you run:
a = ephem.separation((panel_az, panel_alt), (sun_az, sun_alt))
print a
Good luck!

Convert both to vectors first:
z = sin(altitude)
hyp = cos(altitude)
y = hyp*cos(azimuth)
x = hyp*sin(azimuth)
vector = (x,y,z)
Then calculate the angle between the vectors (say a and b) using cross and dot products.
angle = atan2(norm(cross(a,b)), dot(a,b))
For cross use:
def cross(a, b):
c = [a[1]*b[2] - a[2]*b[1],
a[2]*b[0] - a[0]*b[2],
a[0]*b[1] - a[1]*b[0]]
return c
For dot use:
def dot(a, b):
c = [ a[i] * b[i] for i in range(len(a)) ]
return c
For norm use:
def norm(a):
mag = sqrt(sum(a[i]*a[i] for i in range(len(a))))
c = [ a[i]/mag for i in range(len(a)) ]
return c

clear,clc,clf;
for n=[15 46 74 105 135 166 196 227 258 288 319 349];
delta=23.45*(sind(360*(284+n)/365));
phi=31.2;
omega=acosd(-tand(phi).*tand(delta));
omega1=-omega:0.1:omega;
alt=(sind(delta).*sind(phi))+(cosd(delta).*cosd(omega1).*cosd(phi));
alt1=asind(abs(alt))
azm=(cosd(delta).*sind(omega1))./cosd(alt);
azm1=asind(azm)
plot(azm1,alt1,'b');hold on;
end
grid on
xlabel('Solar Azimuth');ylabel('Solar altitude');
text(0,85,'noon')
hold off

Related

Euler Angles and Rotation Matrix from two 3D points

I am trying to find the Euler angles that allow the transformation from point A to point B in 3D space.
Consider the normalized vectors A = [1, 0, 0] and B = [0.32 0.88 -0.34].
I understand that by computing the cross product A × B I get the rotation axis. The angle between A and B is given by tan⁻¹(||cross||, A·B), where A·B is the dot product between A and B.
This gives me the rotation vector rotvec = [0 0.36 0.93 1.24359531111], which is rotvec = [A × B; angle] (the cross product is normalized).
Now my question is: How do I move from here to get the Euler angles that correspond to the transformation from A to B?
In MATLAB the function vrrotvec2mat receives as input a rotation vector and outputs a rotation matrix. Then the function rotm2eul should return the corresponding Euler angles. I get the following result (in radians): [0.2456 0.3490 1.2216], according to the XYZ convention. Yet, this is not the expected result.
The correct answer is [0 0.3490 1.2216] that corresponds to a rotation of 20° and 70° in Y and Z, respectively.
When I use eul2rot([0 0.3490 1.2216]) (with eul2rot taken from here) to verify the resulting rotation matrix, this one is different from the one I obtain when using vrrotvec2mat(rotvec).
I also have a Python spinet that yields the exactly same results as described above.
--- Python (2.7) using transform3d ---
import numpy as np
import transforms3d
cross = np.cross(A, B)
dot = np.dot(A, B.transpose())
angle = math.atan2(np.linalg.norm(cross), dot)
rotation_axes = sklearn.preprocessing.normalize(cross)
rotation_m = transforms3d.axangles.axangle2mat(rotation_axes[0], angle, True)
rotation_angles = transforms3d.euler.mat2euler(rotation_m, 'sxyz')
What I am missing here? What should I be doing instead?
Thank you
A rotation matrix has 3 degrees of freedom but the constraints of your problem only constrain 2 of those degrees.
This can be made more concrete by considering the case where we have a rotation matrix R which rotates from A to B so R*A == B. If we then construct another rotation matrix RB which rotates about vector B then applying this rotation to R*A won't have any effect, i.e. B == R*A == RB*R*A. It will, however, produce a different rotation matrix RB*R with different Euler angles.
Here's an example in MATLAB:
A = [1; 0; 0];
B = [0.32; 0.88; -0.34];
A = A / norm(A);
B = B / norm(B);
ax = cross(A, B);
ang = atan2(norm(ax), dot(A, B)); % ang = acos(dot(A, B)) works too
R = axang2rotm([ax; ang].');
ang_arbitrary = rand()*2*pi;
RB = axang2rotm([B; ang_arbitrary].');
R*A - B
RB*R*A - B
rotm2eul(R)
rotm2eul(RB*R)
Result
ans =
1.0e-15 *
-0.0555
0.1110
0
ans =
1.0e-15 *
0.2220
0.7772
-0.2776
ans =
1.2220 0.3483 0.2452
ans =
1.2220 0.3483 0.7549
I will give you a solution based on Euler's rotation theorem.
This solution gives you only the one angle, but the other angles can be derived.
import numpy as np
a_vec = np.array([1, 0, 0])/np.linalg.norm(np.array([1, 0, 0]))
b_vec = np.array([0.32, 0.88, -0.34])/np.linalg.norm(np.array([0.32, 0.88, -0.34]))
cross = np.cross(a_vec, b_vec)
ab_angle = np.arccos(np.dot(a_vec,b_vec))
vx = np.array([[0,-cross[2],cross[1]],[cross[2],0,-cross[0]],[-cross[1],cross[0],0]])
R = np.identity(3)*np.cos(ab_angle) + (1-np.cos(ab_angle))*np.outer(cross,cross) + np.sin(ab_angle)*vx
validation=np.matmul(R,a_vec)
This uses the common axis of rotation (eigenvector in this case), as the cross product.
The matrix R is then the rotation matrix.
This is a general way of doing it, and very simple.

Calculate LookAt like function in 2 dimensions

I'm trying to create a lookAt function in 2 dimensions using Python, so here's my code right now.
from math import *
def lookAt(segment, originPoint):
segmentCenterPoint = getSegmentCenter(segment)
for i in range(2):
vtx = getVertex(segment, i)
x, y = getVertexCoord(vtx)
# Calculate the rotation angle already applied on the polygon
offsetAngle = atan2(y - segmentCenterPoint.y, x - segmentCenterPoint.x)
# Calculate the rotation angle to orient the polygon to an origin point
orientAngle = atan2(segmentCenterPoint.y - originPoint.y, segmentCenterPoint.x - originPoint.x)
# Get the final angle
finalAngle = orientAngle - (pi / 2)
if offsetAngle >= pi:
offsetAngle -= pi
elif offsetAngle < 0:
offsetAngle += pi
finalAngle += offsetAngle
# Temporary move the point to have its rotation pivot to (0,0)
tempX = x - segmentCenterPoint.x
tempY = y - segmentCenterPoint.y
# Calculate coords of the point with the rotation applied
s = sin(finalAngle)
c = cos(finalAngle)
newX = tempX * c - tempY * s
newY = tempX * s + tempY * c
# Move the point to the initial pivot
x = newX + segmentCenterPoint.x
y = newY + segmentCenterPoint.y
# Apply new coords to the vertex
setVertexCoord(vtx, x, y)
I tried some examples manually and worked well, but when I tried to apply the function on thousands of segments, it seems some segment are not well oriented.
I probably missed something but i don't know what it is. Also, maybe there's a faster way to calculate it ?
Thank you for your help.
EDIT
Here is a visualization to understand better the goal of the lookAt.
The goal is to find A' and B' coordinates, assuming we already know O, A and B ones. ([AB] is the segment we need to orient perpendicularly to the point O)
To find positions of A' and B', you don't need rotate points (and dealt with angles at all).
Find vector OC = segmentCenterPoint - originPoint
Make normalized (unit) vector oc = OC / Length(OC)
Make perpendicular vector P = (-oc.Y, oc.X)
Find CB length lCB
Find A' = C + lCB * P
B' = C - lCB * P

calculating angle between three points but only anticlockwise in python

So I'm trying to calculate the angle between three points. for example
a = [14, 140]
b = [13, 120]
c = [12, 130]
d = [11, 110]
|
| c a
|
| d b
|____________
say i want to calculate the angle between ABC i use the follow code
#create vectors
ba = a - b
bc = c- b
# calculate angle
cosine_angle = numpy.dot(ba,bc) / (numpy.linalg.norm(ba) * numpy.linalg.norm(bc))
angle = numpy.arccos(cosine_angle)
pAngle = numpy.degrees(angle)
My script runs and the output angle works, my issue though is when i want to calculate BCD I want the angle on the outside not the inside so say instead of the angle being 120 degrees i want the angle 240. So i only want the anti-clockwise angles.
Not sure how to get this value, can anyone point me in the right direction?
*edit: in other terms i want to identify angles that are over 180 degrees anticlockwise
*edit2: the duplicate answer does not answer the question for me as i have not used alot of java so not sure how to code that in python
Now using angular cosine distance to calculate the angle between two vectors is quite good, but in your case it might be better to use arc tangent as mentioned in the comments.
Now assuming you want to calculate the counterclockwise angle between BCD, you can do this by using the numpy's atan2 function. atan2(x, y) will give the angle between the origin point y to x.
import numpy as np
def calculate_angle(point_a, point_b):
""" Calculate angle between two points """
ang_a = np.arctan2(*point_a[::-1])
ang_b = np.arctan2(*point_b[::-1])
return np.rad2deg((ang_a - ang_b) % (2 * np.pi))
a = np.array([14, 140])
b = np.array([13, 120])
c = np.array([12, 130])
d = np.array([11, 110])
# create vectors
ba = a - b
bc = c - b
cd = d - c
# calculate angle
cosine_angle = np.dot(ba, bc) / (np.linalg.norm(ba) * np.linalg.norm(bc))
angle = np.arccos(cosine_angle)
inner_angle = np.degrees(angle)
print inner_angle # 8.57299836361
# see how changing the direction changes the angle
print calculate_angle(bc, cd) # 188.572998364
print calculate_angle(cd, bc) # 171.427001636
You are able to calculate the inner angle, but you want the reversed angle? why not just calculating 360 - angle

how to rotate a triangle pygame

I have this triangle in pygame
triangle = pygame.draw.polygon(window, (210,180,140), [[x, y], [x -10, y -10], [x + 10, y - 10]], 5)
that i need to rotate towards the mouse, very much like the center arrow in this gif: http://i.stack.imgur.com/yxsV1.gif. Pygame doesn't have a built in function for rotating polygons, so I'll need to manually move the three points in a circle, with the lowermost point [x,y] pointing towards the coords of the mouse. The variables I have are:
the distance between the center of the triangle and the circle i want it to rotate along (i.e. the radius)
the distance from the center to the mouse coordinates
the coordinates of the lowermost point of the triangle [x,y] and the other two sides
with this information, how can I use trigonometry to rotate all three sides of the triangle so that the bottom point allways faces the mouse position?
EDIT: this is what I've got so far, but it only manages to move the triangle back and forth along a diagonal instead of rotating.
def draw(self):
curx,cury = cur
#cur is a global var that is mouse coords
angle = math.atan2(self.x - curx, self.y - cury)
distance = math.sqrt(200 - (200 * math.cos(angle)))
x = self.x + distance
y = self.y + distance
triangle = pygame.draw.polygon(window, (210,180,140), [[x, y], [x - 10,y - 10], [x + 10,y - 10]], 5)
Edit: Thinking about this again this morning there's another way to do this since the polygon is a triangle. Also the math is potentially easier to understand, and it requires less calculation for each point.
Let Cx and Cy be the center of the circle inscribing the triangle. We can describe the equation of a circle using the parametric equation:
F(t) = { x = Cx + r * cos(t)
{ y = Cy + r * sin(t)
Where r is the radius of the circle, and t represents the angle along the circle.
Using this equation we can describe the triangle using the points that touch the circle, in this case we'll use t = { 0, 3 * pi / 4, 5 * pi / 4 } as our points.
We also need to calculate the angle that we need to rotate the triangle so that the point that was at t = (0) is on a line from (Cx, Cy) to the mouse location. The angle between two (normalized) vectors can be calculated by:
t = acos(v1 . v2) = acos(<x1, y1> . <x2, y2>) = acos(x1 * x2 + y1 * y2)
where . represents the dot product, and acos is the inverse cosine (arccos or cos^-1).
From these two equations we can easily create a python function which, given the center of the triangle/circle, the radius of the circle, and the location of the mouse, returns a list of tuples representing the x-y coordinates of the triangle. (For the example the center and mouse position are tuples of the form (x, y))
def get_points(center, radius, mouse_position):
# calculate the normalized vector pointing from center to mouse_position
length = math.hypot(mouse_position[0] - center[0], mouse_position[1] - center[1])
# (note we only need the x component since y falls
# out of the dot product, so we won't bother to calculate y)
angle_vector_x = (mouse_position[0] - center[0]) / length
# calculate the angle between that vector and the x axis vector (aka <1,0> or i)
angle = math.acos(angle_vector_x)
# list of un-rotated point locations
triangle = [0, (3 * math.pi / 4), (5 * math.pi / 4)]
result = list()
for t in triangle:
# apply the circle formula
x = center[0] + radius * math.cos(t + angle)
y = center[1] + radius * math.sin(t + angle)
result.append((x, y))
return result
Calling this function like this:
from pprint import pprint
center = (0,0)
radius = 10
mouse_position = (50, 50)
points = get_points(center, radius, mouse_position)
pprint(points)
produces:
[(7.071067811865475, 7.0710678118654755),
(-10.0, 1.2246467991473533e-15),
(-1.8369701987210296e-15, -10.0)]
which is the three points (x, y) of the triangle.
I'm going to leave the original method below, since it's the way that modern computer graphics systems (OpenGL, DirectX, etc.) do it.
Rotation about the centroid of a arbitrary polygon is a sequence of three distinct matrix operations, Translating the object so that the centroid is at the origin (0,0), applying a rotation, and translating back to the original position.
Calculating the centroid for an arbitrary n-gon is probably outside the scope of an answer here, (Google will reveal many options), but it could be done completely by hand using graph paper. Call that point C.
To simplify operations, and to enable all transformations to be applied using simple matrix multiplications, we use so called Homogeneous coordinates, which are of the form:
[ x ]
p = | y |
[ 1 ]
for 2d coordinates.
Let
[ Cx ]
C = | Cy |
[ 1 ]
The general form of the translation matrix is:
[ 1 0 Vx ]
T = | 0 1 Vy |
[ 0 0 1 ]
Where <Vx, Vy> represents the translation vector. Since the goal of the translation is to move the centroid C to the origin, Vx = -Cx and Vy = -Cy. The inverse translation T' is simply Vx = Cx, Vy = Cy
Next the rotation matrix is needed. Let r be the desired clockwise rotation angle, and R be the general form of the rotation matrix. Then,
[ cos(r) sin(r) 0 ]
R = | -sin(r) cos(r) 0 |
[ 0 0 1 ]
The final transformation matrix is therefore:
[ 1 0 -Cx ] [ cos(r) sin(r) 0 ] [ 1 0 Cx ]
TRT' = | 0 1 -Cy | * | -sin(r) cos(r) 0 | * | 0 1 Cy |
[ 0 0 1 ] [ 0 0 1 ] [ 0 0 1 ]
Which simplifies to:
[ cos(r) sin(r) cos(r)*Cx-Cx+Cy*sin(r) ]
|-sin(r) cos(r) cos(r)*Cy-Cy-Cx*sin(r) |
[ 0 0 1 ]
Applying this to a point p = (x,y) we obtain the following equation:
p' = { x' = Cx*cos(r)-Cx+Cy*sin(r)+x*cos(r)+y*sin(r)
{ y' = -Cx*sin(r)+Cy*cos(r)-Cy-x*sin(r)+y*cos(r)
In Python:
def RotatePoint(c, p, r):
x = c[0]*math.cos(r)-c[0]+c[1]*math.sin(r)+p[0]*math.cos(r)+p[1]*math.sin(r)
y = -c[0]*math.sin(r)+c[1]*math.cos(r)-c[1]-p[0]*math.sin(r)+p[1]*math.cos(r)
return (x, y)
After typing all that I realize that your object may already be centered on the origin, in which case the function above simplifies to x=p[0]*math.cos(r)+p[1]*math.sin(r) and y=p[0]*math.sin(r)+p[1]*math.cos(r)
I put some faith in Wolfram Alpha here, rather than multiplying everything out by hand. If anyone notices any issues, feel free to make the edit.

Calculating point of intersection based on angle and speed

I have a vector consisting of a point, speed and direction. We will call this vector R. And another vector that only consists of a point and a speed. No direction. We will call this one T.
Now, what I am trying to do is to find the shortest intersection point of these two vectors. Since T has no direction, this is proving to be difficult. I was able to create a formula that works in CaRMetal but I can not get it working in python.
Can someone suggest a more efficient way to solve this problem? Or solve my existing formula for X?
Formula:
(source: bja888.com)
Key:
(source: bja888.com)
Where o or k is the speed difference between vectors. R.speed / T.speed
My math could be a bit rusty, but try this:
p and q are the position vectors, d and e are the direction vectors. After time t, you want them to be at the same place:
(1) p+t*d = q+t*e
Since you want the direction vector e, write it like this
(2) e = (p-q)/t + d
Now you don't need the time t, which you can calculate using your speed constraint s (otherwise you could just travel to the other point directly):
The direction vector e has to be of the length s, so
(3) e12 + e22 = s2
After some equation solving you end up with
(4)
I) a = sum(p-q)/(s2-sum(d2))
II) b = 2*sum(d*(p-q))/(s2-sum(d2))
III) c = -1
IV) a + b*t + c*t2 = 0
The sum goes over your vector components (2 in 2d, 3 in 3d)
The last one is a quadratic formula which you should be able to solve on your own ;-)
Let's assume that the first point,
A, has zero speed. In this case, it
should be very simple to find the
direction which will give the
fastest intersection.
Now, A does have a speed. We can force it to have zero speed by deducting it's speed vector from the vector of B. Now we can solve as we did in 1.
Just a rough idea that came to mind...
Some more thoughts:
If A is standing still, then the direction B need to travel in is directly towards A. This gives us the direction in the coordinate system in which A is standing still. Let's call it d.
Now we only need to convert the direction B needs to travel from the coordinate system in which A is still to the coordinate system in which A is moving at the given speed and direction, d2.
This is simply vector addition. d3 = d - d2
We can now find the direction of d3.
And a bit more formal:
A is stationary:
Sb = speed of B, known, scalar
alpha = atan2( a_y-b_y, a_x-b_x )
Vb_x = Sb * cos(alpha)
Vb_y = Sb * sin(alpha)
A moves at speed Sa, direction beta:
Vb_x' = Sb * cos(alpha) + Sa * cos(beta)
Vb_y' = Sb * sin(alpha) + Sa * sin(beta)
alpha' = atan2( Vb_y', Vb_x' )
Haven't tested the above, but it looks reasonable at first glance...
In nature hunters use the constant bearing decreasing range algorithm to catch prey.
I like the explanation of how bats do this link text
We need to define a few more terms.
Point A - the position associated with vector R.
Point B - the position associated with vector T.
Vector AB - the vector from point A to point B
Angle beta - the angle between vector R and vector AB.
Angle theta - the angle between vector T and vector AB
The formula is usually given as
theta = asin( |R| * sin(beta) / |T| )
where
beta = acos( AB.xR.x + AB.yR.y )
You don't want to use this directly, since asin and acos only return angles between -PI/2 to PI/2.
beta = atan2( R.y, R.x ) - atan2( AB.y, AB.x )
x = |R| * sin(beta) / |T|
y = 1 + sqrt( 1 - x*x )
theta = 2*atan2( y, x )
Of course if x > 1 R is too fast and intersection doesn't exist
EG
OK, if I understand you right, you have
R = [ xy0, v, r ]
T = [ xy1, v ]
If you are concerned about the shortest intersection point, this will be achieved when your positions are identical, and in an Euclidean space this also forces the direction of the second "thing" being perpendicular to the first. You can write down the equations for this and solve them easily.

Categories

Resources