Geant4 11.1.1
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4CutTubs.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// G4CutTubs implementation
27//
28// 01.06.11 T.Nikitina - Derived from G4Tubs
29// 30.10.16 E.Tcherniaev - reimplemented CalculateExtent(),
30// removed CreateRotatedVetices()
31// --------------------------------------------------------------------
32
33#include "G4CutTubs.hh"
34
35#if !defined(G4GEOM_USE_UCTUBS)
36
37#include "G4GeomTools.hh"
38#include "G4VoxelLimits.hh"
39#include "G4AffineTransform.hh"
41#include "G4BoundingEnvelope.hh"
42
44#include "G4QuickRand.hh"
45
46#include "G4VGraphicsScene.hh"
47#include "G4Polyhedron.hh"
48
49#include "G4AutoLock.hh"
50
51namespace
52{
53 G4Mutex zminmaxMutex = G4MUTEX_INITIALIZER;
54}
55
56using namespace CLHEP;
57
58/////////////////////////////////////////////////////////////////////////
59//
60// Constructor - check parameters, convert angles so 0<sphi+dpshi<=2_PI
61// - note if pdphi>2PI then reset to 2PI
62
64 G4double pRMin, G4double pRMax,
65 G4double pDz,
66 G4double pSPhi, G4double pDPhi,
67 G4ThreeVector pLowNorm,G4ThreeVector pHighNorm )
68 : G4CSGSolid(pName), fRMin(pRMin), fRMax(pRMax), fDz(pDz),
69 fSPhi(0.), fDPhi(0.), fZMin(0.), fZMax(0.)
70{
73
74 halfCarTolerance = kCarTolerance*0.5;
75 halfRadTolerance = kRadTolerance*0.5;
76 halfAngTolerance = kAngTolerance*0.5;
77
78 if (pDz<=0) // Check z-len
79 {
80 std::ostringstream message;
81 message << "Negative Z half-length (" << pDz << ") in solid: " << GetName();
82 G4Exception("G4CutTubs::G4CutTubs()", "GeomSolids0002", FatalException, message);
83 }
84 if ( (pRMin >= pRMax) || (pRMin < 0) ) // Check radii
85 {
86 std::ostringstream message;
87 message << "Invalid values for radii in solid: " << GetName()
88 << G4endl
89 << " pRMin = " << pRMin << ", pRMax = " << pRMax;
90 G4Exception("G4CutTubs::G4CutTubs()", "GeomSolids0002", FatalException, message);
91 }
92
93 // Check angles
94 //
95 CheckPhiAngles(pSPhi, pDPhi);
96
97 // Check on Cutted Planes Normals
98 // If there is NO CUT, propose to use G4Tubs instead
99 //
100 if ( ( !pLowNorm.x()) && ( !pLowNorm.y())
101 && ( !pHighNorm.x()) && (!pHighNorm.y()) )
102 {
103 std::ostringstream message;
104 message << "Inexisting Low/High Normal to Z plane or Parallel to Z."
105 << G4endl
106 << "Normals to Z plane are " << pLowNorm << " and "
107 << pHighNorm << " in solid: " << GetName() << " \n";
108 G4Exception("G4CutTubs::G4CutTubs()", "GeomSolids1001",
109 JustWarning, message, "Should use G4Tubs!");
110 }
111
112 // If Normal is (0,0,0),means parallel to R, give it value of (0,0,+/-1)
113 //
114 if (pLowNorm.mag2() == 0.) { pLowNorm.setZ(-1.); }
115 if (pHighNorm.mag2()== 0.) { pHighNorm.setZ(1.); }
116
117 // Given Normals to Cut Planes have to be an unit vectors.
118 // Normalize if it is needed.
119 //
120 if (pLowNorm.mag2() != 1.) { pLowNorm = pLowNorm.unit(); }
121 if (pHighNorm.mag2()!= 1.) { pHighNorm = pHighNorm.unit(); }
122
123 // Normals to cutted planes have to point outside Solid
124 //
125 if( (pLowNorm.mag2() != 0.) && (pHighNorm.mag2()!= 0. ) )
126 {
127 if( ( pLowNorm.z()>= 0. ) || ( pHighNorm.z() <= 0.))
128 {
129 std::ostringstream message;
130 message << "Invalid Low or High Normal to Z plane; "
131 "has to point outside Solid." << G4endl
132 << "Invalid Norm to Z plane (" << pLowNorm << " or "
133 << pHighNorm << ") in solid: " << GetName();
134 G4Exception("G4CutTubs::G4CutTubs()", "GeomSolids0002",
135 FatalException, message);
136 }
137 }
138 fLowNorm = pLowNorm;
139 fHighNorm = pHighNorm;
140
141 // Check intersection of cut planes, they MUST NOT intersect
142 // each other inside the lateral surface
143 //
145 {
146 std::ostringstream message;
147 message << "Invalid normals to Z plane in solid : " << GetName() << G4endl
148 << "Cut planes are crossing inside lateral surface !!!\n"
149 << " Solid type: G4CutTubs\n"
150 << " Parameters: \n"
151 << " inner radius : " << fRMin/mm << " mm \n"
152 << " outer radius : " << fRMax/mm << " mm \n"
153 << " half length Z: " << fDz/mm << " mm \n"
154 << " starting phi : " << fSPhi/degree << " degrees \n"
155 << " delta phi : " << fDPhi/degree << " degrees \n"
156 << " low Norm : " << fLowNorm << " \n"
157 << " high Norm : " << fHighNorm;
158 G4Exception("G4CutTubs::G4CutTubs()", "GeomSolids0002",
159 FatalException, message);
160 }
161}
162
163///////////////////////////////////////////////////////////////////////
164//
165// Fake default constructor - sets only member data and allocates memory
166// for usage restricted to object persistency.
167//
169 : G4CSGSolid(a), kRadTolerance(0.), kAngTolerance(0.),
170 fRMin(0.), fRMax(0.), fDz(0.), fSPhi(0.), fDPhi(0.), fZMin(0.), fZMax(0.),
171 sinCPhi(0.), cosCPhi(0.), cosHDPhi(0.), cosHDPhiOT(0.), cosHDPhiIT(0.),
172 sinSPhi(0.), cosSPhi(0.), sinEPhi(0.), cosEPhi(0.),
173 halfCarTolerance(0.), halfRadTolerance(0.), halfAngTolerance(0.),
174 fLowNorm(G4ThreeVector()), fHighNorm(G4ThreeVector())
175{
176}
177
178//////////////////////////////////////////////////////////////////////////
179//
180// Destructor
181
183{
184}
185
186//////////////////////////////////////////////////////////////////////////
187//
188// Copy constructor
189
191 : G4CSGSolid(rhs),
192 kRadTolerance(rhs.kRadTolerance), kAngTolerance(rhs.kAngTolerance),
193 fRMin(rhs.fRMin), fRMax(rhs.fRMax), fDz(rhs.fDz),
194 fSPhi(rhs.fSPhi), fDPhi(rhs.fDPhi),
195 fZMin(rhs.fZMin), fZMax(rhs.fZMax),
196 sinCPhi(rhs.sinCPhi), cosCPhi(rhs.cosCPhi), cosHDPhi(rhs.cosHDPhi),
197 cosHDPhiOT(rhs.cosHDPhiOT), cosHDPhiIT(rhs.cosHDPhiIT),
198 sinSPhi(rhs.sinSPhi), cosSPhi(rhs.cosSPhi),
199 sinEPhi(rhs.sinEPhi), cosEPhi(rhs.cosEPhi),
200 fPhiFullCutTube(rhs.fPhiFullCutTube),
201 halfCarTolerance(rhs.halfCarTolerance),
202 halfRadTolerance(rhs.halfRadTolerance),
203 halfAngTolerance(rhs.halfAngTolerance),
204 fLowNorm(rhs.fLowNorm), fHighNorm(rhs.fHighNorm)
205{
206}
207
208//////////////////////////////////////////////////////////////////////////
209//
210// Assignment operator
211
213{
214 // Check assignment to self
215 //
216 if (this == &rhs) { return *this; }
217
218 // Copy base class data
219 //
221
222 // Copy data
223 //
224 kRadTolerance = rhs.kRadTolerance; kAngTolerance = rhs.kAngTolerance;
225 fRMin = rhs.fRMin; fRMax = rhs.fRMax; fDz = rhs.fDz;
226 fSPhi = rhs.fSPhi; fDPhi = rhs.fDPhi;
227 fZMin = rhs.fZMin; fZMax = rhs.fZMax;
228 sinCPhi = rhs.sinCPhi; cosCPhi = rhs.cosCPhi;
229 cosHDPhiOT = rhs.cosHDPhiOT; cosHDPhiIT = rhs.cosHDPhiIT;
230 sinSPhi = rhs.sinSPhi; cosSPhi = rhs.cosSPhi;
231 sinEPhi = rhs.sinEPhi; cosEPhi = rhs.cosEPhi;
232 fPhiFullCutTube = rhs.fPhiFullCutTube;
233 halfCarTolerance = rhs.halfCarTolerance;
234 halfRadTolerance = rhs.halfRadTolerance;
235 halfAngTolerance = rhs.halfAngTolerance;
236 fLowNorm = rhs.fLowNorm; fHighNorm = rhs.fHighNorm;
237
238 return *this;
239}
240
241//////////////////////////////////////////////////////////////////////////
242//
243// Get volume
244
246{
247 constexpr G4int nphi = 200, nrho = 100;
248
249 if (fCubicVolume == 0.)
250 {
251 // get parameters
252 G4double rmin = GetInnerRadius();
253 G4double rmax = GetOuterRadius();
255 G4double sphi = GetStartPhiAngle();
256 G4double dphi = GetDeltaPhiAngle();
257
258 // calculate volume
259 G4double volume = dz*dphi*(rmax*rmax - rmin*rmin);
260 if (dphi < twopi) // make recalculation
261 {
262 // set values for calculation of h - distance between
263 // opposite points on bases
264 G4ThreeVector nbot = GetLowNorm();
265 G4ThreeVector ntop = GetHighNorm();
266 G4double nx = nbot.x()/nbot.z() - ntop.x()/ntop.z();
267 G4double ny = nbot.y()/nbot.z() - ntop.y()/ntop.z();
268
269 // compute volume by integration
270 G4double delrho = (rmax - rmin)/nrho;
271 G4double delphi = dphi/nphi;
272 volume = 0.;
273 for (G4int irho=0; irho<nrho; ++irho)
274 {
275 G4double r1 = rmin + delrho*irho;
276 G4double r2 = rmin + delrho*(irho + 1);
277 G4double rho = 0.5*(r1 + r2);
278 G4double sector = 0.5*delphi*(r2*r2 - r1*r1);
279 for (G4int iphi=0; iphi<nphi; ++iphi)
280 {
281 G4double phi = sphi + delphi*(iphi + 0.5);
282 G4double h = nx*rho*std::cos(phi) + ny*rho*std::sin(phi) + 2.*dz;
283 volume += sector*h;
284 }
285 }
286 }
287 fCubicVolume = volume;
288 }
289 return fCubicVolume;
290}
291
292//////////////////////////////////////////////////////////////////////////
293//
294// Get surface area
295
297{
298 constexpr G4int nphi = 400;
299
300 if (fSurfaceArea == 0.)
301 {
302 // get parameters
303 G4double rmin = GetInnerRadius();
304 G4double rmax = GetOuterRadius();
306 G4double sphi = GetStartPhiAngle();
307 G4double dphi = GetDeltaPhiAngle();
308 G4ThreeVector nbot = GetLowNorm();
309 G4ThreeVector ntop = GetHighNorm();
310
311 // calculate lateral surface area
312 G4double sinner = 2.*dz*dphi*rmin;
313 G4double souter = 2.*dz*dphi*rmax;
314 if (dphi < twopi) // make recalculation
315 {
316 // set values for calculation of h - distance between
317 // opposite points on bases
318 G4double nx = nbot.x()/nbot.z() - ntop.x()/ntop.z();
319 G4double ny = nbot.y()/nbot.z() - ntop.y()/ntop.z();
320
321 // compute lateral surface area by integration
322 G4double delphi = dphi/nphi;
323 sinner = 0.;
324 souter = 0.;
325 for (G4int iphi=0; iphi<nphi; ++iphi)
326 {
327 G4double phi = sphi + delphi*(iphi + 0.5);
328 G4double cosphi = std::cos(phi);
329 G4double sinphi = std::sin(phi);
330 sinner += rmin*(nx*cosphi + ny*sinphi) + 2.*dz;
331 souter += rmax*(nx*cosphi + ny*sinphi) + 2.*dz;
332 }
333 sinner *= delphi*rmin;
334 souter *= delphi*rmax;
335 }
336 // set surface area
337 G4double scut = (dphi == twopi) ? 0. : 2.*dz*(rmax - rmin);
338 G4double szero = 0.5*dphi*(rmax*rmax - rmin*rmin);
339 G4double slow = szero/std::abs(nbot.z());
340 G4double shigh = szero/std::abs(ntop.z());
341 fSurfaceArea = sinner + souter + 2.*scut + slow + shigh;
342 }
343 return fSurfaceArea;
344}
345
346//////////////////////////////////////////////////////////////////////////
347//
348// Get bounding box
349
351{
352 G4double rmin = GetInnerRadius();
353 G4double rmax = GetOuterRadius();
355 G4double dphi = GetDeltaPhiAngle();
356
357 G4double sinSphi = GetSinStartPhi();
358 G4double cosSphi = GetCosStartPhi();
359 G4double sinEphi = GetSinEndPhi();
360 G4double cosEphi = GetCosEndPhi();
361
362 G4ThreeVector norm;
363 G4double mag, topx, topy, dists, diste;
364 G4bool iftop;
365
366 // Find Zmin
367 //
368 G4double zmin;
369 norm = GetLowNorm();
370 mag = std::sqrt(norm.x()*norm.x() + norm.y()*norm.y());
371 topx = (mag == 0) ? 0 : -rmax*norm.x()/mag;
372 topy = (mag == 0) ? 0 : -rmax*norm.y()/mag;
373 dists = sinSphi*topx - cosSphi*topy;
374 diste = -sinEphi*topx + cosEphi*topy;
375 if (dphi > pi)
376 {
377 iftop = true;
378 if (dists > 0 && diste > 0)iftop = false;
379 }
380 else
381 {
382 iftop = false;
383 if (dists <= 0 && diste <= 0) iftop = true;
384 }
385 if (iftop)
386 {
387 zmin = -(norm.x()*topx + norm.y()*topy)/norm.z() - dz;
388 }
389 else
390 {
391 G4double z1 = -rmin*(norm.x()*cosSphi + norm.y()*sinSphi)/norm.z() - dz;
392 G4double z2 = -rmin*(norm.x()*cosEphi + norm.y()*sinEphi)/norm.z() - dz;
393 G4double z3 = -rmax*(norm.x()*cosSphi + norm.y()*sinSphi)/norm.z() - dz;
394 G4double z4 = -rmax*(norm.x()*cosEphi + norm.y()*sinEphi)/norm.z() - dz;
395 zmin = std::min(std::min(std::min(z1,z2),z3),z4);
396 }
397
398 // Find Zmax
399 //
400 G4double zmax;
401 norm = GetHighNorm();
402 mag = std::sqrt(norm.x()*norm.x() + norm.y()*norm.y());
403 topx = (mag == 0) ? 0 : -rmax*norm.x()/mag;
404 topy = (mag == 0) ? 0 : -rmax*norm.y()/mag;
405 dists = sinSphi*topx - cosSphi*topy;
406 diste = -sinEphi*topx + cosEphi*topy;
407 if (dphi > pi)
408 {
409 iftop = true;
410 if (dists > 0 && diste > 0) iftop = false;
411 }
412 else
413 {
414 iftop = false;
415 if (dists <= 0 && diste <= 0) iftop = true;
416 }
417 if (iftop)
418 {
419 zmax = -(norm.x()*topx + norm.y()*topy)/norm.z() + dz;
420 }
421 else
422 {
423 G4double z1 = -rmin*(norm.x()*cosSphi + norm.y()*sinSphi)/norm.z() + dz;
424 G4double z2 = -rmin*(norm.x()*cosEphi + norm.y()*sinEphi)/norm.z() + dz;
425 G4double z3 = -rmax*(norm.x()*cosSphi + norm.y()*sinSphi)/norm.z() + dz;
426 G4double z4 = -rmax*(norm.x()*cosEphi + norm.y()*sinEphi)/norm.z() + dz;
427 zmax = std::max(std::max(std::max(z1,z2),z3),z4);
428 }
429
430 // Find bounding box
431 //
432 if (dphi < twopi)
433 {
434 G4TwoVector vmin,vmax;
435 G4GeomTools::DiskExtent(rmin,rmax,
438 vmin,vmax);
439 pMin.set(vmin.x(),vmin.y(), zmin);
440 pMax.set(vmax.x(),vmax.y(), zmax);
441 }
442 else
443 {
444 pMin.set(-rmax,-rmax, zmin);
445 pMax.set( rmax, rmax, zmax);
446 }
447
448 // Check correctness of the bounding box
449 //
450 if (pMin.x() >= pMax.x() || pMin.y() >= pMax.y() || pMin.z() >= pMax.z())
451 {
452 std::ostringstream message;
453 message << "Bad bounding box (min >= max) for solid: "
454 << GetName() << " !"
455 << "\npMin = " << pMin
456 << "\npMax = " << pMax;
457 G4Exception("G4CutTubs::BoundingLimits()", "GeomMgt0001",
458 JustWarning, message);
459 DumpInfo();
460 }
461}
462
463//////////////////////////////////////////////////////////////////////////
464//
465// Calculate extent under transform and specified limit
466
468 const G4VoxelLimits& pVoxelLimit,
469 const G4AffineTransform& pTransform,
470 G4double& pMin,
471 G4double& pMax ) const
472{
473 G4ThreeVector bmin, bmax;
474 G4bool exist;
475
476 // Get bounding box
477 BoundingLimits(bmin,bmax);
478
479 // Check bounding box
480 G4BoundingEnvelope bbox(bmin,bmax);
481#ifdef G4BBOX_EXTENT
482 return bbox.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax);
483#endif
484 if (bbox.BoundingBoxVsVoxelLimits(pAxis,pVoxelLimit,pTransform,pMin,pMax))
485 {
486 return exist = (pMin < pMax) ? true : false;
487 }
488
489 // Get parameters of the solid
490 G4double rmin = GetInnerRadius();
491 G4double rmax = GetOuterRadius();
492 G4double dphi = GetDeltaPhiAngle();
493 G4double zmin = bmin.z();
494 G4double zmax = bmax.z();
495
496 // Find bounding envelope and calculate extent
497 //
498 const G4int NSTEPS = 24; // number of steps for whole circle
499 G4double astep = twopi/NSTEPS; // max angle for one step
500 G4int ksteps = (dphi <= astep) ? 1 : (G4int)((dphi-deg)/astep) + 1;
501 G4double ang = dphi/ksteps;
502
503 G4double sinHalf = std::sin(0.5*ang);
504 G4double cosHalf = std::cos(0.5*ang);
505 G4double sinStep = 2.*sinHalf*cosHalf;
506 G4double cosStep = 1. - 2.*sinHalf*sinHalf;
507 G4double rext = rmax/cosHalf;
508
509 // bounding envelope for full cylinder consists of two polygons,
510 // in other cases it is a sequence of quadrilaterals
511 if (rmin == 0 && dphi == twopi)
512 {
513 G4double sinCur = sinHalf;
514 G4double cosCur = cosHalf;
515
516 G4ThreeVectorList baseA(NSTEPS),baseB(NSTEPS);
517 for (G4int k=0; k<NSTEPS; ++k)
518 {
519 baseA[k].set(rext*cosCur,rext*sinCur,zmin);
520 baseB[k].set(rext*cosCur,rext*sinCur,zmax);
521
522 G4double sinTmp = sinCur;
523 sinCur = sinCur*cosStep + cosCur*sinStep;
524 cosCur = cosCur*cosStep - sinTmp*sinStep;
525 }
526 std::vector<const G4ThreeVectorList *> polygons(2);
527 polygons[0] = &baseA;
528 polygons[1] = &baseB;
529 G4BoundingEnvelope benv(bmin,bmax,polygons);
530 exist = benv.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax);
531 }
532 else
533 {
534 G4double sinStart = GetSinStartPhi();
535 G4double cosStart = GetCosStartPhi();
536 G4double sinEnd = GetSinEndPhi();
537 G4double cosEnd = GetCosEndPhi();
538 G4double sinCur = sinStart*cosHalf + cosStart*sinHalf;
539 G4double cosCur = cosStart*cosHalf - sinStart*sinHalf;
540
541 // set quadrilaterals
542 G4ThreeVectorList pols[NSTEPS+2];
543 for (G4int k=0; k<ksteps+2; ++k) pols[k].resize(4);
544 pols[0][0].set(rmin*cosStart,rmin*sinStart,zmax);
545 pols[0][1].set(rmin*cosStart,rmin*sinStart,zmin);
546 pols[0][2].set(rmax*cosStart,rmax*sinStart,zmin);
547 pols[0][3].set(rmax*cosStart,rmax*sinStart,zmax);
548 for (G4int k=1; k<ksteps+1; ++k)
549 {
550 pols[k][0].set(rmin*cosCur,rmin*sinCur,zmax);
551 pols[k][1].set(rmin*cosCur,rmin*sinCur,zmin);
552 pols[k][2].set(rext*cosCur,rext*sinCur,zmin);
553 pols[k][3].set(rext*cosCur,rext*sinCur,zmax);
554
555 G4double sinTmp = sinCur;
556 sinCur = sinCur*cosStep + cosCur*sinStep;
557 cosCur = cosCur*cosStep - sinTmp*sinStep;
558 }
559 pols[ksteps+1][0].set(rmin*cosEnd,rmin*sinEnd,zmax);
560 pols[ksteps+1][1].set(rmin*cosEnd,rmin*sinEnd,zmin);
561 pols[ksteps+1][2].set(rmax*cosEnd,rmax*sinEnd,zmin);
562 pols[ksteps+1][3].set(rmax*cosEnd,rmax*sinEnd,zmax);
563
564 // set envelope and calculate extent
565 std::vector<const G4ThreeVectorList *> polygons;
566 polygons.resize(ksteps+2);
567 for (G4int k=0; k<ksteps+2; ++k) { polygons[k] = &pols[k]; }
568 G4BoundingEnvelope benv(bmin,bmax,polygons);
569 exist = benv.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax);
570 }
571 return exist;
572}
573
574//////////////////////////////////////////////////////////////////////////
575//
576// Return whether point inside/outside/on surface
577
579{
580 G4ThreeVector vZ = G4ThreeVector(0,0,fDz);
581 EInside in = kInside;
582
583 // Check the lower cut plane
584 //
585 G4double zinLow =(p+vZ).dot(fLowNorm);
586 if (zinLow > halfCarTolerance) { return kOutside; }
587
588 // Check the higher cut plane
589 //
590 G4double zinHigh = (p-vZ).dot(fHighNorm);
591 if (zinHigh > halfCarTolerance) { return kOutside; }
592
593 // Check radius
594 //
595 G4double r2 = p.x()*p.x() + p.y()*p.y() ;
596
597 G4double tolRMin = fRMin - halfRadTolerance;
598 G4double tolRMax = fRMax + halfRadTolerance;
599 if ( tolRMin < 0 ) { tolRMin = 0; }
600
601 if (r2 < tolRMin*tolRMin || r2 > tolRMax*tolRMax) { return kOutside; }
602
603 // Check Phi cut
604 //
605 if(!fPhiFullCutTube)
606 {
607 if ((tolRMin == 0) && (std::fabs(p.x()) <= halfCarTolerance)
608 && (std::fabs(p.y()) <= halfCarTolerance))
609 {
610 return kSurface;
611 }
612
613 G4double phi0 = std::atan2(p.y(),p.x());
614 G4double phi1 = phi0 - twopi;
615 G4double phi2 = phi0 + twopi;
616
617 in = kOutside;
618 G4double sphi = fSPhi - halfAngTolerance;
619 G4double ephi = sphi + fDPhi + kAngTolerance;
620 if ((phi0 >= sphi && phi0 <= ephi) ||
621 (phi1 >= sphi && phi1 <= ephi) ||
622 (phi2 >= sphi && phi2 <= ephi)) in = kSurface;
623 if (in == kOutside) { return kOutside; }
624
625 sphi += kAngTolerance;
626 ephi -= kAngTolerance;
627 if ((phi0 >= sphi && phi0 <= ephi) ||
628 (phi1 >= sphi && phi1 <= ephi) ||
629 (phi2 >= sphi && phi2 <= ephi)) in = kInside;
630 if (in == kSurface) { return kSurface; }
631 }
632
633 // Check on the Surface for Z
634 //
635 if ((zinLow >= -halfCarTolerance) || (zinHigh >= -halfCarTolerance))
636 {
637 return kSurface;
638 }
639
640 // Check on the Surface for R
641 //
642 if (fRMin) { tolRMin = fRMin + halfRadTolerance; }
643 else { tolRMin = 0; }
644 tolRMax = fRMax - halfRadTolerance;
645 if (((r2 <= tolRMin*tolRMin) || (r2 >= tolRMax*tolRMax)) &&
646 (r2 >= halfRadTolerance*halfRadTolerance))
647 {
648 return kSurface;
649 }
650
651 return in;
652}
653
654///////////////////////////////////////////////////////////////////////////
655//
656// Return unit normal of surface closest to p
657// - note if point on z axis, ignore phi divided sides
658// - unsafe if point close to z axis a rmin=0 - no explicit checks
659
661{
662 G4int noSurfaces = 0;
663 G4double rho, pPhi;
664 G4double distZLow,distZHigh, distRMin, distRMax;
665 G4double distSPhi = kInfinity, distEPhi = kInfinity;
666 G4ThreeVector vZ=G4ThreeVector(0,0,fDz);
667
668 G4ThreeVector norm, sumnorm(0.,0.,0.);
669 G4ThreeVector nZ = G4ThreeVector(0, 0, 1.0);
670 G4ThreeVector nR, nPs, nPe;
671
672 rho = std::sqrt(p.x()*p.x() + p.y()*p.y());
673
674 distRMin = std::fabs(rho - fRMin);
675 distRMax = std::fabs(rho - fRMax);
676
677 // dist to Low Cut
678 //
679 distZLow =std::fabs((p+vZ).dot(fLowNorm));
680
681 // dist to High Cut
682 //
683 distZHigh = std::fabs((p-vZ).dot(fHighNorm));
684
685 if (!fPhiFullCutTube) // Protected against (0,0,z)
686 {
687 if ( rho > halfCarTolerance )
688 {
689 pPhi = std::atan2(p.y(),p.x());
690
691 if(pPhi < fSPhi- halfCarTolerance) { pPhi += twopi; }
692 else if(pPhi > fSPhi+fDPhi+ halfCarTolerance) { pPhi -= twopi; }
693
694 distSPhi = std::fabs(pPhi - fSPhi);
695 distEPhi = std::fabs(pPhi - fSPhi - fDPhi);
696 }
697 else if( !fRMin )
698 {
699 distSPhi = 0.;
700 distEPhi = 0.;
701 }
702 nPs = G4ThreeVector( sinSPhi, -cosSPhi, 0 );
703 nPe = G4ThreeVector( -sinEPhi, cosEPhi, 0 );
704 }
705 if ( rho > halfCarTolerance ) { nR = G4ThreeVector(p.x()/rho,p.y()/rho,0); }
706
707 if( distRMax <= halfCarTolerance )
708 {
709 ++noSurfaces;
710 sumnorm += nR;
711 }
712 if( fRMin && (distRMin <= halfCarTolerance) )
713 {
714 ++noSurfaces;
715 sumnorm -= nR;
716 }
717 if( fDPhi < twopi )
718 {
719 if (distSPhi <= halfAngTolerance)
720 {
721 ++noSurfaces;
722 sumnorm += nPs;
723 }
724 if (distEPhi <= halfAngTolerance)
725 {
726 ++noSurfaces;
727 sumnorm += nPe;
728 }
729 }
730 if (distZLow <= halfCarTolerance)
731 {
732 ++noSurfaces;
733 sumnorm += fLowNorm;
734 }
735 if (distZHigh <= halfCarTolerance)
736 {
737 ++noSurfaces;
738 sumnorm += fHighNorm;
739 }
740 if ( noSurfaces == 0 )
741 {
742#ifdef G4CSGDEBUG
743 G4Exception("G4CutTubs::SurfaceNormal(p)", "GeomSolids1002",
744 JustWarning, "Point p is not on surface !?" );
745 G4int oldprc = G4cout.precision(20);
746 G4cout<< "G4CutTubs::SN ( "<<p.x()<<", "<<p.y()<<", "<<p.z()<<" ); "
747 << G4endl << G4endl;
748 G4cout.precision(oldprc) ;
749#endif
750 norm = ApproxSurfaceNormal(p);
751 }
752 else if ( noSurfaces == 1 ) { norm = sumnorm; }
753 else { norm = sumnorm.unit(); }
754
755 return norm;
756}
757
758/////////////////////////////////////////////////////////////////////////////
759//
760// Algorithm for SurfaceNormal() following the original specification
761// for points not on the surface
762
764{
765 enum ENorm {kNRMin,kNRMax,kNSPhi,kNEPhi,kNZ};
766
767 ENorm side ;
768 G4ThreeVector norm ;
769 G4double rho, phi ;
770 G4double distZLow,distZHigh,distZ;
771 G4double distRMin, distRMax, distSPhi, distEPhi, distMin ;
772 G4ThreeVector vZ=G4ThreeVector(0,0,fDz);
773
774 rho = std::sqrt(p.x()*p.x() + p.y()*p.y()) ;
775
776 distRMin = std::fabs(rho - fRMin) ;
777 distRMax = std::fabs(rho - fRMax) ;
778
779 //dist to Low Cut
780 //
781 distZLow =std::fabs((p+vZ).dot(fLowNorm));
782
783 //dist to High Cut
784 //
785 distZHigh = std::fabs((p-vZ).dot(fHighNorm));
786 distZ=std::min(distZLow,distZHigh);
787
788 if (distRMin < distRMax) // First minimum
789 {
790 if ( distZ < distRMin )
791 {
792 distMin = distZ ;
793 side = kNZ ;
794 }
795 else
796 {
797 distMin = distRMin ;
798 side = kNRMin ;
799 }
800 }
801 else
802 {
803 if ( distZ < distRMax )
804 {
805 distMin = distZ ;
806 side = kNZ ;
807 }
808 else
809 {
810 distMin = distRMax ;
811 side = kNRMax ;
812 }
813 }
814 if (!fPhiFullCutTube && rho ) // Protected against (0,0,z)
815 {
816 phi = std::atan2(p.y(),p.x()) ;
817
818 if ( phi < 0 ) { phi += twopi; }
819
820 if ( fSPhi < 0 )
821 {
822 distSPhi = std::fabs(phi - (fSPhi + twopi))*rho ;
823 }
824 else
825 {
826 distSPhi = std::fabs(phi - fSPhi)*rho ;
827 }
828 distEPhi = std::fabs(phi - fSPhi - fDPhi)*rho ;
829
830 if (distSPhi < distEPhi) // Find new minimum
831 {
832 if ( distSPhi < distMin )
833 {
834 side = kNSPhi ;
835 }
836 }
837 else
838 {
839 if ( distEPhi < distMin )
840 {
841 side = kNEPhi ;
842 }
843 }
844 }
845 switch ( side )
846 {
847 case kNRMin : // Inner radius
848 {
849 norm = G4ThreeVector(-p.x()/rho, -p.y()/rho, 0) ;
850 break ;
851 }
852 case kNRMax : // Outer radius
853 {
854 norm = G4ThreeVector(p.x()/rho, p.y()/rho, 0) ;
855 break ;
856 }
857 case kNZ : // + or - dz
858 {
859 if ( distZHigh > distZLow ) { norm = fHighNorm ; }
860 else { norm = fLowNorm; }
861 break ;
862 }
863 case kNSPhi:
864 {
865 norm = G4ThreeVector(sinSPhi, -cosSPhi, 0) ;
866 break ;
867 }
868 case kNEPhi:
869 {
870 norm = G4ThreeVector(-sinEPhi, cosEPhi, 0) ;
871 break;
872 }
873 default: // Should never reach this case ...
874 {
875 DumpInfo();
876 G4Exception("G4CutTubs::ApproxSurfaceNormal()",
877 "GeomSolids1002", JustWarning,
878 "Undefined side for valid surface normal to solid.");
879 break ;
880 }
881 }
882 return norm;
883}
884
885////////////////////////////////////////////////////////////////////
886//
887//
888// Calculate distance to shape from outside, along normalised vector
889// - return kInfinity if no intersection, or intersection distance <= tolerance
890//
891// - Compute the intersection with the z planes
892// - if at valid r, phi, return
893//
894// -> If point is outer outer radius, compute intersection with rmax
895// - if at valid phi,z return
896//
897// -> Compute intersection with inner radius, taking largest +ve root
898// - if valid (in z,phi), save intersction
899//
900// -> If phi segmented, compute intersections with phi half planes
901// - return smallest of valid phi intersections and
902// inner radius intersection
903//
904// NOTE:
905// - 'if valid' implies tolerant checking of intersection points
906
908 const G4ThreeVector& v ) const
909{
910 G4double snxt = kInfinity ; // snxt = default return value
911 G4double tolORMin2, tolIRMax2 ; // 'generous' radii squared
912 G4double tolORMax2, tolIRMin2;
913 const G4double dRmax = 100.*fRMax;
914 G4ThreeVector vZ=G4ThreeVector(0,0,fDz);
915
916 // Intersection point variables
917 //
918 G4double Dist, sd=0, xi, yi, zi, rho2, inum, iden, cosPsi, Comp,calf ;
919 G4double t1, t2, t3, b, c, d ; // Quadratic solver variables
920 G4double distZLow,distZHigh;
921 // Calculate tolerant rmin and rmax
922
923 if (fRMin > kRadTolerance)
924 {
925 tolORMin2 = (fRMin - halfRadTolerance)*(fRMin - halfRadTolerance) ;
926 tolIRMin2 = (fRMin + halfRadTolerance)*(fRMin + halfRadTolerance) ;
927 }
928 else
929 {
930 tolORMin2 = 0.0 ;
931 tolIRMin2 = 0.0 ;
932 }
933 tolORMax2 = (fRMax + halfRadTolerance)*(fRMax + halfRadTolerance) ;
934 tolIRMax2 = (fRMax - halfRadTolerance)*(fRMax - halfRadTolerance) ;
935
936 // Intersection with ZCut surfaces
937
938 // dist to Low Cut
939 //
940 distZLow =(p+vZ).dot(fLowNorm);
941
942 // dist to High Cut
943 //
944 distZHigh = (p-vZ).dot(fHighNorm);
945
946 if ( distZLow >= -halfCarTolerance )
947 {
948 calf = v.dot(fLowNorm);
949 if (calf<0)
950 {
951 sd = -distZLow/calf;
952 if(sd < 0.0) { sd = 0.0; }
953
954 xi = p.x() + sd*v.x() ; // Intersection coords
955 yi = p.y() + sd*v.y() ;
956 rho2 = xi*xi + yi*yi ;
957
958 // Check validity of intersection
959
960 if ((tolIRMin2 <= rho2) && (rho2 <= tolIRMax2))
961 {
962 if (!fPhiFullCutTube && rho2)
963 {
964 // Psi = angle made with central (average) phi of shape
965 //
966 inum = xi*cosCPhi + yi*sinCPhi ;
967 iden = std::sqrt(rho2) ;
968 cosPsi = inum/iden ;
969 if (cosPsi >= cosHDPhiIT) { return sd ; }
970 }
971 else
972 {
973 return sd ;
974 }
975 }
976 }
977 else
978 {
979 if ( sd<halfCarTolerance )
980 {
981 if(calf>=0) { sd=kInfinity; }
982 return sd ; // On/outside extent, and heading away
983 } // -> cannot intersect
984 }
985 }
986
987 if(distZHigh >= -halfCarTolerance )
988 {
989 calf = v.dot(fHighNorm);
990 if (calf<0)
991 {
992 sd = -distZHigh/calf;
993
994 if(sd < 0.0) { sd = 0.0; }
995
996 xi = p.x() + sd*v.x() ; // Intersection coords
997 yi = p.y() + sd*v.y() ;
998 rho2 = xi*xi + yi*yi ;
999
1000 // Check validity of intersection
1001
1002 if ((tolIRMin2 <= rho2) && (rho2 <= tolIRMax2))
1003 {
1004 if (!fPhiFullCutTube && rho2)
1005 {
1006 // Psi = angle made with central (average) phi of shape
1007 //
1008 inum = xi*cosCPhi + yi*sinCPhi ;
1009 iden = std::sqrt(rho2) ;
1010 cosPsi = inum/iden ;
1011 if (cosPsi >= cosHDPhiIT) { return sd ; }
1012 }
1013 else
1014 {
1015 return sd ;
1016 }
1017 }
1018 }
1019 else
1020 {
1021 if ( sd<halfCarTolerance )
1022 {
1023 if(calf>=0) { sd=kInfinity; }
1024 return sd ; // On/outside extent, and heading away
1025 } // -> cannot intersect
1026 }
1027 }
1028
1029 // -> Can not intersect z surfaces
1030 //
1031 // Intersection with rmax (possible return) and rmin (must also check phi)
1032 //
1033 // Intersection point (xi,yi,zi) on line x=p.x+t*v.x etc.
1034 //
1035 // Intersects with x^2+y^2=R^2
1036 //
1037 // Hence (v.x^2+v.y^2)t^2+ 2t(p.x*v.x+p.y*v.y)+p.x^2+p.y^2-R^2=0
1038 // t1 t2 t3
1039
1040 t1 = 1.0 - v.z()*v.z() ;
1041 t2 = p.x()*v.x() + p.y()*v.y() ;
1042 t3 = p.x()*p.x() + p.y()*p.y() ;
1043 if ( t1 > 0 ) // Check not || to z axis
1044 {
1045 b = t2/t1 ;
1046 c = t3 - fRMax*fRMax ;
1047
1048 if ((t3 >= tolORMax2) && (t2<0)) // This also handles the tangent case
1049 {
1050 // Try outer cylinder intersection, c=(t3-fRMax*fRMax)/t1;
1051
1052 c /= t1 ;
1053 d = b*b - c ;
1054
1055 if (d >= 0) // If real root
1056 {
1057 sd = c/(-b+std::sqrt(d));
1058 if (sd >= 0) // If 'forwards'
1059 {
1060 if ( sd>dRmax ) // Avoid rounding errors due to precision issues on
1061 { // 64 bits systems. Split long distances and recompute
1062 G4double fTerm = sd-std::fmod(sd,dRmax);
1063 sd = fTerm + DistanceToIn(p+fTerm*v,v);
1064 }
1065 // Check z intersection
1066 //
1067 zi = p.z() + sd*v.z() ;
1068 xi = p.x() + sd*v.x() ;
1069 yi = p.y() + sd*v.y() ;
1070 if ((-xi*fLowNorm.x()-yi*fLowNorm.y()
1071 -(zi+fDz)*fLowNorm.z())>-halfCarTolerance)
1072 {
1073 if ((-xi*fHighNorm.x()-yi*fHighNorm.y()
1074 +(fDz-zi)*fHighNorm.z())>-halfCarTolerance)
1075 {
1076 // Z ok. Check phi intersection if reqd
1077 //
1078 if (fPhiFullCutTube)
1079 {
1080 return sd ;
1081 }
1082 else
1083 {
1084 xi = p.x() + sd*v.x() ;
1085 yi = p.y() + sd*v.y() ;
1086 cosPsi = (xi*cosCPhi + yi*sinCPhi)/fRMax ;
1087 if (cosPsi >= cosHDPhiIT) { return sd ; }
1088 }
1089 } // end if std::fabs(zi)
1090 }
1091 } // end if (sd>=0)
1092 } // end if (d>=0)
1093 } // end if (r>=fRMax)
1094 else
1095 {
1096 // Inside outer radius :
1097 // check not inside, and heading through tubs (-> 0 to in)
1098 if ((t3 > tolIRMin2) && (t2 < 0)
1099 && (std::fabs(p.z()) <= std::fabs(GetCutZ(p))-halfCarTolerance ))
1100 {
1101 // Inside both radii, delta r -ve, inside z extent
1102
1103 if (!fPhiFullCutTube)
1104 {
1105 inum = p.x()*cosCPhi + p.y()*sinCPhi ;
1106 iden = std::sqrt(t3) ;
1107 cosPsi = inum/iden ;
1108 if (cosPsi >= cosHDPhiIT)
1109 {
1110 // In the old version, the small negative tangent for the point
1111 // on surface was not taken in account, and returning 0.0 ...
1112 // New version: check the tangent for the point on surface and
1113 // if no intersection, return kInfinity, if intersection instead
1114 // return sd.
1115 //
1116 c = t3-fRMax*fRMax;
1117 if ( c<=0.0 )
1118 {
1119 return 0.0;
1120 }
1121 else
1122 {
1123 c = c/t1 ;
1124 d = b*b-c;
1125 if ( d>=0.0 )
1126 {
1127 snxt = c/(-b+std::sqrt(d)); // using safe solution
1128 // for quadratic equation
1129 if ( snxt < halfCarTolerance ) { snxt=0; }
1130 return snxt ;
1131 }
1132 else
1133 {
1134 return kInfinity;
1135 }
1136 }
1137 }
1138 }
1139 else
1140 {
1141 // In the old version, the small negative tangent for the point
1142 // on surface was not taken in account, and returning 0.0 ...
1143 // New version: check the tangent for the point on surface and
1144 // if no intersection, return kInfinity, if intersection instead
1145 // return sd.
1146 //
1147 c = t3 - fRMax*fRMax;
1148 if ( c<=0.0 )
1149 {
1150 return 0.0;
1151 }
1152 else
1153 {
1154 c = c/t1 ;
1155 d = b*b-c;
1156 if ( d>=0.0 )
1157 {
1158 snxt= c/(-b+std::sqrt(d)); // using safe solution
1159 // for quadratic equation
1160 if ( snxt < halfCarTolerance ) { snxt=0; }
1161 return snxt ;
1162 }
1163 else
1164 {
1165 return kInfinity;
1166 }
1167 }
1168 } // end if (!fPhiFullCutTube)
1169 } // end if (t3>tolIRMin2)
1170 } // end if (Inside Outer Radius)
1171
1172 if ( fRMin ) // Try inner cylinder intersection
1173 {
1174 c = (t3 - fRMin*fRMin)/t1 ;
1175 d = b*b - c ;
1176 if ( d >= 0.0 ) // If real root
1177 {
1178 // Always want 2nd root - we are outside and know rmax Hit was bad
1179 // - If on surface of rmin also need farthest root
1180
1181 sd =( b > 0. )? c/(-b - std::sqrt(d)) : (-b + std::sqrt(d));
1182 if (sd >= -10*halfCarTolerance) // check forwards
1183 {
1184 // Check z intersection
1185 //
1186 if (sd < 0.0) { sd = 0.0; }
1187 if (sd>dRmax) // Avoid rounding errors due to precision issues seen
1188 { // 64 bits systems. Split long distances and recompute
1189 G4double fTerm = sd-std::fmod(sd,dRmax);
1190 sd = fTerm + DistanceToIn(p+fTerm*v,v);
1191 }
1192 zi = p.z() + sd*v.z() ;
1193 xi = p.x() + sd*v.x() ;
1194 yi = p.y() + sd*v.y() ;
1195 if ((-xi*fLowNorm.x()-yi*fLowNorm.y()
1196 -(zi+fDz)*fLowNorm.z())>-halfCarTolerance)
1197 {
1198 if ((-xi*fHighNorm.x()-yi*fHighNorm.y()
1199 +(fDz-zi)*fHighNorm.z())>-halfCarTolerance)
1200 {
1201 // Z ok. Check phi
1202 //
1203 if ( fPhiFullCutTube )
1204 {
1205 return sd ;
1206 }
1207 else
1208 {
1209 cosPsi = (xi*cosCPhi + yi*sinCPhi)/fRMin ;
1210 if (cosPsi >= cosHDPhiIT)
1211 {
1212 // Good inner radius isect
1213 // - but earlier phi isect still possible
1214 //
1215 snxt = sd ;
1216 }
1217 }
1218 } // end if std::fabs(zi)
1219 }
1220 } // end if (sd>=0)
1221 } // end if (d>=0)
1222 } // end if (fRMin)
1223 }
1224
1225 // Phi segment intersection
1226 //
1227 // o Tolerant of points inside phi planes by up to kCarTolerance*0.5
1228 //
1229 // o NOTE: Large duplication of code between sphi & ephi checks
1230 // -> only diffs: sphi -> ephi, Comp -> -Comp and half-plane
1231 // intersection check <=0 -> >=0
1232 // -> use some form of loop Construct ?
1233 //
1234 if ( !fPhiFullCutTube )
1235 {
1236 // First phi surface (Starting phi)
1237 //
1238 Comp = v.x()*sinSPhi - v.y()*cosSPhi ;
1239
1240 if ( Comp < 0 ) // Component in outwards normal dirn
1241 {
1242 Dist = (p.y()*cosSPhi - p.x()*sinSPhi) ;
1243
1244 if ( Dist < halfCarTolerance )
1245 {
1246 sd = Dist/Comp ;
1247
1248 if (sd < snxt)
1249 {
1250 if ( sd < 0 ) { sd = 0.0; }
1251 zi = p.z() + sd*v.z() ;
1252 xi = p.x() + sd*v.x() ;
1253 yi = p.y() + sd*v.y() ;
1254 if ((-xi*fLowNorm.x()-yi*fLowNorm.y()
1255 -(zi+fDz)*fLowNorm.z())>-halfCarTolerance)
1256 {
1257 if ((-xi*fHighNorm.x()-yi*fHighNorm.y()
1258 +(fDz-zi)*fHighNorm.z())>-halfCarTolerance)
1259 {
1260 rho2 = xi*xi + yi*yi ;
1261 if ( ( (rho2 >= tolIRMin2) && (rho2 <= tolIRMax2) )
1262 || ( (rho2 > tolORMin2) && (rho2 < tolIRMin2)
1263 && ( v.y()*cosSPhi - v.x()*sinSPhi > 0 )
1264 && ( v.x()*cosSPhi + v.y()*sinSPhi >= 0 ) )
1265 || ( (rho2 > tolIRMax2) && (rho2 < tolORMax2)
1266 && (v.y()*cosSPhi - v.x()*sinSPhi > 0)
1267 && (v.x()*cosSPhi + v.y()*sinSPhi < 0) ) )
1268 {
1269 // z and r intersections good
1270 // - check intersecting with correct half-plane
1271 //
1272 if ((yi*cosCPhi-xi*sinCPhi) <= halfCarTolerance) { snxt = sd; }
1273 }
1274 } //two Z conditions
1275 }
1276 }
1277 }
1278 }
1279
1280 // Second phi surface (Ending phi)
1281 //
1282 Comp = -(v.x()*sinEPhi - v.y()*cosEPhi) ;
1283
1284 if (Comp < 0 ) // Component in outwards normal dirn
1285 {
1286 Dist = -(p.y()*cosEPhi - p.x()*sinEPhi) ;
1287
1288 if ( Dist < halfCarTolerance )
1289 {
1290 sd = Dist/Comp ;
1291
1292 if (sd < snxt)
1293 {
1294 if ( sd < 0 ) { sd = 0; }
1295 zi = p.z() + sd*v.z() ;
1296 xi = p.x() + sd*v.x() ;
1297 yi = p.y() + sd*v.y() ;
1298 if ((-xi*fLowNorm.x()-yi*fLowNorm.y()
1299 -(zi+fDz)*fLowNorm.z())>-halfCarTolerance)
1300 {
1301 if ((-xi*fHighNorm.x()-yi*fHighNorm.y()
1302 +(fDz-zi)*fHighNorm.z())>-halfCarTolerance)
1303 {
1304 xi = p.x() + sd*v.x() ;
1305 yi = p.y() + sd*v.y() ;
1306 rho2 = xi*xi + yi*yi ;
1307 if ( ( (rho2 >= tolIRMin2) && (rho2 <= tolIRMax2) )
1308 || ( (rho2 > tolORMin2) && (rho2 < tolIRMin2)
1309 && (v.x()*sinEPhi - v.y()*cosEPhi > 0)
1310 && (v.x()*cosEPhi + v.y()*sinEPhi >= 0) )
1311 || ( (rho2 > tolIRMax2) && (rho2 < tolORMax2)
1312 && (v.x()*sinEPhi - v.y()*cosEPhi > 0)
1313 && (v.x()*cosEPhi + v.y()*sinEPhi < 0) ) )
1314 {
1315 // z and r intersections good
1316 // - check intersecting with correct half-plane
1317 //
1318 if ( (yi*cosCPhi-xi*sinCPhi) >= -halfCarTolerance )
1319 {
1320 snxt = sd;
1321 }
1322 } //?? >=-halfCarTolerance
1323 }
1324 } // two Z conditions
1325 }
1326 }
1327 } // Comp < 0
1328 } // !fPhiFullTube
1329 if ( snxt<halfCarTolerance ) { snxt=0; }
1330
1331 return snxt ;
1332}
1333
1334//////////////////////////////////////////////////////////////////
1335//
1336// Calculate distance to shape from outside, along normalised vector
1337// - return kInfinity if no intersection, or intersection distance <= tolerance
1338//
1339// - Compute the intersection with the z planes
1340// - if at valid r, phi, return
1341//
1342// -> If point is outer outer radius, compute intersection with rmax
1343// - if at valid phi,z return
1344//
1345// -> Compute intersection with inner radius, taking largest +ve root
1346// - if valid (in z,phi), save intersction
1347//
1348// -> If phi segmented, compute intersections with phi half planes
1349// - return smallest of valid phi intersections and
1350// inner radius intersection
1351//
1352// NOTE:
1353// - Precalculations for phi trigonometry are Done `just in time'
1354// - `if valid' implies tolerant checking of intersection points
1355// Calculate distance (<= actual) to closest surface of shape from outside
1356// - Calculate distance to z, radial planes
1357// - Only to phi planes if outside phi extent
1358// - Return 0 if point inside
1359
1361{
1362 G4double safRMin,safRMax,safZLow,safZHigh,safePhi,safe,rho,cosPsi;
1363 G4ThreeVector vZ=G4ThreeVector(0,0,fDz);
1364
1365 // Distance to R
1366 //
1367 rho = std::sqrt(p.x()*p.x() + p.y()*p.y()) ;
1368
1369 safRMin = fRMin- rho ;
1370 safRMax = rho - fRMax ;
1371
1372 // Distances to ZCut(Low/High)
1373
1374 // Dist to Low Cut
1375 //
1376 safZLow = (p+vZ).dot(fLowNorm);
1377
1378 // Dist to High Cut
1379 //
1380 safZHigh = (p-vZ).dot(fHighNorm);
1381
1382 safe = std::max(safZLow,safZHigh);
1383
1384 if ( safRMin > safe ) { safe = safRMin; }
1385 if ( safRMax> safe ) { safe = safRMax; }
1386
1387 // Distance to Phi
1388 //
1389 if ( (!fPhiFullCutTube) && (rho) )
1390 {
1391 // Psi=angle from central phi to point
1392 //
1393 cosPsi = (p.x()*cosCPhi + p.y()*sinCPhi)/rho ;
1394
1395 if ( cosPsi < cosHDPhi )
1396 {
1397 // Point lies outside phi range
1398
1399 if ( (p.y()*cosCPhi - p.x()*sinCPhi) <= 0 )
1400 {
1401 safePhi = std::fabs(p.x()*sinSPhi - p.y()*cosSPhi) ;
1402 }
1403 else
1404 {
1405 safePhi = std::fabs(p.x()*sinEPhi - p.y()*cosEPhi) ;
1406 }
1407 if ( safePhi > safe ) { safe = safePhi; }
1408 }
1409 }
1410 if ( safe < 0 ) { safe = 0; }
1411
1412 return safe ;
1413}
1414
1415//////////////////////////////////////////////////////////////////////////////
1416//
1417// Calculate distance to surface of shape from `inside', allowing for tolerance
1418// - Only Calc rmax intersection if no valid rmin intersection
1419
1421 const G4ThreeVector& v,
1422 const G4bool calcNorm,
1423 G4bool* validNorm,
1424 G4ThreeVector* n ) const
1425{
1426 enum ESide {kNull,kRMin,kRMax,kSPhi,kEPhi,kPZ,kMZ};
1427
1428 ESide side=kNull , sider=kNull, sidephi=kNull ;
1429 G4double snxt=kInfinity, srd=kInfinity,sz=kInfinity, sphi=kInfinity ;
1430 G4double deltaR, t1, t2, t3, b, c, d2, roMin2 ;
1431 G4double distZLow,distZHigh,calfH,calfL;
1432 G4ThreeVector vZ=G4ThreeVector(0,0,fDz);
1433
1434 // Vars for phi intersection:
1435 //
1436 G4double pDistS, compS, pDistE, compE, sphi2, xi, yi, vphi, roi2 ;
1437
1438 // Z plane intersection
1439 // Distances to ZCut(Low/High)
1440
1441 // dist to Low Cut
1442 //
1443 distZLow =(p+vZ).dot(fLowNorm);
1444
1445 // dist to High Cut
1446 //
1447 distZHigh = (p-vZ).dot(fHighNorm);
1448
1449 calfH = v.dot(fHighNorm);
1450 calfL = v.dot(fLowNorm);
1451
1452 if (calfH > 0 )
1453 {
1454 if ( distZHigh < halfCarTolerance )
1455 {
1456 snxt = -distZHigh/calfH ;
1457 side = kPZ ;
1458 }
1459 else
1460 {
1461 if (calcNorm)
1462 {
1463 *n = G4ThreeVector(0,0,1) ;
1464 *validNorm = true ;
1465 }
1466 return snxt = 0 ;
1467 }
1468 }
1469 if ( calfL>0)
1470 {
1471
1472 if ( distZLow < halfCarTolerance )
1473 {
1474 sz = -distZLow/calfL ;
1475 if(sz<snxt){
1476 snxt=sz;
1477 side = kMZ ;
1478 }
1479
1480 }
1481 else
1482 {
1483 if (calcNorm)
1484 {
1485 *n = G4ThreeVector(0,0,-1) ;
1486 *validNorm = true ;
1487 }
1488 return snxt = 0.0 ;
1489 }
1490 }
1491 if((calfH<=0)&&(calfL<=0))
1492 {
1493 snxt = kInfinity ; // Travel perpendicular to z axis
1494 side = kNull;
1495 }
1496 // Radial Intersections
1497 //
1498 // Find intersection with cylinders at rmax/rmin
1499 // Intersection point (xi,yi,zi) on line x=p.x+t*v.x etc.
1500 //
1501 // Intersects with x^2+y^2=R^2
1502 //
1503 // Hence (v.x^2+v.y^2)t^2+ 2t(p.x*v.x+p.y*v.y)+p.x^2+p.y^2-R^2=0
1504 //
1505 // t1 t2 t3
1506
1507 t1 = 1.0 - v.z()*v.z() ; // since v normalised
1508 t2 = p.x()*v.x() + p.y()*v.y() ;
1509 t3 = p.x()*p.x() + p.y()*p.y() ;
1510
1511 if ( snxt > 10*(fDz+fRMax) ) { roi2 = 2*fRMax*fRMax; }
1512 else { roi2 = snxt*snxt*t1 + 2*snxt*t2 + t3; } // radius^2 on +-fDz
1513
1514 if ( t1 > 0 ) // Check not parallel
1515 {
1516 // Calculate srd, r exit distance
1517
1518 if ( (t2 >= 0.0) && (roi2 > fRMax*(fRMax + kRadTolerance)) )
1519 {
1520 // Delta r not negative => leaving via rmax
1521
1522 deltaR = t3 - fRMax*fRMax ;
1523
1524 // NOTE: Should use rho-fRMax<-kRadTolerance*0.5
1525 // - avoid sqrt for efficiency
1526
1527 if ( deltaR < -kRadTolerance*fRMax )
1528 {
1529 b = t2/t1 ;
1530 c = deltaR/t1 ;
1531 d2 = b*b-c;
1532 if( d2 >= 0 ) { srd = c/( -b - std::sqrt(d2)); }
1533 else { srd = 0.; }
1534 sider = kRMax ;
1535 }
1536 else
1537 {
1538 // On tolerant boundary & heading outwards (or perpendicular to)
1539 // outer radial surface -> leaving immediately
1540
1541 if ( calcNorm )
1542 {
1543 *n = G4ThreeVector(p.x()/fRMax,p.y()/fRMax,0) ;
1544 *validNorm = true ;
1545 }
1546 return snxt = 0 ; // Leaving by rmax immediately
1547 }
1548 }
1549 else if ( t2 < 0. ) // i.e. t2 < 0; Possible rmin intersection
1550 {
1551 roMin2 = t3 - t2*t2/t1 ; // min ro2 of the plane of movement
1552
1553 if ( fRMin && (roMin2 < fRMin*(fRMin - kRadTolerance)) )
1554 {
1555 deltaR = t3 - fRMin*fRMin ;
1556 b = t2/t1 ;
1557 c = deltaR/t1 ;
1558 d2 = b*b - c ;
1559
1560 if ( d2 >= 0 ) // Leaving via rmin
1561 {
1562 // NOTE: SHould use rho-rmin>kRadTolerance*0.5
1563 // - avoid sqrt for efficiency
1564
1565 if (deltaR > kRadTolerance*fRMin)
1566 {
1567 srd = c/(-b+std::sqrt(d2));
1568 sider = kRMin ;
1569 }
1570 else
1571 {
1572 if ( calcNorm ) { *validNorm = false; } // Concave side
1573 return snxt = 0.0;
1574 }
1575 }
1576 else // No rmin intersect -> must be rmax intersect
1577 {
1578 deltaR = t3 - fRMax*fRMax ;
1579 c = deltaR/t1 ;
1580 d2 = b*b-c;
1581 if( d2 >=0. )
1582 {
1583 srd = -b + std::sqrt(d2) ;
1584 sider = kRMax ;
1585 }
1586 else // Case: On the border+t2<kRadTolerance
1587 // (v is perpendicular to the surface)
1588 {
1589 if (calcNorm)
1590 {
1591 *n = G4ThreeVector(p.x()/fRMax,p.y()/fRMax,0) ;
1592 *validNorm = true ;
1593 }
1594 return snxt = 0.0;
1595 }
1596 }
1597 }
1598 else if ( roi2 > fRMax*(fRMax + kRadTolerance) )
1599 // No rmin intersect -> must be rmax intersect
1600 {
1601 deltaR = t3 - fRMax*fRMax ;
1602 b = t2/t1 ;
1603 c = deltaR/t1;
1604 d2 = b*b-c;
1605 if( d2 >= 0 )
1606 {
1607 srd = -b + std::sqrt(d2) ;
1608 sider = kRMax ;
1609 }
1610 else // Case: On the border+t2<kRadTolerance
1611 // (v is perpendicular to the surface)
1612 {
1613 if (calcNorm)
1614 {
1615 *n = G4ThreeVector(p.x()/fRMax,p.y()/fRMax,0) ;
1616 *validNorm = true ;
1617 }
1618 return snxt = 0.0;
1619 }
1620 }
1621 }
1622 // Phi Intersection
1623
1624 if ( !fPhiFullCutTube )
1625 {
1626 // add angle calculation with correction
1627 // of the difference in domain of atan2 and Sphi
1628 //
1629 vphi = std::atan2(v.y(),v.x()) ;
1630
1631 if ( vphi < fSPhi - halfAngTolerance ) { vphi += twopi; }
1632 else if ( vphi > fSPhi + fDPhi + halfAngTolerance ) { vphi -= twopi; }
1633
1634
1635 if ( p.x() || p.y() ) // Check if on z axis (rho not needed later)
1636 {
1637 // pDist -ve when inside
1638
1639 pDistS = p.x()*sinSPhi - p.y()*cosSPhi ;
1640 pDistE = -p.x()*sinEPhi + p.y()*cosEPhi ;
1641
1642 // Comp -ve when in direction of outwards normal
1643
1644 compS = -sinSPhi*v.x() + cosSPhi*v.y() ;
1645 compE = sinEPhi*v.x() - cosEPhi*v.y() ;
1646
1647 sidephi = kNull;
1648
1649 if( ( (fDPhi <= pi) && ( (pDistS <= halfCarTolerance)
1650 && (pDistE <= halfCarTolerance) ) )
1651 || ( (fDPhi > pi) && !((pDistS > halfCarTolerance)
1652 && (pDistE > halfCarTolerance) ) ) )
1653 {
1654 // Inside both phi *full* planes
1655
1656 if ( compS < 0 )
1657 {
1658 sphi = pDistS/compS ;
1659
1660 if (sphi >= -halfCarTolerance)
1661 {
1662 xi = p.x() + sphi*v.x() ;
1663 yi = p.y() + sphi*v.y() ;
1664
1665 // Check intersecting with correct half-plane
1666 // (if not -> no intersect)
1667 //
1668 if( (std::fabs(xi)<=kCarTolerance)
1669 && (std::fabs(yi)<=kCarTolerance) )
1670 {
1671 sidephi = kSPhi;
1672 if (((fSPhi-halfAngTolerance)<=vphi)
1673 &&((fSPhi+fDPhi+halfAngTolerance)>=vphi))
1674 {
1675 sphi = kInfinity;
1676 }
1677 }
1678 else if ( yi*cosCPhi-xi*sinCPhi >=0 )
1679 {
1680 sphi = kInfinity ;
1681 }
1682 else
1683 {
1684 sidephi = kSPhi ;
1685 if ( pDistS > -halfCarTolerance )
1686 {
1687 sphi = 0.0 ; // Leave by sphi immediately
1688 }
1689 }
1690 }
1691 else
1692 {
1693 sphi = kInfinity ;
1694 }
1695 }
1696 else
1697 {
1698 sphi = kInfinity ;
1699 }
1700
1701 if ( compE < 0 )
1702 {
1703 sphi2 = pDistE/compE ;
1704
1705 // Only check further if < starting phi intersection
1706 //
1707 if ( (sphi2 > -halfCarTolerance) && (sphi2 < sphi) )
1708 {
1709 xi = p.x() + sphi2*v.x() ;
1710 yi = p.y() + sphi2*v.y() ;
1711
1712 if ((std::fabs(xi)<=kCarTolerance)&&(std::fabs(yi)<=kCarTolerance))
1713 {
1714 // Leaving via ending phi
1715 //
1716 if( !((fSPhi-halfAngTolerance <= vphi)
1717 &&(fSPhi+fDPhi+halfAngTolerance >= vphi)) )
1718 {
1719 sidephi = kEPhi ;
1720 if ( pDistE <= -halfCarTolerance ) { sphi = sphi2 ; }
1721 else { sphi = 0.0 ; }
1722 }
1723 }
1724 else // Check intersecting with correct half-plane
1725
1726 if ( (yi*cosCPhi-xi*sinCPhi) >= 0)
1727 {
1728 // Leaving via ending phi
1729 //
1730 sidephi = kEPhi ;
1731 if ( pDistE <= -halfCarTolerance ) { sphi = sphi2 ; }
1732 else { sphi = 0.0 ; }
1733 }
1734 }
1735 }
1736 }
1737 else
1738 {
1739 sphi = kInfinity ;
1740 }
1741 }
1742 else
1743 {
1744 // On z axis + travel not || to z axis -> if phi of vector direction
1745 // within phi of shape, Step limited by rmax, else Step =0
1746
1747 if ( (fSPhi - halfAngTolerance <= vphi)
1748 && (vphi <= fSPhi + fDPhi + halfAngTolerance ) )
1749 {
1750 sphi = kInfinity ;
1751 }
1752 else
1753 {
1754 sidephi = kSPhi ; // arbitrary
1755 sphi = 0.0 ;
1756 }
1757 }
1758 if (sphi < snxt) // Order intersecttions
1759 {
1760 snxt = sphi ;
1761 side = sidephi ;
1762 }
1763 }
1764 if (srd < snxt) // Order intersections
1765 {
1766 snxt = srd ;
1767 side = sider ;
1768 }
1769 }
1770 if (calcNorm)
1771 {
1772 switch(side)
1773 {
1774 case kRMax:
1775 // Note: returned vector not normalised
1776 // (divide by fRMax for unit vector)
1777 //
1778 xi = p.x() + snxt*v.x() ;
1779 yi = p.y() + snxt*v.y() ;
1780 *n = G4ThreeVector(xi/fRMax,yi/fRMax,0) ;
1781 *validNorm = true ;
1782 break ;
1783
1784 case kRMin:
1785 *validNorm = false ; // Rmin is inconvex
1786 break ;
1787
1788 case kSPhi:
1789 if ( fDPhi <= pi )
1790 {
1791 *n = G4ThreeVector(sinSPhi,-cosSPhi,0) ;
1792 *validNorm = true ;
1793 }
1794 else
1795 {
1796 *validNorm = false ;
1797 }
1798 break ;
1799
1800 case kEPhi:
1801 if (fDPhi <= pi)
1802 {
1803 *n = G4ThreeVector(-sinEPhi,cosEPhi,0) ;
1804 *validNorm = true ;
1805 }
1806 else
1807 {
1808 *validNorm = false ;
1809 }
1810 break ;
1811
1812 case kPZ:
1813 *n = fHighNorm ;
1814 *validNorm = true ;
1815 break ;
1816
1817 case kMZ:
1818 *n = fLowNorm ;
1819 *validNorm = true ;
1820 break ;
1821
1822 default:
1823 G4cout << G4endl ;
1824 DumpInfo();
1825 std::ostringstream message;
1826 G4long oldprc = message.precision(16);
1827 message << "Undefined side for valid surface normal to solid."
1828 << G4endl
1829 << "Position:" << G4endl << G4endl
1830 << "p.x() = " << p.x()/mm << " mm" << G4endl
1831 << "p.y() = " << p.y()/mm << " mm" << G4endl
1832 << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl
1833 << "Direction:" << G4endl << G4endl
1834 << "v.x() = " << v.x() << G4endl
1835 << "v.y() = " << v.y() << G4endl
1836 << "v.z() = " << v.z() << G4endl << G4endl
1837 << "Proposed distance :" << G4endl << G4endl
1838 << "snxt = " << snxt/mm << " mm" << G4endl ;
1839 message.precision(oldprc) ;
1840 G4Exception("G4CutTubs::DistanceToOut(p,v,..)", "GeomSolids1002",
1841 JustWarning, message);
1842 break ;
1843 }
1844 }
1845 if ( snxt<halfCarTolerance ) { snxt=0 ; }
1846 return snxt ;
1847}
1848
1849//////////////////////////////////////////////////////////////////////////
1850//
1851// Calculate distance (<=actual) to closest surface of shape from inside
1852
1854{
1855 G4double safRMin,safRMax,safZLow,safZHigh,safePhi,safe,rho;
1856 G4ThreeVector vZ=G4ThreeVector(0,0,fDz);
1857
1858 rho = std::sqrt(p.x()*p.x() + p.y()*p.y()) ; // Distance to R
1859
1860 safRMin = rho - fRMin ;
1861 safRMax = fRMax - rho ;
1862
1863 // Distances to ZCut(Low/High)
1864
1865 // Dist to Low Cut
1866 //
1867 safZLow = std::fabs((p+vZ).dot(fLowNorm));
1868
1869 // Dist to High Cut
1870 //
1871 safZHigh = std::fabs((p-vZ).dot(fHighNorm));
1872 safe = std::min(safZLow,safZHigh);
1873
1874 if ( safRMin < safe ) { safe = safRMin; }
1875 if ( safRMax< safe ) { safe = safRMax; }
1876
1877 // Check if phi divided, Calc distances closest phi plane
1878 //
1879 if ( !fPhiFullCutTube )
1880 {
1881 if ( p.y()*cosCPhi-p.x()*sinCPhi <= 0 )
1882 {
1883 safePhi = -(p.x()*sinSPhi - p.y()*cosSPhi) ;
1884 }
1885 else
1886 {
1887 safePhi = (p.x()*sinEPhi - p.y()*cosEPhi) ;
1888 }
1889 if (safePhi < safe) { safe = safePhi ; }
1890 }
1891 if ( safe < 0 ) { safe = 0; }
1892
1893 return safe ;
1894}
1895
1896//////////////////////////////////////////////////////////////////////////
1897//
1898// Stream object contents to an output stream
1899
1901{
1902 return G4String("G4CutTubs");
1903}
1904
1905//////////////////////////////////////////////////////////////////////////
1906//
1907// Make a clone of the object
1908//
1910{
1911 return new G4CutTubs(*this);
1912}
1913
1914//////////////////////////////////////////////////////////////////////////
1915//
1916// Stream object contents to an output stream
1917
1918std::ostream& G4CutTubs::StreamInfo( std::ostream& os ) const
1919{
1920 G4long oldprc = os.precision(16);
1921 os << "-----------------------------------------------------------\n"
1922 << " *** Dump for solid - " << GetName() << " ***\n"
1923 << " ===================================================\n"
1924 << " Solid type: G4CutTubs\n"
1925 << " Parameters: \n"
1926 << " inner radius : " << fRMin/mm << " mm \n"
1927 << " outer radius : " << fRMax/mm << " mm \n"
1928 << " half length Z: " << fDz/mm << " mm \n"
1929 << " starting phi : " << fSPhi/degree << " degrees \n"
1930 << " delta phi : " << fDPhi/degree << " degrees \n"
1931 << " low Norm : " << fLowNorm << " \n"
1932 << " high Norm : " <<fHighNorm << " \n"
1933 << "-----------------------------------------------------------\n";
1934 os.precision(oldprc);
1935
1936 return os;
1937}
1938
1939/////////////////////////////////////////////////////////////////////////
1940//
1941// GetPointOnSurface
1942
1944{
1945 // Set min and max z
1946 if (fZMin == 0. && fZMax == 0.)
1947 {
1948 G4AutoLock l(&zminmaxMutex);
1949 G4ThreeVector bmin, bmax;
1950 BoundingLimits(bmin,bmax);
1951 fZMin = bmin.z();
1952 fZMax = bmax.z();
1953 l.unlock();
1954 }
1955
1956 // Set parameters
1957 G4double hmax = fZMax - fZMin;
1958 G4double sphi = fSPhi;
1959 G4double dphi = fDPhi;
1960 G4double rmin = fRMin;
1961 G4double rmax = fRMax;
1962 G4double rrmax = rmax*rmax;
1963 G4double rrmin = rmin*rmin;
1964
1965 G4ThreeVector nbot = GetLowNorm();
1966 G4ThreeVector ntop = GetHighNorm();
1967
1968 // Set array of surface areas
1969 G4double sbase = 0.5*dphi*(rrmax - rrmin);
1970 G4double sbot = sbase/std::abs(nbot.z());
1971 G4double stop = sbase/std::abs(ntop.z());
1972 G4double scut = (dphi == twopi) ? 0. : hmax*(rmax - rmin);
1973 G4double ssurf[6] = { scut, scut, sbot, stop, dphi*rmax*hmax, dphi*rmin*hmax };
1974 ssurf[1] += ssurf[0];
1975 ssurf[2] += ssurf[1];
1976 ssurf[3] += ssurf[2];
1977 ssurf[4] += ssurf[3];
1978 ssurf[5] += ssurf[4];
1979
1980 constexpr G4int ntry = 100000;
1981 for (G4int i=0; i<ntry; ++i)
1982 {
1983 // Select surface
1984 G4double select = ssurf[5]*G4QuickRand();
1985 G4int k = 5;
1986 k -= (select <= ssurf[4]);
1987 k -= (select <= ssurf[3]);
1988 k -= (select <= ssurf[2]);
1989 k -= (select <= ssurf[1]);
1990 k -= (select <= ssurf[0]);
1991
1992 // Generate point on selected surface (rejection sampling)
1993 G4ThreeVector p(0,0,0);
1994 switch(k)
1995 {
1996 case 0: // cut at start phi
1997 {
1998 G4double r = rmin + (rmax - rmin)*G4QuickRand();
1999 p.set(r*cosSPhi, r*sinSPhi, fZMin + hmax*G4QuickRand());
2000 break;
2001 }
2002 case 1: // cut at end phi
2003 {
2004 G4double r = rmin + (rmax - rmin)*G4QuickRand();
2005 p.set(r*cosEPhi, r*sinEPhi, fZMin + hmax*G4QuickRand());
2006 break;
2007 }
2008 case 2: // base at low z
2009 {
2010 G4double r = std::sqrt(rrmin + (rrmax - rrmin)*G4QuickRand());
2011 G4double phi = sphi + dphi*G4QuickRand();
2012 G4double x = r*std::cos(phi);
2013 G4double y = r*std::sin(phi);
2014 G4double z = -fDz - (x*nbot.x() + y*nbot.y())/nbot.z();
2015 return G4ThreeVector(x, y, z);
2016 }
2017 case 3: // base at high z
2018 {
2019 G4double r = std::sqrt(rrmin + (rrmax - rrmin)*G4QuickRand());
2020 G4double phi = sphi + dphi*G4QuickRand();
2021 G4double x = r*std::cos(phi);
2022 G4double y = r*std::sin(phi);
2023 G4double z = fDz - (x*ntop.x() + y*ntop.y())/ntop.z();
2024 return G4ThreeVector(x, y, z);
2025 }
2026 case 4: // external lateral surface
2027 {
2028 G4double phi = sphi + dphi*G4QuickRand();
2029 G4double z = fZMin + hmax*G4QuickRand();
2030 G4double x = rmax*std::cos(phi);
2031 G4double y = rmax*std::sin(phi);
2032 p.set(x, y, z);
2033 break;
2034 }
2035 case 5: // internal lateral surface
2036 {
2037 G4double phi = sphi + dphi*G4QuickRand();
2038 G4double z = fZMin + hmax*G4QuickRand();
2039 G4double x = rmin*std::cos(phi);
2040 G4double y = rmin*std::sin(phi);
2041 p.set(x, y, z);
2042 break;
2043 }
2044 }
2045 if ((ntop.dot(p) - fDz*ntop.z()) > 0.) continue;
2046 if ((nbot.dot(p) + fDz*nbot.z()) > 0.) continue;
2047 return p;
2048 }
2049 // Just in case, if all attempts to generate a point have failed
2050 // Normally should never happen
2051 G4double x = rmax*std::cos(sphi + 0.5*dphi);
2052 G4double y = rmax*std::sin(sphi + 0.5*dphi);
2053 G4double z = fDz - (x*ntop.x() + y*ntop.y())/ntop.z();
2054 return G4ThreeVector(x, y, z);
2055}
2056
2057///////////////////////////////////////////////////////////////////////////
2058//
2059// Methods for visualisation
2060
2062{
2063 scene.AddSolid (*this) ;
2064}
2065
2067{
2068 typedef G4double G4double3[3];
2069 typedef G4int G4int4[4];
2070
2071 G4Polyhedron *ph = new G4Polyhedron;
2072 G4Polyhedron *ph1 = new G4PolyhedronTubs (fRMin, fRMax, fDz, fSPhi, fDPhi);
2073 G4int nn=ph1->GetNoVertices();
2074 G4int nf=ph1->GetNoFacets();
2075 G4double3* xyz = new G4double3[nn]; // number of nodes
2076 G4int4* faces = new G4int4[nf] ; // number of faces
2077
2078 for(G4int i=0; i<nn; ++i)
2079 {
2080 xyz[i][0]=ph1->GetVertex(i+1).x();
2081 xyz[i][1]=ph1->GetVertex(i+1).y();
2082 G4double tmpZ=ph1->GetVertex(i+1).z();
2083 if(tmpZ>=fDz-kCarTolerance)
2084 {
2085 xyz[i][2]=GetCutZ(G4ThreeVector(xyz[i][0],xyz[i][1],fDz));
2086 }
2087 else if(tmpZ<=-fDz+kCarTolerance)
2088 {
2089 xyz[i][2]=GetCutZ(G4ThreeVector(xyz[i][0],xyz[i][1],-fDz));
2090 }
2091 else
2092 {
2093 xyz[i][2]=tmpZ;
2094 }
2095 }
2096 G4int iNodes[4];
2097 G4int *iEdge=0;
2098 G4int n;
2099 for(G4int i=0; i<nf ; ++i)
2100 {
2101 ph1->GetFacet(i+1,n,iNodes,iEdge);
2102 for(G4int k=0; k<n; ++k)
2103 {
2104 faces[i][k]=iNodes[k];
2105 }
2106 for(G4int k=n; k<4; ++k)
2107 {
2108 faces[i][k]=0;
2109 }
2110 }
2111 ph->createPolyhedron(nn,nf,xyz,faces);
2112
2113 delete [] xyz;
2114 delete [] faces;
2115 delete ph1;
2116
2117 return ph;
2118}
2119
2120// Auxilary Methods for Solid
2121
2122//////////////////////////////////////////////////////////////////////////
2123//
2124// Check set of points on the outer lateral surface and return true
2125// if the cut planes are crossing inside the surface
2126//
2127
2129{
2130 constexpr G4int npoints = 30;
2131
2132 // set values for calculation of h - distance between
2133 // opposite points on bases
2134 G4ThreeVector nbot = GetLowNorm();
2135 G4ThreeVector ntop = GetHighNorm();
2136 if (std::abs(nbot.z()) < kCarTolerance) return true;
2137 if (std::abs(ntop.z()) < kCarTolerance) return true;
2138 G4double nx = nbot.x()/nbot.z() - ntop.x()/ntop.z();
2139 G4double ny = nbot.y()/nbot.z() - ntop.y()/ntop.z();
2140
2141 // check points
2142 G4double cosphi = GetCosStartPhi();
2143 G4double sinphi = GetSinStartPhi();
2144 G4double delphi = GetDeltaPhiAngle()/npoints;
2145 G4double cosdel = std::cos(delphi);
2146 G4double sindel = std::sin(delphi);
2147 G4double hzero = 2.*GetZHalfLength()/GetOuterRadius();
2148 for (G4int i=0; i<npoints+1; ++i)
2149 {
2150 G4double h = nx*cosphi + ny*sinphi + hzero;
2151 if (h < 0.) return true;
2152 G4double sintmp = sinphi;
2153 sinphi = sintmp*cosdel + cosphi*sindel;
2154 cosphi = cosphi*cosdel - sintmp*sindel;
2155 }
2156 return false;
2157}
2158
2159///////////////////////////////////////////////////////////////////////////
2160//
2161// Return real Z coordinate of point on Cutted +/- fDZ plane
2162
2164{
2165 G4double newz = p.z(); // p.z() should be either +fDz or -fDz
2166 if (p.z()<0)
2167 {
2168 if(fLowNorm.z()!=0.)
2169 {
2170 newz = -fDz-(p.x()*fLowNorm.x()+p.y()*fLowNorm.y())/fLowNorm.z();
2171 }
2172 }
2173 else
2174 {
2175 if(fHighNorm.z()!=0.)
2176 {
2177 newz = fDz-(p.x()*fHighNorm.x()+p.y()*fHighNorm.y())/fHighNorm.z();
2178 }
2179 }
2180 return newz;
2181}
2182#endif
std::vector< G4ThreeVector > G4ThreeVectorList
@ JustWarning
@ FatalException
void G4Exception(const char *originOfException, const char *exceptionCode, G4ExceptionSeverity severity, const char *description)
Definition: G4Exception.cc:59
G4double G4QuickRand()
Definition: G4QuickRand.hh:34
ESide
Definition: G4Sphere.cc:61
@ kRMax
Definition: G4Sphere.cc:61
@ kNull
Definition: G4Sphere.cc:61
@ kSPhi
Definition: G4Sphere.cc:61
@ kRMin
Definition: G4Sphere.cc:61
@ kEPhi
Definition: G4Sphere.cc:61
ENorm
Definition: G4Sphere.cc:65
@ kNRMax
Definition: G4Sphere.cc:65
@ kNEPhi
Definition: G4Sphere.cc:65
@ kNSPhi
Definition: G4Sphere.cc:65
@ kNRMin
Definition: G4Sphere.cc:65
#define G4MUTEX_INITIALIZER
Definition: G4Threading.hh:85
std::mutex G4Mutex
Definition: G4Threading.hh:81
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
#define G4endl
Definition: G4ios.hh:57
G4GLOB_DLL std::ostream G4cout
double x() const
double y() const
double z() const
Hep3Vector unit() const
double x() const
double mag2() const
double y() const
double dot(const Hep3Vector &) const
void setZ(double)
void set(double x, double y, double z)
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
G4double fSurfaceArea
Definition: G4CSGSolid.hh:71
G4double fCubicVolume
Definition: G4CSGSolid.hh:70
G4CSGSolid & operator=(const G4CSGSolid &rhs)
Definition: G4CSGSolid.cc:89
G4ThreeVector GetHighNorm() const
G4double GetCubicVolume()
Definition: G4CutTubs.cc:245
G4double GetStartPhiAngle() const
G4double GetZHalfLength() const
G4double GetInnerRadius() const
EInside Inside(const G4ThreeVector &p) const
Definition: G4CutTubs.cc:578
G4ThreeVector GetLowNorm() const
G4double GetCutZ(const G4ThreeVector &p) const
Definition: G4CutTubs.cc:2163
G4Polyhedron * CreatePolyhedron() const
Definition: G4CutTubs.cc:2066
G4double GetDeltaPhiAngle() const
G4double GetOuterRadius() const
G4ThreeVector ApproxSurfaceNormal(const G4ThreeVector &p) const
Definition: G4CutTubs.cc:763
G4bool IsCrossingCutPlanes() const
Definition: G4CutTubs.cc:2128
G4double GetSinStartPhi() const
G4GeometryType GetEntityType() const
Definition: G4CutTubs.cc:1900
void CheckPhiAngles(G4double sPhi, G4double dPhi)
G4CutTubs & operator=(const G4CutTubs &rhs)
Definition: G4CutTubs.cc:212
void BoundingLimits(G4ThreeVector &pMin, G4ThreeVector &pMax) const
Definition: G4CutTubs.cc:350
G4double DistanceToOut(const G4ThreeVector &p, const G4ThreeVector &v, const G4bool calcNorm=false, G4bool *validNorm=nullptr, G4ThreeVector *n=nullptr) const
Definition: G4CutTubs.cc:1420
G4VSolid * Clone() const
Definition: G4CutTubs.cc:1909
G4double GetSurfaceArea()
Definition: G4CutTubs.cc:296
G4bool CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimit, const G4AffineTransform &pTransform, G4double &pmin, G4double &pmax) const
Definition: G4CutTubs.cc:467
G4ThreeVector GetPointOnSurface() const
Definition: G4CutTubs.cc:1943
G4double GetSinEndPhi() const
std::ostream & StreamInfo(std::ostream &os) const
Definition: G4CutTubs.cc:1918
G4ThreeVector SurfaceNormal(const G4ThreeVector &p) const
Definition: G4CutTubs.cc:660
G4double DistanceToIn(const G4ThreeVector &p, const G4ThreeVector &v) const
Definition: G4CutTubs.cc:907
G4double GetCosStartPhi() const
G4double GetCosEndPhi() const
void DescribeYourselfTo(G4VGraphicsScene &scene) const
Definition: G4CutTubs.cc:2061
G4CutTubs(const G4String &pName, G4double pRMin, G4double pRMax, G4double pDz, G4double pSPhi, G4double pDPhi, G4ThreeVector pLowNorm, G4ThreeVector pHighNorm)
Definition: G4CutTubs.cc:63
static G4bool DiskExtent(G4double rmin, G4double rmax, G4double startPhi, G4double delPhi, G4TwoVector &pmin, G4TwoVector &pmax)
Definition: G4GeomTools.cc:390
G4double GetRadialTolerance() const
static G4GeometryTolerance * GetInstance()
G4double GetAngularTolerance() const
virtual void AddSolid(const G4Box &)=0
G4String GetName() const
void DumpInfo() const
G4double kCarTolerance
Definition: G4VSolid.hh:299
G4Point3D GetVertex(G4int index) const
void GetFacet(G4int iFace, G4int &n, G4int *iNodes, G4int *edgeFlags=nullptr, G4int *iFaces=nullptr) const
G4int createPolyhedron(G4int Nnodes, G4int Nfaces, const G4double xyz[][3], const G4int faces[][4])
G4int GetNoFacets() const
G4int GetNoVertices() const
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
Definition: DoubConv.h:17