4

Angle A is a degree angle that keeps increasing by increments and Angle B is the stopping point of Angle A (think 'Spin-the-bottle' where Angle A is the current angle of the bottle Angle B is the angle needed to point to your crush and the bottle spins at a fixed rate clock-wise).

To do this, I've been trying to compare Angle A and Angle B with inequalities. If Angle A is 60 degrees and Angle B is 80 degrees, this is no problem. If Angle A is 350 degrees and Angle B is 10 degrees however, the inequality thinks that Angle A has crossed Angle B even though it hasn't.

How do I compare angles when they wraparound at 360 degrees?

This is some pseudo-code for what I have so far:

int AngleB = 30;
int AngleA = 300;

void Update() {
    AngleA += 13;
    if (AngleA > AngleB) {
        AngleA = AngleB;
    }
}

Update: Here's my new method that wraps Angle A relative to Angle B:

double GetAngleDifference(double from, double to)
{
    double difference = to - from;
    while (difference < -180) double += 360;
    while (difference > 180) double-= 360;
    return difference;
}
3
  • 1
    compare directions instead, it alleviates you from the wrap around and only lets you focus on the difference Jan 5, 2015 at 23:20
  • 2
    Your angles aren't plain integers; they form the cyclic group Z/360Z under addition, and therefore follow slightly different mathematical laws than natural numbers. In particular, there is a cyclic order of angles so simply comparing whether one angle is larger than another is meaningless. Ideally, you would define a new angle type with overloaded operators to reflect these changes. The distance between angle a and b is the difference b-a, but in Z/360Z math, 10 - 350 = 20. (Tip: perform normal subtraction and then map the result into the range [0, 360) via a modulo operation).
    – amon
    Jan 5, 2015 at 23:56
  • Thanks for that explanation. I got it working with integers (for precision across multiple clients) by wrapping AngleA relative to AngleB. I didn't think of mapping it into a range, and I think that would've been a lot easier than what I did.
    – JPtheK9
    Jan 6, 2015 at 0:31

4 Answers 4

1

Any angle is equivalent to the angle + 360 degrees.

So if you are increasing a, but a > b (numerically), then add 360 to b at the start. Now a < b works for your loop.

e.g.

a = 270
b = 45
b += 360 // = 405
while (a < b)
  a += ... // 270 up to 405

If you are decreasing a but b > a (numerically), then add 360 to a at the start. Now a > b works for your loop.

e.g.

a = 10
b = 310
a += 360 // = 370
while (a > b)
  a -= ...  // 370 down to 310

That's not the full pseudocode, but illustrates the two cases where you need to worry about "crossing" the 360 mark.

1
  • "Any angle is equivalent to the angle + 360 degrees." --> No, not when angle is a double as many bits of significance can be lost. This is due to the difference between math and double math. Nov 16, 2018 at 19:35
2

If the question is How do I detect whether A has crossed B? you might use the following logic:

    a := A mod 360.
    b := B mod 360.
    prev := a > b.
    A := A + 13.
    a := A mod 360.
    current := a > b.
    Return: current not = prev

The pseudo-code above returns with TRUE if, and only if, A has crossed B. This means that you should update the position of A and, at the same time, find out whether the cross just happened.

3
  • Can you elaborate a bit on "A := A + 13."?
    – J Trana
    Jan 6, 2015 at 3:33
  • See the original question. The constant 13 is used as the value of delta by which A is increased at every step. A more general approach should use A := A + delta instead. Jan 6, 2015 at 8:35
  • ...and that's what I get for not reading closely enough. Thanks!
    – J Trana
    Jan 7, 2015 at 16:36
0

I don't completely understand the problem being posed, but I suspect that it would be useful to find the smallest angle between AngleA and AngleB, where the smallest angle is in the range -180 to 180. This can be done with modulo arithmetic.

Most programming languages have some form of a modulo function, but their behavior varies, see wikipedia page. In order to find the smallest angle, you actually want to use a modulo function that rounds to the nearest integer. It turns out this isn't very common. However, it is rather simple to implement (as described at link):

double ModNearestInt(double a, double b) {
    return a - b * round(a / b);
}

The has the nice property that the remainder returned is

  • always in the interval [-b/2, +b/2]
  • always the shortest distance to zero

So, to find the smallest angle between AngleA and AngleB, you could do:

double smallestAngle = ModNearestInt(AngleA - AngleB, 360.0);

To detect A crossing B in the positive direction if it is known that AngleA is increasing, it is sufficient to check to see that smallestAngle changes sign from negative to positive. When the sign of smallestAngle changes from positive to negative and AngleA is increasing, this corresponds to A crossing (B + 180). Similarly, if it is known that AngleA is decreasing, then A crosses B when the sign of smallestAngle changes from positive to negative.

0

How do deal with angle wraparounds when comparing them?

Given, AngleA, AngleB there is more than one difference. Below the differences are 270 and -90 depending if we move clock-wise or counter clock-wise.

int AngleA = 30;
int AngleB = 300;

Possible conventions:

1) Angle with the smaller magnitude: -90.

2) Smaller of the 2 magnitudes: 90.

3) In a fixed rotation: e.g. clockwise 270.

4) Both: -90, 270.


Let us continue with #3 or 270 degrees given OP's double from, double to code.

How do I compare angles when they wraparound at 360 degrees?

First consideration is what is the domain of from,to?
Could they be any value or are they restricted to [-360...360] or [0...360) or what?
Let us assume [-360...360].

Next, consider type:
For int, use %, the remainder operator.
For double, use fmod, the remainder function.
Remainder differs from mod.

When the goal is for the answer to lie in [0...360)....

With integers, this is simple.

int GetAngleDifferenceClockwise_int(int from, int to)  {
  int diff = (from - to)%360;  // diff now in (-360 ... 360) range
  if (diff < 0) diff += 360;   // diff now in [   0 ... 360) range
  return diff;
}

With double, this more interesting. To preserve precision, usually the target range is [-180 ... 180) rather than [0 ... 360).

double GetAngleDifferenceClockwise_double(double from, double to)  {
  double diff = fmod(from - to, 360.0); // diff now in (-360.0 ... 360.0) range
  if (diff >= 180.0) diff -= 360.0;     // diff now in (-360.0 ... 180.0) range
  else if (diff < -180.0) diff += 360.0;// diff now in [-180.0 ... 180.0) range
  return diff;
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.