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 =
48  Surface::makeShared<CylinderSurface>(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  Intersection3D::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  Intersection3D::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  Intersection3D::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  Intersection3D::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  Intersection3D::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  Intersection3D::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  Intersection3D::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  Intersection3D::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  Intersection3D::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  Intersection3D::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>(transform, alpha, true);
176 
177  // Linear transform
178  auto lTransform = transform.linear();
179 
180  // An onCylinder solution
181  Vector3D onCone = transform * Vector3D(std::sqrt(2.), std::sqrt(2.), 2.);
182  Vector3D outCone = transform * Vector3D(std::sqrt(4.), std::sqrt(4.), 2.);
183  // Simply along the x axis
184  Vector3D perpXY = lTransform * Vector3D(1., -1., 0.).normalized();
185  Vector3D transXY = lTransform * Vector3D(1., 1., 0).normalized();
186 
187  // Intersect without boundary check with an on solution
188  BOOST_CHECK(aCone->isOnSurface(tgContext, onCone, transXY, false));
189  auto aIntersection = aCone->intersect(tgContext, onCone, transXY, true);
190 
191  // Check the validity of the interseciton
192  BOOST_CHECK(aIntersection);
193  // The status of this one should be on surface
194  BOOST_CHECK(aIntersection.intersection.status ==
195  Intersection3D::Status::onSurface);
196 
197  // There MUST be a second solution
198  BOOST_CHECK(aIntersection.alternative);
199  // The other intersection MUST be reachable
200  BOOST_CHECK(aIntersection.alternative.status ==
201  Intersection3D::Status::reachable);
202  // The other intersection is at 2 meter distance
203  CHECK_CLOSE_ABS(aIntersection.alternative.pathLength, -4.,
205 
206  // Intersection from outside without chance of hitting the cylinder
207  auto iIntersection = aCone->intersect(tgContext, outCone, perpXY, false);
208 
209  // Check the validity of the interseciton
210  BOOST_CHECK(!iIntersection);
211  };
212 
213  // In a nominal world
214  testConeIntersection(Transform3D::Identity());
215 
216  // In a system somewhere away
217  testConeIntersection(aTransform);
218 }
219 
224 BOOST_AUTO_TEST_CASE(PlanarIntersectionTest) {
225  double halfX = 1_m;
226  double halfY = 10_m;
227 
228  auto testPlanarIntersection = [&](const Transform3D& transform) -> void {
229  // A Plane created with a specific transform
230  auto aPlane = Surface::makeShared<PlaneSurface>(
231  transform, std::make_shared<RectangleBounds>(halfX, halfY));
232 
234  Vector3D before = transform * Vector3D(-50_cm, -1_m, -1_m);
235  Vector3D onit = transform * Vector3D(11_cm, -22_cm, 0_m);
236  Vector3D after = transform * Vector3D(33_cm, 12_mm, 1_m);
237  Vector3D outside = transform * Vector3D(2. * halfX, 2 * halfY, -1_mm);
238 
239  // Linear transform
240  auto lTransform = transform.linear();
241 
242  // A direction that is non trivial
243  Vector3D direction = lTransform * Vector3D(4_mm, 8_mm, 50_cm).normalized();
244  Vector3D parallel = lTransform * Vector3D(1., 1., 0.).normalized();
245 
246  // Intersect forward
247  auto fIntersection = aPlane->intersect(tgContext, before, direction, true);
248 
249  // The intersection MUST be valid
250  BOOST_CHECK(fIntersection);
251  // The intersection MUST be reachable
252  BOOST_CHECK(fIntersection.intersection.status ==
253  Intersection3D::Status::reachable);
254  // The path length MUST be positive
255  BOOST_CHECK(fIntersection.intersection.pathLength > 0.);
256  // The intersection MUST be unique
257  BOOST_CHECK(!fIntersection.alternative);
258 
259  // On surface intersection
260  auto oIntersection = aPlane->intersect(tgContext, onit, direction, true);
261  // The intersection MUST be valid
262  BOOST_CHECK(oIntersection);
263  // The intersection MUST be reachable
264  BOOST_CHECK(oIntersection.intersection.status ==
265  Intersection3D::Status::onSurface);
266  // The path length MUST be positive
267  BOOST_CHECK(std::abs(oIntersection.intersection.pathLength) <
269  // The intersection MUST be unique
270  BOOST_CHECK(!oIntersection.alternative);
271 
272  // Intersect backwards
273  auto bIntersection = aPlane->intersect(tgContext, after, direction, true);
274  // The intersection MUST be valid
275  BOOST_CHECK(bIntersection);
276  // The intersection MUST be reachable
277  BOOST_CHECK(bIntersection.intersection.status ==
278  Intersection3D::Status::reachable);
279  // The path length MUST be negative
280  BOOST_CHECK(bIntersection.intersection.pathLength < 0.);
281  // The intersection MUST be unique
282  BOOST_CHECK(!bIntersection.alternative);
283 
284  // An out of bounds attempt: missed
285  auto mIntersection = aPlane->intersect(tgContext, outside, direction, true);
286  // The intersection MUST NOT be valid
287  BOOST_CHECK(!mIntersection);
288  // The intersection MUST be reachable
289  BOOST_CHECK(mIntersection.intersection.status ==
290  Intersection3D::Status::missed);
291  // The path length MUST be negative
292  BOOST_CHECK(mIntersection.intersection.pathLength > 0.);
293  // The intersection MUST be unique
294  BOOST_CHECK(!mIntersection.alternative);
295 
296  // An invalid attempt
297  auto iIntersection = aPlane->intersect(tgContext, before, parallel, true);
298  // The intersection MUST NOT be valid
299  BOOST_CHECK(!iIntersection);
300  // The intersection MUST be reachable
301  BOOST_CHECK(iIntersection.intersection.status ==
302  Intersection3D::Status::unreachable);
303  // The intersection MUST be unique
304  BOOST_CHECK(!iIntersection.alternative);
305  };
306 
307  // In a nominal world
308  testPlanarIntersection(Transform3D::Identity());
309 
310  // In a system somewhere away
311  testPlanarIntersection(aTransform);
312 }
313 
318 BOOST_AUTO_TEST_CASE(LineIntersectionTest) {
319  double radius = 1_m;
320  double halfZ = 10_m;
321 
322  auto testLineAppraoch = [&](const Transform3D& transform) -> void {
323  // A Plane created with a specific transform
324  auto aLine = Surface::makeShared<StrawSurface>(transform, radius, halfZ);
325 
327  Vector3D before = transform * Vector3D(-50_cm, -1_m, -1_m);
328  Vector3D onit1 = transform * Vector3D(0_m, 0_m, 0_m);
329  Vector3D onitP = transform * Vector3D(1_cm, 0_m, 23_um);
330  Vector3D after = transform * Vector3D(33_cm, 12_mm, 1_m);
331  Vector3D outside = transform * Vector3D(2., 0., 100_m);
332 
333  // Linear transform
334  auto lTransform = transform.linear();
335  Vector3D direction = lTransform * Vector3D(2_cm, 3_cm, 5_cm).normalized();
336  Vector3D normalP = lTransform * Vector3D(0, 1., 0.).normalized();
337  Vector3D parallel = lTransform * Vector3D(0, 0., 1.).normalized();
338 
339  // A random intersection form backward
340  // Intersect forward
341  auto fIntersection = aLine->intersect(tgContext, before, direction, true);
342  // The intersection MUST be valid
343  BOOST_CHECK(fIntersection);
344  // The intersection MUST be reachable
345  BOOST_CHECK(fIntersection.intersection.status ==
346  Intersection3D::Status::reachable);
347  // The path length MUST be positive
348  BOOST_CHECK(fIntersection.intersection.pathLength > 0.);
349  // The intersection MUST be unique
350  BOOST_CHECK(!fIntersection.alternative);
351 
352  // On surface intersection - on the straw with random direction
353  auto oIntersection = aLine->intersect(tgContext, onit1, direction, true);
354  // The intersection MUST be valid
355  BOOST_CHECK(oIntersection);
356  // The intersection MUST be reachable
357  BOOST_CHECK(oIntersection.intersection.status ==
358  Intersection3D::Status::onSurface);
359  // The path length MUST be positive
360  BOOST_CHECK(std::abs(oIntersection.intersection.pathLength) <
362  // The intersection MUST be unique
363  BOOST_CHECK(!oIntersection.alternative);
364 
365  // On surface intersecion - on the surface with normal vector
366  oIntersection = aLine->intersect(tgContext, onitP, normalP, true);
367  // The intersection MUST be valid
368  BOOST_CHECK(oIntersection);
369  // The intersection MUST be reachable
370  BOOST_CHECK(oIntersection.intersection.status ==
371  Intersection3D::Status::onSurface);
372  // The path length MUST be positive
373  BOOST_CHECK(std::abs(oIntersection.intersection.pathLength) <
375  // The intersection MUST be unique
376  BOOST_CHECK(!oIntersection.alternative);
377 
378  // Intersect backwards
379  auto bIntersection = aLine->intersect(tgContext, after, direction, true);
380  // The intersection MUST be valid
381  BOOST_CHECK(bIntersection);
382  // The intersection MUST be reachable
383  BOOST_CHECK(bIntersection.intersection.status ==
384  Intersection3D::Status::reachable);
385  // The path length MUST be negative
386  BOOST_CHECK(bIntersection.intersection.pathLength < 0.);
387  // The intersection MUST be unique
388  BOOST_CHECK(!bIntersection.alternative);
389 
390  // An out of bounds attempt: missed
391  auto mIntersection = aLine->intersect(tgContext, outside, direction, true);
392  // The intersection MUST NOT be valid
393  BOOST_CHECK(!mIntersection);
394  // The intersection MUST be reachable
395  BOOST_CHECK(mIntersection.intersection.status ==
396  Intersection3D::Status::missed);
397  // The path length MUST be negative
398  BOOST_CHECK(mIntersection.intersection.pathLength < 0.);
399  // The intersection MUST be unique
400  BOOST_CHECK(!mIntersection.alternative);
401 
402  // An invalid attempt
403  auto iIntersection = aLine->intersect(tgContext, before, parallel, true);
404  // The intersection MUST NOT be valid
405  BOOST_CHECK(!iIntersection);
406  // The intersection MUST be reachable
407  BOOST_CHECK(iIntersection.intersection.status ==
408  Intersection3D::Status::unreachable);
409  // The intersection MUST be unique
410  BOOST_CHECK(!iIntersection.alternative);
411  };
412 
413  // In a nominal world
414  testLineAppraoch(Transform3D::Identity());
415 
416  // In a system somewhere away
417  testLineAppraoch(aTransform);
418 }
419 
420 BOOST_AUTO_TEST_SUITE_END()
421 
422 } // namespace Test
423 
424 } // namespace Acts