File indexing completed on 2025-09-18 08:12:24
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/Surfaces/CylinderBounds.hpp"
0010
0011 #include "Acts/Surfaces/detail/VerticesHelper.hpp"
0012 #include "Acts/Utilities/VectorHelpers.hpp"
0013 #include "Acts/Utilities/detail/periodic.hpp"
0014
0015 #include <algorithm>
0016 #include <cmath>
0017 #include <iomanip>
0018 #include <iostream>
0019 #include <numbers>
0020 #include <utility>
0021
0022 namespace Acts {
0023
0024 using VectorHelpers::perp;
0025 using VectorHelpers::phi;
0026
0027 std::vector<double> CylinderBounds::values() const {
0028 return {m_values.begin(), m_values.end()};
0029 }
0030
0031 Vector2 CylinderBounds::shifted(const Vector2& lposition) const {
0032 return {detail::radian_sym((lposition[0] / get(eR)) - get(eAveragePhi)),
0033 lposition[1]};
0034 }
0035
0036 bool CylinderBounds::inside(const Vector2& lposition) const {
0037 double bevelMinZ = get(eBevelMinZ);
0038 double bevelMaxZ = get(eBevelMaxZ);
0039
0040 double halfLengthZ = get(eHalfLengthZ);
0041 double halfPhi = get(eHalfPhiSector);
0042
0043 if (bevelMinZ == 0. || bevelMaxZ == 0.) {
0044 return detail::VerticesHelper::isInsideRectangle(
0045 shifted(lposition), Vector2(-halfPhi, -halfLengthZ),
0046 Vector2(halfPhi, halfLengthZ));
0047 }
0048
0049 double radius = get(eR);
0050
0051
0052
0053
0054
0055
0056
0057 double localx =
0058 lposition[0] > radius ? 2 * radius - lposition[0] : lposition[0];
0059 Vector2 shiftedlposition = shifted(lposition);
0060 if ((std::abs(shiftedlposition[0]) <= halfPhi &&
0061 std::abs(shiftedlposition[1]) <= halfLengthZ)) {
0062 return true;
0063 }
0064
0065 if ((lposition[1] >= -(localx * std::tan(bevelMinZ) + halfLengthZ)) &&
0066 (lposition[1] <= (localx * std::tan(bevelMaxZ) + halfLengthZ))) {
0067 return true;
0068 }
0069
0070 Vector2 lowerLeft = {-radius, -halfLengthZ};
0071 Vector2 middleLeft = {0., -(halfLengthZ + radius * std::tan(bevelMinZ))};
0072 Vector2 upperLeft = {radius, -halfLengthZ};
0073 Vector2 upperRight = {radius, halfLengthZ};
0074 Vector2 middleRight = {0., (halfLengthZ + radius * std::tan(bevelMaxZ))};
0075 Vector2 lowerRight = {-radius, halfLengthZ};
0076 std::array<Vector2, 6> vertices{lowerLeft, middleLeft, upperLeft,
0077 upperRight, middleRight, lowerRight};
0078
0079 return detail::VerticesHelper::isInsidePolygon(lposition, vertices);
0080 }
0081
0082 Vector2 CylinderBounds::closestPoint(const Vector2& lposition,
0083 const SquareMatrix2& metric) const {
0084 double bevelMinZ = get(eBevelMinZ);
0085 double bevelMaxZ = get(eBevelMaxZ);
0086 double halfLengthZ = get(eHalfLengthZ);
0087 double radius = get(eR);
0088
0089 Vector2 lowerLeft = {-radius, -halfLengthZ};
0090 Vector2 middleLeft = {0., -(halfLengthZ + radius * std::tan(bevelMinZ))};
0091 Vector2 upperLeft = {radius, -halfLengthZ};
0092 Vector2 upperRight = {radius, halfLengthZ};
0093 Vector2 middleRight = {0., (halfLengthZ + radius * std::tan(bevelMaxZ))};
0094 Vector2 lowerRight = {-radius, halfLengthZ};
0095 Vector2 vertices[] = {lowerLeft, middleLeft, upperLeft,
0096 upperRight, middleRight, lowerRight};
0097
0098 return detail::VerticesHelper::computeClosestPointOnPolygon(lposition,
0099 vertices, metric);
0100 }
0101
0102 Vector2 CylinderBounds::center() const {
0103
0104
0105 return Vector2(get(eAveragePhi), 0.0);
0106 }
0107
0108 std::ostream& CylinderBounds::toStream(std::ostream& sl) const {
0109 sl << std::setiosflags(std::ios::fixed);
0110 sl << std::setprecision(7);
0111 sl << "Acts::CylinderBounds: (radius, halfLengthZ, halfPhiSector, "
0112 "averagePhi, bevelMinZ, bevelMaxZ) = ";
0113 sl << "(" << get(eR) << ", " << get(eHalfLengthZ) << ", ";
0114 sl << get(eHalfPhiSector) << ", " << get(eAveragePhi) << ", ";
0115 sl << get(eBevelMinZ) << ", " << get(eBevelMaxZ) << ")";
0116 sl << std::setprecision(-1);
0117 return sl;
0118 }
0119
0120 std::vector<Vector3> CylinderBounds::circleVertices(
0121 const Transform3 transform, unsigned int quarterSegments) const {
0122 std::vector<Vector3> vertices;
0123
0124 double avgPhi = get(eAveragePhi);
0125 double halfPhi = get(eHalfPhiSector);
0126
0127 std::vector<double> phiRef = {};
0128 if (bool fullCylinder = coversFullAzimuth(); fullCylinder) {
0129 phiRef = {avgPhi};
0130 }
0131
0132
0133 std::vector<int> sides = {-1, 1};
0134 for (auto& side : sides) {
0135
0136 auto svertices = detail::VerticesHelper::segmentVertices(
0137 {get(eR), get(eR)}, avgPhi - halfPhi, avgPhi + halfPhi, phiRef,
0138 quarterSegments, Vector3(0., 0., side * get(eHalfLengthZ)), transform);
0139 vertices.insert(vertices.end(), svertices.begin(), svertices.end());
0140 }
0141
0142 double bevelMinZ = get(eBevelMinZ);
0143 double bevelMaxZ = get(eBevelMaxZ);
0144
0145
0146 if ((bevelMinZ != 0. || bevelMaxZ != 0.) && vertices.size() % 2 == 0) {
0147 auto halfWay = vertices.end() - vertices.size() / 2;
0148 double mult{1};
0149 auto invTransform = transform.inverse();
0150 auto func = [&mult, &transform, &invTransform](Vector3& v) {
0151 v = invTransform * v;
0152 v(2) += v(1) * mult;
0153 v = transform * v;
0154 };
0155 if (bevelMinZ != 0.) {
0156 mult = std::tan(-bevelMinZ);
0157 std::for_each(vertices.begin(), halfWay, func);
0158 }
0159 if (bevelMaxZ != 0.) {
0160 mult = std::tan(bevelMaxZ);
0161 std::for_each(halfWay, vertices.end(), func);
0162 }
0163 }
0164 return vertices;
0165 }
0166
0167 void CylinderBounds::checkConsistency() noexcept(false) {
0168 if (get(eR) <= 0.) {
0169 throw std::invalid_argument(
0170 "CylinderBounds: invalid radial setup: radius is negative");
0171 }
0172 if (get(eHalfLengthZ) <= 0.) {
0173 throw std::invalid_argument(
0174 "CylinderBounds: invalid length setup: half length is negative");
0175 }
0176 if (get(eHalfPhiSector) <= 0. || get(eHalfPhiSector) > std::numbers::pi) {
0177 throw std::invalid_argument("CylinderBounds: invalid phi sector setup.");
0178 }
0179 if (get(eAveragePhi) != detail::radian_sym(get(eAveragePhi)) &&
0180 std::abs(std::abs(get(eAveragePhi)) - std::numbers::pi) > s_epsilon) {
0181 throw std::invalid_argument("CylinderBounds: invalid phi positioning.");
0182 }
0183 if (get(eBevelMinZ) != detail::radian_sym(get(eBevelMinZ))) {
0184 throw std::invalid_argument("CylinderBounds: invalid bevel at min Z.");
0185 }
0186 if (get(eBevelMaxZ) != detail::radian_sym(get(eBevelMaxZ))) {
0187 throw std::invalid_argument("CylinderBounds: invalid bevel at max Z.");
0188 }
0189 }
0190
0191 }