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