File indexing completed on 2025-01-18 10:14:10
0001 #ifndef VECGEOM_POLYGONAL_SHELL_H
0002 #define VECGEOM_POLYGONAL_SHELL_H
0003
0004 #include "VecGeom/base/Global.h"
0005 #include "VecGeom/volumes/PlanarPolygon.h"
0006
0007 namespace vecgeom {
0008
0009 VECGEOM_DEVICE_FORWARD_DECLARE(class PolygonalShell;);
0010 VECGEOM_DEVICE_DECLARE_CONV(class, PolygonalShell);
0011
0012 inline namespace VECGEOM_IMPL_NAMESPACE {
0013
0014
0015
0016 class PolygonalShell : AlignedBase {
0017
0018 private:
0019
0020 PlanarPolygon fPolygon;
0021 Precision fLowerZ;
0022 Precision fUpperZ;
0023
0024 friend class SimpleExtruPolygon;
0025 friend struct SExtruImplementation;
0026 friend class UnplacedSExtruVolume;
0027
0028 public:
0029 VECCORE_ATT_HOST_DEVICE
0030 PolygonalShell() : fPolygon() {}
0031
0032 VECCORE_ATT_HOST_DEVICE
0033 PolygonalShell(int nvertices, Precision *x, Precision *y, Precision lowerz, Precision upperz)
0034 : fPolygon(nvertices, x, y), fLowerZ(lowerz), fUpperZ(upperz)
0035 {
0036 }
0037
0038 VECCORE_ATT_HOST_DEVICE
0039 void Init(int nvertices, Precision *x, Precision *y, Precision lowerz, Precision upperz)
0040 {
0041 fPolygon.Init(nvertices, x, y);
0042 fLowerZ = lowerz;
0043 fUpperZ = upperz;
0044 }
0045
0046
0047 VECCORE_ATT_HOST_DEVICE
0048 Precision SurfaceArea() const
0049 {
0050 const auto kS = fPolygon.fVertices.size();
0051 Precision area(0.);
0052 for (size_t i = 0; i < kS; ++i) {
0053
0054 area += fPolygon.fLengthSqr[i];
0055 }
0056 return std::sqrt(area) * (fUpperZ - fLowerZ);
0057 }
0058
0059 VECCORE_ATT_HOST_DEVICE
0060 PlanarPolygon const &GetPolygon() const { return fPolygon; }
0061
0062 VECCORE_ATT_HOST_DEVICE
0063 Precision GetLowerZ() const { return fLowerZ; }
0064
0065 VECCORE_ATT_HOST_DEVICE
0066 Precision GetUpperZ() const { return fUpperZ; }
0067
0068 template <typename Real_v>
0069 VECCORE_ATT_HOST_DEVICE void Extent(Vector3D<Real_v> &aMin, Vector3D<Real_v> &aMax) const
0070 {
0071 aMin[0] = Real_v(fPolygon.GetMinX());
0072 aMin[1] = Real_v(fPolygon.GetMinY());
0073 aMin[2] = Real_v(fLowerZ);
0074
0075 aMax[0] = Real_v(fPolygon.GetMaxX());
0076 aMax[1] = Real_v(fPolygon.GetMaxY());
0077 aMax[2] = Real_v(fUpperZ);
0078 }
0079
0080 template <typename Real_v>
0081 VECCORE_ATT_HOST_DEVICE Real_v DistanceToIn(Vector3D<Real_v> const &point, Vector3D<Real_v> const &dir) const
0082 {
0083 return fPolygon.IsConvex() ? DistanceToInConvex(point, dir) : DistanceToInConcave(point, dir);
0084 }
0085
0086 template <typename Real_v>
0087 VECCORE_ATT_HOST_DEVICE Real_v DistanceToInConvex(Vector3D<Real_v> const &point, Vector3D<Real_v> const &dir) const
0088 {
0089 using Bool_v = vecCore::Mask_v<Real_v>;
0090 Bool_v done(false);
0091 Real_v result(kInfLength);
0092 const auto S = fPolygon.fVertices.size();
0093
0094 for (size_t i = 0; i < S; ++i) {
0095
0096
0097 const Real_v proj = fPolygon.fA[i] * dir.x() + fPolygon.fB[i] * dir.y();
0098 const Bool_v sidecorrect = proj >= -kTolerance;
0099 if (vecCore::MaskEmpty(sidecorrect)) {
0100 continue;
0101 }
0102
0103
0104 const Real_v pdist = fPolygon.fA[i] * point.x() + fPolygon.fB[i] * point.y() + fPolygon.fD[i];
0105
0106 const Bool_v moving_away = pdist > kTolerance;
0107 if (vecCore::MaskFull(moving_away)) {
0108 continue;
0109 }
0110
0111 const Real_v dist = -pdist / NonZero(proj);
0112
0113
0114 const Real_v zInters(point.z() + dist * dir.z());
0115 const Bool_v zRangeOk = (zInters <= fUpperZ) && (zInters >= fLowerZ);
0116 if (!vecCore::MaskEmpty(zRangeOk)) {
0117
0118 const Real_v xInters(point.x() + dist * dir.x());
0119 const Real_v yInters(point.y() + dist * dir.y());
0120
0121
0122 const Bool_v intersects = fPolygon.OnSegment<Real_v, Precision, Bool_v>(i, xInters, yInters);
0123
0124 vecCore::MaskedAssign(result, !done && intersects, dist);
0125 done |= intersects;
0126 }
0127 if (vecCore::MaskFull(done)) {
0128 return result;
0129 }
0130 }
0131 return result;
0132 }
0133
0134 template <typename Real_v>
0135 VECCORE_ATT_HOST_DEVICE Real_v DistanceToInConcave(Vector3D<Real_v> const &point, Vector3D<Real_v> const &dir) const
0136 {
0137 using Bool_v = vecCore::Mask_v<Real_v>;
0138 Real_v result(kInfLength);
0139 const auto S = fPolygon.fVertices.size();
0140
0141 for (size_t i = 0; i < S; ++i) {
0142
0143
0144 const Real_v proj = fPolygon.fA[i] * dir.x() + fPolygon.fB[i] * dir.y();
0145 const Bool_v sidecorrect = proj >= -kTolerance;
0146 if (vecCore::MaskEmpty(sidecorrect)) {
0147 continue;
0148 }
0149
0150
0151 const Real_v pdist = fPolygon.fA[i] * point.x() + fPolygon.fB[i] * point.y() + fPolygon.fD[i];
0152
0153 const Bool_v moving_away = pdist > kTolerance;
0154 if (vecCore::MaskFull(moving_away)) {
0155 continue;
0156 }
0157
0158 const Real_v dist = -pdist / NonZero(proj);
0159
0160
0161 const Real_v zInters(point.z() + dist * dir.z());
0162 const Bool_v zRangeOk = (zInters <= fUpperZ) && (zInters >= fLowerZ);
0163 if (!vecCore::MaskEmpty(zRangeOk)) {
0164
0165 const Real_v xInters(point.x() + dist * dir.x());
0166 const Real_v yInters(point.y() + dist * dir.y());
0167
0168
0169 const Bool_v intersects = fPolygon.OnSegment<Real_v, Precision, Bool_v>(i, xInters, yInters);
0170
0171 vecCore__MaskedAssignFunc(result, intersects, Min(dist, result));
0172 }
0173
0174
0175
0176 }
0177 return result;
0178 }
0179
0180
0181
0182 template <typename Real_v>
0183 VECCORE_ATT_HOST_DEVICE Real_v DistanceToOut(Vector3D<Real_v> const &point, Vector3D<Real_v> const &dir) const
0184 {
0185 return fPolygon.IsConvex() ? DistanceToOutConvex(point, dir) : DistanceToOutConcave(point, dir);
0186 }
0187
0188
0189
0190
0191 template <typename Real_v>
0192 VECCORE_ATT_HOST_DEVICE Real_v DistanceToOutConvex(Vector3D<Real_v> const &point, Vector3D<Real_v> const &dir) const
0193 {
0194 using Bool_v = vecCore::Mask_v<Real_v>;
0195 Bool_v done(false);
0196 Real_v result(kInfLength);
0197 const auto S = fPolygon.fVertices.size();
0198
0199 for (size_t i = 0; i < S; ++i) {
0200
0201
0202 const Real_v proj = fPolygon.fA[i] * dir.x() + fPolygon.fB[i] * dir.y();
0203 const Bool_v sidecorrect = proj <= kTolerance;
0204 if (vecCore::MaskEmpty(sidecorrect)) {
0205 continue;
0206 }
0207
0208
0209 const Real_v pdist = fPolygon.fA[i] * point.x() + fPolygon.fB[i] * point.y() + fPolygon.fD[i];
0210
0211 const Bool_v moving_away = pdist < -kTolerance;
0212 if (vecCore::MaskFull(moving_away)) {
0213 continue;
0214 }
0215
0216 const Real_v dist = -pdist / NonZero(proj);
0217
0218
0219 const Real_v zInters(point.z() + dist * dir.z());
0220 const Bool_v zRangeOk = (zInters <= fUpperZ) && (zInters >= fLowerZ) && sidecorrect && !moving_away;
0221 if (!vecCore::MaskEmpty(zRangeOk)) {
0222
0223 const Real_v xInters(point.x() + dist * dir.x());
0224 const Real_v yInters(point.y() + dist * dir.y());
0225
0226
0227 const Bool_v intersects = fPolygon.OnSegment<Real_v, Precision, Bool_v>(i, xInters, yInters) && zRangeOk &&
0228 (dist >= -Real_v(kTolerance));
0229
0230 vecCore::MaskedAssign(result, !done && intersects, dist);
0231 done |= intersects;
0232 }
0233 if (vecCore::MaskFull(done)) {
0234 return result;
0235 }
0236 }
0237 return result;
0238 }
0239
0240
0241
0242 template <typename Real_v>
0243 VECCORE_ATT_HOST_DEVICE Real_v DistanceToOutConcave(Vector3D<Real_v> const &point, Vector3D<Real_v> const &dir) const
0244 {
0245 using Bool_v = vecCore::Mask_v<Real_v>;
0246 Real_v result(kInfLength);
0247 const auto S = fPolygon.fVertices.size();
0248
0249 for (size_t i = 0; i < S; ++i) {
0250
0251
0252 const Real_v proj = fPolygon.fA[i] * dir.x() + fPolygon.fB[i] * dir.y();
0253 const Bool_v sidecorrect = proj <= kTolerance;
0254 if (vecCore::MaskEmpty(sidecorrect)) {
0255 continue;
0256 }
0257
0258
0259 const Real_v pdist = fPolygon.fA[i] * point.x() + fPolygon.fB[i] * point.y() + fPolygon.fD[i];
0260
0261 const Bool_v moving_away = pdist < -kTolerance;
0262 if (vecCore::MaskFull(moving_away)) {
0263 continue;
0264 }
0265
0266 const Real_v dist = -pdist / NonZero(proj);
0267
0268
0269 const Real_v zInters(point.z() + dist * dir.z());
0270 const Bool_v zRangeOk = (zInters <= fUpperZ) && (zInters >= fLowerZ) && sidecorrect && !moving_away;
0271 if (!vecCore::MaskEmpty(zRangeOk)) {
0272
0273 const Real_v xInters(point.x() + dist * dir.x());
0274 const Real_v yInters(point.y() + dist * dir.y());
0275
0276
0277 const Bool_v intersects = fPolygon.OnSegment<Real_v, Precision, Bool_v>(i, xInters, yInters) && zRangeOk &&
0278 (dist >= -Real_v(kTolerance));
0279
0280 vecCore__MaskedAssignFunc(result, intersects, Min(dist, result));
0281
0282 }
0283
0284
0285
0286 }
0287 return result;
0288 }
0289
0290 };
0291
0292 #define SPECIALIZATION
0293 #ifdef SPECIALIZATION
0294
0295 template <>
0296 VECCORE_ATT_HOST_DEVICE inline Precision PolygonalShell::DistanceToOutConvex(Vector3D<Precision> const &point,
0297 Vector3D<Precision> const &dir) const
0298 {
0299 Precision dz = 0.5 * (fUpperZ - fLowerZ);
0300 Precision pz = point.z() - 0.5 * (fLowerZ + fUpperZ);
0301 const Precision safz = vecCore::math::Abs(pz) - dz;
0302 if (safz > kTolerance) return -kTolerance;
0303
0304 Precision vz = dir.z();
0305 Precision tmax = (vecCore::math::CopySign(dz, vz) - pz) / NonZero(vz);
0306 const auto S = fPolygon.fVertices.size();
0307 for (size_t i = 0; i < S; ++i) {
0308
0309 const Precision proj = -(fPolygon.fA[i] * dir.x() + fPolygon.fB[i] * dir.y());
0310
0311 const Precision pdist = -(fPolygon.fA[i] * point.x() + fPolygon.fB[i] * point.y() + fPolygon.fD[i]);
0312 if (pdist > kTolerance) return -kTolerance;
0313 if (proj > 0) {
0314 const Precision dist = -pdist / NonZero(proj);
0315 if (tmax > dist) tmax = dist;
0316 }
0317 }
0318 return tmax;
0319 }
0320
0321
0322 template <>
0323 VECCORE_ATT_HOST_DEVICE inline Precision PolygonalShell::DistanceToInConvex(Vector3D<Precision> const &point,
0324 Vector3D<Precision> const &dir) const
0325 {
0326 Precision dz = 0.5 * (fUpperZ - fLowerZ);
0327 Precision pz = point.z() - 0.5 * (fLowerZ + fUpperZ);
0328 if ((vecCore::math::Abs(pz) - dz) > -kTolerance && pz * dir.z() >= 0) return kInfLength;
0329 const Precision invz = -1. / NonZero(dir.z());
0330 const Precision ddz = (invz < 0) ? dz : -dz;
0331 Precision tmin = (pz + ddz) * invz;
0332 Precision tmax = (pz - ddz) * invz;
0333 const auto S = fPolygon.fVertices.size();
0334 for (size_t i = 0; i < S; ++i) {
0335
0336 const Precision proj = -(fPolygon.fA[i] * dir.x() + fPolygon.fB[i] * dir.y());
0337
0338 const bool moving_away = proj > -kTolerance;
0339
0340 const Precision pdist = -(fPolygon.fA[i] * point.x() + fPolygon.fB[i] * point.y() + fPolygon.fD[i]);
0341 const bool side_correct = pdist > -kTolerance;
0342 if (side_correct) {
0343 if (moving_away) return kInfLength;
0344 const Precision dist = -pdist / NonZero(proj);
0345 if (dist > tmin) tmin = dist;
0346 } else if (moving_away) {
0347 const Precision dist = -pdist / NonZero(proj);
0348 if (dist < tmax) tmax = dist;
0349 }
0350 }
0351 if (tmax < tmin + kTolerance) return kInfLength;
0352 return tmin;
0353 }
0354
0355 #endif
0356
0357 }
0358 }
0359
0360 #endif