798 lines
20 KiB
C++
798 lines
20 KiB
C++
//
|
|
// ********************************************************************
|
|
// * DISCLAIMER *
|
|
// * *
|
|
// * The following disclaimer summarizes all the specific disclaimers *
|
|
// * of contributors to this software. The specific disclaimers,which *
|
|
// * govern, are listed with their locations in: *
|
|
// * http://cern.ch/geant4/license *
|
|
// * *
|
|
// * 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. *
|
|
// * *
|
|
// * 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. *
|
|
// ********************************************************************
|
|
//
|
|
//
|
|
// $Id: G4EllipticalTube.cc,v 1.13 2002/10/28 15:18:40 gcosmo Exp $
|
|
// GEANT4 tag $Name: geant4-05-00 $
|
|
//
|
|
//
|
|
// --------------------------------------------------------------------
|
|
// GEANT 4 class source file
|
|
//
|
|
//
|
|
// G4EllipticalTube.cc
|
|
//
|
|
// Implementation of a CSG volume representing a tube with elliptical cross
|
|
// section (geant3 solid 'ELTU')
|
|
//
|
|
// --------------------------------------------------------------------
|
|
|
|
#include "G4EllipticalTube.hh"
|
|
|
|
#include "G4ClippablePolygon.hh"
|
|
#include "G4AffineTransform.hh"
|
|
#include "G4SolidExtentList.hh"
|
|
#include "G4VoxelLimits.hh"
|
|
#include "meshdefs.hh"
|
|
|
|
#include "G4VGraphicsScene.hh"
|
|
#include "G4Polyhedron.hh"
|
|
#include "G4VisExtent.hh"
|
|
|
|
//
|
|
// Constructor
|
|
//
|
|
G4EllipticalTube::G4EllipticalTube( const G4String &name,
|
|
G4double theDx,
|
|
G4double theDy,
|
|
G4double theDz )
|
|
: G4VSolid( name )
|
|
{
|
|
dx = theDx;
|
|
dy = theDy;
|
|
dz = theDz;
|
|
}
|
|
|
|
|
|
//
|
|
// Destructor
|
|
//
|
|
G4EllipticalTube::~G4EllipticalTube() {;}
|
|
|
|
|
|
//
|
|
// CalculateExtent
|
|
//
|
|
G4bool
|
|
G4EllipticalTube::CalculateExtent( const EAxis axis,
|
|
const G4VoxelLimits &voxelLimit,
|
|
const G4AffineTransform &transform,
|
|
G4double &min, G4double &max ) const
|
|
{
|
|
G4SolidExtentList extentList( axis, voxelLimit );
|
|
|
|
//
|
|
// We are going to divide up our elliptical face into small
|
|
// pieces
|
|
//
|
|
|
|
//
|
|
// Choose phi size of our segment(s) based on constants as
|
|
// defined in meshdefs.hh
|
|
//
|
|
G4int numPhi = kMaxMeshSections;
|
|
G4double sigPhi = 2*M_PI/numPhi;
|
|
|
|
//
|
|
// We have to be careful to keep our segments completely outside
|
|
// of the elliptical surface. To do so we imagine we have
|
|
// a simple (unit radius) circular cross section (as in G4Tubs)
|
|
// and then "stretch" the dimensions as necessary to fit the ellipse.
|
|
//
|
|
G4double rFudge = 1.0/cos(0.5*sigPhi);
|
|
G4double dxFudge = dx*rFudge,
|
|
dyFudge = dy*rFudge;
|
|
|
|
//
|
|
// As we work around the elliptical surface, we build
|
|
// a "phi" segment on the way, and keep track of two
|
|
// additional polygons for the two ends.
|
|
//
|
|
G4ClippablePolygon endPoly1, endPoly2, phiPoly;
|
|
|
|
G4double phi = 0,
|
|
cosPhi = cos(phi),
|
|
sinPhi = sin(phi);
|
|
G4ThreeVector v0( dxFudge*cosPhi, dyFudge*sinPhi, +dz ),
|
|
v1( dxFudge*cosPhi, dyFudge*sinPhi, -dz ),
|
|
w0, w1;
|
|
transform.ApplyPointTransform( v0 );
|
|
transform.ApplyPointTransform( v1 );
|
|
do
|
|
{
|
|
phi += sigPhi;
|
|
if (numPhi == 1) phi = 0; // Try to avoid roundoff
|
|
cosPhi = cos(phi),
|
|
sinPhi = sin(phi);
|
|
|
|
w0 = G4ThreeVector( dxFudge*cosPhi, dyFudge*sinPhi, +dz );
|
|
w1 = G4ThreeVector( dxFudge*cosPhi, dyFudge*sinPhi, -dz );
|
|
transform.ApplyPointTransform( w0 );
|
|
transform.ApplyPointTransform( w1 );
|
|
|
|
//
|
|
// Add a point to our z ends
|
|
//
|
|
endPoly1.AddVertexInOrder( v0 );
|
|
endPoly2.AddVertexInOrder( v1 );
|
|
|
|
//
|
|
// Build phi polygon
|
|
//
|
|
phiPoly.ClearAllVertices();
|
|
|
|
phiPoly.AddVertexInOrder( v0 );
|
|
phiPoly.AddVertexInOrder( v1 );
|
|
phiPoly.AddVertexInOrder( w1 );
|
|
phiPoly.AddVertexInOrder( w0 );
|
|
|
|
if (phiPoly.PartialClip( voxelLimit, axis ))
|
|
{
|
|
//
|
|
// Get unit normal
|
|
//
|
|
phiPoly.SetNormal( (v1-v0).cross(w0-v0).unit() );
|
|
|
|
extentList.AddSurface( phiPoly );
|
|
}
|
|
|
|
//
|
|
// Next vertex
|
|
//
|
|
v0 = w0;
|
|
v1 = w1;
|
|
} while( --numPhi > 0 );
|
|
|
|
//
|
|
// Process the end pieces
|
|
//
|
|
if (endPoly1.PartialClip( voxelLimit, axis ))
|
|
{
|
|
static const G4ThreeVector normal(0,0,+1);
|
|
endPoly1.SetNormal( transform.TransformAxis(normal) );
|
|
extentList.AddSurface( endPoly1 );
|
|
}
|
|
|
|
if (endPoly2.PartialClip( voxelLimit, axis ))
|
|
{
|
|
static const G4ThreeVector normal(0,0,-1);
|
|
endPoly2.SetNormal( transform.TransformAxis(normal) );
|
|
extentList.AddSurface( endPoly2 );
|
|
}
|
|
|
|
//
|
|
// Return min/max value
|
|
//
|
|
return extentList.GetExtent( min, max );
|
|
}
|
|
|
|
|
|
//
|
|
// Inside
|
|
//
|
|
// Note that for this solid, we've decided to define the tolerant
|
|
// surface as that which is bounded by ellipses with axes
|
|
// at +/- 0.5*kCarTolerance.
|
|
//
|
|
EInside G4EllipticalTube::Inside( const G4ThreeVector& p ) const
|
|
{
|
|
static const G4double halfTol = 0.5*kCarTolerance;
|
|
|
|
//
|
|
// Check z extents: are we outside?
|
|
//
|
|
G4double absZ = fabs(p.z());
|
|
if (absZ > dz+halfTol) return kOutside;
|
|
|
|
//
|
|
// Check x,y: are we outside?
|
|
//
|
|
// G4double x = p.x(), y = p.y();
|
|
|
|
if (CheckXY(p.x(), p.y(), +halfTol) > 1.0) return kOutside;
|
|
|
|
//
|
|
// We are either inside or on the surface: recheck z extents
|
|
//
|
|
if (absZ > dz-halfTol) return kSurface;
|
|
|
|
//
|
|
// Recheck x,y
|
|
//
|
|
if (CheckXY(p.x(), p.y(), -halfTol) > 1.0) return kSurface;
|
|
|
|
return kInside;
|
|
}
|
|
|
|
|
|
//
|
|
// SurfaceNormal
|
|
//
|
|
G4ThreeVector G4EllipticalTube::SurfaceNormal( const G4ThreeVector& p ) const
|
|
{
|
|
//
|
|
// Which of the three surfaces are we closest to (approximately)?
|
|
//
|
|
G4double distZ = fabs(p.z()) - dz;
|
|
|
|
G4double rxy = CheckXY( p.x(), p.y() );
|
|
G4double distR2 = (rxy < DBL_MIN) ? DBL_MAX : 1.0/rxy;
|
|
|
|
//
|
|
// Closer to z?
|
|
//
|
|
if (distZ*distZ < distR2)
|
|
return G4ThreeVector( 0.0, 0.0, p.z() < 0 ? -1.0 : 1.0 );
|
|
|
|
//
|
|
// Closer to x/y
|
|
//
|
|
return G4ThreeVector( p.x()*dy*dy, p.y()*dx*dx, 0.0 ).unit();
|
|
}
|
|
|
|
|
|
//
|
|
// DistanceToIn(p,v)
|
|
//
|
|
// Unlike DistanceToOut(p,v), it is possible for the trajectory
|
|
// to miss. The geometric calculations here are quite simple.
|
|
// More difficult is the logic required to prevent particles
|
|
// from sneaking (or leaking) between the elliptical and end
|
|
// surfaces.
|
|
//
|
|
// Keep in mind that the true distance is allowed to be
|
|
// negative if the point is currently on the surface. For oblique
|
|
// angles, it can be very negative.
|
|
//
|
|
G4double G4EllipticalTube::DistanceToIn( const G4ThreeVector& p,
|
|
const G4ThreeVector& v ) const
|
|
{
|
|
static const G4double halfTol = 0.5*kCarTolerance;
|
|
|
|
//
|
|
// Check z = -dz planer surface
|
|
//
|
|
G4double sigz = p.z()+dz;
|
|
|
|
if (sigz < halfTol)
|
|
{
|
|
//
|
|
// We are "behind" the shape in z, and so can
|
|
// potentially hit the rear face. Correct direction?
|
|
//
|
|
if (v.z() <= 0)
|
|
{
|
|
//
|
|
// As long as we are far enough away, we know we
|
|
// can't intersect
|
|
//
|
|
if (sigz < 0) return kInfinity;
|
|
|
|
//
|
|
// Otherwise, we don't intersect unless we are
|
|
// on the surface of the ellipse
|
|
//
|
|
if (CheckXY(p.x(),p.y(),-halfTol) <= 1.0) return kInfinity;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// How far?
|
|
//
|
|
G4double s = -sigz/v.z();
|
|
|
|
//
|
|
// Where does that place us?
|
|
//
|
|
G4double xi = p.x() + s*v.x(),
|
|
yi = p.y() + s*v.y();
|
|
|
|
//
|
|
// Is this on the surface (within ellipse)?
|
|
//
|
|
if (CheckXY(xi,yi) <= 1.0)
|
|
{
|
|
//
|
|
// Yup. Return s, unless we are on the surface
|
|
//
|
|
return (sigz < -halfTol) ? s : 0;
|
|
}
|
|
else if (xi*dy*dy*v.x() + yi*dx*dx*v.y() >= 0)
|
|
{
|
|
//
|
|
// Else, if we are traveling outwards, we know
|
|
// we must miss
|
|
//
|
|
return kInfinity;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check z = +dz planer surface
|
|
//
|
|
sigz = p.z() - dz;
|
|
|
|
if (sigz > -halfTol)
|
|
{
|
|
if (v.z() >= 0)
|
|
{
|
|
if (sigz > 0) return kInfinity;
|
|
if (CheckXY(p.x(),p.y(),-halfTol) <= 1.0) return kInfinity;
|
|
}
|
|
else {
|
|
G4double s = -sigz/v.z();
|
|
|
|
G4double xi = p.x() + s*v.x(),
|
|
yi = p.y() + s*v.y();
|
|
|
|
if (CheckXY(xi,yi) <= 1.0)
|
|
{
|
|
return (sigz > -halfTol) ? s : 0;
|
|
}
|
|
else if (xi*dy*dy*v.x() + yi*dx*dx*v.y() >= 0)
|
|
{
|
|
return kInfinity;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check intersection with the elliptical tube
|
|
//
|
|
G4double s[2];
|
|
G4int n = IntersectXY( p, v, s );
|
|
|
|
if (n==0) return kInfinity;
|
|
|
|
//
|
|
// Is the original point on the surface?
|
|
//
|
|
if (fabs(p.z()) < dz+halfTol) {
|
|
if (CheckXY( p.x(), p.y(), halfTol ) < 1.0)
|
|
{
|
|
//
|
|
// Well, yes, but are we traveling inwards at this point?
|
|
//
|
|
if (p.x()*dy*dy*v.x() + p.y()*dx*dx*v.y() < 0) return 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// We are now certain that point p is not on the surface of
|
|
// the solid (and thus fabs(s[0]) > halfTol).
|
|
// Return kInfinity if the intersection is "behind" the point.
|
|
//
|
|
if (s[0] < 0) return kInfinity;
|
|
|
|
//
|
|
// Check to see if we intersect the tube within
|
|
// dz, but only when we know it might miss
|
|
//
|
|
G4double zi = p.z() + s[0]*v.z();
|
|
|
|
if (v.z() < 0)
|
|
{
|
|
if (zi < -dz) return kInfinity;
|
|
}
|
|
else if (v.z() > 0)
|
|
{
|
|
if (zi > +dz) return kInfinity;
|
|
}
|
|
|
|
return s[0];
|
|
}
|
|
|
|
|
|
//
|
|
// DistanceToIn(p)
|
|
//
|
|
// The distance from a point to an ellipse (in 2 dimensions) is a
|
|
// surprisingly complicated quadric expression (this is easy to
|
|
// appreciate once one understands that there may be up to
|
|
// four lines normal to the ellipse intersecting any point). To
|
|
// solve it exactly would be rather time consuming. This method,
|
|
// however, is supposed to be a quick check, and is allowed to be an
|
|
// underestimate.
|
|
//
|
|
// So, I will use the following underestimate of the distance
|
|
// from an outside point to an ellipse. First: find the intersection "A"
|
|
// of the line from the origin to the point with the ellipse.
|
|
// Find the line passing through "A" and tangent to the ellipse
|
|
// at A. The distance of the point p from the ellipse will be approximated
|
|
// as the distance to this line.
|
|
//
|
|
G4double G4EllipticalTube::DistanceToIn( const G4ThreeVector& p ) const
|
|
{
|
|
static const G4double halfTol = 0.5*kCarTolerance;
|
|
|
|
if (CheckXY( p.x(), p.y(), +halfTol ) < 1.0)
|
|
{
|
|
//
|
|
// We are inside or on the surface of the
|
|
// elliptical cross section in x/y. Check z
|
|
//
|
|
if (p.z() < -dz-halfTol)
|
|
return -p.z()-dz;
|
|
else if (p.z() > dz+halfTol)
|
|
return p.z()-dz;
|
|
else
|
|
return 0; // On any surface here (or inside)
|
|
}
|
|
|
|
//
|
|
// Find point on ellipse
|
|
//
|
|
G4double qnorm = CheckXY( p.x(), p.y() );
|
|
if (qnorm < DBL_MIN) return 0; // This should never happen
|
|
|
|
G4double q = 1.0/sqrt(qnorm);
|
|
|
|
G4double xe = q*p.x(), ye = q*p.y();
|
|
|
|
//
|
|
// Get tangent to ellipse
|
|
//
|
|
G4double tx = -ye*dx*dx, ty = +xe*dy*dy;
|
|
G4double tnorm = sqrt( tx*tx + ty*ty );
|
|
|
|
//
|
|
// Calculate distance
|
|
//
|
|
G4double distR = ( (p.x()-xe)*ty - (p.y()-ye)*tx )/tnorm;
|
|
|
|
//
|
|
// Add the result in quadrature if we are, in addition,
|
|
// outside the z bounds of the shape
|
|
//
|
|
// We could save some time by returning the maximum rather
|
|
// than the quadrature sum
|
|
//
|
|
if (p.z() < -dz)
|
|
return sqrt( (p.z()+dz)*(p.z()+dz) + distR*distR );
|
|
else if (p.z() > dz)
|
|
return sqrt( (p.z()-dz)*(p.z()-dz) + distR*distR );
|
|
|
|
return distR;
|
|
}
|
|
|
|
|
|
//
|
|
// DistanceToOut(p,v)
|
|
//
|
|
// This method can be somewhat complicated for a general shape.
|
|
// For a convex one, like this, there are several simplifications,
|
|
// the most important of which is that one can treat the surfaces
|
|
// as infinite in extent when deciding if the p is on the surface.
|
|
//
|
|
G4double G4EllipticalTube::DistanceToOut( const G4ThreeVector& p,
|
|
const G4ThreeVector& v,
|
|
const G4bool calcNorm,
|
|
G4bool *validNorm,
|
|
G4ThreeVector *norm ) const
|
|
{
|
|
static const G4double halfTol = 0.5*kCarTolerance;
|
|
|
|
//
|
|
// Our normal is always valid
|
|
//
|
|
if (calcNorm) *validNorm = true;
|
|
|
|
G4double sBest = kInfinity;
|
|
const G4ThreeVector *nBest=0;
|
|
|
|
//
|
|
// Might we intersect the -dz surface?
|
|
//
|
|
if (v.z() < 0)
|
|
{
|
|
static const G4ThreeVector normHere(0.0,0.0,-1.0);
|
|
//
|
|
// Yup. What distance?
|
|
//
|
|
sBest = -(p.z()+dz)/v.z();
|
|
|
|
//
|
|
// Are we on the surface? If so, return zero
|
|
//
|
|
if (p.z() < -dz+halfTol) {
|
|
if (calcNorm) *norm = normHere;
|
|
return 0;
|
|
}
|
|
else
|
|
nBest = &normHere;
|
|
}
|
|
|
|
//
|
|
// How about the +dz surface?
|
|
//
|
|
if (v.z() > 0)
|
|
{
|
|
static const G4ThreeVector normHere(0.0,0.0,+1.0);
|
|
//
|
|
// Yup. What distance?
|
|
//
|
|
G4double s = (dz-p.z())/v.z();
|
|
|
|
//
|
|
// Are we on the surface? If so, return zero
|
|
//
|
|
if (p.z() > +dz-halfTol) {
|
|
if (calcNorm) *norm = normHere;
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Best so far?
|
|
//
|
|
if (s < sBest) { sBest = s; nBest = &normHere; }
|
|
}
|
|
|
|
//
|
|
// Check furthest intersection with ellipse
|
|
//
|
|
G4double s[2];
|
|
G4int n = IntersectXY( p, v, s );
|
|
|
|
if (n == 0)
|
|
{
|
|
if (sBest == kInfinity)
|
|
{
|
|
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 << "Direction:" << G4endl << G4endl;
|
|
G4cout << "v.x() = " << v.x() << G4endl;
|
|
G4cout << "v.y() = " << v.y() << G4endl;
|
|
G4cout << "v.z() = " << v.z() << G4endl << G4endl;
|
|
G4cout << "Proposed distance :" << G4endl << G4endl;
|
|
G4cout << "snxt = " << sBest/mm << " mm" << G4endl << G4endl;
|
|
G4Exception( "G4EllipticalTube::DistanceToOut() - Point p is outside" );
|
|
}
|
|
if (calcNorm) *norm = *nBest;
|
|
return sBest;
|
|
}
|
|
else if (s[n-1] > sBest)
|
|
{
|
|
if (calcNorm) *norm = *nBest;
|
|
return sBest;
|
|
}
|
|
sBest = s[n-1];
|
|
|
|
//
|
|
// Intersection with ellipse. Get normal at intersection point.
|
|
//
|
|
if (calcNorm)
|
|
{
|
|
G4ThreeVector ip = p + sBest*v;
|
|
*norm = G4ThreeVector( ip.x()*dy*dy, ip.y()*dx*dx, 0.0 ).unit();
|
|
}
|
|
|
|
//
|
|
// Do we start on the surface?
|
|
//
|
|
if (CheckXY( p.x(), p.y(), -halfTol ) > 1.0)
|
|
{
|
|
//
|
|
// Well, yes, but are we traveling outwards at this point?
|
|
//
|
|
if (p.x()*dy*dy*v.x() + p.y()*dx*dx*v.y() > 0) return 0;
|
|
}
|
|
|
|
return sBest;
|
|
}
|
|
|
|
|
|
//
|
|
// DistanceToOut(p)
|
|
//
|
|
// See DistanceToIn(p) for notes on the distance from a point
|
|
// to an ellipse in two dimensions.
|
|
//
|
|
// The approximation used here for a point inside the ellipse
|
|
// is to find the intersection with the ellipse of the lines
|
|
// through the point and parallel to the x and y axes. The
|
|
// distance of the point from the line connecting the two
|
|
// intersecting points is then used.
|
|
//
|
|
G4double G4EllipticalTube::DistanceToOut( const G4ThreeVector& p ) const
|
|
{
|
|
static const G4double halfTol = 0.5*kCarTolerance;
|
|
|
|
//
|
|
// We need to calculate the distances to all surfaces,
|
|
// and then return the smallest
|
|
//
|
|
// Check -dz and +dz surface
|
|
//
|
|
G4double sBest = dz - fabs(p.z());
|
|
if (sBest < halfTol) return 0;
|
|
|
|
//
|
|
// Check elliptical surface: find intersection of
|
|
// line through p and parallel to x axis
|
|
//
|
|
G4double radical = 1.0 - p.y()*p.y()/dy/dy;
|
|
if (radical < +DBL_MIN) return 0;
|
|
|
|
G4double xi = dx*sqrt( radical );
|
|
if (p.x() < 0) xi = -xi;
|
|
|
|
//
|
|
// Do the same with y axis
|
|
//
|
|
radical = 1.0 - p.x()*p.x()/dx/dx;
|
|
if (radical < +DBL_MIN) return 0;
|
|
|
|
G4double yi = dy*sqrt( radical );
|
|
if (p.y() < 0) yi = -yi;
|
|
|
|
//
|
|
// Get distance from p to the line connecting
|
|
// these two points
|
|
//
|
|
G4double xdi = p.x() - xi,
|
|
ydi = yi - p.y();
|
|
|
|
G4double normi = sqrt( xdi*xdi + ydi*ydi );
|
|
if (normi < halfTol) return 0;
|
|
xdi /= normi;
|
|
ydi /= normi;
|
|
|
|
G4double s = 0.5*(xdi*(p.y()-yi) - ydi*(p.x()-xi));
|
|
if (xi*yi < 0) s = -s;
|
|
|
|
if (s < sBest) sBest = s;
|
|
|
|
//
|
|
// Return best answer
|
|
//
|
|
return sBest < halfTol ? 0 : sBest;
|
|
}
|
|
|
|
|
|
//
|
|
// CreatePolyhedron
|
|
//
|
|
G4Polyhedron* G4EllipticalTube::CreatePolyhedron() const
|
|
{
|
|
// create cylinder with radius=1...
|
|
//
|
|
G4Polyhedron* eTube = new G4PolyhedronTube(0.,1.,dz);
|
|
|
|
// apply non-uniform scaling...
|
|
//
|
|
eTube->Transform(G4Scale3D(dx,dy,1.));
|
|
return eTube;
|
|
}
|
|
|
|
|
|
//
|
|
// GetEntityType
|
|
//
|
|
G4GeometryType G4EllipticalTube::GetEntityType() const
|
|
{
|
|
return G4String("G4EllipticalTube");
|
|
}
|
|
|
|
|
|
//
|
|
// Stream object contents to an output stream
|
|
//
|
|
G4std::ostream& G4EllipticalTube::StreamInfo(G4std::ostream& os) const
|
|
{
|
|
os << "-----------------------------------------------------------\n"
|
|
<< " *** Dump for solid - " << GetName() << " ***\n"
|
|
<< " ===================================================\n"
|
|
<< " Solid type: G4EllipticalTube\n"
|
|
<< " Parameters: \n"
|
|
<< " length Z: " << dz/mm << " mm \n"
|
|
<< " surface equation in X and Y: \n"
|
|
<< " (X / " << dx << ")^2 + (Y / " << dy << ")^2 = 1 \n"
|
|
<< "-----------------------------------------------------------\n";
|
|
|
|
return os;
|
|
}
|
|
|
|
|
|
//
|
|
// DescribeYourselfTo
|
|
//
|
|
void G4EllipticalTube::DescribeYourselfTo( G4VGraphicsScene& scene ) const
|
|
{
|
|
scene.AddThis (*this);
|
|
}
|
|
|
|
|
|
//
|
|
// GetExtent
|
|
//
|
|
G4VisExtent G4EllipticalTube::GetExtent() const
|
|
{
|
|
return G4VisExtent( -dx, dx, -dy, dy, -dz, dz );
|
|
}
|
|
|
|
|
|
//
|
|
// IntersectXY
|
|
//
|
|
// Decide if and where the x/y trajectory hits the elliptical cross
|
|
// section.
|
|
//
|
|
// Arguments:
|
|
// p - (in) Point on trajectory
|
|
// v - (in) Vector along trajectory
|
|
// s - (out) Up to two points of intersection, where the
|
|
// intersection point is p + s*v, and if there are
|
|
// two intersections, s[0] < s[1]. May be negative.
|
|
// Returns:
|
|
// The number of intersections. If 0, the trajectory misses. If 1, the
|
|
// trajectory just grazes the surface.
|
|
//
|
|
// Solution:
|
|
// One needs to solve: ( (p.x + s*v.x)/dx )**2 + ( (p.y + s*v.y)/dy )**2 = 1
|
|
//
|
|
// The solution is quadratic: a*s**2 + b*s + c = 0
|
|
//
|
|
// a = (v.x/dx)**2 + (v.y/dy)**2
|
|
// b = 2*p.x*v.x/dx**2 + 2*p.y*v.y/dy**2
|
|
// c = (p.x/dx)**2 + (p.y/dy)**2 - 1
|
|
//
|
|
G4int G4EllipticalTube::IntersectXY( const G4ThreeVector &p,
|
|
const G4ThreeVector &v,
|
|
G4double s[2] ) const
|
|
{
|
|
G4double px = p.x(), py = p.y();
|
|
G4double vx = v.x(), vy = v.y();
|
|
|
|
G4double a = (vx/dx)*(vx/dx) + (vy/dy)*(vy/dy);
|
|
G4double b = 2.0*( px*vx/dx/dx + py*vy/dy/dy );
|
|
G4double c = (px/dx)*(px/dx) + (py/dy)*(py/dy) - 1.0;
|
|
|
|
if (a < DBL_MIN) return 0; // Trajectory parallel to z axis
|
|
|
|
G4double radical = b*b - 4*a*c;
|
|
|
|
if (radical < -DBL_MIN) return 0; // No solution
|
|
|
|
if (radical < DBL_MIN)
|
|
{
|
|
//
|
|
// Grazes surface
|
|
//
|
|
s[0] = -b/a/2.0;
|
|
return 1;
|
|
}
|
|
|
|
radical = sqrt(radical);
|
|
|
|
G4double q = -0.5*( b + (b < 0 ? -radical : +radical) );
|
|
G4double sa = q/a;
|
|
G4double sb = c/q;
|
|
if (sa < sb) { s[0] = sa; s[1] = sb; } else { s[0] = sb; s[1] = sa; }
|
|
return 2;
|
|
}
|