# Simplified 3D rotations using Quaternions in 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, qrmat4; /*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;
qr4_10 = qrmat4;
qr4_20 = qrmat4;
qr4_01 = qrmat4;
qr4_11 = qrmat4;
qr4_21 = qrmat4;
} /
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 + y * qrmat4 + z *
``````

qrmat4 + qrmat4; 30 is always 0
yplot = x * qrmat4 + y * qrmat4 + z *
qrmat4 + qrmat4; 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, double qrmat4) {
/~/
/
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 = dbl_1 - dbl_2 * (yy + zz);
qrmat4 = dbl_2 * (xy - zw);
qrmat4 = dbl_2 * (xz + yw);

qrmat4 = dbl_2 * (xy + zw);
qrmat4 = dbl_1 - dbl_2 * (xx + zz);
qrmat4 = dbl_2 * (yz - xw);

qrmat4 = dbl_2 * (xz - yw);
qrmat4 = dbl_2 * (yz + xw);
qrmat4 = dbl_1 - dbl_2 * (xx + yy);

qrmat4 = qrmat4 = qrmat4 =
``````

qrmat4 = qrmat4 = qrmat4 = 0.0;
qrmat4 = dbl_1;

``````/*\$F

Here
``````

OpenGL

``````    |         |
``````

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

*/
return;
}

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

Hi John!
the position that I have to use it.
I’m currently at coding a tunnel (no, I didn’t read any of those tutorials
online!), and I found out, that I have to do some rotation with every
segment of my tunnel so that I am able to “let the tunnel turn around”.
Ok, a closer look:
a segment is circular, and right now every circle is perpendicular to the
Z-Axis.
what I actually need is that the circle is perpendicular to it’s
tangent-vector. I thought of rotating via OpenGL, but in this case, as I
always draw the whole tunnel, this would result in a massive loss of
speed. I get the Tangent-Vector from adding the direction-vectors of this
and the previous circle. now I get the angles for rotation from
where? Calculating the scalar product from (0,0,1)and the tangent? This
just gives me one angle, so it’s not what I need. … While thinking about
this I guess I just found out what I need: the agles I get from scalar
products: X-angle: (1,0,0)*tangent; Y-Angle: (0,1,0)*tangent, Z-Angle:
(0,0,1)*tangent … Am I right?
Well, when I got these angles, can I then start rotating the points of my
circle via quartanions?
Ok, a lot of questions, maybe a bit off-topic, but still any help would be
appreciated … also my demo might go onto the sdl-page as source ditrib.,
but for this I need to get rid of all windows-related code in it (like
using bass.lib for mp3-playback).
Best wishes,
St0fF 64