source: trunk/src/gui/math3d/qmatrix4x4.cpp@ 862

Last change on this file since 862 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

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