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