Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-06 08:11:32

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 #include <boost/test/unit_test.hpp>
0010 
0011 #include "Acts/Definitions/Algebra.hpp"
0012 #include "Acts/Geometry/GenericCuboidVolumeBounds.hpp"
0013 #include "Acts/Geometry/Volume.hpp"
0014 #include "Acts/Tests/CommonHelpers/FloatComparisons.hpp"
0015 #include "Acts/Utilities/BoundingBox.hpp"
0016 #include "Acts/Utilities/Frustum.hpp"
0017 #include "Acts/Utilities/Ray.hpp"
0018 #include "Acts/Visualization/IVisualization3D.hpp"
0019 #include "Acts/Visualization/PlyVisualization3D.hpp"
0020 
0021 #include <algorithm>
0022 #include <array>
0023 #include <cmath>
0024 #include <cstdio>
0025 #include <filesystem>
0026 #include <fstream>
0027 #include <iostream>
0028 #include <memory>
0029 #include <set>
0030 #include <sstream>
0031 #include <string>
0032 #include <utility>
0033 #include <vector>
0034 
0035 namespace Acts::Test {
0036 
0037 struct Object {};
0038 
0039 using BoundingBoxScalar = ActsScalar;
0040 
0041 using ObjectBBox = Acts::AxisAlignedBoundingBox<Object, BoundingBoxScalar, 3>;
0042 
0043 using Vector2F = Eigen::Matrix<BoundingBoxScalar, 2, 1>;
0044 using Vector3F = Eigen::Matrix<BoundingBoxScalar, 3, 1>;
0045 using AngleAxis3F = Eigen::AngleAxis<BoundingBoxScalar>;
0046 
0047 std::filesystem::path tmp_path = []() {
0048   auto p = std::filesystem::temp_directory_path() / "acts_unit_tests";
0049   std::filesystem::create_directory(p);
0050   std::cout << "Writing test output to: " << p << std::endl;
0051   return p;
0052 }();
0053 
0054 std::ofstream tmp(const std::string& path) {
0055   return std::ofstream{(tmp_path / path).string()};
0056 }
0057 
0058 BOOST_AUTO_TEST_CASE(box_construction) {
0059   BOOST_TEST_CONTEXT("2D") {
0060     Object o;
0061     using Box = Acts::AxisAlignedBoundingBox<Object, BoundingBoxScalar, 2>;
0062     Box bb(&o, {-1, -1}, {2, 2});
0063 
0064     typename Box::transform_type rot;
0065     rot = Eigen::Rotation2D<BoundingBoxScalar>(M_PI / 7.);
0066     Box bb_rot = bb.transformed(rot);
0067 
0068     CHECK_CLOSE_ABS(bb_rot.min(), Vector2F(-1.76874, -1.33485), 1e-4);
0069     CHECK_CLOSE_ABS(bb_rot.max(), Vector2F(2.23582, 2.66971), 1e-4);
0070   }
0071 
0072   BOOST_TEST_CONTEXT("3D") {
0073     Object o;
0074     using Box = Acts::AxisAlignedBoundingBox<Object, BoundingBoxScalar, 3>;
0075     Box bb(&o, {-1, -1, -1}, {2, 2, 2});
0076 
0077     typename Box::transform_type rot;
0078     rot = AngleAxis3F(M_PI / 3., Vector3F::UnitZ());
0079     Box bb_rot = bb.transformed(rot);
0080 
0081     CHECK_CLOSE_ABS(bb_rot.min(), Vector3F(-2.23205, -1.36603, -1), 1e-4);
0082     CHECK_CLOSE_ABS(bb_rot.max(), Vector3F(1.86603, 2.73205, 2), 1e-4);
0083 
0084     rot *= AngleAxis3F(M_PI / 5., Vector3F(1, 1, 0).normalized());
0085     Box bb_rot2 = bb.transformed(rot);
0086 
0087     CHECK_CLOSE_ABS(bb_rot2.min(), Vector3F(-2.40848, -1.51816, -2.0559), 1e-4);
0088     CHECK_CLOSE_ABS(bb_rot2.max(), Vector3F(2.61021, 3.03631, 2.86491), 1e-4);
0089   }
0090 }
0091 
0092 BOOST_AUTO_TEST_CASE(intersect_points) {
0093   using VertexType = ObjectBBox::VertexType;
0094 
0095   Object o;
0096   ObjectBBox bb(&o, {0, 0, 0}, {1, 1, 1});
0097   VertexType p;
0098 
0099   p = {0.5, 0.5, 0.5};
0100   BOOST_CHECK(bb.intersect(p));
0101   p = {0.25, 0.25, 0.25};
0102   BOOST_CHECK(bb.intersect(p));
0103   p = {0.75, 0.75, 0.75};
0104   BOOST_CHECK(bb.intersect(p));
0105 
0106   // lower bound is inclusive
0107   p = {0, 0, 0};
0108   BOOST_CHECK(bb.intersect(p));
0109   // upper bound is exclusive
0110   p = {1.0, 1.0, 1.0};
0111   BOOST_CHECK(!bb.intersect(p));
0112 
0113   // some outsides
0114   p = {2, 0, 0};
0115   BOOST_CHECK(!bb.intersect(p));
0116   p = {0, 2, 0};
0117   BOOST_CHECK(!bb.intersect(p));
0118   p = {0, 0, 2};
0119   BOOST_CHECK(!bb.intersect(p));
0120   p = {2, 2, 0};
0121   BOOST_CHECK(!bb.intersect(p));
0122   p = {2, 0, 2};
0123   BOOST_CHECK(!bb.intersect(p));
0124   p = {2, 2, 2};
0125   BOOST_CHECK(!bb.intersect(p));
0126 
0127   p = {-1, 0, 0};
0128   BOOST_CHECK(!bb.intersect(p));
0129   p = {0, -1, 0};
0130   BOOST_CHECK(!bb.intersect(p));
0131   p = {0, 0, -1};
0132   BOOST_CHECK(!bb.intersect(p));
0133   p = {-1, -1, 0};
0134   BOOST_CHECK(!bb.intersect(p));
0135   p = {-1, 0, -1};
0136   BOOST_CHECK(!bb.intersect(p));
0137   p = {-1, -1, -1};
0138   BOOST_CHECK(!bb.intersect(p));
0139 }
0140 
0141 BOOST_AUTO_TEST_CASE(intersect_rays) {
0142   /* temporarily removed, fails with double precision
0143   BOOST_TEST_CONTEXT("2D") {
0144     using Box = AxisAlignedBoundingBox<Object, BoundingBoxScalar, 2>;
0145 
0146     Object o;
0147     Box bb(&o, {-1, -1}, {1, 1});
0148 
0149     // ray in positive x direction
0150 
0151     Ray<BoundingBoxScalar, 2> ray({-2, 0}, {1, 0});
0152     BOOST_CHECK(bb.intersect(ray));
0153 
0154     ray = {{-2, 2}, {1, 0}};
0155     BOOST_CHECK(!bb.intersect(ray));
0156 
0157     ray = {{-2, -2}, {1, 0}};
0158     BOOST_CHECK(!bb.intersect(ray));
0159 
0160     // upper bound is exclusive
0161     ray = {{-2, 1}, {1, 0}};
0162     BOOST_CHECK(!bb.intersect(ray));
0163 
0164     // lower bound is inclusive
0165     ray = {{-2, -1}, {1, 0}};
0166     BOOST_CHECK(bb.intersect(ray));
0167 
0168     // ray faces away from box
0169     ray = {{2, 0}, {1, 0}};
0170     BOOST_CHECK(!bb.intersect(ray));
0171 
0172     // ray in negative x direction
0173 
0174     ray = {{2, 0}, {-1, 0}};
0175     BOOST_CHECK(bb.intersect(ray));
0176 
0177     ray = {{2, 2}, {-1, 0}};
0178     BOOST_CHECK(!bb.intersect(ray));
0179 
0180     ray = {{2, -2}, {-1, 0}};
0181     BOOST_CHECK(!bb.intersect(ray));
0182 
0183     // upper bound is exclusive
0184     ray = {{2, 1}, {-1, 0}};
0185     BOOST_CHECK(!bb.intersect(ray));
0186 
0187     // lower bound is inclusive
0188     ray = {{2, -1}, {-1, 0}};
0189     BOOST_CHECK(bb.intersect(ray));
0190 
0191     // ray in positive y direction
0192 
0193     ray = {{0, -2}, {0, 1}};
0194     BOOST_CHECK(bb.intersect(ray));
0195 
0196     ray = {{2, -2}, {0, 1}};
0197     BOOST_CHECK(!bb.intersect(ray));
0198 
0199     ray = {{-2, -2}, {0, 1}};
0200     BOOST_CHECK(!bb.intersect(ray));
0201 
0202     // upper bound is exclusive
0203     ray = {{1, -2}, {0, 1}};
0204     BOOST_CHECK(!bb.intersect(ray));
0205 
0206     // lower bound is not inclusive,
0207     // due to Eigen's NaN handling.
0208     ray = {{-1, -2}, {0, 1}};
0209     BOOST_CHECK(!bb.intersect(ray));
0210 
0211     // other direction
0212     ray = {{0, -2}, {0, -1}};
0213     BOOST_CHECK(!bb.intersect(ray));
0214 
0215     // ray in positive y direction
0216 
0217     ray = {{0, 2}, {0, -1}};
0218     BOOST_CHECK(bb.intersect(ray));
0219 
0220     ray = {{2, 2}, {0, -1}};
0221     BOOST_CHECK(!bb.intersect(ray));
0222 
0223     ray = {{-2, 2}, {0, -1}};
0224     BOOST_CHECK(!bb.intersect(ray));
0225 
0226     // upper bound is exclusive
0227     ray = {{1, 2}, {0, -1}};
0228     BOOST_CHECK(!bb.intersect(ray));
0229 
0230     // lower bound is not inclusive,
0231     // due to Eigen's NaN handling.
0232     ray = {{-1, 2}, {0, -1}};
0233     BOOST_CHECK(!bb.intersect(ray));
0234 
0235     // other direction
0236     ray = {{0, 2}, {0, 1}};
0237     BOOST_CHECK(!bb.intersect(ray));
0238 
0239     // some off axis rays
0240 
0241     ray = {{-2, 0}, {0.5, 0.25}};
0242     BOOST_CHECK(bb.intersect(ray));
0243 
0244     ray = {{-2, 0}, {0.5, 0.4}};
0245     BOOST_CHECK(bb.intersect(ray));
0246 
0247     ray = {{-2, 0}, {0.5, 0.6}};
0248     BOOST_CHECK(!bb.intersect(ray));
0249 
0250     ray = {{-2, 0}, {0.5, 0.1}};
0251     BOOST_CHECK(bb.intersect(ray));
0252 
0253     ray = {{-2, 0}, {0.5, -0.4}};
0254     BOOST_CHECK(bb.intersect(ray));
0255 
0256     ray = {{-2, 0}, {0.5, -0.6}};
0257     BOOST_CHECK(!bb.intersect(ray));
0258 
0259     ray = {{-2, 0}, {0.1, 0.5}};
0260     BOOST_CHECK(!bb.intersect(ray));
0261 
0262     // starting point inside
0263     ray = {{
0264                0,
0265                0,
0266            },
0267            {-1, 0}};
0268     BOOST_CHECK(bb.intersect(ray));
0269     ray = {{
0270                0,
0271                0,
0272            },
0273            {1, 0}};
0274     BOOST_CHECK(bb.intersect(ray));
0275     ray = {{
0276                0,
0277                0,
0278            },
0279            {0, -1}};
0280     BOOST_CHECK(bb.intersect(ray));
0281     ray = {{
0282                0,
0283                0,
0284            },
0285            {0, 1}};
0286     BOOST_CHECK(bb.intersect(ray));
0287   } */
0288 
0289   BOOST_TEST_CONTEXT("3D visualize") {
0290     Object o;
0291 
0292     // let's make sure it also works in 3d
0293     ObjectBBox bb3(&o, {-1, -1, -1}, {1, 1, 1});
0294     Ray<BoundingBoxScalar, 3> ray3({0, 0, -2}, {0, 0, 1});
0295     BOOST_CHECK(bb3.intersect(ray3));
0296 
0297     PlyVisualization3D<BoundingBoxScalar> ply;
0298 
0299     ray3.draw(ply);
0300     auto os = tmp("ray3d.ply");
0301     os << ply << std::flush;
0302     os.close();
0303   }
0304 
0305   BOOST_TEST_CONTEXT("3D") {
0306     using VertexType3 = ObjectBBox::VertexType;
0307     Object o;
0308 
0309     // let's make sure it also works in 3d
0310     ObjectBBox bb3(&o, {-1, -1, -1}, {1, 1, 1});
0311     Ray<BoundingBoxScalar, 3> ray3({0, 0, -2}, {0, 0, 1});
0312     BOOST_CHECK(bb3.intersect(ray3));
0313 
0314     // facing away from box
0315     ray3 = {{0, 0, -2}, {0, 0, -1}};
0316     BOOST_CHECK(!bb3.intersect(ray3));
0317 
0318     ray3 = {{0, 2, -2}, {0, 0, 1}};
0319     BOOST_CHECK(!bb3.intersect(ray3));
0320 
0321     ray3 = {{0, -2, -2}, {0, 0, 1}};
0322     BOOST_CHECK(!bb3.intersect(ray3));
0323 
0324     // right on slab - temporarily removed, fails with double precision
0325     // ray3 = {{0, 1, -2}, {0, 0, 1}};
0326     // BOOST_CHECK(!bb3.intersect(ray3));
0327 
0328     // right on slab - temporarily removed, fails with double precision
0329     // ray3 = {{0, -1, -2}, {0, 0, 1}};
0330     // BOOST_CHECK(bb3.intersect(ray3));
0331 
0332     // right on slab
0333     ray3 = {{-1, 0, -2}, {0, 0, 1}};
0334     BOOST_CHECK(!bb3.intersect(ray3));
0335 
0336     // right on slab - temporarily removed, fails with double precision
0337     // ray3 = {{1, 0, -2}, {0, 0, 1}};
0338     // BOOST_CHECK(!bb3.intersect(ray3));
0339 
0340     ray3 = {{-0.95, 0, -2}, {0, 0, 1}};
0341     BOOST_CHECK(bb3.intersect(ray3));
0342 
0343     // some off-axis rays
0344     ObjectBBox::VertexType p(0, 0, -2);
0345 
0346     ray3 = {p, VertexType3(1, 1, 1) - p};
0347     BOOST_CHECK(bb3.intersect(ray3));
0348 
0349     ray3 = {p, VertexType3(-1, 1, 1) - p};
0350     BOOST_CHECK(bb3.intersect(ray3));
0351 
0352     ray3 = {p, VertexType3(-1, -1, 1) - p};
0353     BOOST_CHECK(bb3.intersect(ray3));
0354 
0355     ray3 = {p, VertexType3(1, -1, 1) - p};
0356     BOOST_CHECK(bb3.intersect(ray3));
0357 
0358     ray3 = {p, VertexType3(1.1, 0, -1) - p};
0359     BOOST_CHECK(!bb3.intersect(ray3));
0360 
0361     ray3 = {p, VertexType3(-1.1, 0, -1) - p};
0362     BOOST_CHECK(!bb3.intersect(ray3));
0363 
0364     ray3 = {p, VertexType3(0, 1.1, -1) - p};
0365     BOOST_CHECK(!bb3.intersect(ray3));
0366 
0367     ray3 = {p, VertexType3(0, -1.1, -1) - p};
0368     BOOST_CHECK(!bb3.intersect(ray3));
0369 
0370     ray3 = {p, VertexType3(0.9, 0, -1) - p};
0371     BOOST_CHECK(bb3.intersect(ray3));
0372 
0373     ray3 = {p, VertexType3(-0.9, 0, -1) - p};
0374     BOOST_CHECK(bb3.intersect(ray3));
0375 
0376     ray3 = {p, VertexType3(0, 0.9, -1) - p};
0377     BOOST_CHECK(bb3.intersect(ray3));
0378 
0379     ray3 = {p, VertexType3(0, -0.9, -1) - p};
0380     BOOST_CHECK(bb3.intersect(ray3));
0381 
0382     ray3 = {{0, 0, 0}, {1, 0, 0}};
0383     BOOST_CHECK(bb3.intersect(ray3));
0384     ray3 = {{0, 0, 0}, {0, 1, 0}};
0385     BOOST_CHECK(bb3.intersect(ray3));
0386     ray3 = {{0, 0, 0}, {0, 0, 1}};
0387     BOOST_CHECK(bb3.intersect(ray3));
0388 
0389     ray3 = {{0, 0, 0}, {-1, 0, 0}};
0390     BOOST_CHECK(bb3.intersect(ray3));
0391     ray3 = {{0, 0, 0}, {0, -1, 0}};
0392     BOOST_CHECK(bb3.intersect(ray3));
0393     ray3 = {{0, 0, 0}, {0, 0, -1}};
0394     BOOST_CHECK(bb3.intersect(ray3));
0395   }
0396 }  // namespace Test
0397 
0398 BOOST_AUTO_TEST_CASE(ray_obb_intersect) {
0399   using Ray = Ray<double, 3>;
0400 
0401   std::array<Vector3, 8> vertices;
0402   vertices = {{{0, 0, 0},
0403                {2, 0, 0.4},
0404                {2, 1, 0.4},
0405                {0, 1, 0},
0406                {0, 0, 1},
0407                {1.8, 0, 1},
0408                {1.8, 1, 1},
0409                {0, 1, 1}}};
0410   auto cubo = std::make_shared<GenericCuboidVolumeBounds>(vertices);
0411   auto trf = Transform3(Translation3(Vector3(0, 8, -5)) *
0412                         AngleAxis3(M_PI / 3., Vector3(1, -3, 9).normalized()));
0413 
0414   Volume vol(trf, cubo);
0415 
0416   PlyVisualization3D<double> ply;
0417 
0418   Transform3 trl = Transform3::Identity();
0419   trl.translation() = trf.translation();
0420 
0421   cubo->draw(ply);
0422 
0423   auto obb = vol.orientedBoundingBox();
0424   obb.draw(ply, {200, 0, 0});
0425 
0426   ply.clear();
0427 
0428   Vector3 origin(10, -20, 6);
0429   Vector3 centroid(0., 0., 0.);
0430 
0431   for (const auto& vtx_ : vertices) {
0432     Vector3 vtx = trf * vtx_;
0433     centroid += vtx;
0434   }
0435 
0436   // approximately the centroid
0437   centroid *= 0.125;
0438 
0439   // shoot rays to the corner points of the cuboid
0440   for (const auto& vtx_ : vertices) {
0441     Vector3 vtx = trf * vtx_;
0442 
0443     // this ray goes straight to the actual vertex, this should
0444     // definitely intersect the OBB
0445     Ray ray(origin, (vtx - origin).normalized());
0446     ray = ray.transformed(trf.inverse());
0447     BOOST_CHECK(obb.intersect(ray));
0448     ray.draw(ply, (vtx - origin).norm());
0449 
0450     // now shift the target point away from the centroid
0451     // this should definitely NOT intersect the OBB
0452     vtx += (vtx - centroid);
0453     ray = Ray(origin, (vtx - origin).normalized());
0454     ray = ray.transformed(trf.inverse());
0455     BOOST_CHECK(!obb.intersect(ray));
0456     ray.draw(ply, (vtx - origin).norm());
0457   }
0458 }
0459 
0460 BOOST_AUTO_TEST_CASE(frustum_intersect) {
0461   BOOST_TEST_CONTEXT("2D") {
0462     auto make_svg = [](const std::string& fname, std::size_t w, std::size_t h) {
0463       auto os = tmp(fname);
0464       os << "<?xml version=\"1.0\" standalone=\"no\"?>\n";
0465       os << "<svg width=\"" << w << "\" height=\"" << h
0466          << "\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n";
0467       return os;
0468     };
0469 
0470     using Frustum2 = Frustum<BoundingBoxScalar, 2, 2>;
0471 
0472     std::ofstream os;
0473 
0474     std::size_t w = 1000;
0475     std::size_t n = 10;
0476 
0477     // BEGIN VISUAL PARAMETER TEST
0478 
0479     // BoundingBoxScalar  min = -20, max = 20;
0480     // os = make_svg("frust2d.svg", w, w);
0481 
0482     // BoundingBoxScalar  step = (max - min) / BoundingBoxScalar(n);
0483     // for (std::size_t i = 0; i <= n; i++) {
0484     // for (std::size_t j = 0; j <= n; j++) {
0485     // ActsVector<BoundingBoxScalar,2> dir    = {1, 0};
0486     // ActsVector<BoundingBoxScalar,2> origin = {min + step * i, min + step *
0487     // j}; origin.x() *= 1.10;  // visual Eigen::Rotation2D<BoundingBoxScalar>
0488     // rot(2 * M_PI / BoundingBoxScalar(n) * i); BoundingBoxScalar angle = 0.5 *
0489     // M_PI / n * j; Frustum2                 fr(origin, rot * dir, angle);
0490     // fr.svg(os, w, w, 2);
0491     //}
0492     //}
0493 
0494     // os << "</svg>";
0495     // os.close();
0496 
0497     // END VISUAL PARAMETER TEST
0498 
0499     w = 1000;
0500     BoundingBoxScalar unit = 20;
0501 
0502     using Box = AxisAlignedBoundingBox<Object, BoundingBoxScalar, 2>;
0503     Object o;
0504     Box::Size size(Eigen::Matrix<BoundingBoxScalar, 2, 1>(2, 2));
0505 
0506     n = 10;
0507     BoundingBoxScalar minx = -20;
0508     BoundingBoxScalar miny = -20;
0509     BoundingBoxScalar maxx = 20;
0510     BoundingBoxScalar maxy = 20;
0511     BoundingBoxScalar stepx = (maxx - minx) / BoundingBoxScalar(n);
0512     BoundingBoxScalar stepy = (maxy - miny) / BoundingBoxScalar(n);
0513 
0514     std::set<std::size_t> act_idxs;
0515 
0516     // clang-format off
0517     std::vector<std::pair<Frustum2, std::set<std::size_t>>> fr_exp;
0518     fr_exp = {
0519         {Frustum2({0, 0}, {1, 0}, M_PI / 2.),
0520          {60,  70,  71,  72,  80,  81,  82,  83,  84,  90,  91,  92,
0521           93,  94,  95,  96,  100, 101, 102, 103, 104, 105, 106, 107,
0522           108, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120}
0523         },
0524         {Frustum2({0, 0}, {1, 0}, 0.5 * M_PI / 2.),
0525          {60,  71,  81,  82,  83,  92,  93,  94, 102,
0526           103, 104, 105, 106, 113, 114, 115, 116, 117}
0527         },
0528         {Frustum2({0, 0}, {1, 0}, 0.2 * M_PI / 2.),
0529          {60, 71, 82, 93, 104, 114, 115, 116}
0530         },
0531         {Frustum2({0, 0}, {1, 0},  3 * M_PI / 4.),
0532          {60, 68, 69, 70, 71, 72, 73, 74, 77, 78, 79, 80, 81, 82, 83,
0533           84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98,
0534           99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
0535           112, 113, 114, 115, 116, 117, 118, 119, 120}
0536         },
0537         {Frustum2({0, 0}, {0, 1}, 0.5 * M_PI / 2.),
0538          {42, 43, 51, 52, 53, 54, 60, 61, 62, 63, 64, 65, 73, 74, 75, 76, 86, 87}
0539         },
0540         {Frustum2({0, 0}, {-1, 0}, 0.5 * M_PI / 2.),
0541          {3, 4, 5, 6, 7, 14, 15, 16, 17, 18, 26, 27, 28, 37, 38, 39, 49, 60}
0542         },
0543         {Frustum2({0, 0}, {0, -1}, 0.5 * M_PI / 2.),
0544          {33, 34, 44, 45, 46, 47, 55, 56, 57, 58, 59, 60, 66, 67, 68, 69, 77, 78}
0545         },
0546         {Frustum2({0, 0}, {1, 1}, 0.5 * M_PI / 2.),
0547          {60, 72, 73, 74, 83, 84, 85, 86, 87, 94, 95, 96, 97, 98, 106, 107,
0548           108, 109, 117, 118, 119, 120}
0549         },
0550         {Frustum2({0, 0}, {-1, 1}, 0.5 * M_PI / 2.),
0551          {7, 8, 9, 10, 18, 19, 20, 21, 28, 29, 30, 31, 32, 39, 40, 41, 42,
0552           43, 50, 51, 52, 60}
0553         },
0554         {Frustum2({0, 0}, {-1, -1}, 0.5 * M_PI / 2.),
0555          {0, 1, 2, 3, 11, 12, 13, 14, 22, 23, 24, 25, 26, 33, 34, 35, 36,
0556           37, 46, 47, 48, 60}
0557         },
0558         {Frustum2({0, 0}, {1, -1}, 0.5 * M_PI / 2.),
0559          {60, 68, 69, 70, 77, 78, 79, 80, 81, 88, 89, 90, 91, 92, 99, 100,
0560           101, 102, 110, 111, 112, 113}
0561         },
0562         {Frustum2({1, 1}, {1, -1}, M_PI / 2.),
0563          {55, 56, 57, 58, 59, 60, 66, 67, 68, 69, 70, 71, 77, 78, 79, 80,
0564           81, 82, 88, 89, 90, 91, 92, 93, 99, 100, 101, 102, 103, 104, 110, 111, 112, 113, 114, 115}
0565         },
0566         {Frustum2({-1, -1}, {1, -1}, M_PI / 2.),
0567          {55, 56, 57, 58, 59, 60, 66, 67, 68, 69, 70, 71, 77, 78, 79, 80,
0568           81, 82, 88, 89, 90, 91, 92, 93, 99, 100, 101, 102, 103, 104, 110, 111, 112, 113, 114, 115}
0569         },
0570         {Frustum2({10, -10}, {1, 1}, 0.5 * M_PI / 2.),
0571          {91, 92, 102, 103, 104, 105, 114, 115, 116, 117, 118, 119}
0572         },
0573         {Frustum2({-10.3, 12.8}, {0.3, -1}, 0.5 * M_PI / 2.),
0574          {22, 23, 24, 25, 26, 27, 28, 33, 34, 35, 36, 37, 38, 39, 40, 41,
0575           44, 45, 46, 47, 48, 49, 50, 55, 56, 57, 58, 59, 60, 66, 67, 68,
0576           69, 70, 77, 78, 79, 80, 88, 89, 99}
0577         },
0578         {Frustum2({17.2, 19.45}, {-1, -0.1}, 0.5 * M_PI / 2.),
0579          {5, 6, 7, 8, 9, 10, 17, 18, 19, 20, 21, 28, 29, 30, 31, 32, 40,
0580           41, 42, 43, 51, 52, 53, 54, 63, 64, 65, 74, 75, 76, 86, 87, 97,
0581           98, 109}
0582         },
0583     };
0584     // clang-format on
0585 
0586     for (std::size_t l = 0; l < fr_exp.size(); l++) {
0587       const Frustum2& fr = fr_exp.at(l).first;
0588       const std::set<std::size_t>& exp_idxs = fr_exp.at(l).second;
0589       std::stringstream ss;
0590       ss << "frust2d_test_" << l << ".svg";
0591       os = make_svg(ss.str(), w, w);
0592 
0593       act_idxs.clear();
0594 
0595       std::vector<Box> boxes;
0596       boxes.reserve((n + 1) * (n + 1));
0597       for (std::size_t i = 0; i <= n; i++) {
0598         for (std::size_t j = 0; j <= n; j++) {
0599           boxes.emplace_back(&o,
0600                              Eigen::Matrix<BoundingBoxScalar, 2, 1>{
0601                                  minx + i * stepx, miny + j * stepy},
0602                              size);
0603           std::stringstream st;
0604           st << boxes.size() - 1;
0605 
0606           std::string color = "red";
0607           if (boxes.back().intersect(fr)) {
0608             color = "green";
0609             act_idxs.insert(boxes.size() - 1);
0610           }
0611 
0612           boxes.back().svg(os, w, w, unit, st.str(), color);
0613         }
0614       }
0615 
0616       BOOST_CHECK(act_idxs == exp_idxs);
0617 
0618       fr.svg(os, w, w, maxx, unit);
0619       os << "</svg>";
0620 
0621       os.close();
0622     }
0623   }
0624 
0625   PlyVisualization3D<BoundingBoxScalar> helper;
0626   BOOST_TEST_CONTEXT("3D - 3 Sides") {
0627     using Frustum3 = Frustum<BoundingBoxScalar, 3, 3>;
0628     std::ofstream os;
0629     std::size_t n = 10;
0630     std::size_t s = 5;
0631     double min = -10, max = 10;
0632     double step = (max - min) / double(s);
0633 
0634     // BEGIN VISUAL PARAMETER TEST
0635 
0636     // std::size_t n_vtx   = 1;
0637     // auto make = [&](double angle, ActsVector<BoundingBoxScalar,3> origin,
0638     // std::ofstream& os)
0639     // {
0640     // helper.clear();
0641     // BoundingBoxScalar    far = 1;
0642     // Frustum3 fr(origin, {0, 0, 1}, angle);
0643     // fr.draw(helper, far);
0644     // fr = Frustum3(origin, {0, 0, -1}, angle);
0645     // fr.draw(helper, far);
0646     // fr = Frustum3(origin, {1, 0, 0}, angle);
0647     // fr.draw(helper, far);
0648     // fr = Frustum3(origin, {-1, 0, 0}, angle);
0649     // fr.draw(helper, far);
0650 
0651     // fr = Frustum3(origin, {0, 1, 0}, angle);
0652     // fr.draw(helper, far);
0653     // fr = Frustum3(origin, {0, -1, 0}, angle);
0654     // fr.draw(helper, far);
0655 
0656     // os << helper << std::flush;
0657 
0658     // helper.clear();
0659     //};
0660 
0661     // os = std::ofstreams("frust3d_dir.ply");
0662     // for (std::size_t i = 0; i <= s; i++) {
0663     // for (std::size_t j = 0; j <= s; j++) {
0664     // for (std::size_t k = 0; k <= s; k++) {
0665     // ActsVector<BoundingBoxScalar,3> origin(
0666     // min + i * step, min + j * step, min + k * step);
0667     //// std::cout << origin.transpose() << std::endl;
0668     // make(M_PI / 4., origin, os);
0669     //}
0670     //}
0671     //}
0672     // os.close();
0673 
0674     // os = tmp("frust3D_angle.ply");
0675     // helper.clear();
0676     // n_vtx             = 1;
0677     // Eigen::Affine3f rot;
0678     // for (std::size_t i = 0; i <= n; i++) {
0679     // ActsVector<BoundingBoxScalar,3> origin(i * 4, 0, 0);
0680     // rot = Eigen::AngleAxisf(M_PI / BoundingBoxScalar(n) * i,
0681     // ActsVector<BoundingBoxScalar,3>::UnitY()); BoundingBoxScalar angle =
0682     // (M_PI / 2.) / BoundingBoxScalar(n) * (1 + i);
0683     // ActsVector<BoundingBoxScalar,3> dir(1, 0, 0); Frustum3 fr(origin, rot *
0684     // dir, angle); fr.draw(helper, 2);
0685     //}
0686 
0687     // os << helper << std::flush;
0688     // os.close();
0689 
0690     //// END VISUAL PARAMETER TEST
0691 
0692     std::set<std::size_t> act_idxs;
0693 
0694     std::vector<std::pair<Frustum3, std::set<std::size_t>>> fr_exp;
0695     fr_exp = {
0696         {Frustum3({0, 0, 0}, {1, 0, 0}, M_PI / 2.),
0697          {
0698              665,  763,  774,  775,  785,  786,  787,  788,  796,  797,  807,
0699              872,  873,  883,  884,  885,  886,  894,  895,  896,  897,  898,
0700              905,  906,  907,  908,  909,  910,  911,  916,  917,  918,  919,
0701              920,  927,  928,  929,  930,  938,  939,  970,  971,  981,  982,
0702              983,  992,  993,  994,  995,  996,  1003, 1004, 1005, 1006, 1007,
0703              1008, 1009, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1025,
0704              1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1036, 1037, 1038,
0705              1039, 1040, 1041, 1042, 1043, 1047, 1048, 1049, 1050, 1051, 1052,
0706              1053, 1058, 1059, 1060, 1061, 1062, 1069, 1070, 1071, 1080, 1081,
0707              1090, 1091, 1092, 1093, 1094, 1101, 1102, 1103, 1104, 1105, 1106,
0708              1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1123, 1124, 1125,
0709              1126, 1127, 1128, 1129, 1130, 1131, 1132, 1134, 1135, 1136, 1137,
0710              1138, 1139, 1140, 1141, 1142, 1143, 1145, 1146, 1147, 1148, 1149,
0711              1150, 1151, 1152, 1153, 1154, 1156, 1157, 1158, 1159, 1160, 1161,
0712              1162, 1163, 1164, 1165, 1167, 1168, 1169, 1170, 1171, 1172, 1173,
0713              1174, 1175, 1176, 1178, 1179, 1180, 1181, 1182, 1183, 1184, 1185,
0714              1189, 1190, 1191, 1192, 1193, 1194, 1200, 1201, 1202, 1203, 1204,
0715              1210, 1211, 1212, 1213, 1214, 1215, 1216, 1217, 1221, 1222, 1223,
0716              1224, 1225, 1226, 1227, 1228, 1229, 1232, 1233, 1234, 1235, 1236,
0717              1237, 1238, 1239, 1240, 1241, 1242, 1243, 1244, 1245, 1246, 1247,
0718              1248, 1249, 1250, 1251, 1252, 1253, 1254, 1255, 1256, 1257, 1258,
0719              1259, 1260, 1261, 1262, 1263, 1264, 1265, 1266, 1267, 1268, 1269,
0720              1270, 1271, 1272, 1273, 1274, 1275, 1276, 1277, 1278, 1279, 1280,
0721              1281, 1282, 1283, 1284, 1285, 1286, 1287, 1288, 1289, 1290, 1291,
0722              1292, 1293, 1294, 1295, 1296, 1297, 1298, 1299, 1300, 1301, 1302,
0723              1303, 1304, 1305, 1306, 1307, 1308, 1309, 1310, 1311, 1312, 1313,
0724              1314, 1315, 1316, 1317, 1320, 1321, 1322, 1323, 1324, 1325, 1326,
0725              1327,
0726          }},
0727         {Frustum3({0, 0, 0}, {0, 1, 0}, M_PI / 2.),
0728          {93,   102,  103,  104,  105,  106,  112,  113,  114,  115,  116,
0729           117,  118,  203,  213,  214,  215,  223,  224,  225,  226,  227,
0730           233,  234,  235,  236,  237,  238,  239,  324,  333,  334,  335,
0731           336,  337,  343,  344,  345,  346,  347,  348,  349,  353,  354,
0732           355,  356,  357,  358,  359,  360,  361,  434,  444,  445,  446,
0733           454,  455,  456,  457,  458,  464,  465,  466,  467,  468,  469,
0734           470,  473,  474,  475,  476,  477,  478,  479,  480,  481,  482,
0735           483,  555,  564,  565,  566,  567,  568,  574,  575,  576,  577,
0736           578,  579,  580,  584,  585,  586,  587,  588,  589,  590,  591,
0737           592,  594,  595,  596,  597,  598,  599,  600,  601,  602,  603,
0738           604,  665,  675,  676,  677,  685,  686,  687,  688,  689,  695,
0739           696,  697,  698,  699,  700,  701,  704,  705,  706,  707,  708,
0740           709,  710,  711,  712,  713,  714,  715,  716,  717,  718,  719,
0741           720,  721,  722,  723,  724,  725,  795,  796,  797,  798,  799,
0742           805,  806,  807,  808,  809,  810,  811,  815,  816,  817,  818,
0743           819,  820,  821,  822,  823,  825,  826,  827,  828,  829,  830,
0744           831,  832,  833,  834,  835,  836,  837,  838,  839,  840,  841,
0745           842,  843,  844,  845,  846,  926,  927,  928,  929,  930,  931,
0746           932,  935,  936,  937,  938,  939,  940,  941,  942,  943,  944,
0747           945,  946,  947,  948,  949,  950,  951,  952,  953,  954,  955,
0748           956,  957,  958,  959,  960,  961,  962,  963,  964,  965,  966,
0749           967,  1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065,
0750           1066, 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076,
0751           1077, 1078, 1079, 1080, 1081, 1082, 1083, 1084, 1085, 1086, 1087,
0752           1088, 1188, 1189, 1190, 1191, 1192, 1193, 1194, 1195, 1196, 1197,
0753           1198, 1199, 1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208,
0754           1209, 1320, 1321, 1322, 1323, 1324, 1325, 1326, 1327, 1328, 1329,
0755           1330}},
0756         {Frustum3({0, 0, 0}, {0, 0, 1}, M_PI / 2.),
0757          {32,   42,   43,   53,   54,   63,   64,   65,   75,   76,   86,
0758           87,   98,   153,  163,  164,  173,  174,  175,  183,  184,  185,
0759           186,  195,  196,  197,  207,  208,  219,  263,  273,  274,  283,
0760           284,  285,  294,  295,  296,  304,  305,  306,  307,  316,  317,
0761           318,  327,  328,  329,  339,  340,  351,  373,  384,  394,  395,
0762           404,  405,  406,  414,  415,  416,  417,  424,  425,  426,  427,
0763           428,  436,  437,  438,  439,  448,  449,  450,  460,  461,  472,
0764           483,  494,  504,  505,  514,  515,  516,  524,  525,  526,  527,
0765           535,  536,  537,  538,  545,  546,  547,  548,  549,  557,  558,
0766           559,  560,  568,  569,  570,  571,  580,  581,  582,  592,  593,
0767           604,  614,  615,  625,  626,  635,  636,  637,  645,  646,  647,
0768           648,  655,  656,  657,  658,  659,  665,  666,  667,  668,  669,
0769           670,  677,  678,  679,  680,  681,  689,  690,  691,  692,  701,
0770           702,  703,  713,  714,  724,  725,  735,  736,  745,  746,  747,
0771           755,  756,  757,  758,  765,  766,  767,  768,  769,  776,  777,
0772           778,  779,  780,  787,  788,  789,  790,  791,  798,  799,  800,
0773           801,  802,  809,  810,  811,  812,  813,  821,  822,  823,  824,
0774           833,  834,  835,  845,  846,  855,  856,  857,  866,  867,  868,
0775           876,  877,  878,  879,  887,  888,  889,  890,  898,  899,  900,
0776           901,  909,  910,  911,  912,  920,  921,  922,  923,  931,  932,
0777           933,  934,  942,  943,  944,  945,  954,  955,  956,  965,  966,
0778           967,  976,  977,  978,  987,  988,  989,  998,  999,  1000, 1009,
0779           1010, 1011, 1020, 1021, 1022, 1031, 1032, 1033, 1042, 1043, 1044,
0780           1053, 1054, 1055, 1064, 1065, 1066, 1075, 1076, 1077, 1086, 1087,
0781           1088, 1098, 1099, 1109, 1110, 1120, 1121, 1131, 1132, 1142, 1143,
0782           1153, 1154, 1164, 1165, 1175, 1176, 1186, 1187, 1197, 1198, 1208,
0783           1209, 1220, 1231, 1242, 1253, 1264, 1275, 1286, 1297, 1308, 1319,
0784           1330}},
0785         {Frustum3({0, 0, 0}, {0, 0, 1}, M_PI / 4.),
0786          {186, 305, 306, 307, 416, 417, 425, 426, 427, 428, 438, 439,
0787           527, 536, 537, 538, 545, 546, 547, 548, 549, 558, 559, 560,
0788           571, 647, 648, 656, 657, 658, 659, 665, 666, 667, 668, 669,
0789           670, 678, 679, 680, 681, 691, 692, 758, 767, 768, 769, 777,
0790           778, 779, 780, 788, 789, 790, 791, 799, 800, 801, 802, 811,
0791           812, 813, 824, 879, 890, 901, 912, 923, 934, 945}},
0792         {Frustum3({0, 0, 0}, {0, 0, 1}, M_PI / 8.),
0793          {427, 428, 546, 547, 548, 549, 658, 659, 665, 666, 667, 668, 669, 670,
0794           680, 681, 780, 791, 802}},
0795         {Frustum3({0, 0, 0}, {0, 0, 1}, M_PI * 3. / 4.),
0796          {8,    9,    10,   19,   20,   21,   29,   30,   31,   32,   40,
0797           41,   42,   43,   51,   52,   53,   54,   61,   62,   63,   64,
0798           65,   73,   74,   75,   76,   84,   85,   86,   87,   95,   96,
0799           97,   98,   107,  108,  109,  118,  119,  120,  129,  130,  131,
0800           140,  141,  142,  150,  151,  152,  153,  161,  162,  163,  164,
0801           171,  172,  173,  174,  175,  182,  183,  184,  185,  186,  193,
0802           194,  195,  196,  197,  205,  206,  207,  208,  216,  217,  218,
0803           219,  228,  229,  230,  239,  240,  241,  250,  251,  252,  260,
0804           261,  262,  263,  271,  272,  273,  274,  282,  283,  284,  285,
0805           292,  293,  294,  295,  296,  303,  304,  305,  306,  307,  314,
0806           315,  316,  317,  318,  326,  327,  328,  329,  337,  338,  339,
0807           340,  348,  349,  350,  351,  360,  361,  362,  370,  371,  372,
0808           373,  381,  382,  383,  384,  392,  393,  394,  395,  402,  403,
0809           404,  405,  406,  413,  414,  415,  416,  417,  424,  425,  426,
0810           427,  428,  435,  436,  437,  438,  439,  446,  447,  448,  449,
0811           450,  458,  459,  460,  461,  469,  470,  471,  472,  480,  481,
0812           482,  483,  491,  492,  493,  494,  502,  503,  504,  505,  513,
0813           514,  515,  516,  523,  524,  525,  526,  527,  534,  535,  536,
0814           537,  538,  544,  545,  546,  547,  548,  549,  556,  557,  558,
0815           559,  560,  567,  568,  569,  570,  571,  579,  580,  581,  582,
0816           590,  591,  592,  593,  601,  602,  603,  604,  612,  613,  614,
0817           615,  623,  624,  625,  626,  633,  634,  635,  636,  637,  644,
0818           645,  646,  647,  648,  655,  656,  657,  658,  659,  665,  666,
0819           667,  668,  669,  670,  677,  678,  679,  680,  681,  688,  689,
0820           690,  691,  692,  699,  700,  701,  702,  703,  711,  712,  713,
0821           714,  722,  723,  724,  725,  733,  734,  735,  736,  743,  744,
0822           745,  746,  747,  754,  755,  756,  757,  758,  765,  766,  767,
0823           768,  769,  776,  777,  778,  779,  780,  787,  788,  789,  790,
0824           791,  798,  799,  800,  801,  802,  809,  810,  811,  812,  813,
0825           820,  821,  822,  823,  824,  831,  832,  833,  834,  835,  843,
0826           844,  845,  846,  854,  855,  856,  857,  864,  865,  866,  867,
0827           868,  875,  876,  877,  878,  879,  886,  887,  888,  889,  890,
0828           897,  898,  899,  900,  901,  908,  909,  910,  911,  912,  919,
0829           920,  921,  922,  923,  930,  931,  932,  933,  934,  941,  942,
0830           943,  944,  945,  952,  953,  954,  955,  956,  964,  965,  966,
0831           967,  975,  976,  977,  978,  986,  987,  988,  989,  997,  998,
0832           999,  1000, 1008, 1009, 1010, 1011, 1019, 1020, 1021, 1022, 1030,
0833           1031, 1032, 1033, 1041, 1042, 1043, 1044, 1052, 1053, 1054, 1055,
0834           1063, 1064, 1065, 1066, 1074, 1075, 1076, 1077, 1085, 1086, 1087,
0835           1088, 1096, 1097, 1098, 1099, 1107, 1108, 1109, 1110, 1118, 1119,
0836           1120, 1121, 1129, 1130, 1131, 1132, 1140, 1141, 1142, 1143, 1151,
0837           1152, 1153, 1154, 1162, 1163, 1164, 1165, 1173, 1174, 1175, 1176,
0838           1184, 1185, 1186, 1187, 1195, 1196, 1197, 1198, 1206, 1207, 1208,
0839           1209, 1217, 1218, 1219, 1220, 1228, 1229, 1230, 1231, 1239, 1240,
0840           1241, 1242, 1250, 1251, 1252, 1253, 1261, 1262, 1263, 1264, 1272,
0841           1273, 1274, 1275, 1283, 1284, 1285, 1286, 1294, 1295, 1296, 1297,
0842           1305, 1306, 1307, 1308, 1316, 1317, 1318, 1319, 1327, 1328, 1329,
0843           1330}},
0844         {Frustum3({1.3, -5.9, 3.5}, {0.2, 0.4, 1}, M_PI / 3.),
0845          {318,  426,  427,  428,  438,  439,  450,  538,  546,  547,  548,
0846           549,  558,  559,  560,  570,  571,  582,  655,  656,  657,  658,
0847           659,  667,  668,  669,  670,  678,  679,  680,  681,  690,  691,
0848           692,  702,  703,  714,  768,  769,  777,  778,  779,  780,  787,
0849           788,  789,  790,  791,  799,  800,  801,  802,  810,  811,  812,
0850           813,  822,  823,  824,  834,  835,  846,  888,  889,  890,  899,
0851           900,  901,  910,  911,  912,  920,  921,  922,  923,  931,  932,
0852           933,  934,  942,  943,  944,  945,  954,  955,  956,  966,  967,
0853           1000, 1010, 1011, 1021, 1022, 1032, 1033, 1042, 1043, 1044, 1053,
0854           1054, 1055, 1064, 1065, 1066, 1074, 1075, 1076, 1077, 1086, 1087,
0855           1088, 1143, 1154, 1165, 1175, 1176, 1186, 1187, 1197, 1198, 1207,
0856           1208, 1209, 1308, 1319, 1330}}};
0857 
0858     for (std::size_t l = 0; l < fr_exp.size(); l++) {
0859       const Frustum3& fr = fr_exp.at(l).first;
0860       const std::set<std::size_t>& exp_idxs = fr_exp.at(l).second;
0861       std::stringstream ss;
0862       ss << "frust3d-3s_test_" << l << ".ply";
0863 
0864       os = tmp(ss.str());
0865 
0866       helper.clear();
0867 
0868       act_idxs.clear();
0869 
0870       fr.draw(helper, 50);
0871 
0872       n = 10;
0873       min = -33;
0874       max = 33;
0875       step = (max - min) / BoundingBoxScalar(n);
0876 
0877       Object o;
0878       using Box = AxisAlignedBoundingBox<Object, BoundingBoxScalar, 3>;
0879       Box::Size size(Eigen::Matrix<BoundingBoxScalar, 3, 1>(2, 2, 2));
0880 
0881       std::size_t idx = 0;
0882 
0883       for (std::size_t i = 0; i <= n; i++) {
0884         for (std::size_t j = 0; j <= n; j++) {
0885           for (std::size_t k = 0; k <= n; k++) {
0886             Eigen::Matrix<BoundingBoxScalar, 3, 1> pos(
0887                 min + i * step, min + j * step, min + k * step);
0888             Box bb(&o, pos, size);
0889 
0890             std::array<int, 3> color = {255, 0, 0};
0891 
0892             if (bb.intersect(fr)) {
0893               color = {0, 255, 0};
0894               act_idxs.insert(idx);
0895             }
0896 
0897             bb.draw(helper, color);
0898             idx++;
0899           }
0900         }
0901       }
0902 
0903       os << helper << std::flush;
0904       os.close();
0905 
0906       BOOST_CHECK(act_idxs == exp_idxs);
0907     }
0908   }
0909 
0910   BOOST_TEST_CONTEXT("3D - 4 Sides") {
0911     using Frustum34 = Frustum<BoundingBoxScalar, 3, 4>;
0912     std::size_t n = 10;
0913     double min = -10, max = 10;
0914     std::size_t s = 5;
0915     double step = (max - min) / double(s);
0916     std::ofstream os;
0917 
0918     // BEGIN VISUAL PARAMETER TEST
0919 
0920     // std::size_t n_vtx    = 1;
0921 
0922     // helper.clear();
0923     // os = tmp("frust3d-4s_dir.ply");
0924 
0925     // double angle = M_PI / 4.;
0926     // for (std::size_t i = 0; i <= s; i++) {
0927     // for (std::size_t j = 0; j <= s; j++) {
0928     // for (std::size_t k = 0; k <= s; k++) {
0929     // ActsVector<BoundingBoxScalar,3> origin(
0930     // min + i * step, min + j * step, min + k * step);
0931     // ActsVector<BoundingBoxScalar,3> dir(1, 0, 0);
0932 
0933     // Eigen::Affine3f rot;
0934     // rot = Eigen::AngleAxisf(M_PI / BoundingBoxScalar(s) * i,
0935     // ActsVector<BoundingBoxScalar,3>::UnitX())
0936     //* Eigen::AngleAxisf(M_PI / BoundingBoxScalar(s) * j,
0937     // ActsVector<BoundingBoxScalar,3>::UnitY())
0938     //* Eigen::AngleAxisf(M_PI / BoundingBoxScalar(s) * k,
0939     // ActsVector<BoundingBoxScalar,3>::UnitZ());
0940 
0941     // Frustum34 fr(origin, rot * dir, angle);
0942     // fr.draw(helper, 1);
0943     //}
0944     //}
0945     //}
0946 
0947     // os << helper << std::flush;
0948     // os.close();
0949     // os = tmp("frust3d-4s_angle.ply");
0950     // helper.clear();
0951 
0952     // n_vtx    = 1;
0953     // for (std::size_t i = 0; i <= n; i++) {
0954     // ActsVector<BoundingBoxScalar,3>  origin(i * 4, 0, 0);
0955     // Eigen::Affine3f rot;
0956     // rot   = Eigen::AngleAxisf(M_PI / BoundingBoxScalar(n) * i,
0957     // ActsVector<BoundingBoxScalar,3>::UnitY());
0958     // angle = (M_PI / 2.) / BoundingBoxScalar(n) * (1 + i);
0959     // ActsVector<BoundingBoxScalar,3> dir(1, 0, 0);
0960     // Frustum34      fr(origin, rot * dir, angle);
0961     // fr.draw(helper, 2);
0962     //}
0963 
0964     // os << helper << std::flush;
0965     // os.close();
0966 
0967     // END VISUAL PARAMETER TEST
0968 
0969     std::set<std::size_t> act_idxs;
0970 
0971     std::vector<std::pair<Frustum34, std::set<std::size_t>>> fr_exp;
0972     fr_exp = {
0973         {Frustum34({0, 0, 0}, {1, 0, 0}, M_PI / 2.),
0974          {665,  774,  775,  776,  785,  786,  787,  796,  797,  798,  883,
0975           884,  885,  886,  887,  894,  895,  896,  897,  898,  905,  906,
0976           907,  908,  909,  916,  917,  918,  919,  920,  927,  928,  929,
0977           930,  931,  992,  993,  994,  995,  996,  997,  998,  1003, 1004,
0978           1005, 1006, 1007, 1008, 1009, 1014, 1015, 1016, 1017, 1018, 1019,
0979           1020, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1036, 1037, 1038,
0980           1039, 1040, 1041, 1042, 1047, 1048, 1049, 1050, 1051, 1052, 1053,
0981           1058, 1059, 1060, 1061, 1062, 1063, 1064, 1101, 1102, 1103, 1104,
0982           1105, 1106, 1107, 1108, 1109, 1112, 1113, 1114, 1115, 1116, 1117,
0983           1118, 1119, 1120, 1123, 1124, 1125, 1126, 1127, 1128, 1129, 1130,
0984           1131, 1134, 1135, 1136, 1137, 1138, 1139, 1140, 1141, 1142, 1145,
0985           1146, 1147, 1148, 1149, 1150, 1151, 1152, 1153, 1156, 1157, 1158,
0986           1159, 1160, 1161, 1162, 1163, 1164, 1167, 1168, 1169, 1170, 1171,
0987           1172, 1173, 1174, 1175, 1178, 1179, 1180, 1181, 1182, 1183, 1184,
0988           1185, 1186, 1189, 1190, 1191, 1192, 1193, 1194, 1195, 1196, 1197,
0989           1210, 1211, 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1219, 1220,
0990           1221, 1222, 1223, 1224, 1225, 1226, 1227, 1228, 1229, 1230, 1231,
0991           1232, 1233, 1234, 1235, 1236, 1237, 1238, 1239, 1240, 1241, 1242,
0992           1243, 1244, 1245, 1246, 1247, 1248, 1249, 1250, 1251, 1252, 1253,
0993           1254, 1255, 1256, 1257, 1258, 1259, 1260, 1261, 1262, 1263, 1264,
0994           1265, 1266, 1267, 1268, 1269, 1270, 1271, 1272, 1273, 1274, 1275,
0995           1276, 1277, 1278, 1279, 1280, 1281, 1282, 1283, 1284, 1285, 1286,
0996           1287, 1288, 1289, 1290, 1291, 1292, 1293, 1294, 1295, 1296, 1297,
0997           1298, 1299, 1300, 1301, 1302, 1303, 1304, 1305, 1306, 1307, 1308,
0998           1309, 1310, 1311, 1312, 1313, 1314, 1315, 1316, 1317, 1318, 1319,
0999           1320, 1321, 1322, 1323, 1324, 1325, 1326, 1327, 1328, 1329, 1330}},
1000         {Frustum34({0, 0, 0}, {0, 1, 0}, M_PI / 2.),
1001          {110,  111,  112,  113,  114,  115,  116,  117,  118,  119,  120,
1002           221,  222,  223,  224,  225,  226,  227,  228,  229,  231,  232,
1003           233,  234,  235,  236,  237,  238,  239,  240,  241,  332,  333,
1004           334,  335,  336,  337,  338,  342,  343,  344,  345,  346,  347,
1005           348,  349,  350,  352,  353,  354,  355,  356,  357,  358,  359,
1006           360,  361,  362,  443,  444,  445,  446,  447,  453,  454,  455,
1007           456,  457,  458,  459,  463,  464,  465,  466,  467,  468,  469,
1008           470,  471,  473,  474,  475,  476,  477,  478,  479,  480,  481,
1009           482,  483,  554,  555,  556,  564,  565,  566,  567,  568,  574,
1010           575,  576,  577,  578,  579,  580,  584,  585,  586,  587,  588,
1011           589,  590,  591,  592,  594,  595,  596,  597,  598,  599,  600,
1012           601,  602,  603,  604,  665,  675,  676,  677,  685,  686,  687,
1013           688,  689,  695,  696,  697,  698,  699,  700,  701,  705,  706,
1014           707,  708,  709,  710,  711,  712,  713,  715,  716,  717,  718,
1015           719,  720,  721,  722,  723,  724,  725,  796,  797,  798,  806,
1016           807,  808,  809,  810,  816,  817,  818,  819,  820,  821,  822,
1017           826,  827,  828,  829,  830,  831,  832,  833,  834,  836,  837,
1018           838,  839,  840,  841,  842,  843,  844,  845,  846,  927,  928,
1019           929,  930,  931,  937,  938,  939,  940,  941,  942,  943,  947,
1020           948,  949,  950,  951,  952,  953,  954,  955,  957,  958,  959,
1021           960,  961,  962,  963,  964,  965,  966,  967,  1058, 1059, 1060,
1022           1061, 1062, 1063, 1064, 1068, 1069, 1070, 1071, 1072, 1073, 1074,
1023           1075, 1076, 1078, 1079, 1080, 1081, 1082, 1083, 1084, 1085, 1086,
1024           1087, 1088, 1189, 1190, 1191, 1192, 1193, 1194, 1195, 1196, 1197,
1025           1199, 1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209,
1026           1320, 1321, 1322, 1323, 1324, 1325, 1326, 1327, 1328, 1329, 1330}},
1027         {Frustum34({0, 0, 0}, {0, 0, 1}, M_PI / 2.),
1028          {10,   21,   32,   43,   54,   65,   76,   87,   98,   109,  120,
1029           131,  141,  142,  152,  153,  163,  164,  174,  175,  185,  186,
1030           196,  197,  207,  208,  218,  219,  229,  230,  241,  252,  262,
1031           263,  272,  273,  274,  283,  284,  285,  294,  295,  296,  305,
1032           306,  307,  316,  317,  318,  327,  328,  329,  338,  339,  340,
1033           350,  351,  362,  373,  383,  384,  393,  394,  395,  403,  404,
1034           405,  406,  414,  415,  416,  417,  425,  426,  427,  428,  436,
1035           437,  438,  439,  447,  448,  449,  450,  459,  460,  461,  471,
1036           472,  483,  494,  504,  505,  514,  515,  516,  524,  525,  526,
1037           527,  534,  535,  536,  537,  538,  545,  546,  547,  548,  549,
1038           556,  557,  558,  559,  560,  568,  569,  570,  571,  580,  581,
1039           582,  592,  593,  604,  615,  625,  626,  635,  636,  637,  645,
1040           646,  647,  648,  655,  656,  657,  658,  659,  665,  666,  667,
1041           668,  669,  670,  677,  678,  679,  680,  681,  689,  690,  691,
1042           692,  701,  702,  703,  713,  714,  725,  736,  746,  747,  756,
1043           757,  758,  766,  767,  768,  769,  776,  777,  778,  779,  780,
1044           787,  788,  789,  790,  791,  798,  799,  800,  801,  802,  810,
1045           811,  812,  813,  822,  823,  824,  834,  835,  846,  857,  867,
1046           868,  877,  878,  879,  887,  888,  889,  890,  898,  899,  900,
1047           901,  909,  910,  911,  912,  920,  921,  922,  923,  931,  932,
1048           933,  934,  943,  944,  945,  955,  956,  967,  978,  988,  989,
1049           998,  999,  1000, 1009, 1010, 1011, 1020, 1021, 1022, 1031, 1032,
1050           1033, 1042, 1043, 1044, 1053, 1054, 1055, 1064, 1065, 1066, 1076,
1051           1077, 1088, 1099, 1109, 1110, 1120, 1121, 1131, 1132, 1142, 1143,
1052           1153, 1154, 1164, 1165, 1175, 1176, 1186, 1187, 1197, 1198, 1209,
1053           1220, 1231, 1242, 1253, 1264, 1275, 1286, 1297, 1308, 1319, 1330}},
1054         {Frustum34({0, 0, 0}, {0, 0, 1}, M_PI / 4.),
1055          {406, 417, 428, 439, 450, 527, 535, 536, 537, 538, 546, 547, 548, 549,
1056           557, 558, 559, 560, 571, 648, 656, 657, 658, 659, 665, 666, 667, 668,
1057           669, 670, 678, 679, 680, 681, 692, 769, 777, 778, 779, 780, 788, 789,
1058           790, 791, 799, 800, 801, 802, 813, 890, 901, 912, 923, 934}},
1059         {Frustum34({0, 0, 0}, {0, 0, 1}, M_PI / 8.),
1060          {538, 549, 560, 659, 665, 666, 667, 668, 669, 670, 681, 780, 791,
1061           802}},
1062         {Frustum34({0, 0, 0}, {0, 0, 1}, M_PI * 3. / 4.),
1063          {7,    8,    9,    10,   18,   19,   20,   21,   29,   30,   31,
1064           32,   40,   41,   42,   43,   51,   52,   53,   54,   62,   63,
1065           64,   65,   73,   74,   75,   76,   84,   85,   86,   87,   95,
1066           96,   97,   98,   106,  107,  108,  109,  117,  118,  119,  120,
1067           128,  129,  130,  131,  139,  140,  141,  142,  150,  151,  152,
1068           153,  161,  162,  163,  164,  172,  173,  174,  175,  183,  184,
1069           185,  186,  194,  195,  196,  197,  205,  206,  207,  208,  216,
1070           217,  218,  219,  227,  228,  229,  230,  238,  239,  240,  241,
1071           249,  250,  251,  252,  260,  261,  262,  263,  271,  272,  273,
1072           274,  282,  283,  284,  285,  293,  294,  295,  296,  304,  305,
1073           306,  307,  315,  316,  317,  318,  326,  327,  328,  329,  337,
1074           338,  339,  340,  348,  349,  350,  351,  359,  360,  361,  362,
1075           370,  371,  372,  373,  381,  382,  383,  384,  392,  393,  394,
1076           395,  402,  403,  404,  405,  406,  413,  414,  415,  416,  417,
1077           424,  425,  426,  427,  428,  435,  436,  437,  438,  439,  446,
1078           447,  448,  449,  450,  458,  459,  460,  461,  469,  470,  471,
1079           472,  480,  481,  482,  483,  491,  492,  493,  494,  502,  503,
1080           504,  505,  513,  514,  515,  516,  523,  524,  525,  526,  527,
1081           534,  535,  536,  537,  538,  545,  546,  547,  548,  549,  556,
1082           557,  558,  559,  560,  567,  568,  569,  570,  571,  579,  580,
1083           581,  582,  590,  591,  592,  593,  601,  602,  603,  604,  612,
1084           613,  614,  615,  623,  624,  625,  626,  634,  635,  636,  637,
1085           644,  645,  646,  647,  648,  655,  656,  657,  658,  659,  665,
1086           666,  667,  668,  669,  670,  677,  678,  679,  680,  681,  688,
1087           689,  690,  691,  692,  700,  701,  702,  703,  711,  712,  713,
1088           714,  722,  723,  724,  725,  733,  734,  735,  736,  744,  745,
1089           746,  747,  755,  756,  757,  758,  765,  766,  767,  768,  769,
1090           776,  777,  778,  779,  780,  787,  788,  789,  790,  791,  798,
1091           799,  800,  801,  802,  809,  810,  811,  812,  813,  821,  822,
1092           823,  824,  832,  833,  834,  835,  843,  844,  845,  846,  854,
1093           855,  856,  857,  865,  866,  867,  868,  876,  877,  878,  879,
1094           886,  887,  888,  889,  890,  897,  898,  899,  900,  901,  908,
1095           909,  910,  911,  912,  919,  920,  921,  922,  923,  930,  931,
1096           932,  933,  934,  942,  943,  944,  945,  953,  954,  955,  956,
1097           964,  965,  966,  967,  975,  976,  977,  978,  986,  987,  988,
1098           989,  997,  998,  999,  1000, 1008, 1009, 1010, 1011, 1019, 1020,
1099           1021, 1022, 1030, 1031, 1032, 1033, 1041, 1042, 1043, 1044, 1052,
1100           1053, 1054, 1055, 1063, 1064, 1065, 1066, 1074, 1075, 1076, 1077,
1101           1085, 1086, 1087, 1088, 1096, 1097, 1098, 1099, 1107, 1108, 1109,
1102           1110, 1118, 1119, 1120, 1121, 1129, 1130, 1131, 1132, 1140, 1141,
1103           1142, 1143, 1151, 1152, 1153, 1154, 1162, 1163, 1164, 1165, 1173,
1104           1174, 1175, 1176, 1184, 1185, 1186, 1187, 1195, 1196, 1197, 1198,
1105           1206, 1207, 1208, 1209, 1217, 1218, 1219, 1220, 1228, 1229, 1230,
1106           1231, 1239, 1240, 1241, 1242, 1250, 1251, 1252, 1253, 1261, 1262,
1107           1263, 1264, 1272, 1273, 1274, 1275, 1283, 1284, 1285, 1286, 1294,
1108           1295, 1296, 1297, 1305, 1306, 1307, 1308, 1316, 1317, 1318, 1319,
1109           1327, 1328, 1329, 1330}},
1110         {Frustum34({1.3, -5.9, 3.5}, {0.2, 0.4, 1}, M_PI / 3.),
1111          {461,  472,  537,  538,  548,  549,  558,  559,  560,  569,  570,
1112           571,  581,  582,  593,  655,  656,  657,  658,  659,  666,  667,
1113           668,  669,  670,  678,  679,  680,  681,  690,  691,  692,  702,
1114           703,  714,  777,  778,  779,  780,  787,  788,  789,  790,  791,
1115           799,  800,  801,  802,  811,  812,  813,  823,  824,  835,  846,
1116           899,  900,  901,  910,  911,  912,  920,  921,  922,  923,  932,
1117           933,  934,  944,  945,  955,  956,  967,  1021, 1022, 1032, 1033,
1118           1042, 1043, 1044, 1053, 1054, 1055, 1064, 1065, 1066, 1076, 1077,
1119           1088, 1143, 1154, 1165, 1175, 1176, 1186, 1187, 1197, 1198, 1209,
1120           1308, 1319, 1330}}};
1121 
1122     for (std::size_t l = 0; l < fr_exp.size(); l++) {
1123       const Frustum34& fr = fr_exp.at(l).first;
1124       const std::set<std::size_t>& exp_idxs = fr_exp.at(l).second;
1125       std::stringstream ss;
1126       ss << "frust3d-4s_test_" << l << ".ply";
1127 
1128       os = tmp(ss.str());
1129 
1130       helper.clear();
1131 
1132       act_idxs.clear();
1133 
1134       fr.draw(helper, 50);
1135 
1136       n = 10;
1137       min = -33;
1138       max = 33;
1139       step = (max - min) / BoundingBoxScalar(n);
1140 
1141       Object o;
1142       using Box = AxisAlignedBoundingBox<Object, BoundingBoxScalar, 3>;
1143       Box::Size size(Eigen::Matrix<BoundingBoxScalar, 3, 1>(2, 2, 2));
1144 
1145       std::size_t idx = 0;
1146       for (std::size_t i = 0; i <= n; i++) {
1147         for (std::size_t j = 0; j <= n; j++) {
1148           for (std::size_t k = 0; k <= n; k++) {
1149             Eigen::Matrix<BoundingBoxScalar, 3, 1> pos(
1150                 min + i * step, min + j * step, min + k * step);
1151             Box bb(&o, pos, size);
1152 
1153             std::array<int, 3> color = {255, 0, 0};
1154 
1155             if (bb.intersect(fr)) {
1156               color = {0, 255, 0};
1157               act_idxs.insert(idx);
1158             }
1159 
1160             bb.draw(helper, color);
1161             idx++;
1162           }
1163         }
1164       }
1165 
1166       os << helper << std::flush;
1167       os.close();
1168 
1169       BOOST_CHECK(act_idxs == exp_idxs);
1170     }
1171   }
1172 
1173   BOOST_TEST_CONTEXT("3D - 5 Sides") {
1174     using Frustum = Frustum<BoundingBoxScalar, 3, 5>;
1175     using Box = AxisAlignedBoundingBox<Object, BoundingBoxScalar, 3>;
1176     Box::Size size(Eigen::Matrix<BoundingBoxScalar, 3, 1>(2, 2, 2));
1177 
1178     Object o;
1179 
1180     PlyVisualization3D<BoundingBoxScalar> ply;
1181 
1182     Frustum fr({0, 0, 0}, {0, 0, 1}, M_PI / 8.);
1183     fr.draw(ply, 10);
1184 
1185     Box bb(&o, {0, 0, 10}, size);
1186     bb.draw(ply);
1187 
1188     BOOST_CHECK(bb.intersect(fr));
1189 
1190     auto os = tmp("frust3d-5s.ply");
1191     os << ply << std::flush;
1192     os.close();
1193   }
1194 
1195   BOOST_TEST_CONTEXT("3D - 10 Sides") {
1196     using Frustum = Frustum<BoundingBoxScalar, 3, 10>;
1197     using Box = AxisAlignedBoundingBox<Object, BoundingBoxScalar, 3>;
1198     using vec3 = Eigen::Matrix<BoundingBoxScalar, 3, 1>;
1199     Box::Size size(vec3(2, 2, 2));
1200 
1201     Object o;
1202 
1203     PlyVisualization3D<BoundingBoxScalar> ply;
1204 
1205     // Frustum fr({0, 0, 0}, {0, 0, 1}, M_PI/8.);
1206     vec3 pos = {-12.4205, 29.3578, 44.6207};
1207     vec3 dir = {-0.656862, 0.48138, 0.58035};
1208     Frustum fr(pos, dir, 0.972419);
1209     fr.draw(ply, 10);
1210 
1211     Box bb(&o, pos + dir * 10, size);
1212     bb.draw(ply);
1213 
1214     BOOST_CHECK(bb.intersect(fr));
1215 
1216     auto os = tmp("frust3d-10s.ply");
1217     os << ply << std::flush;
1218     os.close();
1219   }
1220 
1221   BOOST_TEST_CONTEXT("3D - 4 Sides - Big box") {
1222     using Frustum = Frustum<BoundingBoxScalar, 3, 4>;
1223     using Box = AxisAlignedBoundingBox<Object, BoundingBoxScalar, 3>;
1224     using vec3 = Eigen::Matrix<BoundingBoxScalar, 3, 1>;
1225 
1226     Object o;
1227 
1228     PlyVisualization3D<BoundingBoxScalar> ply;
1229 
1230     vec3 pos = {0, 0, 0};
1231     vec3 dir = {0, 0, 1};
1232     Frustum fr(pos, dir, 0.972419);
1233     fr.draw(ply, 10);
1234 
1235     Box::Size size(vec3(100, 100, 2));
1236     Box bb(&o, pos + dir * 7, size);
1237     bb.draw(ply);
1238 
1239     BOOST_CHECK(bb.intersect(fr));
1240 
1241     auto os = tmp("frust3d-4s-bigbox.ply");
1242     os << ply << std::flush;
1243     os.close();
1244   }
1245 }
1246 
1247 BOOST_AUTO_TEST_CASE(ostream_operator) {
1248   Object o;
1249   using Box = Acts::AxisAlignedBoundingBox<Object, BoundingBoxScalar, 2>;
1250   Box bb(&o, {-1, -1}, {2, 2});
1251 
1252   std::stringstream ss;
1253   ss << bb;
1254 
1255   BOOST_CHECK(ss.str() == "AABB(ctr=(0.5, 0.5) vmin=(-1, -1) vmax=(2, 2))");
1256 }
1257 
1258 }  // namespace Acts::Test