+1  A: 

As Marcel rightly points out, modulo on negative numbers is potentially problematic. Also, what is the difference between 355 and 5 degrees? It might be worked out to be 350 degrees but 10 degrees is probably what people are expecting. We make the following assumptions:

  1. we want the smallest positive angle between two other angles so 0 <= diff <= 180;
  2. we are working in degrees. If radians, substitute 360 for 2*PI;
  3. angles can be positive or negative can be outside the range -360 < x < 360 where x is an input angle and
  4. order of input angles or the direction of the difference is irrelevant.

Inputs: angles a and b. So the algorithm is simply:

  1. Normalize a and b to 0 <= x < 360;
  2. Compute the shortest angle between the two normal angles.

For the first step, to convert the angle to the desired range, there are two possibilities:

  • x >= 0: normal = x % 360
  • x < 0: normal = (-x / 360 + 1) * 360 + x

The second is designed to remove any ambiguity on the difference in interpretation of negative modulus operations. So to give a worked example for x = -400:

  -x / 360 + 1
= -(-400) / 360 + 1
= 400 / 360 + 1
= 1 + 1
= 2

then

normal = 2 * 360 + (-400)
       = 320

so for inputs 10 and -400 the normal angles are 10 and 320.

Now we calculate the shortest angle between them. As a sanity check, the sum of those two angles must be 360. In this case the possibilities are 50 and 310 (draw it and you'll see this). To work these out:

normal1 = min(normal(a), normal(b))
normal2 = max(normal(a), normal(b))
angle1 = normal2 - normal1
angle2 = 360 + normal1 - normal2

So for our example:

normal1 = min(320, 10) = 10
normal2 = max(320, 10) = 320
angle1 = normal2 - normal1 = 320 - 10 = 310
angle2 = 360 + normal1 - normal2 = 360 + 10 - 320 = 50

You'll note normal1 + normal2 = 360 (and you can even prove this will be the case if you like).

Lastly:

diff = min(normal1, normal2)

or 50 in our case.

cletus
Have you a typo there between angle1 and angle2?
Charlie Salts
Modulo on a potentially negative number (diff) might be dangerous in some languages.
Marcel J.
Is that relying on the angle being 0 - 360, or can I use it with angles being between -180 and 180?
Charlie Somerville
I tested that (http://codepad.org/UIvgBnOr) and it doesn't appear to work
Charlie Somerville
+2  A: 

try this formula:

360-(|a-b|)%360<x || (|a-b|)%360<x

Or, in PHP:

<?php

$b = 10;
$angle1 = -179;
$angle2 = 180;

$diff = $angle1 - $angle2;
if(abs($diff % 360) <= $b || (360-abs($diff % 360))<=$b) {
  echo "yes";
} else {
  echo "no";
}

?>
Ngu Soon Hui
This appears to work! Thanks Ngu.
Charlie Somerville
+1  A: 

You can also use a dot product:

cos(a)*cos(b) + sin(a)*sin(b) >= cos(x)
peejaybee
+1  A: 

For a radius of 1, the distance between the line endpoints is 2sin((a-b/2). So throw away the 2 since you are only interested in a comparison, and compare sin(x/2) with sin((a-b)/2). The trig functions take care of all the wrapping.

Steve Weller