summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Krus <mike.krus@kdab.com>2017-02-17 23:14:27 +0000
committerMike Krus <mike.krus@kdab.com>2017-05-26 09:58:37 +0000
commitcd68b050998200584f2b6a5604a2538a27c77fbe (patch)
tree4db8138b0e4d27d57e1624c06530178580148d9d
parenta441bd7d3d83284f68f1d8addedc93989a18cfeb (diff)
Add support for line picking
PickingSettings can ask to get line as well as triangle picks. Introduces a radius value to compensate for numerical precision in ray-segment intersections. Introduces QPickLineEvent with the details about the picking. Job will perform line picking if appropriate. Hit encode the type of picking and this is used to generate the right type of event. Task-number: QTBUG-58071 Change-Id: I834e6cc08044a8cfb28bba7443034e05267aedbf Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
-rw-r--r--src/render/backend/rendersettings.cpp4
-rw-r--r--src/render/backend/rendersettings_p.h3
-rw-r--r--src/render/frontend/qpickingsettings.cpp33
-rw-r--r--src/render/frontend/qpickingsettings.h12
-rw-r--r--src/render/frontend/qpickingsettings_p.h1
-rw-r--r--src/render/frontend/qrendersettings.cpp9
-rw-r--r--src/render/frontend/qrendersettings.h1
-rw-r--r--src/render/frontend/qrendersettings_p.h2
-rw-r--r--src/render/jobs/pickboundingvolumejob.cpp56
-rw-r--r--src/render/jobs/pickboundingvolumejob_p.h1
-rw-r--r--src/render/jobs/pickboundingvolumeutils.cpp150
-rw-r--r--src/render/jobs/pickboundingvolumeutils_p.h10
-rw-r--r--src/render/picking/picking.pri2
-rw-r--r--src/render/picking/qpicklineevent.cpp173
-rw-r--r--src/render/picking/qpicklineevent.h75
-rw-r--r--src/render/raycasting/qcollisionqueryresult_p.h15
-rw-r--r--tests/auto/render/qrendersettings/tst_qrendersettings.cpp37
17 files changed, 561 insertions, 23 deletions
diff --git a/src/render/backend/rendersettings.cpp b/src/render/backend/rendersettings.cpp
index 2cd2b1d07..397d297e9 100644
--- a/src/render/backend/rendersettings.cpp
+++ b/src/render/backend/rendersettings.cpp
@@ -57,6 +57,7 @@ RenderSettings::RenderSettings()
, m_pickMethod(QPickingSettings::BoundingVolumePicking)
, m_pickResultMode(QPickingSettings::NearestPick)
, m_faceOrientationPickingMode(QPickingSettings::FrontFace)
+ , m_pickWorldSpaceTolerance(.1f)
, m_activeFrameGraph()
{
}
@@ -69,6 +70,7 @@ void RenderSettings::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePt
m_renderPolicy = data.renderPolicy;
m_pickMethod = data.pickMethod;
m_pickResultMode = data.pickResultMode;
+ m_pickWorldSpaceTolerance = data.pickWorldSpaceTolerance;
m_faceOrientationPickingMode = data.faceOrientationPickingMode;
}
@@ -82,6 +84,8 @@ void RenderSettings::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
m_pickResultMode = propertyChange->value().value<QPickingSettings::PickResultMode>();
else if (propertyChange->propertyName() == QByteArrayLiteral("faceOrientationPickingMode"))
m_faceOrientationPickingMode = propertyChange->value().value<QPickingSettings::FaceOrientationPickingMode>();
+ else if (propertyChange->propertyName() == QByteArrayLiteral("pickWorldSpaceTolerance"))
+ m_pickWorldSpaceTolerance = propertyChange->value().toFloat();
else if (propertyChange->propertyName() == QByteArrayLiteral("activeFrameGraph"))
m_activeFrameGraph = propertyChange->value().value<QNodeId>();
else if (propertyChange->propertyName() == QByteArrayLiteral("renderPolicy"))
diff --git a/src/render/backend/rendersettings_p.h b/src/render/backend/rendersettings_p.h
index 37771c40b..bfd2c21b2 100644
--- a/src/render/backend/rendersettings_p.h
+++ b/src/render/backend/rendersettings_p.h
@@ -74,7 +74,7 @@ public:
QPickingSettings::PickMethod pickMethod() const { return m_pickMethod; }
QPickingSettings::PickResultMode pickResultMode() const { return m_pickResultMode; }
QPickingSettings::FaceOrientationPickingMode faceOrientationPickingMode() const { return m_faceOrientationPickingMode; }
-
+ float pickWorldSpaceTolerance() const { return m_pickWorldSpaceTolerance; }
private:
void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL;
@@ -82,6 +82,7 @@ private:
QPickingSettings::PickMethod m_pickMethod;
QPickingSettings::PickResultMode m_pickResultMode;
QPickingSettings::FaceOrientationPickingMode m_faceOrientationPickingMode;
+ float m_pickWorldSpaceTolerance;
Qt3DCore::QNodeId m_activeFrameGraph;
};
diff --git a/src/render/frontend/qpickingsettings.cpp b/src/render/frontend/qpickingsettings.cpp
index 1cda638cb..b24d0b7d0 100644
--- a/src/render/frontend/qpickingsettings.cpp
+++ b/src/render/frontend/qpickingsettings.cpp
@@ -81,6 +81,7 @@ QPickingSettingsPrivate::QPickingSettingsPrivate()
, m_pickMethod(QPickingSettings::BoundingVolumePicking)
, m_pickResultMode(QPickingSettings::NearestPick)
, m_faceOrientationPickingMode(QPickingSettings::FrontFace)
+ , m_worldSpaceTolerance(.1f)
{
}
@@ -121,6 +122,15 @@ QPickingSettings::FaceOrientationPickingMode QPickingSettings::faceOrientationPi
}
/*!
+ * \return the line and point precision worldSpaceTolerance
+ */
+float QPickingSettings::worldSpaceTolerance() const
+{
+ Q_D(const QPickingSettings);
+ return d->m_worldSpaceTolerance;
+}
+
+/*!
* \enum Qt3DRender::QPickingSettings::PickMethod
*
* Specifies the picking method.
@@ -247,6 +257,29 @@ void QPickingSettings::setFaceOrientationPickingMode(QPickingSettings::FaceOrien
emit faceOrientationPickingModeChanged(faceOrientationPickingMode);
}
+/*!
+ \qmlproperty qreal worldSpaceTolerance
+
+ Holds the threshold, in model space coordinates, used to evaluate line and point picking.
+*/
+/*!
+ \property QPickingSettings::worldSpaceTolerance
+
+ Holds the threshold, in model space coordinates, used to evaluate line and point picking.
+*/
+/*!
+ * Set the threshold used for line and point picking
+ */
+void QPickingSettings::setWorldSpaceTolerance(float worldSpaceTolerance)
+{
+ Q_D(QPickingSettings);
+ if (qFuzzyCompare(worldSpaceTolerance, d->m_worldSpaceTolerance))
+ return;
+
+ d->m_worldSpaceTolerance = worldSpaceTolerance;
+ emit worldSpaceToleranceChanged(worldSpaceTolerance);
+}
+
} // namespace Qt3Drender
QT_END_NAMESPACE
diff --git a/src/render/frontend/qpickingsettings.h b/src/render/frontend/qpickingsettings.h
index 655bf952a..9c8a2c856 100644
--- a/src/render/frontend/qpickingsettings.h
+++ b/src/render/frontend/qpickingsettings.h
@@ -57,14 +57,17 @@ class QT3DRENDERSHARED_EXPORT QPickingSettings : public Qt3DCore::QNode
Q_PROPERTY(PickMethod pickMethod READ pickMethod WRITE setPickMethod NOTIFY pickMethodChanged)
Q_PROPERTY(PickResultMode pickResultMode READ pickResultMode WRITE setPickResultMode NOTIFY pickResultModeChanged)
Q_PROPERTY(FaceOrientationPickingMode faceOrientationPickingMode READ faceOrientationPickingMode WRITE setFaceOrientationPickingMode NOTIFY faceOrientationPickingModeChanged)
-
+ Q_PROPERTY(float worldSpaceTolerance READ worldSpaceTolerance WRITE setWorldSpaceTolerance NOTIFY worldSpaceToleranceChanged REVISION 10)
public:
explicit QPickingSettings(Qt3DCore::QNode *parent = nullptr);
~QPickingSettings();
enum PickMethod {
- BoundingVolumePicking,
- TrianglePicking
+ BoundingVolumePicking = 0x00,
+ TrianglePicking = 0x01,
+ LinePicking = 0x02,
+ PointPicking = 0x04,
+ PrimitivePicking = TrianglePicking | LinePicking | PointPicking
};
Q_ENUM(PickMethod) // LCOV_EXCL_LINE
@@ -84,16 +87,19 @@ public:
PickMethod pickMethod() const;
PickResultMode pickResultMode() const;
FaceOrientationPickingMode faceOrientationPickingMode() const;
+ float worldSpaceTolerance() const;
public Q_SLOTS:
void setPickMethod(PickMethod pickMethod);
void setPickResultMode(PickResultMode pickResultMode);
void setFaceOrientationPickingMode(FaceOrientationPickingMode faceOrientationPickingMode);
+ void setWorldSpaceTolerance(float worldSpaceTolerance);
Q_SIGNALS:
void pickMethodChanged(QPickingSettings::PickMethod pickMethod);
void pickResultModeChanged(QPickingSettings::PickResultMode pickResult);
void faceOrientationPickingModeChanged(QPickingSettings::FaceOrientationPickingMode faceOrientationPickingMode);
+ void worldSpaceToleranceChanged(float worldSpaceTolerance);
protected:
Q_DECLARE_PRIVATE(QPickingSettings)
diff --git a/src/render/frontend/qpickingsettings_p.h b/src/render/frontend/qpickingsettings_p.h
index 039b6a435..5da9bfd79 100644
--- a/src/render/frontend/qpickingsettings_p.h
+++ b/src/render/frontend/qpickingsettings_p.h
@@ -66,6 +66,7 @@ public:
QPickingSettings::PickMethod m_pickMethod;
QPickingSettings::PickResultMode m_pickResultMode;
QPickingSettings::FaceOrientationPickingMode m_faceOrientationPickingMode;
+ float m_worldSpaceTolerance;
};
} // namespace Qt3Drender
diff --git a/src/render/frontend/qrendersettings.cpp b/src/render/frontend/qrendersettings.cpp
index b73fed77b..4212897ab 100644
--- a/src/render/frontend/qrendersettings.cpp
+++ b/src/render/frontend/qrendersettings.cpp
@@ -92,6 +92,8 @@ void QRenderSettingsPrivate::init()
q, SLOT(_q_onPickResultModeChanged(QPickingSettings::PickResultMode)));
QObject::connect(&m_pickingSettings, SIGNAL(faceOrientationPickingModeChanged(QPickingSettings::FaceOrientationPickingMode)),
q, SLOT(_q_onFaceOrientationPickingModeChanged(QPickingSettings::FaceOrientationPickingMode)));
+ QObject::connect(&m_pickingSettings, SIGNAL(worldSpaceToleranceChanged(float)),
+ q, SLOT(_q_onWorldSpaceToleranceChanged(float)));
}
/*! \internal */
@@ -112,6 +114,12 @@ void QRenderSettingsPrivate::_q_onFaceOrientationPickingModeChanged(QPickingSett
notifyPropertyChange("faceOrientationPickingMode", faceOrientationPickingMode);
}
+/*! \internal */
+void QRenderSettingsPrivate::_q_onWorldSpaceToleranceChanged(float worldSpaceTolerance)
+{
+ notifyPropertyChange("pickWorldSpaceTolerance", worldSpaceTolerance);
+}
+
QRenderSettings::QRenderSettings(Qt3DCore::QNode *parent)
: QRenderSettings(*new QRenderSettingsPrivate, parent) {}
@@ -248,6 +256,7 @@ Qt3DCore::QNodeCreatedChangeBasePtr QRenderSettings::createNodeCreationChange()
data.pickMethod = d->m_pickingSettings.pickMethod();
data.pickResultMode = d->m_pickingSettings.pickResultMode();
data.faceOrientationPickingMode = d->m_pickingSettings.faceOrientationPickingMode();
+ data.pickWorldSpaceTolerance = d->m_pickingSettings.worldSpaceTolerance();
return creationChange;
}
diff --git a/src/render/frontend/qrendersettings.h b/src/render/frontend/qrendersettings.h
index 71da7c562..db6ffb6d8 100644
--- a/src/render/frontend/qrendersettings.h
+++ b/src/render/frontend/qrendersettings.h
@@ -90,6 +90,7 @@ private:
Q_PRIVATE_SLOT(d_func(), void _q_onPickingMethodChanged(QPickingSettings::PickMethod))
Q_PRIVATE_SLOT(d_func(), void _q_onPickResultModeChanged(QPickingSettings::PickResultMode))
Q_PRIVATE_SLOT(d_func(), void _q_onFaceOrientationPickingModeChanged(QPickingSettings::FaceOrientationPickingMode))
+ Q_PRIVATE_SLOT(d_func(), void _q_onWorldSpaceToleranceChanged(float))
Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const Q_DECL_OVERRIDE;
};
diff --git a/src/render/frontend/qrendersettings_p.h b/src/render/frontend/qrendersettings_p.h
index f05124296..5060634c9 100644
--- a/src/render/frontend/qrendersettings_p.h
+++ b/src/render/frontend/qrendersettings_p.h
@@ -73,6 +73,7 @@ public:
void _q_onPickingMethodChanged(QPickingSettings::PickMethod pickMethod);
void _q_onPickResultModeChanged(QPickingSettings::PickResultMode pickResultMode);
void _q_onFaceOrientationPickingModeChanged(QPickingSettings::FaceOrientationPickingMode faceOrientationPickingMode);
+ void _q_onWorldSpaceToleranceChanged(float worldSpaceTolerance);
Q_DECLARE_PUBLIC(QRenderSettings)
};
@@ -84,6 +85,7 @@ struct QRenderSettingsData
QPickingSettings::PickMethod pickMethod;
QPickingSettings::PickResultMode pickResultMode;
QPickingSettings::FaceOrientationPickingMode faceOrientationPickingMode;
+ float pickWorldSpaceTolerance;
};
} // namespace Qt3Drender
diff --git a/src/render/jobs/pickboundingvolumejob.cpp b/src/render/jobs/pickboundingvolumejob.cpp
index a1c8dd864..592b270f3 100644
--- a/src/render/jobs/pickboundingvolumejob.cpp
+++ b/src/render/jobs/pickboundingvolumejob.cpp
@@ -39,6 +39,7 @@
#include "pickboundingvolumejob_p.h"
#include "qpicktriangleevent.h"
+#include "qpicklineevent.h"
#include <Qt3DRender/qgeometryrenderer.h>
#include <Qt3DRender/private/renderer_p.h>
#include <Qt3DRender/private/nodemanagers_p.h>
@@ -47,6 +48,7 @@
#include <Qt3DRender/private/managers_p.h>
#include <Qt3DRender/private/geometryrenderer_p.h>
#include <Qt3DRender/private/rendersettings_p.h>
+#include <Qt3DRender/private/trianglesvisitor_p.h>
#include <Qt3DRender/private/job_common_p.h>
#include <Qt3DRender/private/qpickevent_p.h>
#include <Qt3DRender/private/pickboundingvolumeutils_p.h>
@@ -222,11 +224,15 @@ bool PickBoundingVolumeJob::runHelper()
// by compressing them into a single one
const bool trianglePickingRequested = (m_renderSettings->pickMethod() == QPickingSettings::TrianglePicking);
+ const bool edgePickingRequested = (m_renderSettings->pickMethod() == QPickingSettings::LinePicking);
+ const bool pointPickingRequested = (m_renderSettings->pickMethod() == QPickingSettings::PointPicking);
+ const bool primitivePickingRequested = pointPickingRequested | edgePickingRequested | trianglePickingRequested;
const bool allHitsRequested = (m_renderSettings->pickResultMode() == QPickingSettings::AllPicks);
const bool frontFaceRequested =
m_renderSettings->faceOrientationPickingMode() != QPickingSettings::BackFace;
const bool backFaceRequested =
m_renderSettings->faceOrientationPickingMode() != QPickingSettings::FrontFace;
+ const float pickWorldSpaceTolerance = m_renderSettings->pickWorldSpaceTolerance();
// For each mouse event
for (const QMouseEvent &event : mouseEvents) {
@@ -251,9 +257,18 @@ bool PickBoundingVolumeJob::runHelper()
gathererFunctor.m_backFaceRequested = backFaceRequested;
gathererFunctor.m_manager = m_manager;
gathererFunctor.m_ray = ray;
- sphereHits = gathererFunctor.computeHits(entityPicker.entities(), allHitsRequested);
- } else {
- sphereHits = entityPicker.hits();
+ sphereHits << gathererFunctor.computeHits(entityPicker.entities(), allHitsRequested);
+ }
+ if (edgePickingRequested) {
+ PickingUtils::LineCollisionGathererFunctor gathererFunctor;
+ gathererFunctor.m_manager = m_manager;
+ gathererFunctor.m_ray = ray;
+ gathererFunctor.m_pickWorldSpaceTolerance = pickWorldSpaceTolerance;
+ sphereHits << gathererFunctor.computeHits(entityPicker.entities(), allHitsRequested);
+ PickingUtils::AbstractCollisionGathererFunctor::sortHits(sphereHits);
+ }
+ if (!primitivePickingRequested) {
+ sphereHits << entityPicker.hits();
PickingUtils::AbstractCollisionGathererFunctor::sortHits(sphereHits);
if (!allHitsRequested)
sphereHits = { sphereHits.front() };
@@ -261,8 +276,7 @@ bool PickBoundingVolumeJob::runHelper()
}
// Dispatch events based on hit results
- dispatchPickEvents(event, sphereHits, eventButton, eventButtons, eventModifiers,
- trianglePickingRequested, allHitsRequested);
+ dispatchPickEvents(event, sphereHits, eventButton, eventButtons, eventModifiers, allHitsRequested);
}
}
@@ -295,7 +309,6 @@ void PickBoundingVolumeJob::dispatchPickEvents(const QMouseEvent &event,
QPickEvent::Buttons eventButton,
int eventButtons,
int eventModifiers,
- bool trianglePickingRequested,
bool allHitsRequested)
{
ObjectPicker *lastCurrentPicker = m_manager->objectPickerManager()->data(m_currentPicker);
@@ -334,14 +347,31 @@ void PickBoundingVolumeJob::dispatchPickEvents(const QMouseEvent &event,
localIntersection = entity->worldTransform()->inverted() * hit.m_intersection;
QPickEventPtr pickEvent;
- if (trianglePickingRequested) {
- pickEvent.reset(new QPickTriangleEvent(event.localPos(), hit.m_intersection, localIntersection, hit.m_distance,
- hit.m_triangleIndex, hit.m_vertexIndex[0], hit.m_vertexIndex[1], hit.m_vertexIndex[2],
- eventButton, eventButtons, eventModifiers, hit.m_uvw));
- QPickEventPrivate::get(pickEvent.data())->m_entity = hit.m_entityId;
- } else {
- pickEvent.reset(new QPickEvent(event.localPos(), hit.m_intersection, localIntersection, hit.m_distance,
+ switch (hit.m_type) {
+ case QCollisionQueryResult::Hit::Triangle:
+ pickEvent.reset(new QPickTriangleEvent(event.localPos(), hit.m_intersection,
+ localIntersection, hit.m_distance,
+ hit.m_primitiveIndex,
+ hit.m_vertexIndex[0],
+ hit.m_vertexIndex[1],
+ hit.m_vertexIndex[2],
+ eventButton, eventButtons,
+ eventModifiers, hit.m_uvw));
+ break;
+ case QCollisionQueryResult::Hit::Edge:
+ pickEvent.reset(new QPickLineEvent(event.localPos(), hit.m_intersection,
+ localIntersection, hit.m_distance,
+ hit.m_primitiveIndex,
+ hit.m_vertexIndex[0], hit.m_vertexIndex[1],
+ eventButton, eventButtons, eventModifiers));
+ break;
+ case QCollisionQueryResult::Hit::Entity:
+ pickEvent.reset(new QPickEvent(event.localPos(), hit.m_intersection,
+ localIntersection, hit.m_distance,
eventButton, eventButtons, eventModifiers));
+ break;
+ default:
+ Q_UNREACHABLE();
}
switch (event.type()) {
case QEvent::MouseButtonPress: {
diff --git a/src/render/jobs/pickboundingvolumejob_p.h b/src/render/jobs/pickboundingvolumejob_p.h
index f13e4e48b..492f8e4fc 100644
--- a/src/render/jobs/pickboundingvolumejob_p.h
+++ b/src/render/jobs/pickboundingvolumejob_p.h
@@ -110,7 +110,6 @@ protected:
QPickEvent::Buttons eventButton,
int eventButtons,
int eventModifiers,
- bool trianglePickingRequested,
bool allHitsRequested);
private:
diff --git a/src/render/jobs/pickboundingvolumeutils.cpp b/src/render/jobs/pickboundingvolumeutils.cpp
index a8367dc20..80825e6e1 100644
--- a/src/render/jobs/pickboundingvolumeutils.cpp
+++ b/src/render/jobs/pickboundingvolumeutils.cpp
@@ -47,6 +47,8 @@
#include <Qt3DRender/private/nodemanagers_p.h>
#include <Qt3DRender/private/sphere_p.h>
#include <Qt3DRender/private/entity_p.h>
+#include <Qt3DRender/private/trianglesvisitor_p.h>
+#include <Qt3DRender/private/segmentsvisitor_p.h>
QT_BEGIN_NAMESPACE
@@ -199,8 +201,9 @@ bool TriangleCollisionVisitor::intersectsSegmentTriangle(uint andx, const QVecto
bool intersected = Render::intersectsSegmentTriangle(m_ray, a, b, c, uvw, t);
if (intersected) {
QCollisionQueryResult::Hit queryResult;
+ queryResult.m_type = QCollisionQueryResult::Hit::Triangle;
queryResult.m_entityId = m_root->peerId();
- queryResult.m_triangleIndex = m_triangleIndex;
+ queryResult.m_primitiveIndex = m_triangleIndex;
queryResult.m_vertexIndex[0] = andx;
queryResult.m_vertexIndex[1] = bndx;
queryResult.m_vertexIndex[2] = cndx;
@@ -212,6 +215,127 @@ bool TriangleCollisionVisitor::intersectsSegmentTriangle(uint andx, const QVecto
return intersected;
}
+class LineCollisionVisitor : public SegmentsVisitor
+{
+public:
+ HitList hits;
+
+ LineCollisionVisitor(NodeManagers* manager, const Entity *root, const RayCasting::QRay3D& ray,
+ float pickWorldSpaceTolerance)
+ : SegmentsVisitor(manager), m_root(root), m_ray(ray)
+ , m_segmentIndex(0), m_pickWorldSpaceTolerance(pickWorldSpaceTolerance)
+ {
+ }
+
+private:
+ const Entity *m_root;
+ RayCasting::QRay3D m_ray;
+ uint m_segmentIndex;
+ float m_pickWorldSpaceTolerance;
+
+ void visit(uint andx, const QVector3D &a,
+ uint bndx, const QVector3D &b) Q_DECL_OVERRIDE;
+ bool intersectsSegmentSegment(uint andx, const QVector3D &a,
+ uint bndx, const QVector3D &b);
+ bool rayToLineSegment(const QVector3D& lineStart,const QVector3D& lineEnd,
+ float &distance, QVector3D &intersection) const;
+};
+
+void LineCollisionVisitor::visit(uint andx, const QVector3D &a, uint bndx, const QVector3D &b)
+{
+ const QMatrix4x4 &mat = *m_root->worldTransform();
+ const QVector3D tA = mat * a;
+ const QVector3D tB = mat * b;
+
+ intersectsSegmentSegment(andx, tA, bndx, tB);
+
+ m_segmentIndex++;
+}
+
+bool LineCollisionVisitor::intersectsSegmentSegment(uint andx, const QVector3D &a,
+ uint bndx, const QVector3D &b)
+{
+ float distance = 0.f;
+ QVector3D intersection;
+ bool res = rayToLineSegment(a, b, distance, intersection);
+ if (res) {
+ QCollisionQueryResult::Hit queryResult;
+ queryResult.m_type = QCollisionQueryResult::Hit::Edge;
+ queryResult.m_entityId = m_root->peerId();
+ queryResult.m_primitiveIndex = m_segmentIndex;
+ queryResult.m_vertexIndex[0] = andx;
+ queryResult.m_vertexIndex[1] = bndx;
+ queryResult.m_intersection = intersection;
+ queryResult.m_distance = m_ray.projectedDistance(queryResult.m_intersection);
+ hits.push_back(queryResult);
+ return true;
+ }
+ return false;
+}
+
+bool LineCollisionVisitor::rayToLineSegment(const QVector3D& lineStart,const QVector3D& lineEnd,
+ float &distance, QVector3D &intersection) const
+{
+ const float epsilon = 0.00000001f;
+
+ const QVector3D u = m_ray.direction() * m_ray.distance();
+ const QVector3D v = lineEnd - lineStart;
+ const QVector3D w = m_ray.origin() - lineStart;
+ const float a = QVector3D::dotProduct(u, u);
+ const float b = QVector3D::dotProduct(u, v);
+ const float c = QVector3D::dotProduct(v, v);
+ const float d = QVector3D::dotProduct(u, w);
+ const float e = QVector3D::dotProduct(v, w);
+ const float D = a * c - b * b;
+ float sc, sN, sD = D;
+ float tc, tN, tD = D;
+
+ if (D < epsilon) {
+ sN = 0.0;
+ sD = 1.0;
+ tN = e;
+ tD = c;
+ } else {
+ sN = (b * e - c * d);
+ tN = (a * e - b * d);
+ if (sN < 0.0) {
+ sN = 0.0;
+ tN = e;
+ tD = c;
+ }
+ }
+
+ if (tN < 0.0) {
+ tN = 0.0;
+ if (-d < 0.0)
+ sN = 0.0;
+ else {
+ sN = -d;
+ sD = a;
+ }
+ } else if (tN > tD) {
+ tN = tD;
+ if ((-d + b) < 0.0)
+ sN = 0;
+ else {
+ sN = (-d + b);
+ sD = a;
+ }
+ }
+
+ sc = (qAbs(sN) < epsilon ? 0.0f : sN / sD);
+ tc = (qAbs(tN) < epsilon ? 0.0f : tN / tD);
+
+ const QVector3D dP = w + (sc * u) - (tc * v);
+ const float f = dP.length();
+ if (f < m_pickWorldSpaceTolerance) {
+ distance = sc * u.length();
+ intersection = lineStart + v * tc;
+ return true;
+ }
+ return false;
+}
+
HitList reduceToFirstHit(HitList &result, const HitList &intermediate)
{
if (!intermediate.empty()) {
@@ -325,6 +449,30 @@ HitList TriangleCollisionGathererFunctor::pick(const Entity *entity) const
return result;
}
+HitList LineCollisionGathererFunctor::computeHits(const QVector<Entity *> &entities, bool allHitsRequested)
+{
+ const auto reducerOp = allHitsRequested ? PickingUtils::reduceToAllHits : PickingUtils::reduceToFirstHit;
+ return QtConcurrent::blockingMappedReduced<HitList>(entities, *this, reducerOp);
+}
+
+HitList LineCollisionGathererFunctor::pick(const Entity *entity) const
+{
+ HitList result;
+
+ GeometryRenderer *gRenderer = entity->renderComponent<GeometryRenderer>();
+ if (!gRenderer)
+ return result;
+
+ if (rayHitsEntity(entity)) {
+ LineCollisionVisitor visitor(m_manager, entity, m_ray, m_pickWorldSpaceTolerance);
+ visitor.apply(gRenderer, entity->peerId());
+ result = visitor.hits;
+ sortHits(result);
+ }
+
+ return result;
+}
+
HierarchicalEntityPicker::HierarchicalEntityPicker(const QRay3D &ray)
: m_ray(ray)
{
diff --git a/src/render/jobs/pickboundingvolumeutils_p.h b/src/render/jobs/pickboundingvolumeutils_p.h
index eb272ce41..ad149fd09 100644
--- a/src/render/jobs/pickboundingvolumeutils_p.h
+++ b/src/render/jobs/pickboundingvolumeutils_p.h
@@ -53,7 +53,6 @@
#include <Qt3DCore/QNodeId>
#include <Qt3DRender/private/qray3d_p.h>
-#include <Qt3DRender/private/trianglesvisitor_p.h>
#include <Qt3DRender/private/qraycastingservice_p.h>
@@ -69,6 +68,7 @@ namespace Render {
class Entity;
class Renderer;
class FrameGraphNode;
+class NodeManagers;
namespace PickingUtils {
@@ -159,6 +159,14 @@ struct Q_AUTOTEST_EXPORT TriangleCollisionGathererFunctor : public AbstractColli
HitList pick(const Entity *entity) const Q_DECL_OVERRIDE;
};
+struct Q_AUTOTEST_EXPORT LineCollisionGathererFunctor : public AbstractCollisionGathererFunctor
+{
+ float m_pickWorldSpaceTolerance;
+
+ HitList computeHits(const QVector<Entity *> &entities, bool allHitsRequested) Q_DECL_OVERRIDE;
+ HitList pick(const Entity *entity) const Q_DECL_OVERRIDE;
+};
+
} // PickingUtils
} // Render
diff --git a/src/render/picking/picking.pri b/src/render/picking/picking.pri
index c4c188a82..fa8611adf 100644
--- a/src/render/picking/picking.pri
+++ b/src/render/picking/picking.pri
@@ -4,6 +4,7 @@ HEADERS += \
$$PWD/qobjectpicker.h \
$$PWD/qpickevent.h \
$$PWD/qpickevent_p.h \
+ $$PWD/qpicklineevent.h \
$$PWD/qpicktriangleevent.h \
$$PWD/objectpicker_p.h \
$$PWD/pickeventfilter_p.h \
@@ -12,6 +13,7 @@ HEADERS += \
SOURCES += \
$$PWD/qobjectpicker.cpp \
$$PWD/qpickevent.cpp \
+ $$PWD/qpicklineevent.cpp \
$$PWD/qpicktriangleevent.cpp \
$$PWD/objectpicker.cpp \
$$PWD/pickeventfilter.cpp
diff --git a/src/render/picking/qpicklineevent.cpp b/src/render/picking/qpicklineevent.cpp
new file mode 100644
index 000000000..5b9ef0d76
--- /dev/null
+++ b/src/render/picking/qpicklineevent.cpp
@@ -0,0 +1,173 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qpicklineevent.h"
+#include "qpickevent_p.h"
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+class QPickLineEventPrivate : public QPickEventPrivate
+{
+public:
+ QPickLineEventPrivate()
+ : QPickEventPrivate()
+ , m_edgeIndex(0)
+ , m_vertex1Index(0)
+ , m_vertex2Index(0)
+ {
+ }
+
+ uint m_edgeIndex;
+ uint m_vertex1Index;
+ uint m_vertex2Index;
+};
+
+/*!
+ \class Qt3DRender::QPickLineEvent
+ \inmodule Qt3DRender
+
+ \brief The QPickLineEvent class holds information when a segment of a line is picked
+
+ \sa QPickEvent
+ \since 5.10
+*/
+
+/*!
+ * \qmltype PickLineEvent
+ * \instantiates Qt3DRender::QPickLineEvent
+ * \inqmlmodule Qt3D.Render
+ * \brief PickLineEvent holds information when a segment of a line is picked.
+ * \sa ObjectPicker
+ */
+
+
+/*!
+ \fn Qt3DRender::QPickLineEvent::QPickLineEvent()
+ Constructs a new QPickEvent.
+ */
+QPickLineEvent::QPickLineEvent()
+ : QPickEvent(*new QPickLineEventPrivate())
+{
+}
+
+QPickLineEvent::QPickLineEvent(const QPointF &position, const QVector3D &worldIntersection,
+ const QVector3D &localIntersection, float distance,
+ uint edgeIndex, uint vertex1Index, uint vertex2Index,
+ QPickEvent::Buttons button, int buttons, int modifiers)
+ : QPickEvent(*new QPickLineEventPrivate())
+{
+ Q_D(QPickLineEvent);
+ d->m_position = position;
+ d->m_distance = distance;
+ d->m_worldIntersection = worldIntersection;
+ d->m_localIntersection = localIntersection;
+ d->m_edgeIndex = edgeIndex;
+ d->m_vertex1Index = vertex1Index;
+ d->m_vertex2Index = vertex2Index;
+ d->m_button = button;
+ d->m_buttons = buttons;
+ d->m_modifiers = modifiers;
+}
+
+/*! \internal */
+QPickLineEvent::~QPickLineEvent()
+{
+}
+
+/*!
+ \qmlproperty uint Qt3D.Render::PickLineEvent::triangleIndex
+ Specifies the triangle index of the event
+*/
+/*!
+ \property Qt3DRender::QPickLineEvent::edgeIndex
+ Specifies the index of the edge that was picked
+ */
+/*!
+ * \brief QPickLineEvent::edgeIndex
+ * Returns the index of the picked edge
+ */
+uint QPickLineEvent::edgeIndex() const
+{
+ Q_D(const QPickLineEvent);
+ return d->m_edgeIndex;
+}
+
+/*!
+ \qmlproperty uint Qt3D.Render::PickLineEvent::vertex1Index
+ Specifies the index of the first point of the picked edge
+*/
+/*!
+ \property Qt3DRender::QPickLineEvent::vertex1Index
+ Specifies the index of the first point of the picked edge
+ */
+/*!
+ * \brief QPickLineEvent::vertex1Index
+ * Returns the index of the first point of the picked edge
+ */
+uint QPickLineEvent::vertex1Index() const
+{
+ Q_D(const QPickLineEvent);
+ return d->m_vertex1Index;
+}
+
+/*!
+ \qmlproperty uint Qt3D.Render::PickLineEvent::vertex2Index
+ Specifies the index of the second point of the picked edge
+*/
+/*!
+ \property Qt3DRender::QPickLineEvent::vertex2Index
+ Specifies the index of the second point of the picked edge
+ */
+/*!
+ * \brief QPickLineEvent::vertex2Index
+ * Returns the index of the second point of the picked triangle
+ */
+uint QPickLineEvent::vertex2Index() const
+{
+ Q_D(const QPickLineEvent);
+ return d->m_vertex2Index;
+}
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
+
diff --git a/src/render/picking/qpicklineevent.h b/src/render/picking/qpicklineevent.h
new file mode 100644
index 000000000..102989450
--- /dev/null
+++ b/src/render/picking/qpicklineevent.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_QPICKLINEEVENT_H
+#define QT3DRENDER_QPICKLINEEVENT_H
+
+#include <Qt3DRender/qpickevent.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+class QPickLineEventPrivate;
+
+class QT3DRENDERSHARED_EXPORT QPickLineEvent : public QPickEvent
+{
+ Q_OBJECT
+ Q_PROPERTY(uint edgeIndex READ edgeIndex CONSTANT)
+ Q_PROPERTY(uint vertex1Index READ vertex1Index CONSTANT)
+ Q_PROPERTY(uint vertex2Index READ vertex2Index CONSTANT)
+public:
+ QPickLineEvent();
+ QPickLineEvent(const QPointF &position, const QVector3D& worldIntersection, const QVector3D& localIntersection, float distance,
+ uint edgeIndex, uint vertex1Index, uint vertex2Index, Buttons button, int buttons, int modifiers);
+ ~QPickLineEvent();
+
+public:
+ uint edgeIndex() const;
+ uint vertex1Index() const;
+ uint vertex2Index() const;
+
+private:
+ Q_DECLARE_PRIVATE(QPickLineEvent)
+};
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_QPICKLINEEVENT_H
diff --git a/src/render/raycasting/qcollisionqueryresult_p.h b/src/render/raycasting/qcollisionqueryresult_p.h
index e13dda74a..1a430e019 100644
--- a/src/render/raycasting/qcollisionqueryresult_p.h
+++ b/src/render/raycasting/qcollisionqueryresult_p.h
@@ -69,9 +69,17 @@ class QT3DRENDERSHARED_EXPORT QCollisionQueryResult
{
public:
struct Hit {
+ enum HitType {
+ Entity,
+ Point,
+ Edge,
+ Triangle
+ };
+
Hit()
- : m_distance(-1.f)
- , m_triangleIndex(0)
+ : m_type(Entity)
+ , m_distance(-1.f)
+ , m_primitiveIndex(0)
{
m_vertexIndex[0] = m_vertexIndex[1] = m_vertexIndex[2] = 0;
}
@@ -85,9 +93,10 @@ public:
}
Qt3DCore::QNodeId m_entityId;
+ HitType m_type;
QVector3D m_intersection;
float m_distance;
- uint m_triangleIndex;
+ uint m_primitiveIndex;
uint m_vertexIndex[3];
QVector3D m_uvw;
};
diff --git a/tests/auto/render/qrendersettings/tst_qrendersettings.cpp b/tests/auto/render/qrendersettings/tst_qrendersettings.cpp
index 1f0a9f066..6f182cbeb 100644
--- a/tests/auto/render/qrendersettings/tst_qrendersettings.cpp
+++ b/tests/auto/render/qrendersettings/tst_qrendersettings.cpp
@@ -184,6 +184,7 @@ private Q_SLOTS:
pickingSettings->setPickMethod(Qt3DRender::QPickingSettings::TrianglePicking);
pickingSettings->setPickResultMode(Qt3DRender::QPickingSettings::AllPicks);
pickingSettings->setFaceOrientationPickingMode(Qt3DRender::QPickingSettings::FrontAndBackFace);
+ pickingSettings->setWorldSpaceTolerance(5.f);
// WHEN
QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges;
@@ -203,6 +204,7 @@ private Q_SLOTS:
QCOMPARE(renderSettings.pickingSettings()->pickMethod(), cloneData.pickMethod);
QCOMPARE(renderSettings.pickingSettings()->pickResultMode(), cloneData.pickResultMode);
QCOMPARE(renderSettings.pickingSettings()->faceOrientationPickingMode(), cloneData.faceOrientationPickingMode);
+ QCOMPARE(renderSettings.pickingSettings()->worldSpaceTolerance(), cloneData.pickWorldSpaceTolerance);
QCOMPARE(renderSettings.renderPolicy(), cloneData.renderPolicy);
QCOMPARE(renderSettings.activeFrameGraph()->id(), cloneData.activeFrameGraphId);
QCOMPARE(renderSettings.id(), creationChangeData->subjectId());
@@ -410,6 +412,41 @@ private Q_SLOTS:
}
+ void checkWorldSpaceToleranceUpdate()
+ {
+ // GIVEN
+ TestArbiter arbiter;
+ Qt3DRender::QRenderSettings renderSettings;
+ Qt3DRender::QPickingSettings *pickingSettings = renderSettings.pickingSettings();
+
+ arbiter.setArbiterOnNode(&renderSettings);
+
+ {
+ // WHEN
+ pickingSettings->setWorldSpaceTolerance(5.f);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 1);
+ auto change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
+ QCOMPARE(change->propertyName(), "pickWorldSpaceTolerance");
+ QCOMPARE(change->value().toFloat(), pickingSettings->worldSpaceTolerance());
+ QCOMPARE(change->type(), Qt3DCore::PropertyUpdated);
+
+ arbiter.events.clear();
+ }
+
+ {
+ // WHEN
+ pickingSettings->setWorldSpaceTolerance(5.f);
+ QCoreApplication::processEvents();
+
+ // THEN
+ QCOMPARE(arbiter.events.size(), 0);
+ }
+
+ }
+
};
QTEST_MAIN(tst_QRenderSettings)