00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include "math/quaternion.hpp"
00035 #include "math/transform.hpp"
00036
00037 #include <cmath>
00038
00039 namespace gsgl
00040 {
00041
00042 namespace math
00043 {
00044
00045
00046 quaternion::quaternion(const double w, const double x, const double y, const double z)
00047 : math_object(), w(w), x(x), y(y), z(z)
00048 {
00049 }
00050
00051
00052
00053 quaternion::quaternion(const vector & v, double a)
00054 : math_object()
00055 {
00056 w = ::cos(a/2.0);
00057 x = v.get_x() * ::sin(a/2.0);
00058 y = v.get_y() * ::sin(a/2.0);
00059 z = v.get_z() * ::sin(a/2.0);
00060
00061 normalize();
00062 }
00063
00064
00065
00066 quaternion::quaternion(const quaternion & q)
00067 : math_object()
00068 {
00069 x = q.x;
00070 y = q.y;
00071 z = q.z;
00072 w = q.w;
00073 }
00074
00075
00076
00077 quaternion::quaternion(const gsgl::string & s)
00078 : math_object()
00079 {
00080 vector v(s);
00081
00082 x = v.get_x();
00083 y = v.get_y();
00084 z = v.get_z();
00085 w = v.get_w();
00086 }
00087
00088
00089
00090 quaternion::quaternion(const transform & t)
00091 : math_object()
00092 {
00093 *this = t;
00094 }
00095
00096
00097
00098 quaternion & quaternion::operator= (const transform & t)
00099 {
00100 const gsgl::real_t *data = t.ptr();
00101
00102 gsgl::real_t tr, s;
00103
00104 tr = data[0] + data[5] + data[10];
00105
00106 if (tr >= 0)
00107 {
00108 s = ::sqrt(tr + 1.0f);
00109 w = s * 0.5f;
00110 s = 0.5f / s;
00111 x = (data[9] - data[6]) * s;
00112 y = (data[2] - data[9]) * s;
00113 z = (data[4] - data[1]) * s;
00114 }
00115 else
00116 {
00117 int i = 0;
00118
00119 if (data[5] > data[0])
00120 i = 1;
00121
00122 if (i == 0)
00123 {
00124 if (data[10] > data[0])
00125 i = 2;
00126 }
00127 else
00128 {
00129 if (data[10] > data[5])
00130 i = 2;
00131 }
00132
00133 switch (i)
00134 {
00135 case 0:
00136 s = ::sqrt( (data[0] - (data[5] + data[10])) + 1.0f );
00137 x = s * 0.5f;
00138 s = 0.5f / s;
00139 y = (data[1] + data[4]) * s;
00140 z = (data[8] + data[2]) * s;
00141 w = (data[0] - data[6]) * s;
00142 break;
00143 case 1:
00144 s = ::sqrt( (data[5] - (data[10] + data[0])) + 1.0f );
00145 y = s * 0.5f;
00146 s = 0.5f / s;
00147 z = (data[6] + data[9]) * s;
00148 x = (data[1] + data[4]) * s;
00149 w = (data[2] - data[8]) * s;
00150 break;
00151 case 2:
00152 s = ::sqrt( (data[10] - (data[0] + data[5])) + 1.0f );
00153 z = s * 0.5f;
00154 s = 0.5f / s;
00155 x = (data[8] + data[2]) * s;
00156 y = (data[6] + data[9]) * s;
00157 w = (data[4] - data[1]) * s;
00158 break;
00159 }
00160 }
00161
00162 normalize();
00163
00164 return *this;
00165 }
00166
00167
00168
00169 quaternion & quaternion::operator= (const quaternion & q)
00170 {
00171 x = q.x;
00172 y = q.y;
00173 z = q.z;
00174 w = q.w;
00175 return *this;
00176 }
00177
00178
00179 quaternion::~quaternion()
00180 {
00181 }
00182
00183
00184
00185
00186
00187 double quaternion::norm() const
00188 {
00189 return ::sqrt(w*w + x*x + y*y + z*z);
00190 }
00191
00192
00193
00194 quaternion quaternion::conjugate() const
00195 {
00196 return quaternion(w, -x, -y, -z);
00197 }
00198
00199
00200
00201 quaternion quaternion::inverse() const
00202 {
00203 double n = norm();
00204
00205 if (n != 0)
00206 return quaternion(w/n, -x/n, -y/n, -z/n);
00207 else
00208 throw runtime_exception(L"Division by zero finding a quaternion inverse.");
00209 }
00210
00211
00212
00213 void quaternion::normalize()
00214 {
00215 double m = norm();
00216
00217 if (m != 0)
00218 {
00219 w /= m;
00220 x /= m;
00221 y /= m;
00222 z /= m;
00223 }
00224 else
00225 {
00226 throw runtime_exception(L"Division by zero finding a quaternion normal.");
00227 }
00228 }
00229
00230
00231
00232
00233 quaternion quaternion::operator+ (const quaternion & q) const
00234 {
00235 return quaternion(w+q.w, x+q.x, y+q.y, z+q.z);
00236 }
00237
00238
00239 quaternion quaternion::operator* (const quaternion & q) const
00240 {
00241 return quaternion(w*q.w - x*q.x - y*q.y - z*q.z,
00242 w*q.x + x*q.w + y*q.z - z*q.y,
00243 w*q.y - x*q.z + y*q.w + z*q.x,
00244 w*q.z + x*q.y - y*q.x + z*q.w);
00245 }
00246
00247
00248 quaternion quaternion::operator* (const double & n) const
00249 {
00250 return quaternion(w*n, x*n, y*n, z*n);
00251 }
00252
00253
00254 double quaternion::dot(const quaternion & q) const
00255 {
00256 return w*q.w + x*q.x + y*q.y + z*q.z;
00257 }
00258
00259
00260 quaternion quaternion::interpolate(const quaternion & start, const quaternion & end, const double & percent)
00261 {
00262 quaternion result;
00263
00264 double theta = ::acos(start.dot(end));
00265 result = ( (start * ::sin((1.0f - percent) * theta)) + (end * ::sin(percent * theta)) ) * (1.0 / ::sin(theta));
00266 result.normalize();
00267
00268 return result;
00269 }
00270
00271
00272 }
00273
00274 }