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

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