2 // ********************************************************************
3 // * This Software is part of the AIDA Unified Solids Library package *
4 // * See: https://aidasoft.web.cern.ch/USolids *
5 // ********************************************************************
9 // --------------------------------------------------------------------
13 // Implementation of inline methods of UCons
15 // 19.10.12 Marek Gayer
16 // Created from original implementation in Geant4
17 // --------------------------------------------------------------------
20 double UCons::GetInnerRadiusMinusZ() const
26 double UCons::GetOuterRadiusMinusZ() const
32 double UCons::GetInnerRadiusPlusZ() const
38 double UCons::GetOuterRadiusPlusZ() const
44 double UCons::GetZHalfLength() const
50 double UCons::GetStartPhiAngle() const
56 double UCons::GetDeltaPhiAngle() const
62 void UCons::Initialize()
67 tanRMin = (fRmin2 - fRmin1) * 0.5 / fDz;
68 secRMin = std::sqrt(1.0 + tanRMin * tanRMin);
70 tanRMax = (fRmax2 - fRmax1) * 0.5 / fDz;
71 secRMax = std::sqrt(1.0 + tanRMax * tanRMax);
75 void UCons::InitializeTrigonometry()
77 double hDPhi = 0.5 * fDPhi; // half delta phi
78 double cPhi = fSPhi + hDPhi;
79 double ePhi = fSPhi + fDPhi;
81 sinCPhi = std::sin(cPhi);
82 cosCPhi = std::cos(cPhi);
83 cosHDPhiIT = std::cos(hDPhi - 0.5 * kAngTolerance); // inner/outer tol half dphi
84 cosHDPhiOT = std::cos(hDPhi + 0.5 * kAngTolerance);
85 sinSPhi = std::sin(fSPhi);
86 cosSPhi = std::cos(fSPhi);
87 sinEPhi = std::sin(ePhi);
88 cosEPhi = std::cos(ePhi);
91 inline void UCons::CheckSPhiAngle(double sPhi)
93 // Ensure fSphi in 0-2PI or -2PI-0 range if shape crosses 0
97 fSPhi = 2 * UUtils::kPi - std::fmod(std::fabs(sPhi), 2 * UUtils::kPi);
101 fSPhi = std::fmod(sPhi, 2 * UUtils::kPi) ;
103 if (fSPhi + fDPhi > 2 * UUtils::kPi)
105 fSPhi -= 2 * UUtils::kPi ;
109 inline void UCons::CheckPhiAngles(double sPhi, double dPhi)
111 CheckDPhiAngle(dPhi);
112 if ((fDPhi < 2 * UUtils::kPi) && (sPhi))
114 CheckSPhiAngle(sPhi);
116 InitializeTrigonometry();
120 void UCons::SetInnerRadiusMinusZ(double Rmin1)
127 void UCons::SetOuterRadiusMinusZ(double Rmax1)
134 void UCons::SetInnerRadiusPlusZ(double Rmin2)
141 void UCons::SetOuterRadiusPlusZ(double Rmax2)
148 void UCons::SetZHalfLength(double newDz)
155 void UCons::SetStartPhiAngle(double newSPhi, bool compute)
157 // Flag 'compute' can be used to explicitely avoid recomputation of
158 // trigonometry in case SetDeltaPhiAngle() is invoked afterwards
160 CheckSPhiAngle(newSPhi);
161 fPhiFullCone = false;
164 InitializeTrigonometry();
169 void UCons::SetDeltaPhiAngle(double newDPhi)
171 CheckPhiAngles(fSPhi, newDPhi);
175 // Old access methods ...
178 double UCons::GetRmin1() const
180 return GetInnerRadiusMinusZ();
184 double UCons::GetRmax1() const
186 return GetOuterRadiusMinusZ();
190 double UCons::GetRmin2() const
192 return GetInnerRadiusPlusZ();
196 double UCons::GetRmax2() const
198 return GetOuterRadiusPlusZ();
202 double UCons::GetDz() const
204 return GetZHalfLength();
208 double UCons::GetSPhi() const
210 return GetStartPhiAngle();
214 double UCons::GetDPhi() const
216 return GetDeltaPhiAngle();
220 double UCons::Capacity()
222 if (fCubicVolume != 0.)
228 double Rmean, rMean, deltaR, deltar;
230 Rmean = 0.5 * (fRmax1 + fRmax2);
231 deltaR = fRmax1 - fRmax2;
233 rMean = 0.5 * (fRmin1 + fRmin2);
234 deltar = fRmin1 - fRmin2;
235 fCubicVolume = fDPhi * fDz * (Rmean * Rmean - rMean * rMean
236 + (deltaR * deltaR - deltar * deltar) / 12);
242 double UCons::SurfaceArea()
244 if (fSurfaceArea != 0.)
250 double mmin, mmax, dmin, dmax;
252 mmin = (fRmin1 + fRmin2) * 0.5;
253 mmax = (fRmax1 + fRmax2) * 0.5;
254 dmin = (fRmin2 - fRmin1);
255 dmax = (fRmax2 - fRmax1);
257 fSurfaceArea = fDPhi * (mmin * std::sqrt(dmin * dmin + 4 * fDz * fDz)
258 + mmax * std::sqrt(dmax * dmax + 4 * fDz * fDz)
259 + 0.5 * (fRmax1 * fRmax1 - fRmin1 * fRmin1
260 + fRmax2 * fRmax2 - fRmin2 * fRmin2));
263 fSurfaceArea = fSurfaceArea + 4 * fDz * (mmax - mmin);
270 double UCons::SafetyToPhi(const UVector3& p,
271 const double rho, bool& outside) const
273 double cosPsi, safePhi = 0.0;
276 cosPsi = (p.x() * cosCPhi + p.y() * sinCPhi) / rho;
278 if (cosPsi < std::cos(fDPhi * 0.5)) // Point lies outside phi range
281 if ((p.y() * cosCPhi - p.x() * sinCPhi) <= 0.0)
283 safePhi = std::fabs(p.x() * std::sin(fSPhi) - p.y() * std::cos(fSPhi));
287 safePhi = std::fabs(p.x() * sinEPhi - p.y() * cosEPhi);
294 double UCons::SafetyFromInsideR(const UVector3& p,
295 const double rho, bool) const
297 double safe = 0.0, safeR1, safeR2, safePhi;
301 if (fRmin1 || fRmin2)
303 pRMin = tanRMin * p.z() + (fRmin1 + fRmin2) * 0.5;
304 safeR1 = (rho - pRMin) / secRMin;
308 safeR1 = UUtils::kInfinity;
311 pRMax = tanRMax * p.z() + (fRmax1 + fRmax2) * 0.5;
312 safeR2 = (pRMax - rho) / secRMax;
323 // Check if phi divided, Calc distances closest phi plane
327 // Above/below central phi of UCons?
329 if ((p.y() * cosCPhi - p.x() * sinCPhi) <= 0)
331 safePhi = -(p.x() * sinSPhi - p.y() * cosSPhi);
335 safePhi = (p.x() * sinEPhi - p.y() * cosEPhi);
352 double UCons::SafetyFromOutsideR(const UVector3& p,
353 const double rho, bool) const
355 double safe = 0.0, safeR1, safeR2;
359 if (fRmin1 || fRmin2)
361 pRMin = tanRMin * p.z() + (fRmin1 + fRmin2) * 0.5;
362 safeR1 = (rho-pRMin ) / secRMin;
364 pRMax = tanRMax * p.z() + (fRmax1 + fRmax2) * 0.5;
365 safeR2 = (rho - pRMax) / secRMax;
378 pRMax = tanRMax * p.z() + (fRmax1 + fRmax2) * 0.5;
379 safe = (rho - pRMax) / secRMax;
383 safePhi=SafetyToPhi(p,rho,outside);
384 if ((outside) && (safePhi > safe))
394 return safe; // not accurate safety
398 VUSolid::EnumInside UCons::Inside(const UVector3& p) const
400 double r2, rl, rh, pPhi, tolRMin, tolRMax; // rh2, rl2;
401 VUSolid::EnumInside in;
402 static const double halfCarTolerance = VUSolid::Tolerance() * 0.5;
403 static const double halfRadTolerance = kRadTolerance * 0.5;
404 static const double halfAngTolerance = kAngTolerance * 0.5;
406 if (std::fabs(p.z()) > fDz + halfCarTolerance)
408 return in = eOutside;
410 else if (std::fabs(p.z()) >= fDz - halfCarTolerance)
418 r2 = p.x() * p.x() + p.y() * p.y();
419 rl = 0.5 * (fRmin2 * (p.z() + fDz) + fRmin1 * (fDz - p.z())) / fDz;
420 rh = 0.5 * (fRmax2 * (p.z() + fDz) + fRmax1 * (fDz - p.z())) / fDz;
422 tolRMin = rl - halfRadTolerance;
427 tolRMax = rh + halfRadTolerance;
429 if ((r2 < tolRMin * tolRMin) || (r2 > tolRMax * tolRMax))
431 return in = eOutside;
435 tolRMin = rl + halfRadTolerance;
442 tolRMax = rh - halfRadTolerance;
443 if (in == eInside) // else it's eSurface already
445 if ((r2 < tolRMin * tolRMin) || (r2 >= tolRMax * tolRMax))
450 if (!fPhiFullCone && ((p.x() != 0.0) || (p.y() != 0.0)))
452 pPhi = std::atan2(p.y(), p.x());
453 if (pPhi < fSPhi - halfAngTolerance)
455 pPhi += 2 * UUtils::kPi;
457 else if (pPhi > fSPhi + fDPhi + halfAngTolerance)
459 pPhi -= 2 * UUtils::kPi;
462 if ((pPhi < fSPhi - halfAngTolerance) ||
463 (pPhi > fSPhi + fDPhi + halfAngTolerance))
465 return in = eOutside;
467 else if (in == eInside) // else it's eSurface anyway already
469 if ((pPhi < fSPhi + halfAngTolerance) ||
470 (pPhi > fSPhi + fDPhi - halfAngTolerance))
476 else if (!fPhiFullCone)