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