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(x: 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(d: len - 1.0f))
268 return *this;
269 else if (!qFuzzyIsNull(d: len))
270 return *this / std::sqrt(x: 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(d: len - 1.0f) || qFuzzyIsNull(d: len))
289 return;
290
291 len = std::sqrt(x: 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 \fn QQuaternion QQuaternion::conjugate() const
319 \obsolete
320
321 Use conjugated() instead.
322*/
323
324/*!
325 Rotates \a vector with this quaternion to produce a new vector
326 in 3D space. The following code:
327
328 \snippet code/src_gui_math3d_qquaternion.cpp 0
329
330 is equivalent to the following:
331
332 \snippet code/src_gui_math3d_qquaternion.cpp 1
333*/
334QVector3D QQuaternion::rotatedVector(const QVector3D& vector) const
335{
336 return (*this * QQuaternion(0, vector) * conjugated()).vector();
337}
338
339/*!
340 \fn QQuaternion &QQuaternion::operator+=(const QQuaternion &quaternion)
341
342 Adds the given \a quaternion to this quaternion and returns a reference to
343 this quaternion.
344
345 \sa operator-=()
346*/
347
348/*!
349 \fn QQuaternion &QQuaternion::operator-=(const QQuaternion &quaternion)
350
351 Subtracts the given \a quaternion from this quaternion and returns a
352 reference to this quaternion.
353
354 \sa operator+=()
355*/
356
357/*!
358 \fn QQuaternion &QQuaternion::operator*=(float factor)
359
360 Multiplies this quaternion's components by the given \a factor, and
361 returns a reference to this quaternion.
362
363 \sa operator/=()
364*/
365
366/*!
367 \fn QQuaternion &QQuaternion::operator*=(const QQuaternion &quaternion)
368
369 Multiplies this quaternion by \a quaternion and returns a reference
370 to this quaternion.
371*/
372
373/*!
374 \fn QQuaternion &QQuaternion::operator/=(float divisor)
375
376 Divides this quaternion's components by the given \a divisor, and
377 returns a reference to this quaternion.
378
379 \sa operator*=()
380*/
381
382#ifndef QT_NO_VECTOR3D
383
384/*!
385 \fn void QQuaternion::getAxisAndAngle(QVector3D *axis, float *angle) const
386 \since 5.5
387 \overload
388
389 Extracts a 3D axis \a axis and a rotating angle \a angle (in degrees)
390 that corresponds to this quaternion.
391
392 \sa fromAxisAndAngle()
393*/
394
395/*!
396 Creates a normalized quaternion that corresponds to rotating through
397 \a angle degrees about the specified 3D \a axis.
398
399 \sa getAxisAndAngle()
400*/
401QQuaternion QQuaternion::fromAxisAndAngle(const QVector3D& axis, float angle)
402{
403 // Algorithm from:
404 // http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q56
405 // We normalize the result just in case the values are close
406 // to zero, as suggested in the above FAQ.
407 float a = qDegreesToRadians(degrees: angle / 2.0f);
408 float s = std::sin(x: a);
409 float c = std::cos(x: a);
410 QVector3D ax = axis.normalized();
411 return QQuaternion(c, ax.x() * s, ax.y() * s, ax.z() * s).normalized();
412}
413
414#endif
415
416/*!
417 \since 5.5
418
419 Extracts a 3D axis (\a x, \a y, \a z) and a rotating angle \a angle (in degrees)
420 that corresponds to this quaternion.
421
422 \sa fromAxisAndAngle()
423*/
424void QQuaternion::getAxisAndAngle(float *x, float *y, float *z, float *angle) const
425{
426 Q_ASSERT(x && y && z && angle);
427
428 // The quaternion representing the rotation is
429 // q = cos(A/2)+sin(A/2)*(x*i+y*j+z*k)
430
431 float length = xp * xp + yp * yp + zp * zp;
432 if (!qFuzzyIsNull(f: length)) {
433 *x = xp;
434 *y = yp;
435 *z = zp;
436 if (!qFuzzyIsNull(f: length - 1.0f)) {
437 length = std::sqrt(x: length);
438 *x /= length;
439 *y /= length;
440 *z /= length;
441 }
442 *angle = 2.0f * std::acos(x: wp);
443 } else {
444 // angle is 0 (mod 2*pi), so any axis will fit
445 *x = *y = *z = *angle = 0.0f;
446 }
447
448 *angle = qRadiansToDegrees(radians: *angle);
449}
450
451/*!
452 Creates a normalized quaternion that corresponds to rotating through
453 \a angle degrees about the 3D axis (\a x, \a y, \a z).
454
455 \sa getAxisAndAngle()
456*/
457QQuaternion QQuaternion::fromAxisAndAngle
458 (float x, float y, float z, float angle)
459{
460 float length = std::sqrt(x: x * x + y * y + z * z);
461 if (!qFuzzyIsNull(f: length - 1.0f) && !qFuzzyIsNull(f: length)) {
462 x /= length;
463 y /= length;
464 z /= length;
465 }
466 float a = qDegreesToRadians(degrees: angle / 2.0f);
467 float s = std::sin(x: a);
468 float c = std::cos(x: a);
469 return QQuaternion(c, x * s, y * s, z * s).normalized();
470}
471
472#ifndef QT_NO_VECTOR3D
473
474/*!
475 \fn QVector3D QQuaternion::toEulerAngles() const
476 \since 5.5
477 \overload
478
479 Calculates roll, pitch, and yaw Euler angles (in degrees)
480 that corresponds to this quaternion.
481
482 \sa fromEulerAngles()
483*/
484
485/*!
486 \fn QQuaternion QQuaternion::fromEulerAngles(const QVector3D &eulerAngles)
487 \since 5.5
488 \overload
489
490 Creates a quaternion that corresponds to a rotation of \a eulerAngles:
491 eulerAngles.z() degrees around the z axis, eulerAngles.x() degrees around the x axis,
492 and eulerAngles.y() degrees around the y axis (in that order).
493
494 \sa toEulerAngles()
495*/
496
497#endif // QT_NO_VECTOR3D
498
499/*!
500 \since 5.5
501
502 Calculates \a roll, \a pitch, and \a yaw Euler angles (in degrees)
503 that corresponds to this quaternion.
504
505 \sa fromEulerAngles()
506*/
507void QQuaternion::getEulerAngles(float *pitch, float *yaw, float *roll) const
508{
509 Q_ASSERT(pitch && yaw && roll);
510
511 // Algorithm from:
512 // http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q37
513
514 float xx = xp * xp;
515 float xy = xp * yp;
516 float xz = xp * zp;
517 float xw = xp * wp;
518 float yy = yp * yp;
519 float yz = yp * zp;
520 float yw = yp * wp;
521 float zz = zp * zp;
522 float zw = zp * wp;
523
524 const float lengthSquared = xx + yy + zz + wp * wp;
525 if (!qFuzzyIsNull(f: lengthSquared - 1.0f) && !qFuzzyIsNull(f: lengthSquared)) {
526 xx /= lengthSquared;
527 xy /= lengthSquared; // same as (xp / length) * (yp / length)
528 xz /= lengthSquared;
529 xw /= lengthSquared;
530 yy /= lengthSquared;
531 yz /= lengthSquared;
532 yw /= lengthSquared;
533 zz /= lengthSquared;
534 zw /= lengthSquared;
535 }
536
537 const float sinp = -2.0f * (yz - xw);
538 if (std::abs(x: sinp) >= 1.0f)
539 *pitch = std::copysign(M_PI_2, y: sinp);
540 else
541 *pitch = std::asin(x: sinp);
542 if (*pitch < M_PI_2) {
543 if (*pitch > -M_PI_2) {
544 *yaw = std::atan2(y: 2.0f * (xz + yw), x: 1.0f - 2.0f * (xx + yy));
545 *roll = std::atan2(y: 2.0f * (xy + zw), x: 1.0f - 2.0f * (xx + zz));
546 } else {
547 // not a unique solution
548 *roll = 0.0f;
549 *yaw = -std::atan2(y: -2.0f * (xy - zw), x: 1.0f - 2.0f * (yy + zz));
550 }
551 } else {
552 // not a unique solution
553 *roll = 0.0f;
554 *yaw = std::atan2(y: -2.0f * (xy - zw), x: 1.0f - 2.0f * (yy + zz));
555 }
556
557 *pitch = qRadiansToDegrees(radians: *pitch);
558 *yaw = qRadiansToDegrees(radians: *yaw);
559 *roll = qRadiansToDegrees(radians: *roll);
560}
561
562/*!
563 \since 5.5
564
565 Creates a quaternion that corresponds to a rotation of
566 \a roll degrees around the z axis, \a pitch degrees around the x axis,
567 and \a yaw degrees around the y axis (in that order).
568
569 \sa getEulerAngles()
570*/
571QQuaternion QQuaternion::fromEulerAngles(float pitch, float yaw, float roll)
572{
573 // Algorithm from:
574 // http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q60
575
576 pitch = qDegreesToRadians(degrees: pitch);
577 yaw = qDegreesToRadians(degrees: yaw);
578 roll = qDegreesToRadians(degrees: roll);
579
580 pitch *= 0.5f;
581 yaw *= 0.5f;
582 roll *= 0.5f;
583
584 const float c1 = std::cos(x: yaw);
585 const float s1 = std::sin(x: yaw);
586 const float c2 = std::cos(x: roll);
587 const float s2 = std::sin(x: roll);
588 const float c3 = std::cos(x: pitch);
589 const float s3 = std::sin(x: pitch);
590 const float c1c2 = c1 * c2;
591 const float s1s2 = s1 * s2;
592
593 const float w = c1c2 * c3 + s1s2 * s3;
594 const float x = c1c2 * s3 + s1s2 * c3;
595 const float y = s1 * c2 * c3 - c1 * s2 * s3;
596 const float z = c1 * s2 * c3 - s1 * c2 * s3;
597
598 return QQuaternion(w, x, y, z);
599}
600
601/*!
602 \since 5.5
603
604 Creates a rotation matrix that corresponds to this quaternion.
605
606 \note If this quaternion is not normalized,
607 the resulting rotation matrix will contain scaling information.
608
609 \sa fromRotationMatrix(), getAxes()
610*/
611QMatrix3x3 QQuaternion::toRotationMatrix() const
612{
613 // Algorithm from:
614 // http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q54
615
616 QMatrix3x3 rot3x3(Qt::Uninitialized);
617
618 const float f2x = xp + xp;
619 const float f2y = yp + yp;
620 const float f2z = zp + zp;
621 const float f2xw = f2x * wp;
622 const float f2yw = f2y * wp;
623 const float f2zw = f2z * wp;
624 const float f2xx = f2x * xp;
625 const float f2xy = f2x * yp;
626 const float f2xz = f2x * zp;
627 const float f2yy = f2y * yp;
628 const float f2yz = f2y * zp;
629 const float f2zz = f2z * zp;
630
631 rot3x3(0, 0) = 1.0f - (f2yy + f2zz);
632 rot3x3(0, 1) = f2xy - f2zw;
633 rot3x3(0, 2) = f2xz + f2yw;
634 rot3x3(1, 0) = f2xy + f2zw;
635 rot3x3(1, 1) = 1.0f - (f2xx + f2zz);
636 rot3x3(1, 2) = f2yz - f2xw;
637 rot3x3(2, 0) = f2xz - f2yw;
638 rot3x3(2, 1) = f2yz + f2xw;
639 rot3x3(2, 2) = 1.0f - (f2xx + f2yy);
640
641 return rot3x3;
642}
643
644/*!
645 \since 5.5
646
647 Creates a quaternion that corresponds to a rotation matrix \a rot3x3.
648
649 \note If a given rotation matrix is not normalized,
650 the resulting quaternion will contain scaling information.
651
652 \sa toRotationMatrix(), fromAxes()
653*/
654QQuaternion QQuaternion::fromRotationMatrix(const QMatrix3x3 &rot3x3)
655{
656 // Algorithm from:
657 // http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q55
658
659 float scalar;
660 float axis[3];
661
662 const float trace = rot3x3(0, 0) + rot3x3(1, 1) + rot3x3(2, 2);
663 if (trace > 0.00000001f) {
664 const float s = 2.0f * std::sqrt(x: trace + 1.0f);
665 scalar = 0.25f * s;
666 axis[0] = (rot3x3(2, 1) - rot3x3(1, 2)) / s;
667 axis[1] = (rot3x3(0, 2) - rot3x3(2, 0)) / s;
668 axis[2] = (rot3x3(1, 0) - rot3x3(0, 1)) / s;
669 } else {
670 static int s_next[3] = { 1, 2, 0 };
671 int i = 0;
672 if (rot3x3(1, 1) > rot3x3(0, 0))
673 i = 1;
674 if (rot3x3(2, 2) > rot3x3(i, i))
675 i = 2;
676 int j = s_next[i];
677 int k = s_next[j];
678
679 const float s = 2.0f * std::sqrt(x: rot3x3(i, i) - rot3x3(j, j) - rot3x3(k, k) + 1.0f);
680 axis[i] = 0.25f * s;
681 scalar = (rot3x3(k, j) - rot3x3(j, k)) / s;
682 axis[j] = (rot3x3(j, i) + rot3x3(i, j)) / s;
683 axis[k] = (rot3x3(k, i) + rot3x3(i, k)) / s;
684 }
685
686 return QQuaternion(scalar, axis[0], axis[1], axis[2]);
687}
688
689#ifndef QT_NO_VECTOR3D
690
691/*!
692 \since 5.5
693
694 Returns the 3 orthonormal axes (\a xAxis, \a yAxis, \a zAxis) defining the quaternion.
695
696 \sa fromAxes(), toRotationMatrix()
697*/
698void QQuaternion::getAxes(QVector3D *xAxis, QVector3D *yAxis, QVector3D *zAxis) const
699{
700 Q_ASSERT(xAxis && yAxis && zAxis);
701
702 const QMatrix3x3 rot3x3(toRotationMatrix());
703
704 *xAxis = QVector3D(rot3x3(0, 0), rot3x3(1, 0), rot3x3(2, 0));
705 *yAxis = QVector3D(rot3x3(0, 1), rot3x3(1, 1), rot3x3(2, 1));
706 *zAxis = QVector3D(rot3x3(0, 2), rot3x3(1, 2), rot3x3(2, 2));
707}
708
709/*!
710 \since 5.5
711
712 Constructs the quaternion using 3 axes (\a xAxis, \a yAxis, \a zAxis).
713
714 \note The axes are assumed to be orthonormal.
715
716 \sa getAxes(), fromRotationMatrix()
717*/
718QQuaternion QQuaternion::fromAxes(const QVector3D &xAxis, const QVector3D &yAxis, const QVector3D &zAxis)
719{
720 QMatrix3x3 rot3x3(Qt::Uninitialized);
721 rot3x3(0, 0) = xAxis.x();
722 rot3x3(1, 0) = xAxis.y();
723 rot3x3(2, 0) = xAxis.z();
724 rot3x3(0, 1) = yAxis.x();
725 rot3x3(1, 1) = yAxis.y();
726 rot3x3(2, 1) = yAxis.z();
727 rot3x3(0, 2) = zAxis.x();
728 rot3x3(1, 2) = zAxis.y();
729 rot3x3(2, 2) = zAxis.z();
730
731 return QQuaternion::fromRotationMatrix(rot3x3);
732}
733
734/*!
735 \since 5.5
736
737 Constructs the quaternion using specified forward direction \a direction
738 and upward direction \a up.
739 If the upward direction was not specified or the forward and upward
740 vectors are collinear, a new orthonormal upward direction will be generated.
741
742 \sa fromAxes(), rotationTo()
743*/
744QQuaternion QQuaternion::fromDirection(const QVector3D &direction, const QVector3D &up)
745{
746 if (qFuzzyIsNull(f: direction.x()) && qFuzzyIsNull(f: direction.y()) && qFuzzyIsNull(f: direction.z()))
747 return QQuaternion();
748
749 const QVector3D zAxis(direction.normalized());
750 QVector3D xAxis(QVector3D::crossProduct(v1: up, v2: zAxis));
751 if (qFuzzyIsNull(f: xAxis.lengthSquared())) {
752 // collinear or invalid up vector; derive shortest arc to new direction
753 return QQuaternion::rotationTo(from: QVector3D(0.0f, 0.0f, 1.0f), to: zAxis);
754 }
755
756 xAxis.normalize();
757 const QVector3D yAxis(QVector3D::crossProduct(v1: zAxis, v2: xAxis));
758
759 return QQuaternion::fromAxes(xAxis, yAxis, zAxis);
760}
761
762/*!
763 \since 5.5
764
765 Returns the shortest arc quaternion to rotate from the direction described by the vector \a from
766 to the direction described by the vector \a to.
767
768 \sa fromDirection()
769*/
770QQuaternion QQuaternion::rotationTo(const QVector3D &from, const QVector3D &to)
771{
772 // Based on Stan Melax's article in Game Programming Gems
773
774 const QVector3D v0(from.normalized());
775 const QVector3D v1(to.normalized());
776
777 float d = QVector3D::dotProduct(v1: v0, v2: v1) + 1.0f;
778
779 // if dest vector is close to the inverse of source vector, ANY axis of rotation is valid
780 if (qFuzzyIsNull(f: d)) {
781 QVector3D axis = QVector3D::crossProduct(v1: QVector3D(1.0f, 0.0f, 0.0f), v2: v0);
782 if (qFuzzyIsNull(f: axis.lengthSquared()))
783 axis = QVector3D::crossProduct(v1: QVector3D(0.0f, 1.0f, 0.0f), v2: v0);
784 axis.normalize();
785
786 // same as QQuaternion::fromAxisAndAngle(axis, 180.0f)
787 return QQuaternion(0.0f, axis.x(), axis.y(), axis.z());
788 }
789
790 d = std::sqrt(x: 2.0f * d);
791 const QVector3D axis(QVector3D::crossProduct(v1: v0, v2: v1) / d);
792
793 return QQuaternion(d * 0.5f, axis).normalized();
794}
795
796#endif // QT_NO_VECTOR3D
797
798/*!
799 \fn bool operator==(const QQuaternion &q1, const QQuaternion &q2)
800 \relates QQuaternion
801
802 Returns \c true if \a q1 is equal to \a q2; otherwise returns \c false.
803 This operator uses an exact floating-point comparison.
804*/
805
806/*!
807 \fn bool operator!=(const QQuaternion &q1, const QQuaternion &q2)
808 \relates QQuaternion
809
810 Returns \c true if \a q1 is not equal to \a q2; otherwise returns \c false.
811 This operator uses an exact floating-point comparison.
812*/
813
814/*!
815 \fn const QQuaternion operator+(const QQuaternion &q1, const QQuaternion &q2)
816 \relates QQuaternion
817
818 Returns a QQuaternion object that is the sum of the given quaternions,
819 \a q1 and \a q2; each component is added separately.
820
821 \sa QQuaternion::operator+=()
822*/
823
824/*!
825 \fn const QQuaternion operator-(const QQuaternion &q1, const QQuaternion &q2)
826 \relates QQuaternion
827
828 Returns a QQuaternion object that is formed by subtracting
829 \a q2 from \a q1; each component is subtracted separately.
830
831 \sa QQuaternion::operator-=()
832*/
833
834/*!
835 \fn const QQuaternion operator*(float factor, const QQuaternion &quaternion)
836 \relates QQuaternion
837
838 Returns a copy of the given \a quaternion, multiplied by the
839 given \a factor.
840
841 \sa QQuaternion::operator*=()
842*/
843
844/*!
845 \fn const QQuaternion operator*(const QQuaternion &quaternion, float factor)
846 \relates QQuaternion
847
848 Returns a copy of the given \a quaternion, multiplied by the
849 given \a factor.
850
851 \sa QQuaternion::operator*=()
852*/
853
854/*!
855 \fn const QQuaternion operator*(const QQuaternion &q1, const QQuaternion& q2)
856 \relates QQuaternion
857
858 Multiplies \a q1 and \a q2 using quaternion multiplication.
859 The result corresponds to applying both of the rotations specified
860 by \a q1 and \a q2.
861
862 \sa QQuaternion::operator*=()
863*/
864
865/*!
866 \fn const QQuaternion operator-(const QQuaternion &quaternion)
867 \relates QQuaternion
868 \overload
869
870 Returns a QQuaternion object that is formed by changing the sign of
871 all three components of the given \a quaternion.
872
873 Equivalent to \c {QQuaternion(0,0,0,0) - quaternion}.
874*/
875
876/*!
877 \fn const QQuaternion operator/(const QQuaternion &quaternion, float divisor)
878 \relates QQuaternion
879
880 Returns the QQuaternion object formed by dividing all components of
881 the given \a quaternion by the given \a divisor.
882
883 \sa QQuaternion::operator/=()
884*/
885
886#ifndef QT_NO_VECTOR3D
887
888/*!
889 \fn QVector3D operator*(const QQuaternion &quaternion, const QVector3D &vec)
890 \since 5.5
891 \relates QQuaternion
892
893 Rotates a vector \a vec with a quaternion \a quaternion to produce a new vector in 3D space.
894*/
895
896#endif
897
898/*!
899 \fn bool qFuzzyCompare(const QQuaternion& q1, const QQuaternion& q2)
900 \relates QQuaternion
901
902 Returns \c true if \a q1 and \a q2 are equal, allowing for a small
903 fuzziness factor for floating-point comparisons; false otherwise.
904*/
905
906/*!
907 Interpolates along the shortest spherical path between the
908 rotational positions \a q1 and \a q2. The value \a t should
909 be between 0 and 1, indicating the spherical distance to travel
910 between \a q1 and \a q2.
911
912 If \a t is less than or equal to 0, then \a q1 will be returned.
913 If \a t is greater than or equal to 1, then \a q2 will be returned.
914
915 \sa nlerp()
916*/
917QQuaternion QQuaternion::slerp
918 (const QQuaternion& q1, const QQuaternion& q2, float t)
919{
920 // Handle the easy cases first.
921 if (t <= 0.0f)
922 return q1;
923 else if (t >= 1.0f)
924 return q2;
925
926 // Determine the angle between the two quaternions.
927 QQuaternion q2b(q2);
928 float dot = QQuaternion::dotProduct(q1, q2);
929 if (dot < 0.0f) {
930 q2b = -q2b;
931 dot = -dot;
932 }
933
934 // Get the scale factors. If they are too small,
935 // then revert to simple linear interpolation.
936 float factor1 = 1.0f - t;
937 float factor2 = t;
938 if ((1.0f - dot) > 0.0000001) {
939 float angle = std::acos(x: dot);
940 float sinOfAngle = std::sin(x: angle);
941 if (sinOfAngle > 0.0000001) {
942 factor1 = std::sin(x: (1.0f - t) * angle) / sinOfAngle;
943 factor2 = std::sin(x: t * angle) / sinOfAngle;
944 }
945 }
946
947 // Construct the result quaternion.
948 return q1 * factor1 + q2b * factor2;
949}
950
951/*!
952 Interpolates along the shortest linear path between the rotational
953 positions \a q1 and \a q2. The value \a t should be between 0 and 1,
954 indicating the distance to travel between \a q1 and \a q2.
955 The result will be normalized().
956
957 If \a t is less than or equal to 0, then \a q1 will be returned.
958 If \a t is greater than or equal to 1, then \a q2 will be returned.
959
960 The nlerp() function is typically faster than slerp() and will
961 give approximate results to spherical interpolation that are
962 good enough for some applications.
963
964 \sa slerp()
965*/
966QQuaternion QQuaternion::nlerp
967 (const QQuaternion& q1, const QQuaternion& q2, float t)
968{
969 // Handle the easy cases first.
970 if (t <= 0.0f)
971 return q1;
972 else if (t >= 1.0f)
973 return q2;
974
975 // Determine the angle between the two quaternions.
976 QQuaternion q2b(q2);
977 float dot = QQuaternion::dotProduct(q1, q2);
978 if (dot < 0.0f)
979 q2b = -q2b;
980
981 // Perform the linear interpolation.
982 return (q1 * (1.0f - t) + q2b * t).normalized();
983}
984
985/*!
986 Returns the quaternion as a QVariant.
987*/
988QQuaternion::operator QVariant() const
989{
990 return QVariant(QMetaType::QQuaternion, this);
991}
992
993#ifndef QT_NO_DEBUG_STREAM
994
995QDebug operator<<(QDebug dbg, const QQuaternion &q)
996{
997 QDebugStateSaver saver(dbg);
998 dbg.nospace() << "QQuaternion(scalar:" << q.scalar()
999 << ", vector:(" << q.x() << ", "
1000 << q.y() << ", " << q.z() << "))";
1001 return dbg;
1002}
1003
1004#endif
1005
1006#ifndef QT_NO_DATASTREAM
1007
1008/*!
1009 \fn QDataStream &operator<<(QDataStream &stream, const QQuaternion &quaternion)
1010 \relates QQuaternion
1011
1012 Writes the given \a quaternion to the given \a stream and returns a
1013 reference to the stream.
1014
1015 \sa {Serializing Qt Data Types}
1016*/
1017
1018QDataStream &operator<<(QDataStream &stream, const QQuaternion &quaternion)
1019{
1020 stream << quaternion.scalar() << quaternion.x()
1021 << quaternion.y() << quaternion.z();
1022 return stream;
1023}
1024
1025/*!
1026 \fn QDataStream &operator>>(QDataStream &stream, QQuaternion &quaternion)
1027 \relates QQuaternion
1028
1029 Reads a quaternion from the given \a stream into the given \a quaternion
1030 and returns a reference to the stream.
1031
1032 \sa {Serializing Qt Data Types}
1033*/
1034
1035QDataStream &operator>>(QDataStream &stream, QQuaternion &quaternion)
1036{
1037 float scalar, x, y, z;
1038 stream >> scalar;
1039 stream >> x;
1040 stream >> y;
1041 stream >> z;
1042 quaternion.setScalar(scalar);
1043 quaternion.setX(x);
1044 quaternion.setY(y);
1045 quaternion.setZ(z);
1046 return stream;
1047}
1048
1049#endif // QT_NO_DATASTREAM
1050
1051#endif
1052
1053QT_END_NAMESPACE
1054

source code of qtbase/src/gui/math3d/qquaternion.cpp