TGeoTube.cxx

Go to the documentation of this file.
00001 // @(#)root/geom:$Id: TGeoTube.cxx 27731 2009-03-09 17:40:56Z brun $
00002 // Author: Andrei Gheata   24/10/01
00003 // TGeoTube::Contains() and DistFromInside/In() 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 // TGeoTube - cylindrical tube class. It takes 3 parameters :
00015 //            inner radius, outer radius and half-length dz.
00016 //
00017 //_____________________________________________________________________________
00018 //Begin_Html
00019 /*
00020 <img src="gif/t_tube.gif">
00021 */
00022 //End_Html
00023 //Begin_Html
00024 /*
00025 <img src="gif/t_tubedivR.gif">
00026 */
00027 //End_Html
00028 //Begin_Html
00029 /*
00030 <img src="gif/t_tubedivstepR.gif">
00031 */
00032 //End_Html
00033 //Begin_Html
00034 /*
00035 <img src="gif/t_tubedivPHI.gif">
00036 */
00037 //End_Html
00038 //Begin_Html
00039 /*
00040 <img src="gif/t_tubedivstepPHI.gif">
00041 */
00042 //End_Html
00043 //Begin_Html
00044 /*
00045 <img src="gif/t_tubedivZ.gif">
00046 */
00047 //End_Html
00048 //Begin_Html
00049 /*
00050 <img src="gif/t_tubedivstepZ.gif">
00051 */
00052 //End_Html
00053 //_____________________________________________________________________________
00054 // TGeoTubeSeg - a phi segment of a tube. Has 5 parameters :
00055 //            - the same 3 as a tube;
00056 //            - first phi limit (in degrees)
00057 //            - second phi limit
00058 //
00059 //_____________________________________________________________________________
00060 //Begin_Html
00061 /*
00062 <img src="gif/t_tubseg.gif">
00063 */
00064 //End_Html
00065 //Begin_Html
00066 /*
00067 <img src="gif/t_tubsegdivstepR.gif">
00068 */
00069 //End_Html
00070 //Begin_Html
00071 /*
00072 <img src="gif/t_tubsegdivPHI.gif">
00073 */
00074 //End_Html
00075 //Begin_Html
00076 /*
00077 <img src="gif/t_tubsegdivZ.gif">
00078 */
00079 //End_Html
00080 //_____________________________________________________________________________
00081 // TGeoCtub - a tube segment cut with 2 planes. Has 11 parameters :
00082 //            - the same 5 as a tube segment;
00083 //            - x, y, z components of the normal to the -dZ cut plane in
00084 //              point (0, 0, -dZ);
00085 //            - x, y, z components of the normal to the +dZ cut plane in
00086 //              point (0, 0, dZ);
00087 //
00088 //_____________________________________________________________________________
00089 //Begin_Html
00090 /*
00091 <img src="gif/t_ctub.gif">
00092 */
00093 //End_Html
00094 
00095 #include "Riostream.h"
00096 
00097 #include "TGeoManager.h"
00098 #include "TGeoVolume.h"
00099 #include "TVirtualGeoPainter.h"
00100 #include "TGeoTube.h"
00101 #include "TVirtualPad.h"
00102 #include "TBuffer3D.h"
00103 #include "TBuffer3DTypes.h"
00104 #include "TMath.h"
00105 
00106 ClassImp(TGeoTube)
00107 
00108 //_____________________________________________________________________________
00109 TGeoTube::TGeoTube()
00110 {
00111 // Default constructor
00112    SetShapeBit(TGeoShape::kGeoTube);
00113    fRmin = 0.0;
00114    fRmax = 0.0;
00115    fDz   = 0.0;
00116 }
00117 
00118 
00119 //_____________________________________________________________________________
00120 TGeoTube::TGeoTube(Double_t rmin, Double_t rmax, Double_t dz)
00121            :TGeoBBox(0, 0, 0)
00122 {
00123 // Default constructor specifying minimum and maximum radius
00124    SetShapeBit(TGeoShape::kGeoTube);
00125    SetTubeDimensions(rmin, rmax, dz);
00126    if ((fDz<0) || (fRmin<0) || (fRmax<0)) {
00127       SetShapeBit(kGeoRunTimeShape);
00128 //      if (fRmax<=fRmin) SetShapeBit(kGeoInvalidShape);
00129 //      printf("tube : dz=%f rmin=%f rmax=%f\n", dz, rmin, rmax);
00130    }
00131    ComputeBBox();
00132 }
00133 //_____________________________________________________________________________
00134 TGeoTube::TGeoTube(const char *name, Double_t rmin, Double_t rmax, Double_t dz)
00135            :TGeoBBox(name, 0, 0, 0)
00136 {
00137 // Default constructor specifying minimum and maximum radius
00138    SetShapeBit(TGeoShape::kGeoTube);
00139    SetTubeDimensions(rmin, rmax, dz);
00140    if ((fDz<0) || (fRmin<0) || (fRmax<0)) {
00141       SetShapeBit(kGeoRunTimeShape);
00142 //      if (fRmax<=fRmin) SetShapeBit(kGeoInvalidShape);
00143 //      printf("tube : dz=%f rmin=%f rmax=%f\n", dz, rmin, rmax);
00144    }
00145    ComputeBBox();
00146 }
00147 
00148 //_____________________________________________________________________________
00149 TGeoTube::TGeoTube(Double_t *param)
00150          :TGeoBBox(0, 0, 0)
00151 {
00152 // Default constructor specifying minimum and maximum radius
00153 // param[0] = Rmin
00154 // param[1] = Rmax
00155 // param[2] = dz
00156    SetShapeBit(TGeoShape::kGeoTube);
00157    SetDimensions(param);
00158    if ((fDz<0) || (fRmin<0) || (fRmax<0)) SetShapeBit(kGeoRunTimeShape);
00159    ComputeBBox();
00160 }
00161 
00162 //_____________________________________________________________________________
00163 TGeoTube::~TGeoTube()
00164 {
00165 // destructor
00166 }
00167 
00168 //_____________________________________________________________________________
00169 Double_t TGeoTube::Capacity() const
00170 {
00171 // Computes capacity of the shape in [length^3]
00172    return TGeoTube::Capacity(fRmin,fRmax, fDz);
00173 }   
00174 
00175 //_____________________________________________________________________________
00176 Double_t TGeoTube::Capacity(Double_t rmin, Double_t rmax, Double_t dz)
00177 {
00178 // Computes capacity of the shape in [length^3]
00179    Double_t capacity = 2.*TMath::Pi()*(rmax*rmax-rmin*rmin)*dz;
00180    return capacity;
00181 }   
00182 
00183 //_____________________________________________________________________________
00184 void TGeoTube::ComputeBBox()
00185 {
00186 // compute bounding box of the tube
00187    fDX = fDY = fRmax;
00188    fDZ = fDz;
00189 }
00190 
00191 //_____________________________________________________________________________
00192 void TGeoTube::ComputeNormal(Double_t *point, Double_t *dir, Double_t *norm)
00193 {
00194 // Compute normal to closest surface from POINT.
00195    Double_t saf[3];
00196    Double_t rsq = point[0]*point[0]+point[1]*point[1];
00197    Double_t r = TMath::Sqrt(rsq);
00198    saf[0] = TMath::Abs(fDz-TMath::Abs(point[2]));
00199    saf[1] = (fRmin>1E-10)?TMath::Abs(r-fRmin):TGeoShape::Big();
00200    saf[2] = TMath::Abs(fRmax-r);
00201    Int_t i = TMath::LocMin(3,saf);
00202    if (i==0) {
00203       norm[0] = norm[1] = 0.;
00204       norm[2] = TMath::Sign(1.,dir[2]);
00205       return;
00206    }
00207    norm[2] = 0;
00208    Double_t phi = TMath::ATan2(point[1], point[0]);
00209    norm[0] = TMath::Cos(phi);
00210    norm[1] = TMath::Sin(phi);
00211    if (norm[0]*dir[0]+norm[1]*dir[1]<0) {
00212       norm[0] = -norm[0];
00213       norm[1] = -norm[1];
00214    }
00215 }
00216 
00217 //_____________________________________________________________________________
00218 void TGeoTube::ComputeNormalS(Double_t *point, Double_t *dir, Double_t *norm,
00219                               Double_t /*rmin*/, Double_t /*rmax*/, Double_t /*dz*/)
00220 {
00221 // Compute normal to closest surface from POINT.
00222    norm[2] = 0;
00223    Double_t phi = TMath::ATan2(point[1], point[0]);
00224    norm[0] = TMath::Cos(phi);
00225    norm[1] = TMath::Sin(phi);
00226    if (norm[0]*dir[0]+norm[1]*dir[1]<0) {
00227       norm[0] = -norm[0];
00228       norm[1] = -norm[1];
00229    }
00230 }
00231 
00232 //_____________________________________________________________________________
00233 Bool_t TGeoTube::Contains(Double_t *point) const
00234 {
00235 // test if point is inside this tube
00236    if (TMath::Abs(point[2]) > fDz) return kFALSE;
00237    Double_t r2 = point[0]*point[0]+point[1]*point[1];
00238    if ((r2<fRmin*fRmin) || (r2>fRmax*fRmax)) return kFALSE;
00239    return kTRUE;
00240 }
00241 
00242 //_____________________________________________________________________________
00243 Int_t TGeoTube::DistancetoPrimitive(Int_t px, Int_t py)
00244 {
00245 // compute closest distance from point px,py to each corner
00246    Int_t n = gGeoManager->GetNsegments();
00247    Int_t numPoints = 4*n;
00248    if (!HasRmin()) numPoints = 2*(n+1);
00249    return ShapeDistancetoPrimitive(numPoints, px, py);
00250 }
00251 
00252 //_____________________________________________________________________________
00253 Double_t TGeoTube::DistFromInsideS(Double_t *point, Double_t *dir, Double_t rmin, Double_t rmax, Double_t dz)
00254 {
00255 // Compute distance from inside point to surface of the tube (static)
00256 // Boundary safe algorithm.
00257    // compute distance to surface
00258    // Do Z
00259    Double_t sz = TGeoShape::Big();
00260    if (dir[2]) {
00261       sz = (TMath::Sign(dz, dir[2])-point[2])/dir[2];
00262       if (sz<=0) return 0.0;
00263    }
00264    // Do R
00265    Double_t nsq=dir[0]*dir[0]+dir[1]*dir[1];
00266    if (TMath::Abs(nsq)<TGeoShape::Tolerance()) return sz;
00267    Double_t rsq=point[0]*point[0]+point[1]*point[1];
00268    Double_t rdotn=point[0]*dir[0]+point[1]*dir[1];
00269    Double_t b,d;
00270    Double_t sr = TGeoShape::Big();
00271    // inner cylinder
00272    if (rmin>0) {
00273       // Protection in case point is actually outside the tube
00274       if (rsq <= rmin*rmin+TGeoShape::Tolerance()) {
00275          if (rdotn<0) return 0.0;
00276       } else {
00277          if (rdotn<0) {
00278             DistToTube(rsq,nsq,rdotn,rmin,b,d);
00279             if (d>0) {
00280                sr=-b-d;
00281                if (sr>0) return TMath::Min(sz,sr);
00282             }
00283          }
00284       }
00285    }
00286    // outer cylinder
00287    if (rsq >= rmax*rmax-TGeoShape::Tolerance()) {
00288       if (rdotn>=0) return 0.0;
00289    }
00290    DistToTube(rsq,nsq,rdotn,rmax,b,d);
00291    if (d>0) {
00292       sr=-b+d;
00293       if (sr>0) return TMath::Min(sz,sr);
00294    }
00295    return 0.;
00296 }
00297 
00298 //_____________________________________________________________________________
00299 Double_t TGeoTube::DistFromInside(Double_t *point, Double_t *dir, Int_t iact, Double_t step, Double_t *safe) const
00300 {
00301 // Compute distance from inside point to surface of the tube
00302 // Boundary safe algorithm.
00303    if (iact<3 && safe) {
00304       *safe = Safety(point, kTRUE);
00305       if (iact==0) return TGeoShape::Big();
00306       if ((iact==1) && (*safe>step)) return TGeoShape::Big();
00307    }
00308    // compute distance to surface
00309    return DistFromInsideS(point, dir, fRmin, fRmax, fDz);
00310 }
00311 
00312 //_____________________________________________________________________________
00313 Double_t TGeoTube::DistFromOutsideS(Double_t *point, Double_t *dir, Double_t rmin, Double_t rmax, Double_t dz)
00314 {
00315 // Static method to compute distance from outside point to a tube with given parameters
00316 // Boundary safe algorithm.
00317    // check Z planes
00318    Double_t xi,yi,zi;
00319    Double_t rmaxsq = rmax*rmax;
00320    Double_t rminsq = rmin*rmin;
00321    zi = dz - TMath::Abs(point[2]);
00322    Double_t s = TGeoShape::Big();
00323    Bool_t in = kFALSE;
00324    Bool_t inz = (zi<0)?kFALSE:kTRUE;
00325    if (!inz) {
00326       if (point[2]*dir[2]>=0) return TGeoShape::Big();
00327       s  = -zi/TMath::Abs(dir[2]);
00328       xi = point[0]+s*dir[0];
00329       yi = point[1]+s*dir[1];
00330       Double_t r2=xi*xi+yi*yi;
00331       if ((rminsq<=r2) && (r2<=rmaxsq)) return s;
00332    }
00333 
00334    Double_t rsq = point[0]*point[0]+point[1]*point[1];
00335    // check outer cyl. surface
00336    Double_t nsq=dir[0]*dir[0]+dir[1]*dir[1];
00337    Double_t rdotn=point[0]*dir[0]+point[1]*dir[1];
00338    Double_t b,d;
00339    Bool_t inrmax = kFALSE;
00340    Bool_t inrmin = kFALSE;
00341    if (rsq<=rmaxsq+TGeoShape::Tolerance()) inrmax = kTRUE;
00342    if (rsq>=rminsq-TGeoShape::Tolerance()) inrmin = kTRUE;
00343    in = inz & inrmin & inrmax;
00344    // If inside, we are most likely on a boundary within machine precision.
00345    if (in) {
00346       Bool_t checkout = kFALSE;
00347       Double_t r = TMath::Sqrt(rsq);
00348       if (zi<rmax-r) {
00349          if ((TGeoShape::IsSameWithinTolerance(rmin,0)) || (zi<r-rmin)) {
00350             if (point[2]*dir[2]<0) return 0.0;
00351             return TGeoShape::Big();
00352          }
00353       }
00354       if ((rmaxsq-rsq) < (rsq-rminsq)) checkout = kTRUE;
00355       if (checkout) {
00356          if (rdotn>=0) return TGeoShape::Big();
00357          return 0.0;
00358       }
00359       if (TGeoShape::IsSameWithinTolerance(rmin,0)) return 0.0;
00360       if (rdotn>=0) return 0.0;
00361       // Ray exiting rmin -> check (+) solution for inner tube
00362       if (TMath::Abs(nsq)<TGeoShape::Tolerance()) return TGeoShape::Big();
00363       DistToTube(rsq, nsq, rdotn, rmin, b, d);
00364       if (d>0) {
00365          s=-b+d;
00366          if (s>0) {
00367             zi=point[2]+s*dir[2];
00368             if (TMath::Abs(zi)<=dz) return s;
00369          }
00370       }
00371       return TGeoShape::Big();
00372    }
00373    // Check outer cylinder (only r>rmax has to be considered)
00374    if (TMath::Abs(nsq)<TGeoShape::Tolerance()) return TGeoShape::Big();
00375    if (!inrmax) {
00376       DistToTube(rsq, nsq, rdotn, rmax, b, d);
00377       if (d>0) {
00378          s=-b-d;
00379          if (s>0) {
00380             zi=point[2]+s*dir[2];
00381             if (TMath::Abs(zi)<=dz) return s;
00382          }
00383       }
00384    }
00385    // check inner cylinder
00386    if (rmin>0) {
00387       DistToTube(rsq, nsq, rdotn, rmin, b, d);
00388       if (d>0) {
00389          s=-b+d;
00390          if (s>0) {
00391             zi=point[2]+s*dir[2];
00392             if (TMath::Abs(zi)<=dz) return s;
00393          }
00394       }
00395    }
00396    return TGeoShape::Big();
00397 }
00398 
00399 //_____________________________________________________________________________
00400 Double_t TGeoTube::DistFromOutside(Double_t *point, Double_t *dir, Int_t iact, Double_t step, Double_t *safe) const
00401 {
00402 // Compute distance from outside point to surface of the tube and safe distance
00403 // Boundary safe algorithm.
00404    // fist localize point w.r.t tube
00405    if (iact<3 && safe) {
00406       *safe = Safety(point, kFALSE);
00407       if (iact==0) return TGeoShape::Big();
00408       if ((iact==1) && (step<=*safe)) return TGeoShape::Big();
00409    }
00410 // Check if the bounding box is crossed within the requested distance
00411    Double_t sdist = TGeoBBox::DistFromOutside(point,dir, fDX, fDY, fDZ, fOrigin, step);
00412    if (sdist>=step) return TGeoShape::Big();
00413    // find distance to shape
00414    return DistFromOutsideS(point, dir, fRmin, fRmax, fDz);
00415 }
00416 
00417 //_____________________________________________________________________________
00418 void TGeoTube::DistToTube(Double_t rsq, Double_t nsq, Double_t rdotn, Double_t radius, Double_t &b, Double_t &delta)
00419 {
00420 // Static method computing the distance to a tube with given radius, starting from
00421 // POINT along DIR director cosines. The distance is computed as :
00422 //    RSQ   = point[0]*point[0]+point[1]*point[1]
00423 //    NSQ   = dir[0]*dir[0]+dir[1]*dir[1]  ---> should NOT be 0 !!!
00424 //    RDOTN = point[0]*dir[0]+point[1]*dir[1]
00425 // The distance can be computed as :
00426 //    D = -B +/- DELTA
00427 // where DELTA.GT.0 and D.GT.0
00428 
00429    Double_t t1 = 1./nsq;
00430    Double_t t3=rsq-(radius*radius);
00431    b          = t1*rdotn;
00432    Double_t c =t1*t3;
00433    delta = b*b-c;
00434    if (delta>0) {
00435       delta=TMath::Sqrt(delta);
00436    } else {
00437       delta = -1;
00438    }
00439 }
00440 
00441 //_____________________________________________________________________________
00442 TGeoVolume *TGeoTube::Divide(TGeoVolume *voldiv, const char *divname, Int_t iaxis, Int_t ndiv,
00443                              Double_t start, Double_t step)
00444 {
00445 //--- Divide this tube shape belonging to volume "voldiv" into ndiv volumes
00446 // called divname, from start position with the given step. Returns pointer
00447 // to created division cell volume in case of Z divisions. For radial division
00448 // creates all volumes with different shapes and returns pointer to volume that
00449 // was divided. In case a wrong division axis is supplied, returns pointer to
00450 // volume that was divided.
00451    TGeoShape *shape;           //--- shape to be created
00452    TGeoVolume *vol;            //--- division volume to be created
00453    TGeoVolumeMulti *vmulti;    //--- generic divided volume
00454    TGeoPatternFinder *finder;  //--- finder to be attached
00455    TString opt = "";           //--- option to be attached
00456    Int_t id;
00457    Double_t end = start+ndiv*step;
00458    switch (iaxis) {
00459       case 1:  //---                R division
00460          finder = new TGeoPatternCylR(voldiv, ndiv, start, end);
00461          vmulti = gGeoManager->MakeVolumeMulti(divname, voldiv->GetMedium());
00462          voldiv->SetFinder(finder);
00463          finder->SetDivIndex(voldiv->GetNdaughters());
00464          for (id=0; id<ndiv; id++) {
00465             shape = new TGeoTube(start+id*step, start+(id+1)*step, fDz);
00466             vol = new TGeoVolume(divname, shape, voldiv->GetMedium());
00467             vmulti->AddVolume(vol);
00468             opt = "R";
00469             voldiv->AddNodeOffset(vol, id, 0, opt.Data());
00470             ((TGeoNodeOffset*)voldiv->GetNodes()->At(voldiv->GetNdaughters()-1))->SetFinder(finder);
00471          }
00472          return vmulti;
00473       case 2:  //---                Phi division
00474          finder = new TGeoPatternCylPhi(voldiv, ndiv, start, end);
00475          voldiv->SetFinder(finder);
00476          finder->SetDivIndex(voldiv->GetNdaughters());
00477          shape = new TGeoTubeSeg(fRmin, fRmax, fDz, -step/2, step/2);
00478          vol = new TGeoVolume(divname, shape, voldiv->GetMedium());
00479          vmulti = gGeoManager->MakeVolumeMulti(divname, voldiv->GetMedium());
00480          vmulti->AddVolume(vol);
00481          opt = "Phi";
00482          for (id=0; id<ndiv; id++) {
00483             voldiv->AddNodeOffset(vol, id, start+id*step+step/2, opt.Data());
00484             ((TGeoNodeOffset*)voldiv->GetNodes()->At(voldiv->GetNdaughters()-1))->SetFinder(finder);
00485          }
00486          return vmulti;
00487       case 3: //---                  Z division
00488          finder = new TGeoPatternZ(voldiv, ndiv, start, start+ndiv*step);
00489          voldiv->SetFinder(finder);
00490          finder->SetDivIndex(voldiv->GetNdaughters());
00491          shape = new TGeoTube(fRmin, fRmax, step/2);
00492          vol = new TGeoVolume(divname, shape, voldiv->GetMedium());
00493          vmulti = gGeoManager->MakeVolumeMulti(divname, voldiv->GetMedium());
00494          vmulti->AddVolume(vol);
00495          opt = "Z";
00496          for (id=0; id<ndiv; id++) {
00497             voldiv->AddNodeOffset(vol, id, start+step/2+id*step, opt.Data());
00498             ((TGeoNodeOffset*)voldiv->GetNodes()->At(voldiv->GetNdaughters()-1))->SetFinder(finder);
00499          }
00500          return vmulti;
00501       default:
00502          Error("Divide", "In shape %s wrong axis type for division", GetName());
00503          return 0;
00504    }
00505 }
00506 
00507 //_____________________________________________________________________________
00508 const char *TGeoTube::GetAxisName(Int_t iaxis) const
00509 {
00510 // Returns name of axis IAXIS.
00511    switch (iaxis) {
00512       case 1:
00513          return "R";
00514       case 2:
00515          return "PHI";
00516       case 3:
00517          return "Z";
00518       default:
00519          return "UNDEFINED";
00520    }
00521 }
00522 
00523 //_____________________________________________________________________________
00524 Double_t TGeoTube::GetAxisRange(Int_t iaxis, Double_t &xlo, Double_t &xhi) const
00525 {
00526 // Get range of shape for a given axis.
00527    xlo = 0;
00528    xhi = 0;
00529    Double_t dx = 0;
00530    switch (iaxis) {
00531       case 1:
00532          xlo = fRmin;
00533          xhi = fRmax;
00534          dx = xhi-xlo;
00535          return dx;
00536       case 2:
00537          xlo = 0;
00538          xhi = 360;
00539          dx = 360;
00540          return dx;
00541       case 3:
00542          xlo = -fDz;
00543          xhi = fDz;
00544          dx = xhi-xlo;
00545          return dx;
00546    }
00547    return dx;
00548 }
00549 
00550 //_____________________________________________________________________________
00551 void TGeoTube::GetBoundingCylinder(Double_t *param) const
00552 {
00553 //--- Fill vector param[4] with the bounding cylinder parameters. The order
00554 // is the following : Rmin, Rmax, Phi1, Phi2, dZ
00555    param[0] = fRmin; // Rmin
00556    param[0] *= param[0];
00557    param[1] = fRmax; // Rmax
00558    param[1] *= param[1];
00559    param[2] = 0.;    // Phi1
00560    param[3] = 360.;  // Phi1
00561 }
00562 
00563 //_____________________________________________________________________________
00564 TGeoShape *TGeoTube::GetMakeRuntimeShape(TGeoShape *mother, TGeoMatrix * /*mat*/) const
00565 {
00566 // in case shape has some negative parameters, these has to be computed
00567 // in order to fit the mother
00568    if (!TestShapeBit(kGeoRunTimeShape)) return 0;
00569    Double_t rmin, rmax, dz;
00570    Double_t xmin,xmax;
00571    rmin = fRmin;
00572    rmax = fRmax;
00573    dz = fDz;
00574    if (fDz<0) {
00575       mother->GetAxisRange(3,xmin,xmax);
00576       if (xmax<0) return 0;
00577       dz=xmax;
00578    }
00579    mother->GetAxisRange(1,xmin,xmax);
00580    if (fRmin<0) {
00581       if (xmin<0) return 0;
00582       rmin = xmin;
00583    }
00584    if (fRmax<0) {
00585       if (xmax<=0) return 0;
00586       rmax = xmax;
00587    }
00588 
00589    return (new TGeoTube(GetName(), rmin, rmax, dz));
00590 }
00591 
00592 //_____________________________________________________________________________
00593 void TGeoTube::InspectShape() const
00594 {
00595 // print shape parameters
00596    printf("*** Shape %s: TGeoTube ***\n", GetName());
00597    printf("    Rmin = %11.5f\n", fRmin);
00598    printf("    Rmax = %11.5f\n", fRmax);
00599    printf("    dz   = %11.5f\n", fDz);
00600    printf(" Bounding box:\n");
00601    TGeoBBox::InspectShape();
00602 }
00603 
00604 //_____________________________________________________________________________
00605 TBuffer3D *TGeoTube::MakeBuffer3D() const
00606 {
00607    // Creates a TBuffer3D describing *this* shape.
00608    // Coordinates are in local reference frame.
00609 
00610    Int_t n = gGeoManager->GetNsegments();
00611    Int_t nbPnts = 4*n;
00612    Int_t nbSegs = 8*n;
00613    Int_t nbPols = 4*n;
00614    if (!HasRmin()) {
00615       nbPnts = 2*(n+1);
00616       nbSegs = 5*n;
00617       nbPols = 3*n;
00618    }   
00619    TBuffer3D* buff = new TBuffer3D(TBuffer3DTypes::kGeneric,
00620                                    nbPnts, 3*nbPnts, nbSegs, 3*nbSegs, nbPols, 6*nbPols);
00621    if (buff)
00622    {
00623       SetPoints(buff->fPnts);
00624       SetSegsAndPols(*buff);
00625    }
00626 
00627    return buff;
00628 }
00629 
00630 //_____________________________________________________________________________
00631 void TGeoTube::SetSegsAndPols(TBuffer3D &buffer) const
00632 {
00633 // Fill TBuffer3D structure for segments and polygons.
00634    Int_t i, j,indx;
00635    Int_t n = gGeoManager->GetNsegments();
00636    Int_t c = (((buffer.fColor) %8) -1) * 4;
00637    if (c < 0) c = 0;
00638 
00639    if (HasRmin()) {
00640       // circle segments:
00641       // lower rmin circle: i=0, (0, n-1)
00642       // lower rmax circle: i=1, (n, 2n-1)
00643       // upper rmin circle: i=2, (2n, 3n-1)
00644       // upper rmax circle: i=1, (3n, 4n-1)
00645       for (i = 0; i < 4; i++) {
00646          for (j = 0; j < n; j++) {
00647             indx = 3*(i*n+j);
00648             buffer.fSegs[indx  ] = c;
00649             buffer.fSegs[indx+1] = i*n+j;
00650             buffer.fSegs[indx+2] = i*n+(j+1)%n;
00651          }
00652       }
00653       // Z-parallel segments
00654       // inner: i=4, (4n, 5n-1)
00655       // outer: i=5, (5n, 6n-1)
00656       for (i = 4; i < 6; i++) {
00657          for (j = 0; j < n; j++) {
00658             indx = 3*(i*n+j);
00659             buffer.fSegs[indx  ] = c+1;
00660             buffer.fSegs[indx+1] = (i-4)*n+j;
00661             buffer.fSegs[indx+2] = (i-2)*n+j;
00662          }
00663       }
00664       // Radial segments
00665       // lower: i=6, (6n, 7n-1)
00666       // upper: i=7, (7n, 8n-1)
00667       for (i = 6; i < 8; i++) {
00668          for (j = 0; j < n; j++) {
00669             indx = 3*(i*n+j);
00670             buffer.fSegs[indx  ] = c;
00671             buffer.fSegs[indx+1] = 2*(i-6)*n+j;
00672             buffer.fSegs[indx+2] = (2*(i-6)+1)*n+j;
00673          }
00674       }
00675       // Polygons
00676       i=0;
00677       // Inner lateral (0, n-1)
00678       for (j = 0; j < n; j++) {
00679          indx = 6*(i*n+j);
00680          buffer.fPols[indx  ] = c;
00681          buffer.fPols[indx+1] = 4;
00682          buffer.fPols[indx+2] = j;
00683          buffer.fPols[indx+3] = 4*n+(j+1)%n;
00684          buffer.fPols[indx+4] = 2*n+j;
00685          buffer.fPols[indx+5] = 4*n+j;
00686       }
00687       i=1;
00688       // Outer lateral (n,2n-1)
00689       for (j = 0; j < n; j++) {
00690          indx = 6*(i*n+j);
00691          buffer.fPols[indx  ] = c+1;
00692          buffer.fPols[indx+1] = 4;
00693          buffer.fPols[indx+2] = n+j;
00694          buffer.fPols[indx+3] = 5*n+j;
00695          buffer.fPols[indx+4] = 3*n+j;
00696          buffer.fPols[indx+5] = 5*n+(j+1)%n;
00697       }
00698       i=2;
00699       // lower disc (2n, 3n-1)
00700       for (j = 0; j < n; j++) {
00701          indx = 6*(i*n+j);
00702          buffer.fPols[indx  ] = c;
00703          buffer.fPols[indx+1] = 4;
00704          buffer.fPols[indx+2] = j;
00705          buffer.fPols[indx+3] = 6*n+j;
00706          buffer.fPols[indx+4] = n+j;
00707          buffer.fPols[indx+5] = 6*n+(j+1)%n;
00708       }
00709       i=3;
00710       // upper disc (3n, 4n-1)
00711       for (j = 0; j < n; j++) {
00712          indx = 6*(i*n+j);
00713          buffer.fPols[indx  ] = c;
00714          buffer.fPols[indx+1] = 4;
00715          buffer.fPols[indx+2] = 2*n+j;
00716          buffer.fPols[indx+3] = 7*n+(j+1)%n;
00717          buffer.fPols[indx+4] = 3*n+j;
00718          buffer.fPols[indx+5] = 7*n+j;
00719       }
00720       return;
00721    }
00722    // Rmin=0 tubes
00723    // circle segments
00724    // lower rmax circle: i=0, (0, n-1)
00725    // upper rmax circle: i=1, (n, 2n-1)
00726    for (i = 0; i < 2; i++) {
00727       for (j = 0; j < n; j++) {
00728          indx = 3*(i*n+j);
00729          buffer.fSegs[indx  ] = c;
00730          buffer.fSegs[indx+1] = 2+i*n+j;
00731          buffer.fSegs[indx+2] = 2+i*n+(j+1)%n;
00732       }
00733    }
00734    // Z-parallel segments (2n,3n-1)
00735    for (j = 0; j < n; j++) {
00736       indx = 3*(2*n+j);
00737       buffer.fSegs[indx  ] = c+1;
00738       buffer.fSegs[indx+1] = 2+j;
00739       buffer.fSegs[indx+2] = 2+n+j;
00740    }
00741    // Radial segments
00742    // Lower circle: i=3, (3n,4n-1)
00743    // Upper circle: i=4, (4n,5n-1)
00744    for (i = 3; i < 5; i++) {
00745       for (j = 0; j < n; j++) {
00746          indx = 3*(i*n+j);
00747          buffer.fSegs[indx  ] = c;
00748          buffer.fSegs[indx+1] = i-3;
00749          buffer.fSegs[indx+2] = 2+(i-3)*n+j;
00750       }
00751    }
00752    // Polygons
00753    // lateral (0,n-1)
00754    for (j = 0; j < n; j++) {
00755       indx = 6*j;
00756       buffer.fPols[indx  ] = c+1;
00757       buffer.fPols[indx+1] = 4;
00758       buffer.fPols[indx+2] = j;
00759       buffer.fPols[indx+3] = 2*n+j;
00760       buffer.fPols[indx+4] = n+j;
00761       buffer.fPols[indx+5] = 2*n+(j+1)%n;
00762    }
00763    // bottom triangles (n,2n-1)
00764    for (j = 0; j < n; j++) {
00765       indx = 6*n + 5*j;
00766       buffer.fPols[indx  ] = c;
00767       buffer.fPols[indx+1] = 3;
00768       buffer.fPols[indx+2] = j;
00769       buffer.fPols[indx+3] = 3*n+(j+1)%n;
00770       buffer.fPols[indx+4] = 3*n+j;
00771    }
00772    // top triangles (2n,3n-1)  
00773    for (j = 0; j < n; j++) {
00774       indx = 6*n + 5*n + 5*j;
00775       buffer.fPols[indx  ] = c;
00776       buffer.fPols[indx+1] = 3;
00777       buffer.fPols[indx+2] = n+j;
00778       buffer.fPols[indx+3] = 4*n+j;
00779       buffer.fPols[indx+4] = 4*n+(j+1)%n;
00780    }
00781 }
00782 
00783 //_____________________________________________________________________________
00784 Double_t TGeoTube::Safety(Double_t *point, Bool_t in) const
00785 {
00786 // computes the closest distance from given point to this shape, according
00787 // to option. The matching point on the shape is stored in spoint.
00788 #ifndef NEVER
00789    Double_t r = TMath::Sqrt(point[0]*point[0]+point[1]*point[1]);
00790    Double_t safe, safrmin, safrmax;
00791    if (in) {
00792       safe    = fDz-TMath::Abs(point[2]); // positive if inside
00793       if (fRmin>1E-10) {
00794          safrmin = r-fRmin;
00795          if (safrmin < safe) safe = safrmin;
00796       }
00797       safrmax = fRmax-r;
00798       if (safrmax < safe) safe = safrmax;
00799    } else {
00800       safe    = -fDz+TMath::Abs(point[2]);
00801       if (fRmin>1E-10) {
00802          safrmin = -r+fRmin;
00803          if (safrmin > safe) safe = safrmin;
00804       }
00805       safrmax = -fRmax+r;
00806       if (safrmax > safe) safe = safrmax;
00807    }
00808    return safe;
00809 #else
00810    Double_t saf[3];
00811    Double_t rsq = point[0]*point[0]+point[1]*point[1];
00812    Double_t r = TMath::Sqrt(rsq);
00813    saf[0] = fDz-TMath::Abs(point[2]); // positive if inside
00814    saf[1] = (fRmin>1E-10)?(r-fRmin):TGeoShape::Big();
00815    saf[2] = fRmax-r;
00816    if (in) return saf[TMath::LocMin(3,saf)];
00817    for (Int_t i=0; i<3; i++) saf[i]=-saf[i];
00818    return saf[TMath::LocMax(3,saf)];
00819 #endif
00820 }
00821 
00822 //_____________________________________________________________________________
00823 Double_t TGeoTube::SafetyS(Double_t *point, Bool_t in, Double_t rmin, Double_t rmax, Double_t dz, Int_t skipz)
00824 {
00825 // computes the closest distance from given point to this shape, according
00826 // to option. The matching point on the shape is stored in spoint.
00827    Double_t saf[3];
00828    Double_t rsq = point[0]*point[0]+point[1]*point[1];
00829    Double_t r = TMath::Sqrt(rsq);
00830    switch (skipz) {
00831       case 1: // skip lower Z plane
00832          saf[0] = dz - point[2];
00833          break;
00834       case 2: // skip upper Z plane
00835          saf[0] = dz + point[2];
00836          break;
00837       case 3: // skip both
00838          saf[0] = TGeoShape::Big();
00839          break;
00840       default:
00841          saf[0] = dz-TMath::Abs(point[2]);
00842    }
00843    saf[1] = (rmin>1E-10)?(r-rmin):TGeoShape::Big();
00844    saf[2] = rmax-r;
00845 //   printf("saf0=%g saf1=%g saf2=%g in=%d skipz=%d\n", saf[0],saf[1],saf[2],in,skipz);
00846    if (in) return saf[TMath::LocMin(3,saf)];
00847    for (Int_t i=0; i<3; i++) saf[i]=-saf[i];
00848    return saf[TMath::LocMax(3,saf)];
00849 }
00850 
00851 //_____________________________________________________________________________
00852 void TGeoTube::SavePrimitive(ostream &out, Option_t * /*option*/ /*= ""*/)
00853 {
00854 // Save a primitive as a C++ statement(s) on output stream "out".
00855    if (TObject::TestBit(kGeoSavePrimitive)) return;
00856    out << "   // Shape: " << GetName() << " type: " << ClassName() << endl;
00857    out << "   rmin = " << fRmin << ";" << endl;
00858    out << "   rmax = " << fRmax << ";" << endl;
00859    out << "   dz   = " << fDz << ";" << endl;
00860    out << "   TGeoShape *" << GetPointerName() << " = new TGeoTube(\"" << GetName() << "\",rmin,rmax,dz);" << endl;
00861    TObject::SetBit(TGeoShape::kGeoSavePrimitive);
00862 }
00863 
00864 //_____________________________________________________________________________
00865 void TGeoTube::SetTubeDimensions(Double_t rmin, Double_t rmax, Double_t dz)
00866 {
00867 // Set tube dimensions.
00868    fRmin = rmin;
00869    fRmax = rmax;
00870    fDz   = dz;
00871    if (fRmin>0 && fRmax>0 && fRmin>=fRmax)
00872       Error("SetTubeDimensions", "In shape %s wrong rmin=%g rmax=%g", GetName(), rmin,rmax);
00873 }
00874 
00875 //_____________________________________________________________________________
00876 void TGeoTube::SetDimensions(Double_t *param)
00877 {
00878 // Set tube dimensions starting from a list.
00879    Double_t rmin = param[0];
00880    Double_t rmax = param[1];
00881    Double_t dz   = param[2];
00882    SetTubeDimensions(rmin, rmax, dz);
00883 }
00884 
00885 //_____________________________________________________________________________
00886 Bool_t TGeoTube::GetPointsOnSegments(Int_t npoints, Double_t *array) const
00887 {
00888 // Fills array with n random points located on the line segments of the shape mesh.
00889 // The output array must be provided with a length of minimum 3*npoints. Returns
00890 // true if operation is implemented.
00891    if (npoints > (npoints/2)*2) {
00892       Error("GetPointsOnSegments","Npoints must be even number");
00893       return kFALSE;
00894    }   
00895    Int_t nc = 0;
00896    if (HasRmin()) nc = (Int_t)TMath::Sqrt(0.5*npoints);
00897    else           nc = (Int_t)TMath::Sqrt(1.*npoints);
00898    Double_t dphi = TMath::TwoPi()/nc;
00899    Double_t phi = 0;
00900    Int_t ntop = 0;
00901    if (HasRmin()) ntop = npoints/2 - nc*(nc-1);
00902    else           ntop = npoints - nc*(nc-1);
00903    Double_t dz = 2*fDz/(nc-1);
00904    Double_t z = 0;
00905    Int_t icrt = 0;
00906    Int_t nphi = nc;
00907    // loop z sections
00908    for (Int_t i=0; i<nc; i++) {
00909       if (i == (nc-1)) nphi = ntop;
00910       z = -fDz + i*dz;
00911       // loop points on circle sections
00912       for (Int_t j=0; j<nphi; j++) {
00913          phi = j*dphi;
00914          if (HasRmin()) {
00915             array[icrt++] = fRmin * TMath::Cos(phi);
00916             array[icrt++] = fRmin * TMath::Sin(phi);
00917             array[icrt++] = z;
00918          }
00919          array[icrt++] = fRmax * TMath::Cos(phi);
00920          array[icrt++] = fRmax * TMath::Sin(phi);
00921          array[icrt++] = z;
00922       }
00923    }
00924    return kTRUE;
00925 }                    
00926 
00927 //_____________________________________________________________________________
00928 void TGeoTube::SetPoints(Double_t *points) const
00929 {
00930 // create tube mesh points
00931    Double_t dz;
00932    Int_t j, n;
00933    n = gGeoManager->GetNsegments();
00934    Double_t dphi = 360./n;
00935    Double_t phi = 0;
00936    dz = fDz;
00937    Int_t indx = 0;
00938    if (points) {
00939       if (HasRmin()) {
00940          // 4*n points
00941          // (0,n-1) lower rmin circle
00942          // (2n, 3n-1) upper rmin circle
00943          for (j = 0; j < n; j++) {
00944             phi = j*dphi*TMath::DegToRad();
00945             points[indx+6*n] = points[indx] = fRmin * TMath::Cos(phi);
00946             indx++;
00947             points[indx+6*n] = points[indx] = fRmin * TMath::Sin(phi);
00948             indx++;
00949             points[indx+6*n] = dz;
00950             points[indx]     =-dz;
00951             indx++;
00952          }   
00953          // (n, 2n-1) lower rmax circle
00954          // (3n, 4n-1) upper rmax circle
00955          for (j = 0; j < n; j++) {
00956             phi = j*dphi*TMath::DegToRad();
00957             points[indx+6*n] = points[indx] = fRmax * TMath::Cos(phi);
00958             indx++;
00959             points[indx+6*n] = points[indx] = fRmax * TMath::Sin(phi);
00960             indx++;
00961             points[indx+6*n]= dz;
00962             points[indx]    =-dz;
00963             indx++;
00964          }
00965       } else {
00966          // centers of lower/upper circles (0,1)
00967          points[indx++] = 0.;
00968          points[indx++] = 0.;
00969          points[indx++] = -dz;
00970          points[indx++] = 0.;
00971          points[indx++] = 0.;
00972          points[indx++] = dz;
00973          // lower rmax circle (2, 2+n-1)
00974          // upper rmax circle (2+n, 2+2n-1)
00975          for (j = 0; j < n; j++) {
00976             phi = j*dphi*TMath::DegToRad();
00977             points[indx+3*n] = points[indx] = fRmax * TMath::Cos(phi);
00978             indx++;
00979             points[indx+3*n] = points[indx] = fRmax * TMath::Sin(phi);
00980             indx++;
00981             points[indx+3*n]= dz;
00982             points[indx]    =-dz;
00983             indx++;
00984          }
00985       }   
00986    }
00987 }
00988 
00989 //_____________________________________________________________________________
00990 void TGeoTube::SetPoints(Float_t *points) const
00991 {
00992 // create tube mesh points
00993    Double_t dz;
00994    Int_t j, n;
00995    n = gGeoManager->GetNsegments();
00996    Double_t dphi = 360./n;
00997    Double_t phi = 0;
00998    dz = fDz;
00999    Int_t indx = 0;
01000    if (points) {
01001       if (HasRmin()) {
01002          // 4*n points
01003          // (0,n-1) lower rmin circle
01004          // (2n, 3n-1) upper rmin circle
01005          for (j = 0; j < n; j++) {
01006             phi = j*dphi*TMath::DegToRad();
01007             points[indx+6*n] = points[indx] = fRmin * TMath::Cos(phi);
01008             indx++;
01009             points[indx+6*n] = points[indx] = fRmin * TMath::Sin(phi);
01010             indx++;
01011             points[indx+6*n] = dz;
01012             points[indx]     =-dz;
01013             indx++;
01014          }   
01015          // (n, 2n-1) lower rmax circle
01016          // (3n, 4n-1) upper rmax circle
01017          for (j = 0; j < n; j++) {
01018             phi = j*dphi*TMath::DegToRad();
01019             points[indx+6*n] = points[indx] = fRmax * TMath::Cos(phi);
01020             indx++;
01021             points[indx+6*n] = points[indx] = fRmax * TMath::Sin(phi);
01022             indx++;
01023             points[indx+6*n]= dz;
01024             points[indx]    =-dz;
01025             indx++;
01026          }
01027       } else {
01028          // centers of lower/upper circles (0,1)
01029          points[indx++] = 0.;
01030          points[indx++] = 0.;
01031          points[indx++] = -dz;
01032          points[indx++] = 0.;
01033          points[indx++] = 0.;
01034          points[indx++] = dz;
01035          // lower rmax circle (2, 2+n-1)
01036          // upper rmax circle (2+n, 2+2n-1)
01037          for (j = 0; j < n; j++) {
01038             phi = j*dphi*TMath::DegToRad();
01039             points[indx+3*n] = points[indx] = fRmax * TMath::Cos(phi);
01040             indx++;
01041             points[indx+3*n] = points[indx] = fRmax * TMath::Sin(phi);
01042             indx++;
01043             points[indx+3*n]= dz;
01044             points[indx]    =-dz;
01045             indx++;
01046          }
01047       }   
01048    }
01049 }
01050 
01051 //_____________________________________________________________________________
01052 Int_t TGeoTube::GetNmeshVertices() const
01053 {
01054 // Return number of vertices of the mesh representation
01055    Int_t n = gGeoManager->GetNsegments();
01056    Int_t numPoints = n*4;
01057    if (!HasRmin()) numPoints = 2*(n+1);
01058    return numPoints;
01059 }
01060 
01061 //_____________________________________________________________________________
01062 void TGeoTube::GetMeshNumbers(Int_t &nvert, Int_t &nsegs, Int_t &npols) const
01063 {
01064 // Returns numbers of vertices, segments and polygons composing the shape mesh.
01065    Int_t n = gGeoManager->GetNsegments();
01066    nvert = n*4;
01067    nsegs = n*8;
01068    npols = n*4;
01069    if (!HasRmin()) {
01070       nvert = 2*(n+1);
01071       nsegs = 5*n;
01072       npols = 3*n;
01073    } else {
01074       nvert = n*4;
01075       nsegs = n*8;
01076       npols = n*4;
01077    }   
01078 }
01079 
01080 //_____________________________________________________________________________
01081 void TGeoTube::Sizeof3D() const
01082 {
01083 ///// fill size of this 3-D object
01084 ///    TVirtualGeoPainter *painter = gGeoManager->GetGeomPainter();
01085 ///    if (!painter) return;
01086 ///    Int_t n = gGeoManager->GetNsegments();
01087 ///    Int_t numPoints = n*4;
01088 ///    Int_t numSegs   = n*8;
01089 ///    Int_t numPolys  = n*4;
01090 ///    painter->AddSize3D(numPoints, numSegs, numPolys);
01091 }
01092 
01093 //_____________________________________________________________________________
01094 const TBuffer3D & TGeoTube::GetBuffer3D(Int_t reqSections, Bool_t localFrame) const
01095 {
01096 // Fills a static 3D buffer and returns a reference.
01097    static TBuffer3DTube buffer;
01098    TGeoBBox::FillBuffer3D(buffer, reqSections, localFrame);
01099 
01100    if (reqSections & TBuffer3D::kShapeSpecific) {
01101       buffer.fRadiusInner  = fRmin;
01102       buffer.fRadiusOuter  = fRmax;
01103       buffer.fHalfLength   = fDz;
01104       buffer.SetSectionsValid(TBuffer3D::kShapeSpecific);
01105    }
01106    if (reqSections & TBuffer3D::kRawSizes) {
01107       Int_t n = gGeoManager->GetNsegments();
01108       Int_t nbPnts = 4*n;
01109       Int_t nbSegs = 8*n;
01110       Int_t nbPols = 4*n;
01111       if (!HasRmin()) {
01112          nbPnts = 2*(n+1);
01113          nbSegs = 5*n;
01114          nbPols = 3*n;
01115       }   
01116       if (buffer.SetRawSizes(nbPnts, 3*nbPnts, nbSegs, 3*nbSegs, nbPols, 6*nbPols)) {
01117          buffer.SetSectionsValid(TBuffer3D::kRawSizes);
01118       }
01119    }
01120    if ((reqSections & TBuffer3D::kRaw) && buffer.SectionsValid(TBuffer3D::kRawSizes)) {
01121       SetPoints(buffer.fPnts);
01122       if (!buffer.fLocalFrame) {
01123          TransformPoints(buffer.fPnts, buffer.NbPnts());
01124       }
01125       SetSegsAndPols(buffer);
01126       buffer.SetSectionsValid(TBuffer3D::kRaw);
01127    }
01128 
01129    return buffer;
01130 }
01131 
01132 ClassImp(TGeoTubeSeg)
01133 
01134 //_____________________________________________________________________________
01135 TGeoTubeSeg::TGeoTubeSeg()
01136 {
01137 // Default constructor
01138    SetShapeBit(TGeoShape::kGeoTubeSeg);
01139    fPhi1 = fPhi2 = 0.0;
01140 }
01141 
01142 //_____________________________________________________________________________
01143 TGeoTubeSeg::TGeoTubeSeg(Double_t rmin, Double_t rmax, Double_t dz,
01144                           Double_t phi1, Double_t phi2)
01145             :TGeoTube(rmin, rmax, dz)
01146 {
01147 // Default constructor specifying minimum and maximum radius
01148    SetShapeBit(TGeoShape::kGeoTubeSeg);
01149    SetTubsDimensions(rmin, rmax, dz, phi1, phi2);
01150    ComputeBBox();
01151 }
01152 
01153 //_____________________________________________________________________________
01154 TGeoTubeSeg::TGeoTubeSeg(const char *name, Double_t rmin, Double_t rmax, Double_t dz,
01155                           Double_t phi1, Double_t phi2)
01156             :TGeoTube(name, rmin, rmax, dz)
01157 {
01158 // Default constructor specifying minimum and maximum radius
01159    SetShapeBit(TGeoShape::kGeoTubeSeg);
01160    SetTubsDimensions(rmin, rmax, dz, phi1, phi2);
01161    ComputeBBox();
01162 }
01163 
01164 //_____________________________________________________________________________
01165 TGeoTubeSeg::TGeoTubeSeg(Double_t *param)
01166             :TGeoTube(0, 0, 0)
01167 {
01168 // Default constructor specifying minimum and maximum radius
01169 // param[0] = Rmin
01170 // param[1] = Rmax
01171 // param[2] = dz
01172 // param[3] = phi1
01173 // param[4] = phi2
01174    SetShapeBit(TGeoShape::kGeoTubeSeg);
01175    SetDimensions(param);
01176    ComputeBBox();
01177 }
01178 
01179 //_____________________________________________________________________________
01180 TGeoTubeSeg::~TGeoTubeSeg()
01181 {
01182 // destructor
01183 }
01184 
01185 //_____________________________________________________________________________
01186 Double_t TGeoTubeSeg::Capacity() const
01187 {
01188 // Computes capacity of the shape in [length^3]
01189    return TGeoTubeSeg::Capacity(fRmin,fRmax,fDz,fPhi1,fPhi2);
01190 }   
01191 
01192 //_____________________________________________________________________________
01193 Double_t TGeoTubeSeg::Capacity(Double_t rmin, Double_t rmax, Double_t dz, Double_t phi1, Double_t phi2)
01194 {
01195 // Computes capacity of the shape in [length^3]
01196    Double_t capacity = TMath::Abs(phi2-phi1)*TMath::DegToRad()*(rmax*rmax-rmin*rmin)*dz;
01197    return capacity;
01198 }   
01199 
01200 //_____________________________________________________________________________
01201 void TGeoTubeSeg::ComputeBBox()
01202 {
01203 // compute bounding box of the tube segment
01204    Double_t xc[4];
01205    Double_t yc[4];
01206    xc[0] = fRmax*TMath::Cos(fPhi1*TMath::DegToRad());
01207    yc[0] = fRmax*TMath::Sin(fPhi1*TMath::DegToRad());
01208    xc[1] = fRmax*TMath::Cos(fPhi2*TMath::DegToRad());
01209    yc[1] = fRmax*TMath::Sin(fPhi2*TMath::DegToRad());
01210    xc[2] = fRmin*TMath::Cos(fPhi1*TMath::DegToRad());
01211    yc[2] = fRmin*TMath::Sin(fPhi1*TMath::DegToRad());
01212    xc[3] = fRmin*TMath::Cos(fPhi2*TMath::DegToRad());
01213    yc[3] = fRmin*TMath::Sin(fPhi2*TMath::DegToRad());
01214 
01215    Double_t xmin = xc[TMath::LocMin(4, &xc[0])];
01216    Double_t xmax = xc[TMath::LocMax(4, &xc[0])];
01217    Double_t ymin = yc[TMath::LocMin(4, &yc[0])];
01218    Double_t ymax = yc[TMath::LocMax(4, &yc[0])];
01219 
01220    Double_t dp = fPhi2-fPhi1;
01221    if (dp<0) dp+=360;
01222    Double_t ddp = -fPhi1;
01223    if (ddp<0) ddp+= 360;
01224    if (ddp>360) ddp-=360;
01225    if (ddp<=dp) xmax = fRmax;
01226    ddp = 90-fPhi1;
01227    if (ddp<0) ddp+= 360;
01228    if (ddp>360) ddp-=360;
01229    if (ddp<=dp) ymax = fRmax;
01230    ddp = 180-fPhi1;
01231    if (ddp<0) ddp+= 360;
01232    if (ddp>360) ddp-=360;
01233    if (ddp<=dp) xmin = -fRmax;
01234    ddp = 270-fPhi1;
01235    if (ddp<0) ddp+= 360;
01236    if (ddp>360) ddp-=360;
01237    if (ddp<=dp) ymin = -fRmax;
01238    fOrigin[0] = (xmax+xmin)/2;
01239    fOrigin[1] = (ymax+ymin)/2;
01240    fOrigin[2] = 0;
01241    fDX = (xmax-xmin)/2;
01242    fDY = (ymax-ymin)/2;
01243    fDZ = fDz;
01244 }
01245 
01246 //_____________________________________________________________________________
01247 void TGeoTubeSeg::ComputeNormal(Double_t *point, Double_t *dir, Double_t *norm)
01248 {
01249 // Compute normal to closest surface from POINT.
01250    Double_t saf[3];
01251    Double_t rsq = point[0]*point[0]+point[1]*point[1];
01252    Double_t r = TMath::Sqrt(rsq);
01253    Double_t c1 = TMath::Cos(fPhi1*TMath::DegToRad());
01254    Double_t s1 = TMath::Sin(fPhi1*TMath::DegToRad());
01255    Double_t c2 = TMath::Cos(fPhi2*TMath::DegToRad());
01256    Double_t s2 = TMath::Sin(fPhi2*TMath::DegToRad());
01257    saf[0] = TMath::Abs(fDz-TMath::Abs(point[2]));
01258    saf[1] = (fRmin>1E-10)?TMath::Abs(r-fRmin):TGeoShape::Big();
01259    saf[2] = TMath::Abs(fRmax-r);
01260    Int_t i = TMath::LocMin(3,saf);
01261    if (((fPhi2-fPhi1)<360.) && TGeoShape::IsCloseToPhi(saf[i], point,c1,s1,c2,s2)) {
01262       TGeoShape::NormalPhi(point,dir,norm,c1,s1,c2,s2);
01263       return;
01264    }
01265    if (i==0) {
01266       norm[0] = norm[1] = 0.;
01267       norm[2] = TMath::Sign(1.,dir[2]);
01268       return;
01269    }
01270    norm[2] = 0;
01271    Double_t phi = TMath::ATan2(point[1], point[0]);
01272    norm[0] = TMath::Cos(phi);
01273    norm[1] = TMath::Sin(phi);
01274    if (norm[0]*dir[0]+norm[1]*dir[1]<0) {
01275       norm[0] = -norm[0];
01276       norm[1] = -norm[1];
01277    }
01278 }
01279 
01280 //_____________________________________________________________________________
01281 void TGeoTubeSeg::ComputeNormalS(Double_t *point, Double_t *dir, Double_t *norm,
01282                                  Double_t rmin, Double_t rmax, Double_t /*dz*/,
01283                                  Double_t c1, Double_t s1, Double_t c2, Double_t s2)
01284 {
01285 // Compute normal to closest surface from POINT.
01286    Double_t saf[2];
01287    Double_t rsq = point[0]*point[0]+point[1]*point[1];
01288    Double_t r = TMath::Sqrt(rsq);
01289    saf[0] = (rmin>1E-10)?TMath::Abs(r-rmin):TGeoShape::Big();
01290    saf[1] = TMath::Abs(rmax-r);
01291    Int_t i = TMath::LocMin(2,saf);
01292    if (TGeoShape::IsCloseToPhi(saf[i], point,c1,s1,c2,s2)) {
01293       TGeoShape::NormalPhi(point,dir,norm,c1,s1,c2,s2);
01294       return;
01295    }
01296    norm[2] = 0;
01297    Double_t phi = TMath::ATan2(point[1], point[0]);
01298    norm[0] = TMath::Cos(phi);
01299    norm[1] = TMath::Sin(phi);
01300    if (norm[0]*dir[0]+norm[1]*dir[1]<0) {
01301       norm[0] = -norm[0];
01302       norm[1] = -norm[1];
01303    }
01304 }
01305 
01306 //_____________________________________________________________________________
01307 Bool_t TGeoTubeSeg::Contains(Double_t *point) const
01308 {
01309 // test if point is inside this tube segment
01310    // first check if point is inside the tube
01311    if (!TGeoTube::Contains(point)) return kFALSE;
01312    return IsInPhiRange(point, fPhi1, fPhi2);
01313 }
01314 
01315 //_____________________________________________________________________________
01316 Int_t TGeoTubeSeg::DistancetoPrimitive(Int_t px, Int_t py)
01317 {
01318 // compute closest distance from point px,py to each corner
01319    Int_t n = gGeoManager->GetNsegments()+1;
01320    const Int_t numPoints = 4*n;
01321    return ShapeDistancetoPrimitive(numPoints, px, py);
01322 }
01323 
01324 //_____________________________________________________________________________
01325 Double_t TGeoTubeSeg::DistFromInsideS(Double_t *point, Double_t *dir, Double_t rmin, Double_t rmax, Double_t dz,
01326                                  Double_t c1, Double_t s1, Double_t c2, Double_t s2, Double_t cm, Double_t sm, Double_t cdfi)
01327 {
01328 // Compute distance from inside point to surface of the tube segment (static)
01329 // Boundary safe algorithm.
01330    // Do Z
01331    Double_t stube = TGeoTube::DistFromInsideS(point,dir,rmin,rmax,dz);
01332    if (stube<=0) return 0.0;
01333    Double_t sfmin = TGeoShape::Big();
01334    Double_t rsq = point[0]*point[0]+point[1]*point[1];
01335    Double_t r = TMath::Sqrt(rsq);
01336    Double_t cpsi=point[0]*cm+point[1]*sm;
01337    if (cpsi>r*cdfi+TGeoShape::Tolerance())  {
01338       sfmin = TGeoShape::DistToPhiMin(point, dir, s1, c1, s2, c2, sm, cm);
01339       return TMath::Min(stube,sfmin);
01340    }
01341    // Point on the phi boundary or outside
01342    // which one: phi1 or phi2
01343    Double_t ddotn, xi, yi;
01344    if (TMath::Abs(point[1]-s1*r) < TMath::Abs(point[1]-s2*r)) {
01345       ddotn = s1*dir[0]-c1*dir[1];
01346       if (ddotn>=0) return 0.0;
01347       ddotn = -s2*dir[0]+c2*dir[1];
01348       if (ddotn<=0) return stube;
01349       sfmin = s2*point[0]-c2*point[1];
01350       if (sfmin<=0) return stube;
01351       sfmin /= ddotn;
01352       if (sfmin >= stube) return stube;
01353       xi = point[0]+sfmin*dir[0];
01354       yi = point[1]+sfmin*dir[1];
01355       if (yi*cm-xi*sm<0) return stube;
01356       return sfmin;
01357    }
01358    ddotn = -s2*dir[0]+c2*dir[1];
01359    if (ddotn>=0) return 0.0;
01360    ddotn = s1*dir[0]-c1*dir[1];
01361    if (ddotn<=0) return stube;
01362    sfmin = -s1*point[0]+c1*point[1];
01363    if (sfmin<=0) return stube;
01364    sfmin /= ddotn;
01365    if (sfmin >= stube) return stube;
01366    xi = point[0]+sfmin*dir[0];
01367    yi = point[1]+sfmin*dir[1];
01368    if (yi*cm-xi*sm>0) return stube;
01369    return sfmin;
01370 }
01371 
01372 //_____________________________________________________________________________
01373 Double_t TGeoTubeSeg::DistFromInside(Double_t *point, Double_t *dir, Int_t iact, Double_t step, Double_t *safe) const
01374 {
01375 // Compute distance from inside point to surface of the tube segment
01376 // Boundary safe algorithm.
01377    if (iact<3 && safe) {
01378       *safe = SafetyS(point, kTRUE, fRmin, fRmax, fDz, fPhi1, fPhi2);
01379       if (iact==0) return TGeoShape::Big();
01380       if ((iact==1) && (*safe>step)) return TGeoShape::Big();
01381    }
01382    if ((fPhi2-fPhi1)>=360.) return TGeoTube::DistFromInsideS(point,dir,fRmin,fRmax,fDz);
01383    Double_t phi1 = fPhi1*TMath::DegToRad();
01384    Double_t phi2 = fPhi2*TMath::DegToRad();
01385    Double_t c1 = TMath::Cos(phi1);
01386    Double_t c2 = TMath::Cos(phi2);
01387    Double_t s1 = TMath::Sin(phi1);
01388    Double_t s2 = TMath::Sin(phi2);
01389    Double_t phim = 0.5*(phi1+phi2);
01390    Double_t cm = TMath::Cos(phim);
01391    Double_t sm = TMath::Sin(phim);
01392    Double_t dfi = 0.5*(phi2-phi1);
01393    Double_t cdfi = TMath::Cos(dfi);
01394 
01395    // compute distance to surface
01396    return TGeoTubeSeg::DistFromInsideS(point,dir,fRmin,fRmax,fDz,c1,s1,c2,s2,cm,sm,cdfi);
01397 }
01398 
01399 //_____________________________________________________________________________
01400 Double_t TGeoTubeSeg::DistFromOutsideS(Double_t *point, Double_t *dir, Double_t rmin, Double_t rmax,
01401                                 Double_t dz, Double_t c1, Double_t s1, Double_t c2, Double_t s2,
01402                                 Double_t cm, Double_t sm, Double_t cdfi)
01403 {
01404 // Static method to compute distance to arbitrary tube segment from outside point
01405 // Boundary safe algorithm.
01406    Double_t r2, cpsi;
01407    // check Z planes
01408    Double_t xi, yi, zi;
01409    zi = dz - TMath::Abs(point[2]);
01410    Double_t rmaxsq = rmax*rmax;
01411    Double_t rminsq = rmin*rmin;
01412    Double_t s = TGeoShape::Big();
01413    Double_t snxt=TGeoShape::Big();
01414    Bool_t in = kFALSE;
01415    Bool_t inz = (zi<0)?kFALSE:kTRUE;
01416    if (!inz) {
01417       if (point[2]*dir[2]>=0) return TGeoShape::Big();
01418       s = -zi/TMath::Abs(dir[2]);
01419       xi = point[0]+s*dir[0];
01420       yi = point[1]+s*dir[1];
01421       r2=xi*xi+yi*yi;
01422       if ((rminsq<=r2) && (r2<=rmaxsq)) {
01423          cpsi=(xi*cm+yi*sm)/TMath::Sqrt(r2);
01424          if (cpsi>=cdfi) return s;
01425       }
01426    }
01427 
01428    // check outer cyl. surface
01429    Double_t rsq = point[0]*point[0]+point[1]*point[1];
01430    Double_t r = TMath::Sqrt(rsq);
01431    Double_t nsq=dir[0]*dir[0]+dir[1]*dir[1];
01432    Double_t rdotn=point[0]*dir[0]+point[1]*dir[1];
01433    Double_t b,d;
01434    Bool_t inrmax = kFALSE;
01435    Bool_t inrmin = kFALSE;
01436    Bool_t inphi  = kFALSE;
01437    if (rsq<=rmaxsq+TGeoShape::Tolerance()) inrmax = kTRUE;
01438    if (rsq>=rminsq-TGeoShape::Tolerance()) inrmin = kTRUE;
01439    cpsi=point[0]*cm+point[1]*sm;
01440    if (cpsi>r*cdfi-TGeoShape::Tolerance())  inphi = kTRUE;
01441    in = inz & inrmin & inrmax & inphi;
01442    // If inside, we are most likely on a boundary within machine precision.
01443    if (in) {
01444       Bool_t checkout = kFALSE;
01445       Double_t safphi = (cpsi-r*cdfi)*TMath::Sqrt(1.-cdfi*cdfi);
01446 //      Double_t sch, cch;
01447       // check if on Z boundaries
01448       if (zi<rmax-r) {
01449          if (TGeoShape::IsSameWithinTolerance(rmin,0) || (zi<r-rmin)) {
01450             if (zi<safphi) {
01451                if (point[2]*dir[2]<0) return 0.0;
01452                return TGeoShape::Big();
01453             }
01454          }
01455       }
01456       if ((rmaxsq-rsq) < (rsq-rminsq)) checkout = kTRUE;
01457       // check if on Rmax boundary
01458       if (checkout && (rmax-r<safphi)) {
01459          if (rdotn>=0) return TGeoShape::Big();
01460          return 0.0;
01461       }
01462       if (TMath::Abs(nsq)<TGeoShape::Tolerance()) return TGeoShape::Big();
01463       // check if on phi boundary
01464       if (TGeoShape::IsSameWithinTolerance(rmin,0) || (safphi<r-rmin)) {
01465          // We may cross again a phi of rmin boundary
01466          // check first if we are on phi1 or phi2
01467          Double_t un;
01468          if (TMath::Abs(point[1]-s1*r) < TMath::Abs(point[1]-s2*r)) {
01469             un = dir[0]*s1-dir[1]*c1;
01470             if (un < 0) return 0.0;
01471             if (cdfi>=0) return TGeoShape::Big();
01472             un = -dir[0]*s2+dir[1]*c2;
01473             if (un<0) {
01474                s = -point[0]*s2+point[1]*c2;
01475                if (s>0) {
01476                   s /= (-un);
01477                   zi = point[2]+s*dir[2];
01478                   if (TMath::Abs(zi)<=dz) {
01479                      xi = point[0]+s*dir[0];
01480                      yi = point[1]+s*dir[1];
01481                      r2=xi*xi+yi*yi;
01482                      if ((rminsq<=r2) && (r2<=rmaxsq)) {
01483                         if ((yi*cm-xi*sm)>0) return s;
01484                      }
01485                   }
01486                }
01487             }
01488          } else {
01489             un = -dir[0]*s2+dir[1]*c2;
01490             if (un < 0) return 0.0;
01491             if (cdfi>=0) return TGeoShape::Big();
01492             un = dir[0]*s1-dir[1]*c1;
01493             if (un<0) {
01494                s = point[0]*s1-point[1]*c1;
01495                if (s>0) {
01496                   s /= (-un);
01497                   zi = point[2]+s*dir[2];
01498                   if (TMath::Abs(zi)<=dz) {
01499                      xi = point[0]+s*dir[0];
01500                      yi = point[1]+s*dir[1];
01501                      r2=xi*xi+yi*yi;
01502                      if ((rminsq<=r2) && (r2<=rmaxsq)) {
01503                         if ((yi*cm-xi*sm)<0) return s;
01504                      }
01505                   }
01506                }
01507             }
01508          }
01509          // We may also cross rmin, (+) solution
01510          if (rdotn>=0) return TGeoShape::Big();
01511          if (cdfi>=0) return TGeoShape::Big();
01512          DistToTube(rsq, nsq, rdotn, rmin, b, d);
01513          if (d>0) {
01514             s=-b+d;
01515             if (s>0) {
01516                zi=point[2]+s*dir[2];
01517                if (TMath::Abs(zi)<=dz) {
01518                   xi=point[0]+s*dir[0];
01519                   yi=point[1]+s*dir[1];
01520                   if ((xi*cm+yi*sm) >= rmin*cdfi) return s;
01521                }
01522             }
01523          }
01524          return TGeoShape::Big();
01525       }
01526       // we are on rmin boundary: we may cross again rmin or a phi facette
01527       if (rdotn>=0) return 0.0;
01528       DistToTube(rsq, nsq, rdotn, rmin, b, d);
01529       if (d>0) {
01530          s=-b+d;
01531          if (s>0) {
01532             zi=point[2]+s*dir[2];
01533             if (TMath::Abs(zi)<=dz) {
01534                // now check phi range
01535                xi=point[0]+s*dir[0];
01536                yi=point[1]+s*dir[1];
01537                r2=xi*xi+yi*yi;
01538                if ((xi*cm+yi*sm) >= rmin*cdfi) return s;
01539                // now we really have to check any phi crossing
01540                Double_t un=-dir[0]*s1+dir[1]*c1;
01541                if (un > 0) {
01542                   s=point[0]*s1-point[1]*c1;
01543                   if (s>=0) {
01544                      s /= un;
01545                      zi=point[2]+s*dir[2];
01546                      if (TMath::Abs(zi)<=dz) {
01547                         xi=point[0]+s*dir[0];
01548                         yi=point[1]+s*dir[1];
01549                         r2=xi*xi+yi*yi;
01550                         if ((rminsq<=r2) && (r2<=rmaxsq)) {
01551                            if ((yi*cm-xi*sm)<=0) {
01552                               if (s<snxt) snxt=s;
01553                            }
01554                         }
01555                      }
01556                   }
01557                }
01558                un=dir[0]*s2-dir[1]*c2;
01559                if (un > 0) {
01560                   s=(point[1]*c2-point[0]*s2)/un;
01561                   if (s>=0 && s<snxt) {
01562                      zi=point[2]+s*dir[2];
01563                      if (TMath::Abs(zi)<=dz) {
01564                         xi=point[0]+s*dir[0];
01565                         yi=point[1]+s*dir[1];
01566                         r2=xi*xi+yi*yi;
01567                         if ((rminsq<=r2) && (r2<=rmaxsq)) {
01568                            if ((yi*cm-xi*sm)>=0) {
01569                               return s;
01570                            }
01571                         }
01572                      }
01573                   }
01574                }
01575                return snxt;
01576             }
01577          }
01578       }
01579       return TGeoShape::Big();
01580    }
01581    // only r>rmax has to be considered
01582    if (TMath::Abs(nsq)<TGeoShape::Tolerance()) return TGeoShape::Big();
01583    if (rsq>=rmax*rmax) {
01584       if (rdotn>=0) return TGeoShape::Big();
01585       TGeoTube::DistToTube(rsq, nsq, rdotn, rmax, b, d);
01586       if (d>0) {
01587          s=-b-d;
01588          if (s>0) {
01589             zi=point[2]+s*dir[2];
01590             if (TMath::Abs(zi)<=dz) {
01591                xi=point[0]+s*dir[0];
01592                yi=point[1]+s*dir[1];
01593                cpsi = xi*cm+yi*sm;
01594                if (cpsi>=rmax*cdfi) return s;
01595             }
01596          }
01597       }
01598    }
01599    // check inner cylinder
01600    if (rmin>0) {
01601       TGeoTube::DistToTube(rsq, nsq, rdotn, rmin, b, d);
01602       if (d>0) {
01603          s=-b+d;
01604          if (s>0) {
01605             zi=point[2]+s*dir[2];
01606             if (TMath::Abs(zi)<=dz) {
01607                xi=point[0]+s*dir[0];
01608                yi=point[1]+s*dir[1];
01609                cpsi = xi*cm+yi*sm;
01610                if (cpsi>=rmin*cdfi) snxt=s;
01611             }
01612          }
01613       }
01614    }
01615    // check phi planes
01616    Double_t un=-dir[0]*s1+dir[1]*c1;
01617    if (un > 0) {
01618       s=point[0]*s1-point[1]*c1;
01619       if (s>=0) {
01620          s /= un;
01621          zi=point[2]+s*dir[2];
01622          if (TMath::Abs(zi)<=dz) {
01623             xi=point[0]+s*dir[0];
01624             yi=point[1]+s*dir[1];
01625             r2=xi*xi+yi*yi;
01626             if ((rminsq<=r2) && (r2<=rmaxsq)) {
01627                if ((yi*cm-xi*sm)<=0) {
01628                   if (s<snxt) snxt=s;
01629                }
01630             }
01631          }
01632       }
01633    }
01634    un=dir[0]*s2-dir[1]*c2;
01635    if (un > 0) {
01636       s=point[1]*c2-point[0]*s2;
01637       if (s>=0) {
01638          s /= un;
01639          zi=point[2]+s*dir[2];
01640          if (TMath::Abs(zi)<=dz) {
01641             xi=point[0]+s*dir[0];
01642             yi=point[1]+s*dir[1];
01643             r2=xi*xi+yi*yi;
01644             if ((rminsq<=r2) && (r2<=rmaxsq)) {
01645                if ((yi*cm-xi*sm)>=0) {
01646                   if (s<snxt) snxt=s;
01647                }
01648             }
01649          }
01650       }
01651    }
01652    return snxt;
01653 }
01654 
01655 //_____________________________________________________________________________
01656 Double_t TGeoTubeSeg::DistFromOutside(Double_t *point, Double_t *dir, Int_t iact, Double_t step, Double_t *safe) const
01657 {
01658 // compute distance from outside point to surface of the tube segment
01659    // fist localize point w.r.t tube
01660    if (iact<3 && safe) {
01661       *safe = SafetyS(point, kFALSE, fRmin, fRmax, fDz, fPhi1, fPhi2);
01662       if (iact==0) return TGeoShape::Big();
01663       if ((iact==1) && (step<=*safe)) return TGeoShape::Big();
01664    }
01665 // Check if the bounding box is crossed within the requested distance
01666    Double_t sdist = TGeoBBox::DistFromOutside(point,dir, fDX, fDY, fDZ, fOrigin, step);
01667    if (sdist>=step) return TGeoShape::Big();
01668    if ((fPhi2-fPhi1)>=360.) return TGeoTube::DistFromOutsideS(point,dir,fRmin,fRmax,fDz);
01669    Double_t phi1 = fPhi1*TMath::DegToRad();
01670    Double_t phi2 = fPhi2*TMath::DegToRad();
01671    Double_t c1 = TMath::Cos(phi1);
01672    Double_t s1 = TMath::Sin(phi1);
01673    Double_t c2 = TMath::Cos(phi2);
01674    Double_t s2 = TMath::Sin(phi2);
01675    Double_t fio = 0.5*(phi1+phi2);
01676    Double_t cm = TMath::Cos(fio);
01677    Double_t sm = TMath::Sin(fio);
01678    Double_t dfi = 0.5*(phi2-phi1);
01679    Double_t cdfi = TMath::Cos(dfi);
01680 
01681    // find distance to shape
01682    return TGeoTubeSeg::DistFromOutsideS(point, dir, fRmin, fRmax, fDz, c1, s1, c2, s2, cm, sm, cdfi);
01683 }
01684 
01685 //_____________________________________________________________________________
01686 TGeoVolume *TGeoTubeSeg::Divide(TGeoVolume *voldiv, const char *divname, Int_t iaxis, Int_t ndiv,
01687                              Double_t start, Double_t step)
01688 {
01689 //--- Divide this tube segment shape belonging to volume "voldiv" into ndiv volumes
01690 // called divname, from start position with the given step. Returns pointer
01691 // to created division cell volume in case of Z divisions. For radialdivision
01692 // creates all volumes with different shapes and returns pointer to volume that
01693 // was divided. In case a wrong division axis is supplied, returns pointer to
01694 // volume that was divided.
01695    TGeoShape *shape;           //--- shape to be created
01696    TGeoVolume *vol;            //--- division volume to be created
01697    TGeoVolumeMulti *vmulti;    //--- generic divided volume
01698    TGeoPatternFinder *finder;  //--- finder to be attached
01699    TString opt = "";           //--- option to be attached
01700    Double_t dphi;
01701    Int_t id;
01702    Double_t end = start+ndiv*step;
01703    switch (iaxis) {
01704       case 1:  //---                 R division
01705          finder = new TGeoPatternCylR(voldiv, ndiv, start, end);
01706          vmulti = gGeoManager->MakeVolumeMulti(divname, voldiv->GetMedium());
01707          voldiv->SetFinder(finder);
01708          finder->SetDivIndex(voldiv->GetNdaughters());
01709          for (id=0; id<ndiv; id++) {
01710             shape = new TGeoTubeSeg(start+id*step, start+(id+1)*step, fDz, fPhi1, fPhi2);
01711             vol = new TGeoVolume(divname, shape, voldiv->GetMedium());
01712             vmulti->AddVolume(vol);
01713             opt = "R";
01714             voldiv->AddNodeOffset(vol, id, 0, opt.Data());
01715             ((TGeoNodeOffset*)voldiv->GetNodes()->At(voldiv->GetNdaughters()-1))->SetFinder(finder);
01716          }
01717          return vmulti;
01718       case 2:  //---                 Phi division
01719          dphi = fPhi2-fPhi1;
01720          if (dphi<0) dphi+=360.;
01721          if (step<=0) {step=dphi/ndiv; start=fPhi1; end=fPhi2;}
01722          finder = new TGeoPatternCylPhi(voldiv, ndiv, start, end);
01723          voldiv->SetFinder(finder);
01724          finder->SetDivIndex(voldiv->GetNdaughters());
01725          shape = new TGeoTubeSeg(fRmin, fRmax, fDz, -step/2, step/2);
01726          vol = new TGeoVolume(divname, shape, voldiv->GetMedium());
01727          vmulti = gGeoManager->MakeVolumeMulti(divname, voldiv->GetMedium());
01728          vmulti->AddVolume(vol);
01729          opt = "Phi";
01730          for (id=0; id<ndiv; id++) {
01731             voldiv->AddNodeOffset(vol, id, start+id*step+step/2, opt.Data());
01732             ((TGeoNodeOffset*)voldiv->GetNodes()->At(voldiv->GetNdaughters()-1))->SetFinder(finder);
01733          }
01734          return vmulti;
01735       case 3: //---                  Z division
01736          finder = new TGeoPatternZ(voldiv, ndiv, start, end);
01737          voldiv->SetFinder(finder);
01738          finder->SetDivIndex(voldiv->GetNdaughters());
01739          shape = new TGeoTubeSeg(fRmin, fRmax, step/2, fPhi1, fPhi2);
01740          vol = new TGeoVolume(divname, shape, voldiv->GetMedium());
01741          vmulti = gGeoManager->MakeVolumeMulti(divname, voldiv->GetMedium());
01742          vmulti->AddVolume(vol);
01743          opt = "Z";
01744          for (id=0; id<ndiv; id++) {
01745             voldiv->AddNodeOffset(vol, id, start+step/2+id*step, opt.Data());
01746             ((TGeoNodeOffset*)voldiv->GetNodes()->At(voldiv->GetNdaughters()-1))->SetFinder(finder);
01747          }
01748          return vmulti;
01749       default:
01750          Error("Divide", "In shape %s wrong axis type for division", GetName());
01751          return 0;
01752    }
01753 }
01754 
01755 //_____________________________________________________________________________
01756 Double_t TGeoTubeSeg::GetAxisRange(Int_t iaxis, Double_t &xlo, Double_t &xhi) const
01757 {
01758 // Get range of shape for a given axis.
01759    xlo = 0;
01760    xhi = 0;
01761    Double_t dx = 0;
01762    switch (iaxis) {
01763       case 1:
01764          xlo = fRmin;
01765          xhi = fRmax;
01766          dx = xhi-xlo;
01767          return dx;
01768       case 2:
01769          xlo = fPhi1;
01770          xhi = fPhi2;
01771          dx = xhi-xlo;
01772          return dx;
01773       case 3:
01774          xlo = -fDz;
01775          xhi = fDz;
01776          dx = xhi-xlo;
01777          return dx;
01778    }
01779    return dx;
01780 }
01781 
01782 //_____________________________________________________________________________
01783 void TGeoTubeSeg::GetBoundingCylinder(Double_t *param) const
01784 {
01785 //--- Fill vector param[4] with the bounding cylinder parameters. The order
01786 // is the following : Rmin, Rmax, Phi1, Phi2
01787    param[0] = fRmin;
01788    param[0] *= param[0];
01789    param[1] = fRmax;
01790    param[1] *= param[1];
01791    param[2] = fPhi1;
01792    param[3] = fPhi2;
01793 }
01794 
01795 //_____________________________________________________________________________
01796 TGeoShape *TGeoTubeSeg::GetMakeRuntimeShape(TGeoShape *mother, TGeoMatrix * /*mat*/) const
01797 {
01798 // in case shape has some negative parameters, these has to be computed
01799 // in order to fit the mother
01800    if (!TestShapeBit(kGeoRunTimeShape)) return 0;
01801    if (!mother->TestShapeBit(kGeoTube)) {
01802       Error("GetMakeRuntimeShape", "Invalid mother for shape %s", GetName());
01803       return 0;
01804    }
01805    Double_t rmin, rmax, dz;
01806    rmin = fRmin;
01807    rmax = fRmax;
01808    dz = fDz;
01809    if (fDz<0) dz=((TGeoTube*)mother)->GetDz();
01810    if (fRmin<0)
01811       rmin = ((TGeoTube*)mother)->GetRmin();
01812    if ((fRmax<0) || (fRmax<=fRmin))
01813       rmax = ((TGeoTube*)mother)->GetRmax();
01814 
01815    return (new TGeoTubeSeg(GetName(),rmin, rmax, dz, fPhi1, fPhi2));
01816 }
01817 
01818 //_____________________________________________________________________________
01819 void TGeoTubeSeg::InspectShape() const
01820 {
01821 // print shape parameters
01822    printf("*** Shape %s: TGeoTubeSeg ***\n", GetName());
01823    printf("    Rmin = %11.5f\n", fRmin);
01824    printf("    Rmax = %11.5f\n", fRmax);
01825    printf("    dz   = %11.5f\n", fDz);
01826    printf("    phi1 = %11.5f\n", fPhi1);
01827    printf("    phi2 = %11.5f\n", fPhi2);
01828    printf(" Bounding box:\n");
01829    TGeoBBox::InspectShape();
01830 }
01831 
01832 //_____________________________________________________________________________
01833 TBuffer3D *TGeoTubeSeg::MakeBuffer3D() const
01834 {
01835    // Creates a TBuffer3D describing *this* shape.
01836    // Coordinates are in local reference frame.
01837 
01838    Int_t n = gGeoManager->GetNsegments()+1;
01839    Int_t nbPnts = 4*n;
01840    Int_t nbSegs = 2*nbPnts;
01841    Int_t nbPols = nbPnts-2;
01842 
01843    TBuffer3D* buff = new TBuffer3D(TBuffer3DTypes::kGeneric,
01844                                    nbPnts, 3*nbPnts, nbSegs, 3*nbSegs, nbPols, 6*nbPols);
01845    if (buff)
01846    {
01847       SetPoints(buff->fPnts);
01848       SetSegsAndPols(*buff);
01849    }
01850 
01851    return buff;
01852 }
01853 
01854 //_____________________________________________________________________________
01855 void TGeoTubeSeg::SetSegsAndPols(TBuffer3D &buff) const
01856 {
01857 // Fill TBuffer3D structure for segments and polygons.
01858    Int_t i, j;
01859    Int_t n = gGeoManager->GetNsegments()+1;
01860    Int_t c = GetBasicColor();
01861 
01862    memset(buff.fSegs, 0, buff.NbSegs()*3*sizeof(Int_t));
01863    for (i = 0; i < 4; i++) {
01864       for (j = 1; j < n; j++) {
01865          buff.fSegs[(i*n+j-1)*3  ] = c;
01866          buff.fSegs[(i*n+j-1)*3+1] = i*n+j-1;
01867          buff.fSegs[(i*n+j-1)*3+2] = i*n+j;
01868       }
01869    }
01870    for (i = 4; i < 6; i++) {
01871       for (j = 0; j < n; j++) {
01872          buff.fSegs[(i*n+j)*3  ] = c+1;
01873          buff.fSegs[(i*n+j)*3+1] = (i-4)*n+j;
01874          buff.fSegs[(i*n+j)*3+2] = (i-2)*n+j;
01875       }
01876    }
01877    for (i = 6; i < 8; i++) {
01878       for (j = 0; j < n; j++) {
01879          buff.fSegs[(i*n+j)*3  ] = c;
01880          buff.fSegs[(i*n+j)*3+1] = 2*(i-6)*n+j;
01881          buff.fSegs[(i*n+j)*3+2] = (2*(i-6)+1)*n+j;
01882       }
01883    }
01884 
01885    Int_t indx = 0;
01886    memset(buff.fPols, 0, buff.NbPols()*6*sizeof(Int_t));
01887    i = 0;
01888    for (j = 0; j < n-1; j++) {
01889       buff.fPols[indx++] = c;
01890       buff.fPols[indx++] = 4;
01891       buff.fPols[indx++] = (4+i)*n+j+1;
01892       buff.fPols[indx++] = (2+i)*n+j;
01893       buff.fPols[indx++] = (4+i)*n+j;
01894       buff.fPols[indx++] = i*n+j;
01895    }
01896    i = 1;
01897    for (j = 0; j < n-1; j++) {
01898       buff.fPols[indx++] = c;
01899       buff.fPols[indx++] = 4;
01900       buff.fPols[indx++] = i*n+j;
01901       buff.fPols[indx++] = (4+i)*n+j;
01902       buff.fPols[indx++] = (2+i)*n+j;
01903       buff.fPols[indx++] = (4+i)*n+j+1;
01904    }
01905    i = 2;
01906    for (j = 0; j < n-1; j++) {
01907       buff.fPols[indx++] = c+i;
01908       buff.fPols[indx++] = 4;
01909       buff.fPols[indx++] = (i-2)*2*n+j;
01910       buff.fPols[indx++] = (4+i)*n+j;
01911       buff.fPols[indx++] = ((i-2)*2+1)*n+j;
01912       buff.fPols[indx++] = (4+i)*n+j+1;
01913    }
01914    i = 3;
01915    for (j = 0; j < n-1; j++) {
01916       buff.fPols[indx++] = c+i;
01917       buff.fPols[indx++] = 4;
01918       buff.fPols[indx++] = (4+i)*n+j+1;
01919       buff.fPols[indx++] = ((i-2)*2+1)*n+j;
01920       buff.fPols[indx++] = (4+i)*n+j;
01921       buff.fPols[indx++] = (i-2)*2*n+j;
01922    }
01923    buff.fPols[indx++] = c+2;
01924    buff.fPols[indx++] = 4;
01925    buff.fPols[indx++] = 6*n;
01926    buff.fPols[indx++] = 4*n;
01927    buff.fPols[indx++] = 7*n;
01928    buff.fPols[indx++] = 5*n;
01929    buff.fPols[indx++] = c+2;
01930    buff.fPols[indx++] = 4;
01931    buff.fPols[indx++] = 6*n-1;
01932    buff.fPols[indx++] = 8*n-1;
01933    buff.fPols[indx++] = 5*n-1;
01934    buff.fPols[indx++] = 7*n-1;
01935 }
01936 
01937 //_____________________________________________________________________________
01938 Double_t TGeoTubeSeg::Safety(Double_t *point, Bool_t in) const
01939 {
01940 // computes the closest distance from given point to this shape, according
01941 // to option. The matching point on the shape is stored in spoint.
01942    Double_t saf[3];
01943    Double_t rsq = point[0]*point[0]+point[1]*point[1];
01944    Double_t r = TMath::Sqrt(rsq);
01945 
01946    Double_t safe = TGeoShape::Big();
01947    if (in) {
01948       saf[0] = fDz-TMath::Abs(point[2]);
01949       saf[1] = r-fRmin;
01950       saf[2] = fRmax-r;
01951       safe   = saf[TMath::LocMin(3,saf)];
01952    } else {
01953    // at least one positive
01954       saf[0] = TMath::Abs(point[2])-fDz;
01955       saf[1] = fRmin-r;
01956       saf[2] = r-fRmax;
01957       safe   = saf[TMath::LocMax(3,saf)];
01958    }
01959    if ((fPhi2-fPhi1)>=360.) return safe;
01960    Double_t safphi = TGeoShape::SafetyPhi(point,in,fPhi1,fPhi2);
01961 
01962    if (in) return TMath::Min(safe, safphi);
01963    return TMath::Max(safe, safphi);
01964 }
01965 
01966 //_____________________________________________________________________________
01967 Double_t TGeoTubeSeg::SafetyS(Double_t *point, Bool_t in, Double_t rmin, Double_t rmax, Double_t dz,
01968                               Double_t phi1, Double_t phi2, Int_t skipz)
01969 {
01970 // Static method to compute the closest distance from given point to this shape.
01971    Double_t saf[3];
01972    Double_t rsq = point[0]*point[0]+point[1]*point[1];
01973    Double_t r = TMath::Sqrt(rsq);
01974 
01975    switch (skipz) {
01976       case 1: // skip lower Z plane
01977          saf[0] = dz - point[2];
01978          break;
01979       case 2: // skip upper Z plane
01980          saf[0] = dz + point[2];
01981          break;
01982       case 3: // skip both
01983          saf[0] = TGeoShape::Big();
01984          break;
01985       default:
01986          saf[0] = dz-TMath::Abs(point[2]);
01987    }
01988    saf[1] = r-rmin;
01989    saf[2] = rmax-r;
01990    Double_t safphi = TGeoShape::SafetyPhi(point,in,phi1,phi2);
01991    Double_t safe = TGeoShape::Big();
01992 
01993    if (in)  {
01994       safe = saf[TMath::LocMin(3,saf)];
01995       return TMath::Min(safe, safphi);
01996    }
01997 
01998    for (Int_t i=0; i<3; i++) saf[i]=-saf[i];
01999    safe = saf[TMath::LocMax(3,saf)];
02000    return TMath::Max(safe, safphi);
02001 }
02002 
02003 //_____________________________________________________________________________
02004 void TGeoTubeSeg::SavePrimitive(ostream &out, Option_t * /*option*/ /*= ""*/)
02005 {
02006 // Save a primitive as a C++ statement(s) on output stream "out".
02007    if (TObject::TestBit(kGeoSavePrimitive)) return;
02008    out << "   // Shape: " << GetName() << " type: " << ClassName() << endl;
02009    out << "   rmin = " << fRmin << ";" << endl;
02010    out << "   rmax = " << fRmax << ";" << endl;
02011    out << "   dz   = " << fDz << ";" << endl;
02012    out << "   phi1 = " << fPhi1 << ";" << endl;
02013    out << "   phi2 = " << fPhi2 << ";" << endl;
02014    out << "   TGeoShape *" << GetPointerName() << " = new TGeoTubeSeg(\"" << GetName() << "\",rmin,rmax,dz,phi1,phi2);" << endl;
02015    TObject::SetBit(TGeoShape::kGeoSavePrimitive);
02016 }
02017 
02018 //_____________________________________________________________________________
02019 void TGeoTubeSeg::SetTubsDimensions(Double_t rmin, Double_t rmax, Double_t dz,
02020                           Double_t phi1, Double_t phi2)
02021 {
02022 // Set dimensions of the tube segment.
02023    fRmin = rmin;
02024    fRmax = rmax;
02025    fDz   = dz;
02026    fPhi1 = phi1;
02027    if (fPhi1 < 0) fPhi1+=360.;
02028    fPhi2 = phi2;
02029    while (fPhi2<=fPhi1) fPhi2+=360.;
02030    if (TGeoShape::IsSameWithinTolerance(fPhi1,fPhi2)) Error("SetTubsDimensions", "In shape %s invalid phi1=%g, phi2=%g\n", GetName(), fPhi1, fPhi2);
02031 }
02032 
02033 //_____________________________________________________________________________
02034 void TGeoTubeSeg::SetDimensions(Double_t *param)
02035 {
02036 // Set dimensions of the tube segment starting from a list.
02037    Double_t rmin = param[0];
02038    Double_t rmax = param[1];
02039    Double_t dz   = param[2];
02040    Double_t phi1 = param[3];
02041    Double_t phi2 = param[4];
02042    SetTubsDimensions(rmin, rmax, dz, phi1, phi2);
02043 }
02044 
02045 //_____________________________________________________________________________
02046 Bool_t TGeoTubeSeg::GetPointsOnSegments(Int_t npoints, Double_t *array) const
02047 {
02048 // Fills array with n random points located on the line segments of the shape mesh.
02049 // The output array must be provided with a length of minimum 3*npoints. Returns
02050 // true if operation is implemented.
02051    if (npoints > (npoints/2)*2) {
02052       Error("GetPointsOnSegments","Npoints must be even number");
02053       return kFALSE;
02054    }   
02055    Int_t nc = (Int_t)TMath::Sqrt(0.5*npoints);
02056    Double_t dphi = (fPhi2-fPhi1)*TMath::DegToRad()/(nc-1);
02057    Double_t phi = 0;
02058    Double_t phi1 = fPhi1 * TMath::DegToRad();
02059    Int_t ntop = npoints/2 - nc*(nc-1);
02060    Double_t dz = 2*fDz/(nc-1);
02061    Double_t z = 0;
02062    Int_t icrt = 0;
02063    Int_t nphi = nc;
02064    // loop z sections
02065    for (Int_t i=0; i<nc; i++) {
02066       if (i == (nc-1)) {
02067          nphi = ntop;
02068          dphi = (fPhi2-fPhi1)*TMath::DegToRad()/(nphi-1);
02069       }   
02070       z = -fDz + i*dz;
02071       // loop points on circle sections
02072       for (Int_t j=0; j<nphi; j++) {
02073          phi = phi1 + j*dphi;
02074          array[icrt++] = fRmin * TMath::Cos(phi);
02075          array[icrt++] = fRmin * TMath::Sin(phi);
02076          array[icrt++] = z;
02077          array[icrt++] = fRmax * TMath::Cos(phi);
02078          array[icrt++] = fRmax * TMath::Sin(phi);
02079          array[icrt++] = z;
02080       }
02081    }
02082    return kTRUE;
02083 }
02084    
02085 //_____________________________________________________________________________
02086 void TGeoTubeSeg::SetPoints(Double_t *points) const
02087 {
02088 // Create tube segment mesh points.
02089    Double_t dz;
02090    Int_t j, n;
02091    Double_t phi, phi1, phi2, dphi;
02092    phi1 = fPhi1;
02093    phi2 = fPhi2;
02094    if (phi2<phi1) phi2+=360.;
02095    n = gGeoManager->GetNsegments()+1;
02096 
02097    dphi = (phi2-phi1)/(n-1);
02098    dz   = fDz;
02099 
02100    if (points) {
02101       Int_t indx = 0;
02102 
02103       for (j = 0; j < n; j++) {
02104          phi = (phi1+j*dphi)*TMath::DegToRad();
02105          points[indx+6*n] = points[indx] = fRmin * TMath::Cos(phi);
02106          indx++;
02107          points[indx+6*n] = points[indx] = fRmin * TMath::Sin(phi);
02108          indx++;
02109          points[indx+6*n] = dz;
02110          points[indx]     =-dz;
02111          indx++;
02112       }
02113       for (j = 0; j < n; j++) {
02114          phi = (phi1+j*dphi)*TMath::DegToRad();
02115          points[indx+6*n] = points[indx] = fRmax * TMath::Cos(phi);
02116          indx++;
02117          points[indx+6*n] = points[indx] = fRmax * TMath::Sin(phi);
02118          indx++;
02119          points[indx+6*n]= dz;
02120          points[indx]    =-dz;
02121          indx++;
02122       }
02123    }
02124 }
02125 
02126 //_____________________________________________________________________________
02127 void TGeoTubeSeg::SetPoints(Float_t *points) const
02128 {
02129 // Create tube segment mesh points.
02130    Double_t dz;
02131    Int_t j, n;
02132    Double_t phi, phi1, phi2, dphi;
02133    phi1 = fPhi1;
02134    phi2 = fPhi2;
02135    if (phi2<phi1) phi2+=360.;
02136    n = gGeoManager->GetNsegments()+1;
02137 
02138    dphi = (phi2-phi1)/(n-1);
02139    dz   = fDz;
02140 
02141    if (points) {
02142       Int_t indx = 0;
02143 
02144       for (j = 0; j < n; j++) {
02145          phi = (phi1+j*dphi)*TMath::DegToRad();
02146          points[indx+6*n] = points[indx] = fRmin * TMath::Cos(phi);
02147          indx++;
02148          points[indx+6*n] = points[indx] = fRmin * TMath::Sin(phi);
02149          indx++;
02150          points[indx+6*n] = dz;
02151          points[indx]     =-dz;
02152          indx++;
02153       }
02154       for (j = 0; j < n; j++) {
02155          phi = (phi1+j*dphi)*TMath::DegToRad();
02156          points[indx+6*n] = points[indx] = fRmax * TMath::Cos(phi);
02157          indx++;
02158          points[indx+6*n] = points[indx] = fRmax * TMath::Sin(phi);
02159          indx++;
02160          points[indx+6*n]= dz;
02161          points[indx]    =-dz;
02162          indx++;
02163       }
02164    }
02165 }
02166 
02167 //_____________________________________________________________________________
02168 void TGeoTubeSeg::GetMeshNumbers(Int_t &nvert, Int_t &nsegs, Int_t &npols) const
02169 {
02170 // Returns numbers of vertices, segments and polygons composing the shape mesh.
02171    Int_t n = gGeoManager->GetNsegments()+1;
02172    nvert = n*4;
02173    nsegs = n*8;
02174    npols = n*4 - 2;
02175 }
02176 
02177 //_____________________________________________________________________________
02178 Int_t TGeoTubeSeg::GetNmeshVertices() const
02179 {
02180 // Return number of vertices of the mesh representation
02181    Int_t n = gGeoManager->GetNsegments()+1;
02182    Int_t numPoints = n*4;
02183    return numPoints;
02184 }
02185 
02186 //_____________________________________________________________________________
02187 void TGeoTubeSeg::Sizeof3D() const
02188 {
02189 ///// fill size of this 3-D object
02190 ///    TVirtualGeoPainter *painter = gGeoManager->GetGeomPainter();
02191 ///    if (!painter) return;
02192 ///
02193 ///    Int_t n = gGeoManager->GetNsegments()+1;
02194 ///    Int_t numPoints = n*4;
02195 ///    Int_t numSegs   = n*8;
02196 ///    Int_t numPolys  = n*4-2;
02197 ///
02198 ///    painter->AddSize3D(numPoints, numSegs, numPolys);
02199 }
02200 
02201 //_____________________________________________________________________________
02202 const TBuffer3D & TGeoTubeSeg::GetBuffer3D(Int_t reqSections, Bool_t localFrame) const
02203 {
02204 // Fills a static 3D buffer and returns a reference.
02205    static TBuffer3DTubeSeg buffer;
02206    TGeoBBox::FillBuffer3D(buffer, reqSections, localFrame);
02207 
02208    if (reqSections & TBuffer3D::kShapeSpecific) {
02209       // These from TBuffer3DTube / TGeoTube
02210       buffer.fRadiusInner  = fRmin;
02211       buffer.fRadiusOuter  = fRmax;
02212       buffer.fHalfLength   = fDz;
02213       buffer.fPhiMin       = fPhi1;
02214       buffer.fPhiMax       = fPhi2;
02215       buffer.SetSectionsValid(TBuffer3D::kShapeSpecific);
02216    }
02217    if (reqSections & TBuffer3D::kRawSizes) {
02218       Int_t n = gGeoManager->GetNsegments()+1;
02219       Int_t nbPnts = 4*n;
02220       Int_t nbSegs = 2*nbPnts;
02221       Int_t nbPols = nbPnts-2;
02222       if (buffer.SetRawSizes(nbPnts, 3*nbPnts, nbSegs, 3*nbSegs, nbPols, 6*nbPols)) {
02223          buffer.SetSectionsValid(TBuffer3D::kRawSizes);
02224       }
02225    }
02226    if ((reqSections & TBuffer3D::kRaw) && buffer.SectionsValid(TBuffer3D::kRawSizes)) {
02227       SetPoints(buffer.fPnts);
02228       if (!buffer.fLocalFrame) {
02229          TransformPoints(buffer.fPnts, buffer.NbPnts());
02230       }
02231       SetSegsAndPols(buffer);
02232       buffer.SetSectionsValid(TBuffer3D::kRaw);
02233    }
02234 
02235    return buffer;
02236 }
02237 
02238 ClassImp(TGeoCtub)
02239 
02240 TGeoCtub::TGeoCtub()
02241 {
02242 // default ctor
02243    fNlow[0] = fNlow[1] = fNhigh[0] = fNhigh[1] = 0.;
02244    fNlow[2] = -1;
02245    fNhigh[2] = 1;
02246 }
02247 
02248 //_____________________________________________________________________________
02249 TGeoCtub::TGeoCtub(Double_t rmin, Double_t rmax, Double_t dz, Double_t phi1, Double_t phi2,
02250                    Double_t lx, Double_t ly, Double_t lz, Double_t tx, Double_t ty, Double_t tz)
02251          :TGeoTubeSeg(rmin, rmax, dz, phi1, phi2)
02252 {
02253 // constructor
02254    fNlow[0] = lx;
02255    fNlow[1] = ly;
02256    fNlow[2] = lz;
02257    fNhigh[0] = tx;
02258    fNhigh[1] = ty;
02259    fNhigh[2] = tz;
02260    SetShapeBit(kGeoCtub);
02261    ComputeBBox();
02262 }
02263 
02264 //_____________________________________________________________________________
02265 TGeoCtub::TGeoCtub(const char *name, Double_t rmin, Double_t rmax, Double_t dz, Double_t phi1, Double_t phi2,
02266                    Double_t lx, Double_t ly, Double_t lz, Double_t tx, Double_t ty, Double_t tz)
02267          :TGeoTubeSeg(name, rmin, rmax, dz, phi1, phi2)
02268 {
02269 // constructor
02270    fNlow[0] = lx;
02271    fNlow[1] = ly;
02272    fNlow[2] = lz;
02273    fNhigh[0] = tx;
02274    fNhigh[1] = ty;
02275    fNhigh[2] = tz;
02276    SetShapeBit(kGeoCtub);
02277    ComputeBBox();
02278 }
02279 
02280 //_____________________________________________________________________________
02281 TGeoCtub::TGeoCtub(Double_t *params)
02282          :TGeoTubeSeg(0,0,0,0,0)
02283 {
02284 // ctor with parameters
02285    SetCtubDimensions(params[0], params[1], params[2], params[3], params[4], params[5],
02286                      params[6], params[7], params[8], params[9], params[10]);
02287    SetShapeBit(kGeoCtub);
02288 }
02289 
02290 //_____________________________________________________________________________
02291 TGeoCtub::~TGeoCtub()
02292 {
02293 // destructor
02294 }
02295 
02296 //_____________________________________________________________________________
02297 Double_t TGeoCtub::Capacity() const
02298 {
02299 // Computes capacity of the shape in [length^3]
02300    Double_t capacity = TGeoTubeSeg::Capacity();
02301    return capacity;
02302 }   
02303 
02304 //_____________________________________________________________________________
02305 void TGeoCtub::ComputeBBox()
02306 {
02307 // compute minimum bounding box of the ctub
02308    TGeoTubeSeg::ComputeBBox();
02309    if ((fNlow[2]>-(1E-10)) || (fNhigh[2]<1E-10)) {
02310       Error("ComputeBBox", "In shape %s wrong definition of cut planes", GetName());
02311       return;
02312    }
02313    Double_t xc=0, yc=0;
02314    Double_t zmin=0, zmax=0;
02315    Double_t z1;
02316    Double_t z[8];
02317    // check if nxy is in the phi range
02318    Double_t phi_low = TMath::ATan2(fNlow[1], fNlow[0]) *TMath::RadToDeg();
02319    Double_t phi_hi = TMath::ATan2(fNhigh[1], fNhigh[0]) *TMath::RadToDeg();
02320    Bool_t in_range_low = kFALSE;
02321    Bool_t in_range_hi = kFALSE;
02322 
02323    Int_t i;
02324    for (i=0; i<2; i++) {
02325       if (phi_low<0) phi_low+=360.;
02326       Double_t dphi = fPhi2 -fPhi1;
02327       if (dphi < 0) dphi+=360.;
02328       Double_t ddp = phi_low-fPhi1;
02329       if (ddp<0) ddp += 360.;
02330       if (ddp <= dphi) {
02331          xc = fRmin*TMath::Cos(phi_low*TMath::DegToRad());
02332          yc = fRmin*TMath::Sin(phi_low*TMath::DegToRad());
02333          z1 = GetZcoord(xc, yc, -fDz);
02334          xc = fRmax*TMath::Cos(phi_low*TMath::DegToRad());
02335          yc = fRmax*TMath::Sin(phi_low*TMath::DegToRad());
02336          z1 = TMath::Min(z1, GetZcoord(xc, yc, -fDz));
02337          if (in_range_low)
02338             zmin = TMath::Min(zmin, z1);
02339          else
02340             zmin = z1;
02341          in_range_low = kTRUE;
02342       }
02343       phi_low += 180;
02344       if (phi_low>360) phi_low-=360.;
02345    }
02346 
02347    for (i=0; i<2; i++) {
02348       if (phi_hi<0) phi_hi+=360.;
02349       Double_t dphi = fPhi2 -fPhi1;
02350       if (dphi < 0) dphi+=360.;
02351       Double_t ddp = phi_hi-fPhi1;
02352       if (ddp<0) ddp += 360.;
02353       if (ddp <= dphi) {
02354          xc = fRmin*TMath::Cos(phi_hi*TMath::DegToRad());
02355          yc = fRmin*TMath::Sin(phi_hi*TMath::DegToRad());
02356          z1 = GetZcoord(xc, yc, fDz);
02357          xc = fRmax*TMath::Cos(phi_hi*TMath::DegToRad());
02358          yc = fRmax*TMath::Sin(phi_hi*TMath::DegToRad());
02359          z1 = TMath::Max(z1, GetZcoord(xc, yc, fDz));
02360          if (in_range_hi)
02361             zmax = TMath::Max(zmax, z1);
02362          else
02363             zmax = z1;
02364          in_range_hi = kTRUE;
02365       }
02366       phi_hi += 180;
02367       if (phi_hi>360) phi_hi-=360.;
02368    }
02369 
02370 
02371    xc = fRmin*TMath::Cos(fPhi1*TMath::DegToRad());
02372    yc = fRmin*TMath::Sin(fPhi1*TMath::DegToRad());
02373    z[0] = GetZcoord(xc, yc, -fDz);
02374    z[4] = GetZcoord(xc, yc, fDz);
02375 
02376    xc = fRmin*TMath::Cos(fPhi2*TMath::DegToRad());
02377    yc = fRmin*TMath::Sin(fPhi2*TMath::DegToRad());
02378    z[1] = GetZcoord(xc, yc, -fDz);
02379    z[5] = GetZcoord(xc, yc, fDz);
02380 
02381    xc = fRmax*TMath::Cos(fPhi1*TMath::DegToRad());
02382    yc = fRmax*TMath::Sin(fPhi1*TMath::DegToRad());
02383    z[2] = GetZcoord(xc, yc, -fDz);
02384    z[6] = GetZcoord(xc, yc, fDz);
02385 
02386    xc = fRmax*TMath::Cos(fPhi2*TMath::DegToRad());
02387    yc = fRmax*TMath::Sin(fPhi2*TMath::DegToRad());
02388    z[3] = GetZcoord(xc, yc, -fDz);
02389    z[7] = GetZcoord(xc, yc, fDz);
02390 
02391    z1 = z[TMath::LocMin(4, &z[0])];
02392    if (in_range_low)
02393       zmin = TMath::Min(zmin, z1);
02394    else
02395       zmin = z1;
02396 
02397    z1 = z[TMath::LocMax(4, &z[4])+4];
02398    if (in_range_hi)
02399       zmax = TMath::Max(zmax, z1);
02400    else
02401       zmax = z1;
02402 
02403    fDZ = 0.5*(zmax-zmin);
02404    fOrigin[2] = 0.5*(zmax+zmin);
02405 }
02406 
02407 //_____________________________________________________________________________
02408 void TGeoCtub::ComputeNormal(Double_t *point, Double_t *dir, Double_t *norm)
02409 {
02410 // Compute normal to closest surface from POINT.
02411    Double_t saf[4];
02412    Bool_t isseg = kTRUE;
02413    if (TMath::Abs(fPhi2-fPhi1-360.)<1E-8) isseg=kFALSE;
02414    Double_t rsq = point[0]*point[0]+point[1]*point[1];
02415    Double_t r = TMath::Sqrt(rsq);
02416 
02417    saf[0] = TMath::Abs(point[0]*fNlow[0] + point[1]*fNlow[1] + (fDz+point[2])*fNlow[2]);
02418    saf[1] = TMath::Abs(point[0]*fNhigh[0] + point[1]*fNhigh[1] - (fDz-point[2])*fNhigh[2]);
02419    saf[2] = (fRmin>1E-10)?TMath::Abs(r-fRmin):TGeoShape::Big();
02420    saf[3] = TMath::Abs(fRmax-r);
02421    Int_t i = TMath::LocMin(4,saf);
02422    if (isseg) {
02423       Double_t c1 = TMath::Cos(fPhi1*TMath::DegToRad());
02424       Double_t s1 = TMath::Sin(fPhi1*TMath::DegToRad());
02425       Double_t c2 = TMath::Cos(fPhi2*TMath::DegToRad());
02426       Double_t s2 = TMath::Sin(fPhi2*TMath::DegToRad());
02427       if (TGeoShape::IsCloseToPhi(saf[i], point,c1,s1,c2,s2)) {
02428          TGeoShape::NormalPhi(point,dir,norm,c1,s1,c2,s2);
02429          return;
02430       }
02431    }
02432    if (i==0) {
02433       memcpy(norm, fNlow, 3*sizeof(Double_t));
02434       if (norm[0]*dir[0]+norm[1]*dir[1]+norm[2]*dir[2]<0) {
02435          norm[0] = -norm[0];
02436          norm[1] = -norm[1];
02437          norm[2] = -norm[2];
02438       }
02439       return;
02440    }
02441    if (i==1) {
02442       memcpy(norm, fNhigh, 3*sizeof(Double_t));
02443       if (norm[0]*dir[0]+norm[1]*dir[1]+norm[2]*dir[2]<0) {
02444          norm[0] = -norm[0];
02445          norm[1] = -norm[1];
02446          norm[2] = -norm[2];
02447       }
02448       return;
02449    }
02450 
02451    norm[2] = 0;
02452    Double_t phi = TMath::ATan2(point[1], point[0]);
02453    norm[0] = TMath::Cos(phi);
02454    norm[1] = TMath::Sin(phi);
02455    if (norm[0]*dir[0]+norm[1]*dir[1]<0) {
02456       norm[0] = -norm[0];
02457       norm[1] = -norm[1];
02458    }
02459 }
02460 
02461 //_____________________________________________________________________________
02462 Bool_t TGeoCtub::Contains(Double_t *point) const
02463 {
02464 // check if point is contained in the cut tube
02465    // check the lower cut plane
02466    Double_t zin = point[0]*fNlow[0]+point[1]*fNlow[1]+(point[2]+fDz)*fNlow[2];
02467    if (zin>0) return kFALSE;
02468    // check the higher cut plane
02469    zin = point[0]*fNhigh[0]+point[1]*fNhigh[1]+(point[2]-fDz)*fNhigh[2];
02470    if (zin>0) return kFALSE;
02471    // check radius
02472    Double_t r2 = point[0]*point[0]+point[1]*point[1];
02473    if ((r2<fRmin*fRmin) || (r2>fRmax*fRmax)) return kFALSE;
02474    // check phi
02475    Double_t phi = TMath::ATan2(point[1], point[0]) * TMath::RadToDeg();
02476    if (phi < 0 ) phi+=360.;
02477    Double_t dphi = fPhi2 -fPhi1;
02478    Double_t ddp = phi-fPhi1;
02479    if (ddp<0) ddp += 360.;
02480 //   if (ddp>360) ddp-=360;
02481    if (ddp > dphi) return kFALSE;
02482    return kTRUE;
02483 }
02484 
02485 //_____________________________________________________________________________
02486 Double_t TGeoCtub::GetAxisRange(Int_t iaxis, Double_t &xlo, Double_t &xhi) const
02487 {
02488 // Get range of shape for a given axis.
02489    xlo = 0;
02490    xhi = 0;
02491    Double_t dx = 0;
02492    switch (iaxis) {
02493       case 1:
02494          xlo = fRmin;
02495          xhi = fRmax;
02496          dx = xhi-xlo;
02497          return dx;
02498       case 2:
02499          xlo = fPhi1;
02500          xhi = fPhi2;
02501          dx = xhi-xlo;
02502          return dx;
02503    }
02504    return dx;
02505 }
02506 
02507 //_____________________________________________________________________________
02508 Double_t TGeoCtub::GetZcoord(Double_t xc, Double_t yc, Double_t zc) const
02509 {
02510 // compute real Z coordinate of a point belonging to either lower or
02511 // higher caps (z should be either +fDz or -fDz)
02512    Double_t newz = 0;
02513    if (zc<0) newz =  -fDz-(xc*fNlow[0]+yc*fNlow[1])/fNlow[2];
02514    else      newz = fDz-(xc*fNhigh[0]+yc*fNhigh[1])/fNhigh[2];
02515    return newz;
02516 }
02517 
02518 //_____________________________________________________________________________
02519 Double_t TGeoCtub::DistFromOutside(Double_t *point, Double_t *dir, Int_t iact, Double_t step, Double_t *safe) const
02520 {
02521 // compute distance from outside point to surface of the cut tube
02522    if (iact<3 && safe) {
02523       *safe = Safety(point, kFALSE);
02524       if (iact==0) return TGeoShape::Big();
02525       if ((iact==1) && (step<=*safe)) return TGeoShape::Big();
02526    }
02527 // Check if the bounding box is crossed within the requested distance
02528    Double_t sdist = TGeoBBox::DistFromOutside(point,dir, fDX, fDY, fDZ, fOrigin, step);
02529    if (sdist>=step) return TGeoShape::Big();
02530    Double_t saf[2];
02531    saf[0] = point[0]*fNlow[0] + point[1]*fNlow[1] + (fDz+point[2])*fNlow[2];
02532    saf[1] = point[0]*fNhigh[0] + point[1]*fNhigh[1] + (point[2]-fDz)*fNhigh[2];
02533    Double_t rsq = point[0]*point[0]+point[1]*point[1];
02534    Double_t r = TMath::Sqrt(rsq);
02535    Double_t c1=0,s1=0,c2=0,s2=0;
02536    Double_t fio=0, cfio=0, sfio=0, dfi=0, cdfi=0, cpsi=0;
02537    Double_t phi1 = fPhi1*TMath::DegToRad();
02538    Double_t phi2 = fPhi2*TMath::DegToRad();
02539    Bool_t tub = kFALSE;
02540    if (TMath::Abs(fPhi2-fPhi1-360.)<1E-8) tub = kTRUE;
02541    if (!tub) {
02542       c1   = TMath::Cos(phi1);
02543       c2   = TMath::Cos(phi2);
02544       s1   = TMath::Sin(phi1);
02545       s2   = TMath::Sin(phi2);
02546       fio  = 0.5*(phi1+phi2);
02547       cfio = TMath::Cos(fio);
02548       sfio = TMath::Sin(fio);
02549       dfi  = 0.5*(phi2-phi1);
02550       cdfi = TMath::Cos(dfi);
02551    }
02552 
02553    // find distance to shape
02554    Double_t r2;
02555    Double_t calf = dir[0]*fNlow[0]+dir[1]*fNlow[1]+dir[2]*fNlow[2];
02556    // check Z planes
02557    Double_t xi, yi, zi;
02558    Double_t s = TGeoShape::Big();
02559    if (saf[0]>0) {
02560       if (calf<0) {
02561          s = -saf[0]/calf;
02562          xi = point[0]+s*dir[0];
02563          yi = point[1]+s*dir[1];
02564          r2=xi*xi+yi*yi;
02565          if (((fRmin*fRmin)<=r2) && (r2<=(fRmax*fRmax))) {
02566             if (tub) return s;
02567             cpsi=(xi*cfio+yi*sfio)/TMath::Sqrt(r2);
02568             if (cpsi>=cdfi) return s;
02569          }
02570       }
02571    }
02572    calf = dir[0]*fNhigh[0]+dir[1]*fNhigh[1]+dir[2]*fNhigh[2];
02573    if (saf[1]>0) {
02574       if (calf<0) {
02575          s = -saf[1]/calf;
02576          xi = point[0]+s*dir[0];
02577          yi = point[1]+s*dir[1];
02578          r2=xi*xi+yi*yi;
02579          if (((fRmin*fRmin)<=r2) && (r2<=(fRmax*fRmax))) {
02580             if (tub) return s;
02581             cpsi=(xi*cfio+yi*sfio)/TMath::Sqrt(r2);
02582             if (cpsi>=cdfi) return s;
02583          }
02584       }
02585    }
02586 
02587    // check outer cyl. surface
02588    Double_t nsq=dir[0]*dir[0]+dir[1]*dir[1];
02589    if (TMath::Abs(nsq)<1E-10) return TGeoShape::Big();
02590    Double_t rdotn=point[0]*dir[0]+point[1]*dir[1];
02591    Double_t b,d;
02592    // only r>fRmax has to be considered
02593    if (r>fRmax) {
02594       TGeoTube::DistToTube(rsq, nsq, rdotn, fRmax, b, d);
02595       if (d>0) {
02596          s=-b-d;
02597          if (s>0) {
02598             xi=point[0]+s*dir[0];
02599             yi=point[1]+s*dir[1];
02600             zi=point[2]+s*dir[2];
02601             if ((-xi*fNlow[0]-yi*fNlow[1]-(zi+fDz)*fNlow[2])>0) {
02602                if ((-xi*fNhigh[0]-yi*fNhigh[1]+(fDz-zi)*fNhigh[2])>0) {
02603                   if (tub) return s;
02604                   cpsi=(xi*cfio+yi*sfio)/fRmax;
02605                   if (cpsi>=cdfi) return s;
02606                }
02607             }
02608          }
02609       }
02610    }
02611    // check inner cylinder
02612    Double_t snxt=TGeoShape::Big();
02613    if (fRmin>0) {
02614       TGeoTube::DistToTube(rsq, nsq, rdotn, fRmin, b, d);
02615       if (d>0) {
02616          s=-b+d;
02617          if (s>0) {
02618             xi=point[0]+s*dir[0];
02619             yi=point[1]+s*dir[1];
02620             zi=point[2]+s*dir[2];
02621             if ((-xi*fNlow[0]-yi*fNlow[1]-(zi+fDz)*fNlow[2])>0) {
02622                if ((-xi*fNhigh[0]-yi*fNhigh[1]+(fDz-zi)*fNhigh[2])>0) {
02623                   if (tub) return s;
02624                   cpsi=(xi*cfio+yi*sfio)/fRmin;
02625                   if (cpsi>=cdfi) snxt=s;
02626                }
02627             }
02628          }
02629       }
02630    }
02631    // check phi planes
02632    if (tub) return snxt;
02633    Double_t un=dir[0]*s1-dir[1]*c1;
02634    if (!TGeoShape::IsSameWithinTolerance(un,0)) {
02635       s=(point[1]*c1-point[0]*s1)/un;
02636       if (s>=0) {
02637          xi=point[0]+s*dir[0];
02638          yi=point[1]+s*dir[1];
02639          zi=point[2]+s*dir[2];
02640          if ((-xi*fNlow[0]-yi*fNlow[1]-(zi+fDz)*fNlow[2])>0) {
02641             if ((-xi*fNhigh[0]-yi*fNhigh[1]+(fDz-zi)*fNhigh[2])>0) {
02642                r2=xi*xi+yi*yi;
02643                if ((fRmin*fRmin<=r2) && (r2<=fRmax*fRmax)) {
02644                   if ((yi*cfio-xi*sfio)<=0) {
02645                      if (s<snxt) snxt=s;
02646                   }
02647                }
02648             }
02649          }
02650       }
02651    }
02652    un=dir[0]*s2-dir[1]*c2;
02653    if (!TGeoShape::IsSameWithinTolerance(un,0)) {
02654       s=(point[1]*c2-point[0]*s2)/un;
02655       if (s>=0) {
02656          xi=point[0]+s*dir[0];
02657          yi=point[1]+s*dir[1];
02658          zi=point[2]+s*dir[2];
02659          if ((-xi*fNlow[0]-yi*fNlow[1]-(zi+fDz)*fNlow[2])>0) {
02660             if ((-xi*fNhigh[0]-yi*fNhigh[1]+(fDz-zi)*fNhigh[2])>0) {
02661                r2=xi*xi+yi*yi;
02662                if ((fRmin*fRmin<=r2) && (r2<=fRmax*fRmax)) {
02663                   if ((yi*cfio-xi*sfio)>=0) {
02664                      if (s<snxt) snxt=s;
02665                   }
02666                }
02667             }
02668          }
02669       }
02670    }
02671    return snxt;
02672 }
02673 
02674 //_____________________________________________________________________________
02675 Double_t TGeoCtub::DistFromInside(Double_t *point, Double_t *dir, Int_t iact, Double_t step, Double_t *safe) const
02676 {
02677 // compute distance from inside point to surface of the cut tube
02678    if (iact<3 && safe) *safe = Safety(point, kTRUE);
02679    if (iact==0) return TGeoShape::Big();
02680    if ((iact==1) && (*safe>step)) return TGeoShape::Big();
02681    Double_t rsq = point[0]*point[0]+point[1]*point[1];
02682    Double_t c1=0,s1=0,c2=0,s2=0,cm=0,sm=0,phim=0;
02683    Double_t phi1 = fPhi1*TMath::DegToRad();
02684    Double_t phi2 = fPhi2*TMath::DegToRad();
02685    Bool_t tub = kFALSE;
02686    if (TMath::Abs(fPhi2-fPhi1-360.)<1E-8) tub = kTRUE;
02687    if (!tub) {
02688       if (phi2<phi1) phi2+=2.*TMath::Pi();
02689       phim = 0.5*(phi1+phi2);
02690       c1 = TMath::Cos(phi1);
02691       c2 = TMath::Cos(phi2);
02692       s1 = TMath::Sin(phi1);
02693       s2 = TMath::Sin(phi2);
02694       cm = TMath::Cos(phim);
02695       sm = TMath::Sin(phim);
02696    }
02697    // compute distance to surface
02698    // Do Z
02699    Double_t sz = TGeoShape::Big();
02700    Double_t saf[2];
02701    saf[0] = -point[0]*fNlow[0] - point[1]*fNlow[1] - (fDz+point[2])*fNlow[2];
02702    saf[1] = -point[0]*fNhigh[0] - point[1]*fNhigh[1] + (fDz-point[2])*fNhigh[2];
02703    Double_t calf = dir[0]*fNlow[0]+dir[1]*fNlow[1]+dir[2]*fNlow[2];
02704    if (calf>0) sz = saf[0]/calf;
02705 
02706    Double_t sz1=TGeoShape::Big();
02707    calf = dir[0]*fNhigh[0]+dir[1]*fNhigh[1]+dir[2]*fNhigh[2];
02708    if (calf>0) {
02709       sz1 = saf[1]/calf;
02710       if (sz1<sz) sz = sz1;
02711    }
02712 
02713    // Do R
02714    Double_t nsq=dir[0]*dir[0]+dir[1]*dir[1];
02715    // track parallel to Z
02716    if (TMath::Abs(nsq)<1E-10) return sz;
02717    Double_t rdotn=point[0]*dir[0]+point[1]*dir[1];
02718    Double_t sr=TGeoShape::Big();
02719    Double_t b, d;
02720    Bool_t skip_outer = kFALSE;
02721    // inner cylinder
02722    if (fRmin>1E-10) {
02723       TGeoTube::DistToTube(rsq, nsq, rdotn, fRmin, b, d);
02724       if (d>0) {
02725          sr=-b-d;
02726          if (sr>0) skip_outer = kTRUE;
02727       }
02728    }
02729    // outer cylinder
02730    if (!skip_outer) {
02731       TGeoTube::DistToTube(rsq, nsq, rdotn, fRmax, b, d);
02732       if (d>0) {
02733          sr=-b+d;
02734          if (sr<0) sr=TGeoShape::Big();
02735       } else {
02736          Error("DistFromInside", "In shape %s cannot get outside !", GetName());
02737       }
02738    }
02739    // phi planes
02740    Double_t sfmin = TGeoShape::Big();
02741    if (!tub) sfmin=TGeoShape::DistToPhiMin(point, dir, s1, c1, s2, c2, sm, cm);
02742    return TMath::Min(TMath::Min(sz,sr), sfmin);
02743 }
02744 
02745 //_____________________________________________________________________________
02746 TGeoVolume *TGeoCtub::Divide(TGeoVolume * /*voldiv*/, const char * /*divname*/, Int_t /*iaxis*/, Int_t /*ndiv*/,
02747                              Double_t /*start*/, Double_t /*step*/)
02748 {
02749 // Divide the tube along one axis.
02750    Warning("Divide", "In shape %s division of a cut tube not implemented", GetName());
02751    return 0;
02752 }
02753 
02754 //_____________________________________________________________________________
02755 TGeoShape *TGeoCtub::GetMakeRuntimeShape(TGeoShape *mother, TGeoMatrix * /*mat*/) const
02756 {
02757 // in case shape has some negative parameters, these has to be computed
02758 // in order to fit the mother
02759    if (!TestShapeBit(kGeoRunTimeShape)) return 0;
02760    if (!mother->TestShapeBit(kGeoTube)) {
02761       Error("GetMakeRuntimeShape", "Invalid mother for shape %s", GetName());
02762       return 0;
02763    }
02764    Double_t rmin, rmax, dz;
02765    rmin = fRmin;
02766    rmax = fRmax;
02767    dz = fDz;
02768    if (fDz<0) dz=((TGeoTube*)mother)->GetDz();
02769    if (fRmin<0)
02770       rmin = ((TGeoTube*)mother)->GetRmin();
02771    if ((fRmax<0) || (fRmax<=fRmin))
02772       rmax = ((TGeoTube*)mother)->GetRmax();
02773 
02774    return (new TGeoCtub(rmin, rmax, dz, fPhi1, fPhi2, fNlow[0], fNlow[1], fNlow[2],
02775                         fNhigh[0], fNhigh[1], fNhigh[2]));
02776 }
02777 
02778 //_____________________________________________________________________________
02779 void TGeoCtub::InspectShape() const
02780 {
02781 // print shape parameters
02782    printf("*** Shape %s: TGeoCtub ***\n", GetName());
02783    printf("    lx = %11.5f\n", fNlow[0]);
02784    printf("    ly = %11.5f\n", fNlow[1]);
02785    printf("    lz = %11.5f\n", fNlow[2]);
02786    printf("    tx = %11.5f\n", fNhigh[0]);
02787    printf("    ty = %11.5f\n", fNhigh[1]);
02788    printf("    tz = %11.5f\n", fNhigh[2]);
02789    TGeoTubeSeg::InspectShape();
02790 }
02791 
02792 //_____________________________________________________________________________
02793 Double_t TGeoCtub::Safety(Double_t *point, Bool_t in) const
02794 {
02795 // computes the closest distance from given point to this shape, according
02796 // to option. The matching point on the shape is stored in spoint.
02797    Double_t saf[4];
02798    Double_t rsq = point[0]*point[0]+point[1]*point[1];
02799    Double_t r = TMath::Sqrt(rsq);
02800    Bool_t isseg = kTRUE;
02801    if (TMath::Abs(fPhi2-fPhi1-360.)<1E-8) isseg=kFALSE;
02802 
02803    saf[0] = -point[0]*fNlow[0] - point[1]*fNlow[1] - (fDz+point[2])*fNlow[2];
02804    saf[1] = -point[0]*fNhigh[0] - point[1]*fNhigh[1] + (fDz-point[2])*fNhigh[2];
02805    saf[2] = (fRmin<1E-10 && !isseg)?TGeoShape::Big():(r-fRmin);
02806    saf[3] = fRmax-r;
02807    Double_t safphi = TGeoShape::Big();
02808    Double_t safe = TGeoShape::Big();
02809    if (isseg) safphi =  TGeoShape::SafetyPhi(point, in, fPhi1, fPhi2);
02810 
02811    if (in) {
02812       safe = saf[TMath::LocMin(4,saf)];
02813       return TMath::Min(safe, safphi);
02814    }
02815    for (Int_t i=0; i<4; i++) saf[i]=-saf[i];
02816    safe = saf[TMath::LocMax(4,saf)];
02817    if (isseg) return TMath::Max(safe, safphi);
02818    return safe;
02819 }
02820 
02821 //_____________________________________________________________________________
02822 void TGeoCtub::SetCtubDimensions(Double_t rmin, Double_t rmax, Double_t dz, Double_t phi1, Double_t phi2,
02823                    Double_t lx, Double_t ly, Double_t lz, Double_t tx, Double_t ty, Double_t tz)
02824 {
02825 // set dimensions of a cut tube
02826    SetTubsDimensions(rmin, rmax, dz, phi1, phi2);
02827    fNlow[0] = lx;
02828    fNlow[1] = ly;
02829    fNlow[2] = lz;
02830    fNhigh[0] = tx;
02831    fNhigh[1] = ty;
02832    fNhigh[2] = tz;
02833    ComputeBBox();
02834 }
02835 
02836 //_____________________________________________________________________________
02837 void TGeoCtub::SavePrimitive(ostream &out, Option_t * /*option*/ /*= ""*/)
02838 {
02839 // Save a primitive as a C++ statement(s) on output stream "out".
02840    if (TObject::TestBit(kGeoSavePrimitive)) return;
02841    out << "   // Shape: " << GetName() << " type: " << ClassName() << endl;
02842    out << "   rmin = " << fRmin << ";" << endl;
02843    out << "   rmax = " << fRmax << ";" << endl;
02844    out << "   dz   = " << fDz << ";" << endl;
02845    out << "   phi1 = " << fPhi1 << ";" << endl;
02846    out << "   phi2 = " << fPhi2 << ";" << endl;
02847    out << "   lx   = " << fNlow[0] << ";" << endl;
02848    out << "   ly   = " << fNlow[1] << ";" << endl;
02849    out << "   lz   = " << fNlow[2] << ";" << endl;
02850    out << "   tx   = " << fNhigh[0] << ";" << endl;
02851    out << "   ty   = " << fNhigh[1] << ";" << endl;
02852    out << "   tz   = " << fNhigh[2] << ";" << endl;
02853    out << "   TGeoShape *" << GetPointerName() << " = new TGeoCtub(\"" << GetName() << "\",rmin,rmax,dz,phi1,phi2,lx,ly,lz,tx,ty,tz);" << endl;   TObject::SetBit(TGeoShape::kGeoSavePrimitive);
02854 }
02855 
02856 //_____________________________________________________________________________
02857 void TGeoCtub::SetDimensions(Double_t *param)
02858 {
02859 // Set dimensions of the cut tube starting from a list.
02860    SetCtubDimensions(param[0], param[1], param[2], param[3], param[4], param[5],
02861                      param[6], param[7], param[8], param[9], param[10]);
02862    ComputeBBox();
02863 }
02864 
02865 //_____________________________________________________________________________
02866 Bool_t TGeoCtub::GetPointsOnSegments(Int_t /*npoints*/, Double_t * /*array*/) const
02867 {
02868 // Fills array with n random points located on the line segments of the shape mesh.
02869 // The output array must be provided with a length of minimum 3*npoints. Returns
02870 // true if operation is implemented.
02871    return kFALSE;
02872 }
02873 
02874 //_____________________________________________________________________________
02875 void TGeoCtub::SetPoints(Double_t *points) const
02876 {
02877 // Create mesh points for the cut tube.
02878    Double_t dz;
02879    Int_t j, n;
02880    Double_t phi, phi1, phi2, dphi;
02881    phi1 = fPhi1;
02882    phi2 = fPhi2;
02883    if (phi2<phi1) phi2+=360.;
02884    n = gGeoManager->GetNsegments()+1;
02885 
02886    dphi = (phi2-phi1)/(n-1);
02887    dz   = fDz;
02888 
02889    if (points) {
02890       Int_t indx = 0;
02891 
02892       for (j = 0; j < n; j++) {
02893          phi = (phi1+j*dphi)*TMath::DegToRad();
02894          points[indx+6*n] = points[indx] = fRmin * TMath::Cos(phi);
02895          indx++;
02896          points[indx+6*n] = points[indx] = fRmin * TMath::Sin(phi);
02897          indx++;
02898          points[indx+6*n] = GetZcoord(points[indx-2], points[indx-1], dz);
02899          points[indx]     = GetZcoord(points[indx-2], points[indx-1], -dz);
02900          indx++;
02901       }
02902       for (j = 0; j < n; j++) {
02903          phi = (phi1+j*dphi)*TMath::DegToRad();
02904          points[indx+6*n] = points[indx] = fRmax * TMath::Cos(phi);
02905          indx++;
02906          points[indx+6*n] = points[indx] = fRmax * TMath::Sin(phi);
02907          indx++;
02908          points[indx+6*n]= GetZcoord(points[indx-2], points[indx-1], dz);
02909          points[indx]    = GetZcoord(points[indx-2], points[indx-1], -dz);
02910          indx++;
02911       }
02912    }
02913 }
02914 
02915 //_____________________________________________________________________________
02916 void TGeoCtub::SetPoints(Float_t *points) const
02917 {
02918 // Create mesh points for the cut tube.
02919    Double_t dz;
02920    Int_t j, n;
02921    Double_t phi, phi1, phi2, dphi;
02922    phi1 = fPhi1;
02923    phi2 = fPhi2;
02924    if (phi2<phi1) phi2+=360.;
02925    n = gGeoManager->GetNsegments()+1;
02926 
02927    dphi = (phi2-phi1)/(n-1);
02928    dz   = fDz;
02929 
02930    if (points) {
02931       Int_t indx = 0;
02932 
02933       for (j = 0; j < n; j++) {
02934          phi = (phi1+j*dphi)*TMath::DegToRad();
02935          points[indx+6*n] = points[indx] = fRmin * TMath::Cos(phi);
02936          indx++;
02937          points[indx+6*n] = points[indx] = fRmin * TMath::Sin(phi);
02938          indx++;
02939          points[indx+6*n] = GetZcoord(points[indx-2], points[indx-1], dz);
02940          points[indx]     = GetZcoord(points[indx-2], points[indx-1], -dz);
02941          indx++;
02942       }
02943       for (j = 0; j < n; j++) {
02944          phi = (phi1+j*dphi)*TMath::DegToRad();
02945          points[indx+6*n] = points[indx] = fRmax * TMath::Cos(phi);
02946          indx++;
02947          points[indx+6*n] = points[indx] = fRmax * TMath::Sin(phi);
02948          indx++;
02949          points[indx+6*n]= GetZcoord(points[indx-2], points[indx-1], dz);
02950          points[indx]    = GetZcoord(points[indx-2], points[indx-1], -dz);
02951          indx++;
02952       }
02953    }
02954 }
02955 
02956 //_____________________________________________________________________________
02957 void TGeoCtub::GetMeshNumbers(Int_t &nvert, Int_t &nsegs, Int_t &npols) const
02958 {
02959 // Returns numbers of vertices, segments and polygons composing the shape mesh.
02960    TGeoTubeSeg::GetMeshNumbers(nvert,nsegs,npols);
02961 }
02962 
02963 //_____________________________________________________________________________
02964 Int_t TGeoCtub::GetNmeshVertices() const
02965 {
02966 // Return number of vertices of the mesh representation
02967    Int_t n = gGeoManager->GetNsegments()+1;
02968    Int_t numPoints = n*4;
02969    return numPoints;
02970 }
02971 
02972 //_____________________________________________________________________________
02973 const TBuffer3D & TGeoCtub::GetBuffer3D(Int_t reqSections, Bool_t localFrame) const
02974 {
02975 // Fills a static 3D buffer and returns a reference.
02976    static TBuffer3DCutTube buffer;
02977 
02978    TGeoBBox::FillBuffer3D(buffer, reqSections, localFrame);
02979 
02980    if (reqSections & TBuffer3D::kShapeSpecific) {
02981       // These from TBuffer3DCutTube / TGeoCtub
02982       buffer.fRadiusInner  = fRmin;
02983       buffer.fRadiusOuter  = fRmax;
02984       buffer.fHalfLength   = fDz;
02985       buffer.fPhiMin       = fPhi1;
02986       buffer.fPhiMax       = fPhi2;
02987 
02988       for (UInt_t i = 0; i < 3; i++ ) {
02989          buffer.fLowPlaneNorm[i] = fNlow[i];
02990          buffer.fHighPlaneNorm[i] = fNhigh[i];
02991       }
02992       buffer.SetSectionsValid(TBuffer3D::kShapeSpecific);
02993    }
02994    if (reqSections & TBuffer3D::kRawSizes) {
02995       Int_t n = gGeoManager->GetNsegments()+1;
02996       Int_t nbPnts = 4*n;
02997       Int_t nbSegs = 2*nbPnts;
02998       Int_t nbPols = nbPnts-2;
02999       if (buffer.SetRawSizes(nbPnts, 3*nbPnts, nbSegs, 3*nbSegs, nbPols, 6*nbPols)) {
03000          buffer.SetSectionsValid(TBuffer3D::kRawSizes);
03001       }
03002    }
03003    if ((reqSections & TBuffer3D::kRaw) && buffer.SectionsValid(TBuffer3D::kRawSizes)) {
03004       SetPoints(buffer.fPnts);
03005       if (!buffer.fLocalFrame) {
03006          TransformPoints(buffer.fPnts, buffer.NbPnts());
03007       }
03008       SetSegsAndPols(buffer);
03009       buffer.SetSectionsValid(TBuffer3D::kRaw);
03010    }
03011 
03012    return buffer;
03013 }

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