File indexing completed on 2025-12-16 10:33:37
0001
0002
0003
0004
0005
0006
0007
0008
0009 #ifndef VECGEOM_VOLUMES_TESSELLATEDSECTION_H_
0010 #define VECGEOM_VOLUMES_TESSELLATEDSECTION_H_
0011
0012 #include "VecGeom/volumes/TessellatedCluster.h"
0013
0014 #include "VecGeom/management/HybridManager2.h"
0015 #include "VecGeom/navigation/HybridNavigator2.h"
0016 #include "VecGeom/management/ABBoxManager.h"
0017
0018 namespace vecgeom {
0019
0020 inline namespace VECGEOM_IMPL_NAMESPACE {
0021
0022
0023
0024
0025 template <typename T>
0026 class TessellatedSection {
0027
0028 template <typename U>
0029
0030 using vector_t = std::vector<U>;
0031
0032 using Real_v = vecgeom::VectorBackend::Real_v;
0033
0034 using Facet_t = QuadrilateralFacet<T>;
0035
0036 using Cluster_t = TessellatedCluster<4, Real_v>;
0037
0038 private:
0039 size_t fNfacets = 0;
0040 T fZ = 0;
0041 T fDz = 0;
0042 T fCubicVolume = 0;
0043 T fSurfaceArea = 0;
0044 Vector3D<T> fMinExtent;
0045 Vector3D<T> fMaxExtent;
0046 bool fSameZ = false;
0047 T fUpNorm = 0;
0048
0049 vector_t<Vector3D<T>> fVertices;
0050 vector_t<Facet_t *> fFacets;
0051 vector_t<Cluster_t *> fClusters;
0052
0053 protected:
0054
0055
0056
0057
0058
0059 VECCORE_ATT_HOST_DEVICE
0060 void AddFacet(Facet_t *facet)
0061 {
0062
0063
0064 if (fSameZ) {
0065 Vector3D<T> const &normal = facet->GetNormal();
0066 assert(normal.Perp() < kTolerance);
0067 if (fUpNorm == 0.) fUpNorm = vecCore::math::CopySign(T(1.), normal.z());
0068 assert(fUpNorm * normal.z() > 0);
0069 }
0070 fFacets.push_back(facet);
0071
0072 using vecCore::math::Max;
0073 using vecCore::math::Min;
0074 T xmin = Min(Min(facet->fVertices[0].x(), facet->fVertices[1].x()),
0075 Min(facet->fVertices[2].x(), facet->fVertices[3].x()));
0076 T ymin = Min(Min(facet->fVertices[0].y(), facet->fVertices[1].y()),
0077 Min(facet->fVertices[2].y(), facet->fVertices[3].y()));
0078 fMinExtent[0] = Min(fMinExtent[0], xmin);
0079 fMinExtent[1] = Min(fMinExtent[1], ymin);
0080 fMinExtent[2] = fZ - fDz;
0081 T xmax = Max(Max(facet->fVertices[0].x(), facet->fVertices[1].x()),
0082 Max(facet->fVertices[2].x(), facet->fVertices[3].x()));
0083 T ymax = Max(Min(facet->fVertices[0].y(), facet->fVertices[1].y()),
0084 Max(facet->fVertices[2].y(), facet->fVertices[3].y()));
0085 fMaxExtent[0] = Max(fMaxExtent[0], xmax);
0086 fMaxExtent[1] = Max(fMaxExtent[1], ymax);
0087 fMaxExtent[2] = fZ + fDz;
0088
0089 size_t nfacets = fFacets.size();
0090 assert(nfacets <= fNfacets && "Cannot add extra facets to section");
0091 if (nfacets % kVecSize == 0 || nfacets == fNfacets) {
0092 size_t istart = nfacets - (nfacets - 1) % kVecSize - 1;
0093 size_t i = 0;
0094 Cluster_t *cluster = new Cluster_t();
0095 for (; istart < nfacets; ++istart) {
0096 cluster->AddFacet(i++, fFacets[istart], istart);
0097 }
0098
0099 for (; i < kVecSize; ++i)
0100 cluster->AddFacet(i, facet, nfacets - 1);
0101 fClusters.push_back(cluster);
0102 }
0103 if (nfacets == fNfacets) {
0104 assert(CalculateConvexity() == true);
0105 }
0106 }
0107
0108
0109 VECCORE_ATT_HOST_DEVICE
0110 bool CalculateConvexity()
0111 {
0112 size_t nconvex = 0;
0113 for (size_t i = 0; i < fNfacets; ++i) {
0114 Facet_t *facet = fFacets[i];
0115 bool convex = true;
0116 for (size_t j = 0; j < fNfacets; ++j) {
0117 if (j == i) continue;
0118 for (size_t ivert = 0; ivert < 4; ++ivert) {
0119 convex &= facet->DistPlane(fFacets[j]->fVertices[ivert]) < kTolerance;
0120 }
0121 if (!convex) continue;
0122 }
0123 facet->fConvex = convex;
0124 if (convex) nconvex++;
0125 }
0126 for (auto cluster : fClusters)
0127 cluster->CalculateConvexity();
0128 if (nconvex == fNfacets) return true;
0129 return false;
0130 }
0131
0132 public:
0133
0134
0135
0136
0137 VECCORE_ATT_HOST_DEVICE
0138 TessellatedSection(int nfacets, T zmin, T zmax) : fNfacets(nfacets), fZ(0.5 * (zmin + zmax)), fDz(0.5 * (zmax - zmin))
0139 {
0140 assert(zmax >= zmin && "zmin is greater than zmax");
0141 if (fDz < kTolerance) {
0142 fSameZ = true;
0143 fDz = 0.;
0144 }
0145 fMinExtent.Set(InfinityLength<T>());
0146 fMaxExtent.Set(-InfinityLength<T>());
0147 }
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159 VECCORE_ATT_HOST_DEVICE
0160 bool AddQuadrilateralFacet(Vector3D<T> const &vt0, Vector3D<T> const &vt1, Vector3D<T> const &vt2,
0161 Vector3D<T> const &vt3, bool absolute = true)
0162 {
0163
0164 Facet_t *facet = new Facet_t;
0165 if (absolute) {
0166 if (!facet->SetVertices(vt0, vt1, vt2, vt3)) {
0167 delete facet;
0168 return false;
0169 }
0170 AddFacet(facet);
0171 } else {
0172 if (!facet->SetVertices(vt0, vt0 + vt1, vt0 + vt1 + vt2, vt0 + vt1 + vt2 + vt3)) {
0173 delete facet;
0174 return false;
0175 }
0176 AddFacet(facet);
0177 }
0178 return true;
0179 }
0180
0181
0182
0183
0184 VECCORE_ATT_HOST_DEVICE
0185 VECGEOM_FORCE_INLINE
0186 bool IsOutside(Vector3D<T> const &point)
0187 {
0188 return ((point - fMinExtent).Min() < -kTolerance || (point - fMaxExtent).Max() > kTolerance);
0189 }
0190
0191
0192
0193
0194 VECCORE_ATT_HOST_DEVICE
0195 VECGEOM_FORCE_INLINE
0196 Inside_t Inside(Vector3D<Real_v> const &point) const
0197 {
0198
0199 using Bool_v = vecCore::Mask<Real_v>;
0200
0201
0202 size_t nclusters = fClusters.size();
0203
0204 Real_v distPlanes;
0205 Bool_v inside(true), outside(false);
0206 for (size_t i = 0; i < nclusters; ++i) {
0207 distPlanes = fClusters[i]->DistPlanes(point);
0208 outside |= distPlanes > Real_v(kTolerance);
0209
0210 inside &= distPlanes < -kTolerance;
0211 }
0212 if (!vecCore::MaskEmpty(outside)) return kOutside;
0213 if (vecCore::MaskFull(inside)) return kInside;
0214 return kSurface;
0215 }
0216
0217
0218 VECCORE_ATT_HOST_DEVICE
0219 VECGEOM_FORCE_INLINE
0220 size_t GetNfacets() const { return fFacets.size(); }
0221
0222
0223 VECCORE_ATT_HOST_DEVICE
0224 VECGEOM_FORCE_INLINE
0225 size_t GetNclusters() const { return fClusters.size(); }
0226
0227
0228 VECCORE_ATT_HOST_DEVICE
0229 VECGEOM_FORCE_INLINE
0230 Cluster_t const &GetCluster(size_t i) const { return *fClusters[i]; }
0231
0232
0233 VECCORE_ATT_HOST_DEVICE
0234 VECGEOM_FORCE_INLINE
0235 Facet_t const &GetFacet(size_t i) const { return *fFacets[i]; }
0236
0237
0238
0239
0240 VECCORE_ATT_HOST_DEVICE
0241 VECGEOM_FORCE_INLINE
0242 bool Contains(Vector3D<Real_v> const &point) const
0243 {
0244 using Bool_v = vecCore::Mask<Real_v>;
0245
0246
0247
0248
0249 size_t nclusters = fClusters.size();
0250
0251 Bool_v outside(false);
0252
0253 for (size_t i = 0; i < nclusters; ++i) {
0254 Real_v distPlanes = fClusters[i]->DistPlanes(point);
0255 outside |= distPlanes > Real_v(0);
0256 if (!vecCore::MaskEmpty(outside)) return false;
0257 }
0258 return true;
0259 }
0260
0261
0262
0263
0264
0265
0266
0267 template <bool skipZ = true>
0268 VECGEOM_FORCE_INLINE
0269 VECCORE_ATT_HOST_DEVICE
0270 T DistanceToIn(Vector3D<T> const &point, Vector3D<T> const &direction, T invdirz, T stepmax) const
0271 {
0272
0273 if (fSameZ) {
0274
0275
0276 T pz = point.z() - fZ;
0277
0278 if (fUpNorm * direction.z() > 0 || pz * fUpNorm < -kTolerance) return InfinityLength<T>();
0279 T distance = -pz * invdirz;
0280
0281 Vector3D<T> propagated(point + distance * direction);
0282 const int nclusters = fClusters.size();
0283 for (int i = 0; i < nclusters; ++i) {
0284 if (fClusters[i]->Contains(propagated)) return distance;
0285 }
0286 return InfinityLength<T>();
0287 }
0288
0289 T pz = point.z() - fZ;
0290 if (!skipZ) {
0291 if ((vecCore::math::Abs(pz) - fDz) > -kTolerance && pz * direction.z() >= 0) return InfinityLength<T>();
0292 }
0293 const T ddz = vecCore::math::CopySign(fDz, invdirz);
0294 const T distz = -(pz + ddz) * invdirz;
0295 T distance = distz;
0296 T limit = vecCore::math::Min(-(pz - ddz) * invdirz, stepmax);
0297
0298 const int nclusters = fClusters.size();
0299 for (int i = 0; i < nclusters; ++i) {
0300 bool canhit =
0301 (fClusters[i]->DistanceToInConvex(point, direction, distance, limit)) && (distance < limit - kTolerance);
0302 if (!canhit) return InfinityLength<T>();
0303 }
0304 if (skipZ) {
0305 if (distance > distz) return distance;
0306 return InfinityLength<T>();
0307 }
0308 return distance;
0309 }
0310
0311
0312
0313
0314
0315 template <bool skipZ = true>
0316 VECGEOM_FORCE_INLINE
0317 VECCORE_ATT_HOST_DEVICE
0318 T DistanceToOut(Vector3D<T> const &point, Vector3D<T> const &direction) const
0319 {
0320
0321
0322 T pz = point.z() - fZ;
0323 const T safz = vecCore::math::Abs(pz) - fDz;
0324 if (safz > kTolerance) return -kTolerance;
0325 const T vz = direction.z();
0326 T distance = (vecCore::math::CopySign(fDz, vz) - pz) / NonZero(vz);
0327 T dist;
0328 const int nclusters = fClusters.size();
0329 for (int i = 0; i < nclusters; ++i) {
0330 if (!fClusters[i]->DistanceToOutConvex(point, direction, dist)) return dist;
0331 if (dist < distance) distance = dist;
0332 }
0333 return distance;
0334 }
0335
0336
0337
0338
0339
0340
0341 VECCORE_ATT_HOST_DEVICE
0342 VECGEOM_FORCE_INLINE
0343 T DistanceToOutRange(Vector3D<T> const &point, Vector3D<T> const &direction, T invdirz) const
0344 {
0345
0346
0347 if (fSameZ) {
0348
0349
0350 T pz = point.z() - fZ;
0351
0352 if (fUpNorm * direction.z() < 0 || pz * fUpNorm > kTolerance) return InfinityLength<T>();
0353 T distance = -pz * invdirz;
0354
0355 Vector3D<T> propagated(point + distance * direction);
0356 const int nclusters = fClusters.size();
0357 for (int i = 0; i < nclusters; ++i) {
0358 if (fClusters[i]->Contains(propagated)) return distance;
0359 }
0360 return InfinityLength<T>();
0361 }
0362 T pz = point.z() - fZ;
0363 T dmax = (vecCore::math::CopySign(fDz, invdirz) - pz) * invdirz;
0364 T dmin = (-vecCore::math::CopySign(fDz, invdirz) - pz) * invdirz;
0365 T dtoin = dmin;
0366 T dtoout = InfinityLength<T>();
0367 const int nclusters = fClusters.size();
0368 for (int i = 0; i < nclusters; ++i) {
0369 bool hit = fClusters[i]->DistanceToInOut(point, direction, dtoin, dtoout);
0370 if (!hit) return InfinityLength<T>();
0371 }
0372
0373 if (dtoout > dtoin - kTolerance && dtoout < dmax) return dtoout;
0374 return InfinityLength<T>();
0375 }
0376
0377
0378
0379
0380
0381
0382 VECCORE_ATT_HOST_DEVICE
0383 VECGEOM_FORCE_INLINE
0384 T DistanceToOut(Vector3D<Real_v> const &point, Vector3D<Real_v> const &direction, int &isurf) const
0385 {
0386
0387
0388 isurf = -1;
0389 T distance = InfinityLength<T>();
0390 T stepmax = InfinityLength<T>();
0391 const int nclusters = fClusters.size();
0392 for (int i = 0; i < nclusters; ++i) {
0393 int isurfcrt = -1;
0394 T distcrt;
0395 fClusters[i]->DistanceToOut(point, direction, stepmax, distcrt, isurfcrt);
0396 if (distcrt < distance) {
0397 distance = distcrt;
0398 isurf = isurfcrt;
0399 }
0400 }
0401 return distance;
0402 }
0403
0404
0405
0406
0407 VECCORE_ATT_HOST_DEVICE
0408 VECGEOM_FORCE_INLINE
0409 T SafetyToIn(Vector3D<T> const &point) const
0410 {
0411
0412 T safety = vecCore::math::Max(fZ - fDz - point.z(), point.z() - fZ - fDz);
0413 const int nclusters = fClusters.size();
0414 for (int i = 0; i < nclusters; ++i) {
0415 const Real_v safcl = fClusters[i]->DistPlanes(point);
0416 const T saf = vecCore::ReduceMax(safcl);
0417 if (saf > safety) safety = saf;
0418 }
0419 return safety;
0420 }
0421
0422
0423
0424
0425
0426 VECCORE_ATT_HOST_DEVICE
0427 VECGEOM_FORCE_INLINE
0428 T SafetyToInSq(Vector3D<Real_v> const &point, int &isurf) const
0429 {
0430
0431
0432 isurf = -1;
0433 T safetysq = InfinityLength<T>();
0434 const int nclusters = fClusters.size();
0435 for (int i = 0; i < nclusters; ++i) {
0436 int isurfcrt = -1;
0437 const T safsqcrt = fClusters[i]->template SafetySq<true>(point, isurfcrt);
0438 if (safsqcrt < safetysq) {
0439 safetysq = safsqcrt;
0440 isurf = isurfcrt;
0441 }
0442 }
0443 return safetysq;
0444 }
0445
0446
0447
0448
0449 VECCORE_ATT_HOST_DEVICE
0450 VECGEOM_FORCE_INLINE
0451 T SafetyToOut(Vector3D<T> const &point) const
0452 {
0453
0454 T safety = vecCore::math::Max(fZ - fDz - point.z(), point.z() - fZ - fDz);
0455 const int nclusters = fClusters.size();
0456 for (int i = 0; i < nclusters; ++i) {
0457 const Real_v safcl = fClusters[i]->DistPlanes(point);
0458 const T saf = vecCore::ReduceMax(safcl);
0459 if (saf > safety) safety = saf;
0460 }
0461 return -safety;
0462 }
0463
0464
0465
0466
0467
0468 VECCORE_ATT_HOST_DEVICE
0469 VECGEOM_FORCE_INLINE
0470 T SafetyToOutSq(Vector3D<Real_v> const &point, int &isurf) const
0471 {
0472
0473
0474 isurf = -1;
0475 T safetysq = InfinityLength<T>();
0476 const int nclusters = fClusters.size();
0477 for (int i = 0; i < nclusters; ++i) {
0478 int isurfcrt = -1;
0479 const T safsqcrt = fClusters[i]->template SafetySq<false>(point, isurfcrt);
0480 if (safsqcrt < safetysq) {
0481 safetysq = safsqcrt;
0482 isurf = isurfcrt;
0483 }
0484 }
0485 return safetysq;
0486 }
0487
0488
0489 VECCORE_ATT_HOST_DEVICE
0490 VECGEOM_FORCE_INLINE
0491 void Normal(Vector3D<T> const & , Vector3D<T> & , bool & ) const {}
0492 };
0493
0494 std::ostream &operator<<(std::ostream &os, TessellatedSection<double> const &ts);
0495
0496 }
0497 }
0498
0499 #endif