Getting a transformation matrix from a normal vector

I’m trying to randomly generate coordinate transformations for a fitting routine I’m writing in python. I want to rotate my data (a bunch of $(x,y,z)$ coordinates) about the origin, ideally using a bunch of randomly generated normal vectors ($(a,b,c)$ for a plane given by $ax+by+cz+d=0$). The goal is to shift each plane I’ve defined so that it lies in the {$z=0$} plane.

How do I get the right transformation matrix from my normal vector? I’m pretty sure I need to start by calculating the angle between the randomly generated normal vector and the one that corresponds to the {$z=0$} plane, $(1,1,0)$. But I have no idea what to do from there.

Solutions Collecting From Web of "Getting a transformation matrix from a normal vector"

As per Wouter’s answer, start by translating the plane so that it passes through the origin. Let $\mathbf n={(a,b,c)^T\over\sqrt{a^2+b^2+c^2}}$ be the unit normal to the plane. The vector ${-d\over\sqrt{a^2+b^2+c^2}}\mathbf n$ is then on the plane, so the translation amounts to subtracting this vector.

Now, you need to find a rotation that will align this plane with the $x$-$y$ plane. Following Wouter’s suggestion, we can tilt the normal so that it’s aligned with the $z$-axis. You could try to find an axis and angle of rotation that accomplish this and then apply Rodrigues’ formula, but there’s another way. Recall that the columns of a transformation matrix are the images of the basis vectors. Recalling also that the inverse of a rotation matrix is its transpose, if we find an orthonormal basis that includes $\mathbf n$, the rows of the rotation matrix we seek will be these basis vectors.

The unit normal $\mathbf n$ gives us one basis vector $\mathbf u_3$. Now, we need to find a pair of orthogonal vectors in the plane to complete the basis. An easy way to generate orthogonal vectors is $\mathbb R^3$ is to use the cross product. Assume that $\mathbf n$ is not aligned with the $z$-axis, otherwise we don’t need to rotate the plane. Then $\mathbf n\times(0,0,1)^T$ is a vector in the intersection of our plane and the $x$-$y$ plane that’s orthogonal to $\mathbf n$ which we then normalize to get the basis vector $\mathbf u_1$. (Were we using Rodrigues’ formula, this would be a natural choice for the rotation axis.) For the third basis vector, $\mathbf u_2=\mathbf n\times\mathbf u_1$ is in the plane that we’re rotating and is orthogonal to both of the other basis vectors. (There’s no need to normalize this product since we’re multiplying orthogonal unit vectors.) Note that we take $\mathbf n$ first in this product so that the resulting basis is right-handed. So, the rotation matrix we’re looking for is $$R=\pmatrix{—\mathbf u_1—\\—\mathbf u_2—\\—\mathbf u_3—}=\pmatrix{{n_y\over\sqrt{n_x^2+n_y^2}}&{-n_x\over\sqrt{n_x^2+n_y^2}}&0\\{n_xn_z\over\sqrt{n_x^2+n_y^2}}&{n_yn_z\over\sqrt{n_x^2+n_y^2}}&-\sqrt{n_x^2+n_y^2}\\n_x&n_y&n_z}.$$ You can verify for yourself that $R\mathbf n=(0,0,1)^T$, $R^TR=RR^T=I$ and $\det{R}=1$, so this is in fact a rotation. (You can instead take the first basis vector to be $(0,0,1)^T\times\mathbf n$, which will change a few signs in the rotation matrix.)

Rotations will not in general suffice to map the plane $ax+by+cz+d=0$ onto the plane $z=0$, you will almost always need a translation as well. So translate along the normal until you have a plane of the form $ax+by+cz=0$.

If your normal vector is not already parallel to the $z$ axis, the most natural rotation to make it parallel to the $z$ axis is a rotation around an axis in the $xy$ plane that is perpendicular to the normal. Let the normal be $\vec{v}=(a,b,c)$. We seek an axis $\vec{u}=(u_1,u_2,0)$ such that
$$\vec{v}\cdot\vec{u}=0$$
$$u_1 a+u_2 b=0$$
Once you found this axis (which is in fact the vector $\mathbf{u}_1$ from amd’s answer), you can construct a rotation matrix around this axis $\vec{u}$, and rotate by the angle between $\vec{v}$ and the $z$ axis, which will map your plane onto the $z=0$ plane.