File indexing completed on 2025-01-30 10:17:09
0001
0002
0003
0004
0005
0006
0007
0008 #pragma once
0009
0010 #include "corecel/math/Algorithms.hh"
0011 #include "corecel/math/NumericLimits.hh"
0012 #include "orange/OrangeData.hh"
0013 #include "orange/OrangeTypes.hh"
0014 #include "orange/transform/TransformVisitor.hh"
0015
0016 namespace celeritas
0017 {
0018 namespace detail
0019 {
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045 class OrientedBoundingZone
0046 {
0047 public:
0048
0049
0050 template<class T>
0051 using StorageItems
0052 = Collection<T, Ownership::const_reference, MemSpace::native>;
0053
0054 using FastReal3 = OrientedBoundingZoneRecord::Real3;
0055 using fast_real_type = FastReal3::value_type;
0056
0057 struct StoragePointers
0058 {
0059 StorageItems<TransformRecord> const* transforms;
0060 StorageItems<real_type> const* reals;
0061
0062 operator bool() const { return transforms && reals; }
0063 };
0064
0065
0066 public:
0067
0068 inline CELER_FUNCTION
0069 OrientedBoundingZone(OrientedBoundingZoneRecord const& obz_record,
0070 StoragePointers const& sp);
0071
0072
0073 inline CELER_FUNCTION real_type calc_safety_inside(Real3 const& pos);
0074
0075
0076 inline CELER_FUNCTION real_type calc_safety_outside(Real3 const& pos);
0077
0078
0079 inline CELER_FUNCTION SignedSense calc_sense(Real3 const& pos);
0080
0081 private:
0082
0083
0084
0085
0086 enum class BBoxType
0087 {
0088 inner,
0089 outer
0090 };
0091
0092
0093 struct OffsetPos
0094 {
0095 Real3 pos;
0096 BBoxType bbt;
0097 };
0098
0099
0100
0101 OrientedBoundingZoneRecord const& obz_record_;
0102 StoragePointers sp_;
0103
0104
0105
0106
0107 inline CELER_FUNCTION Real3 translate(Real3 const& unit_pos);
0108
0109
0110 inline CELER_FUNCTION OffsetPos apply_offset(Real3 const& trans_pos,
0111 BBoxType bbt);
0112
0113
0114 inline CELER_FUNCTION bool is_inside(OffsetPos const& off_pos);
0115
0116
0117 inline CELER_FUNCTION FastReal3 get_hw(BBoxType bbt);
0118
0119
0120 inline CELER_FUNCTION Real3 quadrant_one(Real3 const& pos);
0121
0122
0123 CELER_CONSTEXPR_FUNCTION int to_int(BBoxType bbt);
0124 };
0125
0126
0127
0128
0129
0130 CELER_FUNCTION
0131 OrientedBoundingZone::OrientedBoundingZone(
0132 OrientedBoundingZoneRecord const& obz_record, StoragePointers const& sp)
0133 : obz_record_(obz_record), sp_(sp)
0134 {
0135 CELER_EXPECT(obz_record_);
0136 CELER_EXPECT(sp_);
0137 }
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153 CELER_FUNCTION real_type
0154 OrientedBoundingZone::calc_safety_inside(Real3 const& pos)
0155 {
0156 CELER_EXPECT(this->calc_sense(pos) != SignedSense::outside);
0157
0158 auto trans_pos = this->translate(pos);
0159
0160 if (!this->is_inside(this->apply_offset(trans_pos, BBoxType::inner)))
0161 {
0162
0163 return 0;
0164 }
0165
0166
0167 auto outer_offset_pos = this->apply_offset(trans_pos, BBoxType::outer);
0168 auto outer_hw = this->get_hw(BBoxType::outer);
0169
0170 fast_real_type min_dist = numeric_limits<real_type>::infinity();
0171 for (auto ax : range(Axis::size_))
0172 {
0173 min_dist = celeritas::min(
0174 min_dist,
0175 outer_hw[int(ax)]
0176 - static_cast<fast_real_type>(
0177 outer_offset_pos.pos[celeritas::to_int(ax)]));
0178 }
0179
0180 return static_cast<real_type>(min_dist);
0181 }
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203 CELER_FUNCTION real_type
0204 OrientedBoundingZone::calc_safety_outside(Real3 const& pos)
0205 {
0206 CELER_EXPECT(this->calc_sense(pos) != SignedSense::inside);
0207
0208 auto trans_pos = this->translate(pos);
0209
0210 if (this->is_inside(this->apply_offset(trans_pos, BBoxType::outer)))
0211 {
0212
0213 return 0;
0214 }
0215
0216
0217 auto inner_offset_pos = this->apply_offset(trans_pos, BBoxType::inner);
0218 auto inner_hw = this->get_hw(BBoxType::inner);
0219
0220 fast_real_type min_squared = 0;
0221 for (auto ax : range(Axis::size_))
0222 {
0223 auto temp
0224 = celeritas::max(fast_real_type{0},
0225 static_cast<fast_real_type>(
0226 inner_offset_pos.pos[celeritas::to_int(ax)])
0227 - inner_hw[celeritas::to_int(ax)]);
0228 min_squared += ipow<2>(temp);
0229 }
0230
0231 return sqrt(min_squared);
0232 }
0233
0234
0235
0236
0237
0238
0239
0240
0241 CELER_FUNCTION SignedSense OrientedBoundingZone::calc_sense(Real3 const& pos)
0242 {
0243 auto trans_pos = this->translate(pos);
0244
0245 if (this->is_inside(this->apply_offset(trans_pos, BBoxType::inner)))
0246 {
0247 return SignedSense::inside;
0248 }
0249 else if (this->is_inside(this->apply_offset(trans_pos, BBoxType::outer)))
0250 {
0251 return SignedSense::on;
0252 }
0253 else
0254 {
0255 return SignedSense::outside;
0256 }
0257 }
0258
0259
0260
0261
0262
0263
0264
0265 CELER_FUNCTION Real3 OrientedBoundingZone::translate(Real3 const& pos)
0266 {
0267 TransformVisitor apply_transform(*sp_.transforms, *sp_.reals);
0268 auto transform_down = [&pos](auto&& t) { return t.transform_down(pos); };
0269
0270 return apply_transform(transform_down, obz_record_.transform_id);
0271 }
0272
0273
0274
0275
0276
0277
0278
0279 CELER_FUNCTION auto
0280 OrientedBoundingZone::apply_offset(Real3 const& trans_pos,
0281 BBoxType bbt) -> OffsetPos
0282 {
0283 TransformVisitor apply_transform(*sp_.transforms, *sp_.reals);
0284 auto transform_down
0285 = [&trans_pos](auto&& t) { return t.transform_down(trans_pos); };
0286
0287 return {this->quadrant_one(apply_transform(
0288 transform_down, obz_record_.offset_ids[this->to_int(bbt)])),
0289 bbt};
0290 }
0291
0292
0293
0294
0295
0296 CELER_FUNCTION bool OrientedBoundingZone::is_inside(OffsetPos const& off_pos)
0297 {
0298 auto const& half_widths = this->get_hw(off_pos.bbt);
0299
0300 for (auto ax : range(Axis::size_))
0301 {
0302 if (off_pos.pos[celeritas::to_int(ax)]
0303 > half_widths[celeritas::to_int(ax)])
0304 {
0305 return false;
0306 }
0307 }
0308
0309 return true;
0310 }
0311
0312
0313
0314
0315
0316 CELER_FUNCTION OrientedBoundingZone::FastReal3
0317 OrientedBoundingZone::get_hw(BBoxType bbt)
0318 {
0319 return obz_record_.half_widths[this->to_int(bbt)];
0320 }
0321
0322
0323
0324
0325
0326 CELER_FUNCTION Real3 OrientedBoundingZone::quadrant_one(Real3 const& pos)
0327 {
0328 Real3 temp;
0329 for (auto ax : range(Axis::size_))
0330 {
0331 temp[celeritas::to_int(ax)] = std::fabs(pos[celeritas::to_int(ax)]);
0332 }
0333 return temp;
0334 }
0335
0336
0337
0338
0339
0340 CELER_CONSTEXPR_FUNCTION int
0341 OrientedBoundingZone::to_int(OrientedBoundingZone::BBoxType bbt)
0342 {
0343 return static_cast<int>(bbt);
0344 }
0345
0346
0347 }
0348 }