File indexing completed on 2025-03-13 09:29:25
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef VECGEOM_VOLUMES_GENTRAPSTRUCT_H_
0009 #define VECGEOM_VOLUMES_GENTRAPSTRUCT_H_
0010 #include "VecGeom/base/Global.h"
0011 #include "VecGeom/volumes/SecondOrderSurfaceShell.h"
0012
0013 #ifndef VECCORE_CUDA
0014 #include "VecGeom/volumes/TessellatedSection.h"
0015 #endif
0016
0017 namespace vecgeom {
0018
0019 inline namespace VECGEOM_IMPL_NAMESPACE {
0020
0021
0022
0023 template <typename T = double>
0024 struct GenTrapStruct {
0025 using Vertex_t = Vector3D<T>;
0026
0027 Vertex_t fBBdimensions;
0028 Vertex_t fBBorigin;
0029 Vertex_t fVertices[8];
0030
0031
0032 T fVerticesX[8];
0033 T fVerticesY[8];
0034 T fTwist[4];
0035
0036 T fDz;
0037 T fInverseDz;
0038 T fHalfInverseDz;
0039 bool fIsTwisted;
0040
0041
0042
0043
0044
0045
0046 T fConnectingComponentsX[4];
0047 T fConnectingComponentsY[4];
0048
0049 T fDeltaX[8];
0050 T fDeltaY[8];
0051
0052 bool fDegenerated[4];
0053
0054 SecondOrderSurfaceShell<4> fSurfaceShell;
0055
0056 #ifndef VECCORE_CUDA
0057 TessellatedSection<T> *fTslHelper = nullptr;
0058 #endif
0059
0060 VECCORE_ATT_HOST_DEVICE
0061 GenTrapStruct()
0062 : fBBdimensions(), fBBorigin(), fVertices(), fVerticesX(), fVerticesY(), fDz(0.), fInverseDz(0.),
0063 fHalfInverseDz(0.), fIsTwisted(false), fConnectingComponentsX(), fConnectingComponentsY(), fDeltaX(), fDeltaY(),
0064 fSurfaceShell()
0065 {
0066
0067 }
0068
0069 VECCORE_ATT_HOST_DEVICE
0070 GenTrapStruct(const Precision verticesx[], const Precision verticesy[], Precision halfzheight)
0071 : fBBdimensions(), fBBorigin(), fVertices(), fVerticesX(), fVerticesY(), fDz(0.), fInverseDz(0.),
0072 fHalfInverseDz(0.), fIsTwisted(false), fConnectingComponentsX(), fConnectingComponentsY(), fDeltaX(), fDeltaY(),
0073 fSurfaceShell()
0074 {
0075
0076 Initialize(verticesx, verticesy, halfzheight);
0077 }
0078
0079 VECCORE_ATT_HOST_DEVICE
0080 bool Initialize(const Precision verticesx[], const Precision verticesy[], Precision halfzheight)
0081 {
0082
0083 fDz = halfzheight;
0084 fInverseDz = 1. / halfzheight;
0085 fHalfInverseDz = 0.5 / halfzheight;
0086 fIsTwisted = false;
0087 fSurfaceShell.Initialize(verticesx, verticesy, halfzheight);
0088
0089
0090 for (int i = 0; i < 4; ++i) {
0091 fVertices[i].operator[](0) = verticesx[i];
0092 fVertices[i].operator[](1) = verticesy[i];
0093 fVertices[i].operator[](2) = -halfzheight;
0094 }
0095 for (int i = 4; i < 8; ++i) {
0096 fVertices[i].operator[](0) = verticesx[i];
0097 fVertices[i].operator[](1) = verticesy[i];
0098 fVertices[i].operator[](2) = halfzheight;
0099 }
0100
0101 for (int i = 0; i < 4; ++i) {
0102 int j = (i + 1) % 4;
0103 fDegenerated[i] = (Abs(verticesx[i] - verticesx[j]) < kTolerance) &&
0104 (Abs(verticesy[i] - verticesy[j]) < kTolerance) &&
0105 (Abs(verticesx[i + 4] - verticesx[j + 4]) < kTolerance) &&
0106 (Abs(verticesy[i + 4] - verticesy[j + 4]) < kTolerance);
0107 }
0108
0109
0110 Precision sum1 = 0.;
0111 Precision sum2 = 0.;
0112 for (int i = 0; i < 4; ++i) {
0113 int j = (i + 1) % 4;
0114 sum1 += fVertices[i].x() * fVertices[j].y() - fVertices[j].x() * fVertices[i].y();
0115 sum2 += fVertices[i + 4].x() * fVertices[j + 4].y() - fVertices[j + 4].x() * fVertices[i + 4].y();
0116 }
0117
0118
0119 if (sum1 * sum2 < -kTolerance) {
0120 printf("ERROR: Unplaced generic trap defined with opposite clockwise\n");
0121 Print();
0122 return false;
0123 }
0124
0125
0126 if (sum1 > kTolerance) {
0127 printf("INFO: Reverting to clockwise vertices of GenTrap shape:\n");
0128 Print();
0129 Vertex_t vtemp;
0130 vtemp = fVertices[1];
0131 fVertices[1] = fVertices[3];
0132 fVertices[3] = vtemp;
0133 vtemp = fVertices[5];
0134 fVertices[5] = fVertices[7];
0135 fVertices[7] = vtemp;
0136 }
0137
0138
0139 for (int i = 0; i < 4; ++i) {
0140 fConnectingComponentsX[i] = (fVertices[i] - fVertices[i + 4]).x();
0141 fConnectingComponentsY[i] = (fVertices[i] - fVertices[i + 4]).y();
0142 fVerticesX[i] = fVertices[i].x();
0143 fVerticesX[i + 4] = fVertices[i + 4].x();
0144 fVerticesY[i] = fVertices[i].y();
0145 fVerticesY[i + 4] = fVertices[i + 4].y();
0146 }
0147
0148
0149 for (int i = 0; i < 4; ++i) {
0150 int j = (i + 1) % 4;
0151 fDeltaX[i] = fVerticesX[j] - fVerticesX[i];
0152 fDeltaX[i + 4] = fVerticesX[j + 4] - fVerticesX[i + 4];
0153 fDeltaY[i] = fVerticesY[j] - fVerticesY[i];
0154 fDeltaY[i + 4] = fVerticesY[j + 4] - fVerticesY[i + 4];
0155 }
0156
0157
0158 if (SegmentsCrossing(fVertices[0], fVertices[1], fVertices[3], fVertices[2]) ||
0159 SegmentsCrossing(fVertices[1], fVertices[2], fVertices[0], fVertices[3]) ||
0160 SegmentsCrossing(fVertices[4], fVertices[5], fVertices[7], fVertices[6]) ||
0161 SegmentsCrossing(fVertices[5], fVertices[6], fVertices[4], fVertices[7])) {
0162 printf("ERROR: Unplaced generic trap defined with crossing opposite segments\n");
0163 Print();
0164 return false;
0165 }
0166
0167
0168 if (!ComputeIsConvexQuadrilaterals()) {
0169 printf("ERROR: Unplaced generic trap defined with top/bottom quadrilaterals not convex\n");
0170 Print();
0171 return false;
0172 }
0173
0174 fIsTwisted = ComputeIsTwisted();
0175
0176 #ifndef VECCORE_CUDA
0177
0178 if (IsPlanar()) {
0179 fTslHelper = new TessellatedSection<T>(4, -fDz, fDz);
0180 fTslHelper->AddQuadrilateralFacet(fVertices[0], fVertices[4], fVertices[5], fVertices[1]);
0181 fTslHelper->AddQuadrilateralFacet(fVertices[1], fVertices[5], fVertices[6], fVertices[2]);
0182 fTslHelper->AddQuadrilateralFacet(fVertices[2], fVertices[6], fVertices[7], fVertices[3]);
0183 fTslHelper->AddQuadrilateralFacet(fVertices[3], fVertices[7], fVertices[4], fVertices[0]);
0184 }
0185 #endif
0186 ComputeBoundingBox();
0187 return true;
0188 }
0189
0190 VECCORE_ATT_HOST_DEVICE
0191 VECGEOM_FORCE_INLINE
0192 bool IsPlanar() const { return (!fIsTwisted); }
0193
0194 VECCORE_ATT_HOST_DEVICE
0195 void ComputeBoundingBox()
0196 {
0197
0198 Vertex_t aMin, aMax;
0199 Extent(aMin, aMax);
0200 fBBorigin = 0.5 * (aMin + aMax);
0201 fBBdimensions = 0.5 * (aMax - aMin);
0202 }
0203
0204 VECCORE_ATT_HOST_DEVICE
0205 void Extent(Vertex_t &aMin, Vertex_t &aMax) const
0206 {
0207
0208 aMin = aMax = fVertices[0];
0209 aMin[2] = -fDz;
0210 aMax[2] = fDz;
0211 for (int i = 0; i < 4; ++i) {
0212
0213 if (aMin[0] > fVertices[i].x()) aMin[0] = fVertices[i].x();
0214 if (aMax[0] < fVertices[i].x()) aMax[0] = fVertices[i].x();
0215 if (aMin[1] > fVertices[i].y()) aMin[1] = fVertices[i].y();
0216 if (aMax[1] < fVertices[i].y()) aMax[1] = fVertices[i].y();
0217
0218 if (aMin[0] > fVertices[i + 4].x()) aMin[0] = fVertices[i + 4].x();
0219 if (aMax[0] < fVertices[i + 4].x()) aMax[0] = fVertices[i + 4].x();
0220 if (aMin[1] > fVertices[i + 4].y()) aMin[1] = fVertices[i + 4].y();
0221 if (aMax[1] < fVertices[i + 4].y()) aMax[1] = fVertices[i + 4].y();
0222 }
0223 }
0224
0225 VECCORE_ATT_HOST_DEVICE
0226 bool ComputeIsConvexQuadrilaterals()
0227 {
0228
0229
0230
0231
0232
0233 for (int i = 0; i < 4; ++i) {
0234 int j = (i + 1) % 4;
0235
0236 Precision crossij = fDeltaX[i] * fDeltaY[j] - fDeltaY[i] * fDeltaX[j];
0237 if (crossij > kTolerance) return false;
0238
0239 crossij = fDeltaX[i + 4] * fDeltaY[j + 4] - fDeltaY[i + 4] * fDeltaX[j + 4];
0240 if (crossij > kTolerance) return false;
0241 }
0242 return true;
0243 }
0244
0245 VECCORE_ATT_HOST_DEVICE
0246 bool ComputeIsTwisted()
0247 {
0248
0249
0250
0251 bool twisted = false;
0252 Precision dx1, dy1, dx2, dy2;
0253 const int nv = 4;
0254
0255 for (int i = 0; i < 4; ++i) {
0256 dx1 = fVertices[(i + 1) % nv].x() - fVertices[i].x();
0257 dy1 = fVertices[(i + 1) % nv].y() - fVertices[i].y();
0258 if ((dx1 == 0) && (dy1 == 0)) {
0259 continue;
0260 }
0261
0262 dx2 = fVertices[nv + (i + 1) % nv].x() - fVertices[nv + i].x();
0263 dy2 = fVertices[nv + (i + 1) % nv].y() - fVertices[nv + i].y();
0264
0265 if ((dx2 == 0 && dy2 == 0)) {
0266 continue;
0267 }
0268 fTwist[i] = std::fabs(dy1 * dx2 - dx1 * dy2);
0269 if (fTwist[i] < kTolerance) {
0270 fTwist[i] = 0.;
0271 continue;
0272 }
0273 twisted = true;
0274 }
0275 return twisted;
0276 }
0277
0278 VECCORE_ATT_HOST_DEVICE
0279 void Print() const
0280 {
0281 printf("--------------------------------------------------------\n");
0282 printf(" =================================================== \n");
0283 printf(" Solid type: UnplacedGenTrap \n");
0284 printf(" half length Z: %f mm \n", fDz);
0285 printf(" list of vertices:\n");
0286
0287 for (int i = 0; i < 8; ++i) {
0288 printf("#%d", i);
0289 printf(" vx = %f mm", fVertices[i].x());
0290 printf(" vy = %f mm\n", fVertices[i].y());
0291 }
0292 printf(" planar: %s\n", IsPlanar() ? "true" : "false");
0293 }
0294
0295 VECCORE_ATT_HOST_DEVICE
0296 bool SegmentsCrossing(Vertex_t p, Vertex_t p1, Vertex_t q, Vertex_t q1) const
0297 {
0298
0299
0300 using Vector = Vertex_t;
0301 Vector r = p1 - p;
0302 Vector s = q1 - q;
0303 Vector r_cross_s = Vector::Cross(r, s);
0304 if (r_cross_s.Mag2() < kTolerance)
0305 return false;
0306
0307
0308
0309
0310
0311 Precision t = Vector::Cross(q - p, s).z() / r_cross_s.z();
0312 if (t < kTolerance || t > 1. - kTolerance) return false;
0313 Precision u = Vector::Cross(q - p, r).z() / r_cross_s.z();
0314 if (u < kTolerance || u > 1. - kTolerance) return false;
0315 return true;
0316 }
0317 };
0318 }
0319 }
0320
0321 #endif