Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Smallest difference between two angles?

Tags:

c#

math

xna

I'm trying to calculate the smallest difference between two angles.

This is my current code (a slight variation of something I found online):

float a1 = MathHelper.ToDegrees(Rot);
float a2 = MathHelper.ToDegrees(m_fTargetRot);

float dif = (float)(Math.Abs(a1 - a2);

if (dif > 180)
  dif = 360 - dif;

dif = MathHelper.ToRadians(dif);

It works fine except for in cases at the edge of a circle. For example if the current angle is 355 and the target angle is 5 it calculates the difference is -350 rather than 10 since 365 degrees is equal to 5 degrees.

Any ideas on what I can do to make this work?

like image 770
meds Avatar asked Jul 17 '11 06:07

meds


People also ask

How do you find the shortest angle?

The angle opposite the smallest side of a triangle has the smallest measure. Likewise, the angle opposite the largest side has the largest measure.

What is the difference between angles made by minute hand and hour?

The minute hand moves 360 degrees in 60 minute(or 6 degrees in one minute) and hour hand moves 360 degrees in 12 hours(or 0.5 degrees in 1 minute).

What is the formula to find the angle between two vectors?

Formula for angle between two Vectors The cosine of the angle between two vectors is equal to the sum of the product of the individual constituents of the two vectors, divided by the product of the magnitude of the two vectors. =| A | | B | cosθ.


4 Answers

You basically had it. Just take the dif modulus 360 before checking to see if greater than 180:

float a1 = MathHelper.ToDegrees(Rot);
float a2 = MathHelper.ToDegrees(m_fTargetRot);

float dif = (float)Math.Abs(a1 - a2) % 360;

if (dif > 180)
    dif = 360 - dif;

dif = MathHelper.ToRadians(dif);

Edit: @Andrew Russell made a great point in comments to your question and the solution below takes advantage of the MathHelper.WrapAngle method as he suggested:

diff = Math.Abs(MathHelper.WrapAngle(a2 - a1));
like image 167
Prestaul Avatar answered Sep 17 '22 13:09

Prestaul


You would expand the check for out of bound angles:

if (dif < 0) dif = dif + 360;
if (dif > 180) dif = 360 - dif;
like image 20
Guffa Avatar answered Sep 21 '22 13:09

Guffa


I never like handling the zero-wrapping with case statements. Instead, I use the definition of the dot product to compute the (unsigned) angle between two angles:

vec(a) . vec(b) = ||a|| ||b|| cos(theta)

We're just going to make a and b unit vectors, so ||a|| == ||b|| == 1.

Since vec(x) = [cos(x),sin(x)], we get:

unsigned_angle_theta(a,b) = acos(cos(a)cos(b) + sin(a)sin(b))

(n.b. all angles in radians)

like image 29
Robert Calhoun Avatar answered Sep 20 '22 13:09

Robert Calhoun


You can normalize the result to be 0 <= theta < 360:

while(theta < 0) { theta += 360; }

If you want to keep the answer in radians (recommended):

const Double TwoPi = 2 * Math.Pi;
while(theta < 0) { theta += TwoPi; }
like image 27
codekaizen Avatar answered Sep 18 '22 13:09

codekaizen