Question

Atan2(y,x) will return a float between -pi and pi. I want to calculate the distance between two angles, but the non-continuity is throwing me off.

See this for better understanding.

I want to be able to calculate the distance between Angle 1 and Angle 2.

The whole point of this is to be able to create a cone from the center to a specified angle. Essentially I will be evaluating:

if(DistanceFromAngle1 < pi/4 [45°])
{
  Angle2 is part of cone
}
Was it helpful?

Solution

If by distance you mean the straight line joining the two interception points, you can calculate the distance by doing this:

SQRT( ( ABS|cos(A) - cos(B)| )^2 + ( ABS|sin(A) - sin(B)| )^2 )

SQRT = square root

ABS = Absolute value

If the distance is the angle, you calculate it by doing (pseudo-code)

var angle = ABS(A - B)
if(angle > pi) angle = 2*pi - angle
return angle

OTHER TIPS

dAngle1 = //convert angle1 to degrees
dAngle2 = // convert to degrees

delta = Math.Max(dAngle1, dAngle2) - Math.Min(dAngle1, dAngle2)
if (180 < delta) {
  delta = 360 - delta;
}

// convert delta to radians if you want

π/2 is 90°, not 45°. I'm going to assume you want to know whether Angle 2 is in an interval centered around Angle 1 which extends 45° away from it in both directions.

You can take the difference between Angle 2 and Angle 1, and reduce modulo 2π until the difference is in [-π, π). This will give a signed distance between Angle 2 and Angle 1. Then, check to see if this is in (-π/4, π/4). Since the value returned by atan2 is always between -π and π, the original difference will always be between -2π and 2π, so you can lump all this into one check:

 if (angle2 - angle1 < -7π/4 || 
     (angle2 - angle1 > -π/4 && angle2 - angle1 < π/4) ||
     angle2 - angle1 > 7π/4)
 {
   angle2 is less than 45° away from angle1
 }

Two wariants of angle difference calculation:

procedure TForm1.sButton1Click(Sender: TObject);
Var a, b, dif : Extended;
begin
  a := sCalcEdit1.Value;
  b := sCalcEdit2.Value;
  If ((a < 180) and (b >= 180) or
      (a >= 180) and (b < 180)) and (abs(a - b) < 180)  then
  Begin
  End else
  If (a < 180) and (b >= 180) then
  Begin
    b := b - 360;
  End else
  If ((a >= 180) and (b < 180)) then
  Begin
    a := a - 360;
  End;
  dif := abs(a - b);
  sCalcEdit3.Value := dif;
end;

procedure TForm1.sButton2Click(Sender: TObject);
Var a, b, dif : Extended;
begin
  a := sCalcEdit1.Value * pi / 180;
  b := sCalcEdit2.Value * pi / 180;
  dif := arccos(cos(a - b));
  sCalcEdit3.Value := dif * 180 / pi;
end;

I want to give an alternative solution: You can use vector math. This can for example be useful if you have two vectors as a starting point (which seems to be your case).

Given two normalized vectors, a and b, the angle between them simply becomes acos(dot(a, b)) = acos(ax*bx + ay*by).

To get a normalized vector from an angle, alpha, you can use a = vec2(cos(alpha), sin(alpha)), for example.

To normalize a denormal vector, use na = a / length(a) = a / sqrt(dot(a, a)).

EDIT: I'm not sure if this will work. I translated it from some python code, but I'm not sure if divmod(radians, math.pi*2)[1] is the same behaviour as System.Math.IEEERemainder(radians, Math.PI*2.0). Need to test...

EDIT2: I think using % is correct

EDIT3: Blah, it's not correct because it returns a negative value for negative numbers. Does anyone know how to get python divmod in C#?

How to calculate the angle between two angles:

public static double NormalizeAngle(double radians)
{
 return fmod(radians,Math.PI*2.0); # this method doesn't exist, see above
}

public static double ArcLength(double radians1, double radians2)
{
 radians1 = NormalizeAngle(radians1);
 radians2 = NormalizeAngle(radians2);
 return Math.Min(NormalizeAngle(radians1 - radians2, NormalizeAngle(radians2 - radians1));
}

How it works is it tries both ways around, all calculations mod 2pi, and it picks the one with a smaller distance.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top