File indexing completed on 2026-04-17 08:35:35
0001 #ifndef VECGEOM_SURFACE_RINGMASK_H
0002 #define VECGEOM_SURFACE_RINGMASK_H
0003
0004 #include <VecGeom/surfaces/base/CommonTypes.h>
0005
0006 namespace vgbrep {
0007
0008
0009
0010 template <typename Real_t>
0011 struct RingMask {
0012 using value_type = Real_t;
0013 Range<Real_t> rangeR;
0014 bool isFullCirc;
0015 AngleVector<Real_t> vecSPhi;
0016 AngleVector<Real_t> vecEPhi;
0017
0018 RingMask() = default;
0019
0020 template <typename Real_i>
0021 RingMask(Real_i rmin, Real_i rmax, bool isFullCircle, Real_i sphi = Real_i{0}, Real_i ephi = Real_i{0})
0022 : rangeR(static_cast<Real_t>(rmin), static_cast<Real_t>(rmax)), isFullCirc(isFullCircle)
0023 {
0024
0025 if (isFullCirc) return;
0026 vecSPhi.Set(static_cast<Real_t>(vecgeom::Cos(sphi)), static_cast<Real_t>(vecgeom::Sin(sphi)));
0027 vecEPhi.Set(static_cast<Real_t>(vecgeom::Cos(ephi)), static_cast<Real_t>(vecgeom::Sin(ephi)));
0028 }
0029
0030 template <typename Real_i>
0031 RingMask(const RingMask<Real_i> &other)
0032 : rangeR(static_cast<Real_t>(other.rangeR[0]), static_cast<Real_t>(other.rangeR[1])), isFullCirc(other.isFullCirc)
0033 {
0034
0035 if (isFullCirc) return;
0036 vecSPhi.Set(static_cast<Real_t>(other.vecSPhi[0]), static_cast<Real_t>(other.vecSPhi[1]));
0037 vecEPhi.Set(static_cast<Real_t>(other.vecEPhi[0]), static_cast<Real_t>(other.vecEPhi[1]));
0038 }
0039
0040
0041
0042
0043
0044
0045 void GetXYextent(Real_t &xmin, Real_t &xmax, Real_t &ymin, Real_t &ymax) const
0046 {
0047 auto const &rmax = rangeR[1];
0048 xmin = -rmax;
0049 xmax = rmax;
0050 ymin = -rmax;
0051 ymax = rmax;
0052
0053 Vector2D<Real_t> axis{1, 0};
0054 if (!isFullCirc) {
0055
0056 Real_t x1, x2, x3, x4, y1, y2, y3, y4;
0057
0058 auto const &rmin = rangeR[0];
0059
0060 x1 = rmax * axis.Dot(vecSPhi);
0061 x2 = rmax * axis.Dot(vecEPhi);
0062 x3 = rmin * axis.Dot(vecSPhi);
0063 x4 = rmin * axis.Dot(vecEPhi);
0064 axis.Set(0, 1);
0065 y1 = rmax * axis.Dot(vecSPhi);
0066 y2 = rmax * axis.Dot(vecEPhi);
0067 y3 = rmin * axis.Dot(vecSPhi);
0068 y4 = rmin * axis.Dot(vecEPhi);
0069
0070 xmax = vecgeom::Max(vecgeom::Max(x1, x2), vecgeom::Max(x3, x4));
0071 ymax = vecgeom::Max(vecgeom::Max(y1, y2), vecgeom::Max(y3, y4));
0072 xmin = vecgeom::Min(vecgeom::Min(x1, x2), vecgeom::Min(x3, x4));
0073 ymin = vecgeom::Min(vecgeom::Min(y1, y2), vecgeom::Min(y3, y4));
0074
0075 if (InsidePhi(1, 0)) xmax = rmax;
0076 if (InsidePhi(0, 1)) ymax = rmax;
0077 if (InsidePhi(-1, 0)) xmin = -rmax;
0078 if (InsidePhi(0, -1)) ymin = -rmax;
0079 }
0080 }
0081
0082
0083
0084
0085 void Extent3D(Vector3D<Real_t> &aMin, Vector3D<Real_t> &aMax) const
0086 {
0087 Real_t xmin, xmax, ymin, ymax;
0088 GetXYextent(xmin, xmax, ymin, ymax);
0089 aMin.Set(xmin, ymin, Real_t(0));
0090 aMax.Set(xmax, ymax, Real_t(0));
0091 }
0092
0093
0094
0095 void GetExtent(WindowMask<Real_t> &window) const
0096 {
0097 Real_t xmin, xmax, ymin, ymax;
0098 GetXYextent(xmin, xmax, ymin, ymax);
0099 window.rangeU.Set(xmin, xmax);
0100 window.rangeV.Set(ymin, ymax);
0101 }
0102
0103 VECCORE_ATT_HOST_DEVICE
0104 VECGEOM_FORCE_INLINE
0105 bool HasRmin() const { return rangeR[0] > vecgeom::kToleranceDist<Real_t>; }
0106
0107 VECCORE_ATT_HOST_DEVICE
0108 VECGEOM_FORCE_INLINE
0109 bool IsConvex() const { return !HasRmin() && vecSPhi.CrossZ(vecEPhi) > -vecgeom::kToleranceDist<Real_t>; }
0110
0111
0112
0113
0114 VECCORE_ATT_HOST_DEVICE
0115 VECGEOM_FORCE_INLINE
0116 bool InsideR(Vector3D<Real_t> const &local) const
0117 {
0118 Real_t rsq = local[0] * local[0] + local[1] * local[1];
0119
0120 if ((rsq < rangeR[0] * rangeR[0] - 2 * vecgeom::kRelTolerance<Real_t>(rangeR[0])) ||
0121 (rsq > rangeR[1] * rangeR[1] + 2 * vecgeom::kRelTolerance<Real_t>(rangeR[1])))
0122 return false;
0123 return true;
0124 }
0125
0126
0127
0128
0129
0130 VECCORE_ATT_HOST_DEVICE
0131 VECGEOM_FORCE_INLINE
0132 bool InsidePhi(Real_t const &x, Real_t const &y) const
0133 {
0134 if (isFullCirc) return true;
0135 AngleVector<Real_t> localAngle{x, y};
0136 auto convex = vecSPhi.CrossZ(vecEPhi) > Real_t(0);
0137 auto in1 = vecSPhi.CrossZ(localAngle) > -vecgeom::kToleranceStrict<Real_t>;
0138 auto in2 = localAngle.CrossZ(vecEPhi) > -vecgeom::kToleranceStrict<Real_t>;
0139 return convex ? in1 && in2 : in1 || in2;
0140 }
0141
0142
0143
0144
0145
0146
0147
0148 VECCORE_ATT_HOST_DEVICE
0149 VECGEOM_FORCE_INLINE
0150 bool Inside(Vector3D<Real_t> const &local) const { return InsideR(local) && InsidePhi(local[0], local[1]); }
0151
0152
0153
0154
0155
0156
0157 VECCORE_ATT_HOST_DEVICE
0158 Real_t Safety(Vector3D<Real_t> const &local, Real_t safetySurf, bool &valid) const
0159 {
0160 valid = true;
0161 Real_t rho = local.Perp();
0162 Real_t safR = HasRmin() ? vecCore::math::Max(rangeR[0] - rho, rho - rangeR[1]) : rho - rangeR[1];
0163 if (isFullCirc || InsidePhi(local[0], local[1]))
0164 #ifdef SURF_ACCURATE_SAFETY
0165 return vecCore::math::Sqrt(safetySurf * safetySurf + ((safR > 0) ? safR * safR : 0));
0166 #else
0167 return vecCore::math::Max(safetySurf, safR);
0168 #endif
0169 AngleVector<Real_t> localAngle{local[0], local[1]};
0170 auto safphi1 = localAngle.CrossZ(vecSPhi);
0171 auto safphi2 = -localAngle.CrossZ(vecEPhi);
0172 bool largerPi = vecSPhi.CrossZ(vecEPhi) < 0;
0173 auto safPhi = largerPi ? vecCore::math::Min(safphi1, safphi2) : vecCore::math::Max(safphi1, safphi2);
0174 auto safInPlane = vecCore::math::Max(safR, safPhi);
0175 #ifdef SURF_ACCURATE_SAFETY
0176 auto safety = safetySurf * safetySurf + ((safInPlane > 0) ? safInPlane * safInPlane : 0);
0177 return vecCore::math::Sqrt(safety);
0178 #else
0179 return vecCore::math::Max(safetySurf, safInPlane);
0180 #endif
0181 }
0182
0183
0184
0185
0186
0187 Real_t SafetyInside(Vector3D<Real_t> const &local) const
0188 {
0189 Real_t rho = local.Perp();
0190 Real_t safR = HasRmin() ? vecCore::math::Min(rangeR[1] - rho, rho - rangeR[0]) : rangeR[1] - rho;
0191 safR = vecCore::math::Max(safR, Real_t(0));
0192 if (isFullCirc) return safR;
0193 AngleVector<Real_t> localAngle{local[0], local[1]};
0194 auto saf1 = (vecSPhi.Dot(localAngle) > Real_t(0)) ? vecCore::math::Max(vecSPhi.CrossZ(localAngle), Real_t(0))
0195 : vecgeom::InfinityLength<Real_t>();
0196 auto saf2 = (vecEPhi.Dot(localAngle) > Real_t(0)) ? vecCore::math::Max(localAngle.CrossZ(vecEPhi), Real_t(0))
0197 : vecgeom::InfinityLength<Real_t>();
0198 Real_t safPhi = vecCore::math::Min(saf1, saf2);
0199 return vecCore::math::Min(safR, safPhi);
0200 }
0201
0202
0203
0204
0205
0206 Real_t SafetyOutside(Vector3D<Real_t> const &local) const
0207 {
0208 Real_t rho = local.Perp();
0209 Real_t safR = HasRmin() ? vecCore::math::Max(rho - rangeR[1], rangeR[0] - rho) : rho - rangeR[1];
0210 safR = vecCore::math::Max(safR, Real_t(0));
0211 if (isFullCirc) return safR;
0212 AngleVector<Real_t> localAngle{local[0], local[1]};
0213 auto saf1 = (vecSPhi.Dot(localAngle) > Real_t(0)) ? vecCore::math::Max(localAngle.CrossZ(vecSPhi), Real_t(0))
0214 : vecgeom::InfinityLength<Real_t>();
0215 auto saf2 = (vecEPhi.Dot(localAngle) > Real_t(0)) ? vecCore::math::Max(vecEPhi.CrossZ(localAngle), Real_t(0))
0216 : vecgeom::InfinityLength<Real_t>();
0217 Real_t safPhi = vecCore::math::Min(saf1, saf2);
0218 if (safPhi == vecgeom::InfinityLength<Real_t>()) safPhi = Real_t(0);
0219 return vecCore::math::Max(safR, safPhi);
0220 }
0221 };
0222
0223 }
0224
0225 #endif