File indexing completed on 2026-05-09 08:04:00
0001
0002
0003
0004
0005
0006
0007
0008
0009 #include "Acts/Surfaces/detail/VerticesHelper.hpp"
0010
0011 #include <algorithm>
0012 #include <cmath>
0013 #include <cstddef>
0014 #include <numbers>
0015
0016 namespace Acts {
0017
0018 std::vector<double> detail::VerticesHelper::phiSegments(
0019 double phiMin, double phiMax, const std::vector<double>& phiRefs,
0020 unsigned int quarterSegments) {
0021
0022 if (phiMin > phiMax) {
0023 throw std::invalid_argument(
0024 "VerticesHelper::phiSegments ... Minimum phi must be smaller than "
0025 "maximum phi");
0026 }
0027
0028
0029 for (double phiRef : phiRefs) {
0030 if (phiRef < phiMin || phiRef > phiMax) {
0031 throw std::invalid_argument(
0032 "VerticesHelper::phiSegments ... Reference phi is outside the range "
0033 "of the segment");
0034 }
0035 }
0036 if (quarterSegments == 0u) {
0037 throw std::invalid_argument(
0038 "VerticesHelper::phiSegments ... Number of segments must be larger "
0039 "than 0.");
0040 }
0041 std::vector<double> phiSegments = {phiMin, phiMax};
0042
0043
0044 for (unsigned int i = 0; i < 4 * quarterSegments + 1; ++i) {
0045 double phiExt =
0046 -std::numbers::pi + i * 2 * std::numbers::pi / (4 * quarterSegments);
0047 if (phiExt > phiMin && phiExt < phiMax &&
0048 std::ranges::none_of(
0049 phiSegments,
0050 [&phiExt](double phi) {
0051 return std::abs(phi - phiExt) <
0052 std::numeric_limits<double>::epsilon();
0053 })) {
0054 phiSegments.push_back(phiExt);
0055 }
0056 }
0057
0058 for (const auto& phiRef : phiRefs) {
0059 if (phiRef > phiMin && phiRef < phiMax) {
0060 if (std::ranges::none_of(phiSegments, [&phiRef](double phi) {
0061 return std::abs(phi - phiRef) <
0062 std::numeric_limits<double>::epsilon();
0063 })) {
0064 phiSegments.push_back(phiRef);
0065 }
0066 }
0067 }
0068
0069
0070 std::ranges::sort(phiSegments);
0071 return phiSegments;
0072 }
0073
0074 std::vector<Vector2> detail::VerticesHelper::ellipsoidVertices(
0075 double innerRx, double innerRy, double outerRx, double outerRy,
0076 double avgPhi, double halfPhi, unsigned int quarterSegments) {
0077
0078
0079 std::vector<Vector2> rvertices;
0080 std::vector<Vector2> ivertices;
0081 std::vector<Vector2> overtices;
0082
0083 bool innerExists = (innerRx > 0. && innerRy > 0.);
0084 bool closed = std::abs(halfPhi - std::numbers::pi) < s_onSurfaceTolerance;
0085
0086 std::vector<double> refPhi = {};
0087 if (avgPhi != 0.) {
0088 refPhi.push_back(avgPhi);
0089 }
0090
0091
0092 if (innerExists) {
0093 ivertices = segmentVertices<Vector2, Transform2>(
0094 {innerRx, innerRy}, avgPhi - halfPhi, avgPhi + halfPhi, refPhi,
0095 quarterSegments);
0096 }
0097 overtices = segmentVertices<Vector2, Transform2>(
0098 {outerRx, outerRy}, avgPhi - halfPhi, avgPhi + halfPhi, refPhi,
0099 quarterSegments);
0100
0101
0102 if (!innerExists) {
0103 if (!closed) {
0104
0105 rvertices.push_back(Vector2(0., 0.));
0106 }
0107 rvertices.insert(rvertices.end(), overtices.begin(), overtices.end());
0108 } else if (!closed) {
0109 rvertices.insert(rvertices.end(), overtices.begin(), overtices.end());
0110 rvertices.insert(rvertices.end(), ivertices.rbegin(), ivertices.rend());
0111 } else {
0112 rvertices.insert(rvertices.end(), overtices.begin(), overtices.end());
0113 rvertices.insert(rvertices.end(), ivertices.begin(), ivertices.end());
0114 }
0115 return rvertices;
0116 }
0117
0118 std::vector<Vector2> detail::VerticesHelper::circularVertices(
0119 double innerR, double outerR, double avgPhi, double halfPhi,
0120 unsigned int quarterSegments) {
0121 return ellipsoidVertices(innerR, innerR, outerR, outerR, avgPhi, halfPhi,
0122 quarterSegments);
0123 }
0124
0125 bool detail::VerticesHelper::onHyperPlane(const std::vector<Vector3>& vertices,
0126 double tolerance) {
0127
0128 if (vertices.size() < 4) {
0129 return true;
0130 }
0131
0132 auto hyperPlane = Eigen::Hyperplane<double, 3>::Through(
0133 vertices[0], vertices[1], vertices[2]);
0134 for (std::size_t ip = 3; ip < vertices.size(); ++ip) {
0135 if (hyperPlane.absDistance(vertices[ip]) > tolerance) {
0136 return false;
0137 }
0138 }
0139 return true;
0140 }
0141
0142 Vector2 detail::VerticesHelper::computeClosestPointOnPolygon(
0143 const Vector2& point, std::span<const Vector2> vertices,
0144 const SquareMatrix2& metric) {
0145 auto squaredNorm = [&](const Vector2& x) {
0146 return (x.transpose() * metric * x).value();
0147 };
0148
0149
0150
0151 auto closestOnSegment = [&](auto&& ll0, auto&& ll1) {
0152
0153 auto n = ll1 - ll0;
0154 auto n_transformed = metric * n;
0155 auto f = n.dot(n_transformed);
0156 auto u = std::isnormal(f)
0157 ? (point - ll0).dot(n_transformed) / f
0158 : 0.5;
0159
0160 return ll0 + std::clamp(u, 0.0, 1.0) * n;
0161 };
0162
0163 auto iv = std::begin(vertices);
0164 Vector2 l0 = *iv;
0165 Vector2 l1 = *(++iv);
0166 Vector2 closest = closestOnSegment(l0, l1);
0167 auto closestDist = squaredNorm(closest - point);
0168
0169 for (++iv; iv != std::end(vertices); ++iv) {
0170 l0 = l1;
0171 l1 = *iv;
0172 Vector2 current = closestOnSegment(l0, l1);
0173 auto currentDist = squaredNorm(current - point);
0174 if (currentDist < closestDist) {
0175 closest = current;
0176 closestDist = currentDist;
0177 }
0178 }
0179
0180 Vector2 last = closestOnSegment(l1, *std::begin(vertices));
0181 if (squaredNorm(last - point) < closestDist) {
0182 closest = last;
0183 }
0184 return closest;
0185 }
0186
0187 Vector2 detail::VerticesHelper::computeEuclideanClosestPointOnRectangle(
0188 const Vector2& point, const Vector2& lowerLeft, const Vector2& upperRight) {
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207 double l0 = point[0];
0208 double l1 = point[1];
0209 double loc0Min = lowerLeft[0];
0210 double loc0Max = upperRight[0];
0211 double loc1Min = lowerLeft[1];
0212 double loc1Max = upperRight[1];
0213
0214
0215 if (loc0Min <= l0 && l0 < loc0Max && loc1Min <= l1 && l1 < loc1Max) {
0216
0217 double dist = std::abs(loc0Max - l0);
0218 Vector2 cls(loc0Max, l1);
0219
0220 double test = std::abs(loc0Min - l0);
0221 if (test <= dist) {
0222 dist = test;
0223 cls = {loc0Min, l1};
0224 }
0225
0226 test = std::abs(loc1Max - l1);
0227 if (test <= dist) {
0228 dist = test;
0229 cls = {l0, loc1Max};
0230 }
0231
0232 test = std::abs(loc1Min - l1);
0233 if (test <= dist) {
0234 return {l0, loc1Min};
0235 }
0236 return cls;
0237 } else {
0238
0239 if (l0 > loc0Max) {
0240 if (l1 > loc1Max) {
0241 return {loc0Max, loc1Max};
0242 } else if (l1 <= loc1Min) {
0243 return {loc0Max, loc1Min};
0244 } else {
0245 return {loc0Max, l1};
0246 }
0247 } else if (l0 < loc0Min) {
0248 if (l1 > loc1Max) {
0249 return {loc0Min, loc1Max};
0250 } else if (l1 <= loc1Min) {
0251 return {loc0Min, loc1Min};
0252 } else {
0253 return {loc0Min, l1};
0254 }
0255 } else {
0256 if (l1 > loc1Max) {
0257 return {l0, loc1Max};
0258 } else {
0259 return {l0, loc1Min};
0260 }
0261
0262 }
0263 }
0264 }
0265
0266 Vector2 detail::VerticesHelper::computeClosestPointOnAlignedBox(
0267 const Vector2& lowerLeft, const Vector2& upperRight, const Vector2& point,
0268 const SquareMatrix2& metric) {
0269 Vector2 closestPoint;
0270
0271 if (metric.isIdentity()) {
0272 closestPoint =
0273 detail::VerticesHelper::computeEuclideanClosestPointOnRectangle(
0274 point, lowerLeft, upperRight);
0275 } else {
0276
0277
0278
0279 std::array<Vector2, 4> vertices = {{lowerLeft,
0280 {upperRight[0], lowerLeft[1]},
0281 upperRight,
0282 {lowerLeft[0], upperRight[1]}}};
0283
0284 closestPoint = detail::VerticesHelper::computeClosestPointOnPolygon(
0285 point, vertices, metric);
0286 }
0287
0288 return closestPoint;
0289 }
0290
0291 }