![]() |
|
|||
File indexing completed on 2025-09-16 09:03:16
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 "corecel/Macros.hh" 0011 #include "corecel/cont/Array.hh" 0012 #include "corecel/math/Turn.hh" 0013 #include "orange/OrangeTypes.hh" 0014 0015 namespace celeritas 0016 { 0017 struct JsonPimpl; 0018 0019 namespace orangeinp 0020 { 0021 class IntersectSurfaceBuilder; 0022 0023 //---------------------------------------------------------------------------// 0024 /*! 0025 * Interface class for building non-reentrant spatial regions. 0026 * 0027 * This is a building block for constructing more complex objects out of 0028 * smaller spatial regions. A \c shape object will have a single intersect 0029 * region, and a \c solid object region may have multiple adjacent intersect 0030 * regions. 0031 * 0032 * Convex regions should be as minimal as possible and rely on transformations 0033 * to change axes, displacement, etc. As a general rule, the exterior bounding 0034 * box of a intersect region should be <em>centered on the origin</em>, and 0035 * objects should be aligned along the \em z axis. 0036 * 0037 * When implementing this class, prefer to build simpler surfaces (planes) 0038 * before complex ones (cones) in case we implement short-circuiting logic, 0039 * since expressions are currently sorted. 0040 * 0041 * \note Additional methods such as volume calculation may be added here later. 0042 */ 0043 class IntersectRegionInterface 0044 { 0045 public: 0046 //! Construct surfaces that are AND-ed into this region 0047 virtual void build(IntersectSurfaceBuilder&) const = 0; 0048 0049 //! Write the region to a JSON object 0050 virtual void output(JsonPimpl*) const = 0; 0051 0052 virtual ~IntersectRegionInterface() = default; 0053 0054 protected: 0055 //!@{ 0056 //! Allow construction and assignment only through daughter classes 0057 IntersectRegionInterface() = default; 0058 CELER_DEFAULT_COPY_MOVE(IntersectRegionInterface); 0059 //!@} 0060 }; 0061 0062 //---------------------------------------------------------------------------// 0063 /*! 0064 * A rectangular parallelepiped/cuboid centered on the origin. 0065 * 0066 * The box is constructed with half-widths. 0067 */ 0068 class Box final : public IntersectRegionInterface 0069 { 0070 public: 0071 // Construct with half-widths 0072 explicit Box(Real3 const& halfwidths); 0073 0074 // Build surfaces 0075 void build(IntersectSurfaceBuilder&) const final; 0076 0077 // Output to JSON 0078 void output(JsonPimpl*) const final; 0079 0080 //// ACCESSORS //// 0081 0082 //! Half-width for each axis 0083 Real3 const& halfwidths() const { return hw_; } 0084 0085 private: 0086 Real3 hw_; 0087 }; 0088 0089 //---------------------------------------------------------------------------// 0090 /*! 0091 * A closed truncated cone along the *z* axis centered on the origin. 0092 * 0093 * A quadric cone technically defines two opposing cones that touch at a single 0094 * vanishing point, but this cone is required to be truncated so that the 0095 * vanishing point is on our outside the cone. 0096 * 0097 * The midpoint along the \em z axis of the cone is the origin. A cone is \em 0098 * not allowed to have equal radii: for that, use a cylinder. However, it \em 0099 * may have a single radius of zero, which puts the vanishing point on one end 0100 * of the cone. 0101 * 0102 * This intersect region, along with the Cylinder, is a base component of the 0103 * G4Polycone (PCON). 0104 */ 0105 class Cone final : public IntersectRegionInterface 0106 { 0107 public: 0108 // Construct with Z half-height and lo, hi radii 0109 Cone(Real2 const& radii, real_type halfheight); 0110 0111 //// INTERFACE //// 0112 0113 // Build surfaces 0114 void build(IntersectSurfaceBuilder&) const final; 0115 0116 // Output to JSON 0117 void output(JsonPimpl*) const final; 0118 0119 //// TEMPLATE INTERFACE //// 0120 0121 // Whether this encloses another cone 0122 bool encloses(Cone const& other) const; 0123 0124 //// ACCESSORS //// 0125 0126 //! Lower and upper radii 0127 Real2 const& radii() const { return radii_; } 0128 0129 //! Half-height along Z 0130 real_type halfheight() const { return hh_; } 0131 0132 private: 0133 Real2 radii_; 0134 real_type hh_; 0135 }; 0136 0137 //---------------------------------------------------------------------------// 0138 /*! 0139 * A *z*-aligned cylinder centered on the origin. 0140 * 0141 * The cylinder is defined with a radius and half-height. 0142 */ 0143 class Cylinder final : public IntersectRegionInterface 0144 { 0145 public: 0146 // Construct with radius 0147 Cylinder(real_type radius, real_type halfheight); 0148 0149 // Build surfaces 0150 void build(IntersectSurfaceBuilder&) const final; 0151 0152 // Output to JSON 0153 void output(JsonPimpl*) const final; 0154 0155 //// TEMPLATE INTERFACE //// 0156 0157 // Whether this encloses another cylinder 0158 bool encloses(Cylinder const& other) const; 0159 0160 //// ACCESSORS //// 0161 0162 //! Radius 0163 real_type radius() const { return radius_; } 0164 0165 //! Half-height along Z 0166 real_type halfheight() const { return hh_; } 0167 0168 private: 0169 real_type radius_; 0170 real_type hh_; 0171 }; 0172 0173 //---------------------------------------------------------------------------// 0174 /*! 0175 * An axis-alligned ellipsoid centered at the origin. 0176 * 0177 * The ellipsoid is constructed with the three radial lengths. 0178 */ 0179 class Ellipsoid final : public IntersectRegionInterface 0180 { 0181 public: 0182 // Construct with radius 0183 explicit Ellipsoid(Real3 const& radii); 0184 0185 // Build surfaces 0186 void build(IntersectSurfaceBuilder&) const final; 0187 0188 // Output to JSON 0189 void output(JsonPimpl*) const final; 0190 0191 //// TEMPLATE INTERFACE //// 0192 0193 // Whether this encloses another ellipsoid 0194 bool encloses(Ellipsoid const& other) const; 0195 0196 //// ACCESSORS //// 0197 0198 //! Radius along each axis 0199 Real3 const& radii() const { return radii_; } 0200 0201 private: 0202 Real3 radii_; 0203 }; 0204 0205 //---------------------------------------------------------------------------// 0206 /*! 0207 * A *z*-aligned cylinder with an elliptical cross section. 0208 * 0209 * The elliptical cylinder is defined with a two radii and a half-height, 0210 * such that the centroid of the bounding box is origin. 0211 */ 0212 class EllipticalCylinder final : public IntersectRegionInterface 0213 { 0214 public: 0215 // Construct with x- and y-radii and half-height in z 0216 EllipticalCylinder(Real2 const& radii, real_type halfheight); 0217 0218 // Build surfaces 0219 void build(IntersectSurfaceBuilder&) const final; 0220 0221 // Output to JSON 0222 void output(JsonPimpl*) const final; 0223 0224 //// TEMPLATE INTERFACE //// 0225 0226 // Whether this encloses another ellipsoid 0227 bool encloses(EllipticalCylinder const& other) const; 0228 0229 //// ACCESSORS //// 0230 0231 //! Radius along each axis 0232 Real2 const& radii() const { return radii_; } 0233 0234 //! Half-height along Z 0235 real_type halfheight() const { return hh_; } 0236 0237 private: 0238 Real2 radii_; 0239 real_type hh_; 0240 }; 0241 0242 //---------------------------------------------------------------------------// 0243 /*! 0244 * A finite *z*-aligned cone with an elliptical cross section. 0245 * 0246 * The elliptical cone is defined in an analogous fashion to the regular 0247 * (i.e., circular) cone. A half-height (hh) defines the z-extents, such 0248 * that the centroid of the outer bounding box is the origin. The lower radii 0249 * are the x- and y-radii at the plane z = -hh. The upper radii are the x- and 0250 * y-radii at the plane z = hh. There are several restrictions on these radii: 0251 * 0252 * 1) Either the lower or upper radii may be (0, 0); this is the only permitted 0253 * way for the elliptical cone to include the vertex. 0254 * 2) The aspect ratio of the elliptical cross sections is constant. Thus, the 0255 * aspect ratio at z = -hh must equal the aspect ratio at z = hh. 0256 * 3) Degenerate elliptical cones with lower_radii == upper_radii (i.e., 0257 * elliptical cylinders) are not permitted. 0258 * 4) Degenerate elliptical cones where lower or upper radii are equal to 0259 * (0, x) or (x, 0), where x is non-zero, are not permitted. 0260 * 0261 * The elliptical surface can be expressed as: 0262 * 0263 * \f[ 0264 (x/r_x)^2 + (y/r_y)^2 = (v-z)^2, 0265 * \f] 0266 * 0267 * which can be converted to SimpleQuadric form: 0268 * \verbatim 0269 (1/r_x)^2 x^2 + (1/r_y)^2 y^2 + (-1) z^2 + (2v) z + (-v^2) = 0. 0270 | | | | | 0271 a b c d e 0272 * \endverbatim 0273 * 0274 * where v is the location of the vertex. The r_x, r_y, and v can be calculated 0275 * from the lower and upper radii as given by \c G4EllipticalCone: 0276 * \verbatim 0277 r_x = (lower_radii[X] - upper_radii[X])/(2 hh), 0278 r_y = (lower_radii[Y] - upper_radii[Y])/(2 hh), 0279 v = hh (lower_radii[X] + upper_radii[X])/(lower_radii[X] - 0280 upper_radii[X]). 0281 * \endverbatim 0282 */ 0283 class EllipticalCone final : public IntersectRegionInterface 0284 { 0285 public: 0286 // Construct with x- and y-radii and half-height in z 0287 EllipticalCone(Real2 const& lower_radii, 0288 Real2 const& upper_radii, 0289 real_type halfheight); 0290 0291 // Build surfaces 0292 void build(IntersectSurfaceBuilder&) const final; 0293 0294 // Output to JSON 0295 void output(JsonPimpl*) const final; 0296 0297 //// TEMPLATE INTERFACE //// 0298 0299 // Whether this encloses another elliptical cone 0300 bool encloses(EllipticalCone const& other) const; 0301 0302 //// ACCESSORS //// 0303 0304 //! Radii along the x- and y-axes at z=-hh 0305 Real2 const& lower_radii() const { return lower_radii_; } 0306 0307 //! Radii along the x- and y-axes at z=-hh 0308 Real2 const& upper_radii() const { return upper_radii_; } 0309 0310 //! Half-height along Z 0311 real_type halfheight() const { return hh_; } 0312 0313 private: 0314 Real2 lower_radii_; 0315 Real2 upper_radii_; 0316 real_type hh_; 0317 }; 0318 0319 //---------------------------------------------------------------------------// 0320 /*! 0321 * A generalized polygon with parallel flat faces along the *z* axis. 0322 * 0323 * A GenPrism, like VecGeom's GenTrap, ROOT's Arb8, and Geant4's 0324 * G4GenericTrap, represents a generalized volume with polyhedral faces on two 0325 * parallel planes perpendicular to the \em z axis. Unlike those other codes, 0326 * the number of faces can be arbitrary in number. 0327 * 0328 * The faces have an orientation and ordering so that \em twisted faces can be 0329 * constructed by joining corresponding points using straight-line "vertical" 0330 * edges, directly matching the G4GenericTrap definition, but directly 0331 * generating a hyperbolic paraboloid for each twisted face. 0332 * 0333 * Trapezoids constructed from the helper functions will have sides that are 0334 * same ordering as a prism: the rightward face is first (normal is along the 0335 * \em +x axis), then the others follow counterclockwise. 0336 */ 0337 class GenPrism final : public IntersectRegionInterface 0338 { 0339 public: 0340 //!@{ 0341 //! \name Type aliases 0342 using VecReal2 = std::vector<Real2>; 0343 //!@} 0344 0345 //! Regular trapezoidal top/bottom face 0346 struct TrapFace 0347 { 0348 //! Half the vertical distance between horizontal edges 0349 real_type hy{}; 0350 //! Top horizontal edge half-length 0351 real_type hx_lo{}; 0352 //! Bottom horizontal edge half-length 0353 real_type hx_hi{}; 0354 //! Shear angle between horizontal line centers and Y axis 0355 Turn alpha; 0356 }; 0357 0358 public: 0359 // Helper function to construct a Trd shape from hz and two rectangles, 0360 // one for each z-face 0361 static GenPrism from_trd(real_type halfz, Real2 const& lo, Real2 const& hi); 0362 0363 // Helper function to construct a general trap from its half-height and 0364 // the two trapezoids defining its lower and upper faces 0365 static GenPrism from_trap(real_type hz, 0366 Turn theta, 0367 Turn phi, 0368 TrapFace const& lo, 0369 TrapFace const& hi); 0370 0371 // Construct from half Z height and 4 vertices for top and bottom planes 0372 GenPrism(real_type halfz, VecReal2 const& lo, VecReal2 const& hi); 0373 0374 // Build surfaces 0375 void build(IntersectSurfaceBuilder&) const final; 0376 0377 // Output to JSON 0378 void output(JsonPimpl*) const final; 0379 0380 //// ACCESSORS //// 0381 0382 //! Half-height along Z 0383 real_type halfheight() const { return hz_; } 0384 0385 //! Polygon on -z face 0386 VecReal2 const& lower() const { return lo_; } 0387 0388 //! Polygon on +z face 0389 VecReal2 const& upper() const { return hi_; } 0390 0391 //! Number of sides (points on the Z face) 0392 size_type num_sides() const { return lo_.size(); } 0393 0394 // Calculate the cosine of the twist angle for a given side 0395 real_type calc_twist_cosine(size_type size_idx) const; 0396 0397 private: 0398 enum class Degenerate 0399 { 0400 none, 0401 lo, 0402 hi 0403 }; 0404 0405 real_type hz_; //!< half-height 0406 VecReal2 lo_; //!< corners of the -z face 0407 VecReal2 hi_; //!< corners of the +z face 0408 Degenerate degen_{Degenerate::none}; //!< no plane on this z axis 0409 }; 0410 0411 //---------------------------------------------------------------------------// 0412 /*! 0413 * An infinite slab bound by lower and upper z-planes. 0414 */ 0415 class InfSlab final : public IntersectRegionInterface 0416 { 0417 public: 0418 // Construct from lower and upper z-planes 0419 InfSlab(real_type lower, real_type upper); 0420 0421 // Build surfaces 0422 void build(IntersectSurfaceBuilder&) const final; 0423 0424 // Write output to the given JSON object 0425 void output(JsonPimpl*) const final; 0426 0427 //// ACCESSORS //// 0428 0429 //! Lower z-plane 0430 real_type lower() const { return lower_; } 0431 0432 //! Upper z-plane 0433 real_type upper() const { return upper_; } 0434 0435 private: 0436 real_type lower_; 0437 real_type upper_; 0438 }; 0439 0440 //---------------------------------------------------------------------------// 0441 /*! 0442 * An open wedge shape from the *z* axis. 0443 * 0444 * The wedge is defined by an interior angle that \em must be less than or 0445 * equal to 180 degrees (half a turn) and \em must be more than zero. It can be 0446 * subtracted, or its negation can be subtracted. The start angle is mapped 0447 * onto \f$[0, 1)\f$ on construction. 0448 */ 0449 class InfWedge final : public IntersectRegionInterface 0450 { 0451 public: 0452 // Construct from a starting angle and interior angle 0453 InfWedge(Turn start, Turn interior); 0454 0455 // Build surfaces 0456 void build(IntersectSurfaceBuilder&) const final; 0457 0458 // Output to JSON 0459 void output(JsonPimpl*) const final; 0460 0461 //// ACCESSORS //// 0462 0463 //! Starting angle 0464 Turn start() const { return start_; } 0465 0466 //! Interior angle 0467 Turn interior() const { return interior_; } 0468 0469 private: 0470 Turn start_; 0471 Turn interior_; 0472 }; 0473 0474 //---------------------------------------------------------------------------// 0475 /*! 0476 * An involute "blade" centered on the origin. 0477 * 0478 * This is the intersection of two parallel involutes with a cylindrical shell. 0479 * The three radii, which must be in ascending order, are that of the involute, 0480 * the inner cylinder, and the outer cylinder. 0481 * 0482 * The "chirality" of the involute is viewed from the \em +z axis looking down: 0483 * whether it spirals to the right or left. 0484 */ 0485 class Involute final : public IntersectRegionInterface 0486 { 0487 public: 0488 // Construct with radius 0489 explicit Involute(Real3 const& radii, 0490 Real2 const& displacement, 0491 Chirality chirality, 0492 real_type halfheight); 0493 0494 // Build surfaces 0495 void build(IntersectSurfaceBuilder&) const final; 0496 0497 // Output to JSON 0498 void output(JsonPimpl*) const final; 0499 0500 //// ACCESSORS //// 0501 0502 //! Radii: Rdius of involute, minimum radius, maximum radius 0503 Real3 const& radii() const { return radii_; } 0504 //! Displacement angle 0505 Real2 const& displacement_angle() const { return a_; } 0506 //! Angular bounds of involute 0507 Real2 const& t_bounds() const { return t_bounds_; } 0508 //! Chirality of involute: turning left or right 0509 Chirality chirality() const { return sign_; } 0510 //! Halfheight 0511 real_type halfheight() const { return hh_; } 0512 0513 private: 0514 Real3 radii_; 0515 Real2 a_; 0516 Real2 t_bounds_; 0517 Chirality sign_; 0518 real_type hh_; 0519 }; 0520 0521 //---------------------------------------------------------------------------// 0522 /*! 0523 * A general parallelepiped centered on the origin. 0524 * 0525 * A parallelepiped is a shape having 3 pairs of parallel faces out of 0526 * which one is parallel with the \em x-y plane (\em z faces). All faces are 0527 * parallelograms in the general case. The \em z faces have 2 edges parallel 0528 * with the \em x axis. Note that all angle parameters are expressed in terms 0529 * of fractions of a 360-degree turn. 0530 * 0531 * The shape has the center in the origin and it is defined by: 0532 * 0533 * - \c halfedges: a 3-vector (dY, dY, dZ) with half-lengths of the 0534 * projections of the edges on X, Y, Z. The lower Z face is positioned at 0535 * `-dZ`, and the upper one at `+dZ`. 0536 * - \c alpha angle between the segment defined by the centers of the 0537 * X-parallel edges and Y axis. Validity range is `(-1/4, 1/4)`; 0538 * - \c theta polar angle of the shape's main axis, e.g. the segment defined 0539 * by the centers of the Z faces. Validity range is `[0, 1/4)`; 0540 * - \c phi azimuthal angle of the shape's main axis (as explained above). 0541 * Validity range is `[0, 1)`. 0542 */ 0543 class Parallelepiped final : public IntersectRegionInterface 0544 { 0545 public: 0546 // Construct with half widths and 3 angles 0547 Parallelepiped(Real3 const& halfedges, Turn alpha, Turn theta, Turn phi); 0548 0549 // Build surfaces 0550 void build(IntersectSurfaceBuilder&) const final; 0551 0552 // Output to JSON 0553 void output(JsonPimpl*) const final; 0554 0555 //// ACCESSORS //// 0556 0557 //! Half-lengths of edge projections along each axis 0558 Real3 const& halfedges() const { return hpr_; } 0559 //! Angle between slanted y-edges and the y-axis (in turns) 0560 Turn alpha() const { return alpha_; } 0561 //! Polar angle of main axis (in turns) 0562 Turn theta() const { return theta_; } 0563 //! Azimuthal angle of main axis (in turns) 0564 Turn phi() const { return phi_; } 0565 0566 private: 0567 // half-lengths 0568 Real3 hpr_; 0569 // angle between slanted y-edges and the y-axis 0570 Turn alpha_; 0571 // polar angle of main axis 0572 Turn theta_; 0573 // azimuthal angle of main axis 0574 Turn phi_; 0575 }; 0576 0577 //---------------------------------------------------------------------------// 0578 /*! 0579 * A regular, z-extruded polygon centered on the origin. 0580 * 0581 * This is the base component of a G4Polyhedra (PGON). The default rotation is 0582 * to put a y-aligned plane on the bottom of the shape, so looking at an x-y 0583 * slice given an apothem \em a, every shape has a surface at \f$ y = -a \f$: 0584 * - n=3 is a triangle with a flat bottom, point up 0585 * - n=4 is a square with axis-aligned sides 0586 * - n=6 is a flat-top hexagon 0587 * 0588 * The "orientation" parameter is a scaled counterclockwise rotation on 0589 * \f$[0, 1)\f$, where zero preserves the orientation described above, and 0590 * unity replicates the original shape but with the "p0" face being where the 0591 * "p1" originally was. With a value of 0.5: 0592 * - n=3 is a downward-pointing triangle 0593 * - n=4 is a diamond 0594 * - n=6 is a pointy-top hexagon 0595 */ 0596 class Prism final : public IntersectRegionInterface 0597 { 0598 public: 0599 // Construct with inner radius (apothem), half height, and orientation 0600 Prism(int num_sides, 0601 real_type apothem, 0602 real_type halfheight, 0603 real_type orientation); 0604 0605 // Build surfaces 0606 void build(IntersectSurfaceBuilder&) const final; 0607 0608 // Output to JSON 0609 void output(JsonPimpl*) const final; 0610 0611 //// TEMPLATE INTERFACE //// 0612 0613 // Whether this encloses another cylinder 0614 bool encloses(Prism const& other) const; 0615 0616 //// ACCESSORS //// 0617 0618 //! Number of sides 0619 int num_sides() const { return num_sides_; } 0620 //! Inner radius 0621 real_type apothem() const { return apothem_; } 0622 //! Half the Z height 0623 real_type halfheight() const { return hh_; } 0624 //! Rotation factor 0625 real_type orientation() const { return orientation_; } 0626 0627 private: 0628 // Number of sides 0629 int num_sides_; 0630 0631 // Distance from center to midpoint of its side 0632 real_type apothem_; 0633 0634 // Half the z height 0635 real_type hh_; 0636 0637 // Rotational offset (0 has bottom face at -Y, 1 is congruent) 0638 real_type orientation_; 0639 }; 0640 0641 //---------------------------------------------------------------------------// 0642 /*! 0643 * A sphere centered on the origin. 0644 * 0645 * \note Be aware there's also a sphere *surface* at orange/surf/Sphere.hh in a 0646 * different namespace. 0647 */ 0648 class Sphere final : public IntersectRegionInterface 0649 { 0650 public: 0651 // Construct with radius 0652 explicit Sphere(real_type radius); 0653 0654 // Build surfaces 0655 void build(IntersectSurfaceBuilder&) const final; 0656 0657 // Output to JSON 0658 void output(JsonPimpl*) const final; 0659 0660 //// TEMPLATE INTERFACE //// 0661 0662 // Whether this encloses another sphere 0663 bool encloses(Sphere const& other) const; 0664 0665 //// ACCESSORS //// 0666 0667 //! Radius 0668 real_type radius() const { return radius_; } 0669 0670 private: 0671 real_type radius_; 0672 }; 0673 0674 //---------------------------------------------------------------------------// 0675 } // namespace orangeinp 0676 } // 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 |
![]() ![]() |