// // ******************************************************************** // * 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: G4FCylindricalSurface.cc,v 1.16 2006/06/29 18:42:14 gunter Exp $ // GEANT4 tag $Name: geant4-09-03 $ // // ---------------------------------------------------------------------- // GEANT 4 class source file // // G4FCylindricalSurface.cc // // ---------------------------------------------------------------------- #include "G4FCylindricalSurface.hh" #include "G4Sort.hh" G4FCylindricalSurface::G4FCylindricalSurface() : length(1.) { } G4FCylindricalSurface::~G4FCylindricalSurface() { } G4FCylindricalSurface::G4FCylindricalSurface( const G4Point3D& o, const G4Vector3D& a, G4double r, G4double l ) { // make a G4FCylindricalSurface with origin o, axis a, // radius r, and length l G4Vector3D dir(1,1,1); Position.Init(dir, a, o); origin = o; radius = r; // Require length to be positive or zero if ( l >= 0.0 ) length = l; else { G4cerr << "Error in G4FCylindricalSurface::G4FCylindricalSurface" << "--asked for negative length\n" << "\tDefault length of 0.0 is used.\n"; length = 0.0; } // Require radius to be non-negative (i.e., allow zero) if ( r >= 0.0 ) radius = r; else { G4cerr << "Error in G4FCylindricalSurface::G4FCylindricalSurface" << "--asked for negative radius\n" << "\tDefault value of 0.0 is used.\n"; radius = 0.0; } } const char* G4FCylindricalSurface::NameOf() const { return "G4FCylindricalSurface"; } void G4FCylindricalSurface::PrintOn( std::ostream& os ) const { os << "G4FCylindricalSurface with origin: " << origin << "\t" << "and axis: " << Position.GetAxis() << "\n" << "\t radius: " << radius << "\t and length: " << length << "\n"; } G4double G4FCylindricalSurface::Area() const { return ( 2.0 * pi * radius * length ); } // Added 18.7-95 // Modified by L. Broglia (01/12/98) void G4FCylindricalSurface::CalcBBox() { // Finds the bounds of the surface iow // calculates the bounds for a bounding box // to the surface. The bounding box is used // for a preliminary check of intersection. G4Point3D Max = G4Point3D(-PINFINITY); G4Point3D Min = G4Point3D( PINFINITY); G4Point3D Tmp; G4Point3D Origin = Position.GetLocation(); G4Point3D EndOrigin = G4Point3D( Origin + (length*Position.GetAxis()) ); G4Point3D Radius(radius, radius, 0); // Default BBox G4Point3D Tolerance(kCarTolerance, kCarTolerance, kCarTolerance); G4Point3D BoxMin(Origin-Tolerance); G4Point3D BoxMax(Origin+Tolerance); bbox = new G4BoundingBox3D(); bbox->Init(BoxMin, BoxMax); Tmp = (Origin - Radius); bbox->Extend(Tmp); Tmp = Origin + Radius; bbox->Extend(Tmp); Tmp = EndOrigin - Radius; bbox->Extend(Tmp); Tmp = EndOrigin + Radius; bbox->Extend(Tmp); } G4int G4FCylindricalSurface::Intersect( const G4Ray& ry ) { // This function count the number of intersections of a // bounded cylindrical surface by a ray. // At first, calculates the intersections with the infinite // cylindrical surfsace. After, count the intersections within the // finite cylindrical surface boundaries, and set "distance" to the // closest distance from the start point to the nearest intersection // If the point is on the surface it returns or the intersection with // the opposite surface or kInfinity // If no intersection is founded, set distance = kInfinity and // return 0 distance = kInfinity; closest_hit = PINFINITY; // origin and direction of the ray G4Point3D x = ry.GetStart(); G4Vector3D dhat = ry.GetDir(); // cylinder axis G4Vector3D ahat = Position.GetAxis(); // array of solutions in distance along the ray G4double s[2]; s[0]=-1.0; s[1]=-1.0; // calculate the two intersections (quadratic equation) G4Vector3D gamma = G4Vector3D( x - Position.GetLocation() ); G4double ga = gamma * ahat; G4double da = dhat * ahat; G4double A = da * da - dhat * dhat; G4double B = 2 * ( -gamma * dhat + ga * da ); G4double C = -gamma * gamma + ga * ga + radius * radius ; G4double radical = B * B - 4.0 * A * C; if ( radical < 0.0 ) // no intersection return 0; else { G4double root = std::sqrt( radical ); s[0] = ( - B + root ) / ( 2. * A ); s[1] = ( - B - root ) / ( 2. * A ); } // validity of the solutions // the hit point must be into the bounding box of the cylindrical surface G4Point3D p0 = G4Point3D( x + s[0]*dhat ); G4Point3D p1 = G4Point3D( x + s[1]*dhat ); if( !GetBBox()->Inside(p0) ) s[0] = kInfinity; if( !GetBBox()->Inside(p1) ) s[1] = kInfinity; // now loop over each positive solution, keeping the first one (smallest // distance along the Ray) which is within the boundary of the sub-shape G4int nbinter = 0; distance = kInfinity; for ( G4int i = 0; i < 2; i++ ) { if(s[i] < kInfinity) { if ( s[i] >= kCarTolerance*0.5 ) { nbinter ++; // real intersection // set the distance if it is the smallest if( distance > s[i]*s[i]) { distance = s[i]*s[i]; } } } } return nbinter; } G4double G4FCylindricalSurface::HowNear( const G4Vector3D& x ) const { // Shortest distance from the point x to the G4FCylindricalSurface. // The distance will be always positive G4double hownear; G4Vector3D upcorner = G4Vector3D ( radius, 0 , origin.z()+length); G4Vector3D downcorner = G4Vector3D ( radius, 0 , origin.z()); G4Vector3D xd; xd = G4Vector3D ( std::sqrt ( x.x()*x.x() + x.y()*x.y() ) , 0 , x.z() ); G4double Zinter = (xd.z()) ; if ( ((Zinter >= downcorner.z()) && (Zinter <=upcorner.z())) ) { hownear = std::fabs( radius - xd.x() ); } else { hownear = std::min ( (xd-upcorner).mag() , (xd-downcorner).mag() ); } return hownear; } G4int G4FCylindricalSurface::WithinBoundary( const G4Vector3D& x ) const { // return 1 if point x is within the boundaries of the G4FCylindricalSurface // return 0 otherwise (assume it is on the cylinder) if ( std::fabs( ( x - Position.GetLocation()) * Position.GetAxis() ) <= 0.5 * length ) return 1; else return 0; } G4double G4FCylindricalSurface::Scale() const { // Returns the radius of a G4FCylindricalSurface unless it is zero, // in which case returns the length. // Used for Scale-invariant tests of surface thickness. if ( radius == 0.0 ) return length; else return radius; } G4Vector3D G4FCylindricalSurface::SurfaceNormal( const G4Point3D& p ) const { // return the Normal unit vector to the G4CylindricalSurface at a point // p on (or nearly on) the G4CylindricalSurface G4Vector3D n = G4Vector3D( ( p - Position.GetLocation() ) - ( ( p - Position.GetLocation()) * Position.GetAxis() ) * Position.GetAxis() ); G4double nmag = n.mag(); if ( nmag != 0.0 ) n = n * (1/nmag); if( !sameSense ) n = -n; return n; } G4int G4FCylindricalSurface::Inside ( const G4Vector3D& x ) const { // Return 0 if point x is outside G4CylindricalSurface, 1 if Inside. // Outside means that the distance to the G4CylindricalSurface would // be negative. // Use the HowNear function to calculate this distance. if ( HowNear( x ) >= -0.5*kCarTolerance ) return 1; else return 0; } void G4FCylindricalSurface::resize( G4double r, G4double l ) { // Resize a G4FCylindricalSurface to a new radius r and new length l // Require radius to be non-negative if ( r >= 0.0 ) radius = r; else { G4cerr << "Error in G4FCylindricalSurface::resize" << "--asked for negative radius\n" << "\tOriginal value of " << radius << " is retained.\n"; } // Require length to be positive if ( l > 0.0 ) length = l; else { G4cerr << "Error in G4FCylindricalSurface::resize" << "--asked for negative or zero length\n" << "\tOriginal value of " << length << " is retained.\n"; } }