00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00019
00029
00030
00031
00032 #ifndef QUATERNION_H
00033 #define QUATERNION_H
00034
00035
00037
00038
00039 #include <cmath>
00040 #ifndef QT_NO_DEBUG
00041 #include <iostream>
00042 #endif
00043
00044
00045 #include <vector3d.h>
00046 template <class T> class Vector3D;
00047
00051
00053 template <class T> class Quaternion
00054 {
00055 public:
00056 Quaternion();
00057 Quaternion(const T w, const T x, const T y, const T z);
00058 Quaternion(const T xAngle, const T yAngle, const T zAngle);
00059 Quaternion(const Vector3D<T> v, const T angle);
00060 ~Quaternion();
00061
00063 Quaternion operator*(const Quaternion& quat);
00064 Quaternion& operator=(const Quaternion& quat);
00065
00067 void identity();
00068 void normalize();
00069 void setValues(const T w, const T x, const T y, const T z);
00070 void conjugate();
00071 void inverse();
00072
00073
00074 T w() const;
00075 T x() const;
00076 T y() const;
00077 T z() const;
00078
00079
00080 void eulerToQuaternion(const T xAngle, const T yAngle, const T zAngle);
00081 void axisToQuaternion(const Vector3D<T> v, const T angle);
00082 void getAxisAngle(Vector3D<T>& v, T& angle);
00083
00084 private:
00085
00086 void limitRange(const T minimum, T& value, const T maximum);
00087
00088
00089 T wQuat, xQuat, yQuat, zQuat;
00090 };
00091
00095
00097 template <class T> Quaternion<T>::Quaternion()
00099 {
00100 identity();
00101 }
00102
00104 template <class T> Quaternion<T>::Quaternion(const T w, const T x, const T y, const T z)
00107 {
00108 setValues(w, x, y, z);
00109 }
00110
00112 template <class T> Quaternion<T>::Quaternion(const T xAngle, const T yAngle, const T zAngle)
00115 {
00116 eulerToQuaternion(xAngle, yAngle, zAngle);
00117 }
00118
00120 template <class T> Quaternion<T>::Quaternion(const Vector3D<T> v, const T angle)
00123 {
00124 axisToQuaternion(v, angle);
00125 }
00126
00128 template <class T> Quaternion<T>::~Quaternion()
00130 {
00131 }
00132
00134 template <class T> Quaternion<T> Quaternion<T>::operator*(const Quaternion& quat)
00136 {
00137 T rw = wQuat*quat.wQuat - xQuat*quat.xQuat - yQuat*quat.yQuat - zQuat*quat.zQuat;
00138 T rx = xQuat*quat.wQuat + wQuat*quat.xQuat + zQuat*quat.yQuat - yQuat*quat.zQuat;
00139 T ry = yQuat*quat.wQuat + wQuat*quat.yQuat + xQuat*quat.zQuat - zQuat*quat.xQuat;
00140 T rz = zQuat*quat.wQuat + wQuat*quat.zQuat + yQuat*quat.xQuat - xQuat*quat.yQuat;
00141
00142 return Quaternion(rw, rx, ry, rz);
00143 }
00144
00146 template <class T> Quaternion<T>& Quaternion<T>::operator=(const Quaternion& quat)
00148 {
00149 wQuat = quat.wQuat;
00150 xQuat = quat.xQuat;
00151 yQuat = quat.yQuat;
00152 zQuat = quat.zQuat;
00153
00154 return (*this);
00155 }
00156
00158 template <class T> void Quaternion<T>::identity()
00160 {
00161 wQuat = 1.0f;
00162 xQuat = 0.0f;
00163 yQuat = 0.0f;
00164 zQuat = 0.0f;
00165 }
00166
00168 template <class T> void Quaternion<T>::normalize()
00170 {
00171 T norm = wQuat*wQuat + xQuat*xQuat + yQuat*yQuat + zQuat*zQuat;
00172 if(norm < Point3D<T>::TOLERANCE)
00173 {
00174 #ifndef QT_NO_DEBUG
00175 std::cerr << "Quaternion::normalize(): Norm of the quaternion too close to zero" << std::endl;
00176 #endif
00177 return;
00178 }
00179
00180 wQuat /= norm;
00181 xQuat /= norm;
00182 yQuat /= norm;
00183 zQuat /= norm;
00184
00185 norm = wQuat*wQuat + xQuat*xQuat + yQuat*yQuat + zQuat*zQuat;
00186 if(fabs(norm - 1.0f) > Point3D<T>::TOLERANCE)
00187 {
00188 #ifndef QT_NO_DEBUG
00189 std::cerr << "Quaternion::normalize(): Norm of the quaternion not equal to 1 but " << norm << std::endl;
00190 #endif
00191 return;
00192 }
00193
00194 limitRange(-1.0, wQuat, 1.0);
00195 limitRange(-1.0, xQuat, 1.0);
00196 limitRange(-1.0, yQuat, 1.0);
00197 limitRange(-1.0, zQuat, 1.0);
00198 }
00199
00201 template <class T> void Quaternion<T>::setValues(const T w, const T x, const T y, const T z)
00203 {
00204 if((w*w + x*x + y*y + z*z) < Point3D<T>::TOLERANCE)
00205 {
00206 #ifndef QT_NO_DEBUG
00207 std::cerr << "Quaternion::setValues(wxyz): Norm of the quaternion too close to zero" << std::endl;
00208 std::cerr << " values: " << w << " " << x << " " << y << " " << z << std::endl;
00209 #endif
00210 identity();
00211 return;
00212 }
00213
00214 wQuat = w;
00215 xQuat = x;
00216 yQuat = y;
00217 zQuat = z;
00218
00219 normalize();
00220 }
00221
00223 template <class T> void Quaternion<T>::conjugate()
00225 {
00226 xQuat = -xQuat;
00227 yQuat = -yQuat;
00228 zQuat = -zQuat;
00229 }
00230
00232 template <class T> void Quaternion<T>::inverse()
00234 {
00235 conjugate();
00236 T norm = wQuat*wQuat + xQuat*xQuat + yQuat*yQuat + zQuat*zQuat;
00237 wQuat /= norm;
00238 xQuat /= norm;
00239 yQuat /= norm;
00240 zQuat /= norm;
00241 }
00242
00244 template <class T> T Quaternion<T>::w() const
00246 {
00247 return wQuat;
00248 }
00249
00251 template <class T> T Quaternion<T>::x() const
00253 {
00254 return xQuat;
00255 }
00256
00258 template <class T> T Quaternion<T>::y() const
00260 {
00261 return yQuat;
00262 }
00263
00265 template <class T> T Quaternion<T>::z() const
00267 {
00268 return zQuat;
00269 }
00270
00272 template <class T> void Quaternion<T>::eulerToQuaternion(const T xAngle, const T yAngle, const T zAngle)
00274 {
00275 T ex = xAngle*Point3D<T>::DEGTORAD / 2.0;
00276 T ey = yAngle*Point3D<T>::DEGTORAD / 2.0;
00277 T ez = zAngle*Point3D<T>::DEGTORAD / 2.0;
00278
00279 T cr = cos(ex);
00280 T cp = cos(ey);
00281 T cy = cos(ez);
00282
00283 T sr = sin(ex);
00284 T sp = sin(ey);
00285 T sy = sin(ez);
00286
00287 T cpcy = cp*cy;
00288 T spsy = sp*sy;
00289
00290 wQuat = cr*cpcy + sr*spsy;
00291 xQuat = sr*cpcy - cr*spsy;
00292 yQuat = cr*sp*cy + sr*cp*sy;
00293 zQuat = cr*cp*sy - sr*sp*cy;
00294
00295 normalize();
00296 }
00297
00299 template <class T> void Quaternion<T>::axisToQuaternion(const Vector3D<T> v, const T angle)
00302 {
00304 if(v.isZero())
00305 {
00306 setValues(1.0, 0.0, 0.0, 0.0);
00307 return;
00308 }
00309
00311 Vector3D<T> unitVector = v;
00312 unitVector.normalize();
00313
00315 T rad = angle * Point3D<T>::DEGTORAD / 2.0;
00316 T scale = sin(rad);
00317 setValues(cos(rad), unitVector.x() * scale, unitVector.y() * scale, unitVector.z() * scale);
00318 normalize();
00319 }
00320
00322 template <class T> void Quaternion<T>::getAxisAngle(Vector3D<T>& v, T& angle)
00325 {
00326 T scale = sqrt(xQuat*xQuat + yQuat*yQuat + zQuat*zQuat);
00327
00328 if(fabs(scale) < Point3D<T>::TOLERANCE)
00329 {
00331 angle = 0.0;
00332 v.setValues(0.0, 0.0, 1.0);
00333 }
00334 else
00335 {
00336 angle = acos(wQuat)*2.0*Point3D<T>::RADTODEG;
00337 v.setValues(xQuat/scale, yQuat/scale, zQuat/scale);
00338 v.normalize();
00339 }
00340 }
00341
00342
00346
00348 template <class T> void Quaternion<T>::limitRange(const T minimum, T& value, const T maximum)
00350 {
00351 if(value < minimum)
00352 value = minimum;
00353 else if(value > maximum)
00354 value = maximum;
00355 }
00356
00357 #endif
00358