QVector2D/QVector3D/QVector4D: ensure well-defined behavior
The purpose of QVectorND classes is to store N floats packed together. One of their usecases is to build arrays of them, then using them as an array of floats (e.g. when uploading data to OpenGL). The design of the class however has a major problem: using separate members does not guarantee that the compiler does not insert padding between them (although that could be static-asserted). What's worse, the implementation of operator[] just does pointer arithmetic on the first member of the class; that's undefined behavior, and will trigger ASAN warnings in the future [1]. Solve both problems by using an array of floats instead of individual x/y/z/w members. Now the compiler is not allowed to insert hidden padding any more, and makes operator[] well-defined. However this might be a BIC (IF the compiler added paddings in the past): hence, add static_asserts checking that the memory layout of the classes hasn't changed. For good measure, also add static_asserts checking 1) that the class is standard_layout, so it's safe to reinterpret_cast it to its first (and only) member; 2) that there's no padding at the _end_ of the class. Note: an alternative solution to the operator[] problem could've been leaving the class untouched, and reimplementing the operator via a switch. Unfortunately none between GCC, clang and MSVC compile away the switch, dramatically pessimizing the code. [1] https://github.com/google/sanitizers/wiki/AddressSanitizerIntraObjectOverflow Change-Id: Iec00ffb6044c58cf728de1754a780068f88152cb Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> Reviewed-by: Lars Knoll <lars.knoll@qt.io>
This commit is contained in:
parent
54dcbf4992
commit
093cf19f1e
@ -49,6 +49,39 @@ QT_BEGIN_NAMESPACE
|
||||
|
||||
#ifndef QT_NO_VECTOR2D
|
||||
|
||||
Q_STATIC_ASSERT_X(std::is_standard_layout<QVector2D>::value, "QVector2D is supposed to be standard layout");
|
||||
Q_STATIC_ASSERT_X(sizeof(QVector2D) == sizeof(float) * 2, "QVector2D is not supposed to have padding at the end");
|
||||
|
||||
// QVector2D used to be defined as class QVector2D { float x, y; };,
|
||||
// now instead it is defined as classs QVector2D { float v[2]; };.
|
||||
// Check that binary compatibility is preserved.
|
||||
// ### Qt 6: remove all of these checks.
|
||||
|
||||
namespace {
|
||||
|
||||
struct QVector2DOld
|
||||
{
|
||||
float x, y;
|
||||
};
|
||||
|
||||
struct QVector2DNew
|
||||
{
|
||||
float v[2];
|
||||
};
|
||||
|
||||
Q_STATIC_ASSERT_X(std::is_standard_layout<QVector2DOld>::value, "Binary compatibility break in QVector2D");
|
||||
Q_STATIC_ASSERT_X(std::is_standard_layout<QVector2DNew>::value, "Binary compatibility break in QVector2D");
|
||||
|
||||
Q_STATIC_ASSERT_X(sizeof(QVector2DOld) == sizeof(QVector2DNew), "Binary compatibility break in QVector2D");
|
||||
|
||||
// requires a constexpr offsetof
|
||||
#if !defined(Q_CC_MSVC) || (_MSC_VER >= 1910)
|
||||
Q_STATIC_ASSERT_X(offsetof(QVector2DOld, x) == offsetof(QVector2DNew, v) + sizeof(QVector2DNew::v[0]) * 0, "Binary compatibility break in QVector2D");
|
||||
Q_STATIC_ASSERT_X(offsetof(QVector2DOld, y) == offsetof(QVector2DNew, v) + sizeof(QVector2DNew::v[0]) * 1, "Binary compatibility break in QVector2D");
|
||||
#endif
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
/*!
|
||||
\class QVector2D
|
||||
\brief The QVector2D class represents a vector or vertex in 2D space.
|
||||
@ -105,8 +138,8 @@ QT_BEGIN_NAMESPACE
|
||||
*/
|
||||
QVector2D::QVector2D(const QVector3D& vector)
|
||||
{
|
||||
xp = vector.xp;
|
||||
yp = vector.yp;
|
||||
v[0] = vector.v[0];
|
||||
v[1] = vector.v[1];
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -121,8 +154,8 @@ QVector2D::QVector2D(const QVector3D& vector)
|
||||
*/
|
||||
QVector2D::QVector2D(const QVector4D& vector)
|
||||
{
|
||||
xp = vector.xp;
|
||||
yp = vector.yp;
|
||||
v[0] = vector.v[0];
|
||||
v[1] = vector.v[1];
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -193,8 +226,8 @@ QVector2D::QVector2D(const QVector4D& vector)
|
||||
float QVector2D::length() const
|
||||
{
|
||||
// Need some extra precision if the length is very small.
|
||||
double len = double(xp) * double(xp) +
|
||||
double(yp) * double(yp);
|
||||
double len = double(v[0]) * double(v[0]) +
|
||||
double(v[1]) * double(v[1]);
|
||||
return float(std::sqrt(len));
|
||||
}
|
||||
|
||||
@ -206,7 +239,7 @@ float QVector2D::length() const
|
||||
*/
|
||||
float QVector2D::lengthSquared() const
|
||||
{
|
||||
return xp * xp + yp * yp;
|
||||
return v[0] * v[0] + v[1] * v[1];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -221,13 +254,13 @@ float QVector2D::lengthSquared() const
|
||||
QVector2D QVector2D::normalized() const
|
||||
{
|
||||
// Need some extra precision if the length is very small.
|
||||
double len = double(xp) * double(xp) +
|
||||
double(yp) * double(yp);
|
||||
double len = double(v[0]) * double(v[0]) +
|
||||
double(v[1]) * double(v[1]);
|
||||
if (qFuzzyIsNull(len - 1.0f)) {
|
||||
return *this;
|
||||
} else if (!qFuzzyIsNull(len)) {
|
||||
double sqrtLen = std::sqrt(len);
|
||||
return QVector2D(float(double(xp) / sqrtLen), float(double(yp) / sqrtLen));
|
||||
return QVector2D(float(double(v[0]) / sqrtLen), float(double(v[1]) / sqrtLen));
|
||||
} else {
|
||||
return QVector2D();
|
||||
}
|
||||
@ -242,15 +275,15 @@ QVector2D QVector2D::normalized() const
|
||||
void QVector2D::normalize()
|
||||
{
|
||||
// Need some extra precision if the length is very small.
|
||||
double len = double(xp) * double(xp) +
|
||||
double(yp) * double(yp);
|
||||
double len = double(v[0]) * double(v[0]) +
|
||||
double(v[1]) * double(v[1]);
|
||||
if (qFuzzyIsNull(len - 1.0f) || qFuzzyIsNull(len))
|
||||
return;
|
||||
|
||||
len = std::sqrt(len);
|
||||
|
||||
xp = float(double(xp) / len);
|
||||
yp = float(double(yp) / len);
|
||||
v[0] = float(double(v[0]) / len);
|
||||
v[1] = float(double(v[1]) / len);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -344,7 +377,7 @@ float QVector2D::distanceToLine
|
||||
*/
|
||||
float QVector2D::dotProduct(const QVector2D& v1, const QVector2D& v2)
|
||||
{
|
||||
return v1.xp * v2.xp + v1.yp * v2.yp;
|
||||
return v1.v[0] * v2.v[0] + v1.v[1] * v2.v[1];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -458,7 +491,7 @@ float QVector2D::dotProduct(const QVector2D& v1, const QVector2D& v2)
|
||||
*/
|
||||
QVector3D QVector2D::toVector3D() const
|
||||
{
|
||||
return QVector3D(xp, yp, 0.0f);
|
||||
return QVector3D(v[0], v[1], 0.0f);
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -472,7 +505,7 @@ QVector3D QVector2D::toVector3D() const
|
||||
*/
|
||||
QVector4D QVector2D::toVector4D() const
|
||||
{
|
||||
return QVector4D(xp, yp, 0.0f, 0.0f);
|
||||
return QVector4D(v[0], v[1], 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -123,7 +123,7 @@ public:
|
||||
operator QVariant() const;
|
||||
|
||||
private:
|
||||
float xp, yp;
|
||||
float v[2];
|
||||
|
||||
friend class QVector3D;
|
||||
friend class QVector4D;
|
||||
@ -131,76 +131,76 @@ private:
|
||||
|
||||
Q_DECLARE_TYPEINFO(QVector2D, Q_PRIMITIVE_TYPE);
|
||||
|
||||
Q_DECL_CONSTEXPR inline QVector2D::QVector2D() : xp(0.0f), yp(0.0f) {}
|
||||
Q_DECL_CONSTEXPR inline QVector2D::QVector2D() : v{0.0f, 0.0f} {}
|
||||
|
||||
Q_DECL_CONSTEXPR inline QVector2D::QVector2D(float xpos, float ypos) : xp(xpos), yp(ypos) {}
|
||||
Q_DECL_CONSTEXPR inline QVector2D::QVector2D(float xpos, float ypos) : v{xpos, ypos} {}
|
||||
|
||||
Q_DECL_CONSTEXPR inline QVector2D::QVector2D(const QPoint& point) : xp(point.x()), yp(point.y()) {}
|
||||
Q_DECL_CONSTEXPR inline QVector2D::QVector2D(const QPoint& point) : v{float(point.x()), float(point.y())} {}
|
||||
|
||||
Q_DECL_CONSTEXPR inline QVector2D::QVector2D(const QPointF& point) : xp(float(point.x())), yp(float(point.y())) {}
|
||||
Q_DECL_CONSTEXPR inline QVector2D::QVector2D(const QPointF& point) : v{float(point.x()), float(point.y())} {}
|
||||
|
||||
inline bool QVector2D::isNull() const
|
||||
{
|
||||
return qIsNull(xp) && qIsNull(yp);
|
||||
return qIsNull(v[0]) && qIsNull(v[1]);
|
||||
}
|
||||
|
||||
Q_DECL_CONSTEXPR inline float QVector2D::x() const { return xp; }
|
||||
Q_DECL_CONSTEXPR inline float QVector2D::y() const { return yp; }
|
||||
Q_DECL_CONSTEXPR inline float QVector2D::x() const { return v[0]; }
|
||||
Q_DECL_CONSTEXPR inline float QVector2D::y() const { return v[1]; }
|
||||
|
||||
inline void QVector2D::setX(float aX) { xp = aX; }
|
||||
inline void QVector2D::setY(float aY) { yp = aY; }
|
||||
inline void QVector2D::setX(float aX) { v[0] = aX; }
|
||||
inline void QVector2D::setY(float aY) { v[1] = aY; }
|
||||
|
||||
inline float &QVector2D::operator[](int i)
|
||||
{
|
||||
Q_ASSERT(uint(i) < 2u);
|
||||
return *(&xp + i);
|
||||
return v[i];
|
||||
}
|
||||
|
||||
inline float QVector2D::operator[](int i) const
|
||||
{
|
||||
Q_ASSERT(uint(i) < 2u);
|
||||
return *(&xp + i);
|
||||
return v[i];
|
||||
}
|
||||
|
||||
inline QVector2D &QVector2D::operator+=(const QVector2D &vector)
|
||||
{
|
||||
xp += vector.xp;
|
||||
yp += vector.yp;
|
||||
v[0] += vector.v[0];
|
||||
v[1] += vector.v[1];
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline QVector2D &QVector2D::operator-=(const QVector2D &vector)
|
||||
{
|
||||
xp -= vector.xp;
|
||||
yp -= vector.yp;
|
||||
v[0] -= vector.v[0];
|
||||
v[1] -= vector.v[1];
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline QVector2D &QVector2D::operator*=(float factor)
|
||||
{
|
||||
xp *= factor;
|
||||
yp *= factor;
|
||||
v[0] *= factor;
|
||||
v[1] *= factor;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline QVector2D &QVector2D::operator*=(const QVector2D &vector)
|
||||
{
|
||||
xp *= vector.xp;
|
||||
yp *= vector.yp;
|
||||
v[0] *= vector.v[0];
|
||||
v[1] *= vector.v[1];
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline QVector2D &QVector2D::operator/=(float divisor)
|
||||
{
|
||||
xp /= divisor;
|
||||
yp /= divisor;
|
||||
v[0] /= divisor;
|
||||
v[1] /= divisor;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline QVector2D &QVector2D::operator/=(const QVector2D &vector)
|
||||
{
|
||||
xp /= vector.xp;
|
||||
yp /= vector.yp;
|
||||
v[0] /= vector.v[0];
|
||||
v[1] /= vector.v[1];
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -209,68 +209,68 @@ QT_WARNING_DISABLE_CLANG("-Wfloat-equal")
|
||||
QT_WARNING_DISABLE_GCC("-Wfloat-equal")
|
||||
Q_DECL_CONSTEXPR inline bool operator==(const QVector2D &v1, const QVector2D &v2)
|
||||
{
|
||||
return v1.xp == v2.xp && v1.yp == v2.yp;
|
||||
return v1.v[0] == v2.v[0] && v1.v[1] == v2.v[1];
|
||||
}
|
||||
|
||||
Q_DECL_CONSTEXPR inline bool operator!=(const QVector2D &v1, const QVector2D &v2)
|
||||
{
|
||||
return v1.xp != v2.xp || v1.yp != v2.yp;
|
||||
return v1.v[0] != v2.v[0] || v1.v[1] != v2.v[1];
|
||||
}
|
||||
QT_WARNING_POP
|
||||
|
||||
Q_DECL_CONSTEXPR inline const QVector2D operator+(const QVector2D &v1, const QVector2D &v2)
|
||||
{
|
||||
return QVector2D(v1.xp + v2.xp, v1.yp + v2.yp);
|
||||
return QVector2D(v1.v[0] + v2.v[0], v1.v[1] + v2.v[1]);
|
||||
}
|
||||
|
||||
Q_DECL_CONSTEXPR inline const QVector2D operator-(const QVector2D &v1, const QVector2D &v2)
|
||||
{
|
||||
return QVector2D(v1.xp - v2.xp, v1.yp - v2.yp);
|
||||
return QVector2D(v1.v[0] - v2.v[0], v1.v[1] - v2.v[1]);
|
||||
}
|
||||
|
||||
Q_DECL_CONSTEXPR inline const QVector2D operator*(float factor, const QVector2D &vector)
|
||||
{
|
||||
return QVector2D(vector.xp * factor, vector.yp * factor);
|
||||
return QVector2D(vector.v[0] * factor, vector.v[1] * factor);
|
||||
}
|
||||
|
||||
Q_DECL_CONSTEXPR inline const QVector2D operator*(const QVector2D &vector, float factor)
|
||||
{
|
||||
return QVector2D(vector.xp * factor, vector.yp * factor);
|
||||
return QVector2D(vector.v[0] * factor, vector.v[1] * factor);
|
||||
}
|
||||
|
||||
Q_DECL_CONSTEXPR inline const QVector2D operator*(const QVector2D &v1, const QVector2D &v2)
|
||||
{
|
||||
return QVector2D(v1.xp * v2.xp, v1.yp * v2.yp);
|
||||
return QVector2D(v1.v[0] * v2.v[0], v1.v[1] * v2.v[1]);
|
||||
}
|
||||
|
||||
Q_DECL_CONSTEXPR inline const QVector2D operator-(const QVector2D &vector)
|
||||
{
|
||||
return QVector2D(-vector.xp, -vector.yp);
|
||||
return QVector2D(-vector.v[0], -vector.v[1]);
|
||||
}
|
||||
|
||||
Q_DECL_CONSTEXPR inline const QVector2D operator/(const QVector2D &vector, float divisor)
|
||||
{
|
||||
return QVector2D(vector.xp / divisor, vector.yp / divisor);
|
||||
return QVector2D(vector.v[0] / divisor, vector.v[1] / divisor);
|
||||
}
|
||||
|
||||
Q_DECL_CONSTEXPR inline const QVector2D operator/(const QVector2D &vector, const QVector2D &divisor)
|
||||
{
|
||||
return QVector2D(vector.xp / divisor.xp, vector.yp / divisor.yp);
|
||||
return QVector2D(vector.v[0] / divisor.v[0], vector.v[1] / divisor.v[1]);
|
||||
}
|
||||
|
||||
Q_DECL_CONSTEXPR inline bool qFuzzyCompare(const QVector2D& v1, const QVector2D& v2)
|
||||
{
|
||||
return qFuzzyCompare(v1.xp, v2.xp) && qFuzzyCompare(v1.yp, v2.yp);
|
||||
return qFuzzyCompare(v1.v[0], v2.v[0]) && qFuzzyCompare(v1.v[1], v2.v[1]);
|
||||
}
|
||||
|
||||
Q_DECL_CONSTEXPR inline QPoint QVector2D::toPoint() const
|
||||
{
|
||||
return QPoint(qRound(xp), qRound(yp));
|
||||
return QPoint(qRound(v[0]), qRound(v[1]));
|
||||
}
|
||||
|
||||
Q_DECL_CONSTEXPR inline QPointF QVector2D::toPointF() const
|
||||
{
|
||||
return QPointF(qreal(xp), qreal(yp));
|
||||
return QPointF(qreal(v[0]), qreal(v[1]));
|
||||
}
|
||||
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
|
@ -51,6 +51,41 @@ QT_BEGIN_NAMESPACE
|
||||
|
||||
#ifndef QT_NO_VECTOR3D
|
||||
|
||||
Q_STATIC_ASSERT_X(std::is_standard_layout<QVector3D>::value, "QVector3D is supposed to be standard layout");
|
||||
Q_STATIC_ASSERT_X(sizeof(QVector3D) == sizeof(float) * 3, "QVector3D is not supposed to have padding at the end");
|
||||
|
||||
// QVector3D used to be defined as class QVector3D { float x, y, z; };,
|
||||
// now instead it is defined as classs QVector3D { float v[3]; };.
|
||||
// Check that binary compatibility is preserved.
|
||||
// ### Qt 6: remove all of these checks.
|
||||
|
||||
namespace {
|
||||
|
||||
struct QVector3DOld
|
||||
{
|
||||
float x, y, z;
|
||||
};
|
||||
|
||||
struct QVector3DNew
|
||||
{
|
||||
float v[3];
|
||||
};
|
||||
|
||||
Q_STATIC_ASSERT_X(std::is_standard_layout<QVector3DOld>::value, "Binary compatibility break in QVector3D");
|
||||
Q_STATIC_ASSERT_X(std::is_standard_layout<QVector3DNew>::value, "Binary compatibility break in QVector3D");
|
||||
|
||||
Q_STATIC_ASSERT_X(sizeof(QVector3DOld) == sizeof(QVector3DNew), "Binary compatibility break in QVector3D");
|
||||
|
||||
// requires a constexpr offsetof
|
||||
#if !defined(Q_CC_MSVC) || (_MSC_VER >= 1910)
|
||||
Q_STATIC_ASSERT_X(offsetof(QVector3DOld, x) == offsetof(QVector3DNew, v) + sizeof(QVector3DNew::v[0]) * 0, "Binary compatibility break in QVector3D");
|
||||
Q_STATIC_ASSERT_X(offsetof(QVector3DOld, y) == offsetof(QVector3DNew, v) + sizeof(QVector3DNew::v[0]) * 1, "Binary compatibility break in QVector3D");
|
||||
Q_STATIC_ASSERT_X(offsetof(QVector3DOld, z) == offsetof(QVector3DNew, v) + sizeof(QVector3DNew::v[0]) * 2, "Binary compatibility break in QVector3D");
|
||||
#endif
|
||||
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
/*!
|
||||
\class QVector3D
|
||||
\brief The QVector3D class represents a vector or vertex in 3D space.
|
||||
@ -112,9 +147,9 @@ QT_BEGIN_NAMESPACE
|
||||
*/
|
||||
QVector3D::QVector3D(const QVector2D& vector)
|
||||
{
|
||||
xp = vector.xp;
|
||||
yp = vector.yp;
|
||||
zp = 0.0f;
|
||||
v[0] = vector.v[0];
|
||||
v[1] = vector.v[1];
|
||||
v[2] = 0.0f;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -125,9 +160,9 @@ QVector3D::QVector3D(const QVector2D& vector)
|
||||
*/
|
||||
QVector3D::QVector3D(const QVector2D& vector, float zpos)
|
||||
{
|
||||
xp = vector.xp;
|
||||
yp = vector.yp;
|
||||
zp = zpos;
|
||||
v[0] = vector.v[0];
|
||||
v[1] = vector.v[1];
|
||||
v[2] = zpos;
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -142,9 +177,9 @@ QVector3D::QVector3D(const QVector2D& vector, float zpos)
|
||||
*/
|
||||
QVector3D::QVector3D(const QVector4D& vector)
|
||||
{
|
||||
xp = vector.xp;
|
||||
yp = vector.yp;
|
||||
zp = vector.zp;
|
||||
v[0] = vector.v[0];
|
||||
v[1] = vector.v[1];
|
||||
v[2] = vector.v[2];
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -235,16 +270,16 @@ QVector3D::QVector3D(const QVector4D& vector)
|
||||
QVector3D QVector3D::normalized() const
|
||||
{
|
||||
// Need some extra precision if the length is very small.
|
||||
double len = double(xp) * double(xp) +
|
||||
double(yp) * double(yp) +
|
||||
double(zp) * double(zp);
|
||||
double len = double(v[0]) * double(v[0]) +
|
||||
double(v[1]) * double(v[1]) +
|
||||
double(v[2]) * double(v[2]);
|
||||
if (qFuzzyIsNull(len - 1.0f)) {
|
||||
return *this;
|
||||
} else if (!qFuzzyIsNull(len)) {
|
||||
double sqrtLen = std::sqrt(len);
|
||||
return QVector3D(float(double(xp) / sqrtLen),
|
||||
float(double(yp) / sqrtLen),
|
||||
float(double(zp) / sqrtLen));
|
||||
return QVector3D(float(double(v[0]) / sqrtLen),
|
||||
float(double(v[1]) / sqrtLen),
|
||||
float(double(v[2]) / sqrtLen));
|
||||
} else {
|
||||
return QVector3D();
|
||||
}
|
||||
@ -259,17 +294,17 @@ QVector3D QVector3D::normalized() const
|
||||
void QVector3D::normalize()
|
||||
{
|
||||
// Need some extra precision if the length is very small.
|
||||
double len = double(xp) * double(xp) +
|
||||
double(yp) * double(yp) +
|
||||
double(zp) * double(zp);
|
||||
double len = double(v[0]) * double(v[0]) +
|
||||
double(v[1]) * double(v[1]) +
|
||||
double(v[2]) * double(v[2]);
|
||||
if (qFuzzyIsNull(len - 1.0f) || qFuzzyIsNull(len))
|
||||
return;
|
||||
|
||||
len = std::sqrt(len);
|
||||
|
||||
xp = float(double(xp) / len);
|
||||
yp = float(double(yp) / len);
|
||||
zp = float(double(zp) / len);
|
||||
v[0] = float(double(v[0]) / len);
|
||||
v[1] = float(double(v[1]) / len);
|
||||
v[2] = float(double(v[2]) / len);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -336,7 +371,7 @@ void QVector3D::normalize()
|
||||
*/
|
||||
float QVector3D::dotProduct(const QVector3D& v1, const QVector3D& v2)
|
||||
{
|
||||
return v1.xp * v2.xp + v1.yp * v2.yp + v1.zp * v2.zp;
|
||||
return v1.v[0] * v2.v[0] + v1.v[1] * v2.v[1] + v1.v[2] * v2.v[2];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -347,9 +382,9 @@ float QVector3D::dotProduct(const QVector3D& v1, const QVector3D& v2)
|
||||
*/
|
||||
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);
|
||||
return QVector3D(v1.v[1] * v2.v[2] - v1.v[2] * v2.v[1],
|
||||
v1.v[2] * v2.v[0] - v1.v[0] * v2.v[2],
|
||||
v1.v[0] * v2.v[1] - v1.v[1] * v2.v[0]);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -629,7 +664,7 @@ float QVector3D::distanceToLine
|
||||
*/
|
||||
QVector2D QVector3D::toVector2D() const
|
||||
{
|
||||
return QVector2D(xp, yp);
|
||||
return QVector2D(v[0], v[1]);
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -643,7 +678,7 @@ QVector2D QVector3D::toVector2D() const
|
||||
*/
|
||||
QVector4D QVector3D::toVector4D() const
|
||||
{
|
||||
return QVector4D(xp, yp, zp, 0.0f);
|
||||
return QVector4D(v[0], v[1], v[2], 0.0f);
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -682,9 +717,9 @@ QVector3D::operator QVariant() const
|
||||
float QVector3D::length() const
|
||||
{
|
||||
// Need some extra precision if the length is very small.
|
||||
double len = double(xp) * double(xp) +
|
||||
double(yp) * double(yp) +
|
||||
double(zp) * double(zp);
|
||||
double len = double(v[0]) * double(v[0]) +
|
||||
double(v[1]) * double(v[1]) +
|
||||
double(v[2]) * double(v[2]);
|
||||
return float(std::sqrt(len));
|
||||
}
|
||||
|
||||
@ -696,7 +731,7 @@ float QVector3D::length() const
|
||||
*/
|
||||
float QVector3D::lengthSquared() const
|
||||
{
|
||||
return xp * xp + yp * yp + zp * zp;
|
||||
return v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
|
||||
}
|
||||
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
|
@ -59,7 +59,7 @@ class Q_GUI_EXPORT QVector3D
|
||||
public:
|
||||
Q_DECL_CONSTEXPR QVector3D();
|
||||
explicit QVector3D(Qt::Initialization) {}
|
||||
Q_DECL_CONSTEXPR QVector3D(float xpos, float ypos, float zpos) : xp(xpos), yp(ypos), zp(zpos) {}
|
||||
Q_DECL_CONSTEXPR QVector3D(float xpos, float ypos, float zpos) : v{xpos, ypos, zpos} {}
|
||||
|
||||
Q_DECL_CONSTEXPR explicit QVector3D(const QPoint& point);
|
||||
Q_DECL_CONSTEXPR explicit QVector3D(const QPointF& point);
|
||||
@ -138,7 +138,7 @@ public:
|
||||
operator QVariant() const;
|
||||
|
||||
private:
|
||||
float xp, yp, zp;
|
||||
float v[3];
|
||||
|
||||
friend class QVector2D;
|
||||
friend class QVector4D;
|
||||
@ -150,82 +150,82 @@ private:
|
||||
|
||||
Q_DECLARE_TYPEINFO(QVector3D, Q_PRIMITIVE_TYPE);
|
||||
|
||||
Q_DECL_CONSTEXPR inline QVector3D::QVector3D() : xp(0.0f), yp(0.0f), zp(0.0f) {}
|
||||
Q_DECL_CONSTEXPR inline QVector3D::QVector3D() : v{0.0f, 0.0f, 0.0f} {}
|
||||
|
||||
Q_DECL_CONSTEXPR inline QVector3D::QVector3D(const QPoint& point) : xp(point.x()), yp(point.y()), zp(0.0f) {}
|
||||
Q_DECL_CONSTEXPR inline QVector3D::QVector3D(const QPoint& point) : v{float(point.x()), float(point.y()), float(0.0f)} {}
|
||||
|
||||
Q_DECL_CONSTEXPR inline QVector3D::QVector3D(const QPointF& point) : xp(float(point.x())), yp(float(point.y())), zp(0.0f) {}
|
||||
Q_DECL_CONSTEXPR inline QVector3D::QVector3D(const QPointF& point) : v{float(point.x()), float(point.y()), 0.0f} {}
|
||||
|
||||
inline bool QVector3D::isNull() const
|
||||
{
|
||||
return qIsNull(xp) && qIsNull(yp) && qIsNull(zp);
|
||||
return qIsNull(v[0]) && qIsNull(v[1]) && qIsNull(v[2]);
|
||||
}
|
||||
|
||||
Q_DECL_CONSTEXPR inline float QVector3D::x() const { return xp; }
|
||||
Q_DECL_CONSTEXPR inline float QVector3D::y() const { return yp; }
|
||||
Q_DECL_CONSTEXPR inline float QVector3D::z() const { return zp; }
|
||||
Q_DECL_CONSTEXPR inline float QVector3D::x() const { return v[0]; }
|
||||
Q_DECL_CONSTEXPR inline float QVector3D::y() const { return v[1]; }
|
||||
Q_DECL_CONSTEXPR inline float QVector3D::z() const { return v[2]; }
|
||||
|
||||
inline void QVector3D::setX(float aX) { xp = aX; }
|
||||
inline void QVector3D::setY(float aY) { yp = aY; }
|
||||
inline void QVector3D::setZ(float aZ) { zp = aZ; }
|
||||
inline void QVector3D::setX(float aX) { v[0] = aX; }
|
||||
inline void QVector3D::setY(float aY) { v[1] = aY; }
|
||||
inline void QVector3D::setZ(float aZ) { v[2] = aZ; }
|
||||
|
||||
inline float &QVector3D::operator[](int i)
|
||||
{
|
||||
Q_ASSERT(uint(i) < 3u);
|
||||
return *(&xp + i);
|
||||
return v[i];
|
||||
}
|
||||
|
||||
inline float QVector3D::operator[](int i) const
|
||||
{
|
||||
Q_ASSERT(uint(i) < 3u);
|
||||
return *(&xp + i);
|
||||
return v[i];
|
||||
}
|
||||
|
||||
inline QVector3D &QVector3D::operator+=(const QVector3D &vector)
|
||||
{
|
||||
xp += vector.xp;
|
||||
yp += vector.yp;
|
||||
zp += vector.zp;
|
||||
v[0] += vector.v[0];
|
||||
v[1] += vector.v[1];
|
||||
v[2] += vector.v[2];
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline QVector3D &QVector3D::operator-=(const QVector3D &vector)
|
||||
{
|
||||
xp -= vector.xp;
|
||||
yp -= vector.yp;
|
||||
zp -= vector.zp;
|
||||
v[0] -= vector.v[0];
|
||||
v[1] -= vector.v[1];
|
||||
v[2] -= vector.v[2];
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline QVector3D &QVector3D::operator*=(float factor)
|
||||
{
|
||||
xp *= factor;
|
||||
yp *= factor;
|
||||
zp *= factor;
|
||||
v[0] *= factor;
|
||||
v[1] *= factor;
|
||||
v[2] *= factor;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline QVector3D &QVector3D::operator*=(const QVector3D& vector)
|
||||
{
|
||||
xp *= vector.xp;
|
||||
yp *= vector.yp;
|
||||
zp *= vector.zp;
|
||||
v[0] *= vector.v[0];
|
||||
v[1] *= vector.v[1];
|
||||
v[2] *= vector.v[2];
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline QVector3D &QVector3D::operator/=(float divisor)
|
||||
{
|
||||
xp /= divisor;
|
||||
yp /= divisor;
|
||||
zp /= divisor;
|
||||
v[0] /= divisor;
|
||||
v[1] /= divisor;
|
||||
v[2] /= divisor;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline QVector3D &QVector3D::operator/=(const QVector3D &vector)
|
||||
{
|
||||
xp /= vector.xp;
|
||||
yp /= vector.yp;
|
||||
zp /= vector.zp;
|
||||
v[0] /= vector.v[0];
|
||||
v[1] /= vector.v[1];
|
||||
v[2] /= vector.v[2];
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -234,70 +234,70 @@ QT_WARNING_DISABLE_CLANG("-Wfloat-equal")
|
||||
QT_WARNING_DISABLE_GCC("-Wfloat-equal")
|
||||
Q_DECL_CONSTEXPR inline bool operator==(const QVector3D &v1, const QVector3D &v2)
|
||||
{
|
||||
return v1.xp == v2.xp && v1.yp == v2.yp && v1.zp == v2.zp;
|
||||
return v1.v[0] == v2.v[0] && v1.v[1] == v2.v[1] && v1.v[2] == v2.v[2];
|
||||
}
|
||||
|
||||
Q_DECL_CONSTEXPR inline bool operator!=(const QVector3D &v1, const QVector3D &v2)
|
||||
{
|
||||
return v1.xp != v2.xp || v1.yp != v2.yp || v1.zp != v2.zp;
|
||||
return v1.v[0] != v2.v[0] || v1.v[1] != v2.v[1] || v1.v[2] != v2.v[2];
|
||||
}
|
||||
QT_WARNING_POP
|
||||
|
||||
Q_DECL_CONSTEXPR inline const QVector3D operator+(const QVector3D &v1, const QVector3D &v2)
|
||||
{
|
||||
return QVector3D(v1.xp + v2.xp, v1.yp + v2.yp, v1.zp + v2.zp);
|
||||
return QVector3D(v1.v[0] + v2.v[0], v1.v[1] + v2.v[1], v1.v[2] + v2.v[2]);
|
||||
}
|
||||
|
||||
Q_DECL_CONSTEXPR inline const QVector3D operator-(const QVector3D &v1, const QVector3D &v2)
|
||||
{
|
||||
return QVector3D(v1.xp - v2.xp, v1.yp - v2.yp, v1.zp - v2.zp);
|
||||
return QVector3D(v1.v[0] - v2.v[0], v1.v[1] - v2.v[1], v1.v[2] - v2.v[2]);
|
||||
}
|
||||
|
||||
Q_DECL_CONSTEXPR inline const QVector3D operator*(float factor, const QVector3D &vector)
|
||||
{
|
||||
return QVector3D(vector.xp * factor, vector.yp * factor, vector.zp * factor);
|
||||
return QVector3D(vector.v[0] * factor, vector.v[1] * factor, vector.v[2] * factor);
|
||||
}
|
||||
|
||||
Q_DECL_CONSTEXPR inline const QVector3D operator*(const QVector3D &vector, float factor)
|
||||
{
|
||||
return QVector3D(vector.xp * factor, vector.yp * factor, vector.zp * factor);
|
||||
return QVector3D(vector.v[0] * factor, vector.v[1] * factor, vector.v[2] * factor);
|
||||
}
|
||||
|
||||
Q_DECL_CONSTEXPR inline const QVector3D operator*(const QVector3D &v1, const QVector3D& v2)
|
||||
{
|
||||
return QVector3D(v1.xp * v2.xp, v1.yp * v2.yp, v1.zp * v2.zp);
|
||||
return QVector3D(v1.v[0] * v2.v[0], v1.v[1] * v2.v[1], v1.v[2] * v2.v[2]);
|
||||
}
|
||||
|
||||
Q_DECL_CONSTEXPR inline const QVector3D operator-(const QVector3D &vector)
|
||||
{
|
||||
return QVector3D(-vector.xp, -vector.yp, -vector.zp);
|
||||
return QVector3D(-vector.v[0], -vector.v[1], -vector.v[2]);
|
||||
}
|
||||
|
||||
Q_DECL_CONSTEXPR inline const QVector3D operator/(const QVector3D &vector, float divisor)
|
||||
{
|
||||
return QVector3D(vector.xp / divisor, vector.yp / divisor, vector.zp / divisor);
|
||||
return QVector3D(vector.v[0] / divisor, vector.v[1] / divisor, vector.v[2] / divisor);
|
||||
}
|
||||
|
||||
Q_DECL_CONSTEXPR inline const QVector3D operator/(const QVector3D &vector, const QVector3D &divisor)
|
||||
{
|
||||
return QVector3D(vector.xp / divisor.xp, vector.yp / divisor.yp, vector.zp / divisor.zp);
|
||||
return QVector3D(vector.v[0] / divisor.v[0], vector.v[1] / divisor.v[1], vector.v[2] / divisor.v[2]);
|
||||
}
|
||||
|
||||
Q_DECL_CONSTEXPR 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);
|
||||
return qFuzzyCompare(v1.v[0], v2.v[0]) &&
|
||||
qFuzzyCompare(v1.v[1], v2.v[1]) &&
|
||||
qFuzzyCompare(v1.v[2], v2.v[2]);
|
||||
}
|
||||
|
||||
Q_DECL_CONSTEXPR inline QPoint QVector3D::toPoint() const
|
||||
{
|
||||
return QPoint(qRound(xp), qRound(yp));
|
||||
return QPoint(qRound(v[0]), qRound(v[1]));
|
||||
}
|
||||
|
||||
Q_DECL_CONSTEXPR inline QPointF QVector3D::toPointF() const
|
||||
{
|
||||
return QPointF(qreal(xp), qreal(yp));
|
||||
return QPointF(qreal(v[0]), qreal(v[1]));
|
||||
}
|
||||
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
|
@ -49,6 +49,42 @@ QT_BEGIN_NAMESPACE
|
||||
|
||||
#ifndef QT_NO_VECTOR4D
|
||||
|
||||
Q_STATIC_ASSERT_X(std::is_standard_layout<QVector4D>::value, "QVector4D is supposed to be standard layout");
|
||||
Q_STATIC_ASSERT_X(sizeof(QVector4D) == sizeof(float) * 4, "QVector4D is not supposed to have padding at the end");
|
||||
|
||||
// QVector4D used to be defined as class QVector4D { float x, y, z, w; };,
|
||||
// now instead it is defined as classs QVector4D { float v[4]; };.
|
||||
// Check that binary compatibility is preserved.
|
||||
// ### Qt 6: remove all of these checks.
|
||||
|
||||
namespace {
|
||||
|
||||
struct QVector4DOld
|
||||
{
|
||||
float x, y, z, w;
|
||||
};
|
||||
|
||||
struct QVector4DNew
|
||||
{
|
||||
float v[4];
|
||||
};
|
||||
|
||||
Q_STATIC_ASSERT_X(std::is_standard_layout<QVector4DOld>::value, "Binary compatibility break in QVector4D");
|
||||
Q_STATIC_ASSERT_X(std::is_standard_layout<QVector4DNew>::value, "Binary compatibility break in QVector4D");
|
||||
|
||||
Q_STATIC_ASSERT_X(sizeof(QVector4DOld) == sizeof(QVector4DNew), "Binary compatibility break in QVector4D");
|
||||
|
||||
// requires a constexpr offsetof
|
||||
#if !defined(Q_CC_MSVC) || (_MSC_VER >= 1910)
|
||||
Q_STATIC_ASSERT_X(offsetof(QVector4DOld, x) == offsetof(QVector4DNew, v) + sizeof(QVector4DNew::v[0]) * 0, "Binary compatibility break in QVector4D");
|
||||
Q_STATIC_ASSERT_X(offsetof(QVector4DOld, y) == offsetof(QVector4DNew, v) + sizeof(QVector4DNew::v[0]) * 1, "Binary compatibility break in QVector4D");
|
||||
Q_STATIC_ASSERT_X(offsetof(QVector4DOld, z) == offsetof(QVector4DNew, v) + sizeof(QVector4DNew::v[0]) * 2, "Binary compatibility break in QVector4D");
|
||||
Q_STATIC_ASSERT_X(offsetof(QVector4DOld, w) == offsetof(QVector4DNew, v) + sizeof(QVector4DNew::v[0]) * 3, "Binary compatibility break in QVector4D");
|
||||
#endif
|
||||
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
/*!
|
||||
\class QVector4D
|
||||
\brief The QVector4D class represents a vector or vertex in 4D space.
|
||||
@ -106,10 +142,10 @@ QT_BEGIN_NAMESPACE
|
||||
*/
|
||||
QVector4D::QVector4D(const QVector2D& vector)
|
||||
{
|
||||
xp = vector.xp;
|
||||
yp = vector.yp;
|
||||
zp = 0.0f;
|
||||
wp = 0.0f;
|
||||
v[0] = vector.v[0];
|
||||
v[1] = vector.v[1];
|
||||
v[2] = 0.0f;
|
||||
v[3] = 0.0f;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -120,10 +156,10 @@ QVector4D::QVector4D(const QVector2D& vector)
|
||||
*/
|
||||
QVector4D::QVector4D(const QVector2D& vector, float zpos, float wpos)
|
||||
{
|
||||
xp = vector.xp;
|
||||
yp = vector.yp;
|
||||
zp = zpos;
|
||||
wp = wpos;
|
||||
v[0] = vector.v[0];
|
||||
v[1] = vector.v[1];
|
||||
v[2] = zpos;
|
||||
v[3] = wpos;
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -138,10 +174,10 @@ QVector4D::QVector4D(const QVector2D& vector, float zpos, float wpos)
|
||||
*/
|
||||
QVector4D::QVector4D(const QVector3D& vector)
|
||||
{
|
||||
xp = vector.xp;
|
||||
yp = vector.yp;
|
||||
zp = vector.zp;
|
||||
wp = 0.0f;
|
||||
v[0] = vector.v[0];
|
||||
v[1] = vector.v[1];
|
||||
v[2] = vector.v[2];
|
||||
v[3] = 0.0f;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -152,10 +188,10 @@ QVector4D::QVector4D(const QVector3D& vector)
|
||||
*/
|
||||
QVector4D::QVector4D(const QVector3D& vector, float wpos)
|
||||
{
|
||||
xp = vector.xp;
|
||||
yp = vector.yp;
|
||||
zp = vector.zp;
|
||||
wp = wpos;
|
||||
v[0] = vector.v[0];
|
||||
v[1] = vector.v[1];
|
||||
v[2] = vector.v[2];
|
||||
v[3] = wpos;
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -258,10 +294,10 @@ QVector4D::QVector4D(const QVector3D& vector, float wpos)
|
||||
float QVector4D::length() const
|
||||
{
|
||||
// Need some extra precision if the length is very small.
|
||||
double len = double(xp) * double(xp) +
|
||||
double(yp) * double(yp) +
|
||||
double(zp) * double(zp) +
|
||||
double(wp) * double(wp);
|
||||
double len = double(v[0]) * double(v[0]) +
|
||||
double(v[1]) * double(v[1]) +
|
||||
double(v[2]) * double(v[2]) +
|
||||
double(v[3]) * double(v[3]);
|
||||
return float(std::sqrt(len));
|
||||
}
|
||||
|
||||
@ -273,7 +309,7 @@ float QVector4D::length() const
|
||||
*/
|
||||
float QVector4D::lengthSquared() const
|
||||
{
|
||||
return xp * xp + yp * yp + zp * zp + wp * wp;
|
||||
return v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -288,18 +324,18 @@ float QVector4D::lengthSquared() const
|
||||
QVector4D QVector4D::normalized() const
|
||||
{
|
||||
// Need some extra precision if the length is very small.
|
||||
double len = double(xp) * double(xp) +
|
||||
double(yp) * double(yp) +
|
||||
double(zp) * double(zp) +
|
||||
double(wp) * double(wp);
|
||||
double len = double(v[0]) * double(v[0]) +
|
||||
double(v[1]) * double(v[1]) +
|
||||
double(v[2]) * double(v[2]) +
|
||||
double(v[3]) * double(v[3]);
|
||||
if (qFuzzyIsNull(len - 1.0f)) {
|
||||
return *this;
|
||||
} else if (!qFuzzyIsNull(len)) {
|
||||
double sqrtLen = std::sqrt(len);
|
||||
return QVector4D(float(double(xp) / sqrtLen),
|
||||
float(double(yp) / sqrtLen),
|
||||
float(double(zp) / sqrtLen),
|
||||
float(double(wp) / sqrtLen));
|
||||
return QVector4D(float(double(v[0]) / sqrtLen),
|
||||
float(double(v[1]) / sqrtLen),
|
||||
float(double(v[2]) / sqrtLen),
|
||||
float(double(v[3]) / sqrtLen));
|
||||
} else {
|
||||
return QVector4D();
|
||||
}
|
||||
@ -314,19 +350,19 @@ QVector4D QVector4D::normalized() const
|
||||
void QVector4D::normalize()
|
||||
{
|
||||
// Need some extra precision if the length is very small.
|
||||
double len = double(xp) * double(xp) +
|
||||
double(yp) * double(yp) +
|
||||
double(zp) * double(zp) +
|
||||
double(wp) * double(wp);
|
||||
double len = double(v[0]) * double(v[0]) +
|
||||
double(v[1]) * double(v[1]) +
|
||||
double(v[2]) * double(v[2]) +
|
||||
double(v[3]) * double(v[3]);
|
||||
if (qFuzzyIsNull(len - 1.0f) || qFuzzyIsNull(len))
|
||||
return;
|
||||
|
||||
len = std::sqrt(len);
|
||||
|
||||
xp = float(double(xp) / len);
|
||||
yp = float(double(yp) / len);
|
||||
zp = float(double(zp) / len);
|
||||
wp = float(double(wp) / len);
|
||||
v[0] = float(double(v[0]) / len);
|
||||
v[1] = float(double(v[1]) / len);
|
||||
v[2] = float(double(v[2]) / len);
|
||||
v[3] = float(double(v[3]) / len);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -387,7 +423,7 @@ void QVector4D::normalize()
|
||||
*/
|
||||
float QVector4D::dotProduct(const QVector4D& v1, const QVector4D& v2)
|
||||
{
|
||||
return v1.xp * v2.xp + v1.yp * v2.yp + v1.zp * v2.zp + v1.wp * v2.wp;
|
||||
return v1.v[0] * v2.v[0] + v1.v[1] * v2.v[1] + v1.v[2] * v2.v[2] + v1.v[3] * v2.v[3];
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -503,7 +539,7 @@ float QVector4D::dotProduct(const QVector4D& v1, const QVector4D& v2)
|
||||
*/
|
||||
QVector2D QVector4D::toVector2D() const
|
||||
{
|
||||
return QVector2D(xp, yp);
|
||||
return QVector2D(v[0], v[1]);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -515,9 +551,9 @@ QVector2D QVector4D::toVector2D() const
|
||||
*/
|
||||
QVector2D QVector4D::toVector2DAffine() const
|
||||
{
|
||||
if (qIsNull(wp))
|
||||
if (qIsNull(v[3]))
|
||||
return QVector2D();
|
||||
return QVector2D(xp / wp, yp / wp);
|
||||
return QVector2D(v[0] / v[3], v[1] / v[3]);
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -531,7 +567,7 @@ QVector2D QVector4D::toVector2DAffine() const
|
||||
*/
|
||||
QVector3D QVector4D::toVector3D() const
|
||||
{
|
||||
return QVector3D(xp, yp, zp);
|
||||
return QVector3D(v[0], v[1], v[2]);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -542,9 +578,9 @@ QVector3D QVector4D::toVector3D() const
|
||||
*/
|
||||
QVector3D QVector4D::toVector3DAffine() const
|
||||
{
|
||||
if (qIsNull(wp))
|
||||
if (qIsNull(v[3]))
|
||||
return QVector3D();
|
||||
return QVector3D(xp / wp, yp / wp, zp / wp);
|
||||
return QVector3D(v[0] / v[3], v[1] / v[3], v[2] / v[3]);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -128,7 +128,7 @@ public:
|
||||
operator QVariant() const;
|
||||
|
||||
private:
|
||||
float xp, yp, zp, wp;
|
||||
float v[4];
|
||||
|
||||
friend class QVector2D;
|
||||
friend class QVector3D;
|
||||
@ -140,92 +140,92 @@ private:
|
||||
|
||||
Q_DECLARE_TYPEINFO(QVector4D, Q_PRIMITIVE_TYPE);
|
||||
|
||||
Q_DECL_CONSTEXPR inline QVector4D::QVector4D() : xp(0.0f), yp(0.0f), zp(0.0f), wp(0.0f) {}
|
||||
Q_DECL_CONSTEXPR inline QVector4D::QVector4D() : v{0.0f, 0.0f, 0.0f, 0.0f} {}
|
||||
|
||||
Q_DECL_CONSTEXPR inline QVector4D::QVector4D(float xpos, float ypos, float zpos, float wpos) : xp(xpos), yp(ypos), zp(zpos), wp(wpos) {}
|
||||
Q_DECL_CONSTEXPR inline QVector4D::QVector4D(float xpos, float ypos, float zpos, float wpos) : v{xpos, ypos, zpos, wpos} {}
|
||||
|
||||
Q_DECL_CONSTEXPR inline QVector4D::QVector4D(const QPoint& point) : xp(point.x()), yp(point.y()), zp(0.0f), wp(0.0f) {}
|
||||
Q_DECL_CONSTEXPR inline QVector4D::QVector4D(const QPoint& point) : v{float(point.x()), float(point.y()), 0.0f, 0.0f} {}
|
||||
|
||||
Q_DECL_CONSTEXPR inline QVector4D::QVector4D(const QPointF& point) : xp(float(point.x())), yp(float(point.y())), zp(0.0f), wp(0.0f) {}
|
||||
Q_DECL_CONSTEXPR inline QVector4D::QVector4D(const QPointF& point) : v{float(point.x()), float(point.y()), 0.0f, 0.0f} {}
|
||||
|
||||
inline bool QVector4D::isNull() const
|
||||
{
|
||||
return qIsNull(xp) && qIsNull(yp) && qIsNull(zp) && qIsNull(wp);
|
||||
return qIsNull(v[0]) && qIsNull(v[1]) && qIsNull(v[2]) && qIsNull(v[3]);
|
||||
}
|
||||
|
||||
Q_DECL_CONSTEXPR inline float QVector4D::x() const { return xp; }
|
||||
Q_DECL_CONSTEXPR inline float QVector4D::y() const { return yp; }
|
||||
Q_DECL_CONSTEXPR inline float QVector4D::z() const { return zp; }
|
||||
Q_DECL_CONSTEXPR inline float QVector4D::w() const { return wp; }
|
||||
Q_DECL_CONSTEXPR inline float QVector4D::x() const { return v[0]; }
|
||||
Q_DECL_CONSTEXPR inline float QVector4D::y() const { return v[1]; }
|
||||
Q_DECL_CONSTEXPR inline float QVector4D::z() const { return v[2]; }
|
||||
Q_DECL_CONSTEXPR inline float QVector4D::w() const { return v[3]; }
|
||||
|
||||
inline void QVector4D::setX(float aX) { xp = aX; }
|
||||
inline void QVector4D::setY(float aY) { yp = aY; }
|
||||
inline void QVector4D::setZ(float aZ) { zp = aZ; }
|
||||
inline void QVector4D::setW(float aW) { wp = aW; }
|
||||
inline void QVector4D::setX(float aX) { v[0] = aX; }
|
||||
inline void QVector4D::setY(float aY) { v[1] = aY; }
|
||||
inline void QVector4D::setZ(float aZ) { v[2] = aZ; }
|
||||
inline void QVector4D::setW(float aW) { v[3] = aW; }
|
||||
|
||||
inline float &QVector4D::operator[](int i)
|
||||
{
|
||||
Q_ASSERT(uint(i) < 4u);
|
||||
return *(&xp + i);
|
||||
return v[i];
|
||||
}
|
||||
|
||||
inline float QVector4D::operator[](int i) const
|
||||
{
|
||||
Q_ASSERT(uint(i) < 4u);
|
||||
return *(&xp + i);
|
||||
return v[i];
|
||||
}
|
||||
|
||||
inline QVector4D &QVector4D::operator+=(const QVector4D &vector)
|
||||
{
|
||||
xp += vector.xp;
|
||||
yp += vector.yp;
|
||||
zp += vector.zp;
|
||||
wp += vector.wp;
|
||||
v[0] += vector.v[0];
|
||||
v[1] += vector.v[1];
|
||||
v[2] += vector.v[2];
|
||||
v[3] += vector.v[3];
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline QVector4D &QVector4D::operator-=(const QVector4D &vector)
|
||||
{
|
||||
xp -= vector.xp;
|
||||
yp -= vector.yp;
|
||||
zp -= vector.zp;
|
||||
wp -= vector.wp;
|
||||
v[0] -= vector.v[0];
|
||||
v[1] -= vector.v[1];
|
||||
v[2] -= vector.v[2];
|
||||
v[3] -= vector.v[3];
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline QVector4D &QVector4D::operator*=(float factor)
|
||||
{
|
||||
xp *= factor;
|
||||
yp *= factor;
|
||||
zp *= factor;
|
||||
wp *= factor;
|
||||
v[0] *= factor;
|
||||
v[1] *= factor;
|
||||
v[2] *= factor;
|
||||
v[3] *= factor;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline QVector4D &QVector4D::operator*=(const QVector4D &vector)
|
||||
{
|
||||
xp *= vector.xp;
|
||||
yp *= vector.yp;
|
||||
zp *= vector.zp;
|
||||
wp *= vector.wp;
|
||||
v[0] *= vector.v[0];
|
||||
v[1] *= vector.v[1];
|
||||
v[2] *= vector.v[2];
|
||||
v[3] *= vector.v[3];
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline QVector4D &QVector4D::operator/=(float divisor)
|
||||
{
|
||||
xp /= divisor;
|
||||
yp /= divisor;
|
||||
zp /= divisor;
|
||||
wp /= divisor;
|
||||
v[0] /= divisor;
|
||||
v[1] /= divisor;
|
||||
v[2] /= divisor;
|
||||
v[3] /= divisor;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline QVector4D &QVector4D::operator/=(const QVector4D &vector)
|
||||
{
|
||||
xp /= vector.xp;
|
||||
yp /= vector.yp;
|
||||
zp /= vector.zp;
|
||||
wp /= vector.wp;
|
||||
v[0] /= vector.v[0];
|
||||
v[1] /= vector.v[1];
|
||||
v[2] /= vector.v[2];
|
||||
v[3] /= vector.v[3];
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -234,71 +234,71 @@ QT_WARNING_DISABLE_CLANG("-Wfloat-equal")
|
||||
QT_WARNING_DISABLE_GCC("-Wfloat-equal")
|
||||
Q_DECL_CONSTEXPR 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;
|
||||
return v1.v[0] == v2.v[0] && v1.v[1] == v2.v[1] && v1.v[2] == v2.v[2] && v1.v[3] == v2.v[3];
|
||||
}
|
||||
|
||||
Q_DECL_CONSTEXPR 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;
|
||||
return v1.v[0] != v2.v[0] || v1.v[1] != v2.v[1] || v1.v[2] != v2.v[2] || v1.v[3] != v2.v[3];
|
||||
}
|
||||
QT_WARNING_POP
|
||||
|
||||
Q_DECL_CONSTEXPR 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);
|
||||
return QVector4D(v1.v[0] + v2.v[0], v1.v[1] + v2.v[1], v1.v[2] + v2.v[2], v1.v[3] + v2.v[3]);
|
||||
}
|
||||
|
||||
Q_DECL_CONSTEXPR 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);
|
||||
return QVector4D(v1.v[0] - v2.v[0], v1.v[1] - v2.v[1], v1.v[2] - v2.v[2], v1.v[3] - v2.v[3]);
|
||||
}
|
||||
|
||||
Q_DECL_CONSTEXPR inline const QVector4D operator*(float factor, const QVector4D &vector)
|
||||
{
|
||||
return QVector4D(vector.xp * factor, vector.yp * factor, vector.zp * factor, vector.wp * factor);
|
||||
return QVector4D(vector.v[0] * factor, vector.v[1] * factor, vector.v[2] * factor, vector.v[3] * factor);
|
||||
}
|
||||
|
||||
Q_DECL_CONSTEXPR inline const QVector4D operator*(const QVector4D &vector, float factor)
|
||||
{
|
||||
return QVector4D(vector.xp * factor, vector.yp * factor, vector.zp * factor, vector.wp * factor);
|
||||
return QVector4D(vector.v[0] * factor, vector.v[1] * factor, vector.v[2] * factor, vector.v[3] * factor);
|
||||
}
|
||||
|
||||
Q_DECL_CONSTEXPR 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);
|
||||
return QVector4D(v1.v[0] * v2.v[0], v1.v[1] * v2.v[1], v1.v[2] * v2.v[2], v1.v[3] * v2.v[3]);
|
||||
}
|
||||
|
||||
Q_DECL_CONSTEXPR inline const QVector4D operator-(const QVector4D &vector)
|
||||
{
|
||||
return QVector4D(-vector.xp, -vector.yp, -vector.zp, -vector.wp);
|
||||
return QVector4D(-vector.v[0], -vector.v[1], -vector.v[2], -vector.v[3]);
|
||||
}
|
||||
|
||||
Q_DECL_CONSTEXPR inline const QVector4D operator/(const QVector4D &vector, float divisor)
|
||||
{
|
||||
return QVector4D(vector.xp / divisor, vector.yp / divisor, vector.zp / divisor, vector.wp / divisor);
|
||||
return QVector4D(vector.v[0] / divisor, vector.v[1] / divisor, vector.v[2] / divisor, vector.v[3] / divisor);
|
||||
}
|
||||
|
||||
Q_DECL_CONSTEXPR inline const QVector4D operator/(const QVector4D &vector, const QVector4D &divisor)
|
||||
{
|
||||
return QVector4D(vector.xp / divisor.xp, vector.yp / divisor.yp, vector.zp / divisor.zp, vector.wp / divisor.wp);
|
||||
return QVector4D(vector.v[0] / divisor.v[0], vector.v[1] / divisor.v[1], vector.v[2] / divisor.v[2], vector.v[3] / divisor.v[3]);
|
||||
}
|
||||
|
||||
Q_DECL_CONSTEXPR 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);
|
||||
return qFuzzyCompare(v1.v[0], v2.v[0]) &&
|
||||
qFuzzyCompare(v1.v[1], v2.v[1]) &&
|
||||
qFuzzyCompare(v1.v[2], v2.v[2]) &&
|
||||
qFuzzyCompare(v1.v[3], v2.v[3]);
|
||||
}
|
||||
|
||||
Q_DECL_CONSTEXPR inline QPoint QVector4D::toPoint() const
|
||||
{
|
||||
return QPoint(qRound(xp), qRound(yp));
|
||||
return QPoint(qRound(v[0]), qRound(v[1]));
|
||||
}
|
||||
|
||||
Q_DECL_CONSTEXPR inline QPointF QVector4D::toPointF() const
|
||||
{
|
||||
return QPointF(qreal(xp), qreal(yp));
|
||||
return QPointF(qreal(v[0]), qreal(v[1]));
|
||||
}
|
||||
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
|
Loading…
Reference in New Issue
Block a user