File indexing completed on 2026-11-13 09:41:06
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <boost/test/unit_test.hpp>
0010
0011 #include "Acts/Navigation/NavigationStream.hpp"
0012 #include "Acts/Surfaces/CylinderSurface.hpp"
0013 #include "Acts/Surfaces/PlaneSurface.hpp"
0014 #include "Acts/Surfaces/RectangleBounds.hpp"
0015 #include "Acts/Utilities/Intersection.hpp"
0016 #include "ActsTests/CommonHelpers/FloatComparisons.hpp"
0017
0018 using namespace Acts;
0019
0020 namespace ActsTests {
0021
0022 ACTS_LOCAL_LOGGER(getDefaultLogger("NavigationStreamTests",
0023 Logging::Level::INFO));
0024
0025
0026 std::vector<std::shared_ptr<Surface>> createPlaneSurfaces() {
0027 auto rectangle = std::make_shared<RectangleBounds>(10., 10.);
0028
0029
0030 Transform3 aTransform = Transform3::Identity();
0031 aTransform.pretranslate(Vector3(0., 0., -20.));
0032 auto surfaceA = Surface::makeShared<PlaneSurface>(aTransform, rectangle);
0033 surfaceA->assignGeometryId(GeometryIdentifier{}.withSensitive(1));
0034
0035
0036
0037 Transform3 bTransform = Transform3::Identity();
0038 bTransform.pretranslate(Vector3(50., 50., 100.));
0039 auto surfaceB = Surface::makeShared<PlaneSurface>(bTransform, rectangle);
0040 surfaceB->assignGeometryId(GeometryIdentifier{}.withSensitive(2));
0041
0042 Transform3 cTransform = Transform3::Identity();
0043 cTransform.pretranslate(Vector3(0., 0., 200.));
0044 auto surfaceC = Surface::makeShared<PlaneSurface>(cTransform, rectangle);
0045 surfaceC->assignGeometryId(GeometryIdentifier{}.withSensitive(3));
0046
0047 Transform3 dTransform = Transform3::Identity();
0048 dTransform.pretranslate(Vector3(0., 0., 400.));
0049 auto surfaceD = Surface::makeShared<PlaneSurface>(dTransform, rectangle);
0050 surfaceD->assignGeometryId(GeometryIdentifier{}.withSensitive(4));
0051
0052
0053 return {surfaceC, surfaceA, surfaceD, surfaceB};
0054 }
0055
0056
0057 std::vector<std::shared_ptr<Surface>> createCylinders() {
0058
0059
0060 Transform3 aTransform = Transform3::Identity();
0061 auto surfaceA = Surface::makeShared<CylinderSurface>(aTransform, 10., 20);
0062 surfaceA->assignGeometryId(GeometryIdentifier{}.withSensitive(6));
0063
0064
0065
0066 Transform3 bTransform = Transform3::Identity();
0067 bTransform.pretranslate(Vector3(20., 20., 0.));
0068 auto surfaceB = Surface::makeShared<CylinderSurface>(bTransform, 2., 10);
0069 surfaceB->assignGeometryId(GeometryIdentifier{}.withSensitive(7));
0070
0071
0072
0073 Transform3 cTransform = Transform3::Identity();
0074 auto surfaceC = Surface::makeShared<CylinderSurface>(cTransform, 40., 20);
0075 surfaceC->assignGeometryId(GeometryIdentifier{}.withSensitive(8));
0076
0077
0078
0079
0080 Transform3 dTransform = Transform3::Identity();
0081 dTransform.pretranslate(Vector3(0., 0., 10.));
0082 auto surfaceD = Surface::makeShared<CylinderSurface>(dTransform, 50., 5.);
0083 surfaceD->assignGeometryId(GeometryIdentifier{}.withSensitive(9));
0084
0085
0086 return {surfaceC, surfaceB, surfaceA, surfaceD};
0087 }
0088
0089 auto gContext = GeometryContext::dangerouslyDefaultConstruct();
0090
0091
0092 NavigationStream makeStream(std::span<const std::shared_ptr<Surface>> surfaces,
0093 const BoundaryTolerance& tolerance) {
0094 NavigationStream stream;
0095 for (const auto& surface : surfaces) {
0096 stream.addSurfaceCandidate(*surface, tolerance);
0097 }
0098 BOOST_CHECK_EQUAL(stream.remainingCandidates(), 4u);
0099 return stream;
0100 }
0101
0102 BOOST_AUTO_TEST_SUITE(Navigation)
0103
0104 BOOST_AUTO_TEST_CASE(NavigationStream_InitializePlanes) {
0105
0106 auto surfaces = createPlaneSurfaces();
0107
0108
0109
0110 NavigationStream nStream =
0111 makeStream(surfaces, BoundaryTolerance::Infinite());
0112 BOOST_CHECK(nStream.initialize(
0113 gContext, {Vector3(0., 0., -30.), Vector3(0., 0., 1.)}, logger()));
0114
0115 BOOST_CHECK_EQUAL(nStream.remainingCandidates(), 4u);
0116 BOOST_CHECK(nStream.isValid());
0117 BOOST_CHECK_EQUAL(&nStream.currentCandidate().surface(),
0118 surfaces.at(1u).get());
0119
0120
0121
0122
0123 nStream = makeStream(surfaces, BoundaryTolerance::Infinite());
0124 BOOST_CHECK(nStream.initialize(
0125 gContext, {Vector3(0., 0., 0.), Vector3(0., 0., 1.)}, logger()));
0126 BOOST_CHECK_EQUAL(nStream.remainingCandidates(), 3u);
0127 BOOST_CHECK(nStream.isValid());
0128 BOOST_CHECK_EQUAL(&nStream.currentCandidate().surface(),
0129 surfaces.at(3u).get());
0130
0131
0132
0133
0134 nStream = makeStream(surfaces, BoundaryTolerance::None());
0135 BOOST_CHECK(nStream.initialize(
0136 gContext, {Vector3(0., 0., -100.), Vector3(0., 0., 1.)}, logger()));
0137 BOOST_CHECK_EQUAL(nStream.remainingCandidates(), 3u);
0138
0139
0140
0141 nStream = makeStream(surfaces, BoundaryTolerance::Infinite());
0142 BOOST_CHECK(!nStream.initialize(
0143 gContext, {Vector3(0., 0., 0.), Vector3(1., 0., 0.)}, logger()));
0144 BOOST_CHECK_EQUAL(nStream.remainingCandidates(), 0u);
0145 BOOST_CHECK_THROW(nStream.currentCandidate(), std::out_of_range);
0146
0147
0148 nStream = makeStream(surfaces, BoundaryTolerance::Infinite());
0149 nStream.addSurfaceCandidate(*surfaces.at(0), BoundaryTolerance::None());
0150
0151 BOOST_CHECK_EQUAL(nStream.remainingCandidates(), 5u);
0152
0153 BOOST_CHECK(nStream.initialize(
0154 gContext, {Vector3(0., 0., -100.), Vector3(0., 0., 1.)}, logger()));
0155 BOOST_CHECK_EQUAL(nStream.remainingCandidates(), 4u);
0156
0157
0158
0159
0160 nStream = makeStream(surfaces, BoundaryTolerance::Infinite());
0161 nStream.addSurfaceCandidate(*surfaces.at(0), BoundaryTolerance::None());
0162 BOOST_CHECK_EQUAL(nStream.remainingCandidates(), 5u);
0163 BOOST_CHECK(nStream.initialize(gContext,
0164 {Vector3(0., 0., -100.), Vector3(0., 0., 1.)},
0165 logger(), s_onSurfaceTolerance,
0166 true));
0167 BOOST_CHECK_EQUAL(nStream.remainingCandidates(), 4u);
0168 }
0169
0170 BOOST_AUTO_TEST_CASE(NavigationStream_UpdatePlanes) {
0171
0172 auto surfaces = createPlaneSurfaces();
0173
0174
0175
0176
0177 NavigationStream::QueryPoint qPoint = {Vector3(0., 0., -30.),
0178 Vector3(0., 0., 1.)};
0179
0180 NavigationStream nStream =
0181 makeStream(surfaces, BoundaryTolerance::Infinite());
0182 BOOST_CHECK(nStream.initialize(gContext, qPoint, logger()));
0183 BOOST_CHECK_EQUAL(nStream.remainingCandidates(), 4u);
0184 BOOST_CHECK(nStream.isValid());
0185
0186 BOOST_CHECK_EQUAL(&nStream.currentCandidate().surface(),
0187 surfaces.at(1u).get());
0188 CHECK_CLOSE_ABS(nStream.currentCandidate().pathLength(), 10.,
0189 std::numeric_limits<double>::epsilon());
0190
0191
0192 qPoint.position = Vector3(0., 0., -22.);
0193 BOOST_CHECK(nStream.update(gContext, qPoint, logger()));
0194 BOOST_CHECK(nStream.isValid());
0195
0196
0197 BOOST_CHECK_EQUAL(&nStream.currentCandidate().surface(),
0198 surfaces.at(1u).get());
0199 CHECK_CLOSE_ABS(nStream.currentCandidate().pathLength(), 2.,
0200 std::numeric_limits<double>::epsilon());
0201
0202
0203 qPoint.position = Vector3(0., 0., -19.5);
0204 BOOST_CHECK(nStream.update(gContext, qPoint, logger()));
0205 BOOST_CHECK(nStream.isValid());
0206
0207
0208 BOOST_CHECK_EQUAL(&nStream.currentCandidate().surface(),
0209 surfaces.at(1u).get());
0210 CHECK_CLOSE_ABS(nStream.currentCandidate().pathLength(), -0.5,
0211 std::numeric_limits<double>::epsilon());
0212
0213
0214 qPoint.position = Vector3(0., 0., -20.);
0215 BOOST_CHECK(nStream.update(gContext, qPoint, logger()));
0216 BOOST_CHECK(nStream.isValid());
0217
0218
0219 BOOST_CHECK_EQUAL(&nStream.currentCandidate().surface(),
0220 surfaces.at(1u).get());
0221 CHECK_CLOSE_ABS(
0222 nStream.currentCandidate().pathLength(), s_onSurfaceTolerance,
0223 std::numeric_limits<double>::epsilon() + s_onSurfaceTolerance);
0224 BOOST_CHECK_EQUAL(nStream.currentCandidate().status(),
0225 IntersectionStatus::onSurface);
0226
0227 BOOST_CHECK(nStream.switchToNextCandidate());
0228
0229 BOOST_CHECK_EQUAL(&nStream.currentCandidate().surface(),
0230 surfaces.at(3u).get());
0231
0232 CHECK_CLOSE_ABS(nStream.currentCandidate().pathLength(), 130.,
0233 std::numeric_limits<double>::epsilon());
0234 nStream = makeStream(surfaces, BoundaryTolerance::None());
0235 BOOST_CHECK(nStream.initialize(gContext, qPoint, logger()));
0236 BOOST_CHECK(nStream.switchToNextCandidate());
0237
0238
0239
0240
0241 BOOST_CHECK(nStream.update(gContext, qPoint, logger()));
0242 BOOST_CHECK(nStream.isValid());
0243 CHECK_CLOSE_ABS(nStream.currentCandidate().pathLength(), 220.,
0244 std::numeric_limits<double>::epsilon());
0245
0246 qPoint.direction = Vector3(0., 1., 1.).normalized();
0247
0248 BOOST_CHECK(!nStream.update(gContext, qPoint, logger()));
0249 }
0250
0251 BOOST_AUTO_TEST_CASE(NavigationStream_InitializeCylinders) {
0252
0253 auto surfaces = createCylinders();
0254
0255
0256
0257
0258 NavigationStream nStream =
0259 makeStream(surfaces, BoundaryTolerance::Infinite());
0260 BOOST_CHECK(nStream.initialize(
0261 gContext, {Vector3(0., 0., 0.), Vector3(1., 1., 0.).normalized()},
0262 logger()));
0263
0264
0265 BOOST_REQUIRE_EQUAL(nStream.remainingCandidates(), 5u);
0266
0267 BOOST_CHECK_EQUAL(&nStream.candidates()[0u].surface(), surfaces.at(2).get());
0268 BOOST_CHECK_EQUAL(&nStream.candidates()[1u].surface(), surfaces.at(1).get());
0269 BOOST_CHECK_EQUAL(&nStream.candidates()[2u].surface(), surfaces.at(1).get());
0270 BOOST_CHECK_NE(nStream.candidates()[1u].intersectionIndex(),
0271 nStream.candidates()[2u].intersectionIndex());
0272 BOOST_CHECK_EQUAL(&nStream.candidates()[3u].surface(), surfaces.at(0).get());
0273
0274
0275
0276
0277 nStream = makeStream(surfaces, BoundaryTolerance::Infinite());
0278 BOOST_CHECK(nStream.initialize(
0279 gContext, {Vector3(0., 0., 0.), Vector3(1., 0., 0.)}, logger()));
0280
0281 BOOST_CHECK_EQUAL(nStream.remainingCandidates(), 3u);
0282
0283
0284
0285 nStream = makeStream(surfaces, BoundaryTolerance::None());
0286 BOOST_CHECK(nStream.initialize(
0287 gContext, {Vector3(0., 0., 0.), Vector3(1., 0., 0.)}, logger()));
0288
0289 BOOST_CHECK_EQUAL(nStream.remainingCandidates(), 2u);
0290
0291
0292
0293
0294 nStream = makeStream(surfaces, BoundaryTolerance::None());
0295 BOOST_CHECK(!nStream.initialize(
0296 gContext, {Vector3(0., 0., 0.), Vector3(0., 0., 1.)}, logger()));
0297
0298 BOOST_CHECK_EQUAL(nStream.remainingCandidates(), 0u);
0299 BOOST_CHECK_THROW(nStream.currentCandidate(), std::out_of_range);
0300 }
0301
0302 BOOST_AUTO_TEST_CASE(NavigationStream_InitializeCylinderFromBoundaryInwards) {
0303
0304
0305 auto cylinder =
0306 Surface::makeShared<CylinderSurface>(Transform3::Identity(), 20., 100.);
0307 NavigationStream stream;
0308 stream.addSurfaceCandidate(*cylinder, BoundaryTolerance::None());
0309 BOOST_REQUIRE(stream.initialize(
0310 gContext, {Vector3(20., 0., 0.), Vector3(-1., 0., 0.)}, logger()));
0311
0312
0313
0314
0315 while (stream.isValid() &&
0316 stream.currentCandidate().pathLength() <= s_onSurfaceTolerance) {
0317 stream.switchToNextCandidate();
0318 }
0319 BOOST_REQUIRE_MESSAGE(
0320 stream.isValid(),
0321 "Far-side cylinder exit was lost at the entry boundary");
0322 BOOST_CHECK_EQUAL(&stream.currentCandidate().surface(), cylinder.get());
0323 CHECK_CLOSE_ABS(stream.currentCandidate().pathLength(), 40.,
0324 s_onSurfaceTolerance);
0325 }
0326
0327 BOOST_AUTO_TEST_SUITE_END()
0328
0329 }