Geant4  9.6.p02
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4ConicalSurface.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 // G4ConicalSurface.cc
33 //
34 // ----------------------------------------------------------------------
35 
36 #include "G4ConicalSurface.hh"
37 #include "G4PhysicalConstants.hh"
38 #include "G4Sort.hh"
39 #include "G4Globals.hh"
40 
41 
43  : G4Surface(), axis(G4Vector3D(1.,0.,0.)), angle(1.)
44 {
45 }
46 
48  const G4Vector3D& a,
49  G4double e )
50  : G4Surface()
51 {
52  // Normal constructor
53  // require axis to be a unit vector
54 
55  G4double amag = a.mag2();
56 
57  if ( amag != 0.0 )
58  {
59  axis = a*(1/amag);
60  }
61  else
62  {
63  std::ostringstream message;
64  message << "Axis has zero length." << G4endl
65  << "Default axis ( 1.0, 0.0, 0.0 ) is used.";
66  G4Exception("G4ConicalSurface::G4ConicalSurface()", "GeomSolids1001",
67  JustWarning, message);
68 
69  axis = G4Vector3D( 1.0, 0.0, 0.0 );
70  }
71 
72  // Require angle to range from 0 to PI/2
73  //
74  if ( ( e > 0.0 ) && ( e < ( 0.5 * pi ) ) )
75  {
76  angle = e;
77  }
78  else
79  {
80  std::ostringstream message;
81  message << "Angle out of range." << G4endl
82  << "Asked for angle out of allowed range of 0 to "
83  << 0.5*pi << " (PI/2): " << e << G4endl
84  << "Default angle of 1.0 is used.";
85  G4Exception("G4ConicalSurface::G4ConicalSurface()", "GeomSolids1001",
86  JustWarning, message);
87  angle = 1.0;
88  }
89 }
90 
91 
93 {
94 }
95 
96 
98  : G4Surface(), axis(c.axis), angle(c.angle)
99 {
100 }
101 
102 
104 G4ConicalSurface::operator=( const G4ConicalSurface& c )
105 {
106  if (&c == this) { return *this; }
107  axis = c.axis;
108  angle = c.angle;
109 
110  return *this;
111 }
112 
113 
114 const char* G4ConicalSurface::NameOf() const
115 {
116  return "G4ConicalSurface";
117 }
118 
120 {
123 }
124 
125 void G4ConicalSurface::PrintOn( std::ostream& os ) const
126 {
127  // printing function using C++ std::ostream class
128 
129  os << "G4ConicalSurface surface with origin: " << origin << "\t"
130  << "angle: " << angle << " radians \tand axis " << axis << "\n";
131 }
132 
133 
135 {
136  // Distance from the point x to the semi-infinite G4ConicalSurface.
137  // The distance will be positive if the point is Inside the G4ConicalSurface,
138  // negative if the point is outside.
139  // Note that this may not be correct for a bounded conical object
140  // subclassed to G4ConicalSurface.
141 
142  G4Vector3D d = G4Vector3D( x - origin );
143  G4double l = d * axis;
144  G4Vector3D q = G4Vector3D( origin + l * axis );
145  G4Vector3D v = G4Vector3D( x - q );
146 
147  G4double Dist = ( l*std::tan(angle) - v.mag2() ) * std::cos(angle);
148 
149  return Dist;
150 }
151 
152 
154 {
155  // Distance along a Ray (straight line with G4Vector3D) to leave or enter
156  // a G4ConicalSurface. The input variable which_way should be set to +1 to
157  // indicate leaving a G4ConicalSurface, -1 to indicate entering a
158  // G4ConicalSurface.
159  // p is the point of intersection of the Ray with the G4ConicalSurface.
160  // If the G4Vector3D of the Ray is opposite to that of the Normal to
161  // the G4ConicalSurface at the intersection point, it will not leave the
162  // G4ConicalSurface.
163  // Similarly, if the G4Vector3D of the Ray is along that of the Normal
164  // to the G4ConicalSurface at the intersection point, it will not enter the
165  // G4ConicalSurface.
166  // This method is called by all finite shapes sub-classed to
167  // G4ConicalSurface.
168  // Use the virtual function table to check if the intersection point
169  // is within the boundary of the finite shape.
170  // A negative result means no intersection.
171  // If no valid intersection point is found, set the distance
172  // and intersection point to large numbers.
173 
174  G4int which_way = -1; // Originally a parameter.Read explanation above.
175 
176  distance = kInfinity;
177 
178  G4Vector3D lv ( kInfinity, kInfinity, kInfinity );
179  closest_hit = lv;
180 
181  // Origin and G4Vector3D unit vector of Ray.
182  //
183  G4Vector3D x = G4Vector3D( ry.GetStart() );
184  G4Vector3D dhat = ry.GetDir();
185 
186 
187  // Cone angle and axis unit vector.
188  //
189  G4double ta = std::tan( GetAngle() );
190  G4Vector3D ahat = GetAxis();
191  G4int isoln = 0,
192  maxsoln = 2;
193 
194  // array of solutions in distance along the Ray
195  //
196  G4double sol[2];
197  sol[0] = -1.0;
198  sol[1] = -1.0 ;
199 
200  // calculate the two solutions (quadratic equation)
201  //
202  G4Vector3D gamma = G4Vector3D( x - GetOrigin() );
203  G4double T = 1.0 + ta * ta;
204  G4double ga = gamma * ahat;
205  G4double da = dhat * ahat;
206  G4double A = 1.0 - T * da * da;
207  G4double B = 2.0 * ( gamma * dhat - T * ga * da );
208  G4double C = gamma * gamma - T * ga * ga;
209 
210  // if quadratic term vanishes, just do the simple solution
211  //
212  if ( std::fabs( A ) < kCarTolerance )
213  {
214  if ( B == 0.0 )
215  { return 1; }
216  else
217  { sol[0] = -C / B; }
218  }
219 
220  // Normal quadratic case, no intersection if radical is less than zero
221  //
222  else
223  {
224  G4double radical = B * B - 4.0 * A * C;
225  if ( radical < 0.0 )
226  {
227  return 1;
228  }
229  else
230  {
231  G4double root = std::sqrt( radical );
232  sol[0] = ( - B + root ) / ( 2. * A );
233  sol[1] = ( - B - root ) / ( 2. * A );
234  }
235  }
236 
237  // order the possible solutions by increasing distance along the Ray
238  //
239  sort_double( sol, isoln, maxsoln-1 );
240 
241  // now loop over each positive solution, keeping the first one (smallest
242  // distance along the Ray) which is within the boundary of the sub-shape
243  // and which also has the correct G4Vector3D with respect to the Normal to
244  // the G4ConicalSurface at the intersection point
245  //
246  for ( isoln = 0; isoln < maxsoln; isoln++ )
247  {
248  if ( sol[isoln] >= 0.0 )
249  {
250  if ( sol[isoln] >= kInfinity ) // quit if too large
251  {
252  return 1;
253  }
254 
255  distance = sol[isoln];
256  closest_hit = ry.GetPoint( distance );
257 
258  // Following line necessary to select non-reflective solutions.
259  //
260  if (( ahat * ( closest_hit - GetOrigin() ) > 0.0 ) &&
261  ((( dhat * SurfaceNormal( closest_hit ) * which_way )) >= 0.0 ) &&
262  ( std::fabs(HowNear( closest_hit )) < 0.1) )
263  {
264  return 1;
265  }
266  }
267  }
268 
269  // get here only if there was no solution within the boundary, Reset
270  // distance and intersection point to large numbers
271  //
272  distance = kInfinity;
273  closest_hit = lv;
274 
275  return 0;
276 }
277 
278 
279 /*
280  G4double G4ConicalSurface::distanceAlongHelix(G4int which_way, const Helix* hx,
281  G4Vector3D& p ) const
282  { // Distance along a Helix to leave or enter a G4ConicalSurface.
283  // The input variable which_way should be set to +1 to
284  // indicate leaving a G4ConicalSurface, -1 to indicate entering a
285  // G4ConicalSurface.
286  // p is the point of intersection of the Helix with the G4ConicalSurface.
287  // If the G4Vector3D of the Helix is opposite to that of the Normal to
288  // the G4ConicalSurface at the intersection point, it will not leave the
289  // G4ConicalSurface.
290  // Similarly, if the G4Vector3D of the Helix is along that of the Normal
291  // to the G4ConicalSurface at the intersection point, it will not enter the
292  // G4ConicalSurface.
293  // This method is called by all finite shapes sub-classed to
294  // G4ConicalSurface.
295  // Use the virtual function table to check if the intersection point
296  // is within the boundary of the finite shape.
297  // If no valid intersection point is found, set the distance
298  // and intersection point to large numbers.
299  // Possible negative distance solutions are discarded.
300  G4double Dist = kInfinity;
301  G4Vector3D lv ( kInfinity, kInfinity, kInfinity );
302  p = lv;
303  G4int isoln = 0, maxsoln = 4;
304 
305  // Array of solutions in turning angle
306  // G4double s[4] = { -1.0, -1.0, -1.0, -1.0 };
307  G4double s[4];s[0] = -1.0; s[1]= -1.0 ;s[2] = -1.0; s[3]= -1.0 ;
308 
309  // Flag set to 1 if exact solution is found
310  G4int exact = 0;
311 
312  // Helix parameters
313  G4double rh = hx->GetRadius(); // radius of Helix
314  G4Vector3D oh = hx->position(); // origin of Helix
315  G4Vector3D dh = hx->direction( 0.0 ); // initial G4Vector3D of Helix
316  G4Vector3D prp = hx->getPerp(); // perpendicular vector
317  G4double prpmag = prp.Magnitude();
318  G4double rhp = rh / prpmag;
319 
320  // G4ConicalSurface parameters
321  G4double ta = std::tan( GetAngle() ); // tangent of angle of G4ConicalSurface
322  G4Vector3D oc = GetOrigin(); // origin of G4ConicalSurface
323  G4Vector3D ac = GetAxis(); // axis of G4ConicalSurface
324 
325  // Calculate quantities of use later on
326  G4Vector3D alpha = rhp * prp;
327  G4Vector3D beta = rhp * dh;
328  G4Vector3D gamma = oh - oc;
329  G4double T = 1.0 + ta * ta;
330  G4double gc = gamma * ac;
331  G4double bc = beta * ac;
332 
333  // General approximate solution for std::sin(s)-->s and std::cos(s)-->1-s**2/2,
334  // keeping only terms to second order in s
335  G4double A = gamma * alpha - T * ( gc * alpha * ac - bc * bc ) +
336  beta * beta;
337  G4double B = 2.0 * ( gamma * beta - gc * bc * T );
338  G4double C = gamma * gamma - gc * gc * T;
339 
340  // Solution for no quadratic term
341  if ( std::fabs( A ) < kCarTolerance )
342  {
343  if ( B == 0.0 )
344  return Dist;
345  else
346  s[0] = -C / B;
347  }
348 
349  // General quadratic solutions
350  else {
351  G4double radical = B * B - 4.0 * A * C;
352  if ( radical < 0.0 )
353  // Radical is less than zero, either there is no intersection, or the
354  // approximation doesn't hold, so try a cruder technique to find a
355  // possible intersection point using the gropeAlongHelix function.
356  s[0] = gropeAlongHelix( hx );
357  // Normal non-negative radical solutions
358  else {
359  G4double root = std::sqrt( radical );
360  s[0] = ( -B + root ) / ( 2.0 * A );
361  s[1] = ( -B - root ) / ( 2.0 * A );
362  if ( rh < 0.0 ) {
363  s[0] = -s[0];
364  s[1] = -s[1];
365  }
366  s[2] = s[0] + 2.0 * pi;
367  s[3] = s[1] + 2.0 * pi;
368  }
369  }
370  //
371  // Order the possible solutions by increasing turning angle
372  // (G4Sorting routines are in support/G4Sort.h).
373  G4Sort_double( s, isoln, maxsoln-1 );
374  //
375  // Now loop over each positive solution, keeping the first one (smallest
376  // distance along the Helix) which is within the boundary of the sub-shape.
377  for ( isoln = 0; isoln < maxsoln; isoln++ ) {
378  if ( s[isoln] >= 0.0 ) {
379  // Calculate distance along Helix and position and G4Vector3D vectors.
380  Dist = s[isoln] * std::fabs( rhp );
381  p = hx->position( Dist );
382  G4Vector3D d = hx->direction( Dist );
383  if ( exact == 0 ) { // only for approximate solns
384  // Now do approximation to get remaining distance to correct this solution.
385  // Iterate it until the accuracy is below the user-set surface precision.
386  G4double delta = 0.;
387  G4double delta0 = kInfinity;
388  G4int dummy = 1;
389  G4int iter = 0;
390  G4int in0 = Inside( hx->position() );
391  G4int in1 = Inside( p );
392  G4double sc = Scale();
393  while ( dummy ) {
394  iter++;
395  // Terminate loop after 50 iterations and Reset distance to large number,
396  // indicating no intersection with G4ConicalSurface.
397  // This generally occurs if the Helix curls too tightly to Intersect it.
398  if ( iter > 50 ) {
399  Dist = kInfinity;
400  p = lv;
401  break;
402  }
403  // Find distance from the current point along the above-calculated
404  // G4Vector3D using a Ray.
405  // The G4Vector3D of the Ray and the Sign of the distance are determined
406  // by whether the starting point of the Helix is Inside or outside of
407  // the G4ConicalSurface.
408  in1 = Inside( p );
409  if ( in1 ) { // current point Inside
410  if ( in0 ) { // starting point Inside
411  Ray* r = new Ray( p, d );
412  delta =
413  distanceAlongRay( 1, r, p );
414  delete r;
415  }
416  else { // starting point outside
417  Ray* r = new Ray( p, -d );
418  delta =
419  -distanceAlongRay( 1, r, p );
420  delete r;
421  }
422  }
423  else { // current point outside
424  if ( in0 ) { // starting point Inside
425  Ray* r = new Ray( p, -d );
426  delta =
427  -distanceAlongRay( -1, r, p );
428  delete r;
429  }
430  else { // starting point outside
431  Ray* r = new Ray( p, d );
432  delta =
433  distanceAlongRay( -1, r, p );
434  delete r;
435  }
436  }
437  // Test if distance is less than the surface precision, if so Terminate loop.
438  if ( std::fabs( delta / sc ) <= SURFACE_PRECISION )
439  break;
440  // If delta has not changed sufficiently from the previous iteration,
441  // skip out of this loop.
442  if ( std::fabs( ( delta - delta0 ) / sc ) <=
443  SURFACE_PRECISION )
444  break;
445  // If delta has increased in absolute value from the previous iteration
446  // either the Helix doesn't Intersect the G4ConicalSurface or the approximate solution
447  // is too far from the real solution. Try groping for a solution. If not
448  // found, Reset distance to large number, indicating no intersection with
449  // the G4ConicalSurface.
450  if ( std::fabs( delta ) > std::fabs( delta0 ) ) {
451  Dist = std::fabs( rhp ) *
452  gropeAlongHelix( hx );
453  if ( Dist < 0.0 ) {
454  Dist = kInfinity;
455  p = lv;
456  }
457  else
458  p = hx->position( Dist );
459  break;
460  }
461  // Set old delta to new one.
462  delta0 = delta;
463  // Add distance to G4ConicalSurface to distance along Helix.
464  Dist += delta;
465  // Negative distance along Helix means Helix doesn't Intersect G4ConicalSurface.
466  // Reset distance to large number, indicating no intersection with G4ConicalSurface.
467  if ( Dist < 0.0 ) {
468  Dist = kInfinity;
469  p = lv;
470  break;
471  }
472  // Recalculate point along Helix and the G4Vector3D.
473  p = hx->position( Dist );
474  d = hx->direction( Dist );
475  } // end of while loop
476  } // end of exact == 0 condition
477  // Now have best value of distance along Helix and position for this
478  // solution, so test if it is within the boundary of the sub-shape
479  // and require that it point in the correct G4Vector3D with respect to
480  // the Normal to the G4ConicalSurface.
481  if ( ( Dist < kInfinity ) &&
482  ( ( hx->direction( Dist ) * Normal( p ) *
483  which_way ) >= 0.0 ) &&
484  ( WithinBoundary( p ) == 1 ) )
485  return Dist;
486  } // end of if s[isoln] >= 0.0 condition
487  } // end of for loop over solutions
488  // If one gets here, there is no solution, so set distance along Helix
489  // and position to large numbers.
490  Dist = kInfinity;
491  p = lv;
492  return Dist;
493  }
494 */
495 
496 
498 {
499  // return the Normal unit vector to the G4ConicalSurface at a point p
500  // on (or nearly on) the G4ConicalSurface
501 
502  G4Vector3D ss = G4Vector3D( p - origin );
503  G4double smag = ss.mag2();
504 
505  // if the point happens to be at the origin, calculate a unit vector Normal
506  // to the axis, with zero z component
507  //
508  if ( smag == 0.0 )
509  {
510  G4double ax = axis.x();
511  G4double ay = axis.y();
512  G4double ap = std::sqrt( ax * ax + ay * ay );
513 
514  if ( ap == 0.0 )
515  { return G4Vector3D( 1.0, 0.0, 0.0 ); }
516  else
517  { return G4Vector3D( ay / ap, -ax / ap, 0.0 ); }
518  }
519  else // otherwise do the calculation of the Normal to the conical surface
520  {
521  G4double l = ss * axis;
522  ss = ss*(1/smag);
523  G4Vector3D q = G4Vector3D( origin + l * axis );
524  G4Vector3D v = G4Vector3D( p - q );
525  G4double sl = v.mag2() * std::sin( angle );
526  G4Vector3D n = G4Vector3D( v - sl * ss );
527  G4double nmag = n.mag2();
528 
529  if ( nmag != 0.0 )
530  {
531  n=n*(1/nmag);
532  }
533  return n;
534  }
535 }
536 
537 
539 {
540  // Return 0 if point x is outside G4ConicalSurface, 1 if Inside.
541  // Outside means that the distance to the G4ConicalSurface would be negative.
542  // Use the HowNear function to calculate this distance.
543 
544  if ( HowNear( x ) >= -0.5*kCarTolerance )
545  { return 1; }
546  else
547  { return 0; }
548 }
549 
550 
552 {
553  // return 1 if point x is on the G4ConicalSurface, otherwise return zero
554  // base this on the surface precision factor
555 
556  if ( std::fabs( HowNear( x ) / Scale() ) <= SURFACE_PRECISION )
557  { return 1; }
558  else
559  { return 0; }
560 }
561 
563 {
564  return 1.0;
565 }
566 
568 {
569  // Reset the angle of the G4ConicalSurface
570  // Require angle to range from 0 to PI/2
571 
572  if ( (e > 0.0) && (e <= ( 0.5 * pi )) )
573  {
574  angle = e;
575  }
576  else // use old value (do not change angle) if out of the range,
577  { // but print warning message
578  std::ostringstream message;
579  message << "Angle out of range." << G4endl
580  << "Asked for angle out of allowed range of 0 to "
581  << 0.5*pi << " (PI/2): " << e << G4endl
582  << "Default angle of " << angle << " is used.";
583  G4Exception("G4ConicalSurface::SetAngle()", "GeomSolids1001",
584  JustWarning, message);
585  }
586 }
587