Arctan > 1 newbie question - trigonometry

It has been quite some time since I've had to compute the theta of an angle. But given a right angle:
|
|
b |
-----------------
a
I'm trying to compute theta (the slope of the angle). My understanding of trigonometry (as rusty as it is) is that theta = arctan(b/a). So if b = 50 and a = 1811. Then using the windows calculator, 50 / 1811 = 0.027609055770292655991165102153506. Therefore the arctan(b/a) = 1.5814806205083755492980816356377. If my math is correct, how do I translate this value into the slope of the angle? It should be around 30-40 degrees, right?

atan2(y, x)
will return you the angle in radians (and successfully cope with the cases where x and/or y are 0).
To convert to degrees apply the following formula:
double degrees = radians * (180 / PI)
Where PI is 3.141592... or math.pi in c#

If you use a C dialect then there a useful function for just this purpose
atan2(y, x);

Related

Having trouble aligning 2D Lidar pointcloud to match the coordinate system of HTC Vive Controller

I have strapped on an RPLidar A1 to an HTC Vive Controller and have written a python script that converts the lidar's pointcloud to XY coordinates and then transforms these points to match the rotation and movement of the Vive controller. The end goal is to be able to scan a 3D space using the controller as tracking.
Sadly, everything I try, the native quaternion of the triad_openvr library, transformation matrix transform, euler angles even, I simply cannot get the system to function on all possible movement/rotation axes.
# This converts the angle and distance measurement of lidar into x,y coordinates
# (divided by 1000 to convert from mm to m)
coord_x = (float(polar_point[0])/1000)*math.sin(math.radians(float(polar_point[1])))
coord_y = (float(polar_point[0])/1000)*math.cos(math.radians(float(polar_point[1])))
# I then tried to use the transformation matrix of the
# vive controller on these points to no avail
matrix = vr.devices["controller_1"].get_pose_matrix()
x = (matrix[0][0]*coord_x+matrix[0][1]*coord_y+matrix[0][2]*coord_z+(pos_x-float(position_x)))
y = (matrix[1][0]*coord_x+matrix[1][1]*coord_y+matrix[1][2]*coord_z+(pos_y-float(position_y)))
z = (matrix[2][0]*coord_x+matrix[2][1]*coord_y+matrix[2][2]*coord_z+(pos_z-float(position_z)))
# I tried making quaternions using the euler angles and world axes
# and noticed that the math for getting euler angles does not correspond
# to the math included in the triad_vr library so I tried both to no avail
>>>>my euler angles
>>>>angle_x = math.atan2(matrix[2][1],matrix[2][2])
>>>>angle_y = math.atan2(-matrix[2][0],math.sqrt(math.pow(matrix[2][1],2)+math.pow(matrix[2][2],2)))
>>>>angle_z = math.atan2(matrix[1][0],matrix[0][0])
euler = v.devices["controller_1"].get_pose_euler()
>>>>their euler angles (pose_mat = matrix)
>>>>yaw = math.pi * math.atan2(pose_mat[1][0], pose_mat[0][0])
>>>>pitch = math.pi * math.atan2(pose_mat[2][0], pose_mat[0][0])
>>>>roll = math.pi * math.atan2(pose_mat[2][1], pose_mat[2][2])
#quaternion is just a generic conversion from the transformation matrix
#etc
Expected results are a correctly oriented 2D slice in 3D space of data, that, if appended, would eventually map the whole 3D space. Currently, I have only managed to successfully scan only on a single axis Z and pitch rotation. I have tried a near infinite number of combinations, some found on other posts, some based on raw linear algebra, and some simply random. What am I doing wrong?
Well we figured it out by working with the euler rotations and converting those to a quaternion:
We had to modify the whole definition of how triad_openvr calculates the euler angles
def convert_to_euler(pose_mat):
pitch = 180 / math.pi * math.atan2(pose_mat[2][1], pose_mat[2][2])
yaw = 180 / math.pi * math.asin(pose_mat[2][0])
roll = 180 / math.pi * math.atan2(-pose_mat[1][0], pose_mat[0][0])
x = pose_mat[0][3]
y = pose_mat[1][3]
z = pose_mat[2][3]
return [x,y,z,yaw,pitch,roll]
And then had to further do some rotations of the euler coordinates originating from the controller here (roll corresponds to X, yaw corresponds to Y, and pitch corresponds to Z axis for some unknown reason):
r0 = np.array([math.radians(-180-euler[5]), math.radians(euler[3]), -math.radians(euler[4]+180)])
As well as pre-rotate our LiDAR points to correspond to the axis displacement of our real world construction:
coord_x = (float(polar_point[0])/1000)*math.sin(math.radians(float(polar_point[1])))*(-1)
coord_y = (float(polar_point[0])/1000)*math.cos(math.radians(float(polar_point[1])))*(math.sqrt(3))*(0.5)-0.125
coord_z = (float(polar_point[0])/1000)*math.cos(math.radians(float(polar_point[1])))*(-0.5)
It was finally a case of rebuilding the quaternions from the euler angles (a workaround, we are aware) and do the rotation & translation, in that order.

How can I scale a 2D rotation vector without trig functions?

I have a normalized 2D vector that I am using to rotate other 2D vectors. In one instance it indicates "spin" (or "angular momentum") and is used to rotate the "orientation" of a simple polygon. My vector class contains this method:
rotateByXY(x, y) {
let rotX = x * this.x - y * this.y;
let rotY = y * this.x + x * this.y;
this.x = rotX;
this.y = rotY;
}
So far, this is all efficient and uses no trig whatsoever.
However, I want the "spin" to decay over time. This means that the angle of the spin should tend towards zero. And here I'm at a loss as to how to do this without expensive trig calls like this:
let angle = Math.atan2(spin.y, spin.x);
angle *= SPIN_DECAY;
spin = new Vector2D(Math.cos(angle), Math.sin(angle));
Is there a better/faster way to accomplish this?
If it's really the trigonometric functions what is slowing down your computation, you might try to approximate them with their Taylor expansions.
For x close to zero the following identities hold:
cos(x) = 1 - (x^2)/2! + (x^4)/4! - (x^6)/6! + ...
sin(x) = x - (x^3)/3! + (x^5)/5! - (x^7)/7! + ...
atan(x) = x - (x^3)/3 + (x^5)/5 - (x^7)/7 + ...
Based on the degree of accuracy you need for your application you can trim the series. For instance,
cos(x) = 1 - (x^2)/2
with an error of the order of x^3 (actually, x^4, as the term with x^3 is zero anyway).
However, I don't think that this is going to solve your problem: the actual implementation of atan is likely to be already using the same trick, written by someone with lots of experience of speeding these things up. So this is not really a proper answer but I hope it could still be useful.

Finding the angle in a right-angle triangle with python 3

I manage to solve this question for only 1 case out of the 5 in the system. I'm certain that my method is correct, but for some reason it doesn't work out for other cases.
Below is my code
import math
AB = int(input("Enter a value for side AB: "))
while(AB>100 and AB<=0):
AB = input("Enter a value for side AB: ")
BC = int(input("Enter a value for side BC: "))
while(BC>100 and BC<=0):
BC = input("Enter a value for side BC: ")
hyp = math.sqrt(math.pow(AB,2) + math.pow(BC,2)) #find side AC
mhyp = hyp/2 #find side MC
sind = (mhyp/BC) #sin(deg)=opp/hypotenuse
degree = round(((math.asin(sind))/((math.pi)*2))*360,0) #find the angle
print("%d" %(degree) + "°")
For the case when AC and BC are 10, it did yield 45 degrees as the angle. But when AC=1 and BC=100, it produces an error since arcsine cannot accept value beyond 1.7 radians. Same goes for AC=20 and BC=10 and AC=100 and BC=1..
Is this question solvable?
It is a matter of primarily your angle coming in radians and then you converting it into degrees. Rest everything then will fall in place :)
Also, We can see that BM is equal to MC basis the median to hypotenuse property making the triangle MBC as isosceles and hence Angle MBC = Angle MCB.
import math
if __name__ == '__main__':
AB = input()
assert 0<int(AB)<=100
BC = input()
assert 0<int(BC)<=100
assert (int(AB) >= 0 and float(AB).is_integer() == True) and (int(BC) >= 0 and float(BC).is_integer() == True)
AC = math.sqrt((int(AB)**2) + (int(BC)**2))
tan_acb_rad = int(AB)/int(BC)
acb_rad = math.atan(tan_acb_rad) #the angle comes in radians
acb_deg = math.degrees(acb_rad) #you have to convert it into degrees
ang_mbc = acb_deg
print(str(int(round(ang_mbc,0)))+u"\N{DEGREE SIGN}") #adding the degree symbol at end
import math
AB =int(input())
BC =int(input())
degree=u'\N{DEGREE SIGN}'
print(str(int(round(math.degrees(math.atan(AB/BC)))))+degree)
I know this isn't exactly your case but it still might explain your issue
Inverse Sine of a Value Greater than One
Think about what the sine wave or curve looks like. As the angles
change, the sine of the angle goes up and down, but it never goes
above 1 or below -1. In other words, there is no angle with a sine
that is greater than 1.
When you use the sine key, you put in an angle and get out the sine of
that angle. For instance, when you do sin(30) you are finding the
sine of 30 degrees and the calculator says it's 0.5. When you use the
inverse sine (shift-sine) you put in the value of the sine and the
calculator tells you the angle. So, the inverse sine of 0.5 is 30
since a 30 degree angle has a sine of 0.5.
So when you ask the calculator to do the inverse sine of 1.732, you
are asking it what angle has a sine of 1.732. But as we said above,
there is no angle that has a sine greater than 1. The inverse sine or
arcsin of 1.732 does not exist. That's what the calculator is saying.
It sounds like your problem is asking you to try to find angle B in a
triangle with a = 40, b = 80, and A = 60 degrees. Try constructing
such a triangle, and see what happens. We make angle A and mark 80
units on one of its rays for side b, then swing an arc around the
resulting point C with a radius or length of 40, so that its
intersection with the other ray will give point B. What happens?
B
/
/
/
/
/
c / ooooooooo
/ oooo oooo
/ ooo \ ooo
/ oo \
/ o \ a=40
/ o \
/ o \
/ o \
/60 o \
A----------------o----------------C-----------
b=80
So the calculator is correct: there is no such triangle! Obviously we
can't measure angle B at the top if side 'a' is not long enough to
complete the triangle and form that angle.
You made mistake in geometry - BM is median, not a height to AC (they accidentally coincide for isoseles right-angle triangle, but differ in general case).
So angle BMC is not right in general case, and you cannot get sin(theta) as ratio of MC and BC
But there is well-known property of right triangle - center of circumcircle lies in the middle of hypotenuse, so M point in this case is circumcenter.
This fact immediately tells us that BM=MC (two radii), BMC triangle is isosceles and theta = ACB angle.
Solution is pretty simple (note atan using):
import math
AB = 1
BC = 1
theta = math.atan(AB / BC)
degrees = round(theta * 180 / math.pi)
print(degrees)
>> 45
AB = 3
BC = 4
...
>> 37

How to get a point on an ellipse's outline given an angle?

So, I have ellipses given - they are defined by their midpoint, an horizontal radius(rh) and an vertical radius(rv). I'm drawing them using sin/cos and the result looks fairly good to me(just making sure this isn't an error source).
Now say I have an angle(or a direction vector) given and I want to have the point on the ellipse's outline with that angle/direction. My intuitive approach was to simply use the direction vector, normalise it and multiply its x-component with rh, its y-component with rv. Now both my written program AND all the calculations I did on a paper give me not the point I want but another one, though it's still on the ellipse's outline. However, this method works just fine if the direction is one of (1,0), (0, 1), (-1, 0), (0, -1), (so it works for 0°, 90°, 180°, 270°).
Although there is a farily big amount of data about ellipses themselves on the internet, I couldn't find any information about my particular problem - and I couldn't come up with any better solution than the above one.
So, any idea how to achieve this?
If I understand what you are asking then I think that what you need is polar form of an ellipse where the angle is measured from the ellipse centre. Using this form of the ellipse, you will be able to evaulate your elliptic radius value for a given choice of theta and then plot your point.
If you take a look at this gif image you will see why using the parametric angle give you the correct result only at theta = 90, 180, 270 and 360 degrees http://en.wikipedia.org/wiki/File:Parametric_ellipse.gif . Use the polar form for an ellipse and you should get the points that you want.
You are correct - the parametric angle is not the same as the angle between the desired point and the X axis. However, their tangents are proportional (with a factor of rh/rv) so you can use this approach:
Get the tangent of the desired angle
Multiply this tangent by rh/rv
Use trigonometric identities to compute the sine and cosine from the tangent
Scale/position the point according to the parameters (midpoint, rh, rv)
In Python:
from math import copysign, cos, sin, sqrt
class Ellipse:
def __init__(self, mx, my, rh, rv):
self.mx = mx
self.my = my
self.rh = rh
self.rv = rv
def pointFromAngle(self, a):
c = cos(a)
s = sin(a)
ta = s / c ## tan(a)
tt = ta * self.rh / self.rv ## tan(t)
d = 1. / sqrt(1. + tt * tt)
x = self.mx + copysign(self.rh * d, c)
y = self.my + copysign(self.rv * tt * d, s)
return x, y

How to determine whether a point (X,Y) is contained within an arc section of a circle (i.e. a Pie slice)?

Imagine a circle. Imagine a pie. Imagine trying to return a bool that determines whether the provided parameters of X, Y are contained within one of those pie pieces.
What I know about the arc:
I have the CenterX, CenterY, Radius, StartingAngle, EndingAngle, StartingPoint (point on circumference), EndingPoint (point on circumference).
Given a coordinate of X,Y, I'd like to determine if this coordinate is contained anywhere within the pie slide.
Check:
The angle from the centerX,centerY through X,Y should be between start&endangle.
The distance from centerX,centerY to X,Y should be less then the Radius
And you'll have your answer.
I know this question is old but none of the answers consider the placement of the arc on the circle.
This algorithm considers that all angles are between 0 and 360, and the arcs are drawn in positive mathematical direction (counter-clockwise)
First you can transform to polar coordinates: radius (R) and angle (A). Note: use Atan2 function if available. wiki
R = sqrt ((X - CenterX)^2 + (Y - CenterY)^2)
A = atan2 (Y - CenterY, X - CenterX)
Now if R < Radius the point is inside the circle.
To check if the angle is between StartingAngle (S) and EndingAngle (E) you need to consider two possibilities:
1) if S < E then if S < A < E the point lies inside the slice
2) if S > E then there are 2 possible scenarios
if A > S
then the point lies inside the slice
if A < E
then the point lies inside the slice
In all other cases the point lies outside the slice.
Convert X,Y to polar coordinates using this:
Angle = arctan(y/x);
Radius = sqrt(x * x + y * y);
Then Angle must be between StartingAngle and EndingAngle, and Radius between 0 and your Radius.
You have to convert atan2() to into 0-360 before making comparisons with starting and ending angles.
(A > 0 ? A : (2PI + A)) * 360 / (2PI)

Resources