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>
This commit is contained in:
parent
fdbf3bec30
commit
595ed595ea
@ -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
|
||||
|
||||
@ -358,6 +360,69 @@ QVector3D QVector3D::normal
|
||||
return crossProduct((v2 - v1), (v3 - v1)).normalized();
|
||||
}
|
||||
|
||||
/*!
|
||||
\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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user