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 */