1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qquaternion.h"
41#include <QtCore/qdatastream.h>
42#include <QtCore/qmath.h>
43#include <QtCore/qvariant.h>
44#include <QtCore/qdebug.h>
45
46#include <cmath>
47
48QT_BEGIN_NAMESPACE
49
50#ifndef QT_NO_QUATERNION
51
52/*!
53 \class QQuaternion
54 \brief The QQuaternion class represents a quaternion consisting of a vector and scalar.
55 \since 4.6
56 \ingroup painting-3D
57 \inmodule QtGui
58
59 Quaternions are used to represent rotations in 3D space, and
60 consist of a 3D rotation axis specified by the x, y, and z
61 coordinates, and a scalar representing the rotation angle.
62*/
63
64/*!
65 \fn QQuaternion::QQuaternion()
66
67 Constructs an identity quaternion (1, 0, 0, 0), i.e. with the vector (0, 0, 0)
68 and scalar 1.
69*/
70
71/*!
72 \fn QQuaternion::QQuaternion(Qt::Initialization)
73 \since 5.5
74 \internal
75
76 Constructs a quaternion without initializing the contents.
77*/
78
79/*!
80 \fn QQuaternion::QQuaternion(float scalar, float xpos, float ypos, float zpos)
81
82 Constructs a quaternion with the vector (\a xpos, \a ypos, \a zpos)
83 and \a scalar.
84*/
85
86#ifndef QT_NO_VECTOR3D
87
88/*!
89 \fn QQuaternion::QQuaternion(float scalar, const QVector3D& vector)
90
91 Constructs a quaternion vector from the specified \a vector and
92 \a scalar.
93
94 \sa vector(), scalar()
95*/
96
97/*!
98 \fn QVector3D QQuaternion::vector() const
99
100 Returns the vector component of this quaternion.
101
102 \sa setVector(), scalar()
103*/
104
105/*!
106 \fn void QQuaternion::setVector(const QVector3D& vector)
107
108 Sets the vector component of this quaternion to \a vector.
109
110 \sa vector(), setScalar()
111*/
112
113#endif
114
115/*!
116 \fn void QQuaternion::setVector(float x, float y, float z)
117
118 Sets the vector component of this quaternion to (\a x, \a y, \a z).
119
120 \sa vector(), setScalar()
121*/
122
123#ifndef QT_NO_VECTOR4D
124
125/*!
126 \fn QQuaternion::QQuaternion(const QVector4D& vector)
127
128 Constructs a quaternion from the components of \a vector.
129*/
130
131/*!
132 \fn QVector4D QQuaternion::toVector4D() const
133
134 Returns this quaternion as a 4D vector.
135*/
136
137#endif
138
139/*!
140 \fn bool QQuaternion::isNull() const
141
142 Returns \c true if the x, y, z, and scalar components of this
143 quaternion are set to 0.0; otherwise returns \c false.
144*/
145
146/*!
147 \fn bool QQuaternion::isIdentity() const
148
149 Returns \c true if the x, y, and z components of this
150 quaternion are set to 0.0, and the scalar component is set
151 to 1.0; otherwise returns \c false.
152*/
153
154/*!
155 \fn float QQuaternion::x() const
156
157 Returns the x coordinate of this quaternion's vector.
158
159 \sa setX(), y(), z(), scalar()
160*/
161
162/*!
163 \fn float QQuaternion::y() const
164
165 Returns the y coordinate of this quaternion's vector.
166
167 \sa setY(), x(), z(), scalar()
168*/
169
170/*!
171 \fn float QQuaternion::z() const
172
173 Returns the z coordinate of this quaternion's vector.
174
175 \sa setZ(), x(), y(), scalar()
176*/
177
178/*!
179 \fn float QQuaternion::scalar() const
180
181 Returns the scalar component of this quaternion.
182
183 \sa setScalar(), x(), y(), z()
184*/
185
186/*!
187 \fn void QQuaternion::setX(float x)
188
189 Sets the x coordinate of this quaternion's vector to the given
190 \a x coordinate.
191
192 \sa x(), setY(), setZ(), setScalar()
193*/
194
195/*!
196 \fn void QQuaternion::setY(float y)
197
198 Sets the y coordinate of this quaternion's vector to the given
199 \a y coordinate.
200
201 \sa y(), setX(), setZ(), setScalar()
202*/
203
204/*!
205 \fn void QQuaternion::setZ(float z)
206
207 Sets the z coordinate of this quaternion's vector to the given
208 \a z coordinate.
209
210 \sa z(), setX(), setY(), setScalar()
211*/
212
213/*!
214 \fn void QQuaternion::setScalar(float scalar)
215
216 Sets the scalar component of this quaternion to \a scalar.
217
218 \sa scalar(), setX(), setY(), setZ()
219*/
220
221/*!
222 \fn float QQuaternion::dotProduct(const QQuaternion &q1, const QQuaternion &q2)
223 \since 5.5
224
225 Returns the dot product of \a q1 and \a q2.
226
227 \sa length()
228*/
229
230/*!
231 Returns the length of the quaternion. This is also called the "norm".
232
233 \sa lengthSquared(), normalized(), dotProduct()
234*/
235float QQuaternion::length() const
236{
237 return std::sqrt(xp * xp + yp * yp + zp * zp + wp * wp);
238}
239
240/*!
241 Returns the squared length of the quaternion.
242
243 \sa length(), dotProduct()
244*/
245float QQuaternion::lengthSquared() const
246{
247 return xp * xp + yp * yp + zp * zp + wp * wp;
248}
249
250/*!
251 Returns the normalized unit form of this quaternion.
252
253 If this quaternion is null, then a null quaternion is returned.
254 If the length of the quaternion is very close to 1, then the quaternion
255 will be returned as-is. Otherwise the normalized form of the
256 quaternion of length 1 will be returned.
257
258 \sa normalize(), length(), dotProduct()
259*/
260QQuaternion QQuaternion::normalized() const
261{
262 // Need some extra precision if the length is very small.
263 double len = double(xp) * double(xp) +
264 double(yp) * double(yp) +
265 double(zp) * double(zp) +
266 double(wp) * double(wp);
267 if (qFuzzyIsNull(len - 1.0f))
268 return *this;
269 else if (!qFuzzyIsNull(len))
270 return *this / std::sqrt(len);
271 else
272 return QQuaternion(0.0f, 0.0f, 0.0f, 0.0f);
273}
274
275/*!
276 Normalizes the current quaternion in place. Nothing happens if this
277 is a null quaternion or the length of the quaternion is very close to 1.
278
279 \sa length(), normalized()
280*/
281void QQuaternion::normalize()
282{
283 // Need some extra precision if the length is very small.
284 double len = double(xp) * double(xp) +
285 double(yp) * double(yp) +
286 double(zp) * double(zp) +
287 double(wp) * double(wp);
288 if (qFuzzyIsNull(len - 1.0f) || qFuzzyIsNull(len))
289 return;
290
291 len = std::sqrt(len);
292
293 xp /= len;
294 yp /= len;
295 zp /= len;
296 wp /= len;
297}
298
299/*!
300 \fn QQuaternion QQuaternion::inverted() const
301 \since 5.5
302
303 Returns the inverse of this quaternion.
304 If this quaternion is null, then a null quaternion is returned.
305
306 \sa isNull(), length()
307*/
308
309/*!
310 \fn QQuaternion QQuaternion::conjugated() const
311 \since 5.5
312
313 Returns the conjugate of this quaternion, which is
314 (-x, -y, -z, scalar).
315*/
316
317/*!
318 Rotates \a vector with this quaternion to produce a new vector
319 in 3D space. The following code:
320
321 \snippet code/src_gui_math3d_qquaternion.cpp 0
322
323 is equivalent to the following:
324
325 \snippet code/src_gui_math3d_qquaternion.cpp 1
326*/
327QVector3D QQuaternion::rotatedVector(const QVector3D& vector) const
328{
329 return (*this * QQuaternion(0, vector) * conjugated()).vector();
330}
331
332/*!
333 \fn QQuaternion &QQuaternion::operator+=(const QQuaternion &quaternion)
334
335 Adds the given \a quaternion to this quaternion and returns a reference to
336 this quaternion.
337
338 \sa operator-=()
339*/
340
341/*!
342 \fn QQuaternion &QQuaternion::operator-=(const QQuaternion &quaternion)
343
344 Subtracts the given \a quaternion from this quaternion and returns a
345 reference to this quaternion.
346
347 \sa operator+=()
348*/
349
350/*!
351 \fn QQuaternion &QQuaternion::operator*=(float factor)
352
353 Multiplies this quaternion's components by the given \a factor, and
354 returns a reference to this quaternion.
355
356 \sa operator/=()
357*/
358
359/*!
360 \fn QQuaternion &QQuaternion::operator*=(const QQuaternion &quaternion)
361
362 Multiplies this quaternion by \a quaternion and returns a reference
363 to this quaternion.
364*/
365
366/*!
367 \fn QQuaternion &QQuaternion::operator/=(float divisor)
368
369 Divides this quaternion's components by the given \a divisor, and
370 returns a reference to this quaternion.
371
372 \sa operator*=()
373*/
374
375#ifndef QT_NO_VECTOR3D
376
377/*!
378 \fn void QQuaternion::getAxisAndAngle(QVector3D *axis, float *angle) const
379 \since 5.5
380 \overload
381
382 Extracts a 3D axis \a axis and a rotating angle \a angle (in degrees)
383 that corresponds to this quaternion.
384
385 \sa fromAxisAndAngle()
386*/
387
388/*!
389 Creates a normalized quaternion that corresponds to rotating through
390 \a angle degrees about the specified 3D \a axis.
391
392 \sa getAxisAndAngle()
393*/
394QQuaternion QQuaternion::fromAxisAndAngle(const QVector3D& axis, float angle)
395{
396 // Algorithm from:
397 // http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q56
398 // We normalize the result just in case the values are close
399 // to zero, as suggested in the above FAQ.
400 float a = qDegreesToRadians(angle / 2.0f);
401 float s = std::sin(a);
402 float c = std::cos(a);
403 QVector3D ax = axis.normalized();
404 return QQuaternion(c, ax.x() * s, ax.y() * s, ax.z() * s).normalized();
405}
406
407#endif
408
409/*!
410 \since 5.5
411
412 Extracts a 3D axis (\a x, \a y, \a z) and a rotating angle \a angle (in degrees)
413 that corresponds to this quaternion.
414
415 \sa fromAxisAndAngle()
416*/
417void QQuaternion::getAxisAndAngle(float *x, float *y, float *z, float *angle) const
418{
419 Q_ASSERT(x && y && z && angle);
420
421 // The quaternion representing the rotation is
422 // q = cos(A/2)+sin(A/2)*(x*i+y*j+z*k)
423
424 float length = xp * xp + yp * yp + zp * zp;
425 if (!qFuzzyIsNull(length)) {
426 *x = xp;
427 *y = yp;
428 *z = zp;
429 if (!qFuzzyIsNull(length - 1.0f)) {
430 length = std::sqrt(length);
431 *x /= length;
432 *y /= length;
433 *z /= length;
434 }
435 *angle = 2.0f * std::acos(wp);
436 } else {
437 // angle is 0 (mod 2*pi), so any axis will fit
438 *x = *y = *z = *angle = 0.0f;
439 }
440
441 *angle = qRadiansToDegrees(*angle);
442}
443
444/*!
445 Creates a normalized quaternion that corresponds to rotating through
446 \a angle degrees about the 3D axis (\a x, \a y, \a z).
447
448 \sa getAxisAndAngle()
449*/
450QQuaternion QQuaternion::fromAxisAndAngle
451 (float x, float y, float z, float angle)
452{
453 float length = std::sqrt(x * x + y * y + z * z);
454 if (!qFuzzyIsNull(length - 1.0f) && !qFuzzyIsNull(length)) {
455 x /= length;
456 y /= length;
457 z /= length;
458 }
459 float a = qDegreesToRadians(angle / 2.0f);
460 float s = std::sin(a);
461 float c = std::cos(a);
462 return QQuaternion(c, x * s, y * s, z * s).normalized();
463}
464
465#ifndef QT_NO_VECTOR3D
466
467/*!
468 \fn QVector3D QQuaternion::toEulerAngles() const
469 \since 5.5
470 \overload
471
472 Calculates roll, pitch, and yaw Euler angles (in degrees)
473 that corresponds to this quaternion.
474
475 \sa fromEulerAngles()
476*/
477
478/*!
479 \fn QQuaternion QQuaternion::fromEulerAngles(const QVector3D &eulerAngles)
480 \since 5.5
481 \overload
482
483 Creates a quaternion that corresponds to a rotation of \a eulerAngles:
484 eulerAngles.z() degrees around the z axis, eulerAngles.x() degrees around the x axis,
485 and eulerAngles.y() degrees around the y axis (in that order).
486
487 \sa toEulerAngles()
488*/
489
490#endif // QT_NO_VECTOR3D
491
492/*!
493 \since 5.5
494
495 Calculates \a roll, \a pitch, and \a yaw Euler angles (in degrees)
496 that corresponds to this quaternion.
497
498 \sa fromEulerAngles()
499*/
500void QQuaternion::getEulerAngles(float *pitch, float *yaw, float *roll) const
501{
502 Q_ASSERT(pitch && yaw && roll);
503
504 // Algorithm from:
505 // http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q37
506
507 float xx = xp * xp;
508 float xy = xp * yp;
509 float xz = xp * zp;
510 float xw = xp * wp;
511 float yy = yp * yp;
512 float yz = yp * zp;
513 float yw = yp * wp;
514 float zz = zp * zp;
515 float zw = zp * wp;
516
517 const float lengthSquared = xx + yy + zz + wp * wp;
518 if (!qFuzzyIsNull(lengthSquared - 1.0f) && !qFuzzyIsNull(lengthSquared)) {
519 xx /= lengthSquared;
520 xy /= lengthSquared; // same as (xp / length) * (yp / length)
521 xz /= lengthSquared;
522 xw /= lengthSquared;
523 yy /= lengthSquared;
524 yz /= lengthSquared;
525 yw /= lengthSquared;
526 zz /= lengthSquared;
527 zw /= lengthSquared;
528 }
529
530 *pitch = std::asin(-2.0f * (yz - xw));
531 if (*pitch < M_PI_2) {
532 if (*pitch > -M_PI_2) {
533 *yaw = std::atan2(2.0f * (xz + yw), 1.0f - 2.0f * (xx + yy));
534 *roll = std::atan2(2.0f * (xy + zw), 1.0f - 2.0f * (xx + zz));
535 } else {
536 // not a unique solution
537 *roll = 0.0f;
538 *yaw = -std::atan2(-2.0f * (xy - zw), 1.0f - 2.0f * (yy + zz));
539 }
540 } else {
541 // not a unique solution
542 *roll = 0.0f;
543 *yaw = std::atan2(-2.0f * (xy - zw), 1.0f - 2.0f * (yy + zz));
544 }
545
546 *pitch = qRadiansToDegrees(*pitch);
547 *yaw = qRadiansToDegrees(*yaw);
548 *roll = qRadiansToDegrees(*roll);
549}
550
551/*!
552 \since 5.5
553
554 Creates a quaternion that corresponds to a rotation of
555 \a roll degrees around the z axis, \a pitch degrees around the x axis,
556 and \a yaw degrees around the y axis (in that order).
557
558 \sa getEulerAngles()
559*/
560QQuaternion QQuaternion::fromEulerAngles(float pitch, float yaw, float roll)
561{
562 // Algorithm from:
563 // http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q60
564
565 pitch = qDegreesToRadians(pitch);
566 yaw = qDegreesToRadians(yaw);
567 roll = qDegreesToRadians(roll);
568
569 pitch *= 0.5f;
570 yaw *= 0.5f;
571 roll *= 0.5f;
572
573 const float c1 = std::cos(yaw);
574 const float s1 = std::sin(yaw);
575 const float c2 = std::cos(roll);
576 const float s2 = std::sin(roll);
577 const float c3 = std::cos(pitch);
578 const float s3 = std::sin(pitch);
579 const float c1c2 = c1 * c2;
580 const float s1s2 = s1 * s2;
581
582 const float w = c1c2 * c3 + s1s2 * s3;
583 const float x = c1c2 * s3 + s1s2 * c3;
584 const float y = s1 * c2 * c3 - c1 * s2 * s3;
585 const float z = c1 * s2 * c3 - s1 * c2 * s3;
586
587 return QQuaternion(w, x, y, z);
588}
589
590/*!
591 \since 5.5
592
593 Creates a rotation matrix that corresponds to this quaternion.
594
595 \note If this quaternion is not normalized,
596 the resulting rotation matrix will contain scaling information.
597
598 \sa fromRotationMatrix(), getAxes()
599*/
600QMatrix3x3 QQuaternion::toRotationMatrix() const
601{
602 // Algorithm from:
603 // http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q54
604
605 QMatrix3x3 rot3x3(Qt::Uninitialized);
606
607 const float f2x = xp + xp;
608 const float f2y = yp + yp;
609 const float f2z = zp + zp;
610 const float f2xw = f2x * wp;
611 const float f2yw = f2y * wp;
612 const float f2zw = f2z * wp;
613 const float f2xx = f2x * xp;
614 const float f2xy = f2x * yp;
615 const float f2xz = f2x * zp;
616 const float f2yy = f2y * yp;
617 const float f2yz = f2y * zp;
618 const float f2zz = f2z * zp;
619
620 rot3x3(0, 0) = 1.0f - (f2yy + f2zz);
621 rot3x3(0, 1) = f2xy - f2zw;
622 rot3x3(0, 2) = f2xz + f2yw;
623 rot3x3(1, 0) = f2xy + f2zw;
624 rot3x3(1, 1) = 1.0f - (f2xx + f2zz);
625 rot3x3(1, 2) = f2yz - f2xw;
626 rot3x3(2, 0) = f2xz - f2yw;
627 rot3x3(2, 1) = f2yz + f2xw;
628 rot3x3(2, 2) = 1.0f - (f2xx + f2yy);
629
630 return rot3x3;
631}
632
633/*!
634 \since 5.5
635
636 Creates a quaternion that corresponds to a rotation matrix \a rot3x3.
637
638 \note If a given rotation matrix is not normalized,
639 the resulting quaternion will contain scaling information.
640
641 \sa toRotationMatrix(), fromAxes()
642*/
643QQuaternion QQuaternion::fromRotationMatrix(const QMatrix3x3 &rot3x3)
644{
645 // Algorithm from:
646 // http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q55
647
648 float scalar;
649 float axis[3];
650
651 const float trace = rot3x3(0, 0) + rot3x3(1, 1) + rot3x3(2, 2);
652 if (trace > 0.00000001f) {
653 const float s = 2.0f * std::sqrt(trace + 1.0f);
654 scalar = 0.25f * s;
655 axis[0] = (rot3x3(2, 1) - rot3x3(1, 2)) / s;
656 axis[1] = (rot3x3(0, 2) - rot3x3(2, 0)) / s;
657 axis[2] = (rot3x3(1, 0) - rot3x3(0, 1)) / s;
658 } else {
659 static int s_next[3] = { 1, 2, 0 };
660 int i = 0;
661 if (rot3x3(1, 1) > rot3x3(0, 0))
662 i = 1;
663 if (rot3x3(2, 2) > rot3x3(i, i))
664 i = 2;
665 int j = s_next[i];
666 int k = s_next[j];
667
668 const float s = 2.0f * std::sqrt(rot3x3(i, i) - rot3x3(j, j) - rot3x3(k, k) + 1.0f);
669 axis[i] = 0.25f * s;
670 scalar = (rot3x3(k, j) - rot3x3(j, k)) / s;
671 axis[j] = (rot3x3(j, i) + rot3x3(i, j)) / s;
672 axis[k] = (rot3x3(k, i) + rot3x3(i, k)) / s;
673 }
674
675 return QQuaternion(scalar, axis[0], axis[1], axis[2]);
676}
677
678#ifndef QT_NO_VECTOR3D
679
680/*!
681 \since 5.5
682
683 Returns the 3 orthonormal axes (\a xAxis, \a yAxis, \a zAxis) defining the quaternion.
684
685 \sa fromAxes(), toRotationMatrix()
686*/
687void QQuaternion::getAxes(QVector3D *xAxis, QVector3D *yAxis, QVector3D *zAxis) const
688{
689 Q_ASSERT(xAxis && yAxis && zAxis);
690
691 const QMatrix3x3 rot3x3(toRotationMatrix());
692
693 *xAxis = QVector3D(rot3x3(0, 0), rot3x3(1, 0), rot3x3(2, 0));
694 *yAxis = QVector3D(rot3x3(0, 1), rot3x3(1, 1), rot3x3(2, 1));
695 *zAxis = QVector3D(rot3x3(0, 2), rot3x3(1, 2), rot3x3(2, 2));
696}
697
698/*!
699 \since 5.5
700
701 Constructs the quaternion using 3 axes (\a xAxis, \a yAxis, \a zAxis).
702
703 \note The axes are assumed to be orthonormal.
704
705 \sa getAxes(), fromRotationMatrix()
706*/
707QQuaternion QQuaternion::fromAxes(const QVector3D &xAxis, const QVector3D &yAxis, const QVector3D &zAxis)
708{
709 QMatrix3x3 rot3x3(Qt::Uninitialized);
710 rot3x3(0, 0) = xAxis.x();
711 rot3x3(1, 0) = xAxis.y();
712 rot3x3(2, 0) = xAxis.z();
713 rot3x3(0, 1) = yAxis.x();
714 rot3x3(1, 1) = yAxis.y();
715 rot3x3(2, 1) = yAxis.z();
716 rot3x3(0, 2) = zAxis.x();
717 rot3x3(1, 2) = zAxis.y();
718 rot3x3(2, 2) = zAxis.z();
719
720 return QQuaternion::fromRotationMatrix(rot3x3);
721}
722
723/*!
724 \since 5.5
725
726 Constructs the quaternion using specified forward direction \a direction
727 and upward direction \a up.
728 If the upward direction was not specified or the forward and upward
729 vectors are collinear, a new orthonormal upward direction will be generated.
730
731 \sa fromAxes(), rotationTo()
732*/
733QQuaternion QQuaternion::fromDirection(const QVector3D &direction, const QVector3D &up)
734{
735 if (qFuzzyIsNull(direction.x()) && qFuzzyIsNull(direction.y()) && qFuzzyIsNull(direction.z()))
736 return QQuaternion();
737
738 const QVector3D zAxis(direction.normalized());
739 QVector3D xAxis(QVector3D::crossProduct(up, zAxis));
740 if (qFuzzyIsNull(xAxis.lengthSquared())) {
741 // collinear or invalid up vector; derive shortest arc to new direction
742 return QQuaternion::rotationTo(QVector3D(0.0f, 0.0f, 1.0f), zAxis);
743 }
744
745 xAxis.normalize();
746 const QVector3D yAxis(QVector3D::crossProduct(zAxis, xAxis));
747
748 return QQuaternion::fromAxes(xAxis, yAxis, zAxis);
749}
750
751/*!
752 \since 5.5
753
754 Returns the shortest arc quaternion to rotate from the direction described by the vector \a from
755 to the direction described by the vector \a to.
756
757 \sa fromDirection()
758*/
759QQuaternion QQuaternion::rotationTo(const QVector3D &from, const QVector3D &to)
760{
761 // Based on Stan Melax's article in Game Programming Gems
762
763 const QVector3D v0(from.normalized());
764 const QVector3D v1(to.normalized());
765
766 float d = QVector3D::dotProduct(v0, v1) + 1.0f;
767
768 // if dest vector is close to the inverse of source vector, ANY axis of rotation is valid
769 if (qFuzzyIsNull(d)) {
770 QVector3D axis = QVector3D::crossProduct(QVector3D(1.0f, 0.0f, 0.0f), v0);
771 if (qFuzzyIsNull(axis.lengthSquared()))
772 axis = QVector3D::crossProduct(QVector3D(0.0f, 1.0f, 0.0f), v0);
773 axis.normalize();
774
775 // same as QQuaternion::fromAxisAndAngle(axis, 180.0f)
776 return QQuaternion(0.0f, axis.x(), axis.y(), axis.z());
777 }
778
779 d = std::sqrt(2.0f * d);
780 const QVector3D axis(QVector3D::crossProduct(v0, v1) / d);
781
782 return QQuaternion(d * 0.5f, axis).normalized();
783}
784
785#endif // QT_NO_VECTOR3D
786
787/*!
788 \fn bool operator==(const QQuaternion &q1, const QQuaternion &q2)
789 \relates QQuaternion
790
791 Returns \c true if \a q1 is equal to \a q2; otherwise returns \c false.
792 This operator uses an exact floating-point comparison.
793*/
794
795/*!
796 \fn bool operator!=(const QQuaternion &q1, const QQuaternion &q2)
797 \relates QQuaternion
798
799 Returns \c true if \a q1 is not equal to \a q2; otherwise returns \c false.
800 This operator uses an exact floating-point comparison.
801*/
802
803/*!
804 \fn const QQuaternion operator+(const QQuaternion &q1, const QQuaternion &q2)
805 \relates QQuaternion
806
807 Returns a QQuaternion object that is the sum of the given quaternions,
808 \a q1 and \a q2; each component is added separately.
809
810 \sa QQuaternion::operator+=()
811*/
812
813/*!
814 \fn const QQuaternion operator-(const QQuaternion &q1, const QQuaternion &q2)
815 \relates QQuaternion
816
817 Returns a QQuaternion object that is formed by subtracting
818 \a q2 from \a q1; each component is subtracted separately.
819
820 \sa QQuaternion::operator-=()
821*/
822
823/*!
824 \fn const QQuaternion operator*(float factor, const QQuaternion &quaternion)
825 \relates QQuaternion
826
827 Returns a copy of the given \a quaternion, multiplied by the
828 given \a factor.
829
830 \sa QQuaternion::operator*=()
831*/
832
833/*!
834 \fn const QQuaternion operator*(const QQuaternion &quaternion, float factor)
835 \relates QQuaternion
836
837 Returns a copy of the given \a quaternion, multiplied by the
838 given \a factor.
839
840 \sa QQuaternion::operator*=()
841*/
842
843/*!
844 \fn const QQuaternion operator*(const QQuaternion &q1, const QQuaternion& q2)
845 \relates QQuaternion
846
847 Multiplies \a q1 and \a q2 using quaternion multiplication.
848 The result corresponds to applying both of the rotations specified
849 by \a q1 and \a q2.
850
851 \sa QQuaternion::operator*=()
852*/
853
854/*!
855 \fn const QQuaternion operator-(const QQuaternion &quaternion)
856 \relates QQuaternion
857 \overload
858
859 Returns a QQuaternion object that is formed by changing the sign of
860 all three components of the given \a quaternion.
861
862 Equivalent to \c {QQuaternion(0,0,0,0) - quaternion}.
863*/
864
865/*!
866 \fn const QQuaternion operator/(const QQuaternion &quaternion, float divisor)
867 \relates QQuaternion
868
869 Returns the QQuaternion object formed by dividing all components of
870 the given \a quaternion by the given \a divisor.
871
872 \sa QQuaternion::operator/=()
873*/
874
875#ifndef QT_NO_VECTOR3D
876
877/*!
878 \fn QVector3D operator*(const QQuaternion &quaternion, const QVector3D &vec)
879 \since 5.5
880 \relates QQuaternion
881
882 Rotates a vector \a vec with a quaternion \a quaternion to produce a new vector in 3D space.
883*/
884
885#endif
886
887/*!
888 \fn bool qFuzzyCompare(const QQuaternion& q1, const QQuaternion& q2)
889 \relates QQuaternion
890
891 Returns \c true if \a q1 and \a q2 are equal, allowing for a small
892 fuzziness factor for floating-point comparisons; false otherwise.
893*/
894
895/*!
896 Interpolates along the shortest spherical path between the
897 rotational positions \a q1 and \a q2. The value \a t should
898 be between 0 and 1, indicating the spherical distance to travel
899 between \a q1 and \a q2.
900
901 If \a t is less than or equal to 0, then \a q1 will be returned.
902 If \a t is greater than or equal to 1, then \a q2 will be returned.
903
904 \sa nlerp()
905*/
906QQuaternion QQuaternion::slerp
907 (const QQuaternion& q1, const QQuaternion& q2, float t)
908{
909 // Handle the easy cases first.
910 if (t <= 0.0f)
911 return q1;
912 else if (t >= 1.0f)
913 return q2;
914
915 // Determine the angle between the two quaternions.
916 QQuaternion q2b(q2);
917 float dot = QQuaternion::dotProduct(q1, q2);
918 if (dot < 0.0f) {
919 q2b = -q2b;
920 dot = -dot;
921 }
922
923 // Get the scale factors. If they are too small,
924 // then revert to simple linear interpolation.
925 float factor1 = 1.0f - t;
926 float factor2 = t;
927 if ((1.0f - dot) > 0.0000001) {
928 float angle = std::acos(dot);
929 float sinOfAngle = std::sin(angle);
930 if (sinOfAngle > 0.0000001) {
931 factor1 = std::sin((1.0f - t) * angle) / sinOfAngle;
932 factor2 = std::sin(t * angle) / sinOfAngle;
933 }
934 }
935
936 // Construct the result quaternion.
937 return q1 * factor1 + q2b * factor2;
938}
939
940/*!
941 Interpolates along the shortest linear path between the rotational
942 positions \a q1 and \a q2. The value \a t should be between 0 and 1,
943 indicating the distance to travel between \a q1 and \a q2.
944 The result will be normalized().
945
946 If \a t is less than or equal to 0, then \a q1 will be returned.
947 If \a t is greater than or equal to 1, then \a q2 will be returned.
948
949 The nlerp() function is typically faster than slerp() and will
950 give approximate results to spherical interpolation that are
951 good enough for some applications.
952
953 \sa slerp()
954*/
955QQuaternion QQuaternion::nlerp
956 (const QQuaternion& q1, const QQuaternion& q2, float t)
957{
958 // Handle the easy cases first.
959 if (t <= 0.0f)
960 return q1;
961 else if (t >= 1.0f)
962 return q2;
963
964 // Determine the angle between the two quaternions.
965 QQuaternion q2b(q2);
966 float dot = QQuaternion::dotProduct(q1, q2);
967 if (dot < 0.0f)
968 q2b = -q2b;
969
970 // Perform the linear interpolation.
971 return (q1 * (1.0f - t) + q2b * t).normalized();
972}
973
974/*!
975 Returns the quaternion as a QVariant.
976*/
977QQuaternion::operator QVariant() const
978{
979 return QVariant::fromValue(*this);
980}
981
982#ifndef QT_NO_DEBUG_STREAM
983
984QDebug operator<<(QDebug dbg, const QQuaternion &q)
985{
986 QDebugStateSaver saver(dbg);
987 dbg.nospace() << "QQuaternion(scalar:" << q.scalar()
988 << ", vector:(" << q.x() << ", "
989 << q.y() << ", " << q.z() << "))";
990 return dbg;
991}
992
993#endif
994
995#ifndef QT_NO_DATASTREAM
996
997/*!
998 \fn QDataStream &operator<<(QDataStream &stream, const QQuaternion &quaternion)
999 \relates QQuaternion
1000
1001 Writes the given \a quaternion to the given \a stream and returns a
1002 reference to the stream.
1003
1004 \sa {Serializing Qt Data Types}
1005*/
1006
1007QDataStream &operator<<(QDataStream &stream, const QQuaternion &quaternion)
1008{
1009 stream << quaternion.scalar() << quaternion.x()
1010 << quaternion.y() << quaternion.z();
1011 return stream;
1012}
1013
1014/*!
1015 \fn QDataStream &operator>>(QDataStream &stream, QQuaternion &quaternion)
1016 \relates QQuaternion
1017
1018 Reads a quaternion from the given \a stream into the given \a quaternion
1019 and returns a reference to the stream.
1020
1021 \sa {Serializing Qt Data Types}
1022*/
1023
1024QDataStream &operator>>(QDataStream &stream, QQuaternion &quaternion)
1025{
1026 float scalar, x, y, z;
1027 stream >> scalar;
1028 stream >> x;
1029 stream >> y;
1030 stream >> z;
1031 quaternion.setScalar(scalar);
1032 quaternion.setX(x);
1033 quaternion.setY(y);
1034 quaternion.setZ(z);
1035 return stream;
1036}
1037
1038#endif // QT_NO_DATASTREAM
1039
1040#endif
1041
1042QT_END_NAMESPACE
1043