Files
geant4/source/geometry/solids/BREPS/src/G4SphericalSurface.cc
T
2016-06-08 15:28:20 +02:00

882 lines
29 KiB
C++

// 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: G4SphericalSurface.cc,v 1.1.10.1 1999/12/07 20:48:27 gunter Exp $
// GEANT4 tag $Name: geant4-01-00 $
//
/* $Header: /private/Net/unixhub/u1/ea/liml/gismo/gismo-0.2/geometry/RCS/G4SphericalSurface.cc,v 1.10 1992/08 */
// File: G4SphericalSurface.cc
// Author: Lorraine Lim
// Additional author: Alan Breakstone
// Contents ----------------------------------------------------------
//
// G4SphericalSurface::G4SphericalSurface()
// G4SphericalSurface::G4SphericalSurface( const G4Vector3D& o, const G4Vector3D& xhat,
// const G4Vector3D& zhat,
// G4double r, G4double ph1, G4double ph2,
// G4double th1, G4double th2 )
// G4SphericalSurface::PrintOn( ostream& os ) const
// G4SphericalSurface::HowNear( const G4Vector3D& x ) const
// G4SphericalSurface::distanceAlongRay( int which_way, const Ray* ry,
// G4Vector3D& p ) const
// G4SphericalSurface::distanceAlongHelix( int which_way, const Helix* hx,
// G4Vector3D& p ) const
// G4SphericalSurface::Normal( const G4Vector3D& p ) const
// G4SphericalSurface::Inside( const G4Vector3D& x ) const
// G4SphericalSurface::WithinBoundary( const G4Vector3D& x ) const
// G4SphericalSurface::Scale() const
// G4SphericalSurface::Area() const
// G4SphericalSurface::resize( G4double r, G4double ph1, G4double ph2,
// G4double th1, G4double th2 )
// G4SphericalSurface::rotate( G4double alpha, G4double beta,
// G4double gamma, G4ThreeMat& m, int inverse )
// G4SphericalSurface::rotate( G4double alpha, G4double beta,
// G4double gamma, int inverse )
// G4SphericalSurface::gropeAlongHelix( const Helix* hx ) const
//
// End ---------------------------------------------------------------
#include "G4SphericalSurface.hh"
/*
G4SphericalSurface::G4SphericalSurface() : G4Surface()
{ // default constructor
// default x_axis is ( 1.0, 0.0, 0.0 ), z_axis is ( 0.0, 0.0, 1.0 ),
// default radius is 1.0
// default phi_1 is 0, phi_2 is 2*PI
// default theta_1 is 0, theta_2 is PI
x_axis = G4Vector3D( 1.0, 0.0, 0.0 );
z_axis = G4Vector3D( 0.0, 0.0, 1.0 );
radius = 1.0;
phi_1 = 0.0;
phi_2 = 2*M_PI;
theta_1 = 0.0;
theta_2 = M_PI;
// OuterBoundary = new G4BREPPolyline();
}
*/
G4SphericalSurface::G4SphericalSurface( const G4Vector3D& o,
const G4Vector3D& xhat,
const G4Vector3D& zhat,
G4double r,
G4double ph1, G4double ph2,
G4double th1, G4double th2)
//: G4Surface( o )
{
// Normal constructor
G4double twopi = 2.0 * M_PI;
// Require both x_axis and z_axis to be unit vectors
G4double xhatmag = xhat.mag();
if ( xhatmag != 0.0 )
x_axis = xhat * (1/ xhatmag); // this makes the x_axis a unit vector
else
{
G4cerr << "Error in G4SphericalSurface::G4SphericalSurface--"
<<"x_axis has zero length\n"
<< "\tDefault x_axis of (1, 0, 0) is used.\n";
x_axis = G4Vector3D( 1.0, 0.0, 0.0 );
}
G4double zhatmag = zhat.mag();
if (zhatmag != 0.0)
z_axis = zhat *(1/ zhatmag); // this makes the z_axis a unit vector
else
{
G4cerr << "Error in G4SphericalSurface::G4SphericalSurface--"
<<"z_axis has zero length\n"
<< "\tDefault z_axis of (0, 0, 1) is used. \n";
z_axis = G4Vector3D( 0.0, 0.0, 1.0 );
}
// Require radius to be non-negative
if ( r >= 0.0 )
radius = r;
else
{
G4cerr << "Error in G4SphericalSurface::G4SphericalSurface"
<< "--radius cannot be less than zero.\n"
<< "\tDefault radius of 1.0 is used.\n";
radius = 1.0;
}
// Require phi_1 in the range: 0 <= phi_1 < 2*PI
// and phi_2 in the range: phi_1 < phi_2 <= phi_1 + 2*PI
if ( ( ph1 >= 0.0 ) && ( ph1 < 2*M_PI ) )
phi_1 = ph1;
else
{
G4cerr << "Error in G4SphericalSurface::G4SphericalSurface"
<< "--lower azimuthal limit is out of range\n"
<< "\tDefault angle of 0 is used.\n";
phi_1 = 0.0;
}
if ( ( ph2 > phi_1 ) && ( ph2 <= ( phi_1 + twopi ) ) )
phi_2 = ph2;
else
{
G4cerr << "Error in G4SphericalSurface::G4SphericalSurface"
<< "--upper azimuthal limit is out of range\n"
<< "\tDefault angle of 2*PI is used.\n";
phi_2 = twopi;
}
// Require theta_1 in the range: 0 <= theta_1 < PI
// and theta-2 in the range: theta_1 < theta_2 <= theta_1 + PI
if ( ( th1 >= 0.0 ) && ( th1 < M_PI ) )
theta_1 = th1;
else
{
G4cerr << "Error in G4SphericalSurface::G4SphericalSurface"
<< "--lower polar limit is out of range\n"
<< "\tDefault angle of 0 is used.\n";
theta_1 = 0.0;
}
if ( ( th2 > theta_1 ) && ( th2 <= ( theta_1 + M_PI ) ) )
theta_2 =th2;
else
{
G4cerr << "Error in G4SphericalSurface::G4SphericalSurface"
<< "--upper polar limit is out of range\n"
<< "\tDefault angle of PI is used.\n";
theta_2 = M_PI;
}
}
void G4SphericalSurface::PrintOn( ostream& os ) const
{
// printing function using C++ ostream class
os << "G4SphericalSurface surface with origin: " << origin << "\t"
<< "radius: " << radius << "\n"
<< "\t local x_axis: " << x_axis
<< "\t local z_axis: " << z_axis << "\n"
<< "\t lower azimuthal limit: " << phi_1 << " radians\n"
<< "\t upper azimuthal limit: " << phi_2 << " radians\n"
<< "\t lower polar limit : " << theta_1 << " radians\n"
<< "\t upper polar limit : " << theta_2 << " radians\n";
}
G4double G4SphericalSurface::HowNear( const G4Vector3D& x ) const
{
// Distance from the point x to the G4SphericalSurface.
// The distance will be positive if the point is Inside the
// G4SphericalSurface, negative if the point is outside.
G4Vector3D d = x - origin;
G4double rad = d.mag();
return (radius - rad);
}
/*
G4double G4SphericalSurface::distanceAlongRay( int which_way, const G4Ray* ry,
G4Vector3D& p ) const
{ // Distance along a Ray (straight line with G4Vector3D) to leave or enter
// a G4SphericalSurface. The input variable which_way should be set to +1 to
// indicate leaving a G4SphericalSurface, -1 to indicate entering a G4SphericalSurface.
// p is the point of intersection of the Ray with the G4SphericalSurface.
// If the G4Vector3D of the Ray is opposite to that of the Normal to
// the G4SphericalSurface at the intersection point, it will not leave the
// G4SphericalSurface.
// Similarly, if the G4Vector3D of the Ray is along that of the Normal
// to the G4SphericalSurface at the intersection point, it will not enter the
// G4SphericalSurface.
// This method is called by all finite shapes sub-classed to G4SphericalSurface.
// Use the virtual function table to check if the intersection point
// is within the boundary of the finite shape.
// A negative result means no intersection.
// If no valid intersection point is found, set the distance
// and intersection point to large numbers.
G4double Dist = FLT_MAXX;
G4Vector3D lv ( FLT_MAXX, FLT_MAXX, FLT_MAXX );
p = lv;
// Origin and G4Vector3D unit vector of Ray.
G4Vector3D x = ry->Position( 0.0 );
G4Vector3D dhat = ry->Direction( 0.0 );
int isoln = 0, maxsoln = 2;
// array of solutions in distance along the Ray
// G4double s[2] = { -1.0, -1.0 };
G4double s[2];s[0] = -1.0; s[1]= -1.0 ;
// calculate the two solutions (quadratic equation)
G4Vector3D d = x - GetOrigin();
G4double radius = GetRadius();
// quit with no intersection if the radius of the G4SphericalSurface is zero
if ( radius <= 0.0 )
return Dist;
G4double dsq = d * d;
G4double rsq = radius * radius;
G4double b = d * dhat;
G4double c = dsq - rsq;
G4double radical = b * b - c;
// quit with no intersection if the radical is negative
if ( radical < 0.0 )
return Dist;
G4double root = sqrt( radical );
s[0] = -b + root;
s[1] = -b - root;
// order the possible solutions by increasing distance along the Ray
// (G4Sorting routines are in support/G4Sort.h)
G4Sort_double( s, isoln, maxsoln-1 );
// now loop over each positive solution, keeping the first one (smallest
// distance along the Ray) which is within the boundary of the sub-shape
// and which also has the correct G4Vector3D with respect to the Normal to
// the G4SphericalSurface at the intersection point
for ( isoln = 0; isoln < maxsoln; isoln++ ) {
if ( s[isoln] >= 0.0 ) {
if ( s[isoln] >= FLT_MAXX ) // quit if too large
return Dist;
Dist = s[isoln];
p = ry->Position( Dist );
if ( ( ( dhat * Normal( p ) * which_way ) >= 0.0 )
&& ( WithinBoundary( p ) == 1 ) )
return Dist;
}
}
// get here only if there was no solution within the boundary, Reset
// distance and intersection point to large numbers
p = lv;
return FLT_MAXX;
}
*/
void G4SphericalSurface::CalcBBox()
{
G4double x_min = origin.x() - radius;
G4double y_min = origin.y() - radius;
G4double z_min = origin.z() - radius;
G4double x_max = origin.x() + radius;
G4double y_max = origin.y() + radius;
G4double z_max = origin.z() + radius;
G4Point3D Min(x_min, y_min, z_min);
G4Point3D Max(x_max, y_max, z_max);
bbox = new G4BoundingBox3D( Min, Max);
}
int G4SphericalSurface::Intersect( const G4Ray& ry )
{
// Distance along a Ray (straight line with G4Vector3D) to leave or enter
// a G4SphericalSurface. The input variable which_way should be set to +1
// to indicate leaving a G4SphericalSurface, -1 to indicate entering a
// G4SphericalSurface.
// p is the point of intersection of the Ray with the G4SphericalSurface.
// If the G4Vector3D of the Ray is opposite to that of the Normal to
// the G4SphericalSurface at the intersection point, it will not leave the
// G4SphericalSurface.
// Similarly, if the G4Vector3D of the Ray is along that of the Normal
// to the G4SphericalSurface at the intersection point, it will not enter
// the G4SphericalSurface.
// This method is called by all finite shapes sub-classed to
// G4SphericalSurface.
// Use the virtual function table to check if the intersection point
// is within the boundary of the finite shape.
// A negative result means no intersection.
// If no valid intersection point is found, set the distance
// and intersection point to large numbers.
int which_way = (int)HowNear(ry.GetStart());
//Originally a parameter.Read explanation above.
if(!which_way)which_way =-1;
distance = FLT_MAXX;
G4Vector3D lv ( FLT_MAXX, FLT_MAXX, FLT_MAXX );
// p = lv;
closest_hit = lv;
// Origin and G4Vector3D unit vector of Ray.
// G4Vector3D x = ry->position( 0.0 );
G4Vector3D x=ry.GetStart();
// G4Vector3D dhat = ry->direction( 0.0 );
G4Vector3D dhat = ry.GetDir();
int isoln = 0, maxsoln = 2;
// array of solutions in distance along the Ray
G4double s[2];
s[0] = -1.0 ;
s[1] = -1.0 ;
// calculate the two solutions (quadratic equation)
G4Vector3D d = x - GetOrigin();
G4double r = GetRadius();
// quit with no intersection if the radius of the G4SphericalSurface is zero
if ( r <= 0.0 )
return 0;
G4double dsq = d * d;
G4double rsq = r * r;
G4double b = d * dhat;
G4double c = dsq - rsq;
G4double radical = b * b - c;
// quit with no intersection if the radical is negative
if ( radical < 0.0 )
return 0;
G4double root = sqrt( radical );
s[0] = -b + root;
s[1] = -b - root;
// order the possible solutions by increasing distance along the Ray
// (G4Sorting routines are in support/G4Sort.h)
// G4Sort_double( s, isoln, maxsoln-1 );
if(s[0] > s[1])
{
G4double tmp =s[0];
s[0] = s[1];
s[1] = tmp;
}
// now loop over each positive solution, keeping the first one (smallest
// distance along the Ray) which is within the boundary of the sub-shape
// and which also has the correct G4Vector3D with respect to the Normal to
// the G4SphericalSurface at the intersection point
for ( isoln = 0; isoln < maxsoln; isoln++ )
{
if ( s[isoln] >= kCarTolerance*0.5 )
{
if ( s[isoln] >= FLT_MAXX ) // quit if too large
return 0;
distance = s[isoln];
closest_hit = ry.GetPoint( distance );
if ( ( ( dhat * Normal( closest_hit ) * which_way ) >= 0.0 ) &&
( WithinBoundary( closest_hit ) == 1 ) )
{
distance = distance*distance;
return 1;
}
}
}
// get here only if there was no solution within the boundary, Reset
// distance and intersection point to large numbers
// p = lv;
// return FLT_MAXX;
distance = FLT_MAXX;
closest_hit = lv;
return 0;
}
/*
G4double G4SphericalSurface::distanceAlongHelix( int which_way, const Helix* hx,
G4Vector3D& p ) const
{ // Distance along a Helix to leave or enter a G4SphericalSurface.
// The input variable which_way should be set to +1 to
// indicate leaving a G4SphericalSurface, -1 to indicate entering a G4SphericalSurface.
// p is the point of intersection of the Helix with the G4SphericalSurface.
// If the G4Vector3D of the Helix is opposite to that of the Normal to
// the G4SphericalSurface at the intersection point, it will not leave the
// G4SphericalSurface.
// Similarly, if the G4Vector3D of the Helix is along that of the Normal
// to the G4SphericalSurface at the intersection point, it will not enter the
// G4SphericalSurface.
// This method is called by all finite shapes sub-classed to G4SphericalSurface.
// Use the virtual function table to check if the intersection point
// is within the boundary of the finite shape.
// If no valid intersection point is found, set the distance
// and intersection point to large numbers.
// Possible negative distance solutions are discarded.
G4double Dist = FLT_MAXX;
G4Vector3D lv ( FLT_MAXX, FLT_MAXX, FLT_MAXX );
p = lv;
int isoln = 0, maxsoln = 4;
// Array of solutions in turning angle
// G4double s[4] = { -1.0, -1.0, -1.0, -1.0 };
G4double s[4];s[0] = -1.0; s[1]= -1.0 ;s[2] = -1.0; s[3]= -1.0 ;
// Helix parameters
G4double rh = hx->GetRadius(); // radius of Helix
G4Vector3D oh = hx->position( 0.0 ); // origin of Helix
G4Vector3D dh = hx->direction( 0.0 ); // initial G4Vector3D of Helix
G4Vector3D prp = hx->getPerp(); // perpendicular vector
G4double prpmag = prp.mag();
G4double rhp = rh / prpmag;
// G4SphericalSurface parameters
G4double rs = GetRadius(); // radius of G4SphericalSurface
if ( rs == 0.0 ) // quit if zero radius
return Dist;
G4Vector3D os = GetOrigin(); // origin of G4SphericalSurface
//
// Calculate quantities of use later on
G4Vector3D alpha = rhp * prp;
G4Vector3D beta = rhp * dh;
G4Vector3D gamma = oh - os;
//
// Only consider approximate solutions to quadratic order in the turning
// angle along the Helix
G4double A = beta * beta + gamma * alpha;
G4double B = 2.0 * gamma * beta;
G4double C = gamma * gamma - rs * rs;
// Case if quadratic term is zero
if ( fabs( A ) < FLT_EPSILO ) {
if ( B == 0.0 ) // no intersection, quit
return Dist;
else // B != 0
s[0] = -C / B;
}
// General quadratic solution, A != 0
else {
G4double radical = B * B - 4.0 * A * C;
if ( radical < 0.0 ) // no intersection, quit
return Dist;
G4double root = sqrt( radical );
s[0] = ( -B + root ) / ( 2.0 * A );
s[1] = ( -B - root ) / ( 2.0 * A );
if ( rh < 0.0 ) {
s[0] = -s[0];
s[1] = -s[1];
}
s[2] = s[0] + 2.0 * M_PI;
s[3] = s[1] + 2.0 * M_PI;
}
//
// Order the possible solutions by increasing turning angle
// (G4Sorting routines are in support/G4Sort.h).
G4Sort_double( s, isoln, maxsoln-1 );
//
// Now loop over each positive solution, keeping the first one (smallest
// distance along the Helix) which is within the boundary of the sub-shape.
for ( isoln = 0; isoln < maxsoln; isoln++ ) {
if ( s[isoln] >= 0.0 ) {
// Calculate distance along Helix and position and G4Vector3D vectors.
Dist = s[isoln] * fabs( rhp );
p = hx->position( Dist );
G4Vector3D d = hx->direction( Dist );
// Now do approximation to get remaining distance to correct this solution
// iterate it until the accuracy is below the user-set surface precision.
G4double delta = 0.;
G4double delta0 = FLT_MAXX;
int dummy = 1;
int iter = 0;
int in0 = Inside( hx->position ( 0.0 ) );
int in1 = Inside( p );
G4double sc = Scale();
while ( dummy ) {
iter++;
// Terminate loop after 50 iterations and Reset distance to large number,
// indicating no intersection with G4SphericalSurface.
// This generally occurs if the Helix curls too tightly to Intersect it.
if ( iter > 50 ) {
Dist = FLT_MAXX;
p = lv;
break;
}
// Find distance from the current point along the above-calculated
// G4Vector3D using a Ray.
// The G4Vector3D of the Ray and the Sign of the distance are determined
// by whether the starting point of the Helix is Inside or outside of
// the G4SphericalSurface.
in1 = Inside( p );
if ( in1 ) { // current point Inside
if ( in0 ) { // starting point Inside
Ray* r = new Ray( p, d );
delta =
distanceAlongRay( 1, r, p );
delete r;
}
else { // starting point outside
Ray* r = new Ray( p, -d );
delta =
-distanceAlongRay( 1, r, p );
delete r;
}
}
else { // current point outside
if ( in0 ) { // starting point Inside
Ray* r = new Ray( p, -d );
delta =
-distanceAlongRay( -1, r, p );
delete r;
}
else { // starting point outside
Ray* r = new Ray( p, d );
delta =
distanceAlongRay( -1, r, p );
delete r;
}
}
// Test if distance is less than the surface precision, if so Terminate loop.
if ( fabs( delta / sc ) <= SURFACE_PRECISION )
break;
// Ff delta has not changed sufficiently from the previous iteration,
// skip out of this loop.
if ( fabs( ( delta - delta0 ) / sc ) <=
SURFACE_PRECISION )
break;
// If delta has increased in absolute value from the previous iteration
// either the Helix doesn't Intersect the G4SphericalSurface or the approximate
// solution is too far from the real solution. Try groping for a solution.
// If not found, Reset distance to large number, indicating no intersection
// with the G4SphericalSurface.
if ( ( fabs( delta ) > fabs( delta0 ) ) ) {
Dist = fabs( rhp ) *
gropeAlongHelix( hx );
if ( Dist < 0.0 ) {
Dist = FLT_MAXX;
p = lv;
}
else
p = hx->position( Dist );
break;
}
// Set old delta to new one.
delta0 = delta;
// Add distance to G4SphericalSurface to distance along Helix.
Dist += delta;
// Negative distance along Helix means Helix doesn't Intersect G4SphericalSurface.
// Reset distance to large number, indicating no intersection with G4SphericalSurface.
if ( Dist < 0.0 ) {
Dist = FLT_MAXX;
p = lv;
break;
}
// Recalculate point along Helix and the G4Vector3D.
p = hx->position( Dist );
d = hx->direction( Dist );
} // end of while loop
// Now have best value of distance along Helix and position for this
// solution, so test if it is within the boundary of the sub-shape
// and require that it point in the correct G4Vector3D with respect to
// the Normal to the G4SphericalSurface.
if ( ( Dist < FLT_MAXX ) &&
( ( hx->direction( Dist ) * Normal( p ) *
which_way ) >= 0.0 ) &&
( WithinBoundary( p ) == 1 ) )
return Dist;
} // end of if s[isoln] >= 0.0 condition
} // end of for loop over solutions
// If one gets here, there is no solution, so set distance along Helix
// and position to large numbers.
Dist = FLT_MAXX;
p = lv;
return Dist;
}
*/
/*
G4Vector3D G4SphericalSurface::Normal( const G4Vector3D& p ) const
{ // Return the Normal unit vector to the G4SphericalSurface at a point p on
// (or nearly on) the G4SphericalSurface.
G4Vector3D n = p - origin;
G4double nmag = n.mag();
if ( nmag != 0.0 )
n = n / nmag;
// If the point p happens to coincide with the origin (which is possible
// if the radius is zero), set the Normal to the z-axis unit vector.
else
n = G4Vector3D( 0.0, 0.0, 1.0 );
return n;
}
*/
G4Vector3D G4SphericalSurface::Normal( const G4Vector3D& p ) const
{
// Return the Normal unit vector to the G4SphericalSurface at a point p on
// (or nearly on) the G4SphericalSurface.
G4Vector3D n = p - origin;
G4double nmag = n.mag();
if ( nmag != 0.0 )
n = n * (1/ nmag);
// If the point p happens to coincide with the origin (which is possible
// if the radius is zero), set the Normal to the z-axis unit vector.
else
n = G4Vector3D( 0.0, 0.0, 1.0 );
return n;
}
G4Vector3D G4SphericalSurface::SurfaceNormal( const G4Point3D& p ) const
{
// Return the Normal unit vector to the G4SphericalSurface at a point p on
// (or nearly on) the G4SphericalSurface.
G4Vector3D n = p - origin;
G4double nmag = n.mag();
if ( nmag != 0.0 )
n = n * (1/ nmag);
// If the point p happens to coincide with the origin (which is possible
// if the radius is zero), set the Normal to the z-axis unit vector.
else
n = G4Vector3D( 0.0, 0.0, 1.0 );
return n;
}
int G4SphericalSurface::Inside ( const G4Vector3D& x ) const
{
// Return 0 if point x is outside G4SphericalSurface, 1 if Inside.
// Outside means that the distance to the G4SphericalSurface would
// be negative.
// Use the HowNear function to calculate this distance.
if ( HowNear( x ) >= 0.0 )
return 1;
else
return 0;
}
int G4SphericalSurface::WithinBoundary( const G4Vector3D& x ) const
{
// return 1 if point x is on the G4SphericalSurface, otherwise return zero
// (x is assumed to lie on the surface of the G4SphericalSurface, so one
// only checks the angular limits)
G4Vector3D y_axis = z_axis.cross( x_axis );
// components of x in the local coordinate system of the G4SphericalSurface
G4double px = x * x_axis;
G4double py = x * y_axis;
G4double pz = x * z_axis;
// check if within polar angle limits
G4double theta = acos( pz / x.mag() ); // acos in range 0 to PI
// Normal case
if ( theta_2 <= M_PI )
{
if ( ( theta < theta_1 ) || ( theta > theta_2 ) )
return 0;
}
// this is for the case that theta_2 is greater than PI
else
{
theta += M_PI;
if ( ( theta < theta_1 ) || ( theta > theta_2 ) )
return 0;
}
// now check if within azimuthal angle limits
G4double phi = atan2( py, px ); // atan2 in range -PI to PI
G4double twopi = 2.0 * M_PI;
if ( phi < 0.0 )
phi += twopi;
// Normal case
if ( ( phi >= phi_1 ) && ( phi <= phi_2 ) )
return 1;
// this is for the case that phi_2 is greater than 2*PI
phi += twopi;
if ( ( phi >= phi_1 ) && ( phi <= phi_2 ) )
return 1;
// get here if not within azimuthal limits
return 0;
}
G4double G4SphericalSurface::Scale() const
{
// Returns the radius of a G4SphericalSurface unless it is zero, in which
// case returns the arbitrary number 1.0.
// Used for Scale-invariant tests of surface thickness.
if ( radius == 0.0 )
return 1.0;
else
return radius;
}
G4double G4SphericalSurface::Area() const
{
// Returns the Area of a G4SphericalSurface
return ( 2.0*( theta_2 - theta_1 )*( phi_2 - phi_1)*radius*radius/M_PI );
}
void G4SphericalSurface::resize( G4double r,
G4double ph1, G4double ph2,
G4double th1, G4double th2 )
{
// Resize the G4SphericalSurface to new radius r, new lower and upper
// azimuthal angle limits ph1 and ph2, and new lower and upper polar
// angle limits th1 and th2.
// Require radius to be non-negative
if ( r >= 0.0 )
radius = r;
else
{
G4cerr << "Error in G4SphericalSurface::resize"
<< "--radius cannot be less than zero.\n"
<< "\tOriginal value of " << radius << " is retained.\n";
}
// Require azimuthal angles to be within bounds
G4double twopi = 2.0 * M_PI;
if ( ( ph1 >= 0.0 ) && ( ph1 < twopi ) )
phi_1 = ph1;
else
{
G4cerr << "Error in G4SphericalSurface::resize"
<< "--lower azimuthal limit out of range\n"
<< "\tOriginal value of " << phi_1 << " is retained.\n";
}
if ( ( ph2 > phi_1 ) && ( ph2 <= ( phi_1 + twopi ) ) )
phi_2 = ph2;
else
{
ph2 = ( phi_2 <= phi_1 ) ? ( phi_1 + FLT_EPSILO ) : phi_2;
phi_2 = ph2;
G4cerr << "Error in G4SphericalSurface::resize"
<< "--upper azimuthal limit out of range\n"
<< "\tValue of " << phi_2 << " is used.\n";
}
// Require polar angles to be within bounds
if ( ( th1 >= 0.0 ) && ( th1 < M_PI ) )
theta_1 = th1;
else
{
G4cerr << "Error in G4SphericalSurface::resize"
<< "--lower polar limit out of range\n"
<< "\tOriginal value of " << theta_1 << " is retained.\n";
}
if ( ( th2 > theta_1 ) && ( th2 <= ( theta_1 + M_PI ) ) )
theta_2 = th2;
else
{
th2 = ( theta_2 <= theta_1 ) ? ( theta_1 + FLT_EPSILO ) : theta_2;
theta_2 = th2;
G4cerr << "Error in G4SphericalSurface::resize"
<< "--upper polar limit out of range\n"
<< "\tValue of " << theta_2 << " is used.\n";
}
}
/*
void G4SphericalSurface::rotate( G4double alpha, G4double beta,
G4double gamma, G4ThreeMat& m, int inverse )
{ // rotate G4SphericalSurface first about global x_axis by angle alpha,
// second about global y-axis by angle beta,
// and third about global z_axis by angle gamma
// by creating and using G4ThreeMat objects in Surface::rotate
// angles are assumed to be given in radians
// if inverse is non-zero, the order of rotations is reversed
// the axis is rotated here, the origin is rotated by calling
// Surface::rotate
G4Surface::rotate( alpha, beta, gamma, m, inverse );
x_axis = m * x_axis;
z_axis = m * z_axis;
}
*/
/*
void G4SphericalSurface::rotate( G4double alpha, G4double beta,
G4double gamma, int inverse )
{ // rotate G4SphericalSurface first about global x_axis by angle alpha,
// second about global y-axis by angle beta,
// and third about global z_axis by angle gamma
// by creating and using G4ThreeMat objects in Surface::rotate
// angles are assumed to be given in radians
// if inverse is non-zero, the order of rotations is reversed
// the axis is rotated here, the origin is rotated by calling
// Surface::rotate
G4ThreeMat m;
G4Surface::rotate( alpha, beta, gamma, m, inverse );
x_axis = m * x_axis;
z_axis = m * z_axis;
}
*/
/*
G4double G4SphericalSurface::gropeAlongHelix( const Helix* hx ) const
{ // Grope for a solution of a Helix intersecting a G4SphericalSurface.
// This function returns the turning angle (in radians) where the
// intersection occurs with only positive values allowed, or -1.0 if
// no intersection is found.
// The idea is to start at the beginning of the Helix, then take steps
// of some fraction of a turn. If at the end of a Step, the current position
// along the Helix and the previous position are on opposite sides of the
// G4SphericalSurface, then the solution must lie somewhere in between.
int one_over_f = 8; // one over fraction of a turn to go in each Step
G4double turn_angle = 0.0;
G4double dist_along = 0.0;
G4double d_new;
G4double fk = 1.0 / G4double( one_over_f );
G4double scal = Scale();
G4double d_old = HowNear( hx->position( dist_along ) );
G4double rh = hx->GetRadius(); // radius of Helix
G4Vector3D prp = hx->getPerp(); // perpendicular vector
G4double prpmag = prp.mag();
G4double rhp = rh / prpmag;
int max_iter = one_over_f * HELIX_MAX_TURNS;
// Take up to a user-settable number of turns along the Helix,
// groping for an intersection point.
for ( int k = 1; k < max_iter; k++ ) {
turn_angle = 2.0 * M_PI * k / one_over_f;
dist_along = turn_angle * fabs( rhp );
d_new = HowNear( hx->position( dist_along ) );
if ( ( d_old < 0.0 && d_new > 0.0 ) ||
( d_old > 0.0 && d_new < 0.0 ) ) {
d_old = d_new;
// Old and new points are on opposite sides of the G4SphericalSurface, therefore
// a solution lies in between, use a binary search to pin the point down
// to the surface precision, but don't do more than 50 iterations.
int itr = 0;
while ( fabs( d_new / scal ) > SURFACE_PRECISION ) {
itr++;
if ( itr > 50 )
return turn_angle;
turn_angle -= fk * M_PI;
dist_along = turn_angle * fabs( rhp );
d_new = HowNear( hx->position( dist_along ) );
if ( ( d_old < 0.0 && d_new > 0.0 ) ||
( d_old > 0.0 && d_new < 0.0 ) )
fk *= -0.5;
else
fk *= 0.5;
d_old = d_new;
} // end of while loop
return turn_angle; // this is the best solution
} // end of if condition
} // end of for loop
// Get here only if no solution is found, so return -1.0 to indicate that.
return -1.0;
}
*/