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

Last change on this file since 1347 was 1337, checked in by garnier, 15 years ago

tag geant4.9.4 beta 1 + modifs locales

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