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