Geant4  10.01.p02
UTubs.cc
Go to the documentation of this file.
1 //
2 // ********************************************************************
3 // * This Software is part of the AIDA Unified Solids Library package *
4 // * See: https://aidasoft.web.cern.ch/USolids *
5 // ********************************************************************
6 //
7 // $Id:$
8 //
9 // --------------------------------------------------------------------
10 //
11 // UTubs
12 //
13 // 19.10.12 Marek Gayer
14 // Created from original implementation in Geant4
15 // --------------------------------------------------------------------
16 
17 #include "UUtils.hh"
18 #include <string>
19 #include <cmath>
20 #include <sstream>
21 #include "UTubs.hh"
22 
23 using namespace std;
24 
26 //
27 // Constructor - check parameters, convert angles so 0<sphi+dpshi<=2_PI
28 // - note if pdphi>2PI then reset to 2PI
29 
30 UTubs::UTubs(const std::string& pName,
31  double pRMin, double pRMax,
32  double pDz,
33  double pSPhi, double pDPhi)
34  : VUSolid(pName.c_str()), fRMin(pRMin), fRMax(pRMax), fDz(pDz), fSPhi(0), fDPhi(0)
35 {
36  fCubicVolume=0.;
37  fSurfaceArea=0.;
40 
41  if (pDz <= 0) // Check z-len
42  {
43  std::ostringstream message;
44  message << "Negative Z half-length (" << pDz << ") in solid: " << GetName();
45  UUtils::Exception("UTubs::UTubs()", "GeomSolids0002",
46  UFatalErrorInArguments, 1, message.str().c_str());
47  }
48  if ((pRMin >= pRMax) || (pRMin < 0)) // Check radii
49  {
50  std::ostringstream message;
51  message << "Invalid values for radii in solid: " << GetName()
52  << std::endl
53  << "pRMin = " << pRMin << ", pRMax = " << pRMax;
54  UUtils::Exception("UTubs::UTubs()", "GeomSolids0002",
55  UFatalErrorInArguments, 1, message.str().c_str());
56  }
57 
58  // Check angles
59  //
60  CheckPhiAngles(pSPhi, pDPhi);
61 }
62 
64 //
65 // Fake default constructor - sets only member data and allocates memory
66 // for usage restricted to object persistency.
67 //
69  : VUSolid(""), fCubicVolume(0.), fSurfaceArea(0.),
70  kRadTolerance(0.), kAngTolerance(0.),
71  fRMin(0.), fRMax(0.), fDz(0.), fSPhi(0.), fDPhi(0.),
72  fSinCPhi(0.), fCosCPhi(0.), fCosHDPhiOT(0.), fCosHDPhiIT(0.),
73  fSinSPhi(0.), fCosSPhi(0.), fSinEPhi(0.), fCosEPhi(0.),
74  fSinSPhiDPhi(0.), fCosSPhiDPhi(0.),
75  fPhiFullTube(false)
76 {
77 }
78 
80 //
81 // Destructor
82 
84 {
85 }
86 
88 //
89 // Copy constructor
90 
91 UTubs::UTubs(const UTubs& rhs)
92  : VUSolid(rhs),
93  fCubicVolume(rhs.fCubicVolume), fSurfaceArea(rhs.fSurfaceArea),
94  kRadTolerance(rhs.kRadTolerance), kAngTolerance(rhs.kAngTolerance),
95  fRMin(rhs.fRMin), fRMax(rhs.fRMax), fDz(rhs.fDz),
96  fSPhi(rhs.fSPhi), fDPhi(rhs.fDPhi),
97  fSinCPhi(rhs.fSinCPhi), fCosCPhi(rhs.fCosCPhi),
98  fCosHDPhiOT(rhs.fCosHDPhiOT), fCosHDPhiIT(rhs.fCosHDPhiIT),
99  fSinSPhi(rhs.fSinSPhi), fCosSPhi(rhs.fCosSPhi),
100  fSinEPhi(rhs.fSinEPhi), fCosEPhi(rhs.fCosEPhi),
101  fSinSPhiDPhi(rhs.fSinSPhiDPhi), fCosSPhiDPhi(rhs.fCosSPhiDPhi),
102  fPhiFullTube(rhs.fPhiFullTube)
103 {
104 }
105 
107 //
108 // Assignment operator
109 
111 {
112  // Check assignment to self
113  //
114  if (this == &rhs)
115  {
116  return *this;
117  }
118 
119  // Copy base class data
120  //
121  VUSolid::operator=(rhs);
122 
123  // Copy data
124  //
129  fRMin = rhs.fRMin;
130  fRMax = rhs.fRMax;
131  fDz = rhs.fDz;
132  fSPhi = rhs.fSPhi;
133  fDPhi = rhs.fDPhi;
134  fSinCPhi = rhs.fSinCPhi;
135  fCosCPhi = rhs.fCosCPhi;
136  fCosHDPhiOT = rhs.fCosHDPhiOT;
137  fCosHDPhiIT = rhs.fCosHDPhiIT;
138  fSinSPhi = rhs.fSinSPhi;
139  fCosSPhi = rhs.fCosSPhi;
140  fSinEPhi = rhs.fSinEPhi;
141  fCosEPhi = rhs.fCosEPhi;
144 
146 
147  return *this;
148 }
149 
150 
152 //
153 // Return whether point inside/outside/on surface
154 
156 {
157  double r2, pPhi, tolRMin, tolRMax;
159  static const double halfCarTolerance = VUSolid::Tolerance() * 0.5;
160  static const double halfRadTolerance = kRadTolerance * 0.5;
161  static const double halfAngTolerance = kAngTolerance * 0.5;
162 
163  if (std::fabs(p.z()) <= fDz - halfCarTolerance)
164  {
165  r2 = p.x() * p.x() + p.y() * p.y();
166 
167  if (fRMin)
168  {
169  tolRMin = fRMin + halfRadTolerance;
170  }
171  else
172  {
173  tolRMin = 0;
174  }
175 
176  tolRMax = fRMax - halfRadTolerance;
177 
178  if ((r2 >= tolRMin * tolRMin) && (r2 <= tolRMax * tolRMax))
179  {
180  if (fPhiFullTube)
181  {
182  in = eInside;
183  }
184  else
185  {
186  // Try inner tolerant phi boundaries (=>inside)
187  // if not inside, try outer tolerant phi boundaries
188 
189  if ((tolRMin == 0) && (std::fabs(p.x()) <= halfCarTolerance)
190  && (std::fabs(p.y()) <= halfCarTolerance))
191  {
192  in = eSurface;
193  }
194  else
195  {
196  pPhi = std::atan2(p.y(), p.x());
197  if (pPhi < -halfAngTolerance)
198  {
199  pPhi += 2 * UUtils::kPi; // 0<=pPhi<2UUtils::kPi
200  }
201 
202  if (fSPhi >= 0)
203  {
204  if ((std::fabs(pPhi) < halfAngTolerance)
205  && (std::fabs(fSPhi + fDPhi - 2 * UUtils::kPi) < halfAngTolerance))
206  {
207  pPhi += 2 * UUtils::kPi; // 0 <= pPhi < 2UUtils::kPi
208  }
209  if ((pPhi >= fSPhi + halfAngTolerance)
210  && (pPhi <= fSPhi + fDPhi - halfAngTolerance))
211  {
212  in = eInside;
213  }
214  else if ((pPhi >= fSPhi - halfAngTolerance)
215  && (pPhi <= fSPhi + fDPhi + halfAngTolerance))
216  {
217  in = eSurface;
218  }
219  }
220  else // fSPhi < 0
221  {
222  if ((pPhi <= fSPhi + 2 * UUtils::kPi - halfAngTolerance)
223  && (pPhi >= fSPhi + fDPhi + halfAngTolerance))
224  {
225  ; //eOutside
226  }
227  else if ((pPhi <= fSPhi + 2 * UUtils::kPi + halfAngTolerance)
228  && (pPhi >= fSPhi + fDPhi - halfAngTolerance))
229  {
230  in = eSurface;
231  }
232  else
233  {
234  in = eInside;
235  }
236  }
237  }
238  }
239  }
240  else // Try generous boundaries
241  {
242  tolRMin = fRMin - halfRadTolerance;
243  tolRMax = fRMax + halfRadTolerance;
244 
245  if (tolRMin < 0)
246  {
247  tolRMin = 0;
248  }
249 
250  if ((r2 >= tolRMin * tolRMin) && (r2 <= tolRMax * tolRMax))
251  {
252  if (fPhiFullTube || (r2 <= halfRadTolerance * halfRadTolerance))
253  {
254  // Continuous in phi or on z-axis
255  in = eSurface;
256  }
257  else // Try outer tolerant phi boundaries only
258  {
259  pPhi = std::atan2(p.y(), p.x());
260 
261  if (pPhi < -halfAngTolerance)
262  {
263  pPhi += 2 * UUtils::kPi; // 0<=pPhi<2UUtils::kPi
264  }
265  if (fSPhi >= 0)
266  {
267  if ((std::fabs(pPhi) < halfAngTolerance)
268  && (std::fabs(fSPhi + fDPhi - 2 * UUtils::kPi) < halfAngTolerance))
269  {
270  pPhi += 2 * UUtils::kPi; // 0 <= pPhi < 2UUtils::kPi
271  }
272  if ((pPhi >= fSPhi - halfAngTolerance)
273  && (pPhi <= fSPhi + fDPhi + halfAngTolerance))
274  {
275  in = eSurface;
276  }
277  }
278  else // fSPhi < 0
279  {
280  if ((pPhi <= fSPhi + 2 * UUtils::kPi - halfAngTolerance)
281  && (pPhi >= fSPhi + fDPhi + halfAngTolerance))
282  {
283  ; // eOutside
284  }
285  else
286  {
287  in = eSurface;
288  }
289  }
290  }
291  }
292  }
293  }
294  else if (std::fabs(p.z()) <= fDz + halfCarTolerance)
295  {
296  // Check within tolerant r limits
297  r2 = p.x() * p.x() + p.y() * p.y();
298  tolRMin = fRMin - halfRadTolerance;
299  tolRMax = fRMax + halfRadTolerance;
300 
301  if (tolRMin < 0)
302  {
303  tolRMin = 0;
304  }
305 
306  if ((r2 >= tolRMin * tolRMin) && (r2 <= tolRMax * tolRMax))
307  {
308  if (fPhiFullTube || (r2 <= halfRadTolerance * halfRadTolerance))
309  {
310  // Continuous in phi or on z-axis
311  in = eSurface;
312  }
313  else // Try outer tolerant phi boundaries
314  {
315  pPhi = std::atan2(p.y(), p.x());
316 
317  if (pPhi < -halfAngTolerance)
318  {
319  pPhi += 2 * UUtils::kPi; // 0<=pPhi<2UUtils::kPi
320  }
321  if (fSPhi >= 0)
322  {
323  if ((std::fabs(pPhi) < halfAngTolerance)
324  && (std::fabs(fSPhi + fDPhi - 2 * UUtils::kPi) < halfAngTolerance))
325  {
326  pPhi += 2 * UUtils::kPi; // 0 <= pPhi < 2UUtils::kPi
327  }
328  if ((pPhi >= fSPhi - halfAngTolerance)
329  && (pPhi <= fSPhi + fDPhi + halfAngTolerance))
330  {
331  in = eSurface;
332  }
333  }
334  else // fSPhi < 0
335  {
336  if ((pPhi <= fSPhi + 2 * UUtils::kPi - halfAngTolerance)
337  && (pPhi >= fSPhi + fDPhi + halfAngTolerance))
338  {
339  ;
340  }
341  else
342  {
343  in = eSurface;
344  }
345  }
346  }
347  }
348  }
349  return in;
350 }
351 
353 //
354 // Return Unit normal of surface closest to p
355 // - note if point on z axis, ignore phi divided sides
356 // - unsafe if point close to z axis a rmin=0 - no explicit checks
357 
358 bool UTubs::Normal(const UVector3& p, UVector3& n) const
359 {
360  int noSurfaces = 0;
361  double rho, pPhi;
362  double distZ, distRMin, distRMax;
363  double distSPhi = UUtils::kInfinity, distEPhi = UUtils::kInfinity;
364 
365  static const double halfCarTolerance = 0.5 * VUSolid::Tolerance();
366  static const double halfAngTolerance = 0.5 * kAngTolerance;
367 
368  UVector3 norm, sumnorm(0., 0., 0.);
369  UVector3 nZ = UVector3(0, 0, 1.0);
370  UVector3 nR, nPs, nPe;
371 
372  rho = std::sqrt(p.x() * p.x() + p.y() * p.y());
373 
374  distRMin = std::fabs(rho - fRMin);
375  distRMax = std::fabs(rho - fRMax);
376  distZ = std::fabs(std::fabs(p.z()) - fDz);
377 
378  if (!fPhiFullTube) // Protected against (0,0,z)
379  {
380  if (rho > halfCarTolerance)
381  {
382  pPhi = std::atan2(p.y(), p.x());
383 
384  if (pPhi < fSPhi - halfCarTolerance)
385  {
386  pPhi += 2 * UUtils::kPi;
387  }
388  else if (pPhi > fSPhi + fDPhi + halfCarTolerance)
389  {
390  pPhi -= 2 * UUtils::kPi;
391  }
392 
393  distSPhi = std::fabs(pPhi - fSPhi);
394  distEPhi = std::fabs(pPhi - fSPhi - fDPhi);
395  }
396  else if (!fRMin)
397  {
398  distSPhi = 0.;
399  distEPhi = 0.;
400  }
401  nPs = UVector3(fSinSPhi, -fCosSPhi, 0);
402  nPe = UVector3(-fSinSPhiDPhi /* std::sin(fSPhi+fDPhi)*/, fCosSPhiDPhi, 0);
403  }
404  if (rho > halfCarTolerance)
405  {
406  nR = UVector3(p.x() / rho, p.y() / rho, 0);
407  }
408 
409  if (distRMax <= halfCarTolerance)
410  {
411  noSurfaces ++;
412  sumnorm += nR;
413  }
414  if (fRMin && (distRMin <= halfCarTolerance))
415  {
416  noSurfaces ++;
417  sumnorm -= nR;
418  }
419  if (fDPhi < 2 * UUtils::kPi)
420  {
421  if (distSPhi <= halfAngTolerance)
422  {
423  noSurfaces ++;
424  sumnorm += nPs;
425  }
426  if (distEPhi <= halfAngTolerance)
427  {
428  noSurfaces ++;
429  sumnorm += nPe;
430  }
431  }
432  if (distZ <= halfCarTolerance)
433  {
434  noSurfaces ++;
435  if (p.z() >= 0.)
436  {
437  sumnorm += nZ;
438  }
439  else
440  {
441  sumnorm -= nZ;
442  }
443  }
444  if (noSurfaces == 0)
445  {
446 #ifdef UDEBUG
447  UUtils::Exception("UTubs::SurfaceNormal(p)", "GeomSolids1002",
448  UWarning, 1, "Point p is not on surface !?");
449  int oldprc = cout.precision(20);
450  cout << "UTubs::SN ( " << p.x() << ", " << p.y() << ", " << p.z() << " ); "
451  << std::endl << std::endl;
452  cout.precision(oldprc);
453 #endif
454  norm = ApproxSurfaceNormal(p);
455  }
456  else if (noSurfaces == 1)
457  {
458  norm = sumnorm;
459  }
460  else
461  {
462  norm = sumnorm.Unit();
463  }
464 
465  n = norm;
466 
467  return noSurfaces; // TODO: return true or false on validity
468 }
469 
471 //
472 // Algorithm for SurfaceNormal() following the original specification
473 // for points not on the surface
474 
476 {
477  ENorm side;
478  UVector3 norm;
479  double rho, phi;
480  double distZ, distRMin, distRMax, distSPhi, distEPhi, distMin;
481 
482  rho = std::sqrt(p.x() * p.x() + p.y() * p.y());
483 
484  distRMin = std::fabs(rho - fRMin);
485  distRMax = std::fabs(rho - fRMax);
486  distZ = std::fabs(std::fabs(p.z()) - fDz);
487 
488  if (distRMin < distRMax) // First minimum
489  {
490  if (distZ < distRMin)
491  {
492  distMin = distZ;
493  side = kNZ;
494  }
495  else
496  {
497  distMin = distRMin;
498  side = kNRMin ;
499  }
500  }
501  else
502  {
503  if (distZ < distRMax)
504  {
505  distMin = distZ;
506  side = kNZ ;
507  }
508  else
509  {
510  distMin = distRMax;
511  side = kNRMax ;
512  }
513  }
514  if (!fPhiFullTube && rho) // Protected against (0,0,z)
515  {
516  phi = std::atan2(p.y(), p.x());
517 
518  if (phi < 0)
519  {
520  phi += 2 * UUtils::kPi;
521  }
522 
523  if (fSPhi < 0)
524  {
525  distSPhi = std::fabs(phi - (fSPhi + 2 * UUtils::kPi)) * rho;
526  }
527  else
528  {
529  distSPhi = std::fabs(phi - fSPhi) * rho;
530  }
531  distEPhi = std::fabs(phi - fSPhi - fDPhi) * rho;
532 
533  if (distSPhi < distEPhi) // Find new minimum
534  {
535  if (distSPhi < distMin)
536  {
537  side = kNSPhi;
538  }
539  }
540  else
541  {
542  if (distEPhi < distMin)
543  {
544  side = kNEPhi;
545  }
546  }
547  }
548  switch (side)
549  {
550  case kNRMin : // Inner radius
551  {
552  norm = UVector3(-p.x() / rho, -p.y() / rho, 0);
553  break;
554  }
555  case kNRMax : // Outer radius
556  {
557  norm = UVector3(p.x() / rho, p.y() / rho, 0);
558  break;
559  }
560  case kNZ : // + or - dz
561  {
562  if (p.z() > 0)
563  {
564  norm = UVector3(0, 0, 1);
565  }
566  else
567  {
568  norm = UVector3(0, 0, -1);
569  }
570  break;
571  }
572  case kNSPhi:
573  {
574  norm = UVector3(fSinSPhi, -fCosSPhi, 0);
575  break;
576  }
577  case kNEPhi:
578  {
579  norm = UVector3(-fSinSPhiDPhi, fCosSPhiDPhi, 0);
580  break;
581  }
582  default: // Should never reach this case ...
583  {
584  // DumpInfo();
585  UUtils::Exception("UTubs::ApproxSurfaceNormal()",
586  "GeomSolids1002", UWarning, 1,
587  "Undefined side for valid surface normal to solid.");
588  break;
589  }
590  }
591  return norm;
592 }
593 
595 //
596 //
597 // Calculate distance to shape from outside, along normalised vector
598 // - return UUtils::kInfinity if no intersection, or intersection distance <= tolerance
599 //
600 // - Compute the intersection with the z planes
601 // - if at valid r, phi, return
602 //
603 // -> If point is outer outer radius, compute intersection with rmax
604 // - if at valid phi,z return
605 //
606 // -> Compute intersection with inner radius, taking largest +ve root
607 // - if valid (in z,phi), save intersction
608 //
609 // -> If phi segmented, compute intersections with phi half planes
610 // - return smallest of valid phi intersections and
611 // inner radius intersection
612 //
613 // NOTE:
614 // - 'if valid' implies tolerant checking of intersection points
615 
616 double UTubs::DistanceToIn(const UVector3& p, const UVector3& v, double) const
617 {
618  double snxt = UUtils::kInfinity; // snxt = default return value
619  double tolORMin2, tolIRMax2; // 'generous' radii squared
620  double tolORMax2, tolIRMin2, tolODz, tolIDz;
621  const double dRmax = 100.*fRMax;
622 
623  static const double halfCarTolerance = 0.5 * VUSolid::Tolerance();
624  static const double halfRadTolerance = 0.5 * kRadTolerance;
625 
626  // Intersection point variables
627  //
628  double Dist, sd, xi, yi, zi, rho2, inum, iden, cosPsi, Comp;
629  double t1, t2, t3, b, c, d; // Quadratic solver variables
630 
631  // Calculate tolerant rmin and rmax
632 
633  if (fRMin > kRadTolerance)
634  {
635  tolORMin2 = (fRMin - halfRadTolerance) * (fRMin - halfRadTolerance);
636  tolIRMin2 = (fRMin + halfRadTolerance) * (fRMin + halfRadTolerance);
637  }
638  else
639  {
640  tolORMin2 = 0.0;
641  tolIRMin2 = 0.0;
642  }
643  tolORMax2 = (fRMax + halfRadTolerance) * (fRMax + halfRadTolerance);
644  tolIRMax2 = (fRMax - halfRadTolerance) * (fRMax - halfRadTolerance);
645 
646  // Intersection with Z surfaces
647 
648  tolIDz = fDz - halfCarTolerance;
649  tolODz = fDz + halfCarTolerance;
650 
651  if (std::fabs(p.z()) >= tolIDz)
652  {
653  if (p.z() * v.z() < 0) // at +Z going in -Z or visa versa
654  {
655  sd = (std::fabs(p.z()) - fDz) / std::fabs(v.z()); // Z intersect distance
656 
657  if (sd < 0.0)
658  {
659  sd = 0.0;
660  }
661 
662  xi = p.x() + sd * v.x(); // Intersection coords
663  yi = p.y() + sd * v.y();
664  rho2 = xi * xi + yi * yi;
665 
666  // Check validity of intersection
667 
668  if ((tolIRMin2 <= rho2) && (rho2 <= tolIRMax2))
669  {
670  if (!fPhiFullTube && rho2)
671  {
672  // Psi = angle made with central (average) phi of shape
673  //
674  inum = xi * fCosCPhi + yi * fSinCPhi;
675  iden = std::sqrt(rho2);
676  cosPsi = inum / iden;
677  if (cosPsi >= fCosHDPhiIT)
678  {
679  return sd;
680  }
681  }
682  else
683  {
684  return sd;
685  }
686  }
687  }
688  else
689  {
690  if (snxt < halfCarTolerance)
691  {
692  snxt = 0;
693  }
694  return snxt; // On/outside extent, and heading away
695  // -> cannot intersect
696  }
697  }
698 
699  // -> Can not intersect z surfaces
700  //
701  // Intersection with rmax (possible return) and rmin (must also check phi)
702  //
703  // Intersection point (xi,yi,zi) on line x=p.x+t*v.x etc.
704  //
705  // Intersects with x^2+y^2=R^2
706  //
707  // 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
708  // t1 t2 t3
709 
710  t1 = 1.0 - v.z() * v.z();
711  t2 = p.x() * v.x() + p.y() * v.y();
712  t3 = p.x() * p.x() + p.y() * p.y();
713 
714  if (t1 > 0) // Check not || to z axis
715  {
716  b = t2 / t1;
717  c = t3 - fRMax * fRMax;
718  if ((t3 >= tolORMax2) && (t2 < 0)) // This also handles the tangent case
719  {
720  // Try outer cylinder intersection
721  // c=(t3-fRMax*fRMax)/t1;
722 
723  c /= t1;
724  d = b * b - c;
725 
726  if (d >= 0) // If real root
727  {
728  sd = c / (-b + std::sqrt(d));
729  if (sd >= 0) // If 'forwards'
730  {
731  if (sd > dRmax) // Avoid rounding errors due to precision issues on
732  {
733  // 64 bits systems. Split long distances and recompute
734  double fTerm = sd - std::fmod(sd, dRmax);
735  sd = fTerm + DistanceToIn(p + fTerm * v, v);
736  }
737  // Check z intersection
738  //
739  zi = p.z() + sd * v.z();
740  if (std::fabs(zi) <= tolODz)
741  {
742  // Z ok. Check phi intersection if reqd
743  //
744  if (fPhiFullTube)
745  {
746  return sd;
747  }
748  else
749  {
750  xi = p.x() + sd * v.x();
751  yi = p.y() + sd * v.y();
752  cosPsi = (xi * fCosCPhi + yi * fSinCPhi) / fRMax;
753  if (cosPsi >= fCosHDPhiIT)
754  {
755  return sd;
756  }
757  }
758  } // end if std::fabs(zi)
759  } // end if (sd>=0)
760  } // end if (d>=0)
761  } // end if (r>=fRMax)
762  else
763  {
764  // Inside outer radius :
765  // check not inside, and heading through tubs (-> 0 to in)
766 
767  if ((t3 > tolIRMin2) && (t2 < 0) && (std::fabs(p.z()) <= tolIDz))
768  {
769  // Inside both radii, delta r -ve, inside z extent
770 
771  if (!fPhiFullTube)
772  {
773  inum = p.x() * fCosCPhi + p.y() * fSinCPhi;
774  iden = std::sqrt(t3);
775  cosPsi = inum / iden;
776  if (cosPsi >= fCosHDPhiIT)
777  {
778  // In the old version, the small negative tangent for the point
779  // on surface was not taken in account, and returning 0.0 ...
780  // New version: check the tangent for the point on surface and
781  // if no intersection, return UUtils::kInfinity, if intersection instead
782  // return sd.
783  //
784  c = t3 - fRMax * fRMax;
785  if (c <= 0.0)
786  {
787  return 0.0;
788  }
789  else
790  {
791  c = c / t1;
792  d = b * b - c;
793  if (d >= 0.0)
794  {
795  snxt = c / (-b + std::sqrt(d)); // using safe solution
796  // for quadratic equation
797  if (snxt < halfCarTolerance)
798  {
799  snxt = 0;
800  }
801  return snxt;
802  }
803  else
804  {
805  return UUtils::kInfinity;
806  }
807  }
808  }
809  }
810  else
811  {
812  // In the old version, the small negative tangent for the point
813  // on surface was not taken in account, and returning 0.0 ...
814  // New version: check the tangent for the point on surface and
815  // if no intersection, return UUtils::kInfinity, if intersection instead
816  // return sd.
817  //
818  c = t3 - fRMax * fRMax;
819  if (c <= 0.0)
820  {
821  return 0.0;
822  }
823  else
824  {
825  c = c / t1;
826  d = b * b - c;
827  if (d >= 0.0)
828  {
829  snxt = c / (-b + std::sqrt(d)); // using safe solution
830  // for quadratic equation
831  if (snxt < halfCarTolerance)
832  {
833  snxt = 0;
834  }
835  return snxt;
836  }
837  else
838  {
839  return UUtils::kInfinity;
840  }
841  }
842  } // end if (!fPhiFullTube)
843  } // end if (t3>tolIRMin2)
844  } // end if (Inside Outer Radius)
845  if (fRMin) // Try inner cylinder intersection
846  {
847  c = (t3 - fRMin * fRMin) / t1;
848  d = b * b - c;
849  if (d >= 0.0) // If real root
850  {
851  // Always want 2nd root - we are outside and know rmax Hit was bad
852  // - If on surface of rmin also need farthest root
853 
854  sd = (b > 0.) ? c / (-b - std::sqrt(d)) : (-b + std::sqrt(d));
855  if (sd >= -halfCarTolerance) // check forwards
856  {
857  // Check z intersection
858  //
859  if (sd < 0.0)
860  {
861  sd = 0.0;
862  }
863  if (sd > dRmax) // Avoid rounding errors due to precision issues seen
864  {
865  // 64 bits systems. Split long distances and recompute
866  double fTerm = sd - std::fmod(sd, dRmax);
867  sd = fTerm + DistanceToIn(p + fTerm * v, v);
868  }
869  zi = p.z() + sd * v.z();
870  if (std::fabs(zi) <= tolODz)
871  {
872  // Z ok. Check phi
873  //
874  if (fPhiFullTube)
875  {
876  return sd;
877  }
878  else
879  {
880  xi = p.x() + sd * v.x();
881  yi = p.y() + sd * v.y();
882  cosPsi = (xi * fCosCPhi + yi * fSinCPhi) / fRMin;
883  if (cosPsi >= fCosHDPhiIT)
884  {
885  // Good inner radius isect
886  // - but earlier phi isect still possible
887 
888  snxt = sd;
889  }
890  }
891  } // end if std::fabs(zi)
892  } // end if (sd>=0)
893  } // end if (d>=0)
894  } // end if (fRMin)
895  }
896 
897  // Phi segment intersection
898  //
899  // o Tolerant of points inside phi planes by up to VUSolid::Tolerance()*0.5
900  //
901  // o NOTE: Large duplication of code between sphi & ephi checks
902  // -> only diffs: sphi -> ephi, Comp -> -Comp and half-plane
903  // intersection check <=0 -> >=0
904  // -> use some form of loop Construct ?
905  //
906  if (!fPhiFullTube)
907  {
908  // First phi surface (Starting phi)
909  //
910  Comp = v.x() * fSinSPhi - v.y() * fCosSPhi;
911 
912  if (Comp < 0) // Component in outwards normal dirn
913  {
914  Dist = (p.y() * fCosSPhi - p.x() * fSinSPhi);
915 
916  if (Dist < halfCarTolerance)
917  {
918  sd = Dist / Comp;
919 
920  if (sd < snxt)
921  {
922  if (sd < 0)
923  {
924  sd = 0.0;
925  }
926  zi = p.z() + sd * v.z();
927  if (std::fabs(zi) <= tolODz)
928  {
929  xi = p.x() + sd * v.x();
930  yi = p.y() + sd * v.y();
931  rho2 = xi * xi + yi * yi;
932 
933  if (((rho2 >= tolIRMin2) && (rho2 <= tolIRMax2))
934  || ((rho2 > tolORMin2) && (rho2 < tolIRMin2)
935  && (v.y() * fCosSPhi - v.x() * fSinSPhi > 0)
936  && (v.x() * fCosSPhi + v.y() * fSinSPhi >= 0))
937  || ((rho2 > tolIRMax2) && (rho2 < tolORMax2)
938  && (v.y() * fCosSPhi - v.x() * fSinSPhi > 0)
939  && (v.x() * fCosSPhi + v.y() * fSinSPhi < 0)))
940  {
941  // z and r intersections good
942  // - check intersecting with correct half-plane
943  //
944  if ((yi * fCosCPhi - xi * fSinCPhi) <= halfCarTolerance)
945  {
946  snxt = sd;
947  }
948  }
949  }
950  }
951  }
952  }
953 
954  // Second phi surface (Ending phi)
955 
956  Comp = -(v.x() * fSinEPhi - v.y() * fCosEPhi);
957 
958  if (Comp < 0) // Component in outwards normal dirn
959  {
960  Dist = -(p.y() * fCosEPhi - p.x() * fSinEPhi);
961 
962  if (Dist < halfCarTolerance)
963  {
964  sd = Dist / Comp;
965 
966  if (sd < snxt)
967  {
968  if (sd < 0)
969  {
970  sd = 0;
971  }
972  zi = p.z() + sd * v.z();
973  if (std::fabs(zi) <= tolODz)
974  {
975  xi = p.x() + sd * v.x();
976  yi = p.y() + sd * v.y();
977  rho2 = xi * xi + yi * yi;
978  if (((rho2 >= tolIRMin2) && (rho2 <= tolIRMax2))
979  || ((rho2 > tolORMin2) && (rho2 < tolIRMin2)
980  && (v.x() * fSinEPhi - v.y() * fCosEPhi > 0)
981  && (v.x() * fCosEPhi + v.y() * fSinEPhi >= 0))
982  || ((rho2 > tolIRMax2) && (rho2 < tolORMax2)
983  && (v.x() * fSinEPhi - v.y() * fCosEPhi > 0)
984  && (v.x() * fCosEPhi + v.y() * fSinEPhi < 0)))
985  {
986  // z and r intersections good
987  // - check intersecting with correct half-plane
988  //
989  if ((yi * fCosCPhi - xi * fSinCPhi) >= 0)
990  {
991  snxt = sd;
992  }
993  } //?? >=-halfCarTolerance
994  }
995  }
996  }
997  } // Comp < 0
998  } // !fPhiFullTube
999  if (snxt < halfCarTolerance)
1000  {
1001  snxt = 0;
1002  }
1003  return snxt;
1004 }
1005 
1007 //
1008 // Calculate distance to shape from outside, along normalised vector
1009 // - return UUtils::kInfinity if no intersection, or intersection distance <= tolerance
1010 //
1011 // - Compute the intersection with the z planes
1012 // - if at valid r, phi, return
1013 //
1014 // -> If point is outer outer radius, compute intersection with rmax
1015 // - if at valid phi,z return
1016 //
1017 // -> Compute intersection with inner radius, taking largest +ve root
1018 // - if valid (in z,phi), save intersction
1019 //
1020 // -> If phi segmented, compute intersections with phi half planes
1021 // - return smallest of valid phi intersections and
1022 // inner radius intersection
1023 //
1024 // NOTE:
1025 // - Precalculations for phi trigonometry are Done `just in time'
1026 // - `if valid' implies tolerant checking of intersection points
1027 // Calculate distance (<= actual) to closest surface of shape from outside
1028 // - Calculate distance to z, radial planes
1029 // - Only to phi planes if outside phi extent
1030 // - Return 0 if point inside
1031 
1032 double UTubs::SafetyFromOutside(const UVector3& p, bool aAccurate) const
1033 {
1034  double safe = 0.0, rho, safe1, safe2, safe3;
1035  double safePhi;
1036  bool outside;
1037 
1038  rho = std::sqrt(p.x() * p.x() + p.y() * p.y());
1039  safe1 = fRMin - rho;
1040  safe2 = rho - fRMax;
1041  safe3 = std::fabs(p.z()) - fDz;
1042 
1043  if (safe1 > safe2)
1044  {
1045  safe = safe1;
1046  }
1047  else
1048  {
1049  safe = safe2;
1050  }
1051  if (safe3 > safe)
1052  {
1053  safe = safe3;
1054  }
1055 
1056  if ((!fPhiFullTube) && (rho))
1057  {
1058  safePhi = SafetyToPhi(p,rho,outside);
1059  if ((outside) && (safePhi > safe))
1060  {
1061  safe = safePhi;
1062  }
1063  }
1064 
1065  if (safe < 0)
1066  {
1067  safe = 0; return safe; // point is Inside;
1068  }
1069  if (!aAccurate) return safe;
1070  double safsq = 0.0;
1071  int count = 0;
1072  if (safe1 > 0)
1073  {
1074  safsq += safe1 * safe1;
1075  count++;
1076  }
1077  if (safe2 > 0)
1078  {
1079  safsq += safe2 * safe2;
1080  count++;
1081  }
1082  if (safe3 > 0)
1083  {
1084  safsq += safe3 * safe3;
1085  count++;
1086  }
1087  if (count == 1) return safe;
1088  return std::sqrt(safsq);
1089 }
1090 
1092 //
1093 // Calculate distance to surface of shape from `inside', allowing for tolerance
1094 // - Only Calc rmax intersection if no valid rmin intersection
1095 
1096 // double UTubs::DistanceToOut( const UVector3& p, const UVector3& v, const bool calcNorm, bool *validNorm, UVector3 *n ) const
1097 double UTubs::DistanceToOut(const UVector3& p, const UVector3& v, UVector3& n, bool& validNorm, double) const
1098 {
1099  ESide side = kNull , sider = kNull, sidephi = kNull;
1100  double snxt, srd = UUtils::kInfinity, sphi = UUtils::kInfinity, pdist;
1101  double deltaR, t1, t2, t3, b, c, d2, roMin2;
1102 
1103  static const double halfCarTolerance = VUSolid::Tolerance() * 0.5;
1104  static const double halfAngTolerance = kAngTolerance * 0.5;
1105 
1106  // Vars for phi intersection:
1107 
1108  double pDistS, compS, pDistE, compE, sphi2, xi, yi, vphi, roi2;
1109 
1110  // Z plane intersection
1111 
1112  if (v.z() > 0)
1113  {
1114  pdist = fDz - p.z();
1115  if (pdist > halfCarTolerance)
1116  {
1117  snxt = pdist / v.z();
1118  side = kPZ;
1119  }
1120  else
1121  {
1122  n = UVector3(0, 0, 1);
1123  validNorm = true;
1124  return snxt = 0;
1125  }
1126  }
1127  else if (v.z() < 0)
1128  {
1129  pdist = fDz + p.z();
1130 
1131  if (pdist > halfCarTolerance)
1132  {
1133  snxt = -pdist / v.z();
1134  side = kMZ;
1135  }
1136  else
1137  {
1138  n = UVector3(0, 0, -1);
1139  validNorm = true;
1140  return snxt = 0.0;
1141  }
1142  }
1143  else
1144  {
1145  snxt = UUtils::kInfinity; // Travel perpendicular to z axis
1146  side = kNull;
1147  }
1148 
1149  // Radial Intersections
1150  //
1151  // Find intersection with cylinders at rmax/rmin
1152  // Intersection point (xi,yi,zi) on line x=p.x+t*v.x etc.
1153  //
1154  // Intersects with x^2+y^2=R^2
1155  //
1156  // 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
1157  //
1158  // t1 t2 t3
1159 
1160  t1 = 1.0 - v.z() * v.z(); // since v normalised
1161  t2 = p.x() * v.x() + p.y() * v.y();
1162  t3 = p.x() * p.x() + p.y() * p.y();
1163 
1164  if (snxt > 10 * (fDz + fRMax))
1165  {
1166  roi2 = 2 * fRMax * fRMax;
1167  }
1168  else
1169  {
1170  roi2 = snxt * snxt * t1 + 2 * snxt * t2 + t3; // radius^2 on +-fDz
1171  }
1172 
1173  if (t1 > 0) // Check not parallel
1174  {
1175  // Calculate srd, r exit distance
1176 
1177  if ((t2 >= 0.0) && (roi2 > fRMax * (fRMax + kRadTolerance)))
1178  {
1179  // Delta r not negative => leaving via rmax
1180 
1181  deltaR = t3 - fRMax * fRMax;
1182 
1183  // NOTE: Should use rho-fRMax<-kRadTolerance*0.5
1184  // - avoid sqrt for efficiency
1185 
1186  if (deltaR < -kRadTolerance * fRMax)
1187  {
1188  b = t2 / t1;
1189  c = deltaR / t1;
1190  d2 = b * b - c;
1191  if (d2 >= 0)
1192  {
1193  srd = c / (-b - std::sqrt(d2));
1194  }
1195  else
1196  {
1197  srd = 0.;
1198  }
1199  sider = kRMax;
1200  }
1201  else
1202  {
1203  // On tolerant boundary & heading outwards (or perpendicular to)
1204  // outer radial surface -> leaving immediately
1205  n = UVector3(p.x() / fRMax, p.y() / fRMax, 0);
1206  validNorm = true;
1207  return snxt = 0; // Leaving by rmax immediately
1208  }
1209  }
1210  else if (t2 < 0.) // i.e. t2 < 0; Possible rmin intersection
1211  {
1212  roMin2 = t3 - t2 * t2 / t1; // min ro2 of the plane of movement
1213 
1214  if (fRMin && (roMin2 < fRMin * (fRMin - kRadTolerance)))
1215  {
1216  deltaR = t3 - fRMin * fRMin;
1217  b = t2 / t1;
1218  c = deltaR / t1;
1219  d2 = b * b - c;
1220 
1221  if (d2 >= 0) // Leaving via rmin
1222  {
1223  // NOTE: SHould use rho-rmin>kRadTolerance*0.5
1224  // - avoid sqrt for efficiency
1225 
1226  if (deltaR > kRadTolerance * fRMin)
1227  {
1228  srd = c / (-b + std::sqrt(d2));
1229  sider = kRMin;
1230  }
1231  else
1232  {
1233  validNorm = false; // Concave side
1234  n = UVector3(-p.x() / fRMin, -p.y() / fRMin, 0);
1235  return snxt = 0.0;
1236  }
1237  }
1238  else // No rmin intersect -> must be rmax intersect
1239  {
1240  deltaR = t3 - fRMax * fRMax;
1241  c = deltaR / t1;
1242  d2 = b * b - c;
1243  if (d2 >= 0.)
1244  {
1245  srd = -b + std::sqrt(d2);
1246  sider = kRMax;
1247  }
1248  else // Case: On the border+t2<kRadTolerance
1249  // (v is perpendicular to the surface)
1250  {
1251  n = UVector3(p.x() / fRMax, p.y() / fRMax, 0);
1252  validNorm = true;
1253  return snxt = 0.0;
1254  }
1255  }
1256  }
1257  else if (roi2 > fRMax * (fRMax + kRadTolerance))
1258  // No rmin intersect -> must be rmax intersect
1259  {
1260  deltaR = t3 - fRMax * fRMax;
1261  b = t2 / t1;
1262  c = deltaR / t1;
1263  d2 = b * b - c;
1264  if (d2 >= 0)
1265  {
1266  srd = -b + std::sqrt(d2);
1267  sider = kRMax;
1268  }
1269  else // Case: On the border+t2<kRadTolerance
1270  // (v is perpendicular to the surface)
1271  {
1272  n = UVector3(p.x() / fRMax, p.y() / fRMax, 0);
1273  validNorm = true;
1274  return snxt = 0.0;
1275  }
1276  }
1277  }
1278 
1279  // Phi Intersection
1280 
1281  if (!fPhiFullTube)
1282  {
1283  // add angle calculation with correction
1284  // of the difference in domain of atan2 and Sphi
1285  //
1286  vphi = std::atan2(v.y(), v.x());
1287 
1288  if (vphi < fSPhi - halfAngTolerance)
1289  {
1290  vphi += 2 * UUtils::kPi;
1291  }
1292  else if (vphi > fSPhi + fDPhi + halfAngTolerance)
1293  {
1294  vphi -= 2 * UUtils::kPi;
1295  }
1296 
1297 
1298  if (p.x() || p.y()) // Check if on z axis (rho not needed later)
1299  {
1300  // pDist -ve when inside
1301 
1302  pDistS = p.x() * fSinSPhi - p.y() * fCosSPhi;
1303  pDistE = -p.x() * fSinEPhi + p.y() * fCosEPhi;
1304 
1305  // Comp -ve when in direction of outwards normal
1306 
1307  compS = -fSinSPhi * v.x() + fCosSPhi * v.y();
1308  compE = fSinEPhi * v.x() - fCosEPhi * v.y();
1309 
1310  sidephi = kNull;
1311 
1312  if (((fDPhi <= UUtils::kPi) && ((pDistS <= halfCarTolerance)
1313  && (pDistE <= halfCarTolerance)))
1314  || ((fDPhi > UUtils::kPi) && !((pDistS > halfCarTolerance)
1315  && (pDistE > halfCarTolerance))))
1316  {
1317  // Inside both phi *full* planes
1318 
1319  if (compS < 0)
1320  {
1321  sphi = pDistS / compS;
1322 
1323  if (sphi >= -halfCarTolerance)
1324  {
1325  xi = p.x() + sphi * v.x();
1326  yi = p.y() + sphi * v.y();
1327 
1328  // Check intersecting with correct half-plane
1329  // (if not -> no intersect)
1330  //
1331  if ((std::fabs(xi) <= VUSolid::Tolerance()) && (std::fabs(yi) <= VUSolid::Tolerance()))
1332  {
1333  sidephi = kSPhi;
1334  if (((fSPhi - halfAngTolerance) <= vphi)
1335  && ((fSPhi + fDPhi + halfAngTolerance) >= vphi))
1336  {
1337  sphi = UUtils::kInfinity;
1338  }
1339  }
1340  else if (yi * fCosCPhi - xi * fSinCPhi >= 0)
1341  {
1342  sphi = UUtils::kInfinity;
1343  }
1344  else
1345  {
1346  sidephi = kSPhi;
1347  if (pDistS > -halfCarTolerance)
1348  {
1349  sphi = 0.0; // Leave by sphi immediately
1350  }
1351  }
1352  }
1353  else
1354  {
1355  sphi = UUtils::kInfinity;
1356  }
1357  }
1358  else
1359  {
1360  sphi = UUtils::kInfinity;
1361  }
1362 
1363  if (compE < 0)
1364  {
1365  sphi2 = pDistE / compE;
1366 
1367  // Only check further if < starting phi intersection
1368  //
1369  if ((sphi2 > -halfCarTolerance) && (sphi2 < sphi))
1370  {
1371  xi = p.x() + sphi2 * v.x();
1372  yi = p.y() + sphi2 * v.y();
1373 
1374  if ((std::fabs(xi) <= VUSolid::Tolerance()) && (std::fabs(yi) <= VUSolid::Tolerance()))
1375  {
1376  // Leaving via ending phi
1377  //
1378  if (!((fSPhi - halfAngTolerance <= vphi)
1379  && (fSPhi + fDPhi + halfAngTolerance >= vphi)))
1380  {
1381  sidephi = kEPhi;
1382  if (pDistE <= -halfCarTolerance)
1383  {
1384  sphi = sphi2;
1385  }
1386  else
1387  {
1388  sphi = 0.0;
1389  }
1390  }
1391  }
1392  else // Check intersecting with correct half-plane
1393 
1394  if ((yi * fCosCPhi - xi * fSinCPhi) >= 0)
1395  {
1396  // Leaving via ending phi
1397  //
1398  sidephi = kEPhi;
1399  if (pDistE <= -halfCarTolerance)
1400  {
1401  sphi = sphi2;
1402  }
1403  else
1404  {
1405  sphi = 0.0;
1406  }
1407  }
1408  }
1409  }
1410  }
1411  else
1412  {
1413  sphi = UUtils::kInfinity;
1414  }
1415  }
1416  else
1417  {
1418  // On z axis + travel not || to z axis -> if phi of vector direction
1419  // within phi of shape, Step limited by rmax, else Step =0
1420 
1421  if ((fSPhi - halfAngTolerance <= vphi)
1422  && (vphi <= fSPhi + fDPhi + halfAngTolerance))
1423  {
1424  sphi = UUtils::kInfinity;
1425  }
1426  else
1427  {
1428  sidephi = kSPhi; // arbitrary
1429  sphi = 0.0;
1430  }
1431  }
1432  if (sphi < snxt) // Order intersecttions
1433  {
1434  snxt = sphi;
1435  side = sidephi;
1436  }
1437  }
1438  if (srd < snxt) // Order intersections
1439  {
1440  snxt = srd;
1441  side = sider;
1442  }
1443  }
1444  // if (calcNorm)
1445  {
1446  switch (side)
1447  {
1448  case kRMax:
1449  // Note: returned vector not normalised
1450  // (divide by fRMax for Unit vector)
1451  //
1452  xi = p.x() + snxt * v.x();
1453  yi = p.y() + snxt * v.y();
1454  n = UVector3(xi / fRMax, yi / fRMax, 0);
1455  validNorm = true;
1456  break;
1457 
1458  case kRMin:
1459  xi = p.x() + snxt * v.x();
1460  yi = p.y() + snxt * v.y();
1461  n = UVector3(-xi / fRMin, -yi / fRMin, 0);
1462  validNorm = false; // Rmin is inconvex
1463  break;
1464 
1465  case kSPhi:
1466  if (fDPhi <= UUtils::kPi)
1467  {
1468  n = UVector3(fSinSPhi, -fCosSPhi, 0);
1469  validNorm = true;
1470  }
1471  else
1472  {
1473  n = UVector3(fSinSPhi, -fCosSPhi, 0);
1474  validNorm = false;
1475  }
1476  break;
1477 
1478  case kEPhi:
1479  if (fDPhi <= UUtils::kPi)
1480  {
1481  n = UVector3(-fSinEPhi, fCosEPhi, 0);
1482  validNorm = true;
1483  }
1484  else
1485  {
1486  n = UVector3(-fSinEPhi, fCosEPhi, 0);
1487  validNorm = false;
1488  }
1489  break;
1490 
1491  case kPZ:
1492  n = UVector3(0, 0, 1);
1493  validNorm = true;
1494  break;
1495 
1496  case kMZ:
1497  n = UVector3(0, 0, -1);
1498  validNorm = true;
1499  break;
1500 
1501  default:
1502  cout << std::endl;
1503  // DumpInfo();
1504  std::ostringstream message;
1505  int oldprc = message.precision(16);
1506  message << "Undefined side for valid surface normal to solid."
1507  << std::endl
1508  << "Position:" << std::endl << std::endl
1509  << "p.x = " << p.x() << " mm" << std::endl
1510  << "p.y = " << p.y() << " mm" << std::endl
1511  << "p.z = " << p.z() << " mm" << std::endl << std::endl
1512  << "Direction:" << std::endl << std::endl
1513  << "v.x = " << v.x() << std::endl
1514  << "v.y = " << v.y() << std::endl
1515  << "v.z = " << v.z() << std::endl << std::endl
1516  << "Proposed distance :" << std::endl << std::endl
1517  << "snxt = " << snxt << " mm" << std::endl;
1518  message.precision(oldprc);
1519  UUtils::Exception("UTubs::DistanceToOut(p,v,..)", "GeomSolids1002",
1520  UWarning, 1, message.str().c_str());
1521  break;
1522  }
1523  }
1524  if (snxt < halfCarTolerance)
1525  {
1526  snxt = 0;
1527  }
1528 
1529  return snxt;
1530 }
1531 
1533 //
1534 // Calculate distance (<=actual) to closest surface of shape from inside
1535 
1536 double UTubs::SafetyFromInside(const UVector3& p, bool) const
1537 {
1538  double safe = 0.0, rho, safeZ;
1539  rho = std::sqrt(p.x() * p.x() + p.y() * p.y());
1540 
1541 #ifdef UDEBUG
1542  if (Inside(p) == eOutside)
1543  {
1544  int oldprc = cout.precision(16);
1545  cout << std::endl;
1546  DumpInfo();
1547  cout << "Position:" << std::endl << std::endl;
1548  cout << "p.x = " << p.x() << " mm" << std::endl;
1549  cout << "p.y = " << p.y() << " mm" << std::endl;
1550  cout << "p.z = " << p.z() << " mm" << std::endl << std::endl;
1551  cout.precision(oldprc);
1552  UUtils::Exception("UTubs::DistanceToOut(p)", "GeomSolids1002",
1553  UWarning, 1, "Point p is outside !?");
1554  }
1555 #endif
1556  safe = SafetyFromInsideR(p, rho);
1557  safeZ = fDz - std::fabs(p.z());
1558 
1559  if (safeZ < safe)
1560  {
1561  safe = safeZ;
1562  }
1563 
1564  if (safe < 0)
1565  {
1566  safe = 0;
1567  }
1568 
1569  return safe;
1570 }
1571 
1573 //
1574 // Stream object contents to an output stream
1575 
1577 {
1578  return std::string("Tubs");
1579 }
1580 
1582 //
1583 // Make a clone of the object
1584 //
1586 {
1587  return new UTubs(*this);
1588 }
1589 
1591 //
1592 // Stream object contents to an output stream
1593 
1594 std::ostream& UTubs::StreamInfo(std::ostream& os) const
1595 {
1596  int oldprc = os.precision(16);
1597  os << "-----------------------------------------------------------\n"
1598  << " *** Dump for solid - " << GetName() << " ***\n"
1599  << " ===================================================\n"
1600  << " Solid type: UTubs\n"
1601  << " Parameters: \n"
1602  << " inner radius : " << fRMin << " mm \n"
1603  << " outer radius : " << fRMax << " mm \n"
1604  << " half length Z: " << fDz << " mm \n"
1605  << " starting phi : " << fSPhi / (UUtils::kPi / 180.0) << " degrees \n"
1606  << " delta phi : " << fDPhi / (UUtils::kPi / 180.0) << " degrees \n"
1607  << "-----------------------------------------------------------\n";
1608  os.precision(oldprc);
1609 
1610  return os;
1611 }
1612 
1614 //
1615 // GetPointOnSurface
1616 
1618 {
1619  double xRand, yRand, zRand, phi, cosphi, sinphi, chose,
1620  aOne, aTwo, aThr, aFou;
1621  double rRand;
1622 
1623  aOne = 2.*fDz * fDPhi * fRMax;
1624  aTwo = 2.*fDz * fDPhi * fRMin;
1625  aThr = 0.5 * fDPhi * (fRMax * fRMax - fRMin * fRMin);
1626  aFou = 2.*fDz * (fRMax - fRMin);
1627 
1628  phi = UUtils::Random(fSPhi, fSPhi + fDPhi);
1629  cosphi = std::cos(phi);
1630  sinphi = std::sin(phi);
1631 
1632  rRand = UUtils::GetRadiusInRing(fRMin, fRMax);
1633 
1634  if ((fSPhi == 0) && (fDPhi == 2 * UUtils::kPi))
1635  {
1636  aFou = 0;
1637  }
1638 
1639  chose = UUtils::Random(0., aOne + aTwo + 2.*aThr + 2.*aFou);
1640 
1641  if ((chose >= 0) && (chose < aOne))
1642  {
1643  xRand = fRMax * cosphi;
1644  yRand = fRMax * sinphi;
1645  zRand = UUtils::Random(-1.*fDz, fDz);
1646  return UVector3(xRand, yRand, zRand);
1647  }
1648  else if ((chose >= aOne) && (chose < aOne + aTwo))
1649  {
1650  xRand = fRMin * cosphi;
1651  yRand = fRMin * sinphi;
1652  zRand = UUtils::Random(-1.*fDz, fDz);
1653  return UVector3(xRand, yRand, zRand);
1654  }
1655  else if ((chose >= aOne + aTwo) && (chose < aOne + aTwo + aThr))
1656  {
1657  xRand = rRand * cosphi;
1658  yRand = rRand * sinphi;
1659  zRand = fDz;
1660  return UVector3(xRand, yRand, zRand);
1661  }
1662  else if ((chose >= aOne + aTwo + aThr) && (chose < aOne + aTwo + 2.*aThr))
1663  {
1664  xRand = rRand * cosphi;
1665  yRand = rRand * sinphi;
1666  zRand = -1.*fDz;
1667  return UVector3(xRand, yRand, zRand);
1668  }
1669  else if ((chose >= aOne + aTwo + 2.*aThr)
1670  && (chose < aOne + aTwo + 2.*aThr + aFou))
1671  {
1672  xRand = rRand * fCosSPhi;
1673  yRand = rRand * fSinSPhi;
1674  zRand = UUtils::Random(-1.*fDz, fDz);
1675  return UVector3(xRand, yRand, zRand);
1676  }
1677  else
1678  {
1679  xRand = rRand * fCosSPhiDPhi;
1680  yRand = rRand * fSinSPhiDPhi;
1681  zRand = UUtils::Random(-1.*fDz, fDz);
1682  return UVector3(xRand, yRand, zRand);
1683  }
1684 }
1685 
1686 void UTubs::Extent(UVector3& aMin, UVector3& aMax) const
1687 {
1688  aMin = UVector3(-fRMax, -fRMax, -fDz);
1689  aMax = UVector3(fRMax, fRMax, fDz);
1690 }
1691 
1692 void UTubs::GetParametersList(int, double* aArray) const
1693 {
1694  aArray[0] = GetInnerRadius();
1695  aArray[1] = GetOuterRadius();
1696  aArray[2] = GetZHalfLength();
1697  aArray[3] = GetStartPhiAngle();
1698  aArray[4] = GetDeltaPhiAngle();
1699 }
double fCosSPhiDPhi
Definition: UTubs.hh:180
Definition: UTubs.hh:48
double fCosEPhi
Definition: UTubs.hh:180
double fSinSPhiDPhi
Definition: UTubs.hh:180
double GetStartPhiAngle() const
double fCosHDPhiIT
Definition: UTubs.hh:180
double & z()
Definition: UVector3.hh:352
double & y()
Definition: UVector3.hh:348
static double frTolerance
Definition: VUSolid.hh:31
double GetZHalfLength() const
double SafetyFromOutside(const UVector3 &p, bool precise=false) const
Definition: UTubs.cc:1032
double fSPhi
Definition: UTubs.hh:176
double SafetyFromInside(const UVector3 &p, bool precise=false) const
Definition: UTubs.cc:1536
virtual void GetParametersList(int, double *) const
Definition: UTubs.cc:1692
const std::string & GetName() const
Definition: VUSolid.hh:103
double GetInnerRadius() const
VUSolid::EnumInside Inside(const UVector3 &p) const
Definition: UTubs.cc:155
double fSinCPhi
Definition: UTubs.hh:180
VUSolid * Clone() const
Definition: UTubs.cc:1585
static double Tolerance()
Definition: VUSolid.hh:127
double fDPhi
Definition: UTubs.hh:176
void CheckPhiAngles(double sPhi, double dPhi)
double fDz
Definition: UTubs.hh:176
static const double kInfinity
Definition: UUtils.hh:54
double DistanceToOut(const UVector3 &p, const UVector3 &v, UVector3 &n, bool &validNorm, double aPstep=UUtils::kInfinity) const
Definition: UTubs.cc:1097
double GetDeltaPhiAngle() const
UGeometryType GetEntityType() const
Definition: UTubs.cc:1576
double fCosSPhi
Definition: UTubs.hh:180
bool Normal(const UVector3 &p, UVector3 &normal) const
Definition: UTubs.cc:358
virtual UVector3 ApproxSurfaceNormal(const UVector3 &p) const
Definition: UTubs.cc:475
UTubs & operator=(const UTubs &rhs)
Definition: UTubs.cc:110
double & x()
Definition: UVector3.hh:344
double fRMin
Definition: UTubs.hh:176
double fSinSPhi
Definition: UTubs.hh:180
static double faTolerance
Definition: VUSolid.hh:32
bool fPhiFullTube
Definition: UTubs.hh:185
double kAngTolerance
Definition: UTubs.hh:172
double fCubicVolume
Definition: UTubs.hh:163
ENorm
Definition: UTubs.hh:170
EnumInside
Definition: VUSolid.hh:23
const G4int n
UVector3 GetPointOnSurface() const
Definition: UTubs.cc:1617
void Extent(UVector3 &aMin, UVector3 &aMax) const
Definition: UTubs.cc:1686
virtual ~UTubs()
Definition: UTubs.cc:83
double GetRadiusInRing(double rmin, double rmax)
Definition: UUtils.hh:156
void Exception(const char *originOfException, const char *exceptionCode, UExceptionSeverity severity, int level, const char *description)
Definition: UUtils.cc:122
std::ostream & StreamInfo(std::ostream &os) const
Definition: UTubs.cc:1594
double fRMax
Definition: UTubs.hh:176
static const double kPi
Definition: UUtils.hh:49
UVector3 Unit() const
Definition: UVector3.cc:80
double GetOuterRadius() const
std::string UGeometryType
Definition: UTypes.hh:39
double kRadTolerance
Definition: UTubs.hh:172
UTubs()
Definition: UTubs.cc:68
ESide
Definition: UTubs.hh:166
double fCosCPhi
Definition: UTubs.hh:180
double SafetyToPhi(const UVector3 &p, const double rho, bool &outside) const
static const G4double d2
double fSinEPhi
Definition: UTubs.hh:180
double DistanceToIn(const UVector3 &p, const UVector3 &v, double aPstep=UUtils::kInfinity) const
Definition: UTubs.cc:616
double Random(double min=0.0, double max=1.0)
Definition: UUtils.cc:69
double SafetyFromInsideR(const UVector3 &p, const double rho, bool precise=false) const
double fSurfaceArea
Definition: UTubs.hh:163
double fCosHDPhiOT
Definition: UTubs.hh:180