Rotating and Orbiting with Affine Transformations

Mar 26 · 5 min read

In this article I’ll go over some algorithms for rotating and orbiting objects in a scene using affine transformations. I’ll provide some JavaScript code that shows the algorithms in action, rotating and orbiting squares in a 2D canvas. These algorithms of course translate to 3D space, but I’ve used a canvas for simplicity and because the demos can be viewed in a browser. Note that when rendering in a 2D canvas, the origin is at the top-left corner of the canvas, with the x-axis growing to the right, the y-axis growing down, and the z-axis growing into the screen. It doesn’t make any difference mathematically, but the illustrations provided adhere to this convention.

To follow along you should know basic linear algebra — matrix multiplication, vectors, and rotation and translation matrices — and you should be able to read JavaScript code. I’ve used one third-party library in the example code, glMatrix, which is a vector and matrix library that I like.

Draw Models Centered at the Origin

It’s good practice to create models (the shapes that are drawn on the screen) such that they are centered at the origin. Although not strictly necessary, doing so will simplify transformation operations, especially scale and rotation operations. If, for example, you want to draw a 20x20 square, then draw the square such that the top-left corner is at `(-10, -10)`.

When a rotation operation is applied, that rotation is about the origin. So if the model is drawn such that it’s centered at the origin, the object will appear to spin about its center.

I’m not going to get into the details of rendering objects on a canvas because it’s not what this article is about, but one way to draw a rectangle on a canvas is with the CanvasRenderingContext2D#fillRect method. Drawing a rectangle such that it’s centered at the origin can be done like so.

`ctx.fillRect(  -rect.width  / 2, // Left (x).  -rect.height / 2, // Top (y).  rect.width,       // Width.  rect.height);     // Height`

Rotating at the Origin

If you have a model that’s center at the origin, then simply apply a rotation matrix to the object and it will spin about its center. In the plunk below, you’ll see a 20x20 rectangle spinning at the origin.

Here’s a basic `Rectangle` class that rotates at a rate of PI per second. The `update` method is called before each render, and that method updates the rotation based on the elapsed time since the last render.

Rotating at a Point

Building on the previous example, to make the object rotate at a certain point `P` in the scene, another matrix is needed. The object needs to be rotated then translated, in that order. (Keep in mind that matrix math is not commutative, and matrix multiplication applies from right to left.)

`transformation = translate(P) * rotate(θ)`

Here is an example that shows a 20x20 rectangle rotating at point `P=(40, 40)`.

And here is the updated `Rectangle` class. The `translation` matrix is created at construction time with the point `(40, 40)` hard-coded to keep the example easy. The `transformation` matrix, computed in the `getTransformation` method, is the product of the `translation` and `rotation` matrices, in that order (again, that means that the rotation is applied first).

At the risk of being a bit repetitive, matrix multiplication is not commutative. Applying an orbit about the origin is almost the same as rotating at a point, but the matrix multiplication is reversed: The object is translated then rotated.

`transformation = rotate(θ) * translate(P)`

Here, the orbit will be centered about the origin and will pass through point `P`. The radius of the orbit `r` is thus:

Below is an example showing a 20x20 square orbiting about the origin and passing through point `P=(40,40)`. The radius of orbit `r` is therefore about 57.

The `Rectangle` class is the same as shown in the last example, but with the matrix multiplication reversed (lines 33 and 34 are swapped).

With another translation matrix, the orbit can be changed such that it’s centered at a point `P`. Let’s say we want an object to orbit about point `P=(100,100)` with a radius of orbit `r=40`. First translate the object a distance of `r` from the origin. `(r, 0)` will do fine. Second apply the rotation. Third translate the object to point `P`.

`transformation = translate(P) * rotate(θ) * translate(r, 0)`

Here it is in action.

And here is the new `Rectangle` class, now fitted with two translations and one rotation.

Rotating and Orbiting

Just for fun, with an extra rotation matrix the rectangle can be updated to both rotate and orbit. Rotate the object first, about the origin, by angle `θ1`. Then apply the orbit algorithm from the last example, rotating by angle `θ2`.

`transformation =  translate(P) * rotate(θ2) * translate(r, 0) * rotate(θ1)`

Another example follows, demonstrating this algorithm.

Here’s the code, now with two translations and two rotations. Note that both rotation matrices are updated in the `update` method before each render.

With that, you should have everything you need to create a cool solar system, a model of an atom, or something equally geeky.

Get in Touch

If you have any questions about the article, drop me a line in the comments section. Please subscribe or clap a few times if you enjoyed the article and found it helpful. The feedback helps me know where to focus my writing. Lastly, contact me and my team if you need a developer. We’re a small software company and we would love to help you out.

Written by

More From Medium

Also tagged Programming

Apr 9 · 7 min read

New Hackathon for the New Normal

Apr 9 · 2 min read

5

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just \$5/month. Upgrade