/*
<img src="gif/t_ctorus.gif">
*/
//End_Html
#include "Riostream.h"
#include "TGeoManager.h"
#include "TGeoVolume.h"
#include "TGeoTube.h"
#include "TVirtualGeoPainter.h"
#include "TGeoTorus.h"
#include "TVirtualPad.h"
#include "TBuffer3D.h"
#include "TBuffer3DTypes.h"
#include "TMath.h"
ClassImp(TGeoTorus)
TGeoTorus::TGeoTorus()
{
   SetShapeBit(TGeoShape::kGeoTorus);
   fR    = 0.0;
   fRmin = 0.0;
   fRmax = 0.0;
   fPhi1 = 0.0;
   fDphi = 0.0;
}   
TGeoTorus::TGeoTorus(Double_t r, Double_t rmin, Double_t rmax, Double_t phi1, Double_t dphi)
          :TGeoBBox(0, 0, 0)
{
   SetShapeBit(TGeoShape::kGeoTorus);
   SetTorusDimensions(r, rmin, rmax, phi1, dphi);
   if ((fRmin<0) || (fRmax<0)) 
      SetShapeBit(kGeoRunTimeShape);
   ComputeBBox();
}
TGeoTorus::TGeoTorus(const char *name, Double_t r, Double_t rmin, Double_t rmax, Double_t phi1, Double_t dphi)
          :TGeoBBox(name, 0, 0, 0)
{
   SetShapeBit(TGeoShape::kGeoTorus);
   SetTorusDimensions(r, rmin, rmax, phi1, dphi);
   if ((fRmin<0) || (fRmax<0)) 
      SetShapeBit(kGeoRunTimeShape);
   ComputeBBox();
}
TGeoTorus::TGeoTorus(Double_t *param)
          :TGeoBBox(0, 0, 0)
{
   SetShapeBit(TGeoShape::kGeoTorus);
   SetDimensions(param);
   if (fRmin<0 || fRmax<0) SetShapeBit(kGeoRunTimeShape);
   ComputeBBox();
}
Double_t TGeoTorus::Capacity() const
{
   Double_t capacity = (fDphi/180.)*TMath::Pi()*TMath::Pi()*fR*(fRmax*fRmax-fRmin*fRmin);
   return capacity;
}
   
void TGeoTorus::ComputeBBox()
{
   fDZ = fRmax;
   if (fDphi == 360.) {
      fDX = fDY = fR+fRmax;
      return;
   }
   Double_t xc[4];
   Double_t yc[4];
   xc[0] = (fR+fRmax)*TMath::Cos(fPhi1*TMath::DegToRad());
   yc[0] = (fR+fRmax)*TMath::Sin(fPhi1*TMath::DegToRad());
   xc[1] = (fR+fRmax)*TMath::Cos((fPhi1+fDphi)*TMath::DegToRad());
   yc[1] = (fR+fRmax)*TMath::Sin((fPhi1+fDphi)*TMath::DegToRad());
   xc[2] = (fR-fRmax)*TMath::Cos(fPhi1*TMath::DegToRad());
   yc[2] = (fR-fRmax)*TMath::Sin(fPhi1*TMath::DegToRad());
   xc[3] = (fR-fRmax)*TMath::Cos((fPhi1+fDphi)*TMath::DegToRad());
   yc[3] = (fR-fRmax)*TMath::Sin((fPhi1+fDphi)*TMath::DegToRad());
      
   Double_t xmin = xc[TMath::LocMin(4, &xc[0])];
   Double_t xmax = xc[TMath::LocMax(4, &xc[0])]; 
   Double_t ymin = yc[TMath::LocMin(4, &yc[0])]; 
   Double_t ymax = yc[TMath::LocMax(4, &yc[0])];
   Double_t ddp = -fPhi1;
   if (ddp<0) ddp+= 360;
   if (ddp<=fDphi) xmax = fR+fRmax;
   ddp = 90-fPhi1;
   if (ddp<0) ddp+= 360;
   if (ddp>360) ddp-=360;
   if (ddp<=fDphi) ymax = fR+fRmax;
   ddp = 180-fPhi1;
   if (ddp<0) ddp+= 360;
   if (ddp>360) ddp-=360;
   if (ddp<=fDphi) xmin = -(fR+fRmax);
   ddp = 270-fPhi1;
   if (ddp<0) ddp+= 360;
   if (ddp>360) ddp-=360;
   if (ddp<=fDphi) ymin = -(fR+fRmax);
   fOrigin[0] = (xmax+xmin)/2;
   fOrigin[1] = (ymax+ymin)/2;
   fOrigin[2] = 0;
   fDX = (xmax-xmin)/2;
   fDY = (ymax-ymin)/2;
}
void TGeoTorus::ComputeNormal(Double_t *point, Double_t *dir, Double_t *norm)
{
   Double_t phi = TMath::ATan2(point[1],point[0]);
   if (fDphi<360) {
      Double_t phi1 = fPhi1*TMath::DegToRad();
      Double_t phi2 = (fPhi1+fDphi)*TMath::DegToRad();
      Double_t c1 = TMath::Cos(phi1);
      Double_t s1 = TMath::Sin(phi1);
      Double_t c2 = TMath::Cos(phi2);
      Double_t s2 = TMath::Sin(phi2);
      Double_t daxis = Daxis(point,dir,0);
      if ((fRmax-daxis)>1E-5) {
         if (fRmin==0 || (daxis-fRmin)>1E-5) {
            TGeoShape::NormalPhi(point,dir,norm,c1,s1,c2,s2);
            return;
         }
      }
   }   
   Double_t r0[3];
   r0[0] = fR*TMath::Cos(phi);
   r0[1] = fR*TMath::Sin(phi);           
   r0[2] = 0;
   Double_t normsq = 0;
   for (Int_t i=0; i<3; i++) {
      norm[i] = point[i] - r0[i];
      normsq += norm[i]*norm[i];
   }
   
   normsq = TMath::Sqrt(normsq);
   norm[0] /= normsq;
   norm[1] /= normsq;
   norm[2] /= normsq;
   if (dir[0]*norm[0]+dir[1]*norm[1]+dir[2]*norm[2] < 0) {
      norm[0] = -norm[0];
      norm[1] = -norm[1];
      norm[2] = -norm[2];
   }      
}
Bool_t TGeoTorus::Contains(Double_t *point) const
{
   
   if (fDphi!=360) {
      Double_t phi = TMath::ATan2(point[1], point[0]) * TMath::RadToDeg();
      if (phi < 0) phi+=360.0;
      Double_t ddp = phi-fPhi1;
      if (ddp<0) ddp+=360.;
      if (ddp>fDphi) return kFALSE;
   }
   
   Double_t rxy = TMath::Sqrt(point[0]*point[0]+point[1]*point[1]);
   Double_t radsq = (rxy-fR)*(rxy-fR) + point[2]*point[2];
   if (radsq<fRmin*fRmin) return kFALSE;
   if (radsq>fRmax*fRmax) return kFALSE;
   return kTRUE;
}   
Int_t TGeoTorus::DistancetoPrimitive(Int_t px, Int_t py)
{
   Int_t n = gGeoManager->GetNsegments()+1;
   Int_t numPoints = n*(n-1);
   if (fRmin>0) numPoints *= 2;
   else if (fDphi<360) numPoints += 2;
   return ShapeDistancetoPrimitive(numPoints, px, py);
}
Double_t TGeoTorus::Daxis(Double_t *pt, Double_t *dir, Double_t t) const
{
   Double_t p[3];
   for (Int_t i=0; i<3; i++) p[i] = pt[i]+t*dir[i];
   Double_t rxy = TMath::Sqrt(p[0]*p[0]+p[1]*p[1]);
   return TMath::Sqrt((rxy-fR)*(rxy-fR)+p[2]*p[2]);
}   
Double_t TGeoTorus::DDaxis(Double_t *pt, Double_t *dir, Double_t t) const
{
   Double_t p[3];
   for (Int_t i=0; i<3; i++) p[i] = pt[i]+t*dir[i];
   Double_t rxy = TMath::Sqrt(p[0]*p[0]+p[1]*p[1]);
   if (rxy<1E-4) return ((p[2]*dir[2]-fR*TMath::Sqrt(dir[0]*dir[0]+dir[1]*dir[1]))/TMath::Sqrt(fR*fR+p[2]*p[2]));
   Double_t d = TMath::Sqrt((rxy-fR)*(rxy-fR)+p[2]*p[2]);
   if (d==0) return 0.;
   Double_t dd = (p[0]*dir[0]+p[1]*dir[1]+p[2]*dir[2] - (p[0]*dir[0]+p[1]*dir[1])*fR/rxy)/d;
   return dd;
}   
Double_t TGeoTorus::DDDaxis(Double_t *pt, Double_t *dir, Double_t t) const
{
   Double_t p[3];
   for (Int_t i=0; i<3; i++) p[i] = pt[i]+t*dir[i];
   Double_t rxy = TMath::Sqrt(p[0]*p[0]+p[1]*p[1]);
   if (rxy<1E-6) return 0;
   Double_t daxis = TMath::Sqrt((rxy-fR)*(rxy-fR)+p[2]*p[2]);
   if (daxis==0) return 0;
   Double_t ddaxis = (p[0]*dir[0]+p[1]*dir[1]+p[2]*dir[2] - (p[0]*dir[0]+p[1]*dir[1])*fR/rxy)/daxis;
   Double_t dddaxis = 1 - ddaxis*ddaxis - (1-dir[2]*dir[2])*fR/rxy +
                      fR*(p[0]*dir[0]+p[1]*dir[1])*(p[0]*dir[0]+p[1]*dir[1])/(rxy*rxy*rxy);
   dddaxis /= daxis;
   return dddaxis;
}
   
Double_t TGeoTorus::DistFromInside(Double_t *point, Double_t *dir, Int_t iact, Double_t step, Double_t *safe) const
{
   if (iact<3 && safe) {
      *safe = Safety(point, kTRUE);
      if (iact==0) return TGeoShape::Big();
      if ((iact==1) && (step<=*safe)) return TGeoShape::Big();
   }
   Double_t snext = TGeoShape::Big();
   Bool_t hasphi = (fDphi<360)?kTRUE:kFALSE;
   Bool_t hasrmin = (fRmin>0)?kTRUE:kFALSE;
   Double_t dout = ToBoundary(point,dir,fRmax);
   if (dout>1E10) {
      Double_t pt[3];
      for (Int_t i=0; i<3; i++) pt[i] = point[i]-1E-4*dir[i];
      dout = ToBoundary(pt,dir,fRmax)-1E-4;
      if (dout<1E10) return dout;
      Error("DistFromInside", "cannot get outside");
      printf("point (%f,%f,%f) daxis=%f contains=%i\n", point[0],point[1],point[2],
             Daxis(point,dir,0), Contains(point));
      return TGeoShape::Big();
   }
   Double_t din = (hasrmin)?ToBoundary(point,dir,fRmin):TGeoShape::Big();
   snext = TMath::Min(dout,din);
   Double_t dphi = TGeoShape::Big();
   if (hasphi) {
      
      Double_t c1,s1,c2,s2,cm,sm,cdfi;
      Double_t phi1=fPhi1*TMath::DegToRad();
      Double_t phi2=(fPhi1+fDphi)*TMath::DegToRad();
      c1=TMath::Cos(phi1);
      s1=TMath::Sin(phi1);
      c2=TMath::Cos(phi2);
      s2=TMath::Sin(phi2);
      Double_t fio=0.5*(phi1+phi2);
      cm=TMath::Cos(fio);
      sm=TMath::Sin(fio);
      cdfi = TMath::Cos(0.5*(phi2-phi1));
      dphi = TGeoTubeSeg::DistFromInsideS(point,dir,fR-fRmax,fR+fRmax, fRmax, c1,s1,c2,s2,cm,sm,cdfi);
      if (dphi>1E10) {
         Double_t pt[3];
         for (Int_t i=0; i<3; i++) pt[i] = point[i]-1E-4*dir[i];
         dphi = TGeoTubeSeg::DistFromInsideS(pt,dir,fR-fRmax,fR+fRmax, fRmax, c1,s1,c2,s2,cm,sm,cdfi)-1E-4;
         if (dphi>1E10) {
            Error("DistFromInside", "cannot get outside");
            return TGeoShape::Big();
         }   
      }
      Double_t daxis = Daxis(point,dir,dphi+1E-8);
      if (daxis>=fRmin && daxis<=fRmax) snext=TMath::Min(snext,dphi);
   }      
   return snext;
}
Double_t TGeoTorus::DistFromOutside(Double_t *point, Double_t *dir, Int_t iact, Double_t step, Double_t *safe) const
{
   if (iact<3 && safe) {
      *safe = Safety(point, kFALSE);
      if (iact==0) return TGeoShape::Big();
      if ((iact==1) && (step<=*safe)) return TGeoShape::Big();
   }
   Double_t daxis;
   Bool_t hasphi = (fDphi<360)?kTRUE:kFALSE;
   Double_t c1=0,s1=0,c2=0,s2=0,cm=0,sm=0,cdfi=0;
   Bool_t inphi = kFALSE;
   Double_t phi, ddp, phi1,phi2,fio;
   Double_t rxy2,dd;
   Double_t snext;
   Double_t pt[3];
   Int_t i;
      
   if (hasphi) {
      
      phi=TMath::ATan2(point[1], point[0])*TMath::RadToDeg();;
      if (phi<0) phi+=360;
      ddp = phi-fPhi1;
      if (ddp<0) ddp+=360;;
      if (ddp<=fDphi) inphi=kTRUE;
      phi1=fPhi1*TMath::DegToRad();
      phi2=(fPhi1+fDphi)*TMath::DegToRad();
      c1=TMath::Cos(phi1);
      s1=TMath::Sin(phi1);
      c2=TMath::Cos(phi2);
      s2=TMath::Sin(phi2);
      fio=0.5*(phi1+phi2);
      cm=TMath::Cos(fio);
      sm=TMath::Sin(fio);
      cdfi=TMath::Cos(0.5*(phi2-phi1));
   }
   
   Bool_t inbring = kFALSE;
   if (TMath::Abs(point[2]) <= fRmax) {
      rxy2 = point[0]*point[0]+point[1]*point[1];
      if ((rxy2>=(fR-fRmax)*(fR-fRmax)) && (rxy2<=(fR+fRmax)*(fR+fRmax))) {
         if (!hasphi || inphi) inbring=kTRUE;
      }
   }   
   
   
   Double_t dring = TGeoShape::Big();
   snext = 0;
   daxis = -1;
   memcpy(pt,point,3*sizeof(Double_t));
   if (!inbring) {
      if (hasphi) dring = TGeoTubeSeg::DistFromOutsideS(point,dir,fR-fRmax,fR+fRmax, fRmax, c1,s1,c2,s2,cm,sm,cdfi);            
      else        dring = TGeoTube::DistFromOutsideS(point,dir,fR-fRmax,fR+fRmax, fRmax);
      
      if (dring>1E10) return TGeoShape::Big();
      snext = dring;
      
      daxis = Daxis(point,dir,snext);
      if (daxis>=fRmin && daxis<fRmax) return snext;
      
      for (i=0; i<3; i++) pt[i] = point[i]+snext*dir[i];      
   }
   
   
   if (daxis<0) daxis = Daxis(pt,dir,0);
   if (daxis<fRmin) {
      
      if (snext>0) {
         
         snext += 1E-6;
         for (i=0; i<3; i++) pt[i] += 1E-6*dir[i];
      }
      
      
      dd = ToBoundary(pt,dir, fRmin);
      
      if (hasphi) dring = TGeoTubeSeg::DistFromInsideS(point,dir,fR-fRmin,fR+fRmin, fRmin, c1,s1,c2,s2,cm,sm,cdfi);            
      else        dring = TGeoTube::DistFromInsideS(point,dir,fR-fRmin,fR+fRmin, fRmin);
      if (dd<dring) return (snext+dd);
      
      return TGeoShape::Big();
   }    
   
   
   dd = ToBoundary(pt, dir, fRmax);
   
   if (snext>0) {
      
      snext += 1E-6;
      for (i=0; i<3; i++) pt[i] += 1E-6*dir[i];
   }
   if (hasphi) dring = TGeoTubeSeg::DistFromInsideS(pt,dir,fR-fRmax,fR+fRmax, fRmax, c1,s1,c2,s2,cm,sm,cdfi);            
   else        dring = TGeoTube::DistFromInsideS(pt,dir,fR-fRmax,fR+fRmax, fRmax);
   if (dd<dring) {
      snext += dd;
      return snext;
   }
   
   snext += dring+1E-6;   
   for (i=0; i<3; i++) pt[i] = point[i] + snext*dir[i];
   snext += DistFromOutside(pt,dir,3);
   return snext;
}      
TGeoVolume *TGeoTorus::Divide(TGeoVolume * , const char * , Int_t , Int_t , 
                              Double_t , Double_t ) 
{
   return 0;
}
const char *TGeoTorus::GetAxisName(Int_t iaxis) const
{
   switch (iaxis) {
      case 1:
         return "R";
      case 2:
         return "PHI";
      case 3:
         return "Z";
      default:
         return "UNDEFINED";
   }
}   
   
Double_t TGeoTorus::GetAxisRange(Int_t iaxis, Double_t &xlo, Double_t &xhi) const
{
   xlo = 0;
   xhi = 0;
   Double_t dx = 0;
   switch (iaxis) {
      case 1:
         xlo = fRmin;
         xhi = fRmax;
         dx = xhi-xlo;
         return dx;
      case 2:
         xlo = fPhi1;
         xhi = fPhi1+fDphi;
         dx = fDphi;
         return dx;
      case 3:
         dx = 0;
         return dx;
   }
   return dx;
}         
   
void TGeoTorus::GetBoundingCylinder(Double_t *param) const
{
   param[0] = (fR-fRmax); 
   param[1] = (fR+fRmax); 
   param[2] = fPhi1;    
   param[3] = fPhi1+fDphi;  
}   
 
TGeoShape *TGeoTorus::GetMakeRuntimeShape(TGeoShape * , TGeoMatrix * ) const
{
   if (!TestShapeBit(kGeoRunTimeShape)) return 0;
   Error("GetMakeRuntimeShape", "parametrized toruses not supported");
   return 0;
}
      
void TGeoTorus::InspectShape() const
{
   printf("*** Shape %s: TGeoTorus ***\n", GetName());
   printf("    R    = %11.5f\n", fR);
   printf("    Rmin = %11.5f\n", fRmin);
   printf("    Rmax = %11.5f\n", fRmax);
   printf("    Phi1 = %11.5f\n", fPhi1);
   printf("    Dphi = %11.5f\n", fDphi);
   printf(" Bounding box:\n");
   TGeoBBox::InspectShape();
}
TBuffer3D *TGeoTorus::MakeBuffer3D() const
{ 
   
   
   Int_t n = gGeoManager->GetNsegments()+1;
   Int_t nbPnts = n*(n-1);
   Bool_t hasrmin = (GetRmin()>0)?kTRUE:kFALSE;
   Bool_t hasphi  = (GetDphi()<360)?kTRUE:kFALSE;
   if (hasrmin) nbPnts *= 2;
   else if (hasphi) nbPnts += 2;
   Int_t nbSegs = (2*n-1)*(n-1);
   Int_t nbPols = (n-1)*(n-1);
   if (hasrmin) {
      nbSegs += (2*n-1)*(n-1);
      nbPols += (n-1)*(n-1);
   }
   if (hasphi) {
      nbSegs += 2*(n-1);
      nbPols += 2*(n-1);
   }
   TBuffer3D* buff = new TBuffer3D(TBuffer3DTypes::kGeneric,
                                   nbPnts, 3*nbPnts, nbSegs, 3*nbSegs, nbPols, 6*nbPols);
   if (buff)
   {
      SetPoints(buff->fPnts);   
      SetSegsAndPols(*buff);
   }
   return buff; 
}
void TGeoTorus::SetSegsAndPols(TBuffer3D &buff) const
{
   Int_t i, j;
   Int_t n = gGeoManager->GetNsegments()+1;
   Int_t nbPnts = n*(n-1);
   Int_t indx, indp, startcap=0;
   Bool_t hasrmin = (GetRmin()>0)?kTRUE:kFALSE;
   Bool_t hasphi  = (GetDphi()<360)?kTRUE:kFALSE;
   if (hasrmin) nbPnts *= 2;
   else if (hasphi) nbPnts += 2;
   Int_t c = GetBasicColor();
   indp = n*(n-1); 
   memset(buff.fSegs, 0, buff.NbSegs()*3*sizeof(Int_t));
   
   
   indx = 0;
   for (i = 0; i < n; i++) { 
      for (j = 0; j < n-1; j++) {  
         buff.fSegs[indx+(i*(n-1)+j)*3] = c;
         buff.fSegs[indx+(i*(n-1)+j)*3+1] = i*(n-1)+j;   
         buff.fSegs[indx+(i*(n-1)+j)*3+2] = i*(n-1)+((j+1)%(n-1)); 
      }
   }
   indx += 3*n*(n-1);
   
   
   for (i = 0; i < n-1; i++) { 
      for (j = 0; j < n-1; j++) {  
         buff.fSegs[indx+(i*(n-1)+j)*3] = c;
         buff.fSegs[indx+(i*(n-1)+j)*3+1] = i*(n-1)+j;     
         buff.fSegs[indx+(i*(n-1)+j)*3+2] = (i+1)*(n-1)+j; 
      }
   }
   indx += 3*(n-1)*(n-1);
   startcap = (2*n-1)*(n-1);
   if (hasrmin) {
      
      
      for (i = 0; i < n; i++) { 
         for (j = 0; j < n-1; j++) {  
            buff.fSegs[indx+(i*(n-1)+j)*3] = c;              
            buff.fSegs[indx+(i*(n-1)+j)*3+1] = indp + i*(n-1)+j;   
            buff.fSegs[indx+(i*(n-1)+j)*3+2] = indp + i*(n-1)+((j+1)%(n-1)); 
         }
      }
      indx += 3*n*(n-1);
      
      
      for (i = 0; i < n-1; i++) { 
         for (j = 0; j < n-1; j++) {  
            buff.fSegs[indx+(i*(n-1)+j)*3] = c;                
            buff.fSegs[indx+(i*(n-1)+j)*3+1] = indp + i*(n-1)+j;     
            buff.fSegs[indx+(i*(n-1)+j)*3+2] = indp + (i+1)*(n-1)+j; 
         }
      }
      indx += 3*(n-1)*(n-1);
      startcap = (4*n-2)*(n-1);
   }
   if (hasphi) {
      if (hasrmin) {
         
         i = 0;
         for (j = 0; j < n-1; j++) {
            buff.fSegs[indx+j*3] = c+1;
            buff.fSegs[indx+j*3+1] = (n-1)*i+j;     
            buff.fSegs[indx+j*3+2] = indp+(n-1)*i+j; 
         }
         indx += 3*(n-1);
         i = n-1;
         for (j = 0; j < n-1; j++) {
            buff.fSegs[indx+j*3] = c+1;
            buff.fSegs[indx+j*3+1] = (n-1)*i+j;     
            buff.fSegs[indx+j*3+2] = indp+(n-1)*i+j; 
         }
         indx += 3*(n-1);
      } else {
         i = 0;
         for (j = 0; j < n-1; j++) {
            buff.fSegs[indx+j*3] = c+1;
            buff.fSegs[indx+j*3+1] = (n-1)*i+j;     
            buff.fSegs[indx+j*3+2] = n*(n-1);       
         }
         indx += 3*(n-1);
         i = n-1;
         for (j = 0; j < n-1; j++) {
            buff.fSegs[indx+j*3] = c+1;
            buff.fSegs[indx+j*3+1] = (n-1)*i+j;     
            buff.fSegs[indx+j*3+2] = n*(n-1)+1;     
         }
         indx += 3*(n-1);
      }
   }
   indx = 0;
   memset(buff.fPols, 0, buff.NbPols()*6*sizeof(Int_t));
   
   
   for (i=0; i<n-1; i++) {
      for (j=0; j<n-1; j++) {
         buff.fPols[indx++] = c;
         buff.fPols[indx++] = 4;
         buff.fPols[indx++] = n*(n-1)+(n-1)*i+((j+1)%(n-1)); 
         buff.fPols[indx++] = (n-1)*(i+1)+j; 
         buff.fPols[indx++] = n*(n-1)+(n-1)*i+j; 
         buff.fPols[indx++] = (n-1)*i+j; 
      }
   }
   if (hasrmin) {
      indp = (2*n-1)*(n-1); 
      
      
      for (i=0; i<n-1; i++) {
         for (j=0; j<n-1; j++) {
            buff.fPols[indx++] = c;
            buff.fPols[indx++] = 4;
            buff.fPols[indx++] = indp+n*(n-1)+(n-1)*i+j; 
            buff.fPols[indx++] = indp+(n-1)*(i+1)+j; 
            buff.fPols[indx++] = indp+n*(n-1)+(n-1)*i+((j+1)%(n-1)); 
            buff.fPols[indx++] = indp+(n-1)*i+j; 
         }
      }
   }
   if (hasphi) {
      
      i=0; 
      Int_t np = (hasrmin)?4:3;
      for (j=0; j<n-1; j++) {
         buff.fPols[indx++] = c+1;
         buff.fPols[indx++] = np;
         buff.fPols[indx++] = j;         
         buff.fPols[indx++] = startcap+j;        
         if(hasrmin)
            buff.fPols[indx++] = indp+j; 
         buff.fPols[indx++] = startcap+((j+1)%(n-1)); 
      }
      i=n-1; 
      for (j=0; j<n-1; j++) {
         buff.fPols[indx++] = c+1;
         buff.fPols[indx++] = np;
         buff.fPols[indx++] = (n-1)*i+j;         
         buff.fPols[indx++] = startcap+(n-1)+((j+1)%(n-1));    
         if (hasrmin)
            buff.fPols[indx++] = indp+(n-1)*i+j; 
         buff.fPols[indx++] = startcap+(n-1)+j;      
      }
   }
}
Double_t TGeoTorus::Safety(Double_t *point, Bool_t in) const
{
   Double_t saf[2];
   Int_t i;
   Double_t rxy = TMath::Sqrt(point[0]*point[0]+point[1]*point[1]);
   Double_t rad = TMath::Sqrt((rxy-fR)*(rxy-fR) + point[2]*point[2]);
   saf[0] = rad-fRmin;
   saf[1] = fRmax-rad;
   if (fDphi==360) {
      if (in) return TMath::Min(saf[0],saf[1]);
      for (i=0; i<2; i++) saf[i]=-saf[i];
      return TMath::Max(saf[0], saf[1]);
   }   
   Double_t safphi = TGeoShape::SafetyPhi(point,in,fPhi1, fPhi1+fDphi);
   Double_t safe = TGeoShape::Big();
   if (in) {
      safe = TMath::Min(saf[0], saf[1]);
      return TMath::Min(safe, safphi);
   }   
   for (i=0; i<2; i++) saf[i]=-saf[i];
   safe = TMath::Max(saf[0], saf[1]);
   return TMath::Max(safe, safphi);
}
void TGeoTorus::SavePrimitive(ostream &out, Option_t *  )
{
   if (TObject::TestBit(kGeoSavePrimitive)) return;  
   out << "   // Shape: " << GetName() << " type: " << ClassName() << endl;
   out << "   r    = " << fR << ";" << endl;
   out << "   rmin = " << fRmin << ";" << endl;
   out << "   rmax = " << fRmax << ";" << endl;
   out << "   phi1 = " << fPhi1 << ";" << endl;
   out << "   dphi = " << fDphi << ";" << endl;
   out << "   TGeoShape *" << GetPointerName() << " = new TGeoTorus(\"" << GetName() << "\",r,rmin,rmax,phi1,dphi);" << endl;
   TObject::SetBit(TGeoShape::kGeoSavePrimitive);
}
void TGeoTorus::SetTorusDimensions(Double_t r, Double_t rmin, Double_t rmax,
                          Double_t phi1, Double_t dphi)
{
   fR = r;
   fRmin = rmin;
   fRmax = rmax;
   fPhi1 = phi1;
   if (fPhi1<0) fPhi1+=360.;
   fDphi = dphi;
}
void TGeoTorus::SetDimensions(Double_t *param)
{
   SetTorusDimensions(param[0], param[1], param[2], param[3], param[4]);
}
void TGeoTorus::SetPoints(Double_t *points) const
{
   if (!points) return;
   Int_t n = gGeoManager->GetNsegments()+1;
   Double_t phin, phout;
   Double_t dpin = 360./(n-1);
   Double_t dpout = fDphi/(n-1);
   Double_t co,so,ci,si;
   Bool_t havermin = (fRmin<TGeoShape::Tolerance())?kFALSE:kTRUE;
   Int_t i,j;
   Int_t indx = 0;
   
   for (i=0; i<n; i++) {
      phout = (fPhi1+i*dpout)*TMath::DegToRad();
      co = TMath::Cos(phout);
      so = TMath::Sin(phout);
      for (j=0; j<n-1; j++) {
         phin = j*dpin*TMath::DegToRad();
         ci = TMath::Cos(phin);
         si = TMath::Sin(phin);
         points[indx++] = (fR+fRmax*ci)*co;
         points[indx++] = (fR+fRmax*ci)*so;
         points[indx++] = fRmax*si;
      }
   }     
    
   if (havermin) {
    
      for (i=0; i<n; i++) {
         phout = (fPhi1+i*dpout)*TMath::DegToRad();
         co = TMath::Cos(phout);
         so = TMath::Sin(phout);
         for (j=0; j<n-1; j++) {
            phin = j*dpin*TMath::DegToRad();
            ci = TMath::Cos(phin);
            si = TMath::Sin(phin);
            points[indx++] = (fR+fRmin*ci)*co;
            points[indx++] = (fR+fRmin*ci)*so;
            points[indx++] = fRmin*si;
         }
      }  
   } else {
      if (fDphi<360.) {
      
         points[indx++] = fR*TMath::Cos(fPhi1*TMath::DegToRad());
         points[indx++] = fR*TMath::Sin(fPhi1*TMath::DegToRad());
         points[indx++] = 0;
         points[indx++] = fR*TMath::Cos((fPhi1+fDphi)*TMath::DegToRad());
         points[indx++] = fR*TMath::Sin((fPhi1+fDphi)*TMath::DegToRad());
         points[indx++] = 0;
      }
   }      
}        
void TGeoTorus::SetPoints(Float_t *points) const
{
   if (!points) return;
   Int_t n = gGeoManager->GetNsegments()+1;
   Double_t phin, phout;
   Double_t dpin = 360./(n-1);
   Double_t dpout = fDphi/(n-1);
   Double_t co,so,ci,si;
   Bool_t havermin = (fRmin<TGeoShape::Tolerance())?kFALSE:kTRUE;
   Int_t i,j;
   Int_t indx = 0;
   
   
   for (i=0; i<n; i++) {
      phout = (fPhi1+i*dpout)*TMath::DegToRad();
      co = TMath::Cos(phout);
      so = TMath::Sin(phout);
      for (j=0; j<n-1; j++) {
         phin = j*dpin*TMath::DegToRad();
         ci = TMath::Cos(phin);
         si = TMath::Sin(phin);
         points[indx++] = (fR+fRmax*ci)*co;
         points[indx++] = (fR+fRmax*ci)*so;
         points[indx++] = fRmax*si;
      }
   }     
    
   if (havermin) {
    
      
      for (i=0; i<n; i++) {
         phout = (fPhi1+i*dpout)*TMath::DegToRad();
         co = TMath::Cos(phout);
         so = TMath::Sin(phout);
         for (j=0; j<n-1; j++) {
            phin = j*dpin*TMath::DegToRad();
            ci = TMath::Cos(phin);
            si = TMath::Sin(phin);
            points[indx++] = (fR+fRmin*ci)*co;
            points[indx++] = (fR+fRmin*ci)*so;
            points[indx++] = fRmin*si;
         }
      }  
   } else {
      if (fDphi<360.) {
      
      
      
         points[indx++] = fR*TMath::Cos(fPhi1*TMath::DegToRad());
         points[indx++] = fR*TMath::Sin(fPhi1*TMath::DegToRad());
         points[indx++] = 0;
         points[indx++] = fR*TMath::Cos((fPhi1+fDphi)*TMath::DegToRad());
         points[indx++] = fR*TMath::Sin((fPhi1+fDphi)*TMath::DegToRad());
         points[indx++] = 0;
      }
   }      
}        
Int_t TGeoTorus::GetNmeshVertices() const
{
   Int_t n = gGeoManager->GetNsegments()+1;
   Int_t numPoints = n*(n-1);
   if (fRmin>TGeoShape::Tolerance()) numPoints *= 2;
   else if (fDphi<360.)              numPoints += 2;
   return numPoints;
}
void TGeoTorus::Sizeof3D() const
{
}
Int_t TGeoTorus::SolveCubic(Double_t a, Double_t b, Double_t c, Double_t *x) const
{
   const Double_t ott = 1./3.;
   const Double_t sq3 = TMath::Sqrt(3.);
   Int_t ireal = 1;
   Double_t p = b-a*a*ott;
   Double_t q = c-a*b*ott+2.*a*a*a*ott*ott*ott;
   Double_t delta = 4*p*p*p+27*q*q;
   Double_t t,u;
   if (delta>=0) {
      delta = TMath::Sqrt(delta);
      t = (-3*q*sq3+delta)/(6*sq3);
      u = (3*q*sq3+delta)/(6*sq3);
      x[0] = TMath::Sign(1.,t)*TMath::Power(TMath::Abs(t),ott)-
             TMath::Sign(1.,u)*TMath::Power(TMath::Abs(u),ott)-a*ott;
   } else {
      delta = TMath::Sqrt(-delta);
      t = -0.5*q;
      u = delta/(6*sq3);
      x[0] = 2.*TMath::Power(t*t+u*u,0.5*ott) * TMath::Cos(ott*TMath::ATan2(u,t));
      x[0] -= a*ott;
   }   
         
   t = x[0]*x[0]+a*x[0]+b;
   u = a+x[0];
   delta = u*u-4.*t;
   if (delta>=0) {
      ireal = 3;
      delta = TMath::Sqrt(delta);
      x[1] = 0.5*(-u-delta);
      x[2] = 0.5*(-u+delta);
   }
   return ireal;
}
Int_t TGeoTorus::SolveQuartic(Double_t a, Double_t b, Double_t c, Double_t d, Double_t *x) const
{
   Double_t e = b-3.*a*a/8.;
   Double_t f = c+a*a*a/8.-0.5*a*b;
   Double_t g = d-3.*a*a*a*a/256. + a*a*b/16. - a*c/4.;
   Double_t xx[3];
   Int_t    ind[4];
   Double_t delta;
   Double_t h=0;
   Int_t ireal = 0;
   Int_t i;
   if (f==0) {
      delta = e*e-4.*g;
      if (delta<0) return 0;
      delta = TMath::Sqrt(delta);
      h = 0.5*(-e-delta);
      if (h>=0) {
         h = TMath::Sqrt(h);
         x[ireal++] = -h-0.25*a;
         x[ireal++] = h-0.25*a;
      }
      h = 0.5*(-e+delta);
      if (h>=0) {
         h = TMath::Sqrt(h);
         x[ireal++] = -h-0.25*a;
         x[ireal++] = h-0.25*a;
      }
      if (ireal>0) {
         TMath::Sort(ireal, x, ind,kFALSE);
         for (i=0; i<ireal; i++) xx[i] = x[ind[i]];
         memcpy(x,xx,ireal*sizeof(Double_t));
      }
      return ireal; 
   }     
   
   if (g==0) {
      x[ireal++] = -0.25*a;
      ind[0] = SolveCubic(0,e,f,xx);
      for (i=0; i<ind[0]; i++) x[ireal++] = xx[i]-0.25*a;      
      if (ireal>0) {
         TMath::Sort(ireal, x, ind,kFALSE);
         for (i=0; i<ireal; i++) xx[i] = x[ind[i]];
         memcpy(x,xx,ireal*sizeof(Double_t));
      }
      return ireal;
   }    
      
      
   ireal = SolveCubic(2.*e, e*e-4.*g, -f*f, xx);
   if (ireal==1) {
      if (xx[0]<=0) return 0;
      h = TMath::Sqrt(xx[0]);   
   } else {
      
      for (Int_t i=0; i<3; i++) {
         h = xx[i];
         if (h>=0) break;
      }
      if (h<=0) return 0;
      h = TMath::Sqrt(h);
   }
   Double_t j = 0.5*(e+h*h-f/h);      
   ireal = 0;
   delta = h*h-4.*j;
   if (delta>=0) {
      delta = TMath::Sqrt(delta);
      x[ireal++] = 0.5*(-h-delta)-0.25*a;
      x[ireal++] = 0.5*(-h+delta)-0.25*a;
   }
   delta = h*h-4.*g/j;
   if (delta>=0) {
      delta = TMath::Sqrt(delta);
      x[ireal++] = 0.5*(h-delta)-0.25*a;
      x[ireal++] = 0.5*(h+delta)-0.25*a;
   }
   if (ireal>0) {
      TMath::Sort(ireal, x, ind,kFALSE);
      for (i=0; i<ireal; i++) xx[i] = x[ind[i]];
      memcpy(x,xx,ireal*sizeof(Double_t));
   }
   return ireal;
}
Double_t TGeoTorus::ToBoundary(Double_t *pt, Double_t *dir, Double_t r) const
{
   
   
   Double_t r0sq  = pt[0]*pt[0]+pt[1]*pt[1]+pt[2]*pt[2];
   Double_t rdotn = pt[0]*dir[0]+pt[1]*dir[1]+pt[2]*dir[2];
   Double_t rsumsq = fR*fR+r*r;
   Double_t a = 4.*rdotn;
   Double_t b = 2.*(r0sq+2.*rdotn*rdotn-rsumsq+2.*fR*fR*dir[2]*dir[2]);
   Double_t c = 4.*(r0sq*rdotn-rsumsq*rdotn+2.*fR*fR*pt[2]*dir[2]);
   Double_t d = r0sq*r0sq-2.*r0sq*rsumsq+4.*fR*fR*pt[2]*pt[2]+(fR*fR-r*r)*(fR*fR-r*r);
   
   Double_t x[4];
   Int_t nsol = SolveQuartic(a,b,c,d,x);
   if (!nsol) return TGeoShape::Big();
   
   for (Int_t i=0; i<nsol; i++) {
      if (x[i]>=0) return x[i];
   }
   return TGeoShape::Big();   
}      
void TGeoTorus::GetMeshNumbers(Int_t &nvert, Int_t &nsegs, Int_t &npols) const
{
   Int_t n = gGeoManager->GetNsegments()+1;
   nvert = n*(n-1);
   Bool_t hasrmin = (GetRmin()>0)?kTRUE:kFALSE;
   Bool_t hasphi  = (GetDphi()<360)?kTRUE:kFALSE;
   if (hasrmin) nvert *= 2;
   else if (hasphi) nvert += 2;
   nsegs = (2*n-1)*(n-1);
   npols = (n-1)*(n-1);
   if (hasrmin) {
      nsegs += (2*n-1)*(n-1);
      npols += (n-1)*(n-1);
   }
   if (hasphi) {
      nsegs += 2*(n-1);
      npols += 2*(n-1);
   }
}
const TBuffer3D & TGeoTorus::GetBuffer3D(Int_t reqSections, Bool_t localFrame) const
{
   static TBuffer3D buffer(TBuffer3DTypes::kGeneric);
   TGeoBBox::FillBuffer3D(buffer, reqSections, localFrame);
   if (reqSections & TBuffer3D::kRawSizes) {
      Int_t n = gGeoManager->GetNsegments()+1;
      Int_t nbPnts = n*(n-1);
      Bool_t hasrmin = (GetRmin()>0)?kTRUE:kFALSE;
      Bool_t hasphi  = (GetDphi()<360)?kTRUE:kFALSE;
      if (hasrmin) nbPnts *= 2;
      else if (hasphi) nbPnts += 2;
      Int_t nbSegs = (2*n-1)*(n-1);
      Int_t nbPols = (n-1)*(n-1);
      if (hasrmin) {
         nbSegs += (2*n-1)*(n-1);
         nbPols += (n-1)*(n-1);
      }
      if (hasphi) {
         nbSegs += 2*(n-1);
         nbPols += 2*(n-1);
      }
      if (buffer.SetRawSizes(nbPnts, 3*nbPnts, nbSegs, 3*nbSegs, nbPols, 6*nbPols)) {
         buffer.SetSectionsValid(TBuffer3D::kRawSizes);
      }
   }
   
   
   if ((reqSections & TBuffer3D::kRaw) && buffer.SectionsValid(TBuffer3D::kRawSizes)) {
      SetPoints(buffer.fPnts);
      if (!buffer.fLocalFrame) {
         TransformPoints(buffer.fPnts, buffer.NbPnts());
      }
      SetSegsAndPols(buffer);      
      buffer.SetSectionsValid(TBuffer3D::kRaw);
   }
      
   return buffer;
}
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.