1 | // Copyright (C) 2020 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
3 | |
4 | #include "qquick3dquaternionutils_p.h" |
5 | #include <QtQuick3DUtils/private/qssgutils_p.h> |
6 | #include <QtMath> |
7 | |
8 | QT_BEGIN_NAMESPACE |
9 | |
10 | /*! |
11 | \qmltype Quaternion |
12 | \inqmlmodule QtQuick3D |
13 | \since 5.15 |
14 | |
15 | \brief Provides utility functions for quaternion. |
16 | |
17 | The \c Quaternion is a global object with utility functions. |
18 | |
19 | It is not instantiable; to use it, call the members of the global \c Quaternion object |
20 | directly. For example: |
21 | |
22 | \qml |
23 | Node { |
24 | rotation: Quaternion.fromAxisAndAngle(Qt.vector3d(1, 0, 0), 45) |
25 | } |
26 | \endqml |
27 | */ |
28 | |
29 | /*! |
30 | \qmlmethod quaternion QtQuick3D::Quaternion::fromAxisAndAngle(vector3d axis, real angle) |
31 | Creates a quaternion from \a axis and \a angle. |
32 | Returns the resulting quaternion. |
33 | */ |
34 | |
35 | /*! |
36 | \qmlmethod quaternion QtQuick3D::Quaternion::fromAxisAndAngle(real x, real y, real z, real angle) |
37 | Creates a quaternion from \a x, \a y, \a z, and \a angle. |
38 | Returns the resulting quaternion. |
39 | */ |
40 | |
41 | /*! |
42 | \qmlmethod quaternion QtQuick3D::Quaternion::fromAxesAndAngles(vector3d axis1, real angle1, |
43 | vector3d axis2, real angle2) |
44 | Creates a quaternion from \a axis1, \a angle1, \a axis2, and \a angle2. |
45 | Returns the resulting quaternion. |
46 | */ |
47 | |
48 | /*! |
49 | \qmlmethod quaternion QtQuick3D::Quaternion::fromAxesAndAngles(vector3d axis1, real angle1, |
50 | vector3d axis2, real angle2, |
51 | vector3d axis3, real angle3) |
52 | Creates a quaternion from \a axis1, \a angle1, \a axis2, \a angle2, \a axis3, and \a angle3. |
53 | Returns the resulting quaternion. |
54 | */ |
55 | |
56 | /*! |
57 | \qmlmethod quaternion QtQuick3D::Quaternion::fromEulerAngles(vector3d eulerAngles) |
58 | Creates a quaternion from \a eulerAngles. |
59 | Returns the resulting quaternion. |
60 | */ |
61 | |
62 | /*! |
63 | \qmlmethod quaternion QtQuick3D::Quaternion::fromEulerAngles(real x, real y, real z) |
64 | Creates a quaternion from \a x, \a y, and \a z. |
65 | Returns the resulting quaternion. |
66 | */ |
67 | |
68 | /*! |
69 | \qmlmethod quaternion QtQuick3D::Quaternion::lookAt(vector3d sourcePosition, vector3d targetPosition, |
70 | vector3d forwardDirection, vector3d upDirection) |
71 | Creates a quaternion from \a sourcePosition, \a targetPosition, \a forwardDirection, and |
72 | \a upDirection. This is used for getting a rotation value for pointing at a particular target, |
73 | and can be used to point a camera at a position in a scene. |
74 | |
75 | \a forwardDirection defaults to \c Qt.vector3d(0, 0, -1) |
76 | \a upDirection defaults to \c Qt.vector3d(0, 1, 0) |
77 | |
78 | Returns the resulting quaternion. |
79 | */ |
80 | |
81 | QQuick3DQuaternionUtils::QQuick3DQuaternionUtils(QObject *parent) : QObject(parent) |
82 | { |
83 | |
84 | } |
85 | |
86 | QQuaternion QQuick3DQuaternionUtils::fromAxisAndAngle(float x, float y, float z, float angle) |
87 | { |
88 | return QQuaternion::fromAxisAndAngle(x, y, z, angle); |
89 | } |
90 | |
91 | QQuaternion QQuick3DQuaternionUtils::fromAxisAndAngle(const QVector3D &axis, float angle) |
92 | { |
93 | return QQuaternion::fromAxisAndAngle(axis, angle); |
94 | } |
95 | |
96 | QQuaternion QQuick3DQuaternionUtils::fromEulerAngles(float x, float y, float z) |
97 | { |
98 | return QQuaternion::fromEulerAngles(pitch: x, yaw: y, roll: z); |
99 | } |
100 | |
101 | QQuaternion QQuick3DQuaternionUtils::fromEulerAngles(const QVector3D &eulerAngles) |
102 | { |
103 | return QQuaternion::fromEulerAngles(eulerAngles); |
104 | } |
105 | |
106 | QQuaternion QQuick3DQuaternionUtils::lookAt(const QVector3D &sourcePosition, |
107 | const QVector3D &targetPosition, |
108 | const QVector3D &forwardDirection, |
109 | const QVector3D &upDirection) |
110 | { |
111 | QVector3D targetDirection = targetPosition - sourcePosition; |
112 | targetDirection.normalize(); |
113 | |
114 | QVector3D rotationAxis = QVector3D::crossProduct(v1: forwardDirection, v2: targetDirection); |
115 | |
116 | const QVector3D normalizedAxis = rotationAxis.normalized(); |
117 | if (qFuzzyIsNull(f: normalizedAxis.lengthSquared())) |
118 | rotationAxis = upDirection; |
119 | |
120 | float dot = QVector3D::dotProduct(v1: forwardDirection, v2: targetDirection); |
121 | float rotationAngle = qRadiansToDegrees(radians: qAcos(v: dot)); |
122 | |
123 | return QQuaternion::fromAxisAndAngle(axis: rotationAxis, angle: rotationAngle); |
124 | } |
125 | |
126 | QQuaternion QQuick3DQuaternionUtils::fromAxesAndAngles(const QVector3D &axis1, |
127 | float angle1, |
128 | const QVector3D &axis2, |
129 | float angle2, |
130 | const QVector3D &axis3, |
131 | float angle3) |
132 | { |
133 | const QQuaternion q1 = QQuaternion::fromAxisAndAngle(axis: axis1, angle: angle1); |
134 | const QQuaternion q2 = QQuaternion::fromAxisAndAngle(axis: axis2, angle: angle2); |
135 | const QQuaternion q3 = QQuaternion::fromAxisAndAngle(axis: axis3, angle: angle3); |
136 | return q3 * q2 * q1; |
137 | } |
138 | |
139 | QQuaternion QQuick3DQuaternionUtils::fromAxesAndAngles(const QVector3D &axis1, |
140 | float angle1, |
141 | const QVector3D &axis2, |
142 | float angle2) |
143 | { |
144 | const QQuaternion q1 = QQuaternion::fromAxisAndAngle(axis: axis1, angle: angle1); |
145 | const QQuaternion q2 = QQuaternion::fromAxisAndAngle(axis: axis2, angle: angle2); |
146 | return q2 * q1; |
147 | } |
148 | |
149 | QT_END_NAMESPACE |
150 | |