/src/ogre/OgreMain/src/OgreQuaternion.cpp
Line | Count | Source |
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-2014 Torus Knot Software Ltd |
8 | | |
9 | | Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | | of this software and associated documentation files (the "Software"), to deal |
11 | | in the Software without restriction, including without limitation the rights |
12 | | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
13 | | copies of the Software, and to permit persons to whom the Software is |
14 | | furnished to do so, subject to the following conditions: |
15 | | |
16 | | The above copyright notice and this permission notice shall be included in |
17 | | all copies or substantial portions of the Software. |
18 | | |
19 | | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
20 | | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
21 | | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
22 | | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
23 | | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
24 | | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
25 | | THE SOFTWARE. |
26 | | ----------------------------------------------------------------------------- |
27 | | */ |
28 | | #include "OgreStableHeaders.h" |
29 | | // NOTE THAT THIS FILE IS BASED ON MATERIAL FROM: |
30 | | |
31 | | // Geometric Tools, LLC |
32 | | // Copyright (c) 1998-2010 |
33 | | // Distributed under the Boost Software License, Version 1.0. |
34 | | // http://www.boost.org/LICENSE_1_0.txt |
35 | | // http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt |
36 | | |
37 | | namespace Ogre { |
38 | | |
39 | | const Real Quaternion::msEpsilon = 1e-03; |
40 | | const Quaternion Quaternion::ZERO(0,0,0,0); |
41 | | const Quaternion Quaternion::IDENTITY(1,0,0,0); |
42 | | |
43 | | //----------------------------------------------------------------------- |
44 | | void Quaternion::FromRotationMatrix (const Matrix3& kRot) |
45 | 0 | { |
46 | | // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes |
47 | | // article "Quaternion Calculus and Fast Animation". |
48 | |
|
49 | 0 | Real fTrace = kRot[0][0]+kRot[1][1]+kRot[2][2]; |
50 | 0 | Real fRoot; |
51 | |
|
52 | 0 | if ( fTrace > 0.0 ) |
53 | 0 | { |
54 | | // |w| > 1/2, may as well choose w > 1/2 |
55 | 0 | fRoot = Math::Sqrt(fTrace + 1.0f); // 2w |
56 | 0 | w = 0.5f*fRoot; |
57 | 0 | fRoot = 0.5f/fRoot; // 1/(4w) |
58 | 0 | x = (kRot[2][1]-kRot[1][2])*fRoot; |
59 | 0 | y = (kRot[0][2]-kRot[2][0])*fRoot; |
60 | 0 | z = (kRot[1][0]-kRot[0][1])*fRoot; |
61 | 0 | } |
62 | 0 | else |
63 | 0 | { |
64 | | // |w| <= 1/2 |
65 | 0 | static size_t s_iNext[3] = { 1, 2, 0 }; |
66 | 0 | size_t i = 0; |
67 | 0 | if ( kRot[1][1] > kRot[0][0] ) |
68 | 0 | i = 1; |
69 | 0 | if ( kRot[2][2] > kRot[i][i] ) |
70 | 0 | i = 2; |
71 | 0 | size_t j = s_iNext[i]; |
72 | 0 | size_t k = s_iNext[j]; |
73 | |
|
74 | 0 | fRoot = Math::Sqrt(kRot[i][i]-kRot[j][j]-kRot[k][k] + 1.0f); |
75 | 0 | Real* apkQuat[3] = { &x, &y, &z }; |
76 | 0 | *apkQuat[i] = 0.5f*fRoot; |
77 | 0 | fRoot = 0.5f/fRoot; |
78 | 0 | w = (kRot[k][j]-kRot[j][k])*fRoot; |
79 | 0 | *apkQuat[j] = (kRot[j][i]+kRot[i][j])*fRoot; |
80 | 0 | *apkQuat[k] = (kRot[k][i]+kRot[i][k])*fRoot; |
81 | 0 | } |
82 | 0 | } |
83 | | //----------------------------------------------------------------------- |
84 | | void Quaternion::ToRotationMatrix (Matrix3& kRot) const |
85 | 0 | { |
86 | 0 | Real fTx = x+x; |
87 | 0 | Real fTy = y+y; |
88 | 0 | Real fTz = z+z; |
89 | 0 | Real fTwx = fTx*w; |
90 | 0 | Real fTwy = fTy*w; |
91 | 0 | Real fTwz = fTz*w; |
92 | 0 | Real fTxx = fTx*x; |
93 | 0 | Real fTxy = fTy*x; |
94 | 0 | Real fTxz = fTz*x; |
95 | 0 | Real fTyy = fTy*y; |
96 | 0 | Real fTyz = fTz*y; |
97 | 0 | Real fTzz = fTz*z; |
98 | |
|
99 | 0 | kRot[0][0] = 1.0f-(fTyy+fTzz); |
100 | 0 | kRot[0][1] = fTxy-fTwz; |
101 | 0 | kRot[0][2] = fTxz+fTwy; |
102 | 0 | kRot[1][0] = fTxy+fTwz; |
103 | 0 | kRot[1][1] = 1.0f-(fTxx+fTzz); |
104 | 0 | kRot[1][2] = fTyz-fTwx; |
105 | 0 | kRot[2][0] = fTxz-fTwy; |
106 | 0 | kRot[2][1] = fTyz+fTwx; |
107 | 0 | kRot[2][2] = 1.0f-(fTxx+fTyy); |
108 | 0 | } |
109 | | //----------------------------------------------------------------------- |
110 | | void Quaternion::FromAngleAxis (const Radian& rfAngle, |
111 | | const Vector3& rkAxis) |
112 | 0 | { |
113 | | // assert: axis[] is unit length |
114 | | // |
115 | | // The quaternion representing the rotation is |
116 | | // q = cos(A/2)+sin(A/2)*(x*i+y*j+z*k) |
117 | |
|
118 | 0 | Radian fHalfAngle ( 0.5*rfAngle ); |
119 | 0 | Real fSin = Math::Sin(fHalfAngle); |
120 | 0 | w = Math::Cos(fHalfAngle); |
121 | 0 | x = fSin*rkAxis.x; |
122 | 0 | y = fSin*rkAxis.y; |
123 | 0 | z = fSin*rkAxis.z; |
124 | 0 | } |
125 | | //----------------------------------------------------------------------- |
126 | | void Quaternion::ToAngleAxis (Radian& rfAngle, Vector3& rkAxis) const |
127 | 0 | { |
128 | | // The quaternion representing the rotation is |
129 | | // q = cos(A/2)+sin(A/2)*(x*i+y*j+z*k) |
130 | |
|
131 | 0 | Real fSqrLength = x*x+y*y+z*z; |
132 | 0 | if ( fSqrLength > 0.0 ) |
133 | 0 | { |
134 | 0 | rfAngle = 2.0*Math::ACos(w); |
135 | 0 | Real fInvLength = Math::InvSqrt(fSqrLength); |
136 | 0 | rkAxis.x = x*fInvLength; |
137 | 0 | rkAxis.y = y*fInvLength; |
138 | 0 | rkAxis.z = z*fInvLength; |
139 | 0 | } |
140 | 0 | else |
141 | 0 | { |
142 | | // angle is 0 (mod 2*pi), so any axis will do |
143 | 0 | rfAngle = Radian(0.0); |
144 | 0 | rkAxis.x = 1.0; |
145 | 0 | rkAxis.y = 0.0; |
146 | 0 | rkAxis.z = 0.0; |
147 | 0 | } |
148 | 0 | } |
149 | | //----------------------------------------------------------------------- |
150 | | void Quaternion::FromAxes (const Vector3* akAxis) |
151 | 0 | { |
152 | 0 | Matrix3 kRot; |
153 | |
|
154 | 0 | for (size_t iCol = 0; iCol < 3; iCol++) |
155 | 0 | { |
156 | 0 | kRot[0][iCol] = akAxis[iCol].x; |
157 | 0 | kRot[1][iCol] = akAxis[iCol].y; |
158 | 0 | kRot[2][iCol] = akAxis[iCol].z; |
159 | 0 | } |
160 | |
|
161 | 0 | FromRotationMatrix(kRot); |
162 | 0 | } |
163 | | //----------------------------------------------------------------------- |
164 | | void Quaternion::FromAxes (const Vector3& xaxis, const Vector3& yaxis, const Vector3& zaxis) |
165 | 0 | { |
166 | 0 | Matrix3 kRot; |
167 | 0 | kRot.FromAxes(xaxis, yaxis, zaxis); |
168 | 0 | FromRotationMatrix(kRot); |
169 | 0 | } |
170 | | //----------------------------------------------------------------------- |
171 | | void Quaternion::ToAxes (Vector3* akAxis) const |
172 | 0 | { |
173 | 0 | Matrix3 kRot; |
174 | |
|
175 | 0 | ToRotationMatrix(kRot); |
176 | |
|
177 | 0 | for (size_t iCol = 0; iCol < 3; iCol++) |
178 | 0 | { |
179 | 0 | akAxis[iCol].x = kRot[0][iCol]; |
180 | 0 | akAxis[iCol].y = kRot[1][iCol]; |
181 | 0 | akAxis[iCol].z = kRot[2][iCol]; |
182 | 0 | } |
183 | 0 | } |
184 | | //----------------------------------------------------------------------- |
185 | | Vector3 Quaternion::xAxis(void) const |
186 | 0 | { |
187 | | //Real fTx = 2.0*x; |
188 | 0 | Real fTy = 2.0f*y; |
189 | 0 | Real fTz = 2.0f*z; |
190 | 0 | Real fTwy = fTy*w; |
191 | 0 | Real fTwz = fTz*w; |
192 | 0 | Real fTxy = fTy*x; |
193 | 0 | Real fTxz = fTz*x; |
194 | 0 | Real fTyy = fTy*y; |
195 | 0 | Real fTzz = fTz*z; |
196 | |
|
197 | 0 | return Vector3(1.0f-(fTyy+fTzz), fTxy+fTwz, fTxz-fTwy); |
198 | 0 | } |
199 | | //----------------------------------------------------------------------- |
200 | | Vector3 Quaternion::yAxis(void) const |
201 | 0 | { |
202 | 0 | Real fTx = 2.0f*x; |
203 | 0 | Real fTy = 2.0f*y; |
204 | 0 | Real fTz = 2.0f*z; |
205 | 0 | Real fTwx = fTx*w; |
206 | 0 | Real fTwz = fTz*w; |
207 | 0 | Real fTxx = fTx*x; |
208 | 0 | Real fTxy = fTy*x; |
209 | 0 | Real fTyz = fTz*y; |
210 | 0 | Real fTzz = fTz*z; |
211 | |
|
212 | 0 | return Vector3(fTxy-fTwz, 1.0f-(fTxx+fTzz), fTyz+fTwx); |
213 | 0 | } |
214 | | //----------------------------------------------------------------------- |
215 | | Vector3 Quaternion::zAxis(void) const |
216 | 0 | { |
217 | 0 | Real fTx = 2.0f*x; |
218 | 0 | Real fTy = 2.0f*y; |
219 | 0 | Real fTz = 2.0f*z; |
220 | 0 | Real fTwx = fTx*w; |
221 | 0 | Real fTwy = fTy*w; |
222 | 0 | Real fTxx = fTx*x; |
223 | 0 | Real fTxz = fTz*x; |
224 | 0 | Real fTyy = fTy*y; |
225 | 0 | Real fTyz = fTz*y; |
226 | |
|
227 | 0 | return Vector3(fTxz+fTwy, fTyz-fTwx, 1.0f-(fTxx+fTyy)); |
228 | 0 | } |
229 | | //----------------------------------------------------------------------- |
230 | | void Quaternion::ToAxes (Vector3& xaxis, Vector3& yaxis, Vector3& zaxis) const |
231 | 0 | { |
232 | 0 | Matrix3 kRot; |
233 | |
|
234 | 0 | ToRotationMatrix(kRot); |
235 | |
|
236 | 0 | xaxis.x = kRot[0][0]; |
237 | 0 | xaxis.y = kRot[1][0]; |
238 | 0 | xaxis.z = kRot[2][0]; |
239 | |
|
240 | 0 | yaxis.x = kRot[0][1]; |
241 | 0 | yaxis.y = kRot[1][1]; |
242 | 0 | yaxis.z = kRot[2][1]; |
243 | |
|
244 | 0 | zaxis.x = kRot[0][2]; |
245 | 0 | zaxis.y = kRot[1][2]; |
246 | 0 | zaxis.z = kRot[2][2]; |
247 | 0 | } |
248 | | |
249 | | //----------------------------------------------------------------------- |
250 | | Quaternion Quaternion::operator+ (const Quaternion& rkQ) const |
251 | 0 | { |
252 | 0 | return Quaternion(w+rkQ.w,x+rkQ.x,y+rkQ.y,z+rkQ.z); |
253 | 0 | } |
254 | | //----------------------------------------------------------------------- |
255 | | Quaternion Quaternion::operator- (const Quaternion& rkQ) const |
256 | 0 | { |
257 | 0 | return Quaternion(w-rkQ.w,x-rkQ.x,y-rkQ.y,z-rkQ.z); |
258 | 0 | } |
259 | | //----------------------------------------------------------------------- |
260 | | Quaternion Quaternion::operator* (const Quaternion& rkQ) const |
261 | 3 | { |
262 | | // NOTE: Multiplication is not generally commutative, so in most |
263 | | // cases p*q != q*p. |
264 | | |
265 | 3 | return Quaternion |
266 | 3 | ( |
267 | 3 | w * rkQ.w - x * rkQ.x - y * rkQ.y - z * rkQ.z, |
268 | 3 | w * rkQ.x + x * rkQ.w + y * rkQ.z - z * rkQ.y, |
269 | 3 | w * rkQ.y + y * rkQ.w + z * rkQ.x - x * rkQ.z, |
270 | 3 | w * rkQ.z + z * rkQ.w + x * rkQ.y - y * rkQ.x |
271 | 3 | ); |
272 | 3 | } |
273 | | //----------------------------------------------------------------------- |
274 | | Quaternion Quaternion::Inverse () const |
275 | 578 | { |
276 | 578 | Real fNorm = w*w+x*x+y*y+z*z; |
277 | 578 | if ( fNorm > 0.0 ) |
278 | 173 | { |
279 | 173 | Real fInvNorm = 1.0f/fNorm; |
280 | 173 | return Quaternion(w*fInvNorm,-x*fInvNorm,-y*fInvNorm,-z*fInvNorm); |
281 | 173 | } |
282 | 405 | else |
283 | 405 | { |
284 | | // return an invalid result to flag the error |
285 | 405 | return ZERO; |
286 | 405 | } |
287 | 578 | } |
288 | | //----------------------------------------------------------------------- |
289 | | Quaternion Quaternion::UnitInverse () const |
290 | 0 | { |
291 | | // assert: 'this' is unit length |
292 | 0 | return Quaternion(w,-x,-y,-z); |
293 | 0 | } |
294 | | //----------------------------------------------------------------------- |
295 | | Quaternion Quaternion::Exp () const |
296 | 0 | { |
297 | | // If q = A*(x*i+y*j+z*k) where (x,y,z) is unit length, then |
298 | | // exp(q) = e^w(cos(A)+sin(A)*(x*i+y*j+z*k)). If sin(A) is near zero, |
299 | | // use exp(q) = e^w(cos(A)+(x*i+y*j+z*k)) since sin(A)/A has limit 1. |
300 | |
|
301 | 0 | Radian fAngle ( Math::Sqrt(x*x+y*y+z*z) ); |
302 | 0 | Real fSin = Math::Sin(fAngle); |
303 | 0 | Real fExpW = Math::Exp(w); |
304 | |
|
305 | 0 | Quaternion kResult; |
306 | 0 | kResult.w = fExpW*Math::Cos(fAngle); |
307 | |
|
308 | 0 | if ( Math::Abs(fAngle.valueRadians()) >= msEpsilon ) |
309 | 0 | { |
310 | 0 | Real fCoeff = fExpW*(fSin/(fAngle.valueRadians())); |
311 | 0 | kResult.x = fCoeff*x; |
312 | 0 | kResult.y = fCoeff*y; |
313 | 0 | kResult.z = fCoeff*z; |
314 | 0 | } |
315 | 0 | else |
316 | 0 | { |
317 | 0 | kResult.x = fExpW*x; |
318 | 0 | kResult.y = fExpW*y; |
319 | 0 | kResult.z = fExpW*z; |
320 | 0 | } |
321 | |
|
322 | 0 | return kResult; |
323 | 0 | } |
324 | | //----------------------------------------------------------------------- |
325 | | Quaternion Quaternion::Log () const |
326 | 0 | { |
327 | | // If q = cos(A)+sin(A)*(x*i+y*j+z*k) where (x,y,z) is unit length, then |
328 | | // log(q) = (A/sin(A))*(x*i+y*j+z*k). If sin(A) is near zero, use |
329 | | // log(q) = (x*i+y*j+z*k) since A/sin(A) has limit 1. |
330 | |
|
331 | 0 | Quaternion kResult; |
332 | 0 | kResult.w = 0.0; |
333 | |
|
334 | 0 | if ( Math::Abs(w) < 1.0 ) |
335 | 0 | { |
336 | | // According to Neil Dantam, atan2 has the best stability. |
337 | | // http://www.neil.dantam.name/note/dantam-quaternion.pdf |
338 | 0 | Real fNormV = Math::Sqrt(x*x + y*y + z*z); |
339 | 0 | Radian fAngle ( Math::ATan2(fNormV, w) ); |
340 | |
|
341 | 0 | Real fSin = Math::Sin(fAngle); |
342 | 0 | if ( Math::Abs(fSin) >= msEpsilon ) |
343 | 0 | { |
344 | 0 | Real fCoeff = fAngle.valueRadians()/fSin; |
345 | 0 | kResult.x = fCoeff*x; |
346 | 0 | kResult.y = fCoeff*y; |
347 | 0 | kResult.z = fCoeff*z; |
348 | 0 | return kResult; |
349 | 0 | } |
350 | 0 | } |
351 | | |
352 | 0 | kResult.x = x; |
353 | 0 | kResult.y = y; |
354 | 0 | kResult.z = z; |
355 | |
|
356 | 0 | return kResult; |
357 | 0 | } |
358 | | //----------------------------------------------------------------------- |
359 | | Vector3 Quaternion::operator* (const Vector3& v) const |
360 | 3 | { |
361 | | // nVidia SDK implementation |
362 | 3 | Vector3 uv, uuv; |
363 | 3 | Vector3 qvec(x, y, z); |
364 | 3 | uv = qvec.crossProduct(v); |
365 | 3 | uuv = qvec.crossProduct(uv); |
366 | 3 | uv *= (2.0f * w); |
367 | 3 | uuv *= 2.0f; |
368 | | |
369 | 3 | return v + uv + uuv; |
370 | | |
371 | 3 | } |
372 | | //----------------------------------------------------------------------- |
373 | | Quaternion Quaternion::Slerp (Real fT, const Quaternion& rkP, |
374 | | const Quaternion& rkQ, bool shortestPath) |
375 | 0 | { |
376 | 0 | Real fCos = rkP.Dot(rkQ); |
377 | 0 | Quaternion rkT; |
378 | | |
379 | | // Do we need to invert rotation? |
380 | 0 | if (fCos < 0.0f && shortestPath) |
381 | 0 | { |
382 | 0 | fCos = -fCos; |
383 | 0 | rkT = -rkQ; |
384 | 0 | } |
385 | 0 | else |
386 | 0 | { |
387 | 0 | rkT = rkQ; |
388 | 0 | } |
389 | |
|
390 | 0 | if (Math::Abs(fCos) < 1 - msEpsilon) |
391 | 0 | { |
392 | | // Standard case (slerp) |
393 | 0 | Real fSin = Math::Sqrt(1 - Math::Sqr(fCos)); |
394 | 0 | Radian fAngle = Math::ATan2(fSin, fCos); |
395 | 0 | Real fInvSin = 1.0f / fSin; |
396 | 0 | Real fCoeff0 = Math::Sin((1.0f - fT) * fAngle) * fInvSin; |
397 | 0 | Real fCoeff1 = Math::Sin(fT * fAngle) * fInvSin; |
398 | 0 | return fCoeff0 * rkP + fCoeff1 * rkT; |
399 | 0 | } |
400 | 0 | else |
401 | 0 | { |
402 | | // There are two situations: |
403 | | // 1. "rkP" and "rkQ" are very close (fCos ~= +1), so we can do a linear |
404 | | // interpolation safely. |
405 | | // 2. "rkP" and "rkQ" are almost inverse of each other (fCos ~= -1), there |
406 | | // are an infinite number of possibilities interpolation. but we haven't |
407 | | // have method to fix this case, so just use linear interpolation here. |
408 | 0 | Quaternion t = (1.0f - fT) * rkP + fT * rkT; |
409 | | // taking the complement requires renormalisation |
410 | 0 | t.normalise(); |
411 | 0 | return t; |
412 | 0 | } |
413 | 0 | } |
414 | | //----------------------------------------------------------------------- |
415 | | Quaternion Quaternion::SlerpExtraSpins (Real fT, |
416 | | const Quaternion& rkP, const Quaternion& rkQ, int iExtraSpins) |
417 | 0 | { |
418 | 0 | Real fCos = rkP.Dot(rkQ); |
419 | 0 | Radian fAngle ( Math::ACos(fCos) ); |
420 | |
|
421 | 0 | if ( Math::Abs(fAngle.valueRadians()) < msEpsilon ) |
422 | 0 | return rkP; |
423 | | |
424 | 0 | Real fSin = Math::Sin(fAngle); |
425 | 0 | Radian fPhase ( Math::PI*iExtraSpins*fT ); |
426 | 0 | Real fInvSin = 1.0f/fSin; |
427 | 0 | Real fCoeff0 = Math::Sin((1.0f-fT)*fAngle - fPhase)*fInvSin; |
428 | 0 | Real fCoeff1 = Math::Sin(fT*fAngle + fPhase)*fInvSin; |
429 | 0 | return fCoeff0*rkP + fCoeff1*rkQ; |
430 | 0 | } |
431 | | //----------------------------------------------------------------------- |
432 | | void Quaternion::Intermediate (const Quaternion& rkQ0, |
433 | | const Quaternion& rkQ1, const Quaternion& rkQ2, |
434 | | Quaternion& rkA, Quaternion& rkB) |
435 | 0 | { |
436 | | // assert: q0, q1, q2 are unit quaternions |
437 | |
|
438 | 0 | Quaternion kQ0inv = rkQ0.UnitInverse(); |
439 | 0 | Quaternion kQ1inv = rkQ1.UnitInverse(); |
440 | 0 | Quaternion rkP0 = kQ0inv*rkQ1; |
441 | 0 | Quaternion rkP1 = kQ1inv*rkQ2; |
442 | 0 | Quaternion kArg = 0.25*(rkP0.Log()-rkP1.Log()); |
443 | 0 | Quaternion kMinusArg = -kArg; |
444 | |
|
445 | 0 | rkA = rkQ1*kArg.Exp(); |
446 | 0 | rkB = rkQ1*kMinusArg.Exp(); |
447 | 0 | } |
448 | | //----------------------------------------------------------------------- |
449 | | Quaternion Quaternion::Squad (Real fT, |
450 | | const Quaternion& rkP, const Quaternion& rkA, |
451 | | const Quaternion& rkB, const Quaternion& rkQ, bool shortestPath) |
452 | 0 | { |
453 | 0 | Real fSlerpT = 2.0f*fT*(1.0f-fT); |
454 | 0 | Quaternion kSlerpP = Slerp(fT, rkP, rkQ, shortestPath); |
455 | 0 | Quaternion kSlerpQ = Slerp(fT, rkA, rkB); |
456 | 0 | return Slerp(fSlerpT, kSlerpP ,kSlerpQ); |
457 | 0 | } |
458 | | //----------------------------------------------------------------------- |
459 | | Radian Quaternion::getRoll(bool reprojectAxis) const |
460 | 0 | { |
461 | 0 | if (reprojectAxis) |
462 | 0 | { |
463 | | // roll = atan2(localx.y, localx.x) |
464 | | // pick parts of xAxis() implementation that we need |
465 | | // Real fTx = 2.0*x; |
466 | 0 | Real fTy = 2.0f*y; |
467 | 0 | Real fTz = 2.0f*z; |
468 | 0 | Real fTwz = fTz*w; |
469 | 0 | Real fTxy = fTy*x; |
470 | 0 | Real fTyy = fTy*y; |
471 | 0 | Real fTzz = fTz*z; |
472 | | |
473 | | // Vector3(1.0-(fTyy+fTzz), fTxy+fTwz, fTxz-fTwy); |
474 | |
|
475 | 0 | return Radian(Math::ATan2(fTxy+fTwz, 1.0f-(fTyy+fTzz))); |
476 | |
|
477 | 0 | } |
478 | 0 | else |
479 | 0 | { |
480 | 0 | return Radian(Math::ATan2(2*(x*y + w*z), w*w + x*x - y*y - z*z)); |
481 | 0 | } |
482 | 0 | } |
483 | | //----------------------------------------------------------------------- |
484 | | Radian Quaternion::getPitch(bool reprojectAxis) const |
485 | 0 | { |
486 | 0 | if (reprojectAxis) |
487 | 0 | { |
488 | | // pitch = atan2(localy.z, localy.y) |
489 | | // pick parts of yAxis() implementation that we need |
490 | 0 | Real fTx = 2.0f*x; |
491 | | // Real fTy = 2.0f*y; |
492 | 0 | Real fTz = 2.0f*z; |
493 | 0 | Real fTwx = fTx*w; |
494 | 0 | Real fTxx = fTx*x; |
495 | 0 | Real fTyz = fTz*y; |
496 | 0 | Real fTzz = fTz*z; |
497 | | |
498 | | // Vector3(fTxy-fTwz, 1.0-(fTxx+fTzz), fTyz+fTwx); |
499 | 0 | return Radian(Math::ATan2(fTyz+fTwx, 1.0f-(fTxx+fTzz))); |
500 | 0 | } |
501 | 0 | else |
502 | 0 | { |
503 | | // internal version |
504 | 0 | return Radian(Math::ATan2(2*(y*z + w*x), w*w - x*x - y*y + z*z)); |
505 | 0 | } |
506 | 0 | } |
507 | | //----------------------------------------------------------------------- |
508 | | Radian Quaternion::getYaw(bool reprojectAxis) const |
509 | 0 | { |
510 | 0 | if (reprojectAxis) |
511 | 0 | { |
512 | | // yaw = atan2(localz.x, localz.z) |
513 | | // pick parts of zAxis() implementation that we need |
514 | 0 | Real fTx = 2.0f*x; |
515 | 0 | Real fTy = 2.0f*y; |
516 | 0 | Real fTz = 2.0f*z; |
517 | 0 | Real fTwy = fTy*w; |
518 | 0 | Real fTxx = fTx*x; |
519 | 0 | Real fTxz = fTz*x; |
520 | 0 | Real fTyy = fTy*y; |
521 | | |
522 | | // Vector3(fTxz+fTwy, fTyz-fTwx, 1.0-(fTxx+fTyy)); |
523 | |
|
524 | 0 | return Radian(Math::ATan2(fTxz+fTwy, 1.0f-(fTxx+fTyy))); |
525 | |
|
526 | 0 | } |
527 | 0 | else |
528 | 0 | { |
529 | | // internal version |
530 | 0 | return Radian(Math::ASin(-2*(x*z - w*y))); |
531 | 0 | } |
532 | 0 | } |
533 | | //----------------------------------------------------------------------- |
534 | | Quaternion Quaternion::nlerp(Real fT, const Quaternion& rkP, |
535 | | const Quaternion& rkQ, bool shortestPath) |
536 | 0 | { |
537 | 0 | Quaternion result; |
538 | 0 | Real fCos = rkP.Dot(rkQ); |
539 | 0 | if (fCos < 0.0f && shortestPath) |
540 | 0 | { |
541 | 0 | result = rkP + fT * ((-rkQ) - rkP); |
542 | 0 | } |
543 | 0 | else |
544 | 0 | { |
545 | 0 | result = rkP + fT * (rkQ - rkP); |
546 | 0 | } |
547 | 0 | result.normalise(); |
548 | 0 | return result; |
549 | 0 | } |
550 | | |
551 | | std::ostream& operator<<(std::ostream& o, const Quaternion& q) |
552 | 0 | { |
553 | 0 | return o << "Quaternion(" << q.w << ", " << q.x << ", " << q.y << ", " << q.z << ")"; |
554 | 0 | } |
555 | | } |