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