Geant4 9.6.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
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