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
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.
-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
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
rotation matrices, in that order (again, that means that the rotation is applied first).
Orbiting about the Origin
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.
Rectangle class is the same as shown in the last example, but with the matrix multiplication reversed (lines 33 and 34 are swapped).
Orbiting about a Point
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
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
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.