diff --git a/Core/include/Acts/Navigation/DetectorNavigator.hpp b/Core/include/Acts/Navigation/DetectorNavigator.hpp index 894238be91b0..2c1ba1df8c9a 100644 --- a/Core/include/Acts/Navigation/DetectorNavigator.hpp +++ b/Core/include/Acts/Navigation/DetectorNavigator.hpp @@ -19,6 +19,8 @@ #include "Acts/Propagator/Propagator.hpp" #include "Acts/Surfaces/BoundaryCheck.hpp" #include "Acts/Surfaces/Surface.hpp" +#include "Acts/Utilities/BoundingBox.hpp" +#include "Acts/Utilities/Frustum.hpp" #include "Acts/Utilities/Logger.hpp" #include @@ -30,12 +32,20 @@ #include namespace Acts::Experimental { + using Frustum3 = Acts::Frustum; + using BoundingBox = + Acts::AxisAlignedBoundingBox; class DetectorNavigator { public: struct Config { /// Detector for this Navigation const Detector* detector = nullptr; + /// The octree for the world + const BoundingBox* topBox = nullptr; + /// The current frustum + std::shared_ptr frustum = nullptr; /// Configuration for this Navigator /// stop at every sensitive surface (whether it has material or not) @@ -44,6 +54,8 @@ class DetectorNavigator { bool resolveMaterial = true; /// stop at every surface regardless what it is bool resolvePassive = false; + /// using the frustum navigator + bool frustumNavigator = false; }; /// Nested State struct @@ -147,6 +159,16 @@ class DetectorNavigator { if (nState.currentDetector == nullptr) { ACTS_VERBOSE("Assigning detector from the config."); nState.currentDetector = m_cfg.detector; + if (m_cfg.frustumNavigator) { + if (!m_cfg.topBox) { + throw std::invalid_argument("DetectorNavigator: no octree assigned for frustum navigator"); + } + ACTS_VERBOSE("Assigning top box of the octree for frustum navigator."); + nState.topBox = m_cfg.topBox; + nState.frustum = m_cfg.frustum; + } else if (m_cfg.topBox) { + throw std::invalid_argument("DetectorNavigator: octree assigned but frustum navigator not enabled"); + } } if (nState.currentDetector == nullptr) { throw std::invalid_argument("DetectorNavigator: no detector assigned"); diff --git a/Core/include/Acts/Navigation/NavigationState.hpp b/Core/include/Acts/Navigation/NavigationState.hpp index 1cd752d940a1..52d9bae64094 100644 --- a/Core/include/Acts/Navigation/NavigationState.hpp +++ b/Core/include/Acts/Navigation/NavigationState.hpp @@ -12,7 +12,9 @@ #include "Acts/Definitions/Units.hpp" #include "Acts/Geometry/GeometryContext.hpp" #include "Acts/Surfaces/BoundaryCheck.hpp" +#include "Acts/Utilities/BoundingBox.hpp" #include "Acts/Utilities/Delegate.hpp" +#include "Acts/Utilities/Frustum.hpp" #include "Acts/Utilities/Intersection.hpp" #include @@ -21,6 +23,7 @@ namespace Acts { +using Frustum3 = Acts::Frustum; class Surface; namespace Experimental { @@ -28,6 +31,9 @@ namespace Experimental { class Portal; class Detector; class DetectorVolume; +using BoundingBox = + Acts::AxisAlignedBoundingBox; /// @brief A navigation state struct that is holding the current navigation information /// @@ -80,6 +86,12 @@ struct NavigationState { /// The current portal, i.e the position is on portal const Portal* currentPortal = nullptr; + /// The octree for the world + const BoundingBox* topBox = nullptr; + + /// The current frustum + std::shared_ptr frustum = nullptr; + /// That are the candidate surfaces to process SurfaceCandidates surfaceCandidates = {}; std::size_t surfaceCandidateIndex = 0; diff --git a/Core/include/Acts/Navigation/SurfaceCandidatesUpdaters.hpp b/Core/include/Acts/Navigation/SurfaceCandidatesUpdaters.hpp index 3c707fcc731e..682da426e622 100644 --- a/Core/include/Acts/Navigation/SurfaceCandidatesUpdaters.hpp +++ b/Core/include/Acts/Navigation/SurfaceCandidatesUpdaters.hpp @@ -91,6 +91,65 @@ struct AllPortalsAndSurfacesImpl : public INavigationDelegate { } }; +struct FrustumNavigation : public IInternalNavigation { + /// The frustum navigation + /// + /// @param gctx is the Geometry context of this call + /// @param nState is the navigation state to be updated + /// + /// @note that the intersections are ordered, such that the + /// smallest intersection pathlength >= overstep tolerance is the lowest + /// + /// @return an ordered list of portal and surface candidates + inline void update(const GeometryContext& gctx, + NavigationState& nState) const { + if (nState.currentDetector == nullptr) { + throw std::runtime_error( + "FrustumNavigation: no detector volume set to navigation state."); + } + // Create the frustum if it's not set + if (nState.frustum == nullptr) { + nState.frustum = std::make_shared(nState.position, nState.direction, M_PI/4); + } + //Check if we leave the frustum, reset candidates if so + const auto& normals = nState.frustum->normals(); + const bool outside = std::any_of(normals.begin(), normals.end(), [&nState](const auto& normal){ + return (nState.position - nState.frustum->origin()).dot(normal) >= 0;}); + if(outside){ + nState.surfaceCandidates.clear(); + nState.frustum = std::make_shared(nState.position, nState.direction, M_PI/4); + } + + // A volume switch has happened, or we left the frustum, update list of portals & surfaces + if (nState.surfaceCandidates.empty()) { + // Fill internal portals if existing + auto topBoxCopy = nState.topBox; + while(topBoxCopy){ + if(topBoxCopy->intersect(*nState.frustum)){ + if(topBoxCopy->hasEntity()){ + const auto& portals = topBoxCopy->entity()->portals(); + const auto& surfaces = topBoxCopy->entity()->surfaces(); + PortalsFiller::fill(nState, portals); + SurfacesFiller::fill(nState, surfaces); + topBoxCopy = topBoxCopy->getSkip(); + } else { + topBoxCopy = topBoxCopy->getLeftChild(); + } + } else { + topBoxCopy = topBoxCopy->getSkip(); + } + } + } + // Assign the new volume + const auto& portals = nState.currentVolume->portals(); + const auto& surfaces = nState.currentVolume->surfaces(); + PortalsFiller::fill(nState, portals); + SurfacesFiller::fill(nState, surfaces); + // Update internal candidates + updateCandidates(gctx, nState); + } +}; + /// Generate a provider for all portals /// /// @return a connected navigationstate updator @@ -114,6 +173,16 @@ inline static SurfaceCandidatesUpdater tryAllPortalsAndSurfaces() { return nStateUpdater; } +/// Generate a provider for portals and surfaces inside a frustum +/// +/// @return a connected navigationstate updator +inline static InternalNavigationDelegate tryFrustumPortalsAndSurfaces() { + auto fr = std::make_unique(); + InternalNavigationDelegate nStateUpdater; + nStateUpdater.connect<&FrustumNavigation::update>(std::move(fr)); + return nStateUpdater; +} + /// @brief This holds and extracts a collection of surfaces without much /// checking, this could be e.g. support surfaces for layer structures, /// e.g.