|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2010 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 static 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 */ |
|
81 QMatrix4x4::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 */ |
|
158 QMatrix4x4::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 */ |
|
184 QMatrix4x4::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 */ |
|
216 QMatrix4x4::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 | |
|
318 static 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. |
|
334 static 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 */ |
|
347 qreal 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 */ |
|
364 QMatrix4x4 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 */ |
|
426 QMatrix3x3 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 */ |
|
466 QMatrix4x4 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 */ |
|
507 QMatrix4x4& 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 */ |
|
663 QMatrix4x4 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 */ |
|
701 void 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 */ |
|
746 void 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 */ |
|
780 void 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 */ |
|
821 void 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 */ |
|
861 void 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 */ |
|
906 void 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 */ |
|
943 void 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 */ |
|
983 void 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 */ |
|
998 void 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 */ |
|
1103 void 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 */ |
|
1212 void 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 */ |
|
1261 void 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 */ |
|
1279 void 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 */ |
|
1292 void 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 */ |
|
1349 void 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 */ |
|
1389 void 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 */ |
|
1432 void 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 */ |
|
1471 void 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 */ |
|
1501 void 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 */ |
|
1515 QMatrix 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 */ |
|
1533 QTransform 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 */ |
|
1557 QTransform 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 */ |
|
1645 QRect 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 */ |
|
1689 QRectF 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. |
|
1746 QMatrix4x4 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 */ |
|
1794 void 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 */ |
|
1835 QMatrix4x4::operator QVariant() const |
|
1836 { |
|
1837 return QVariant(QVariant::Matrix4x4, this); |
|
1838 } |
|
1839 |
|
1840 #ifndef QT_NO_DEBUG_STREAM |
|
1841 |
|
1842 QDebug 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 {Format of the QDataStream Operators} |
|
1882 */ |
|
1883 |
|
1884 QDataStream &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 {Format of the QDataStream Operators} |
|
1900 */ |
|
1901 |
|
1902 QDataStream &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 |
|
1919 QT_END_NAMESPACE |