Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:11:10

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 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 https://mozilla.org/MPL/2.0/.
0008 
0009 #include "Acts/Utilities/VectorHelpers.hpp"
0010 
0011 #include <numbers>
0012 
0013 template <typename value_t, std::size_t DIM, std::size_t SIDES>
0014 Acts::Frustum<value_t, DIM, SIDES>::Frustum(const VertexType& origin,
0015                                             const VertexType& dir,
0016                                             value_type opening_angle)
0017   requires(DIM == 2)
0018     : m_origin(origin) {
0019   using rotation_t = Eigen::Rotation2D<value_type>;
0020 
0021   static_assert(SIDES == 2, "2D frustum can only have 2 sides");
0022   assert(opening_angle < std::numbers::pi_v<value_type>);
0023 
0024   translation_t translation(origin);
0025   value_type angle = VectorHelpers::phi(dir);
0026   Eigen::Rotation2D<value_type> rot(angle);
0027 
0028   value_type normal_angle = std::numbers::pi / 2. - opening_angle / 2.;
0029   VertexType normal1 = rotation_t(normal_angle) * VertexType::UnitX();
0030   VertexType normal2 = rotation_t(-normal_angle) * VertexType::UnitX();
0031 
0032   m_normals = {rot * VertexType::UnitX(), rot * normal1, rot * normal2};
0033 }
0034 
0035 template <typename value_t, std::size_t DIM, std::size_t SIDES>
0036 Acts::Frustum<value_t, DIM, SIDES>::Frustum(const VertexType& origin,
0037                                             const VertexType& dir,
0038                                             value_type opening_angle)
0039   requires(DIM == 3)
0040     : m_origin(origin) {
0041   static_assert(SIDES > 2, "3D frustum must have 3 or more sides");
0042   assert(opening_angle < std::numbers::pi_v<value_type>);
0043   using angle_axis_t = Eigen::AngleAxis<value_type>;
0044 
0045   const VertexType ldir = VertexType::UnitZ();
0046   const VertexType lup = VertexType::UnitX();
0047 
0048   transform_type transform;
0049   transform = (Eigen::Quaternion<value_type>().setFromTwoVectors(ldir, dir));
0050 
0051   m_normals[0] = ldir;
0052 
0053   const value_type phi_sep = 2. * std::numbers::pi_v<value_type> / sides;
0054   transform_type rot;
0055   rot = angle_axis_t(phi_sep, ldir);
0056 
0057   value_type half_opening_angle = opening_angle / 2.;
0058   auto calculate_normal =
0059       [&ldir, &half_opening_angle](const VertexType& out) -> VertexType {
0060     const VertexType tilt_axis = -1 * out.cross(ldir);
0061     return (-1 * (angle_axis_t(half_opening_angle, tilt_axis) * out))
0062         .normalized();
0063   };
0064 
0065   VertexType current_outward = lup;
0066   m_normals[1] = calculate_normal(current_outward);
0067 
0068   for (std::size_t i = 1; i < sides; i++) {
0069     current_outward = rot * current_outward;
0070     m_normals[i + 1] = calculate_normal(current_outward);
0071   }
0072 
0073   for (auto& normal : m_normals) {
0074     normal = transform * normal;
0075   }
0076 }
0077 
0078 template <typename value_t, std::size_t DIM, std::size_t SIDES>
0079 void Acts::Frustum<value_t, DIM, SIDES>::draw(IVisualization3D& helper,
0080                                               value_type far_distance) const
0081   requires(DIM == 3)
0082 {
0083   static_assert(DIM == 3, "Drawing is only supported in 3D");
0084 
0085   // Iterate around normals, calculate cross with "far" plane
0086   // to get intersection lines.
0087   // Work in local reference frame of the frustum, and only convert to global
0088   // right before drawing.
0089   VertexType far_normal = m_normals[0];  // far has same normal as pseudo-near
0090   VertexType far_center = m_normals[0] * far_distance;
0091   std::array<std::pair<VertexType, VertexType>, SIDES> planeFarIXs;
0092 
0093   auto ixPlanePlane = [](const auto& n1, const auto& p1, const auto& n2,
0094                          const auto& p2) -> std::pair<VertexType, VertexType> {
0095     const VertexType m = n1.cross(n2).normalized();
0096     const double j = (n2.dot(p2 - p1)) / (n2.dot(n1.cross(m)));
0097     const VertexType q = p1 + j * n1.cross(m);
0098     return {m, q};
0099   };
0100 
0101   auto ixLineLine = [](const auto& p1, const auto& d1, const auto& p2,
0102                        const auto& d2) -> VertexType {
0103     return p1 + (((p2 - p1).cross(d2)).norm() / (d1.cross(d2)).norm()) * d1;
0104   };
0105 
0106   // skip i=0 <=> pseudo-near
0107   for (std::size_t i = 1; i < n_normals; i++) {
0108     const auto ixLine =
0109         ixPlanePlane(far_normal, far_center, m_normals[i], VertexType::Zero());
0110     planeFarIXs.at(i - 1) = ixLine;
0111   }
0112 
0113   std::array<VertexType, SIDES> points;
0114 
0115   for (std::size_t i = 0; i < std::size(planeFarIXs); i++) {
0116     std::size_t j = (i + 1) % std::size(planeFarIXs);
0117     const auto& l1 = planeFarIXs.at(i);
0118     const auto& l2 = planeFarIXs.at(j);
0119     const VertexType ix =
0120         m_origin + ixLineLine(l1.second, l1.first, l2.second, l2.first);
0121     points.at(i) = ix;
0122   }
0123 
0124   for (std::size_t i = 0; i < std::size(points); i++) {
0125     std::size_t j = (i + 1) % std::size(points);
0126     helper.face(
0127         std::vector<VertexType>({m_origin, points.at(i), points.at(j)}));
0128   }
0129 }
0130 
0131 template <typename value_t, std::size_t DIM, std::size_t SIDES>
0132 std::ostream& Acts::Frustum<value_t, DIM, SIDES>::svg(std::ostream& os,
0133                                                       value_type w,
0134                                                       value_type h,
0135                                                       value_type far_distance,
0136                                                       value_type unit) const
0137   requires(DIM == 2)
0138 {
0139   static_assert(DIM == 2, "SVG is only supported in 2D");
0140 
0141   VertexType mid(w / 2., h / 2.);
0142 
0143   // set up transform for svg. +y is down, normally, and unit is pixels.
0144   // We flip the y axis, and scale up by `unit`.
0145   transform_type trf = transform_type::Identity();
0146   trf.translate(mid);
0147   trf = trf * Eigen::Scaling(VertexType(1, -1));
0148   trf.scale(unit);
0149 
0150   std::array<std::string, 3> colors({"orange", "blue", "red"});
0151 
0152   auto draw_line = [&](const VertexType& left_, const VertexType& right_,
0153                        const std::string& color, std::size_t width) {
0154     VertexType left = trf * left_;
0155     VertexType right = trf * right_;
0156     os << "<line ";
0157 
0158     os << "x1=\"" << left.x() << "\" ";
0159     os << "y1=\"" << left.y() << "\" ";
0160     os << "x2=\"" << right.x() << "\" ";
0161     os << "y2=\"" << right.y() << "\" ";
0162 
0163     os << " stroke=\"" << color << "\" stroke-width=\"" << width << "\"/>\n";
0164   };
0165 
0166   auto draw_point = [&](const VertexType& p_, const std::string& color,
0167                         std::size_t r) {
0168     VertexType p = trf * p_;
0169     os << "<circle ";
0170     os << "cx=\"" << p.x() << "\" cy=\"" << p.y() << "\" r=\"" << r << "\"";
0171     os << " fill=\"" << color << "\"";
0172     os << "/>\n";
0173   };
0174 
0175   using vec3 = Eigen::Matrix<value_type, 3, 1>;
0176   auto ixLineLine = [](const VertexType& p1_2, const VertexType& d1_2,
0177                        const VertexType& p2_2,
0178                        const VertexType& d2_2) -> VertexType {
0179     const vec3 p1(p1_2.x(), p1_2.y(), 0);
0180     const vec3 p2(p2_2.x(), p2_2.y(), 0);
0181     const vec3 d1(d1_2.x(), d1_2.y(), 0);
0182     const vec3 d2(d2_2.x(), d2_2.y(), 0);
0183 
0184     vec3 num = (p2 - p1).cross(d2);
0185     vec3 den = d1.cross(d2);
0186 
0187     value_type f = 1.;
0188     value_type dot = num.normalized().dot(den.normalized());
0189     if (std::abs(dot) - 1 < 1e-9 && dot < 0) {
0190       f = -1.;
0191     }
0192 
0193     const vec3 p = p1 + f * (num.norm() / den.norm()) * d1;
0194     assert(std::abs(p.z()) < 1e-9);
0195     return {p.x(), p.y()};
0196   };
0197 
0198   const VertexType far_dir = {m_normals[0].y(), -m_normals[0].x()};
0199   const VertexType far_point = m_normals[0] * far_distance;
0200 
0201   std::array<VertexType, 2> points;
0202 
0203   for (std::size_t i = 1; i < n_normals; i++) {
0204     VertexType plane_dir(m_normals[i].y(), -m_normals[i].x());
0205 
0206     const VertexType ix = ixLineLine(far_point, far_dir, {0, 0}, plane_dir);
0207     draw_point(m_origin + ix, "black", 3);
0208     draw_line(m_origin, m_origin + ix, "black", 2);
0209     points.at(i - 1) = ix;
0210   }
0211 
0212   draw_line(m_origin + points.at(0), m_origin + points.at(1), "black", 2);
0213 
0214   draw_line(m_origin, m_origin + m_normals[0] * 2, colors[0], 3);
0215 
0216   draw_point({0, 0}, "yellow", 5);
0217   draw_point(m_origin, "green", 5);
0218 
0219   return os;
0220 }
0221 
0222 template <typename value_t, std::size_t DIM, std::size_t SIDES>
0223 Acts::Frustum<value_t, DIM, SIDES>
0224 Acts::Frustum<value_t, DIM, SIDES>::transformed(
0225     const transform_type& trf) const {
0226   const auto& rot = trf.rotation();
0227 
0228   std::array<VertexType, n_normals> new_normals;
0229   for (std::size_t i = 0; i < n_normals; i++) {
0230     new_normals[i] = rot * m_normals[i];
0231   }
0232 
0233   return Frustum<value_t, DIM, SIDES>(trf * m_origin, std::move(new_normals));
0234 }