source: trunk/source/geometry/solids/BREPS/src/G4ConicalSurface.cc @ 1119

Last change on this file since 1119 was 1058, checked in by garnier, 15 years ago

file release beta

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