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