File indexing completed on 2026-04-17 08:35:32
0001 #ifndef VECGEOM_SURFACE_COMMONTYPES_H
0002 #define VECGEOM_SURFACE_COMMONTYPES_H
0003
0004 #include "VecGeom/base/Assert.h"
0005 #include <VecGeom/base/Transformation3D.h>
0006 #include <VecGeom/base/Transformation3DMP.h>
0007 #include <VecGeom/base/Transformation2DMP.h>
0008 #include <VecGeom/base/Vector2D.h>
0009 #include <VecGeom/base/Vector3D.h>
0010 #include <VecGeom/volumes/kernel/GenericKernels.h>
0011 #include <VecGeom/navigation/NavigationState.h>
0012 #include <VecGeom/management/Logger.h>
0013
0014 namespace vgbrep {
0015
0016
0017
0018 using Precision = vecgeom::Precision;
0019 using uint = vecgeom::uint;
0020 using NavIndex_t = vecgeom::NavIndex_t;
0021 using Transformation = vecgeom::Transformation3D;
0022
0023 template <typename Real_t>
0024 using Vector3D = vecgeom::Vector3D<Real_t>;
0025 template <typename Real_t>
0026 using Vector2D = vecgeom::Vector2D<Real_t>;
0027 template <typename Real_t>
0028 using TransformationMP = vecgeom::Transformation3DMP<Real_t>;
0029
0030 using logic_int = int;
0031
0032
0033 enum OperatorToken : logic_int {
0034 lbegin = logic_int(0x7FFFFFFF - 8),
0035 lfalse = lbegin,
0036 ltrue,
0037 lplus,
0038 lminus,
0039 lnot,
0040 lor,
0041 land,
0042 lend
0043 };
0044
0045 struct LogicExpression {
0046 logic_int size_;
0047 logic_int *data_{nullptr};
0048
0049 static VECCORE_ATT_HOST_DEVICE bool is_operator_token(logic_int lv) { return (lv >= lbegin); }
0050
0051 VECCORE_ATT_HOST_DEVICE
0052 unsigned size() const { return (unsigned)size_; }
0053
0054 VECCORE_ATT_HOST_DEVICE
0055 logic_int operator[](unsigned i) const { return data_[i]; }
0056 };
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066 enum class SurfaceType : char { kNoSurf, kPlanar, kCylindrical, kConical, kSpherical, kTorus, kElliptical, kArb4 };
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077 enum class FrameType : char { kNoFrame, kRangeZ, kRing, kZPhi, kRangeSph, kWindow, kTriangle, kQuadrilateral };
0078
0079
0080 enum class SegmentIntersect : char { kNoIntersect, kEmbedding, kEmbedded, kOverlap, kIntersect, kEqual };
0081 using FrameIntersect = SegmentIntersect;
0082
0083
0084 struct Candidates {
0085 int fNcand{0};
0086 int fNExiting{0};
0087 int *fCandidates{nullptr};
0088 int *fFrameInd{nullptr};
0089 char *fSides{nullptr};
0090
0091 VECCORE_ATT_HOST_DEVICE
0092 int operator[](int i) const { return fCandidates[i]; }
0093 VECCORE_ATT_HOST_DEVICE
0094 int operator[](int i) { return fCandidates[i]; }
0095
0096 Candidates() = default;
0097 };
0098
0099
0100 struct FSlocatorB {
0101 int common_id{0};
0102 int frame_id{-1};
0103
0104 FSlocatorB() = default;
0105
0106 FSlocatorB(int csind, int iframe) : common_id(csind), frame_id(iframe) {}
0107
0108 VECCORE_ATT_HOST_DEVICE
0109 VECGEOM_FORCE_INLINE
0110 FSlocatorB(int csind, int iframe, bool left) { Set(csind, iframe, left); }
0111
0112 VECCORE_ATT_HOST_DEVICE
0113 VECGEOM_FORCE_INLINE
0114 void Set(int csind, int iframe, bool left)
0115 {
0116 common_id = (2 * int(left) - 1) * csind;
0117 frame_id = iframe;
0118 }
0119
0120 VECCORE_ATT_HOST_DEVICE
0121 VECGEOM_FORCE_INLINE
0122 int GetCSindex() const { return vecCore::math::Abs(common_id); }
0123
0124 VECCORE_ATT_HOST_DEVICE
0125 VECGEOM_FORCE_INLINE
0126 bool IsLeftSide() const { return common_id > 0; }
0127
0128 VECCORE_ATT_HOST_DEVICE
0129 VECGEOM_FORCE_INLINE
0130 int GetFSindex() const { return frame_id; }
0131 };
0132
0133 #ifdef VECGEOM_USE_SURF
0134
0135 struct FSlocator : FSlocatorB {
0136 vecgeom::NavigationState state;
0137
0138 VECCORE_ATT_HOST_DEVICE
0139 VECGEOM_FORCE_INLINE
0140 FSlocator() : FSlocatorB() {}
0141
0142 VECCORE_ATT_HOST_DEVICE
0143 VECGEOM_FORCE_INLINE
0144 FSlocator(int csind, int iframe) : FSlocatorB(csind, iframe) {}
0145
0146 VECCORE_ATT_HOST_DEVICE
0147 VECGEOM_FORCE_INLINE
0148 FSlocator(int csind, int iframe, bool left) : FSlocatorB(csind, iframe, left) {}
0149 };
0150
0151
0152 struct CrossedSurface {
0153 FSlocator exit_surf;
0154 FSlocator hit_surf;
0155
0156
0157 CrossedSurface() = default;
0158
0159
0160 VECCORE_ATT_HOST_DEVICE
0161 VECGEOM_FORCE_INLINE
0162 CrossedSurface(int csind1, int iframe1, bool left1, int csind2, int iframe2, bool left2)
0163 : exit_surf(csind1, iframe1, left1), hit_surf(csind2, iframe2, left2)
0164 {
0165 }
0166
0167
0168 VECCORE_ATT_HOST_DEVICE
0169 VECGEOM_FORCE_INLINE
0170 void Set(int csind1, int iframe1, bool left1, int csind2, int iframe2, bool left2)
0171 {
0172 exit_surf.Set(csind1, iframe1, left1);
0173 hit_surf.Set(csind2, iframe2, left2);
0174 }
0175
0176 VECCORE_ATT_HOST_DEVICE
0177 VECGEOM_FORCE_INLINE
0178 void Set(int csind, int iframe, bool left)
0179 {
0180 exit_surf.Set(csind, iframe, left);
0181 hit_surf.Set(csind, iframe, left);
0182 }
0183 };
0184
0185 struct SliceCand {
0186 int fNcand{0};
0187 int *fCandidates{nullptr};
0188 };
0189
0190 enum AxisType : char {
0191 kX,
0192 kY,
0193 kZ,
0194 kR,
0195 kPhi,
0196 kXY,
0197 kNoAxis
0198 };
0199 #endif
0200
0201 template <typename Real_t>
0202 VECCORE_ATT_HOST_DEVICE bool ApproxEqual(Real_t t1, Real_t t2)
0203 {
0204 return std::abs(t1 - t2) <= vecgeom::kToleranceDist<Real_t>;
0205 }
0206
0207 template <typename Real_t>
0208 VECCORE_ATT_HOST_DEVICE bool ApproxEqualVector(Vector3D<Real_t> const &v1, Vector3D<Real_t> const &v2)
0209 {
0210 return ApproxEqual(v1[0], v2[0]) && ApproxEqual(v1[1], v2[1]) && ApproxEqual(v1[2], v2[2]);
0211 }
0212
0213 template <typename Real_t>
0214 VECCORE_ATT_HOST_DEVICE bool ApproxEqualVector2(Vector2D<Real_t> const &v1, Vector2D<Real_t> const &v2)
0215 {
0216 return ApproxEqual(v1[0], v2[0]) && ApproxEqual(v1[1], v2[1]);
0217 }
0218
0219 template <typename Real_t>
0220 bool ApproxEqualTransformation(const vecgeom::Transformation3DMP<Real_t> &t1,
0221 const vecgeom::Transformation3DMP<Real_t> &t2)
0222 {
0223 if (!ApproxEqualVector(t1.Translation(), t2.Translation())) return false;
0224 for (int i = 0; i < 9; ++i)
0225 if (!ApproxEqual(t1.Rotation(i), t2.Rotation(i))) return false;
0226 return true;
0227 }
0228
0229
0230
0231
0232
0233
0234
0235 template <typename Real_t>
0236 VECCORE_ATT_HOST_DEVICE Real_t TruncateValue(Real_t x, Real_t tolerance = vecgeom::kToleranceDist<Real_t>())
0237 {
0238 auto div = std::abs(x);
0239 while (int(div) > 0) {
0240 div /= 10;
0241 tolerance *= 10;
0242 }
0243 return tolerance * std::lround(x / tolerance);
0244 }
0245
0246
0247
0248
0249
0250
0251 template <typename Real_t>
0252 VECCORE_ATT_HOST_DEVICE Real_t RoundingError(Real_t x, Real_t tolerance = vecgeom::kToleranceDist<Real_t>())
0253 {
0254 auto div = std::abs(x);
0255 while (int(div) > 0) {
0256 div /= 10;
0257 tolerance *= 10;
0258 }
0259 return tolerance;
0260 }
0261
0262
0263
0264
0265
0266
0267
0268 template <typename Point>
0269 VECCORE_ATT_HOST_DEVICE auto DistanceToSegmentSquared(Point const &p, Point const &p1, Point const &p2)
0270 {
0271 auto line = p2 - p1;
0272 auto pvec = p - p1;
0273 auto dot0 = line.Dot(pvec);
0274 if (dot0 <= 0) return pvec.Mag2();
0275 auto dot1 = line.Mag2();
0276 if (dot1 <= dot0) return (p - p2).Mag2();
0277 return ((dot0 / dot1) * line - pvec).Mag2();
0278 }
0279
0280
0281
0282
0283
0284 template <typename Real_t>
0285 struct SideDivision {
0286 Real_t fStartU{0.};
0287 Real_t fStepU{0.};
0288 Real_t fStartV{0.};
0289 Real_t fStepV{0.};
0290 unsigned short fNslices{0};
0291 unsigned short fNslicesU{0};
0292 unsigned short fNslicesV{0};
0293 AxisType fAxis{AxisType::kNoAxis};
0294 SliceCand *fSlices{nullptr};
0295
0296
0297 SideDivision() = default;
0298
0299 VECCORE_ATT_HOST_DEVICE VECGEOM_FORCE_INLINE SliceCand const &GetSlice(int indU, int indV)
0300 {
0301 return (fAxis == AxisType::kXY) ? fSlices[fNslicesV * indU + indV] : fSlices[indU];
0302 }
0303
0304
0305
0306
0307
0308 template <typename Real_i>
0309 VECCORE_ATT_HOST_DEVICE VECGEOM_FORCE_INLINE int GetSliceIndex(Vector3D<Real_i> const &onsurf) const
0310 {
0311 int ind = -1;
0312 switch (fAxis) {
0313 case AxisType::kXY: {
0314 int indU = (onsurf[0] - fStartU) / fStepU;
0315 int indV = (onsurf[1] - fStartV) / fStepV;
0316 ind = (indU >= 0 && indV >= 0 && indU < fNslicesU && indV < fNslicesV) ? fNslicesV * indU + indV : -1;
0317 return ind;
0318 }
0319 case AxisType::kR: {
0320 ind = (onsurf.Perp() - fStartU) / fStepU;
0321 return (ind < fNslices) ? ind : -1;
0322 }
0323 case AxisType::kPhi: {
0324 ind = (onsurf.Phi() - fStartU) / fStepU;
0325 return (ind >= 0 && ind < fNslices) ? ind : -1;
0326 }
0327 default:
0328 ind = (onsurf[fAxis] - fStartU) / fStepU;
0329 return (ind >= 0 && ind < fNslices) ? ind : -1;
0330 }
0331 }
0332
0333
0334
0335
0336
0337
0338
0339
0340
0341
0342 template <typename Real_i>
0343 VECGEOM_FORCE_INLINE int GetNslices(Vector3D<Real_i> const &corner1, Vector3D<Real_i> const &corner2, int &u1,
0344 int &u2, int &v1, int &v2) const
0345 {
0346 u1 = -1;
0347 u2 = -1;
0348 v1 = -1;
0349 v2 = -1;
0350 switch (fAxis) {
0351 case kXY: {
0352 int ind1 = (corner1[0] - fStartU) / fStepU;
0353 int ind2 = (corner2[0] - fStartU) / fStepU;
0354 int indmin = std::min(ind1, ind2);
0355 int indmax = std::max(ind1, ind2);
0356 u1 = std::max(indmin, 0);
0357 u2 = std::min(indmax, fNslicesU - 1);
0358 int nslicesx = u2 - u1 + 1;
0359 nslicesx = std::max(nslicesx, 0);
0360 ind1 = (corner1[1] - fStartV) / fStepV;
0361 ind2 = (corner2[1] - fStartV) / fStepV;
0362 indmin = std::min(ind1, ind2);
0363 indmax = std::max(ind1, ind2);
0364 v1 = std::max(indmin, 0);
0365 v2 = std::min(indmax, fNslicesV - 1);
0366 int nslicesy = v2 - v1 + 1;
0367 nslicesy = std::max(nslicesy, 0);
0368 return (nslicesx * nslicesy);
0369 }
0370 case AxisType::kR: {
0371 auto rmax = std::max(corner1.Perp(), corner2.Perp());
0372 u1 = 0;
0373 int indmax = (rmax - fStartU) / fStepU;
0374 u2 = std::min(indmax, fNslices - 1);
0375 return (u2 + 1);
0376 }
0377 case AxisType::kPhi: {
0378 int ind1 = (corner1.Phi() - fStartU) / fStepU;
0379 int ind2 = (corner2.Phi() - fStartU) / fStepU;
0380 int indmin = std::min(ind1, ind2);
0381 int indmax = std::max(ind1, ind2);
0382 u1 = std::max(indmin, 0);
0383 u2 = std::min(indmax, fNslices - 1);
0384 int nslices = u2 - u1 + 1;
0385 return std::max(nslices, 0);
0386 }
0387 default:
0388 int ind1 = (corner1[fAxis] - fStartU) / fStepU;
0389 int ind2 = (corner2[fAxis] - fStartU) / fStepU;
0390 int indmin = std::min(ind1, ind2);
0391 int indmax = std::max(ind1, ind2);
0392 u1 = std::max(indmin, 0);
0393 u2 = std::min(indmax, fNslices - 1);
0394 int nslices = u2 - u1 + 1;
0395 return std::max(nslices, 0);
0396 }
0397 }
0398 };
0399
0400
0401 template <typename Real_t>
0402 using Range = Vector2D<Real_t>;
0403
0404 template <typename Real_t>
0405 using AngleVector = Vector2D<Real_t>;
0406
0407 template <typename Real_t>
0408 using Point2D = Vector2D<Real_t>;
0409
0410 template <typename Real_t>
0411 struct AngleInterval {
0412 Range<Real_t> range;
0413
0414 AngleInterval(Real_t start, Real_t end, bool normalize = true)
0415 {
0416 range[0] = start;
0417 range[1] = end;
0418 if (normalize) Normalize();
0419 }
0420
0421 bool operator<(AngleInterval const &other) { return (range[1] - other.range[0]) < vecgeom::kToleranceStrict<Real_t>; }
0422 bool operator>(AngleInterval const &other) { return (other.range[1] - range[0]) < vecgeom::kToleranceStrict<Real_t>; }
0423 bool operator==(AngleInterval const &other)
0424 {
0425
0426 AngleInterval other_moved = other;
0427 while (other_moved > *this)
0428 other_moved = other_moved.Previous();
0429
0430 while (other_moved < *this)
0431 other_moved = other_moved.Next();
0432 bool equal = vecCore::math::Abs(range[0] - other_moved.range[0]) < vecgeom::kToleranceStrict<Real_t> &&
0433 vecCore::math::Abs(range[1] - other_moved.range[1]) < vecgeom::kToleranceStrict<Real_t>;
0434 return equal;
0435 }
0436 bool operator!=(AngleInterval const &other) { return !operator==(other); }
0437
0438 void Clear() { range[0] = range[1] = Real_t(0); }
0439 bool IsNull() const { return (range[1] - range[0]) < vecgeom::kToleranceStrict<Real_t>; }
0440
0441 void Normalize()
0442 {
0443 range[0] = std::fmod(range[0], vecgeom::kTwoPi) + vecgeom::kTwoPi * (range[0] < Real_t(0));
0444 range[1] = std::fmod(range[1], vecgeom::kTwoPi) + vecgeom::kTwoPi * (range[1] < Real_t(0));
0445 range[1] += vecgeom::kTwoPi * (range[1] - range[0] < vecgeom::kToleranceStrict<Real_t>);
0446 }
0447
0448 AngleInterval Next() const { return AngleInterval(range[0] + vecgeom::kTwoPi, range[1] + vecgeom::kTwoPi, false); }
0449 AngleInterval Previous() const
0450 {
0451 return AngleInterval(range[0] - vecgeom::kTwoPi, range[1] - vecgeom::kTwoPi, false);
0452 }
0453
0454 AngleInterval Intersect(AngleInterval const &other)
0455 {
0456
0457 AngleInterval other_moved = other;
0458 while (other_moved > *this)
0459 other_moved = other_moved.Previous();
0460
0461 while (other_moved < *this)
0462 other_moved = other_moved.Next();
0463
0464 if (other_moved > *this) return AngleInterval(Real_t(0), Real_t(0), false);
0465 return AngleInterval(vecCore::math::Max(range[0], other_moved.range[0]),
0466 vecCore::math::Min(range[1], other_moved.range[1]));
0467 }
0468 };
0469
0470 template <typename Real_t>
0471 struct Circle2D {
0472 Real_t fR;
0473 Point2D<Real_t> fC;
0474 Circle2D(Real_t r, Point2D<Real_t> const ¢er) : fR{r}, fC{center} {}
0475 };
0476
0477 template <typename Real_t>
0478 struct Segment2D {
0479 Point2D<Real_t> fP1;
0480 Point2D<Real_t> fP2;
0481 Vector2D<Real_t> fV;
0482 bool fDegen{false};
0483
0484 Segment2D(Point2D<Real_t> const &p1, Point2D<Real_t> const &p2)
0485 {
0486 fP1 = p1;
0487 fP2 = p2;
0488 fV = fP2 - fP1;
0489 fDegen = fV.Mag2() < vecgeom::kToleranceDistSquared<Real_t>;
0490 }
0491
0492
0493
0494
0495 SegmentIntersect Intersect(Circle2D<Real_t> const &circle) const
0496 {
0497 Vector2D<Real_t> v1 = circle.fC - fP1;
0498 Vector2D<Real_t> v2 = circle.fC - fP2;
0499 bool inside1 = false;
0500 bool inside2 = false;
0501 if (v1.Dot(fV) < vecgeom::MakePlusTolerant<true, Real_t>(0) ||
0502 v2.Dot(fV) > vecgeom::MakeMinusTolerant<true, Real_t>(0)) {
0503
0504
0505 inside1 = v1.Mag() < vecgeom::MakeMinusTolerant<true, Real_t>(circle.fR);
0506 inside2 = v2.Mag() < vecgeom::MakeMinusTolerant<true, Real_t>(circle.fR);
0507 if (inside1 && inside2) return SegmentIntersect::kEmbedded;
0508 if (inside1 ^ inside2) return SegmentIntersect::kIntersect;
0509 return SegmentIntersect::kNoIntersect;
0510 }
0511
0512 auto saf = std::abs(v1.CrossZ(fV)) / fV.Mag();
0513 if (saf > vecgeom::MakeMinusTolerant<true, Real_t>(circle.fR)) return SegmentIntersect::kNoIntersect;
0514
0515 inside1 = v1.Mag() < vecgeom::MakeMinusTolerant<true, Real_t>(circle.fR);
0516 inside2 = v2.Mag() < vecgeom::MakeMinusTolerant<true, Real_t>(circle.fR);
0517 if (inside1 && inside2) return SegmentIntersect::kEmbedded;
0518 return SegmentIntersect::kIntersect;
0519 }
0520
0521 bool BoundingBoxOverlap(Segment2D<Real_t> const &other) const
0522 {
0523 Real_t min_x1 = std::min(fP1.x(), fP2.x());
0524 Real_t max_x1 = std::max(fP1.x(), fP2.x());
0525 Real_t min_y1 = std::min(fP1.y(), fP2.y());
0526 Real_t max_y1 = std::max(fP1.y(), fP2.y());
0527
0528 Real_t min_x2 = std::min(other.fP1.x(), other.fP2.x());
0529 Real_t max_x2 = std::max(other.fP1.x(), other.fP2.x());
0530 Real_t min_y2 = std::min(other.fP1.y(), other.fP2.y());
0531 Real_t max_y2 = std::max(other.fP1.y(), other.fP2.y());
0532
0533 return !(max_x1 - min_x2 < vecgeom::kToleranceDist<Real_t> || max_x2 - min_x1 < vecgeom::kToleranceDist<Real_t> ||
0534 max_y1 - min_y2 < vecgeom::kToleranceDist<Real_t> || max_y2 - min_y1 < vecgeom::kToleranceDist<Real_t>);
0535 }
0536
0537
0538
0539
0540 SegmentIntersect Intersect(Segment2D<Real_t> const &other) const
0541 {
0542
0543 if (fDegen || other.fDegen) return SegmentIntersect::kNoIntersect;
0544 auto v12 = other.fP1 - fP1;
0545 auto s = v12.CrossZ(other.fV);
0546 auto t = v12.CrossZ(fV);
0547 auto norm = fV.CrossZ(other.fV);
0548 auto l1 = fV.Length();
0549 auto l2 = other.fV.Length();
0550 if (std::abs(norm) < 2. * vecCore::math::Max(l1, l2) * vecgeom::kToleranceDist<Real_t>) {
0551
0552 if (std::abs(s / other.fV.Length()) < vecgeom::kToleranceDist<Real_t>) {
0553
0554 auto inv_vsq = l1 / fV.Dot(fV);
0555 auto t1 = inv_vsq * fV.Dot(v12);
0556 auto t2 = inv_vsq * fV.Dot(v12 + other.fV);
0557 if (t1 > t2) std::swap(t1, t2);
0558
0559 if (ApproxEqual(t1, Real_t(0)) && ApproxEqual(t2, l1)) return SegmentIntersect::kEqual;
0560 auto start = std::max(0., t1);
0561 auto end = std::min(l1, t2);
0562 if (end - start < vecgeom::kToleranceDist<Real_t>) return SegmentIntersect::kNoIntersect;
0563 if (ApproxEqual(start, t1) && ApproxEqual(end, t2)) return SegmentIntersect::kEmbedding;
0564 if (ApproxEqual(start, Real_t(0)) && ApproxEqual(end, l1)) return SegmentIntersect::kEmbedded;
0565 return SegmentIntersect::kOverlap;
0566 } else
0567
0568 return SegmentIntersect::kNoIntersect;
0569 }
0570
0571
0572 auto invnorm = 1. / norm;
0573 s *= l1 * invnorm;
0574 t *= l2 * invnorm;
0575 bool outBounds = s < vecgeom::kToleranceDist<Real_t> || (s - l1) > -vecgeom::kToleranceDist<Real_t> ||
0576 t < vecgeom::kToleranceDist<Real_t> || (t - l2) > -vecgeom::kToleranceDist<Real_t>;
0577
0578 if (outBounds) return SegmentIntersect::kNoIntersect;
0579 return SegmentIntersect::kIntersect;
0580 }
0581 };
0582
0583 template <typename Real_t, char N>
0584 struct Polygon {
0585 Point2D<Real_t> fVert[N];
0586 Polygon(Point2D<Real_t> const vertices[N])
0587 {
0588 for (auto i = 0; i < int(N); ++i)
0589 fVert[i] = vertices[i];
0590 }
0591
0592 Polygon(Vector3D<Real_t> const vertices[N])
0593 {
0594 for (auto i = 0; i < int(N); ++i) {
0595 fVert[i][0] = vertices[i][0];
0596 fVert[i][1] = vertices[i][1];
0597 }
0598 }
0599
0600 Point2D<Real_t> GetCenter() const
0601 {
0602 Point2D<Real_t> center;
0603 for (auto i = 0; i < int(N); ++i)
0604 center += fVert[i];
0605 center *= Real_t(1.) / N;
0606 return center;
0607 }
0608
0609
0610
0611
0612
0613 template <char M>
0614 FrameIntersect Intersect(Polygon<Real_t, M> const &other) const
0615 {
0616
0617 int noverlaps = 0;
0618 for (auto i = 0; i < int(N); ++i) {
0619 Segment2D<Real_t> crt{fVert[i], fVert[(i + 1) % N]};
0620
0621
0622 for (auto j = 0; j < int(M); ++j) {
0623 Segment2D<Real_t> ocrt{other.fVert[j], other.fVert[(j + 1) % M]};
0624 auto intersect = crt.Intersect(ocrt);
0625
0626 if (intersect == SegmentIntersect::kIntersect) return FrameIntersect::kIntersect;
0627
0628 noverlaps += intersect != FrameIntersect::kNoIntersect;
0629
0630 if (noverlaps > 1) return FrameIntersect::kIntersect;
0631 }
0632 }
0633
0634 return FrameIntersect::kNoIntersect;
0635 }
0636
0637
0638
0639
0640 FrameIntersect Intersect(Circle2D<Real_t> const &circle) const
0641 {
0642 bool intersect = false;
0643 bool embedded = false;
0644 for (auto i = 0; i < int(N); ++i) {
0645 Segment2D<Real_t> crt{fVert[i], fVert[(i + 1) % N]};
0646
0647 auto intersect_type = crt.Intersect(circle);
0648 embedded &= intersect_type == SegmentIntersect::kEmbedded;
0649 intersect |= intersect_type == SegmentIntersect::kIntersect;
0650 }
0651 if (intersect) return SegmentIntersect::kIntersect;
0652 if (embedded) return SegmentIntersect::kEmbedded;
0653 return SegmentIntersect::kNoIntersect;
0654 }
0655 };
0656
0657
0658
0659
0660 template <typename Real_t>
0661 struct EllipData {
0662 Real_t Rx{0};
0663 Real_t Ry{0};
0664 Real_t dz{0};
0665 Real_t R{0};
0666
0667
0668
0669 Real_t fRsph;
0670 Real_t fDDx;
0671 Real_t fDDy;
0672 Real_t fSx;
0673 Real_t fSy;
0674 Real_t fQ1;
0675 Real_t fQ2;
0676
0677 EllipData() = default;
0678
0679 template <typename Real_i>
0680 EllipData(Real_i radx, Real_i rady, Real_i half_z)
0681 : Rx(static_cast<Real_t>(radx)), Ry(static_cast<Real_t>(rady)), dz(static_cast<Real_t>(half_z))
0682 {
0683
0684 R = vecCore::math::Min(Rx, Ry);
0685
0686
0687 fRsph = vecCore::math::Sqrt(Rx * Rx + Ry * Ry + dz * dz);
0688 fDDx = Rx * Rx;
0689 fDDy = Ry * Ry;
0690 fSx = R / Rx;
0691 fSy = R / Ry;
0692
0693
0694 fQ1 = 0.5 / R;
0695 fQ2 = 0.5 * (R + vecgeom::kHalfTolerance * vecgeom::kHalfTolerance / R);
0696 }
0697 template <typename Real_i>
0698 EllipData(const EllipData<Real_i> &other)
0699 : Rx(static_cast<Real_t>(other.Rx)), Ry(static_cast<Real_t>(other.Ry)), dz(static_cast<Real_t>(other.dz)),
0700 R(static_cast<Real_t>(other.R)), fRsph(static_cast<Real_t>(other.fRsph)), fDDx(static_cast<Real_t>(other.fDDx)),
0701 fDDy(static_cast<Real_t>(other.fDDy)), fSx(static_cast<Real_t>(other.fSx)), fSy(static_cast<Real_t>(other.fSy)),
0702 fQ1(static_cast<Real_t>(other.fQ1)), fQ2(static_cast<Real_t>(other.fQ2))
0703 {
0704 }
0705 };
0706
0707
0708
0709
0710 template <typename Real_t>
0711 struct Arb4Data {
0712 using Vector3D = vecgeom::Vector3D<Real_t>;
0713
0714 Real_t verticesX[4];
0715 Real_t verticesY[4];
0716 Real_t connecting_compX[2];
0717 Real_t connecting_compY[2];
0718 Real_t halfH;
0719 Real_t halfH_inv;
0720 Real_t ftx1, fty1, ftx2, fty2;
0721
0722 Real_t ft1crosst2;
0723 Real_t fDeltatx;
0724 Real_t fDeltaty;
0725
0726
0727 Vector3D fViCrossHi0;
0728 Vector3D fViCrossVj;
0729 Vector3D fHi1CrossHi0;
0730
0731 #ifdef SURF_ACCURATE_SAFETY
0732
0733 Vector3D normal0;
0734 Vector3D normal1;
0735 Vector3D normal2;
0736 Vector3D normal3;
0737 #endif
0738
0739 Arb4Data() = default;
0740
0741 template <typename Real_i>
0742 Arb4Data(Real_i v0_0, Real_i v0_1, Real_i v0_2, Real_i v1_0, Real_i v1_1, Real_i v2_0, Real_i v2_1, Real_i v2_2,
0743 Real_i v3_0, Real_i v3_1)
0744 : halfH(0.5 * static_cast<Real_t>(v2_2 - v0_2)), halfH_inv(1. / halfH)
0745 {
0746
0747 verticesX[0] = static_cast<Real_t>(v0_0);
0748 verticesX[1] = static_cast<Real_t>(v1_0);
0749 verticesX[2] = static_cast<Real_t>(
0750 v3_0);
0751 verticesX[3] = static_cast<Real_t>(v2_0);
0752 verticesY[0] = static_cast<Real_t>(v0_1);
0753 verticesY[1] = static_cast<Real_t>(v1_1);
0754 verticesY[2] = static_cast<Real_t>(v3_1);
0755 verticesY[3] = static_cast<Real_t>(v2_1);
0756
0757 for (int i = 0; i < 2; ++i) {
0758 connecting_compX[i] = verticesX[i] - verticesX[i + 2];
0759 connecting_compY[i] = verticesY[i] - verticesY[i + 2];
0760 }
0761
0762 ftx1 = 0.5 * halfH_inv * -connecting_compX[1];
0763 fty1 = 0.5 * halfH_inv * -connecting_compY[1];
0764 ftx2 = 0.5 * halfH_inv * -connecting_compX[0];
0765 fty2 = 0.5 * halfH_inv * -connecting_compY[0];
0766
0767 ft1crosst2 = ftx1 * fty2 - ftx2 * fty1;
0768 fDeltatx = ftx2 - ftx1;
0769 fDeltaty = fty2 - fty1;
0770
0771
0772 Vector3D va = {verticesX[1], verticesY[1], -halfH};
0773 Vector3D vb = {verticesX[3], verticesY[3], halfH};
0774 Vector3D vc = {verticesX[0], verticesY[0], -halfH};
0775 Vector3D vd = {verticesX[2], verticesY[2], halfH};
0776
0777
0778 fViCrossHi0 = (vb - va).Cross(vc - va);
0779 fViCrossVj = (vb - va).Cross(vd - vc);
0780 fHi1CrossHi0 = (vd - vb).Cross(vc - va);
0781
0782 #ifdef SURF_ACCURATE_SAFETY
0783 normal0 = (vd - vc).Cross(va - vc);
0784 normal0.Normalize();
0785 if ((vb - vc).Dot(normal0) < 0) normal0 *= -1;
0786
0787 normal1 = (vb - va).Cross(vc - va);
0788 normal1.Normalize();
0789 if ((vd - va).Dot(normal1) < 0) normal1 *= -1;
0790
0791 normal2 = (vc - vd).Cross(vb - vd);
0792 normal2.Normalize();
0793 if ((va - vd).Dot(normal2) < 0) normal2 *= -1;
0794
0795 normal3 = (vd - vb).Cross(vc - vb);
0796 normal3.Normalize();
0797 if ((vc - vb).Dot(normal3) < 0) normal3 *= -1;
0798 #endif
0799 }
0800 template <typename Real_i>
0801 Arb4Data(const Arb4Data<Real_i> &other)
0802 : halfH(static_cast<Real_t>(other.halfH)), halfH_inv(static_cast<Real_t>(other.halfH_inv)),
0803 ftx1(static_cast<Real_t>(other.ftx1)), fty1(static_cast<Real_t>(other.fty1)),
0804 ftx2(static_cast<Real_t>(other.ftx2)), fty2(static_cast<Real_t>(other.fty2)),
0805 ft1crosst2(static_cast<Real_t>(other.ft1crosst2)), fDeltatx(static_cast<Real_t>(other.fDeltatx)),
0806 fDeltaty(static_cast<Real_t>(other.fDeltaty)),
0807 fViCrossHi0(Vector3D(static_cast<Real_t>(other.fViCrossHi0[0]), static_cast<Real_t>(other.fViCrossHi0[1]),
0808 static_cast<Real_t>(other.fViCrossHi0[2]))),
0809 fViCrossVj(Vector3D(static_cast<Real_t>(other.fViCrossVj[0]), static_cast<Real_t>(other.fViCrossVj[1]),
0810 static_cast<Real_t>(other.fViCrossVj[2]))),
0811 fHi1CrossHi0(Vector3D(static_cast<Real_t>(other.fHi1CrossHi0[0]), static_cast<Real_t>(other.fHi1CrossHi0[1]),
0812 static_cast<Real_t>(other.fHi1CrossHi0[2])))
0813 #ifdef SURF_ACCURATE_SAFETY
0814 ,
0815 normal0(Vector3D(static_cast<Real_t>(other.normal0[0]), static_cast<Real_t>(other.normal0[1]),
0816 static_cast<Real_t>(other.normal0[2]))),
0817 normal1(Vector3D(static_cast<Real_t>(other.normal1[0]), static_cast<Real_t>(other.normal1[1]),
0818 static_cast<Real_t>(other.normal1[2]))),
0819 normal2(Vector3D(static_cast<Real_t>(other.normal2[0]), static_cast<Real_t>(other.normal2[1]),
0820 static_cast<Real_t>(other.normal2[2]))),
0821 normal3(Vector3D(static_cast<Real_t>(other.normal3[0]), static_cast<Real_t>(other.normal3[1]),
0822 static_cast<Real_t>(other.normal3[2])))
0823
0824 #endif
0825 {
0826 for (int i = 0; i < 4; ++i) {
0827 verticesX[i] = static_cast<Real_t>(other.verticesX[i]);
0828 verticesY[i] = static_cast<Real_t>(other.verticesY[i]);
0829 }
0830
0831 for (int i = 0; i < 2; ++i) {
0832 connecting_compX[i] = static_cast<Real_t>(other.connecting_compX[i]);
0833 connecting_compY[i] = static_cast<Real_t>(other.connecting_compY[i]);
0834 }
0835 }
0836 };
0837
0838
0839
0840
0841 template <typename Real_t>
0842 struct TorusData {
0843 Real_t rTor{0};
0844 Real_t rTube{0};
0845 AngleVector<Real_t> vecSPhi{vecCore::NumericLimits<Real_t>::Max(),
0846 vecCore::NumericLimits<Real_t>::Max()};
0847
0848 AngleVector<Real_t> vecEPhi{vecCore::NumericLimits<Real_t>::Max(),
0849 vecCore::NumericLimits<Real_t>::Max()};
0850
0851 Real_t inner_BC_radius{0};
0852 Real_t outer_BC_radius{0};
0853
0854
0855
0856
0857 VECCORE_ATT_HOST_DEVICE
0858 VECGEOM_FORCE_INLINE
0859 bool InsidePhi(Vector3D<Real_t> const &local, bool flip) const
0860 {
0861 if (vecSPhi[0] >= vecgeom::InfinityLength<Real_t>() - vecgeom::kToleranceStrict<Real_t> &&
0862 vecEPhi[0] >= vecgeom::InfinityLength<Real_t>() - vecgeom::kToleranceStrict<Real_t>)
0863 return true;
0864 int flipsign = flip ? -1 : 1;
0865 AngleVector<Real_t> localAngle{local[0], local[1]};
0866 auto convex = vecSPhi.CrossZ(vecEPhi) > Real_t(0);
0867 auto in1 = vecSPhi.CrossZ(localAngle) > -flipsign * vecgeom::kToleranceStrict<Real_t>;
0868 auto in2 = localAngle.CrossZ(vecEPhi) > -flipsign * vecgeom::kToleranceStrict<Real_t>;
0869 return convex ? in1 && in2 : in1 || in2;
0870 }
0871
0872 TorusData() = default;
0873
0874 template <typename Real_i>
0875 TorusData(Real_i rad, Real_i rad_tube, Real_i sphi = Real_i{0}, Real_i ephi = Real_i{0}, bool flip = false)
0876 : rTor(static_cast<Real_t>(rad)), rTube(flip ? static_cast<Real_t>(-rad_tube) : static_cast<Real_t>(rad_tube)),
0877 vecSPhi(static_cast<Real_t>(vecgeom::Cos(sphi)), static_cast<Real_t>(vecgeom::Sin(sphi))),
0878 vecEPhi(static_cast<Real_t>(vecgeom::Cos(ephi)), static_cast<Real_t>(vecgeom::Sin(ephi))),
0879 inner_BC_radius(-(1. - rad_tube / vecgeom::NonZero(rad))),
0880 outer_BC_radius(1. + rad_tube / vecgeom::NonZero(rad))
0881 {
0882 }
0883 template <typename Real_i>
0884 TorusData(const TorusData<Real_i> &other)
0885 : rTor(static_cast<Real_t>(other.rTor)), rTube(static_cast<Real_t>(other.rTube)),
0886 vecSPhi(static_cast<Real_t>(other.vecSPhi[0]), static_cast<Real_t>(other.vecSPhi[1])),
0887 vecEPhi(static_cast<Real_t>(other.vecEPhi[0]), static_cast<Real_t>(other.vecEPhi[1])),
0888 inner_BC_radius(static_cast<Real_t>(other.inner_BC_radius)),
0889 outer_BC_radius(static_cast<Real_t>(other.outer_BC_radius))
0890 {
0891 }
0892
0893 VECCORE_ATT_HOST_DEVICE
0894 Real_t Radius() const { return std::abs(rTor); }
0895 VECCORE_ATT_HOST_DEVICE
0896 Real_t RadiusTube() const { return std::abs(rTube); }
0897 VECCORE_ATT_HOST_DEVICE
0898 VECCORE_ATT_HOST_DEVICE
0899 bool IsFlipped() const { return rTube < 0; }
0900 VECCORE_ATT_HOST_DEVICE
0901 VECGEOM_FORCE_INLINE
0902 Real_t InnerBCRadius() const { return std::abs(inner_BC_radius); }
0903 VECCORE_ATT_HOST_DEVICE
0904 VECGEOM_FORCE_INLINE
0905 Real_t OuterBCRadius() const { return std::abs(outer_BC_radius); }
0906 };
0907
0908 }
0909
0910 #endif