TGeoPcon.cxx

Go to the documentation of this file.
00001 // @(#)root/geom:$Id: TGeoPcon.cxx 34894 2010-08-20 15:23:12Z agheata $
00002 // Author: Andrei Gheata   24/10/01
00003 // TGeoPcon::Contains() 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 // TGeoPcon - a polycone. It has at least 9 parameters :
00015 //            - the lower phi limit;
00016 //            - the range in phi;
00017 //            - the number of z planes (at least two) where the inner/outer 
00018 //              radii are changing;
00019 //            - z coordinate, inner and outer radius for each z plane
00020 //
00021 //_____________________________________________________________________________
00022 //Begin_Html
00023 /*
00024 <img src="gif/t_pcon.gif">
00025 */
00026 //End_Html
00027 
00028 //Begin_Html
00029 /*
00030 <img src="gif/t_pcondivPHI.gif">
00031 */
00032 //End_Html
00033 
00034 //Begin_Html
00035 /*
00036 <img src="gif/t_pcondivstepPHI.gif">
00037 */
00038 //End_Html
00039 
00040 //Begin_Html
00041 /*
00042 <img src="gif/t_pcondivstepZ.gif">
00043 */
00044 //End_Html
00045 
00046 #include "Riostream.h"
00047 
00048 #include "TGeoManager.h"
00049 #include "TGeoVolume.h"
00050 #include "TVirtualGeoPainter.h"
00051 #include "TGeoTube.h"
00052 #include "TGeoCone.h"
00053 #include "TGeoPcon.h"
00054 #include "TVirtualPad.h"
00055 #include "TBuffer3D.h"
00056 #include "TBuffer3DTypes.h"
00057 #include "TMath.h"
00058 
00059 ClassImp(TGeoPcon)
00060 
00061 //_____________________________________________________________________________
00062 TGeoPcon::TGeoPcon()
00063          :TGeoBBox(0, 0, 0),
00064           fNz(0),
00065           fPhi1(0.),
00066           fDphi(0.),
00067           fRmin(NULL),
00068           fRmax(NULL),
00069           fZ(NULL)
00070 {
00071 // dummy ctor
00072    SetShapeBit(TGeoShape::kGeoPcon);
00073 }   
00074 
00075 //_____________________________________________________________________________
00076 TGeoPcon::TGeoPcon(Double_t phi, Double_t dphi, Int_t nz)
00077          :TGeoBBox(0, 0, 0),
00078           fNz(nz),
00079           fPhi1(phi),
00080           fDphi(dphi),
00081           fRmin(NULL),
00082           fRmax(NULL),
00083           fZ(NULL)
00084 {
00085 // Default constructor
00086    SetShapeBit(TGeoShape::kGeoPcon);
00087    if (fPhi1<0) fPhi1+=360.;
00088    fRmin = new Double_t [nz];
00089    fRmax = new Double_t [nz];
00090    fZ    = new Double_t [nz];
00091    memset(fRmin, 0, nz*sizeof(Double_t));
00092    memset(fRmax, 0, nz*sizeof(Double_t));
00093    memset(fZ, 0, nz*sizeof(Double_t));
00094 }
00095 
00096 //_____________________________________________________________________________
00097 TGeoPcon::TGeoPcon(const char *name, Double_t phi, Double_t dphi, Int_t nz)
00098          :TGeoBBox(name, 0, 0, 0),
00099           fNz(nz),
00100           fPhi1(phi),
00101           fDphi(dphi),
00102           fRmin(NULL),
00103           fRmax(NULL),
00104           fZ(NULL)         
00105 {
00106 // Default constructor
00107    SetShapeBit(TGeoShape::kGeoPcon);
00108    if (fPhi1<0) fPhi1+=360.;
00109    fRmin = new Double_t [nz];
00110    fRmax = new Double_t [nz];
00111    fZ    = new Double_t [nz];
00112    memset(fRmin, 0, nz*sizeof(Double_t));
00113    memset(fRmax, 0, nz*sizeof(Double_t));
00114    memset(fZ, 0, nz*sizeof(Double_t));
00115 }
00116 
00117 //_____________________________________________________________________________
00118 TGeoPcon::TGeoPcon(Double_t *param)
00119          :TGeoBBox(0, 0, 0),
00120           fNz(0),
00121           fPhi1(0.),
00122           fDphi(0.),
00123           fRmin(0),
00124           fRmax(0),
00125           fZ(0)
00126 {
00127 // Default constructor in GEANT3 style
00128 // param[0] = phi1
00129 // param[1] = dphi
00130 // param[2] = nz
00131 //
00132 // param[3] = z1
00133 // param[4] = Rmin1
00134 // param[5] = Rmax1
00135 // ...
00136    SetShapeBit(TGeoShape::kGeoPcon);
00137    SetDimensions(param);
00138    ComputeBBox();
00139 }
00140 
00141 //_____________________________________________________________________________
00142 TGeoPcon::TGeoPcon(const TGeoPcon& pc) : 
00143   TGeoBBox(pc),
00144   fNz(pc.fNz),
00145   fPhi1(pc.fPhi1),
00146   fDphi(pc.fDphi),
00147   fRmin(pc.fRmin),
00148   fRmax(pc.fRmax),
00149   fZ(pc.fZ)
00150 { 
00151    //copy constructor
00152 }
00153 
00154 //_____________________________________________________________________________
00155 TGeoPcon& TGeoPcon::operator=(const TGeoPcon& pc) 
00156 {
00157    //assignment operator
00158    if(this!=&pc) {
00159       TGeoBBox::operator=(pc);
00160       fNz=pc.fNz;
00161       fPhi1=pc.fPhi1;
00162       fDphi=pc.fDphi;
00163       fRmin=pc.fRmin;
00164       fRmax=pc.fRmax;
00165       fZ=pc.fZ;
00166    } 
00167    return *this;
00168 }
00169 
00170 //_____________________________________________________________________________
00171 TGeoPcon::~TGeoPcon()
00172 {
00173 // destructor
00174    if (fRmin) {delete[] fRmin; fRmin = 0;}
00175    if (fRmax) {delete[] fRmax; fRmax = 0;}
00176    if (fZ)    {delete[] fZ; fZ = 0;}
00177 }
00178 
00179 //_____________________________________________________________________________
00180 Double_t TGeoPcon::Capacity() const
00181 {
00182 // Computes capacity of the shape in [length^3]
00183    Int_t ipl;
00184    Double_t rmin1, rmax1, rmin2, rmax2, phi1, phi2, dz;
00185    Double_t capacity = 0.;
00186    phi1 = fPhi1;
00187    phi2 = fPhi1 + fDphi;
00188    for (ipl=0; ipl<fNz-1; ipl++) {
00189       dz    = 0.5*(fZ[ipl+1]-fZ[ipl]);
00190       if (dz < TGeoShape::Tolerance()) continue;
00191       rmin1 = fRmin[ipl];
00192       rmax1 = fRmax[ipl];
00193       rmin2 = fRmin[ipl+1];
00194       rmax2 = fRmax[ipl+1];
00195       capacity += TGeoConeSeg::Capacity(dz,rmin1,rmax1,rmin2,rmax2,phi1,phi2);
00196    }
00197    return capacity;   
00198 }
00199 
00200 //_____________________________________________________________________________   
00201 void TGeoPcon::ComputeBBox()
00202 {
00203 // compute bounding box of the pcon
00204    // Check if the sections are in increasing Z order
00205    for (Int_t isec=0; isec<fNz-1; isec++) {
00206       if (TMath::Abs(fZ[isec]-fZ[isec+1]) < TGeoShape::Tolerance()) fZ[isec+1]=fZ[isec];
00207       if (fZ[isec]>fZ[isec+1]) {
00208          InspectShape();
00209          Fatal("ComputeBBox", "Wrong section order");
00210       }   
00211    }
00212    // Check if the last sections are valid
00213    if (TMath::Abs(fZ[1]-fZ[0]) < TGeoShape::Tolerance() ||
00214        TMath::Abs(fZ[fNz-1]-fZ[fNz-2]) < TGeoShape::Tolerance()) {
00215       InspectShape();
00216       Fatal("ComputeBBox","Shape %s at index %d: Not allowed first two or last two sections at same Z",
00217              GetName(), gGeoManager->GetListOfShapes()->IndexOf(this));
00218    }          
00219    Double_t zmin = TMath::Min(fZ[0], fZ[fNz-1]);
00220    Double_t zmax = TMath::Max(fZ[0], fZ[fNz-1]);
00221    // find largest rmax an smallest rmin
00222    Double_t rmin, rmax;
00223    rmin = fRmin[TMath::LocMin(fNz, fRmin)];
00224    rmax = fRmax[TMath::LocMax(fNz, fRmax)];
00225    Double_t phi1 = fPhi1;
00226    Double_t phi2 = phi1 + fDphi;
00227    
00228    Double_t xc[4];
00229    Double_t yc[4];
00230    xc[0] = rmax*TMath::Cos(phi1*TMath::DegToRad());
00231    yc[0] = rmax*TMath::Sin(phi1*TMath::DegToRad());
00232    xc[1] = rmax*TMath::Cos(phi2*TMath::DegToRad());
00233    yc[1] = rmax*TMath::Sin(phi2*TMath::DegToRad());
00234    xc[2] = rmin*TMath::Cos(phi1*TMath::DegToRad());
00235    yc[2] = rmin*TMath::Sin(phi1*TMath::DegToRad());
00236    xc[3] = rmin*TMath::Cos(phi2*TMath::DegToRad());
00237    yc[3] = rmin*TMath::Sin(phi2*TMath::DegToRad());
00238 
00239    Double_t xmin = xc[TMath::LocMin(4, &xc[0])];
00240    Double_t xmax = xc[TMath::LocMax(4, &xc[0])]; 
00241    Double_t ymin = yc[TMath::LocMin(4, &yc[0])]; 
00242    Double_t ymax = yc[TMath::LocMax(4, &yc[0])];
00243 
00244    Double_t ddp = -phi1;
00245    if (ddp<0) ddp+= 360;
00246    if (ddp<=fDphi) xmax = rmax;
00247    ddp = 90-phi1;
00248    if (ddp<0) ddp+= 360;
00249    if (ddp<=fDphi) ymax = rmax;
00250    ddp = 180-phi1;
00251    if (ddp<0) ddp+= 360;
00252    if (ddp<=fDphi) xmin = -rmax;
00253    ddp = 270-phi1;
00254    if (ddp<0) ddp+= 360;
00255    if (ddp<=fDphi) ymin = -rmax;
00256    fOrigin[0] = (xmax+xmin)/2;
00257    fOrigin[1] = (ymax+ymin)/2;
00258    fOrigin[2] = (zmax+zmin)/2;
00259    fDX = (xmax-xmin)/2;
00260    fDY = (ymax-ymin)/2;
00261    fDZ = (zmax-zmin)/2;
00262    SetShapeBit(kGeoClosedShape);
00263 }   
00264 
00265 //_____________________________________________________________________________   
00266 void TGeoPcon::ComputeNormal(Double_t *point, Double_t *dir, Double_t *norm)
00267 {
00268 // Compute normal to closest surface from POINT. 
00269    memset(norm,0,3*sizeof(Double_t));
00270    Double_t r;
00271    Double_t ptnew[3];
00272    Double_t dz, rmin1, rmax1, rmin2, rmax2;
00273    Bool_t is_tube, is_seg;
00274    Double_t phi1=0, phi2=0, c1=0, s1=0, c2=0, s2=0;
00275    Int_t ipl = TMath::BinarySearch(fNz, fZ, point[2]);
00276    if (ipl==(fNz-1) || ipl<0) {
00277       // point outside Z range
00278       norm[2] = TMath::Sign(1., dir[2]);
00279       return;
00280    }
00281    Int_t iplclose = ipl;
00282    if ((fZ[ipl+1]-point[2])<(point[2]-fZ[ipl])) iplclose++;
00283    dz = TMath::Abs(fZ[iplclose]-point[2]);
00284    if (dz<1E-5) {
00285       if (iplclose==0 || iplclose==(fNz-1)) {
00286          norm[2] = TMath::Sign(1., dir[2]);
00287          return;
00288       }
00289       if (iplclose==ipl && TGeoShape::IsSameWithinTolerance(fZ[ipl],fZ[ipl-1])) {
00290          r = TMath::Sqrt(point[0]*point[0]+point[1]*point[1]);
00291          if (r<TMath::Max(fRmin[ipl],fRmin[ipl-1]) || r>TMath::Min(fRmax[ipl],fRmax[ipl-1])) {
00292             norm[2] = TMath::Sign(1., dir[2]);
00293             return;
00294          }
00295       } else {
00296          if (TGeoShape::IsSameWithinTolerance(fZ[iplclose],fZ[iplclose+1])) {
00297             r = TMath::Sqrt(point[0]*point[0]+point[1]*point[1]);
00298             if (r<TMath::Max(fRmin[iplclose],fRmin[iplclose+1]) || r>TMath::Min(fRmax[iplclose],fRmax[iplclose+1])) {
00299                norm[2] = TMath::Sign(1., dir[2]);
00300                return;
00301             }
00302          }
00303       }
00304    } //-> Z done
00305    memcpy(ptnew, point, 3*sizeof(Double_t));
00306    dz = 0.5*(fZ[ipl+1]-fZ[ipl]);
00307    if (TGeoShape::IsSameWithinTolerance(dz,0.)) {
00308       norm[2] = TMath::Sign(1., dir[2]);
00309       return;
00310    }         
00311    ptnew[2] -= 0.5*(fZ[ipl]+fZ[ipl+1]);
00312    rmin1 = fRmin[ipl];
00313    rmax1 = fRmax[ipl];
00314    rmin2 = fRmin[ipl+1];
00315    rmax2 = fRmax[ipl+1];
00316    is_tube = (TGeoShape::IsSameWithinTolerance(rmin1,rmin2) && TGeoShape::IsSameWithinTolerance(rmax1,rmax2))?kTRUE:kFALSE;
00317    is_seg  = (fDphi<360)?kTRUE:kFALSE;
00318    if (is_seg) {
00319       phi1 = fPhi1;
00320       if (phi1<0) phi1+=360;
00321       phi2 = phi1 + fDphi;
00322       phi1 *= TMath::DegToRad();
00323       phi2 *= TMath::DegToRad();
00324       c1 = TMath::Cos(phi1);
00325       s1 = TMath::Sin(phi1);
00326       c2 = TMath::Cos(phi2);
00327       s2 = TMath::Sin(phi2);
00328       if (is_tube) TGeoTubeSeg::ComputeNormalS(ptnew,dir,norm,rmin1,rmax1,dz,c1,s1,c2,s2);
00329       else         TGeoConeSeg::ComputeNormalS(ptnew,dir,norm,dz,rmin1,rmax1,rmin2,rmax2,c1,s1,c2,s2);
00330    } else {
00331       if (is_tube) TGeoTube::ComputeNormalS(ptnew,dir,norm,rmin1,rmax1,dz);
00332       else         TGeoCone::ComputeNormalS(ptnew,dir,norm,dz,rmin1,rmax1,rmin2,rmax2);
00333    }
00334 }
00335 
00336 //_____________________________________________________________________________
00337 Bool_t TGeoPcon::Contains(Double_t *point) const
00338 {
00339 // test if point is inside this shape
00340    // check total z range
00341    if ((point[2]<fZ[0]) || (point[2]>fZ[fNz-1])) return kFALSE;
00342    // check R squared
00343    Double_t r2 = point[0]*point[0]+point[1]*point[1];
00344    
00345    Int_t izl = 0;
00346    Int_t izh = fNz-1;
00347    Int_t izt = (fNz-1)/2;
00348    while ((izh-izl)>1) {
00349       if (point[2] > fZ[izt]) izl = izt;     
00350       else izh = izt;
00351       izt = (izl+izh)>>1;
00352    }
00353    // the point is in the section bounded by izl and izh Z planes
00354    
00355    // compute Rmin and Rmax and test the value of R squared
00356    Double_t rmin, rmax;  
00357    if (TGeoShape::IsSameWithinTolerance(fZ[izl],fZ[izh]) && TGeoShape::IsSameWithinTolerance(point[2],fZ[izl])) {
00358       rmin = TMath::Min(fRmin[izl], fRmin[izh]);
00359       rmax = TMath::Max(fRmax[izl], fRmax[izh]);
00360    } else {
00361       Double_t dz = fZ[izh] - fZ[izl];
00362       Double_t dz1 = point[2] - fZ[izl];
00363       rmin = (fRmin[izl]*(dz-dz1)+fRmin[izh]*dz1)/dz;
00364       rmax = (fRmax[izl]*(dz-dz1)+fRmax[izh]*dz1)/dz;
00365    }
00366    if ((r2<rmin*rmin) || (r2>rmax*rmax)) return kFALSE;
00367    // now check phi 
00368    if (TGeoShape::IsSameWithinTolerance(fDphi,360)) return kTRUE;
00369    if (r2<1E-10) return kTRUE;
00370    Double_t phi = TMath::ATan2(point[1], point[0]) * TMath::RadToDeg();
00371    if (phi < 0) phi+=360.0;
00372    Double_t ddp = phi-fPhi1;
00373    if (ddp<0) ddp+=360.;
00374    if (ddp<=fDphi) return kTRUE;
00375    return kFALSE;
00376 }
00377 
00378 //_____________________________________________________________________________
00379 Int_t TGeoPcon::DistancetoPrimitive(Int_t px, Int_t py)
00380 {
00381 // compute closest distance from point px,py to each corner
00382    Int_t n = gGeoManager->GetNsegments()+1;
00383    const Int_t numPoints = 2*n*fNz;
00384    return ShapeDistancetoPrimitive(numPoints, px, py);
00385 }
00386 
00387 //_____________________________________________________________________________
00388 Double_t TGeoPcon::DistFromInside(Double_t *point, Double_t *dir, Int_t iact, Double_t step, Double_t *safe) const
00389 {
00390 // compute distance from inside point to surface of the polycone
00391    if (iact<3 && safe) {
00392       *safe = Safety(point, kTRUE);
00393       if (iact==0) return TGeoShape::Big();
00394       if ((iact==1) && (*safe>step)) return TGeoShape::Big();
00395    }
00396    Double_t snxt = TGeoShape::Big();
00397    Double_t sstep = 1E-6;
00398    Double_t point_new[3];
00399    // determine which z segment contains the point
00400    Int_t ipl = TMath::BinarySearch(fNz, fZ, point[2]);
00401    if (ipl<0) ipl=0;
00402    if (ipl==(fNz-1)) ipl--;
00403    Double_t dz = 0.5*(fZ[ipl+1]-fZ[ipl]);
00404    Bool_t special_case = kFALSE;
00405    if (dz<1e-9) {
00406       // radius changing segment, make sure track is not in the XY plane
00407       if (TGeoShape::IsSameWithinTolerance(dir[2], 0)) {
00408          special_case = kTRUE;
00409       } else {
00410          //check if a close point is still contained
00411          point_new[0] = point[0]+sstep*dir[0];
00412          point_new[1] = point[1]+sstep*dir[1];
00413          point_new[2] = point[2]+sstep*dir[2];
00414          if (!Contains(point_new)) return 0.;
00415          return (DistFromInside(point_new,dir,iact,step,safe)+sstep);
00416       }   
00417    }   
00418    // determine if the current segment is a tube or a cone
00419    Bool_t intub = kTRUE;
00420    if (!TGeoShape::IsSameWithinTolerance(fRmin[ipl],fRmin[ipl+1])) intub=kFALSE;
00421    else if (!TGeoShape::IsSameWithinTolerance(fRmax[ipl],fRmax[ipl+1])) intub=kFALSE;
00422    // determine phi segmentation
00423    Bool_t inphi=kTRUE;
00424    if (TGeoShape::IsSameWithinTolerance(fDphi,360)) inphi=kFALSE;     
00425    memcpy(point_new, point, 2*sizeof(Double_t));
00426    // new point in reference system of the current segment
00427    point_new[2] = point[2]-0.5*(fZ[ipl]+fZ[ipl+1]);
00428    
00429    Double_t phi1 = fPhi1;
00430    if (phi1<0) phi1+=360.;
00431    Double_t phi2 = phi1+fDphi;
00432    Double_t phim = 0.5*(phi1+phi2);
00433    Double_t c1 = TMath::Cos(phi1*TMath::DegToRad());
00434    Double_t s1 = TMath::Sin(phi1*TMath::DegToRad());
00435    Double_t c2 = TMath::Cos(phi2*TMath::DegToRad());
00436    Double_t s2 = TMath::Sin(phi2*TMath::DegToRad());
00437    Double_t cm = TMath::Cos(phim*TMath::DegToRad());
00438    Double_t sm = TMath::Sin(phim*TMath::DegToRad());
00439    Double_t cdfi = TMath::Cos(0.5*fDphi*TMath::DegToRad());
00440    if (special_case) {
00441       if (inphi) snxt = TGeoTubeSeg::DistFromInsideS(point_new, dir, 
00442                TMath::Min(fRmin[ipl],fRmin[ipl+1]), TMath::Max(fRmax[ipl],fRmax[ipl+1]),
00443                dz, c1,s1,c2,s2,cm,sm,cdfi);
00444       else       snxt = TGeoTube::DistFromInsideS(point_new, dir, 
00445                TMath::Min(fRmin[ipl],fRmin[ipl+1]), TMath::Max(fRmax[ipl],fRmax[ipl+1]),dz);
00446       return snxt;
00447    }   
00448    if (intub) {
00449       if (inphi) snxt=TGeoTubeSeg::DistFromInsideS(point_new, dir, fRmin[ipl], fRmax[ipl],dz, c1,s1,c2,s2,cm,sm,cdfi); 
00450       else snxt=TGeoTube::DistFromInsideS(point_new, dir, fRmin[ipl], fRmax[ipl],dz);
00451    } else {
00452       if (inphi) snxt=TGeoConeSeg::DistFromInsideS(point_new,dir,dz,fRmin[ipl],fRmax[ipl],fRmin[ipl+1],fRmax[ipl+1],c1,s1,c2,s2,cm,sm,cdfi);
00453       else snxt=TGeoCone::DistFromInsideS(point_new,dir,dz,fRmin[ipl],fRmax[ipl],fRmin[ipl+1], fRmax[ipl+1]);
00454    }                              
00455 
00456    for (Int_t i=0; i<3; i++) point_new[i]=point[i]+(snxt+1E-6)*dir[i];
00457    if (!Contains(&point_new[0])) return snxt;
00458    
00459    snxt += DistFromInside(&point_new[0], dir, 3) + 1E-6;
00460    return snxt;
00461 }
00462 
00463 //_____________________________________________________________________________
00464 Double_t TGeoPcon::DistToSegZ(Double_t *point, Double_t *dir, Int_t &iz, Double_t c1, Double_t s1, 
00465                               Double_t c2, Double_t s2, Double_t cfio, Double_t sfio, Double_t cdfi) const
00466 {
00467 // compute distance to a pcon Z slice. Segment iz must be valid
00468    Double_t zmin=fZ[iz];
00469    Double_t zmax=fZ[iz+1];
00470    if (TGeoShape::IsSameWithinTolerance(zmin,zmax)) {
00471       if (TGeoShape::IsSameWithinTolerance(dir[2],0)) return TGeoShape::Big();
00472       Int_t istep=(dir[2]>0)?1:-1;
00473       iz+=istep;
00474       if (iz<0 || iz>(fNz-2)) return TGeoShape::Big();
00475       return DistToSegZ(point,dir,iz,c1,s1,c2,s2,cfio,sfio,cdfi);
00476    }
00477    Double_t dz=0.5*(zmax-zmin);
00478    Double_t local[3];
00479    memcpy(&local[0], point, 3*sizeof(Double_t));
00480    local[2]=point[2]-0.5*(zmin+zmax);
00481    Double_t snxt;
00482    Double_t rmin1=fRmin[iz];
00483    Double_t rmax1=fRmax[iz];
00484    Double_t rmin2=fRmin[iz+1];
00485    Double_t rmax2=fRmax[iz+1];
00486    Bool_t is_seg=(TGeoShape::IsSameWithinTolerance(fDphi,360))?kFALSE:kTRUE;
00487 
00488    if (TGeoShape::IsSameWithinTolerance(rmin1,rmin2) && TGeoShape::IsSameWithinTolerance(rmax1,rmax2)) {
00489       if (!is_seg) snxt=TGeoTube::DistFromOutsideS(local, dir, rmin1, rmax1, dz);
00490       else snxt=TGeoTubeSeg::DistFromOutsideS(local,dir,rmin1,rmax1,dz,c1,s1,c2,s2,cfio,sfio,cdfi);
00491    } else {  
00492       if (!is_seg) snxt=TGeoCone::DistFromOutsideS(local,dir,dz,rmin1, rmax1,rmin2,rmax2);
00493       else snxt=TGeoConeSeg::DistFromOutsideS(local,dir,dz,rmin1,rmax1,rmin2,rmax2,c1,s1,c2,s2,cfio,sfio,cdfi);
00494    }
00495    if (snxt<1E20) return snxt;
00496    // check next segment
00497    if (TGeoShape::IsSameWithinTolerance(dir[2],0)) return TGeoShape::Big();
00498    Int_t istep=(dir[2]>0)?1:-1;
00499    iz+=istep;
00500    if (iz<0 || iz>(fNz-2)) return TGeoShape::Big();
00501    return DistToSegZ(point,dir,iz,c1,s1,c2,s2,cfio,sfio,cdfi);
00502 }      
00503 
00504 //_____________________________________________________________________________
00505 Double_t TGeoPcon::DistFromOutside(Double_t *point, Double_t *dir, Int_t iact, Double_t step, Double_t *safe) const
00506 {
00507 // compute distance from outside point to surface of the tube
00508    if ((iact<3) && safe) {
00509       *safe = Safety(point, kFALSE);
00510       if ((iact==1) && (*safe>step)) return TGeoShape::Big();
00511       if (iact==0) return TGeoShape::Big();
00512    }
00513    // check if ray intersect outscribed cylinder
00514    if ((point[2]<fZ[0]) && (dir[2]<=0)) return TGeoShape::Big();
00515    if ((point[2]>fZ[fNz-1]) && (dir[2]>=0)) return TGeoShape::Big();
00516 // Check if the bounding box is crossed within the requested distance
00517    Double_t sdist = TGeoBBox::DistFromOutside(point,dir, fDX, fDY, fDZ, fOrigin, step);
00518    if (sdist>=step) return TGeoShape::Big();
00519 
00520    Double_t r2 = point[0]*point[0]+point[1]*point[1];
00521    Double_t radmax=0;
00522    radmax=fRmax[TMath::LocMax(fNz, fRmax)];
00523    if (r2>(radmax*radmax)) {
00524       Double_t rpr=-point[0]*dir[0]-point[1]*dir[1];
00525       Double_t nxy=dir[0]*dir[0]+dir[1]*dir[1];
00526       if (rpr<TMath::Sqrt((r2-radmax*radmax)*nxy)) return TGeoShape::Big();
00527    }
00528 
00529    // find in which Z segment we are
00530    Int_t ipl = TMath::BinarySearch(fNz, fZ, point[2]);
00531    Int_t ifirst = ipl;
00532    if (ifirst<0) {
00533       ifirst=0;
00534    } else if (ifirst>=(fNz-1)) ifirst=fNz-2;
00535    // find if point is in the phi gap
00536    Double_t phi=0;
00537    Double_t phi1=0;
00538    Double_t phi2=0;
00539    Double_t c1=0., s1=0., c2=0., s2=0., cfio=0., sfio=0., cdfi=0.;
00540    Bool_t inphi = (fDphi<360)?kTRUE:kFALSE;
00541    if (inphi) {
00542       phi1=fPhi1;
00543       if (phi1<0) phi1+=360;
00544       phi2=(phi1+fDphi)*TMath::DegToRad();
00545       phi1=phi1*TMath::DegToRad();
00546       phi=TMath::ATan2(point[1], point[0]);
00547       if (phi<0) phi+=2.*TMath::Pi();
00548       c1=TMath::Cos(phi1);
00549       s1=TMath::Sin(phi1);
00550       c2=TMath::Cos(phi2);
00551       s2=TMath::Sin(phi2);
00552       Double_t fio=0.5*(phi1+phi2);
00553       cfio=TMath::Cos(fio);
00554       sfio=TMath::Sin(fio);
00555       cdfi=TMath::Cos(0.5*(phi2-phi1));
00556    } 
00557 
00558    // compute distance to boundary
00559    return DistToSegZ(point,dir,ifirst, c1,s1,c2,s2,cfio,sfio,cdfi);
00560 }
00561 
00562 //_____________________________________________________________________________
00563 void TGeoPcon::DefineSection(Int_t snum, Double_t z, Double_t rmin, Double_t rmax)
00564 {
00565 // Defines z position of a section plane, rmin and rmax at this z. Sections
00566 // should be defined in increasing or decreasing Z order and the last section 
00567 // HAS to be snum = fNz-1
00568    if ((snum<0) || (snum>=fNz)) return;
00569    fZ[snum]    = z;
00570    fRmin[snum] = rmin;
00571    fRmax[snum] = rmax;
00572    if (rmin>rmax) 
00573       Warning("DefineSection", "Shape %s: invalid rmin=%g rmax=%g", GetName(), rmin, rmax);
00574    if (snum==(fNz-1)) {
00575       // Reorder sections in increasing Z order
00576       if (fZ[0] > fZ[snum]) {
00577          Int_t iz = 0;
00578          Int_t izi = fNz-1;
00579          Double_t temp;
00580          while (iz<izi) {
00581             temp = fZ[iz];
00582             fZ[iz] = fZ[izi];
00583             fZ[izi] = temp;
00584             temp = fRmin[iz];
00585             fRmin[iz] = fRmin[izi];
00586             fRmin[izi] = temp;
00587             temp = fRmax[iz];
00588             fRmax[iz] = fRmax[izi];
00589             fRmax[izi] = temp;
00590             iz++;
00591             izi--;
00592          }   
00593       }      
00594       ComputeBBox();
00595    }   
00596 }
00597 
00598 //_____________________________________________________________________________
00599 Int_t TGeoPcon::GetNsegments() const
00600 {
00601 // Returns number of segments on each mesh circle segment.
00602    return gGeoManager->GetNsegments();
00603 }
00604 
00605 //_____________________________________________________________________________
00606 TGeoVolume *TGeoPcon::Divide(TGeoVolume *voldiv, const char *divname, Int_t iaxis, Int_t ndiv, 
00607                              Double_t start, Double_t step) 
00608 {
00609 //--- Divide this polycone shape belonging to volume "voldiv" into ndiv volumes
00610 // called divname, from start position with the given step. Returns pointer
00611 // to created division cell volume in case of Z divisions. Z divisions can be
00612 // performed if the divided range is in between two consecutive Z planes.
00613 //  In case a wrong division axis is supplied, returns pointer to 
00614 // volume that was divided.
00615    TGeoShape *shape;           //--- shape to be created
00616    TGeoVolume *vol;            //--- division volume to be created
00617    TGeoVolumeMulti *vmulti;    //--- generic divided volume
00618    TGeoPatternFinder *finder;  //--- finder to be attached 
00619    TString opt = "";           //--- option to be attached
00620    Double_t zmin = start;
00621    Double_t zmax = start+ndiv*step;            
00622    Int_t isect = -1;
00623    Int_t is, id, ipl;
00624    switch (iaxis) {
00625       case 1:  //---               R division
00626          Error("Divide", "Shape %s: cannot divide a pcon on radius", GetName());
00627          return 0;
00628       case 2:  //---               Phi division
00629          finder = new TGeoPatternCylPhi(voldiv, ndiv, start, start+ndiv*step);
00630          vmulti = gGeoManager->MakeVolumeMulti(divname, voldiv->GetMedium());
00631          voldiv->SetFinder(finder);
00632          finder->SetDivIndex(voldiv->GetNdaughters());            
00633          shape = new TGeoPcon(-step/2, step, fNz);
00634          for (is=0; is<fNz; is++)
00635             ((TGeoPcon*)shape)->DefineSection(is, fZ[is], fRmin[is], fRmax[is]); 
00636             vol = new TGeoVolume(divname, shape, voldiv->GetMedium());
00637             vmulti->AddVolume(vol);
00638             opt = "Phi";
00639             for (id=0; id<ndiv; id++) {
00640                voldiv->AddNodeOffset(vol, id, start+id*step+step/2, opt.Data());
00641                ((TGeoNodeOffset*)voldiv->GetNodes()->At(voldiv->GetNdaughters()-1))->SetFinder(finder);
00642             }
00643             return vmulti;
00644       case 3: //---                Z division
00645          // find start plane
00646          for (ipl=0; ipl<fNz-1; ipl++) {
00647             if (start<fZ[ipl]) continue;
00648             else {
00649                if ((start+ndiv*step)>fZ[ipl+1]) continue;
00650             }
00651             isect = ipl;
00652             zmin = fZ[isect];
00653             zmax= fZ[isect+1];
00654             break;
00655          }
00656          if (isect<0) {
00657             Error("Divide", "Shape %s: cannot divide pcon on Z if divided region is not between 2 planes", GetName());
00658             return 0;
00659          }
00660          finder = new TGeoPatternZ(voldiv, ndiv, start, start+ndiv*step);
00661          vmulti = gGeoManager->MakeVolumeMulti(divname, voldiv->GetMedium());
00662          voldiv->SetFinder(finder);
00663          finder->SetDivIndex(voldiv->GetNdaughters());
00664          opt = "Z";
00665          for (id=0; id<ndiv; id++) {
00666             Double_t z1 = start+id*step;
00667             Double_t z2 = start+(id+1)*step;
00668             Double_t rmin1 = (fRmin[isect]*(zmax-z1)-fRmin[isect+1]*(zmin-z1))/(zmax-zmin);
00669             Double_t rmax1 = (fRmax[isect]*(zmax-z1)-fRmax[isect+1]*(zmin-z1))/(zmax-zmin);
00670             Double_t rmin2 = (fRmin[isect]*(zmax-z2)-fRmin[isect+1]*(zmin-z2))/(zmax-zmin);
00671             Double_t rmax2 = (fRmax[isect]*(zmax-z2)-fRmax[isect+1]*(zmin-z2))/(zmax-zmin);
00672             Bool_t is_tube = (TGeoShape::IsSameWithinTolerance(fRmin[isect],fRmin[isect+1]) && TGeoShape::IsSameWithinTolerance(fRmax[isect],fRmax[isect+1]))?kTRUE:kFALSE;
00673             Bool_t is_seg = (fDphi<360)?kTRUE:kFALSE;
00674             if (is_seg) {
00675                if (is_tube) shape=new TGeoTubeSeg(fRmin[isect],fRmax[isect],step/2, fPhi1, fPhi1+fDphi);
00676                else shape=new TGeoConeSeg(step/2, rmin1, rmax1, rmin2, rmax2, fPhi1, fPhi1+fDphi);
00677             } else {
00678                if (is_tube) shape=new TGeoTube(fRmin[isect],fRmax[isect],step/2);
00679                else shape = new TGeoCone(step/2,rmin1,rmax1,rmin2,rmax2);
00680             }    
00681             vol = new TGeoVolume(divname, shape, voldiv->GetMedium());
00682             vmulti->AddVolume(vol);
00683             voldiv->AddNodeOffset(vol, id, start+id*step+step/2, opt.Data());
00684             ((TGeoNodeOffset*)voldiv->GetNodes()->At(voldiv->GetNdaughters()-1))->SetFinder(finder);
00685          }
00686          return vmulti;
00687       default:
00688          Error("Divide", "Shape %s: Wrong axis %d for division",GetName(), iaxis);
00689          return 0;            
00690    }
00691 }
00692 
00693 //_____________________________________________________________________________
00694 const char *TGeoPcon::GetAxisName(Int_t iaxis) const
00695 {
00696 // Returns name of axis IAXIS.
00697    switch (iaxis) {
00698       case 1:
00699          return "R";
00700       case 2:
00701          return "PHI";
00702       case 3:
00703          return "Z";
00704       default:
00705          return "UNDEFINED";
00706    }
00707 }   
00708 
00709 //_____________________________________________________________________________
00710 Double_t TGeoPcon::GetAxisRange(Int_t iaxis, Double_t &xlo, Double_t &xhi) const
00711 {
00712 // Get range of shape for a given axis.
00713    xlo = 0;
00714    xhi = 0;
00715    Double_t dx = 0;
00716    switch (iaxis) {
00717       case 2:
00718          xlo = fPhi1;
00719          xhi = fPhi1 + fDphi;
00720          dx = fDphi;
00721          return dx;
00722       case 3:
00723          xlo = fZ[0];
00724          xhi = fZ[fNz-1];
00725          dx = xhi-xlo;
00726          return dx;
00727    }
00728    return dx;
00729 }         
00730             
00731 //_____________________________________________________________________________
00732 void TGeoPcon::GetBoundingCylinder(Double_t *param) const
00733 {
00734 //--- Fill vector param[4] with the bounding cylinder parameters. The order
00735 // is the following : Rmin, Rmax, Phi1, Phi2
00736    param[0] = fRmin[0];           // Rmin
00737    param[1] = fRmax[0];           // Rmax
00738    for (Int_t i=1; i<fNz; i++) {
00739       if (fRmin[i] < param[0]) param[0] = fRmin[i];
00740       if (fRmax[i] > param[1]) param[1] = fRmax[i];
00741    }
00742    param[0] *= param[0];
00743    param[1] *= param[1];
00744    if (TGeoShape::IsSameWithinTolerance(fDphi,360.)) {
00745       param[2] = 0.;
00746       param[3] = 360.;
00747       return;
00748    }   
00749    param[2] = (fPhi1<0)?(fPhi1+360.):fPhi1;     // Phi1
00750    param[3] = param[2]+fDphi;                   // Phi2
00751 }   
00752 
00753 //_____________________________________________________________________________
00754 Double_t TGeoPcon::GetRmin(Int_t ipl) const
00755 {
00756 // Returns Rmin for Z segment IPL.
00757    if (ipl<0 || ipl>(fNz-1)) {
00758       Error("GetRmin","ipl=%i out of range (0,%i) in shape %s",ipl,fNz-1,GetName());
00759       return 0.;
00760    }
00761    return fRmin[ipl];
00762 }      
00763 
00764 //_____________________________________________________________________________
00765 Double_t TGeoPcon::GetRmax(Int_t ipl) const
00766 {
00767 // Returns Rmax for Z segment IPL.
00768    if (ipl<0 || ipl>(fNz-1)) {
00769       Error("GetRmax","ipl=%i out of range (0,%i) in shape %s",ipl,fNz-1,GetName());
00770       return 0.;
00771    }
00772    return fRmax[ipl];
00773 }      
00774 
00775 //_____________________________________________________________________________
00776 Double_t TGeoPcon::GetZ(Int_t ipl) const
00777 {
00778 // Returns Z for segment IPL.
00779    if (ipl<0 || ipl>(fNz-1)) {
00780       Error("GetZ","ipl=%i out of range (0,%i) in shape %s",ipl,fNz-1,GetName());
00781       return 0.;
00782    }
00783    return fZ[ipl];
00784 }      
00785 
00786 //_____________________________________________________________________________
00787 void TGeoPcon::InspectShape() const
00788 {
00789 // print shape parameters
00790    printf("*** Shape %s: TGeoPcon ***\n", GetName());
00791    printf("    Nz    = %i\n", fNz);
00792    printf("    phi1  = %11.5f\n", fPhi1);
00793    printf("    dphi  = %11.5f\n", fDphi);
00794    for (Int_t ipl=0; ipl<fNz; ipl++)
00795       printf("     plane %i: z=%11.5f Rmin=%11.5f Rmax=%11.5f\n", ipl, fZ[ipl], fRmin[ipl], fRmax[ipl]);
00796    printf(" Bounding box:\n");
00797    TGeoBBox::InspectShape();
00798 }
00799 
00800 //_____________________________________________________________________________
00801 TBuffer3D *TGeoPcon::MakeBuffer3D() const
00802 { 
00803    // Creates a TBuffer3D describing *this* shape.
00804    // Coordinates are in local reference frame.
00805 
00806    const Int_t n = gGeoManager->GetNsegments()+1;
00807    Int_t nz = GetNz();
00808    if (nz < 2) return 0;
00809    Int_t nbPnts = nz*2*n;
00810    if (nbPnts <= 0) return 0;
00811    Double_t dphi = GetDphi();
00812 
00813    Bool_t specialCase = kFALSE;
00814    if (TGeoShape::IsSameWithinTolerance(dphi,360)) specialCase = kTRUE;
00815 
00816    Int_t nbSegs = 4*(nz*n-1+(specialCase == kTRUE));
00817    Int_t nbPols = 2*(nz*n-1+(specialCase == kTRUE));
00818    TBuffer3D* buff = new TBuffer3D(TBuffer3DTypes::kGeneric,
00819                                    nbPnts, 3*nbPnts, nbSegs, 3*nbSegs, nbPols, 6*nbPols);
00820    if (buff)
00821    {
00822       SetPoints(buff->fPnts);
00823       SetSegsAndPols(*buff);
00824    }
00825 
00826    return buff;  
00827 }
00828 
00829 //_____________________________________________________________________________
00830 void TGeoPcon::SetSegsAndPols(TBuffer3D &buff) const
00831 {
00832 // Fill TBuffer3D structure for segments and polygons.
00833    Int_t i, j;
00834    const Int_t n = gGeoManager->GetNsegments()+1;
00835    Int_t nz = GetNz();
00836    if (nz < 2) return;
00837    Int_t nbPnts = nz*2*n;
00838    if (nbPnts <= 0) return;
00839    Double_t dphi = GetDphi();
00840 
00841    Bool_t specialCase = kFALSE;
00842    if (TGeoShape::IsSameWithinTolerance(dphi,360)) specialCase = kTRUE;
00843    Int_t c = GetBasicColor();
00844 
00845    Int_t indx, indx2, k;
00846    indx = indx2 = 0;
00847 
00848    //inside & outside circles, number of segments: 2*nz*(n-1)
00849    //             special case number of segments: 2*nz*n
00850    for (i = 0; i < nz*2; i++) {
00851       indx2 = i*n;
00852       for (j = 1; j < n; j++) {
00853          buff.fSegs[indx++] = c;
00854          buff.fSegs[indx++] = indx2+j-1;
00855          buff.fSegs[indx++] = indx2+j;
00856       }
00857       if (specialCase) {
00858          buff.fSegs[indx++] = c;
00859          buff.fSegs[indx++] = indx2+j-1;
00860          buff.fSegs[indx++] = indx2;
00861       }
00862    }
00863 
00864    //bottom & top lines, number of segments: 2*n
00865    for (i = 0; i < 2; i++) {
00866       indx2 = i*(nz-1)*2*n;
00867       for (j = 0; j < n; j++) {
00868          buff.fSegs[indx++] = c;
00869          buff.fSegs[indx++] = indx2+j;
00870          buff.fSegs[indx++] = indx2+n+j;
00871       }
00872    }
00873 
00874    //inside & outside cilindres, number of segments: 2*(nz-1)*n
00875    for (i = 0; i < (nz-1); i++) {
00876       //inside cilinder
00877       indx2 = i*n*2;
00878       for (j = 0; j < n; j++) {
00879          buff.fSegs[indx++] = c+2;
00880          buff.fSegs[indx++] = indx2+j;
00881          buff.fSegs[indx++] = indx2+n*2+j;
00882       }
00883       //outside cilinder
00884       indx2 = i*n*2+n;
00885       for (j = 0; j < n; j++) {
00886          buff.fSegs[indx++] = c+3;
00887          buff.fSegs[indx++] = indx2+j;
00888          buff.fSegs[indx++] = indx2+n*2+j;
00889       }
00890    }
00891 
00892    //left & right sections, number of segments: 2*(nz-2)
00893    //          special case number of segments: 0
00894    if (!specialCase) {
00895       for (i = 1; i < (nz-1); i++) {
00896          for (j = 0; j < 2; j++) {
00897             buff.fSegs[indx++] = c;
00898             buff.fSegs[indx++] =  2*i    * n + j*(n-1);
00899             buff.fSegs[indx++] = (2*i+1) * n + j*(n-1);
00900          }
00901       }
00902    }
00903 
00904    Int_t m = n - 1 + (specialCase == kTRUE);
00905    indx = 0;
00906 
00907    //bottom & top, number of polygons: 2*(n-1)
00908    // special case number of polygons: 2*n
00909    for (j = 0; j < n-1; j++) {
00910       buff.fPols[indx++] = c+3;
00911       buff.fPols[indx++] = 4;
00912       buff.fPols[indx++] = 2*nz*m+j;
00913       buff.fPols[indx++] = m+j;
00914       buff.fPols[indx++] = 2*nz*m+j+1;
00915       buff.fPols[indx++] = j;
00916    }
00917    for (j = 0; j < n-1; j++) {
00918       buff.fPols[indx++] = c+3;
00919       buff.fPols[indx++] = 4;
00920       buff.fPols[indx++] = 2*nz*m+n+j;
00921       buff.fPols[indx++] = (nz*2-2)*m+j;
00922       buff.fPols[indx++] = 2*nz*m+n+j+1;
00923       buff.fPols[indx++] = (nz*2-2)*m+m+j;
00924    }
00925    if (specialCase) {
00926       buff.fPols[indx++] = c+3;
00927       buff.fPols[indx++] = 4;
00928       buff.fPols[indx++] = 2*nz*m+j;
00929       buff.fPols[indx++] = m+j;
00930       buff.fPols[indx++] = 2*nz*m;
00931       buff.fPols[indx++] = j;
00932  
00933       buff.fPols[indx++] = c+3;
00934       buff.fPols[indx++] = 4;
00935       buff.fPols[indx++] = 2*nz*m+n+j;
00936       buff.fPols[indx++] = (nz*2-2)*m+m+j;
00937       buff.fPols[indx++] = 2*nz*m+n;
00938       buff.fPols[indx++] = (nz*2-2)*m+j;
00939    }
00940 
00941    //inside & outside, number of polygons: (nz-1)*2*(n-1)
00942    for (k = 0; k < (nz-1); k++) {
00943       for (j = 0; j < n-1; j++) {
00944          buff.fPols[indx++] = c;
00945          buff.fPols[indx++] = 4;
00946          buff.fPols[indx++] = 2*k*m+j;
00947          buff.fPols[indx++] = nz*2*m+(2*k+2)*n+j+1;
00948          buff.fPols[indx++] = (2*k+2)*m+j;
00949          buff.fPols[indx++] = nz*2*m+(2*k+2)*n+j;
00950       }
00951       for (j = 0; j < n-1; j++) {
00952          buff.fPols[indx++] = c+1;
00953          buff.fPols[indx++] = 4;
00954          buff.fPols[indx++] = (2*k+1)*m+j;
00955          buff.fPols[indx++] = nz*2*m+(2*k+3)*n+j;
00956          buff.fPols[indx++] = (2*k+3)*m+j;
00957          buff.fPols[indx++] = nz*2*m+(2*k+3)*n+j+1;
00958       }
00959       if (specialCase) {
00960          buff.fPols[indx++] = c;
00961          buff.fPols[indx++] = 4;
00962          buff.fPols[indx++] = 2*k*m+j;
00963          buff.fPols[indx++] = nz*2*m+(2*k+2)*n;
00964          buff.fPols[indx++] = (2*k+2)*m+j;
00965          buff.fPols[indx++] = nz*2*m+(2*k+2)*n+j;
00966  
00967          buff.fPols[indx++] = c+1;
00968          buff.fPols[indx++] = 4;
00969          buff.fPols[indx++] = (2*k+1)*m+j;
00970          buff.fPols[indx++] = nz*2*m+(2*k+3)*n+j;
00971          buff.fPols[indx++] = (2*k+3)*m+j;
00972          buff.fPols[indx++] = nz*2*m+(2*k+3)*n;
00973       }
00974    }
00975 
00976    //left & right sections, number of polygons: 2*(nz-1)
00977    //          special case number of polygons: 0
00978    if (!specialCase) {
00979       indx2 = nz*2*(n-1);
00980       for (k = 0; k < (nz-1); k++) {
00981          buff.fPols[indx++] = c+2;
00982          buff.fPols[indx++] = 4;
00983          buff.fPols[indx++] = k==0 ? indx2 : indx2+2*nz*n+2*(k-1);
00984          buff.fPols[indx++] = indx2+2*(k+1)*n;
00985          buff.fPols[indx++] = indx2+2*nz*n+2*k;
00986          buff.fPols[indx++] = indx2+(2*k+3)*n;
00987  
00988          buff.fPols[indx++] = c+2;
00989          buff.fPols[indx++] = 4;
00990          buff.fPols[indx++] = k==0 ? indx2+n-1 : indx2+2*nz*n+2*(k-1)+1;
00991          buff.fPols[indx++] = indx2+(2*k+3)*n+n-1;
00992          buff.fPols[indx++] = indx2+2*nz*n+2*k+1;
00993          buff.fPols[indx++] = indx2+2*(k+1)*n+n-1;
00994       }
00995       buff.fPols[indx-8] = indx2+n;
00996       buff.fPols[indx-2] = indx2+2*n-1;
00997    }
00998 }   
00999 
01000 //_____________________________________________________________________________
01001 Double_t TGeoPcon::SafetyToSegment(Double_t *point, Int_t ipl, Bool_t in, Double_t safmin) const
01002 {
01003 // Compute safety from POINT to segment between planes ipl, ipl+1 within safmin.
01004 
01005    Double_t safe = TGeoShape::Big();
01006    if (ipl<0 || ipl>fNz-2) return (safmin+1.); // error in input plane
01007 // Get info about segment.
01008    Double_t dz = 0.5*(fZ[ipl+1]-fZ[ipl]);
01009    if (dz<1E-9) return 1E9; // radius-changing segment
01010    Double_t ptnew[3];
01011    memcpy(ptnew, point, 3*sizeof(Double_t));
01012    ptnew[2] -= 0.5*(fZ[ipl]+fZ[ipl+1]);
01013    safe = TMath::Abs(ptnew[2])-dz;
01014    if (safe>safmin) return TGeoShape::Big(); // means: stop checking further segments
01015    Double_t rmin1 = fRmin[ipl];
01016    Double_t rmax1 = fRmax[ipl];
01017    Double_t rmin2 = fRmin[ipl+1];
01018    Double_t rmax2 = fRmax[ipl+1];
01019    Bool_t   is_tube = (TGeoShape::IsSameWithinTolerance(rmin1,rmin2) && TGeoShape::IsSameWithinTolerance(rmax1,rmax2))?kTRUE:kFALSE;
01020    Bool_t   is_seg  = (fDphi<360)?kTRUE:kFALSE;
01021    if (is_seg) {
01022       if (is_tube) safe = TGeoTubeSeg::SafetyS(ptnew,in,rmin1,rmax1, dz,fPhi1,fPhi1+fDphi,0);
01023       else         safe = TGeoConeSeg::SafetyS(ptnew,in,dz,rmin1,rmax1,rmin2,rmax2,fPhi1,fPhi1+fDphi,0);
01024    } else {
01025       if (is_tube) safe = TGeoTube::SafetyS(ptnew,in,rmin1,rmax1,dz,0);
01026       else         safe = TGeoCone::SafetyS(ptnew,in,dz,rmin1,rmax1,rmin2,rmax2,0);
01027    }
01028    if (safe<0) safe=0;
01029    return safe;   
01030 }
01031 
01032 //_____________________________________________________________________________
01033 Double_t TGeoPcon::Safety(Double_t *point, Bool_t in) const
01034 {
01035 // computes the closest distance from given point to this shape, according
01036 // to option. The matching point on the shape is stored in spoint.
01037    //---> localize the Z segment
01038    
01039    Double_t safmin, saftmp;
01040    Double_t dz;
01041    Int_t ipl, iplane;
01042 
01043    if (in) {
01044    //---> point is inside pcon
01045       ipl = TMath::BinarySearch(fNz, fZ, point[2]);
01046       if (ipl==(fNz-1)) return 0;   // point on last Z boundary
01047       if (ipl<0) return 0;          // point on first Z boundary
01048       if (ipl>0 && TGeoShape::IsSameWithinTolerance(fZ[ipl-1],fZ[ipl]) && TGeoShape::IsSameWithinTolerance(point[2],fZ[ipl-1])) ipl--;
01049       dz = 0.5*(fZ[ipl+1]-fZ[ipl]);
01050       if (dz<1E-8) {
01051          // Point on a segment-changing plane
01052          safmin = TMath::Min(point[2]-fZ[ipl-1],fZ[ipl+2]-point[2]);
01053          saftmp = TGeoShape::Big();
01054          if (fDphi<360) saftmp = TGeoShape::SafetyPhi(point,in,fPhi1,fPhi1+fDphi);
01055          if (saftmp<safmin) safmin = saftmp;
01056          Double_t radius = TMath::Sqrt(point[0]*point[0]+point[1]*point[1]);
01057          if (fRmin[ipl]>0) safmin = TMath::Min(safmin, radius-fRmin[ipl]);
01058          if (fRmin[ipl+1]>0) safmin = TMath::Min(safmin, radius-fRmin[ipl+1]);
01059          safmin = TMath::Min(safmin, fRmax[ipl]-radius);
01060          safmin = TMath::Min(safmin, fRmax[ipl+1]-radius);
01061          if (safmin<0) safmin = 0;
01062          return safmin;
01063       }   
01064       // Check safety for current segment
01065       safmin = SafetyToSegment(point, ipl);
01066       if (safmin>1E10) {
01067          //  something went wrong - point is not inside current segment
01068          return TGeoShape::Big();
01069       }
01070       if (safmin<1E-6) return TMath::Abs(safmin); // point on radius-changing plane
01071       // check increasing iplanes
01072       iplane = ipl+1;
01073       saftmp = 0.;
01074       while ((iplane<fNz-1) && saftmp<1E10) {
01075          saftmp = TMath::Abs(SafetyToSegment(point,iplane,kFALSE,safmin));
01076          if (saftmp<safmin) safmin=saftmp;
01077          iplane++;
01078       }   
01079       // now decreasing nplanes
01080       iplane = ipl-1;
01081       saftmp = 0.;
01082       while ((iplane>=0) && saftmp<1E10) {
01083          saftmp = TMath::Abs(SafetyToSegment(point,iplane,kFALSE,safmin));
01084          if (saftmp<safmin) safmin=saftmp;
01085          iplane--;
01086       }   
01087       return safmin;
01088    }   
01089    //---> point is outside pcon
01090    ipl = TMath::BinarySearch(fNz, fZ, point[2]);
01091    if (ipl<0) ipl=0;
01092    else if (ipl==fNz-1) ipl=fNz-2;
01093    dz = 0.5*(fZ[ipl+1]-fZ[ipl]);
01094    if (dz<1E-8 && (ipl+2<fNz)) {
01095       ipl++;
01096       dz = 0.5*(fZ[ipl+1]-fZ[ipl]);
01097    }   
01098    // Check safety for current segment
01099    safmin = SafetyToSegment(point, ipl, kFALSE);
01100    if (safmin<1E-6) return TMath::Abs(safmin); // point on radius-changing plane
01101    saftmp = 0.;
01102    // check increasing iplanes
01103    iplane = ipl+1;
01104    saftmp = 0.;
01105    while ((iplane<fNz-1) && saftmp<1E10) {
01106       saftmp = TMath::Abs(SafetyToSegment(point,iplane,kFALSE,safmin));
01107       if (saftmp<safmin) safmin=saftmp;
01108       iplane++;
01109    }   
01110    // now decreasing nplanes
01111    iplane = ipl-1;
01112    saftmp = 0.;
01113    while ((iplane>=0) && saftmp<1E10) {
01114       saftmp = TMath::Abs(SafetyToSegment(point,iplane,kFALSE,safmin));
01115       if (saftmp<safmin) safmin=saftmp;
01116       iplane--;
01117    }   
01118    return safmin;
01119 }
01120 
01121 //_____________________________________________________________________________
01122 void TGeoPcon::SavePrimitive(ostream &out, Option_t * /*option*/ /*= ""*/)
01123 {
01124 // Save a primitive as a C++ statement(s) on output stream "out".
01125    if (TObject::TestBit(kGeoSavePrimitive)) return;
01126    out << "   // Shape: " << GetName() << " type: " << ClassName() << endl;
01127    out << "   phi1  = " << fPhi1 << ";" << endl;
01128    out << "   dphi  = " << fDphi << ";" << endl;
01129    out << "   nz    = " << fNz << ";" << endl;
01130    out << "   TGeoPcon *pcon = new TGeoPcon(\"" << GetName() << "\",phi1,dphi,nz);" << endl;
01131    for (Int_t i=0; i<fNz; i++) {
01132       out << "      z     = " << fZ[i] << ";" << endl;
01133       out << "      rmin  = " << fRmin[i] << ";" << endl;
01134       out << "      rmax  = " << fRmax[i] << ";" << endl;
01135       out << "   pcon->DefineSection(" << i << ", z,rmin,rmax);" << endl;
01136    }
01137    out << "   TGeoShape *" << GetPointerName() << " = pcon;" << endl;
01138    TObject::SetBit(TGeoShape::kGeoSavePrimitive);
01139 }
01140          
01141 //_____________________________________________________________________________
01142 void TGeoPcon::SetDimensions(Double_t *param)
01143 {
01144 // Set polycone dimensions starting from an array.
01145    fPhi1    = param[0];
01146    fDphi    = param[1];
01147    fNz      = (Int_t)param[2];
01148    if (fNz<2) {
01149       Error("SetDimensions","Pcon %s: Number of Z sections must be > 2", GetName());
01150       return;
01151    } 
01152    if (fRmin) delete [] fRmin;  
01153    if (fRmax) delete [] fRmax;  
01154    if (fZ) delete [] fZ;  
01155    fRmin = new Double_t [fNz];
01156    fRmax = new Double_t [fNz];
01157    fZ    = new Double_t [fNz];
01158    memset(fRmin, 0, fNz*sizeof(Double_t));
01159    memset(fRmax, 0, fNz*sizeof(Double_t));
01160    memset(fZ, 0, fNz*sizeof(Double_t));
01161    for (Int_t i=0; i<fNz; i++) 
01162       DefineSection(i, param[3+3*i], param[4+3*i], param[5+3*i]);
01163 }   
01164 
01165 //_____________________________________________________________________________
01166 void TGeoPcon::SetPoints(Double_t *points) const
01167 {
01168 // create polycone mesh points
01169    Double_t phi, dphi;
01170    Int_t n = gGeoManager->GetNsegments() + 1;
01171    dphi = fDphi/(n-1);
01172    Int_t i, j;
01173    Int_t indx = 0;
01174 
01175    if (points) {
01176       for (i = 0; i < fNz; i++) {
01177          for (j = 0; j < n; j++) {
01178             phi = (fPhi1+j*dphi)*TMath::DegToRad();
01179             points[indx++] = fRmin[i] * TMath::Cos(phi);
01180             points[indx++] = fRmin[i] * TMath::Sin(phi);
01181             points[indx++] = fZ[i];
01182          }
01183          for (j = 0; j < n; j++) {
01184             phi = (fPhi1+j*dphi)*TMath::DegToRad();
01185             points[indx++] = fRmax[i] * TMath::Cos(phi);
01186             points[indx++] = fRmax[i] * TMath::Sin(phi);
01187             points[indx++] = fZ[i];
01188          }
01189       }
01190    }
01191 }
01192 
01193 //_____________________________________________________________________________
01194 void TGeoPcon::SetPoints(Float_t *points) const
01195 {
01196 // create polycone mesh points
01197    Double_t phi, dphi;
01198    Int_t n = gGeoManager->GetNsegments() + 1;
01199    dphi = fDphi/(n-1);
01200    Int_t i, j;
01201    Int_t indx = 0;
01202 
01203    if (points) {
01204       for (i = 0; i < fNz; i++) {
01205          for (j = 0; j < n; j++) {
01206             phi = (fPhi1+j*dphi)*TMath::DegToRad();
01207             points[indx++] = fRmin[i] * TMath::Cos(phi);
01208             points[indx++] = fRmin[i] * TMath::Sin(phi);
01209             points[indx++] = fZ[i];
01210          }
01211          for (j = 0; j < n; j++) {
01212             phi = (fPhi1+j*dphi)*TMath::DegToRad();
01213             points[indx++] = fRmax[i] * TMath::Cos(phi);
01214             points[indx++] = fRmax[i] * TMath::Sin(phi);
01215             points[indx++] = fZ[i];
01216          }
01217       }
01218    }
01219 }
01220 //_____________________________________________________________________________
01221 Int_t TGeoPcon::GetNmeshVertices() const
01222 {
01223 // Return number of vertices of the mesh representation
01224    Int_t n = gGeoManager->GetNsegments()+1;
01225    Int_t numPoints = fNz*2*n;
01226    return numPoints;
01227 }   
01228 
01229 //_____________________________________________________________________________
01230 void TGeoPcon::Sizeof3D() const
01231 {
01232 ///// fill size of this 3-D object
01233 ///   TVirtualGeoPainter *painter = gGeoManager->GetGeomer();
01234 ///   if (!painter) return;
01235 ///    Int_t n;
01236    ///
01237 ///    n = gGeoManager->GetNsegments()+1;
01238    ///
01239 ///    Int_t numPoints = fNz*2*n;
01240 ///    Int_t numSegs   = 4*(fNz*n-1+(fDphi == 360));
01241 ///    Int_t numPolys  = 2*(fNz*n-1+(fDphi == 360));
01242 ///    painter->AddSize3D(numPoints, numSegs, numPolys);
01243 }
01244 
01245 //_____________________________________________________________________________
01246 void TGeoPcon::GetMeshNumbers(Int_t &nvert, Int_t &nsegs, Int_t &npols) const
01247 {
01248 // Returns numbers of vertices, segments and polygons composing the shape mesh.
01249    Int_t n = gGeoManager->GetNsegments()+1;
01250    Int_t nz = GetNz();
01251    nvert = nz*2*n;
01252    Bool_t specialCase = TGeoShape::IsSameWithinTolerance(GetDphi(),360);
01253    nsegs = 4*(nz*n-1+(specialCase == kTRUE));
01254    npols = 2*(nz*n-1+(specialCase == kTRUE));
01255 }
01256 
01257 //_____________________________________________________________________________
01258 const TBuffer3D & TGeoPcon::GetBuffer3D(Int_t reqSections, Bool_t localFrame) const
01259 {
01260 // Fills a static 3D buffer and returns a reference.
01261    static TBuffer3D buffer(TBuffer3DTypes::kGeneric);
01262 
01263    TGeoBBox::FillBuffer3D(buffer, reqSections, localFrame);
01264 
01265    if (reqSections & TBuffer3D::kRawSizes) {
01266       const Int_t n = gGeoManager->GetNsegments()+1;
01267       Int_t nz = GetNz();
01268       Int_t nbPnts = nz*2*n;
01269       if (nz >= 2 && nbPnts > 0) {
01270          Bool_t specialCase = TGeoShape::IsSameWithinTolerance(GetDphi(),360);
01271          Int_t nbSegs = 4*(nz*n-1+(specialCase == kTRUE));
01272          Int_t nbPols = 2*(nz*n-1+(specialCase == kTRUE));
01273          if (buffer.SetRawSizes(nbPnts, 3*nbPnts, nbSegs, 3*nbSegs, nbPols, 6*nbPols)) {
01274             buffer.SetSectionsValid(TBuffer3D::kRawSizes);
01275          }
01276       }
01277    }
01278    // TODO: Push down to TGeoShape?? Wuld have to do raw sizes set first..
01279    // can rest of TGeoShape be defered until after this?
01280    if ((reqSections & TBuffer3D::kRaw) && buffer.SectionsValid(TBuffer3D::kRawSizes)) {
01281       SetPoints(buffer.fPnts);
01282       if (!buffer.fLocalFrame) {
01283          TransformPoints(buffer.fPnts, buffer.NbPnts());
01284       }
01285 
01286       SetSegsAndPols(buffer);      
01287       buffer.SetSectionsValid(TBuffer3D::kRaw);
01288    }
01289       
01290    return buffer;
01291 }

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