1339 lines
35 KiB
C++
1339 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. *
|
|
// ********************************************************************
|
|
//
|
|
//
|
|
// $Id: G4Trd.cc 101121 2016-11-07 09:18:01Z gcosmo $
|
|
//
|
|
//
|
|
// Implementation for G4Trd class
|
|
//
|
|
// History:
|
|
//
|
|
// 23.09.16 E.Tcherniaev: added Extent(pmin,pmax),
|
|
// use G4BoundingEnvelope for CalculateExtent(),
|
|
// removed CreateRotatedVertices()
|
|
// 28.04.05 V.Grichine: new SurfaceNormal according to J. Apostolakis proposal
|
|
// 26.04.05, V.Grichine, new SurfaceNoramal is default
|
|
// 07.12.04, V.Grichine, SurfaceNoramal with edges/vertices.
|
|
// 07.05.00, V.Grichine, in d = DistanceToIn(p,v), if d<0.5*kCarTolerance, d=0
|
|
// ~1996, V.Grichine, 1st implementation based on old code of P.Kent
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "G4Trd.hh"
|
|
|
|
#if !defined(G4GEOM_USE_UTRD)
|
|
|
|
#include "G4VoxelLimits.hh"
|
|
#include "G4AffineTransform.hh"
|
|
#include "G4BoundingEnvelope.hh"
|
|
#include "Randomize.hh"
|
|
|
|
#include "G4VPVParameterisation.hh"
|
|
|
|
#include "G4VGraphicsScene.hh"
|
|
|
|
using namespace CLHEP;
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Constructor - check & set half widths
|
|
|
|
G4Trd::G4Trd( const G4String& pName,
|
|
G4double pdx1, G4double pdx2,
|
|
G4double pdy1, G4double pdy2,
|
|
G4double pdz )
|
|
: G4CSGSolid(pName)
|
|
{
|
|
CheckAndSetAllParameters (pdx1, pdx2, pdy1, pdy2, pdz);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Set and check (coplanarity) of trd parameters
|
|
|
|
void G4Trd::CheckAndSetAllParameters ( G4double pdx1, G4double pdx2,
|
|
G4double pdy1, G4double pdy2,
|
|
G4double pdz )
|
|
{
|
|
if ( pdx1>0&&pdx2>0&&pdy1>0&&pdy2>0&&pdz>0 )
|
|
{
|
|
fDx1=pdx1; fDx2=pdx2;
|
|
fDy1=pdy1; fDy2=pdy2;
|
|
fDz=pdz;
|
|
}
|
|
else
|
|
{
|
|
if ( pdx1>=0 && pdx2>=0 && pdy1>=0 && pdy2>=0 && pdz>=0 )
|
|
{
|
|
// G4double Minimum_length= (1+per_thousand) * kCarTolerance/2.;
|
|
// FIX-ME : temporary solution for ZERO or very-small parameters
|
|
//
|
|
G4double Minimum_length= kCarTolerance/2.;
|
|
fDx1=std::max(pdx1,Minimum_length);
|
|
fDx2=std::max(pdx2,Minimum_length);
|
|
fDy1=std::max(pdy1,Minimum_length);
|
|
fDy2=std::max(pdy2,Minimum_length);
|
|
fDz=std::max(pdz,Minimum_length);
|
|
}
|
|
else
|
|
{
|
|
std::ostringstream message;
|
|
message << "Invalid negative dimensions for Solid: " << GetName()
|
|
<< G4endl
|
|
<< " X - " << pdx1 << ", " << pdx2 << G4endl
|
|
<< " Y - " << pdy1 << ", " << pdy2 << G4endl
|
|
<< " Z - " << pdz;
|
|
G4Exception("G4Trd::CheckAndSetAllParameters()",
|
|
"GeomSolids0002", FatalException, message);
|
|
}
|
|
}
|
|
fCubicVolume= 0.;
|
|
fSurfaceArea= 0.;
|
|
fRebuildPolyhedron = true;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Fake default constructor - sets only member data and allocates memory
|
|
// for usage restricted to object persistency.
|
|
//
|
|
G4Trd::G4Trd( __void__& a )
|
|
: G4CSGSolid(a), fDx1(0.), fDx2(0.), fDy1(0.), fDy2(0.), fDz(0.)
|
|
{
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Destructor
|
|
|
|
G4Trd::~G4Trd()
|
|
{
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copy constructor
|
|
|
|
G4Trd::G4Trd(const G4Trd& rhs)
|
|
: G4CSGSolid(rhs), fDx1(rhs.fDx1), fDx2(rhs.fDx2),
|
|
fDy1(rhs.fDy1), fDy2(rhs.fDy2), fDz(rhs.fDz)
|
|
{
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Assignment operator
|
|
|
|
G4Trd& G4Trd::operator = (const G4Trd& rhs)
|
|
{
|
|
// Check assignment to self
|
|
//
|
|
if (this == &rhs) { return *this; }
|
|
|
|
// Copy base class data
|
|
//
|
|
G4CSGSolid::operator=(rhs);
|
|
|
|
// Copy data
|
|
//
|
|
fDx1 = rhs.fDx1; fDx2 = rhs.fDx2;
|
|
fDy1 = rhs.fDy1; fDy2 = rhs.fDy2;
|
|
fDz = rhs.fDz;
|
|
|
|
return *this;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
|
|
void G4Trd::SetAllParameters ( G4double pdx1, G4double pdx2, G4double pdy1,
|
|
G4double pdy2, G4double pdz )
|
|
{
|
|
CheckAndSetAllParameters (pdx1, pdx2, pdy1, pdy2, pdz);
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Dispatch to parameterisation for replication mechanism dimension
|
|
// computation & modification.
|
|
|
|
void G4Trd::ComputeDimensions( G4VPVParameterisation* p,
|
|
const G4int n,
|
|
const G4VPhysicalVolume* pRep )
|
|
{
|
|
p->ComputeDimensions(*this,n,pRep);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Get bounding box
|
|
|
|
void G4Trd::Extent(G4ThreeVector& pMin, G4ThreeVector& pMax) const
|
|
{
|
|
G4double dx1 = GetXHalfLength1();
|
|
G4double dx2 = GetXHalfLength2();
|
|
G4double dy1 = GetYHalfLength1();
|
|
G4double dy2 = GetYHalfLength2();
|
|
G4double dz = GetZHalfLength();
|
|
|
|
G4double xmax = std::max(dx1,dx2);
|
|
G4double ymax = std::max(dy1,dy2);
|
|
pMin.set(-xmax,-ymax,-dz);
|
|
pMax.set( xmax, ymax, dz);
|
|
|
|
// Check correctness of the bounding box
|
|
//
|
|
if (pMin.x() >= pMax.x() || pMin.y() >= pMax.y() || pMin.z() >= pMax.z())
|
|
{
|
|
std::ostringstream message;
|
|
message << "Bad bounding box (min >= max) for solid: "
|
|
<< GetName() << " !"
|
|
<< "\npMin = " << pMin
|
|
<< "\npMax = " << pMax;
|
|
G4Exception("G4Trd::Extent()", "GeomMgt0001", JustWarning, message);
|
|
DumpInfo();
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Calculate extent under transform and specified limit
|
|
|
|
G4bool G4Trd::CalculateExtent( const EAxis pAxis,
|
|
const G4VoxelLimits& pVoxelLimit,
|
|
const G4AffineTransform& pTransform,
|
|
G4double& pMin, G4double& pMax ) const
|
|
{
|
|
G4ThreeVector bmin, bmax;
|
|
G4bool exist;
|
|
|
|
// Check bounding box (bbox)
|
|
//
|
|
Extent(bmin,bmax);
|
|
G4BoundingEnvelope bbox(bmin,bmax);
|
|
#ifdef G4BBOX_EXTENT
|
|
if (true) return bbox.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax);
|
|
#endif
|
|
if (bbox.BoundingBoxVsVoxelLimits(pAxis,pVoxelLimit,pTransform,pMin,pMax))
|
|
{
|
|
return exist = (pMin < pMax) ? true : false;
|
|
}
|
|
|
|
// Set bounding envelope (benv) and calculate extent
|
|
//
|
|
G4double dx1 = GetXHalfLength1();
|
|
G4double dx2 = GetXHalfLength2();
|
|
G4double dy1 = GetYHalfLength1();
|
|
G4double dy2 = GetYHalfLength2();
|
|
G4double dz = GetZHalfLength();
|
|
|
|
G4ThreeVectorList baseA(4), baseB(4);
|
|
baseA[0].set(-dx1,-dy1,-dz);
|
|
baseA[1].set( dx1,-dy1,-dz);
|
|
baseA[2].set( dx1, dy1,-dz);
|
|
baseA[3].set(-dx1, dy1,-dz);
|
|
baseB[0].set(-dx2,-dy2, dz);
|
|
baseB[1].set( dx2,-dy2, dz);
|
|
baseB[2].set( dx2, dy2, dz);
|
|
baseB[3].set(-dx2, dy2, dz);
|
|
|
|
std::vector<const G4ThreeVectorList *> polygons(2);
|
|
polygons[0] = &baseA;
|
|
polygons[1] = &baseB;
|
|
|
|
G4BoundingEnvelope benv(bmin,bmax,polygons);
|
|
exist = benv.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax);
|
|
return exist;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Return whether point inside/outside/on surface, using tolerance
|
|
|
|
EInside G4Trd::Inside( const G4ThreeVector& p ) const
|
|
{
|
|
EInside in=kOutside;
|
|
G4double x,y,zbase1,zbase2;
|
|
|
|
if (std::fabs(p.z())<=fDz-kCarTolerance/2)
|
|
{
|
|
zbase1=p.z()+fDz; // Dist from -ve z plane
|
|
zbase2=fDz-p.z(); // Dist from +ve z plane
|
|
|
|
// Check whether inside x tolerance
|
|
//
|
|
x=0.5*(fDx2*zbase1+fDx1*zbase2)/fDz - kCarTolerance/2;
|
|
if (std::fabs(p.x())<=x)
|
|
{
|
|
y=0.5*((fDy2*zbase1+fDy1*zbase2))/fDz - kCarTolerance/2;
|
|
if (std::fabs(p.y())<=y)
|
|
{
|
|
in=kInside;
|
|
}
|
|
else if (std::fabs(p.y())<=y+kCarTolerance)
|
|
{
|
|
in=kSurface;
|
|
}
|
|
}
|
|
else if (std::fabs(p.x())<=x+kCarTolerance)
|
|
{
|
|
// y = y half width of shape at z of point + tolerant boundary
|
|
//
|
|
y=0.5*((fDy2*zbase1+fDy1*zbase2))/fDz + kCarTolerance/2;
|
|
if (std::fabs(p.y())<=y)
|
|
{
|
|
in=kSurface;
|
|
}
|
|
}
|
|
}
|
|
else if (std::fabs(p.z())<=fDz+kCarTolerance/2)
|
|
{
|
|
// Only need to check outer tolerant boundaries
|
|
//
|
|
zbase1=p.z()+fDz; // Dist from -ve z plane
|
|
zbase2=fDz-p.z(); // Dist from +ve z plane
|
|
|
|
// x = x half width of shape at z of point plus tolerance
|
|
//
|
|
x=0.5*(fDx2*zbase1+fDx1*zbase2)/fDz + kCarTolerance/2;
|
|
if (std::fabs(p.x())<=x)
|
|
{
|
|
// y = y half width of shape at z of point
|
|
//
|
|
y=0.5*((fDy2*zbase1+fDy1*zbase2))/fDz + kCarTolerance/2;
|
|
if (std::fabs(p.y())<=y) in=kSurface;
|
|
}
|
|
}
|
|
return in;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Calculate side nearest to p, and return normal
|
|
// If two sides are equidistant, normal of first side (x/y/z)
|
|
// encountered returned
|
|
|
|
G4ThreeVector G4Trd::SurfaceNormal( const G4ThreeVector& p ) const
|
|
{
|
|
G4ThreeVector norm, sumnorm(0.,0.,0.);
|
|
G4int noSurfaces = 0;
|
|
G4double z = 2.0*fDz, tanx, secx, newpx, widx;
|
|
G4double tany, secy, newpy, widy;
|
|
G4double distx, disty, distz, fcos;
|
|
G4double delta = 0.5*kCarTolerance;
|
|
|
|
tanx = (fDx2 - fDx1)/z;
|
|
secx = std::sqrt(1.0+tanx*tanx);
|
|
newpx = std::fabs(p.x())-p.z()*tanx;
|
|
widx = fDx2 - fDz*tanx;
|
|
|
|
tany = (fDy2 - fDy1)/z;
|
|
secy = std::sqrt(1.0+tany*tany);
|
|
newpy = std::fabs(p.y())-p.z()*tany;
|
|
widy = fDy2 - fDz*tany;
|
|
|
|
distx = std::fabs(newpx-widx)/secx; // perp. distance to x side
|
|
disty = std::fabs(newpy-widy)/secy; // to y side
|
|
distz = std::fabs(std::fabs(p.z())-fDz); // to z side
|
|
|
|
fcos = 1.0/secx;
|
|
G4ThreeVector nX = G4ThreeVector( fcos,0,-tanx*fcos);
|
|
G4ThreeVector nmX = G4ThreeVector(-fcos,0,-tanx*fcos);
|
|
|
|
fcos = 1.0/secy;
|
|
G4ThreeVector nY = G4ThreeVector(0, fcos,-tany*fcos);
|
|
G4ThreeVector nmY = G4ThreeVector(0,-fcos,-tany*fcos);
|
|
G4ThreeVector nZ = G4ThreeVector( 0, 0, 1.0);
|
|
|
|
if (distx <= delta)
|
|
{
|
|
noSurfaces ++;
|
|
if ( p.x() >= 0.) sumnorm += nX;
|
|
else sumnorm += nmX;
|
|
}
|
|
if (disty <= delta)
|
|
{
|
|
noSurfaces ++;
|
|
if ( p.y() >= 0.) sumnorm += nY;
|
|
else sumnorm += nmY;
|
|
}
|
|
if (distz <= delta)
|
|
{
|
|
noSurfaces ++;
|
|
if ( p.z() >= 0.) sumnorm += nZ;
|
|
else sumnorm -= nZ;
|
|
}
|
|
if ( noSurfaces == 0 )
|
|
{
|
|
#ifdef G4CSGDEBUG
|
|
G4Exception("G4Trd::SurfaceNormal(p)", "GeomSolids1002", JustWarning,
|
|
"Point p is not on surface !?" );
|
|
#endif
|
|
norm = ApproxSurfaceNormal(p);
|
|
}
|
|
else if ( noSurfaces == 1 ) norm = sumnorm;
|
|
else norm = sumnorm.unit();
|
|
return norm;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Algorithm for SurfaceNormal() following the original specification
|
|
// for points not on the surface
|
|
|
|
G4ThreeVector G4Trd::ApproxSurfaceNormal( const G4ThreeVector& p ) const
|
|
{
|
|
G4ThreeVector norm;
|
|
G4double z,tanx,secx,newpx,widx;
|
|
G4double tany,secy,newpy,widy;
|
|
G4double distx,disty,distz,fcos;
|
|
|
|
z=2.0*fDz;
|
|
|
|
tanx=(fDx2-fDx1)/z;
|
|
secx=std::sqrt(1.0+tanx*tanx);
|
|
newpx=std::fabs(p.x())-p.z()*tanx;
|
|
widx=fDx2-fDz*tanx;
|
|
|
|
tany=(fDy2-fDy1)/z;
|
|
secy=std::sqrt(1.0+tany*tany);
|
|
newpy=std::fabs(p.y())-p.z()*tany;
|
|
widy=fDy2-fDz*tany;
|
|
|
|
distx=std::fabs(newpx-widx)/secx; // perpendicular distance to x side
|
|
disty=std::fabs(newpy-widy)/secy; // to y side
|
|
distz=std::fabs(std::fabs(p.z())-fDz); // to z side
|
|
|
|
// find closest side
|
|
//
|
|
if (distx<=disty)
|
|
{
|
|
if (distx<=distz)
|
|
{
|
|
// Closest to X
|
|
//
|
|
fcos=1.0/secx;
|
|
// normal=(+/-std::cos(ang),0,-std::sin(ang))
|
|
if (p.x()>=0)
|
|
norm=G4ThreeVector(fcos,0,-tanx*fcos);
|
|
else
|
|
norm=G4ThreeVector(-fcos,0,-tanx*fcos);
|
|
}
|
|
else
|
|
{
|
|
// Closest to Z
|
|
//
|
|
if (p.z()>=0)
|
|
norm=G4ThreeVector(0,0,1);
|
|
else
|
|
norm=G4ThreeVector(0,0,-1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (disty<=distz)
|
|
{
|
|
// Closest to Y
|
|
//
|
|
fcos=1.0/secy;
|
|
if (p.y()>=0)
|
|
norm=G4ThreeVector(0,fcos,-tany*fcos);
|
|
else
|
|
norm=G4ThreeVector(0,-fcos,-tany*fcos);
|
|
}
|
|
else
|
|
{
|
|
// Closest to Z
|
|
//
|
|
if (p.z()>=0)
|
|
norm=G4ThreeVector(0,0,1);
|
|
else
|
|
norm=G4ThreeVector(0,0,-1);
|
|
}
|
|
}
|
|
return norm;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Calculate distance to shape from outside
|
|
// - return kInfinity if no intersection
|
|
//
|
|
// ALGORITHM:
|
|
// For each component, calculate pair of minimum and maximum intersection
|
|
// values for which the particle is in the extent of the shape
|
|
// - The smallest (MAX minimum) allowed distance of the pairs is intersect
|
|
// - Z plane intersectin uses tolerance
|
|
// - XZ YZ planes use logic & *SLIGHTLY INCORRECT* tolerance
|
|
// (this saves at least 1 sqrt, 1 multiply and 1 divide... in applicable
|
|
// cases)
|
|
// - Note: XZ and YZ planes each divide space into four regions,
|
|
// characterised by ss1 ss2
|
|
// NOTE:
|
|
//
|
|
// `Inside' safe - meaningful answers given if point is inside the exact
|
|
// shape.
|
|
|
|
G4double G4Trd::DistanceToIn( const G4ThreeVector& p,
|
|
const G4ThreeVector& v ) const
|
|
{
|
|
G4double snxt = kInfinity ; // snxt = default return value
|
|
G4double smin,smax;
|
|
G4double s1,s2,tanxz,tanyz,ds1,ds2;
|
|
G4double ss1,ss2,sn1=0.,sn2=0.,Dist;
|
|
|
|
if ( v.z() ) // Calculate valid z intersect range
|
|
{
|
|
if ( v.z() > 0 ) // Calculate smax: must be +ve or no intersection.
|
|
{
|
|
Dist = fDz - p.z() ; // to plane at +dz
|
|
|
|
if (Dist >= 0.5*kCarTolerance)
|
|
{
|
|
smax = Dist/v.z() ;
|
|
smin = -(fDz + p.z())/v.z() ;
|
|
}
|
|
else return snxt ;
|
|
}
|
|
else // v.z <0
|
|
{
|
|
Dist=fDz+p.z(); // plane at -dz
|
|
|
|
if ( Dist >= 0.5*kCarTolerance )
|
|
{
|
|
smax = -Dist/v.z() ;
|
|
smin = (fDz - p.z())/v.z() ;
|
|
}
|
|
else return snxt ;
|
|
}
|
|
if (smin < 0 ) smin = 0 ;
|
|
}
|
|
else // v.z=0
|
|
{
|
|
if (std::fabs(p.z()) >= fDz ) return snxt ; // Outside & no intersect
|
|
else
|
|
{
|
|
smin = 0 ; // Always inside z range
|
|
smax = kInfinity;
|
|
}
|
|
}
|
|
|
|
// Calculate x intersection range
|
|
//
|
|
// Calc half width at p.z, and components towards planes
|
|
|
|
tanxz = (fDx2 - fDx1)*0.5/fDz ;
|
|
s1 = 0.5*(fDx1+fDx2) + tanxz*p.z() ; // x half width at p.z
|
|
ds1 = v.x() - tanxz*v.z() ; // Components of v towards faces at +-x
|
|
ds2 = v.x() + tanxz*v.z() ;
|
|
ss1 = s1 - p.x() ; // -delta x to +ve plane
|
|
// -ve when outside
|
|
ss2 = -s1 - p.x() ; // -delta x to -ve plane
|
|
// +ve when outside
|
|
|
|
if (ss1 < 0 && ss2 <= 0 )
|
|
{
|
|
if (ds1 < 0) // In +ve coord Area
|
|
{
|
|
sn1 = ss1/ds1 ;
|
|
|
|
if ( ds2 < 0 ) sn2 = ss2/ds2 ;
|
|
else sn2 = kInfinity ;
|
|
}
|
|
else return snxt ;
|
|
}
|
|
else if ( ss1 >= 0 && ss2 > 0 )
|
|
{
|
|
if ( ds2 > 0 ) // In -ve coord Area
|
|
{
|
|
sn1 = ss2/ds2 ;
|
|
|
|
if (ds1 > 0) sn2 = ss1/ds1 ;
|
|
else sn2 = kInfinity;
|
|
|
|
}
|
|
else return snxt ;
|
|
}
|
|
else if (ss1 >= 0 && ss2 <= 0 )
|
|
{
|
|
// Inside Area - calculate leaving distance
|
|
// *Don't* use exact distance to side for tolerance
|
|
// = ss1*std::cos(ang xz)
|
|
// = ss1/std::sqrt(1.0+tanxz*tanxz)
|
|
sn1 = 0 ;
|
|
|
|
if ( ds1 > 0 )
|
|
{
|
|
if (ss1 > 0.5*kCarTolerance) sn2 = ss1/ds1 ; // Leave +ve side extent
|
|
else return snxt ; // Leave immediately by +ve
|
|
}
|
|
else sn2 = kInfinity ;
|
|
|
|
if ( ds2 < 0 )
|
|
{
|
|
if ( ss2 < -0.5*kCarTolerance )
|
|
{
|
|
Dist = ss2/ds2 ; // Leave -ve side extent
|
|
if ( Dist < sn2 ) sn2 = Dist ;
|
|
}
|
|
else return snxt ;
|
|
}
|
|
}
|
|
else if (ss1 < 0 && ss2 > 0 )
|
|
{
|
|
// Within +/- plane cross-over areas (not on boundaries ss1||ss2==0)
|
|
|
|
if ( ds1 >= 0 || ds2 <= 0 )
|
|
{
|
|
return snxt ;
|
|
}
|
|
else // Will intersect & stay inside
|
|
{
|
|
sn1 = ss1/ds1 ;
|
|
Dist = ss2/ds2 ;
|
|
if (Dist > sn1 ) sn1 = Dist ;
|
|
sn2 = kInfinity ;
|
|
}
|
|
}
|
|
|
|
// Reduce allowed range of distances as appropriate
|
|
|
|
if ( sn1 > smin ) smin = sn1 ;
|
|
if ( sn2 < smax ) smax = sn2 ;
|
|
|
|
// Check for incompatible ranges (eg z intersects between 50 ->100 and x
|
|
// only 10-40 -> no intersection)
|
|
|
|
if ( smax < smin ) return snxt ;
|
|
|
|
// Calculate valid y intersection range
|
|
// (repeat of x intersection code)
|
|
|
|
tanyz = (fDy2-fDy1)*0.5/fDz ;
|
|
s2 = 0.5*(fDy1+fDy2) + tanyz*p.z() ; // y half width at p.z
|
|
ds1 = v.y() - tanyz*v.z() ; // Components of v towards faces at +-y
|
|
ds2 = v.y() + tanyz*v.z() ;
|
|
ss1 = s2 - p.y() ; // -delta y to +ve plane
|
|
ss2 = -s2 - p.y() ; // -delta y to -ve plane
|
|
|
|
if ( ss1 < 0 && ss2 <= 0 )
|
|
{
|
|
if (ds1 < 0 ) // In +ve coord Area
|
|
{
|
|
sn1 = ss1/ds1 ;
|
|
if ( ds2 < 0 ) sn2 = ss2/ds2 ;
|
|
else sn2 = kInfinity ;
|
|
}
|
|
else return snxt ;
|
|
}
|
|
else if ( ss1 >= 0 && ss2 > 0 )
|
|
{
|
|
if ( ds2 > 0 ) // In -ve coord Area
|
|
{
|
|
sn1 = ss2/ds2 ;
|
|
if ( ds1 > 0 ) sn2 = ss1/ds1 ;
|
|
else sn2 = kInfinity ;
|
|
}
|
|
else return snxt ;
|
|
}
|
|
else if (ss1 >= 0 && ss2 <= 0 )
|
|
{
|
|
// Inside Area - calculate leaving distance
|
|
// *Don't* use exact distance to side for tolerance
|
|
// = ss1*std::cos(ang yz)
|
|
// = ss1/std::sqrt(1.0+tanyz*tanyz)
|
|
sn1 = 0 ;
|
|
|
|
if ( ds1 > 0 )
|
|
{
|
|
if (ss1 > 0.5*kCarTolerance) sn2 = ss1/ds1 ; // Leave +ve side extent
|
|
else return snxt ; // Leave immediately by +ve
|
|
}
|
|
else sn2 = kInfinity ;
|
|
|
|
if ( ds2 < 0 )
|
|
{
|
|
if ( ss2 < -0.5*kCarTolerance )
|
|
{
|
|
Dist = ss2/ds2 ; // Leave -ve side extent
|
|
if (Dist < sn2) sn2=Dist;
|
|
}
|
|
else return snxt ;
|
|
}
|
|
}
|
|
else if (ss1 < 0 && ss2 > 0 )
|
|
{
|
|
// Within +/- plane cross-over areas (not on boundaries ss1||ss2==0)
|
|
|
|
if (ds1 >= 0 || ds2 <= 0 )
|
|
{
|
|
return snxt ;
|
|
}
|
|
else // Will intersect & stay inside
|
|
{
|
|
sn1 = ss1/ds1 ;
|
|
Dist = ss2/ds2 ;
|
|
if (Dist > sn1 ) sn1 = Dist ;
|
|
sn2 = kInfinity ;
|
|
}
|
|
}
|
|
|
|
// Reduce allowed range of distances as appropriate
|
|
|
|
if ( sn1 > smin) smin = sn1 ;
|
|
if ( sn2 < smax) smax = sn2 ;
|
|
|
|
// Check for incompatible ranges (eg x intersects between 50 ->100 and y
|
|
// only 10-40 -> no intersection). Set snxt if ok
|
|
|
|
if ( smax > smin ) snxt = smin ;
|
|
if (snxt < 0.5*kCarTolerance ) snxt = 0.0 ;
|
|
|
|
return snxt ;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Approximate distance to shape
|
|
// Calculate perpendicular distances to z/x/y surfaces, return largest
|
|
// which is the most fast estimation of shortest distance to Trd
|
|
// - Safe underestimate
|
|
// - If point within exact shape, return 0
|
|
|
|
G4double G4Trd::DistanceToIn( const G4ThreeVector& p ) const
|
|
{
|
|
G4double safe=0.0;
|
|
G4double tanxz,distx,safx;
|
|
G4double tanyz,disty,safy;
|
|
G4double zbase;
|
|
|
|
safe=std::fabs(p.z())-fDz;
|
|
if (safe<0) safe=0; // Also used to ensure x/y distances
|
|
// POSITIVE
|
|
|
|
zbase=fDz+p.z();
|
|
|
|
// Find distance along x direction to closest x plane
|
|
//
|
|
tanxz=(fDx2-fDx1)*0.5/fDz;
|
|
// widx=fDx1+tanxz*(fDz+p.z()); // x width at p.z
|
|
// distx=std::fabs(p.x())-widx; // distance to plane
|
|
distx=std::fabs(p.x())-(fDx1+tanxz*zbase);
|
|
if (distx>safe)
|
|
{
|
|
safx=distx/std::sqrt(1.0+tanxz*tanxz); // vector Dist=Dist*std::cos(ang)
|
|
if (safx>safe) safe=safx;
|
|
}
|
|
|
|
// Find distance along y direction to slanted wall
|
|
tanyz=(fDy2-fDy1)*0.5/fDz;
|
|
// widy=fDy1+tanyz*(fDz+p.z()); // y width at p.z
|
|
// disty=std::fabs(p.y())-widy; // distance to plane
|
|
disty=std::fabs(p.y())-(fDy1+tanyz*zbase);
|
|
if (disty>safe)
|
|
{
|
|
safy=disty/std::sqrt(1.0+tanyz*tanyz); // distance along vector
|
|
if (safy>safe) safe=safy;
|
|
}
|
|
return safe;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Calcluate distance to surface of shape from inside
|
|
// Calculate distance to x/y/z planes - smallest is exiting distance
|
|
// - z planes have std. check for tolerance
|
|
// - xz yz planes have check based on distance || to x or y axis
|
|
// (not corrected for slope of planes)
|
|
// ?BUG? If v.z==0 are there cases when snside not set????
|
|
|
|
G4double G4Trd::DistanceToOut( const G4ThreeVector& p,
|
|
const G4ThreeVector& v,
|
|
const G4bool calcNorm,
|
|
G4bool *validNorm,
|
|
G4ThreeVector *n ) const
|
|
{
|
|
ESide side = kUndefined, snside = kUndefined;
|
|
G4double snxt,pdist;
|
|
G4double central,ss1,ss2,ds1,ds2,sn=0.,sn2=0.;
|
|
G4double tanxz=0.,cosxz=0.,tanyz=0.,cosyz=0.;
|
|
|
|
if (calcNorm) *validNorm=true; // All normals are valid
|
|
|
|
// Calculate 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);
|
|
}
|
|
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);
|
|
}
|
|
return snxt=0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
snxt=kInfinity;
|
|
}
|
|
|
|
//
|
|
// Calculate x intersection
|
|
//
|
|
tanxz=(fDx2-fDx1)*0.5/fDz;
|
|
central=0.5*(fDx1+fDx2);
|
|
|
|
// +ve plane (1)
|
|
//
|
|
ss1=central+tanxz*p.z()-p.x(); // distance || x axis to plane
|
|
// (+ve if point inside)
|
|
ds1=v.x()-tanxz*v.z(); // component towards plane at +x
|
|
// (-ve if +ve -> -ve direction)
|
|
// -ve plane (2)
|
|
//
|
|
ss2=-tanxz*p.z()-p.x()-central; //distance || x axis to plane
|
|
// (-ve if point inside)
|
|
ds2=tanxz*v.z()+v.x(); // component towards plane at -x
|
|
|
|
if (ss1>0&&ss2<0)
|
|
{
|
|
// Normal case - entirely inside region
|
|
if (ds1<=0&&ds2<0)
|
|
{
|
|
if (ss2<-kCarTolerance/2)
|
|
{
|
|
sn=ss2/ds2; // Leave by -ve side
|
|
snside=kMX;
|
|
}
|
|
else
|
|
{
|
|
sn=0; // Leave immediately by -ve side
|
|
snside=kMX;
|
|
}
|
|
}
|
|
else if (ds1>0&&ds2>=0)
|
|
{
|
|
if (ss1>kCarTolerance/2)
|
|
{
|
|
sn=ss1/ds1; // Leave by +ve side
|
|
snside=kPX;
|
|
}
|
|
else
|
|
{
|
|
sn=0; // Leave immediately by +ve side
|
|
snside=kPX;
|
|
}
|
|
}
|
|
else if (ds1>0&&ds2<0)
|
|
{
|
|
if (ss1>kCarTolerance/2)
|
|
{
|
|
// sn=ss1/ds1; // Leave by +ve side
|
|
if (ss2<-kCarTolerance/2)
|
|
{
|
|
sn=ss1/ds1; // Leave by +ve side
|
|
sn2=ss2/ds2;
|
|
if (sn2<sn)
|
|
{
|
|
sn=sn2;
|
|
snside=kMX;
|
|
}
|
|
else
|
|
{
|
|
snside=kPX;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sn=0; // Leave immediately by -ve
|
|
snside=kMX;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sn=0; // Leave immediately by +ve side
|
|
snside=kPX;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Must be || to both
|
|
//
|
|
sn=kInfinity; // Don't leave by either side
|
|
}
|
|
}
|
|
else if (ss1<=0&&ss2<0)
|
|
{
|
|
// Outside, in +ve Area
|
|
|
|
if (ds1>0)
|
|
{
|
|
sn=0; // Away from shape
|
|
// Left by +ve side
|
|
snside=kPX;
|
|
}
|
|
else
|
|
{
|
|
if (ds2<0)
|
|
{
|
|
// Ignore +ve plane and use -ve plane intersect
|
|
//
|
|
sn=ss2/ds2; // Leave by -ve side
|
|
snside=kMX;
|
|
}
|
|
else
|
|
{
|
|
// Must be || to both -> exit determined by other axes
|
|
//
|
|
sn=kInfinity; // Don't leave by either side
|
|
}
|
|
}
|
|
}
|
|
else if (ss1>0&&ss2>=0)
|
|
{
|
|
// Outside, in -ve Area
|
|
|
|
if (ds2<0)
|
|
{
|
|
sn=0; // away from shape
|
|
// Left by -ve side
|
|
snside=kMX;
|
|
}
|
|
else
|
|
{
|
|
if (ds1>0)
|
|
{
|
|
// Ignore +ve plane and use -ve plane intersect
|
|
//
|
|
sn=ss1/ds1; // Leave by +ve side
|
|
snside=kPX;
|
|
}
|
|
else
|
|
{
|
|
// Must be || to both -> exit determined by other axes
|
|
//
|
|
sn=kInfinity; // Don't leave by either side
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update minimum exit distance
|
|
|
|
if (sn<snxt)
|
|
{
|
|
snxt=sn;
|
|
side=snside;
|
|
}
|
|
if (snxt>0)
|
|
{
|
|
// Calculate y intersection
|
|
|
|
tanyz=(fDy2-fDy1)*0.5/fDz;
|
|
central=0.5*(fDy1+fDy2);
|
|
|
|
// +ve plane (1)
|
|
//
|
|
ss1=central+tanyz*p.z()-p.y(); // distance || y axis to plane
|
|
// (+ve if point inside)
|
|
ds1=v.y()-tanyz*v.z(); // component towards +ve plane
|
|
// (-ve if +ve -> -ve direction)
|
|
// -ve plane (2)
|
|
//
|
|
ss2=-tanyz*p.z()-p.y()-central; // distance || y axis to plane
|
|
// (-ve if point inside)
|
|
ds2=tanyz*v.z()+v.y(); // component towards -ve plane
|
|
|
|
if (ss1>0&&ss2<0)
|
|
{
|
|
// Normal case - entirely inside region
|
|
|
|
if (ds1<=0&&ds2<0)
|
|
{
|
|
if (ss2<-kCarTolerance/2)
|
|
{
|
|
sn=ss2/ds2; // Leave by -ve side
|
|
snside=kMY;
|
|
}
|
|
else
|
|
{
|
|
sn=0; // Leave immediately by -ve side
|
|
snside=kMY;
|
|
}
|
|
}
|
|
else if (ds1>0&&ds2>=0)
|
|
{
|
|
if (ss1>kCarTolerance/2)
|
|
{
|
|
sn=ss1/ds1; // Leave by +ve side
|
|
snside=kPY;
|
|
}
|
|
else
|
|
{
|
|
sn=0; // Leave immediately by +ve side
|
|
snside=kPY;
|
|
}
|
|
}
|
|
else if (ds1>0&&ds2<0)
|
|
{
|
|
if (ss1>kCarTolerance/2)
|
|
{
|
|
// sn=ss1/ds1; // Leave by +ve side
|
|
if (ss2<-kCarTolerance/2)
|
|
{
|
|
sn=ss1/ds1; // Leave by +ve side
|
|
sn2=ss2/ds2;
|
|
if (sn2<sn)
|
|
{
|
|
sn=sn2;
|
|
snside=kMY;
|
|
}
|
|
else
|
|
{
|
|
snside=kPY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sn=0; // Leave immediately by -ve
|
|
snside=kMY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sn=0; // Leave immediately by +ve side
|
|
snside=kPY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Must be || to both
|
|
//
|
|
sn=kInfinity; // Don't leave by either side
|
|
}
|
|
}
|
|
else if (ss1<=0&&ss2<0)
|
|
{
|
|
// Outside, in +ve Area
|
|
|
|
if (ds1>0)
|
|
{
|
|
sn=0; // Away from shape
|
|
// Left by +ve side
|
|
snside=kPY;
|
|
}
|
|
else
|
|
{
|
|
if (ds2<0)
|
|
{
|
|
// Ignore +ve plane and use -ve plane intersect
|
|
//
|
|
sn=ss2/ds2; // Leave by -ve side
|
|
snside=kMY;
|
|
}
|
|
else
|
|
{
|
|
// Must be || to both -> exit determined by other axes
|
|
//
|
|
sn=kInfinity; // Don't leave by either side
|
|
}
|
|
}
|
|
}
|
|
else if (ss1>0&&ss2>=0)
|
|
{
|
|
// Outside, in -ve Area
|
|
if (ds2<0)
|
|
{
|
|
sn=0; // away from shape
|
|
// Left by -ve side
|
|
snside=kMY;
|
|
}
|
|
else
|
|
{
|
|
if (ds1>0)
|
|
{
|
|
// Ignore +ve plane and use -ve plane intersect
|
|
//
|
|
sn=ss1/ds1; // Leave by +ve side
|
|
snside=kPY;
|
|
}
|
|
else
|
|
{
|
|
// Must be || to both -> exit determined by other axes
|
|
//
|
|
sn=kInfinity; // Don't leave by either side
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update minimum exit distance
|
|
|
|
if (sn<snxt)
|
|
{
|
|
snxt=sn;
|
|
side=snside;
|
|
}
|
|
}
|
|
|
|
if (calcNorm)
|
|
{
|
|
switch (side)
|
|
{
|
|
case kPX:
|
|
cosxz=1.0/std::sqrt(1.0+tanxz*tanxz);
|
|
*n=G4ThreeVector(cosxz,0,-tanxz*cosxz);
|
|
break;
|
|
case kMX:
|
|
cosxz=-1.0/std::sqrt(1.0+tanxz*tanxz);
|
|
*n=G4ThreeVector(cosxz,0,tanxz*cosxz);
|
|
break;
|
|
case kPY:
|
|
cosyz=1.0/std::sqrt(1.0+tanyz*tanyz);
|
|
*n=G4ThreeVector(0,cosyz,-tanyz*cosyz);
|
|
break;
|
|
case kMY:
|
|
cosyz=-1.0/std::sqrt(1.0+tanyz*tanyz);
|
|
*n=G4ThreeVector(0,cosyz,tanyz*cosyz);
|
|
break;
|
|
case kPZ:
|
|
*n=G4ThreeVector(0,0,1);
|
|
break;
|
|
case kMZ:
|
|
*n=G4ThreeVector(0,0,-1);
|
|
break;
|
|
default:
|
|
DumpInfo();
|
|
G4Exception("G4Trd::DistanceToOut(p,v,..)",
|
|
"GeomSolids1002", JustWarning,
|
|
"Undefined side for valid surface normal to solid.");
|
|
break;
|
|
}
|
|
}
|
|
return snxt;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Calculate exact shortest distance to any boundary from inside
|
|
// - Returns 0 is point outside
|
|
|
|
G4double G4Trd::DistanceToOut( const G4ThreeVector& p ) const
|
|
{
|
|
G4double safe=0.0;
|
|
G4double tanxz,xdist,saf1;
|
|
G4double tanyz,ydist,saf2;
|
|
G4double zbase;
|
|
|
|
#ifdef G4CSGDEBUG
|
|
if( Inside(p) == kOutside )
|
|
{
|
|
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("G4Trd::DistanceToOut(p)", "GeomSolids1002", JustWarning,
|
|
"Point p is outside !?" );
|
|
}
|
|
#endif
|
|
|
|
safe=fDz-std::fabs(p.z()); // z perpendicular Dist
|
|
|
|
zbase=fDz+p.z();
|
|
|
|
// xdist = distance perpendicular to z axis to closest x plane from p
|
|
// = (x half width of shape at p.z) - std::fabs(p.x)
|
|
//
|
|
tanxz=(fDx2-fDx1)*0.5/fDz;
|
|
xdist=fDx1+tanxz*zbase-std::fabs(p.x());
|
|
saf1=xdist/std::sqrt(1.0+tanxz*tanxz); // x*std::cos(ang_xz) =
|
|
// shortest (perpendicular)
|
|
// distance to plane
|
|
tanyz=(fDy2-fDy1)*0.5/fDz;
|
|
ydist=fDy1+tanyz*zbase-std::fabs(p.y());
|
|
saf2=ydist/std::sqrt(1.0+tanyz*tanyz);
|
|
|
|
// Return minimum x/y/z distance
|
|
//
|
|
if (safe>saf1) safe=saf1;
|
|
if (safe>saf2) safe=saf2;
|
|
|
|
if (safe<0) safe=0;
|
|
return safe;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetEntityType
|
|
|
|
G4GeometryType G4Trd::GetEntityType() const
|
|
{
|
|
return G4String("G4Trd");
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Make a clone of the object
|
|
//
|
|
G4VSolid* G4Trd::Clone() const
|
|
{
|
|
return new G4Trd(*this);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Stream object contents to an output stream
|
|
|
|
std::ostream& G4Trd::StreamInfo( std::ostream& os ) const
|
|
{
|
|
G4int oldprc = os.precision(16);
|
|
os << "-----------------------------------------------------------\n"
|
|
<< " *** Dump for solid - " << GetName() << " ***\n"
|
|
<< " ===================================================\n"
|
|
<< " Solid type: G4Trd\n"
|
|
<< " Parameters: \n"
|
|
<< " half length X, surface -dZ: " << fDx1/mm << " mm \n"
|
|
<< " half length X, surface +dZ: " << fDx2/mm << " mm \n"
|
|
<< " half length Y, surface -dZ: " << fDy1/mm << " mm \n"
|
|
<< " half length Y, surface +dZ: " << fDy2/mm << " mm \n"
|
|
<< " half length Z : " << fDz/mm << " mm \n"
|
|
<< "-----------------------------------------------------------\n";
|
|
os.precision(oldprc);
|
|
|
|
return os;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetPointOnSurface
|
|
//
|
|
// Return a point (G4ThreeVector) randomly and uniformly
|
|
// selected on the solid surface
|
|
|
|
G4ThreeVector G4Trd::GetPointOnSurface() const
|
|
{
|
|
G4double px, py, pz, tgX, tgY, secX, secY, select, sumS, tmp;
|
|
G4double Sxy1, Sxy2, Sxy, Sxz, Syz;
|
|
|
|
tgX = 0.5*(fDx2-fDx1)/fDz;
|
|
secX = std::sqrt(1+tgX*tgX);
|
|
tgY = 0.5*(fDy2-fDy1)/fDz;
|
|
secY = std::sqrt(1+tgY*tgY);
|
|
|
|
// calculate 0.25 of side surfaces, sumS is 0.25 of total surface
|
|
|
|
Sxy1 = fDx1*fDy1;
|
|
Sxy2 = fDx2*fDy2;
|
|
Sxy = Sxy1 + Sxy2;
|
|
Sxz = (fDx1 + fDx2)*fDz*secY;
|
|
Syz = (fDy1 + fDy2)*fDz*secX;
|
|
sumS = Sxy + Sxz + Syz;
|
|
|
|
select = sumS*G4UniformRand();
|
|
|
|
if( select < Sxy ) // Sxy1 or Sxy2
|
|
{
|
|
if( select < Sxy1 )
|
|
{
|
|
pz = -fDz;
|
|
px = -fDx1 + 2*fDx1*G4UniformRand();
|
|
py = -fDy1 + 2*fDy1*G4UniformRand();
|
|
}
|
|
else
|
|
{
|
|
pz = fDz;
|
|
px = -fDx2 + 2*fDx2*G4UniformRand();
|
|
py = -fDy2 + 2*fDy2*G4UniformRand();
|
|
}
|
|
}
|
|
else if ( ( select - Sxy ) < Sxz ) // Sxz
|
|
{
|
|
pz = -fDz + 2*fDz*G4UniformRand();
|
|
tmp = fDx1 + (pz + fDz)*tgX;
|
|
px = -tmp + 2*tmp*G4UniformRand();
|
|
tmp = fDy1 + (pz + fDz)*tgY;
|
|
|
|
if(G4UniformRand() > 0.5) { py = tmp; }
|
|
else { py = -tmp; }
|
|
}
|
|
else // Syz
|
|
{
|
|
pz = -fDz + 2*fDz*G4UniformRand();
|
|
tmp = fDy1 + (pz + fDz)*tgY;
|
|
py = -tmp + 2*tmp*G4UniformRand();
|
|
tmp = fDx1 + (pz + fDz)*tgX;
|
|
|
|
if(G4UniformRand() > 0.5) { px = tmp; }
|
|
else { px = -tmp; }
|
|
}
|
|
return G4ThreeVector(px,py,pz);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Methods for visualisation
|
|
|
|
void G4Trd::DescribeYourselfTo ( G4VGraphicsScene& scene ) const
|
|
{
|
|
scene.AddSolid (*this);
|
|
}
|
|
|
|
G4Polyhedron* G4Trd::CreatePolyhedron () const
|
|
{
|
|
return new G4PolyhedronTrd2 (fDx1, fDx2, fDy1, fDy2, fDz);
|
|
}
|
|
|
|
#endif
|