# Simplified 3D rotations using Quaternionsin C

This is a very simple yet efficient adaptation of
quaternions to combined x/y/z rotations. Quaternions
avoid the gimble lock problem.
to rotate a point only requires 3 multiplies and 4

It took me a couple of days to digest:

http://www.gamedev.net/reference/articles/article1095.asp

and

http://www.cs.ualberta.ca/~andreas/math/matrfaq_latest.html

for where I use this.

This is the result. I am throwing my Euler rotation
matrix code into the bit bucket=========================================================

/* Given an array of xyz points I do translation and
scaling elsewhere*/

typedef struct {
float x, y, z;
} points;

static double quat4[4], qrmat4[4][4]; /*quat4 is
the Quaternion qrmat4 is the 4x4 Quaternion rotation
matrix /
float x, y, z; /
w not currently used /
static float qr4_00, qr4_10, qr4_20,
qr4_01, qr4_11, qr4_21; /
don’t really need double
unless you have a football field sized
100 DPI monitor, but I
kept double in the quaternion derivation
function /
float xplot, yplot; /
Rotated point */

/* and angles (Note that angles are in 1/10th of a
degree) */

int xrotation, yrotation, zrotation;

``````if(rotation_changed) { /* Only need to recalculate if
``````

the angles have changed /
euler_to_quat4(xrotation, yrotation, zrotation,
quat4, qrmat4); /
angles are in 1/10th degree /
qr4_00 = qrmat4[0][0];
qr4_10 = qrmat4[1][0];
qr4_20 = qrmat4[2][0];
qr4_01 = qrmat4[0][1];
qr4_11 = qrmat4[1][1];
qr4_21 = qrmat4[2][1];
} /
if(rotation_changed) */

``````/*\$ LOOP THROUGH POINTS */

for(i = 0; i < NUMBER_OR_POINTS; i++) {	/* Need to
``````

make some of these inline */
xplot = particle_frame[i].x;
yplot = particle_frame[i].y;

``````	if((xrotation != 0) || (yrotation != 0) ||
``````

(zrotation != 0)) { /* Do quaternion rotation */

``````		x = particle_frame[i].x;
y = particle_frame[i].y;
z = particle_frame[i].z;

/*\$F Original
xplot = x * qrmat4[0][0] + y * qrmat4[1][0] + z *
``````

qrmat4[2][0] + qrmat4[3][0]; 30 is always 0
yplot = x * qrmat4[0][1] + y * qrmat4[1][1] + z *
qrmat4[2][1] + qrmat4[3][1]; 31 is always 0
/
/
\$F Hand opimized version of the above. /
xplot = x * qr4_00 + y * qr4_10 + z * qr4_20;
yplot = x * qr4_01 + y * qr4_11 + z * qr4_21;
} /
if((xrotation != 0) || (yrotation != 0) ||
(zrotation != 0)) /
} /
for(i = 0; i < NUMBER_OR_POINTS; i++) */

=========================================================================================

/*\$T bg_euler_to_quat4.c GC 1.129 02/27/02 17:38:08 */

/*\$6

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*/

/*\$F

Use quaternions to do multi axis rotations. Avoids
gimbal lock

/*\$F
This source is free software; you can redistribute it
and/or
modify it under the terms of the GNU Library General
Public
either
later
version.

This source is distributed in the hope that it will
be useful,
but WITHOUT ANY WARRANTY; without even the implied
warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

See the GNU Library General Public License for more
details.
You should have received a copy of the GNU Library
General
Public License along with this library; if not, write
to the
Free Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA
02111-1307 USA

Any feedback is very welcome. For any question,

@John_Battles

*/

#include <math.h>

/*

=======================================================================================================================

=======================================================================================================================
*/

/* Parts of this can be gutted out for the special
case above */

void euler_to_quat4(const int ax, const int ay, const
int az, double quat4[4], double qrmat4[4][4]) {
/~/
/
angles are in 1/10th degree /
double ex, ey, ez, x, y, z, w; /
temp half
euler angles /
double cr, cp, cy, sr, sp, sy, cpcy, spsy; /
temp
vars in roll,pitch yaw /
double norm;
double xx, xy, xz, xw, yy, yz, yw, zz, zw;
static double dbl_1 = 1.0;
static double dbl_2 = 2.0;
enum { X = 0, Y = 1, Z = 2, W = 3 };
/
~
/

``````ex = (double) (M_PI * (double) ax / (double) 1800.0);
ey = (double) (M_PI * (double) ay / (double) 1800.0);
ez = (double) (M_PI * (double) az / (double) 1800.0);

/*
``````

half them ey = DEGTORAD(y) /
* 2.0; ez = DEGTORAD(z) / 2.0;
*/
cr = cos(ex);
cp = cos(ey);
cy = cos(ez);

``````sr = sin(ex);
sp = sin(ey);
sy = sin(ez);

cpcy = cp * cy;
spsy = sp * sy;

x = sr * cpcy - cr * spsy;
y = cr * sp * cy + sr * cp * sy;
z = cr * cp * sy - sr * sp * cy;
w = cr * cpcy + sr * spsy;

/* Normalize(); Should always == 1 */
norm = sqrt(x * x + y * y + z * z + w * w);

quat4[X] = x / norm;
quat4[Y] = y / norm;
quat4[Z] = z / norm;
quat4[W] = w / norm;
``````

/* Create the Quaternion 4x4 Rotation Matrix */

``````xx = quat4[X] * quat4[X];
xy = quat4[X] * quat4[Y];
xz = quat4[X] * quat4[Z];
xw = quat4[X] * quat4[W];

yy = quat4[Y] * quat4[Y];
yz = quat4[Y] * quat4[Z];
yw = quat4[Y] * quat4[W];

zz = quat4[Z] * quat4[Z];
zw = quat4[Z] * quat4[W];

qrmat4[0][0] = dbl_1 - dbl_2 * (yy + zz);
qrmat4[1][0] = dbl_2 * (xy - zw);
qrmat4[2][0] = dbl_2 * (xz + yw);

qrmat4[0][1] = dbl_2 * (xy + zw);
qrmat4[1][1] = dbl_1 - dbl_2 * (xx + zz);
qrmat4[2][1] = dbl_2 * (yz - xw);

qrmat4[0][2] = dbl_2 * (xz - yw);
qrmat4[1][2] = dbl_2 * (yz + xw);
qrmat4[2][2] = dbl_1 - dbl_2 * (xx + yy);

qrmat4[3][0] = qrmat4[3][1] = qrmat4[3][2] =
``````

qrmat4[0][3] = qrmat4[1][3] = qrmat4[2][3] = 0.0;
qrmat4[3][3] = dbl_1;

``````/*\$F

Here
``````

OpenGL

``````    | [0][0]  [0][1]  [0][2]  [0][3]  |
``````

| 0 4 8 12 |
| |
| |
| [1][0] [1][1] [1][2] [1][3] |
| 1 5 9 13 |
M = | | M =
| |
| [2][0] [2][1] [2][2] [2][3] |
| 2 6 10 14 |
| |
| |
| [3][0] [3][1] [3][2] [3][3] |
| 3 7 11 15 |

*/
return;
}

Do You Yahoo!?
Yahoo! Greetings - Send FREE e-cards for every occasion!
http://greetings.yahoo.com