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#ifndef QQUATERNION_H
41#define QQUATERNION_H
42
43#include <QtGui/qtguiglobal.h>
44#include <QtGui/qgenericmatrix.h>
45#include <QtGui/qvector3d.h>
46#include <QtGui/qvector4d.h>
47
48QT_BEGIN_NAMESPACE
49
50
51#ifndef QT_NO_QUATERNION
52
53class QMatrix4x4;
54class QVariant;
55
56class Q_GUI_EXPORT QQuaternion
57{
58public:
59 QQuaternion();
60 explicit QQuaternion(Qt::Initialization) {}
61 QQuaternion(float scalar, float xpos, float ypos, float zpos);
62#ifndef QT_NO_VECTOR3D
63 QQuaternion(float scalar, const QVector3D& vector);
64#endif
65#ifndef QT_NO_VECTOR4D
66 explicit QQuaternion(const QVector4D& vector);
67#endif
68
69 bool isNull() const;
70 bool isIdentity() const;
71
72#ifndef QT_NO_VECTOR3D
73 QVector3D vector() const;
74 void setVector(const QVector3D& vector);
75#endif
76 void setVector(float x, float y, float z);
77
78 float x() const;
79 float y() const;
80 float z() const;
81 float scalar() const;
82
83 void setX(float x);
84 void setY(float y);
85 void setZ(float z);
86 void setScalar(float scalar);
87
88 constexpr static inline float dotProduct(const QQuaternion &q1, const QQuaternion &q2);
89
90 float length() const;
91 float lengthSquared() const;
92
93 [[nodiscard]] QQuaternion normalized() const;
94 void normalize();
95
96 inline QQuaternion inverted() const;
97
98 [[nodiscard]] QQuaternion conjugated() const;
99
100 QVector3D rotatedVector(const QVector3D& vector) const;
101
102 QQuaternion &operator+=(const QQuaternion &quaternion);
103 QQuaternion &operator-=(const QQuaternion &quaternion);
104 QQuaternion &operator*=(float factor);
105 QQuaternion &operator*=(const QQuaternion &quaternion);
106 QQuaternion &operator/=(float divisor);
107
108 friend inline bool operator==(const QQuaternion &q1, const QQuaternion &q2);
109 friend inline bool operator!=(const QQuaternion &q1, const QQuaternion &q2);
110 friend inline const QQuaternion operator+(const QQuaternion &q1, const QQuaternion &q2);
111 friend inline const QQuaternion operator-(const QQuaternion &q1, const QQuaternion &q2);
112 friend inline const QQuaternion operator*(float factor, const QQuaternion &quaternion);
113 friend inline const QQuaternion operator*(const QQuaternion &quaternion, float factor);
114 friend inline const QQuaternion operator*(const QQuaternion &q1, const QQuaternion& q2);
115 friend inline const QQuaternion operator-(const QQuaternion &quaternion);
116 friend inline const QQuaternion operator/(const QQuaternion &quaternion, float divisor);
117
118 friend inline bool qFuzzyCompare(const QQuaternion& q1, const QQuaternion& q2);
119
120#ifndef QT_NO_VECTOR4D
121 QVector4D toVector4D() const;
122#endif
123
124 operator QVariant() const;
125
126#ifndef QT_NO_VECTOR3D
127 inline void getAxisAndAngle(QVector3D *axis, float *angle) const;
128 static QQuaternion fromAxisAndAngle(const QVector3D& axis, float angle);
129#endif
130 void getAxisAndAngle(float *x, float *y, float *z, float *angle) const;
131 static QQuaternion fromAxisAndAngle
132 (float x, float y, float z, float angle);
133
134#ifndef QT_NO_VECTOR3D
135 inline QVector3D toEulerAngles() const;
136 static inline QQuaternion fromEulerAngles(const QVector3D &eulerAngles);
137#endif
138 void getEulerAngles(float *pitch, float *yaw, float *roll) const;
139 static QQuaternion fromEulerAngles(float pitch, float yaw, float roll);
140
141 QMatrix3x3 toRotationMatrix() const;
142 static QQuaternion fromRotationMatrix(const QMatrix3x3 &rot3x3);
143
144#ifndef QT_NO_VECTOR3D
145 void getAxes(QVector3D *xAxis, QVector3D *yAxis, QVector3D *zAxis) const;
146 static QQuaternion fromAxes(const QVector3D &xAxis, const QVector3D &yAxis, const QVector3D &zAxis);
147
148 static QQuaternion fromDirection(const QVector3D &direction, const QVector3D &up);
149
150 static QQuaternion rotationTo(const QVector3D &from, const QVector3D &to);
151#endif
152
153 static QQuaternion slerp
154 (const QQuaternion& q1, const QQuaternion& q2, float t);
155 static QQuaternion nlerp
156 (const QQuaternion& q1, const QQuaternion& q2, float t);
157
158private:
159 float wp, xp, yp, zp;
160};
161
162Q_DECLARE_TYPEINFO(QQuaternion, Q_MOVABLE_TYPE);
163
164inline QQuaternion::QQuaternion() : wp(1.0f), xp(0.0f), yp(0.0f), zp(0.0f) {}
165
166inline QQuaternion::QQuaternion(float aScalar, float xpos, float ypos, float zpos) : wp(aScalar), xp(xpos), yp(ypos), zp(zpos) {}
167
168QT_WARNING_PUSH
169QT_WARNING_DISABLE_FLOAT_COMPARE
170
171inline bool QQuaternion::isNull() const
172{
173 return wp == 0.0f && xp == 0.0f && yp == 0.0f && zp == 0.0f;
174}
175
176inline bool QQuaternion::isIdentity() const
177{
178 return wp == 1.0f && xp == 0.0f && yp == 0.0f && zp == 0.0f;
179}
180
181inline bool operator==(const QQuaternion &q1, const QQuaternion &q2)
182{
183 return q1.wp == q2.wp && q1.xp == q2.xp && q1.yp == q2.yp && q1.zp == q2.zp;
184}
185QT_WARNING_POP
186
187inline float QQuaternion::x() const { return xp; }
188inline float QQuaternion::y() const { return yp; }
189inline float QQuaternion::z() const { return zp; }
190inline float QQuaternion::scalar() const { return wp; }
191
192inline void QQuaternion::setX(float aX) { xp = aX; }
193inline void QQuaternion::setY(float aY) { yp = aY; }
194inline void QQuaternion::setZ(float aZ) { zp = aZ; }
195inline void QQuaternion::setScalar(float aScalar) { wp = aScalar; }
196
197constexpr inline float QQuaternion::dotProduct(const QQuaternion &q1, const QQuaternion &q2)
198{
199 return q1.wp * q2.wp + q1.xp * q2.xp + q1.yp * q2.yp + q1.zp * q2.zp;
200}
201
202inline QQuaternion QQuaternion::inverted() const
203{
204 // Need some extra precision if the length is very small.
205 double len = double(wp) * double(wp) +
206 double(xp) * double(xp) +
207 double(yp) * double(yp) +
208 double(zp) * double(zp);
209 if (!qFuzzyIsNull(len))
210 return QQuaternion(float(double(wp) / len), float(double(-xp) / len),
211 float(double(-yp) / len), float(double(-zp) / len));
212 return QQuaternion(0.0f, 0.0f, 0.0f, 0.0f);
213}
214
215inline QQuaternion QQuaternion::conjugated() const
216{
217 return QQuaternion(wp, -xp, -yp, -zp);
218}
219
220inline QQuaternion &QQuaternion::operator+=(const QQuaternion &quaternion)
221{
222 wp += quaternion.wp;
223 xp += quaternion.xp;
224 yp += quaternion.yp;
225 zp += quaternion.zp;
226 return *this;
227}
228
229inline QQuaternion &QQuaternion::operator-=(const QQuaternion &quaternion)
230{
231 wp -= quaternion.wp;
232 xp -= quaternion.xp;
233 yp -= quaternion.yp;
234 zp -= quaternion.zp;
235 return *this;
236}
237
238inline QQuaternion &QQuaternion::operator*=(float factor)
239{
240 wp *= factor;
241 xp *= factor;
242 yp *= factor;
243 zp *= factor;
244 return *this;
245}
246
247inline const QQuaternion operator*(const QQuaternion &q1, const QQuaternion& q2)
248{
249 float yy = (q1.wp - q1.yp) * (q2.wp + q2.zp);
250 float zz = (q1.wp + q1.yp) * (q2.wp - q2.zp);
251 float ww = (q1.zp + q1.xp) * (q2.xp + q2.yp);
252 float xx = ww + yy + zz;
253 float qq = 0.5f * (xx + (q1.zp - q1.xp) * (q2.xp - q2.yp));
254
255 float w = qq - ww + (q1.zp - q1.yp) * (q2.yp - q2.zp);
256 float x = qq - xx + (q1.xp + q1.wp) * (q2.xp + q2.wp);
257 float y = qq - yy + (q1.wp - q1.xp) * (q2.yp + q2.zp);
258 float z = qq - zz + (q1.zp + q1.yp) * (q2.wp - q2.xp);
259
260 return QQuaternion(w, x, y, z);
261}
262
263inline QQuaternion &QQuaternion::operator*=(const QQuaternion &quaternion)
264{
265 *this = *this * quaternion;
266 return *this;
267}
268
269inline QQuaternion &QQuaternion::operator/=(float divisor)
270{
271 wp /= divisor;
272 xp /= divisor;
273 yp /= divisor;
274 zp /= divisor;
275 return *this;
276}
277
278inline bool operator!=(const QQuaternion &q1, const QQuaternion &q2)
279{
280 return !operator==(q1, q2);
281}
282
283inline const QQuaternion operator+(const QQuaternion &q1, const QQuaternion &q2)
284{
285 return QQuaternion(q1.wp + q2.wp, q1.xp + q2.xp, q1.yp + q2.yp, q1.zp + q2.zp);
286}
287
288inline const QQuaternion operator-(const QQuaternion &q1, const QQuaternion &q2)
289{
290 return QQuaternion(q1.wp - q2.wp, q1.xp - q2.xp, q1.yp - q2.yp, q1.zp - q2.zp);
291}
292
293inline const QQuaternion operator*(float factor, const QQuaternion &quaternion)
294{
295 return QQuaternion(quaternion.wp * factor, quaternion.xp * factor, quaternion.yp * factor, quaternion.zp * factor);
296}
297
298inline const QQuaternion operator*(const QQuaternion &quaternion, float factor)
299{
300 return QQuaternion(quaternion.wp * factor, quaternion.xp * factor, quaternion.yp * factor, quaternion.zp * factor);
301}
302
303inline const QQuaternion operator-(const QQuaternion &quaternion)
304{
305 return QQuaternion(-quaternion.wp, -quaternion.xp, -quaternion.yp, -quaternion.zp);
306}
307
308inline const QQuaternion operator/(const QQuaternion &quaternion, float divisor)
309{
310 return QQuaternion(quaternion.wp / divisor, quaternion.xp / divisor, quaternion.yp / divisor, quaternion.zp / divisor);
311}
312
313inline bool qFuzzyCompare(const QQuaternion& q1, const QQuaternion& q2)
314{
315 return qFuzzyCompare(q1.wp, q2.wp) &&
316 qFuzzyCompare(q1.xp, q2.xp) &&
317 qFuzzyCompare(q1.yp, q2.yp) &&
318 qFuzzyCompare(q1.zp, q2.zp);
319}
320
321#ifndef QT_NO_VECTOR3D
322
323inline QQuaternion::QQuaternion(float aScalar, const QVector3D& aVector)
324 : wp(aScalar), xp(aVector.x()), yp(aVector.y()), zp(aVector.z()) {}
325
326inline void QQuaternion::setVector(const QVector3D& aVector)
327{
328 xp = aVector.x();
329 yp = aVector.y();
330 zp = aVector.z();
331}
332
333inline QVector3D QQuaternion::vector() const
334{
335 return QVector3D(xp, yp, zp);
336}
337
338inline QVector3D operator*(const QQuaternion &quaternion, const QVector3D &vec)
339{
340 return quaternion.rotatedVector(vec);
341}
342
343inline void QQuaternion::getAxisAndAngle(QVector3D *axis, float *angle) const
344{
345 float aX, aY, aZ;
346 getAxisAndAngle(&aX, &aY, &aZ, angle);
347 *axis = QVector3D(aX, aY, aZ);
348}
349
350inline QVector3D QQuaternion::toEulerAngles() const
351{
352 float pitch, yaw, roll;
353 getEulerAngles(&pitch, &yaw, &roll);
354 return QVector3D(pitch, yaw, roll);
355}
356
357inline QQuaternion QQuaternion::fromEulerAngles(const QVector3D &eulerAngles)
358{
359 return QQuaternion::fromEulerAngles(eulerAngles.x(), eulerAngles.y(), eulerAngles.z());
360}
361
362#endif
363
364inline void QQuaternion::setVector(float aX, float aY, float aZ)
365{
366 xp = aX;
367 yp = aY;
368 zp = aZ;
369}
370
371#ifndef QT_NO_VECTOR4D
372
373inline QQuaternion::QQuaternion(const QVector4D& aVector)
374 : wp(aVector.w()), xp(aVector.x()), yp(aVector.y()), zp(aVector.z()) {}
375
376inline QVector4D QQuaternion::toVector4D() const
377{
378 return QVector4D(xp, yp, zp, wp);
379}
380
381#endif
382
383#ifndef QT_NO_DEBUG_STREAM
384Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QQuaternion &q);
385#endif
386
387#ifndef QT_NO_DATASTREAM
388Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QQuaternion &);
389Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QQuaternion &);
390#endif
391
392#endif
393
394QT_END_NAMESPACE
395
396#endif
397