Simulating simultaneous rotation of an object about a fixed origin given limited resources.

Sorry if the title is a bit cryptic. It's the best I could come up with.

First of all, this question is related to another question I posted here, but that question wasn't posed correctly and ended up generating responses that may be helpful for some people who stumble upon the question, but don't address my problem as it stands.

Also, a disclaimer: I am going to be posting some code here. I will be annotating it to try to make it as clear as possible what I am doing.

Okay, so I am using the Processing programming language to move a box around randomly(according to Perlin noise) As the box moves around, I would like it to rotate such that it looks like it is rolling. I am not looking to simulate exact physics here, I am only looking for a visually pleasing solution.

The general rules for rotation are that, if the box is only moving to the right, then it should rotate around the Y axis such that it rotates to the right and if the box is only moving upwards, it should rotate about the $X$-axis such that it looks like it is rolling directly upwards.

In other words, if this is what the box normally looks like: Then, if I say: rotate2D(45,0) I should get: and if I say rotate2D(0,45) I should get: (for clarity, the function declaration for rotate2D looks like rotate2D(horizontal, vertical) )

Processing makes this easy to do with the rotation functions that it provides, which are:

rotateX();
rotateY();
rotatez();

The problem arises when you want to rotate in 2 dimensions simultaneously. You see, in Processing, If I call rotateX() to rotate an object about the $X$-axis, it is actually the coordinate system itself that gets shifted and all of the other axis go along with it, so when I go to do rotateY() after doing a rotateX()I wont get the result I want because the $Y$-axis that I am rotating around has now been skewed. You can see this in the pictures above.

So, If I do:

I get: and if I do:

I get: But what I want is something like: which I drew by calling my function rotate2D()

The problem is that the results that my function produces are a bit counter intuitive. It is not apparent in the above example, but lets say I want to do: rotate2D(90,90);. I would think that would produce a box that looks like It hasn't been rotated at all right? However, it actually produces: This is my current implementation of rotate2D()

The Function:

void rotate2D(float horizontal, float vertical)
{
float[] rotations ={horizontal, vertical};
if(rotations>rotations)
{
float tmp = rotations;
rotations=rotations;
rotations=tmp;
}

float hIncr= (horizontal<0) ? -0.1 : 0.1;
float vIncr= (vertical<0) ? -0.1 : 0.1;
for(float i=0; i<=abs(rotations);i+=0.1)
{
}

}

Function Explanation: What the function is doing is essentially as follows (and this is all you really need to address the question from a mathematical standpoint).

The function slowly performs a bunch of $X$ and $Y$ axis rotations right after each other by a small amount each time(0.1 degrees) until it reaches an upper bound. That upper bound is the smaller of the values that the function was passed. The box will have already been rotated about the proper axis by the difference between the larger and the smaller value before this sequence takes place.

To further clarify, I am looking for a mathematical explanation for why this process is producing counter intuitive results, which will hopefully shed light on a solution.

The ideal end goal here is to find a formula that i can use to simulate rotation about a fixed axis in multiple dimensions when all I can do is rotate 'the world' one axis at a time as described above (which is essentially equivalent to rotating the objects relative axes)

please do not hesitate to ask me to clarify further. Thanks in advance.

EDIT

After reading the comments, I now understand that rotations about 2 axis do not commute and I should not expect the results that I was previously expecting.

What I am calculating and passing to my function is the net rotation in each direction.

So, is it possible to edit my formula so that it produces this net rotation? For example, in the 90/90 example, If I continue the sequence for ~37 extra steps (127 total) I get the result that I intuitively want to get) This would need to work for all combinations of inputs though.

• I don't see why rotate(90,90) should produce a result which doesn't look rotated. It would alternate rotating by small amounts in x and y, so that each totals 90. The result should be equivalent to a rotation around an axis midway between X and Y rotations - but not by 180 degrees. The net rotation is somewhere between 90 degrees. Consider travelling from (0,0) on the plane to (90,90) - even if you do it it small x and y steps, you still have travelled about 127 along the diagonal when done. The net angle may not be be 127 here, since rotations don't add the same way. – greggo Jan 8 '15 at 1:44
• I haven't checked carefully to see if this fully explains the discrepancy you're seeing with rotate2D(90,90), but rotations about distinct (even perpendicular) axes don't commute. Breaking up $90$ degrees into small steps and rotating alternately about the $x$- and $y$-axes for a "total" amount of $90$ degrees about each axis is not the same as rotating $90$ degrees about each axis separately. (Your intuition may be misled by geographic coordinates?) Even $90$ degree rotations about the $x$- and $y$-axes don't commute. – Andrew D. Hwang Jan 8 '15 at 1:46
• So, not sure what you are asking. A general rotation can be expressed as "rotate by angle A about axis v" where v is a unit vector. It's not simple to turn that into x/y/z rotations, but it can be done ... is that what you are looking for? – greggo Jan 8 '15 at 1:47
• Okay then I am going to try to reword my question then, because ultimately what I am looking for is way to simulate the rotation about a fixed coordinate system, but I am looking for a formula that I can use instead of this solution because it is inefficient and is also glitchy. – Luke Jan 8 '15 at 1:49
• Maybe helpful? engr.uvic.ca/~mech410/lectures/4_2_RotateArbi.pdf – greggo Jan 8 '15 at 1:51

Sorry, Luke, I don't think your solution works. You should have a rigorous solution that is founded in the mathematics of rotations. This is most easily done using quaternions--or better yet, their clifford algebra analogues called rotors.

I'll briefly explain clifford algebra rotors and how they can be used to convert sequential rotations into a net rotation.

Clifford algebra

Clifford algebra introduces a product of vectors that is noncommutative but still associative. If you're familiar with dot and cross products, it incorporates properties of both. Given an orthogonal basis $e_1, e_2, e_3$, we have the following:

$$e_i e_j = \begin{cases} +1 & i = j \\ -e_j e_i & i \neq j \end{cases}$$

Again, it's also associative, so $e_1 e_2 e_3 = (e_1 e_2) e_3 = e_1 (e_2 e_3)$ for instance. This creates an 8-dimensional vector space, with the following basis elements: $$1 \\ e_1, e_2, e_3 \\ e_1 e_2, e_2 e_3, e_3e_1 \\e_1 e_2 e_3$$

Scalar multiples of $1$ are scalars. Linear combinations of $e_1, e_2, e_3$ are vectors. Linear combinations of $e_1 e_2, e_2 e_3, e_3 e_1$ are called bivectors, and these are of interest for rotations. Rotations take place in planes (it's only in 3d that we can say they are about an axis instead, equivalently), and bivectors directly describe the planes in which rotations take place.

Rotors and rotations

I'll state the following without proof, though it should be familiar to anyone with a base understanding of quaternions.

Define a rotor as the exponential of a bivector (usually defined through a power series). Let $B$ be some unit bivector. Then the rotor $q = \exp(Bt)$ for some scalar $t$ is

$$q = \exp(Bt) = \cos t+ B \sin t$$

A rotation map $\underline R$ in the plane corresponding to $B$ by the angle $\theta$ takes the form

$$\underline R(a) =e^{-B\theta/2} a e^{B\theta/2}$$

where $a$ is any vector.

(Note: for those with quaternion background, $i = -e_2 e_3$, $j = -e_3 e_1$, and $k = -e_1 e_2$, so there is no sign discrepancy with this definition.)

Application: finding a net rotation

Using rotors simplifies a lot of the mathematics of analyzing rotations. For instance, let's consider the problem you have: your rotation functions rotate the global frame, and themselves use the global frame as the frame of reference for these rotations. This makes sequencing the rotations somewhat nontrivial, but rotors let us find a simpler way of doing things.

Let $e_x, e_y, e_z$ be the original frame. If you want to rotate about the original $e_x$ and then about the original $e_y$, then your rotors would look like this:

$$q_\text{net} = \exp(-e_ze_x \phi/2) \exp(-e_y e_z \theta/2) = q_y q_x$$

We can then multiply this out to find the net rotation plane and the net angle.

$$q_\text{net} = \cos \frac{\phi}{2} \cos \frac{\theta}{2} - e_z e_x \sin \frac{\phi}{2} \cos \frac{\theta}{2} - e_y e_z \cos \frac{\phi}{2} \sin \frac{\theta}{2} + e_x e_y \sin \frac{\theta}{2} \sin \frac{\phi}{2}$$

We can find the net rotation angle $\alpha$ by

$$\cos\frac{\alpha}{2} = \cos \frac{\phi}{2} \cos \frac{\theta}{2}$$

Let's consider the case like you suggested, $\phi = \theta = \pi/2$. Then we should have

$$\cos\frac{\alpha}{2} =\left (\cos\frac{\pi}{4}\right)^2 = \frac{1}{2} \implies \frac{\alpha}{2} = \frac{\pi}{3}$$

or $\alpha = 2\pi/3 = 120^\circ$.

The net rotation plane is $(e_y e_z + e_z e_x - e_x e_y)/\sqrt{3}$, or a rotation about the axis $(e_x + e_y - e_z)/\sqrt{3}$.

Edit: with this in mind, here's what you need to do.

• For each rotation in a sequence of rotations, identify the rotation angle $\theta$ and a the unit plane $\hat B$. For example, if you want to rotate about the $e_x$ direction, then the rotation plane is $e_y e_z$.
• Write the corresponding rotor for each of those rotations as $q = \cos \theta/2 - \hat B \sin \theta/2$.
• Write a function to multiply rotors. Each rotor has only four components and is a linear combination of $1, e_x e_y, e_y e_z, e_z e_x$. Using the rules I outlined in the second section, figure out the multiplication table for these basis elements. (Or cheat, and look up a quaternion multiplication table.)
• Multiply the individual rotors to find the net rotor of the combined rotation.
• Given that rotor, find the angle $\phi$ and the rotation plane $\hat b$ for the net rotation. Again, remember that the rotor can be written as $q = \cos \phi/2 - \hat b \sin \phi/2$. This means you can take the scalar part and use an inverse cosine to find $\phi$. You can take the remaining components and normalize them as a bivector (the same way you would as a vector) to find the unit plane of rotation.
• Awesome! a lot of this math is over my head right now, but (once I understand it) I can probably use it to make a more efficient algorithm, but I do believe my solution works. I just implemented it in my application and it looks great. Were you just speaking of my implementation of the idea (if so, check my updated code in my answer)? – Luke Jan 8 '15 at 17:30
• Regardless thank you, I upvoted, but I am going to wait to see if more people have opinions on my solution vs yours before I pick one to "accept". Although, regardless, yours would technically be more precise as I would have to slow down my algorithm considerably to get past single decimal place precision. – Luke Jan 8 '15 at 17:34
• I was speaking specifically of your answer. For instance, you invoke the Pythagorean theorem to conclude the angle should be $127^\circ$. The Pythagorean theorem isn't involved in this calculation, though, and that is why I concluded the angle of rotation is $120^\circ$ and not $127^\circ$. – Muphrid Jan 8 '15 at 17:40
• hmm one reason why I was confident in my method is that it matched up with what @greggo said in his comment. Will your method indeed result in a net rotation of 90 degrees right and 90 degrees up? – Luke Jan 8 '15 at 17:43
• Yes. I took the rotors for each of those $90^\circ$ rotations, multiplied them to perform those rotations in sequence, and then I just analyzed the net rotor to find its angle and rotation plane. – Muphrid Jan 8 '15 at 17:48

My Solution

To everyone in the comment section, I would like to thank you for your help as you have guided me to a solution!

So, as you stated, my intuition was incorrect and rotations about multiple axes do not commute.

To make it completely clear what I am working with, I want to re-state that the values being passed to my function represent the desired net rotation in the horizontal and vertical directions, respectively.

so, when I tried rotate2D(90,90) I was not getting a 90 degree rotation in each direction, but rather a compromise between the two. In other words, I was trying to use the length of one of the small sides of the triangle as it's hypotenuse!

Since I have the magnitude of each small side when the function is called, I can just use Pythagorean's theorum to determine what the length of the hypotenuse should be. After reading the comments, I believe that this hypotenuse is equivalent to the unit vector of the resulting rotation. (please correct me if I am wrong on that point.) So by using Pythagorean's theorum to determine how long to continue the sequence of 0.1 degree rotations based on the desired net rotations in the horizontal and vertical directions, I can achieve the results that I want!

Here is the new code:

void rotate2D(float horizontal, float vertical)
{
float[] rotations ={horizontal, vertical};
if(rotations>rotations)
{
float tmp = rotations;
rotations=rotations;
rotations=tmp;
}

float c= sqrt(pow(rotations,2)+pow(rotations,2));
float cIncr=0.1;
float hIncr=(horizontal/(c/cIncr));
float vIncr=(vertical/(c/cIncr));
for(float i=0; i<c; i+=cIncr)
{