File indexing completed on 2026-09-14 09:26:21
0001
0002
0003
0004
0005 #ifndef BOOLEANIMPLEMENTATION_H_
0006 #define BOOLEANIMPLEMENTATION_H_
0007
0008 #include "VecGeom/base/Vector3D.h"
0009 #include "VecGeom/volumes/BooleanStruct.h"
0010 #include <VecCore/VecCore>
0011
0012 namespace vecgeom {
0013
0014 VECGEOM_DEVICE_DECLARE_CONV_TEMPLATE_1v(struct, BooleanImplementation, BooleanOperation, Arg1);
0015
0016 inline namespace VECGEOM_IMPL_NAMESPACE {
0017
0018 template <BooleanOperation Op>
0019 class PlacedBooleanVolume;
0020 template <BooleanOperation Op>
0021 class UnplacedBooleanVolume;
0022
0023 template <BooleanOperation boolOp>
0024 struct BooleanImplementation {
0025 using PlacedShape_t = PlacedBooleanVolume<boolOp>;
0026 using UnplacedVolume_t = UnplacedBooleanVolume<boolOp>;
0027 using UnplacedStruct_t = BooleanStruct;
0028
0029
0030
0031 };
0032
0033
0034
0035
0036
0037
0038
0039 template <>
0040 struct BooleanImplementation<kSubtraction> {
0041 using PlacedShape_t = PlacedBooleanVolume<kSubtraction>;
0042 using UnplacedVolume_t = UnplacedBooleanVolume<kSubtraction>;
0043 using UnplacedStruct_t = BooleanStruct;
0044
0045 template <typename Real_v, typename Bool_v>
0046 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void Contains(BooleanStruct const &unplaced,
0047 Vector3D<Real_v> const &point, Bool_v &inside)
0048 {
0049 Vector3D<Real_v> tmp;
0050 inside = unplaced.fLeftVolume->Contains(point);
0051 if (vecCore::MaskEmpty(inside)) return;
0052
0053 auto rightInside = unplaced.fRightVolume->Contains(point);
0054 inside &= !rightInside;
0055 }
0056
0057 template <typename Real_v, typename Inside_t>
0058 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void Inside(BooleanStruct const &unplaced,
0059 Vector3D<Real_v> const &p, Inside_t &inside)
0060 {
0061
0062
0063
0064 VPlacedVolume const *const fPtrSolidA = unplaced.fLeftVolume;
0065 VPlacedVolume const *const fPtrSolidB = unplaced.fRightVolume;
0066
0067 const auto positionA = fPtrSolidA->Inside(p);
0068 if (positionA == EInside::kOutside) {
0069 inside = EInside::kOutside;
0070 return;
0071 }
0072
0073 const auto positionB = fPtrSolidB->Inside(p);
0074
0075 if (positionA == EInside::kInside && positionB == EInside::kOutside) {
0076 inside = EInside::kInside;
0077 return;
0078 } else {
0079 if ((positionA == EInside::kInside && positionB == EInside::kSurface) ||
0080 (positionB == EInside::kOutside && positionA == EInside::kSurface)
0081
0082
0083
0084
0085
0086 ) {
0087 inside = EInside::kSurface;
0088 return;
0089 } else {
0090 inside = EInside::kOutside;
0091 return;
0092 }
0093 }
0094
0095 }
0096
0097 template <typename Real_v>
0098 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void DistanceToIn(BooleanStruct const &unplaced,
0099 Vector3D<Real_v> const &p,
0100 Vector3D<Real_v> const &dir,
0101 Real_v const &stepMax, Real_v &distance)
0102 {
0103 Real_v dist_right, dist_left, advance = 0.;
0104 Real_v limit = stepMax;
0105 Vector3D<Real_v> hitpoint(p);
0106
0107 auto insideRight = unplaced.fRightVolume->Inside(p) != kOutside;
0108
0109 Precision epsil(0.), push(0.);
0110 while (1) {
0111 if (insideRight) {
0112
0113 dist_right = unplaced.fRightVolume->PlacedDistanceToOut(hitpoint, dir, limit);
0114 if (dist_right >= 0.) {
0115 advance += dist_right + push;
0116 limit = stepMax - advance;
0117 epsil = kRelTolerance(hitpoint + dist_right * dir);
0118
0119 hitpoint += (dist_right + epsil) * dir;
0120 push = epsil;
0121 } else {
0122 push = 0.;
0123 }
0124
0125
0126 if (unplaced.fLeftVolume->Inside(hitpoint) != kOutside) {
0127 auto check = unplaced.fLeftVolume->PlacedDistanceToOut(hitpoint, dir);
0128 if (check > epsil) {
0129 distance = advance;
0130 return;
0131 }
0132 }
0133 }
0134
0135
0136 dist_left = unplaced.fLeftVolume->DistanceToIn(hitpoint, dir, limit);
0137 dist_left = vecCore::math::Max(dist_left, 0.);
0138 if (dist_left >= limit) {
0139 distance = kInfLength;
0140 return;
0141 }
0142
0143 dist_right = unplaced.fRightVolume->DistanceToIn(hitpoint, dir, limit);
0144 if (dist_left < dist_right - kTolerance) {
0145 advance += dist_left + push;
0146 distance = advance;
0147 return;
0148 }
0149
0150
0151 if (dist_right >= 0. && dist_right < kInfLength) {
0152 advance += dist_right + push;
0153 limit = stepMax - advance;
0154 epsil = kRelTolerance(hitpoint + dist_right * dir);
0155 hitpoint += (dist_right + epsil) * dir;
0156 push = epsil;
0157 } else {
0158 push = 0.;
0159 }
0160 insideRight = true;
0161 }
0162 }
0163
0164 template <typename Real_v>
0165 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void DistanceToOut(BooleanStruct const &unplaced,
0166 Vector3D<Real_v> const &point,
0167 Vector3D<Real_v> const &direction,
0168 Real_v const &stepMax, Real_v &distance)
0169 {
0170 const auto distancel = unplaced.fLeftVolume->PlacedDistanceToOut(point, direction, stepMax);
0171 const Real_v dinright = unplaced.fRightVolume->DistanceToIn(point, direction, stepMax);
0172 distance = Min(distancel, dinright);
0173 return;
0174 }
0175
0176 template <typename Real_v>
0177 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void SafetyToIn(BooleanStruct const &unplaced,
0178 Vector3D<Real_v> const &point, Real_v &safety)
0179 {
0180 VPlacedVolume const *const fPtrSolidA = unplaced.fLeftVolume;
0181 VPlacedVolume const *const fPtrSolidB = unplaced.fRightVolume;
0182
0183
0184 if ((fPtrSolidA->Contains(point)) &&
0185 (fPtrSolidB->Contains(point))) {
0186 safety = fPtrSolidB->SafetyToOut(fPtrSolidB->GetTransformation()->Transform(point));
0187 } else {
0188
0189 safety = fPtrSolidA->SafetyToIn(point);
0190 }
0191 }
0192
0193 template <typename Real_v>
0194 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void SafetyToOut(BooleanStruct const &unplaced,
0195 Vector3D<Real_v> const &point, Real_v &safety)
0196 {
0197 const auto safetyleft = unplaced.fLeftVolume->SafetyToOut(point);
0198 const auto safetyright = unplaced.fRightVolume->SafetyToIn(point);
0199 safety = Min(safetyleft, safetyright);
0200 }
0201
0202 template <typename Real_v, typename Bool_v>
0203 VECGEOM_FORCE_INLINE VECCORE_ATT_HOST_DEVICE static void NormalKernel(BooleanStruct const &unplaced,
0204 Vector3D<Real_v> const &point,
0205 Vector3D<Real_v> &normal, Bool_v &valid)
0206 {
0207 Vector3D<Real_v> localNorm;
0208 Vector3D<Real_v> localPoint;
0209 valid = false;
0210
0211 VPlacedVolume const *const fPtrSolidA = unplaced.fLeftVolume;
0212 VPlacedVolume const *const fPtrSolidB = unplaced.fRightVolume;
0213
0214
0215 if (fPtrSolidB->Contains(point)) {
0216 fPtrSolidB->GetTransformation()->Transform(point, localPoint);
0217 valid = fPtrSolidB->Normal(localPoint, localNorm);
0218
0219 localNorm *= -1.;
0220 fPtrSolidB->GetTransformation()->InverseTransformDirection(localNorm, normal);
0221 return;
0222 }
0223
0224
0225 if (!fPtrSolidA->Contains(point)) {
0226 fPtrSolidA->GetTransformation()->Transform(point, localPoint);
0227 valid = fPtrSolidA->Normal(localPoint, localNorm);
0228 fPtrSolidA->GetTransformation()->InverseTransformDirection(localNorm, normal);
0229 return;
0230 }
0231
0232
0233 fPtrSolidA->GetTransformation()->Transform(point, localPoint);
0234 Real_v safetyA = fPtrSolidA->SafetyToOut(localPoint);
0235 Real_v safetyB = fPtrSolidB->SafetyToIn(point);
0236 Bool_v onA = safetyA < safetyB;
0237 if (vecCore::MaskFull(onA)) {
0238 valid = fPtrSolidA->Normal(localPoint, localNorm);
0239 fPtrSolidA->GetTransformation()->InverseTransformDirection(localNorm, normal);
0240 return;
0241 } else {
0242
0243 fPtrSolidB->GetTransformation()->Transform(point, localPoint);
0244 valid = fPtrSolidB->Normal(localPoint, localNorm);
0245
0246 localNorm *= -1.;
0247 fPtrSolidB->GetTransformation()->InverseTransformDirection(localNorm, normal);
0248 return;
0249 }
0250
0251
0252 return;
0253 }
0254
0255 };
0256
0257 }
0258
0259 }
0260
0261
0262 #include "BooleanUnionImplementation.h"
0263
0264
0265 #include "BooleanIntersectionImplementation.h"
0266
0267 #endif