source: trunk/source/geometry/solids/BREPS/src/G4CylindricalSurface.cc @ 1337

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

tag geant4.9.4 beta 1 + modifs locales

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