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