|
|
|||
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
| [ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
|
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
|