summaryrefslogtreecommitdiffstats
path: root/dev/MinGfx/src/quaternion.h
blob: fc69ba7a71812fae5b5e533ba3e0b9808c947421 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/*
 This file is part of the MinGfx Project.
 
 Copyright (c) 2017,2018 Regents of the University of Minnesota.
 All Rights Reserved.
 
 Original Author(s) of this File:
	Dan Keefe, 2018, University of Minnesota
	
 Author(s) of Significant Updates/Modifications to the File:
	...
 */

#ifndef SRC_QUATERNION_H_
#define SRC_QUATERNION_H_

#include <iostream>

#include "vector3.h"

namespace mingfx {

/** A quaternion to represent rotations in 3D space.  The main use of quaternions
 within the library is to support smooth interpolation between rotations, since
 this is not possible using Euler angles or rotation matrices.  The class includes
 a Slerp routine for spherical interpolation between rotations.  Example use:
 ~~~
 // find a rotation 1/2 way between r1 and r2, both originally expressed in Euler angles
 
 Vector3 euler1 = GfxMath::ToRadians(Vector3(0,0,60));
 Vector3 euler2 = GfxMath::ToRadians(Vector3(45,45,60));
 
 Quaternion q1 = Quaternion::FromEulerAnglesZYX(euler1);
 Quaternion q2 = Quaternion::FromEulerAnglesZYX(euler2);

 float alpha = 0.5;
 Quaternion q_half_way = q1.Slerp(q2, alpha);
 Vector3 new_euler_angles = GfxMath::ToDegrees(q_half_way.ToEulerAnglesZYX());
 ~~~
 */
class Quaternion {
public:
    /// Creates a quat with the identity rotation
    Quaternion();

    /// Creates a quat from the 4 parameters
    Quaternion(float qx, float qy, float qz, float qw);
    
    /// Creates a quate from a pointer to 4 floating point numbers in the order
    /// qx, qy, qz, qw.
    Quaternion(float *ptr);

    /// Copy constructor
    Quaternion(const Quaternion& other);
    
    virtual ~Quaternion();
    
    /// Check for "equality", taking floating point imprecision into account
    bool operator==(const Quaternion& q) const;
    
    /// Check for "inequality", taking floating point imprecision into account
    bool operator!=(const Quaternion& q) const;
    
    /// Assignment operator
    Quaternion& operator=(const Quaternion& q);
    
    /// Read only access to the ith coordinate of the quaternion (qx, qy, qz, qw).
    float operator[](const int i) const;
    
    /// Writable access the ith coordinate of the quaternion (qx, qy, qz, qw).
    float& operator[](const int i);
    
    /// Read only access to the x coordinate of the imaginary part of the quaternion.
    float x() const { return q[0]; }

    /// Read only access to the y coordinate of the imaginary part of the quaternion.
    float y() const { return q[1]; }
    
    /// Read only access to the z coordinate of the imaginary part of the quaternion.
    float z() const { return q[2]; }

    /// Read only access to the w, real part, of the quaternion.
    float w() const { return q[3]; }
    
    /// Returns a const pointer to the raw data array, stored in the order qx, qy, qz, qw.
    const float * value_ptr() const;

    /// Returns the dot product of this quaternion with another.
    float Dot(const Quaternion& q) const;

    /// Returns the length of the quaternion.
    float Length() const;
    
    /// Normalizes the quat by making it unit length.
    void Normalize();
    
    /// Returns a normalized (i.e., unit length) version of the quaternion without
    /// modifying the original.
    Quaternion ToUnit() const;
    
    /// Returns the conjugate of the quaternion.
    Quaternion Conjugate() const;
    
    /// Converts the rotation specified by the quaternion into Euler angles.
    Vector3 ToEulerAnglesZYX() const;

    /// Uses spherical interpolation to interpoloate between the rotation stored
    /// in this quaternion and the rotation stored in another.
    Quaternion Slerp(const Quaternion &other, float alpha) const;

    /// Creates a new quaternion that describes a rotation by angle radians about
    // the specified axis.
    static Quaternion FromAxisAngle(const Vector3 &axis, float angle);
    
    /// Creates a new quaternion from a rotation defined in Euler angles.
    static Quaternion FromEulerAnglesZYX(const Vector3 &angles);
    
    /// Uses spherical interpolation to interpoloate between the rotations
    /// specified by two quaternions.
    static Quaternion Slerp(const Quaternion &a, const Quaternion &b, float alpha);
    
private:
    float q[4];
};


Quaternion operator*(const Quaternion& q1, const Quaternion& q2);
Quaternion operator/(const Quaternion& q, const float s);
Quaternion operator*(const float s, const Quaternion& q);
Quaternion operator*(const Quaternion& q, const float s);
Quaternion operator-(const Quaternion& q);
Quaternion operator+(const Quaternion& q1, const Quaternion& q2);
Quaternion operator-(const Quaternion& q1, const Quaternion& q2);

std::ostream & operator<< ( std::ostream &os, const Quaternion &q);
std::istream & operator>> ( std::istream &is, Quaternion &q);

    
} // end namespace


#endif