Reputation: 155
How would I calculate the difference between 2 angles in degrees?
This is simple for most as I just use:
var difference = Math.Abs(direction1 - direction2);
However when direction2 is north (0 degrees) and direction1 is north west (eg 318 degrees) obviously this is way out.
What's the correct way to calculate this difference past the north (0) boundary?
Upvotes: 1
Views: 1290
Reputation: 36649
Edit: This answer assumes the directions are vectors and not angles. For angles, see Mindswipes answer
In general you take the dot product, use Arccosine to get the angle, and convert to degree by multiplying with 180d / Math.PI
. This assumes the directions are normalized.
var angleInDegrees = Math.ACos(direction1.Dot(direction2)) * 180d / Math.PI;
This always produces a positive angle in the range [0, 180]. This works for both 2D and 3D vectors.
If you ware using 2D vectors and want an angle in [0, 360] you can check if the closest rotation is clockwise or counter clockwise by rotating one of the vectors 90 degrees, and checking if it the angle to the other is smaller or larger than 90 degrees:
var isClockwise = direction1.Dot(new Vector(direction2.Y, -direction2.X)) > 0;
If it is clockwise, add 180 degrees to the result. Or vice versa, depending on your coordinate system.
Upvotes: 2
Reputation: 7950
That's quite easy, all you need to do is add a check to see if the direction (heading) is larger than 180, and if so, subtract the difference from 360. Like so:
static int GetHeadingDifference(int heading1, int heading2)
{
var difference = Math.Abs(heading1 - heading2);
if (difference > 180)
return 360 - difference;
return difference;
}
This will return the correct heading. Here a demonstration.
But you may want to wrap this in a custom object to handle everything for you. This is how you could do it:
struct Heading
{
private const float MaxDegrees = 360;
// Use a float for more accurate heading
public float Degree {get; set;}
public Heading(float heading)
{
Degree = heading;
}
// Override addition to wrap around
public static Heading operator +(Heading a, Heading b)
{
var val = (a.Degree + b.Degree) % MaxDegrees;
return new Heading(val);
}
// Override subtraction to always result in a number <= 180
public static Heading operator -(Heading a, Heading b)
{
var difference = Math.Abs(a.Degree - b.Degree);
if (difference > 180)
return new Heading(MaxDegrees - difference);
return new Heading(difference);
}
// Override equality to check the actual degree value
public static bool operator ==(Heading a, Heading b)
{
return a.Degree == b.Degree;
}
// Overriding equality requires overriding inequality
public static bool operator !=(Heading a, Heading b)
{
return !(a == b);
}
// Override Equals to catch explicit a.Equals(b) calls
public override bool Equals(object other)
{
if (other is not Heading)
return false;
return ((Heading) other).Degree == Degree;
}
// When overriding equality you must implement GetHashCode
public override int GetHashCode()
{
// Oerflow is ok here, just wrap
unchecked
{
var hash = 17;
hash = hash * 23 + Degree.GetHashCode();
return hash;
}
}
}
Demo of it working here
P.S use this if you just want to have your one number, if you actually have vectors, use JonasH's answer
Upvotes: 3