Import Geant4 0.1.0 source tree

This commit is contained in:
Gabriele Cosmo
2016-06-08 15:09:25 +02:00
parent b97f8d0df7
commit aaa409b6ee
2922 changed files with 55107 additions and 81674 deletions
+8 -8
View File
@@ -5,8 +5,8 @@
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4Box.cc,v 2.3 1998/10/09 13:24:45 japost Exp $
// GEANT4 tag $Name: geant4-00 $
// $Id: G4Box.cc,v 1.2 1999/04/13 11:05:04 sgiani Exp $
// GEANT4 tag $Name: geant4-00-01 $
//
//
//
@@ -77,8 +77,8 @@ G4bool G4Box::CalculateExtent(const EAxis pAxis,
xMax=xoffset+fDx;
if (pVoxelLimit.IsXLimited())
{
if (xMin>pVoxelLimit.GetMaxXExtent()
||xMax<pVoxelLimit.GetMinXExtent())
if (xMin>pVoxelLimit.GetMaxXExtent()+kCarTolerance
||xMax<pVoxelLimit.GetMinXExtent()-kCarTolerance)
{
return false;
}
@@ -101,8 +101,8 @@ G4bool G4Box::CalculateExtent(const EAxis pAxis,
yMax=yoffset+fDy;
if (pVoxelLimit.IsYLimited())
{
if (yMin>pVoxelLimit.GetMaxYExtent()
||yMax<pVoxelLimit.GetMinYExtent())
if (yMin>pVoxelLimit.GetMaxYExtent()+kCarTolerance
||yMax<pVoxelLimit.GetMinYExtent()-kCarTolerance)
{
return false;
}
@@ -125,8 +125,8 @@ G4bool G4Box::CalculateExtent(const EAxis pAxis,
zMax=zoffset+fDz;
if (pVoxelLimit.IsZLimited())
{
if (zMin>pVoxelLimit.GetMaxZExtent()
||zMax<pVoxelLimit.GetMinZExtent())
if (zMin>pVoxelLimit.GetMaxZExtent()+kCarTolerance
||zMax<pVoxelLimit.GetMinZExtent()-kCarTolerance)
{
return false;
}
+2 -2
View File
@@ -5,8 +5,8 @@
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4CSGSolid.cc,v 2.0 1998/07/02 17:02:11 gunter Exp $
// GEANT4 tag $Name: geant4-00 $
// $Id: G4CSGSolid.cc,v 1.1 1999/01/07 16:07:55 gunter Exp $
// GEANT4 tag $Name: geant4-00-01 $
//
#include "G4CSGSolid.hh"
@@ -1,7 +1,15 @@
//
// G4ClippablePolygon.cc
//
// Based on code from G4VSolid (P. Kent, V. Grichine, J. Allison)
// Includes code from G4VSolid (P. Kent, V. Grichine, J. Allison)
//
// ----------------------------------------------------------
// This code implementation is the intellectual property of
// the GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
#include "G4ClippablePolygon.hh"
@@ -26,80 +34,347 @@ void G4ClippablePolygon::ClearAllVertices()
}
//
// Clip
//
void G4ClippablePolygon::Clip( const G4VoxelLimits &voxelLimit )
{
//
// Heh. Do we have anything to do?
//
if (!voxelLimit.IsLimited()) return;
const G4bool G4ClippablePolygon::Clip( const G4VoxelLimits &voxelLimit )
{
if (voxelLimit.IsLimited()) {
ClipAlongOneAxis( voxelLimit, kXAxis );
ClipAlongOneAxis( voxelLimit, kYAxis );
ClipAlongOneAxis( voxelLimit, kZAxis );
}
//
// Loop over all axes
//
static EAxis axes[3] = { kXAxis, kYAxis, kZAxis };
EAxis *axis = axes;
do {
if (voxelLimit.IsLimited(*axis)) {
G4ThreeVectorList tempPolygon;
//
// Build a "simple" voxelLimit that includes only the min extent
// and apply this to our vertices, producing result in tempPolygon
//
G4VoxelLimits simpleLimit1;
simpleLimit1.AddLimit( *axis, voxelLimit.GetMinExtent(*axis), kInfinity );
ClipToSimpleLimits( vertices, tempPolygon, simpleLimit1 );
//
// If nothing is left from the above clip, we might as well return now
// (but with an empty vertices)
//
if (tempPolygon.entries() == 0) {
vertices.clear();
return;
}
//
// Now do the same, but using a "simple" limit that includes only the max extent.
// Apply this to out tempPolygon, producing result in vertices.
//
G4VoxelLimits simpleLimit2;
simpleLimit2.AddLimit( *axis, -kInfinity, voxelLimit.GetMaxExtent(*axis) );
ClipToSimpleLimits( tempPolygon, vertices, simpleLimit2 );
//
// If nothing is left, return now
//
if (vertices.entries() == 0) return;
}
} while( ++axis < axes + sizeof(axes)/sizeof(EAxis) );
return (vertices.entries() > 0);
}
//
// PartialClip
//
// Clip, while ignoring the indicated axis
//
const G4bool G4ClippablePolygon::PartialClip( const G4VoxelLimits &voxelLimit, const EAxis IgnoreMe )
{
if (voxelLimit.IsLimited()) {
if (IgnoreMe != kXAxis) ClipAlongOneAxis( voxelLimit, kXAxis );
if (IgnoreMe != kYAxis) ClipAlongOneAxis( voxelLimit, kYAxis );
if (IgnoreMe != kZAxis) ClipAlongOneAxis( voxelLimit, kZAxis );
}
return (vertices.entries() > 0);
}
//
// GetExtent
//
void G4ClippablePolygon::GetExtent( const EAxis axis,
G4double &min, G4double &max )
const G4bool G4ClippablePolygon::GetExtent( const EAxis axis,
G4double &min, G4double &max ) const
{
//
// Okay, how many entries do we have?
//
G4int noLeft = vertices.entries();
//
// Return false if nothing is left
//
if (noLeft == 0) return false;
//
// Initialize min and max to our first vertex
//
min = max = vertices(0).operator()( axis );
//
// Compare to the rest
//
G4int i;
for( i=0; i<noLeft; i++ ) {
for( i=1; i<noLeft; i++ ) {
G4double component = vertices(i).operator()( axis );
if (component < min )
min = component;
else if (component > max )
max = component;
}
return true;
}
//
// GetMinPoint
//
// Returns pointer to minimum point along the specified axis.
// Take care! Do not use pointer after destroying parent polygon.
//
const G4ThreeVector *G4ClippablePolygon::GetMinPoint( const EAxis axis ) const
{
G4int noLeft = vertices.entries();
if (noLeft==0) G4Exception( "G4ClippablePolygon::GetMinPoint -- empty polygon" );
const G4ThreeVector *answer = &(vertices[0]);
G4double min = answer->operator()(axis);
G4int i;
for( i=1; i<noLeft; i++ ) {
G4double component = vertices(i).operator()( axis );
if (component < min) {
answer = &(vertices[i]);
min = component;
}
}
return answer;
}
//
// GetMaxPoint
//
// Returns pointer to maximum point along the specified axis.
// Take care! Do not use pointer after destroying parent polygon.
//
const G4ThreeVector *G4ClippablePolygon::GetMaxPoint( const EAxis axis ) const
{
G4int noLeft = vertices.entries();
if (noLeft==0) G4Exception( "G4ClippablePolygon::GetMaxPoint -- empty polygon" );
const G4ThreeVector *answer = &(vertices[0]);
G4double max = answer->operator()(axis);
G4int i;
for( i=1; i<noLeft; i++ ) {
G4double component = vertices(i).operator()( axis );
if (component > max) {
answer = &(vertices[i]);
max = component;
}
}
return answer;
}
//
// InFrontOf
//
// Decide if this polygon is in "front" of another when
// viewed along the specified axis. For our purposes here,
// it is sufficient to use the minimum extent of the
// polygon along the axis to determine this.
//
// In case the minima of the two polygons are equal,
// we use a more sophisticated test.
//
// Note that it is possible for the two following
// statements to both return true or both return false:
// polygon1.InFrontOf(polygon2)
// polygon2.BehindOf(polygon1)
//
const G4bool G4ClippablePolygon::InFrontOf( const G4ClippablePolygon &other, EAxis axis ) const
{
//
// If things are empty, do something semi-sensible
//
G4int noLeft = vertices.entries();
if (noLeft==0) return false;
if (other.Empty()) return true;
//
// Get minimum of other polygon
//
const G4ThreeVector *minPointOther = other.GetMinPoint( axis );
const G4double minOther = minPointOther->operator()(axis);
//
// Get minimum of this polygon
//
const G4ThreeVector *minPoint = GetMinPoint( axis );
const G4double min = minPoint->operator()(axis);
//
// Easy decision
//
if (min < minOther-kCarTolerance) return true; // Clear winner
if (minOther < min-kCarTolerance) return false; // Clear loser
//
// We have a tie (this will not be all that rare since our
// polygons are connected)
//
// Check to see if there is a vertex in the other polygon
// that is behind this one (or vice versa)
//
G4bool answer;
G4ThreeVector normalOther = other.GetNormal();
if (fabs(normalOther(axis)) > fabs(normal(axis))) {
G4double minP, maxP;
GetPlanerExtent( *minPointOther, normalOther, minP, maxP );
answer = (normalOther(axis) > 0) ? (minP < -kCarTolerance) : (maxP > +kCarTolerance);
}
else {
G4double minP, maxP;
other.GetPlanerExtent( *minPoint, normal, minP, maxP );
answer = (normal(axis) > 0) ? (maxP > +kCarTolerance) : (minP < -kCarTolerance);
}
return answer;
}
//
// BehindOf
//
// Decide if this polygon is behind another.
// See notes in method "InFrontOf"
//
const G4bool G4ClippablePolygon::BehindOf( const G4ClippablePolygon &other, EAxis axis ) const
{
//
// If things are empty, do something semi-sensible
//
G4int noLeft = vertices.entries();
if (noLeft==0) return false;
if (other.Empty()) return true;
//
// Get minimum of other polygon
//
const G4ThreeVector *maxPointOther = other.GetMaxPoint( axis );
const G4double maxOther = maxPointOther->operator()(axis);
//
// Get minimum of this polygon
//
const G4ThreeVector *maxPoint = GetMaxPoint( axis );
const G4double max = maxPoint->operator()(axis);
//
// Easy decision
//
if (max > maxOther+kCarTolerance) return true; // Clear winner
if (maxOther > max+kCarTolerance) return false; // Clear loser
//
// We have a tie (this will not be all that rare since our
// polygons are connected)
//
// Check to see if there is a vertex in the other polygon
// that is in front of this one (or vice versa)
//
G4bool answer;
G4ThreeVector normalOther = other.GetNormal();
if (fabs(normalOther(axis)) > fabs(normal(axis))) {
G4double minP, maxP;
GetPlanerExtent( *maxPointOther, normalOther, minP, maxP );
answer = (normalOther(axis) > 0) ? (maxP > +kCarTolerance) : (minP < -kCarTolerance);
}
else {
G4double minP, maxP;
other.GetPlanerExtent( *maxPoint, normal, minP, maxP );
answer = (normal(axis) > 0) ? (minP < -kCarTolerance) : (maxP > +kCarTolerance);
}
return answer;
}
//
// GetPlanerExtent
//
// Get min/max distance in or out of a plane
//
const G4bool G4ClippablePolygon::GetPlanerExtent( const G4ThreeVector &pointOnPlane,
const G4ThreeVector &planeNormal,
G4double &min, G4double &max ) const
{
//
// Okay, how many entries do we have?
//
G4int noLeft = vertices.entries();
//
// Return false if nothing is left
//
if (noLeft == 0) return false;
//
// Initialize min and max to our first vertex
//
min = max = planeNormal.dot(vertices(0)-pointOnPlane);
//
// Compare to the rest
//
G4int i;
for( i=1; i<noLeft; i++ ) {
G4double component = planeNormal.dot(vertices(i) - pointOnPlane);
if (component < min )
min = component;
else if (component > max )
max = component;
}
return true;
}
//
// Clip along just one axis, as specified in voxelLimit
//
void G4ClippablePolygon::ClipAlongOneAxis( const G4VoxelLimits &voxelLimit, const EAxis axis )
{
if (!voxelLimit.IsLimited(axis)) return;
G4ThreeVectorList tempPolygon;
//
// Build a "simple" voxelLimit that includes only the min extent
// and apply this to our vertices, producing result in tempPolygon
//
G4VoxelLimits simpleLimit1;
simpleLimit1.AddLimit( axis, voxelLimit.GetMinExtent(axis), kInfinity );
ClipToSimpleLimits( vertices, tempPolygon, simpleLimit1 );
//
// If nothing is left from the above clip, we might as well return now
// (but with an empty vertices)
//
if (tempPolygon.entries() == 0) {
vertices.clear();
return;
}
//
// Now do the same, but using a "simple" limit that includes only the max extent.
// Apply this to out tempPolygon, producing result in vertices.
//
G4VoxelLimits simpleLimit2;
simpleLimit2.AddLimit( axis, -kInfinity, voxelLimit.GetMaxExtent(axis) );
ClipToSimpleLimits( tempPolygon, vertices, simpleLimit2 );
//
// If nothing is left, return now
//
if (vertices.entries() == 0) return;
}
// pVoxelLimits must be only limited along one axis, and either the maximum
// along the axis must be +kInfinity, or the minimum -kInfinity
void G4ClippablePolygon::ClipToSimpleLimits( G4ThreeVectorList& pPolygon,
+226 -210
View File
@@ -5,17 +5,20 @@
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4Cons.cc,v 2.3 1998/10/09 17:17:19 grichine Exp $
// GEANT4 tag $Name: geant4-00 $
// $Id: G4Cons.cc,v 1.4 1999/04/29 09:46:34 grichine Exp $
// GEANT4 tag $Name: geant4-00-01 $
//
// class G4Cons
//
// Implementation for G4Cons class
//
// History:
// ~1994 P. Kent: main part of geometry functions
// 13.9.96 V. Grichine: final modifications to commit
//
// 28.04.99 V. Grichine bugs fixed in Distance ToOut(p,v,...) and
// Distance ToIn(p,v)
// 09.10.98 V. Grichine modifications in Distance ToOut(p,v,...)
// 13.09.96 V. Grichine: final modifications to commit
// ~1994 P. Kent: main part of geometry functions
#include "G4Cons.hh"
@@ -308,8 +311,8 @@ G4bool G4Cons::CalculateExtent(const EAxis pAxis,
zMax=zoffset+fDz;
if (pVoxelLimit.IsZLimited())
{
if (zMin > pVoxelLimit.GetMaxZExtent()
|| zMax < pVoxelLimit.GetMinZExtent())
if (zMin > pVoxelLimit.GetMaxZExtent()+kCarTolerance
|| zMax < pVoxelLimit.GetMinZExtent()-kCarTolerance)
{
return false;
}
@@ -332,8 +335,8 @@ G4bool G4Cons::CalculateExtent(const EAxis pAxis,
xMin = 2*xoffset-xMax ;
if (pVoxelLimit.IsXLimited())
{
if (xMin > pVoxelLimit.GetMaxXExtent()
|| xMax < pVoxelLimit.GetMinXExtent())
if (xMin > pVoxelLimit.GetMaxXExtent()+kCarTolerance
|| xMax < pVoxelLimit.GetMinXExtent()-kCarTolerance)
{
return false;
}
@@ -356,8 +359,8 @@ G4bool G4Cons::CalculateExtent(const EAxis pAxis,
RMax = yMax - yoffset ; // is equal to max radius due to Zmax/Zmin cuttings
if (pVoxelLimit.IsYLimited())
{
if (yMin > pVoxelLimit.GetMaxYExtent()
|| yMax < pVoxelLimit.GetMinYExtent())
if (yMin > pVoxelLimit.GetMaxYExtent()+kCarTolerance
|| yMax < pVoxelLimit.GetMinYExtent()-kCarTolerance)
{
return false;
}
@@ -619,8 +622,8 @@ G4ThreeVector G4Cons::SurfaceNormal( const G4ThreeVector& p) const
return norm;
}
// ---------------------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////
//
// Calculate distance to shape from outside, along normalised vector
// - return kInfinity if no intersection, or intersection distance <= tolerance
//
@@ -720,61 +723,65 @@ G4double G4Cons::DistanceToIn(const G4ThreeVector& p,
tolIDz=fDz-kCarTolerance/2;
tolODz=fDz+kCarTolerance/2;
if (fabs(p.z())>=tolIDz)
{
if (p.z()*v.z()<0) // at +Z going in -Z or visa versa
{
s=(fabs(p.z())-fDz)/fabs(v.z()); // Z intersect distance
xi=p.x()+s*v.x(); // Intersection coords
yi=p.y()+s*v.y();
rho2=xi*xi+yi*yi;
// Check validity of intersection
{
if (p.z()*v.z()<0) // at +Z going in -Z or visa versa
{
s=(fabs(p.z())-fDz)/fabs(v.z()); // Z intersect distance
// Calculate (outer) tolerant radi^2 at intersecion
if (v.z()>0)
{
tolORMin=fRmin1-kRadTolerance;
tolORMax2=(fRmax1+kRadTolerance)*(fRmax1+kRadTolerance);
}
else
{
tolORMin=fRmin2-kRadTolerance;
tolORMax2=(fRmax2+kRadTolerance)*(fRmax2+kRadTolerance);
}
if (tolORMin>0)
{
if(s<0.0) s = 0.0 ; // negative dist -> zero
xi=p.x()+s*v.x(); // Intersection coords
yi=p.y()+s*v.y();
rho2=xi*xi+yi*yi;
// Check validity of intersection
//
// Calculate (outer) tolerant radi^2 at intersecion
if (v.z()>0)
{
tolORMin=fRmin1-kRadTolerance;
tolORMax2=(fRmax1+kRadTolerance)*(fRmax1+kRadTolerance);
}
else
{
tolORMin=fRmin2-kRadTolerance;
tolORMax2=(fRmax2+kRadTolerance)*(fRmax2+kRadTolerance);
}
if ( tolORMin > 0 )
{
tolORMin2=tolORMin*tolORMin;
}
else
{
tolORMin2=0;
}
if (tolORMin2<=rho2&&rho2<=tolORMax2)
{
if (seg&&rho2)
{
}
else
{
tolORMin2=0;
}
if (tolORMin2 <= rho2 && rho2 <= tolORMax2)
{
if (seg&&rho2)
{
// Psi = angle made with central (average) phi of shape
cosPsi=(xi*cosCPhi+yi*sinCPhi)/sqrt(rho2);
if (cosPsi>=cosHDPhiOT)
{
return s;
}
}
else
{
return s;
}
}
}
else
cosPsi=(xi*cosCPhi+yi*sinCPhi)/sqrt(rho2);
if (cosPsi >= cosHDPhiOT)
{
return snxt; // On/outside extent, and heading away
// -> cannot intersect
return s ;
}
}
// -> Can not intersect z surfaces
}
else
{
return s ;
}
}
}
else // On/outside extent, and heading away -> cannot intersect
{
return snxt ;
}
}
//
// -> Can not intersect z surfaces
@@ -943,7 +950,7 @@ G4double G4Cons::DistanceToIn(const G4ThreeVector& p,
}
else // travel || cone surface from its origin
{
return kInfinity ;
s = kInfinity ;
}
}
@@ -1249,7 +1256,7 @@ G4double G4Cons::DistanceToIn(const G4ThreeVector& p,
return snxt;
}
// -------------------------------------------------------------------------------------------
/* ****************************************************************************************
@@ -1705,8 +1712,8 @@ G4double G4Cons::DistanceToIn(const G4ThreeVector& p) const
return safe;
}
// -----------------------------------------------------------------------------------
///////////////////////////////////////////////////////////////
//
// Calculate distance to surface of shape from `inside', allowing for tolerance
// - Only Calc rmax intersection if no valid rmin intersection
@@ -1737,55 +1744,54 @@ G4double G4Cons::DistanceToOut(const G4ThreeVector& p,
// Z plane intersection
//
if (v.z()>0)
{
pdist=fDz-p.z();
if (pdist>kCarTolerance/2)
{
snxt=pdist/v.z();
side=kPZ;
}
else
{
if (calcNorm)
{
*n=G4ThreeVector(0,0,1);
*validNorm=true;
}
return snxt=0;
}
}
{
pdist=fDz-p.z();
if (pdist > kCarTolerance*0.5)
{
snxt=pdist/v.z();
side=kPZ;
}
else
{
if (calcNorm)
{
*n=G4ThreeVector(0,0,1);
*validNorm=true;
}
return snxt=0;
}
}
else if (v.z()<0)
{
pdist=fDz+p.z();
if (pdist>kCarTolerance/2)
{
snxt=-pdist/v.z();
side=kMZ;
}
else
{
if (calcNorm)
{
*n=G4ThreeVector(0,0,-1);
*validNorm=true;
}
return snxt=0;
}
}
{
pdist=fDz+p.z();
if (pdist > kCarTolerance*0.5)
{
snxt=-pdist/v.z();
side=kMZ;
}
else
{
if (calcNorm)
{
*n=G4ThreeVector(0,0,-1);
*validNorm=true;
}
return snxt=0;
}
}
else
{
snxt=kInfinity; // Travel perpendicular to z axis
side=kNull;
}
{
snxt=kInfinity; // Travel perpendicular to z axis
side=kNull;
}
//
// Radial Intersections
//
//
// Intersection with outer cone (possible return) and
// inner cone (must also check phi)
//
// Intersection point (xi,yi,zi) on line x=p.x+t*v.x etc.
//
// Intersects with x^2+y^2=(a*z+b)^2
@@ -1812,138 +1818,146 @@ G4double G4Cons::DistanceToOut(const G4ThreeVector& p,
nt2=t2-tanRMax*v.z()*rout;
nt3=t3-rout*rout;
if (nt1)
{
{
//
// Equation quadratic => 2 roots : second root must be leaving
//
b=nt2/nt1;
c=nt3/nt1;
d=b*b-c;
if (d>=0)
{
b=nt2/nt1;
c=nt3/nt1;
d=b*b-c;
if ( d >= 0 )
{
// Check if on outer cone & heading outwards
// NOTE: Should use rho-rout>-kRadtolerance/2
if (nt3>-kRadTolerance/2&&nt2>=0)
{
if (calcNorm)
{
risec=sqrt(t3)*secRMax;
*validNorm=true;
*n=G4ThreeVector(p.x()/risec,p.y()/risec,-tanRMax/secRMax);
}
return snxt=0;
}
else
{
// NOTE: Should use rho-rout>-kRadtolerance/2
if (nt3 > -kRadTolerance*0.5 && nt2 >= 0 )
{
if (calcNorm)
{
risec=sqrt(t3)*secRMax;
*validNorm=true;
*n=G4ThreeVector(p.x()/risec,p.y()/risec,-tanRMax/secRMax);
}
return snxt=0;
}
else
{
// // -*-* ORIG ROOT CODE
// sr=-b+sqrt(d);
// sider=kRMax;
// // -*-* ORIG ROOT CODE
// Patch 4.4.95 - root above cross-over point
sider=kRMax;
sr=-b+sqrt(d);
zi=p.z()+sr*v.z();
ri=tanRMax*zi+rMaxAv;
if( (ri>=0)
&& (-kRadTolerance/2 <= sr)
&& ( sr <= kRadTolerance/2) )
{
// An intersection within the tolerance
// we will Store it in case it is good -
//
slentol = sr;
sidetol= kRMax;
}
if ( (ri<0)
|| (sr<kRadTolerance/2) )
{
sr2=-b+sqrt(d);
// Safety: if both roots -ve ensure that sr cannot `win' distancetoout
zi=p.z()+sr2*v.z();
ri=tanRMax*zi+rMaxAv;
if (ri>=0&&sr2>kRadTolerance/2)
{
sr=sr2;
}
else
{
sr=kInfinity;
if( (-kRadTolerance/2 <= sr2)
&&( sr2 <= kRadTolerance/2) )
{
// An intersection within the
// tolerance. Storing it
// in case it is good.
slentol = sr2;
sidetol= kRMax;
}
}
}
}
}
else
sider=kRMax ;
sr=-b - sqrt(d); // was +srqrt(d), vmg 28.04.99
zi=p.z()+sr*v.z();
ri=tanRMax*zi+rMaxAv;
if ( (ri >= 0)
&& (-kRadTolerance/2 <= sr)
&& ( sr <= kRadTolerance/2) )
{
// An intersection within the tolerance
// we will Store it in case it is good -
//
slentol = sr;
sidetol= kRMax;
}
if ( (ri < 0) || (sr < kRadTolerance/2) )
{
// Safety: if both roots -ve ensure that sr cannot `win' distancetoout
sr2=-b+sqrt(d);
zi=p.z()+sr2*v.z();
ri=tanRMax*zi+rMaxAv;
if (ri>=0&&sr2>kRadTolerance/2)
{
sr=sr2;
}
else
{
sr = kInfinity ;
if( (-kRadTolerance/2 <= sr2)
&& ( sr2 <= kRadTolerance/2) )
{
// An intersection within the tolerance. Storing it in case it is good.
slentol = sr2;
sidetol= kRMax;
}
}
}
}
}
else
{
// No intersection with outer cone & not parallel -> already outside, no
// intersection
if (calcNorm)
{
risec=sqrt(t3)*secRMax;
*validNorm=true;
*n=G4ThreeVector(p.x()/risec,p.y()/risec,-tanRMax/secRMax);
}
return snxt=0;
}
}
if (calcNorm)
{
risec=sqrt(t3)*secRMax;
*validNorm=true;
*n=G4ThreeVector(p.x()/risec,p.y()/risec,-tanRMax/secRMax);
}
return snxt=0;
}
}
else if (nt2)
{
{
//
// Linear case (only one intersection) => point outside outer cone
//
if (calcNorm)
{
risec=sqrt(t3)*secRMax;
*validNorm=true;
*n=G4ThreeVector(p.x()/risec,p.y()/risec,-tanRMax/secRMax);
}
return snxt=0;
}
if (calcNorm)
{
risec=sqrt(t3)*secRMax;
*validNorm=true;
*n=G4ThreeVector(p.x()/risec,p.y()/risec,-tanRMax/secRMax);
}
return snxt=0;
}
else
{
{
// No intersection -> parallel to outer cone => Z or inner cone intersection
sr=kInfinity;
}
sr=kInfinity;
}
// Check possible intersection within tolerance
if( slentol <= kCarTolerance/2 )
if ( slentol <= kCarTolerance/2 )
{
// An intersection within the tolerance was found.
// We must accept it only if the momentum points outwards.
//
// An intersection within the tolerance was found.
// We must accept it only if the momentum points outwards.
//
// G4ThreeVector ptTol; // The point of the intersection
// ptTol= p + slentol*v;
// ri=tanRMax*zi+rMaxAv;
//
// Calculate a normal vector, as below
// G4ThreeVector ptTol; // The point of the intersection
// ptTol= p + slentol*v;
// ri=tanRMax*zi+rMaxAv;
xi=p.x()+slentol*v.x();
yi=p.y()+slentol*v.y();
risec=sqrt(xi*xi+yi*yi)*secRMax;
G4ThreeVector Normal=G4ThreeVector(xi/risec,yi/risec,-tanRMax/secRMax);
// Calculate a normal vector, as below
xi=p.x()+slentol*v.x();
yi=p.y()+slentol*v.y();
risec=sqrt(xi*xi+yi*yi)*secRMax;
G4ThreeVector Normal=G4ThreeVector(xi/risec,yi/risec,-tanRMax/secRMax);
if( Normal.dot(v) > 0 )
{
if ( Normal.dot(v) > 0 )
{
// We will leave the Cone immediatelly
if(calcNorm)
{
*n= Normal.unit();
*validNorm=true;
}
if ( calcNorm )
{
*n= Normal.unit();
*validNorm=true;
}
return snxt = 0.0;
}
else
else
{
// On the surface, but not heading out
// so we ignore this intersection (as it is within tolerance).
@@ -2651,3 +2665,5 @@ G4NURBS* G4Cons::CreateNURBS () const
}
// ******************************* End of G4Cons.cc file **********************************
@@ -3,27 +3,31 @@
//
// Implementation of a utility class for a quick check of geometry
//
// ----------------------------------------------------------
// This code implementation is the intellectual property of
// the GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
#include "G4EnclosingCylinder.hh"
#include "G4ReduciblePolygon.hh"
//
// Constructor
//
G4EnclosingCylinder::G4EnclosingCylinder( const G4double r[], const G4double z[], const G4int n,
G4EnclosingCylinder::G4EnclosingCylinder( const G4ReduciblePolygon *rz,
const G4bool thePhiIsOpen,
const G4double theStartPhi, const G4double theTotalPhi )
{
//
// Obtain larges r and smallest and larges z
// Obtain largest r and smallest and largest z
//
radius = r[0];
zLo = zHi = z[0];
const G4double *rr = r, *zz = z;
while( ++zz, ++rr < r+n ) {
if (*rr > radius) radius = *rr;
if (*zz > zHi ) zHi = *zz;
if (*zz < zLo ) zLo = *zz;
}
radius = rz->Amax();
zHi = rz->Bmax();
zLo = rz->Bmin();
//
// Save phi info
@@ -41,6 +45,8 @@ G4EnclosingCylinder::G4EnclosingCylinder( const G4double r[], const G4double z[]
ry2 = sin(startPhi+totalPhi);
dx2 = -ry2*10*kCarTolerance;
dy2 = +rx2*10*kCarTolerance;
concave = totalPhi > M_PI;
}
//
@@ -64,16 +70,21 @@ G4EnclosingCylinder::~G4EnclosingCylinder() {;}
//
// If one is not certain, return false
//
G4bool G4EnclosingCylinder::Outside( const G4ThreeVector &p ) const
G4bool G4EnclosingCylinder::MustBeOutside( const G4ThreeVector &p ) const
{
if (p.perp() > radius) return true;
if (p.z() < zLo) return true;
if (p.z() > zHi) return true;
if (phiIsOpen) {
if ( ((p.x()-dx1)*ry1 - (p.y()-dy1)*rx1) > 0) return false;
if ( ((p.x()-dx2)*ry2 - (p.y()-dy2)*rx2) < 0) return false;
return true;
if (concave) {
if ( ((p.x()-dx1)*ry1 - (p.y()-dy1)*rx1) < 0) return false;
if ( ((p.x()-dx2)*ry2 - (p.y()-dy2)*rx2) > 0) return false;
}
else {
if ( ((p.x()-dx1)*ry1 - (p.y()-dy1)*rx1) > 0) return true;
if ( ((p.x()-dx2)*ry2 - (p.y()-dy2)*rx2) < 0) return true;
}
}
return false;
@@ -87,9 +98,9 @@ G4bool G4EnclosingCylinder::Outside( const G4ThreeVector &p ) const
//
// If one is not sure, return false
//
G4bool G4EnclosingCylinder::Misses( const G4ThreeVector &p, const G4ThreeVector &v ) const
G4bool G4EnclosingCylinder::ShouldMiss( const G4ThreeVector &p, const G4ThreeVector &v ) const
{
if (!Outside(p)) return false;
if (!MustBeOutside(p)) return false;
G4double cross = p.x()*v.y() - p.y()*v.x();
if (cross > radius) return true;
+8 -8
View File
@@ -5,8 +5,8 @@
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4Hype.cc,v 2.2 1998/07/13 16:52:46 urbi Exp $
// GEANT4 tag $Name: geant4-00 $
// $Id: G4Hype.cc,v 1.2 1999/04/16 09:29:54 grichine Exp $
// GEANT4 tag $Name: geant4-00-01 $
//
// class G4Hype: this class implements in G4 the volume equivalent
// to the HYPE volume in Geant 3, i.e. a tube with
@@ -137,8 +137,8 @@ G4bool G4Hype::CalculateExtent(const EAxis pAxis,
//G4cout << "xMin, xMax : " << xMin << " " << xMax << endl;
if (pVoxelLimit.IsXLimited())
{
if (xMin>pVoxelLimit.GetMaxXExtent() ||
xMax<pVoxelLimit.GetMinXExtent())
if (xMin>pVoxelLimit.GetMaxXExtent()+kCarTolerance ||
xMax<pVoxelLimit.GetMinXExtent()-kCarTolerance)
{
return false;
}
@@ -162,8 +162,8 @@ G4bool G4Hype::CalculateExtent(const EAxis pAxis,
yMax=yoffset+endOuterRadius;
if (pVoxelLimit.IsYLimited())
{
if (yMin>pVoxelLimit.GetMaxYExtent()
||yMax<pVoxelLimit.GetMinYExtent())
if (yMin>pVoxelLimit.GetMaxYExtent()+kCarTolerance
||yMax<pVoxelLimit.GetMinYExtent()-kCarTolerance)
{
return false;
}
@@ -186,8 +186,8 @@ G4bool G4Hype::CalculateExtent(const EAxis pAxis,
zMax=zoffset+halfLenZ;
if (pVoxelLimit.IsZLimited())
{
if (zMin>pVoxelLimit.GetMaxZExtent()
||zMax<pVoxelLimit.GetMinZExtent())
if (zMin>pVoxelLimit.GetMaxZExtent()+kCarTolerance
||zMax<pVoxelLimit.GetMinZExtent()-kCarTolerance)
{
return false;
}
@@ -4,6 +4,14 @@
// Implementation of a utility class which calculates the intersection
// of an arbitrary line with a fixed cone
//
// ----------------------------------------------------------
// This code implementation is the intellectual property of
// the GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
#include "G4IntersectingCone.hh"
//
@@ -168,7 +176,7 @@ G4int G4IntersectingCone::LineHitsCone1( const G4ThreeVector &p, const G4ThreeVe
//
// The radical is roughly zero: check for special, very rare, cases
//
if ( (fabs(x0*tx + y0*ty) < fabs(1E-6/B)) && (a < 1/kInfinity) ) {
if ( (fabs(x0*tx + y0*ty) < fabs(1E-6/B)) && (a < -1/kInfinity) ) {
*s1 = -0.5*b/a;
return 1;
}
@@ -255,7 +263,7 @@ G4int G4IntersectingCone::LineHitsCone2( const G4ThreeVector &p, const G4ThreeVe
//
// The radical is roughly zero: check for special, very rare, cases
//
if ( (fabs(x0*tx + y0*ty) < fabs(1E-6*B)) && (a < 1/kInfinity) ) {
if ( (fabs(x0*tx + y0*ty) < fabs(1E-6*B)) && (a < -1/kInfinity) ) {
*s1 = -0.5*b/a;
return 1;
}
+8 -8
View File
@@ -5,8 +5,8 @@
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4Para.cc,v 2.1 1998/07/12 02:56:56 urbi Exp $
// GEANT4 tag $Name: geant4-00 $
// $Id: G4Para.cc,v 1.2 1999/04/16 09:29:54 grichine Exp $
// GEANT4 tag $Name: geant4-00-01 $
//
// class G4Para
//
@@ -175,8 +175,8 @@ G4bool G4Para::CalculateExtent(const EAxis pAxis,
zMax=zoffset+fDz;
if (pVoxelLimit.IsZLimited())
{
if (zMin>pVoxelLimit.GetMaxZExtent()
||zMax<pVoxelLimit.GetMinZExtent())
if (zMin>pVoxelLimit.GetMaxZExtent()+kCarTolerance
||zMax<pVoxelLimit.GetMinZExtent()-kCarTolerance)
{
return false;
}
@@ -207,8 +207,8 @@ G4bool G4Para::CalculateExtent(const EAxis pAxis,
if (pVoxelLimit.IsYLimited())
{
if (yMin>pVoxelLimit.GetMaxYExtent()
||yMax<pVoxelLimit.GetMinYExtent())
if (yMin>pVoxelLimit.GetMaxYExtent()+kCarTolerance
||yMax<pVoxelLimit.GetMinYExtent()-kCarTolerance)
{
return false;
}
@@ -244,8 +244,8 @@ G4bool G4Para::CalculateExtent(const EAxis pAxis,
// xMax/Min = f(yMax/Min) ?
if (pVoxelLimit.IsXLimited())
{
if (xMin>pVoxelLimit.GetMaxXExtent()
||xMax<pVoxelLimit.GetMinXExtent())
if (xMin>pVoxelLimit.GetMaxXExtent()+kCarTolerance
||xMax<pVoxelLimit.GetMinXExtent()-kCarTolerance)
{
return false;
}
+360 -88
View File
@@ -4,10 +4,20 @@
// Implementation of the face that bounds a polycone or polyhedra at
// its phi opening.
//
// ----------------------------------------------------------
// This code implementation is the intellectual property of
// the GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
#include "G4PolyPhiFace.hh"
#include "G4ClippablePolygon.hh"
#include "G4ReduciblePolygon.hh"
#include "G4AffineTransform.hh"
#include "G4SolidExtentList.hh"
//
// Constructor
@@ -19,10 +29,21 @@
// | | +--> z
// [0]---------[3]
//
G4PolyPhiFace::G4PolyPhiFace( const G4double *r, const G4double *z,
const G4int n, const G4double phi,
const G4double deltaPhi, const G4bool start )
G4PolyPhiFace::G4PolyPhiFace( const G4ReduciblePolygon *rz, const G4double phi,
const G4double deltaPhi, const G4double phiOther )
{
numEdges = rz->NumVertices();
rMin = rz->Amin();
rMax = rz->Amax();
zMin = rz->Bmin();
zMax = rz->Bmax();
//
// Is this the "starting" phi edge of the two?
//
G4bool start = (phiOther > phi);
//
// Build radial vector
//
@@ -33,41 +54,37 @@ G4PolyPhiFace::G4PolyPhiFace( const G4double *r, const G4double *z,
//
G4double zSign = start ? 1 : -1;
normal = G4ThreeVector( zSign*radial.y(), -zSign*radial.x(), 0 );
//
// Is allBehind?
//
allBehind = (zSign*(cos(phiOther)*radial.y() - sin(phiOther)*radial.x()) < 0);
//
// Adjacent edges
//
G4double midPhi = phi + (start ? +0.5 : -0.5)*deltaPhi;
G4double cosMid = cos(midPhi),
sinMid = sin(midPhi);
//
// Allocate corners
//
corners = new G4PolyPhiFaceVertex[n];
corners = new G4PolyPhiFaceVertex[numEdges];
//
// Fill their positions, avoiding duplicates
// Fill them
//
rMin = kInfinity; rMax = -kInfinity;
zMin = kInfinity; zMax = -kInfinity;
const G4double *rOne = r, *zOne = z,
*rNext, *zNext;
G4PolyPhiFaceVertex *corn = corners;
do {
rNext = rOne + 1;
zNext = zOne + 1;
if (rNext == r+n) {rNext = r; zNext = z;}
if (*rNext == *rOne && *zNext == *zOne) continue;
corn->r = *rOne;
corn->z = *zOne;
corn++;
if (*rOne < rMin) rMin = *rOne;
if (*rOne > rMax) rMax = *rOne;
if (*zOne < zMin) zMin = *zOne;
if (*zOne > zMax) zMax = *zOne;
} while( rOne=rNext, zOne=zNext, rOne != r );
numEdges = corn-corners;
G4ReduciblePolygonIterator iterRZ(rz);
G4PolyPhiFaceVertex *corn = corners;
iterRZ.Begin();
do {
corn->r = iterRZ.GetA();
corn->z = iterRZ.GetB();
corn->x = corn->r*radial.x();
corn->y = corn->r*radial.y();
} while( ++corn, iterRZ.Next() );
//
// Allocate edges
@@ -77,17 +94,16 @@ G4PolyPhiFace::G4PolyPhiFace( const G4double *r, const G4double *z,
//
// Fill them
//
G4double midPhi = phi + (start ? +0.5 : -0.5)*deltaPhi;
G4double cosMid = cos(midPhi),
sinMid = sin(midPhi);
G4double rFact = cos(0.5*deltaPhi);
G4ThreeVector sideNorm;
G4double rFactNormalize = 1.0/sqrt(1.0+rFact*rFact);
G4PolyPhiFaceVertex *prev = corners+numEdges-1,
*here = corners;
G4PolyPhiFaceEdge *edge = edges;
do {
edge->v0 = prev;
G4ThreeVector sideNorm;
edge->v0 = prev;
edge->v1 = here;
G4double dr = here->r - prev->r,
@@ -98,44 +114,84 @@ G4PolyPhiFace::G4PolyPhiFace( const G4double *r, const G4double *z,
edge->tr = dr/edge->length;
edge->tz = dz/edge->length;
sideNorm = G4ThreeVector( dz*rFact*cosMid, dz*rFact*sinMid, -dr );
sideNorm = sideNorm.unit();
if ((here->r < DBL_MIN) && (prev->r < DBL_MIN)) {
//
// Sigh! Always exceptions!
// This edge runs at r==0, so its adjoing surface is not a
// PolyconeSide or PolyhedraSide, but the opposite PolyPhiFace.
//
G4double zSignOther = start ? -1 : 1;
sideNorm = G4ThreeVector( zSignOther*sin(phiOther),
-zSignOther*cos(phiOther), 0 );
}
else {
sideNorm = G4ThreeVector( edge->tz*cosMid, edge->tz*sinMid, -edge->tr*rFact );
sideNorm *= rFactNormalize;
}
sideNorm += normal;
edge->norm3D = sideNorm.unit();
} while( edge++, prev=here, ++here < corners+numEdges );
//
// Go back an fill in corner "normals", which are just the
// average of the normals of the ajoining edges
// Go back and fill in corner "normals"
//
G4PolyPhiFaceEdge *prevEdge = edges+numEdges-1;
edge = edges;
do {
//
// Calculate vertex 2D normals (on the phi surface)
//
G4double rPart = prevEdge->tr + edge->tr;
G4double zPart = prevEdge->tz + edge->tz;
G4double norm = sqrt( rPart*rPart + zPart*zPart );
edge->v0->rNorm = +zPart/norm;
edge->v0->zNorm = -rPart/norm;
G4double rNorm = +zPart/norm;
G4double zNorm = -rPart/norm;
edge->v0->rNorm = rNorm;
edge->v0->zNorm = zNorm;
//
// Corner normal should be average of normals of connecting edges,
// or, equivalently, the average of all connecting faces.
// Calculate the 3D normals.
//
// prevEdge->norm3D = normal + side1.normal = A
// edge->norm3D = normal + side2.normal = B
// A + B - normal = normal + side1.normal + side2.normal
// Find the vector perpendicular to the z axis
// that defines the plane that contains the vertex normal
//
G4ThreeVector xyVector;
G4ThreeVector norm3D = prevEdge->norm3D + edge->norm3D - normal;
edge->v0->norm3D = norm3D.unit();
if (edge->v0->r < DBL_MIN) {
//
// This is a vertex at r==0, which is a special
// case. The normal we will construct lays in the
// plane at the center of the phi opening.
//
// We also know that rNorm < 0
//
G4double zSignOther = start ? -1 : 1;
G4ThreeVector normalOther( zSignOther*sin(phiOther),
-zSignOther*cos(phiOther), 0 );
xyVector = - normal - normalOther;
}
else {
//
// This is a vertex at r > 0. The plane
// is the average of the normal and the
// normal of the adjacent phi face
//
xyVector = G4ThreeVector( cosMid, sinMid, 0 );
if (rNorm < 0)
xyVector -= normal;
else
xyVector += normal;
}
//
// Combine it with the r/z direction from the face
//
edge->v0->norm3D = rNorm*xyVector.unit() + G4ThreeVector( 0, 0, zNorm );
} while( prevEdge=edge, ++edge < edges+numEdges );
//
// Complain if something is obviously wrong
//
if (numEdges <= 2)
G4Exception( "G4PolyPhiFace: more than two unique corners must be specified" );
//
// Build point on surface
//
@@ -145,12 +201,104 @@ G4PolyPhiFace::G4PolyPhiFace( const G4double *r, const G4double *z,
}
//
// Diagnose
//
// Throw an exception if something is found inconsistent with
// the solid.
//
// For debugging purposes only
//
void G4PolyPhiFace::Diagnose( G4VSolid *owner )
{
G4PolyPhiFaceVertex *corner = corners;
do {
G4ThreeVector test(corner->x, corner->y, corner->z);
test -= 1E-6*corner->norm3D;
if (owner->Inside(test) != kInside)
G4Exception( "G4PolyPhiFace::Diagnose -- Bad vertex normal found" );
} while( ++corner < corners+numEdges );
}
//
// Destructor
//
G4PolyPhiFace::~G4PolyPhiFace()
{
delete [] edges;
delete [] corners;
}
//
// Copy constructor
//
G4PolyPhiFace::G4PolyPhiFace( const G4PolyPhiFace &source )
{
CopyStuff( source );
}
//
// Assignment operator
//
G4PolyPhiFace *G4PolyPhiFace::operator=( const G4PolyPhiFace &source )
{
if (this == &source) return this;
delete [] edges;
delete [] corners;
CopyStuff( source );
return this;
}
//
// CopyStuff (protected)
//
void G4PolyPhiFace::CopyStuff( const G4PolyPhiFace &source )
{
//
// The simple stuff
//
numEdges = source.numEdges;
normal = source.normal;
radial = source.radial;
surface = source.surface;
rMin = source.rMin;
rMax = source.rMax;
zMin = source.zMin;
zMax = source.zMax;
allBehind = source.allBehind;
//
// Corner dynamic array
//
corners = new G4PolyPhiFaceVertex[numEdges];
G4PolyPhiFaceVertex *corn = corners,
*sourceCorn = source.corners;
do {
*corn = *sourceCorn;
} while( ++sourceCorn, ++corn < corners+numEdges );
//
// Edge dynamic array
//
edges = new G4PolyPhiFaceEdge[numEdges];
G4PolyPhiFaceVertex *prev = corners+numEdges-1,
*here = corners;
G4PolyPhiFaceEdge *edge = edges,
*sourceEdge = source.edges;
do {
*edge = *sourceEdge;
edge->v0 = prev;
edge->v1 = here;
} while( ++sourceEdge, ++edge, prev=here, ++here < corners+numEdges );
}
@@ -160,14 +308,14 @@ G4PolyPhiFace::~G4PolyPhiFace()
G4bool G4PolyPhiFace::Intersect( const G4ThreeVector &p, const G4ThreeVector &v,
const G4bool outgoing, const G4double surfTolerance,
G4double &distance, G4double &distFromSurface,
G4ThreeVector &aNormal, G4bool &allBehind )
G4ThreeVector &aNormal, G4bool &isAllBehind )
{
G4double normSign = outgoing ? +1 : -1;
//
// These don't change
//
allBehind = true;
isAllBehind = allBehind;
aNormal = normal;
//
@@ -185,7 +333,7 @@ G4bool G4PolyPhiFace::Intersect( const G4ThreeVector &p, const G4ThreeVector &v,
G4ThreeVector ps = p - surface;
distFromSurface = -normSign*ps.dot(normal);
if (distFromSurface < surfTolerance) return false;
if (distFromSurface < -surfTolerance) return false;
//
// Calculate precise distance to intersection with the side
@@ -203,7 +351,7 @@ G4bool G4PolyPhiFace::Intersect( const G4ThreeVector &p, const G4ThreeVector &v,
//
// And is it inside the r/z extent?
//
return InsideEdges( r, ip.z() );
return InsideEdgesExact( r, ip.z(), normSign, p, v );
}
@@ -219,7 +367,10 @@ G4double G4PolyPhiFace::Distance( const G4ThreeVector &p, const G4bool outgoing
G4ThreeVector ps = p - surface;
G4double distPhi = -normSign*normal.dot(ps);
if (distPhi <= 0) return kInfinity;
if (distPhi < -0.5*kCarTolerance)
return kInfinity;
else if (distPhi < 0)
distPhi = 0.0;
//
// Calculate projected point in r,z
@@ -270,30 +421,15 @@ EInside G4PolyPhiFace::Inside( const G4ThreeVector &p, const G4double tolerance,
G4double distRZ2;
G4PolyPhiFaceVertex *base3Dnorm;
G4ThreeVector *head3Dnorm;
G4bool wereIn = InsideEdges( r, p.z(), &distRZ2, &base3Dnorm, &head3Dnorm );
if (wereIn) {
if (InsideEdges( r, p.z(), &distRZ2, &base3Dnorm, &head3Dnorm )) {
//
// Looks like we're inside. Distance is distance in phi.
//
*bestDistance = fabs(distPhi);
}
else {
//
// We're outside the extent of the face,
// so the distance is penalized by distance from edges in RZ
//
*bestDistance = sqrt( distPhi*distPhi + distRZ2 );
}
//
// Can we be on the surface? Yes, but only if we're inside, or
// close to inside by tolerance
//
if (wereIn || distRZ2 < tolerance*tolerance ) {
//
// Yup, answer depends on distPhi, and we can use tolerance
// to decide if we are on the surface
// Use distPhi to decide fate
//
if (distPhi < -tolerance) return kInside;
if (distPhi < tolerance) return kSurface;
@@ -301,14 +437,29 @@ EInside G4PolyPhiFace::Inside( const G4ThreeVector &p, const G4double tolerance,
}
else {
//
// Nope. we can only be in or out, and we must
// used the edge normal to decide
// We're outside the extent of the face,
// so the distance is penalized by distance from edges in RZ
//
*bestDistance = sqrt( distPhi*distPhi + distRZ2 );
//
// Use edge normal to decide fate
//
G4ThreeVector cc( base3Dnorm->r*radial.x(),
base3Dnorm->r*radial.y(),
base3Dnorm->z );
cc = p - cc;
return head3Dnorm->dot(cc) < 0 ? kInside : kOutside;
G4double normDist = head3Dnorm->dot(cc);
if ( distRZ2 > tolerance*tolerance ) {
//
// We're far enough away that kSurface is not possible
//
return normDist < 0 ? kInside : kOutside;
}
if (normDist < -tolerance) return kInside;
if (normDist < tolerance) return kSurface;
return kOutside;
}
}
@@ -382,7 +533,7 @@ G4double G4PolyPhiFace::Extent( const G4ThreeVector axis )
void G4PolyPhiFace::CalculateExtent( const EAxis axis,
const G4VoxelLimits &voxelLimit,
const G4AffineTransform &transform,
G4double &min, G4double &max )
G4SolidExtentList &extentList )
{
//
// Construct a (sometimes big) clippable polygon,
@@ -402,18 +553,139 @@ void G4PolyPhiFace::CalculateExtent( const EAxis axis,
//
// Clip away
//
polygon.Clip( voxelLimit );
//
// Get extent
//
polygon.GetExtent( axis, min, max );
if (polygon.PartialClip( voxelLimit, axis )) {
//
// Add it to the list
//
polygon.SetNormal( transform.TransformAxis(normal) );
extentList.AddSurface( polygon );
}
}
//
//-------------------------------------------------------
//
// InsideEdgesExact
//
// Decide if the point in r,z is inside the edges of our face,
// **but** do so consistently with other faces.
//
// This routine has functionality similar to InsideEdges, but uses
// an algorithm to decide if a trajectory falls inside or outside the
// face that uses only the trajectory p,v values and the three dimensional
// points representing the edges of the polygon. The objective is to plug up
// any leaks between touching G4PolyPhiFaces (at r==0) and any other face
// that uses the same convention.
//
// See: "Computational Geometry in C (Second Edition)"
// http://cs.smith.edu/~orourke/
//
G4bool G4PolyPhiFace::InsideEdgesExact( const G4double r, const G4double z,
const G4double normSign, const G4ThreeVector &p, const G4ThreeVector &v )
{
//
// Quick check of extent
//
if ( r < rMin-kCarTolerance ||
r > rMax+kCarTolerance ) return false;
if ( z < zMin-kCarTolerance ||
z > zMax+kCarTolerance ) return false;
//
// Exact check: loop over all vertices
//
G4double qx = p.x() + v.x(),
qy = p.y() + v.y(),
qz = p.z() + v.z();
int answer = 0;
G4PolyPhiFaceVertex *corn = corners,
*prev = corners+numEdges-1;
G4double cornZ, prevZ;
prevZ = ExactZOrder( z, qx, qy, qz, v, normSign, prev );
do {
//
// Get z order of this vertex, and compare to previous vertex
//
cornZ = ExactZOrder( z, qx, qy, qz, v, normSign, corn );
if (cornZ < 0) {
if (prevZ < 0) continue;
}
else if (cornZ > 0) {
if (prevZ > 0) continue;
}
else {
//
// By chance, we overlap exactly (within precision) with
// the current vertex. Continue if the same happened previously
// (e.g. the previous vertex had the same z value)
//
if (prevZ == 0) continue;
//
// Otherwise, to decide what to do, we need to know what is
// coming up next. Specifically, we need to find the next vertex
// with a non-zero z order.
//
// One might worry about infinite loops, but the above conditional
// should prevent it
//
G4PolyPhiFaceVertex *next = corn;
G4double nextZ;
do {
next++;
if (next == corners+numEdges) next = corners;
nextZ = ExactZOrder( z, qx, qy, qz, v, normSign, next );
} while( nextZ == 0 );
//
// If we won't be changing direction, go to the next vertex
//
if (nextZ*prevZ < 0) continue;
}
//
// We overlap in z with the side of the face that stretches from
// vertex "prev" to "corn". On which side (left or right) do
// we lay with respect to this segment?
//
G4ThreeVector qa( qx - prev->x, qy - prev->y, qz - prev->z ),
qb( qx - corn->x, qy - corn->y, qz - corn->z );
G4double aboveOrBelow = normSign*qa.cross(qb).dot(v);
if (aboveOrBelow > 0)
answer++;
else if (aboveOrBelow < 0)
answer--;
else {
//
// A precisely zero answer here means we exactly
// intersect (within roundoff) the edge of the face.
// Return true in this case.
//
return true;
}
} while( prevZ = cornZ, prev=corn, ++corn < corners+numEdges );
// G4int fanswer = abs(answer);
// if (fanswer==1 || fanswer>2) {
// G4cerr << "G4PolyPhiFace::InsideEdgesExact: answer is " << answer << endl;
// }
return answer!=0;
}
//
// InsideEdges (don't care aboud distance)
//
+240 -77
View File
@@ -3,11 +3,21 @@
//
// Implementation of a CSG polycone
//
// ----------------------------------------------------------
// This code implementation is the intellectual property of
// the GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
#include "G4Polycone.hh"
#include "G4PolyconeSide.hh"
#include "G4PolyPhiFace.hh"
#include "G4Polyhedron.hh"
#include "G4EnclosingCylinder.hh"
#include "G4ReduciblePolygon.hh"
//
@@ -22,46 +32,34 @@ G4Polycone::G4Polycone( G4String name,
const G4double rOuter[] ) : G4VCSGfaceted( name )
{
//
// Real ugly
// Some historical ugliness
//
original_parameters.exist = true;
original_parameters = new G4PolyconeHistorical();
original_parameters.Start_angle = phiStart;
original_parameters.Opening_angle = phiTotal;
original_parameters.Num_z_planes = numZPlanes;
original_parameters.Z_values = new G4double[numZPlanes];
original_parameters.Rmin = new G4double[numZPlanes];
original_parameters.Rmax = new G4double[numZPlanes];
original_parameters->Start_angle = phiStart;
original_parameters->Opening_angle = phiTotal;
original_parameters->Num_z_planes = numZPlanes;
original_parameters->Z_values = new G4double[numZPlanes];
original_parameters->Rmin = new G4double[numZPlanes];
original_parameters->Rmax = new G4double[numZPlanes];
G4int i;
for (i=0; i<numZPlanes; i++) {
original_parameters.Z_values[i] = zPlane[i];
original_parameters.Rmin[i] = rInner[i];
original_parameters.Rmax[i] = rOuter[i];
original_parameters->Z_values[i] = zPlane[i];
original_parameters->Rmin[i] = rInner[i];
original_parameters->Rmax[i] = rOuter[i];
}
//
// Translate GEANT3 into generic parameters
// Duplicate vertices and divided surfaces are (or should be) dealt with
// by routine "Create."
// Build RZ polygon using special PCON/PGON GEANT3 constructor
//
G4double *r = new G4double[numZPlanes*2];
G4double *z = new G4double[numZPlanes*2];
G4ReduciblePolygon *rz = new G4ReduciblePolygon( rInner, rOuter, zPlane, numZPlanes );
G4double *rOut = r + numZPlanes,
*zOut = z + numZPlanes,
*rIn = rOut-1,
*zIn = zOut-1;
for( i=0; i < numZPlanes; i++, rOut++, zOut++, rIn--, zIn-- ) {
*rOut = rOuter[i];
*rIn = rInner[i];
*zOut = *zIn = zPlane[i];
}
//
// Do the real work
//
Create( phiStart, phiTotal, rz );
Create( phiStart, phiTotal, numZPlanes*2, r, z );
delete [] r;
delete [] z;
delete rz;
}
@@ -75,9 +73,13 @@ G4Polycone::G4Polycone( G4String name,
const G4double r[],
const G4double z[] ) : G4VCSGfaceted( name )
{
original_parameters.exist = false;
original_parameters = 0;
G4ReduciblePolygon *rz = new G4ReduciblePolygon( r, z, numRZ );
Create( phiStart, phiTotal, numRZ, r, z );
Create( phiStart, phiTotal, rz );
delete rz;
}
@@ -88,10 +90,29 @@ G4Polycone::G4Polycone( G4String name,
//
void G4Polycone::Create( const G4double phiStart,
const G4double phiTotal,
const G4int numRZ,
const G4double r[],
const G4double z[] )
G4ReduciblePolygon *rz )
{
//
// Perform checks of rz values
//
if (rz->Amin() < 0.0)
G4Exception( "G4Polycone: Illegal input parameters: All R values must be >= 0" );
G4double rzArea = rz->Area();
if (rzArea < -kCarTolerance)
G4Exception( "G4Polycone: Illegal input parameters: R/Z values must be specified clockwise" );
else if (rzArea < -kCarTolerance)
G4Exception( "G4Polycone: Illegal input parameters: R/Z cross section is zero or near zero" );
if ((!rz->RemoveDuplicateVertices( kCarTolerance )) ||
(!rz->RemoveRedundantVertices( kCarTolerance )) )
G4Exception( "G4Polycone: Illegal input parameters: Too few unique R/Z values" );
if (rz->CrossesItself(1/kInfinity))
G4Exception( "G4Polycone: Illegal input parameters: R/Z segments cross" );
numCorner = rz->NumVertices();
//
// Phi opening? Account for some possible roundoff, and interpret
// nonsense value as representing no phi opening
@@ -115,35 +136,21 @@ void G4Polycone::Create( const G4double phiStart,
}
//
// Allocate corner array. We may not end up using all of this array,
// since we delete duplicate corners, but that's not so bad
// Allocate corner array.
//
corners = new G4PolyconeSideRZ[numRZ];
corners = new G4PolyconeSideRZ[numCorner];
//
// Copy corners, avoiding duplicates on the way
//
// We should also look for divided conical surfaces...
// We must also look for overlapping surfaces...
// Copy corners
//
G4ReduciblePolygonIterator iterRZ(rz);
G4PolyconeSideRZ *next = corners;
const G4double *rOne = r;
const G4double *zOne = z;
const G4double *rNext, *zNext;
G4bool notFinished;
iterRZ.Begin();
do {
rNext = rOne + 1;
zNext = zOne + 1;
if (notFinished = (rNext < r+numRZ)) {
if (*rNext == *rOne && *zNext == *zOne) continue;
}
next->r = *rOne;
next->z = *zOne;
next++;
} while( rOne=rNext, zOne=zNext, notFinished );
numCorner = next - corners;
next->r = iterRZ.GetA();
next->z = iterRZ.GetB();
} while( ++next, iterRZ.Next() );
//
// Allocate face pointer array
@@ -168,22 +175,46 @@ void G4Polycone::Create( const G4double phiStart,
if (corner->r < 1/kInfinity && next->r < 1/kInfinity) continue;
//
// We must decide here if we can dare declare one of our faces
// as having a "valid" normal (i.e. allBehind = true). This
// is never possible if the face faces "inward" in r.
//
G4bool allBehind;
if (corner->z > next->z) {
allBehind = false;
}
else {
//
// Otherwise, it is only true if the line passing
// through the two points of the segment do not
// split the r/z cross section
//
allBehind = !rz->BisectedBy( corner->r, corner->z,
next->r, next->z, kCarTolerance );
}
*face++ = new G4PolyconeSide( prev, corner, next, nextNext,
startPhi, endPhi-startPhi, phiIsOpen );
startPhi, endPhi-startPhi, phiIsOpen, allBehind );
} while( prev=corner, corner=next, corner > corners );
if (phiIsOpen) {
//
// Construct phi open edges
//
*face++ = new G4PolyPhiFace( r, z, numRZ, startPhi, 0, true );
*face++ = new G4PolyPhiFace( r, z, numRZ, endPhi, 0, false );
*face++ = new G4PolyPhiFace( rz, startPhi, 0, endPhi );
*face++ = new G4PolyPhiFace( rz, endPhi, 0, startPhi );
}
//
// We might have dropped a face or two: recalculate numFace
//
numFace = face-faces;
//
// Make enclosingCylinder
//
enclosingCylinder = new G4EnclosingCylinder( rz, phiIsOpen, phiStart, phiTotal );
}
@@ -194,11 +225,116 @@ G4Polycone::~G4Polycone()
{
delete [] corners;
if (original_parameters.exist) {
delete [] original_parameters.Z_values;
delete [] original_parameters.Rmin;
delete [] original_parameters.Rmax;
if (original_parameters) delete original_parameters;
}
//
// Copy constructor
//
G4Polycone::G4Polycone( const G4Polycone &source ) : G4VCSGfaceted( source )
{
CopyStuff( source );
}
//
// Assignment operator
//
const G4Polycone &G4Polycone::operator=( const G4Polycone &source )
{
if (this == &source) return *this;
G4VCSGfaceted::operator=( source );
delete [] corners;
if (original_parameters) delete original_parameters;
delete enclosingCylinder;
CopyStuff( source );
return *this;
}
//
// CopyStuff
//
void G4Polycone::CopyStuff( const G4Polycone &source )
{
//
// Simple stuff
//
startPhi = source.startPhi;
endPhi = source.endPhi;
phiIsOpen = source.phiIsOpen;
numCorner = source.numCorner;
//
// The corner array
//
corners = new G4PolyconeSideRZ[numCorner];
G4PolyconeSideRZ *corn = corners,
*sourceCorn = source.corners;
do {
*corn = *sourceCorn;
} while( ++sourceCorn, ++corn < corners+numCorner );
//
// Original parameters
//
if (source.original_parameters) {
original_parameters = new G4PolyconeHistorical( *source.original_parameters );
}
//
// Enclosing cylinder
//
enclosingCylinder = new G4EnclosingCylinder( *source.enclosingCylinder );
}
//
// Inside
//
// This is an override of G4VCSGfaceted::Inside, created in order to speed things
// up by first checking with G4EnclosingCylinder.
//
EInside G4Polycone::Inside( const G4ThreeVector &p ) const
{
//
// Quick test
//
if (enclosingCylinder->MustBeOutside(p)) return kOutside;
//
// Long answer
//
return G4VCSGfaceted::Inside(p);
}
//
// DistanceToIn
//
// This is an override of G4VCSGfaceted::Inside, created in order to speed things
// up by first checking with G4EnclosingCylinder.
//
G4double G4Polycone::DistanceToIn( const G4ThreeVector &p, const G4ThreeVector &v ) const
{
//
// Quick test
//
if (enclosingCylinder->ShouldMiss(p,v)) return kInfinity;
//
// Long answer
//
return G4VCSGfaceted::DistanceToIn( p, v );
}
@@ -218,22 +354,19 @@ void G4Polycone::ComputeDimensions( G4VPVParameterisation* p,
G4Polyhedron *G4Polycone::CreatePolyhedron() const
{
//
// It is *really* unfortunate how the design in /graphics_reps is
// written to parallel the design in /geometry/solids. Ugly, ugly, ugly.
//
// This has to be fixed, but I won't do it now. Fake it for the moment.
// This has to be fixed in visualization. Fake it for the moment.
//
if (original_parameters.exist) {
if (original_parameters) {
return new G4PolyhedronPcon( original_parameters.Start_angle,
original_parameters.Opening_angle,
original_parameters.Num_z_planes,
original_parameters.Z_values,
original_parameters.Rmin,
original_parameters.Rmax);
return new G4PolyhedronPcon( original_parameters->Start_angle,
original_parameters->Opening_angle,
original_parameters->Num_z_planes,
original_parameters->Z_values,
original_parameters->Rmin,
original_parameters->Rmax);
}
else {
G4Exception( "G4Polycone: waiting for graphics_reps to catch up" );
G4cerr << "G4Polycone: visualization of this type of G4Polycone is not supported at this time" << endl;
return 0;
}
}
@@ -246,3 +379,33 @@ G4NURBS *G4Polycone::CreateNURBS() const
{
return 0;
}
//
// G4Polycone:G4PolyconeHistorical stuff
//
G4Polycone::G4PolyconeHistorical::~G4PolyconeHistorical()
{
delete [] Z_values;
delete [] Rmin;
delete [] Rmax;
}
G4Polycone::G4PolyconeHistorical::G4PolyconeHistorical( const G4Polycone::G4PolyconeHistorical &source )
{
Start_angle = source.Start_angle;
Opening_angle = source.Opening_angle;
Num_z_planes = source.Num_z_planes;
Z_values = new G4double[Num_z_planes];
Rmin = new G4double[Num_z_planes];
Rmax = new G4double[Num_z_planes];
G4int i;
for( i = 0; i < Num_z_planes; i++) {
Z_values[i] = source.Z_values[i];
Rmin[i] = source.Rmin[i];
Rmax[i] = source.Rmax[i];
}
}
+438 -66
View File
@@ -3,12 +3,21 @@
//
// Implemenation of the face representing one conical side of a polycone
//
// ----------------------------------------------------------
// This code implementation is the intellectual property of
// the GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
#include "G4PolyconeSide.hh"
#include "G4IntersectingCone.hh"
#include "G4ClippablePolygon.hh"
#include "G4AffineTransform.hh"
#include "meshdefs.hh"
#include "G4SolidExtentList.hh"
//
// Constructor
@@ -22,7 +31,8 @@ G4PolyconeSide::G4PolyconeSide( const G4PolyconeSideRZ *prevRZ,
const G4PolyconeSideRZ *nextRZ,
const G4double thePhiStart,
const G4double theDeltaPhi,
const G4bool thePhiIsOpen )
const G4bool thePhiIsOpen,
const G4bool isAllBehind )
{
//
// Record values
@@ -40,11 +50,23 @@ G4PolyconeSide::G4PolyconeSide( const G4PolyconeSideRZ *prevRZ,
//
while (deltaPhi < 0.0) deltaPhi += 2.0*M_PI;
while (startPhi < 0.0) startPhi += 2.0*M_PI;
//
// Calculate corner coordinates
//
corners = new G4ThreeVector[4];
corners[0] = G4ThreeVector( tail->r*cos(startPhi), tail->r*sin(startPhi), tail->z );
corners[1] = G4ThreeVector( head->r*cos(startPhi), head->r*sin(startPhi), head->z );
corners[2] = G4ThreeVector( tail->r*cos(startPhi+deltaPhi), tail->r*sin(startPhi+deltaPhi), tail->z );
corners[3] = G4ThreeVector( head->r*cos(startPhi+deltaPhi), head->r*sin(startPhi+deltaPhi), head->z );
}
else {
deltaPhi = 2*M_PI;
startPhi = 0.0;
}
allBehind = isAllBehind;
//
// Make our intersecting cone
@@ -61,24 +83,28 @@ G4PolyconeSide::G4PolyconeSide( const G4PolyconeSideRZ *prevRZ,
rNorm = +zS;
zNorm = -rS;
G4double rAdj = r[0]-prevRZ->r, zAdj = z[0]-prevRZ->z;
G4double lAdj = sqrt( rAdj*rAdj + zAdj*zAdj );
rAdj /= lAdj;
zAdj /= lAdj;
G4double lAdj;
rNormEdge[0] = rNorm + zAdj;
zNormEdge[0] = zNorm - rAdj;
prevRS = r[0]-prevRZ->r;
prevZS = z[0]-prevRZ->z;
lAdj = sqrt( prevRS*prevRS + prevZS*prevZS );
prevRS /= lAdj;
prevZS /= lAdj;
rNormEdge[0] = rNorm + prevZS;
zNormEdge[0] = zNorm - prevRS;
lAdj = sqrt( rNormEdge[0]*rNormEdge[0] + zNormEdge[0]*zNormEdge[0] );
rNormEdge[0] /= lAdj;
zNormEdge[0] /= lAdj;
rAdj = nextRZ->r-r[1], zAdj = nextRZ->z-z[1];
lAdj = sqrt( rAdj*rAdj + zAdj*zAdj );
rAdj /= lAdj;
zAdj /= lAdj;
rNormEdge[1] = rNorm + zAdj;
zNormEdge[1] = zNorm - rAdj;
nextRS = nextRZ->r-r[1];
nextZS = nextRZ->z-z[1];
lAdj = sqrt( nextRS*nextRS + nextZS*nextZS );
nextRS /= lAdj;
nextZS /= lAdj;
rNormEdge[1] = rNorm + nextZS;
zNormEdge[1] = zNorm - nextRS;
lAdj = sqrt( rNormEdge[1]*rNormEdge[1] + zNormEdge[1]*zNormEdge[1] );
rNormEdge[1] /= lAdj;
zNormEdge[1] /= lAdj;
@@ -91,18 +117,90 @@ G4PolyconeSide::G4PolyconeSide( const G4PolyconeSideRZ *prevRZ,
G4PolyconeSide::~G4PolyconeSide()
{
delete cone;
if (phiIsOpen) delete [] corners;
}
//
// Copy constructor
//
G4PolyconeSide::G4PolyconeSide( const G4PolyconeSide &source )
{
CopyStuff( source );
}
//
// Assignment operator
//
G4PolyconeSide *G4PolyconeSide::operator=( const G4PolyconeSide &source )
{
if (this == &source) return this;
delete cone;
if (phiIsOpen) delete [] corners;
CopyStuff( source );
return this;
}
//
// CopyStuff
//
void G4PolyconeSide::CopyStuff( const G4PolyconeSide &source )
{
r[0] = source.r[0];
r[1] = source.r[1];
z[0] = source.z[0];
z[1] = source.z[1];
startPhi = source.startPhi;
deltaPhi = source.deltaPhi;
phiIsOpen = source.phiIsOpen;
allBehind = source.allBehind;
cone = new G4IntersectingCone( *source.cone );
rNorm = source.rNorm;
zNorm = source.zNorm;
rS = source.rS;
zS = source.zS;
length = source.length;
prevRS = source.prevRS;
prevZS = source.prevZS;
nextRS = source.nextRS;
nextZS = source.nextZS;
rNormEdge[0] = source.rNormEdge[0];
rNormEdge[1] = source.rNormEdge[1];
zNormEdge[0] = source.zNormEdge[0];
zNormEdge[1] = source.zNormEdge[1];
if (phiIsOpen) {
corners = new G4ThreeVector[4];
corners[0] = source.corners[0];
corners[1] = source.corners[1];
corners[2] = source.corners[2];
corners[3] = source.corners[3];
}
}
//
// Intersect
//
G4bool G4PolyconeSide::Intersect( const G4ThreeVector &p, const G4ThreeVector &v,
const G4bool outgoing, const G4double surfTolerance,
G4double &distance, G4double &distFromSurface,
G4ThreeVector &normal, G4bool &allBehind )
G4ThreeVector &normal, G4bool &isAllBehind )
{
G4double s1, s2;
G4double normSign = outgoing ? +1 : -1;
allBehind = true;
isAllBehind = allBehind;
//
// Check for two possible intersections
@@ -115,7 +213,7 @@ G4bool G4PolyconeSide::Intersect( const G4ThreeVector &p, const G4ThreeVector &v
//
G4ThreeVector hit = p + s1*v;
if (PointOnCone( hit, normal )) {
if (PointOnCone( hit, normSign, p, v, normal )) {
//
// Good intersection! What about the normal?
//
@@ -129,7 +227,7 @@ G4bool G4PolyconeSide::Intersect( const G4ThreeVector &p, const G4ThreeVector &v
//
G4bool opposite = (p.x()*hit.x()+p.y()*hit.y() < 0);
G4double distOutside2;
G4double notUsed = -normSign*DistanceAway( p, opposite, distOutside2, 0 );
G4double notUsed = -normSign*DistanceAway( p, opposite, distOutside2 );
//
// The distance from the surface is defined along the
@@ -143,7 +241,7 @@ G4bool G4PolyconeSide::Intersect( const G4ThreeVector &p, const G4ThreeVector &v
// Apply tolerance, but only if the point is outside
// the edges of the cone
//
if (distFromSurface > (distOutside2 > 0 ? 0 : surfTolerance)) {
if (distFromSurface > (distOutside2 > 0 ? 0 : -surfTolerance)) {
//
// Good intersection. Return now, since it is the closest.
//
@@ -160,7 +258,7 @@ G4bool G4PolyconeSide::Intersect( const G4ThreeVector &p, const G4ThreeVector &v
//
hit = p + s2*v;
if (PointOnCone( hit, normal )) {
if (PointOnCone( hit, normSign, p, v, normal )) {
//
// Good intersection! What about the normal?
//
@@ -174,7 +272,7 @@ G4bool G4PolyconeSide::Intersect( const G4ThreeVector &p, const G4ThreeVector &v
//
G4bool opposite = (p.x()*hit.x()+p.y()*hit.y() < 0);
G4double distOutside2;
G4double notUsed = -normSign*DistanceAway( p, opposite, distOutside2, 0 );
G4double notUsed = -normSign*DistanceAway( p, opposite, distOutside2 );
//
// The distance from the surface is defined along the
@@ -188,7 +286,7 @@ G4bool G4PolyconeSide::Intersect( const G4ThreeVector &p, const G4ThreeVector &v
// Apply tolerance, but only if the point is outside
// the edges of the cone
//
if (distFromSurface > (distOutside2 > 0 ? 0 : surfTolerance)) {
if (distFromSurface > (distOutside2 > 0 ? 0 : -surfTolerance)) {
//
// Good intersection. Return now, since it is the closest.
//
@@ -213,22 +311,22 @@ G4double G4PolyconeSide::Distance( const G4ThreeVector &p, const G4bool outgoing
//
// We have two tries for each hemisphere. Try the closest first.
//
distFrom = DistanceAway( p, false, distOut2, 0 );
if (distFrom*normSign > 0) {
distFrom = normSign*DistanceAway( p, false, distOut2 );
if (distFrom > -0.5*kCarTolerance ) {
//
// Good answer
//
if (distOut2 > 0)
return sqrt( distFrom*distFrom + distOut2 );
else
else
return fabs(distFrom);
}
//
// Try second side.
//
distFrom = DistanceAway( p, true, distOut2, 0 );
if (distFrom*normSign > 0) {
distFrom = normSign*DistanceAway( p, true, distOut2 );
if (distFrom > -0.5*kCarTolerance) {
if (distOut2 > 0)
return sqrt( distFrom*distFrom + distOut2 );
@@ -252,7 +350,7 @@ EInside G4PolyconeSide::Inside( const G4ThreeVector &p, const G4double tolerance
G4double distFrom[2], distOut2[2], dist2[2];
G4double edgeRZnorm[2];
distFrom[0] = DistanceAway( p, false, distOut2[0], edgeRZnorm );
distFrom[0] = DistanceAway( p, false, distOut2[0], edgeRZnorm );
distFrom[1] = DistanceAway( p, true, distOut2[1], edgeRZnorm+1 );
dist2[0] = distFrom[0]*distFrom[0] + distOut2[0];
@@ -270,7 +368,7 @@ EInside G4PolyconeSide::Inside( const G4ThreeVector &p, const G4double tolerance
//
if ( (fabs(edgeRZnorm[i]) < tolerance) && (distOut2[i] < tolerance*tolerance) )
return kSurface;
else if (edgeRZnorm[i] < 0)
else if (edgeRZnorm[i] < 0)
return kInside;
else
return kOutside;
@@ -285,7 +383,7 @@ G4ThreeVector G4PolyconeSide::Normal( const G4ThreeVector &p, G4double *bestDis
G4ThreeVector dFrom;
G4double dOut2;
dFrom = DistanceAway( p, false, dOut2, 0 );
dFrom = DistanceAway( p, false, dOut2 );
*bestDistance = sqrt( dFrom*dFrom + dOut2 );
@@ -299,7 +397,7 @@ G4ThreeVector G4PolyconeSide::Normal( const G4ThreeVector &p, G4double *bestDis
//
G4double G4PolyconeSide::Extent( const G4ThreeVector axis )
{
if (axis.perp2() < 1.0/kInfinity) {
if (axis.perp2() < DBL_MIN) {
//
// Special case
//
@@ -352,6 +450,7 @@ G4double G4PolyconeSide::Extent( const G4ThreeVector axis )
}
//
// CalculateExtent
//
@@ -360,17 +459,12 @@ G4double G4PolyconeSide::Extent( const G4ThreeVector axis )
void G4PolyconeSide::CalculateExtent( const EAxis axis,
const G4VoxelLimits &voxelLimit,
const G4AffineTransform &transform,
G4double &min, G4double &max )
G4SolidExtentList &extentList )
{
G4ClippablePolygon polygon;
//
// The following code does not work correctly and needs to be
// fixed... DCW 12/10/98
//
//
// Here we will cheat (ala G4Cons) and divide our conical section
// Here we will approximate (ala G4Cons) and divide our conical section
// into segments, like G4Polyhedra. When doing so, the radius
// is extented far enough such that the segments always lie
// just outside the surface of the conical section we are
@@ -392,54 +486,271 @@ void G4PolyconeSide::CalculateExtent( const EAxis axis,
//
// Determine radius factor to keep segments outside
//
G4double rFudge = 1.0/cos(sigPhi);
G4double rFudge = 1.0/cos(0.5*sigPhi);
//
// Decide which radius to use on each end of the side,
// and whether a transition mesh is required
//
// {r0,z0} - Beginning of this side
// {r1,z1} - Ending of this side
// {r2,z0} - Beginning of transition piece connecting previous
// side (and ends at beginning of this side)
//
// So, order is 2 --> 0 --> 1.
// -------
//
// r2 < 0 indicates that no transition piece is required
//
G4double r0, r1, r2, z0, z1;
r2 = -1; // By default: no transition piece
if (rNorm < -DBL_MIN) {
//
// This side faces *inward*, and so our mesh has
// the same radius
//
r1 = r[1];
z1 = z[1];
z0 = z[0];
r0 = r[0];
r2 = -1;
if (prevZS > DBL_MIN) {
//
// The previous side is facing outwards
//
if ( prevRS*zS - prevZS*rS > 0 ) {
//
// Transition was convex: build transition piece
//
if (r[0] > DBL_MIN) r2 = r[0]*rFudge;
}
else {
//
// Transition was concave: short this side
//
FindLineIntersect( z0, r0, zS, rS,
z0, r0*rFudge, prevZS, prevRS*rFudge, z0, r0 );
}
}
if ( nextZS > DBL_MIN && (rS*nextZS - zS*nextRS < 0) ) {
//
// The next side is facing outwards, forming a
// concave transition: short this side
//
FindLineIntersect( z1, r1, zS, rS,
z1, r1*rFudge, nextZS, nextRS*rFudge, z1, r1 );
}
}
else if (rNorm > DBL_MIN) {
//
// This side faces *outward* and is given a boost to
// it radius
//
r0 = r[0]*rFudge;
z0 = z[0];
r1 = r[1]*rFudge;
z1 = z[1];
if (prevZS < -DBL_MIN) {
//
// The previous side is facing inwards
//
if ( prevRS*zS - prevZS*rS > 0 ) {
//
// Transition was convex: build transition piece
//
if (r[0] > DBL_MIN) r2 = r[0];
}
else {
//
// Transition was concave: short this side
//
FindLineIntersect( z0, r0, zS, rS*rFudge,
z0, r[0], prevZS, prevRS, z0, r0 );
}
}
if ( nextZS < -DBL_MIN && (rS*nextZS - zS*nextRS < 0) ) {
//
// The next side is facing inwards, forming a
// concave transition: short this side
//
FindLineIntersect( z1, r1, zS, rS*rFudge,
z1, r[1], nextZS, nextRS, z1, r1 );
}
}
else {
//
// This side is perpendicular to the z axis (is a disk)
//
// Whether or not r0 needs a rFudge factor depends
// on the normal of the previous edge. Similar with r1
// and the next edge. No transition piece is required.
//
r0 = r[0];
r1 = r[1];
z0 = z[0];
z1 = z[1];
if (prevZS > DBL_MIN) r0 *= rFudge;
if (nextZS > DBL_MIN) r1 *= rFudge;
}
//
// Loop
//
G4double phi = startPhi,
cosPhi = rFudge*cos(phi),
sinPhi = rFudge*sin(phi);
cosPhi = cos(phi),
sinPhi = sin(phi);
G4ThreeVector v0( r[0]*cosPhi, r[0]*sinPhi, z[0] ),
v1( r[1]*cosPhi, r[1]*sinPhi, z[1] ),
w0, w1;
G4ThreeVector v0( r0*cosPhi, r0*sinPhi, z0 ),
v1( r1*cosPhi, r1*sinPhi, z1 ),
v2, w0, w1, w2;
transform.ApplyPointTransform( v0 );
transform.ApplyPointTransform( v1 );
if (r2 >= 0) {
v2 = G4ThreeVector( r2*cosPhi, r2*sinPhi, z0 );
transform.ApplyPointTransform( v2 );
}
do {
G4double min, max;
phi += sigPhi;
cosPhi = rFudge*cos(phi),
sinPhi = rFudge*sin(phi);
if (numPhi == 1) phi = startPhi+deltaPhi; // Try to avoid roundoff
cosPhi = cos(phi),
sinPhi = sin(phi);
w0 = G4ThreeVector( r[0]*cosPhi, r[0]*sinPhi, z[0] );
w1 = G4ThreeVector( r[1]*cosPhi, r[1]*sinPhi, z[1] );
w0 = G4ThreeVector( r0*cosPhi, r0*sinPhi, z0 );
w1 = G4ThreeVector( r1*cosPhi, r1*sinPhi, z1 );
transform.ApplyPointTransform( w0 );
transform.ApplyPointTransform( w1 );
G4ThreeVector deltaV = r0 > r1 ? w0-v0 : w1-v1;
//
// Build polygon, taking special care to keep the vertices
// in order
//
polygon.ClearAllVertices();
polygon.AddVertexInOrder( v0 );
polygon.AddVertexInOrder( v1 );
polygon.AddVertexInOrder( w1 );
polygon.AddVertexInOrder( w0 );
//
// Get extent
//
polygon.Clip( voxelLimit );
polygon.GetExtent( axis, min, max );
if (polygon.PartialClip( voxelLimit, axis )) {
//
// Get dot product of normal with target axis
//
polygon.SetNormal( deltaV.cross(v1-v0).unit() );
extentList.AddSurface( polygon );
}
if (r2 >= 0) {
//
// Repeat, for transition piece
//
w2 = G4ThreeVector( r2*cosPhi, r2*sinPhi, z0 );
transform.ApplyPointTransform( w2 );
polygon.ClearAllVertices();
polygon.AddVertexInOrder( v2 );
polygon.AddVertexInOrder( v0 );
polygon.AddVertexInOrder( w0 );
polygon.AddVertexInOrder( w2 );
if (polygon.PartialClip( voxelLimit, axis )) {
polygon.SetNormal( deltaV.cross(v0-v2).unit() );
extentList.AddSurface( polygon );
}
v2 = w2;
}
//
// Next vertex
//
v0 = w0;
v1 = w1;
} while( --numPhi > 0 );
//
// We are almost done. But, it is important that we leave no
// gaps in the surface of our solid. By using rFudge, however,
// we've done exactly that, if we have a phi segment.
// Add two additional faces if necessary
//
if (phiIsOpen && rNorm > DBL_MIN) {
G4double min, max;
G4double cosPhi = cos(startPhi),
sinPhi = sin(startPhi);
G4ThreeVector a0( r[0]*cosPhi, r[0]*sinPhi, z[0] ),
a1( r[1]*cosPhi, r[1]*sinPhi, z[1] ),
b0( r0*cosPhi, r0*sinPhi, z[0] ),
b1( r1*cosPhi, r1*sinPhi, z[1] );
transform.ApplyPointTransform( a0 );
transform.ApplyPointTransform( a1 );
transform.ApplyPointTransform( b0 );
transform.ApplyPointTransform( b1 );
polygon.ClearAllVertices();
polygon.AddVertexInOrder( a0 );
polygon.AddVertexInOrder( a1 );
polygon.AddVertexInOrder( b0 );
polygon.AddVertexInOrder( b1 );
if (polygon.PartialClip( voxelLimit , axis)) {
G4ThreeVector normal( sinPhi, -cosPhi, 0 );
polygon.SetNormal( transform.TransformAxis( normal ) );
extentList.AddSurface( polygon );
}
cosPhi = cos(startPhi+deltaPhi);
sinPhi = sin(startPhi+deltaPhi);
a0 = G4ThreeVector( r[0]*cosPhi, r[0]*sinPhi, z[0] ),
a1 = G4ThreeVector( r[1]*cosPhi, r[1]*sinPhi, z[1] ),
b0 = G4ThreeVector( r0*cosPhi, r0*sinPhi, z[0] ),
b1 = G4ThreeVector( r1*cosPhi, r1*sinPhi, z[1] );
transform.ApplyPointTransform( a0 );
transform.ApplyPointTransform( a1 );
transform.ApplyPointTransform( b0 );
transform.ApplyPointTransform( b1 );
polygon.ClearAllVertices();
polygon.AddVertexInOrder( a0 );
polygon.AddVertexInOrder( a1 );
polygon.AddVertexInOrder( b0 );
polygon.AddVertexInOrder( b1 );
if (polygon.PartialClip( voxelLimit, axis )) {
G4ThreeVector normal( -sinPhi, cosPhi, 0 );
polygon.SetNormal( transform.TransformAxis( normal ) );
extentList.AddSurface( polygon );
}
}
return;
}
@@ -457,7 +768,7 @@ void G4PolyconeSide::CalculateExtent( const EAxis axis,
// opposite - (in) If true, check opposite hemisphere (see below)
// distOutside - (out) Additional distance outside the edges of the
// surface
// edgeNorm - (out) Edge Status (belowRZ, aboveRZ, inRZ)
// edgeRZnorm - (out) if negative, point is inside
// return value = distance from the conical plane, if extrapolated beyond edges,
// signed by whether the point is in inside or outside the shape
//
@@ -465,7 +776,7 @@ void G4PolyconeSide::CalculateExtent( const EAxis axis,
// * There are two answers, depending on which hemisphere is considered.
//
G4double G4PolyconeSide::DistanceAway( const G4ThreeVector &p, const G4bool opposite,
G4double &distOutside2, G4double *edgeRZnorm )
G4double &distOutside2, G4double *edgeRZnorm )
{
//
// Convert our point to r and z
@@ -520,7 +831,10 @@ G4double G4PolyconeSide::DistanceAway( const G4ThreeVector &p, const G4bool oppo
//
// Add result to our distance
//
distOutside2 += d1*d1*p.perp2();
G4double dist = d1*rx;
distOutside2 += dist*dist;
if (edgeRZnorm) *edgeRZnorm = fabs(dist);
}
}
@@ -533,32 +847,90 @@ G4double G4PolyconeSide::DistanceAway( const G4ThreeVector &p, const G4bool oppo
//
// Decide if a point is on a cone and return normal if it is
//
G4bool G4PolyconeSide::PointOnCone( const G4ThreeVector &p, G4ThreeVector &normal )
G4bool G4PolyconeSide::PointOnCone( const G4ThreeVector &hit, const G4double normSign,
const G4ThreeVector &p, const G4ThreeVector &v,
G4ThreeVector &normal )
{
G4double rx = p.perp();
G4double rx = hit.perp();
//
// Check radial/z extent, as appropriate
//
if (!cone->HitOn( rx, p.z() )) return false;
if (!cone->HitOn( rx, hit.z() )) return false;
if (phiIsOpen) {
G4double phiTolerant = 2.0*kCarTolerance/(rx+kCarTolerance);
//
// Check phi segment
// Check phi segment. Here we have to be careful
// to use the standard method consistent with
// PolyPhiFace. See PolyPhiFace::InsideEdgesExact
//
G4double phi = p.phi();
while( phi < startPhi ) phi += 2*M_PI;
G4double phi = hit.phi();
while( phi < startPhi-phiTolerant ) phi += 2*M_PI;
if (phi > startPhi+deltaPhi) return false;
if (phi > startPhi+deltaPhi+phiTolerant) return false;
if (phi > startPhi+deltaPhi-phiTolerant) {
//
// Exact treatment
//
G4ThreeVector qx = p + v;
G4ThreeVector qa = qx - corners[2],
qb = qx - corners[3];
G4ThreeVector qacb = qa.cross(qb);
if (normSign*qacb.dot(v) < 0) return false;
}
else if (phi < phiTolerant) {
G4ThreeVector qx = p + v;
G4ThreeVector qa = qx - corners[1],
qb = qx - corners[0];
G4ThreeVector qacb = qa.cross(qb);
if (normSign*qacb.dot(v) < 0) return false;
}
}
//
// We have a good hit! Calculate normal
//
if (rx<0) rx = p.perp();
if (rx<0) rx = hit.perp();
if (rx < -1.0/kInfinity)
if (rx < DBL_MIN)
normal = G4ThreeVector( 0, 0, zNorm < 0 ? -1 : 1 );
else
normal = G4ThreeVector( rNorm*p.x()/rx, rNorm*p.y()/rx, zNorm );
normal = G4ThreeVector( rNorm*hit.x()/rx, rNorm*hit.y()/rx, zNorm );
return true;
}
//
// FindLineIntersect
//
// Decide the point at which two 2-dimensional lines intersect
//
// Equation of line: x = x1 + s*tx1
// y = y1 + s*ty1
//
// It is assumed that the lines are *not* parallel
//
void G4PolyconeSide::FindLineIntersect( const G4double x1, const G4double y1,
const G4double tx1, const G4double ty1,
const G4double x2, const G4double y2,
const G4double tx2, const G4double ty2,
G4double &x, G4double &y )
{
//
// The solution is a simple linear equation
//
G4double deter = tx1*ty2 - tx2*ty1;
G4double s1 = ((x2-x1)*ty2 - tx2*(y2-y1))/deter;
G4double s2 = ((x2-x1)*ty1 - tx1*(y2-y1))/deter;
//
// We want the answer to not depend on which order the
// lines were specified. Take average.
//
x = 0.5*( x1+s1*tx1 + x2+s2*tx2 );
y = 0.5*( y1+s1*ty1 + y2+s2*ty2 );
}
+232 -101
View File
@@ -4,22 +4,37 @@
// Implementation of a CSG polyhedra, as an inherited class of G4VCSGfaceted.
//
// To be done:
// * Checks for bad input should be improved. It is now possible for
// users to specify crazy polyhedra parameters without complaint that
// could produce unpredictable results.
// * Cracks: there are probably small cracks in the seams between the
// phi face (G4PolyPhiFace) and sides (G4PolyhedraSide) that are not
// entirely leakproof. Also, I am not sure all vertices are leak proof.
// * Many optimizations are possible, but not implemented.
// * Visualization needs to be updated outside of this routine.
//
// Utility classes:
// * G4EnclosingCylinder: I decided a quick check of geometry would be a
// good idea (for CPU speed). If the quick check fails, the regular
// full-blown G4VCSGfaceted version is invoked.
// * G4ReduciblePolygon: Really meant as a check of input parameters,
// this utility class also "converts" the GEANT3-like PGON/PCON
// arguments into the newer ones.
// Both these classes are implemented outside this file because they are
// shared with G4Polycone.
//
// ----------------------------------------------------------
// This code implementation is the intellectual property of
// the GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
#include "G4Polyhedra.hh"
#include "G4PolyhedraSide.hh"
#include "G4PolyPhiFace.hh"
#include "G4Polyhedron.hh"
#include "G4EnclosingCylinder.hh"
#include "G4ReduciblePolygon.hh"
//
// Constructor (GEANT3 style parameters)
@@ -29,7 +44,7 @@
G4Polyhedra::G4Polyhedra( G4String name,
const G4double phiStart,
const G4double thePhiTotal,
const G4double theNumSide,
const G4int theNumSide,
const G4int numZPlanes,
const G4double zPlane[],
const G4double rInner[],
@@ -41,52 +56,42 @@ G4Polyhedra::G4Polyhedra( G4String name,
// Calculate conversion factor from G3 radius to G4 radius
//
G4double phiTotal = thePhiTotal;
if (phiTotal <=0 || phiTotal > 2*M_PI) phiTotal = 2*M_PI;
if (phiTotal <=0 || phiTotal >= 2*M_PI*(1-DBL_EPSILON)) phiTotal = 2*M_PI;
G4double convertRad = cos(0.5*phiTotal/theNumSide);
//
// Real ugly
// Some historical stuff
//
original_parameters.exist = true;
original_parameters = new G4PolyhedraHistorical;
original_parameters.numSide = theNumSide;
original_parameters.Start_angle = phiStart;
original_parameters.Opening_angle = phiTotal;
original_parameters.Num_z_planes = numZPlanes;
original_parameters.Z_values = new G4double[numZPlanes];
original_parameters.Rmin = new G4double[numZPlanes];
original_parameters.Rmax = new G4double[numZPlanes];
original_parameters->numSide = theNumSide;
original_parameters->Start_angle = phiStart;
original_parameters->Opening_angle = phiTotal;
original_parameters->Num_z_planes = numZPlanes;
original_parameters->Z_values = new G4double[numZPlanes];
original_parameters->Rmin = new G4double[numZPlanes];
original_parameters->Rmax = new G4double[numZPlanes];
G4int i;
for (i=0; i<numZPlanes; i++) {
original_parameters.Z_values[i] = zPlane[i];
original_parameters.Rmin[i] = rInner[i]/convertRad;
original_parameters.Rmax[i] = rOuter[i]/convertRad;
}
//
// Translate GEANT3 into generic parameters
// Duplicate vertices and divided surfaces are (or should be) dealt with
// by routine "Create."
//
G4double *r = new G4double[numZPlanes*2];
G4double *z = new G4double[numZPlanes*2];
G4double *rOut = r + numZPlanes,
*zOut = z + numZPlanes,
*rIn = rOut-1,
*zIn = zOut-1;
for( i=0; i < numZPlanes; i++, rOut++, zOut++, rIn--, zIn-- ) {
*rOut = rOuter[i]/convertRad;
*rIn = rInner[i]/convertRad;
*zOut = *zIn = zPlane[i];
original_parameters->Z_values[i] = zPlane[i];
original_parameters->Rmin[i] = rInner[i]/convertRad;
original_parameters->Rmax[i] = rOuter[i]/convertRad;
}
Create( phiStart, phiTotal, theNumSide, numZPlanes*2, r, z );
delete [] r;
delete [] z;
//
// Build RZ polygon using special PCON/PGON GEANT3 constructor
//
G4ReduciblePolygon *rz = new G4ReduciblePolygon( rInner, rOuter, zPlane, numZPlanes );
rz->ScaleA( 1/convertRad );
//
// Do the real work
//
Create( phiStart, phiTotal, theNumSide, rz );
delete rz;
}
@@ -96,14 +101,18 @@ G4Polyhedra::G4Polyhedra( G4String name,
G4Polyhedra::G4Polyhedra( G4String name,
const G4double phiStart,
const G4double phiTotal,
const G4double theNumSide,
const G4int theNumSide,
const G4int numRZ,
const G4double r[],
const G4double z[] ) : G4VCSGfaceted( name )
{
original_parameters.exist = false;
original_parameters = 0;
Create( phiStart, phiTotal, theNumSide, numRZ, r, z );
G4ReduciblePolygon *rz = new G4ReduciblePolygon( r, z, numRZ );
Create( phiStart, phiTotal, theNumSide, rz );
delete rz;
}
@@ -114,19 +123,40 @@ G4Polyhedra::G4Polyhedra( G4String name,
//
void G4Polyhedra::Create( const G4double phiStart,
const G4double phiTotal,
const G4double theNumSide,
const G4int numRZ,
const G4double r[],
const G4double z[] )
const G4int theNumSide,
G4ReduciblePolygon *rz )
{
//
// Perform checks of rz values
//
if (rz->Amin() < 0.0)
G4Exception( "G4Polyhedra: Illegal input parameters: All R values must be >= 0" );
G4double rzArea = rz->Area();
if (rzArea < -kCarTolerance)
G4Exception( "G4Polyhedra: Illegal input parameters: R/Z values must be specified clockwise" );
else if (rzArea < -kCarTolerance)
G4Exception( "G4Polyhedra: Illegal input parameters: R/Z cross section is zero or near zero" );
if ((!rz->RemoveDuplicateVertices( kCarTolerance )) ||
(!rz->RemoveRedundantVertices( kCarTolerance )) )
G4Exception( "G4Polyhedra: Illegal input parameters: Too few unique R/Z values" );
if (rz->CrossesItself( 1/kInfinity ))
G4Exception( "G4Polyhedra: Illegal input parameters: R/Z segments cross" );
numCorner = rz->NumVertices();
startPhi = phiStart;
while( startPhi < 0 ) startPhi += 2*M_PI;
//
// Phi opening? Account for some possible roundoff, and interpret
// nonsense value as representing no phi opening
//
if (phiTotal <= 0 || phiTotal > 2.0*M_PI-1E-10) {
if (phiTotal <= 0 || phiTotal > 2.0*M_PI*(1-DBL_EPSILON)) {
phiIsOpen = false;
startPhi = 0;
endPhi = 2*M_PI;
endPhi = phiStart+2*M_PI;
}
else {
phiIsOpen = true;
@@ -134,9 +164,6 @@ void G4Polyhedra::Create( const G4double phiStart,
//
// Convert phi into our convention
//
startPhi = phiStart;
while( startPhi < 0 ) startPhi += 2*M_PI;
endPhi = phiStart+phiTotal;
while( endPhi < startPhi ) endPhi += 2*M_PI;
}
@@ -147,35 +174,21 @@ void G4Polyhedra::Create( const G4double phiStart,
numSide = theNumSide;
//
// Allocate corner array. We may not end up using all of this array,
// since we delete duplicate corners, but that's not so bad
// Allocate corner array.
//
corners = new G4PolyhedraSideRZ[numRZ];
corners = new G4PolyhedraSideRZ[numCorner];
//
// Copy corners, avoiding duplicates on the way
//
// We should also look for divided conical surfaces...
// We must also look for overlapping surfaces...
// Copy corners
//
G4ReduciblePolygonIterator iterRZ(rz);
G4PolyhedraSideRZ *next = corners;
const G4double *rOne = r;
const G4double *zOne = z;
const G4double *rNext, *zNext;
G4bool notFinished;
iterRZ.Begin();
do {
rNext = rOne + 1;
zNext = zOne + 1;
if (notFinished = (rNext < r+numRZ)) {
if (*rNext == *rOne && *zNext == *zOne) continue;
}
next->r = *rOne;
next->z = *zOne;
next++;
} while( rOne=rNext, zOne=zNext, notFinished );
numCorner = next - corners;
next->r = iterRZ.GetA();
next->z = iterRZ.GetB();
} while( ++next, iterRZ.Next() );
//
// Allocate face pointer array
@@ -202,6 +215,26 @@ void G4Polyhedra::Create( const G4double phiStart,
if (nextNext >= corners+numCorner) nextNext = corners;
if (corner->r < 1/kInfinity && next->r < 1/kInfinity) continue;
//
// We must decide here if we can dare declare one of our faces
// as having a "valid" normal (i.e. allBehind = true). This
// is never possible if the face faces "inward" in r *unless*
// we have only one side
//
G4bool allBehind;
if ((corner->z > next->z) && (numSide > 1)) {
allBehind = false;
}
else {
//
// Otherwise, it is only true if the line passing
// through the two points of the segment do not
// split the r/z cross section
//
allBehind = !rz->BisectedBy( corner->r, corner->z,
next->r, next->z, kCarTolerance );
}
*face++ = new G4PolyhedraSide( prev, corner, next, nextNext,
numSide, startPhi, endPhi-startPhi, phiIsOpen );
@@ -211,8 +244,8 @@ void G4Polyhedra::Create( const G4double phiStart,
//
// Construct phi open edges
//
*face++ = new G4PolyPhiFace( r, z, numRZ, startPhi, phiTotal/numSide, true );
*face++ = new G4PolyPhiFace( r, z, numRZ, endPhi, phiTotal/numSide, false );
*face++ = new G4PolyPhiFace( rz, startPhi, phiTotal/numSide, endPhi );
*face++ = new G4PolyPhiFace( rz, endPhi, phiTotal/numSide, startPhi );
}
//
@@ -223,8 +256,7 @@ void G4Polyhedra::Create( const G4double phiStart,
//
// Make enclosingCylinder
//
enclosingCylinder = new G4EnclosingCylinder( r, z, numRZ,
phiIsOpen, phiStart, phiTotal );
enclosingCylinder = new G4EnclosingCylinder( rz, phiIsOpen, phiStart, phiTotal );
}
@@ -234,26 +266,92 @@ void G4Polyhedra::Create( const G4double phiStart,
G4Polyhedra::~G4Polyhedra()
{
delete [] corners;
if (original_parameters.exist) {
delete [] original_parameters.Z_values;
delete [] original_parameters.Rmin;
delete [] original_parameters.Rmax;
}
if (original_parameters) delete original_parameters;
delete enclosingCylinder;
}
//
// Copy constructor
//
G4Polyhedra::G4Polyhedra( const G4Polyhedra &source ) : G4VCSGfaceted( source )
{
CopyStuff( source );
}
//
// Assignment operator
//
const G4Polyhedra &G4Polyhedra::operator=( const G4Polyhedra &source )
{
if (this == &source) return *this;
G4VCSGfaceted::operator=( source );
delete [] corners;
if (original_parameters) delete original_parameters;
delete enclosingCylinder;
CopyStuff( source );
return *this;
}
//
// CopyStuff
//
void G4Polyhedra::CopyStuff( const G4Polyhedra &source )
{
//
// Simple stuff
//
numSide = source.numSide;
startPhi = source.startPhi;
endPhi = source.endPhi;
phiIsOpen = source.phiIsOpen;
numCorner = source.numCorner;
//
// The corner array
//
corners = new G4PolyhedraSideRZ[numCorner];
G4PolyhedraSideRZ *corn = corners,
*sourceCorn = source.corners;
do {
*corn = *sourceCorn;
} while( ++sourceCorn, ++corn < corners+numCorner );
//
// Original parameters
//
if (source.original_parameters) {
original_parameters = new G4PolyhedraHistorical( *source.original_parameters );
}
//
// Enclosing cylinder
//
enclosingCylinder = new G4EnclosingCylinder( *source.enclosingCylinder );
}
//
// Inside
//
// This is an override of G4VCSGfaceted::Inside, created in order to speed things
// up by first checking with G4EnclosingCylinder.
//
EInside G4Polyhedra::Inside( const G4ThreeVector &p ) const
{
//
// Quick test
//
if (enclosingCylinder->Outside(p)) return kOutside;
if (enclosingCylinder->MustBeOutside(p)) return kOutside;
//
// Long answer
@@ -265,12 +363,15 @@ EInside G4Polyhedra::Inside( const G4ThreeVector &p ) const
//
// DistanceToIn
//
// This is an override of G4VCSGfaceted::Inside, created in order to speed things
// up by first checking with G4EnclosingCylinder.
//
G4double G4Polyhedra::DistanceToIn( const G4ThreeVector &p, const G4ThreeVector &v ) const
{
//
// Quick test
//
if (enclosingCylinder->Misses(p,v)) return kInfinity;
if (enclosingCylinder->ShouldMiss(p,v)) return kInfinity;
//
// Long answer
@@ -295,23 +396,20 @@ void G4Polyhedra::ComputeDimensions( G4VPVParameterisation* p,
G4Polyhedron *G4Polyhedra::CreatePolyhedron() const
{
//
// It is *really* unfortunate how the design in /graphics_reps is
// written to parallel the design in /geometry/solids. Ugly, ugly, ugly.
//
// This has to be fixed, but I won't do it now. Fake it for the moment.
// This has to be fixed in visualization. Fake it for the moment.
//
if (original_parameters.exist) {
if (original_parameters) {
return new G4PolyhedronPgon( original_parameters.Start_angle,
original_parameters.Opening_angle,
original_parameters.numSide,
original_parameters.Num_z_planes,
original_parameters.Z_values,
original_parameters.Rmin,
original_parameters.Rmax);
return new G4PolyhedronPgon( original_parameters->Start_angle,
original_parameters->Opening_angle,
original_parameters->numSide,
original_parameters->Num_z_planes,
original_parameters->Z_values,
original_parameters->Rmin,
original_parameters->Rmax);
}
else {
G4Exception( "G4Polyhedra: waiting for graphics_reps to catch up" );
G4cerr << "G4Polyhedra: visualization of this type of G4Polyhedra is not supported at this time" << endl;
return 0;
}
@@ -325,3 +423,36 @@ G4NURBS *G4Polyhedra::CreateNURBS() const
{
return 0;
}
//
// G4Polyhedra::G4PolyhedraHistorical stuff
//
G4Polyhedra::G4PolyhedraHistorical::~G4PolyhedraHistorical()
{
delete [] Z_values;
delete [] Rmin;
delete [] Rmax;
}
G4Polyhedra::G4PolyhedraHistorical::G4PolyhedraHistorical( const G4PolyhedraHistorical &source )
{
Start_angle = source.Start_angle;
Opening_angle = source.Opening_angle;
numSide = source.numSide;
Num_z_planes = source.Num_z_planes;
Z_values = new G4double[Num_z_planes];
Rmin = new G4double[Num_z_planes];
Rmax = new G4double[Num_z_planes];
G4int i;
for( i = 0; i < Num_z_planes; i++) {
Z_values[i] = source.Z_values[i];
Rmin[i] = source.Rmin[i];
Rmax[i] = source.Rmax[i];
}
}
+296 -148
View File
@@ -3,11 +3,20 @@
//
// Implemenation of the face representing one segmented side of a Polyhedra
//
// ----------------------------------------------------------
// This code implementation is the intellectual property of
// the GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
#include "G4PolyhedraSide.hh"
#include "G4IntersectingCone.hh"
#include "G4ClippablePolygon.hh"
#include "G4AffineTransform.hh"
#include "G4SolidExtentList.hh"
//
// Constructor
@@ -22,7 +31,8 @@ G4PolyhedraSide::G4PolyhedraSide( const G4PolyhedraSideRZ *prevRZ,
const G4int theNumSide,
const G4double thePhiStart,
const G4double thePhiTotal,
const G4bool thePhiIsOpen )
const G4bool thePhiIsOpen,
const G4bool isAllBehind )
{
//
// Record values
@@ -32,20 +42,16 @@ G4PolyhedraSide::G4PolyhedraSide( const G4PolyhedraSideRZ *prevRZ,
G4double phiTotal;
//
// Set phi to our convention
//
startPhi = thePhiStart;
while (startPhi < 0.0) startPhi += 2.0*M_PI;
phiIsOpen = thePhiIsOpen;
if (phiIsOpen) {
phiTotal = thePhiTotal;
startPhi = thePhiStart;
//
// Set phi values to our conventions
//
while (startPhi < 0.0) startPhi += 2.0*M_PI;
}
else {
phiTotal = 2*M_PI;
startPhi = 0;
}
phiTotal = (phiIsOpen) ? thePhiTotal : 2*M_PI;
allBehind = isAllBehind;
//
// Make our intersecting cone
@@ -57,6 +63,7 @@ G4PolyhedraSide::G4PolyhedraSide( const G4PolyhedraSideRZ *prevRZ,
//
numSide = theNumSide;
deltaPhi = phiTotal/theNumSide;
endPhi = startPhi+phiTotal;
vecs = new G4PolyhedraSideVec[numSide];
@@ -179,82 +186,53 @@ G4PolyhedraSide::G4PolyhedraSide( const G4PolyhedraSideRZ *prevRZ,
edge->normal = eNorm.unit();
//
// Vertex normal is average of norms of attached edges
// Vertex normal is average of norms of adjacent surfaces (all four)
// However, vec->edgeNorm is unit vector in some direction
// as the sum of normals of adjacent PolyhedraSide with vec.
// The normalization used for this vector should be the same
// for vec and prev.
//
eNorm = edge->normal + vec->edgeNorm[0] + prev->edgeNorm[0];
eNorm = vec->edgeNorm[0] + prev->edgeNorm[0];
edge->cornNorm[0] = eNorm.unit();
eNorm = edge->normal + vec->edgeNorm[1] + prev->edgeNorm[1];
eNorm = vec->edgeNorm[1] + prev->edgeNorm[1];
edge->cornNorm[1] = eNorm.unit();
} while( prev=vec, ++vec < vecs + numSide );
if (phiIsOpen) {
G4double rFact = cos(0.5*deltaPhi);
//
// If phi is open, we need to patch up the first and last edges
// If phi is open, we need to patch up normals of the
// first and last edges and their corresponding
// vertices.
//
// We use vectors that are in the plane of the
// face. This should be safe.
//
G4double phi1 = startPhi - 0.5*M_PI;
G4ThreeVector phiNorm( cos(phi1), sin(phi1), 0 );
vec = vecs;
//
// Edge normal is average of vec->normal and the normal
// of the face closing the polyhedra in phi
//
G4ThreeVector eNorm = vec->normal + phiNorm;
vec->edges[0]->normal = eNorm.unit();
G4ThreeVector normvec = vec->edges[0]->corner[0] - vec->edges[0]->corner[1];
normvec = normvec.cross(vec->normal);
if (normvec.dot(vec->surfPhi) > 0) normvec = -normvec;
vec->edges[0]->normal = normvec.unit();
vec->edges[0]->cornNorm[0] = (vec->edges[0]->corner[0] - vec->center).unit();
vec->edges[0]->cornNorm[1] = (vec->edges[0]->corner[1] - vec->center).unit();
//
// We need the edge normals (like above) of the adjacent
// G4PolyhedraSides.
// Repeat for ending phi
//
G4double dr = r[0]-prevRZ->r, dz = z[0]-prevRZ->z;
phi1 = startPhi + 0.5*deltaPhi;
eNorm = G4ThreeVector( dz*rFact*cos(phi1), dz*rFact*sin(phi1), -dr );
//
// Average three line normals for the vertex normal
//
eNorm = eNorm.unit() + vec->edges[0]->normal + vec->edgeNorm[0];
vec->edges[0]->cornNorm[0] = eNorm.unit();
//
// Repeat for edgeNorm[1]
//
dr = nextRZ->r-r[1], dz = nextRZ->z-z[1];
eNorm = G4ThreeVector( dz*rFact*cos(phi1), dz*rFact*sin(phi1), -dr );
eNorm = eNorm.unit() + vec->edges[0]->normal + vec->edgeNorm[1];
vec->edges[0]->cornNorm[1] = eNorm.unit();
//
// That was bad...
//
// But, now repeat for ending phi (edge[1])
//
phi1 = startPhi + phiTotal + 0.5*M_PI;
phiNorm = G4ThreeVector( cos(phi1), sin(phi1), 0 );
vec = vecs + numSide - 1;
eNorm = vec->normal + phiNorm;
vec->edges[1]->normal = eNorm.unit();
dr = r[0]-prevRZ->r, dz = z[0]-prevRZ->z;
phi1 = startPhi + phiTotal - 0.5*deltaPhi;
eNorm = G4ThreeVector( dz*rFact*cos(phi1), dz*rFact*sin(phi1), -dr );
eNorm = eNorm.unit() + vec->edges[1]->normal + vec->edgeNorm[0];
vec->edges[1]->cornNorm[0] = eNorm.unit();
dr = nextRZ->r-r[1], dz = nextRZ->z-z[1];
eNorm = G4ThreeVector( dz*rFact*cos(phi1), dz*rFact*sin(phi1), -dr );
eNorm = eNorm.unit() + vec->edges[1]->normal + vec->edgeNorm[1];
vec->edges[1]->cornNorm[1] = eNorm.unit();
//
// Phew! I need a beer!
//
normvec = vec->edges[1]->corner[0] - vec->edges[1]->corner[1];
normvec = normvec.cross(vec->normal);
if (normvec.dot(vec->surfPhi) < 0) normvec = -normvec;
vec->edges[1]->normal = normvec.unit();
vec->edges[1]->cornNorm[0] = (vec->edges[1]->corner[0] - vec->center).unit();
vec->edges[1]->cornNorm[1] = (vec->edges[1]->corner[1] - vec->center).unit();
}
//
@@ -277,6 +255,85 @@ G4PolyhedraSide::~G4PolyhedraSide()
}
//
// Copy constructor
//
G4PolyhedraSide::G4PolyhedraSide( const G4PolyhedraSide &source )
{
CopyStuff( source );
}
//
// Assignment operator
//
G4PolyhedraSide *G4PolyhedraSide::operator=( const G4PolyhedraSide &source )
{
if (this == &source) return this;
delete cone;
delete [] vecs;
delete [] edges;
CopyStuff( source );
return this;
}
//
// CopyStuff
//
void G4PolyhedraSide::CopyStuff( const G4PolyhedraSide &source )
{
//
// The simple stuff
//
numSide = source.numSide;
r[0] = source.r[0];
r[1] = source.r[1];
z[0] = source.z[0];
z[1] = source.z[1];
startPhi = source.startPhi;
deltaPhi = source.deltaPhi;
endPhi = source.endPhi;
phiIsOpen = source.phiIsOpen;
allBehind = source.allBehind;
lenRZ = source.lenRZ;
lenPhi[0] = source.lenPhi[0];
lenPhi[1] = source.lenPhi[1];
edgeNorm = source.edgeNorm;
cone = new G4IntersectingCone( *source.cone );
//
// Duplicate edges
//
G4int numEdges = phiIsOpen ? numSide+1 : numSide;
edges = new G4PolyhedraSideEdge[numEdges];
G4PolyhedraSideEdge *edge = edges,
*sourceEdge = source.edges;
do {
*edge = *sourceEdge;
} while( ++sourceEdge, ++edge < edges + numEdges);
//
// Duplicate vecs
//
vecs = new G4PolyhedraSideVec[numSide];
G4PolyhedraSideVec *vec = vecs,
*sourceVec = source.vecs;
do {
*vec = *sourceVec;
vec->edges[0] = edges + (sourceVec->edges[0] - source.edges);
vec->edges[1] = edges + (sourceVec->edges[1] - source.edges);
} while( ++sourceVec, ++vec < vecs + numSide );
}
//
// Intersect
//
@@ -287,7 +344,7 @@ G4PolyhedraSide::~G4PolyhedraSide()
// v = (in) direction of line segment (assumed a unit vector)
// A, B = (in) 2d transform variables (see note top of file)
// normSign = (in) desired sign for dot product with normal (see below)
// surfTolerance = (in) minimum distance from the surface (can be < 0, see below)
// surfTolerance = (in) minimum distance from the surface
// vecs = (in) Vector set array
// distance = (out) distance to surface furfilling all requirements
// distFromSurface = (out) distance from the surface
@@ -306,67 +363,121 @@ G4PolyhedraSide::~G4PolyhedraSide()
// we are outside and want to go in, normSign should be set to -1.0.
// Don't set normSign to zero, or you will get no intersections!
//
// * surfTolerance: see notes on argument "surfTolerance" in routine "IntersectSide".
// * surfTolerance: see notes on argument "surfTolerance" in routine "IntersectSidePlane".
// ----HOWEVER---- We should *not* apply this surface tolerance if the starting
// point is not within phi or z of the surface. Specifically, if the starting
// point p angle in x/y places it on a separate side from the intersection or
// if the starting point p is outside the z bounds of the segment, surfTolerance
// must be ignored are we should *always* accept the intersection!
// must be ignored or we should *always* accept the intersection!
// This is simply because the sides do not have infinite extent.
//
//
G4bool G4PolyhedraSide::Intersect( const G4ThreeVector &p, const G4ThreeVector &v,
const G4bool outgoing, const G4double surfTolerance,
G4double &distance, G4double &distFromSurface,
G4ThreeVector &normal, G4bool &allBehind )
G4ThreeVector &normal, G4bool &isAllBehind )
{
G4int nside, i1, i2, iStart;
G4double normSign = outgoing ? +1 : -1;
allBehind = true; // this is always true for this face
//
// ------------------TO BE IMPLEMENTED---------------------
// Testing the intersection of individual phi faces is
// pretty straight forward. The simple thing therefore is to
// form a loop and check them all in sequence.
//
// But, I worry about one day someone making
// a polygon with a thousands sides. A linear search
// would not be ideal in such a case.
//
// So, it would be nice to be able to quickly decide
// which face would be intersected. One can make a very
// good guess by using the intersection with a cone.
// However, this is only reliable in 99% of the cases.
//
// My solution: make a decent guess as to the one or
// two potential faces might get intersected, and then
// test them. If we have the wrong face, use the test
// to make a better guess.
//
// Since we might have two guesses, form a queue of
// potential intersecting faces. Keep an array of
// already tested faces to avoid doing one more than
// once.
//
// Result: at worst, an iterative search. On average,
// a little more than two tests would be required.
//
G4ThreeVector q = p + v;
G4int face = 0;
G4PolyhedraSideVec *vec = vecs;
do {
//
// Correct normal?
//
G4double dotProd = normSign*v.dot(vec->normal);
if (dotProd <= 0) continue;
//
// Is this face in front of the point along the trajectory?
//
G4ThreeVector delta = p - vec->center;
distFromSurface = -normSign*delta.dot(vec->normal);
if (distFromSurface < -surfTolerance) continue;
//
// phi
// c -------- d ^
// | | |
// a -------- b +---> r/z
//
//
// Do we remain on this particular segment?
//
G4ThreeVector qc = q - vec->edges[1]->corner[0];
G4ThreeVector qd = q - vec->edges[1]->corner[1];
if (normSign*qc.cross(qd).dot(v) < 0) continue;
G4ThreeVector qa = q - vec->edges[0]->corner[0];
G4ThreeVector qb = q - vec->edges[0]->corner[1];
if (normSign*qa.cross(qb).dot(v) > 0) continue;
//
// We found the one and only segment we might be intersecting.
// Do we remain within r/z bounds?
//
if (normSign*qa.cross(qc).dot(v) < 0) return false;
if (normSign*qb.cross(qd).dot(v) > 0) return false;
//
// We allow the face to be slightly behind the trajectory
// (surface tolerance) only if the point p is within
// the vicinity of the face
//
if (distFromSurface < 0) {
G4ThreeVector ps = p - vec->center;
G4double rz = ps.dot(vec->surfRZ);
if (fabs(rz) > lenRZ+surfTolerance) return false;
//
// Is the starting point outside z bounds?
//
iStart = (p.z() < cone->ZLo() || p.z() > cone->ZHi()) ? -1 : 0;
if (iStart==0) {
//
// Which phi segment does the starting point p belong to?
//
iStart = PhiSegment( p.phi() );
}
//
// Check for two possible intersections
//
nside = LineHitsSegments( p, v, &i1, &i2 );
if (nside==0) return false;
//
// Try the first side first. LineHitsSegments is suppose to return
// the nearest intersection first. If this succeeds, we are done.
//
if (IntersectSidePlane( p, v, vecs[i1], normSign,
(i1 == iStart) ? surfTolerance : 0,
distance, distFromSurface )) {
normal = vecs[i1].normal;
return true;
}
if (nside==2) {
//
// No luck? Well, we have the second side
//
if (IntersectSidePlane( p, v, vecs[i2], normSign,
(i2 == iStart) ? surfTolerance : 0,
distance, distFromSurface )) {
normal = vecs[i2].normal;
return true;
G4double pp = ps.dot(vec->surfPhi);
if (fabs(pp) > lenPhi[0] + lenPhi[1]*rz + surfTolerance) return false;
}
}
//
// Intersection found. Return answer.
//
distance = distFromSurface/dotProd;
normal = vec->normal;
isAllBehind = allBehind;
return true;
} while( ++vec, ++face < numSide );
//
// Oh well. Better luck next time.
//
@@ -386,7 +497,7 @@ G4double G4PolyhedraSide::Distance( const G4ThreeVector &p, const G4bool outgoin
G4ThreeVector pdotc = p - vecs[iPhi].center;
G4double normDist = pdotc.dot(vecs[iPhi].normal);
if (normSign*normDist > 0) {
if (normSign*normDist > -0.5*kCarTolerance) {
return DistanceAway( p, vecs[iPhi], &normDist );
}
@@ -448,7 +559,7 @@ G4ThreeVector G4PolyhedraSide::Normal( const G4ThreeVector &p, G4double *bestDi
//
G4double G4PolyhedraSide::Extent( const G4ThreeVector axis )
{
if (axis.perp2() < 1.0/kInfinity) {
if (axis.perp2() < DBL_MIN) {
//
// Special case
//
@@ -505,10 +616,8 @@ G4double G4PolyhedraSide::Extent( const G4ThreeVector axis )
void G4PolyhedraSide::CalculateExtent( const EAxis axis,
const G4VoxelLimits &voxelLimit,
const G4AffineTransform &transform,
G4double &min, G4double &max )
G4SolidExtentList &extentList )
{
G4ClippablePolygon polygon;
//
// Loop over all sides
//
@@ -518,7 +627,7 @@ void G4PolyhedraSide::CalculateExtent( const EAxis axis,
// Fill our polygon with the four corners of
// this side, after the specified transformation
//
polygon.ClearAllVertices();
G4ClippablePolygon polygon;
polygon.AddVertexInOrder( transform.TransformPoint( vec->edges[0]->corner[0] ) );
polygon.AddVertexInOrder( transform.TransformPoint( vec->edges[0]->corner[1] ) );
@@ -528,9 +637,17 @@ void G4PolyhedraSide::CalculateExtent( const EAxis axis,
//
// Get extent
//
polygon.Clip( voxelLimit );
polygon.GetExtent( axis, min, max );
if (polygon.PartialClip( voxelLimit, axis )) {
//
// Get dot product of normal along target axis
//
polygon.SetNormal( transform.TransformAxis(vec->normal) );
extentList.AddSurface( polygon );
}
} while( ++vec < vecs+numSide );
return;
}
@@ -548,6 +665,21 @@ void G4PolyhedraSide::CalculateExtent( const EAxis axis,
// = +1.0 normal is unchanged
// = -1.0 normal is reversed (now points inward)
//
// Arguments:
// p - (in) Point
// v - (in) Direction
// vec - (in) Description record of the side plane
// normSign - (in) Sign (+/- 1) to apply to normal
// surfTolerance - (in) Surface tolerance (generally > 0, see below)
// distance - (out) Distance along v to intersection
// distFromSurface - (out) Distance from surface normal
//
// Notes:
// surfTolerance - Used to decide if a point is behind the surface,
// a point is allow to be -surfTolerance behind the
// surface (as measured along the normal), but *only*
// if the point is within the r/z bounds + surfTolerance
// of the segment.
//
G4bool G4PolyhedraSide::IntersectSidePlane( const G4ThreeVector &p, const G4ThreeVector &v,
const G4PolyhedraSideVec vec,
@@ -570,7 +702,7 @@ G4bool G4PolyhedraSide::IntersectSidePlane( const G4ThreeVector &p, const G4Thre
G4ThreeVector delta = p - vec.center;
distFromSurface = -normSign*delta.dot(vec.normal);
if (distFromSurface < surfTolerance) return false;
if (distFromSurface < -surfTolerance) return false;
//
// Calculate precise distance to intersection with the side
@@ -595,6 +727,7 @@ G4bool G4PolyhedraSide::IntersectSidePlane( const G4ThreeVector &p, const G4Thre
//
G4ThreeVector ic = p + distance*v - vec.center;
G4double atRZ = vec.surfRZ.dot(ic);
if (atRZ < 0) {
if (r[0]==0) return true; // Can't miss!
@@ -605,6 +738,10 @@ G4bool G4PolyhedraSide::IntersectSidePlane( const G4ThreeVector &p, const G4Thre
qb = q - vec.edges[1]->corner[0];
G4ThreeVector qacb = qa.cross(qb);
if (normSign*qacb.dot(v) < 0) return false;
if (distFromSurface < 0) {
if (atRZ < -lenRZ-surfTolerance) return false;
}
}
else if (atRZ > 0) {
if (r[1]==0) return true; // Can't miss!
@@ -616,6 +753,10 @@ G4bool G4PolyhedraSide::IntersectSidePlane( const G4ThreeVector &p, const G4Thre
qb = q - vec.edges[1]->corner[1];
G4ThreeVector qacb = qa.cross(qb);
if (normSign*qacb.dot(v) >= 0) return false;
if (distFromSurface < 0) {
if (atRZ > lenRZ+surfTolerance) return false;
}
}
return true;
@@ -625,7 +766,7 @@ G4bool G4PolyhedraSide::IntersectSidePlane( const G4ThreeVector &p, const G4Thre
//
// LineHitsSegments
//
// Calculate which phi segments a line intersections in three dimensions.
// Calculate which phi segments a line intersects in three dimensions.
// No check is made as to whether the intersections are within the z bounds of
// the segment.
//
@@ -638,16 +779,19 @@ G4int G4PolyhedraSide::LineHitsSegments( const G4ThreeVector &p, const G4ThreeVe
//
G4int n = cone->LineHitsCone( p, v, &s1, &s2 );
//
// Check intersections
//
if (n==0) return 0;
//
// Try first intersection.
//
*i1 = PhiSegment( atan2( p.y() + s1*v.y(), p.x() + s1*v.x() ) );
if (n==1) {
return (*i1 < 0) ? 0 : 1;
}
//
// Try second intersection
//
*i2 = PhiSegment( atan2( p.y() + s2*v.y(), p.x() + s2*v.x() ) );
if (*i1 == *i2) return 0;
@@ -681,7 +825,7 @@ G4int G4PolyhedraSide::ClosestPhiSegment( const G4double phi0 )
G4double phi = phi0;
while( phi < startPhi ) phi += 2*M_PI;
G4double d1 = phi-startPhi-deltaPhi;
G4double d1 = phi-endPhi;
while( phi > startPhi ) phi -= 2*M_PI;
G4double d2 = startPhi-phi;
@@ -725,8 +869,6 @@ G4int G4PolyhedraSide::PhiSegment( const G4double phi0 )
}
//
// DistanceToOneSide
//
@@ -737,7 +879,7 @@ G4int G4PolyhedraSide::PhiSegment( const G4double phi0 )
// Return value = total distance from the side
//
G4double G4PolyhedraSide::DistanceToOneSide( const G4ThreeVector &p,
const G4PolyhedraSideVec vec,
const G4PolyhedraSideVec &vec,
G4double *normDist )
{
G4ThreeVector pc = p - vec.center;
@@ -761,7 +903,7 @@ G4double G4PolyhedraSide::DistanceToOneSide( const G4ThreeVector &p,
// and updates normDist appropriate depending on edge normals.
//
G4double G4PolyhedraSide::DistanceAway( const G4ThreeVector &p,
const G4PolyhedraSideVec vec,
const G4PolyhedraSideVec &vec,
G4double *normDist )
{
G4double distOut2;
@@ -796,15 +938,14 @@ G4double G4PolyhedraSide::DistanceAway( const G4ThreeVector &p,
//
// Below in RZ
//
*normDist = pc.dot(vec.edgeNorm[0]);
if (pcDotPhi < -lenPhiZ) {
//
// ...and below in phi. Find distance to point (A)
//
G4double distOutPhi = pcDotPhi+lenPhiZ;
distOut2 = distOutPhi*distOutPhi + distOutZ*distOutZ;
*normDist = pc.dot(vec.edges[0]->cornNorm[0]);
G4ThreeVector pa = p - vec.edges[0]->corner[0];
*normDist = pa.dot(vec.edges[0]->cornNorm[0]);
}
else if (pcDotPhi > lenPhiZ) {
//
@@ -812,14 +953,16 @@ G4double G4PolyhedraSide::DistanceAway( const G4ThreeVector &p,
//
G4double distOutPhi = pcDotPhi-lenPhiZ;
distOut2 = distOutPhi*distOutPhi + distOutZ*distOutZ;
*normDist = pc.dot(vec.edges[1]->cornNorm[0]);
G4ThreeVector pb = p - vec.edges[1]->corner[0];
*normDist = pb.dot(vec.edges[1]->cornNorm[0]);
}
else {
//
// ...and inside in phi. Find distance to line (C)
//
G4ThreeVector pa = p - vec.edges[0]->corner[0];
distOut2 = distOutZ*distOutZ;
*normDist = pc.dot(vec.edgeNorm[0]);
*normDist = pa.dot(vec.edgeNorm[0]);
}
}
else if (pcDotRZ > lenRZ) {
@@ -834,7 +977,8 @@ G4double G4PolyhedraSide::DistanceAway( const G4ThreeVector &p,
//
G4double distOutPhi = pcDotPhi+lenPhiZ;
distOut2 = distOutPhi*distOutPhi + distOutZ*distOutZ;
*normDist = pc.dot(vec.edges[0]->cornNorm[1]);
G4ThreeVector pd = p - vec.edges[0]->corner[1];
*normDist = pd.dot(vec.edges[0]->cornNorm[1]);
}
else if (pcDotPhi > lenPhiZ) {
//
@@ -842,14 +986,16 @@ G4double G4PolyhedraSide::DistanceAway( const G4ThreeVector &p,
//
G4double distOutPhi = pcDotPhi-lenPhiZ;
distOut2 = distOutPhi*distOutPhi + distOutZ*distOutZ;
*normDist = pc.dot(vec.edges[1]->cornNorm[1]);
G4ThreeVector pe = p - vec.edges[1]->corner[1];
*normDist = pe.dot(vec.edges[1]->cornNorm[1]);
}
else {
//
// ...and inside in phi. Find distance to line (F)
//
distOut2 = distOutZ*distOutZ;
*normDist = pc.dot(vec.edgeNorm[1]);
G4ThreeVector pd = p - vec.edges[0]->corner[1];
*normDist = pd.dot(vec.edgeNorm[1]);
}
}
else {
@@ -863,7 +1009,8 @@ G4double G4PolyhedraSide::DistanceAway( const G4ThreeVector &p,
//
G4double distOut = edgeNorm*(pcDotPhi+lenPhiZ);
distOut2 = distOut*distOut;
*normDist = pc.dot(vec.edges[0]->normal);
G4ThreeVector pd = p - vec.edges[0]->corner[1];
*normDist = pd.dot(vec.edges[0]->normal);
}
else if (pcDotPhi > lenPhiZ) {
//
@@ -871,7 +1018,8 @@ G4double G4PolyhedraSide::DistanceAway( const G4ThreeVector &p,
//
G4double distOut = edgeNorm*(pcDotPhi-lenPhiZ);
distOut2 = distOut*distOut;
*normDist = pc.dot(vec.edges[1]->normal);
G4ThreeVector pe = p - vec.edges[1]->corner[1];
*normDist = pe.dot(vec.edges[1]->normal);
}
else {
//
@@ -0,0 +1,462 @@
//
// G4ReduciblePolygon.cc
//
// Implementation of a utility class used to specify, test, reduce,
// and/or otherwise manipulate a 2D polygon.
//
// See G4ReduciblePolygon.hh for more info.
//
// ----------------------------------------------------------
// This code implementation is the intellectual property of
// the GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
#include "G4ReduciblePolygon.hh"
#include "math.h"
//
// Constructor: with simple arrays
//
G4ReduciblePolygon::G4ReduciblePolygon( const G4double a[], const G4double b[], const G4int n )
{
//
// Do all of the real work in Create
//
Create( a, b, n );
}
//
// Constructor: special PGON/PCON case
//
G4ReduciblePolygon::G4ReduciblePolygon( const G4double rmin[], const G4double rmax[],
const G4double z[], const G4int n )
{
//
// Translate
//
G4double *a = new G4double[n*2];
G4double *b = new G4double[n*2];
G4double *rOut = a + n,
*zOut = b + n,
*rIn = rOut-1,
*zIn = zOut-1;
G4int i;
for( i=0; i < n; i++, rOut++, zOut++, rIn--, zIn-- ) {
*rOut = rmax[i];
*rIn = rmin[i];
*zOut = *zIn = z[i];
}
Create( a, b, n*2 );
delete [] a;
delete [] b;
}
//
// Create
//
// To be called by constructors, fill in the list and statistics for a new
// polygon
//
void G4ReduciblePolygon::Create( const G4double a[], const G4double b[], const G4int n )
{
if (n<3) G4Exception( "G4ReduciblePolygon: less than 3 vertices specified" );
const G4double *anext = a, *bnext = b;
ABVertex *prev = 0;
do {
ABVertex *newVertex = new ABVertex;
newVertex->a = *anext;
newVertex->b = *bnext;
newVertex->next = 0;
if (prev==0) {
vertexHead = newVertex;
}
else {
prev->next = newVertex;
}
prev = newVertex;
} while( ++anext, ++bnext < b+n );
numVertices = n;
CalculateMaxMin();
}
//
// Destructor
//
G4ReduciblePolygon::~G4ReduciblePolygon()
{
ABVertex *curr = vertexHead;
while( curr ) {
ABVertex *toDelete = curr;
curr = curr->next;
delete toDelete;
}
}
//
// CopyVertices
//
// Copy contents into simple linear arrays.
// ***** CAUTION ***** Be care to declare the arrays to a large
// enough size!
//
void G4ReduciblePolygon::CopyVertices( G4double a[], G4double b[] ) const
{
G4double *anext = a, *bnext = b;
ABVertex *curr = vertexHead;
while( curr ) {
*anext++ = curr->a;
*bnext++ = curr->b;
curr = curr->next;
}
}
//
// ScaleA
//
// Multiply all a values by a common scale
//
void G4ReduciblePolygon::ScaleA( const G4double scale )
{
ABVertex *curr = vertexHead;
while( curr ) {
curr->a *= scale;
curr = curr->next;
}
}
//
// ScaleB
//
// Multiply all b values by a common scale
//
void G4ReduciblePolygon::ScaleB( const G4double scale )
{
ABVertex *curr = vertexHead;
while( curr ) {
curr->b *= scale;
curr = curr->next;
}
}
//
// RemoveDuplicateVertices
//
// Remove adjacent vertices that are equal. Returns "false" if there
// is a problem (too few vertices remaining).
//
G4bool G4ReduciblePolygon::RemoveDuplicateVertices( const G4double tolerance )
{
ABVertex *curr = vertexHead,
*prev = 0,
*next = curr->next; // A little dangerous
while( curr ) {
next = curr->next;
if (next == 0) next = vertexHead;
if (fabs(curr->a-next->a) < tolerance &&
fabs(curr->b-next->b) < tolerance ) {
//
// Duplicate found: do we have > 3 vertices?
//
if (numVertices <= 3) {
CalculateMaxMin();
return false;
}
//
// Delete
//
ABVertex *toDelete = curr;
curr = curr->next;
delete toDelete;
numVertices--;
if (prev) prev->next = curr; else vertexHead = curr;
}
else {
prev = curr;
curr = curr->next;
}
}
//
// In principle, this is not needed, but why not just play it safe?
//
CalculateMaxMin();
return true;
}
//
// RemoveRedundantVertices
//
// Remove any unneeded vertices, i.e. those vertices which
// are on the line connecting the previous and next vertices.
//
G4bool G4ReduciblePolygon::RemoveRedundantVertices( const G4double tolerance )
{
//
// Under these circumstances, we can quit now!
//
if (numVertices <= 2) return false;
G4double tolerance2 = tolerance*tolerance;
//
// Loop over all vertices
//
ABVertex *curr = vertexHead,
*prev = 0,
*next = curr->next; // A little dangerous
while( curr ) {
next = curr->next;
if (next == 0) next = vertexHead;
G4double da = next->a - curr->a,
db = next->b - curr->b;
//
// Loop over all subsequent vertices, up to curr
//
for(;;) {
//
// Get vertex after next
//
ABVertex *test = next->next;
if (test == 0) test = vertexHead;
//
// If we are back to the original vertex, stop
//
if (test==curr) break;
//
// Test for parallel line segments
//
G4double dat = test->a - curr->a,
dbt = test->b - curr->b;
if (fabs(dat*db-dbt*da)>tolerance2) break;
//
// Redundant vertex found: do we have > 3 vertices?
//
if (numVertices <= 3) {
CalculateMaxMin();
return false;
}
//
// Delete vertex pointed to by next. Carefully!
//
if (curr->next) { // next is not head
if (next->next)
curr->next = test; // next is not tail
else
curr->next = 0; // New tail
}
else
vertexHead = test; // New head
delete next;
numVertices--;
//
// Replace next by the vertex we just tested,
// and keep on going...
//
next = test;
da = dat; db = dbt;
}
curr = curr->next;
}
//
// In principle, this is not needed, but why not just play it safe?
//
CalculateMaxMin();
return true;
}
//
// CrossesItself
//
// Return "true" if the polygon crosses itself
//
// Warning: this routine is not very fast (runs as N**2)
//
G4bool G4ReduciblePolygon::CrossesItself( const G4double tolerance )
{
G4double tolerance2 = tolerance*tolerance;
G4double one = 1.0-tolerance,
zero = tolerance;
//
// Top loop over line segments. By the time we finish
// with the second to last segment, we're done.
//
ABVertex *curr1 = vertexHead, *next1;
while (next1 = curr1->next) {
G4double da1 = next1->a-curr1->a,
db1 = next1->b-curr1->b;
//
// Inner loop over subsequent line segments
//
ABVertex *curr2 = next1->next;
while( curr2 ) {
ABVertex *next2 = curr2->next;
if (next2==0) next2 = vertexHead;
G4double da2 = next2->a-curr2->a,
db2 = next2->b-curr2->b;
G4double a12 = curr2->a-curr1->a,
b12 = curr2->b-curr1->b;
//
// Calculate intersection of the two lines
//
G4double deter = da1*db2 - db1*da2;
if (fabs(deter) > tolerance2) {
G4double s1, s2;
s1 = (a12*db2-b12*da2)/deter;
if (s1 >= zero && s1 < one) {
s2 = -(da1*b12-db1*a12)/deter;
if (s2 >= zero && s2 < one) return true;
}
}
curr2 = curr2->next;
}
curr1 = next1;
}
return false;
}
//
// BisectedBy
//
// Decide if a line through two points crosses the polygon, within tolerance
//
G4bool G4ReduciblePolygon::BisectedBy( const G4double a1, const G4double b1,
const G4double a2, const G4double b2, const G4double tolerance )
{
G4int nNeg = 0, nPos = 0;
G4double a12 = a2-a1, b12 = b2-b1;
G4double len12 = sqrt( a12*a12 + b12*b12 );
a12 /= len12; b12 /= len12;
ABVertex *curr = vertexHead;
do {
G4double av = curr->a - a1,
bv = curr->b - b1;
G4double cross = av*b12 - bv*a12;
if (cross < -tolerance) {
if (nPos) return true;
nNeg++;
}
else if (cross > tolerance) {
if (nNeg) return true;
nPos++;
}
} while( curr = curr->next );
return false;
}
//
// Area
//
// Calculated signed polygon area, where polygons specified in a clockwise manner
// (where x==a, y==b) have negative area
//
// References: [O' Rourke (C)] pp. 18-27; [Gems II] pp. 5-6:
// "The Area of a Simple Polygon", Jon Rokne.
//
G4double G4ReduciblePolygon::Area()
{
G4double answer = 0;
ABVertex *curr = vertexHead, *next;
do {
next = curr->next;
if (next==0) next = vertexHead;
answer += curr->a*next->b - curr->b*next->a;
} while( curr = curr->next );
return 0.5*answer;
}
//
// Print
//
void G4ReduciblePolygon::Print()
{
ABVertex *curr = vertexHead;
do {
G4cerr << curr->a << " " << curr->b << endl;
} while( curr = curr->next );
}
//
// CalculateMaxMin
//
// To be called when the vertices are changed, this
// routine re-calculates global values
//
void G4ReduciblePolygon::CalculateMaxMin()
{
ABVertex *curr = vertexHead;
aMin = aMax = curr->a;
bMin = bMax = curr->b;
curr = curr->next;
while( curr ) {
if (curr->a < aMin)
aMin = curr->a;
else if (curr->a > aMax)
aMax = curr->a;
if (curr->b < bMin)
bMin = curr->b;
else if (curr->b > bMax)
bMax = curr->b;
curr = curr->next;
}
}
@@ -0,0 +1,156 @@
//
// G4SolidExtentList.cc
//
// Implementation of a list of (voxel) extents along one axis
//
// ----------------------------------------------------------
// This code implementation is the intellectual property of
// the GEANT4 collaboration.
//
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
#include "G4SolidExtentList.hh"
#include "G4VoxelLimits.hh"
//
// Constructor (default)
//
G4SolidExtentList::G4SolidExtentList()
{
axis = kZAxis;
limited = false;
minLimit = -DBL_MAX;
maxLimit = +DBL_MAX;
}
//
// Constructor (limited case)
//
G4SolidExtentList::G4SolidExtentList( const EAxis targetAxis, const G4VoxelLimits &voxelLimits )
{
axis = targetAxis;
limited = voxelLimits.IsLimited( axis );
if (limited) {
minLimit = voxelLimits.GetMinExtent( axis );
maxLimit = voxelLimits.GetMaxExtent( axis );
}
else {
minLimit = -DBL_MAX;
maxLimit = +DBL_MAX;
}
}
//
// Destructor
//
G4SolidExtentList::~G4SolidExtentList() {;}
//
// AddSurface
//
//
void G4SolidExtentList::AddSurface( const G4ClippablePolygon &surface )
{
//
// Keep track of four surfaces
//
G4double min, max;
surface.GetExtent( axis, min, max );
if (min > maxLimit) {
//
// Nearest surface beyond maximum limit
//
if (surface.InFrontOf(minAbove,axis)) minAbove = surface;
}
else if (max < minLimit) {
//
// Nearest surface below minimum limit
//
if (surface.BehindOf(maxBelow,axis)) maxBelow = surface;
}
else {
//
// Max and min surfaces inside
//
if (surface.BehindOf(maxSurface,axis)) maxSurface = surface;
if (surface.InFrontOf(minSurface,axis)) minSurface = surface;
}
}
//
// GetExtent
//
// Return extent after processing all surfaces
//
G4bool G4SolidExtentList::GetExtent( G4double &min, G4double &max ) const
{
//
// Did we have any surfaces within the limits?
//
if (minSurface.Empty()) {
//
// Nothing! Do we have anything above?
//
if (minAbove.Empty()) return false;
//
// Yup. Is it facing inwards?
//
if (minAbove.GetNormal().operator()(axis) < 0) return false;
//
// No. We must be entirely within the solid
//
max = maxLimit + kCarTolerance;
min = minLimit - kCarTolerance;
return true;
}
//
// Check max surface
//
if (maxSurface.GetNormal().operator()(axis) < 0) {
//
// Inward facing: max limit must be embedded within solid
//
max = maxLimit + kCarTolerance;
}
else {
G4double sMin, sMax;
maxSurface.GetExtent( axis, sMin, sMax );
max = ( (sMax > maxLimit) ? maxLimit : sMax ) + kCarTolerance;
}
//
// Check min surface
//
if (minSurface.GetNormal().operator()(axis) > 0) {
//
// Inward facing: max limit must be embedded within solid
//
min = minLimit - kCarTolerance;
}
else {
G4double sMin, sMax;
minSurface.GetExtent( axis, sMin, sMax );
min = ( (sMin < minLimit) ? minLimit : sMin ) - kCarTolerance;
}
return true;
}
+8 -8
View File
@@ -5,8 +5,8 @@
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4Sphere.cc,v 2.5 1998/11/25 15:01:12 grichine Exp $
// GEANT4 tag $Name: geant4-00 $
// $Id: G4Sphere.cc,v 1.2 1999/04/16 09:29:55 grichine Exp $
// GEANT4 tag $Name: geant4-00-01 $
//
// class G4Sphere
//
@@ -158,8 +158,8 @@ G4bool G4Sphere::CalculateExtent(const EAxis pAxis,
xMax=xoffset+fRmax;
if (pVoxelLimit.IsXLimited())
{
if (xMin>pVoxelLimit.GetMaxXExtent()
||xMax<pVoxelLimit.GetMinXExtent())
if (xMin>pVoxelLimit.GetMaxXExtent()+kCarTolerance
||xMax<pVoxelLimit.GetMinXExtent()-kCarTolerance)
{
return false;
}
@@ -181,8 +181,8 @@ G4bool G4Sphere::CalculateExtent(const EAxis pAxis,
yMax=yoffset+fRmax;
if (pVoxelLimit.IsYLimited())
{
if (yMin>pVoxelLimit.GetMaxYExtent()
||yMax<pVoxelLimit.GetMinYExtent())
if (yMin>pVoxelLimit.GetMaxYExtent()+kCarTolerance
||yMax<pVoxelLimit.GetMinYExtent()-kCarTolerance)
{
return false;
}
@@ -205,8 +205,8 @@ G4bool G4Sphere::CalculateExtent(const EAxis pAxis,
zMax=zoffset+fRmax;
if (pVoxelLimit.IsZLimited())
{
if (zMin>pVoxelLimit.GetMaxZExtent()
||zMax<pVoxelLimit.GetMinZExtent())
if (zMin>pVoxelLimit.GetMaxZExtent()+kCarTolerance
||zMax<pVoxelLimit.GetMinZExtent()-kCarTolerance)
{
return false;
}
+8 -8
View File
@@ -5,8 +5,8 @@
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4Torus.cc,v 2.3 1998/10/12 14:43:11 grichine Exp $
// GEANT4 tag $Name: geant4-00 $
// $Id: G4Torus.cc,v 1.2 1999/04/16 09:29:55 grichine Exp $
// GEANT4 tag $Name: geant4-00-01 $
//
//
// class G4Torus
@@ -471,8 +471,8 @@ G4bool G4Torus::CalculateExtent(const EAxis pAxis,
xMax=xoffset+fRmax+fRtor;
if (pVoxelLimit.IsXLimited())
{
if (xMin>pVoxelLimit.GetMaxXExtent()
||xMax<pVoxelLimit.GetMinXExtent())
if (xMin>pVoxelLimit.GetMaxXExtent()+kCarTolerance
||xMax<pVoxelLimit.GetMinXExtent()-kCarTolerance)
{
return false;
}
@@ -494,8 +494,8 @@ G4bool G4Torus::CalculateExtent(const EAxis pAxis,
yMax=yoffset+fRmax+fRtor;
if (pVoxelLimit.IsYLimited())
{
if (yMin>pVoxelLimit.GetMaxYExtent()
||yMax<pVoxelLimit.GetMinYExtent())
if (yMin>pVoxelLimit.GetMaxYExtent()+kCarTolerance
||yMax<pVoxelLimit.GetMinYExtent()-kCarTolerance)
{
return false;
}
@@ -518,8 +518,8 @@ G4bool G4Torus::CalculateExtent(const EAxis pAxis,
zMax=zoffset+fRmax;
if (pVoxelLimit.IsZLimited())
{
if (zMin>pVoxelLimit.GetMaxZExtent()
||zMax<pVoxelLimit.GetMinZExtent())
if (zMin>pVoxelLimit.GetMaxZExtent()+kCarTolerance
||zMax<pVoxelLimit.GetMinZExtent()-kCarTolerance)
{
return false;
}
+120 -46
View File
@@ -5,8 +5,8 @@
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4Trap.cc,v 2.1 1998/07/12 02:56:59 urbi Exp $
// GEANT4 tag $Name: geant4-00 $
// $Id: G4Trap.cc,v 1.3 1999/06/04 17:19:16 sgiani Exp $
// GEANT4 tag $Name: geant4-00-01 $
//
// class G4Trap
//
@@ -17,6 +17,7 @@
// 9.9.96 V. Grichine: Final modifications before to commit
// 1.11.96 V.Grichine Costructors for Right Angular Wedge from STEP & G4Trd/Para
// 8.12.97 J.Allison Added "nominal" constructor and method SetAllParameters.
// 4.6.99 S.Giani: Fixed CalculateExtent in rotated case.
#include <math.h>
#include "G4Trap.hh"
@@ -490,19 +491,19 @@ G4bool G4Trap::MakePlane( const G4ThreeVector& p1,
// a,b,c correspond to the x/y/z components of the normal vector to the plane
// a=(p2.y()-p1.y())*(p1.z()+p2.z())+(p3.y()-p2.y())*(p2.z()+p3.z());
// a+=(p4.y()-p3.y())*(p3.z()+p4.z())+(p1.y()-p4.y())*(p4.z()+p1.z()); // may be delete ?
a=(p2.y()-p1.y())*(p1.z()+p2.z())+(p3.y()-p2.y())*(p2.z()+p3.z());
a+=(p4.y()-p3.y())*(p3.z()+p4.z())+(p1.y()-p4.y())*(p4.z()+p1.z()); // may be delete ?
// b=(p2.z()-p1.z())*(p1.x()+p2.x())+(p3.z()-p2.z())*(p2.x()+p3.x());
// b+=(p4.z()-p3.z())*(p3.x()+p4.x())+(p1.z()-p4.z())*(p4.x()+p1.x()); // ?
b=(p2.z()-p1.z())*(p1.x()+p2.x())+(p3.z()-p2.z())*(p2.x()+p3.x());
b+=(p4.z()-p3.z())*(p3.x()+p4.x())+(p1.z()-p4.z())*(p4.x()+p1.x()); // ?
// c=(p2.x()-p1.x())*(p1.y()+p2.y())+(p3.x()-p2.x())*(p2.y()+p3.y());
// c+=(p4.x()-p3.x())*(p3.y()+p4.y())+(p1.x()-p4.x())*(p4.y()+p1.y()); // ?
c=(p2.x()-p1.x())*(p1.y()+p2.y())+(p3.x()-p2.x())*(p2.y()+p3.y());
c+=(p4.x()-p3.x())*(p3.y()+p4.y())+(p1.x()-p4.x())*(p4.y()+p1.y()); // ?
// Let create diagonals 4-2 and 3-1 than (4-2)x(3-1) provides vector perpendicular to the
// plane directed to outside !!! and a,b,c, = f(1,2,3,4)
a = +(p4.y() - p2.y())*(p3.z() - p1.z()) - (p3.y() - p1.y())*(p4.z() - p2.z()) ;
b = -(p4.x() - p2.x())*(p3.z() - p1.z()) + (p3.x() - p1.x())*(p4.z() - p2.z()) ;
c = +(p4.x() - p2.x())*(p3.y() - p1.y()) - (p3.x() - p1.x())*(p4.y() - p2.y()) ;
//a = +(p4.y() - p2.y())*(p3.z() - p1.z()) - (p3.y() - p1.y())*(p4.z() - p2.z()) ;
//b = -(p4.x() - p2.x())*(p3.z() - p1.z()) + (p3.x() - p1.x())*(p4.z() - p2.z()) ;
//c = +(p4.x() - p2.x())*(p3.y() - p1.y()) - (p3.x() - p1.x())*(p4.y() - p2.y()) ;
s=sqrt(a*a+b*b+c*c); // so now vector plane.(a,b,c) is unit
plane.a=a/s;
plane.b=b/s;
@@ -538,6 +539,8 @@ G4bool G4Trap::CalculateExtent(const EAxis pAxis,
const G4AffineTransform& pTransform,
G4double& pMin, G4double& pMax) const
{
G4double xMin, xMax, yMin, yMax, zMin, zMax;
G4bool flag;
if (!pTransform.IsRotated())
@@ -546,9 +549,9 @@ G4bool G4Trap::CalculateExtent(const EAxis pAxis,
// Compute z/x/y/ mins and maxs respecting limits, with early returns
// if outside limits. Then switch() on pAxis
G4int i ;
G4double xoffset,xMin,xMax;
G4double yoffset,yMin,yMax;
G4double zoffset,zMin,zMax;
G4double xoffset;
G4double yoffset;
G4double zoffset;
G4double temp[8] ; // some points for intersection with zMin/zMax
xoffset=pTransform.NetTranslation().x();
@@ -576,8 +579,8 @@ G4bool G4Trap::CalculateExtent(const EAxis pAxis,
zMax=zoffset+fDz;
if (pVoxelLimit.IsZLimited())
{
if (zMin>pVoxelLimit.GetMaxZExtent()
||zMax<pVoxelLimit.GetMinZExtent())
if (zMin>pVoxelLimit.GetMaxZExtent()+kCarTolerance
||zMax<pVoxelLimit.GetMinZExtent()-kCarTolerance)
{
return false;
}
@@ -608,8 +611,8 @@ G4bool G4Trap::CalculateExtent(const EAxis pAxis,
if (pVoxelLimit.IsYLimited())
{
if (yMin>pVoxelLimit.GetMaxYExtent()
||yMax<pVoxelLimit.GetMinYExtent())
if (yMin>pVoxelLimit.GetMaxYExtent()+kCarTolerance
||yMax<pVoxelLimit.GetMinYExtent()-kCarTolerance)
{
return false;
}
@@ -645,8 +648,8 @@ G4bool G4Trap::CalculateExtent(const EAxis pAxis,
// xMax/Min = f(yMax/Min) ?
if (pVoxelLimit.IsXLimited())
{
if (xMin>pVoxelLimit.GetMaxXExtent()
||xMax<pVoxelLimit.GetMinXExtent())
if (xMin>pVoxelLimit.GetMaxXExtent()+kCarTolerance
||xMax<pVoxelLimit.GetMinXExtent()-kCarTolerance)
{
return false;
}
@@ -686,48 +689,119 @@ G4bool G4Trap::CalculateExtent(const EAxis pAxis,
}
else
{
// General rotated case - create and clip mesh to boundaries
// General rotated case -
G4bool existsAfterClip=false;
G4ThreeVectorList *vertices;
pMin=+kInfinity;
pMax=-kInfinity;
// Calculate rotated vertex coordinates
vertices=CreateRotatedVertices(pTransform);
ClipCrossSection(vertices,0,pVoxelLimit,pAxis,pMin,pMax);
ClipCrossSection(vertices,4,pVoxelLimit,pAxis,pMin,pMax);
ClipBetweenSections(vertices,0,pVoxelLimit,pAxis,pMin,pMax);
xMin = +kInfinity; yMin = +kInfinity; zMin = +kInfinity;
xMax = -kInfinity; yMax = -kInfinity; zMax = -kInfinity;
for(G4int nv=0; nv<8; nv++){
if((*vertices)[nv].x() > xMax){xMax = (*vertices)[nv].x();};
if((*vertices)[nv].y() > yMax){yMax = (*vertices)[nv].y();};
if((*vertices)[nv].z() > zMax){zMax = (*vertices)[nv].z();};
if((*vertices)[nv].x() < xMin){xMin = (*vertices)[nv].x();};
if((*vertices)[nv].y() < yMin){yMin = (*vertices)[nv].y();};
if((*vertices)[nv].z() < zMin){zMin = (*vertices)[nv].z();};
};
if (pVoxelLimit.IsZLimited())
{
if (zMin>pVoxelLimit.GetMaxZExtent()+kCarTolerance
||zMax<pVoxelLimit.GetMinZExtent()-kCarTolerance)
{
return false;
}
else
{
if (zMin<pVoxelLimit.GetMinZExtent())
{
zMin=pVoxelLimit.GetMinZExtent();
}
if (zMax>pVoxelLimit.GetMaxZExtent())
{
zMax=pVoxelLimit.GetMaxZExtent();
}
}
}
if (pVoxelLimit.IsYLimited())
{
if (yMin>pVoxelLimit.GetMaxYExtent()+kCarTolerance
||yMax<pVoxelLimit.GetMinYExtent()-kCarTolerance)
{
return false;
}
else
{
if (yMin<pVoxelLimit.GetMinYExtent())
{
yMin=pVoxelLimit.GetMinYExtent();
}
if (yMax>pVoxelLimit.GetMaxYExtent())
{
yMax=pVoxelLimit.GetMaxYExtent();
}
}
}
if (pVoxelLimit.IsXLimited())
{
if (xMin>pVoxelLimit.GetMaxXExtent()+kCarTolerance
||xMax<pVoxelLimit.GetMinXExtent()-kCarTolerance)
{
return false;
}
else
{
if (xMin<pVoxelLimit.GetMinXExtent())
{
xMin=pVoxelLimit.GetMinXExtent();
}
if (xMax>pVoxelLimit.GetMaxXExtent())
{
xMax=pVoxelLimit.GetMaxXExtent();
}
}
}
switch (pAxis)
{
case kXAxis:
pMin=xMin;
pMax=xMax;
break;
case kYAxis:
pMin=yMin;
pMax=yMax;
break;
case kZAxis:
pMin=zMin;
pMax=zMax;
break;
}
if (pMin!=kInfinity||pMax!=-kInfinity)
{
existsAfterClip=true;
// Add 2*tolerance to avoid precision troubles
// Add tolerance to avoid precision troubles
pMin-=kCarTolerance;
pMax+=kCarTolerance;
}
else
{
// Check for case where completely enveloping clipping volume
// If point inside then we are confident that the solid completely
// envelopes the clipping volume. Hence set min/max extents according
// to clipping volume extents along the specified axis.
G4ThreeVector clipCentre(
(pVoxelLimit.GetMinXExtent()+pVoxelLimit.GetMaxXExtent())*0.5,
(pVoxelLimit.GetMinYExtent()+pVoxelLimit.GetMaxYExtent())*0.5,
(pVoxelLimit.GetMinZExtent()+pVoxelLimit.GetMaxZExtent())*0.5);
if (Inside(pTransform.Inverse().TransformPoint(clipCentre))!=kOutside)
{
existsAfterClip=true;
pMin=pVoxelLimit.GetMinExtent(pAxis);
pMax=pVoxelLimit.GetMaxExtent(pAxis);
}
}
};
delete vertices ; // 'new' in the function called
flag = existsAfterClip ;
}
+8 -8
View File
@@ -5,8 +5,8 @@
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4Trd.cc,v 2.1 1998/07/12 02:57:00 urbi Exp $
// GEANT4 tag $Name: geant4-00 $
// $Id: G4Trd.cc,v 1.2 1999/04/16 09:29:56 grichine Exp $
// GEANT4 tag $Name: geant4-00-01 $
//
//
// Implementation for G4Trd class
@@ -118,8 +118,8 @@ G4bool G4Trd::CalculateExtent(const EAxis pAxis,
zMax=zoffset+fDz;
if (pVoxelLimit.IsZLimited())
{
if (zMin>pVoxelLimit.GetMaxZExtent()
||zMax<pVoxelLimit.GetMinZExtent())
if (zMin>pVoxelLimit.GetMaxZExtent()+kCarTolerance
||zMax<pVoxelLimit.GetMinZExtent()-kCarTolerance)
{
return false;
}
@@ -150,8 +150,8 @@ G4bool G4Trd::CalculateExtent(const EAxis pAxis,
}
if (pVoxelLimit.IsXLimited())
{
if (xMin>pVoxelLimit.GetMaxXExtent()
||xMax<pVoxelLimit.GetMinXExtent())
if (xMin>pVoxelLimit.GetMaxXExtent()+kCarTolerance
||xMax<pVoxelLimit.GetMinXExtent()-kCarTolerance)
{
return false;
}
@@ -182,8 +182,8 @@ G4bool G4Trd::CalculateExtent(const EAxis pAxis,
}
if (pVoxelLimit.IsYLimited())
{
if (yMin>pVoxelLimit.GetMaxYExtent()
||yMax<pVoxelLimit.GetMinYExtent())
if (yMin>pVoxelLimit.GetMaxYExtent()+kCarTolerance
||yMax<pVoxelLimit.GetMinYExtent()-kCarTolerance)
{
return false;
}
+10 -8
View File
@@ -5,8 +5,8 @@
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
// $Id: G4Tubs.cc,v 2.3 1998/10/09 17:17:21 grichine Exp $
// GEANT4 tag $Name: geant4-00 $
// $Id: G4Tubs.cc,v 1.7 1999/06/04 12:43:35 japost Exp $
// GEANT4 tag $Name: geant4-00-01 $
//
//
// class G4Tubs
@@ -14,6 +14,7 @@
// Implementation
// 18.06.98 n-normalisation in DistanceToOut(p.v) V. Grichine
// 09.10.98 V. Grichine modifications in Distance ToOut(p,v,...)
// 23.03.99 V.Grichine, bug fixed in DistanceToIn(p,v)
#include "G4Tubs.hh"
@@ -137,8 +138,8 @@ G4bool G4Tubs::CalculateExtent(const EAxis pAxis,
xMax=xoffset+fRMax;
if (pVoxelLimit.IsXLimited())
{
if (xMin>pVoxelLimit.GetMaxXExtent()
||xMax<pVoxelLimit.GetMinXExtent())
if (xMin>pVoxelLimit.GetMaxXExtent()+kCarTolerance
||xMax<pVoxelLimit.GetMinXExtent()-kCarTolerance)
{
return false;
}
@@ -160,8 +161,8 @@ G4bool G4Tubs::CalculateExtent(const EAxis pAxis,
yMax=yoffset+fRMax;
if (pVoxelLimit.IsYLimited())
{
if (yMin>pVoxelLimit.GetMaxYExtent()
||yMax<pVoxelLimit.GetMinYExtent())
if (yMin>pVoxelLimit.GetMaxYExtent()+kCarTolerance
||yMax<pVoxelLimit.GetMinYExtent()-kCarTolerance)
{
return false;
}
@@ -184,8 +185,8 @@ G4bool G4Tubs::CalculateExtent(const EAxis pAxis,
zMax=zoffset+fDz;
if (pVoxelLimit.IsZLimited())
{
if (zMin>pVoxelLimit.GetMaxZExtent()
||zMax<pVoxelLimit.GetMinZExtent())
if (zMin>pVoxelLimit.GetMaxZExtent()+kCarTolerance
||zMax<pVoxelLimit.GetMinZExtent()-kCarTolerance)
{
return false;
}
@@ -662,6 +663,7 @@ G4double G4Tubs::DistanceToIn(const G4ThreeVector& p,
if (p.z()*v.z()<0) // at +Z going in -Z or visa versa
{
s=(fabs(p.z())-fDz)/fabs(v.z()); // Z intersect distance
if(s<0.0) s = 0.0 ; // negative dist -> zero
xi=p.x()+s*v.x(); // Intersection coords
yi=p.y()+s*v.y();
rho2=xi*xi+yi*yi;
+83 -72
View File
@@ -4,43 +4,17 @@
// Implementation of the virtual class of a CSG type shape that is built
// entirely out of G4VCSGface faces.
//
// \begin{preach mode}
// ----------------------------------------------------------
// This code implementation is the intellectual property of
// the GEANT4 collaboration.
//
// Do not be fooled by the content, the algorithms in here are not
// very clever. This is obvious if one (tries) to read a good textbook
// on 3D modeling.
//
// GEANT4 has some rather esoteric demands on its geometric models,
// which makes most canned 3D routines not useful. So we have to
// try to invent a few. This is dangerous, because 3D modeling is
// a serious programming game.
//
// One of the real simplifications in the methods I've used here for
// a shape is that each face of a solid is treated separately. Or, at
// least this is the illusion. In fact, for non-convex solids (which
// abound in GEANT4), the face routine Inside cannot be correctly written
// unless each face knows something about all of it's neighbor. Furthermore,
// is is absolutely *crucial* that the algebraic instructions for
// deciding if a track intersection falls outside a face matches
// for the edge between adjacent faces. If not, THERE WILL BE A
// CRACK IN YOUR SOLID, GUARANTEED. It will be small, but it will
// be there.
//
// So? If we were writing a 3D display routine, cracks wouldn't
// matter. But we are writing instead a tracking simulation. One crack,
// and things may fall about very quickly. Probably not, if you generate a
// 100 events, or a thousand, but millions?? *BEWARE*
//
// Note that none of this is obvious in the pretty code below. Such
// invisible interdependencies are a evil sin for a software designer.
// So, I *confess*.
//
// Now, I should explain what you have to do.
//
// \end{preach mode}
// By copying, distributing or modifying the Program (or any work
// based on the Program) you indicate your acceptance of this statement,
// and all its terms.
//
#include "G4VCSGfaceted.hh"
#include "G4VCSGface.hh"
#include "G4SolidExtentList.hh"
#include "G4VoxelLimits.hh"
#include "G4AffineTransform.hh"
@@ -56,56 +30,93 @@
//
G4VCSGfaceted::~G4VCSGfaceted()
{
G4VCSGface **face = faces;
do {
delete *face;
} while( ++face < faces + numFace );
DeleteStuff();
}
//
// Copy constructor
//
G4VCSGfaceted::G4VCSGfaceted( const G4VCSGfaceted &source ) : G4CSGSolid( source )
{
CopyStuff( source );
}
//
// Assignment operator
//
const G4VCSGfaceted &G4VCSGfaceted::operator=( const G4VCSGfaceted &source )
{
if (&source == this) return *this;
delete [] faces;
DeleteStuff();
CopyStuff( source );
return *this;
}
//
// CopyStuff (protected)
//
// Copy the contents of source
//
void G4VCSGfaceted::CopyStuff( const G4VCSGfaceted &source )
{
numFace = source.numFace;
if (numFace == 0) return; // odd, but permissable?
faces = new G4VCSGface*[numFace];
G4VCSGface **face = faces,
**sourceFace = source.faces;
do {
*face = (*sourceFace)->Clone();
} while( ++sourceFace, ++face < faces+numFace );
}
//
// DeleteStuff (protected)
//
// Delete all allocated objects
//
void G4VCSGfaceted::DeleteStuff()
{
if (numFace) {
G4VCSGface **face = faces;
do {
delete *face;
} while( ++face < faces + numFace );
delete [] faces;
}
}
//
// CalculateExtent
//
G4bool G4VCSGfaceted::CalculateExtent( const EAxis pAxis,
const G4VoxelLimits& pVoxelLimit,
const G4AffineTransform& pTransform,
G4double &pMin, G4double &pMax ) const
G4bool G4VCSGfaceted::CalculateExtent( const EAxis axis,
const G4VoxelLimits &voxelLimit,
const G4AffineTransform &transform,
G4double &min, G4double &max ) const
{
//
// Loop over all faces, testing each as we go
//
G4VCSGface **face = faces;
G4double max = -kInfinity, min = +kInfinity;
do {
(*face)->CalculateExtent( pAxis, pVoxelLimit, pTransform, min, max );
} while( ++face < faces + numFace );
G4SolidExtentList extentList( axis, voxelLimit );
//
// Any luck?
// Loop over all faces, checking min/max extent as we go.
//
if (max == -kInfinity) return false;
G4VCSGface **face = faces;
do {
(*face)->CalculateExtent( axis, voxelLimit, transform, extentList );
} while( ++face < faces + numFace );
//
// What are the voxel limits along this particular axis?
// Return min/max value
//
if (pVoxelLimit.IsLimited(pAxis)) {
G4double vMax = pVoxelLimit.GetMaxExtent(pAxis),
vMin = pVoxelLimit.GetMinExtent(pAxis);
if (max < vMin) return false;
if (min > vMax) return false;
pMin = min < vMin ? vMin : min;
pMax = max > vMax ? vMax : max;
}
else {
pMin = min;
pMax = max;
}
return true;
return extentList.GetExtent( min, max );
}
@@ -135,6 +146,7 @@ EInside G4VCSGfaceted::Inside( const G4ThreeVector &p ) const
return answer;
}
//
// SurfaceNormal
//
@@ -155,6 +167,7 @@ G4ThreeVector G4VCSGfaceted::SurfaceNormal( const G4ThreeVector& p) const
return answer;
}
//
// DistanceToIn(p,v)
//
@@ -268,7 +281,7 @@ G4double G4VCSGfaceted::DistanceTo( const G4ThreeVector &p, const G4bool outgoin
if (distance < best) best = distance;
} while( ++face < faces + numFace );
return best;
return (best < 0.5*kCarTolerance) ? 0 : best;
}
@@ -284,8 +297,6 @@ void G4VCSGfaceted::DescribeYourselfTo( G4VGraphicsScene& scene ) const
//
// GetExtent
//
// This routine might need testing
//
G4VisExtent G4VCSGfaceted::GetExtent() const
{
G4ThreeVector plusX(1,0,0), minusX(-1,0,0),