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