Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-11-05 10:42:59

0001 //------------------------------- -*- C++ -*- -------------------------------//
0002 // Copyright Celeritas contributors: see top-level COPYRIGHT file for details
0003 // SPDX-License-Identifier: (Apache-2.0 OR MIT)
0004 //---------------------------------------------------------------------------//
0005 //! \file orange/orangeinp/IntersectRegion.hh
0006 //! \brief Contains IntersectRegionInterface and concrete daughters
0007 //---------------------------------------------------------------------------//
0008 #pragma once
0009 
0010 #include <vector>
0011 
0012 #include "corecel/Macros.hh"
0013 #include "corecel/cont/Array.hh"
0014 #include "corecel/cont/EnumArray.hh"
0015 #include "corecel/grid/GridTypes.hh"
0016 #include "corecel/math/Turn.hh"
0017 #include "orange/OrangeTypes.hh"
0018 
0019 namespace celeritas
0020 {
0021 struct JsonPimpl;
0022 
0023 namespace orangeinp
0024 {
0025 class IntersectSurfaceBuilder;
0026 
0027 //---------------------------------------------------------------------------//
0028 /*!
0029  * Interface class for building non-reentrant spatial regions.
0030  *
0031  * This is a building block for constructing more complex objects out of
0032  * smaller spatial regions. A \c shape object will have a single intersect
0033  * region, and a \c solid object region may have multiple adjacent intersect
0034  * regions.
0035  *
0036  * Convex regions should be as minimal as possible and rely on transformations
0037  * to change axes, displacement, etc. As a general rule, the exterior bounding
0038  * box of a intersect region should be <em>centered on the origin</em>, and
0039  * objects should be aligned along the \em z axis.
0040  *
0041  * When implementing this class, prefer to build simpler surfaces (planes)
0042  * before complex ones (cones) in case we implement short-circuiting logic,
0043  * since expressions are currently sorted.
0044  *
0045  * \note Additional methods such as volume calculation may be added here later.
0046  */
0047 class IntersectRegionInterface
0048 {
0049   public:
0050     //! Construct surfaces that are AND-ed into this region
0051     virtual void build(IntersectSurfaceBuilder&) const = 0;
0052 
0053     //! Write the region to a JSON object
0054     virtual void output(JsonPimpl*) const = 0;
0055 
0056     virtual ~IntersectRegionInterface() = default;
0057 
0058   protected:
0059     //!@{
0060     //! Allow construction and assignment only through daughter classes
0061     IntersectRegionInterface() = default;
0062     CELER_DEFAULT_COPY_MOVE(IntersectRegionInterface);
0063     //!@}
0064 };
0065 
0066 //---------------------------------------------------------------------------//
0067 /*!
0068  * A rectangular parallelepiped/cuboid centered on the origin.
0069  *
0070  * The box is constructed with half-widths.
0071  */
0072 class Box final : public IntersectRegionInterface
0073 {
0074   public:
0075     // Construct with half-widths
0076     explicit Box(Real3 const& halfwidths);
0077 
0078     // Build surfaces
0079     void build(IntersectSurfaceBuilder&) const final;
0080 
0081     // Output to JSON
0082     void output(JsonPimpl*) const final;
0083 
0084     //// ACCESSORS ////
0085 
0086     //! Half-width for each axis
0087     Real3 const& halfwidths() const { return hw_; }
0088 
0089   private:
0090     Real3 hw_;
0091 };
0092 
0093 //---------------------------------------------------------------------------//
0094 /*!
0095  * A closed truncated cone along the *z* axis centered on the origin.
0096  *
0097  * A quadric cone technically defines two opposing cones that touch at a single
0098  * vanishing point, but this cone is required to be truncated so that the
0099  * vanishing point is on our outside the cone.
0100  *
0101  * The midpoint along the \em z axis of the cone is the origin. A cone is \em
0102  * not allowed to have equal radii: for that, use a cylinder. However, it \em
0103  * may have a single radius of zero, which puts the vanishing point on one end
0104  * of the cone.
0105  *
0106  * This intersect region, along with the Cylinder, is a base component of the
0107  * G4Polycone (PCON).
0108  *
0109  * \note The Cone is allowed to be "degenerate" in the sense of
0110  * having nearly equal lower and upper radii. It will construct a cylinder with
0111  * an average of the two radii.
0112  */
0113 class Cone final : public IntersectRegionInterface
0114 {
0115   public:
0116     // Construct with Z half-height and lo, hi radii
0117     Cone(Real2 const& radii, real_type halfheight);
0118 
0119     //// INTERFACE ////
0120 
0121     // Build surfaces
0122     void build(IntersectSurfaceBuilder&) const final;
0123 
0124     // Output to JSON
0125     void output(JsonPimpl*) const final;
0126 
0127     //// TEMPLATE INTERFACE ////
0128 
0129     // Whether this encloses another cone
0130     bool encloses(Cone const& other) const;
0131 
0132     //// ACCESSORS ////
0133 
0134     //! Lower and upper radii
0135     Real2 const& radii() const { return radii_; }
0136 
0137     //! Half-height along Z
0138     real_type halfheight() const { return hh_; }
0139 
0140   private:
0141     Real2 radii_;
0142     real_type hh_;
0143 };
0144 
0145 //---------------------------------------------------------------------------//
0146 /*!
0147  * A *z*-aligned cylinder centered on the origin, with top/bottom cuts.
0148  *
0149  * The shape is defined with a radius, half-height, and the outward-facing
0150  * normals of the cutting planes, passing through \f$(0, 0, \pm
0151  * \mathrm{hh})\f$.
0152  */
0153 class CutCylinder final : public IntersectRegionInterface
0154 {
0155   public:
0156     // Construct with radius, half-height, and bottom/top cut plane normals
0157     CutCylinder(real_type radius,
0158                 real_type halfheight,
0159                 Real3 const& bottom_normal,
0160                 Real3 const& top_normal);
0161 
0162     // Build surfaces
0163     void build(IntersectSurfaceBuilder&) const final;
0164 
0165     // Output to JSON
0166     void output(JsonPimpl*) const final;
0167 
0168     //// TEMPLATE INTERFACE ////
0169 
0170     // Whether this encloses another cut cylinder
0171     bool encloses(CutCylinder const& other) const;
0172 
0173     //// ACCESSORS ////
0174 
0175     //! Radius
0176     real_type radius() const { return radius_; }
0177 
0178     //! Half-height along Z
0179     real_type halfheight() const { return hh_; }
0180 
0181     //! Outward-facing normal of the bottom cuting plane
0182     Real3 const& bottom_normal() const { return bot_normal_; }
0183 
0184     //! Outward-facing normal of the top cuting plane
0185     Real3 const& top_normal() const { return top_normal_; }
0186 
0187   private:
0188     real_type radius_;
0189     real_type hh_;
0190     Real3 bot_normal_;
0191     Real3 top_normal_;
0192 };
0193 
0194 //---------------------------------------------------------------------------//
0195 /*!
0196  * A *z*-aligned cylinder centered on the origin.
0197  *
0198  * The cylinder is defined with a radius and half-height.
0199  */
0200 class Cylinder final : public IntersectRegionInterface
0201 {
0202   public:
0203     // Construct with radius
0204     Cylinder(real_type radius, real_type halfheight);
0205 
0206     // Build surfaces
0207     void build(IntersectSurfaceBuilder&) const final;
0208 
0209     // Output to JSON
0210     void output(JsonPimpl*) const final;
0211 
0212     //// TEMPLATE INTERFACE ////
0213 
0214     // Whether this encloses another cylinder
0215     bool encloses(Cylinder const& other) const;
0216 
0217     //// ACCESSORS ////
0218 
0219     //! Radius
0220     real_type radius() const { return radius_; }
0221 
0222     //! Half-height along Z
0223     real_type halfheight() const { return hh_; }
0224 
0225   private:
0226     real_type radius_;
0227     real_type hh_;
0228 };
0229 
0230 //---------------------------------------------------------------------------//
0231 /*!
0232  * An axis-aligned ellipsoid centered at the origin.
0233  *
0234  * The ellipsoid is constructed with the three radial lengths. For a length
0235  * scale \em L , the quadric it creates has second-order terms that are \f$
0236  * O(1) \f$ and a zeroth order term that's \f$ O(L^2) \f$. Translations on that
0237  * length scale will preserve the accuracy of the quadratic solution.
0238  *
0239  * There are many scalings of the quadric equation that produce unitary
0240  * second-order terms if the ellipsoid's radii are identical: \f[
0241   \frac{k}{r_x^2} x^2 +  \frac{k}{r_y^2} y^2 +  \frac{k}{r_z^2} z^2 = k
0242  * \f]
0243  * but we make the ad hoc decision to choose \f$ k = \min r_i \max r_i \f$
0244  * to avoid irrational normalization constants, which makes unit tests and
0245  * output easier to read.
0246  */
0247 class Ellipsoid final : public IntersectRegionInterface
0248 {
0249   public:
0250     // Construct with radius along each Cartesian axis
0251     explicit Ellipsoid(Real3 const& radii);
0252 
0253     // Build surfaces
0254     void build(IntersectSurfaceBuilder&) const final;
0255 
0256     // Output to JSON
0257     void output(JsonPimpl*) const final;
0258 
0259     //// TEMPLATE INTERFACE ////
0260 
0261     // Whether this encloses another ellipsoid
0262     bool encloses(Ellipsoid const& other) const;
0263 
0264     //// ACCESSORS ////
0265 
0266     //! Radius along each axis
0267     Real3 const& radii() const { return radii_; }
0268 
0269     //! Get the radius along a single axis
0270     real_type radius(Axis ax) const { return radii_[to_int(ax)]; }
0271 
0272   private:
0273     Real3 radii_;
0274 };
0275 
0276 //---------------------------------------------------------------------------//
0277 /*!
0278  * A *z*-aligned cylinder with an elliptical cross section.
0279  *
0280  * The elliptical cylinder is defined with a two radii and a half-height,
0281  * such that the centroid of the bounding box is origin. The quadric
0282  * coefficient of the cylindrical component, \f[
0283   x^2 / r_x^2 + y^2 / r_y^2 = 1 \,
0284   \f]
0285  * are scaled based on the radii of the cylinder, reducing to
0286  * \f$ x^2 + y^2 = R^2 \f$ when the radii are equal.
0287  */
0288 class EllipticalCylinder final : public IntersectRegionInterface
0289 {
0290   public:
0291     // Construct with x- and y-radii and half-height in z
0292     EllipticalCylinder(Real2 const& radii, real_type halfheight);
0293 
0294     // Build surfaces
0295     void build(IntersectSurfaceBuilder&) const final;
0296 
0297     // Output to JSON
0298     void output(JsonPimpl*) const final;
0299 
0300     //// TEMPLATE INTERFACE ////
0301 
0302     // Whether this encloses another ellipsoid
0303     bool encloses(EllipticalCylinder const& other) const;
0304 
0305     //// ACCESSORS ////
0306 
0307     //! Radius along each axis
0308     Real2 const& radii() const { return radii_; }
0309 
0310     //! Half-height along Z
0311     real_type halfheight() const { return hh_; }
0312 
0313     // Get the radius along the x/y axis
0314     real_type radius(Axis ax) const;
0315 
0316   private:
0317     Real2 radii_;
0318     real_type hh_;
0319 };
0320 
0321 //---------------------------------------------------------------------------//
0322 /*!
0323  * A finite \em z-aligned cone with an elliptical cross section.
0324  *
0325  * The elliptical cone is defined in an analogous fashion to the regular
0326  * (i.e., circular) cone. A half-height (hh) defines the \em z extents, such
0327  * that the centroid of the outer bounding box is the origin. The lower radii
0328  * are the \em x  and \em y radii at the plane \f$ z = -\mathrm{hh} \f$.
0329  * The upper radii are the \em x and \em y radii at the plane
0330  * \f$ z = \mathrm{hh} \f$. There are several restrictions on these radii:
0331  *
0332  * - Either the lower or upper radii may be \f$(0, 0)\f$; this is the only
0333  *   permitted way for the elliptical cone to include the vertex.
0334  * - The aspect ratio of the elliptical cross sections is constant. Thus, the
0335  *   upper radii must be a constant scalar times the upper radii.
0336  * - Degenerate elliptical cones (lower_radii == upper_radii, i.e.,
0337  *   elliptical cylinders) are not permitted.
0338  * - Degenerate elliptical cones where lower or upper radii are equal to
0339  *   \f$(0, x)\f$ or \f$(x, 0)\f$, where \em x is non-zero, are not permitted.
0340  *
0341  * The elliptical surface can be expressed as
0342  * \f[
0343    (x/r_x)^2 + (y/r_y)^2 = (v-z)^2,
0344  * \f]
0345  * where \em v is the location of the vertex.
0346  *
0347  * The \f$ r_x \f$, \f$r_y \f$, and \f$v\f$ can be calculated from the lower
0348  * and upper radii as given by \c G4EllipticalCone:
0349  * \verbatim
0350    r_x = (lower_radii[X] - upper_radii[X])/(2 hh),
0351    r_y = (lower_radii[Y] - upper_radii[Y])/(2 hh),
0352      v = hh (lower_radii[X] + upper_radii[X])
0353          / (lower_radii[X] - upper_radii[X]).
0354    \endverbatim
0355  */
0356 class EllipticalCone final : public IntersectRegionInterface
0357 {
0358   public:
0359     // Construct with x- and y-radii and half-height in z
0360     EllipticalCone(Real2 const& lower_radii,
0361                    Real2 const& upper_radii,
0362                    real_type halfheight);
0363 
0364     // Build surfaces
0365     void build(IntersectSurfaceBuilder&) const final;
0366 
0367     // Output to JSON
0368     void output(JsonPimpl*) const final;
0369 
0370     //// TEMPLATE INTERFACE ////
0371 
0372     // Whether this encloses another elliptical cone
0373     bool encloses(EllipticalCone const& other) const;
0374 
0375     //// ACCESSORS ////
0376 
0377     //! Radii along the x- and y-axes at z=-hh
0378     Real2 const& lower_radii() const { return lower_radii_; }
0379 
0380     //! Radii along the x- and y-axes at z=-hh
0381     Real2 const& upper_radii() const { return upper_radii_; }
0382 
0383     //! Half-height along Z
0384     real_type halfheight() const { return hh_; }
0385 
0386     // Get the bottom/top radius along the x/y axis
0387     real_type radius(Bound b, Axis ax) const;
0388 
0389   private:
0390     Real2 lower_radii_;
0391     Real2 upper_radii_;
0392     real_type hh_;
0393 };
0394 
0395 //---------------------------------------------------------------------------//
0396 /*!
0397  * Region formed by extruding + scaling a convex polygon along a line segment.
0398  *
0399  * The convex polygon is supplied as a set of points on the \em xy plane in
0400  * counterclockwise order. The line segment and scaling factors are specified
0401  * by providing a line segment point and scaling factor for the top and bottom
0402  * polygon faces of the region. The line segment point of the top face must
0403  * have a \em z value greater than that of the bottom face. Along the line
0404  * segment,
0405  * the size of the polygon is linearly scaled in accordance with scaling
0406  * factors.
0407  *
0408  * As is done in Geant4, construction is done by first applying scaling factors
0409  * to the upper and lower polygons via scalar multiplication with each polygon
0410  * point, then the points on the line are used to offset the upper and lower
0411  * polygons.
0412  */
0413 class ExtrudedPolygon final : public IntersectRegionInterface
0414 {
0415   public:
0416     //!@{
0417     //! \name Type aliases
0418     using VecReal2 = std::vector<Real2>;
0419 
0420     //! Specifies the top or bottom face of the ExtrudedPolygon
0421     struct PolygonFace
0422     {
0423         //! Start or end point of the line segment the polygon is extruded
0424         //! along
0425         Real3 line_segment_point{};
0426 
0427         //! The fractional amount this face is scaled
0428         real_type scaling_factor{};
0429     };
0430     //!@}
0431 
0432   public:
0433     // Construct from a convex polygon and bottom/top faces
0434     ExtrudedPolygon(VecReal2 const& polygon,
0435                     PolygonFace const& bot_face,
0436                     PolygonFace const& top_face);
0437 
0438     // Build surfaces
0439     void build(IntersectSurfaceBuilder&) const final;
0440 
0441     // Output to JSON
0442     void output(JsonPimpl*) const final;
0443 
0444     //// ACCESSORS ////
0445 
0446     //! Polygon points (2D)
0447     VecReal2 polygon() const { return polygon_; }
0448 
0449     //! Bottom point of the line segment
0450     Real3 bot_line_segment_point() const { return line_segment_[Bound::lo]; }
0451 
0452     //! Top point of the line segment
0453     Real3 top_line_segment_point() const { return line_segment_[Bound::hi]; }
0454 
0455     //! Bottom scaling factor
0456     real_type bot_scaling_factor() const
0457     {
0458         return scaling_factors_[Bound::lo];
0459     }
0460 
0461     //! Top scaling factor
0462     real_type top_scaling_factor() const
0463     {
0464         return scaling_factors_[Bound::hi];
0465     }
0466 
0467   private:
0468     //// TYPES ////
0469     using Range = celeritas::Array<real_type, 2>;
0470 
0471     //// DATA ////
0472 
0473     VecReal2 polygon_;
0474 
0475     EnumArray<Bound, Real3> line_segment_;
0476     EnumArray<Bound, real_type> scaling_factors_;
0477 
0478     Range x_range_;
0479     Range y_range_;
0480 
0481     //// HELPER FUNCTIONS ////
0482 
0483     // Calculate the min/max x or y values of the extruded region
0484     Range calc_range(VecReal2 const& polygon, size_type dim);
0485 };
0486 
0487 //---------------------------------------------------------------------------//
0488 /*!
0489  * A generalized polygon with parallel flat faces along the *z* axis.
0490  *
0491  * A GenPrism, like VecGeom's GenTrap, ROOT's Arb8, and Geant4's
0492  * G4GenericTrap, represents a generalized volume with polyhedral faces on two
0493  * parallel planes perpendicular to the \em z axis. Unlike those other codes,
0494  * the number of faces can be arbitrary in number.
0495  *
0496  * The faces have an orientation and ordering so that \em twisted faces can be
0497  * constructed by joining corresponding points using straight-line "vertical"
0498  * edges, directly matching the G4GenericTrap definition, but directly
0499  * generating a hyperbolic paraboloid for each twisted face.
0500  *
0501  * Trapezoids constructed from the helper functions will have sides that are
0502  * same ordering as a prism: the rightward face is first (normal is along the
0503  * \em +x axis), then the others follow counterclockwise.
0504  */
0505 class GenPrism final : public IntersectRegionInterface
0506 {
0507   public:
0508     //!@{
0509     //! \name Type aliases
0510     using VecReal2 = std::vector<Real2>;
0511     //!@}
0512 
0513     //! Regular trapezoidal top/bottom face
0514     struct TrapFace
0515     {
0516         //! Half the vertical distance between horizontal edges
0517         real_type hy{};
0518         //! Top horizontal edge half-length
0519         real_type hx_lo{};
0520         //! Bottom horizontal edge half-length
0521         real_type hx_hi{};
0522         //! Shear angle between horizontal line centers and Y axis
0523         Turn alpha;
0524     };
0525 
0526   public:
0527     // Helper function to construct a Trd shape from hz and two rectangles,
0528     // one for each z-face
0529     static GenPrism from_trd(real_type halfz, Real2 const& lo, Real2 const& hi);
0530 
0531     // Helper function to construct a general trap from its half-height and
0532     // the two trapezoids defining its lower and upper faces
0533     static GenPrism from_trap(real_type hz,
0534                               Turn theta,
0535                               Turn phi,
0536                               TrapFace const& lo,
0537                               TrapFace const& hi);
0538 
0539     // Construct from half Z height and 4 vertices for top and bottom planes
0540     GenPrism(real_type halfz, VecReal2 const& lo, VecReal2 const& hi);
0541 
0542     // Build surfaces
0543     void build(IntersectSurfaceBuilder&) const final;
0544 
0545     // Output to JSON
0546     void output(JsonPimpl*) const final;
0547 
0548     //// ACCESSORS ////
0549 
0550     //! Half-height along Z
0551     real_type halfheight() const { return hh_; }
0552 
0553     //! Polygon on -z face
0554     VecReal2 const& lower() const { return lo_; }
0555 
0556     //! Polygon on +z face
0557     VecReal2 const& upper() const { return hi_; }
0558 
0559     //! Number of sides (points on the Z face)
0560     size_type num_sides() const { return lo_.size(); }
0561 
0562     // Calculate the cosine of the twist angle for a given side
0563     real_type calc_twist_cosine(size_type size_idx) const;
0564 
0565   private:
0566     enum class Degenerate
0567     {
0568         none,
0569         lo,
0570         hi
0571     };
0572 
0573     real_type hh_;  //!< half-height
0574     VecReal2 lo_;  //!< corners of the -z face (CCW)
0575     VecReal2 hi_;  //!< corners of the +z face (CCW)
0576     Degenerate degen_{Degenerate::none};  //!< no plane on this z axis
0577     real_type length_scale_{};
0578 };
0579 // ...existing code...
0580 
0581 //---------------------------------------------------------------------------//
0582 /*!
0583  * A *z*-aligned hyperboloid of revolution centered on the origin.
0584  *
0585  * A hyperboloid is defined by rotating a hyperbola around the z-axis. This
0586  * implementation uses a minimum radius (at \f$ z=0 \f$) and a maximum radius
0587  * (at \f$z=\pm \textrm{hh}\f$).
0588  *
0589  * The hyperboloid surface is defined by the equation:
0590  * \f[
0591  *   x^2 + y^2 - r_{min}^2 \left(1 + z^2 t^2\right) = 0
0592  * \f]
0593  * where \f$ r_{min} \f$ is the minimum radius (at z=0) and
0594  * \f$ t^2 = (r_{max}^2 - r_{min}^2) / h^2 \f$, with \f$ r_{max} \f$
0595  * being the maximum radius and \f$ h \f$ the half-height.
0596  *
0597  * The maximum radius must be greater than the minimum radius, ensuring a valid
0598  * hyperboloid shape. The minimum radius must be positive, as a radius of zero
0599  * would produce a two-sheeted cone.
0600  */
0601 class Hyperboloid final : public IntersectRegionInterface
0602 {
0603   public:
0604     // Construct with radius at midpoint (min) and end (max), and half-height
0605     Hyperboloid(
0606         real_type min_radius, real_type max_radius, real_type halfheight);
0607 
0608     // Build surfaces
0609     void build(IntersectSurfaceBuilder&) const final;
0610 
0611     // Output to JSON
0612     void output(JsonPimpl*) const final;
0613 
0614     //// TEMPLATE INTERFACE ////
0615 
0616     // Whether this encloses another hyperboloid
0617     bool encloses(Hyperboloid const& other) const;
0618 
0619     //// ACCESSORS ////
0620 
0621     //! Minimum radius at z=0
0622     real_type min_radius() const { return r_min_; }
0623 
0624     //! Maximum radius at |z|=hh
0625     real_type max_radius() const { return r_max_; }
0626 
0627     //! Half-height along z
0628     real_type halfheight() const { return hh_; }
0629 
0630   private:
0631     real_type r_min_;  //!< Minimum radius at z=0
0632     real_type r_max_;  //!< Maximum radius at |z|=hh
0633     real_type hh_;  //!< Half-height along z
0634 };
0635 
0636 //---------------------------------------------------------------------------//
0637 /*!
0638  * An axis-aligned infinite half-space to use for truncation operations.
0639  *
0640  * An "inside" sense means to include everything *below* the position on the
0641  * axis, and an "outside" sense means to include only what's *above* the
0642  * position.
0643  */
0644 class InfPlane : public IntersectRegionInterface
0645 {
0646   public:
0647     // Construct with sense, axis, and position
0648     InfPlane(Sense sense, Axis axis, real_type position);
0649 
0650     // Build surfaces
0651     void build(IntersectSurfaceBuilder&) const final;
0652 
0653     // Output to JSON
0654     void output(JsonPimpl*) const final;
0655 
0656     //// ACCESSORS ////
0657 
0658     //! Get the sense (inside or outside)
0659     Sense sense() const { return sense_; }
0660 
0661     //! Get the axis (x, y, or z)
0662     Axis axis() const { return axis_; }
0663 
0664     //! Get the position along the axis
0665     real_type position() const { return position_; }
0666 
0667   private:
0668     Sense sense_;
0669     Axis axis_;
0670     real_type position_;
0671 };
0672 
0673 //---------------------------------------------------------------------------//
0674 /*!
0675  * An open wedge shape from the *z* axis.
0676  *
0677  * The wedge is defined by an interior angle that \em must be less than or
0678  * equal to 180 degrees (half a turn) and \em must be more than zero. It can be
0679  * subtracted, or its negation can be subtracted. The start angle is mapped
0680  * onto \f$[0, 1)\f$ on construction.
0681  */
0682 class InfAziWedge final : public IntersectRegionInterface
0683 {
0684   public:
0685     // Construct from an angular range less than 180
0686     InfAziWedge(Turn start, Turn stop);
0687 
0688     // Build surfaces
0689     void build(IntersectSurfaceBuilder&) const final;
0690 
0691     // Output to JSON
0692     void output(JsonPimpl*) const final;
0693 
0694     //// ACCESSORS ////
0695 
0696     //! Starting angle
0697     Turn start() const { return start_; }
0698 
0699     //! stop angle
0700     Turn stop() const { return stop_; }
0701 
0702   private:
0703     Turn start_;
0704     Turn stop_;
0705 };
0706 
0707 //---------------------------------------------------------------------------//
0708 /*!
0709  * Select a polar (latitudinal) region.
0710  *
0711  * This uses an equatorial plane and up to two cones to slice a
0712  * polar-coordinate region from the origin.  A polar wedge always defines a
0713  * region in a single hemisphere: either \f$ z >= 0 \f$ or \f$ z <= 0 \f$,
0714  * corresponding to an stop range of [0, .25] turns or [0.25, 0.5] turns.
0715  */
0716 class InfPolarWedge final : public IntersectRegionInterface
0717 {
0718   public:
0719     // Construct from a starting angle and stop angle
0720     InfPolarWedge(Turn start, Turn stop);
0721 
0722     // Build surfaces
0723     void build(IntersectSurfaceBuilder&) const final;
0724 
0725     // Output to JSON
0726     void output(JsonPimpl*) const final;
0727 
0728     //// ACCESSORS ////
0729 
0730     //! Starting angle
0731     Turn start() const { return start_; }
0732 
0733     //! stop angle
0734     Turn stop() const { return stop_; }
0735 
0736   private:
0737     Turn start_;
0738     Turn stop_;
0739 
0740     static constexpr Turn north_pole{0};
0741     static constexpr Turn equator{0.25};
0742     static constexpr Turn south_pole{0.5};
0743 };
0744 
0745 //---------------------------------------------------------------------------//
0746 /*!
0747  * An involute "blade" centered on the origin.
0748  *
0749  * This is the intersection of two parallel involutes with a cylindrical shell.
0750  * The three radii, which must be in ascending order, are that of the involute,
0751  * the inner cylinder, and the outer cylinder.
0752  *
0753  * The "chirality" of the involute is viewed from the \em +z axis looking down:
0754  * whether it spirals to the right or left.
0755  */
0756 class Involute final : public IntersectRegionInterface
0757 {
0758   public:
0759     // Construct with radius
0760     explicit Involute(Real3 const& radii,
0761                       Real2 const& displacement,
0762                       Chirality chirality,
0763                       real_type halfheight);
0764 
0765     // Build surfaces
0766     void build(IntersectSurfaceBuilder&) const final;
0767 
0768     // Output to JSON
0769     void output(JsonPimpl*) const final;
0770 
0771     //// ACCESSORS ////
0772 
0773     //! Radii: Rdius of involute, minimum radius, maximum radius
0774     Real3 const& radii() const { return radii_; }
0775     //! Displacement angle
0776     Real2 const& displacement_angle() const { return a_; }
0777     //!  Angular bounds of involute
0778     Real2 const& t_bounds() const { return t_bounds_; }
0779     //! Chirality of involute: turning left or right
0780     Chirality chirality() const { return sign_; }
0781     //! Halfheight
0782     real_type halfheight() const { return hh_; }
0783 
0784   private:
0785     Real3 radii_;
0786     Real2 a_;
0787     Real2 t_bounds_;
0788     Chirality sign_;
0789     real_type hh_;
0790 };
0791 
0792 //---------------------------------------------------------------------------//
0793 /*!
0794  * A finite *z*-aligned parabolid.
0795  *
0796  * The paraboloid is defined in an analogous fashion to the cone. A half-height
0797  * (hh) defines the z-extents, such that the centroid of the outer bounding box
0798  * is the origin. The lower and upper radii correspond to the radii at
0799  * \f$ z = \pm h \f$. Either the lower or upper radii may be 0, i.e.,
0800  * the solid may include the vertex. Degenerate cases where the lower and upper
0801  * radii are equal are not permitted: a cylinder should be used instead.
0802  *
0803  * A paraboloid with these properties is expressed in SimpleQuadric form as:
0804  * \f[
0805     x^2 + y^2 + \frac{(R_{\mathrm{lo}}^2 - R_{\mathrm{hi}}^2)}{h} z
0806     - \frac{R_{\mathrm{lo}}^2 + R_{\mathrm{hi}}^2}{2} = 0,
0807  * \f]
0808  * where \f$R_{\mathrm{lo}}\f$ and \f$R_\mathrm{hi}\f$ correspond to the lower
0809  * and upper radii, respectively, and \f$h\f$ is the full height. Note that the
0810  * scaling is such that as \f$ R_{\mathrm{lo}} \to R_{\mathrm{hi}} \f$ this
0811  * approaches the cylindrical equation \f$ x^2 + y^2 = R^2 \f$.
0812  *
0813  */
0814 class Paraboloid final : public IntersectRegionInterface
0815 {
0816   public:
0817     // Construct with lower/upper radii and the half-height
0818     Paraboloid(
0819         real_type lower_radius, real_type upper_radius, real_type halfheight);
0820 
0821     // Build surfaces
0822     void build(IntersectSurfaceBuilder&) const final;
0823 
0824     // Output to JSON
0825     void output(JsonPimpl*) const final;
0826 
0827     //// TEMPLATE INTERFACE ////
0828 
0829     // Whether this encloses another paraboloid
0830     bool encloses(Paraboloid const& other) const;
0831 
0832     //// ACCESSORS ////
0833 
0834     //! Radius at z=-hh
0835     real_type lower_radius() const { return r_lo_; }
0836 
0837     //! Radius at z=hh
0838     real_type upper_radius() const { return r_hi_; }
0839 
0840     //! Half-height along Z
0841     real_type halfheight() const { return hh_; }
0842 
0843   private:
0844     real_type r_lo_;
0845     real_type r_hi_;
0846     real_type hh_;
0847 };
0848 
0849 //---------------------------------------------------------------------------//
0850 /*!
0851  * A general parallelepiped centered on the origin.
0852  *
0853  * A parallelepiped is a shape having 3 pairs of parallel faces out of
0854  * which one is parallel with the \em x-y plane (\em z faces). All faces are
0855  * parallelograms in the general case. The \em z faces have 2 edges parallel
0856  * with the \em x axis. Note that all angle parameters are expressed in terms
0857  * of fractions of a 360-degree turn.
0858  *
0859  * The shape has the center in the origin and it is defined by:
0860  *
0861  *   - \c halfedges: a 3-vector (dY, dY, dZ) with half-lengths of the
0862  *     projections of the edges on X, Y, Z. The lower Z face is positioned at
0863  *     `-dZ`, and the upper one at `+dZ`.
0864  *   - \c alpha angle between the segment defined by the centers of the
0865  *     X-parallel edges and Y axis. Validity range is `(-1/4, 1/4)`;
0866  *   - \c theta polar angle of the shape's main axis, e.g. the segment defined
0867  *     by the centers of the Z faces. Validity range is `[0, 1/4)`;
0868  *   - \c phi azimuthal angle of the shape's main axis (as explained above).
0869  *     Validity range is `[0, 1)`.
0870  */
0871 class Parallelepiped final : public IntersectRegionInterface
0872 {
0873   public:
0874     // Construct with half widths and 3 angles
0875     Parallelepiped(Real3 const& halfedges, Turn alpha, Turn theta, Turn phi);
0876 
0877     // Build surfaces
0878     void build(IntersectSurfaceBuilder&) const final;
0879 
0880     // Output to JSON
0881     void output(JsonPimpl*) const final;
0882 
0883     //// ACCESSORS ////
0884 
0885     //! Half-lengths of edge projections along each axis
0886     Real3 const& halfedges() const { return hpr_; }
0887     //! Angle between slanted *y* edges and the *y* axis (in turns)
0888     Turn alpha() const { return alpha_; }
0889     //! Polar angle of main axis (in turns)
0890     Turn theta() const { return theta_; }
0891     //! Azimuthal angle of main axis (in turns)
0892     Turn phi() const { return phi_; }
0893 
0894   private:
0895     // half-lengths
0896     Real3 hpr_;
0897     // angle between slanted y-edges and the y-axis
0898     Turn alpha_;
0899     // polar angle of main axis
0900     Turn theta_;
0901     // azimuthal angle of main axis
0902     Turn phi_;
0903 };
0904 
0905 //---------------------------------------------------------------------------//
0906 /*!
0907  * A regular, z-extruded polygon centered on the origin.
0908  *
0909  * This is the base component of a G4Polyhedra (PGON). The default rotation is
0910  * to put the first point at \f$ y = 0 \f$. Looking at an x-y
0911  * slice for a prism with apothem \em a, odd-numbered prisms have a plane at
0912  * \f$ x=-a \f$:
0913  * - \f$ n=3 \f$ is a triangle pointing right,
0914  * - \f$ n=4 \f$ is a diamond,
0915  * - \f$ n=5 \f$ is a tilted pentagon (flat on the left), and
0916  * - \f$ n=6 \f$ is a flat-top hexagon.
0917  *
0918  *
0919  * The "orientation" parameter is a scaled counterclockwise rotation on
0920  * \f$[0, 1)\f$, where zero preserves the orientation described above, and
0921  * unity would replicate the original shape but with the "p0" face being where
0922  * the "p1" originally was. With a value of 0.5:
0923  * - \f$ n=3 \f$ is a triangle pointing left
0924  * - \f$ n=4 \f$ is an upright square,
0925  * - \f$ n=5 \f$ is a tilted pentagon (flat on the right), and
0926  * - \f$ n=6 \f$ is a pointy-top hexagon.
0927  */
0928 class Prism final : public IntersectRegionInterface
0929 {
0930   public:
0931     // Construct with inner radius (apothem), half height, and orientation
0932     Prism(int num_sides,
0933           real_type apothem,
0934           real_type halfheight,
0935           real_type orientation);
0936 
0937     // Build surfaces
0938     void build(IntersectSurfaceBuilder&) const final;
0939 
0940     // Output to JSON
0941     void output(JsonPimpl*) const final;
0942 
0943     //// TEMPLATE INTERFACE ////
0944 
0945     // Whether this encloses another cylinder
0946     bool encloses(Prism const& other) const;
0947 
0948     //// ACCESSORS ////
0949 
0950     //! Number of sides
0951     int num_sides() const { return num_sides_; }
0952     //! Inner radius
0953     real_type apothem() const { return apothem_; }
0954     //! Half the Z height
0955     real_type halfheight() const { return hh_; }
0956     //! Rotation factor
0957     real_type orientation() const { return orientation_; }
0958 
0959   private:
0960     // Number of sides
0961     int num_sides_;
0962 
0963     // Distance from center to midpoint of its side
0964     real_type apothem_;
0965 
0966     // Half the z height
0967     real_type hh_;
0968 
0969     // Rotational offset: 0 has point at (r, 0), 1 is congruent with 0
0970     real_type orientation_;
0971 };
0972 
0973 //---------------------------------------------------------------------------//
0974 /*!
0975  * A sphere centered on the origin.
0976  *
0977  * \note Be aware there's also a sphere *surface* at orange/surf/Sphere.hh in a
0978  * different namespace.
0979  */
0980 class Sphere final : public IntersectRegionInterface
0981 {
0982   public:
0983     // Construct with radius
0984     explicit Sphere(real_type radius);
0985 
0986     // Build surfaces
0987     void build(IntersectSurfaceBuilder&) const final;
0988 
0989     // Output to JSON
0990     void output(JsonPimpl*) const final;
0991 
0992     //// TEMPLATE INTERFACE ////
0993 
0994     // Whether this encloses another sphere
0995     bool encloses(Sphere const& other) const;
0996 
0997     //// ACCESSORS ////
0998 
0999     //! Radius
1000     real_type radius() const { return radius_; }
1001 
1002   private:
1003     real_type radius_;
1004 };
1005 
1006 //---------------------------------------------------------------------------//
1007 /*!
1008  * A tetrahedron defined by four vertices.
1009  *
1010  * A tetrahedron is a polyhedron with four triangular faces. The four vertices
1011  * should not be coplanar, and they should be ordered such that when viewed
1012  * from outside the tetrahedron, each triangular face has vertices in
1013  * counterclockwise order (following the right-hand rule for outward normals).
1014  *
1015  * The tetrahedron is constructed by defining four planes, one for each face.
1016  * Each plane is determined by three vertices. Face \em i uses all the vertices
1017  * except for the one at index \em i .
1018  */
1019 class Tet final : public IntersectRegionInterface
1020 {
1021   public:
1022     //!@{
1023     //! \name Type aliases
1024     using ArrReal3 = Array<Real3, 4>;
1025     //!@}
1026 
1027   public:
1028     // Construct from an array of four vertices
1029     explicit Tet(ArrReal3 const&);
1030 
1031     //! Construct from four vertices
1032     Tet(Real3 const& v0, Real3 const& v1, Real3 const& v2, Real3 const& v3)
1033         : Tet(ArrReal3{v0, v1, v2, v3})
1034     {
1035     }
1036 
1037     // Build surfaces
1038     void build(IntersectSurfaceBuilder&) const final;
1039 
1040     // Output to JSON
1041     void output(JsonPimpl*) const final;
1042 
1043     //// ACCESSORS ////
1044 
1045     // Get a vertex by index
1046     Real3 const& vertex(size_type i) const;
1047 
1048     //! Get all vertices
1049     ArrReal3 const& vertices() const { return v_; }
1050 
1051   private:
1052     ArrReal3 v_;  //!< Four vertices defining the tetrahedron
1053 };
1054 
1055 /*!
1056  * A torus centered around the origin, defined by two radii.
1057  *
1058  * The major radius extends from the origin to the center of the revolved
1059  * circle, and the minor radius is that of the revolved circle.
1060  *
1061  * Uses a special case of the Toroid surface, with equal ellipse radii.
1062  */
1063 class Torus final : public IntersectRegionInterface
1064 {
1065   public:
1066     // Construct with radii
1067     Torus(real_type major_radius, real_type minor_radius);
1068 
1069     // Build surfaces
1070     void build(IntersectSurfaceBuilder&) const final;
1071 
1072     // Output to JSON
1073     void output(JsonPimpl*) const final;
1074 
1075     // Whether this encloses another torus
1076     bool encloses(Torus const& other) const;
1077 
1078     //// ACCESSORS ////
1079 
1080     //! Major radius (from the origin to the revolved circle)
1081     real_type major_radius() const { return r_maj_; }
1082 
1083     //! Minor radius (of the revolved circle)
1084     real_type minor_radius() const { return r_min_; }
1085 
1086   private:
1087     real_type r_maj_;
1088     real_type r_min_;
1089 };
1090 
1091 //---------------------------------------------------------------------------//
1092 }  // namespace orangeinp
1093 }  // namespace celeritas