38#if !(defined(G4GEOM_USE_UELLIPTICALCONE) && defined(G4GEOM_USE_SYS_USOLIDS))
76 if ( (pxSemiAxis <= 0.) || (pySemiAxis <= 0.) || (pzMax <= 0.) )
78 std::ostringstream message;
79 message <<
"Invalid semi-axis or height for solid: " <<
GetName()
80 <<
"\n X semi-axis, Y semi-axis, height = "
81 << pxSemiAxis <<
", " << pySemiAxis <<
", " << pzMax;
82 G4Exception(
"G4EllipticalCone::G4EllipticalCone()",
"GeomSolids0002",
88 std::ostringstream message;
89 message <<
"Invalid z-coordinate for cutting plane for solid: " <<
GetName()
90 <<
"\n Z top cut = " << pzTopCut;
91 G4Exception(
"G4EllipticalCone::G4EllipticalCone()",
"GeomSolids0002",
107 xSemiAxis(0.), ySemiAxis(0.), zheight(0.), zTopCut(0.),
108 cosAxisMin(0.), invXX(0.), invYY(0.)
126 :
G4VSolid(rhs), halfCarTol(rhs.halfCarTol),
127 fCubicVolume(rhs.fCubicVolume), fSurfaceArea(rhs.fSurfaceArea),
128 fMinZBaseArea(rhs.fMinZBaseArea), fMaxZBaseArea(rhs.fMaxZBaseArea),
129 xSemiAxis(rhs.xSemiAxis), ySemiAxis(rhs.ySemiAxis),
130 zheight(rhs.zheight), zTopCut(rhs.zTopCut),
131 cosAxisMin(rhs.cosAxisMin), invXX(rhs.invXX), invYY(rhs.invYY)
143 if (
this == &rhs) {
return *
this; }
151 halfCarTol = rhs.halfCarTol;
152 fCubicVolume = rhs.fCubicVolume; fSurfaceArea = rhs.fSurfaceArea;
153 fMinZBaseArea = rhs.fMinZBaseArea; fMaxZBaseArea = rhs.fMaxZBaseArea;
154 xSemiAxis = rhs.xSemiAxis; ySemiAxis = rhs.ySemiAxis;
155 zheight = rhs.zheight; zTopCut = rhs.zTopCut;
156 cosAxisMin = rhs.cosAxisMin; invXX = rhs.invXX; invYY = rhs.invYY;
172 xSemiAxis = newxSemiAxis;
173 ySemiAxis = newySemiAxis;
175 if (zTopCut > zheight) { zTopCut = zheight; }
176 G4double axmin = std::min(xSemiAxis, ySemiAxis);
177 cosAxisMin = axmin/std::sqrt(1. + axmin*axmin);
178 invXX = 1./(xSemiAxis*xSemiAxis);
179 invYY = 1./(ySemiAxis*ySemiAxis);
192 zTopCut = std::min(newzTopCut, zheight);
210 pMin.
set(-xmax,-ymax,-zcut);
211 pMax.
set( xmax, ymax, zcut);
215 if (pMin.
x() >= pMax.
x() || pMin.
y() >= pMax.
y() || pMin.
z() >= pMax.
z())
217 std::ostringstream message;
218 message <<
"Bad bounding box (min >= max) for solid: "
220 <<
"\npMin = " << pMin
221 <<
"\npMax = " << pMax;
222 G4Exception(
"G4EllipticalCone::BoundingLimits()",
"GeomMgt0001",
250 return exist = pMin < pMax;
255 static const G4int NSTEPS = 48;
256 static const G4double ang = twopi/NSTEPS;
257 static const G4double sinHalf = std::sin(0.5*ang);
258 static const G4double cosHalf = std::cos(0.5*ang);
259 static const G4double sinStep = 2.*sinHalf*cosHalf;
260 static const G4double cosStep = 1. - 2.*sinHalf*sinHalf;
271 for (
G4int k=0; k<NSTEPS; ++k)
273 baseA[k].set(sxmax*cosCur,symax*sinCur,-zcut);
274 baseB[k].set(sxmin*cosCur,symin*sinCur, zcut);
277 sinCur = sinCur*cosStep + cosCur*sinStep;
278 cosCur = cosCur*cosStep - sinTmp*sinStep;
281 std::vector<const G4ThreeVectorList *> polygons(2);
282 polygons[0] = &baseA;
283 polygons[1] = &baseB;
295 G4double hp = std::sqrt(p.
x()*p.
x()*invXX + p.
y()*p.
y()*invYY) + p.
z();
296 G4double ds = (hp - zheight)*cosAxisMin;
300 if (dist > halfCarTol) {
return kOutside; }
313 G4double hp = std::sqrt(p.
x()*p.
x()*invXX + p.
y()*p.
y()*invYY) + p.
z();
314 G4double ds = (hp - zheight)*cosAxisMin;
315 if (std::abs(ds) <= halfCarTol)
319 if (mag == 0) {
return {0,0,1}; }
324 if (std::abs(dz) <= halfCarTol)
342 std::ostringstream message;
343 G4long oldprc = message.precision(16);
344 message <<
"Point p is not on surface (!?) of solid: "
346 message <<
"Position:\n";
347 message <<
" p.x() = " << p.
x()/mm <<
" mm\n";
348 message <<
" p.y() = " << p.
y()/mm <<
" mm\n";
349 message <<
" p.z() = " << p.
z()/mm <<
" mm";
351 G4Exception(
"G4EllipticalCone::SurfaceNormal(p)",
"GeomSolids1002",
355 return ApproxSurfaceNormal(p);
365G4EllipticalCone::ApproxSurfaceNormal(
const G4ThreeVector& p)
const
367 G4double hp = std::sqrt(p.
x()*p.
x()*invXX + p.
y()*p.
y()*invYY) + p.
z();
368 G4double ds = (hp - zheight)*cosAxisMin;
370 if (ds > dz && std::abs(hp - p.
z()) > halfCarTol)
374 return { 0., 0., (
G4double)((p.
z() < 0) ? -1. : 1.) };
395 if (sigz < halfCarTol)
407 if (sigz < 0) {
return kInfinity; }
414 if (
sqr(p.
x()/( xSemiAxis - halfCarTol ))
415 +
sqr(p.
y()/( ySemiAxis - halfCarTol )) <=
sqr( zheight + zTopCut ) )
431 yi = p.
y() + q*v.
y();
436 if (
sqr(xi/xSemiAxis) +
sqr(yi/ySemiAxis) <=
sqr( zheight + zTopCut ) )
441 return (sigz < -halfCarTol) ? q : 0;
443 if (xi/(xSemiAxis*xSemiAxis)*v.
x() + yi/(ySemiAxis*ySemiAxis)*v.
y() >= 0)
457 sigz = p.
z() - zTopCut;
459 if (sigz > -halfCarTol)
463 if (sigz > 0) {
return kInfinity; }
465 if (
sqr(p.
x()/( xSemiAxis - halfCarTol ))
466 +
sqr(p.
y()/( ySemiAxis - halfCarTol )) <=
sqr( zheight-zTopCut ) )
476 yi = p.
y() + q*v.
y();
478 if (
sqr(xi/xSemiAxis) +
sqr(yi/ySemiAxis) <=
sqr( zheight - zTopCut ) )
480 return (sigz > -halfCarTol) ? q : 0;
482 if (xi/(xSemiAxis*xSemiAxis)*v.
x() + yi/(ySemiAxis*ySemiAxis)*v.
y() >= 0)
493 if (p.
z() < -zTopCut - halfCarTol)
495 if (v.
z() <= 0.0) {
return distMin; }
499 if (
sqr((lambda*v.
x()+p.
x())/xSemiAxis) +
500 sqr((lambda*v.
y()+p.
y())/ySemiAxis) <=
501 sqr(zTopCut + zheight + halfCarTol) )
503 return distMin = std::fabs(lambda);
507 if (p.
z() > zTopCut + halfCarTol)
509 if (v.
z() >= 0.0) {
return distMin; }
513 if (
sqr((lambda*v.
x() + p.
x())/xSemiAxis) +
514 sqr((lambda*v.
y() + p.
y())/ySemiAxis) <=
515 sqr(zheight - zTopCut + halfCarTol) )
517 return distMin = std::fabs(lambda);
521 if (p.
z() > zTopCut - halfCarTol
522 && p.
z() < zTopCut + halfCarTol )
524 if (v.
z() > 0.) {
return kInfinity; }
529 if (p.
z() < -zTopCut + halfCarTol
530 && p.
z() > -zTopCut - halfCarTol)
532 if (v.
z() < 0.) {
return distMin = kInfinity; }
544 v.
y()*p.
y()/
sqr(ySemiAxis) + v.
z()*(zheight-p.
z()));
546 sqr(zheight - p.
z());
552 if ( discr < -halfCarTol ) {
return distMin; }
556 if ( (discr >= -halfCarTol ) && (discr < halfCarTol ) )
558 return distMin = std::fabs(-
B/(2.*
A));
562 G4double minus = (-
B-std::sqrt(discr))/(2.*
A);
566 if ( ( std::fabs(plus) < halfCarTol )||( std::fabs(minus) < halfCarTol ) )
569 p.
y()/(ySemiAxis*ySemiAxis),
570 -( p.
z() - zheight ));
571 if ( truenorm*v >= 0)
581 if ( minus > halfCarTol && minus < distMin )
586 if(std::fabs(pin.
z())< zTopCut + halfCarTol)
589 pin.
y()/(ySemiAxis*ySemiAxis),
590 - ( pin.
z() - zheight ));
597 if ( plus > halfCarTol && plus < distMin )
602 if(std::fabs(pin.
z()) < zTopCut + halfCarTol)
605 pin.
y()/(ySemiAxis*ySemiAxis),
606 - ( pin.
z() - zheight ) );
613 if (distMin < halfCarTol) { distMin=0.; }
624 G4double hp = std::sqrt(p.
x()*p.
x()*invXX + p.
y()*p.
y()*invYY) + p.
z();
625 G4double ds = (hp - zheight)*cosAxisMin;
628 return (dist > 0) ? dist : 0.;
643 enum surface_e {kPlaneSurf, kCurvedSurf, kNoSurf} surface;
650 lambda = (-p.
z() - zTopCut)/v.
z();
652 if ( (
sqr((p.
x() + lambda*v.
x())/xSemiAxis) +
653 sqr((p.
y() + lambda*v.
y())/ySemiAxis)) <
654 sqr(zheight + zTopCut + halfCarTol) )
656 distMin = std::fabs(lambda);
658 if (!calcNorm) {
return distMin; }
660 distMin = std::fabs(lambda);
661 surface = kPlaneSurf;
666 lambda = (zTopCut - p.
z()) / v.
z();
668 if ( (
sqr((p.
x() + lambda*v.
x())/xSemiAxis)
669 +
sqr((p.
y() + lambda*v.
y())/ySemiAxis) )
670 < (
sqr(zheight - zTopCut + halfCarTol)) )
672 distMin = std::fabs(lambda);
673 if (!calcNorm) {
return distMin; }
675 distMin = std::fabs(lambda);
676 surface = kPlaneSurf;
684 v.
y()*p.
y()/
sqr(ySemiAxis) + v.
z()*(zheight-p.
z()));
686 -
sqr(zheight - p.
z());
690 if ( discr >= - halfCarTol && discr < halfCarTol )
692 if(!calcNorm) {
return distMin = std::fabs(-
B/(2.*
A)); }
695 else if ( discr > halfCarTol )
698 G4double minus = (-
B-std::sqrt(discr))/(2.*
A);
700 if ( plus > halfCarTol && minus > halfCarTol )
704 lambda = std::fabs(plus) < std::fabs(minus) ? plus : minus;
711 lambda = plus > -halfCarTol ? plus : 0;
714 if ( std::fabs(lambda) < distMin )
716 if( std::fabs(lambda) > halfCarTol)
718 distMin = std::fabs(lambda);
719 surface = kCurvedSurf;
724 p.
y()/(ySemiAxis*ySemiAxis),
725 -( p.
z() - zheight ));
726 if( truenorm.
dot(v) > 0 )
729 surface = kCurvedSurf;
739 if (surface == kNoSurf)
758 pexit.
y()/(ySemiAxis*ySemiAxis),
759 -( pexit.
z() - zheight ) );
760 truenorm /= truenorm.
mag();
767 std::ostringstream message;
768 G4long oldprc = message.precision(16);
769 message <<
"Undefined side for valid surface normal to solid."
772 <<
" p.x() = " << p.
x()/mm <<
" mm" <<
G4endl
773 <<
" p.y() = " << p.
y()/mm <<
" mm" <<
G4endl
774 <<
" p.z() = " << p.
z()/mm <<
" mm" <<
G4endl
776 <<
" v.x() = " << v.
x() <<
G4endl
777 <<
" v.y() = " << v.
y() <<
G4endl
778 <<
" v.z() = " << v.
z() <<
G4endl
779 <<
"Proposed distance :" <<
G4endl
780 <<
" distMin = " << distMin/mm <<
" mm";
781 message.precision(oldprc);
782 G4Exception(
"G4EllipticalCone::DistanceToOut(p,v,..)",
789 if (distMin < halfCarTol) { distMin=0; }
803 std::ostringstream message;
804 G4long oldprc = message.precision(16);
805 message <<
"Point p is outside (!?) of solid: " <<
GetName() <<
"\n"
807 <<
" p.x() = " << p.
x()/mm <<
" mm\n"
808 <<
" p.y() = " << p.
y()/mm <<
" mm\n"
809 <<
" p.z() = " << p.
z()/mm <<
" mm";
810 message.precision(oldprc) ;
811 G4Exception(
"G4Ellipsoid::DistanceToOut(p)",
"GeomSolids1002",
816 G4double hp = std::sqrt(p.
x()*p.
x()*invXX + p.
y()*p.
y()*invYY) + p.
z();
817 G4double ds = (zheight - hp)*cosAxisMin;
820 return (dist > 0) ? dist : 0.;
829 return {
"G4EllipticalCone"};
847 G4long oldprc = os.precision(16);
848 os <<
"-----------------------------------------------------------\n"
849 <<
" *** Dump for solid - " <<
GetName() <<
" ***\n"
850 <<
" ===================================================\n"
851 <<
" Solid type: G4EllipticalCone\n"
854 <<
" semi-axis x: " << xSemiAxis/mm <<
" mm \n"
855 <<
" semi-axis y: " << ySemiAxis/mm <<
" mm \n"
856 <<
" height z: " << zheight/mm <<
" mm \n"
857 <<
" half length in z: " << zTopCut/mm <<
" mm \n"
858 <<
"-----------------------------------------------------------\n";
859 os.precision(oldprc);
874 if (select < fMinZBaseArea + fMaxZBaseArea)
877 G4double z = (select < fMinZBaseArea) ? -zTopCut : zTopCut;
878 G4double a = xSemiAxis*(zheight - z);
879 G4double b = ySemiAxis*(zheight - z);
881 return { a*rho*cosphi, b*rho*sinphi, z };
891 G4double aabb = aa*bb + bb*cosphi*cosphi + aa*sinphi*sinphi;
892 G4double ss_max = 4.*ucut*ucut*(std::max(aa, bb) + aa*bb);
894 for (
auto i = 0; i < 10000; ++i)
897 G4double ss = (1. - u)*(1. - u)*aabb;
900 return { a*h*(1. - u)*cosphi, b*h*(1 - u)*sinphi, h*u };
909 if (fCubicVolume == 0)
914 G4double v0 = CLHEP::pi*x0*y0*zheight/3.;
915 G4double kmin = (zTopCut >= zheight ) ? 0. : (zheight - zTopCut)/zheight;
916 G4double kmax = (zTopCut >= zheight ) ? 2. : (zheight + zTopCut)/zheight;
917 fCubicVolume = (kmax - kmin)*(kmax*kmax + kmax*kmin + kmin*kmin)*v0;
929 if (fSurfaceArea == 0)
935 G4double kmin = (zTopCut >= zheight ) ? 0. : (zheight - zTopCut)/zheight;
936 G4double kmax = (zTopCut >= zheight ) ? 2. : (zheight + zTopCut)/zheight;
937 fMinZBaseArea = pi*x0*y0*kmax*kmax;
938 fMaxZBaseArea = pi*x0*y0*kmin*kmin;
939 fSurfaceArea = (kmax - kmin)*(kmax + kmin)*s0 + fMinZBaseArea + fMaxZBaseArea;
960 return { pmin.
x(), pmax.
x(), pmin.
y(), pmax.
y(), pmin.
z(), pmax.
z() };
972 || (
fpPolyhedron->GetNumberOfRotationStepsAtTimeOfCreation() !=
G4TemplateAutoLock< G4Mutex > G4AutoLock
std::vector< G4ThreeVector > G4ThreeVectorList
G4double C(G4double temp)
G4double B(G4double temperature)
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
G4GLOB_DLL std::ostream G4cout
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 BoundingBoxVsVoxelLimits(const EAxis pAxis, const G4VoxelLimits &pVoxelLimits, const G4Transform3D &pTransform3D, G4double &pMin, G4double &pMax) const
G4bool CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimits, const G4Transform3D &pTransform3D, G4double &pMin, G4double &pMax) const
G4bool CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimit, const G4AffineTransform &pTransform, G4double &pMin, G4double &pMax) const override
void SetSemiAxis(G4double x, G4double y, G4double z)
G4double GetSurfaceArea() override
G4VSolid * Clone() const override
EInside Inside(const G4ThreeVector &p) const override
G4double DistanceToIn(const G4ThreeVector &p, const G4ThreeVector &v) const override
G4ThreeVector SurfaceNormal(const G4ThreeVector &p) const override
G4VisExtent GetExtent() const override
void BoundingLimits(G4ThreeVector &pMin, G4ThreeVector &pMax) const override
G4EllipticalCone(const G4String &pName, G4double pxSemiAxis, G4double pySemiAxis, G4double zMax, G4double pzTopCut)
G4double GetCubicVolume() override
G4double DistanceToOut(const G4ThreeVector &p, const G4ThreeVector &v, const G4bool calcNorm=false, G4bool *validNorm=nullptr, G4ThreeVector *n=nullptr) const override
void SetZCut(G4double newzTopCut)
void DescribeYourselfTo(G4VGraphicsScene &scene) const override
G4GeometryType GetEntityType() const override
G4double GetSemiAxisX() const
G4bool fRebuildPolyhedron
G4Polyhedron * GetPolyhedron() const override
G4Polyhedron * fpPolyhedron
G4ThreeVector GetPointOnSurface() const override
G4double GetSemiAxisY() const
~G4EllipticalCone() override
std::ostream & StreamInfo(std::ostream &os) const override
G4Polyhedron * CreatePolyhedron() const override
G4double GetZTopCut() const
G4EllipticalCone & operator=(const G4EllipticalCone &rhs)
virtual void AddSolid(const G4Box &)=0
G4VSolid(const G4String &name)
G4VSolid & operator=(const G4VSolid &rhs)
G4VoxelLimits represents limitation/restrictions of space, where restrictions are only made perpendic...