G4ConicalSurface.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 // G4ConicalSurface.cc
00033 //
00034 // ----------------------------------------------------------------------
00035 
00036 #include "G4ConicalSurface.hh"
00037 #include "G4PhysicalConstants.hh"
00038 #include "G4Sort.hh"
00039 #include "G4Globals.hh"
00040 
00041 
00042 G4ConicalSurface::G4ConicalSurface()
00043   : G4Surface(), axis(G4Vector3D(1.,0.,0.)), angle(1.)
00044 {  
00045 }
00046 
00047 G4ConicalSurface::G4ConicalSurface( const G4Point3D&, 
00048                                     const G4Vector3D& a,
00049                                     G4double e           )
00050   : G4Surface()
00051 {  
00052   // Normal constructor
00053   // require axis to be a unit vector
00054 
00055   G4double amag = a.mag2();
00056 
00057   if ( amag != 0.0 )
00058   {
00059     axis = a*(1/amag);
00060   }
00061   else
00062   {
00063     std::ostringstream message;
00064     message << "Axis has zero length." << G4endl
00065             << "Default axis ( 1.0, 0.0, 0.0 ) is used.";
00066     G4Exception("G4ConicalSurface::G4ConicalSurface()", "GeomSolids1001",
00067                 JustWarning, message);
00068 
00069     axis = G4Vector3D( 1.0, 0.0, 0.0 );
00070   }
00071 
00072   //  Require angle to range from 0 to PI/2
00073   //
00074   if ( ( e > 0.0 ) && ( e < ( 0.5 * pi ) ) )
00075   {
00076     angle = e;
00077   }
00078   else
00079   {
00080     std::ostringstream message;
00081     message << "Angle out of range." << G4endl
00082             << "Asked for angle out of allowed range of 0 to "
00083             << 0.5*pi << " (PI/2): " << e << G4endl
00084             << "Default angle of 1.0 is used.";    
00085     G4Exception("G4ConicalSurface::G4ConicalSurface()", "GeomSolids1001",
00086                 JustWarning, message);
00087     angle = 1.0;
00088   }
00089 }
00090 
00091 
00092 G4ConicalSurface::~G4ConicalSurface()
00093 {
00094 }
00095 
00096 
00097 G4ConicalSurface::G4ConicalSurface( const G4ConicalSurface& c )
00098   : G4Surface(), axis(c.axis), angle(c.angle)
00099 {
00100 }
00101 
00102 
00103 G4ConicalSurface&
00104 G4ConicalSurface::operator=( const G4ConicalSurface& c )
00105 {
00106   if (&c == this)  { return *this; }
00107   axis    = c.axis;
00108   angle   = c.angle;
00109 
00110   return *this;
00111 }
00112 
00113 
00114 const char* G4ConicalSurface::NameOf() const
00115 {
00116    return "G4ConicalSurface";
00117 }
00118 
00119 void G4ConicalSurface::CalcBBox()
00120 {
00121   bbox= new G4BoundingBox3D(surfaceBoundary.BBox().GetBoxMin(), 
00122                             surfaceBoundary.BBox().GetBoxMax());
00123 }
00124 
00125 void G4ConicalSurface::PrintOn( std::ostream& os ) const
00126 { 
00127   // printing function using C++ std::ostream class
00128 
00129   os << "G4ConicalSurface surface with origin: " << origin << "\t"
00130      << "angle: " << angle << " radians \tand axis " << axis << "\n";
00131 }
00132 
00133 
00134 G4double G4ConicalSurface::HowNear( const G4Vector3D& x ) const
00135 { 
00136   // Distance from the point x to the semi-infinite G4ConicalSurface.
00137   // The distance will be positive if the point is Inside the G4ConicalSurface,
00138   // negative if the point is outside.
00139   // Note that this may not be correct for a bounded conical object
00140   // subclassed to G4ConicalSurface.
00141 
00142   G4Vector3D d    = G4Vector3D( x - origin );
00143   G4double   l    = d * axis;
00144   G4Vector3D q    = G4Vector3D( origin  +  l * axis );
00145   G4Vector3D v    = G4Vector3D( x - q );
00146 
00147   G4double   Dist = ( l*std::tan(angle) - v.mag2() ) * std::cos(angle);
00148 
00149   return Dist;
00150 }
00151 
00152 
00153 G4int G4ConicalSurface::Intersect( const G4Ray& ry )  
00154 {
00155   //  Distance along a Ray (straight line with G4Vector3D) to leave or enter
00156   //  a G4ConicalSurface.  The input variable which_way should be set to +1 to
00157   //  indicate leaving a G4ConicalSurface, -1 to indicate entering a 
00158   //  G4ConicalSurface.
00159   //  p is the point of intersection of the Ray with the G4ConicalSurface.
00160   //  If the G4Vector3D of the Ray is opposite to that of the Normal to
00161   //  the G4ConicalSurface at the intersection point, it will not leave the 
00162   //  G4ConicalSurface.
00163   //  Similarly, if the G4Vector3D of the Ray is along that of the Normal 
00164   //  to the G4ConicalSurface at the intersection point, it will not enter the
00165   //  G4ConicalSurface.
00166   //  This method is called by all finite shapes sub-classed to 
00167   //  G4ConicalSurface.
00168   //  Use the virtual function table to check if the intersection point
00169   //  is within the boundary of the finite shape.
00170   //  A negative result means no intersection.
00171   //  If no valid intersection point is found, set the distance
00172   //  and intersection point to large numbers.
00173   
00174   G4int which_way = -1; // Originally a parameter.Read explanation above. 
00175 
00176   distance = kInfinity;
00177 
00178   G4Vector3D lv ( kInfinity, kInfinity, kInfinity );
00179   closest_hit = lv;
00180 
00181   //  Origin and G4Vector3D unit vector of Ray.
00182   //
00183   G4Vector3D x = G4Vector3D( ry.GetStart() );
00184   G4Vector3D dhat = ry.GetDir();
00185   
00186   
00187   //  Cone angle and axis unit vector.
00188   //
00189   G4double   ta      = std::tan( GetAngle() );
00190   G4Vector3D ahat    = GetAxis();
00191   G4int      isoln   = 0, 
00192              maxsoln = 2;
00193 
00194   //  array of solutions in distance along the Ray
00195   //
00196   G4double sol[2];
00197   sol[0] = -1.0; 
00198   sol[1] = -1.0 ;
00199 
00200   //  calculate the two solutions (quadratic equation)
00201   //
00202   G4Vector3D gamma = G4Vector3D( x - GetOrigin() );
00203   G4double   T  = 1.0  +  ta * ta;
00204   G4double   ga = gamma * ahat;
00205   G4double   da = dhat * ahat;
00206   G4double   A  = 1.0 - T * da * da;
00207   G4double   B  = 2.0 * ( gamma * dhat - T * ga * da );
00208   G4double   C  = gamma * gamma - T * ga * ga;
00209 
00210   //  if quadratic term vanishes, just do the simple solution
00211   //
00212   if ( std::fabs( A ) < kCarTolerance ) 
00213   {
00214     if ( B == 0.0 )
00215       { return 1; }
00216     else
00217       { sol[0] = -C / B; }
00218   }
00219 
00220   //  Normal quadratic case, no intersection if radical is less than zero
00221   //
00222   else 
00223   {
00224     G4double radical = B * B  -  4.0 * A * C; 
00225     if ( radical < 0.0 ) 
00226     {
00227       return 1;
00228     }
00229     else 
00230     {
00231       G4double root = std::sqrt( radical );
00232       sol[0] = ( - B + root ) / ( 2. * A );
00233       sol[1] = ( - B - root ) / ( 2. * A );
00234     }
00235   }
00236 
00237   //  order the possible solutions by increasing distance along the Ray
00238   //
00239   sort_double( sol, isoln, maxsoln-1 );
00240 
00241   //  now loop over each positive solution, keeping the first one (smallest
00242   //  distance along the Ray) which is within the boundary of the sub-shape
00243   //  and which also has the correct G4Vector3D with respect to the Normal to
00244   //  the G4ConicalSurface at the intersection point
00245   //
00246   for ( isoln = 0; isoln < maxsoln; isoln++ ) 
00247   {
00248     if ( sol[isoln] >= 0.0 ) 
00249     {
00250       if ( sol[isoln] >= kInfinity )  // quit if too large
00251       {
00252         return 1;
00253       }
00254       
00255       distance = sol[isoln];
00256       closest_hit = ry.GetPoint( distance );
00257 
00258       //  Following line necessary to select non-reflective solutions.
00259       //
00260       if (( ahat * ( closest_hit - GetOrigin() ) > 0.0 ) && 
00261           ((( dhat * SurfaceNormal( closest_hit ) * which_way )) >= 0.0 ) && 
00262           ( std::fabs(HowNear( closest_hit )) < 0.1)                               )
00263       {
00264         return 1;
00265       }
00266     }
00267   }
00268 
00269   //  get here only if there was no solution within the boundary, Reset
00270   //  distance and intersection point to large numbers
00271   //
00272   distance = kInfinity;
00273   closest_hit = lv;
00274 
00275   return 0;
00276 }
00277 
00278 
00279 /*
00280   G4double G4ConicalSurface::distanceAlongHelix(G4int which_way, const Helix* hx,
00281   G4Vector3D& p ) const 
00282   {  //  Distance along a Helix to leave or enter a G4ConicalSurface.
00283   //  The input variable which_way should be set to +1 to
00284   //  indicate leaving a G4ConicalSurface, -1 to indicate entering a 
00285   //  G4ConicalSurface.
00286   //  p is the point of intersection of the Helix with the G4ConicalSurface.
00287   //  If the G4Vector3D of the Helix is opposite to that of the Normal to
00288   //  the G4ConicalSurface at the intersection point, it will not leave the 
00289   //  G4ConicalSurface.
00290   //  Similarly, if the G4Vector3D of the Helix is along that of the Normal 
00291   //  to the G4ConicalSurface at the intersection point, it will not enter the
00292   //  G4ConicalSurface.
00293   //  This method is called by all finite shapes sub-classed to 
00294   //  G4ConicalSurface.
00295   //  Use the virtual function table to check if the intersection point
00296   //  is within the boundary of the finite shape.
00297   //  If no valid intersection point is found, set the distance
00298   //  and intersection point to large numbers.
00299   //  Possible negative distance solutions are discarded.
00300   G4double Dist = kInfinity;
00301   G4Vector3D lv ( kInfinity, kInfinity, kInfinity );
00302   p = lv;
00303   G4int isoln = 0, maxsoln = 4;
00304   
00305   //  Array of solutions in turning angle
00306   //    G4double s[4] = { -1.0, -1.0, -1.0, -1.0 };
00307   G4double s[4];s[0] = -1.0; s[1]= -1.0 ;s[2] = -1.0; s[3]= -1.0 ;
00308   
00309   //  Flag set to 1 if exact solution is found
00310   G4int exact = 0;
00311   
00312   //  Helix parameters
00313   G4double   rh     = hx->GetRadius();      // radius of Helix
00314   G4Vector3D oh     = hx->position();       // origin of Helix
00315   G4Vector3D dh     = hx->direction( 0.0 ); // initial G4Vector3D of Helix
00316   G4Vector3D prp    = hx->getPerp();        // perpendicular vector
00317   G4double   prpmag = prp.Magnitude();
00318   G4double   rhp    = rh / prpmag;
00319 
00320    //  G4ConicalSurface parameters
00321    G4double   ta = std::tan( GetAngle() );  // tangent of angle of G4ConicalSurface
00322    G4Vector3D oc = GetOrigin();        // origin of G4ConicalSurface
00323    G4Vector3D ac = GetAxis();          // axis of G4ConicalSurface
00324    
00325    //  Calculate quantities of use later on
00326    G4Vector3D alpha = rhp * prp;
00327    G4Vector3D beta  = rhp * dh;
00328    G4Vector3D gamma = oh - oc;
00329    G4double   T     = 1.0  +  ta * ta;
00330    G4double   gc    = gamma * ac;
00331    G4double   bc    = beta * ac;
00332    
00333    //  General approximate solution for std::sin(s)-->s and std::cos(s)-->1-s**2/2,
00334    //  keeping only terms to second order in s
00335    G4double A = gamma * alpha - T * ( gc * alpha * ac - bc * bc ) +
00336                 beta * beta;
00337    G4double B = 2.0 * ( gamma * beta - gc * bc * T );
00338    G4double C = gamma * gamma - gc * gc * T;
00339    
00340    //  Solution for no quadratic term
00341    if ( std::fabs( A ) < kCarTolerance ) 
00342    {
00343      if ( B == 0.0 )
00344        return Dist;
00345      else
00346        s[0] = -C / B;
00347    }
00348 
00349    //  General quadratic solutions
00350    else {
00351    G4double radical = B * B - 4.0 * A * C;
00352    if ( radical < 0.0 )
00353    //  Radical is less than zero, either there is no intersection, or the
00354    //  approximation doesn't hold, so try a cruder technique to find a 
00355    //  possible intersection point using the gropeAlongHelix function.
00356    s[0] = gropeAlongHelix( hx );
00357    //  Normal non-negative radical solutions
00358    else {
00359    G4double root = std::sqrt( radical );
00360    s[0] = ( -B + root ) / ( 2.0 * A );
00361    s[1] = ( -B - root ) / ( 2.0 * A );
00362    if ( rh < 0.0 ) {
00363    s[0] = -s[0];
00364    s[1] = -s[1];
00365    }
00366    s[2] = s[0] + 2.0 * pi;
00367    s[3] = s[1] + 2.0 * pi;
00368    }
00369    }
00370    //
00371    //  Order the possible solutions by increasing turning angle
00372    //  (G4Sorting routines are in support/G4Sort.h).
00373    G4Sort_double( s, isoln, maxsoln-1 );
00374    //
00375    //  Now loop over each positive solution, keeping the first one (smallest
00376    //  distance along the Helix) which is within the boundary of the sub-shape.
00377    for ( isoln = 0; isoln < maxsoln; isoln++ ) {
00378    if ( s[isoln] >= 0.0 ) {
00379    //  Calculate distance along Helix and position and G4Vector3D vectors.
00380    Dist = s[isoln] * std::fabs( rhp );
00381    p = hx->position( Dist );
00382    G4Vector3D d = hx->direction( Dist );
00383    if ( exact == 0 ) {  //  only for approximate solns
00384    //  Now do approximation to get remaining distance to correct this solution.
00385    //  Iterate it until the accuracy is below the user-set surface precision.
00386    G4double delta = 0.;  
00387    G4double delta0 = kInfinity;
00388    G4int dummy = 1;
00389    G4int iter = 0;
00390    G4int in0 = Inside( hx->position() );
00391    G4int in1 = Inside( p );
00392    G4double sc = Scale();
00393    while ( dummy ) {
00394    iter++;
00395    //  Terminate loop after 50 iterations and Reset distance to large number,
00396    //  indicating no intersection with G4ConicalSurface.
00397    //  This generally occurs if the Helix curls too tightly to Intersect it.
00398    if ( iter > 50 ) {
00399    Dist = kInfinity;
00400    p = lv;
00401    break;
00402    }
00403    //  Find distance from the current point along the above-calculated
00404    //  G4Vector3D using a Ray.
00405    //  The G4Vector3D of the Ray and the Sign of the distance are determined
00406    //  by whether the starting point of the Helix is Inside or outside of
00407    //  the G4ConicalSurface.
00408    in1 = Inside( p );
00409    if ( in1 ) {  //  current point Inside
00410    if ( in0 ) {  //  starting point Inside
00411    Ray* r = new Ray( p, d );
00412    delta = 
00413    distanceAlongRay( 1, r, p );
00414    delete r;
00415    }
00416    else {       //  starting point outside
00417    Ray* r = new Ray( p, -d );
00418    delta = 
00419    -distanceAlongRay( 1, r, p );
00420    delete r;
00421    }
00422    }
00423    else {        //  current point outside
00424    if ( in0 ) {  //  starting point Inside
00425    Ray* r = new Ray( p, -d );
00426    delta = 
00427    -distanceAlongRay( -1, r, p );
00428    delete r;
00429    }
00430    else {        //  starting point outside
00431    Ray* r = new Ray( p, d );
00432    delta = 
00433    distanceAlongRay( -1, r, p );
00434    delete r;
00435    }
00436    }
00437    //  Test if distance is less than the surface precision, if so Terminate loop.
00438    if ( std::fabs( delta / sc ) <= SURFACE_PRECISION )
00439    break;
00440    //  If delta has not changed sufficiently from the previous iteration, 
00441    //  skip out of this loop.
00442    if ( std::fabs( ( delta - delta0 ) / sc ) <=
00443    SURFACE_PRECISION )
00444    break;
00445    //  If delta has increased in absolute value from the previous iteration
00446    //  either the Helix doesn't Intersect the G4ConicalSurface or the approximate solution
00447    //  is too far from the real solution.  Try groping for a solution.  If not
00448    //  found, Reset distance to large number, indicating no intersection with
00449    //  the G4ConicalSurface.
00450    if ( std::fabs( delta ) > std::fabs( delta0 ) ) {
00451    Dist = std::fabs( rhp ) * 
00452    gropeAlongHelix( hx );
00453    if ( Dist < 0.0 ) {
00454    Dist = kInfinity;
00455    p = lv;
00456    }
00457    else
00458    p = hx->position( Dist );
00459    break;
00460    }
00461    //  Set old delta to new one.
00462    delta0 = delta;
00463    //  Add distance to G4ConicalSurface to distance along Helix.
00464    Dist += delta;
00465    //  Negative distance along Helix means Helix doesn't Intersect G4ConicalSurface.
00466    //  Reset distance to large number, indicating no intersection with G4ConicalSurface.
00467    if ( Dist < 0.0 ) {
00468    Dist = kInfinity;
00469    p = lv;
00470    break;
00471    }
00472    //  Recalculate point along Helix and the G4Vector3D.
00473    p = hx->position( Dist );
00474    d = hx->direction( Dist );
00475    }  //  end of while loop
00476    }  //  end of exact == 0 condition
00477    //  Now have best value of distance along Helix and position for this
00478    //  solution, so test if it is within the boundary of the sub-shape
00479    //  and require that it point in the correct G4Vector3D with respect to
00480    //  the Normal to the G4ConicalSurface.
00481    if ( ( Dist < kInfinity ) &&
00482    ( ( hx->direction( Dist ) * Normal( p ) *
00483    which_way ) >= 0.0 ) &&
00484    ( WithinBoundary( p ) == 1 ) )
00485    return Dist;
00486    }  // end of if s[isoln] >= 0.0 condition
00487    }  // end of for loop over solutions
00488    //  If one gets here, there is no solution, so set distance along Helix
00489    //  and position to large numbers.
00490    Dist = kInfinity;
00491    p = lv;
00492    return Dist;
00493    }
00494 */
00495 
00496 
00497 G4Vector3D G4ConicalSurface::SurfaceNormal( const G4Point3D& p ) const
00498 {  
00499   //  return the Normal unit vector to the G4ConicalSurface at a point p 
00500   //  on (or nearly on) the G4ConicalSurface
00501 
00502   G4Vector3D ss   = G4Vector3D( p - origin );
00503   G4double   smag = ss.mag2();
00504   
00505   //  if the point happens to be at the origin, calculate a unit vector Normal
00506   //  to the axis, with zero z component
00507   //
00508   if ( smag == 0.0 )
00509   {
00510     G4double ax = axis.x();
00511     G4double ay = axis.y();
00512     G4double ap = std::sqrt( ax * ax  +  ay * ay );
00513 
00514     if ( ap == 0.0 )
00515       { return G4Vector3D( 1.0, 0.0, 0.0 ); }
00516     else
00517       { return G4Vector3D( ay / ap, -ax / ap, 0.0 ); }
00518   }
00519   else  // otherwise do the calculation of the Normal to the conical surface
00520   {
00521     G4double l = ss * axis;
00522     ss = ss*(1/smag);
00523     G4Vector3D q    = G4Vector3D( origin  +  l * axis );
00524     G4Vector3D v    = G4Vector3D( p - q );
00525     G4double   sl   = v.mag2() * std::sin( angle );
00526     G4Vector3D n    = G4Vector3D( v - sl * ss );
00527     G4double   nmag = n.mag2(); 
00528 
00529     if ( nmag != 0.0 )
00530     {
00531       n=n*(1/nmag);
00532     }
00533     return n;
00534   }
00535 }
00536 
00537 
00538 G4int G4ConicalSurface::Inside ( const G4Vector3D& x ) const
00539 { 
00540   // Return 0 if point x is outside G4ConicalSurface, 1 if Inside.
00541   // Outside means that the distance to the G4ConicalSurface would be negative.
00542   // Use the HowNear function to calculate this distance.
00543 
00544   if ( HowNear( x ) >= -0.5*kCarTolerance )
00545     { return 1; }
00546   else
00547     { return 0; }
00548 }
00549 
00550 
00551 G4int G4ConicalSurface::WithinBoundary( const G4Vector3D& x ) const
00552 {  
00553   //  return 1 if point x is on the G4ConicalSurface, otherwise return zero
00554   //  base this on the surface precision factor
00555 
00556   if ( std::fabs( HowNear( x ) / Scale() ) <= SURFACE_PRECISION )
00557     { return 1; }
00558   else
00559     { return 0; }
00560 }
00561 
00562 G4double G4ConicalSurface::Scale() const
00563 {
00564   return 1.0;
00565 }
00566 
00567 void G4ConicalSurface::SetAngle( G4double e )
00568 {
00569   //  Reset the angle of the G4ConicalSurface
00570   //  Require angle to range from 0 to PI/2
00571 
00572   if ( (e > 0.0) && (e <= ( 0.5 * pi )) )
00573   {
00574     angle = e;
00575   }
00576   else   // use old value (do not change angle) if out of the range, 
00577   {      // but print warning message
00578     std::ostringstream message;
00579     message << "Angle out of range." << G4endl
00580             << "Asked for angle out of allowed range of 0 to "
00581             << 0.5*pi << " (PI/2): " << e << G4endl
00582             << "Default angle of " << angle << " is used.";    
00583     G4Exception("G4ConicalSurface::SetAngle()", "GeomSolids1001",
00584                 JustWarning, message);
00585   }
00586 }
00587 

Generated on Mon May 27 17:47:57 2013 for Geant4 by  doxygen 1.4.7