diff options
Diffstat (limited to 'src/gui/math3d')
-rw-r--r-- | src/gui/math3d/math3d.pri | 20 | ||||
-rw-r--r-- | src/gui/math3d/qfixedpt.cpp | 681 | ||||
-rw-r--r-- | src/gui/math3d/qfixedpt.h | 521 | ||||
-rw-r--r-- | src/gui/math3d/qgenericmatrix.cpp | 221 | ||||
-rw-r--r-- | src/gui/math3d/qgenericmatrix.h | 341 | ||||
-rw-r--r-- | src/gui/math3d/qmath3dglobal.h | 72 | ||||
-rw-r--r-- | src/gui/math3d/qmath3dutil.cpp | 164 | ||||
-rw-r--r-- | src/gui/math3d/qmath3dutil_p.h | 66 | ||||
-rw-r--r-- | src/gui/math3d/qmatrix4x4.cpp | 1649 | ||||
-rw-r--r-- | src/gui/math3d/qmatrix4x4.h | 954 | ||||
-rw-r--r-- | src/gui/math3d/qquaternion.cpp | 513 | ||||
-rw-r--r-- | src/gui/math3d/qquaternion.h | 313 | ||||
-rw-r--r-- | src/gui/math3d/qvector2d.cpp | 386 | ||||
-rw-r--r-- | src/gui/math3d/qvector2d.h | 237 | ||||
-rw-r--r-- | src/gui/math3d/qvector3d.cpp | 535 | ||||
-rw-r--r-- | src/gui/math3d/qvector3d.h | 266 | ||||
-rw-r--r-- | src/gui/math3d/qvector4d.cpp | 491 | ||||
-rw-r--r-- | src/gui/math3d/qvector4d.h | 270 |
18 files changed, 7700 insertions, 0 deletions
diff --git a/src/gui/math3d/math3d.pri b/src/gui/math3d/math3d.pri new file mode 100644 index 0000000..581adbd --- /dev/null +++ b/src/gui/math3d/math3d.pri @@ -0,0 +1,20 @@ +HEADERS += \ + math3d/qfixedpt.h \ + math3d/qgenericmatrix.h \ + math3d/qmath3dglobal.h \ + math3d/qmath3dutil_p.h \ + math3d/qmatrix4x4.h \ + math3d/qquaternion.h \ + math3d/qvector2d.h \ + math3d/qvector3d.h \ + math3d/qvector4d.h + +SOURCES += \ + math3d/qfixedpt.cpp \ + math3d/qgenericmatrix.cpp \ + math3d/qmath3dutil.cpp \ + math3d/qmatrix4x4.cpp \ + math3d/qquaternion.cpp \ + math3d/qvector2d.cpp \ + math3d/qvector3d.cpp \ + math3d/qvector4d.cpp diff --git a/src/gui/math3d/qfixedpt.cpp b/src/gui/math3d/qfixedpt.cpp new file mode 100644 index 0000000..e7e61b6 --- /dev/null +++ b/src/gui/math3d/qfixedpt.cpp @@ -0,0 +1,681 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_LICENSE$ +** +****************************************************************************/ + +#include "qfixedpt.h" + +QT_BEGIN_NAMESPACE + +/*! + \internal + Returns the fixed-point square root of \a value. +*/ +qint64 qt_math3d_fixed_sqrt(qint64 value) +{ + qint64 result = 0; + qint64 bit = ((qint64)1) << 62; + while (bit > value) + bit >>= 2; + while (bit != 0) { + if (value >= (result + bit)) { + value -= result + bit; + result += (bit << 1); + } + result >>= 1; + bit >>= 2; + } + return result; +} + +/*! + \class QFixedPt + \brief The QFixedPt class represents fixed-point numbers within a 32-bit integer with a configurable precision. + + The template parameter is the number of bits of precision after + the decimal point. For example, QFixedPt<5> indicates that there + are 27 bits before the decimal point, and 5 bits of precision after + the decimal point. +*/ + +/*! + \fn QFixedPt::QFixedPt() + + Constructs a default fixed-point number. The initial value + is undefined. +*/ + +/*! + \fn QFixedPt::QFixedPt(int value) + + Constructs a fixed-point number from the integer \a value. +*/ + +/*! + \fn QFixedPt::QFixedPt(qreal value) + + Constructs a fixed-point number from the floating-point \a value. +*/ + +/*! + \fn QFixedPt<PrecBits>& QFixedPt::operator=(int value) + + Assigns the integer \a value to this fixed-point variable. +*/ + +/*! + \fn QFixedPt<PrecBits>& QFixedPt::operator=(qreal value) + + Assigns the floating-point \a value to this fixed-point variable. +*/ + +/*! + \fn int QFixedPt::bits() const + + Returns the raw bits that represent the fixed-point value of this object. + + \sa setBits() +*/ + +/*! + \fn void QFixedPt::setBits(int value) + + Sets the raw bits that represent the fixed-point value of + this object to \a value. + + \sa bits() +*/ + +#if !defined(QT_NO_MEMBER_TEMPLATES) || defined(Q_QDOC) + +/*! + \fn QFixedPt<Prec> QFixedPt::toPrecision() const + + Returns this fixed-point number, converted to the new fixed-point + precision Prec. + + \sa qFixedPtToPrecision() +*/ + +#endif + +/*! + \fn QFixedPt<Prec> qFixedPtToPrecision(const QFixedPt<PrecBits>& value) + + Returns the fixed-point number \a value, converted to the new fixed-point + precision Prec. + + \sa QFixedPt::toPrecision() +*/ + +/*! + \fn QFixedPt<PrecBits>& QFixedPt::operator+=(const QFixedPt<PrecBits>& value) + + Adds \a value to this fixed-point number. +*/ + +/*! + \fn QFixedPt<PrecBits>& QFixedPt::operator+=(int value) + + Adds an integer \a value to this fixed-point number. +*/ + +/*! + \fn QFixedPt<PrecBits>& QFixedPt::operator+=(qreal value) + + Adds a floating-point \a value to this fixed-point number. +*/ + +/*! + \fn QFixedPt<PrecBits>& QFixedPt::operator-=(const QFixedPt<PrecBits>& value) + + Subtracts \a value from this fixed-point number. +*/ + +/*! + \fn QFixedPt<PrecBits>& QFixedPt::operator-=(int value) + + Subtracts an integer \a value from this fixed-point number. +*/ + +/*! + \fn QFixedPt<PrecBits>& QFixedPt::operator-=(qreal value) + + Subtracts a floating-point \a value from this fixed-point number. +*/ + +/*! + \fn QFixedPt<PrecBits>& QFixedPt::operator*=(const QFixedPt<PrecBits>& value) + + Multiplies this fixed-point number by \a value. +*/ + +/*! + \fn QFixedPt<PrecBits>& QFixedPt::operator*=(int value) + + Multiplies this fixed-point number by an integer \a value. +*/ + +/*! + \fn QFixedPt<PrecBits>& QFixedPt::operator*=(qreal value) + + Multiplies this fixed-point number by a floating-point \a value. +*/ + +/*! + \fn QFixedPt<PrecBits>& QFixedPt::operator/=(const QFixedPt<PrecBits>& value) + + Divides this fixed-point number by \a value. Division by zero + will result in zero. +*/ + +/*! + \fn QFixedPt<PrecBits>& QFixedPt::operator/=(int value) + + Divides this fixed-point number by an integer \a value. Division + by zero will result in zero. +*/ + +/*! + \fn QFixedPt<PrecBits>& QFixedPt::operator/=(qreal value) + + Divides this fixed-point number by a floating-point \a value. Division + by zero will result in zero. +*/ + +/*! + \fn QFixedPt<PrecBits>& QFixedPt::operator<<=(int value) + + Shifts this fixed-point number left by \a value bits. +*/ + +/*! + \fn QFixedPt<PrecBits>& QFixedPt::operator>>=(int value) + + Shifts this fixed-point number right by \a value bits. +*/ + +/*! + \fn QFixedPt<PrecBits> QFixedPt::operator<<(int value) const + + Returns the result of shifting this fixed-point number + left by \a value bits. +*/ + +/*! + \fn QFixedPt<PrecBits> QFixedPt::operator>>(int value) const + + Returns the result of shifting this fixed-point number + right by \a value bits. +*/ + +/*! + \fn bool QFixedPt::operator==(const QFixedPt<PrecBits>& value) const + + Returns true if this fixed-point number is equal to \a value; + false otherwise. +*/ + +/*! + \fn bool operator==(const QFixedPt<PrecBits>& v1, int v2) + \relates QFixedPt + + Returns true if \a v1 is equal to \a v2; false otherwise. +*/ + +/*! + \fn bool operator==(int v1, const QFixedPt<PrecBits>& v2) + \relates QFixedPt + + Returns true if \a v1 is equal to \a v2; false otherwise. +*/ + +/*! + \fn bool operator==(const QFixedPt<PrecBits>& v1, qreal v2) + \relates QFixedPt + + Returns true if \a v1 is equal to \a v2; false otherwise. +*/ + +/*! + \fn bool operator==(qreal v1, const QFixedPt<PrecBits>& v2) + \relates QFixedPt + + Returns true if \a v1 is equal to \a v2; false otherwise. +*/ + +/*! + \fn bool QFixedPt::operator!=(const QFixedPt<PrecBits>& value) const + + Returns true if this fixed-point number is not equal to \a value; + false otherwise. +*/ + +/*! + \fn bool operator!=(const QFixedPt<PrecBits>& v1, int v2) + \relates QFixedPt + + Returns true if \a v1 is not equal to \a v2; false otherwise. +*/ + +/*! + \fn bool operator!=(int v1, const QFixedPt<PrecBits>& v2) + \relates QFixedPt + + Returns true if \a v1 is not equal to \a v2; false otherwise. +*/ + +/*! + \fn bool operator!=(const QFixedPt<PrecBits>& v1, qreal v2) + \relates QFixedPt + + Returns true if \a v1 is not equal to \a v2; false otherwise. +*/ + +/*! + \fn bool operator!=(qreal v1, const QFixedPt<PrecBits>& v2) + \relates QFixedPt + + Returns true if \a v1 is not equal to \a v2; false otherwise. +*/ + +/*! + \fn bool QFixedPt::operator<=(const QFixedPt<PrecBits>& value) const + + Returns true if this fixed-point number is less than or equal to + \a value; false otherwise. +*/ + +/*! + \fn bool operator<=(const QFixedPt<PrecBits>& v1, int v2) + \relates QFixedPt + + Returns true if \a v1 is less than or equal to \a v2; false otherwise. +*/ + +/*! + \fn bool operator<=(int v1, const QFixedPt<PrecBits>& v2) + \relates QFixedPt + + Returns true if \a v1 is less than or equal to \a v2; false otherwise. +*/ + +/*! + \fn bool operator<=(const QFixedPt<PrecBits>& v1, qreal v2) + \relates QFixedPt + + Returns true if \a v1 is less than or equal to \a v2; false otherwise. +*/ + +/*! + \fn bool operator<=(qreal v1, const QFixedPt<PrecBits>& v2) + \relates QFixedPt + + Returns true if \a v1 is less than or equal to \a v2; false otherwise. +*/ + +/*! + \fn bool QFixedPt::operator<(const QFixedPt<PrecBits>& value) const + + Returns true if this fixed-point number is less than \a value; + false otherwise. +*/ + +/*! + \fn bool operator<(const QFixedPt<PrecBits>& v1, int v2) + \relates QFixedPt + + Returns true if \a v1 is less than \a v2; false otherwise. +*/ + +/*! + \fn bool operator<(int v1, const QFixedPt<PrecBits>& v2) + \relates QFixedPt + + Returns true if \a v1 is less than \a v2; false otherwise. +*/ + +/*! + \fn bool operator<(const QFixedPt<PrecBits>& v1, qreal v2) + \relates QFixedPt + + Returns true if \a v1 is less than \a v2; false otherwise. +*/ + +/*! + \fn bool operator<(qreal v1, const QFixedPt<PrecBits>& v2) + \relates QFixedPt + + Returns true if \a v1 is less than \a v2; false otherwise. +*/ + +/*! + \fn bool QFixedPt::operator>=(const QFixedPt<PrecBits>& value) const + + Returns true if this fixed-point number is greater than or equal to + \a value; false otherwise. +*/ + +/*! + \fn bool operator>=(const QFixedPt<PrecBits>& v1, int v2) + \relates QFixedPt + + Returns true if \a v1 is greater than or equal to \a v2; false otherwise. +*/ + +/*! + \fn bool operator>=(int v1, const QFixedPt<PrecBits>& v2) + \relates QFixedPt + + Returns true if \a v1 is greater than or equal to \a v2; false otherwise. +*/ + +/*! + \fn bool operator>=(const QFixedPt<PrecBits>& v1, qreal v2) + \relates QFixedPt + + Returns true if \a v1 is greater than or equal to \a v2; false otherwise. +*/ + +/*! + \fn bool operator>=(qreal v1, const QFixedPt<PrecBits>& v2) + \relates QFixedPt + + Returns true if \a v1 is greater than or equal to \a v2; false otherwise. +*/ + +/*! + \fn bool QFixedPt::operator>(const QFixedPt<PrecBits>& value) const + + Returns true if this fixed-point number is greater than \a value; + false otherwise. +*/ + +/*! + \fn bool operator>(const QFixedPt<PrecBits>& v1, int v2) + \relates QFixedPt + + Returns true if \a v1 is greater than \a v2; false otherwise. +*/ + +/*! + \fn bool operator>(int v1, const QFixedPt<PrecBits>& v2) + \relates QFixedPt + + Returns true if \a v1 is greater than \a v2; false otherwise. +*/ + +/*! + \fn bool operator>(const QFixedPt<PrecBits>& v1, qreal v2) + \relates QFixedPt + + Returns true if \a v1 is greater than \a v2; false otherwise. +*/ + +/*! + \fn bool operator>(qreal v1, const QFixedPt<PrecBits>& v2) + \relates QFixedPt + + Returns true if \a v1 is greater than \a v2; false otherwise. +*/ + +/*! + \fn QFixedPt<PrecBits> QFixedPt::operator+(const QFixedPt<PrecBits>& value) const + + Returns the result of adding this fixed-point number and \a value. +*/ + +/*! + \fn QFixedPt<PrecBits> QFixedPt::operator+(int value) const + + Returns the result of adding this fixed-point number and \a value. +*/ + +/*! + \fn QFixedPt<PrecBits> QFixedPt::operator+(qreal value) const + + Returns the result of adding this fixed-point number and \a value. +*/ + +/*! + \fn QFixedPt<PrecBits> operator+(int v1, const QFixedPt<PrecBits>& v2) + \relates QFixedPt + + Returns the result of adding \a v1 and \a v2. +*/ + +/*! + \fn QFixedPt<PrecBits> operator+(qreal v1, const QFixedPt<PrecBits>& v2) + \relates QFixedPt + + Returns the result of adding \a v1 and \a v2. +*/ + +/*! + \fn QFixedPt<PrecBits> QFixedPt::operator-(const QFixedPt<PrecBits>& value) const + + Returns the result of subtracting \a value from this fixed-point number. +*/ + +/*! + \fn QFixedPt<PrecBits> QFixedPt::operator-(int value) const + + Returns the result of subtracting \a value from this fixed-point number. +*/ + +/*! + \fn QFixedPt<PrecBits> QFixedPt::operator-(qreal value) const + + Returns the result of subtracting \a value from this fixed-point number. +*/ + +/*! + \fn QFixedPt<PrecBits> operator-(int v1, const QFixedPt<PrecBits>& v2) + \relates QFixedPt + + Returns the result of subtracting \a v2 from \a v1. +*/ + +/*! + \fn QFixedPt<PrecBits> operator-(qreal v1, const QFixedPt<PrecBits>& v2) + \relates QFixedPt + + Returns the result of subtracting \a v2 from \a v1. +*/ + +/*! + \fn QFixedPt<PrecBits> QFixedPt::operator*(const QFixedPt<PrecBits>& value) const + + Returns the result of multiplying this fixed-point number by \a value. +*/ + +/*! + \fn QFixedPt<PrecBits> QFixedPt::operator*(int value) const + + Returns the result of multiplying this fixed-point number by \a value. +*/ + +/*! + \fn QFixedPt<PrecBits> QFixedPt::operator*(qreal value) const + + Returns the result of multiplying this fixed-point number by \a value. +*/ + +/*! + \fn QFixedPt<PrecBits> operator*(int v1, const QFixedPt<PrecBits>& v2) + \relates QFixedPt + + Returns the result of multiplying \a v1 by \a v2. +*/ + +/*! + \fn QFixedPt<PrecBits> operator*(qreal v1, const QFixedPt<PrecBits>& v2) + \relates QFixedPt + + Returns the result of multiplying \a v1 by \a v2. +*/ + +/*! + \fn QFixedPt<PrecBits> QFixedPt::operator/(const QFixedPt<PrecBits>& value) const + + Returns the result of dividing this fixed-point number by \a value. + Division by zero will result in zero. +*/ + +/*! + \fn QFixedPt<PrecBits> QFixedPt::operator/(int value) const + + Returns the result of dividing this fixed-point number by \a value. + Division by zero will result in zero. +*/ + +/*! + \fn QFixedPt<PrecBits> QFixedPt::operator/(qreal value) const + + Returns the result of dividing this fixed-point number by \a value. + Division by zero will result in zero. +*/ + +/*! + \fn QFixedPt<PrecBits> operator/(int v1, const QFixedPt<PrecBits>& v2) + \relates QFixedPt + + Returns the result of dividing \a v1 by \a v2. Division by zero will + result in zero. +*/ + +/*! + \fn QFixedPt<PrecBits> operator/(qreal v1, const QFixedPt<PrecBits>& v2) + \relates QFixedPt + + Returns the result of dividing \a v1 by \a v2. Division by zero will + result in zero. +*/ + +/*! + \fn QFixedPt<PrecBits> QFixedPt::operator-() const + + Returns the negation of this fixed-point number. +*/ + +/*! + \fn QFixedPt<PrecBits> QFixedPt::sqrt() const + + Returns the square root of this fixed-point number. + + \sa sqrtF() +*/ + +/*! + \fn qreal QFixedPt::sqrtF() const + + Return the square root of this fixed-point number as a + floating-point value. + + \sa sqrt() +*/ + +/*! + \fn QFixedPt<PrecBits> QFixedPt::round() const + + Returns this fixed-point number, rounded to the nearest integer. + + \sa floor(), ceil(), truncate() +*/ + +/*! + \fn QFixedPt<PrecBits> QFixedPt::floor() const; + + Returns the largest integer that is less than or equal to + this fixed-point number. + + \sa round(), ceil(), truncate() +*/ + +/*! + \fn QFixedPt<PrecBits> QFixedPt::ceil() const + + Returns the smallest integer that is greater than or equal to + this fixed-point number. + + \sa round(), floor(), truncate() +*/ + +/*! + \fn int QFixedPt::truncate() const + + Returns this fixed-point number with the bits after the + decimal point truncated. + + \sa round(), floor(), ceil() +*/ + +/*! + \fn int QFixedPt::toInt() const + + Returns this fixed-point number, rounded to the nearest integer. + + \sa toReal() +*/ + +/*! + \fn qreal QFixedPt::toReal() const + + Returns this fixed-point number as a floating-point value. + + \sa toInt() +*/ + +/*! + \fn int qCeil(const QFixedPt<PrecBits>& value) + \relates QFixedPt + + Returns the smallest integer that is greater than or equal to + \a value. + + \sa qFloor(), qRound(), QFixedPt::ceil() +*/ + +/*! + \fn int qFloor(const QFixedPt<PrecBits>& value) + \relates QFixedPt + + Returns the largest integer that is less than or equal to + \a value. + + \sa qCeil(), qRound(), QFixedPt::floor() +*/ + +/*! + \fn int qRound(const QFixedPt<PrecBits>& value) + \relates QFixedPt + + Returns \a value, rounded to the nearest integer. + + \sa qCeil(), qFloor(), QFixedPt::round() +*/ + +/*! + \fn bool qFuzzyCompare(const QFixedPt<PrecBits>& v1, const QFixedPt<PrecBits>& v2, int compareBits) + \relates QFixedPt + + Returns true if \a v1 is almost equal to \a v2; false otherwise. + The \a compareBits parameter specifies the number of bits of precision + that should be considered relevant when performing the comparison. + By default, \a compareBits is PrecBits / 4. +*/ + +/*! + \fn bool qIsNull(const QFixedPt<PrecBits>& v) + \relates QFixedPt + + Returns true if \a v is zero; false otherwise. +*/ + +QT_END_NAMESPACE diff --git a/src/gui/math3d/qfixedpt.h b/src/gui/math3d/qfixedpt.h new file mode 100644 index 0000000..ecbcad4 --- /dev/null +++ b/src/gui/math3d/qfixedpt.h @@ -0,0 +1,521 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_LICENSE$ +** +****************************************************************************/ + +#ifndef QFIXEDPT_H +#define QFIXEDPT_H + +#include <QtCore/qglobal.h> +#include <QtCore/qdebug.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +Q_GUI_EXPORT qint64 qt_math3d_fixed_sqrt(qint64 value); + +// Should be called QFixed or QFixedPoint, but both of those +// are already in use in src/gui/painting/qfixed_p.h. +template <int PrecBits> +class QFixedPt +{ +public: + inline QFixedPt() {} // Deliberately not initialized - don't change this. + inline QFixedPt(int value) : val(value << PrecBits) {} + inline QFixedPt(qreal value) : val(int(value * (1 << PrecBits))) {} + + inline QFixedPt<PrecBits>& operator=(int value) + { val = value << PrecBits; return *this; } + inline QFixedPt<PrecBits>& operator=(qreal value) + { val = int(value * (1 << PrecBits)); return *this; } + + inline int bits() const { return val; } + inline void setBits(int value) { val = value; } + +#if !defined(QT_NO_MEMBER_TEMPLATES) || defined(Q_QDOC) + template <int Prec> + inline QFixedPt<Prec> toPrecision() const + { + QFixedPt<Prec> result; + if (Prec < PrecBits) + result.setBits(shiftRight(val, (PrecBits - Prec))); + else + result.setBits(shiftLeft(val, (Prec - PrecBits))); + return result; + } +#endif + + inline QFixedPt<PrecBits>& operator+=(const QFixedPt<PrecBits>& value) + { val += value.val; return *this; } + inline QFixedPt<PrecBits>& operator+=(int value) + { val += (value << PrecBits); return *this; } + inline QFixedPt<PrecBits>& operator+=(qreal value) + { val += int(value * (1 << PrecBits)); return *this; } + + inline QFixedPt<PrecBits>& operator-=(const QFixedPt<PrecBits>& value) + { val -= value.val; return *this; } + inline QFixedPt<PrecBits>& operator-=(int value) + { val -= (value << PrecBits); return *this; } + inline QFixedPt<PrecBits>& operator-=(qreal value) + { val -= int(value * (1 << PrecBits)); return *this; } + + inline QFixedPt<PrecBits>& operator*=(const QFixedPt<PrecBits>& value) + { val = mul(val, value.val); return *this; } + inline QFixedPt<PrecBits>& operator*=(int value) + { val = mul(val, (value << PrecBits)); return *this; } + inline QFixedPt<PrecBits>& operator*=(qreal value) + { val = mul(val, int(value * (1 << PrecBits))); return *this; } + + inline QFixedPt<PrecBits>& operator/=(const QFixedPt<PrecBits>& value) + { val = div(val, value.val); return *this; } + inline QFixedPt<PrecBits>& operator/=(int value) + { val = div(val, (value << PrecBits)); return *this; } + inline QFixedPt<PrecBits>& operator/=(qreal value) + { val = div(val, int(value * (1 << PrecBits))); return *this; } + + inline QFixedPt<PrecBits>& operator<<=(int value) + { val <<= value; return *this; } + inline QFixedPt<PrecBits>& operator>>=(int value) + { val >>= value; return *this; } + + inline QFixedPt<PrecBits> operator<<(int value) const + { QFixedPt<PrecBits> result; result.val = val << value; return result; } + inline QFixedPt<PrecBits> operator>>(int value) const + { QFixedPt<PrecBits> result; result.val = val >> value; return result; } + + inline bool operator==(const QFixedPt<PrecBits>& value) const + { return val == value.val; } + inline bool operator!=(const QFixedPt<PrecBits>& value) const + { return val != value.val; } + inline bool operator<=(const QFixedPt<PrecBits>& value) const + { return val <= value.val; } + inline bool operator<(const QFixedPt<PrecBits>& value) const + { return val < value.val; } + inline bool operator>=(const QFixedPt<PrecBits>& value) const + { return val >= value.val; } + inline bool operator>(const QFixedPt<PrecBits>& value) const + { return val > value.val; } + + inline QFixedPt<PrecBits> operator+(const QFixedPt<PrecBits>& value) const + { QFixedPt<PrecBits> result; + result.val = val + value.val; return result; } + inline QFixedPt<PrecBits> operator+(int value) const + { QFixedPt<PrecBits> result; + result.val = val + (value << PrecBits); return result; } + inline QFixedPt<PrecBits> operator+(qreal value) const + { QFixedPt<PrecBits> result; + result.val = val + int(value * (1 << PrecBits)); return result; } + + inline QFixedPt<PrecBits> operator-(const QFixedPt<PrecBits>& value) const + { QFixedPt<PrecBits> result; + result.val = val - value.val; return result; } + inline QFixedPt<PrecBits> operator-(int value) const + { QFixedPt<PrecBits> result; + result.val = val - (value << PrecBits); return result; } + inline QFixedPt<PrecBits> operator-(qreal value) const + { QFixedPt<PrecBits> result; + result.val = val - int(value * (1 << PrecBits)); return result; } + + inline QFixedPt<PrecBits> operator*(const QFixedPt<PrecBits>& value) const + { QFixedPt<PrecBits> result; + result.val = mul(val, value.val); return result; } + inline QFixedPt<PrecBits> operator*(int value) const + { QFixedPt<PrecBits> result; + result.val = mul(val, (value << PrecBits)); return result; } + inline QFixedPt<PrecBits> operator*(qreal value) const + { QFixedPt<PrecBits> result; + result.val = mul(val, int(value * (1 << PrecBits))); return result; } + + inline QFixedPt<PrecBits> operator/(const QFixedPt<PrecBits>& value) const + { QFixedPt<PrecBits> result; + result.val = div(val, value.val); return result; } + inline QFixedPt<PrecBits> operator/(int value) const + { QFixedPt<PrecBits> result; + result.val = div(val, (value << PrecBits)); return result; } + inline QFixedPt<PrecBits> operator/(qreal value) const + { QFixedPt<PrecBits> result; + result.val = div(val, int(value * (1 << PrecBits))); return result; } + + inline QFixedPt<PrecBits> operator-() const + { QFixedPt<PrecBits> result; result.val = -val; return result; } + + inline QFixedPt<PrecBits> sqrt() const; + inline qreal sqrtF() const; + inline QFixedPt<PrecBits> round() const; + inline QFixedPt<PrecBits> floor() const; + inline QFixedPt<PrecBits> ceil() const; + inline int truncate() const { return val >> PrecBits; } + + inline int toInt() const { return (val + (1 << (PrecBits - 1))) >> PrecBits; } + inline qreal toReal() const { return qreal(val) / qreal(1 << PrecBits); } + +#if !defined(Q_NO_TEMPLATE_FRIENDS) + template <int Prec> + friend QFixedPt<Prec> operator/(int v1, const QFixedPt<Prec>& v2); + template <int Prec> + friend QFixedPt<Prec> operator/(qreal v1, const QFixedPt<Prec>& v2); + +private: +#endif + int val; + + inline static int mul(int v1, int v2) + { + return int((qint64(v1) * qint64(v2)) >> PrecBits); + } + + inline static int div(int v1, int v2) + { + if (v2) + return int((qint64(v1) << PrecBits) / qint64(v2)); + else + return 0; + } + + // These are used by toPrecision() to avoid a silly gcc compiler warning + // related to negative shift values that will never actually be used. + inline static int shiftRight(int val, int shift) + { + return val >> shift; + } + inline static int shiftLeft(int val, int shift) + { + return val << shift; + } + +#if !defined(Q_NO_TEMPLATE_FRIENDS) + template <int Prec, int Prec2> + friend QFixedPt<Prec> qFixedPtToPrecision(const QFixedPt<Prec2>& value); +#endif +}; + +template <int PrecBits> +inline bool operator==(const QFixedPt<PrecBits>& v1, int v2) +{ + return v1.bits() == (v2 << PrecBits); +} + +template <int PrecBits> +inline bool operator==(int v1, const QFixedPt<PrecBits>& v2) +{ + return (v1 << PrecBits) == v2.bits(); +} + +template <int PrecBits> +inline bool operator==(const QFixedPt<PrecBits>& v1, qreal v2) +{ + return v1.bits() == int(v2 * (1 << PrecBits)); +} + +template <int PrecBits> +inline bool operator==(qreal v1, const QFixedPt<PrecBits>& v2) +{ + return int(v1 * (1 << PrecBits)) == v2.bits(); +} + +template <int PrecBits> +inline bool operator!=(const QFixedPt<PrecBits>& v1, int v2) +{ + return v1.bits() != (v2 << PrecBits); +} + +template <int PrecBits> +inline bool operator!=(int v1, const QFixedPt<PrecBits>& v2) +{ + return (v1 << PrecBits) != v2.bits(); +} + +template <int PrecBits> +inline bool operator!=(const QFixedPt<PrecBits>& v1, qreal v2) +{ + return v1.bits() != int(v2 * (1 << PrecBits)); +} + +template <int PrecBits> +inline bool operator!=(qreal v1, const QFixedPt<PrecBits>& v2) +{ + return int(v1 * (1 << PrecBits)) != v2.bits(); +} + +template <int PrecBits> +inline bool operator<=(const QFixedPt<PrecBits>& v1, int v2) +{ + return v1.bits() <= (v2 << PrecBits); +} + +template <int PrecBits> +inline bool operator<=(int v1, const QFixedPt<PrecBits>& v2) +{ + return (v1 << PrecBits) <= v2.bits(); +} + +template <int PrecBits> +inline bool operator<=(const QFixedPt<PrecBits>& v1, qreal v2) +{ + return v1.bits() <= int(v2 * (1 << PrecBits)); +} + +template <int PrecBits> +inline bool operator<=(qreal v1, const QFixedPt<PrecBits>& v2) +{ + return int(v1 * (1 << PrecBits)) <= v2.bits(); +} + +template <int PrecBits> +inline bool operator<(const QFixedPt<PrecBits>& v1, int v2) +{ + return v1.bits() < (v2 << PrecBits); +} + +template <int PrecBits> +inline bool operator<(int v1, const QFixedPt<PrecBits>& v2) +{ + return (v1 << PrecBits) < v2.bits(); +} + +template <int PrecBits> +inline bool operator<(const QFixedPt<PrecBits>& v1, qreal v2) +{ + return v1.bits() < int(v2 * (1 << PrecBits)); +} + +template <int PrecBits> +inline bool operator<(qreal v1, const QFixedPt<PrecBits>& v2) +{ + return int(v1 * (1 << PrecBits)) < v2.bits(); +} + +template <int PrecBits> +inline bool operator>=(const QFixedPt<PrecBits>& v1, int v2) +{ + return v1.bits() >= (v2 << PrecBits); +} + +template <int PrecBits> +inline bool operator>=(int v1, const QFixedPt<PrecBits>& v2) +{ + return (v1 << PrecBits) >= v2.bits(); +} + +template <int PrecBits> +inline bool operator>=(const QFixedPt<PrecBits>& v1, qreal v2) +{ + return v1.bits() >= int(v2 * (1 << PrecBits)); +} + +template <int PrecBits> +inline bool operator>=(qreal v1, const QFixedPt<PrecBits>& v2) +{ + return int(v1 * (1 << PrecBits)) >= v2.bits(); +} + +template <int PrecBits> +inline bool operator>(const QFixedPt<PrecBits>& v1, int v2) +{ + return v1.bits() > (v2 << PrecBits); +} + +template <int PrecBits> +inline bool operator>(int v1, const QFixedPt<PrecBits>& v2) +{ + return (v1 << PrecBits) > v2.bits(); +} + +template <int PrecBits> +inline bool operator>(const QFixedPt<PrecBits>& v1, qreal v2) +{ + return v1.bits() > int(v2 * (1 << PrecBits)); +} + +template <int PrecBits> +inline bool operator>(qreal v1, const QFixedPt<PrecBits>& v2) +{ + return int(v1 * (1 << PrecBits)) > v2.bits(); +} + +template <int PrecBits> +inline QFixedPt<PrecBits> operator+(int v1, const QFixedPt<PrecBits>& v2) +{ + return v2 + v1; +} + +template <int PrecBits> +inline QFixedPt<PrecBits> operator+(qreal v1, const QFixedPt<PrecBits>& v2) +{ + return v2 + v1; +} + +template <int PrecBits> +inline QFixedPt<PrecBits> operator-(int v1, const QFixedPt<PrecBits>& v2) +{ + return -(v2 - v1); +} + +template <int PrecBits> +inline QFixedPt<PrecBits> operator-(qreal v1, const QFixedPt<PrecBits>& v2) +{ + return -(v2 - v1); +} + +template <int PrecBits> +inline QFixedPt<PrecBits> operator*(int v1, const QFixedPt<PrecBits>& v2) +{ + return v2 * v1; +} + +template <int PrecBits> +inline QFixedPt<PrecBits> operator*(qreal v1, const QFixedPt<PrecBits>& v2) +{ + return v2 * v1; +} + +template <int PrecBits> +inline QFixedPt<PrecBits> operator/(int v1, const QFixedPt<PrecBits>& v2) +{ + QFixedPt<PrecBits> result; + result.val = QFixedPt<PrecBits>::div(v1 << PrecBits, v2.val); + return result; +} + +template <int PrecBits> +inline QFixedPt<PrecBits> operator/(qreal v1, const QFixedPt<PrecBits>& v2) +{ + QFixedPt<PrecBits> result; + result.val = QFixedPt<PrecBits>::div(int(v1 * (1 << PrecBits)), v2.val); + return result; +} + +template <int PrecBits> +inline QFixedPt<PrecBits> QFixedPt<PrecBits>::sqrt() const +{ + QFixedPt<PrecBits> result; + result.val = int(qt_math3d_fixed_sqrt + (qint64(val) << (PrecBits * 2)) >> (PrecBits / 2)); + return result; +} + +template <int PrecBits> +inline qreal QFixedPt<PrecBits>::sqrtF() const +{ + return qt_math3d_fixed_sqrt + (qint64(val) << (PrecBits * 2)) / (qreal)(1 << (PrecBits + (PrecBits / 2))); +} + +template <int PrecBits> +inline QFixedPt<PrecBits> QFixedPt<PrecBits>::round() const +{ + QFixedPt<PrecBits> result; + result.val = (val + (1 << (PrecBits - 1))) & ~((1 << PrecBits) - 1); + return result; +} + +template <int PrecBits> +inline QFixedPt<PrecBits> QFixedPt<PrecBits>::floor() const +{ + QFixedPt<PrecBits> result; + result.val = val & ~((1 << PrecBits) - 1); + return result; +} + +template <int PrecBits> +inline QFixedPt<PrecBits> QFixedPt<PrecBits>::ceil() const +{ + QFixedPt<PrecBits> result; + result.val = (val + (1 << PrecBits) - 1) & ~((1 << PrecBits) - 1); + return result; +} + +template <int PrecBits> +inline int qCeil(const QFixedPt<PrecBits>& value) +{ + return value.ceil().bits() >> PrecBits; +} + +template <int PrecBits> +inline int qFloor(const QFixedPt<PrecBits>& value) +{ + return value.floor().bits() >> PrecBits; +} + +template <int PrecBits> +inline int qRound(const QFixedPt<PrecBits>& value) +{ + return value.round().bits() >> PrecBits; +} + +template <int PrecBits> +inline bool qFuzzyCompare(const QFixedPt<PrecBits>& v1, const QFixedPt<PrecBits>& v2, int compareBits = (PrecBits / 4)) +{ + return ((v1.bits() ^ v2.bits()) & ~((1 << compareBits) - 1)) == 0; +} + +template <int PrecBits> +inline bool qIsNull(const QFixedPt<PrecBits>& v) +{ + return v.bits() == 0; +} + +template <int Prec, int PrecBits> +QFixedPt<Prec> qFixedPtToPrecision(const QFixedPt<PrecBits>& value) +{ + QFixedPt<Prec> result; + if (Prec < PrecBits) + result.setBits(QFixedPt<PrecBits>::shiftRight(value.bits(), (PrecBits - Prec))); + else + result.setBits(QFixedPt<PrecBits>::shiftLeft(value.bits(), (Prec - PrecBits))); + return result; +} + +template <int PrecBits> +inline QDebug &operator<<(QDebug &dbg, const QFixedPt<PrecBits> &f) +{ + return dbg << f.toReal(); +} + +Q_DECLARE_TYPEINFO(QFixedPt<0>, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(QFixedPt<1>, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(QFixedPt<2>, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(QFixedPt<3>, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(QFixedPt<4>, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(QFixedPt<5>, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(QFixedPt<6>, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(QFixedPt<7>, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(QFixedPt<8>, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(QFixedPt<9>, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(QFixedPt<10>, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(QFixedPt<11>, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(QFixedPt<12>, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(QFixedPt<13>, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(QFixedPt<14>, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(QFixedPt<15>, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(QFixedPt<16>, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(QFixedPt<17>, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(QFixedPt<18>, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(QFixedPt<19>, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(QFixedPt<20>, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(QFixedPt<21>, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(QFixedPt<22>, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(QFixedPt<23>, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(QFixedPt<24>, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(QFixedPt<25>, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(QFixedPt<26>, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(QFixedPt<27>, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(QFixedPt<28>, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(QFixedPt<29>, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(QFixedPt<30>, Q_PRIMITIVE_TYPE); +Q_DECLARE_TYPEINFO(QFixedPt<31>, Q_PRIMITIVE_TYPE); + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/gui/math3d/qgenericmatrix.cpp b/src/gui/math3d/qgenericmatrix.cpp new file mode 100644 index 0000000..cb48909 --- /dev/null +++ b/src/gui/math3d/qgenericmatrix.cpp @@ -0,0 +1,221 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_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 + + The QGenericMatrix template has four 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. + \row \i InnerT \i Element type that is used inside the class. + \endtable + + Normally T and InnerT are the same type; e.g. float or double. + But they can be different if the user wants to store elements + internally in a fixed-point format for the underlying hardware. + + \sa QMatrix4x4, QFixedPt +*/ + +/*! + \fn QGenericMatrix::QGenericMatrix() + + Constructs a NxM identity matrix. +*/ + +/*! + \fn QGenericMatrix::QGenericMatrix(const QGenericMatrix<N, M, T, InnerT>& 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 toValueArray() +*/ + +/*! + \fn T QGenericMatrix::operator()(int row, int column) const + + Returns the element at position (\a row, \a column) in this matrix. +*/ + +/*! + \fn InnerT& 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 setIdentity() +*/ + +/*! + \fn void QGenericMatrix::setIdentity() + + Sets this matrix to the identity. + + \sa isIdentity() +*/ + +/*! + \fn void QGenericMatrix::fill(qreal 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, InnerT>& QGenericMatrix::operator+=(const QGenericMatrix<N, M, T, InnerT>& other) + + Adds the contents of \a other to this matrix. +*/ + +/*! + \fn QGenericMatrix<N, M, T, InnerT>& QGenericMatrix::operator-=(const QGenericMatrix<N, M, T, InnerT>& other) + + Subtracts the contents of \a other from this matrix. +*/ + +/*! + \fn QGenericMatrix<N, M, T, InnerT>& QGenericMatrix::operator*=(T factor) + + Multiplies all elements of this matrix by \a factor. +*/ + +/*! + \fn QGenericMatrix<N, M, T, InnerT>& QGenericMatrix::operator/=(T divisor) + + Divides all elements of this matrix by \a divisor. +*/ + +/*! + \fn bool QGenericMatrix::operator==(const QGenericMatrix<N, M, T, InnerT>& other) const + + Returns true if this matrix is identical to \a other; false otherwise. +*/ + +/*! + \fn bool QGenericMatrix::operator!=(const QGenericMatrix<N, M, T, InnerT>& other) const + + Returns true if this matrix is not identical to \a other; false otherwise. +*/ + +/*! + \fn QGenericMatrix<N, M, T, InnerT> operator+(const QGenericMatrix<N, M, T, InnerT>& m1, const QGenericMatrix<N, M, T, InnerT>& m2) + \relates QGenericMatrix + + Returns the sum of \a m1 and \a m2. +*/ + +/*! + \fn QGenericMatrix<N, M, T, InnerT> operator-(const QGenericMatrix<N, M, T, InnerT>& m1, const QGenericMatrix<N, M, T, InnerT>& m2) + \relates QGenericMatrix + + Returns the difference of \a m1 and \a m2. +*/ + +/*! + \fn QGenericMatrix<M1, M2, T, InnerT> operator*(const QGenericMatrix<N, M2, T, InnerT>& m1, const QGenericMatrix<M1, N, T, InnerT>& 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, InnerT> operator-(const QGenericMatrix<N, M, T, InnerT>& matrix) + \overload + \relates QGenericMatrix + + Returns the negation of \a matrix. +*/ + +/*! + \fn QGenericMatrix<N, M, T, InnerT> operator*(T factor, const QGenericMatrix<N, M, T, InnerT>& matrix) + \relates QGenericMatrix + + Returns the result of multiplying all elements of \a matrix by \a factor. +*/ + +/*! + \fn QGenericMatrix<N, M, T, InnerT> operator*(const QGenericMatrix<N, M, T, InnerT>& matrix, T factor) + \relates QGenericMatrix + + Returns the result of multiplying all elements of \a matrix by \a factor. +*/ + +/*! + \fn QGenericMatrix<N, M, T, InnerT> operator/(const QGenericMatrix<N, M, T, InnerT>& matrix, T divisor) + \relates QGenericMatrix + + Returns the result of dividing all elements of \a matrix by \a divisor. +*/ + +/*! + \fn void QGenericMatrix::toValueArray(T *values) + + Retrieves the N * M items in this matrix and writes them to \a values + in row-major order. +*/ + +/*! + \fn InnerT *QGenericMatrix::data() + + Returns a pointer to the raw data of this matrix. This is indended + for use with raw GL functions. + + \sa constData() +*/ + +/*! + \fn const InnerT *QGenericMatrix::data() const + + Returns a constant pointer to the raw data of this matrix. + This is indended for use with raw GL functions. + + \sa constData() +*/ + +/*! + \fn const InnerT *QGenericMatrix::constData() const + + Returns a constant pointer to the raw data of this matrix. + This is indended for use with raw GL functions. + + \sa data() +*/ + +QT_END_NAMESPACE diff --git a/src/gui/math3d/qgenericmatrix.h b/src/gui/math3d/qgenericmatrix.h new file mode 100644 index 0000000..26a0e48 --- /dev/null +++ b/src/gui/math3d/qgenericmatrix.h @@ -0,0 +1,341 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_LICENSE$ +** +****************************************************************************/ + +#ifndef QGENERICMATRIX_H +#define QGENERICMATRIX_H + +#include <QtGui/qmath3dglobal.h> +#include <QtCore/qmetatype.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +template <int N, int M, typename T, typename InnerT = T> +class QGenericMatrix +{ +public: + QGenericMatrix(); + QGenericMatrix(const QGenericMatrix<N, M, T, InnerT>& other); + explicit QGenericMatrix(const T *values); + + T operator()(int row, int column) const; + InnerT& operator()(int row, int column); + + bool isIdentity() const; + void setIdentity(); + + void fill(qreal value); + + QGenericMatrix<M, N, T, InnerT> transposed() const; + + QGenericMatrix<N, M, T, InnerT>& operator+=(const QGenericMatrix<N, M, T, InnerT>& other); + QGenericMatrix<N, M, T, InnerT>& operator-=(const QGenericMatrix<N, M, T, InnerT>& other); + QGenericMatrix<N, M, T, InnerT>& operator*=(T factor); + QGenericMatrix<N, M, T, InnerT>& operator/=(T divisor); + bool operator==(const QGenericMatrix<N, M, T, InnerT>& other) const; + bool operator!=(const QGenericMatrix<N, M, T, InnerT>& other) const; + + void toValueArray(T *values); + + InnerT *data() { return m[0]; } + const InnerT *data() const { return m[0]; } + const InnerT *constData() const { return m[0]; } + +#if !defined(Q_NO_TEMPLATE_FRIENDS) + template<int NN, int MM, typename TT, typename ITT> + friend QGenericMatrix<NN, MM, TT, ITT> operator+(const QGenericMatrix<NN, MM, TT, ITT>& m1, const QGenericMatrix<NN, MM, TT, ITT>& m2); + template<int NN, int MM, typename TT, typename ITT> + friend QGenericMatrix<NN, MM, TT, ITT> operator-(const QGenericMatrix<NN, MM, TT, ITT>& m1, const QGenericMatrix<NN, MM, TT, ITT>& m2); + template<int NN, int M1, int M2, typename TT, typename ITT> + friend QGenericMatrix<M1, M2, TT, ITT> operator*(const QGenericMatrix<NN, M2, TT, ITT>& m1, const QGenericMatrix<M1, NN, TT, ITT>& m2); + template<int NN, int MM, typename TT, typename ITT> + friend QGenericMatrix<NN, MM, TT, ITT> operator-(const QGenericMatrix<NN, MM, TT, ITT>& matrix); + template<int NN, int MM, typename TT, typename ITT> + friend QGenericMatrix<NN, MM, TT, ITT> operator*(TT factor, const QGenericMatrix<NN, MM, TT, ITT>& matrix); + template<int NN, int MM, typename TT, typename ITT> + friend QGenericMatrix<NN, MM, TT, ITT> operator*(const QGenericMatrix<NN, MM, TT, ITT>& matrix, TT factor); + template<int NN, int MM, typename TT, typename ITT> + friend QGenericMatrix<NN, MM, TT, ITT> operator/(const QGenericMatrix<NN, MM, TT, ITT>& matrix, TT divisor); + +private: +#endif + InnerT 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, typename ITT> + friend class QGenericMatrix; +#endif +}; + +template <int N, int M, typename T, typename InnerT> +Q_INLINE_TEMPLATE QGenericMatrix<N, M, T, InnerT>::QGenericMatrix() +{ + setIdentity(); +} + +template <int N, int M, typename T, typename InnerT> +Q_INLINE_TEMPLATE QGenericMatrix<N, M, T, InnerT>::QGenericMatrix(const QGenericMatrix<N, M, T, InnerT>& other) +{ + qMemCopy(m, other.m, sizeof(m)); +} + +template <int N, int M, typename T, typename InnerT> +Q_OUTOFLINE_TEMPLATE QGenericMatrix<N, M, T, InnerT>::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, typename InnerT> +Q_INLINE_TEMPLATE T QGenericMatrix<N, M, T, InnerT>::operator()(int row, int column) const +{ + Q_ASSERT(row >= 0 && row < M && column >= 0 && column < N); + return qt_math3d_convert<T, InnerT>(m[column][row]); +} + +template <int N, int M, typename T, typename InnerT> +Q_INLINE_TEMPLATE InnerT& QGenericMatrix<N, M, T, InnerT>::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, typename InnerT> +Q_OUTOFLINE_TEMPLATE bool QGenericMatrix<N, M, T, InnerT>::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, typename InnerT> +Q_OUTOFLINE_TEMPLATE void QGenericMatrix<N, M, T, InnerT>::setIdentity() +{ + 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, typename InnerT> +Q_OUTOFLINE_TEMPLATE void QGenericMatrix<N, M, T, InnerT>::fill(qreal 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, typename InnerT> +Q_OUTOFLINE_TEMPLATE QGenericMatrix<M, N, T, InnerT> QGenericMatrix<N, M, T, InnerT>::transposed() const +{ + QGenericMatrix<M, N, T, InnerT> 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, typename InnerT> +Q_OUTOFLINE_TEMPLATE QGenericMatrix<N, M, T, InnerT>& QGenericMatrix<N, M, T, InnerT>::operator+=(const QGenericMatrix<N, M, T, InnerT>& other) +{ + for (int index = 0; index < N * M; ++index) + m[0][index] += other.m[0][index]; + return *this; +} + +template <int N, int M, typename T, typename InnerT> +Q_OUTOFLINE_TEMPLATE QGenericMatrix<N, M, T, InnerT>& QGenericMatrix<N, M, T, InnerT>::operator-=(const QGenericMatrix<N, M, T, InnerT>& other) +{ + for (int index = 0; index < N * M; ++index) + m[0][index] -= other.m[0][index]; + return *this; +} + +template <int N, int M, typename T, typename InnerT> +Q_OUTOFLINE_TEMPLATE QGenericMatrix<N, M, T, InnerT>& QGenericMatrix<N, M, T, InnerT>::operator*=(T factor) +{ + InnerT f(factor); + for (int index = 0; index < N * M; ++index) + m[0][index] *= f; + return *this; +} + +template <int N, int M, typename T, typename InnerT> +Q_OUTOFLINE_TEMPLATE bool QGenericMatrix<N, M, T, InnerT>::operator==(const QGenericMatrix<N, M, T, InnerT>& other) const +{ + for (int index = 0; index < N * M; ++index) { + if (m[0][index] != other.m[0][index]) + return false; + } + return true; +} + +template <int N, int M, typename T, typename InnerT> +Q_OUTOFLINE_TEMPLATE bool QGenericMatrix<N, M, T, InnerT>::operator!=(const QGenericMatrix<N, M, T, InnerT>& other) const +{ + for (int index = 0; index < N * M; ++index) { + if (m[0][index] != other.m[0][index]) + return true; + } + return false; +} + +template <int N, int M, typename T, typename InnerT> +Q_OUTOFLINE_TEMPLATE QGenericMatrix<N, M, T, InnerT>& QGenericMatrix<N, M, T, InnerT>::operator/=(T divisor) +{ + InnerT d(divisor); + for (int index = 0; index < N * M; ++index) + m[0][index] /= d; + return *this; +} + +template <int N, int M, typename T, typename InnerT> +Q_OUTOFLINE_TEMPLATE QGenericMatrix<N, M, T, InnerT> operator+(const QGenericMatrix<N, M, T, InnerT>& m1, const QGenericMatrix<N, M, T, InnerT>& m2) +{ + QGenericMatrix<N, M, T, InnerT> result(1); + for (int index = 0; index < N * M; ++index) + result.m[0][index] = m1.m[0][index] + m2.m[0][index]; + return result; +} + +template <int N, int M, typename T, typename InnerT> +Q_OUTOFLINE_TEMPLATE QGenericMatrix<N, M, T, InnerT> operator-(const QGenericMatrix<N, M, T, InnerT>& m1, const QGenericMatrix<N, M, T, InnerT>& m2) +{ + QGenericMatrix<N, M, T, InnerT> result(1); + for (int index = 0; index < N * M; ++index) + result.m[0][index] = m1.m[0][index] - m2.m[0][index]; + return result; +} + +template <int N, int M1, int M2, typename T, typename InnerT> +Q_OUTOFLINE_TEMPLATE QGenericMatrix<M1, M2, T, InnerT> operator*(const QGenericMatrix<N, M2, T, InnerT>& m1, const QGenericMatrix<M1, N, T, InnerT>& m2) +{ + QGenericMatrix<M1, M2, T, InnerT> result(1); + for (int row = 0; row < M2; ++row) { + for (int col = 0; col < M1; ++col) { + InnerT 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, typename InnerT> +Q_OUTOFLINE_TEMPLATE QGenericMatrix<N, M, T, InnerT> operator-(const QGenericMatrix<N, M, T, InnerT>& matrix) +{ + QGenericMatrix<N, M, T, InnerT> result(1); + for (int index = 0; index < N * M; ++index) + result.m[0][index] = -matrix.m[0][index]; + return result; +} + +template <int N, int M, typename T, typename InnerT> +Q_OUTOFLINE_TEMPLATE QGenericMatrix<N, M, T, InnerT> operator*(T factor, const QGenericMatrix<N, M, T, InnerT>& matrix) +{ + InnerT f(factor); + QGenericMatrix<N, M, T, InnerT> result(1); + for (int index = 0; index < N * M; ++index) + result.m[0][index] = matrix.m[0][index] * f; + return result; +} + +template <int N, int M, typename T, typename InnerT> +Q_OUTOFLINE_TEMPLATE QGenericMatrix<N, M, T, InnerT> operator*(const QGenericMatrix<N, M, T, InnerT>& matrix, T factor) +{ + InnerT f(factor); + QGenericMatrix<N, M, T, InnerT> result(1); + for (int index = 0; index < N * M; ++index) + result.m[0][index] = matrix.m[0][index] * f; + return result; +} + +template <int N, int M, typename T, typename InnerT> +Q_OUTOFLINE_TEMPLATE QGenericMatrix<N, M, T, InnerT> operator/(const QGenericMatrix<N, M, T, InnerT>& matrix, T divisor) +{ + InnerT d(divisor); + QGenericMatrix<N, M, T, InnerT> result(1); + for (int index = 0; index < N * M; ++index) + result.m[0][index] = matrix.m[0][index] / d; + return result; +} + +template <int N, int M, typename T, typename InnerT> +Q_OUTOFLINE_TEMPLATE void QGenericMatrix<N, M, T, InnerT>::toValueArray(T *values) +{ + for (int col = 0; col < N; ++col) + for (int row = 0; row < M; ++row) + values[row * N + col] = qt_math3d_convert<T, InnerT>(m[col][row]); +} + +// Define aliases for the useful variants of QGenericMatrix. +typedef QGenericMatrix<2, 2, qreal, qrealinner> QMatrix2x2; +typedef QGenericMatrix<2, 3, qreal, qrealinner> QMatrix2x3; +typedef QGenericMatrix<2, 4, qreal, qrealinner> QMatrix2x4; +typedef QGenericMatrix<3, 2, qreal, qrealinner> QMatrix3x2; +typedef QGenericMatrix<3, 3, qreal, qrealinner> QMatrix3x3; +typedef QGenericMatrix<3, 4, qreal, qrealinner> QMatrix3x4; +typedef QGenericMatrix<4, 2, qreal, qrealinner> QMatrix4x2; +typedef QGenericMatrix<4, 3, qreal, qrealinner> QMatrix4x3; + +#ifndef QT_NO_DEBUG_STREAM + +template <int N, int M, typename T, typename InnerT> +QDebug operator<<(QDebug dbg, const QGenericMatrix<N, M, T, InnerT> &m) +{ + dbg.nospace() << "QGenericMatrix<" << N << ", " << M + << ", " << QTypeInfo<T>::name() << ", " << QTypeInfo<InnerT>::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 + +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/qmath3dglobal.h b/src/gui/math3d/qmath3dglobal.h new file mode 100644 index 0000000..ee5e734 --- /dev/null +++ b/src/gui/math3d/qmath3dglobal.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_LICENSE$ +** +****************************************************************************/ + +#ifndef QMATH3DGLOBAL_H +#define QMATH3DGLOBAL_H + +#include <QtCore/qglobal.h> +#include <QtGui/qfixedpt.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +// Detect the presence of a fixed-point OpenGL implementation. +#if defined(QT_OPENGL_ES_1_CL) || defined(QT_NO_GL_FLOAT) +#ifndef QT_GL_FIXED_PREFERRED +#define QT_GL_FIXED_PREFERRED 1 +#endif +#endif + +// QT_GL_FIXED_PREFERRED indicates that fixed-point should be +// preferred over floating-point for operations requiring high performance. +// +// qreal is the floating-point type that should be used in +// user-visible functions. qrealinner is used internally where +// values may be stored as either floating-point or fixed-point. +// qrealinner will typically be the same size as GLfloat or GLfixed. +#if defined(QT_GL_FIXED_PREFERRED) +typedef QFixedPt<16> qrealinner; +#else +typedef float qrealinner; +#endif + +// Explicit conversion operator, primarily for converting from +// fixed point back to floating-point. This is safer than +// declaring conversion operators in the QFixedPt class. +template <typename T1, typename T2> +T1 qt_math3d_convert(T2 v) +{ + return T1(v); +} +template <> +inline float qt_math3d_convert< float, QFixedPt<16> >(QFixedPt<16> v) +{ + return float(v.toReal()); +} +template <> +inline double qt_math3d_convert< double, QFixedPt<16> >(QFixedPt<16> v) +{ + return double(v.toReal()); +} +template <> +inline int qt_math3d_convert< int, QFixedPt<16> >(QFixedPt<16> v) +{ + return v.toInt(); +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/gui/math3d/qmath3dutil.cpp b/src/gui/math3d/qmath3dutil.cpp new file mode 100644 index 0000000..91d4b15 --- /dev/null +++ b/src/gui/math3d/qmath3dutil.cpp @@ -0,0 +1,164 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_LICENSE$ +** +****************************************************************************/ + +#include "qmath3dutil_p.h" + +QT_BEGIN_NAMESPACE + +#ifdef QT_GL_FIXED_PREFERRED + +// The table that follows was automatically generated by the following code: +// +//#include <math.h> +//#include <stdio.h> +// +//int main() +//{ +// double angle; +// int count = 0; +// for (angle = 0.0; angle < 360.0; angle += 1.0) { +// if ((count % 4) == 0) +// printf(" "); +// printf(" qf2vt(%f)", sin(angle * M_PI / 180.0)); +// ++count; +// if (count != 360) +// printf(","); +// if ((count % 4) == 0) +// printf("\n"); +// } +// return 0; +//} + +#define qf2vt(x) (int((x) * 65536.0)) + +static int const sinTable[360] = { + qf2vt(0.000000), qf2vt(0.017452), qf2vt(0.034899), qf2vt(0.052336), + qf2vt(0.069756), qf2vt(0.087156), qf2vt(0.104528), qf2vt(0.121869), + qf2vt(0.139173), qf2vt(0.156434), qf2vt(0.173648), qf2vt(0.190809), + qf2vt(0.207912), qf2vt(0.224951), qf2vt(0.241922), qf2vt(0.258819), + qf2vt(0.275637), qf2vt(0.292372), qf2vt(0.309017), qf2vt(0.325568), + qf2vt(0.342020), qf2vt(0.358368), qf2vt(0.374607), qf2vt(0.390731), + qf2vt(0.406737), qf2vt(0.422618), qf2vt(0.438371), qf2vt(0.453990), + qf2vt(0.469472), qf2vt(0.484810), qf2vt(0.500000), qf2vt(0.515038), + qf2vt(0.529919), qf2vt(0.544639), qf2vt(0.559193), qf2vt(0.573576), + qf2vt(0.587785), qf2vt(0.601815), qf2vt(0.615661), qf2vt(0.629320), + qf2vt(0.642788), qf2vt(0.656059), qf2vt(0.669131), qf2vt(0.681998), + qf2vt(0.694658), qf2vt(0.707107), qf2vt(0.719340), qf2vt(0.731354), + qf2vt(0.743145), qf2vt(0.754710), qf2vt(0.766044), qf2vt(0.777146), + qf2vt(0.788011), qf2vt(0.798636), qf2vt(0.809017), qf2vt(0.819152), + qf2vt(0.829038), qf2vt(0.838671), qf2vt(0.848048), qf2vt(0.857167), + qf2vt(0.866025), qf2vt(0.874620), qf2vt(0.882948), qf2vt(0.891007), + qf2vt(0.898794), qf2vt(0.906308), qf2vt(0.913545), qf2vt(0.920505), + qf2vt(0.927184), qf2vt(0.933580), qf2vt(0.939693), qf2vt(0.945519), + qf2vt(0.951057), qf2vt(0.956305), qf2vt(0.961262), qf2vt(0.965926), + qf2vt(0.970296), qf2vt(0.974370), qf2vt(0.978148), qf2vt(0.981627), + qf2vt(0.984808), qf2vt(0.987688), qf2vt(0.990268), qf2vt(0.992546), + qf2vt(0.994522), qf2vt(0.996195), qf2vt(0.997564), qf2vt(0.998630), + qf2vt(0.999391), qf2vt(0.999848), qf2vt(1.000000), qf2vt(0.999848), + qf2vt(0.999391), qf2vt(0.998630), qf2vt(0.997564), qf2vt(0.996195), + qf2vt(0.994522), qf2vt(0.992546), qf2vt(0.990268), qf2vt(0.987688), + qf2vt(0.984808), qf2vt(0.981627), qf2vt(0.978148), qf2vt(0.974370), + qf2vt(0.970296), qf2vt(0.965926), qf2vt(0.961262), qf2vt(0.956305), + qf2vt(0.951057), qf2vt(0.945519), qf2vt(0.939693), qf2vt(0.933580), + qf2vt(0.927184), qf2vt(0.920505), qf2vt(0.913545), qf2vt(0.906308), + qf2vt(0.898794), qf2vt(0.891007), qf2vt(0.882948), qf2vt(0.874620), + qf2vt(0.866025), qf2vt(0.857167), qf2vt(0.848048), qf2vt(0.838671), + qf2vt(0.829038), qf2vt(0.819152), qf2vt(0.809017), qf2vt(0.798636), + qf2vt(0.788011), qf2vt(0.777146), qf2vt(0.766044), qf2vt(0.754710), + qf2vt(0.743145), qf2vt(0.731354), qf2vt(0.719340), qf2vt(0.707107), + qf2vt(0.694658), qf2vt(0.681998), qf2vt(0.669131), qf2vt(0.656059), + qf2vt(0.642788), qf2vt(0.629320), qf2vt(0.615661), qf2vt(0.601815), + qf2vt(0.587785), qf2vt(0.573576), qf2vt(0.559193), qf2vt(0.544639), + qf2vt(0.529919), qf2vt(0.515038), qf2vt(0.500000), qf2vt(0.484810), + qf2vt(0.469472), qf2vt(0.453990), qf2vt(0.438371), qf2vt(0.422618), + qf2vt(0.406737), qf2vt(0.390731), qf2vt(0.374607), qf2vt(0.358368), + qf2vt(0.342020), qf2vt(0.325568), qf2vt(0.309017), qf2vt(0.292372), + qf2vt(0.275637), qf2vt(0.258819), qf2vt(0.241922), qf2vt(0.224951), + qf2vt(0.207912), qf2vt(0.190809), qf2vt(0.173648), qf2vt(0.156434), + qf2vt(0.139173), qf2vt(0.121869), qf2vt(0.104528), qf2vt(0.087156), + qf2vt(0.069756), qf2vt(0.052336), qf2vt(0.034899), qf2vt(0.017452), + qf2vt(0.000000), qf2vt(-0.017452), qf2vt(-0.034899), qf2vt(-0.052336), + qf2vt(-0.069756), qf2vt(-0.087156), qf2vt(-0.104528), qf2vt(-0.121869), + qf2vt(-0.139173), qf2vt(-0.156434), qf2vt(-0.173648), qf2vt(-0.190809), + qf2vt(-0.207912), qf2vt(-0.224951), qf2vt(-0.241922), qf2vt(-0.258819), + qf2vt(-0.275637), qf2vt(-0.292372), qf2vt(-0.309017), qf2vt(-0.325568), + qf2vt(-0.342020), qf2vt(-0.358368), qf2vt(-0.374607), qf2vt(-0.390731), + qf2vt(-0.406737), qf2vt(-0.422618), qf2vt(-0.438371), qf2vt(-0.453990), + qf2vt(-0.469472), qf2vt(-0.484810), qf2vt(-0.500000), qf2vt(-0.515038), + qf2vt(-0.529919), qf2vt(-0.544639), qf2vt(-0.559193), qf2vt(-0.573576), + qf2vt(-0.587785), qf2vt(-0.601815), qf2vt(-0.615661), qf2vt(-0.629320), + qf2vt(-0.642788), qf2vt(-0.656059), qf2vt(-0.669131), qf2vt(-0.681998), + qf2vt(-0.694658), qf2vt(-0.707107), qf2vt(-0.719340), qf2vt(-0.731354), + qf2vt(-0.743145), qf2vt(-0.754710), qf2vt(-0.766044), qf2vt(-0.777146), + qf2vt(-0.788011), qf2vt(-0.798636), qf2vt(-0.809017), qf2vt(-0.819152), + qf2vt(-0.829038), qf2vt(-0.838671), qf2vt(-0.848048), qf2vt(-0.857167), + qf2vt(-0.866025), qf2vt(-0.874620), qf2vt(-0.882948), qf2vt(-0.891007), + qf2vt(-0.898794), qf2vt(-0.906308), qf2vt(-0.913545), qf2vt(-0.920505), + qf2vt(-0.927184), qf2vt(-0.933580), qf2vt(-0.939693), qf2vt(-0.945519), + qf2vt(-0.951057), qf2vt(-0.956305), qf2vt(-0.961262), qf2vt(-0.965926), + qf2vt(-0.970296), qf2vt(-0.974370), qf2vt(-0.978148), qf2vt(-0.981627), + qf2vt(-0.984808), qf2vt(-0.987688), qf2vt(-0.990268), qf2vt(-0.992546), + qf2vt(-0.994522), qf2vt(-0.996195), qf2vt(-0.997564), qf2vt(-0.998630), + qf2vt(-0.999391), qf2vt(-0.999848), qf2vt(-1.000000), qf2vt(-0.999848), + qf2vt(-0.999391), qf2vt(-0.998630), qf2vt(-0.997564), qf2vt(-0.996195), + qf2vt(-0.994522), qf2vt(-0.992546), qf2vt(-0.990268), qf2vt(-0.987688), + qf2vt(-0.984808), qf2vt(-0.981627), qf2vt(-0.978148), qf2vt(-0.974370), + qf2vt(-0.970296), qf2vt(-0.965926), qf2vt(-0.961262), qf2vt(-0.956305), + qf2vt(-0.951057), qf2vt(-0.945519), qf2vt(-0.939693), qf2vt(-0.933580), + qf2vt(-0.927184), qf2vt(-0.920505), qf2vt(-0.913545), qf2vt(-0.906308), + qf2vt(-0.898794), qf2vt(-0.891007), qf2vt(-0.882948), qf2vt(-0.874620), + qf2vt(-0.866025), qf2vt(-0.857167), qf2vt(-0.848048), qf2vt(-0.838671), + qf2vt(-0.829038), qf2vt(-0.819152), qf2vt(-0.809017), qf2vt(-0.798636), + qf2vt(-0.788011), qf2vt(-0.777146), qf2vt(-0.766044), qf2vt(-0.754710), + qf2vt(-0.743145), qf2vt(-0.731354), qf2vt(-0.719340), qf2vt(-0.707107), + qf2vt(-0.694658), qf2vt(-0.681998), qf2vt(-0.669131), qf2vt(-0.656059), + qf2vt(-0.642788), qf2vt(-0.629320), qf2vt(-0.615661), qf2vt(-0.601815), + qf2vt(-0.587785), qf2vt(-0.573576), qf2vt(-0.559193), qf2vt(-0.544639), + qf2vt(-0.529919), qf2vt(-0.515038), qf2vt(-0.500000), qf2vt(-0.484810), + qf2vt(-0.469472), qf2vt(-0.453990), qf2vt(-0.438371), qf2vt(-0.422618), + qf2vt(-0.406737), qf2vt(-0.390731), qf2vt(-0.374607), qf2vt(-0.358368), + qf2vt(-0.342020), qf2vt(-0.325568), qf2vt(-0.309017), qf2vt(-0.292372), + qf2vt(-0.275637), qf2vt(-0.258819), qf2vt(-0.241922), qf2vt(-0.224951), + qf2vt(-0.207912), qf2vt(-0.190809), qf2vt(-0.173648), qf2vt(-0.156434), + qf2vt(-0.139173), qf2vt(-0.121869), qf2vt(-0.104528), qf2vt(-0.087156), + qf2vt(-0.069756), qf2vt(-0.052336), qf2vt(-0.034899), qf2vt(-0.017452) +}; + +void qt_math3d_sincos(qreal angle, qrealinner *s, qrealinner *c) +{ + if (angle == qFloor(angle)) { + // The angle is an integer number of degrees, so look up the results. + int a = (int)angle; + if (a >= 0) + a = (a % 360); + else + a = 360 - (-a % 360); + s->setBits(sinTable[a]); + c->setBits(sinTable[(a + 90) % 360]); + } else { + qreal a = angle * M_PI / 180.0f; + *s = qSin(a); + *c = qCos(a); + } +} + +#else + +void qt_math3d_sincos(qreal angle, qrealinner *s, qrealinner *c) +{ + qreal a = angle * M_PI / 180.0f; + *s = qSin(a); + *c = qCos(a); +} + +#endif + +QT_END_NAMESPACE diff --git a/src/gui/math3d/qmath3dutil_p.h b/src/gui/math3d/qmath3dutil_p.h new file mode 100644 index 0000000..1cb0bb9 --- /dev/null +++ b/src/gui/math3d/qmath3dutil_p.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_LICENSE$ +** +****************************************************************************/ + +#ifndef QMATH3DUTIL_P_H +#define QMATH3DUTIL_P_H + +#include <QtGui/qmath3dglobal.h> +#include <QtCore/qmath.h> + +QT_BEGIN_NAMESPACE + +#ifdef QT_GL_FIXED_PREFERRED +#define qvtsqrt(x) ((x).sqrtF()) +#else +#define qvtsqrt(x) qSqrt((x)) +#endif + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +void qt_math3d_sincos(qreal degrees, qrealinner *s, qrealinner *c); + +#ifdef QT_GL_FIXED_PREFERRED + +inline qrealinner qf2vt_round(qreal x) +{ + QFixedPt<16> result; + if (x >= 0.0f) + result.setBits(int(x * 65536.0f + 0.5f)); + else + result.setBits(int(x * 65536.0f - 0.5f)); + return result; +} + +// Helper macros for computing dot products without losing precision. +// In fixed-point mode, a 64-bit intermediate result is used. +#define qvtmul64(x,y) ((qint64((x).bits())) * (qint64((y).bits()))) +#define qvtsqrt64(x) \ + (qt_math3d_fixed_sqrt((x) << 16) / (qreal)(1 << 24)) +#define qvtdot64(x) ((x) / (qreal)(((qint64)1) << 32)) + +#else + +inline qrealinner qf2vt_round(qreal x) +{ + return x; +} + +#define qvtmul64(x,y) ((x) * (y)) +#define qvtsqrt64(x) (qvtsqrt((x))) +#define qvtdot64(x) ((x)) + +#endif + +QT_END_NAMESPACE + +#endif diff --git a/src/gui/math3d/qmatrix4x4.cpp b/src/gui/math3d/qmatrix4x4.cpp new file mode 100644 index 0000000..9941ca8 --- /dev/null +++ b/src/gui/math3d/qmatrix4x4.cpp @@ -0,0 +1,1649 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_LICENSE$ +** +****************************************************************************/ + +#include "qmatrix4x4.h" +#include "qmath3dutil_p.h" +#include <QtCore/qmath.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 + + The matrix elements are stored internally using the most efficient + numeric representation for the underlying hardware: floating-point + or fixed-point. + + \sa QVector3D, QGenericMatrix +*/ + +/*! + \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 + inferSpecialType() if they wish QMatrix4x4 to optimize further + calls to translate(), scale(), etc. + + \sa toValueArray(), inferSpecialType() +*/ +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 + inferSpecialType() if they wish QMatrix4x4 to optimize further + calls to translate(), scale(), etc. + + \sa inferSpecialType() +*/ + +#if !defined(QT_NO_MEMBER_TEMPLATES) || defined(Q_QDOC) + +/*! + \fn QMatrix4x4::QMatrix4x4(const QGenericMatrix<N, M, qreal, qrealinner>& 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(), qGenericMatrixToMatrix4x4() +*/ + +/*! + \fn QGenericMatrix<N, M, qreal, qrealinner> 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. + + \sa qGenericMatrixFromMatrix4x4() +*/ + +#endif + +/*! + \fn QMatrix4x4 qGenericMatrixToMatrix4x4(const QGenericMatrix<N, M, qreal, qrealinner>& matrix) + \relates QMatrix4x4 + + 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 qGenericMatrixFromMatrix4x4() +*/ + +/*! + \fn QGenericMatrix<N, M, qreal, qrealinner> qGenericMatrixFromMatrix4x4(const QMatrix4x4& matrix) + \relates QMatrix4x4 + + 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 qGenericMatrixToMatrix4x4(), QMatrix4x4::toGenericMatrix() +*/ + +/*! + \internal +*/ +QMatrix4x4::QMatrix4x4(const qrealinner *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 + inferSpecialType() if they wish QMatrix4x4 to optimize further + calls to translate(), scale(), etc. + + \sa toAffine(), inferSpecialType() +*/ +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 + inferSpecialType() if they wish QMatrix4x4 to optimize further + calls to translate(), scale(), etc. + + \sa toTransform(), inferSpecialType() +*/ +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 qreal QMatrix4x4::operator()(int row, int column) const + + Returns the element at position (\a row, \a column) in this matrix. + + \sa column(), row() +*/ + +/*! + \fn qrealinner& 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 inferSpecialType(), 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 setIdentity() +*/ + +/*! + \fn void QMatrix4x4::setIdentity() + + 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, to do calculations in fixed-point where required, +// 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 qrealinner matrixDet3 + (const qrealinner 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 qrealinner matrixDet4(const qrealinner m[4][4]) +{ + qrealinner 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 qt_math3d_convert<qreal, qrealinner>(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. + + qrealinner det = matrixDet4(m); + if (det == 0.0f) { + if (invertible) + *invertible = false; + return QMatrix4x4(); + } + det = qrealinner(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] = qrealinner(1.0f) / m[0][0]; + inv.data()[4] = qrealinner(1.0f) / m[1][1]; + inv.data()[8] = qrealinner(1.0f) / m[2][2]; + return inv; + } + + qrealinner det = matrixDet3(m, 0, 1, 2, 0, 1, 2); + if (det == 0.0f) + return inv; + det = qrealinner(1.0f) / det; + + qrealinner *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) +{ + qrealinner d(divisor); + m[0][0] /= d; + m[0][1] /= d; + m[0][2] /= d; + m[0][3] /= d; + m[1][0] /= d; + m[1][1] /= d; + m[1][2] /= d; + m[1][3] /= d; + m[2][0] /= d; + m[2][1] /= d; + m[2][2] /= d; + m[2][3] /= d; + m[3][0] /= d; + m[3][1] /= d; + m[3][2] /= d; + m[3][3] /= d; + 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. + qrealinner d(divisor); + m.m[0][0] = matrix.m[0][0] / d; + m.m[0][1] = matrix.m[0][1] / d; + m.m[0][2] = matrix.m[0][2] / d; + m.m[0][3] = matrix.m[0][3] / d; + m.m[1][0] = matrix.m[1][0] / d; + m.m[1][1] = matrix.m[1][1] / d; + m.m[1][2] = matrix.m[1][2] / d; + m.m[1][3] = matrix.m[1][3] / d; + m.m[2][0] = matrix.m[2][0] / d; + m.m[2][1] = matrix.m[2][1] / d; + m.m[2][2] = matrix.m[2][2] / d; + m.m[2][3] = matrix.m[2][3] / d; + m.m[3][0] = matrix.m[3][0] / d; + m.m[3][1] = matrix.m[3][1] / d; + m.m[3][2] = matrix.m[3][2] / d; + m.m[3][3] = matrix.m[3][3] / d; + 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. Returns this matrix. + + \sa translate(), rotate() +*/ +QMatrix4x4& QMatrix4x4::scale(const QVector3D& vector) +{ + qrealinner vx = vector.xp; + qrealinner vy = vector.yp; + qrealinner vz = vector.zp; + 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; + } + return *this; +} +#endif + +/*! + \overload + + Multiplies this matrix by another that scales coordinates by the + components \a x, \a y, and \a z. Returns this matrix. + + \sa translate(), rotate() +*/ +QMatrix4x4& QMatrix4x4::scale(qreal x, qreal y, qreal z) +{ + qrealinner vx(x); + qrealinner vy(y); + qrealinner vz(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; + } + return *this; +} + +/*! + \overload + + Multiplies this matrix by another that scales coordinates by the + given \a factor. Returns this matrix. + + \sa translate(), rotate() +*/ +QMatrix4x4& QMatrix4x4::scale(qreal factor) +{ + qrealinner f(factor); + if (flagBits == Identity) { + m[0][0] = f; + m[1][1] = f; + m[2][2] = f; + flagBits = Scale; + } else if (flagBits == Scale || flagBits == (Scale | Translation)) { + m[0][0] *= f; + m[1][1] *= f; + m[2][2] *= f; + } else if (flagBits == Translation) { + m[0][0] = f; + m[1][1] = f; + m[2][2] = f; + flagBits |= Scale; + } else { + m[0][0] *= f; + m[0][1] *= f; + m[0][2] *= f; + m[0][3] *= f; + m[1][0] *= f; + m[1][1] *= f; + m[1][2] *= f; + m[1][3] *= f; + m[2][0] *= f; + m[2][1] *= f; + m[2][2] *= f; + m[2][3] *= f; + flagBits = General; + } + return *this; +} + +#ifndef QT_NO_VECTOR3D +/*! + Multiplies this matrix by another that translates coordinates by + the components of \a vector. Returns this matrix. + + \sa scale(), rotate() +*/ +QMatrix4x4& QMatrix4x4::translate(const QVector3D& vector) +{ + qrealinner vx = vector.xp; + qrealinner vy = vector.yp; + qrealinner vz = vector.zp; + 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; + } + return *this; +} + +#endif + +/*! + \overload + + Multiplies this matrix by another that translates coordinates + by the components \a x, \a y, and \a z. Returns this matrix. + + \sa scale(), rotate() +*/ +QMatrix4x4& QMatrix4x4::translate(qreal x, qreal y, qreal z) +{ + qrealinner vx(x); + qrealinner vy(y); + qrealinner vz(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; + } + return *this; +} + +#ifndef QT_NO_VECTOR3D + +/*! + Multiples this matrix by another that rotates coordinates through + \a angle degrees about \a vector. Returns this matrix. + + \sa scale(), translate() +*/ +QMatrix4x4& QMatrix4x4::rotate(qreal angle, const QVector3D& vector) +{ + return 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). Returns this matrix. + + \sa scale(), translate() +*/ +QMatrix4x4& QMatrix4x4::rotate(qreal angle, qreal x, qreal y, qreal z) +{ + QMatrix4x4 m(1); // The "1" says to not load the identity. + qrealinner c, s, ic; + qt_math3d_sincos(angle, &s, &c); + bool quick = false; + if (x == 0.0f) { + if (y == 0.0f) { + if (z != 0.0f) { + // Rotate around the Z axis. + m.setIdentity(); + 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.setIdentity(); + 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.setIdentity(); + 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) { + qrealinner vx(x); + qrealinner vy(y); + qrealinner vz(z); + qrealinner len(qvtsqrt(vx * vx + vy * vy + vz * vz)); + if (len != 0) { + vx /= len; + vy /= len; + vz /= len; + } + ic = 1.0f - c; + m.m[0][0] = vx * vx * ic + c; + m.m[1][0] = vx * vy * ic - vz * s; + m.m[2][0] = vx * vz * ic + vy * s; + m.m[3][0] = 0.0f; + m.m[0][1] = vy * vx * ic + vz * s; + m.m[1][1] = vy * vy * ic + c; + m.m[2][1] = vy * vz * ic - vx * s; + m.m[3][1] = 0.0f; + m.m[0][2] = vx * vz * ic - vy * s; + m.m[1][2] = vy * vz * ic + vx * s; + m.m[2][2] = vz * vz * 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; + return *this; +} + +#ifndef QT_NO_VECTOR4D + +/*! + Multiples this matrix by another that rotates coordinates according + to a specified \a quaternion. The \a quaternion is assumed to have + been normalized. Returns this matrix. + + \sa scale(), translate(), QQuaternion +*/ +QMatrix4x4& QMatrix4x4::rotate(const QQuaternion& quaternion) +{ + // Algorithm from: + // http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q54 + QMatrix4x4 m(1); + qrealinner xx = quaternion.xp * quaternion.xp; + qrealinner xy = quaternion.xp * quaternion.yp; + qrealinner xz = quaternion.xp * quaternion.zp; + qrealinner xw = quaternion.xp * quaternion.wp; + qrealinner yy = quaternion.yp * quaternion.yp; + qrealinner yz = quaternion.yp * quaternion.zp; + qrealinner yw = quaternion.yp * quaternion.wp; + qrealinner zz = quaternion.zp * quaternion.zp; + qrealinner zw = quaternion.zp * quaternion.wp; + 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; + return *this; +} + +#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. + Returns this matrix. + + \sa frustum(), perspective() +*/ +QMatrix4x4& 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. + return 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. + Returns this matrix. + + \sa frustum(), perspective() +*/ +QMatrix4x4& QMatrix4x4::ortho(const QRectF& rect) +{ + return 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. Returns this matrix. + + \sa frustum(), perspective() +*/ +QMatrix4x4& 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 *this; + + // 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 + (qf2vt_round(-(left + right) / width), + qf2vt_round(-(top + bottom) / invheight), + 0.0f, 1)); + scale(QVector3D + (qf2vt_round(2.0f / width), + qf2vt_round(2.0f / invheight), + -1.0f, 1)); + return *this; + } +#endif + QMatrix4x4 m(1); + m.m[0][0] = qf2vt_round(2.0f / width); + m.m[1][0] = qf2vt_round(0.0f); + m.m[2][0] = qf2vt_round(0.0f); + m.m[3][0] = qf2vt_round(-(left + right) / width); + m.m[0][1] = qf2vt_round(0.0f); + m.m[1][1] = qf2vt_round(2.0f / invheight); + m.m[2][1] = qf2vt_round(0.0f); + m.m[3][1] = qf2vt_round(-(top + bottom) / invheight); + m.m[0][2] = qf2vt_round(0.0f); + m.m[1][2] = qf2vt_round(0.0f); + m.m[2][2] = qf2vt_round(-2.0f / clip); + m.m[3][2] = qf2vt_round(-(nearPlane + farPlane) / clip); + m.m[0][3] = qf2vt_round(0.0f); + m.m[1][3] = qf2vt_round(0.0f); + m.m[2][3] = qf2vt_round(0.0f); + m.m[3][3] = qf2vt_round(1.0f); + + // Apply the projection. + *this *= m; + return *this; +} + +/*! + 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. Returns this matrix. + + \sa ortho(), perspective() +*/ +QMatrix4x4& 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 *this; + + // Construct the projection. + QMatrix4x4 m(1); + qreal width = right - left; + qreal invheight = top - bottom; + qreal clip = farPlane - nearPlane; + m.m[0][0] = qf2vt_round(2.0f * nearPlane / width); + m.m[1][0] = qf2vt_round(0.0f); + m.m[2][0] = qf2vt_round((left + right) / width); + m.m[3][0] = qf2vt_round(0.0f); + m.m[0][1] = qf2vt_round(0.0f); + m.m[1][1] = qf2vt_round(2.0f * nearPlane / invheight); + m.m[2][1] = qf2vt_round((top + bottom) / invheight); + m.m[3][1] = qf2vt_round(0.0f); + m.m[0][2] = qf2vt_round(0.0f); + m.m[1][2] = qf2vt_round(0.0f); + m.m[2][2] = qf2vt_round(-(nearPlane + farPlane) / clip); + m.m[3][2] = qf2vt_round(-(2.0f * nearPlane * farPlane) / clip); + m.m[0][3] = qf2vt_round(0.0f); + m.m[1][3] = qf2vt_round(0.0f); + m.m[2][3] = qf2vt_round(-1.0f); + m.m[3][3] = qf2vt_round(0.0f); + + // Apply the projection. + *this *= m; + return *this; +} + +/*! + 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. + Returns this matrix. + + \sa ortho(), frustum() +*/ +QMatrix4x4& 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 *this; + + // Construct the projection. + QMatrix4x4 m(1); + qreal radians = (angle / 2.0f) * M_PI / 180.0f; + qreal sine = qSin(radians); + if (sine == 0.0f) + return *this; + qreal cotan = qCos(radians) / sine; + qreal clip = farPlane - nearPlane; + m.m[0][0] = qf2vt_round(cotan / aspect); + m.m[1][0] = qf2vt_round(0.0f); + m.m[2][0] = qf2vt_round(0.0f); + m.m[3][0] = qf2vt_round(0.0f); + m.m[0][1] = qf2vt_round(0.0f); + m.m[1][1] = qf2vt_round(cotan); + m.m[2][1] = qf2vt_round(0.0f); + m.m[3][1] = qf2vt_round(0.0f); + m.m[0][2] = qf2vt_round(0.0f); + m.m[1][2] = qf2vt_round(0.0f); + m.m[2][2] = qf2vt_round(-(nearPlane + farPlane) / clip); + m.m[3][2] = qf2vt_round(-(2.0f * nearPlane * farPlane) / clip); + m.m[0][3] = qf2vt_round(0.0f); + m.m[1][3] = qf2vt_round(0.0f); + m.m[2][3] = qf2vt_round(-1.0f); + m.m[3][3] = qf2vt_round(0.0f); + + // Apply the projection. + *this *= m; + return *this; +} + +#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. + Returns this matrix. +*/ +QMatrix4x4& 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.xp; + m.m[1][0] = side.yp; + m.m[2][0] = side.zp; + m.m[3][0] = 0.0f; + m.m[0][1] = upVector.xp; + m.m[1][1] = upVector.yp; + m.m[2][1] = upVector.zp; + m.m[3][1] = 0.0f; + m.m[0][2] = -forward.xp; + m.m[1][2] = -forward.yp; + m.m[2][2] = -forward.zp; + 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; + return 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. Returns this matrix. + + \sa ortho() +*/ +QMatrix4x4& 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; + } + return *this; +} + +/*! + Retrieves the 16 items in this matrix and writes them to \a values + in row-major order. +*/ +void QMatrix4x4::toValueArray(qreal *values) const +{ + for (int row = 0; row < 4; ++row) + for (int col = 0; col < 4; ++col) + values[row * 4 + col] = qt_math3d_convert<qreal, qrealinner>(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(qt_math3d_convert<qreal, qrealinner>(m[0][0]), + qt_math3d_convert<qreal, qrealinner>(m[0][1]), + qt_math3d_convert<qreal, qrealinner>(m[1][0]), + qt_math3d_convert<qreal, qrealinner>(m[1][1]), + qt_math3d_convert<qreal, qrealinner>(m[3][0]), + qt_math3d_convert<qreal, qrealinner>(m[3][1])); +} + +/*! + Returns the conventional Qt 2D transformation matrix that + corresponds to this matrix. It is assumed that this matrix + only contains 2D transformation elements. + + \sa toAffine() +*/ +QTransform QMatrix4x4::toTransform() const +{ + return QTransform(qt_math3d_convert<qreal, qrealinner>(m[0][0]), + qt_math3d_convert<qreal, qrealinner>(m[0][1]), + qt_math3d_convert<qreal, qrealinner>(m[0][3]), + qt_math3d_convert<qreal, qrealinner>(m[1][0]), + qt_math3d_convert<qreal, qrealinner>(m[1][1]), + qt_math3d_convert<qreal, qrealinner>(m[1][3]), + qt_math3d_convert<qreal, qrealinner>(m[3][0]), + qt_math3d_convert<qreal, qrealinner>(m[3][1]), + qt_math3d_convert<qreal, qrealinner>(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() +*/ + +#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 + +/*! + \fn QRect QMatrix4x4::mapRect(const QRect& rect) const + + 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() +*/ + +/*! + \fn QRectF QMatrix4x4::mapRect(const QRectF& rect) const + + 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() +*/ + +/*! + \fn qrealinner *QMatrix4x4::data() + + Returns a pointer to the raw data of this matrix. This is indended + for use with raw GL functions. + + \sa constData(), inferSpecialType() +*/ + +/*! + \fn const qrealinner *QMatrix4x4::data() const + + Returns a constant pointer to the raw data of this matrix. + This is indended for use with raw GL functions. + + \sa constData() +*/ + +/*! + \fn const qrealinner *QMatrix4x4::constData() const + + Returns a constant pointer to the raw data of this matrix. + This is indended for use with raw GL functions. + + \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; +} + +#ifndef QT_NO_VECTOR3D +/*! + Decomposes the current rotation matrix into an \a axis of rotation plus + an \a angle. The result can be used to construct an equivalent rotation + matrix using glRotate(). It is assumed that the homogenous coordinate + is 1.0. The returned vector is guaranteed to be normalized. + + \code + qreal angle; + QVector3D axis; + + matrix.extractAxisAngle(angle, axis); + glRotate(angle, axis[0], axis[1], axis[2]); + \endcode + + \sa rotate() +*/ +void QMatrix4x4::extractAxisRotation(qreal &angle, QVector3D &axis) const +{ + // Orientation is dependent on the upper 3x3 matrix; subtract the + // homogeneous scaling element from the trace of the 4x4 matrix + qrealinner tr = m[0][0] + m[1][1] + m[2][2]; + qreal cosa = qt_math3d_convert<qreal, qrealinner>(0.5f * (tr - 1.0f)); + angle = acos(cosa) * 180.0f / M_PI; + + // Any axis will work if r is zero (means no rotation) + if (qFuzzyCompare(angle, (qreal)0.0f)) { + axis.setX(1.0f); + axis.setY(0.0f); + axis.setZ(0.0f); + return; + } + + if (angle < 180.0f) { + axis.xp = m[1][2] - m[2][1]; + axis.yp = m[2][0] - m[0][2]; + axis.zp = m[0][1] - m[1][0]; + axis.normalize(); + return; + } + + // rads == PI + qrealinner tmp; + + // r00 is maximum + if ((m[0][0] >= m[2][2]) && (m[0][0] >= m[1][1])) { + axis.xp = 0.5f * qvtsqrt(m[0][0] - m[1][1] - m[2][2] + 1.0f); + tmp = 0.5f / axis.x(); + axis.yp = m[1][0] * tmp; + axis.zp = m[2][0] * tmp; + } + + // r11 is maximum + if ((m[1][1] >= m[2][2]) && (m[1][1] >= m[0][0])) { + axis.yp = 0.5f * qvtsqrt(m[1][1] - m[0][0] - m[2][2] + 1.0f); + tmp = 0.5f / axis.y(); + axis.xp = tmp * m[1][0]; + axis.zp = tmp * m[2][1]; + } + + // r22 is maximum + if ((m[2][2] >= m[1][1]) && (m[2][2] >= m[0][0])) { + axis.zp = 0.5f * qvtsqrt(m[2][2] - m[0][0] - m[1][1] + 1.0f); + tmp = 0.5f / axis.z(); + axis.xp = m[2][0]*tmp; + axis.yp = m[2][1]*tmp; + } +} + +/*! + If this is an orthonormal transformation matrix (e.g. only rotations and + translations have been applied to the matrix, no scaling, or shearing) + then the world translational component can be obtained by calling this function. + + This is most useful for camera matrices, where the negation of this vector + is effectively the camera world coordinates. +*/ +QVector3D QMatrix4x4::extractTranslation() const +{ + return QVector3D + (m[0][0] * m[3][0] + m[0][1] * m[3][1] + m[0][2] * m[3][2], + m[1][0] * m[3][0] + m[1][1] * m[3][1] + m[1][2] * m[3][2], + m[2][0] * m[3][0] + m[2][1] * m[3][1] + m[2][2] * m[3][2], 1); +} +#endif + +/*! + Infers the special type 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 inferSpecialType() 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::inferSpecialType() +{ + // 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; +} + +#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 + +#endif + +QT_END_NAMESPACE diff --git a/src/gui/math3d/qmatrix4x4.h b/src/gui/math3d/qmatrix4x4.h new file mode 100644 index 0000000..8ef73bf --- /dev/null +++ b/src/gui/math3d/qmatrix4x4.h @@ -0,0 +1,954 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_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 Q_GUI_EXPORT QMatrix4x4 +{ +public: + inline QMatrix4x4() { setIdentity(); } + 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); +#if !defined(QT_NO_MEMBER_TEMPLATES) || defined(Q_QDOC) + template <int N, int M> + explicit QMatrix4x4(const QGenericMatrix<N, M, qreal, qrealinner>& matrix); +#endif + QMatrix4x4(const qrealinner *values, int cols, int rows); + QMatrix4x4(const QTransform& transform); + QMatrix4x4(const QMatrix& matrix); + + inline qreal operator()(int row, int column) const; + inline qrealinner& 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 setIdentity(); + + 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 + QMatrix4x4& scale(const QVector3D& vector); + QMatrix4x4& translate(const QVector3D& vector); + QMatrix4x4& rotate(qreal angle, const QVector3D& vector); +#endif + QMatrix4x4& scale(qreal x, qreal y, qreal z = 1.0f); + QMatrix4x4& scale(qreal factor); + QMatrix4x4& translate(qreal x, qreal y, qreal z = 0.0f); + QMatrix4x4& rotate(qreal angle, qreal x, qreal y, qreal z = 0.0f); +#ifndef QT_NO_QUATERNION + QMatrix4x4& rotate(const QQuaternion& quaternion); +#endif + +#ifndef QT_NO_VECTOR3D + void extractAxisRotation(qreal &angle, QVector3D &axis) const; + QVector3D extractTranslation() const; +#endif + + QMatrix4x4& ortho(const QRect& rect); + QMatrix4x4& ortho(const QRectF& rect); + QMatrix4x4& ortho(qreal left, qreal right, qreal bottom, qreal top, qreal nearPlane, qreal farPlane); + QMatrix4x4& frustum(qreal left, qreal right, qreal bottom, qreal top, qreal nearPlane, qreal farPlane); + QMatrix4x4& perspective(qreal angle, qreal aspect, qreal nearPlane, qreal farPlane); +#ifndef QT_NO_VECTOR3D + QMatrix4x4& lookAt(const QVector3D& eye, const QVector3D& center, const QVector3D& up); +#endif + QMatrix4x4& flipCoordinates(); + + void toValueArray(qreal *values) const; + + QMatrix toAffine() const; + QTransform toTransform() const; + + QPoint map(const QPoint& point) const; + QPointF map(const QPointF& point) const; +#ifndef QT_NO_VECTOR3D + QVector3D map(const QVector3D& point) 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; + +#if !defined(QT_NO_MEMBER_TEMPLATES) || defined(Q_QDOC) + template <int N, int M> + QGenericMatrix<N, M, qreal, qrealinner> toGenericMatrix() const; +#endif + + inline qrealinner *data(); + inline const qrealinner *data() const { return m[0]; } + inline const qrealinner *constData() const { return m[0]; } + + void inferSpecialType(); + +#ifndef QT_NO_DEBUG_STREAM + friend Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QMatrix4x4 &m); +#endif + +private: + qrealinner 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; +}; + +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; +} + +#if !defined(QT_NO_MEMBER_TEMPLATES) + +template <int N, int M> +Q_INLINE_TEMPLATE QMatrix4x4::QMatrix4x4 + (const QGenericMatrix<N, M, qreal, qrealinner>& matrix) +{ + const qrealinner *values = matrix.constData(); + for (int col = 0; col < 4; ++col) { + for (int row = 0; row < 4; ++row) { + if (col < N && row < M) + m[col][row] = values[col * M + row]; + else if (col == row) + m[col][row] = 1.0f; + else + m[col][row] = 0.0f; + } + } + flagBits = General; +} + +template <int N, int M> +QGenericMatrix<N, M, qreal, qrealinner> QMatrix4x4::toGenericMatrix() const +{ + QGenericMatrix<N, M, qreal, qrealinner> result; + qrealinner *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][row]; + else if (col == row) + values[col * M + row] = 1.0f; + else + values[col * M + row] = 0.0f; + } + } + return result; +} + +#endif + +inline qreal QMatrix4x4::operator()(int row, int column) const +{ + Q_ASSERT(row >= 0 && row < 4 && column >= 0 && column < 4); + return qt_math3d_convert<qreal, qrealinner>(m[column][row]); +} + +inline qrealinner& QMatrix4x4::operator()(int row, int column) +{ + Q_ASSERT(row >= 0 && row < 4 && column >= 0 && column < 4); + flagBits = General; + return m[column][row]; +} + +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], 1); +} + +inline void QMatrix4x4::setColumn(int index, const QVector4D& value) +{ + Q_ASSERT(index >= 0 && index < 4); + m[index][0] = value.xp; + m[index][1] = value.yp; + m[index][2] = value.zp; + m[index][3] = value.wp; + 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], 1); +} + +inline void QMatrix4x4::setRow(int index, const QVector4D& value) +{ + Q_ASSERT(index >= 0 && index < 4); + m[0][index] = value.xp; + m[1][index] = value.yp; + m[2][index] = value.zp; + m[3][index] = value.wp; + 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::setIdentity() +{ + 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) +{ + qrealinner f(factor); + m[0][0] *= f; + m[0][1] *= f; + m[0][2] *= f; + m[0][3] *= f; + m[1][0] *= f; + m[1][1] *= f; + m[1][2] *= f; + m[1][3] *= f; + m[2][0] *= f; + m[2][1] *= f; + m[2][2] *= f; + m[2][3] *= f; + m[3][0] *= f; + m[3][1] *= f; + m[3][2] *= f; + m[3][3] *= f; + 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) +{ + qrealinner x, y, z, w; + x = vector.xp * matrix.m[0][0] + + vector.yp * matrix.m[0][1] + + vector.zp * matrix.m[0][2] + + matrix.m[0][3]; + y = vector.xp * matrix.m[1][0] + + vector.yp * matrix.m[1][1] + + vector.zp * matrix.m[1][2] + + matrix.m[1][3]; + z = vector.xp * matrix.m[2][0] + + vector.yp * matrix.m[2][1] + + vector.zp * matrix.m[2][2] + + matrix.m[2][3]; + w = vector.xp * matrix.m[3][0] + + vector.yp * matrix.m[3][1] + + vector.zp * matrix.m[3][2] + + matrix.m[3][3]; + if (w == 1.0f) + return QVector3D(x, y, z, 1); + else + return QVector3D(x / w, y / w, z / w, 1); +} + +inline QVector3D operator*(const QMatrix4x4& matrix, const QVector3D& vector) +{ + qrealinner x, y, z, w; + x = vector.xp * matrix.m[0][0] + + vector.yp * matrix.m[1][0] + + vector.zp * matrix.m[2][0] + + matrix.m[3][0]; + y = vector.xp * matrix.m[0][1] + + vector.yp * matrix.m[1][1] + + vector.zp * matrix.m[2][1] + + matrix.m[3][1]; + z = vector.xp * matrix.m[0][2] + + vector.yp * matrix.m[1][2] + + vector.zp * matrix.m[2][2] + + matrix.m[3][2]; + w = vector.xp * matrix.m[0][3] + + vector.yp * matrix.m[1][3] + + vector.zp * matrix.m[2][3] + + matrix.m[3][3]; + if (w == 1.0f) + return QVector3D(x, y, z, 1); + else + return QVector3D(x / w, y / w, z / w, 1); +} + +#endif + +#ifndef QT_NO_VECTOR4D + +inline QVector4D operator*(const QVector4D& vector, const QMatrix4x4& matrix) +{ + qrealinner x, y, z, w; + x = vector.xp * matrix.m[0][0] + + vector.yp * matrix.m[0][1] + + vector.zp * matrix.m[0][2] + + vector.wp * matrix.m[0][3]; + y = vector.xp * matrix.m[1][0] + + vector.yp * matrix.m[1][1] + + vector.zp * matrix.m[1][2] + + vector.wp * matrix.m[1][3]; + z = vector.xp * matrix.m[2][0] + + vector.yp * matrix.m[2][1] + + vector.zp * matrix.m[2][2] + + vector.wp * matrix.m[2][3]; + w = vector.xp * matrix.m[3][0] + + vector.yp * matrix.m[3][1] + + vector.zp * matrix.m[3][2] + + vector.wp * matrix.m[3][3]; + return QVector4D(x, y, z, w, 1); +} + +inline QVector4D operator*(const QMatrix4x4& matrix, const QVector4D& vector) +{ + qrealinner x, y, z, w; + x = vector.xp * matrix.m[0][0] + + vector.yp * matrix.m[1][0] + + vector.zp * matrix.m[2][0] + + vector.wp * matrix.m[3][0]; + y = vector.xp * matrix.m[0][1] + + vector.yp * matrix.m[1][1] + + vector.zp * matrix.m[2][1] + + vector.wp * matrix.m[3][1]; + z = vector.xp * matrix.m[0][2] + + vector.yp * matrix.m[1][2] + + vector.zp * matrix.m[2][2] + + vector.wp * matrix.m[3][2]; + w = vector.xp * matrix.m[0][3] + + vector.yp * matrix.m[1][3] + + vector.zp * matrix.m[2][3] + + vector.wp * matrix.m[3][3]; + return QVector4D(x, y, z, w, 1); +} + +#endif + +inline QPoint operator*(const QPoint& point, const QMatrix4x4& matrix) +{ + qrealinner xin, yin; + qrealinner 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) +{ + qrealinner xin, yin; + qrealinner 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(qt_math3d_convert<qreal, qrealinner>(x), + qt_math3d_convert<qreal, qrealinner>(y)); + } else { + return QPointF(qt_math3d_convert<qreal, qrealinner>(x / w), + qt_math3d_convert<qreal, qrealinner>(y / w)); + } +} + +inline QPoint operator*(const QMatrix4x4& matrix, const QPoint& point) +{ + qrealinner xin, yin; + qrealinner x, y, w; + xin = point.x(); + yin = point.y(); + 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) +{ + qrealinner xin, yin; + qrealinner x, y, w; + xin = point.x(); + yin = point.y(); + 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(qt_math3d_convert<qreal, qrealinner>(x), + qt_math3d_convert<qreal, qrealinner>(y)); + } else { + return QPointF(qt_math3d_convert<qreal, qrealinner>(x / w), + qt_math3d_convert<qreal, qrealinner>(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); + qrealinner f(factor); + m.m[0][0] = matrix.m[0][0] * f; + m.m[0][1] = matrix.m[0][1] * f; + m.m[0][2] = matrix.m[0][2] * f; + m.m[0][3] = matrix.m[0][3] * f; + m.m[1][0] = matrix.m[1][0] * f; + m.m[1][1] = matrix.m[1][1] * f; + m.m[1][2] = matrix.m[1][2] * f; + m.m[1][3] = matrix.m[1][3] * f; + m.m[2][0] = matrix.m[2][0] * f; + m.m[2][1] = matrix.m[2][1] * f; + m.m[2][2] = matrix.m[2][2] * f; + m.m[2][3] = matrix.m[2][3] * f; + m.m[3][0] = matrix.m[3][0] * f; + m.m[3][1] = matrix.m[3][1] * f; + m.m[3][2] = matrix.m[3][2] * f; + m.m[3][3] = matrix.m[3][3] * f; + return m; +} + +inline QMatrix4x4 operator*(const QMatrix4x4& matrix, qreal factor) +{ + QMatrix4x4 m(1); + qrealinner f(factor); + m.m[0][0] = matrix.m[0][0] * f; + m.m[0][1] = matrix.m[0][1] * f; + m.m[0][2] = matrix.m[0][2] * f; + m.m[0][3] = matrix.m[0][3] * f; + m.m[1][0] = matrix.m[1][0] * f; + m.m[1][1] = matrix.m[1][1] * f; + m.m[1][2] = matrix.m[1][2] * f; + m.m[1][3] = matrix.m[1][3] * f; + m.m[2][0] = matrix.m[2][0] * f; + m.m[2][1] = matrix.m[2][1] * f; + m.m[2][2] = matrix.m[2][2] * f; + m.m[2][3] = matrix.m[2][3] * f; + m.m[3][0] = matrix.m[3][0] * f; + m.m[3][1] = matrix.m[3][1] * f; + m.m[3][2] = matrix.m[3][2] * f; + m.m[3][3] = matrix.m[3][3] * f; + 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; +} + +#endif + +#ifndef QT_NO_VECTOR4D + +inline QVector4D QMatrix4x4::map(const QVector4D& point) const +{ + return *this * point; +} + +#endif + +inline QRect QMatrix4x4::mapRect(const QRect& rect) const +{ + QPoint tl = map(rect.topLeft()); QPoint tr = map(rect.topRight()); + QPoint bl = map(rect.bottomLeft()); QPoint br = map(rect.bottomRight()); + + 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(QPoint(xmin, ymin), QPoint(xmax, ymax)); +} + +inline QRectF QMatrix4x4::mapRect(const QRectF& rect) const +{ + 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)); +} + +inline qrealinner *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[0]; +} + +#ifndef QT_NO_DEBUG_STREAM +Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QMatrix4x4 &m); +#endif + +template <int N, int M> +QMatrix4x4 qGenericMatrixToMatrix4x4(const QGenericMatrix<N, M, qreal, qrealinner>& matrix) +{ + return QMatrix4x4(matrix.constData(), N, M); +} + +template <int N, int M> +QGenericMatrix<N, M, qreal, qrealinner> qGenericMatrixFromMatrix4x4(const QMatrix4x4& matrix) +{ + QGenericMatrix<N, M, qreal, qrealinner> result; + const qrealinner *m = matrix.constData(); + qrealinner *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 + +QT_END_NAMESPACE + +#ifndef QT_NO_MATRIX4X4 +Q_DECLARE_METATYPE(QMatrix4x4) +#endif + +QT_END_HEADER + +#endif diff --git a/src/gui/math3d/qquaternion.cpp b/src/gui/math3d/qquaternion.cpp new file mode 100644 index 0000000..730844f --- /dev/null +++ b/src/gui/math3d/qquaternion.cpp @@ -0,0 +1,513 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_LICENSE$ +** +****************************************************************************/ + +#include "qquaternion.h" +#include "qmath3dutil_p.h" +#include <QtCore/qmath.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 + + 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. + + The components of a quaternion are stored internally using the most + efficient representation for the GL rendering engine, which will be + either floating-point or fixed-point. +*/ + +/*! + \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. +*/ + +/*! + \fn QQuaternion::QQuaternion(int scalar, int xpos, int ypos, int 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 qvtsqrt64(qvtmul64(xp, xp) + qvtmul64(yp, yp) + + qvtmul64(zp, zp) + qvtmul64(wp, wp)); +} + +/*! + Returns the squared length of the quaternion. + + \sa length() +*/ +qreal QQuaternion::lengthSquared() const +{ + return qvtdot64(qvtmul64(xp, xp) + qvtmul64(yp, yp) + + qvtmul64(zp, zp) + qvtmul64(wp, wp)); +} + +/*! + Returns the normalized unit form of this quaternion. If this quaternion + is not null, the returned quaternion is guaranteed to be 1.0 in length. + If this quaternion is null, then a null quaternion is returned. + + \sa length(), normalize() +*/ +QQuaternion QQuaternion::normalized() const +{ + qreal len = length(); + if (!qIsNull(len)) + return *this / 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. + + \sa length(), normalized() +*/ +void QQuaternion::normalize() +{ + qreal len = length(); + if (qIsNull(len)) + return; + + 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.rotateVector(vector); + \endcode + + is equivalent to the following: + + \code + QVector3D result = (q * QQuaternion(0, vector) * q.conjugate()).vector(); + \endcode +*/ +QVector3D QQuaternion::rotateVector(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. + qrealinner s, c; + QVector3D ax = axis.normalized(); + qt_math3d_sincos(angle / 2.0f, &s, &c); + return QQuaternion(c, ax.xp * s, ax.yp * s, ax.zp * s, 1).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) +{ + qrealinner xp = x; + qrealinner yp = y; + qrealinner zp = z; + qrealinner s, c; + qreal length = qvtsqrt(xp * xp + yp * yp + zp * zp); + if (!qIsNull(length)) { + xp /= length; + yp /= length; + zp /= length; + } + qt_math3d_sincos(angle / 2.0f, &s, &c); + return QQuaternion(c, xp * s, yp * s, zp * s, 1).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. +*/ +QQuaternion QQuaternion::interpolate + (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 = qvtdot64(qvtmul64(q1.xp, q2.xp) + qvtmul64(q1.yp, q2.yp) + + qvtmul64(q1.zp, q2.zp) + qvtmul64(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; +} + +#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 + +#endif + +QT_END_NAMESPACE diff --git a/src/gui/math3d/qquaternion.h b/src/gui/math3d/qquaternion.h new file mode 100644 index 0000000..cc71b7d --- /dev/null +++ b/src/gui/math3d/qquaternion.h @@ -0,0 +1,313 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_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 Q_GUI_EXPORT QQuaternion +{ +public: + QQuaternion(); + QQuaternion(qreal scalar, qreal xpos, qreal ypos, qreal zpos); + QQuaternion(int scalar, int xpos, int ypos, int 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 rotateVector(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 + +#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 interpolate + (const QQuaternion& q1, const QQuaternion& q2, qreal t); + +private: + qrealinner wp, xp, yp, zp; + + friend class QMatrix4x4; + + QQuaternion(qrealinner scalar, qrealinner xpos, qrealinner ypos, qrealinner zpos, int dummy); +}; + +inline QQuaternion::QQuaternion() : wp(1.0f), xp(0.0f), yp(0.0f), zp(0.0f) {} + +inline QQuaternion::QQuaternion(qreal scalar, qreal xpos, qreal ypos, qreal zpos) : wp(scalar), xp(xpos), yp(ypos), zp(zpos) {} + + +inline QQuaternion::QQuaternion(qrealinner scalar, qrealinner xpos, qrealinner ypos, qrealinner zpos, int) : wp(scalar), xp(xpos), yp(ypos), zp(zpos) {} + +inline QQuaternion::QQuaternion(int scalar, int xpos, int ypos, int zpos) : wp(scalar), 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 qt_math3d_convert<qreal, qrealinner>(xp); } +inline qreal QQuaternion::y() const { return qt_math3d_convert<qreal, qrealinner>(yp); } +inline qreal QQuaternion::z() const { return qt_math3d_convert<qreal, qrealinner>(zp); } +inline qreal QQuaternion::scalar() const { return qt_math3d_convert<qreal, qrealinner>(wp); } + +inline void QQuaternion::setX(qreal x) { xp = x; } +inline void QQuaternion::setY(qreal y) { yp = y; } +inline void QQuaternion::setZ(qreal z) { zp = z; } +inline void QQuaternion::setScalar(qreal scalar) { wp = scalar; } + +inline QQuaternion QQuaternion::conjugate() const +{ + return QQuaternion(wp, -xp, -yp, -zp, 1); +} + +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) +{ + qrealinner f(factor); + xp *= f; + yp *= f; + zp *= f; + wp *= f; + return *this; +} + +inline const QQuaternion operator*(const QQuaternion &q1, const QQuaternion& q2) +{ + // Algorithm from: + // http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q53 + qrealinner x = q1.wp * q2.xp + + q1.xp * q2.wp + + q1.yp * q2.zp - + q1.zp * q2.yp; + qrealinner y = q1.wp * q2.yp + + q1.yp * q2.wp + + q1.zp * q2.xp - + q1.xp * q2.zp; + qrealinner z = q1.wp * q2.zp + + q1.zp * q2.wp + + q1.xp * q2.yp - + q1.yp * q2.xp; + qrealinner w = q1.wp * q2.wp - + q1.xp * q2.xp - + q1.yp * q2.yp - + q1.zp * q2.zp; + return QQuaternion(w, x, y, z, 1); +} + +inline QQuaternion &QQuaternion::operator*=(const QQuaternion &quaternion) +{ + *this = *this * quaternion; + return *this; +} + +inline QQuaternion &QQuaternion::operator/=(qreal divisor) +{ + qrealinner d(divisor); + xp /= d; + yp /= d; + zp /= d; + wp /= d; + 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, 1); +} + +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, 1); +} + +inline const QQuaternion operator*(qreal factor, const QQuaternion &quaternion) +{ + qrealinner f(factor); + return QQuaternion(quaternion.wp * f, quaternion.xp * f, quaternion.yp * f, quaternion.zp * f, 1); +} + +inline const QQuaternion operator*(const QQuaternion &quaternion, qreal factor) +{ + qrealinner f(factor); + return QQuaternion(quaternion.wp * f, quaternion.xp * f, quaternion.yp * f, quaternion.zp * f, 1); +} + +inline const QQuaternion operator-(const QQuaternion &quaternion) +{ + return QQuaternion(-quaternion.wp, -quaternion.xp, -quaternion.yp, -quaternion.zp, 1); +} + +inline const QQuaternion operator/(const QQuaternion &quaternion, qreal divisor) +{ + qrealinner d(divisor); + return QQuaternion(quaternion.wp / d, quaternion.xp / d, quaternion.yp / d, quaternion.zp / d, 1); +} + +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 scalar, const QVector3D& vector) + : wp(scalar), xp(vector.xp), yp(vector.yp), zp(vector.zp) {} + +inline void QQuaternion::setVector(const QVector3D& vector) +{ + xp = vector.xp; + yp = vector.yp; + zp = vector.zp; +} + +inline QVector3D QQuaternion::vector() const +{ + return QVector3D(xp, yp, zp, 1); +} + +#endif + +inline void QQuaternion::setVector(qreal x, qreal y, qreal z) +{ + xp = x; + yp = y; + zp = z; +} + +#ifndef QT_NO_VECTOR4D + +inline QQuaternion::QQuaternion(const QVector4D& vector) + : wp(vector.wp), xp(vector.xp), yp(vector.yp), zp(vector.zp) {} + +inline QVector4D QQuaternion::toVector4D() const +{ + return QVector4D(xp, yp, zp, wp, 1); +} + +#endif + +#ifndef QT_NO_DEBUG_STREAM +Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QQuaternion &q); +#endif + +#endif + +QT_END_NAMESPACE + +#ifndef QT_NO_QUATERNION +Q_DECLARE_METATYPE(QQuaternion) +#endif + +QT_END_HEADER + +#endif diff --git a/src/gui/math3d/qvector2d.cpp b/src/gui/math3d/qvector2d.cpp new file mode 100644 index 0000000..13d6cc9 --- /dev/null +++ b/src/gui/math3d/qvector2d.cpp @@ -0,0 +1,386 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_LICENSE$ +** +****************************************************************************/ + +#include "qvector2d.h" +#include "qvector3d.h" +#include "qvector4d.h" +#include "qmath3dutil_p.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 + + The QVector2D class can also be used to represent vertices in 2D space. + We therefore do not need to provide a separate vertex class. + + The coordinates are stored internally using the most efficient + representation for the GL rendering engine, which will be either + floating-point or fixed-point. +*/ + +/*! + \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(int xpos, int 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 qvtsqrt64(qvtmul64(xp, xp) + qvtmul64(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 qvtdot64(qvtmul64(xp, xp) + qvtmul64(yp, yp)); +} + +/*! + Returns the normalized unit vector form of this vector. If this vector + is not null, the returned vector is guaranteed to be 1.0 in length. + If this vector is null, then a null vector is returned. + + \sa length(), normalize() +*/ +QVector2D QVector2D::normalized() const +{ + qreal len = length(); + if (!qIsNull(len)) + return *this / len; + else + return QVector2D(); +} + +/*! + Normalizes the currect vector in place. Nothing happens if this + vector is a null vector. + + \sa length(), normalized() +*/ +void QVector2D::normalize() +{ + qreal len = length(); + if (qIsNull(len)) + return; + + 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 qvtdot64(qvtmul64(v1.xp, v2.xp) + qvtmul64(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() +*/ + +#ifndef QT_NO_DEBUG_STREAM + +QDebug operator<<(QDebug dbg, const QVector2D &vector) +{ + dbg.nospace() << "QVector2D(" << vector.x() << ", " << vector.y() << ')'; + return dbg.space(); +} + +#endif + +#endif + +QT_END_NAMESPACE diff --git a/src/gui/math3d/qvector2d.h b/src/gui/math3d/qvector2d.h new file mode 100644 index 0000000..55452b0 --- /dev/null +++ b/src/gui/math3d/qvector2d.h @@ -0,0 +1,237 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_LICENSE$ +** +****************************************************************************/ + +#ifndef QVECTOR2D_H +#define QVECTOR2D_H + +#include <QtGui/qmath3dglobal.h> +#include <QtCore/qpoint.h> +#include <QtCore/qmetatype.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QVector3D; +class QVector4D; + +#ifndef QT_NO_VECTOR2D + +class Q_GUI_EXPORT QVector2D +{ +public: + QVector2D(); + QVector2D(qreal xpos, qreal ypos); + QVector2D(int xpos, int 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; + +private: + qrealinner xp, yp; + + QVector2D(qrealinner xpos, qrealinner ypos, int dummy); + + friend class QVector3D; + friend class QVector4D; + friend class QVertexArray; +}; + +inline QVector2D::QVector2D() : xp(0.0f), yp(0.0f) {} + +inline QVector2D::QVector2D(qrealinner xpos, qrealinner ypos, int) : xp(xpos), yp(ypos) {} + +inline QVector2D::QVector2D(qreal xpos, qreal ypos) : xp(xpos), yp(ypos) {} + +inline QVector2D::QVector2D(int xpos, int 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 qt_math3d_convert<qreal, qrealinner>(xp); } +inline qreal QVector2D::y() const { return qt_math3d_convert<qreal, qrealinner>(yp); } + +inline void QVector2D::setX(qreal x) { xp = x; } +inline void QVector2D::setY(qreal y) { yp = y; } + +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) +{ + qrealinner f(factor); + xp *= f; + yp *= f; + return *this; +} + +inline QVector2D &QVector2D::operator*=(const QVector2D &vector) +{ + xp *= vector.xp; + yp *= vector.yp; + return *this; +} + +inline QVector2D &QVector2D::operator/=(qreal divisor) +{ + qrealinner d(divisor); + xp /= d; + yp /= d; + 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) +{ + qrealinner f(factor); + return QVector2D(vector.xp * f, vector.yp * f, 1); +} + +inline const QVector2D operator*(const QVector2D &vector, qreal factor) +{ + qrealinner f(factor); + return QVector2D(vector.xp * f, vector.yp * f, 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) +{ + qrealinner d(divisor); + return QVector2D(vector.xp / d, vector.yp / d, 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(qt_math3d_convert<qreal, qrealinner>(xp), + qt_math3d_convert<qreal, qrealinner>(yp)); +} + +#ifndef QT_NO_DEBUG_STREAM +Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QVector2D &vector); +#endif + +#endif + +QT_END_NAMESPACE + +#ifndef QT_NO_VECTOR2D +Q_DECLARE_METATYPE(QVector2D) +#endif + +QT_END_HEADER + +#endif diff --git a/src/gui/math3d/qvector3d.cpp b/src/gui/math3d/qvector3d.cpp new file mode 100644 index 0000000..f0b3aeb --- /dev/null +++ b/src/gui/math3d/qvector3d.cpp @@ -0,0 +1,535 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_LICENSE$ +** +****************************************************************************/ + +#include "qvector3d.h" +#include "qvector2d.h" +#include "qvector4d.h" +#include "qmath3dutil_p.h" +#include <QtCore/qmath.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 + + 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. + + The coordinates are stored internally using the most efficient + representation for the GL rendering engine, which will be either + floating-point or fixed-point. +*/ + +/*! + \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(int xpos, int ypos, int 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 not null, the returned vector is guaranteed to be 1.0 in length. + If this vector is null, then a null vector is returned. + + \sa length(), normalize() +*/ +QVector3D QVector3D::normalized() const +{ + qreal len = length(); + if (!qIsNull(len)) + return *this / len; + else + return QVector3D(); +} + +/*! + Normalizes the currect vector in place. Nothing happens if this + vector is a null vector. + + \sa length(), normalized() +*/ +void QVector3D::normalize() +{ + qreal len = length(); + if (qIsNull(len)) + return; + + 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 qvtdot64(qvtmul64(v1.xp, v2.xp) + qvtmul64(v1.yp, v2.yp) + qvtmul64(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. + + \sa toPointF(), toVector2D() +*/ + +/*! + \fn QPointF QVector3D::toPointF() const + + Returns the QPointF form of this 3D vector. + + \sa toPoint(), toVector2D() +*/ + +/*! + Returns the length of the vector from the origin. + + \sa lengthSquared(), normalized() +*/ +qreal QVector3D::length() const +{ + return qvtsqrt64(qvtmul64(xp, xp) + qvtmul64(yp, yp) + qvtmul64(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 qvtdot64(qvtmul64(xp, xp) + qvtmul64(yp, yp) + qvtmul64(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 + +#endif + +QT_END_NAMESPACE diff --git a/src/gui/math3d/qvector3d.h b/src/gui/math3d/qvector3d.h new file mode 100644 index 0000000..dd1d014 --- /dev/null +++ b/src/gui/math3d/qvector3d.h @@ -0,0 +1,266 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_LICENSE$ +** +****************************************************************************/ + +#ifndef QVECTOR3D_H +#define QVECTOR3D_H + +#include <QtGui/qmath3dglobal.h> +#include <QtCore/qpoint.h> +#include <QtCore/qmetatype.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QMatrix4x4; +class QVector2D; +class QVector4D; +class QQuaternion; + +#ifndef QT_NO_VECTOR3D + +class Q_GUI_EXPORT QVector3D +{ +public: + QVector3D(); + QVector3D(qreal xpos, qreal ypos, qreal zpos); + QVector3D(int xpos, int ypos, int 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; + +private: + qrealinner xp, yp, zp; + + QVector3D(qrealinner xpos, qrealinner ypos, qrealinner zpos, int dummy); + + friend class QVector2D; + friend class QVector4D; + friend class QQuaternion; + friend class QMatrix4x4; + friend class QVertexArray; + friend class QGLPainter; +#ifndef QT_NO_MATRIX4X4 + friend QVector3D operator*(const QVector3D& vector, const QMatrix4x4& matrix); + friend QVector3D operator*(const QMatrix4x4& matrix, const QVector3D& vector); +#endif +}; + +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(qrealinner xpos, qrealinner ypos, qrealinner zpos, int) : xp(xpos), yp(ypos), zp(zpos) {} + +inline QVector3D::QVector3D(int xpos, int ypos, int zpos) : 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 qt_math3d_convert<qreal, qrealinner>(xp); } +inline qreal QVector3D::y() const { return qt_math3d_convert<qreal, qrealinner>(yp); } +inline qreal QVector3D::z() const { return qt_math3d_convert<qreal, qrealinner>(zp); } + +inline void QVector3D::setX(qreal x) { xp = x; } +inline void QVector3D::setY(qreal y) { yp = y; } +inline void QVector3D::setZ(qreal z) { zp = z; } + +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) +{ + qrealinner f(factor); + xp *= f; + yp *= f; + zp *= f; + 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) +{ + qrealinner d(divisor); + xp /= d; + yp /= d; + zp /= d; + 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) +{ + qrealinner f(factor); + return QVector3D(vector.xp * f, vector.yp * f, vector.zp * f, 1); +} + +inline const QVector3D operator*(const QVector3D &vector, qreal factor) +{ + qrealinner f(factor); + return QVector3D(vector.xp * f, vector.yp * f, vector.zp * f, 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) +{ + qrealinner d(divisor); + return QVector3D(vector.xp / d, vector.yp / d, vector.zp / d, 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(qt_math3d_convert<qreal, qrealinner>(xp), + qt_math3d_convert<qreal, qrealinner>(yp)); +} + +#ifndef QT_NO_DEBUG_STREAM +Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QVector3D &vector); +#endif + +#endif + +QT_END_NAMESPACE + +#ifndef QT_NO_VECTOR3D +Q_DECLARE_METATYPE(QVector3D) +#endif + +QT_END_HEADER + +#endif diff --git a/src/gui/math3d/qvector4d.cpp b/src/gui/math3d/qvector4d.cpp new file mode 100644 index 0000000..1239df0 --- /dev/null +++ b/src/gui/math3d/qvector4d.cpp @@ -0,0 +1,491 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_LICENSE$ +** +****************************************************************************/ + +#include "qvector4d.h" +#include "qvector3d.h" +#include "qvector2d.h" +#include "qmath3dutil_p.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 + + The QVector4D class can also be used to represent vertices in 4D space. + We therefore do not need to provide a separate vertex class. + + The coordinates are stored internally using the most efficient + representation for the GL rendering engine, which will be either + floating-point or fixed-point. + + \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(int xpos, int ypos, int zpos, int 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 qvtsqrt64(qvtmul64(xp, xp) + qvtmul64(yp, yp) + + qvtmul64(zp, zp) + qvtmul64(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 qvtdot64(qvtmul64(xp, xp) + qvtmul64(yp, yp) + + qvtmul64(zp, zp) + qvtmul64(wp, wp)); +} + +/*! + Returns the normalized unit vector form of this vector. If this vector + is not null, the returned vector is guaranteed to be 1.0 in length. + If this vector is null, then a null vector is returned. + + \sa length(), normalize() +*/ +QVector4D QVector4D::normalized() const +{ + qreal len = length(); + if (!qIsNull(len)) + return *this / len; + else + return QVector4D(); +} + +/*! + Normalizes the currect vector in place. Nothing happens if this + vector is a null vector. + + \sa length(), normalized() +*/ +void QVector4D::normalize() +{ + qreal len = length(); + if (qIsNull(len)) + return; + + 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 qvtdot64(qvtmul64(v1.xp, v2.xp) + qvtmul64(v1.yp, v2.yp) + + qvtmul64(v1.zp, v2.zp) + qvtmul64(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. + + \sa toPointF(), toVector2D() +*/ + +/*! + \fn QPointF QVector4D::toPointF() const + + Returns the QPointF form of this 4D vector. + + \sa toPoint(), toVector2D() +*/ + +#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 + +#endif + +QT_END_NAMESPACE diff --git a/src/gui/math3d/qvector4d.h b/src/gui/math3d/qvector4d.h new file mode 100644 index 0000000..078c328 --- /dev/null +++ b/src/gui/math3d/qvector4d.h @@ -0,0 +1,270 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_LICENSE$ +** +****************************************************************************/ + +#ifndef QVECTOR4D_H +#define QVECTOR4D_H + +#include <QtGui/qmath3dglobal.h> +#include <QtCore/qpoint.h> +#include <QtCore/qmetatype.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QMatrix4x4; +class QVector2D; +class QVector3D; +class QQuaternion; + +#ifndef QT_NO_VECTOR4D + +class Q_GUI_EXPORT QVector4D +{ +public: + QVector4D(); + QVector4D(qreal xpos, qreal ypos, qreal zpos, qreal wpos); + QVector4D(int xpos, int ypos, int zpos, int 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; + +private: + qrealinner xp, yp, zp, wp; + + QVector4D(qrealinner xpos, qrealinner ypos, qrealinner zpos, qrealinner wpos, int dummy); + + friend class QVector2D; + friend class QVector3D; + friend class QQuaternion; + friend class QMatrix4x4; + friend class QVertexArray; +#ifndef QT_NO_MATRIX4X4 + friend QVector4D operator*(const QVector4D& vector, const QMatrix4x4& matrix); + friend QVector4D operator*(const QMatrix4x4& matrix, const QVector4D& vector); +#endif +}; + +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(qrealinner xpos, qrealinner ypos, qrealinner zpos, qrealinner wpos, int) : xp(xpos), yp(ypos), zp(zpos), wp(wpos) {} + +inline QVector4D::QVector4D(int xpos, int ypos, int zpos, int wpos) : 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 qt_math3d_convert<qreal, qrealinner>(xp); } +inline qreal QVector4D::y() const { return qt_math3d_convert<qreal, qrealinner>(yp); } +inline qreal QVector4D::z() const { return qt_math3d_convert<qreal, qrealinner>(zp); } +inline qreal QVector4D::w() const { return qt_math3d_convert<qreal, qrealinner>(wp); } + +inline void QVector4D::setX(qreal x) { xp = x; } +inline void QVector4D::setY(qreal y) { yp = y; } +inline void QVector4D::setZ(qreal z) { zp = z; } +inline void QVector4D::setW(qreal w) { wp = w; } + +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) +{ + qrealinner f(factor); + xp *= f; + yp *= f; + zp *= f; + wp *= f; + 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) +{ + qrealinner d(divisor); + xp /= d; + yp /= d; + zp /= d; + wp /= d; + 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) +{ + qrealinner f(factor); + return QVector4D(vector.xp * f, vector.yp * f, vector.zp * f, vector.wp * f, 1); +} + +inline const QVector4D operator*(const QVector4D &vector, qreal factor) +{ + qrealinner f(factor); + return QVector4D(vector.xp * f, vector.yp * f, vector.zp * f, vector.wp * f, 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) +{ + qrealinner d(divisor); + return QVector4D(vector.xp / d, vector.yp / d, vector.zp / d, vector.wp / d, 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(qt_math3d_convert<qreal, qrealinner>(xp), + qt_math3d_convert<qreal, qrealinner>(yp)); +} + +#ifndef QT_NO_DEBUG_STREAM +Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QVector4D &vector); +#endif + +#endif + +QT_END_NAMESPACE + +#ifndef QT_NO_VECTOR4D +Q_DECLARE_METATYPE(QVector4D) +#endif + +QT_END_HEADER + +#endif |