ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SurfaceIntersectionTests.cpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file SurfaceIntersectionTests.cpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2019 CERN for the benefit of the Acts project
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
9 #include <boost/test/data/test_case.hpp>
10 #include <boost/test/tools/output_test_stream.hpp>
11 #include <boost/test/unit_test.hpp>
12 
21 #include "Acts/Utilities/Units.hpp"
22 
23 namespace Acts {
24 
25 using namespace UnitLiterals;
26 
27 // Create a test context
29 
30 // Some random transform
31 Transform3D aTransform = Transform3D::Identity() *
32  Translation3D(30_cm, 7_m, -87_mm) *
33  AngleAxis3D(0.42, Vector3D(-3., 1., 8).normalized());
34 
35 namespace Test {
36 
37 BOOST_AUTO_TEST_SUITE(Surfaces)
38 
39 
40 
41 BOOST_AUTO_TEST_CASE(CylinderIntersectionTests) {
42  double radius = 1_m;
43  double halfZ = 10_m;
44 
45  auto testCylinderIntersection = [&](const Transform3D& transform) -> void {
46  // A cylinder created alinged with a provided transform
47  auto aCylinder = Surface::makeShared<CylinderSurface>(
48  std::make_shared<Transform3D>(transform), radius, halfZ);
49 
50  // Linear transform
51  auto lTransform = transform.linear();
52 
53  // An onCylinder solution
54  Vector3D onCylinder = transform * Vector3D(radius, 0., 0.);
55  Vector3D outCylinder = transform * Vector3D(-radius, 0.6 * radius, 90_cm);
56  Vector3D atCenter = transform * Vector3D(0., 0., 0.);
57  Vector3D atEdge = transform * Vector3D(0.5 * radius, 0., 0.99 * halfZ);
58  // Simply along the x axis
59  Vector3D alongX = lTransform * Vector3D(1., 0., 0.);
60  Vector3D transXY = lTransform * Vector3D(1., 1., 0).normalized();
61  Vector3D transTZ = lTransform * Vector3D(1., 0., 1.).normalized();
62 
63  // Intersect without boundary check
64  auto aIntersection =
65  aCylinder->intersect(tgContext, onCylinder, alongX, true);
66 
67  // Check the validity of the interseciton
68  BOOST_CHECK(aIntersection);
69  // The status of this one should be on surface
70  BOOST_CHECK(aIntersection.intersection.status ==
71  Intersection::Status::onSurface);
72  // There MUST be a second solution
73  BOOST_CHECK(aIntersection.alternative);
74  // The other intersection MUST be reachable
75  BOOST_CHECK(aIntersection.alternative.status ==
76  Intersection::Status::reachable);
77  // The other intersection is at 2 meter distance
78  CHECK_CLOSE_ABS(aIntersection.alternative.pathLength, -2_m,
80 
81  // Intersect from the the center
82  auto cIntersection =
83  aCylinder->intersect(tgContext, atCenter, alongX, true);
84 
85  // Check the validity of the interseciton
86  BOOST_CHECK(cIntersection);
87  // The status of this one MUST be reachable
88  BOOST_CHECK(cIntersection.intersection.status ==
89  Intersection::Status::reachable);
90  // There MUST be a second solution
91  BOOST_CHECK(cIntersection.alternative);
92  // The other intersection MUST be reachable
93  BOOST_CHECK(cIntersection.alternative.status ==
94  Intersection::Status::reachable);
95  // There MUST be one forward one backwards solution
96  BOOST_CHECK(cIntersection.alternative.pathLength *
97  cIntersection.intersection.pathLength <
98  0);
99 
100  // Intersect from outside where both intersections are reachable
101  auto oIntersection =
102  aCylinder->intersect(tgContext, outCylinder, alongX, true);
103 
104  // Check the validity of the interseciton
105  BOOST_CHECK(oIntersection);
106  // The status of this one MUST be reachable
107  BOOST_CHECK(oIntersection.intersection.status ==
108  Intersection::Status::reachable);
109  // There MUST be a second solution
110  BOOST_CHECK(oIntersection.alternative);
111  // The other intersection MUST be reachable
112  BOOST_CHECK(oIntersection.alternative.status ==
113  Intersection::Status::reachable);
114  // There MUST be one forward one backwards solution
115  BOOST_CHECK(oIntersection.alternative.pathLength *
116  oIntersection.intersection.pathLength >
117  0);
118 
119  // Intersection from outside without chance of hitting the cylinder
120  auto iIntersection =
121  aCylinder->intersect(tgContext, outCylinder, transXY, false);
122 
123  // Check the validity of the interseciton
124  BOOST_CHECK(!iIntersection);
125 
126  // From edge tests - wo boundary test
127  auto eIntersection =
128  aCylinder->intersect(tgContext, atEdge, transTZ, false);
129 
130  // Check the validity of the interseciton
131  BOOST_CHECK(eIntersection);
132  // This should be the positive one
133  BOOST_CHECK(eIntersection.intersection.pathLength > 0.);
134  // The status of this one should be reachable
135  BOOST_CHECK(eIntersection.intersection.status ==
136  Intersection::Status::reachable);
137  // There MUST be a second solution
138  BOOST_CHECK(eIntersection.alternative);
139  // The other intersection MUST be reachable
140  BOOST_CHECK(eIntersection.alternative.status ==
141  Intersection::Status::reachable);
142  // And be the negative one
143  BOOST_CHECK(eIntersection.alternative.pathLength < 0.);
144 
145  // Now re-do with boundary check
146  eIntersection = aCylinder->intersect(tgContext, atEdge, transTZ, true);
147  // This should be the negative one
148  BOOST_CHECK(eIntersection.intersection.pathLength < 0.);
149  // The status of this one should be reachable
150  BOOST_CHECK(eIntersection.intersection.status ==
151  Intersection::Status::reachable);
152  // There MUST be a second solution
153  BOOST_CHECK(!eIntersection.alternative);
154  // The other intersection MUST NOT be reachable
155  BOOST_CHECK(eIntersection.alternative.status ==
156  Intersection::Status::missed);
157  // And be the positive one
158  BOOST_CHECK(eIntersection.alternative.pathLength > 0.);
159  };
160 
161  // In a nominal world
162  testCylinderIntersection(Transform3D::Identity());
163 
164  // In a system somewhere away
165  testCylinderIntersection(aTransform);
166 }
167 
170 BOOST_AUTO_TEST_CASE(ConeIntersectionTest) {
171  double alpha = 0.25 * M_PI;
172 
173  auto testConeIntersection = [&](const Transform3D& transform) -> void {
174  // A cone suface ready to use
175  auto aCone = Surface::makeShared<ConeSurface>(
176  std::make_shared<Transform3D>(transform), alpha, true);
177 
178  // Linear transform
179  auto lTransform = transform.linear();
180 
181  // An onCylinder solution
182  Vector3D onCone = transform * Vector3D(std::sqrt(2.), std::sqrt(2.), 2.);
183  Vector3D outCone = transform * Vector3D(std::sqrt(4.), std::sqrt(4.), 2.);
184  // Simply along the x axis
185  Vector3D perpXY = lTransform * Vector3D(1., -1., 0.).normalized();
186  Vector3D transXY = lTransform * Vector3D(1., 1., 0).normalized();
187 
188  // Intersect without boundary check with an on solution
189  BOOST_CHECK(aCone->isOnSurface(tgContext, onCone, transXY, false));
190  auto aIntersection = aCone->intersect(tgContext, onCone, transXY, true);
191 
192  // Check the validity of the interseciton
193  BOOST_CHECK(aIntersection);
194  // The status of this one should be on surface
195  BOOST_CHECK(aIntersection.intersection.status ==
196  Intersection::Status::onSurface);
197 
198  // There MUST be a second solution
199  BOOST_CHECK(aIntersection.alternative);
200  // The other intersection MUST be reachable
201  BOOST_CHECK(aIntersection.alternative.status ==
202  Intersection::Status::reachable);
203  // The other intersection is at 2 meter distance
204  CHECK_CLOSE_ABS(aIntersection.alternative.pathLength, -4.,
206 
207  // Intersection from outside without chance of hitting the cylinder
208  auto iIntersection = aCone->intersect(tgContext, outCone, perpXY, false);
209 
210  // Check the validity of the interseciton
211  BOOST_CHECK(!iIntersection);
212  };
213 
214  // In a nominal world
215  testConeIntersection(Transform3D::Identity());
216 
217  // In a system somewhere away
218  testConeIntersection(aTransform);
219 }
220 
225 BOOST_AUTO_TEST_CASE(PlanarIntersectionTest) {
226  double halfX = 1_m;
227  double halfY = 10_m;
228 
229  auto testPlanarIntersection = [&](const Transform3D& transform) -> void {
230  // A Plane created with a specific transform
231  auto aPlane = Surface::makeShared<PlaneSurface>(
232  std::make_shared<Transform3D>(transform),
233  std::make_shared<RectangleBounds>(halfX, halfY));
234 
236  Vector3D before = transform * Vector3D(-50_cm, -1_m, -1_m);
237  Vector3D onit = transform * Vector3D(11_cm, -22_cm, 0_m);
238  Vector3D after = transform * Vector3D(33_cm, 12_mm, 1_m);
239  Vector3D outside = transform * Vector3D(2. * halfX, 2 * halfY, -1_mm);
240 
241  // Linear transform
242  auto lTransform = transform.linear();
243 
244  // A direction that is non trivial
245  Vector3D direction = lTransform * Vector3D(4_mm, 8_mm, 50_cm).normalized();
246  Vector3D parallel = lTransform * Vector3D(1., 1., 0.).normalized();
247 
248  // Intersect forward
249  auto fIntersection = aPlane->intersect(tgContext, before, direction, true);
250 
251  // The intersection MUST be valid
252  BOOST_CHECK(fIntersection);
253  // The intersection MUST be reachable
254  BOOST_CHECK(fIntersection.intersection.status ==
255  Intersection::Status::reachable);
256  // The path length MUST be positive
257  BOOST_CHECK(fIntersection.intersection.pathLength > 0.);
258  // The intersection MUST be unique
259  BOOST_CHECK(!fIntersection.alternative);
260 
261  // On surface intersection
262  auto oIntersection = aPlane->intersect(tgContext, onit, direction, true);
263  // The intersection MUST be valid
264  BOOST_CHECK(oIntersection);
265  // The intersection MUST be reachable
266  BOOST_CHECK(oIntersection.intersection.status ==
267  Intersection::Status::onSurface);
268  // The path length MUST be positive
269  BOOST_CHECK(std::abs(oIntersection.intersection.pathLength) <
271  // The intersection MUST be unique
272  BOOST_CHECK(!oIntersection.alternative);
273 
274  // Intersect backwards
275  auto bIntersection = aPlane->intersect(tgContext, after, direction, true);
276  // The intersection MUST be valid
277  BOOST_CHECK(bIntersection);
278  // The intersection MUST be reachable
279  BOOST_CHECK(bIntersection.intersection.status ==
280  Intersection::Status::reachable);
281  // The path length MUST be negative
282  BOOST_CHECK(bIntersection.intersection.pathLength < 0.);
283  // The intersection MUST be unique
284  BOOST_CHECK(!bIntersection.alternative);
285 
286  // An out of bounds attempt: missed
287  auto mIntersection = aPlane->intersect(tgContext, outside, direction, true);
288  // The intersection MUST NOT be valid
289  BOOST_CHECK(!mIntersection);
290  // The intersection MUST be reachable
291  BOOST_CHECK(mIntersection.intersection.status ==
292  Intersection::Status::missed);
293  // The path length MUST be negative
294  BOOST_CHECK(mIntersection.intersection.pathLength > 0.);
295  // The intersection MUST be unique
296  BOOST_CHECK(!mIntersection.alternative);
297 
298  // An invalid attempt
299  auto iIntersection = aPlane->intersect(tgContext, before, parallel, true);
300  // The intersection MUST NOT be valid
301  BOOST_CHECK(!iIntersection);
302  // The intersection MUST be reachable
303  BOOST_CHECK(iIntersection.intersection.status ==
304  Intersection::Status::unreachable);
305  // The intersection MUST be unique
306  BOOST_CHECK(!iIntersection.alternative);
307  };
308 
309  // In a nominal world
310  testPlanarIntersection(Transform3D::Identity());
311 
312  // In a system somewhere away
313  testPlanarIntersection(aTransform);
314 }
315 
320 BOOST_AUTO_TEST_CASE(LineIntersectionTest) {
321  double radius = 1_m;
322  double halfZ = 10_m;
323 
324  auto testLineAppraoch = [&](const Transform3D& transform) -> void {
325  // A Plane created with a specific transform
326  auto aLine = Surface::makeShared<StrawSurface>(
327  std::make_shared<Transform3D>(transform), radius, halfZ);
328 
330  Vector3D before = transform * Vector3D(-50_cm, -1_m, -1_m);
331  Vector3D onit1 = transform * Vector3D(0_m, 0_m, 0_m);
332  Vector3D onitP = transform * Vector3D(1_cm, 0_m, 23_um);
333  Vector3D after = transform * Vector3D(33_cm, 12_mm, 1_m);
334  Vector3D outside = transform * Vector3D(2., 0., 100_m);
335 
336  // Linear transform
337  auto lTransform = transform.linear();
338  Vector3D direction = lTransform * Vector3D(2_cm, 3_cm, 5_cm).normalized();
339  Vector3D normalP = lTransform * Vector3D(0, 1., 0.).normalized();
340  Vector3D parallel = lTransform * Vector3D(0, 0., 1.).normalized();
341 
342  // A random intersection form backward
343  // Intersect forward
344  auto fIntersection = aLine->intersect(tgContext, before, direction, true);
345  // The intersection MUST be valid
346  BOOST_CHECK(fIntersection);
347  // The intersection MUST be reachable
348  BOOST_CHECK(fIntersection.intersection.status ==
349  Intersection::Status::reachable);
350  // The path length MUST be positive
351  BOOST_CHECK(fIntersection.intersection.pathLength > 0.);
352  // The intersection MUST be unique
353  BOOST_CHECK(!fIntersection.alternative);
354 
355  // On surface intersection - on the straw with random direction
356  auto oIntersection = aLine->intersect(tgContext, onit1, direction, true);
357  // The intersection MUST be valid
358  BOOST_CHECK(oIntersection);
359  // The intersection MUST be reachable
360  BOOST_CHECK(oIntersection.intersection.status ==
361  Intersection::Status::onSurface);
362  // The path length MUST be positive
363  BOOST_CHECK(std::abs(oIntersection.intersection.pathLength) <
365  // The intersection MUST be unique
366  BOOST_CHECK(!oIntersection.alternative);
367 
368  // On surface intersecion - on the surface with normal vector
369  oIntersection = aLine->intersect(tgContext, onitP, normalP, true);
370  // The intersection MUST be valid
371  BOOST_CHECK(oIntersection);
372  // The intersection MUST be reachable
373  BOOST_CHECK(oIntersection.intersection.status ==
374  Intersection::Status::onSurface);
375  // The path length MUST be positive
376  BOOST_CHECK(std::abs(oIntersection.intersection.pathLength) <
378  // The intersection MUST be unique
379  BOOST_CHECK(!oIntersection.alternative);
380 
381  // Intersect backwards
382  auto bIntersection = aLine->intersect(tgContext, after, direction, true);
383  // The intersection MUST be valid
384  BOOST_CHECK(bIntersection);
385  // The intersection MUST be reachable
386  BOOST_CHECK(bIntersection.intersection.status ==
387  Intersection::Status::reachable);
388  // The path length MUST be negative
389  BOOST_CHECK(bIntersection.intersection.pathLength < 0.);
390  // The intersection MUST be unique
391  BOOST_CHECK(!bIntersection.alternative);
392 
393  // An out of bounds attempt: missed
394  auto mIntersection = aLine->intersect(tgContext, outside, direction, true);
395  // The intersection MUST NOT be valid
396  BOOST_CHECK(!mIntersection);
397  // The intersection MUST be reachable
398  BOOST_CHECK(mIntersection.intersection.status ==
399  Intersection::Status::missed);
400  // The path length MUST be negative
401  BOOST_CHECK(mIntersection.intersection.pathLength < 0.);
402  // The intersection MUST be unique
403  BOOST_CHECK(!mIntersection.alternative);
404 
405  // An invalid attempt
406  auto iIntersection = aLine->intersect(tgContext, before, parallel, true);
407  // The intersection MUST NOT be valid
408  BOOST_CHECK(!iIntersection);
409  // The intersection MUST be reachable
410  BOOST_CHECK(iIntersection.intersection.status ==
411  Intersection::Status::unreachable);
412  // The intersection MUST be unique
413  BOOST_CHECK(!iIntersection.alternative);
414  };
415 
416  // In a nominal world
417  testLineAppraoch(Transform3D::Identity());
418 
419  // In a system somewhere away
420  testLineAppraoch(aTransform);
421 }
422 
423 BOOST_AUTO_TEST_SUITE_END()
424 
425 } // namespace Test
426 
427 } // namespace Acts