TGeoSphere.cxx

Go to the documentation of this file.
00001 // @(#)root/geom:$Id: TGeoSphere.cxx 33479 2010-05-12 11:57:34Z agheata $
00002 // Author: Andrei Gheata   31/01/02
00003 // TGeoSphere::Contains() DistFromOutside/Out() implemented by Mihaela Gheata
00004 
00005 /*************************************************************************
00006  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
00007  * All rights reserved.                                                  *
00008  *                                                                       *
00009  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00010  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00011  *************************************************************************/
00012 
00013 //_____________________________________________________________________________
00014 // TGeoSphere - spherical shell class. It takes 6 parameters : 
00015 //           - inner and outer radius Rmin, Rmax
00016 //           - the theta limits Tmin, Tmax
00017 //           - the phi limits Pmin, Pmax (the sector in phi is considered
00018 //             starting from Pmin to Pmax counter-clockwise
00019 //
00020 //_____________________________________________________________________________
00021 //Begin_Html
00022 /*
00023 <img src="gif/t_sphere.gif">
00024 */
00025 //End_Html
00026 
00027 #include "Riostream.h"
00028 
00029 #include "TGeoCone.h"
00030 #include "TGeoManager.h"
00031 #include "TGeoVolume.h"
00032 #include "TVirtualGeoPainter.h"
00033 #include "TGeoSphere.h"
00034 #include "TVirtualPad.h"
00035 #include "TBuffer3D.h"
00036 #include "TBuffer3DTypes.h"
00037 #include "TMath.h"
00038 
00039 ClassImp(TGeoSphere)
00040    
00041 //_____________________________________________________________________________
00042 TGeoSphere::TGeoSphere()
00043 {
00044 // Default constructor
00045    SetShapeBit(TGeoShape::kGeoSph);
00046    fNz = 0;
00047    fNseg = 0;
00048    fRmin = 0.0;
00049    fRmax = 0.0;
00050    fTheta1 = 0.0;
00051    fTheta2 = 180.0;
00052    fPhi1 = 0.0;
00053    fPhi2 = 360.0;
00054 }   
00055 
00056 //_____________________________________________________________________________
00057 TGeoSphere::TGeoSphere(Double_t rmin, Double_t rmax, Double_t theta1,
00058                        Double_t theta2, Double_t phi1, Double_t phi2)
00059            :TGeoBBox(0, 0, 0)
00060 {
00061 // Default constructor specifying minimum and maximum radius
00062    SetShapeBit(TGeoShape::kGeoSph);
00063    SetSphDimensions(rmin, rmax, theta1, theta2, phi1, phi2);
00064    ComputeBBox();
00065    SetNumberOfDivisions(20);
00066 }
00067 
00068 //_____________________________________________________________________________
00069 TGeoSphere::TGeoSphere(const char *name, Double_t rmin, Double_t rmax, Double_t theta1,
00070                        Double_t theta2, Double_t phi1, Double_t phi2)
00071            :TGeoBBox(name, 0, 0, 0)
00072 {
00073 // Default constructor specifying minimum and maximum radius
00074    SetShapeBit(TGeoShape::kGeoSph);
00075    SetSphDimensions(rmin, rmax, theta1, theta2, phi1, phi2);
00076    ComputeBBox();
00077    SetNumberOfDivisions(20);
00078 }
00079 
00080 //_____________________________________________________________________________
00081 TGeoSphere::TGeoSphere(Double_t *param, Int_t /*nparam*/)
00082            :TGeoBBox(0, 0, 0)
00083 {
00084 // Default constructor specifying minimum and maximum radius
00085 // param[0] = Rmin
00086 // param[1] = Rmax
00087    SetShapeBit(TGeoShape::kGeoSph);
00088    SetDimensions(param);
00089    ComputeBBox();
00090    SetNumberOfDivisions(20);
00091 }
00092 
00093 //_____________________________________________________________________________
00094 TGeoSphere::~TGeoSphere()
00095 {
00096 // destructor
00097 }
00098 
00099 //_____________________________________________________________________________
00100 Double_t TGeoSphere::Capacity() const
00101 {
00102 // Computes capacity of the shape in [length^3]
00103    Double_t th1 = fTheta1*TMath::DegToRad();
00104    Double_t th2 = fTheta2*TMath::DegToRad();
00105    Double_t ph1 = fPhi1*TMath::DegToRad();
00106    Double_t ph2 = fPhi2*TMath::DegToRad();
00107    Double_t capacity = (1./3.)*(fRmax*fRmax*fRmax-fRmin*fRmin*fRmin)*
00108                        TMath::Abs(TMath::Cos(th1)-TMath::Cos(th2))*
00109                        TMath::Abs(ph2-ph1);
00110    return capacity;
00111 }                       
00112 
00113 //_____________________________________________________________________________   
00114 void TGeoSphere::ComputeBBox()
00115 {
00116 // compute bounding box of the sphere
00117 //   Double_t xmin, xmax, ymin, ymax, zmin, zmax;
00118    if (TGeoShape::IsSameWithinTolerance(TMath::Abs(fTheta2-fTheta1),180)) {
00119       if (TGeoShape::IsSameWithinTolerance(TMath::Abs(fPhi2-fPhi1),360)) {
00120          TGeoBBox::SetBoxDimensions(fRmax, fRmax, fRmax);
00121          memset(fOrigin, 0, 3*sizeof(Double_t));
00122          return;
00123       }
00124    }   
00125    Double_t st1 = TMath::Sin(fTheta1*TMath::DegToRad());
00126    Double_t st2 = TMath::Sin(fTheta2*TMath::DegToRad());
00127    Double_t r1min, r1max, r2min, r2max, rmin, rmax;
00128    r1min = TMath::Min(fRmax*st1, fRmax*st2);
00129    r1max = TMath::Max(fRmax*st1, fRmax*st2);
00130    r2min = TMath::Min(fRmin*st1, fRmin*st2);
00131    r2max = TMath::Max(fRmin*st1, fRmin*st2);
00132    if (((fTheta1<=90) && (fTheta2>=90)) || ((fTheta2<=90) && (fTheta1>=90))) {
00133       r1max = fRmax;
00134       r2max = fRmin;
00135    }
00136    rmin = TMath::Min(r1min, r2min);
00137    rmax = TMath::Max(r1max, r2max);
00138 
00139    Double_t xc[4];
00140    Double_t yc[4];
00141    xc[0] = rmax*TMath::Cos(fPhi1*TMath::DegToRad());
00142    yc[0] = rmax*TMath::Sin(fPhi1*TMath::DegToRad());
00143    xc[1] = rmax*TMath::Cos(fPhi2*TMath::DegToRad());
00144    yc[1] = rmax*TMath::Sin(fPhi2*TMath::DegToRad());
00145    xc[2] = rmin*TMath::Cos(fPhi1*TMath::DegToRad());
00146    yc[2] = rmin*TMath::Sin(fPhi1*TMath::DegToRad());
00147    xc[3] = rmin*TMath::Cos(fPhi2*TMath::DegToRad());
00148    yc[3] = rmin*TMath::Sin(fPhi2*TMath::DegToRad());
00149 
00150    Double_t xmin = xc[TMath::LocMin(4, &xc[0])];
00151    Double_t xmax = xc[TMath::LocMax(4, &xc[0])]; 
00152    Double_t ymin = yc[TMath::LocMin(4, &yc[0])]; 
00153    Double_t ymax = yc[TMath::LocMax(4, &yc[0])];
00154    Double_t dp = fPhi2-fPhi1;
00155    if (dp<0) dp+=360;
00156    Double_t ddp = -fPhi1;
00157    if (ddp<0) ddp+= 360;
00158    if (ddp>360) ddp-=360;
00159    if (ddp<=dp) xmax = rmax;
00160    ddp = 90-fPhi1;
00161    if (ddp<0) ddp+= 360;
00162    if (ddp>360) ddp-=360;
00163    if (ddp<=dp) ymax = rmax;
00164    ddp = 180-fPhi1;
00165    if (ddp<0) ddp+= 360;
00166    if (ddp>360) ddp-=360;
00167    if (ddp<=dp) xmin = -rmax;
00168    ddp = 270-fPhi1;
00169    if (ddp<0) ddp+= 360;
00170    if (ddp>360) ddp-=360;
00171    if (ddp<=dp) ymin = -rmax;
00172    xc[0] = fRmax*TMath::Cos(fTheta1*TMath::DegToRad());  
00173    xc[1] = fRmax*TMath::Cos(fTheta2*TMath::DegToRad());  
00174    xc[2] = fRmin*TMath::Cos(fTheta1*TMath::DegToRad());  
00175    xc[3] = fRmin*TMath::Cos(fTheta2*TMath::DegToRad());  
00176    Double_t zmin = xc[TMath::LocMin(4, &xc[0])];
00177    Double_t zmax = xc[TMath::LocMax(4, &xc[0])]; 
00178 
00179 
00180    fOrigin[0] = (xmax+xmin)/2;
00181    fOrigin[1] = (ymax+ymin)/2;
00182    fOrigin[2] = (zmax+zmin)/2;;
00183    fDX = (xmax-xmin)/2;
00184    fDY = (ymax-ymin)/2;
00185    fDZ = (zmax-zmin)/2;
00186 }   
00187 
00188 //_____________________________________________________________________________   
00189 void TGeoSphere::ComputeNormal(Double_t *point, Double_t *dir, Double_t *norm)
00190 {
00191 // Compute normal to closest surface from POINT. 
00192    Double_t rxy2 = point[0]*point[0]+point[1]*point[1];
00193    Double_t r2 = rxy2+point[2]*point[2];
00194    Double_t r=TMath::Sqrt(r2);
00195    Bool_t rzero=kFALSE;
00196    if (r<=1E-20) rzero=kTRUE;
00197    //localize theta
00198    Double_t phi=0;
00199    Double_t th=0.;
00200    if (!rzero) th = TMath::ACos(point[2]/r);
00201  
00202    //localize phi
00203    phi=TMath::ATan2(point[1], point[0]);
00204 
00205    Double_t saf[4];
00206    saf[0]=(TGeoShape::IsSameWithinTolerance(fRmin,0) && !TestShapeBit(kGeoThetaSeg) && !TestShapeBit(kGeoPhiSeg))?TGeoShape::Big():TMath::Abs(r-fRmin);
00207    saf[1]=TMath::Abs(fRmax-r);
00208    saf[2]=saf[3]= TGeoShape::Big();
00209    if (TestShapeBit(kGeoThetaSeg)) {
00210       if (fTheta1>0) {
00211          saf[2] = r*TMath::Abs(TMath::Sin(th-fTheta1*TMath::DegToRad()));
00212       }
00213       if (fTheta2<180) {
00214          saf[3] = r*TMath::Abs(TMath::Sin(fTheta2*TMath::DegToRad()-th));
00215       }    
00216    }
00217    Int_t i = TMath::LocMin(4,saf);
00218    if (TestShapeBit(kGeoPhiSeg)) {
00219       Double_t c1 = TMath::Cos(fPhi1*TMath::DegToRad());
00220       Double_t s1 = TMath::Sin(fPhi1*TMath::DegToRad());
00221       Double_t c2 = TMath::Cos(fPhi2*TMath::DegToRad());
00222       Double_t s2 = TMath::Sin(fPhi2*TMath::DegToRad());
00223       if (TGeoShape::IsCloseToPhi(saf[i], point,c1,s1,c2,s2)) {
00224          TGeoShape::NormalPhi(point,dir,norm,c1,s1,c2,s2);
00225          return;
00226       }   
00227    }  
00228    if (i>1) {
00229       if (i==2) th=(fTheta1<90)?(fTheta1+90):(fTheta1-90);
00230       else      th=(fTheta2<90)?(fTheta2+90):(fTheta2-90);
00231       th *= TMath::DegToRad();
00232    }
00233       
00234    norm[0] = TMath::Sin(th)*TMath::Cos(phi);
00235    norm[1] = TMath::Sin(th)*TMath::Sin(phi);
00236    norm[2] = TMath::Cos(th);
00237    if (norm[0]*dir[0]+norm[1]*dir[1]+norm[2]*dir[2]<0) {
00238       norm[0] = -norm[0];
00239       norm[1] = -norm[1];
00240       norm[2] = -norm[2];
00241    }             
00242 }
00243 
00244 //_____________________________________________________________________________
00245 Int_t TGeoSphere::IsOnBoundary(Double_t *point) const
00246 {
00247 // Check if a point in local sphere coordinates is close to a boundary within
00248 // shape tolerance. Return values:
00249 //   0 - not close to boundary
00250 //   1 - close to Rmin boundary
00251 //   2 - close to Rmax boundary
00252 //   3,4 - close to phi1/phi2 boundary
00253 //   5,6 - close to theta1/theta2 boundary
00254    Int_t icode = 0;
00255    Double_t tol = TGeoShape::Tolerance();
00256    Double_t r2 = point[0]*point[0]+point[1]*point[1]+point[2]*point[2];
00257    Double_t drsqout = r2-fRmax*fRmax;
00258    // Test if point is on fRmax boundary
00259    if (TMath::Abs(drsqout)<2.*fRmax*tol) return 2;
00260    Double_t drsqin = r2;
00261    // Test if point is on fRmin boundary
00262    if (TestShapeBit(kGeoRSeg)) {
00263       drsqin -= fRmin*fRmin;
00264       if (TMath::Abs(drsqin)<2.*fRmin*tol) return 1;
00265    } 
00266    if (TestShapeBit(kGeoPhiSeg)) { 
00267       Double_t phi = TMath::ATan2(point[1], point[0]);
00268       if (phi<0) phi+=2*TMath::Pi();
00269       Double_t phi1 = fPhi1*TMath::DegToRad();
00270       Double_t phi2 = fPhi2*TMath::DegToRad();
00271       Double_t ddp = phi-phi1;
00272       if (r2*ddp*ddp < tol*tol) return 3;
00273       ddp = phi - phi2;
00274       if (r2*ddp*ddp < tol*tol) return 4;
00275    }   
00276    if (TestShapeBit(kGeoThetaSeg)) { 
00277       Double_t r = TMath::Sqrt(r2);
00278       Double_t theta = TMath::ACos(point[2]/r2);
00279       Double_t theta1 = fTheta1*TMath::DegToRad();
00280       Double_t theta2 = fTheta2*TMath::DegToRad();
00281       Double_t ddt;
00282       if (fTheta1>0) {
00283          ddt = TMath::Abs(theta-theta1);
00284          if (r*ddt < tol) return 5;
00285       }
00286       if (fTheta2<180) {
00287          ddt = TMath::Abs(theta-theta2);
00288          if (r*ddt < tol) return 6;
00289       }   
00290    }
00291    return icode;
00292 }      
00293 
00294 //_____________________________________________________________________________
00295 Bool_t TGeoSphere::IsPointInside(Double_t *point, Bool_t checkR, Bool_t checkTh, Bool_t checkPh) const
00296 {
00297 // Check if a point is inside radius/theta/phi ranges for the spherical sector.
00298    Double_t r2 = point[0]*point[0]+point[1]*point[1]+point[2]*point[2];
00299    if (checkR) {
00300       if (TestShapeBit(kGeoRSeg) && (r2<fRmin*fRmin)) return kFALSE;
00301       if (r2>fRmax*fRmax) return kFALSE;
00302    }
00303    if (r2<1E-20) return kTRUE;
00304    if (checkPh && TestShapeBit(kGeoPhiSeg)) {
00305       Double_t phi = TMath::ATan2(point[1], point[0]) * TMath::RadToDeg();
00306       while (phi < fPhi1) phi+=360.;
00307       Double_t dphi = fPhi2 -fPhi1;
00308       Double_t ddp = phi - fPhi1;
00309       if (ddp > dphi) return kFALSE;    
00310    }
00311    if (checkTh && TestShapeBit(kGeoThetaSeg)) {
00312       r2=TMath::Sqrt(r2);
00313       // check theta range
00314       Double_t theta = TMath::ACos(point[2]/r2)*TMath::RadToDeg();
00315       if ((theta<fTheta1) || (theta>fTheta2)) return kFALSE;
00316    }      
00317    return kTRUE;
00318 }
00319 
00320 //_____________________________________________________________________________
00321 Bool_t TGeoSphere::Contains(Double_t *point) const
00322 {
00323 // test if point is inside this sphere
00324    // check Rmin<=R<=Rmax
00325    Double_t r2=point[0]*point[0]+point[1]*point[1]+point[2]*point[2];
00326    if (TestShapeBit(kGeoRSeg) && (r2<fRmin*fRmin)) return kFALSE;
00327    if (r2>fRmax*fRmax) return kFALSE;
00328    if (r2<1E-20) return kTRUE;
00329    // check phi range
00330    if (TestShapeBit(kGeoPhiSeg)) {
00331       Double_t phi = TMath::ATan2(point[1], point[0]) * TMath::RadToDeg();
00332       if (phi < 0 ) phi+=360.;
00333       Double_t dphi = fPhi2 -fPhi1;
00334       if (dphi < 0) dphi+=360.;
00335       Double_t ddp = phi - fPhi1;
00336       if (ddp < 0) ddp += 360.;
00337       if (ddp > dphi) return kFALSE;    
00338    }
00339    if (TestShapeBit(kGeoThetaSeg)) {
00340       r2=TMath::Sqrt(r2);
00341       // check theta range
00342       Double_t theta = TMath::ACos(point[2]/r2)*TMath::RadToDeg();
00343       if ((theta<fTheta1) || (theta>fTheta2)) return kFALSE;
00344    }      
00345    return kTRUE;
00346 }
00347 
00348 //_____________________________________________________________________________
00349 Int_t TGeoSphere::DistancetoPrimitive(Int_t px, Int_t py)
00350 {
00351 // compute closest distance from point px,py to each corner
00352    Int_t n = fNseg+1;
00353    Int_t nz = fNz+1;
00354    const Int_t numPoints = 2*n*nz;
00355    return ShapeDistancetoPrimitive(numPoints, px, py);
00356 }
00357 
00358 //_____________________________________________________________________________
00359 Double_t TGeoSphere::DistFromOutside(Double_t *point, Double_t *dir, Int_t iact, Double_t step, Double_t *safe) const
00360 {
00361 // compute distance from outside point to surface of the sphere
00362 // Check if the bounding box is crossed within the requested distance
00363    Double_t sdist = TGeoBBox::DistFromOutside(point,dir, fDX, fDY, fDZ, fOrigin, step);
00364    if (sdist>=step) return TGeoShape::Big();
00365    Double_t saf[6];
00366    Double_t r1,r2,z1,z2,dz,si,ci;
00367    Double_t rxy2 = point[0]*point[0]+point[1]*point[1];
00368    Double_t rxy = TMath::Sqrt(rxy2);
00369    r2 = rxy2+point[2]*point[2];
00370    Double_t r=TMath::Sqrt(r2);
00371    Bool_t rzero=kFALSE;
00372    Double_t phi=0;
00373    if (r<1E-20) rzero=kTRUE;
00374    //localize theta
00375    Double_t th=0.;
00376    if (TestShapeBit(kGeoThetaSeg) && (!rzero)) {
00377       th = TMath::ACos(point[2]/r)*TMath::RadToDeg();
00378    }
00379    //localize phi
00380    if (TestShapeBit(kGeoPhiSeg)) {
00381       phi=TMath::ATan2(point[1], point[0])*TMath::RadToDeg();
00382       if (phi<0) phi+=360.;
00383    }   
00384    if (iact<3 && safe) {
00385       saf[0]=(r<fRmin)?fRmin-r:TGeoShape::Big();
00386       saf[1]=(r>fRmax)?(r-fRmax):TGeoShape::Big();
00387       saf[2]=saf[3]=saf[4]=saf[5]= TGeoShape::Big();
00388       if (TestShapeBit(kGeoThetaSeg)) {
00389          if (th < fTheta1) {
00390             saf[2] = r*TMath::Sin((fTheta1-th)*TMath::DegToRad());
00391          }    
00392          if (th > fTheta2) {
00393             saf[3] = r*TMath::Sin((th-fTheta2)*TMath::DegToRad());
00394          }
00395       }
00396       if (TestShapeBit(kGeoPhiSeg)) {
00397          Double_t dph1=phi-fPhi1;
00398          if (dph1<0) dph1+=360.;
00399          if (dph1<=90.) saf[4]=rxy*TMath::Sin(dph1*TMath::DegToRad());
00400          Double_t dph2=fPhi2-phi;
00401          if (dph2<0) dph2+=360.;
00402          if (dph2>90.) saf[5]=rxy*TMath::Sin(dph2*TMath::DegToRad());
00403       }
00404       *safe = saf[TMath::LocMin(6, &saf[0])];
00405       if (iact==0) return TGeoShape::Big();
00406       if (iact==1 && step<*safe) return TGeoShape::Big();
00407    }
00408    // compute distance to shape
00409    // first check if any crossing at all
00410    Double_t snxt = TGeoShape::Big();
00411    Double_t rdotn = point[0]*dir[0]+point[1]*dir[1]+point[2]*dir[2];
00412    Bool_t fullsph = (!TestShapeBit(kGeoThetaSeg) && !TestShapeBit(kGeoPhiSeg))?kTRUE:kFALSE;
00413    if (r>fRmax) {
00414       Double_t b = rdotn;
00415       Double_t c = r2-fRmax*fRmax;
00416       Double_t d=b*b-c;
00417       if (d<0) return TGeoShape::Big();
00418    }
00419    if (fullsph) {
00420       Bool_t inrmax = kFALSE;
00421       Bool_t inrmin = kFALSE;
00422       if (r<=fRmax+TGeoShape::Tolerance()) inrmax = kTRUE;
00423       if (r>=fRmin-TGeoShape::Tolerance()) inrmin = kTRUE;
00424       if (inrmax && inrmin) {
00425          if ((fRmax-r) < (r-fRmin)) {
00426          // close to Rmax
00427             if (rdotn>=0) return TGeoShape::Big();
00428             return 0.0; // already in
00429          }
00430          // close to Rmin
00431          if (TGeoShape::IsSameWithinTolerance(fRmin,0) || rdotn>=0) return 0.0;
00432          // check second crossing of Rmin
00433          return DistToSphere(point, dir, fRmin, kFALSE, kFALSE);
00434       }
00435    }   
00436    
00437    // do rmin, rmax,  checking phi and theta ranges
00438    if (r<fRmin) {
00439       // check first cross of rmin
00440       snxt = DistToSphere(point, dir, fRmin, kTRUE);
00441       if (snxt<1E20) return snxt;
00442    } else {
00443       if (r>fRmax) {      
00444          // point outside rmax, check first cross of rmax
00445          snxt = DistToSphere(point, dir, fRmax, kTRUE);
00446          if (snxt<1E20) return snxt;
00447          // now check second crossing of rmin
00448          if (fRmin>0) snxt = DistToSphere(point, dir, fRmin, kTRUE, kFALSE);
00449       } else {
00450          // point between rmin and rmax, check second cross of rmin
00451          if (fRmin>0) snxt = DistToSphere(point, dir, fRmin, kTRUE, kFALSE);
00452       } 
00453    }       
00454    // check theta conical surfaces
00455    Double_t ptnew[3];
00456    Double_t b,delta, znew;
00457    Double_t snext = snxt;
00458    Double_t st1=TGeoShape::Big(), st2=TGeoShape::Big();
00459    if (TestShapeBit(kGeoThetaSeg)) {
00460       if (fTheta1>0) {
00461          if (TGeoShape::IsSameWithinTolerance(fTheta1,90)) {
00462          // surface is a plane
00463             if (point[2]*dir[2]<0) {
00464                snxt = -point[2]/dir[2];
00465                ptnew[0] = point[0]+snxt*dir[0];
00466                ptnew[1] = point[1]+snxt*dir[1];
00467                ptnew[2] = 0;
00468                // check range
00469                if (IsPointInside(&ptnew[0], kTRUE, kFALSE, kTRUE)) return TMath::Min(snxt,snext);
00470             }       
00471          } else {
00472             si = TMath::Sin(fTheta1*TMath::DegToRad());
00473             ci = TMath::Cos(fTheta1*TMath::DegToRad());
00474             if (ci>0) {
00475                r1 = fRmin*si;
00476                z1 = fRmin*ci;
00477                r2 = fRmax*si;
00478                z2 = fRmax*ci;
00479             } else {   
00480                r1 = fRmax*si;
00481                z1 = fRmax*ci;
00482                r2 = fRmin*si;
00483                z2 = fRmin*ci;
00484             }
00485             dz = 0.5*(z2-z1);
00486             ptnew[0] = point[0];
00487             ptnew[1] = point[1];
00488             ptnew[2] = point[2]-0.5*(z1+z2);
00489             if (TestShapeBit(kGeoPhiSeg)) {
00490                st1 = TGeoConeSeg::DistToCons(point, dir, r1, z1, r2, z2, fPhi1, fPhi2); 
00491             } else {
00492                TGeoCone::DistToCone(ptnew, dir, dz, r1, r2, b, delta);
00493                if (delta>0) {
00494                   st1 = -b-delta;
00495                   znew = ptnew[2]+st1*dir[2];
00496                   if (st1<0 || TMath::Abs(znew)>dz) {
00497                      st1 = -b+delta; 
00498                      znew = ptnew[2]+st1*dir[2];
00499                      if (st1<0 || TMath::Abs(znew)>dz) st1=TGeoShape::Big();
00500                   } 
00501                }     
00502             }
00503          }       
00504       }
00505       
00506       if (fTheta2<180) {
00507          if (TGeoShape::IsSameWithinTolerance(fTheta2,90)) {
00508             // surface is a plane
00509             if (point[2]*dir[2]<0) {
00510                snxt = -point[2]/dir[2];
00511                ptnew[0] = point[0]+snxt*dir[0];
00512                ptnew[1] = point[1]+snxt*dir[1];
00513                ptnew[2] = 0;
00514                // check range
00515                if (IsPointInside(&ptnew[0], kTRUE, kFALSE, kTRUE)) return TMath::Min(snxt,snext);
00516             }       
00517          } else {
00518             si = TMath::Sin(fTheta2*TMath::DegToRad());
00519             ci = TMath::Cos(fTheta2*TMath::DegToRad());
00520             if (ci>0) {
00521                r1 = fRmin*si;
00522                z1 = fRmin*ci;
00523                r2 = fRmax*si;
00524                z2 = fRmax*ci;
00525             } else {   
00526                r1 = fRmax*si;
00527                z1 = fRmax*ci;
00528                r2 = fRmin*si;
00529                z2 = fRmin*ci;
00530             }
00531             dz = 0.5*(z2-z1);
00532             ptnew[0] = point[0];
00533             ptnew[1] = point[1];
00534             ptnew[2] = point[2]-0.5*(z1+z2);
00535             if (TestShapeBit(kGeoPhiSeg)) {
00536                st2 = TGeoConeSeg::DistToCons(point, dir, r1, z1, r2, z2, fPhi1, fPhi2); 
00537             } else {
00538                TGeoCone::DistToCone(ptnew, dir, dz, r1, r2, b, delta);
00539                if (delta>0) {
00540                   st2 = -b-delta;
00541                   znew = ptnew[2]+st2*dir[2];
00542                   if (st2<0 || TMath::Abs(znew)>dz) {
00543                      st2 = -b+delta; 
00544                      znew = ptnew[2]+st2*dir[2];
00545                      if (st2<0 || TMath::Abs(znew)>dz) st2=TGeoShape::Big();
00546                   }   
00547                }    
00548             }
00549          }
00550       }
00551    }
00552    snxt = TMath::Min(st1, st2);
00553    snxt = TMath::Min(snxt,snext);
00554 //   if (snxt<1E20) return snxt;       
00555    if (TestShapeBit(kGeoPhiSeg)) {
00556       Double_t s1 = TMath::Sin(fPhi1*TMath::DegToRad());
00557       Double_t c1 = TMath::Cos(fPhi1*TMath::DegToRad());
00558       Double_t s2 = TMath::Sin(fPhi2*TMath::DegToRad());
00559       Double_t c2 = TMath::Cos(fPhi2*TMath::DegToRad());
00560       Double_t phim = 0.5*(fPhi1+fPhi2);
00561       Double_t sm = TMath::Sin(phim*TMath::DegToRad());
00562       Double_t cm = TMath::Cos(phim*TMath::DegToRad());
00563       Double_t sfi1=TGeoShape::Big();
00564       Double_t sfi2=TGeoShape::Big();
00565       Double_t s=0;
00566       Double_t safety, un;
00567       safety = point[0]*s1-point[1]*c1;
00568       if (safety>0) {
00569          un = dir[0]*s1-dir[1]*c1;
00570          if (un<0) {
00571             s=-safety/un;
00572             ptnew[0] = point[0]+s*dir[0];
00573             ptnew[1] = point[1]+s*dir[1];
00574             ptnew[2] = point[2]+s*dir[2];
00575             if ((ptnew[1]*cm-ptnew[0]*sm)<=0) {
00576                sfi1=s;
00577                if (IsPointInside(&ptnew[0], kTRUE, kTRUE, kFALSE) && sfi1<snxt) return sfi1;
00578             }
00579          }       
00580       }
00581       safety = -point[0]*s2+point[1]*c2;
00582       if (safety>0) {
00583          un = -dir[0]*s2+dir[1]*c2;    
00584          if (un<0) {
00585             s=-safety/un;
00586             ptnew[0] = point[0]+s*dir[0];
00587             ptnew[1] = point[1]+s*dir[1];
00588             ptnew[2] = point[2]+s*dir[2];
00589             if ((ptnew[1]*cm-ptnew[0]*sm)>=0) {
00590                sfi2=s;
00591                if (IsPointInside(&ptnew[0], kTRUE, kTRUE, kFALSE) && sfi2<snxt) return sfi2;
00592             }   
00593          }   
00594       }
00595    }      
00596    return snxt;            
00597 }   
00598 
00599 //_____________________________________________________________________________
00600 Double_t TGeoSphere::DistFromInside(Double_t *point, Double_t *dir, Int_t iact, Double_t step, Double_t *safe) const
00601 {
00602 // compute distance from inside point to surface of the sphere
00603    Double_t saf[6];
00604    Double_t rxy2 = point[0]*point[0]+point[1]*point[1];
00605    Double_t rxy = TMath::Sqrt(rxy2);
00606    Double_t rad2 = rxy2+point[2]*point[2];
00607    Double_t r=TMath::Sqrt(rad2);
00608    Bool_t rzero=kFALSE;
00609    if (r<=1E-20) rzero=kTRUE;
00610    //localize theta
00611    Double_t phi=0;;
00612    Double_t th=0.;
00613    if (TestShapeBit(kGeoThetaSeg) && (!rzero)) {
00614       th = TMath::ACos(point[2]/r)*TMath::RadToDeg();
00615    }
00616    //localize phi
00617    if (TestShapeBit(kGeoPhiSeg)) {
00618       phi=TMath::ATan2(point[1], point[0])*TMath::RadToDeg();
00619       if (phi<0) phi+=360.;
00620    }   
00621    if (iact<3 && safe) {
00622       saf[0]=(TGeoShape::IsSameWithinTolerance(fRmin,0))?TGeoShape::Big():r-fRmin;
00623       saf[1]=fRmax-r;
00624       saf[2]=saf[3]=saf[4]=saf[5]= TGeoShape::Big();
00625       if (TestShapeBit(kGeoThetaSeg)) {
00626          if (fTheta1>0) {
00627             saf[2] = r*TMath::Sin((th-fTheta1)*TMath::DegToRad());
00628          }
00629          if (fTheta2<180) {
00630             saf[3] = r*TMath::Sin((fTheta2-th)*TMath::DegToRad());
00631          }    
00632       }
00633       if (TestShapeBit(kGeoPhiSeg)) {
00634          Double_t dph1=phi-fPhi1;
00635          if (dph1<0) dph1+=360.;
00636          if (dph1<=90.) saf[4]=rxy*TMath::Sin(dph1*TMath::DegToRad());
00637          Double_t dph2=fPhi2-phi;
00638          if (dph2<0) dph2+=360.;
00639          if (dph2<=90.) saf[5]=rxy*TMath::Sin(dph2*TMath::DegToRad());
00640       }
00641       *safe = saf[TMath::LocMin(6, &saf[0])];
00642       if (iact==0) return TGeoShape::Big();
00643       if (iact==1 && step<*safe) return TGeoShape::Big();
00644    }
00645    // compute distance to shape
00646    Double_t snxt = TGeoShape::Big();
00647    if (rzero) {
00648 //      gGeoManager->SetNormalChecked(1.);
00649       return fRmax;
00650    }
00651    // first do rmin, rmax
00652    Double_t b,delta, znew;
00653    Double_t rdotn = point[0]*dir[0]+point[1]*dir[1]+point[2]*dir[2];
00654    Double_t sn1 = TGeoShape::Big();
00655    // Inner sphere
00656    if (fRmin>0) {
00657       // Protection in case point is actually outside the sphere
00658       if (r <= fRmin+TGeoShape::Tolerance()) {
00659          if (rdotn<0) return 0.0;
00660       } else {
00661          if (rdotn<0) sn1 = DistToSphere(point, dir, fRmin, kFALSE);
00662       }
00663    }      
00664    Double_t sn2 = TGeoShape::Big();
00665    // Outer sphere
00666    if (r >= fRmax-TGeoShape::Tolerance()) {
00667       if (rdotn>=0) return 0.0;
00668    }   
00669    sn2 = DistToSphere(point, dir, fRmax, kFALSE);
00670    Double_t sr = TMath::Min(sn1, sn2);
00671    // check theta conical surfaces
00672    sn1 = TGeoShape::Big();
00673    sn2 = TGeoShape::Big();
00674    if (TestShapeBit(kGeoThetaSeg)) {
00675       if (TGeoShape::IsSameWithinTolerance(fTheta1,90)) {
00676       // surface is a plane
00677          if (point[2]*dir[2]<0)  sn1 = -point[2]/dir[2];
00678       } else {
00679          if (fTheta1>0) {
00680             Double_t r1,r2,z1,z2,dz,ptnew[3];
00681             Double_t si = TMath::Sin(fTheta1*TMath::DegToRad());
00682             Double_t ci = TMath::Cos(fTheta1*TMath::DegToRad());
00683             if (ci>0) {
00684                r1 = fRmin*si;
00685                z1 = fRmin*ci;
00686                r2 = fRmax*si;
00687                z2 = fRmax*ci;
00688             } else {   
00689                r1 = fRmax*si;
00690                z1 = fRmax*ci;
00691                r2 = fRmin*si;
00692                z2 = fRmin*ci;
00693             }
00694             dz = 0.5*(z2-z1);
00695             ptnew[0] = point[0];
00696             ptnew[1] = point[1];
00697             ptnew[2] = point[2]-0.5*(z1+z2);             
00698             if (TestShapeBit(kGeoPhiSeg)) {
00699                sn1 = TGeoConeSeg::DistToCons(point, dir, r1, z1, r2, z2, fPhi1, fPhi2); 
00700             } else {
00701                TGeoCone::DistToCone(ptnew, dir, dz, r1, r2, b, delta);
00702                if (delta>0) {
00703                   sn1 = -b-delta;
00704                   znew = ptnew[2]+sn1*dir[2];
00705                   if (sn1<0 || TMath::Abs(znew)>dz) {
00706                      sn1 = -b+delta; 
00707                      znew = ptnew[2]+sn1*dir[2];
00708                      if (sn1<0 || TMath::Abs(znew)>dz) sn1=TGeoShape::Big();
00709                   } 
00710                }     
00711             }
00712          }        
00713       }
00714       if (TGeoShape::IsSameWithinTolerance(fTheta2,90)) {
00715          // surface is a plane
00716          if (point[2]*dir[2]<0)  sn1 = -point[2]/dir[2];
00717       } else {
00718          if (fTheta2<180) {
00719             Double_t r1,r2,z1,z2,dz,ptnew[3];
00720             Double_t si = TMath::Sin(fTheta2*TMath::DegToRad());
00721             Double_t ci = TMath::Cos(fTheta2*TMath::DegToRad());
00722             if (ci>0) {
00723                r1 = fRmin*si;
00724                z1 = fRmin*ci;
00725                r2 = fRmax*si;
00726                z2 = fRmax*ci;
00727             } else {   
00728                r1 = fRmax*si;
00729                z1 = fRmax*ci;
00730                r2 = fRmin*si;
00731                z2 = fRmin*ci;
00732             }
00733             dz = 0.5*(z2-z1);
00734             ptnew[0] = point[0];
00735             ptnew[1] = point[1];
00736             ptnew[2] = point[2]-0.5*(z1+z2);             
00737             if (TestShapeBit(kGeoPhiSeg)) {
00738                sn2 = TGeoConeSeg::DistToCons(point, dir, r1, z1, r2, z2, fPhi1, fPhi2); 
00739             } else {
00740                TGeoCone::DistToCone(ptnew, dir, dz, r1, r2, b, delta);
00741                if (delta>0) {
00742                   sn2 = -b-delta;
00743                   znew = ptnew[2]+sn2*dir[2];
00744                   if (sn2<0 || TMath::Abs(znew)>dz) {
00745                      sn2 = -b+delta; 
00746                      znew = ptnew[2]+sn2*dir[2];
00747                      if (sn2<0 || TMath::Abs(znew)>dz) sn2=TGeoShape::Big();
00748                   } 
00749                }     
00750             }
00751          }        
00752       }
00753    }
00754    Double_t st = TMath::Min(sn1,sn2);       
00755    Double_t sp = TGeoShape::Big();
00756    if (TestShapeBit(kGeoPhiSeg)) {
00757       Double_t s1 = TMath::Sin(fPhi1*TMath::DegToRad());
00758       Double_t c1 = TMath::Cos(fPhi1*TMath::DegToRad());
00759       Double_t s2 = TMath::Sin(fPhi2*TMath::DegToRad());
00760       Double_t c2 = TMath::Cos(fPhi2*TMath::DegToRad());
00761       Double_t phim = 0.5*(fPhi1+fPhi2);
00762       Double_t sm = TMath::Sin(phim*TMath::DegToRad());
00763       Double_t cm = TMath::Cos(phim*TMath::DegToRad());
00764       sp = TGeoShape::DistToPhiMin(point, dir, s1, c1, s2, c2, sm, cm);
00765    }      
00766    snxt = TMath::Min(sr, st);
00767    snxt = TMath::Min(snxt, sp);
00768    return snxt;            
00769 }   
00770 
00771 //_____________________________________________________________________________
00772 Double_t TGeoSphere::DistToSphere(Double_t *point, Double_t *dir, Double_t rsph, Bool_t check, Bool_t firstcross) const
00773 {
00774 // compute distance to sphere of radius rsph. Direction has to be a unit vector
00775    if (rsph<=0) return TGeoShape::Big();
00776    Double_t s=TGeoShape::Big();
00777    Double_t r2 = point[0]*point[0]+point[1]*point[1]+point[2]*point[2];
00778    Double_t b = point[0]*dir[0]+point[1]*dir[1]+point[2]*dir[2];
00779    Double_t c = r2-rsph*rsph;
00780    Bool_t in = (c<=0)?kTRUE:kFALSE;
00781    Double_t d;
00782    
00783    d=b*b-c;
00784    if (d<0) return TGeoShape::Big();
00785    Double_t pt[3];
00786    Int_t i;
00787    d = TMath::Sqrt(d);
00788    if (in) {
00789       s=-b+d;
00790    } else {
00791       s = (firstcross)?(-b-d):(-b+d);
00792    }            
00793    if (s<0) return TGeoShape::Big();
00794    if (!check) return s;
00795    for (i=0; i<3; i++) pt[i]=point[i]+s*dir[i];
00796    // check theta and phi ranges
00797    if (IsPointInside(&pt[0], kFALSE)) return s;
00798    return TGeoShape::Big();
00799 }
00800 
00801 //_____________________________________________________________________________
00802 TGeoVolume *TGeoSphere::Divide(TGeoVolume * /*voldiv*/, const char * /*divname*/, Int_t /*iaxis*/, Int_t /*ndiv*/,
00803                                Double_t /*start*/, Double_t /*step*/) 
00804 {
00805 // Divide all range of iaxis in range/step cells 
00806    Error("Divide", "Division of a sphere not implemented");
00807    return 0;
00808 }      
00809 
00810 //_____________________________________________________________________________
00811 const char *TGeoSphere::GetAxisName(Int_t iaxis) const
00812 {
00813 // Returns name of axis IAXIS.
00814    switch (iaxis) {
00815       case 1:
00816          return "R";
00817       case 2:
00818          return "THETA";
00819       case 3:
00820          return "PHI";
00821       default:
00822          return "UNDEFINED";
00823    }
00824 }   
00825 
00826 //_____________________________________________________________________________
00827 Double_t TGeoSphere::GetAxisRange(Int_t iaxis, Double_t &xlo, Double_t &xhi) const
00828 {
00829 // Get range of shape for a given axis.
00830    xlo = 0;
00831    xhi = 0;
00832    Double_t dx = 0;
00833    switch (iaxis) {
00834       case 1:
00835          xlo = fRmin;
00836          xhi = fRmax;
00837          dx = xhi-xlo;
00838          return dx;
00839       case 2:
00840          xlo = fPhi1;
00841          xhi = fPhi2;
00842          dx = xhi-xlo;
00843          return dx;
00844       case 3:
00845          xlo = fTheta1;
00846          xhi = fTheta2;
00847          dx = xhi-xlo;
00848          return dx;
00849    }
00850    return dx;
00851 }         
00852 
00853 //_____________________________________________________________________________
00854 void TGeoSphere::GetBoundingCylinder(Double_t *param) const
00855 {
00856 //--- Fill vector param[4] with the bounding cylinder parameters. The order
00857 // is the following : Rmin, Rmax, Phi1, Phi2
00858    Double_t smin = TMath::Sin(fTheta1*TMath::DegToRad());
00859    Double_t smax = TMath::Sin(fTheta2*TMath::DegToRad());
00860    if (smin>smax) {
00861       Double_t a = smin;
00862       smin = smax;
00863       smax = a;
00864    }   
00865    param[0] = fRmin*smin; // Rmin
00866    param[0] *= param[0];
00867    if (((90.-fTheta1)*(fTheta2-90.))>=0) smax = 1.;
00868    param[1] = fRmax*smax; // Rmax
00869    param[1] *= param[1];
00870    param[2] = (fPhi1<0)?(fPhi1+360.):fPhi1; // Phi1
00871    param[3] = fPhi2;
00872    if (TGeoShape::IsSameWithinTolerance(param[3]-param[2],360)) {         // Phi2
00873       param[2] = 0.;
00874       param[3] = 360.;
00875    }   
00876    while (param[3]<param[2]) param[3]+=360.;
00877 }
00878 
00879 //_____________________________________________________________________________
00880 void TGeoSphere::InspectShape() const
00881 {
00882 // print shape parameters
00883    printf("*** Shape %s: TGeoSphere ***\n", GetName());
00884    printf("    Rmin = %11.5f\n", fRmin);
00885    printf("    Rmax = %11.5f\n", fRmax);
00886    printf("    Th1  = %11.5f\n", fTheta1);
00887    printf("    Th2  = %11.5f\n", fTheta2);
00888    printf("    Ph1  = %11.5f\n", fPhi1);
00889    printf("    Ph2  = %11.5f\n", fPhi2);
00890    printf(" Bounding box:\n");
00891    TGeoBBox::InspectShape();
00892 }
00893 
00894 //_____________________________________________________________________________
00895 TBuffer3D *TGeoSphere::MakeBuffer3D() const
00896 { 
00897    // Creates a TBuffer3D describing *this* shape.
00898    // Coordinates are in local reference frame.
00899 
00900    Bool_t full = kTRUE;
00901    if (TestShapeBit(kGeoThetaSeg) || TestShapeBit(kGeoPhiSeg)) full = kFALSE;
00902    Int_t ncenter = 1;
00903    if (full || TestShapeBit(kGeoRSeg)) ncenter = 0;
00904    Int_t nup = (fTheta1>0)?0:1;
00905    Int_t ndown = (fTheta2<180)?0:1;
00906    // number of different latitudes, excluding 0 and 180 degrees
00907    Int_t nlat = fNz+1-(nup+ndown);
00908    // number of different longitudes
00909    Int_t nlong = fNseg;
00910    if (TestShapeBit(kGeoPhiSeg)) nlong++;
00911 
00912    Int_t nbPnts = nlat*nlong+nup+ndown+ncenter;
00913    if (TestShapeBit(kGeoRSeg)) nbPnts *= 2;
00914 
00915    Int_t nbSegs = nlat*fNseg + (nlat-1+nup+ndown)*nlong; // outer sphere
00916    if (TestShapeBit(kGeoRSeg)) nbSegs *= 2; // inner sphere
00917    if (TestShapeBit(kGeoPhiSeg)) nbSegs += 2*nlat+nup+ndown; // 2 phi planes
00918    nbSegs += nlong * (2-nup - ndown);  // connecting cones
00919       
00920    Int_t nbPols = fNz*fNseg; // outer
00921    if (TestShapeBit(kGeoRSeg)) nbPols *=2;  // inner
00922    if (TestShapeBit(kGeoPhiSeg)) nbPols += 2*fNz; // 2 phi planes
00923    nbPols += (2-nup-ndown)*fNseg; // connecting
00924 
00925    TBuffer3D* buff = new TBuffer3D(TBuffer3DTypes::kGeneric,
00926                                    nbPnts, 3*nbPnts, nbSegs, 3*nbSegs, nbPols, 6*nbPols);
00927 
00928    if (buff)
00929    {
00930       SetPoints(buff->fPnts);
00931       SetSegsAndPols(*buff);
00932    }
00933 
00934    return buff; 
00935 }
00936 
00937 //_____________________________________________________________________________
00938 void TGeoSphere::SetSegsAndPols(TBuffer3D & buff) const
00939 {
00940 // Fill TBuffer3D structure for segments and polygons.
00941    Bool_t full = kTRUE;
00942    if (TestShapeBit(kGeoThetaSeg) || TestShapeBit(kGeoPhiSeg)) full = kFALSE;
00943    Int_t ncenter = 1;
00944    if (full || TestShapeBit(kGeoRSeg)) ncenter = 0;
00945    Int_t nup = (fTheta1>0)?0:1;
00946    Int_t ndown = (fTheta2<180)?0:1;
00947    // number of different latitudes, excluding 0 and 180 degrees
00948    Int_t nlat = fNz+1-(nup+ndown);
00949    // number of different longitudes
00950    Int_t nlong = fNseg;
00951    if (TestShapeBit(kGeoPhiSeg)) nlong++;
00952 
00953    Int_t nbPnts = nlat*nlong+nup+ndown+ncenter;
00954    if (TestShapeBit(kGeoRSeg)) nbPnts *= 2;
00955 
00956    Int_t nbSegs = nlat*fNseg + (nlat-1+nup+ndown)*nlong; // outer sphere
00957    if (TestShapeBit(kGeoRSeg)) nbSegs *= 2; // inner sphere
00958    if (TestShapeBit(kGeoPhiSeg)) nbSegs += 2*nlat+nup+ndown; // 2 phi planes
00959    nbSegs += nlong * (2-nup - ndown);  // connecting cones
00960       
00961    Int_t nbPols = fNz*fNseg; // outer
00962    if (TestShapeBit(kGeoRSeg)) nbPols *=2;  // inner
00963    if (TestShapeBit(kGeoPhiSeg)) nbPols += 2*fNz; // 2 phi planes
00964    nbPols += (2-nup-ndown)*fNseg; // connecting
00965 
00966    Int_t c = GetBasicColor();
00967    Int_t i, j;
00968    Int_t indx;
00969    indx = 0;
00970    // outside sphere
00971    // loop all segments on latitudes (except 0 and 180 degrees)
00972    // [0, nlat*fNseg)
00973    Int_t indpar = 0;
00974    for (i=0; i<nlat; i++) {
00975       for (j=0; j<fNseg; j++) {
00976          buff.fSegs[indx++]   = c;
00977          buff.fSegs[indx++] = i*nlong+j;
00978          buff.fSegs[indx++] = i*nlong+(j+1)%nlong;
00979       }
00980    }
00981    // loop all segments on longitudes
00982    // nlat*fNseg + [0, (nlat-1)*nlong)
00983    Int_t indlong = indpar + nlat*fNseg;
00984    for (i=0; i<nlat-1; i++) {
00985       for (j=0; j<nlong; j++) {
00986          buff.fSegs[indx++]   = c;
00987          buff.fSegs[indx++] = i*nlong+j;
00988          buff.fSegs[indx++] = (i+1)*nlong+j;
00989       }
00990    }
00991    Int_t indup = indlong + (nlat-1)*nlong;
00992    // extra longitudes on top
00993    // nlat*fNseg+(nlat-1)*nlong + [0, nlong)
00994    if (nup) {
00995       Int_t indpup = nlat*nlong;
00996       for (j=0; j<nlong; j++) {
00997          buff.fSegs[indx++]   = c;
00998          buff.fSegs[indx++] = j;
00999          buff.fSegs[indx++] = indpup;
01000       }   
01001    }      
01002    Int_t inddown = indup + nup*nlong;
01003    // extra longitudes on bottom
01004    // nlat*fNseg+(nlat+nup-1)*nlong + [0, nlong)
01005    if (ndown) {
01006       Int_t indpdown = nlat*nlong+nup;
01007       for (j=0; j<nlong; j++) {
01008          buff.fSegs[indx++]   = c;
01009          buff.fSegs[indx++] = (nlat-1)*nlong+j;
01010          buff.fSegs[indx++] = indpdown;
01011       }   
01012    }      
01013    Int_t indparin = inddown + ndown*nlong;
01014    Int_t indlongin = indparin;
01015    Int_t indupin = indparin;
01016    Int_t inddownin = indparin;
01017    Int_t indphi = indparin;
01018    // inner sphere
01019    Int_t indptin = nlat*nlong + nup + ndown;
01020    Int_t iptcenter = indptin;
01021    // nlat*fNseg+(nlat+nup+ndown-1)*nlong
01022    if (TestShapeBit(kGeoRSeg)) {
01023       indlongin = indparin + nlat*fNseg;
01024       indupin   = indlongin + (nlat-1)*nlong;
01025       inddownin = indupin + nup*nlong;
01026       // loop all segments on latitudes (except 0 and 180 degrees)
01027       // indsegin + [0, nlat*fNseg)
01028       for (i=0; i<nlat; i++) {
01029          for (j=0; j<fNseg; j++) {
01030             buff.fSegs[indx++]   = c+1;
01031             buff.fSegs[indx++] = indptin + i*nlong+j;
01032             buff.fSegs[indx++] = indptin + i*nlong+(j+1)%nlong;
01033          }
01034       }
01035       // loop all segments on longitudes
01036       // indsegin + nlat*fNseg + [0, (nlat-1)*nlong)
01037       for (i=0; i<nlat-1; i++) {
01038          for (j=0; j<nlong; j++) {
01039             buff.fSegs[indx++]   = c+1;
01040             buff.fSegs[indx++] = indptin + i*nlong+j;
01041             buff.fSegs[indx++] = indptin + (i+1)*nlong+j;
01042          }
01043       }
01044       // extra longitudes on top
01045       // indsegin + nlat*fNseg+(nlat-1)*nlong + [0, nlong)
01046       if (nup) {
01047          Int_t indupltop = indptin + nlat*nlong;
01048          for (j=0; j<nlong; j++) {
01049             buff.fSegs[indx++]   = c+1;
01050             buff.fSegs[indx++] = indptin + j;
01051             buff.fSegs[indx++] = indupltop;
01052          }   
01053       }      
01054       // extra longitudes on bottom
01055       // indsegin + nlat*fNseg+(nlat+nup-1)*nlong + [0, nlong)
01056       if (ndown) {
01057          Int_t indpdown = indptin + nlat*nlong+nup;
01058          for (j=0; j<nlong; j++) {
01059             buff.fSegs[indx++]   = c+1;
01060             buff.fSegs[indx++] = indptin + (nlat-1)*nlong+j;
01061             buff.fSegs[indx++] = indpdown;
01062          }   
01063       }      
01064       indphi = inddownin + ndown*nlong;
01065    }
01066    Int_t indtheta = indphi; 
01067    // Segments on phi planes
01068    if (TestShapeBit(kGeoPhiSeg)) {
01069       indtheta += 2*nlat + nup + ndown;
01070       for (j=0; j<nlat; j++) {
01071          buff.fSegs[indx++]   = c+2;
01072          buff.fSegs[indx++] = j*nlong;
01073          if (TestShapeBit(kGeoRSeg)) buff.fSegs[indx++] = indptin + j*nlong;
01074          else buff.fSegs[indx++] = iptcenter;
01075       }
01076       for (j=0; j<nlat; j++) {
01077          buff.fSegs[indx++]   = c+2;
01078          buff.fSegs[indx++] = (j+1)*nlong-1;
01079          if (TestShapeBit(kGeoRSeg)) buff.fSegs[indx++] = indptin + (j+1)*nlong-1;
01080          else buff.fSegs[indx++] = iptcenter;
01081       }
01082       if (nup) {
01083          buff.fSegs[indx++]   = c+2;
01084          buff.fSegs[indx++] = nlat*nlong;
01085          if (TestShapeBit(kGeoRSeg)) buff.fSegs[indx++] = indptin + nlat*nlong;
01086          else buff.fSegs[indx++] = iptcenter;
01087       }   
01088       if (ndown) {
01089          buff.fSegs[indx++]   = c+2;
01090          buff.fSegs[indx++] = nlat*nlong+nup;
01091          if (TestShapeBit(kGeoRSeg)) buff.fSegs[indx++] = indptin + nlat*nlong+nup;
01092          else buff.fSegs[indx++] = iptcenter;
01093       }   
01094    }
01095    // Segments on cones
01096    if (!nup) {   
01097       for (j=0; j<nlong; j++) {
01098          buff.fSegs[indx++]   = c+2;
01099          buff.fSegs[indx++] = j;
01100          if (TestShapeBit(kGeoRSeg)) buff.fSegs[indx++] = indptin + j;
01101          else buff.fSegs[indx++] = iptcenter;
01102       }
01103    }     
01104    if (!ndown) {   
01105       for (j=0; j<nlong; j++) {
01106          buff.fSegs[indx++]   = c+2;
01107          buff.fSegs[indx++] = (nlat-1)*nlong + j;
01108          if (TestShapeBit(kGeoRSeg)) buff.fSegs[indx++] = indptin + (nlat-1)*nlong +j;
01109          else buff.fSegs[indx++] = iptcenter;
01110       }
01111    }     
01112    
01113    indx = 0;
01114    // Fill polygons for outside sphere (except 0/180)
01115    for (i=0; i<nlat-1; i++) {
01116       for (j=0; j<fNseg; j++) {
01117          buff.fPols[indx++] = c;   
01118          buff.fPols[indx++] = 4;
01119          buff.fPols[indx++] = indpar+i*fNseg+j;
01120          buff.fPols[indx++] = indlong+i*nlong+(j+1)%nlong;
01121          buff.fPols[indx++] = indpar+(i+1)*fNseg+j;
01122          buff.fPols[indx++] = indlong+i*nlong+j;
01123       }
01124    }      
01125    // upper
01126    if (nup) {
01127       for (j=0; j<fNseg; j++) {
01128          buff.fPols[indx++] = c;   
01129          buff.fPols[indx++] = 3;
01130          buff.fPols[indx++] = indup + j;
01131          buff.fPols[indx++] = indup + (j+1)%nlong;
01132          buff.fPols[indx++] = indpar + j;
01133       }      
01134    }
01135    // lower
01136    if (ndown) {
01137       for (j=0; j<fNseg; j++) {
01138          buff.fPols[indx++] = c;   
01139          buff.fPols[indx++] = 3;
01140          buff.fPols[indx++] = inddown + j;
01141          buff.fPols[indx++] = indpar + (nlat-1)*fNseg + j;
01142          buff.fPols[indx++] = inddown + (j+1)%nlong;
01143       }      
01144    }
01145    // Fill polygons for inside sphere (except 0/180)
01146 
01147    if (TestShapeBit(kGeoRSeg)) {
01148       for (i=0; i<nlat-1; i++) {
01149          for (j=0; j<fNseg; j++) {
01150             buff.fPols[indx++] = c+1;   
01151             buff.fPols[indx++] = 4;
01152             buff.fPols[indx++] = indparin+i*fNseg+j;
01153             buff.fPols[indx++] = indlongin+i*nlong+j;
01154             buff.fPols[indx++] = indparin+(i+1)*fNseg+j;
01155             buff.fPols[indx++] = indlongin+i*nlong+(j+1)%nlong;
01156          }
01157       }
01158       // upper
01159       if (nup) {
01160          for (j=0; j<fNseg; j++) {
01161             buff.fPols[indx++] = c+1;   
01162             buff.fPols[indx++] = 3;
01163             buff.fPols[indx++] = indupin + j;
01164             buff.fPols[indx++] = indparin + j;
01165             buff.fPols[indx++] = indupin + (j+1)%nlong;
01166          }      
01167       }
01168       // lower
01169       if (ndown) {
01170          for (j=0; j<fNseg; j++) {
01171             buff.fPols[indx++] = c+1;   
01172             buff.fPols[indx++] = 3;
01173             buff.fPols[indx++] = inddownin + j;
01174             buff.fPols[indx++] = inddownin + (j+1)%nlong;
01175             buff.fPols[indx++] = indparin + (nlat-1)*fNseg + j;
01176          }      
01177       }
01178    }         
01179    // Polygons on phi planes
01180    if (TestShapeBit(kGeoPhiSeg)) {
01181       for (i=0; i<nlat-1; i++) {
01182          buff.fPols[indx++]   = c+2;
01183          if (TestShapeBit(kGeoRSeg)) {
01184             buff.fPols[indx++] = 4;
01185             buff.fPols[indx++] = indlong + i*nlong;
01186             buff.fPols[indx++] = indphi + i + 1;
01187             buff.fPols[indx++] = indlongin + i*nlong;
01188             buff.fPols[indx++] = indphi + i;
01189          } else {
01190             buff.fPols[indx++] = 3;  
01191             buff.fPols[indx++] = indlong + i*nlong;
01192             buff.fPols[indx++] = indphi + i + 1;
01193             buff.fPols[indx++] = indphi + i;
01194          }
01195       }      
01196       for (i=0; i<nlat-1; i++) {
01197          buff.fPols[indx++]   = c+2;
01198          if (TestShapeBit(kGeoRSeg)) {
01199             buff.fPols[indx++] = 4;
01200             buff.fPols[indx++] = indlong + (i+1)*nlong-1;
01201             buff.fPols[indx++] = indphi + nlat + i;
01202             buff.fPols[indx++] = indlongin + (i+1)*nlong-1;
01203             buff.fPols[indx++] = indphi + nlat + i + 1;
01204          } else {
01205             buff.fPols[indx++] = 3;  
01206             buff.fPols[indx++] = indlong + (i+1)*nlong-1;
01207             buff.fPols[indx++] = indphi + nlat + i;
01208             buff.fPols[indx++] = indphi + nlat + i + 1;
01209          }
01210       }      
01211       if (nup) {
01212          buff.fPols[indx++]   = c+2;
01213          if (TestShapeBit(kGeoRSeg)) {
01214             buff.fPols[indx++] = 4;
01215             buff.fPols[indx++] = indup;
01216             buff.fPols[indx++] = indphi;
01217             buff.fPols[indx++] = indupin;
01218             buff.fPols[indx++] = indphi + 2*nlat;
01219          } else {
01220             buff.fPols[indx++] = 3;
01221             buff.fPols[indx++] = indup;  
01222             buff.fPols[indx++] = indphi;
01223             buff.fPols[indx++] = indphi + 2*nlat;
01224          }                      
01225          buff.fPols[indx++]   = c+2;
01226          if (TestShapeBit(kGeoRSeg)) {
01227             buff.fPols[indx++] = 4;
01228             buff.fPols[indx++] = indup+nlong-1;
01229             buff.fPols[indx++] = indphi + 2*nlat;
01230             buff.fPols[indx++] = indupin+nlong-1;
01231             buff.fPols[indx++] = indphi + nlat;
01232          } else {
01233             buff.fPols[indx++] = 3;
01234             buff.fPols[indx++] = indup+nlong-1;  
01235             buff.fPols[indx++] = indphi + 2*nlat;
01236             buff.fPols[indx++] = indphi + nlat;
01237          }                      
01238       }
01239       if (ndown) {
01240          buff.fPols[indx++]   = c+2;
01241          if (TestShapeBit(kGeoRSeg)) {
01242             buff.fPols[indx++] = 4;
01243             buff.fPols[indx++] = inddown;
01244             buff.fPols[indx++] = indphi + 2*nlat + nup;
01245             buff.fPols[indx++] = inddownin;
01246             buff.fPols[indx++] = indphi + nlat-1;
01247          } else {
01248             buff.fPols[indx++] = 3;
01249             buff.fPols[indx++] = inddown;  
01250             buff.fPols[indx++] = indphi + 2*nlat + nup;
01251             buff.fPols[indx++] = indphi + nlat-1;
01252          }                      
01253          buff.fPols[indx++]   = c+2;
01254          if (TestShapeBit(kGeoRSeg)) {
01255             buff.fPols[indx++] = 4;
01256             buff.fPols[indx++] = inddown+nlong-1;
01257             buff.fPols[indx++] = indphi + 2*nlat-1;
01258             buff.fPols[indx++] = inddownin+nlong-1;
01259             buff.fPols[indx++] = indphi + 2*nlat+nup;
01260          } else {
01261             buff.fPols[indx++] = 3;
01262             buff.fPols[indx++] = inddown+nlong-1;  
01263             buff.fPols[indx++] = indphi + 2*nlat-1;
01264             buff.fPols[indx++] = indphi + 2*nlat+nup;
01265          } 
01266       }
01267    }                           
01268    // Polygons on cones
01269    if (!nup) {
01270       for (j=0; j<fNseg; j++) {
01271          buff.fPols[indx++] = c+2;
01272          if (TestShapeBit(kGeoRSeg)) {
01273             buff.fPols[indx++] = 4;
01274             buff.fPols[indx++] = indpar+j;
01275             buff.fPols[indx++] = indtheta + j;
01276             buff.fPols[indx++] = indparin + j;
01277             buff.fPols[indx++] = indtheta + (j+1)%nlong;            
01278          } else {
01279             buff.fPols[indx++] = 3;
01280             buff.fPols[indx++] = indpar+j;
01281             buff.fPols[indx++] = indtheta + j;
01282             buff.fPols[indx++] = indtheta + (j+1)%nlong;            
01283          }
01284       }   
01285    }
01286    if (!ndown) {
01287       for (j=0; j<fNseg; j++) {
01288          buff.fPols[indx++] = c+2;
01289          if (TestShapeBit(kGeoRSeg)) {
01290             buff.fPols[indx++] = 4;
01291             buff.fPols[indx++] = indpar+(nlat-1)*fNseg+j;
01292             buff.fPols[indx++] = indtheta + (1-nup)*nlong +(j+1)%nlong;            
01293             buff.fPols[indx++] = indparin + (nlat-1)*fNseg + j;
01294             buff.fPols[indx++] = indtheta + (1-nup)*nlong + j;
01295          } else {
01296             buff.fPols[indx++] = 3;
01297             buff.fPols[indx++] = indpar+(nlat-1)*fNseg+j;
01298             buff.fPols[indx++] = indtheta + (1-nup)*nlong +(j+1)%nlong;            
01299             buff.fPols[indx++] = indtheta + (1-nup)*nlong + j;
01300          }
01301       }   
01302    }
01303 }   
01304    
01305 //_____________________________________________________________________________
01306 Double_t TGeoSphere::Safety(Double_t *point, Bool_t in) const
01307 {
01308 // computes the closest distance from given point to this shape, according
01309 // to option. The matching point on the shape is stored in spoint.
01310    Double_t r2 = point[0]*point[0]+point[1]*point[1]+point[2]*point[2];
01311    Double_t r=TMath::Sqrt(r2);
01312    Bool_t rzero=kFALSE;
01313    if (r<=1E-20) rzero=kTRUE;
01314    //localize theta
01315    Double_t th=0.;
01316    if (TestShapeBit(kGeoThetaSeg) && (!rzero)) {
01317       th = TMath::ACos(point[2]/r)*TMath::RadToDeg();
01318    }
01319    Double_t saf[4];
01320    saf[0]=(TGeoShape::IsSameWithinTolerance(fRmin,0) && !TestShapeBit(kGeoThetaSeg) && !TestShapeBit(kGeoPhiSeg))?TGeoShape::Big():r-fRmin;
01321    saf[1]=fRmax-r;
01322    saf[2]=saf[3]= TGeoShape::Big();
01323    if (TestShapeBit(kGeoThetaSeg)) {
01324       if (fTheta1>0)    saf[2] = r*TMath::Sin((th-fTheta1)*TMath::DegToRad());
01325       if (fTheta2<180)  saf[3] = r*TMath::Sin((fTheta2-th)*TMath::DegToRad());
01326    }
01327    Double_t safphi = TGeoShape::Big();
01328    Double_t safe = TGeoShape::Big();
01329    if (TestShapeBit(kGeoPhiSeg)) safphi = TGeoShape::SafetyPhi(point,in,fPhi1,fPhi2);
01330    if (in) {
01331       safe = saf[TMath::LocMin(4,saf)];
01332       return TMath::Min(safe,safphi);
01333    }   
01334    for (Int_t i=0; i<4; i++) saf[i]=-saf[i];
01335    safe = saf[TMath::LocMax(4, saf)];
01336    if (TestShapeBit(kGeoPhiSeg)) return TMath::Max(safe, safphi);
01337    return safe;
01338 }
01339 
01340 //_____________________________________________________________________________
01341 void TGeoSphere::SavePrimitive(ostream &out, Option_t * /*option*/ /*= ""*/)
01342 {
01343 // Save a primitive as a C++ statement(s) on output stream "out".
01344    if (TObject::TestBit(kGeoSavePrimitive)) return;
01345    out << "   // Shape: " << GetName() << " type: " << ClassName() << endl;
01346    out << "   rmin   = " << fRmin << ";" << endl;
01347    out << "   rmax   = " << fRmax << ";" << endl;
01348    out << "   theta1 = " << fTheta1<< ";" << endl;
01349    out << "   theta2 = " << fTheta2 << ";" << endl;
01350    out << "   phi1   = " << fPhi1 << ";" << endl;
01351    out << "   phi2   = " << fPhi2 << ";" << endl;
01352    out << "   TGeoShape *" << GetPointerName() << " = new TGeoSphere(\"" << GetName() << "\",rmin,rmax,theta1, theta2,phi1,phi2);" << endl;
01353    TObject::SetBit(TGeoShape::kGeoSavePrimitive);   
01354 }
01355 
01356 //_____________________________________________________________________________
01357 void TGeoSphere::SetSphDimensions(Double_t rmin, Double_t rmax, Double_t theta1,
01358                                Double_t theta2, Double_t phi1, Double_t phi2)
01359 {
01360 // Set spherical segment dimensions.
01361    if (rmin >= rmax) {
01362       Error("SetDimensions", "invalid parameters rmin/rmax");
01363       return;
01364    }
01365    fRmin = rmin;
01366    fRmax = rmax;
01367    if (rmin>0) SetShapeBit(kGeoRSeg);
01368    if (theta1 >= theta2 || theta1<0 || theta1>180 || theta2>180) {
01369       Error("SetDimensions", "invalid parameters theta1/theta2");
01370       return;
01371    }
01372    fTheta1 = theta1;
01373    fTheta2 = theta2;
01374    if ((theta2-theta1)<180.) SetShapeBit(kGeoThetaSeg);
01375    fPhi1 = phi1;
01376    if (phi1<0) fPhi1+=360.;
01377    fPhi2 = phi2;
01378    while (fPhi2<=fPhi1) fPhi2+=360.;
01379    if (!TGeoShape::IsSameWithinTolerance(TMath::Abs(phi2-phi1),360)) SetShapeBit(kGeoPhiSeg);
01380 }   
01381 
01382 //_____________________________________________________________________________
01383 void TGeoSphere::SetDimensions(Double_t *param)
01384 {
01385 // Set dimensions of the spherical segment starting from a list of parameters.
01386    Double_t rmin = param[0];
01387    Double_t rmax = param[1];
01388    Double_t theta1 = 0;
01389    Double_t theta2 = 180.;
01390    Double_t phi1 = 0;
01391    Double_t phi2 = 360.;
01392 //   if (nparam > 2) theta1 = param[2];
01393 //   if (nparam > 3) theta2 = param[3];
01394 //   if (nparam > 4) phi1   = param[4];
01395 //   if (nparam > 5) phi2   = param[5];
01396    SetSphDimensions(rmin, rmax, theta1, theta2, phi1, phi2);
01397 }   
01398 
01399 //_____________________________________________________________________________
01400 void TGeoSphere::SetNumberOfDivisions(Int_t p)
01401 {
01402 // Set the number of divisions of mesh circles keeping aspect ratio.
01403    fNseg = p;
01404    Double_t dphi = fPhi2 - fPhi1;
01405    if (dphi<0) dphi+=360;
01406    Double_t dtheta = TMath::Abs(fTheta2-fTheta1);
01407    fNz = Int_t(fNseg*dtheta/dphi) +1;
01408    if (fNz<2) fNz=2;
01409 }
01410 
01411 //_____________________________________________________________________________
01412 void TGeoSphere::SetPoints(Double_t *points) const
01413 {
01414 // create sphere mesh points
01415    if (!points) {
01416       Error("SetPoints", "Input array is NULL");
01417       return;
01418    }   
01419    Bool_t full = kTRUE;
01420    if (TestShapeBit(kGeoThetaSeg) || TestShapeBit(kGeoPhiSeg)) full = kFALSE;
01421    Int_t ncenter = 1;
01422    if (full || TestShapeBit(kGeoRSeg)) ncenter = 0;
01423    Int_t nup = (fTheta1>0)?0:1;
01424    Int_t ndown = (fTheta2<180)?0:1;
01425    // number of different latitudes, excluding 0 and 180 degrees
01426    Int_t nlat = fNz+1-(nup+ndown);
01427    // number of different longitudes
01428    Int_t nlong = fNseg;
01429    if (TestShapeBit(kGeoPhiSeg)) nlong++;
01430    // total number of points on mesh is:
01431    //    nlat*nlong + nup + ndown + ncenter;    // in case rmin=0
01432    //   2*(nlat*nlong + nup + ndown);           // in case rmin>0
01433    Int_t i,j ;
01434    Double_t phi1 = fPhi1*TMath::DegToRad();
01435    Double_t phi2 = fPhi2*TMath::DegToRad();
01436    Double_t dphi = (phi2-phi1)/fNseg;
01437    Double_t theta1 = fTheta1*TMath::DegToRad();
01438    Double_t theta2 = fTheta2*TMath::DegToRad();
01439    Double_t dtheta = (theta2-theta1)/fNz;
01440    Double_t z,zi,theta,phi,cphi,sphi;
01441    Int_t indx=0;
01442    // FILL ALL POINTS ON OUTER SPHERE
01443    // (nlat * nlong) points
01444    // loop all latitudes except 0/180 degrees (nlat times)
01445    // ilat = [0,nlat]   jlong = [0,nlong]
01446    // Index(ilat, jlong) = 3*(ilat*nlat + jlong)
01447    for (i = 0; i < nlat; i++) {
01448       theta = theta1+(nup+i)*dtheta;
01449       z =  fRmax * TMath::Cos(theta);
01450       zi = fRmax * TMath::Sin(theta);
01451       // loop all different longitudes (nlong times)
01452       for (j = 0; j < nlong; j++) {
01453          phi = phi1+j*dphi;
01454          cphi = TMath::Cos(phi);
01455          sphi = TMath::Sin(phi);
01456          points[indx++] = zi * cphi;
01457          points[indx++] = zi * sphi;
01458          points[indx++] = z;
01459       }
01460    }
01461    // upper/lower points (if they exist) for outer sphere
01462    if (nup) {
01463       // ind_up = 3*nlat*nlong
01464       points[indx++] = 0.;
01465       points[indx++] = 0.;
01466       points[indx++] = fRmax;
01467    }   
01468    if (ndown) {
01469       // ind_down = 3*(nlat*nlong+nup)
01470       points[indx++] = 0.;
01471       points[indx++] = 0.;
01472       points[indx++] = -fRmax;
01473    }   
01474    // do the same for inner sphere if it exist
01475    // Start_index = 3*(nlat*nlong + nup + ndown)
01476    if (TestShapeBit(kGeoRSeg)) {
01477    // Index(ilat, jlong) = start_index + 3*(ilat*nlat + jlong)
01478       for (i = 0; i < nlat; i++) {
01479          theta = theta1+(nup+i)*dtheta;
01480          z =  fRmin * TMath::Cos(theta);
01481          zi = fRmin * TMath::Sin(theta);
01482          // loop all different longitudes (nlong times)
01483          for (j = 0; j < nlong; j++) {
01484             phi = phi1+j*dphi;
01485             cphi = TMath::Cos(phi);
01486             sphi = TMath::Sin(phi);
01487             points[indx++] = zi * cphi;
01488             points[indx++] = zi * sphi;
01489             points[indx++] = z;
01490          }
01491       }
01492       // upper/lower points (if they exist) for inner sphere
01493       if (nup) {
01494       // ind_up = start_index + 3*nlat*nlong
01495          points[indx++] = 0.;
01496          points[indx++] = 0.;
01497          points[indx++] = fRmin;
01498       }   
01499       if (ndown) {
01500       // ind_down = start_index + 3*(nlat*nlong+nup)
01501          points[indx++] = 0.;
01502          points[indx++] = 0.;
01503          points[indx++] = -fRmin;
01504       }   
01505    }
01506    // Add center of sphere if needed
01507    if (ncenter) {
01508       // ind_center = 6*(nlat*nlong + nup + ndown)
01509       points[indx++] = 0.;
01510       points[indx++] = 0.;
01511       points[indx++] = 0.;
01512    }   
01513 }
01514 
01515 //_____________________________________________________________________________
01516 void TGeoSphere::SetPoints(Float_t *points) const
01517 {
01518 // create sphere mesh points
01519    if (!points) {
01520       Error("SetPoints", "Input array is NULL");
01521       return;
01522    }   
01523    Bool_t full = kTRUE;
01524    if (TestShapeBit(kGeoThetaSeg) || TestShapeBit(kGeoPhiSeg)) full = kFALSE;
01525    Int_t ncenter = 1;
01526    if (full || TestShapeBit(kGeoRSeg)) ncenter = 0;
01527    Int_t nup = (fTheta1>0)?0:1;
01528    Int_t ndown = (fTheta2<180)?0:1;
01529    // number of different latitudes, excluding 0 and 180 degrees
01530    Int_t nlat = fNz+1-(nup+ndown);
01531    // number of different longitudes
01532    Int_t nlong = fNseg;
01533    if (TestShapeBit(kGeoPhiSeg)) nlong++;
01534    // total number of points on mesh is:
01535    //    nlat*nlong + nup + ndown + ncenter;    // in case rmin=0
01536    //   2*(nlat*nlong + nup + ndown);           // in case rmin>0
01537    Int_t i,j ;
01538    Double_t phi1 = fPhi1*TMath::DegToRad();
01539    Double_t phi2 = fPhi2*TMath::DegToRad();
01540    Double_t dphi = (phi2-phi1)/fNseg;
01541    Double_t theta1 = fTheta1*TMath::DegToRad();
01542    Double_t theta2 = fTheta2*TMath::DegToRad();
01543    Double_t dtheta = (theta2-theta1)/fNz;
01544    Double_t z,zi,theta,phi,cphi,sphi;
01545    Int_t indx=0;
01546    // FILL ALL POINTS ON OUTER SPHERE
01547    // (nlat * nlong) points
01548    // loop all latitudes except 0/180 degrees (nlat times)
01549    // ilat = [0,nlat]   jlong = [0,nlong]
01550    // Index(ilat, jlong) = 3*(ilat*nlat + jlong)
01551    for (i = 0; i < nlat; i++) {
01552       theta = theta1+(nup+i)*dtheta;
01553       z =  fRmax * TMath::Cos(theta);
01554       zi = fRmax * TMath::Sin(theta);
01555       // loop all different longitudes (nlong times)
01556       for (j = 0; j < nlong; j++) {
01557          phi = phi1+j*dphi;
01558          cphi = TMath::Cos(phi);
01559          sphi = TMath::Sin(phi);
01560          points[indx++] = zi * cphi;
01561          points[indx++] = zi * sphi;
01562          points[indx++] = z;
01563       }
01564    }
01565    // upper/lower points (if they exist) for outer sphere
01566    if (nup) {
01567       // ind_up = 3*nlat*nlong
01568       points[indx++] = 0.;
01569       points[indx++] = 0.;
01570       points[indx++] = fRmax;
01571    }   
01572    if (ndown) {
01573       // ind_down = 3*(nlat*nlong+nup)
01574       points[indx++] = 0.;
01575       points[indx++] = 0.;
01576       points[indx++] = -fRmax;
01577    }   
01578    // do the same for inner sphere if it exist
01579    // Start_index = 3*(nlat*nlong + nup + ndown)
01580    if (TestShapeBit(kGeoRSeg)) {
01581    // Index(ilat, jlong) = start_index + 3*(ilat*nlat + jlong)
01582       for (i = 0; i < nlat; i++) {
01583          theta = theta1+(nup+i)*dtheta;
01584          z =  fRmin * TMath::Cos(theta);
01585          zi = fRmin * TMath::Sin(theta);
01586          // loop all different longitudes (nlong times)
01587          for (j = 0; j < nlong; j++) {
01588             phi = phi1+j*dphi;
01589             cphi = TMath::Cos(phi);
01590             sphi = TMath::Sin(phi);
01591             points[indx++] = zi * cphi;
01592             points[indx++] = zi * sphi;
01593             points[indx++] = z;
01594          }
01595       }
01596       // upper/lower points (if they exist) for inner sphere
01597       if (nup) {
01598       // ind_up = start_index + 3*nlat*nlong
01599          points[indx++] = 0.;
01600          points[indx++] = 0.;
01601          points[indx++] = fRmin;
01602       }   
01603       if (ndown) {
01604       // ind_down = start_index + 3*(nlat*nlong+nup)
01605          points[indx++] = 0.;
01606          points[indx++] = 0.;
01607          points[indx++] = -fRmin;
01608       }   
01609    }
01610    // Add center of sphere if needed
01611    if (ncenter) {
01612       // ind_center = 6*(nlat*nlong + nup + ndown)
01613       points[indx++] = 0.;
01614       points[indx++] = 0.;
01615       points[indx++] = 0.;
01616    }   
01617 }
01618 
01619 //_____________________________________________________________________________
01620 void TGeoSphere::GetMeshNumbers(Int_t &nvert, Int_t &nsegs, Int_t &npols) const
01621 {
01622 // Returns numbers of vertices, segments and polygons composing the shape mesh.
01623    TGeoSphere * localThis = const_cast<TGeoSphere *>(this);
01624    localThis->SetNumberOfDivisions(gGeoManager->GetNsegments());
01625    Bool_t full = kTRUE;
01626    if (TestShapeBit(kGeoThetaSeg) || TestShapeBit(kGeoPhiSeg)) full = kFALSE;
01627    Int_t ncenter = 1;
01628    if (full || TestShapeBit(kGeoRSeg)) ncenter = 0;
01629    Int_t nup = (fTheta1>0)?0:1;
01630    Int_t ndown = (fTheta2<180)?0:1;
01631    // number of different latitudes, excluding 0 and 180 degrees
01632    Int_t nlat = fNz+1-(nup+ndown);
01633    // number of different longitudes
01634    Int_t nlong = fNseg;
01635    if (TestShapeBit(kGeoPhiSeg)) nlong++;
01636 
01637    nvert = nlat*nlong+nup+ndown+ncenter;
01638    if (TestShapeBit(kGeoRSeg)) nvert *= 2;
01639 
01640    nsegs = nlat*fNseg + (nlat-1+nup+ndown)*nlong; // outer sphere
01641    if (TestShapeBit(kGeoRSeg)) nsegs *= 2; // inner sphere
01642    if (TestShapeBit(kGeoPhiSeg)) nsegs += 2*nlat+nup+ndown; // 2 phi planes
01643    nsegs += nlong * (2-nup - ndown);  // connecting cones
01644       
01645    npols = fNz*fNseg; // outer
01646    if (TestShapeBit(kGeoRSeg)) npols *=2;  // inner
01647    if (TestShapeBit(kGeoPhiSeg)) npols += 2*fNz; // 2 phi planes
01648    npols += (2-nup-ndown)*fNseg; // connecting
01649 }
01650 
01651 //_____________________________________________________________________________
01652 Int_t TGeoSphere::GetNmeshVertices() const
01653 {
01654 // Return number of vertices of the mesh representation
01655    Bool_t full = kTRUE;
01656    if (TestShapeBit(kGeoThetaSeg) || TestShapeBit(kGeoPhiSeg)) full = kFALSE;
01657    Int_t ncenter = 1;
01658    if (full || TestShapeBit(kGeoRSeg)) ncenter = 0;
01659    Int_t nup = (fTheta1>0)?0:1;
01660    Int_t ndown = (fTheta2<180)?0:1;
01661    // number of different latitudes, excluding 0 and 180 degrees
01662    Int_t nlat = fNz+1-(nup+ndown);
01663    // number of different longitudes
01664    Int_t nlong = fNseg;
01665    if (TestShapeBit(kGeoPhiSeg)) nlong++;
01666    // total number of points on mesh is:
01667    //    nlat*nlong + nup + ndown + ncenter;    // in case rmin=0
01668    //   2*(nlat*nlong + nup + ndown);           // in case rmin>0
01669    Int_t numPoints = 0;
01670    if (TestShapeBit(kGeoRSeg)) numPoints = 2*(nlat*nlong+nup+ndown);
01671    else numPoints = nlat*nlong+nup+ndown+ncenter;
01672    return numPoints;
01673 }
01674 
01675 //_____________________________________________________________________________
01676 void TGeoSphere::Sizeof3D() const
01677 {
01678 ///// obsolete - to be removed
01679 }
01680 
01681 //_____________________________________________________________________________
01682 const TBuffer3D & TGeoSphere::GetBuffer3D(Int_t reqSections, Bool_t localFrame) const
01683 {
01684 // Fills a static 3D buffer and returns a reference.
01685    static TBuffer3DSphere buffer;
01686 
01687    TGeoBBox::FillBuffer3D(buffer, reqSections, localFrame);
01688 
01689    if (reqSections & TBuffer3D::kShapeSpecific) {
01690       buffer.fRadiusInner  = fRmin;
01691       buffer.fRadiusOuter  = fRmax;
01692       buffer.fThetaMin     = fTheta1;
01693       buffer.fThetaMax     = fTheta2;
01694       buffer.fPhiMin       = fPhi1;
01695       buffer.fPhiMax       = fPhi2;
01696       buffer.SetSectionsValid(TBuffer3D::kShapeSpecific);
01697    }
01698    if (reqSections & TBuffer3D::kRawSizes) {
01699       // We want FillBuffer to be const
01700       TGeoSphere * localThis = const_cast<TGeoSphere *>(this);
01701       localThis->SetNumberOfDivisions(gGeoManager->GetNsegments());
01702 
01703       Bool_t full = kTRUE;
01704       if (TestShapeBit(kGeoThetaSeg) || TestShapeBit(kGeoPhiSeg)) full = kFALSE;
01705       Int_t ncenter = 1;
01706       if (full || TestShapeBit(kGeoRSeg)) ncenter = 0;
01707       Int_t nup = (fTheta1>0)?0:1;
01708       Int_t ndown = (fTheta2<180)?0:1;
01709       // number of different latitudes, excluding 0 and 180 degrees
01710       Int_t nlat = fNz+1-(nup+ndown);
01711       // number of different longitudes
01712       Int_t nlong = fNseg;
01713       if (TestShapeBit(kGeoPhiSeg)) nlong++;
01714 
01715       Int_t nbPnts = nlat*nlong+nup+ndown+ncenter;
01716       if (TestShapeBit(kGeoRSeg)) nbPnts *= 2;
01717 
01718       Int_t nbSegs = nlat*fNseg + (nlat-1+nup+ndown)*nlong; // outer sphere
01719       if (TestShapeBit(kGeoRSeg)) nbSegs *= 2; // inner sphere
01720       if (TestShapeBit(kGeoPhiSeg)) nbSegs += 2*nlat+nup+ndown; // 2 phi planes
01721       nbSegs += nlong * (2-nup - ndown);  // connecting cones
01722       
01723       Int_t nbPols = fNz*fNseg; // outer
01724       if (TestShapeBit(kGeoRSeg)) nbPols *=2;  // inner
01725       if (TestShapeBit(kGeoPhiSeg)) nbPols += 2*fNz; // 2 phi planes
01726       nbPols += (2-nup-ndown)*fNseg; // connecting
01727       
01728       if (buffer.SetRawSizes(nbPnts, 3*nbPnts, nbSegs, 3*nbSegs, nbPols, 6*nbPols)) {
01729          buffer.SetSectionsValid(TBuffer3D::kRawSizes);
01730       }
01731    }
01732    if ((reqSections & TBuffer3D::kRaw) && buffer.SectionsValid(TBuffer3D::kRawSizes)) {
01733       SetPoints(buffer.fPnts);
01734       if (!buffer.fLocalFrame) {
01735          TransformPoints(buffer.fPnts, buffer.NbPnts());
01736       }
01737       SetSegsAndPols(buffer);  
01738       buffer.SetSectionsValid(TBuffer3D::kRaw);
01739    }
01740       
01741    return buffer;
01742 }

Generated on Tue Jul 5 14:12:58 2011 for ROOT_528-00b_version by  doxygen 1.5.1