37#if !(defined(G4GEOM_USE_UELLIPSOID) && defined(G4GEOM_USE_SYS_USOLIDS))
73 :
G4VSolid(name), fDx(xSemiAxis), fDy(ySemiAxis), fDz(zSemiAxis),
74 fZBottomCut(zBottomCut), fZTopCut(zTopCut)
85 :
G4VSolid(a), fDx(0.), fDy(0.), fDz(0.), fZBottomCut(0.), fZTopCut(0.)
95 delete fpPolyhedron; fpPolyhedron =
nullptr;
104 fDx(rhs.fDx), fDy(rhs.fDy), fDz(rhs.fDz),
105 fZBottomCut(rhs.fZBottomCut), fZTopCut(rhs.fZTopCut),
106 halfTolerance(rhs.halfTolerance),
107 fXmax(rhs.fXmax), fYmax(rhs.fYmax),
108 fRsph(rhs.fRsph), fR(rhs.fR),
109 fSx(rhs.fSx), fSy(rhs.fSy), fSz(rhs.fSz),
110 fZMidCut(rhs.fZMidCut), fZDimCut(rhs.fZDimCut),
111 fQ1(rhs.fQ1), fQ2(rhs.fQ2),
112 fCubicVolume(rhs.fCubicVolume),
113 fSurfaceArea(rhs.fSurfaceArea),
114 fLateralArea(rhs.fLateralArea)
126 if (
this == &rhs) {
return *
this; }
137 fZBottomCut = rhs.fZBottomCut;
138 fZTopCut = rhs.fZTopCut;
140 halfTolerance = rhs.halfTolerance;
148 fZMidCut = rhs.fZMidCut;
149 fZDimCut = rhs.fZDimCut;
153 fCubicVolume = rhs.fCubicVolume;
154 fSurfaceArea = rhs.fSurfaceArea;
155 fLateralArea = rhs.fLateralArea;
157 fRebuildPolyhedron =
false;
158 delete fpPolyhedron; fpPolyhedron =
nullptr;
167void G4Ellipsoid::CheckParameters()
174 if (fDx < dmin || fDy < dmin || fDz < dmin)
176 std::ostringstream message;
177 message <<
"Invalid (too small or negative) dimensions for Solid: "
179 <<
" semi-axis x: " << fDx <<
"\n"
180 <<
" semi-axis y: " << fDy <<
"\n"
181 <<
" semi-axis z: " << fDz;
182 G4Exception(
"G4Ellipsoid::CheckParameters()",
"GeomSolids0002",
191 if (fZBottomCut == 0. && fZTopCut == 0.)
196 if (fZBottomCut >= C || fZTopCut <= -C || fZBottomCut >= fZTopCut)
198 std::ostringstream message;
199 message <<
"Invalid Z cuts for Solid: "
201 <<
" bottom cut: " << fZBottomCut <<
"\n"
202 <<
" top cut: " << fZTopCut;
203 G4Exception(
"G4Ellipsoid::CheckParameters()",
"GeomSolids0002",
207 fZBottomCut = std::max(fZBottomCut, -C);
208 fZTopCut = std::min(fZTopCut, C);
213 if (fZBottomCut > 0.)
216 G4double scale = std::sqrt((1. - ratio) * (1 + ratio));
223 G4double scale = std::sqrt((1. - ratio) * (1 + ratio));
229 fRsph = std::max(std::max(
A, B), C);
230 fR = std::min(std::min(
A, B), C);
236 fZMidCut = 0.5 * (fZTopCut + fZBottomCut) * fSz;
237 fZDimCut = 0.5 * (fZTopCut - fZBottomCut) * fSz;
241 fQ2 = 0.5 * fR + halfTolerance * halfTolerance * fQ1;
267 pMin.
set(-fXmax,-fYmax, fZBottomCut);
268 pMax.
set( fXmax, fYmax, fZTopCut);
300 G4double rr = x * x + y * y + z * z;
301 G4double distZ = std::abs(z - fZMidCut) - fZDimCut;
303 G4double dist = std::max(distZ, distR);
305 if (dist > halfTolerance)
return kOutside;
322 G4double distZ = std::abs(z - fZMidCut) - fZDimCut;
323 if (std::abs(distZ) <= halfTolerance)
325 norm.
setZ(std::copysign(1., z - fZMidCut));
330 G4double distR = fQ1*(x*x + y*y + z*z) - fQ2;
331 if (std::abs(distR) <= halfTolerance)
339 if (nsurf == 1)
return norm;
340 else if (nsurf > 1)
return norm.
unit();
344 std::ostringstream message;
345 G4long oldprc = message.precision(16);
346 message <<
"Point p is not on surface (!?) of solid: "
348 message <<
"Position:\n";
349 message <<
" p.x() = " << p.
x()/mm <<
" mm\n";
350 message <<
" p.y() = " << p.
y()/mm <<
" mm\n";
351 message <<
" p.z() = " << p.
z()/mm <<
" mm";
353 G4Exception(
"G4Ellipsoid::SurfaceNormal(p)",
"GeomSolids1002",
357 return ApproxSurfaceNormal(p);
371 G4double rr = x * x + y * y + z * z;
372 G4double distZ = std::abs(z - fZMidCut) - fZDimCut;
373 G4double distR = std::sqrt(rr) - fR;
374 if (distR > distZ && rr > 0.)
377 return { 0., 0., std::copysign(1., z - fZMidCut) };
392 G4double safex = std::abs(p.
x()) - fXmax;
393 G4double safey = std::abs(p.
y()) - fYmax;
397 if (safex >= -halfTolerance && p.
x() * v.
x() >= 0.)
return kInfinity;
398 if (safey >= -halfTolerance && p.
y() * v.
y() >= 0.)
return kInfinity;
399 if (safet >= -halfTolerance && v.
z() >= 0.)
return kInfinity;
400 if (safeb >= -halfTolerance && v.
z() <= 0.)
return kInfinity;
404 G4double safe = std::max(std::max(std::max(safex, safey), safet), safeb);
405 if (safe > 32. * fRsph)
407 offset = (1. - 1.e-08) * safe - 2. * fRsph;
410 return (dist == kInfinity) ? kInfinity : dist + offset;
426 G4double distZ = std::abs(pzcut) - dzcut;
427 if (distZ >= -halfTolerance && pzcut * vz >= 0.)
return kInfinity;
429 G4double rr = px * px + py * py + pz * pz;
430 G4double pv = px * vx + py * vy + pz * vz;
432 if (distR >= -halfTolerance && pv >= 0.)
return kInfinity;
434 G4double A = vx * vx + vy * vy + vz * vz;
440 if (
D <=
EPS)
return kInfinity;
445 G4double dz = std::copysign(dzcut, invz);
446 G4double tzmin = (pzcut - dz) * invz;
447 G4double tzmax = (pzcut + dz) * invz;
451 G4double tmp = -
B - std::copysign(std::sqrt(
D),
B);
459 G4double tmin = std::max(tzmin, trmin);
460 G4double tmax = std::min(tzmax, trmax);
462 if (tmax - tmin <= halfTolerance)
return kInfinity;
463 return (tmin < halfTolerance) ? offset : tmin + offset;
477 G4double distX = std::abs(px) - fXmax;
478 G4double distY = std::abs(py) - fYmax;
479 G4double distZ = std::max(pz - fZTopCut, fZBottomCut - pz);
480 G4double distB = std::max(std::max(distX, distY), distZ);
486 G4double distR = std::sqrt(x*x + y*y + z*z) - fR;
489 G4double dist = std::max(distB, distR);
490 return (dist < 0.) ? 0. : dist;
509 G4double distZ = std::abs(pzcut) - dzcut;
510 if (distZ >= -halfTolerance && pzcut * vz > 0.)
515 n->set(0., 0., std::copysign(1., pzcut));
526 G4double rr = px * px + py * py + pz * pz;
527 G4double pv = px * vx + py * vy + pz * vz;
529 if (distR >= -halfTolerance && pv > 0.)
541 if (std::max(distZ, distR) > halfTolerance)
544 std::ostringstream message;
545 G4long oldprc = message.precision(16);
546 message <<
"Point p is outside (!?) of solid: "
548 message <<
"Position: " << p <<
G4endl;;
549 message <<
"Direction: " << v;
551 G4Exception(
"G4Ellipsoid::DistanceToOut(p,v)",
"GeomSolids1002",
558 *n = ApproxSurfaceNormal(p);
565 G4double A = vx * vx + vy * vy + vz * vz;
587 G4double tzmax = (vz == 0.) ?
DBL_MAX : (std::copysign(dzcut, vz) - pzcut) / vz;
591 G4double tmp = -
B - std::copysign(std::sqrt(
D),
B);
596 G4double tmax = std::min(tzmax, trmax);
605 n->set(0., 0., (pznew > fZMidCut) ? 1. : -1.);
609 G4double nx = (px + tmax * vx) * fSx;
610 G4double ny = (py + tmax * vy) * fSy;
611 G4double nz = (pz + tmax * vz) * fSz;
625 G4double distZ = std::min(fZTopCut - p.
z(), p.
z() - fZBottomCut);
631 G4double distR = fR - std::sqrt(x*x + y*y + z*z);
634 G4double dist = std::min(distZ, distR);
635 return (dist < 0.) ? 0. : dist;
644 return {
"G4Ellipsoid"};
662 G4long oldprc = os.precision(16);
663 os <<
"-----------------------------------------------------------\n"
664 <<
" *** Dump for solid - " <<
GetName() <<
" ***\n"
665 <<
" ===================================================\n"
668 <<
" semi-axis x: " <<
GetDx()/mm <<
" mm \n"
669 <<
" semi-axis y: " <<
GetDy()/mm <<
" mm \n"
670 <<
" semi-axis z: " <<
GetDz()/mm <<
" mm \n"
672 <<
" upper cut in z: " <<
GetZTopCut()/mm <<
" mm \n"
673 <<
"-----------------------------------------------------------\n";
674 os.precision(oldprc);
684 if (fCubicVolume == 0.)
686 G4double piAB_3 = CLHEP::pi * fDx * fDy / 3.;
687 fCubicVolume = 4. * piAB_3 * fDz;
688 if (fZBottomCut > -fDz)
690 G4double hbot = 1. + fZBottomCut / fDz;
691 fCubicVolume -= piAB_3 * hbot * hbot * (2. * fDz - fZBottomCut);
695 G4double htop = 1. - fZTopCut / fDz;
696 fCubicVolume -= piAB_3 * htop * htop * (2. * fDz + fZTopCut);
706G4double G4Ellipsoid::LateralSurfaceArea()
const
708 constexpr G4int NPHI = 1000.;
709 constexpr G4double dPhi = CLHEP::halfpi/NPHI;
718 G4double zmax = std::min(fZTopCut, fDz);
719 G4double zmin = std::max(fZBottomCut,-fDz);
735 ((zmax_c*std::sqrt(kk + tmax*tmax) - zmin_c*std::sqrt(kk + tmin*tmin)) +
736 (std::asinh(tmax*invk) - std::asinh(tmin*invk))*kk/root);
738 else if (kk > 1. + eps)
745 ((zmax_c*std::sqrt(kk - tmax*tmax) - zmin_c*std::sqrt(kk - tmin*tmin)) +
746 (std::asin(tmax*invk) - std::asin(tmin*invk))*kk/root);
750 area = CLHEP::twopi*fDx*(zmax - zmin);
756 for (
G4int i = 0; i < NPHI; ++i)
758 G4double sinPhi = std::sin(dPhi*(i + 0.5));
759 G4double kk = cc_aa + (cc_bb - cc_aa)*sinPhi*sinPhi;
767 ((zmax_c*std::sqrt(kk + tmax*tmax) - zmin_c*std::sqrt(kk + tmin*tmin)) +
768 (std::asinh(tmax*invk) - std::asinh(tmin*invk))*kk/root);
770 else if (kk > 1. + eps)
777 ((zmax_c*std::sqrt(kk - tmax*tmax) - zmin_c*std::sqrt(kk - tmin*tmin)) +
778 (std::asin(tmax*invk) - std::asin(tmin*invk))*kk/root);
782 area += 4.*ab*dPhi*(zmax_c - zmin_c);
794 if (fSurfaceArea == 0.)
796 G4double piAB = CLHEP::pi * fDx * fDy;
797 fSurfaceArea = LateralSurfaceArea();
798 if (fZBottomCut > -fDz)
800 G4double hbot = 1. + fZBottomCut / fDz;
801 fSurfaceArea += piAB * hbot * (2. - hbot);
805 G4double htop = 1. - fZTopCut / fDz;
806 fSurfaceArea += piAB * htop * (2. - htop);
828 G4double Sbot = piAB * Hbot * (2. - Hbot);
829 G4double Stop = piAB * Htop * (2. - Htop);
832 if (fLateralArea == 0.)
835 fLateralArea = LateralSurfaceArea();
843 if (select > Sbot) k = 1;
844 if (select > Sbot + Slat) k = 2;
852 G4double scale = std::sqrt(Hbot * (2. - Hbot));
854 p.
set(rho.
x(), rho.
y(), Zbot);
861 for (
G4int i = 0; i < 1000; ++i)
865 G4double rho = std::sqrt((1. + z) * (1. - z));
867 x = rho * std::cos(phi);
868 y = rho * std::sin(phi);
873 G4double mu = std::sqrt(xbc * xbc + yac * yac + zab * zab);
876 p.
set(
A * x,
B * y,
C * z);
881 G4double scale = std::sqrt(Htop * (2. - Htop));
883 p.
set(rho.
x(), rho.
y(), Ztop);
905 return { -fXmax, fXmax, -fYmax, fYmax, fZBottomCut, fZTopCut };
923 if (fpPolyhedron ==
nullptr ||
924 fRebuildPolyhedron ||
931 fRebuildPolyhedron =
false;
G4double C(G4double temp)
G4double B(G4double temperature)
G4double D(G4double temp)
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
#define G4MUTEX_INITIALIZER
CLHEP::Hep3Vector G4ThreeVector
G4GLOB_DLL std::ostream G4cout
void set(double x, double y, double z)
G4bool CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimits, const G4Transform3D &pTransform3D, G4double &pMin, G4double &pMax) const
G4double DistanceToOut(const G4ThreeVector &p, const G4ThreeVector &v, const G4bool calcNorm=false, G4bool *validNorm=nullptr, G4ThreeVector *n=nullptr) const override
void DescribeYourselfTo(G4VGraphicsScene &scene) const override
void ComputeDimensions(G4VPVParameterisation *p, const G4int n, const G4VPhysicalVolume *pRep) override
G4Ellipsoid(const G4String &name, G4double xSemiAxis, G4double ySemiAxis, G4double zSemiAxis, G4double zBottomCut=0., G4double zTopCut=0.)
EInside Inside(const G4ThreeVector &p) const override
G4Polyhedron * CreatePolyhedron() const override
G4double GetSurfaceArea() override
G4VSolid * Clone() const override
G4ThreeVector GetPointOnSurface() const override
G4double GetZTopCut() const
G4double GetZBottomCut() const
G4bool CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimit, const G4AffineTransform &pTransform, G4double &pmin, G4double &pmax) const override
G4double GetCubicVolume() override
G4GeometryType GetEntityType() const override
G4Polyhedron * GetPolyhedron() const override
void BoundingLimits(G4ThreeVector &pMin, G4ThreeVector &pMax) const override
G4VisExtent GetExtent() const override
G4Ellipsoid & operator=(const G4Ellipsoid &rhs)
G4ThreeVector SurfaceNormal(const G4ThreeVector &p) const override
std::ostream & StreamInfo(std::ostream &os) const override
G4double DistanceToIn(const G4ThreeVector &p, const G4ThreeVector &v) const override
G4int GetNumberOfRotationStepsAtTimeOfCreation() const
virtual void AddSolid(const G4Box &)=0
virtual void ComputeDimensions(G4Box &, const G4int, const G4VPhysicalVolume *) const
G4VSolid & operator=(const G4VSolid &rhs)
static G4int GetNumberOfRotationSteps()