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

additions.

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

See http://www.geocities.com/capgadget

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

static float qr4_00, qr4_10, qr4_20,

qr4_01, qr4_11, qr4_21; /

unless you have a football field sized

100 DPI monitor, but I

kept double in the quaternion derivation

function

*/*

float xplot, yplot; /Rotated point */

float xplot, yplot; /

/* 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) */

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];

} /

```
/*$ 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) ||

xplot = x * qr4_00 + y * qr4_10 + z * qr4_20;

yplot = x * qr4_01 + y * qr4_11 + z * qr4_21;

} /

(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

Derivedfrom

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

and

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

*/

/*$F

This source is free software; you can redistribute it

and/or

modify it under the terms of the GNU Library General

Public

License as published by the Free Software Foundation;

either

version 2 of the License, or (at your option) any

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

Copyright © 2002 John B. Battles

Any feedback is very welcome. For any question,

comments,

see http://www.geocities.com/capgadget.html or email

*/

#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

double ex, ey, ez, x, y, z, w; /

euler angles

*/*

double cr, cp, cy, sr, sp, sy, cpcy, spsy; /temp

double cr, cp, cy, sr, sp, sy, cpcy, spsy; /

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 };

/~

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);
/*
* ex = DEGTORAD(x) / 2.0; // convert to rads and
```

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