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