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