Calculating reflex and obtuse angles - math

Given two lines of common origin point, whose rotational angles I have in degrees, what's the best way in Lua to calculate the reflex and obtuse angles involved?

Assuming that you want the reflex angle that complements the obtuse angle, and don't worry about getting values of 90 or 180 degrees for the obtuse value:
function obtuse_reflex(a, b)
local diff = (a - b) % 180
if diff < 90 then diff = 180 - diff end
return diff, 360 - diff
end

Related

Calculate bearing from lateral and longitudinal speeds

How can I calculate the bearing from an relative "origin" by lateral and longitudinal speeds?
For example if the lateral speed was 0 meters a second and the longitudinal speed is positive, that would mean the bearing would be 0 degrees of "origin" but if the longitudinal speed was negative that would indicate the bearing is 180 degrees of "origin". This scenario is simple. (I think, laughs at self).
Now lets make things interesting. The longitudinal speed is still positive, say 30.0 meters a second and my lateral speed is -0.05 meters a second. That would indicate my bearing would be angled ever so slightly "left of origin". But specifically what degree?
Is there a formula to calculate the bearing from two speeds?
Thanks!
After digging into the trigonometry trenches. I found a solution.
Given a lon/lat speeds create a 90 degree triangle. In this scenario the hypotenuse doesn't matter.
It boils down to (in python for folks)...
fraction = a / b # sides of the projection that form the 90 degree angle
if b < 0:
fraction = b / a
bearing = 360 - (90 + math.atan(fraction))
Using that bearing. If you have a distance you can project a point.

Calculating if an angle is between two angles

So I am making a little game where I am checking if a character can "see" another where character A can see character B if A is within a certain distance of B, and the direction in degrees of A is +/- 45 degrees of the angle B is facing.
Currently, I do a little calculation where I'm checking if
(facingAngle - 45) =< angleOfTarget =< (facingAngle + 45)
This works fine except for when we cross the 360 degree line.
Let's say facingAngle = 359, angleOfTarget = 5. In this situation, the target is only 6 degrees off center, so I want my function to return true. Unfortunately, 5 is not between 314 and 404.
Just try
anglediff = (facingAngle - angleOfTarget + 180 + 360) % 360 - 180
if (anglediff <= 45 && anglediff>=-45) ....
The reason is that the difference in angles is facingAngle - angleOfTarget although due to wrapping effects, might be off by 360 degrees.
The add 180+360 then modulo 360 then subtract 180, effectively just converts everything to the range -180 to 180 degrees (by adding or subtracting 360 degrees).
Then you can check the angle difference easily, whether it is within -45 to 45 degrees.
Here is a simple function I found online, and modified. It works correctly for any angles (can be outside of 0-360). (This function is made to work in c, works in Xcode.)
Remember, it checks COUNTER-CLOCKWISE from angle A to angle B. It returns YES (true) if the angle is between :)
First, a simple conversion function to make all angles 1-360
//function to convert angle to 1-360 degrees
static inline double angle_1to360(double angle){
angle=((int)angle % 360) + (angle-trunc(angle)); //converts angle to range -360 + 360
if(angle>0.0)
return angle;
else
return angle + 360.0;
}
Check if angle is between :)
//check if angle is between angles
static inline BOOL angle_is_between_angles(float N,float a,float b) {
N = angle_1to360(N); //normalize angles to be 1-360 degrees
a = angle_1to360(a);
b = angle_1to360(b);
if (a < b)
return a <= N && N <= b;
return a <= N || N <= b;
}
Eg. To check if the angle 300 is between 180 and 10 degrees:
BOOL isBetween=angle_is_between_angles( 300, 180,10);
//RETURNS YES
There is a trigonometric solution that avoids the wrapping problem.
I'm assuming that you have (x, y) coordinates for both characters P1 and P2. You've already specified that you know the distance between the two which you presumably calculated using Pythagoras' theorem.
You can use the dot product of two vectors to calculate the angle between them:
A . B = |A| . |B| . cos(theta).
If you take A as the facingAngle vector it will be [cos(fA), sin(fA)], and will have magnitude |A| of 1.
If you take B as the vector between the two characters, and your distance above you get:
cos(theta) = (cos(fA) * (P2x - P1x) + sin(fA) * (P2y - P1y)) / |B|
where |B| is the distance you've already calculated.
You don't need to actually take the inverse cosine to find theta, since for range of -45 to +45 you just need to check for cos(theta) >= 0.70710678 (i.e. 1 / sqrt(2)).
This might seem slightly complicated, but the chances are that you've already got all of the required variables hanging around in your program anyway.
A simple solution to handle wrapping at the low end (into negative values), is just to add 360 to all your values:
(facingAngle + 315) =< (angleOfTarget + 360) =< (facingAngle + 405)
That way, the subtraction of 45 can never go negative, because it no longer happens.
To handle wrapping at the top end, you need to check again, adding another 360 to the angleOfTarget value:
canSee = (facingAngle + 315 <= angleOfTarget + 360) &&
(angleOfTarget + 360 <= facingAngle + 405);
canSee |= (facingAngle + 315 <= angleOfTarget + 720) &&
(angleOfTarget + 720 <= facingAngle + 405);
Another way using always minimum positive difference and comparing with threshold:
anglediff = Math.min(Math.abs(facingAngle - angleOfTarget), 360 - Math.abs(angleOfTarget - allowDirection));
if (anglediff <= 45)
Restating Alnitak's answer in a different way, a solution that avoids the angle wrap at 360 degrees is to restate the problem in a different coordinate system where the angles are always small. Here is the code:
def inside_angle(facing, target):
dot = cos(facing)*cos(target) + sin(facing)*sin(target)
angle = acos(dot)
return angle <= pi/4
This is done using vector projection. Assuming the vectors |facing> = [cos(facing) sin(facing)] and |target> = [cos(target) sin(target)], when projecting the target into the facing vector, the angle will range from zero, when the target is exactly at the facing vector or will increase to either side. This way we can just compare it to pi/4 (45 degrees). The formula for the angle is the following:
cos(angle) = <facing|target> / <target|target> <facing|facing>
That is, the cosine of the angle is the dot product between the vectors |facing> and |target> divided their modules, which is 1 in this case, which becomes:
angle = acos(<facing|target>)
Reference:
https://en.wikipedia.org/wiki/Vector_projection

About Sines in Programming

I am trying to understand trigonometry and the short answer is that I do not.
I drew a little triangle to mess around with and I asked myself the question, "If I know the length of the hypotenuse and the angle, how do I find the length of the other edges?".
Then I started reading. Apparently, the sine of angle A is supposed to equal the length of the opposite side divided by the length of the hypotenuse. So I figured that, using a right triangle, multiplying the length of the hypotenuse by the sine of the angle would yield the length of the opposing side.
1.414 / 1 = .707blahblah * 1.414 = 1 on my calculator.
But in every programming language I try sin(45.0) equals .8somethingsomething. I tried c++, c#, java, php, and lua.
Is the input not being interpreted as degrees? What unit is being used and how do I convert it? I've been seeing the word Radians, it would be helpful if someone could explain what a Radian is.
Radians are units of angular measure, like degrees, except that while there are 360 degrees in a circle, there are 2*pi (about 6.28) radians in a circle. You can convert degrees to radians by multiplying by pi (3.14159) and dividing by 180.
The formula works if the triangle is a right triangle, and yes, most programming languages expect radians rather than degrees as arguments to functions like sin() and cos().
Regarding the argument in the comments below: if you fix angle <BAC, side AB, and side BC, you can see that there are two possible positions for point C which preserve the the length D2 for side BC. Therefore <BAC, D1, and D2 do not fully determine a triangle.
The input to sin functions generally is expected in radians, not degrees. For example, in the Java documentation for sin it's stated that:
Parameters:
a - an angle, in radians.
Convert the angle in degrees to radians first, by multiplying it by pi/180
A radian is the distance of the radius of a circle along its circumference. Since a circle's circumference is 2 times pi times its radius, there are 2 times pi radians in one complete circle.
Yes, you are correct. Those functions all take their input in radians, not degrees.
You can convert degrees to radians by multiplying the degrees by π/180.
Convert to radians: Radian = degree/180*Pi
In order to convert from degrees to radians, divide the number in degrees by 180 and multiply by pi.

Finding if an angle lies between two points

This is basically just a math question.
Heres what I am having troubles with... I am having a difficult time coming up with how to phrase the question, so bear with me. Basically I think I need to use some advanced math to accomplish this, but I do not know what I need.
I will use some illustrations to make this clear. Spam prevention doesn't let me post pictures... Here's a simple concept image though: http://radleygh.com/images/gimp-2_2011-057-00-57-26-40.bmp
Objective: Determine if several objects lie within a cone on a 2D plane
Cone Properties:
Position (x, y)
Angle (0-359)
Spread (0-359, aka Width)
Distance (0++)
I can decide the brownish lines using a simple bit of math:
Angle_A = Angle + (Spread / 2)
Angle_B = Angle - (Spread / 2)
Angle_Target = Point_Direction(origin, object_position)
Now I thought of comparing these with the position of each object with a simple if/then statement:
If (Angle_A > Angle_Target) && (Angle_B < Angle_Target) Then Angle_Target is between A and B
This works... untill Angle_A or Angle_B pass the 0-360 threshold. 0* is between 45* and 315*... but the above if statement wouldn't work. We can then determine which direction to check based on the size of the cone...
And what if the cone effect is larger than a 180* cone?
I'm not sure of the answer. I'm pretty sure I should be using Radians... But I do not understand the concept of Radians. if someone can point me in the right direction, perhaps show me an example somewhere, that would be wonderful!
I will continue to do my own research in the mean time.
You may consider a simple transformation which sets your coordinate system such that Angle_B is zero. In other words, instead of testing
Angle_B < Angle_Target < Angle_A
you may also use
0 < Angle_Target - Angle_B < Angle_A - Angle_B
If you apply a modulo 360° to all terms you're logic should work:
0 < (Angle_Target - Angle_B) % 360 < (Angle_A - Angle_B) % 360
One radian is the angle made by tracing a circle's circumference by a length equal to that circle's radius. Hence there are exactly 2*PI radians in a circle.
So 2*PI radians = 360 degrees
So to convert degrees to radians, multiply by 2 * PI, then divide by 360. (Or of course, multiply by PI, divide by 180).
However, whether you work in radians or degrees should only be dictated by the library you are using. Even then, you could write wrappers which do the above calculations.
But to the main part of your question. Consider that:
sin (theta) = sin (360 + theta).
cos (theta) = cos (360 + theta).
etc.
So if you come across your cone that goes through 0 degrees, simply add 360 to both angles of the cone.
e.g. if your cone goes from -10 to +20, simply use 350 to 380 instead.
And of course, when you test an angle, make sure you also add 360 to that and test both the original and added angles.
e.g. testing +5 (which is in your cone), you would test 5 (which fails) then 365 (which passes).
Good luck!

Angle of a vector pointing from A to B

I'm not the best in Maths, but for what I am doing now I need to calculate the angle of the vector which is shown as arrow in the picture below:
I have a point A and a point B in a 2D plane. I need to calculate the following:
The angle in which the arrow must be rotated in order to point to B
atan2(yB-yA, xB-xA), assuming your library has atan2. Otherwise you need to use atan, which will return the correct answer if B is to the right of A, and will be 180 degrees off otherwise. Also note that the return value is in radians, you can convert radians to degrees by multiplying by 180/pi if necessary.
Wikipedia has a detailed explanation of the geometry.
arctan((A.y - B.y) / (A.x - B.x)) and note the special case where A.x = B.x

Resources