File indexing completed on 2026-07-16 08:07:52
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/Propagator/Navigator.hpp"
0010
0011 #include "Acts/Geometry/BoundarySurfaceT.hpp"
0012 #include "Acts/Geometry/Portal.hpp"
0013 #include "Acts/Propagator/NavigatorError.hpp"
0014 #include "Acts/Surfaces/Surface.hpp"
0015 #include "Acts/Utilities/Intersection.hpp"
0016 #include "Acts/Utilities/StringHelpers.hpp"
0017
0018 #include <algorithm>
0019 #include <cassert>
0020 #include <sstream>
0021
0022 namespace Acts {
0023
0024 Navigator::Navigator(Config cfg, std::shared_ptr<const Logger> _logger)
0025 : m_cfg{std::move(cfg)}, m_logger{std::move(_logger)} {
0026 if (m_cfg.trackingGeometry == nullptr) {
0027 throw std::invalid_argument("Navigator: No tracking geometry provided.");
0028 }
0029 m_geometryVersion = m_cfg.trackingGeometry->geometryVersion();
0030 }
0031
0032 Navigator::State Navigator::makeState(const Options& options) const {
0033 State state(options);
0034 return state;
0035 }
0036
0037 const Surface* Navigator::currentSurface(const State& state) const {
0038 return state.currentSurface;
0039 }
0040
0041 const TrackingVolume* Navigator::currentVolume(const State& state) const {
0042 return state.currentVolume;
0043 }
0044
0045 const IVolumeMaterial* Navigator::currentVolumeMaterial(
0046 const State& state) const {
0047 if (state.currentVolume == nullptr) {
0048 return nullptr;
0049 }
0050 return state.currentVolume->volumeMaterial();
0051 }
0052
0053 const Surface* Navigator::startSurface(const State& state) const {
0054 return state.startSurface;
0055 }
0056
0057 const Surface* Navigator::targetSurface(const State& state) const {
0058 return state.targetSurface;
0059 }
0060
0061 bool Navigator::endOfWorldReached(const State& state) const {
0062 return state.currentVolume == nullptr;
0063 }
0064
0065 bool Navigator::navigationBreak(const State& state) const {
0066 return state.navigationBreak;
0067 }
0068
0069 Result<void> Navigator::initialize(State& state, const Vector3& position,
0070 const Vector3& direction,
0071 Direction propagationDirection) const {
0072 static_cast<void>(propagationDirection);
0073
0074 ACTS_VERBOSE(volInfo(state) << "Initialization.");
0075
0076 auto printGeometryVersion = [](auto ver) {
0077 using enum TrackingGeometry::GeometryVersion;
0078 switch (ver) {
0079 case Gen1:
0080 return "Gen1";
0081 case Gen3:
0082 return "Gen3";
0083 default:
0084 throw std::runtime_error("Unknown geometry version.");
0085 }
0086 };
0087 ACTS_VERBOSE(volInfo(state) << "Geometry version is: "
0088 << printGeometryVersion(m_geometryVersion));
0089
0090 state.reset();
0091
0092 if (m_geometryVersion == GeometryVersion::Gen3) {
0093
0094
0095
0096 state.stream.candidates().reserve(50);
0097
0098 state.freeCandidates.clear();
0099 state.freeCandidates.reserve(state.options.freeSurfaces.size());
0100 for (const Surface* candidate : state.options.freeSurfaces) {
0101 state.freeCandidates.emplace_back(candidate, false);
0102 }
0103 }
0104
0105 state.startSurface = state.options.startSurface;
0106 state.targetSurface = state.options.targetSurface;
0107
0108
0109
0110
0111
0112
0113
0114 if (state.startSurface != nullptr &&
0115 state.startSurface->associatedLayer() != nullptr) {
0116 ACTS_VERBOSE(
0117 volInfo(state)
0118 << "Fast start initialization through association from Surface.");
0119
0120 state.startLayer = state.startSurface->associatedLayer();
0121 state.startVolume = state.startLayer->trackingVolume();
0122 } else if (state.startVolume != nullptr) {
0123 ACTS_VERBOSE(
0124 volInfo(state)
0125 << "Fast start initialization through association from Volume.");
0126
0127 state.startLayer =
0128 state.startVolume->associatedLayer(state.options.geoContext, position);
0129 } else {
0130 ACTS_VERBOSE(volInfo(state) << "Slow start initialization through search.");
0131 ACTS_VERBOSE(volInfo(state)
0132 << "Starting from position " << toString(position)
0133 << " and direction " << toString(direction));
0134
0135
0136 state.startVolume = m_cfg.trackingGeometry->lowestTrackingVolume(
0137 state.options.geoContext, position);
0138
0139 if (state.startVolume != nullptr) {
0140 state.startLayer = state.startVolume->associatedLayer(
0141 state.options.geoContext, position);
0142 } else {
0143 ACTS_DEBUG(volInfo(state)
0144 << "No start volume resolved. Nothing left to do.");
0145 state.navigationBreak = true;
0146 return Result<void>::failure(NavigatorError::NoStartVolume);
0147 }
0148 }
0149
0150 state.currentVolume = state.startVolume;
0151 state.currentLayer = state.startLayer;
0152 state.currentSurface = state.startSurface;
0153
0154 if (state.currentVolume != nullptr) {
0155 ACTS_VERBOSE(volInfo(state) << "Start volume resolved "
0156 << state.currentVolume->geometryId());
0157
0158 if (!state.currentVolume->inside(state.options.geoContext, position,
0159 state.options.surfaceTolerance)) {
0160 ACTS_DEBUG(volInfo(state)
0161 << "We did not end up inside the expected volume. position = "
0162 << position.transpose());
0163
0164 return Result<void>::failure(NavigatorError::NotInsideExpectedVolume);
0165 }
0166 }
0167 if (state.currentLayer != nullptr) {
0168 ACTS_VERBOSE(volInfo(state) << "Start layer resolved "
0169 << state.currentLayer->geometryId());
0170 }
0171 if (state.currentSurface != nullptr) {
0172 ACTS_VERBOSE(volInfo(state) << "Start surface resolved "
0173 << state.currentSurface->geometryId());
0174
0175 if (!state.currentSurface->isOnSurface(
0176 state.options.geoContext, position, direction,
0177 BoundaryTolerance::Infinite(), state.options.surfaceTolerance)) {
0178 ACTS_DEBUG(volInfo(state)
0179 << "We did not end up on the expected surface. surface = "
0180 << state.currentSurface->geometryId()
0181 << " position = " << position.transpose()
0182 << " direction = " << direction.transpose());
0183
0184 return Result<void>::failure(NavigatorError::NotOnExpectedSurface);
0185 }
0186 }
0187
0188 return Result<void>::success();
0189 }
0190
0191 NavigationTarget Navigator::nextTarget(State& state, const Vector3& position,
0192 const Vector3& direction) const {
0193
0194 state.currentSurface = nullptr;
0195
0196 if (inactive(state)) {
0197 return NavigationTarget::None();
0198 }
0199
0200 ACTS_VERBOSE(volInfo(state) << "Entering Navigator::nextTarget.");
0201
0202 NavigationTarget nextTarget = tryGetNextTarget(state, position, direction);
0203 if (!nextTarget.isNone()) {
0204 return nextTarget;
0205 }
0206
0207 state.reset();
0208 ++state.statistics.nRenavigations;
0209
0210
0211
0212 state.currentVolume = m_cfg.trackingGeometry->lowestTrackingVolume(
0213 state.options.geoContext, position);
0214
0215 if (state.currentVolume == nullptr) {
0216 ACTS_VERBOSE(volInfo(state) << "No volume found, stop navigation.");
0217 state.navigationBreak = true;
0218 return NavigationTarget::None();
0219 }
0220
0221 state.currentLayer =
0222 state.currentVolume->associatedLayer(state.options.geoContext, position);
0223
0224 ACTS_VERBOSE(volInfo(state) << "Resolved volume and layer.");
0225
0226
0227 nextTarget = tryGetNextTarget(state, position, direction);
0228 if (!nextTarget.isNone()) {
0229 return nextTarget;
0230 }
0231
0232 ACTS_VERBOSE(
0233 volInfo(state)
0234 << "No targets found again, we got really lost! Stop navigation.");
0235 state.navigationBreak = true;
0236 return NavigationTarget::None();
0237 }
0238
0239 bool Navigator::checkTargetValid(const State& state, const Vector3& position,
0240 const Vector3& direction) const {
0241 static_cast<void>(position);
0242 static_cast<void>(direction);
0243
0244 return state.navigationStage != Stage::initial;
0245 }
0246
0247 void Navigator::handleSurfaceReached(State& state, const Vector3& position,
0248 const Vector3& direction,
0249 const Surface& surface) const {
0250 if (inactive(state)) {
0251 return;
0252 }
0253
0254 ACTS_VERBOSE(volInfo(state) << "Entering Navigator::handleSurfaceReached.");
0255
0256 state.currentSurface = &surface;
0257
0258 ACTS_VERBOSE(volInfo(state)
0259 << "Current surface: " << state.currentSurface->geometryId());
0260
0261
0262 if (m_geometryVersion == GeometryVersion::Gen3) {
0263 if (state.navCandidate().isPortalTarget() &&
0264 &state.navCandidate().surface() == &surface) {
0265 ACTS_VERBOSE(volInfo(state) << "Handling portal status.");
0266
0267
0268 const Portal* portal = &state.navCandidate().portal();
0269 auto res =
0270 portal->resolveVolume(state.options.geoContext, position, direction);
0271 if (!res.ok()) {
0272 ACTS_ERROR(volInfo(state) << "Failed to resolve volume through portal: "
0273 << res.error().message());
0274 return;
0275 }
0276
0277 state.currentVolume = res.value();
0278
0279
0280 state.resetAfterVolumeSwitch();
0281
0282 if (state.currentVolume != nullptr) {
0283 ACTS_VERBOSE(volInfo(state) << "Volume updated.");
0284
0285
0286
0287 state.navigationStage = Stage::surfaceTarget;
0288 } else {
0289 ACTS_VERBOSE(volInfo(state)
0290 << "No more volume to progress to, stopping navigation.");
0291 state.navigationBreak = true;
0292 }
0293 }
0294
0295 else if (&state.navCandidate().surface() == &surface &&
0296 surface.geometryId() == GeometryIdentifier{}) {
0297 auto freeItr = std::ranges::find_if(
0298 state.freeCandidates,
0299 [&surface](const std::pair<const Surface*, bool>& cand) {
0300 return &surface == cand.first;
0301 });
0302 if (freeItr != state.freeCandidates.end()) {
0303 freeItr->second = true;
0304 }
0305 }
0306 return;
0307 }
0308
0309 if (state.navigationStage == Stage::surfaceTarget &&
0310 &state.navSurface().surface() == &surface) {
0311 ACTS_VERBOSE(volInfo(state) << "Handling surface status.");
0312
0313 return;
0314 }
0315
0316 if (state.navigationStage == Stage::layerTarget &&
0317 &state.navLayer().surface() == &surface) {
0318 ACTS_VERBOSE(volInfo(state) << "Handling layer status.");
0319
0320
0321 state.currentLayer = &state.navLayer().layer();
0322 state.navigationStage = Stage::surfaceTarget;
0323
0324
0325 state.resetAfterLayerSwitch();
0326
0327 return;
0328 }
0329
0330 if (state.navigationStage == Stage::boundaryTarget &&
0331 &state.navBoundary().surface() == &surface) {
0332 ACTS_VERBOSE(volInfo(state) << "Handling boundary status.");
0333
0334
0335 const BoundarySurface* boundary = &state.navBoundary().boundarySurface();
0336 assert(boundary != nullptr && "Retrieved boundary surface is nullptr");
0337 state.currentVolume =
0338 boundary->attachedVolume(state.options.geoContext, position, direction);
0339
0340
0341 state.resetAfterVolumeSwitch();
0342
0343 if (state.currentVolume != nullptr) {
0344 ACTS_VERBOSE(volInfo(state) << "Volume updated.");
0345 state.navigationStage = Stage::layerTarget;
0346 } else {
0347 ACTS_VERBOSE(volInfo(state)
0348 << "No more volume to progress to, stopping navigation.");
0349 state.navigationBreak = true;
0350 }
0351
0352 return;
0353 }
0354
0355 ACTS_ERROR(volInfo(state) << "Surface reached but unknown state.");
0356 }
0357
0358 NavigationTarget Navigator::getNextTargetGen1(State& state,
0359 const Vector3& position,
0360 const Vector3& direction) const {
0361
0362 if (state.navigationStage == Stage::surfaceTarget) {
0363 if (!state.navSurfaceIndex.has_value()) {
0364
0365 resolveSurfaces(state, position, direction);
0366 state.navSurfaceIndex = 0;
0367 } else {
0368 ++state.navSurfaceIndex.value();
0369 }
0370 if (state.navSurfaceIndex.value() < state.navSurfaces.size()) {
0371 ACTS_VERBOSE(volInfo(state) << "Target set to next surface.");
0372 return state.navSurface();
0373 } else {
0374
0375 ACTS_VERBOSE(volInfo(state) << "Target layers.");
0376 state.navigationStage = Stage::layerTarget;
0377 }
0378 }
0379
0380 if (state.navigationStage == Stage::layerTarget) {
0381 if (!state.navLayerIndex.has_value()) {
0382
0383 resolveLayers(state, position, direction);
0384 state.navLayerIndex = 0;
0385 } else {
0386 ++state.navLayerIndex.value();
0387 }
0388 if (state.navLayerIndex.value() < state.navLayers.size()) {
0389 ACTS_VERBOSE(volInfo(state) << "Target set to next layer.");
0390 return state.navLayer();
0391 } else {
0392
0393 ACTS_VERBOSE(volInfo(state) << "Target boundaries.");
0394 state.navigationStage = Stage::boundaryTarget;
0395 }
0396 }
0397
0398 if (state.navigationStage == Stage::boundaryTarget) {
0399 if (!state.navBoundaryIndex.has_value()) {
0400
0401 resolveBoundaries(state, position, direction);
0402 state.navBoundaryIndex = 0;
0403 } else {
0404 ++state.navBoundaryIndex.value();
0405 }
0406 if (state.navBoundaryIndex.value() < state.navBoundaries.size()) {
0407 ACTS_VERBOSE(volInfo(state) << "Target set to next boundary.");
0408 return state.navBoundary();
0409 } else {
0410
0411
0412 ACTS_VERBOSE(volInfo(state) << "Boundary targets exhausted. Renavigate.");
0413 return NavigationTarget::None();
0414 }
0415 }
0416
0417 ACTS_VERBOSE(volInfo(state) << "Unknown state. No target found. Renavigate.");
0418 return NavigationTarget::None();
0419 }
0420
0421 NavigationTarget Navigator::getNextTargetGen3(State& state,
0422 const Vector3& position,
0423 const Vector3& direction) const {
0424 if (!state.navCandidateIndex.has_value()) {
0425
0426 resolveCandidates(state, position, direction);
0427 state.navCandidateIndex = 0;
0428 } else {
0429 ++state.navCandidateIndex.value();
0430 }
0431 if (state.navCandidateIndex.value() < state.navCandidates.size()) {
0432 ACTS_VERBOSE(volInfo(state)
0433 << "Target set to next candidate " << state.navCandidate());
0434 return state.navCandidate();
0435 } else {
0436 ACTS_VERBOSE(volInfo(state) << "Candidate targets exhausted. Renavigate.");
0437 return NavigationTarget::None();
0438 }
0439 }
0440
0441 NavigationTarget Navigator::tryGetNextTarget(State& state,
0442 const Vector3& position,
0443 const Vector3& direction) const {
0444
0445
0446
0447
0448
0449 if (state.navigationStage == Stage::initial) {
0450 ACTS_VERBOSE(volInfo(state) << "Target surfaces.");
0451 state.navigationStage = Stage::surfaceTarget;
0452 }
0453
0454 if (m_geometryVersion == GeometryVersion::Gen1) {
0455 return getNextTargetGen1(state, position, direction);
0456
0457 } else {
0458
0459 return getNextTargetGen3(state, position, direction);
0460 }
0461 }
0462
0463 void Navigator::resolveCandidates(State& state, const Vector3& position,
0464 const Vector3& direction) const {
0465 if (state.currentVolume == nullptr) {
0466 ACTS_VERBOSE(volInfo(state) << "No volume to resolve candidates.");
0467 return;
0468 }
0469 ACTS_VERBOSE(volInfo(state) << "Searching for compatible candidates.");
0470
0471 state.stream.reset();
0472 AppendOnlyNavigationStream appendOnly{state.stream};
0473 NavigationArguments args;
0474 args.position = position;
0475 args.direction = direction;
0476 state.currentVolume->initializeNavigationCandidates(
0477 state.options.geoContext, args, appendOnly, logger());
0478
0479 ACTS_VERBOSE(volInfo(state) << "Found " << state.stream.candidates().size()
0480 << " navigation candidates.");
0481 if (!state.options.externalSurfaces.empty()) {
0482 for (const GeometryIdentifier& geoId : state.options.externalSurfaces) {
0483
0484
0485 if (geoId.volume() != state.currentVolume->geometryId().volume() ||
0486 geoId.extra() != state.currentVolume->geometryId().extra()) {
0487 continue;
0488 }
0489 const Surface* surface = m_cfg.trackingGeometry->findSurface(geoId);
0490 assert(surface != nullptr);
0491 ACTS_VERBOSE(volInfo(state) << "Try to navigate to " << surface->type()
0492 << " surface " << geoId);
0493 appendOnly.addSurfaceCandidate(*surface, BoundaryTolerance::Infinite());
0494 };
0495 }
0496 bool pruneFreeCand{false};
0497 if (!state.freeCandidates.empty()) {
0498 for (const auto& [surface, wasReached] : state.freeCandidates) {
0499
0500 if (wasReached) {
0501 continue;
0502 }
0503 if (!state.options.freeSurfaceSelector.connected() ||
0504 state.options.freeSurfaceSelector(state.options.geoContext,
0505 *state.currentVolume, position,
0506 direction, *surface)) {
0507 ACTS_VERBOSE(volInfo(state)
0508 << "Append free " << surface->type() << " surface \n"
0509 << surface->toStream(state.options.geoContext));
0510 appendOnly.addSurfaceCandidate(*surface, BoundaryTolerance::Infinite());
0511 pruneFreeCand = !state.options.freeSurfaceSelector.connected();
0512 }
0513 };
0514 }
0515 state.stream.initialize(state.options.geoContext, {position, direction},
0516 BoundaryTolerance::None(),
0517 state.options.surfaceTolerance);
0518
0519 ACTS_VERBOSE(volInfo(state) << "Now " << state.stream.candidates().size()
0520 << " navigation candidates after initialization");
0521
0522 state.navCandidates.clear();
0523
0524 double farLimit = state.options.farLimit;
0525
0526
0527
0528 if (pruneFreeCand) {
0529 farLimit = state.options.nearLimit;
0530 for (const auto& candidate : state.stream.candidates()) {
0531 if (candidate.isPortalTarget()) {
0532 farLimit = std::max(farLimit, candidate.intersection().pathLength() +
0533 state.options.surfaceTolerance);
0534 }
0535 }
0536 }
0537
0538 for (auto& candidate : state.stream.candidates()) {
0539 if (!detail::checkPathLength(candidate.intersection().pathLength(),
0540 state.options.nearLimit, farLimit, logger())) {
0541 continue;
0542 }
0543
0544 state.navCandidates.emplace_back(candidate);
0545 }
0546
0547
0548 std::ranges::sort(state.navCandidates, [](const auto& a, const auto& b) {
0549 return a.intersection().pathLength() < b.intersection().pathLength();
0550 });
0551
0552
0553
0554 if (logger().doPrint(Logging::VERBOSE)) {
0555 std::ostringstream os;
0556 os << "Navigation candidates: " << state.navCandidates.size() << "\n";
0557 for (auto& candidate : state.navCandidates) {
0558 os << " -- " << candidate << "\n";
0559 }
0560
0561 logger().log(Logging::VERBOSE, os.str());
0562 }
0563 }
0564
0565 void Navigator::resolveSurfaces(State& state, const Vector3& position,
0566 const Vector3& direction) const {
0567
0568 ACTS_VERBOSE(volInfo(state) << "Searching for compatible surfaces.");
0569
0570 const Layer* currentLayer = state.currentLayer;
0571
0572 if (currentLayer == nullptr) {
0573 ACTS_VERBOSE(volInfo(state) << "No layer to resolve surfaces.");
0574 return;
0575 }
0576
0577 const Surface* layerSurface = ¤tLayer->surfaceRepresentation();
0578
0579 NavigationOptions<Surface> navOpts;
0580 navOpts.resolveSensitive = m_cfg.resolveSensitive;
0581 navOpts.resolveMaterial = m_cfg.resolveMaterial;
0582 navOpts.resolvePassive = m_cfg.resolvePassive;
0583 navOpts.startObject = state.currentSurface;
0584 navOpts.endObject = state.targetSurface;
0585 navOpts.nearLimit = state.options.nearLimit;
0586 navOpts.farLimit = state.options.farLimit;
0587
0588 if (!state.options.externalSurfaces.empty()) {
0589 const auto layerId = layerSurface->geometryId().layer();
0590 for (const GeometryIdentifier& id : state.options.externalSurfaces) {
0591 if (id.layer() == layerId) {
0592 navOpts.externalSurfaces.push_back(id);
0593 }
0594 }
0595 }
0596
0597
0598 state.navSurfaces = currentLayer->compatibleSurfaces(
0599 state.options.geoContext, position, direction, navOpts);
0600
0601
0602
0603 std::ranges::sort(state.navSurfaces, [&state](const NavigationTarget& a,
0604 const NavigationTarget& b) {
0605
0606
0607 if (std::abs(a.pathLength() - b.pathLength()) >
0608 state.options.surfaceTolerance) {
0609 return NavigationTarget::pathLengthOrder(a, b);
0610 }
0611
0612
0613 bool aIsExternal = a.boundaryTolerance().isInfinite();
0614 bool bIsExternal = b.boundaryTolerance().isInfinite();
0615 if (aIsExternal == bIsExternal) {
0616
0617
0618 return a.surface().geometryId() < b.surface().geometryId();
0619 }
0620
0621 return aIsExternal;
0622 });
0623
0624
0625
0626
0627 auto toBeRemoved =
0628 std::ranges::unique(state.navSurfaces, [&](const auto& a, const auto& b) {
0629 return std::abs(a.pathLength() - b.pathLength()) <
0630 state.options.surfaceTolerance;
0631 });
0632 if (toBeRemoved.begin() != toBeRemoved.end()) {
0633 ACTS_VERBOSE(volInfo(state)
0634 << "Removing "
0635 << std::distance(toBeRemoved.begin(), toBeRemoved.end())
0636 << " overlapping surfaces.");
0637 }
0638 state.navSurfaces.erase(toBeRemoved.begin(), toBeRemoved.end());
0639
0640
0641 if (logger().doPrint(Logging::VERBOSE)) {
0642 std::ostringstream os;
0643 os << state.navSurfaces.size();
0644 os << " surface candidates found at path(s): ";
0645 for (auto& sfc : state.navSurfaces) {
0646 os << sfc.pathLength() << " ";
0647 }
0648 logger().log(Logging::VERBOSE, os.str());
0649 }
0650
0651 if (state.navSurfaces.empty()) {
0652 ACTS_VERBOSE(volInfo(state) << "No surface candidates found.");
0653 }
0654 }
0655
0656 void Navigator::resolveLayers(State& state, const Vector3& position,
0657 const Vector3& direction) const {
0658 ACTS_VERBOSE(volInfo(state) << "Searching for compatible layers.");
0659
0660 NavigationOptions<Layer> navOpts;
0661 navOpts.resolveSensitive = m_cfg.resolveSensitive;
0662 navOpts.resolveMaterial = m_cfg.resolveMaterial;
0663 navOpts.resolvePassive = m_cfg.resolvePassive;
0664 navOpts.startObject = state.currentLayer;
0665 navOpts.nearLimit = state.options.nearLimit;
0666 navOpts.farLimit = state.options.farLimit;
0667
0668
0669 state.navLayers = state.currentVolume->compatibleLayers(
0670 state.options.geoContext, position, direction, navOpts);
0671 std::ranges::sort(state.navLayers, NavigationTarget::pathLengthOrder);
0672
0673
0674 if (logger().doPrint(Logging::VERBOSE)) {
0675 std::ostringstream os;
0676 os << state.navLayers.size();
0677 os << " layer candidates found at path(s): ";
0678 for (auto& lc : state.navLayers) {
0679 os << lc.pathLength() << " ";
0680 }
0681 logger().log(Logging::VERBOSE, os.str());
0682 }
0683
0684 if (state.navLayers.empty()) {
0685 ACTS_VERBOSE(volInfo(state) << "No layer candidates found.");
0686 }
0687 }
0688
0689 void Navigator::resolveBoundaries(State& state, const Vector3& position,
0690 const Vector3& direction) const {
0691 ACTS_VERBOSE(volInfo(state) << "Searching for compatible boundaries.");
0692
0693 NavigationOptions<Surface> navOpts;
0694 navOpts.startObject = state.currentSurface;
0695 navOpts.nearLimit = state.options.nearLimit;
0696 navOpts.farLimit = state.options.farLimit;
0697
0698 ACTS_VERBOSE(volInfo(state)
0699 << "Try to find boundaries, we are at: " << toString(position)
0700 << ", dir: " << toString(direction));
0701
0702
0703 state.navBoundaries = state.currentVolume->compatibleBoundaries(
0704 state.options.geoContext, position, direction, navOpts, logger());
0705 std::ranges::sort(state.navBoundaries, NavigationTarget::pathLengthOrder);
0706
0707
0708 if (logger().doPrint(Logging::VERBOSE)) {
0709 std::ostringstream os;
0710 os << state.navBoundaries.size();
0711 os << " boundary candidates found at path(s): ";
0712 for (const auto& bc : state.navBoundaries) {
0713 os << bc.pathLength() << " ";
0714 }
0715 logger().log(Logging::VERBOSE, os.str());
0716 }
0717
0718 if (state.navBoundaries.empty()) {
0719 ACTS_VERBOSE(volInfo(state) << "No boundary candidates found.");
0720 }
0721 }
0722
0723 bool Navigator::inactive(const State& state) const {
0724
0725 if (!m_cfg.resolveSensitive && !m_cfg.resolveMaterial &&
0726 !m_cfg.resolvePassive) {
0727 return true;
0728 }
0729
0730 if (state.navigationBreak) {
0731 return true;
0732 }
0733
0734 return false;
0735 }
0736
0737 std::string Navigator::volInfo(const State& state) const {
0738 if (state.currentVolume == nullptr) {
0739 return "No Volume | ";
0740 }
0741 std::stringstream sstr{};
0742 sstr << state.currentVolume->volumeName() << " ("
0743 << state.currentVolume->geometryId() << ") | ";
0744 return sstr.str();
0745 }
0746
0747 }