summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Lemire <paul.lemire@kdab.com>2015-01-19 12:50:05 +0100
committerSean Harmer <sean.harmer@kdab.com>2015-01-22 12:39:20 +0100
commit595ed595eabe01a1cf11c8b846fd777de8233721 (patch)
treec23d42c57c16fe0df5ec5450f237512d8202e85a
parentfdbf3bec3009343362448141faa42734ec31b1c3 (diff)
Add project/unproject methods in QVector3D
Equivalent of gluProject and gluUnproject. [ChangeLog][QtCore][QVector3D] add convenience project and unproject methods to use like gluProject and gluUnproject Change-Id: I6e4e3e79ea6e34d1fb0c375e15185c950b699ef0 Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
-rw-r--r--src/gui/math3d/qvector3d.cpp65
-rw-r--r--src/gui/math3d/qvector3d.h4
-rw-r--r--tests/auto/gui/math3d/qvectornd/tst_qvectornd.cpp158
3 files changed, 227 insertions, 0 deletions
diff --git a/src/gui/math3d/qvector3d.cpp b/src/gui/math3d/qvector3d.cpp
index 75d61e5f85..014987b90d 100644
--- a/src/gui/math3d/qvector3d.cpp
+++ b/src/gui/math3d/qvector3d.cpp
@@ -34,10 +34,12 @@
#include "qvector3d.h"
#include "qvector2d.h"
#include "qvector4d.h"
+#include "qmatrix4x4.h"
#include <QtCore/qdatastream.h>
#include <QtCore/qmath.h>
#include <QtCore/qvariant.h>
#include <QtCore/qdebug.h>
+#include <QtCore/qrect.h>
QT_BEGIN_NAMESPACE
@@ -359,6 +361,69 @@ QVector3D QVector3D::normal
}
/*!
+ \since 5.5
+
+ Returns the window coordinates of this vector initially in object/model
+ coordinates using the model view matrix \a modelView, the projection matrix
+ \a projection and the viewport dimensions \a viewport.
+
+ When transforming from clip to normalized space, a division by the w
+ component on the vector components takes place. To prevent dividing by 0 if
+ w equals to 0, it is set to 1.
+
+ \note the returned y coordinates are in OpenGL orientation. OpenGL expects
+ the bottom to be 0 whereas for Qt top is 0.
+
+ \sa unproject()
+ */
+QVector3D QVector3D::project(const QMatrix4x4 &modelView, const QMatrix4x4 &projection, const QRect &viewport) const
+{
+ QVector4D tmp(*this, 1.0f);
+ tmp = projection * modelView * tmp;
+ if (qFuzzyIsNull(tmp.w()))
+ tmp.setW(1.0f);
+ tmp /= tmp.w();
+
+ tmp = tmp * 0.5f + QVector4D(0.5f, 0.5f, 0.5f, 0.5f);
+ tmp.setX(tmp.x() * viewport.width() + viewport.x());
+ tmp.setY(tmp.y() * viewport.height() + viewport.y());
+
+ return tmp.toVector3D();
+}
+
+/*!
+ \since 5.5
+
+ Returns the object/model coordinates of this vector initially in window
+ coordinates using the model view matrix \a modelView, the projection matrix
+ \a projection and the viewport dimensions \a viewport.
+
+ When transforming from clip to normalized space, a division by the w
+ component of the vector components takes place. To prevent dividing by 0 if
+ w equals to 0, it is set to 1.
+
+ \note y coordinates in \a point should use OpenGL orientation. OpenGL
+ expects the bottom to be 0 whereas for Qt top is 0.
+
+ \sa project()
+ */
+QVector3D QVector3D::unproject(const QMatrix4x4 &modelView, const QMatrix4x4 &projection, const QRect &viewport) const
+{
+ QMatrix4x4 inverse = QMatrix4x4( projection * modelView ).inverted();
+
+ QVector4D tmp(*this, 1.0f);
+ tmp.setX((tmp.x() - float(viewport.x())) / float(viewport.width()));
+ tmp.setY((tmp.y() - float(viewport.y())) / float(viewport.height()));
+ tmp = tmp * 2.0f - QVector4D(1.0f, 1.0f, 1.0f, 1.0f);
+
+ QVector4D obj = inverse * tmp;
+ if (qFuzzyIsNull(obj.w()))
+ obj.setW(1.0f);
+ obj /= obj.w();
+ return obj.toVector3D();
+}
+
+/*!
\since 5.1
Returns the distance from this vertex to a point defined by
diff --git a/src/gui/math3d/qvector3d.h b/src/gui/math3d/qvector3d.h
index 40e9035621..4c25451bab 100644
--- a/src/gui/math3d/qvector3d.h
+++ b/src/gui/math3d/qvector3d.h
@@ -43,6 +43,7 @@ QT_BEGIN_NAMESPACE
class QMatrix4x4;
class QVector2D;
class QVector4D;
+class QRect;
#ifndef QT_NO_VECTOR3D
@@ -94,6 +95,9 @@ public:
static QVector3D normal
(const QVector3D& v1, const QVector3D& v2, const QVector3D& v3);
+ QVector3D project(const QMatrix4x4 &modelView, const QMatrix4x4 &projection, const QRect &viewport) const;
+ QVector3D unproject(const QMatrix4x4 &modelView, const QMatrix4x4 &projection, const QRect &viewport) const;
+
float distanceToPoint(const QVector3D& point) const;
float distanceToPlane(const QVector3D& plane, const QVector3D& normal) const;
float distanceToPlane(const QVector3D& plane1, const QVector3D& plane2, const QVector3D& plane3) const;
diff --git a/tests/auto/gui/math3d/qvectornd/tst_qvectornd.cpp b/tests/auto/gui/math3d/qvectornd/tst_qvectornd.cpp
index 2d4b6d16b0..fa5d1b576f 100644
--- a/tests/auto/gui/math3d/qvectornd/tst_qvectornd.cpp
+++ b/tests/auto/gui/math3d/qvectornd/tst_qvectornd.cpp
@@ -36,6 +36,7 @@
#include <QtGui/qvector2d.h>
#include <QtGui/qvector3d.h>
#include <QtGui/qvector4d.h>
+#include <QtGui/qmatrix4x4.h>
class tst_QVectorND : public QObject
{
@@ -142,6 +143,11 @@ private slots:
void dotProduct4_data();
void dotProduct4();
+ void project_data();
+ void project();
+ void unproject_data();
+ void unproject();
+
void properties();
void metaTypes();
};
@@ -2291,6 +2297,158 @@ void tst_QVectorND::dotProduct4()
QCOMPARE(QVector4D::dotProduct(v1, v2), d);
}
+void tst_QVectorND::project_data()
+{
+ QTest::addColumn<QVector3D>("point");
+ QTest::addColumn<QRect>("viewport");
+ QTest::addColumn<QMatrix4x4>("projection");
+ QTest::addColumn<QMatrix4x4>("view");
+ QTest::addColumn<QVector2D>("result");
+
+ QMatrix4x4 projection;
+ projection.ortho(-1.0f, 1.0f, -1.0f, 1.0f, 0.1f, 1000.0f);
+
+ QMatrix4x4 view;
+ // Located at (0, 0, 10), looking at origin, y is up
+ view.lookAt(QVector3D(0.0f, 0.0f, 10.0f), QVector3D(0.0f, 0.0f, 0.0f), QVector3D(0.0f, 1.0f, 0.0f));
+
+ QMatrix4x4 nullMatrix(0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f);
+
+ QTest::newRow("center")
+ << QVector3D(0.0f, 0.0f, 0.0f)
+ << QRect(0.0f, 0.0f, 800.0f, 600.0f)
+ << projection
+ << view
+ << QVector2D(400.0f, 300.0f);
+
+ QTest::newRow("topLeft")
+ << QVector3D(-1.0f, 1.0f, 0.0f)
+ << QRect(0.0f, 0.0f, 800.0f, 600.0f)
+ << projection
+ << view
+ << QVector2D(0.0f, 600.0f);
+
+ QTest::newRow("topRight")
+ << QVector3D(1.0f, 1.0f, 0.0f)
+ << QRect(0.0f, 0.0f, 800.0f, 600.0f)
+ << projection
+ << view
+ << QVector2D(800.0f, 600.0f);
+
+ QTest::newRow("bottomLeft")
+ << QVector3D(-1.0f, -1.0f, 0.0f)
+ << QRect(0.0f, 0.0f, 800.0f, 600.0f)
+ << projection
+ << view
+ << QVector2D(0.0f, 0.0f);
+
+ QTest::newRow("bottomRight")
+ << QVector3D(1.0f, -1.0f, 0.0f)
+ << QRect(0.0f, 0.0f, 800.0f, 600.0f)
+ << projection
+ << view
+ << QVector2D(800.0f, 0.0f);
+
+ QTest::newRow("nullMatrix")
+ << QVector3D(0.0f, 0.0f, 0.0f)
+ << QRect(0.0f, 0.0f, 800.0f, 600.0f)
+ << nullMatrix
+ << nullMatrix
+ << QVector2D(400.0f, 300.0f);
+}
+
+void tst_QVectorND::project()
+{
+ QFETCH(QVector3D, point);
+ QFETCH(QRect, viewport);
+ QFETCH(QMatrix4x4, projection);
+ QFETCH(QMatrix4x4, view);
+ QFETCH(QVector2D, result);
+
+ QVector3D project = point.project(view, projection, viewport);
+
+ QCOMPARE(project.toVector2D(), result);
+}
+
+void tst_QVectorND::unproject_data()
+{
+ QTest::addColumn<QVector3D>("point");
+ QTest::addColumn<QRect>("viewport");
+ QTest::addColumn<QMatrix4x4>("projection");
+ QTest::addColumn<QMatrix4x4>("view");
+ QTest::addColumn<QVector3D>("result");
+
+ QMatrix4x4 projection;
+ projection.ortho(-1.0f, 1.0f, -1.0f, 1.0f, 0.1f, 1000.0f);
+
+ QMatrix4x4 view;
+ // Located at (0, 0, 10), looking at origin, y is up
+ view.lookAt(QVector3D(0.0f, 0.0f, 10.0f), QVector3D(0.0f, 0.0f, 0.0f), QVector3D(0.0f, 1.0f, 0.0f));
+
+ QMatrix4x4 nullMatrix(0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f);
+
+ QTest::newRow("center")
+ << QVector3D(400.0f, 300.0f, 0.0f)
+ << QRect(0.0f, 0.0f, 800.0f, 600.0f)
+ << projection
+ << view
+ << QVector3D(0.0f, 0.0f, 9.9f);
+
+ QTest::newRow("topLeft")
+ << QVector3D(0.0f, 600.0f, 0.0f)
+ << QRect(0.0f, 0.0f, 800.0f, 600.0f)
+ << projection
+ << view
+ << QVector3D(-1.0f, 1.0f, 9.9f);
+
+ QTest::newRow("topRight")
+ << QVector3D(800.0f, 600.0f, 0.0f)
+ << QRect(0.0f, 0.0f, 800.0f, 600.0f)
+ << projection
+ << view
+ << QVector3D(1.0f, 1.0f, 9.9f);
+
+ QTest::newRow("bottomLeft")
+ << QVector3D(0.0f, 0.0f, 0.0f)
+ << QRect(0.0f, 0.0f, 800.0f, 600.0f)
+ << projection
+ << view
+ << QVector3D(-1.0, -1.0f, 9.9f);
+
+ QTest::newRow("bottomRight")
+ << QVector3D(800.0f, 0.0f, 0.0f)
+ << QRect(0.0f, 0.0f, 800.0f, 600.0f)
+ << projection
+ << view
+ << QVector3D(1.0f, -1.0f, 9.9f);
+
+ QTest::newRow("nullMatrix")
+ << QVector3D(400.0f, 300.0f, 0.0f)
+ << QRect(0.0f, 0.0f, 800.0f, 600.0f)
+ << nullMatrix
+ << nullMatrix
+ << QVector3D(0.0f, 0.0f, -1.0f);
+
+}
+
+void tst_QVectorND::unproject()
+{
+ QFETCH(QVector3D, point);
+ QFETCH(QRect, viewport);
+ QFETCH(QMatrix4x4, projection);
+ QFETCH(QMatrix4x4, view);
+ QFETCH(QVector3D, result);
+
+ QVector3D unproject = point.unproject(view, projection, viewport);
+ QVERIFY(qFuzzyCompare(unproject, result));
+}
+
class tst_QVectorNDProperties : public QObject
{
Q_OBJECT