Geant4 11.4.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// Implementation of G4EllipticalCone class
27//
28// This code implements an Elliptical Cone given explicitly by the
29// equation:
30// x^2/a^2 + y^2/b^2 = (z-h)^2
31// and specified by the parameters (a,b,h) and a cut parallel to the
32// xy plane above z = 0.
33//
34// Author: Dionysios Anninos
35// Revised: Evgueni Tcherniaev
36// --------------------------------------------------------------------
37
38#if !(defined(G4GEOM_USE_UELLIPTICALCONE) && defined(G4GEOM_USE_SYS_USOLIDS))
39
40#include "G4EllipticalCone.hh"
41
42#include "G4GeomTools.hh"
43#include "G4VoxelLimits.hh"
44#include "G4AffineTransform.hh"
45#include "G4BoundingEnvelope.hh"
46#include "G4QuickRand.hh"
47
48#include "G4VGraphicsScene.hh"
49#include "G4VisExtent.hh"
50
51#include "G4AutoLock.hh"
52
53namespace
54{
55 G4Mutex polyhedronMutex = G4MUTEX_INITIALIZER;
56 G4Mutex elconeMutex = G4MUTEX_INITIALIZER;
57}
58
59using namespace CLHEP;
60
61/////////////////////////////////////////////////////////////////////////
62//
63// Constructor - check parameters
64
66 G4double pxSemiAxis,
67 G4double pySemiAxis,
68 G4double pzMax,
69 G4double pzTopCut)
70 : G4VSolid(pName), zTopCut(0.)
71{
72 halfCarTol = 0.5*kCarTolerance;
73
74 // Check Semi-Axis & Z-cut
75 //
76 if ( (pxSemiAxis <= 0.) || (pySemiAxis <= 0.) || (pzMax <= 0.) )
77 {
78 std::ostringstream message;
79 message << "Invalid semi-axis or height for solid: " << GetName()
80 << "\n X semi-axis, Y semi-axis, height = "
81 << pxSemiAxis << ", " << pySemiAxis << ", " << pzMax;
82 G4Exception("G4EllipticalCone::G4EllipticalCone()", "GeomSolids0002",
83 FatalErrorInArgument, message);
84 }
85
86 if ( pzTopCut <= 0 )
87 {
88 std::ostringstream message;
89 message << "Invalid z-coordinate for cutting plane for solid: " << GetName()
90 << "\n Z top cut = " << pzTopCut;
91 G4Exception("G4EllipticalCone::G4EllipticalCone()", "GeomSolids0002",
92 FatalErrorInArgument, message);
93 }
94
95 SetSemiAxis( pxSemiAxis, pySemiAxis, pzMax );
96 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), halfCarTol(0.),
107 xSemiAxis(0.), ySemiAxis(0.), zheight(0.), zTopCut(0.),
108 cosAxisMin(0.), invXX(0.), invYY(0.)
109{
110}
111
112/////////////////////////////////////////////////////////////////////////
113//
114// Destructor
115
120
121/////////////////////////////////////////////////////////////////////////
122//
123// Copy constructor
124
126 : G4VSolid(rhs), halfCarTol(rhs.halfCarTol),
127 fCubicVolume(rhs.fCubicVolume), fSurfaceArea(rhs.fSurfaceArea),
128 fMinZBaseArea(rhs.fMinZBaseArea), fMaxZBaseArea(rhs.fMaxZBaseArea),
129 xSemiAxis(rhs.xSemiAxis), ySemiAxis(rhs.ySemiAxis),
130 zheight(rhs.zheight), zTopCut(rhs.zTopCut),
131 cosAxisMin(rhs.cosAxisMin), invXX(rhs.invXX), invYY(rhs.invYY)
132{
133}
134
135/////////////////////////////////////////////////////////////////////////
136//
137// Assignment operator
138
140{
141 // Check assignment to self
142 //
143 if (this == &rhs) { return *this; }
144
145 // Copy base class data
146 //
148
149 // Copy data
150 //
151 halfCarTol = rhs.halfCarTol;
152 fCubicVolume = rhs.fCubicVolume; fSurfaceArea = rhs.fSurfaceArea;
153 fMinZBaseArea = rhs.fMinZBaseArea; fMaxZBaseArea = rhs.fMaxZBaseArea;
154 xSemiAxis = rhs.xSemiAxis; ySemiAxis = rhs.ySemiAxis;
155 zheight = rhs.zheight; zTopCut = rhs.zTopCut;
156 cosAxisMin = rhs.cosAxisMin; invXX = rhs.invXX; invYY = rhs.invYY;
157
158 fRebuildPolyhedron = false;
159 delete fpPolyhedron; fpPolyhedron = nullptr;
160
161 return *this;
162}
163
164/////////////////////////////////////////////////////////////////////////
165//
166// Set new semi axis
167
169 G4double newySemiAxis,
170 G4double newzMax)
171{
172 xSemiAxis = newxSemiAxis;
173 ySemiAxis = newySemiAxis;
174 zheight = newzMax;
175 if (zTopCut > zheight) { zTopCut = zheight; }
176 G4double axmin = std::min(xSemiAxis, ySemiAxis);
177 cosAxisMin = axmin/std::sqrt(1. + axmin*axmin);
178 invXX = 1./(xSemiAxis*xSemiAxis);
179 invYY = 1./(ySemiAxis*ySemiAxis);
180 fCubicVolume = 0.0;
181 fSurfaceArea = 0.0;
183 fRebuildPolyhedron = true;
184}
185
186/////////////////////////////////////////////////////////////////////////
187//
188// Set new Z cut
189
191{
192 zTopCut = std::min(newzTopCut, zheight);
193 fCubicVolume = 0.0;
194 fSurfaceArea = 0.0;
196 fRebuildPolyhedron = true;
197}
198
199/////////////////////////////////////////////////////////////////////////
200//
201// Get bounding box
202
204 G4ThreeVector& pMax) const
205{
206 G4double zcut = GetZTopCut();
207 G4double height = GetZMax();
208 G4double xmax = GetSemiAxisX()*(height+zcut);
209 G4double ymax = GetSemiAxisY()*(height+zcut);
210 pMin.set(-xmax,-ymax,-zcut);
211 pMax.set( xmax, ymax, zcut);
212
213 // Check correctness of the bounding box
214 //
215 if (pMin.x() >= pMax.x() || pMin.y() >= pMax.y() || pMin.z() >= pMax.z())
216 {
217 std::ostringstream message;
218 message << "Bad bounding box (min >= max) for solid: "
219 << GetName() << " !"
220 << "\npMin = " << pMin
221 << "\npMax = " << pMax;
222 G4Exception("G4EllipticalCone::BoundingLimits()", "GeomMgt0001",
223 JustWarning, message);
224 DumpInfo();
225 }
226}
227
228/////////////////////////////////////////////////////////////////////////
229//
230// Calculate extent under transform and specified limit
231
232G4bool
234 const G4VoxelLimits& pVoxelLimit,
235 const G4AffineTransform& pTransform,
236 G4double& pMin, G4double& pMax) const
237{
238 G4ThreeVector bmin,bmax;
239 G4bool exist;
240
241 // Check bounding box (bbox)
242 //
243 BoundingLimits(bmin,bmax);
244 G4BoundingEnvelope bbox(bmin,bmax);
245#ifdef G4BBOX_EXTENT
246 return bbox.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax);
247#endif
248 if (bbox.BoundingBoxVsVoxelLimits(pAxis,pVoxelLimit,pTransform,pMin,pMax))
249 {
250 return exist = pMin < pMax;
251 }
252
253 // Set bounding envelope (benv) and calculate extent
254 //
255 static const G4int NSTEPS = 48; // number of steps for whole circle
256 static const G4double ang = twopi/NSTEPS;
257 static const G4double sinHalf = std::sin(0.5*ang);
258 static const G4double cosHalf = std::cos(0.5*ang);
259 static const G4double sinStep = 2.*sinHalf*cosHalf;
260 static const G4double cosStep = 1. - 2.*sinHalf*sinHalf;
261 G4double zcut = bmax.z();
262 G4double height = GetZMax();
263 G4double sxmin = GetSemiAxisX()*(height-zcut)/cosHalf;
264 G4double symin = GetSemiAxisY()*(height-zcut)/cosHalf;
265 G4double sxmax = bmax.x()/cosHalf;
266 G4double symax = bmax.y()/cosHalf;
267
268 G4double sinCur = sinHalf;
269 G4double cosCur = cosHalf;
270 G4ThreeVectorList baseA(NSTEPS),baseB(NSTEPS);
271 for (G4int k=0; k<NSTEPS; ++k)
272 {
273 baseA[k].set(sxmax*cosCur,symax*sinCur,-zcut);
274 baseB[k].set(sxmin*cosCur,symin*sinCur, zcut);
275
276 G4double sinTmp = sinCur;
277 sinCur = sinCur*cosStep + cosCur*sinStep;
278 cosCur = cosCur*cosStep - sinTmp*sinStep;
279 }
280
281 std::vector<const G4ThreeVectorList *> polygons(2);
282 polygons[0] = &baseA;
283 polygons[1] = &baseB;
284 G4BoundingEnvelope benv(bmin,bmax,polygons);
285 exist = benv.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax);
286 return exist;
287}
288
289/////////////////////////////////////////////////////////////////////////
290//
291// Determine where is point: inside, outside or on surface
292
294{
295 G4double hp = std::sqrt(p.x()*p.x()*invXX + p.y()*p.y()*invYY) + p.z();
296 G4double ds = (hp - zheight)*cosAxisMin;
297 G4double dz = std::abs(p.z()) - zTopCut;
298 G4double dist = std::max(ds,dz);
299
300 if (dist > halfCarTol) { return kOutside; }
301 return (dist > -halfCarTol) ? kSurface : kInside;
302}
303
304/////////////////////////////////////////////////////////////////////////
305//
306// Return unit normal at surface closest to p
307
309{
310 G4ThreeVector norm(0,0,0);
311 G4int nsurf = 0; // number of surfaces where p is placed
312
313 G4double hp = std::sqrt(p.x()*p.x()*invXX + p.y()*p.y()*invYY) + p.z();
314 G4double ds = (hp - zheight)*cosAxisMin;
315 if (std::abs(ds) <= halfCarTol)
316 {
317 norm = G4ThreeVector(p.x()*invXX, p.y()*invYY, hp - p.z());
318 G4double mag = norm.mag();
319 if (mag == 0) { return {0,0,1}; } // apex
320 norm *= (1/mag);
321 ++nsurf;
322 }
323 G4double dz = std::abs(p.z()) - zTopCut;
324 if (std::abs(dz) <= halfCarTol)
325 {
326 norm += G4ThreeVector(0., 0.,(p.z() < 0) ? -1. : 1.);
327 ++nsurf;
328 }
329
330 if (nsurf == 1)
331 {
332 return norm;
333 }
334 if (nsurf > 1)
335 {
336 return norm.unit(); // elliptic edge
337 }
338
339 // Point is not on the surface
340 //
341#ifdef G4CSGDEBUG
342 std::ostringstream message;
343 G4long oldprc = message.precision(16);
344 message << "Point p is not on surface (!?) of solid: "
345 << GetName() << G4endl;
346 message << "Position:\n";
347 message << " p.x() = " << p.x()/mm << " mm\n";
348 message << " p.y() = " << p.y()/mm << " mm\n";
349 message << " p.z() = " << p.z()/mm << " mm";
350 G4cout.precision(oldprc);
351 G4Exception("G4EllipticalCone::SurfaceNormal(p)", "GeomSolids1002",
352 JustWarning, message );
353 DumpInfo();
354#endif
355 return ApproxSurfaceNormal(p);
356}
357
358/////////////////////////////////////////////////////////////////////////
359//
360// Find surface nearest to point and return corresponding normal.
361// The algorithm is similar to the algorithm used in Inside().
362// This method normally should not be called.
363
365G4EllipticalCone::ApproxSurfaceNormal(const G4ThreeVector& p) const
366{
367 G4double hp = std::sqrt(p.x()*p.x()*invXX + p.y()*p.y()*invYY) + p.z();
368 G4double ds = (hp - zheight)*cosAxisMin;
369 G4double dz = std::abs(p.z()) - zTopCut;
370 if (ds > dz && std::abs(hp - p.z()) > halfCarTol)
371 {
372 return G4ThreeVector(p.x()*invXX, p.y()*invYY, hp - p.z()).unit();
373 }
374 return { 0., 0., (G4double)((p.z() < 0) ? -1. : 1.) };
375}
376
377////////////////////////////////////////////////////////////////////////
378//
379// Calculate distance to shape from outside, along normalised vector
380// return kInfinity if no intersection, or intersection distance <= tolerance
381
383 const G4ThreeVector& v ) const
384{
385 G4double distMin = kInfinity;
386
387 // code from EllipticalTube
388
389 G4double sigz = p.z()+zTopCut;
390
391 //
392 // Check z = -dz planer surface
393 //
394
395 if (sigz < halfCarTol)
396 {
397 //
398 // We are "behind" the shape in z, and so can
399 // potentially hit the rear face. Correct direction?
400 //
401 if (v.z() <= 0)
402 {
403 //
404 // As long as we are far enough away, we know we
405 // can't intersect
406 //
407 if (sigz < 0) { return kInfinity; }
408
409 //
410 // Otherwise, we don't intersect unless we are
411 // on the surface of the ellipse
412 //
413
414 if ( sqr(p.x()/( xSemiAxis - halfCarTol ))
415 + sqr(p.y()/( ySemiAxis - halfCarTol )) <= sqr( zheight + zTopCut ) )
416 {
417 return kInfinity;
418 }
419 }
420 else
421 {
422 //
423 // How far?
424 //
425 G4double q = -sigz/v.z();
426
427 //
428 // Where does that place us?
429 //
430 G4double xi = p.x() + q*v.x(),
431 yi = p.y() + q*v.y();
432
433 //
434 // Is this on the surface (within ellipse)?
435 //
436 if ( sqr(xi/xSemiAxis) + sqr(yi/ySemiAxis) <= sqr( zheight + zTopCut ) )
437 {
438 //
439 // Yup. Return q, unless we are on the surface
440 //
441 return (sigz < -halfCarTol) ? q : 0;
442 }
443 if (xi/(xSemiAxis*xSemiAxis)*v.x() + yi/(ySemiAxis*ySemiAxis)*v.y() >= 0)
444 {
445 //
446 // Else, if we are traveling outwards, we know
447 // we must miss
448 //
449 // return kInfinity;
450 }
451 }
452 }
453
454 //
455 // Check z = +dz planer surface
456 //
457 sigz = p.z() - zTopCut;
458
459 if (sigz > -halfCarTol)
460 {
461 if (v.z() >= 0)
462 {
463 if (sigz > 0) { return kInfinity; }
464
465 if ( sqr(p.x()/( xSemiAxis - halfCarTol ))
466 + sqr(p.y()/( ySemiAxis - halfCarTol )) <= sqr( zheight-zTopCut ) )
467 {
468 return kInfinity;
469 }
470 }
471 else
472 {
473 G4double q = -sigz/v.z();
474
475 G4double xi = p.x() + q*v.x(),
476 yi = p.y() + q*v.y();
477
478 if ( sqr(xi/xSemiAxis) + sqr(yi/ySemiAxis) <= sqr( zheight - zTopCut ) )
479 {
480 return (sigz > -halfCarTol) ? q : 0;
481 }
482 if (xi/(xSemiAxis*xSemiAxis)*v.x() + yi/(ySemiAxis*ySemiAxis)*v.y() >= 0)
483 {
484 // return kInfinity;
485 }
486 }
487 }
488
489#if 0
490
491 // check to see if Z plane is relevant
492 //
493 if (p.z() < -zTopCut - halfCarTol)
494 {
495 if (v.z() <= 0.0) { return distMin; }
496
497 G4double lambda = (-zTopCut - p.z())/v.z();
498
499 if ( sqr((lambda*v.x()+p.x())/xSemiAxis) +
500 sqr((lambda*v.y()+p.y())/ySemiAxis) <=
501 sqr(zTopCut + zheight + halfCarTol) )
502 {
503 return distMin = std::fabs(lambda);
504 }
505 }
506
507 if (p.z() > zTopCut + halfCarTol)
508 {
509 if (v.z() >= 0.0) { return distMin; }
510
511 G4double lambda = (zTopCut - p.z()) / v.z();
512
513 if ( sqr((lambda*v.x() + p.x())/xSemiAxis) +
514 sqr((lambda*v.y() + p.y())/ySemiAxis) <=
515 sqr(zheight - zTopCut + halfCarTol) )
516 {
517 return distMin = std::fabs(lambda);
518 }
519 }
520
521 if (p.z() > zTopCut - halfCarTol
522 && p.z() < zTopCut + halfCarTol )
523 {
524 if (v.z() > 0.) { return kInfinity; }
525
526 return distMin = 0.;
527 }
528
529 if (p.z() < -zTopCut + halfCarTol
530 && p.z() > -zTopCut - halfCarTol)
531 {
532 if (v.z() < 0.) { return distMin = kInfinity; }
533
534 return distMin = 0.;
535 }
536
537#endif
538
539 // if we are here then it either intersects or grazes the curved surface
540 // or it does not intersect at all
541 //
542 G4double A = sqr(v.x()/xSemiAxis) + sqr(v.y()/ySemiAxis) - sqr(v.z());
543 G4double B = 2*(v.x()*p.x()/sqr(xSemiAxis) +
544 v.y()*p.y()/sqr(ySemiAxis) + v.z()*(zheight-p.z()));
545 G4double C = sqr(p.x()/xSemiAxis) + sqr(p.y()/ySemiAxis) -
546 sqr(zheight - p.z());
547
548 G4double discr = B*B - 4.*A*C;
549
550 // if the discriminant is negative it never hits the curved object
551 //
552 if ( discr < -halfCarTol ) { return distMin; }
553
554 // case below is when it hits or grazes the surface
555 //
556 if ( (discr >= -halfCarTol ) && (discr < halfCarTol ) )
557 {
558 return distMin = std::fabs(-B/(2.*A));
559 }
560
561 G4double plus = (-B+std::sqrt(discr))/(2.*A);
562 G4double minus = (-B-std::sqrt(discr))/(2.*A);
563
564 // Special case::Point on Surface, Check norm.dot(v)
565
566 if ( ( std::fabs(plus) < halfCarTol )||( std::fabs(minus) < halfCarTol ) )
567 {
568 G4ThreeVector truenorm(p.x()/(xSemiAxis*xSemiAxis),
569 p.y()/(ySemiAxis*ySemiAxis),
570 -( p.z() - zheight ));
571 if ( truenorm*v >= 0) // going outside the solid from surface
572 {
573 return kInfinity;
574 }
575 return 0;
576 }
577
578 // G4double lambda = std::fabs(plus) < std::fabs(minus) ? plus : minus;
579 G4double lambda = 0;
580
581 if ( minus > halfCarTol && minus < distMin )
582 {
583 lambda = minus ;
584 // check normal vector n * v < 0
585 G4ThreeVector pin = p + lambda*v;
586 if(std::fabs(pin.z())< zTopCut + halfCarTol)
587 {
588 G4ThreeVector truenorm(pin.x()/(xSemiAxis*xSemiAxis),
589 pin.y()/(ySemiAxis*ySemiAxis),
590 - ( pin.z() - zheight ));
591 if ( truenorm*v < 0)
592 { // yes, going inside the solid
593 distMin = lambda;
594 }
595 }
596 }
597 if ( plus > halfCarTol && plus < distMin )
598 {
599 lambda = plus ;
600 // check normal vector n * v < 0
601 G4ThreeVector pin = p + lambda*v;
602 if(std::fabs(pin.z()) < zTopCut + halfCarTol)
603 {
604 G4ThreeVector truenorm(pin.x()/(xSemiAxis*xSemiAxis),
605 pin.y()/(ySemiAxis*ySemiAxis),
606 - ( pin.z() - zheight ) );
607 if ( truenorm*v < 0)
608 { // yes, going inside the solid
609 distMin = lambda;
610 }
611 }
612 }
613 if (distMin < halfCarTol) { distMin=0.; }
614 return distMin ;
615}
616
617/////////////////////////////////////////////////////////////////////////
618//
619// Calculate distance (<= actual) to closest surface of shape from outside
620// Return 0 if point inside
621
623{
624 G4double hp = std::sqrt(p.x()*p.x()*invXX + p.y()*p.y()*invYY) + p.z();
625 G4double ds = (hp - zheight)*cosAxisMin;
626 G4double dz = std::abs(p.z()) - zTopCut;
627 G4double dist = std::max(ds,dz);
628 return (dist > 0) ? dist : 0.;
629}
630
631////////////////////////////////////////////////////////////////////////
632//
633// Calculate distance to surface of shape from `inside',
634// allowing for tolerance
635
637 const G4ThreeVector& v,
638 const G4bool calcNorm,
639 G4bool* validNorm,
640 G4ThreeVector* n ) const
641{
642 G4double distMin, lambda;
643 enum surface_e {kPlaneSurf, kCurvedSurf, kNoSurf} surface;
644
645 distMin = kInfinity;
646 surface = kNoSurf;
647
648 if (v.z() < 0.0)
649 {
650 lambda = (-p.z() - zTopCut)/v.z();
651
652 if ( (sqr((p.x() + lambda*v.x())/xSemiAxis) +
653 sqr((p.y() + lambda*v.y())/ySemiAxis)) <
654 sqr(zheight + zTopCut + halfCarTol) )
655 {
656 distMin = std::fabs(lambda);
657
658 if (!calcNorm) { return distMin; }
659 }
660 distMin = std::fabs(lambda);
661 surface = kPlaneSurf;
662 }
663
664 if (v.z() > 0.0)
665 {
666 lambda = (zTopCut - p.z()) / v.z();
667
668 if ( (sqr((p.x() + lambda*v.x())/xSemiAxis)
669 + sqr((p.y() + lambda*v.y())/ySemiAxis) )
670 < (sqr(zheight - zTopCut + halfCarTol)) )
671 {
672 distMin = std::fabs(lambda);
673 if (!calcNorm) { return distMin; }
674 }
675 distMin = std::fabs(lambda);
676 surface = kPlaneSurf;
677 }
678
679 // if we are here then it either intersects or grazes the
680 // curved surface...
681 //
682 G4double A = sqr(v.x()/xSemiAxis) + sqr(v.y()/ySemiAxis) - sqr(v.z());
683 G4double B = 2.*(v.x()*p.x()/sqr(xSemiAxis) +
684 v.y()*p.y()/sqr(ySemiAxis) + v.z()*(zheight-p.z()));
685 G4double C = sqr(p.x()/xSemiAxis) + sqr(p.y()/ySemiAxis)
686 - sqr(zheight - p.z());
687
688 G4double discr = B*B - 4.*A*C;
689
690 if ( discr >= - halfCarTol && discr < halfCarTol )
691 {
692 if(!calcNorm) { return distMin = std::fabs(-B/(2.*A)); }
693 }
694
695 else if ( discr > halfCarTol )
696 {
697 G4double plus = (-B+std::sqrt(discr))/(2.*A);
698 G4double minus = (-B-std::sqrt(discr))/(2.*A);
699
700 if ( plus > halfCarTol && minus > halfCarTol )
701 {
702 // take the shorter distance
703 //
704 lambda = std::fabs(plus) < std::fabs(minus) ? plus : minus;
705 }
706 else
707 {
708 // at least one solution is close to zero or negative
709 // so, take small positive solution or zero
710 //
711 lambda = plus > -halfCarTol ? plus : 0;
712 }
713
714 if ( std::fabs(lambda) < distMin )
715 {
716 if( std::fabs(lambda) > halfCarTol)
717 {
718 distMin = std::fabs(lambda);
719 surface = kCurvedSurf;
720 }
721 else // Point is On the Surface, Check Normal
722 {
723 G4ThreeVector truenorm(p.x()/(xSemiAxis*xSemiAxis),
724 p.y()/(ySemiAxis*ySemiAxis),
725 -( p.z() - zheight ));
726 if( truenorm.dot(v) > 0 )
727 {
728 distMin = 0.0;
729 surface = kCurvedSurf;
730 }
731 }
732 }
733 }
734
735 // set normal if requested
736 //
737 if (calcNorm)
738 {
739 if (surface == kNoSurf)
740 {
741 *validNorm = false;
742 }
743 else
744 {
745 *validNorm = true;
746 switch (surface)
747 {
748 case kPlaneSurf:
749 {
750 *n = G4ThreeVector(0.,0.,(v.z() > 0.0 ? 1. : -1.));
751 }
752 break;
753
754 case kCurvedSurf:
755 {
756 G4ThreeVector pexit = p + distMin*v;
757 G4ThreeVector truenorm( pexit.x()/(xSemiAxis*xSemiAxis),
758 pexit.y()/(ySemiAxis*ySemiAxis),
759 -( pexit.z() - zheight ) );
760 truenorm /= truenorm.mag();
761 *n= truenorm;
762 }
763 break;
764
765 default: // Should never reach this case ...
766 DumpInfo();
767 std::ostringstream message;
768 G4long oldprc = message.precision(16);
769 message << "Undefined side for valid surface normal to solid."
770 << G4endl
771 << "Position:" << G4endl
772 << " p.x() = " << p.x()/mm << " mm" << G4endl
773 << " p.y() = " << p.y()/mm << " mm" << G4endl
774 << " p.z() = " << p.z()/mm << " mm" << G4endl
775 << "Direction:" << G4endl
776 << " v.x() = " << v.x() << G4endl
777 << " v.y() = " << v.y() << G4endl
778 << " v.z() = " << v.z() << G4endl
779 << "Proposed distance :" << G4endl
780 << " distMin = " << distMin/mm << " mm";
781 message.precision(oldprc);
782 G4Exception("G4EllipticalCone::DistanceToOut(p,v,..)",
783 "GeomSolids1002", JustWarning, message);
784 break;
785 }
786 }
787 }
788
789 if (distMin < halfCarTol) { distMin=0; }
790
791 return distMin;
792}
793
794/////////////////////////////////////////////////////////////////////////
795//
796// Calculate distance (<=actual) to closest surface of shape from inside
797
799{
800#ifdef G4SPECSDEBUG
801 if( Inside(p) == kOutside )
802 {
803 std::ostringstream message;
804 G4long oldprc = message.precision(16);
805 message << "Point p is outside (!?) of solid: " << GetName() << "\n"
806 << "Position:\n"
807 << " p.x() = " << p.x()/mm << " mm\n"
808 << " p.y() = " << p.y()/mm << " mm\n"
809 << " p.z() = " << p.z()/mm << " mm";
810 message.precision(oldprc) ;
811 G4Exception("G4Ellipsoid::DistanceToOut(p)", "GeomSolids1002",
812 JustWarning, message);
813 DumpInfo();
814 }
815#endif
816 G4double hp = std::sqrt(p.x()*p.x()*invXX + p.y()*p.y()*invYY) + p.z();
817 G4double ds = (zheight - hp)*cosAxisMin;
818 G4double dz = zTopCut - std::abs(p.z());
819 G4double dist = std::min(ds,dz);
820 return (dist > 0) ? dist : 0.;
821}
822
823/////////////////////////////////////////////////////////////////////////
824//
825// GetEntityType
826
828{
829 return {"G4EllipticalCone"};
830}
831
832/////////////////////////////////////////////////////////////////////////
833//
834// Make a clone of the object
835
837{
838 return new G4EllipticalCone(*this);
839}
840
841/////////////////////////////////////////////////////////////////////////
842//
843// Stream object contents to an output stream
844
845std::ostream& G4EllipticalCone::StreamInfo( std::ostream& os ) const
846{
847 G4long oldprc = os.precision(16);
848 os << "-----------------------------------------------------------\n"
849 << " *** Dump for solid - " << GetName() << " ***\n"
850 << " ===================================================\n"
851 << " Solid type: G4EllipticalCone\n"
852 << " Parameters: \n"
853
854 << " semi-axis x: " << xSemiAxis/mm << " mm \n"
855 << " semi-axis y: " << ySemiAxis/mm << " mm \n"
856 << " height z: " << zheight/mm << " mm \n"
857 << " half length in z: " << zTopCut/mm << " mm \n"
858 << "-----------------------------------------------------------\n";
859 os.precision(oldprc);
860
861 return os;
862}
863
864/////////////////////////////////////////////////////////////////////////
865//
866// Return random point on the surface of the solid
867
869{
870 G4double phi = twopi*G4QuickRand();
871 G4double cosphi = std::cos(phi);
872 G4double sinphi = std::sin(phi);
873 G4double select = fSurfaceArea*G4QuickRand();
874 if (select < fMinZBaseArea + fMaxZBaseArea)
875 {
876 // elliptical bases
877 G4double z = (select < fMinZBaseArea) ? -zTopCut : zTopCut;
878 G4double a = xSemiAxis*(zheight - z);
879 G4double b = ySemiAxis*(zheight - z);
880 G4double rho = std::sqrt(G4QuickRand());
881 return { a*rho*cosphi, b*rho*sinphi, z };
882 }
883
884 // lateral surface (rejection sampling)
885 G4double ucut = zTopCut/zheight;
886 G4double a = xSemiAxis;
887 G4double b = ySemiAxis;
888 G4double h = zheight;
889 G4double aa = a*a;
890 G4double bb = b*b;
891 G4double aabb = aa*bb + bb*cosphi*cosphi + aa*sinphi*sinphi;
892 G4double ss_max = 4.*ucut*ucut*(std::max(aa, bb) + aa*bb);
893 G4double u;
894 for (auto i = 0; i < 10000; ++i)
895 {
896 u = ucut*(2.*G4QuickRand() - 1.);
897 G4double ss = (1. - u)*(1. - u)*aabb;
898 if (ss_max*sqr(G4QuickRand()) <= ss) { break; }
899 }
900 return { a*h*(1. - u)*cosphi, b*h*(1 - u)*sinphi, h*u };
901}
902
903/////////////////////////////////////////////////////////////////////////
904//
905// Get cubic volume
906
908{
909 if (fCubicVolume == 0)
910 {
911 G4AutoLock l(&elconeMutex);
912 G4double x0 = xSemiAxis*zheight; // x semi axis at z=0
913 G4double y0 = ySemiAxis*zheight; // y semi axis at z=0
914 G4double v0 = CLHEP::pi*x0*y0*zheight/3.;
915 G4double kmin = (zTopCut >= zheight ) ? 0. : (zheight - zTopCut)/zheight;
916 G4double kmax = (zTopCut >= zheight ) ? 2. : (zheight + zTopCut)/zheight;
917 fCubicVolume = (kmax - kmin)*(kmax*kmax + kmax*kmin + kmin*kmin)*v0;
918 l.unlock();
919 }
920 return fCubicVolume;
921}
922
923/////////////////////////////////////////////////////////////////////////
924//
925// Get surface area
926
928{
929 if (fSurfaceArea == 0)
930 {
931 G4AutoLock l(&elconeMutex);
932 G4double x0 = xSemiAxis*zheight; // x semi axis at z=0
933 G4double y0 = ySemiAxis*zheight; // y semi axis at z=0
935 G4double kmin = (zTopCut >= zheight ) ? 0. : (zheight - zTopCut)/zheight;
936 G4double kmax = (zTopCut >= zheight ) ? 2. : (zheight + zTopCut)/zheight;
937 fMinZBaseArea = pi*x0*y0*kmax*kmax;
938 fMaxZBaseArea = pi*x0*y0*kmin*kmin;
939 fSurfaceArea = (kmax - kmin)*(kmax + kmin)*s0 + fMinZBaseArea + fMaxZBaseArea;
940 l.unlock();
941 }
942 return fSurfaceArea;
943}
944
945/////////////////////////////////////////////////////////////////////////
946//
947// Methods for visualisation
948
950{
951 scene.AddSolid(*this);
952}
953
955{
956 // Define the sides of the box into which the solid instance would fit.
957 //
958 G4ThreeVector pmin,pmax;
959 BoundingLimits(pmin,pmax);
960 return { pmin.x(), pmax.x(), pmin.y(), pmax.y(), pmin.z(), pmax.z() };
961}
962
964{
965 return new G4PolyhedronEllipticalCone(xSemiAxis, ySemiAxis, zheight, zTopCut);
966}
967
969{
970 if ( (fpPolyhedron == nullptr)
972 || (fpPolyhedron->GetNumberOfRotationStepsAtTimeOfCreation() !=
973 fpPolyhedron->GetNumberOfRotationSteps()) )
974 {
975 G4AutoLock l(&polyhedronMutex);
976 delete fpPolyhedron;
978 fRebuildPolyhedron = false;
979 l.unlock();
980 }
981 return fpPolyhedron;
982}
983
984#endif // !defined(G4GEOM_USE_UELLIPTICALCONE) || !defined(G4GEOM_USE_SYS_USOLIDS)
G4TemplateAutoLock< G4Mutex > G4AutoLock
std::vector< G4ThreeVector > G4ThreeVectorList
G4double C(G4double temp)
G4double B(G4double temperature)
@ JustWarning
@ FatalErrorInArgument
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
G4double G4QuickRand(uint32_t seed=0)
#define G4MUTEX_INITIALIZER
std::mutex G4Mutex
CLHEP::Hep3Vector G4ThreeVector
double G4double
Definition G4Types.hh:83
long G4long
Definition G4Types.hh:87
bool G4bool
Definition G4Types.hh:86
int G4int
Definition G4Types.hh:85
G4String G4GeometryType
Definition G4VSolid.hh:70
const G4double A[17]
#define G4endl
Definition G4ios.hh:67
G4GLOB_DLL std::ostream G4cout
double z() const
Hep3Vector unit() const
double x() const
double y() const
double dot(const Hep3Vector &) const
double mag() const
void set(double x, double y, double z)
G4AffineTransform is a class for geometric affine transformations. It supports efficient arbitrary ro...
G4BoundingEnvelope is a helper class to facilitate calculation of the extent of a solid within the li...
G4bool BoundingBoxVsVoxelLimits(const EAxis pAxis, const G4VoxelLimits &pVoxelLimits, const G4Transform3D &pTransform3D, G4double &pMin, G4double &pMax) const
G4bool CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimits, const G4Transform3D &pTransform3D, G4double &pMin, G4double &pMax) const
G4bool CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimit, const G4AffineTransform &pTransform, G4double &pMin, G4double &pMax) const override
void SetSemiAxis(G4double x, G4double y, G4double z)
G4double GetSurfaceArea() override
G4VSolid * Clone() const override
EInside Inside(const G4ThreeVector &p) const override
G4double DistanceToIn(const G4ThreeVector &p, const G4ThreeVector &v) const override
G4ThreeVector SurfaceNormal(const G4ThreeVector &p) const override
G4VisExtent GetExtent() const override
void BoundingLimits(G4ThreeVector &pMin, G4ThreeVector &pMax) const override
G4EllipticalCone(const G4String &pName, G4double pxSemiAxis, G4double pySemiAxis, G4double zMax, G4double pzTopCut)
G4double GetCubicVolume() override
G4double DistanceToOut(const G4ThreeVector &p, const G4ThreeVector &v, const G4bool calcNorm=false, G4bool *validNorm=nullptr, G4ThreeVector *n=nullptr) const override
void SetZCut(G4double newzTopCut)
void DescribeYourselfTo(G4VGraphicsScene &scene) const override
G4GeometryType GetEntityType() const override
G4double GetSemiAxisX() const
G4Polyhedron * GetPolyhedron() const override
G4Polyhedron * fpPolyhedron
G4ThreeVector GetPointOnSurface() const override
G4double GetSemiAxisY() const
~G4EllipticalCone() override
std::ostream & StreamInfo(std::ostream &os) const override
G4double GetZMax() const
G4Polyhedron * CreatePolyhedron() const override
G4double GetZTopCut() const
G4EllipticalCone & operator=(const G4EllipticalCone &rhs)
static G4double EllipticConeLateralArea(G4double a, G4double b, G4double h)
virtual void AddSolid(const G4Box &)=0
G4String GetName() const
G4VSolid(const G4String &name)
Definition G4VSolid.cc:59
void DumpInfo() const
G4double kCarTolerance
Definition G4VSolid.hh:418
G4VSolid & operator=(const G4VSolid &rhs)
Definition G4VSolid.cc:108
G4VoxelLimits represents limitation/restrictions of space, where restrictions are only made perpendic...
EAxis
Definition geomdefs.hh:54
EInside
Definition geomdefs.hh:67
@ kInside
Definition geomdefs.hh:70
@ kOutside
Definition geomdefs.hh:68
@ kSurface
Definition geomdefs.hh:69
T sqr(const T &x)
Definition templates.hh:128