File indexing completed on 2025-01-18 10:14:07
0001
0002
0003
0004 #ifndef VECGEOM_EXTRUDED_STRUCT_H
0005 #define VECGEOM_EXTRUDED_STRUCT_H
0006
0007 #include "VecGeom/base/Config.h"
0008
0009 #include "VecGeom/volumes/PolygonalShell.h"
0010 #include "VecGeom/volumes/TessellatedStruct.h"
0011
0012 #ifndef VECGEOM_ENABLE_CUDA
0013 #include "VecGeom/volumes/TessellatedSection.h"
0014 #endif
0015
0016 namespace vecgeom {
0017
0018 VECGEOM_DEVICE_FORWARD_DECLARE(class ExtrudedStruct;);
0019 VECGEOM_DEVICE_DECLARE_CONV(class, ExtrudedStruct);
0020 VECGEOM_DEVICE_DECLARE_CONV(struct, XtruVertex2);
0021 VECGEOM_DEVICE_DECLARE_CONV(struct, XtruSection);
0022
0023 inline namespace VECGEOM_IMPL_NAMESPACE {
0024
0025
0026
0027
0028 struct XtruVertex2 {
0029 Precision x;
0030 Precision y;
0031 };
0032
0033 struct XtruSection {
0034 Vector3D<Precision> fOrigin;
0035 Precision fScale;
0036 };
0037
0038 class ExtrudedStruct {
0039
0040
0041
0042 template <typename U>
0043 using vector_t = vecgeom::Vector<U>;
0044
0045 public:
0046 bool fIsSxtru = false;
0047 bool fInitialized = false;
0048 Precision *fZPlanes = nullptr;
0049 mutable Precision fCubicVolume = 0.;
0050 mutable Precision fSurfaceArea = 0.;
0051 PolygonalShell fSxtruHelper;
0052 TessellatedStruct<3, Precision> fTslHelper;
0053 #ifndef VECGEOM_ENABLE_CUDA
0054 bool fUseTslSections = false;
0055 vector_t<TessellatedSection<Precision> *> fTslSections;
0056 #endif
0057 vector_t<XtruVertex2> fVertices;
0058 vector_t<XtruSection> fSections;
0059 PlanarPolygon fPolygon;
0060
0061 public:
0062
0063 VECCORE_ATT_HOST_DEVICE
0064 ExtrudedStruct() {}
0065
0066
0067 VECCORE_ATT_HOST_DEVICE
0068 ExtrudedStruct(int nvertices, XtruVertex2 const *vertices, int nsections, XtruSection const *sections)
0069 {
0070 Initialize(nvertices, vertices, nsections, sections);
0071 }
0072
0073
0074 VECCORE_ATT_HOST_DEVICE
0075 ExtrudedStruct(size_t nvertices, const Precision *x, const Precision *y, Precision zmin, Precision zmax)
0076 {
0077 XtruVertex2 *vertices = new XtruVertex2[nvertices];
0078 XtruSection *sections = new XtruSection[2];
0079 for (size_t i = 0; i < nvertices; ++i) {
0080 vertices[i].x = x[i];
0081 vertices[i].y = y[i];
0082 }
0083
0084 sections[0].fScale = 1.;
0085 sections[0].fOrigin.Set(0., 0., zmin);
0086
0087 sections[1].fScale = 1.;
0088 sections[1].fOrigin.Set(0., 0., zmax);
0089
0090 Initialize(nvertices, vertices, 2, sections);
0091 delete[] vertices;
0092 delete[] sections;
0093 }
0094
0095 VECGEOM_FORCE_INLINE
0096 VECCORE_ATT_HOST_DEVICE
0097 int FindZSegment(Precision const &pointZ) const
0098 {
0099 int index = -1;
0100 Precision const *begin = fZPlanes;
0101 Precision const *end = fZPlanes + fSections.size() + 1;
0102 while (begin < end - 1 && pointZ - kTolerance > *begin) {
0103 ++index;
0104 ++begin;
0105 }
0106 if (pointZ + kTolerance > *begin) return (index + 1);
0107 return index;
0108 }
0109
0110
0111 void Initialize(int nvertices, XtruVertex2 const *vertices, int nsections, XtruSection const *sections)
0112 {
0113 if (fInitialized) return;
0114 assert(nsections > 1 && nvertices > 2);
0115 fZPlanes = new Precision[nsections];
0116 fZPlanes[0] = sections[0].fOrigin.z();
0117 bool degenerated = false;
0118 for (size_t i = 1; i < (size_t)nsections; ++i) {
0119 fZPlanes[i] = sections[i].fOrigin.z();
0120
0121 assert(fZPlanes[i] >= fZPlanes[i - 1] && "Extruded sections not defined in increasing Z order");
0122 if (fZPlanes[i] - fZPlanes[i - 1] < kTolerance) degenerated = true;
0123 }
0124 #ifndef VECGEOM_ENABLE_CUDA
0125 if (!degenerated) fUseTslSections = true;
0126 #endif
0127 (void)degenerated;
0128
0129 if (nsections == 2 && (sections[0].fOrigin - sections[1].fOrigin).Perp2() < kTolerance &&
0130 vecCore::math::Abs(sections[0].fScale - sections[1].fScale) < kTolerance)
0131 fIsSxtru = true;
0132 if (fIsSxtru) {
0133
0134 Precision *x = new Precision[nvertices];
0135 Precision *y = new Precision[nvertices];
0136 for (size_t i = 0; i < (size_t)nvertices; ++i) {
0137 x[i] = sections[0].fOrigin.x() + sections[0].fScale * vertices[i].x;
0138 y[i] = sections[0].fOrigin.y() + sections[0].fScale * vertices[i].y;
0139 }
0140 fSxtruHelper.Init(nvertices, x, y, sections[0].fOrigin[2], sections[1].fOrigin[2]);
0141 delete[] x;
0142 delete[] y;
0143 }
0144
0145 CreateTessellated(nvertices, vertices, nsections, sections);
0146 fInitialized = true;
0147 }
0148
0149
0150 VECCORE_ATT_HOST_DEVICE
0151 void CreateTessellated(size_t nvertices, XtruVertex2 const *vertices, size_t nsections, XtruSection const *sections)
0152 {
0153 struct FacetInd {
0154 size_t ind1, ind2, ind3;
0155 FacetInd(int i1, int i2, int i3)
0156 {
0157 ind1 = i1;
0158 ind2 = i2;
0159 ind3 = i3;
0160 }
0161 };
0162
0163
0164 for (size_t isect = 0; isect < nsections; ++isect)
0165 fSections.push_back(sections[isect]);
0166
0167
0168 Precision *vx = new Precision[nvertices];
0169 Precision *vy = new Precision[nvertices];
0170 for (size_t i = 0; i < nvertices; ++i) {
0171 vx[i] = vertices[i].x;
0172 vy[i] = vertices[i].y;
0173 }
0174 fPolygon.Init(nvertices, vx, vy);
0175 #ifndef VECGEOM_ENABLE_CUDA
0176 fUseTslSections &= fPolygon.IsConvex();
0177 if (fUseTslSections) {
0178
0179 fTslSections.reserve(nsections);
0180 for (size_t i = 0; i < nsections - 1; ++i) {
0181 fTslSections[i] =
0182 new TessellatedSection<Precision>(nvertices, sections[i].fOrigin.z(), sections[i + 1].fOrigin.z());
0183 }
0184 }
0185 #endif
0186
0187
0188 VectorBase<FacetInd> facets(nvertices);
0189
0190 vector_t<size_t> vtx;
0191 for (size_t i = 0; i < nvertices; ++i)
0192 vtx.push_back(i);
0193
0194 size_t i1 = 0;
0195 size_t i2 = 1;
0196 size_t i3 = 2;
0197
0198 while (vtx.size() > 2) {
0199
0200 size_t counter = 0;
0201 while (!IsConvexSide(vtx[i1], vtx[i2], vtx[i3])) {
0202 i1++;
0203 i2++;
0204 i3 = (i3 + 1) % vtx.size();
0205 counter++;
0206 assert(counter < nvertices && "Triangulation failed");
0207 (void)counter;
0208 }
0209 bool good = true;
0210
0211 for (auto i : vtx) {
0212 if (i == vtx[i1] || i == vtx[i2] || i == vtx[i3]) continue;
0213 if (IsPointInside(vtx[i1], vtx[i2], vtx[i3], i)) {
0214 good = false;
0215 i1++;
0216 i2++;
0217 i3 = (i3 + 1) % vtx.size();
0218 break;
0219 }
0220 }
0221
0222 if (good) {
0223
0224 facets.push_back(FacetInd(vtx[i1], vtx[i2], vtx[i3]));
0225
0226 vtx.erase(vtx.begin() + i2);
0227 i1 = 0;
0228 i2 = 1;
0229 i3 = 2;
0230 }
0231 }
0232
0233
0234 for (size_t i = 0; i < facets.size(); ++i) {
0235 i1 = facets[i].ind1;
0236 i2 = facets[i].ind2;
0237 i3 = facets[i].ind3;
0238 fTslHelper.AddTriangularFacet(VertexToSection(i1, 0), VertexToSection(i2, 0), VertexToSection(i3, 0));
0239 }
0240
0241 for (size_t isect = 0; isect < nsections - 1; ++isect) {
0242 for (size_t i = 0; i < (size_t)nvertices; ++i) {
0243 size_t j = (i + 1) % nvertices;
0244
0245 fTslHelper.AddQuadrilateralFacet(VertexToSection(j, isect), VertexToSection(i, isect),
0246 VertexToSection(i, isect + 1), VertexToSection(j, isect + 1));
0247 #ifndef VECGEOM_ENABLE_CUDA
0248 if (fUseTslSections)
0249 fTslSections[isect]->AddQuadrilateralFacet(VertexToSection(j, isect), VertexToSection(i, isect),
0250 VertexToSection(i, isect + 1), VertexToSection(j, isect + 1));
0251 #endif
0252 }
0253 }
0254
0255 for (size_t i = 0; i < facets.size(); ++i) {
0256 i1 = facets[i].ind1;
0257 i2 = facets[i].ind2;
0258 i3 = facets[i].ind3;
0259 fTslHelper.AddTriangularFacet(VertexToSection(i1, nsections - 1), VertexToSection(i3, nsections - 1),
0260 VertexToSection(i2, nsections - 1));
0261 }
0262
0263 fTslHelper.Close();
0264 }
0265
0266
0267 VECCORE_ATT_HOST_DEVICE
0268 VECGEOM_FORCE_INLINE
0269 size_t GetNSections() const { return fSections.size(); }
0270
0271
0272 VECCORE_ATT_HOST_DEVICE
0273 VECGEOM_FORCE_INLINE
0274 size_t GetNSegments() const { return (fSections.size() - 1); }
0275
0276
0277 VECCORE_ATT_HOST_DEVICE
0278 VECGEOM_FORCE_INLINE
0279 XtruSection GetSection(int i) const { return fSections[i]; }
0280
0281
0282 VECCORE_ATT_HOST_DEVICE
0283 VECGEOM_FORCE_INLINE
0284 size_t GetNVertices() const { return fPolygon.GetNVertices(); }
0285
0286
0287 VECCORE_ATT_HOST_DEVICE
0288 VECGEOM_FORCE_INLINE
0289 void GetVertex(int i, Precision &x, Precision &y) const
0290 {
0291 x = fPolygon.GetVertices().x()[i];
0292 y = fPolygon.GetVertices().y()[i];
0293 }
0294
0295
0296 VECCORE_ATT_HOST_DEVICE
0297 VECGEOM_FORCE_INLINE
0298 bool IsSameLine(size_t i, size_t i1, size_t i2) const
0299 {
0300 const Precision *x = fPolygon.GetVertices().x();
0301 const Precision *y = fPolygon.GetVertices().y();
0302 if (x[i1] == x[i2]) return std::fabs(x[i] - x[i1]) < kTolerance * 0.5;
0303
0304 Precision slope = (y[i2] - y[i1]) / (x[i2] - x[i1]);
0305 Precision predy = y[i1] + slope * (x[i] - x[i1]);
0306 Precision dy = y[i] - predy;
0307
0308
0309 const Precision tol = 0.5 * kTolerance;
0310 bool squareComp = (dy * dy < (1 + slope * slope) * tol * tol);
0311 return squareComp;
0312 }
0313
0314
0315 VECCORE_ATT_HOST_DEVICE
0316 VECGEOM_FORCE_INLINE
0317 bool IsSameLineSegment(size_t i, size_t i1, size_t i2) const
0318 {
0319 const Precision *x = fPolygon.GetVertices().x();
0320 const Precision *y = fPolygon.GetVertices().y();
0321 if (x[i] < std::min(x[i1], x[i2]) - kTolerance * 0.5 || x[i] > std::max(x[i1], x[i2]) + kTolerance * 0.5 ||
0322 y[i] < std::min(y[i1], y[i2]) - kTolerance * 0.5 || y[i] > std::max(y[i1], y[i2]) + kTolerance * 0.5)
0323 return false;
0324
0325 return IsSameLine(i, i1, i2);
0326 }
0327
0328
0329 VECCORE_ATT_HOST_DEVICE
0330 VECGEOM_FORCE_INLINE
0331 bool IsSameSide(size_t i, size_t j, size_t i1, size_t i2) const
0332 {
0333 const Precision *x = fPolygon.GetVertices().x();
0334 const Precision *y = fPolygon.GetVertices().y();
0335
0336 return ((x[i] - x[i1]) * (y[i2] - y[i1]) - (x[i2] - x[i1]) * (y[i] - y[i1])) *
0337 ((x[j] - x[i1]) * (y[i2] - y[i1]) - (x[i2] - x[i1]) * (y[j] - y[i1])) >
0338 0;
0339 }
0340
0341
0342 VECCORE_ATT_HOST_DEVICE
0343 VECGEOM_FORCE_INLINE
0344 bool IsPointInside(size_t i1, size_t i2, size_t i3, size_t i) const
0345 {
0346 const Precision *x = fPolygon.GetVertices().x();
0347 const Precision *y = fPolygon.GetVertices().y();
0348
0349
0350 if ((x[i] < x[i1] && x[i] < x[i2] && x[i] < x[i3]) || (x[i] > x[i1] && x[i] > x[i2] && x[i] > x[i3]) ||
0351 (y[i] < y[i1] && y[i] < y[i2] && y[i] < y[i3]) || (y[i] > y[i1] && y[i] > y[i2] && y[i] > y[i3]))
0352 return false;
0353
0354 bool inside = IsSameSide(i, i1, i2, i3) && IsSameSide(i, i2, i1, i3) && IsSameSide(i, i3, i1, i2);
0355
0356 bool onEdge = IsSameLineSegment(i, i1, i2) || IsSameLineSegment(i, i2, i3) || IsSameLineSegment(i, i3, i1);
0357
0358 return inside || onEdge;
0359 }
0360
0361
0362 VECCORE_ATT_HOST_DEVICE
0363 VECGEOM_FORCE_INLINE
0364 bool IsConvexSide(size_t i0, size_t i1, size_t i2)
0365 {
0366 const Precision *x = fPolygon.GetVertices().x();
0367 const Precision *y = fPolygon.GetVertices().y();
0368 Precision cross = (x[i1] - x[i0]) * (y[i2] - y[i1]) - (x[i2] - x[i1]) * (y[i1] - y[i0]);
0369 return cross < 0.;
0370 }
0371
0372
0373 VECCORE_ATT_HOST_DEVICE
0374 VECGEOM_FORCE_INLINE
0375 bool IsConvexPolygon() const { return fPolygon.IsConvex(); }
0376
0377
0378 VECCORE_ATT_HOST_DEVICE
0379 VECGEOM_FORCE_INLINE
0380 Vector3D<Precision> VertexToSection(size_t ivert, size_t isect) const
0381 {
0382 const Precision *x = fPolygon.GetVertices().x();
0383 const Precision *y = fPolygon.GetVertices().y();
0384 Vector3D<Precision> vert(fSections[isect].fOrigin[0] + fSections[isect].fScale * x[ivert],
0385 fSections[isect].fOrigin[1] + fSections[isect].fScale * y[ivert],
0386 fSections[isect].fOrigin[2]);
0387 return vert;
0388 }
0389 };
0390
0391 }
0392 }
0393
0394 #endif