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)