2D Rotation and Why it Works

Hi! I hope you've all recovered from Hugi #14 and are ready for some math.

This article is intended for beginners who want to learn the formulae behind 2D rotation, as it is used for spinning logos or sprites. But I'm also writing this article because no tutorial I've ever seen explains why these formulae work. To remedy the situation, I'll give solid mathematical proof.

One note: I strongly recommend the use of a pencil and paper to follow this article. The diagrams are worth jotting down as you'll scroll them off the screen before long.

The task of rotating any object can be reduced to the rotation of points. [If you're working in 2D, you can break down your sprite into pixels, i.e. points. In 3D, the points could be the vertices of your object - note though that the formulae shown here will only hold for rotation in one plane. Surely if you're into 3D you knew that already.]

Now consider how to deal with one point - let's call it P, at the co-ordinates (x,y). Its rotated equivalent shall be known as Q, at (u,v). Both points are separated from the origin by the same distance, r. Using simple trig we now express the co-ordinates of each point in terms of r and the angles.

For P(x,y):

```           x
cos(a) = ---                 so x = r * cos(a)        (1)
r

y
sin(a) = ---                 so y = r * sin(a)        (2)
r```

For Q(u,v):

```               u
cos(b + a) = ---             so u = r * cos(b + a)    (3)
r

v
sin(b + a) = ---             so v = r * sin(b + a)    (4)
r```

Using the x-u and y-v pairs as simultaneous equations, we eliminate r:

```             u     cos(b + a)
(3) / (1)  --- = ------------
x       cos(a)

cos(b + a)
hence  u  = x * ------------
cos(a)

v     sin(b + a)
(4) / (2)  --- = ------------
y       sin(a)

sin(b + a)
hence  v  = y * ------------
sin(a)```

These formulae will work fine! However, think about the variables in this equation:

```                       cos(b + a)
u  = x * ------------
cos(a)```

u is the unknown.

On the right hand side, we know x and b. We also indirectly know a, because we can determine it from x and y:

```                         y
a = arctan ---
x```

Unfortunately, this calculation is a pain in terms of programming. It requires a division and a look-up table, thus consuming both speed and space. Clearly this is undesirable.

The solution is to expand the trig terms containing (b + a). [This is the point where most tutorials stop and jump straight to the solution.]

Terms such as these can be expanded to trig terms containing just b or a. These expansions are called compound angle identities.

Consider the following diagram: Just follow me through.

We start with the rectangular triangle ACD, containing the angle a. On top of it, we pile the second rectangular triangle ADF, containing the angle b. Immediately you can see that b and a lie adjacent to each other, which will be very handy. We also draw in the line BF, and the line DE.

Starting from square one, we can now express the sine of (b + a):

```                     opposite       BF
sin(b + a) = ------------- = ----
hypothenuse     AF```

The triangle ABF is used because it is the only rectangular triangle containing (b + a).

The aim is to express BF/AF in terms of sides belonging to the triangles containing b and a on their own (i.e. ADF and ACD).

```              BF
sin(b + a) = ----
AF

BE + EF
= ---------                     First, split BF into its two
AF                         constituents BE and EF.

BE     EF
= ---- + ----
AF     AF

CD     EF                    From the diagram, BCDE is a
= ---- + ----                   rectangle. Hence opposite sides
AF     AF                    are of equal length, BE = CD.

CD     AD       EF     DF    This is the clever bit. We expand
= ---- * ----  +  ---- * ----   each fraction by a term that
AF     AD       AF     DF    occurs in the triangles containing
b and a on their own.

CD     AD       EF     DF
= ---- * ----  +  ---- * ----   Some equivalent swapping. We're
AD     AF       DF     AF    nearly there!

= sin(b) * cos(a) + cos(b) * sin(a)```

The last bit uses just simple trig:

```        opposite
------------- = sine
hypothenuse

adjacent
------------- = cosine
hypothenuse```

I suggest you look at the diagrams and confirm it for yourself. Seeing why EF/DF equals cos(b) may not be entirely obvious. I'll leave this one to you - if you can't figure it out, let me know.

The compound angle identity for cos(b + a) is very similar:

```                    AB
cos(b + a) = ----
AF

AC - BC
= ---------
AF

AC     BC
= ---- - ----
AF     AF

AC     AD       DE     DF
= ---- * ----  -  ---- * ----
AF     AD       AF     DF

AC     AD       DE     DF
= ---- * ----  -  ---- * ----
AD     AF       DF     AF

= cos(b) * cos(a) - sin(b) * sin(a)```

The time has come to incorporate the compound angle identities into our equations. We stopped at:

```                       cos(b + a)
u  = x * ------------
cos(a)

sin(b + a)
v  = y * ------------
sin(a)```

Let's kill 'em one by one, shall we?

```               cos(b + a)
u  = x * ------------
cos(a)

cos(b) * cos(a) - sin(b) * sin(a)
u  = x * -----------------------------------
cos(a)

sin(a)
u  = x * ( cos(b) - sin(b) * -------- )
cos(a)

u  = x * ( cos(b) - sin(b) * tan(a) )

y
u  = x * ( cos(b) - sin(b) * --- )
x

u  = x * cos(b) - y * sin(b)```

And voilŕ, we've done it! This equation no longer contains a. And the second one:

```               sin(b + a)
v  = y * ------------
sin(a)

sin(b) * cos(a) + cos(b) * sin(a)
v  = y * -----------------------------------
sin(a)

v  = y * ( sin(b) * cot(a) + cos(b) )```

"cot" is not a spelling mistake but is the reciprocal of the tangent function.

```                      1        cos(a)     x
cot(a) = -------- = -------- = ---
tan(a)     sin(a)     y

x
v  = y * ( sin(b) * ---  + cos(b) )
y

v  = x * sin(b) + y * cos(b)```

In summary our equations are:

```     u  = x * cos(b) - y * sin(b)
v  = x * sin(b) + y * cos(b)```

Phew - finished! Well done to everyone who followed this stuff; if not, try again, or simply use the equations! If you have any questions, please email me at thunderchopper@hotmail.com.

Have fun!