Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:59:35

0001 //----------------------------------*-C++-*----------------------------------//
0002 // Copyright 2021-2024 UT-Battelle, LLC, and other Celeritas developers.
0003 // See the top-level COPYRIGHT file for details.
0004 // SPDX-License-Identifier: (Apache-2.0 OR MIT)
0005 //---------------------------------------------------------------------------//
0006 //! \file geocel/BoundingBox.hh
0007 //---------------------------------------------------------------------------//
0008 #pragma once
0009 
0010 #include <cmath>
0011 #include <type_traits>
0012 
0013 #include "corecel/Assert.hh"
0014 #include "corecel/Macros.hh"
0015 #include "corecel/Types.hh"
0016 #include "corecel/cont/Array.hh"
0017 #include "corecel/math/NumericLimits.hh"
0018 
0019 #include "Types.hh"
0020 
0021 namespace celeritas
0022 {
0023 //---------------------------------------------------------------------------//
0024 /*!
0025  * Axis-aligned bounding box.
0026  *
0027  * Bounding boxes "contain" all points inside \em and on their faces. See \c
0028  * is_inside in \c BoundingBoxUtils.hh .
0029  *
0030  * The default bounding box is "null", which has at least one \c lower
0031  * coordinate greater than its \c upper coordinate: it evaluates to \c false .
0032  * A null bounding box still has the ability to be unioned and intersected with
0033  * other bounding boxes with the expected effect, but geometrical operations on
0034  * it (center, surface area, volume) are prohibited.
0035  *
0036  * A "degenerate" bounding box is one that is well-defined but has zero volume
0037  * because at least one lower coordinate is equal to the corresponding upper
0038  * coordinate. Any point on the surface of this bounding box is still "inside".
0039  * It may have nonzero surface area but will have zero volume.
0040  */
0041 template<class T = ::celeritas::real_type>
0042 class BoundingBox
0043 {
0044   public:
0045     //!@{
0046     //! \name Type aliases
0047     using real_type = T;
0048     using Real3 = Array<real_type, 3>;
0049     //!@}
0050 
0051   public:
0052     // Construct from infinite extents
0053     static inline CELER_FUNCTION BoundingBox from_infinite();
0054 
0055     // Construct from unchecked lower/upper bounds
0056     static CELER_CONSTEXPR_FUNCTION BoundingBox
0057     from_unchecked(Real3 const& lower, Real3 const& upper);
0058 
0059     // Construct in unassigned state
0060     CELER_CONSTEXPR_FUNCTION BoundingBox();
0061 
0062     // Construct from upper and lower points
0063     inline CELER_FUNCTION BoundingBox(Real3 const& lower, Real3 const& upper);
0064 
0065     //// ACCESSORS ////
0066 
0067     //! Lower bbox coordinate
0068     CELER_CONSTEXPR_FUNCTION Real3 const& lower() const
0069     {
0070         return this->point(Bound::lo);
0071     }
0072 
0073     //! Upper bbox coordinate
0074     CELER_CONSTEXPR_FUNCTION Real3 const& upper() const
0075     {
0076         return this->point(Bound::hi);
0077     }
0078 
0079     //! Access a bounding point
0080     CELER_CONSTEXPR_FUNCTION Real3 const& point(Bound b) const
0081     {
0082         return points_[to_int(b)];
0083     }
0084 
0085     // Whether the bbox is non-null
0086     CELER_CONSTEXPR_FUNCTION explicit operator bool() const;
0087 
0088     //// MUTATORS ////
0089 
0090     // Reduce the bounding box's extent along an axis
0091     CELER_CONSTEXPR_FUNCTION void
0092     shrink(Bound bnd, Axis axis, real_type position);
0093 
0094     // Increase the bounding box's extent along an axis
0095     CELER_CONSTEXPR_FUNCTION void
0096     grow(Bound bnd, Axis axis, real_type position);
0097 
0098     // Increase the bounding box's extent on both bounds
0099     CELER_CONSTEXPR_FUNCTION void grow(Axis axis, real_type position);
0100 
0101   private:
0102     Array<Real3, 2> points_;  //!< lo/hi points
0103 
0104     // Implementation of 'from_unchecked' (true type 'tag')
0105     CELER_CONSTEXPR_FUNCTION
0106     BoundingBox(std::true_type, Real3 const& lower, Real3 const& upper);
0107 };
0108 
0109 //---------------------------------------------------------------------------//
0110 // TYPE ALIASES
0111 //---------------------------------------------------------------------------//
0112 
0113 //! Bounding box for host metadata
0114 using BBox = BoundingBox<>;
0115 
0116 //---------------------------------------------------------------------------//
0117 // INLINE FREE FUNCTIONS
0118 //---------------------------------------------------------------------------//
0119 /*!
0120  * Test equality of two bounding boxes.
0121  */
0122 template<class T>
0123 CELER_CONSTEXPR_FUNCTION bool
0124 operator==(BoundingBox<T> const& lhs, BoundingBox<T> const& rhs)
0125 {
0126     return lhs.lower() == rhs.lower() && lhs.upper() == rhs.upper();
0127 }
0128 
0129 //---------------------------------------------------------------------------//
0130 /*!
0131  * Test inequality of two bounding boxes.
0132  */
0133 template<class T>
0134 CELER_CONSTEXPR_FUNCTION bool
0135 operator!=(BoundingBox<T> const& lhs, BoundingBox<T> const& rhs)
0136 {
0137     return !(lhs == rhs);
0138 }
0139 
0140 //---------------------------------------------------------------------------//
0141 /*!
0142  * Determine if a point is contained in a bounding box.
0143  *
0144  * No point is ever contained in a null bounding box. A degenerate bounding
0145  * box will return "true" for any point on its face.
0146  */
0147 template<class T, class U>
0148 CELER_CONSTEXPR_FUNCTION bool
0149 is_inside(BoundingBox<T> const& bbox, Array<U, 3> const& point)
0150 {
0151     return bbox.lower()[0] <= point[0] && point[0] <= bbox.upper()[0]
0152            && bbox.lower()[1] <= point[1] && point[1] <= bbox.upper()[1]
0153            && bbox.lower()[2] <= point[2] && point[2] <= bbox.upper()[2];
0154 }
0155 
0156 //---------------------------------------------------------------------------//
0157 // INLINE DEFINITIONS
0158 //---------------------------------------------------------------------------//
0159 /*!
0160  * Create a bounding box with infinite extents.
0161  */
0162 template<class T>
0163 CELER_FUNCTION BoundingBox<T> BoundingBox<T>::from_infinite()
0164 {
0165     constexpr real_type inf = numeric_limits<real_type>::infinity();
0166     return {{-inf, -inf, -inf}, {inf, inf, inf}};
0167 }
0168 
0169 //---------------------------------------------------------------------------//
0170 /*!
0171  * Create a bounding box from unchecked lower/upper bounds.
0172  *
0173  * This should be used exclusively for utilities that understand the
0174  * "null" implementation of the bounding box.
0175  */
0176 template<class T>
0177 CELER_CONSTEXPR_FUNCTION BoundingBox<T>
0178 BoundingBox<T>::from_unchecked(Real3 const& lo, Real3 const& hi)
0179 {
0180     return BoundingBox<T>{std::true_type{}, lo, hi};
0181 }
0182 
0183 //---------------------------------------------------------------------------//
0184 /*!
0185  * Create a null bounding box.
0186  *
0187  * This should naturally satisfy
0188  * \code
0189         calc_union(BBox{}, other) = other:
0190    \endcode
0191  *  and
0192  * \code
0193         calc_intersection(BBox{}, other) = other;
0194    \endcode
0195  */
0196 template<class T>
0197 CELER_CONSTEXPR_FUNCTION BoundingBox<T>::BoundingBox()
0198 {
0199     constexpr real_type inf = numeric_limits<real_type>::infinity();
0200     points_[to_int(Bound::lo)] = {inf, inf, inf};
0201     points_[to_int(Bound::hi)] = {-inf, -inf, -inf};
0202 }
0203 
0204 //---------------------------------------------------------------------------//
0205 /*!
0206  * Create a non-null bounding box from two points.
0207  *
0208  * The lower and upper points are allowed to be equal (an empty bounding box
0209  * at a single point) but upper must not be less than lower.
0210  */
0211 template<class T>
0212 CELER_FUNCTION BoundingBox<T>::BoundingBox(Real3 const& lo, Real3 const& hi)
0213     : points_{{lo, hi}}
0214 {
0215     if constexpr (CELERITAS_DEBUG)
0216     {
0217         for (auto ax : {Axis::x, Axis::y, Axis::z})
0218         {
0219             CELER_EXPECT(this->lower()[to_int(ax)]
0220                          <= this->upper()[to_int(ax)]);
0221         }
0222     }
0223     CELER_ENSURE(*this);
0224 }
0225 
0226 //---------------------------------------------------------------------------//
0227 /*!
0228  * Create a possibly null bounding box from two points.
0229  */
0230 template<class T>
0231 CELER_CONSTEXPR_FUNCTION
0232 BoundingBox<T>::BoundingBox(std::true_type, Real3 const& lo, Real3 const& hi)
0233     : points_{{lo, hi}}
0234 {
0235 }
0236 
0237 //---------------------------------------------------------------------------//
0238 /*!
0239  * Whether the bbox is in a valid state.
0240  */
0241 template<class T>
0242 CELER_CONSTEXPR_FUNCTION BoundingBox<T>::operator bool() const
0243 {
0244     return this->lower()[0] <= this->upper()[0]
0245            && this->lower()[1] <= this->upper()[1]
0246            && this->lower()[2] <= this->upper()[2];
0247 }
0248 
0249 //---------------------------------------------------------------------------//
0250 /*!
0251  * Reduce (clip) the bounding box's extent along an axis.
0252  *
0253  * If the point is inside the box, the box is clipped so the given boundary is
0254  * on that point. Otherwise no change is made.
0255  */
0256 template<class T>
0257 CELER_CONSTEXPR_FUNCTION void
0258 BoundingBox<T>::shrink(Bound bnd, Axis axis, real_type position)
0259 {
0260     real_type p = points_[to_int(bnd)][to_int(axis)];
0261     if (bnd == Bound::lo)
0262     {
0263         p = std::fmax(p, position);
0264     }
0265     else
0266     {
0267         p = std::fmin(p, position);
0268     }
0269     points_[to_int(bnd)][to_int(axis)] = p;
0270 }
0271 
0272 //---------------------------------------------------------------------------//
0273 /*!
0274  * Increase (expand) the bounding box's extent along an axis.
0275  *
0276  * If the point is outside the box, the box is expanded so the given boundary
0277  * is on that point. Otherwise no change is made.
0278  */
0279 template<class T>
0280 CELER_CONSTEXPR_FUNCTION void
0281 BoundingBox<T>::grow(Bound bnd, Axis axis, real_type position)
0282 {
0283     real_type p = points_[to_int(bnd)][to_int(axis)];
0284     if (bnd == Bound::lo)
0285     {
0286         p = std::fmin(p, position);
0287     }
0288     else
0289     {
0290         p = std::fmax(p, position);
0291     }
0292     points_[to_int(bnd)][to_int(axis)] = p;
0293 }
0294 
0295 //---------------------------------------------------------------------------//
0296 /*!
0297  * Increase (expand) the bounding box's extent along an axis.
0298  *
0299  * If the point is outside the box, the box is expanded so the given boundary
0300  * is on that point. Otherwise no change is made.
0301  */
0302 template<class T>
0303 CELER_CONSTEXPR_FUNCTION void
0304 BoundingBox<T>::grow(Axis axis, real_type position)
0305 {
0306     this->grow(Bound::lo, axis, position);
0307     this->grow(Bound::hi, axis, position);
0308 }
0309 
0310 //---------------------------------------------------------------------------//
0311 }  // namespace celeritas