File indexing completed on 2025-07-05 08:11:08
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include "Acts/Definitions/Tolerance.hpp"
0012 #include "Acts/Geometry/GeometryIdentifier.hpp"
0013 #include "Acts/Geometry/Layer.hpp"
0014 #include "Acts/Geometry/TrackingGeometry.hpp"
0015 #include "Acts/Geometry/TrackingVolume.hpp"
0016 #include "Acts/Navigation/NavigationStream.hpp"
0017 #include "Acts/Propagator/NavigationTarget.hpp"
0018 #include "Acts/Propagator/NavigatorError.hpp"
0019 #include "Acts/Propagator/NavigatorOptions.hpp"
0020 #include "Acts/Propagator/NavigatorStatistics.hpp"
0021 #include "Acts/Surfaces/BoundaryTolerance.hpp"
0022 #include "Acts/Surfaces/Surface.hpp"
0023 #include "Acts/Utilities/Intersection.hpp"
0024 #include "Acts/Utilities/Logger.hpp"
0025 #include "Acts/Utilities/StringHelpers.hpp"
0026
0027 #include <algorithm>
0028 #include <map>
0029 #include <optional>
0030 #include <sstream>
0031 #include <string>
0032
0033 #include <boost/container/small_vector.hpp>
0034
0035 namespace Acts {
0036
0037
0038
0039
0040 template <typename object_t>
0041 struct NavigationOptions {
0042
0043 BoundaryTolerance boundaryTolerance = BoundaryTolerance::None();
0044
0045
0046
0047 bool resolveSensitive = true;
0048
0049 bool resolveMaterial = true;
0050
0051 bool resolvePassive = false;
0052
0053
0054 const object_t* startObject = nullptr;
0055
0056 const object_t* endObject = nullptr;
0057
0058
0059 std::vector<GeometryIdentifier> externalSurfaces = {};
0060
0061
0062 double nearLimit = 0;
0063
0064 double farLimit = std::numeric_limits<double>::max();
0065 };
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084 class Navigator {
0085 public:
0086 using NavigationSurfaces =
0087 boost::container::small_vector<SurfaceIntersection, 10>;
0088
0089 using NavigationLayers =
0090 boost::container::small_vector<LayerIntersection, 10>;
0091
0092 using NavigationBoundaries =
0093 boost::container::small_vector<BoundaryIntersection, 4>;
0094
0095 using ExternalSurfaces = std::multimap<std::uint64_t, GeometryIdentifier>;
0096
0097 using GeometryVersion = TrackingGeometry::GeometryVersion;
0098
0099
0100 enum struct Stage : int {
0101 initial = 0,
0102 surfaceTarget = 1,
0103 layerTarget = 2,
0104 boundaryTarget = 3,
0105 };
0106
0107
0108 struct Config {
0109
0110 std::shared_ptr<const TrackingGeometry> trackingGeometry{nullptr};
0111
0112
0113 bool resolveSensitive = true;
0114
0115 bool resolveMaterial = true;
0116
0117 bool resolvePassive = false;
0118 };
0119
0120
0121 struct Options : public NavigatorPlainOptions {
0122 explicit Options(const GeometryContext& gctx)
0123 : NavigatorPlainOptions(gctx) {}
0124
0125
0126 double surfaceTolerance = s_onSurfaceTolerance;
0127
0128
0129 double nearLimit = s_onSurfaceTolerance;
0130
0131
0132 double farLimit = std::numeric_limits<double>::max();
0133
0134
0135 ExternalSurfaces externalSurfaces = {};
0136
0137 void insertExternalSurface(GeometryIdentifier geoid) {
0138 externalSurfaces.insert(
0139 std::pair<std::uint64_t, GeometryIdentifier>(geoid.layer(), geoid));
0140 }
0141
0142 void setPlainOptions(const NavigatorPlainOptions& options) {
0143 static_cast<NavigatorPlainOptions&>(*this) = options;
0144 }
0145 };
0146
0147
0148
0149
0150
0151 struct State {
0152 explicit State(const Options& options_) : options(options_) {}
0153
0154 Options options;
0155
0156
0157
0158 NavigationSurfaces navSurfaces = {};
0159
0160 std::optional<std::size_t> navSurfaceIndex;
0161
0162
0163
0164 NavigationLayers navLayers = {};
0165
0166 std::optional<std::size_t> navLayerIndex;
0167
0168
0169
0170 NavigationBoundaries navBoundaries = {};
0171
0172 std::optional<std::size_t> navBoundaryIndex;
0173
0174 SurfaceIntersection& navSurface() {
0175 return navSurfaces.at(navSurfaceIndex.value());
0176 }
0177 LayerIntersection& navLayer() {
0178 return navLayers.at(navLayerIndex.value());
0179 }
0180 BoundaryIntersection& navBoundary() {
0181 return navBoundaries.at(navBoundaryIndex.value());
0182 }
0183
0184 const TrackingVolume* startVolume = nullptr;
0185 const Layer* startLayer = nullptr;
0186 const Surface* startSurface = nullptr;
0187 const TrackingVolume* currentVolume = nullptr;
0188 const Layer* currentLayer = nullptr;
0189 const Surface* currentSurface = nullptr;
0190 const Surface* targetSurface = nullptr;
0191
0192 bool navigationBreak = false;
0193 Stage navigationStage = Stage::initial;
0194
0195 NavigatorStatistics statistics;
0196
0197 NavigationStream stream;
0198
0199 void resetAfterLayerSwitch() {
0200 navSurfaces.clear();
0201 navSurfaceIndex.reset();
0202 }
0203
0204 void resetAfterVolumeSwitch() {
0205 resetAfterLayerSwitch();
0206
0207 navLayers.clear();
0208 navLayerIndex.reset();
0209 navBoundaries.clear();
0210 navBoundaryIndex.reset();
0211
0212 currentLayer = nullptr;
0213 }
0214
0215 void reset() {
0216 resetAfterVolumeSwitch();
0217
0218 currentVolume = nullptr;
0219 currentSurface = nullptr;
0220
0221 navigationBreak = false;
0222 navigationStage = Stage::initial;
0223 }
0224 };
0225
0226
0227
0228
0229
0230 explicit Navigator(Config cfg,
0231 std::shared_ptr<const Logger> _logger =
0232 getDefaultLogger("Navigator", Logging::Level::INFO))
0233 : m_cfg{std::move(cfg)}, m_logger{std::move(_logger)} {
0234 if (m_cfg.trackingGeometry == nullptr) {
0235 throw std::invalid_argument("Navigator: No tracking geometry provided.");
0236 }
0237 m_geometryVersion = m_cfg.trackingGeometry->geometryVersion();
0238 }
0239
0240 State makeState(const Options& options) const {
0241 State state(options);
0242 return state;
0243 }
0244
0245 const Surface* currentSurface(const State& state) const {
0246 return state.currentSurface;
0247 }
0248
0249 const TrackingVolume* currentVolume(const State& state) const {
0250 return state.currentVolume;
0251 }
0252
0253 const IVolumeMaterial* currentVolumeMaterial(const State& state) const {
0254 if (state.currentVolume == nullptr) {
0255 return nullptr;
0256 }
0257 return state.currentVolume->volumeMaterial();
0258 }
0259
0260 const Surface* startSurface(const State& state) const {
0261 return state.startSurface;
0262 }
0263
0264 const Surface* targetSurface(const State& state) const {
0265 return state.targetSurface;
0266 }
0267
0268 bool endOfWorldReached(const State& state) const {
0269 return state.currentVolume == nullptr;
0270 }
0271
0272 bool navigationBreak(const State& state) const {
0273 return state.navigationBreak;
0274 }
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286 [[nodiscard]] Result<void> initialize(State& state, const Vector3& position,
0287 const Vector3& direction,
0288 Direction propagationDirection) const {
0289 (void)propagationDirection;
0290
0291 ACTS_VERBOSE(volInfo(state) << "Initialization.");
0292
0293 auto printGeometryVersion = [](auto ver) {
0294 using enum TrackingGeometry::GeometryVersion;
0295 switch (ver) {
0296 case Gen1:
0297 return "Gen1";
0298 case Gen3:
0299 return "Gen3";
0300 default:
0301 throw std::runtime_error("Unknown geometry version.");
0302 }
0303 };
0304 ACTS_VERBOSE(volInfo(state) << "Geometry version is: "
0305 << printGeometryVersion(m_geometryVersion));
0306
0307 state.reset();
0308
0309
0310
0311 state.stream.candidates().reserve(50);
0312
0313 state.startSurface = state.options.startSurface;
0314 state.targetSurface = state.options.targetSurface;
0315
0316
0317
0318
0319
0320
0321 if (state.startSurface != nullptr &&
0322 state.startSurface->associatedLayer() != nullptr) {
0323 ACTS_VERBOSE(
0324 volInfo(state)
0325 << "Fast start initialization through association from Surface.");
0326
0327 state.startLayer = state.startSurface->associatedLayer();
0328 state.startVolume = state.startLayer->trackingVolume();
0329 } else if (state.startVolume != nullptr) {
0330 ACTS_VERBOSE(
0331 volInfo(state)
0332 << "Fast start initialization through association from Volume.");
0333
0334 state.startLayer = state.startVolume->associatedLayer(
0335 state.options.geoContext, position);
0336 } else {
0337 ACTS_VERBOSE(volInfo(state)
0338 << "Slow start initialization through search.");
0339 ACTS_VERBOSE(volInfo(state)
0340 << "Starting from position " << toString(position)
0341 << " and direction " << toString(direction));
0342
0343
0344 state.startVolume = m_cfg.trackingGeometry->lowestTrackingVolume(
0345 state.options.geoContext, position);
0346
0347 if (state.startVolume != nullptr) {
0348 state.startLayer = state.startVolume->associatedLayer(
0349 state.options.geoContext, position);
0350 } else {
0351 ACTS_ERROR(volInfo(state)
0352 << "No start volume resolved. Nothing left to do.");
0353 state.navigationBreak = true;
0354 }
0355 }
0356
0357 state.currentVolume = state.startVolume;
0358 state.currentLayer = state.startLayer;
0359 state.currentSurface = state.startSurface;
0360
0361 if (state.currentVolume != nullptr) {
0362 ACTS_VERBOSE(volInfo(state) << "Start volume resolved "
0363 << state.currentVolume->geometryId());
0364
0365 if (!state.currentVolume->inside(position,
0366 state.options.surfaceTolerance)) {
0367 ACTS_DEBUG(
0368 volInfo(state)
0369 << "We did not end up inside the expected volume. position = "
0370 << position.transpose());
0371
0372 return Result<void>::failure(NavigatorError::NotInsideExpectedVolume);
0373 }
0374 }
0375 if (state.currentLayer != nullptr) {
0376 ACTS_VERBOSE(volInfo(state) << "Start layer resolved "
0377 << state.currentLayer->geometryId());
0378 }
0379 if (state.currentSurface != nullptr) {
0380 ACTS_VERBOSE(volInfo(state) << "Start surface resolved "
0381 << state.currentSurface->geometryId());
0382
0383 if (!state.currentSurface->isOnSurface(
0384 state.options.geoContext, position, direction,
0385 BoundaryTolerance::Infinite(), state.options.surfaceTolerance)) {
0386 ACTS_DEBUG(volInfo(state)
0387 << "We did not end up on the expected surface. surface = "
0388 << state.currentSurface->geometryId()
0389 << " position = " << position.transpose()
0390 << " direction = " << direction.transpose());
0391
0392 return Result<void>::failure(NavigatorError::NotOnExpectedSurface);
0393 }
0394 }
0395
0396 return Result<void>::success();
0397 }
0398
0399
0400
0401
0402
0403
0404
0405
0406
0407
0408 NavigationTarget nextTarget(State& state, const Vector3& position,
0409 const Vector3& direction) const {
0410
0411 state.currentSurface = nullptr;
0412
0413 if (inactive(state)) {
0414 return NavigationTarget::None();
0415 }
0416
0417 ACTS_VERBOSE(volInfo(state) << "Entering Navigator::nextTarget.");
0418
0419 auto tryGetNextTarget = [&]() -> NavigationTarget {
0420
0421
0422 if (state.navigationStage == Stage::initial) {
0423 ACTS_VERBOSE(volInfo(state) << "Target surfaces.");
0424 state.navigationStage = Stage::surfaceTarget;
0425 }
0426
0427 if (state.navigationStage == Stage::surfaceTarget) {
0428 if (!state.navSurfaceIndex.has_value()) {
0429
0430 resolveSurfaces(state, position, direction);
0431 state.navSurfaceIndex = 0;
0432 } else {
0433 ++state.navSurfaceIndex.value();
0434 }
0435 if (state.navSurfaceIndex.value() < state.navSurfaces.size()) {
0436 ACTS_VERBOSE(volInfo(state) << "Target set to next surface.");
0437 return NavigationTarget(*state.navSurface().object(),
0438 state.navSurface().index(),
0439 BoundaryTolerance::None());
0440 } else {
0441
0442 ACTS_VERBOSE(volInfo(state) << "Target layers.");
0443 if (m_geometryVersion == GeometryVersion::Gen1) {
0444 state.navigationStage = Stage::layerTarget;
0445 } else {
0446 state.navigationStage = Stage::boundaryTarget;
0447 }
0448 }
0449 }
0450
0451 if (state.navigationStage == Stage::layerTarget) {
0452 if (!state.navLayerIndex.has_value()) {
0453
0454 resolveLayers(state, position, direction);
0455 state.navLayerIndex = 0;
0456 } else {
0457 ++state.navLayerIndex.value();
0458 }
0459 if (state.navLayerIndex.value() < state.navLayers.size()) {
0460 ACTS_VERBOSE(volInfo(state) << "Target set to next layer.");
0461 return NavigationTarget(*state.navLayer().first.object(),
0462 state.navLayer().first.index(),
0463 BoundaryTolerance::None());
0464 } else {
0465
0466 ACTS_VERBOSE(volInfo(state) << "Target boundaries.");
0467 state.navigationStage = Stage::boundaryTarget;
0468 }
0469 }
0470
0471 if (state.navigationStage == Stage::boundaryTarget) {
0472 if (!state.navBoundaryIndex.has_value()) {
0473
0474 resolveBoundaries(state, position, direction);
0475 state.navBoundaryIndex = 0;
0476 } else {
0477 ++state.navBoundaryIndex.value();
0478 }
0479 if (state.navBoundaryIndex.value() < state.navBoundaries.size()) {
0480 ACTS_VERBOSE(volInfo(state) << "Target set to next boundary.");
0481 return NavigationTarget(*state.navBoundary().intersection.object(),
0482 state.navBoundary().intersection.index(),
0483 BoundaryTolerance::None());
0484 } else {
0485
0486
0487 ACTS_VERBOSE(volInfo(state)
0488 << "Boundary targets exhausted. Renavigate.");
0489 }
0490 }
0491
0492 ACTS_VERBOSE(volInfo(state)
0493 << "Unknown state. No target found. Renavigate.");
0494 return NavigationTarget::None();
0495 };
0496
0497 NavigationTarget nextTarget = tryGetNextTarget();
0498 if (!nextTarget.isNone()) {
0499 return nextTarget;
0500 }
0501
0502 state.reset();
0503 ++state.statistics.nRenavigations;
0504
0505
0506
0507 state.currentVolume = m_cfg.trackingGeometry->lowestTrackingVolume(
0508 state.options.geoContext, position);
0509
0510 if (state.currentVolume == nullptr) {
0511 ACTS_VERBOSE(volInfo(state) << "No volume found, stop navigation.");
0512 state.navigationBreak = true;
0513 return NavigationTarget::None();
0514 }
0515
0516 state.currentLayer = state.currentVolume->associatedLayer(
0517 state.options.geoContext, position);
0518
0519 ACTS_VERBOSE(volInfo(state) << "Resolved volume and layer.");
0520
0521
0522 nextTarget = tryGetNextTarget();
0523 if (!nextTarget.isNone()) {
0524 return nextTarget;
0525 }
0526
0527 ACTS_VERBOSE(
0528 volInfo(state)
0529 << "No targets found again, we got really lost! Stop navigation.");
0530 state.navigationBreak = true;
0531 return NavigationTarget::None();
0532 }
0533
0534
0535
0536
0537
0538
0539
0540
0541
0542
0543 bool checkTargetValid(const State& state, const Vector3& position,
0544 const Vector3& direction) const {
0545 (void)position;
0546 (void)direction;
0547
0548 return state.navigationStage != Stage::initial;
0549 }
0550
0551
0552
0553
0554
0555
0556
0557
0558
0559 void handleSurfaceReached(State& state, const Vector3& position,
0560 const Vector3& direction,
0561 const Surface& surface) const {
0562 if (inactive(state)) {
0563 return;
0564 }
0565
0566 ACTS_VERBOSE(volInfo(state) << "Entering Navigator::handleSurfaceReached.");
0567
0568 state.currentSurface = &surface;
0569
0570 ACTS_VERBOSE(volInfo(state)
0571 << "Current surface: " << state.currentSurface->geometryId());
0572
0573 if (state.navigationStage == Stage::surfaceTarget &&
0574 state.navSurface().object() == &surface) {
0575 ACTS_VERBOSE(volInfo(state) << "Handling surface status.");
0576
0577 return;
0578 }
0579
0580 if (state.navigationStage == Stage::layerTarget &&
0581 state.navLayer().first.object() == &surface) {
0582 ACTS_VERBOSE(volInfo(state) << "Handling layer status.");
0583
0584
0585 state.currentLayer = state.navLayer().second;
0586 state.navigationStage = Stage::surfaceTarget;
0587
0588
0589 state.resetAfterLayerSwitch();
0590
0591 return;
0592 }
0593
0594 if (state.navigationStage == Stage::boundaryTarget &&
0595 state.navBoundary().intersection.object() == &surface) {
0596 ACTS_VERBOSE(volInfo(state) << "Handling boundary status.");
0597
0598 if (m_geometryVersion == GeometryVersion::Gen1) {
0599
0600 const BoundarySurface* boundary = state.navBoundary().boundarySurface;
0601 assert(boundary != nullptr && "Retrieved boundary surface is nullptr");
0602 state.currentVolume = boundary->attachedVolume(state.options.geoContext,
0603 position, direction);
0604 } else {
0605 const Portal* portal = state.navBoundary().portal;
0606 assert(portal != nullptr && "Retrieved portal is nullptr");
0607 auto res = portal->resolveVolume(state.options.geoContext, position,
0608 direction);
0609 if (!res.ok()) {
0610 ACTS_ERROR(volInfo(state)
0611 << "Failed to resolve volume through portal: "
0612 << res.error().message());
0613 return;
0614 }
0615
0616 state.currentVolume = res.value();
0617 }
0618
0619
0620 state.resetAfterVolumeSwitch();
0621
0622 if (state.currentVolume != nullptr) {
0623 ACTS_VERBOSE(volInfo(state) << "Volume updated.");
0624 if (m_geometryVersion == GeometryVersion::Gen1) {
0625 state.navigationStage = Stage::layerTarget;
0626 } else {
0627 state.navigationStage = Stage::surfaceTarget;
0628 }
0629 } else {
0630 ACTS_VERBOSE(volInfo(state)
0631 << "No more volume to progress to, stopping navigation.");
0632 state.navigationBreak = true;
0633 }
0634
0635 return;
0636 }
0637
0638 ACTS_ERROR(volInfo(state) << "Surface reached but unknown state.");
0639 }
0640
0641 private:
0642
0643
0644
0645
0646
0647
0648
0649 void resolveSurfaces(State& state, const Vector3& position,
0650 const Vector3& direction) const {
0651 ACTS_VERBOSE(volInfo(state) << "Searching for compatible surfaces.");
0652
0653 if (m_geometryVersion == GeometryVersion::Gen1) {
0654 const Layer* currentLayer = state.currentLayer;
0655
0656 if (currentLayer == nullptr) {
0657 ACTS_VERBOSE(volInfo(state) << "No layer to resolve surfaces.");
0658 return;
0659 }
0660
0661 const Surface* layerSurface = ¤tLayer->surfaceRepresentation();
0662
0663 NavigationOptions<Surface> navOpts;
0664 navOpts.resolveSensitive = m_cfg.resolveSensitive;
0665 navOpts.resolveMaterial = m_cfg.resolveMaterial;
0666 navOpts.resolvePassive = m_cfg.resolvePassive;
0667 navOpts.startObject = state.currentSurface;
0668 navOpts.endObject = state.targetSurface;
0669 navOpts.nearLimit = state.options.nearLimit;
0670 navOpts.farLimit = state.options.farLimit;
0671
0672 if (!state.options.externalSurfaces.empty()) {
0673 auto layerId = layerSurface->geometryId().layer();
0674 auto externalSurfaceRange =
0675 state.options.externalSurfaces.equal_range(layerId);
0676 navOpts.externalSurfaces.reserve(
0677 state.options.externalSurfaces.count(layerId));
0678 for (auto itSurface = externalSurfaceRange.first;
0679 itSurface != externalSurfaceRange.second; itSurface++) {
0680 navOpts.externalSurfaces.push_back(itSurface->second);
0681 }
0682 }
0683
0684
0685 state.navSurfaces = currentLayer->compatibleSurfaces(
0686 state.options.geoContext, position, direction, navOpts);
0687 std::ranges::sort(state.navSurfaces,
0688 SurfaceIntersection::pathLengthOrder);
0689 } else {
0690
0691
0692 state.stream.reset();
0693 AppendOnlyNavigationStream appendOnly{state.stream};
0694 NavigationArguments args;
0695 args.position = position;
0696 args.direction = direction;
0697 args.wantsPortals = false;
0698 args.wantsSurfaces = true;
0699 state.currentVolume->initializeNavigationCandidates(args, appendOnly,
0700 logger());
0701
0702
0703
0704 ACTS_VERBOSE(volInfo(state)
0705 << "Found " << state.stream.candidates().size()
0706 << " navigation candidates.");
0707
0708 state.stream.initialize(state.options.geoContext, {position, direction},
0709 BoundaryTolerance::None(),
0710 state.options.surfaceTolerance);
0711 ACTS_VERBOSE(volInfo(state)
0712 << "Now " << state.stream.candidates().size()
0713 << " navigation candidates after initialization");
0714
0715 state.navSurfaces.clear();
0716
0717 auto it = std::ranges::find_if(
0718 state.stream.candidates(), [&](const auto& candidate) {
0719 return detail::checkPathLength(candidate.intersection.pathLength(),
0720 state.options.nearLimit,
0721 state.options.farLimit, logger());
0722 });
0723
0724 for (; it != state.stream.candidates().end(); ++it) {
0725 state.navSurfaces.emplace_back(it->intersection);
0726 }
0727 }
0728
0729
0730 if (logger().doPrint(Logging::VERBOSE)) {
0731 std::ostringstream os;
0732 os << state.navSurfaces.size();
0733 os << " surface candidates found at path(s): ";
0734 for (auto& sfc : state.navSurfaces) {
0735 os << sfc.pathLength() << " ";
0736 }
0737 logger().log(Logging::VERBOSE, os.str());
0738 }
0739
0740 if (state.navSurfaces.empty()) {
0741 ACTS_VERBOSE(volInfo(state) << "No surface candidates found.");
0742 }
0743 }
0744
0745
0746
0747
0748
0749
0750
0751
0752 void resolveLayers(State& state, const Vector3& position,
0753 const Vector3& direction) const {
0754 ACTS_VERBOSE(volInfo(state) << "Searching for compatible layers.");
0755
0756 NavigationOptions<Layer> navOpts;
0757 navOpts.resolveSensitive = m_cfg.resolveSensitive;
0758 navOpts.resolveMaterial = m_cfg.resolveMaterial;
0759 navOpts.resolvePassive = m_cfg.resolvePassive;
0760 navOpts.startObject = state.currentLayer;
0761 navOpts.nearLimit = state.options.nearLimit;
0762 navOpts.farLimit = state.options.farLimit;
0763
0764
0765 state.navLayers = state.currentVolume->compatibleLayers(
0766 state.options.geoContext, position, direction, navOpts);
0767 std::ranges::sort(state.navLayers, [](const auto& a, const auto& b) {
0768 return SurfaceIntersection::pathLengthOrder(a.first, b.first);
0769 });
0770
0771
0772 if (logger().doPrint(Logging::VERBOSE)) {
0773 std::ostringstream os;
0774 os << state.navLayers.size();
0775 os << " layer candidates found at path(s): ";
0776 for (auto& lc : state.navLayers) {
0777 os << lc.first.pathLength() << " ";
0778 }
0779 logger().log(Logging::VERBOSE, os.str());
0780 }
0781
0782 if (state.navLayers.empty()) {
0783 ACTS_VERBOSE(volInfo(state) << "No layer candidates found.");
0784 }
0785 }
0786
0787
0788
0789
0790
0791
0792
0793
0794 void resolveBoundaries(State& state, const Vector3& position,
0795 const Vector3& direction) const {
0796 ACTS_VERBOSE(volInfo(state) << "Searching for compatible boundaries.");
0797
0798 NavigationOptions<Surface> navOpts;
0799 navOpts.startObject = state.currentSurface;
0800 navOpts.nearLimit = state.options.nearLimit;
0801 navOpts.farLimit = state.options.farLimit;
0802
0803 ACTS_VERBOSE(volInfo(state)
0804 << "Try to find boundaries, we are at: " << toString(position)
0805 << ", dir: " << toString(direction));
0806
0807 if (m_geometryVersion == GeometryVersion::Gen1) {
0808
0809 state.navBoundaries = state.currentVolume->compatibleBoundaries(
0810 state.options.geoContext, position, direction, navOpts, logger());
0811 std::ranges::sort(state.navBoundaries, [](const auto& a, const auto& b) {
0812 return SurfaceIntersection::pathLengthOrder(a.intersection,
0813 b.intersection);
0814 });
0815 } else {
0816
0817 state.stream.reset();
0818 AppendOnlyNavigationStream appendOnly{state.stream};
0819 NavigationArguments args;
0820 args.position = position;
0821 args.direction = direction;
0822 args.wantsPortals = true;
0823 args.wantsSurfaces = false;
0824 state.currentVolume->initializeNavigationCandidates(args, appendOnly,
0825 logger());
0826
0827 ACTS_VERBOSE(volInfo(state)
0828 << "Found " << state.stream.candidates().size()
0829 << " navigation candidates.");
0830
0831 state.stream.initialize(state.options.geoContext, {position, direction},
0832 BoundaryTolerance::None(),
0833 state.options.surfaceTolerance);
0834
0835 state.navBoundaries.clear();
0836 for (auto& candidate : state.stream.candidates()) {
0837 if (!detail::checkPathLength(candidate.intersection.pathLength(),
0838 state.options.nearLimit,
0839 state.options.farLimit, logger())) {
0840 continue;
0841 }
0842
0843 state.navBoundaries.emplace_back(candidate.intersection, nullptr,
0844 candidate.portal);
0845 }
0846 }
0847
0848
0849 if (logger().doPrint(Logging::VERBOSE)) {
0850 std::ostringstream os;
0851 os << state.navBoundaries.size();
0852 os << " boundary candidates found at path(s): ";
0853 for (auto& bc : state.navBoundaries) {
0854 os << bc.intersection.pathLength() << " ";
0855 }
0856 logger().log(Logging::VERBOSE, os.str());
0857 }
0858
0859 if (state.navBoundaries.empty()) {
0860 ACTS_VERBOSE(volInfo(state) << "No boundary candidates found.");
0861 }
0862 }
0863
0864
0865
0866
0867
0868
0869
0870
0871 bool inactive(const State& state) const {
0872
0873 if (!m_cfg.resolveSensitive && !m_cfg.resolveMaterial &&
0874 !m_cfg.resolvePassive) {
0875 return true;
0876 }
0877
0878 if (state.navigationBreak) {
0879 return true;
0880 }
0881
0882 return false;
0883 }
0884
0885 private:
0886 template <typename propagator_state_t>
0887 std::string volInfo(const propagator_state_t& state) const {
0888 return (state.currentVolume != nullptr ? state.currentVolume->volumeName()
0889 : "No Volume") +
0890 " | ";
0891 }
0892
0893 const Logger& logger() const { return *m_logger; }
0894
0895 Config m_cfg;
0896
0897
0898 TrackingGeometry::GeometryVersion m_geometryVersion;
0899
0900 std::shared_ptr<const Logger> m_logger;
0901 };
0902
0903 }