To main page | 3dengine.org

Quaternions (C++ & Python)


Quats are mostly used in Heading, pitch and roll angles.

C++

Reference implementation
#include <math>

class Quat
{
public:
    Quat(): w(1),x(0),y(0),z(0) {};
    Quat(float x1, float y1, float z1, float degrees)
    {
        float angle = float((degrees / 180.0f) * 3.1415926);
        float result = (float)sin( angle / 2.0f );
        w = (float)cos( angle / 2.0f );
        x = float(x1 * result);
        y = float(y1 * result);
        z = float(z1 * result);
    };
    void gl_matrix(double *m)
    {
        if(!m) return;
        m[0] = 1.0f - 2.0f * ( y * y + z * z ); 
        m[1] = 2.0f * (x * y + z * w);
        m[2] = 2.0f * (x * z - y * w);
        m[3] = 0.0f;  
        m[ 4] = 2.0f * ( x * y - z * w );  
        m[ 5] = 1.0f - 2.0f * ( x * x + z * z ); 
        m[ 6] = 2.0f * (z * y + x * w );  
        m[ 7] = 0.0f;  
        m[ 8] = 2.0f * ( x * z + y * w );
        m[ 9] = 2.0f * ( y * z - x * w );
        m[10] = 1.0f - 2.0f * ( x * x + y * y );  
        m[11] = 0.0f;  
        m[12] = 0;  
        m[13] = 0;  
        m[14] = 0;  
        m[15] = 1.0f;
    };
    Quat operator* (const Quat &b) {
        Quat r;
        r.w = w*b.w - x*b.x - y*b.y - z*b.z;
        r.x = w*b.x + x*b.w + y*b.z - z*b.y;
        r.y = w*b.y + y*b.w + z*b.x - x*b.z;
        r.z = w*b.z + z*b.w + x*b.y - y*b.x;
        return(r);
    };
private:
    float w,x,y,z;
};
Example usage:
// the order of multiplication is important!
Quat Q1 = Quat(0,0,1, roll) * Quat(1,0,0, pitch) * Quat(0,1,0, heading);
double matrix_for_openGL[16];
Q1.gl_matrix(&matrix_for_openGL);
Now matrix_for_openGL has modelview matrix for roll, pitch, heading angles.

Python

import math
class Quat:
    """
        Quaternion Class
        >>> roll = 30
        >>> pitch = 45
        >>> heading = 30
        >>> Q1 = Quat(0,0,1, roll) * Quat(1,0,0, pitch) * \
               Quat(0,1,0, heading)
        >>> Q1.gl_matrix()
        [0.57322332027622536, 0.73919890801437749, \
        -0.3535533898605015, 0.0, -0.3535533898605015, \
        0.61237244705783134, 0.70710677171312086, 0.0, \
        0.73919890801437749, -0.28033009198934633, \
        0.61237244705783134, 0.0, 0, 0, 0, 1.0]
    """
    def __init__(self, *args, **kwargs):
        if 'w' in kwargs:
            self.w = kwargs['w']
            self.x = kwargs['x']
            self.y = kwargs['y']
            self.z = kwargs['z']
        elif len(args)==4:
            angle = (float(args[3]) / 180.) * 3.1415926
            result = math.sin(angle / 2.)
            self.w = math.cos(angle / 2.)
            self.x = float(args[0]) * result
            self.y = float(args[1]) * result
            self.z = float(args[2]) * result
        else:
            self.w = 1.
            self.x = 0.
            self.y = 0.
            self.z = 0.

    def gl_matrix(self):
        """
           Returns OpenGL compatible modelview matrix
        """
        m = [0.] * 16
        m[0] = 1.0 - 2.0 * ( self.y * self.y + self.z * self.z )
        m[1] = 2.0 * (self.x * self.y + self.z * self.w)
        m[2] = 2.0 * (self.x * self.z - self.y * self.w)
        m[3] = 0.0 
        m[ 4] = 2.0 * ( self.x * self.y - self.z * self.w ) 
        m[ 5] = 1.0 - 2.0 * ( self.x * self.x + self.z * self.z )
        m[ 6] = 2.0 * (self.z * self.y + self.x * self.w ) 
        m[ 7] = 0.0 
        m[ 8] = 2.0 * ( self.x * self.z + self.y * self.w )
        m[ 9] = 2.0 * ( self.y * self.z - self.x * self.w )
        m[10] = 1.0 - 2.0 * ( self.x * self.x + self.y * self.y ) 
        m[11] = 0.0 
        m[12] = 0 
        m[13] = 0 
        m[14] = 0 
        m[15] = 1.0
        return m
    
    def __mul__(self, b):
        r = Quat()
        r.w = self.w*b.w - self.x*b.x - self.y*b.y - self.z*b.z
        r.x = self.w*b.x + self.x*b.w + self.y*b.z - self.z*b.y
        r.y = self.w*b.y + self.y*b.w + self.z*b.x - self.x*b.z
        r.z = self.w*b.z + self.z*b.w + self.x*b.y - self.y*b.x
        return(r)
Example usage:
roll = 30
pitch = 45
heading = 30
# the order of multiplication is important
Q1 = Quat(0,0,1, roll) * Quat(1,0,0, pitch) * Quat(0,1,0, heading)
print Q1.gl_matrix()