Skip to content

151. When (2D) rotations go weird

February 19, 2014

Recently, a couple of forum users posted the same problem. They had something rotating on the screen, when suddenly, it started going in the opposite direction, as shown in this video. As the rotation gets to 180 degrees, the ship suddenly flips the other way.

This is a mysterious problem, and the solution seems equally mysterious.

  • If your angle is greater than 180 degrees, subtract 360 degrees
  • if your angle is less than -180 degrees, add 360 degrees

This is another post with the same problem.

So what is going on?

The first clue is that this doesn’t happen when you simply rotate by an angle, which we’ll call A. You can write a little program which keeps adding 1 to A,  rotating by A and drawing a sprite, and your sprite will turn happily round and round forever without any problems.

The problem happens if you don’t know the angle, eg you might be trying to calculate the angle between two objects on the screen. You can do this by subtracting their x and y values from each other, and using math.atan2 ( y difference , x difference), to calculate the angle between them.

Note – there are two atan functions – atan, and atan2. Atan2 gives a more precise answer, so always use that.

This works nicely, except for one little thing. The tan function repeats every 180 degrees. So the tan of 20 degrees and 200 degrees both equal 0.36. Obviously, the atan2 function can only give you one answer, so it always gives you an answer between -180 and +180 degrees, ie in this example, it will give 20. This is a problem if the angle was actually 200, and this is what causes the weird behaviour in the video above.

You can see it with this little bit of code, which rotates from 0 to 360 degrees, calculates how much x and y change for each angle, and feeds them into the atan function to see if it gives back the original angle.

function setup()
    for i=0,360,60 do  --rotate by 60 degrees at a time
        --calculate how much x and y change, at this angle
        x=math.cos(math.rad(i))
        x=math.sin(math.rad(i))
        --use atan2 to calculate and print angle
        print(i,math.deg(math.atan2(x,y)))
    end
end

This is what you get. The number on the left is the correct angle, the number on the right is what atan2 produces.

0      0
60    60
120  120
180  180
240 -120
300  -60
360    0

So the problem is that 240 degrees has the same tan value as -120 degrees, and atan2 always gives back an answer between -180 and +180, so it gives -120 instead of the correct answer of 240.

The solution

The solution is this – before calculating the atan2 value, store the previous value for your angle A, (say) with prevA = A.

Then calculate the new angle A using atan2, and check whether it is more than 180 degrees different from prevA. If it is more than 180 degrees

  • less than before, you add 360 degrees
  • greater than before, you subtract 360 degrees

And if you do this to the set of results above, you get the correct answers.

As another example, suppose A = 178 degrees, and it rotates a few more degrees to 182 degrees (we don’t know that yet, all we have is x and y differences).

We set prevA = A, and calculate atan2, which gives us A = -178 degrees.

This is 356 degrees less than prevA, so we add 360 degrees to get A = 182 degrees, the correct figure.

Why it works

The reason it works is that for any positive rotation angle, there is a negative angle that gives exactly the same result. because you can rotate left or right and get to the same place.

So a rotation of +90 degrees is exactly the same as a rotation of -270 degrees, a rotation of -40 degrees is the same as a rotation of +320 degrees, and so on. They give exactly the same answer. And you’ll see that the positive and negative figures are always exactly 360 degrees apart.

So there are two ways to describe any angle, one positive and one negative. Atan2 will always give us the one which is between -180 and +180. So if it gives us a weird answer that is very different from the previous angle, it means atan2 has chosen the wrong one, and we need to flip to the other way of describing our angle, by adding or subtracting 360 degrees.

Remember, this particular problem is caused by using the atan2 function. If you don’t need to use it, hopefully your rotations will work just fine.

Advertisement

From → Graphics

One Comment

Trackbacks & Pingbacks

  1. Index of posts | coolcodea

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: