4

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
}
ATD
  • 824
  • 1
  • 9
  • 14
  • 1
    How going counter-clockwise from the upper left quadrant to the lower left quadrant jumps from positive to negative without crossing 0. (Yet going clockwise will go negative, 0, positive.) – ATD Jan 25 '13 at 00:22
  • Ah. I see. This would be a simple calculation if you converted to degrees first. – Sam Axe Jan 25 '13 at 00:30
  • By distance you mean the straight line joining the two interception points? – António Almeida Jan 25 '13 at 00:33
  • 1
    @Dan-o How would it be simpler in degrees? You'd still get the jump from -179, 180/-180, 179...or 359,360/0, 1 – ATD Jan 25 '13 at 00:51
  • @ToniAlmeida - I mean the smallest angle between the two angles. So the difference in rotation between Angle1 = -3pi/4 and Angle2 = 3pi/4 should be pi/2, not 3pi/2. – ATD Jan 25 '13 at 00:53
  • @ATD: see my answer below – Sam Axe Jan 25 '13 at 01:20

6 Answers6

7

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
António Almeida
  • 9,620
  • 8
  • 59
  • 66
5
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
Sam Axe
  • 33,313
  • 9
  • 55
  • 89
  • Left: 0 | Top: 90 | Right 180 | Bottom 270 Assuming that your circle is like this... if Angle1 = 45 and Angle2 = 315, then delta = 90 (correct). However, if Angle1 = 0 and Angle2 = 225, then delta = 45 (incorrect). Distance between 0 and 225 is the same as (360 - 225) and should be 135. Close, but not quite right. – ATD Jan 25 '13 at 02:05
  • I edited my answer at roughly the time you made that comment. I believe the edit is correct. – Sam Axe Jan 25 '13 at 03:10
  • Yeah, this works now. Also, just to make note of it, you could use Math.abs(dAngle1 - dAngle2) instead of the max/min thing. – ATD Jan 30 '13 at 20:27
1

π/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
 }
David Moews
  • 186
  • 3
1

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;
Eric Aya
  • 69,473
  • 35
  • 181
  • 253
Shamr
  • 11
  • 1
0

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)).

rasmus
  • 3,136
  • 17
  • 22
0

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.

Patashu
  • 21,443
  • 3
  • 45
  • 53