File indexing completed on 2026-10-02 08:04:18
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include "Acts/Definitions/Direction.hpp"
0012 #include "Acts/Definitions/Units.hpp"
0013 #include "Acts/Geometry/Layer.hpp"
0014 #include "Acts/Geometry/TrackingGeometry.hpp"
0015 #include "Acts/Geometry/TrackingVolume.hpp"
0016 #include "Acts/Propagator/NavigationTarget.hpp"
0017 #include "Acts/Propagator/NavigatorInitializeArguments.hpp"
0018 #include "Acts/Propagator/NavigatorOptions.hpp"
0019 #include "Acts/Propagator/NavigatorStatistics.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/Result.hpp"
0026
0027 #include <limits>
0028 #include <memory>
0029
0030 namespace Acts {
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040 class DirectNavigator {
0041 public:
0042
0043 struct Config {};
0044
0045
0046 struct Options : public NavigatorPlainOptions {
0047
0048
0049 explicit Options(const GeometryContext& gctx)
0050 : NavigatorPlainOptions(gctx) {}
0051
0052
0053 double surfaceTolerance = s_onSurfaceTolerance;
0054
0055
0056
0057
0058
0059 double nearLimit = -100 * UnitConstants::um;
0060
0061
0062 double farLimit = std::numeric_limits<double>::max();
0063
0064
0065 std::vector<const Surface*> surfaceSequence;
0066
0067
0068
0069 void setPlainOptions(const NavigatorPlainOptions& options) {
0070 static_cast<NavigatorPlainOptions&>(*this) = options;
0071 }
0072 };
0073
0074
0075
0076
0077
0078
0079 struct State {
0080
0081
0082 explicit State(const Options& options_) : options(options_) {}
0083
0084
0085 Options options;
0086
0087
0088 Direction direction = Direction::Forward();
0089
0090
0091 const Surface* startSurface = nullptr;
0092
0093
0094 const Surface* targetSurface = nullptr;
0095
0096
0097
0098
0099 std::int32_t surfaceIndex = -1;
0100
0101
0102 const Surface* currentSurface = nullptr;
0103
0104
0105 bool navigationBreak = false;
0106
0107
0108 NavigatorStatistics statistics;
0109
0110
0111
0112 const Surface& navSurface() const {
0113 return *options.surfaceSequence.at(surfaceIndex);
0114 }
0115
0116
0117
0118 void nextSurface() {
0119 if (direction == Direction::Forward()) {
0120 ++surfaceIndex;
0121 } else {
0122 --surfaceIndex;
0123 }
0124 }
0125
0126
0127
0128 bool endOfSurfaces() const {
0129 if (direction == Direction::Forward()) {
0130 return surfaceIndex >= static_cast<int>(options.surfaceSequence.size());
0131 }
0132 return surfaceIndex < 0;
0133 }
0134
0135
0136
0137 int remainingSurfaces() const {
0138 if (direction == Direction::Forward()) {
0139 return static_cast<int>(options.surfaceSequence.size()) - surfaceIndex;
0140 }
0141 return surfaceIndex + 1;
0142 }
0143
0144
0145
0146
0147 void resetSurfaceIndex() {
0148 surfaceIndex = direction == Direction::Forward()
0149 ? -1
0150 : static_cast<int>(options.surfaceSequence.size());
0151 }
0152 };
0153
0154
0155
0156 explicit DirectNavigator(std::unique_ptr<const Logger> _logger =
0157 getDefaultLogger("DirectNavigator",
0158 Logging::INFO))
0159 : m_logger{std::move(_logger)} {}
0160
0161
0162
0163
0164 State makeState(const Options& options) const {
0165 State state(options);
0166 return state;
0167 }
0168
0169
0170
0171
0172 const Surface* currentSurface(const State& state) const {
0173 return state.currentSurface;
0174 }
0175
0176
0177
0178
0179 const TrackingVolume* currentVolume(const State& state) const {
0180 static_cast<void>(state);
0181 return nullptr;
0182 }
0183
0184
0185
0186
0187 const IVolumeMaterial* currentVolumeMaterial(const State& state) const {
0188 static_cast<void>(state);
0189 return nullptr;
0190 }
0191
0192
0193
0194
0195 const Surface* startSurface(const State& state) const {
0196 return state.startSurface;
0197 }
0198
0199
0200
0201
0202 const Surface* targetSurface(const State& state) const {
0203 return state.targetSurface;
0204 }
0205
0206
0207
0208
0209
0210 bool endOfWorldReached(State& state) const {
0211 static_cast<void>(state);
0212 return false;
0213 }
0214
0215
0216
0217
0218 bool navigationBreak(const State& state) const {
0219 return state.navigationBreak;
0220 }
0221
0222
0223
0224
0225
0226
0227
0228
0229 [[nodiscard]] Result<void> initialize(
0230 State& state, const NavigatorInitializeArguments& args) const {
0231 ACTS_VERBOSE("Initialize. Surface sequence for navigation:");
0232 for (const Surface* surface : state.options.surfaceSequence) {
0233 ACTS_VERBOSE(surface->geometryId()
0234 << " - "
0235 << surface->center(state.options.geoContext).transpose());
0236 }
0237
0238 state.direction = args.propagationDirection;
0239 ACTS_VERBOSE("Navigation direction is " << args.propagationDirection);
0240
0241 state.startSurface = args.startSurface;
0242 state.targetSurface = args.targetSurface;
0243
0244
0245 state.currentSurface = state.startSurface;
0246 if (state.currentSurface != nullptr) {
0247 ACTS_VERBOSE("Current surface set to start surface "
0248 << state.currentSurface->geometryId());
0249 } else {
0250 ACTS_VERBOSE("Current surface set to nullptr");
0251 }
0252
0253
0254 auto found =
0255 std::ranges::find(state.options.surfaceSequence, state.startSurface);
0256
0257 if (found != state.options.surfaceSequence.end()) {
0258
0259
0260 state.surfaceIndex =
0261 std::distance(state.options.surfaceSequence.begin(), found);
0262 state.surfaceIndex += state.direction == Direction::Backward() ? 1 : -1;
0263 } else {
0264 ACTS_DEBUG(
0265 "Did not find the start surface in the sequence. Assuming it is not "
0266 "part of the sequence. Trusting the correctness of the input "
0267 "sequence. Resetting the surface index.");
0268 state.resetSurfaceIndex();
0269 }
0270
0271 state.navigationBreak = false;
0272
0273 return Result<void>::success();
0274 }
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286 NavigationTarget nextTarget(State& state, const Vector3& position,
0287 const Vector3& direction) const {
0288
0289 state.currentSurface = nullptr;
0290
0291 if (state.navigationBreak) {
0292 return NavigationTarget::None();
0293 }
0294
0295 ACTS_VERBOSE("DirectNavigator::nextTarget");
0296
0297
0298 state.nextSurface();
0299
0300 while (!state.endOfSurfaces()) {
0301 ACTS_VERBOSE("Next surface candidate is "
0302 << state.navSurface().geometryId() << ". "
0303 << state.remainingSurfaces() << " out of "
0304 << state.options.surfaceSequence.size()
0305 << " surfaces remain to try.");
0306
0307
0308
0309 const Surface& surface = state.navSurface();
0310 const double farLimit = std::numeric_limits<double>::max();
0311 const NavigationTarget target = chooseIntersection(
0312 state.options.geoContext, surface, position, direction,
0313 BoundaryTolerance::Infinite(), state.options.nearLimit, farLimit,
0314 state.options.surfaceTolerance);
0315 if (target.isValid()) {
0316 return target;
0317 }
0318
0319 ACTS_VERBOSE("No valid intersection found with surface "
0320 << surface.geometryId() << ", trying next surface.");
0321 state.nextSurface();
0322 }
0323
0324 ACTS_VERBOSE("End of surfaces reached, navigation break.");
0325 state.navigationBreak = true;
0326 return NavigationTarget::None();
0327 }
0328
0329
0330
0331
0332
0333
0334
0335
0336
0337
0338
0339 bool checkTargetValid(const State& state, const Vector3& position,
0340 const Vector3& direction) const {
0341 static_cast<void>(state);
0342 static_cast<void>(position);
0343 static_cast<void>(direction);
0344
0345 return true;
0346 }
0347
0348
0349
0350
0351
0352
0353
0354
0355
0356
0357 void handleSurfaceReached(State& state, const Vector3& position,
0358 const Vector3& direction,
0359 const Surface& surface) const {
0360 static_cast<void>(position);
0361 static_cast<void>(direction);
0362 static_cast<void>(surface);
0363
0364 if (state.navigationBreak) {
0365 return;
0366 }
0367
0368 ACTS_VERBOSE("DirectNavigator::handleSurfaceReached");
0369
0370
0371 state.currentSurface = &state.navSurface();
0372 ACTS_VERBOSE("Current surface set to "
0373 << state.currentSurface->geometryId());
0374 }
0375
0376 private:
0377 NavigationTarget chooseIntersection(
0378 const GeometryContext& gctx, const Surface& surface,
0379 const Vector3& position, const Vector3& direction,
0380 const BoundaryTolerance& boundaryTolerance, double nearLimit,
0381 double farLimit, double tolerance) const {
0382 auto intersections = surface.intersect(gctx, position, direction,
0383 boundaryTolerance, tolerance);
0384
0385 for (auto [intersectionIndex, intersection] :
0386 Acts::enumerate(intersections)) {
0387 if (intersection.isValid() &&
0388 detail::checkPathLength(intersection.pathLength(), nearLimit,
0389 farLimit, logger())) {
0390 return NavigationTarget(intersection, intersectionIndex, surface,
0391 boundaryTolerance);
0392 }
0393 }
0394
0395 return NavigationTarget::None();
0396 }
0397
0398 const Logger& logger() const { return *m_logger; }
0399
0400 std::unique_ptr<const Logger> m_logger;
0401 };
0402
0403 }