summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/core/services/nullservices_p.h3
-rw-r--r--src/core/services/qabstractcollisionqueryservice.h3
-rw-r--r--src/render/jobs/pickboundingvolumejob.cpp86
-rw-r--r--src/render/jobs/pickboundingvolumejob_p.h7
-rw-r--r--src/render/services/qraycastingservice.cpp120
-rw-r--r--src/render/services/qraycastingservice.h4
-rw-r--r--src/render/services/qraycastingservice_p.h4
-rw-r--r--tests/auto/render/raycasting/tst_raycasting.cpp40
8 files changed, 184 insertions, 83 deletions
diff --git a/src/core/services/nullservices_p.h b/src/core/services/nullservices_p.h
index 31f8da3b5..a3e3fd672 100644
--- a/src/core/services/nullservices_p.h
+++ b/src/core/services/nullservices_p.h
@@ -91,10 +91,11 @@ public:
{}
~NullCollisionQueryService() {}
- QQueryHandle query(const QRay3D &ray, QueryMode mode) Q_DECL_OVERRIDE
+ QQueryHandle query(const QRay3D &ray, QueryMode mode, Qt3DCore::QBoundingVolumeProvider *provider) Q_DECL_OVERRIDE
{
Q_UNUSED(ray);
Q_UNUSED(mode);
+ Q_UNUSED(provider);
return 0;
}
diff --git a/src/core/services/qabstractcollisionqueryservice.h b/src/core/services/qabstractcollisionqueryservice.h
index 04d92c687..4f9d6b02f 100644
--- a/src/core/services/qabstractcollisionqueryservice.h
+++ b/src/core/services/qabstractcollisionqueryservice.h
@@ -50,6 +50,7 @@ namespace Qt3DCore {
class QRay3D;
class QAbstractCollisionQueryServicePrivate;
+class QBoundingVolumeProvider;
class QT3DCORESHARED_EXPORT QAbstractCollisionQueryService : public QAbstractServiceProvider
{
@@ -59,7 +60,7 @@ public:
AllHits
};
- virtual QQueryHandle query(const QRay3D &ray, QueryMode mode) = 0;
+ virtual QQueryHandle query(const QRay3D &ray, QueryMode mode, QBoundingVolumeProvider *provider) = 0;
virtual QCollisionQueryResult fetchResult(const QQueryHandle &handle) = 0;
virtual QVector<QCollisionQueryResult> fetchAllResults() const = 0;
diff --git a/src/render/jobs/pickboundingvolumejob.cpp b/src/render/jobs/pickboundingvolumejob.cpp
index f6c2acfff..4f82a0f39 100644
--- a/src/render/jobs/pickboundingvolumejob.cpp
+++ b/src/render/jobs/pickboundingvolumejob.cpp
@@ -45,7 +45,9 @@
#include <Qt3DRender/private/objectpicker_p.h>
#include <Qt3DRender/private/managers_p.h>
#include <Qt3DRender/private/sphere_p.h>
+#include <Qt3DRender/private/geometryrenderer_p.h>
#include <Qt3DRender/qraycastingservice.h>
+#include <Qt3DRender/qgeometryrenderer.h>
#include <Qt3DCore/qservicelocator.h>
#include <Qt3DCore/qray3d.h>
#include <Qt3DCore/qabstractcollisionqueryservice.h>
@@ -65,8 +67,8 @@ struct ViewportCameraPair
QRectF viewport;
};
-class ViewportCameraGatherer {
-
+class ViewportCameraGatherer
+{
private:
QVector<FrameGraphNode *> m_leaves;
@@ -120,6 +122,44 @@ public:
};
+QVector<Qt3DCore::QBoundingVolume *> gatherBoundingVolumes(Entity *entity)
+{
+ QVector<Qt3DCore::QBoundingVolume *> volumes;
+
+ if (entity != Q_NULLPTR) {
+ volumes.push_back(entity->worldBoundingVolume());
+ // Traverse children
+ Q_FOREACH (Entity *child, entity->children())
+ volumes += gatherBoundingVolumes(child);
+ }
+ return volumes;
+}
+
+class SphereBoundingVolumesGatherer : public Qt3DCore::QBoundingVolumeProvider
+{
+public:
+ explicit SphereBoundingVolumesGatherer(Entity *root)
+ : Qt3DCore::QBoundingVolumeProvider()
+ , m_root(root)
+ , m_needsRefresh(true)
+ {
+ }
+
+ QVector<Qt3DCore::QBoundingVolume *> boundingVolumes() const Q_DECL_FINAL
+ {
+ if (m_needsRefresh) {
+ m_volumes = gatherBoundingVolumes(m_root);
+ m_needsRefresh = false;
+ }
+ return m_volumes;
+ }
+
+private:
+ Entity *m_root;
+ mutable QVector<Qt3DCore::QBoundingVolume *> m_volumes;
+ mutable bool m_needsRefresh;
+};
+
} // anonymous
PickBoundingVolumeJob::PickBoundingVolumeJob(Renderer *renderer)
@@ -134,14 +174,8 @@ void PickBoundingVolumeJob::setRoot(Entity *root)
m_node = root;
}
-QVector<Qt3DCore::QBoundingVolume *> PickBoundingVolumeJob::boundingVolumes() const
-{
- return gatherBoundingVolumes(m_node);
-}
-
Qt3DCore::QRay3D PickBoundingVolumeJob::intersectionRay(const QPoint &pos, const QMatrix4x4 &viewMatrix, const QMatrix4x4 &projectionMatrix, const QRect &viewport)
{
- // TO DO: We may need to invert the y pos (Qt vs GL coordinates)
QVector3D nearPos = QVector3D(pos.x(), pos.y(), 0.0f);
nearPos = nearPos.unproject(viewMatrix, projectionMatrix, viewport);
QVector3D farPos = QVector3D(pos.x(), pos.y(), 1.0f);
@@ -163,7 +197,7 @@ void PickBoundingVolumeJob::run()
(Qt3DCore::QServiceLocator::CollisionService);
if (rayCasting == Q_NULLPTR) {
- Qt3DRender::QRayCastingService *rayCastingService = new QRayCastingService(this);
+ Qt3DRender::QRayCastingService *rayCastingService = new QRayCastingService();
m_renderer->rendererAspect()->services()->registerServiceProvider(Qt3DCore::QServiceLocator::CollisionService, rayCastingService);
rayCasting = rayCastingService;
}
@@ -172,6 +206,8 @@ void PickBoundingVolumeJob::run()
ViewportCameraGatherer vcGatherer;
const QVector<ViewportCameraPair> vcPairs = vcGatherer.gather(m_renderer->frameGraphRoot());
+ SphereBoundingVolumesGatherer sphereGatherer(m_node);
+
if (!vcPairs.empty()) {
Q_FOREACH (const QMouseEvent &event, m_mouseEvents) {
m_hoveredPickersToClear = m_hoveredPickers;
@@ -180,10 +216,22 @@ void PickBoundingVolumeJob::run()
const QVector<Qt3DCore::QNodeId> hits = hitsForViewportAndCamera(event.pos(),
vc.viewport,
vc.cameraId,
- rayCasting);
+ rayCasting,
+ &sphereGatherer);
// If we have hits
if (!hits.isEmpty()) {
+ // Note: how can we control that we want the first/last/all elements along the ray to be picked
+
+ // How do we differentiate betwnee an Entity with no GeometryRenderer and one with one, both having
+ // an ObjectPicker component when it comes
+
+ // We want to gather hits against triangles
+ // build a triangle based bounding volume
+
+
+
+
Q_FOREACH (const Qt3DCore::QNodeId &entityId, hits) {
Entity *entity = m_manager->renderNodesManager()->lookupResource(entityId);
HObjectPicker objectPickerHandle = entity->componentHandle<ObjectPicker, 16>();
@@ -276,19 +324,6 @@ void PickBoundingVolumeJob::run()
m_mouseEvents.clear();
}
-QVector<Qt3DCore::QBoundingVolume *> PickBoundingVolumeJob::gatherBoundingVolumes(Entity *entity) const
-{
- QVector<Qt3DCore::QBoundingVolume *> volumes;
-
- if (entity != Q_NULLPTR) {
- volumes.push_back(entity->worldBoundingVolume());
- // Traverse children
- Q_FOREACH (Entity *child, entity->children())
- volumes += gatherBoundingVolumes(child);
- }
- return volumes;
-}
-
void PickBoundingVolumeJob::viewMatrixForCamera(const Qt3DCore::QNodeId &cameraId,
QMatrix4x4 &viewMatrix,
QMatrix4x4 &projectionMatrix) const
@@ -322,7 +357,8 @@ QRect PickBoundingVolumeJob::windowViewport(const QRectF &relativeViewport) cons
QVector<Qt3DCore::QNodeId> PickBoundingVolumeJob::hitsForViewportAndCamera(const QPoint &pos,
const QRectF &relativeViewport,
const Qt3DCore::QNodeId &cameraId,
- Qt3DCore::QAbstractCollisionQueryService *rayCasting) const
+ Qt3DCore::QAbstractCollisionQueryService *rayCasting,
+ Qt3DCore::QBoundingVolumeProvider *volumeProvider) const
{
QMatrix4x4 viewMatrix;
QMatrix4x4 projectionMatrix;
@@ -334,7 +370,7 @@ QVector<Qt3DCore::QNodeId> PickBoundingVolumeJob::hitsForViewportAndCamera(const
// In GL the y is inverted compared to Qt
const QPoint glCorrectPos = s ? QPoint(pos.x(), s->size().height() - pos.y()) : pos;
const Qt3DCore::QRay3D ray = intersectionRay(glCorrectPos, viewMatrix, projectionMatrix, viewport);
- const Qt3DCore::QQueryHandle rayCastingHandle = rayCasting->query(ray, Qt3DCore::QAbstractCollisionQueryService::AllHits);
+ const Qt3DCore::QQueryHandle rayCastingHandle = rayCasting->query(ray, Qt3DCore::QAbstractCollisionQueryService::AllHits, volumeProvider);
const Qt3DCore::QCollisionQueryResult queryResult = rayCasting->fetchResult(rayCastingHandle);
return queryResult.entitiesHit();
}
diff --git a/src/render/jobs/pickboundingvolumejob_p.h b/src/render/jobs/pickboundingvolumejob_p.h
index 6edfa23b4..aeb2f008e 100644
--- a/src/render/jobs/pickboundingvolumejob_p.h
+++ b/src/render/jobs/pickboundingvolumejob_p.h
@@ -70,13 +70,12 @@ class Entity;
class Renderer;
class NodeManagers;
-class Q_AUTOTEST_EXPORT PickBoundingVolumeJob : public Qt3DCore::QAspectJob, public Qt3DCore::QBoundingVolumeProvider
+class Q_AUTOTEST_EXPORT PickBoundingVolumeJob : public Qt3DCore::QAspectJob
{
public:
PickBoundingVolumeJob(Renderer *renderer);
void setRoot(Entity *root);
- QVector<Qt3DCore::QBoundingVolume *> boundingVolumes() const Q_DECL_FINAL;
static Qt3DCore::QRay3D intersectionRay(const QPoint &pos,
const QMatrix4x4 &viewMatrix,
@@ -91,7 +90,6 @@ private:
Entity *m_node;
QList<QMouseEvent> m_mouseEvents;
- QVector<Qt3DCore::QBoundingVolume *> gatherBoundingVolumes(Entity *entity) const;
void viewMatrixForCamera(const Qt3DCore::QNodeId &cameraId,
QMatrix4x4 &viewMatrix,
QMatrix4x4 &projectionMatrix) const;
@@ -99,7 +97,8 @@ private:
QVector<Qt3DCore::QNodeId> hitsForViewportAndCamera(const QPoint &pos,
const QRectF &relativeViewport,
const Qt3DCore::QNodeId &cameraId,
- Qt3DCore::QAbstractCollisionQueryService *rayCasting) const;
+ Qt3DCore::QAbstractCollisionQueryService *rayCasting,
+ Qt3DCore::QBoundingVolumeProvider *volumeProvider) const;
void clearPreviouslyHoveredPickers();
HObjectPicker m_currentPicker;
QVector<HObjectPicker> m_hoveredPickers;
diff --git a/src/render/services/qraycastingservice.cpp b/src/render/services/qraycastingservice.cpp
index 93dbc4e2e..af06b06d7 100644
--- a/src/render/services/qraycastingservice.cpp
+++ b/src/render/services/qraycastingservice.cpp
@@ -52,66 +52,120 @@ using namespace Qt3DCore;
namespace Qt3DRender {
+namespace {
+
+struct Hit
+{
+ Hit()
+ : intersects(false)
+ , distance(-1.0f)
+ {}
+
+ bool intersects;
+ float distance;
+ Qt3DCore::QNodeId id;
+ QVector3D intersection;
+};
+
+bool compareHitsDistance(const Hit &a, const Hit &b)
+{
+ return a.distance < b.distance;
+}
+
+Hit volumeRayIntersection(const QBoundingVolume *volume, const Qt3DCore::QRay3D &ray)
+{
+ Hit hit;
+ if ((hit.intersects = volume->intersects(ray, &hit.intersection))) {
+ hit.distance = ray.projectedDistance(hit.intersection);
+ hit.id = volume->id();
+ }
+ return hit;
+}
+
+Hit reduceToFirstHit(Hit &result, const Hit &intermediate)
+{
+ if (intermediate.intersects) {
+ if (result.distance == -1.0f ||
+ (intermediate.distance >= 0.0f &&
+ intermediate.distance < result.distance))
+ result = intermediate;
+ }
+ return result;
+}
+
+// Unordered
+QVector<Hit> reduceToAllHits(QVector<Hit> &results, const Hit &intermediate)
+{
+ if (intermediate.intersects)
+ results.push_back(intermediate);
+ return results;
+}
+
+struct CollisionGathererFunctor
+{
+ Qt3DCore::QRay3D ray;
+
+ typedef Hit result_type;
+
+ Hit operator ()(const QBoundingVolume *volume) const
+ {
+ return volumeRayIntersection(volume, ray);
+ }
+};
+
+} // anonymous
+
+
QCollisionQueryResult QRayCastingServicePrivate::collides(const Qt3DCore::QRay3D &ray, Qt3DCore::QBoundingVolumeProvider *provider,
Qt3DCore::QAbstractCollisionQueryService::QueryMode mode, const Qt3DCore::QQueryHandle &handle)
{
Q_Q(QRayCastingService);
- const QVector<QBoundingVolume *> spheres(provider->boundingVolumes());
+ const QVector<QBoundingVolume *> volumes(provider->boundingVolumes());
QCollisionQueryResult result;
q->setResultHandle(result, handle);
+ CollisionGathererFunctor gathererFunctor;
+ gathererFunctor.ray = ray;
+
if (mode == QAbstractCollisionQueryService::FirstHit) {
- QVector3D intersection;
- float collidingPointDistance = -1.0f;
- QNodeId collidingSphere;
-
- Q_FOREACH (QBoundingVolume *bs, spheres) {
- if (bs->intersects(ray, &intersection)) {
- const float distanceFromRay = ray.projectedDistance(intersection);
-
- if (collidingPointDistance == -1.0f || (distanceFromRay >= 0.0f && distanceFromRay < collidingPointDistance)) {
- collidingPointDistance = distanceFromRay;
- collidingSphere = bs->id();
- }
- }
- }
-
- if (!collidingSphere.isNull()) {
- q->addEntityHit(result, collidingSphere);
- }
-
- } else if (mode == QAbstractCollisionQueryService::AllHits) {
- Q_FOREACH (QBoundingVolume *bs, spheres) {
- if (bs->intersects(ray))
- q->addEntityHit(result, bs->id());
- }
+ Hit firstHit = QtConcurrent::blockingMappedReduced<Hit>(volumes, gathererFunctor, reduceToFirstHit);
+ if (firstHit.intersects)
+ q->addEntityHit(result, firstHit.id);
+ } else {
+ QVector<Hit> hits = QtConcurrent::blockingMappedReduced<QVector<Hit> >(volumes, gathererFunctor, reduceToAllHits);
+ std::sort(hits.begin(), hits.end(), compareHitsDistance);
+ Q_FOREACH (const Hit &hit, hits)
+ q->addEntityHit(result, hit.id);
}
+
return result;
}
-QRayCastingServicePrivate::QRayCastingServicePrivate(const QString &description, QBoundingVolumeProvider *provider)
+QRayCastingServicePrivate::QRayCastingServicePrivate(const QString &description)
: QAbstractCollisionQueryServicePrivate(description)
, m_handlesCount(0)
- , m_boundingProvider(provider)
{
}
-QRayCastingService::QRayCastingService(Qt3DCore::QBoundingVolumeProvider *provider)
- : QAbstractCollisionQueryService(*new QRayCastingServicePrivate(QStringLiteral("Collision detection service using Ray Casting"),
- provider))
+QRayCastingService::QRayCastingService()
+ : QAbstractCollisionQueryService(*new QRayCastingServicePrivate(QStringLiteral("Collision detection service using Ray Casting")))
{
}
-Qt3DCore::QQueryHandle QRayCastingService::query(const Qt3DCore::QRay3D &ray, QAbstractCollisionQueryService::QueryMode mode)
+Qt3DCore::QQueryHandle QRayCastingService::query(const Qt3DCore::QRay3D &ray,
+ QAbstractCollisionQueryService::QueryMode mode,
+ Qt3DCore::QBoundingVolumeProvider *provider)
{
Q_D(QRayCastingService);
QQueryHandle handle = d->m_handlesCount.fetchAndStoreOrdered(1);
- // TODO: Implement run using jobs to avoid multiple threadpool
+
+ // Blocking mapReduce
+
FutureQueryResult future = QtConcurrent::run(d, &QRayCastingServicePrivate::collides,
- ray, d->m_boundingProvider, mode, handle);
+ ray, provider, mode, handle);
d->m_results.insert(handle, future);
return handle;
diff --git a/src/render/services/qraycastingservice.h b/src/render/services/qraycastingservice.h
index 680d4c092..2982c161c 100644
--- a/src/render/services/qraycastingservice.h
+++ b/src/render/services/qraycastingservice.h
@@ -54,9 +54,9 @@ class QRayCastingServicePrivate;
class QT3DRENDERSHARED_EXPORT QRayCastingService : public Qt3DCore::QAbstractCollisionQueryService
{
public:
- explicit QRayCastingService(Qt3DCore::QBoundingVolumeProvider *provider);
+ QRayCastingService();
- Qt3DCore::QQueryHandle query(const Qt3DCore::QRay3D &ray, QueryMode mode) Q_DECL_OVERRIDE;
+ Qt3DCore::QQueryHandle query(const Qt3DCore::QRay3D &ray, QueryMode mode, Qt3DCore::QBoundingVolumeProvider *provider) Q_DECL_OVERRIDE;
Qt3DCore::QCollisionQueryResult fetchResult(const Qt3DCore::QQueryHandle &handle) Q_DECL_OVERRIDE;
QVector<Qt3DCore::QCollisionQueryResult> fetchAllResults() const Q_DECL_OVERRIDE;
diff --git a/src/render/services/qraycastingservice_p.h b/src/render/services/qraycastingservice_p.h
index 95b455ee1..252c50bfd 100644
--- a/src/render/services/qraycastingservice_p.h
+++ b/src/render/services/qraycastingservice_p.h
@@ -71,7 +71,7 @@ typedef QFuture<Qt3DCore::QCollisionQueryResult> FutureQueryResult;
class QRayCastingServicePrivate : public Qt3DCore::QAbstractCollisionQueryServicePrivate
{
public:
- QRayCastingServicePrivate(const QString &description, Qt3DCore::QBoundingVolumeProvider *provider);
+ QRayCastingServicePrivate(const QString &description);
Qt3DCore::QCollisionQueryResult collides(const Qt3DCore::QRay3D &ray,
Qt3DCore::QBoundingVolumeProvider *provider,
@@ -89,8 +89,6 @@ public:
QHash<Qt3DCore::QQueryHandle, FutureQueryResult> m_results;
QAtomicInt m_handlesCount;
-
- Qt3DCore::QBoundingVolumeProvider *m_boundingProvider;
};
} // namespace Qt3DRender
diff --git a/tests/auto/render/raycasting/tst_raycasting.cpp b/tests/auto/render/raycasting/tst_raycasting.cpp
index 57a22a8ee..ced9bb136 100644
--- a/tests/auto/render/raycasting/tst_raycasting.cpp
+++ b/tests/auto/render/raycasting/tst_raycasting.cpp
@@ -133,10 +133,12 @@ void tst_RayCasting::shouldReturnValidHandle()
Sphere v1;
MyBoudingVolumesProvider provider = QVector<QBoundingVolume *>() << &v1;
- QRayCastingService service(&provider);
+ QRayCastingService service;
// WHEN
- QQueryHandle handle = service.query(ray, QAbstractCollisionQueryService::AllHits);
+ QQueryHandle handle = service.query(ray,
+ QAbstractCollisionQueryService::AllHits,
+ &provider);
// THEN
QVERIFY(handle >= 0);
@@ -152,10 +154,14 @@ void tst_RayCasting::shouldReturnResultForEachHandle()
QVector<QBoundingVolume *> volumes;
MyBoudingVolumesProvider provider(volumes);
- QRayCastingService service(&provider);
+ QRayCastingService service;
- QQueryHandle handle1 = service.query(ray, QAbstractCollisionQueryService::AllHits);
- QQueryHandle handle2 = service.query(ray, QAbstractCollisionQueryService::FirstHit);
+ QQueryHandle handle1 = service.query(ray,
+ QAbstractCollisionQueryService::AllHits,
+ &provider);
+ QQueryHandle handle2 = service.query(ray,
+ QAbstractCollisionQueryService::FirstHit,
+ &provider);
// WHEN
QCollisionQueryResult result2 = service.fetchResult(handle2);
@@ -173,11 +179,15 @@ void tst_RayCasting::shouldReturnAllResults()
QVector<QBoundingVolume *> volumes;
MyBoudingVolumesProvider provider(volumes);
- QRayCastingService service(&provider);
+ QRayCastingService service;
QVector<QQueryHandle> handles;
- handles.append(service.query(ray, QAbstractCollisionQueryService::AllHits));
- handles.append(service.query(ray, QAbstractCollisionQueryService::FirstHit));
+ handles.append(service.query(ray,
+ QAbstractCollisionQueryService::AllHits,
+ &provider));
+ handles.append(service.query(ray,
+ QAbstractCollisionQueryService::FirstHit,
+ &provider));
// WHEN
QVector<QCollisionQueryResult> results = service.fetchAllResults();
@@ -222,7 +232,7 @@ void tst_RayCasting::shouldReturnHits_data()
QTest::newRow("All hits, Three sphere intersect") << ray
<< (QVector<QBoundingVolume *> () << volumeAt(0) << volumeAt(3) << volumeAt(6) << volumeAt(2))
- << (QVector<QNodeId>() << volumeAt(0)->id() << volumeAt(6)->id() << volumeAt(2)->id())
+ << (QVector<QNodeId>() << volumeAt(0)->id() << volumeAt(2)->id() << volumeAt(6)->id())
<< QAbstractCollisionQueryService::AllHits;
QTest::newRow("All hits, No sphere intersect") << ray
@@ -231,7 +241,7 @@ void tst_RayCasting::shouldReturnHits_data()
<< QAbstractCollisionQueryService::AllHits;
QTest::newRow("Sphere 1 intersect, returns First Hit") << ray
- << (QVector<QBoundingVolume *> () << volumeAt(0) << volumeAt(3) << volumeAt(1))
+ << (QVector<QBoundingVolume *> () << volumeAt(0) << volumeAt(3) << volumeAt(6))
<< (QVector<QNodeId>() << volumeAt(0)->id())
<< QAbstractCollisionQueryService::FirstHit;
@@ -260,10 +270,10 @@ void tst_RayCasting::shouldReturnHits()
QFETCH(QAbstractCollisionQueryService::QueryMode, queryMode);
MyBoudingVolumesProvider provider(volumes);
- QRayCastingService service(&provider);
+ QRayCastingService service;
// WHEN
- QQueryHandle handle = service.query(ray, queryMode);
+ QQueryHandle handle = service.query(ray, queryMode, &provider);
QCollisionQueryResult result = service.fetchResult(handle);
// THEN
@@ -283,10 +293,12 @@ void tst_RayCasting::shouldUseProvidedBoudingVolumes()
MyBoudingVolumesProvider provider(QVector<QBoundingVolume *>() << &sphere1 << &sphere4 << &sphere3);
QVector<QNodeId> hits(QVector<QNodeId>() << sphere1.id() << sphere3.id());
- QRayCastingService service(&provider);
+ QRayCastingService service;
// WHEN
- QQueryHandle handle = service.query(ray, QAbstractCollisionQueryService::AllHits);
+ QQueryHandle handle = service.query(ray,
+ QAbstractCollisionQueryService::AllHits,
+ &provider);
QCollisionQueryResult result = service.fetchResult(handle);
// THEN