File indexing completed on 2025-09-17 09:07:51
0001
0002
0003
0004
0005
0006
0007
0008 #pragma once
0009
0010 #include <cmath>
0011 #include <iosfwd>
0012
0013 #include "corecel/Assert.hh"
0014 #include "corecel/cont/Range.hh"
0015 #include "corecel/math/Algorithms.hh"
0016 #include "geocel/BoundingBox.hh"
0017
0018 #include "OrangeTypes.hh"
0019
0020 namespace celeritas
0021 {
0022
0023 class Translation;
0024 class Transformation;
0025
0026
0027
0028
0029
0030 template<class T>
0031 inline bool is_infinite(BoundingBox<T> const& bbox)
0032 {
0033 auto all_equal = [](Array<T, 3> const& values, T rhs) {
0034 return all_of(
0035 values.begin(), values.end(), [rhs](T lhs) { return lhs == rhs; });
0036 };
0037 constexpr T inf = numeric_limits<T>::infinity();
0038
0039 return all_equal(bbox.lower(), -inf) && all_equal(bbox.upper(), inf);
0040 }
0041
0042
0043
0044
0045
0046
0047
0048 template<class T>
0049 inline bool is_finite(BoundingBox<T> const& bbox)
0050 {
0051 CELER_EXPECT(bbox);
0052
0053 auto isinf = [](T value) { return std::isinf(value); };
0054 return !any_of(bbox.lower().begin(), bbox.lower().end(), isinf)
0055 && !any_of(bbox.upper().begin(), bbox.upper().end(), isinf);
0056 }
0057
0058
0059
0060
0061
0062
0063
0064 template<class T>
0065 inline bool is_degenerate(BoundingBox<T> const& bbox)
0066 {
0067 CELER_EXPECT(bbox);
0068
0069 auto axes = range(to_int(Axis::size_));
0070 return any_of(axes.begin(), axes.end(), [&bbox](int ax) {
0071 return bbox.lower()[ax] == bbox.upper()[ax];
0072 });
0073 }
0074
0075
0076
0077
0078
0079 template<class T>
0080 inline bool is_half_inf(BoundingBox<T> const& bbox)
0081 {
0082 auto axes = range(to_int(Axis::size_));
0083 return any_of(axes.begin(), axes.end(), [&bbox](int ax) {
0084 return std::isinf(bbox.lower()[ax]) != std::isinf(bbox.upper()[ax]);
0085 });
0086 }
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096 template<class T>
0097 inline Array<T, 3> calc_center(BoundingBox<T> const& bbox)
0098 {
0099 CELER_EXPECT(bbox);
0100 CELER_EXPECT(!is_half_inf(bbox));
0101
0102 Array<T, 3> center;
0103 for (auto ax : range(to_int(Axis::size_)))
0104 {
0105 center[ax] = (bbox.lower()[ax] + bbox.upper()[ax]) / 2;
0106 if (CELER_UNLIKELY(std::isnan(center[ax])))
0107 {
0108
0109 center[ax] = 0;
0110 }
0111 }
0112
0113 return center;
0114 }
0115
0116
0117
0118
0119
0120
0121
0122 template<class T>
0123 inline Array<T, 3> calc_half_widths(BoundingBox<T> const& bbox)
0124 {
0125 CELER_EXPECT(bbox);
0126
0127 Array<T, 3> hw;
0128 for (auto ax : range(to_int(Axis::size_)))
0129 {
0130 hw[ax] = (bbox.upper()[ax] - bbox.lower()[ax]) / 2;
0131 }
0132
0133 return hw;
0134 }
0135
0136
0137
0138
0139
0140
0141
0142 template<class T>
0143 inline T calc_surface_area(BoundingBox<T> const& bbox)
0144 {
0145 CELER_EXPECT(bbox);
0146
0147 Array<T, 3> lengths;
0148
0149 for (auto ax : range(to_int(Axis::size_)))
0150 {
0151 lengths[ax] = bbox.upper()[ax] - bbox.lower()[ax];
0152 }
0153
0154 return 2
0155 * (lengths[to_int(Axis::x)] * lengths[to_int(Axis::y)]
0156 + lengths[to_int(Axis::x)] * lengths[to_int(Axis::z)]
0157 + lengths[to_int(Axis::y)] * lengths[to_int(Axis::z)]);
0158 }
0159
0160
0161
0162
0163
0164
0165
0166 template<class T>
0167 inline T calc_volume(BoundingBox<T> const& bbox)
0168 {
0169 CELER_EXPECT(bbox);
0170
0171 T result{1};
0172
0173 for (auto ax : range(to_int(Axis::size_)))
0174 {
0175 result *= bbox.upper()[ax] - bbox.lower()[ax];
0176 }
0177
0178 return result;
0179 }
0180
0181
0182
0183
0184
0185 template<class T>
0186 inline constexpr BoundingBox<T>
0187 calc_union(BoundingBox<T> const& a, BoundingBox<T> const& b)
0188 {
0189 Array<T, 3> lower{};
0190 Array<T, 3> upper{};
0191
0192 for (auto ax : range(to_int(Axis::size_)))
0193 {
0194 lower[ax] = celeritas::min(a.lower()[ax], b.lower()[ax]);
0195 upper[ax] = celeritas::max(a.upper()[ax], b.upper()[ax]);
0196 }
0197
0198 return BoundingBox<T>::from_unchecked(lower, upper);
0199 }
0200
0201
0202
0203
0204
0205
0206
0207 template<class T>
0208 inline constexpr BoundingBox<T>
0209 calc_intersection(BoundingBox<T> const& a, BoundingBox<T> const& b)
0210 {
0211 Array<T, 3> lower{};
0212 Array<T, 3> upper{};
0213
0214 for (auto ax : range(to_int(Axis::size_)))
0215 {
0216 lower[ax] = celeritas::max(a.lower()[ax], b.lower()[ax]);
0217 upper[ax] = celeritas::min(a.upper()[ax], b.upper()[ax]);
0218 }
0219
0220 return BoundingBox<T>::from_unchecked(lower, upper);
0221 }
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232 template<class T>
0233 inline bool encloses(BoundingBox<T> const& big, BoundingBox<T> const& small)
0234 {
0235 CELER_EXPECT(big || small);
0236
0237 auto axes = range(to_int(Axis::size_));
0238 return all_of(axes.begin(), axes.end(), [&big, &small](int ax) {
0239 return big.lower()[ax] <= small.lower()[ax]
0240 && big.upper()[ax] >= small.upper()[ax];
0241 });
0242 }
0243
0244
0245
0246
0247
0248
0249
0250
0251 template<class T, class U>
0252 inline CELER_FUNCTION T calc_dist_to_inside(BoundingBox<T> const& bbox,
0253 Array<U, 3> const& pos,
0254 Array<U, 3> const& dir)
0255 {
0256 CELER_EXPECT(!is_inside(bbox, pos));
0257
0258
0259 auto out_of_bounds = [&bbox](T intersect, int ax) {
0260 return !(intersect >= bbox.lower()[ax]
0261 && intersect <= bbox.upper()[ax]);
0262 };
0263
0264
0265
0266 auto in_bounds = [&](int ax, T dist) {
0267 for (auto other_ax : range(to_int(Axis::size_)))
0268 {
0269 if (other_ax == ax)
0270 continue;
0271
0272 auto intersect
0273 = celeritas::fma<T>(dist, dir[other_ax], pos[other_ax]);
0274 if (out_of_bounds(intersect, other_ax))
0275 return false;
0276 }
0277 return true;
0278 };
0279
0280
0281 T min_dist = numeric_limits<T>::infinity();
0282 for (auto bound : range(Bound::size_))
0283 {
0284 for (auto ax : range(to_int(Axis::size_)))
0285 {
0286 if (dir[ax] == 0)
0287 {
0288
0289 continue;
0290 }
0291
0292 T dist = (bbox.point(static_cast<Bound>(bound))[ax] - pos[ax])
0293 / dir[ax];
0294 if (dist <= 0)
0295 {
0296
0297 continue;
0298 }
0299
0300 if (in_bounds(ax, dist))
0301 {
0302 min_dist = celeritas::min(min_dist, dist);
0303 }
0304 }
0305 }
0306
0307 return min_dist;
0308 }
0309
0310
0311
0312
0313
0314
0315
0316
0317
0318
0319
0320
0321 template<class T, class U = T>
0322 class BoundingBoxBumper
0323 {
0324 public:
0325
0326
0327 using TolU = Tolerance<U>;
0328 using result_type = BoundingBox<T>;
0329 using argument_type = BoundingBox<U>;
0330
0331
0332 public:
0333
0334 BoundingBoxBumper() : tol_{TolU::from_softequal()} {}
0335
0336
0337 explicit BoundingBoxBumper(TolU const& tol) : tol_{tol}
0338 {
0339 CELER_EXPECT(tol_);
0340 }
0341
0342
0343 result_type operator()(argument_type const& bbox)
0344 {
0345 Array<T, 3> lower;
0346 Array<T, 3> upper;
0347
0348 for (auto ax : range(to_int(Axis::size_)))
0349 {
0350 lower[ax] = this->bumped<-1>(bbox.lower()[ax]);
0351 upper[ax] = this->bumped<+1>(bbox.upper()[ax]);
0352 }
0353
0354 return result_type::from_unchecked(lower, upper);
0355 }
0356
0357 private:
0358 TolU tol_;
0359
0360
0361 template<int S>
0362 T bumped(U value) const
0363 {
0364 U bumped = value
0365 + S * celeritas::max(tol_.abs, tol_.rel * std::fabs(value));
0366 return std::nextafter(static_cast<T>(bumped),
0367 S * numeric_limits<T>::infinity());
0368 }
0369 };
0370
0371
0372
0373 BBox calc_transform(Translation const& tr, BBox const& a);
0374
0375 BBox calc_transform(Transformation const& tr, BBox const& a);
0376
0377
0378 template<class T>
0379 std::ostream& operator<<(std::ostream&, BoundingBox<T> const& bbox);
0380
0381
0382 }