Rotation in 4 Spatial Dimensions.
Paul "V'lion" Nathan.
So you have decided to make a 4D engine, have you ?
Good for you ! I`m going to discuss 4D rotation, extrapolating the
4D equations from the 3D equations, as well as using 2D rotation for various
purposes. I`m not going to go into the actual mathematical proof for rotations;
thats well documented on the internet in 2D and 3D contexts and it does not change
for 4D.
This article uses Euler angle rotations.
These are the one derived in the basic trig books.
They are the simplest to conceptualize, so I use them.
In the code examples, I use C++.
Even if you work in another language, the C++-only contructs I use can be ignored for
the most part, and if they can't, I indicate what they do.
In actual code, you would need to use radians or convert to radians for the sin/cos funcs.
Please remember that.
Lets start by rotations in the plane-
Call it the XY plane, in 2-space.
math equations for 2D are:
x' = y * sin(theta) + x * cos(theta)
y' = y * cos(theta) - y * sin(theta)
code.
void c2DPoint::2DRotate(float theta)
{
float x0, y0;
x0 = y * sin(theta) + x * cos(theta)
y0 = y * cos(theta) - x * sin(theta)
//This just assigns the results to itself, assuming c2DPoint has a x and a y.
*this.x = x0;
*this.y = y0;
}
Now, you are wondering, why just not use x and y, instead of x0 and y0 ?
Because if you did, you would screw up the equation.
It needs the original, unaltered x and y to operate with.
So it requires 1 angle and 1 equation set to do a 2-space rotation.
Lets go into the 3-space rotation.
The math looks hairy, but don`t let it confuse you !
Just remember that y' is simply a different variable than y.
x' = y * sin(theta) + x * cos(theta)
y' = y * cos(theta) - x * sin(theta)
z' = z
x'' = x' * sin(phi) + x' * cos(phi)
y'' = y'
z'' = z' * cos(phi) - z' * sin(phi)
x''' = x''
y''' = y' * sin(chi) + y' * cos(chi)
z''' = z' * cos(chi) - z' * sin(chi)
Heres the code;
void c3DPoint::Rotate(float theta = 0, float phi = 0, float chi = 0)
{
c3DPoint temp0, temp1, temp2, temp3;
temp0 = temp1 = temp2 = *this;
//XY plane
temp1.x = temp0.y * sin(theta) + temp0.x * cos(theta);
temp1.y = temp0.y * cos(theta) - temp0.x * sin(theta);
temp1.z = temp0.z;
//XZ plane
temp2.x = temp1.z * sin(phi) + temp1.x * cos(phi);
temp2.y = temp1.y;
temp2.z = temp1.z * cos(phi) - temp1.x * sin(phi);
//YZ
temp3.x = temp2.x;
temp3.y = temp2.z * sin(chi) + temp2.y * cos(chi);
temp3.z = temp2.z * cos(chi) - temp2.y * sin(chi);
*this = temp3;
}
We now have 3 angles, and 3 equation sets.
I won`t do the math for 4 dimensions, but it works _exactly_ as does the 2D math
and the 3D math.
What that means for you is you have to do- heres the funky part- 6 sets of equations, and 6 angles.
That really shocked me when I found it out- I just didn`t believe it.
But, heres how it works.
In 2D, the plane is XY. All angles are expressed from a initial and a terminal side in the plane.
In 3D, we have 1 more axis. But- 2 more planes: YZ and XZ.
So in 4d, we have 4 axes, and 3 more planes.
XQ, YQ, and ZQ.
Add all the planes up and you get 6 planes, with 4 axes.
If you have 1 rotation anlge a plane, that means- 6 angles.
Here is the relevant code from my own engine, bugle4d:
//Works similar to the OGL function, but operates against the point that calls it.
//6 angles. XY plane, XZ plane, YZ plane, XQ plane, YQ plane, ZQ plane.
void c4Point::Rotate(float theta = 0, float phi = 0, float chi = 0, float rho = 0, float mu = 0, float lambda = 0)
{
//I know I could use like only 3 of these, but having all of these makes it more clear
c4Point temp0, temp1, temp2, temp3, temp4, temp5, temp6;
temp0 = *this;
theta = Deg2Rad(theta);
phi = Deg2Rad(phi);
chi = Deg2Rad(chi);
rho = Deg2Rad(rho);
mu = Deg2Rad(mu);
lambda = Deg2Rad(lambda);
{
//XY plane
temp1.x = (temp0.y * sin(theta)) + (temp0.x * cos(theta));
temp1.y = (temp0.y * cos(theta)) - (temp0.x * sin(theta));
temp1.z = temp0.z;
temp1.q = temp0.q;
//XZ plane
temp2.x = (temp1.z * sin(phi)) + (temp1.x * cos(phi));
temp2.y = temp1.y;
temp2.z = (temp1.z * cos(phi)) - (temp1.x * sin(phi));
temp2.q = temp1.q;
//YZ
temp3.x = temp2.x;
temp3.y = (temp2.z * sin(chi)) + (temp2.y * cos(chi));
temp3.z = (temp2.z * cos(chi)) - (temp2.y * sin(chi));
temp3.q = temp2.q;
//XQ
temp4.x = (temp3.q * sin(rho)) + (temp3.x * cos(rho));
temp4.y = temp3.y;
temp4.z = temp3.z;
temp4.q = (temp3.q * cos(rho)) - (temp3.x * sin(rho));
//YQ
temp5.x = temp4.x;
temp5.y = (temp4.q * sin(mu)) + (temp4.y * sin(mu));
temp5.z = temp4.z;
temp5.q = (temp4.q * cos(mu)) - (temp4.y * cos(mu));
//ZQ
temp6.x = temp5.x;
temp6.y = temp5.y;
temp6.z = (temp5.q * sin(lambda)) + (temp5.z * sin(lambda));
temp6.q = (temp5.q * cos(lambda)) - (temp5.z * cos(lambda));
}
//After the cumulative effect for the rotations, we assign it to *this.
*this = temp6;
}
I hope this makes 4D rotation a little easier for you.
-V'lion
For a full software implementation with matrices,
look at:
http://research.microsoft.com/~hollasch/thesis/
Steven Richard Hollasch`s 4D engine.
It is research and a 4D engine. It is also the only other one in a "real" language that I`ve seen.
Its written in C for a old API, but his reasearch still looks sound. :-D
Note on notation:
For the 4th dimension, I used Q, because when you have homogneous coords, you use W as the extra coord.
So to ease confusion, Q.
Also quaternions use W for a element.
(C)2002 Paul "V'lion" Nathan.
Please do not cut-and-paste my code.
If you write it yourself, you will understand it much better.
Please do not copy this article without notifying me; if you alter it and give it to others,
note your changes.
Questions/Comments/Bugs ???
pdn@rmci.net