File indexing completed on 2025-07-11 07:50:01
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include "Acts/Utilities/BoundingBox.hpp"
0012
0013 template <typename entity_t, typename value_t, std::size_t DIM>
0014 Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::AxisAlignedBoundingBox(
0015 const entity_t* entity, const VertexType& vmin, const VertexType& vmax)
0016 : m_entity(entity),
0017 m_vmin(vmin),
0018 m_vmax(vmax),
0019 m_center((vmin + vmax) / 2.),
0020 m_width(vmax - vmin),
0021 m_iwidth(1 / m_width) {}
0022
0023 template <typename entity_t, typename value_t, std::size_t DIM>
0024 Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::AxisAlignedBoundingBox(
0025 const entity_t* entity, const VertexType& center, const Size& size)
0026 : m_entity(entity),
0027 m_vmin(center - size.get() * 0.5),
0028 m_vmax(center + size.get() * 0.5),
0029 m_center(center),
0030 m_width(size.get()),
0031 m_iwidth(1 / m_width) {}
0032
0033 template <typename entity_t, typename value_t, std::size_t DIM>
0034 Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::AxisAlignedBoundingBox(
0035 const std::vector<self_t*>& boxes, vertex_array_type envelope)
0036 : m_entity(nullptr) {
0037 assert(boxes.size() > 1);
0038
0039 for (std::size_t i = 0; i < boxes.size(); i++) {
0040 if (i < boxes.size() - 1) {
0041
0042 boxes[i]->setSkip(boxes[i + 1]);
0043 } else {
0044
0045
0046 boxes[i]->setSkip(nullptr);
0047 }
0048 }
0049
0050 m_left_child = boxes.front();
0051 m_right_child = boxes.back();
0052 m_skip = nullptr;
0053
0054 std::tie(m_vmin, m_vmax) = wrap(boxes, envelope);
0055
0056 m_center = (m_vmin + m_vmax) / 2.;
0057 m_width = m_vmax - m_vmin;
0058 m_iwidth = 1 / m_width;
0059 }
0060
0061 template <typename entity_t, typename value_t, std::size_t DIM>
0062 std::pair<
0063 typename Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::VertexType,
0064 typename Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::VertexType>
0065 Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::wrap(
0066 const std::vector<const self_t*>& boxes, vertex_array_type envelope) {
0067 assert(boxes.size() > 1);
0068
0069
0070 vertex_array_type vmax(
0071 vertex_array_type::Constant(std::numeric_limits<value_type>::lowest()));
0072 vertex_array_type vmin(
0073 vertex_array_type::Constant(std::numeric_limits<value_type>::max()));
0074
0075 for (std::size_t i = 0; i < boxes.size(); i++) {
0076 vmin = vmin.min(boxes[i]->min().array());
0077 vmax = vmax.max(boxes[i]->max().array());
0078 }
0079
0080 vmax += envelope;
0081 vmin -= envelope;
0082
0083 return {vmin, vmax};
0084 }
0085
0086 template <typename entity_t, typename value_t, std::size_t DIM>
0087 std::pair<
0088 typename Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::VertexType,
0089 typename Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::VertexType>
0090 Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::wrap(
0091 const std::vector<self_t*>& boxes, vertex_array_type envelope) {
0092 assert(boxes.size() > 1);
0093 std::vector<const self_t*> box_ptrs;
0094 box_ptrs.reserve(boxes.size());
0095 std::transform(boxes.begin(), boxes.end(), std::back_inserter(box_ptrs),
0096 [](const auto* box) { return box; });
0097 return wrap(box_ptrs, envelope);
0098 }
0099
0100 template <typename entity_t, typename value_t, std::size_t DIM>
0101 std::pair<
0102 typename Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::VertexType,
0103 typename Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::VertexType>
0104 Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::wrap(
0105 const std::vector<self_t>& boxes, vertex_array_type envelope) {
0106 assert(boxes.size() > 1);
0107 std::vector<const self_t*> box_ptrs;
0108 box_ptrs.reserve(boxes.size());
0109 std::transform(boxes.begin(), boxes.end(), std::back_inserter(box_ptrs),
0110 [](auto& box) { return &box; });
0111 return wrap(box_ptrs, envelope);
0112 }
0113
0114 template <typename entity_t, typename value_t, std::size_t DIM>
0115 bool Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::intersect(
0116 const VertexType& point) const {
0117 vertex_array_type t = (point - m_vmin).array() * m_iwidth;
0118 return t.minCoeff() >= 0 && t.maxCoeff() < 1;
0119 }
0120
0121 template <typename entity_t, typename value_t, std::size_t DIM>
0122 bool Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::intersect(
0123 const Ray<value_type, DIM>& ray) const {
0124 const VertexType& origin = ray.origin();
0125 const vertex_array_type& idir = ray.idir();
0126
0127
0128
0129
0130 vertex_array_type t0s = (m_vmin - origin).array() * idir;
0131 vertex_array_type t1s = (m_vmax - origin).array() * idir;
0132
0133
0134
0135
0136
0137
0138 vertex_array_type tsmaller = t0s.min(t1s);
0139 vertex_array_type tbigger = t0s.max(t1s);
0140
0141
0142 value_type tmin = tsmaller.maxCoeff();
0143 value_type tmax = tbigger.minCoeff();
0144
0145
0146
0147 return tmin < tmax && tmax > 0.0;
0148 }
0149
0150 template <typename entity_t, typename value_t, std::size_t DIM>
0151 template <std::size_t sides>
0152 bool Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::intersect(
0153 const Frustum<value_type, DIM, sides>& fr) const {
0154 const auto& normals = fr.normals();
0155
0156
0157 const vertex_array_type fr_vmin = m_vmin - fr.origin();
0158 const vertex_array_type fr_vmax = m_vmax - fr.origin();
0159
0160
0161
0162
0163 VertexType p_vtx;
0164
0165
0166
0167 for (std::size_t i = 0; i < sides + 1; i++) {
0168 const VertexType& normal = normals[i];
0169
0170
0171
0172 p_vtx = (normal.array() < 0).template cast<value_type>() * fr_vmin +
0173 (normal.array() >= 0).template cast<value_type>() * fr_vmax;
0174
0175
0176
0177
0178 if (p_vtx.dot(normal) < 0) {
0179
0180 return false;
0181 }
0182 }
0183
0184
0185
0186 return true;
0187 }
0188
0189 template <typename entity_t, typename value_t, std::size_t DIM>
0190 void Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::setSkip(
0191 self_t* skip) {
0192
0193 m_skip = skip;
0194
0195 if (m_right_child != nullptr) {
0196 m_right_child->setSkip(skip);
0197 }
0198 }
0199
0200 template <typename entity_t, typename value_t, std::size_t DIM>
0201 const Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>*
0202 Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::getLeftChild() const {
0203 return m_left_child;
0204 }
0205
0206 template <typename entity_t, typename value_t, std::size_t DIM>
0207 const Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>*
0208 Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::getSkip() const {
0209 return m_skip;
0210 }
0211
0212 template <typename entity_t, typename value_t, std::size_t DIM>
0213 bool Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::hasEntity() const {
0214 return m_entity != nullptr;
0215 }
0216
0217 template <typename entity_t, typename value_t, std::size_t DIM>
0218 const entity_t* Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::entity()
0219 const {
0220 return m_entity;
0221 }
0222
0223 template <typename entity_t, typename value_t, std::size_t DIM>
0224 void Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::setEntity(
0225 const entity_t* entity) {
0226 m_entity = entity;
0227 }
0228
0229 template <typename entity_t, typename value_t, std::size_t DIM>
0230 const typename Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::VertexType&
0231 Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::center() const {
0232 return m_center;
0233 }
0234
0235 template <typename entity_t, typename value_t, std::size_t DIM>
0236 const typename Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::VertexType&
0237 Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::min() const {
0238 return m_vmin;
0239 }
0240
0241 template <typename entity_t, typename value_t, std::size_t DIM>
0242 const typename Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::VertexType&
0243 Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::max() const {
0244 return m_vmax;
0245 }
0246
0247 template <typename entity_t, typename value_t, std::size_t DIM>
0248 std::ostream& Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::toStream(
0249 std::ostream& os) const {
0250 os << "AABB(ctr=(";
0251
0252 for (std::size_t i = 0; i < DIM; i++) {
0253 if (i > 0) {
0254 os << ", ";
0255 }
0256 os << m_center[i];
0257 }
0258
0259 os << ") vmin=(";
0260 for (std::size_t i = 0; i < DIM; i++) {
0261 if (i > 0) {
0262 os << ", ";
0263 }
0264 os << m_vmin[i];
0265 }
0266
0267 os << ") vmax=(";
0268
0269 for (std::size_t i = 0; i < DIM; i++) {
0270 if (i > 0) {
0271 os << ", ";
0272 }
0273 os << m_vmax[i];
0274 }
0275
0276 os << "))";
0277
0278 return os;
0279 }
0280
0281 template <typename entity_t, typename value_t, std::size_t DIM>
0282 std::pair<
0283 typename Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::VertexType,
0284 typename Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::VertexType>
0285 Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::transformVertices(
0286 const transform_type& trf) const
0287 requires(DIM == 3)
0288 {
0289
0290
0291
0292 std::array<VertexType, 8> vertices({{
0293 {m_vmin.x(), m_vmin.y(), m_vmin.z()},
0294 {m_vmin.x(), m_vmax.y(), m_vmin.z()},
0295 {m_vmax.x(), m_vmax.y(), m_vmin.z()},
0296 {m_vmax.x(), m_vmin.y(), m_vmin.z()},
0297 {m_vmin.x(), m_vmin.y(), m_vmax.z()},
0298 {m_vmin.x(), m_vmax.y(), m_vmax.z()},
0299 {m_vmax.x(), m_vmax.y(), m_vmax.z()},
0300 {m_vmax.x(), m_vmin.y(), m_vmax.z()},
0301 }});
0302
0303 VertexType vmin = trf * vertices[0];
0304 VertexType vmax = trf * vertices[0];
0305
0306 for (std::size_t i = 1; i < 8; i++) {
0307 const VertexType vtx = trf * vertices[i];
0308 vmin = vmin.cwiseMin(vtx);
0309 vmax = vmax.cwiseMax(vtx);
0310 }
0311
0312 return {vmin, vmax};
0313 }
0314
0315 template <typename entity_t, typename value_t, std::size_t DIM>
0316 std::pair<
0317 typename Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::VertexType,
0318 typename Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::VertexType>
0319 Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::transformVertices(
0320 const transform_type& trf) const
0321 requires(DIM == 2)
0322 {
0323
0324
0325
0326 std::array<VertexType, 4> vertices({{{m_vmin.x(), m_vmin.y()},
0327 {m_vmin.x(), m_vmax.y()},
0328 {m_vmax.x(), m_vmax.y()},
0329 {m_vmax.x(), m_vmin.y()}}});
0330
0331 VertexType vmin = trf * vertices[0];
0332 VertexType vmax = trf * vertices[0];
0333
0334 for (std::size_t i = 1; i < 4; i++) {
0335 const VertexType vtx = trf * vertices[i];
0336 vmin = vmin.cwiseMin(vtx);
0337 vmax = vmax.cwiseMax(vtx);
0338 }
0339
0340 return {vmin, vmax};
0341 }
0342
0343 template <typename entity_t, typename value_t, std::size_t DIM>
0344 void Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::transform(
0345 const transform_type& trf) {
0346 std::tie(m_vmin, m_vmax) = transformVertices(trf);
0347 }
0348
0349 template <typename entity_t, typename value_t, std::size_t DIM>
0350 Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>
0351 Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::transformed(
0352 const transform_type& trf) const {
0353 const auto [vmin, vmax] = transformVertices(trf);
0354 return self_t(m_entity, vmin, vmax);
0355 }
0356
0357 template <typename entity_t, typename value_t, std::size_t DIM>
0358 void Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::draw(
0359 IVisualization3D& helper, Color color, const transform_type& trf) const
0360 requires(DIM == 3)
0361 {
0362 static_assert(DIM == 3, "PLY output only supported in 3D");
0363
0364 const VertexType& vmin = m_vmin;
0365 const VertexType& vmax = m_vmax;
0366
0367 auto write = [&](const VertexType& a, const VertexType& b,
0368 const VertexType& c, const VertexType& d) {
0369 helper.face(std::vector<VertexType>({trf * a, trf * b, trf * c, trf * d}),
0370 color);
0371 };
0372
0373 write({vmin.x(), vmin.y(), vmin.z()}, {vmin.x(), vmax.y(), vmin.z()},
0374 {vmin.x(), vmax.y(), vmax.z()}, {vmin.x(), vmin.y(), vmax.z()});
0375
0376 write({vmax.x(), vmin.y(), vmin.z()}, {vmax.x(), vmax.y(), vmin.z()},
0377 {vmax.x(), vmax.y(), vmax.z()}, {vmax.x(), vmin.y(), vmax.z()});
0378
0379 write({vmin.x(), vmin.y(), vmin.z()}, {vmax.x(), vmin.y(), vmin.z()},
0380 {vmax.x(), vmin.y(), vmax.z()}, {vmin.x(), vmin.y(), vmax.z()});
0381
0382 write({vmin.x(), vmax.y(), vmin.z()}, {vmax.x(), vmax.y(), vmin.z()},
0383 {vmax.x(), vmax.y(), vmax.z()}, {vmin.x(), vmax.y(), vmax.z()});
0384
0385 write({vmin.x(), vmin.y(), vmin.z()}, {vmax.x(), vmin.y(), vmin.z()},
0386 {vmax.x(), vmax.y(), vmin.z()}, {vmin.x(), vmax.y(), vmin.z()});
0387
0388 write({vmin.x(), vmin.y(), vmax.z()}, {vmax.x(), vmin.y(), vmax.z()},
0389 {vmax.x(), vmax.y(), vmax.z()}, {vmin.x(), vmax.y(), vmax.z()});
0390 }
0391
0392 template <typename entity_t, typename value_t, std::size_t DIM>
0393 std::ostream& Acts::AxisAlignedBoundingBox<entity_t, value_t, DIM>::svg(
0394 std::ostream& os, value_type w, value_type h, value_type unit,
0395 const std::string& label, const std::string& fillcolor) const
0396 requires(DIM == 2)
0397 {
0398 static_assert(DIM == 2, "SVG is only supported in 2D");
0399
0400 VertexType mid(w / 2., h / 2.);
0401
0402 using transform_t = Eigen::Transform<value_t, DIM, Eigen::Affine>;
0403
0404 transform_t trf = transform_t::Identity();
0405 trf.translate(mid);
0406 trf = trf * Eigen::Scaling(VertexType(1, -1));
0407 trf.scale(unit);
0408
0409 auto draw_point = [&](const VertexType& p_, const std::string& color,
0410 std::size_t r) {
0411 VertexType p = trf * p_;
0412 os << "<circle ";
0413 os << "cx=\"" << p.x() << "\" cy=\"" << p.y() << "\" r=\"" << r << "\"";
0414 os << " fill=\"" << color << "\"";
0415 os << "/>\n";
0416 };
0417
0418 auto draw_rect = [&](const VertexType& center_, const VertexType& size_,
0419 const std::string& color) {
0420 VertexType size = size_ * unit;
0421 VertexType center = trf * center_ - size * 0.5;
0422
0423 os << "<rect ";
0424 os << "x=\"" << center.x() << "\" y=\"" << center.y() << "\" ";
0425 os << "width=\"" << size.x() << "\" height=\"" << size.y() << "\"";
0426 os << " fill=\"" << color << "\"";
0427 os << "/>\n";
0428 };
0429
0430 auto draw_text = [&](const VertexType& center_, const std::string& text,
0431 const std::string& color, std::size_t size) {
0432 VertexType center = trf * center_;
0433 os << "<text dominant-baseline=\"middle\" text-anchor=\"middle\" ";
0434 os << "fill=\"" << color << "\" font-size=\"" << size << "\" ";
0435 os << "x=\"" << center.x() << "\" y=\"" << center.y() << "\">";
0436 os << text << "</text>\n";
0437 };
0438
0439 draw_rect(m_center, m_width, fillcolor);
0440 draw_point(m_vmin, "black", 2);
0441 draw_point(m_vmax, "black", 2);
0442 draw_text(m_center, label, "white", 10);
0443
0444 return os;
0445 }
0446
0447 template <typename box_t>
0448 box_t* octree_inner(std::vector<std::unique_ptr<box_t>>& store,
0449 std::size_t max_depth,
0450 typename box_t::vertex_array_type envelope,
0451 const std::vector<box_t*>& lprims, std::size_t depth) {
0452 using VertexType = typename box_t::VertexType;
0453
0454 assert(!lprims.empty());
0455 if (lprims.size() == 1) {
0456
0457 return lprims.front();
0458 }
0459
0460 if (depth >= max_depth) {
0461
0462 auto bb = std::make_unique<box_t>(lprims, envelope);
0463 store.push_back(std::move(bb));
0464 return store.back().get();
0465 }
0466
0467 std::array<std::vector<box_t*>, 8> octants;
0468
0469 const auto [vmin, vmax] = box_t::wrap(lprims);
0470 VertexType glob_ctr = (vmin + vmax) / 2.;
0471
0472 for (auto* box : lprims) {
0473 VertexType ctr = box->center() - glob_ctr;
0474 if (ctr.x() < 0 && ctr.y() < 0 && ctr.z() < 0) {
0475 octants[0].push_back(box);
0476 continue;
0477 }
0478 if (ctr.x() > 0 && ctr.y() < 0 && ctr.z() < 0) {
0479 octants[1].push_back(box);
0480 continue;
0481 }
0482 if (ctr.x() < 0 && ctr.y() > 0 && ctr.z() < 0) {
0483 octants[2].push_back(box);
0484 continue;
0485 }
0486 if (ctr.x() > 0 && ctr.y() > 0 && ctr.z() < 0) {
0487 octants[3].push_back(box);
0488 continue;
0489 }
0490
0491 if (ctr.x() < 0 && ctr.y() < 0 && ctr.z() > 0) {
0492 octants[4].push_back(box);
0493 continue;
0494 }
0495 if (ctr.x() > 0 && ctr.y() < 0 && ctr.z() > 0) {
0496 octants[5].push_back(box);
0497 continue;
0498 }
0499 if (ctr.x() < 0 && ctr.y() > 0 && ctr.z() > 0) {
0500 octants[6].push_back(box);
0501 continue;
0502 }
0503 if (ctr.x() > 0 && ctr.y() > 0 && ctr.z() > 0) {
0504 octants[7].push_back(box);
0505 continue;
0506 }
0507
0508
0509 octants[0].push_back(box);
0510 }
0511
0512 std::vector<box_t*> sub_octs;
0513 for (const auto& sub_prims : octants) {
0514 if (sub_prims.size() <= 8) {
0515 if (sub_prims.empty()) {
0516
0517 } else if (sub_prims.size() == 1) {
0518 sub_octs.push_back(sub_prims.front());
0519 } else {
0520 store.push_back(std::make_unique<box_t>(sub_prims, envelope));
0521 sub_octs.push_back(store.back().get());
0522 }
0523 } else {
0524
0525 sub_octs.push_back(
0526 octree_inner(store, max_depth, envelope, sub_prims, depth + 1));
0527 }
0528 }
0529
0530 if (sub_octs.size() == 1) {
0531 return sub_octs.front();
0532 }
0533
0534 auto bb = std::make_unique<box_t>(sub_octs, envelope);
0535 store.push_back(std::move(bb));
0536 return store.back().get();
0537 }
0538
0539 template <typename box_t>
0540 box_t* Acts::make_octree(std::vector<std::unique_ptr<box_t>>& store,
0541 const std::vector<box_t*>& prims,
0542 std::size_t max_depth,
0543 typename box_t::value_type envelope1) {
0544 static_assert(box_t::dim == 3, "Octree can only be created in 3D");
0545
0546 using vertex_array_type = typename box_t::vertex_array_type;
0547
0548 vertex_array_type envelope(vertex_array_type::Constant(envelope1));
0549
0550 box_t* top = octree_inner(store, max_depth, envelope, prims, 0);
0551 return top;
0552 }
0553
0554 template <typename T, typename U, std::size_t V>
0555 std::ostream& Acts::operator<<(
0556 std::ostream& os, const Acts::AxisAlignedBoundingBox<T, U, V>& box) {
0557 return box.toStream(os);
0558 }