source: trunk/source/geometry/solids/BREPS/src/G4SphericalSurface.cc @ 1228

Last change on this file since 1228 was 1228, checked in by garnier, 14 years ago

update geant4.9.3 tag

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