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