1/****************************************************************************
2**
3** Copyright (C) 2015 Konstantin Ritt.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt3D 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 QT3DCORE_QMATH3D_P_H
41#define QT3DCORE_QMATH3D_P_H
42
43//
44// W A R N I N G
45// -------------
46//
47// This file is not part of the Qt3D API. It exists purely as an
48// implementation detail. This header file may change from version to
49// version without notice, or even be removed.
50//
51// We mean it.
52//
53#include <QtGui/qmatrix4x4.h>
54#include <QtGui/qquaternion.h>
55#include <QtGui/qvector3d.h>
56#include <Qt3DCore/private/sqt_p.h>
57
58#include <cmath>
59
60QT_BEGIN_NAMESPACE
61
62inline void composeQMatrix4x4(const QVector3D &position, const QQuaternion &orientation, const QVector3D &scale, QMatrix4x4 &m)
63{
64 const QMatrix3x3 rot3x3(orientation.toRotationMatrix());
65
66 // set up final matrix with scale, rotation and translation
67 m(0, 0) = scale.x() * rot3x3(0, 0); m(0, 1) = scale.y() * rot3x3(0, 1); m(0, 2) = scale.z() * rot3x3(0, 2); m(0, 3) = position.x();
68 m(1, 0) = scale.x() * rot3x3(1, 0); m(1, 1) = scale.y() * rot3x3(1, 1); m(1, 2) = scale.z() * rot3x3(1, 2); m(1, 3) = position.y();
69 m(2, 0) = scale.x() * rot3x3(2, 0); m(2, 1) = scale.y() * rot3x3(2, 1); m(2, 2) = scale.z() * rot3x3(2, 2); m(2, 3) = position.z();
70 // no projection term
71 m(3, 0) = 0.0f; m(3, 1) = 0.0f; m(3, 2) = 0.0f; m(3, 3) = 1.0f;
72}
73
74inline void decomposeQMatrix3x3(const QMatrix3x3 &m, QMatrix3x3 &Q, QVector3D &D, QVector3D &U)
75{
76 // Factor M = QR = QDU where Q is orthogonal, D is diagonal,
77 // and U is upper triangular with ones on its diagonal.
78 // Algorithm uses Gram-Schmidt orthogonalization (the QR algorithm).
79 //
80 // If M = [ m0 | m1 | m2 ] and Q = [ q0 | q1 | q2 ], then
81 // q0 = m0/|m0|
82 // q1 = (m1-(q0*m1)q0)/|m1-(q0*m1)q0|
83 // q2 = (m2-(q0*m2)q0-(q1*m2)q1)/|m2-(q0*m2)q0-(q1*m2)q1|
84 //
85 // where |V| indicates length of vector V and A*B indicates dot
86 // product of vectors A and B. The matrix R has entries
87 //
88 // r00 = q0*m0 r01 = q0*m1 r02 = q0*m2
89 // r10 = 0 r11 = q1*m1 r12 = q1*m2
90 // r20 = 0 r21 = 0 r22 = q2*m2
91 //
92 // so D = diag(r00,r11,r22) and U has entries u01 = r01/r00,
93 // u02 = r02/r00, and u12 = r12/r11.
94
95 // Q = rotation
96 // D = scaling
97 // U = shear
98
99 // D stores the three diagonal entries r00, r11, r22
100 // U stores the entries U[0] = u01, U[1] = u02, U[2] = u12
101
102 // build orthogonal matrix Q
103 float invLen = 1.0f / std::sqrt(x: m(0, 0) * m(0, 0) + m(1, 0) * m(1, 0) + m(2, 0) * m(2, 0));
104 Q(0, 0) = m(0, 0) * invLen;
105 Q(1, 0) = m(1, 0) * invLen;
106 Q(2, 0) = m(2, 0) * invLen;
107
108 float dot = Q(0, 0) * m(0, 1) + Q(1, 0) * m(1, 1) + Q(2, 0) * m(2, 1);
109 Q(0, 1) = m(0, 1) - dot * Q(0, 0);
110 Q(1, 1) = m(1, 1) - dot * Q(1, 0);
111 Q(2, 1) = m(2, 1) - dot * Q(2, 0);
112 invLen = 1.0f / std::sqrt(x: Q(0, 1) * Q(0, 1) + Q(1, 1) * Q(1, 1) + Q(2, 1) * Q(2, 1));
113 Q(0, 1) *= invLen;
114 Q(1, 1) *= invLen;
115 Q(2, 1) *= invLen;
116
117 dot = Q(0, 0) * m(0, 2) + Q(1, 0) * m(1, 2) + Q(2, 0) * m(2, 2);
118 Q(0, 2) = m(0, 2) - dot * Q(0, 0);
119 Q(1, 2) = m(1, 2) - dot * Q(1, 0);
120 Q(2, 2) = m(2, 2) - dot * Q(2, 0);
121 dot = Q(0, 1) * m(0, 2) + Q(1, 1) * m(1, 2) + Q(2, 1) * m(2, 2);
122 Q(0, 2) -= dot * Q(0, 1);
123 Q(1, 2) -= dot * Q(1, 1);
124 Q(2, 2) -= dot * Q(2, 1);
125 invLen = 1.0f / std::sqrt(x: Q(0, 2) * Q(0, 2) + Q(1, 2) * Q(1, 2) + Q(2, 2) * Q(2, 2));
126 Q(0, 2) *= invLen;
127 Q(1, 2) *= invLen;
128 Q(2, 2) *= invLen;
129
130 // guarantee that orthogonal matrix has determinant 1 (no reflections)
131 const float det = Q(0, 0) * Q(1, 1) * Q(2, 2) + Q(0, 1) * Q(1, 2) * Q(2, 0) +
132 Q(0, 2) * Q(1, 0) * Q(2, 1) - Q(0, 2) * Q(1, 1) * Q(2, 0) -
133 Q(0, 1) * Q(1, 0) * Q(2, 2) - Q(0, 0) * Q(1, 2) * Q(2, 1);
134 if (det < 0.0f)
135 Q *= -1.0f;
136
137 // build "right" matrix R
138 QMatrix3x3 R(Qt::Uninitialized);
139 R(0, 0) = Q(0, 0) * m(0, 0) + Q(1, 0) * m(1, 0) + Q(2, 0) * m(2, 0);
140 R(0, 1) = Q(0, 0) * m(0, 1) + Q(1, 0) * m(1, 1) + Q(2, 0) * m(2, 1);
141 R(1, 1) = Q(0, 1) * m(0, 1) + Q(1, 1) * m(1, 1) + Q(2, 1) * m(2, 1);
142 R(0, 2) = Q(0, 0) * m(0, 2) + Q(1, 0) * m(1, 2) + Q(2, 0) * m(2, 2);
143 R(1, 2) = Q(0, 1) * m(0, 2) + Q(1, 1) * m(1, 2) + Q(2, 1) * m(2, 2);
144 R(2, 2) = Q(0, 2) * m(0, 2) + Q(1, 2) * m(1, 2) + Q(2, 2) * m(2, 2);
145
146 // the scaling component
147 D[0] = R(0, 0);
148 D[1] = R(1, 1);
149 D[2] = R(2, 2);
150
151 // the shear component
152 U[0] = R(0, 1) / D[0];
153 U[1] = R(0, 2) / D[0];
154 U[2] = R(1, 2) / D[1];
155}
156
157inline bool hasScale(const QMatrix4x4 &m)
158{
159 // If the columns are orthonormal and form a right-handed system, then there is no scale
160 float t(m.determinant());
161 if (!qFuzzyIsNull(f: t - 1.0f))
162 return true;
163 t = m(0, 0) * m(0, 0) + m(1, 0) * m(1, 0) + m(2, 0) * m(2, 0);
164 if (!qFuzzyIsNull(f: t - 1.0f))
165 return true;
166 t = m(0, 1) * m(0, 1) + m(1, 1) * m(1, 1) + m(2, 1) * m(2, 1);
167 if (!qFuzzyIsNull(f: t - 1.0f))
168 return true;
169 t = m(0, 2) * m(0, 2) + m(1, 2) * m(1, 2) + m(2, 2) * m(2, 2);
170 if (!qFuzzyIsNull(f: t - 1.0f))
171 return true;
172 return false;
173}
174
175inline void decomposeQMatrix4x4(const QMatrix4x4 &m, QVector3D &position, QQuaternion &orientation, QVector3D &scale)
176{
177 Q_ASSERT(m.isAffine());
178
179 const QMatrix3x3 m3x3(m.toGenericMatrix<3, 3>());
180
181 QMatrix3x3 rot3x3(Qt::Uninitialized);
182 if (hasScale(m)) {
183 decomposeQMatrix3x3(m: m3x3, Q&: rot3x3, D&: scale, U&: position);
184 } else {
185 // we know there is no scaling part; no need for QDU decomposition
186 scale = QVector3D(1.0f, 1.0f, 1.0f);
187 rot3x3 = m3x3;
188 }
189 orientation = QQuaternion::fromRotationMatrix(rot3x3);
190 position = QVector3D(m(0, 3), m(1, 3), m(2, 3));
191}
192
193inline void decomposeQMatrix4x4(const QMatrix4x4 &m, Qt3DCore::Sqt &sqt)
194{
195 Q_ASSERT(m.isAffine());
196
197 const QMatrix3x3 m3x3(m.toGenericMatrix<3, 3>());
198
199 QMatrix3x3 rot3x3(Qt::Uninitialized);
200 if (hasScale(m)) {
201 decomposeQMatrix3x3(m: m3x3, Q&: rot3x3, D&: sqt.scale, U&: sqt.translation);
202 } else {
203 // we know there is no scaling part; no need for QDU decomposition
204 sqt.scale = QVector3D(1.0f, 1.0f, 1.0f);
205 rot3x3 = m3x3;
206 }
207 sqt.rotation = QQuaternion::fromRotationMatrix(rot3x3);
208 sqt.translation = QVector3D(m(0, 3), m(1, 3), m(2, 3));
209}
210
211QT_END_NAMESPACE
212
213#endif // QT3DCORE_QMATH3D_P_H
214

source code of qt3d/src/core/transforms/qmath3d_p.h