Geant4  9.6.p02
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4SphericalSurface.cc
Go to the documentation of this file.
1 //
2 // ********************************************************************
3 // * License and Disclaimer *
4 // * *
5 // * The Geant4 software is copyright of the Copyright Holders of *
6 // * the Geant4 Collaboration. It is provided under the terms and *
7 // * conditions of the Geant4 Software License, included in the file *
8 // * LICENSE and available at http://cern.ch/geant4/license . These *
9 // * include a list of copyright holders. *
10 // * *
11 // * Neither the authors of this software system, nor their employing *
12 // * institutes,nor the agencies providing financial support for this *
13 // * work make any representation or warranty, express or implied, *
14 // * regarding this software system or assume any liability for its *
15 // * use. Please see the license in the file LICENSE and URL above *
16 // * for the full disclaimer and the limitation of liability. *
17 // * *
18 // * This code implementation is the result of the scientific and *
19 // * technical work of the GEANT4 collaboration. *
20 // * By using, copying, modifying or distributing the software (or *
21 // * any work based on the software) you agree to acknowledge its *
22 // * use in resulting scientific publications, and indicate your *
23 // * acceptance of all terms of the Geant4 Software license. *
24 // ********************************************************************
25 //
26 //
27 // $Id$
28 //
29 // ----------------------------------------------------------------------
30 // GEANT 4 class source file
31 //
32 // G4SphericalSurface.cc
33 //
34 // ----------------------------------------------------------------------
35 
36 #include "G4SphericalSurface.hh"
37 #include "G4PhysicalConstants.hh"
38 
40  : G4Surface(), radius(1.0), phi_1(0.0), phi_2(2*pi),
41  theta_1(0.0), theta_2(pi)
42 {
43  // default constructor
44  // default x_axis is ( 1.0, 0.0, 0.0 ), z_axis is ( 0.0, 0.0, 1.0 ),
45  // default radius is 1.0
46  // default phi_1 is 0, phi_2 is 2*PI
47  // default theta_1 is 0, theta_2 is PI
48 
49  x_axis = G4Vector3D( 1.0, 0.0, 0.0 );
50  z_axis = G4Vector3D( 0.0, 0.0, 1.0 );
51  // OuterBoundary = new G4BREPPolyline();
52 }
53 
54 
56  const G4Vector3D& xhat,
57  const G4Vector3D& zhat,
58  G4double r,
59  G4double ph1, G4double ph2,
60  G4double th1, G4double th2)
61  : G4Surface()
62 {
63  // Require both x_axis and z_axis to be unit vectors
64 
65  G4double xhatmag = xhat.mag();
66  if ( xhatmag != 0.0 )
67  {
68  x_axis = xhat * (1/ xhatmag); // this makes the x_axis a unit vector
69  }
70  else
71  {
72  std::ostringstream message;
73  message << "x_axis has zero length." << G4endl
74  << "Default x_axis of (1, 0, 0) is used.";
75  G4Exception("G4SphericalSurface::G4SphericalSurface()",
76  "GeomSolids1001", JustWarning, message);
77 
78  x_axis = G4Vector3D( 1.0, 0.0, 0.0 );
79  }
80 
81  G4double zhatmag = zhat.mag();
82 
83  if (zhatmag != 0.0)
84  {
85  z_axis = zhat *(1/ zhatmag); // this makes the z_axis a unit vector
86  }
87  else
88  {
89  std::ostringstream message;
90  message << "z_axis has zero length." << G4endl
91  << "Default z_axis of (0, 0, 1) is used.";
92  G4Exception("G4SphericalSurface::G4SphericalSurface()",
93  "GeomSolids1001", JustWarning, message);
94 
95  z_axis = G4Vector3D( 0.0, 0.0, 1.0 );
96  }
97 
98  // Require radius to be non-negative
99  //
100  if ( r >= 0.0 )
101  {
102  radius = r;
103  }
104  else
105  {
106  std::ostringstream message;
107  message << "Radius cannot be less than zero." << G4endl
108  << "Default radius of 1.0 is used.";
109  G4Exception("G4SphericalSurface::G4SphericalSurface()",
110  "GeomSolids1001", JustWarning, message);
111 
112  radius = 1.0;
113  }
114 
115  // Require phi_1 in the range: 0 <= phi_1 < 2*PI
116  // and phi_2 in the range: phi_1 < phi_2 <= phi_1 + 2*PI
117  //
118  if ( ( ph1 >= 0.0 ) && ( ph1 < 2*pi ) )
119  {
120  phi_1 = ph1;
121  }
122  else
123  {
124  std::ostringstream message;
125  message << "Lower azimuthal limit is out of range." << G4endl
126  << "Default angle of 0 is used.";
127  G4Exception("G4SphericalSurface::G4SphericalSurface()",
128  "GeomSolids1001", JustWarning, message);
129 
130  phi_1 = 0.0;
131  }
132 
133  if ( ( ph2 > phi_1 ) && ( ph2 <= ( phi_1 + twopi ) ) )
134  {
135  phi_2 = ph2;
136  }
137  else
138  {
139  std::ostringstream message;
140  message << "Upper azimuthal limit is out of range." << G4endl
141  << "Default angle of 2*PI is used.";
142  G4Exception("G4SphericalSurface::G4SphericalSurface()",
143  "GeomSolids1001", JustWarning, message);
144 
145  phi_2 = twopi;
146  }
147 
148  // Require theta_1 in the range: 0 <= theta_1 < PI
149  // and theta-2 in the range: theta_1 < theta_2 <= theta_1 + PI
150  //
151  if ( ( th1 >= 0.0 ) && ( th1 < pi ) )
152  {
153  theta_1 = th1;
154  }
155  else
156  {
157  std::ostringstream message;
158  message << "Lower polar limit is out of range." << G4endl
159  << "Default angle of 0 is used.";
160  G4Exception("G4SphericalSurface::G4SphericalSurface()",
161  "GeomSolids1001", JustWarning, message);
162 
163  theta_1 = 0.0;
164  }
165 
166  if ( ( th2 > theta_1 ) && ( th2 <= ( theta_1 + pi ) ) )
167  {
168  theta_2 =th2;
169  }
170  else
171  {
172  std::ostringstream message;
173  message << "Upper polar limit is out of range." << G4endl
174  << "Default angle of PI is used.";
175  G4Exception("G4SphericalSurface::G4SphericalSurface()",
176  "GeomSolids1001", JustWarning, message);
177 
178  theta_2 = pi;
179  }
180 }
181 
182 
184 {
185 }
186 
187 
189  : G4Surface()
190 {
191  x_axis = surf.x_axis;
192  z_axis = surf.z_axis;
193  radius = surf.radius;
194  phi_1 = surf.phi_1;
195  phi_2 = surf.phi_2;
196  theta_1 = surf.theta_1;
197  theta_2 = surf.theta_2;
198 }
199 
201 G4SphericalSurface::operator=( const G4SphericalSurface& surf )
202 {
203  if (&surf == this) { return *this; }
204  x_axis = surf.x_axis;
205  z_axis = surf.z_axis;
206  radius = surf.radius;
207  phi_1 = surf.phi_1;
208  phi_2 = surf.phi_2;
209  theta_1 = surf.theta_1;
210  theta_2 = surf.theta_2;
211 
212  return *this;
213 }
214 
215 const char* G4SphericalSurface::NameOf() const
216 {
217  return "G4SphericalSurface";
218 }
219 
220 void G4SphericalSurface::PrintOn( std::ostream& os ) const
221 {
222  os << "G4SphericalSurface surface with origin: " << origin << "\t"
223  << "radius: " << radius << "\n"
224  << "\t local x_axis: " << x_axis
225  << "\t local z_axis: " << z_axis << "\n"
226  << "\t lower azimuthal limit: " << phi_1 << " radians\n"
227  << "\t upper azimuthal limit: " << phi_2 << " radians\n"
228  << "\t lower polar limit : " << theta_1 << " radians\n"
229  << "\t upper polar limit : " << theta_2 << " radians\n";
230 }
231 
232 
234 {
235  // Distance from the point x to the G4SphericalSurface.
236  // The distance will be positive if the point is Inside the
237  // G4SphericalSurface, negative if the point is outside.
238 
239  G4Vector3D d = G4Vector3D( x - origin );
240  G4double rds = d.mag();
241 
242  return (radius - rds);
243 }
244 
245 
246 /*
247 G4double G4SphericalSurface::distanceAlongRay( G4int which_way,
248  const G4Ray* ry,
249  G4Vector3D& p ) const
250 
251  // Distance along a Ray (straight line with G4Vector3D) to leave or enter
252  // a G4SphericalSurface. The input variable which_way should be set to +1 to
253  // indicate leaving a G4SphericalSurface, -1 to indicate entering the surface.
254  // p is the point of intersection of the Ray with the G4SphericalSurface.
255  // If the G4Vector3D of the Ray is opposite to that of the Normal to
256  // the G4SphericalSurface at the intersection point, it will not leave the
257  // G4SphericalSurface.
258  // Similarly, if the G4Vector3D of the Ray is along that of the Normal
259  // to the G4SphericalSurface at the intersection point, it will not enter the
260  // G4SphericalSurface.
261  // This method is called by all finite shapes sub-classed to
262  // G4SphericalSurface.
263  // Use the virtual function table to check if the intersection point
264  // is within the boundary of the finite shape.
265  // A negative result means no intersection.
266  // If no valid intersection point is found, set the distance
267  // and intersection point to large numbers.
268 
269 {
270  G4double Dist = kInfinity;
271  G4Vector3D lv ( kInfinity, kInfinity, kInfinity );
272  p = lv;
273 
274  // Origin and G4Vector3D unit vector of Ray.
275  //
276  G4Vector3D x = ry->Position( 0.0 );
277  G4Vector3D dhat = ry->Direction( 0.0 );
278  G4int isoln = 0, maxsoln = 2;
279 
280  // Array of solutions in distance along the Ray
281  //
282  G4double s[2];s[0] = -1.0; s[1]= -1.0 ;
283 
284  // Calculate the two solutions (quadratic equation)
285  //
286  G4Vector3D d = x - GetOrigin();
287  G4double radius = GetRadius();
288 
289  // Quit with no intersection if the radius of the G4SphericalSurface is zero
290  //
291  if ( radius <= 0.0 ) { return Dist; }
292 
293  G4double dsq = d * d;
294  G4double rsq = radius * radius;
295  G4double b = d * dhat;
296  G4double c = dsq - rsq;
297  G4double radical = b * b - c;
298 
299  // Quit with no intersection if the radical is negative
300  //
301  if ( radical < 0.0 ) { return Dist; }
302 
303  G4double root = std::sqrt( radical );
304  s[0] = -b + root;
305  s[1] = -b - root;
306 
307  // Order the possible solutions by increasing distance along the Ray
308  //
309  G4Sort_double( s, isoln, maxsoln-1 );
310 
311  // Now loop over each positive solution, keeping the first one (smallest
312  // distance along the Ray) which is within the boundary of the sub-shape
313  // and which also has the correct G4Vector3D with respect to the Normal to
314  // the G4SphericalSurface at the intersection point
315  //
316  for ( isoln = 0; isoln < maxsoln; isoln++ )
317  {
318  if ( s[isoln] >= 0.0 )
319  {
320  if ( s[isoln] >= kInfinity ) { return Dist; } // quit if too large
321  Dist = s[isoln];
322  p = ry->Position( Dist );
323  if ( ( ( dhat * Normal( p ) * which_way ) >= 0.0 )
324  && ( WithinBoundary( p ) == 1 ) ) { return Dist; }
325  }
326  }
327 
328  // Get here only if there was no solution within the boundary,
329  // reset distance and intersection point to large numbers
330 
331  p = lv;
332  return kInfinity;
333 }
334 */
335 
336 
338 {
339  G4double x_min = origin.x() - radius;
340  G4double y_min = origin.y() - radius;
341  G4double z_min = origin.z() - radius;
342  G4double x_max = origin.x() + radius;
343  G4double y_max = origin.y() + radius;
344  G4double z_max = origin.z() + radius;
345 
346  G4Point3D Min(x_min, y_min, z_min);
347  G4Point3D Max(x_max, y_max, z_max);
348  bbox = new G4BoundingBox3D( Min, Max);
349 }
350 
351 
353 {
354  // Distance along a Ray (straight line with G4Vector3D) to leave or enter
355  // a G4SphericalSurface. The input variable which_way should be set to +1
356  // to indicate leaving a G4SphericalSurface, -1 to indicate entering a
357  // G4SphericalSurface.
358  // p is the point of intersection of the Ray with the G4SphericalSurface.
359  // If the G4Vector3D of the Ray is opposite to that of the Normal to
360  // the G4SphericalSurface at the intersection point, it will not leave the
361  // G4SphericalSurface.
362  // Similarly, if the G4Vector3D of the Ray is along that of the Normal
363  // to the G4SphericalSurface at the intersection point, it will not enter
364  // the G4SphericalSurface.
365  // This method is called by all finite shapes sub-classed to
366  // G4SphericalSurface.
367  // Use the virtual function table to check if the intersection point
368  // is within the boundary of the finite shape.
369  // A negative result means no intersection.
370  // If no valid intersection point is found, set the distance
371  // and intersection point to large numbers.
372 
373  G4int which_way = (G4int)HowNear(ry.GetStart());
374 
375  if(!which_way) { which_way =-1; }
376  distance = kInfinity;
377 
378  G4Vector3D lv ( kInfinity, kInfinity, kInfinity );
379 
380  // p = lv;
381  //
382  closest_hit = lv;
383 
384  // Origin and G4Vector3D unit vector of Ray.
385  //
386  G4Vector3D x= G4Vector3D( ry.GetStart() );
387  G4Vector3D dhat = ry.GetDir();
388  G4int isoln = 0, maxsoln = 2;
389 
390  // Array of solutions in distance along the Ray
391  //
392  G4double ss[2];
393  ss[0] = -1.0 ;
394  ss[1] = -1.0 ;
395 
396  // Calculate the two solutions (quadratic equation)
397  //
398  G4Vector3D d = G4Vector3D( x - GetOrigin() );
399  G4double r = GetRadius();
400 
401  // Quit with no intersection if the radius of the G4SphericalSurface is zero
402  //
403  if ( r <= 0.0 ) { return 0; }
404 
405  G4double dsq = d * d;
406  G4double rsq = r * r;
407  G4double b = d * dhat;
408  G4double c = dsq - rsq;
409  G4double radical = b * b - c;
410 
411  // Quit with no intersection if the radical is negative
412  //
413  if ( radical < 0.0 ) { return 0; }
414 
415  G4double root = std::sqrt( radical );
416  ss[0] = -b + root;
417  ss[1] = -b - root;
418 
419  // Order the possible solutions by increasing distance along the Ray
420  // G4Sort_double( ss, isoln, maxsoln-1 );
421  //
422  if(ss[0] > ss[1])
423  {
424  G4double tmp =ss[0];
425  ss[0] = ss[1];
426  ss[1] = tmp;
427  }
428 
429  // Now loop over each positive solution, keeping the first one (smallest
430  // distance along the Ray) which is within the boundary of the sub-shape
431  // and which also has the correct G4Vector3D with respect to the Normal to
432  // the G4SphericalSurface at the intersection point
433  //
434  for ( isoln = 0; isoln < maxsoln; isoln++ )
435  {
436  if ( ss[isoln] >= kCarTolerance*0.5 )
437  {
438  if ( ss[isoln] >= kInfinity ) { return 0; } // quit if too large
439  distance = ss[isoln];
440  closest_hit = ry.GetPoint( distance );
441  if ( ( ( dhat * Normal( closest_hit ) * which_way ) >= 0.0 ) &&
442  ( WithinBoundary( closest_hit ) == 1 ) )
443  {
445  return 1;
446  }
447  }
448  }
449 
450  // Get here only if there was no solution within the boundary,
451  // reset distance and intersection point to large numbers
452  //
453  distance = kInfinity;
454  closest_hit = lv;
455 
456  return 0;
457 }
458 
459 
460 /*
461 G4double G4SphericalSurface::distanceAlongHelix( G4int which_way,
462  const Helix* hx,
463  G4Vector3D& p ) const
464 {
465  // Distance along a Helix to leave or enter a G4SphericalSurface.
466  // The input variable which_way should be set to +1 to
467  // indicate leaving a G4SphericalSurface, -1 to indicate entering a
468  // G4SphericalSurface.
469  // p is the point of intersection of the Helix with the G4SphericalSurface.
470  // If the G4Vector3D of the Helix is opposite to that of the Normal to
471  // the G4SphericalSurface at the intersection point, it will not leave the
472  // G4SphericalSurface.
473  // Similarly, if the G4Vector3D of the Helix is along that of the Normal
474  // to the G4SphericalSurface at the intersection point, it will not enter
475  // the G4SphericalSurface.
476  // This method is called by all finite shapes sub-classed to
477  // G4SphericalSurface.
478  // Use the virtual function table to check if the intersection point
479  // is within the boundary of the finite shape.
480  // If no valid intersection point is found, set the distance
481  // and intersection point to large numbers.
482  // Possible negative distance solutions are discarded.
483 
484 {
485  G4double Dist = kInfinity;
486  G4Vector3D lv ( kInfinity, kInfinity, kInfinity );
487  p = lv;
488  G4int isoln = 0, maxsoln = 4;
489 
490  // Array of solutions in turning angle
491  //
492  G4double s[4];s[0] = -1.0; s[1]= -1.0 ;s[2] = -1.0; s[3]= -1.0 ;
493 
494  // Helix parameters
495  //
496  G4double rh = hx->GetRadius(); // radius of Helix
497  G4Vector3D oh = hx->position( 0.0 ); // origin of Helix
498  G4Vector3D dh = hx->direction( 0.0 ); // initial G4Vector3D of Helix
499  G4Vector3D prp = hx->getPerp(); // perpendicular vector
500  G4double prpmag = prp.mag();
501  G4double rhp = rh / prpmag;
502  G4double rs = GetRadius(); // radius of G4SphericalSurface
503  if ( rs == 0.0 ) { return Dist; } // quit if zero radius
504  G4Vector3D os = GetOrigin(); // origin of G4SphericalSurface
505 
506  // Calculate quantities of use later on
507  //
508  G4Vector3D alpha = rhp * prp;
509  G4Vector3D beta = rhp * dh;
510  G4Vector3D gamma = oh - os;
511 
512  // Only consider approximate solutions to quadratic order in the turning
513  // angle along the Helix
514  //
515  G4double A = beta * beta + gamma * alpha;
516  G4double B = 2.0 * gamma * beta;
517  G4double C = gamma * gamma - rs * rs;
518 
519  // Case if quadratic term is zero
520  //
521  if ( std::fabs( A ) < kCarTolerance )
522  {
523  if ( B == 0.0 ) { return Dist; } // no intersection, quit
524  else { s[0] = -C / B; }
525  }
526  else // General quadratic solution, A != 0
527  {
528  G4double radical = B * B - 4.0 * A * C;
529  if ( radical < 0.0 ) { return Dist; } // no intersection, quit
530 
531  G4double root = std::sqrt( radical );
532  s[0] = ( -B + root ) / ( 2.0 * A );
533  s[1] = ( -B - root ) / ( 2.0 * A );
534  if ( rh < 0.0 )
535  {
536  s[0] = -s[0];
537  s[1] = -s[1];
538  }
539  s[2] = s[0] + twopi;
540  s[3] = s[1] + twopi;
541  }
542 
543  // Order the possible solutions by increasing turning angle
544  //
545  G4Sort_double( s, isoln, maxsoln-1 );
546 
547  // Now loop over each positive solution, keeping the first one (smallest
548  // distance along the Helix) which is within the boundary of the sub-shape.
549  //
550  for ( isoln = 0; isoln < maxsoln; isoln++ )
551  {
552  if ( s[isoln] >= 0.0 )
553  {
554  // Calculate distance along Helix and position and G4Vector3D vectors.
555  //
556  Dist = s[isoln] * std::fabs( rhp );
557  p = hx->position( Dist );
558  G4Vector3D d = hx->direction( Dist );
559 
560  // Now do approximation to get remaining distance to correct this
561  // solution iterate it until the accuracy is below the user-set
562  // surface precision
563  //
564  G4double delta = 0.;
565  G4double delta0 = kInfinity;
566  G4int dummy = 1;
567  G4int iter = 0;
568  G4int in0 = Inside( hx->position ( 0.0 ) );
569  G4int in1 = Inside( p );
570  G4double sc = Scale();
571  while ( dummy )
572  {
573  iter++;
574 
575  // Terminate loop after 50 iterations and Reset distance to large
576  // number, indicating no intersection with G4SphericalSurface. This
577  // generally occurs if the Helix curls too tightly to intersect it.
578  //
579  if ( iter > 50 )
580  {
581  Dist = kInfinity;
582  p = lv;
583  break;
584  }
585 
586  // Find distance from the current point along the above-calculated
587  // G4Vector3D using a Ray.
588  // The G4Vector3D of the Ray and the Sign of the distance are
589  // determined by whether the starting point of the Helix is Inside
590  // or outside of the G4SphericalSurface.
591  //
592  in1 = Inside( p );
593  if ( in1 ) // current point Inside
594  {
595  if ( in0 ) // starting point Inside
596  {
597  Ray* r = new Ray( p, d );
598  delta = distanceAlongRay( 1, r, p );
599  delete r;
600  }
601  else // starting point outside
602  {
603  Ray* r = new Ray( p, -d );
604  delta = -distanceAlongRay( 1, r, p );
605  delete r;
606  }
607  }
608  else // current point outside
609  {
610  if ( in0 ) // starting point Inside
611  {
612  Ray* r = new Ray( p, -d );
613  delta = -distanceAlongRay( -1, r, p );
614  delete r;
615  }
616  else // starting point outside
617  {
618  Ray* r = new Ray( p, d );
619  delta = distanceAlongRay( -1, r, p );
620  delete r;
621  }
622  }
623 
624  // Test if distance is less than the surface precision, if so
625  // terminate loop.
626  //
627  if ( std::fabs( delta / sc ) <= SURFACE_PRECISION ) { break; }
628 
629  // If delta has not changed sufficiently from the previous iteration,
630  // skip out of this loop.
631  //
632  if (std::fabs( ( delta-delta0 )/sc ) <= SURFACE_PRECISION) { break; }
633 
634  // If delta has increased in absolute value from the previous iteration
635  // either the Helix doesn't Intersect the G4SphericalSurface or the
636  // approximate solution is too far from the real solution. Try groping
637  // for a solution. If not found, Reset distance to large number,
638  // indicating no intersection with the G4SphericalSurface.
639  //
640  if ( ( std::fabs( delta ) > std::fabs( delta0 ) ) )
641  {
642  Dist = std::fabs( rhp ) * gropeAlongHelix( hx );
643  if ( Dist < 0.0 )
644  {
645  Dist = kInfinity;
646  p = lv;
647  }
648  else
649  {
650  p = hx->position( Dist );
651  }
652  break;
653  }
654 
655  // Set old delta to new one.
656  //
657  delta0 = delta;
658 
659  // Add distance to G4SphericalSurface to distance along Helix.
660  //
661  Dist += delta;
662 
663  // Negative distance along Helix means Helix doesn't Intersect
664  // G4SphericalSurface. Reset distance to large number, indicating
665  // no intersection with G4SphericalSurface.
666  //
667  if ( Dist < 0.0 )
668  {
669  Dist = kInfinity;
670  p = lv;
671  break;
672  }
673 
674  // Recalculate point along Helix and the G4Vector3D.
675  //
676  p = hx->position( Dist );
677  d = hx->direction( Dist );
678  } // end of while loop
679 
680  // Now have best value of distance along Helix and position for this
681  // solution, so test if it is within the boundary of the sub-shape
682  // and require that it point in the correct G4Vector3D with respect to
683  // the Normal to the G4SphericalSurface.
684 
685  if ( ( Dist < kInfinity ) &&
686  ( ( hx->direction( Dist ) * Normal( p ) * which_way ) >= 0.0 )
687  && ( WithinBoundary( p ) == 1 ) ) { return Dist; }
688  } // end of if s[isoln] >= 0.0 condition
689  } // end of for loop over solutions
690 
691  // If one gets here, there is no solution, so set distance along Helix
692  // and position to large numbers.
693  //
694  Dist = kInfinity;
695  p = lv;
696 
697  return Dist;
698 }
699 
700 
701 G4Vector3D G4SphericalSurface::Normal( const G4Vector3D& p ) const
702 {
703  // Return the Normal unit vector to the G4SphericalSurface at a point p on
704  // (or nearly on) the G4SphericalSurface.
705 
706  G4Vector3D n = p - origin;
707  G4double nmag = n.mag();
708 
709  // If the point p happens to coincide with the origin (which is possible
710  // if the radius is zero), set the Normal to the z-axis unit vector.
711  //
712  if ( nmag != 0.0 ) { n = n / nmag; }
713  else { n = G4Vector3D( 0.0, 0.0, 1.0 ); }
714 
715  return n;
716 }
717 */
718 
719 
721 {
722  // Return the Normal unit vector to the G4SphericalSurface at a point p on
723  // (or nearly on) the G4SphericalSurface.
724 
725  G4Vector3D n = G4Vector3D( p - origin );
726  G4double nmag = n.mag();
727 
728  // If the point p happens to coincide with the origin (which is possible
729  // if the radius is zero), set the Normal to the z-axis unit vector.
730  //
731  if ( nmag != 0.0 ) { n = n * (1/ nmag); }
732  else { n = G4Vector3D( 0.0, 0.0, 1.0 ); }
733 
734  return n;
735 }
736 
737 
739 {
740  // Return the Normal unit vector to the G4SphericalSurface at a point p on
741  // (or nearly on) the G4SphericalSurface.
742 
743  G4Vector3D n = G4Vector3D( p - origin );
744  G4double nmag = n.mag();
745 
746  // If the point p happens to coincide with the origin (which is possible
747  // if the radius is zero), set the Normal to the z-axis unit vector.
748  //
749  if ( nmag != 0.0 ) { n = n * (1/ nmag); }
750  else { n = G4Vector3D( 0.0, 0.0, 1.0 ); }
751 
752  return n;
753 }
754 
755 
757 {
758  // Return 0 if point x is outside G4SphericalSurface, 1 if Inside.
759  // Outside means that the distance to the G4SphericalSurface would
760  // be negative.
761  // Use the HowNear function to calculate this distance.
762 
763  if ( HowNear( x ) >= 0.0 ) { return 1; }
764  else { return 0; }
765 }
766 
767 
769 {
770  // Return 1 if point x is on the G4SphericalSurface, otherwise return zero
771  // (x is assumed to lie on the surface of the G4SphericalSurface, so one
772  // only checks the angular limits)
773 
774  G4Vector3D y_axis = G4Vector3D( z_axis.cross( x_axis ) );
775 
776  // Components of x in the local coordinate system of the G4SphericalSurface
777  //
778  G4double px = x * x_axis;
779  G4double py = x * y_axis;
780  G4double pz = x * z_axis;
781 
782  // Check if within polar angle limits
783  //
784  G4double theta = std::acos( pz / x.mag() ); // acos in range 0 to PI
785 
786  // Normal case
787  //
788  if ( theta_2 <= pi )
789  {
790  if ( ( theta < theta_1 ) || ( theta > theta_2 ) ) { return 0; }
791  }
792  else
793  {
794  theta += pi;
795  if ( ( theta < theta_1 ) || ( theta > theta_2 ) ) { return 0; }
796  }
797 
798  // Now check if within azimuthal angle limits
799  //
800  G4double phi = std::atan2( py, px ); // atan2 in range -PI to PI
801 
802  if ( phi < 0.0 ) { phi += twopi; }
803 
804  // Normal case
805  //
806  if ( ( phi >= phi_1 ) && ( phi <= phi_2 ) ) { return 1; }
807 
808  // This is for the case that phi_2 is greater than 2*PI
809  //
810  phi += twopi;
811 
812  if ( ( phi >= phi_1 ) && ( phi <= phi_2 ) ) { return 1; }
813 
814  // Get here if not within azimuthal limits
815 
816  return 0;
817 }
818 
819 
821 {
822  // Returns the radius of a G4SphericalSurface unless it is zero, in which
823  // case returns the arbitrary number 1.0.
824  // Used for Scale-invariant tests of surface thickness.
825 
826  if ( radius == 0.0 ) { return 1.0; }
827  else { return radius; }
828 }
829 
830 
832 {
833  // Returns the Area of a G4SphericalSurface
834 
835  return ( 2.0*( theta_2 - theta_1 )*( phi_2 - phi_1)*radius*radius/pi );
836 }
837 
838 
840  G4double ph1, G4double ph2,
841  G4double th1, G4double th2 )
842 {
843  // Resize the G4SphericalSurface to new radius r, new lower and upper
844  // azimuthal angle limits ph1 and ph2, and new lower and upper polar
845  // angle limits th1 and th2.
846 
847  // Require radius to be non-negative
848  //
849  if ( r >= 0.0 ) { radius = r; }
850  else
851  {
852  std::ostringstream message;
853  message << "Radius cannot be less than zero." << G4endl
854  << "Original value of " << radius << " is retained.";
855  G4Exception("G4SphericalSurface::resize()",
856  "GeomSolids1001", JustWarning, message);
857  }
858 
859  // Require azimuthal angles to be within bounds
860 
861  if ( ( ph1 >= 0.0 ) && ( ph1 < twopi ) ) { phi_1 = ph1; }
862  else
863  {
864  std::ostringstream message;
865  message << "Lower azimuthal limit out of range." << G4endl
866  << "Original value of " << phi_1 << " is retained.";
867  G4Exception("G4SphericalSurface::resize()",
868  "GeomSolids1001", JustWarning, message);
869  }
870 
871  if ( ( ph2 > phi_1 ) && ( ph2 <= ( phi_1 + twopi ) ) ) { phi_2 = ph2; }
872  else
873  {
874  ph2 = ( phi_2 <= phi_1 ) ? ( phi_1 + kAngTolerance ) : phi_2;
875  phi_2 = ph2;
876  std::ostringstream message;
877  message << "Upper azimuthal limit out of range." << G4endl
878  << "Value of " << phi_2 << " is used.";
879  G4Exception("G4SphericalSurface::resize()",
880  "GeomSolids1001", JustWarning, message);
881  }
882 
883  // Require polar angles to be within bounds
884  //
885  if ( ( th1 >= 0.0 ) && ( th1 < pi ) ) { theta_1 = th1; }
886  else
887  {
888  std::ostringstream message;
889  message << "Lower polar limit out of range." << G4endl
890  << "Original value of " << theta_1 << " is retained.";
891  G4Exception("G4SphericalSurface::resize()",
892  "GeomSolids1001", JustWarning, message);
893  }
894 
895  if ( ( th2 > theta_1 ) && ( th2 <= ( theta_1 + pi ) ) ) { theta_2 = th2; }
896  else
897  {
898  th2 = ( theta_2 <= theta_1 ) ? ( theta_1 + kAngTolerance ) : theta_2;
899  theta_2 = th2;
900  std::ostringstream message;
901  message << "Upper polar limit out of range." << G4endl
902  << "Value of " << theta_2 << " is used.";
903  G4Exception("G4SphericalSurface::resize()",
904  "GeomSolids1001", JustWarning, message);
905  }
906 }
907 
908 
909 /*
910 void G4SphericalSurface::
911 rotate( G4double alpha, G4double beta,
912  G4double gamma, G4ThreeMat& m, G4int inverse )
913 {
914  // Rotate G4SphericalSurface first about global x_axis by angle alpha,
915  // second about global y-axis by angle beta,
916  // and third about global z_axis by angle gamma
917  // by creating and using G4ThreeMat objects in Surface::rotate
918  // angles are assumed to be given in radians
919  // if inverse is non-zero, the order of rotations is reversed
920  // the axis is rotated here, the origin is rotated by calling
921  // Surface::rotate
922 
923  G4Surface::rotate( alpha, beta, gamma, m, inverse );
924  x_axis = m * x_axis;
925  z_axis = m * z_axis;
926 }
927 
928 
929 void G4SphericalSurface::
930 rotate( G4double alpha, G4double beta, G4double gamma, G4int inverse )
931 {
932  // Rotate G4SphericalSurface first about global x_axis by angle alpha,
933  // second about global y-axis by angle beta,
934  // and third about global z_axis by angle gamma
935  // by creating and using G4ThreeMat objects in Surface::rotate
936  // angles are assumed to be given in radians
937  // if inverse is non-zero, the order of rotations is reversed
938  // the axis is rotated here, the origin is rotated by calling
939  // Surface::rotate
940 
941  G4ThreeMat m;
942  G4Surface::rotate( alpha, beta, gamma, m, inverse );
943  x_axis = m * x_axis;
944  z_axis = m * z_axis;
945 }
946 */
947 
948 
949 /*
950 G4double G4SphericalSurface::gropeAlongHelix( const Helix* hx ) const
951 {
952  // Grope for a solution of a Helix intersecting a G4SphericalSurface.
953  // This function returns the turning angle (in radians) where the
954  // intersection occurs with only positive values allowed, or -1.0 if
955  // no intersection is found.
956  // The idea is to start at the beginning of the Helix, then take steps
957  // of some fraction of a turn. If at the end of a Step, the current position
958  // along the Helix and the previous position are on opposite sides of the
959  // G4SphericalSurface, then the solution must lie somewhere in between.
960 
961  G4int one_over_f = 8; // one over fraction of a turn to go in each Step
962  G4double turn_angle = 0.0;
963  G4double dist_along = 0.0;
964  G4double d_new;
965  G4double fk = 1.0 / G4double( one_over_f );
966  G4double scal = Scale();
967  G4double d_old = HowNear( hx->position( dist_along ) );
968  G4double rh = hx->GetRadius(); // radius of Helix
969  G4Vector3D prp = hx->getPerp(); // perpendicular vector
970  G4double prpmag = prp.mag();
971  G4double rhp = rh / prpmag;
972  G4int max_iter = one_over_f * HELIX_MAX_TURNS;
973 
974  // Take up to a user-settable number of turns along the Helix,
975  // groping for an intersection point.
976 
977  for ( G4int k = 1; k < max_iter; k++ )
978  {
979  turn_angle = twopi * k / one_over_f;
980  dist_along = turn_angle * std::fabs( rhp );
981  d_new = HowNear( hx->position( dist_along ) );
982  if ( ( d_old < 0.0 && d_new > 0.0 ) || ( d_old > 0.0 && d_new < 0.0 ) )
983  {
984  d_old = d_new;
985 
986  // Old and new points are on opposite sides of the G4SphericalSurface,
987  // therefore a solution lies in between, use a binary search to pin the
988  // point down to the surface precision, but don't do more than 50
989  // iterations.
990 
991  G4int itr = 0;
992  while ( std::fabs( d_new / scal ) > SURFACE_PRECISION )
993  {
994  itr++;
995  if ( itr > 50 ) { return turn_angle; }
996  turn_angle -= fk * pi;
997  dist_along = turn_angle * std::fabs( rhp );
998  d_new = HowNear( hx->position( dist_along ) );
999  if (( d_old < 0.0 && d_new > 0.0 ) || ( d_old > 0.0 && d_new < 0.0 ))
1000  { fk *= -0.5; }
1001  else
1002  { fk *= 0.5; }
1003  d_old = d_new;
1004  } // end of while loop
1005  return turn_angle; // this is the best solution
1006  } // end of if condition
1007  } // end of for loop
1008 
1009  // Get here only if no solution is found, so return -1.0 to indicate that.
1010 
1011  return -1.0;
1012 }
1013 */