00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "PreCompiled.h"
00025 #ifndef _PreComp_
00026 # include <cmath>
00027 # include <climits>
00028 #endif
00029
00030 #include "Rotation.h"
00031 #include "Matrix.h"
00032
00033 using namespace Base;
00034
00035 Rotation::Rotation()
00036 {
00037 quat[0]=quat[1]=quat[2]=0.0f;quat[3]=1.0f;
00038 }
00039
00041 Rotation::Rotation(const Vector3d& axis, const double fAngle)
00042 {
00043 this->setValue(axis, fAngle);
00044 }
00045
00046 Rotation::Rotation(const Matrix4D& matrix)
00047 {
00048 this->setValue(matrix);
00049 }
00050
00055 Rotation::Rotation(const double q[4])
00056 {
00057 this->setValue(q);
00058 }
00059
00064 Rotation::Rotation(const double q0, const double q1, const double q2, const double q3)
00065 {
00066 this->setValue(q0, q1, q2, q3);
00067 }
00068
00069 Rotation::Rotation(const Vector3d & rotateFrom, const Vector3d & rotateTo)
00070 {
00071 this->setValue(rotateFrom, rotateTo);
00072 }
00073
00074 Rotation::Rotation(const Rotation& rot)
00075 {
00076 this->quat[0] = rot.quat[0];
00077 this->quat[1] = rot.quat[1];
00078 this->quat[2] = rot.quat[2];
00079 this->quat[3] = rot.quat[3];
00080 }
00081
00082 const double * Rotation::getValue(void) const
00083 {
00084 return &this->quat[0];
00085 }
00086
00087 void Rotation::getValue(double & q0, double & q1, double & q2, double & q3) const
00088 {
00089 q0 = this->quat[0];
00090 q1 = this->quat[1];
00091 q2 = this->quat[2];
00092 q3 = this->quat[3];
00093 }
00094
00095 void Rotation::setValue(const double q0, const double q1, const double q2, const double q3)
00096 {
00097 this->quat[0] = q0;
00098 this->quat[1] = q1;
00099 this->quat[2] = q2;
00100 this->quat[3] = q3;
00101 this->normalize();
00102 }
00103
00104 void Rotation::getValue(Vector3d & axis, double & rfAngle) const
00105 {
00106
00107
00108
00109 if((this->quat[3] > -1.0f) && (this->quat[3] < 1.0f)) {
00110 rfAngle = double(acos(this->quat[3])) * 2.0f;
00111 double scale = (double)sin(rfAngle / 2.0f);
00112
00113 axis.x = this->quat[0] / scale;
00114 axis.y = this->quat[1] / scale;
00115 axis.z = this->quat[2] / scale;
00116 }
00117 else {
00118
00119 axis.Set(0.0f, 0.0f, 1.0f);
00120 rfAngle = 0.0f;
00121 }
00122 }
00123
00127 void Rotation::getValue(Matrix4D & matrix) const
00128 {
00129
00130
00131 const double x = this->quat[0];
00132 const double y = this->quat[1];
00133 const double z = this->quat[2];
00134 const double w = this->quat[3];
00135
00136 matrix[0][0] = 1.0f-2.0f*(y*y+z*z);
00137 matrix[0][1] = 2.0f*(x*y-z*w);
00138 matrix[0][2] = 2.0f*(x*z+y*w);
00139 matrix[0][3] = 0.0f;
00140
00141 matrix[1][0] = 2.0f*(x*y+z*w);
00142 matrix[1][1] = 1.0f-2.0f*(x*x+z*z);
00143 matrix[1][2] = 2.0f*(y*z-x*w);
00144 matrix[1][3] = 0.0f;
00145
00146 matrix[2][0] = 2.0f*(x*z-y*w);
00147 matrix[2][1] = 2.0f*(y*z+x*w);
00148 matrix[2][2] = 1.0f-2.0f*(x*x+y*y);
00149 matrix[2][3] = 0.0f;
00150
00151 matrix[3][0] = 0.0f;
00152 matrix[3][1] = 0.0f;
00153 matrix[3][2] = 0.0f;
00154 matrix[3][3] = 1.0f;
00155 }
00156
00157 void Rotation::setValue(const double q[4])
00158 {
00159 this->quat[0] = q[0];
00160 this->quat[1] = q[1];
00161 this->quat[2] = q[2];
00162 this->quat[3] = q[3];
00163 this->normalize();
00164 }
00165
00166 void Rotation::setValue(const Matrix4D & m)
00167 {
00168 double trace = (double)(m[0][0] + m[1][1] + m[2][2]);
00169 if (trace > 0.0f) {
00170 double s = (double)sqrt(1.0f+trace);
00171 this->quat[3] = 0.5f * s;
00172 s = 0.5f / s;
00173 this->quat[0] = (double)((m[2][1] - m[1][2]) * s);
00174 this->quat[1] = (double)((m[0][2] - m[2][0]) * s);
00175 this->quat[2] = (double)((m[1][0] - m[0][1]) * s);
00176 }
00177 else {
00178
00179
00180
00181 int i = 0;
00182 if (m[1][1] > m[0][0]) i = 1;
00183 if (m[2][2] > m[i][i]) i = 2;
00184
00185 int j = (i+1)%3;
00186 int k = (i+2)%3;
00187
00188 double s = (double)sqrt((m[i][i] - (m[j][j] + m[k][k])) + 1.0f);
00189 this->quat[i] = s * 0.5f;
00190 s = 0.5f / s;
00191 this->quat[3] = (double)((m[k][j] - m[j][k]) * s);
00192 this->quat[j] = (double)((m[j][i] + m[i][j]) * s);
00193 this->quat[k] = (double)((m[k][i] + m[i][k]) * s);
00194 }
00195 }
00196
00197 void Rotation::setValue(const Vector3d & axis, const double fAngle)
00198 {
00199
00200
00201 this->quat[3] = (double)cos(fAngle/2.0);
00202 Vector3d norm = axis;
00203 norm.Normalize();
00204 double scale = (double)sin(fAngle/2.0);
00205 this->quat[0] = norm.x * scale;
00206 this->quat[1] = norm.y * scale;
00207 this->quat[2] = norm.z * scale;
00208 }
00209
00210 void Rotation::setValue(const Vector3d & rotateFrom, const Vector3d & rotateTo)
00211 {
00212 Vector3d u(rotateFrom); u.Normalize();
00213 Vector3d v(rotateTo); v.Normalize();
00214
00215
00216 const double dot = u * v;
00217 Vector3d w = u % v;
00218 const double wlen = w.Length();
00219
00220 if (wlen == 0.0f) {
00221
00222 if (dot > 0.0f) {
00223 this->setValue(0.0f, 0.0f, 0.0f, 1.0f);
00224 }
00225 else {
00226
00227 Vector3d t = u % Vector3d(1.0f, 0.0f, 0.0f);
00228 if(t.Length() < FLT_EPSILON)
00229 t = u % Vector3d(0.0f, 1.0f, 0.0f);
00230 this->setValue(t.x, t.y, t.z, 0.0f);
00231 }
00232 }
00233 else {
00234
00235
00236 double angle = (double)acos(dot);
00237 this->setValue(w, angle);
00238 }
00239 }
00240
00241 void Rotation::normalize()
00242 {
00243 double len = (double)sqrt(this->quat[0]*this->quat[0]+
00244 this->quat[1]*this->quat[1]+
00245 this->quat[2]*this->quat[2]+
00246 this->quat[3]*this->quat[3]);
00247 if (len != 0) {
00248 this->quat[0] /= len;
00249 this->quat[1] /= len;
00250 this->quat[2] /= len;
00251 this->quat[3] /= len;
00252 }
00253 }
00254
00255 Rotation & Rotation::invert(void)
00256 {
00257 this->quat[0] = -this->quat[0];
00258 this->quat[1] = -this->quat[1];
00259 this->quat[2] = -this->quat[2];
00260 this->quat[3] = this->quat[3];
00261 return *this;
00262 }
00263
00264 Rotation Rotation::inverse(void) const
00265 {
00266 Rotation rot;
00267 rot.quat[0] = -this->quat[0];
00268 rot.quat[1] = -this->quat[1];
00269 rot.quat[2] = -this->quat[2];
00270 rot.quat[3] = this->quat[3];
00271 return rot;
00272 }
00273
00274 Rotation & Rotation::operator*=(const Rotation & q)
00275 {
00276
00277 double x0, y0, z0, w0;
00278 this->getValue(x0, y0, z0, w0);
00279 double x1, y1, z1, w1;
00280 q.getValue(x1, y1, z1, w1);
00281
00282 this->setValue(w0*x1 + x0*w1 + y0*z1 - z0*y1,
00283 w0*y1 - x0*z1 + y0*w1 + z0*x1,
00284 w0*z1 + x0*y1 - y0*x1 + z0*w1,
00285 w0*w1 - x0*x1 - y0*y1 - z0*z1);
00286 return *this;
00287 }
00288
00289 Rotation Rotation::operator*(const Rotation & q) const
00290 {
00291 Rotation quat(*this);
00292 quat *= q;
00293 return quat;
00294 }
00295
00296 bool Rotation::operator==(const Rotation & q) const
00297 {
00298 bool equal = true;
00299 for (int i=0; i<4;i++)
00300 equal &= (fabs(this->quat[i] - q.quat[i]) < 0.005 );
00301 return equal;
00302 }
00303
00304 bool Rotation::operator!=(const Rotation & q) const
00305 {
00306 return !(*this == q);
00307 }
00308
00309 void Rotation::multVec(const Vector3d & src, Vector3d & dst) const
00310 {
00311 double x = this->quat[0];
00312 double y = this->quat[1];
00313 double z = this->quat[2];
00314 double w = this->quat[3];
00315 double x2 = x * x;
00316 double y2 = y * y;
00317 double z2 = z * z;
00318 double w2 = w * w;
00319
00320 double dx = (x2+w2-y2-z2)*src.x + 2.0f*(x*y-z*w)*src.y + 2.0f*(x*z+y*w)*src.z;
00321 double dy = 2.0f*(x*y+z*w)*src.x + (w2-x2+y2-z2)*src.y + 2.0f*(y*z-x*w)*src.z;
00322 double dz = 2.0f*(x*z-y*w)*src.x + 2.0f*(x*w+y*z)*src.y + (w2-x2-y2+z2)*src.z;
00323 dst.x = dx;
00324 dst.y = dy;
00325 dst.z = dz;
00326 }
00327
00328 void Rotation::scaleAngle(const double scaleFactor)
00329 {
00330 Vector3d axis;
00331 double fAngle;
00332 this->getValue(axis, fAngle);
00333 this->setValue(axis, fAngle * scaleFactor);
00334 }
00335
00336 Rotation Rotation::slerp(const Rotation & q0, const Rotation & q1, double t)
00337 {
00338
00339
00340 if (t<0.0f) t=0.0f;
00341 else if (t>1.0f) t=1.0f;
00342
00343
00344 double scale0 = 1.0f - t;
00345 double scale1 = t;
00346 double dot = q0.quat[0]*q1.quat[0]+q0.quat[1]*q1.quat[1]+q0.quat[2]*q1.quat[2]+q0.quat[3]*q1.quat[3];
00347 bool neg=false;
00348 if(dot < 0.0f) {
00349 dot = -dot;
00350 neg = true;
00351 }
00352
00353 if ((1.0f - dot) > FLT_EPSILON) {
00354 double angle = (double)acos(dot);
00355 double sinangle = (double)sin(angle);
00356
00357 if (sinangle > FLT_EPSILON) {
00358 scale0 = double(sin((1.0 - t) * angle)) / sinangle;
00359 scale1 = double(sin(t * angle)) / sinangle;
00360 }
00361 }
00362
00363 if (neg)
00364 scale1 = -scale1;
00365
00366 double x = scale0 * q0.quat[0] + scale1 * q1.quat[0];
00367 double y = scale0 * q0.quat[1] + scale1 * q1.quat[1];
00368 double z = scale0 * q0.quat[2] + scale1 * q1.quat[2];
00369 double w = scale0 * q0.quat[3] + scale1 * q1.quat[3];
00370 return Rotation(x, y, z, w);
00371 }
00372
00373 Rotation Rotation::identity(void)
00374 {
00375 return Rotation(0.0f, 0.0f, 0.0f, 1.0f);
00376 }
00377
00378 void Rotation::setYawPitchRoll(double y, double p, double r)
00379 {
00380
00381
00382 double c1 = cos(((y/180.0)*D_PI)/2.0);
00383 double s1 = sin(((y/180.0)*D_PI)/2.0);
00384 double c2 = cos(((p/180.0)*D_PI)/2.0);
00385 double s2 = sin(((p/180.0)*D_PI)/2.0);
00386 double c3 = cos(((r/180.0)*D_PI)/2.0);
00387 double s3 = sin(((r/180.0)*D_PI)/2.0);
00388
00389 quat[0] = c1*c2*s3 - s1*s2*c3;
00390 quat[1] = c1*s2*c3 + s1*c2*s3;
00391 quat[2] = s1*c2*c3 - c1*s2*s3;
00392 quat[3] = c1*c2*c3 + s1*s2*s3;
00393 }
00394
00395 void Rotation::getYawPitchRoll(double& y, double& p, double& r) const
00396 {
00397
00398
00399 double q00 = quat[0]*quat[0];
00400 double q11 = quat[1]*quat[1];
00401 double q22 = quat[2]*quat[2];
00402 double q33 = quat[3]*quat[3];
00403 double q01 = quat[0]*quat[1];
00404 double q02 = quat[0]*quat[2];
00405 double q03 = quat[0]*quat[3];
00406 double q12 = quat[1]*quat[2];
00407 double q13 = quat[1]*quat[3];
00408 double q23 = quat[2]*quat[3];
00409 double qd2 = 2.0*(q13-q02);
00410
00411 y = atan2(2.0*(q01+q23),(q00+q33)-(q11+q22));
00412 p = qd2 > 1.0 ? D_PI/2.0 : (qd2 < -1.0 ? -D_PI/2.0 : asin (qd2));
00413 r = atan2(2.0*(q12+q03),(q22+q33)-(q00+q11));
00414
00415
00416 y = (y/D_PI)*180;
00417 p = (p/D_PI)*180;
00418 r = (r/D_PI)*180;
00419 }