diff options
Diffstat (limited to 'src/positioning/qdoublematrix4x4.cpp')
-rw-r--r-- | src/positioning/qdoublematrix4x4.cpp | 1112 |
1 files changed, 0 insertions, 1112 deletions
diff --git a/src/positioning/qdoublematrix4x4.cpp b/src/positioning/qdoublematrix4x4.cpp deleted file mode 100644 index 0bc56460..00000000 --- a/src/positioning/qdoublematrix4x4.cpp +++ /dev/null @@ -1,1112 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qdoublematrix4x4_p.h" -#include <QtCore/qmath.h> -//#include <QtCore/qvariant.h> -#include <QtCore/qdatastream.h> -#include <cmath> - -QT_BEGIN_NAMESPACE - -static const double inv_dist_to_plane = 1.0 / 1024.0; - -QDoubleMatrix4x4::QDoubleMatrix4x4(const double *values) -{ - for (int row = 0; row < 4; ++row) - for (int col = 0; col < 4; ++col) - m[col][row] = values[row * 4 + col]; - flagBits = General; -} - -QDoubleMatrix4x4::QDoubleMatrix4x4(const double *values, int cols, int rows) -{ - for (int col = 0; col < 4; ++col) { - for (int row = 0; row < 4; ++row) { - if (col < cols && row < rows) - m[col][row] = values[col * rows + row]; - else if (col == row) - m[col][row] = 1.0; - else - m[col][row] = 0.0; - } - } - flagBits = General; -} - -static inline double matrixDet2(const double m[4][4], int col0, int col1, int row0, int row1) -{ - return m[col0][row0] * m[col1][row1] - m[col0][row1] * m[col1][row0]; -} - -static inline double matrixDet3 - (const double m[4][4], int col0, int col1, int col2, - int row0, int row1, int row2) -{ - return m[col0][row0] * matrixDet2(m, col1, col2, row1, row2) - - m[col1][row0] * matrixDet2(m, col0, col2, row1, row2) - + m[col2][row0] * matrixDet2(m, col0, col1, row1, row2); -} - -static inline double matrixDet4(const double m[4][4]) -{ - double det; - det = m[0][0] * matrixDet3(m, 1, 2, 3, 1, 2, 3); - det -= m[1][0] * matrixDet3(m, 0, 2, 3, 1, 2, 3); - det += m[2][0] * matrixDet3(m, 0, 1, 3, 1, 2, 3); - det -= m[3][0] * matrixDet3(m, 0, 1, 2, 1, 2, 3); - return det; -} - -double QDoubleMatrix4x4::determinant() const -{ - if ((flagBits & ~(Translation | Rotation2D | Rotation)) == Identity) - return 1.0; - - if (flagBits < Rotation2D) - return m[0][0] * m[1][1] * m[2][2]; // Translation | Scale - if (flagBits < Perspective) - return matrixDet3(m, 0, 1, 2, 0, 1, 2); - return matrixDet4(m); -} - -QDoubleMatrix4x4 QDoubleMatrix4x4::inverted(bool *invertible) const -{ - // Handle some of the easy cases first. - if (flagBits == Identity) { - if (invertible) - *invertible = true; - return QDoubleMatrix4x4(); - } else if (flagBits == Translation) { - QDoubleMatrix4x4 inv; - inv.m[3][0] = -m[3][0]; - inv.m[3][1] = -m[3][1]; - inv.m[3][2] = -m[3][2]; - inv.flagBits = Translation; - if (invertible) - *invertible = true; - return inv; - } else if (flagBits < Rotation2D) { - // Translation | Scale - if (m[0][0] == 0 || m[1][1] == 0 || m[2][2] == 0) { - if (invertible) - *invertible = false; - return QDoubleMatrix4x4(); - } - QDoubleMatrix4x4 inv; - inv.m[0][0] = 1.0 / m[0][0]; - inv.m[1][1] = 1.0 / m[1][1]; - inv.m[2][2] = 1.0 / m[2][2]; - inv.m[3][0] = -m[3][0] * inv.m[0][0]; - inv.m[3][1] = -m[3][1] * inv.m[1][1]; - inv.m[3][2] = -m[3][2] * inv.m[2][2]; - inv.flagBits = flagBits; - - if (invertible) - *invertible = true; - return inv; - } else if ((flagBits & ~(Translation | Rotation2D | Rotation)) == Identity) { - if (invertible) - *invertible = true; - return orthonormalInverse(); - } else if (flagBits < Perspective) { - QDoubleMatrix4x4 inv(1); // The "1" says to not load the identity. - - double det = matrixDet3(m, 0, 1, 2, 0, 1, 2); - if (det == 0.0) { - if (invertible) - *invertible = false; - return QDoubleMatrix4x4(); - } - det = 1.0 / det; - - inv.m[0][0] = matrixDet2(m, 1, 2, 1, 2) * det; - inv.m[0][1] = -matrixDet2(m, 0, 2, 1, 2) * det; - inv.m[0][2] = matrixDet2(m, 0, 1, 1, 2) * det; - inv.m[0][3] = 0; - inv.m[1][0] = -matrixDet2(m, 1, 2, 0, 2) * det; - inv.m[1][1] = matrixDet2(m, 0, 2, 0, 2) * det; - inv.m[1][2] = -matrixDet2(m, 0, 1, 0, 2) * det; - inv.m[1][3] = 0; - inv.m[2][0] = matrixDet2(m, 1, 2, 0, 1) * det; - inv.m[2][1] = -matrixDet2(m, 0, 2, 0, 1) * det; - inv.m[2][2] = matrixDet2(m, 0, 1, 0, 1) * det; - inv.m[2][3] = 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]; - 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]; - 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]; - inv.m[3][3] = 1; - inv.flagBits = flagBits; - - if (invertible) - *invertible = true; - return inv; - } - - QDoubleMatrix4x4 inv(1); // The "1" says to not load the identity. - - double det = matrixDet4(m); - if (det == 0.0) { - if (invertible) - *invertible = false; - return QDoubleMatrix4x4(); - } - det = 1.0 / det; - - inv.m[0][0] = matrixDet3(m, 1, 2, 3, 1, 2, 3) * det; - inv.m[0][1] = -matrixDet3(m, 0, 2, 3, 1, 2, 3) * det; - inv.m[0][2] = matrixDet3(m, 0, 1, 3, 1, 2, 3) * det; - inv.m[0][3] = -matrixDet3(m, 0, 1, 2, 1, 2, 3) * det; - inv.m[1][0] = -matrixDet3(m, 1, 2, 3, 0, 2, 3) * det; - inv.m[1][1] = matrixDet3(m, 0, 2, 3, 0, 2, 3) * det; - inv.m[1][2] = -matrixDet3(m, 0, 1, 3, 0, 2, 3) * det; - inv.m[1][3] = matrixDet3(m, 0, 1, 2, 0, 2, 3) * det; - inv.m[2][0] = matrixDet3(m, 1, 2, 3, 0, 1, 3) * det; - inv.m[2][1] = -matrixDet3(m, 0, 2, 3, 0, 1, 3) * det; - inv.m[2][2] = matrixDet3(m, 0, 1, 3, 0, 1, 3) * det; - inv.m[2][3] = -matrixDet3(m, 0, 1, 2, 0, 1, 3) * det; - inv.m[3][0] = -matrixDet3(m, 1, 2, 3, 0, 1, 2) * det; - inv.m[3][1] = matrixDet3(m, 0, 2, 3, 0, 1, 2) * det; - inv.m[3][2] = -matrixDet3(m, 0, 1, 3, 0, 1, 2) * det; - inv.m[3][3] = matrixDet3(m, 0, 1, 2, 0, 1, 2) * det; - inv.flagBits = flagBits; - - if (invertible) - *invertible = true; - return inv; -} - -QDoubleMatrix4x4 QDoubleMatrix4x4::transposed() const -{ - QDoubleMatrix4x4 result(1); // The "1" says to not load the identity. - for (int row = 0; row < 4; ++row) { - for (int col = 0; col < 4; ++col) { - result.m[col][row] = m[row][col]; - } - } - // When a translation is transposed, it becomes a perspective transformation. - result.flagBits = (flagBits & Translation ? General : flagBits); - return result; -} - -QDoubleMatrix4x4& QDoubleMatrix4x4::operator/=(double divisor) -{ - m[0][0] /= divisor; - m[0][1] /= divisor; - m[0][2] /= divisor; - m[0][3] /= divisor; - m[1][0] /= divisor; - m[1][1] /= divisor; - m[1][2] /= divisor; - m[1][3] /= divisor; - m[2][0] /= divisor; - m[2][1] /= divisor; - m[2][2] /= divisor; - m[2][3] /= divisor; - m[3][0] /= divisor; - m[3][1] /= divisor; - m[3][2] /= divisor; - m[3][3] /= divisor; - flagBits = General; - return *this; -} - -QDoubleMatrix4x4 operator/(const QDoubleMatrix4x4& matrix, double divisor) -{ - QDoubleMatrix4x4 m(1); // The "1" says to not load the identity. - m.m[0][0] = matrix.m[0][0] / divisor; - m.m[0][1] = matrix.m[0][1] / divisor; - m.m[0][2] = matrix.m[0][2] / divisor; - m.m[0][3] = matrix.m[0][3] / divisor; - m.m[1][0] = matrix.m[1][0] / divisor; - m.m[1][1] = matrix.m[1][1] / divisor; - m.m[1][2] = matrix.m[1][2] / divisor; - m.m[1][3] = matrix.m[1][3] / divisor; - m.m[2][0] = matrix.m[2][0] / divisor; - m.m[2][1] = matrix.m[2][1] / divisor; - m.m[2][2] = matrix.m[2][2] / divisor; - m.m[2][3] = matrix.m[2][3] / divisor; - m.m[3][0] = matrix.m[3][0] / divisor; - m.m[3][1] = matrix.m[3][1] / divisor; - m.m[3][2] = matrix.m[3][2] / divisor; - m.m[3][3] = matrix.m[3][3] / divisor; - m.flagBits = QDoubleMatrix4x4::General; - return m; -} - -void QDoubleMatrix4x4::scale(const QDoubleVector3D& vector) -{ - double vx = vector.x(); - double vy = vector.y(); - double vz = vector.z(); - if (flagBits < Scale) { - m[0][0] = vx; - m[1][1] = vy; - m[2][2] = vz; - } else if (flagBits < Rotation2D) { - m[0][0] *= vx; - m[1][1] *= vy; - m[2][2] *= vz; - } else if (flagBits < Rotation) { - m[0][0] *= vx; - m[0][1] *= vx; - m[1][0] *= vy; - m[1][1] *= vy; - m[2][2] *= vz; - } else { - m[0][0] *= vx; - m[0][1] *= vx; - m[0][2] *= vx; - m[0][3] *= vx; - m[1][0] *= vy; - m[1][1] *= vy; - m[1][2] *= vy; - m[1][3] *= vy; - m[2][0] *= vz; - m[2][1] *= vz; - m[2][2] *= vz; - m[2][3] *= vz; - } - flagBits |= Scale; -} - -void QDoubleMatrix4x4::scale(double x, double y) -{ - if (flagBits < Scale) { - m[0][0] = x; - m[1][1] = y; - } else if (flagBits < Rotation2D) { - m[0][0] *= x; - m[1][1] *= y; - } else if (flagBits < Rotation) { - m[0][0] *= x; - m[0][1] *= x; - m[1][0] *= y; - m[1][1] *= y; - } else { - m[0][0] *= x; - m[0][1] *= x; - m[0][2] *= x; - m[0][3] *= x; - m[1][0] *= y; - m[1][1] *= y; - m[1][2] *= y; - m[1][3] *= y; - } - flagBits |= Scale; -} - -void QDoubleMatrix4x4::scale(double x, double y, double z) -{ - if (flagBits < Scale) { - m[0][0] = x; - m[1][1] = y; - m[2][2] = z; - } else if (flagBits < Rotation2D) { - m[0][0] *= x; - m[1][1] *= y; - m[2][2] *= z; - } else if (flagBits < Rotation) { - m[0][0] *= x; - m[0][1] *= x; - m[1][0] *= y; - m[1][1] *= y; - m[2][2] *= z; - } else { - m[0][0] *= x; - m[0][1] *= x; - m[0][2] *= x; - m[0][3] *= x; - m[1][0] *= y; - m[1][1] *= y; - m[1][2] *= y; - m[1][3] *= y; - m[2][0] *= z; - m[2][1] *= z; - m[2][2] *= z; - m[2][3] *= z; - } - flagBits |= Scale; -} - -void QDoubleMatrix4x4::scale(double factor) -{ - if (flagBits < Scale) { - m[0][0] = factor; - m[1][1] = factor; - m[2][2] = factor; - } else if (flagBits < Rotation2D) { - m[0][0] *= factor; - m[1][1] *= factor; - m[2][2] *= factor; - } else if (flagBits < Rotation) { - m[0][0] *= factor; - m[0][1] *= factor; - m[1][0] *= factor; - m[1][1] *= factor; - m[2][2] *= factor; - } else { - m[0][0] *= factor; - m[0][1] *= factor; - m[0][2] *= factor; - m[0][3] *= factor; - m[1][0] *= factor; - m[1][1] *= factor; - m[1][2] *= factor; - m[1][3] *= factor; - m[2][0] *= factor; - m[2][1] *= factor; - m[2][2] *= factor; - m[2][3] *= factor; - } - flagBits |= Scale; -} - -void QDoubleMatrix4x4::translate(const QDoubleVector3D& vector) -{ - double vx = vector.x(); - double vy = vector.y(); - double vz = vector.z(); - if (flagBits == Identity) { - m[3][0] = vx; - m[3][1] = vy; - m[3][2] = vz; - } else if (flagBits == Translation) { - m[3][0] += vx; - m[3][1] += vy; - m[3][2] += vz; - } else if (flagBits == Scale) { - m[3][0] = m[0][0] * vx; - m[3][1] = m[1][1] * vy; - m[3][2] = m[2][2] * vz; - } else if (flagBits == (Translation | Scale)) { - m[3][0] += m[0][0] * vx; - m[3][1] += m[1][1] * vy; - m[3][2] += m[2][2] * vz; - } else if (flagBits < Rotation) { - m[3][0] += m[0][0] * vx + m[1][0] * vy; - m[3][1] += m[0][1] * vx + m[1][1] * vy; - m[3][2] += m[2][2] * vz; - } else { - m[3][0] += m[0][0] * vx + m[1][0] * vy + m[2][0] * vz; - m[3][1] += m[0][1] * vx + m[1][1] * vy + m[2][1] * vz; - m[3][2] += m[0][2] * vx + m[1][2] * vy + m[2][2] * vz; - m[3][3] += m[0][3] * vx + m[1][3] * vy + m[2][3] * vz; - } - flagBits |= Translation; -} - -void QDoubleMatrix4x4::translate(double x, double y) -{ - if (flagBits == Identity) { - m[3][0] = x; - m[3][1] = y; - } else if (flagBits == Translation) { - m[3][0] += x; - m[3][1] += y; - } else if (flagBits == Scale) { - m[3][0] = m[0][0] * x; - m[3][1] = m[1][1] * y; - } else if (flagBits == (Translation | Scale)) { - m[3][0] += m[0][0] * x; - m[3][1] += m[1][1] * y; - } else if (flagBits < Rotation) { - m[3][0] += m[0][0] * x + m[1][0] * y; - m[3][1] += m[0][1] * x + m[1][1] * y; - } else { - m[3][0] += m[0][0] * x + m[1][0] * y; - m[3][1] += m[0][1] * x + m[1][1] * y; - m[3][2] += m[0][2] * x + m[1][2] * y; - m[3][3] += m[0][3] * x + m[1][3] * y; - } - flagBits |= Translation; -} - -void QDoubleMatrix4x4::translate(double x, double y, double z) -{ - if (flagBits == Identity) { - m[3][0] = x; - m[3][1] = y; - m[3][2] = z; - } else if (flagBits == Translation) { - m[3][0] += x; - m[3][1] += y; - m[3][2] += z; - } else if (flagBits == Scale) { - m[3][0] = m[0][0] * x; - m[3][1] = m[1][1] * y; - m[3][2] = m[2][2] * z; - } else if (flagBits == (Translation | Scale)) { - m[3][0] += m[0][0] * x; - m[3][1] += m[1][1] * y; - m[3][2] += m[2][2] * z; - } else if (flagBits < Rotation) { - m[3][0] += m[0][0] * x + m[1][0] * y; - m[3][1] += m[0][1] * x + m[1][1] * y; - m[3][2] += m[2][2] * z; - } else { - m[3][0] += m[0][0] * x + m[1][0] * y + m[2][0] * z; - m[3][1] += m[0][1] * x + m[1][1] * y + m[2][1] * z; - m[3][2] += m[0][2] * x + m[1][2] * y + m[2][2] * z; - m[3][3] += m[0][3] * x + m[1][3] * y + m[2][3] * z; - } - flagBits |= Translation; -} - -void QDoubleMatrix4x4::rotate(double angle, const QDoubleVector3D& vector) -{ - rotate(angle, vector.x(), vector.y(), vector.z()); -} - -void QDoubleMatrix4x4::rotate(double angle, double x, double y, double z) -{ - if (angle == 0.0) - return; - double c, s; - if (angle == 90.0 || angle == -270.0) { - s = 1.0; - c = 0.0; - } else if (angle == -90.0 || angle == 270.0) { - s = -1.0; - c = 0.0; - } else if (angle == 180.0 || angle == -180.0) { - s = 0.0; - c = -1.0; - } else { - double a = qDegreesToRadians(angle); - c = std::cos(a); - s = std::sin(a); - } - if (x == 0.0) { - if (y == 0.0) { - if (z != 0.0) { - // Rotate around the Z axis. - if (z < 0) - s = -s; - double tmp; - m[0][0] = (tmp = m[0][0]) * c + m[1][0] * s; - m[1][0] = m[1][0] * c - tmp * s; - m[0][1] = (tmp = m[0][1]) * c + m[1][1] * s; - m[1][1] = m[1][1] * c - tmp * s; - m[0][2] = (tmp = m[0][2]) * c + m[1][2] * s; - m[1][2] = m[1][2] * c - tmp * s; - m[0][3] = (tmp = m[0][3]) * c + m[1][3] * s; - m[1][3] = m[1][3] * c - tmp * s; - - flagBits |= Rotation2D; - return; - } - } else if (z == 0.0) { - // Rotate around the Y axis. - if (y < 0) - s = -s; - double tmp; - m[2][0] = (tmp = m[2][0]) * c + m[0][0] * s; - m[0][0] = m[0][0] * c - tmp * s; - m[2][1] = (tmp = m[2][1]) * c + m[0][1] * s; - m[0][1] = m[0][1] * c - tmp * s; - m[2][2] = (tmp = m[2][2]) * c + m[0][2] * s; - m[0][2] = m[0][2] * c - tmp * s; - m[2][3] = (tmp = m[2][3]) * c + m[0][3] * s; - m[0][3] = m[0][3] * c - tmp * s; - - flagBits |= Rotation; - return; - } - } else if (y == 0.0 && z == 0.0) { - // Rotate around the X axis. - if (x < 0) - s = -s; - double tmp; - m[1][0] = (tmp = m[1][0]) * c + m[2][0] * s; - m[2][0] = m[2][0] * c - tmp * s; - m[1][1] = (tmp = m[1][1]) * c + m[2][1] * s; - m[2][1] = m[2][1] * c - tmp * s; - m[1][2] = (tmp = m[1][2]) * c + m[2][2] * s; - m[2][2] = m[2][2] * c - tmp * s; - m[1][3] = (tmp = m[1][3]) * c + m[2][3] * s; - m[2][3] = m[2][3] * c - tmp * s; - - flagBits |= Rotation; - return; - } - - double len = double(x) * double(x) + - double(y) * double(y) + - double(z) * double(z); - if (!qFuzzyCompare(len, 1.0) && !qFuzzyIsNull(len)) { - len = std::sqrt(len); - x = double(double(x) / len); - y = double(double(y) / len); - z = double(double(z) / len); - } - double ic = 1.0 - c; - QDoubleMatrix4x4 rot(1); // The "1" says to not load the identity. - rot.m[0][0] = x * x * ic + c; - rot.m[1][0] = x * y * ic - z * s; - rot.m[2][0] = x * z * ic + y * s; - rot.m[3][0] = 0.0; - rot.m[0][1] = y * x * ic + z * s; - rot.m[1][1] = y * y * ic + c; - rot.m[2][1] = y * z * ic - x * s; - rot.m[3][1] = 0.0; - rot.m[0][2] = x * z * ic - y * s; - rot.m[1][2] = y * z * ic + x * s; - rot.m[2][2] = z * z * ic + c; - rot.m[3][2] = 0.0; - rot.m[0][3] = 0.0; - rot.m[1][3] = 0.0; - rot.m[2][3] = 0.0; - rot.m[3][3] = 1.0; - rot.flagBits = Rotation; - *this *= rot; -} - -void QDoubleMatrix4x4::projectedRotate(double angle, double x, double y, double z) -{ - // Used by QGraphicsRotation::applyTo() to perform a rotation - // and projection back to 2D in a single step. - if (angle == 0.0) - return; - double c, s; - if (angle == 90.0 || angle == -270.0) { - s = 1.0; - c = 0.0; - } else if (angle == -90.0 || angle == 270.0) { - s = -1.0; - c = 0.0; - } else if (angle == 180.0 || angle == -180.0) { - s = 0.0; - c = -1.0; - } else { - double a = qDegreesToRadians(angle); - c = std::cos(a); - s = std::sin(a); - } - if (x == 0.0) { - if (y == 0.0) { - if (z != 0.0) { - // Rotate around the Z axis. - if (z < 0) - s = -s; - double tmp; - m[0][0] = (tmp = m[0][0]) * c + m[1][0] * s; - m[1][0] = m[1][0] * c - tmp * s; - m[0][1] = (tmp = m[0][1]) * c + m[1][1] * s; - m[1][1] = m[1][1] * c - tmp * s; - m[0][2] = (tmp = m[0][2]) * c + m[1][2] * s; - m[1][2] = m[1][2] * c - tmp * s; - m[0][3] = (tmp = m[0][3]) * c + m[1][3] * s; - m[1][3] = m[1][3] * c - tmp * s; - - flagBits |= Rotation2D; - return; - } - } else if (z == 0.0) { - // Rotate around the Y axis. - if (y < 0) - s = -s; - m[0][0] = m[0][0] * c + m[3][0] * s * inv_dist_to_plane; - m[0][1] = m[0][1] * c + m[3][1] * s * inv_dist_to_plane; - m[0][2] = m[0][2] * c + m[3][2] * s * inv_dist_to_plane; - m[0][3] = m[0][3] * c + m[3][3] * s * inv_dist_to_plane; - flagBits = General; - return; - } - } else if (y == 0.0 && z == 0.0) { - // Rotate around the X axis. - if (x < 0) - s = -s; - m[1][0] = m[1][0] * c - m[3][0] * s * inv_dist_to_plane; - m[1][1] = m[1][1] * c - m[3][1] * s * inv_dist_to_plane; - m[1][2] = m[1][2] * c - m[3][2] * s * inv_dist_to_plane; - m[1][3] = m[1][3] * c - m[3][3] * s * inv_dist_to_plane; - flagBits = General; - return; - } - double len = double(x) * double(x) + - double(y) * double(y) + - double(z) * double(z); - if (!qFuzzyCompare(len, 1.0) && !qFuzzyIsNull(len)) { - len = std::sqrt(len); - x = double(double(x) / len); - y = double(double(y) / len); - z = double(double(z) / len); - } - double ic = 1.0 - c; - QDoubleMatrix4x4 rot(1); // The "1" says to not load the identity. - rot.m[0][0] = x * x * ic + c; - rot.m[1][0] = x * y * ic - z * s; - rot.m[2][0] = 0.0; - rot.m[3][0] = 0.0; - rot.m[0][1] = y * x * ic + z * s; - rot.m[1][1] = y * y * ic + c; - rot.m[2][1] = 0.0; - rot.m[3][1] = 0.0; - rot.m[0][2] = 0.0; - rot.m[1][2] = 0.0; - rot.m[2][2] = 1.0; - rot.m[3][2] = 0.0; - rot.m[0][3] = (x * z * ic - y * s) * -inv_dist_to_plane; - rot.m[1][3] = (y * z * ic + x * s) * -inv_dist_to_plane; - rot.m[2][3] = 0.0; - rot.m[3][3] = 1.0; - rot.flagBits = General; - *this *= rot; -} - -void QDoubleMatrix4x4::ortho(const QRect& rect) -{ - // Note: rect.right() and rect.bottom() subtract 1 in QRect, - // which gives the location of a pixel within the rectangle, - // instead of the extent of the rectangle. We want the extent. - // QRectF expresses the extent properly. - ortho(rect.x(), rect.x() + rect.width(), rect.y() + rect.height(), rect.y(), -1.0, 1.0); -} - -void QDoubleMatrix4x4::ortho(const QRectF& rect) -{ - ortho(rect.left(), rect.right(), rect.bottom(), rect.top(), -1.0, 1.0); -} - -void QDoubleMatrix4x4::ortho(double left, double right, double bottom, double top, double nearPlane, double farPlane) -{ - // Bail out if the projection volume is zero-sized. - if (left == right || bottom == top || nearPlane == farPlane) - return; - - // Construct the projection. - double width = right - left; - double invheight = top - bottom; - double clip = farPlane - nearPlane; - QDoubleMatrix4x4 m(1); - m.m[0][0] = 2.0 / width; - m.m[1][0] = 0.0; - m.m[2][0] = 0.0; - m.m[3][0] = -(left + right) / width; - m.m[0][1] = 0.0; - m.m[1][1] = 2.0 / invheight; - m.m[2][1] = 0.0; - m.m[3][1] = -(top + bottom) / invheight; - m.m[0][2] = 0.0; - m.m[1][2] = 0.0; - m.m[2][2] = -2.0 / clip; - m.m[3][2] = -(nearPlane + farPlane) / clip; - m.m[0][3] = 0.0; - m.m[1][3] = 0.0; - m.m[2][3] = 0.0; - m.m[3][3] = 1.0; - m.flagBits = Translation | Scale; - - // Apply the projection. - *this *= m; -} - -void QDoubleMatrix4x4::frustum(double left, double right, double bottom, double top, double nearPlane, double farPlane) -{ - // Bail out if the projection volume is zero-sized. - if (left == right || bottom == top || nearPlane == farPlane) - return; - - // Construct the projection. - QDoubleMatrix4x4 m(1); - double width = right - left; - double invheight = top - bottom; - double clip = farPlane - nearPlane; - m.m[0][0] = 2.0 * nearPlane / width; - m.m[1][0] = 0.0; - m.m[2][0] = (left + right) / width; - m.m[3][0] = 0.0; - m.m[0][1] = 0.0; - m.m[1][1] = 2.0 * nearPlane / invheight; - m.m[2][1] = (top + bottom) / invheight; - m.m[3][1] = 0.0; - m.m[0][2] = 0.0; - m.m[1][2] = 0.0; - m.m[2][2] = -(nearPlane + farPlane) / clip; - m.m[3][2] = -2.0 * nearPlane * farPlane / clip; - m.m[0][3] = 0.0; - m.m[1][3] = 0.0; - m.m[2][3] = -1.0; - m.m[3][3] = 0.0; - m.flagBits = General; - - // Apply the projection. - *this *= m; -} - -void QDoubleMatrix4x4::perspective(double verticalAngle, double aspectRatio, double nearPlane, double farPlane) -{ - // Bail out if the projection volume is zero-sized. - if (nearPlane == farPlane || aspectRatio == 0.0) - return; - - // Construct the projection. - QDoubleMatrix4x4 m(1); - double radians = qDegreesToRadians(verticalAngle / 2.0); - double sine = std::sin(radians); - if (sine == 0.0) - return; - double cotan = std::cos(radians) / sine; - double clip = farPlane - nearPlane; - m.m[0][0] = cotan / aspectRatio; - m.m[1][0] = 0.0; - m.m[2][0] = 0.0; - m.m[3][0] = 0.0; - m.m[0][1] = 0.0; - m.m[1][1] = cotan; - m.m[2][1] = 0.0; - m.m[3][1] = 0.0; - m.m[0][2] = 0.0; - m.m[1][2] = 0.0; - m.m[2][2] = -(nearPlane + farPlane) / clip; - m.m[3][2] = -(2.0 * nearPlane * farPlane) / clip; - m.m[0][3] = 0.0; - m.m[1][3] = 0.0; - m.m[2][3] = -1.0; - m.m[3][3] = 0.0; - m.flagBits = General; - - // Apply the projection. - *this *= m; -} - -void QDoubleMatrix4x4::lookAt(const QDoubleVector3D& eye, const QDoubleVector3D& center, const QDoubleVector3D& up) -{ - QDoubleVector3D forward = center - eye; - if (qFuzzyIsNull(forward.x()) && qFuzzyIsNull(forward.y()) && qFuzzyIsNull(forward.z())) - return; - - forward.normalize(); - QDoubleVector3D side = QDoubleVector3D::crossProduct(forward, up).normalized(); - QDoubleVector3D upVector = QDoubleVector3D::crossProduct(side, forward); - - QDoubleMatrix4x4 m(1); - m.m[0][0] = side.x(); - m.m[1][0] = side.y(); - m.m[2][0] = side.z(); - m.m[3][0] = 0.0; - m.m[0][1] = upVector.x(); - m.m[1][1] = upVector.y(); - m.m[2][1] = upVector.z(); - m.m[3][1] = 0.0; - m.m[0][2] = -forward.x(); - m.m[1][2] = -forward.y(); - m.m[2][2] = -forward.z(); - m.m[3][2] = 0.0; - m.m[0][3] = 0.0; - m.m[1][3] = 0.0; - m.m[2][3] = 0.0; - m.m[3][3] = 1.0; - m.flagBits = Rotation; - - *this *= m; - translate(-eye); -} - -void QDoubleMatrix4x4::viewport(double left, double bottom, double width, double height, double nearPlane, double farPlane) -{ - const double w2 = width / 2.0; - const double h2 = height / 2.0; - - QDoubleMatrix4x4 m(1); - m.m[0][0] = w2; - m.m[1][0] = 0.0; - m.m[2][0] = 0.0; - m.m[3][0] = left + w2; - m.m[0][1] = 0.0; - m.m[1][1] = h2; - m.m[2][1] = 0.0; - m.m[3][1] = bottom + h2; - m.m[0][2] = 0.0; - m.m[1][2] = 0.0; - m.m[2][2] = (farPlane - nearPlane) / 2.0; - m.m[3][2] = (nearPlane + farPlane) / 2.0; - m.m[0][3] = 0.0; - m.m[1][3] = 0.0; - m.m[2][3] = 0.0; - m.m[3][3] = 1.0; - m.flagBits = General; - - *this *= m; -} - -void QDoubleMatrix4x4::flipCoordinates() -{ - // Multiplying the y and z coordinates with -1 does NOT flip between right-handed and - // left-handed coordinate systems, it just rotates 180 degrees around the x axis, so - // I'm deprecating this function. - if (flagBits < Rotation2D) { - // Translation | Scale - m[1][1] = -m[1][1]; - m[2][2] = -m[2][2]; - } else { - m[1][0] = -m[1][0]; - m[1][1] = -m[1][1]; - m[1][2] = -m[1][2]; - m[1][3] = -m[1][3]; - m[2][0] = -m[2][0]; - m[2][1] = -m[2][1]; - m[2][2] = -m[2][2]; - m[2][3] = -m[2][3]; - } - flagBits |= Scale; -} - -void QDoubleMatrix4x4::copyDataTo(double *values) const -{ - for (int row = 0; row < 4; ++row) - for (int col = 0; col < 4; ++col) - values[row * 4 + col] = double(m[col][row]); -} - -QRect QDoubleMatrix4x4::mapRect(const QRect& rect) const -{ - if (flagBits < Scale) { - // Translation - return QRect(qRound(rect.x() + m[3][0]), - qRound(rect.y() + m[3][1]), - rect.width(), rect.height()); - } else if (flagBits < Rotation2D) { - // Translation | Scale - double x = rect.x() * m[0][0] + m[3][0]; - double y = rect.y() * m[1][1] + m[3][1]; - double w = rect.width() * m[0][0]; - double h = rect.height() * m[1][1]; - if (w < 0) { - w = -w; - x -= w; - } - if (h < 0) { - h = -h; - y -= h; - } - return QRect(qRound(x), qRound(y), qRound(w), qRound(h)); - } - - QPoint tl = map(rect.topLeft()); - QPoint tr = map(QPoint(rect.x() + rect.width(), rect.y())); - QPoint bl = map(QPoint(rect.x(), rect.y() + rect.height())); - QPoint br = map(QPoint(rect.x() + rect.width(), - rect.y() + rect.height())); - - int xmin = qMin(qMin(tl.x(), tr.x()), qMin(bl.x(), br.x())); - int xmax = qMax(qMax(tl.x(), tr.x()), qMax(bl.x(), br.x())); - int ymin = qMin(qMin(tl.y(), tr.y()), qMin(bl.y(), br.y())); - int ymax = qMax(qMax(tl.y(), tr.y()), qMax(bl.y(), br.y())); - - return QRect(xmin, ymin, xmax - xmin, ymax - ymin); -} - -QRectF QDoubleMatrix4x4::mapRect(const QRectF& rect) const -{ - if (flagBits < Scale) { - // Translation - return rect.translated(m[3][0], m[3][1]); - } else if (flagBits < Rotation2D) { - // Translation | Scale - double x = rect.x() * m[0][0] + m[3][0]; - double y = rect.y() * m[1][1] + m[3][1]; - double w = rect.width() * m[0][0]; - double h = rect.height() * m[1][1]; - if (w < 0) { - w = -w; - x -= w; - } - if (h < 0) { - h = -h; - y -= h; - } - return QRectF(x, y, w, h); - } - - QPointF tl = map(rect.topLeft()); QPointF tr = map(rect.topRight()); - QPointF bl = map(rect.bottomLeft()); QPointF br = map(rect.bottomRight()); - - double xmin = qMin(qMin(tl.x(), tr.x()), qMin(bl.x(), br.x())); - double xmax = qMax(qMax(tl.x(), tr.x()), qMax(bl.x(), br.x())); - double ymin = qMin(qMin(tl.y(), tr.y()), qMin(bl.y(), br.y())); - double ymax = qMax(qMax(tl.y(), tr.y()), qMax(bl.y(), br.y())); - - return QRectF(QPointF(xmin, ymin), QPointF(xmax, ymax)); -} - -QDoubleMatrix4x4 QDoubleMatrix4x4::orthonormalInverse() const -{ - QDoubleMatrix4x4 result(1); // The '1' says not to load identity - - result.m[0][0] = m[0][0]; - result.m[1][0] = m[0][1]; - result.m[2][0] = m[0][2]; - - result.m[0][1] = m[1][0]; - result.m[1][1] = m[1][1]; - result.m[2][1] = m[1][2]; - - result.m[0][2] = m[2][0]; - result.m[1][2] = m[2][1]; - result.m[2][2] = m[2][2]; - - result.m[0][3] = 0.0; - result.m[1][3] = 0.0; - result.m[2][3] = 0.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]); - 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]); - 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]); - result.m[3][3] = 1.0; - - result.flagBits = flagBits; - - return result; -} - -void QDoubleMatrix4x4::optimize() -{ - // If the last row is not (0, 0, 0, 1), the matrix is not a special type. - flagBits = General; - if (m[0][3] != 0 || m[1][3] != 0 || m[2][3] != 0 || m[3][3] != 1) - return; - - flagBits &= ~Perspective; - - // If the last column is (0, 0, 0, 1), then there is no translation. - if (m[3][0] == 0 && m[3][1] == 0 && m[3][2] == 0) - flagBits &= ~Translation; - - // If the two first elements of row 3 and column 3 are 0, then any rotation must be about Z. - if (!m[0][2] && !m[1][2] && !m[2][0] && !m[2][1]) { - flagBits &= ~Rotation; - // If the six non-diagonal elements in the top left 3x3 matrix are 0, there is no rotation. - if (!m[0][1] && !m[1][0]) { - flagBits &= ~Rotation2D; - // Check for identity. - if (m[0][0] == 1 && m[1][1] == 1 && m[2][2] == 1) - flagBits &= ~Scale; - } else { - // If the columns are orthonormal and form a right-handed system, then there is no scale. - double det = matrixDet2(m, 0, 1, 0, 1); - double lenX = m[0][0] * m[0][0] + m[0][1] * m[0][1]; - double lenY = m[1][0] * m[1][0] + m[1][1] * m[1][1]; - double lenZ = m[2][2]; - if (qFuzzyCompare(det, 1.0) && qFuzzyCompare(lenX, 1.0) - && qFuzzyCompare(lenY, 1.0) && qFuzzyCompare(lenZ, 1.0)) - { - flagBits &= ~Scale; - } - } - } else { - // If the columns are orthonormal and form a right-handed system, then there is no scale. - double det = matrixDet3(m, 0, 1, 2, 0, 1, 2); - double lenX = m[0][0] * m[0][0] + m[0][1] * m[0][1] + m[0][2] * m[0][2]; - double lenY = m[1][0] * m[1][0] + m[1][1] * m[1][1] + m[1][2] * m[1][2]; - double lenZ = m[2][0] * m[2][0] + m[2][1] * m[2][1] + m[2][2] * m[2][2]; - if (qFuzzyCompare(det, 1.0) && qFuzzyCompare(lenX, 1.0) - && qFuzzyCompare(lenY, 1.0) && qFuzzyCompare(lenZ, 1.0)) - { - flagBits &= ~Scale; - } - } -} - -#ifndef QT_NO_DEBUG_STREAM - -QDebug operator<<(QDebug dbg, const QDoubleMatrix4x4 &m) -{ - QDebugStateSaver saver(dbg); - // Create a string that represents the matrix type. - QByteArray bits; - if (m.flagBits == QDoubleMatrix4x4::Identity) { - bits = "Identity"; - } else if (m.flagBits == QDoubleMatrix4x4::General) { - bits = "General"; - } else { - if ((m.flagBits & QDoubleMatrix4x4::Translation) != 0) - bits += "Translation,"; - if ((m.flagBits & QDoubleMatrix4x4::Scale) != 0) - bits += "Scale,"; - if ((m.flagBits & QDoubleMatrix4x4::Rotation2D) != 0) - bits += "Rotation2D,"; - if ((m.flagBits & QDoubleMatrix4x4::Rotation) != 0) - bits += "Rotation,"; - if ((m.flagBits & QDoubleMatrix4x4::Perspective) != 0) - bits += "Perspective,"; - if (bits.size() > 0) - bits = bits.left(bits.size() - 1); - } - - // Output in row-major order because it is more human-readable. - dbg.nospace() << "QDoubleMatrix4x4(type:" << bits.constData() << Qt::endl - << qSetFieldWidth(10) - << m(0, 0) << m(0, 1) << m(0, 2) << m(0, 3) << Qt::endl - << m(1, 0) << m(1, 1) << m(1, 2) << m(1, 3) << Qt::endl - << m(2, 0) << m(2, 1) << m(2, 2) << m(2, 3) << Qt::endl - << m(3, 0) << m(3, 1) << m(3, 2) << m(3, 3) << Qt::endl - << qSetFieldWidth(0) << ')'; - return dbg; -} - -#endif - -#ifndef QT_NO_DATASTREAM - -QDataStream &operator<<(QDataStream &stream, const QDoubleMatrix4x4 &matrix) -{ - for (int row = 0; row < 4; ++row) - for (int col = 0; col < 4; ++col) - stream << matrix(row, col); - return stream; -} - -QDataStream &operator>>(QDataStream &stream, QDoubleMatrix4x4 &matrix) -{ - double x; - for (int row = 0; row < 4; ++row) { - for (int col = 0; col < 4; ++col) { - stream >> x; - matrix(row, col) = x; - } - } - matrix.optimize(); - return stream; -} - -#endif // QT_NO_DATASTREAM - -QT_END_NAMESPACE |