Introduction

[Update: A slightly more sophisticated Javascript version of my program is available to use here.]

For part of my Pygame 3D graphics program I wanted to work out the matrix required to rotate an object around a point other than the origin. To rotate an object around an arbitrary point $(cx, cy, cz)$ you first translate the object along the vector $(-cx, -cy, -cz)$, so that $(cx, cy, cz)$ is now at the origin; then use the standard rotation matrix to rotate the object around the origin; then translate the object back along the vector $(cx, cy, cz)$.

$ \begin{bmatrix} 1 & 0 & 0 & -cx \\ 0 & 1 & 0 & -cy \\ 0 & 0 & 1 & -cz \\ 1 & 1 & 1 & 1 \end{bmatrix} \begin{bmatrix} cos(\theta) & -sin(\theta) & 0 & 0 \\ sin(\theta) & cos(\theta) & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} 1 & 0 & 0 & cx \\ 0 & 1 & 0 & cy \\ 0 & 0 & 1 & cz \\ 1 & 1 & 1 & 1 \end{bmatrix} = \text{ ?} $

Naturally I wanted to work out what the final matrix was, but after several attempts to do it by hand, I wasn't convinced that I hadn't made a mistake. So I decided to write a program to calculate matrix multiplications for me. It's easy enough to multiply matrices of numbers with numpy, but I wanted to keep the variables as variables.

The program

The first program I made just went through, converting the values to strings then multiplying and adding the relevant bits. This gave a very long, messy answer. The last entry in the first row of the matrix, for example, was:

(1.(c.-cx + -s.-cy + 0.-cz + 0.1) + 0.(s.-cx + c.-cy + 0.-cz + 0.1) + 0.(0.-cx + 0.-cy + 1.-cz + 0.1) + cx.(0.-cx + 0.-cy + 0.-cz + 1.1))

Note that c is short for $cos(\theta)$, s for $sin(\theta)$. Dots indicate multiplication, so 1.0 is 1 times 0, not a decimal.

I added some code to cancel anything multiplied by 0 and make any variable multiplied by 1 equal itself. This simplified the answer significantly:

((c.-cx + -s.-cy) + cx.(1))

Then I changed the code to only add parentheses where necessary:

c.-cx + -s.-cy + cx

Finally I added some code to keep track of minus signs so I could cancel them where possible and otherwise move minus signs to the front, giving a final answer for the whole matrix:

c  -s   0   -c.cx + s.cy + cx
s   c   0   -s.cx - c.cy + cy
0   0   1   -cz + cz
0   0   0   1

As you can see, it's still not perfect: one of the entries is $-cz + cz$, which should cancel to 0. It is also unable to multiply numbers that aren't 1 or 0. Now I would like to make a more complete program that can properly parse expressions, then add and multiply them. I think I will try to make an online Javascript version so anyone can quickly and easily use it [See top of page].