Files
geant4/source/geometry/solids/specific/src/G4VTwistedFaceted.cc
T
2018-12-07 15:15:39 +01:00

1178 lines
35 KiB
C++

//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
//
//
// --------------------------------------------------------------------
// GEANT 4 class source file
//
//
// G4VTwistedFaceted.cc
//
// Author:
//
// 04-Nov-2004 - O.Link (Oliver.Link@cern.ch)
//
// --------------------------------------------------------------------
#include "G4VTwistedFaceted.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
#include "G4VoxelLimits.hh"
#include "G4AffineTransform.hh"
#include "G4BoundingEnvelope.hh"
#include "G4SolidExtentList.hh"
#include "G4ClippablePolygon.hh"
#include "G4VPVParameterisation.hh"
#include "G4GeometryTolerance.hh"
#include "meshdefs.hh"
#include "G4VGraphicsScene.hh"
#include "G4Polyhedron.hh"
#include "G4VisExtent.hh"
#include "Randomize.hh"
#include "G4AutoLock.hh"
namespace
{
G4Mutex polyhedronMutex = G4MUTEX_INITIALIZER;
}
//=====================================================================
//* constructors ------------------------------------------------------
G4VTwistedFaceted::
G4VTwistedFaceted( const G4String &pname, // Name of instance
G4double PhiTwist, // twist angle
G4double pDz, // half z length
G4double pTheta, // direction between end planes
G4double pPhi, // defined by polar and azim. angles
G4double pDy1, // half y length at -pDz
G4double pDx1, // half x length at -pDz,-pDy
G4double pDx2, // half x length at -pDz,+pDy
G4double pDy2, // half y length at +pDz
G4double pDx3, // half x length at +pDz,-pDy
G4double pDx4, // half x length at +pDz,+pDy
G4double pAlph // tilt angle
)
: G4VSolid(pname), fRebuildPolyhedron(false), fpPolyhedron(0),
fLowerEndcap(0), fUpperEndcap(0), fSide0(0),
fSide90(0), fSide180(0), fSide270(0),
fSurfaceArea(0.)
{
G4double pDytmp ;
G4double fDxUp ;
G4double fDxDown ;
fDx1 = pDx1 ;
fDx2 = pDx2 ;
fDx3 = pDx3 ;
fDx4 = pDx4 ;
fDy1 = pDy1 ;
fDy2 = pDy2 ;
fDz = pDz ;
G4double kAngTolerance
= G4GeometryTolerance::GetInstance()->GetAngularTolerance();
// maximum values
//
fDxDown = ( fDx1 > fDx2 ? fDx1 : fDx2 ) ;
fDxUp = ( fDx3 > fDx4 ? fDx3 : fDx4 ) ;
fDx = ( fDxUp > fDxDown ? fDxUp : fDxDown ) ;
fDy = ( fDy1 > fDy2 ? fDy1 : fDy2 ) ;
// planarity check
//
if ( fDx1 != fDx2 && fDx3 != fDx4 )
{
pDytmp = fDy1 * ( fDx3 - fDx4 ) / ( fDx1 - fDx2 ) ;
if ( std::fabs(pDytmp - fDy2) > kCarTolerance )
{
std::ostringstream message;
message << "Not planar surface in untwisted Trapezoid: "
<< GetName() << G4endl
<< "fDy2 is " << fDy2 << " but should be "
<< pDytmp << ".";
G4Exception("G4VTwistedFaceted::G4VTwistedFaceted()", "GeomSolids0002",
FatalErrorInArgument, message);
}
}
#ifdef G4TWISTDEBUG
if ( fDx1 == fDx2 && fDx3 == fDx4 )
{
G4cout << "Trapezoid is a box" << G4endl ;
}
#endif
if ( ( fDx1 == fDx2 && fDx3 != fDx4 ) || ( fDx1 != fDx2 && fDx3 == fDx4 ) )
{
std::ostringstream message;
message << "Not planar surface in untwisted Trapezoid: "
<< GetName() << G4endl
<< "One endcap is rectangular, the other is a trapezoid." << G4endl
<< "For planarity reasons they have to be rectangles or trapezoids "
<< "on both sides.";
G4Exception("G4VTwistedFaceted::G4VTwistedFaceted()", "GeomSolids0002",
FatalErrorInArgument, message);
}
// twist angle
//
fPhiTwist = PhiTwist ;
// tilt angle
//
fAlph = pAlph ;
fTAlph = std::tan(fAlph) ;
fTheta = pTheta ;
fPhi = pPhi ;
// dx in surface equation
//
fdeltaX = 2 * fDz * std::tan(fTheta) * std::cos(fPhi) ;
// dy in surface equation
//
fdeltaY = 2 * fDz * std::tan(fTheta) * std::sin(fPhi) ;
if ( ! ( ( fDx1 > 2*kCarTolerance)
&& ( fDx2 > 2*kCarTolerance)
&& ( fDx3 > 2*kCarTolerance)
&& ( fDx4 > 2*kCarTolerance)
&& ( fDy1 > 2*kCarTolerance)
&& ( fDy2 > 2*kCarTolerance)
&& ( fDz > 2*kCarTolerance)
&& ( std::fabs(fPhiTwist) > 2*kAngTolerance )
&& ( std::fabs(fPhiTwist) < pi/2 )
&& ( std::fabs(fAlph) < pi/2 )
&& ( fTheta < pi/2 && fTheta >= 0 ) )
)
{
std::ostringstream message;
message << "Invalid dimensions. Too small, or twist angle too big: "
<< GetName() << G4endl
<< "fDx 1-4 = " << fDx1/cm << ", " << fDx2/cm << ", "
<< fDx3/cm << ", " << fDx4/cm << " cm" << G4endl
<< "fDy 1-2 = " << fDy1/cm << ", " << fDy2/cm << ", "
<< " cm" << G4endl
<< "fDz = " << fDz/cm << " cm" << G4endl
<< " twistangle " << fPhiTwist/deg << " deg" << G4endl
<< " phi,theta = " << fPhi/deg << ", " << fTheta/deg << " deg";
G4Exception("G4TwistedTrap::G4VTwistedFaceted()",
"GeomSolids0002", FatalErrorInArgument, message);
}
CreateSurfaces();
fCubicVolume = 2 * fDz * ( ( fDx1 + fDx2 ) * fDy1 + ( fDx3 + fDx4 ) * fDy2 );
}
//=====================================================================
//* Fake default constructor ------------------------------------------
G4VTwistedFaceted::G4VTwistedFaceted( __void__& a )
: G4VSolid(a), fRebuildPolyhedron(false), fpPolyhedron(0),
fTheta(0.), fPhi(0.), fDy1(0.),
fDx1(0.), fDx2(0.), fDy2(0.), fDx3(0.), fDx4(0.),
fDz(0.), fDx(0.), fDy(0.), fAlph(0.),
fTAlph(0.), fdeltaX(0.), fdeltaY(0.), fPhiTwist(0.),
fLowerEndcap(0), fUpperEndcap(0), fSide0(0), fSide90(0), fSide180(0),
fSide270(0), fCubicVolume(0.), fSurfaceArea(0.)
{
}
//=====================================================================
//* destructor --------------------------------------------------------
G4VTwistedFaceted::~G4VTwistedFaceted()
{
if (fLowerEndcap) { delete fLowerEndcap ; }
if (fUpperEndcap) { delete fUpperEndcap ; }
if (fSide0) { delete fSide0 ; }
if (fSide90) { delete fSide90 ; }
if (fSide180) { delete fSide180 ; }
if (fSide270) { delete fSide270 ; }
if (fpPolyhedron) { delete fpPolyhedron; fpPolyhedron = 0; }
}
//=====================================================================
//* Copy constructor --------------------------------------------------
G4VTwistedFaceted::G4VTwistedFaceted(const G4VTwistedFaceted& rhs)
: G4VSolid(rhs), fRebuildPolyhedron(false), fpPolyhedron(0),
fTheta(rhs.fTheta), fPhi(rhs.fPhi),
fDy1(rhs.fDy1), fDx1(rhs.fDx1), fDx2(rhs.fDx2), fDy2(rhs.fDy2),
fDx3(rhs.fDx3), fDx4(rhs.fDx4), fDz(rhs.fDz), fDx(rhs.fDx), fDy(rhs.fDy),
fAlph(rhs.fAlph), fTAlph(rhs.fTAlph), fdeltaX(rhs.fdeltaX),
fdeltaY(rhs.fdeltaY), fPhiTwist(rhs.fPhiTwist), fLowerEndcap(0),
fUpperEndcap(0), fSide0(0), fSide90(0), fSide180(0), fSide270(0),
fCubicVolume(rhs.fCubicVolume), fSurfaceArea(rhs.fSurfaceArea),
fLastInside(rhs.fLastInside), fLastNormal(rhs.fLastNormal),
fLastDistanceToIn(rhs.fLastDistanceToIn),
fLastDistanceToOut(rhs.fLastDistanceToOut),
fLastDistanceToInWithV(rhs.fLastDistanceToInWithV),
fLastDistanceToOutWithV(rhs.fLastDistanceToOutWithV)
{
CreateSurfaces();
}
//=====================================================================
//* Assignment operator -----------------------------------------------
G4VTwistedFaceted& G4VTwistedFaceted::operator = (const G4VTwistedFaceted& rhs)
{
// Check assignment to self
//
if (this == &rhs) { return *this; }
// Copy base class data
//
G4VSolid::operator=(rhs);
// Copy data
//
fTheta = rhs.fTheta; fPhi = rhs.fPhi;
fDy1= rhs.fDy1; fDx1= rhs.fDx1; fDx2= rhs.fDx2; fDy2= rhs.fDy2;
fDx3= rhs.fDx3; fDx4= rhs.fDx4; fDz= rhs.fDz; fDx= rhs.fDx; fDy= rhs.fDy;
fAlph= rhs.fAlph; fTAlph= rhs.fTAlph; fdeltaX= rhs.fdeltaX;
fdeltaY= rhs.fdeltaY; fPhiTwist= rhs.fPhiTwist; fLowerEndcap= 0;
fUpperEndcap= 0; fSide0= 0; fSide90= 0; fSide180= 0; fSide270= 0;
fCubicVolume= rhs.fCubicVolume; fSurfaceArea= rhs.fSurfaceArea;
fRebuildPolyhedron = false;
delete fpPolyhedron; fpPolyhedron= 0;
fLastInside= rhs.fLastInside; fLastNormal= rhs.fLastNormal;
fLastDistanceToIn= rhs.fLastDistanceToIn;
fLastDistanceToOut= rhs.fLastDistanceToOut;
fLastDistanceToInWithV= rhs.fLastDistanceToInWithV;
fLastDistanceToOutWithV= rhs.fLastDistanceToOutWithV;
CreateSurfaces();
return *this;
}
//=====================================================================
//* ComputeDimensions -------------------------------------------------
void G4VTwistedFaceted::ComputeDimensions(G4VPVParameterisation* ,
const G4int ,
const G4VPhysicalVolume* )
{
G4Exception("G4VTwistedFaceted::ComputeDimensions()",
"GeomSolids0001", FatalException,
"G4VTwistedFaceted does not support Parameterisation.");
}
//=====================================================================
//* Extent ------------------------------------------------------------
void G4VTwistedFaceted::BoundingLimits(G4ThreeVector &pMin,
G4ThreeVector &pMax) const
{
G4double maxRad = std::sqrt(fDx*fDx + fDy*fDy);
pMin.set(-maxRad,-maxRad,-fDz);
pMax.set( maxRad, maxRad, fDz);
}
//=====================================================================
//* CalculateExtent ---------------------------------------------------
G4bool
G4VTwistedFaceted::CalculateExtent( const EAxis pAxis,
const G4VoxelLimits &pVoxelLimit,
const G4AffineTransform &pTransform,
G4double &pMin,
G4double &pMax ) const
{
G4ThreeVector bmin, bmax;
// Get bounding box
BoundingLimits(bmin,bmax);
// Find extent
G4BoundingEnvelope bbox(bmin,bmax);
return bbox.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax);
}
//=====================================================================
//* Inside ------------------------------------------------------------
EInside G4VTwistedFaceted::Inside(const G4ThreeVector& p) const
{
G4ThreeVector *tmpp;
EInside *tmpin;
if (fLastInside.p == p) {
return fLastInside.inside;
} else {
tmpp = const_cast<G4ThreeVector*>(&(fLastInside.p));
tmpin = const_cast<EInside*>(&(fLastInside.inside));
tmpp->set(p.x(), p.y(), p.z());
}
*tmpin = kOutside ;
G4double phi = p.z()/(2*fDz) * fPhiTwist ; // rotate the point to z=0
G4double cphi = std::cos(-phi) ;
G4double sphi = std::sin(-phi) ;
G4double px = p.x() + fdeltaX * ( -phi/fPhiTwist) ; // shift
G4double py = p.y() + fdeltaY * ( -phi/fPhiTwist) ;
G4double pz = p.z() ;
G4double posx = px * cphi - py * sphi ; // rotation
G4double posy = px * sphi + py * cphi ;
G4double posz = pz ;
G4double xMin = Xcoef(posy,phi,fTAlph) - 2*Xcoef(posy,phi,0.) ;
G4double xMax = Xcoef(posy,phi,fTAlph) ;
G4double yMax = GetValueB(phi)/2. ; // b(phi)/2 is limit
G4double yMin = -yMax ;
#ifdef G4TWISTDEBUG
G4cout << "inside called: p = " << p << G4endl ;
G4cout << "fDx1 = " << fDx1 << G4endl ;
G4cout << "fDx2 = " << fDx2 << G4endl ;
G4cout << "fDx3 = " << fDx3 << G4endl ;
G4cout << "fDx4 = " << fDx4 << G4endl ;
G4cout << "fDy1 = " << fDy1 << G4endl ;
G4cout << "fDy2 = " << fDy2 << G4endl ;
G4cout << "fDz = " << fDz << G4endl ;
G4cout << "Tilt angle alpha = " << fAlph << G4endl ;
G4cout << "phi,theta = " << fPhi << " , " << fTheta << G4endl ;
G4cout << "Twist angle = " << fPhiTwist << G4endl ;
G4cout << "posx = " << posx << G4endl ;
G4cout << "posy = " << posy << G4endl ;
G4cout << "xMin = " << xMin << G4endl ;
G4cout << "xMax = " << xMax << G4endl ;
G4cout << "yMin = " << yMin << G4endl ;
G4cout << "yMax = " << yMax << G4endl ;
#endif
if ( posx <= xMax - kCarTolerance*0.5
&& posx >= xMin + kCarTolerance*0.5 )
{
if ( posy <= yMax - kCarTolerance*0.5
&& posy >= yMin + kCarTolerance*0.5 )
{
if (std::fabs(posz) <= fDz - kCarTolerance*0.5 ) *tmpin = kInside ;
else if (std::fabs(posz) <= fDz + kCarTolerance*0.5 ) *tmpin = kSurface ;
}
else if ( posy <= yMax + kCarTolerance*0.5
&& posy >= yMin - kCarTolerance*0.5 )
{
if (std::fabs(posz) <= fDz + kCarTolerance*0.5 ) *tmpin = kSurface ;
}
}
else if ( posx <= xMax + kCarTolerance*0.5
&& posx >= xMin - kCarTolerance*0.5 )
{
if ( posy <= yMax + kCarTolerance*0.5
&& posy >= yMin - kCarTolerance*0.5 )
{
if (std::fabs(posz) <= fDz + kCarTolerance*0.5) *tmpin = kSurface ;
}
}
#ifdef G4TWISTDEBUG
G4cout << "inside = " << fLastInside.inside << G4endl ;
#endif
return fLastInside.inside;
}
//=====================================================================
//* SurfaceNormal -----------------------------------------------------
G4ThreeVector G4VTwistedFaceted::SurfaceNormal(const G4ThreeVector& p) const
{
//
// return the normal unit vector to the Hyperbolical Surface at a point
// p on (or nearly on) the surface
//
// Which of the three or four surfaces are we closest to?
//
if (fLastNormal.p == p)
{
return fLastNormal.vec;
}
G4ThreeVector *tmpp = const_cast<G4ThreeVector*>(&(fLastNormal.p));
G4ThreeVector *tmpnormal = const_cast<G4ThreeVector*>(&(fLastNormal.vec));
G4VTwistSurface **tmpsurface = const_cast<G4VTwistSurface**>(fLastNormal.surface);
tmpp->set(p.x(), p.y(), p.z());
G4double distance = kInfinity;
G4VTwistSurface *surfaces[6];
surfaces[0] = fSide0 ;
surfaces[1] = fSide90 ;
surfaces[2] = fSide180 ;
surfaces[3] = fSide270 ;
surfaces[4] = fLowerEndcap;
surfaces[5] = fUpperEndcap;
G4ThreeVector xx;
G4ThreeVector bestxx;
G4int i;
G4int besti = -1;
for (i=0; i< 6; i++)
{
G4double tmpdistance = surfaces[i]->DistanceTo(p, xx);
if (tmpdistance < distance)
{
distance = tmpdistance;
bestxx = xx;
besti = i;
}
}
tmpsurface[0] = surfaces[besti];
*tmpnormal = tmpsurface[0]->GetNormal(bestxx, true);
return fLastNormal.vec;
}
//=====================================================================
//* DistanceToIn (p, v) -----------------------------------------------
G4double G4VTwistedFaceted::DistanceToIn (const G4ThreeVector& p,
const G4ThreeVector& v ) const
{
// DistanceToIn (p, v):
// Calculate distance to surface of shape from `outside'
// along with the v, allowing for tolerance.
// The function returns kInfinity if no intersection or
// just grazing within tolerance.
//
// checking last value
//
G4ThreeVector *tmpp;
G4ThreeVector *tmpv;
G4double *tmpdist;
if (fLastDistanceToInWithV.p == p && fLastDistanceToInWithV.vec == v)
{
return fLastDistanceToIn.value;
}
else
{
tmpp = const_cast<G4ThreeVector*>(&(fLastDistanceToInWithV.p));
tmpv = const_cast<G4ThreeVector*>(&(fLastDistanceToInWithV.vec));
tmpdist = const_cast<G4double*>(&(fLastDistanceToInWithV.value));
tmpp->set(p.x(), p.y(), p.z());
tmpv->set(v.x(), v.y(), v.z());
}
//
// Calculate DistanceToIn(p,v)
//
EInside currentside = Inside(p);
if (currentside == kInside)
{
}
else if (currentside == kSurface)
{
// particle is just on a boundary.
// if the particle is entering to the volume, return 0
//
G4ThreeVector normal = SurfaceNormal(p);
if (normal*v < 0)
{
*tmpdist = 0;
return fLastDistanceToInWithV.value;
}
}
// now, we can take smallest positive distance.
// Initialize
//
G4double distance = kInfinity;
// Find intersections and choose nearest one
//
G4VTwistSurface *surfaces[6];
surfaces[0] = fSide0;
surfaces[1] = fSide90 ;
surfaces[2] = fSide180 ;
surfaces[3] = fSide270 ;
surfaces[4] = fLowerEndcap;
surfaces[5] = fUpperEndcap;
G4ThreeVector xx;
G4ThreeVector bestxx;
G4int i;
for (i=0; i < 6 ; i++)
{
#ifdef G4TWISTDEBUG
G4cout << G4endl << "surface " << i << ": " << G4endl << G4endl ;
#endif
G4double tmpdistance = surfaces[i]->DistanceToIn(p, v, xx);
#ifdef G4TWISTDEBUG
G4cout << "Solid DistanceToIn : distance = " << tmpdistance << G4endl ;
G4cout << "intersection point = " << xx << G4endl ;
#endif
if (tmpdistance < distance)
{
distance = tmpdistance;
bestxx = xx;
}
}
#ifdef G4TWISTDEBUG
G4cout << "best distance = " << distance << G4endl ;
#endif
*tmpdist = distance;
// timer.Stop();
return fLastDistanceToInWithV.value;
}
//=====================================================================
//* DistanceToIn (p) --------------------------------------------------
G4double G4VTwistedFaceted::DistanceToIn (const G4ThreeVector& p) const
{
// DistanceToIn(p):
// Calculate distance to surface of shape from `outside',
// allowing for tolerance
//
//
// checking last value
//
G4ThreeVector *tmpp;
G4double *tmpdist;
if (fLastDistanceToIn.p == p)
{
return fLastDistanceToIn.value;
}
else
{
tmpp = const_cast<G4ThreeVector*>(&(fLastDistanceToIn.p));
tmpdist = const_cast<G4double*>(&(fLastDistanceToIn.value));
tmpp->set(p.x(), p.y(), p.z());
}
//
// Calculate DistanceToIn(p)
//
EInside currentside = Inside(p);
switch (currentside)
{
case (kInside) :
{
}
case (kSurface) :
{
*tmpdist = 0.;
return fLastDistanceToIn.value;
}
case (kOutside) :
{
// Initialize
//
G4double distance = kInfinity;
// Find intersections and choose nearest one
//
G4VTwistSurface *surfaces[6];
surfaces[0] = fSide0;
surfaces[1] = fSide90 ;
surfaces[2] = fSide180 ;
surfaces[3] = fSide270 ;
surfaces[4] = fLowerEndcap;
surfaces[5] = fUpperEndcap;
G4int i;
G4ThreeVector xx;
G4ThreeVector bestxx;
for (i=0; i< 6; i++)
{
G4double tmpdistance = surfaces[i]->DistanceTo(p, xx);
if (tmpdistance < distance)
{
distance = tmpdistance;
bestxx = xx;
}
}
*tmpdist = distance;
return fLastDistanceToIn.value;
}
default :
{
G4Exception("G4VTwistedFaceted::DistanceToIn(p)", "GeomSolids0003",
FatalException, "Unknown point location!");
}
} // switch end
return 0;
}
//=====================================================================
//* DistanceToOut (p, v) ----------------------------------------------
G4double
G4VTwistedFaceted::DistanceToOut( const G4ThreeVector& p,
const G4ThreeVector& v,
const G4bool calcNorm,
G4bool *validNorm,
G4ThreeVector *norm ) const
{
// DistanceToOut (p, v):
// Calculate distance to surface of shape from `inside'
// along with the v, allowing for tolerance.
// The function returns kInfinity if no intersection or
// just grazing within tolerance.
//
// checking last value
//
G4ThreeVector *tmpp;
G4ThreeVector *tmpv;
G4double *tmpdist;
if (fLastDistanceToOutWithV.p == p && fLastDistanceToOutWithV.vec == v )
{
return fLastDistanceToOutWithV.value;
}
else
{
tmpp = const_cast<G4ThreeVector*>(&(fLastDistanceToOutWithV.p));
tmpv = const_cast<G4ThreeVector*>(&(fLastDistanceToOutWithV.vec));
tmpdist = const_cast<G4double*>(&(fLastDistanceToOutWithV.value));
tmpp->set(p.x(), p.y(), p.z());
tmpv->set(v.x(), v.y(), v.z());
}
//
// Calculate DistanceToOut(p,v)
//
EInside currentside = Inside(p);
if (currentside == kOutside)
{
}
else if (currentside == kSurface)
{
// particle is just on a boundary.
// if the particle is exiting from the volume, return 0
//
G4ThreeVector normal = SurfaceNormal(p);
G4VTwistSurface *blockedsurface = fLastNormal.surface[0];
if (normal*v > 0)
{
if (calcNorm)
{
*norm = (blockedsurface->GetNormal(p, true));
*validNorm = blockedsurface->IsValidNorm();
}
*tmpdist = 0.;
// timer.Stop();
return fLastDistanceToOutWithV.value;
}
}
// now, we can take smallest positive distance.
// Initialize
G4double distance = kInfinity;
// find intersections and choose nearest one.
G4VTwistSurface *surfaces[6];
surfaces[0] = fSide0;
surfaces[1] = fSide90 ;
surfaces[2] = fSide180 ;
surfaces[3] = fSide270 ;
surfaces[4] = fLowerEndcap;
surfaces[5] = fUpperEndcap;
G4int i;
G4int besti = -1;
G4ThreeVector xx;
G4ThreeVector bestxx;
for (i=0; i< 6 ; i++) {
G4double tmpdistance = surfaces[i]->DistanceToOut(p, v, xx);
if (tmpdistance < distance)
{
distance = tmpdistance;
bestxx = xx;
besti = i;
}
}
if (calcNorm)
{
if (besti != -1)
{
*norm = (surfaces[besti]->GetNormal(p, true));
*validNorm = surfaces[besti]->IsValidNorm();
}
}
*tmpdist = distance;
// timer.Stop();
return fLastDistanceToOutWithV.value;
}
//=====================================================================
//* DistanceToOut (p) -------------------------------------------------
G4double G4VTwistedFaceted::DistanceToOut( const G4ThreeVector& p ) const
{
// DistanceToOut(p):
// Calculate distance to surface of shape from `inside',
// allowing for tolerance
//
// checking last value
//
G4ThreeVector *tmpp;
G4double *tmpdist;
if (fLastDistanceToOut.p == p)
{
return fLastDistanceToOut.value;
}
else
{
tmpp = const_cast<G4ThreeVector*>(&(fLastDistanceToOut.p));
tmpdist = const_cast<G4double*>(&(fLastDistanceToOut.value));
tmpp->set(p.x(), p.y(), p.z());
}
//
// Calculate DistanceToOut(p)
//
EInside currentside = Inside(p);
G4double retval = kInfinity;
switch (currentside)
{
case (kOutside) :
{
#ifdef G4SPECSDEBUG
G4int oldprc = G4cout.precision(16) ;
G4cout << G4endl ;
DumpInfo();
G4cout << "Position:" << G4endl << G4endl ;
G4cout << "p.x() = " << p.x()/mm << " mm" << G4endl ;
G4cout << "p.y() = " << p.y()/mm << " mm" << G4endl ;
G4cout << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl ;
G4cout.precision(oldprc) ;
G4Exception("G4VTwistedFaceted::DistanceToOut(p)", "GeomSolids1002",
JustWarning, "Point p is outside !?" );
#endif
break;
}
case (kSurface) :
{
*tmpdist = 0.;
retval = fLastDistanceToOut.value;
break;
}
case (kInside) :
{
// Initialize
//
G4double distance = kInfinity;
// find intersections and choose nearest one
//
G4VTwistSurface *surfaces[6];
surfaces[0] = fSide0;
surfaces[1] = fSide90 ;
surfaces[2] = fSide180 ;
surfaces[3] = fSide270 ;
surfaces[4] = fLowerEndcap;
surfaces[5] = fUpperEndcap;
G4int i;
G4ThreeVector xx;
G4ThreeVector bestxx;
for (i=0; i< 6; i++)
{
G4double tmpdistance = surfaces[i]->DistanceTo(p, xx);
if (tmpdistance < distance)
{
distance = tmpdistance;
bestxx = xx;
}
}
*tmpdist = distance;
retval = fLastDistanceToOut.value;
break;
}
default :
{
G4Exception("G4VTwistedFaceted::DistanceToOut(p)", "GeomSolids0003",
FatalException, "Unknown point location!");
break;
}
} // switch end
return retval;
}
//=====================================================================
//* StreamInfo --------------------------------------------------------
std::ostream& G4VTwistedFaceted::StreamInfo(std::ostream& os) const
{
//
// Stream object contents to an output stream
//
G4int oldprc = os.precision(16);
os << "-----------------------------------------------------------\n"
<< " *** Dump for solid - " << GetName() << " ***\n"
<< " ===================================================\n"
<< " Solid type: G4VTwistedFaceted\n"
<< " Parameters: \n"
<< " polar angle theta = " << fTheta/degree << " deg" << G4endl
<< " azimuthal angle phi = " << fPhi/degree << " deg" << G4endl
<< " tilt angle alpha = " << fAlph/degree << " deg" << G4endl
<< " TWIST angle = " << fPhiTwist/degree << " deg" << G4endl
<< " Half length along y (lower endcap) = " << fDy1/cm << " cm"
<< G4endl
<< " Half length along x (lower endcap, bottom) = " << fDx1/cm << " cm"
<< G4endl
<< " Half length along x (lower endcap, top) = " << fDx2/cm << " cm"
<< G4endl
<< " Half length along y (upper endcap) = " << fDy2/cm << " cm"
<< G4endl
<< " Half length along x (upper endcap, bottom) = " << fDx3/cm << " cm"
<< G4endl
<< " Half length along x (upper endcap, top) = " << fDx4/cm << " cm"
<< G4endl
<< "-----------------------------------------------------------\n";
os.precision(oldprc);
return os;
}
//=====================================================================
//* DiscribeYourselfTo ------------------------------------------------
void G4VTwistedFaceted::DescribeYourselfTo (G4VGraphicsScene& scene) const
{
scene.AddSolid (*this);
}
//=====================================================================
//* GetExtent ---------------------------------------------------------
G4VisExtent G4VTwistedFaceted::GetExtent() const
{
G4double maxRad = std::sqrt( fDx*fDx + fDy*fDy);
return G4VisExtent(-maxRad, maxRad ,
-maxRad, maxRad ,
-fDz, fDz );
}
//=====================================================================
//* CreateSurfaces ----------------------------------------------------
void G4VTwistedFaceted::CreateSurfaces()
{
// create 6 surfaces of TwistedTub.
if ( fDx1 == fDx2 && fDx3 == fDx4 ) // special case : Box
{
fSide0 = new G4TwistBoxSide("0deg", fPhiTwist, fDz, fTheta, fPhi,
fDy1, fDx1, fDx1, fDy2, fDx3, fDx3, fAlph, 0.*deg);
fSide180 = new G4TwistBoxSide("180deg", fPhiTwist, fDz, fTheta, fPhi+pi,
fDy1, fDx1, fDx1, fDy2, fDx3, fDx3, fAlph, 180.*deg);
}
else // default general case
{
fSide0 = new G4TwistTrapAlphaSide("0deg" ,fPhiTwist, fDz, fTheta,
fPhi, fDy1, fDx1, fDx2, fDy2, fDx3, fDx4, fAlph, 0.*deg);
fSide180 = new G4TwistTrapAlphaSide("180deg", fPhiTwist, fDz, fTheta,
fPhi+pi, fDy1, fDx2, fDx1, fDy2, fDx4, fDx3, fAlph, 180.*deg);
}
// create parallel sides
//
fSide90 = new G4TwistTrapParallelSide("90deg", fPhiTwist, fDz, fTheta,
fPhi, fDy1, fDx1, fDx2, fDy2, fDx3, fDx4, fAlph, 0.*deg);
fSide270 = new G4TwistTrapParallelSide("270deg", fPhiTwist, fDz, fTheta,
fPhi+pi, fDy1, fDx2, fDx1, fDy2, fDx4, fDx3, fAlph, 180.*deg);
// create endcaps
//
fUpperEndcap = new G4TwistTrapFlatSide("UpperCap",fPhiTwist, fDx3, fDx4, fDy2,
fDz, fAlph, fPhi, fTheta, 1 );
fLowerEndcap = new G4TwistTrapFlatSide("LowerCap",fPhiTwist, fDx1, fDx2, fDy1,
fDz, fAlph, fPhi, fTheta, -1 );
// Set neighbour surfaces
fSide0->SetNeighbours( fSide270 , fLowerEndcap , fSide90 , fUpperEndcap );
fSide90->SetNeighbours( fSide0 , fLowerEndcap , fSide180 , fUpperEndcap );
fSide180->SetNeighbours(fSide90 , fLowerEndcap , fSide270 , fUpperEndcap );
fSide270->SetNeighbours(fSide180 , fLowerEndcap , fSide0 , fUpperEndcap );
fUpperEndcap->SetNeighbours( fSide180, fSide270 , fSide0 , fSide90 );
fLowerEndcap->SetNeighbours( fSide180, fSide270 , fSide0 , fSide90 );
}
//=====================================================================
//* GetEntityType -----------------------------------------------------
G4GeometryType G4VTwistedFaceted::GetEntityType() const
{
return G4String("G4VTwistedFaceted");
}
//=====================================================================
//* GetPolyhedron -----------------------------------------------------
G4Polyhedron* G4VTwistedFaceted::GetPolyhedron() const
{
if (!fpPolyhedron ||
fRebuildPolyhedron ||
fpPolyhedron->GetNumberOfRotationStepsAtTimeOfCreation() !=
fpPolyhedron->GetNumberOfRotationSteps())
{
G4AutoLock l(&polyhedronMutex);
delete fpPolyhedron;
fpPolyhedron = CreatePolyhedron();
fRebuildPolyhedron = false;
l.unlock();
}
return fpPolyhedron;
}
//=====================================================================
//* GetPointInSolid ---------------------------------------------------
G4ThreeVector G4VTwistedFaceted::GetPointInSolid(G4double z) const
{
// this routine is only used for a test
// can be deleted ...
if ( z == fDz ) z -= 0.1*fDz ;
if ( z == -fDz ) z += 0.1*fDz ;
G4double phi = z/(2*fDz)*fPhiTwist ;
return G4ThreeVector(fdeltaX * phi/fPhiTwist, fdeltaY * phi/fPhiTwist, z ) ;
}
//=====================================================================
//* GetPointOnSurface -------------------------------------------------
G4ThreeVector G4VTwistedFaceted::GetPointOnSurface() const
{
G4double phi = G4RandFlat::shoot(-fPhiTwist/2.,fPhiTwist/2.);
G4double u , umin, umax ; // variable for twisted surfaces
G4double y ; // variable for flat surface (top and bottom)
// Compute the areas. Attention: Only correct for trapezoids
// where the twisting is done along the z-axis. In the general case
// the computed surface area is more difficult. However this simplification
// does not affect the tracking through the solid.
G4double a1 = fSide0->GetSurfaceArea();
G4double a2 = fSide90->GetSurfaceArea();
G4double a3 = fSide180->GetSurfaceArea() ;
G4double a4 = fSide270->GetSurfaceArea() ;
G4double a5 = fLowerEndcap->GetSurfaceArea() ;
G4double a6 = fUpperEndcap->GetSurfaceArea() ;
#ifdef G4TWISTDEBUG
G4cout << "Surface 0 deg = " << a1 << G4endl ;
G4cout << "Surface 90 deg = " << a2 << G4endl ;
G4cout << "Surface 180 deg = " << a3 << G4endl ;
G4cout << "Surface 270 deg = " << a4 << G4endl ;
G4cout << "Surface Lower = " << a5 << G4endl ;
G4cout << "Surface Upper = " << a6 << G4endl ;
#endif
G4double chose = G4RandFlat::shoot(0.,a1 + a2 + a3 + a4 + a5 + a6) ;
if(chose < a1)
{
umin = fSide0->GetBoundaryMin(phi) ;
umax = fSide0->GetBoundaryMax(phi) ;
u = G4RandFlat::shoot(umin,umax) ;
return fSide0->SurfacePoint(phi, u, true) ; // point on 0deg surface
}
else if( (chose >= a1) && (chose < a1 + a2 ) )
{
umin = fSide90->GetBoundaryMin(phi) ;
umax = fSide90->GetBoundaryMax(phi) ;
u = G4RandFlat::shoot(umin,umax) ;
return fSide90->SurfacePoint(phi, u, true); // point on 90deg surface
}
else if( (chose >= a1 + a2 ) && (chose < a1 + a2 + a3 ) )
{
umin = fSide180->GetBoundaryMin(phi) ;
umax = fSide180->GetBoundaryMax(phi) ;
u = G4RandFlat::shoot(umin,umax) ;
return fSide180->SurfacePoint(phi, u, true); // point on 180 deg surface
}
else if( (chose >= a1 + a2 + a3 ) && (chose < a1 + a2 + a3 + a4 ) )
{
umin = fSide270->GetBoundaryMin(phi) ;
umax = fSide270->GetBoundaryMax(phi) ;
u = G4RandFlat::shoot(umin,umax) ;
return fSide270->SurfacePoint(phi, u, true); // point on 270 deg surface
}
else if( (chose >= a1 + a2 + a3 + a4 ) && (chose < a1 + a2 + a3 + a4 + a5 ) )
{
y = G4RandFlat::shoot(-fDy1,fDy1) ;
umin = fLowerEndcap->GetBoundaryMin(y) ;
umax = fLowerEndcap->GetBoundaryMax(y) ;
u = G4RandFlat::shoot(umin,umax) ;
return fLowerEndcap->SurfacePoint(u,y,true); // point on lower endcap
}
else {
y = G4RandFlat::shoot(-fDy2,fDy2) ;
umin = fUpperEndcap->GetBoundaryMin(y) ;
umax = fUpperEndcap->GetBoundaryMax(y) ;
u = G4RandFlat::shoot(umin,umax) ;
return fUpperEndcap->SurfacePoint(u,y,true) ; // point on upper endcap
}
}
//=====================================================================
//* CreatePolyhedron --------------------------------------------------
G4Polyhedron* G4VTwistedFaceted::CreatePolyhedron () const
{
// number of meshes
const G4int k =
G4int(G4Polyhedron::GetNumberOfRotationSteps() *
std::abs(fPhiTwist) / twopi) + 2;
const G4int n = k;
const G4int nnodes = 4*(k-1)*(n-2) + 2*k*k ;
const G4int nfaces = 4*(k-1)*(n-1) + 2*(k-1)*(k-1) ;
G4Polyhedron *ph=new G4Polyhedron;
typedef G4double G4double3[3];
typedef G4int G4int4[4];
G4double3* xyz = new G4double3[nnodes]; // number of nodes
G4int4* faces = new G4int4[nfaces] ; // number of faces
fLowerEndcap->GetFacets(k,k,xyz,faces,0) ;
fUpperEndcap->GetFacets(k,k,xyz,faces,1) ;
fSide270->GetFacets(k,n,xyz,faces,2) ;
fSide0->GetFacets(k,n,xyz,faces,3) ;
fSide90->GetFacets(k,n,xyz,faces,4) ;
fSide180->GetFacets(k,n,xyz,faces,5) ;
ph->createPolyhedron(nnodes,nfaces,xyz,faces);
return ph;
}