File indexing completed on 2025-08-05 08:09:22
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010 #include "Acts/Definitions/Algebra.hpp"
0011 #include "Acts/Definitions/TrackParametrization.hpp"
0012 #include "Acts/Surfaces/detail/VerticesHelper.hpp"
0013
0014 #include <cfloat>
0015 #include <cmath>
0016 #include <iterator>
0017 #include <vector>
0018
0019 namespace Acts {
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036 class BoundaryCheck {
0037 public:
0038
0039 explicit BoundaryCheck(bool check);
0040
0041
0042
0043
0044
0045
0046
0047 BoundaryCheck(bool checkLocal0, bool checkLocal1, double tolerance0 = 0,
0048 double tolerance1 = 0);
0049
0050
0051
0052
0053
0054 BoundaryCheck(const SquareMatrix2& localCovariance, double sigmaMax = 1);
0055
0056 bool isEnabled() const { return m_type != Type::eNone; }
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068 template <typename Vector2Container>
0069 bool isInside(const Vector2& point, const Vector2Container& vertices) const;
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079 bool isInside(const Vector2& point, const Vector2& lowerLeft,
0080 const Vector2& upperRight) const;
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093 template <typename Vector2Container>
0094 double distance(const Vector2& point, const Vector2Container& vertices) const;
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105 double distance(const Vector2& point, const Vector2& lowerLeft,
0106 const Vector2& upperRight) const;
0107
0108 enum class Type {
0109 eNone,
0110 eAbsolute,
0111 eChi2
0112 };
0113
0114
0115 Type type() const;
0116
0117
0118 const Vector2& tolerance() const;
0119
0120
0121 SquareMatrix2 covariance() const;
0122
0123 private:
0124
0125
0126
0127
0128 BoundaryCheck transformed(const ActsMatrix<2, 2>& jacobian) const;
0129
0130
0131 bool isTolerated(const Vector2& delta) const;
0132
0133
0134 double squaredNorm(const Vector2& x) const;
0135
0136
0137 template <typename Vector2Container>
0138 Vector2 computeClosestPointOnPolygon(const Vector2& point,
0139 const Vector2Container& vertices) const;
0140
0141
0142 Vector2 computeEuclideanClosestPointOnRectangle(
0143 const Vector2& point, const Vector2& lowerLeft,
0144 const Vector2& upperRight) const;
0145
0146
0147 SquareMatrix2 m_weight;
0148
0149
0150 Vector2 m_tolerance;
0151 Type m_type;
0152
0153
0154 friend class CylinderBounds;
0155 friend class RectangleBounds;
0156
0157 friend class CylinderBounds;
0158 friend class DiscTrapezoidBounds;
0159
0160 friend class EllipseBounds;
0161 };
0162
0163 }
0164
0165 inline Acts::BoundaryCheck::Type Acts::BoundaryCheck::type() const {
0166 return m_type;
0167 }
0168
0169 inline const Acts::Vector2& Acts::BoundaryCheck::tolerance() const {
0170 return m_tolerance;
0171 }
0172
0173 inline Acts::SquareMatrix2 Acts::BoundaryCheck::covariance() const {
0174 return m_weight.inverse();
0175 }
0176
0177 inline Acts::BoundaryCheck::BoundaryCheck(bool check)
0178 : m_weight(SquareMatrix2::Identity()),
0179 m_tolerance(0, 0),
0180 m_type(check ? Type::eAbsolute : Type::eNone) {}
0181
0182 inline Acts::BoundaryCheck::BoundaryCheck(bool checkLocal0, bool checkLocal1,
0183 double tolerance0, double tolerance1)
0184 : m_weight(SquareMatrix2::Identity()),
0185 m_tolerance(checkLocal0 ? tolerance0 : DBL_MAX,
0186 checkLocal1 ? tolerance1 : DBL_MAX),
0187 m_type(Type::eAbsolute) {}
0188
0189 inline Acts::BoundaryCheck::BoundaryCheck(const SquareMatrix2& localCovariance,
0190 double sigmaMax)
0191 : m_weight(localCovariance.inverse()),
0192 m_tolerance(sigmaMax, 0),
0193 m_type(Type::eChi2) {}
0194
0195 inline Acts::BoundaryCheck Acts::BoundaryCheck::transformed(
0196 const ActsMatrix<2, 2>& jacobian) const {
0197 BoundaryCheck bc = *this;
0198 if (m_type == Type::eAbsolute) {
0199
0200
0201 bc.m_tolerance = (jacobian * m_tolerance).cwiseAbs();
0202 } else {
0203 bc.m_weight =
0204 (jacobian * m_weight.inverse() * jacobian.transpose()).inverse();
0205 }
0206 return bc;
0207 }
0208
0209 template <typename Vector2Container>
0210 inline bool Acts::BoundaryCheck::isInside(
0211 const Vector2& point, const Vector2Container& vertices) const {
0212 if (m_type == Type::eNone) {
0213
0214 return true;
0215 } else if (detail::VerticesHelper::isInsidePolygon(point, vertices)) {
0216
0217 return true;
0218 } else if (m_tolerance == Vector2(0., 0.)) {
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229 return false;
0230 } else {
0231
0232
0233 auto closestPoint = computeClosestPointOnPolygon(point, vertices);
0234 return isTolerated(closestPoint - point);
0235 }
0236 }
0237
0238 inline bool Acts::BoundaryCheck::isInside(const Vector2& point,
0239 const Vector2& lowerLeft,
0240 const Vector2& upperRight) const {
0241 if (detail::VerticesHelper::isInsideRectangle(point, lowerLeft, upperRight)) {
0242 return true;
0243 } else {
0244 Vector2 closestPoint;
0245
0246 if (m_type == Type::eNone || m_type == Type::eAbsolute) {
0247
0248 closestPoint =
0249 computeEuclideanClosestPointOnRectangle(point, lowerLeft, upperRight);
0250
0251 } else {
0252
0253 Vector2 vertices[] = {{lowerLeft[0], lowerLeft[1]},
0254 {upperRight[0], lowerLeft[1]},
0255 {upperRight[0], upperRight[1]},
0256 {lowerLeft[0], upperRight[1]}};
0257 closestPoint = computeClosestPointOnPolygon(point, vertices);
0258 }
0259
0260 return isTolerated(closestPoint - point);
0261 }
0262 }
0263
0264 template <typename Vector2Container>
0265 inline double Acts::BoundaryCheck::distance(
0266 const Acts::Vector2& point, const Vector2Container& vertices) const {
0267
0268 double d = squaredNorm(point - computeClosestPointOnPolygon(point, vertices));
0269 d = std::sqrt(d);
0270 return detail::VerticesHelper::isInsidePolygon(point, vertices) ? -d : d;
0271 }
0272
0273 inline double Acts::BoundaryCheck::distance(const Acts::Vector2& point,
0274 const Vector2& lowerLeft,
0275 const Vector2& upperRight) const {
0276 if (m_type == Type::eNone || m_type == Type::eAbsolute) {
0277
0278 double d = (point - computeEuclideanClosestPointOnRectangle(
0279 point, lowerLeft, upperRight))
0280 .norm();
0281 return detail::VerticesHelper::isInsideRectangle(point, lowerLeft,
0282 upperRight)
0283 ? -d
0284 : d;
0285
0286 } else {
0287 Vector2 vertices[] = {{lowerLeft[0], lowerLeft[1]},
0288 {upperRight[0], lowerLeft[1]},
0289 {upperRight[0], upperRight[1]},
0290 {lowerLeft[0], upperRight[1]}};
0291 return distance(point, vertices);
0292 }
0293 }
0294
0295 inline bool Acts::BoundaryCheck::isTolerated(const Vector2& delta) const {
0296 if (m_type == Type::eNone) {
0297 return true;
0298 } else if (m_type == Type::eAbsolute) {
0299 return (std::abs(delta[0]) <= m_tolerance[0]) &&
0300 (std::abs(delta[1]) <= m_tolerance[1]);
0301 } else {
0302
0303 return (squaredNorm(delta) < (2 * m_tolerance[0]));
0304 }
0305 }
0306
0307 inline double Acts::BoundaryCheck::squaredNorm(const Vector2& x) const {
0308 return (x.transpose() * m_weight * x).value();
0309 }
0310
0311 template <typename Vector2Container>
0312 inline Acts::Vector2 Acts::BoundaryCheck::computeClosestPointOnPolygon(
0313 const Acts::Vector2& point, const Vector2Container& vertices) const {
0314
0315
0316 auto closestOnSegment = [&](auto&& ll0, auto&& ll1) {
0317
0318 auto n = ll1 - ll0;
0319 auto weighted_n = m_weight * n;
0320 auto f = n.dot(weighted_n);
0321 auto u = std::isnormal(f)
0322 ? (point - ll0).dot(weighted_n) / f
0323 : 0.5;
0324
0325 return ll0 + std::clamp(u, 0.0, 1.0) * n;
0326 };
0327
0328 auto iv = std::begin(vertices);
0329 Vector2 l0 = *iv;
0330 Vector2 l1 = *(++iv);
0331 Vector2 closest = closestOnSegment(l0, l1);
0332 auto closestDist = squaredNorm(closest - point);
0333
0334 for (++iv; iv != std::end(vertices); ++iv) {
0335 l0 = l1;
0336 l1 = *iv;
0337 Vector2 current = closestOnSegment(l0, l1);
0338 auto currentDist = squaredNorm(current - point);
0339 if (currentDist < closestDist) {
0340 closest = current;
0341 closestDist = currentDist;
0342 }
0343 }
0344
0345 Vector2 last = closestOnSegment(l1, *std::begin(vertices));
0346 if (squaredNorm(last - point) < closestDist) {
0347 closest = last;
0348 }
0349 return closest;
0350 }
0351
0352 inline Acts::Vector2
0353 Acts::BoundaryCheck::computeEuclideanClosestPointOnRectangle(
0354 const Vector2& point, const Vector2& lowerLeft,
0355 const Vector2& upperRight) const {
0356
0357
0358
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368
0369
0370
0371
0372
0373
0374 double l0 = point[0], l1 = point[1];
0375 double loc0Min = lowerLeft[0], loc0Max = upperRight[0];
0376 double loc1Min = lowerLeft[1], loc1Max = upperRight[1];
0377
0378
0379 if (loc0Min <= l0 && l0 < loc0Max && loc1Min <= l1 && l1 < loc1Max) {
0380
0381 double dist = std::abs(loc0Max - l0);
0382 Vector2 cls(loc0Max, l1);
0383
0384 double test = std::abs(loc0Min - l0);
0385 if (test <= dist) {
0386 dist = test;
0387 cls = {loc0Min, l1};
0388 }
0389
0390 test = std::abs(loc1Max - l1);
0391 if (test <= dist) {
0392 dist = test;
0393 cls = {l0, loc1Max};
0394 }
0395
0396 test = std::abs(loc1Min - l1);
0397 if (test <= dist) {
0398 return {l0, loc1Min};
0399 }
0400 return cls;
0401 } else {
0402
0403 if (l0 > loc0Max) {
0404 if (l1 > loc1Max) {
0405 return {loc0Max, loc1Max};
0406 } else if (l1 <= loc1Min) {
0407 return {loc0Max, loc1Min};
0408 } else {
0409 return {loc0Max, l1};
0410 }
0411 } else if (l0 < loc0Min) {
0412 if (l1 > loc1Max) {
0413 return {loc0Min, loc1Max};
0414 } else if (l1 <= loc1Min) {
0415 return {loc0Min, loc1Min};
0416 } else {
0417 return {loc0Min, l1};
0418 }
0419 } else {
0420 if (l1 > loc1Max) {
0421 return {l0, loc1Max};
0422 } else {
0423 return {l0, loc1Min};
0424 }
0425
0426 }
0427 }
0428 }