Geant4 11.4.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4CutTubs Class Reference

G4CutTubs is a tube with possible cuts in +-Z. More...

#include <G4CutTubs.hh>

Inheritance diagram for G4CutTubs:

Public Member Functions

 G4CutTubs (const G4String &pName, G4double pRMin, G4double pRMax, G4double pDz, G4double pSPhi, G4double pDPhi, G4ThreeVector pLowNorm, G4ThreeVector pHighNorm)
 ~G4CutTubs () override=default
G4double GetInnerRadius () const
G4double GetOuterRadius () const
G4double GetZHalfLength () const
G4double GetStartPhiAngle () const
G4double GetDeltaPhiAngle () const
G4double GetSinStartPhi () const
G4double GetCosStartPhi () const
G4double GetSinEndPhi () const
G4double GetCosEndPhi () const
G4ThreeVector GetLowNorm () const
G4ThreeVector GetHighNorm () const
void SetInnerRadius (G4double newRMin)
void SetOuterRadius (G4double newRMax)
void SetZHalfLength (G4double newDz)
void SetStartPhiAngle (G4double newSPhi, G4bool trig=true)
void SetDeltaPhiAngle (G4double newDPhi)
G4double GetCubicVolume () override
G4double GetSurfaceArea () override
void BoundingLimits (G4ThreeVector &pMin, G4ThreeVector &pMax) const override
G4bool CalculateExtent (const EAxis pAxis, const G4VoxelLimits &pVoxelLimit, const G4AffineTransform &pTransform, G4double &pmin, G4double &pmax) const override
EInside Inside (const G4ThreeVector &p) const override
G4ThreeVector SurfaceNormal (const G4ThreeVector &p) const override
G4double DistanceToIn (const G4ThreeVector &p, const G4ThreeVector &v) const override
G4double DistanceToIn (const G4ThreeVector &p) const override
G4double DistanceToOut (const G4ThreeVector &p, const G4ThreeVector &v, const G4bool calcNorm=false, G4bool *validNorm=nullptr, G4ThreeVector *n=nullptr) const override
G4double DistanceToOut (const G4ThreeVector &p) const override
G4GeometryType GetEntityType () const override
G4ThreeVector GetPointOnSurface () const override
G4VSolidClone () const override
std::ostream & StreamInfo (std::ostream &os) const override
void DescribeYourselfTo (G4VGraphicsScene &scene) const override
G4PolyhedronCreatePolyhedron () const override
 G4CutTubs (__void__ &)
 G4CutTubs (const G4CutTubs &rhs)=default
G4CutTubsoperator= (const G4CutTubs &rhs)
Public Member Functions inherited from G4CSGSolid
 G4CSGSolid (const G4String &pName)
 ~G4CSGSolid () override
G4PolyhedronGetPolyhedron () const override
 G4CSGSolid (__void__ &)
 G4CSGSolid (const G4CSGSolid &rhs)
G4CSGSolidoperator= (const G4CSGSolid &rhs)
Public Member Functions inherited from G4VSolid
 G4VSolid (const G4String &name)
virtual ~G4VSolid ()
 G4VSolid (const G4VSolid &rhs)
G4VSolidoperator= (const G4VSolid &rhs)
G4bool operator== (const G4VSolid &s) const
G4String GetName () const
void SetName (const G4String &name)
G4double GetTolerance () const
virtual void ComputeDimensions (G4VPVParameterisation *p, const G4int n, const G4VPhysicalVolume *pRep)
virtual G4int GetNumOfConstituents () const
virtual G4bool IsFaceted () const
void DumpInfo () const
virtual G4VisExtent GetExtent () const
virtual const G4VSolidGetConstituentSolid (G4int no) const
virtual G4VSolidGetConstituentSolid (G4int no)
virtual const G4DisplacedSolidGetDisplacedSolidPtr () const
virtual G4DisplacedSolidGetDisplacedSolidPtr ()
 G4VSolid (__void__ &)
G4double EstimateCubicVolume (G4int nStat, G4double epsilon) const
G4double EstimateSurfaceArea (G4int nStat, G4double epsilon) const

Protected Member Functions

void Initialize ()
void CheckSPhiAngle (G4double sPhi)
void CheckDPhiAngle (G4double dPhi)
void CheckPhiAngles (G4double sPhi, G4double dPhi)
void InitializeTrigonometry ()
G4ThreeVector ApproxSurfaceNormal (const G4ThreeVector &p) const
G4bool IsCrossingCutPlanes () const
G4double GetCutZ (const G4ThreeVector &p) const
Protected Member Functions inherited from G4CSGSolid
G4double GetRadiusInRing (G4double rmin, G4double rmax) const
Protected Member Functions inherited from G4VSolid
void CalculateClippedPolygonExtent (G4ThreeVectorList &pPolygon, const G4VoxelLimits &pVoxelLimit, const EAxis pAxis, G4double &pMin, G4double &pMax) const
void ClipCrossSection (G4ThreeVectorList *pVertices, const G4int pSectionIndex, const G4VoxelLimits &pVoxelLimit, const EAxis pAxis, G4double &pMin, G4double &pMax) const
void ClipBetweenSections (G4ThreeVectorList *pVertices, const G4int pSectionIndex, const G4VoxelLimits &pVoxelLimit, const EAxis pAxis, G4double &pMin, G4double &pMax) const
void ClipPolygon (G4ThreeVectorList &pPolygon, const G4VoxelLimits &pVoxelLimit, const EAxis pAxis) const

Additional Inherited Members

Protected Attributes inherited from G4CSGSolid
G4double fCubicVolume = 0.0
G4double fSurfaceArea = 0.0
G4bool fRebuildPolyhedron = false
G4PolyhedronfpPolyhedron = nullptr
Protected Attributes inherited from G4VSolid
G4double kCarTolerance

Detailed Description

G4CutTubs is a tube with possible cuts in +-Z.

Definition at line 61 of file G4CutTubs.hh.

Constructor & Destructor Documentation

◆ G4CutTubs() [1/3]

G4CutTubs::G4CutTubs ( const G4String & pName,
G4double pRMin,
G4double pRMax,
G4double pDz,
G4double pSPhi,
G4double pDPhi,
G4ThreeVector pLowNorm,
G4ThreeVector pHighNorm )

Constructs a tube with the given name and dimensions.

Parameters
[in]pNameThe name of the solid.
[in]pRminInner radius.
[in]pRmaxOuter radius.
[in]pDZHalf length in Z.
[in]pSPhiStarting angle of the segment in radians.
[in]pDPhiDelta angle of the segment in radians.
[in]pLowNormOutside normal vector at -Z.
[in]pHighNormOutside normal vector at +Z.

Definition at line 63 of file G4CutTubs.cc.

68 : G4CSGSolid(pName), fRMin(pRMin), fRMax(pRMax), fDz(pDz),
69 fSPhi(0.), fDPhi(0.), fZMin(0.), fZMax(0.)
70{
73
74 halfCarTolerance = kCarTolerance*0.5;
75 halfRadTolerance = kRadTolerance*0.5;
76 halfAngTolerance = kAngTolerance*0.5;
77
78 if (pDz<=0) // Check z-len
79 {
80 std::ostringstream message;
81 message << "Negative Z half-length (" << pDz << ") in solid: " << GetName();
82 G4Exception("G4CutTubs::G4CutTubs()", "GeomSolids0002", FatalException, message);
83 }
84 if ( (pRMin >= pRMax) || (pRMin < 0) ) // Check radii
85 {
86 std::ostringstream message;
87 message << "Invalid values for radii in solid: " << GetName()
88 << G4endl
89 << " pRMin = " << pRMin << ", pRMax = " << pRMax;
90 G4Exception("G4CutTubs::G4CutTubs()", "GeomSolids0002", FatalException, message);
91 }
92
93 // Check angles
94 //
95 CheckPhiAngles(pSPhi, pDPhi);
96
97 // Check on Cutted Planes Normals
98 // If there is NO CUT, propose to use G4Tubs instead
99 //
100 if ( ( pLowNorm.x() == 0.0) && ( pLowNorm.y() == 0.0)
101 && ( pHighNorm.x() == 0.0) && (pHighNorm.y() == 0.0) )
102 {
103 std::ostringstream message;
104 message << "Inexisting Low/High Normal to Z plane or Parallel to Z."
105 << G4endl
106 << "Normals to Z plane are " << pLowNorm << " and "
107 << pHighNorm << " in solid: " << GetName() << " \n";
108 G4Exception("G4CutTubs::G4CutTubs()", "GeomSolids1001",
109 JustWarning, message, "Should use G4Tubs!");
110 }
111
112 // If Normal is (0,0,0),means parallel to R, give it value of (0,0,+/-1)
113 //
114 if (pLowNorm.mag2() == 0.) { pLowNorm.setZ(-1.); }
115 if (pHighNorm.mag2()== 0.) { pHighNorm.setZ(1.); }
116
117 // Given Normals to Cut Planes have to be an unit vectors.
118 // Normalize if it is needed.
119 //
120 if (pLowNorm.mag2() != 1.) { pLowNorm = pLowNorm.unit(); }
121 if (pHighNorm.mag2()!= 1.) { pHighNorm = pHighNorm.unit(); }
122
123 // Normals to cutted planes have to point outside Solid
124 //
125 if( (pLowNorm.mag2() != 0.) && (pHighNorm.mag2()!= 0. ) )
126 {
127 if( ( pLowNorm.z()>= 0. ) || ( pHighNorm.z() <= 0.))
128 {
129 std::ostringstream message;
130 message << "Invalid Low or High Normal to Z plane; "
131 "has to point outside Solid." << G4endl
132 << "Invalid Norm to Z plane (" << pLowNorm << " or "
133 << pHighNorm << ") in solid: " << GetName();
134 G4Exception("G4CutTubs::G4CutTubs()", "GeomSolids0002",
135 FatalException, message);
136 }
137 }
138 fLowNorm = pLowNorm;
139 fHighNorm = pHighNorm;
140
141 // Check intersection of cut planes, they MUST NOT intersect
142 // each other inside the lateral surface
143 //
145 {
146 std::ostringstream message;
147 message << "Invalid normals to Z plane in solid : " << GetName() << G4endl
148 << "Cut planes are crossing inside lateral surface !!!\n"
149 << " Solid type: G4CutTubs\n"
150 << " Parameters: \n"
151 << " inner radius : " << fRMin/mm << " mm \n"
152 << " outer radius : " << fRMax/mm << " mm \n"
153 << " half length Z: " << fDz/mm << " mm \n"
154 << " starting phi : " << fSPhi/degree << " degrees \n"
155 << " delta phi : " << fDPhi/degree << " degrees \n"
156 << " low Norm : " << fLowNorm << " \n"
157 << " high Norm : " << fHighNorm;
158 G4Exception("G4CutTubs::G4CutTubs()", "GeomSolids0002",
159 FatalException, message);
160 }
161}
@ JustWarning
@ FatalException
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
#define G4endl
Definition G4ios.hh:67
double z() const
Hep3Vector unit() const
double x() const
double mag2() const
double y() const
void setZ(double)
G4CSGSolid(const G4String &pName)
Definition G4CSGSolid.cc:49
G4bool IsCrossingCutPlanes() const
void CheckPhiAngles(G4double sPhi, G4double dPhi)
G4double GetRadialTolerance() const
static G4GeometryTolerance * GetInstance()
G4double GetAngularTolerance() const
G4String GetName() const
G4double kCarTolerance
Definition G4VSolid.hh:418

Referenced by Clone(), G4CutTubs(), and operator=().

◆ ~G4CutTubs()

G4CutTubs::~G4CutTubs ( )
overridedefault

Default destructor.

◆ G4CutTubs() [2/3]

G4CutTubs::G4CutTubs ( __void__ & a)

Fake default constructor for usage restricted to direct object persistency for clients requiring preallocation of memory for persistifiable objects.

Definition at line 168 of file G4CutTubs.cc.

169 : G4CSGSolid(a)
170{
171}

◆ G4CutTubs() [3/3]

G4CutTubs::G4CutTubs ( const G4CutTubs & rhs)
default

Copy constructor and assignment operator.

Member Function Documentation

◆ ApproxSurfaceNormal()

G4ThreeVector G4CutTubs::ApproxSurfaceNormal ( const G4ThreeVector & p) const
protected

Algorithm for SurfaceNormal() following the original specification for points not on the surface.

Definition at line 630 of file G4CutTubs.cc.

631{
632 enum ENorm {kNRMin,kNRMax,kNSPhi,kNEPhi,kNZ};
633
634 ENorm side ;
635 G4ThreeVector norm ;
636 G4double rho, phi ;
637 G4double distZLow,distZHigh,distZ;
638 G4double distRMin, distRMax, distSPhi, distEPhi, distMin ;
639 G4ThreeVector vZ=G4ThreeVector(0,0,fDz);
640
641 rho = std::sqrt(p.x()*p.x() + p.y()*p.y()) ;
642
643 distRMin = std::fabs(rho - fRMin) ;
644 distRMax = std::fabs(rho - fRMax) ;
645
646 //dist to Low Cut
647 //
648 distZLow =std::fabs((p+vZ).dot(fLowNorm));
649
650 //dist to High Cut
651 //
652 distZHigh = std::fabs((p-vZ).dot(fHighNorm));
653 distZ=std::min(distZLow,distZHigh);
654
655 if (distRMin < distRMax) // First minimum
656 {
657 if ( distZ < distRMin )
658 {
659 distMin = distZ ;
660 side = kNZ ;
661 }
662 else
663 {
664 distMin = distRMin ;
665 side = kNRMin ;
666 }
667 }
668 else
669 {
670 if ( distZ < distRMax )
671 {
672 distMin = distZ ;
673 side = kNZ ;
674 }
675 else
676 {
677 distMin = distRMax ;
678 side = kNRMax ;
679 }
680 }
681 if (!fPhiFullCutTube && (rho != 0.0) ) // Protected against (0,0,z)
682 {
683 phi = std::atan2(p.y(),p.x()) ;
684
685 if ( phi < 0 ) { phi += twopi; }
686
687 if ( fSPhi < 0 )
688 {
689 distSPhi = std::fabs(phi - (fSPhi + twopi))*rho ;
690 }
691 else
692 {
693 distSPhi = std::fabs(phi - fSPhi)*rho ;
694 }
695 distEPhi = std::fabs(phi - fSPhi - fDPhi)*rho ;
696
697 if (distSPhi < distEPhi) // Find new minimum
698 {
699 if ( distSPhi < distMin )
700 {
701 side = kNSPhi ;
702 }
703 }
704 else
705 {
706 if ( distEPhi < distMin )
707 {
708 side = kNEPhi ;
709 }
710 }
711 }
712 switch ( side )
713 {
714 case kNRMin : // Inner radius
715 {
716 norm = G4ThreeVector(-p.x()/rho, -p.y()/rho, 0) ;
717 break ;
718 }
719 case kNRMax : // Outer radius
720 {
721 norm = G4ThreeVector(p.x()/rho, p.y()/rho, 0) ;
722 break ;
723 }
724 case kNZ : // + or - dz
725 {
726 if ( distZHigh > distZLow ) { norm = fHighNorm ; }
727 else { norm = fLowNorm; }
728 break ;
729 }
730 case kNSPhi:
731 {
732 norm = G4ThreeVector(sinSPhi, -cosSPhi, 0) ;
733 break ;
734 }
735 case kNEPhi:
736 {
737 norm = G4ThreeVector(-sinEPhi, cosEPhi, 0) ;
738 break;
739 }
740 default: // Should never reach this case ...
741 {
742 DumpInfo();
743 G4Exception("G4CutTubs::ApproxSurfaceNormal()",
744 "GeomSolids1002", JustWarning,
745 "Undefined side for valid surface normal to solid.");
746 break ;
747 }
748 }
749 return norm;
750}
CLHEP::Hep3Vector G4ThreeVector
double G4double
Definition G4Types.hh:83
void DumpInfo() const

Referenced by SurfaceNormal().

◆ BoundingLimits()

void G4CutTubs::BoundingLimits ( G4ThreeVector & pMin,
G4ThreeVector & pMax ) const
overridevirtual

Computes the bounding limits of the solid.

Parameters
[out]pMinThe minimum bounding limit point.
[out]pMaxThe maximum bounding limit point.

Reimplemented from G4VSolid.

Definition at line 210 of file G4CutTubs.cc.

211{
212 G4double rmin = GetInnerRadius();
213 G4double rmax = GetOuterRadius();
215 G4double dphi = GetDeltaPhiAngle();
216
217 G4double sinSphi = GetSinStartPhi();
218 G4double cosSphi = GetCosStartPhi();
219 G4double sinEphi = GetSinEndPhi();
220 G4double cosEphi = GetCosEndPhi();
221
222 G4ThreeVector norm;
223 G4double mag, topx, topy, dists, diste;
224 G4bool iftop;
225
226 // Find Zmin
227 //
228 G4double zmin;
229 norm = GetLowNorm();
230 mag = std::sqrt(norm.x()*norm.x() + norm.y()*norm.y());
231 topx = (mag == 0) ? 0 : -rmax*norm.x()/mag;
232 topy = (mag == 0) ? 0 : -rmax*norm.y()/mag;
233 dists = sinSphi*topx - cosSphi*topy;
234 diste = -sinEphi*topx + cosEphi*topy;
235 if (dphi > pi)
236 {
237 iftop = true;
238 if (dists > 0 && diste > 0) { iftop = false; }
239 }
240 else
241 {
242 iftop = false;
243 if (dists <= 0 && diste <= 0) { iftop = true; }
244 }
245 if (iftop)
246 {
247 zmin = -(norm.x()*topx + norm.y()*topy)/norm.z() - dz;
248 }
249 else
250 {
251 G4double z1 = -rmin*(norm.x()*cosSphi + norm.y()*sinSphi)/norm.z() - dz;
252 G4double z2 = -rmin*(norm.x()*cosEphi + norm.y()*sinEphi)/norm.z() - dz;
253 G4double z3 = -rmax*(norm.x()*cosSphi + norm.y()*sinSphi)/norm.z() - dz;
254 G4double z4 = -rmax*(norm.x()*cosEphi + norm.y()*sinEphi)/norm.z() - dz;
255 zmin = std::min(std::min(std::min(z1,z2),z3),z4);
256 }
257
258 // Find Zmax
259 //
260 G4double zmax;
261 norm = GetHighNorm();
262 mag = std::sqrt(norm.x()*norm.x() + norm.y()*norm.y());
263 topx = (mag == 0) ? 0 : -rmax*norm.x()/mag;
264 topy = (mag == 0) ? 0 : -rmax*norm.y()/mag;
265 dists = sinSphi*topx - cosSphi*topy;
266 diste = -sinEphi*topx + cosEphi*topy;
267 if (dphi > pi)
268 {
269 iftop = true;
270 if (dists > 0 && diste > 0) { iftop = false; }
271 }
272 else
273 {
274 iftop = false;
275 if (dists <= 0 && diste <= 0) { iftop = true; }
276 }
277 if (iftop)
278 {
279 zmax = -(norm.x()*topx + norm.y()*topy)/norm.z() + dz;
280 }
281 else
282 {
283 G4double z1 = -rmin*(norm.x()*cosSphi + norm.y()*sinSphi)/norm.z() + dz;
284 G4double z2 = -rmin*(norm.x()*cosEphi + norm.y()*sinEphi)/norm.z() + dz;
285 G4double z3 = -rmax*(norm.x()*cosSphi + norm.y()*sinSphi)/norm.z() + dz;
286 G4double z4 = -rmax*(norm.x()*cosEphi + norm.y()*sinEphi)/norm.z() + dz;
287 zmax = std::max(std::max(std::max(z1,z2),z3),z4);
288 }
289
290 // Find bounding box
291 //
292 if (dphi < twopi)
293 {
294 G4TwoVector vmin,vmax;
295 G4GeomTools::DiskExtent(rmin,rmax,
298 vmin,vmax);
299 pMin.set(vmin.x(),vmin.y(), zmin);
300 pMax.set(vmax.x(),vmax.y(), zmax);
301 }
302 else
303 {
304 pMin.set(-rmax,-rmax, zmin);
305 pMax.set( rmax, rmax, zmax);
306 }
307
308 // Check correctness of the bounding box
309 //
310 if (pMin.x() >= pMax.x() || pMin.y() >= pMax.y() || pMin.z() >= pMax.z())
311 {
312 std::ostringstream message;
313 message << "Bad bounding box (min >= max) for solid: "
314 << GetName() << " !"
315 << "\npMin = " << pMin
316 << "\npMax = " << pMax;
317 G4Exception("G4CutTubs::BoundingLimits()", "GeomMgt0001",
318 JustWarning, message);
319 DumpInfo();
320 }
321}
CLHEP::Hep2Vector G4TwoVector
bool G4bool
Definition G4Types.hh:86
double x() const
double y() const
void set(double x, double y, double z)
G4ThreeVector GetHighNorm() const
G4double GetZHalfLength() const
G4double GetInnerRadius() const
G4ThreeVector GetLowNorm() const
G4double GetDeltaPhiAngle() const
G4double GetOuterRadius() const
G4double GetSinStartPhi() const
G4double GetSinEndPhi() const
G4double GetCosStartPhi() const
G4double GetCosEndPhi() const
static G4bool DiskExtent(G4double rmin, G4double rmax, G4double startPhi, G4double delPhi, G4TwoVector &pmin, G4TwoVector &pmax)

Referenced by CalculateExtent(), and GetPointOnSurface().

◆ CalculateExtent()

G4bool G4CutTubs::CalculateExtent ( const EAxis pAxis,
const G4VoxelLimits & pVoxelLimit,
const G4AffineTransform & pTransform,
G4double & pmin,
G4double & pmax ) const
overridevirtual

Calculates the minimum and maximum extent of the solid, when under the specified transform, and within the specified limits.

Parameters
[in]pAxisThe axis along which compute the extent.
[in]pVoxelLimitThe limiting space dictated by voxels.
[in]pTransformThe internal transformation applied to the solid.
[out]pMinThe minimum extent value.
[out]pMaxThe maximum extent value.
Returns
True if the solid is intersected by the extent region.

Implements G4VSolid.

Definition at line 327 of file G4CutTubs.cc.

332{
333 G4ThreeVector bmin, bmax;
334 G4bool exist;
335
336 // Get bounding box
337 BoundingLimits(bmin,bmax);
338
339 // Check bounding box
340 G4BoundingEnvelope bbox(bmin,bmax);
341#ifdef G4BBOX_EXTENT
342 return bbox.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax);
343#endif
344 if (bbox.BoundingBoxVsVoxelLimits(pAxis,pVoxelLimit,pTransform,pMin,pMax))
345 {
346 return exist = pMin < pMax;
347 }
348
349 // Get parameters of the solid
350 G4double rmin = GetInnerRadius();
351 G4double rmax = GetOuterRadius();
352 G4double dphi = GetDeltaPhiAngle();
353 G4double zmin = bmin.z();
354 G4double zmax = bmax.z();
355
356 // Find bounding envelope and calculate extent
357 //
358 const G4int NSTEPS = 24; // number of steps for whole circle
359 G4double astep = twopi/NSTEPS; // max angle for one step
360 G4int ksteps = (dphi <= astep) ? 1 : (G4int)((dphi-deg)/astep) + 1;
361 G4double ang = dphi/ksteps;
362
363 G4double sinHalf = std::sin(0.5*ang);
364 G4double cosHalf = std::cos(0.5*ang);
365 G4double sinStep = 2.*sinHalf*cosHalf;
366 G4double cosStep = 1. - 2.*sinHalf*sinHalf;
367 G4double rext = rmax/cosHalf;
368
369 // bounding envelope for full cylinder consists of two polygons,
370 // in other cases it is a sequence of quadrilaterals
371 if (rmin == 0 && dphi == twopi)
372 {
373 G4double sinCur = sinHalf;
374 G4double cosCur = cosHalf;
375
376 G4ThreeVectorList baseA(NSTEPS),baseB(NSTEPS);
377 for (G4int k=0; k<NSTEPS; ++k)
378 {
379 baseA[k].set(rext*cosCur,rext*sinCur,zmin);
380 baseB[k].set(rext*cosCur,rext*sinCur,zmax);
381
382 G4double sinTmp = sinCur;
383 sinCur = sinCur*cosStep + cosCur*sinStep;
384 cosCur = cosCur*cosStep - sinTmp*sinStep;
385 }
386 std::vector<const G4ThreeVectorList *> polygons(2);
387 polygons[0] = &baseA;
388 polygons[1] = &baseB;
389 G4BoundingEnvelope benv(bmin,bmax,polygons);
390 exist = benv.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax);
391 }
392 else
393 {
394 G4double sinStart = GetSinStartPhi();
395 G4double cosStart = GetCosStartPhi();
396 G4double sinEnd = GetSinEndPhi();
397 G4double cosEnd = GetCosEndPhi();
398 G4double sinCur = sinStart*cosHalf + cosStart*sinHalf;
399 G4double cosCur = cosStart*cosHalf - sinStart*sinHalf;
400
401 // set quadrilaterals
402 G4ThreeVectorList pols[NSTEPS+2];
403 for (G4int k=0; k<ksteps+2; ++k)
404 {
405 pols[k].resize(4);
406 }
407 pols[0][0].set(rmin*cosStart,rmin*sinStart,zmax);
408 pols[0][1].set(rmin*cosStart,rmin*sinStart,zmin);
409 pols[0][2].set(rmax*cosStart,rmax*sinStart,zmin);
410 pols[0][3].set(rmax*cosStart,rmax*sinStart,zmax);
411 for (G4int k=1; k<ksteps+1; ++k)
412 {
413 pols[k][0].set(rmin*cosCur,rmin*sinCur,zmax);
414 pols[k][1].set(rmin*cosCur,rmin*sinCur,zmin);
415 pols[k][2].set(rext*cosCur,rext*sinCur,zmin);
416 pols[k][3].set(rext*cosCur,rext*sinCur,zmax);
417
418 G4double sinTmp = sinCur;
419 sinCur = sinCur*cosStep + cosCur*sinStep;
420 cosCur = cosCur*cosStep - sinTmp*sinStep;
421 }
422 pols[ksteps+1][0].set(rmin*cosEnd,rmin*sinEnd,zmax);
423 pols[ksteps+1][1].set(rmin*cosEnd,rmin*sinEnd,zmin);
424 pols[ksteps+1][2].set(rmax*cosEnd,rmax*sinEnd,zmin);
425 pols[ksteps+1][3].set(rmax*cosEnd,rmax*sinEnd,zmax);
426
427 // set envelope and calculate extent
428 std::vector<const G4ThreeVectorList *> polygons;
429 polygons.resize(ksteps+2);
430 for (G4int k=0; k<ksteps+2; ++k) { polygons[k] = &pols[k]; }
431 G4BoundingEnvelope benv(bmin,bmax,polygons);
432 exist = benv.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax);
433 }
434 return exist;
435}
std::vector< G4ThreeVector > G4ThreeVectorList
int G4int
Definition G4Types.hh:85
void BoundingLimits(G4ThreeVector &pMin, G4ThreeVector &pMax) const override
Definition G4CutTubs.cc:210

◆ CheckDPhiAngle()

void G4CutTubs::CheckDPhiAngle ( G4double dPhi)
inlineprotected

◆ CheckPhiAngles()

void G4CutTubs::CheckPhiAngles ( G4double sPhi,
G4double dPhi )
inlineprotected

Referenced by G4CutTubs().

◆ CheckSPhiAngle()

void G4CutTubs::CheckSPhiAngle ( G4double sPhi)
inlineprotected

Reset relevant flags and angle values.

◆ Clone()

G4VSolid * G4CutTubs::Clone ( ) const
overridevirtual

Makes a clone of the object for use in multi-treading.

Returns
A pointer to the new cloned allocated solid.

Reimplemented from G4VSolid.

Definition at line 1764 of file G4CutTubs.cc.

1765{
1766 return new G4CutTubs(*this);
1767}
G4CutTubs(const G4String &pName, G4double pRMin, G4double pRMax, G4double pDz, G4double pSPhi, G4double pDPhi, G4ThreeVector pLowNorm, G4ThreeVector pHighNorm)
Definition G4CutTubs.cc:63

◆ CreatePolyhedron()

G4Polyhedron * G4CutTubs::CreatePolyhedron ( ) const
overridevirtual

Creates a Polyhedron used for Visualisation. It is the caller's responsibility to delete it. A null pointer means "not created".

Reimplemented from G4VSolid.

Definition at line 2030 of file G4CutTubs.cc.

2031{
2032 typedef G4double G4double3[3];
2033 typedef G4int G4int4[4];
2034
2035 auto ph = new G4Polyhedron;
2036 G4Polyhedron *ph1 = new G4PolyhedronTubs (fRMin, fRMax, fDz, fSPhi, fDPhi);
2037 G4int nn=ph1->GetNoVertices();
2038 G4int nf=ph1->GetNoFacets();
2039 auto xyz = new G4double3[nn]; // number of nodes
2040 auto faces = new G4int4[nf] ; // number of faces
2041
2042 for(G4int i=0; i<nn; ++i)
2043 {
2044 xyz[i][0]=ph1->GetVertex(i+1).x();
2045 xyz[i][1]=ph1->GetVertex(i+1).y();
2046 G4double tmpZ=ph1->GetVertex(i+1).z();
2047 if(tmpZ>=fDz-kCarTolerance)
2048 {
2049 xyz[i][2]=GetCutZ(G4ThreeVector(xyz[i][0],xyz[i][1],fDz));
2050 }
2051 else if(tmpZ<=-fDz+kCarTolerance)
2052 {
2053 xyz[i][2]=GetCutZ(G4ThreeVector(xyz[i][0],xyz[i][1],-fDz));
2054 }
2055 else
2056 {
2057 xyz[i][2]=tmpZ;
2058 }
2059 }
2060 G4int iNodes[4];
2061 G4int* iEdge = nullptr;
2062 G4int n;
2063 for(G4int i=0; i<nf ; ++i)
2064 {
2065 ph1->GetFacet(i+1,n,iNodes,iEdge);
2066 for(G4int k=0; k<n; ++k)
2067 {
2068 faces[i][k]=iNodes[k];
2069 }
2070 for(G4int k=n; k<4; ++k)
2071 {
2072 faces[i][k]=0;
2073 }
2074 }
2075 ph->createPolyhedron(nn,nf,xyz,faces);
2076
2077 delete [] xyz;
2078 delete [] faces;
2079 delete ph1;
2080
2081 return ph;
2082}
G4double GetCutZ(const G4ThreeVector &p) const
G4Point3D GetVertex(G4int index) const
void GetFacet(G4int iFace, G4int &n, G4int *iNodes, G4int *edgeFlags=nullptr, G4int *iFaces=nullptr) const
G4int GetNoFacets() const
G4int GetNoVertices() const

◆ DescribeYourselfTo()

void G4CutTubs::DescribeYourselfTo ( G4VGraphicsScene & scene) const
overridevirtual

Methods for creating graphical representations (i.e. for visualisation).

Implements G4VSolid.

Definition at line 2025 of file G4CutTubs.cc.

2026{
2027 scene.AddSolid (*this) ;
2028}
virtual void AddSolid(const G4Box &)=0

◆ DistanceToIn() [1/2]

G4double G4CutTubs::DistanceToIn ( const G4ThreeVector & p) const
overridevirtual

Calculates the distance to the nearest surface of a shape from an outside point. The distance can be an underestimate.

Parameters
[in]pThe point at offset p.
Returns
The safety distance to enter the shape.

Implements G4VSolid.

Definition at line 1215 of file G4CutTubs.cc.

1216{
1217 G4double safRMin,safRMax,safZLow,safZHigh,safePhi,safe,rho,cosPsi;
1218 G4ThreeVector vZ=G4ThreeVector(0,0,fDz);
1219
1220 // Distance to R
1221 //
1222 rho = std::sqrt(p.x()*p.x() + p.y()*p.y()) ;
1223
1224 safRMin = fRMin- rho ;
1225 safRMax = rho - fRMax ;
1226
1227 // Distances to ZCut(Low/High)
1228
1229 // Dist to Low Cut
1230 //
1231 safZLow = (p+vZ).dot(fLowNorm);
1232
1233 // Dist to High Cut
1234 //
1235 safZHigh = (p-vZ).dot(fHighNorm);
1236
1237 safe = std::max(safZLow,safZHigh);
1238
1239 if ( safRMin > safe ) { safe = safRMin; }
1240 if ( safRMax> safe ) { safe = safRMax; }
1241
1242 // Distance to Phi
1243 //
1244 if ( (!fPhiFullCutTube) && ((rho) != 0.0) )
1245 {
1246 // Psi=angle from central phi to point
1247 //
1248 cosPsi = (p.x()*cosCPhi + p.y()*sinCPhi)/rho ;
1249
1250 if ( cosPsi < cosHDPhi )
1251 {
1252 // Point lies outside phi range
1253
1254 if ( (p.y()*cosCPhi - p.x()*sinCPhi) <= 0 )
1255 {
1256 safePhi = std::fabs(p.x()*sinSPhi - p.y()*cosSPhi) ;
1257 }
1258 else
1259 {
1260 safePhi = std::fabs(p.x()*sinEPhi - p.y()*cosEPhi) ;
1261 }
1262 if ( safePhi > safe ) { safe = safePhi; }
1263 }
1264 }
1265 if ( safe < 0 ) { safe = 0; }
1266
1267 return safe ;
1268}

◆ DistanceToIn() [2/2]

G4double G4CutTubs::DistanceToIn ( const G4ThreeVector & p,
const G4ThreeVector & v ) const
overridevirtual

Returns the distance along the normalised vector 'v' to the shape, from the point at offset 'p'. If there is no intersection, returns kInfinity. The first intersection resulting from 'leaving' a surface/volume is discarded. Hence, it is tolerant of points on the surface of the shape.

Parameters
[in]pThe point at offset p.
[in]vThe normalised direction vector.
Returns
The distance to enter the shape.

Implements G4VSolid.

Definition at line 774 of file G4CutTubs.cc.

776{
777 G4double snxt = kInfinity ; // snxt = default return value
778 G4double tolORMin2, tolIRMax2 ; // 'generous' radii squared
779 G4double tolORMax2, tolIRMin2;
780 const G4double dRmax = 100.*fRMax;
781 G4ThreeVector vZ=G4ThreeVector(0,0,fDz);
782
783 // Intersection point variables
784 //
785 G4double Dist, sd=0, xi, yi, zi, rho2, inum, iden, cosPsi, Comp,calf ;
786 G4double t1, t2, t3, b, c, d ; // Quadratic solver variables
787 G4double distZLow,distZHigh;
788 // Calculate tolerant rmin and rmax
789
790 if (fRMin > kRadTolerance)
791 {
792 tolORMin2 = (fRMin - halfRadTolerance)*(fRMin - halfRadTolerance) ;
793 tolIRMin2 = (fRMin + halfRadTolerance)*(fRMin + halfRadTolerance) ;
794 }
795 else
796 {
797 tolORMin2 = 0.0 ;
798 tolIRMin2 = 0.0 ;
799 }
800 tolORMax2 = (fRMax + halfRadTolerance)*(fRMax + halfRadTolerance) ;
801 tolIRMax2 = (fRMax - halfRadTolerance)*(fRMax - halfRadTolerance) ;
802
803 // Intersection with ZCut surfaces
804
805 // dist to Low Cut
806 //
807 distZLow =(p+vZ).dot(fLowNorm);
808
809 // dist to High Cut
810 //
811 distZHigh = (p-vZ).dot(fHighNorm);
812
813 if ( distZLow >= -halfCarTolerance )
814 {
815 calf = v.dot(fLowNorm);
816 if (calf<0)
817 {
818 sd = -distZLow/calf;
819 if(sd < 0.0) { sd = 0.0; }
820
821 xi = p.x() + sd*v.x() ; // Intersection coords
822 yi = p.y() + sd*v.y() ;
823 rho2 = xi*xi + yi*yi ;
824
825 // Check validity of intersection
826
827 if ((tolIRMin2 <= rho2) && (rho2 <= tolIRMax2))
828 {
829 if (!fPhiFullCutTube && (rho2 != 0.0))
830 {
831 // Psi = angle made with central (average) phi of shape
832 //
833 inum = xi*cosCPhi + yi*sinCPhi ;
834 iden = std::sqrt(rho2) ;
835 cosPsi = inum/iden ;
836 if (cosPsi >= cosHDPhiIT) { return sd ; }
837 }
838 else
839 {
840 return sd ;
841 }
842 }
843 }
844 else
845 {
846 if ( sd<halfCarTolerance )
847 {
848 if(calf>=0) { sd=kInfinity; }
849 return sd ; // On/outside extent, and heading away
850 } // -> cannot intersect
851 }
852 }
853
854 if(distZHigh >= -halfCarTolerance )
855 {
856 calf = v.dot(fHighNorm);
857 if (calf<0)
858 {
859 sd = -distZHigh/calf;
860
861 if(sd < 0.0) { sd = 0.0; }
862
863 xi = p.x() + sd*v.x() ; // Intersection coords
864 yi = p.y() + sd*v.y() ;
865 rho2 = xi*xi + yi*yi ;
866
867 // Check validity of intersection
868
869 if ((tolIRMin2 <= rho2) && (rho2 <= tolIRMax2))
870 {
871 if (!fPhiFullCutTube && (rho2 != 0.0))
872 {
873 // Psi = angle made with central (average) phi of shape
874 //
875 inum = xi*cosCPhi + yi*sinCPhi ;
876 iden = std::sqrt(rho2) ;
877 cosPsi = inum/iden ;
878 if (cosPsi >= cosHDPhiIT) { return sd ; }
879 }
880 else
881 {
882 return sd ;
883 }
884 }
885 }
886 else
887 {
888 if ( sd<halfCarTolerance )
889 {
890 if(calf>=0) { sd=kInfinity; }
891 return sd ; // On/outside extent, and heading away
892 } // -> cannot intersect
893 }
894 }
895
896 // -> Can not intersect z surfaces
897 //
898 // Intersection with rmax (possible return) and rmin (must also check phi)
899 //
900 // Intersection point (xi,yi,zi) on line x=p.x+t*v.x etc.
901 //
902 // Intersects with x^2+y^2=R^2
903 //
904 // Hence (v.x^2+v.y^2)t^2+ 2t(p.x*v.x+p.y*v.y)+p.x^2+p.y^2-R^2=0
905 // t1 t2 t3
906
907 t1 = 1.0 - v.z()*v.z() ;
908 t2 = p.x()*v.x() + p.y()*v.y() ;
909 t3 = p.x()*p.x() + p.y()*p.y() ;
910 if ( t1 > 0 ) // Check not || to z axis
911 {
912 b = t2/t1 ;
913 c = t3 - fRMax*fRMax ;
914
915 if ((t3 >= tolORMax2) && (t2<0)) // This also handles the tangent case
916 {
917 // Try outer cylinder intersection, c=(t3-fRMax*fRMax)/t1;
918
919 c /= t1 ;
920 d = b*b - c ;
921
922 if (d >= 0) // If real root
923 {
924 sd = c/(-b+std::sqrt(d));
925 if (sd >= 0) // If 'forwards'
926 {
927 if ( sd>dRmax ) // Avoid rounding errors due to precision issues on
928 { // 64 bits systems. Split long distances and recompute
929 G4double fTerm = sd-std::fmod(sd,dRmax);
930 sd = fTerm + DistanceToIn(p+fTerm*v,v);
931 }
932 // Check z intersection
933 //
934 zi = p.z() + sd*v.z() ;
935 xi = p.x() + sd*v.x() ;
936 yi = p.y() + sd*v.y() ;
937 if ((-xi*fLowNorm.x()-yi*fLowNorm.y()
938 -(zi+fDz)*fLowNorm.z())>-halfCarTolerance)
939 {
940 if ((-xi*fHighNorm.x()-yi*fHighNorm.y()
941 +(fDz-zi)*fHighNorm.z())>-halfCarTolerance)
942 {
943 // Z ok. Check phi intersection if reqd
944 //
945 if (fPhiFullCutTube)
946 {
947 return sd ;
948 }
949
950 xi = p.x() + sd*v.x() ;
951 yi = p.y() + sd*v.y() ;
952 cosPsi = (xi*cosCPhi + yi*sinCPhi)/fRMax ;
953 if (cosPsi >= cosHDPhiIT) { return sd ; }
954 } // end if std::fabs(zi)
955 }
956 } // end if (sd>=0)
957 } // end if (d>=0)
958 } // end if (r>=fRMax)
959 else
960 {
961 // Inside outer radius :
962 // check not inside, and heading through tubs (-> 0 to in)
963 if ((t3 > tolIRMin2) && (t2 < 0)
964 && (std::fabs(p.z()) <= std::fabs(GetCutZ(p))-halfCarTolerance ))
965 {
966 // Inside both radii, delta r -ve, inside z extent
967
968 if (!fPhiFullCutTube)
969 {
970 inum = p.x()*cosCPhi + p.y()*sinCPhi ;
971 iden = std::sqrt(t3) ;
972 cosPsi = inum/iden ;
973 if (cosPsi >= cosHDPhiIT)
974 {
975 // In the old version, the small negative tangent for the point
976 // on surface was not taken in account, and returning 0.0 ...
977 // New version: check the tangent for the point on surface and
978 // if no intersection, return kInfinity, if intersection instead
979 // return sd.
980 //
981 c = t3-fRMax*fRMax;
982 if ( c<=0.0 )
983 {
984 return 0.0;
985 }
986
987 c = c/t1 ;
988 d = b*b-c;
989 if ( d>=0.0 )
990 {
991 snxt = c/(-b+std::sqrt(d)); // using safe solution
992 // for quadratic equation
993 if ( snxt < halfCarTolerance ) { snxt=0; }
994 return snxt ;
995 }
996
997 return kInfinity;
998 }
999 }
1000 else
1001 {
1002 // In the old version, the small negative tangent for the point
1003 // on surface was not taken in account, and returning 0.0 ...
1004 // New version: check the tangent for the point on surface and
1005 // if no intersection, return kInfinity, if intersection instead
1006 // return sd.
1007 //
1008 c = t3 - fRMax*fRMax;
1009 if ( c<=0.0 )
1010 {
1011 return 0.0;
1012 }
1013
1014 c = c/t1 ;
1015 d = b*b-c;
1016 if ( d>=0.0 )
1017 {
1018 snxt= c/(-b+std::sqrt(d)); // using safe solution
1019 // for quadratic equation
1020 if ( snxt < halfCarTolerance ) { snxt=0; }
1021 return snxt ;
1022 }
1023
1024 return kInfinity;
1025 } // end if (!fPhiFullCutTube)
1026 } // end if (t3>tolIRMin2)
1027 } // end if (Inside Outer Radius)
1028
1029 if ( fRMin != 0.0 ) // Try inner cylinder intersection
1030 {
1031 c = (t3 - fRMin*fRMin)/t1 ;
1032 d = b*b - c ;
1033 if ( d >= 0.0 ) // If real root
1034 {
1035 // Always want 2nd root - we are outside and know rmax Hit was bad
1036 // - If on surface of rmin also need farthest root
1037
1038 sd =( b > 0. )? c/(-b - std::sqrt(d)) : (-b + std::sqrt(d));
1039 if (sd >= -10*halfCarTolerance) // check forwards
1040 {
1041 // Check z intersection
1042 //
1043 if (sd < 0.0) { sd = 0.0; }
1044 if (sd>dRmax) // Avoid rounding errors due to precision issues seen
1045 { // 64 bits systems. Split long distances and recompute
1046 G4double fTerm = sd-std::fmod(sd,dRmax);
1047 sd = fTerm + DistanceToIn(p+fTerm*v,v);
1048 }
1049 zi = p.z() + sd*v.z() ;
1050 xi = p.x() + sd*v.x() ;
1051 yi = p.y() + sd*v.y() ;
1052 if ((-xi*fLowNorm.x()-yi*fLowNorm.y()
1053 -(zi+fDz)*fLowNorm.z())>-halfCarTolerance)
1054 {
1055 if ((-xi*fHighNorm.x()-yi*fHighNorm.y()
1056 +(fDz-zi)*fHighNorm.z())>-halfCarTolerance)
1057 {
1058 // Z ok. Check phi
1059 //
1060 if ( fPhiFullCutTube )
1061 {
1062 return sd ;
1063 }
1064
1065 cosPsi = (xi*cosCPhi + yi*sinCPhi)/fRMin ;
1066 if (cosPsi >= cosHDPhiIT)
1067 {
1068 // Good inner radius isect
1069 // - but earlier phi isect still possible
1070 //
1071 snxt = sd ;
1072 }
1073 } // end if std::fabs(zi)
1074 }
1075 } // end if (sd>=0)
1076 } // end if (d>=0)
1077 } // end if (fRMin)
1078 }
1079
1080 // Phi segment intersection
1081 //
1082 // o Tolerant of points inside phi planes by up to kCarTolerance*0.5
1083 //
1084 // o NOTE: Large duplication of code between sphi & ephi checks
1085 // -> only diffs: sphi -> ephi, Comp -> -Comp and half-plane
1086 // intersection check <=0 -> >=0
1087 // -> use some form of loop Construct ?
1088 //
1089 if ( !fPhiFullCutTube )
1090 {
1091 // First phi surface (Starting phi)
1092 //
1093 Comp = v.x()*sinSPhi - v.y()*cosSPhi ;
1094
1095 if ( Comp < 0 ) // Component in outwards normal dirn
1096 {
1097 Dist = (p.y()*cosSPhi - p.x()*sinSPhi) ;
1098
1099 if ( Dist < halfCarTolerance )
1100 {
1101 sd = Dist/Comp ;
1102
1103 if (sd < snxt)
1104 {
1105 if ( sd < 0 ) { sd = 0.0; }
1106 zi = p.z() + sd*v.z() ;
1107 xi = p.x() + sd*v.x() ;
1108 yi = p.y() + sd*v.y() ;
1109 if ((-xi*fLowNorm.x()-yi*fLowNorm.y()
1110 -(zi+fDz)*fLowNorm.z())>-halfCarTolerance)
1111 {
1112 if ((-xi*fHighNorm.x()-yi*fHighNorm.y()
1113 +(fDz-zi)*fHighNorm.z())>-halfCarTolerance)
1114 {
1115 rho2 = xi*xi + yi*yi ;
1116 if ( ( (rho2 >= tolIRMin2) && (rho2 <= tolIRMax2) )
1117 || ( (rho2 > tolORMin2) && (rho2 < tolIRMin2)
1118 && ( v.y()*cosSPhi - v.x()*sinSPhi > 0 )
1119 && ( v.x()*cosSPhi + v.y()*sinSPhi >= 0 ) )
1120 || ( (rho2 > tolIRMax2) && (rho2 < tolORMax2)
1121 && (v.y()*cosSPhi - v.x()*sinSPhi > 0)
1122 && (v.x()*cosSPhi + v.y()*sinSPhi < 0) ) )
1123 {
1124 // z and r intersections good
1125 // - check intersecting with correct half-plane
1126 //
1127 if ((yi*cosCPhi-xi*sinCPhi) <= halfCarTolerance) { snxt = sd; }
1128 }
1129 } //two Z conditions
1130 }
1131 }
1132 }
1133 }
1134
1135 // Second phi surface (Ending phi)
1136 //
1137 Comp = -(v.x()*sinEPhi - v.y()*cosEPhi) ;
1138
1139 if (Comp < 0 ) // Component in outwards normal dirn
1140 {
1141 Dist = -(p.y()*cosEPhi - p.x()*sinEPhi) ;
1142
1143 if ( Dist < halfCarTolerance )
1144 {
1145 sd = Dist/Comp ;
1146
1147 if (sd < snxt)
1148 {
1149 if ( sd < 0 ) { sd = 0; }
1150 zi = p.z() + sd*v.z() ;
1151 xi = p.x() + sd*v.x() ;
1152 yi = p.y() + sd*v.y() ;
1153 if ((-xi*fLowNorm.x()-yi*fLowNorm.y()
1154 -(zi+fDz)*fLowNorm.z())>-halfCarTolerance)
1155 {
1156 if ((-xi*fHighNorm.x()-yi*fHighNorm.y()
1157 +(fDz-zi)*fHighNorm.z())>-halfCarTolerance)
1158 {
1159 xi = p.x() + sd*v.x() ;
1160 yi = p.y() + sd*v.y() ;
1161 rho2 = xi*xi + yi*yi ;
1162 if ( ( (rho2 >= tolIRMin2) && (rho2 <= tolIRMax2) )
1163 || ( (rho2 > tolORMin2) && (rho2 < tolIRMin2)
1164 && (v.x()*sinEPhi - v.y()*cosEPhi > 0)
1165 && (v.x()*cosEPhi + v.y()*sinEPhi >= 0) )
1166 || ( (rho2 > tolIRMax2) && (rho2 < tolORMax2)
1167 && (v.x()*sinEPhi - v.y()*cosEPhi > 0)
1168 && (v.x()*cosEPhi + v.y()*sinEPhi < 0) ) )
1169 {
1170 // z and r intersections good
1171 // - check intersecting with correct half-plane
1172 //
1173 if ( (yi*cosCPhi-xi*sinCPhi) >= -halfCarTolerance )
1174 {
1175 snxt = sd;
1176 }
1177 } //?? >=-halfCarTolerance
1178 }
1179 } // two Z conditions
1180 }
1181 }
1182 } // Comp < 0
1183 } // !fPhiFullTube
1184 if ( snxt<halfCarTolerance ) { snxt=0; }
1185
1186 return snxt ;
1187}
double dot(const Hep3Vector &) const
G4double DistanceToIn(const G4ThreeVector &p, const G4ThreeVector &v) const override
Definition G4CutTubs.cc:774

Referenced by DistanceToIn().

◆ DistanceToOut() [1/2]

G4double G4CutTubs::DistanceToOut ( const G4ThreeVector & p) const
overridevirtual

Calculates the distance to the nearest surface of a shape from an inside point 'p'. The distance can be an underestimate.

Parameters
[in]pThe point at offset p.
Returns
The safety distance to exit the shape.

Implements G4VSolid.

Definition at line 1708 of file G4CutTubs.cc.

1709{
1710 G4double safRMin,safRMax,safZLow,safZHigh,safePhi,safe,rho;
1711 G4ThreeVector vZ=G4ThreeVector(0,0,fDz);
1712
1713 rho = std::sqrt(p.x()*p.x() + p.y()*p.y()) ; // Distance to R
1714
1715 safRMin = rho - fRMin ;
1716 safRMax = fRMax - rho ;
1717
1718 // Distances to ZCut(Low/High)
1719
1720 // Dist to Low Cut
1721 //
1722 safZLow = std::fabs((p+vZ).dot(fLowNorm));
1723
1724 // Dist to High Cut
1725 //
1726 safZHigh = std::fabs((p-vZ).dot(fHighNorm));
1727 safe = std::min(safZLow,safZHigh);
1728
1729 if ( safRMin < safe ) { safe = safRMin; }
1730 if ( safRMax< safe ) { safe = safRMax; }
1731
1732 // Check if phi divided, Calc distances closest phi plane
1733 //
1734 if ( !fPhiFullCutTube )
1735 {
1736 if ( p.y()*cosCPhi-p.x()*sinCPhi <= 0 )
1737 {
1738 safePhi = -(p.x()*sinSPhi - p.y()*cosSPhi) ;
1739 }
1740 else
1741 {
1742 safePhi = (p.x()*sinEPhi - p.y()*cosEPhi) ;
1743 }
1744 if (safePhi < safe) { safe = safePhi ; }
1745 }
1746 if ( safe < 0 ) { safe = 0; }
1747
1748 return safe ;
1749}

◆ DistanceToOut() [2/2]

G4double G4CutTubs::DistanceToOut ( const G4ThreeVector & p,
const G4ThreeVector & v,
const G4bool calcNorm = false,
G4bool * validNorm = nullptr,
G4ThreeVector * n = nullptr ) const
overridevirtual

Returns the distance along the normalised vector 'v' to the shape, from a point at an offset 'p' inside or on the surface of the shape. Intersections with surfaces, when the point is less than Tolerance/2 from a surface must be ignored.

Parameters
[in]pThe point at offset p.
[in]vThe normalised direction vector.
[in]calcNormFlag to indicate if to calculate the normal or not.
[out]validNormFlag set to true if the solid lies entirely behind or on the exiting surface. It is set false if the solid does not lie entirely behind or on the exiting surface. 'calcNorm' must be true, otherwise it is unused.
[out]nThe exiting outwards normal vector (undefined Magnitude). 'calcNorm' must be true, otherwise it is unused.
Returns
The distance to exit the shape.

Implements G4VSolid.

Definition at line 1275 of file G4CutTubs.cc.

1280{
1281 enum ESide {kNull,kRMin,kRMax,kSPhi,kEPhi,kPZ,kMZ};
1282
1283 ESide side=kNull , sider=kNull, sidephi=kNull ;
1284 G4double snxt=kInfinity, srd=kInfinity,sz=kInfinity, sphi=kInfinity ;
1285 G4double deltaR, t1, t2, t3, b, c, d2, roMin2 ;
1286 G4double distZLow,distZHigh,calfH,calfL;
1287 G4ThreeVector vZ=G4ThreeVector(0,0,fDz);
1288
1289 // Vars for phi intersection:
1290 //
1291 G4double pDistS, compS, pDistE, compE, sphi2, xi, yi, vphi, roi2 ;
1292
1293 // Z plane intersection
1294 // Distances to ZCut(Low/High)
1295
1296 // dist to Low Cut
1297 //
1298 distZLow =(p+vZ).dot(fLowNorm);
1299
1300 // dist to High Cut
1301 //
1302 distZHigh = (p-vZ).dot(fHighNorm);
1303
1304 calfH = v.dot(fHighNorm);
1305 calfL = v.dot(fLowNorm);
1306
1307 if (calfH > 0 )
1308 {
1309 if ( distZHigh < halfCarTolerance )
1310 {
1311 snxt = -distZHigh/calfH ;
1312 side = kPZ ;
1313 }
1314 else
1315 {
1316 if (calcNorm)
1317 {
1318 *n = G4ThreeVector(0,0,1) ;
1319 *validNorm = true ;
1320 }
1321 return snxt = 0 ;
1322 }
1323 }
1324 if ( calfL>0)
1325 {
1326
1327 if ( distZLow < halfCarTolerance )
1328 {
1329 sz = -distZLow/calfL ;
1330 if(sz<snxt){
1331 snxt=sz;
1332 side = kMZ ;
1333 }
1334
1335 }
1336 else
1337 {
1338 if (calcNorm)
1339 {
1340 *n = G4ThreeVector(0,0,-1) ;
1341 *validNorm = true ;
1342 }
1343 return snxt = 0.0 ;
1344 }
1345 }
1346 if((calfH<=0)&&(calfL<=0))
1347 {
1348 snxt = kInfinity ; // Travel perpendicular to z axis
1349 side = kNull;
1350 }
1351 // Radial Intersections
1352 //
1353 // Find intersection with cylinders at rmax/rmin
1354 // Intersection point (xi,yi,zi) on line x=p.x+t*v.x etc.
1355 //
1356 // Intersects with x^2+y^2=R^2
1357 //
1358 // Hence (v.x^2+v.y^2)t^2+ 2t(p.x*v.x+p.y*v.y)+p.x^2+p.y^2-R^2=0
1359 //
1360 // t1 t2 t3
1361
1362 t1 = 1.0 - v.z()*v.z() ; // since v normalised
1363 t2 = p.x()*v.x() + p.y()*v.y() ;
1364 t3 = p.x()*p.x() + p.y()*p.y() ;
1365
1366 if ( snxt > 10*(fDz+fRMax) ) { roi2 = 2*fRMax*fRMax; }
1367 else { roi2 = snxt*snxt*t1 + 2*snxt*t2 + t3; } // radius^2 on +-fDz
1368
1369 if ( t1 > 0 ) // Check not parallel
1370 {
1371 // Calculate srd, r exit distance
1372
1373 if ( (t2 >= 0.0) && (roi2 > fRMax*(fRMax + kRadTolerance)) )
1374 {
1375 // Delta r not negative => leaving via rmax
1376
1377 deltaR = t3 - fRMax*fRMax ;
1378
1379 // NOTE: Should use rho-fRMax<-kRadTolerance*0.5
1380 // - avoid sqrt for efficiency
1381
1382 if ( deltaR < -kRadTolerance*fRMax )
1383 {
1384 b = t2/t1 ;
1385 c = deltaR/t1 ;
1386 d2 = b*b-c;
1387 if( d2 >= 0 ) { srd = c/( -b - std::sqrt(d2)); }
1388 else { srd = 0.; }
1389 sider = kRMax ;
1390 }
1391 else
1392 {
1393 // On tolerant boundary & heading outwards (or perpendicular to)
1394 // outer radial surface -> leaving immediately
1395
1396 if ( calcNorm )
1397 {
1398 *n = G4ThreeVector(p.x()/fRMax,p.y()/fRMax,0) ;
1399 *validNorm = true ;
1400 }
1401 return snxt = 0 ; // Leaving by rmax immediately
1402 }
1403 }
1404 else if ( t2 < 0. ) // i.e. t2 < 0; Possible rmin intersection
1405 {
1406 roMin2 = t3 - t2*t2/t1 ; // min ro2 of the plane of movement
1407
1408 if ( (fRMin != 0.0) && (roMin2 < fRMin*(fRMin - kRadTolerance)) )
1409 {
1410 deltaR = t3 - fRMin*fRMin ;
1411 b = t2/t1 ;
1412 c = deltaR/t1 ;
1413 d2 = b*b - c ;
1414
1415 if ( d2 >= 0 ) // Leaving via rmin
1416 {
1417 // NOTE: SHould use rho-rmin>kRadTolerance*0.5
1418 // - avoid sqrt for efficiency
1419
1420 if (deltaR > kRadTolerance*fRMin)
1421 {
1422 srd = c/(-b+std::sqrt(d2));
1423 sider = kRMin ;
1424 }
1425 else
1426 {
1427 if ( calcNorm ) { *validNorm = false; } // Concave side
1428 return snxt = 0.0;
1429 }
1430 }
1431 else // No rmin intersect -> must be rmax intersect
1432 {
1433 deltaR = t3 - fRMax*fRMax ;
1434 c = deltaR/t1 ;
1435 d2 = b*b-c;
1436 if( d2 >=0. )
1437 {
1438 srd = -b + std::sqrt(d2) ;
1439 sider = kRMax ;
1440 }
1441 else // Case: On the border+t2<kRadTolerance
1442 // (v is perpendicular to the surface)
1443 {
1444 if (calcNorm)
1445 {
1446 *n = G4ThreeVector(p.x()/fRMax,p.y()/fRMax,0) ;
1447 *validNorm = true ;
1448 }
1449 return snxt = 0.0;
1450 }
1451 }
1452 }
1453 else if ( roi2 > fRMax*(fRMax + kRadTolerance) )
1454 // No rmin intersect -> must be rmax intersect
1455 {
1456 deltaR = t3 - fRMax*fRMax ;
1457 b = t2/t1 ;
1458 c = deltaR/t1;
1459 d2 = b*b-c;
1460 if( d2 >= 0 )
1461 {
1462 srd = -b + std::sqrt(d2) ;
1463 sider = kRMax ;
1464 }
1465 else // Case: On the border+t2<kRadTolerance
1466 // (v is perpendicular to the surface)
1467 {
1468 if (calcNorm)
1469 {
1470 *n = G4ThreeVector(p.x()/fRMax,p.y()/fRMax,0) ;
1471 *validNorm = true ;
1472 }
1473 return snxt = 0.0;
1474 }
1475 }
1476 }
1477 // Phi Intersection
1478
1479 if ( !fPhiFullCutTube )
1480 {
1481 // add angle calculation with correction
1482 // of the difference in domain of atan2 and Sphi
1483 //
1484 vphi = std::atan2(v.y(),v.x()) ;
1485
1486 if ( vphi < fSPhi - halfAngTolerance ) { vphi += twopi; }
1487 else if ( vphi > fSPhi + fDPhi + halfAngTolerance ) { vphi -= twopi; }
1488
1489
1490 if ( (p.x() != 0.0) || (p.y() != 0.0) ) // Check if on z axis (rho not needed later)
1491 {
1492 // pDist -ve when inside
1493
1494 pDistS = p.x()*sinSPhi - p.y()*cosSPhi ;
1495 pDistE = -p.x()*sinEPhi + p.y()*cosEPhi ;
1496
1497 // Comp -ve when in direction of outwards normal
1498
1499 compS = -sinSPhi*v.x() + cosSPhi*v.y() ;
1500 compE = sinEPhi*v.x() - cosEPhi*v.y() ;
1501
1502 sidephi = kNull;
1503
1504 if( ( (fDPhi <= pi) && ( (pDistS <= halfCarTolerance)
1505 && (pDistE <= halfCarTolerance) ) )
1506 || ( (fDPhi > pi) && ((pDistS <= halfCarTolerance)
1507 || (pDistE <= halfCarTolerance) ) ) )
1508 {
1509 // Inside both phi *full* planes
1510
1511 if ( compS < 0 )
1512 {
1513 sphi = pDistS/compS ;
1514
1515 if (sphi >= -halfCarTolerance)
1516 {
1517 xi = p.x() + sphi*v.x() ;
1518 yi = p.y() + sphi*v.y() ;
1519
1520 // Check intersecting with correct half-plane
1521 // (if not -> no intersect)
1522 //
1523 if( (std::fabs(xi)<=kCarTolerance)
1524 && (std::fabs(yi)<=kCarTolerance) )
1525 {
1526 sidephi = kSPhi;
1527 if (((fSPhi-halfAngTolerance)<=vphi)
1528 &&((fSPhi+fDPhi+halfAngTolerance)>=vphi))
1529 {
1530 sphi = kInfinity;
1531 }
1532 }
1533 else if ( yi*cosCPhi-xi*sinCPhi >=0 )
1534 {
1535 sphi = kInfinity ;
1536 }
1537 else
1538 {
1539 sidephi = kSPhi ;
1540 if ( pDistS > -halfCarTolerance )
1541 {
1542 sphi = 0.0 ; // Leave by sphi immediately
1543 }
1544 }
1545 }
1546 else
1547 {
1548 sphi = kInfinity ;
1549 }
1550 }
1551 else
1552 {
1553 sphi = kInfinity ;
1554 }
1555
1556 if ( compE < 0 )
1557 {
1558 sphi2 = pDistE/compE ;
1559
1560 // Only check further if < starting phi intersection
1561 //
1562 if ( (sphi2 > -halfCarTolerance) && (sphi2 < sphi) )
1563 {
1564 xi = p.x() + sphi2*v.x() ;
1565 yi = p.y() + sphi2*v.y() ;
1566
1567 if ((std::fabs(xi)<=kCarTolerance)&&(std::fabs(yi)<=kCarTolerance))
1568 {
1569 // Leaving via ending phi
1570 //
1571 if( (fSPhi-halfAngTolerance > vphi)
1572 ||(fSPhi+fDPhi+halfAngTolerance < vphi) )
1573 {
1574 sidephi = kEPhi ;
1575 if ( pDistE <= -halfCarTolerance ) { sphi = sphi2 ; }
1576 else { sphi = 0.0 ; }
1577 }
1578 }
1579 else // Check intersecting with correct half-plane
1580
1581 if ( (yi*cosCPhi-xi*sinCPhi) >= 0)
1582 {
1583 // Leaving via ending phi
1584 //
1585 sidephi = kEPhi ;
1586 if ( pDistE <= -halfCarTolerance ) { sphi = sphi2 ; }
1587 else { sphi = 0.0 ; }
1588 }
1589 }
1590 }
1591 }
1592 else
1593 {
1594 sphi = kInfinity ;
1595 }
1596 }
1597 else
1598 {
1599 // On z axis + travel not || to z axis -> if phi of vector direction
1600 // within phi of shape, Step limited by rmax, else Step =0
1601
1602 if ( (fSPhi - halfAngTolerance <= vphi)
1603 && (vphi <= fSPhi + fDPhi + halfAngTolerance ) )
1604 {
1605 sphi = kInfinity ;
1606 }
1607 else
1608 {
1609 sidephi = kSPhi ; // arbitrary
1610 sphi = 0.0 ;
1611 }
1612 }
1613 if (sphi < snxt) // Order intersecttions
1614 {
1615 snxt = sphi ;
1616 side = sidephi ;
1617 }
1618 }
1619 if (srd < snxt) // Order intersections
1620 {
1621 snxt = srd ;
1622 side = sider ;
1623 }
1624 }
1625 if (calcNorm)
1626 {
1627 switch(side)
1628 {
1629 case kRMax:
1630 // Note: returned vector not normalised
1631 // (divide by fRMax for unit vector)
1632 //
1633 xi = p.x() + snxt*v.x() ;
1634 yi = p.y() + snxt*v.y() ;
1635 *n = G4ThreeVector(xi/fRMax,yi/fRMax,0) ;
1636 *validNorm = true ;
1637 break ;
1638
1639 case kRMin:
1640 *validNorm = false ; // Rmin is inconvex
1641 break ;
1642
1643 case kSPhi:
1644 if ( fDPhi <= pi )
1645 {
1646 *n = G4ThreeVector(sinSPhi,-cosSPhi,0) ;
1647 *validNorm = true ;
1648 }
1649 else
1650 {
1651 *validNorm = false ;
1652 }
1653 break ;
1654
1655 case kEPhi:
1656 if (fDPhi <= pi)
1657 {
1658 *n = G4ThreeVector(-sinEPhi,cosEPhi,0) ;
1659 *validNorm = true ;
1660 }
1661 else
1662 {
1663 *validNorm = false ;
1664 }
1665 break ;
1666
1667 case kPZ:
1668 *n = fHighNorm ;
1669 *validNorm = true ;
1670 break ;
1671
1672 case kMZ:
1673 *n = fLowNorm ;
1674 *validNorm = true ;
1675 break ;
1676
1677 default:
1678 G4cout << G4endl ;
1679 DumpInfo();
1680 std::ostringstream message;
1681 G4long oldprc = message.precision(16);
1682 message << "Undefined side for valid surface normal to solid."
1683 << G4endl
1684 << "Position:" << G4endl << G4endl
1685 << "p.x() = " << p.x()/mm << " mm" << G4endl
1686 << "p.y() = " << p.y()/mm << " mm" << G4endl
1687 << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl
1688 << "Direction:" << G4endl << G4endl
1689 << "v.x() = " << v.x() << G4endl
1690 << "v.y() = " << v.y() << G4endl
1691 << "v.z() = " << v.z() << G4endl << G4endl
1692 << "Proposed distance :" << G4endl << G4endl
1693 << "snxt = " << snxt/mm << " mm" << G4endl ;
1694 message.precision(oldprc) ;
1695 G4Exception("G4CutTubs::DistanceToOut(p,v,..)", "GeomSolids1002",
1696 JustWarning, message);
1697 break ;
1698 }
1699 }
1700 if ( snxt<halfCarTolerance ) { snxt=0 ; }
1701 return snxt ;
1702}
long G4long
Definition G4Types.hh:87
G4GLOB_DLL std::ostream G4cout

◆ GetCosEndPhi()

G4double G4CutTubs::GetCosEndPhi ( ) const
inline

Referenced by BoundingLimits(), and CalculateExtent().

◆ GetCosStartPhi()

G4double G4CutTubs::GetCosStartPhi ( ) const
inline

◆ GetCubicVolume()

G4double G4CutTubs::GetCubicVolume ( )
overridevirtual

Returning an estimation of the solid volume (capacity) and surface area, in internal units.

Reimplemented from G4VSolid.

Definition at line 1916 of file G4CutTubs.cc.

1917{
1918 constexpr G4int nphi = 200, nrho = 100;
1919
1920 if (fCubicVolume == 0)
1921 {
1922 G4AutoLock l(&ctubsMutex);
1923 // get parameters
1924 G4double rmin = GetInnerRadius();
1925 G4double rmax = GetOuterRadius();
1926 G4double dz = GetZHalfLength();
1927 G4double sphi = GetStartPhiAngle();
1928 G4double dphi = GetDeltaPhiAngle();
1929
1930 // calculate volume
1931 G4double volume = dz*dphi*(rmax*rmax - rmin*rmin);
1932 if (dphi < twopi) // make recalculation
1933 {
1934 // set values for calculation of h - distance between
1935 // opposite points on bases
1936 G4ThreeVector nbot = GetLowNorm();
1937 G4ThreeVector ntop = GetHighNorm();
1938 G4double nx = nbot.x()/nbot.z() - ntop.x()/ntop.z();
1939 G4double ny = nbot.y()/nbot.z() - ntop.y()/ntop.z();
1940
1941 // compute volume by integration
1942 G4double delrho = (rmax - rmin)/nrho;
1943 G4double delphi = dphi/nphi;
1944 volume = 0.;
1945 for (G4int irho=0; irho<nrho; ++irho)
1946 {
1947 G4double r1 = rmin + delrho*irho;
1948 G4double r2 = rmin + delrho*(irho + 1);
1949 G4double rho = 0.5*(r1 + r2);
1950 G4double sector = 0.5*delphi*(r2*r2 - r1*r1);
1951 for (G4int iphi=0; iphi<nphi; ++iphi)
1952 {
1953 G4double phi = sphi + delphi*(iphi + 0.5);
1954 G4double h = nx*rho*std::cos(phi) + ny*rho*std::sin(phi) + 2.*dz;
1955 volume += sector*h;
1956 }
1957 }
1958 }
1959 fCubicVolume = volume;
1960 l.unlock();
1961 }
1962 return fCubicVolume;
1963}
G4TemplateAutoLock< G4Mutex > G4AutoLock
G4double fCubicVolume
Definition G4CSGSolid.hh:92
G4double GetStartPhiAngle() const

◆ GetCutZ()

G4double G4CutTubs::GetCutZ ( const G4ThreeVector & p) const
protected

Gets the Z value of the point "p" on the cut plane.

Definition at line 2127 of file G4CutTubs.cc.

2128{
2129 G4double newz = p.z(); // p.z() should be either +fDz or -fDz
2130 if (p.z()<0)
2131 {
2132 if(fLowNorm.z()!=0.)
2133 {
2134 newz = -fDz-(p.x()*fLowNorm.x()+p.y()*fLowNorm.y())/fLowNorm.z();
2135 }
2136 }
2137 else
2138 {
2139 if(fHighNorm.z()!=0.)
2140 {
2141 newz = fDz-(p.x()*fHighNorm.x()+p.y()*fHighNorm.y())/fHighNorm.z();
2142 }
2143 }
2144 return newz;
2145}

Referenced by CreatePolyhedron(), and DistanceToIn().

◆ GetDeltaPhiAngle()

◆ GetEntityType()

G4GeometryType G4CutTubs::GetEntityType ( ) const
overridevirtual

Returns the type ID, "G4CutTubs" of the solid.

Implements G4VSolid.

Definition at line 1755 of file G4CutTubs.cc.

1756{
1757 return {"G4CutTubs"};
1758}

◆ GetHighNorm()

◆ GetInnerRadius()

G4double G4CutTubs::GetInnerRadius ( ) const
inline

◆ GetLowNorm()

◆ GetOuterRadius()

◆ GetPointOnSurface()

G4ThreeVector G4CutTubs::GetPointOnSurface ( ) const
overridevirtual

Returns a random point located and uniformly distributed on the surface of the solid.

Reimplemented from G4VSolid.

Definition at line 1798 of file G4CutTubs.cc.

1799{
1800 // Set min and max z
1801 if (fZMin == 0. && fZMax == 0.)
1802 {
1803 G4AutoLock l(&ctubsMutex);
1804 G4ThreeVector bmin, bmax;
1805 BoundingLimits(bmin,bmax);
1806 fZMin = bmin.z();
1807 fZMax = bmax.z();
1808 l.unlock();
1809 }
1810
1811 // Set parameters
1812 G4double hmax = fZMax - fZMin;
1813 G4double sphi = fSPhi;
1814 G4double dphi = fDPhi;
1815 G4double rmin = fRMin;
1816 G4double rmax = fRMax;
1817 G4double rrmax = rmax*rmax;
1818 G4double rrmin = rmin*rmin;
1819
1820 G4ThreeVector nbot = GetLowNorm();
1821 G4ThreeVector ntop = GetHighNorm();
1822
1823 // Set array of surface areas
1824 G4double sbase = 0.5*dphi*(rrmax - rrmin);
1825 G4double sbot = sbase/std::abs(nbot.z());
1826 G4double stop = sbase/std::abs(ntop.z());
1827 G4double scut = (dphi == twopi) ? 0. : hmax*(rmax - rmin);
1828 G4double ssurf[6] = { scut, scut, sbot, stop, dphi*rmax*hmax, dphi*rmin*hmax };
1829 ssurf[1] += ssurf[0];
1830 ssurf[2] += ssurf[1];
1831 ssurf[3] += ssurf[2];
1832 ssurf[4] += ssurf[3];
1833 ssurf[5] += ssurf[4];
1834
1835 constexpr G4int ntry = 100000;
1836 for (G4int i=0; i<ntry; ++i)
1837 {
1838 // Select surface
1839 G4double select = ssurf[5]*G4QuickRand();
1840 G4int k = 5;
1841 k -= (G4int)(select <= ssurf[4]);
1842 k -= (G4int)(select <= ssurf[3]);
1843 k -= (G4int)(select <= ssurf[2]);
1844 k -= (G4int)(select <= ssurf[1]);
1845 k -= (G4int)(select <= ssurf[0]);
1846
1847 // Generate point on selected surface (rejection sampling)
1848 G4ThreeVector p(0,0,0);
1849 switch(k)
1850 {
1851 case 0: // cut at start phi
1852 {
1853 G4double r = rmin + (rmax - rmin)*G4QuickRand();
1854 p.set(r*cosSPhi, r*sinSPhi, fZMin + hmax*G4QuickRand());
1855 break;
1856 }
1857 case 1: // cut at end phi
1858 {
1859 G4double r = rmin + (rmax - rmin)*G4QuickRand();
1860 p.set(r*cosEPhi, r*sinEPhi, fZMin + hmax*G4QuickRand());
1861 break;
1862 }
1863 case 2: // base at low z
1864 {
1865 G4double r = std::sqrt(rrmin + (rrmax - rrmin)*G4QuickRand());
1866 G4double phi = sphi + dphi*G4QuickRand();
1867 G4double x = r*std::cos(phi);
1868 G4double y = r*std::sin(phi);
1869 G4double z = -fDz - (x*nbot.x() + y*nbot.y())/nbot.z();
1870 return {x, y, z};
1871 }
1872 case 3: // base at high z
1873 {
1874 G4double r = std::sqrt(rrmin + (rrmax - rrmin)*G4QuickRand());
1875 G4double phi = sphi + dphi*G4QuickRand();
1876 G4double x = r*std::cos(phi);
1877 G4double y = r*std::sin(phi);
1878 G4double z = fDz - (x*ntop.x() + y*ntop.y())/ntop.z();
1879 return {x, y, z};
1880 }
1881 case 4: // external lateral surface
1882 {
1883 G4double phi = sphi + dphi*G4QuickRand();
1884 G4double z = fZMin + hmax*G4QuickRand();
1885 G4double x = rmax*std::cos(phi);
1886 G4double y = rmax*std::sin(phi);
1887 p.set(x, y, z);
1888 break;
1889 }
1890 case 5: // internal lateral surface
1891 {
1892 G4double phi = sphi + dphi*G4QuickRand();
1893 G4double z = fZMin + hmax*G4QuickRand();
1894 G4double x = rmin*std::cos(phi);
1895 G4double y = rmin*std::sin(phi);
1896 p.set(x, y, z);
1897 break;
1898 }
1899 }
1900 if ((ntop.dot(p) - fDz*ntop.z()) > 0.) { continue; }
1901 if ((nbot.dot(p) + fDz*nbot.z()) > 0.) { continue; }
1902 return p;
1903 }
1904 // Just in case, if all attempts to generate a point have failed
1905 // Normally should never happen
1906 G4double x = rmax*std::cos(sphi + 0.5*dphi);
1907 G4double y = rmax*std::sin(sphi + 0.5*dphi);
1908 G4double z = fDz - (x*ntop.x() + y*ntop.y())/ntop.z();
1909 return {x, y, z};
1910}
G4double G4QuickRand(uint32_t seed=0)

◆ GetSinEndPhi()

G4double G4CutTubs::GetSinEndPhi ( ) const
inline

Referenced by BoundingLimits(), and CalculateExtent().

◆ GetSinStartPhi()

G4double G4CutTubs::GetSinStartPhi ( ) const
inline

◆ GetStartPhiAngle()

G4double G4CutTubs::GetStartPhiAngle ( ) const
inline

◆ GetSurfaceArea()

G4double G4CutTubs::GetSurfaceArea ( )
overridevirtual

Returns an estimation of the solid surface area in internal units. This method may be overloaded by derived classes to compute the exact geometrical quantity for solids where this is possible, or anyway to cache the computed value. Note: the computed value is NOT cached.

Reimplemented from G4VSolid.

Definition at line 1969 of file G4CutTubs.cc.

1970{
1971 constexpr G4int nphi = 400;
1972
1973 if (fSurfaceArea == 0)
1974 {
1975 G4AutoLock l(&ctubsMutex);
1976 // get parameters
1977 G4double rmin = GetInnerRadius();
1978 G4double rmax = GetOuterRadius();
1979 G4double dz = GetZHalfLength();
1980 G4double sphi = GetStartPhiAngle();
1981 G4double dphi = GetDeltaPhiAngle();
1982 G4ThreeVector nbot = GetLowNorm();
1983 G4ThreeVector ntop = GetHighNorm();
1984
1985 // calculate lateral surface area
1986 G4double sinner = 2.*dz*dphi*rmin;
1987 G4double souter = 2.*dz*dphi*rmax;
1988 if (dphi < twopi) // make recalculation
1989 {
1990 // set values for calculation of h - distance between
1991 // opposite points on bases
1992 G4double nx = nbot.x()/nbot.z() - ntop.x()/ntop.z();
1993 G4double ny = nbot.y()/nbot.z() - ntop.y()/ntop.z();
1994
1995 // compute lateral surface area by integration
1996 G4double delphi = dphi/nphi;
1997 sinner = 0.;
1998 souter = 0.;
1999 for (G4int iphi=0; iphi<nphi; ++iphi)
2000 {
2001 G4double phi = sphi + delphi*(iphi + 0.5);
2002 G4double cosphi = std::cos(phi);
2003 G4double sinphi = std::sin(phi);
2004 sinner += rmin*(nx*cosphi + ny*sinphi) + 2.*dz;
2005 souter += rmax*(nx*cosphi + ny*sinphi) + 2.*dz;
2006 }
2007 sinner *= delphi*rmin;
2008 souter *= delphi*rmax;
2009 }
2010 // set surface area
2011 G4double scut = (dphi == twopi) ? 0. : 2.*dz*(rmax - rmin);
2012 G4double szero = 0.5*dphi*(rmax*rmax - rmin*rmin);
2013 G4double slow = szero/std::abs(nbot.z());
2014 G4double shigh = szero/std::abs(ntop.z());
2015 fSurfaceArea = sinner + souter + 2.*scut + slow + shigh;
2016 l.unlock();
2017 }
2018 return fSurfaceArea;
2019}
G4double fSurfaceArea
Definition G4CSGSolid.hh:93

◆ GetZHalfLength()

◆ Initialize()

void G4CutTubs::Initialize ( )
inlineprotected

Resets relevant values to zero.

◆ InitializeTrigonometry()

void G4CutTubs::InitializeTrigonometry ( )
inlineprotected

Recomputes relevant trigonometric values and caches them.

◆ Inside()

EInside G4CutTubs::Inside ( const G4ThreeVector & p) const
overridevirtual

Concrete implementations of the expected query interfaces for solids, as defined in the base class G4VSolid.

Implements G4VSolid.

Definition at line 441 of file G4CutTubs.cc.

442{
443 G4ThreeVector vZ = G4ThreeVector(0,0,fDz);
444 EInside in = kInside;
445
446 // Check the lower cut plane
447 //
448 G4double zinLow =(p+vZ).dot(fLowNorm);
449 if (zinLow > halfCarTolerance) { return kOutside; }
450
451 // Check the higher cut plane
452 //
453 G4double zinHigh = (p-vZ).dot(fHighNorm);
454 if (zinHigh > halfCarTolerance) { return kOutside; }
455
456 // Check radius
457 //
458 G4double r2 = p.x()*p.x() + p.y()*p.y() ;
459
460 G4double tolRMin = fRMin - halfRadTolerance;
461 G4double tolRMax = fRMax + halfRadTolerance;
462 if ( tolRMin < 0 ) { tolRMin = 0; }
463
464 if (r2 < tolRMin*tolRMin || r2 > tolRMax*tolRMax) { return kOutside; }
465
466 // Check Phi cut
467 //
468 if(!fPhiFullCutTube)
469 {
470 if ((tolRMin == 0) && (std::fabs(p.x()) <= halfCarTolerance)
471 && (std::fabs(p.y()) <= halfCarTolerance))
472 {
473 return kSurface;
474 }
475
476 G4double phi0 = std::atan2(p.y(),p.x());
477 G4double phi1 = phi0 - twopi;
478 G4double phi2 = phi0 + twopi;
479
480 in = kOutside;
481 G4double sphi = fSPhi - halfAngTolerance;
482 G4double ephi = sphi + fDPhi + kAngTolerance;
483 if ((phi0 >= sphi && phi0 <= ephi) ||
484 (phi1 >= sphi && phi1 <= ephi) ||
485 (phi2 >= sphi && phi2 <= ephi))
486 {
487 in = kSurface;
488 }
489 if (in == kOutside) { return kOutside; }
490
491 sphi += kAngTolerance;
492 ephi -= kAngTolerance;
493 if ((phi0 >= sphi && phi0 <= ephi) ||
494 (phi1 >= sphi && phi1 <= ephi) ||
495 (phi2 >= sphi && phi2 <= ephi)) { in = kInside;
496}
497 if (in == kSurface) { return kSurface; }
498 }
499
500 // Check on the Surface for Z
501 //
502 if ((zinLow >= -halfCarTolerance) || (zinHigh >= -halfCarTolerance))
503 {
504 return kSurface;
505 }
506
507 // Check on the Surface for R
508 //
509 if (fRMin != 0.0) { tolRMin = fRMin + halfRadTolerance; }
510 else { tolRMin = 0; }
511 tolRMax = fRMax - halfRadTolerance;
512 if (((r2 <= tolRMin*tolRMin) || (r2 >= tolRMax*tolRMax)) &&
513 (r2 >= halfRadTolerance*halfRadTolerance))
514 {
515 return kSurface;
516 }
517
518 return in;
519}
EInside
Definition geomdefs.hh:67
@ kInside
Definition geomdefs.hh:70
@ kOutside
Definition geomdefs.hh:68
@ kSurface
Definition geomdefs.hh:69

◆ IsCrossingCutPlanes()

G4bool G4CutTubs::IsCrossingCutPlanes ( ) const
protected

Checks if the cutted planes are crossing.

Returns
True if the solid is ill defined.

Definition at line 2092 of file G4CutTubs.cc.

2093{
2094 constexpr G4int npoints = 30;
2095
2096 // set values for calculation of h - distance between
2097 // opposite points on bases
2098 G4ThreeVector nbot = GetLowNorm();
2099 G4ThreeVector ntop = GetHighNorm();
2100 if (std::abs(nbot.z()) < kCarTolerance) { return true; }
2101 if (std::abs(ntop.z()) < kCarTolerance) { return true; }
2102 G4double nx = nbot.x()/nbot.z() - ntop.x()/ntop.z();
2103 G4double ny = nbot.y()/nbot.z() - ntop.y()/ntop.z();
2104
2105 // check points
2106 G4double cosphi = GetCosStartPhi();
2107 G4double sinphi = GetSinStartPhi();
2108 G4double delphi = GetDeltaPhiAngle()/npoints;
2109 G4double cosdel = std::cos(delphi);
2110 G4double sindel = std::sin(delphi);
2111 G4double hzero = 2.*GetZHalfLength()/GetOuterRadius();
2112 for (G4int i=0; i<npoints+1; ++i)
2113 {
2114 G4double h = nx*cosphi + ny*sinphi + hzero;
2115 if (h < 0.) { return true; }
2116 G4double sintmp = sinphi;
2117 sinphi = sintmp*cosdel + cosphi*sindel;
2118 cosphi = cosphi*cosdel - sintmp*sindel;
2119 }
2120 return false;
2121}

Referenced by G4CutTubs().

◆ operator=()

G4CutTubs & G4CutTubs::operator= ( const G4CutTubs & rhs)

Definition at line 177 of file G4CutTubs.cc.

178{
179 // Check assignment to self
180 //
181 if (this == &rhs) { return *this; }
182
183 // Copy base class data
184 //
186
187 // Copy data
188 //
189 kRadTolerance = rhs.kRadTolerance; kAngTolerance = rhs.kAngTolerance;
190 fRMin = rhs.fRMin; fRMax = rhs.fRMax; fDz = rhs.fDz;
191 fSPhi = rhs.fSPhi; fDPhi = rhs.fDPhi;
192 fZMin = rhs.fZMin; fZMax = rhs.fZMax;
193 sinCPhi = rhs.sinCPhi; cosCPhi = rhs.cosCPhi;
194 cosHDPhiOT = rhs.cosHDPhiOT; cosHDPhiIT = rhs.cosHDPhiIT;
195 sinSPhi = rhs.sinSPhi; cosSPhi = rhs.cosSPhi;
196 sinEPhi = rhs.sinEPhi; cosEPhi = rhs.cosEPhi;
197 fPhiFullCutTube = rhs.fPhiFullCutTube;
198 halfCarTolerance = rhs.halfCarTolerance;
199 halfRadTolerance = rhs.halfRadTolerance;
200 halfAngTolerance = rhs.halfAngTolerance;
201 fLowNorm = rhs.fLowNorm; fHighNorm = rhs.fHighNorm;
202
203 return *this;
204}
G4CSGSolid & operator=(const G4CSGSolid &rhs)
Definition G4CSGSolid.cc:89

◆ SetDeltaPhiAngle()

void G4CutTubs::SetDeltaPhiAngle ( G4double newDPhi)
inline

◆ SetInnerRadius()

void G4CutTubs::SetInnerRadius ( G4double newRMin)
inline

Modifiers.

◆ SetOuterRadius()

void G4CutTubs::SetOuterRadius ( G4double newRMax)
inline

◆ SetStartPhiAngle()

void G4CutTubs::SetStartPhiAngle ( G4double newSPhi,
G4bool trig = true )
inline

◆ SetZHalfLength()

void G4CutTubs::SetZHalfLength ( G4double newDz)
inline

◆ StreamInfo()

std::ostream & G4CutTubs::StreamInfo ( std::ostream & os) const
overridevirtual

Streams the object contents to an output stream.

Reimplemented from G4CSGSolid.

Definition at line 1773 of file G4CutTubs.cc.

1774{
1775 G4long oldprc = os.precision(16);
1776 os << "-----------------------------------------------------------\n"
1777 << " *** Dump for solid - " << GetName() << " ***\n"
1778 << " ===================================================\n"
1779 << " Solid type: G4CutTubs\n"
1780 << " Parameters: \n"
1781 << " inner radius : " << fRMin/mm << " mm \n"
1782 << " outer radius : " << fRMax/mm << " mm \n"
1783 << " half length Z: " << fDz/mm << " mm \n"
1784 << " starting phi : " << fSPhi/degree << " degrees \n"
1785 << " delta phi : " << fDPhi/degree << " degrees \n"
1786 << " low Norm : " << fLowNorm << " \n"
1787 << " high Norm : " <<fHighNorm << " \n"
1788 << "-----------------------------------------------------------\n";
1789 os.precision(oldprc);
1790
1791 return os;
1792}

◆ SurfaceNormal()

G4ThreeVector G4CutTubs::SurfaceNormal ( const G4ThreeVector & p) const
overridevirtual

Returns the outwards pointing unit normal of the shape for the surface closest to the point at offset 'p'.

Parameters
[in]pThe point at offset p.
Returns
The outwards pointing unit normal.

Implements G4VSolid.

Definition at line 527 of file G4CutTubs.cc.

528{
529 G4int noSurfaces = 0;
530 G4double rho, pPhi;
531 G4double distZLow,distZHigh, distRMin, distRMax;
532 G4double distSPhi = kInfinity, distEPhi = kInfinity;
533 G4ThreeVector vZ=G4ThreeVector(0,0,fDz);
534
535 G4ThreeVector norm, sumnorm(0.,0.,0.);
536 G4ThreeVector nZ = G4ThreeVector(0, 0, 1.0);
537 G4ThreeVector nR, nPs, nPe;
538
539 rho = std::sqrt(p.x()*p.x() + p.y()*p.y());
540
541 distRMin = std::fabs(rho - fRMin);
542 distRMax = std::fabs(rho - fRMax);
543
544 // dist to Low Cut
545 //
546 distZLow =std::fabs((p+vZ).dot(fLowNorm));
547
548 // dist to High Cut
549 //
550 distZHigh = std::fabs((p-vZ).dot(fHighNorm));
551
552 if (!fPhiFullCutTube) // Protected against (0,0,z)
553 {
554 if ( rho > halfCarTolerance )
555 {
556 pPhi = std::atan2(p.y(),p.x());
557
558 if(pPhi < fSPhi- halfCarTolerance) { pPhi += twopi; }
559 else if(pPhi > fSPhi+fDPhi+ halfCarTolerance) { pPhi -= twopi; }
560
561 distSPhi = std::fabs(pPhi - fSPhi);
562 distEPhi = std::fabs(pPhi - fSPhi - fDPhi);
563 }
564 else if( fRMin == 0.0 )
565 {
566 distSPhi = 0.;
567 distEPhi = 0.;
568 }
569 nPs = G4ThreeVector( sinSPhi, -cosSPhi, 0 );
570 nPe = G4ThreeVector( -sinEPhi, cosEPhi, 0 );
571 }
572 if ( rho > halfCarTolerance ) { nR = G4ThreeVector(p.x()/rho,p.y()/rho,0); }
573
574 if( distRMax <= halfCarTolerance )
575 {
576 ++noSurfaces;
577 sumnorm += nR;
578 }
579 if( (fRMin != 0.0) && (distRMin <= halfCarTolerance) )
580 {
581 ++noSurfaces;
582 sumnorm -= nR;
583 }
584 if( fDPhi < twopi )
585 {
586 if (distSPhi <= halfAngTolerance)
587 {
588 ++noSurfaces;
589 sumnorm += nPs;
590 }
591 if (distEPhi <= halfAngTolerance)
592 {
593 ++noSurfaces;
594 sumnorm += nPe;
595 }
596 }
597 if (distZLow <= halfCarTolerance)
598 {
599 ++noSurfaces;
600 sumnorm += fLowNorm;
601 }
602 if (distZHigh <= halfCarTolerance)
603 {
604 ++noSurfaces;
605 sumnorm += fHighNorm;
606 }
607 if ( noSurfaces == 0 )
608 {
609#ifdef G4CSGDEBUG
610 G4Exception("G4CutTubs::SurfaceNormal(p)", "GeomSolids1002",
611 JustWarning, "Point p is not on surface !?" );
612 G4int oldprc = G4cout.precision(20);
613 G4cout<< "G4CutTubs::SN ( "<<p.x()<<", "<<p.y()<<", "<<p.z()<<" ); "
614 << G4endl << G4endl;
615 G4cout.precision(oldprc) ;
616#endif
617 norm = ApproxSurfaceNormal(p);
618 }
619 else if ( noSurfaces == 1 ) { norm = sumnorm; }
620 else { norm = sumnorm.unit(); }
621
622 return norm;
623}
G4ThreeVector ApproxSurfaceNormal(const G4ThreeVector &p) const
Definition G4CutTubs.cc:630

The documentation for this class was generated from the following files: