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 "qmatrix4x4.h"
41#include <QtCore/qmath.h>
42#include <QtCore/qvariant.h>
43#include <QtGui/qmatrix.h>
44#include <QtGui/qtransform.h>
45
46#include <cmath>
47
48QT_BEGIN_NAMESPACE
49
50#ifndef QT_NO_MATRIX4X4
51
52/*!
53 \class QMatrix4x4
54 \brief The QMatrix4x4 class represents a 4x4 transformation matrix in 3D space.
55 \since 4.6
56 \ingroup painting-3D
57 \inmodule QtGui
58
59 The QMatrix4x4 class in general is treated as a row-major matrix, in that the
60 constructors and operator() functions take data in row-major format, as is
61 familiar in C-style usage.
62
63 Internally the data is stored as column-major format, so as to be optimal for
64 passing to OpenGL functions, which expect column-major data.
65
66 When using these functions be aware that they return data in \b{column-major}
67 format:
68 \list
69 \li data()
70 \li constData()
71 \endlist
72
73 \sa QVector3D, QGenericMatrix
74*/
75
76static const float inv_dist_to_plane = 1.0f / 1024.0f;
77
78/*!
79 \fn QMatrix4x4::QMatrix4x4()
80
81 Constructs an identity matrix.
82*/
83
84/*!
85 \fn QMatrix4x4::QMatrix4x4(Qt::Initialization)
86 \since 5.5
87 \internal
88
89 Constructs a matrix without initializing the contents.
90*/
91
92/*!
93 Constructs a matrix from the given 16 floating-point \a values.
94 The contents of the array \a values is assumed to be in
95 row-major order.
96
97 If the matrix has a special type (identity, translate, scale, etc),
98 the programmer should follow this constructor with a call to
99 optimize() if they wish QMatrix4x4 to optimize further
100 calls to translate(), scale(), etc.
101
102 \sa copyDataTo(), optimize()
103*/
104QMatrix4x4::QMatrix4x4(const float *values)
105{
106 for (int row = 0; row < 4; ++row)
107 for (int col = 0; col < 4; ++col)
108 m[col][row] = values[row * 4 + col];
109 flagBits = General;
110}
111
112/*!
113 \fn QMatrix4x4::QMatrix4x4(float m11, float m12, float m13, float m14, float m21, float m22, float m23, float m24, float m31, float m32, float m33, float m34, float m41, float m42, float m43, float m44)
114
115 Constructs a matrix from the 16 elements \a m11, \a m12, \a m13, \a m14,
116 \a m21, \a m22, \a m23, \a m24, \a m31, \a m32, \a m33, \a m34,
117 \a m41, \a m42, \a m43, and \a m44. The elements are specified in
118 row-major order.
119
120 If the matrix has a special type (identity, translate, scale, etc),
121 the programmer should follow this constructor with a call to
122 optimize() if they wish QMatrix4x4 to optimize further
123 calls to translate(), scale(), etc.
124
125 \sa optimize()
126*/
127
128/*!
129 \fn template <int N, int M> QMatrix4x4::QMatrix4x4(const QGenericMatrix<N, M, float>& matrix)
130
131 Constructs a 4x4 matrix from the left-most 4 columns and top-most
132 4 rows of \a matrix. If \a matrix has less than 4 columns or rows,
133 the remaining elements are filled with elements from the identity
134 matrix.
135
136 \sa toGenericMatrix()
137*/
138
139/*!
140 \fn QGenericMatrix<N, M, float> QMatrix4x4::toGenericMatrix() const
141
142 Constructs a NxM generic matrix from the left-most N columns and
143 top-most M rows of this 4x4 matrix. If N or M is greater than 4,
144 then the remaining elements are filled with elements from the
145 identity matrix.
146*/
147
148/*!
149 \fn template <int N, int M> QMatrix4x4 qGenericMatrixToMatrix4x4(const QGenericMatrix<N, M, float>& matrix)
150 \relates QMatrix4x4
151 \obsolete
152
153 Returns a 4x4 matrix constructed from the left-most 4 columns and
154 top-most 4 rows of \a matrix. If \a matrix has less than 4 columns
155 or rows, the remaining elements are filled with elements from the
156 identity matrix.
157*/
158
159/*!
160 \fn QGenericMatrix<N, M, float> qGenericMatrixFromMatrix4x4(const QMatrix4x4& matrix)
161 \relates QMatrix4x4
162 \obsolete
163
164 Returns a NxM generic matrix constructed from the left-most N columns
165 and top-most M rows of \a matrix. If N or M is greater than 4,
166 then the remaining elements are filled with elements from the
167 identity matrix.
168
169 \sa QMatrix4x4::toGenericMatrix()
170*/
171
172/*!
173 \internal
174*/
175QMatrix4x4::QMatrix4x4(const float *values, int cols, int rows)
176{
177 for (int col = 0; col < 4; ++col) {
178 for (int row = 0; row < 4; ++row) {
179 if (col < cols && row < rows)
180 m[col][row] = values[col * rows + row];
181 else if (col == row)
182 m[col][row] = 1.0f;
183 else
184 m[col][row] = 0.0f;
185 }
186 }
187 flagBits = General;
188}
189
190#if QT_DEPRECATED_SINCE(5, 15)
191/*!
192 \obsolete
193
194 Constructs a 4x4 matrix from a conventional Qt 2D affine
195 transformation \a matrix.
196
197 If \a matrix has a special type (identity, translate, scale, etc),
198 the programmer should follow this constructor with a call to
199 optimize() if they wish QMatrix4x4 to optimize further
200 calls to translate(), scale(), etc.
201
202 \sa toAffine(), optimize()
203*/
204QMatrix4x4::QMatrix4x4(const QMatrix& matrix)
205{
206 m[0][0] = matrix.m11();
207 m[0][1] = matrix.m12();
208 m[0][2] = 0.0f;
209 m[0][3] = 0.0f;
210 m[1][0] = matrix.m21();
211 m[1][1] = matrix.m22();
212 m[1][2] = 0.0f;
213 m[1][3] = 0.0f;
214 m[2][0] = 0.0f;
215 m[2][1] = 0.0f;
216 m[2][2] = 1.0f;
217 m[2][3] = 0.0f;
218 m[3][0] = matrix.dx();
219 m[3][1] = matrix.dy();
220 m[3][2] = 0.0f;
221 m[3][3] = 1.0f;
222 flagBits = Translation | Scale | Rotation2D;
223}
224#endif // QT_DEPRECATED_SINCE(5, 15)
225
226/*!
227 Constructs a 4x4 matrix from the conventional Qt 2D
228 transformation matrix \a transform.
229
230 If \a transform has a special type (identity, translate, scale, etc),
231 the programmer should follow this constructor with a call to
232 optimize() if they wish QMatrix4x4 to optimize further
233 calls to translate(), scale(), etc.
234
235 \sa toTransform(), optimize()
236*/
237QMatrix4x4::QMatrix4x4(const QTransform& transform)
238{
239 m[0][0] = transform.m11();
240 m[0][1] = transform.m12();
241 m[0][2] = 0.0f;
242 m[0][3] = transform.m13();
243 m[1][0] = transform.m21();
244 m[1][1] = transform.m22();
245 m[1][2] = 0.0f;
246 m[1][3] = transform.m23();
247 m[2][0] = 0.0f;
248 m[2][1] = 0.0f;
249 m[2][2] = 1.0f;
250 m[2][3] = 0.0f;
251 m[3][0] = transform.dx();
252 m[3][1] = transform.dy();
253 m[3][2] = 0.0f;
254 m[3][3] = transform.m33();
255 flagBits = General;
256}
257
258/*!
259 \fn const float& QMatrix4x4::operator()(int row, int column) const
260
261 Returns a constant reference to the element at position
262 (\a row, \a column) in this matrix.
263
264 \sa column(), row()
265*/
266
267/*!
268 \fn float& QMatrix4x4::operator()(int row, int column)
269
270 Returns a reference to the element at position (\a row, \a column)
271 in this matrix so that the element can be assigned to.
272
273 \sa optimize(), setColumn(), setRow()
274*/
275
276/*!
277 \fn QVector4D QMatrix4x4::column(int index) const
278
279 Returns the elements of column \a index as a 4D vector.
280
281 \sa setColumn(), row()
282*/
283
284/*!
285 \fn void QMatrix4x4::setColumn(int index, const QVector4D& value)
286
287 Sets the elements of column \a index to the components of \a value.
288
289 \sa column(), setRow()
290*/
291
292/*!
293 \fn QVector4D QMatrix4x4::row(int index) const
294
295 Returns the elements of row \a index as a 4D vector.
296
297 \sa setRow(), column()
298*/
299
300/*!
301 \fn void QMatrix4x4::setRow(int index, const QVector4D& value)
302
303 Sets the elements of row \a index to the components of \a value.
304
305 \sa row(), setColumn()
306*/
307
308/*!
309 \fn bool QMatrix4x4::isAffine() const
310 \since 5.5
311
312 Returns \c true if this matrix is affine matrix; false otherwise.
313
314 An affine matrix is a 4x4 matrix with row 3 equal to (0, 0, 0, 1),
315 e.g. no projective coefficients.
316
317 \sa isIdentity()
318*/
319
320/*!
321 \fn bool QMatrix4x4::isIdentity() const
322
323 Returns \c true if this matrix is the identity; false otherwise.
324
325 \sa setToIdentity()
326*/
327
328/*!
329 \fn void QMatrix4x4::setToIdentity()
330
331 Sets this matrix to the identity.
332
333 \sa isIdentity()
334*/
335
336/*!
337 \fn void QMatrix4x4::fill(float value)
338
339 Fills all elements of this matrx with \a value.
340*/
341
342static inline double matrixDet2(const double m[4][4], int col0, int col1, int row0, int row1)
343{
344 return m[col0][row0] * m[col1][row1] - m[col0][row1] * m[col1][row0];
345}
346
347
348// The 4x4 matrix inverse algorithm is based on that described at:
349// http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q24
350// Some optimization has been done to avoid making copies of 3x3
351// sub-matrices and to unroll the loops.
352
353// Calculate the determinant of a 3x3 sub-matrix.
354// | A B C |
355// M = | D E F | det(M) = A * (EI - HF) - B * (DI - GF) + C * (DH - GE)
356// | G H I |
357static inline double matrixDet3
358 (const double m[4][4], int col0, int col1, int col2,
359 int row0, int row1, int row2)
360{
361 return m[col0][row0] * matrixDet2(m, col0: col1, col1: col2, row0: row1, row1: row2)
362 - m[col1][row0] * matrixDet2(m, col0, col1: col2, row0: row1, row1: row2)
363 + m[col2][row0] * matrixDet2(m, col0, col1, row0: row1, row1: row2);
364}
365
366// Calculate the determinant of a 4x4 matrix.
367static inline double matrixDet4(const double m[4][4])
368{
369 double det;
370 det = m[0][0] * matrixDet3(m, col0: 1, col1: 2, col2: 3, row0: 1, row1: 2, row2: 3);
371 det -= m[1][0] * matrixDet3(m, col0: 0, col1: 2, col2: 3, row0: 1, row1: 2, row2: 3);
372 det += m[2][0] * matrixDet3(m, col0: 0, col1: 1, col2: 3, row0: 1, row1: 2, row2: 3);
373 det -= m[3][0] * matrixDet3(m, col0: 0, col1: 1, col2: 2, row0: 1, row1: 2, row2: 3);
374 return det;
375}
376
377static inline void copyToDoubles(const float m[4][4], double mm[4][4])
378{
379 for (int i = 0; i < 4; ++i)
380 for (int j = 0; j < 4; ++j)
381 mm[i][j] = double(m[i][j]);
382}
383
384/*!
385 Returns the determinant of this matrix.
386*/
387double QMatrix4x4::determinant() const
388{
389 if ((flagBits & ~(Translation | Rotation2D | Rotation)) == Identity)
390 return 1.0;
391
392 double mm[4][4];
393 copyToDoubles(m, mm);
394 if (flagBits < Rotation2D)
395 return mm[0][0] * mm[1][1] * mm[2][2]; // Translation | Scale
396 if (flagBits < Perspective)
397 return matrixDet3(m: mm, col0: 0, col1: 1, col2: 2, row0: 0, row1: 1, row2: 2);
398 return matrixDet4(m: mm);
399}
400
401/*!
402 Returns the inverse of this matrix. Returns the identity if
403 this matrix cannot be inverted; i.e. determinant() is zero.
404 If \a invertible is not null, then true will be written to
405 that location if the matrix can be inverted; false otherwise.
406
407 If the matrix is recognized as the identity or an orthonormal
408 matrix, then this function will quickly invert the matrix
409 using optimized routines.
410
411 \sa determinant(), normalMatrix()
412*/
413QMatrix4x4 QMatrix4x4::inverted(bool *invertible) const
414{
415 // Handle some of the easy cases first.
416 if (flagBits == Identity) {
417 if (invertible)
418 *invertible = true;
419 return QMatrix4x4();
420 } else if (flagBits == Translation) {
421 QMatrix4x4 inv;
422 inv.m[3][0] = -m[3][0];
423 inv.m[3][1] = -m[3][1];
424 inv.m[3][2] = -m[3][2];
425 inv.flagBits = Translation;
426 if (invertible)
427 *invertible = true;
428 return inv;
429 } else if (flagBits < Rotation2D) {
430 // Translation | Scale
431 if (m[0][0] == 0 || m[1][1] == 0 || m[2][2] == 0) {
432 if (invertible)
433 *invertible = false;
434 return QMatrix4x4();
435 }
436 QMatrix4x4 inv;
437 inv.m[0][0] = 1.0f / m[0][0];
438 inv.m[1][1] = 1.0f / m[1][1];
439 inv.m[2][2] = 1.0f / m[2][2];
440 inv.m[3][0] = -m[3][0] * inv.m[0][0];
441 inv.m[3][1] = -m[3][1] * inv.m[1][1];
442 inv.m[3][2] = -m[3][2] * inv.m[2][2];
443 inv.flagBits = flagBits;
444
445 if (invertible)
446 *invertible = true;
447 return inv;
448 } else if ((flagBits & ~(Translation | Rotation2D | Rotation)) == Identity) {
449 if (invertible)
450 *invertible = true;
451 return orthonormalInverse();
452 } else if (flagBits < Perspective) {
453 QMatrix4x4 inv(1); // The "1" says to not load the identity.
454
455 double mm[4][4];
456 copyToDoubles(m, mm);
457
458 double det = matrixDet3(m: mm, col0: 0, col1: 1, col2: 2, row0: 0, row1: 1, row2: 2);
459 if (det == 0.0f) {
460 if (invertible)
461 *invertible = false;
462 return QMatrix4x4();
463 }
464 det = 1.0f / det;
465
466 inv.m[0][0] = matrixDet2(m: mm, col0: 1, col1: 2, row0: 1, row1: 2) * det;
467 inv.m[0][1] = -matrixDet2(m: mm, col0: 0, col1: 2, row0: 1, row1: 2) * det;
468 inv.m[0][2] = matrixDet2(m: mm, col0: 0, col1: 1, row0: 1, row1: 2) * det;
469 inv.m[0][3] = 0;
470 inv.m[1][0] = -matrixDet2(m: mm, col0: 1, col1: 2, row0: 0, row1: 2) * det;
471 inv.m[1][1] = matrixDet2(m: mm, col0: 0, col1: 2, row0: 0, row1: 2) * det;
472 inv.m[1][2] = -matrixDet2(m: mm, col0: 0, col1: 1, row0: 0, row1: 2) * det;
473 inv.m[1][3] = 0;
474 inv.m[2][0] = matrixDet2(m: mm, col0: 1, col1: 2, row0: 0, row1: 1) * det;
475 inv.m[2][1] = -matrixDet2(m: mm, col0: 0, col1: 2, row0: 0, row1: 1) * det;
476 inv.m[2][2] = matrixDet2(m: mm, col0: 0, col1: 1, row0: 0, row1: 1) * det;
477 inv.m[2][3] = 0;
478 inv.m[3][0] = -inv.m[0][0] * m[3][0] - inv.m[1][0] * m[3][1] - inv.m[2][0] * m[3][2];
479 inv.m[3][1] = -inv.m[0][1] * m[3][0] - inv.m[1][1] * m[3][1] - inv.m[2][1] * m[3][2];
480 inv.m[3][2] = -inv.m[0][2] * m[3][0] - inv.m[1][2] * m[3][1] - inv.m[2][2] * m[3][2];
481 inv.m[3][3] = 1;
482 inv.flagBits = flagBits;
483
484 if (invertible)
485 *invertible = true;
486 return inv;
487 }
488
489 QMatrix4x4 inv(1); // The "1" says to not load the identity.
490
491 double mm[4][4];
492 copyToDoubles(m, mm);
493
494 double det = matrixDet4(m: mm);
495 if (det == 0.0f) {
496 if (invertible)
497 *invertible = false;
498 return QMatrix4x4();
499 }
500 det = 1.0f / det;
501
502 inv.m[0][0] = matrixDet3(m: mm, col0: 1, col1: 2, col2: 3, row0: 1, row1: 2, row2: 3) * det;
503 inv.m[0][1] = -matrixDet3(m: mm, col0: 0, col1: 2, col2: 3, row0: 1, row1: 2, row2: 3) * det;
504 inv.m[0][2] = matrixDet3(m: mm, col0: 0, col1: 1, col2: 3, row0: 1, row1: 2, row2: 3) * det;
505 inv.m[0][3] = -matrixDet3(m: mm, col0: 0, col1: 1, col2: 2, row0: 1, row1: 2, row2: 3) * det;
506 inv.m[1][0] = -matrixDet3(m: mm, col0: 1, col1: 2, col2: 3, row0: 0, row1: 2, row2: 3) * det;
507 inv.m[1][1] = matrixDet3(m: mm, col0: 0, col1: 2, col2: 3, row0: 0, row1: 2, row2: 3) * det;
508 inv.m[1][2] = -matrixDet3(m: mm, col0: 0, col1: 1, col2: 3, row0: 0, row1: 2, row2: 3) * det;
509 inv.m[1][3] = matrixDet3(m: mm, col0: 0, col1: 1, col2: 2, row0: 0, row1: 2, row2: 3) * det;
510 inv.m[2][0] = matrixDet3(m: mm, col0: 1, col1: 2, col2: 3, row0: 0, row1: 1, row2: 3) * det;
511 inv.m[2][1] = -matrixDet3(m: mm, col0: 0, col1: 2, col2: 3, row0: 0, row1: 1, row2: 3) * det;
512 inv.m[2][2] = matrixDet3(m: mm, col0: 0, col1: 1, col2: 3, row0: 0, row1: 1, row2: 3) * det;
513 inv.m[2][3] = -matrixDet3(m: mm, col0: 0, col1: 1, col2: 2, row0: 0, row1: 1, row2: 3) * det;
514 inv.m[3][0] = -matrixDet3(m: mm, col0: 1, col1: 2, col2: 3, row0: 0, row1: 1, row2: 2) * det;
515 inv.m[3][1] = matrixDet3(m: mm, col0: 0, col1: 2, col2: 3, row0: 0, row1: 1, row2: 2) * det;
516 inv.m[3][2] = -matrixDet3(m: mm, col0: 0, col1: 1, col2: 3, row0: 0, row1: 1, row2: 2) * det;
517 inv.m[3][3] = matrixDet3(m: mm, col0: 0, col1: 1, col2: 2, row0: 0, row1: 1, row2: 2) * det;
518 inv.flagBits = flagBits;
519
520 if (invertible)
521 *invertible = true;
522 return inv;
523}
524
525/*!
526 Returns the normal matrix corresponding to this 4x4 transformation.
527 The normal matrix is the transpose of the inverse of the top-left
528 3x3 part of this 4x4 matrix. If the 3x3 sub-matrix is not invertible,
529 this function returns the identity.
530
531 \sa inverted()
532*/
533QMatrix3x3 QMatrix4x4::normalMatrix() const
534{
535 QMatrix3x3 inv;
536
537 // Handle the simple cases first.
538 if (flagBits < Scale) {
539 // Translation
540 return inv;
541 } else if (flagBits < Rotation2D) {
542 // Translation | Scale
543 if (m[0][0] == 0.0f || m[1][1] == 0.0f || m[2][2] == 0.0f)
544 return inv;
545 inv.data()[0] = 1.0f / m[0][0];
546 inv.data()[4] = 1.0f / m[1][1];
547 inv.data()[8] = 1.0f / m[2][2];
548 return inv;
549 } else if ((flagBits & ~(Translation | Rotation2D | Rotation)) == Identity) {
550 float *invm = inv.data();
551 invm[0 + 0 * 3] = m[0][0];
552 invm[1 + 0 * 3] = m[0][1];
553 invm[2 + 0 * 3] = m[0][2];
554 invm[0 + 1 * 3] = m[1][0];
555 invm[1 + 1 * 3] = m[1][1];
556 invm[2 + 1 * 3] = m[1][2];
557 invm[0 + 2 * 3] = m[2][0];
558 invm[1 + 2 * 3] = m[2][1];
559 invm[2 + 2 * 3] = m[2][2];
560 return inv;
561 }
562
563 double mm[4][4];
564 copyToDoubles(m, mm);
565 double det = matrixDet3(m: mm, col0: 0, col1: 1, col2: 2, row0: 0, row1: 1, row2: 2);
566 if (det == 0.0f)
567 return inv;
568 det = 1.0f / det;
569
570 float *invm = inv.data();
571
572 // Invert and transpose in a single step.
573 invm[0 + 0 * 3] = (mm[1][1] * mm[2][2] - mm[2][1] * mm[1][2]) * det;
574 invm[1 + 0 * 3] = -(mm[1][0] * mm[2][2] - mm[1][2] * mm[2][0]) * det;
575 invm[2 + 0 * 3] = (mm[1][0] * mm[2][1] - mm[1][1] * mm[2][0]) * det;
576 invm[0 + 1 * 3] = -(mm[0][1] * mm[2][2] - mm[2][1] * mm[0][2]) * det;
577 invm[1 + 1 * 3] = (mm[0][0] * mm[2][2] - mm[0][2] * mm[2][0]) * det;
578 invm[2 + 1 * 3] = -(mm[0][0] * mm[2][1] - mm[0][1] * mm[2][0]) * det;
579 invm[0 + 2 * 3] = (mm[0][1] * mm[1][2] - mm[0][2] * mm[1][1]) * det;
580 invm[1 + 2 * 3] = -(mm[0][0] * mm[1][2] - mm[0][2] * mm[1][0]) * det;
581 invm[2 + 2 * 3] = (mm[0][0] * mm[1][1] - mm[1][0] * mm[0][1]) * det;
582
583 return inv;
584}
585
586/*!
587 Returns this matrix, transposed about its diagonal.
588*/
589QMatrix4x4 QMatrix4x4::transposed() const
590{
591 QMatrix4x4 result(1); // The "1" says to not load the identity.
592 for (int row = 0; row < 4; ++row) {
593 for (int col = 0; col < 4; ++col) {
594 result.m[col][row] = m[row][col];
595 }
596 }
597 // When a translation is transposed, it becomes a perspective transformation.
598 result.flagBits = (flagBits & Translation ? General : flagBits);
599 return result;
600}
601
602/*!
603 \fn QMatrix4x4& QMatrix4x4::operator+=(const QMatrix4x4& other)
604
605 Adds the contents of \a other to this matrix.
606*/
607
608/*!
609 \fn QMatrix4x4& QMatrix4x4::operator-=(const QMatrix4x4& other)
610
611 Subtracts the contents of \a other from this matrix.
612*/
613
614/*!
615 \fn QMatrix4x4& QMatrix4x4::operator*=(const QMatrix4x4& other)
616
617 Multiplies the contents of \a other by this matrix.
618*/
619
620/*!
621 \fn QMatrix4x4& QMatrix4x4::operator*=(float factor)
622 \overload
623
624 Multiplies all elements of this matrix by \a factor.
625*/
626
627/*!
628 \overload
629
630 Divides all elements of this matrix by \a divisor.
631*/
632QMatrix4x4& QMatrix4x4::operator/=(float divisor)
633{
634 m[0][0] /= divisor;
635 m[0][1] /= divisor;
636 m[0][2] /= divisor;
637 m[0][3] /= divisor;
638 m[1][0] /= divisor;
639 m[1][1] /= divisor;
640 m[1][2] /= divisor;
641 m[1][3] /= divisor;
642 m[2][0] /= divisor;
643 m[2][1] /= divisor;
644 m[2][2] /= divisor;
645 m[2][3] /= divisor;
646 m[3][0] /= divisor;
647 m[3][1] /= divisor;
648 m[3][2] /= divisor;
649 m[3][3] /= divisor;
650 flagBits = General;
651 return *this;
652}
653
654/*!
655 \fn bool QMatrix4x4::operator==(const QMatrix4x4& other) const
656
657 Returns \c true if this matrix is identical to \a other; false otherwise.
658 This operator uses an exact floating-point comparison.
659*/
660
661/*!
662 \fn bool QMatrix4x4::operator!=(const QMatrix4x4& other) const
663
664 Returns \c true if this matrix is not identical to \a other; false otherwise.
665 This operator uses an exact floating-point comparison.
666*/
667
668/*!
669 \fn QMatrix4x4 operator+(const QMatrix4x4& m1, const QMatrix4x4& m2)
670 \relates QMatrix4x4
671
672 Returns the sum of \a m1 and \a m2.
673*/
674
675/*!
676 \fn QMatrix4x4 operator-(const QMatrix4x4& m1, const QMatrix4x4& m2)
677 \relates QMatrix4x4
678
679 Returns the difference of \a m1 and \a m2.
680*/
681
682/*!
683 \fn QMatrix4x4 operator*(const QMatrix4x4& m1, const QMatrix4x4& m2)
684 \relates QMatrix4x4
685
686 Returns the product of \a m1 and \a m2.
687*/
688
689#ifndef QT_NO_VECTOR3D
690
691/*!
692 \fn QVector3D operator*(const QVector3D& vector, const QMatrix4x4& matrix)
693 \relates QMatrix4x4
694
695 Returns the result of transforming \a vector according to \a matrix,
696 with the matrix applied post-vector.
697*/
698
699/*!
700 \fn QVector3D operator*(const QMatrix4x4& matrix, const QVector3D& vector)
701 \relates QMatrix4x4
702
703 Returns the result of transforming \a vector according to \a matrix,
704 with the matrix applied pre-vector.
705*/
706
707#endif
708
709#ifndef QT_NO_VECTOR4D
710
711/*!
712 \fn QVector4D operator*(const QVector4D& vector, const QMatrix4x4& matrix)
713 \relates QMatrix4x4
714
715 Returns the result of transforming \a vector according to \a matrix,
716 with the matrix applied post-vector.
717*/
718
719/*!
720 \fn QVector4D operator*(const QMatrix4x4& matrix, const QVector4D& vector)
721 \relates QMatrix4x4
722
723 Returns the result of transforming \a vector according to \a matrix,
724 with the matrix applied pre-vector.
725*/
726
727#endif
728
729/*!
730 \fn QPoint operator*(const QPoint& point, const QMatrix4x4& matrix)
731 \relates QMatrix4x4
732
733 Returns the result of transforming \a point according to \a matrix,
734 with the matrix applied post-point.
735*/
736
737/*!
738 \fn QPointF operator*(const QPointF& point, const QMatrix4x4& matrix)
739 \relates QMatrix4x4
740
741 Returns the result of transforming \a point according to \a matrix,
742 with the matrix applied post-point.
743*/
744
745/*!
746 \fn QPoint operator*(const QMatrix4x4& matrix, const QPoint& point)
747 \relates QMatrix4x4
748
749 Returns the result of transforming \a point according to \a matrix,
750 with the matrix applied pre-point.
751*/
752
753/*!
754 \fn QPointF operator*(const QMatrix4x4& matrix, const QPointF& point)
755 \relates QMatrix4x4
756
757 Returns the result of transforming \a point according to \a matrix,
758 with the matrix applied pre-point.
759*/
760
761/*!
762 \fn QMatrix4x4 operator-(const QMatrix4x4& matrix)
763 \overload
764 \relates QMatrix4x4
765
766 Returns the negation of \a matrix.
767*/
768
769/*!
770 \fn QMatrix4x4 operator*(float factor, const QMatrix4x4& matrix)
771 \relates QMatrix4x4
772
773 Returns the result of multiplying all elements of \a matrix by \a factor.
774*/
775
776/*!
777 \fn QMatrix4x4 operator*(const QMatrix4x4& matrix, float factor)
778 \relates QMatrix4x4
779
780 Returns the result of multiplying all elements of \a matrix by \a factor.
781*/
782
783/*!
784 \relates QMatrix4x4
785
786 Returns the result of dividing all elements of \a matrix by \a divisor.
787*/
788QMatrix4x4 operator/(const QMatrix4x4& matrix, float divisor)
789{
790 QMatrix4x4 m(1); // The "1" says to not load the identity.
791 m.m[0][0] = matrix.m[0][0] / divisor;
792 m.m[0][1] = matrix.m[0][1] / divisor;
793 m.m[0][2] = matrix.m[0][2] / divisor;
794 m.m[0][3] = matrix.m[0][3] / divisor;
795 m.m[1][0] = matrix.m[1][0] / divisor;
796 m.m[1][1] = matrix.m[1][1] / divisor;
797 m.m[1][2] = matrix.m[1][2] / divisor;
798 m.m[1][3] = matrix.m[1][3] / divisor;
799 m.m[2][0] = matrix.m[2][0] / divisor;
800 m.m[2][1] = matrix.m[2][1] / divisor;
801 m.m[2][2] = matrix.m[2][2] / divisor;
802 m.m[2][3] = matrix.m[2][3] / divisor;
803 m.m[3][0] = matrix.m[3][0] / divisor;
804 m.m[3][1] = matrix.m[3][1] / divisor;
805 m.m[3][2] = matrix.m[3][2] / divisor;
806 m.m[3][3] = matrix.m[3][3] / divisor;
807 m.flagBits = QMatrix4x4::General;
808 return m;
809}
810
811/*!
812 \fn bool qFuzzyCompare(const QMatrix4x4& m1, const QMatrix4x4& m2)
813 \relates QMatrix4x4
814
815 Returns \c true if \a m1 and \a m2 are equal, allowing for a small
816 fuzziness factor for floating-point comparisons; false otherwise.
817*/
818
819#ifndef QT_NO_VECTOR3D
820
821/*!
822 Multiplies this matrix by another that scales coordinates by
823 the components of \a vector.
824
825 \sa translate(), rotate()
826*/
827void QMatrix4x4::scale(const QVector3D& vector)
828{
829 float vx = vector.x();
830 float vy = vector.y();
831 float vz = vector.z();
832 if (flagBits < Scale) {
833 m[0][0] = vx;
834 m[1][1] = vy;
835 m[2][2] = vz;
836 } else if (flagBits < Rotation2D) {
837 m[0][0] *= vx;
838 m[1][1] *= vy;
839 m[2][2] *= vz;
840 } else if (flagBits < Rotation) {
841 m[0][0] *= vx;
842 m[0][1] *= vx;
843 m[1][0] *= vy;
844 m[1][1] *= vy;
845 m[2][2] *= vz;
846 } else {
847 m[0][0] *= vx;
848 m[0][1] *= vx;
849 m[0][2] *= vx;
850 m[0][3] *= vx;
851 m[1][0] *= vy;
852 m[1][1] *= vy;
853 m[1][2] *= vy;
854 m[1][3] *= vy;
855 m[2][0] *= vz;
856 m[2][1] *= vz;
857 m[2][2] *= vz;
858 m[2][3] *= vz;
859 }
860 flagBits |= Scale;
861}
862
863#endif
864
865/*!
866 \overload
867
868 Multiplies this matrix by another that scales coordinates by the
869 components \a x, and \a y.
870
871 \sa translate(), rotate()
872*/
873void QMatrix4x4::scale(float x, float y)
874{
875 if (flagBits < Scale) {
876 m[0][0] = x;
877 m[1][1] = y;
878 } else if (flagBits < Rotation2D) {
879 m[0][0] *= x;
880 m[1][1] *= y;
881 } else if (flagBits < Rotation) {
882 m[0][0] *= x;
883 m[0][1] *= x;
884 m[1][0] *= y;
885 m[1][1] *= y;
886 } else {
887 m[0][0] *= x;
888 m[0][1] *= x;
889 m[0][2] *= x;
890 m[0][3] *= x;
891 m[1][0] *= y;
892 m[1][1] *= y;
893 m[1][2] *= y;
894 m[1][3] *= y;
895 }
896 flagBits |= Scale;
897}
898
899/*!
900 \overload
901
902 Multiplies this matrix by another that scales coordinates by the
903 components \a x, \a y, and \a z.
904
905 \sa translate(), rotate()
906*/
907void QMatrix4x4::scale(float x, float y, float z)
908{
909 if (flagBits < Scale) {
910 m[0][0] = x;
911 m[1][1] = y;
912 m[2][2] = z;
913 } else if (flagBits < Rotation2D) {
914 m[0][0] *= x;
915 m[1][1] *= y;
916 m[2][2] *= z;
917 } else if (flagBits < Rotation) {
918 m[0][0] *= x;
919 m[0][1] *= x;
920 m[1][0] *= y;
921 m[1][1] *= y;
922 m[2][2] *= z;
923 } else {
924 m[0][0] *= x;
925 m[0][1] *= x;
926 m[0][2] *= x;
927 m[0][3] *= x;
928 m[1][0] *= y;
929 m[1][1] *= y;
930 m[1][2] *= y;
931 m[1][3] *= y;
932 m[2][0] *= z;
933 m[2][1] *= z;
934 m[2][2] *= z;
935 m[2][3] *= z;
936 }
937 flagBits |= Scale;
938}
939
940/*!
941 \overload
942
943 Multiplies this matrix by another that scales coordinates by the
944 given \a factor.
945
946 \sa translate(), rotate()
947*/
948void QMatrix4x4::scale(float factor)
949{
950 if (flagBits < Scale) {
951 m[0][0] = factor;
952 m[1][1] = factor;
953 m[2][2] = factor;
954 } else if (flagBits < Rotation2D) {
955 m[0][0] *= factor;
956 m[1][1] *= factor;
957 m[2][2] *= factor;
958 } else if (flagBits < Rotation) {
959 m[0][0] *= factor;
960 m[0][1] *= factor;
961 m[1][0] *= factor;
962 m[1][1] *= factor;
963 m[2][2] *= factor;
964 } else {
965 m[0][0] *= factor;
966 m[0][1] *= factor;
967 m[0][2] *= factor;
968 m[0][3] *= factor;
969 m[1][0] *= factor;
970 m[1][1] *= factor;
971 m[1][2] *= factor;
972 m[1][3] *= factor;
973 m[2][0] *= factor;
974 m[2][1] *= factor;
975 m[2][2] *= factor;
976 m[2][3] *= factor;
977 }
978 flagBits |= Scale;
979}
980
981#ifndef QT_NO_VECTOR3D
982/*!
983 Multiplies this matrix by another that translates coordinates by
984 the components of \a vector.
985
986 \sa scale(), rotate()
987*/
988
989void QMatrix4x4::translate(const QVector3D& vector)
990{
991 float vx = vector.x();
992 float vy = vector.y();
993 float vz = vector.z();
994 if (flagBits == Identity) {
995 m[3][0] = vx;
996 m[3][1] = vy;
997 m[3][2] = vz;
998 } else if (flagBits == Translation) {
999 m[3][0] += vx;
1000 m[3][1] += vy;
1001 m[3][2] += vz;
1002 } else if (flagBits == Scale) {
1003 m[3][0] = m[0][0] * vx;
1004 m[3][1] = m[1][1] * vy;
1005 m[3][2] = m[2][2] * vz;
1006 } else if (flagBits == (Translation | Scale)) {
1007 m[3][0] += m[0][0] * vx;
1008 m[3][1] += m[1][1] * vy;
1009 m[3][2] += m[2][2] * vz;
1010 } else if (flagBits < Rotation) {
1011 m[3][0] += m[0][0] * vx + m[1][0] * vy;
1012 m[3][1] += m[0][1] * vx + m[1][1] * vy;
1013 m[3][2] += m[2][2] * vz;
1014 } else {
1015 m[3][0] += m[0][0] * vx + m[1][0] * vy + m[2][0] * vz;
1016 m[3][1] += m[0][1] * vx + m[1][1] * vy + m[2][1] * vz;
1017 m[3][2] += m[0][2] * vx + m[1][2] * vy + m[2][2] * vz;
1018 m[3][3] += m[0][3] * vx + m[1][3] * vy + m[2][3] * vz;
1019 }
1020 flagBits |= Translation;
1021}
1022#endif
1023
1024/*!
1025 \overload
1026
1027 Multiplies this matrix by another that translates coordinates
1028 by the components \a x, and \a y.
1029
1030 \sa scale(), rotate()
1031*/
1032void QMatrix4x4::translate(float x, float y)
1033{
1034 if (flagBits == Identity) {
1035 m[3][0] = x;
1036 m[3][1] = y;
1037 } else if (flagBits == Translation) {
1038 m[3][0] += x;
1039 m[3][1] += y;
1040 } else if (flagBits == Scale) {
1041 m[3][0] = m[0][0] * x;
1042 m[3][1] = m[1][1] * y;
1043 } else if (flagBits == (Translation | Scale)) {
1044 m[3][0] += m[0][0] * x;
1045 m[3][1] += m[1][1] * y;
1046 } else if (flagBits < Rotation) {
1047 m[3][0] += m[0][0] * x + m[1][0] * y;
1048 m[3][1] += m[0][1] * x + m[1][1] * y;
1049 } else {
1050 m[3][0] += m[0][0] * x + m[1][0] * y;
1051 m[3][1] += m[0][1] * x + m[1][1] * y;
1052 m[3][2] += m[0][2] * x + m[1][2] * y;
1053 m[3][3] += m[0][3] * x + m[1][3] * y;
1054 }
1055 flagBits |= Translation;
1056}
1057
1058/*!
1059 \overload
1060
1061 Multiplies this matrix by another that translates coordinates
1062 by the components \a x, \a y, and \a z.
1063
1064 \sa scale(), rotate()
1065*/
1066void QMatrix4x4::translate(float x, float y, float z)
1067{
1068 if (flagBits == Identity) {
1069 m[3][0] = x;
1070 m[3][1] = y;
1071 m[3][2] = z;
1072 } else if (flagBits == Translation) {
1073 m[3][0] += x;
1074 m[3][1] += y;
1075 m[3][2] += z;
1076 } else if (flagBits == Scale) {
1077 m[3][0] = m[0][0] * x;
1078 m[3][1] = m[1][1] * y;
1079 m[3][2] = m[2][2] * z;
1080 } else if (flagBits == (Translation | Scale)) {
1081 m[3][0] += m[0][0] * x;
1082 m[3][1] += m[1][1] * y;
1083 m[3][2] += m[2][2] * z;
1084 } else if (flagBits < Rotation) {
1085 m[3][0] += m[0][0] * x + m[1][0] * y;
1086 m[3][1] += m[0][1] * x + m[1][1] * y;
1087 m[3][2] += m[2][2] * z;
1088 } else {
1089 m[3][0] += m[0][0] * x + m[1][0] * y + m[2][0] * z;
1090 m[3][1] += m[0][1] * x + m[1][1] * y + m[2][1] * z;
1091 m[3][2] += m[0][2] * x + m[1][2] * y + m[2][2] * z;
1092 m[3][3] += m[0][3] * x + m[1][3] * y + m[2][3] * z;
1093 }
1094 flagBits |= Translation;
1095}
1096
1097#ifndef QT_NO_VECTOR3D
1098/*!
1099 Multiples this matrix by another that rotates coordinates through
1100 \a angle degrees about \a vector.
1101
1102 \sa scale(), translate()
1103*/
1104
1105void QMatrix4x4::rotate(float angle, const QVector3D& vector)
1106{
1107 rotate(angle, x: vector.x(), y: vector.y(), z: vector.z());
1108}
1109
1110#endif
1111
1112/*!
1113 \overload
1114
1115 Multiplies this matrix by another that rotates coordinates through
1116 \a angle degrees about the vector (\a x, \a y, \a z).
1117
1118 \sa scale(), translate()
1119*/
1120void QMatrix4x4::rotate(float angle, float x, float y, float z)
1121{
1122 if (angle == 0.0f)
1123 return;
1124 float c, s;
1125 if (angle == 90.0f || angle == -270.0f) {
1126 s = 1.0f;
1127 c = 0.0f;
1128 } else if (angle == -90.0f || angle == 270.0f) {
1129 s = -1.0f;
1130 c = 0.0f;
1131 } else if (angle == 180.0f || angle == -180.0f) {
1132 s = 0.0f;
1133 c = -1.0f;
1134 } else {
1135 float a = qDegreesToRadians(degrees: angle);
1136 c = std::cos(x: a);
1137 s = std::sin(x: a);
1138 }
1139 if (x == 0.0f) {
1140 if (y == 0.0f) {
1141 if (z != 0.0f) {
1142 // Rotate around the Z axis.
1143 if (z < 0)
1144 s = -s;
1145 float tmp;
1146 m[0][0] = (tmp = m[0][0]) * c + m[1][0] * s;
1147 m[1][0] = m[1][0] * c - tmp * s;
1148 m[0][1] = (tmp = m[0][1]) * c + m[1][1] * s;
1149 m[1][1] = m[1][1] * c - tmp * s;
1150 m[0][2] = (tmp = m[0][2]) * c + m[1][2] * s;
1151 m[1][2] = m[1][2] * c - tmp * s;
1152 m[0][3] = (tmp = m[0][3]) * c + m[1][3] * s;
1153 m[1][3] = m[1][3] * c - tmp * s;
1154
1155 flagBits |= Rotation2D;
1156 return;
1157 }
1158 } else if (z == 0.0f) {
1159 // Rotate around the Y axis.
1160 if (y < 0)
1161 s = -s;
1162 float tmp;
1163 m[2][0] = (tmp = m[2][0]) * c + m[0][0] * s;
1164 m[0][0] = m[0][0] * c - tmp * s;
1165 m[2][1] = (tmp = m[2][1]) * c + m[0][1] * s;
1166 m[0][1] = m[0][1] * c - tmp * s;
1167 m[2][2] = (tmp = m[2][2]) * c + m[0][2] * s;
1168 m[0][2] = m[0][2] * c - tmp * s;
1169 m[2][3] = (tmp = m[2][3]) * c + m[0][3] * s;
1170 m[0][3] = m[0][3] * c - tmp * s;
1171
1172 flagBits |= Rotation;
1173 return;
1174 }
1175 } else if (y == 0.0f && z == 0.0f) {
1176 // Rotate around the X axis.
1177 if (x < 0)
1178 s = -s;
1179 float tmp;
1180 m[1][0] = (tmp = m[1][0]) * c + m[2][0] * s;
1181 m[2][0] = m[2][0] * c - tmp * s;
1182 m[1][1] = (tmp = m[1][1]) * c + m[2][1] * s;
1183 m[2][1] = m[2][1] * c - tmp * s;
1184 m[1][2] = (tmp = m[1][2]) * c + m[2][2] * s;
1185 m[2][2] = m[2][2] * c - tmp * s;
1186 m[1][3] = (tmp = m[1][3]) * c + m[2][3] * s;
1187 m[2][3] = m[2][3] * c - tmp * s;
1188
1189 flagBits |= Rotation;
1190 return;
1191 }
1192
1193 double len = double(x) * double(x) +
1194 double(y) * double(y) +
1195 double(z) * double(z);
1196 if (!qFuzzyCompare(p1: len, p2: 1.0) && !qFuzzyIsNull(d: len)) {
1197 len = std::sqrt(x: len);
1198 x = float(double(x) / len);
1199 y = float(double(y) / len);
1200 z = float(double(z) / len);
1201 }
1202 float ic = 1.0f - c;
1203 QMatrix4x4 rot(1); // The "1" says to not load the identity.
1204 rot.m[0][0] = x * x * ic + c;
1205 rot.m[1][0] = x * y * ic - z * s;
1206 rot.m[2][0] = x * z * ic + y * s;
1207 rot.m[3][0] = 0.0f;
1208 rot.m[0][1] = y * x * ic + z * s;
1209 rot.m[1][1] = y * y * ic + c;
1210 rot.m[2][1] = y * z * ic - x * s;
1211 rot.m[3][1] = 0.0f;
1212 rot.m[0][2] = x * z * ic - y * s;
1213 rot.m[1][2] = y * z * ic + x * s;
1214 rot.m[2][2] = z * z * ic + c;
1215 rot.m[3][2] = 0.0f;
1216 rot.m[0][3] = 0.0f;
1217 rot.m[1][3] = 0.0f;
1218 rot.m[2][3] = 0.0f;
1219 rot.m[3][3] = 1.0f;
1220 rot.flagBits = Rotation;
1221 *this *= rot;
1222}
1223
1224/*!
1225 \internal
1226*/
1227void QMatrix4x4::projectedRotate(float angle, float x, float y, float z)
1228{
1229 // Used by QGraphicsRotation::applyTo() to perform a rotation
1230 // and projection back to 2D in a single step.
1231 if (angle == 0.0f)
1232 return;
1233 float c, s;
1234 if (angle == 90.0f || angle == -270.0f) {
1235 s = 1.0f;
1236 c = 0.0f;
1237 } else if (angle == -90.0f || angle == 270.0f) {
1238 s = -1.0f;
1239 c = 0.0f;
1240 } else if (angle == 180.0f || angle == -180.0f) {
1241 s = 0.0f;
1242 c = -1.0f;
1243 } else {
1244 float a = qDegreesToRadians(degrees: angle);
1245 c = std::cos(x: a);
1246 s = std::sin(x: a);
1247 }
1248 if (x == 0.0f) {
1249 if (y == 0.0f) {
1250 if (z != 0.0f) {
1251 // Rotate around the Z axis.
1252 if (z < 0)
1253 s = -s;
1254 float tmp;
1255 m[0][0] = (tmp = m[0][0]) * c + m[1][0] * s;
1256 m[1][0] = m[1][0] * c - tmp * s;
1257 m[0][1] = (tmp = m[0][1]) * c + m[1][1] * s;
1258 m[1][1] = m[1][1] * c - tmp * s;
1259 m[0][2] = (tmp = m[0][2]) * c + m[1][2] * s;
1260 m[1][2] = m[1][2] * c - tmp * s;
1261 m[0][3] = (tmp = m[0][3]) * c + m[1][3] * s;
1262 m[1][3] = m[1][3] * c - tmp * s;
1263
1264 flagBits |= Rotation2D;
1265 return;
1266 }
1267 } else if (z == 0.0f) {
1268 // Rotate around the Y axis.
1269 if (y < 0)
1270 s = -s;
1271 m[0][0] = m[0][0] * c + m[3][0] * s * inv_dist_to_plane;
1272 m[0][1] = m[0][1] * c + m[3][1] * s * inv_dist_to_plane;
1273 m[0][2] = m[0][2] * c + m[3][2] * s * inv_dist_to_plane;
1274 m[0][3] = m[0][3] * c + m[3][3] * s * inv_dist_to_plane;
1275 flagBits = General;
1276 return;
1277 }
1278 } else if (y == 0.0f && z == 0.0f) {
1279 // Rotate around the X axis.
1280 if (x < 0)
1281 s = -s;
1282 m[1][0] = m[1][0] * c - m[3][0] * s * inv_dist_to_plane;
1283 m[1][1] = m[1][1] * c - m[3][1] * s * inv_dist_to_plane;
1284 m[1][2] = m[1][2] * c - m[3][2] * s * inv_dist_to_plane;
1285 m[1][3] = m[1][3] * c - m[3][3] * s * inv_dist_to_plane;
1286 flagBits = General;
1287 return;
1288 }
1289 double len = double(x) * double(x) +
1290 double(y) * double(y) +
1291 double(z) * double(z);
1292 if (!qFuzzyCompare(p1: len, p2: 1.0) && !qFuzzyIsNull(d: len)) {
1293 len = std::sqrt(x: len);
1294 x = float(double(x) / len);
1295 y = float(double(y) / len);
1296 z = float(double(z) / len);
1297 }
1298 float ic = 1.0f - c;
1299 QMatrix4x4 rot(1); // The "1" says to not load the identity.
1300 rot.m[0][0] = x * x * ic + c;
1301 rot.m[1][0] = x * y * ic - z * s;
1302 rot.m[2][0] = 0.0f;
1303 rot.m[3][0] = 0.0f;
1304 rot.m[0][1] = y * x * ic + z * s;
1305 rot.m[1][1] = y * y * ic + c;
1306 rot.m[2][1] = 0.0f;
1307 rot.m[3][1] = 0.0f;
1308 rot.m[0][2] = 0.0f;
1309 rot.m[1][2] = 0.0f;
1310 rot.m[2][2] = 1.0f;
1311 rot.m[3][2] = 0.0f;
1312 rot.m[0][3] = (x * z * ic - y * s) * -inv_dist_to_plane;
1313 rot.m[1][3] = (y * z * ic + x * s) * -inv_dist_to_plane;
1314 rot.m[2][3] = 0.0f;
1315 rot.m[3][3] = 1.0f;
1316 rot.flagBits = General;
1317 *this *= rot;
1318}
1319
1320#ifndef QT_NO_QUATERNION
1321
1322/*!
1323 Multiples this matrix by another that rotates coordinates according
1324 to a specified \a quaternion. The \a quaternion is assumed to have
1325 been normalized.
1326
1327 \sa scale(), translate(), QQuaternion
1328*/
1329void QMatrix4x4::rotate(const QQuaternion& quaternion)
1330{
1331 // Algorithm from:
1332 // http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q54
1333
1334 QMatrix4x4 m(Qt::Uninitialized);
1335
1336 const float f2x = quaternion.x() + quaternion.x();
1337 const float f2y = quaternion.y() + quaternion.y();
1338 const float f2z = quaternion.z() + quaternion.z();
1339 const float f2xw = f2x * quaternion.scalar();
1340 const float f2yw = f2y * quaternion.scalar();
1341 const float f2zw = f2z * quaternion.scalar();
1342 const float f2xx = f2x * quaternion.x();
1343 const float f2xy = f2x * quaternion.y();
1344 const float f2xz = f2x * quaternion.z();
1345 const float f2yy = f2y * quaternion.y();
1346 const float f2yz = f2y * quaternion.z();
1347 const float f2zz = f2z * quaternion.z();
1348
1349 m.m[0][0] = 1.0f - (f2yy + f2zz);
1350 m.m[1][0] = f2xy - f2zw;
1351 m.m[2][0] = f2xz + f2yw;
1352 m.m[3][0] = 0.0f;
1353 m.m[0][1] = f2xy + f2zw;
1354 m.m[1][1] = 1.0f - (f2xx + f2zz);
1355 m.m[2][1] = f2yz - f2xw;
1356 m.m[3][1] = 0.0f;
1357 m.m[0][2] = f2xz - f2yw;
1358 m.m[1][2] = f2yz + f2xw;
1359 m.m[2][2] = 1.0f - (f2xx + f2yy);
1360 m.m[3][2] = 0.0f;
1361 m.m[0][3] = 0.0f;
1362 m.m[1][3] = 0.0f;
1363 m.m[2][3] = 0.0f;
1364 m.m[3][3] = 1.0f;
1365 m.flagBits = Rotation;
1366 *this *= m;
1367}
1368
1369#endif
1370
1371/*!
1372 \overload
1373
1374 Multiplies this matrix by another that applies an orthographic
1375 projection for a window with boundaries specified by \a rect.
1376 The near and far clipping planes will be -1 and 1 respectively.
1377
1378 \sa frustum(), perspective()
1379*/
1380void QMatrix4x4::ortho(const QRect& rect)
1381{
1382 // Note: rect.right() and rect.bottom() subtract 1 in QRect,
1383 // which gives the location of a pixel within the rectangle,
1384 // instead of the extent of the rectangle. We want the extent.
1385 // QRectF expresses the extent properly.
1386 ortho(left: rect.x(), right: rect.x() + rect.width(), bottom: rect.y() + rect.height(), top: rect.y(), nearPlane: -1.0f, farPlane: 1.0f);
1387}
1388
1389/*!
1390 \overload
1391
1392 Multiplies this matrix by another that applies an orthographic
1393 projection for a window with boundaries specified by \a rect.
1394 The near and far clipping planes will be -1 and 1 respectively.
1395
1396 \sa frustum(), perspective()
1397*/
1398void QMatrix4x4::ortho(const QRectF& rect)
1399{
1400 ortho(left: rect.left(), right: rect.right(), bottom: rect.bottom(), top: rect.top(), nearPlane: -1.0f, farPlane: 1.0f);
1401}
1402
1403/*!
1404 Multiplies this matrix by another that applies an orthographic
1405 projection for a window with lower-left corner (\a left, \a bottom),
1406 upper-right corner (\a right, \a top), and the specified \a nearPlane
1407 and \a farPlane clipping planes.
1408
1409 \sa frustum(), perspective()
1410*/
1411void QMatrix4x4::ortho(float left, float right, float bottom, float top, float nearPlane, float farPlane)
1412{
1413 // Bail out if the projection volume is zero-sized.
1414 if (left == right || bottom == top || nearPlane == farPlane)
1415 return;
1416
1417 // Construct the projection.
1418 float width = right - left;
1419 float invheight = top - bottom;
1420 float clip = farPlane - nearPlane;
1421 QMatrix4x4 m(1);
1422 m.m[0][0] = 2.0f / width;
1423 m.m[1][0] = 0.0f;
1424 m.m[2][0] = 0.0f;
1425 m.m[3][0] = -(left + right) / width;
1426 m.m[0][1] = 0.0f;
1427 m.m[1][1] = 2.0f / invheight;
1428 m.m[2][1] = 0.0f;
1429 m.m[3][1] = -(top + bottom) / invheight;
1430 m.m[0][2] = 0.0f;
1431 m.m[1][2] = 0.0f;
1432 m.m[2][2] = -2.0f / clip;
1433 m.m[3][2] = -(nearPlane + farPlane) / clip;
1434 m.m[0][3] = 0.0f;
1435 m.m[1][3] = 0.0f;
1436 m.m[2][3] = 0.0f;
1437 m.m[3][3] = 1.0f;
1438 m.flagBits = Translation | Scale;
1439
1440 // Apply the projection.
1441 *this *= m;
1442}
1443
1444/*!
1445 Multiplies this matrix by another that applies a perspective
1446 frustum projection for a window with lower-left corner (\a left, \a bottom),
1447 upper-right corner (\a right, \a top), and the specified \a nearPlane
1448 and \a farPlane clipping planes.
1449
1450 \sa ortho(), perspective()
1451*/
1452void QMatrix4x4::frustum(float left, float right, float bottom, float top, float nearPlane, float farPlane)
1453{
1454 // Bail out if the projection volume is zero-sized.
1455 if (left == right || bottom == top || nearPlane == farPlane)
1456 return;
1457
1458 // Construct the projection.
1459 QMatrix4x4 m(1);
1460 float width = right - left;
1461 float invheight = top - bottom;
1462 float clip = farPlane - nearPlane;
1463 m.m[0][0] = 2.0f * nearPlane / width;
1464 m.m[1][0] = 0.0f;
1465 m.m[2][0] = (left + right) / width;
1466 m.m[3][0] = 0.0f;
1467 m.m[0][1] = 0.0f;
1468 m.m[1][1] = 2.0f * nearPlane / invheight;
1469 m.m[2][1] = (top + bottom) / invheight;
1470 m.m[3][1] = 0.0f;
1471 m.m[0][2] = 0.0f;
1472 m.m[1][2] = 0.0f;
1473 m.m[2][2] = -(nearPlane + farPlane) / clip;
1474 m.m[3][2] = -2.0f * nearPlane * farPlane / clip;
1475 m.m[0][3] = 0.0f;
1476 m.m[1][3] = 0.0f;
1477 m.m[2][3] = -1.0f;
1478 m.m[3][3] = 0.0f;
1479 m.flagBits = General;
1480
1481 // Apply the projection.
1482 *this *= m;
1483}
1484
1485/*!
1486 Multiplies this matrix by another that applies a perspective
1487 projection. The vertical field of view will be \a verticalAngle degrees
1488 within a window with a given \a aspectRatio that determines the horizontal
1489 field of view.
1490 The projection will have the specified \a nearPlane and \a farPlane clipping
1491 planes which are the distances from the viewer to the corresponding planes.
1492
1493 \sa ortho(), frustum()
1494*/
1495void QMatrix4x4::perspective(float verticalAngle, float aspectRatio, float nearPlane, float farPlane)
1496{
1497 // Bail out if the projection volume is zero-sized.
1498 if (nearPlane == farPlane || aspectRatio == 0.0f)
1499 return;
1500
1501 // Construct the projection.
1502 QMatrix4x4 m(1);
1503 float radians = qDegreesToRadians(degrees: verticalAngle / 2.0f);
1504 float sine = std::sin(x: radians);
1505 if (sine == 0.0f)
1506 return;
1507 float cotan = std::cos(x: radians) / sine;
1508 float clip = farPlane - nearPlane;
1509 m.m[0][0] = cotan / aspectRatio;
1510 m.m[1][0] = 0.0f;
1511 m.m[2][0] = 0.0f;
1512 m.m[3][0] = 0.0f;
1513 m.m[0][1] = 0.0f;
1514 m.m[1][1] = cotan;
1515 m.m[2][1] = 0.0f;
1516 m.m[3][1] = 0.0f;
1517 m.m[0][2] = 0.0f;
1518 m.m[1][2] = 0.0f;
1519 m.m[2][2] = -(nearPlane + farPlane) / clip;
1520 m.m[3][2] = -(2.0f * nearPlane * farPlane) / clip;
1521 m.m[0][3] = 0.0f;
1522 m.m[1][3] = 0.0f;
1523 m.m[2][3] = -1.0f;
1524 m.m[3][3] = 0.0f;
1525 m.flagBits = General;
1526
1527 // Apply the projection.
1528 *this *= m;
1529}
1530
1531#ifndef QT_NO_VECTOR3D
1532
1533/*!
1534 Multiplies this matrix by a viewing matrix derived from an eye
1535 point. The \a center value indicates the center of the view that
1536 the \a eye is looking at. The \a up value indicates which direction
1537 should be considered up with respect to the \a eye.
1538
1539 \note The \a up vector must not be parallel to the line of sight
1540 from \a eye to \a center.
1541*/
1542void QMatrix4x4::lookAt(const QVector3D& eye, const QVector3D& center, const QVector3D& up)
1543{
1544 QVector3D forward = center - eye;
1545 if (qFuzzyIsNull(f: forward.x()) && qFuzzyIsNull(f: forward.y()) && qFuzzyIsNull(f: forward.z()))
1546 return;
1547
1548 forward.normalize();
1549 QVector3D side = QVector3D::crossProduct(v1: forward, v2: up).normalized();
1550 QVector3D upVector = QVector3D::crossProduct(v1: side, v2: forward);
1551
1552 QMatrix4x4 m(1);
1553 m.m[0][0] = side.x();
1554 m.m[1][0] = side.y();
1555 m.m[2][0] = side.z();
1556 m.m[3][0] = 0.0f;
1557 m.m[0][1] = upVector.x();
1558 m.m[1][1] = upVector.y();
1559 m.m[2][1] = upVector.z();
1560 m.m[3][1] = 0.0f;
1561 m.m[0][2] = -forward.x();
1562 m.m[1][2] = -forward.y();
1563 m.m[2][2] = -forward.z();
1564 m.m[3][2] = 0.0f;
1565 m.m[0][3] = 0.0f;
1566 m.m[1][3] = 0.0f;
1567 m.m[2][3] = 0.0f;
1568 m.m[3][3] = 1.0f;
1569 m.flagBits = Rotation;
1570
1571 *this *= m;
1572 translate(vector: -eye);
1573}
1574
1575#endif
1576
1577/*!
1578 \fn void QMatrix4x4::viewport(const QRectF &rect)
1579 \overload
1580
1581 Sets up viewport transform for viewport bounded by \a rect and with near and far set
1582 to 0 and 1 respectively.
1583*/
1584
1585/*!
1586 Multiplies this matrix by another that performs the scale and bias
1587 transformation used by OpenGL to transform from normalized device
1588 coordinates (NDC) to viewport (window) coordinates. That is it maps
1589 points from the cube ranging over [-1, 1] in each dimension to the
1590 viewport with it's near-lower-left corner at (\a left, \a bottom, \a nearPlane)
1591 and with size (\a width, \a height, \a farPlane - \a nearPlane).
1592
1593 This matches the transform used by the fixed function OpenGL viewport
1594 transform controlled by the functions glViewport() and glDepthRange().
1595 */
1596void QMatrix4x4::viewport(float left, float bottom, float width, float height, float nearPlane, float farPlane)
1597{
1598 const float w2 = width / 2.0f;
1599 const float h2 = height / 2.0f;
1600
1601 QMatrix4x4 m(1);
1602 m.m[0][0] = w2;
1603 m.m[1][0] = 0.0f;
1604 m.m[2][0] = 0.0f;
1605 m.m[3][0] = left + w2;
1606 m.m[0][1] = 0.0f;
1607 m.m[1][1] = h2;
1608 m.m[2][1] = 0.0f;
1609 m.m[3][1] = bottom + h2;
1610 m.m[0][2] = 0.0f;
1611 m.m[1][2] = 0.0f;
1612 m.m[2][2] = (farPlane - nearPlane) / 2.0f;
1613 m.m[3][2] = (nearPlane + farPlane) / 2.0f;
1614 m.m[0][3] = 0.0f;
1615 m.m[1][3] = 0.0f;
1616 m.m[2][3] = 0.0f;
1617 m.m[3][3] = 1.0f;
1618 m.flagBits = General;
1619
1620 *this *= m;
1621}
1622
1623/*!
1624 \deprecated
1625
1626 Flips between right-handed and left-handed coordinate systems
1627 by multiplying the y and z co-ordinates by -1. This is normally
1628 used to create a left-handed orthographic view without scaling
1629 the viewport as ortho() does.
1630
1631 \sa ortho()
1632*/
1633void QMatrix4x4::flipCoordinates()
1634{
1635 // Multiplying the y and z coordinates with -1 does NOT flip between right-handed and
1636 // left-handed coordinate systems, it just rotates 180 degrees around the x axis, so
1637 // I'm deprecating this function.
1638 if (flagBits < Rotation2D) {
1639 // Translation | Scale
1640 m[1][1] = -m[1][1];
1641 m[2][2] = -m[2][2];
1642 } else {
1643 m[1][0] = -m[1][0];
1644 m[1][1] = -m[1][1];
1645 m[1][2] = -m[1][2];
1646 m[1][3] = -m[1][3];
1647 m[2][0] = -m[2][0];
1648 m[2][1] = -m[2][1];
1649 m[2][2] = -m[2][2];
1650 m[2][3] = -m[2][3];
1651 }
1652 flagBits |= Scale;
1653}
1654
1655/*!
1656 Retrieves the 16 items in this matrix and copies them to \a values
1657 in row-major order.
1658*/
1659void QMatrix4x4::copyDataTo(float *values) const
1660{
1661 for (int row = 0; row < 4; ++row)
1662 for (int col = 0; col < 4; ++col)
1663 values[row * 4 + col] = float(m[col][row]);
1664}
1665
1666#if QT_DEPRECATED_SINCE(5, 15)
1667/*!
1668 \obsolete
1669
1670 Use toTransform() instead.
1671
1672 Returns the conventional Qt 2D affine transformation matrix that
1673 corresponds to this matrix. It is assumed that this matrix
1674 only contains 2D affine transformation elements.
1675
1676 \sa toTransform()
1677*/
1678QMatrix QMatrix4x4::toAffine() const
1679{
1680 return QMatrix(m[0][0], m[0][1],
1681 m[1][0], m[1][1],
1682 m[3][0], m[3][1]);
1683}
1684#endif // QT_DEPRECATED_SINCE(5, 15)
1685
1686/*!
1687 Returns the conventional Qt 2D transformation matrix that
1688 corresponds to this matrix.
1689
1690 The returned QTransform is formed by simply dropping the
1691 third row and third column of the QMatrix4x4. This is suitable
1692 for implementing orthographic projections where the z co-ordinate
1693 should be dropped rather than projected.
1694
1695 \sa toAffine()
1696*/
1697QTransform QMatrix4x4::toTransform() const
1698{
1699 return QTransform(m[0][0], m[0][1], m[0][3],
1700 m[1][0], m[1][1], m[1][3],
1701 m[3][0], m[3][1], m[3][3]);
1702}
1703
1704/*!
1705 Returns the conventional Qt 2D transformation matrix that
1706 corresponds to this matrix.
1707
1708 If \a distanceToPlane is non-zero, it indicates a projection
1709 factor to use to adjust for the z co-ordinate. The value of
1710 1024 corresponds to the projection factor used
1711 by QTransform::rotate() for the x and y axes.
1712
1713 If \a distanceToPlane is zero, then the returned QTransform
1714 is formed by simply dropping the third row and third column
1715 of the QMatrix4x4. This is suitable for implementing
1716 orthographic projections where the z co-ordinate should
1717 be dropped rather than projected.
1718
1719 \sa toAffine()
1720*/
1721QTransform QMatrix4x4::toTransform(float distanceToPlane) const
1722{
1723 if (distanceToPlane == 1024.0f) {
1724 // Optimize the common case with constants.
1725 return QTransform(m[0][0], m[0][1], m[0][3] - m[0][2] * inv_dist_to_plane,
1726 m[1][0], m[1][1], m[1][3] - m[1][2] * inv_dist_to_plane,
1727 m[3][0], m[3][1], m[3][3] - m[3][2] * inv_dist_to_plane);
1728 } else if (distanceToPlane != 0.0f) {
1729 // The following projection matrix is pre-multiplied with "matrix":
1730 // | 1 0 0 0 |
1731 // | 0 1 0 0 |
1732 // | 0 0 1 0 |
1733 // | 0 0 d 1 |
1734 // where d = -1 / distanceToPlane. After projection, row 3 and
1735 // column 3 are dropped to form the final QTransform.
1736 float d = 1.0f / distanceToPlane;
1737 return QTransform(m[0][0], m[0][1], m[0][3] - m[0][2] * d,
1738 m[1][0], m[1][1], m[1][3] - m[1][2] * d,
1739 m[3][0], m[3][1], m[3][3] - m[3][2] * d);
1740 } else {
1741 // Orthographic projection: drop row 3 and column 3.
1742 return QTransform(m[0][0], m[0][1], m[0][3],
1743 m[1][0], m[1][1], m[1][3],
1744 m[3][0], m[3][1], m[3][3]);
1745 }
1746}
1747
1748/*!
1749 \fn QPoint QMatrix4x4::map(const QPoint& point) const
1750
1751 Maps \a point by multiplying this matrix by \a point.
1752
1753 \sa mapRect()
1754*/
1755
1756/*!
1757 \fn QPointF QMatrix4x4::map(const QPointF& point) const
1758
1759 Maps \a point by multiplying this matrix by \a point.
1760
1761 \sa mapRect()
1762*/
1763
1764#ifndef QT_NO_VECTOR3D
1765
1766/*!
1767 \fn QVector3D QMatrix4x4::map(const QVector3D& point) const
1768
1769 Maps \a point by multiplying this matrix by \a point.
1770
1771 \sa mapRect(), mapVector()
1772*/
1773
1774/*!
1775 \fn QVector3D QMatrix4x4::mapVector(const QVector3D& vector) const
1776
1777 Maps \a vector by multiplying the top 3x3 portion of this matrix
1778 by \a vector. The translation and projection components of
1779 this matrix are ignored.
1780
1781 \sa map()
1782*/
1783
1784#endif
1785
1786#ifndef QT_NO_VECTOR4D
1787
1788/*!
1789 \fn QVector4D QMatrix4x4::map(const QVector4D& point) const;
1790
1791 Maps \a point by multiplying this matrix by \a point.
1792
1793 \sa mapRect()
1794*/
1795
1796#endif
1797
1798/*!
1799 Maps \a rect by multiplying this matrix by the corners
1800 of \a rect and then forming a new rectangle from the results.
1801 The returned rectangle will be an ordinary 2D rectangle
1802 with sides parallel to the horizontal and vertical axes.
1803
1804 \sa map()
1805*/
1806QRect QMatrix4x4::mapRect(const QRect& rect) const
1807{
1808 if (flagBits < Scale) {
1809 // Translation
1810 return QRect(qRound(d: rect.x() + m[3][0]),
1811 qRound(d: rect.y() + m[3][1]),
1812 rect.width(), rect.height());
1813 } else if (flagBits < Rotation2D) {
1814 // Translation | Scale
1815 float x = rect.x() * m[0][0] + m[3][0];
1816 float y = rect.y() * m[1][1] + m[3][1];
1817 float w = rect.width() * m[0][0];
1818 float h = rect.height() * m[1][1];
1819 if (w < 0) {
1820 w = -w;
1821 x -= w;
1822 }
1823 if (h < 0) {
1824 h = -h;
1825 y -= h;
1826 }
1827 return QRect(qRound(d: x), qRound(d: y), qRound(d: w), qRound(d: h));
1828 }
1829
1830 QPoint tl = map(point: rect.topLeft());
1831 QPoint tr = map(point: QPoint(rect.x() + rect.width(), rect.y()));
1832 QPoint bl = map(point: QPoint(rect.x(), rect.y() + rect.height()));
1833 QPoint br = map(point: QPoint(rect.x() + rect.width(),
1834 rect.y() + rect.height()));
1835
1836 int xmin = qMin(a: qMin(a: tl.x(), b: tr.x()), b: qMin(a: bl.x(), b: br.x()));
1837 int xmax = qMax(a: qMax(a: tl.x(), b: tr.x()), b: qMax(a: bl.x(), b: br.x()));
1838 int ymin = qMin(a: qMin(a: tl.y(), b: tr.y()), b: qMin(a: bl.y(), b: br.y()));
1839 int ymax = qMax(a: qMax(a: tl.y(), b: tr.y()), b: qMax(a: bl.y(), b: br.y()));
1840
1841 return QRect(xmin, ymin, xmax - xmin, ymax - ymin);
1842}
1843
1844/*!
1845 Maps \a rect by multiplying this matrix by the corners
1846 of \a rect and then forming a new rectangle from the results.
1847 The returned rectangle will be an ordinary 2D rectangle
1848 with sides parallel to the horizontal and vertical axes.
1849
1850 \sa map()
1851*/
1852QRectF QMatrix4x4::mapRect(const QRectF& rect) const
1853{
1854 if (flagBits < Scale) {
1855 // Translation
1856 return rect.translated(dx: m[3][0], dy: m[3][1]);
1857 } else if (flagBits < Rotation2D) {
1858 // Translation | Scale
1859 float x = rect.x() * m[0][0] + m[3][0];
1860 float y = rect.y() * m[1][1] + m[3][1];
1861 float w = rect.width() * m[0][0];
1862 float h = rect.height() * m[1][1];
1863 if (w < 0) {
1864 w = -w;
1865 x -= w;
1866 }
1867 if (h < 0) {
1868 h = -h;
1869 y -= h;
1870 }
1871 return QRectF(x, y, w, h);
1872 }
1873
1874 QPointF tl = map(point: rect.topLeft()); QPointF tr = map(point: rect.topRight());
1875 QPointF bl = map(point: rect.bottomLeft()); QPointF br = map(point: rect.bottomRight());
1876
1877 float xmin = qMin(a: qMin(a: tl.x(), b: tr.x()), b: qMin(a: bl.x(), b: br.x()));
1878 float xmax = qMax(a: qMax(a: tl.x(), b: tr.x()), b: qMax(a: bl.x(), b: br.x()));
1879 float ymin = qMin(a: qMin(a: tl.y(), b: tr.y()), b: qMin(a: bl.y(), b: br.y()));
1880 float ymax = qMax(a: qMax(a: tl.y(), b: tr.y()), b: qMax(a: bl.y(), b: br.y()));
1881
1882 return QRectF(QPointF(xmin, ymin), QPointF(xmax, ymax));
1883}
1884
1885/*!
1886 \fn float *QMatrix4x4::data()
1887
1888 Returns a pointer to the raw data of this matrix.
1889
1890 \sa constData(), optimize()
1891*/
1892
1893/*!
1894 \fn const float *QMatrix4x4::data() const
1895
1896 Returns a constant pointer to the raw data of this matrix.
1897 This raw data is stored in column-major format.
1898
1899 \sa constData()
1900*/
1901
1902/*!
1903 \fn const float *QMatrix4x4::constData() const
1904
1905 Returns a constant pointer to the raw data of this matrix.
1906 This raw data is stored in column-major format.
1907
1908 \sa data()
1909*/
1910
1911// Helper routine for inverting orthonormal matrices that consist
1912// of just rotations and translations.
1913QMatrix4x4 QMatrix4x4::orthonormalInverse() const
1914{
1915 QMatrix4x4 result(1); // The '1' says not to load identity
1916
1917 result.m[0][0] = m[0][0];
1918 result.m[1][0] = m[0][1];
1919 result.m[2][0] = m[0][2];
1920
1921 result.m[0][1] = m[1][0];
1922 result.m[1][1] = m[1][1];
1923 result.m[2][1] = m[1][2];
1924
1925 result.m[0][2] = m[2][0];
1926 result.m[1][2] = m[2][1];
1927 result.m[2][2] = m[2][2];
1928
1929 result.m[0][3] = 0.0f;
1930 result.m[1][3] = 0.0f;
1931 result.m[2][3] = 0.0f;
1932
1933 result.m[3][0] = -(result.m[0][0] * m[3][0] + result.m[1][0] * m[3][1] + result.m[2][0] * m[3][2]);
1934 result.m[3][1] = -(result.m[0][1] * m[3][0] + result.m[1][1] * m[3][1] + result.m[2][1] * m[3][2]);
1935 result.m[3][2] = -(result.m[0][2] * m[3][0] + result.m[1][2] * m[3][1] + result.m[2][2] * m[3][2]);
1936 result.m[3][3] = 1.0f;
1937
1938 result.flagBits = flagBits;
1939
1940 return result;
1941}
1942
1943/*!
1944 Optimize the usage of this matrix from its current elements.
1945
1946 Some operations such as translate(), scale(), and rotate() can be
1947 performed more efficiently if the matrix being modified is already
1948 known to be the identity, a previous translate(), a previous
1949 scale(), etc.
1950
1951 Normally the QMatrix4x4 class keeps track of this special type internally
1952 as operations are performed. However, if the matrix is modified
1953 directly with \l {QMatrix4x4::}{operator()()} or data(), then
1954 QMatrix4x4 will lose track of the special type and will revert to the
1955 safest but least efficient operations thereafter.
1956
1957 By calling optimize() after directly modifying the matrix,
1958 the programmer can force QMatrix4x4 to recover the special type if
1959 the elements appear to conform to one of the known optimized types.
1960
1961 \sa {QMatrix4x4::}{operator()()}, data(), translate()
1962*/
1963void QMatrix4x4::optimize()
1964{
1965 // If the last row is not (0, 0, 0, 1), the matrix is not a special type.
1966 flagBits = General;
1967 if (m[0][3] != 0 || m[1][3] != 0 || m[2][3] != 0 || m[3][3] != 1)
1968 return;
1969
1970 flagBits &= ~Perspective;
1971
1972 // If the last column is (0, 0, 0, 1), then there is no translation.
1973 if (m[3][0] == 0 && m[3][1] == 0 && m[3][2] == 0)
1974 flagBits &= ~Translation;
1975
1976 // If the two first elements of row 3 and column 3 are 0, then any rotation must be about Z.
1977 if (!m[0][2] && !m[1][2] && !m[2][0] && !m[2][1]) {
1978 flagBits &= ~Rotation;
1979 // If the six non-diagonal elements in the top left 3x3 matrix are 0, there is no rotation.
1980 if (!m[0][1] && !m[1][0]) {
1981 flagBits &= ~Rotation2D;
1982 // Check for identity.
1983 if (m[0][0] == 1 && m[1][1] == 1 && m[2][2] == 1)
1984 flagBits &= ~Scale;
1985 } else {
1986 // If the columns are orthonormal and form a right-handed system, then there is no scale.
1987 double mm[4][4];
1988 copyToDoubles(m, mm);
1989 double det = matrixDet2(m: mm, col0: 0, col1: 1, row0: 0, row1: 1);
1990 double lenX = mm[0][0] * mm[0][0] + mm[0][1] * mm[0][1];
1991 double lenY = mm[1][0] * mm[1][0] + mm[1][1] * mm[1][1];
1992 double lenZ = mm[2][2];
1993 if (qFuzzyCompare(p1: det, p2: 1.0) && qFuzzyCompare(p1: lenX, p2: 1.0)
1994 && qFuzzyCompare(p1: lenY, p2: 1.0) && qFuzzyCompare(p1: lenZ, p2: 1.0))
1995 {
1996 flagBits &= ~Scale;
1997 }
1998 }
1999 } else {
2000 // If the columns are orthonormal and form a right-handed system, then there is no scale.
2001 double mm[4][4];
2002 copyToDoubles(m, mm);
2003 double det = matrixDet3(m: mm, col0: 0, col1: 1, col2: 2, row0: 0, row1: 1, row2: 2);
2004 double lenX = mm[0][0] * mm[0][0] + mm[0][1] * mm[0][1] + mm[0][2] * mm[0][2];
2005 double lenY = mm[1][0] * mm[1][0] + mm[1][1] * mm[1][1] + mm[1][2] * mm[1][2];
2006 double lenZ = mm[2][0] * mm[2][0] + mm[2][1] * mm[2][1] + mm[2][2] * mm[2][2];
2007 if (qFuzzyCompare(p1: det, p2: 1.0) && qFuzzyCompare(p1: lenX, p2: 1.0)
2008 && qFuzzyCompare(p1: lenY, p2: 1.0) && qFuzzyCompare(p1: lenZ, p2: 1.0))
2009 {
2010 flagBits &= ~Scale;
2011 }
2012 }
2013}
2014
2015/*!
2016 Returns the matrix as a QVariant.
2017*/
2018QMatrix4x4::operator QVariant() const
2019{
2020 return QVariant(QMetaType::QMatrix4x4, this);
2021}
2022
2023#ifndef QT_NO_DEBUG_STREAM
2024
2025QDebug operator<<(QDebug dbg, const QMatrix4x4 &m)
2026{
2027 QDebugStateSaver saver(dbg);
2028 // Create a string that represents the matrix type.
2029 QByteArray bits;
2030 if (m.flagBits == QMatrix4x4::Identity) {
2031 bits = "Identity";
2032 } else if (m.flagBits == QMatrix4x4::General) {
2033 bits = "General";
2034 } else {
2035 if ((m.flagBits & QMatrix4x4::Translation) != 0)
2036 bits += "Translation,";
2037 if ((m.flagBits & QMatrix4x4::Scale) != 0)
2038 bits += "Scale,";
2039 if ((m.flagBits & QMatrix4x4::Rotation2D) != 0)
2040 bits += "Rotation2D,";
2041 if ((m.flagBits & QMatrix4x4::Rotation) != 0)
2042 bits += "Rotation,";
2043 if ((m.flagBits & QMatrix4x4::Perspective) != 0)
2044 bits += "Perspective,";
2045 if (bits.size() > 0)
2046 bits = bits.left(len: bits.size() - 1);
2047 }
2048
2049 // Output in row-major order because it is more human-readable.
2050 dbg.nospace() << "QMatrix4x4(type:" << bits.constData() << Qt::endl
2051 << qSetFieldWidth(width: 10)
2052 << m(0, 0) << m(0, 1) << m(0, 2) << m(0, 3) << Qt::endl
2053 << m(1, 0) << m(1, 1) << m(1, 2) << m(1, 3) << Qt::endl
2054 << m(2, 0) << m(2, 1) << m(2, 2) << m(2, 3) << Qt::endl
2055 << m(3, 0) << m(3, 1) << m(3, 2) << m(3, 3) << Qt::endl
2056 << qSetFieldWidth(width: 0) << ')';
2057 return dbg;
2058}
2059
2060#endif
2061
2062#ifndef QT_NO_DATASTREAM
2063
2064/*!
2065 \fn QDataStream &operator<<(QDataStream &stream, const QMatrix4x4 &matrix)
2066 \relates QMatrix4x4
2067
2068 Writes the given \a matrix to the given \a stream and returns a
2069 reference to the stream.
2070
2071 \sa {Serializing Qt Data Types}
2072*/
2073
2074QDataStream &operator<<(QDataStream &stream, const QMatrix4x4 &matrix)
2075{
2076 for (int row = 0; row < 4; ++row)
2077 for (int col = 0; col < 4; ++col)
2078 stream << matrix(row, col);
2079 return stream;
2080}
2081
2082/*!
2083 \fn QDataStream &operator>>(QDataStream &stream, QMatrix4x4 &matrix)
2084 \relates QMatrix4x4
2085
2086 Reads a 4x4 matrix from the given \a stream into the given \a matrix
2087 and returns a reference to the stream.
2088
2089 \sa {Serializing Qt Data Types}
2090*/
2091
2092QDataStream &operator>>(QDataStream &stream, QMatrix4x4 &matrix)
2093{
2094 float x;
2095 for (int row = 0; row < 4; ++row) {
2096 for (int col = 0; col < 4; ++col) {
2097 stream >> x;
2098 matrix(row, col) = x;
2099 }
2100 }
2101 matrix.optimize();
2102 return stream;
2103}
2104
2105#endif // QT_NO_DATASTREAM
2106
2107#endif // QT_NO_MATRIX4X4
2108
2109QT_END_NAMESPACE
2110

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