3
$\begingroup$

I have two orthogonal vectors $a$, $b$, which lie on a unit sphere (i.e. unit vectors).

I want to apply one or more rotations to the sphere such that $a$ is transformed to $c$, and $b$ is transformed to $d$, where $c$ and $d$ are two other orthogonal unit vectors.

It feels a very similar problem to this question:, but I'm not quite seeing how to obtain a rotation matrix for the sphere from the answer given there (which I'm sure is due to my limited mathematical abilities!).

$\endgroup$
2
$\begingroup$

Of course, if you can do it with two or more rotations, you can do it with one: the composition of rotations is a rotation.

Conceptually the strategy should be clear: $a$ and $c$ lie in a plane, and you can find a rotation $R_1$ that turns that plane carrying $a$ onto $c$. After that, $R_1(b)$ and $d$ lie in the plane perpendicular to $R_1(a)=c$, and you just need to rotate around $c$ through some angle with $R_2$ to get $b$ to lie on $d$. Then the rotation $R_2R_1$ carries the first orthonormal pair onto the second pair.

It would be great exercise for you to work the details of this strategy out with matrices. Just start with a rotation around $a\times c$ and follow up with a rotation around $c$.

I'm not sure if you're familiar with doing such things in terms of quaternions, but that would also be a great exercise.

$\endgroup$
  • 1
    $\begingroup$ For ways of generating rotation matrices, see Rodrigues' rotation formula en.wikipedia.org/wiki/Rodrigues'_rotation_formula $\endgroup$ – Alex S Jun 29 '15 at 17:21
  • $\begingroup$ Thanks for the answer - I had been attempting to achieve what I wanted using two rotations (not the ones you gave) and by decomposing my 3D model into separate parts to which distinct rotations are applied, but I was having some trouble with that approach. I tried implementing the approach you describe this evening, but so far without the expected results. I'll look again with fresh eyes tomorrow to see where I might be going wrong. BTW, I was v impressed with the speed and quality of response here on math.sx.com - seems like a great community! $\endgroup$ – StephenT Jul 1 '15 at 4:35
  • $\begingroup$ OK - I have this approach working. After fixing a couple of errors in my late evening coding this morning, the only change I had to make was to perform the matrix multiplication in the order R1R2 rather than R2R1. $\endgroup$ – StephenT Jul 1 '15 at 17:20
  • 1
    $\begingroup$ @StephenT Good job :) It's nice when we can give general ideas and still let you have the benefit of the experience working the problem. $\endgroup$ – rschwieb Jul 1 '15 at 18:02
  • $\begingroup$ @rschwieb appreciate the pointers! One question: is the fact that I had to reverse the order of the matrix multiplication a question of the function I'm using (developer.apple.com/library/mac/documentation/SceneKit/…), or is it that in fact the order should in fact be R1R2 rather R2R1 as given above? I can't quite tell. $\endgroup$ – StephenT Jul 2 '15 at 17:23
4
$\begingroup$

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:

  1. If $\theta = 0$, then any unit vector serves as an axis for the rotation.

  2. 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).

  3. 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_{22}$, 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[1,1];
        double t = 2 * Math.Sin(theta);
        omega = Vector3D(x/t, y/t, z/t);
        return;
    }
}
$\endgroup$
  • $\begingroup$ Hi John - many thanks for the great answer. I've spent the past couple of hours trying to implement both your approach and rschwieb's answer below, so far without success (likely due to errors on my part). 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. $\endgroup$ – StephenT Jul 1 '15 at 4:32
  • 1
    $\begingroup$ Details and code added. (Code is direct from "Computer Graphics: Principles and Practice, 3rd ed.", of which I'm the lead author.) $\endgroup$ – John Hughes Jul 1 '15 at 5:27
  • $\begingroup$ Thanks John - sounds like I have some reading to do! $\endgroup$ – StephenT Jul 1 '15 at 17:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.