summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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)