Geant4 9.6.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
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
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
107G4CylindricalSurface::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
118{
119 return "G4CylindricalSurface";
120}
121
122void 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];
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/*
259G4double G4CylindricalSurface::
260distanceAlongRay( 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
356G4double G4CylindricalSurface::
357distanceAlongHelix( 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/*
907void G4CylindricalSurface::
908rotate( 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
924void G4CylindricalSurface::
925rotate( 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/*
959G4double 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*/
@ JustWarning
#define SURFACE_PRECISION
Definition: G4Globals.hh:47
void sort_double(G4double[], G4int, G4int)
Definition: G4Sort.cc:39
double G4double
Definition: G4Types.hh:64
int G4int
Definition: G4Types.hh:66
HepGeom::Vector3D< G4double > G4Vector3D
Definition: G4Vector3D.hh:35
#define G4endl
Definition: G4ios.hh:52
G4Vector3D GetAxis() const
virtual void PrintOn(std::ostream &os=G4cout) const
virtual G4int Inside(const G4Vector3D &x) const
virtual G4double Scale() const
virtual G4Vector3D SurfaceNormal(const G4Point3D &p) const
virtual const char * NameOf() const
G4int Intersect(const G4Ray &ry)
virtual G4Vector3D Normal(const G4Vector3D &p) const
G4double GetRadius() const
virtual G4int WithinBoundary(const G4Vector3D &x) const
virtual G4double HowNear(const G4Vector3D &x) const
Definition: G4Ray.hh:49
G4Point3D GetPoint(G4double i) const
const G4Vector3D & GetDir() const
const G4Point3D & GetStart() const
G4Vector3D origin
Definition: G4Surface.hh:197
G4double distance
Definition: G4Surface.hh:203
G4Vector3D GetOrigin() const
G4Point3D closest_hit
Definition: G4Surface.hh:186
G4double kCarTolerance
Definition: G4Surface.hh:192
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *comments)
Definition: G4Exception.cc:41