We have a gazillion spatial coordinates (x, y and z) representing atoms in 3d space, and I’m constructing a function that will translate these points to a new coordinate system. Shifting the coordinates to an arbitrary origin is simple, but I can’t wrap my head around the next step: 3d point rotation calculations. In other words, I’m trying to translate the points from (x, y, z) to (x’, y’, z’), where x’, y’ and z’ are in terms of i’, j’ and k’, the new axis vectors I’m making with the help of the euclid python module.
I think all I need is a euclid quaternion to do this, i.e.
>>> q * Vector3(x, y, z)
Vector3(x', y', z')
but to make THAT i believe I need a rotation axis vector and an angle of rotation. But I have no idea how to calculate these from i’, j’ and k’. This seems like a simple procedure to code from scratch, but I suspect something like this requires linear algebra to figure out on my own. Many thanks for a nudge in the right direction.
Using quaternions to represent rotation isn’t difficult from an algebraic point of view. Personally, I find it hard to reason visually about quaternions, but the formulas involved in using them for rotations are not overly complicated. I’ll provide a basic set of reference functions here.1 (See also this lovely answer by hosolmaz, in which he packages these together to create a handy Quaternion class.)
You can think of a quaternion (for our purposes) as a scalar plus a 3-d vector — abstractly,
w + xi + yj + zk, here represented by an ordinary tuple(w, x, y, z). The space of 3-d rotations is represented in full by a sub-space of the quaternions, the space of unit quaternions, so you want to make sure that your quaternions are normalized. You can do so in just the way you would normalize any 4-vector (i.e. magnitude should be close to 1; if it isn’t, scale down the values by the magnitude):Please note that for simplicity, the following functions assume that quaternion values are already normalized. In practice, you’ll need to renormalize them from time to time, but the best way to deal with that will depend on the problem domain. These functions provide just the very basics, for reference purposes only.
Every rotation is represented by a unit quaternion, and concatenations of rotations correspond to multiplications of unit quaternions. The formula2 for this is as follows:
To rotate a vector by a quaternion, you need the quaternion’s conjugate too:
Quaternion-vector multiplication is then a matter of converting your vector into a quaternion (by setting
w = 0and leavingx,y, andzthe same) and then multiplyingq * v * q_conjugate(q):Finally, you need to know how to convert from axis-angle rotations to quaternions and back. This is also surprisingly straightforward. It makes sense to "sanitize" input and output here by calling
normalize.And back:
Here’s a quick usage example. A sequence of 90-degree rotations about the x, y, and z axes will return a vector on the y axis to its original position. This code performs those rotations:
Keep in mind that this sequence of rotations won’t return all vectors to the same position; for example, for a vector on the x axis, it will correspond to a 90 degree rotation about the y axis. (Think of the right-hand-rule here; a positive rotation about the y axis pushes a vector on the x axis into the negative z region.)
As always, please let me know if you find any problems here.
1. These are adapted from an OpenGL tutorial archived here.
2. The quaternion multiplication formula looks like a horrible rat’s nest at first, but the derivation is easy, albeit tedious. Working with pencil and paper, you can represent the two quaternions like so:
w + xi + yj + zk. Then note thatii = jj = kk = -1; thatij = k,jk = i,ki = j; and thatji = -k,kj = -i,ik = -j. Finally, multiply the two quaternions, distributing out the terms and rearranging them based on the results of each of the 16 multiplications. This helps to illustrate why you can use quaternions to represent rotation; the last six identities follow the right-hand rule, creating bijections between rotations fromitojand rotations aroundk, and so on.If you do this, you’ll see that the identity
ii = jj = kk = -1explains the last three terms in thewformula; thatjk = iexplains the third term in thexformula; and thatkj = -iexplains the fourth term in thexformula. Theyandzformulas work the same way. The remaining terms are all examples of ordinary scalar multiplication.