Skip to content

Commit

Permalink
add frustum navigation
Browse files Browse the repository at this point in the history
  • Loading branch information
Matthew Harris committed Jun 18, 2024
1 parent 4a8ab5b commit edfc219
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 0 deletions.
22 changes: 22 additions & 0 deletions Core/include/Acts/Navigation/DetectorNavigator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <iomanip>
Expand All @@ -30,12 +32,20 @@
#include <boost/container/small_vector.hpp>

namespace Acts::Experimental {
using Frustum3 = Acts::Frustum<Acts::ActsScalar, 3, 3>;
using BoundingBox =
Acts::AxisAlignedBoundingBox<DetectorVolume,
Acts::ActsScalar, 3>;

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<Frustum3> frustum = nullptr;

/// Configuration for this Navigator
/// stop at every sensitive surface (whether it has material or not)
Expand All @@ -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
Expand Down Expand Up @@ -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");
Expand Down
12 changes: 12 additions & 0 deletions Core/include/Acts/Navigation/NavigationState.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <any>
Expand All @@ -21,13 +23,17 @@

namespace Acts {

using Frustum3 = Acts::Frustum<Acts::ActsScalar, 3, 3>;
class Surface;

namespace Experimental {

class Portal;
class Detector;
class DetectorVolume;
using BoundingBox =
Acts::AxisAlignedBoundingBox<DetectorVolume,
Acts::ActsScalar, 3>;

/// @brief A navigation state struct that is holding the current navigation information
///
Expand Down Expand Up @@ -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<Frustum3> frustum = nullptr;

/// That are the candidate surfaces to process
SurfaceCandidates surfaceCandidates = {};
std::size_t surfaceCandidateIndex = 0;
Expand Down
69 changes: 69 additions & 0 deletions Core/include/Acts/Navigation/SurfaceCandidatesUpdaters.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<Frustum3>(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<Frustum3>(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
Expand All @@ -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<const FrustumNavigation>();
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.
Expand Down

0 comments on commit edfc219

Please sign in to comment.