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?
The angle opposite the smallest side of a triangle has the smallest measure. Likewise, the angle opposite the largest side has the largest measure.
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).
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θ.
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));
You would expand the check for out of bound angles:
if (dif < 0) dif = dif + 360;
if (dif > 180) dif = 360 - dif;
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)
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; }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With