Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add possibility to rotate the trapezoid bounds #2583

Merged
merged 15 commits into from
Mar 12, 2024
37 changes: 8 additions & 29 deletions Core/include/Acts/Surfaces/TrapezoidBounds.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ class TrapezoidBounds : public PlanarBounds {
eHalfLengthXnegY = 0,
eHalfLengthXposY = 1,
eHalfLengthY = 2,
eSize = 3
eRotationAngle = 3,
eSize = 4
};

TrapezoidBounds() = delete;
Expand All @@ -46,23 +47,14 @@ class TrapezoidBounds : public PlanarBounds {
/// @param halfXnegY minimal half length X, definition at negative Y
/// @param halfXposY maximal half length X, definition at positive Y
/// @param halfY half length Y - defined at x=0
TrapezoidBounds(double halfXnegY, double halfXposY,
double halfY) noexcept(false)
: m_values({halfXnegY, halfXposY, halfY}),
m_boundingBox(std::max(halfXnegY, halfXposY), halfY) {
checkConsistency();
}
/// @param rotAngle: rotation angle of the bounds w.r.t coordinate axes
TrapezoidBounds(double halfXnegY, double halfXposY, double halfY,
double rotAngle = 0.) noexcept(false);

/// Constructor for symmetric Trapezoid - from fixed size array
///
/// @param values the values to be stream in
TrapezoidBounds(const std::array<double, eSize>& values) noexcept(false)
: m_values(values),
m_boundingBox(
std::max(values[eHalfLengthXnegY], values[eHalfLengthXposY]),
values[eHalfLengthY]) {
checkConsistency();
}
TrapezoidBounds(const std::array<double, eSize>& values) noexcept(false);

~TrapezoidBounds() override;

Expand Down Expand Up @@ -140,24 +132,11 @@ class TrapezoidBounds : public PlanarBounds {
std::array<double, eSize> m_values;
RectangleBounds m_boundingBox;

void rotateBoundingBox() noexcept(false);

/// Check the input values for consistency, will throw a logic_exception
/// if consistency is not given
void checkConsistency() noexcept(false);
};

inline std::vector<double> TrapezoidBounds::values() const {
std::vector<double> valvector;
valvector.insert(valvector.begin(), m_values.begin(), m_values.end());
return valvector;
}

inline void TrapezoidBounds::checkConsistency() noexcept(false) {
if (get(eHalfLengthXnegY) <= 0. || get(eHalfLengthXposY) <= 0.) {
throw std::invalid_argument("TrapezoidBounds: invalid local x setup");
}
if (get(eHalfLengthY) <= 0.) {
throw std::invalid_argument("TrapezoidBounds: invalid local y setup");
}
}

} // namespace Acts
91 changes: 76 additions & 15 deletions Core/src/Surfaces/TrapezoidBounds.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,39 @@
#include "Acts/Surfaces/TrapezoidBounds.hpp"

#include "Acts/Definitions/TrackParametrization.hpp"
#include "Acts/Surfaces/ConvexPolygonBounds.hpp"

#include <iomanip>
#include <iostream>

/// Constructor for symmetric Trapezoid
///
/// @param halfXnegY minimal half length X, definition at negative Y
/// @param halfXposY maximal half length X, definition at positive Y
/// @param halfY half length Y - defined at x=0
/// @param rotAngle: rotation angle of the bounds w.r.t coordinate axes
Acts::TrapezoidBounds::TrapezoidBounds(double halfXnegY, double halfXposY,
double halfY,
double rotAngle) noexcept(false)
: m_values({halfXnegY, halfXposY, halfY, rotAngle}),
m_boundingBox(std::max(halfXnegY, halfXposY), halfY) {
rotateBoundingBox();
checkConsistency();
}

/// Constructor for symmetric Trapezoid - from fixed size array
///
/// @param values the values to be stream in
Acts::TrapezoidBounds::TrapezoidBounds(
const std::array<double, eSize>& values) noexcept(false)
: m_values(values),
m_boundingBox(
std::max(values[eHalfLengthXnegY], values[eHalfLengthXposY]),
values[eHalfLengthY]) {
rotateBoundingBox();
checkConsistency();
}

Acts::TrapezoidBounds::~TrapezoidBounds() = default;

Acts::SurfaceBounds::BoundsType Acts::TrapezoidBounds::type() const {
Expand All @@ -21,16 +50,18 @@ Acts::SurfaceBounds::BoundsType Acts::TrapezoidBounds::type() const {

bool Acts::TrapezoidBounds::inside(const Acts::Vector2& lposition,
const Acts::BoundaryCheck& bcheck) const {
const double x = lposition[0];
const double y = lposition[1];

const double hlY = get(TrapezoidBounds::eHalfLengthY);
const double hlXnY = get(TrapezoidBounds::eHalfLengthXnegY);
const double hlXpY = get(TrapezoidBounds::eHalfLengthXposY);
const double hlY = get(TrapezoidBounds::eHalfLengthY);
const double rotAngle = get(TrapezoidBounds::eRotationAngle);

const Acts::Vector2 extPosition = Eigen::Rotation2Dd(rotAngle) * lposition;
const double x = extPosition[0];
const double y = extPosition[1];

if (bcheck.type() == BoundaryCheck::Type::eAbsolute) {
double tolX = bcheck.tolerance()[eBoundLoc0];
double tolY = bcheck.tolerance()[eBoundLoc1];
const double tolX = bcheck.tolerance()[eBoundLoc0];
const double tolY = bcheck.tolerance()[eBoundLoc1];

if (std::abs(y) - hlY > tolY) {
// outside y range
Expand All @@ -50,17 +81,24 @@ bool Acts::TrapezoidBounds::inside(const Acts::Vector2& lposition,

// at this stage, the point can only be in the triangles
// run slow-ish polygon check
std::array<Vector2, 4> v{
Vector2{-hlXnY, -hlY}, {hlXnY, -hlY}, {hlXpY, hlY}, {-hlXpY, hlY}};
return bcheck.isInside(lposition, v);
std::vector<Acts::Vector2> vertices = {
{-hlXnY, -hlY}, {hlXnY, -hlY}, {hlXpY, hlY}, {-hlXpY, hlY}};
return bcheck.isInside(extPosition, vertices);
}

std::vector<Acts::Vector2> Acts::TrapezoidBounds::vertices(
unsigned int /*lseg*/) const {
double minhx = get(TrapezoidBounds::eHalfLengthXnegY);
double maxhx = get(TrapezoidBounds::eHalfLengthXposY);
double hy = get(TrapezoidBounds::eHalfLengthY);
return {{-minhx, -hy}, {minhx, -hy}, {maxhx, hy}, {-maxhx, hy}};
const double hlXnY = get(TrapezoidBounds::eHalfLengthXnegY);
const double hlXpY = get(TrapezoidBounds::eHalfLengthXposY);
const double hlY = get(TrapezoidBounds::eHalfLengthY);
const double rotAngle = get(TrapezoidBounds::eRotationAngle);

std::vector<Acts::Vector2> vertices = {
{-hlXnY, -hlY}, {hlXnY, -hlY}, {hlXpY, hlY}, {-hlXpY, hlY}};
for (auto& v : vertices) {
v = Eigen::Rotation2Dd(-rotAngle) * v;
}
return vertices;
}

const Acts::RectangleBounds& Acts::TrapezoidBounds::boundingBox() const {
Expand All @@ -70,9 +108,32 @@ const Acts::RectangleBounds& Acts::TrapezoidBounds::boundingBox() const {
std::ostream& Acts::TrapezoidBounds::toStream(std::ostream& sl) const {
sl << std::setiosflags(std::ios::fixed);
sl << std::setprecision(7);
sl << "Acts::TrapezoidBounds: (halfXnegY, halfXposY, halfY) = "
sl << "Acts::TrapezoidBounds: (halfXnegY, halfXposY, halfY, rotAngle) = "
<< "(" << get(eHalfLengthXnegY) << ", " << get(eHalfLengthXposY) << ", "
<< get(eHalfLengthY) << ")";
<< get(eHalfLengthY) << ", " << get(eRotationAngle) << ")";
sl << std::setprecision(-1);
return sl;
}

std::vector<double> Acts::TrapezoidBounds::values() const {
std::vector<double> valvector;
valvector.insert(valvector.begin(), m_values.begin(), m_values.end());
return valvector;
}

void Acts::TrapezoidBounds::rotateBoundingBox() noexcept(false) {
const double rotAngle = get(eRotationAngle);

if (rotAngle != 0.) {
m_boundingBox = ConvexPolygonBounds<4>(vertices()).boundingBox();
}
}

void Acts::TrapezoidBounds::checkConsistency() noexcept(false) {
if (get(eHalfLengthXnegY) <= 0. || get(eHalfLengthXposY) <= 0.) {
throw std::invalid_argument("TrapezoidBounds: invalid local x setup");
}
if (get(eHalfLengthY) <= 0.) {
throw std::invalid_argument("TrapezoidBounds: invalid local y setup");
}
}
27 changes: 27 additions & 0 deletions Tests/UnitTests/Core/Surfaces/PlaneSurfaceTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@
#include "Acts/Definitions/Alignment.hpp"
#include "Acts/Definitions/Tolerance.hpp"
#include "Acts/Definitions/TrackParametrization.hpp"
#include "Acts/Definitions/Units.hpp"
#include "Acts/Geometry/Extent.hpp"
#include "Acts/Geometry/GeometryContext.hpp"
#include "Acts/Geometry/Polyhedron.hpp"
#include "Acts/Surfaces/PlaneSurface.hpp"
#include "Acts/Surfaces/RectangleBounds.hpp"
#include "Acts/Surfaces/Surface.hpp"
#include "Acts/Surfaces/SurfaceBounds.hpp"
#include "Acts/Surfaces/TrapezoidBounds.hpp"
#include "Acts/Tests/CommonHelpers/DetectorElementStub.hpp"
#include "Acts/Tests/CommonHelpers/FloatComparisons.hpp"
#include "Acts/Utilities/BinningType.hpp"
Expand All @@ -33,6 +35,8 @@
#include <string>
#include <utility>

using namespace Acts::UnitLiterals;

namespace Acts {
namespace Test {

Expand Down Expand Up @@ -265,6 +269,29 @@ BOOST_AUTO_TEST_CASE(PlaneSurfaceExtent) {
s_onSurfaceTolerance);
}

BOOST_AUTO_TEST_CASE(RotatedTrapezoid) {
double shortHalfX{100.};
double longHalfX{200.};
double halfY{300.};
double rotAngle{45._degree};

Vector2 edgePoint{longHalfX - 10., halfY};

std::shared_ptr<TrapezoidBounds> bounds =
std::make_shared<TrapezoidBounds>(shortHalfX, longHalfX, halfY);

BOOST_CHECK(bounds->inside(edgePoint, BoundaryCheck(true)));
BOOST_CHECK(!bounds->inside(Eigen::Rotation2D(-rotAngle) * edgePoint,
BoundaryCheck(true)));

std::shared_ptr<TrapezoidBounds> rotatedBounds =
std::make_shared<TrapezoidBounds>(shortHalfX, longHalfX, halfY, rotAngle);

BOOST_CHECK(!rotatedBounds->inside(edgePoint, BoundaryCheck(true)));
BOOST_CHECK(rotatedBounds->inside(Eigen::Rotation2D(-rotAngle) * edgePoint,
BoundaryCheck(true)));
}

/// Unit test for testing PlaneSurface alignment derivatives
BOOST_AUTO_TEST_CASE(PlaneSurfaceAlignment) {
// bounds object, rectangle type
Expand Down
6 changes: 3 additions & 3 deletions Tests/UnitTests/Core/Surfaces/TrapezoidBoundsTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,9 @@ BOOST_AUTO_TEST_CASE(TrapezoidBoundsProperties) {
/// Test dump
boost::test_tools::output_test_stream dumpOuput;
trapezoidBoundsObject.toStream(dumpOuput);
BOOST_CHECK(
dumpOuput.is_equal("Acts::TrapezoidBounds: (halfXnegY, halfXposY, "
"halfY) = (1.0000000, 6.0000000, 2.0000000)"));
BOOST_CHECK(dumpOuput.is_equal(
"Acts::TrapezoidBounds: (halfXnegY, halfXposY, halfY, rotAngle) = "
"(1.0000000, 6.0000000, 2.0000000, 0.0000000)"));
//
/// Test inside
BOOST_CHECK(trapezoidBoundsObject.inside(inRectangle, BoundaryCheck(true)));
Expand Down
Loading