Coverage Report

Created: 2026-08-29 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}