Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-30 07:27:26

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 #include <boost/test/unit_test.hpp>
0010 
0011 #include "Acts/Definitions/Units.hpp"
0012 #include "Acts/Geometry/Extent.hpp"
0013 #include "Acts/Geometry/Polyhedron.hpp"
0014 #include "Acts/Surfaces/AnnulusBounds.hpp"
0015 #include "Acts/Surfaces/ConeBounds.hpp"
0016 #include "Acts/Surfaces/ConeSurface.hpp"
0017 #include "Acts/Surfaces/ConvexPolygonBounds.hpp"
0018 #include "Acts/Surfaces/CylinderBounds.hpp"
0019 #include "Acts/Surfaces/CylinderSurface.hpp"
0020 #include "Acts/Surfaces/DiamondBounds.hpp"
0021 #include "Acts/Surfaces/DiscSurface.hpp"
0022 #include "Acts/Surfaces/DiscTrapezoidBounds.hpp"
0023 #include "Acts/Surfaces/EllipseBounds.hpp"
0024 #include "Acts/Surfaces/PlaneSurface.hpp"
0025 #include "Acts/Surfaces/RadialBounds.hpp"
0026 #include "Acts/Surfaces/RectangleBounds.hpp"
0027 #include "Acts/Surfaces/TrapezoidBounds.hpp"
0028 #include "Acts/Utilities/Logger.hpp"
0029 #include "ActsTests/CommonHelpers/FloatComparisons.hpp"
0030 
0031 #include <tuple>
0032 #include <vector>
0033 
0034 using namespace Acts;
0035 using namespace Acts::UnitLiterals;
0036 
0037 Logging::Level logLevel = Logging::VERBOSE;
0038 
0039 namespace ActsTests {
0040 
0041 // Create a test context
0042 const GeometryContext tgContext =
0043     GeometryContext::dangerouslyDefaultConstruct();
0044 
0045 const std::vector<std::tuple<std::string, unsigned int>> testModes = {
0046     {"Triangulate", 18}, {"Extrema", 1}};
0047 
0048 const Transform3 transform = Transform3::Identity();
0049 const double epsAbs = 1e-12;
0050 
0051 BOOST_AUTO_TEST_SUITE(SurfacesSuite)
0052 
0053 /// Unit tests for Cone Surfaces
0054 BOOST_AUTO_TEST_CASE(ConeSurfacePolyhedrons) {
0055   ACTS_LOCAL_LOGGER(
0056       Acts::getDefaultLogger("PolyhedronSurfacesTests", logLevel));
0057   ACTS_INFO("Test: ConeSurfacePolyhedrons");
0058 
0059   const double hzPos = 35_mm;
0060   const double hzNeg = -20_mm;
0061   const double alpha = 0.234;
0062 
0063   const double rMax = hzPos * std::tan(alpha);
0064 
0065   for (const auto& [mode, segments] : testModes) {
0066     ACTS_INFO("\tMode: " << mode);
0067 
0068     /// The full cone on one side
0069     {
0070       auto cone = std::make_shared<ConeBounds>(alpha, 0_mm, hzPos);
0071       auto oneCone = Surface::makeShared<ConeSurface>(transform, cone);
0072       auto oneConePh = oneCone->polyhedronRepresentation(tgContext, segments);
0073 
0074       const auto extent = oneConePh.extent();
0075       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisX).min(), -rMax, epsAbs);
0076       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisX).max(), rMax, epsAbs);
0077       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisY).min(), -rMax, epsAbs);
0078       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisY).max(), rMax, epsAbs);
0079       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).min(), 0_mm, epsAbs);
0080       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).max(), rMax, epsAbs);
0081       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).min(), 0_mm, epsAbs);
0082       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).max(), hzPos, epsAbs);
0083 
0084       const unsigned int expectedFaces = 4 * segments;
0085       BOOST_CHECK_EQUAL(oneConePh.faces.size(), expectedFaces);
0086       // full segments + overlap at (pi/pi) + tip
0087       BOOST_CHECK_EQUAL(oneConePh.vertices.size(), expectedFaces + 2);
0088     }
0089 
0090     /// The full cone on one side
0091     {
0092       const double hzpMin = 10_mm;
0093       const double rMin = hzpMin * std::tan(alpha);
0094 
0095       auto conePiece = std::make_shared<ConeBounds>(alpha, hzpMin, hzPos);
0096       auto oneConePiece =
0097           Surface::makeShared<ConeSurface>(transform, conePiece);
0098       auto oneConePiecePh =
0099           oneConePiece->polyhedronRepresentation(tgContext, segments);
0100 
0101       const auto extent = oneConePiecePh.extent();
0102       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisX).min(), -rMax, epsAbs);
0103       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisX).max(), rMax, epsAbs);
0104       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisY).min(), -rMax, epsAbs);
0105       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisY).max(), rMax, epsAbs);
0106       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).min(), rMin, epsAbs);
0107       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).max(), rMax, epsAbs);
0108       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).min(), hzpMin, epsAbs);
0109       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).max(), hzPos, epsAbs);
0110 
0111       const unsigned int expectedFaces = 4 * segments;
0112       BOOST_CHECK_EQUAL(oneConePiecePh.faces.size(), expectedFaces);
0113       BOOST_CHECK_EQUAL(oneConePiecePh.vertices.size(),
0114                         (expectedFaces + 1) * 2);
0115     }
0116 
0117     /// The full cone on both sides
0118     {
0119       auto coneBoth = std::make_shared<ConeBounds>(alpha, hzNeg, hzPos);
0120       auto twoCones = Surface::makeShared<ConeSurface>(transform, coneBoth);
0121       auto twoConesPh = twoCones->polyhedronRepresentation(tgContext, segments);
0122 
0123       const auto extent = twoConesPh.extent();
0124       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisX).min(), -rMax, epsAbs);
0125       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisX).max(), rMax, epsAbs);
0126       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisY).min(), -rMax, epsAbs);
0127       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisY).max(), rMax, epsAbs);
0128       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).min(), 0_mm, epsAbs);
0129       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).max(), rMax, epsAbs);
0130       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).min(), hzNeg, epsAbs);
0131       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).max(), hzPos, epsAbs);
0132 
0133       const unsigned int expectedFaces = 2 * segments * 4;
0134       const unsigned int expectedVertices = 2 * (4 * segments + 1) + 1;
0135 
0136       BOOST_CHECK_EQUAL(twoConesPh.faces.size(), expectedFaces);
0137       BOOST_CHECK_EQUAL(twoConesPh.vertices.size(), expectedVertices);
0138     }
0139 
0140     /// A centered sectoral cone on both sides
0141     {
0142       const double phiSector = 0.358;
0143 
0144       auto sectoralBoth =
0145           std::make_shared<ConeBounds>(alpha, hzNeg, hzPos, phiSector, 0.);
0146       auto sectoralCones =
0147           Surface::makeShared<ConeSurface>(transform, sectoralBoth);
0148       auto sectoralConesPh =
0149           sectoralCones->polyhedronRepresentation(tgContext, segments);
0150 
0151       const auto extent = sectoralConesPh.extent();
0152       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisX).min(), 0, epsAbs);
0153       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisX).max(), rMax, epsAbs);
0154       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisY).min(),
0155                       -rMax * std::sin(phiSector), epsAbs);
0156       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisY).max(),
0157                       rMax * std::sin(phiSector), epsAbs);
0158       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).min(), 0_mm, epsAbs);
0159       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).max(), rMax, epsAbs);
0160       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).min(), hzNeg, epsAbs);
0161       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).max(), hzPos, epsAbs);
0162 
0163       // Segment numbers are further checked with the VertexHelper checks
0164     }
0165   }
0166 }
0167 
0168 /// Unit tests for Cylinder Surfaces
0169 BOOST_AUTO_TEST_CASE(CylinderSurfacePolyhedrons) {
0170   ACTS_LOCAL_LOGGER(
0171       Acts::getDefaultLogger("PolyhedronSurfacesTests", logLevel));
0172   ACTS_INFO("Test: CylinderSurfacePolyhedrons");
0173 
0174   const double r = 25_mm;
0175   const double hZ = 35_mm;
0176 
0177   for (const auto& mode : testModes) {
0178     ACTS_INFO("\tMode: " << std::get<std::string>(mode));
0179     const unsigned int segments = std::get<unsigned int>(mode);
0180 
0181     /// The full cone on one side
0182     {
0183       auto cylinder = std::make_shared<CylinderBounds>(r, hZ);
0184       auto fullCylinder =
0185           Surface::makeShared<CylinderSurface>(transform, cylinder);
0186       auto fullCylinderPh =
0187           fullCylinder->polyhedronRepresentation(tgContext, segments);
0188 
0189       const auto extent = fullCylinderPh.extent();
0190       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisX).min(), -r, epsAbs);
0191       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisX).max(), r, epsAbs);
0192       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisY).min(), -r, epsAbs);
0193       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisY).max(), r, epsAbs);
0194       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).min(), r, epsAbs);
0195       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).max(), r, epsAbs);
0196       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).min(), -hZ, epsAbs);
0197       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).max(), hZ, epsAbs);
0198 
0199       const unsigned int expectedFaces = 4 * segments;
0200       const unsigned int expectedVertices = (4 * segments + 1) * 2;
0201       BOOST_CHECK_EQUAL(fullCylinderPh.faces.size(), expectedFaces);
0202       BOOST_CHECK_EQUAL(fullCylinderPh.vertices.size(), expectedVertices);
0203     }
0204 
0205     /// The full cone on one side
0206     {
0207       const double phiSector = 0.458;
0208 
0209       auto sectorCentered = std::make_shared<CylinderBounds>(r, hZ, phiSector);
0210       auto centerSectoredCylinder =
0211           Surface::makeShared<CylinderSurface>(transform, sectorCentered);
0212       auto centerSectoredCylinderPh =
0213           centerSectoredCylinder->polyhedronRepresentation(tgContext, segments);
0214 
0215       const auto extent = centerSectoredCylinderPh.extent();
0216       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisX).min(),
0217                       r * std::cos(phiSector), epsAbs);
0218       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisX).max(), r, epsAbs);
0219       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisY).min(),
0220                       -r * std::sin(phiSector), epsAbs);
0221       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisY).max(),
0222                       r * std::sin(phiSector), epsAbs);
0223       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).min(), r, epsAbs);
0224       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).max(), r, epsAbs);
0225       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).min(), -hZ, epsAbs);
0226       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).max(), hZ, epsAbs);
0227     }
0228   }
0229 }
0230 
0231 /// Unit tests for Disc Surfaces
0232 BOOST_AUTO_TEST_CASE(DiscSurfacePolyhedrons) {
0233   ACTS_LOCAL_LOGGER(
0234       Acts::getDefaultLogger("PolyhedronSurfacesTests", logLevel));
0235   ACTS_INFO("Test: DiscSurfacePolyhedrons");
0236 
0237   const double innerR = 10_mm;
0238   const double outerR = 25_mm;
0239   const double phiSector = 0.345;
0240 
0241   for (const auto& mode : testModes) {
0242     ACTS_INFO("\tMode: " << std::get<std::string>(mode));
0243     const unsigned int segments = std::get<unsigned int>(mode);
0244 
0245     /// Full disc
0246     {
0247       auto disc = std::make_shared<RadialBounds>(0_mm, outerR);
0248       auto fullDisc = Surface::makeShared<DiscSurface>(transform, disc);
0249       auto fullDiscPh = fullDisc->polyhedronRepresentation(tgContext, segments);
0250 
0251       const auto extent = fullDiscPh.extent();
0252       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisX).min(), -outerR,
0253                       epsAbs);
0254       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisX).max(), outerR, epsAbs);
0255       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisY).min(), -outerR,
0256                       epsAbs);
0257       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisY).max(), outerR, epsAbs);
0258       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).min(), 0., epsAbs);
0259       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).max(), outerR, epsAbs);
0260       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).min(), 0., epsAbs);
0261       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).max(), 0., epsAbs);
0262 
0263       const unsigned int expectedFaces = 1;
0264       // Segments + overlap + center
0265       const unsigned int expectedVertices = 4 * segments + 1 + 1;
0266       BOOST_CHECK_EQUAL(fullDiscPh.faces.size(), expectedFaces);
0267       BOOST_CHECK_EQUAL(fullDiscPh.vertices.size(), expectedVertices);
0268     }
0269 
0270     /// Ring disc
0271     {
0272       auto radial = std::make_shared<RadialBounds>(innerR, outerR);
0273       auto radialDisc = Surface::makeShared<DiscSurface>(transform, radial);
0274       auto radialPh = radialDisc->polyhedronRepresentation(tgContext, segments);
0275 
0276       const auto extent = radialPh.extent();
0277       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisX).min(), -outerR,
0278                       epsAbs);
0279       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisX).max(), outerR, epsAbs);
0280       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisY).min(), -outerR,
0281                       epsAbs);
0282       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisY).max(), outerR, epsAbs);
0283       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).min(), innerR, epsAbs);
0284       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).max(), outerR, epsAbs);
0285       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).min(), 0., epsAbs);
0286       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).max(), 0., epsAbs);
0287     }
0288 
0289     /// Sectoral disc - around 0.
0290     {
0291       auto sector = std::make_shared<RadialBounds>(0., outerR, phiSector);
0292       auto sectorDisc = Surface::makeShared<DiscSurface>(transform, sector);
0293       auto sectorPh = sectorDisc->polyhedronRepresentation(tgContext, segments);
0294 
0295       const auto extent = sectorPh.extent();
0296       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisX).min(), 0., epsAbs);
0297       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisX).max(), outerR, epsAbs);
0298       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisY).min(),
0299                       -outerR * std::sin(phiSector), epsAbs);
0300       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisY).max(),
0301                       outerR * std::sin(phiSector), epsAbs);
0302       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).min(), 0., epsAbs);
0303       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).max(), outerR, epsAbs);
0304       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).min(), 0., epsAbs);
0305       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).max(), 0., epsAbs);
0306     }
0307 
0308     /// Sectoral ring - around 0.
0309     {
0310       auto sectorRing =
0311           std::make_shared<RadialBounds>(innerR, outerR, phiSector);
0312       auto sectorRingDisc =
0313           Surface::makeShared<DiscSurface>(transform, sectorRing);
0314       auto sectorRingDiscPh =
0315           sectorRingDisc->polyhedronRepresentation(tgContext, segments);
0316 
0317       const auto extent = sectorRingDiscPh.extent();
0318       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisX).min(),
0319                       innerR * std::cos(phiSector), epsAbs);
0320       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisX).max(), outerR, epsAbs);
0321       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisY).min(),
0322                       -outerR * std::sin(phiSector), epsAbs);
0323       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisY).max(),
0324                       outerR * std::sin(phiSector), epsAbs);
0325       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).min(), innerR, epsAbs);
0326       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).max(), outerR, epsAbs);
0327       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).min(), 0., epsAbs);
0328       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).max(), 0., epsAbs);
0329     }
0330 
0331     /// Trapezoid for a disc
0332     {
0333       const double halfXmin = 10_mm;
0334       const double halfXmax = 20_mm;
0335 
0336       auto trapezoidDisc = std::make_shared<DiscTrapezoidBounds>(
0337           halfXmin, halfXmax, innerR, outerR, 0.);
0338       auto trapezoidDiscSf =
0339           Surface::makeShared<DiscSurface>(transform, trapezoidDisc);
0340       auto trapezoidDiscSfPh =
0341           trapezoidDiscSf->polyhedronRepresentation(tgContext, segments);
0342       const auto extent = trapezoidDiscSfPh.extent();
0343 
0344       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisX).min(),
0345                       -std::abs(outerR - innerR) / 2., epsAbs);
0346       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisX).max(),
0347                       std::abs(outerR - innerR) / 2., epsAbs);
0348       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisY).min(), -halfXmax,
0349                       epsAbs);
0350       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisY).max(), halfXmax,
0351                       epsAbs);
0352       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).min(), 0., epsAbs);
0353       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).max(),
0354                       std::hypot(std::abs(outerR - innerR) / 2., halfXmax),
0355                       epsAbs);
0356       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).min(), 0., epsAbs);
0357       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).max(), 0., epsAbs);
0358     }
0359 
0360     /// AnnulusBounds for a disc
0361     {
0362       const double minRadius = 7.;
0363       const double maxRadius = 12.;
0364       const double minPhiA = 0.75;
0365       const double maxPhiA = 1.4;
0366       const Vector2 offset(0., 0.);
0367 
0368       auto annulus = std::make_shared<AnnulusBounds>(minRadius, maxRadius,
0369                                                      minPhiA, maxPhiA, offset);
0370       auto annulusDisc = Surface::makeShared<DiscSurface>(transform, annulus);
0371       auto annulusDiscPh =
0372           annulusDisc->polyhedronRepresentation(tgContext, segments);
0373       const auto extent = annulusDiscPh.extent();
0374       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).min(), minRadius,
0375                       epsAbs);
0376       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).max(), maxRadius,
0377                       epsAbs);
0378       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).min(), 0., epsAbs);
0379       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).max(), 0., epsAbs);
0380     }
0381   }
0382 }
0383 
0384 /// Unit tests for Plane Surfaces
0385 BOOST_AUTO_TEST_CASE(PlaneSurfacePolyhedrons) {
0386   ACTS_LOCAL_LOGGER(
0387       Acts::getDefaultLogger("PolyhedronSurfacesTests", logLevel));
0388   ACTS_INFO("Test: PlaneSurfacePolyhedrons");
0389 
0390   for (const auto& mode : testModes) {
0391     ACTS_INFO("\tMode: " << std::get<std::string>(mode));
0392     const unsigned int segments = std::get<unsigned int>(mode);
0393 
0394     /// Rectangular Plane
0395     {
0396       const double rhX = 10_mm;
0397       const double rhY = 25_mm;
0398 
0399       auto rectangular = std::make_shared<RectangleBounds>(rhX, rhY);
0400       auto rectangularPlane =
0401           Surface::makeShared<PlaneSurface>(transform, rectangular);
0402       auto rectangularPh =
0403           rectangularPlane->polyhedronRepresentation(tgContext, segments);
0404 
0405       const auto extent = rectangularPh.extent();
0406       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisX).min(), -rhX, epsAbs);
0407       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisX).max(), rhX, epsAbs);
0408       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisY).min(), -rhY, epsAbs);
0409       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisY).max(), rhY, epsAbs);
0410       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).min(), 0., epsAbs);
0411       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).max(),
0412                       std::hypot(rhX, rhY), epsAbs);
0413       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).min(), 0., epsAbs);
0414       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).max(), 0., epsAbs);
0415 
0416       BOOST_CHECK_EQUAL(rectangularPh.vertices.size(), 4);
0417       BOOST_CHECK_EQUAL(rectangularPh.faces.size(), 1);
0418 
0419       const std::vector<std::size_t> expectedRect = {0, 1, 2, 3};
0420       BOOST_CHECK(rectangularPh.faces[0] == expectedRect);
0421     }
0422 
0423     /// Trapezoidal Plane
0424     {
0425       const double thX1 = 10_mm;
0426       const double thX2 = 25_mm;
0427       const double thY = 35_mm;
0428 
0429       auto trapezoid = std::make_shared<TrapezoidBounds>(thX1, thX2, thY);
0430       auto trapezoidalPlane =
0431           Surface::makeShared<PlaneSurface>(transform, trapezoid);
0432       auto trapezoidalPh =
0433           trapezoidalPlane->polyhedronRepresentation(tgContext, segments);
0434 
0435       const auto extent = trapezoidalPh.extent();
0436       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisX).min(),
0437                       -std::max(thX1, thX2), epsAbs);
0438       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisX).max(),
0439                       std::max(thX1, thX2), epsAbs);
0440       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisY).min(), -thY, epsAbs);
0441       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisY).max(), thY, epsAbs);
0442       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).min(), 0., epsAbs);
0443       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).max(),
0444                       std::hypot(std::max(thX1, thX2), thY), epsAbs);
0445       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).min(), 0., epsAbs);
0446       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).max(), 0., epsAbs);
0447 
0448       BOOST_CHECK_EQUAL(trapezoidalPh.vertices.size(), 4);
0449       BOOST_CHECK_EQUAL(trapezoidalPh.faces.size(), 1);
0450 
0451       const std::vector<std::size_t> expectedTra = {0, 1, 2, 3};
0452       BOOST_CHECK(trapezoidalPh.faces[0] == expectedTra);
0453     }
0454 
0455     /// Ring-like ellipsoidal plane
0456     {
0457       const double rMinX = 0_mm;
0458       const double rMinY = 0_mm;
0459       const double rMaxX = 30_mm;
0460       const double rMaxY = 40_mm;
0461       auto ellipse =
0462           std::make_shared<EllipseBounds>(rMinX, rMinY, rMaxX, rMaxY);
0463       auto ellipsoidPlane =
0464           Surface::makeShared<PlaneSurface>(transform, ellipse);
0465       auto ellipsoidPh =
0466           ellipsoidPlane->polyhedronRepresentation(tgContext, segments);
0467 
0468       const auto extent = ellipsoidPh.extent();
0469       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisX).min(), -rMaxX, epsAbs);
0470       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisX).max(), rMaxX, epsAbs);
0471       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisY).min(), -rMaxY, epsAbs);
0472       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisY).max(), rMaxY, epsAbs);
0473       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).min(),
0474                       std::min(rMinX, rMinY), epsAbs);
0475       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).max(),
0476                       std::max(rMaxX, rMaxY), epsAbs);
0477       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).min(), 0., epsAbs);
0478       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).max(), 0., epsAbs);
0479     }
0480 
0481     {
0482       const double rMinX = 10_mm;
0483       const double rMinY = 20_mm;
0484       const double rMaxX = 30_mm;
0485       const double rMaxY = 40_mm;
0486       auto ellipseRing =
0487           std::make_shared<EllipseBounds>(rMinX, rMinY, rMaxX, rMaxY);
0488       auto ellipsoidRingPlane =
0489           Surface::makeShared<PlaneSurface>(transform, ellipseRing);
0490       auto ellipsoidRingPh =
0491           ellipsoidRingPlane->polyhedronRepresentation(tgContext, segments);
0492 
0493       const auto extent = ellipsoidRingPh.extent();
0494       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisX).min(), -rMaxX, epsAbs);
0495       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisX).max(), rMaxX, epsAbs);
0496       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisY).min(), -rMaxY, epsAbs);
0497       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisY).max(), rMaxY, epsAbs);
0498       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).min(),
0499                       std::min(rMinX, rMinY), epsAbs);
0500       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).max(),
0501                       std::max(rMaxX, rMaxY), epsAbs);
0502       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).min(), 0., epsAbs);
0503       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).max(), 0., epsAbs);
0504     }
0505 
0506     /// ConvexPolygonBounds test
0507     {
0508       std::vector<Vector2> vtxs = {
0509           Vector2(-40_mm, -10_mm), Vector2(-10_mm, -30_mm),
0510           Vector2(30_mm, -20_mm),  Vector2(10_mm, 20_mm),
0511           Vector2(-20_mm, 50_mm),  Vector2(-30_mm, 30_mm)};
0512 
0513       auto hexagon = std::make_shared<ConvexPolygonBounds<6>>(vtxs);
0514       auto hexagonPlane = Surface::makeShared<PlaneSurface>(transform, hexagon);
0515       auto hexagonPlanePh =
0516           hexagonPlane->polyhedronRepresentation(tgContext, segments);
0517 
0518       const auto extent = hexagonPlanePh.extent();
0519       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisX).min(), -40, epsAbs);
0520       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisX).max(), 30, epsAbs);
0521       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisY).min(), -30, epsAbs);
0522       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisY).max(), 50, epsAbs);
0523       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).min(), 0, epsAbs);
0524       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).max(), std::sqrt(2900),
0525                       epsAbs);
0526       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).min(), 0., epsAbs);
0527       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).max(), 0., epsAbs);
0528     }
0529 
0530     /// Diamond shaped plane
0531     {
0532       const double hMinX = 10_mm;
0533       const double hMedX = 20_mm;
0534       const double hMaxX = 15_mm;
0535       const double hMinY = 40_mm;
0536       const double hMaxY = 50_mm;
0537 
0538       auto diamond =
0539           std::make_shared<DiamondBounds>(hMinX, hMedX, hMaxX, hMinY, hMaxY);
0540       auto diamondPlane = Surface::makeShared<PlaneSurface>(transform, diamond);
0541       auto diamondPh =
0542           diamondPlane->polyhedronRepresentation(tgContext, segments);
0543 
0544       const auto extent = diamondPh.extent();
0545       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisX).min(), -hMedX, epsAbs);
0546       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisX).max(), hMedX, epsAbs);
0547       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisY).min(), -hMinY, epsAbs);
0548       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisY).max(), hMaxY, epsAbs);
0549       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).min(), 0., epsAbs);
0550       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).max(),
0551                       std::hypot(hMaxX, hMaxY), epsAbs);
0552       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).min(), 0., epsAbs);
0553       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).max(), 0., epsAbs);
0554 
0555       BOOST_CHECK_EQUAL(diamondPh.vertices.size(), 6);
0556       BOOST_CHECK_EQUAL(diamondPh.faces.size(), 1);
0557     }
0558   }
0559 }
0560 
0561 /// Unit tests shifted plane
0562 BOOST_AUTO_TEST_CASE(ShiftedSurfacePolyhedrons) {
0563   ACTS_LOCAL_LOGGER(
0564       Acts::getDefaultLogger("PolyhedronSurfacesTests", logLevel));
0565   ACTS_INFO("Test: ShiftedSurfacePolyhedrons");
0566 
0567   const double shiftY = 50_mm;
0568   Vector3 shift(0., shiftY, 0.);
0569   Transform3 shiftedTransform = Transform3::Identity();
0570   shiftedTransform.pretranslate(shift);
0571 
0572   for (const auto& mode : testModes) {
0573     ACTS_INFO("\tMode: " << std::get<std::string>(mode));
0574     const unsigned int segments = std::get<unsigned int>(mode);
0575 
0576     /// Rectangular Plane
0577     {
0578       const double rhX = 10_mm;
0579       const double rhY = 25_mm;
0580 
0581       auto rectangular = std::make_shared<RectangleBounds>(rhX, rhY);
0582       auto rectangularPlane =
0583           Surface::makeShared<PlaneSurface>(shiftedTransform, rectangular);
0584       auto rectangularPh =
0585           rectangularPlane->polyhedronRepresentation(tgContext, segments);
0586 
0587       const auto extent = rectangularPh.extent();
0588       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisX).min(), -rhX, epsAbs);
0589       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisX).max(), rhX, epsAbs);
0590       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisY).min(), -rhY + shiftY,
0591                       epsAbs);
0592       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisY).max(), rhY + shiftY,
0593                       epsAbs);
0594       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).min(), 25, epsAbs);
0595       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisR).max(),
0596                       std::hypot(rhX, rhY + shiftY), epsAbs);
0597       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).min(), 0., epsAbs);
0598       CHECK_CLOSE_ABS(extent.range(AxisDirection::AxisZ).max(), 0., epsAbs);
0599 
0600       BOOST_CHECK_EQUAL(rectangularPh.vertices.size(), 4);
0601       BOOST_CHECK_EQUAL(rectangularPh.faces.size(), 1);
0602 
0603       const std::vector<std::size_t> expectedRect = {0, 1, 2, 3};
0604       BOOST_CHECK(rectangularPh.faces[0] == expectedRect);
0605     }
0606   }
0607 }
0608 BOOST_AUTO_TEST_SUITE_END()
0609 
0610 }  // namespace ActsTests