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