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