35#if !(defined(G4GEOM_USE_UHYPE) && defined(G4GEOM_USE_SYS_USOLIDS))
75 std::ostringstream message;
76 message <<
"Invalid Z half-length in solid: " <<
GetName() <<
" !"
77 <<
"\nZ half-length: " << newHalfLenZ/mm <<
" mm";
81 halfLenZ = newHalfLenZ;
85 if (newInnerRadius < 0 || newOuterRadius < 0 || newInnerRadius >= newOuterRadius)
87 std::ostringstream message;
88 message <<
"Invalid radii in solid: " <<
GetName() <<
" !"
89 <<
"\nInner radius: " << newInnerRadius/mm <<
" mm"
90 <<
"\nOuter radius: " << newOuterRadius/mm <<
" mm";
95 innerRadius = newInnerRadius;
96 outerRadius = newOuterRadius;
98 innerRadius2 = innerRadius*innerRadius;
99 outerRadius2 = outerRadius*outerRadius;
106 if (endInnerRadius > endOuterRadius)
108 std::ostringstream message;
109 message <<
"Inconsistent stereo angles in solid: " <<
GetName() <<
" !"
110 <<
"\nEnd inner radius: " << endInnerRadius/mm <<
" mm"
111 <<
"\nEnd outer radius: " << endOuterRadius/mm <<
" mm";
121 :
G4VSolid(a), innerRadius(0.), outerRadius(0.), halfLenZ(0.), innerStereo(0.),
122 outerStereo(0.), tanInnerStereo(0.), tanOuterStereo(0.), tanInnerStereo2(0.),
123 tanOuterStereo2(0.), innerRadius2(0.), outerRadius2(0.), endInnerRadius2(0.),
124 endOuterRadius2(0.), endInnerRadius(0.), endOuterRadius(0.), fHalfTol(0.)
132 delete fpPolyhedron; fpPolyhedron =
nullptr;
138 :
G4VSolid(rhs), innerRadius(rhs.innerRadius),
139 outerRadius(rhs.outerRadius), halfLenZ(rhs.halfLenZ),
140 innerStereo(rhs.innerStereo), outerStereo(rhs.outerStereo),
141 tanInnerStereo(rhs.tanInnerStereo), tanOuterStereo(rhs.tanOuterStereo),
142 tanInnerStereo2(rhs.tanInnerStereo2), tanOuterStereo2(rhs.tanOuterStereo2),
143 innerRadius2(rhs.innerRadius2), outerRadius2(rhs.outerRadius2),
144 endInnerRadius2(rhs.endInnerRadius2), endOuterRadius2(rhs.endOuterRadius2),
145 endInnerRadius(rhs.endInnerRadius), endOuterRadius(rhs.endOuterRadius),
146 fCubicVolume(rhs.fCubicVolume), fSurfaceArea(rhs.fSurfaceArea),
147 fInnerSurfaceArea(rhs.fInnerSurfaceArea), fOuterSurfaceArea(rhs.fOuterSurfaceArea),
148 fHalfTol(rhs.fHalfTol)
158 if (
this == &rhs) {
return *
this; }
166 innerRadius = rhs.innerRadius; outerRadius = rhs.outerRadius;
167 halfLenZ = rhs.halfLenZ;
168 innerStereo = rhs.innerStereo; outerStereo = rhs.outerStereo;
169 tanInnerStereo = rhs.tanInnerStereo; tanOuterStereo = rhs.tanOuterStereo;
170 tanInnerStereo2 = rhs.tanInnerStereo2; tanOuterStereo2 = rhs.tanOuterStereo2;
171 innerRadius2 = rhs.innerRadius2; outerRadius2 = rhs.outerRadius2;
172 endInnerRadius2 = rhs.endInnerRadius2; endOuterRadius2 = rhs.endOuterRadius2;
173 endInnerRadius = rhs.endInnerRadius; endOuterRadius = rhs.endOuterRadius;
174 fCubicVolume = rhs.fCubicVolume; fSurfaceArea = rhs.fSurfaceArea;
175 fInnerSurfaceArea = rhs.fInnerSurfaceArea; fOuterSurfaceArea = rhs.fOuterSurfaceArea;
176 fHalfTol = rhs.fHalfTol;
177 fRebuildPolyhedron =
false;
178 delete fpPolyhedron; fpPolyhedron =
nullptr;
187 innerRadius = newIRad;
188 innerRadius2 = newIRad*newIRad;
189 endInnerRadius2 = HypeInnerRadius2(halfLenZ);
190 endInnerRadius = std::sqrt(endInnerRadius2);
195 fRebuildPolyhedron =
true;
202 outerRadius = newORad;
203 outerRadius2 = newORad*newORad;
204 endOuterRadius2 = HypeOuterRadius2(halfLenZ);
205 endOuterRadius = std::sqrt(endOuterRadius2);
210 fRebuildPolyhedron =
true;
218 endInnerRadius2 = HypeInnerRadius2(halfLenZ);
219 endInnerRadius = std::sqrt(endInnerRadius2);
220 endOuterRadius2 = HypeOuterRadius2(halfLenZ);
221 endOuterRadius = std::sqrt(endOuterRadius2);
228 fRebuildPolyhedron =
true;
235 innerStereo = std::abs(newISte);
236 tanInnerStereo = std::tan(innerStereo);
237 tanInnerStereo2 = tanInnerStereo*tanInnerStereo;
238 endInnerRadius2 = HypeInnerRadius2(halfLenZ);
239 endInnerRadius = std::sqrt(endInnerRadius2);
244 fRebuildPolyhedron =
true;
251 outerStereo = std::abs(newOSte);
252 tanOuterStereo = std::tan(outerStereo);
253 tanOuterStereo2 = tanOuterStereo*tanOuterStereo;
254 endOuterRadius2 = HypeOuterRadius2(halfLenZ);
255 endOuterRadius = std::sqrt(endOuterRadius2);
260 fRebuildPolyhedron =
true;
277 pMin.
set(-endOuterRadius,-endOuterRadius,-halfLenZ);
278 pMax.
set( endOuterRadius, endOuterRadius, halfLenZ);
282 if (pMin.
x() >= pMax.
x() || pMin.
y() >= pMax.
y() || pMin.
z() >= pMax.
z())
284 std::ostringstream message;
285 message <<
"Bad bounding box (min >= max) for solid: " <<
GetName() <<
" !"
286 <<
"\npMin = " << pMin
287 <<
"\npMax = " << pMax;
288 G4Exception(
"G4Hype::BoundingLimits()",
"GeomMgt0001",
319 if (absZ > halfLenZ + fHalfTol) {
return kOutside; }
324 const G4double oRad2(HypeOuterRadius2(absZ));
331 if (InnerSurfaceExists())
336 const G4double iRad2(HypeInnerRadius2(absZ));
346 if (absZ > halfLenZ - fHalfTol) {
return kSurface; }
360 const G4double distZ(absZ - halfLenZ);
364 const G4double dist2Outer( std::fabs(xR2 - HypeOuterRadius2(absZ)) );
366 if (InnerSurfaceExists())
371 const G4double dist2Inner( std::fabs(xR2 - HypeInnerRadius2(absZ)) );
372 if (dist2Inner < dist2Z && dist2Inner < dist2Outer)
381 if (dist2Z < dist2Outer)
383 return { 0.0, 0.0, (
G4double)(p.
z() < 0 ? -1.0 : 1.0) };
435 G4bool couldMissOuter(
true),
436 couldMissInner(
true),
437 cantMissInnerCylinder(
false);
444 if (sigz > -fHalfTol)
456 if (sigz > 0) {
return kInfinity; }
468 if (InnerSurfaceExists())
495 yi = p.
y() + q*v.
y();
502 if (pr2 <= endOuterRadius2)
504 if (InnerSurfaceExists())
506 if (pr2 >= endInnerRadius2) {
return (sigz < fHalfTol) ? 0 : q; }
512 G4double dot1 = (xi*v.
x() + yi*v.
y())*endInnerRadius/std::sqrt(pr2);
513 couldMissInner = (dot1 - halfLenZ*tanInnerStereo2*vz <= 0);
524 cantMissInnerCylinder =
true;
530 return (sigz < fHalfTol) ? 0 : q;
551 G4double dot1 = dotR*endOuterRadius/std::sqrt(pr2);
552 couldMissOuter = (dot1 - halfLenZ*tanOuterStereo2*vz>= 0);
564 G4int n = IntersectHype( p, v, outerRadius2, tanOuterStereo2, q );
571 if (pz < halfLenZ+fHalfTol)
573 G4double dr2 = p.
x()*p.
x() + p.
y()*p.
y() - HypeOuterRadius2(pz);
580 if (p.
x()*v.
x() + p.
y()*v.
y() - pz*tanOuterStereo2*vz < 0) {
return 0; }
588 for(
G4int i=0; i<n; ++i )
599 if (zi < -halfLenZ) {
continue; }
600 if (zi > +halfLenZ && couldMissOuter) {
continue; }
606 yi = p.
y() + q[i]*v.
y();
608 if (xi*v.
x() + yi*v.
y() - zi*tanOuterStereo2*vz > 0) {
continue; }
616 if (!InnerSurfaceExists()) {
return best; }
621 n = IntersectHype( p, v, innerRadius2, tanInnerStereo2, q );
624 if (cantMissInnerCylinder)
626 return (sigz < fHalfTol) ? 0 : -sigz/vz;
635 if (pz < halfLenZ+fHalfTol)
637 G4double dr2 = p.
x()*p.
x() + p.
y()*p.
y() - HypeInnerRadius2(pz);
644 if (p.
x()*v.
x() + p.
y()*v.
y() - pz*tanInnerStereo2*vz > 0) {
return 0; }
652 for(
G4int i=0; i<n; ++i )
654 if (q[i] > best) {
break; }
664 if (zi < -halfLenZ) {
continue; }
665 if (zi > +halfLenZ && couldMissInner) {
continue; }
671 yi = p.
y() + q[i]*v.
y();
673 if (xi*v.
x() + yi*v.
y() - zi*tanOuterStereo2*vz < 0) {
continue; }
716 if (r < endOuterRadius)
718 if (sigz > -fHalfTol)
720 if (InnerSurfaceExists())
722 if (r > endInnerRadius)
724 return sigz < fHalfTol ? 0 : sigz;
728 if (sigz > dr*tanInnerStereo2)
733 G4double answer = std::sqrt( dr*dr + sigz*sigz );
734 return answer < fHalfTol ? 0 : answer;
742 return sigz < fHalfTol ? 0 : sigz;
749 if (sigz > -dr*tanOuterStereo2)
754 G4double answer = std::sqrt( dr*dr + sigz*sigz );
755 return answer < fHalfTol ? 0 : answer;
759 if (InnerSurfaceExists())
761 if (r2 < HypeInnerRadius2(absZ)+
kCarTolerance*endInnerRadius)
766 G4double answer = ApproxDistInside( r,absZ,innerRadius,tanInnerStereo2 );
767 return answer < fHalfTol ? 0 : answer;
774 G4double answer = ApproxDistOutside( r, absZ, outerRadius, tanOuterStereo );
775 return answer < fHalfTol ? 0 : answer;
820 if (pz > halfLenZ-fHalfTol)
822 if (calcNorm) { *norm = *nBest; *validNorm =
true; }
829 sBest = (vz >
DBL_MIN) ? (halfLenZ - pz)/vz : kInfinity;
838 G4int n = IntersectHype( p, v, outerRadius2, tanOuterStereo2, q );
847 G4double dr2 = r2 - HypeOuterRadius2(pz);
854 if (normHere.
dot(v) > 0)
856 if (calcNorm) { *norm = normHere.
unit(); *validNorm =
false; }
864 for(
G4int i=0; i<n; ++i )
866 if (q[i] > sBest) {
break; }
875 if (norm1.
dot(v) > 0)
886 if (InnerSurfaceExists())
891 n = IntersectHype( p, v, innerRadius2, tanInnerStereo2, q );
897 G4double dr2 = r2 - HypeInnerRadius2(pz);
901 if (normHere.
dot(v) > 0)
905 *norm = normHere.
unit();
915 for(
G4int i=0; i<n; ++i )
917 if (q[i] > sBest) {
break; }
922 if (norm2.
dot(v) > 0)
941 if (nBest == &norm1 || nBest == &norm2)
943 *norm = nBest->
unit();
968 G4double tryOuter = ApproxDistInside( r, absZ, outerRadius, tanOuterStereo2 );
969 if (tryOuter < sBest) { sBest = tryOuter; }
971 if (InnerSurfaceExists())
973 G4double tryInner = ApproxDistOutside( r,absZ,innerRadius,tanInnerStereo );
974 if (tryInner < sBest) { sBest = tryInner; }
1024 G4double a = tx*tx + ty*ty - tz*tz*tan2Phi;
1025 G4double b = 2*( x0*tx + y0*ty - z0*tz*tan2Phi );
1026 G4double c = x0*x0 + y0*y0 - r2 - z0*z0*tan2Phi;
1034 if (std::fabs(b) <
DBL_MIN) {
return 0; }
1043 if (radical < -
DBL_MIN) {
return 0; }
1054 radical = std::sqrt(radical);
1056 G4double q = -0.5*( b + (b < 0 ? -radical : +radical) );
1061 ss[0] = sa; ss[1] = sb;
1065 ss[0] = sb; ss[1] = sa;
1093 if (tanPhi <
DBL_MIN) {
return pr-r0; }
1101 G4double r1 = std::sqrt( r0*r0 + z1*z1*tan2Phi );
1106 G4double z2 = (pr*tanPhi + pz)/(1 + tan2Phi);
1107 G4double r2 = std::sqrt( r0*r0 + z2*z2*tan2Phi );
1115 G4double len = std::sqrt(dr*dr + dz*dz);
1124 return std::sqrt( dr*dr + dz*dz );
1130 return std::fabs((pr-r1)*dz - (pz-z1)*dr)/len;
1150 if (tan2Phi <
DBL_MIN) {
return r0 - pr; }
1155 G4double rh = std::sqrt( r0*r0 + pz*pz*tan2Phi );
1159 G4double len = std::sqrt(dr*dr + dz*dz);
1164 return std::fabs((pr-rh)*dr)/len;
1178 return new G4Hype(*
this);
1185 G4long oldprc = os.precision(16);
1186 os <<
"-----------------------------------------------------------\n"
1187 <<
" *** Dump for solid - " <<
GetName() <<
" ***\n"
1188 <<
" ===================================================\n"
1189 <<
" Solid type: G4Hype\n"
1190 <<
" Parameters: \n"
1191 <<
" half length Z: " << halfLenZ/mm <<
" mm \n"
1192 <<
" inner radius : " << innerRadius/mm <<
" mm \n"
1193 <<
" outer radius : " << outerRadius/mm <<
" mm \n"
1194 <<
" inner stereo angle : " << innerStereo/degree <<
" degrees \n"
1195 <<
" outer stereo angle : " << outerStereo/degree <<
" degrees \n"
1196 <<
"-----------------------------------------------------------\n";
1197 os.precision(oldprc);
1206 G4double sbases = twopi*(endOuterRadius2 - endInnerRadius2);
1207 G4double stotal = fInnerSurfaceArea + fOuterSurfaceArea + sbases;
1214 if (select < sbases)
1218 G4double rho = std::sqrt(u*endOuterRadius2 + (1. - u)*endInnerRadius2);
1219 G4double z = (select < 0.5*sbases) ? -h : h;
1220 return { rho*cosphi, rho*sinphi, z };
1225 G4double rr = (select < stotal - fInnerSurfaceArea) ? outerRadius2 : innerRadius2;
1226 G4double endrr = (select < stotal - fInnerSurfaceArea) ? endOuterRadius2 : endInnerRadius2;
1229 G4double ss_max = rr*hh + delrr*(delrr + hh);
1231 for (
auto i = 0; i < 10000; ++i)
1235 G4double ss = rr*hh + delrr*(delrr + hh)*u*u;
1239 G4double rho = std::sqrt(rr + delrr*u*u);
1240 return { rho*cosphi, rho*sinphi, z };
1247 if (fCubicVolume == 0)
1251 twopi*halfLenZ*(2.*(outerRadius2 - innerRadius2) + endOuterRadius2 - endInnerRadius2)/3.;
1254 return fCubicVolume;
1261 if (fSurfaceArea == 0)
1264 fSurfaceArea = fInnerSurfaceArea + fOuterSurfaceArea + twopi*(endOuterRadius2 - endInnerRadius2);
1267 return fSurfaceArea;
1283 return { -endOuterRadius, endOuterRadius,
1284 -endOuterRadius, endOuterRadius,
1285 -halfLenZ, halfLenZ };
1293 tanInnerStereo2, tanOuterStereo2, halfLenZ);
1300 if (fpPolyhedron ==
nullptr ||
1301 fRebuildPolyhedron ||
1302 fpPolyhedron->GetNumberOfRotationStepsAtTimeOfCreation() !=
1303 fpPolyhedron->GetNumberOfRotationSteps())
1306 delete fpPolyhedron;
1308 fRebuildPolyhedron =
false;
1311 return fpPolyhedron;
G4TemplateAutoLock< G4Mutex > G4AutoLock
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
G4double G4QuickRand(uint32_t seed=0)
#define G4MUTEX_INITIALIZER
CLHEP::Hep3Vector G4ThreeVector
double dot(const Hep3Vector &) const
void set(double x, double y, double z)
G4BoundingEnvelope is a helper class to facilitate calculation of the extent of a solid within the li...
G4bool CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimits, const G4Transform3D &pTransform3D, G4double &pMin, G4double &pMax) const
void ComputeDimensions(G4VPVParameterisation *p, const G4int n, const G4VPhysicalVolume *pRep) override
G4Hype(const G4String &pName, G4double newInnerRadius, G4double newOuterRadius, G4double newInnerStereo, G4double newOuterStereo, G4double newHalfLenZ)
EInside Inside(const G4ThreeVector &p) const override
void BoundingLimits(G4ThreeVector &pMin, G4ThreeVector &pMax) const override
void DescribeYourselfTo(G4VGraphicsScene &scene) const override
G4GeometryType GetEntityType() const override
G4Hype & operator=(const G4Hype &rhs)
G4VisExtent GetExtent() const override
G4VSolid * Clone() const override
void SetOuterStereo(G4double newOSte)
G4Polyhedron * CreatePolyhedron() const override
G4ThreeVector GetPointOnSurface() const override
G4Polyhedron * GetPolyhedron() const override
G4bool CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimit, const G4AffineTransform &pTransform, G4double &pMin, G4double &pMax) const override
void SetOuterRadius(G4double newORad)
G4double GetSurfaceArea() override
G4double DistanceToOut(const G4ThreeVector &p, const G4ThreeVector &v, const G4bool calcNorm=false, G4bool *validNorm=nullptr, G4ThreeVector *n=nullptr) const override
std::ostream & StreamInfo(std::ostream &os) const override
void SetZHalfLength(G4double newHLZ)
G4ThreeVector SurfaceNormal(const G4ThreeVector &p) const override
G4double DistanceToIn(const G4ThreeVector &p, const G4ThreeVector &v) const override
void SetInnerStereo(G4double newISte)
void SetInnerRadius(G4double newIRad)
G4double GetCubicVolume() override
virtual void AddSolid(const G4Box &)=0
G4VPVParameterisation ia an abstract base class for Parameterisation, able to compute the transformat...
virtual void ComputeDimensions(G4Box &, const G4int, const G4VPhysicalVolume *) const
G4VPhysicalVolume is an abstract base class for the representation of a positioned volume....
G4VSolid(const G4String &name)
G4VSolid & operator=(const G4VSolid &rhs)
G4VoxelLimits represents limitation/restrictions of space, where restrictions are only made perpendic...