File indexing completed on 2026-11-01 09:08:30
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
0054
0055 nearLimit = -100 * UnitConstants::um;
0056 }
0057
0058
0059 std::vector<const Surface*> surfaceSequence;
0060
0061
0062
0063 void setPlainOptions(const NavigatorPlainOptions& options) {
0064
0065
0066 const double keepNearLimit = nearLimit;
0067 static_cast<NavigatorPlainOptions&>(*this) = options;
0068 nearLimit = keepNearLimit;
0069 }
0070 };
0071
0072
0073
0074
0075
0076
0077 struct State {
0078
0079
0080 explicit State(const Options& options_) : options(options_) {}
0081
0082
0083 Options options;
0084
0085
0086 Direction direction = Direction::Forward();
0087
0088
0089 const Surface* startSurface = nullptr;
0090
0091
0092 const Surface* targetSurface = nullptr;
0093
0094
0095
0096
0097 std::int32_t surfaceIndex = -1;
0098
0099
0100 const Surface* currentSurface = nullptr;
0101
0102
0103 bool navigationBreak = false;
0104
0105
0106 NavigatorStatistics statistics;
0107
0108
0109
0110 const Surface& navSurface() const {
0111 return *options.surfaceSequence.at(surfaceIndex);
0112 }
0113
0114
0115
0116 void nextSurface() {
0117 if (direction == Direction::Forward()) {
0118 ++surfaceIndex;
0119 } else {
0120 --surfaceIndex;
0121 }
0122 }
0123
0124
0125
0126 bool endOfSurfaces() const {
0127 if (direction == Direction::Forward()) {
0128 return surfaceIndex >= static_cast<int>(options.surfaceSequence.size());
0129 }
0130 return surfaceIndex < 0;
0131 }
0132
0133
0134
0135 int remainingSurfaces() const {
0136 if (direction == Direction::Forward()) {
0137 return static_cast<int>(options.surfaceSequence.size()) - surfaceIndex;
0138 }
0139 return surfaceIndex + 1;
0140 }
0141
0142
0143
0144
0145 void resetSurfaceIndex() {
0146 surfaceIndex = direction == Direction::Forward()
0147 ? -1
0148 : static_cast<int>(options.surfaceSequence.size());
0149 }
0150 };
0151
0152
0153
0154 explicit DirectNavigator(std::unique_ptr<const Logger> _logger =
0155 getDefaultLogger("DirectNavigator",
0156 Logging::INFO))
0157 : m_logger{std::move(_logger)} {}
0158
0159
0160
0161
0162 State makeState(const Options& options) const {
0163 State state(options);
0164 return state;
0165 }
0166
0167
0168
0169
0170 const Surface* currentSurface(const State& state) const {
0171 return state.currentSurface;
0172 }
0173
0174
0175
0176
0177 const TrackingVolume* currentVolume(const State& state) const {
0178 static_cast<void>(state);
0179 return nullptr;
0180 }
0181
0182
0183
0184
0185 const IVolumeMaterial* currentVolumeMaterial(const State& state) const {
0186 static_cast<void>(state);
0187 return nullptr;
0188 }
0189
0190
0191
0192
0193 const Surface* startSurface(const State& state) const {
0194 return state.startSurface;
0195 }
0196
0197
0198
0199
0200 const Surface* targetSurface(const State& state) const {
0201 return state.targetSurface;
0202 }
0203
0204
0205
0206
0207
0208 bool endOfWorldReached(State& state) const {
0209 static_cast<void>(state);
0210 return false;
0211 }
0212
0213
0214
0215
0216 bool navigationBreak(const State& state) const {
0217 return state.navigationBreak;
0218 }
0219
0220
0221
0222
0223
0224
0225
0226
0227 [[nodiscard]] Result<void> initialize(
0228 State& state, const NavigatorInitializeArguments& args) const {
0229 ACTS_VERBOSE("Initialize. Surface sequence for navigation:");
0230 for (const Surface* surface : state.options.surfaceSequence) {
0231 ACTS_VERBOSE(surface->geometryId()
0232 << " - "
0233 << surface->center(state.options.geoContext).transpose());
0234 }
0235
0236 state.direction = args.propagationDirection;
0237 ACTS_VERBOSE("Navigation direction is " << args.propagationDirection);
0238
0239 state.startSurface = args.startSurface;
0240 state.targetSurface = args.targetSurface;
0241
0242
0243 state.currentSurface = state.startSurface;
0244 if (state.currentSurface != nullptr) {
0245 ACTS_VERBOSE("Current surface set to start surface "
0246 << state.currentSurface->geometryId());
0247 } else {
0248 ACTS_VERBOSE("Current surface set to nullptr");
0249 }
0250
0251
0252 auto found =
0253 std::ranges::find(state.options.surfaceSequence, state.startSurface);
0254
0255 if (found != state.options.surfaceSequence.end()) {
0256
0257
0258 state.surfaceIndex =
0259 std::distance(state.options.surfaceSequence.begin(), found);
0260 state.surfaceIndex += state.direction == Direction::Backward() ? 1 : -1;
0261 } else {
0262 ACTS_DEBUG(
0263 "Did not find the start surface in the sequence. Assuming it is not "
0264 "part of the sequence. Trusting the correctness of the input "
0265 "sequence. Resetting the surface index.");
0266 state.resetSurfaceIndex();
0267 }
0268
0269 state.navigationBreak = false;
0270
0271 return Result<void>::success();
0272 }
0273
0274
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285 NavigationTarget nextTarget(
0286 State& state, const Vector3& position, const Vector3& direction,
0287 [[maybe_unused]] const Vector3& curvature = Vector3::Zero()) 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
0340 bool checkTargetValid(
0341 const State& state, const Vector3& position, const Vector3& direction,
0342 [[maybe_unused]] const Vector3& curvature = Vector3::Zero()) const {
0343 static_cast<void>(state);
0344 static_cast<void>(position);
0345 static_cast<void>(direction);
0346
0347 return true;
0348 }
0349
0350
0351
0352
0353
0354
0355
0356
0357
0358
0359
0360 void handleSurfaceReached(
0361 State& state, const Vector3& position, const Vector3& direction,
0362 const Surface& surface,
0363 [[maybe_unused]] const Vector3& curvature = Vector3::Zero()) const {
0364 static_cast<void>(position);
0365 static_cast<void>(direction);
0366 static_cast<void>(surface);
0367
0368 if (state.navigationBreak) {
0369 return;
0370 }
0371
0372 ACTS_VERBOSE("DirectNavigator::handleSurfaceReached");
0373
0374
0375 state.currentSurface = &state.navSurface();
0376 ACTS_VERBOSE("Current surface set to "
0377 << state.currentSurface->geometryId());
0378 }
0379
0380 private:
0381 NavigationTarget chooseIntersection(
0382 const GeometryContext& gctx, const Surface& surface,
0383 const Vector3& position, const Vector3& direction,
0384 const BoundaryTolerance& boundaryTolerance, double nearLimit,
0385 double farLimit, double tolerance) const {
0386 auto intersections = surface.intersect(gctx, position, direction,
0387 boundaryTolerance, tolerance);
0388
0389 for (auto [intersectionIndex, intersection] :
0390 Acts::enumerate(intersections)) {
0391 if (intersection.isValid() &&
0392 detail::checkPathLength(intersection.pathLength(), nearLimit,
0393 farLimit, logger())) {
0394 return NavigationTarget(intersection, intersectionIndex, surface,
0395 boundaryTolerance);
0396 }
0397 }
0398
0399 return NavigationTarget::None();
0400 }
0401
0402 const Logger& logger() const { return *m_logger; }
0403
0404 std::unique_ptr<const Logger> m_logger;
0405 };
0406
0407 }