Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-27 07:23:59

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 #pragma once
0010 
0011 // Project include(s)
0012 #include "detray/definitions/algebra.hpp"
0013 #include "detray/definitions/detail/qualifiers.hpp"
0014 #include "detray/definitions/indexing.hpp"
0015 #include "detray/geometry/concepts.hpp"
0016 #include "detray/geometry/shapes/cuboid3D.hpp"
0017 #include "detray/navigation/intersection/intersection.hpp"
0018 
0019 // System include(s)
0020 #include <algorithm>
0021 #include <cassert>
0022 #include <ostream>
0023 #include <sstream>
0024 #include <string>
0025 #include <vector>
0026 
0027 namespace detray {
0028 
0029 /// @brief Mask a region on a surface and link it to a volume.
0030 ///
0031 /// The class uses a lightweight 'shape' that defines the local geometry of a
0032 /// surface (local coordinates and how to check boundaries on local point that
0033 /// lies on the surface). A simple example is @c rectangle2D , can be used to
0034 /// mask a rectangle on an underlying plane.
0035 /// This class can then be instantiated as a concrete mask that holds the
0036 /// boundary values, as well as the link to a particular volume, which is
0037 /// needed during geometry navigation.
0038 ///
0039 /// @tparam shape_t underlying geometrical shape of the mask, rectangle etc
0040 /// @tparam links_t the type of link into the volume container
0041 ///                 (e.g. single index vs range)
0042 template <typename shape_t, concepts::algebra algebra_t,
0043           typename links_t = std::uint_least16_t>
0044   requires concepts::shape<shape_t, algebra_t>
0045 class mask {
0046  public:
0047   // Linear algebra types
0048   using algebra_type = algebra_t;
0049   using scalar_type = dscalar<algebra_t>;
0050   using point2_type = dpoint2D<algebra_t>;
0051   using point3_type = dpoint3D<algebra_t>;
0052   using vector3_type = dvector3D<algebra_t>;
0053   using transform3_type = dtransform3D<algebra_t>;
0054 
0055   using links_type = links_t;
0056   using shape = shape_t;
0057   using boundaries = typename shape::boundaries;
0058   using mask_values = typename shape::template bounds_type<scalar_type>;
0059   using local_frame = typename shape::template local_frame_type<algebra_t>;
0060   using result_type = typename shape::template result_type<dbool<algebra_t>>;
0061 
0062   /// Default constructor
0063   constexpr mask() = default;
0064 
0065   /// Constructor from single mask boundary values @param args and
0066   /// volume link @param link
0067   template <typename... Args>
0068     requires(sizeof...(Args) == shape::boundaries::e_size)
0069   DETRAY_HOST_DEVICE explicit constexpr mask(const links_type& link,
0070                                              Args&&... args)
0071       : _values({{std::forward<Args>(args)...}}), _volume_link(link) {}
0072 
0073   /// Constructor from mask boundary array @param values and
0074   /// volume link @param link
0075   DETRAY_HOST_DEVICE
0076   constexpr mask(const mask_values& values, const links_type& link)
0077       : _values{values}, _volume_link{link} {}
0078 
0079   /// Constructor from mask boundary vector @param values and
0080   /// volume link @param link
0081   DETRAY_HOST mask(const std::vector<scalar_type>& values,
0082                    const links_type& link)
0083       : _volume_link(link) {
0084     assert(values.size() == boundaries::e_size &&
0085            " Given number of boundaries does not match mask shape.");
0086     std::ranges::copy(values, std::begin(_values));
0087   }
0088 
0089   /// Assignment operator from an array, convenience function
0090   ///
0091   /// @param rhs is the right hand side object
0092   DETRAY_HOST
0093   auto operator=(const mask_values& rhs) -> mask<shape_t, algebra_t, links_t>& {
0094     _values = rhs;
0095     return (*this);
0096   }
0097 
0098   /// Equality operator
0099   ///
0100   /// @param rhs is the mask to be compared
0101   ///
0102   /// @returns a boolean if the values and links are equal.
0103   bool operator==(const mask& rhs) const = default;
0104 
0105   /// Subscript operator - non-const
0106   ///
0107   /// @returns the reference to the member variable
0108   DETRAY_HOST_DEVICE
0109   constexpr auto operator[](const std::size_t value_index) -> scalar_type& {
0110     return _values[value_index];
0111   }
0112 
0113   /// Subscript operator - const
0114   ///
0115   /// @returns a copy of the member variable
0116   DETRAY_HOST_DEVICE
0117   constexpr auto operator[](const std::size_t value_index) const
0118       -> scalar_type {
0119     return _values[value_index];
0120   }
0121 
0122   /// @returns the mask shape
0123   DETRAY_HOST_DEVICE
0124   static consteval auto get_shape() -> shape { return shape{}; }
0125 
0126   /// @returns return local frame object (used in geometrical checks)
0127   DETRAY_HOST_DEVICE static consteval local_frame get_local_frame() {
0128     return local_frame{};
0129   }
0130 
0131   /// @returns the global point projected onto the surface (3D)
0132   DETRAY_HOST_DEVICE constexpr static auto to_local_frame3D(
0133       const transform3_type& trf, const point3_type& glob_p,
0134       const point3_type& glob_dir = {}) -> point3_type {
0135     return get_local_frame().global_to_local_3D(trf, glob_p, glob_dir);
0136   }
0137 
0138   /// @returns the global point projected onto the surface (2D)
0139   DETRAY_HOST_DEVICE constexpr static auto to_local_frame(
0140       const transform3_type& trf, const point3_type& glob_p,
0141       const point3_type& glob_dir = {}) -> point2_type {
0142     return get_local_frame().global_to_local(trf, glob_p, glob_dir);
0143   }
0144 
0145   /// @returns the global point for a 3D local position on the surface
0146   DETRAY_HOST_DEVICE constexpr static auto to_global_frame(
0147       const transform3_type& trf, const point3_type& loc) -> point3_type {
0148     return get_local_frame().local_to_global(trf, loc);
0149   }
0150 
0151   /// @returns the global point for a 2D local position on the surface
0152   DETRAY_HOST_DEVICE constexpr auto to_global_frame(
0153       const transform3_type& trf, const point2_type& loc,
0154       const vector3_type& dir) const -> point3_type {
0155     return get_local_frame().local_to_global(trf, *this, loc, dir);
0156   }
0157 
0158   /// @brief Mask this shape onto a surface.
0159   /// @{
0160 
0161   /// @note the point is expected to be given in local coordinates and to lie
0162   /// on the underlying surface geometry.
0163   /// For the projection from global to local coordinates, the method
0164   /// @c to_local_frame() can be used.
0165   /// To check that a point lies on the surface, use the corresponding
0166   /// intersector.
0167   ///
0168   /// @param loc_p the point to be checked in the local system (2D or 3D)
0169   /// @param tol dynamic tolerance determined by caller
0170   /// @param edge_tol tolerance that allows for an edge around the mask
0171   ///
0172   /// @returns a mask check result (contains checks with and without edges)
0173   template <concepts::point point_t>
0174   DETRAY_HOST_DEVICE constexpr result_type resolve(
0175       const point_t& loc_p,
0176       const scalar_type tol = std::numeric_limits<scalar_type>::epsilon(),
0177       const scalar_type edge_tol = 0.f) const {
0178     return get_shape().check_boundaries(_values, loc_p, tol, edge_tol);
0179   }
0180 
0181   /// @param trf the (contextual) surface transform
0182   /// @param glob_p the point to be checked in the global cartesian system
0183   /// @param tol dynamic tolerance determined by caller
0184   /// @param edge_tol tolerance that allows for an edge around the mask
0185   ///
0186   /// @returns a mask check result (contains checks with and without edges)
0187   DETRAY_HOST_DEVICE constexpr result_type resolve(
0188       const transform3_type& trf, const point3_type& glob_p,
0189       const scalar_type tol = std::numeric_limits<scalar_type>::epsilon(),
0190       const scalar_type edge_tol = 0.f) const {
0191     return get_shape().template check_boundaries<algebra_type>(
0192         _values, trf, glob_p, tol, edge_tol);
0193   }
0194 
0195   /// @param loc_p the point to be checked in the local system (2D or 3D)
0196   /// @param tol dynamic tolerance determined by caller
0197   ///
0198   /// @returns an intersection status e_inside / e_outside
0199   template <concepts::point point_t>
0200   DETRAY_HOST_DEVICE constexpr dbool<algebra_t> is_inside(
0201       const point_t& loc_p,
0202       const scalar_type tol =
0203           std::numeric_limits<scalar_type>::epsilon()) const {
0204     return detray::get<check_type::e_precise>(
0205         get_shape().check_boundaries(_values, loc_p, tol, scalar_type{0.f}));
0206   }
0207 
0208   /// @param trf the (contextual) surface transform
0209   /// @param glob_p the point to be checked in the global cartesian system
0210   /// @param tol dynamic tolerance determined by caller
0211   ///
0212   /// @returns an intersection status e_inside / e_outside
0213   DETRAY_HOST_DEVICE constexpr dbool<algebra_type> is_inside(
0214       const transform3_type& trf, const point3_type& glob_p,
0215       const scalar_type tol =
0216           std::numeric_limits<scalar_type>::epsilon()) const {
0217     return detray::get<check_type::e_precise>(
0218         get_shape().template check_boundaries<algebra_type>(
0219             _values, trf, glob_p, tol, scalar_type{0.f}));
0220   }
0221   /// @}
0222 
0223   /// @returns the boundary values
0224   DETRAY_HOST_DEVICE
0225   auto values() const -> const mask_values& { return _values; }
0226 
0227   /// @returns the volume link - const reference
0228   DETRAY_HOST_DEVICE
0229   auto volume_link() const -> const links_type& { return _volume_link; }
0230 
0231   /// @returns the volume link - non-const access
0232   DETRAY_HOST_DEVICE
0233   auto volume_link() -> links_type& { return _volume_link; }
0234 
0235   /// @returns the masks measure (area or volume covered by boundary check
0236   /// on local positions)
0237   DETRAY_HOST_DEVICE constexpr auto measure() const -> scalar_type {
0238     return get_shape().measure(_values);
0239   }
0240 
0241   /// @returns the area the mask defines on the local geometry (2D)
0242   template <typename S = shape_t>
0243     requires(S::dim == 2)
0244   DETRAY_HOST_DEVICE constexpr auto area() const -> scalar_type {
0245     return get_shape().area(_values);
0246   }
0247 
0248   /// @returns the area the mask defines on the local geometry (3D)
0249   template <typename S = shape_t>
0250     requires(S::dim == 3)
0251   DETRAY_HOST_DEVICE constexpr auto volume() const -> scalar_type {
0252     return get_shape().volume(_values);
0253   }
0254 
0255   /// @returns the masks centroid in local cartesian coordinates
0256   DETRAY_HOST_DEVICE auto centroid() const {
0257     return get_shape().template centroid<algebra_t>(_values);
0258   }
0259 
0260   /// @brief Find the minimum distance to any boundary.
0261   ///
0262   /// @param loc_p the point to be checked in the local system
0263   ///
0264   /// @returns the minimum distance.
0265   DETRAY_HOST_DEVICE
0266   auto min_dist_to_boundary(const point3_type& loc_p) const -> scalar_type {
0267     return get_shape().min_dist_to_boundary(_values, loc_p);
0268   }
0269 
0270   /// @brief Lower and upper point for minimum axis aligned bounding box.
0271   ///
0272   /// Computes the min and max vertices in a local 3 dim cartesian frame.
0273   ///
0274   /// @param env dynamic envelope around the shape
0275   ///
0276   /// @returns a cuboid3D mask that is equivalent to the minimum local aabb.
0277   DETRAY_HOST_DEVICE
0278   auto local_min_bounds(
0279       const scalar_type env = std::numeric_limits<scalar_type>::epsilon()) const
0280       -> mask<cuboid3D, algebra_t, unsigned int> {
0281     const auto bounds =
0282         get_shape().template local_min_bounds<algebra_t>(_values, env);
0283     static_assert(bounds.size() == cuboid3D::e_size,
0284                   "Shape returns incompatible bounds for bound box");
0285     return {bounds, std::numeric_limits<unsigned int>::max()};
0286   }
0287 
0288   /// @brief Vertices of the mask in local cartesian coordinates.
0289   ///
0290   /// Computes vertices along the mask boundary.
0291   ///
0292   /// @param n_seg the number of segments in for arcs
0293   ///
0294   /// @returns a vector of vertices.
0295   DETRAY_HOST
0296   auto vertices(const dindex n_seg) const -> dvector<point3_type> {
0297     return get_shape().template vertices<algebra_t>(_values, n_seg);
0298   }
0299 
0300   /// @brief Merge two masks to a bigger one of the same shape.
0301   ///
0302   /// Takes the maximum/minimum values of the boundaries, no gaps allowed.
0303   /// If the volumes links do not match, an invalid link is set.
0304   ///
0305   /// @param left the left-hand mask
0306   /// @param right the righ-thand mask
0307   ///
0308   /// @returns the merged mask.
0309   DETRAY_HOST
0310   friend mask operator+(const mask& left, const mask& right) {
0311     links_type vol_link{left.volume_link() == right.volume_link()
0312                             ? left.volume_link()
0313                             : detail::invalid_value<links_type>()};
0314     mask_values merged_vals =
0315         mask::get_shape().merge(left.values(), right.values());
0316 
0317     return {std::move(merged_vals), vol_link};
0318   }
0319 
0320   /// @returns true if the mask boundary values are consistent
0321   DETRAY_HOST
0322   constexpr bool self_check(std::ostream& os) const {
0323     const bool result = get_shape().check_consistency(_values, os);
0324 
0325     if (!result) {
0326       os << to_string();
0327     }
0328 
0329     return result;
0330   }
0331 
0332   /// @returns a string representation of the mask
0333   DETRAY_HOST
0334   auto to_string() const -> std::string {
0335     std::stringstream ss;
0336     ss << std::string(shape::name);
0337     for (const auto& v : _values) {
0338       ss << ", " << v;
0339     }
0340     return ss.str();
0341   }
0342 
0343   /// @returns a string stream that prints the mask details
0344   DETRAY_HOST
0345   friend std::ostream& operator<<(std::ostream& os, const mask& m) {
0346     os << m.to_string();
0347     return os;
0348   }
0349 
0350  private:
0351   mask_values _values{};
0352   links_type _volume_link{std::numeric_limits<links_type>::max()};
0353 };
0354 
0355 }  // namespace detray