source: trunk/source/geometry/solids/specific/src/G4EllipticalTube.cc@ 1316

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

update geant4.9.3 tag

File size: 22.6 KB
RevLine 
[831]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: G4EllipticalTube.cc,v 1.27 2006/10/20 13:45:21 gcosmo Exp $
[1228]28// GEANT4 tag $Name: geant4-09-03 $
[831]29//
30//
31// --------------------------------------------------------------------
32// GEANT 4 class source file
33//
34//
35// G4EllipticalTube.cc
36//
37// Implementation of a CSG volume representing a tube with elliptical cross
38// section (geant3 solid 'ELTU')
39//
40// --------------------------------------------------------------------
41
42#include "G4EllipticalTube.hh"
43
44#include "G4ClippablePolygon.hh"
45#include "G4AffineTransform.hh"
46#include "G4SolidExtentList.hh"
47#include "G4VoxelLimits.hh"
48#include "meshdefs.hh"
49
50#include "Randomize.hh"
51
52#include "G4VGraphicsScene.hh"
53#include "G4Polyhedron.hh"
54#include "G4VisExtent.hh"
55
56using namespace CLHEP;
57
58//
59// Constructor
60//
61G4EllipticalTube::G4EllipticalTube( const G4String &name,
62 G4double theDx,
63 G4double theDy,
64 G4double theDz )
65 : G4VSolid( name ), fCubicVolume(0.), fSurfaceArea(0.), fpPolyhedron(0)
66{
67 dx = theDx;
68 dy = theDy;
69 dz = theDz;
70}
71
72
73//
74// Fake default constructor - sets only member data and allocates memory
75// for usage restricted to object persistency.
76//
77G4EllipticalTube::G4EllipticalTube( __void__& a )
78 : G4VSolid(a), fCubicVolume(0.), fSurfaceArea(0.), fpPolyhedron(0)
79{
80}
81
82
83//
84// Destructor
85//
86G4EllipticalTube::~G4EllipticalTube()
87{
88 delete fpPolyhedron;
89}
90
91
92//
93// CalculateExtent
94//
95G4bool
96G4EllipticalTube::CalculateExtent( const EAxis axis,
97 const G4VoxelLimits &voxelLimit,
98 const G4AffineTransform &transform,
99 G4double &min, G4double &max ) const
100{
101 G4SolidExtentList extentList( axis, voxelLimit );
102
103 //
104 // We are going to divide up our elliptical face into small
105 // pieces
106 //
107
108 //
109 // Choose phi size of our segment(s) based on constants as
110 // defined in meshdefs.hh
111 //
112 G4int numPhi = kMaxMeshSections;
113 G4double sigPhi = twopi/numPhi;
114
115 //
116 // We have to be careful to keep our segments completely outside
117 // of the elliptical surface. To do so we imagine we have
118 // a simple (unit radius) circular cross section (as in G4Tubs)
119 // and then "stretch" the dimensions as necessary to fit the ellipse.
120 //
121 G4double rFudge = 1.0/std::cos(0.5*sigPhi);
122 G4double dxFudge = dx*rFudge,
123 dyFudge = dy*rFudge;
124
125 //
126 // As we work around the elliptical surface, we build
127 // a "phi" segment on the way, and keep track of two
128 // additional polygons for the two ends.
129 //
130 G4ClippablePolygon endPoly1, endPoly2, phiPoly;
131
132 G4double phi = 0,
133 cosPhi = std::cos(phi),
134 sinPhi = std::sin(phi);
135 G4ThreeVector v0( dxFudge*cosPhi, dyFudge*sinPhi, +dz ),
136 v1( dxFudge*cosPhi, dyFudge*sinPhi, -dz ),
137 w0, w1;
138 transform.ApplyPointTransform( v0 );
139 transform.ApplyPointTransform( v1 );
140 do
141 {
142 phi += sigPhi;
143 if (numPhi == 1) phi = 0; // Try to avoid roundoff
144 cosPhi = std::cos(phi),
145 sinPhi = std::sin(phi);
146
147 w0 = G4ThreeVector( dxFudge*cosPhi, dyFudge*sinPhi, +dz );
148 w1 = G4ThreeVector( dxFudge*cosPhi, dyFudge*sinPhi, -dz );
149 transform.ApplyPointTransform( w0 );
150 transform.ApplyPointTransform( w1 );
151
152 //
153 // Add a point to our z ends
154 //
155 endPoly1.AddVertexInOrder( v0 );
156 endPoly2.AddVertexInOrder( v1 );
157
158 //
159 // Build phi polygon
160 //
161 phiPoly.ClearAllVertices();
162
163 phiPoly.AddVertexInOrder( v0 );
164 phiPoly.AddVertexInOrder( v1 );
165 phiPoly.AddVertexInOrder( w1 );
166 phiPoly.AddVertexInOrder( w0 );
167
168 if (phiPoly.PartialClip( voxelLimit, axis ))
169 {
170 //
171 // Get unit normal
172 //
173 phiPoly.SetNormal( (v1-v0).cross(w0-v0).unit() );
174
175 extentList.AddSurface( phiPoly );
176 }
177
178 //
179 // Next vertex
180 //
181 v0 = w0;
182 v1 = w1;
183 } while( --numPhi > 0 );
184
185 //
186 // Process the end pieces
187 //
188 if (endPoly1.PartialClip( voxelLimit, axis ))
189 {
190 static const G4ThreeVector normal(0,0,+1);
191 endPoly1.SetNormal( transform.TransformAxis(normal) );
192 extentList.AddSurface( endPoly1 );
193 }
194
195 if (endPoly2.PartialClip( voxelLimit, axis ))
196 {
197 static const G4ThreeVector normal(0,0,-1);
198 endPoly2.SetNormal( transform.TransformAxis(normal) );
199 extentList.AddSurface( endPoly2 );
200 }
201
202 //
203 // Return min/max value
204 //
205 return extentList.GetExtent( min, max );
206}
207
208
209//
210// Inside
211//
212// Note that for this solid, we've decided to define the tolerant
213// surface as that which is bounded by ellipses with axes
214// at +/- 0.5*kCarTolerance.
215//
216EInside G4EllipticalTube::Inside( const G4ThreeVector& p ) const
217{
218 static const G4double halfTol = 0.5*kCarTolerance;
219
220 //
221 // Check z extents: are we outside?
222 //
223 G4double absZ = std::fabs(p.z());
224 if (absZ > dz+halfTol) return kOutside;
225
226 //
227 // Check x,y: are we outside?
228 //
229 // G4double x = p.x(), y = p.y();
230
231 if (CheckXY(p.x(), p.y(), +halfTol) > 1.0) return kOutside;
232
233 //
234 // We are either inside or on the surface: recheck z extents
235 //
236 if (absZ > dz-halfTol) return kSurface;
237
238 //
239 // Recheck x,y
240 //
241 if (CheckXY(p.x(), p.y(), -halfTol) > 1.0) return kSurface;
242
243 return kInside;
244}
245
246
247//
248// SurfaceNormal
249//
250G4ThreeVector G4EllipticalTube::SurfaceNormal( const G4ThreeVector& p ) const
251{
252 //
253 // Which of the three surfaces are we closest to (approximately)?
254 //
255 G4double distZ = std::fabs(p.z()) - dz;
256
257 G4double rxy = CheckXY( p.x(), p.y() );
258 G4double distR2 = (rxy < DBL_MIN) ? DBL_MAX : 1.0/rxy;
259
260 //
261 // Closer to z?
262 //
263 if (distZ*distZ < distR2)
264 return G4ThreeVector( 0.0, 0.0, p.z() < 0 ? -1.0 : 1.0 );
265
266 //
267 // Closer to x/y
268 //
269 return G4ThreeVector( p.x()*dy*dy, p.y()*dx*dx, 0.0 ).unit();
270}
271
272
273//
274// DistanceToIn(p,v)
275//
276// Unlike DistanceToOut(p,v), it is possible for the trajectory
277// to miss. The geometric calculations here are quite simple.
278// More difficult is the logic required to prevent particles
279// from sneaking (or leaking) between the elliptical and end
280// surfaces.
281//
282// Keep in mind that the true distance is allowed to be
283// negative if the point is currently on the surface. For oblique
284// angles, it can be very negative.
285//
286G4double G4EllipticalTube::DistanceToIn( const G4ThreeVector& p,
287 const G4ThreeVector& v ) const
288{
289 static const G4double halfTol = 0.5*kCarTolerance;
290
291 //
292 // Check z = -dz planer surface
293 //
294 G4double sigz = p.z()+dz;
295
296 if (sigz < halfTol)
297 {
298 //
299 // We are "behind" the shape in z, and so can
300 // potentially hit the rear face. Correct direction?
301 //
302 if (v.z() <= 0)
303 {
304 //
305 // As long as we are far enough away, we know we
306 // can't intersect
307 //
308 if (sigz < 0) return kInfinity;
309
310 //
311 // Otherwise, we don't intersect unless we are
312 // on the surface of the ellipse
313 //
314 if (CheckXY(p.x(),p.y(),-halfTol) <= 1.0) return kInfinity;
315 }
316 else
317 {
318 //
319 // How far?
320 //
321 G4double s = -sigz/v.z();
322
323 //
324 // Where does that place us?
325 //
326 G4double xi = p.x() + s*v.x(),
327 yi = p.y() + s*v.y();
328
329 //
330 // Is this on the surface (within ellipse)?
331 //
332 if (CheckXY(xi,yi) <= 1.0)
333 {
334 //
335 // Yup. Return s, unless we are on the surface
336 //
337 return (sigz < -halfTol) ? s : 0;
338 }
339 else if (xi*dy*dy*v.x() + yi*dx*dx*v.y() >= 0)
340 {
341 //
342 // Else, if we are traveling outwards, we know
343 // we must miss
344 //
345 return kInfinity;
346 }
347 }
348 }
349
350 //
351 // Check z = +dz planer surface
352 //
353 sigz = p.z() - dz;
354
355 if (sigz > -halfTol)
356 {
357 if (v.z() >= 0)
358 {
359 if (sigz > 0) return kInfinity;
360 if (CheckXY(p.x(),p.y(),-halfTol) <= 1.0) return kInfinity;
361 }
362 else {
363 G4double s = -sigz/v.z();
364
365 G4double xi = p.x() + s*v.x(),
366 yi = p.y() + s*v.y();
367
368 if (CheckXY(xi,yi) <= 1.0)
369 {
370 return (sigz > -halfTol) ? s : 0;
371 }
372 else if (xi*dy*dy*v.x() + yi*dx*dx*v.y() >= 0)
373 {
374 return kInfinity;
375 }
376 }
377 }
378
379 //
380 // Check intersection with the elliptical tube
381 //
382 G4double s[2];
383 G4int n = IntersectXY( p, v, s );
384
385 if (n==0) return kInfinity;
386
387 //
388 // Is the original point on the surface?
389 //
390 if (std::fabs(p.z()) < dz+halfTol) {
391 if (CheckXY( p.x(), p.y(), halfTol ) < 1.0)
392 {
393 //
394 // Well, yes, but are we traveling inwards at this point?
395 //
396 if (p.x()*dy*dy*v.x() + p.y()*dx*dx*v.y() < 0) return 0;
397 }
398 }
399
400 //
401 // We are now certain that point p is not on the surface of
402 // the solid (and thus std::fabs(s[0]) > halfTol).
403 // Return kInfinity if the intersection is "behind" the point.
404 //
405 if (s[0] < 0) return kInfinity;
406
407 //
408 // Check to see if we intersect the tube within
409 // dz, but only when we know it might miss
410 //
411 G4double zi = p.z() + s[0]*v.z();
412
413 if (v.z() < 0)
414 {
415 if (zi < -dz) return kInfinity;
416 }
417 else if (v.z() > 0)
418 {
419 if (zi > +dz) return kInfinity;
420 }
421
422 return s[0];
423}
424
425
426//
427// DistanceToIn(p)
428//
429// The distance from a point to an ellipse (in 2 dimensions) is a
430// surprisingly complicated quadric expression (this is easy to
431// appreciate once one understands that there may be up to
432// four lines normal to the ellipse intersecting any point). To
433// solve it exactly would be rather time consuming. This method,
434// however, is supposed to be a quick check, and is allowed to be an
435// underestimate.
436//
437// So, I will use the following underestimate of the distance
438// from an outside point to an ellipse. First: find the intersection "A"
439// of the line from the origin to the point with the ellipse.
440// Find the line passing through "A" and tangent to the ellipse
441// at A. The distance of the point p from the ellipse will be approximated
442// as the distance to this line.
443//
444G4double G4EllipticalTube::DistanceToIn( const G4ThreeVector& p ) const
445{
446 static const G4double halfTol = 0.5*kCarTolerance;
447
448 if (CheckXY( p.x(), p.y(), +halfTol ) < 1.0)
449 {
450 //
451 // We are inside or on the surface of the
452 // elliptical cross section in x/y. Check z
453 //
454 if (p.z() < -dz-halfTol)
455 return -p.z()-dz;
456 else if (p.z() > dz+halfTol)
457 return p.z()-dz;
458 else
459 return 0; // On any surface here (or inside)
460 }
461
462 //
463 // Find point on ellipse
464 //
465 G4double qnorm = CheckXY( p.x(), p.y() );
466 if (qnorm < DBL_MIN) return 0; // This should never happen
467
468 G4double q = 1.0/std::sqrt(qnorm);
469
470 G4double xe = q*p.x(), ye = q*p.y();
471
472 //
473 // Get tangent to ellipse
474 //
475 G4double tx = -ye*dx*dx, ty = +xe*dy*dy;
476 G4double tnorm = std::sqrt( tx*tx + ty*ty );
477
478 //
479 // Calculate distance
480 //
481 G4double distR = ( (p.x()-xe)*ty - (p.y()-ye)*tx )/tnorm;
482
483 //
484 // Add the result in quadrature if we are, in addition,
485 // outside the z bounds of the shape
486 //
487 // We could save some time by returning the maximum rather
488 // than the quadrature sum
489 //
490 if (p.z() < -dz)
491 return std::sqrt( (p.z()+dz)*(p.z()+dz) + distR*distR );
492 else if (p.z() > dz)
493 return std::sqrt( (p.z()-dz)*(p.z()-dz) + distR*distR );
494
495 return distR;
496}
497
498
499//
500// DistanceToOut(p,v)
501//
502// This method can be somewhat complicated for a general shape.
503// For a convex one, like this, there are several simplifications,
504// the most important of which is that one can treat the surfaces
505// as infinite in extent when deciding if the p is on the surface.
506//
507G4double G4EllipticalTube::DistanceToOut( const G4ThreeVector& p,
508 const G4ThreeVector& v,
509 const G4bool calcNorm,
510 G4bool *validNorm,
511 G4ThreeVector *norm ) const
512{
513 static const G4double halfTol = 0.5*kCarTolerance;
514
515 //
516 // Our normal is always valid
517 //
518 if (calcNorm) *validNorm = true;
519
520 G4double sBest = kInfinity;
521 const G4ThreeVector *nBest=0;
522
523 //
524 // Might we intersect the -dz surface?
525 //
526 if (v.z() < 0)
527 {
528 static const G4ThreeVector normHere(0.0,0.0,-1.0);
529 //
530 // Yup. What distance?
531 //
532 sBest = -(p.z()+dz)/v.z();
533
534 //
535 // Are we on the surface? If so, return zero
536 //
537 if (p.z() < -dz+halfTol) {
538 if (calcNorm) *norm = normHere;
539 return 0;
540 }
541 else
542 nBest = &normHere;
543 }
544
545 //
546 // How about the +dz surface?
547 //
548 if (v.z() > 0)
549 {
550 static const G4ThreeVector normHere(0.0,0.0,+1.0);
551 //
552 // Yup. What distance?
553 //
554 G4double s = (dz-p.z())/v.z();
555
556 //
557 // Are we on the surface? If so, return zero
558 //
559 if (p.z() > +dz-halfTol) {
560 if (calcNorm) *norm = normHere;
561 return 0;
562 }
563
564 //
565 // Best so far?
566 //
567 if (s < sBest) { sBest = s; nBest = &normHere; }
568 }
569
570 //
571 // Check furthest intersection with ellipse
572 //
573 G4double s[2];
574 G4int n = IntersectXY( p, v, s );
575
576 if (n == 0)
577 {
578 if (sBest == kInfinity)
579 {
580 G4cout.precision(16) ;
581 G4cout << G4endl ;
582 DumpInfo();
583 G4cout << "Position:" << G4endl << G4endl ;
584 G4cout << "p.x() = " << p.x()/mm << " mm" << G4endl ;
585 G4cout << "p.y() = " << p.y()/mm << " mm" << G4endl ;
586 G4cout << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl ;
587 G4cout << "Direction:" << G4endl << G4endl;
588 G4cout << "v.x() = " << v.x() << G4endl;
589 G4cout << "v.y() = " << v.y() << G4endl;
590 G4cout << "v.z() = " << v.z() << G4endl << G4endl;
591 G4cout << "Proposed distance :" << G4endl << G4endl;
592 G4cout << "snxt = " << sBest/mm << " mm" << G4endl << G4endl;
593 G4Exception( "G4EllipticalTube::DistanceToOut(p,v,...)",
594 "Notification", JustWarning, "Point p is outside !?" );
595 }
596 if (calcNorm) *norm = *nBest;
597 return sBest;
598 }
599 else if (s[n-1] > sBest)
600 {
601 if (calcNorm) *norm = *nBest;
602 return sBest;
603 }
604 sBest = s[n-1];
605
606 //
607 // Intersection with ellipse. Get normal at intersection point.
608 //
609 if (calcNorm)
610 {
611 G4ThreeVector ip = p + sBest*v;
612 *norm = G4ThreeVector( ip.x()*dy*dy, ip.y()*dx*dx, 0.0 ).unit();
613 }
614
615 //
616 // Do we start on the surface?
617 //
618 if (CheckXY( p.x(), p.y(), -halfTol ) > 1.0)
619 {
620 //
621 // Well, yes, but are we traveling outwards at this point?
622 //
623 if (p.x()*dy*dy*v.x() + p.y()*dx*dx*v.y() > 0) return 0;
624 }
625
626 return sBest;
627}
628
629
630//
631// DistanceToOut(p)
632//
633// See DistanceToIn(p) for notes on the distance from a point
634// to an ellipse in two dimensions.
635//
636// The approximation used here for a point inside the ellipse
637// is to find the intersection with the ellipse of the lines
638// through the point and parallel to the x and y axes. The
639// distance of the point from the line connecting the two
640// intersecting points is then used.
641//
642G4double G4EllipticalTube::DistanceToOut( const G4ThreeVector& p ) const
643{
644 static const G4double halfTol = 0.5*kCarTolerance;
645
646 //
647 // We need to calculate the distances to all surfaces,
648 // and then return the smallest
649 //
650 // Check -dz and +dz surface
651 //
652 G4double sBest = dz - std::fabs(p.z());
653 if (sBest < halfTol) return 0;
654
655 //
656 // Check elliptical surface: find intersection of
657 // line through p and parallel to x axis
658 //
659 G4double radical = 1.0 - p.y()*p.y()/dy/dy;
660 if (radical < +DBL_MIN) return 0;
661
662 G4double xi = dx*std::sqrt( radical );
663 if (p.x() < 0) xi = -xi;
664
665 //
666 // Do the same with y axis
667 //
668 radical = 1.0 - p.x()*p.x()/dx/dx;
669 if (radical < +DBL_MIN) return 0;
670
671 G4double yi = dy*std::sqrt( radical );
672 if (p.y() < 0) yi = -yi;
673
674 //
675 // Get distance from p to the line connecting
676 // these two points
677 //
678 G4double xdi = p.x() - xi,
679 ydi = yi - p.y();
680
681 G4double normi = std::sqrt( xdi*xdi + ydi*ydi );
682 if (normi < halfTol) return 0;
683 xdi /= normi;
684 ydi /= normi;
685
686 G4double s = 0.5*(xdi*(p.y()-yi) - ydi*(p.x()-xi));
687 if (xi*yi < 0) s = -s;
688
689 if (s < sBest) sBest = s;
690
691 //
692 // Return best answer
693 //
694 return sBest < halfTol ? 0 : sBest;
695}
696
697
698//
699// IntersectXY
700//
701// Decide if and where the x/y trajectory hits the elliptical cross
702// section.
703//
704// Arguments:
705// p - (in) Point on trajectory
706// v - (in) Vector along trajectory
707// s - (out) Up to two points of intersection, where the
708// intersection point is p + s*v, and if there are
709// two intersections, s[0] < s[1]. May be negative.
710// Returns:
711// The number of intersections. If 0, the trajectory misses. If 1, the
712// trajectory just grazes the surface.
713//
714// Solution:
715// One needs to solve: ( (p.x + s*v.x)/dx )**2 + ( (p.y + s*v.y)/dy )**2 = 1
716//
717// The solution is quadratic: a*s**2 + b*s + c = 0
718//
719// a = (v.x/dx)**2 + (v.y/dy)**2
720// b = 2*p.x*v.x/dx**2 + 2*p.y*v.y/dy**2
721// c = (p.x/dx)**2 + (p.y/dy)**2 - 1
722//
723G4int G4EllipticalTube::IntersectXY( const G4ThreeVector &p,
724 const G4ThreeVector &v,
725 G4double s[2] ) const
726{
727 G4double px = p.x(), py = p.y();
728 G4double vx = v.x(), vy = v.y();
729
730 G4double a = (vx/dx)*(vx/dx) + (vy/dy)*(vy/dy);
731 G4double b = 2.0*( px*vx/dx/dx + py*vy/dy/dy );
732 G4double c = (px/dx)*(px/dx) + (py/dy)*(py/dy) - 1.0;
733
734 if (a < DBL_MIN) return 0; // Trajectory parallel to z axis
735
736 G4double radical = b*b - 4*a*c;
737
738 if (radical < -DBL_MIN) return 0; // No solution
739
740 if (radical < DBL_MIN)
741 {
742 //
743 // Grazes surface
744 //
745 s[0] = -b/a/2.0;
746 return 1;
747 }
748
749 radical = std::sqrt(radical);
750
751 G4double q = -0.5*( b + (b < 0 ? -radical : +radical) );
752 G4double sa = q/a;
753 G4double sb = c/q;
754 if (sa < sb) { s[0] = sa; s[1] = sb; } else { s[0] = sb; s[1] = sa; }
755 return 2;
756}
757
758
759//
760// GetEntityType
761//
762G4GeometryType G4EllipticalTube::GetEntityType() const
763{
764 return G4String("G4EllipticalTube");
765}
766
767
768//
769// GetCubicVolume
770//
771G4double G4EllipticalTube::GetCubicVolume()
772{
773 if(fCubicVolume != 0.) {;}
774 else { fCubicVolume = G4VSolid::GetCubicVolume(); }
775 return fCubicVolume;
776}
777
778//
779// GetSurfaceArea
780//
781G4double G4EllipticalTube::GetSurfaceArea()
782{
783 if(fSurfaceArea != 0.) {;}
784 else { fSurfaceArea = G4VSolid::GetSurfaceArea(); }
785 return fSurfaceArea;
786}
787
788//
789// Stream object contents to an output stream
790//
791std::ostream& G4EllipticalTube::StreamInfo(std::ostream& os) const
792{
793 os << "-----------------------------------------------------------\n"
794 << " *** Dump for solid - " << GetName() << " ***\n"
795 << " ===================================================\n"
796 << " Solid type: G4EllipticalTube\n"
797 << " Parameters: \n"
798 << " length Z: " << dz/mm << " mm \n"
799 << " surface equation in X and Y: \n"
800 << " (X / " << dx << ")^2 + (Y / " << dy << ")^2 = 1 \n"
801 << "-----------------------------------------------------------\n";
802
803 return os;
804}
805
806
807//
808// GetPointOnSurface
809//
810// Randomly generates a point on the surface,
811// with ~ uniform distribution across surface.
812//
813G4ThreeVector G4EllipticalTube::GetPointOnSurface() const
814{
815 G4double xRand, yRand, zRand, phi, cosphi, sinphi, zArea, cArea,p, chose;
816
817 phi = RandFlat::shoot(0., 2.*pi);
818 cosphi = std::cos(phi);
819 sinphi = std::sin(phi);
820
821 // the ellipse perimeter from: "http://mathworld.wolfram.com/Ellipse.html"
822 // m = (dx - dy)/(dx + dy);
823 // k = 1.+1./4.*m*m+1./64.*sqr(m)*sqr(m)+1./256.*sqr(m)*sqr(m)*sqr(m);
824 // p = pi*(a+b)*k;
825
826 // perimeter below from "http://www.efunda.com/math/areas/EllipseGen.cfm"
827
828 p = 2.*pi*std::sqrt(0.5*(dx*dx+dy*dy));
829
830 cArea = 2.*dz*p;
831 zArea = pi*dx*dy;
832
833 xRand = dx*cosphi;
834 yRand = dy*sinphi;
835 zRand = RandFlat::shoot(dz, -1.*dz);
836
837 chose = RandFlat::shoot(0.,2.*zArea+cArea);
838
839 if( (chose>=0) && (chose < cArea) )
840 {
841 return G4ThreeVector (xRand,yRand,zRand);
842 }
843 else if( (chose >= cArea) && (chose < cArea + zArea) )
844 {
845 xRand = RandFlat::shoot(-1.*dx,dx);
846 yRand = std::sqrt(1.-sqr(xRand/dx));
847 yRand = RandFlat::shoot(-1.*yRand, yRand);
848 return G4ThreeVector (xRand,yRand,dz);
849 }
850 else
851 {
852 xRand = RandFlat::shoot(-1.*dx,dx);
853 yRand = std::sqrt(1.-sqr(xRand/dx));
854 yRand = RandFlat::shoot(-1.*yRand, yRand);
855 return G4ThreeVector (xRand,yRand,-1.*dz);
856 }
857}
858
859
860//
861// CreatePolyhedron
862//
863G4Polyhedron* G4EllipticalTube::CreatePolyhedron() const
864{
865 // create cylinder with radius=1...
866 //
867 G4Polyhedron* eTube = new G4PolyhedronTube(0.,1.,dz);
868
869 // apply non-uniform scaling...
870 //
871 eTube->Transform(G4Scale3D(dx,dy,1.));
872 return eTube;
873}
874
875
876//
877// GetPolyhedron
878//
879G4Polyhedron* G4EllipticalTube::GetPolyhedron () const
880{
881 if (!fpPolyhedron ||
882 fpPolyhedron->GetNumberOfRotationStepsAtTimeOfCreation() !=
883 fpPolyhedron->GetNumberOfRotationSteps())
884 {
885 delete fpPolyhedron;
886 fpPolyhedron = CreatePolyhedron();
887 }
888 return fpPolyhedron;
889}
890
891
892//
893// DescribeYourselfTo
894//
895void G4EllipticalTube::DescribeYourselfTo( G4VGraphicsScene& scene ) const
896{
897 scene.AddSolid (*this);
898}
899
900
901//
902// GetExtent
903//
904G4VisExtent G4EllipticalTube::GetExtent() const
905{
906 return G4VisExtent( -dx, dx, -dy, dy, -dz, dz );
907}
Note: See TracBrowser for help on using the repository browser.