57 using namespace CLHEP;
70 :
G4VSolid(pName), fpPolyhedron(0), fCubicVolume(0.), fSurfaceArea(0.),
71 zBottomCut(0.), zTopCut(0.)
79 if ( (pxSemiAxis<=0.) || (pySemiAxis<=0.) || (pzSemiAxis<=0.) )
81 std::ostringstream message;
82 message <<
"Invalid semi-axis - " <<
GetName();
83 G4Exception(
"G4Ellipsoid::G4Ellipsoid()",
"GeomSolids0002",
88 if ( pzBottomCut == 0 && pzTopCut == 0 )
92 else if ( (pzBottomCut < pzSemiAxis) && (pzTopCut > -pzSemiAxis)
93 && (pzBottomCut < pzTopCut) )
99 std::ostringstream message;
100 message <<
"Invalid z-coordinate for cutting plane - " <<
GetName();
101 G4Exception(
"G4Ellipsoid::G4Ellipsoid()",
"GeomSolids0002",
112 :
G4VSolid(a), fpPolyhedron(0), kRadTolerance(0.), fCubicVolume(0.),
113 fSurfaceArea(0.), xSemiAxis(0.), ySemiAxis(0.), zSemiAxis(0.),
114 semiAxisMax(0.), zBottomCut(0.), zTopCut(0.)
132 fpPolyhedron(0), kRadTolerance(rhs.kRadTolerance),
133 fCubicVolume(rhs.fCubicVolume), fSurfaceArea(rhs.fSurfaceArea),
134 xSemiAxis(rhs.xSemiAxis), ySemiAxis(rhs.ySemiAxis),
135 zSemiAxis(rhs.zSemiAxis), semiAxisMax(rhs.semiAxisMax),
136 zBottomCut(rhs.zBottomCut), zTopCut(rhs.zTopCut)
148 if (
this == &rhs) {
return *
this; }
157 fCubicVolume = rhs.fCubicVolume; fSurfaceArea = rhs.fSurfaceArea;
158 xSemiAxis = rhs.xSemiAxis; ySemiAxis = rhs.ySemiAxis;
159 zSemiAxis = rhs.zSemiAxis; semiAxisMax = rhs.semiAxisMax;
160 zBottomCut = rhs.zBottomCut; zTopCut = rhs.zTopCut;
190 xMin=xoffset - xSemiAxis;
191 xMax=xoffset + xSemiAxis;
213 yMin=yoffset - ySemiAxis;
214 yMax=yoffset + ySemiAxis;
236 zMin=zoffset + (-zSemiAxis > zBottomCut ? -zSemiAxis : zBottomCut);
237 zMax=zoffset + ( zSemiAxis < zTopCut ? zSemiAxis : zTopCut);
260 xoff = (xoffset < xMin) ? (xMin-xoffset)
261 : (xoffset > xMax) ? (xoffset-xMax) : 0.0;
262 yoff = (yoffset < yMin) ? (yMin-yoffset)
263 : (yoffset > yMax) ? (yoffset-yMax) : 0.0;
285 maxDiff= 1.0-
sqr(yoff/ySemiAxis);
286 if (maxDiff < 0.0) {
return false; }
287 maxDiff= xSemiAxis * std::sqrt(maxDiff);
288 newMin=xoffset-maxDiff;
289 newMax=xoffset+maxDiff;
290 pMin=(newMin<xMin) ? xMin : newMin;
291 pMax=(newMax>xMax) ? xMax : newMax;
307 maxDiff= 1.0-
sqr(xoff/xSemiAxis);
308 if (maxDiff < 0.0) {
return false; }
309 maxDiff= ySemiAxis * std::sqrt(maxDiff);
310 newMin=yoffset-maxDiff;
311 newMax=yoffset+maxDiff;
312 pMin=(newMin<yMin) ? yMin : newMin;
313 pMax=(newMax>yMax) ? yMax : newMax;
330 G4int i,j,noEntries,noBetweenSections;
331 G4bool existsAfterClip=
false;
335 G4int noPolygonVertices=0;
342 noEntries=vertices->size();
343 noBetweenSections=noEntries-noPolygonVertices;
346 for (i=0;i<noEntries;i+=noPolygonVertices)
348 for(j=0;j<(noPolygonVertices/2)-1;j++)
350 ThetaPolygon.push_back((*vertices)[i+j]);
351 ThetaPolygon.push_back((*vertices)[i+j+1]);
352 ThetaPolygon.push_back((*vertices)[i+noPolygonVertices-2-j]);
353 ThetaPolygon.push_back((*vertices)[i+noPolygonVertices-1-j]);
355 ThetaPolygon.clear();
358 for (i=0;i<noBetweenSections;i+=noPolygonVertices)
360 for(j=0;j<noPolygonVertices-1;j++)
362 ThetaPolygon.push_back((*vertices)[i+j]);
363 ThetaPolygon.push_back((*vertices)[i+j+1]);
364 ThetaPolygon.push_back((*vertices)[i+noPolygonVertices+j+1]);
365 ThetaPolygon.push_back((*vertices)[i+noPolygonVertices+j]);
367 ThetaPolygon.clear();
369 ThetaPolygon.push_back((*vertices)[i+noPolygonVertices-1]);
370 ThetaPolygon.push_back((*vertices)[i]);
371 ThetaPolygon.push_back((*vertices)[i+noPolygonVertices]);
372 ThetaPolygon.push_back((*vertices)[i+2*noPolygonVertices-1]);
374 ThetaPolygon.clear();
376 if ( (pMin!=kInfinity) || (pMax!=-kInfinity) )
378 existsAfterClip=
true;
400 existsAfterClip=
true;
406 return existsAfterClip;
422 static const G4double halfRadTolerance=kRadTolerance*0.5;
426 if (p.
z() < zBottomCut-halfRadTolerance) {
return in=
kOutside; }
427 if (p.
z() > zTopCut+halfRadTolerance) {
return in=
kOutside; }
429 rad2oo=
sqr(p.
x()/(xSemiAxis+halfRadTolerance))
430 +
sqr(p.
y()/(ySemiAxis+halfRadTolerance))
431 +
sqr(p.
z()/(zSemiAxis+halfRadTolerance));
433 if (rad2oo > 1.0) {
return in=
kOutside; }
435 rad2oi=
sqr(p.
x()*(1.0+halfRadTolerance/xSemiAxis)/xSemiAxis)
436 +
sqr(p.
y()*(1.0+halfRadTolerance/ySemiAxis)/ySemiAxis)
437 +
sqr(p.
z()*(1.0+halfRadTolerance/zSemiAxis)/zSemiAxis);
444 in = ( (p.
z() < zBottomCut+halfRadTolerance)
446 if ( rad2oi > 1.0-halfRadTolerance ) { in=
kSurface; }
462 G4double distR, distZBottom, distZTop;
468 p.
y()/(ySemiAxis*ySemiAxis),
469 p.
z()/(zSemiAxis*zSemiAxis));
474 distR = std::fabs( (p*norm - 1.0) * radius ) / 2.0;
478 distZBottom = std::fabs( p.
z() - zBottomCut );
479 distZTop = std::fabs( p.
z() - zTopCut );
481 if ( (distZBottom < distR) || (distZTop < distR) )
483 return G4ThreeVector(0.,0.,(distZBottom < distZTop) ? -1.0 : 1.0);
485 return ( norm *= radius );
498 static const G4double halfRadTolerance=kRadTolerance*0.5;
500 G4double distMin = std::min(xSemiAxis,ySemiAxis);
501 const G4double dRmax = 100.*std::min(distMin,zSemiAxis);
505 if (p.
z() <= zBottomCut+halfCarTolerance)
507 if (v.
z() <= 0.0) {
return distMin; }
508 G4double distZ = (zBottomCut - p.
z()) / v.
z();
510 if ( (distZ > -halfRadTolerance) && (
Inside(p+distZ*v) !=
kOutside) )
513 if ( std::fabs(distZ) < halfRadTolerance ) { distZ=0.; }
514 return distMin= distZ;
517 if (p.
z() >= zTopCut-halfCarTolerance)
519 if (v.
z() >= 0.0) {
return distMin;}
521 if ( (distZ > -halfRadTolerance) && (
Inside(p+distZ*v) !=
kOutside) )
524 if ( std::fabs(distZ) < halfRadTolerance ) { distZ=0.; }
525 return distMin= distZ;
533 A=
sqr(v.
x()/xSemiAxis) +
sqr(v.
y()/ySemiAxis) +
sqr(v.
z()/zSemiAxis);
534 C=
sqr(p.
x()/xSemiAxis) +
sqr(p.
y()/ySemiAxis) +
sqr(p.
z()/zSemiAxis) - 1.0;
535 B= 2.0 * ( p.
x()*v.
x()/(xSemiAxis*xSemiAxis)
536 + p.
y()*v.
y()/(ySemiAxis*ySemiAxis)
537 + p.
z()*v.
z()/(zSemiAxis*zSemiAxis) );
542 G4double distR= (-B - std::sqrt(C)) / (2.0*A);
544 if ( (distR > halfRadTolerance)
545 && (intZ >= zBottomCut-halfRadTolerance)
546 && (intZ <= zTopCut+halfRadTolerance) )
550 else if( (distR >- halfRadTolerance)
551 && (intZ >= zBottomCut-halfRadTolerance)
552 && (intZ <= zTopCut+halfRadTolerance) )
558 distR = (-B + std::sqrt(C) ) / (2.0*A);
559 if(distR>0.) { distMin=0.; }
563 distR= (-B + std::sqrt(C)) / (2.0*A);
564 intZ = p.
z()+distR*v.
z();
565 if ( (distR > halfRadTolerance)
566 && (intZ >= zBottomCut-halfRadTolerance)
567 && (intZ <= zTopCut+halfRadTolerance) )
570 if (norm.
dot(v)<0.) { distMin = distR; }
573 if ( (distMin!=kInfinity) && (distMin>dRmax) )
576 G4double fTerm = distMin-std::fmod(distMin,dRmax);
581 if (std::fabs(distMin)<halfRadTolerance) { distMin=0.; }
597 p.
y()/(ySemiAxis*ySemiAxis),
598 p.
z()/(zSemiAxis*zSemiAxis));
603 distR= (p*norm - 1.0) * radius / 2.0;
607 distZ= zBottomCut - p.
z();
610 distZ = p.
z() - zTopCut;
617 return (distR < 0.0) ? 0.0 : distR;
619 else if (distR < 0.0)
625 return (distZ < distR) ? distZ : distR;
640 enum surface_e {kPlaneSurf, kCurvedSurf, kNoSurf} surface;
649 G4double distZ = (zBottomCut - p.
z()) / v.
z();
653 if (!calcNorm) {
return 0.0;}
664 if (!calcNorm) {
return 0.0;}
673 p.
y()/(ySemiAxis*ySemiAxis),
674 p.
z()/(zSemiAxis*zSemiAxis));
680 A=
sqr(v.
x()/xSemiAxis) +
sqr(v.
y()/ySemiAxis) +
sqr(v.
z()/zSemiAxis);
681 C= (p * nearnorm) - 1.0;
682 B= 2.0 * (v * nearnorm);
687 G4double distR= (-B + std::sqrt(C) ) / (2.0*A);
691 if (!calcNorm) {
return 0.0;}
696 surface= kCurvedSurf;
704 if (surface == kNoSurf)
720 pexit.
y()/(ySemiAxis*ySemiAxis),
721 pexit.
z()/(zSemiAxis*zSemiAxis));
722 truenorm *= 1.0/truenorm.
mag();
727 std::ostringstream message;
728 G4int oldprc = message.precision(16);
729 message <<
"Undefined side for valid surface normal to solid."
732 <<
" p.x() = " << p.
x()/
mm <<
" mm" <<
G4endl
733 <<
" p.y() = " << p.
y()/
mm <<
" mm" <<
G4endl
734 <<
" p.z() = " << p.
z()/
mm <<
" mm" <<
G4endl
736 <<
" v.x() = " << v.
x() <<
G4endl
737 <<
" v.y() = " << v.
y() <<
G4endl
738 <<
" v.z() = " << v.
z() <<
G4endl
739 <<
"Proposed distance :" <<
G4endl
740 <<
" distMin = " << distMin/
mm <<
" mm";
741 message.precision(oldprc);
764 std::ostringstream message;
765 G4int oldprc = message.precision(16);
766 message <<
"Point p is outside !?" <<
G4endl
768 <<
" p.x() = " << p.
x()/
mm <<
" mm" <<
G4endl
769 <<
" p.y() = " << p.
y()/
mm <<
" mm" <<
G4endl
770 <<
" p.z() = " << p.
z()/
mm <<
" mm";
771 message.precision(oldprc) ;
772 G4Exception(
"G4Ellipsoid::DistanceToOut(p)",
"GeomSolids1002",
780 p.
y()/(ySemiAxis*ySemiAxis),
781 p.
z()/(zSemiAxis*zSemiAxis));
787 if ( (tmp > 0.0) && (1.0 < radius*tmp) ) {radius = 1.0/
tmp;}
791 distR = (1.0 - p*
norm) * radius / 2.0;
795 distZ = p.
z() - zBottomCut;
796 if (distZ < 0.0) {distZ= zTopCut - p.
z();}
800 if ( (distZ < 0.0) || (distR < 0.0) )
806 return (distZ < distR) ? distZ : distR;
823 G4int& noPolygonVertices)
const
827 G4double meshAnglePhi, meshRMaxFactor,
828 crossAnglePhi, coscrossAnglePhi, sincrossAnglePhi, sAnglePhi;
829 G4double meshTheta, crossTheta, startTheta;
830 G4double rMaxX, rMaxY, rMaxZ, rMaxMax, rx, ry, rz;
831 G4int crossSectionPhi, noPhiCrossSections, crossSectionTheta, noThetaSections;
847 meshAnglePhi=
twopi/(noPhiCrossSections-1);
852 sAnglePhi = -meshAnglePhi*0.5;
868 meshTheta=
pi/(noThetaSections-2);
873 startTheta = -meshTheta*0.5;
875 meshRMaxFactor = 1.0/std::cos(0.5*
876 std::sqrt(meshAnglePhi*meshAnglePhi+meshTheta*meshTheta));
877 rMaxMax= (xSemiAxis > ySemiAxis ? xSemiAxis : ySemiAxis);
878 if (zSemiAxis > rMaxMax) rMaxMax= zSemiAxis;
879 rMaxX= xSemiAxis + rMaxMax*(meshRMaxFactor-1.0);
880 rMaxY= ySemiAxis + rMaxMax*(meshRMaxFactor-1.0);
881 rMaxZ= zSemiAxis + rMaxMax*(meshRMaxFactor-1.0);
885 if (vertices && cosCrossTheta && sinCrossTheta)
887 for (crossSectionTheta=0; crossSectionTheta<noThetaSections;
892 crossTheta=startTheta+crossSectionTheta*meshTheta;
893 cosCrossTheta[crossSectionTheta]=std::cos(crossTheta);
894 sinCrossTheta[crossSectionTheta]=std::sin(crossTheta);
896 for (crossSectionPhi=0; crossSectionPhi<noPhiCrossSections;
899 crossAnglePhi=sAnglePhi+crossSectionPhi*meshAnglePhi;
900 coscrossAnglePhi=std::cos(crossAnglePhi);
901 sincrossAnglePhi=std::sin(crossAnglePhi);
902 for (crossSectionTheta=0; crossSectionTheta<noThetaSections;
907 rx= sinCrossTheta[crossSectionTheta]*coscrossAnglePhi*rMaxX;
908 ry= sinCrossTheta[crossSectionTheta]*sincrossAnglePhi*rMaxY;
909 rz= cosCrossTheta[crossSectionTheta]*rMaxZ;
918 noPolygonVertices = noThetaSections ;
923 G4Exception(
"G4Ellipsoid::CreateRotatedVertices()",
925 "Error in allocation of vertices. Out of memory !");
928 delete[] cosCrossTheta;
929 delete[] sinCrossTheta;
958 G4int oldprc = os.precision(16);
959 os <<
"-----------------------------------------------------------\n"
960 <<
" *** Dump for solid - " <<
GetName() <<
" ***\n"
961 <<
" ===================================================\n"
962 <<
" Solid type: G4Ellipsoid\n"
965 <<
" semi-axis x: " << xSemiAxis/
mm <<
" mm \n"
966 <<
" semi-axis y: " << ySemiAxis/
mm <<
" mm \n"
967 <<
" semi-axis z: " << zSemiAxis/
mm <<
" mm \n"
968 <<
" max semi-axis: " << semiAxisMax/
mm <<
" mm \n"
969 <<
" lower cut plane level z: " << zBottomCut/
mm <<
" mm \n"
970 <<
" upper cut plane level z: " << zTopCut/
mm <<
" mm \n"
971 <<
"-----------------------------------------------------------\n";
972 os.precision(oldprc);
983 G4double aTop, aBottom, aCurved, chose, xRand, yRand, zRand, phi;
984 G4double cosphi, sinphi, costheta, sintheta,
alpha, beta, max1, max2, max3;
986 max1 = xSemiAxis > ySemiAxis ? xSemiAxis : ySemiAxis;
987 max1 = max1 > zSemiAxis ? max1 : zSemiAxis;
988 if (max1 == xSemiAxis) { max2 = ySemiAxis; max3 = zSemiAxis; }
989 else if (max1 == ySemiAxis) { max2 = xSemiAxis; max3 = zSemiAxis; }
990 else { max2 = xSemiAxis; max3 = ySemiAxis; }
992 phi = RandFlat::shoot(0.,
twopi);
994 cosphi = std::cos(phi); sinphi = std::sin(phi);
995 costheta = RandFlat::shoot(zBottomCut,zTopCut)/zSemiAxis;
996 sintheta = std::sqrt(1.-
sqr(costheta));
998 alpha = 1.-
sqr(max2/max1); beta = 1.-
sqr(max3/max1);
1000 aTop =
pi*xSemiAxis*ySemiAxis*(1 -
sqr(zTopCut/zSemiAxis));
1001 aBottom =
pi*xSemiAxis*ySemiAxis*(1 -
sqr(zBottomCut/zSemiAxis));
1005 aCurved = 4.*
pi*max1*max2*(1.-1./6.*(alpha+beta)-
1006 1./120.*(3.*
sqr(alpha)+2.*alpha*beta+3.*
sqr(beta)));
1008 aCurved *= 0.5*(1.2*zTopCut/zSemiAxis - 1.2*zBottomCut/zSemiAxis);
1010 if( ( zTopCut >= zSemiAxis && zBottomCut <= -1.*zSemiAxis )
1011 || ( zTopCut == 0 && zBottomCut ==0 ) )
1013 aTop = 0; aBottom = 0;
1016 chose = RandFlat::shoot(0.,aTop + aBottom + aCurved);
1020 xRand = xSemiAxis*sintheta*cosphi;
1021 yRand = ySemiAxis*sintheta*sinphi;
1022 zRand = zSemiAxis*costheta;
1025 else if(chose >= aCurved && chose < aCurved + aTop)
1027 xRand = RandFlat::shoot(-1.,1.)*xSemiAxis
1028 * std::sqrt(1-
sqr(zTopCut/zSemiAxis));
1029 yRand = RandFlat::shoot(-1.,1.)*ySemiAxis
1030 * std::sqrt(1.-
sqr(zTopCut/zSemiAxis)-
sqr(xRand/xSemiAxis));
1036 xRand = RandFlat::shoot(-1.,1.)*xSemiAxis
1037 * std::sqrt(1-
sqr(zBottomCut/zSemiAxis));
1038 yRand = RandFlat::shoot(-1.,1.)*ySemiAxis
1039 * std::sqrt(1.-
sqr(zBottomCut/zSemiAxis)-
sqr(xRand/xSemiAxis));
1059 -semiAxisMax, semiAxisMax,
1060 -semiAxisMax, semiAxisMax);
1067 return new G4NURBSbox(semiAxisMax, semiAxisMax, semiAxisMax);
1073 zBottomCut, zTopCut);