Geant4 9.6.0
Toolkit for the simulation of the passage of particles through matter
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
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"
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
104G4ConicalSurface::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
114const char* G4ConicalSurface::NameOf() const
115{
116 return "G4ConicalSurface";
117}
118
120{
123}
124
125void 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];
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
@ 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
G4Point3D GetBoxMin() const
G4Point3D GetBoxMax() const
virtual void PrintOn(std::ostream &os=G4cout) const
G4int Intersect(const G4Ray &ry)
virtual G4Vector3D SurfaceNormal(const G4Point3D &p) const
virtual G4int WithinBoundary(const G4Vector3D &x) const
virtual G4int Inside(const G4Vector3D &x) const
virtual G4double HowNear(const G4Vector3D &x) const
G4Vector3D GetAxis() const
G4double GetAngle() const
virtual ~G4ConicalSurface()
void SetAngle(G4double e)
virtual G4double Scale() const
virtual const char * NameOf() const
Definition: G4Ray.hh:49
G4Point3D GetPoint(G4double i) const
const G4Vector3D & GetDir() const
const G4Point3D & GetStart() const
const G4BoundingBox3D & BBox() const
G4Vector3D origin
Definition: G4Surface.hh:197
G4double distance
Definition: G4Surface.hh:203
G4BoundingBox3D * bbox
Definition: G4Surface.hh:185
G4Vector3D GetOrigin() const
G4Point3D closest_hit
Definition: G4Surface.hh:186
G4SurfaceBoundary surfaceBoundary
Definition: G4Surface.hh:189
G4double kCarTolerance
Definition: G4Surface.hh:192
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *comments)
Definition: G4Exception.cc:41