Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-05 08:09:28

0001 // This file is part of the Acts project.
0002 //
0003 // Copyright (C) 2018-2019 CERN for the benefit of the Acts project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
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       // set next on i to i+1
0038       boxes[i]->setSkip(boxes[i + 1]);
0039     } else {
0040       // make sure last is set to nullptr, this marks end
0041       // boxes[i]->m_next = nullptr;
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   // figure out extent of boxes
0065   // use array for Eigen coefficient wise min/max
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   // Calculate the intersect distances with the min and max planes along the ray
0124   // direction, from the ray origin. See Ch VII.5 Fig.1 in [1].
0125   // This is done in all dimensions at the same time:
0126   vertex_array_type t0s = (m_vmin - origin).array() * idir;
0127   vertex_array_type t1s = (m_vmax - origin).array() * idir;
0128 
0129   // Calculate the component wise min/max between the t0s and t1s
0130   // this is non-compliant with IEEE-754-2008, NaN gets propagated through
0131   // http://eigen.tuxfamily.org/bz/show_bug.cgi?id=564
0132   // this means that rays parallel to boundaries might not be considered
0133   // to intersect.
0134   vertex_array_type tsmaller = t0s.min(t1s);
0135   vertex_array_type tbigger = t0s.max(t1s);
0136 
0137   // extract largest and smallest component of the component wise extrema
0138   value_type tmin = tsmaller.maxCoeff();
0139   value_type tmax = tbigger.minCoeff();
0140 
0141   // If tmin is smaller than tmax and tmax is positive, then the box is in
0142   // positive ray direction, and the ray intersects the box.
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   // Transform vmin and vmax into the coordinate system, at which the frustum is
0152   // located at the coordinate origin.
0153   const vertex_array_type fr_vmin = m_vmin - fr.origin();
0154   const vertex_array_type fr_vmax = m_vmax - fr.origin();
0155 
0156   // For each plane, find the p-vertex, which is the vertex that is at the
0157   // furthest distance from the plane *along* its normal direction.
0158   // See Fig. 2 in [2].
0159   VertexType p_vtx;
0160   // for loop, we could eliminate this, probably,
0161   // but sides+1 is known at compile time, so the compiler
0162   // will most likely unroll the loop
0163   for (std::size_t i = 0; i < sides + 1; i++) {
0164     const VertexType& normal = normals[i];
0165 
0166     // for AABBs, take the component from the min vertex, if the normal
0167     // component is negative, else take the component from the max vertex.
0168     p_vtx = (normal.array() < 0).template cast<value_type>() * fr_vmin +
0169             (normal.array() >= 0).template cast<value_type>() * fr_vmax;
0170 
0171     // Check if the p-vertex is at positive or negative direction along the
0172     // If the p vertex is along negative normal direction *once*, the box is
0173     // outside the frustum, and we can terminate early.
0174     if (p_vtx.dot(normal) < 0) {
0175       // p vertex is outside on this plane, box must be outside
0176       return false;
0177     }
0178   }
0179 
0180   // If we get here, no p-vertex was outside, so box intersects or is
0181   // contained. We don't care, so report 'intersect'
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   // set next on this
0189   m_skip = skip;
0190   // find last child and set its skip
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   // we need to enumerate all the vertices, transform,
0285   // and then recalculate min and max
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   // we need to enumerate all the vertices, transform,
0318   // and then recalculate min and max
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     // just return
0451     return lprims.front();
0452   }
0453 
0454   if (depth >= max_depth) {
0455     // just wrap them all up
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   // calc center of boxes
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     // not in any quadrant (numerics probably)
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         // done
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       // recurse
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 }