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

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

update geant4.9.3 tag

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