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
G4EllipticalCone.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// $Id$
27//
28// Implementation of G4EllipticalCone class
29//
30// This code implements an Elliptical Cone given explicitly by the
31// equation:
32// x^2/a^2 + y^2/b^2 = (z-h)^2
33// and specified by the parameters (a,b,h) and a cut parallel to the
34// xy plane above z = 0.
35//
36// Author: Dionysios Anninos
37//
38// --------------------------------------------------------------------
39
40#include "globals.hh"
41
42#include "G4EllipticalCone.hh"
43
44#include "G4ClippablePolygon.hh"
45#include "G4SolidExtentList.hh"
46#include "G4VoxelLimits.hh"
47#include "G4AffineTransform.hh"
49
50#include "meshdefs.hh"
51
52#include "Randomize.hh"
53
54#include "G4VGraphicsScene.hh"
55#include "G4Polyhedron.hh"
56#include "G4NURBS.hh"
57#include "G4NURBSbox.hh"
58#include "G4VisExtent.hh"
59
60//#define G4SPECSDEBUG 1
61
62using namespace CLHEP;
63
64//////////////////////////////////////////////////////////////////////
65//
66// Constructor - check parameters
67//
69 G4double pxSemiAxis,
70 G4double pySemiAxis,
71 G4double pzMax,
72 G4double pzTopCut)
73 : G4VSolid(pName), fpPolyhedron(0), fCubicVolume(0.), fSurfaceArea(0.),
74 zTopCut(0.)
75{
76
78
79 // Check Semi-Axis & Z-cut
80 //
81 if ( (pxSemiAxis <= 0.) || (pySemiAxis <= 0.) || (pzMax <= 0.) )
82 {
83 std::ostringstream message;
84 message << "Invalid semi-axis or height - " << GetName();
85 G4Exception("G4EllipticalCone::G4EllipticalCone()", "GeomSolids0002",
86 FatalErrorInArgument, message);
87 }
88 if ( pzTopCut <= 0 )
89 {
90 std::ostringstream message;
91 message << "Invalid z-coordinate for cutting plane - " << GetName();
92 G4Exception("G4EllipticalCone::G4EllipticalCone()", "InvalidSetup",
93 FatalErrorInArgument, message);
94 }
95
96 SetSemiAxis( pxSemiAxis, pySemiAxis, pzMax );
97 SetZCut(pzTopCut);
98}
99
100///////////////////////////////////////////////////////////////////////////////
101//
102// Fake default constructor - sets only member data and allocates memory
103// for usage restricted to object persistency.
104//
106 : G4VSolid(a), fpPolyhedron(0), kRadTolerance(0.), fCubicVolume(0.),
107 fSurfaceArea(0.), xSemiAxis(0.), ySemiAxis(0.), zheight(0.),
108 semiAxisMax(0.), zTopCut(0.)
109{
110}
111
112///////////////////////////////////////////////////////////////////////////////
113//
114// Destructor
115//
117{
118}
119
120///////////////////////////////////////////////////////////////////////////////
121//
122// Copy constructor
123//
125 : G4VSolid(rhs),
126 fpPolyhedron(0), kRadTolerance(rhs.kRadTolerance),
127 fCubicVolume(rhs.fCubicVolume), fSurfaceArea(rhs.fSurfaceArea),
128 xSemiAxis(rhs.xSemiAxis), ySemiAxis(rhs.ySemiAxis), zheight(rhs.zheight),
129 semiAxisMax(rhs.semiAxisMax), zTopCut(rhs.zTopCut)
130{
131}
132
133///////////////////////////////////////////////////////////////////////////////
134//
135// Assignment operator
136//
138{
139 // Check assignment to self
140 //
141 if (this == &rhs) { return *this; }
142
143 // Copy base class data
144 //
146
147 // Copy data
148 //
149 fpPolyhedron = 0; kRadTolerance = rhs.kRadTolerance;
150 fCubicVolume = rhs.fCubicVolume; fSurfaceArea = rhs.fSurfaceArea;
151 xSemiAxis = rhs.xSemiAxis; ySemiAxis = rhs.ySemiAxis;
152 zheight = rhs.zheight; semiAxisMax = rhs.semiAxisMax; zTopCut = rhs.zTopCut;
153
154 return *this;
155}
156
157///////////////////////////////////////////////////////////////////////////////
158//
159// Calculate extent under transform and specified limit
160//
161G4bool
163 const G4VoxelLimits &voxelLimit,
164 const G4AffineTransform &transform,
165 G4double &min, G4double &max ) const
166{
167 G4SolidExtentList extentList( axis, voxelLimit );
168
169 //
170 // We are going to divide up our elliptical face into small pieces
171 //
172
173 //
174 // Choose phi size of our segment(s) based on constants as
175 // defined in meshdefs.hh
176 //
177 G4int numPhi = kMaxMeshSections;
178 G4double sigPhi = twopi/numPhi;
179
180 //
181 // We have to be careful to keep our segments completely outside
182 // of the elliptical surface. To do so we imagine we have
183 // a simple (unit radius) circular cross section (as in G4Tubs)
184 // and then "stretch" the dimensions as necessary to fit the ellipse.
185 //
186 G4double rFudge = 1.0/std::cos(0.5*sigPhi);
187 G4double dxFudgeBot = xSemiAxis*2.*zheight*rFudge,
188 dyFudgeBot = ySemiAxis*2.*zheight*rFudge;
189 G4double dxFudgeTop = xSemiAxis*(zheight-zTopCut)*rFudge,
190 dyFudgeTop = ySemiAxis*(zheight-zTopCut)*rFudge;
191
192 //
193 // As we work around the elliptical surface, we build
194 // a "phi" segment on the way, and keep track of two
195 // additional polygons for the two ends.
196 //
197 G4ClippablePolygon endPoly1, endPoly2, phiPoly;
198
199 G4double phi = 0,
200 cosPhi = std::cos(phi),
201 sinPhi = std::sin(phi);
202 G4ThreeVector v0( dxFudgeTop*cosPhi, dyFudgeTop*sinPhi, +zTopCut ),
203 v1( dxFudgeBot*cosPhi, dyFudgeBot*sinPhi, -zTopCut ),
204 w0, w1;
205 transform.ApplyPointTransform( v0 );
206 transform.ApplyPointTransform( v1 );
207 do
208 {
209 phi += sigPhi;
210 if (numPhi == 1) phi = 0; // Try to avoid roundoff
211 cosPhi = std::cos(phi),
212 sinPhi = std::sin(phi);
213
214 w0 = G4ThreeVector( dxFudgeTop*cosPhi, dyFudgeTop*sinPhi, +zTopCut );
215 w1 = G4ThreeVector( dxFudgeBot*cosPhi, dyFudgeBot*sinPhi, -zTopCut );
216 transform.ApplyPointTransform( w0 );
217 transform.ApplyPointTransform( w1 );
218
219 //
220 // Add a point to our z ends
221 //
222 endPoly1.AddVertexInOrder( v0 );
223 endPoly2.AddVertexInOrder( v1 );
224
225 //
226 // Build phi polygon
227 //
228 phiPoly.ClearAllVertices();
229
230 phiPoly.AddVertexInOrder( v0 );
231 phiPoly.AddVertexInOrder( v1 );
232 phiPoly.AddVertexInOrder( w1 );
233 phiPoly.AddVertexInOrder( w0 );
234
235 if (phiPoly.PartialClip( voxelLimit, axis ))
236 {
237 //
238 // Get unit normal
239 //
240 phiPoly.SetNormal( (v1-v0).cross(w0-v0).unit() );
241
242 extentList.AddSurface( phiPoly );
243 }
244
245 //
246 // Next vertex
247 //
248 v0 = w0;
249 v1 = w1;
250 } while( --numPhi > 0 );
251
252 //
253 // Process the end pieces
254 //
255 if (endPoly1.PartialClip( voxelLimit, axis ))
256 {
257 static const G4ThreeVector normal(0,0,+1);
258 endPoly1.SetNormal( transform.TransformAxis(normal) );
259 extentList.AddSurface( endPoly1 );
260 }
261
262 if (endPoly2.PartialClip( voxelLimit, axis ))
263 {
264 static const G4ThreeVector normal(0,0,-1);
265 endPoly2.SetNormal( transform.TransformAxis(normal) );
266 extentList.AddSurface( endPoly2 );
267 }
268
269 //
270 // Return min/max value
271 //
272 return extentList.GetExtent( min, max );
273}
274
275////////////////////////////////////////////////////////////////////////
276//
277// Return whether point inside/outside/on surface
278// Split into radius, phi, theta checks
279// Each check modifies `in', or returns as approprate
280//
282{
283 G4double rad2oo, // outside surface outer tolerance
284 rad2oi; // outside surface inner tolerance
285
286 EInside in;
287
288 static const G4double halfRadTol = 0.5*kRadTolerance;
289 static const G4double halfCarTol = 0.5*kCarTolerance;
290
291 // check this side of z cut first, because that's fast
292 //
293
294 if ( (p.z() < -zTopCut - halfCarTol)
295 || (p.z() > zTopCut + halfCarTol ) )
296 {
297 return in = kOutside;
298 }
299
300 rad2oo= sqr(p.x()/( xSemiAxis + halfRadTol ))
301 + sqr(p.y()/( ySemiAxis + halfRadTol ));
302
303 if ( rad2oo > sqr( zheight-p.z() ) )
304 {
305 return in = kOutside;
306 }
307
308 // rad2oi= sqr( p.x()*(1.0 + 0.5*kRadTolerance/(xSemiAxis*xSemiAxis)) )
309 // + sqr( p.y()*(1.0 + 0.5*kRadTolerance/(ySemiAxis*ySemiAxis)) );
310 rad2oi = sqr(p.x()/( xSemiAxis - halfRadTol ))
311 + sqr(p.y()/( ySemiAxis - halfRadTol ));
312
313 if (rad2oi < sqr( zheight-p.z() ) )
314 {
315 in = ( ( p.z() < -zTopCut + halfRadTol )
316 || ( p.z() > zTopCut - halfRadTol ) ) ? kSurface : kInside;
317 }
318 else
319 {
320 in = kSurface;
321 }
322
323 return in;
324}
325
326/////////////////////////////////////////////////////////////////////////
327//
328// Return unit normal of surface closest to p not protected against p=0
329//
331{
332
333 G4double rx = sqr(p.x()/xSemiAxis),
334 ry = sqr(p.y()/ySemiAxis);
335
336 G4double rds = std::sqrt(rx + ry);
337
338 G4ThreeVector norm;
339
340 if( (p.z() < -zTopCut) && ((rx+ry) < sqr(zTopCut + zheight)) )
341 {
342 return G4ThreeVector( 0., 0., -1. );
343 }
344
345 if( (p.z() > (zheight > zTopCut ? zheight : zTopCut)) &&
346 ((rx+ry) < sqr(zheight-zTopCut)) )
347 {
348 return G4ThreeVector( 0., 0., 1. );
349 }
350
351 if( p.z() > rds + 2.*zTopCut - zheight )
352 {
353 if ( p.z() > zTopCut )
354 {
355 if( p.x() == 0. )
356 {
357 norm = G4ThreeVector( 0., p.y() < 0. ? -1. : 1., 1. );
358 return norm /= norm.mag();
359 }
360 if( p.y() == 0. )
361 {
362 norm = G4ThreeVector( p.x() < 0. ? -1. : 1., 0., 1. );
363 return norm /= norm.mag();
364 }
365
366 G4double k = std::fabs(p.x()/p.y());
367 G4double c2 = sqr(zheight-zTopCut)/(1./sqr(xSemiAxis)+sqr(k/ySemiAxis));
368 G4double x = std::sqrt(c2);
369 G4double y = k*x;
370
371 x /= sqr(xSemiAxis);
372 y /= sqr(ySemiAxis);
373
374 norm = G4ThreeVector( p.x() < 0. ? -x : x,
375 p.y() < 0. ? -y : y,
376 - ( zheight - zTopCut ) );
377 norm /= norm.mag();
378 norm += G4ThreeVector( 0., 0., 1. );
379 return norm /= norm.mag();
380 }
381
382 return G4ThreeVector( 0., 0., 1. );
383 }
384
385 if( p.z() < rds - 2.*zTopCut - zheight )
386 {
387 if( p.x() == 0. )
388 {
389 norm = G4ThreeVector( 0., p.y() < 0. ? -1. : 1., -1. );
390 return norm /= norm.mag();
391 }
392 if( p.y() == 0. )
393 {
394 norm = G4ThreeVector( p.x() < 0. ? -1. : 1., 0., -1. );
395 return norm /= norm.mag();
396 }
397
398 G4double k = std::fabs(p.x()/p.y());
399 G4double c2 = sqr(zheight+zTopCut)/(1./sqr(xSemiAxis)+sqr(k/ySemiAxis));
400 G4double x = std::sqrt(c2);
401 G4double y = k*x;
402
403 x /= sqr(xSemiAxis);
404 y /= sqr(ySemiAxis);
405
406 norm = G4ThreeVector( p.x() < 0. ? -x : x,
407 p.y() < 0. ? -y : y,
408 - ( zheight - zTopCut ) );
409 norm /= norm.mag();
410 norm += G4ThreeVector( 0., 0., -1. );
411 return norm /= norm.mag();
412 }
413
414 norm = G4ThreeVector(p.x()/sqr(xSemiAxis), p.y()/sqr(ySemiAxis), rds);
415
416 G4double k = std::tan(pi/8.);
417 G4double c = -zTopCut - k*(zTopCut + zheight);
418
419 if( p.z() < -k*rds + c )
420 return G4ThreeVector (0.,0.,-1.);
421
422 return norm /= norm.mag();
423}
424
425//////////////////////////////////////////////////////////////////////////
426//
427// Calculate distance to shape from outside, along normalised vector
428// return kInfinity if no intersection, or intersection distance <= tolerance
429//
431 const G4ThreeVector& v ) const
432{
433 static const G4double halfTol = 0.5*kCarTolerance;
434
435 G4double distMin = kInfinity;
436
437 // code from EllipticalTube
438
439 G4double sigz = p.z()+zTopCut;
440
441 //
442 // Check z = -dz planer surface
443 //
444
445 if (sigz < halfTol)
446 {
447 //
448 // We are "behind" the shape in z, and so can
449 // potentially hit the rear face. Correct direction?
450 //
451 if (v.z() <= 0)
452 {
453 //
454 // As long as we are far enough away, we know we
455 // can't intersect
456 //
457 if (sigz < 0) return kInfinity;
458
459 //
460 // Otherwise, we don't intersect unless we are
461 // on the surface of the ellipse
462 //
463
464 if ( sqr(p.x()/( xSemiAxis - halfTol ))
465 + sqr(p.y()/( ySemiAxis - halfTol )) <= sqr( zheight+zTopCut ) )
466 return kInfinity;
467
468 }
469 else
470 {
471 //
472 // How far?
473 //
474 G4double q = -sigz/v.z();
475
476 //
477 // Where does that place us?
478 //
479 G4double xi = p.x() + q*v.x(),
480 yi = p.y() + q*v.y();
481
482 //
483 // Is this on the surface (within ellipse)?
484 //
485 if ( sqr(xi/xSemiAxis) + sqr(yi/ySemiAxis) <= sqr( zheight + zTopCut ) )
486 {
487 //
488 // Yup. Return q, unless we are on the surface
489 //
490 return (sigz < -halfTol) ? q : 0;
491 }
492 else if (xi/(xSemiAxis*xSemiAxis)*v.x()
493 + yi/(ySemiAxis*ySemiAxis)*v.y() >= 0)
494 {
495 //
496 // Else, if we are traveling outwards, we know
497 // we must miss
498 //
499 // return kInfinity;
500 }
501 }
502 }
503
504 //
505 // Check z = +dz planer surface
506 //
507 sigz = p.z() - zTopCut;
508
509 if (sigz > -halfTol)
510 {
511 if (v.z() >= 0)
512 {
513
514 if (sigz > 0) return kInfinity;
515
516 if ( sqr(p.x()/( xSemiAxis - halfTol ))
517 + sqr(p.y()/( ySemiAxis - halfTol )) <= sqr( zheight-zTopCut ) )
518 return kInfinity;
519
520 }
521 else {
522 G4double q = -sigz/v.z();
523
524 G4double xi = p.x() + q*v.x(),
525 yi = p.y() + q*v.y();
526
527 if ( sqr(xi/xSemiAxis) + sqr(yi/ySemiAxis) <= sqr( zheight - zTopCut ) )
528 {
529 return (sigz > -halfTol) ? q : 0;
530 }
531 else if (xi/(xSemiAxis*xSemiAxis)*v.x()
532 + yi/(ySemiAxis*ySemiAxis)*v.y() >= 0)
533 {
534 // return kInfinity;
535 }
536 }
537 }
538
539
540#if 0
541
542 // check to see if Z plane is relevant
543 //
544 if (p.z() < -zTopCut - 0.5*kCarTolerance)
545 {
546 if (v.z() <= 0.0)
547 return distMin;
548
549 G4double lambda = (-zTopCut - p.z())/v.z();
550
551 if ( sqr((lambda*v.x()+p.x())/xSemiAxis) +
552 sqr((lambda*v.y()+p.y())/ySemiAxis) <=
553 sqr(zTopCut + zheight + 0.5*kRadTolerance) )
554 {
555 return distMin = std::fabs(lambda);
556 }
557 }
558
559 if (p.z() > zTopCut+0.5*kCarTolerance)
560 {
561 if (v.z() >= 0.0)
562 { return distMin; }
563
564 G4double lambda = (zTopCut - p.z()) / v.z();
565
566 if ( sqr((lambda*v.x() + p.x())/xSemiAxis) +
567 sqr((lambda*v.y() + p.y())/ySemiAxis) <=
568 sqr(zheight - zTopCut + 0.5*kRadTolerance) )
569 {
570 return distMin = std::fabs(lambda);
571 }
572 }
573
574 if (p.z() > zTopCut - halfTol
575 && p.z() < zTopCut + halfTol )
576 {
577 if (v.z() > 0.)
578 { return kInfinity; }
579
580 return distMin = 0.;
581 }
582
583 if (p.z() < -zTopCut + halfTol
584 && p.z() > -zTopCut - halfTol)
585 {
586 if (v.z() < 0.)
587 { return distMin = kInfinity; }
588
589 return distMin = 0.;
590 }
591
592#endif
593
594 // if we are here then it either intersects or grazes the curved surface
595 // or it does not intersect at all
596 //
597 G4double A = sqr(v.x()/xSemiAxis) + sqr(v.y()/ySemiAxis) - sqr(v.z());
598 G4double B = 2*(v.x()*p.x()/sqr(xSemiAxis) +
599 v.y()*p.y()/sqr(ySemiAxis) + v.z()*(zheight-p.z()));
600 G4double C = sqr(p.x()/xSemiAxis) + sqr(p.y()/ySemiAxis) -
601 sqr(zheight - p.z());
602
603 G4double discr = B*B - 4.*A*C;
604
605 // if the discriminant is negative it never hits the curved object
606 //
607 if ( discr < -halfTol )
608 { return distMin; }
609
610 // case below is when it hits or grazes the surface
611 //
612 if ( (discr >= - halfTol ) && (discr < halfTol ) )
613 {
614 return distMin = std::fabs(-B/(2.*A));
615 }
616
617 G4double plus = (-B+std::sqrt(discr))/(2.*A);
618 G4double minus = (-B-std::sqrt(discr))/(2.*A);
619
620 // Special case::Point on Surface, Check norm.dot(v)
621
622 if ( ( std::fabs(plus) < halfTol )||( std::fabs(minus) < halfTol ) )
623 {
624 G4ThreeVector truenorm(p.x()/(xSemiAxis*xSemiAxis),
625 p.y()/(ySemiAxis*ySemiAxis),
626 -( p.z() - zheight ));
627 if ( truenorm*v >= 0) // going outside the solid from surface
628 {
629 return kInfinity;
630 }
631 else
632 {
633 return 0;
634 }
635 }
636
637 // G4double lambda = std::fabs(plus) < std::fabs(minus) ? plus : minus;
638 G4double lambda = 0;
639
640 if ( minus > halfTol && minus < distMin )
641 {
642 lambda = minus ;
643 // check normal vector n * v < 0
644 G4ThreeVector pin = p + lambda*v;
645 if(std::fabs(pin.z())<zTopCut+0.5*kCarTolerance)
646 {
647 G4ThreeVector truenorm(pin.x()/(xSemiAxis*xSemiAxis),
648 pin.y()/(ySemiAxis*ySemiAxis),
649 - ( pin.z() - zheight ));
650 if ( truenorm*v < 0)
651 { // yes, going inside the solid
652 distMin = lambda;
653 }
654 }
655 }
656 if ( plus > halfTol && plus < distMin )
657 {
658 lambda = plus ;
659 // check normal vector n * v < 0
660 G4ThreeVector pin = p + lambda*v;
661 if(std::fabs(pin.z())<zTopCut+0.5*kCarTolerance)
662 {
663 G4ThreeVector truenorm(pin.x()/(xSemiAxis*xSemiAxis),
664 pin.y()/(ySemiAxis*ySemiAxis),
665 - ( pin.z() - zheight ) );
666 if ( truenorm*v < 0)
667 { // yes, going inside the solid
668 distMin = lambda;
669 }
670 }
671 }
672 if (distMin < halfTol) distMin=0.;
673 return distMin ;
674}
675
676//////////////////////////////////////////////////////////////////////////
677//
678// Calculate distance (<= actual) to closest surface of shape from outside
679// Return 0 if point inside
680//
682{
683 G4double distR, distR2, distZ, maxDim;
684 G4double distRad;
685
686 // check if the point lies either below z=-zTopCut in bottom elliptical
687 // region or on top within cut elliptical region
688 //
689 if( (p.z() <= -zTopCut) && (sqr(p.x()/xSemiAxis) + sqr(p.y()/ySemiAxis)
690 <= sqr(zTopCut + zheight + 0.5*kCarTolerance )) )
691 {
692 //return distZ = std::fabs(zTopCut - p.z());
693 return distZ = std::fabs(zTopCut + p.z());
694 }
695
696 if( (p.z() >= zTopCut) && (sqr(p.x()/xSemiAxis)+sqr(p.y()/ySemiAxis)
697 <= sqr(zheight - zTopCut + kCarTolerance/2.0 )) )
698 {
699 return distZ = std::fabs(p.z() - zTopCut);
700 }
701
702 // below we use the following approximation: we take the largest of the
703 // axes and find the shortest distance to the circular (cut) cone of that
704 // radius.
705 //
706 maxDim = xSemiAxis >= ySemiAxis ? xSemiAxis:ySemiAxis;
707 distRad = std::sqrt(p.x()*p.x()+p.y()*p.y());
708
709 if( p.z() > maxDim*distRad + zTopCut*(1.+maxDim)-sqr(maxDim)*zheight )
710 {
711 distR2 = sqr(p.z() - zTopCut) + sqr(distRad - maxDim*(zheight - zTopCut));
712 return std::sqrt( distR2 );
713 }
714
715 if( distRad > maxDim*( zheight - p.z() ) )
716 {
717 if( p.z() > maxDim*distRad - (zTopCut*(1.+maxDim)+sqr(maxDim)*zheight) )
718 {
719 G4double zVal = (p.z()-maxDim*(distRad-maxDim*zheight))/(1.+sqr(maxDim));
720 G4double rVal = maxDim*(zheight - zVal);
721 return distR = std::sqrt(sqr(p.z() - zVal) + sqr(distRad - rVal));
722 }
723 }
724
725 if( distRad <= maxDim*(zheight - p.z()) )
726 {
727 distR2 = sqr(distRad - maxDim*(zheight + zTopCut)) + sqr(p.z() + zTopCut);
728 return std::sqrt( distR2 );
729 }
730
731 return distR = 0;
732}
733
734/////////////////////////////////////////////////////////////////////////
735//
736// Calculate distance to surface of shape from `inside',
737// allowing for tolerance
738//
740 const G4ThreeVector& v,
741 const G4bool calcNorm,
742 G4bool *validNorm,
743 G4ThreeVector *n ) const
744{
745 G4double distMin, lambda;
746 enum surface_e {kPlaneSurf, kCurvedSurf, kNoSurf} surface;
747
748 distMin = kInfinity;
749 surface = kNoSurf;
750
751 if (v.z() < 0.0)
752 {
753 lambda = (-p.z() - zTopCut)/v.z();
754
755 if ( (sqr((p.x() + lambda*v.x())/xSemiAxis) +
756 sqr((p.y() + lambda*v.y())/ySemiAxis)) <
757 sqr(zheight + zTopCut + 0.5*kCarTolerance) )
758 {
759 distMin = std::fabs(lambda);
760
761 if (!calcNorm) { return distMin; }
762 }
763 distMin = std::fabs(lambda);
764 surface = kPlaneSurf;
765 }
766
767 if (v.z() > 0.0)
768 {
769 lambda = (zTopCut - p.z()) / v.z();
770
771 if ( (sqr((p.x() + lambda*v.x())/xSemiAxis)
772 + sqr((p.y() + lambda*v.y())/ySemiAxis) )
773 < (sqr(zheight - zTopCut + 0.5*kCarTolerance)) )
774 {
775 distMin = std::fabs(lambda);
776 if (!calcNorm) { return distMin; }
777 }
778 distMin = std::fabs(lambda);
779 surface = kPlaneSurf;
780 }
781
782 // if we are here then it either intersects or grazes the
783 // curved surface...
784 //
785 G4double A = sqr(v.x()/xSemiAxis) + sqr(v.y()/ySemiAxis) - sqr(v.z());
786 G4double B = 2.*(v.x()*p.x()/sqr(xSemiAxis) +
787 v.y()*p.y()/sqr(ySemiAxis) + v.z()*(zheight-p.z()));
788 G4double C = sqr(p.x()/xSemiAxis) + sqr(p.y()/ySemiAxis)
789 - sqr(zheight - p.z());
790
791 G4double discr = B*B - 4.*A*C;
792
793 if ( discr >= - 0.5*kCarTolerance && discr < 0.5*kCarTolerance )
794 {
795 if(!calcNorm) { return distMin = std::fabs(-B/(2.*A)); }
796 }
797
798 else if ( discr > 0.5*kCarTolerance )
799 {
800 G4double plus = (-B+std::sqrt(discr))/(2.*A);
801 G4double minus = (-B-std::sqrt(discr))/(2.*A);
802
803 if ( plus > 0.5*kCarTolerance && minus > 0.5*kCarTolerance )
804 {
805 // take the shorter distance
806 //
807 lambda = std::fabs(plus) < std::fabs(minus) ? plus : minus;
808 }
809 else
810 {
811 // at least one solution is close to zero or negative
812 // so, take small positive solution or zero
813 //
814 lambda = plus > -0.5*kCarTolerance ? plus : 0;
815 }
816
817 if ( std::fabs(lambda) < distMin )
818 {
819 if( std::fabs(lambda) > 0.5*kCarTolerance)
820 {
821 distMin = std::fabs(lambda);
822 surface = kCurvedSurf;
823 }
824 else // Point is On the Surface, Check Normal
825 {
826 G4ThreeVector truenorm(p.x()/(xSemiAxis*xSemiAxis),
827 p.y()/(ySemiAxis*ySemiAxis),
828 -( p.z() - zheight ));
829 if( truenorm.dot(v) > 0 )
830 {
831 distMin = 0.0;
832 surface = kCurvedSurf;
833 }
834 }
835 }
836 }
837
838 // set normal if requested
839 //
840 if (calcNorm)
841 {
842 if (surface == kNoSurf)
843 {
844 *validNorm = false;
845 }
846 else
847 {
848 *validNorm = true;
849 switch (surface)
850 {
851 case kPlaneSurf:
852 {
853 *n = G4ThreeVector(0.,0.,(v.z() > 0.0 ? 1. : -1.));
854 }
855 break;
856
857 case kCurvedSurf:
858 {
859 G4ThreeVector pexit = p + distMin*v;
860 G4ThreeVector truenorm( pexit.x()/(xSemiAxis*xSemiAxis),
861 pexit.y()/(ySemiAxis*ySemiAxis),
862 -( pexit.z() - zheight ) );
863 truenorm /= truenorm.mag();
864 *n= truenorm;
865 }
866 break;
867
868 default: // Should never reach this case ...
869 DumpInfo();
870 std::ostringstream message;
871 G4int oldprc = message.precision(16);
872 message << "Undefined side for valid surface normal to solid."
873 << G4endl
874 << "Position:" << G4endl
875 << " p.x() = " << p.x()/mm << " mm" << G4endl
876 << " p.y() = " << p.y()/mm << " mm" << G4endl
877 << " p.z() = " << p.z()/mm << " mm" << G4endl
878 << "Direction:" << G4endl
879 << " v.x() = " << v.x() << G4endl
880 << " v.y() = " << v.y() << G4endl
881 << " v.z() = " << v.z() << G4endl
882 << "Proposed distance :" << G4endl
883 << " distMin = " << distMin/mm << " mm";
884 message.precision(oldprc);
885 G4Exception("G4EllipticalCone::DistanceToOut(p,v,..)",
886 "GeomSolids1002", JustWarning, message);
887 break;
888 }
889 }
890 }
891
892 if (distMin<0.5*kCarTolerance) { distMin=0; }
893
894 return distMin;
895}
896
897/////////////////////////////////////////////////////////////////////////
898//
899// Calculate distance (<=actual) to closest surface of shape from inside
900//
902{
903 G4double rds,roo,roo1, distR, distZ, distMin=0.;
904 G4double minAxis = xSemiAxis < ySemiAxis ? xSemiAxis : ySemiAxis;
905
906#ifdef G4SPECSDEBUG
907 if( Inside(p) == kOutside )
908 {
909 DumpInfo();
910 std::ostringstream message;
911 G4int oldprc = message.precision(16);
912 message << "Point p is outside !?" << G4endl
913 << "Position:" << G4endl
914 << " p.x() = " << p.x()/mm << " mm" << G4endl
915 << " p.y() = " << p.y()/mm << " mm" << G4endl
916 << " p.z() = " << p.z()/mm << " mm";
917 message.precision(oldprc) ;
918 G4Exception("G4Ellipsoid::DistanceToOut(p)", "GeomSolids1002",
919 JustWarning, message);
920 }
921#endif
922
923 // since we have made the above warning, below we are working assuming p
924 // is inside check how close it is to the circular cone with radius equal
925 // to the smaller of the axes
926 //
927 if( sqr(p.x()/minAxis)+sqr(p.y()/minAxis) < sqr(zheight - p.z()) )
928 {
929 rds = std::sqrt(sqr(p.x()) + sqr(p.y()));
930 roo = minAxis*(zheight-p.z()); // radius of cone at z= p.z()
931 roo1 = minAxis*(zheight-zTopCut); // radius of cone at z=+zTopCut
932
933 distZ=zTopCut - std::fabs(p.z()) ;
934 distR=(roo-rds)/(std::sqrt(1+sqr(minAxis)));
935
936 if(rds>roo1)
937 {
938 distMin=(zTopCut-p.z())*(roo-rds)/(roo-roo1);
939 distMin=std::min(distMin,distR);
940 }
941 distMin=std::min(distR,distZ);
942 }
943
944 return distMin;
945}
946
947//////////////////////////////////////////////////////////////////////////
948//
949// GetEntityType
950//
952{
953 return G4String("G4EllipticalCone");
954}
955
956//////////////////////////////////////////////////////////////////////////
957//
958// Make a clone of the object
959//
961{
962 return new G4EllipticalCone(*this);
963}
964
965//////////////////////////////////////////////////////////////////////////
966//
967// Stream object contents to an output stream
968//
969std::ostream& G4EllipticalCone::StreamInfo( std::ostream& os ) const
970{
971 G4int oldprc = os.precision(16);
972 os << "-----------------------------------------------------------\n"
973 << " *** Dump for solid - " << GetName() << " ***\n"
974 << " ===================================================\n"
975 << " Solid type: G4EllipticalCone\n"
976 << " Parameters: \n"
977
978 << " semi-axis x: " << xSemiAxis/mm << " mm \n"
979 << " semi-axis y: " << ySemiAxis/mm << " mm \n"
980 << " height z: " << zheight/mm << " mm \n"
981 << " half length in z: " << zTopCut/mm << " mm \n"
982 << "-----------------------------------------------------------\n";
983 os.precision(oldprc);
984
985 return os;
986}
987
988/////////////////////////////////////////////////////////////////////////
989//
990// GetPointOnSurface
991//
992// returns quasi-uniformly distributed point on surface of elliptical cone
993//
995{
996
997 G4double phi, sinphi, cosphi, aOne, aTwo, aThree,
998 chose, zRand, rRand1, rRand2;
999
1000 G4double rOne = std::sqrt(sqr(xSemiAxis)
1001 + sqr(ySemiAxis))*(zheight - zTopCut);
1002 G4double rTwo = std::sqrt(sqr(xSemiAxis)
1003 + sqr(ySemiAxis))*(zheight + zTopCut);
1004
1005 aOne = pi*(rOne + rTwo)*std::sqrt(sqr(rOne - rTwo)+sqr(2.*zTopCut));
1006 aTwo = pi*xSemiAxis*ySemiAxis*sqr(zheight+zTopCut);
1007 aThree = pi*xSemiAxis*ySemiAxis*sqr(zheight-zTopCut);
1008
1009 phi = RandFlat::shoot(0.,twopi);
1010 cosphi = std::cos(phi);
1011 sinphi = std::sin(phi);
1012
1013 if(zTopCut >= zheight) aThree = 0.;
1014
1015 chose = RandFlat::shoot(0.,aOne+aTwo+aThree);
1016 if((chose>=0.) && (chose<aOne))
1017 {
1018 zRand = RandFlat::shoot(-zTopCut,zTopCut);
1019 return G4ThreeVector(xSemiAxis*(zheight-zRand)*cosphi,
1020 ySemiAxis*(zheight-zRand)*sinphi,zRand);
1021 }
1022 else if((chose>=aOne) && (chose<aOne+aTwo))
1023 {
1024 do
1025 {
1026 rRand1 = RandFlat::shoot(0.,1.) ;
1027 rRand2 = RandFlat::shoot(0.,1.) ;
1028 } while ( rRand2 >= rRand1 ) ;
1029
1030 // rRand2 = RandFlat::shoot(0.,std::sqrt(1.-sqr(rRand1)));
1031 return G4ThreeVector(rRand1*xSemiAxis*(zheight+zTopCut)*cosphi,
1032 rRand1*ySemiAxis*(zheight+zTopCut)*sinphi, -zTopCut);
1033
1034 }
1035 // else
1036 //
1037
1038 do
1039 {
1040 rRand1 = RandFlat::shoot(0.,1.) ;
1041 rRand2 = RandFlat::shoot(0.,1.) ;
1042 } while ( rRand2 >= rRand1 ) ;
1043
1044 return G4ThreeVector(rRand1*xSemiAxis*(zheight-zTopCut)*cosphi,
1045 rRand1*ySemiAxis*(zheight-zTopCut)*sinphi, zTopCut);
1046}
1047
1048//
1049// Methods for visualisation
1050//
1051
1053{
1054 scene.AddSolid(*this);
1055}
1056
1058{
1059 // Define the sides of the box into which the solid instance would fit.
1060 //
1061 G4double maxDim;
1062 maxDim = xSemiAxis > ySemiAxis ? xSemiAxis : ySemiAxis;
1063 maxDim = maxDim > zTopCut ? maxDim : zTopCut;
1064
1065 return G4VisExtent (-maxDim, maxDim,
1066 -maxDim, maxDim,
1067 -maxDim, maxDim);
1068}
1069
1071{
1072 // Box for now!!!
1073 //
1074 return new G4NURBSbox(xSemiAxis, ySemiAxis,zheight);
1075}
1076
1078{
1079 return new G4PolyhedronEllipticalCone(xSemiAxis, ySemiAxis, zheight, zTopCut);
1080}
1081
1083{
1084 if ( (!fpPolyhedron)
1087 {
1088 delete fpPolyhedron;
1090 }
1091 return fpPolyhedron;
1092}
@ JustWarning
@ FatalErrorInArgument
CLHEP::Hep3Vector G4ThreeVector
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
double x() const
double y() const
double dot(const Hep3Vector &) const
double mag() 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)
G4VisExtent GetExtent() const
void SetSemiAxis(G4double x, G4double y, G4double z)
G4Polyhedron * GetPolyhedron() const
G4bool CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimit, const G4AffineTransform &pTransform, G4double &pmin, G4double &pmax) const
G4NURBS * CreateNURBS() const
G4GeometryType GetEntityType() const
G4VSolid * Clone() const
G4EllipticalCone(const G4String &pName, G4double pxSemiAxis, G4double pySemiAxis, G4double zMax, G4double pzTopCut)
void SetZCut(G4double newzTopCut)
virtual ~G4EllipticalCone()
G4ThreeVector GetPointOnSurface() const
G4Polyhedron * CreatePolyhedron() const
G4Polyhedron * fpPolyhedron
G4double DistanceToIn(const G4ThreeVector &p, const G4ThreeVector &v) const
G4double DistanceToOut(const G4ThreeVector &p, const G4ThreeVector &v, const G4bool calcNorm=G4bool(false), G4bool *validNorm=0, G4ThreeVector *n=0) const
std::ostream & StreamInfo(std::ostream &os) const
G4ThreeVector SurfaceNormal(const G4ThreeVector &p) const
EInside Inside(const G4ThreeVector &p) const
G4EllipticalCone & operator=(const G4EllipticalCone &rhs)
void DescribeYourselfTo(G4VGraphicsScene &scene) const
G4double GetRadialTolerance() const
static G4GeometryTolerance * GetInstance()
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
static G4int GetNumberOfRotationSteps()
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