Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-10-23 08:24:25

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/tools/old/interface.hpp>
0010 #include <boost/test/tools/output_test_stream.hpp>
0011 #include <boost/test/unit_test.hpp>
0012 
0013 #include "Acts/Definitions/Algebra.hpp"
0014 #include "Acts/Definitions/Alignment.hpp"
0015 #include "Acts/Definitions/Tolerance.hpp"
0016 #include "Acts/Definitions/TrackParametrization.hpp"
0017 #include "Acts/Definitions/Units.hpp"
0018 #include "Acts/Geometry/Extent.hpp"
0019 #include "Acts/Geometry/GeometryContext.hpp"
0020 #include "Acts/Geometry/Polyhedron.hpp"
0021 #include "Acts/Surfaces/PlaneSurface.hpp"
0022 #include "Acts/Surfaces/RectangleBounds.hpp"
0023 #include "Acts/Surfaces/Surface.hpp"
0024 #include "Acts/Surfaces/SurfaceBounds.hpp"
0025 #include "Acts/Surfaces/SurfaceMergingException.hpp"
0026 #include "Acts/Surfaces/TrapezoidBounds.hpp"
0027 #include "Acts/Utilities/Intersection.hpp"
0028 #include "Acts/Utilities/Result.hpp"
0029 #include "Acts/Utilities/ThrowAssert.hpp"
0030 #include "ActsTests/CommonHelpers/DetectorElementStub.hpp"
0031 #include "ActsTests/CommonHelpers/FloatComparisons.hpp"
0032 
0033 #include <cmath>
0034 #include <memory>
0035 #include <numbers>
0036 #include <string>
0037 
0038 using namespace Acts;
0039 using namespace Acts::UnitLiterals;
0040 
0041 namespace ActsTests {
0042 
0043 // Create a test context
0044 GeometryContext tgContext = GeometryContext();
0045 
0046 BOOST_AUTO_TEST_SUITE(SurfacesSuite)
0047 
0048 /// Unit test for creating compliant/non-compliant PlaneSurface object
0049 BOOST_AUTO_TEST_CASE(PlaneSurfaceConstruction) {
0050   /// Test default construction
0051   // default construction is deleted
0052 
0053   // bounds object, rectangle type
0054   auto rBounds = std::make_shared<const RectangleBounds>(3., 4.);
0055   /// Constructor with transform and bounds
0056   Translation3 translation{0., 1., 2.};
0057   auto pTransform = Transform3(translation);
0058 
0059   /// Constructor with transform
0060   BOOST_CHECK_EQUAL(
0061       Surface::makeShared<PlaneSurface>(pTransform, rBounds)->type(),
0062       Surface::Plane);
0063 
0064   /// Copy constructor
0065   auto planeSurfaceObject =
0066       Surface::makeShared<PlaneSurface>(pTransform, rBounds);
0067   auto copiedPlaneSurface =
0068       Surface::makeShared<PlaneSurface>(*planeSurfaceObject);
0069   BOOST_CHECK_EQUAL(copiedPlaneSurface->type(), Surface::Plane);
0070   BOOST_CHECK(*copiedPlaneSurface == *planeSurfaceObject);
0071 
0072   /// Copied and transformed
0073   auto copiedTransformedPlaneSurface = Surface::makeShared<PlaneSurface>(
0074       tgContext, *planeSurfaceObject, pTransform);
0075   BOOST_CHECK_EQUAL(copiedTransformedPlaneSurface->type(), Surface::Plane);
0076 
0077   /// Construct with nullptr bounds
0078   DetectorElementStub detElem;
0079   BOOST_CHECK_THROW(
0080       auto nullBounds = Surface::makeShared<PlaneSurface>(nullptr, detElem),
0081       AssertionFailureException);
0082 }
0083 
0084 /// Unit test for testing PlaneSurface properties
0085 BOOST_AUTO_TEST_CASE(PlaneSurfaceProperties) {
0086   // bounds object, rectangle type
0087   auto rBounds = std::make_shared<const RectangleBounds>(3., 4.);
0088 
0089   /// Test clone method
0090   Translation3 translation{0., 1., 2.};
0091   auto pTransform = Transform3(translation);
0092   auto planeSurfaceObject =
0093       Surface::makeShared<PlaneSurface>(pTransform, rBounds);
0094   // Is it in the right place?
0095   Translation3 translation2{0., 2., 4.};
0096   auto pTransform2 = Transform3(translation2);
0097   auto planeSurfaceObject2 =
0098       Surface::makeShared<PlaneSurface>(pTransform2, rBounds);
0099 
0100   /// Test type (redundant)
0101   BOOST_CHECK_EQUAL(planeSurfaceObject->type(), Surface::Plane);
0102 
0103   /// Test referencePosition
0104   Vector3 referencePosition{0., 1., 2.};
0105   BOOST_CHECK_EQUAL(
0106       planeSurfaceObject->referencePosition(tgContext, AxisDirection::AxisX),
0107       referencePosition);
0108 
0109   /// Test referenceFrame
0110   Vector3 arbitraryGlobalPosition{2., 2., 2.};
0111   Vector3 momentum{1.e6, 1.e6, 1.e6};
0112   RotationMatrix3 expectedFrame;
0113   expectedFrame << 1., 0., 0., 0., 1., 0., 0., 0., 1.;
0114 
0115   CHECK_CLOSE_OR_SMALL(planeSurfaceObject->referenceFrame(
0116                            tgContext, arbitraryGlobalPosition, momentum),
0117                        expectedFrame, 1e-6, 1e-9);
0118 
0119   /// Test normal, given 3D position
0120   Vector3 normal3D(0., 0., 1.);
0121   BOOST_CHECK_EQUAL(planeSurfaceObject->normal(tgContext), normal3D);
0122 
0123   /// Test bounds
0124   BOOST_CHECK_EQUAL(planeSurfaceObject->bounds().type(),
0125                     SurfaceBounds::eRectangle);
0126 
0127   /// Test localToGlobal
0128   Vector2 localPosition{1.5, 1.7};
0129   Vector3 globalPosition =
0130       planeSurfaceObject->localToGlobal(tgContext, localPosition, momentum);
0131   // expected position is the translated one
0132   Vector3 expectedPosition{1.5 + translation.x(), 1.7 + translation.y(),
0133                            translation.z()};
0134 
0135   CHECK_CLOSE_REL(globalPosition, expectedPosition, 1e-2);
0136 
0137   /// Testing globalToLocal
0138   localPosition =
0139       planeSurfaceObject->globalToLocal(tgContext, globalPosition, momentum)
0140           .value();
0141   Vector2 expectedLocalPosition{1.5, 1.7};
0142 
0143   CHECK_CLOSE_REL(localPosition, expectedLocalPosition, 1e-2);
0144 
0145   Vector3 globalPositionOff =
0146       globalPosition +
0147       planeSurfaceObject->normal(tgContext, localPosition) * 0.1;
0148 
0149   BOOST_CHECK(
0150       planeSurfaceObject->globalToLocal(tgContext, globalPositionOff, momentum)
0151           .error());
0152   BOOST_CHECK(planeSurfaceObject
0153                   ->globalToLocal(tgContext, globalPositionOff, momentum, 0.05)
0154                   .error());
0155   BOOST_CHECK(planeSurfaceObject
0156                   ->globalToLocal(tgContext, globalPositionOff, momentum, 0.2)
0157                   .ok());
0158 
0159   /// Test isOnSurface
0160   Vector3 offSurface{0, 1, -2.};
0161   BOOST_CHECK(planeSurfaceObject->isOnSurface(
0162       tgContext, globalPosition, momentum, BoundaryTolerance::None()));
0163   BOOST_CHECK(planeSurfaceObject->isOnSurface(tgContext, globalPosition,
0164                                               BoundaryTolerance::None()));
0165   BOOST_CHECK(!planeSurfaceObject->isOnSurface(tgContext, offSurface, momentum,
0166                                                BoundaryTolerance::None()));
0167   BOOST_CHECK(!planeSurfaceObject->isOnSurface(tgContext, offSurface,
0168                                                BoundaryTolerance::None()));
0169 
0170   /// Test intersection
0171   Vector3 direction{0., 0., 1.};
0172   Intersection3D sfIntersection =
0173       planeSurfaceObject
0174           ->intersect(tgContext, offSurface, direction,
0175                       BoundaryTolerance::None())
0176           .closest();
0177   Intersection3D expectedIntersect{Vector3{0, 1, 2}, 4.,
0178                                    IntersectionStatus::reachable};
0179   BOOST_CHECK(sfIntersection.isValid());
0180   BOOST_CHECK_EQUAL(sfIntersection.position(), expectedIntersect.position());
0181   BOOST_CHECK_EQUAL(sfIntersection.pathLength(),
0182                     expectedIntersect.pathLength());
0183 
0184   /// Test pathCorrection
0185   CHECK_CLOSE_REL(planeSurfaceObject->pathCorrection(tgContext, offSurface,
0186                                                      momentum.normalized()),
0187                   std::numbers::sqrt3, 0.01);
0188 
0189   /// Test name
0190   BOOST_CHECK_EQUAL(planeSurfaceObject->name(),
0191                     std::string("Acts::PlaneSurface"));
0192 
0193   /// Test dump
0194   boost::test_tools::output_test_stream dumpOutput;
0195   dumpOutput << planeSurfaceObject->toStream(tgContext);
0196   BOOST_CHECK(dumpOutput.is_equal(
0197       "Acts::PlaneSurface\n"
0198       "     Center position  (x, y, z) = (0.0000, 1.0000, 2.0000)\n"
0199       "     Rotation:             colX = (1.000000, 0.000000, 0.000000)\n"
0200       "                           colY = (0.000000, 1.000000, 0.000000)\n"
0201       "                           colZ = (0.000000, 0.000000, 1.000000)\n"
0202       "     Bounds  : Acts::RectangleBounds:  (hlX, hlY) = (3.0000000, "
0203       "4.0000000)\n"
0204       "(lower left, upper right):\n"
0205       "-3.0000000 -4.0000000\n"
0206       "3.0000000 4.0000000"));
0207 }
0208 
0209 BOOST_AUTO_TEST_CASE(PlaneSurfaceEqualityOperators) {
0210   // rectangle bounds
0211   auto rBounds = std::make_shared<const RectangleBounds>(3., 4.);
0212   Translation3 translation{0., 1., 2.};
0213   auto pTransform = Transform3(translation);
0214   auto planeSurfaceObject =
0215       Surface::makeShared<PlaneSurface>(pTransform, rBounds);
0216   auto planeSurfaceObject2 =
0217       Surface::makeShared<PlaneSurface>(pTransform, rBounds);
0218 
0219   /// Test equality operator
0220   BOOST_CHECK(*planeSurfaceObject == *planeSurfaceObject2);
0221 
0222   BOOST_TEST_CHECKPOINT(
0223       "Create and then assign a PlaneSurface object to the existing one");
0224 
0225   /// Test assignment
0226   auto assignedPlaneSurface =
0227       Surface::makeShared<PlaneSurface>(Transform3::Identity(), nullptr);
0228   *assignedPlaneSurface = *planeSurfaceObject;
0229 
0230   /// Test equality of assigned to original
0231   BOOST_CHECK(*assignedPlaneSurface == *planeSurfaceObject);
0232 }
0233 
0234 /// Unit test for testing PlaneSurface extent via Polyhedron representation
0235 BOOST_AUTO_TEST_CASE(PlaneSurfaceExtent) {
0236   // First test - non-rotated
0237   static const Transform3 planeZX =
0238       AngleAxis3(-std::numbers::pi / 2., Vector3::UnitX()) *
0239       AngleAxis3(-std::numbers::pi / 2., Vector3::UnitZ()) *
0240       Transform3::Identity();
0241 
0242   double rHx = 2.;
0243   double rHy = 4.;
0244   double yPs = 3.;
0245   auto rBounds = std::make_shared<RectangleBounds>(rHx, rHy);
0246 
0247   auto plane = Surface::makeShared<PlaneSurface>(
0248       Transform3(Translation3(Vector3(0., yPs, 0.)) * planeZX), rBounds);
0249 
0250   auto planeExtent = plane->polyhedronRepresentation(tgContext, 1).extent();
0251 
0252   CHECK_CLOSE_ABS(planeExtent.min(AxisDirection::AxisZ), -rHx,
0253                   s_onSurfaceTolerance);
0254   CHECK_CLOSE_ABS(planeExtent.max(AxisDirection::AxisZ), rHx,
0255                   s_onSurfaceTolerance);
0256   CHECK_CLOSE_ABS(planeExtent.min(AxisDirection::AxisX), -rHy,
0257                   s_onSurfaceTolerance);
0258   CHECK_CLOSE_ABS(planeExtent.max(AxisDirection::AxisX), rHy,
0259                   s_onSurfaceTolerance);
0260   CHECK_CLOSE_ABS(planeExtent.min(AxisDirection::AxisY), yPs,
0261                   s_onSurfaceTolerance);
0262   CHECK_CLOSE_ABS(planeExtent.max(AxisDirection::AxisY), yPs,
0263                   s_onSurfaceTolerance);
0264   CHECK_CLOSE_ABS(planeExtent.min(AxisDirection::AxisR), yPs,
0265                   s_onSurfaceTolerance);
0266   CHECK_CLOSE_ABS(planeExtent.max(AxisDirection::AxisR), std::hypot(yPs, rHy),
0267                   s_onSurfaceTolerance);
0268 
0269   // Now rotate
0270   double alpha = 0.123;
0271   auto planeRot = Surface::makeShared<PlaneSurface>(
0272       Transform3(Translation3(Vector3(0., yPs, 0.)) *
0273                  AngleAxis3(alpha, Vector3(0., 0., 1.)) * planeZX),
0274       rBounds);
0275 
0276   auto planeExtentRot =
0277       planeRot->polyhedronRepresentation(tgContext, 1).extent();
0278   CHECK_CLOSE_ABS(planeExtentRot.min(AxisDirection::AxisZ), -rHx,
0279                   s_onSurfaceTolerance);
0280   CHECK_CLOSE_ABS(planeExtentRot.max(AxisDirection::AxisZ), rHx,
0281                   s_onSurfaceTolerance);
0282   CHECK_CLOSE_ABS(planeExtentRot.min(AxisDirection::AxisX),
0283                   -rHy * std::cos(alpha), s_onSurfaceTolerance);
0284   CHECK_CLOSE_ABS(planeExtentRot.max(AxisDirection::AxisX),
0285                   rHy * std::cos(alpha), s_onSurfaceTolerance);
0286   CHECK_CLOSE_ABS(planeExtentRot.min(AxisDirection::AxisY),
0287                   yPs - rHy * std::sin(alpha), s_onSurfaceTolerance);
0288   CHECK_CLOSE_ABS(planeExtentRot.max(AxisDirection::AxisY),
0289                   yPs + rHy * std::sin(alpha), s_onSurfaceTolerance);
0290   CHECK_CLOSE_ABS(planeExtentRot.min(AxisDirection::AxisR),
0291                   yPs * std::cos(alpha), s_onSurfaceTolerance);
0292 }
0293 
0294 BOOST_AUTO_TEST_CASE(RotatedTrapezoid) {
0295   const double shortHalfX = 100.;
0296   const double longHalfX = 200.;
0297   const double halfY = 300.;
0298   const double rotAngle = 45._degree;
0299 
0300   Vector2 edgePoint{longHalfX - 10., halfY};
0301 
0302   std::shared_ptr<TrapezoidBounds> bounds =
0303       std::make_shared<TrapezoidBounds>(shortHalfX, longHalfX, halfY);
0304 
0305   BOOST_CHECK(bounds->inside(edgePoint, BoundaryTolerance::None()));
0306   BOOST_CHECK(!bounds->inside(Eigen::Rotation2D(-rotAngle) * edgePoint,
0307                               BoundaryTolerance::None()));
0308 
0309   std::shared_ptr<TrapezoidBounds> rotatedBounds =
0310       std::make_shared<TrapezoidBounds>(shortHalfX, longHalfX, halfY, rotAngle);
0311 
0312   BOOST_CHECK(!rotatedBounds->inside(edgePoint, BoundaryTolerance::None()));
0313   BOOST_CHECK(rotatedBounds->inside(Eigen::Rotation2D(-rotAngle) * edgePoint,
0314                                     BoundaryTolerance::None()));
0315 }
0316 
0317 /// Unit test for testing PlaneSurface alignment derivatives
0318 BOOST_AUTO_TEST_CASE(PlaneSurfaceAlignment) {
0319   // bounds object, rectangle type
0320   auto rBounds = std::make_shared<const RectangleBounds>(3., 4.);
0321   // Test clone method
0322   Translation3 translation{0., 1., 2.};
0323   const double rotationAngle = std::numbers::pi / 2.;
0324   AngleAxis3 rotation(rotationAngle, Vector3::UnitY());
0325   RotationMatrix3 rotationMat = rotation.toRotationMatrix();
0326 
0327   auto pTransform = Transform3{translation * rotationMat};
0328   auto planeSurfaceObject =
0329       Surface::makeShared<PlaneSurface>(pTransform, rBounds);
0330 
0331   // The local frame z axis
0332   const Vector3 localZAxis = rotationMat.col(2);
0333   // Check the local z axis is aligned to global x axis
0334   CHECK_CLOSE_ABS(localZAxis, Vector3(1., 0., 0.), 1e-15);
0335 
0336   // Define the track (local) position and direction
0337   Vector2 localPosition{1, 2};
0338   Vector3 momentum{1, 0, 0};
0339   Vector3 direction = momentum.normalized();
0340   // Get the global position
0341   Vector3 globalPosition =
0342       planeSurfaceObject->localToGlobal(tgContext, localPosition, momentum);
0343 
0344   // (a) Test the derivative of path length w.r.t. alignment parameters
0345   const AlignmentToPathMatrix& alignToPath =
0346       planeSurfaceObject->alignmentToPathDerivative(tgContext, globalPosition,
0347                                                     direction);
0348   // The expected results
0349   AlignmentToPathMatrix expAlignToPath = AlignmentToPathMatrix::Zero();
0350   expAlignToPath << 1, 0, 0, 2, -1, 0;
0351 
0352   // Check if the calculated derivative is as expected
0353   CHECK_CLOSE_ABS(alignToPath, expAlignToPath, 1e-10);
0354 
0355   // (b) Test the derivative of bound track parameters local position w.r.t.
0356   // position in local 3D Cartesian coordinates
0357   const auto& loc3DToLocBound =
0358       planeSurfaceObject->localCartesianToBoundLocalDerivative(tgContext,
0359                                                                globalPosition);
0360   // For plane surface, this should be identity matrix
0361   CHECK_CLOSE_ABS(loc3DToLocBound, (ActsMatrix<2, 3>::Identity()), 1e-10);
0362 
0363   // (c) Test the derivative of bound parameters (only test loc0, loc1 here)
0364   // w.r.t. alignment parameters
0365   FreeVector derivatives = FreeVector::Zero();
0366   derivatives.head<3>() = direction;
0367   const AlignmentToBoundMatrix& alignToBound =
0368       planeSurfaceObject->alignmentToBoundDerivative(tgContext, globalPosition,
0369                                                      direction, derivatives);
0370   const AlignmentToPathMatrix alignToloc0 =
0371       alignToBound.block<1, 6>(eBoundLoc0, eAlignmentCenter0);
0372   const AlignmentToPathMatrix alignToloc1 =
0373       alignToBound.block<1, 6>(eBoundLoc1, eAlignmentCenter0);
0374   // The expected results
0375   AlignmentToPathMatrix expAlignToloc0;
0376   expAlignToloc0 << 0, 0, 1, 0, 0, 2;
0377   AlignmentToPathMatrix expAlignToloc1;
0378   expAlignToloc1 << 0, -1, 0, 0, 0, -1;
0379   // Check if the calculated derivatives are as expected
0380   CHECK_CLOSE_ABS(alignToloc0, expAlignToloc0, 1e-10);
0381   CHECK_CLOSE_ABS(alignToloc1, expAlignToloc1, 1e-10);
0382 }
0383 
0384 BOOST_AUTO_TEST_SUITE(PlaneSurfaceMerging)
0385 
0386 auto logger = Acts::getDefaultLogger("UnitTests", Acts::Logging::VERBOSE);
0387 
0388 // Create a test context
0389 GeometryContext gctx = GeometryContext();
0390 
0391 auto rBounds = std::make_shared<const RectangleBounds>(1., 2.);
0392 
0393 BOOST_AUTO_TEST_CASE(SurfaceOverlap) {
0394   // Correct orientation, overlapping along merging direction
0395   Translation3 offsetX{4., 0., 0.};
0396   Translation3 offsetY{0., 2., 0.};
0397 
0398   Transform3 base(Translation3::Identity());
0399   Transform3 otherX = base * offsetX;
0400   Transform3 otherY = base * offsetY;
0401 
0402   auto plane = Surface::makeShared<PlaneSurface>(base, rBounds);
0403   auto planeX = Surface::makeShared<PlaneSurface>(otherX, rBounds);
0404   auto planeY = Surface::makeShared<PlaneSurface>(otherY, rBounds);
0405 
0406   BOOST_CHECK_THROW(plane->mergedWith(*planeX, Acts::AxisDirection::AxisX),
0407                     SurfaceMergingException);
0408   BOOST_CHECK_THROW(plane->mergedWith(*planeY, Acts::AxisDirection::AxisY),
0409                     SurfaceMergingException);
0410 
0411   BOOST_CHECK_THROW(planeX->mergedWith(*plane, Acts::AxisDirection::AxisX),
0412                     SurfaceMergingException);
0413   BOOST_CHECK_THROW(planeY->mergedWith(*plane, Acts::AxisDirection::AxisY),
0414                     SurfaceMergingException);
0415 }
0416 
0417 BOOST_AUTO_TEST_CASE(SurfaceMisalignmentShift) {
0418   // Correct orientation, not aligned along orthogonal to merging direction
0419   Translation3 offsetX{2., 1., 0.};
0420   Translation3 offsetY{-1., 4., 0.};
0421   Translation3 offsetZ{0., 4., 1.};
0422 
0423   Transform3 base(Translation3::Identity());
0424   Transform3 otherX = base * offsetX;
0425   Transform3 otherY = base * offsetY;
0426   Transform3 otherZ = base * offsetZ;
0427 
0428   auto plane = Surface::makeShared<PlaneSurface>(base, rBounds);
0429   auto planeX = Surface::makeShared<PlaneSurface>(otherX, rBounds);
0430   auto planeY = Surface::makeShared<PlaneSurface>(otherY, rBounds);
0431   auto planeZ = Surface::makeShared<PlaneSurface>(otherZ, rBounds);
0432 
0433   BOOST_CHECK_THROW(plane->mergedWith(*planeX, Acts::AxisDirection::AxisX),
0434                     SurfaceMergingException);
0435   BOOST_CHECK_THROW(plane->mergedWith(*planeY, Acts::AxisDirection::AxisY),
0436                     SurfaceMergingException);
0437   BOOST_CHECK_THROW(plane->mergedWith(*planeZ, Acts::AxisDirection::AxisX),
0438                     SurfaceMergingException);
0439 
0440   BOOST_CHECK_THROW(planeX->mergedWith(*plane, Acts::AxisDirection::AxisX),
0441                     SurfaceMergingException);
0442   BOOST_CHECK_THROW(planeY->mergedWith(*plane, Acts::AxisDirection::AxisY),
0443                     SurfaceMergingException);
0444   BOOST_CHECK_THROW(planeZ->mergedWith(*plane, Acts::AxisDirection::AxisX),
0445                     SurfaceMergingException);
0446 }
0447 
0448 BOOST_AUTO_TEST_CASE(SurfaceMisalignedAngle) {
0449   // Correct positioning, rotated in different directions
0450   Translation3 offsetX{2., 0., 0.};
0451   Translation3 offsetY{0., 4., 0.};
0452 
0453   double angle = std::numbers::pi / 12;
0454   Transform3 base(Translation3::Identity());
0455   Transform3 otherX = base * offsetX * AngleAxis3(angle, Vector3::UnitZ());
0456   Transform3 otherY = base * offsetY * AngleAxis3(angle, Vector3::UnitY());
0457   Transform3 otherZ = base * offsetY * AngleAxis3(angle, Vector3::UnitZ());
0458 
0459   auto plane = Surface::makeShared<PlaneSurface>(base, rBounds);
0460   auto planeX = Surface::makeShared<PlaneSurface>(otherX, rBounds);
0461   auto planeY = Surface::makeShared<PlaneSurface>(otherY, rBounds);
0462   auto planeZ = Surface::makeShared<PlaneSurface>(otherZ, rBounds);
0463 
0464   BOOST_CHECK_THROW(plane->mergedWith(*planeX, Acts::AxisDirection::AxisX),
0465                     SurfaceMergingException);
0466   BOOST_CHECK_THROW(plane->mergedWith(*planeY, Acts::AxisDirection::AxisY),
0467                     SurfaceMergingException);
0468   BOOST_CHECK_THROW(plane->mergedWith(*planeZ, Acts::AxisDirection::AxisY),
0469                     SurfaceMergingException);
0470 
0471   BOOST_CHECK_THROW(planeX->mergedWith(*plane, Acts::AxisDirection::AxisX),
0472                     SurfaceMergingException);
0473   BOOST_CHECK_THROW(planeY->mergedWith(*plane, Acts::AxisDirection::AxisY),
0474                     SurfaceMergingException);
0475   BOOST_CHECK_THROW(planeZ->mergedWith(*plane, Acts::AxisDirection::AxisY),
0476                     SurfaceMergingException);
0477 }
0478 
0479 BOOST_AUTO_TEST_CASE(SurfaceDifferentBounds) {
0480   // Correct orientation and alignment, different bounds lengths along
0481   // orthogonal to merging direction
0482   Translation3 offset{2., 0., 0.};
0483 
0484   Transform3 base(Translation3::Identity());
0485   Transform3 other = base * offset;
0486 
0487   auto plane = Surface::makeShared<PlaneSurface>(base, rBounds);
0488 
0489   auto rBoundsOther = std::make_shared<const RectangleBounds>(2., 4.);
0490   auto planeOther = Surface::makeShared<PlaneSurface>(other, rBoundsOther);
0491 
0492   BOOST_CHECK_THROW(plane->mergedWith(*planeOther, Acts::AxisDirection::AxisX),
0493                     SurfaceMergingException);
0494 }
0495 
0496 BOOST_AUTO_TEST_CASE(XYDirection) {
0497   double angle = std::numbers::pi / 12;
0498   Translation3 offsetX{2., 0., 0.};
0499   Translation3 offsetY{0., 4., 0.};
0500 
0501   Transform3 base =
0502       AngleAxis3(angle, Vector3::UnitX()) * Translation3::Identity();
0503   Transform3 otherX = base * offsetX;
0504   Transform3 otherY = base * offsetY;
0505 
0506   auto plane = Surface::makeShared<PlaneSurface>(base, rBounds);
0507   auto planeX = Surface::makeShared<PlaneSurface>(otherX, rBounds);
0508   auto planeY = Surface::makeShared<PlaneSurface>(otherY, rBounds);
0509 
0510   BOOST_CHECK_THROW(plane->mergedWith(*planeX, Acts::AxisDirection::AxisZ),
0511                     SurfaceMergingException);
0512 
0513   auto expectedBoundsX = std::make_shared<const RectangleBounds>(2, 2);
0514   auto [planeXMerged, reversedX] =
0515       plane->mergedWith(*planeX, Acts::AxisDirection::AxisX, *logger);
0516   BOOST_REQUIRE_NE(planeXMerged, nullptr);
0517   BOOST_CHECK(!reversedX);
0518   BOOST_CHECK_EQUAL(planeXMerged->bounds(), *expectedBoundsX);
0519   BOOST_CHECK_EQUAL(planeXMerged->center(gctx), base * Vector3::UnitX() * 1);
0520 
0521   auto expectedBoundsY = std::make_shared<const RectangleBounds>(1, 4);
0522   auto [planeYMerged, reversedY] =
0523       plane->mergedWith(*planeY, Acts::AxisDirection::AxisY, *logger);
0524   BOOST_REQUIRE_NE(planeYMerged, nullptr);
0525   BOOST_CHECK(!reversedY);
0526   BOOST_CHECK_EQUAL(planeYMerged->bounds(), *expectedBoundsY);
0527   BOOST_CHECK_EQUAL(planeYMerged->center(gctx), base * Vector3::UnitY() * 2);
0528 
0529   auto [planeXMerged2, reversedX2] =
0530       planeX->mergedWith(*plane, Acts::AxisDirection::AxisX, *logger);
0531   BOOST_REQUIRE_NE(planeXMerged2, nullptr);
0532   BOOST_CHECK(planeXMerged->bounds() == planeXMerged2->bounds());
0533   BOOST_CHECK(reversedX2);
0534   BOOST_CHECK_EQUAL(planeXMerged2->bounds(), *expectedBoundsX);
0535   BOOST_CHECK_EQUAL(planeXMerged2->center(gctx), base * Vector3::UnitX() * 1);
0536 
0537   auto [planeYMerged2, reversedY2] =
0538       planeY->mergedWith(*plane, Acts::AxisDirection::AxisY, *logger);
0539   BOOST_REQUIRE_NE(planeYMerged2, nullptr);
0540   BOOST_CHECK(planeYMerged->bounds() == planeYMerged2->bounds());
0541   BOOST_CHECK(reversedY2);
0542   BOOST_CHECK_EQUAL(planeYMerged2->bounds(), *expectedBoundsY);
0543   BOOST_CHECK_EQUAL(planeYMerged2->center(gctx), base * Vector3::UnitY() * 2);
0544 }
0545 
0546 BOOST_AUTO_TEST_SUITE_END()
0547 BOOST_AUTO_TEST_SUITE_END()
0548 
0549 }  // namespace ActsTests