Coverage Report

Created: 2026-07-25 07:03

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