File indexing completed on 2026-11-13 11:00:28
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef VECGEOM_VOLUMES_UTILITIES_CLIPPEDEXTENT_H_
0009 #define VECGEOM_VOLUMES_UTILITIES_CLIPPEDEXTENT_H_
0010
0011 #include "VecGeom/base/Global.h"
0012 #include "VecGeom/base/Transformation3D.h"
0013 #include "VecGeom/base/Vector3D.h"
0014
0015 namespace vecgeom {
0016
0017
0018 enum class Axis { kX = 0, kY = 1, kZ = 2 };
0019
0020
0021
0022
0023 inline int AxisIndex(Axis axis) { return static_cast<int>(axis); }
0024
0025
0026
0027
0028 inline Axis AxisFromIndex(int axis) { return static_cast<Axis>(axis); }
0029
0030
0031
0032
0033 inline const char *AxisName(Axis axis) { return axis == Axis::kX ? "x" : (axis == Axis::kY ? "y" : "z"); }
0034
0035
0036 struct ExtentInterval {
0037
0038 bool exists = false;
0039
0040 Precision min = kInfLength;
0041
0042 Precision max = -kInfLength;
0043
0044 ExtentInterval() = default;
0045
0046
0047
0048
0049 ExtentInterval(Precision min_value, Precision max_value)
0050 : exists(min_value <= max_value), min(min_value), max(max_value)
0051 {
0052 }
0053 };
0054
0055
0056 struct ClippedBox {
0057
0058 bool exists = false;
0059
0060 Vector3D<Precision> min{kInfLength, kInfLength, kInfLength};
0061
0062 Vector3D<Precision> max{-kInfLength, -kInfLength, -kInfLength};
0063
0064 ClippedBox() = default;
0065
0066
0067
0068
0069 ClippedBox(Vector3D<Precision> const &min_value, Vector3D<Precision> const &max_value)
0070 : exists(min_value.x() <= max_value.x() && min_value.y() <= max_value.y() && min_value.z() <= max_value.z()),
0071 min(min_value), max(max_value)
0072 {
0073 }
0074
0075
0076
0077
0078 ExtentInterval Interval(Axis axis) const
0079 {
0080 const int index = AxisIndex(axis);
0081 return exists ? ExtentInterval(min[index], max[index]) : ExtentInterval();
0082 }
0083
0084
0085
0086 void Include(Vector3D<Precision> const &point)
0087 {
0088 if (!exists) {
0089 min = point;
0090 max = point;
0091 exists = true;
0092 return;
0093 }
0094 for (int axis = 0; axis < 3; ++axis) {
0095 if (point[axis] < min[axis]) min[axis] = point[axis];
0096 if (point[axis] > max[axis]) max[axis] = point[axis];
0097 }
0098 }
0099
0100
0101
0102 void Include(ClippedBox const &other)
0103 {
0104 if (!other.exists) return;
0105 Include(other.min);
0106 Include(other.max);
0107 }
0108
0109
0110
0111 void Inflate(Precision margin)
0112 {
0113 if (!exists || margin <= Precision(0.)) return;
0114 min -= Vector3D<Precision>(margin);
0115 max += Vector3D<Precision>(margin);
0116 }
0117
0118
0119
0120
0121
0122 bool Contains(Vector3D<Precision> const &point, Precision tolerance = Precision(0.)) const
0123 {
0124 if (!exists) return false;
0125 return point.x() >= min.x() - tolerance && point.x() <= max.x() + tolerance && point.y() >= min.y() - tolerance &&
0126 point.y() <= max.y() + tolerance && point.z() >= min.z() - tolerance && point.z() <= max.z() + tolerance;
0127 }
0128 };
0129
0130
0131 class VoxelLimits {
0132 public:
0133
0134 VoxelLimits()
0135 {
0136 for (int axis = 0; axis < 3; ++axis) {
0137 fMin[axis] = -kInfLength;
0138 fMax[axis] = kInfLength;
0139 fLimited[axis] = false;
0140 }
0141 }
0142
0143
0144
0145
0146
0147 void AddLimit(Axis axis, Precision min_value, Precision max_value)
0148 {
0149 const int index = AxisIndex(axis);
0150 if (min_value > max_value) {
0151 fEmpty = true;
0152 return;
0153 }
0154 if (fLimited[index]) {
0155 if (min_value > fMin[index]) fMin[index] = min_value;
0156 if (max_value < fMax[index]) fMax[index] = max_value;
0157 } else {
0158 fMin[index] = min_value;
0159 fMax[index] = max_value;
0160 fLimited[index] = true;
0161 }
0162 if (fMin[index] > fMax[index]) fEmpty = true;
0163 }
0164
0165
0166
0167
0168 bool IsLimited(Axis axis) const { return fLimited[AxisIndex(axis)]; }
0169
0170
0171
0172 bool IsLimited() const { return fLimited[0] || fLimited[1] || fLimited[2]; }
0173
0174
0175
0176 bool IsEmpty() const { return fEmpty; }
0177
0178
0179
0180
0181 Precision Min(Axis axis) const { return fMin[AxisIndex(axis)]; }
0182
0183
0184
0185
0186 Precision Max(Axis axis) const { return fMax[AxisIndex(axis)]; }
0187
0188
0189
0190
0191
0192 bool Inside(Vector3D<Precision> const &point, Precision tolerance = Precision(0.)) const
0193 {
0194 if (fEmpty) return false;
0195 for (int axis = 0; axis < 3; ++axis) {
0196 if (!fLimited[axis]) continue;
0197 if (point[axis] < fMin[axis] - tolerance || point[axis] > fMax[axis] + tolerance) return false;
0198 }
0199 return true;
0200 }
0201
0202
0203
0204
0205
0206 bool ClipSegment(Vector3D<Precision> &start, Vector3D<Precision> &end) const
0207 {
0208 if (fEmpty) return false;
0209 const Vector3D<Precision> original_start = start;
0210 const Vector3D<Precision> delta = end - start;
0211 Precision tmin = 0.;
0212 Precision tmax = 1.;
0213
0214 for (int axis = 0; axis < 3; ++axis) {
0215 if (!fLimited[axis]) continue;
0216 const Precision direction = delta[axis];
0217 if (Abs(direction) <= kTolerance) {
0218 if (start[axis] < fMin[axis] || start[axis] > fMax[axis]) return false;
0219 continue;
0220 }
0221 Precision lo = (fMin[axis] - start[axis]) / direction;
0222 Precision hi = (fMax[axis] - start[axis]) / direction;
0223 if (lo > hi) {
0224 const Precision tmp = lo;
0225 lo = hi;
0226 hi = tmp;
0227 }
0228 if (lo > tmin) tmin = lo;
0229 if (hi < tmax) tmax = hi;
0230 if (tmin > tmax) return false;
0231 }
0232
0233 start = original_start + tmin * delta;
0234 end = original_start + tmax * delta;
0235 return true;
0236 }
0237
0238 private:
0239 Vector3D<Precision> fMin;
0240 Vector3D<Precision> fMax;
0241 bool fLimited[3] = {false, false, false};
0242 bool fEmpty = false;
0243 };
0244
0245
0246
0247
0248
0249
0250 inline bool IntersectBoxWithLimits(ClippedBox &box, VoxelLimits const &limits, Precision margin = Precision(0.))
0251 {
0252 if (!box.exists || limits.IsEmpty()) {
0253 box.exists = false;
0254 return false;
0255 }
0256 for (int axis = 0; axis < 3; ++axis) {
0257 const Axis clipped_axis = AxisFromIndex(axis);
0258 if (!limits.IsLimited(clipped_axis)) continue;
0259 const Precision lower = limits.Min(clipped_axis) - margin;
0260 const Precision upper = limits.Max(clipped_axis) + margin;
0261 if (box.max[axis] < lower || box.min[axis] > upper) {
0262 box.exists = false;
0263 return false;
0264 }
0265 if (box.min[axis] < lower) box.min[axis] = lower;
0266 if (box.max[axis] > upper) box.max[axis] = upper;
0267 }
0268 return box.exists;
0269 }
0270
0271
0272
0273
0274
0275
0276
0277 inline ClippedBox TransformLocalAABBToMother(Vector3D<Precision> const &local_min, Vector3D<Precision> const &local_max,
0278 Transformation3D const &transform, Precision padding = kAABBPadding)
0279 {
0280 const Vector3D<Precision> delta = local_max - local_min;
0281 ClippedBox box;
0282 for (int x = 0; x <= 1; ++x) {
0283 for (int y = 0; y <= 1; ++y) {
0284 for (int z = 0; z <= 1; ++z) {
0285 Vector3D<Precision> corner(local_min.x() + x * delta.x(), local_min.y() + y * delta.y(),
0286 local_min.z() + z * delta.z());
0287 box.Include(transform.InverseTransform(corner));
0288 }
0289 }
0290 }
0291 box.Inflate(padding);
0292 return box;
0293 }
0294
0295
0296
0297
0298
0299
0300
0301 inline ClippedBox TransformLocalAABBToMother(Vector3D<Precision> const &local_min, Vector3D<Precision> const &local_max,
0302 Transformation3D const *transform, Precision padding = kAABBPadding)
0303 {
0304 return TransformLocalAABBToMother(local_min, local_max, *transform, padding);
0305 }
0306
0307 }
0308
0309 #endif