G4SphericalSurface.cc

Go to the documentation of this file.
00001 //
00002 // ********************************************************************
00003 // * License and Disclaimer                                           *
00004 // *                                                                  *
00005 // * The  Geant4 software  is  copyright of the Copyright Holders  of *
00006 // * the Geant4 Collaboration.  It is provided  under  the terms  and *
00007 // * conditions of the Geant4 Software License,  included in the file *
00008 // * LICENSE and available at  http://cern.ch/geant4/license .  These *
00009 // * include a list of copyright holders.                             *
00010 // *                                                                  *
00011 // * Neither the authors of this software system, nor their employing *
00012 // * institutes,nor the agencies providing financial support for this *
00013 // * work  make  any representation or  warranty, express or implied, *
00014 // * regarding  this  software system or assume any liability for its *
00015 // * use.  Please see the license in the file  LICENSE  and URL above *
00016 // * for the full disclaimer and the limitation of liability.         *
00017 // *                                                                  *
00018 // * This  code  implementation is the result of  the  scientific and *
00019 // * technical work of the GEANT4 collaboration.                      *
00020 // * By using,  copying,  modifying or  distributing the software (or *
00021 // * any work based  on the software)  you  agree  to acknowledge its *
00022 // * use  in  resulting  scientific  publications,  and indicate your *
00023 // * acceptance of all terms of the Geant4 Software license.          *
00024 // ********************************************************************
00025 //
00026 //
00027 // $Id$
00028 //
00029 // ----------------------------------------------------------------------
00030 // GEANT 4 class source file
00031 //
00032 // G4SphericalSurface.cc
00033 //
00034 // ----------------------------------------------------------------------
00035 
00036 #include "G4SphericalSurface.hh"
00037 #include "G4PhysicalConstants.hh"
00038 
00039 G4SphericalSurface::G4SphericalSurface()
00040   : G4Surface(), radius(1.0), phi_1(0.0), phi_2(2*pi),
00041     theta_1(0.0), theta_2(pi)
00042 {
00043    // default constructor
00044    // default x_axis is ( 1.0, 0.0, 0.0 ), z_axis is ( 0.0, 0.0, 1.0 ),
00045    // default radius is 1.0
00046    // default phi_1 is 0, phi_2 is 2*PI
00047    // default theta_1 is 0, theta_2 is PI
00048 
00049    x_axis = G4Vector3D( 1.0, 0.0, 0.0 );
00050    z_axis = G4Vector3D( 0.0, 0.0, 1.0 );
00051    //   OuterBoundary = new G4BREPPolyline();
00052 }
00053 
00054 
00055 G4SphericalSurface::G4SphericalSurface( const G4Vector3D&, 
00056                                         const G4Vector3D& xhat,
00057                                         const G4Vector3D& zhat,
00058                                         G4double r, 
00059                                         G4double ph1, G4double ph2, 
00060                                         G4double th1, G4double th2) 
00061   : G4Surface()
00062 { 
00063   // Require both x_axis and z_axis to be unit vectors
00064 
00065   G4double xhatmag = xhat.mag();
00066   if ( xhatmag != 0.0 )
00067   {
00068     x_axis = xhat * (1/ xhatmag); // this makes the x_axis a unit vector
00069   }
00070   else
00071   {
00072     std::ostringstream message;
00073     message << "x_axis has zero length." << G4endl
00074             << "Default x_axis of (1, 0, 0) is used.";    
00075     G4Exception("G4SphericalSurface::G4SphericalSurface()",
00076                 "GeomSolids1001", JustWarning, message);
00077 
00078     x_axis = G4Vector3D( 1.0, 0.0, 0.0 );
00079   }
00080 
00081   G4double zhatmag = zhat.mag();
00082   
00083   if (zhatmag != 0.0)
00084   {
00085     z_axis = zhat *(1/ zhatmag);  // this makes the z_axis a unit vector
00086   }
00087   else 
00088   {
00089     std::ostringstream message;
00090     message << "z_axis has zero length." << G4endl
00091             << "Default z_axis of (0, 0, 1) is used.";    
00092     G4Exception("G4SphericalSurface::G4SphericalSurface()",
00093                 "GeomSolids1001", JustWarning, message);
00094 
00095     z_axis = G4Vector3D( 0.0, 0.0, 1.0 );
00096   }
00097   
00098   //  Require radius to be non-negative
00099   //
00100   if ( r >= 0.0 )
00101   {
00102     radius = r;
00103   }
00104   else 
00105   {
00106     std::ostringstream message;
00107     message << "Radius cannot be less than zero." << G4endl
00108             << "Default radius of 1.0 is used.";    
00109     G4Exception("G4SphericalSurface::G4SphericalSurface()",
00110                 "GeomSolids1001", JustWarning, message);
00111 
00112     radius = 1.0;
00113   }
00114 
00115   //  Require phi_1 in the range: 0 <= phi_1 < 2*PI
00116   //  and phi_2 in the range: phi_1 < phi_2 <= phi_1 + 2*PI
00117   //
00118   if ( ( ph1 >= 0.0 ) && ( ph1 < 2*pi ) )
00119   {
00120     phi_1 = ph1;
00121   }
00122   else 
00123   {
00124     std::ostringstream message;
00125     message << "Lower azimuthal limit is out of range." << G4endl
00126             << "Default angle of 0 is used.";    
00127     G4Exception("G4SphericalSurface::G4SphericalSurface()",
00128                 "GeomSolids1001", JustWarning, message);
00129 
00130     phi_1 = 0.0;
00131   }
00132 
00133   if ( ( ph2 > phi_1 ) && ( ph2 <=  ( phi_1 + twopi ) ) )
00134   {
00135     phi_2 = ph2;
00136   }
00137   else 
00138   {
00139     std::ostringstream message;
00140     message << "Upper azimuthal limit is out of range." << G4endl
00141             << "Default angle of 2*PI is used.";    
00142     G4Exception("G4SphericalSurface::G4SphericalSurface()",
00143                 "GeomSolids1001", JustWarning, message);
00144 
00145     phi_2 = twopi;
00146   }
00147  
00148   //  Require theta_1 in the range: 0 <= theta_1 < PI 
00149   //  and theta-2 in the range: theta_1 < theta_2 <= theta_1 + PI
00150   //
00151   if ( ( th1 >= 0.0 ) && ( th1 < pi ) )
00152   {
00153     theta_1 = th1;
00154   }
00155   else
00156   {
00157     std::ostringstream message;
00158     message << "Lower polar limit is out of range." << G4endl
00159             << "Default angle of 0 is used.";    
00160     G4Exception("G4SphericalSurface::G4SphericalSurface()",
00161                 "GeomSolids1001", JustWarning, message);
00162 
00163     theta_1 = 0.0;
00164   }  
00165   
00166   if  ( ( th2 > theta_1 ) && ( th2 <= ( theta_1 + pi ) ) )
00167   {
00168     theta_2 =th2;
00169   }
00170   else 
00171   {
00172     std::ostringstream message;
00173     message << "Upper polar limit is out of range." << G4endl
00174             << "Default angle of PI is used.";    
00175     G4Exception("G4SphericalSurface::G4SphericalSurface()",
00176                 "GeomSolids1001", JustWarning, message);
00177 
00178     theta_2 = pi;
00179   } 
00180 }
00181 
00182 
00183 G4SphericalSurface::~G4SphericalSurface()
00184 {
00185 }
00186 
00187 
00188 G4SphericalSurface::G4SphericalSurface( const G4SphericalSurface& surf )
00189   : G4Surface()
00190 {
00191   x_axis = surf.x_axis;
00192   z_axis = surf.z_axis;
00193   radius = surf.radius;
00194   phi_1 = surf.phi_1;
00195   phi_2 = surf.phi_2;
00196   theta_1 = surf.theta_1;
00197   theta_2 = surf.theta_2;
00198 }                               
00199 
00200 G4SphericalSurface&
00201 G4SphericalSurface::operator=( const G4SphericalSurface& surf )
00202 {
00203   if (&surf == this)  { return *this; }
00204   x_axis = surf.x_axis;
00205   z_axis = surf.z_axis;
00206   radius = surf.radius;
00207   phi_1 = surf.phi_1;
00208   phi_2 = surf.phi_2;
00209   theta_1 = surf.theta_1;
00210   theta_2 = surf.theta_2;
00211 
00212   return *this;
00213 }
00214 
00215 const char* G4SphericalSurface::NameOf() const
00216 {
00217   return "G4SphericalSurface";
00218 }
00219 
00220 void G4SphericalSurface::PrintOn( std::ostream& os ) const
00221 {  
00222   os << "G4SphericalSurface surface with origin: " << origin << "\t"
00223      << "radius: " << radius << "\n"
00224      << "\t local x_axis: " << x_axis
00225      << "\t local z_axis: " << z_axis << "\n" 
00226      << "\t lower azimuthal limit: " << phi_1 << " radians\n"
00227      << "\t upper azimuthal limit: " << phi_2 << " radians\n"
00228      << "\t lower polar limit    : " << theta_1 << " radians\n"
00229      << "\t upper polar limit    : " << theta_2 << " radians\n";
00230 }
00231 
00232 
00233 G4double G4SphericalSurface::HowNear( const G4Vector3D& x ) const
00234 {
00235   //  Distance from the point x to the G4SphericalSurface.
00236   //  The distance will be positive if the point is Inside the 
00237   //  G4SphericalSurface, negative if the point is outside.
00238 
00239   G4Vector3D d = G4Vector3D( x - origin );
00240   G4double rds = d.mag();
00241 
00242   return (radius - rds);
00243 }
00244 
00245 
00246 /*
00247 G4double G4SphericalSurface::distanceAlongRay( G4int which_way,
00248                                                const G4Ray* ry,
00249                                                G4Vector3D& p ) const
00250 
00251  // Distance along a Ray (straight line with G4Vector3D) to leave or enter
00252  // a G4SphericalSurface.  The input variable which_way should be set to +1 to
00253  // indicate leaving a G4SphericalSurface, -1 to indicate entering the surface.
00254  // p is the point of intersection of the Ray with the G4SphericalSurface.
00255  // If the G4Vector3D of the Ray is opposite to that of the Normal to
00256  // the G4SphericalSurface at the intersection point, it will not leave the
00257  // G4SphericalSurface.
00258  // Similarly, if the G4Vector3D of the Ray is along that of the Normal 
00259  // to the G4SphericalSurface at the intersection point, it will not enter the
00260  // G4SphericalSurface.
00261  // This method is called by all finite shapes sub-classed to
00262  // G4SphericalSurface.
00263  // Use the virtual function table to check if the intersection point
00264  // is within the boundary of the finite shape.
00265  // A negative result means no intersection.
00266  // If no valid intersection point is found, set the distance
00267  // and intersection point to large numbers.
00268 
00269 {
00270   G4double Dist = kInfinity;
00271   G4Vector3D lv ( kInfinity, kInfinity, kInfinity );
00272   p = lv;
00273 
00274   // Origin and G4Vector3D unit vector of Ray.
00275   //
00276   G4Vector3D x = ry->Position( 0.0 );
00277   G4Vector3D dhat = ry->Direction( 0.0 );
00278   G4int isoln = 0, maxsoln = 2;
00279 
00280   // Array of solutions in distance along the Ray
00281   //
00282   G4double s[2];s[0] = -1.0; s[1]= -1.0 ;
00283 
00284   // Calculate the two solutions (quadratic equation)
00285   //
00286   G4Vector3D d = x - GetOrigin();
00287   G4double radius = GetRadius();
00288 
00289   // Quit with no intersection if the radius of the G4SphericalSurface is zero
00290   //
00291   if ( radius <= 0.0 )  { return Dist; }
00292 
00293   G4double dsq = d * d;
00294   G4double rsq = radius * radius;
00295   G4double b = d * dhat;
00296   G4double c = dsq - rsq;
00297   G4double radical = b * b - c;
00298 
00299   // Quit with no intersection if the radical is negative
00300   //
00301   if ( radical < 0.0 )  { return Dist; }
00302 
00303   G4double root = std::sqrt( radical );
00304   s[0] = -b + root;
00305   s[1] = -b - root;
00306 
00307   // Order the possible solutions by increasing distance along the Ray
00308   //
00309   G4Sort_double( s, isoln, maxsoln-1 );
00310 
00311   // Now loop over each positive solution, keeping the first one (smallest
00312   // distance along the Ray) which is within the boundary of the sub-shape
00313   // and which also has the correct G4Vector3D with respect to the Normal to
00314   // the G4SphericalSurface at the intersection point
00315   //
00316   for ( isoln = 0; isoln < maxsoln; isoln++ )
00317   {
00318     if ( s[isoln] >= 0.0 )
00319     {
00320       if ( s[isoln] >= kInfinity )  { return Dist; }  // quit if too large
00321       Dist = s[isoln];
00322       p = ry->Position( Dist );
00323       if ( ( ( dhat * Normal( p ) * which_way ) >= 0.0 )
00324           && ( WithinBoundary( p ) == 1 ) )  { return Dist; }
00325     }
00326   }
00327 
00328   // Get here only if there was no solution within the boundary,
00329   // reset distance and intersection point to large numbers
00330 
00331   p = lv;
00332   return kInfinity;
00333 }          
00334 */
00335 
00336 
00337 void G4SphericalSurface::CalcBBox()
00338 {
00339   G4double x_min = origin.x() - radius;
00340   G4double y_min = origin.y() - radius;
00341   G4double z_min = origin.z() - radius;
00342   G4double x_max = origin.x() + radius;
00343   G4double y_max = origin.y() + radius;
00344   G4double z_max = origin.z() + radius;  
00345     
00346   G4Point3D Min(x_min, y_min, z_min);
00347   G4Point3D Max(x_max, y_max, z_max);  
00348   bbox = new G4BoundingBox3D( Min, Max); 
00349 }
00350 
00351 
00352 G4int G4SphericalSurface::Intersect( const G4Ray& ry )
00353 {
00354   //  Distance along a Ray (straight line with G4Vector3D) to leave or enter
00355   //  a G4SphericalSurface.  The input variable which_way should be set to +1 
00356   //  to indicate leaving a G4SphericalSurface, -1 to indicate entering a 
00357   //  G4SphericalSurface.
00358   //  p is the point of intersection of the Ray with the G4SphericalSurface.
00359   //  If the G4Vector3D of the Ray is opposite to that of the Normal to
00360   //  the G4SphericalSurface at the intersection point, it will not leave the
00361   //  G4SphericalSurface.
00362   //  Similarly, if the G4Vector3D of the Ray is along that of the Normal 
00363   //  to the G4SphericalSurface at the intersection point, it will not enter 
00364   //  the G4SphericalSurface.
00365   //  This method is called by all finite shapes sub-classed to 
00366   //  G4SphericalSurface.
00367   //  Use the virtual function table to check if the intersection point
00368   //  is within the boundary of the finite shape.
00369   //  A negative result means no intersection.
00370   //  If no valid intersection point is found, set the distance
00371   //  and intersection point to large numbers.
00372 
00373   G4int which_way = (G4int)HowNear(ry.GetStart());
00374   
00375   if(!which_way)  { which_way =-1; }
00376   distance = kInfinity;
00377   
00378   G4Vector3D lv ( kInfinity, kInfinity, kInfinity );
00379 
00380   // p = lv;
00381   //
00382   closest_hit = lv;
00383 
00384   // Origin and G4Vector3D unit vector of Ray.
00385   //
00386   G4Vector3D x= G4Vector3D( ry.GetStart() );
00387   G4Vector3D dhat = ry.GetDir();
00388   G4int isoln = 0, maxsoln = 2;
00389 
00390   // Array of solutions in distance along the Ray
00391   //
00392   G4double ss[2];
00393   ss[0] = -1.0 ; 
00394   ss[1] = -1.0 ;
00395 
00396   // Calculate the two solutions (quadratic equation)
00397   //
00398   G4Vector3D d = G4Vector3D( x - GetOrigin() );
00399   G4double r = GetRadius();
00400 
00401   // Quit with no intersection if the radius of the G4SphericalSurface is zero
00402   //
00403   if ( r <= 0.0 )  { return 0; }
00404   
00405   G4double dsq     = d * d;
00406   G4double rsq     = r * r;
00407   G4double b       = d * dhat;
00408   G4double c       = dsq - rsq;
00409   G4double radical = b * b - c;
00410   
00411   // Quit with no intersection if the radical is negative
00412   //
00413   if ( radical < 0.0 )  { return 0; }
00414   
00415   G4double root = std::sqrt( radical );
00416   ss[0] = -b + root;
00417   ss[1] = -b - root;
00418 
00419   // Order the possible solutions by increasing distance along the Ray
00420   // G4Sort_double( ss, isoln, maxsoln-1 );
00421   //        
00422   if(ss[0] > ss[1])
00423   {
00424     G4double tmp =ss[0];
00425     ss[0] = ss[1];
00426     ss[1] = tmp;
00427   }
00428 
00429   // Now loop over each positive solution, keeping the first one (smallest
00430   // distance along the Ray) which is within the boundary of the sub-shape
00431   // and which also has the correct G4Vector3D with respect to the Normal to
00432   // the G4SphericalSurface at the intersection point
00433   //
00434   for ( isoln = 0; isoln < maxsoln; isoln++ ) 
00435   {
00436     if ( ss[isoln] >= kCarTolerance*0.5 ) 
00437     {
00438       if ( ss[isoln] >= kInfinity )  { return 0; }  // quit if too large
00439       distance = ss[isoln];
00440       closest_hit = ry.GetPoint( distance );
00441       if ( ( ( dhat * Normal( closest_hit ) * which_way ) >= 0.0 ) && 
00442            ( WithinBoundary( closest_hit ) == 1 )                      )
00443       {
00444         distance =  distance*distance;    
00445         return 1;
00446       }
00447     }
00448   }
00449   
00450   // Get here only if there was no solution within the boundary,
00451   // reset distance and intersection point to large numbers
00452   //
00453   distance = kInfinity;
00454   closest_hit = lv;
00455 
00456   return 0;
00457 }          
00458 
00459 
00460 /*
00461 G4double G4SphericalSurface::distanceAlongHelix( G4int which_way,
00462                                                  const Helix* hx,
00463                                                  G4Vector3D& p ) const
00464 {
00465   // Distance along a Helix to leave or enter a G4SphericalSurface.
00466   // The input variable which_way should be set to +1 to
00467   // indicate leaving a G4SphericalSurface, -1 to indicate entering a
00468   // G4SphericalSurface.
00469   // p is the point of intersection of the Helix with the G4SphericalSurface.
00470   // If the G4Vector3D of the Helix is opposite to that of the Normal to
00471   // the G4SphericalSurface at the intersection point, it will not leave the
00472   // G4SphericalSurface.
00473   // Similarly, if the G4Vector3D of the Helix is along that of the Normal 
00474   // to the G4SphericalSurface at the intersection point, it will not enter
00475   // the G4SphericalSurface.
00476   // This method is called by all finite shapes sub-classed to
00477   // G4SphericalSurface.
00478   // Use the virtual function table to check if the intersection point
00479   // is within the boundary of the finite shape.
00480   // If no valid intersection point is found, set the distance
00481   // and intersection point to large numbers.
00482   // Possible negative distance solutions are discarded.
00483 
00484 {
00485   G4double Dist = kInfinity;
00486   G4Vector3D lv ( kInfinity, kInfinity, kInfinity );
00487   p = lv;
00488   G4int isoln = 0, maxsoln = 4;
00489 
00490   // Array of solutions in turning angle
00491   //
00492   G4double s[4];s[0] = -1.0; s[1]= -1.0 ;s[2] = -1.0; s[3]= -1.0 ;
00493 
00494   // Helix parameters
00495   //
00496   G4double rh = hx->GetRadius();         // radius of Helix
00497   G4Vector3D oh = hx->position( 0.0 );   // origin of Helix
00498   G4Vector3D dh = hx->direction( 0.0 );  // initial G4Vector3D of Helix
00499   G4Vector3D prp = hx->getPerp();        // perpendicular vector
00500   G4double prpmag = prp.mag();
00501   G4double rhp = rh / prpmag;
00502   G4double rs = GetRadius();             // radius of G4SphericalSurface
00503   if ( rs == 0.0 )   { return Dist; }    // quit if zero radius
00504   G4Vector3D os = GetOrigin();           // origin of G4SphericalSurface
00505 
00506   // Calculate quantities of use later on
00507   //
00508   G4Vector3D alpha = rhp * prp;
00509   G4Vector3D beta = rhp * dh;
00510   G4Vector3D gamma = oh - os;
00511 
00512   // Only consider approximate solutions to quadratic order in the turning
00513   // angle along the Helix
00514   //
00515   G4double A = beta * beta  +  gamma * alpha;
00516   G4double B = 2.0 * gamma * beta;
00517   G4double C = gamma * gamma  -  rs * rs;
00518 
00519   // Case if quadratic term is zero
00520   //
00521   if ( std::fabs( A ) < kCarTolerance )
00522   {
00523     if ( B == 0.0 )  { return Dist; }      // no intersection, quit
00524     else             { s[0] = -C / B; }
00525   }
00526   else   // General quadratic solution, A != 0
00527   {
00528     G4double radical = B * B  -  4.0 * A * C;
00529     if ( radical < 0.0 )  { return Dist; } // no intersection, quit
00530                        
00531     G4double root = std::sqrt( radical );
00532     s[0] = ( -B + root ) / ( 2.0 * A );
00533     s[1] = ( -B - root ) / ( 2.0 * A );     
00534     if ( rh < 0.0 )
00535     {
00536       s[0] = -s[0];
00537       s[1] = -s[1];
00538     }
00539     s[2] = s[0] + twopi;
00540     s[3] = s[1] + twopi;
00541   }
00542 
00543   // Order the possible solutions by increasing turning angle
00544   //
00545   G4Sort_double( s, isoln, maxsoln-1 );
00546 
00547   // Now loop over each positive solution, keeping the first one (smallest
00548   // distance along the Helix) which is within the boundary of the sub-shape.
00549   //
00550   for ( isoln = 0; isoln < maxsoln; isoln++ )
00551   {
00552     if ( s[isoln] >= 0.0 )
00553     {
00554       // Calculate distance along Helix and position and G4Vector3D vectors.
00555       //
00556       Dist = s[isoln] * std::fabs( rhp );
00557       p = hx->position( Dist );
00558       G4Vector3D d = hx->direction( Dist );
00559 
00560       // Now do approximation to get remaining distance to correct this
00561       // solution iterate it until the accuracy is below the user-set
00562       // surface precision
00563       //
00564       G4double delta = 0.;  
00565       G4double delta0 = kInfinity;
00566       G4int dummy = 1;
00567       G4int iter = 0;
00568       G4int in0 = Inside( hx->position ( 0.0 ) );
00569       G4int in1 = Inside( p );
00570       G4double sc = Scale();
00571       while ( dummy )
00572       {
00573         iter++;
00574 
00575         // Terminate loop after 50 iterations and Reset distance to large
00576         // number, indicating no intersection with G4SphericalSurface. This
00577         // generally occurs if the Helix curls too tightly to intersect it.
00578         //
00579         if ( iter > 50 )
00580         {
00581           Dist = kInfinity;
00582           p = lv;
00583           break;
00584         }
00585 
00586         // Find distance from the current point along the above-calculated
00587         // G4Vector3D using a Ray.
00588         // The G4Vector3D of the Ray and the Sign of the distance are
00589         // determined by whether the starting point of the Helix is Inside
00590         // or outside of the G4SphericalSurface.
00591         //
00592         in1 = Inside( p );
00593         if ( in1 )    //  current point Inside
00594         {
00595           if ( in0 )    //  starting point Inside
00596           {
00597             Ray* r = new Ray( p, d );
00598             delta = distanceAlongRay( 1, r, p );
00599             delete r;
00600           }
00601           else         //  starting point outside
00602           {
00603             Ray* r = new Ray( p, -d );
00604             delta = -distanceAlongRay( 1, r, p );
00605             delete r;
00606           }
00607         }
00608         else          //  current point outside
00609         {
00610           if ( in0 )    //  starting point Inside
00611           {
00612             Ray* r = new Ray( p, -d );
00613             delta = -distanceAlongRay( -1, r, p );
00614             delete r;
00615           }
00616           else          //  starting point outside
00617           {
00618             Ray* r = new Ray( p, d );
00619             delta = distanceAlongRay( -1, r, p );
00620             delete r;
00621           }
00622         }
00623 
00624         // Test if distance is less than the surface precision, if so
00625         // terminate loop.
00626         //
00627         if ( std::fabs( delta / sc ) <= SURFACE_PRECISION )  { break; }
00628 
00629         // If delta has not changed sufficiently from the previous iteration, 
00630         // skip out of this loop.
00631         //
00632         if (std::fabs( ( delta-delta0 )/sc ) <= SURFACE_PRECISION)  { break; }
00633 
00634         // If delta has increased in absolute value from the previous iteration
00635         // either the Helix doesn't Intersect the G4SphericalSurface or the
00636         // approximate solution is too far from the real solution.  Try groping
00637         // for a solution. If not found, Reset distance to large number,
00638         // indicating no intersection with the G4SphericalSurface.
00639         //
00640         if ( ( std::fabs( delta ) > std::fabs( delta0 ) ) )
00641         {
00642           Dist = std::fabs( rhp ) * gropeAlongHelix( hx );
00643           if ( Dist < 0.0 )
00644           {
00645             Dist = kInfinity;
00646             p = lv;
00647           }
00648           else
00649           {
00650             p = hx->position( Dist );
00651           }
00652           break;
00653         }
00654 
00655         // Set old delta to new one.
00656         //
00657         delta0 = delta;
00658 
00659         // Add distance to G4SphericalSurface to distance along Helix.
00660         //
00661         Dist += delta;
00662 
00663         // Negative distance along Helix means Helix doesn't Intersect
00664         // G4SphericalSurface. Reset distance to large number, indicating
00665         // no intersection with G4SphericalSurface.
00666         //
00667         if ( Dist < 0.0 )
00668         {
00669           Dist = kInfinity;
00670           p = lv;
00671           break;
00672         }
00673 
00674         // Recalculate point along Helix and the G4Vector3D.
00675         //
00676         p = hx->position( Dist );
00677         d = hx->direction( Dist );
00678       }  //  end of while loop
00679 
00680       // Now have best value of distance along Helix and position for this
00681       // solution, so test if it is within the boundary of the sub-shape
00682       // and require that it point in the correct G4Vector3D with respect to
00683       // the Normal to the G4SphericalSurface.
00684 
00685       if ( ( Dist < kInfinity ) &&
00686            ( ( hx->direction( Dist ) * Normal( p ) * which_way ) >= 0.0 )
00687           && ( WithinBoundary( p ) == 1 ) )  { return Dist; }
00688     }  // end of if s[isoln] >= 0.0 condition
00689   }  // end of for loop over solutions
00690 
00691   // If one gets here, there is no solution, so set distance along Helix
00692   // and position to large numbers.
00693   //
00694   Dist = kInfinity;
00695   p = lv;
00696 
00697   return Dist;
00698 }
00699 
00700 
00701 G4Vector3D G4SphericalSurface::Normal( const G4Vector3D& p ) const
00702 {
00703   //  Return the Normal unit vector to the G4SphericalSurface at a point p on
00704   //  (or nearly on) the G4SphericalSurface.
00705 
00706   G4Vector3D n = p - origin;
00707   G4double nmag = n.mag();
00708 
00709   //  If the point p happens to coincide with the origin (which is possible
00710   //  if the radius is zero), set the Normal to the z-axis unit vector.
00711   //
00712   if ( nmag != 0.0 )  { n = n / nmag; }
00713   else  { n = G4Vector3D( 0.0, 0.0, 1.0 ); }
00714 
00715   return n;
00716 }
00717 */
00718 
00719          
00720 G4Vector3D G4SphericalSurface::Normal( const G4Vector3D& p ) const
00721 { 
00722   // Return the Normal unit vector to the G4SphericalSurface at a point p on
00723   // (or nearly on) the G4SphericalSurface.
00724 
00725   G4Vector3D n = G4Vector3D( p - origin );
00726   G4double nmag = n.mag();
00727   
00728   //  If the point p happens to coincide with the origin (which is possible
00729   //  if the radius is zero), set the Normal to the z-axis unit vector.
00730   //
00731   if ( nmag != 0.0 )  { n = n * (1/ nmag); }
00732   else  { n = G4Vector3D( 0.0, 0.0, 1.0 ); }
00733 
00734   return n;
00735 }
00736 
00737 
00738 G4Vector3D G4SphericalSurface::SurfaceNormal( const G4Point3D& p ) const
00739 { 
00740   // Return the Normal unit vector to the G4SphericalSurface at a point p on
00741   // (or nearly on) the G4SphericalSurface.
00742 
00743   G4Vector3D n = G4Vector3D( p - origin );
00744   G4double nmag = n.mag();
00745   
00746   //  If the point p happens to coincide with the origin (which is possible
00747   //  if the radius is zero), set the Normal to the z-axis unit vector.
00748   //
00749   if ( nmag != 0.0 )  { n = n * (1/ nmag); }
00750   else  { n = G4Vector3D( 0.0, 0.0, 1.0 ); }
00751 
00752   return n;
00753 }
00754 
00755 
00756 G4int G4SphericalSurface::Inside ( const G4Vector3D& x ) const
00757 {
00758   // Return 0 if point x is outside G4SphericalSurface, 1 if Inside.
00759   // Outside means that the distance to the G4SphericalSurface would 
00760   // be negative.
00761   // Use the HowNear function to calculate this distance.
00762 
00763   if ( HowNear( x ) >= 0.0 )  { return 1; }
00764   else                        { return 0; }
00765 }
00766 
00767 
00768 G4int G4SphericalSurface::WithinBoundary( const G4Vector3D& x ) const
00769 { 
00770   // Return 1 if point x is on the G4SphericalSurface, otherwise return zero
00771   // (x is assumed to lie on the surface of the G4SphericalSurface, so one 
00772   // only checks the angular limits)
00773 
00774   G4Vector3D y_axis = G4Vector3D( z_axis.cross( x_axis ) );
00775 
00776   // Components of x in the local coordinate system of the G4SphericalSurface
00777   //
00778   G4double px = x * x_axis;
00779   G4double py = x * y_axis;
00780   G4double pz = x * z_axis;
00781 
00782   // Check if within polar angle limits
00783   //
00784   G4double theta = std::acos( pz / x.mag() );  // acos in range 0 to PI
00785   
00786   // Normal case
00787   //
00788   if ( theta_2 <= pi ) 
00789   {
00790     if ( ( theta < theta_1 ) || ( theta > theta_2 ) )  { return 0; }
00791   }
00792   else 
00793   {
00794     theta += pi;
00795     if ( ( theta < theta_1 ) || ( theta > theta_2 ) )  { return 0; }
00796   }
00797 
00798   // Now check if within azimuthal angle limits
00799   //
00800   G4double phi = std::atan2( py, px );  // atan2 in range -PI to PI
00801   
00802   if ( phi < 0.0 )  { phi += twopi; }
00803   
00804   // Normal case
00805   //
00806   if ( ( phi >= phi_1 )  &&  ( phi <= phi_2 ) )  { return 1; }
00807   
00808   // This is for the case that phi_2 is greater than 2*PI
00809   //
00810   phi += twopi;
00811   
00812   if ( ( phi >= phi_1 )  &&  ( phi <= phi_2 ) )  { return 1; }
00813 
00814   // Get here if not within azimuthal limits
00815  
00816   return 0;
00817 }
00818 
00819 
00820 G4double G4SphericalSurface::Scale() const
00821 {
00822   // Returns the radius of a G4SphericalSurface unless it is zero, in which
00823   // case returns the arbitrary number 1.0.
00824   // Used for Scale-invariant tests of surface thickness.
00825 
00826   if ( radius == 0.0 )  { return 1.0; }
00827   else                  { return radius; }
00828 }
00829 
00830 
00831 G4double G4SphericalSurface::Area() const
00832 {
00833   // Returns the Area of a G4SphericalSurface
00834 
00835   return ( 2.0*( theta_2 - theta_1 )*( phi_2 - phi_1)*radius*radius/pi );
00836 }
00837 
00838 
00839 void G4SphericalSurface::resize( G4double r, 
00840                                  G4double ph1, G4double ph2,
00841                                  G4double th1, G4double th2 )
00842 { 
00843   // Resize the G4SphericalSurface to new radius r, new lower and upper 
00844   // azimuthal angle limits ph1 and ph2, and new lower and upper polar 
00845   // angle limits th1 and th2.
00846   
00847   //  Require radius to be non-negative
00848   //
00849   if ( r >= 0.0 )  { radius = r; }
00850   else 
00851   {
00852     std::ostringstream message;
00853     message << "Radius cannot be less than zero." << G4endl
00854             << "Original value of " << radius << " is retained.";    
00855     G4Exception("G4SphericalSurface::resize()",
00856                 "GeomSolids1001", JustWarning, message);
00857   }
00858 
00859   //  Require azimuthal angles to be within bounds
00860   
00861   if ( ( ph1 >= 0.0 ) && ( ph1 < twopi ) )  { phi_1 = ph1; }
00862   else 
00863   {
00864     std::ostringstream message;
00865     message << "Lower azimuthal limit out of range." << G4endl
00866             << "Original value of " << phi_1 << " is retained.";    
00867     G4Exception("G4SphericalSurface::resize()",
00868                 "GeomSolids1001", JustWarning, message);
00869   }
00870   
00871   if ( ( ph2 > phi_1 ) && ( ph2 <= ( phi_1 + twopi ) ) )  { phi_2 = ph2; }
00872   else 
00873   {
00874     ph2 = ( phi_2 <= phi_1 ) ? ( phi_1 + kAngTolerance ) : phi_2;
00875     phi_2 = ph2;
00876     std::ostringstream message;
00877     message << "Upper azimuthal limit out of range." << G4endl
00878             << "Value of " << phi_2 << " is used.";    
00879     G4Exception("G4SphericalSurface::resize()",
00880                 "GeomSolids1001", JustWarning, message);
00881   }
00882 
00883   // Require polar angles to be within bounds
00884   //
00885   if ( ( th1 >= 0.0 ) && ( th1 < pi ) )  { theta_1 = th1; }
00886   else 
00887   {
00888     std::ostringstream message;
00889     message << "Lower polar limit out of range." << G4endl
00890             << "Original value of " << theta_1 << " is retained.";    
00891     G4Exception("G4SphericalSurface::resize()",
00892                 "GeomSolids1001", JustWarning, message);
00893   }
00894   
00895   if ( ( th2 > theta_1 ) && ( th2 <= ( theta_1 + pi ) ) )  { theta_2 = th2; }
00896   else
00897   {
00898     th2 = ( theta_2 <= theta_1 ) ? ( theta_1 + kAngTolerance ) : theta_2;
00899     theta_2 = th2;
00900     std::ostringstream message;
00901     message << "Upper polar limit out of range." << G4endl
00902             << "Value of " << theta_2 << " is used.";    
00903     G4Exception("G4SphericalSurface::resize()",
00904                 "GeomSolids1001", JustWarning, message);
00905   }
00906 }
00907 
00908 
00909 /*
00910 void G4SphericalSurface::
00911 rotate( G4double alpha, G4double beta,
00912         G4double gamma, G4ThreeMat& m, G4int inverse )
00913 {
00914   // Rotate G4SphericalSurface first about global x_axis by angle alpha,
00915   //                  second about global y-axis by angle beta,
00916   //               and third about global z_axis by angle gamma
00917   // by creating and using G4ThreeMat objects in Surface::rotate
00918   // angles are assumed to be given in radians
00919   // if inverse is non-zero, the order of rotations is reversed
00920   // the axis is rotated here, the origin is rotated by calling
00921   // Surface::rotate
00922 
00923   G4Surface::rotate( alpha, beta, gamma, m, inverse );
00924   x_axis = m * x_axis;
00925   z_axis = m * z_axis;
00926 }
00927 
00928 
00929 void G4SphericalSurface::
00930 rotate( G4double alpha, G4double beta, G4double gamma, G4int inverse )
00931 {
00932   // Rotate G4SphericalSurface first about global x_axis by angle alpha,
00933   //                  second about global y-axis by angle beta,
00934   //               and third about global z_axis by angle gamma
00935   // by creating and using G4ThreeMat objects in Surface::rotate
00936   // angles are assumed to be given in radians
00937   // if inverse is non-zero, the order of rotations is reversed
00938   // the axis is rotated here, the origin is rotated by calling
00939   // Surface::rotate
00940 
00941   G4ThreeMat m;
00942   G4Surface::rotate( alpha, beta, gamma, m, inverse );
00943   x_axis = m * x_axis;
00944   z_axis = m * z_axis;
00945 }
00946 */
00947 
00948 
00949 /*
00950 G4double G4SphericalSurface::gropeAlongHelix( const Helix* hx ) const
00951 {
00952   // Grope for a solution of a Helix intersecting a G4SphericalSurface.
00953   // This function returns the turning angle (in radians) where the
00954   // intersection occurs with only positive values allowed, or -1.0 if
00955   // no intersection is found.
00956   // The idea is to start at the beginning of the Helix, then take steps
00957   // of some fraction of a turn.  If at the end of a Step, the current position
00958   // along the Helix and the previous position are on opposite sides of the
00959   // G4SphericalSurface, then the solution must lie somewhere in between.
00960 
00961   G4int one_over_f = 8;  // one over fraction of a turn to go in each Step
00962   G4double turn_angle = 0.0;
00963   G4double dist_along = 0.0;
00964   G4double d_new;
00965   G4double fk = 1.0 / G4double( one_over_f );
00966   G4double scal = Scale();
00967   G4double d_old = HowNear( hx->position( dist_along ) );
00968   G4double rh = hx->GetRadius();    // radius of Helix
00969   G4Vector3D prp = hx->getPerp();   // perpendicular vector
00970   G4double prpmag = prp.mag();
00971   G4double rhp = rh / prpmag;
00972   G4int max_iter = one_over_f * HELIX_MAX_TURNS;
00973 
00974   // Take up to a user-settable number of turns along the Helix,
00975   // groping for an intersection point.
00976 
00977   for ( G4int k = 1; k < max_iter; k++ )
00978   {
00979     turn_angle = twopi * k / one_over_f;
00980     dist_along = turn_angle * std::fabs( rhp );
00981     d_new = HowNear( hx->position( dist_along ) );
00982     if ( ( d_old < 0.0 && d_new > 0.0 ) || ( d_old > 0.0 && d_new < 0.0 ) )
00983     {
00984       d_old = d_new;
00985 
00986       // Old and new points are on opposite sides of the G4SphericalSurface,
00987       // therefore a solution lies in between, use a binary search to pin the
00988       // point down to the surface precision, but don't do more than 50
00989       // iterations.
00990 
00991       G4int itr = 0;
00992       while ( std::fabs( d_new / scal ) > SURFACE_PRECISION )
00993       {
00994         itr++;
00995         if ( itr > 50 )  { return turn_angle; }
00996         turn_angle -= fk * pi;
00997         dist_along = turn_angle * std::fabs( rhp );
00998         d_new = HowNear( hx->position( dist_along ) );
00999         if (( d_old < 0.0 && d_new > 0.0 ) || ( d_old > 0.0 && d_new < 0.0 ))
01000           { fk *= -0.5; }
01001         else
01002           { fk *=  0.5; }
01003         d_old = d_new;
01004       }  //  end of while loop
01005       return turn_angle;  // this is the best solution
01006     }  //  end of if condition
01007   }  //  end of for loop
01008 
01009   //  Get here only if no solution is found, so return -1.0 to indicate that.
01010 
01011   return -1.0;
01012 }
01013 */

Generated on Mon May 27 17:49:52 2013 for Geant4 by  doxygen 1.4.7