summaryrefslogtreecommitdiffstats
path: root/src/gui/math3d
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/math3d')
-rw-r--r--src/gui/math3d/math3d.pri15
-rw-r--r--src/gui/math3d/qgenericmatrix.cpp342
-rw-r--r--src/gui/math3d/qgenericmatrix.h407
-rw-r--r--src/gui/math3d/qmatrix4x4.cpp1915
-rw-r--r--src/gui/math3d/qmatrix4x4.h1022
-rw-r--r--src/gui/math3d/qquaternion.cpp636
-rw-r--r--src/gui/math3d/qquaternion.h330
-rw-r--r--src/gui/math3d/qvector2d.cpp475
-rw-r--r--src/gui/math3d/qvector2d.h262
-rw-r--r--src/gui/math3d/qvector3d.cpp629
-rw-r--r--src/gui/math3d/qvector3d.h286
-rw-r--r--src/gui/math3d/qvector4d.cpp584
-rw-r--r--src/gui/math3d/qvector4d.h291
13 files changed, 7194 insertions, 0 deletions
diff --git a/src/gui/math3d/math3d.pri b/src/gui/math3d/math3d.pri
new file mode 100644
index 0000000000..e4dd53a68e
--- /dev/null
+++ b/src/gui/math3d/math3d.pri
@@ -0,0 +1,15 @@
+HEADERS += \
+ math3d/qgenericmatrix.h \
+ math3d/qmatrix4x4.h \
+ math3d/qquaternion.h \
+ math3d/qvector2d.h \
+ math3d/qvector3d.h \
+ math3d/qvector4d.h
+
+SOURCES += \
+ math3d/qgenericmatrix.cpp \
+ math3d/qmatrix4x4.cpp \
+ math3d/qquaternion.cpp \
+ math3d/qvector2d.cpp \
+ math3d/qvector3d.cpp \
+ math3d/qvector4d.cpp
diff --git a/src/gui/math3d/qgenericmatrix.cpp b/src/gui/math3d/qgenericmatrix.cpp
new file mode 100644
index 0000000000..922f5e0045
--- /dev/null
+++ b/src/gui/math3d/qgenericmatrix.cpp
@@ -0,0 +1,342 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgenericmatrix.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QGenericMatrix
+ \brief The QGenericMatrix class is a template class that represents a NxM transformation matrix with N columns and M rows.
+ \since 4.6
+ \ingroup painting
+ \ingroup painting-3D
+
+ The QGenericMatrix template has three parameters:
+
+ \table
+ \row \i N \i Number of columns.
+ \row \i M \i Number of rows.
+ \row \i T \i Element type that is visible to users of the class.
+ \endtable
+
+ \sa QMatrix4x4
+*/
+
+/*!
+ \fn QGenericMatrix::QGenericMatrix()
+
+ Constructs a NxM identity matrix.
+*/
+
+/*!
+ \fn QGenericMatrix::QGenericMatrix(const QGenericMatrix<N, M, T>& other)
+
+ Constructs a copy of \a other.
+*/
+
+/*!
+ \fn QGenericMatrix::QGenericMatrix(const T *values)
+
+ Constructs a matrix from the given N * M floating-point \a values.
+ The contents of the array \a values is assumed to be in
+ row-major order.
+
+ \sa copyDataTo()
+*/
+
+/*!
+ \fn const T& QGenericMatrix::operator()(int row, int column) const
+
+ Returns a constant reference to the element at position
+ (\a row, \a column) in this matrix.
+*/
+
+/*!
+ \fn T& QGenericMatrix::operator()(int row, int column)
+
+ Returns a reference to the element at position (\a row, \a column)
+ in this matrix so that the element can be assigned to.
+*/
+
+/*!
+ \fn bool QGenericMatrix::isIdentity() const
+
+ Returns true if this matrix is the identity; false otherwise.
+
+ \sa setToIdentity()
+*/
+
+/*!
+ \fn void QGenericMatrix::setToIdentity()
+
+ Sets this matrix to the identity.
+
+ \sa isIdentity()
+*/
+
+/*!
+ \fn void QGenericMatrix::fill(T value)
+
+ Fills all elements of this matrix with \a value.
+*/
+
+/*!
+ \fn QGenericMatrix<M, N> QGenericMatrix::transposed() const
+
+ Returns this matrix, transposed about its diagonal.
+*/
+
+/*!
+ \fn QGenericMatrix<N, M, T>& QGenericMatrix::operator+=(const QGenericMatrix<N, M, T>& other)
+
+ Adds the contents of \a other to this matrix.
+*/
+
+/*!
+ \fn QGenericMatrix<N, M, T>& QGenericMatrix::operator-=(const QGenericMatrix<N, M, T>& other)
+
+ Subtracts the contents of \a other from this matrix.
+*/
+
+/*!
+ \fn QGenericMatrix<N, M, T>& QGenericMatrix::operator*=(T factor)
+
+ Multiplies all elements of this matrix by \a factor.
+*/
+
+/*!
+ \fn QGenericMatrix<N, M, T>& QGenericMatrix::operator/=(T divisor)
+
+ Divides all elements of this matrix by \a divisor.
+*/
+
+/*!
+ \fn bool QGenericMatrix::operator==(const QGenericMatrix<N, M, T>& other) const
+
+ Returns true if this matrix is identical to \a other; false otherwise.
+*/
+
+/*!
+ \fn bool QGenericMatrix::operator!=(const QGenericMatrix<N, M, T>& other) const
+
+ Returns true if this matrix is not identical to \a other; false otherwise.
+*/
+
+/*!
+ \fn QGenericMatrix<N, M, T> operator+(const QGenericMatrix<N, M, T>& m1, const QGenericMatrix<N, M, T>& m2)
+ \relates QGenericMatrix
+
+ Returns the sum of \a m1 and \a m2.
+*/
+
+/*!
+ \fn QGenericMatrix<N, M, T> operator-(const QGenericMatrix<N, M, T>& m1, const QGenericMatrix<N, M, T>& m2)
+ \relates QGenericMatrix
+
+ Returns the difference of \a m1 and \a m2.
+*/
+
+/*!
+ \fn QGenericMatrix<M1, M2, T> operator*(const QGenericMatrix<N, M2, T>& m1, const QGenericMatrix<M1, N, T>& m2)
+ \relates QGenericMatrix
+
+ Returns the product of the NxM2 matrix \a m1 and the M1xN matrix \a m2
+ to produce a M1xM2 matrix result.
+*/
+
+/*!
+ \fn QGenericMatrix<N, M, T> operator-(const QGenericMatrix<N, M, T>& matrix)
+ \overload
+ \relates QGenericMatrix
+
+ Returns the negation of \a matrix.
+*/
+
+/*!
+ \fn QGenericMatrix<N, M, T> operator*(T factor, const QGenericMatrix<N, M, T>& matrix)
+ \relates QGenericMatrix
+
+ Returns the result of multiplying all elements of \a matrix by \a factor.
+*/
+
+/*!
+ \fn QGenericMatrix<N, M, T> operator*(const QGenericMatrix<N, M, T>& matrix, T factor)
+ \relates QGenericMatrix
+
+ Returns the result of multiplying all elements of \a matrix by \a factor.
+*/
+
+/*!
+ \fn QGenericMatrix<N, M, T> operator/(const QGenericMatrix<N, M, T>& matrix, T divisor)
+ \relates QGenericMatrix
+
+ Returns the result of dividing all elements of \a matrix by \a divisor.
+*/
+
+/*!
+ \fn void QGenericMatrix::copyDataTo(T *values) const
+
+ Retrieves the N * M items in this matrix and copies them to \a values
+ in row-major order.
+*/
+
+/*!
+ \fn T *QGenericMatrix::data()
+
+ Returns a pointer to the raw data of this matrix.
+
+ \sa constData()
+*/
+
+/*!
+ \fn const T *QGenericMatrix::data() const
+
+ Returns a constant pointer to the raw data of this matrix.
+
+ \sa constData()
+*/
+
+/*!
+ \fn const T *QGenericMatrix::constData() const
+
+ Returns a constant pointer to the raw data of this matrix.
+
+ \sa data()
+*/
+
+#ifndef QT_NO_DATASTREAM
+
+/*!
+ \fn QDataStream &operator<<(QDataStream &stream, const QGenericMatrix<N, M, T> &matrix)
+ \relates QGenericMatrix
+
+ Writes the given \a matrix to the given \a stream and returns a
+ reference to the stream.
+
+ \sa {Serializing Qt Data Types}
+*/
+
+/*!
+ \fn QDataStream &operator>>(QDataStream &stream, QGenericMatrix<N, M, T> &matrix)
+ \relates QGenericMatrix
+
+ Reads a NxM matrix from the given \a stream into the given \a matrix
+ and returns a reference to the stream.
+
+ \sa {Serializing Qt Data Types}
+*/
+
+#endif
+
+/*!
+ \typedef QMatrix2x2
+ \relates QGenericMatrix
+
+ The QMatrix2x2 type defines a convenient instantiation of the
+ QGenericMatrix template for 2 columns, 2 rows, and qreal as
+ the element type.
+*/
+
+/*!
+ \typedef QMatrix2x3
+ \relates QGenericMatrix
+
+ The QMatrix2x3 type defines a convenient instantiation of the
+ QGenericMatrix template for 2 columns, 3 rows, and qreal as
+ the element type.
+*/
+
+/*!
+ \typedef QMatrix2x4
+ \relates QGenericMatrix
+
+ The QMatrix2x4 type defines a convenient instantiation of the
+ QGenericMatrix template for 2 columns, 4 rows, and qreal as
+ the element type.
+*/
+
+/*!
+ \typedef QMatrix3x2
+ \relates QGenericMatrix
+
+ The QMatrix3x2 type defines a convenient instantiation of the
+ QGenericMatrix template for 3 columns, 2 rows, and qreal as
+ the element type.
+*/
+
+/*!
+ \typedef QMatrix3x3
+ \relates QGenericMatrix
+
+ The QMatrix3x3 type defines a convenient instantiation of the
+ QGenericMatrix template for 3 columns, 3 rows, and qreal as
+ the element type.
+*/
+
+/*!
+ \typedef QMatrix3x4
+ \relates QGenericMatrix
+
+ The QMatrix3x4 type defines a convenient instantiation of the
+ QGenericMatrix template for 3 columns, 4 rows, and qreal as
+ the element type.
+*/
+
+/*!
+ \typedef QMatrix4x2
+ \relates QGenericMatrix
+
+ The QMatrix4x2 type defines a convenient instantiation of the
+ QGenericMatrix template for 4 columns, 2 rows, and qreal as
+ the element type.
+*/
+
+/*!
+ \typedef QMatrix4x3
+ \relates QGenericMatrix
+
+ The QMatrix4x3 type defines a convenient instantiation of the
+ QGenericMatrix template for 4 columns, 3 rows, and qreal as
+ the element type.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/gui/math3d/qgenericmatrix.h b/src/gui/math3d/qgenericmatrix.h
new file mode 100644
index 0000000000..181eda8e27
--- /dev/null
+++ b/src/gui/math3d/qgenericmatrix.h
@@ -0,0 +1,407 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGENERICMATRIX_H
+#define QGENERICMATRIX_H
+
+#include <QtCore/qmetatype.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qdatastream.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+template <int N, int M, typename T>
+class QGenericMatrix
+{
+public:
+ QGenericMatrix();
+ QGenericMatrix(const QGenericMatrix<N, M, T>& other);
+ explicit QGenericMatrix(const T *values);
+
+ const T& operator()(int row, int column) const;
+ T& operator()(int row, int column);
+
+ bool isIdentity() const;
+ void setToIdentity();
+
+ void fill(T value);
+
+ QGenericMatrix<M, N, T> transposed() const;
+
+ QGenericMatrix<N, M, T>& operator+=(const QGenericMatrix<N, M, T>& other);
+ QGenericMatrix<N, M, T>& operator-=(const QGenericMatrix<N, M, T>& other);
+ QGenericMatrix<N, M, T>& operator*=(T factor);
+ QGenericMatrix<N, M, T>& operator/=(T divisor);
+ bool operator==(const QGenericMatrix<N, M, T>& other) const;
+ bool operator!=(const QGenericMatrix<N, M, T>& other) const;
+
+ void copyDataTo(T *values) const;
+
+ T *data() { return *m; }
+ const T *data() const { return *m; }
+ const T *constData() const { return *m; }
+
+#if !defined(Q_NO_TEMPLATE_FRIENDS)
+ template<int NN, int MM, typename TT>
+ friend QGenericMatrix<NN, MM, TT> operator+(const QGenericMatrix<NN, MM, TT>& m1, const QGenericMatrix<NN, MM, TT>& m2);
+ template<int NN, int MM, typename TT>
+ friend QGenericMatrix<NN, MM, TT> operator-(const QGenericMatrix<NN, MM, TT>& m1, const QGenericMatrix<NN, MM, TT>& m2);
+ template<int NN, int M1, int M2, typename TT>
+ friend QGenericMatrix<M1, M2, TT> operator*(const QGenericMatrix<NN, M2, TT>& m1, const QGenericMatrix<M1, NN, TT>& m2);
+ template<int NN, int MM, typename TT>
+ friend QGenericMatrix<NN, MM, TT> operator-(const QGenericMatrix<NN, MM, TT>& matrix);
+ template<int NN, int MM, typename TT>
+ friend QGenericMatrix<NN, MM, TT> operator*(TT factor, const QGenericMatrix<NN, MM, TT>& matrix);
+ template<int NN, int MM, typename TT>
+ friend QGenericMatrix<NN, MM, TT> operator*(const QGenericMatrix<NN, MM, TT>& matrix, TT factor);
+ template<int NN, int MM, typename TT>
+ friend QGenericMatrix<NN, MM, TT> operator/(const QGenericMatrix<NN, MM, TT>& matrix, TT divisor);
+
+private:
+#endif
+ T m[N][M]; // Column-major order to match OpenGL.
+
+ QGenericMatrix(int) {} // Construct without initializing identity matrix.
+
+#if !defined(Q_NO_TEMPLATE_FRIENDS)
+ template <int NN, int MM, typename TT>
+ friend class QGenericMatrix;
+#endif
+};
+
+template <int N, int M, typename T>
+Q_INLINE_TEMPLATE QGenericMatrix<N, M, T>::QGenericMatrix()
+{
+ setToIdentity();
+}
+
+template <int N, int M, typename T>
+Q_INLINE_TEMPLATE QGenericMatrix<N, M, T>::QGenericMatrix(const QGenericMatrix<N, M, T>& other)
+{
+ for (int col = 0; col < N; ++col)
+ for (int row = 0; row < M; ++row)
+ m[col][row] = other.m[col][row];
+}
+
+template <int N, int M, typename T>
+Q_OUTOFLINE_TEMPLATE QGenericMatrix<N, M, T>::QGenericMatrix(const T *values)
+{
+ for (int col = 0; col < N; ++col)
+ for (int row = 0; row < M; ++row)
+ m[col][row] = values[row * N + col];
+}
+
+template <int N, int M, typename T>
+Q_INLINE_TEMPLATE const T& QGenericMatrix<N, M, T>::operator()(int row, int column) const
+{
+ Q_ASSERT(row >= 0 && row < M && column >= 0 && column < N);
+ return m[column][row];
+}
+
+template <int N, int M, typename T>
+Q_INLINE_TEMPLATE T& QGenericMatrix<N, M, T>::operator()(int row, int column)
+{
+ Q_ASSERT(row >= 0 && row < M && column >= 0 && column < N);
+ return m[column][row];
+}
+
+template <int N, int M, typename T>
+Q_OUTOFLINE_TEMPLATE bool QGenericMatrix<N, M, T>::isIdentity() const
+{
+ for (int col = 0; col < N; ++col) {
+ for (int row = 0; row < M; ++row) {
+ if (row == col) {
+ if (m[col][row] != 1.0f)
+ return false;
+ } else {
+ if (m[col][row] != 0.0f)
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+template <int N, int M, typename T>
+Q_OUTOFLINE_TEMPLATE void QGenericMatrix<N, M, T>::setToIdentity()
+{
+ for (int col = 0; col < N; ++col) {
+ for (int row = 0; row < M; ++row) {
+ if (row == col)
+ m[col][row] = 1.0f;
+ else
+ m[col][row] = 0.0f;
+ }
+ }
+}
+
+template <int N, int M, typename T>
+Q_OUTOFLINE_TEMPLATE void QGenericMatrix<N, M, T>::fill(T value)
+{
+ for (int col = 0; col < N; ++col)
+ for (int row = 0; row < M; ++row)
+ m[col][row] = value;
+}
+
+template <int N, int M, typename T>
+Q_OUTOFLINE_TEMPLATE QGenericMatrix<M, N, T> QGenericMatrix<N, M, T>::transposed() const
+{
+ QGenericMatrix<M, N, T> result(1);
+ for (int row = 0; row < M; ++row)
+ for (int col = 0; col < N; ++col)
+ result.m[row][col] = m[col][row];
+ return result;
+}
+
+template <int N, int M, typename T>
+Q_OUTOFLINE_TEMPLATE QGenericMatrix<N, M, T>& QGenericMatrix<N, M, T>::operator+=(const QGenericMatrix<N, M, T>& other)
+{
+ for (int row = 0; row < M; ++row)
+ for (int col = 0; col < N; ++col)
+ m[col][row] += other.m[col][row];
+ return *this;
+}
+
+template <int N, int M, typename T>
+Q_OUTOFLINE_TEMPLATE QGenericMatrix<N, M, T>& QGenericMatrix<N, M, T>::operator-=(const QGenericMatrix<N, M, T>& other)
+{
+ for (int row = 0; row < M; ++row)
+ for (int col = 0; col < N; ++col)
+ m[col][row] -= other.m[col][row];
+ return *this;
+}
+
+template <int N, int M, typename T>
+Q_OUTOFLINE_TEMPLATE QGenericMatrix<N, M, T>& QGenericMatrix<N, M, T>::operator*=(T factor)
+{
+ for (int row = 0; row < M; ++row)
+ for (int col = 0; col < N; ++col)
+ m[col][row] *= factor;
+ return *this;
+}
+
+template <int N, int M, typename T>
+Q_OUTOFLINE_TEMPLATE bool QGenericMatrix<N, M, T>::operator==(const QGenericMatrix<N, M, T>& other) const
+{
+ for (int row = 0; row < M; ++row)
+ for (int col = 0; col < N; ++col) {
+ if (m[col][row] != other.m[col][row])
+ return false;
+ }
+ return true;
+}
+
+template <int N, int M, typename T>
+Q_OUTOFLINE_TEMPLATE bool QGenericMatrix<N, M, T>::operator!=(const QGenericMatrix<N, M, T>& other) const
+{
+ for (int row = 0; row < M; ++row)
+ for (int col = 0; col < N; ++col) {
+ if (m[col][row] != other.m[col][row])
+ return true;
+ }
+ return false;
+}
+
+template <int N, int M, typename T>
+Q_OUTOFLINE_TEMPLATE QGenericMatrix<N, M, T>& QGenericMatrix<N, M, T>::operator/=(T divisor)
+{
+ for (int row = 0; row < M; ++row)
+ for (int col = 0; col < N; ++col)
+ m[col][row] /= divisor;
+ return *this;
+}
+
+template <int N, int M, typename T>
+Q_OUTOFLINE_TEMPLATE QGenericMatrix<N, M, T> operator+(const QGenericMatrix<N, M, T>& m1, const QGenericMatrix<N, M, T>& m2)
+{
+ QGenericMatrix<N, M, T> result(1);
+ for (int row = 0; row < M; ++row)
+ for (int col = 0; col < N; ++col)
+ result.m[col][row] = m1.m[col][row] + m2.m[col][row];
+ return result;
+}
+
+template <int N, int M, typename T>
+Q_OUTOFLINE_TEMPLATE QGenericMatrix<N, M, T> operator-(const QGenericMatrix<N, M, T>& m1, const QGenericMatrix<N, M, T>& m2)
+{
+ QGenericMatrix<N, M, T> result(1);
+ for (int row = 0; row < M; ++row)
+ for (int col = 0; col < N; ++col)
+ result.m[col][row] = m1.m[col][row] - m2.m[col][row];
+ return result;
+}
+
+template <int N, int M1, int M2, typename T>
+Q_OUTOFLINE_TEMPLATE QGenericMatrix<M1, M2, T> operator*(const QGenericMatrix<N, M2, T>& m1, const QGenericMatrix<M1, N, T>& m2)
+{
+ QGenericMatrix<M1, M2, T> result(1);
+ for (int row = 0; row < M2; ++row) {
+ for (int col = 0; col < M1; ++col) {
+ T sum(0.0f);
+ for (int j = 0; j < N; ++j)
+ sum += m1.m[j][row] * m2.m[col][j];
+ result.m[col][row] = sum;
+ }
+ }
+ return result;
+}
+
+template <int N, int M, typename T>
+Q_OUTOFLINE_TEMPLATE QGenericMatrix<N, M, T> operator-(const QGenericMatrix<N, M, T>& matrix)
+{
+ QGenericMatrix<N, M, T> result(1);
+ for (int row = 0; row < M; ++row)
+ for (int col = 0; col < N; ++col)
+ result.m[col][row] = -matrix.m[col][row];
+ return result;
+}
+
+template <int N, int M, typename T>
+Q_OUTOFLINE_TEMPLATE QGenericMatrix<N, M, T> operator*(T factor, const QGenericMatrix<N, M, T>& matrix)
+{
+ QGenericMatrix<N, M, T> result(1);
+ for (int row = 0; row < M; ++row)
+ for (int col = 0; col < N; ++col)
+ result.m[col][row] = matrix.m[col][row] * factor;
+ return result;
+}
+
+template <int N, int M, typename T>
+Q_OUTOFLINE_TEMPLATE QGenericMatrix<N, M, T> operator*(const QGenericMatrix<N, M, T>& matrix, T factor)
+{
+ QGenericMatrix<N, M, T> result(1);
+ for (int row = 0; row < M; ++row)
+ for (int col = 0; col < N; ++col)
+ result.m[col][row] = matrix.m[col][row] * factor;
+ return result;
+}
+
+template <int N, int M, typename T>
+Q_OUTOFLINE_TEMPLATE QGenericMatrix<N, M, T> operator/(const QGenericMatrix<N, M, T>& matrix, T divisor)
+{
+ QGenericMatrix<N, M, T> result(1);
+ for (int row = 0; row < M; ++row)
+ for (int col = 0; col < N; ++col)
+ result.m[col][row] = matrix.m[col][row] / divisor;
+ return result;
+}
+
+template <int N, int M, typename T>
+Q_OUTOFLINE_TEMPLATE void QGenericMatrix<N, M, T>::copyDataTo(T *values) const
+{
+ for (int col = 0; col < N; ++col)
+ for (int row = 0; row < M; ++row)
+ values[row * N + col] = T(m[col][row]);
+}
+
+// Define aliases for the useful variants of QGenericMatrix.
+typedef QGenericMatrix<2, 2, qreal> QMatrix2x2;
+typedef QGenericMatrix<2, 3, qreal> QMatrix2x3;
+typedef QGenericMatrix<2, 4, qreal> QMatrix2x4;
+typedef QGenericMatrix<3, 2, qreal> QMatrix3x2;
+typedef QGenericMatrix<3, 3, qreal> QMatrix3x3;
+typedef QGenericMatrix<3, 4, qreal> QMatrix3x4;
+typedef QGenericMatrix<4, 2, qreal> QMatrix4x2;
+typedef QGenericMatrix<4, 3, qreal> QMatrix4x3;
+
+#ifndef QT_NO_DEBUG_STREAM
+
+template <int N, int M, typename T>
+QDebug operator<<(QDebug dbg, const QGenericMatrix<N, M, T> &m)
+{
+ dbg.nospace() << "QGenericMatrix<" << N << ", " << M
+ << ", " << QTypeInfo<T>::name()
+ << ">(" << endl << qSetFieldWidth(10);
+ for (int row = 0; row < M; ++row) {
+ for (int col = 0; col < N; ++col)
+ dbg << m(row, col);
+ dbg << endl;
+ }
+ dbg << qSetFieldWidth(0) << ')';
+ return dbg.space();
+}
+
+#endif
+
+#ifndef QT_NO_DATASTREAM
+
+template <int N, int M, typename T>
+QDataStream &operator<<(QDataStream &stream, const QGenericMatrix<N, M, T> &matrix)
+{
+ for (int row = 0; row < M; ++row)
+ for (int col = 0; col < N; ++col)
+ stream << double(matrix(row, col));
+ return stream;
+}
+
+template <int N, int M, typename T>
+QDataStream &operator>>(QDataStream &stream, QGenericMatrix<N, M, T> &matrix)
+{
+ double x;
+ for (int row = 0; row < M; ++row) {
+ for (int col = 0; col < N; ++col) {
+ stream >> x;
+ matrix(row, col) = T(x);
+ }
+ }
+ return stream;
+}
+
+#endif
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QMatrix2x2)
+Q_DECLARE_METATYPE(QMatrix2x3)
+Q_DECLARE_METATYPE(QMatrix2x4)
+Q_DECLARE_METATYPE(QMatrix3x2)
+Q_DECLARE_METATYPE(QMatrix3x3)
+Q_DECLARE_METATYPE(QMatrix3x4)
+Q_DECLARE_METATYPE(QMatrix4x2)
+Q_DECLARE_METATYPE(QMatrix4x3)
+
+QT_END_HEADER
+
+#endif
diff --git a/src/gui/math3d/qmatrix4x4.cpp b/src/gui/math3d/qmatrix4x4.cpp
new file mode 100644
index 0000000000..c18dd3c29d
--- /dev/null
+++ b/src/gui/math3d/qmatrix4x4.cpp
@@ -0,0 +1,1915 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qmatrix4x4.h"
+#include <QtCore/qmath.h>
+#include <QtCore/qvariant.h>
+#include <QtGui/qmatrix.h>
+#include <QtGui/qtransform.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_MATRIX4X4
+
+/*!
+ \class QMatrix4x4
+ \brief The QMatrix4x4 class represents a 4x4 transformation matrix in 3D space.
+ \since 4.6
+ \ingroup painting-3D
+
+ \sa QVector3D, QGenericMatrix
+*/
+
+static const qreal inv_dist_to_plane = 1. / 1024.;
+
+/*!
+ \fn QMatrix4x4::QMatrix4x4()
+
+ Constructs an identity matrix.
+*/
+
+/*!
+ Constructs a matrix from the given 16 floating-point \a values.
+ The contents of the array \a values is assumed to be in
+ row-major order.
+
+ If the matrix has a special type (identity, translate, scale, etc),
+ the programmer should follow this constructor with a call to
+ optimize() if they wish QMatrix4x4 to optimize further
+ calls to translate(), scale(), etc.
+
+ \sa copyDataTo(), optimize()
+*/
+QMatrix4x4::QMatrix4x4(const qreal *values)
+{
+ for (int row = 0; row < 4; ++row)
+ for (int col = 0; col < 4; ++col)
+ m[col][row] = values[row * 4 + col];
+ flagBits = General;
+}
+
+/*!
+ \fn QMatrix4x4::QMatrix4x4(qreal m11, qreal m12, qreal m13, qreal m14, qreal m21, qreal m22, qreal m23, qreal m24, qreal m31, qreal m32, qreal m33, qreal m34, qreal m41, qreal m42, qreal m43, qreal m44)
+
+ Constructs a matrix from the 16 elements \a m11, \a m12, \a m13, \a m14,
+ \a m21, \a m22, \a m23, \a m24, \a m31, \a m32, \a m33, \a m34,
+ \a m41, \a m42, \a m43, and \a m44. The elements are specified in
+ row-major order.
+
+ If the matrix has a special type (identity, translate, scale, etc),
+ the programmer should follow this constructor with a call to
+ optimize() if they wish QMatrix4x4 to optimize further
+ calls to translate(), scale(), etc.
+
+ \sa optimize()
+*/
+
+/*!
+ \fn QMatrix4x4::QMatrix4x4(const QGenericMatrix<N, M, qreal>& matrix)
+
+ Constructs a 4x4 matrix from the left-most 4 columns and top-most
+ 4 rows of \a matrix. If \a matrix has less than 4 columns or rows,
+ the remaining elements are filled with elements from the identity
+ matrix.
+
+ \sa toGenericMatrix()
+*/
+
+/*!
+ \fn QGenericMatrix<N, M, qreal> QMatrix4x4::toGenericMatrix() const
+
+ Constructs a NxM generic matrix from the left-most N columns and
+ top-most M rows of this 4x4 matrix. If N or M is greater than 4,
+ then the remaining elements are filled with elements from the
+ identity matrix.
+*/
+
+/*!
+ \fn QMatrix4x4 qGenericMatrixToMatrix4x4(const QGenericMatrix<N, M, qreal>& matrix)
+ \relates QMatrix4x4
+ \obsolete
+
+ Returns a 4x4 matrix constructed from the left-most 4 columns and
+ top-most 4 rows of \a matrix. If \a matrix has less than 4 columns
+ or rows, the remaining elements are filled with elements from the
+ identity matrix.
+
+ \sa QMatrix4x4(const QGenericMatrix &)
+*/
+
+/*!
+ \fn QGenericMatrix<N, M, qreal> qGenericMatrixFromMatrix4x4(const QMatrix4x4& matrix)
+ \relates QMatrix4x4
+ \obsolete
+
+ Returns a NxM generic matrix constructed from the left-most N columns
+ and top-most M rows of \a matrix. If N or M is greater than 4,
+ then the remaining elements are filled with elements from the
+ identity matrix.
+
+ \sa QMatrix4x4::toGenericMatrix()
+*/
+
+/*!
+ \internal
+*/
+QMatrix4x4::QMatrix4x4(const qreal *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.0f;
+ else
+ m[col][row] = 0.0f;
+ }
+ }
+ flagBits = General;
+}
+
+/*!
+ Constructs a 4x4 matrix from a conventional Qt 2D affine
+ transformation \a matrix.
+
+ If \a matrix has a special type (identity, translate, scale, etc),
+ the programmer should follow this constructor with a call to
+ optimize() if they wish QMatrix4x4 to optimize further
+ calls to translate(), scale(), etc.
+
+ \sa toAffine(), optimize()
+*/
+QMatrix4x4::QMatrix4x4(const QMatrix& matrix)
+{
+ m[0][0] = matrix.m11();
+ m[0][1] = matrix.m12();
+ m[0][2] = 0.0f;
+ m[0][3] = 0.0f;
+ m[1][0] = matrix.m21();
+ m[1][1] = matrix.m22();
+ m[1][2] = 0.0f;
+ m[1][3] = 0.0f;
+ m[2][0] = 0.0f;
+ m[2][1] = 0.0f;
+ m[2][2] = 1.0f;
+ m[2][3] = 0.0f;
+ m[3][0] = matrix.dx();
+ m[3][1] = matrix.dy();
+ m[3][2] = 0.0f;
+ m[3][3] = 1.0f;
+ flagBits = General;
+}
+
+/*!
+ Constructs a 4x4 matrix from the conventional Qt 2D
+ transformation matrix \a transform.
+
+ If \a transform has a special type (identity, translate, scale, etc),
+ the programmer should follow this constructor with a call to
+ optimize() if they wish QMatrix4x4 to optimize further
+ calls to translate(), scale(), etc.
+
+ \sa toTransform(), optimize()
+*/
+QMatrix4x4::QMatrix4x4(const QTransform& transform)
+{
+ m[0][0] = transform.m11();
+ m[0][1] = transform.m12();
+ m[0][2] = 0.0f;
+ m[0][3] = transform.m13();
+ m[1][0] = transform.m21();
+ m[1][1] = transform.m22();
+ m[1][2] = 0.0f;
+ m[1][3] = transform.m23();
+ m[2][0] = 0.0f;
+ m[2][1] = 0.0f;
+ m[2][2] = 1.0f;
+ m[2][3] = 0.0f;
+ m[3][0] = transform.dx();
+ m[3][1] = transform.dy();
+ m[3][2] = 0.0f;
+ m[3][3] = transform.m33();
+ flagBits = General;
+}
+
+/*!
+ \fn const qreal& QMatrix4x4::operator()(int row, int column) const
+
+ Returns a constant reference to the element at position
+ (\a row, \a column) in this matrix.
+
+ \sa column(), row()
+*/
+
+/*!
+ \fn qreal& QMatrix4x4::operator()(int row, int column)
+
+ Returns a reference to the element at position (\a row, \a column)
+ in this matrix so that the element can be assigned to.
+
+ \sa optimize(), setColumn(), setRow()
+*/
+
+/*!
+ \fn QVector4D QMatrix4x4::column(int index) const
+
+ Returns the elements of column \a index as a 4D vector.
+
+ \sa setColumn(), row()
+*/
+
+/*!
+ \fn void QMatrix4x4::setColumn(int index, const QVector4D& value)
+
+ Sets the elements of column \a index to the components of \a value.
+
+ \sa column(), setRow()
+*/
+
+/*!
+ \fn QVector4D QMatrix4x4::row(int index) const
+
+ Returns the elements of row \a index as a 4D vector.
+
+ \sa setRow(), column()
+*/
+
+/*!
+ \fn void QMatrix4x4::setRow(int index, const QVector4D& value)
+
+ Sets the elements of row \a index to the components of \a value.
+
+ \sa row(), setColumn()
+*/
+
+/*!
+ \fn bool QMatrix4x4::isIdentity() const
+
+ Returns true if this matrix is the identity; false otherwise.
+
+ \sa setToIdentity()
+*/
+
+/*!
+ \fn void QMatrix4x4::setToIdentity()
+
+ Sets this matrix to the identity.
+
+ \sa isIdentity()
+*/
+
+/*!
+ \fn void QMatrix4x4::fill(qreal value)
+
+ Fills all elements of this matrx with \a value.
+*/
+
+// The 4x4 matrix inverse algorithm is based on that described at:
+// http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q24
+// Some optimization has been done to avoid making copies of 3x3
+// sub-matrices and to unroll the loops.
+
+// Calculate the determinant of a 3x3 sub-matrix.
+// | A B C |
+// M = | D E F | det(M) = A * (EI - HF) - B * (DI - GF) + C * (DH - GE)
+// | G H I |
+static inline qreal matrixDet3
+ (const qreal m[4][4], int col0, int col1, int col2,
+ int row0, int row1, int row2)
+{
+ return m[col0][row0] *
+ (m[col1][row1] * m[col2][row2] -
+ m[col1][row2] * m[col2][row1]) -
+ m[col1][row0] *
+ (m[col0][row1] * m[col2][row2] -
+ m[col0][row2] * m[col2][row1]) +
+ m[col2][row0] *
+ (m[col0][row1] * m[col1][row2] -
+ m[col0][row2] * m[col1][row1]);
+}
+
+// Calculate the determinant of a 4x4 matrix.
+static inline qreal matrixDet4(const qreal m[4][4])
+{
+ qreal 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;
+}
+
+/*!
+ Returns the determinant of this matrix.
+*/
+qreal QMatrix4x4::determinant() const
+{
+ return qreal(matrixDet4(m));
+}
+
+/*!
+ Returns the inverse of this matrix. Returns the identity if
+ this matrix cannot be inverted; i.e. determinant() is zero.
+ If \a invertible is not null, then true will be written to
+ that location if the matrix can be inverted; false otherwise.
+
+ If the matrix is recognized as the identity or an orthonormal
+ matrix, then this function will quickly invert the matrix
+ using optimized routines.
+
+ \sa determinant(), normalMatrix()
+*/
+QMatrix4x4 QMatrix4x4::inverted(bool *invertible) const
+{
+ // Handle some of the easy cases first.
+ if (flagBits == Identity) {
+ if (invertible)
+ *invertible = true;
+ return QMatrix4x4();
+ } else if (flagBits == Translation) {
+ QMatrix4x4 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 == Rotation || flagBits == (Rotation | Translation)) {
+ if (invertible)
+ *invertible = true;
+ return orthonormalInverse();
+ }
+
+ QMatrix4x4 inv(1); // The "1" says to not load the identity.
+
+ qreal det = matrixDet4(m);
+ if (det == 0.0f) {
+ if (invertible)
+ *invertible = false;
+ return QMatrix4x4();
+ }
+ det = 1.0f / 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;
+
+ if (invertible)
+ *invertible = true;
+ return inv;
+}
+
+/*!
+ Returns the normal matrix corresponding to this 4x4 transformation.
+ The normal matrix is the transpose of the inverse of the top-left
+ 3x3 part of this 4x4 matrix. If the 3x3 sub-matrix is not invertible,
+ this function returns the identity.
+
+ \sa inverted()
+*/
+QMatrix3x3 QMatrix4x4::normalMatrix() const
+{
+ QMatrix3x3 inv;
+
+ // Handle the simple cases first.
+ if (flagBits == Identity || flagBits == Translation) {
+ return inv;
+ } else if (flagBits == Scale || flagBits == (Translation | Scale)) {
+ if (m[0][0] == 0.0f || m[1][1] == 0.0f || m[2][2] == 0.0f)
+ return inv;
+ inv.data()[0] = 1.0f / m[0][0];
+ inv.data()[4] = 1.0f / m[1][1];
+ inv.data()[8] = 1.0f / m[2][2];
+ return inv;
+ }
+
+ qreal det = matrixDet3(m, 0, 1, 2, 0, 1, 2);
+ if (det == 0.0f)
+ return inv;
+ det = 1.0f / det;
+
+ qreal *invm = inv.data();
+
+ // Invert and transpose in a single step.
+ invm[0 + 0 * 3] = (m[1][1] * m[2][2] - m[2][1] * m[1][2]) * det;
+ invm[1 + 0 * 3] = -(m[1][0] * m[2][2] - m[1][2] * m[2][0]) * det;
+ invm[2 + 0 * 3] = (m[1][0] * m[2][1] - m[1][1] * m[2][0]) * det;
+ invm[0 + 1 * 3] = -(m[0][1] * m[2][2] - m[2][1] * m[0][2]) * det;
+ invm[1 + 1 * 3] = (m[0][0] * m[2][2] - m[0][2] * m[2][0]) * det;
+ invm[2 + 1 * 3] = -(m[0][0] * m[2][1] - m[0][1] * m[2][0]) * det;
+ invm[0 + 2 * 3] = (m[0][1] * m[1][2] - m[0][2] * m[1][1]) * det;
+ invm[1 + 2 * 3] = -(m[0][0] * m[1][2] - m[0][2] * m[1][0]) * det;
+ invm[2 + 2 * 3] = (m[0][0] * m[1][1] - m[1][0] * m[0][1]) * det;
+
+ return inv;
+}
+
+/*!
+ Returns this matrix, transposed about its diagonal.
+*/
+QMatrix4x4 QMatrix4x4::transposed() const
+{
+ QMatrix4x4 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];
+ }
+ }
+ return result;
+}
+
+/*!
+ \fn QMatrix4x4& QMatrix4x4::operator+=(const QMatrix4x4& other)
+
+ Adds the contents of \a other to this matrix.
+*/
+
+/*!
+ \fn QMatrix4x4& QMatrix4x4::operator-=(const QMatrix4x4& other)
+
+ Subtracts the contents of \a other from this matrix.
+*/
+
+/*!
+ \fn QMatrix4x4& QMatrix4x4::operator*=(const QMatrix4x4& other)
+
+ Multiplies the contents of \a other by this matrix.
+*/
+
+/*!
+ \fn QMatrix4x4& QMatrix4x4::operator*=(qreal factor)
+ \overload
+
+ Multiplies all elements of this matrix by \a factor.
+*/
+
+/*!
+ \overload
+
+ Divides all elements of this matrix by \a divisor.
+*/
+QMatrix4x4& QMatrix4x4::operator/=(qreal 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;
+}
+
+/*!
+ \fn bool QMatrix4x4::operator==(const QMatrix4x4& other) const
+
+ Returns true if this matrix is identical to \a other; false otherwise.
+ This operator uses an exact floating-point comparison.
+*/
+
+/*!
+ \fn bool QMatrix4x4::operator!=(const QMatrix4x4& other) const
+
+ Returns true if this matrix is not identical to \a other; false otherwise.
+ This operator uses an exact floating-point comparison.
+*/
+
+/*!
+ \fn QMatrix4x4 operator+(const QMatrix4x4& m1, const QMatrix4x4& m2)
+ \relates QMatrix4x4
+
+ Returns the sum of \a m1 and \a m2.
+*/
+
+/*!
+ \fn QMatrix4x4 operator-(const QMatrix4x4& m1, const QMatrix4x4& m2)
+ \relates QMatrix4x4
+
+ Returns the difference of \a m1 and \a m2.
+*/
+
+/*!
+ \fn QMatrix4x4 operator*(const QMatrix4x4& m1, const QMatrix4x4& m2)
+ \relates QMatrix4x4
+
+ Returns the product of \a m1 and \a m2.
+*/
+
+#ifndef QT_NO_VECTOR3D
+
+/*!
+ \fn QVector3D operator*(const QVector3D& vector, const QMatrix4x4& matrix)
+ \relates QMatrix4x4
+
+ Returns the result of transforming \a vector according to \a matrix,
+ with the matrix applied post-vector.
+*/
+
+/*!
+ \fn QVector3D operator*(const QMatrix4x4& matrix, const QVector3D& vector)
+ \relates QMatrix4x4
+
+ Returns the result of transforming \a vector according to \a matrix,
+ with the matrix applied pre-vector.
+*/
+
+#endif
+
+#ifndef QT_NO_VECTOR4D
+
+/*!
+ \fn QVector4D operator*(const QVector4D& vector, const QMatrix4x4& matrix)
+ \relates QMatrix4x4
+
+ Returns the result of transforming \a vector according to \a matrix,
+ with the matrix applied post-vector.
+*/
+
+/*!
+ \fn QVector4D operator*(const QMatrix4x4& matrix, const QVector4D& vector)
+ \relates QMatrix4x4
+
+ Returns the result of transforming \a vector according to \a matrix,
+ with the matrix applied pre-vector.
+*/
+
+#endif
+
+/*!
+ \fn QPoint operator*(const QPoint& point, const QMatrix4x4& matrix)
+ \relates QMatrix4x4
+
+ Returns the result of transforming \a point according to \a matrix,
+ with the matrix applied post-point.
+*/
+
+/*!
+ \fn QPointF operator*(const QPointF& point, const QMatrix4x4& matrix)
+ \relates QMatrix4x4
+
+ Returns the result of transforming \a point according to \a matrix,
+ with the matrix applied post-point.
+*/
+
+/*!
+ \fn QPoint operator*(const QMatrix4x4& matrix, const QPoint& point)
+ \relates QMatrix4x4
+
+ Returns the result of transforming \a point according to \a matrix,
+ with the matrix applied pre-point.
+*/
+
+/*!
+ \fn QPointF operator*(const QMatrix4x4& matrix, const QPointF& point)
+ \relates QMatrix4x4
+
+ Returns the result of transforming \a point according to \a matrix,
+ with the matrix applied pre-point.
+*/
+
+/*!
+ \fn QMatrix4x4 operator-(const QMatrix4x4& matrix)
+ \overload
+ \relates QMatrix4x4
+
+ Returns the negation of \a matrix.
+*/
+
+/*!
+ \fn QMatrix4x4 operator*(qreal factor, const QMatrix4x4& matrix)
+ \relates QMatrix4x4
+
+ Returns the result of multiplying all elements of \a matrix by \a factor.
+*/
+
+/*!
+ \fn QMatrix4x4 operator*(const QMatrix4x4& matrix, qreal factor)
+ \relates QMatrix4x4
+
+ Returns the result of multiplying all elements of \a matrix by \a factor.
+*/
+
+/*!
+ \relates QMatrix4x4
+
+ Returns the result of dividing all elements of \a matrix by \a divisor.
+*/
+QMatrix4x4 operator/(const QMatrix4x4& matrix, qreal divisor)
+{
+ QMatrix4x4 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;
+ return m;
+}
+
+/*!
+ \fn bool qFuzzyCompare(const QMatrix4x4& m1, const QMatrix4x4& m2)
+ \relates QMatrix4x4
+
+ Returns true if \a m1 and \a m2 are equal, allowing for a small
+ fuzziness factor for floating-point comparisons; false otherwise.
+*/
+
+#ifndef QT_NO_VECTOR3D
+
+/*!
+ Multiplies this matrix by another that scales coordinates by
+ the components of \a vector.
+
+ \sa translate(), rotate()
+*/
+void QMatrix4x4::scale(const QVector3D& vector)
+{
+ qreal vx = vector.x();
+ qreal vy = vector.y();
+ qreal vz = vector.z();
+ if (flagBits == Identity) {
+ m[0][0] = vx;
+ m[1][1] = vy;
+ m[2][2] = vz;
+ flagBits = Scale;
+ } else if (flagBits == Scale || flagBits == (Scale | Translation)) {
+ m[0][0] *= vx;
+ m[1][1] *= vy;
+ m[2][2] *= vz;
+ } else if (flagBits == Translation) {
+ m[0][0] = vx;
+ m[1][1] = vy;
+ m[2][2] = vz;
+ flagBits |= Scale;
+ } 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 = General;
+ }
+}
+#endif
+
+/*!
+ \overload
+
+ Multiplies this matrix by another that scales coordinates by the
+ components \a x, and \a y.
+
+ \sa translate(), rotate()
+*/
+void QMatrix4x4::scale(qreal x, qreal y)
+{
+ if (flagBits == Identity) {
+ m[0][0] = x;
+ m[1][1] = y;
+ flagBits = Scale;
+ } else if (flagBits == Scale || flagBits == (Scale | Translation)) {
+ m[0][0] *= x;
+ m[1][1] *= y;
+ } else if (flagBits == Translation) {
+ m[0][0] = x;
+ m[1][1] = y;
+ flagBits |= Scale;
+ } 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 = General;
+ }
+}
+
+/*!
+ \overload
+
+ Multiplies this matrix by another that scales coordinates by the
+ components \a x, \a y, and \a z.
+
+ \sa translate(), rotate()
+*/
+void QMatrix4x4::scale(qreal x, qreal y, qreal z)
+{
+ if (flagBits == Identity) {
+ m[0][0] = x;
+ m[1][1] = y;
+ m[2][2] = z;
+ flagBits = Scale;
+ } else if (flagBits == Scale || flagBits == (Scale | Translation)) {
+ m[0][0] *= x;
+ m[1][1] *= y;
+ m[2][2] *= z;
+ } else if (flagBits == Translation) {
+ m[0][0] = x;
+ m[1][1] = y;
+ m[2][2] = z;
+ flagBits |= Scale;
+ } 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 = General;
+ }
+}
+
+/*!
+ \overload
+
+ Multiplies this matrix by another that scales coordinates by the
+ given \a factor.
+
+ \sa translate(), rotate()
+*/
+void QMatrix4x4::scale(qreal factor)
+{
+ if (flagBits == Identity) {
+ m[0][0] = factor;
+ m[1][1] = factor;
+ m[2][2] = factor;
+ flagBits = Scale;
+ } else if (flagBits == Scale || flagBits == (Scale | Translation)) {
+ m[0][0] *= factor;
+ m[1][1] *= factor;
+ m[2][2] *= factor;
+ } else if (flagBits == Translation) {
+ m[0][0] = factor;
+ m[1][1] = factor;
+ m[2][2] = factor;
+ flagBits |= Scale;
+ } 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 = General;
+ }
+}
+
+#ifndef QT_NO_VECTOR3D
+/*!
+ Multiplies this matrix by another that translates coordinates by
+ the components of \a vector.
+
+ \sa scale(), rotate()
+*/
+void QMatrix4x4::translate(const QVector3D& vector)
+{
+ qreal vx = vector.x();
+ qreal vy = vector.y();
+ qreal vz = vector.z();
+ if (flagBits == Identity) {
+ m[3][0] = vx;
+ m[3][1] = vy;
+ m[3][2] = vz;
+ flagBits = Translation;
+ } 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;
+ flagBits |= Translation;
+ } else if (flagBits == (Scale | Translation)) {
+ m[3][0] += m[0][0] * vx;
+ m[3][1] += 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;
+ if (flagBits == Rotation)
+ flagBits |= Translation;
+ else if (flagBits != (Rotation | Translation))
+ flagBits = General;
+ }
+}
+
+#endif
+
+/*!
+ \overload
+
+ Multiplies this matrix by another that translates coordinates
+ by the components \a x, and \a y.
+
+ \sa scale(), rotate()
+*/
+void QMatrix4x4::translate(qreal x, qreal y)
+{
+ if (flagBits == Identity) {
+ m[3][0] = x;
+ m[3][1] = y;
+ flagBits = Translation;
+ } 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;
+ m[3][2] = 0.;
+ flagBits |= Translation;
+ } else if (flagBits == (Scale | Translation)) {
+ m[3][0] += m[0][0] * x;
+ m[3][1] += 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;
+ if (flagBits == Rotation)
+ flagBits |= Translation;
+ else if (flagBits != (Rotation | Translation))
+ flagBits = General;
+ }
+}
+
+/*!
+ \overload
+
+ Multiplies this matrix by another that translates coordinates
+ by the components \a x, \a y, and \a z.
+
+ \sa scale(), rotate()
+*/
+void QMatrix4x4::translate(qreal x, qreal y, qreal z)
+{
+ if (flagBits == Identity) {
+ m[3][0] = x;
+ m[3][1] = y;
+ m[3][2] = z;
+ flagBits = Translation;
+ } 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;
+ flagBits |= Translation;
+ } else if (flagBits == (Scale | Translation)) {
+ m[3][0] += m[0][0] * x;
+ m[3][1] += 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;
+ if (flagBits == Rotation)
+ flagBits |= Translation;
+ else if (flagBits != (Rotation | Translation))
+ flagBits = General;
+ }
+}
+
+#ifndef QT_NO_VECTOR3D
+
+/*!
+ Multiples this matrix by another that rotates coordinates through
+ \a angle degrees about \a vector.
+
+ \sa scale(), translate()
+*/
+void QMatrix4x4::rotate(qreal angle, const QVector3D& vector)
+{
+ rotate(angle, vector.x(), vector.y(), vector.z());
+}
+
+#endif
+
+/*!
+ \overload
+
+ Multiplies this matrix by another that rotates coordinates through
+ \a angle degrees about the vector (\a x, \a y, \a z).
+
+ \sa scale(), translate()
+*/
+void QMatrix4x4::rotate(qreal angle, qreal x, qreal y, qreal z)
+{
+ if (angle == 0.0f)
+ return;
+ QMatrix4x4 m(1); // The "1" says to not load the identity.
+ qreal c, s, ic;
+ if (angle == 90.0f || angle == -270.0f) {
+ s = 1.0f;
+ c = 0.0f;
+ } else if (angle == -90.0f || angle == 270.0f) {
+ s = -1.0f;
+ c = 0.0f;
+ } else if (angle == 180.0f || angle == -180.0f) {
+ s = 0.0f;
+ c = -1.0f;
+ } else {
+ qreal a = angle * M_PI / 180.0f;
+ c = qCos(a);
+ s = qSin(a);
+ }
+ bool quick = false;
+ if (x == 0.0f) {
+ if (y == 0.0f) {
+ if (z != 0.0f) {
+ // Rotate around the Z axis.
+ m.setToIdentity();
+ m.m[0][0] = c;
+ m.m[1][1] = c;
+ if (z < 0.0f) {
+ m.m[1][0] = s;
+ m.m[0][1] = -s;
+ } else {
+ m.m[1][0] = -s;
+ m.m[0][1] = s;
+ }
+ m.flagBits = General;
+ quick = true;
+ }
+ } else if (z == 0.0f) {
+ // Rotate around the Y axis.
+ m.setToIdentity();
+ m.m[0][0] = c;
+ m.m[2][2] = c;
+ if (y < 0.0f) {
+ m.m[2][0] = -s;
+ m.m[0][2] = s;
+ } else {
+ m.m[2][0] = s;
+ m.m[0][2] = -s;
+ }
+ m.flagBits = General;
+ quick = true;
+ }
+ } else if (y == 0.0f && z == 0.0f) {
+ // Rotate around the X axis.
+ m.setToIdentity();
+ m.m[1][1] = c;
+ m.m[2][2] = c;
+ if (x < 0.0f) {
+ m.m[2][1] = s;
+ m.m[1][2] = -s;
+ } else {
+ m.m[2][1] = -s;
+ m.m[1][2] = s;
+ }
+ m.flagBits = General;
+ quick = true;
+ }
+ if (!quick) {
+ qreal len = x * x + y * y + z * z;
+ if (!qFuzzyIsNull(len - 1.0f) && !qFuzzyIsNull(len)) {
+ len = qSqrt(len);
+ x /= len;
+ y /= len;
+ z /= len;
+ }
+ ic = 1.0f - c;
+ m.m[0][0] = x * x * ic + c;
+ m.m[1][0] = x * y * ic - z * s;
+ m.m[2][0] = x * z * ic + y * s;
+ m.m[3][0] = 0.0f;
+ m.m[0][1] = y * x * ic + z * s;
+ m.m[1][1] = y * y * ic + c;
+ m.m[2][1] = y * z * ic - x * s;
+ m.m[3][1] = 0.0f;
+ m.m[0][2] = x * z * ic - y * s;
+ m.m[1][2] = y * z * ic + x * s;
+ m.m[2][2] = z * z * ic + c;
+ m.m[3][2] = 0.0f;
+ m.m[0][3] = 0.0f;
+ m.m[1][3] = 0.0f;
+ m.m[2][3] = 0.0f;
+ m.m[3][3] = 1.0f;
+ }
+ int flags = flagBits;
+ *this *= m;
+ if (flags != Identity)
+ flagBits = flags | Rotation;
+ else
+ flagBits = Rotation;
+}
+
+/*!
+ \internal
+*/
+void QMatrix4x4::projectedRotate(qreal angle, qreal x, qreal y, qreal z)
+{
+ // Used by QGraphicsRotation::applyTo() to perform a rotation
+ // and projection back to 2D in a single step.
+ if (angle == 0.0f)
+ return;
+ QMatrix4x4 m(1); // The "1" says to not load the identity.
+ qreal c, s, ic;
+ if (angle == 90.0f || angle == -270.0f) {
+ s = 1.0f;
+ c = 0.0f;
+ } else if (angle == -90.0f || angle == 270.0f) {
+ s = -1.0f;
+ c = 0.0f;
+ } else if (angle == 180.0f || angle == -180.0f) {
+ s = 0.0f;
+ c = -1.0f;
+ } else {
+ qreal a = angle * M_PI / 180.0f;
+ c = qCos(a);
+ s = qSin(a);
+ }
+ bool quick = false;
+ if (x == 0.0f) {
+ if (y == 0.0f) {
+ if (z != 0.0f) {
+ // Rotate around the Z axis.
+ m.setToIdentity();
+ m.m[0][0] = c;
+ m.m[1][1] = c;
+ if (z < 0.0f) {
+ m.m[1][0] = s;
+ m.m[0][1] = -s;
+ } else {
+ m.m[1][0] = -s;
+ m.m[0][1] = s;
+ }
+ m.flagBits = General;
+ quick = true;
+ }
+ } else if (z == 0.0f) {
+ // Rotate around the Y axis.
+ m.setToIdentity();
+ m.m[0][0] = c;
+ m.m[2][2] = 1.0f;
+ if (y < 0.0f) {
+ m.m[0][3] = -s * inv_dist_to_plane;
+ } else {
+ m.m[0][3] = s * inv_dist_to_plane;
+ }
+ m.flagBits = General;
+ quick = true;
+ }
+ } else if (y == 0.0f && z == 0.0f) {
+ // Rotate around the X axis.
+ m.setToIdentity();
+ m.m[1][1] = c;
+ m.m[2][2] = 1.0f;
+ if (x < 0.0f) {
+ m.m[1][3] = s * inv_dist_to_plane;
+ } else {
+ m.m[1][3] = -s * inv_dist_to_plane;
+ }
+ m.flagBits = General;
+ quick = true;
+ }
+ if (!quick) {
+ qreal len = x * x + y * y + z * z;
+ if (!qFuzzyIsNull(len - 1.0f) && !qFuzzyIsNull(len)) {
+ len = qSqrt(len);
+ x /= len;
+ y /= len;
+ z /= len;
+ }
+ ic = 1.0f - c;
+ m.m[0][0] = x * x * ic + c;
+ m.m[1][0] = x * y * ic - z * s;
+ m.m[2][0] = 0.0f;
+ m.m[3][0] = 0.0f;
+ m.m[0][1] = y * x * ic + z * s;
+ m.m[1][1] = y * y * ic + c;
+ m.m[2][1] = 0.0f;
+ m.m[3][1] = 0.0f;
+ m.m[0][2] = 0.0f;
+ m.m[1][2] = 0.0f;
+ m.m[2][2] = 1.0f;
+ m.m[3][2] = 0.0f;
+ m.m[0][3] = (x * z * ic - y * s) * -inv_dist_to_plane;
+ m.m[1][3] = (y * z * ic + x * s) * -inv_dist_to_plane;
+ m.m[2][3] = 0.0f;
+ m.m[3][3] = 1.0f;
+ }
+ int flags = flagBits;
+ *this *= m;
+ if (flags != Identity)
+ flagBits = flags | Rotation;
+ else
+ flagBits = Rotation;
+}
+
+#ifndef QT_NO_QUATERNION
+
+/*!
+ Multiples this matrix by another that rotates coordinates according
+ to a specified \a quaternion. The \a quaternion is assumed to have
+ been normalized.
+
+ \sa scale(), translate(), QQuaternion
+*/
+void QMatrix4x4::rotate(const QQuaternion& quaternion)
+{
+ // Algorithm from:
+ // http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q54
+ QMatrix4x4 m(1);
+ qreal xx = quaternion.x() * quaternion.x();
+ qreal xy = quaternion.x() * quaternion.y();
+ qreal xz = quaternion.x() * quaternion.z();
+ qreal xw = quaternion.x() * quaternion.scalar();
+ qreal yy = quaternion.y() * quaternion.y();
+ qreal yz = quaternion.y() * quaternion.z();
+ qreal yw = quaternion.y() * quaternion.scalar();
+ qreal zz = quaternion.z() * quaternion.z();
+ qreal zw = quaternion.z() * quaternion.scalar();
+ m.m[0][0] = 1.0f - 2 * (yy + zz);
+ m.m[1][0] = 2 * (xy - zw);
+ m.m[2][0] = 2 * (xz + yw);
+ m.m[3][0] = 0.0f;
+ m.m[0][1] = 2 * (xy + zw);
+ m.m[1][1] = 1.0f - 2 * (xx + zz);
+ m.m[2][1] = 2 * (yz - xw);
+ m.m[3][1] = 0.0f;
+ m.m[0][2] = 2 * (xz - yw);
+ m.m[1][2] = 2 * (yz + xw);
+ m.m[2][2] = 1.0f - 2 * (xx + yy);
+ m.m[3][2] = 0.0f;
+ m.m[0][3] = 0.0f;
+ m.m[1][3] = 0.0f;
+ m.m[2][3] = 0.0f;
+ m.m[3][3] = 1.0f;
+ int flags = flagBits;
+ *this *= m;
+ if (flags != Identity)
+ flagBits = flags | Rotation;
+ else
+ flagBits = Rotation;
+}
+
+#endif
+
+/*!
+ \overload
+
+ Multiplies this matrix by another that applies an orthographic
+ projection for a window with boundaries specified by \a rect.
+ The near and far clipping planes will be -1 and 1 respectively.
+
+ \sa frustum(), perspective()
+*/
+void QMatrix4x4::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.0f, 1.0f);
+}
+
+/*!
+ \overload
+
+ Multiplies this matrix by another that applies an orthographic
+ projection for a window with boundaries specified by \a rect.
+ The near and far clipping planes will be -1 and 1 respectively.
+
+ \sa frustum(), perspective()
+*/
+void QMatrix4x4::ortho(const QRectF& rect)
+{
+ ortho(rect.left(), rect.right(), rect.bottom(), rect.top(), -1.0f, 1.0f);
+}
+
+/*!
+ Multiplies this matrix by another that applies an orthographic
+ projection for a window with lower-left corner (\a left, \a bottom),
+ upper-right corner (\a right, \a top), and the specified \a nearPlane
+ and \a farPlane clipping planes.
+
+ \sa frustum(), perspective()
+*/
+void QMatrix4x4::ortho(qreal left, qreal right, qreal bottom, qreal top, qreal nearPlane, qreal farPlane)
+{
+ // Bail out if the projection volume is zero-sized.
+ if (left == right || bottom == top || nearPlane == farPlane)
+ return;
+
+ // Construct the projection.
+ qreal width = right - left;
+ qreal invheight = top - bottom;
+ qreal clip = farPlane - nearPlane;
+#ifndef QT_NO_VECTOR3D
+ if (clip == 2.0f && (nearPlane + farPlane) == 0.0f) {
+ // We can express this projection as a translate and scale
+ // which will be more efficient to modify with further
+ // transformations than producing a "General" matrix.
+ translate(QVector3D
+ (-(left + right) / width,
+ -(top + bottom) / invheight,
+ 0.0f));
+ scale(QVector3D
+ (2.0f / width,
+ 2.0f / invheight,
+ -1.0f));
+ return;
+ }
+#endif
+ QMatrix4x4 m(1);
+ m.m[0][0] = 2.0f / width;
+ m.m[1][0] = 0.0f;
+ m.m[2][0] = 0.0f;
+ m.m[3][0] = -(left + right) / width;
+ m.m[0][1] = 0.0f;
+ m.m[1][1] = 2.0f / invheight;
+ m.m[2][1] = 0.0f;
+ m.m[3][1] = -(top + bottom) / invheight;
+ m.m[0][2] = 0.0f;
+ m.m[1][2] = 0.0f;
+ m.m[2][2] = -2.0f / clip;
+ m.m[3][2] = -(nearPlane + farPlane) / clip;
+ m.m[0][3] = 0.0f;
+ m.m[1][3] = 0.0f;
+ m.m[2][3] = 0.0f;
+ m.m[3][3] = 1.0f;
+
+ // Apply the projection.
+ *this *= m;
+ return;
+}
+
+/*!
+ Multiplies this matrix by another that applies a perspective
+ frustum projection for a window with lower-left corner (\a left, \a bottom),
+ upper-right corner (\a right, \a top), and the specified \a nearPlane
+ and \a farPlane clipping planes.
+
+ \sa ortho(), perspective()
+*/
+void QMatrix4x4::frustum(qreal left, qreal right, qreal bottom, qreal top, qreal nearPlane, qreal farPlane)
+{
+ // Bail out if the projection volume is zero-sized.
+ if (left == right || bottom == top || nearPlane == farPlane)
+ return;
+
+ // Construct the projection.
+ QMatrix4x4 m(1);
+ qreal width = right - left;
+ qreal invheight = top - bottom;
+ qreal clip = farPlane - nearPlane;
+ m.m[0][0] = 2.0f * nearPlane / width;
+ m.m[1][0] = 0.0f;
+ m.m[2][0] = (left + right) / width;
+ m.m[3][0] = 0.0f;
+ m.m[0][1] = 0.0f;
+ m.m[1][1] = 2.0f * nearPlane / invheight;
+ m.m[2][1] = (top + bottom) / invheight;
+ m.m[3][1] = 0.0f;
+ m.m[0][2] = 0.0f;
+ m.m[1][2] = 0.0f;
+ m.m[2][2] = -(nearPlane + farPlane) / clip;
+ m.m[3][2] = -2.0f * nearPlane * farPlane / clip;
+ m.m[0][3] = 0.0f;
+ m.m[1][3] = 0.0f;
+ m.m[2][3] = -1.0f;
+ m.m[3][3] = 0.0f;
+
+ // Apply the projection.
+ *this *= m;
+}
+
+/*!
+ Multiplies this matrix by another that applies a perspective
+ projection. The field of view will be \a angle degrees within
+ a window with a given \a aspect ratio. The projection will
+ have the specified \a nearPlane and \a farPlane clipping planes.
+
+ \sa ortho(), frustum()
+*/
+void QMatrix4x4::perspective(qreal angle, qreal aspect, qreal nearPlane, qreal farPlane)
+{
+ // Bail out if the projection volume is zero-sized.
+ if (nearPlane == farPlane || aspect == 0.0f)
+ return;
+
+ // Construct the projection.
+ QMatrix4x4 m(1);
+ qreal radians = (angle / 2.0f) * M_PI / 180.0f;
+ qreal sine = qSin(radians);
+ if (sine == 0.0f)
+ return;
+ qreal cotan = qCos(radians) / sine;
+ qreal clip = farPlane - nearPlane;
+ m.m[0][0] = cotan / aspect;
+ m.m[1][0] = 0.0f;
+ m.m[2][0] = 0.0f;
+ m.m[3][0] = 0.0f;
+ m.m[0][1] = 0.0f;
+ m.m[1][1] = cotan;
+ m.m[2][1] = 0.0f;
+ m.m[3][1] = 0.0f;
+ m.m[0][2] = 0.0f;
+ m.m[1][2] = 0.0f;
+ m.m[2][2] = -(nearPlane + farPlane) / clip;
+ m.m[3][2] = -(2.0f * nearPlane * farPlane) / clip;
+ m.m[0][3] = 0.0f;
+ m.m[1][3] = 0.0f;
+ m.m[2][3] = -1.0f;
+ m.m[3][3] = 0.0f;
+
+ // Apply the projection.
+ *this *= m;
+}
+
+#ifndef QT_NO_VECTOR3D
+
+/*!
+ Multiplies this matrix by another that applies an \a eye position
+ transformation. The \a center value indicates the center of the
+ view that the \a eye is looking at. The \a up value indicates
+ which direction should be considered up with respect to the \a eye.
+*/
+void QMatrix4x4::lookAt(const QVector3D& eye, const QVector3D& center, const QVector3D& up)
+{
+ QVector3D forward = (center - eye).normalized();
+ QVector3D side = QVector3D::crossProduct(forward, up).normalized();
+ QVector3D upVector = QVector3D::crossProduct(side, forward);
+
+ QMatrix4x4 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.0f;
+ m.m[0][1] = upVector.x();
+ m.m[1][1] = upVector.y();
+ m.m[2][1] = upVector.z();
+ m.m[3][1] = 0.0f;
+ m.m[0][2] = -forward.x();
+ m.m[1][2] = -forward.y();
+ m.m[2][2] = -forward.z();
+ m.m[3][2] = 0.0f;
+ m.m[0][3] = 0.0f;
+ m.m[1][3] = 0.0f;
+ m.m[2][3] = 0.0f;
+ m.m[3][3] = 1.0f;
+
+ *this *= m;
+ translate(-eye);
+}
+
+#endif
+
+/*!
+ Flips between right-handed and left-handed coordinate systems
+ by multiplying the y and z co-ordinates by -1. This is normally
+ used to create a left-handed orthographic view without scaling
+ the viewport as ortho() does.
+
+ \sa ortho()
+*/
+void QMatrix4x4::flipCoordinates()
+{
+ if (flagBits == Scale || flagBits == (Scale | Translation)) {
+ m[1][1] = -m[1][1];
+ m[2][2] = -m[2][2];
+ } else if (flagBits == Translation) {
+ m[1][1] = -m[1][1];
+ m[2][2] = -m[2][2];
+ flagBits |= Scale;
+ } else if (flagBits == Identity) {
+ m[1][1] = -1.0f;
+ m[2][2] = -1.0f;
+ flagBits = Scale;
+ } 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 = General;
+ }
+}
+
+/*!
+ Retrieves the 16 items in this matrix and copies them to \a values
+ in row-major order.
+*/
+void QMatrix4x4::copyDataTo(qreal *values) const
+{
+ for (int row = 0; row < 4; ++row)
+ for (int col = 0; col < 4; ++col)
+ values[row * 4 + col] = qreal(m[col][row]);
+}
+
+/*!
+ Returns the conventional Qt 2D affine transformation matrix that
+ corresponds to this matrix. It is assumed that this matrix
+ only contains 2D affine transformation elements.
+
+ \sa toTransform()
+*/
+QMatrix QMatrix4x4::toAffine() const
+{
+ return QMatrix(m[0][0], m[0][1],
+ m[1][0], m[1][1],
+ m[3][0], m[3][1]);
+}
+
+/*!
+ Returns the conventional Qt 2D transformation matrix that
+ corresponds to this matrix.
+
+ The returned QTransform is formed by simply dropping the
+ third row and third column of the QMatrix4x4. This is suitable
+ for implementing orthographic projections where the z co-ordinate
+ should be dropped rather than projected.
+
+ \sa toAffine()
+*/
+QTransform QMatrix4x4::toTransform() const
+{
+ return QTransform(m[0][0], m[0][1], m[0][3],
+ m[1][0], m[1][1], m[1][3],
+ m[3][0], m[3][1], m[3][3]);
+}
+
+/*!
+ Returns the conventional Qt 2D transformation matrix that
+ corresponds to this matrix.
+
+ If \a distanceToPlane is non-zero, it indicates a projection
+ factor to use to adjust for the z co-ordinate. The value of
+ 1024 corresponds to the projection factor used
+ by QTransform::rotate() for the x and y axes.
+
+ If \a distanceToPlane is zero, then the returned QTransform
+ is formed by simply dropping the third row and third column
+ of the QMatrix4x4. This is suitable for implementing
+ orthographic projections where the z co-ordinate should
+ be dropped rather than projected.
+
+ \sa toAffine()
+*/
+QTransform QMatrix4x4::toTransform(qreal distanceToPlane) const
+{
+ if (distanceToPlane == 1024.0f) {
+ // Optimize the common case with constants.
+ return QTransform(m[0][0], m[0][1],
+ m[0][3] - m[0][2] * inv_dist_to_plane,
+ m[1][0], m[1][1],
+ m[1][3] - m[1][2] * inv_dist_to_plane,
+ m[3][0], m[3][1],
+ m[3][3] - m[3][2] * inv_dist_to_plane);
+ } else if (distanceToPlane != 0.0f) {
+ // The following projection matrix is pre-multiplied with "matrix":
+ // | 1 0 0 0 |
+ // | 0 1 0 0 |
+ // | 0 0 1 0 |
+ // | 0 0 d 1 |
+ // where d = -1 / distanceToPlane. After projection, row 3 and
+ // column 3 are dropped to form the final QTransform.
+ qreal d = 1.0f / distanceToPlane;
+ return QTransform(m[0][0], m[0][1], m[0][3] - m[0][2] * d,
+ m[1][0], m[1][1], m[1][3] - m[1][2] * d,
+ m[3][0], m[3][1], m[3][3] - m[3][2] * d);
+ } else {
+ // Orthographic projection: drop row 3 and column 3.
+ return QTransform(m[0][0], m[0][1], m[0][3],
+ m[1][0], m[1][1], m[1][3],
+ m[3][0], m[3][1], m[3][3]);
+ }
+}
+
+/*!
+ \fn QPoint QMatrix4x4::map(const QPoint& point) const
+
+ Maps \a point by multiplying this matrix by \a point.
+
+ \sa mapRect()
+*/
+
+/*!
+ \fn QPointF QMatrix4x4::map(const QPointF& point) const
+
+ Maps \a point by multiplying this matrix by \a point.
+
+ \sa mapRect()
+*/
+
+#ifndef QT_NO_VECTOR3D
+
+/*!
+ \fn QVector3D QMatrix4x4::map(const QVector3D& point) const
+
+ Maps \a point by multiplying this matrix by \a point.
+
+ \sa mapRect(), mapVector()
+*/
+
+/*!
+ \fn QVector3D QMatrix4x4::mapVector(const QVector3D& vector) const
+
+ Maps \a vector by multiplying the top 3x3 portion of this matrix
+ by \a vector. The translation and projection components of
+ this matrix are ignored.
+
+ \sa map()
+*/
+
+#endif
+
+#ifndef QT_NO_VECTOR4D
+
+/*!
+ \fn QVector4D QMatrix4x4::map(const QVector4D& point) const;
+
+ Maps \a point by multiplying this matrix by \a point.
+
+ \sa mapRect()
+*/
+
+#endif
+
+/*!
+ Maps \a rect by multiplying this matrix by the corners
+ of \a rect and then forming a new rectangle from the results.
+ The returned rectangle will be an ordinary 2D rectangle
+ with sides parallel to the horizontal and vertical axes.
+
+ \sa map()
+*/
+QRect QMatrix4x4::mapRect(const QRect& rect) const
+{
+ if (flagBits == (Translation | Scale) || flagBits == Scale) {
+ qreal x = rect.x() * m[0][0] + m[3][0];
+ qreal y = rect.y() * m[1][1] + m[3][1];
+ qreal w = rect.width() * m[0][0];
+ qreal 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));
+ } else if (flagBits == Translation) {
+ return QRect(qRound(rect.x() + m[3][0]),
+ qRound(rect.y() + m[3][1]),
+ rect.width(), rect.height());
+ }
+
+ 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);
+}
+
+/*!
+ Maps \a rect by multiplying this matrix by the corners
+ of \a rect and then forming a new rectangle from the results.
+ The returned rectangle will be an ordinary 2D rectangle
+ with sides parallel to the horizontal and vertical axes.
+
+ \sa map()
+*/
+QRectF QMatrix4x4::mapRect(const QRectF& rect) const
+{
+ if (flagBits == (Translation | Scale) || flagBits == Scale) {
+ qreal x = rect.x() * m[0][0] + m[3][0];
+ qreal y = rect.y() * m[1][1] + m[3][1];
+ qreal w = rect.width() * m[0][0];
+ qreal 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);
+ } else if (flagBits == Translation) {
+ return rect.translated(m[3][0], m[3][1]);
+ }
+
+ QPointF tl = map(rect.topLeft()); QPointF tr = map(rect.topRight());
+ QPointF bl = map(rect.bottomLeft()); QPointF br = map(rect.bottomRight());
+
+ qreal xmin = qMin(qMin(tl.x(), tr.x()), qMin(bl.x(), br.x()));
+ qreal xmax = qMax(qMax(tl.x(), tr.x()), qMax(bl.x(), br.x()));
+ qreal ymin = qMin(qMin(tl.y(), tr.y()), qMin(bl.y(), br.y()));
+ qreal ymax = qMax(qMax(tl.y(), tr.y()), qMax(bl.y(), br.y()));
+
+ return QRectF(QPointF(xmin, ymin), QPointF(xmax, ymax));
+}
+
+/*!
+ \fn qreal *QMatrix4x4::data()
+
+ Returns a pointer to the raw data of this matrix.
+
+ \sa constData(), optimize()
+*/
+
+/*!
+ \fn const qreal *QMatrix4x4::data() const
+
+ Returns a constant pointer to the raw data of this matrix.
+
+ \sa constData()
+*/
+
+/*!
+ \fn const qreal *QMatrix4x4::constData() const
+
+ Returns a constant pointer to the raw data of this matrix.
+
+ \sa data()
+*/
+
+// Helper routine for inverting orthonormal matrices that consist
+// of just rotations and translations.
+QMatrix4x4 QMatrix4x4::orthonormalInverse() const
+{
+ QMatrix4x4 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.0f;
+ result.m[1][3] = 0.0f;
+ result.m[2][3] = 0.0f;
+
+ 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.0f;
+
+ return result;
+}
+
+/*!
+ Optimize the usage of this matrix from its current elements.
+
+ Some operations such as translate(), scale(), and rotate() can be
+ performed more efficiently if the matrix being modified is already
+ known to be the identity, a previous translate(), a previous
+ scale(), etc.
+
+ Normally the QMatrix4x4 class keeps track of this special type internally
+ as operations are performed. However, if the matrix is modified
+ directly with operator()() or data(), then QMatrix4x4 will lose track of
+ the special type and will revert to the safest but least efficient
+ operations thereafter.
+
+ By calling optimize() after directly modifying the matrix,
+ the programmer can force QMatrix4x4 to recover the special type if
+ the elements appear to conform to one of the known optimized types.
+
+ \sa operator()(), data(), translate()
+*/
+void QMatrix4x4::optimize()
+{
+ // If the last element is not 1, then it can never be special.
+ if (m[3][3] != 1.0f) {
+ flagBits = General;
+ return;
+ }
+
+ // If the upper three elements m12, m13, and m21 are not all zero,
+ // or the lower elements below the diagonal are not all zero, then
+ // the matrix can never be special.
+ if (m[1][0] != 0.0f || m[2][0] != 0.0f || m[2][1] != 0.0f) {
+ flagBits = General;
+ return;
+ }
+ if (m[0][1] != 0.0f || m[0][2] != 0.0f || m[0][3] != 0.0f ||
+ m[1][2] != 0.0f || m[1][3] != 0.0f || m[2][3] != 0.0f) {
+ flagBits = General;
+ return;
+ }
+
+ // Determine what we have in the remaining regions of the matrix.
+ bool identityAlongDiagonal
+ = (m[0][0] == 1.0f && m[1][1] == 1.0f && m[2][2] == 1.0f);
+ bool translationPresent
+ = (m[3][0] != 0.0f || m[3][1] != 0.0f || m[3][2] != 0.0f);
+
+ // Now determine the special matrix type.
+ if (translationPresent && identityAlongDiagonal)
+ flagBits = Translation;
+ else if (translationPresent)
+ flagBits = (Translation | Scale);
+ else if (identityAlongDiagonal)
+ flagBits = Identity;
+ else
+ flagBits = Scale;
+}
+
+/*!
+ Returns the matrix as a QVariant.
+*/
+QMatrix4x4::operator QVariant() const
+{
+ return QVariant(QVariant::Matrix4x4, this);
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+
+QDebug operator<<(QDebug dbg, const QMatrix4x4 &m)
+{
+ // Create a string that represents the matrix type.
+ QByteArray bits;
+ if ((m.flagBits & QMatrix4x4::Identity) != 0)
+ bits += "Identity,";
+ if ((m.flagBits & QMatrix4x4::General) != 0)
+ bits += "General,";
+ if ((m.flagBits & QMatrix4x4::Translation) != 0)
+ bits += "Translation,";
+ if ((m.flagBits & QMatrix4x4::Scale) != 0)
+ bits += "Scale,";
+ if ((m.flagBits & QMatrix4x4::Rotation) != 0)
+ bits += "Rotation,";
+ if (bits.size() > 0)
+ bits = bits.left(bits.size() - 1);
+
+ // Output in row-major order because it is more human-readable.
+ dbg.nospace() << "QMatrix4x4(type:" << bits.constData() << endl
+ << qSetFieldWidth(10)
+ << m(0, 0) << m(0, 1) << m(0, 2) << m(0, 3) << endl
+ << m(1, 0) << m(1, 1) << m(1, 2) << m(1, 3) << endl
+ << m(2, 0) << m(2, 1) << m(2, 2) << m(2, 3) << endl
+ << m(3, 0) << m(3, 1) << m(3, 2) << m(3, 3) << endl
+ << qSetFieldWidth(0) << ')';
+ return dbg.space();
+}
+
+#endif
+
+#ifndef QT_NO_DATASTREAM
+
+/*!
+ \fn QDataStream &operator<<(QDataStream &stream, const QMatrix4x4 &matrix)
+ \relates QMatrix4x4
+
+ Writes the given \a matrix to the given \a stream and returns a
+ reference to the stream.
+
+ \sa {Serializing Qt Data Types}
+*/
+
+QDataStream &operator<<(QDataStream &stream, const QMatrix4x4 &matrix)
+{
+ for (int row = 0; row < 4; ++row)
+ for (int col = 0; col < 4; ++col)
+ stream << double(matrix(row, col));
+ return stream;
+}
+
+/*!
+ \fn QDataStream &operator>>(QDataStream &stream, QMatrix4x4 &matrix)
+ \relates QMatrix4x4
+
+ Reads a 4x4 matrix from the given \a stream into the given \a matrix
+ and returns a reference to the stream.
+
+ \sa {Serializing Qt Data Types}
+*/
+
+QDataStream &operator>>(QDataStream &stream, QMatrix4x4 &matrix)
+{
+ double x;
+ for (int row = 0; row < 4; ++row) {
+ for (int col = 0; col < 4; ++col) {
+ stream >> x;
+ matrix(row, col) = qreal(x);
+ }
+ }
+ matrix.optimize();
+ return stream;
+}
+
+#endif // QT_NO_DATASTREAM
+
+#endif // QT_NO_MATRIX4X4
+
+QT_END_NAMESPACE
diff --git a/src/gui/math3d/qmatrix4x4.h b/src/gui/math3d/qmatrix4x4.h
new file mode 100644
index 0000000000..ad051160c9
--- /dev/null
+++ b/src/gui/math3d/qmatrix4x4.h
@@ -0,0 +1,1022 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMATRIX4X4_H
+#define QMATRIX4X4_H
+
+#include <QtGui/qvector3d.h>
+#include <QtGui/qvector4d.h>
+#include <QtGui/qquaternion.h>
+#include <QtGui/qgenericmatrix.h>
+#include <QtCore/qrect.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_MATRIX4X4
+
+class QMatrix;
+class QTransform;
+class QVariant;
+
+class Q_GUI_EXPORT QMatrix4x4
+{
+public:
+ inline QMatrix4x4() { setToIdentity(); }
+ explicit QMatrix4x4(const qreal *values);
+ inline QMatrix4x4(qreal m11, qreal m12, qreal m13, qreal m14,
+ qreal m21, qreal m22, qreal m23, qreal m24,
+ qreal m31, qreal m32, qreal m33, qreal m34,
+ qreal m41, qreal m42, qreal m43, qreal m44);
+
+ template <int N, int M>
+ explicit QMatrix4x4(const QGenericMatrix<N, M, qreal>& matrix);
+
+ QMatrix4x4(const qreal *values, int cols, int rows);
+ QMatrix4x4(const QTransform& transform);
+ QMatrix4x4(const QMatrix& matrix);
+
+ inline const qreal& operator()(int row, int column) const;
+ inline qreal& operator()(int row, int column);
+
+ inline QVector4D column(int index) const;
+ inline void setColumn(int index, const QVector4D& value);
+
+ inline QVector4D row(int index) const;
+ inline void setRow(int index, const QVector4D& value);
+
+ inline bool isIdentity() const;
+ inline void setToIdentity();
+
+ inline void fill(qreal value);
+
+ qreal determinant() const;
+ QMatrix4x4 inverted(bool *invertible = 0) const;
+ QMatrix4x4 transposed() const;
+ QMatrix3x3 normalMatrix() const;
+
+ inline QMatrix4x4& operator+=(const QMatrix4x4& other);
+ inline QMatrix4x4& operator-=(const QMatrix4x4& other);
+ inline QMatrix4x4& operator*=(const QMatrix4x4& other);
+ inline QMatrix4x4& operator*=(qreal factor);
+ QMatrix4x4& operator/=(qreal divisor);
+ inline bool operator==(const QMatrix4x4& other) const;
+ inline bool operator!=(const QMatrix4x4& other) const;
+
+ friend QMatrix4x4 operator+(const QMatrix4x4& m1, const QMatrix4x4& m2);
+ friend QMatrix4x4 operator-(const QMatrix4x4& m1, const QMatrix4x4& m2);
+ friend QMatrix4x4 operator*(const QMatrix4x4& m1, const QMatrix4x4& m2);
+#ifndef QT_NO_VECTOR3D
+ friend QVector3D operator*(const QMatrix4x4& matrix, const QVector3D& vector);
+ friend QVector3D operator*(const QVector3D& vector, const QMatrix4x4& matrix);
+#endif
+#ifndef QT_NO_VECTOR4D
+ friend QVector4D operator*(const QVector4D& vector, const QMatrix4x4& matrix);
+ friend QVector4D operator*(const QMatrix4x4& matrix, const QVector4D& vector);
+#endif
+ friend QPoint operator*(const QPoint& point, const QMatrix4x4& matrix);
+ friend QPointF operator*(const QPointF& point, const QMatrix4x4& matrix);
+ friend QMatrix4x4 operator-(const QMatrix4x4& matrix);
+ friend QPoint operator*(const QMatrix4x4& matrix, const QPoint& point);
+ friend QPointF operator*(const QMatrix4x4& matrix, const QPointF& point);
+ friend QMatrix4x4 operator*(qreal factor, const QMatrix4x4& matrix);
+ friend QMatrix4x4 operator*(const QMatrix4x4& matrix, qreal factor);
+ friend Q_GUI_EXPORT QMatrix4x4 operator/(const QMatrix4x4& matrix, qreal divisor);
+
+ friend inline bool qFuzzyCompare(const QMatrix4x4& m1, const QMatrix4x4& m2);
+
+#ifndef QT_NO_VECTOR3D
+ void scale(const QVector3D& vector);
+ void translate(const QVector3D& vector);
+ void rotate(qreal angle, const QVector3D& vector);
+#endif
+ void scale(qreal x, qreal y);
+ void scale(qreal x, qreal y, qreal z);
+ void scale(qreal factor);
+ void translate(qreal x, qreal y);
+ void translate(qreal x, qreal y, qreal z);
+ void rotate(qreal angle, qreal x, qreal y, qreal z = 0.0f);
+#ifndef QT_NO_QUATERNION
+ void rotate(const QQuaternion& quaternion);
+#endif
+
+ void ortho(const QRect& rect);
+ void ortho(const QRectF& rect);
+ void ortho(qreal left, qreal right, qreal bottom, qreal top, qreal nearPlane, qreal farPlane);
+ void frustum(qreal left, qreal right, qreal bottom, qreal top, qreal nearPlane, qreal farPlane);
+ void perspective(qreal angle, qreal aspect, qreal nearPlane, qreal farPlane);
+#ifndef QT_NO_VECTOR3D
+ void lookAt(const QVector3D& eye, const QVector3D& center, const QVector3D& up);
+#endif
+ void flipCoordinates();
+
+ void copyDataTo(qreal *values) const;
+
+ QMatrix toAffine() const;
+ QTransform toTransform() const;
+ QTransform toTransform(qreal distanceToPlane) const;
+
+ QPoint map(const QPoint& point) const;
+ QPointF map(const QPointF& point) const;
+#ifndef QT_NO_VECTOR3D
+ QVector3D map(const QVector3D& point) const;
+ QVector3D mapVector(const QVector3D& vector) const;
+#endif
+#ifndef QT_NO_VECTOR4D
+ QVector4D map(const QVector4D& point) const;
+#endif
+ QRect mapRect(const QRect& rect) const;
+ QRectF mapRect(const QRectF& rect) const;
+
+ template <int N, int M>
+ QGenericMatrix<N, M, qreal> toGenericMatrix() const;
+
+ inline qreal *data();
+ inline const qreal *data() const { return *m; }
+ inline const qreal *constData() const { return *m; }
+
+ void optimize();
+
+ operator QVariant() const;
+
+#ifndef QT_NO_DEBUG_STREAM
+ friend Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QMatrix4x4 &m);
+#endif
+
+private:
+ qreal m[4][4]; // Column-major order to match OpenGL.
+ int flagBits; // Flag bits from the enum below.
+
+ enum {
+ Identity = 0x0001, // Identity matrix
+ General = 0x0002, // General matrix, unknown contents
+ Translation = 0x0004, // Contains a simple translation
+ Scale = 0x0008, // Contains a simple scale
+ Rotation = 0x0010 // Contains a simple rotation
+ };
+
+ // Construct without initializing identity matrix.
+ QMatrix4x4(int) { flagBits = General; }
+
+ QMatrix4x4 orthonormalInverse() const;
+
+ void projectedRotate(qreal angle, qreal x, qreal y, qreal z);
+
+ friend class QGraphicsRotation;
+};
+
+Q_DECLARE_TYPEINFO(QMatrix4x4, Q_MOVABLE_TYPE);
+
+inline QMatrix4x4::QMatrix4x4
+ (qreal m11, qreal m12, qreal m13, qreal m14,
+ qreal m21, qreal m22, qreal m23, qreal m24,
+ qreal m31, qreal m32, qreal m33, qreal m34,
+ qreal m41, qreal m42, qreal m43, qreal m44)
+{
+ m[0][0] = m11; m[0][1] = m21; m[0][2] = m31; m[0][3] = m41;
+ m[1][0] = m12; m[1][1] = m22; m[1][2] = m32; m[1][3] = m42;
+ m[2][0] = m13; m[2][1] = m23; m[2][2] = m33; m[2][3] = m43;
+ m[3][0] = m14; m[3][1] = m24; m[3][2] = m34; m[3][3] = m44;
+ flagBits = General;
+}
+
+template <int N, int M>
+Q_INLINE_TEMPLATE QMatrix4x4::QMatrix4x4
+ (const QGenericMatrix<N, M, qreal>& matrix)
+{
+ const qreal *values = matrix.constData();
+ for (int matrixCol = 0; matrixCol < 4; ++matrixCol) {
+ for (int matrixRow = 0; matrixRow < 4; ++matrixRow) {
+ if (matrixCol < N && matrixRow < M)
+ m[matrixCol][matrixRow] = values[matrixCol * M + matrixRow];
+ else if (matrixCol == matrixRow)
+ m[matrixCol][matrixRow] = 1.0f;
+ else
+ m[matrixCol][matrixRow] = 0.0f;
+ }
+ }
+ flagBits = General;
+}
+
+template <int N, int M>
+QGenericMatrix<N, M, qreal> QMatrix4x4::toGenericMatrix() const
+{
+ QGenericMatrix<N, M, qreal> result;
+ qreal *values = result.data();
+ for (int matrixCol = 0; matrixCol < N; ++matrixCol) {
+ for (int matrixRow = 0; matrixRow < M; ++matrixRow) {
+ if (matrixCol < 4 && matrixRow < 4)
+ values[matrixCol * M + matrixRow] = m[matrixCol][matrixRow];
+ else if (matrixCol == matrixRow)
+ values[matrixCol * M + matrixRow] = 1.0f;
+ else
+ values[matrixCol * M + matrixRow] = 0.0f;
+ }
+ }
+ return result;
+}
+
+inline const qreal& QMatrix4x4::operator()(int aRow, int aColumn) const
+{
+ Q_ASSERT(aRow >= 0 && aRow < 4 && aColumn >= 0 && aColumn < 4);
+ return m[aColumn][aRow];
+}
+
+inline qreal& QMatrix4x4::operator()(int aRow, int aColumn)
+{
+ Q_ASSERT(aRow >= 0 && aRow < 4 && aColumn >= 0 && aColumn < 4);
+ flagBits = General;
+ return m[aColumn][aRow];
+}
+
+inline QVector4D QMatrix4x4::column(int index) const
+{
+ Q_ASSERT(index >= 0 && index < 4);
+ return QVector4D(m[index][0], m[index][1], m[index][2], m[index][3]);
+}
+
+inline void QMatrix4x4::setColumn(int index, const QVector4D& value)
+{
+ Q_ASSERT(index >= 0 && index < 4);
+ m[index][0] = value.x();
+ m[index][1] = value.y();
+ m[index][2] = value.z();
+ m[index][3] = value.w();
+ flagBits = General;
+}
+
+inline QVector4D QMatrix4x4::row(int index) const
+{
+ Q_ASSERT(index >= 0 && index < 4);
+ return QVector4D(m[0][index], m[1][index], m[2][index], m[3][index]);
+}
+
+inline void QMatrix4x4::setRow(int index, const QVector4D& value)
+{
+ Q_ASSERT(index >= 0 && index < 4);
+ m[0][index] = value.x();
+ m[1][index] = value.y();
+ m[2][index] = value.z();
+ m[3][index] = value.w();
+ flagBits = General;
+}
+
+Q_GUI_EXPORT QMatrix4x4 operator/(const QMatrix4x4& matrix, qreal divisor);
+
+inline bool QMatrix4x4::isIdentity() const
+{
+ if (flagBits == Identity)
+ return true;
+ if (m[0][0] != 1.0f || m[0][1] != 0.0f || m[0][2] != 0.0f)
+ return false;
+ if (m[0][3] != 0.0f || m[1][0] != 0.0f || m[1][1] != 1.0f)
+ return false;
+ if (m[1][2] != 0.0f || m[1][3] != 0.0f || m[2][0] != 0.0f)
+ return false;
+ if (m[2][1] != 0.0f || m[2][2] != 1.0f || m[2][3] != 0.0f)
+ return false;
+ if (m[3][0] != 0.0f || m[3][1] != 0.0f || m[3][2] != 0.0f)
+ return false;
+ return (m[3][3] == 1.0f);
+}
+
+inline void QMatrix4x4::setToIdentity()
+{
+ m[0][0] = 1.0f;
+ m[0][1] = 0.0f;
+ m[0][2] = 0.0f;
+ m[0][3] = 0.0f;
+ m[1][0] = 0.0f;
+ m[1][1] = 1.0f;
+ m[1][2] = 0.0f;
+ m[1][3] = 0.0f;
+ m[2][0] = 0.0f;
+ m[2][1] = 0.0f;
+ m[2][2] = 1.0f;
+ m[2][3] = 0.0f;
+ m[3][0] = 0.0f;
+ m[3][1] = 0.0f;
+ m[3][2] = 0.0f;
+ m[3][3] = 1.0f;
+ flagBits = Identity;
+}
+
+inline void QMatrix4x4::fill(qreal value)
+{
+ m[0][0] = value;
+ m[0][1] = value;
+ m[0][2] = value;
+ m[0][3] = value;
+ m[1][0] = value;
+ m[1][1] = value;
+ m[1][2] = value;
+ m[1][3] = value;
+ m[2][0] = value;
+ m[2][1] = value;
+ m[2][2] = value;
+ m[2][3] = value;
+ m[3][0] = value;
+ m[3][1] = value;
+ m[3][2] = value;
+ m[3][3] = value;
+ flagBits = General;
+}
+
+inline QMatrix4x4& QMatrix4x4::operator+=(const QMatrix4x4& other)
+{
+ m[0][0] += other.m[0][0];
+ m[0][1] += other.m[0][1];
+ m[0][2] += other.m[0][2];
+ m[0][3] += other.m[0][3];
+ m[1][0] += other.m[1][0];
+ m[1][1] += other.m[1][1];
+ m[1][2] += other.m[1][2];
+ m[1][3] += other.m[1][3];
+ m[2][0] += other.m[2][0];
+ m[2][1] += other.m[2][1];
+ m[2][2] += other.m[2][2];
+ m[2][3] += other.m[2][3];
+ m[3][0] += other.m[3][0];
+ m[3][1] += other.m[3][1];
+ m[3][2] += other.m[3][2];
+ m[3][3] += other.m[3][3];
+ flagBits = General;
+ return *this;
+}
+
+inline QMatrix4x4& QMatrix4x4::operator-=(const QMatrix4x4& other)
+{
+ m[0][0] -= other.m[0][0];
+ m[0][1] -= other.m[0][1];
+ m[0][2] -= other.m[0][2];
+ m[0][3] -= other.m[0][3];
+ m[1][0] -= other.m[1][0];
+ m[1][1] -= other.m[1][1];
+ m[1][2] -= other.m[1][2];
+ m[1][3] -= other.m[1][3];
+ m[2][0] -= other.m[2][0];
+ m[2][1] -= other.m[2][1];
+ m[2][2] -= other.m[2][2];
+ m[2][3] -= other.m[2][3];
+ m[3][0] -= other.m[3][0];
+ m[3][1] -= other.m[3][1];
+ m[3][2] -= other.m[3][2];
+ m[3][3] -= other.m[3][3];
+ flagBits = General;
+ return *this;
+}
+
+inline QMatrix4x4& QMatrix4x4::operator*=(const QMatrix4x4& other)
+{
+ if (flagBits == Identity) {
+ *this = other;
+ return *this;
+ } else if (other.flagBits == Identity) {
+ return *this;
+ } else {
+ *this = *this * other;
+ return *this;
+ }
+}
+
+inline QMatrix4x4& QMatrix4x4::operator*=(qreal factor)
+{
+ 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;
+ m[3][0] *= factor;
+ m[3][1] *= factor;
+ m[3][2] *= factor;
+ m[3][3] *= factor;
+ flagBits = General;
+ return *this;
+}
+
+inline bool QMatrix4x4::operator==(const QMatrix4x4& other) const
+{
+ return m[0][0] == other.m[0][0] &&
+ m[0][1] == other.m[0][1] &&
+ m[0][2] == other.m[0][2] &&
+ m[0][3] == other.m[0][3] &&
+ m[1][0] == other.m[1][0] &&
+ m[1][1] == other.m[1][1] &&
+ m[1][2] == other.m[1][2] &&
+ m[1][3] == other.m[1][3] &&
+ m[2][0] == other.m[2][0] &&
+ m[2][1] == other.m[2][1] &&
+ m[2][2] == other.m[2][2] &&
+ m[2][3] == other.m[2][3] &&
+ m[3][0] == other.m[3][0] &&
+ m[3][1] == other.m[3][1] &&
+ m[3][2] == other.m[3][2] &&
+ m[3][3] == other.m[3][3];
+}
+
+inline bool QMatrix4x4::operator!=(const QMatrix4x4& other) const
+{
+ return m[0][0] != other.m[0][0] ||
+ m[0][1] != other.m[0][1] ||
+ m[0][2] != other.m[0][2] ||
+ m[0][3] != other.m[0][3] ||
+ m[1][0] != other.m[1][0] ||
+ m[1][1] != other.m[1][1] ||
+ m[1][2] != other.m[1][2] ||
+ m[1][3] != other.m[1][3] ||
+ m[2][0] != other.m[2][0] ||
+ m[2][1] != other.m[2][1] ||
+ m[2][2] != other.m[2][2] ||
+ m[2][3] != other.m[2][3] ||
+ m[3][0] != other.m[3][0] ||
+ m[3][1] != other.m[3][1] ||
+ m[3][2] != other.m[3][2] ||
+ m[3][3] != other.m[3][3];
+}
+
+inline QMatrix4x4 operator+(const QMatrix4x4& m1, const QMatrix4x4& m2)
+{
+ QMatrix4x4 m(1);
+ m.m[0][0] = m1.m[0][0] + m2.m[0][0];
+ m.m[0][1] = m1.m[0][1] + m2.m[0][1];
+ m.m[0][2] = m1.m[0][2] + m2.m[0][2];
+ m.m[0][3] = m1.m[0][3] + m2.m[0][3];
+ m.m[1][0] = m1.m[1][0] + m2.m[1][0];
+ m.m[1][1] = m1.m[1][1] + m2.m[1][1];
+ m.m[1][2] = m1.m[1][2] + m2.m[1][2];
+ m.m[1][3] = m1.m[1][3] + m2.m[1][3];
+ m.m[2][0] = m1.m[2][0] + m2.m[2][0];
+ m.m[2][1] = m1.m[2][1] + m2.m[2][1];
+ m.m[2][2] = m1.m[2][2] + m2.m[2][2];
+ m.m[2][3] = m1.m[2][3] + m2.m[2][3];
+ m.m[3][0] = m1.m[3][0] + m2.m[3][0];
+ m.m[3][1] = m1.m[3][1] + m2.m[3][1];
+ m.m[3][2] = m1.m[3][2] + m2.m[3][2];
+ m.m[3][3] = m1.m[3][3] + m2.m[3][3];
+ return m;
+}
+
+inline QMatrix4x4 operator-(const QMatrix4x4& m1, const QMatrix4x4& m2)
+{
+ QMatrix4x4 m(1);
+ m.m[0][0] = m1.m[0][0] - m2.m[0][0];
+ m.m[0][1] = m1.m[0][1] - m2.m[0][1];
+ m.m[0][2] = m1.m[0][2] - m2.m[0][2];
+ m.m[0][3] = m1.m[0][3] - m2.m[0][3];
+ m.m[1][0] = m1.m[1][0] - m2.m[1][0];
+ m.m[1][1] = m1.m[1][1] - m2.m[1][1];
+ m.m[1][2] = m1.m[1][2] - m2.m[1][2];
+ m.m[1][3] = m1.m[1][3] - m2.m[1][3];
+ m.m[2][0] = m1.m[2][0] - m2.m[2][0];
+ m.m[2][1] = m1.m[2][1] - m2.m[2][1];
+ m.m[2][2] = m1.m[2][2] - m2.m[2][2];
+ m.m[2][3] = m1.m[2][3] - m2.m[2][3];
+ m.m[3][0] = m1.m[3][0] - m2.m[3][0];
+ m.m[3][1] = m1.m[3][1] - m2.m[3][1];
+ m.m[3][2] = m1.m[3][2] - m2.m[3][2];
+ m.m[3][3] = m1.m[3][3] - m2.m[3][3];
+ return m;
+}
+
+inline QMatrix4x4 operator*(const QMatrix4x4& m1, const QMatrix4x4& m2)
+{
+ if (m1.flagBits == QMatrix4x4::Identity)
+ return m2;
+ else if (m2.flagBits == QMatrix4x4::Identity)
+ return m1;
+
+ QMatrix4x4 m(1);
+ m.m[0][0] = m1.m[0][0] * m2.m[0][0] +
+ m1.m[1][0] * m2.m[0][1] +
+ m1.m[2][0] * m2.m[0][2] +
+ m1.m[3][0] * m2.m[0][3];
+ m.m[0][1] = m1.m[0][1] * m2.m[0][0] +
+ m1.m[1][1] * m2.m[0][1] +
+ m1.m[2][1] * m2.m[0][2] +
+ m1.m[3][1] * m2.m[0][3];
+ m.m[0][2] = m1.m[0][2] * m2.m[0][0] +
+ m1.m[1][2] * m2.m[0][1] +
+ m1.m[2][2] * m2.m[0][2] +
+ m1.m[3][2] * m2.m[0][3];
+ m.m[0][3] = m1.m[0][3] * m2.m[0][0] +
+ m1.m[1][3] * m2.m[0][1] +
+ m1.m[2][3] * m2.m[0][2] +
+ m1.m[3][3] * m2.m[0][3];
+ m.m[1][0] = m1.m[0][0] * m2.m[1][0] +
+ m1.m[1][0] * m2.m[1][1] +
+ m1.m[2][0] * m2.m[1][2] +
+ m1.m[3][0] * m2.m[1][3];
+ m.m[1][1] = m1.m[0][1] * m2.m[1][0] +
+ m1.m[1][1] * m2.m[1][1] +
+ m1.m[2][1] * m2.m[1][2] +
+ m1.m[3][1] * m2.m[1][3];
+ m.m[1][2] = m1.m[0][2] * m2.m[1][0] +
+ m1.m[1][2] * m2.m[1][1] +
+ m1.m[2][2] * m2.m[1][2] +
+ m1.m[3][2] * m2.m[1][3];
+ m.m[1][3] = m1.m[0][3] * m2.m[1][0] +
+ m1.m[1][3] * m2.m[1][1] +
+ m1.m[2][3] * m2.m[1][2] +
+ m1.m[3][3] * m2.m[1][3];
+ m.m[2][0] = m1.m[0][0] * m2.m[2][0] +
+ m1.m[1][0] * m2.m[2][1] +
+ m1.m[2][0] * m2.m[2][2] +
+ m1.m[3][0] * m2.m[2][3];
+ m.m[2][1] = m1.m[0][1] * m2.m[2][0] +
+ m1.m[1][1] * m2.m[2][1] +
+ m1.m[2][1] * m2.m[2][2] +
+ m1.m[3][1] * m2.m[2][3];
+ m.m[2][2] = m1.m[0][2] * m2.m[2][0] +
+ m1.m[1][2] * m2.m[2][1] +
+ m1.m[2][2] * m2.m[2][2] +
+ m1.m[3][2] * m2.m[2][3];
+ m.m[2][3] = m1.m[0][3] * m2.m[2][0] +
+ m1.m[1][3] * m2.m[2][1] +
+ m1.m[2][3] * m2.m[2][2] +
+ m1.m[3][3] * m2.m[2][3];
+ m.m[3][0] = m1.m[0][0] * m2.m[3][0] +
+ m1.m[1][0] * m2.m[3][1] +
+ m1.m[2][0] * m2.m[3][2] +
+ m1.m[3][0] * m2.m[3][3];
+ m.m[3][1] = m1.m[0][1] * m2.m[3][0] +
+ m1.m[1][1] * m2.m[3][1] +
+ m1.m[2][1] * m2.m[3][2] +
+ m1.m[3][1] * m2.m[3][3];
+ m.m[3][2] = m1.m[0][2] * m2.m[3][0] +
+ m1.m[1][2] * m2.m[3][1] +
+ m1.m[2][2] * m2.m[3][2] +
+ m1.m[3][2] * m2.m[3][3];
+ m.m[3][3] = m1.m[0][3] * m2.m[3][0] +
+ m1.m[1][3] * m2.m[3][1] +
+ m1.m[2][3] * m2.m[3][2] +
+ m1.m[3][3] * m2.m[3][3];
+ return m;
+}
+
+#ifndef QT_NO_VECTOR3D
+
+inline QVector3D operator*(const QVector3D& vector, const QMatrix4x4& matrix)
+{
+ qreal x, y, z, w;
+ x = vector.x() * matrix.m[0][0] +
+ vector.y() * matrix.m[0][1] +
+ vector.z() * matrix.m[0][2] +
+ matrix.m[0][3];
+ y = vector.x() * matrix.m[1][0] +
+ vector.y() * matrix.m[1][1] +
+ vector.z() * matrix.m[1][2] +
+ matrix.m[1][3];
+ z = vector.x() * matrix.m[2][0] +
+ vector.y() * matrix.m[2][1] +
+ vector.z() * matrix.m[2][2] +
+ matrix.m[2][3];
+ w = vector.x() * matrix.m[3][0] +
+ vector.y() * matrix.m[3][1] +
+ vector.z() * matrix.m[3][2] +
+ matrix.m[3][3];
+ if (w == 1.0f)
+ return QVector3D(x, y, z);
+ else
+ return QVector3D(x / w, y / w, z / w);
+}
+
+inline QVector3D operator*(const QMatrix4x4& matrix, const QVector3D& vector)
+{
+ qreal x, y, z, w;
+ if (matrix.flagBits == QMatrix4x4::Identity) {
+ return vector;
+ } else if (matrix.flagBits == QMatrix4x4::Translation) {
+ return QVector3D(vector.x() + matrix.m[3][0],
+ vector.y() + matrix.m[3][1],
+ vector.z() + matrix.m[3][2]);
+ } else if (matrix.flagBits ==
+ (QMatrix4x4::Translation | QMatrix4x4::Scale)) {
+ return QVector3D(vector.x() * matrix.m[0][0] + matrix.m[3][0],
+ vector.y() * matrix.m[1][1] + matrix.m[3][1],
+ vector.z() * matrix.m[2][2] + matrix.m[3][2]);
+ } else if (matrix.flagBits == QMatrix4x4::Scale) {
+ return QVector3D(vector.x() * matrix.m[0][0],
+ vector.y() * matrix.m[1][1],
+ vector.z() * matrix.m[2][2]);
+ } else {
+ x = vector.x() * matrix.m[0][0] +
+ vector.y() * matrix.m[1][0] +
+ vector.z() * matrix.m[2][0] +
+ matrix.m[3][0];
+ y = vector.x() * matrix.m[0][1] +
+ vector.y() * matrix.m[1][1] +
+ vector.z() * matrix.m[2][1] +
+ matrix.m[3][1];
+ z = vector.x() * matrix.m[0][2] +
+ vector.y() * matrix.m[1][2] +
+ vector.z() * matrix.m[2][2] +
+ matrix.m[3][2];
+ w = vector.x() * matrix.m[0][3] +
+ vector.y() * matrix.m[1][3] +
+ vector.z() * matrix.m[2][3] +
+ matrix.m[3][3];
+ if (w == 1.0f)
+ return QVector3D(x, y, z);
+ else
+ return QVector3D(x / w, y / w, z / w);
+ }
+}
+
+#endif
+
+#ifndef QT_NO_VECTOR4D
+
+inline QVector4D operator*(const QVector4D& vector, const QMatrix4x4& matrix)
+{
+ qreal x, y, z, w;
+ x = vector.x() * matrix.m[0][0] +
+ vector.y() * matrix.m[0][1] +
+ vector.z() * matrix.m[0][2] +
+ vector.w() * matrix.m[0][3];
+ y = vector.x() * matrix.m[1][0] +
+ vector.y() * matrix.m[1][1] +
+ vector.z() * matrix.m[1][2] +
+ vector.w() * matrix.m[1][3];
+ z = vector.x() * matrix.m[2][0] +
+ vector.y() * matrix.m[2][1] +
+ vector.z() * matrix.m[2][2] +
+ vector.w() * matrix.m[2][3];
+ w = vector.x() * matrix.m[3][0] +
+ vector.y() * matrix.m[3][1] +
+ vector.z() * matrix.m[3][2] +
+ vector.w() * matrix.m[3][3];
+ return QVector4D(x, y, z, w);
+}
+
+inline QVector4D operator*(const QMatrix4x4& matrix, const QVector4D& vector)
+{
+ qreal x, y, z, w;
+ x = vector.x() * matrix.m[0][0] +
+ vector.y() * matrix.m[1][0] +
+ vector.z() * matrix.m[2][0] +
+ vector.w() * matrix.m[3][0];
+ y = vector.x() * matrix.m[0][1] +
+ vector.y() * matrix.m[1][1] +
+ vector.z() * matrix.m[2][1] +
+ vector.w() * matrix.m[3][1];
+ z = vector.x() * matrix.m[0][2] +
+ vector.y() * matrix.m[1][2] +
+ vector.z() * matrix.m[2][2] +
+ vector.w() * matrix.m[3][2];
+ w = vector.x() * matrix.m[0][3] +
+ vector.y() * matrix.m[1][3] +
+ vector.z() * matrix.m[2][3] +
+ vector.w() * matrix.m[3][3];
+ return QVector4D(x, y, z, w);
+}
+
+#endif
+
+inline QPoint operator*(const QPoint& point, const QMatrix4x4& matrix)
+{
+ qreal xin, yin;
+ qreal x, y, w;
+ xin = point.x();
+ yin = point.y();
+ x = xin * matrix.m[0][0] +
+ yin * matrix.m[0][1] +
+ matrix.m[0][3];
+ y = xin * matrix.m[1][0] +
+ yin * matrix.m[1][1] +
+ matrix.m[1][3];
+ w = xin * matrix.m[3][0] +
+ yin * matrix.m[3][1] +
+ matrix.m[3][3];
+ if (w == 1.0f)
+ return QPoint(qRound(x), qRound(y));
+ else
+ return QPoint(qRound(x / w), qRound(y / w));
+}
+
+inline QPointF operator*(const QPointF& point, const QMatrix4x4& matrix)
+{
+ qreal xin, yin;
+ qreal x, y, w;
+ xin = point.x();
+ yin = point.y();
+ x = xin * matrix.m[0][0] +
+ yin * matrix.m[0][1] +
+ matrix.m[0][3];
+ y = xin * matrix.m[1][0] +
+ yin * matrix.m[1][1] +
+ matrix.m[1][3];
+ w = xin * matrix.m[3][0] +
+ yin * matrix.m[3][1] +
+ matrix.m[3][3];
+ if (w == 1.0f) {
+ return QPointF(qreal(x), qreal(y));
+ } else {
+ return QPointF(qreal(x / w), qreal(y / w));
+ }
+}
+
+inline QPoint operator*(const QMatrix4x4& matrix, const QPoint& point)
+{
+ qreal xin, yin;
+ qreal x, y, w;
+ xin = point.x();
+ yin = point.y();
+ if (matrix.flagBits == QMatrix4x4::Identity) {
+ return point;
+ } else if (matrix.flagBits == QMatrix4x4::Translation) {
+ return QPoint(qRound(xin + matrix.m[3][0]),
+ qRound(yin + matrix.m[3][1]));
+ } else if (matrix.flagBits ==
+ (QMatrix4x4::Translation | QMatrix4x4::Scale)) {
+ return QPoint(qRound(xin * matrix.m[0][0] + matrix.m[3][0]),
+ qRound(yin * matrix.m[1][1] + matrix.m[3][1]));
+ } else if (matrix.flagBits == QMatrix4x4::Scale) {
+ return QPoint(qRound(xin * matrix.m[0][0]),
+ qRound(yin * matrix.m[1][1]));
+ } else {
+ x = xin * matrix.m[0][0] +
+ yin * matrix.m[1][0] +
+ matrix.m[3][0];
+ y = xin * matrix.m[0][1] +
+ yin * matrix.m[1][1] +
+ matrix.m[3][1];
+ w = xin * matrix.m[0][3] +
+ yin * matrix.m[1][3] +
+ matrix.m[3][3];
+ if (w == 1.0f)
+ return QPoint(qRound(x), qRound(y));
+ else
+ return QPoint(qRound(x / w), qRound(y / w));
+ }
+}
+
+inline QPointF operator*(const QMatrix4x4& matrix, const QPointF& point)
+{
+ qreal xin, yin;
+ qreal x, y, w;
+ xin = point.x();
+ yin = point.y();
+ if (matrix.flagBits == QMatrix4x4::Identity) {
+ return point;
+ } else if (matrix.flagBits == QMatrix4x4::Translation) {
+ return QPointF(xin + matrix.m[3][0],
+ yin + matrix.m[3][1]);
+ } else if (matrix.flagBits ==
+ (QMatrix4x4::Translation | QMatrix4x4::Scale)) {
+ return QPointF(xin * matrix.m[0][0] + matrix.m[3][0],
+ yin * matrix.m[1][1] + matrix.m[3][1]);
+ } else if (matrix.flagBits == QMatrix4x4::Scale) {
+ return QPointF(xin * matrix.m[0][0],
+ yin * matrix.m[1][1]);
+ } else {
+ x = xin * matrix.m[0][0] +
+ yin * matrix.m[1][0] +
+ matrix.m[3][0];
+ y = xin * matrix.m[0][1] +
+ yin * matrix.m[1][1] +
+ matrix.m[3][1];
+ w = xin * matrix.m[0][3] +
+ yin * matrix.m[1][3] +
+ matrix.m[3][3];
+ if (w == 1.0f) {
+ return QPointF(qreal(x), qreal(y));
+ } else {
+ return QPointF(qreal(x / w), qreal(y / w));
+ }
+ }
+}
+
+inline QMatrix4x4 operator-(const QMatrix4x4& matrix)
+{
+ QMatrix4x4 m(1);
+ m.m[0][0] = -matrix.m[0][0];
+ m.m[0][1] = -matrix.m[0][1];
+ m.m[0][2] = -matrix.m[0][2];
+ m.m[0][3] = -matrix.m[0][3];
+ m.m[1][0] = -matrix.m[1][0];
+ m.m[1][1] = -matrix.m[1][1];
+ m.m[1][2] = -matrix.m[1][2];
+ m.m[1][3] = -matrix.m[1][3];
+ m.m[2][0] = -matrix.m[2][0];
+ m.m[2][1] = -matrix.m[2][1];
+ m.m[2][2] = -matrix.m[2][2];
+ m.m[2][3] = -matrix.m[2][3];
+ m.m[3][0] = -matrix.m[3][0];
+ m.m[3][1] = -matrix.m[3][1];
+ m.m[3][2] = -matrix.m[3][2];
+ m.m[3][3] = -matrix.m[3][3];
+ return m;
+}
+
+inline QMatrix4x4 operator*(qreal factor, const QMatrix4x4& matrix)
+{
+ QMatrix4x4 m(1);
+ m.m[0][0] = matrix.m[0][0] * factor;
+ m.m[0][1] = matrix.m[0][1] * factor;
+ m.m[0][2] = matrix.m[0][2] * factor;
+ m.m[0][3] = matrix.m[0][3] * factor;
+ m.m[1][0] = matrix.m[1][0] * factor;
+ m.m[1][1] = matrix.m[1][1] * factor;
+ m.m[1][2] = matrix.m[1][2] * factor;
+ m.m[1][3] = matrix.m[1][3] * factor;
+ m.m[2][0] = matrix.m[2][0] * factor;
+ m.m[2][1] = matrix.m[2][1] * factor;
+ m.m[2][2] = matrix.m[2][2] * factor;
+ m.m[2][3] = matrix.m[2][3] * factor;
+ m.m[3][0] = matrix.m[3][0] * factor;
+ m.m[3][1] = matrix.m[3][1] * factor;
+ m.m[3][2] = matrix.m[3][2] * factor;
+ m.m[3][3] = matrix.m[3][3] * factor;
+ return m;
+}
+
+inline QMatrix4x4 operator*(const QMatrix4x4& matrix, qreal factor)
+{
+ QMatrix4x4 m(1);
+ m.m[0][0] = matrix.m[0][0] * factor;
+ m.m[0][1] = matrix.m[0][1] * factor;
+ m.m[0][2] = matrix.m[0][2] * factor;
+ m.m[0][3] = matrix.m[0][3] * factor;
+ m.m[1][0] = matrix.m[1][0] * factor;
+ m.m[1][1] = matrix.m[1][1] * factor;
+ m.m[1][2] = matrix.m[1][2] * factor;
+ m.m[1][3] = matrix.m[1][3] * factor;
+ m.m[2][0] = matrix.m[2][0] * factor;
+ m.m[2][1] = matrix.m[2][1] * factor;
+ m.m[2][2] = matrix.m[2][2] * factor;
+ m.m[2][3] = matrix.m[2][3] * factor;
+ m.m[3][0] = matrix.m[3][0] * factor;
+ m.m[3][1] = matrix.m[3][1] * factor;
+ m.m[3][2] = matrix.m[3][2] * factor;
+ m.m[3][3] = matrix.m[3][3] * factor;
+ return m;
+}
+
+inline bool qFuzzyCompare(const QMatrix4x4& m1, const QMatrix4x4& m2)
+{
+ return qFuzzyCompare(m1.m[0][0], m2.m[0][0]) &&
+ qFuzzyCompare(m1.m[0][1], m2.m[0][1]) &&
+ qFuzzyCompare(m1.m[0][2], m2.m[0][2]) &&
+ qFuzzyCompare(m1.m[0][3], m2.m[0][3]) &&
+ qFuzzyCompare(m1.m[1][0], m2.m[1][0]) &&
+ qFuzzyCompare(m1.m[1][1], m2.m[1][1]) &&
+ qFuzzyCompare(m1.m[1][2], m2.m[1][2]) &&
+ qFuzzyCompare(m1.m[1][3], m2.m[1][3]) &&
+ qFuzzyCompare(m1.m[2][0], m2.m[2][0]) &&
+ qFuzzyCompare(m1.m[2][1], m2.m[2][1]) &&
+ qFuzzyCompare(m1.m[2][2], m2.m[2][2]) &&
+ qFuzzyCompare(m1.m[2][3], m2.m[2][3]) &&
+ qFuzzyCompare(m1.m[3][0], m2.m[3][0]) &&
+ qFuzzyCompare(m1.m[3][1], m2.m[3][1]) &&
+ qFuzzyCompare(m1.m[3][2], m2.m[3][2]) &&
+ qFuzzyCompare(m1.m[3][3], m2.m[3][3]);
+}
+
+inline QPoint QMatrix4x4::map(const QPoint& point) const
+{
+ return *this * point;
+}
+
+inline QPointF QMatrix4x4::map(const QPointF& point) const
+{
+ return *this * point;
+}
+
+#ifndef QT_NO_VECTOR3D
+
+inline QVector3D QMatrix4x4::map(const QVector3D& point) const
+{
+ return *this * point;
+}
+
+inline QVector3D QMatrix4x4::mapVector(const QVector3D& vector) const
+{
+ if (flagBits == Identity || flagBits == Translation) {
+ return vector;
+ } else if (flagBits == Scale || flagBits == (Translation | Scale)) {
+ return QVector3D(vector.x() * m[0][0],
+ vector.y() * m[1][1],
+ vector.z() * m[2][2]);
+ } else {
+ return QVector3D(vector.x() * m[0][0] +
+ vector.y() * m[1][0] +
+ vector.z() * m[2][0],
+ vector.x() * m[0][1] +
+ vector.y() * m[1][1] +
+ vector.z() * m[2][1],
+ vector.x() * m[0][2] +
+ vector.y() * m[1][2] +
+ vector.z() * m[2][2]);
+ }
+}
+
+#endif
+
+#ifndef QT_NO_VECTOR4D
+
+inline QVector4D QMatrix4x4::map(const QVector4D& point) const
+{
+ return *this * point;
+}
+
+#endif
+
+inline qreal *QMatrix4x4::data()
+{
+ // We have to assume that the caller will modify the matrix elements,
+ // so we flip it over to "General" mode.
+ flagBits = General;
+ return *m;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QMatrix4x4 &m);
+#endif
+
+#ifndef QT_NO_DATASTREAM
+Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QMatrix4x4 &);
+Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QMatrix4x4 &);
+#endif
+
+#ifdef QT_DEPRECATED
+template <int N, int M>
+QT_DEPRECATED QMatrix4x4 qGenericMatrixToMatrix4x4(const QGenericMatrix<N, M, qreal>& matrix)
+{
+ return QMatrix4x4(matrix.constData(), N, M);
+}
+
+template <int N, int M>
+QT_DEPRECATED QGenericMatrix<N, M, qreal> qGenericMatrixFromMatrix4x4(const QMatrix4x4& matrix)
+{
+ QGenericMatrix<N, M, qreal> result;
+ const qreal *m = matrix.constData();
+ qreal *values = result.data();
+ for (int col = 0; col < N; ++col) {
+ for (int row = 0; row < M; ++row) {
+ if (col < 4 && row < 4)
+ values[col * M + row] = m[col * 4 + row];
+ else if (col == row)
+ values[col * M + row] = 1.0f;
+ else
+ values[col * M + row] = 0.0f;
+ }
+ }
+ return result;
+}
+#endif
+
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/gui/math3d/qquaternion.cpp b/src/gui/math3d/qquaternion.cpp
new file mode 100644
index 0000000000..0819afe783
--- /dev/null
+++ b/src/gui/math3d/qquaternion.cpp
@@ -0,0 +1,636 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquaternion.h"
+#include <QtCore/qmath.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_QUATERNION
+
+/*!
+ \class QQuaternion
+ \brief The QQuaternion class represents a quaternion consisting of a vector and scalar.
+ \since 4.6
+ \ingroup painting-3D
+
+ Quaternions are used to represent rotations in 3D space, and
+ consist of a 3D rotation axis specified by the x, y, and z
+ coordinates, and a scalar representing the rotation angle.
+*/
+
+/*!
+ \fn QQuaternion::QQuaternion()
+
+ Constructs an identity quaternion, i.e. with coordinates (1, 0, 0, 0).
+*/
+
+/*!
+ \fn QQuaternion::QQuaternion(qreal scalar, qreal xpos, qreal ypos, qreal zpos)
+
+ Constructs a quaternion with the vector (\a xpos, \a ypos, \a zpos)
+ and \a scalar.
+*/
+
+#ifndef QT_NO_VECTOR3D
+
+/*!
+ \fn QQuaternion::QQuaternion(qreal scalar, const QVector3D& vector)
+
+ Constructs a quaternion vector from the specified \a vector and
+ \a scalar.
+
+ \sa vector(), scalar()
+*/
+
+/*!
+ \fn QVector3D QQuaternion::vector() const
+
+ Returns the vector component of this quaternion.
+
+ \sa setVector(), scalar()
+*/
+
+/*!
+ \fn void QQuaternion::setVector(const QVector3D& vector)
+
+ Sets the vector component of this quaternion to \a vector.
+
+ \sa vector(), setScalar()
+*/
+
+#endif
+
+/*!
+ \fn void QQuaternion::setVector(qreal x, qreal y, qreal z)
+
+ Sets the vector component of this quaternion to (\a x, \a y, \a z).
+
+ \sa vector(), setScalar()
+*/
+
+#ifndef QT_NO_VECTOR4D
+
+/*!
+ \fn QQuaternion::QQuaternion(const QVector4D& vector)
+
+ Constructs a quaternion from the components of \a vector.
+*/
+
+/*!
+ \fn QVector4D QQuaternion::toVector4D() const
+
+ Returns this quaternion as a 4D vector.
+*/
+
+#endif
+
+/*!
+ \fn bool QQuaternion::isNull() const
+
+ Returns true if the x, y, z, and scalar components of this
+ quaternion are set to 0.0; otherwise returns false.
+*/
+
+/*!
+ \fn bool QQuaternion::isIdentity() const
+
+ Returns true if the x, y, and z components of this
+ quaternion are set to 0.0, and the scalar component is set
+ to 1.0; otherwise returns false.
+*/
+
+/*!
+ \fn qreal QQuaternion::x() const
+
+ Returns the x coordinate of this quaternion's vector.
+
+ \sa setX(), y(), z(), scalar()
+*/
+
+/*!
+ \fn qreal QQuaternion::y() const
+
+ Returns the y coordinate of this quaternion's vector.
+
+ \sa setY(), x(), z(), scalar()
+*/
+
+/*!
+ \fn qreal QQuaternion::z() const
+
+ Returns the z coordinate of this quaternion's vector.
+
+ \sa setZ(), x(), y(), scalar()
+*/
+
+/*!
+ \fn qreal QQuaternion::scalar() const
+
+ Returns the scalar component of this quaternion.
+
+ \sa setScalar(), x(), y(), z()
+*/
+
+/*!
+ \fn void QQuaternion::setX(qreal x)
+
+ Sets the x coordinate of this quaternion's vector to the given
+ \a x coordinate.
+
+ \sa x(), setY(), setZ(), setScalar()
+*/
+
+/*!
+ \fn void QQuaternion::setY(qreal y)
+
+ Sets the y coordinate of this quaternion's vector to the given
+ \a y coordinate.
+
+ \sa y(), setX(), setZ(), setScalar()
+*/
+
+/*!
+ \fn void QQuaternion::setZ(qreal z)
+
+ Sets the z coordinate of this quaternion's vector to the given
+ \a z coordinate.
+
+ \sa z(), setX(), setY(), setScalar()
+*/
+
+/*!
+ \fn void QQuaternion::setScalar(qreal scalar)
+
+ Sets the scalar component of this quaternion to \a scalar.
+
+ \sa scalar(), setX(), setY(), setZ()
+*/
+
+/*!
+ Returns the length of the quaternion. This is also called the "norm".
+
+ \sa lengthSquared(), normalized()
+*/
+qreal QQuaternion::length() const
+{
+ return qSqrt(xp * xp + yp * yp + zp * zp + wp * wp);
+}
+
+/*!
+ Returns the squared length of the quaternion.
+
+ \sa length()
+*/
+qreal QQuaternion::lengthSquared() const
+{
+ return xp * xp + yp * yp + zp * zp + wp * wp;
+}
+
+/*!
+ Returns the normalized unit form of this quaternion.
+
+ If this quaternion is null, then a null quaternion is returned.
+ If the length of the quaternion is very close to 1, then the quaternion
+ will be returned as-is. Otherwise the normalized form of the
+ quaternion of length 1 will be returned.
+
+ \sa length(), normalize()
+*/
+QQuaternion QQuaternion::normalized() const
+{
+ // Need some extra precision if the length is very small.
+ double len = double(xp) * double(xp) +
+ double(yp) * double(yp) +
+ double(zp) * double(zp) +
+ double(wp) * double(wp);
+ if (qFuzzyIsNull(len - 1.0f))
+ return *this;
+ else if (!qFuzzyIsNull(len))
+ return *this / qSqrt(len);
+ else
+ return QQuaternion(0.0f, 0.0f, 0.0f, 0.0f);
+}
+
+/*!
+ Normalizes the currect quaternion in place. Nothing happens if this
+ is a null quaternion or the length of the quaternion is very close to 1.
+
+ \sa length(), normalized()
+*/
+void QQuaternion::normalize()
+{
+ // Need some extra precision if the length is very small.
+ double len = double(xp) * double(xp) +
+ double(yp) * double(yp) +
+ double(zp) * double(zp) +
+ double(wp) * double(wp);
+ if (qFuzzyIsNull(len - 1.0f) || qFuzzyIsNull(len))
+ return;
+
+ len = qSqrt(len);
+
+ xp /= len;
+ yp /= len;
+ zp /= len;
+ wp /= len;
+}
+
+/*!
+ \fn QQuaternion QQuaternion::conjugate() const
+
+ Returns the conjugate of this quaternion, which is
+ (-x, -y, -z, scalar).
+*/
+
+/*!
+ Rotates \a vector with this quaternion to produce a new vector
+ in 3D space. The following code:
+
+ \code
+ QVector3D result = q.rotatedVector(vector);
+ \endcode
+
+ is equivalent to the following:
+
+ \code
+ QVector3D result = (q * QQuaternion(0, vector) * q.conjugate()).vector();
+ \endcode
+*/
+QVector3D QQuaternion::rotatedVector(const QVector3D& vector) const
+{
+ return (*this * QQuaternion(0, vector) * conjugate()).vector();
+}
+
+/*!
+ \fn QQuaternion &QQuaternion::operator+=(const QQuaternion &quaternion)
+
+ Adds the given \a quaternion to this quaternion and returns a reference to
+ this quaternion.
+
+ \sa operator-=()
+*/
+
+/*!
+ \fn QQuaternion &QQuaternion::operator-=(const QQuaternion &quaternion)
+
+ Subtracts the given \a quaternion from this quaternion and returns a
+ reference to this quaternion.
+
+ \sa operator+=()
+*/
+
+/*!
+ \fn QQuaternion &QQuaternion::operator*=(qreal factor)
+
+ Multiplies this quaternion's components by the given \a factor, and
+ returns a reference to this quaternion.
+
+ \sa operator/=()
+*/
+
+/*!
+ \fn QQuaternion &QQuaternion::operator*=(const QQuaternion &quaternion)
+
+ Multiplies this quaternion by \a quaternion and returns a reference
+ to this quaternion.
+*/
+
+/*!
+ \fn QQuaternion &QQuaternion::operator/=(qreal divisor)
+
+ Divides this quaternion's components by the given \a divisor, and
+ returns a reference to this quaternion.
+
+ \sa operator*=()
+*/
+
+#ifndef QT_NO_VECTOR3D
+
+/*!
+ Creates a normalized quaternion that corresponds to rotating through
+ \a angle degrees about the specified 3D \a axis.
+*/
+QQuaternion QQuaternion::fromAxisAndAngle(const QVector3D& axis, qreal angle)
+{
+ // Algorithm from:
+ // http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q56
+ // We normalize the result just in case the values are close
+ // to zero, as suggested in the above FAQ.
+ qreal a = (angle / 2.0f) * M_PI / 180.0f;
+ qreal s = qSin(a);
+ qreal c = qCos(a);
+ QVector3D ax = axis.normalized();
+ return QQuaternion(c, ax.x() * s, ax.y() * s, ax.z() * s).normalized();
+}
+
+#endif
+
+/*!
+ Creates a normalized quaternion that corresponds to rotating through
+ \a angle degrees about the 3D axis (\a x, \a y, \a z).
+*/
+QQuaternion QQuaternion::fromAxisAndAngle
+ (qreal x, qreal y, qreal z, qreal angle)
+{
+ qreal length = qSqrt(x * x + y * y + z * z);
+ if (!qFuzzyIsNull(length - 1.0f) && !qFuzzyIsNull(length)) {
+ x /= length;
+ y /= length;
+ z /= length;
+ }
+ qreal a = (angle / 2.0f) * M_PI / 180.0f;
+ qreal s = qSin(a);
+ qreal c = qCos(a);
+ return QQuaternion(c, x * s, y * s, z * s).normalized();
+}
+
+/*!
+ \fn bool operator==(const QQuaternion &q1, const QQuaternion &q2)
+ \relates QQuaternion
+
+ Returns true if \a q1 is equal to \a q2; otherwise returns false.
+ This operator uses an exact floating-point comparison.
+*/
+
+/*!
+ \fn bool operator!=(const QQuaternion &q1, const QQuaternion &q2)
+ \relates QQuaternion
+
+ Returns true if \a q1 is not equal to \a q2; otherwise returns false.
+ This operator uses an exact floating-point comparison.
+*/
+
+/*!
+ \fn const QQuaternion operator+(const QQuaternion &q1, const QQuaternion &q2)
+ \relates QQuaternion
+
+ Returns a QQuaternion object that is the sum of the given quaternions,
+ \a q1 and \a q2; each component is added separately.
+
+ \sa QQuaternion::operator+=()
+*/
+
+/*!
+ \fn const QQuaternion operator-(const QQuaternion &q1, const QQuaternion &q2)
+ \relates QQuaternion
+
+ Returns a QQuaternion object that is formed by subtracting
+ \a q2 from \a q1; each component is subtracted separately.
+
+ \sa QQuaternion::operator-=()
+*/
+
+/*!
+ \fn const QQuaternion operator*(qreal factor, const QQuaternion &quaternion)
+ \relates QQuaternion
+
+ Returns a copy of the given \a quaternion, multiplied by the
+ given \a factor.
+
+ \sa QQuaternion::operator*=()
+*/
+
+/*!
+ \fn const QQuaternion operator*(const QQuaternion &quaternion, qreal factor)
+ \relates QQuaternion
+
+ Returns a copy of the given \a quaternion, multiplied by the
+ given \a factor.
+
+ \sa QQuaternion::operator*=()
+*/
+
+/*!
+ \fn const QQuaternion operator*(const QQuaternion &q1, const QQuaternion& q2)
+ \relates QQuaternion
+
+ Multiplies \a q1 and \a q2 using quaternion multiplication.
+ The result corresponds to applying both of the rotations specified
+ by \a q1 and \a q2.
+
+ \sa QQuaternion::operator*=()
+*/
+
+/*!
+ \fn const QQuaternion operator-(const QQuaternion &quaternion)
+ \relates QQuaternion
+ \overload
+
+ Returns a QQuaternion object that is formed by changing the sign of
+ all three components of the given \a quaternion.
+
+ Equivalent to \c {QQuaternion(0,0,0,0) - quaternion}.
+*/
+
+/*!
+ \fn const QQuaternion operator/(const QQuaternion &quaternion, qreal divisor)
+ \relates QQuaternion
+
+ Returns the QQuaternion object formed by dividing all components of
+ the given \a quaternion by the given \a divisor.
+
+ \sa QQuaternion::operator/=()
+*/
+
+/*!
+ \fn bool qFuzzyCompare(const QQuaternion& q1, const QQuaternion& q2)
+ \relates QQuaternion
+
+ Returns true if \a q1 and \a q2 are equal, allowing for a small
+ fuzziness factor for floating-point comparisons; false otherwise.
+*/
+
+/*!
+ Interpolates along the shortest spherical path between the
+ rotational positions \a q1 and \a q2. The value \a t should
+ be between 0 and 1, indicating the spherical distance to travel
+ between \a q1 and \a q2.
+
+ If \a t is less than or equal to 0, then \a q1 will be returned.
+ If \a t is greater than or equal to 1, then \a q2 will be returned.
+
+ \sa nlerp()
+*/
+QQuaternion QQuaternion::slerp
+ (const QQuaternion& q1, const QQuaternion& q2, qreal t)
+{
+ // Handle the easy cases first.
+ if (t <= 0.0f)
+ return q1;
+ else if (t >= 1.0f)
+ return q2;
+
+ // Determine the angle between the two quaternions.
+ QQuaternion q2b;
+ qreal dot;
+ dot = q1.xp * q2.xp + q1.yp * q2.yp + q1.zp * q2.zp + q1.wp * q2.wp;
+ if (dot >= 0.0f) {
+ q2b = q2;
+ } else {
+ q2b = -q2;
+ dot = -dot;
+ }
+
+ // Get the scale factors. If they are too small,
+ // then revert to simple linear interpolation.
+ qreal factor1 = 1.0f - t;
+ qreal factor2 = t;
+ if ((1.0f - dot) > 0.0000001) {
+ qreal angle = qreal(qAcos(dot));
+ qreal sinOfAngle = qreal(qSin(angle));
+ if (sinOfAngle > 0.0000001) {
+ factor1 = qreal(qSin((1.0f - t) * angle)) / sinOfAngle;
+ factor2 = qreal(qSin(t * angle)) / sinOfAngle;
+ }
+ }
+
+ // Construct the result quaternion.
+ return q1 * factor1 + q2b * factor2;
+}
+
+/*!
+ Interpolates along the shortest linear path between the rotational
+ positions \a q1 and \a q2. The value \a t should be between 0 and 1,
+ indicating the distance to travel between \a q1 and \a q2.
+ The result will be normalized().
+
+ If \a t is less than or equal to 0, then \a q1 will be returned.
+ If \a t is greater than or equal to 1, then \a q2 will be returned.
+
+ The nlerp() function is typically faster than slerp() and will
+ give approximate results to spherical interpolation that are
+ good enough for some applications.
+
+ \sa slerp()
+*/
+QQuaternion QQuaternion::nlerp
+ (const QQuaternion& q1, const QQuaternion& q2, qreal t)
+{
+ // Handle the easy cases first.
+ if (t <= 0.0f)
+ return q1;
+ else if (t >= 1.0f)
+ return q2;
+
+ // Determine the angle between the two quaternions.
+ QQuaternion q2b;
+ qreal dot;
+ dot = q1.xp * q2.xp + q1.yp * q2.yp + q1.zp * q2.zp + q1.wp * q2.wp;
+ if (dot >= 0.0f)
+ q2b = q2;
+ else
+ q2b = -q2;
+
+ // Perform the linear interpolation.
+ return (q1 * (1.0f - t) + q2b * t).normalized();
+}
+
+/*!
+ Returns the quaternion as a QVariant.
+*/
+QQuaternion::operator QVariant() const
+{
+ return QVariant(QVariant::Quaternion, this);
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+
+QDebug operator<<(QDebug dbg, const QQuaternion &q)
+{
+ dbg.nospace() << "QQuaternion(scalar:" << q.scalar()
+ << ", vector:(" << q.x() << ", "
+ << q.y() << ", " << q.z() << "))";
+ return dbg.space();
+}
+
+#endif
+
+#ifndef QT_NO_DATASTREAM
+
+/*!
+ \fn QDataStream &operator<<(QDataStream &stream, const QQuaternion &quaternion)
+ \relates QQuaternion
+
+ Writes the given \a quaternion to the given \a stream and returns a
+ reference to the stream.
+
+ \sa {Serializing Qt Data Types}
+*/
+
+QDataStream &operator<<(QDataStream &stream, const QQuaternion &quaternion)
+{
+ stream << double(quaternion.scalar()) << double(quaternion.x())
+ << double(quaternion.y()) << double(quaternion.z());
+ return stream;
+}
+
+/*!
+ \fn QDataStream &operator>>(QDataStream &stream, QQuaternion &quaternion)
+ \relates QQuaternion
+
+ Reads a quaternion from the given \a stream into the given \a quaternion
+ and returns a reference to the stream.
+
+ \sa {Serializing Qt Data Types}
+*/
+
+QDataStream &operator>>(QDataStream &stream, QQuaternion &quaternion)
+{
+ double scalar, x, y, z;
+ stream >> scalar;
+ stream >> x;
+ stream >> y;
+ stream >> z;
+ quaternion.setScalar(qreal(scalar));
+ quaternion.setX(qreal(x));
+ quaternion.setY(qreal(y));
+ quaternion.setZ(qreal(z));
+ return stream;
+}
+
+#endif // QT_NO_DATASTREAM
+
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/gui/math3d/qquaternion.h b/src/gui/math3d/qquaternion.h
new file mode 100644
index 0000000000..24c41a01ea
--- /dev/null
+++ b/src/gui/math3d/qquaternion.h
@@ -0,0 +1,330 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUATERNION_H
+#define QQUATERNION_H
+
+#include <QtGui/qvector3d.h>
+#include <QtGui/qvector4d.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_QUATERNION
+
+class QMatrix4x4;
+class QVariant;
+
+class Q_GUI_EXPORT QQuaternion
+{
+public:
+ QQuaternion();
+ QQuaternion(qreal scalar, qreal xpos, qreal ypos, qreal zpos);
+#ifndef QT_NO_VECTOR3D
+ QQuaternion(qreal scalar, const QVector3D& vector);
+#endif
+#ifndef QT_NO_VECTOR4D
+ explicit QQuaternion(const QVector4D& vector);
+#endif
+
+ bool isNull() const;
+ bool isIdentity() const;
+
+#ifndef QT_NO_VECTOR3D
+ QVector3D vector() const;
+ void setVector(const QVector3D& vector);
+#endif
+ void setVector(qreal x, qreal y, qreal z);
+
+ qreal x() const;
+ qreal y() const;
+ qreal z() const;
+ qreal scalar() const;
+
+ void setX(qreal x);
+ void setY(qreal y);
+ void setZ(qreal z);
+ void setScalar(qreal scalar);
+
+ qreal length() const;
+ qreal lengthSquared() const;
+
+ QQuaternion normalized() const;
+ void normalize();
+
+ QQuaternion conjugate() const;
+
+ QVector3D rotatedVector(const QVector3D& vector) const;
+
+ QQuaternion &operator+=(const QQuaternion &quaternion);
+ QQuaternion &operator-=(const QQuaternion &quaternion);
+ QQuaternion &operator*=(qreal factor);
+ QQuaternion &operator*=(const QQuaternion &quaternion);
+ QQuaternion &operator/=(qreal divisor);
+
+ friend inline bool operator==(const QQuaternion &q1, const QQuaternion &q2);
+ friend inline bool operator!=(const QQuaternion &q1, const QQuaternion &q2);
+ friend inline const QQuaternion operator+(const QQuaternion &q1, const QQuaternion &q2);
+ friend inline const QQuaternion operator-(const QQuaternion &q1, const QQuaternion &q2);
+ friend inline const QQuaternion operator*(qreal factor, const QQuaternion &quaternion);
+ friend inline const QQuaternion operator*(const QQuaternion &quaternion, qreal factor);
+ friend inline const QQuaternion operator*(const QQuaternion &q1, const QQuaternion& q2);
+ friend inline const QQuaternion operator-(const QQuaternion &quaternion);
+ friend inline const QQuaternion operator/(const QQuaternion &quaternion, qreal divisor);
+
+ friend inline bool qFuzzyCompare(const QQuaternion& q1, const QQuaternion& q2);
+
+#ifndef QT_NO_VECTOR4D
+ QVector4D toVector4D() const;
+#endif
+
+ operator QVariant() const;
+
+#ifndef QT_NO_VECTOR3D
+ static QQuaternion fromAxisAndAngle(const QVector3D& axis, qreal angle);
+#endif
+ static QQuaternion fromAxisAndAngle
+ (qreal x, qreal y, qreal z, qreal angle);
+
+ static QQuaternion slerp
+ (const QQuaternion& q1, const QQuaternion& q2, qreal t);
+ static QQuaternion nlerp
+ (const QQuaternion& q1, const QQuaternion& q2, qreal t);
+
+private:
+ qreal wp, xp, yp, zp;
+};
+
+Q_DECLARE_TYPEINFO(QQuaternion, Q_MOVABLE_TYPE);
+
+inline QQuaternion::QQuaternion() : wp(1.0f), xp(0.0f), yp(0.0f), zp(0.0f) {}
+
+inline QQuaternion::QQuaternion(qreal aScalar, qreal xpos, qreal ypos, qreal zpos) : wp(aScalar), xp(xpos), yp(ypos), zp(zpos) {}
+
+
+inline bool QQuaternion::isNull() const
+{
+ return qIsNull(xp) && qIsNull(yp) && qIsNull(zp) && qIsNull(wp);
+}
+
+inline bool QQuaternion::isIdentity() const
+{
+ return qIsNull(xp) && qIsNull(yp) && qIsNull(zp) && wp == 1.0f;
+}
+
+inline qreal QQuaternion::x() const { return qreal(xp); }
+inline qreal QQuaternion::y() const { return qreal(yp); }
+inline qreal QQuaternion::z() const { return qreal(zp); }
+inline qreal QQuaternion::scalar() const { return qreal(wp); }
+
+inline void QQuaternion::setX(qreal aX) { xp = aX; }
+inline void QQuaternion::setY(qreal aY) { yp = aY; }
+inline void QQuaternion::setZ(qreal aZ) { zp = aZ; }
+inline void QQuaternion::setScalar(qreal aScalar) { wp = aScalar; }
+
+inline QQuaternion QQuaternion::conjugate() const
+{
+ return QQuaternion(wp, -xp, -yp, -zp);
+}
+
+inline QQuaternion &QQuaternion::operator+=(const QQuaternion &quaternion)
+{
+ xp += quaternion.xp;
+ yp += quaternion.yp;
+ zp += quaternion.zp;
+ wp += quaternion.wp;
+ return *this;
+}
+
+inline QQuaternion &QQuaternion::operator-=(const QQuaternion &quaternion)
+{
+ xp -= quaternion.xp;
+ yp -= quaternion.yp;
+ zp -= quaternion.zp;
+ wp -= quaternion.wp;
+ return *this;
+}
+
+inline QQuaternion &QQuaternion::operator*=(qreal factor)
+{
+ xp *= factor;
+ yp *= factor;
+ zp *= factor;
+ wp *= factor;
+ return *this;
+}
+
+inline const QQuaternion operator*(const QQuaternion &q1, const QQuaternion& q2)
+{
+ qreal ww = (q1.zp + q1.xp) * (q2.xp + q2.yp);
+ qreal yy = (q1.wp - q1.yp) * (q2.wp + q2.zp);
+ qreal zz = (q1.wp + q1.yp) * (q2.wp - q2.zp);
+ qreal xx = ww + yy + zz;
+ qreal qq = 0.5 * (xx + (q1.zp - q1.xp) * (q2.xp - q2.yp));
+
+ qreal w = qq - ww + (q1.zp - q1.yp) * (q2.yp - q2.zp);
+ qreal x = qq - xx + (q1.xp + q1.wp) * (q2.xp + q2.wp);
+ qreal y = qq - yy + (q1.wp - q1.xp) * (q2.yp + q2.zp);
+ qreal z = qq - zz + (q1.zp + q1.yp) * (q2.wp - q2.xp);
+
+ return QQuaternion(w, x, y, z);
+}
+
+inline QQuaternion &QQuaternion::operator*=(const QQuaternion &quaternion)
+{
+ *this = *this * quaternion;
+ return *this;
+}
+
+inline QQuaternion &QQuaternion::operator/=(qreal divisor)
+{
+ xp /= divisor;
+ yp /= divisor;
+ zp /= divisor;
+ wp /= divisor;
+ return *this;
+}
+
+inline bool operator==(const QQuaternion &q1, const QQuaternion &q2)
+{
+ return q1.xp == q2.xp && q1.yp == q2.yp && q1.zp == q2.zp && q1.wp == q2.wp;
+}
+
+inline bool operator!=(const QQuaternion &q1, const QQuaternion &q2)
+{
+ return q1.xp != q2.xp || q1.yp != q2.yp || q1.zp != q2.zp || q1.wp != q2.wp;
+}
+
+inline const QQuaternion operator+(const QQuaternion &q1, const QQuaternion &q2)
+{
+ return QQuaternion(q1.wp + q2.wp, q1.xp + q2.xp, q1.yp + q2.yp, q1.zp + q2.zp);
+}
+
+inline const QQuaternion operator-(const QQuaternion &q1, const QQuaternion &q2)
+{
+ return QQuaternion(q1.wp - q2.wp, q1.xp - q2.xp, q1.yp - q2.yp, q1.zp - q2.zp);
+}
+
+inline const QQuaternion operator*(qreal factor, const QQuaternion &quaternion)
+{
+ return QQuaternion(quaternion.wp * factor, quaternion.xp * factor, quaternion.yp * factor, quaternion.zp * factor);
+}
+
+inline const QQuaternion operator*(const QQuaternion &quaternion, qreal factor)
+{
+ return QQuaternion(quaternion.wp * factor, quaternion.xp * factor, quaternion.yp * factor, quaternion.zp * factor);
+}
+
+inline const QQuaternion operator-(const QQuaternion &quaternion)
+{
+ return QQuaternion(-quaternion.wp, -quaternion.xp, -quaternion.yp, -quaternion.zp);
+}
+
+inline const QQuaternion operator/(const QQuaternion &quaternion, qreal divisor)
+{
+ return QQuaternion(quaternion.wp / divisor, quaternion.xp / divisor, quaternion.yp / divisor, quaternion.zp / divisor);
+}
+
+inline bool qFuzzyCompare(const QQuaternion& q1, const QQuaternion& q2)
+{
+ return qFuzzyCompare(q1.xp, q2.xp) &&
+ qFuzzyCompare(q1.yp, q2.yp) &&
+ qFuzzyCompare(q1.zp, q2.zp) &&
+ qFuzzyCompare(q1.wp, q2.wp);
+}
+
+#ifndef QT_NO_VECTOR3D
+
+inline QQuaternion::QQuaternion(qreal aScalar, const QVector3D& aVector)
+ : wp(aScalar), xp(aVector.x()), yp(aVector.y()), zp(aVector.z()) {}
+
+inline void QQuaternion::setVector(const QVector3D& aVector)
+{
+ xp = aVector.x();
+ yp = aVector.y();
+ zp = aVector.z();
+}
+
+inline QVector3D QQuaternion::vector() const
+{
+ return QVector3D(xp, yp, zp);
+}
+
+#endif
+
+inline void QQuaternion::setVector(qreal aX, qreal aY, qreal aZ)
+{
+ xp = aX;
+ yp = aY;
+ zp = aZ;
+}
+
+#ifndef QT_NO_VECTOR4D
+
+inline QQuaternion::QQuaternion(const QVector4D& aVector)
+ : wp(aVector.w()), xp(aVector.x()), yp(aVector.y()), zp(aVector.z()) {}
+
+inline QVector4D QQuaternion::toVector4D() const
+{
+ return QVector4D(xp, yp, zp, wp);
+}
+
+#endif
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QQuaternion &q);
+#endif
+
+#ifndef QT_NO_DATASTREAM
+Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QQuaternion &);
+Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QQuaternion &);
+#endif
+
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/gui/math3d/qvector2d.cpp b/src/gui/math3d/qvector2d.cpp
new file mode 100644
index 0000000000..1fccfc9f88
--- /dev/null
+++ b/src/gui/math3d/qvector2d.cpp
@@ -0,0 +1,475 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qvector2d.h"
+#include "qvector3d.h"
+#include "qvector4d.h"
+#include <QtCore/qdebug.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_VECTOR2D
+
+/*!
+ \class QVector2D
+ \brief The QVector2D class represents a vector or vertex in 2D space.
+ \since 4.6
+ \ingroup painting
+ \ingroup painting-3D
+
+ The QVector2D class can also be used to represent vertices in 2D space.
+ We therefore do not need to provide a separate vertex class.
+
+ \bold{Note:} By design values in the QVector2D instance are stored as \c float.
+ This means that on platforms where the \c qreal arguments to QVector2D
+ functions are represented by \c double values, it is possible to
+ lose precision.
+
+ \sa QVector3D, QVector4D, QQuaternion
+*/
+
+/*!
+ \fn QVector2D::QVector2D()
+
+ Constructs a null vector, i.e. with coordinates (0, 0, 0).
+*/
+
+/*!
+ \fn QVector2D::QVector2D(qreal xpos, qreal ypos)
+
+ Constructs a vector with coordinates (\a xpos, \a ypos).
+*/
+
+/*!
+ \fn QVector2D::QVector2D(const QPoint& point)
+
+ Constructs a vector with x and y coordinates from a 2D \a point.
+*/
+
+/*!
+ \fn QVector2D::QVector2D(const QPointF& point)
+
+ Constructs a vector with x and y coordinates from a 2D \a point.
+*/
+
+#ifndef QT_NO_VECTOR3D
+
+/*!
+ Constructs a vector with x and y coordinates from a 3D \a vector.
+ The z coordinate of \a vector is dropped.
+
+ \sa toVector3D()
+*/
+QVector2D::QVector2D(const QVector3D& vector)
+{
+ xp = vector.xp;
+ yp = vector.yp;
+}
+
+#endif
+
+#ifndef QT_NO_VECTOR4D
+
+/*!
+ Constructs a vector with x and y coordinates from a 3D \a vector.
+ The z and w coordinates of \a vector are dropped.
+
+ \sa toVector4D()
+*/
+QVector2D::QVector2D(const QVector4D& vector)
+{
+ xp = vector.xp;
+ yp = vector.yp;
+}
+
+#endif
+
+/*!
+ \fn bool QVector2D::isNull() const
+
+ Returns true if the x and y coordinates are set to 0.0,
+ otherwise returns false.
+*/
+
+/*!
+ \fn qreal QVector2D::x() const
+
+ Returns the x coordinate of this point.
+
+ \sa setX(), y()
+*/
+
+/*!
+ \fn qreal QVector2D::y() const
+
+ Returns the y coordinate of this point.
+
+ \sa setY(), x()
+*/
+
+/*!
+ \fn void QVector2D::setX(qreal x)
+
+ Sets the x coordinate of this point to the given \a x coordinate.
+
+ \sa x(), setY()
+*/
+
+/*!
+ \fn void QVector2D::setY(qreal y)
+
+ Sets the y coordinate of this point to the given \a y coordinate.
+
+ \sa y(), setX()
+*/
+
+/*!
+ Returns the length of the vector from the origin.
+
+ \sa lengthSquared(), normalized()
+*/
+qreal QVector2D::length() const
+{
+ return qSqrt(xp * xp + yp * yp);
+}
+
+/*!
+ Returns the squared length of the vector from the origin.
+ This is equivalent to the dot product of the vector with itself.
+
+ \sa length(), dotProduct()
+*/
+qreal QVector2D::lengthSquared() const
+{
+ return xp * xp + yp * yp;
+}
+
+/*!
+ Returns the normalized unit vector form of this vector.
+
+ If this vector is null, then a null vector is returned. If the length
+ of the vector is very close to 1, then the vector will be returned as-is.
+ Otherwise the normalized form of the vector of length 1 will be returned.
+
+ \sa length(), normalize()
+*/
+QVector2D QVector2D::normalized() const
+{
+ // Need some extra precision if the length is very small.
+ double len = double(xp) * double(xp) +
+ double(yp) * double(yp);
+ if (qFuzzyIsNull(len - 1.0f))
+ return *this;
+ else if (!qFuzzyIsNull(len))
+ return *this / qSqrt(len);
+ else
+ return QVector2D();
+}
+
+/*!
+ Normalizes the currect vector in place. Nothing happens if this
+ vector is a null vector or the length of the vector is very close to 1.
+
+ \sa length(), normalized()
+*/
+void QVector2D::normalize()
+{
+ // Need some extra precision if the length is very small.
+ double len = double(xp) * double(xp) +
+ double(yp) * double(yp);
+ if (qFuzzyIsNull(len - 1.0f) || qFuzzyIsNull(len))
+ return;
+
+ len = qSqrt(len);
+
+ xp /= len;
+ yp /= len;
+}
+
+/*!
+ \fn QVector2D &QVector2D::operator+=(const QVector2D &vector)
+
+ Adds the given \a vector to this vector and returns a reference to
+ this vector.
+
+ \sa operator-=()
+*/
+
+/*!
+ \fn QVector2D &QVector2D::operator-=(const QVector2D &vector)
+
+ Subtracts the given \a vector from this vector and returns a reference to
+ this vector.
+
+ \sa operator+=()
+*/
+
+/*!
+ \fn QVector2D &QVector2D::operator*=(qreal factor)
+
+ Multiplies this vector's coordinates by the given \a factor, and
+ returns a reference to this vector.
+
+ \sa operator/=()
+*/
+
+/*!
+ \fn QVector2D &QVector2D::operator*=(const QVector2D &vector)
+
+ Multiplies the components of this vector by the corresponding
+ components in \a vector.
+*/
+
+/*!
+ \fn QVector2D &QVector2D::operator/=(qreal divisor)
+
+ Divides this vector's coordinates by the given \a divisor, and
+ returns a reference to this vector.
+
+ \sa operator*=()
+*/
+
+/*!
+ Returns the dot product of \a v1 and \a v2.
+*/
+qreal QVector2D::dotProduct(const QVector2D& v1, const QVector2D& v2)
+{
+ return v1.xp * v2.xp + v1.yp * v2.yp;
+}
+
+/*!
+ \fn bool operator==(const QVector2D &v1, const QVector2D &v2)
+ \relates QVector2D
+
+ Returns true if \a v1 is equal to \a v2; otherwise returns false.
+ This operator uses an exact floating-point comparison.
+*/
+
+/*!
+ \fn bool operator!=(const QVector2D &v1, const QVector2D &v2)
+ \relates QVector2D
+
+ Returns true if \a v1 is not equal to \a v2; otherwise returns false.
+ This operator uses an exact floating-point comparison.
+*/
+
+/*!
+ \fn const QVector2D operator+(const QVector2D &v1, const QVector2D &v2)
+ \relates QVector2D
+
+ Returns a QVector2D object that is the sum of the given vectors, \a v1
+ and \a v2; each component is added separately.
+
+ \sa QVector2D::operator+=()
+*/
+
+/*!
+ \fn const QVector2D operator-(const QVector2D &v1, const QVector2D &v2)
+ \relates QVector2D
+
+ Returns a QVector2D object that is formed by subtracting \a v2 from \a v1;
+ each component is subtracted separately.
+
+ \sa QVector2D::operator-=()
+*/
+
+/*!
+ \fn const QVector2D operator*(qreal factor, const QVector2D &vector)
+ \relates QVector2D
+
+ Returns a copy of the given \a vector, multiplied by the given \a factor.
+
+ \sa QVector2D::operator*=()
+*/
+
+/*!
+ \fn const QVector2D operator*(const QVector2D &vector, qreal factor)
+ \relates QVector2D
+
+ Returns a copy of the given \a vector, multiplied by the given \a factor.
+
+ \sa QVector2D::operator*=()
+*/
+
+/*!
+ \fn const QVector2D operator*(const QVector2D &v1, const QVector2D &v2)
+ \relates QVector2D
+
+ Multiplies the components of \a v1 by the corresponding
+ components in \a v2.
+*/
+
+/*!
+ \fn const QVector2D operator-(const QVector2D &vector)
+ \relates QVector2D
+ \overload
+
+ Returns a QVector2D object that is formed by changing the sign of
+ the components of the given \a vector.
+
+ Equivalent to \c {QVector2D(0,0) - vector}.
+*/
+
+/*!
+ \fn const QVector2D operator/(const QVector2D &vector, qreal divisor)
+ \relates QVector2D
+
+ Returns the QVector2D object formed by dividing all three components of
+ the given \a vector by the given \a divisor.
+
+ \sa QVector2D::operator/=()
+*/
+
+/*!
+ \fn bool qFuzzyCompare(const QVector2D& v1, const QVector2D& v2)
+ \relates QVector2D
+
+ Returns true if \a v1 and \a v2 are equal, allowing for a small
+ fuzziness factor for floating-point comparisons; false otherwise.
+*/
+
+#ifndef QT_NO_VECTOR3D
+
+/*!
+ Returns the 3D form of this 2D vector, with the z coordinate set to zero.
+
+ \sa toVector4D(), toPoint()
+*/
+QVector3D QVector2D::toVector3D() const
+{
+ return QVector3D(xp, yp, 0.0f, 1);
+}
+
+#endif
+
+#ifndef QT_NO_VECTOR4D
+
+/*!
+ Returns the 4D form of this 2D vector, with the z and w coordinates set to zero.
+
+ \sa toVector3D(), toPoint()
+*/
+QVector4D QVector2D::toVector4D() const
+{
+ return QVector4D(xp, yp, 0.0f, 0.0f, 1);
+}
+
+#endif
+
+/*!
+ \fn QPoint QVector2D::toPoint() const
+
+ Returns the QPoint form of this 2D vector.
+
+ \sa toPointF(), toVector3D()
+*/
+
+/*!
+ \fn QPointF QVector2D::toPointF() const
+
+ Returns the QPointF form of this 2D vector.
+
+ \sa toPoint(), toVector3D()
+*/
+
+/*!
+ Returns the 2D vector as a QVariant.
+*/
+QVector2D::operator QVariant() const
+{
+ return QVariant(QVariant::Vector2D, this);
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+
+QDebug operator<<(QDebug dbg, const QVector2D &vector)
+{
+ dbg.nospace() << "QVector2D(" << vector.x() << ", " << vector.y() << ')';
+ return dbg.space();
+}
+
+#endif
+
+#ifndef QT_NO_DATASTREAM
+
+/*!
+ \fn QDataStream &operator<<(QDataStream &stream, const QVector2D &vector)
+ \relates QVector2D
+
+ Writes the given \a vector to the given \a stream and returns a
+ reference to the stream.
+
+ \sa {Serializing Qt Data Types}
+*/
+
+QDataStream &operator<<(QDataStream &stream, const QVector2D &vector)
+{
+ stream << double(vector.x()) << double(vector.y());
+ return stream;
+}
+
+/*!
+ \fn QDataStream &operator>>(QDataStream &stream, QVector2D &vector)
+ \relates QVector2D
+
+ Reads a 2D vector from the given \a stream into the given \a vector
+ and returns a reference to the stream.
+
+ \sa {Serializing Qt Data Types}
+*/
+
+QDataStream &operator>>(QDataStream &stream, QVector2D &vector)
+{
+ double x, y;
+ stream >> x;
+ stream >> y;
+ vector.setX(qreal(x));
+ vector.setY(qreal(y));
+ return stream;
+}
+
+#endif // QT_NO_DATASTREAM
+
+#endif // QT_NO_VECTOR2D
+
+QT_END_NAMESPACE
diff --git a/src/gui/math3d/qvector2d.h b/src/gui/math3d/qvector2d.h
new file mode 100644
index 0000000000..089caf3620
--- /dev/null
+++ b/src/gui/math3d/qvector2d.h
@@ -0,0 +1,262 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QVECTOR2D_H
+#define QVECTOR2D_H
+
+#include <QtCore/qpoint.h>
+#include <QtCore/qmetatype.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QVector3D;
+class QVector4D;
+class QVariant;
+
+#ifndef QT_NO_VECTOR2D
+
+class Q_GUI_EXPORT QVector2D
+{
+public:
+ QVector2D();
+ QVector2D(qreal xpos, qreal ypos);
+ explicit QVector2D(const QPoint& point);
+ explicit QVector2D(const QPointF& point);
+#ifndef QT_NO_VECTOR3D
+ explicit QVector2D(const QVector3D& vector);
+#endif
+#ifndef QT_NO_VECTOR4D
+ explicit QVector2D(const QVector4D& vector);
+#endif
+
+ bool isNull() const;
+
+ qreal x() const;
+ qreal y() const;
+
+ void setX(qreal x);
+ void setY(qreal y);
+
+ qreal length() const;
+ qreal lengthSquared() const;
+
+ QVector2D normalized() const;
+ void normalize();
+
+ QVector2D &operator+=(const QVector2D &vector);
+ QVector2D &operator-=(const QVector2D &vector);
+ QVector2D &operator*=(qreal factor);
+ QVector2D &operator*=(const QVector2D &vector);
+ QVector2D &operator/=(qreal divisor);
+
+ static qreal dotProduct(const QVector2D& v1, const QVector2D& v2);
+
+ friend inline bool operator==(const QVector2D &v1, const QVector2D &v2);
+ friend inline bool operator!=(const QVector2D &v1, const QVector2D &v2);
+ friend inline const QVector2D operator+(const QVector2D &v1, const QVector2D &v2);
+ friend inline const QVector2D operator-(const QVector2D &v1, const QVector2D &v2);
+ friend inline const QVector2D operator*(qreal factor, const QVector2D &vector);
+ friend inline const QVector2D operator*(const QVector2D &vector, qreal factor);
+ friend inline const QVector2D operator*(const QVector2D &v1, const QVector2D &v2);
+ friend inline const QVector2D operator-(const QVector2D &vector);
+ friend inline const QVector2D operator/(const QVector2D &vector, qreal divisor);
+
+ friend inline bool qFuzzyCompare(const QVector2D& v1, const QVector2D& v2);
+
+#ifndef QT_NO_VECTOR3D
+ QVector3D toVector3D() const;
+#endif
+#ifndef QT_NO_VECTOR4D
+ QVector4D toVector4D() const;
+#endif
+
+ QPoint toPoint() const;
+ QPointF toPointF() const;
+
+ operator QVariant() const;
+
+private:
+ float xp, yp;
+
+ QVector2D(float xpos, float ypos, int dummy);
+
+ friend class QVector3D;
+ friend class QVector4D;
+};
+
+Q_DECLARE_TYPEINFO(QVector2D, Q_MOVABLE_TYPE);
+
+inline QVector2D::QVector2D() : xp(0.0f), yp(0.0f) {}
+
+inline QVector2D::QVector2D(float xpos, float ypos, int) : xp(xpos), yp(ypos) {}
+
+inline QVector2D::QVector2D(qreal xpos, qreal ypos) : xp(xpos), yp(ypos) {}
+
+inline QVector2D::QVector2D(const QPoint& point) : xp(point.x()), yp(point.y()) {}
+
+inline QVector2D::QVector2D(const QPointF& point) : xp(point.x()), yp(point.y()) {}
+
+inline bool QVector2D::isNull() const
+{
+ return qIsNull(xp) && qIsNull(yp);
+}
+
+inline qreal QVector2D::x() const { return qreal(xp); }
+inline qreal QVector2D::y() const { return qreal(yp); }
+
+inline void QVector2D::setX(qreal aX) { xp = aX; }
+inline void QVector2D::setY(qreal aY) { yp = aY; }
+
+inline QVector2D &QVector2D::operator+=(const QVector2D &vector)
+{
+ xp += vector.xp;
+ yp += vector.yp;
+ return *this;
+}
+
+inline QVector2D &QVector2D::operator-=(const QVector2D &vector)
+{
+ xp -= vector.xp;
+ yp -= vector.yp;
+ return *this;
+}
+
+inline QVector2D &QVector2D::operator*=(qreal factor)
+{
+ xp *= factor;
+ yp *= factor;
+ return *this;
+}
+
+inline QVector2D &QVector2D::operator*=(const QVector2D &vector)
+{
+ xp *= vector.xp;
+ yp *= vector.yp;
+ return *this;
+}
+
+inline QVector2D &QVector2D::operator/=(qreal divisor)
+{
+ xp /= divisor;
+ yp /= divisor;
+ return *this;
+}
+
+inline bool operator==(const QVector2D &v1, const QVector2D &v2)
+{
+ return v1.xp == v2.xp && v1.yp == v2.yp;
+}
+
+inline bool operator!=(const QVector2D &v1, const QVector2D &v2)
+{
+ return v1.xp != v2.xp || v1.yp != v2.yp;
+}
+
+inline const QVector2D operator+(const QVector2D &v1, const QVector2D &v2)
+{
+ return QVector2D(v1.xp + v2.xp, v1.yp + v2.yp, 1);
+}
+
+inline const QVector2D operator-(const QVector2D &v1, const QVector2D &v2)
+{
+ return QVector2D(v1.xp - v2.xp, v1.yp - v2.yp, 1);
+}
+
+inline const QVector2D operator*(qreal factor, const QVector2D &vector)
+{
+ return QVector2D(vector.xp * factor, vector.yp * factor, 1);
+}
+
+inline const QVector2D operator*(const QVector2D &vector, qreal factor)
+{
+ return QVector2D(vector.xp * factor, vector.yp * factor, 1);
+}
+
+inline const QVector2D operator*(const QVector2D &v1, const QVector2D &v2)
+{
+ return QVector2D(v1.xp * v2.xp, v1.yp * v2.yp, 1);
+}
+
+inline const QVector2D operator-(const QVector2D &vector)
+{
+ return QVector2D(-vector.xp, -vector.yp, 1);
+}
+
+inline const QVector2D operator/(const QVector2D &vector, qreal divisor)
+{
+ return QVector2D(vector.xp / divisor, vector.yp / divisor, 1);
+}
+
+inline bool qFuzzyCompare(const QVector2D& v1, const QVector2D& v2)
+{
+ return qFuzzyCompare(v1.xp, v2.xp) && qFuzzyCompare(v1.yp, v2.yp);
+}
+
+inline QPoint QVector2D::toPoint() const
+{
+ return QPoint(qRound(xp), qRound(yp));
+}
+
+inline QPointF QVector2D::toPointF() const
+{
+ return QPointF(qreal(xp), qreal(yp));
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QVector2D &vector);
+#endif
+
+#ifndef QT_NO_DATASTREAM
+Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QVector2D &);
+Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QVector2D &);
+#endif
+
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/gui/math3d/qvector3d.cpp b/src/gui/math3d/qvector3d.cpp
new file mode 100644
index 0000000000..7bf0400acb
--- /dev/null
+++ b/src/gui/math3d/qvector3d.cpp
@@ -0,0 +1,629 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qvector3d.h"
+#include "qvector2d.h"
+#include "qvector4d.h"
+#include <QtCore/qmath.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_VECTOR3D
+
+/*!
+ \class QVector3D
+ \brief The QVector3D class represents a vector or vertex in 3D space.
+ \since 4.6
+ \ingroup painting-3D
+
+ Vectors are one of the main building blocks of 3D representation and
+ drawing. They consist of three coordinates, traditionally called
+ x, y, and z.
+
+ The QVector3D class can also be used to represent vertices in 3D space.
+ We therefore do not need to provide a separate vertex class.
+
+ \bold{Note:} By design values in the QVector3D instance are stored as \c float.
+ This means that on platforms where the \c qreal arguments to QVector3D
+ functions are represented by \c double values, it is possible to
+ lose precision.
+
+ \sa QVector2D, QVector4D, QQuaternion
+*/
+
+/*!
+ \fn QVector3D::QVector3D()
+
+ Constructs a null vector, i.e. with coordinates (0, 0, 0).
+*/
+
+/*!
+ \fn QVector3D::QVector3D(qreal xpos, qreal ypos, qreal zpos)
+
+ Constructs a vector with coordinates (\a xpos, \a ypos, \a zpos).
+*/
+
+/*!
+ \fn QVector3D::QVector3D(const QPoint& point)
+
+ Constructs a vector with x and y coordinates from a 2D \a point, and a
+ z coordinate of 0.
+*/
+
+/*!
+ \fn QVector3D::QVector3D(const QPointF& point)
+
+ Constructs a vector with x and y coordinates from a 2D \a point, and a
+ z coordinate of 0.
+*/
+
+#ifndef QT_NO_VECTOR2D
+
+/*!
+ Constructs a 3D vector from the specified 2D \a vector. The z
+ coordinate is set to zero.
+
+ \sa toVector2D()
+*/
+QVector3D::QVector3D(const QVector2D& vector)
+{
+ xp = vector.xp;
+ yp = vector.yp;
+ zp = 0.0f;
+}
+
+/*!
+ Constructs a 3D vector from the specified 2D \a vector. The z
+ coordinate is set to \a zpos.
+
+ \sa toVector2D()
+*/
+QVector3D::QVector3D(const QVector2D& vector, qreal zpos)
+{
+ xp = vector.xp;
+ yp = vector.yp;
+ zp = zpos;
+}
+
+#endif
+
+#ifndef QT_NO_VECTOR4D
+
+/*!
+ Constructs a 3D vector from the specified 4D \a vector. The w
+ coordinate is dropped.
+
+ \sa toVector4D()
+*/
+QVector3D::QVector3D(const QVector4D& vector)
+{
+ xp = vector.xp;
+ yp = vector.yp;
+ zp = vector.zp;
+}
+
+#endif
+
+/*!
+ \fn bool QVector3D::isNull() const
+
+ Returns true if the x, y, and z coordinates are set to 0.0,
+ otherwise returns false.
+*/
+
+/*!
+ \fn qreal QVector3D::x() const
+
+ Returns the x coordinate of this point.
+
+ \sa setX(), y(), z()
+*/
+
+/*!
+ \fn qreal QVector3D::y() const
+
+ Returns the y coordinate of this point.
+
+ \sa setY(), x(), z()
+*/
+
+/*!
+ \fn qreal QVector3D::z() const
+
+ Returns the z coordinate of this point.
+
+ \sa setZ(), x(), y()
+*/
+
+/*!
+ \fn void QVector3D::setX(qreal x)
+
+ Sets the x coordinate of this point to the given \a x coordinate.
+
+ \sa x(), setY(), setZ()
+*/
+
+/*!
+ \fn void QVector3D::setY(qreal y)
+
+ Sets the y coordinate of this point to the given \a y coordinate.
+
+ \sa y(), setX(), setZ()
+*/
+
+/*!
+ \fn void QVector3D::setZ(qreal z)
+
+ Sets the z coordinate of this point to the given \a z coordinate.
+
+ \sa z(), setX(), setY()
+*/
+
+/*!
+ Returns the normalized unit vector form of this vector.
+
+ If this vector is null, then a null vector is returned. If the length
+ of the vector is very close to 1, then the vector will be returned as-is.
+ Otherwise the normalized form of the vector of length 1 will be returned.
+
+ \sa length(), normalize()
+*/
+QVector3D QVector3D::normalized() const
+{
+ // Need some extra precision if the length is very small.
+ double len = double(xp) * double(xp) +
+ double(yp) * double(yp) +
+ double(zp) * double(zp);
+ if (qFuzzyIsNull(len - 1.0f))
+ return *this;
+ else if (!qFuzzyIsNull(len))
+ return *this / qSqrt(len);
+ else
+ return QVector3D();
+}
+
+/*!
+ Normalizes the currect vector in place. Nothing happens if this
+ vector is a null vector or the length of the vector is very close to 1.
+
+ \sa length(), normalized()
+*/
+void QVector3D::normalize()
+{
+ // Need some extra precision if the length is very small.
+ double len = double(xp) * double(xp) +
+ double(yp) * double(yp) +
+ double(zp) * double(zp);
+ if (qFuzzyIsNull(len - 1.0f) || qFuzzyIsNull(len))
+ return;
+
+ len = qSqrt(len);
+
+ xp /= len;
+ yp /= len;
+ zp /= len;
+}
+
+/*!
+ \fn QVector3D &QVector3D::operator+=(const QVector3D &vector)
+
+ Adds the given \a vector to this vector and returns a reference to
+ this vector.
+
+ \sa operator-=()
+*/
+
+/*!
+ \fn QVector3D &QVector3D::operator-=(const QVector3D &vector)
+
+ Subtracts the given \a vector from this vector and returns a reference to
+ this vector.
+
+ \sa operator+=()
+*/
+
+/*!
+ \fn QVector3D &QVector3D::operator*=(qreal factor)
+
+ Multiplies this vector's coordinates by the given \a factor, and
+ returns a reference to this vector.
+
+ \sa operator/=()
+*/
+
+/*!
+ \fn QVector3D &QVector3D::operator*=(const QVector3D& vector)
+ \overload
+
+ Multiplies the components of this vector by the corresponding
+ components in \a vector.
+
+ Note: this is not the same as the crossProduct() of this
+ vector and \a vector.
+
+ \sa crossProduct()
+*/
+
+/*!
+ \fn QVector3D &QVector3D::operator/=(qreal divisor)
+
+ Divides this vector's coordinates by the given \a divisor, and
+ returns a reference to this vector.
+
+ \sa operator*=()
+*/
+
+/*!
+ Returns the dot product of \a v1 and \a v2.
+*/
+qreal QVector3D::dotProduct(const QVector3D& v1, const QVector3D& v2)
+{
+ return v1.xp * v2.xp + v1.yp * v2.yp + v1.zp * v2.zp;
+}
+
+/*!
+ Returns the cross-product of vectors \a v1 and \a v2, which corresponds
+ to the normal vector of a plane defined by \a v1 and \a v2.
+
+ \sa normal()
+*/
+QVector3D QVector3D::crossProduct(const QVector3D& v1, const QVector3D& v2)
+{
+ return QVector3D(v1.yp * v2.zp - v1.zp * v2.yp,
+ v1.zp * v2.xp - v1.xp * v2.zp,
+ v1.xp * v2.yp - v1.yp * v2.xp, 1);
+}
+
+/*!
+ Returns the normal vector of a plane defined by vectors \a v1 and \a v2,
+ normalized to be a unit vector.
+
+ Use crossProduct() to compute the cross-product of \a v1 and \a v2 if you
+ do not need the result to be normalized to a unit vector.
+
+ \sa crossProduct(), distanceToPlane()
+*/
+QVector3D QVector3D::normal(const QVector3D& v1, const QVector3D& v2)
+{
+ return crossProduct(v1, v2).normalized();
+}
+
+/*!
+ \overload
+
+ Returns the normal vector of a plane defined by vectors
+ \a v2 - \a v1 and \a v3 - \a v1, normalized to be a unit vector.
+
+ Use crossProduct() to compute the cross-product of \a v2 - \a v1 and
+ \a v3 - \a v1 if you do not need the result to be normalized to a
+ unit vector.
+
+ \sa crossProduct(), distanceToPlane()
+*/
+QVector3D QVector3D::normal
+ (const QVector3D& v1, const QVector3D& v2, const QVector3D& v3)
+{
+ return crossProduct((v2 - v1), (v3 - v1)).normalized();
+}
+
+/*!
+ Returns the distance from this vertex to a plane defined by
+ the vertex \a plane and a \a normal unit vector. The \a normal
+ parameter is assumed to have been normalized to a unit vector.
+
+ The return value will be negative if the vertex is below the plane,
+ or zero if it is on the plane.
+
+ \sa normal(), distanceToLine()
+*/
+qreal QVector3D::distanceToPlane
+ (const QVector3D& plane, const QVector3D& normal) const
+{
+ return dotProduct(*this - plane, normal);
+}
+
+/*!
+ \overload
+
+ Returns the distance from this vertex a plane defined by
+ the vertices \a plane1, \a plane2 and \a plane3.
+
+ The return value will be negative if the vertex is below the plane,
+ or zero if it is on the plane.
+
+ The two vectors that define the plane are \a plane2 - \a plane1
+ and \a plane3 - \a plane1.
+
+ \sa normal(), distanceToLine()
+*/
+qreal QVector3D::distanceToPlane
+ (const QVector3D& plane1, const QVector3D& plane2, const QVector3D& plane3) const
+{
+ QVector3D n = normal(plane2 - plane1, plane3 - plane1);
+ return dotProduct(*this - plane1, n);
+}
+
+/*!
+ Returns the distance that this vertex is from a line defined
+ by \a point and the unit vector \a direction.
+
+ If \a direction is a null vector, then it does not define a line.
+ In that case, the distance from \a point to this vertex is returned.
+
+ \sa distanceToPlane()
+*/
+qreal QVector3D::distanceToLine
+ (const QVector3D& point, const QVector3D& direction) const
+{
+ if (direction.isNull())
+ return (*this - point).length();
+ QVector3D p = point + dotProduct(*this - point, direction) * direction;
+ return (*this - p).length();
+}
+
+/*!
+ \fn bool operator==(const QVector3D &v1, const QVector3D &v2)
+ \relates QVector3D
+
+ Returns true if \a v1 is equal to \a v2; otherwise returns false.
+ This operator uses an exact floating-point comparison.
+*/
+
+/*!
+ \fn bool operator!=(const QVector3D &v1, const QVector3D &v2)
+ \relates QVector3D
+
+ Returns true if \a v1 is not equal to \a v2; otherwise returns false.
+ This operator uses an exact floating-point comparison.
+*/
+
+/*!
+ \fn const QVector3D operator+(const QVector3D &v1, const QVector3D &v2)
+ \relates QVector3D
+
+ Returns a QVector3D object that is the sum of the given vectors, \a v1
+ and \a v2; each component is added separately.
+
+ \sa QVector3D::operator+=()
+*/
+
+/*!
+ \fn const QVector3D operator-(const QVector3D &v1, const QVector3D &v2)
+ \relates QVector3D
+
+ Returns a QVector3D object that is formed by subtracting \a v2 from \a v1;
+ each component is subtracted separately.
+
+ \sa QVector3D::operator-=()
+*/
+
+/*!
+ \fn const QVector3D operator*(qreal factor, const QVector3D &vector)
+ \relates QVector3D
+
+ Returns a copy of the given \a vector, multiplied by the given \a factor.
+
+ \sa QVector3D::operator*=()
+*/
+
+/*!
+ \fn const QVector3D operator*(const QVector3D &vector, qreal factor)
+ \relates QVector3D
+
+ Returns a copy of the given \a vector, multiplied by the given \a factor.
+
+ \sa QVector3D::operator*=()
+*/
+
+/*!
+ \fn const QVector3D operator*(const QVector3D &v1, const QVector3D& v2)
+ \relates QVector3D
+
+ Multiplies the components of \a v1 by the corresponding components in \a v2.
+
+ Note: this is not the same as the crossProduct() of \a v1 and \a v2.
+
+ \sa QVector3D::crossProduct()
+*/
+
+/*!
+ \fn const QVector3D operator-(const QVector3D &vector)
+ \relates QVector3D
+ \overload
+
+ Returns a QVector3D object that is formed by changing the sign of
+ all three components of the given \a vector.
+
+ Equivalent to \c {QVector3D(0,0,0) - vector}.
+*/
+
+/*!
+ \fn const QVector3D operator/(const QVector3D &vector, qreal divisor)
+ \relates QVector3D
+
+ Returns the QVector3D object formed by dividing all three components of
+ the given \a vector by the given \a divisor.
+
+ \sa QVector3D::operator/=()
+*/
+
+/*!
+ \fn bool qFuzzyCompare(const QVector3D& v1, const QVector3D& v2)
+ \relates QVector3D
+
+ Returns true if \a v1 and \a v2 are equal, allowing for a small
+ fuzziness factor for floating-point comparisons; false otherwise.
+*/
+
+#ifndef QT_NO_VECTOR2D
+
+/*!
+ Returns the 2D vector form of this 3D vector, dropping the z coordinate.
+
+ \sa toVector4D(), toPoint()
+*/
+QVector2D QVector3D::toVector2D() const
+{
+ return QVector2D(xp, yp, 1);
+}
+
+#endif
+
+#ifndef QT_NO_VECTOR4D
+
+/*!
+ Returns the 4D form of this 3D vector, with the w coordinate set to zero.
+
+ \sa toVector2D(), toPoint()
+*/
+QVector4D QVector3D::toVector4D() const
+{
+ return QVector4D(xp, yp, zp, 0.0f, 1);
+}
+
+#endif
+
+/*!
+ \fn QPoint QVector3D::toPoint() const
+
+ Returns the QPoint form of this 3D vector. The z coordinate
+ is dropped.
+
+ \sa toPointF(), toVector2D()
+*/
+
+/*!
+ \fn QPointF QVector3D::toPointF() const
+
+ Returns the QPointF form of this 3D vector. The z coordinate
+ is dropped.
+
+ \sa toPoint(), toVector2D()
+*/
+
+/*!
+ Returns the 3D vector as a QVariant.
+*/
+QVector3D::operator QVariant() const
+{
+ return QVariant(QVariant::Vector3D, this);
+}
+
+/*!
+ Returns the length of the vector from the origin.
+
+ \sa lengthSquared(), normalized()
+*/
+qreal QVector3D::length() const
+{
+ return qSqrt(xp * xp + yp * yp + zp * zp);
+}
+
+/*!
+ Returns the squared length of the vector from the origin.
+ This is equivalent to the dot product of the vector with itself.
+
+ \sa length(), dotProduct()
+*/
+qreal QVector3D::lengthSquared() const
+{
+ return xp * xp + yp * yp + zp * zp;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+
+QDebug operator<<(QDebug dbg, const QVector3D &vector)
+{
+ dbg.nospace() << "QVector3D("
+ << vector.x() << ", " << vector.y() << ", " << vector.z() << ')';
+ return dbg.space();
+}
+
+#endif
+
+#ifndef QT_NO_DATASTREAM
+
+/*!
+ \fn QDataStream &operator<<(QDataStream &stream, const QVector3D &vector)
+ \relates QVector3D
+
+ Writes the given \a vector to the given \a stream and returns a
+ reference to the stream.
+
+ \sa {Serializing Qt Data Types}
+*/
+
+QDataStream &operator<<(QDataStream &stream, const QVector3D &vector)
+{
+ stream << double(vector.x()) << double(vector.y())
+ << double(vector.z());
+ return stream;
+}
+
+/*!
+ \fn QDataStream &operator>>(QDataStream &stream, QVector3D &vector)
+ \relates QVector3D
+
+ Reads a 3D vector from the given \a stream into the given \a vector
+ and returns a reference to the stream.
+
+ \sa {Serializing Qt Data Types}
+*/
+
+QDataStream &operator>>(QDataStream &stream, QVector3D &vector)
+{
+ double x, y, z;
+ stream >> x;
+ stream >> y;
+ stream >> z;
+ vector.setX(qreal(x));
+ vector.setY(qreal(y));
+ vector.setZ(qreal(z));
+ return stream;
+}
+
+#endif // QT_NO_DATASTREAM
+
+#endif // QT_NO_VECTOR3D
+
+QT_END_NAMESPACE
diff --git a/src/gui/math3d/qvector3d.h b/src/gui/math3d/qvector3d.h
new file mode 100644
index 0000000000..c33cf42d4b
--- /dev/null
+++ b/src/gui/math3d/qvector3d.h
@@ -0,0 +1,286 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QVECTOR3D_H
+#define QVECTOR3D_H
+
+#include <QtCore/qpoint.h>
+#include <QtCore/qmetatype.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QMatrix4x4;
+class QVector2D;
+class QVector4D;
+
+#ifndef QT_NO_VECTOR3D
+
+class Q_GUI_EXPORT QVector3D
+{
+public:
+ QVector3D();
+ QVector3D(qreal xpos, qreal ypos, qreal zpos);
+ explicit QVector3D(const QPoint& point);
+ explicit QVector3D(const QPointF& point);
+#ifndef QT_NO_VECTOR2D
+ QVector3D(const QVector2D& vector);
+ QVector3D(const QVector2D& vector, qreal zpos);
+#endif
+#ifndef QT_NO_VECTOR4D
+ explicit QVector3D(const QVector4D& vector);
+#endif
+
+ bool isNull() const;
+
+ qreal x() const;
+ qreal y() const;
+ qreal z() const;
+
+ void setX(qreal x);
+ void setY(qreal y);
+ void setZ(qreal z);
+
+ qreal length() const;
+ qreal lengthSquared() const;
+
+ QVector3D normalized() const;
+ void normalize();
+
+ QVector3D &operator+=(const QVector3D &vector);
+ QVector3D &operator-=(const QVector3D &vector);
+ QVector3D &operator*=(qreal factor);
+ QVector3D &operator*=(const QVector3D& vector);
+ QVector3D &operator/=(qreal divisor);
+
+ static qreal dotProduct(const QVector3D& v1, const QVector3D& v2);
+ static QVector3D crossProduct(const QVector3D& v1, const QVector3D& v2);
+ static QVector3D normal(const QVector3D& v1, const QVector3D& v2);
+ static QVector3D normal
+ (const QVector3D& v1, const QVector3D& v2, const QVector3D& v3);
+
+ qreal distanceToPlane(const QVector3D& plane, const QVector3D& normal) const;
+ qreal distanceToPlane(const QVector3D& plane1, const QVector3D& plane2, const QVector3D& plane3) const;
+ qreal distanceToLine(const QVector3D& point, const QVector3D& direction) const;
+
+ friend inline bool operator==(const QVector3D &v1, const QVector3D &v2);
+ friend inline bool operator!=(const QVector3D &v1, const QVector3D &v2);
+ friend inline const QVector3D operator+(const QVector3D &v1, const QVector3D &v2);
+ friend inline const QVector3D operator-(const QVector3D &v1, const QVector3D &v2);
+ friend inline const QVector3D operator*(qreal factor, const QVector3D &vector);
+ friend inline const QVector3D operator*(const QVector3D &vector, qreal factor);
+ friend const QVector3D operator*(const QVector3D &v1, const QVector3D& v2);
+ friend inline const QVector3D operator-(const QVector3D &vector);
+ friend inline const QVector3D operator/(const QVector3D &vector, qreal divisor);
+
+ friend inline bool qFuzzyCompare(const QVector3D& v1, const QVector3D& v2);
+
+#ifndef QT_NO_VECTOR2D
+ QVector2D toVector2D() const;
+#endif
+#ifndef QT_NO_VECTOR4D
+ QVector4D toVector4D() const;
+#endif
+
+ QPoint toPoint() const;
+ QPointF toPointF() const;
+
+ operator QVariant() const;
+
+private:
+ float xp, yp, zp;
+
+ QVector3D(float xpos, float ypos, float zpos, int dummy);
+
+ friend class QVector2D;
+ friend class QVector4D;
+#ifndef QT_NO_MATRIX4X4
+ friend QVector3D operator*(const QVector3D& vector, const QMatrix4x4& matrix);
+ friend QVector3D operator*(const QMatrix4x4& matrix, const QVector3D& vector);
+#endif
+};
+
+Q_DECLARE_TYPEINFO(QVector3D, Q_MOVABLE_TYPE);
+
+inline QVector3D::QVector3D() : xp(0.0f), yp(0.0f), zp(0.0f) {}
+
+inline QVector3D::QVector3D(qreal xpos, qreal ypos, qreal zpos) : xp(xpos), yp(ypos), zp(zpos) {}
+
+inline QVector3D::QVector3D(float xpos, float ypos, float zpos, int) : xp(xpos), yp(ypos), zp(zpos) {}
+
+inline QVector3D::QVector3D(const QPoint& point) : xp(point.x()), yp(point.y()), zp(0.0f) {}
+
+inline QVector3D::QVector3D(const QPointF& point) : xp(point.x()), yp(point.y()), zp(0.0f) {}
+
+inline bool QVector3D::isNull() const
+{
+ return qIsNull(xp) && qIsNull(yp) && qIsNull(zp);
+}
+
+inline qreal QVector3D::x() const { return qreal(xp); }
+inline qreal QVector3D::y() const { return qreal(yp); }
+inline qreal QVector3D::z() const { return qreal(zp); }
+
+inline void QVector3D::setX(qreal aX) { xp = aX; }
+inline void QVector3D::setY(qreal aY) { yp = aY; }
+inline void QVector3D::setZ(qreal aZ) { zp = aZ; }
+
+inline QVector3D &QVector3D::operator+=(const QVector3D &vector)
+{
+ xp += vector.xp;
+ yp += vector.yp;
+ zp += vector.zp;
+ return *this;
+}
+
+inline QVector3D &QVector3D::operator-=(const QVector3D &vector)
+{
+ xp -= vector.xp;
+ yp -= vector.yp;
+ zp -= vector.zp;
+ return *this;
+}
+
+inline QVector3D &QVector3D::operator*=(qreal factor)
+{
+ xp *= factor;
+ yp *= factor;
+ zp *= factor;
+ return *this;
+}
+
+inline QVector3D &QVector3D::operator*=(const QVector3D& vector)
+{
+ xp *= vector.xp;
+ yp *= vector.yp;
+ zp *= vector.zp;
+ return *this;
+}
+
+inline QVector3D &QVector3D::operator/=(qreal divisor)
+{
+ xp /= divisor;
+ yp /= divisor;
+ zp /= divisor;
+ return *this;
+}
+
+inline bool operator==(const QVector3D &v1, const QVector3D &v2)
+{
+ return v1.xp == v2.xp && v1.yp == v2.yp && v1.zp == v2.zp;
+}
+
+inline bool operator!=(const QVector3D &v1, const QVector3D &v2)
+{
+ return v1.xp != v2.xp || v1.yp != v2.yp || v1.zp != v2.zp;
+}
+
+inline const QVector3D operator+(const QVector3D &v1, const QVector3D &v2)
+{
+ return QVector3D(v1.xp + v2.xp, v1.yp + v2.yp, v1.zp + v2.zp, 1);
+}
+
+inline const QVector3D operator-(const QVector3D &v1, const QVector3D &v2)
+{
+ return QVector3D(v1.xp - v2.xp, v1.yp - v2.yp, v1.zp - v2.zp, 1);
+}
+
+inline const QVector3D operator*(qreal factor, const QVector3D &vector)
+{
+ return QVector3D(vector.xp * factor, vector.yp * factor, vector.zp * factor, 1);
+}
+
+inline const QVector3D operator*(const QVector3D &vector, qreal factor)
+{
+ return QVector3D(vector.xp * factor, vector.yp * factor, vector.zp * factor, 1);
+}
+
+inline const QVector3D operator*(const QVector3D &v1, const QVector3D& v2)
+{
+ return QVector3D(v1.xp * v2.xp, v1.yp * v2.yp, v1.zp * v2.zp, 1);
+}
+
+inline const QVector3D operator-(const QVector3D &vector)
+{
+ return QVector3D(-vector.xp, -vector.yp, -vector.zp, 1);
+}
+
+inline const QVector3D operator/(const QVector3D &vector, qreal divisor)
+{
+ return QVector3D(vector.xp / divisor, vector.yp / divisor, vector.zp / divisor, 1);
+}
+
+inline bool qFuzzyCompare(const QVector3D& v1, const QVector3D& v2)
+{
+ return qFuzzyCompare(v1.xp, v2.xp) &&
+ qFuzzyCompare(v1.yp, v2.yp) &&
+ qFuzzyCompare(v1.zp, v2.zp);
+}
+
+inline QPoint QVector3D::toPoint() const
+{
+ return QPoint(qRound(xp), qRound(yp));
+}
+
+inline QPointF QVector3D::toPointF() const
+{
+ return QPointF(qreal(xp), qreal(yp));
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QVector3D &vector);
+#endif
+
+#ifndef QT_NO_DATASTREAM
+Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QVector3D &);
+Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QVector3D &);
+#endif
+
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/gui/math3d/qvector4d.cpp b/src/gui/math3d/qvector4d.cpp
new file mode 100644
index 0000000000..23befc01a5
--- /dev/null
+++ b/src/gui/math3d/qvector4d.cpp
@@ -0,0 +1,584 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qvector4d.h"
+#include "qvector3d.h"
+#include "qvector2d.h"
+#include <QtCore/qdebug.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_VECTOR4D
+
+/*!
+ \class QVector4D
+ \brief The QVector4D class represents a vector or vertex in 4D space.
+ \since 4.6
+ \ingroup painting-3D
+
+ The QVector4D class can also be used to represent vertices in 4D space.
+ We therefore do not need to provide a separate vertex class.
+
+ \bold{Note:} By design values in the QVector4D instance are stored as \c float.
+ This means that on platforms where the \c qreal arguments to QVector4D
+ functions are represented by \c double values, it is possible to
+ lose precision.
+
+ \sa QQuaternion, QVector2D, QVector3D
+*/
+
+/*!
+ \fn QVector4D::QVector4D()
+
+ Constructs a null vector, i.e. with coordinates (0, 0, 0, 0).
+*/
+
+/*!
+ \fn QVector4D::QVector4D(qreal xpos, qreal ypos, qreal zpos, qreal wpos)
+
+ Constructs a vector with coordinates (\a xpos, \a ypos, \a zpos, \a wpos).
+*/
+
+/*!
+ \fn QVector4D::QVector4D(const QPoint& point)
+
+ Constructs a vector with x and y coordinates from a 2D \a point, and
+ z and w coordinates of 0.
+*/
+
+/*!
+ \fn QVector4D::QVector4D(const QPointF& point)
+
+ Constructs a vector with x and y coordinates from a 2D \a point, and
+ z and w coordinates of 0.
+*/
+
+#ifndef QT_NO_VECTOR2D
+
+/*!
+ Constructs a 4D vector from the specified 2D \a vector. The z
+ and w coordinates are set to zero.
+
+ \sa toVector2D()
+*/
+QVector4D::QVector4D(const QVector2D& vector)
+{
+ xp = vector.xp;
+ yp = vector.yp;
+ zp = 0.0f;
+ wp = 0.0f;
+}
+
+/*!
+ Constructs a 4D vector from the specified 2D \a vector. The z
+ and w coordinates are set to \a zpos and \a wpos respectively.
+
+ \sa toVector2D()
+*/
+QVector4D::QVector4D(const QVector2D& vector, qreal zpos, qreal wpos)
+{
+ xp = vector.xp;
+ yp = vector.yp;
+ zp = zpos;
+ wp = wpos;
+}
+
+#endif
+
+#ifndef QT_NO_VECTOR3D
+
+/*!
+ Constructs a 4D vector from the specified 3D \a vector. The w
+ coordinate is set to zero.
+
+ \sa toVector3D()
+*/
+QVector4D::QVector4D(const QVector3D& vector)
+{
+ xp = vector.xp;
+ yp = vector.yp;
+ zp = vector.zp;
+ wp = 0.0f;
+}
+
+/*!
+ Constructs a 4D vector from the specified 3D \a vector. The w
+ coordinate is set to \a wpos.
+
+ \sa toVector3D()
+*/
+QVector4D::QVector4D(const QVector3D& vector, qreal wpos)
+{
+ xp = vector.xp;
+ yp = vector.yp;
+ zp = vector.zp;
+ wp = wpos;
+}
+
+#endif
+
+/*!
+ \fn bool QVector4D::isNull() const
+
+ Returns true if the x, y, z, and w coordinates are set to 0.0,
+ otherwise returns false.
+*/
+
+/*!
+ \fn qreal QVector4D::x() const
+
+ Returns the x coordinate of this point.
+
+ \sa setX(), y(), z(), w()
+*/
+
+/*!
+ \fn qreal QVector4D::y() const
+
+ Returns the y coordinate of this point.
+
+ \sa setY(), x(), z(), w()
+*/
+
+/*!
+ \fn qreal QVector4D::z() const
+
+ Returns the z coordinate of this point.
+
+ \sa setZ(), x(), y(), w()
+*/
+
+/*!
+ \fn qreal QVector4D::w() const
+
+ Returns the w coordinate of this point.
+
+ \sa setW(), x(), y(), z()
+*/
+
+/*!
+ \fn void QVector4D::setX(qreal x)
+
+ Sets the x coordinate of this point to the given \a x coordinate.
+
+ \sa x(), setY(), setZ(), setW()
+*/
+
+/*!
+ \fn void QVector4D::setY(qreal y)
+
+ Sets the y coordinate of this point to the given \a y coordinate.
+
+ \sa y(), setX(), setZ(), setW()
+*/
+
+/*!
+ \fn void QVector4D::setZ(qreal z)
+
+ Sets the z coordinate of this point to the given \a z coordinate.
+
+ \sa z(), setX(), setY(), setW()
+*/
+
+/*!
+ \fn void QVector4D::setW(qreal w)
+
+ Sets the w coordinate of this point to the given \a w coordinate.
+
+ \sa w(), setX(), setY(), setZ()
+*/
+
+/*!
+ Returns the length of the vector from the origin.
+
+ \sa lengthSquared(), normalized()
+*/
+qreal QVector4D::length() const
+{
+ return qSqrt(xp * xp + yp * yp + zp * zp + wp * wp);
+}
+
+/*!
+ Returns the squared length of the vector from the origin.
+ This is equivalent to the dot product of the vector with itself.
+
+ \sa length(), dotProduct()
+*/
+qreal QVector4D::lengthSquared() const
+{
+ return xp * xp + yp * yp + zp * zp + wp * wp;
+}
+
+/*!
+ Returns the normalized unit vector form of this vector.
+
+ If this vector is null, then a null vector is returned. If the length
+ of the vector is very close to 1, then the vector will be returned as-is.
+ Otherwise the normalized form of the vector of length 1 will be returned.
+
+ \sa length(), normalize()
+*/
+QVector4D QVector4D::normalized() const
+{
+ // Need some extra precision if the length is very small.
+ double len = double(xp) * double(xp) +
+ double(yp) * double(yp) +
+ double(zp) * double(zp) +
+ double(wp) * double(wp);
+ if (qFuzzyIsNull(len - 1.0f))
+ return *this;
+ else if (!qFuzzyIsNull(len))
+ return *this / qSqrt(len);
+ else
+ return QVector4D();
+}
+
+/*!
+ Normalizes the currect vector in place. Nothing happens if this
+ vector is a null vector or the length of the vector is very close to 1.
+
+ \sa length(), normalized()
+*/
+void QVector4D::normalize()
+{
+ // Need some extra precision if the length is very small.
+ double len = double(xp) * double(xp) +
+ double(yp) * double(yp) +
+ double(zp) * double(zp) +
+ double(wp) * double(wp);
+ if (qFuzzyIsNull(len - 1.0f) || qFuzzyIsNull(len))
+ return;
+
+ len = qSqrt(len);
+
+ xp /= len;
+ yp /= len;
+ zp /= len;
+ wp /= len;
+}
+
+/*!
+ \fn QVector4D &QVector4D::operator+=(const QVector4D &vector)
+
+ Adds the given \a vector to this vector and returns a reference to
+ this vector.
+
+ \sa operator-=()
+*/
+
+/*!
+ \fn QVector4D &QVector4D::operator-=(const QVector4D &vector)
+
+ Subtracts the given \a vector from this vector and returns a reference to
+ this vector.
+
+ \sa operator+=()
+*/
+
+/*!
+ \fn QVector4D &QVector4D::operator*=(qreal factor)
+
+ Multiplies this vector's coordinates by the given \a factor, and
+ returns a reference to this vector.
+
+ \sa operator/=()
+*/
+
+/*!
+ \fn QVector4D &QVector4D::operator*=(const QVector4D &vector)
+
+ Multiplies the components of this vector by the corresponding
+ components in \a vector.
+*/
+
+/*!
+ \fn QVector4D &QVector4D::operator/=(qreal divisor)
+
+ Divides this vector's coordinates by the given \a divisor, and
+ returns a reference to this vector.
+
+ \sa operator*=()
+*/
+
+/*!
+ Returns the dot product of \a v1 and \a v2.
+*/
+qreal QVector4D::dotProduct(const QVector4D& v1, const QVector4D& v2)
+{
+ return v1.xp * v2.xp + v1.yp * v2.yp + v1.zp * v2.zp + v1.wp * v2.wp;
+}
+
+/*!
+ \fn bool operator==(const QVector4D &v1, const QVector4D &v2)
+ \relates QVector4D
+
+ Returns true if \a v1 is equal to \a v2; otherwise returns false.
+ This operator uses an exact floating-point comparison.
+*/
+
+/*!
+ \fn bool operator!=(const QVector4D &v1, const QVector4D &v2)
+ \relates QVector4D
+
+ Returns true if \a v1 is not equal to \a v2; otherwise returns false.
+ This operator uses an exact floating-point comparison.
+*/
+
+/*!
+ \fn const QVector4D operator+(const QVector4D &v1, const QVector4D &v2)
+ \relates QVector4D
+
+ Returns a QVector4D object that is the sum of the given vectors, \a v1
+ and \a v2; each component is added separately.
+
+ \sa QVector4D::operator+=()
+*/
+
+/*!
+ \fn const QVector4D operator-(const QVector4D &v1, const QVector4D &v2)
+ \relates QVector4D
+
+ Returns a QVector4D object that is formed by subtracting \a v2 from \a v1;
+ each component is subtracted separately.
+
+ \sa QVector4D::operator-=()
+*/
+
+/*!
+ \fn const QVector4D operator*(qreal factor, const QVector4D &vector)
+ \relates QVector4D
+
+ Returns a copy of the given \a vector, multiplied by the given \a factor.
+
+ \sa QVector4D::operator*=()
+*/
+
+/*!
+ \fn const QVector4D operator*(const QVector4D &vector, qreal factor)
+ \relates QVector4D
+
+ Returns a copy of the given \a vector, multiplied by the given \a factor.
+
+ \sa QVector4D::operator*=()
+*/
+
+/*!
+ \fn const QVector4D operator*(const QVector4D &v1, const QVector4D& v2)
+ \relates QVector4D
+
+ Returns the vector consisting of the multiplication of the
+ components from \a v1 and \a v2.
+
+ \sa QVector4D::operator*=()
+*/
+
+/*!
+ \fn const QVector4D operator-(const QVector4D &vector)
+ \relates QVector4D
+ \overload
+
+ Returns a QVector4D object that is formed by changing the sign of
+ all three components of the given \a vector.
+
+ Equivalent to \c {QVector4D(0,0,0,0) - vector}.
+*/
+
+/*!
+ \fn const QVector4D operator/(const QVector4D &vector, qreal divisor)
+ \relates QVector4D
+
+ Returns the QVector4D object formed by dividing all four components of
+ the given \a vector by the given \a divisor.
+
+ \sa QVector4D::operator/=()
+*/
+
+/*!
+ \fn bool qFuzzyCompare(const QVector4D& v1, const QVector4D& v2)
+ \relates QVector4D
+
+ Returns true if \a v1 and \a v2 are equal, allowing for a small
+ fuzziness factor for floating-point comparisons; false otherwise.
+*/
+
+#ifndef QT_NO_VECTOR2D
+
+/*!
+ Returns the 2D vector form of this 4D vector, dropping the z and w coordinates.
+
+ \sa toVector2DAffine(), toVector3D(), toPoint()
+*/
+QVector2D QVector4D::toVector2D() const
+{
+ return QVector2D(xp, yp, 1);
+}
+
+/*!
+ Returns the 2D vector form of this 4D vector, dividing the x and y
+ coordinates by the w coordinate and dropping the z coordinate.
+ Returns a null vector if w is zero.
+
+ \sa toVector2D(), toVector3DAffine(), toPoint()
+*/
+QVector2D QVector4D::toVector2DAffine() const
+{
+ if (qIsNull(wp))
+ return QVector2D();
+ return QVector2D(xp / wp, yp / wp, 1);
+}
+
+#endif
+
+#ifndef QT_NO_VECTOR3D
+
+/*!
+ Returns the 3D vector form of this 4D vector, dropping the w coordinate.
+
+ \sa toVector3DAffine(), toVector2D(), toPoint()
+*/
+QVector3D QVector4D::toVector3D() const
+{
+ return QVector3D(xp, yp, zp, 1);
+}
+
+/*!
+ Returns the 3D vector form of this 4D vector, dividing the x, y, and
+ z coordinates by the w coordinate. Returns a null vector if w is zero.
+
+ \sa toVector3D(), toVector2DAffine(), toPoint()
+*/
+QVector3D QVector4D::toVector3DAffine() const
+{
+ if (qIsNull(wp))
+ return QVector3D();
+ return QVector3D(xp / wp, yp / wp, zp / wp, 1);
+}
+
+#endif
+
+/*!
+ \fn QPoint QVector4D::toPoint() const
+
+ Returns the QPoint form of this 4D vector. The z and w coordinates
+ are dropped.
+
+ \sa toPointF(), toVector2D()
+*/
+
+/*!
+ \fn QPointF QVector4D::toPointF() const
+
+ Returns the QPointF form of this 4D vector. The z and w coordinates
+ are dropped.
+
+ \sa toPoint(), toVector2D()
+*/
+
+/*!
+ Returns the 4D vector as a QVariant.
+*/
+QVector4D::operator QVariant() const
+{
+ return QVariant(QVariant::Vector4D, this);
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+
+QDebug operator<<(QDebug dbg, const QVector4D &vector)
+{
+ dbg.nospace() << "QVector4D("
+ << vector.x() << ", " << vector.y() << ", "
+ << vector.z() << ", " << vector.w() << ')';
+ return dbg.space();
+}
+
+#endif
+
+#ifndef QT_NO_DATASTREAM
+
+/*!
+ \fn QDataStream &operator<<(QDataStream &stream, const QVector4D &vector)
+ \relates QVector4D
+
+ Writes the given \a vector to the given \a stream and returns a
+ reference to the stream.
+
+ \sa {Serializing Qt Data Types}
+*/
+
+QDataStream &operator<<(QDataStream &stream, const QVector4D &vector)
+{
+ stream << double(vector.x()) << double(vector.y())
+ << double(vector.z()) << double(vector.w());
+ return stream;
+}
+
+/*!
+ \fn QDataStream &operator>>(QDataStream &stream, QVector4D &vector)
+ \relates QVector4D
+
+ Reads a 4D vector from the given \a stream into the given \a vector
+ and returns a reference to the stream.
+
+ \sa {Serializing Qt Data Types}
+*/
+
+QDataStream &operator>>(QDataStream &stream, QVector4D &vector)
+{
+ double x, y, z, w;
+ stream >> x;
+ stream >> y;
+ stream >> z;
+ stream >> w;
+ vector.setX(qreal(x));
+ vector.setY(qreal(y));
+ vector.setZ(qreal(z));
+ vector.setW(qreal(w));
+ return stream;
+}
+
+#endif // QT_NO_DATASTREAM
+
+#endif // QT_NO_VECTOR4D
+
+QT_END_NAMESPACE
diff --git a/src/gui/math3d/qvector4d.h b/src/gui/math3d/qvector4d.h
new file mode 100644
index 0000000000..1c1fb75873
--- /dev/null
+++ b/src/gui/math3d/qvector4d.h
@@ -0,0 +1,291 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QVECTOR4D_H
+#define QVECTOR4D_H
+
+#include <QtCore/qpoint.h>
+#include <QtCore/qmetatype.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QMatrix4x4;
+class QVector2D;
+class QVector3D;
+
+#ifndef QT_NO_VECTOR4D
+
+class Q_GUI_EXPORT QVector4D
+{
+public:
+ QVector4D();
+ QVector4D(qreal xpos, qreal ypos, qreal zpos, qreal wpos);
+ explicit QVector4D(const QPoint& point);
+ explicit QVector4D(const QPointF& point);
+#ifndef QT_NO_VECTOR2D
+ QVector4D(const QVector2D& vector);
+ QVector4D(const QVector2D& vector, qreal zpos, qreal wpos);
+#endif
+#ifndef QT_NO_VECTOR3D
+ QVector4D(const QVector3D& vector);
+ QVector4D(const QVector3D& vector, qreal wpos);
+#endif
+
+ bool isNull() const;
+
+ qreal x() const;
+ qreal y() const;
+ qreal z() const;
+ qreal w() const;
+
+ void setX(qreal x);
+ void setY(qreal y);
+ void setZ(qreal z);
+ void setW(qreal w);
+
+ qreal length() const;
+ qreal lengthSquared() const;
+
+ QVector4D normalized() const;
+ void normalize();
+
+ QVector4D &operator+=(const QVector4D &vector);
+ QVector4D &operator-=(const QVector4D &vector);
+ QVector4D &operator*=(qreal factor);
+ QVector4D &operator*=(const QVector4D &vector);
+ QVector4D &operator/=(qreal divisor);
+
+ static qreal dotProduct(const QVector4D& v1, const QVector4D& v2);
+
+ friend inline bool operator==(const QVector4D &v1, const QVector4D &v2);
+ friend inline bool operator!=(const QVector4D &v1, const QVector4D &v2);
+ friend inline const QVector4D operator+(const QVector4D &v1, const QVector4D &v2);
+ friend inline const QVector4D operator-(const QVector4D &v1, const QVector4D &v2);
+ friend inline const QVector4D operator*(qreal factor, const QVector4D &vector);
+ friend inline const QVector4D operator*(const QVector4D &vector, qreal factor);
+ friend inline const QVector4D operator*(const QVector4D &v1, const QVector4D& v2);
+ friend inline const QVector4D operator-(const QVector4D &vector);
+ friend inline const QVector4D operator/(const QVector4D &vector, qreal divisor);
+
+ friend inline bool qFuzzyCompare(const QVector4D& v1, const QVector4D& v2);
+
+#ifndef QT_NO_VECTOR2D
+ QVector2D toVector2D() const;
+ QVector2D toVector2DAffine() const;
+#endif
+#ifndef QT_NO_VECTOR3D
+ QVector3D toVector3D() const;
+ QVector3D toVector3DAffine() const;
+#endif
+
+ QPoint toPoint() const;
+ QPointF toPointF() const;
+
+ operator QVariant() const;
+
+private:
+ float xp, yp, zp, wp;
+
+ QVector4D(float xpos, float ypos, float zpos, float wpos, int dummy);
+
+ friend class QVector2D;
+ friend class QVector3D;
+#ifndef QT_NO_MATRIX4X4
+ friend QVector4D operator*(const QVector4D& vector, const QMatrix4x4& matrix);
+ friend QVector4D operator*(const QMatrix4x4& matrix, const QVector4D& vector);
+#endif
+};
+
+Q_DECLARE_TYPEINFO(QVector4D, Q_MOVABLE_TYPE);
+
+inline QVector4D::QVector4D() : xp(0.0f), yp(0.0f), zp(0.0f), wp(0.0f) {}
+
+inline QVector4D::QVector4D(qreal xpos, qreal ypos, qreal zpos, qreal wpos) : xp(xpos), yp(ypos), zp(zpos), wp(wpos) {}
+
+inline QVector4D::QVector4D(float xpos, float ypos, float zpos, float wpos, int) : xp(xpos), yp(ypos), zp(zpos), wp(wpos) {}
+
+inline QVector4D::QVector4D(const QPoint& point) : xp(point.x()), yp(point.y()), zp(0.0f), wp(0.0f) {}
+
+inline QVector4D::QVector4D(const QPointF& point) : xp(point.x()), yp(point.y()), zp(0.0f), wp(0.0f) {}
+
+inline bool QVector4D::isNull() const
+{
+ return qIsNull(xp) && qIsNull(yp) && qIsNull(zp) && qIsNull(wp);
+}
+
+inline qreal QVector4D::x() const { return qreal(xp); }
+inline qreal QVector4D::y() const { return qreal(yp); }
+inline qreal QVector4D::z() const { return qreal(zp); }
+inline qreal QVector4D::w() const { return qreal(wp); }
+
+inline void QVector4D::setX(qreal aX) { xp = aX; }
+inline void QVector4D::setY(qreal aY) { yp = aY; }
+inline void QVector4D::setZ(qreal aZ) { zp = aZ; }
+inline void QVector4D::setW(qreal aW) { wp = aW; }
+
+inline QVector4D &QVector4D::operator+=(const QVector4D &vector)
+{
+ xp += vector.xp;
+ yp += vector.yp;
+ zp += vector.zp;
+ wp += vector.wp;
+ return *this;
+}
+
+inline QVector4D &QVector4D::operator-=(const QVector4D &vector)
+{
+ xp -= vector.xp;
+ yp -= vector.yp;
+ zp -= vector.zp;
+ wp -= vector.wp;
+ return *this;
+}
+
+inline QVector4D &QVector4D::operator*=(qreal factor)
+{
+ xp *= factor;
+ yp *= factor;
+ zp *= factor;
+ wp *= factor;
+ return *this;
+}
+
+inline QVector4D &QVector4D::operator*=(const QVector4D &vector)
+{
+ xp *= vector.xp;
+ yp *= vector.yp;
+ zp *= vector.zp;
+ wp *= vector.wp;
+ return *this;
+}
+
+inline QVector4D &QVector4D::operator/=(qreal divisor)
+{
+ xp /= divisor;
+ yp /= divisor;
+ zp /= divisor;
+ wp /= divisor;
+ return *this;
+}
+
+inline bool operator==(const QVector4D &v1, const QVector4D &v2)
+{
+ return v1.xp == v2.xp && v1.yp == v2.yp && v1.zp == v2.zp && v1.wp == v2.wp;
+}
+
+inline bool operator!=(const QVector4D &v1, const QVector4D &v2)
+{
+ return v1.xp != v2.xp || v1.yp != v2.yp || v1.zp != v2.zp || v1.wp != v2.wp;
+}
+
+inline const QVector4D operator+(const QVector4D &v1, const QVector4D &v2)
+{
+ return QVector4D(v1.xp + v2.xp, v1.yp + v2.yp, v1.zp + v2.zp, v1.wp + v2.wp, 1);
+}
+
+inline const QVector4D operator-(const QVector4D &v1, const QVector4D &v2)
+{
+ return QVector4D(v1.xp - v2.xp, v1.yp - v2.yp, v1.zp - v2.zp, v1.wp - v2.wp, 1);
+}
+
+inline const QVector4D operator*(qreal factor, const QVector4D &vector)
+{
+ return QVector4D(vector.xp * factor, vector.yp * factor, vector.zp * factor, vector.wp * factor, 1);
+}
+
+inline const QVector4D operator*(const QVector4D &vector, qreal factor)
+{
+ return QVector4D(vector.xp * factor, vector.yp * factor, vector.zp * factor, vector.wp * factor, 1);
+}
+
+inline const QVector4D operator*(const QVector4D &v1, const QVector4D& v2)
+{
+ return QVector4D(v1.xp * v2.xp, v1.yp * v2.yp, v1.zp * v2.zp, v1.wp * v2.wp, 1);
+}
+
+inline const QVector4D operator-(const QVector4D &vector)
+{
+ return QVector4D(-vector.xp, -vector.yp, -vector.zp, -vector.wp, 1);
+}
+
+inline const QVector4D operator/(const QVector4D &vector, qreal divisor)
+{
+ return QVector4D(vector.xp / divisor, vector.yp / divisor, vector.zp / divisor, vector.wp / divisor, 1);
+}
+
+inline bool qFuzzyCompare(const QVector4D& v1, const QVector4D& v2)
+{
+ return qFuzzyCompare(v1.xp, v2.xp) &&
+ qFuzzyCompare(v1.yp, v2.yp) &&
+ qFuzzyCompare(v1.zp, v2.zp) &&
+ qFuzzyCompare(v1.wp, v2.wp);
+}
+
+inline QPoint QVector4D::toPoint() const
+{
+ return QPoint(qRound(xp), qRound(yp));
+}
+
+inline QPointF QVector4D::toPointF() const
+{
+ return QPointF(qreal(xp), qreal(yp));
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QVector4D &vector);
+#endif
+
+#ifndef QT_NO_DATASTREAM
+Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QVector4D &);
+Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QVector4D &);
+#endif
+
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif