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