1 /****************************************************************************
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the QtGui module of the Qt Toolkit.
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 Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
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 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
40 ****************************************************************************/
42 #include "qmatrix4x4.h"
43 #include <QtCore/qmath.h>
44 #include <QtCore/qvariant.h>
45 #include <QtGui/qmatrix.h>
46 #include <QtGui/qtransform.h>
50 #ifndef QT_NO_MATRIX4X4
54 \brief The QMatrix4x4 class represents a 4x4 transformation matrix in 3D space.
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.
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.
66 When using these functions be aware that they return data in \b{column-major}
73 \sa QVector3D, QGenericMatrix
76 static const float inv_dist_to_plane = 1.0f / 1024.0f;
79 \fn QMatrix4x4::QMatrix4x4()
81 Constructs an identity matrix.
85 Constructs a matrix from the given 16 floating-point \a values.
86 The contents of the array \a values is assumed to be in
89 If the matrix has a special type (identity, translate, scale, etc),
90 the programmer should follow this constructor with a call to
91 optimize() if they wish QMatrix4x4 to optimize further
92 calls to translate(), scale(), etc.
94 \sa copyDataTo(), optimize()
96 QMatrix4x4::QMatrix4x4(const float *values)
98 for (int row = 0; row < 4; ++row)
99 for (int col = 0; col < 4; ++col)
100 m[col][row] = values[row * 4 + col];
105 \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)
107 Constructs a matrix from the 16 elements \a m11, \a m12, \a m13, \a m14,
108 \a m21, \a m22, \a m23, \a m24, \a m31, \a m32, \a m33, \a m34,
109 \a m41, \a m42, \a m43, and \a m44. The elements are specified in
112 If the matrix has a special type (identity, translate, scale, etc),
113 the programmer should follow this constructor with a call to
114 optimize() if they wish QMatrix4x4 to optimize further
115 calls to translate(), scale(), etc.
121 \fn QMatrix4x4::QMatrix4x4(const QGenericMatrix<N, M, float>& matrix)
123 Constructs a 4x4 matrix from the left-most 4 columns and top-most
124 4 rows of \a matrix. If \a matrix has less than 4 columns or rows,
125 the remaining elements are filled with elements from the identity
128 \sa toGenericMatrix()
132 \fn QGenericMatrix<N, M, float> QMatrix4x4::toGenericMatrix() const
134 Constructs a NxM generic matrix from the left-most N columns and
135 top-most M rows of this 4x4 matrix. If N or M is greater than 4,
136 then the remaining elements are filled with elements from the
141 \fn QMatrix4x4 qGenericMatrixToMatrix4x4(const QGenericMatrix<N, M, float>& matrix)
145 Returns a 4x4 matrix constructed from the left-most 4 columns and
146 top-most 4 rows of \a matrix. If \a matrix has less than 4 columns
147 or rows, the remaining elements are filled with elements from the
150 \sa QMatrix4x4(const QGenericMatrix &)
154 \fn QGenericMatrix<N, M, float> qGenericMatrixFromMatrix4x4(const QMatrix4x4& matrix)
158 Returns a NxM generic matrix constructed from the left-most N columns
159 and top-most M rows of \a matrix. If N or M is greater than 4,
160 then the remaining elements are filled with elements from the
163 \sa QMatrix4x4::toGenericMatrix()
169 QMatrix4x4::QMatrix4x4(const float *values, int cols, int rows)
171 for (int col = 0; col < 4; ++col) {
172 for (int row = 0; row < 4; ++row) {
173 if (col < cols && row < rows)
174 m[col][row] = values[col * rows + row];
185 Constructs a 4x4 matrix from a conventional Qt 2D affine
186 transformation \a matrix.
188 If \a matrix has a special type (identity, translate, scale, etc),
189 the programmer should follow this constructor with a call to
190 optimize() if they wish QMatrix4x4 to optimize further
191 calls to translate(), scale(), etc.
193 \sa toAffine(), optimize()
195 QMatrix4x4::QMatrix4x4(const QMatrix& matrix)
197 m[0][0] = matrix.m11();
198 m[0][1] = matrix.m12();
201 m[1][0] = matrix.m21();
202 m[1][1] = matrix.m22();
209 m[3][0] = matrix.dx();
210 m[3][1] = matrix.dy();
213 flagBits = Translation | Scale | Rotation2D;
217 Constructs a 4x4 matrix from the conventional Qt 2D
218 transformation matrix \a transform.
220 If \a transform has a special type (identity, translate, scale, etc),
221 the programmer should follow this constructor with a call to
222 optimize() if they wish QMatrix4x4 to optimize further
223 calls to translate(), scale(), etc.
225 \sa toTransform(), optimize()
227 QMatrix4x4::QMatrix4x4(const QTransform& transform)
229 m[0][0] = transform.m11();
230 m[0][1] = transform.m12();
232 m[0][3] = transform.m13();
233 m[1][0] = transform.m21();
234 m[1][1] = transform.m22();
236 m[1][3] = transform.m23();
241 m[3][0] = transform.dx();
242 m[3][1] = transform.dy();
244 m[3][3] = transform.m33();
249 \fn const float& QMatrix4x4::operator()(int row, int column) const
251 Returns a constant reference to the element at position
252 (\a row, \a column) in this matrix.
258 \fn float& QMatrix4x4::operator()(int row, int column)
260 Returns a reference to the element at position (\a row, \a column)
261 in this matrix so that the element can be assigned to.
263 \sa optimize(), setColumn(), setRow()
267 \fn QVector4D QMatrix4x4::column(int index) const
269 Returns the elements of column \a index as a 4D vector.
271 \sa setColumn(), row()
275 \fn void QMatrix4x4::setColumn(int index, const QVector4D& value)
277 Sets the elements of column \a index to the components of \a value.
279 \sa column(), setRow()
283 \fn QVector4D QMatrix4x4::row(int index) const
285 Returns the elements of row \a index as a 4D vector.
287 \sa setRow(), column()
291 \fn void QMatrix4x4::setRow(int index, const QVector4D& value)
293 Sets the elements of row \a index to the components of \a value.
295 \sa row(), setColumn()
299 \fn bool QMatrix4x4::isIdentity() const
301 Returns true if this matrix is the identity; false otherwise.
307 \fn void QMatrix4x4::setToIdentity()
309 Sets this matrix to the identity.
315 \fn void QMatrix4x4::fill(float value)
317 Fills all elements of this matrx with \a value.
320 static inline double matrixDet2(const double m[4][4], int col0, int col1, int row0, int row1)
322 return m[col0][row0] * m[col1][row1] - m[col0][row1] * m[col1][row0];
326 // The 4x4 matrix inverse algorithm is based on that described at:
327 // http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q24
328 // Some optimization has been done to avoid making copies of 3x3
329 // sub-matrices and to unroll the loops.
331 // Calculate the determinant of a 3x3 sub-matrix.
333 // M = | D E F | det(M) = A * (EI - HF) - B * (DI - GF) + C * (DH - GE)
335 static inline double matrixDet3
336 (const double m[4][4], int col0, int col1, int col2,
337 int row0, int row1, int row2)
339 return m[col0][row0] * matrixDet2(m, col1, col2, row1, row2)
340 - m[col1][row0] * matrixDet2(m, col0, col2, row1, row2)
341 + m[col2][row0] * matrixDet2(m, col0, col1, row1, row2);
344 // Calculate the determinant of a 4x4 matrix.
345 static inline double matrixDet4(const double m[4][4])
348 det = m[0][0] * matrixDet3(m, 1, 2, 3, 1, 2, 3);
349 det -= m[1][0] * matrixDet3(m, 0, 2, 3, 1, 2, 3);
350 det += m[2][0] * matrixDet3(m, 0, 1, 3, 1, 2, 3);
351 det -= m[3][0] * matrixDet3(m, 0, 1, 2, 1, 2, 3);
355 static inline void copyToDoubles(const float m[4][4], double mm[4][4])
357 for (int i = 0; i < 4; ++i)
358 for (int j = 0; j < 4; ++j)
359 mm[i][j] = double(m[i][j]);
363 Returns the determinant of this matrix.
365 double QMatrix4x4::determinant() const
367 if ((flagBits & ~(Translation | Rotation2D | Rotation)) == Identity)
371 copyToDoubles(m, mm);
372 if (flagBits < Rotation2D)
373 return mm[0][0] * mm[1][1] * mm[2][2]; // Translation | Scale
374 if (flagBits < Perspective)
375 return matrixDet3(mm, 0, 1, 2, 0, 1, 2);
376 return matrixDet4(mm);
380 Returns the inverse of this matrix. Returns the identity if
381 this matrix cannot be inverted; i.e. determinant() is zero.
382 If \a invertible is not null, then true will be written to
383 that location if the matrix can be inverted; false otherwise.
385 If the matrix is recognized as the identity or an orthonormal
386 matrix, then this function will quickly invert the matrix
387 using optimized routines.
389 \sa determinant(), normalMatrix()
391 QMatrix4x4 QMatrix4x4::inverted(bool *invertible) const
393 // Handle some of the easy cases first.
394 if (flagBits == Identity) {
398 } else if (flagBits == Translation) {
400 inv.m[3][0] = -m[3][0];
401 inv.m[3][1] = -m[3][1];
402 inv.m[3][2] = -m[3][2];
403 inv.flagBits = Translation;
407 } else if (flagBits < Rotation2D) {
408 // Translation | Scale
409 if (m[0][0] == 0 || m[1][1] == 0 || m[2][2] == 0) {
415 inv.m[0][0] = 1.0f / m[0][0];
416 inv.m[1][1] = 1.0f / m[1][1];
417 inv.m[2][2] = 1.0f / m[2][2];
418 inv.m[3][0] = -m[3][0] * inv.m[0][0];
419 inv.m[3][1] = -m[3][1] * inv.m[1][1];
420 inv.m[3][2] = -m[3][2] * inv.m[2][2];
421 inv.flagBits = flagBits;
426 } else if ((flagBits & ~(Translation | Rotation2D | Rotation)) == Identity) {
429 return orthonormalInverse();
430 } else if (flagBits < Perspective) {
431 QMatrix4x4 inv(1); // The "1" says to not load the identity.
434 copyToDoubles(m, mm);
436 double det = matrixDet3(mm, 0, 1, 2, 0, 1, 2);
444 inv.m[0][0] = matrixDet2(mm, 1, 2, 1, 2) * det;
445 inv.m[0][1] = -matrixDet2(mm, 0, 2, 1, 2) * det;
446 inv.m[0][2] = matrixDet2(mm, 0, 1, 1, 2) * det;
448 inv.m[1][0] = -matrixDet2(mm, 1, 2, 0, 2) * det;
449 inv.m[1][1] = matrixDet2(mm, 0, 2, 0, 2) * det;
450 inv.m[1][2] = -matrixDet2(mm, 0, 1, 0, 2) * det;
452 inv.m[2][0] = matrixDet2(mm, 1, 2, 0, 1) * det;
453 inv.m[2][1] = -matrixDet2(mm, 0, 2, 0, 1) * det;
454 inv.m[2][2] = matrixDet2(mm, 0, 1, 0, 1) * det;
456 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];
457 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];
458 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];
460 inv.flagBits = flagBits;
467 QMatrix4x4 inv(1); // The "1" says to not load the identity.
470 copyToDoubles(m, mm);
472 double det = matrixDet4(mm);
480 inv.m[0][0] = matrixDet3(mm, 1, 2, 3, 1, 2, 3) * det;
481 inv.m[0][1] = -matrixDet3(mm, 0, 2, 3, 1, 2, 3) * det;
482 inv.m[0][2] = matrixDet3(mm, 0, 1, 3, 1, 2, 3) * det;
483 inv.m[0][3] = -matrixDet3(mm, 0, 1, 2, 1, 2, 3) * det;
484 inv.m[1][0] = -matrixDet3(mm, 1, 2, 3, 0, 2, 3) * det;
485 inv.m[1][1] = matrixDet3(mm, 0, 2, 3, 0, 2, 3) * det;
486 inv.m[1][2] = -matrixDet3(mm, 0, 1, 3, 0, 2, 3) * det;
487 inv.m[1][3] = matrixDet3(mm, 0, 1, 2, 0, 2, 3) * det;
488 inv.m[2][0] = matrixDet3(mm, 1, 2, 3, 0, 1, 3) * det;
489 inv.m[2][1] = -matrixDet3(mm, 0, 2, 3, 0, 1, 3) * det;
490 inv.m[2][2] = matrixDet3(mm, 0, 1, 3, 0, 1, 3) * det;
491 inv.m[2][3] = -matrixDet3(mm, 0, 1, 2, 0, 1, 3) * det;
492 inv.m[3][0] = -matrixDet3(mm, 1, 2, 3, 0, 1, 2) * det;
493 inv.m[3][1] = matrixDet3(mm, 0, 2, 3, 0, 1, 2) * det;
494 inv.m[3][2] = -matrixDet3(mm, 0, 1, 3, 0, 1, 2) * det;
495 inv.m[3][3] = matrixDet3(mm, 0, 1, 2, 0, 1, 2) * det;
496 inv.flagBits = flagBits;
504 Returns the normal matrix corresponding to this 4x4 transformation.
505 The normal matrix is the transpose of the inverse of the top-left
506 3x3 part of this 4x4 matrix. If the 3x3 sub-matrix is not invertible,
507 this function returns the identity.
511 QMatrix3x3 QMatrix4x4::normalMatrix() const
515 // Handle the simple cases first.
516 if (flagBits < Scale) {
519 } else if (flagBits < Rotation2D) {
520 // Translation | Scale
521 if (m[0][0] == 0.0f || m[1][1] == 0.0f || m[2][2] == 0.0f)
523 inv.data()[0] = 1.0f / m[0][0];
524 inv.data()[4] = 1.0f / m[1][1];
525 inv.data()[8] = 1.0f / m[2][2];
527 } else if ((flagBits & ~(Translation | Rotation2D | Rotation)) == Identity) {
528 float *invm = inv.data();
529 invm[0 + 0 * 3] = m[0][0];
530 invm[1 + 0 * 3] = m[0][1];
531 invm[2 + 0 * 3] = m[0][2];
532 invm[0 + 1 * 3] = m[1][0];
533 invm[1 + 1 * 3] = m[1][1];
534 invm[2 + 1 * 3] = m[1][2];
535 invm[0 + 2 * 3] = m[2][0];
536 invm[1 + 2 * 3] = m[2][1];
537 invm[2 + 2 * 3] = m[2][2];
542 copyToDoubles(m, mm);
543 double det = matrixDet3(mm, 0, 1, 2, 0, 1, 2);
548 float *invm = inv.data();
550 // Invert and transpose in a single step.
551 invm[0 + 0 * 3] = (mm[1][1] * mm[2][2] - mm[2][1] * mm[1][2]) * det;
552 invm[1 + 0 * 3] = -(mm[1][0] * mm[2][2] - mm[1][2] * mm[2][0]) * det;
553 invm[2 + 0 * 3] = (mm[1][0] * mm[2][1] - mm[1][1] * mm[2][0]) * det;
554 invm[0 + 1 * 3] = -(mm[0][1] * mm[2][2] - mm[2][1] * mm[0][2]) * det;
555 invm[1 + 1 * 3] = (mm[0][0] * mm[2][2] - mm[0][2] * mm[2][0]) * det;
556 invm[2 + 1 * 3] = -(mm[0][0] * mm[2][1] - mm[0][1] * mm[2][0]) * det;
557 invm[0 + 2 * 3] = (mm[0][1] * mm[1][2] - mm[0][2] * mm[1][1]) * det;
558 invm[1 + 2 * 3] = -(mm[0][0] * mm[1][2] - mm[0][2] * mm[1][0]) * det;
559 invm[2 + 2 * 3] = (mm[0][0] * mm[1][1] - mm[1][0] * mm[0][1]) * det;
565 Returns this matrix, transposed about its diagonal.
567 QMatrix4x4 QMatrix4x4::transposed() const
569 QMatrix4x4 result(1); // The "1" says to not load the identity.
570 for (int row = 0; row < 4; ++row) {
571 for (int col = 0; col < 4; ++col) {
572 result.m[col][row] = m[row][col];
575 // When a translation is transposed, it becomes a perspective transformation.
576 result.flagBits = (flagBits & Translation ? General : flagBits);
581 \fn QMatrix4x4& QMatrix4x4::operator+=(const QMatrix4x4& other)
583 Adds the contents of \a other to this matrix.
587 \fn QMatrix4x4& QMatrix4x4::operator-=(const QMatrix4x4& other)
589 Subtracts the contents of \a other from this matrix.
593 \fn QMatrix4x4& QMatrix4x4::operator*=(const QMatrix4x4& other)
595 Multiplies the contents of \a other by this matrix.
599 \fn QMatrix4x4& QMatrix4x4::operator*=(float factor)
602 Multiplies all elements of this matrix by \a factor.
608 Divides all elements of this matrix by \a divisor.
610 QMatrix4x4& QMatrix4x4::operator/=(float divisor)
633 \fn bool QMatrix4x4::operator==(const QMatrix4x4& other) const
635 Returns true if this matrix is identical to \a other; false otherwise.
636 This operator uses an exact floating-point comparison.
640 \fn bool QMatrix4x4::operator!=(const QMatrix4x4& other) const
642 Returns true if this matrix is not identical to \a other; false otherwise.
643 This operator uses an exact floating-point comparison.
647 \fn QMatrix4x4 operator+(const QMatrix4x4& m1, const QMatrix4x4& m2)
650 Returns the sum of \a m1 and \a m2.
654 \fn QMatrix4x4 operator-(const QMatrix4x4& m1, const QMatrix4x4& m2)
657 Returns the difference of \a m1 and \a m2.
661 \fn QMatrix4x4 operator*(const QMatrix4x4& m1, const QMatrix4x4& m2)
664 Returns the product of \a m1 and \a m2.
667 #ifndef QT_NO_VECTOR3D
670 \fn QVector3D operator*(const QVector3D& vector, const QMatrix4x4& matrix)
673 Returns the result of transforming \a vector according to \a matrix,
674 with the matrix applied post-vector.
678 \fn QVector3D operator*(const QMatrix4x4& matrix, const QVector3D& vector)
681 Returns the result of transforming \a vector according to \a matrix,
682 with the matrix applied pre-vector.
687 #ifndef QT_NO_VECTOR4D
690 \fn QVector4D operator*(const QVector4D& vector, const QMatrix4x4& matrix)
693 Returns the result of transforming \a vector according to \a matrix,
694 with the matrix applied post-vector.
698 \fn QVector4D operator*(const QMatrix4x4& matrix, const QVector4D& vector)
701 Returns the result of transforming \a vector according to \a matrix,
702 with the matrix applied pre-vector.
708 \fn QPoint operator*(const QPoint& point, const QMatrix4x4& matrix)
711 Returns the result of transforming \a point according to \a matrix,
712 with the matrix applied post-point.
716 \fn QPointF operator*(const QPointF& point, const QMatrix4x4& matrix)
719 Returns the result of transforming \a point according to \a matrix,
720 with the matrix applied post-point.
724 \fn QPoint operator*(const QMatrix4x4& matrix, const QPoint& point)
727 Returns the result of transforming \a point according to \a matrix,
728 with the matrix applied pre-point.
732 \fn QPointF operator*(const QMatrix4x4& matrix, const QPointF& point)
735 Returns the result of transforming \a point according to \a matrix,
736 with the matrix applied pre-point.
740 \fn QMatrix4x4 operator-(const QMatrix4x4& matrix)
744 Returns the negation of \a matrix.
748 \fn QMatrix4x4 operator*(float factor, const QMatrix4x4& matrix)
751 Returns the result of multiplying all elements of \a matrix by \a factor.
755 \fn QMatrix4x4 operator*(const QMatrix4x4& matrix, float factor)
758 Returns the result of multiplying all elements of \a matrix by \a factor.
764 Returns the result of dividing all elements of \a matrix by \a divisor.
766 QMatrix4x4 operator/(const QMatrix4x4& matrix, float divisor)
768 QMatrix4x4 m(1); // The "1" says to not load the identity.
769 m.m[0][0] = matrix.m[0][0] / divisor;
770 m.m[0][1] = matrix.m[0][1] / divisor;
771 m.m[0][2] = matrix.m[0][2] / divisor;
772 m.m[0][3] = matrix.m[0][3] / divisor;
773 m.m[1][0] = matrix.m[1][0] / divisor;
774 m.m[1][1] = matrix.m[1][1] / divisor;
775 m.m[1][2] = matrix.m[1][2] / divisor;
776 m.m[1][3] = matrix.m[1][3] / divisor;
777 m.m[2][0] = matrix.m[2][0] / divisor;
778 m.m[2][1] = matrix.m[2][1] / divisor;
779 m.m[2][2] = matrix.m[2][2] / divisor;
780 m.m[2][3] = matrix.m[2][3] / divisor;
781 m.m[3][0] = matrix.m[3][0] / divisor;
782 m.m[3][1] = matrix.m[3][1] / divisor;
783 m.m[3][2] = matrix.m[3][2] / divisor;
784 m.m[3][3] = matrix.m[3][3] / divisor;
785 m.flagBits = QMatrix4x4::General;
790 \fn bool qFuzzyCompare(const QMatrix4x4& m1, const QMatrix4x4& m2)
793 Returns true if \a m1 and \a m2 are equal, allowing for a small
794 fuzziness factor for floating-point comparisons; false otherwise.
797 #ifndef QT_NO_VECTOR3D
800 Multiplies this matrix by another that scales coordinates by
801 the components of \a vector.
803 \sa translate(), rotate()
805 void QMatrix4x4::scale(const QVector3D& vector)
807 float vx = vector.x();
808 float vy = vector.y();
809 float vz = vector.z();
810 if (flagBits < Scale) {
814 } else if (flagBits < Rotation2D) {
818 } else if (flagBits < Rotation) {
846 Multiplies this matrix by another that scales coordinates by the
847 components \a x, and \a y.
849 \sa translate(), rotate()
851 void QMatrix4x4::scale(float x, float y)
853 if (flagBits < Scale) {
856 } else if (flagBits < Rotation2D) {
859 } else if (flagBits < Rotation) {
880 Multiplies this matrix by another that scales coordinates by the
881 components \a x, \a y, and \a z.
883 \sa translate(), rotate()
885 void QMatrix4x4::scale(float x, float y, float z)
887 if (flagBits < Scale) {
891 } else if (flagBits < Rotation2D) {
895 } else if (flagBits < Rotation) {
921 Multiplies this matrix by another that scales coordinates by the
924 \sa translate(), rotate()
926 void QMatrix4x4::scale(float factor)
928 if (flagBits < Scale) {
932 } else if (flagBits < Rotation2D) {
936 } else if (flagBits < Rotation) {
959 #ifndef QT_NO_VECTOR3D
961 Multiplies this matrix by another that translates coordinates by
962 the components of \a vector.
964 \sa scale(), rotate()
967 void QMatrix4x4::translate(const QVector3D& vector)
969 float vx = vector.x();
970 float vy = vector.y();
971 float vz = vector.z();
972 if (flagBits == Identity) {
976 } else if (flagBits == Translation) {
980 } else if (flagBits == Scale) {
981 m[3][0] = m[0][0] * vx;
982 m[3][1] = m[1][1] * vy;
983 m[3][2] = m[2][2] * vz;
984 } else if (flagBits == (Translation | Scale)) {
985 m[3][0] += m[0][0] * vx;
986 m[3][1] += m[1][1] * vy;
987 m[3][2] += m[2][2] * vz;
988 } else if (flagBits < Rotation) {
989 m[3][0] += m[0][0] * vx + m[1][0] * vy;
990 m[3][1] += m[0][1] * vx + m[1][1] * vy;
991 m[3][2] += m[2][2] * vz;
993 m[3][0] += m[0][0] * vx + m[1][0] * vy + m[2][0] * vz;
994 m[3][1] += m[0][1] * vx + m[1][1] * vy + m[2][1] * vz;
995 m[3][2] += m[0][2] * vx + m[1][2] * vy + m[2][2] * vz;
996 m[3][3] += m[0][3] * vx + m[1][3] * vy + m[2][3] * vz;
998 flagBits |= Translation;
1005 Multiplies this matrix by another that translates coordinates
1006 by the components \a x, and \a y.
1008 \sa scale(), rotate()
1010 void QMatrix4x4::translate(float x, float y)
1012 if (flagBits == Identity) {
1015 } else if (flagBits == Translation) {
1018 } else if (flagBits == Scale) {
1019 m[3][0] = m[0][0] * x;
1020 m[3][1] = m[1][1] * y;
1021 } else if (flagBits == (Translation | Scale)) {
1022 m[3][0] += m[0][0] * x;
1023 m[3][1] += m[1][1] * y;
1024 } else if (flagBits < Rotation) {
1025 m[3][0] += m[0][0] * x + m[1][0] * y;
1026 m[3][1] += m[0][1] * x + m[1][1] * y;
1028 m[3][0] += m[0][0] * x + m[1][0] * y;
1029 m[3][1] += m[0][1] * x + m[1][1] * y;
1030 m[3][2] += m[0][2] * x + m[1][2] * y;
1031 m[3][3] += m[0][3] * x + m[1][3] * y;
1033 flagBits |= Translation;
1039 Multiplies this matrix by another that translates coordinates
1040 by the components \a x, \a y, and \a z.
1042 \sa scale(), rotate()
1044 void QMatrix4x4::translate(float x, float y, float z)
1046 if (flagBits == Identity) {
1050 } else if (flagBits == Translation) {
1054 } else if (flagBits == Scale) {
1055 m[3][0] = m[0][0] * x;
1056 m[3][1] = m[1][1] * y;
1057 m[3][2] = m[2][2] * z;
1058 } else if (flagBits == (Translation | Scale)) {
1059 m[3][0] += m[0][0] * x;
1060 m[3][1] += m[1][1] * y;
1061 m[3][2] += m[2][2] * z;
1062 } else if (flagBits < Rotation) {
1063 m[3][0] += m[0][0] * x + m[1][0] * y;
1064 m[3][1] += m[0][1] * x + m[1][1] * y;
1065 m[3][2] += m[2][2] * z;
1067 m[3][0] += m[0][0] * x + m[1][0] * y + m[2][0] * z;
1068 m[3][1] += m[0][1] * x + m[1][1] * y + m[2][1] * z;
1069 m[3][2] += m[0][2] * x + m[1][2] * y + m[2][2] * z;
1070 m[3][3] += m[0][3] * x + m[1][3] * y + m[2][3] * z;
1072 flagBits |= Translation;
1075 #ifndef QT_NO_VECTOR3D
1077 Multiples this matrix by another that rotates coordinates through
1078 \a angle degrees about \a vector.
1080 \sa scale(), translate()
1083 void QMatrix4x4::rotate(float angle, const QVector3D& vector)
1085 rotate(angle, vector.x(), vector.y(), vector.z());
1093 Multiplies this matrix by another that rotates coordinates through
1094 \a angle degrees about the vector (\a x, \a y, \a z).
1096 \sa scale(), translate()
1098 void QMatrix4x4::rotate(float angle, float x, float y, float z)
1103 if (angle == 90.0f || angle == -270.0f) {
1106 } else if (angle == -90.0f || angle == 270.0f) {
1109 } else if (angle == 180.0f || angle == -180.0f) {
1113 float a = angle * M_PI / 180.0f;
1120 // Rotate around the Z axis.
1124 m[0][0] = (tmp = m[0][0]) * c + m[1][0] * s;
1125 m[1][0] = m[1][0] * c - tmp * s;
1126 m[0][1] = (tmp = m[0][1]) * c + m[1][1] * s;
1127 m[1][1] = m[1][1] * c - tmp * s;
1128 m[0][2] = (tmp = m[0][2]) * c + m[1][2] * s;
1129 m[1][2] = m[1][2] * c - tmp * s;
1130 m[0][3] = (tmp = m[0][3]) * c + m[1][3] * s;
1131 m[1][3] = m[1][3] * c - tmp * s;
1133 flagBits |= Rotation2D;
1136 } else if (z == 0.0f) {
1137 // Rotate around the Y axis.
1141 m[2][0] = (tmp = m[2][0]) * c + m[0][0] * s;
1142 m[0][0] = m[0][0] * c - tmp * s;
1143 m[2][1] = (tmp = m[2][1]) * c + m[0][1] * s;
1144 m[0][1] = m[0][1] * c - tmp * s;
1145 m[2][2] = (tmp = m[2][2]) * c + m[0][2] * s;
1146 m[0][2] = m[0][2] * c - tmp * s;
1147 m[2][3] = (tmp = m[2][3]) * c + m[0][3] * s;
1148 m[0][3] = m[0][3] * c - tmp * s;
1150 flagBits |= Rotation;
1153 } else if (y == 0.0f && z == 0.0f) {
1154 // Rotate around the X axis.
1158 m[1][0] = (tmp = m[1][0]) * c + m[2][0] * s;
1159 m[2][0] = m[2][0] * c - tmp * s;
1160 m[1][1] = (tmp = m[1][1]) * c + m[2][1] * s;
1161 m[2][1] = m[2][1] * c - tmp * s;
1162 m[1][2] = (tmp = m[1][2]) * c + m[2][2] * s;
1163 m[2][2] = m[2][2] * c - tmp * s;
1164 m[1][3] = (tmp = m[1][3]) * c + m[2][3] * s;
1165 m[2][3] = m[2][3] * c - tmp * s;
1167 flagBits |= Rotation;
1171 double len = double(x) * double(x) +
1172 double(y) * double(y) +
1173 double(z) * double(z);
1174 if (!qFuzzyCompare(len, 1.0) && !qFuzzyIsNull(len)) {
1176 x = float(double(x) / len);
1177 y = float(double(y) / len);
1178 z = float(double(z) / len);
1180 float ic = 1.0f - c;
1181 QMatrix4x4 rot(1); // The "1" says to not load the identity.
1182 rot.m[0][0] = x * x * ic + c;
1183 rot.m[1][0] = x * y * ic - z * s;
1184 rot.m[2][0] = x * z * ic + y * s;
1186 rot.m[0][1] = y * x * ic + z * s;
1187 rot.m[1][1] = y * y * ic + c;
1188 rot.m[2][1] = y * z * ic - x * s;
1190 rot.m[0][2] = x * z * ic - y * s;
1191 rot.m[1][2] = y * z * ic + x * s;
1192 rot.m[2][2] = z * z * ic + c;
1198 rot.flagBits = Rotation;
1205 void QMatrix4x4::projectedRotate(float angle, float x, float y, float z)
1207 // Used by QGraphicsRotation::applyTo() to perform a rotation
1208 // and projection back to 2D in a single step.
1212 if (angle == 90.0f || angle == -270.0f) {
1215 } else if (angle == -90.0f || angle == 270.0f) {
1218 } else if (angle == 180.0f || angle == -180.0f) {
1222 float a = angle * M_PI / 180.0f;
1229 // Rotate around the Z axis.
1233 m[0][0] = (tmp = m[0][0]) * c + m[1][0] * s;
1234 m[1][0] = m[1][0] * c - tmp * s;
1235 m[0][1] = (tmp = m[0][1]) * c + m[1][1] * s;
1236 m[1][1] = m[1][1] * c - tmp * s;
1237 m[0][2] = (tmp = m[0][2]) * c + m[1][2] * s;
1238 m[1][2] = m[1][2] * c - tmp * s;
1239 m[0][3] = (tmp = m[0][3]) * c + m[1][3] * s;
1240 m[1][3] = m[1][3] * c - tmp * s;
1242 flagBits |= Rotation2D;
1245 } else if (z == 0.0f) {
1246 // Rotate around the Y axis.
1249 m[0][0] = m[0][0] * c + m[3][0] * s * inv_dist_to_plane;
1250 m[0][1] = m[0][1] * c + m[3][1] * s * inv_dist_to_plane;
1251 m[0][2] = m[0][2] * c + m[3][2] * s * inv_dist_to_plane;
1252 m[0][3] = m[0][3] * c + m[3][3] * s * inv_dist_to_plane;
1256 } else if (y == 0.0f && z == 0.0f) {
1257 // Rotate around the X axis.
1260 m[1][0] = m[1][0] * c - m[3][0] * s * inv_dist_to_plane;
1261 m[1][1] = m[1][1] * c - m[3][1] * s * inv_dist_to_plane;
1262 m[1][2] = m[1][2] * c - m[3][2] * s * inv_dist_to_plane;
1263 m[1][3] = m[1][3] * c - m[3][3] * s * inv_dist_to_plane;
1267 double len = double(x) * double(x) +
1268 double(y) * double(y) +
1269 double(z) * double(z);
1270 if (!qFuzzyCompare(len, 1.0) && !qFuzzyIsNull(len)) {
1272 x = float(double(x) / len);
1273 y = float(double(y) / len);
1274 z = float(double(z) / len);
1276 float ic = 1.0f - c;
1277 QMatrix4x4 rot(1); // The "1" says to not load the identity.
1278 rot.m[0][0] = x * x * ic + c;
1279 rot.m[1][0] = x * y * ic - z * s;
1282 rot.m[0][1] = y * x * ic + z * s;
1283 rot.m[1][1] = y * y * ic + c;
1290 rot.m[0][3] = (x * z * ic - y * s) * -inv_dist_to_plane;
1291 rot.m[1][3] = (y * z * ic + x * s) * -inv_dist_to_plane;
1294 rot.flagBits = General;
1298 #ifndef QT_NO_QUATERNION
1301 Multiples this matrix by another that rotates coordinates according
1302 to a specified \a quaternion. The \a quaternion is assumed to have
1305 \sa scale(), translate(), QQuaternion
1307 void QMatrix4x4::rotate(const QQuaternion& quaternion)
1310 // http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q54
1312 float xx = quaternion.x() * quaternion.x();
1313 float xy = quaternion.x() * quaternion.y();
1314 float xz = quaternion.x() * quaternion.z();
1315 float xw = quaternion.x() * quaternion.scalar();
1316 float yy = quaternion.y() * quaternion.y();
1317 float yz = quaternion.y() * quaternion.z();
1318 float yw = quaternion.y() * quaternion.scalar();
1319 float zz = quaternion.z() * quaternion.z();
1320 float zw = quaternion.z() * quaternion.scalar();
1321 m.m[0][0] = 1.0f - 2 * (yy + zz);
1322 m.m[1][0] = 2 * (xy - zw);
1323 m.m[2][0] = 2 * (xz + yw);
1325 m.m[0][1] = 2 * (xy + zw);
1326 m.m[1][1] = 1.0f - 2 * (xx + zz);
1327 m.m[2][1] = 2 * (yz - xw);
1329 m.m[0][2] = 2 * (xz - yw);
1330 m.m[1][2] = 2 * (yz + xw);
1331 m.m[2][2] = 1.0f - 2 * (xx + yy);
1337 m.flagBits = Rotation;
1346 Multiplies this matrix by another that applies an orthographic
1347 projection for a window with boundaries specified by \a rect.
1348 The near and far clipping planes will be -1 and 1 respectively.
1350 \sa frustum(), perspective()
1352 void QMatrix4x4::ortho(const QRect& rect)
1354 // Note: rect.right() and rect.bottom() subtract 1 in QRect,
1355 // which gives the location of a pixel within the rectangle,
1356 // instead of the extent of the rectangle. We want the extent.
1357 // QRectF expresses the extent properly.
1358 ortho(rect.x(), rect.x() + rect.width(), rect.y() + rect.height(), rect.y(), -1.0f, 1.0f);
1364 Multiplies this matrix by another that applies an orthographic
1365 projection for a window with boundaries specified by \a rect.
1366 The near and far clipping planes will be -1 and 1 respectively.
1368 \sa frustum(), perspective()
1370 void QMatrix4x4::ortho(const QRectF& rect)
1372 ortho(rect.left(), rect.right(), rect.bottom(), rect.top(), -1.0f, 1.0f);
1376 Multiplies this matrix by another that applies an orthographic
1377 projection for a window with lower-left corner (\a left, \a bottom),
1378 upper-right corner (\a right, \a top), and the specified \a nearPlane
1379 and \a farPlane clipping planes.
1381 \sa frustum(), perspective()
1383 void QMatrix4x4::ortho(float left, float right, float bottom, float top, float nearPlane, float farPlane)
1385 // Bail out if the projection volume is zero-sized.
1386 if (left == right || bottom == top || nearPlane == farPlane)
1389 // Construct the projection.
1390 float width = right - left;
1391 float invheight = top - bottom;
1392 float clip = farPlane - nearPlane;
1394 m.m[0][0] = 2.0f / width;
1397 m.m[3][0] = -(left + right) / width;
1399 m.m[1][1] = 2.0f / invheight;
1401 m.m[3][1] = -(top + bottom) / invheight;
1404 m.m[2][2] = -2.0f / clip;
1405 m.m[3][2] = -(nearPlane + farPlane) / clip;
1410 m.flagBits = Translation | Scale;
1412 // Apply the projection.
1417 Multiplies this matrix by another that applies a perspective
1418 frustum projection for a window with lower-left corner (\a left, \a bottom),
1419 upper-right corner (\a right, \a top), and the specified \a nearPlane
1420 and \a farPlane clipping planes.
1422 \sa ortho(), perspective()
1424 void QMatrix4x4::frustum(float left, float right, float bottom, float top, float nearPlane, float farPlane)
1426 // Bail out if the projection volume is zero-sized.
1427 if (left == right || bottom == top || nearPlane == farPlane)
1430 // Construct the projection.
1432 float width = right - left;
1433 float invheight = top - bottom;
1434 float clip = farPlane - nearPlane;
1435 m.m[0][0] = 2.0f * nearPlane / width;
1437 m.m[2][0] = (left + right) / width;
1440 m.m[1][1] = 2.0f * nearPlane / invheight;
1441 m.m[2][1] = (top + bottom) / invheight;
1445 m.m[2][2] = -(nearPlane + farPlane) / clip;
1446 m.m[3][2] = -2.0f * nearPlane * farPlane / clip;
1451 m.flagBits = General;
1453 // Apply the projection.
1458 Multiplies this matrix by another that applies a perspective
1459 projection. The field of view will be \a angle degrees within
1460 a window with a given \a aspect ratio. The projection will
1461 have the specified \a nearPlane and \a farPlane clipping planes.
1463 \sa ortho(), frustum()
1465 void QMatrix4x4::perspective(float angle, float aspect, float nearPlane, float farPlane)
1467 // Bail out if the projection volume is zero-sized.
1468 if (nearPlane == farPlane || aspect == 0.0f)
1471 // Construct the projection.
1473 float radians = (angle / 2.0f) * M_PI / 180.0f;
1474 float sine = sinf(radians);
1477 float cotan = cosf(radians) / sine;
1478 float clip = farPlane - nearPlane;
1479 m.m[0][0] = cotan / aspect;
1489 m.m[2][2] = -(nearPlane + farPlane) / clip;
1490 m.m[3][2] = -(2.0f * nearPlane * farPlane) / clip;
1495 m.flagBits = General;
1497 // Apply the projection.
1501 #ifndef QT_NO_VECTOR3D
1504 Multiplies this matrix by another that applies an \a eye position
1505 transformation. The \a center value indicates the center of the
1506 view that the \a eye is looking at. The \a up value indicates
1507 which direction should be considered up with respect to the \a eye.
1509 void QMatrix4x4::lookAt(const QVector3D& eye, const QVector3D& center, const QVector3D& up)
1511 QVector3D forward = (center - eye).normalized();
1512 QVector3D side = QVector3D::crossProduct(forward, up).normalized();
1513 QVector3D upVector = QVector3D::crossProduct(side, forward);
1516 m.m[0][0] = side.x();
1517 m.m[1][0] = side.y();
1518 m.m[2][0] = side.z();
1520 m.m[0][1] = upVector.x();
1521 m.m[1][1] = upVector.y();
1522 m.m[2][1] = upVector.z();
1524 m.m[0][2] = -forward.x();
1525 m.m[1][2] = -forward.y();
1526 m.m[2][2] = -forward.z();
1532 m.flagBits = Rotation;
1543 Flips between right-handed and left-handed coordinate systems
1544 by multiplying the y and z co-ordinates by -1. This is normally
1545 used to create a left-handed orthographic view without scaling
1546 the viewport as ortho() does.
1550 void QMatrix4x4::flipCoordinates()
1552 // Multiplying the y and z coordinates with -1 does NOT flip between right-handed and
1553 // left-handed coordinate systems, it just rotates 180 degrees around the x axis, so
1554 // I'm deprecating this function.
1555 if (flagBits < Rotation2D) {
1556 // Translation | Scale
1573 Retrieves the 16 items in this matrix and copies them to \a values
1576 void QMatrix4x4::copyDataTo(float *values) const
1578 for (int row = 0; row < 4; ++row)
1579 for (int col = 0; col < 4; ++col)
1580 values[row * 4 + col] = float(m[col][row]);
1584 Returns the conventional Qt 2D affine transformation matrix that
1585 corresponds to this matrix. It is assumed that this matrix
1586 only contains 2D affine transformation elements.
1590 QMatrix QMatrix4x4::toAffine() const
1592 return QMatrix(m[0][0], m[0][1],
1598 Returns the conventional Qt 2D transformation matrix that
1599 corresponds to this matrix.
1601 The returned QTransform is formed by simply dropping the
1602 third row and third column of the QMatrix4x4. This is suitable
1603 for implementing orthographic projections where the z co-ordinate
1604 should be dropped rather than projected.
1608 QTransform QMatrix4x4::toTransform() const
1610 return QTransform(m[0][0], m[0][1], m[0][3],
1611 m[1][0], m[1][1], m[1][3],
1612 m[3][0], m[3][1], m[3][3]);
1616 Returns the conventional Qt 2D transformation matrix that
1617 corresponds to this matrix.
1619 If \a distanceToPlane is non-zero, it indicates a projection
1620 factor to use to adjust for the z co-ordinate. The value of
1621 1024 corresponds to the projection factor used
1622 by QTransform::rotate() for the x and y axes.
1624 If \a distanceToPlane is zero, then the returned QTransform
1625 is formed by simply dropping the third row and third column
1626 of the QMatrix4x4. This is suitable for implementing
1627 orthographic projections where the z co-ordinate should
1628 be dropped rather than projected.
1632 QTransform QMatrix4x4::toTransform(float distanceToPlane) const
1634 if (distanceToPlane == 1024.0f) {
1635 // Optimize the common case with constants.
1636 return QTransform(m[0][0], m[0][1], m[0][3] - m[0][2] * inv_dist_to_plane,
1637 m[1][0], m[1][1], m[1][3] - m[1][2] * inv_dist_to_plane,
1638 m[3][0], m[3][1], m[3][3] - m[3][2] * inv_dist_to_plane);
1639 } else if (distanceToPlane != 0.0f) {
1640 // The following projection matrix is pre-multiplied with "matrix":
1645 // where d = -1 / distanceToPlane. After projection, row 3 and
1646 // column 3 are dropped to form the final QTransform.
1647 float d = 1.0f / distanceToPlane;
1648 return QTransform(m[0][0], m[0][1], m[0][3] - m[0][2] * d,
1649 m[1][0], m[1][1], m[1][3] - m[1][2] * d,
1650 m[3][0], m[3][1], m[3][3] - m[3][2] * d);
1652 // Orthographic projection: drop row 3 and column 3.
1653 return QTransform(m[0][0], m[0][1], m[0][3],
1654 m[1][0], m[1][1], m[1][3],
1655 m[3][0], m[3][1], m[3][3]);
1660 \fn QPoint QMatrix4x4::map(const QPoint& point) const
1662 Maps \a point by multiplying this matrix by \a point.
1668 \fn QPointF QMatrix4x4::map(const QPointF& point) const
1670 Maps \a point by multiplying this matrix by \a point.
1675 #ifndef QT_NO_VECTOR3D
1678 \fn QVector3D QMatrix4x4::map(const QVector3D& point) const
1680 Maps \a point by multiplying this matrix by \a point.
1682 \sa mapRect(), mapVector()
1686 \fn QVector3D QMatrix4x4::mapVector(const QVector3D& vector) const
1688 Maps \a vector by multiplying the top 3x3 portion of this matrix
1689 by \a vector. The translation and projection components of
1690 this matrix are ignored.
1697 #ifndef QT_NO_VECTOR4D
1700 \fn QVector4D QMatrix4x4::map(const QVector4D& point) const;
1702 Maps \a point by multiplying this matrix by \a point.
1710 Maps \a rect by multiplying this matrix by the corners
1711 of \a rect and then forming a new rectangle from the results.
1712 The returned rectangle will be an ordinary 2D rectangle
1713 with sides parallel to the horizontal and vertical axes.
1717 QRect QMatrix4x4::mapRect(const QRect& rect) const
1719 if (flagBits < Scale) {
1721 return QRect(qRound(rect.x() + m[3][0]),
1722 qRound(rect.y() + m[3][1]),
1723 rect.width(), rect.height());
1724 } else if (flagBits < Rotation2D) {
1725 // Translation | Scale
1726 float x = rect.x() * m[0][0] + m[3][0];
1727 float y = rect.y() * m[1][1] + m[3][1];
1728 float w = rect.width() * m[0][0];
1729 float h = rect.height() * m[1][1];
1738 return QRect(qRound(x), qRound(y), qRound(w), qRound(h));
1741 QPoint tl = map(rect.topLeft());
1742 QPoint tr = map(QPoint(rect.x() + rect.width(), rect.y()));
1743 QPoint bl = map(QPoint(rect.x(), rect.y() + rect.height()));
1744 QPoint br = map(QPoint(rect.x() + rect.width(),
1745 rect.y() + rect.height()));
1747 int xmin = qMin(qMin(tl.x(), tr.x()), qMin(bl.x(), br.x()));
1748 int xmax = qMax(qMax(tl.x(), tr.x()), qMax(bl.x(), br.x()));
1749 int ymin = qMin(qMin(tl.y(), tr.y()), qMin(bl.y(), br.y()));
1750 int ymax = qMax(qMax(tl.y(), tr.y()), qMax(bl.y(), br.y()));
1752 return QRect(xmin, ymin, xmax - xmin, ymax - ymin);
1756 Maps \a rect by multiplying this matrix by the corners
1757 of \a rect and then forming a new rectangle from the results.
1758 The returned rectangle will be an ordinary 2D rectangle
1759 with sides parallel to the horizontal and vertical axes.
1763 QRectF QMatrix4x4::mapRect(const QRectF& rect) const
1765 if (flagBits < Scale) {
1767 return rect.translated(m[3][0], m[3][1]);
1768 } else if (flagBits < Rotation2D) {
1769 // Translation | Scale
1770 float x = rect.x() * m[0][0] + m[3][0];
1771 float y = rect.y() * m[1][1] + m[3][1];
1772 float w = rect.width() * m[0][0];
1773 float h = rect.height() * m[1][1];
1782 return QRectF(x, y, w, h);
1785 QPointF tl = map(rect.topLeft()); QPointF tr = map(rect.topRight());
1786 QPointF bl = map(rect.bottomLeft()); QPointF br = map(rect.bottomRight());
1788 float xmin = qMin(qMin(tl.x(), tr.x()), qMin(bl.x(), br.x()));
1789 float xmax = qMax(qMax(tl.x(), tr.x()), qMax(bl.x(), br.x()));
1790 float ymin = qMin(qMin(tl.y(), tr.y()), qMin(bl.y(), br.y()));
1791 float ymax = qMax(qMax(tl.y(), tr.y()), qMax(bl.y(), br.y()));
1793 return QRectF(QPointF(xmin, ymin), QPointF(xmax, ymax));
1797 \fn float *QMatrix4x4::data()
1799 Returns a pointer to the raw data of this matrix.
1801 \sa constData(), optimize()
1805 \fn const float *QMatrix4x4::data() const
1807 Returns a constant pointer to the raw data of this matrix.
1808 This raw data is stored in column-major format.
1814 \fn const float *QMatrix4x4::constData() const
1816 Returns a constant pointer to the raw data of this matrix.
1817 This raw data is stored in column-major format.
1822 // Helper routine for inverting orthonormal matrices that consist
1823 // of just rotations and translations.
1824 QMatrix4x4 QMatrix4x4::orthonormalInverse() const
1826 QMatrix4x4 result(1); // The '1' says not to load identity
1828 result.m[0][0] = m[0][0];
1829 result.m[1][0] = m[0][1];
1830 result.m[2][0] = m[0][2];
1832 result.m[0][1] = m[1][0];
1833 result.m[1][1] = m[1][1];
1834 result.m[2][1] = m[1][2];
1836 result.m[0][2] = m[2][0];
1837 result.m[1][2] = m[2][1];
1838 result.m[2][2] = m[2][2];
1840 result.m[0][3] = 0.0f;
1841 result.m[1][3] = 0.0f;
1842 result.m[2][3] = 0.0f;
1844 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]);
1845 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]);
1846 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]);
1847 result.m[3][3] = 1.0f;
1849 result.flagBits = flagBits;
1855 Optimize the usage of this matrix from its current elements.
1857 Some operations such as translate(), scale(), and rotate() can be
1858 performed more efficiently if the matrix being modified is already
1859 known to be the identity, a previous translate(), a previous
1862 Normally the QMatrix4x4 class keeps track of this special type internally
1863 as operations are performed. However, if the matrix is modified
1864 directly with operator()() or data(), then QMatrix4x4 will lose track of
1865 the special type and will revert to the safest but least efficient
1866 operations thereafter.
1868 By calling optimize() after directly modifying the matrix,
1869 the programmer can force QMatrix4x4 to recover the special type if
1870 the elements appear to conform to one of the known optimized types.
1872 \sa operator()(), data(), translate()
1874 void QMatrix4x4::optimize()
1876 // If the last row is not (0, 0, 0, 1), the matrix is not a special type.
1878 if (m[0][3] != 0 || m[1][3] != 0 || m[2][3] != 0 || m[3][3] != 1)
1881 flagBits &= ~Perspective;
1883 // If the last column is (0, 0, 0, 1), then there is no translation.
1884 if (m[3][0] == 0 && m[3][1] == 0 && m[3][2] == 0)
1885 flagBits &= ~Translation;
1887 // If the two first elements of row 3 and column 3 are 0, then any rotation must be about Z.
1888 if (!m[0][2] && !m[1][2] && !m[2][0] && !m[2][1]) {
1889 flagBits &= ~Rotation;
1890 // If the six non-diagonal elements in the top left 3x3 matrix are 0, there is no rotation.
1891 if (!m[0][1] && !m[1][0]) {
1892 flagBits &= ~Rotation2D;
1893 // Check for identity.
1894 if (m[0][0] == 1 && m[1][1] == 1 && m[2][2] == 1)
1897 // If the columns are orthonormal and form a right-handed system, then there is no scale.
1899 copyToDoubles(m, mm);
1900 double det = matrixDet2(mm, 0, 1, 0, 1);
1901 double lenX = mm[0][0] * mm[0][0] + mm[0][1] * mm[0][1];
1902 double lenY = mm[1][0] * mm[1][0] + mm[1][1] * mm[1][1];
1903 double lenZ = mm[2][2];
1904 if (qFuzzyCompare(det, 1.0) && qFuzzyCompare(lenX, 1.0)
1905 && qFuzzyCompare(lenY, 1.0) && qFuzzyCompare(lenZ, 1.0))
1911 // If the columns are orthonormal and form a right-handed system, then there is no scale.
1913 copyToDoubles(m, mm);
1914 double det = matrixDet3(mm, 0, 1, 2, 0, 1, 2);
1915 double lenX = mm[0][0] * mm[0][0] + mm[0][1] * mm[0][1] + mm[0][2] * mm[0][2];
1916 double lenY = mm[1][0] * mm[1][0] + mm[1][1] * mm[1][1] + mm[1][2] * mm[1][2];
1917 double lenZ = mm[2][0] * mm[2][0] + mm[2][1] * mm[2][1] + mm[2][2] * mm[2][2];
1918 if (qFuzzyCompare(det, 1.0) && qFuzzyCompare(lenX, 1.0)
1919 && qFuzzyCompare(lenY, 1.0) && qFuzzyCompare(lenZ, 1.0))
1927 Returns the matrix as a QVariant.
1929 QMatrix4x4::operator QVariant() const
1931 return QVariant(QVariant::Matrix4x4, this);
1934 #ifndef QT_NO_DEBUG_STREAM
1936 QDebug operator<<(QDebug dbg, const QMatrix4x4 &m)
1938 // Create a string that represents the matrix type.
1940 if (m.flagBits == QMatrix4x4::Identity) {
1942 } else if (m.flagBits == QMatrix4x4::General) {
1945 if ((m.flagBits & QMatrix4x4::Translation) != 0)
1946 bits += "Translation,";
1947 if ((m.flagBits & QMatrix4x4::Scale) != 0)
1949 if ((m.flagBits & QMatrix4x4::Rotation2D) != 0)
1950 bits += "Rotation2D,";
1951 if ((m.flagBits & QMatrix4x4::Rotation) != 0)
1952 bits += "Rotation,";
1953 if ((m.flagBits & QMatrix4x4::Perspective) != 0)
1954 bits += "Perspective,";
1955 if (bits.size() > 0)
1956 bits = bits.left(bits.size() - 1);
1959 // Output in row-major order because it is more human-readable.
1960 dbg.nospace() << "QMatrix4x4(type:" << bits.constData() << endl
1961 << qSetFieldWidth(10)
1962 << m(0, 0) << m(0, 1) << m(0, 2) << m(0, 3) << endl
1963 << m(1, 0) << m(1, 1) << m(1, 2) << m(1, 3) << endl
1964 << m(2, 0) << m(2, 1) << m(2, 2) << m(2, 3) << endl
1965 << m(3, 0) << m(3, 1) << m(3, 2) << m(3, 3) << endl
1966 << qSetFieldWidth(0) << ')';
1972 #ifndef QT_NO_DATASTREAM
1975 \fn QDataStream &operator<<(QDataStream &stream, const QMatrix4x4 &matrix)
1978 Writes the given \a matrix to the given \a stream and returns a
1979 reference to the stream.
1981 \sa {Serializing Qt Data Types}
1984 QDataStream &operator<<(QDataStream &stream, const QMatrix4x4 &matrix)
1986 for (int row = 0; row < 4; ++row)
1987 for (int col = 0; col < 4; ++col)
1988 stream << matrix(row, col);
1993 \fn QDataStream &operator>>(QDataStream &stream, QMatrix4x4 &matrix)
1996 Reads a 4x4 matrix from the given \a stream into the given \a matrix
1997 and returns a reference to the stream.
1999 \sa {Serializing Qt Data Types}
2002 QDataStream &operator>>(QDataStream &stream, QMatrix4x4 &matrix)
2005 for (int row = 0; row < 4; ++row) {
2006 for (int col = 0; col < 4; ++col) {
2008 matrix(row, col) = x;
2015 #endif // QT_NO_DATASTREAM
2017 #endif // QT_NO_MATRIX4X4