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
11QT_BEGIN_NAMESPACE
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 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, col0: col1, col1: col2, row0: row1, row1: row2)
265 - m[col1][row0] * matrixDet2(m, col0, col1: col2, row0: row1, row1: row2)
266 + m[col2][row0] * matrixDet2(m, col0, col1, row0: row1, 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, col0: 1, col1: 2, col2: 3, row0: 1, row1: 2, row2: 3);
274 det -= m[1][0] * matrixDet3(m, col0: 0, col1: 2, col2: 3, row0: 1, row1: 2, row2: 3);
275 det += m[2][0] * matrixDet3(m, col0: 0, col1: 1, col2: 3, row0: 1, row1: 2, row2: 3);
276 det -= m[3][0] * matrixDet3(m, col0: 0, col1: 1, col2: 2, row0: 1, row1: 2, row2: 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(m: mm, col0: 0, col1: 1, col2: 2, row0: 0, row1: 1, row2: 2);
301 return matrixDet4(m: 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(m: mm, col0: 0, col1: 1, col2: 2, row0: 0, row1: 1, row2: 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(m: mm, col0: 1, col1: 2, row0: 1, row1: 2) * det;
370 inv.m[0][1] = -matrixDet2(m: mm, col0: 0, col1: 2, row0: 1, row1: 2) * det;
371 inv.m[0][2] = matrixDet2(m: mm, col0: 0, col1: 1, row0: 1, row1: 2) * det;
372 inv.m[0][3] = 0;
373 inv.m[1][0] = -matrixDet2(m: mm, col0: 1, col1: 2, row0: 0, row1: 2) * det;
374 inv.m[1][1] = matrixDet2(m: mm, col0: 0, col1: 2, row0: 0, row1: 2) * det;
375 inv.m[1][2] = -matrixDet2(m: mm, col0: 0, col1: 1, row0: 0, row1: 2) * det;
376 inv.m[1][3] = 0;
377 inv.m[2][0] = matrixDet2(m: mm, col0: 1, col1: 2, row0: 0, row1: 1) * det;
378 inv.m[2][1] = -matrixDet2(m: mm, col0: 0, col1: 2, row0: 0, row1: 1) * det;
379 inv.m[2][2] = matrixDet2(m: mm, col0: 0, col1: 1, row0: 0, row1: 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(m: 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(m: mm, col0: 1, col1: 2, col2: 3, row0: 1, row1: 2, row2: 3) * det;
406 inv.m[0][1] = -matrixDet3(m: mm, col0: 0, col1: 2, col2: 3, row0: 1, row1: 2, row2: 3) * det;
407 inv.m[0][2] = matrixDet3(m: mm, col0: 0, col1: 1, col2: 3, row0: 1, row1: 2, row2: 3) * det;
408 inv.m[0][3] = -matrixDet3(m: mm, col0: 0, col1: 1, col2: 2, row0: 1, row1: 2, row2: 3) * det;
409 inv.m[1][0] = -matrixDet3(m: mm, col0: 1, col1: 2, col2: 3, row0: 0, row1: 2, row2: 3) * det;
410 inv.m[1][1] = matrixDet3(m: mm, col0: 0, col1: 2, col2: 3, row0: 0, row1: 2, row2: 3) * det;
411 inv.m[1][2] = -matrixDet3(m: mm, col0: 0, col1: 1, col2: 3, row0: 0, row1: 2, row2: 3) * det;
412 inv.m[1][3] = matrixDet3(m: mm, col0: 0, col1: 1, col2: 2, row0: 0, row1: 2, row2: 3) * det;
413 inv.m[2][0] = matrixDet3(m: mm, col0: 1, col1: 2, col2: 3, row0: 0, row1: 1, row2: 3) * det;
414 inv.m[2][1] = -matrixDet3(m: mm, col0: 0, col1: 2, col2: 3, row0: 0, row1: 1, row2: 3) * det;
415 inv.m[2][2] = matrixDet3(m: mm, col0: 0, col1: 1, col2: 3, row0: 0, row1: 1, row2: 3) * det;
416 inv.m[2][3] = -matrixDet3(m: mm, col0: 0, col1: 1, col2: 2, row0: 0, row1: 1, row2: 3) * det;
417 inv.m[3][0] = -matrixDet3(m: mm, col0: 1, col1: 2, col2: 3, row0: 0, row1: 1, row2: 2) * det;
418 inv.m[3][1] = matrixDet3(m: mm, col0: 0, col1: 2, col2: 3, row0: 0, row1: 1, row2: 2) * det;
419 inv.m[3][2] = -matrixDet3(m: mm, col0: 0, col1: 1, col2: 3, row0: 0, row1: 1, row2: 2) * det;
420 inv.m[3][3] = matrixDet3(m: mm, col0: 0, col1: 1, col2: 2, row0: 0, row1: 1, row2: 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(m: mm, col0: 0, col1: 1, col2: 2, row0: 0, row1: 1, row2: 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 qFuzzyCompare(const QMatrix4x4& m1, const QMatrix4x4& m2)
733 \relates QMatrix4x4
734
735 Returns \c true if \a m1 and \a m2 are equal, allowing for a small
736 fuzziness factor for floating-point comparisons; false otherwise.
737*/
738bool qFuzzyCompare(const QMatrix4x4& m1, const QMatrix4x4& m2)
739{
740 return qFuzzyCompare(p1: m1.m[0][0], p2: m2.m[0][0]) &&
741 qFuzzyCompare(p1: m1.m[0][1], p2: m2.m[0][1]) &&
742 qFuzzyCompare(p1: m1.m[0][2], p2: m2.m[0][2]) &&
743 qFuzzyCompare(p1: m1.m[0][3], p2: m2.m[0][3]) &&
744 qFuzzyCompare(p1: m1.m[1][0], p2: m2.m[1][0]) &&
745 qFuzzyCompare(p1: m1.m[1][1], p2: m2.m[1][1]) &&
746 qFuzzyCompare(p1: m1.m[1][2], p2: m2.m[1][2]) &&
747 qFuzzyCompare(p1: m1.m[1][3], p2: m2.m[1][3]) &&
748 qFuzzyCompare(p1: m1.m[2][0], p2: m2.m[2][0]) &&
749 qFuzzyCompare(p1: m1.m[2][1], p2: m2.m[2][1]) &&
750 qFuzzyCompare(p1: m1.m[2][2], p2: m2.m[2][2]) &&
751 qFuzzyCompare(p1: m1.m[2][3], p2: m2.m[2][3]) &&
752 qFuzzyCompare(p1: m1.m[3][0], p2: m2.m[3][0]) &&
753 qFuzzyCompare(p1: m1.m[3][1], p2: m2.m[3][1]) &&
754 qFuzzyCompare(p1: m1.m[3][2], p2: m2.m[3][2]) &&
755 qFuzzyCompare(p1: m1.m[3][3], p2: m2.m[3][3]);
756}
757
758
759#ifndef QT_NO_VECTOR3D
760
761/*!
762 Multiplies this matrix by another that scales coordinates by
763 the components of \a vector.
764
765 \sa translate(), rotate()
766*/
767void QMatrix4x4::scale(const QVector3D& vector)
768{
769 float vx = vector.x();
770 float vy = vector.y();
771 float vz = vector.z();
772 if (flagBits < Scale) {
773 m[0][0] = vx;
774 m[1][1] = vy;
775 m[2][2] = vz;
776 } else if (flagBits < Rotation2D) {
777 m[0][0] *= vx;
778 m[1][1] *= vy;
779 m[2][2] *= vz;
780 } else if (flagBits < Rotation) {
781 m[0][0] *= vx;
782 m[0][1] *= vx;
783 m[1][0] *= vy;
784 m[1][1] *= vy;
785 m[2][2] *= vz;
786 } else {
787 m[0][0] *= vx;
788 m[0][1] *= vx;
789 m[0][2] *= vx;
790 m[0][3] *= vx;
791 m[1][0] *= vy;
792 m[1][1] *= vy;
793 m[1][2] *= vy;
794 m[1][3] *= vy;
795 m[2][0] *= vz;
796 m[2][1] *= vz;
797 m[2][2] *= vz;
798 m[2][3] *= vz;
799 }
800 flagBits |= Scale;
801}
802
803#endif
804
805/*!
806 \overload
807
808 Multiplies this matrix by another that scales coordinates by the
809 components \a x, and \a y.
810
811 \sa translate(), rotate()
812*/
813void QMatrix4x4::scale(float x, float y)
814{
815 if (flagBits < Scale) {
816 m[0][0] = x;
817 m[1][1] = y;
818 } else if (flagBits < Rotation2D) {
819 m[0][0] *= x;
820 m[1][1] *= y;
821 } else if (flagBits < Rotation) {
822 m[0][0] *= x;
823 m[0][1] *= x;
824 m[1][0] *= y;
825 m[1][1] *= y;
826 } else {
827 m[0][0] *= x;
828 m[0][1] *= x;
829 m[0][2] *= x;
830 m[0][3] *= x;
831 m[1][0] *= y;
832 m[1][1] *= y;
833 m[1][2] *= y;
834 m[1][3] *= y;
835 }
836 flagBits |= Scale;
837}
838
839/*!
840 \overload
841
842 Multiplies this matrix by another that scales coordinates by the
843 components \a x, \a y, and \a z.
844
845 \sa translate(), rotate()
846*/
847void QMatrix4x4::scale(float x, float y, float z)
848{
849 if (flagBits < Scale) {
850 m[0][0] = x;
851 m[1][1] = y;
852 m[2][2] = z;
853 } else if (flagBits < Rotation2D) {
854 m[0][0] *= x;
855 m[1][1] *= y;
856 m[2][2] *= z;
857 } else if (flagBits < Rotation) {
858 m[0][0] *= x;
859 m[0][1] *= x;
860 m[1][0] *= y;
861 m[1][1] *= y;
862 m[2][2] *= z;
863 } else {
864 m[0][0] *= x;
865 m[0][1] *= x;
866 m[0][2] *= x;
867 m[0][3] *= x;
868 m[1][0] *= y;
869 m[1][1] *= y;
870 m[1][2] *= y;
871 m[1][3] *= y;
872 m[2][0] *= z;
873 m[2][1] *= z;
874 m[2][2] *= z;
875 m[2][3] *= z;
876 }
877 flagBits |= Scale;
878}
879
880/*!
881 \overload
882
883 Multiplies this matrix by another that scales coordinates by the
884 given \a factor.
885
886 \sa translate(), rotate()
887*/
888void QMatrix4x4::scale(float factor)
889{
890 if (flagBits < Scale) {
891 m[0][0] = factor;
892 m[1][1] = factor;
893 m[2][2] = factor;
894 } else if (flagBits < Rotation2D) {
895 m[0][0] *= factor;
896 m[1][1] *= factor;
897 m[2][2] *= factor;
898 } else if (flagBits < Rotation) {
899 m[0][0] *= factor;
900 m[0][1] *= factor;
901 m[1][0] *= factor;
902 m[1][1] *= factor;
903 m[2][2] *= factor;
904 } else {
905 m[0][0] *= factor;
906 m[0][1] *= factor;
907 m[0][2] *= factor;
908 m[0][3] *= factor;
909 m[1][0] *= factor;
910 m[1][1] *= factor;
911 m[1][2] *= factor;
912 m[1][3] *= factor;
913 m[2][0] *= factor;
914 m[2][1] *= factor;
915 m[2][2] *= factor;
916 m[2][3] *= factor;
917 }
918 flagBits |= Scale;
919}
920
921#ifndef QT_NO_VECTOR3D
922/*!
923 Multiplies this matrix by another that translates coordinates by
924 the components of \a vector.
925
926 \sa scale(), rotate()
927*/
928
929void QMatrix4x4::translate(const QVector3D& vector)
930{
931 float vx = vector.x();
932 float vy = vector.y();
933 float vz = vector.z();
934 if (flagBits == Identity) {
935 m[3][0] = vx;
936 m[3][1] = vy;
937 m[3][2] = vz;
938 } else if (flagBits == Translation) {
939 m[3][0] += vx;
940 m[3][1] += vy;
941 m[3][2] += vz;
942 } else if (flagBits == Scale) {
943 m[3][0] = m[0][0] * vx;
944 m[3][1] = m[1][1] * vy;
945 m[3][2] = m[2][2] * vz;
946 } else if (flagBits == (Translation | Scale)) {
947 m[3][0] += m[0][0] * vx;
948 m[3][1] += m[1][1] * vy;
949 m[3][2] += m[2][2] * vz;
950 } else if (flagBits < Rotation) {
951 m[3][0] += m[0][0] * vx + m[1][0] * vy;
952 m[3][1] += m[0][1] * vx + m[1][1] * vy;
953 m[3][2] += m[2][2] * vz;
954 } else {
955 m[3][0] += m[0][0] * vx + m[1][0] * vy + m[2][0] * vz;
956 m[3][1] += m[0][1] * vx + m[1][1] * vy + m[2][1] * vz;
957 m[3][2] += m[0][2] * vx + m[1][2] * vy + m[2][2] * vz;
958 m[3][3] += m[0][3] * vx + m[1][3] * vy + m[2][3] * vz;
959 }
960 flagBits |= Translation;
961}
962#endif
963
964/*!
965 \overload
966
967 Multiplies this matrix by another that translates coordinates
968 by the components \a x, and \a y.
969
970 \sa scale(), rotate()
971*/
972void QMatrix4x4::translate(float x, float y)
973{
974 if (flagBits == Identity) {
975 m[3][0] = x;
976 m[3][1] = y;
977 } else if (flagBits == Translation) {
978 m[3][0] += x;
979 m[3][1] += y;
980 } else if (flagBits == Scale) {
981 m[3][0] = m[0][0] * x;
982 m[3][1] = m[1][1] * y;
983 } else if (flagBits == (Translation | Scale)) {
984 m[3][0] += m[0][0] * x;
985 m[3][1] += m[1][1] * y;
986 } else if (flagBits < Rotation) {
987 m[3][0] += m[0][0] * x + m[1][0] * y;
988 m[3][1] += m[0][1] * x + m[1][1] * y;
989 } else {
990 m[3][0] += m[0][0] * x + m[1][0] * y;
991 m[3][1] += m[0][1] * x + m[1][1] * y;
992 m[3][2] += m[0][2] * x + m[1][2] * y;
993 m[3][3] += m[0][3] * x + m[1][3] * y;
994 }
995 flagBits |= Translation;
996}
997
998/*!
999 \overload
1000
1001 Multiplies this matrix by another that translates coordinates
1002 by the components \a x, \a y, and \a z.
1003
1004 \sa scale(), rotate()
1005*/
1006void QMatrix4x4::translate(float x, float y, float z)
1007{
1008 if (flagBits == Identity) {
1009 m[3][0] = x;
1010 m[3][1] = y;
1011 m[3][2] = z;
1012 } else if (flagBits == Translation) {
1013 m[3][0] += x;
1014 m[3][1] += y;
1015 m[3][2] += z;
1016 } else if (flagBits == Scale) {
1017 m[3][0] = m[0][0] * x;
1018 m[3][1] = m[1][1] * y;
1019 m[3][2] = m[2][2] * z;
1020 } else if (flagBits == (Translation | Scale)) {
1021 m[3][0] += m[0][0] * x;
1022 m[3][1] += m[1][1] * y;
1023 m[3][2] += m[2][2] * z;
1024 } else if (flagBits < Rotation) {
1025 m[3][0] += m[0][0] * x + m[1][0] * y;
1026 m[3][1] += m[0][1] * x + m[1][1] * y;
1027 m[3][2] += m[2][2] * z;
1028 } else {
1029 m[3][0] += m[0][0] * x + m[1][0] * y + m[2][0] * z;
1030 m[3][1] += m[0][1] * x + m[1][1] * y + m[2][1] * z;
1031 m[3][2] += m[0][2] * x + m[1][2] * y + m[2][2] * z;
1032 m[3][3] += m[0][3] * x + m[1][3] * y + m[2][3] * z;
1033 }
1034 flagBits |= Translation;
1035}
1036
1037#ifndef QT_NO_VECTOR3D
1038/*!
1039 Multiples this matrix by another that rotates coordinates through
1040 \a angle degrees about \a vector.
1041
1042 \sa scale(), translate()
1043*/
1044
1045void QMatrix4x4::rotate(float angle, const QVector3D& vector)
1046{
1047 rotate(angle, x: vector.x(), y: vector.y(), z: vector.z());
1048}
1049
1050#endif
1051
1052/*!
1053 \overload
1054
1055 Multiplies this matrix by another that rotates coordinates through
1056 \a angle degrees about the vector (\a x, \a y, \a z).
1057
1058 \sa scale(), translate()
1059*/
1060void QMatrix4x4::rotate(float angle, float x, float y, float z)
1061{
1062 if (angle == 0.0f)
1063 return;
1064 float c, s;
1065 if (angle == 90.0f || angle == -270.0f) {
1066 s = 1.0f;
1067 c = 0.0f;
1068 } else if (angle == -90.0f || angle == 270.0f) {
1069 s = -1.0f;
1070 c = 0.0f;
1071 } else if (angle == 180.0f || angle == -180.0f) {
1072 s = 0.0f;
1073 c = -1.0f;
1074 } else {
1075 float a = qDegreesToRadians(degrees: angle);
1076 c = std::cos(x: a);
1077 s = std::sin(x: a);
1078 }
1079 if (x == 0.0f) {
1080 if (y == 0.0f) {
1081 if (z != 0.0f) {
1082 // Rotate around the Z axis.
1083 if (z < 0)
1084 s = -s;
1085 float tmp;
1086 m[0][0] = (tmp = m[0][0]) * c + m[1][0] * s;
1087 m[1][0] = m[1][0] * c - tmp * s;
1088 m[0][1] = (tmp = m[0][1]) * c + m[1][1] * s;
1089 m[1][1] = m[1][1] * c - tmp * s;
1090 m[0][2] = (tmp = m[0][2]) * c + m[1][2] * s;
1091 m[1][2] = m[1][2] * c - tmp * s;
1092 m[0][3] = (tmp = m[0][3]) * c + m[1][3] * s;
1093 m[1][3] = m[1][3] * c - tmp * s;
1094
1095 flagBits |= Rotation2D;
1096 return;
1097 }
1098 } else if (z == 0.0f) {
1099 // Rotate around the Y axis.
1100 if (y < 0)
1101 s = -s;
1102 float tmp;
1103 m[2][0] = (tmp = m[2][0]) * c + m[0][0] * s;
1104 m[0][0] = m[0][0] * c - tmp * s;
1105 m[2][1] = (tmp = m[2][1]) * c + m[0][1] * s;
1106 m[0][1] = m[0][1] * c - tmp * s;
1107 m[2][2] = (tmp = m[2][2]) * c + m[0][2] * s;
1108 m[0][2] = m[0][2] * c - tmp * s;
1109 m[2][3] = (tmp = m[2][3]) * c + m[0][3] * s;
1110 m[0][3] = m[0][3] * c - tmp * s;
1111
1112 flagBits |= Rotation;
1113 return;
1114 }
1115 } else if (y == 0.0f && z == 0.0f) {
1116 // Rotate around the X axis.
1117 if (x < 0)
1118 s = -s;
1119 float tmp;
1120 m[1][0] = (tmp = m[1][0]) * c + m[2][0] * s;
1121 m[2][0] = m[2][0] * c - tmp * s;
1122 m[1][1] = (tmp = m[1][1]) * c + m[2][1] * s;
1123 m[2][1] = m[2][1] * c - tmp * s;
1124 m[1][2] = (tmp = m[1][2]) * c + m[2][2] * s;
1125 m[2][2] = m[2][2] * c - tmp * s;
1126 m[1][3] = (tmp = m[1][3]) * c + m[2][3] * s;
1127 m[2][3] = m[2][3] * c - tmp * s;
1128
1129 flagBits |= Rotation;
1130 return;
1131 }
1132
1133 double len = double(x) * double(x) +
1134 double(y) * double(y) +
1135 double(z) * double(z);
1136 if (!qFuzzyCompare(p1: len, p2: 1.0) && !qFuzzyIsNull(d: len)) {
1137 len = std::sqrt(x: len);
1138 x = float(double(x) / len);
1139 y = float(double(y) / len);
1140 z = float(double(z) / len);
1141 }
1142 float ic = 1.0f - c;
1143 QMatrix4x4 rot(Qt::Uninitialized);
1144 rot.m[0][0] = x * x * ic + c;
1145 rot.m[1][0] = x * y * ic - z * s;
1146 rot.m[2][0] = x * z * ic + y * s;
1147 rot.m[3][0] = 0.0f;
1148 rot.m[0][1] = y * x * ic + z * s;
1149 rot.m[1][1] = y * y * ic + c;
1150 rot.m[2][1] = y * z * ic - x * s;
1151 rot.m[3][1] = 0.0f;
1152 rot.m[0][2] = x * z * ic - y * s;
1153 rot.m[1][2] = y * z * ic + x * s;
1154 rot.m[2][2] = z * z * ic + c;
1155 rot.m[3][2] = 0.0f;
1156 rot.m[0][3] = 0.0f;
1157 rot.m[1][3] = 0.0f;
1158 rot.m[2][3] = 0.0f;
1159 rot.m[3][3] = 1.0f;
1160 rot.flagBits = Rotation;
1161 *this *= rot;
1162}
1163
1164/*!
1165 \internal
1166*/
1167void QMatrix4x4::projectedRotate(float angle, float x, float y, float z, float distanceToPlane)
1168{
1169 // Used by QGraphicsRotation::applyTo() to perform a rotation
1170 // and projection back to 2D in a single step.
1171 if (qIsNull(f: distanceToPlane))
1172 return rotate(angle, x, y, z);
1173 if (angle == 0.0f)
1174 return;
1175
1176 float c, s;
1177 if (angle == 90.0f || angle == -270.0f) {
1178 s = 1.0f;
1179 c = 0.0f;
1180 } else if (angle == -90.0f || angle == 270.0f) {
1181 s = -1.0f;
1182 c = 0.0f;
1183 } else if (angle == 180.0f || angle == -180.0f) {
1184 s = 0.0f;
1185 c = -1.0f;
1186 } else {
1187 float a = qDegreesToRadians(degrees: angle);
1188 c = std::cos(x: a);
1189 s = std::sin(x: a);
1190 }
1191
1192 const qreal d = 1.0 / distanceToPlane;
1193 if (x == 0.0f) {
1194 if (y == 0.0f) {
1195 if (z != 0.0f) {
1196 // Rotate around the Z axis.
1197 if (z < 0)
1198 s = -s;
1199 float tmp;
1200 m[0][0] = (tmp = m[0][0]) * c + m[1][0] * s;
1201 m[1][0] = m[1][0] * c - tmp * s;
1202 m[0][1] = (tmp = m[0][1]) * c + m[1][1] * s;
1203 m[1][1] = m[1][1] * c - tmp * s;
1204 m[0][2] = (tmp = m[0][2]) * c + m[1][2] * s;
1205 m[1][2] = m[1][2] * c - tmp * s;
1206 m[0][3] = (tmp = m[0][3]) * c + m[1][3] * s;
1207 m[1][3] = m[1][3] * c - tmp * s;
1208
1209 flagBits |= Rotation2D;
1210 return;
1211 }
1212 } else if (z == 0.0f) {
1213 // Rotate around the Y axis.
1214 if (y < 0)
1215 s = -s;
1216 s *= d;
1217 m[0][0] = m[0][0] * c + m[3][0] * s;
1218 m[0][1] = m[0][1] * c + m[3][1] * s;
1219 m[0][2] = m[0][2] * c + m[3][2] * s;
1220 m[0][3] = m[0][3] * c + m[3][3] * s;
1221 flagBits = General;
1222 return;
1223 }
1224 } else if (y == 0.0f && z == 0.0f) {
1225 // Rotate around the X axis.
1226 if (x < 0)
1227 s = -s;
1228 s *= d;
1229 m[1][0] = m[1][0] * c - m[3][0] * s;
1230 m[1][1] = m[1][1] * c - m[3][1] * s;
1231 m[1][2] = m[1][2] * c - m[3][2] * s;
1232 m[1][3] = m[1][3] * c - m[3][3] * s;
1233 flagBits = General;
1234 return;
1235 }
1236 double len = double(x) * double(x) +
1237 double(y) * double(y) +
1238 double(z) * double(z);
1239 if (!qFuzzyCompare(p1: len, p2: 1.0) && !qFuzzyIsNull(d: len)) {
1240 len = std::sqrt(x: len);
1241 x = float(double(x) / len);
1242 y = float(double(y) / len);
1243 z = float(double(z) / len);
1244 }
1245 const float ic = 1.0f - c;
1246 QMatrix4x4 rot(Qt::Uninitialized);
1247 rot.m[0][0] = x * x * ic + c;
1248 rot.m[1][0] = x * y * ic - z * s;
1249 rot.m[2][0] = 0.0f;
1250 rot.m[3][0] = 0.0f;
1251 rot.m[0][1] = y * x * ic + z * s;
1252 rot.m[1][1] = y * y * ic + c;
1253 rot.m[2][1] = 0.0f;
1254 rot.m[3][1] = 0.0f;
1255 rot.m[0][2] = 0.0f;
1256 rot.m[1][2] = 0.0f;
1257 rot.m[2][2] = 1.0f;
1258 rot.m[3][2] = 0.0f;
1259 rot.m[0][3] = (x * z * ic - y * s) * -d;
1260 rot.m[1][3] = (y * z * ic + x * s) * -d;
1261 rot.m[2][3] = 0.0f;
1262 rot.m[3][3] = 1.0f;
1263 rot.flagBits = General;
1264 *this *= rot;
1265}
1266
1267#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
1268/*!
1269 \internal
1270*/
1271void QMatrix4x4::projectedRotate(float angle, float x, float y, float z)
1272{
1273 projectedRotate(angle, x, y, z, distanceToPlane: 1024.0);
1274}
1275#endif
1276
1277/*!
1278 \fn int QMatrix4x4::flags() const
1279 \internal
1280*/
1281
1282/*!
1283 \enum QMatrix4x4::Flags
1284 \internal
1285 \omitvalue Identity
1286 \omitvalue Translation
1287 \omitvalue Scale
1288 \omitvalue Rotation2D
1289 \omitvalue Rotation
1290 \omitvalue Perspective
1291 \omitvalue General
1292*/
1293
1294#ifndef QT_NO_QUATERNION
1295
1296/*!
1297 Multiples this matrix by another that rotates coordinates according
1298 to a specified \a quaternion. The \a quaternion is assumed to have
1299 been normalized.
1300
1301 \sa scale(), translate(), QQuaternion
1302*/
1303void QMatrix4x4::rotate(const QQuaternion& quaternion)
1304{
1305 // Algorithm from:
1306 // http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q54
1307
1308 QMatrix4x4 m(Qt::Uninitialized);
1309
1310 const float f2x = quaternion.x() + quaternion.x();
1311 const float f2y = quaternion.y() + quaternion.y();
1312 const float f2z = quaternion.z() + quaternion.z();
1313 const float f2xw = f2x * quaternion.scalar();
1314 const float f2yw = f2y * quaternion.scalar();
1315 const float f2zw = f2z * quaternion.scalar();
1316 const float f2xx = f2x * quaternion.x();
1317 const float f2xy = f2x * quaternion.y();
1318 const float f2xz = f2x * quaternion.z();
1319 const float f2yy = f2y * quaternion.y();
1320 const float f2yz = f2y * quaternion.z();
1321 const float f2zz = f2z * quaternion.z();
1322
1323 m.m[0][0] = 1.0f - (f2yy + f2zz);
1324 m.m[1][0] = f2xy - f2zw;
1325 m.m[2][0] = f2xz + f2yw;
1326 m.m[3][0] = 0.0f;
1327 m.m[0][1] = f2xy + f2zw;
1328 m.m[1][1] = 1.0f - (f2xx + f2zz);
1329 m.m[2][1] = f2yz - f2xw;
1330 m.m[3][1] = 0.0f;
1331 m.m[0][2] = f2xz - f2yw;
1332 m.m[1][2] = f2yz + f2xw;
1333 m.m[2][2] = 1.0f - (f2xx + f2yy);
1334 m.m[3][2] = 0.0f;
1335 m.m[0][3] = 0.0f;
1336 m.m[1][3] = 0.0f;
1337 m.m[2][3] = 0.0f;
1338 m.m[3][3] = 1.0f;
1339 m.flagBits = Rotation;
1340 *this *= m;
1341}
1342
1343#endif
1344
1345/*!
1346 \overload
1347
1348 Multiplies this matrix by another that applies an orthographic
1349 projection for a window with boundaries specified by \a rect.
1350 The near and far clipping planes will be -1 and 1 respectively.
1351
1352 \sa frustum(), perspective()
1353*/
1354void QMatrix4x4::ortho(const QRect& rect)
1355{
1356 // Note: rect.right() and rect.bottom() subtract 1 in QRect,
1357 // which gives the location of a pixel within the rectangle,
1358 // instead of the extent of the rectangle. We want the extent.
1359 // QRectF expresses the extent properly.
1360 ortho(left: rect.x(), right: rect.x() + rect.width(), bottom: rect.y() + rect.height(), top: rect.y(), nearPlane: -1.0f, farPlane: 1.0f);
1361}
1362
1363/*!
1364 \overload
1365
1366 Multiplies this matrix by another that applies an orthographic
1367 projection for a window with boundaries specified by \a rect.
1368 The near and far clipping planes will be -1 and 1 respectively.
1369
1370 \sa frustum(), perspective()
1371*/
1372void QMatrix4x4::ortho(const QRectF& rect)
1373{
1374 ortho(left: rect.left(), right: rect.right(), bottom: rect.bottom(), top: rect.top(), nearPlane: -1.0f, farPlane: 1.0f);
1375}
1376
1377/*!
1378 Multiplies this matrix by another that applies an orthographic
1379 projection for a window with lower-left corner (\a left, \a bottom),
1380 upper-right corner (\a right, \a top), and the specified \a nearPlane
1381 and \a farPlane clipping planes.
1382
1383 \sa frustum(), perspective()
1384*/
1385void QMatrix4x4::ortho(float left, float right, float bottom, float top, float nearPlane, float farPlane)
1386{
1387 // Bail out if the projection volume is zero-sized.
1388 if (left == right || bottom == top || nearPlane == farPlane)
1389 return;
1390
1391 // Construct the projection.
1392 const float width = right - left;
1393 const float invheight = top - bottom;
1394 const float clip = farPlane - nearPlane;
1395 QMatrix4x4 m(Qt::Uninitialized);
1396 m.m[0][0] = 2.0f / width;
1397 m.m[1][0] = 0.0f;
1398 m.m[2][0] = 0.0f;
1399 m.m[3][0] = -(left + right) / width;
1400 m.m[0][1] = 0.0f;
1401 m.m[1][1] = 2.0f / invheight;
1402 m.m[2][1] = 0.0f;
1403 m.m[3][1] = -(top + bottom) / invheight;
1404 m.m[0][2] = 0.0f;
1405 m.m[1][2] = 0.0f;
1406 m.m[2][2] = -2.0f / clip;
1407 m.m[3][2] = -(nearPlane + farPlane) / clip;
1408 m.m[0][3] = 0.0f;
1409 m.m[1][3] = 0.0f;
1410 m.m[2][3] = 0.0f;
1411 m.m[3][3] = 1.0f;
1412 m.flagBits = Translation | Scale;
1413
1414 // Apply the projection.
1415 *this *= m;
1416}
1417
1418/*!
1419 Multiplies this matrix by another that applies a perspective
1420 frustum projection for a window with lower-left corner (\a left, \a bottom),
1421 upper-right corner (\a right, \a top), and the specified \a nearPlane
1422 and \a farPlane clipping planes.
1423
1424 \sa ortho(), perspective()
1425*/
1426void QMatrix4x4::frustum(float left, float right, float bottom, float top, float nearPlane, float farPlane)
1427{
1428 // Bail out if the projection volume is zero-sized.
1429 if (left == right || bottom == top || nearPlane == farPlane)
1430 return;
1431
1432 // Construct the projection.
1433 QMatrix4x4 m(Qt::Uninitialized);
1434 const float width = right - left;
1435 const float invheight = top - bottom;
1436 const float clip = farPlane - nearPlane;
1437 m.m[0][0] = 2.0f * nearPlane / width;
1438 m.m[1][0] = 0.0f;
1439 m.m[2][0] = (left + right) / width;
1440 m.m[3][0] = 0.0f;
1441 m.m[0][1] = 0.0f;
1442 m.m[1][1] = 2.0f * nearPlane / invheight;
1443 m.m[2][1] = (top + bottom) / invheight;
1444 m.m[3][1] = 0.0f;
1445 m.m[0][2] = 0.0f;
1446 m.m[1][2] = 0.0f;
1447 m.m[2][2] = -(nearPlane + farPlane) / clip;
1448 m.m[3][2] = -2.0f * nearPlane * farPlane / clip;
1449 m.m[0][3] = 0.0f;
1450 m.m[1][3] = 0.0f;
1451 m.m[2][3] = -1.0f;
1452 m.m[3][3] = 0.0f;
1453 m.flagBits = General;
1454
1455 // Apply the projection.
1456 *this *= m;
1457}
1458
1459/*!
1460 Multiplies this matrix by another that applies a perspective
1461 projection. The vertical field of view will be \a verticalAngle degrees
1462 within a window with a given \a aspectRatio that determines the horizontal
1463 field of view.
1464 The projection will have the specified \a nearPlane and \a farPlane clipping
1465 planes which are the distances from the viewer to the corresponding planes.
1466
1467 \sa ortho(), frustum()
1468*/
1469void QMatrix4x4::perspective(float verticalAngle, float aspectRatio, float nearPlane, float farPlane)
1470{
1471 // Bail out if the projection volume is zero-sized.
1472 if (nearPlane == farPlane || aspectRatio == 0.0f)
1473 return;
1474
1475 // Construct the projection.
1476 QMatrix4x4 m(Qt::Uninitialized);
1477 const float radians = qDegreesToRadians(degrees: verticalAngle / 2.0f);
1478 const float sine = std::sin(x: radians);
1479 if (sine == 0.0f)
1480 return;
1481 float cotan = std::cos(x: radians) / sine;
1482 float clip = farPlane - nearPlane;
1483 m.m[0][0] = cotan / aspectRatio;
1484 m.m[1][0] = 0.0f;
1485 m.m[2][0] = 0.0f;
1486 m.m[3][0] = 0.0f;
1487 m.m[0][1] = 0.0f;
1488 m.m[1][1] = cotan;
1489 m.m[2][1] = 0.0f;
1490 m.m[3][1] = 0.0f;
1491 m.m[0][2] = 0.0f;
1492 m.m[1][2] = 0.0f;
1493 m.m[2][2] = -(nearPlane + farPlane) / clip;
1494 m.m[3][2] = -(2.0f * nearPlane * farPlane) / clip;
1495 m.m[0][3] = 0.0f;
1496 m.m[1][3] = 0.0f;
1497 m.m[2][3] = -1.0f;
1498 m.m[3][3] = 0.0f;
1499 m.flagBits = General;
1500
1501 // Apply the projection.
1502 *this *= m;
1503}
1504
1505#ifndef QT_NO_VECTOR3D
1506
1507/*!
1508 Multiplies this matrix by a viewing matrix derived from an eye
1509 point. The \a center value indicates the center of the view that
1510 the \a eye is looking at. The \a up value indicates which direction
1511 should be considered up with respect to the \a eye.
1512
1513 \note The \a up vector must not be parallel to the line of sight
1514 from \a eye to \a center.
1515*/
1516void QMatrix4x4::lookAt(const QVector3D& eye, const QVector3D& center, const QVector3D& up)
1517{
1518 QVector3D forward = center - eye;
1519 if (qFuzzyIsNull(f: forward.x()) && qFuzzyIsNull(f: forward.y()) && qFuzzyIsNull(f: forward.z()))
1520 return;
1521
1522 forward.normalize();
1523 QVector3D side = QVector3D::crossProduct(v1: forward, v2: up).normalized();
1524 QVector3D upVector = QVector3D::crossProduct(v1: side, v2: forward);
1525
1526 QMatrix4x4 m(Qt::Uninitialized);
1527 m.m[0][0] = side.x();
1528 m.m[1][0] = side.y();
1529 m.m[2][0] = side.z();
1530 m.m[3][0] = 0.0f;
1531 m.m[0][1] = upVector.x();
1532 m.m[1][1] = upVector.y();
1533 m.m[2][1] = upVector.z();
1534 m.m[3][1] = 0.0f;
1535 m.m[0][2] = -forward.x();
1536 m.m[1][2] = -forward.y();
1537 m.m[2][2] = -forward.z();
1538 m.m[3][2] = 0.0f;
1539 m.m[0][3] = 0.0f;
1540 m.m[1][3] = 0.0f;
1541 m.m[2][3] = 0.0f;
1542 m.m[3][3] = 1.0f;
1543 m.flagBits = Rotation;
1544
1545 *this *= m;
1546 translate(vector: -eye);
1547}
1548
1549#endif
1550
1551/*!
1552 \fn void QMatrix4x4::viewport(const QRectF &rect)
1553 \overload
1554
1555 Sets up viewport transform for viewport bounded by \a rect and with near and far set
1556 to 0 and 1 respectively.
1557*/
1558
1559/*!
1560 Multiplies this matrix by another that performs the scale and bias
1561 transformation used by OpenGL to transform from normalized device
1562 coordinates (NDC) to viewport (window) coordinates. That is it maps
1563 points from the cube ranging over [-1, 1] in each dimension to the
1564 viewport with it's near-lower-left corner at (\a left, \a bottom, \a nearPlane)
1565 and with size (\a width, \a height, \a farPlane - \a nearPlane).
1566
1567 This matches the transform used by the fixed function OpenGL viewport
1568 transform controlled by the functions glViewport() and glDepthRange().
1569 */
1570void QMatrix4x4::viewport(float left, float bottom, float width, float height, float nearPlane, float farPlane)
1571{
1572 const float w2 = width / 2.0f;
1573 const float h2 = height / 2.0f;
1574
1575 QMatrix4x4 m(Qt::Uninitialized);
1576 m.m[0][0] = w2;
1577 m.m[1][0] = 0.0f;
1578 m.m[2][0] = 0.0f;
1579 m.m[3][0] = left + w2;
1580 m.m[0][1] = 0.0f;
1581 m.m[1][1] = h2;
1582 m.m[2][1] = 0.0f;
1583 m.m[3][1] = bottom + h2;
1584 m.m[0][2] = 0.0f;
1585 m.m[1][2] = 0.0f;
1586 m.m[2][2] = (farPlane - nearPlane) / 2.0f;
1587 m.m[3][2] = (nearPlane + farPlane) / 2.0f;
1588 m.m[0][3] = 0.0f;
1589 m.m[1][3] = 0.0f;
1590 m.m[2][3] = 0.0f;
1591 m.m[3][3] = 1.0f;
1592 m.flagBits = General;
1593
1594 *this *= m;
1595}
1596
1597/*!
1598 \deprecated
1599
1600 Flips between right-handed and left-handed coordinate systems
1601 by multiplying the y and z coordinates by -1. This is normally
1602 used to create a left-handed orthographic view without scaling
1603 the viewport as ortho() does.
1604
1605 \sa ortho()
1606*/
1607void QMatrix4x4::flipCoordinates()
1608{
1609 // Multiplying the y and z coordinates with -1 does NOT flip between right-handed and
1610 // left-handed coordinate systems, it just rotates 180 degrees around the x axis, so
1611 // I'm deprecating this function.
1612 if (flagBits < Rotation2D) {
1613 // Translation | Scale
1614 m[1][1] = -m[1][1];
1615 m[2][2] = -m[2][2];
1616 } else {
1617 m[1][0] = -m[1][0];
1618 m[1][1] = -m[1][1];
1619 m[1][2] = -m[1][2];
1620 m[1][3] = -m[1][3];
1621 m[2][0] = -m[2][0];
1622 m[2][1] = -m[2][1];
1623 m[2][2] = -m[2][2];
1624 m[2][3] = -m[2][3];
1625 }
1626 flagBits |= Scale;
1627}
1628
1629/*!
1630 Retrieves the 16 items in this matrix and copies them to \a values
1631 in row-major order.
1632*/
1633void QMatrix4x4::copyDataTo(float *values) const
1634{
1635 for (int row = 0; row < 4; ++row)
1636 for (int col = 0; col < 4; ++col)
1637 values[row * 4 + col] = float(m[col][row]);
1638}
1639
1640/*!
1641 Returns the conventional Qt 2D transformation matrix that
1642 corresponds to this matrix.
1643
1644 The returned QTransform is formed by simply dropping the
1645 third row and third column of the QMatrix4x4. This is suitable
1646 for implementing orthographic projections where the z coordinate
1647 should be dropped rather than projected.
1648*/
1649QTransform QMatrix4x4::toTransform() const
1650{
1651 return QTransform(m[0][0], m[0][1], m[0][3],
1652 m[1][0], m[1][1], m[1][3],
1653 m[3][0], m[3][1], m[3][3]);
1654}
1655
1656/*!
1657 Returns the conventional Qt 2D transformation matrix that
1658 corresponds to this matrix.
1659
1660 If \a distanceToPlane is non-zero, it indicates a projection
1661 factor to use to adjust for the z coordinate. The value of
1662 1024 corresponds to the projection factor used
1663 by QTransform::rotate() for the x and y axes.
1664
1665 If \a distanceToPlane is zero, then the returned QTransform
1666 is formed by simply dropping the third row and third column
1667 of the QMatrix4x4. This is suitable for implementing
1668 orthographic projections where the z coordinate should
1669 be dropped rather than projected.
1670*/
1671QTransform QMatrix4x4::toTransform(float distanceToPlane) const
1672{
1673 if (distanceToPlane == 1024.0f) {
1674 // Optimize the common case with constants.
1675 return QTransform(m[0][0], m[0][1], m[0][3] - m[0][2] * inv_dist_to_plane,
1676 m[1][0], m[1][1], m[1][3] - m[1][2] * inv_dist_to_plane,
1677 m[3][0], m[3][1], m[3][3] - m[3][2] * inv_dist_to_plane);
1678 } else if (distanceToPlane != 0.0f) {
1679 // The following projection matrix is pre-multiplied with "matrix":
1680 // | 1 0 0 0 |
1681 // | 0 1 0 0 |
1682 // | 0 0 1 0 |
1683 // | 0 0 d 1 |
1684 // where d = -1 / distanceToPlane. After projection, row 3 and
1685 // column 3 are dropped to form the final QTransform.
1686 float d = 1.0f / distanceToPlane;
1687 return QTransform(m[0][0], m[0][1], m[0][3] - m[0][2] * d,
1688 m[1][0], m[1][1], m[1][3] - m[1][2] * d,
1689 m[3][0], m[3][1], m[3][3] - m[3][2] * d);
1690 } else {
1691 // Orthographic projection: drop row 3 and column 3.
1692 return QTransform(m[0][0], m[0][1], m[0][3],
1693 m[1][0], m[1][1], m[1][3],
1694 m[3][0], m[3][1], m[3][3]);
1695 }
1696}
1697
1698/*!
1699 \fn QPoint QMatrix4x4::map(const QPoint& point) const
1700
1701 Maps \a point by multiplying this matrix by \a point.
1702 The matrix is applied pre-point.
1703
1704 \sa mapRect()
1705*/
1706
1707/*!
1708 \fn QPointF QMatrix4x4::map(const QPointF& point) const
1709
1710 Maps \a point by post-multiplying this matrix by \a point.
1711 The matrix is applied pre-point.
1712
1713 \sa mapRect()
1714*/
1715
1716#ifndef QT_NO_VECTOR3D
1717
1718/*!
1719 \fn QVector3D QMatrix4x4::map(const QVector3D& point) const
1720
1721 Maps \a point by multiplying this matrix by \a point extended to a 4D
1722 vector by assuming 1.0 for the w coordinate. The matrix is applied
1723 pre-point.
1724
1725 \note This function is not the same as mapVector(). For points, always use
1726 map(). mapVector() is suitable for vectors (directions) only.
1727
1728 \sa mapRect(), mapVector()
1729*/
1730
1731/*!
1732 \fn QVector3D QMatrix4x4::mapVector(const QVector3D& vector) const
1733
1734 Maps \a vector by multiplying the top 3x3 portion of this matrix
1735 by \a vector. The translation and projection components of
1736 this matrix are ignored. The matrix is applied pre-vector.
1737
1738 \sa map()
1739*/
1740
1741#endif
1742
1743#ifndef QT_NO_VECTOR4D
1744
1745/*!
1746 \fn QVector4D QMatrix4x4::map(const QVector4D& point) const;
1747
1748 Maps \a point by multiplying this matrix by \a point.
1749 The matrix is applied pre-point.
1750
1751 \sa mapRect()
1752*/
1753
1754#endif
1755
1756/*!
1757 Maps \a rect by multiplying this matrix by the corners
1758 of \a rect and then forming a new rectangle from the results.
1759 The returned rectangle will be an ordinary 2D rectangle
1760 with sides parallel to the horizontal and vertical axes.
1761
1762 \sa map()
1763*/
1764QRect QMatrix4x4::mapRect(const QRect& rect) const
1765{
1766 if (flagBits < Scale) {
1767 // Translation
1768 return QRect(qRound(f: rect.x() + m[3][0]),
1769 qRound(f: rect.y() + m[3][1]),
1770 rect.width(), rect.height());
1771 } else if (flagBits < Rotation2D) {
1772 // Translation | Scale
1773 float x = rect.x() * m[0][0] + m[3][0];
1774 float y = rect.y() * m[1][1] + m[3][1];
1775 float w = rect.width() * m[0][0];
1776 float h = rect.height() * m[1][1];
1777 if (w < 0) {
1778 w = -w;
1779 x -= w;
1780 }
1781 if (h < 0) {
1782 h = -h;
1783 y -= h;
1784 }
1785 return QRect(qRound(f: x), qRound(f: y), qRound(f: w), qRound(f: h));
1786 }
1787
1788 QPoint tl = map(point: rect.topLeft());
1789 QPoint tr = map(point: QPoint(rect.x() + rect.width(), rect.y()));
1790 QPoint bl = map(point: QPoint(rect.x(), rect.y() + rect.height()));
1791 QPoint br = map(point: QPoint(rect.x() + rect.width(),
1792 rect.y() + rect.height()));
1793
1794 int xmin = qMin(a: qMin(a: tl.x(), b: tr.x()), b: qMin(a: bl.x(), b: br.x()));
1795 int xmax = qMax(a: qMax(a: tl.x(), b: tr.x()), b: qMax(a: bl.x(), b: br.x()));
1796 int ymin = qMin(a: qMin(a: tl.y(), b: tr.y()), b: qMin(a: bl.y(), b: br.y()));
1797 int ymax = qMax(a: qMax(a: tl.y(), b: tr.y()), b: qMax(a: bl.y(), b: br.y()));
1798
1799 return QRect(xmin, ymin, xmax - xmin, ymax - ymin);
1800}
1801
1802/*!
1803 Maps \a rect by multiplying this matrix by the corners
1804 of \a rect and then forming a new rectangle from the results.
1805 The returned rectangle will be an ordinary 2D rectangle
1806 with sides parallel to the horizontal and vertical axes.
1807
1808 \sa map()
1809*/
1810QRectF QMatrix4x4::mapRect(const QRectF& rect) const
1811{
1812 if (flagBits < Scale) {
1813 // Translation
1814 return rect.translated(dx: m[3][0], dy: m[3][1]);
1815 } else if (flagBits < Rotation2D) {
1816 // Translation | Scale
1817 float x = rect.x() * m[0][0] + m[3][0];
1818 float y = rect.y() * m[1][1] + m[3][1];
1819 float w = rect.width() * m[0][0];
1820 float h = rect.height() * m[1][1];
1821 if (w < 0) {
1822 w = -w;
1823 x -= w;
1824 }
1825 if (h < 0) {
1826 h = -h;
1827 y -= h;
1828 }
1829 return QRectF(x, y, w, h);
1830 }
1831
1832 QPointF tl = map(point: rect.topLeft()); QPointF tr = map(point: rect.topRight());
1833 QPointF bl = map(point: rect.bottomLeft()); QPointF br = map(point: rect.bottomRight());
1834
1835 float xmin = qMin(a: qMin(a: tl.x(), b: tr.x()), b: qMin(a: bl.x(), b: br.x()));
1836 float xmax = qMax(a: qMax(a: tl.x(), b: tr.x()), b: qMax(a: bl.x(), b: br.x()));
1837 float ymin = qMin(a: qMin(a: tl.y(), b: tr.y()), b: qMin(a: bl.y(), b: br.y()));
1838 float ymax = qMax(a: qMax(a: tl.y(), b: tr.y()), b: qMax(a: bl.y(), b: br.y()));
1839
1840 return QRectF(QPointF(xmin, ymin), QPointF(xmax, ymax));
1841}
1842
1843/*!
1844 \fn float *QMatrix4x4::data()
1845
1846 Returns a pointer to the raw data of this matrix.
1847
1848 \sa constData(), optimize()
1849*/
1850
1851/*!
1852 \fn const float *QMatrix4x4::data() const
1853
1854 Returns a constant pointer to the raw data of this matrix.
1855 This raw data is stored in column-major format.
1856
1857 \sa constData()
1858*/
1859
1860/*!
1861 \fn const float *QMatrix4x4::constData() const
1862
1863 Returns a constant pointer to the raw data of this matrix.
1864 This raw data is stored in column-major format.
1865
1866 \sa data()
1867*/
1868
1869// Helper routine for inverting orthonormal matrices that consist
1870// of just rotations and translations.
1871QMatrix4x4 QMatrix4x4::orthonormalInverse() const
1872{
1873 QMatrix4x4 result(Qt::Uninitialized);
1874
1875 result.m[0][0] = m[0][0];
1876 result.m[1][0] = m[0][1];
1877 result.m[2][0] = m[0][2];
1878
1879 result.m[0][1] = m[1][0];
1880 result.m[1][1] = m[1][1];
1881 result.m[2][1] = m[1][2];
1882
1883 result.m[0][2] = m[2][0];
1884 result.m[1][2] = m[2][1];
1885 result.m[2][2] = m[2][2];
1886
1887 result.m[0][3] = 0.0f;
1888 result.m[1][3] = 0.0f;
1889 result.m[2][3] = 0.0f;
1890
1891 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]);
1892 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]);
1893 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]);
1894 result.m[3][3] = 1.0f;
1895
1896 result.flagBits = flagBits;
1897
1898 return result;
1899}
1900
1901/*!
1902 Optimize the usage of this matrix from its current elements.
1903
1904 Some operations such as translate(), scale(), and rotate() can be
1905 performed more efficiently if the matrix being modified is already
1906 known to be the identity, a previous translate(), a previous
1907 scale(), etc.
1908
1909 Normally the QMatrix4x4 class keeps track of this special type internally
1910 as operations are performed. However, if the matrix is modified
1911 directly with operator()(int, int) or data(), then QMatrix4x4 will
1912 lose track of the special type and will revert to the safest but least
1913 efficient operations thereafter.
1914
1915 By calling optimize() after directly modifying the matrix,
1916 the programmer can force QMatrix4x4 to recover the special type if
1917 the elements appear to conform to one of the known optimized types.
1918
1919 \sa operator()(int, int), data(), translate()
1920*/
1921void QMatrix4x4::optimize()
1922{
1923 // If the last row is not (0, 0, 0, 1), the matrix is not a special type.
1924 flagBits = General;
1925 if (m[0][3] != 0 || m[1][3] != 0 || m[2][3] != 0 || m[3][3] != 1)
1926 return;
1927
1928 flagBits &= ~Perspective;
1929
1930 // If the last column is (0, 0, 0, 1), then there is no translation.
1931 if (m[3][0] == 0 && m[3][1] == 0 && m[3][2] == 0)
1932 flagBits &= ~Translation;
1933
1934 // If the two first elements of row 3 and column 3 are 0, then any rotation must be about Z.
1935 if (!m[0][2] && !m[1][2] && !m[2][0] && !m[2][1]) {
1936 flagBits &= ~Rotation;
1937 // If the six non-diagonal elements in the top left 3x3 matrix are 0, there is no rotation.
1938 if (!m[0][1] && !m[1][0]) {
1939 flagBits &= ~Rotation2D;
1940 // Check for identity.
1941 if (m[0][0] == 1 && m[1][1] == 1 && m[2][2] == 1)
1942 flagBits &= ~Scale;
1943 } else {
1944 // If the columns are orthonormal and form a right-handed system, then there is no scale.
1945 double mm[4][4];
1946 copyToDoubles(m, mm);
1947 double det = matrixDet2(m: mm, col0: 0, col1: 1, row0: 0, row1: 1);
1948 double lenX = mm[0][0] * mm[0][0] + mm[0][1] * mm[0][1];
1949 double lenY = mm[1][0] * mm[1][0] + mm[1][1] * mm[1][1];
1950 double lenZ = mm[2][2];
1951 if (qFuzzyCompare(p1: det, p2: 1.0) && qFuzzyCompare(p1: lenX, p2: 1.0)
1952 && qFuzzyCompare(p1: lenY, p2: 1.0) && qFuzzyCompare(p1: lenZ, p2: 1.0))
1953 {
1954 flagBits &= ~Scale;
1955 }
1956 }
1957 } else {
1958 // If the columns are orthonormal and form a right-handed system, then there is no scale.
1959 double mm[4][4];
1960 copyToDoubles(m, mm);
1961 double det = matrixDet3(m: mm, col0: 0, col1: 1, col2: 2, row0: 0, row1: 1, row2: 2);
1962 double lenX = mm[0][0] * mm[0][0] + mm[0][1] * mm[0][1] + mm[0][2] * mm[0][2];
1963 double lenY = mm[1][0] * mm[1][0] + mm[1][1] * mm[1][1] + mm[1][2] * mm[1][2];
1964 double lenZ = mm[2][0] * mm[2][0] + mm[2][1] * mm[2][1] + mm[2][2] * mm[2][2];
1965 if (qFuzzyCompare(p1: det, p2: 1.0) && qFuzzyCompare(p1: lenX, p2: 1.0)
1966 && qFuzzyCompare(p1: lenY, p2: 1.0) && qFuzzyCompare(p1: lenZ, p2: 1.0))
1967 {
1968 flagBits &= ~Scale;
1969 }
1970 }
1971}
1972
1973/*!
1974 Returns the matrix as a QVariant.
1975*/
1976QMatrix4x4::operator QVariant() const
1977{
1978 return QVariant::fromValue(value: *this);
1979}
1980
1981#ifndef QT_NO_DEBUG_STREAM
1982
1983QDebug operator<<(QDebug dbg, const QMatrix4x4 &m)
1984{
1985 QDebugStateSaver saver(dbg);
1986 // Create a string that represents the matrix type.
1987 QByteArray bits;
1988 if (m.flagBits == QMatrix4x4::Identity) {
1989 bits = "Identity";
1990 } else if (m.flagBits == QMatrix4x4::General) {
1991 bits = "General";
1992 } else {
1993 if ((m.flagBits & QMatrix4x4::Translation) != 0)
1994 bits += "Translation,";
1995 if ((m.flagBits & QMatrix4x4::Scale) != 0)
1996 bits += "Scale,";
1997 if ((m.flagBits & QMatrix4x4::Rotation2D) != 0)
1998 bits += "Rotation2D,";
1999 if ((m.flagBits & QMatrix4x4::Rotation) != 0)
2000 bits += "Rotation,";
2001 if ((m.flagBits & QMatrix4x4::Perspective) != 0)
2002 bits += "Perspective,";
2003 bits.chop(n: 1);
2004 }
2005
2006 // Output in row-major order because it is more human-readable.
2007 dbg.nospace() << "QMatrix4x4(type:" << bits.constData() << Qt::endl
2008 << qSetFieldWidth(width: 10)
2009 << m(0, 0) << m(0, 1) << m(0, 2) << m(0, 3) << Qt::endl
2010 << m(1, 0) << m(1, 1) << m(1, 2) << m(1, 3) << Qt::endl
2011 << m(2, 0) << m(2, 1) << m(2, 2) << m(2, 3) << Qt::endl
2012 << m(3, 0) << m(3, 1) << m(3, 2) << m(3, 3) << Qt::endl
2013 << qSetFieldWidth(width: 0) << ')';
2014 return dbg;
2015}
2016
2017#endif
2018
2019#ifndef QT_NO_DATASTREAM
2020
2021/*!
2022 \fn QDataStream &operator<<(QDataStream &stream, const QMatrix4x4 &matrix)
2023 \relates QMatrix4x4
2024
2025 Writes the given \a matrix to the given \a stream and returns a
2026 reference to the stream.
2027
2028 \sa {Serializing Qt Data Types}
2029*/
2030
2031QDataStream &operator<<(QDataStream &stream, const QMatrix4x4 &matrix)
2032{
2033 for (int row = 0; row < 4; ++row)
2034 for (int col = 0; col < 4; ++col)
2035 stream << matrix(row, col);
2036 return stream;
2037}
2038
2039/*!
2040 \fn QDataStream &operator>>(QDataStream &stream, QMatrix4x4 &matrix)
2041 \relates QMatrix4x4
2042
2043 Reads a 4x4 matrix from the given \a stream into the given \a matrix
2044 and returns a reference to the stream.
2045
2046 \sa {Serializing Qt Data Types}
2047*/
2048
2049QDataStream &operator>>(QDataStream &stream, QMatrix4x4 &matrix)
2050{
2051 float x;
2052 for (int row = 0; row < 4; ++row) {
2053 for (int col = 0; col < 4; ++col) {
2054 stream >> x;
2055 matrix(row, col) = x;
2056 }
2057 }
2058 matrix.optimize();
2059 return stream;
2060}
2061
2062#endif // QT_NO_DATASTREAM
2063
2064#endif // QT_NO_MATRIX4X4
2065
2066QT_END_NAMESPACE
2067

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