[692] | 1 | /*
|
---|
| 2 | -----------------------------------------------------------------------------
|
---|
| 3 | This source file is part of OGRE
|
---|
| 4 | (Object-oriented Graphics Rendering Engine)
|
---|
| 5 | For the latest info, see http://www.ogre3d.org/
|
---|
| 6 |
|
---|
| 7 | Copyright (c) 2000-2005 The OGRE Team
|
---|
| 8 | Also see acknowledgements in Readme.html
|
---|
| 9 |
|
---|
| 10 | This program is free software; you can redistribute it and/or modify it under
|
---|
| 11 | the terms of the GNU Lesser General Public License as published by the Free Software
|
---|
| 12 | Foundation; either version 2 of the License, or (at your option) any later
|
---|
| 13 | version.
|
---|
| 14 |
|
---|
| 15 | This program is distributed in the hope that it will be useful, but WITHOUT
|
---|
| 16 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
---|
| 17 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
---|
| 18 |
|
---|
| 19 | You should have received a copy of the GNU Lesser General Public License along with
|
---|
| 20 | this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
---|
| 21 | Place - Suite 330, Boston, MA 02111-1307, USA, or go to
|
---|
| 22 | http://www.gnu.org/copyleft/lesser.txt.
|
---|
| 23 | -----------------------------------------------------------------------------
|
---|
| 24 | */
|
---|
| 25 | #include "OgreStableHeaders.h"
|
---|
| 26 | // NOTE THAT THIS FILE IS BASED ON MATERIAL FROM:
|
---|
| 27 |
|
---|
| 28 | // Magic Software, Inc.
|
---|
| 29 | // http://www.geometrictools.com
|
---|
| 30 | // Copyright (c) 2000, All Rights Reserved
|
---|
| 31 | //
|
---|
| 32 | // Source code from Magic Software is supplied under the terms of a license
|
---|
| 33 | // agreement and may not be copied or disclosed except in accordance with the
|
---|
| 34 | // terms of that agreement. The various license agreements may be found at
|
---|
| 35 | // the Magic Software web site. This file is subject to the license
|
---|
| 36 | //
|
---|
| 37 | // FREE SOURCE CODE
|
---|
| 38 | // http://www.geometrictools.com/License/WildMagic3License.pdf
|
---|
| 39 |
|
---|
| 40 | #include "OgreQuaternion.h"
|
---|
| 41 |
|
---|
| 42 | #include "OgreMath.h"
|
---|
| 43 | #include "OgreMatrix3.h"
|
---|
| 44 | #include "OgreVector3.h"
|
---|
| 45 |
|
---|
| 46 | namespace Ogre {
|
---|
| 47 |
|
---|
| 48 | const Real Quaternion::ms_fEpsilon = 1e-03;
|
---|
| 49 | const Quaternion Quaternion::ZERO(0.0,0.0,0.0,0.0);
|
---|
| 50 | const Quaternion Quaternion::IDENTITY(1.0,0.0,0.0,0.0);
|
---|
| 51 |
|
---|
| 52 | //-----------------------------------------------------------------------
|
---|
| 53 | void Quaternion::FromRotationMatrix (const Matrix3& kRot)
|
---|
| 54 | {
|
---|
| 55 | // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
|
---|
| 56 | // article "Quaternion Calculus and Fast Animation".
|
---|
| 57 |
|
---|
| 58 | Real fTrace = kRot[0][0]+kRot[1][1]+kRot[2][2];
|
---|
| 59 | Real fRoot;
|
---|
| 60 |
|
---|
| 61 | if ( fTrace > 0.0 )
|
---|
| 62 | {
|
---|
| 63 | // |w| > 1/2, may as well choose w > 1/2
|
---|
| 64 | fRoot = Math::Sqrt(fTrace + 1.0); // 2w
|
---|
| 65 | w = 0.5*fRoot;
|
---|
| 66 | fRoot = 0.5/fRoot; // 1/(4w)
|
---|
| 67 | x = (kRot[2][1]-kRot[1][2])*fRoot;
|
---|
| 68 | y = (kRot[0][2]-kRot[2][0])*fRoot;
|
---|
| 69 | z = (kRot[1][0]-kRot[0][1])*fRoot;
|
---|
| 70 | }
|
---|
| 71 | else
|
---|
| 72 | {
|
---|
| 73 | // |w| <= 1/2
|
---|
| 74 | static size_t s_iNext[3] = { 1, 2, 0 };
|
---|
| 75 | size_t i = 0;
|
---|
| 76 | if ( kRot[1][1] > kRot[0][0] )
|
---|
| 77 | i = 1;
|
---|
| 78 | if ( kRot[2][2] > kRot[i][i] )
|
---|
| 79 | i = 2;
|
---|
| 80 | size_t j = s_iNext[i];
|
---|
| 81 | size_t k = s_iNext[j];
|
---|
| 82 |
|
---|
| 83 | fRoot = Math::Sqrt(kRot[i][i]-kRot[j][j]-kRot[k][k] + 1.0);
|
---|
| 84 | Real* apkQuat[3] = { &x, &y, &z };
|
---|
| 85 | *apkQuat[i] = 0.5*fRoot;
|
---|
| 86 | fRoot = 0.5/fRoot;
|
---|
| 87 | w = (kRot[k][j]-kRot[j][k])*fRoot;
|
---|
| 88 | *apkQuat[j] = (kRot[j][i]+kRot[i][j])*fRoot;
|
---|
| 89 | *apkQuat[k] = (kRot[k][i]+kRot[i][k])*fRoot;
|
---|
| 90 | }
|
---|
| 91 | }
|
---|
| 92 | //-----------------------------------------------------------------------
|
---|
| 93 | void Quaternion::ToRotationMatrix (Matrix3& kRot) const
|
---|
| 94 | {
|
---|
| 95 | Real fTx = 2.0*x;
|
---|
| 96 | Real fTy = 2.0*y;
|
---|
| 97 | Real fTz = 2.0*z;
|
---|
| 98 | Real fTwx = fTx*w;
|
---|
| 99 | Real fTwy = fTy*w;
|
---|
| 100 | Real fTwz = fTz*w;
|
---|
| 101 | Real fTxx = fTx*x;
|
---|
| 102 | Real fTxy = fTy*x;
|
---|
| 103 | Real fTxz = fTz*x;
|
---|
| 104 | Real fTyy = fTy*y;
|
---|
| 105 | Real fTyz = fTz*y;
|
---|
| 106 | Real fTzz = fTz*z;
|
---|
| 107 |
|
---|
| 108 | kRot[0][0] = 1.0-(fTyy+fTzz);
|
---|
| 109 | kRot[0][1] = fTxy-fTwz;
|
---|
| 110 | kRot[0][2] = fTxz+fTwy;
|
---|
| 111 | kRot[1][0] = fTxy+fTwz;
|
---|
| 112 | kRot[1][1] = 1.0-(fTxx+fTzz);
|
---|
| 113 | kRot[1][2] = fTyz-fTwx;
|
---|
| 114 | kRot[2][0] = fTxz-fTwy;
|
---|
| 115 | kRot[2][1] = fTyz+fTwx;
|
---|
| 116 | kRot[2][2] = 1.0-(fTxx+fTyy);
|
---|
| 117 | }
|
---|
| 118 | //-----------------------------------------------------------------------
|
---|
| 119 | void Quaternion::FromAngleAxis (const Radian& rfAngle,
|
---|
| 120 | const Vector3& rkAxis)
|
---|
| 121 | {
|
---|
| 122 | // assert: axis[] is unit length
|
---|
| 123 | //
|
---|
| 124 | // The quaternion representing the rotation is
|
---|
| 125 | // q = cos(A/2)+sin(A/2)*(x*i+y*j+z*k)
|
---|
| 126 |
|
---|
| 127 | Radian fHalfAngle ( 0.5*rfAngle );
|
---|
| 128 | Real fSin = Math::Sin(fHalfAngle);
|
---|
| 129 | w = Math::Cos(fHalfAngle);
|
---|
| 130 | x = fSin*rkAxis.x;
|
---|
| 131 | y = fSin*rkAxis.y;
|
---|
| 132 | z = fSin*rkAxis.z;
|
---|
| 133 | }
|
---|
| 134 | //-----------------------------------------------------------------------
|
---|
| 135 | void Quaternion::ToAngleAxis (Radian& rfAngle, Vector3& rkAxis) const
|
---|
| 136 | {
|
---|
| 137 | // The quaternion representing the rotation is
|
---|
| 138 | // q = cos(A/2)+sin(A/2)*(x*i+y*j+z*k)
|
---|
| 139 |
|
---|
| 140 | Real fSqrLength = x*x+y*y+z*z;
|
---|
| 141 | if ( fSqrLength > 0.0 )
|
---|
| 142 | {
|
---|
| 143 | rfAngle = 2.0*Math::ACos(w);
|
---|
| 144 | Real fInvLength = Math::InvSqrt(fSqrLength);
|
---|
| 145 | rkAxis.x = x*fInvLength;
|
---|
| 146 | rkAxis.y = y*fInvLength;
|
---|
| 147 | rkAxis.z = z*fInvLength;
|
---|
| 148 | }
|
---|
| 149 | else
|
---|
| 150 | {
|
---|
| 151 | // angle is 0 (mod 2*pi), so any axis will do
|
---|
| 152 | rfAngle = Radian(0.0);
|
---|
| 153 | rkAxis.x = 1.0;
|
---|
| 154 | rkAxis.y = 0.0;
|
---|
| 155 | rkAxis.z = 0.0;
|
---|
| 156 | }
|
---|
| 157 | }
|
---|
| 158 | //-----------------------------------------------------------------------
|
---|
| 159 | void Quaternion::FromAxes (const Vector3* akAxis)
|
---|
| 160 | {
|
---|
| 161 | Matrix3 kRot;
|
---|
| 162 |
|
---|
| 163 | for (size_t iCol = 0; iCol < 3; iCol++)
|
---|
| 164 | {
|
---|
| 165 | kRot[0][iCol] = akAxis[iCol].x;
|
---|
| 166 | kRot[1][iCol] = akAxis[iCol].y;
|
---|
| 167 | kRot[2][iCol] = akAxis[iCol].z;
|
---|
| 168 | }
|
---|
| 169 |
|
---|
| 170 | FromRotationMatrix(kRot);
|
---|
| 171 | }
|
---|
| 172 | //-----------------------------------------------------------------------
|
---|
| 173 | void Quaternion::FromAxes (const Vector3& xaxis, const Vector3& yaxis, const Vector3& zaxis)
|
---|
| 174 | {
|
---|
| 175 | Matrix3 kRot;
|
---|
| 176 |
|
---|
| 177 | kRot[0][0] = xaxis.x;
|
---|
| 178 | kRot[1][0] = xaxis.y;
|
---|
| 179 | kRot[2][0] = xaxis.z;
|
---|
| 180 |
|
---|
| 181 | kRot[0][1] = yaxis.x;
|
---|
| 182 | kRot[1][1] = yaxis.y;
|
---|
| 183 | kRot[2][1] = yaxis.z;
|
---|
| 184 |
|
---|
| 185 | kRot[0][2] = zaxis.x;
|
---|
| 186 | kRot[1][2] = zaxis.y;
|
---|
| 187 | kRot[2][2] = zaxis.z;
|
---|
| 188 |
|
---|
| 189 | FromRotationMatrix(kRot);
|
---|
| 190 |
|
---|
| 191 | }
|
---|
| 192 | //-----------------------------------------------------------------------
|
---|
| 193 | void Quaternion::ToAxes (Vector3* akAxis) const
|
---|
| 194 | {
|
---|
| 195 | Matrix3 kRot;
|
---|
| 196 |
|
---|
| 197 | ToRotationMatrix(kRot);
|
---|
| 198 |
|
---|
| 199 | for (size_t iCol = 0; iCol < 3; iCol++)
|
---|
| 200 | {
|
---|
| 201 | akAxis[iCol].x = kRot[0][iCol];
|
---|
| 202 | akAxis[iCol].y = kRot[1][iCol];
|
---|
| 203 | akAxis[iCol].z = kRot[2][iCol];
|
---|
| 204 | }
|
---|
| 205 | }
|
---|
| 206 | //-----------------------------------------------------------------------
|
---|
| 207 | Vector3 Quaternion::xAxis(void) const
|
---|
| 208 | {
|
---|
| 209 | //Real fTx = 2.0*x;
|
---|
| 210 | Real fTy = 2.0*y;
|
---|
| 211 | Real fTz = 2.0*z;
|
---|
| 212 | Real fTwy = fTy*w;
|
---|
| 213 | Real fTwz = fTz*w;
|
---|
| 214 | Real fTxy = fTy*x;
|
---|
| 215 | Real fTxz = fTz*x;
|
---|
| 216 | Real fTyy = fTy*y;
|
---|
| 217 | Real fTzz = fTz*z;
|
---|
| 218 |
|
---|
| 219 | return Vector3(1.0-(fTyy+fTzz), fTxy+fTwz, fTxz-fTwy);
|
---|
| 220 | }
|
---|
| 221 | //-----------------------------------------------------------------------
|
---|
| 222 | Vector3 Quaternion::yAxis(void) const
|
---|
| 223 | {
|
---|
| 224 | Real fTx = 2.0*x;
|
---|
| 225 | Real fTy = 2.0*y;
|
---|
| 226 | Real fTz = 2.0*z;
|
---|
| 227 | Real fTwx = fTx*w;
|
---|
| 228 | Real fTwz = fTz*w;
|
---|
| 229 | Real fTxx = fTx*x;
|
---|
| 230 | Real fTxy = fTy*x;
|
---|
| 231 | Real fTyz = fTz*y;
|
---|
| 232 | Real fTzz = fTz*z;
|
---|
| 233 |
|
---|
| 234 | return Vector3(fTxy-fTwz, 1.0-(fTxx+fTzz), fTyz+fTwx);
|
---|
| 235 | }
|
---|
| 236 | //-----------------------------------------------------------------------
|
---|
| 237 | Vector3 Quaternion::zAxis(void) const
|
---|
| 238 | {
|
---|
| 239 | Real fTx = 2.0*x;
|
---|
| 240 | Real fTy = 2.0*y;
|
---|
| 241 | Real fTz = 2.0*z;
|
---|
| 242 | Real fTwx = fTx*w;
|
---|
| 243 | Real fTwy = fTy*w;
|
---|
| 244 | Real fTxx = fTx*x;
|
---|
| 245 | Real fTxz = fTz*x;
|
---|
| 246 | Real fTyy = fTy*y;
|
---|
| 247 | Real fTyz = fTz*y;
|
---|
| 248 |
|
---|
| 249 | return Vector3(fTxz+fTwy, fTyz-fTwx, 1.0-(fTxx+fTyy));
|
---|
| 250 | }
|
---|
| 251 | //-----------------------------------------------------------------------
|
---|
| 252 | void Quaternion::ToAxes (Vector3& xaxis, Vector3& yaxis, Vector3& zaxis) const
|
---|
| 253 | {
|
---|
| 254 | Matrix3 kRot;
|
---|
| 255 |
|
---|
| 256 | ToRotationMatrix(kRot);
|
---|
| 257 |
|
---|
| 258 | xaxis.x = kRot[0][0];
|
---|
| 259 | xaxis.y = kRot[1][0];
|
---|
| 260 | xaxis.z = kRot[2][0];
|
---|
| 261 |
|
---|
| 262 | yaxis.x = kRot[0][1];
|
---|
| 263 | yaxis.y = kRot[1][1];
|
---|
| 264 | yaxis.z = kRot[2][1];
|
---|
| 265 |
|
---|
| 266 | zaxis.x = kRot[0][2];
|
---|
| 267 | zaxis.y = kRot[1][2];
|
---|
| 268 | zaxis.z = kRot[2][2];
|
---|
| 269 | }
|
---|
| 270 |
|
---|
| 271 | //-----------------------------------------------------------------------
|
---|
| 272 | Quaternion Quaternion::operator+ (const Quaternion& rkQ) const
|
---|
| 273 | {
|
---|
| 274 | return Quaternion(w+rkQ.w,x+rkQ.x,y+rkQ.y,z+rkQ.z);
|
---|
| 275 | }
|
---|
| 276 | //-----------------------------------------------------------------------
|
---|
| 277 | Quaternion Quaternion::operator- (const Quaternion& rkQ) const
|
---|
| 278 | {
|
---|
| 279 | return Quaternion(w-rkQ.w,x-rkQ.x,y-rkQ.y,z-rkQ.z);
|
---|
| 280 | }
|
---|
| 281 | //-----------------------------------------------------------------------
|
---|
| 282 | Quaternion Quaternion::operator* (const Quaternion& rkQ) const
|
---|
| 283 | {
|
---|
| 284 | // NOTE: Multiplication is not generally commutative, so in most
|
---|
| 285 | // cases p*q != q*p.
|
---|
| 286 |
|
---|
| 287 | return Quaternion
|
---|
| 288 | (
|
---|
| 289 | w * rkQ.w - x * rkQ.x - y * rkQ.y - z * rkQ.z,
|
---|
| 290 | w * rkQ.x + x * rkQ.w + y * rkQ.z - z * rkQ.y,
|
---|
| 291 | w * rkQ.y + y * rkQ.w + z * rkQ.x - x * rkQ.z,
|
---|
| 292 | w * rkQ.z + z * rkQ.w + x * rkQ.y - y * rkQ.x
|
---|
| 293 | );
|
---|
| 294 | }
|
---|
| 295 | //-----------------------------------------------------------------------
|
---|
| 296 | Quaternion Quaternion::operator* (Real fScalar) const
|
---|
| 297 | {
|
---|
| 298 | return Quaternion(fScalar*w,fScalar*x,fScalar*y,fScalar*z);
|
---|
| 299 | }
|
---|
| 300 | //-----------------------------------------------------------------------
|
---|
| 301 | Quaternion operator* (Real fScalar, const Quaternion& rkQ)
|
---|
| 302 | {
|
---|
| 303 | return Quaternion(fScalar*rkQ.w,fScalar*rkQ.x,fScalar*rkQ.y,
|
---|
| 304 | fScalar*rkQ.z);
|
---|
| 305 | }
|
---|
| 306 | //-----------------------------------------------------------------------
|
---|
| 307 | Quaternion Quaternion::operator- () const
|
---|
| 308 | {
|
---|
| 309 | return Quaternion(-w,-x,-y,-z);
|
---|
| 310 | }
|
---|
| 311 | //-----------------------------------------------------------------------
|
---|
| 312 | Real Quaternion::Dot (const Quaternion& rkQ) const
|
---|
| 313 | {
|
---|
| 314 | return w*rkQ.w+x*rkQ.x+y*rkQ.y+z*rkQ.z;
|
---|
| 315 | }
|
---|
| 316 | //-----------------------------------------------------------------------
|
---|
| 317 | Real Quaternion::Norm () const
|
---|
| 318 | {
|
---|
| 319 | return w*w+x*x+y*y+z*z;
|
---|
| 320 | }
|
---|
| 321 | //-----------------------------------------------------------------------
|
---|
| 322 | Quaternion Quaternion::Inverse () const
|
---|
| 323 | {
|
---|
| 324 | Real fNorm = w*w+x*x+y*y+z*z;
|
---|
| 325 | if ( fNorm > 0.0 )
|
---|
| 326 | {
|
---|
| 327 | Real fInvNorm = 1.0/fNorm;
|
---|
| 328 | return Quaternion(w*fInvNorm,-x*fInvNorm,-y*fInvNorm,-z*fInvNorm);
|
---|
| 329 | }
|
---|
| 330 | else
|
---|
| 331 | {
|
---|
| 332 | // return an invalid result to flag the error
|
---|
| 333 | return ZERO;
|
---|
| 334 | }
|
---|
| 335 | }
|
---|
| 336 | //-----------------------------------------------------------------------
|
---|
| 337 | Quaternion Quaternion::UnitInverse () const
|
---|
| 338 | {
|
---|
| 339 | // assert: 'this' is unit length
|
---|
| 340 | return Quaternion(w,-x,-y,-z);
|
---|
| 341 | }
|
---|
| 342 | //-----------------------------------------------------------------------
|
---|
| 343 | Quaternion Quaternion::Exp () const
|
---|
| 344 | {
|
---|
| 345 | // If q = A*(x*i+y*j+z*k) where (x,y,z) is unit length, then
|
---|
| 346 | // exp(q) = cos(A)+sin(A)*(x*i+y*j+z*k). If sin(A) is near zero,
|
---|
| 347 | // use exp(q) = cos(A)+A*(x*i+y*j+z*k) since A/sin(A) has limit 1.
|
---|
| 348 |
|
---|
| 349 | Radian fAngle ( Math::Sqrt(x*x+y*y+z*z) );
|
---|
| 350 | Real fSin = Math::Sin(fAngle);
|
---|
| 351 |
|
---|
| 352 | Quaternion kResult;
|
---|
| 353 | kResult.w = Math::Cos(fAngle);
|
---|
| 354 |
|
---|
| 355 | if ( Math::Abs(fSin) >= ms_fEpsilon )
|
---|
| 356 | {
|
---|
| 357 | Real fCoeff = fSin/(fAngle.valueRadians());
|
---|
| 358 | kResult.x = fCoeff*x;
|
---|
| 359 | kResult.y = fCoeff*y;
|
---|
| 360 | kResult.z = fCoeff*z;
|
---|
| 361 | }
|
---|
| 362 | else
|
---|
| 363 | {
|
---|
| 364 | kResult.x = x;
|
---|
| 365 | kResult.y = y;
|
---|
| 366 | kResult.z = z;
|
---|
| 367 | }
|
---|
| 368 |
|
---|
| 369 | return kResult;
|
---|
| 370 | }
|
---|
| 371 | //-----------------------------------------------------------------------
|
---|
| 372 | Quaternion Quaternion::Log () const
|
---|
| 373 | {
|
---|
| 374 | // If q = cos(A)+sin(A)*(x*i+y*j+z*k) where (x,y,z) is unit length, then
|
---|
| 375 | // log(q) = A*(x*i+y*j+z*k). If sin(A) is near zero, use log(q) =
|
---|
| 376 | // sin(A)*(x*i+y*j+z*k) since sin(A)/A has limit 1.
|
---|
| 377 |
|
---|
| 378 | Quaternion kResult;
|
---|
| 379 | kResult.w = 0.0;
|
---|
| 380 |
|
---|
| 381 | if ( Math::Abs(w) < 1.0 )
|
---|
| 382 | {
|
---|
| 383 | Radian fAngle ( Math::ACos(w) );
|
---|
| 384 | Real fSin = Math::Sin(fAngle);
|
---|
| 385 | if ( Math::Abs(fSin) >= ms_fEpsilon )
|
---|
| 386 | {
|
---|
| 387 | Real fCoeff = fAngle.valueRadians()/fSin;
|
---|
| 388 | kResult.x = fCoeff*x;
|
---|
| 389 | kResult.y = fCoeff*y;
|
---|
| 390 | kResult.z = fCoeff*z;
|
---|
| 391 | return kResult;
|
---|
| 392 | }
|
---|
| 393 | }
|
---|
| 394 |
|
---|
| 395 | kResult.x = x;
|
---|
| 396 | kResult.y = y;
|
---|
| 397 | kResult.z = z;
|
---|
| 398 |
|
---|
| 399 | return kResult;
|
---|
| 400 | }
|
---|
| 401 | //-----------------------------------------------------------------------
|
---|
| 402 | Vector3 Quaternion::operator* (const Vector3& v) const
|
---|
| 403 | {
|
---|
| 404 | // nVidia SDK implementation
|
---|
| 405 | Vector3 uv, uuv;
|
---|
| 406 | Vector3 qvec(x, y, z);
|
---|
| 407 | uv = qvec.crossProduct(v);
|
---|
| 408 | uuv = qvec.crossProduct(uv);
|
---|
| 409 | uv *= (2.0f * w);
|
---|
| 410 | uuv *= 2.0f;
|
---|
| 411 |
|
---|
| 412 | return v + uv + uuv;
|
---|
| 413 |
|
---|
| 414 | }
|
---|
| 415 | //-----------------------------------------------------------------------
|
---|
| 416 | bool Quaternion::equals(const Quaternion& rhs, const Radian& tolerance) const
|
---|
| 417 | {
|
---|
| 418 | Real fCos = Dot(rhs);
|
---|
| 419 | Radian angle = Math::ACos(fCos);
|
---|
| 420 |
|
---|
| 421 | return (Math::Abs(angle.valueRadians()) <= tolerance.valueRadians())
|
---|
| 422 | || Math::RealEqual(angle.valueRadians(), Math::PI, tolerance.valueRadians());
|
---|
| 423 |
|
---|
| 424 |
|
---|
| 425 | }
|
---|
| 426 | //-----------------------------------------------------------------------
|
---|
| 427 | Quaternion Quaternion::Slerp (Real fT, const Quaternion& rkP,
|
---|
| 428 | const Quaternion& rkQ, bool shortestPath)
|
---|
| 429 | {
|
---|
| 430 | Real fCos = rkP.Dot(rkQ);
|
---|
| 431 | Radian fAngle ( Math::ACos(fCos) );
|
---|
| 432 |
|
---|
| 433 | if ( Math::Abs(fAngle.valueRadians()) < ms_fEpsilon )
|
---|
| 434 | return rkP;
|
---|
| 435 |
|
---|
| 436 | Real fSin = Math::Sin(fAngle);
|
---|
| 437 | Real fInvSin = 1.0/fSin;
|
---|
| 438 | Real fCoeff0 = Math::Sin((1.0-fT)*fAngle)*fInvSin;
|
---|
| 439 | Real fCoeff1 = Math::Sin(fT*fAngle)*fInvSin;
|
---|
| 440 | // Do we need to invert rotation?
|
---|
| 441 | if (fCos < 0.0f && shortestPath)
|
---|
| 442 | {
|
---|
| 443 | fCoeff0 = -fCoeff0;
|
---|
| 444 | // taking the complement requires renormalisation
|
---|
| 445 | Quaternion t(fCoeff0*rkP + fCoeff1*rkQ);
|
---|
| 446 | t.normalise();
|
---|
| 447 | return t;
|
---|
| 448 | }
|
---|
| 449 | else
|
---|
| 450 | {
|
---|
| 451 | return fCoeff0*rkP + fCoeff1*rkQ;
|
---|
| 452 | }
|
---|
| 453 | }
|
---|
| 454 | //-----------------------------------------------------------------------
|
---|
| 455 | Quaternion Quaternion::SlerpExtraSpins (Real fT,
|
---|
| 456 | const Quaternion& rkP, const Quaternion& rkQ, int iExtraSpins)
|
---|
| 457 | {
|
---|
| 458 | Real fCos = rkP.Dot(rkQ);
|
---|
| 459 | Radian fAngle ( Math::ACos(fCos) );
|
---|
| 460 |
|
---|
| 461 | if ( Math::Abs(fAngle.valueRadians()) < ms_fEpsilon )
|
---|
| 462 | return rkP;
|
---|
| 463 |
|
---|
| 464 | Real fSin = Math::Sin(fAngle);
|
---|
| 465 | Radian fPhase ( Math::PI*iExtraSpins*fT );
|
---|
| 466 | Real fInvSin = 1.0/fSin;
|
---|
| 467 | Real fCoeff0 = Math::Sin((1.0-fT)*fAngle - fPhase)*fInvSin;
|
---|
| 468 | Real fCoeff1 = Math::Sin(fT*fAngle + fPhase)*fInvSin;
|
---|
| 469 | return fCoeff0*rkP + fCoeff1*rkQ;
|
---|
| 470 | }
|
---|
| 471 | //-----------------------------------------------------------------------
|
---|
| 472 | void Quaternion::Intermediate (const Quaternion& rkQ0,
|
---|
| 473 | const Quaternion& rkQ1, const Quaternion& rkQ2,
|
---|
| 474 | Quaternion& rkA, Quaternion& rkB)
|
---|
| 475 | {
|
---|
| 476 | // assert: q0, q1, q2 are unit quaternions
|
---|
| 477 |
|
---|
| 478 | Quaternion kQ0inv = rkQ0.UnitInverse();
|
---|
| 479 | Quaternion kQ1inv = rkQ1.UnitInverse();
|
---|
| 480 | Quaternion rkP0 = kQ0inv*rkQ1;
|
---|
| 481 | Quaternion rkP1 = kQ1inv*rkQ2;
|
---|
| 482 | Quaternion kArg = 0.25*(rkP0.Log()-rkP1.Log());
|
---|
| 483 | Quaternion kMinusArg = -kArg;
|
---|
| 484 |
|
---|
| 485 | rkA = rkQ1*kArg.Exp();
|
---|
| 486 | rkB = rkQ1*kMinusArg.Exp();
|
---|
| 487 | }
|
---|
| 488 | //-----------------------------------------------------------------------
|
---|
| 489 | Quaternion Quaternion::Squad (Real fT,
|
---|
| 490 | const Quaternion& rkP, const Quaternion& rkA,
|
---|
| 491 | const Quaternion& rkB, const Quaternion& rkQ, bool shortestPath)
|
---|
| 492 | {
|
---|
| 493 | Real fSlerpT = 2.0*fT*(1.0-fT);
|
---|
| 494 | Quaternion kSlerpP = Slerp(fT, rkP, rkQ, shortestPath);
|
---|
| 495 | Quaternion kSlerpQ = Slerp(fT, rkA, rkB);
|
---|
| 496 | return Slerp(fSlerpT, kSlerpP ,kSlerpQ);
|
---|
| 497 | }
|
---|
| 498 | //-----------------------------------------------------------------------
|
---|
| 499 | Real Quaternion::normalise(void)
|
---|
| 500 | {
|
---|
| 501 | Real len = Norm();
|
---|
| 502 | Real factor = 1.0f / Math::Sqrt(len);
|
---|
| 503 | *this = *this * factor;
|
---|
| 504 | return len;
|
---|
| 505 | }
|
---|
| 506 | //-----------------------------------------------------------------------
|
---|
| 507 | Radian Quaternion::getRoll(void) const
|
---|
| 508 | {
|
---|
| 509 | return Radian(Math::ATan2(2*(x*y + w*z), w*w + x*x - y*y - z*z));
|
---|
| 510 | }
|
---|
| 511 | //-----------------------------------------------------------------------
|
---|
| 512 | Radian Quaternion::getPitch(void) const
|
---|
| 513 | {
|
---|
| 514 | return Radian(Math::ATan2(2*(y*z + w*x), w*w - x*x - y*y + z*z));
|
---|
| 515 | }
|
---|
| 516 | //-----------------------------------------------------------------------
|
---|
| 517 | Radian Quaternion::getYaw(void) const
|
---|
| 518 | {
|
---|
| 519 | return Radian(Math::ASin(-2*(x*z - w*y)));
|
---|
| 520 | }
|
---|
| 521 | //-----------------------------------------------------------------------
|
---|
| 522 | Quaternion Quaternion::nlerp(Real fT, const Quaternion& rkP,
|
---|
| 523 | const Quaternion& rkQ, bool shortestPath)
|
---|
| 524 | {
|
---|
| 525 | Quaternion result;
|
---|
| 526 | Real fCos = rkP.Dot(rkQ);
|
---|
| 527 | if (fCos < 0.0f && shortestPath)
|
---|
| 528 | {
|
---|
| 529 | result = rkP + fT * ((-rkQ) - rkP);
|
---|
| 530 | }
|
---|
| 531 | else
|
---|
| 532 | {
|
---|
| 533 | result = rkP + fT * (rkQ - rkP);
|
---|
| 534 | }
|
---|
| 535 | result.normalise();
|
---|
| 536 | return result;
|
---|
| 537 | }
|
---|
| 538 | }
|
---|