Let $q = a \times b$, let $w = c \times d$.
Then the matrix $M$ whose columns are $a, b, q$, sends the standard basis vectors $e_1 = \begin{bmatrix} 1 \\ 0 \\ 0 \end{bmatrix}$, $e_2 = \begin{bmatrix} 0 \\ 1 \\ 0 \end{bmatrix}$, and $e_3 = \begin{bmatrix} 0 \\ 0 \\ 1 \end{bmatrix}$ to $a, b,$ and $q$ respectively. Since each of these triples is a positively oriented orthonormal frame, the map "multiplication by $M$" must be a rotation.
Similarly, the matrix $K$, whose columns are $c, d,$ and $w$, sends the standard basis vectors to those three vectors.
Therefore
$$
v \mapsto KM^t v
$$
sends $a$ to $c$ (because $M^t$ sends $a$ to $e_1$, and $K$ sends $e_1$ to $c$), $b$ to $d$ and $q$ to $w$ as needed.
And because both $K$ and $M$ are rotations, the product matrix $KM^t$ is also a rotation.
If you actually need to know the axis and angle of the rotation rather than just a matrix for the rotation, let me know and I can expand on this a little bit.
Addition after comments
OP Asks for a way to find the axis and angle from the rotation matrix, so here we go. If $M$ is a rotation matrix that represents rotation by angle $\theta$ about axis $v$, then
$$
\theta = \cos^{-1} \left(\frac{tr(M) -1}{2} \right).
$$
where $tr(M)$ denotes the sum of the diagonal entries. You'll notice that if $tr(M) = 2$ (i.e., $M$ is the identity), then you get $\theta = 0$.
At this point, there are three cases:
If $\theta = 0$, then any unit vector serves as an axis for the rotation.
If $\theta = \pi$, then look at $M + I$, for which at least one column is nonzero. Take such a nonzero column and normalize it (i.e., divide by its length) to get a unit vector $v$ which is the axis of the rotation. (You might want to try this for the diagonal matrix with diagonal entries $-1, -1, 1$
just to see what happens).
For all other $\theta$, compute $Q = \frac{M - M^t}{2 \sin \theta}$; this will be skew-symmetric matrix (i.e., its transpose is its negative). Letting $x = -q_{23}, y = q_{13}, z = -q_{12}$, the vector
$$
v = \begin{bmatrix} x\\y\\z\end{bmatrix}
$$
is the axis of rotation.
Code for this, in pidgin C#, is below. (Note that C# uses 0-based indexing, while my math above uses 1-based indexing). The output vector is called "omega" instead of "v".
void RotationToAxisAngle(
Mat33 m,
out Vector3D omega,
out double theta)
{
// convert a 3x3 rotation matrix m to an axis-angle representation
theta = Math.acos( (m.trace()-1)/2);
if (theta is near zero)
{
omega = Vector3D(1,0,0); // any vector works
return;
}
if (theta is near pi)
{
int col = column with largest entry of m in absolute value;
omega = Vector3D(m[0, col], m[1, col], m[2, col]);
return;
}
else
{
mat 33 s = m - m.transpose();
double x = -s[1,2], y = s[0,2]; z = -s[0,1];
double t = 2 * Math.Sin(theta);
omega = Vector3D(x/t, y/t, z/t);
return;
}
}
The 3D framework I'm using (Apple's SceneKit), likes to specify rotations using an axis and angle, so it would be great if you could give any pointers in how to get to that result.
– stephent Jul 01 '15 at 04:32