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