00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifndef KEOS_QUATERNION_H
00023 #define KEOS_QUATERNION_H
00024
00025 #include "KeosPrerequisites.h"
00026 #include "KeosMatrix4.h"
00027
00028 namespace Keos
00029 {
00030
00034 class CQuaternion
00035 {
00036 public :
00037
00040 CQuaternion(float X = 0.0f, float Y = 0.0f, float Z = 0.0f, float W = 1.0f);
00041
00045 CQuaternion(const CMatrix4& Matrix);
00046
00051 CQuaternion(const TVector3F& Axis, float Angle);
00052
00055 void Identity();
00056
00059 inline void Normalize();
00060
00064 CQuaternion Conjugate() const;
00065
00069 CMatrix4 ToMatrix() const;
00070
00074 void FromMatrix(const CMatrix4& Matrix);
00075
00080 void FromAxisAngle(const TVector3F& Axis, float Angle);
00081
00086 void ToAxisAngle(TVector3F& Axis, float& Angle) const;
00087
00093 void FromEulerAngles(float X, float Y, float Z);
00094
00095
00096 CQuaternion operator *(const CQuaternion& Quaternion) const;
00097 const CQuaternion& operator *=(const CQuaternion& Quaternion);
00098
00099 float x;
00100 float y;
00101 float z;
00102 float w;
00103 };
00104
00105
00106 std::istream& operator >>(std::istream& Stream, CQuaternion& Quaternion);
00107 std::ostream& operator <<(std::ostream& Stream, const CQuaternion& Quaternion);
00108
00109
00110
00111
00112
00113
00114 inline CQuaternion::CQuaternion(float X, float Y, float Z, float W) :
00115 x(X),
00116 y(Y),
00117 z(Z),
00118 w(W)
00119 {}
00120
00121
00122 inline CQuaternion::CQuaternion(const CMatrix4& Matrix)
00123 {
00124 FromMatrix(Matrix);
00125 }
00126
00127
00128 inline CQuaternion::CQuaternion(const TVector3F& Axis, float Angle)
00129 {
00130 FromAxisAngle(Axis, Angle);
00131 }
00132
00133
00134 inline void CQuaternion::Identity()
00135 {
00136 x = y = z = 0.0f;
00137 w = 1.0f;
00138 }
00139
00140
00141 inline void CQuaternion::Normalize()
00142 {
00143 float Norm = x * x + y * y + z * z + w * w;
00144
00145 if (std::fabs(Norm) > std::numeric_limits<float>::epsilon())
00146 {
00147 x /= Norm;
00148 y /= Norm;
00149 z /= Norm;
00150 w /= Norm;
00151 }
00152 }
00153
00154
00155 inline CQuaternion CQuaternion::Conjugate() const
00156 {
00157 return CQuaternion(-x, -y, -z, w);
00158 }
00159
00160
00161 inline CMatrix4 CQuaternion::ToMatrix() const
00162 {
00163 float xx = x * x;
00164 float xy = x * y;
00165 float xz = x * z;
00166 float xw = x * w;
00167 float yy = y * y;
00168 float yz = y * z;
00169 float yw = y * w;
00170 float zz = z * z;
00171 float zw = z * w;
00172
00173 return CMatrix4(1 - 2 * (yy + zz), 2 * (xy - zw), 2 * (xy + yw), 0,
00174 2 * (xy + zw), 1 - 2 * (xx + zz), 2 * (yz - xw), 0,
00175 2 * (xz - yw), 2 * (yz + xw), 1 - 2 * (xx + yy), 0,
00176 0, 0, 0, 1);
00177 }
00178
00179
00180 inline void CQuaternion::FromMatrix(const CMatrix4& Matrix)
00181 {
00182 float Trace = Matrix(0, 0) + Matrix(1, 1) + Matrix(2, 2) + 1;
00183
00184 if (Trace > 0)
00185 {
00186 float s = 0.5f / std::sqrtf(Trace);
00187 x = (Matrix(2, 1) - Matrix(1, 2)) * s;
00188 y = (Matrix(0, 2) - Matrix(2, 0)) * s;
00189 z = (Matrix(1, 0) - Matrix(0, 1)) * s;
00190 w = 0.25f / s;
00191 }
00192 else
00193 {
00194 if ((Matrix(0, 0) > Matrix(1, 1) && (Matrix(0, 0) > Matrix(2, 2)))
00195 {
00196 float s = std::sqrt(1 + Matrix(0, 0) - Matrix(1, 1) - Matrix(2, 2)) * 2;
00197 x = 0.5f / s;
00198 y = (Matrix(0, 1) + Matrix(1, 0)) / s;
00199 z = (Matrix(0, 2) + Matrix(2, 0)) / s;
00200 w = (Matrix(1, 2) + Matrix(2, 1)) / s;
00201 }
00202 else if (Matrix(1, 1) > Matrix(2, 2))
00203 {
00204 float s = std::sqrt(1 - Matrix(0, 0) + Matrix(1, 1) - Matrix(2, 2)) * 2;
00205 x = (Matrix(0, 1) + Matrix(1, 0)) / s;
00206 y = 0.5f / s;
00207 z = (Matrix(1, 2) + Matrix(2, 1)) / s;
00208 w = (Matrix(0, 2) + Matrix(2, 0)) / s;
00209 }
00210 else
00211 {
00212 float s = std::sqrt(1 - Matrix(0, 0) - Matrix(1, 1) + Matrix(2, 2)) * 2;
00213 x = (Matrix(0, 2) + Matrix(2, 0)) / s;
00214 y = (Matrix(1, 2) + Matrix(2, 1)) / s;
00215 z = 0.5f / s;
00216 w = (Matrix(0, 1) + Matrix(1, 0)) / s;
00217 }
00218 }
00219 }
00220
00221
00222 inline void CQuaternion::FromAxisAngle(const TVector3F& Axis, float Angle)
00223 {
00224 float Cos = std::cos(Angle / 2);
00225 float Sin = std::sin(Angle / 2);
00226
00227 x = Axis.x * Sin;
00228 y = Axis.y * Sin;
00229 z = Axis.z * Sin;
00230 w = Cos;
00231
00232 Normalize();
00233 }
00234
00235
00236 inline void CQuaternion::ToAxisAngle(TVector3F& Axis, float& Angle) const
00237 {
00238
00239 Angle = std::acosf(w) * 2;
00240
00241
00242 float Norm = std::sqrtf(x * x + y * y + z * z);
00243 if (std::fabs(Norm) > std::numeric_limits<float>::epsilon())
00244 {
00245 Axis.x = x / Norm;
00246 Axis.y = y / Norm;
00247 Axis.z = z / Norm;
00248 }
00249 else
00250 {
00251 Axis.x = 0.0f;
00252 Axis.y = 1.0f;
00253 Axis.z = 0.0f;
00254 }
00255 }
00256
00257
00258 inline void CQuaternion::FromEulerAngles(float X, float Y, float Z)
00259 {
00260 CQuaternion Qx(TVector3F(1, 0, 0), X);
00261 CQuaternion Qy(TVector3F(0, 1, 0), Y);
00262 CQuaternion Qz(TVector3F(0, 0, 1), Z);
00263
00264 *this = Qx * Qy * Qz;
00265 }
00266
00267
00268 inline CQuaternion CQuaternion::operator *(const CQuaternion& Quaternion) const
00269 {
00270 return CQuaternion(w * Quaternion.x + x * Quaternion.w + y * Quaternion.z - z * Quaternion.y,
00271 w * Quaternion.y + y * Quaternion.w + z * Quaternion.x - x * Quaternion.z,
00272 w * Quaternion.z + z * Quaternion.w + x * Quaternion.y - y * Quaternion.x,
00273 w * Quaternion.w - x * Quaternion.x - y * Quaternion.y - z * Quaternion.z);
00274 }
00275
00276
00277 inline const CQuaternion& CQuaternion::operator *=(const CQuaternion& Quaternion)
00278 {
00279 *this = *this * Quaternion;
00280
00281 return *this;
00282 }
00283
00284
00285 std::istream& operator >>(std::istream& Stream, CQuaternion& Quaternion)
00286 {
00287 return Stream >> Quaternion.x >> Quaternion.y >> Quaternion.z >> Quaternion.w;
00288 }
00289
00290
00291 std::ostream& operator <<(std::ostream& Stream, const CQuaternion& Quaternion)
00292 {
00293 return Stream << Quaternion.x << " " << Quaternion.y << " " << Quaternion.z << " " << Quaternion.w;
00294 }
00295
00296 }
00297
00298
00299 #endif // KEOS_QUATERNION_H