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