File indexing completed on 2025-07-06 07:51:48
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Geometry/Layer.hpp"
0013 #include "Acts/Geometry/TrackingGeometry.hpp"
0014 #include "Acts/Geometry/TrackingVolume.hpp"
0015 #include "Acts/Propagator/NavigationTarget.hpp"
0016 #include "Acts/Propagator/NavigatorOptions.hpp"
0017 #include "Acts/Propagator/NavigatorStatistics.hpp"
0018 #include "Acts/Propagator/detail/NavigationHelpers.hpp"
0019 #include "Acts/Surfaces/BoundaryTolerance.hpp"
0020 #include "Acts/Surfaces/Surface.hpp"
0021 #include "Acts/Utilities/Intersection.hpp"
0022 #include "Acts/Utilities/Logger.hpp"
0023 #include "Acts/Utilities/StringHelpers.hpp"
0024
0025 #include <algorithm>
0026 #include <cstdint>
0027 #include <limits>
0028 #include <memory>
0029 #include <vector>
0030
0031 namespace Acts {
0032
0033
0034
0035
0036
0037
0038 class TryAllNavigatorBase {
0039 public:
0040
0041 struct Config {
0042
0043 std::shared_ptr<const TrackingGeometry> trackingGeometry;
0044
0045
0046 bool resolveSensitive = true;
0047
0048 bool resolveMaterial = true;
0049
0050 bool resolvePassive = false;
0051
0052
0053 BoundaryTolerance boundaryToleranceSurfaceApproach =
0054 BoundaryTolerance::None();
0055 };
0056
0057
0058 struct Options : public NavigatorPlainOptions {
0059 explicit Options(const GeometryContext& gctx)
0060 : NavigatorPlainOptions(gctx) {}
0061
0062
0063 double surfaceTolerance = s_onSurfaceTolerance;
0064
0065
0066 double nearLimit = s_onSurfaceTolerance;
0067
0068
0069 double farLimit = std::numeric_limits<double>::max();
0070
0071 void setPlainOptions(const NavigatorPlainOptions& options) {
0072 static_cast<NavigatorPlainOptions&>(*this) = options;
0073 }
0074 };
0075
0076
0077
0078
0079
0080 struct State {
0081 explicit State(const Options& options_) : options(options_) {}
0082
0083 Options options;
0084
0085
0086
0087
0088 const Surface* startSurface = nullptr;
0089
0090
0091
0092
0093 const Surface* targetSurface = nullptr;
0094
0095
0096
0097 const Surface* currentSurface = nullptr;
0098 const TrackingVolume* currentVolume = nullptr;
0099
0100
0101 std::vector<detail::NavigationObjectCandidate> navigationCandidates;
0102
0103
0104 bool navigationBreak = false;
0105
0106
0107 NavigatorStatistics statistics;
0108 };
0109
0110
0111
0112
0113
0114 TryAllNavigatorBase(Config cfg, std::unique_ptr<const Logger> logger)
0115 : m_cfg(std::move(cfg)), m_logger{std::move(logger)} {}
0116
0117 const Surface* currentSurface(const State& state) const {
0118 return state.currentSurface;
0119 }
0120
0121 const TrackingVolume* currentVolume(const State& state) const {
0122 return state.currentVolume;
0123 }
0124
0125 const IVolumeMaterial* currentVolumeMaterial(const State& state) const {
0126 if (state.currentVolume == nullptr) {
0127 return nullptr;
0128 }
0129 return state.currentVolume->volumeMaterial();
0130 }
0131
0132 const Surface* startSurface(const State& state) const {
0133 return state.startSurface;
0134 }
0135
0136 const Surface* targetSurface(const State& state) const {
0137 return state.targetSurface;
0138 }
0139
0140 bool endOfWorldReached(State& state) const {
0141 return state.currentVolume == nullptr;
0142 }
0143
0144 bool navigationBreak(const State& state) const {
0145 return state.navigationBreak;
0146 }
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157 [[nodiscard]] Result<void> initialize(State& state, const Vector3& position,
0158 const Vector3& direction,
0159 Direction propagationDirection) const {
0160 (void)propagationDirection;
0161
0162 ACTS_VERBOSE("initialize");
0163
0164 state.startSurface = state.options.startSurface;
0165 state.targetSurface = state.options.targetSurface;
0166
0167 const TrackingVolume* startVolume = nullptr;
0168
0169 if (state.startSurface != nullptr &&
0170 state.startSurface->associatedLayer() != nullptr) {
0171 ACTS_VERBOSE(
0172 "Fast start initialization through association from Surface.");
0173 const auto* startLayer = state.startSurface->associatedLayer();
0174 startVolume = startLayer->trackingVolume();
0175 } else {
0176 ACTS_VERBOSE("Slow start initialization through search.");
0177 ACTS_VERBOSE("Starting from position " << toString(position)
0178 << " and direction "
0179 << toString(direction));
0180 startVolume = m_cfg.trackingGeometry->lowestTrackingVolume(
0181 state.options.geoContext, position);
0182 }
0183
0184
0185 {
0186 state.currentVolume = startVolume;
0187 if (state.currentVolume != nullptr) {
0188 ACTS_VERBOSE(volInfo(state) << "Start volume resolved.");
0189 } else {
0190 ACTS_ERROR("Start volume not resolved.");
0191 }
0192
0193 state.currentSurface = state.startSurface;
0194 if (state.currentSurface != nullptr) {
0195 ACTS_VERBOSE(volInfo(state) << "Current surface set to start surface "
0196 << state.currentSurface->geometryId());
0197 } else {
0198 ACTS_VERBOSE(volInfo(state) << "No start surface set.");
0199 }
0200 }
0201
0202 return Result<void>::success();
0203 }
0204
0205 protected:
0206
0207 void initializeVolumeCandidates(State& state) const {
0208 const TrackingVolume* volume = state.currentVolume;
0209 ACTS_VERBOSE(volInfo(state) << "Initialize volume");
0210
0211 if (volume == nullptr) {
0212 state.navigationBreak = true;
0213 ACTS_VERBOSE(volInfo(state) << "No volume set. Good luck.");
0214 return;
0215 }
0216
0217 emplaceAllVolumeCandidates(
0218 state.navigationCandidates, *volume, m_cfg.resolveSensitive,
0219 m_cfg.resolveMaterial, m_cfg.resolvePassive,
0220 m_cfg.boundaryToleranceSurfaceApproach, logger());
0221 }
0222
0223 std::string volInfo(const State& state) const {
0224 return (state.currentVolume != nullptr ? state.currentVolume->volumeName()
0225 : "No Volume") +
0226 " | ";
0227 }
0228
0229 const Logger& logger() const { return *m_logger; }
0230
0231 Config m_cfg;
0232
0233 std::unique_ptr<const Logger> m_logger;
0234 };
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245 class TryAllNavigator : public TryAllNavigatorBase {
0246 public:
0247 using Config = TryAllNavigatorBase::Config;
0248 using Options = TryAllNavigatorBase::Options;
0249
0250
0251 struct State : public TryAllNavigatorBase::State {
0252 explicit State(const Options& options_)
0253 : TryAllNavigatorBase::State(options_) {}
0254
0255 std::vector<detail::IntersectedNavigationObject> currentCandidates;
0256 };
0257
0258
0259
0260
0261
0262 explicit TryAllNavigator(Config cfg, std::unique_ptr<const Logger> logger =
0263 getDefaultLogger("TryAllNavigator",
0264 Logging::INFO))
0265 : TryAllNavigatorBase(std::move(cfg), std::move(logger)) {}
0266
0267 State makeState(const Options& options) const {
0268 State state(options);
0269 return state;
0270 }
0271
0272 using TryAllNavigatorBase::currentSurface;
0273 using TryAllNavigatorBase::currentVolume;
0274 using TryAllNavigatorBase::currentVolumeMaterial;
0275 using TryAllNavigatorBase::endOfWorldReached;
0276 using TryAllNavigatorBase::navigationBreak;
0277 using TryAllNavigatorBase::startSurface;
0278 using TryAllNavigatorBase::targetSurface;
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288
0289 [[nodiscard]] Result<void> initialize(State& state, const Vector3& position,
0290 const Vector3& direction,
0291 Direction propagationDirection) const {
0292 auto baseRes = TryAllNavigatorBase::initialize(state, position, direction,
0293 propagationDirection);
0294 if (!baseRes.ok()) {
0295 return baseRes.error();
0296 }
0297
0298
0299 reinitializeCandidates(state);
0300
0301 return Result<void>::success();
0302 }
0303
0304
0305
0306
0307
0308
0309
0310
0311
0312
0313
0314
0315 NavigationTarget nextTarget(State& state, const Vector3& position,
0316 const Vector3& direction) const {
0317
0318 state.currentSurface = nullptr;
0319
0320
0321 if (state.navigationBreak) {
0322 return NavigationTarget::None();
0323 }
0324
0325 ACTS_VERBOSE(volInfo(state) << "nextTarget");
0326
0327 double nearLimit = state.options.nearLimit;
0328 double farLimit = state.options.farLimit;
0329
0330
0331 if (!state.currentCandidates.empty()) {
0332 const detail::IntersectedNavigationObject& previousCandidate =
0333 state.currentCandidates.front();
0334
0335 const Surface& surface = *previousCandidate.intersection.object();
0336 std::uint8_t index = previousCandidate.intersection.index();
0337 BoundaryTolerance boundaryTolerance = previousCandidate.boundaryTolerance;
0338
0339 auto intersection = surface.intersect(
0340 state.options.geoContext, position, direction, boundaryTolerance,
0341 state.options.surfaceTolerance)[index];
0342
0343 if (intersection.pathLength() < 0) {
0344 nearLimit = std::min(nearLimit, intersection.pathLength() -
0345 state.options.surfaceTolerance);
0346 farLimit = -state.options.surfaceTolerance;
0347
0348 ACTS_VERBOSE(volInfo(state)
0349 << "handle overstepping with nearLimit " << nearLimit
0350 << " and farLimit " << farLimit);
0351 }
0352 }
0353
0354 std::vector<detail::IntersectedNavigationObject> intersectionCandidates;
0355
0356
0357 for (const auto& candidate : state.navigationCandidates) {
0358 auto intersections =
0359 candidate.intersect(state.options.geoContext, position, direction,
0360 state.options.surfaceTolerance);
0361 for (const auto& intersection : intersections.first.split()) {
0362
0363 if (!intersection.isValid() ||
0364 !detail::checkPathLength(intersection.pathLength(), nearLimit,
0365 farLimit)) {
0366 continue;
0367 }
0368
0369 intersectionCandidates.emplace_back(intersection, intersections.second,
0370 candidate.boundaryTolerance);
0371 }
0372 }
0373
0374 std::ranges::sort(intersectionCandidates,
0375 detail::IntersectedNavigationObject::forwardOrder);
0376
0377 ACTS_VERBOSE(volInfo(state) << "found " << intersectionCandidates.size()
0378 << " intersections");
0379
0380 NavigationTarget nextTarget = NavigationTarget::None();
0381 state.currentCandidates.clear();
0382
0383 for (const auto& candidate : intersectionCandidates) {
0384 const auto& intersection = candidate.intersection;
0385 const Surface& surface = *intersection.object();
0386 BoundaryTolerance boundaryTolerance = candidate.boundaryTolerance;
0387
0388 if (intersection.status() == IntersectionStatus::onSurface) {
0389 ACTS_ERROR(volInfo(state)
0390 << "We are on surface " << surface.geometryId()
0391 << " before trying to reach it. This should not happen. "
0392 "Good luck.");
0393 continue;
0394 }
0395
0396 if (intersection.status() == IntersectionStatus::reachable) {
0397 nextTarget =
0398 NavigationTarget(surface, intersection.index(), boundaryTolerance);
0399 break;
0400 }
0401 }
0402
0403 state.currentCandidates = std::move(intersectionCandidates);
0404
0405 if (nextTarget.isNone()) {
0406 ACTS_VERBOSE(volInfo(state) << "no target found");
0407 } else {
0408 ACTS_VERBOSE(volInfo(state)
0409 << "next target is " << nextTarget.surface->geometryId());
0410 }
0411
0412 return nextTarget;
0413 }
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423
0424
0425
0426
0427
0428 bool checkTargetValid(const State& state, const Vector3& position,
0429 const Vector3& direction) const {
0430 (void)state;
0431 (void)position;
0432 (void)direction;
0433
0434 return false;
0435 }
0436
0437
0438
0439
0440
0441
0442
0443
0444
0445 void handleSurfaceReached(State& state, const Vector3& position,
0446 const Vector3& direction,
0447 const Surface& ) const {
0448
0449 if (state.navigationBreak) {
0450 return;
0451 }
0452
0453 ACTS_VERBOSE(volInfo(state) << "handleSurfaceReached");
0454
0455 if (state.currentCandidates.empty()) {
0456 ACTS_VERBOSE(volInfo(state) << "No current candidate set.");
0457 return;
0458 }
0459
0460 assert(state.currentSurface == nullptr && "Current surface must be reset.");
0461
0462
0463
0464 std::vector<detail::IntersectedNavigationObject> hitCandidates;
0465
0466 for (const auto& candidate : state.currentCandidates) {
0467 const Surface& surface = *candidate.intersection.object();
0468 std::uint8_t index = candidate.intersection.index();
0469 BoundaryTolerance boundaryTolerance = BoundaryTolerance::None();
0470
0471 auto intersection = surface.intersect(
0472 state.options.geoContext, position, direction, boundaryTolerance,
0473 state.options.surfaceTolerance)[index];
0474
0475 if (intersection.status() == IntersectionStatus::onSurface) {
0476 hitCandidates.emplace_back(candidate);
0477 }
0478 }
0479
0480 state.currentCandidates.clear();
0481
0482 ACTS_VERBOSE(volInfo(state)
0483 << "Found " << hitCandidates.size()
0484 << " intersections on surface with bounds check.");
0485
0486 if (hitCandidates.empty()) {
0487 ACTS_VERBOSE(volInfo(state) << "No hit candidates found.");
0488 return;
0489 }
0490
0491 if (hitCandidates.size() > 1) {
0492 ACTS_VERBOSE(volInfo(state)
0493 << "Only using first intersection within bounds.");
0494 }
0495
0496
0497 const auto candidate = hitCandidates.front();
0498 const auto& intersection = candidate.intersection;
0499 const Surface& surface = *intersection.object();
0500
0501 ACTS_VERBOSE(volInfo(state) << "Surface " << surface.geometryId()
0502 << " successfully hit, storing it.");
0503 state.currentSurface = &surface;
0504
0505 if (candidate.template checkType<Surface>()) {
0506 ACTS_VERBOSE(volInfo(state) << "This is a surface");
0507 } else if (candidate.template checkType<Layer>()) {
0508 ACTS_VERBOSE(volInfo(state) << "This is a layer");
0509 } else if (candidate.template checkType<BoundarySurface>()) {
0510 ACTS_VERBOSE(volInfo(state)
0511 << "This is a boundary. Reinitialize navigation");
0512
0513 const auto& boundary = *candidate.template object<BoundarySurface>();
0514
0515 state.currentVolume = boundary.attachedVolume(state.options.geoContext,
0516 position, direction);
0517
0518 ACTS_VERBOSE(volInfo(state) << "Switched volume");
0519
0520 reinitializeCandidates(state);
0521 } else {
0522 ACTS_ERROR(volInfo(state) << "Unknown intersection type");
0523 }
0524 }
0525
0526 private:
0527
0528 void reinitializeCandidates(State& state) const {
0529 state.navigationCandidates.clear();
0530 state.currentCandidates.clear();
0531
0532 initializeVolumeCandidates(state);
0533 }
0534 };
0535
0536
0537
0538
0539
0540
0541
0542
0543
0544
0545
0546
0547
0548
0549
0550 class TryAllOverstepNavigator : public TryAllNavigatorBase {
0551 public:
0552 using Config = TryAllNavigatorBase::Config;
0553
0554 using Options = TryAllNavigatorBase::Options;
0555
0556
0557
0558
0559
0560 struct State : public TryAllNavigatorBase::State {
0561 explicit State(const Options& options_)
0562 : TryAllNavigatorBase::State(options_) {}
0563
0564
0565 std::vector<detail::IntersectedNavigationObject> activeCandidates;
0566
0567 int activeCandidateIndex = -1;
0568
0569
0570 std::optional<Vector3> lastPosition;
0571
0572
0573 const detail::IntersectedNavigationObject& activeCandidate() const {
0574 return activeCandidates.at(activeCandidateIndex);
0575 }
0576
0577 bool endOfCandidates() const {
0578 return activeCandidateIndex >= static_cast<int>(activeCandidates.size());
0579 }
0580 };
0581
0582
0583
0584
0585
0586 explicit TryAllOverstepNavigator(
0587 Config cfg, std::unique_ptr<const Logger> logger = getDefaultLogger(
0588 "TryAllOverstepNavigator", Logging::INFO))
0589 : TryAllNavigatorBase(std::move(cfg), std::move(logger)) {}
0590
0591 State makeState(const Options& options) const {
0592 State state(options);
0593 return state;
0594 }
0595
0596 using TryAllNavigatorBase::currentSurface;
0597 using TryAllNavigatorBase::currentVolume;
0598 using TryAllNavigatorBase::currentVolumeMaterial;
0599 using TryAllNavigatorBase::endOfWorldReached;
0600 using TryAllNavigatorBase::navigationBreak;
0601 using TryAllNavigatorBase::startSurface;
0602 using TryAllNavigatorBase::targetSurface;
0603
0604
0605
0606
0607
0608
0609
0610
0611
0612
0613 [[nodiscard]] Result<void> initialize(State& state, const Vector3& position,
0614 const Vector3& direction,
0615 Direction propagationDirection) const {
0616 auto baseRes = TryAllNavigatorBase::initialize(state, position, direction,
0617 propagationDirection);
0618 if (!baseRes.ok()) {
0619 return baseRes.error();
0620 }
0621
0622
0623 reinitializeCandidates(state);
0624
0625 state.lastPosition.reset();
0626
0627 return Result<void>::success();
0628 }
0629
0630
0631
0632
0633
0634
0635
0636
0637
0638
0639
0640
0641 NavigationTarget nextTarget(State& state, const Vector3& position,
0642 const Vector3& direction) const {
0643 (void)direction;
0644
0645
0646 state.currentSurface = nullptr;
0647
0648
0649 if (state.navigationBreak) {
0650 return NavigationTarget::None();
0651 }
0652
0653 ACTS_VERBOSE(volInfo(state) << "nextTarget");
0654
0655
0656 if (!state.lastPosition.has_value() && state.endOfCandidates()) {
0657 ACTS_VERBOSE(
0658 volInfo(state)
0659 << "Initial position, nothing to do, blindly stepping forward.");
0660 state.lastPosition = position;
0661 return NavigationTarget::None();
0662 }
0663
0664 if (state.endOfCandidates()) {
0665 ACTS_VERBOSE(volInfo(state) << "evaluate blind step");
0666
0667 Vector3 stepStart = state.lastPosition.value();
0668 Vector3 stepEnd = position;
0669 Vector3 step = stepEnd - stepStart;
0670 double stepDistance = step.norm();
0671 if (stepDistance < std::numeric_limits<double>::epsilon()) {
0672 ACTS_ERROR(volInfo(state) << "Step distance is zero. " << stepDistance);
0673 }
0674 Vector3 stepDirection = step.normalized();
0675
0676 double nearLimit = -stepDistance + state.options.surfaceTolerance;
0677 double farLimit = 0;
0678
0679 state.lastPosition.reset();
0680 state.activeCandidates.clear();
0681 state.activeCandidateIndex = -1;
0682
0683
0684 for (const auto& candidate : state.navigationCandidates) {
0685 auto intersections =
0686 candidate.intersect(state.options.geoContext, stepEnd,
0687 stepDirection, state.options.surfaceTolerance);
0688 for (const auto& intersection : intersections.first.split()) {
0689
0690 if (!intersection.isValid() ||
0691 !detail::checkPathLength(intersection.pathLength(), nearLimit,
0692 farLimit)) {
0693 continue;
0694 }
0695
0696 state.activeCandidates.emplace_back(
0697 intersection, intersections.second, candidate.boundaryTolerance);
0698 }
0699 }
0700
0701 std::ranges::sort(state.activeCandidates,
0702 detail::IntersectedNavigationObject::forwardOrder);
0703
0704 ACTS_VERBOSE(volInfo(state) << "Found " << state.activeCandidates.size()
0705 << " intersections");
0706
0707 for (const auto& candidate : state.activeCandidates) {
0708 ACTS_VERBOSE("found candidate "
0709 << candidate.intersection.object()->geometryId());
0710 }
0711 }
0712
0713 ++state.activeCandidateIndex;
0714
0715 if (state.endOfCandidates()) {
0716 ACTS_VERBOSE(volInfo(state)
0717 << "No target found, blindly stepping forward.");
0718 state.lastPosition = position;
0719 return NavigationTarget::None();
0720 }
0721
0722 ACTS_VERBOSE(volInfo(state) << "handle active candidates");
0723
0724 ACTS_VERBOSE(volInfo(state)
0725 << (state.activeCandidates.size() - state.activeCandidateIndex)
0726 << " out of " << state.activeCandidates.size()
0727 << " surfaces remain to try.");
0728
0729 const auto& candidate = state.activeCandidate();
0730 const auto& intersection = candidate.intersection;
0731 const Surface& surface = *intersection.object();
0732 BoundaryTolerance boundaryTolerance = candidate.boundaryTolerance;
0733
0734 ACTS_VERBOSE(volInfo(state)
0735 << "Next surface candidate will be " << surface.geometryId());
0736
0737 return NavigationTarget(surface, intersection.index(), boundaryTolerance);
0738 }
0739
0740
0741
0742
0743
0744
0745
0746
0747
0748
0749
0750 bool checkTargetValid(const State& state, const Vector3& position,
0751 const Vector3& direction) const {
0752 (void)state;
0753 (void)position;
0754 (void)direction;
0755
0756 return true;
0757 }
0758
0759
0760
0761
0762
0763
0764
0765
0766
0767 void handleSurfaceReached(State& state, const Vector3& position,
0768 const Vector3& direction,
0769 const Surface& ) const {
0770 if (state.navigationBreak) {
0771 return;
0772 }
0773
0774 ACTS_VERBOSE(volInfo(state) << "handleSurfaceReached");
0775
0776 assert(state.currentSurface == nullptr && "Current surface must be reset.");
0777
0778 if (state.endOfCandidates()) {
0779 ACTS_VERBOSE(volInfo(state) << "No active candidate set.");
0780 return;
0781 }
0782
0783 std::vector<detail::IntersectedNavigationObject> hitCandidates;
0784
0785 while (!state.endOfCandidates()) {
0786 const auto& candidate = state.activeCandidate();
0787 const auto& intersection = candidate.intersection;
0788 const Surface& surface = *intersection.object();
0789 BoundaryTolerance boundaryTolerance = candidate.boundaryTolerance;
0790
0791
0792 IntersectionStatus surfaceStatus =
0793 surface
0794 .intersect(state.options.geoContext, position, direction,
0795 boundaryTolerance,
0796 state.options.surfaceTolerance)[intersection.index()]
0797 .status();
0798
0799 if (surfaceStatus != IntersectionStatus::onSurface) {
0800 break;
0801 }
0802
0803
0804 boundaryTolerance = BoundaryTolerance::None();
0805 surfaceStatus =
0806 surface
0807 .intersect(state.options.geoContext, position, direction,
0808 boundaryTolerance,
0809 state.options.surfaceTolerance)[intersection.index()]
0810 .status();
0811
0812 if (surfaceStatus == IntersectionStatus::onSurface) {
0813 hitCandidates.emplace_back(candidate);
0814 }
0815
0816 ++state.activeCandidateIndex;
0817 ACTS_VERBOSE("skip candidate " << surface.geometryId());
0818 }
0819
0820
0821 --state.activeCandidateIndex;
0822
0823 ACTS_VERBOSE(volInfo(state)
0824 << "Found " << hitCandidates.size()
0825 << " intersections on surface with bounds check.");
0826
0827 if (hitCandidates.empty()) {
0828 ACTS_VERBOSE(volInfo(state)
0829 << "Surface successfully hit, but outside bounds.");
0830 return;
0831 }
0832
0833 if (hitCandidates.size() > 1) {
0834 ACTS_VERBOSE(volInfo(state)
0835 << "Only using first intersection within bounds.");
0836 }
0837
0838
0839 const auto& candidate = hitCandidates.front();
0840 const auto& intersection = candidate.intersection;
0841 const Surface& surface = *intersection.object();
0842
0843 ACTS_VERBOSE(volInfo(state) << "Surface successfully hit, storing it.");
0844 state.currentSurface = &surface;
0845
0846 if (state.currentSurface != nullptr) {
0847 ACTS_VERBOSE(volInfo(state) << "Current surface set to surface "
0848 << surface.geometryId());
0849 }
0850
0851 if (candidate.template checkType<Surface>()) {
0852 ACTS_VERBOSE(volInfo(state) << "This is a surface");
0853 } else if (candidate.template checkType<Layer>()) {
0854 ACTS_VERBOSE(volInfo(state) << "This is a layer");
0855 } else if (candidate.template checkType<BoundarySurface>()) {
0856 ACTS_VERBOSE(volInfo(state)
0857 << "This is a boundary. Reinitialize navigation");
0858
0859 const auto& boundary = *candidate.template object<BoundarySurface>();
0860
0861 state.currentVolume = boundary.attachedVolume(state.options.geoContext,
0862 position, direction);
0863
0864 ACTS_VERBOSE(volInfo(state) << "Switched volume");
0865
0866 reinitializeCandidates(state);
0867 } else {
0868 ACTS_ERROR(volInfo(state) << "Unknown intersection type");
0869 }
0870 }
0871
0872 private:
0873
0874 void reinitializeCandidates(State& state) const {
0875 state.navigationCandidates.clear();
0876 state.activeCandidates.clear();
0877 state.activeCandidateIndex = -1;
0878
0879 initializeVolumeCandidates(state);
0880 }
0881 };
0882
0883 }