Geant4 11.4.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4Paraboloid.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 for G4Paraboloid class
27//
28// Author : Lukas Lindroos (CERN), July 2007
29// Revised: Tatiana Nikitina (CERN)
30// --------------------------------------------------------------------
31
32#include "globals.hh"
33
34#include "G4Paraboloid.hh"
35
36#if !(defined(G4GEOM_USE_UPARABOLOID) && defined(G4GEOM_USE_SYS_USOLIDS))
37
38#include "G4VoxelLimits.hh"
39#include "G4AffineTransform.hh"
40#include "G4BoundingEnvelope.hh"
41#include "G4QuickRand.hh"
42
43#include "G4VGraphicsScene.hh"
44#include "G4VisExtent.hh"
45
46#include "G4AutoLock.hh"
47
48namespace
49{
50 G4Mutex polyhedronMutex = G4MUTEX_INITIALIZER;
51 G4Mutex paraboloidMutex = G4MUTEX_INITIALIZER;
52}
53
54using namespace CLHEP;
55
56///////////////////////////////////////////////////////////////////////////////
57//
58// constructor - check parameters
59//
61 G4double pDz,
62 G4double pR1,
63 G4double pR2)
64 : G4VSolid(pName)
65{
66 if( (pDz <= 0.) || (pR2 <= pR1) || (pR1 < 0.) )
67 {
68 std::ostringstream message;
69 message << "Invalid dimensions. Negative Input Values or R1>=R2 - "
70 << GetName();
71 G4Exception("G4Paraboloid::G4Paraboloid()", "GeomSolids0002",
72 FatalErrorInArgument, message,
73 "Z half-length must be larger than zero or R1>=R2.");
74 }
75
76 r1 = pR1;
77 r2 = pR2;
78 dz = pDz;
79
80 // r1^2 = k1 * (-dz) + k2
81 // r2^2 = k1 * ( dz) + k2
82 // => r1^2 + r2^2 = k2 + k2 => k2 = (r2^2 + r1^2) / 2
83 // and r2^2 - r1^2 = k1 * dz - k1 * (-dz) => k1 = (r2^2 - r1^2) / 2 / dz
84
85 k1 = (r2 * r2 - r1 * r1) / 2 / dz;
86 k2 = (r2 * r2 + r1 * r1) / 2;
87
88 fSurfaceArea = CalculateSurfaceArea();
89}
90
91///////////////////////////////////////////////////////////////////////////////
92//
93// Fake default constructor - sets only member data and allocates memory
94// for usage restricted to object persistency.
95//
97 : G4VSolid(a)
98{
99}
100
101///////////////////////////////////////////////////////////////////////////////
102//
103// Destructor
104//
106{
107 delete fpPolyhedron; fpPolyhedron = nullptr;
108}
109
110///////////////////////////////////////////////////////////////////////////////
111//
112// Copy constructor
113//
115 : G4VSolid(rhs),
116 fSurfaceArea(rhs.fSurfaceArea), fCubicVolume(rhs.fCubicVolume),
117 dz(rhs.dz), r1(rhs.r1), r2(rhs.r2), k1(rhs.k1), k2(rhs.k2)
118{
119}
120
121///////////////////////////////////////////////////////////////////////////////
122//
123// Assignment operator
124//
126{
127 // Check assignment to self
128 //
129 if (this == &rhs) { return *this; }
130
131 // Copy base class data
132 //
134
135 // Copy data
136 //
137 fSurfaceArea = rhs.fSurfaceArea; fCubicVolume = rhs.fCubicVolume;
138 dz = rhs.dz; r1 = rhs.r1; r2 = rhs.r2; k1 = rhs.k1; k2 = rhs.k2;
139 fRebuildPolyhedron = false;
140 delete fpPolyhedron; fpPolyhedron = nullptr;
141
142 return *this;
143}
144
145///////////////////////////////////////////////////////////////////////////////
146//
147// Set half height
148//
150{
151 if(pDz <= 0)
152 {
153 G4Exception("G4Paraboloid::SetZHalfLength()", "GeomSolids0002",
154 FatalException, "Invalid dimensions.");
155 }
156 else
157 {
158 dz = pDz;
159 k1 = (sqr(r2) - sqr(r1)) / (2 * dz);
160 k2 = (sqr(r2) + sqr(r1)) / 2;
161 fSurfaceArea = CalculateSurfaceArea();
162 fCubicVolume = 0.;
163 fRebuildPolyhedron = true;
164 }
165}
166
167///////////////////////////////////////////////////////////////////////////////
168//
169// Set radius at z = dz
170//
172{
173 if(pR2 <= 0 || pR2 <= r1)
174 {
175 G4Exception("G4Paraboloid::SetRadiusPlusZ()", "GeomSolids0002",
176 FatalException, "Invalid dimensions.");
177 }
178 else
179 {
180 r2 = pR2;
181 k1 = (sqr(r2) - sqr(r1)) / (2 * dz);
182 k2 = (sqr(r2) + sqr(r1)) / 2;
183 fSurfaceArea = CalculateSurfaceArea();
184 fCubicVolume = 0.;
185 fRebuildPolyhedron = true;
186 }
187}
188
189///////////////////////////////////////////////////////////////////////////////
190//
191// Set radius at z = -dz
192//
194{
195 if(pR1 < 0 || pR1 >= r2)
196 {
197 G4Exception("G4Paraboloid::SetRadiusMinusZ()", "GeomSolids0002",
198 FatalException, "Invalid dimensions.");
199 }
200 else
201 {
202 r1 = pR1;
203 k1 = (sqr(r2) - sqr(r1)) / (2 * dz);
204 k2 = (sqr(r2) + sqr(r1)) / 2;
205 fSurfaceArea = CalculateSurfaceArea();
206 fCubicVolume = 0.;
207 fRebuildPolyhedron = true;
208 }
209}
210
211///////////////////////////////////////////////////////////////////////////////
212//
213// Compute surface area of the solid
214//
215G4double G4Paraboloid::CalculateSurfaceArea() const
216{
217 // Surface area for a paraboloid of height hmax
218 G4double hmax = k2/k1 + dz;
219 G4double Amax = sqr(r2) + 4*sqr(hmax);
220 Amax *= std::sqrt(Amax); // set Amax = sqrt(Amax^3)
221 Amax = CLHEP::pi * r2 / 6 / sqr(hmax) * (Amax - r2 * r2 * r2);
222
223 // Surface area for a paraboloid of height hmin
224 G4double Amin = 0.0;
225 if(r1 != 0)
226 {
227 G4double hmin = k2/k1 - dz;
228 Amin = sqr(r1) + 4*sqr(hmin);
229 Amin *= std::sqrt(Amin); // set Amin = sqrt(Amin^3)
230 Amin = CLHEP::pi * r1 / 6 / sqr(hmin) * (Amin - r1 * r1 * r1);
231 }
232 // Total surface area
233 return Amax - Amin + (sqr(r1) + sqr(r2))*CLHEP::pi;
234}
235
236///////////////////////////////////////////////////////////////////////////////
237//
238// Return surface area of the solid
239//
241{
242 if (fSurfaceArea == 0)
243 {
244 G4AutoLock l(&paraboloidMutex);
245 fSurfaceArea = CalculateSurfaceArea();
246 l.unlock();
247 }
248 return fSurfaceArea;
249}
250
251///////////////////////////////////////////////////////////////////////////////
252//
253// Return volume of the solid
254//
256{
257 if(fCubicVolume == 0)
258 {
259 G4AutoLock l(&paraboloidMutex);
260 fCubicVolume = CLHEP::pi * (sqr(r1) + sqr(r2)) * dz;
261 l.unlock();
262 }
263 return fCubicVolume;
264}
265
266///////////////////////////////////////////////////////////////////////////////
267//
268// Get bounding box
269//
271 G4ThreeVector& pMax) const
272{
273 pMin.set(-r2,-r2,-dz);
274 pMax.set( r2, r2, dz);
275
276 // Check correctness of the bounding box
277 //
278 if (pMin.x() >= pMax.x() || pMin.y() >= pMax.y() || pMin.z() >= pMax.z())
279 {
280 std::ostringstream message;
281 message << "Bad bounding box (min >= max) for solid: "
282 << GetName() << " !"
283 << "\npMin = " << pMin
284 << "\npMax = " << pMax;
285 G4Exception("G4Paraboloid::BoundingLimits()", "GeomMgt0001",
286 JustWarning, message);
287 DumpInfo();
288 }
289}
290
291///////////////////////////////////////////////////////////////////////////////
292//
293// Calculate extent under transform and specified limit
294//
295G4bool
297 const G4VoxelLimits& pVoxelLimit,
298 const G4AffineTransform& pTransform,
299 G4double& pMin, G4double& pMax) const
300{
301 G4ThreeVector bmin, bmax;
302
303 // Get bounding box
304 BoundingLimits(bmin,bmax);
305
306 // Find extent
307 G4BoundingEnvelope bbox(bmin,bmax);
308 return bbox.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax);
309}
310
311///////////////////////////////////////////////////////////////////////////////
312//
313// Return whether point inside/outside/on surface
314//
316{
317 // First check is the point is above or below the solid.
318 //
319 if(std::fabs(p.z()) > dz + 0.5 * kCarTolerance) { return kOutside; }
320
321 G4double rho2 = p.perp2(),
322 rhoSurfTimesTol2 = (k1 * p.z() + k2) * sqr(kCarTolerance),
323 A = rho2 - ((k1 *p.z() + k2) + 0.25 * kCarTolerance * kCarTolerance);
324
325 if(A < 0 && sqr(A) > rhoSurfTimesTol2)
326 {
327 // Actually checking rho < radius of paraboloid at z = p.z().
328 // We're either inside or in lower/upper cutoff area.
329
330 if(std::fabs(p.z()) > dz - 0.5 * kCarTolerance)
331 {
332 // We're in the upper/lower cutoff area, sides have a paraboloid shape
333 // maybe further checks should be made to make these nicer
334
335 return kSurface;
336 }
337 return kInside;
338 }
339 if(A <= 0 || sqr(A) < rhoSurfTimesTol2)
340 {
341 // We're in the parabolic surface.
342
343 return kSurface;
344 }
345
346 return kOutside;
347}
348
349///////////////////////////////////////////////////////////////////////////////
350//
351// SurfaceNormal
352//
354{
355 G4ThreeVector n(0, 0, 0);
356 if(std::fabs(p.z()) > dz + 0.5 * kCarTolerance)
357 {
358 // If above or below just return normal vector for the cutoff plane.
359
360 n = G4ThreeVector(0, 0, p.z()/std::fabs(p.z()));
361 }
362 else if(std::fabs(p.z()) > dz - 0.5 * kCarTolerance)
363 {
364 // This means we're somewhere in the plane z = dz or z = -dz.
365 // (As far as the program is concerned anyway.
366
367 if(p.z() < 0) // Are we in upper or lower plane?
368 {
369 if(p.perp2() > sqr(r1 + 0.5 * kCarTolerance))
370 {
371 n = G4ThreeVector(p.x(), p.y(), -k1 / 2).unit();
372 }
373 else if(r1 < 0.5 * kCarTolerance
374 || p.perp2() > sqr(r1 - 0.5 * kCarTolerance))
375 {
376 n = G4ThreeVector(p.x(), p.y(), 0.).unit()
377 + G4ThreeVector(0., 0., -1.).unit();
378 n = n.unit();
379 }
380 else
381 {
382 n = G4ThreeVector(0., 0., -1.);
383 }
384 }
385 else
386 {
387 if(p.perp2() > sqr(r2 + 0.5 * kCarTolerance))
388 {
389 n = G4ThreeVector(p.x(), p.y(), 0.).unit();
390 }
391 else if(r2 < 0.5 * kCarTolerance
392 || p.perp2() > sqr(r2 - 0.5 * kCarTolerance))
393 {
394 n = G4ThreeVector(p.x(), p.y(), 0.).unit()
395 + G4ThreeVector(0., 0., 1.).unit();
396 n = n.unit();
397 }
398 else
399 {
400 n = G4ThreeVector(0., 0., 1.);
401 }
402 }
403 }
404 else
405 {
406 G4double rho2 = p.perp2();
407 G4double rhoSurfTimesTol2 = (k1 * p.z() + k2) * sqr(kCarTolerance);
408 G4double A = rho2 - ((k1 *p.z() + k2)
409 + 0.25 * kCarTolerance * kCarTolerance);
410
411 if(A < 0 && sqr(A) > rhoSurfTimesTol2)
412 {
413 // Actually checking rho < radius of paraboloid at z = p.z().
414 // We're inside.
415
416 if(p.mag2() != 0) { n = p.unit(); }
417 }
418 else if(A <= 0 || sqr(A) < rhoSurfTimesTol2)
419 {
420 // We're in the parabolic surface.
421
422 n = G4ThreeVector(p.x(), p.y(), - k1 / 2).unit();
423 }
424 else
425 {
426 n = G4ThreeVector(p.x(), p.y(), - k1 / 2).unit();
427 }
428 }
429
430 if(n.mag2() == 0)
431 {
432 std::ostringstream message;
433 message << "No normal defined for this point p." << G4endl
434 << " p = " << 1 / mm * p << " mm";
435 G4Exception("G4Paraboloid::SurfaceNormal(p)", "GeomSolids1002",
436 JustWarning, message);
437 }
438 return n;
439}
440
441///////////////////////////////////////////////////////////////////////////////
442//
443// Calculate distance to shape from outside, along normalised vector
444// - return kInfinity if no intersection
445//
446//
448 const G4ThreeVector& v ) const
449{
450 G4double rho2 = p.perp2(), paraRho2 = std::fabs(k1 * p.z() + k2);
452 G4double tolh = 0.5*kCarTolerance;
453
454 if((r2 != 0.0) && p.z() > - tolh + dz)
455 {
456 // If the points is above check for intersection with upper edge.
457
458 if(v.z() < 0)
459 {
460 G4double intersection = (dz - p.z()) / v.z(); // With plane z = dz.
461 if(sqr(p.x() + v.x()*intersection)
462 + sqr(p.y() + v.y()*intersection) < sqr(r2 + 0.5 * kCarTolerance))
463 {
464 if(p.z() < tolh + dz) { return 0; }
465 return intersection;
466 }
467 }
468 else // Direction away, no possibility of intersection
469 {
470 return kInfinity;
471 }
472 }
473 else if((r1 != 0.0) && p.z() < tolh - dz)
474 {
475 // If the points is belove check for intersection with lower edge.
476
477 if(v.z() > 0)
478 {
479 G4double intersection = (-dz - p.z()) / v.z(); // With plane z = -dz.
480 if(sqr(p.x() + v.x()*intersection)
481 + sqr(p.y() + v.y()*intersection) < sqr(r1 + 0.5 * kCarTolerance))
482 {
483 if(p.z() > -tolh - dz) { return 0; }
484 return intersection;
485 }
486 }
487 else // Direction away, no possibility of intersection
488 {
489 return kInfinity;
490 }
491 }
492
493 G4double A = k1 / 2 * v.z() - p.x() * v.x() - p.y() * v.y(),
494 vRho2 = v.perp2(), intersection,
495 B = (k1 * p.z() + k2 - rho2) * vRho2;
496
497 if ( ( (rho2 > paraRho2) && (sqr(rho2-paraRho2-0.25*tol2) > tol2*paraRho2) )
498 || (p.z() < - dz+kCarTolerance)
499 || (p.z() > dz-kCarTolerance) ) // Make sure it's safely outside.
500 {
501 // Is there a problem with squaring rho twice?
502
503 if(vRho2<tol2) // Needs to be treated separately.
504 {
505 intersection = ((rho2 - k2)/k1 - p.z())/v.z();
506 if(intersection < 0) { return kInfinity; }
507 if(std::fabs(p.z() + v.z() * intersection) <= dz) { return intersection; }
508 return kInfinity;
509 }
510
511 if(A*A + B < 0) // No real intersections.
512 {
513 return kInfinity;
514 }
515
516 intersection = (A - std::sqrt(B + sqr(A))) / vRho2;
517 if(intersection < 0)
518 {
519 return kInfinity;
520 }
521
522 if(std::fabs(p.z() + intersection * v.z()) < dz + tolh)
523 {
524 return intersection;
525 }
526
527 return kInfinity;
528 }
529 if(sqr(rho2 - paraRho2 - .25 * tol2) <= tol2 * paraRho2)
530 {
531 // If this is true we're somewhere in the border.
532
533 G4ThreeVector normal(p.x(), p.y(), -k1/2);
534 if(normal.dot(v) <= 0) { return 0; }
535
536 return kInfinity;
537 }
538
539 std::ostringstream message;
540 if(Inside(p) == kInside)
541 {
542 message << "Point p is inside! - " << GetName() << G4endl;
543 }
544 else
545 {
546 message << "Likely a problem in this function, for solid: " << GetName()
547 << G4endl;
548 }
549 message << " p = " << p * (1/mm) << " mm" << G4endl
550 << " v = " << v * (1/mm) << " mm";
551 G4Exception("G4Paraboloid::DistanceToIn(p,v)", "GeomSolids1002",
552 JustWarning, message);
553 return 0;
554}
555
556///////////////////////////////////////////////////////////////////////////////
557//
558// Calculate distance (<= actual) to closest surface of shape from outside
559// - Return zero if point inside
560//
562{
563 G4double safz = -dz+std::fabs(p.z());
564 if(safz<0.) { safz=0.; }
565 G4double safr = kInfinity;
566
567 G4double rho = p.x()*p.x()+p.y()*p.y();
568 G4double paraRho = (p.z()-k2)/k1;
569 G4double sqrho = std::sqrt(rho);
570
571 if(paraRho<0.)
572 {
573 safr=sqrho-r2;
574 if(safr>safz) { safz=safr; }
575 return safz;
576 }
577
578 G4double sqprho = std::sqrt(paraRho);
579 G4double dRho = sqrho-sqprho;
580 if(dRho<0.) { return safz; }
581
582 G4double talf = -2.*k1*sqprho;
583 G4double tmp = 1+talf*talf;
584 if(tmp<0.) { return safz; }
585
586 G4double salf = talf/std::sqrt(tmp);
587 safr = std::fabs(dRho*salf);
588 if(safr>safz) { safz=safr; }
589
590 return safz;
591}
592
593///////////////////////////////////////////////////////////////////////////////
594//
595// Calculate distance to surface of shape from 'inside'
596//
598 const G4ThreeVector& v,
599 const G4bool calcNorm,
600 G4bool* validNorm,
601 G4ThreeVector* n ) const
602{
603 G4double rho2 = p.perp2(), paraRho2 = std::fabs(k1 * p.z() + k2);
604 G4double vRho2 = v.perp2(), intersection;
606 G4double tolh = 0.5*kCarTolerance;
607
608 if(calcNorm) { *validNorm = false; }
609
610 // We have that the particle p follows the line x = p + s * v
611 // meaning x = p.x() + s * v.x(), y = p.y() + s * v.y() and
612 // z = p.z() + s * v.z()
613 // The equation for all points on the surface (surface expanded for
614 // to include all z) x^2 + y^2 = k1 * z + k2 => .. =>
615 // => s = (A +- std::sqrt(A^2 + B)) / vRho2
616 // where:
617 //
618 G4double A = k1 / 2 * v.z() - p.x() * v.x() - p.y() * v.y();
619 //
620 // and:
621 //
622 G4double B = (-rho2 + paraRho2) * vRho2;
623
624 if ( rho2 < paraRho2 && sqr(rho2 - paraRho2 - 0.25 * tol2) > tol2 * paraRho2
625 && std::fabs(p.z()) < dz - kCarTolerance)
626 {
627 // Make sure it's safely inside.
628
629 if(v.z() > 0)
630 {
631 // It's heading upwards, check where it colides with the plane z = dz.
632 // When it does, is that in the surface of the paraboloid.
633 // z = p.z() + variable * v.z() for all points the particle can go.
634 // => variable = (z - p.z()) / v.z() so intersection must be:
635
636 intersection = (dz - p.z()) / v.z();
637 G4ThreeVector ip = p + intersection * v; // Point of intersection.
638
639 if(ip.perp2() < sqr(r2 + kCarTolerance))
640 {
641 if(calcNorm)
642 {
643 *n = G4ThreeVector(0, 0, 1);
644 if(r2 < tolh || ip.perp2() > sqr(r2 - tolh))
645 {
646 *n += G4ThreeVector(ip.x(), ip.y(), - k1 / 2).unit();
647 *n = n->unit();
648 }
649 *validNorm = true;
650 }
651 return intersection;
652 }
653 }
654 else if(v.z() < 0)
655 {
656 // It's heading downwards, check were it colides with the plane z = -dz.
657 // When it does, is that in the surface of the paraboloid.
658 // z = p.z() + variable * v.z() for all points the particle can go.
659 // => variable = (z - p.z()) / v.z() so intersection must be:
660
661 intersection = (-dz - p.z()) / v.z();
662 G4ThreeVector ip = p + intersection * v; // Point of intersection.
663
664 if(ip.perp2() < sqr(r1 + tolh))
665 {
666 if(calcNorm)
667 {
668 *n = G4ThreeVector(0, 0, -1);
669 if(r1 < tolh || ip.perp2() > sqr(r1 - tolh))
670 {
671 *n += G4ThreeVector(ip.x(), ip.y(), - k1 / 2).unit();
672 *n = n->unit();
673 }
674 *validNorm = true;
675 }
676 return intersection;
677 }
678 }
679
680 // Now check for collisions with paraboloid surface.
681
682 if(vRho2 == 0) // Needs to be treated seperately.
683 {
684 intersection = ((rho2 - k2)/k1 - p.z())/v.z();
685 if(calcNorm)
686 {
687 G4ThreeVector intersectionP = p + v * intersection;
688 *n = G4ThreeVector(intersectionP.x(), intersectionP.y(), -k1/2);
689 *n = n->unit();
690
691 *validNorm = true;
692 }
693 return intersection;
694 }
695 if( ((A <= 0) && (B >= sqr(A) * (sqr(vRho2) - 1))) || (A >= 0))
696 {
697 // intersection = (A + std::sqrt(B + sqr(A))) / vRho2;
698 // The above calculation has a precision problem:
699 // known problem of solving quadratic equation with small A
700
701 A = A/vRho2;
702 B = (k1 * p.z() + k2 - rho2)/vRho2;
703 intersection = B/(-A + std::sqrt(B + sqr(A)));
704 if(calcNorm)
705 {
706 G4ThreeVector intersectionP = p + v * intersection;
707 *n = G4ThreeVector(intersectionP.x(), intersectionP.y(), -k1/2);
708 *n = n->unit();
709 *validNorm = true;
710 }
711 return intersection;
712 }
713 std::ostringstream message;
714 message << "There is no intersection between given line and solid!"
715 << G4endl
716 << " p = " << p << G4endl
717 << " v = " << v;
718 G4Exception("G4Paraboloid::DistanceToOut(p,v,...)", "GeomSolids1002",
719 JustWarning, message);
720
721 return kInfinity;
722 }
723 if ( (rho2 < paraRho2 + kCarTolerance
724 || sqr(rho2 - paraRho2 - 0.25 * tol2) < tol2 * paraRho2 )
725 && std::fabs(p.z()) < dz + tolh)
726 {
727 // If this is true we're somewhere in the border.
728
729 G4ThreeVector normal = G4ThreeVector (p.x(), p.y(), -k1/2);
730
731 if(std::fabs(p.z()) > dz - tolh)
732 {
733 // We're in the lower or upper edge
734 //
735 if( ((v.z() > 0) && (p.z() > 0)) || ((v.z() < 0) && (p.z() < 0)) )
736 { // If we're heading out of the object that is treated here
737 if(calcNorm)
738 {
739 *validNorm = true;
740 if(p.z() > 0)
741 { *n = G4ThreeVector(0, 0, 1); }
742 else
743 { *n = G4ThreeVector(0, 0, -1); }
744 }
745 return 0;
746 }
747
748 if(v.z() == 0)
749 {
750 // Case where we're moving inside the surface needs to be
751 // treated separately.
752 // Distance until it goes out through a side is returned.
753
754 G4double r = (p.z() > 0)? r2 : r1;
755 G4double pDotV = p.dot(v);
756 A = vRho2 * ( sqr(r) - sqr(p.x()) - sqr(p.y()));
757 intersection = (-pDotV + std::sqrt(A + sqr(pDotV))) / vRho2;
758
759 if(calcNorm)
760 {
761 *validNorm = true;
762
763 *n = (G4ThreeVector(0, 0, p.z()/std::fabs(p.z()))
764 + G4ThreeVector(p.x() + v.x() * intersection, p.y() + v.y()
765 * intersection, -k1/2).unit()).unit();
766 }
767 return intersection;
768 }
769 }
770 //
771 // Problem in the Logic :: Following condition for point on upper surface
772 // and Vz<0 will return 0 (Problem #1015), but
773 // it has to return intersection with parabolic
774 // surface or with lower plane surface (z = -dz)
775 // The logic has to be :: If not found intersection until now,
776 // do not exit but continue to search for possible intersection.
777 // Only for point situated on both borders (Z and parabolic)
778 // this condition has to be taken into account and done later
779 //
780 //
781 // else if(normal.dot(v) >= 0)
782 // {
783 // if(calcNorm)
784 // {
785 // *validNorm = true;
786 // *n = normal.unit();
787 // }
788 // return 0;
789 // }
790
791 if(v.z() > 0)
792 {
793 // Check for collision with upper edge.
794
795 intersection = (dz - p.z()) / v.z();
796 G4ThreeVector ip = p + intersection * v;
797
798 if(ip.perp2() < sqr(r2 - tolh))
799 {
800 if(calcNorm)
801 {
802 *validNorm = true;
803 *n = G4ThreeVector(0, 0, 1);
804 }
805 return intersection;
806 }
807 if(ip.perp2() < sqr(r2 + tolh))
808 {
809 if(calcNorm)
810 {
811 *validNorm = true;
812 *n = G4ThreeVector(0, 0, 1)
813 + G4ThreeVector(ip.x(), ip.y(), - k1 / 2).unit();
814 *n = n->unit();
815 }
816 return intersection;
817 }
818 }
819 if( v.z() < 0)
820 {
821 // Check for collision with lower edge.
822
823 intersection = (-dz - p.z()) / v.z();
824 G4ThreeVector ip = p + intersection * v;
825
826 if(ip.perp2() < sqr(r1 - tolh))
827 {
828 if(calcNorm)
829 {
830 *validNorm = true;
831 *n = G4ThreeVector(0, 0, -1);
832 }
833 return intersection;
834 }
835 if(ip.perp2() < sqr(r1 + tolh))
836 {
837 if(calcNorm)
838 {
839 *validNorm = true;
840 *n = G4ThreeVector(0, 0, -1)
841 + G4ThreeVector(ip.x(), ip.y(), - k1 / 2).unit();
842 *n = n->unit();
843 }
844 return intersection;
845 }
846 }
847
848 // Note: comparison with zero below would not be correct !
849 //
850 if(std::fabs(vRho2) > tol2) // precision error in the calculation of
851 { // intersection = (A+std::sqrt(B+sqr(A)))/vRho2
852 A = A/vRho2;
853 B = (k1 * p.z() + k2 - rho2);
854 if(std::fabs(B)>kCarTolerance)
855 {
856 B = (B)/vRho2;
857 intersection = B/(-A + std::sqrt(B + sqr(A)));
858 }
859 else // Point is On both borders: Z and parabolic
860 { // solution depends on normal.dot(v) sign
861 if(normal.dot(v) >= 0)
862 {
863 if(calcNorm)
864 {
865 *validNorm = true;
866 *n = normal.unit();
867 }
868 return 0;
869 }
870 intersection = 2.*A;
871 }
872 }
873 else
874 {
875 intersection = ((rho2 - k2) / k1 - p.z()) / v.z();
876 }
877
878 if(calcNorm)
879 {
880 *validNorm = true;
881 *n = G4ThreeVector(p.x() + intersection * v.x(), p.y()
882 + intersection * v.y(), - k1 / 2);
883 *n = n->unit();
884 }
885 return intersection;
886 }
887
888#ifdef G4SPECSDEBUG
889 if(kOutside == Inside(p))
890 {
891 G4Exception("G4Paraboloid::DistanceToOut(p,v,...)", "GeomSolids1002",
892 JustWarning, "Point p is outside!");
893 }
894 G4Exception("G4Paraboloid::DistanceToOut(p,v,...)", "GeomSolids1002",
895 JustWarning, "There's an error in this functions code.");
896#endif
897 return kInfinity;
898}
899
900///////////////////////////////////////////////////////////////////////////////
901//
902// Calculate distance (<=actual) to closest surface of shape from inside
903//
905{
906 G4double safe=0.0,rho,safeR,safeZ ;
907 G4double tanRMax,secRMax,pRMax ;
908
909#ifdef G4SPECSDEBUG
910 if( Inside(p) == kOutside )
911 {
912 G4cout << G4endl ;
913 DumpInfo();
914 std::ostringstream message;
915 G4long oldprc = message.precision(16);
916 message << "Point p is outside !?" << G4endl
917 << "Position:" << G4endl
918 << " p.x() = " << p.x()/mm << " mm" << G4endl
919 << " p.y() = " << p.y()/mm << " mm" << G4endl
920 << " p.z() = " << p.z()/mm << " mm";
921 message.precision(oldprc) ;
922 G4Exception("G4Paraboloid::DistanceToOut(p)", "GeomSolids1002",
923 JustWarning, message);
924 }
925#endif
926
927 rho = p.perp();
928 safeZ = dz - std::fabs(p.z()) ;
929
930 tanRMax = (r2 - r1)*0.5/dz ;
931 secRMax = std::sqrt(1.0 + tanRMax*tanRMax) ;
932 pRMax = tanRMax*p.z() + (r1+r2)*0.5 ;
933 safeR = (pRMax - rho)/secRMax ;
934
935 if (safeZ < safeR) { safe = safeZ; }
936 else { safe = safeR; }
937 if ( safe < 0.5 * kCarTolerance ) { safe = 0; }
938 return safe ;
939}
940
941///////////////////////////////////////////////////////////////////////////////
942//
943// G4EntityType
944//
946{
947 return {"G4Paraboloid"};
948}
949
950///////////////////////////////////////////////////////////////////////////////
951//
952// Make a clone of the object
953//
955{
956 return new G4Paraboloid(*this);
957}
958
959///////////////////////////////////////////////////////////////////////////////
960//
961// Stream object contents to an output stream
962//
963std::ostream& G4Paraboloid::StreamInfo( std::ostream& os ) const
964{
965 G4long oldprc = os.precision(16);
966 os << "-----------------------------------------------------------\n"
967 << " *** Dump for solid - " << GetName() << " ***\n"
968 << " ===================================================\n"
969 << " Solid type: G4Paraboloid\n"
970 << " Parameters: \n"
971 << " z half-axis: " << dz/mm << " mm \n"
972 << " radius at -dz: " << r1/mm << " mm \n"
973 << " radius at dz: " << r2/mm << " mm \n"
974 << "-----------------------------------------------------------\n";
975 os.precision(oldprc);
976
977 return os;
978}
979
980///////////////////////////////////////////////////////////////////////////////
981//
982// GetPointOnSurface
983//
985{
986 G4double phi = twopi*G4QuickRand();
987 G4double select = fSurfaceArea*G4QuickRand();
988 G4double z, rho;
989 if (select < pi*(sqr(r1) + sqr(r2)))
990 {
991 if(select < pi*sqr(r1))
992 {
993 z = -dz;
994 rho = r1*std::sqrt(G4QuickRand());
995 }
996 else
997 {
998 z = dz;
999 rho = r2*std::sqrt(G4QuickRand());
1000 }
1001 }
1002 else
1003 {
1004 // rejection sampling
1005 G4double mu_max = dz*k1 + k2 + 0.25*k1; // max surface element squared
1006 for (auto i = 0; i < 10000; ++i)
1007 {
1008 z = dz*(2*G4QuickRand() - 1);
1009 G4double mu = z*k1 + k2 + 0.25*k1; // surface element squared
1010 if (mu_max*sqr(G4QuickRand()) <= mu) { break; }
1011 }
1012 rho = std::sqrt(z*k1 + k2);
1013 }
1014 return { rho*std::cos(phi), rho*std::sin(phi), z };
1015}
1016
1017///////////////////////////////////////////////////////////////////////////////
1018//
1019// Methods for visualisation
1020//
1022{
1023 scene.AddSolid(*this);
1024}
1025
1027{
1028 return new G4PolyhedronParaboloid(r1, r2, dz, 0., twopi);
1029}
1030
1032{
1033 if (fpPolyhedron == nullptr ||
1034 fRebuildPolyhedron ||
1035 fpPolyhedron->GetNumberOfRotationStepsAtTimeOfCreation() !=
1036 fpPolyhedron->GetNumberOfRotationSteps())
1037 {
1038 G4AutoLock l(&polyhedronMutex);
1039 delete fpPolyhedron;
1040 fpPolyhedron = CreatePolyhedron();
1041 fRebuildPolyhedron = false;
1042 l.unlock();
1043 }
1044 return fpPolyhedron;
1045}
1046
1047#endif // !defined(G4GEOM_USE_UPARABOLOID) || !defined(G4GEOM_USE_SYS_USOLIDS)
G4TemplateAutoLock< G4Mutex > G4AutoLock
G4double B(G4double temperature)
@ JustWarning
@ FatalException
@ 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
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 mag2() const
double y() const
double dot(const Hep3Vector &) const
double perp2() const
void set(double x, double y, double z)
double perp() const
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 CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimits, const G4Transform3D &pTransform3D, G4double &pMin, G4double &pMax) const
G4ThreeVector SurfaceNormal(const G4ThreeVector &p) const override
G4ThreeVector GetPointOnSurface() const override
~G4Paraboloid() override
G4VSolid * Clone() const override
G4double GetSurfaceArea() override
G4double DistanceToIn(const G4ThreeVector &p, const G4ThreeVector &v) const override
std::ostream & StreamInfo(std::ostream &os) const override
G4Polyhedron * GetPolyhedron() const override
void SetZHalfLength(G4double dz)
G4bool CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimit, const G4AffineTransform &pTransform, G4double &pmin, G4double &pmax) const override
G4double GetCubicVolume() override
G4Paraboloid(const G4String &pName, G4double pDz, G4double pR1, G4double pR2)
void SetRadiusPlusZ(G4double R2)
G4GeometryType GetEntityType() const override
G4double DistanceToOut(const G4ThreeVector &p, const G4ThreeVector &v, const G4bool calcNorm=false, G4bool *validNorm=nullptr, G4ThreeVector *n=nullptr) const override
G4Polyhedron * CreatePolyhedron() const override
G4Paraboloid & operator=(const G4Paraboloid &rhs)
EInside Inside(const G4ThreeVector &p) const override
void BoundingLimits(G4ThreeVector &pMin, G4ThreeVector &pMax) const override
void SetRadiusMinusZ(G4double R1)
void DescribeYourselfTo(G4VGraphicsScene &scene) const override
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