diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/render/backend/rendersettings.cpp | 4 | ||||
-rw-r--r-- | src/render/backend/rendersettings_p.h | 3 | ||||
-rw-r--r-- | src/render/frontend/qpickingsettings.cpp | 33 | ||||
-rw-r--r-- | src/render/frontend/qpickingsettings.h | 12 | ||||
-rw-r--r-- | src/render/frontend/qpickingsettings_p.h | 1 | ||||
-rw-r--r-- | src/render/frontend/qrendersettings.cpp | 9 | ||||
-rw-r--r-- | src/render/frontend/qrendersettings.h | 1 | ||||
-rw-r--r-- | src/render/frontend/qrendersettings_p.h | 2 | ||||
-rw-r--r-- | src/render/jobs/pickboundingvolumejob.cpp | 56 | ||||
-rw-r--r-- | src/render/jobs/pickboundingvolumejob_p.h | 1 | ||||
-rw-r--r-- | src/render/jobs/pickboundingvolumeutils.cpp | 150 | ||||
-rw-r--r-- | src/render/jobs/pickboundingvolumeutils_p.h | 10 | ||||
-rw-r--r-- | src/render/picking/picking.pri | 2 | ||||
-rw-r--r-- | src/render/picking/qpicklineevent.cpp | 173 | ||||
-rw-r--r-- | src/render/picking/qpicklineevent.h | 75 | ||||
-rw-r--r-- | src/render/raycasting/qcollisionqueryresult_p.h | 15 |
16 files changed, 524 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; }; |