66 using namespace CLHEP;
79 :
G4VSolid(pName), fRebuildPolyhedron(false), fpPolyhedron(0),
80 fCubicVolume(0.), fSurfaceArea(0.), zBottomCut(0.), zTopCut(0.)
88 halfRadTolerance = kRadTolerance*0.5;
91 if ( (pxSemiAxis<=0.) || (pySemiAxis<=0.) || (pzSemiAxis<=0.) )
93 std::ostringstream message;
94 message <<
"Invalid semi-axis - " <<
GetName();
95 G4Exception(
"G4Ellipsoid::G4Ellipsoid()",
"GeomSolids0002",
100 if ( pzBottomCut == 0 && pzTopCut == 0 )
104 else if ( (pzBottomCut < pzSemiAxis) && (pzTopCut > -pzSemiAxis)
105 && (pzBottomCut < pzTopCut) )
111 std::ostringstream message;
112 message <<
"Invalid z-coordinate for cutting plane - " <<
GetName();
113 G4Exception(
"G4Ellipsoid::G4Ellipsoid()",
"GeomSolids0002",
124 :
G4VSolid(a), fRebuildPolyhedron(false), fpPolyhedron(0), kRadTolerance(0.),
125 halfCarTolerance(0.), halfRadTolerance(0.), fCubicVolume(0.),
126 fSurfaceArea(0.), xSemiAxis(0.), ySemiAxis(0.), zSemiAxis(0.),
127 semiAxisMax(0.), zBottomCut(0.), zTopCut(0.)
146 fRebuildPolyhedron(false), fpPolyhedron(0),
147 kRadTolerance(rhs.kRadTolerance),
148 halfCarTolerance(rhs.halfCarTolerance),
149 halfRadTolerance(rhs.halfRadTolerance),
150 fCubicVolume(rhs.fCubicVolume), fSurfaceArea(rhs.fSurfaceArea),
151 xSemiAxis(rhs.xSemiAxis), ySemiAxis(rhs.ySemiAxis),
152 zSemiAxis(rhs.zSemiAxis), semiAxisMax(rhs.semiAxisMax),
153 zBottomCut(rhs.zBottomCut), zTopCut(rhs.zTopCut)
165 if (
this == &rhs) {
return *
this; }
173 kRadTolerance = rhs.kRadTolerance;
174 halfCarTolerance = rhs.halfCarTolerance;
175 halfRadTolerance = rhs.halfRadTolerance;
176 fCubicVolume = rhs.fCubicVolume; fSurfaceArea = rhs.fSurfaceArea;
177 xSemiAxis = rhs.xSemiAxis; ySemiAxis = rhs.ySemiAxis;
178 zSemiAxis = rhs.zSemiAxis; semiAxisMax = rhs.semiAxisMax;
179 zBottomCut = rhs.zBottomCut; zTopCut = rhs.zTopCut;
209 pMin.
set(-dx,-dy,zmin);
210 pMax.
set( dx, dy,zmax);
214 if (pMin.
x() >= pMax.
x() || pMin.
y() >= pMax.
y() || pMin.
z() >= pMax.
z())
216 std::ostringstream message;
217 message <<
"Bad bounding box (min >= max) for solid: "
219 <<
"\npMin = " << pMin
220 <<
"\npMax = " << pMax;
260 if (p.
z() < zBottomCut-halfRadTolerance) {
return in=
kOutside; }
261 if (p.
z() > zTopCut+halfRadTolerance) {
return in=
kOutside; }
263 rad2oo=
sqr(p.
x()/(xSemiAxis+halfRadTolerance))
264 +
sqr(p.
y()/(ySemiAxis+halfRadTolerance))
265 +
sqr(p.
z()/(zSemiAxis+halfRadTolerance));
267 if (rad2oo > 1.0) {
return in=
kOutside; }
269 rad2oi=
sqr(p.
x()*(1.0+halfRadTolerance/xSemiAxis)/xSemiAxis)
270 +
sqr(p.
y()*(1.0+halfRadTolerance/ySemiAxis)/ySemiAxis)
271 +
sqr(p.
z()*(1.0+halfRadTolerance/zSemiAxis)/zSemiAxis);
278 in = ( (p.
z() < zBottomCut+halfRadTolerance)
280 if ( rad2oi > 1.0-halfRadTolerance ) { in=
kSurface; }
296 G4double distR, distZBottom, distZTop;
302 p.
y()/(ySemiAxis*ySemiAxis),
303 p.
z()/(zSemiAxis*zSemiAxis));
308 distR = std::fabs( (p*norm - 1.0) * radius ) / 2.0;
312 distZBottom = std::fabs( p.
z() - zBottomCut );
313 distZTop = std::fabs( p.
z() - zTopCut );
315 if ( (distZBottom < distR) || (distZTop < distR) )
317 return G4ThreeVector(0.,0.,(distZBottom < distZTop) ? -1.0 : 1.0);
319 return ( norm *= radius );
336 if (p.
z() <= zBottomCut+halfCarTolerance)
338 if (v.
z() <= 0.0) {
return distMin; }
339 G4double distZ = (zBottomCut - p.
z()) / v.
z();
341 if ( (distZ > -halfRadTolerance) && (
Inside(p+distZ*v) !=
kOutside) )
344 if ( std::fabs(distZ) < halfRadTolerance ) { distZ=0.; }
345 return distMin= distZ;
348 if (p.
z() >= zTopCut-halfCarTolerance)
350 if (v.
z() >= 0.0) {
return distMin;}
352 if ( (distZ > -halfRadTolerance) && (
Inside(p+distZ*v) !=
kOutside) )
355 if ( std::fabs(distZ) < halfRadTolerance ) { distZ=0.; }
356 return distMin= distZ;
364 A=
sqr(v.
x()/xSemiAxis) +
sqr(v.
y()/ySemiAxis) +
sqr(v.
z()/zSemiAxis);
365 C=
sqr(p.
x()/xSemiAxis) +
sqr(p.
y()/ySemiAxis) +
sqr(p.
z()/zSemiAxis) - 1.0;
366 B= 2.0 * ( p.
x()*v.
x()/(xSemiAxis*xSemiAxis)
367 + p.
y()*v.
y()/(ySemiAxis*ySemiAxis)
368 + p.
z()*v.
z()/(zSemiAxis*zSemiAxis) );
373 G4double distR= (-B - std::sqrt(C)) / (2.0*A);
375 if ( (distR > halfRadTolerance)
376 && (intZ >= zBottomCut-halfRadTolerance)
377 && (intZ <= zTopCut+halfRadTolerance) )
381 else if( (distR >- halfRadTolerance)
382 && (intZ >= zBottomCut-halfRadTolerance)
383 && (intZ <= zTopCut+halfRadTolerance) )
389 distR = (-B + std::sqrt(C) ) / (2.0*A);
390 if(distR>0.) { distMin=0.; }
394 distR= (-B + std::sqrt(C)) / (2.0*A);
395 intZ = p.
z()+distR*v.
z();
396 if ( (distR > halfRadTolerance)
397 && (intZ >= zBottomCut-halfRadTolerance)
398 && (intZ <= zTopCut+halfRadTolerance) )
401 if (norm.
dot(v)<0.) { distMin = distR; }
404 if ( (distMin!=
kInfinity) && (distMin>dRmax) )
407 G4double fTerm = distMin-std::fmod(distMin,dRmax);
412 if (std::fabs(distMin)<halfRadTolerance) { distMin=0.; }
428 p.
y()/(ySemiAxis*ySemiAxis),
429 p.
z()/(zSemiAxis*zSemiAxis));
434 distR= (p*norm - 1.0) * radius / 2.0;
438 distZ= zBottomCut - p.
z();
441 distZ = p.
z() - zTopCut;
448 return (distR < 0.0) ? 0.0 : distR;
450 else if (distR < 0.0)
456 return (distZ < distR) ? distZ : distR;
471 enum surface_e {kPlaneSurf, kCurvedSurf, kNoSurf} surface;
480 G4double distZ = (zBottomCut - p.
z()) / v.
z();
484 if (!calcNorm) {
return 0.0;}
495 if (!calcNorm) {
return 0.0;}
504 p.
y()/(ySemiAxis*ySemiAxis),
505 p.
z()/(zSemiAxis*zSemiAxis));
511 A=
sqr(v.
x()/xSemiAxis) +
sqr(v.
y()/ySemiAxis) +
sqr(v.
z()/zSemiAxis);
512 C= (p * nearnorm) - 1.0;
513 B= 2.0 * (v * nearnorm);
518 G4double distR= (-B + std::sqrt(C) ) / (2.0*A);
522 if (!calcNorm) {
return 0.0;}
527 surface= kCurvedSurf;
535 if (surface == kNoSurf)
551 pexit.
y()/(ySemiAxis*ySemiAxis),
552 pexit.
z()/(zSemiAxis*zSemiAxis));
553 truenorm *= 1.0/truenorm.
mag();
558 std::ostringstream message;
559 G4int oldprc = message.precision(16);
560 message <<
"Undefined side for valid surface normal to solid."
563 <<
" p.x() = " << p.
x()/
mm <<
" mm" <<
G4endl
564 <<
" p.y() = " << p.
y()/
mm <<
" mm" <<
G4endl
565 <<
" p.z() = " << p.
z()/
mm <<
" mm" <<
G4endl
567 <<
" v.x() = " << v.
x() <<
G4endl
568 <<
" v.y() = " << v.
y() <<
G4endl
569 <<
" v.z() = " << v.
z() <<
G4endl
570 <<
"Proposed distance :" <<
G4endl
571 <<
" distMin = " << distMin/
mm <<
" mm";
572 message.precision(oldprc);
595 std::ostringstream message;
596 G4int oldprc = message.precision(16);
597 message <<
"Point p is outside !?" <<
G4endl
599 <<
" p.x() = " << p.
x()/
mm <<
" mm" <<
G4endl
600 <<
" p.y() = " << p.
y()/
mm <<
" mm" <<
G4endl
601 <<
" p.z() = " << p.
z()/
mm <<
" mm";
602 message.precision(oldprc) ;
603 G4Exception(
"G4Ellipsoid::DistanceToOut(p)",
"GeomSolids1002",
611 p.
y()/(ySemiAxis*ySemiAxis),
612 p.
z()/(zSemiAxis*zSemiAxis));
618 if ( (tmp > 0.0) && (1.0 < radius*tmp) ) {radius = 1.0/tmp;}
622 distR = (1.0 - p*norm) * radius / 2.0;
626 distZ = p.
z() - zBottomCut;
627 if (distZ < 0.0) {distZ= zTopCut - p.
z();}
631 if ( (distZ < 0.0) || (distR < 0.0) )
637 return (distZ < distR) ? distZ : distR;
665 G4int oldprc = os.precision(16);
666 os <<
"-----------------------------------------------------------\n"
667 <<
" *** Dump for solid - " <<
GetName() <<
" ***\n"
668 <<
" ===================================================\n"
669 <<
" Solid type: G4Ellipsoid\n"
672 <<
" semi-axis x: " << xSemiAxis/
mm <<
" mm \n"
673 <<
" semi-axis y: " << ySemiAxis/
mm <<
" mm \n"
674 <<
" semi-axis z: " << zSemiAxis/
mm <<
" mm \n"
675 <<
" max semi-axis: " << semiAxisMax/
mm <<
" mm \n"
676 <<
" lower cut plane level z: " << zBottomCut/
mm <<
" mm \n"
677 <<
" upper cut plane level z: " << zTopCut/
mm <<
" mm \n"
678 <<
"-----------------------------------------------------------\n";
679 os.precision(oldprc);
690 G4double aTop, aBottom, aCurved, chose, xRand, yRand, zRand, phi;
693 max1 = xSemiAxis > ySemiAxis ? xSemiAxis : ySemiAxis;
694 max1 = max1 > zSemiAxis ? max1 : zSemiAxis;
695 if (max1 == xSemiAxis) { max2 = ySemiAxis; max3 = zSemiAxis; }
696 else if (max1 == ySemiAxis) { max2 = xSemiAxis; max3 = zSemiAxis; }
697 else { max2 = xSemiAxis; max3 = ySemiAxis; }
701 cosphi = std::cos(phi); sinphi = std::sin(phi);
703 sintheta = std::sqrt(1.-
sqr(costheta));
705 alpha = 1.-
sqr(max2/max1); beta = 1.-
sqr(max3/max1);
707 aTop =
pi*xSemiAxis*ySemiAxis*(1 -
sqr(zTopCut/zSemiAxis));
708 aBottom =
pi*xSemiAxis*ySemiAxis*(1 -
sqr(zBottomCut/zSemiAxis));
712 aCurved = 4.*
pi*max1*max2*(1.-1./6.*(alpha+beta)-
713 1./120.*(3.*
sqr(alpha)+2.*alpha*beta+3.*
sqr(beta)));
715 aCurved *= 0.5*(1.2*zTopCut/zSemiAxis - 1.2*zBottomCut/zSemiAxis);
717 if( ( zTopCut >= zSemiAxis && zBottomCut <= -1.*zSemiAxis )
718 || ( zTopCut == 0 && zBottomCut ==0 ) )
720 aTop = 0; aBottom = 0;
727 xRand = xSemiAxis*sintheta*cosphi;
728 yRand = ySemiAxis*sintheta*sinphi;
729 zRand = zSemiAxis*costheta;
732 else if(chose >= aCurved && chose < aCurved + aTop)
735 * std::sqrt(1-
sqr(zTopCut/zSemiAxis));
737 * std::sqrt(1.-
sqr(zTopCut/zSemiAxis)-
sqr(xRand/xSemiAxis));
744 * std::sqrt(1-
sqr(zBottomCut/zSemiAxis));
746 * std::sqrt(1.-
sqr(zBottomCut/zSemiAxis)-
sqr(xRand/xSemiAxis));
766 -semiAxisMax, semiAxisMax,
767 -semiAxisMax, semiAxisMax);
773 zBottomCut, zTopCut);
void set(double x, double y, double z)
G4Polyhedron * GetPolyhedron() const
ThreeVector shoot(const G4int Ap, const G4int Af)
G4GeometryType GetEntityType() const
G4bool fRebuildPolyhedron
static constexpr double mm
static const G4double kInfinity
CLHEP::Hep3Vector G4ThreeVector
double dot(const Hep3Vector &) const
void Extent(G4ThreeVector &pMin, G4ThreeVector &pMax) const
G4double DistanceToOut(const G4ThreeVector &p, const G4ThreeVector &v, const G4bool calcNorm=G4bool(false), G4bool *validNorm=0, G4ThreeVector *n=0) const
G4double GetZTopCut() const
EInside Inside(const G4ThreeVector &p) const
G4double GetZBottomCut() const
double B(double temperature)
virtual void AddSolid(const G4Box &)=0
G4bool CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimit, const G4AffineTransform &pTransform, G4double &pmin, G4double &pmax) const
G4double GetSemiAxisMax(G4int i) const
#define G4MUTEX_INITIALIZER
static constexpr double twopi
void SetZCuts(G4double newzBottomCut, G4double newzTopCut)
void DescribeYourselfTo(G4VGraphicsScene &scene) const
G4Ellipsoid(const G4String &pName, G4double pxSemiAxis, G4double pySemiAxis, G4double pzSemiAxis, G4double pzBottomCut=0, G4double pzTopCut=0)
double A(double temperature)
G4VisExtent GetExtent() const
G4Polyhedron * fpPolyhedron
G4double GetRadialTolerance() const
G4Ellipsoid & operator=(const G4Ellipsoid &rhs)
G4Polyhedron * CreatePolyhedron() const
G4bool CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimits, const G4Transform3D &pTransform3D, G4double &pMin, G4double &pMax) const
G4double DistanceToIn(const G4ThreeVector &p, const G4ThreeVector &v) const
G4ThreeVector SurfaceNormal(const G4ThreeVector &p) const
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *comments)
virtual void ComputeDimensions(G4Box &, const G4int, const G4VPhysicalVolume *) const
std::ostream & StreamInfo(std::ostream &os) const
static G4int GetNumberOfRotationSteps()
T max(const T t1, const T t2)
brief Return the largest of the two arguments
T min(const T t1, const T t2)
brief Return the smallest of the two arguments
void SetSemiAxis(G4double x, G4double y, G4double z)
G4VSolid & operator=(const G4VSolid &rhs)
G4int GetNumberOfRotationStepsAtTimeOfCreation() const
static constexpr double pi
G4ThreeVector GetPointOnSurface() const
static const G4double alpha
void ComputeDimensions(G4VPVParameterisation *p, const G4int n, const G4VPhysicalVolume *pRep)
static G4GeometryTolerance * GetInstance()
static int max3(int a, int b, int c)