ATLAS Offline Software
G4ShiftedCone.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 //
6 // The G4ShiftedCone class copied from standard G4Cons and modified to:
7 // 1) have an arbitrary position along Z axis,
8 // 2) represent a twopi-cone. Sectors are not supported but the
9 // corresponding code kept and just commented out.
10 //
11 
12 //
13 // ********************************************************************
14 // * License and Disclaimer *
15 // * *
16 // * The Geant4 software is copyright of the Copyright Holders of *
17 // * the Geant4 Collaboration. It is provided under the terms and *
18 // * conditions of the Geant4 Software License, included in the file *
19 // * LICENSE and available at http://cern.ch/geant4/license . These *
20 // * include a list of copyright holders. *
21 // * *
22 // * Neither the authors of this software system, nor their employing *
23 // * institutes,nor the agencies providing financial support for this *
24 // * work make any representation or warranty, express or implied, *
25 // * regarding this software system or assume any liability for its *
26 // * use. Please see the license in the file LICENSE and URL above *
27 // * for the full disclaimer and the limitation of liability. *
28 // * *
29 // * This code implementation is the result of the scientific and *
30 // * technical work of the GEANT4 collaboration. *
31 // * By using, copying, modifying or distributing the software (or *
32 // * any work based on the software) you agree to acknowledge its *
33 // * use in resulting scientific publications, and indicate your *
34 // * acceptance of all terms of the Geant4 Software license. *
35 // ********************************************************************
36 //
37 //
38 //
39 //
40 // class G4ShiftedCone
41 //
42 // Implementation for G4ShiftedCone class
43 //
44 // History:
45 // 03.07.2019 A. Sukharev: copied from G4Cons
46 // --------------------------------------------------------------------
47 
48 #include "G4ShiftedCone.h"
49 
50 #include "G4GeomTools.hh"
51 #include "G4VoxelLimits.hh"
52 #include "G4AffineTransform.hh"
53 #include "G4BoundingEnvelope.hh"
54 #include "G4GeometryTolerance.hh"
55 
56 #include "G4VPVParameterisation.hh"
57 
58 #include "meshdefs.hh"
59 
60 #include "Randomize.hh"
61 
62 #include "G4VGraphicsScene.hh"
63 
64 using namespace CLHEP;
65 
67 //
68 // Private enum: Not for external use - used by distanceToOut
69 
71 
72 // used by normal
73 
75 
77 //
78 // constructor - check parameters, convert angles so 0<sphi+dpshi<=2_PI
79 // - note if pDPhi>2PI then reset to 2PI
80 
81 G4ShiftedCone::G4ShiftedCone( const G4String& pName,
82  G4double pZ1, G4double pZ2,
83  G4double pRmin1, G4double pRmax1,
84  G4double pRmin2, G4double pRmax2)
85 // G4double pDz,
86 // G4double pSPhi, G4double pDPhi)
87  : G4CSGSolid(pName),
88  kRadTolerance (G4GeometryTolerance::GetInstance()->GetRadialTolerance()),
89  kAngTolerance (G4GeometryTolerance::GetInstance()->GetAngularTolerance()),
90  fRmin1(pRmin1), fRmin2(pRmin2),
91  fRmax1(pRmax1), fRmax2(pRmax2),
92  fDz((pZ2 - pZ1) * 0.5), fZshift(pZ1 + fDz),
93  // fSPhi(0.), fDPhi(0.)
94  halfCarTolerance (kCarTolerance*0.5),
95  halfRadTolerance (kRadTolerance*0.5),
96  halfAngTolerance (kAngTolerance*0.5)
97 {
98  // Check z-len
99  //
100  if ( fDz < 0 )
101  {
102  std::ostringstream message;
103  message << "Invalid Z half-length for Solid: " << GetName() << G4endl
104  << " hZ = " << fDz;
105  G4Exception("G4ShiftedCone::G4ShiftedCone()", "GeomSolids0002",
106  FatalException, message);
107  }
108 
109  // Check radii
110  //
111  if (((pRmin1>=pRmax1) || (pRmin2>=pRmax2) || (pRmin1<0)) && (pRmin2<0))
112  {
113  std::ostringstream message;
114  message << "Invalid values of radii for Solid: " << GetName() << G4endl
115  << " pRmin1 = " << pRmin1 << ", pRmin2 = " << pRmin2
116  << ", pRmax1 = " << pRmax1 << ", pRmax2 = " << pRmax2;
117  G4Exception("G4ShiftedCone::G4ShiftedCone()", "GeomSolids0002",
118  FatalException, message) ;
119  }
120  if( (pRmin1 == 0.0) && (pRmin2 > 0.0) ) { fRmin1 = 1e3*kRadTolerance ; }
121  if( (pRmin2 == 0.0) && (pRmin1 > 0.0) ) { fRmin2 = 1e3*kRadTolerance ; }
122 
123  // Check angles
124  //
125 // CheckPhiAngles(pSPhi, pDPhi);
126 }
127 
129 //
130 // Fake default constructor - sets only member data and allocates memory
131 // for usage restricted to object persistency.
132 //
134  : G4CSGSolid(a), kRadTolerance(0.), kAngTolerance(0.),
135  fRmin1(0.), fRmin2(0.), fRmax1(0.), fRmax2(0.),
136  fDz(0.), fZshift(0.),
137 // fSPhi(0.), fDPhi(0.), sinCPhi(0.), cosCPhi(0.), cosHDPhiOT(0.),
138 // cosHDPhiIT(0.), sinSPhi(0.), cosSPhi(0.), sinEPhi(0.), cosEPhi(0.),
139 // fPhiFullCone(false),
140  halfCarTolerance(0.), halfRadTolerance(0.), halfAngTolerance(0.)
141 {
142 }
143 
145 //
146 // Destructor
147 
149 {
150 }
151 
153 //
154 // Copy constructor
155 
157  : G4CSGSolid(rhs), kRadTolerance(rhs.kRadTolerance),
158  kAngTolerance(rhs.kAngTolerance), fRmin1(rhs.fRmin1), fRmin2(rhs.fRmin2),
159  fRmax1(rhs.fRmax1), fRmax2(rhs.fRmax2), fDz(rhs.fDz), fZshift(rhs.fZshift),
160 // fSPhi(rhs.fSPhi),
161 // fDPhi(rhs.fDPhi), sinCPhi(rhs.sinCPhi), cosCPhi(rhs.cosCPhi),
162 // cosHDPhiOT(rhs.cosHDPhiOT), cosHDPhiIT(rhs.cosHDPhiIT),
163 // sinSPhi(rhs.sinSPhi), cosSPhi(rhs.cosSPhi), sinEPhi(rhs.sinEPhi),
164 // cosEPhi(rhs.cosEPhi), fPhiFullCone(rhs.fPhiFullCone),
165  halfCarTolerance(rhs.halfCarTolerance),
166  halfRadTolerance(rhs.halfRadTolerance),
167  halfAngTolerance(rhs.halfAngTolerance)
168 {
169 }
170 
172 //
173 // Assignment operator
174 
176 {
177  // Check assignment to self
178  //
179  if (this == &rhs) { return *this; }
180 
181  // Copy base class data
182  //
183  G4CSGSolid::operator=(rhs);
184 
185  // Copy data
186  //
189  fRmin1 = rhs.fRmin1; fRmin2 = rhs.fRmin2;
190  fRmax1 = rhs.fRmax1; fRmax2 = rhs.fRmax2;
191  fDz = rhs.fDz; fZshift = rhs.fZshift;
192 // fSPhi = rhs.fSPhi; fDPhi = rhs.fDPhi;
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 // fPhiFullCone = rhs.fPhiFullCone;
201 
202  return *this;
203 }
204 
206 //
207 // Return whether point inside/outside/on surface
208 
209 EInside G4ShiftedCone::Inside(const G4ThreeVector& p) const
210 {
211  G4double r2, rl, rh, /*pPhi,*/ tolRMin, tolRMax; // rh2, rl2 ;
212  EInside in;
213 
214  G4double z = p.z() - fZshift;
215 
216  if (std::fabs(z) > fDz + halfCarTolerance ) { return in = kOutside; }
217  else if(std::fabs(z) >= fDz - halfCarTolerance ) { in = kSurface; }
218  else { in = kInside; }
219 
220  r2 = p.x()*p.x() + p.y()*p.y() ;
221  rl = 0.5*(fRmin2*(z + fDz) + fRmin1*(fDz - z))/fDz ;
222  rh = 0.5*(fRmax2*(z+fDz)+fRmax1*(fDz-z))/fDz;
223 
224  // rh2 = rh*rh;
225 
226  tolRMin = rl - halfRadTolerance;
227  if ( tolRMin < 0 ) { tolRMin = 0; }
228  tolRMax = rh + halfRadTolerance;
229 
230  if ( (r2<tolRMin*tolRMin) || (r2>tolRMax*tolRMax) ) { return in = kOutside; }
231 
232  if (rl) { tolRMin = rl + halfRadTolerance; }
233  else { tolRMin = 0.0; }
234  tolRMax = rh - halfRadTolerance;
235 
236  if (in == kInside) // else it's kSurface already
237  {
238  if ( (r2 < tolRMin*tolRMin) || (r2 >= tolRMax*tolRMax) ) { in = kSurface; }
239  }
240 /*
241  if ( !fPhiFullCone && ((p.x() != 0.0) || (p.y() != 0.0)) )
242  {
243  pPhi = std::atan2(p.y(),p.x()) ;
244 
245  if ( pPhi < fSPhi - halfAngTolerance ) { pPhi += twopi; }
246  else if ( pPhi > fSPhi + fDPhi + halfAngTolerance ) { pPhi -= twopi; }
247 
248  if ( (pPhi < fSPhi - halfAngTolerance) ||
249  (pPhi > fSPhi + fDPhi + halfAngTolerance) ) { return in = kOutside; }
250 
251  else if (in == kInside) // else it's kSurface anyway already
252  {
253  if ( (pPhi < fSPhi + halfAngTolerance) ||
254  (pPhi > fSPhi + fDPhi - halfAngTolerance) ) { in = kSurface; }
255  }
256  }
257  else if ( !fPhiFullCone ) { in = kSurface; }
258 */
259  return in ;
260 }
261 
263 //
264 // Dispatch to parameterisation for replication mechanism dimension
265 // computation & modification.
266 
267 void G4ShiftedCone::ComputeDimensions( G4VPVParameterisation*,// p,
268  const G4int ,//n,
269  const G4VPhysicalVolume* )//pRep )
270 {
271  std::ostringstream message;
272  message << "ComputeDimensions is not implemented for Solid: " << GetName();
273  G4Exception("G4ShiftedCone::ComputeDimensions()", "GeomSolids0002",
274  FatalException, message) ;
275 // p->ComputeDimensions(*this,n,pRep) ;
276 }
277 
279 //
280 // Get bounding box
281 
282 void G4ShiftedCone::BoundingLimits(G4ThreeVector& pMin, G4ThreeVector& pMax) const
283 {
284 // G4double rmin = std::min(GetInnerRadiusMinusZ(),GetInnerRadiusPlusZ());
286 
287  // Find bounding box
288  //
289 /* if (GetDeltaPhiAngle() < twopi)
290  {
291  G4double dz = GetZHalfLength();
292  G4TwoVector vmin,vmax;
293  G4GeomTools::DiskExtent(rmin,rmax,
294  GetSinStartPhi(),GetCosStartPhi(),
295  GetSinEndPhi(),GetCosEndPhi(),
296  vmin,vmax);
297  pMin.set(vmin.x(),vmin.y(),-dz);
298  pMax.set(vmax.x(),vmax.y(), dz);
299  }
300  else*/
301  {
302  pMin.set(-rmax,-rmax, fZshift - fDz);
303  pMax.set( rmax, rmax, fZshift + fDz);
304  }
305 
306  // Check correctness of the bounding box
307  //
308  if (pMin.x() >= pMax.x() || pMin.y() >= pMax.y() || pMin.z() >= pMax.z())
309  {
310  std::ostringstream message;
311  message << "Bad bounding box (min >= max) for solid: "
312  << GetName() << " !"
313  << "\npMin = " << pMin
314  << "\npMax = " << pMax;
315  G4Exception("G4ShiftedCone::BoundingLimits()", "GeomMgt0001",
316  JustWarning, message);
317  DumpInfo();
318  }
319 }
320 
322 //
323 // Calculate extent under transform and specified limit
324 
325 G4bool G4ShiftedCone::CalculateExtent( const EAxis pAxis,
326  const G4VoxelLimits& pVoxelLimit,
327  const G4AffineTransform& pTransform,
328  G4double& pMin,
329  G4double& pMax ) const
330 {
331  G4ThreeVector bmin, bmax;
332  G4bool exist;
333 
334  // Get bounding box
336 
337  // Check bounding box
338  G4BoundingEnvelope bbox(bmin,bmax);
339 #ifdef G4BBOX_EXTENT
340  if (true) return bbox.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax);
341 #endif
342  if (bbox.BoundingBoxVsVoxelLimits(pAxis,pVoxelLimit,pTransform,pMin,pMax))
343  {
344  return exist = (pMin < pMax) ? true : false;
345  }
346 
347  // Get parameters of the solid
348  G4double rmin1 = GetInnerRadiusMinusZ();
349  G4double rmax1 = GetOuterRadiusMinusZ();
350  G4double rmin2 = GetInnerRadiusPlusZ();
351  G4double rmax2 = GetOuterRadiusPlusZ();
352  G4double z1 = GetZ1();
353  G4double z2 = GetZ2();
354  G4double dphi = GetDeltaPhiAngle();
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 rext1 = rmax1/cosHalf;
368  G4double rext2 = rmax2/cosHalf;
369 
370  // bounding envelope for full cone without hole consists of two polygons,
371  // in other cases it is a sequence of quadrilaterals
372  if (rmin1 == 0 && rmin2 == 0 && dphi == twopi)
373  {
374  G4double sinCur = sinHalf;
375  G4double cosCur = cosHalf;
376 
377  G4ThreeVectorList baseA(NSTEPS),baseB(NSTEPS);
378  for (G4int k=0; k<NSTEPS; ++k)
379  {
380  baseA[k].set(rext1*cosCur,rext1*sinCur, z1);
381  baseB[k].set(rext2*cosCur,rext2*sinCur, z2);
382 
383  G4double sinTmp = sinCur;
384  sinCur = sinCur*cosStep + cosCur*sinStep;
385  cosCur = cosCur*cosStep - sinTmp*sinStep;
386  }
387  std::vector<const G4ThreeVectorList *> polygons(2);
388  polygons[0] = &baseA;
389  polygons[1] = &baseB;
390  G4BoundingEnvelope benv(bmin,bmax,polygons);
391  exist = benv.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax);
392  }
393  else
394  {
395 
396  G4double sinStart = GetSinStartPhi();
397  G4double cosStart = GetCosStartPhi();
398  G4double sinEnd = GetSinEndPhi();
399  G4double cosEnd = GetCosEndPhi();
400  G4double sinCur = sinStart*cosHalf + cosStart*sinHalf;
401  G4double cosCur = cosStart*cosHalf - sinStart*sinHalf;
402 
403  // set quadrilaterals
404  G4ThreeVectorList pols[NSTEPS+2];
405  for (G4int k=0; k<ksteps+2; ++k) pols[k].resize(4);
406  pols[0][0].set(rmin2*cosStart,rmin2*sinStart, z2);
407  pols[0][1].set(rmin1*cosStart,rmin1*sinStart, z1);
408  pols[0][2].set(rmax1*cosStart,rmax1*sinStart, z1);
409  pols[0][3].set(rmax2*cosStart,rmax2*sinStart, z2);
410  for (G4int k=1; k<ksteps+1; ++k)
411  {
412  pols[k][0].set(rmin2*cosCur,rmin2*sinCur, z2);
413  pols[k][1].set(rmin1*cosCur,rmin1*sinCur, z1);
414  pols[k][2].set(rext1*cosCur,rext1*sinCur, z1);
415  pols[k][3].set(rext2*cosCur,rext2*sinCur, z2);
416 
417  G4double sinTmp = sinCur;
418  sinCur = sinCur*cosStep + cosCur*sinStep;
419  cosCur = cosCur*cosStep - sinTmp*sinStep;
420  }
421  pols[ksteps+1][0].set(rmin2*cosEnd,rmin2*sinEnd, z2);
422  pols[ksteps+1][1].set(rmin1*cosEnd,rmin1*sinEnd, z1);
423  pols[ksteps+1][2].set(rmax1*cosEnd,rmax1*sinEnd, z1);
424  pols[ksteps+1][3].set(rmax2*cosEnd,rmax2*sinEnd, z2);
425 
426  // set envelope and calculate extent
427  std::vector<const G4ThreeVectorList *> polygons;
428  polygons.resize(ksteps+2);
429  for (G4int k=0; k<ksteps+2; ++k) polygons[k] = &pols[k];
430  G4BoundingEnvelope benv(bmin,bmax,polygons);
431  exist = benv.CalculateExtent(pAxis,pVoxelLimit,pTransform,pMin,pMax);
432  }
433  return exist;
434 }
435 
437 //
438 // Return unit normal of surface closest to p
439 // - note if point on z axis, ignore phi divided sides
440 // - unsafe if point close to z axis a rmin=0 - no explicit checks
441 
442 G4ThreeVector G4ShiftedCone::SurfaceNormal( const G4ThreeVector& p) const
443 {
444  G4int noSurfaces = 0;
445  G4double rho;//, pPhi;
446  G4double distZ, distRMin, distRMax;
447 // G4double distSPhi = kInfinity, distEPhi = kInfinity;
448  G4double tanRMin, secRMin, pRMin, widRMin;
449  G4double tanRMax, secRMax, pRMax, widRMax;
450 
451  G4ThreeVector norm, sumnorm(0.,0.,0.), nZ = G4ThreeVector(0.,0.,1.);
452  G4ThreeVector nR, nr(0.,0.,0.), nPs, nPe;
453 
454  G4double z = p.z() - fZshift;
455 
456  distZ = std::fabs(std::fabs(z) - fDz);
457  rho = std::sqrt(p.x()*p.x() + p.y()*p.y());
458 
459  tanRMin = (fRmin2 - fRmin1)*0.5/fDz;
460  secRMin = std::sqrt(1 + tanRMin*tanRMin);
461  pRMin = rho - z*tanRMin;
462  widRMin = fRmin2 - fDz*tanRMin;
463  distRMin = std::fabs(pRMin - widRMin)/secRMin;
464 
465  tanRMax = (fRmax2 - fRmax1)*0.5/fDz;
466  secRMax = std::sqrt(1+tanRMax*tanRMax);
467  pRMax = rho - z*tanRMax;
468  widRMax = fRmax2 - fDz*tanRMax;
469  distRMax = std::fabs(pRMax - widRMax)/secRMax;
470 /*
471  if (!fPhiFullCone) // Protected against (0,0,z)
472  {
473  if ( rho )
474  {
475  pPhi = std::atan2(p.y(),p.x());
476 
477  if (pPhi < fSPhi-halfCarTolerance) { pPhi += twopi; }
478  else if (pPhi > fSPhi+fDPhi+halfCarTolerance) { pPhi -= twopi; }
479 
480  distSPhi = std::fabs( pPhi - fSPhi );
481  distEPhi = std::fabs( pPhi - fSPhi - fDPhi );
482  }
483  else if( !(fRmin1) || !(fRmin2) )
484  {
485  distSPhi = 0.;
486  distEPhi = 0.;
487  }
488  nPs = G4ThreeVector(std::sin(fSPhi), -std::cos(fSPhi), 0);
489  nPe = G4ThreeVector(-std::sin(fSPhi+fDPhi), std::cos(fSPhi+fDPhi), 0);
490  }*/
491  if ( rho > halfCarTolerance )
492  {
493  nR = G4ThreeVector(p.x()/rho/secRMax, p.y()/rho/secRMax, -tanRMax/secRMax);
494  if (fRmin1 || fRmin2)
495  {
496  nr = G4ThreeVector(-p.x()/rho/secRMin,-p.y()/rho/secRMin,tanRMin/secRMin);
497  }
498  }
499 
500  if( distRMax <= halfCarTolerance )
501  {
502  noSurfaces ++;
503  sumnorm += nR;
504  }
505  if( (fRmin1 || fRmin2) && (distRMin <= halfCarTolerance) )
506  {
507  noSurfaces ++;
508  sumnorm += nr;
509  }
510 /* if( !fPhiFullCone )
511  {
512  if (distSPhi <= halfAngTolerance)
513  {
514  noSurfaces ++;
515  sumnorm += nPs;
516  }
517  if (distEPhi <= halfAngTolerance)
518  {
519  noSurfaces ++;
520  sumnorm += nPe;
521  }
522  }*/
523  if (distZ <= halfCarTolerance)
524  {
525  noSurfaces ++;
526  if ( z >= 0.) { sumnorm += nZ; }
527  else { sumnorm -= nZ; }
528  }
529  if ( noSurfaces == 0 )
530  {
531 #ifdef G4CSGDEBUG
532  G4Exception("G4ShiftedCone::SurfaceNormal(p)", "GeomSolids1002",
533  JustWarning, "Point p is not on surface !?" );
534 #endif
536  }
537  else if ( noSurfaces == 1 ) { norm = sumnorm; }
538  else { norm = sumnorm.unit(); }
539 
540  return norm ;
541 }
542 
544 //
545 // Algorithm for SurfaceNormal() following the original specification
546 // for points not on the surface
547 
548 G4ThreeVector G4ShiftedCone::ApproxSurfaceNormal( const G4ThreeVector& p ) const
549 {
550  ENorm side ;
551  G4ThreeVector norm ;
552  G4double rho;//, phi ;
553  G4double distZ, distRMin, distRMax;//, distSPhi, distEPhi, distMin ;
554  G4double tanRMin, secRMin, pRMin, widRMin ;
555  G4double tanRMax, secRMax, pRMax, widRMax ;
556 
557  G4double z = p.z() - fZshift;
558 
559  distZ = std::fabs(std::fabs(z) - fDz) ;
560  rho = std::sqrt(p.x()*p.x() + p.y()*p.y()) ;
561 
562  tanRMin = (fRmin2 - fRmin1)*0.5/fDz ;
563  secRMin = std::sqrt(1 + tanRMin*tanRMin) ;
564  pRMin = rho - z*tanRMin ;
565  widRMin = fRmin2 - fDz*tanRMin ;
566  distRMin = std::fabs(pRMin - widRMin)/secRMin ;
567 
568  tanRMax = (fRmax2 - fRmax1)*0.5/fDz ;
569  secRMax = std::sqrt(1+tanRMax*tanRMax) ;
570  pRMax = rho - z*tanRMax ;
571  widRMax = fRmax2 - fDz*tanRMax ;
572  distRMax = std::fabs(pRMax - widRMax)/secRMax ;
573 
574  if (distRMin < distRMax) // First minimum
575  {
576  if (distZ < distRMin)
577  {
578 // distMin = distZ ;
579  side = kNZ ;
580  }
581  else
582  {
583 // distMin = distRMin ;
584  side = kNRMin ;
585  }
586  }
587  else
588  {
589  if (distZ < distRMax)
590  {
591 // distMin = distZ ;
592  side = kNZ ;
593  }
594  else
595  {
596 // distMin = distRMax ;
597  side = kNRMax ;
598  }
599  }
600 /*
601  if ( !fPhiFullCone && rho ) // Protected against (0,0,z)
602  {
603  phi = std::atan2(p.y(),p.x()) ;
604 
605  if (phi < 0) { phi += twopi; }
606 
607  if (fSPhi < 0) { distSPhi = std::fabs(phi - (fSPhi + twopi))*rho; }
608  else { distSPhi = std::fabs(phi - fSPhi)*rho; }
609 
610  distEPhi = std::fabs(phi - fSPhi - fDPhi)*rho ;
611 
612  // Find new minimum
613 
614  if (distSPhi < distEPhi)
615  {
616  if (distSPhi < distMin) { side = kNSPhi; }
617  }
618  else
619  {
620  if (distEPhi < distMin) { side = kNEPhi; }
621  }
622  }*/
623  switch (side)
624  {
625  case kNRMin: // Inner radius
626  rho *= secRMin ;
627  norm = G4ThreeVector(-p.x()/rho, -p.y()/rho, tanRMin/secRMin) ;
628  break ;
629  case kNRMax: // Outer radius
630  rho *= secRMax ;
631  norm = G4ThreeVector(p.x()/rho, p.y()/rho, -tanRMax/secRMax) ;
632  break ;
633  case kNZ: // +/- dz
634  if (z > 0) { norm = G4ThreeVector(0,0,1); }
635  else { norm = G4ThreeVector(0,0,-1); }
636  break ;
637 // case kNSPhi:
638 // norm = G4ThreeVector(std::sin(fSPhi), -std::cos(fSPhi), 0) ;
639 // break ;
640 // case kNEPhi:
641 // norm=G4ThreeVector(-std::sin(fSPhi+fDPhi), std::cos(fSPhi+fDPhi), 0) ;
642 // break ;
643  default: // Should never reach this case...
644  DumpInfo();
645  G4Exception("G4ShiftedCone::ApproxSurfaceNormal()",
646  "GeomSolids1002", JustWarning,
647  "Undefined side for valid surface normal to solid.");
648  break ;
649  }
650  return norm ;
651 }
652 
654 //
655 // Calculate distance to shape from outside, along normalised vector
656 // - return kInfinity if no intersection, or intersection distance <= tolerance
657 //
658 // - Compute the intersection with the z planes
659 // - if at valid r, phi, return
660 //
661 // -> If point is outside cone, compute intersection with rmax1*0.5
662 // - if at valid phi,z return
663 // - if inside outer cone, handle case when on tolerant outer cone
664 // boundary and heading inwards(->0 to in)
665 //
666 // -> Compute intersection with inner cone, taking largest +ve root
667 // - if valid (in z,phi), save intersction
668 //
669 // -> If phi segmented, compute intersections with phi half planes
670 // - return smallest of valid phi intersections and
671 // inner radius intersection
672 //
673 // NOTE:
674 // - `if valid' implies tolerant checking of intersection points
675 // - z, phi intersection from Tubs
676 
677 G4double G4ShiftedCone::DistanceToIn( const G4ThreeVector& p,
678  const G4ThreeVector& v ) const
679 {
680  G4double snxt = kInfinity ; // snxt = default return value
681  const G4double dRmax = 50*(fRmax1+fRmax2);// 100*(Rmax1+Rmax2)/2.
682 
683  G4double tanRMax,secRMax,rMaxAv;//,rMaxOAv ; // Data for cones
684  G4double tanRMin,secRMin,rMinAv;//,rMinOAv ;
685  G4double rout,rin ;
686 
687  G4double tolORMin,/*tolORMin2,*/tolIRMin,tolIRMin2 ; // `generous' radii squared
688  G4double /*tolORMax2,*/tolIRMax,tolIRMax2 ;
689  G4double tolODz,tolIDz ;
690 
691  G4double /*Dist,*/ sd,xi,yi,zi,ri=0.,risec,rhoi2;//,cosPsi ; // Intersection point vars
692 
693  G4double t1,t2,t3,b,c,d ; // Quadratic solver variables
694  G4double nt1,nt2,nt3 ;
695 // G4double Comp ;
696 
697  G4ThreeVector Normal;
698 
699  G4double z = p.z() - fZshift;
700 
701  // Cone Precalcs
702 
703  tanRMin = (fRmin2 - fRmin1)*0.5/fDz ;
704  secRMin = std::sqrt(1.0 + tanRMin*tanRMin) ;
705  rMinAv = (fRmin1 + fRmin2)*0.5 ;
706 /*
707  if (rMinAv > halfRadTolerance)
708  {
709  rMinOAv = rMinAv - halfRadTolerance ;
710  }
711  else
712  {
713  rMinOAv = 0.0 ;
714  }*/
715  tanRMax = (fRmax2 - fRmax1)*0.5/fDz ;
716  secRMax = std::sqrt(1.0 + tanRMax*tanRMax) ;
717  rMaxAv = (fRmax1 + fRmax2)*0.5 ;
718 // rMaxOAv = rMaxAv + halfRadTolerance ;
719 
720  // Intersection with z-surfaces
721 
722  tolIDz = fDz - halfCarTolerance ;
723  tolODz = fDz + halfCarTolerance ;
724 
725  if (std::fabs(z) >= tolIDz)
726  {
727  if ( z*v.z() < 0 ) // at +Z going in -Z or visa versa
728  {
729  sd = (std::fabs(z) - fDz)/std::fabs(v.z()) ; // Z intersect distance
730 
731  if( sd < 0.0 ) { sd = 0.0; } // negative dist -> zero
732 
733  xi = p.x() + sd*v.x() ; // Intersection coords
734  yi = p.y() + sd*v.y() ;
735  rhoi2 = xi*xi + yi*yi ;
736 
737  // Check validity of intersection
738  // Calculate (outer) tolerant radi^2 at intersecion
739 
740  if (v.z() > 0)
741  {
742  tolORMin = fRmin1 - halfRadTolerance*secRMin ;
743  tolIRMin = fRmin1 + halfRadTolerance*secRMin ;
744  tolIRMax = fRmax1 - halfRadTolerance*secRMin ;
745  // tolORMax2 = (fRmax1 + halfRadTolerance*secRMax)*
746  // (fRmax1 + halfRadTolerance*secRMax) ;
747  }
748  else
749  {
750  tolORMin = fRmin2 - halfRadTolerance*secRMin ;
751  tolIRMin = fRmin2 + halfRadTolerance*secRMin ;
752  tolIRMax = fRmax2 - halfRadTolerance*secRMin ;
753  // tolORMax2 = (fRmax2 + halfRadTolerance*secRMax)*
754  // (fRmax2 + halfRadTolerance*secRMax) ;
755  }
756  if ( tolORMin > 0 )
757  {
758  // tolORMin2 = tolORMin*tolORMin ;
759  tolIRMin2 = tolIRMin*tolIRMin ;
760  }
761  else
762  {
763  // tolORMin2 = 0.0 ;
764  tolIRMin2 = 0.0 ;
765  }
766  if ( tolIRMax > 0 ) { tolIRMax2 = tolIRMax*tolIRMax; }
767  else { tolIRMax2 = 0.0; }
768 
769  if ( (tolIRMin2 <= rhoi2) && (rhoi2 <= tolIRMax2) )
770  {
771 /* if ( !fPhiFullCone && rhoi2 )
772  {
773  // Psi = angle made with central (average) phi of shape
774 
775  cosPsi = (xi*cosCPhi + yi*sinCPhi)/std::sqrt(rhoi2) ;
776 
777  if (cosPsi >= cosHDPhiIT) { return sd; }
778  }
779  else */
780  {
781  return sd;
782  }
783  }
784  }
785  else // On/outside extent, and heading away -> cannot intersect
786  {
787  return snxt ;
788  }
789  }
790 
791 // ----> Can not intersect z surfaces
792 
793 
794 // Intersection with outer cone (possible return) and
795 // inner cone (must also check phi)
796 //
797 // Intersection point (xi,yi,zi) on line x=p.x+t*v.x etc.
798 //
799 // Intersects with x^2+y^2=(a*z+b)^2
800 //
801 // where a=tanRMax or tanRMin
802 // b=rMaxAv or rMinAv
803 //
804 // (vx^2+vy^2-(a*vz)^2)t^2+2t(pxvx+pyvy-a*vz(a*pz+b))+px^2+py^2-(a*pz+b)^2=0 ;
805 // t1 t2 t3
806 //
807 // \--------u-------/ \-----------v----------/ \---------w--------/
808 //
809 
810  t1 = 1.0 - v.z()*v.z() ;
811  t2 = p.x()*v.x() + p.y()*v.y() ;
812  t3 = p.x()*p.x() + p.y()*p.y() ;
813  rin = tanRMin*z + rMinAv ;
814  rout = tanRMax*z + rMaxAv ;
815 
816  // Outer Cone Intersection
817  // Must be outside/on outer cone for valid intersection
818 
819  nt1 = t1 - (tanRMax*v.z())*(tanRMax*v.z()) ;
820  nt2 = t2 - tanRMax*v.z()*rout ;
821  nt3 = t3 - rout*rout ;
822 
823  if (std::fabs(nt1) > kRadTolerance) // Equation quadratic => 2 roots
824  {
825  b = nt2/nt1;
826  c = nt3/nt1;
827  d = b*b-c ;
828  if ( (nt3 > rout*rout*kRadTolerance*kRadTolerance*secRMax*secRMax)
829  || (rout < 0) )
830  {
831  // If outside real cone (should be rho-rout>kRadTolerance*0.5
832  // NOT rho^2 etc) saves a std::sqrt() at expense of accuracy
833 
834  if (d >= 0)
835  {
836 
837  if ((rout < 0) && (nt3 <= 0))
838  {
839  // Inside `shadow cone' with -ve radius
840  // -> 2nd root could be on real cone
841 
842  if (b>0) { sd = c/(-b-std::sqrt(d)); }
843  else { sd = -b + std::sqrt(d); }
844  }
845  else
846  {
847  if ((b <= 0) && (c >= 0)) // both >=0, try smaller root
848  {
849  sd=c/(-b+std::sqrt(d));
850  }
851  else
852  {
853  if ( c <= 0 ) // second >=0
854  {
855  sd = -b + std::sqrt(d) ;
856  if((sd<0) & (sd>-halfRadTolerance)) sd=0;
857  }
858  else // both negative, travel away
859  {
860  return kInfinity ;
861  }
862  }
863  }
864  if ( sd >= 0 ) // If 'forwards'. Check z intersection
865  {
866  if ( sd>dRmax ) // Avoid rounding errors due to precision issues on
867  { // 64 bits systems. Split long distances and recompute
868  G4double fTerm = sd-std::fmod(sd,dRmax);
869  sd = fTerm + DistanceToIn(p+fTerm*v,v);
870  }
871  zi = z + sd*v.z() ;
872 
873  if (std::fabs(zi) <= tolODz)
874  {
875  // Z ok. Check phi intersection if reqd
876 
877  return sd;
878 /* if ( fPhiFullCone ) { return sd; }
879  else
880  {
881  xi = p.x() + sd*v.x() ;
882  yi = p.y() + sd*v.y() ;
883  ri = rMaxAv + zi*tanRMax ;
884  cosPsi = (xi*cosCPhi + yi*sinCPhi)/ri ;
885 
886  if ( cosPsi >= cosHDPhiIT ) { return sd; }
887  }*/
888  }
889  } // end if (sd>0)
890  }
891  }
892  else
893  {
894  // Inside outer cone
895  // check not inside, and heading through G4ShiftedCone (-> 0 to in)
896 
897  if ( ( t3 > (rin + halfRadTolerance*secRMin)*
898  (rin + halfRadTolerance*secRMin) )
899  && (nt2 < 0) && (d >= 0) && (std::fabs(z) <= tolIDz) )
900  {
901  // Inside cones, delta r -ve, inside z extent
902  // Point is on the Surface => check Direction using Normal.dot(v)
903 
904  xi = p.x() ;
905  yi = p.y() ;
906  risec = std::sqrt(xi*xi + yi*yi)*secRMax ;
907  Normal = G4ThreeVector(xi/risec,yi/risec,-tanRMax/secRMax) ;
908 /* if ( !fPhiFullCone )
909  {
910  cosPsi = (p.x()*cosCPhi + p.y()*sinCPhi)/std::sqrt(t3) ;
911  if ( cosPsi >= cosHDPhiIT )
912  {
913  if ( Normal.dot(v) <= 0 ) { return 0.0; }
914  }
915  }
916  else*/
917  {
918  if ( Normal.dot(v) <= 0 ) { return 0.0; }
919  }
920  }
921  }
922  }
923  else // Single root case
924  {
925  if ( std::fabs(nt2) > kRadTolerance )
926  {
927  sd = -0.5*nt3/nt2 ;
928 
929  if ( sd < 0 ) { return kInfinity; } // travel away
930  else // sd >= 0, If 'forwards'. Check z intersection
931  {
932  zi = z + sd*v.z() ;
933 
934  if ((std::fabs(zi) <= tolODz) && (nt2 < 0))
935  {
936  // Z ok. Check phi intersection if reqd
937  return sd;
938 /* if ( fPhiFullCone ) { return sd; }
939  else
940  {
941  xi = p.x() + sd*v.x() ;
942  yi = p.y() + sd*v.y() ;
943  ri = rMaxAv + zi*tanRMax ;
944  cosPsi = (xi*cosCPhi + yi*sinCPhi)/ri ;
945 
946  if (cosPsi >= cosHDPhiIT) { return sd; }
947  }*/
948  }
949  }
950  }
951  else // travel || cone surface from its origin
952  {
953  sd = kInfinity ;
954  }
955  }
956 
957  // Inner Cone Intersection
958  // o Space is divided into 3 areas:
959  // 1) Radius greater than real inner cone & imaginary cone & outside
960  // tolerance
961  // 2) Radius less than inner or imaginary cone & outside tolarance
962  // 3) Within tolerance of real or imaginary cones
963  // - Extra checks needed for 3's intersections
964  // => lots of duplicated code
965 
966  if (rMinAv)
967  {
968  nt1 = t1 - (tanRMin*v.z())*(tanRMin*v.z()) ;
969  nt2 = t2 - tanRMin*v.z()*rin ;
970  nt3 = t3 - rin*rin ;
971 
972  if ( nt1 )
973  {
974  if ( nt3 > rin*kRadTolerance*secRMin )
975  {
976  // At radius greater than real & imaginary cones
977  // -> 2nd root, with zi check
978 
979  b = nt2/nt1 ;
980  c = nt3/nt1 ;
981  d = b*b-c ;
982  if (d >= 0) // > 0
983  {
984  if(b>0){sd = c/( -b-std::sqrt(d));}
985  else {sd = -b + std::sqrt(d) ;}
986 
987  if ( sd >= 0 ) // > 0
988  {
989  if ( sd>dRmax ) // Avoid rounding errors due to precision issues on
990  { // 64 bits systems. Split long distance and recompute
991  G4double fTerm = sd-std::fmod(sd,dRmax);
992  sd = fTerm + DistanceToIn(p+fTerm*v,v);
993  }
994  zi = z + sd*v.z() ;
995 
996  if ( std::fabs(zi) <= tolODz )
997  {
998 /* if ( !fPhiFullCone )
999  {
1000  xi = p.x() + sd*v.x() ;
1001  yi = p.y() + sd*v.y() ;
1002  ri = rMinAv + zi*tanRMin ;
1003  cosPsi = (xi*cosCPhi + yi*sinCPhi)/ri ;
1004 
1005  if (cosPsi >= cosHDPhiIT)
1006  {
1007  if ( sd > halfRadTolerance ) { snxt=sd; }
1008  else
1009  {
1010  // Calculate a normal vector in order to check Direction
1011 
1012  risec = std::sqrt(xi*xi + yi*yi)*secRMin ;
1013  Normal = G4ThreeVector(-xi/risec,-yi/risec,tanRMin/secRMin);
1014  if ( Normal.dot(v) <= 0 ) { snxt = sd; }
1015  }
1016  }
1017  }
1018  else */
1019  {
1020  if ( sd > halfRadTolerance ) { return sd; }
1021  else
1022  {
1023  // Calculate a normal vector in order to check Direction
1024 
1025  xi = p.x() + sd*v.x() ;
1026  yi = p.y() + sd*v.y() ;
1027  risec = std::sqrt(xi*xi + yi*yi)*secRMin ;
1028  Normal = G4ThreeVector(-xi/risec,-yi/risec,tanRMin/secRMin) ;
1029  if ( Normal.dot(v) <= 0 ) { return sd; }
1030  }
1031  }
1032  }
1033  }
1034  }
1035  }
1036  else if ( nt3 < -rin*kRadTolerance*secRMin )
1037  {
1038  // Within radius of inner cone (real or imaginary)
1039  // -> Try 2nd root, with checking intersection is with real cone
1040  // -> If check fails, try 1st root, also checking intersection is
1041  // on real cone
1042 
1043  b = nt2/nt1 ;
1044  c = nt3/nt1 ;
1045  d = b*b - c ;
1046 
1047  if ( d >= 0 ) // > 0
1048  {
1049  if (b>0) { sd = c/(-b-std::sqrt(d)); }
1050  else { sd = -b + std::sqrt(d); }
1051  zi = z + sd*v.z() ;
1052  ri = rMinAv + zi*tanRMin ;
1053 
1054  if ( ri > 0 )
1055  {
1056  if ( (sd >= 0) && (std::fabs(zi) <= tolODz) ) // sd > 0
1057  {
1058  if ( sd>dRmax ) // Avoid rounding errors due to precision issues
1059  { // seen on 64 bits systems. Split and recompute
1060  G4double fTerm = sd-std::fmod(sd,dRmax);
1061  sd = fTerm + DistanceToIn(p+fTerm*v,v);
1062  }
1063 /* if ( !fPhiFullCone )
1064  {
1065  xi = p.x() + sd*v.x() ;
1066  yi = p.y() + sd*v.y() ;
1067  cosPsi = (xi*cosCPhi + yi*sinCPhi)/ri ;
1068 
1069  if (cosPsi >= cosHDPhiOT)
1070  {
1071  if ( sd > halfRadTolerance ) { snxt=sd; }
1072  else
1073  {
1074  // Calculate a normal vector in order to check Direction
1075 
1076  risec = std::sqrt(xi*xi + yi*yi)*secRMin ;
1077  Normal = G4ThreeVector(-xi/risec,-yi/risec,tanRMin/secRMin);
1078  if ( Normal.dot(v) <= 0 ) { snxt = sd; }
1079  }
1080  }
1081  }
1082  else */
1083  {
1084  if( sd > halfRadTolerance ) { return sd; }
1085  else
1086  {
1087  // Calculate a normal vector in order to check Direction
1088 
1089  xi = p.x() + sd*v.x() ;
1090  yi = p.y() + sd*v.y() ;
1091  risec = std::sqrt(xi*xi + yi*yi)*secRMin ;
1092  Normal = G4ThreeVector(-xi/risec,-yi/risec,tanRMin/secRMin) ;
1093  if ( Normal.dot(v) <= 0 ) { return sd; }
1094  }
1095  }
1096  }
1097  }
1098  else
1099  {
1100  if (b>0) { sd = -b - std::sqrt(d); }
1101  else { sd = c/(-b+std::sqrt(d)); }
1102  zi = z + sd*v.z() ;
1103  ri = rMinAv + zi*tanRMin ;
1104 
1105  if ( (sd >= 0) && (ri > 0) && (std::fabs(zi) <= tolODz) ) // sd>0
1106  {
1107  if ( sd>dRmax ) // Avoid rounding errors due to precision issues
1108  { // seen on 64 bits systems. Split and recompute
1109  G4double fTerm = sd-std::fmod(sd,dRmax);
1110  sd = fTerm + DistanceToIn(p+fTerm*v,v);
1111  }
1112 /* if ( !fPhiFullCone )
1113  {
1114  xi = p.x() + sd*v.x() ;
1115  yi = p.y() + sd*v.y() ;
1116  cosPsi = (xi*cosCPhi + yi*sinCPhi)/ri ;
1117 
1118  if (cosPsi >= cosHDPhiIT)
1119  {
1120  if ( sd > halfRadTolerance ) { snxt=sd; }
1121  else
1122  {
1123  // Calculate a normal vector in order to check Direction
1124 
1125  risec = std::sqrt(xi*xi + yi*yi)*secRMin ;
1126  Normal = G4ThreeVector(-xi/risec,-yi/risec,tanRMin/secRMin);
1127  if ( Normal.dot(v) <= 0 ) { snxt = sd; }
1128  }
1129  }
1130  }
1131  else */
1132  {
1133  if ( sd > halfRadTolerance ) { return sd; }
1134  else
1135  {
1136  // Calculate a normal vector in order to check Direction
1137 
1138  xi = p.x() + sd*v.x() ;
1139  yi = p.y() + sd*v.y() ;
1140  risec = std::sqrt(xi*xi + yi*yi)*secRMin ;
1141  Normal = G4ThreeVector(-xi/risec,-yi/risec,tanRMin/secRMin) ;
1142  if ( Normal.dot(v) <= 0 ) { return sd; }
1143  }
1144  }
1145  }
1146  }
1147  }
1148  }
1149  else
1150  {
1151  // Within kRadTol*0.5 of inner cone (real OR imaginary)
1152  // ----> Check not travelling through (=>0 to in)
1153  // ----> if not:
1154  // -2nd root with validity check
1155 
1156  if ( std::fabs(z) <= tolODz )
1157  {
1158  if ( nt2 > 0 )
1159  {
1160  // Inside inner real cone, heading outwards, inside z range
1161 
1162 /* if ( !fPhiFullCone )
1163  {
1164  cosPsi = (p.x()*cosCPhi + p.y()*sinCPhi)/std::sqrt(t3) ;
1165 
1166  if (cosPsi >= cosHDPhiIT) { return 0.0; }
1167  }
1168  else */ { return 0.0; }
1169  }
1170  else
1171  {
1172  // Within z extent, but not travelling through
1173  // -> 2nd root or kInfinity if 1st root on imaginary cone
1174 
1175  b = nt2/nt1 ;
1176  c = nt3/nt1 ;
1177  d = b*b - c ;
1178 
1179  if ( d >= 0 ) // > 0
1180  {
1181  if (b>0) { sd = -b - std::sqrt(d); }
1182  else { sd = c/(-b+std::sqrt(d)); }
1183  zi = z + sd*v.z() ;
1184  ri = rMinAv + zi*tanRMin ;
1185 
1186  if ( ri > 0 ) // 2nd root
1187  {
1188  if (b>0) { sd = c/(-b-std::sqrt(d)); }
1189  else { sd = -b + std::sqrt(d); }
1190 
1191  zi = z + sd*v.z() ;
1192 
1193  if ( (sd >= 0) && (std::fabs(zi) <= tolODz) ) // sd>0
1194  {
1195  if ( sd>dRmax ) // Avoid rounding errors due to precision issue
1196  { // seen on 64 bits systems. Split and recompute
1197  G4double fTerm = sd-std::fmod(sd,dRmax);
1198  sd = fTerm + DistanceToIn(p+fTerm*v,v);
1199  }
1200 /* if ( !fPhiFullCone )
1201  {
1202  xi = p.x() + sd*v.x() ;
1203  yi = p.y() + sd*v.y() ;
1204  ri = rMinAv + zi*tanRMin ;
1205  cosPsi = (xi*cosCPhi + yi*sinCPhi)/ri ;
1206 
1207  if ( cosPsi >= cosHDPhiIT ) { snxt = sd; }
1208  }
1209  else */ { return sd; }
1210  }
1211  }
1212  else { return kInfinity; }
1213  }
1214  }
1215  }
1216  else // 2nd root
1217  {
1218  b = nt2/nt1 ;
1219  c = nt3/nt1 ;
1220  d = b*b - c ;
1221 
1222  if ( d > 0 )
1223  {
1224  if (b>0) { sd = c/(-b-std::sqrt(d)); }
1225  else { sd = -b + std::sqrt(d) ; }
1226  zi = z + sd*v.z() ;
1227 
1228  if ( (sd >= 0) && (std::fabs(zi) <= tolODz) ) // sd>0
1229  {
1230  if ( sd>dRmax ) // Avoid rounding errors due to precision issues
1231  { // seen on 64 bits systems. Split and recompute
1232  G4double fTerm = sd-std::fmod(sd,dRmax);
1233  sd = fTerm + DistanceToIn(p+fTerm*v,v);
1234  }
1235 /* if ( !fPhiFullCone )
1236  {
1237  xi = p.x() + sd*v.x();
1238  yi = p.y() + sd*v.y();
1239  ri = rMinAv + zi*tanRMin ;
1240  cosPsi = (xi*cosCPhi + yi*sinCPhi)/ri;
1241 
1242  if (cosPsi >= cosHDPhiIT) { snxt = sd; }
1243  }
1244  else */ { return sd; }
1245  }
1246  }
1247  }
1248  }
1249  }
1250  }
1251 
1252  // Phi segment intersection
1253  //
1254  // o Tolerant of points inside phi planes by up to kCarTolerance*0.5
1255  //
1256  // o NOTE: Large duplication of code between sphi & ephi checks
1257  // -> only diffs: sphi -> ephi, Comp -> -Comp and half-plane
1258  // intersection check <=0 -> >=0
1259  // -> Should use some form of loop Construct
1260 /*
1261  if ( !fPhiFullCone )
1262  {
1263  // First phi surface (starting phi)
1264 
1265  Comp = v.x()*sinSPhi - v.y()*cosSPhi ;
1266 
1267  if ( Comp < 0 ) // Component in outwards normal dirn
1268  {
1269  Dist = (p.y()*cosSPhi - p.x()*sinSPhi) ;
1270 
1271  if (Dist < halfCarTolerance)
1272  {
1273  sd = Dist/Comp ;
1274 
1275  if ( sd < snxt )
1276  {
1277  if ( sd < 0 ) { sd = 0.0; }
1278 
1279  zi = z + sd*v.z() ;
1280 
1281  if ( std::fabs(zi) <= tolODz )
1282  {
1283  xi = p.x() + sd*v.x() ;
1284  yi = p.y() + sd*v.y() ;
1285  rhoi2 = xi*xi + yi*yi ;
1286  tolORMin2 = (rMinOAv + zi*tanRMin)*(rMinOAv + zi*tanRMin) ;
1287  tolORMax2 = (rMaxOAv + zi*tanRMax)*(rMaxOAv + zi*tanRMax) ;
1288 
1289  if ( (rhoi2 >= tolORMin2) && (rhoi2 <= tolORMax2) )
1290  {
1291  // z and r intersections good - check intersecting with
1292  // correct half-plane
1293 
1294  if ((yi*cosCPhi - xi*sinCPhi) <= 0 ) { snxt = sd; }
1295  }
1296  }
1297  }
1298  }
1299  }
1300 
1301  // Second phi surface (Ending phi)
1302 
1303  Comp = -(v.x()*sinEPhi - v.y()*cosEPhi) ;
1304 
1305  if ( Comp < 0 ) // Component in outwards normal dirn
1306  {
1307  Dist = -(p.y()*cosEPhi - p.x()*sinEPhi) ;
1308  if (Dist < halfCarTolerance)
1309  {
1310  sd = Dist/Comp ;
1311 
1312  if ( sd < snxt )
1313  {
1314  if ( sd < 0 ) { sd = 0.0; }
1315 
1316  zi = z + sd*v.z() ;
1317 
1318  if (std::fabs(zi) <= tolODz)
1319  {
1320  xi = p.x() + sd*v.x() ;
1321  yi = p.y() + sd*v.y() ;
1322  rhoi2 = xi*xi + yi*yi ;
1323  tolORMin2 = (rMinOAv + zi*tanRMin)*(rMinOAv + zi*tanRMin) ;
1324  tolORMax2 = (rMaxOAv + zi*tanRMax)*(rMaxOAv + zi*tanRMax) ;
1325 
1326  if ( (rhoi2 >= tolORMin2) && (rhoi2 <= tolORMax2) )
1327  {
1328  // z and r intersections good - check intersecting with
1329  // correct half-plane
1330 
1331  if ( (yi*cosCPhi - xi*sinCPhi) >= 0.0 ) { snxt = sd; }
1332  }
1333  }
1334  }
1335  }
1336  }
1337  }*/
1338  if (snxt < halfCarTolerance) { snxt = 0.; }
1339 
1340  return snxt ;
1341 }
1342 
1344 //
1345 // Calculate distance (<= actual) to closest surface of shape from outside
1346 // - Calculate distance to z, radial planes
1347 // - Only to phi planes if outside phi extent
1348 // - Return 0 if point inside
1349 
1350 G4double G4ShiftedCone::DistanceToIn(const G4ThreeVector& p) const
1351 {
1352  G4double safe=0.0, rho, safeR1, safeR2, safeZ;//, safePhi, cosPsi ;
1353  G4double tanRMin, secRMin, pRMin ;
1354  G4double tanRMax, secRMax, pRMax ;
1355 
1356  G4double z = p.z() - fZshift;
1357 
1358  rho = std::sqrt(p.x()*p.x() + p.y()*p.y()) ;
1359  safeZ = std::fabs(z) - fDz ;
1360 
1361  if ( fRmin1 || fRmin2 )
1362  {
1363  tanRMin = (fRmin2 - fRmin1)*0.5/fDz ;
1364  secRMin = std::sqrt(1.0 + tanRMin*tanRMin) ;
1365  pRMin = tanRMin*z + (fRmin1 + fRmin2)*0.5 ;
1366  safeR1 = (pRMin - rho)/secRMin ;
1367 
1368  tanRMax = (fRmax2 - fRmax1)*0.5/fDz ;
1369  secRMax = std::sqrt(1.0 + tanRMax*tanRMax) ;
1370  pRMax = tanRMax*z + (fRmax1 + fRmax2)*0.5 ;
1371  safeR2 = (rho - pRMax)/secRMax ;
1372 
1373  if ( safeR1 > safeR2) { safe = safeR1; }
1374  else { safe = safeR2; }
1375  }
1376  else
1377  {
1378  tanRMax = (fRmax2 - fRmax1)*0.5/fDz ;
1379  secRMax = std::sqrt(1.0 + tanRMax*tanRMax) ;
1380  pRMax = tanRMax*z + (fRmax1 + fRmax2)*0.5 ;
1381  safe = (rho - pRMax)/secRMax ;
1382  }
1383  if ( safeZ > safe ) { safe = safeZ; }
1384 
1385 /* if ( !fPhiFullCone && rho )
1386  {
1387  // Psi=angle from central phi to point
1388 
1389  cosPsi = (p.x()*cosCPhi + p.y()*sinCPhi)/rho ;
1390 
1391  if ( cosPsi < std::cos(fDPhi*0.5) ) // Point lies outside phi range
1392  {
1393  if ( (p.y()*cosCPhi - p.x()*sinCPhi) <= 0.0 )
1394  {
1395  safePhi = std::fabs(p.x()*std::sin(fSPhi)-p.y()*std::cos(fSPhi));
1396  }
1397  else
1398  {
1399  safePhi = std::fabs(p.x()*sinEPhi-p.y()*cosEPhi);
1400  }
1401  if ( safePhi > safe ) { safe = safePhi; }
1402  }
1403  }*/
1404  if ( safe < 0.0 ) { safe = 0.0; }
1405 
1406  return safe ;
1407 }
1408 
1410 //
1411 // Calculate distance to surface of shape from 'inside', allowing for tolerance
1412 // - Only Calc rmax intersection if no valid rmin intersection
1413 
1414 G4double G4ShiftedCone::DistanceToOut( const G4ThreeVector& p,
1415  const G4ThreeVector& v,
1416  const G4bool calcNorm,
1417  G4bool *validNorm,
1418  G4ThreeVector *n) const
1419 {
1420  ESide side = kNull, sider = kNull;//, sidephi = kNull;
1421 
1422  G4double snxt,srd,/*sphi,*/pdist ;
1423 
1424  G4double tanRMax, secRMax, rMaxAv ; // Data for outer cone
1425  G4double tanRMin, secRMin, rMinAv ; // Data for inner cone
1426 
1427  G4double t1, t2, t3, rout, rin, nt1, nt2, nt3 ;
1428  G4double b, c, d, sr2, sr3 ;
1429 
1430  // Vars for intersection within tolerance
1431 
1432  ESide sidetol = kNull ;
1433  G4double slentol = kInfinity ;
1434 
1435  // Vars for phi intersection:
1436 
1437 // G4double pDistS, compS, pDistE, compE, sphi2, vphi ;
1438  G4double zi, ri, deltaRoi2, xi, yi, risec ;
1439 
1440  // Z plane intersection
1441 
1442  G4double z = p.z() - fZshift;
1443 
1444  if ( v.z() > 0.0 )
1445  {
1446  pdist = fDz - z ;
1447 
1448  if (pdist > halfCarTolerance)
1449  {
1450  snxt = pdist/v.z() ;
1451  side = kPZ ;
1452  }
1453  else
1454  {
1455  if (calcNorm)
1456  {
1457  *n = G4ThreeVector(0,0,1) ;
1458  *validNorm = true ;
1459  }
1460  return snxt = 0.0;
1461  }
1462  }
1463  else if ( v.z() < 0.0 )
1464  {
1465  pdist = fDz + z ;
1466 
1467  if ( pdist > halfCarTolerance)
1468  {
1469  snxt = -pdist/v.z() ;
1470  side = kMZ ;
1471  }
1472  else
1473  {
1474  if ( calcNorm )
1475  {
1476  *n = G4ThreeVector(0,0,-1) ;
1477  *validNorm = true ;
1478  }
1479  return snxt = 0.0 ;
1480  }
1481  }
1482  else // Travel perpendicular to z axis
1483  {
1484  snxt = kInfinity ;
1485  side = kNull ;
1486  }
1487 
1488  // Radial Intersections
1489  //
1490  // Intersection with outer cone (possible return) and
1491  // inner cone (must also check phi)
1492  //
1493  // Intersection point (xi,yi,zi) on line x=p.x+t*v.x etc.
1494  //
1495  // Intersects with x^2+y^2=(a*z+b)^2
1496  //
1497  // where a=tanRMax or tanRMin
1498  // b=rMaxAv or rMinAv
1499  //
1500  // (vx^2+vy^2-(a*vz)^2)t^2+2t(pxvx+pyvy-a*vz(a*pz+b))+px^2+py^2-(a*pz+b)^2=0 ;
1501  // t1 t2 t3
1502  //
1503  // \--------u-------/ \-----------v----------/ \---------w--------/
1504 
1505  tanRMax = (fRmax2 - fRmax1)*0.5/fDz ;
1506  secRMax = std::sqrt(1.0 + tanRMax*tanRMax) ;
1507  rMaxAv = (fRmax1 + fRmax2)*0.5 ;
1508 
1509 
1510  t1 = 1.0 - v.z()*v.z() ; // since v normalised
1511  t2 = p.x()*v.x() + p.y()*v.y() ;
1512  t3 = p.x()*p.x() + p.y()*p.y() ;
1513  rout = tanRMax*z + rMaxAv ;
1514 
1515  nt1 = t1 - (tanRMax*v.z())*(tanRMax*v.z()) ;
1516  nt2 = t2 - tanRMax*v.z()*rout ;
1517  nt3 = t3 - rout*rout ;
1518 
1519  if (v.z() > 0.0)
1520  {
1521  deltaRoi2 = snxt*snxt*t1 + 2*snxt*t2 + t3
1522  - fRmax2*(fRmax2 + kRadTolerance*secRMax);
1523  }
1524  else if ( v.z() < 0.0 )
1525  {
1526  deltaRoi2 = snxt*snxt*t1 + 2*snxt*t2 + t3
1527  - fRmax1*(fRmax1 + kRadTolerance*secRMax);
1528  }
1529  else
1530  {
1531  deltaRoi2 = 1.0;
1532  }
1533 
1534  if ( nt1 && (deltaRoi2 > 0.0) )
1535  {
1536  // Equation quadratic => 2 roots : second root must be leaving
1537 
1538  b = nt2/nt1 ;
1539  c = nt3/nt1 ;
1540  d = b*b - c ;
1541 
1542  if ( d >= 0 )
1543  {
1544  // Check if on outer cone & heading outwards
1545  // NOTE: Should use rho-rout>-kRadTolerance*0.5
1546 
1547  if (nt3 > -halfRadTolerance && nt2 >= 0 )
1548  {
1549  if (calcNorm)
1550  {
1551  risec = std::sqrt(t3)*secRMax ;
1552  *validNorm = true ;
1553  *n = G4ThreeVector(p.x()/risec,p.y()/risec,-tanRMax/secRMax);
1554  }
1555  return snxt=0 ;
1556  }
1557  else
1558  {
1559  sider = kRMax ;
1560  if (b>0) { srd = -b - std::sqrt(d); }
1561  else { srd = c/(-b+std::sqrt(d)) ; }
1562 
1563  zi = z + srd*v.z() ;
1564  ri = tanRMax*zi + rMaxAv ;
1565 
1566  if ((ri >= 0) && (-halfRadTolerance <= srd) && (srd <= halfRadTolerance))
1567  {
1568  // An intersection within the tolerance
1569  // we will Store it in case it is good -
1570  //
1571  slentol = srd ;
1572  sidetol = kRMax ;
1573  }
1574  if ( (ri < 0) || (srd < halfRadTolerance) )
1575  {
1576  // Safety: if both roots -ve ensure that srd cannot `win'
1577  // distance to out
1578 
1579  if (b>0) { sr2 = c/(-b-std::sqrt(d)); }
1580  else { sr2 = -b + std::sqrt(d); }
1581  zi = z + sr2*v.z() ;
1582  ri = tanRMax*zi + rMaxAv ;
1583 
1584  if ((ri >= 0) && (sr2 > halfRadTolerance))
1585  {
1586  srd = sr2;
1587  }
1588  else
1589  {
1590  srd = kInfinity ;
1591 
1592  if( (-halfRadTolerance <= sr2) && ( sr2 <= halfRadTolerance) )
1593  {
1594  // An intersection within the tolerance.
1595  // Storing it in case it is good.
1596 
1597  slentol = sr2 ;
1598  sidetol = kRMax ;
1599  }
1600  }
1601  }
1602  }
1603  }
1604  else
1605  {
1606  // No intersection with outer cone & not parallel
1607  // -> already outside, no intersection
1608 
1609  if ( calcNorm )
1610  {
1611  risec = std::sqrt(t3)*secRMax;
1612  *validNorm = true;
1613  *n = G4ThreeVector(p.x()/risec,p.y()/risec,-tanRMax/secRMax);
1614  }
1615  return snxt = 0.0 ;
1616  }
1617  }
1618  else if ( nt2 && (deltaRoi2 > 0.0) )
1619  {
1620  // Linear case (only one intersection) => point outside outer cone
1621 
1622  if ( calcNorm )
1623  {
1624  risec = std::sqrt(t3)*secRMax;
1625  *validNorm = true;
1626  *n = G4ThreeVector(p.x()/risec,p.y()/risec,-tanRMax/secRMax);
1627  }
1628  return snxt = 0.0 ;
1629  }
1630  else
1631  {
1632  // No intersection -> parallel to outer cone
1633  // => Z or inner cone intersection
1634 
1635  srd = kInfinity ;
1636  }
1637 
1638  // Check possible intersection within tolerance
1639 
1640  if ( slentol <= halfCarTolerance )
1641  {
1642  // An intersection within the tolerance was found.
1643  // We must accept it only if the momentum points outwards.
1644  //
1645  // G4ThreeVector ptTol ; // The point of the intersection
1646  // ptTol= p + slentol*v ;
1647  // ri=tanRMax*zi+rMaxAv ;
1648  //
1649  // Calculate a normal vector, as below
1650 
1651  xi = p.x() + slentol*v.x();
1652  yi = p.y() + slentol*v.y();
1653  risec = std::sqrt(xi*xi + yi*yi)*secRMax;
1654  G4ThreeVector Normal = G4ThreeVector(xi/risec,yi/risec,-tanRMax/secRMax);
1655 
1656  if ( Normal.dot(v) > 0 ) // We will leave the Cone immediatelly
1657  {
1658  if ( calcNorm )
1659  {
1660  *n = Normal.unit() ;
1661  *validNorm = true ;
1662  }
1663  return snxt = 0.0 ;
1664  }
1665  else // On the surface, but not heading out so we ignore this intersection
1666  { // (as it is within tolerance).
1667  slentol = kInfinity ;
1668  }
1669  }
1670 
1671  // Inner Cone intersection
1672 
1673  if ( fRmin1 || fRmin2 )
1674  {
1675  tanRMin = (fRmin2 - fRmin1)*0.5/fDz ;
1676  nt1 = t1 - (tanRMin*v.z())*(tanRMin*v.z()) ;
1677 
1678  if ( nt1 )
1679  {
1680  secRMin = std::sqrt(1.0 + tanRMin*tanRMin) ;
1681  rMinAv = (fRmin1 + fRmin2)*0.5 ;
1682  rin = tanRMin*z + rMinAv ;
1683  nt2 = t2 - tanRMin*v.z()*rin ;
1684  nt3 = t3 - rin*rin ;
1685 
1686  // Equation quadratic => 2 roots : first root must be leaving
1687 
1688  b = nt2/nt1 ;
1689  c = nt3/nt1 ;
1690  d = b*b - c ;
1691 
1692  if ( d >= 0.0 )
1693  {
1694  // NOTE: should be rho-rin<kRadTolerance*0.5,
1695  // but using squared versions for efficiency
1696 
1697  if (nt3 < kRadTolerance*(rin + kRadTolerance*0.25))
1698  {
1699  if ( nt2 < 0.0 )
1700  {
1701  if (calcNorm) { *validNorm = false; }
1702  return snxt = 0.0;
1703  }
1704  }
1705  else
1706  {
1707  if (b>0) { sr2 = -b - std::sqrt(d); }
1708  else { sr2 = c/(-b+std::sqrt(d)); }
1709  zi = z + sr2*v.z() ;
1710  ri = tanRMin*zi + rMinAv ;
1711 
1712  if( (ri>=0.0)&&(-halfRadTolerance<=sr2)&&(sr2<=halfRadTolerance) )
1713  {
1714  // An intersection within the tolerance
1715  // storing it in case it is good.
1716 
1717  slentol = sr2 ;
1718  sidetol = kRMax ;
1719  }
1720  if( (ri<0) || (sr2 < halfRadTolerance) )
1721  {
1722  if (b>0) { sr3 = c/(-b-std::sqrt(d)); }
1723  else { sr3 = -b + std::sqrt(d) ; }
1724 
1725  // Safety: if both roots -ve ensure that srd cannot `win'
1726  // distancetoout
1727 
1728  if ( sr3 > halfRadTolerance )
1729  {
1730  if( sr3 < srd )
1731  {
1732  zi = z + sr3*v.z() ;
1733  ri = tanRMin*zi + rMinAv ;
1734 
1735  if ( ri >= 0.0 )
1736  {
1737  srd=sr3 ;
1738  sider=kRMin ;
1739  }
1740  }
1741  }
1742  else if ( sr3 > -halfRadTolerance )
1743  {
1744  // Intersection in tolerance. Store to check if it's good
1745 
1746  slentol = sr3 ;
1747  sidetol = kRMin ;
1748  }
1749  }
1750  else if ( (sr2 < srd) && (sr2 > halfCarTolerance) )
1751  {
1752  srd = sr2 ;
1753  sider = kRMin ;
1754  }
1755  else if (sr2 > -halfCarTolerance)
1756  {
1757  // Intersection in tolerance. Store to check if it's good
1758 
1759  slentol = sr2 ;
1760  sidetol = kRMin ;
1761  }
1762  if( slentol <= halfCarTolerance )
1763  {
1764  // An intersection within the tolerance was found.
1765  // We must accept it only if the momentum points outwards.
1766 
1767  G4ThreeVector Normal ;
1768 
1769  // Calculate a normal vector, as below
1770 
1771  xi = p.x() + slentol*v.x() ;
1772  yi = p.y() + slentol*v.y() ;
1773  if( sidetol==kRMax )
1774  {
1775  risec = std::sqrt(xi*xi + yi*yi)*secRMax ;
1776  Normal = G4ThreeVector(xi/risec,yi/risec,-tanRMax/secRMax) ;
1777  }
1778  else
1779  {
1780  risec = std::sqrt(xi*xi + yi*yi)*secRMin ;
1781  Normal = G4ThreeVector(-xi/risec,-yi/risec,tanRMin/secRMin) ;
1782  }
1783  if( Normal.dot(v) > 0 )
1784  {
1785  // We will leave the cone immediately
1786 
1787  if( calcNorm )
1788  {
1789  *n = Normal.unit() ;
1790  *validNorm = true ;
1791  }
1792  return snxt = 0.0 ;
1793  }
1794  else
1795  {
1796  // On the surface, but not heading out so we ignore this
1797  // intersection (as it is within tolerance).
1798 
1799  slentol = kInfinity ;
1800  }
1801  }
1802  }
1803  }
1804  }
1805  }
1806 
1807  // Linear case => point outside inner cone ---> outer cone intersect
1808  //
1809  // Phi Intersection
1810 /*
1811  if ( !fPhiFullCone )
1812  {
1813  // add angle calculation with correction
1814  // of the difference in domain of atan2 and Sphi
1815 
1816  vphi = std::atan2(v.y(),v.x()) ;
1817 
1818  if ( vphi < fSPhi - halfAngTolerance ) { vphi += twopi; }
1819  else if ( vphi > fSPhi + fDPhi + halfAngTolerance ) { vphi -= twopi; }
1820 
1821  if ( p.x() || p.y() ) // Check if on z axis (rho not needed later)
1822  {
1823  // pDist -ve when inside
1824 
1825  pDistS = p.x()*sinSPhi - p.y()*cosSPhi ;
1826  pDistE = -p.x()*sinEPhi + p.y()*cosEPhi ;
1827 
1828  // Comp -ve when in direction of outwards normal
1829 
1830  compS = -sinSPhi*v.x() + cosSPhi*v.y() ;
1831  compE = sinEPhi*v.x() - cosEPhi*v.y() ;
1832 
1833  sidephi = kNull ;
1834 
1835  if( ( (fDPhi <= pi) && ( (pDistS <= halfCarTolerance)
1836  && (pDistE <= halfCarTolerance) ) )
1837  || ( (fDPhi > pi) && !((pDistS > halfCarTolerance)
1838  && (pDistE > halfCarTolerance) ) ) )
1839  {
1840  // Inside both phi *full* planes
1841  if ( compS < 0 )
1842  {
1843  sphi = pDistS/compS ;
1844  if (sphi >= -halfCarTolerance)
1845  {
1846  xi = p.x() + sphi*v.x() ;
1847  yi = p.y() + sphi*v.y() ;
1848 
1849  // Check intersecting with correct half-plane
1850  // (if not -> no intersect)
1851  //
1852  if ( (std::fabs(xi)<=kCarTolerance)
1853  && (std::fabs(yi)<=kCarTolerance) )
1854  {
1855  sidephi= kSPhi;
1856  if ( ( fSPhi-halfAngTolerance <= vphi )
1857  && ( fSPhi+fDPhi+halfAngTolerance >=vphi ) )
1858  {
1859  sphi = kInfinity;
1860  }
1861  }
1862  else
1863  if ( (yi*cosCPhi-xi*sinCPhi)>=0 )
1864  {
1865  sphi = kInfinity ;
1866  }
1867  else
1868  {
1869  sidephi = kSPhi ;
1870  if ( pDistS > -halfCarTolerance )
1871  {
1872  sphi = 0.0 ; // Leave by sphi immediately
1873  }
1874  }
1875  }
1876  else
1877  {
1878  sphi = kInfinity ;
1879  }
1880  }
1881  else
1882  {
1883  sphi = kInfinity ;
1884  }
1885 
1886  if ( compE < 0 )
1887  {
1888  sphi2 = pDistE/compE ;
1889 
1890  // Only check further if < starting phi intersection
1891  //
1892  if ( (sphi2 > -halfCarTolerance) && (sphi2 < sphi) )
1893  {
1894  xi = p.x() + sphi2*v.x() ;
1895  yi = p.y() + sphi2*v.y() ;
1896 
1897  // Check intersecting with correct half-plane
1898 
1899  if ( (std::fabs(xi)<=kCarTolerance)
1900  && (std::fabs(yi)<=kCarTolerance) )
1901  {
1902  // Leaving via ending phi
1903 
1904  if(!( (fSPhi-halfAngTolerance <= vphi)
1905  && (fSPhi+fDPhi+halfAngTolerance >= vphi) ) )
1906  {
1907  sidephi = kEPhi ;
1908  if ( pDistE <= -halfCarTolerance ) { sphi = sphi2; }
1909  else { sphi = 0.0; }
1910  }
1911  }
1912  else // Check intersecting with correct half-plane
1913  if ( yi*cosCPhi-xi*sinCPhi >= 0 )
1914  {
1915  // Leaving via ending phi
1916 
1917  sidephi = kEPhi ;
1918  if ( pDistE <= -halfCarTolerance ) { sphi = sphi2; }
1919  else { sphi = 0.0; }
1920  }
1921  }
1922  }
1923  }
1924  else
1925  {
1926  sphi = kInfinity ;
1927  }
1928  }
1929  else
1930  {
1931  // On z axis + travel not || to z axis -> if phi of vector direction
1932  // within phi of shape, Step limited by rmax, else Step =0
1933 
1934  if ( (fSPhi-halfAngTolerance <= vphi)
1935  && (vphi <= fSPhi+fDPhi+halfAngTolerance) )
1936  {
1937  sphi = kInfinity ;
1938  }
1939  else
1940  {
1941  sidephi = kSPhi ; // arbitrary
1942  sphi = 0.0 ;
1943  }
1944  }
1945  if ( sphi < snxt ) // Order intersecttions
1946  {
1947  snxt=sphi ;
1948  side=sidephi ;
1949  }
1950  }
1951 */
1952  if ( srd < snxt ) // Order intersections
1953  {
1954  snxt = srd ;
1955  side = sider ;
1956  }
1957  if (calcNorm)
1958  {
1959  switch(side)
1960  { // Note: returned vector not normalised
1961  case kRMax: // (divide by frmax for unit vector)
1962  xi = p.x() + snxt*v.x() ;
1963  yi = p.y() + snxt*v.y() ;
1964  risec = std::sqrt(xi*xi + yi*yi)*secRMax ;
1965  *n = G4ThreeVector(xi/risec,yi/risec,-tanRMax/secRMax) ;
1966  *validNorm = true ;
1967  break ;
1968  case kRMin:
1969  *validNorm = false ; // Rmin is inconvex
1970  break ;
1971 /* case kSPhi:
1972  if ( fDPhi <= pi )
1973  {
1974  *n = G4ThreeVector(sinSPhi, -cosSPhi, 0);
1975  *validNorm = true ;
1976  }
1977  else
1978  {
1979  *validNorm = false ;
1980  }
1981  break ;
1982  case kEPhi:
1983  if ( fDPhi <= pi )
1984  {
1985  *n = G4ThreeVector(-sinEPhi, cosEPhi, 0);
1986  *validNorm = true ;
1987  }
1988  else
1989  {
1990  *validNorm = false ;
1991  }
1992  break ;*/
1993  case kPZ:
1994  *n = G4ThreeVector(0,0,1) ;
1995  *validNorm = true ;
1996  break ;
1997  case kMZ:
1998  *n = G4ThreeVector(0,0,-1) ;
1999  *validNorm = true ;
2000  break ;
2001  default:
2002  G4cout << G4endl ;
2003  DumpInfo();
2004  std::ostringstream message;
2005  G4int oldprc = message.precision(16) ;
2006  message << "Undefined side for valid surface normal to solid."
2007  << G4endl
2008  << "Position:" << G4endl << G4endl
2009  << "p.x() = " << p.x()/mm << " mm" << G4endl
2010  << "p.y() = " << p.y()/mm << " mm" << G4endl
2011  << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl
2012  << "pho at z = " << std::sqrt( p.x()*p.x()+p.y()*p.y() )/mm
2013  << " mm" << G4endl << G4endl ;
2014  if( p.x() != 0. || p.y() != 0.)
2015  {
2016  message << "point phi = " << std::atan2(p.y(),p.x())/degree
2017  << " degree" << G4endl << G4endl ;
2018  }
2019  message << "Direction:" << G4endl << G4endl
2020  << "v.x() = " << v.x() << G4endl
2021  << "v.y() = " << v.y() << G4endl
2022  << "v.z() = " << v.z() << G4endl<< G4endl
2023  << "Proposed distance :" << G4endl<< G4endl
2024  << "snxt = " << snxt/mm << " mm" << G4endl ;
2025  message.precision(oldprc) ;
2026  G4Exception("G4ShiftedCone::DistanceToOut(p,v,..)","GeomSolids1002",
2027  JustWarning, message) ;
2028  break ;
2029  }
2030  }
2031  if (snxt < halfCarTolerance) { snxt = 0.; }
2032 
2033  return snxt ;
2034 }
2035 
2037 //
2038 // Calculate distance (<=actual) to closest surface of shape from inside
2039 
2040 G4double G4ShiftedCone::DistanceToOut(const G4ThreeVector& p) const
2041 {
2042  G4double safe=0.0, rho, safeR1, safeR2, safeZ;//, safePhi;
2043  G4double tanRMin, secRMin, pRMin;
2044  G4double tanRMax, secRMax, pRMax;
2045 
2046 #ifdef G4CSGDEBUG
2047  if( Inside(p) == kOutside )
2048  {
2049  G4int oldprc=G4cout.precision(16) ;
2050  G4cout << G4endl ;
2051  DumpInfo();
2052  G4cout << "Position:" << G4endl << G4endl ;
2053  G4cout << "p.x() = " << p.x()/mm << " mm" << G4endl ;
2054  G4cout << "p.y() = " << p.y()/mm << " mm" << G4endl ;
2055  G4cout << "p.z() = " << p.z()/mm << " mm" << G4endl << G4endl ;
2056  G4cout << "pho at z = " << std::sqrt( p.x()*p.x()+p.y()*p.y() )/mm
2057  << " mm" << G4endl << G4endl ;
2058  if( (p.x() != 0.) || (p.x() != 0.) )
2059  {
2060  G4cout << "point phi = " << std::atan2(p.y(),p.x())/degree
2061  << " degree" << G4endl << G4endl ;
2062  }
2063  G4cout.precision(oldprc) ;
2064  G4Exception("G4ShiftedCone::DistanceToOut(p)", "GeomSolids1002",
2065  JustWarning, "Point p is outside !?" );
2066  }
2067 #endif
2068 
2069  G4double z = p.z() - fZshift;
2070 
2071  rho = std::sqrt(p.x()*p.x() + p.y()*p.y()) ;
2072  safeZ = fDz - std::fabs(z) ;
2073 
2074  if (fRmin1 || fRmin2)
2075  {
2076  tanRMin = (fRmin2 - fRmin1)*0.5/fDz ;
2077  secRMin = std::sqrt(1.0 + tanRMin*tanRMin) ;
2078  pRMin = tanRMin*z + (fRmin1 + fRmin2)*0.5 ;
2079  safeR1 = (rho - pRMin)/secRMin ;
2080  }
2081  else
2082  {
2083  safeR1 = kInfinity ;
2084  }
2085 
2086  tanRMax = (fRmax2 - fRmax1)*0.5/fDz ;
2087  secRMax = std::sqrt(1.0 + tanRMax*tanRMax) ;
2088  pRMax = tanRMax*z + (fRmax1+fRmax2)*0.5 ;
2089  safeR2 = (pRMax - rho)/secRMax ;
2090 
2091  if (safeR1 < safeR2) { safe = safeR1; }
2092  else { safe = safeR2; }
2093  if (safeZ < safe) { safe = safeZ ; }
2094 
2095  // Check if phi divided, Calc distances closest phi plane
2096 /*
2097  if (!fPhiFullCone)
2098  {
2099  // Above/below central phi of G4ShiftedCone?
2100 
2101  if ( (p.y()*cosCPhi - p.x()*sinCPhi) <= 0 )
2102  {
2103  safePhi = -(p.x()*sinSPhi - p.y()*cosSPhi) ;
2104  }
2105  else
2106  {
2107  safePhi = (p.x()*sinEPhi - p.y()*cosEPhi) ;
2108  }
2109  if (safePhi < safe) { safe = safePhi; }
2110  }*/
2111  if ( safe < 0 ) { safe = 0; }
2112 
2113  return safe ;
2114 }
2115 
2117 //
2118 // GetEntityType
2119 
2120 G4GeometryType G4ShiftedCone::GetEntityType() const
2121 {
2122  return G4String("G4ShiftedCone");
2123 }
2124 
2126 //
2127 // Make a clone of the object
2128 //
2129 G4VSolid* G4ShiftedCone::Clone() const
2130 {
2131  return new G4ShiftedCone(*this);
2132 }
2133 
2135 //
2136 // Stream object contents to an output stream
2137 
2138 std::ostream& G4ShiftedCone::StreamInfo(std::ostream& os) const
2139 {
2140  G4int oldprc = os.precision(16);
2141  os << "-----------------------------------------------------------\n"
2142  << " *** Dump for solid - " << GetName() << " ***\n"
2143  << " ===================================================\n"
2144  << " Solid type: G4ShiftedCone\n"
2145  << " Parameters: \n"
2146  << " inside -fDz radius: " << fRmin1/mm << " mm \n"
2147  << " outside -fDz radius: " << fRmax1/mm << " mm \n"
2148  << " inside +fDz radius: " << fRmin2/mm << " mm \n"
2149  << " outside +fDz radius: " << fRmax2/mm << " mm \n"
2150  << " Z1 : " << GetZ1()/mm << " mm \n"
2151  << " Z2 : " << GetZ2()/mm << " mm \n"
2152 // << " starting angle of segment: " << fSPhi/degree << " degrees \n"
2153 // << " delta angle of segment : " << fDPhi/degree << " degrees \n"
2154  << "-----------------------------------------------------------\n";
2155  os.precision(oldprc);
2156 
2157  return os;
2158 }
2159 
2160 
2161 
2163 //
2164 // GetPointOnSurface
2165 
2167 {
2168  // declare working variables
2169  //
2170  G4double rone = (fRmax1-fRmax2)/(2.*fDz);
2171  G4double rtwo = (fRmin1-fRmin2)/(2.*fDz);
2172  G4double qone = (fRmax1 == fRmax2) ? 0. : fDz*(fRmax1+fRmax2)/(fRmax1-fRmax2);
2173  G4double qtwo = (fRmin1 == fRmin2) ? 0. : fDz*(fRmin1+fRmin2)/(fRmin1-fRmin2);
2174 
2175  G4double slin = std::hypot(fRmin1-fRmin2, 2.*fDz);
2176  G4double slout = std::hypot(fRmax1-fRmax2, 2.*fDz);
2177  G4double Aone = 0.5*GetDeltaPhiAngle()*(fRmax2 + fRmax1)*slout; // outer surface
2178  G4double Atwo = 0.5*GetDeltaPhiAngle()*(fRmin2 + fRmin1)*slin; // inner surface
2179  G4double Athree = 0.5*GetDeltaPhiAngle()*(fRmax1*fRmax1-fRmin1*fRmin1); // base at -Dz
2180  G4double Afour = 0.5*GetDeltaPhiAngle()*(fRmax2*fRmax2-fRmin2*fRmin2); // base at +Dz
2181  G4double Afive = fDz*(fRmax1-fRmin1+fRmax2-fRmin2); // phi section
2182 
2183  G4double phi = G4RandFlat::shoot(GetStartPhiAngle(),GetStartPhiAngle() + GetDeltaPhiAngle());
2184  G4double cosu = std::cos(phi);
2185  G4double sinu = std::sin(phi);
2186  G4double rRand1 = GetRadiusInRing(fRmin1, fRmax1);
2187  G4double rRand2 = GetRadiusInRing(fRmin2, fRmax2);
2188 
2189  G4bool fPhiFullCone = true;
2190  if ( (GetStartPhiAngle() == 0.) && fPhiFullCone ) { Afive = 0.; }
2191  G4double chose = G4RandFlat::shoot(0.,Aone+Atwo+Athree+Afour+2.*Afive);
2192 
2193  if( (chose >= 0.) && (chose < Aone) ) // outer surface
2194  {
2195  if(fRmax1 != fRmax2)
2196  {
2197  G4double zRand = G4RandFlat::shoot(-1.*fDz,fDz);
2198  return G4ThreeVector (rone*cosu*(qone-zRand),
2199  rone*sinu*(qone-zRand), zRand + fZshift);
2200  }
2201  else
2202  {
2203  return G4ThreeVector(fRmax1*cosu, fRmax2*sinu,
2204  G4RandFlat::shoot(-1.*fDz,fDz) + fZshift);
2205  }
2206  }
2207  else if( (chose >= Aone) && (chose < Aone + Atwo) ) // inner surface
2208  {
2209  if(fRmin1 != fRmin2)
2210  {
2211  G4double zRand = G4RandFlat::shoot(-1.*fDz,fDz);
2212  return G4ThreeVector (rtwo*cosu*(qtwo-zRand),
2213  rtwo*sinu*(qtwo-zRand), zRand + fZshift);
2214  }
2215  else
2216  {
2217  return G4ThreeVector(fRmin1*cosu, fRmin2*sinu,
2218  G4RandFlat::shoot(-1.*fDz,fDz) + fZshift);
2219  }
2220  }
2221  else if( (chose >= Aone + Atwo) && (chose < Aone + Atwo + Athree) ) // base at -Dz
2222  {
2223  return G4ThreeVector (rRand1*cosu, rRand1*sinu, -1*fDz + fZshift);
2224  }
2225  else if( (chose >= Aone + Atwo + Athree)
2226  && (chose < Aone + Atwo + Athree + Afour) ) // base at +Dz
2227  {
2228  return G4ThreeVector (rRand2*cosu,rRand2*sinu,fDz + fZshift);
2229  }
2230  else if( (chose >= Aone + Atwo + Athree + Afour) // SPhi section
2231  && (chose < Aone + Atwo + Athree + Afour + Afive) )
2232  {
2233  G4double zRand = G4RandFlat::shoot(-1.*fDz,fDz);
2234  rRand1 = G4RandFlat::shoot(fRmin2-((zRand-fDz)/(2.*fDz))*(fRmin1-fRmin2),
2235  fRmax2-((zRand-fDz)/(2.*fDz))*(fRmax1-fRmax2));
2236  return G4ThreeVector (rRand1*GetCosStartPhi(),
2237  rRand1*GetSinStartPhi(), zRand + fZshift);
2238  }
2239  else // SPhi+DPhi section
2240  {
2241  G4double zRand = G4RandFlat::shoot(-1.*fDz,fDz);
2242  rRand1 = G4RandFlat::shoot(fRmin2-((zRand-fDz)/(2.*fDz))*(fRmin1-fRmin2),
2243  fRmax2-((zRand-fDz)/(2.*fDz))*(fRmax1-fRmax2));
2244  return G4ThreeVector (rRand1*GetCosEndPhi(),
2245  rRand1*GetSinEndPhi(), zRand + fZshift);
2246  }
2247 }
2248 
2250 //
2251 // Methods for visualisation
2252 
2253 void G4ShiftedCone::DescribeYourselfTo (G4VGraphicsScene& scene) const
2254 {
2255  scene.AddSolid (*this);
2256 }
2257 
2258 G4Polyhedron* G4ShiftedCone::CreatePolyhedron () const
2259 {
2260  G4double rmin[2] = { GetRmin1(), GetRmin2() };
2261  G4double rmax[2] = { GetRmax1(), GetRmax2() };
2262  G4double z[2] = { GetZ1(), GetZ2() };
2263  return new G4PolyhedronPcon(
2264  GetStartPhiAngle(), GetDeltaPhiAngle(), 2, z, rmin, rmax
2265  );
2266 }
kRMax
@ kRMax
Definition: G4ShiftedCone.cxx:70
G4ShiftedCone::fDz
G4double fDz
Definition: G4ShiftedCone.h:227
G4ShiftedCone::DescribeYourselfTo
void DescribeYourselfTo(G4VGraphicsScene &scene) const
Definition: G4ShiftedCone.cxx:2253
G4ShiftedCone::fZshift
G4double fZshift
Definition: G4ShiftedCone.h:227
G4ShiftedCone::~G4ShiftedCone
~G4ShiftedCone()
Definition: G4ShiftedCone.cxx:148
PlotCalibFromCool.norm
norm
Definition: PlotCalibFromCool.py:100
kNRMax
@ kNRMax
Definition: G4ShiftedCone.cxx:74
G4ShiftedCone::GetRmin1
G4double GetRmin1() const
G4ShiftedCone::GetCosStartPhi
G4double GetCosStartPhi() const
G4ShiftedCone::Clone
G4VSolid * Clone() const
Definition: G4ShiftedCone.cxx:2129
python.PerfMonSerializer.p
def p
Definition: PerfMonSerializer.py:743
max
#define max(a, b)
Definition: cfImp.cxx:41
phi
Scalar phi() const
phi method
Definition: AmgMatrixBasePlugin.h:64
G4ShiftedCone::operator=
G4ShiftedCone & operator=(const G4ShiftedCone &rhs)
Definition: G4ShiftedCone.cxx:175
G4ShiftedCone::kNRMax
@ kNRMax
Definition: G4ShiftedCone.h:220
G4ShiftedCone::GetInnerRadiusPlusZ
G4double GetInnerRadiusPlusZ() const
G4ShiftedCone::DistanceToOut
G4double DistanceToOut(const G4ThreeVector &p, const G4ThreeVector &v, const G4bool calcNorm=G4bool(false), G4bool *validNorm=0, G4ThreeVector *n=0) const
Definition: G4ShiftedCone.cxx:1414
kNSPhi
@ kNSPhi
Definition: G4ShiftedCone.cxx:74
hist_file_dump.d
d
Definition: hist_file_dump.py:137
LUCID_EventTPCnv_Dict::t3
std::vector< LUCID_RawData_p1 > t3
Definition: LUCID_EventTPCnvDict.h:28
kSPhi
@ kSPhi
Definition: G4ShiftedCone.cxx:70
G4ShiftedCone::GetRmax2
G4double GetRmax2() const
ALFA_EventTPCnv_Dict::t1
std::vector< ALFA_RawDataCollection_p1 > t1
Definition: ALFA_EventTPCnvDict.h:43
G4ShiftedCone::GetEntityType
G4GeometryType GetEntityType() const
Definition: G4ShiftedCone.cxx:2120
deg
#define deg
Definition: SbPolyhedron.cxx:17
G4ShiftedCone::GetZ1
G4double GetZ1() const
G4ShiftedCone::kMZ
@ kMZ
Definition: G4ShiftedCone.h:216
ORAlgo::Normal
@ Normal
G4ShiftedCone::Inside
EInside Inside(const G4ThreeVector &p) const
Definition: G4ShiftedCone.cxx:209
G4ShiftedCone::CalculateExtent
G4bool CalculateExtent(const EAxis pAxis, const G4VoxelLimits &pVoxelLimit, const G4AffineTransform &pTransform, G4double &pMin, G4double &pMax) const
Definition: G4ShiftedCone.cxx:325
kRMin
@ kRMin
Definition: G4ShiftedCone.cxx:70
G4ShiftedCone::SurfaceNormal
G4ThreeVector SurfaceNormal(const G4ThreeVector &p) const
Definition: G4ShiftedCone.cxx:442
drawFromPickle.cos
cos
Definition: drawFromPickle.py:36
G4ShiftedCone::CreatePolyhedron
G4Polyhedron * CreatePolyhedron() const
Definition: G4ShiftedCone.cxx:2258
G4ShiftedCone::GetInnerRadiusMinusZ
G4double GetInnerRadiusMinusZ() const
G4ShiftedCone
Definition: G4ShiftedCone.h:87
G4ShiftedCone::GetSinEndPhi
G4double GetSinEndPhi() const
ReweightUtils.message
message
Definition: ReweightUtils.py:15
G4ShiftedCone::StreamInfo
std::ostream & StreamInfo(std::ostream &os) const
Definition: G4ShiftedCone.cxx:2138
G4ShiftedCone::ESide
ESide
Definition: G4ShiftedCone.h:216
G4ShiftedCone::halfCarTolerance
G4double halfCarTolerance
Definition: G4ShiftedCone.h:240
G4ShiftedCone::GetRmax1
G4double GetRmax1() const
G4ShiftedCone::kRMin
@ kRMin
Definition: G4ShiftedCone.h:216
TRT::Hit::side
@ side
Definition: HitInfo.h:83
python.selector.AtlRunQuerySelectorLhcOlc.sd
sd
Definition: AtlRunQuerySelectorLhcOlc.py:612
xAOD::TauJetParameters::dRmax
@ dRmax
Get maximal dR of tracks associated to calo-seeded tau.
Definition: TauDefs.h:226
G4ShiftedCone::DistanceToIn
G4double DistanceToIn(const G4ThreeVector &p, const G4ThreeVector &v) const
Definition: G4ShiftedCone.cxx:677
G4ShiftedCone::ComputeDimensions
void ComputeDimensions(G4VPVParameterisation *p, const G4int n, const G4VPhysicalVolume *pRep)
Definition: G4ShiftedCone.cxx:267
WriteCellNoiseToCool.exist
exist
Definition: WriteCellNoiseToCool.py:543
CheckAppliedSFs.e3
e3
Definition: CheckAppliedSFs.py:264
G4ShiftedCone::GetOuterRadiusMinusZ
G4double GetOuterRadiusMinusZ() const
G4ShiftedCone::GetSinStartPhi
G4double GetSinStartPhi() const
G4ShiftedCone::halfAngTolerance
G4double halfAngTolerance
Definition: G4ShiftedCone.h:240
z
#define z
G4ShiftedCone::fRmax1
G4double fRmax1
Definition: G4ShiftedCone.h:226
ENorm
ENorm
Definition: G4ShiftedCone.cxx:74
CheckAppliedSFs.bmin
bmin
Definition: CheckAppliedSFs.py:242
beamspotman.n
n
Definition: beamspotman.py:731
G4ShiftedCone::GetCosEndPhi
G4double GetCosEndPhi() const
CLHEP
STD'S.
Definition: IAtRndmGenSvc.h:19
G4ShiftedCone::fRmin2
G4double fRmin2
Definition: G4ShiftedCone.h:226
G4ShiftedCone::fRmin1
G4double fRmin1
Definition: G4ShiftedCone.h:226
kNRMin
@ kNRMin
Definition: G4ShiftedCone.cxx:74
G4ShiftedCone::G4ShiftedCone
G4ShiftedCone(const G4String &pName, G4double pZ1, G4double pZ2, G4double pRmin1, G4double pRmax1, G4double pRmin2, G4double pRmax2)
Definition: G4ShiftedCone.cxx:81
ReadFromCoolCompare.os
os
Definition: ReadFromCoolCompare.py:231
G4ShiftedCone.h
twopi
constexpr double twopi
Definition: VertexPointEstimator.cxx:16
CheckAppliedSFs.bmax
bmax
Definition: CheckAppliedSFs.py:264
G4ShiftedCone::BoundingLimits
void BoundingLimits(G4ThreeVector &pMin, G4ThreeVector &pMax) const
Definition: G4ShiftedCone.cxx:282
G4ShiftedCone::kRadTolerance
G4double kRadTolerance
Definition: G4ShiftedCone.h:222
plotBeamSpotMon.b
b
Definition: plotBeamSpotMon.py:77
G4ShiftedCone::GetZ2
G4double GetZ2() const
kEPhi
@ kEPhi
Definition: G4ShiftedCone.cxx:70
G4ShiftedCone::kNRMin
@ kNRMin
Definition: G4ShiftedCone.h:220
G4ShiftedCone::ApproxSurfaceNormal
G4ThreeVector ApproxSurfaceNormal(const G4ThreeVector &p) const
Definition: G4ShiftedCone.cxx:548
G4ShiftedCone::kNull
@ kNull
Definition: G4ShiftedCone.h:216
kMZ
@ kMZ
Definition: G4ShiftedCone.cxx:70
PlotCalibFromCool.rl
rl
Definition: PlotCalibFromCool.py:529
G4ShiftedCone::GetRmin2
G4double GetRmin2() const
python.SystemOfUnits.mm
int mm
Definition: SystemOfUnits.py:83
G4ShiftedCone::GetPointOnSurface
G4ThreeVector GetPointOnSurface() const
Definition: G4ShiftedCone.cxx:2166
python.PyAthena.v
v
Definition: PyAthena.py:157
G4ShiftedCone::kPZ
@ kPZ
Definition: G4ShiftedCone.h:216
ALFA_EventTPCnv_Dict::t2
std::vector< ALFA_RawDataContainer_p1 > t2
Definition: ALFA_EventTPCnvDict.h:44
a
TList * a
Definition: liststreamerinfos.cxx:10
G4ShiftedCone::ENorm
ENorm
Definition: G4ShiftedCone.h:220
G4ShiftedCone::kRMax
@ kRMax
Definition: G4ShiftedCone.h:216
kNZ
@ kNZ
Definition: G4ShiftedCone.cxx:74
G4ShiftedCone::kAngTolerance
G4double kAngTolerance
Definition: G4ShiftedCone.h:222
G4ShiftedCone::kNZ
@ kNZ
Definition: G4ShiftedCone.h:220
ESide
ESide
Definition: G4ShiftedCone.cxx:70
kNEPhi
@ kNEPhi
Definition: G4ShiftedCone.cxx:74
kNull
@ kNull
Definition: G4ShiftedCone.cxx:70
G4ShiftedCone::GetDeltaPhiAngle
G4double GetDeltaPhiAngle() const
G4ShiftedCone::GetStartPhiAngle
G4double GetStartPhiAngle() const
drawFromPickle.sin
sin
Definition: drawFromPickle.py:36
kPZ
@ kPZ
Definition: G4ShiftedCone.cxx:70
G4ShiftedCone::fRmax2
G4double fRmax2
Definition: G4ShiftedCone.h:226
python.compressB64.c
def c
Definition: compressB64.py:93
python.SystemOfUnits.degree
tuple degree
Definition: SystemOfUnits.py:106
G4ShiftedCone::halfRadTolerance
G4double halfRadTolerance
Definition: G4ShiftedCone.h:240
fitman.rho
rho
Definition: fitman.py:532
fitman.k
k
Definition: fitman.py:528
G4ShiftedCone::GetOuterRadiusPlusZ
G4double GetOuterRadiusPlusZ() const