TGeoPgon.cxx

Go to the documentation of this file.
00001 // @(#)root/geom:$Id: TGeoPgon.cxx 27731 2009-03-09 17:40:56Z brun $
00002 // Author: Andrei Gheata   31/01/02
00003 // TGeoPgon::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 // TGeoPgon - a polygone. It has at least 10 parameters :
00015 //            - the lower phi limit;
00016 //            - the range in phi;
00017 //            - the number of edges on each z plane;
00018 //            - the number of z planes (at least two) where the inner/outer 
00019 //              radii are changing;
00020 //            - z coordinate, inner and outer radius for each z plane
00021 //
00022 //_____________________________________________________________________________
00023 //Begin_Html
00024 /*
00025 <img src="gif/t_pgon.gif">
00026 */
00027 //End_Html
00028 //Begin_Html
00029 /*
00030 <img src="gif/t_pgondivZ.gif">
00031 */
00032 //End_Html
00033 
00034 #include "Riostream.h"
00035 
00036 #include "TGeoPgon.h"
00037 
00038 #include "TGeoManager.h"
00039 #include "TGeoVolume.h"
00040 #include "TVirtualGeoPainter.h"
00041 #include "TGeoTube.h"
00042 #include "TVirtualPad.h"
00043 #include "TBuffer3D.h"
00044 #include "TBuffer3DTypes.h"
00045 #include "TMath.h"
00046    
00047 ClassImp(TGeoPgon)
00048 
00049 //_____________________________________________________________________________
00050 TGeoPgon::TGeoPgon()
00051 {
00052 // dummy ctor
00053    SetShapeBit(TGeoShape::kGeoPgon);
00054    fNedges = 0;
00055 }   
00056 
00057 //_____________________________________________________________________________
00058 TGeoPgon::TGeoPgon(Double_t phi, Double_t dphi, Int_t nedges, Int_t nz)
00059          :TGeoPcon(phi, dphi, nz) 
00060 {
00061 // Default constructor
00062    SetShapeBit(TGeoShape::kGeoPgon);
00063    fNedges = nedges;
00064 }
00065 
00066 //_____________________________________________________________________________
00067 TGeoPgon::TGeoPgon(const char *name, Double_t phi, Double_t dphi, Int_t nedges, Int_t nz)
00068          :TGeoPcon(name, phi, dphi, nz) 
00069 {
00070 // Default constructor
00071    SetShapeBit(TGeoShape::kGeoPgon);
00072    fNedges = nedges;
00073 }
00074 
00075 //_____________________________________________________________________________
00076 TGeoPgon::TGeoPgon(Double_t *param)
00077          :TGeoPcon() 
00078 {
00079 // Default constructor in GEANT3 style
00080 // param[0] = phi1
00081 // param[1] = dphi
00082 // param[2] = nedges
00083 // param[3] = nz
00084 //
00085 // param[4] = z1
00086 // param[5] = Rmin1
00087 // param[6] = Rmax1
00088 // ...
00089    SetShapeBit(TGeoShape::kGeoPgon);
00090    SetDimensions(param);
00091    ComputeBBox();
00092 }
00093 
00094 //_____________________________________________________________________________
00095 TGeoPgon::~TGeoPgon()
00096 {
00097 // destructor
00098 }
00099 
00100 //_____________________________________________________________________________
00101 Double_t TGeoPgon::Capacity() const
00102 {
00103 // Computes capacity of the shape in [length^3]
00104    Int_t ipl;
00105    Double_t rmin1, rmax1, rmin2, rmax2, dphi, dz;
00106    Double_t capacity = 0.;
00107    dphi = fDphi/fNedges; // [deg]
00108    Double_t tphi2 = TMath::Tan(0.5*dphi*TMath::DegToRad());
00109    for (ipl=0; ipl<fNz-1; ipl++) {
00110       dz    = fZ[ipl+1]-fZ[ipl];
00111       if (dz < TGeoShape::Tolerance()) continue;
00112       rmin1 = fRmin[ipl];
00113       rmax1 = fRmax[ipl];
00114       rmin2 = fRmin[ipl+1];
00115       rmax2 = fRmax[ipl+1];
00116       capacity += fNedges*(tphi2/3.)*dz*(rmax1*rmax1+rmax1*rmax2+rmax2*rmax2 -
00117                                  rmin1*rmin1-rmin1*rmin2-rmin2*rmin2);
00118    }
00119    return capacity;   
00120 }
00121 
00122 //_____________________________________________________________________________
00123 void TGeoPgon::ComputeBBox()
00124 {
00125 // compute bounding box for a polygone
00126    // Check if the sections are in increasing Z order
00127    for (Int_t isec=0; isec<fNz-1; isec++) {
00128       if (fZ[isec]>fZ[isec+1]) {
00129          InspectShape();
00130          Fatal("ComputeBBox", "Wrong section order");
00131       }   
00132    }
00133    // Check if the last sections are valid
00134    if (TMath::Abs(fZ[1]-fZ[0]) < TGeoShape::Tolerance() ||
00135        TMath::Abs(fZ[fNz-1]-fZ[fNz-2]) < TGeoShape::Tolerance()) {
00136       InspectShape();
00137       Fatal("ComputeBBox","Shape %s at index %d: Not allowed first two or last two sections at same Z",
00138              GetName(), gGeoManager->GetListOfShapes()->IndexOf(this));
00139    }          
00140    Double_t zmin = TMath::Min(fZ[0], fZ[fNz-1]);
00141    Double_t zmax = TMath::Max(fZ[0], fZ[fNz-1]);
00142    // find largest rmax an smallest rmin
00143    Double_t rmin, rmax;
00144    Double_t divphi = fDphi/fNedges;
00145    // find the radius of the outscribed circle
00146    rmin = fRmin[TMath::LocMin(fNz, fRmin)];   
00147    rmax = fRmax[TMath::LocMax(fNz, fRmax)];
00148    rmax = rmax/TMath::Cos(0.5*divphi*TMath::DegToRad());
00149    Double_t phi1 = fPhi1;
00150    Double_t phi2 = phi1 + fDphi;
00151    
00152    Double_t xc[4];
00153    Double_t yc[4];
00154    xc[0] = rmax*TMath::Cos(phi1*TMath::DegToRad());
00155    yc[0] = rmax*TMath::Sin(phi1*TMath::DegToRad());
00156    xc[1] = rmax*TMath::Cos(phi2*TMath::DegToRad());
00157    yc[1] = rmax*TMath::Sin(phi2*TMath::DegToRad());
00158    xc[2] = rmin*TMath::Cos(phi1*TMath::DegToRad());
00159    yc[2] = rmin*TMath::Sin(phi1*TMath::DegToRad());
00160    xc[3] = rmin*TMath::Cos(phi2*TMath::DegToRad());
00161    yc[3] = rmin*TMath::Sin(phi2*TMath::DegToRad());
00162 
00163    Double_t xmin = xc[TMath::LocMin(4, &xc[0])];
00164    Double_t xmax = xc[TMath::LocMax(4, &xc[0])]; 
00165    Double_t ymin = yc[TMath::LocMin(4, &yc[0])]; 
00166    Double_t ymax = yc[TMath::LocMax(4, &yc[0])];
00167 
00168    Double_t ddp = -phi1;
00169    if (ddp<0) ddp+= 360;
00170    if (ddp<=fDphi) xmax = rmax;
00171    ddp = 90-phi1;
00172    if (ddp<0) ddp+= 360;
00173    if (ddp<=fDphi) ymax = rmax;
00174    ddp = 180-phi1;
00175    if (ddp<0) ddp+= 360;
00176    if (ddp<=fDphi) xmin = -rmax;
00177    ddp = 270-phi1;
00178    if (ddp<0) ddp+= 360;
00179    if (ddp<=fDphi) ymin = -rmax;
00180    fOrigin[0] = 0.5*(xmax+xmin);
00181    fOrigin[1] = 0.5*(ymax+ymin);
00182    fOrigin[2] = 0.5*(zmax+zmin);
00183    fDX = 0.5*(xmax-xmin);
00184    fDY = 0.5*(ymax-ymin);
00185    fDZ = 0.5*(zmax-zmin);
00186    SetShapeBit(kGeoClosedShape);
00187 }
00188 
00189 //_____________________________________________________________________________   
00190 void TGeoPgon::ComputeNormal(Double_t *point, Double_t *dir, Double_t *norm)
00191 {
00192 // Compute normal to closest surface from POINT. 
00193    memset(norm,0,3*sizeof(Double_t));
00194    Double_t phi1=0, phi2=0, c1=0, s1=0, c2=0, s2=0;
00195    Double_t dz, rmin1, rmin2;
00196    Bool_t is_seg  = (fDphi<360)?kTRUE:kFALSE;
00197    if (is_seg) {
00198       phi1 = fPhi1;
00199       if (phi1<0) phi1+=360;
00200       phi2 = phi1 + fDphi;
00201       phi1 *= TMath::DegToRad();
00202       phi2 *= TMath::DegToRad();
00203       c1 = TMath::Cos(phi1);
00204       s1 = TMath::Sin(phi1);
00205       c2 = TMath::Cos(phi2);
00206       s2 = TMath::Sin(phi2);
00207       if (TGeoShape::IsCloseToPhi(1E-5, point, c1,s1,c2,s2)) {
00208          TGeoShape::NormalPhi(point,dir,norm,c1,s1,c2,s2);
00209          return;
00210       }
00211    } // Phi done   
00212 
00213    Int_t ipl = TMath::BinarySearch(fNz, fZ, point[2]);
00214    if (ipl==(fNz-1) || ipl<0) {
00215       // point outside Z range
00216       norm[2] = TMath::Sign(1., dir[2]);
00217       return;
00218    }
00219    Int_t iplclose = ipl;
00220    if ((fZ[ipl+1]-point[2])<(point[2]-fZ[ipl])) iplclose++;
00221    dz = TMath::Abs(fZ[iplclose]-point[2]);
00222 
00223    Double_t divphi = fDphi/fNedges;
00224    Double_t phi = TMath::ATan2(point[1], point[0])*TMath::RadToDeg();
00225    while (phi<fPhi1) phi+=360.;
00226    Double_t ddp = phi-fPhi1;
00227    Int_t ipsec = Int_t(ddp/divphi);
00228    Double_t ph0 = (fPhi1+divphi*(ipsec+0.5))*TMath::DegToRad();
00229    // compute projected distance
00230    Double_t r, rsum, rpgon, ta, calf;
00231    r = TMath::Abs(point[0]*TMath::Cos(ph0)+point[1]*TMath::Sin(ph0));
00232    if (dz<1E-5) {
00233       if (iplclose==0 || iplclose==(fNz-1)) {
00234          norm[2] = TMath::Sign(1., dir[2]);
00235          return;
00236       }
00237       if (iplclose==ipl && TGeoShape::IsSameWithinTolerance(fZ[ipl],fZ[ipl-1])) {
00238          if (r<TMath::Max(fRmin[ipl],fRmin[ipl-1]) || r>TMath::Min(fRmax[ipl],fRmax[ipl-1])) {
00239             norm[2] = TMath::Sign(1., dir[2]);
00240             return;
00241          }
00242       } else {
00243          if (TGeoShape::IsSameWithinTolerance(fZ[iplclose],fZ[iplclose+1])) {
00244             if (r<TMath::Max(fRmin[iplclose],fRmin[iplclose+1]) || r>TMath::Min(fRmax[iplclose],fRmax[iplclose+1])) {
00245                norm[2] = TMath::Sign(1., dir[2]);
00246                return;
00247             }
00248          }
00249       }
00250    } //-> Z done
00251 
00252    dz = fZ[ipl+1]-fZ[ipl];
00253    rmin1 = fRmin[ipl];
00254    rmin2 = fRmin[ipl+1];
00255    rsum = rmin1+rmin2;
00256    Double_t safe = TGeoShape::Big();
00257    if (rsum>1E-10) {
00258       ta = (rmin2-rmin1)/dz;
00259       calf = 1./TMath::Sqrt(1+ta*ta);
00260       rpgon = rmin1 + (point[2]-fZ[ipl])*ta;
00261       safe = TMath::Abs(r-rpgon);
00262       norm[0] = calf*TMath::Cos(ph0);
00263       norm[1] = calf*TMath::Sin(ph0);
00264       norm[2] = -calf*ta;
00265    }
00266    ta = (fRmax[ipl+1]-fRmax[ipl])/dz;
00267    calf = 1./TMath::Sqrt(1+ta*ta);
00268    rpgon = fRmax[ipl] + (point[2]-fZ[ipl])*ta;
00269    if (safe>TMath::Abs(rpgon-r)) {
00270       norm[0] = calf*TMath::Cos(ph0);
00271       norm[1] = calf*TMath::Sin(ph0);
00272       norm[2] = -calf*ta;
00273    }   
00274    if (norm[0]*dir[0]+norm[1]*dir[1]+norm[2]*dir[2]<0) {
00275       norm[0] = -norm[0];
00276       norm[1] = -norm[1];
00277       norm[2] = -norm[2];
00278    }   
00279 }
00280 
00281 //_____________________________________________________________________________
00282 Bool_t TGeoPgon::Contains(Double_t *point) const
00283 {
00284 // test if point is inside this shape
00285    // check total z range
00286    if (point[2]<fZ[0]) return kFALSE;
00287    if (point[2]>fZ[fNz-1]) return kFALSE;
00288    Double_t divphi = fDphi/fNedges;
00289    // now check phi
00290    Double_t phi = TMath::ATan2(point[1], point[0])*TMath::RadToDeg();
00291    while (phi < fPhi1) phi += 360.0;
00292    Double_t ddp = phi-fPhi1;
00293    if (ddp>fDphi) return kFALSE;
00294    // now find phi division
00295    Int_t ipsec = TMath::Min(Int_t(ddp/divphi), fNedges-1);
00296    Double_t ph0 = (fPhi1+divphi*(ipsec+0.5))*TMath::DegToRad();
00297    // now check projected distance
00298    Double_t r = point[0]*TMath::Cos(ph0) + point[1]*TMath::Sin(ph0);
00299    // find in which Z section the point is in
00300    Int_t iz = TMath::BinarySearch(fNz, fZ, point[2]);
00301    if (iz==fNz-1) {
00302       if (r<fRmin[iz]) return kFALSE;
00303       if (r>fRmax[iz]) return kFALSE;
00304       return kTRUE;
00305    }  
00306    Double_t dz = fZ[iz+1]-fZ[iz];
00307    Double_t rmin, rmax;
00308    if (dz<1E-8) {
00309       // we are at a radius-changing plane 
00310       rmin = TMath::Min(fRmin[iz], fRmin[iz+1]);
00311       rmax = TMath::Max(fRmax[iz], fRmax[iz+1]);
00312       if (r<rmin) return kFALSE;
00313       if (r>rmax) return kFALSE;
00314       return kTRUE;
00315    }   
00316    // now compute rmin and rmax and test the value of r
00317    Double_t dzrat = (point[2]-fZ[iz])/dz;
00318    rmin = fRmin[iz]+dzrat*(fRmin[iz+1]-fRmin[iz]);
00319    // is the point inside the 'hole' at the center of the volume ?
00320    if (r < rmin) return kFALSE;
00321    rmax = fRmax[iz]+dzrat*(fRmax[iz+1]-fRmax[iz]);
00322    if (r > rmax) return kFALSE;
00323    
00324    return kTRUE;
00325 }
00326 
00327 //_____________________________________________________________________________
00328 Double_t TGeoPgon::DistFromInside(Double_t *point, Double_t *dir, Int_t iact, Double_t step, Double_t *safe) const
00329 {
00330 // compute distance from inside point to surface of the polygone
00331    // first find out in which Z section the point is in
00332    if (iact<3 && safe) {
00333       *safe = Safety(point, kTRUE);
00334       if (iact==0) return TGeoShape::Big();
00335       if (iact==1 && step<*safe) return TGeoShape::Big();
00336    }   
00337    // find current Z section
00338    Int_t ipl, ipsec;
00339    ipl = TMath::BinarySearch(fNz, fZ, point[2]);
00340    if (ipl==fNz-1) {
00341       if (dir[2]>=0) return 0.;
00342       ipl--;
00343    }   
00344    if (ipl<0) {
00345       // point out
00346       if (dir[2]<=0) return 0.;
00347       ipl++;
00348    }
00349    Double_t stepmax = step;
00350    Double_t *sph = gGeoManager->GetDblBuffer(fNedges+2);
00351    Int_t *iph = gGeoManager->GetIntBuffer(fNedges+2);
00352    // locate current phi sector [0,fNedges-1]; -1 for dead region
00353    LocatePhi(point, ipsec);
00354    if (ipsec<0) {
00355    // Point on a phi boundary - entering or exiting ?
00356       Double_t phi1 = fPhi1*TMath::DegToRad();
00357       Double_t phi2 = (fPhi1+fDphi)*TMath::DegToRad();
00358       if ((point[0]*dir[1]-point[1]*dir[0])>0) {
00359          // phi1 next crossing
00360          if ((point[0]*TMath::Cos(phi1)+point[1]*TMath::Sin(phi1)) <
00361             (point[0]*TMath::Cos(phi2)+point[1]*TMath::Sin(phi2))) {
00362             // close to phimax 
00363             return 0.0;
00364          } else { 
00365             // close to phi1 - ignore it
00366             ipsec = 0;
00367          }
00368       } else {
00369          // phimax next crossing
00370          if ((point[0]*TMath::Cos(phi1)+point[1]*TMath::Sin(phi1)) >
00371             (point[0]*TMath::Cos(phi2)+point[1]*TMath::Sin(phi2))) {
00372             // close to phi1 
00373             return 0.0;
00374          } else {
00375             // close to phimax - ignore it
00376             ipsec = fNedges-1;
00377          }         
00378       }      
00379    }
00380    Int_t ipln = -1;
00381    if (TGeoShape::IsSameWithinTolerance(fZ[ipl],fZ[ipl+1])) {
00382       ipln = ipl;
00383    } else {   
00384       if (fNz>3 && ipl>0 && ipl<fNz-3 && TGeoShape::IsSameWithinTolerance(fZ[ipl+1],fZ[ipl+2]) && TGeoShape::IsSameWithinTolerance(point[2],fZ[ipl+1])) {
00385          ipln = ipl+1;
00386       } else {
00387          if (ipl>1 && TGeoShape::IsSameWithinTolerance(fZ[ipl],fZ[ipl-1]) && TGeoShape::IsSameWithinTolerance(point[2],fZ[ipl])) ipln = ipl-1;
00388       }   
00389    }
00390    if (ipln>0) {
00391       // point between segments
00392       Double_t divphi = fDphi/fNedges;
00393       Double_t phi = (fPhi1 + (ipsec+0.5)*divphi)*TMath::DegToRad();
00394       Double_t cphi = TMath::Cos(phi);
00395       Double_t sphi = TMath::Sin(phi);
00396       Double_t rproj = point[0]*cphi+point[1]*sphi;
00397       if (dir[2]>0) {
00398          ipl = ipln+1;
00399          if (rproj>fRmin[ipln] && rproj<fRmin[ipln+1]) return 0.0;
00400          if (rproj<fRmax[ipln] && rproj>fRmax[ipln+1]) return 0.0;
00401       } else {
00402          ipl = ipln-1;
00403          if (rproj<fRmin[ipln] && rproj>fRmin[ipln+1]) return 0.0;
00404          if (rproj>fRmax[ipln] && rproj<fRmax[ipln+1]) return 0.0;
00405       }   
00406    }   
00407          
00408    Int_t icrossed;
00409    icrossed = GetPhiCrossList(point,dir,ipsec,sph,iph, stepmax);
00410    Double_t snext;
00411    if (TMath::Abs(dir[2])<TGeoShape::Tolerance()) {
00412       if (SliceCrossingInZ(point, dir, icrossed, iph, sph, snext, stepmax)) return snext;
00413       if (snext>TGeoShape::Tolerance()) return TGeoShape::Big();
00414       return 0.;
00415    }
00416    if (SliceCrossingIn(point, dir, ipl, icrossed, iph, sph, snext, stepmax)) return snext;
00417    if (snext>TGeoShape::Tolerance()) return TGeoShape::Big();
00418    return 0.;
00419 }   
00420 
00421 //_____________________________________________________________________________
00422 void TGeoPgon::LocatePhi(Double_t *point, Int_t &ipsec) const
00423 {
00424 // Locates index IPSEC of the phi sector containing POINT.
00425    Double_t phi = TMath::ATan2(point[1], point[0])*TMath::RadToDeg();
00426    while (phi<fPhi1) phi+=360.;
00427    ipsec = Int_t(fNedges*(phi-fPhi1)/fDphi); // [0, fNedges-1]
00428    if (ipsec>fNedges-1) ipsec = -1; // in gap
00429 }                    
00430 
00431 //_____________________________________________________________________________
00432 Int_t TGeoPgon::GetPhiCrossList(Double_t *point, Double_t *dir, Int_t istart, Double_t *sphi, Int_t *iphi, Double_t stepmax) const
00433 {
00434 // Returns lists of PGON phi crossings for a ray starting from POINT.
00435    Double_t rxy, phi, cph, sph;
00436    Int_t icrossed = 0;
00437    if ((1.-TMath::Abs(dir[2]))<1E-8) {
00438       // ray is going parallel with Z
00439       iphi[0] = istart;
00440       sphi[0] = stepmax;
00441       return 1;
00442    }   
00443    Bool_t shootorig = (TMath::Abs(point[0]*dir[1]-point[1]*dir[0])<1E-8)?kTRUE:kFALSE;
00444    Double_t divphi = fDphi/fNedges;
00445    if (shootorig) {
00446       Double_t rdotn = point[0]*dir[0]+point[1]*dir[1];
00447       if (rdotn>0) {
00448          sphi[icrossed] = stepmax;
00449          iphi[icrossed++] = istart;
00450          return icrossed;
00451       }
00452       sphi[icrossed] = TMath::Sqrt((point[0]*point[0]+point[1]*point[1])/(1.-dir[2]*dir[2]));
00453       iphi[icrossed++] = istart;
00454       if (sphi[icrossed-1]>stepmax) {
00455          sphi[icrossed-1] = stepmax;
00456          return icrossed;
00457       }   
00458       phi = TMath::ATan2(dir[1], dir[0])*TMath::RadToDeg();   
00459       while (phi<fPhi1) phi+=360.;
00460       istart = Int_t((phi-fPhi1)/divphi);
00461       if (istart>fNedges-1) istart=-1;
00462       iphi[icrossed] = istart;
00463       sphi[icrossed] = stepmax;
00464       icrossed++;
00465       return icrossed;
00466    }   
00467    Int_t incsec = Int_t(TMath::Sign(1., point[0]*dir[1]-point[1]*dir[0]));
00468    Int_t ist;
00469    if (istart<0) ist=(incsec>0)?0:fNedges;
00470    else          ist=(incsec>0)?(istart+1):istart;
00471    Bool_t crossing = kTRUE;
00472    Bool_t gapdone = kFALSE;
00473    divphi *= TMath::DegToRad();
00474    Double_t phi1 = fPhi1*TMath::DegToRad();
00475    while (crossing) { 
00476       if (istart<0) gapdone = kTRUE;
00477       phi = phi1+ist*divphi;
00478       cph = TMath::Cos(phi);
00479       sph = TMath::Sin(phi);
00480       crossing = IsCrossingSemiplane(point,dir,cph,sph,sphi[icrossed],rxy);
00481       if (!crossing) sphi[icrossed] = stepmax;
00482       iphi[icrossed++] = istart;  
00483       if (crossing) {
00484          if (sphi[icrossed-1]>stepmax) {
00485             sphi[icrossed-1] = stepmax;
00486             return icrossed;
00487          }   
00488          if (istart<0) {
00489             istart = (incsec>0)?0:(fNedges-1);
00490          } else {
00491             istart += incsec;
00492             if (istart>fNedges-1) istart=(fDphi<360.)?(-1):0;
00493             else if (istart<0 && TGeoShape::IsSameWithinTolerance(fDphi,360)) istart=fNedges-1;
00494          }
00495          if (istart<0) {
00496             if (gapdone) return icrossed;
00497             ist=(incsec>0)?0:fNedges;
00498          } else  {
00499             ist=(incsec>0)?(istart+1):istart;
00500          }   
00501       }
00502    }      
00503    return icrossed;
00504 }        
00505 
00506 //_____________________________________________________________________________
00507 Bool_t TGeoPgon::SliceCrossingInZ(Double_t *point, Double_t *dir, Int_t nphi, Int_t *iphi, Double_t *stepphi, Double_t &snext, Double_t stepmax) const
00508 {
00509 // Performs ray propagation between Z segments.
00510    snext = 0.;
00511    if (!nphi) return kFALSE;
00512    Int_t i;
00513    Double_t rmin, rmax;
00514    Double_t apg,bpg;
00515    Double_t pt[3];
00516    if (iphi[0]<0 && nphi==1) return kFALSE;
00517    // Get current Z segment
00518    Int_t ipl = TMath::BinarySearch(fNz, fZ, point[2]);
00519    if (ipl<0 || ipl==fNz-1) return kFALSE;
00520    if (TMath::Abs(point[2]-fZ[ipl])<TGeoShape::Tolerance()) {
00521       if (ipl<fNz-2 && TGeoShape::IsSameWithinTolerance(fZ[ipl],fZ[ipl+1])) {
00522          rmin = TMath::Min(fRmin[ipl], fRmin[ipl+1]);
00523          rmax = TMath::Max(fRmax[ipl], fRmax[ipl+1]);
00524       } else if (ipl>1 && TGeoShape::IsSameWithinTolerance(fZ[ipl],fZ[ipl-1])) {
00525          rmin = TMath::Min(fRmin[ipl], fRmin[ipl+1]);
00526          rmax = TMath::Max(fRmax[ipl], fRmax[ipl+1]);
00527       } else {
00528          rmin = fRmin[ipl];
00529          rmax = fRmax[ipl];
00530       }
00531    } else {
00532       rmin = Rpg(point[2], ipl, kTRUE, apg,bpg);        
00533       rmax = Rpg(point[2], ipl, kFALSE, apg,bpg);        
00534    }
00535    Int_t iphcrt;
00536    Double_t divphi = TMath::DegToRad()*fDphi/fNedges;
00537    Double_t rproj, ndot, dist;
00538    Double_t phi1 = fPhi1*TMath::DegToRad();
00539    Double_t cosph, sinph;
00540    Double_t snextphi = 0.;
00541    Double_t step = 0;
00542    Double_t phi;
00543    memcpy(pt,point,3*sizeof(Double_t));
00544    for (iphcrt=0; iphcrt<nphi; iphcrt++) {
00545       if (step>stepmax) {
00546          snext = step;
00547          return kFALSE;             
00548       }   
00549       if (iphi[iphcrt]<0) {
00550          snext = step;
00551          return kTRUE;
00552       }
00553       // check crossing
00554       snextphi = stepphi[iphcrt];
00555       phi = phi1+(iphi[iphcrt]+0.5)*divphi;
00556       cosph = TMath::Cos(phi);
00557       sinph = TMath::Sin(phi);
00558       rproj = pt[0]*cosph+pt[1]*sinph;
00559       dist = TGeoShape::Big();
00560       ndot = dir[0]*cosph+dir[1]*sinph;
00561       if (!TGeoShape::IsSameWithinTolerance(ndot,0)) {
00562          dist = (ndot>0)?((rmax-rproj)/ndot):((rmin-rproj)/ndot);
00563          if (dist<0) dist=0.;
00564       }
00565       if (dist < (snextphi-step)) {
00566          snext = step + dist;
00567          if (snext<stepmax) return kTRUE;
00568          return kFALSE;
00569       }            
00570       step = snextphi;
00571       for (i=0; i<3; i++) pt[i] = point[i]+step*dir[i];      
00572    }
00573    snext = step;
00574    return kFALSE;            
00575 }
00576  
00577 //_____________________________________________________________________________
00578 Bool_t TGeoPgon::SliceCrossingZ(Double_t *point, Double_t *dir, Int_t nphi, Int_t *iphi, Double_t *stepphi, Double_t &snext, Double_t stepmax) const
00579 {
00580 // Performs ray propagation between Z segments.
00581    if (!nphi) return kFALSE;
00582    Int_t i;
00583    Double_t rmin, rmax;
00584    Double_t apg,bpg;
00585    Double_t pt[3];
00586    if (iphi[0]<0 && nphi==1) return kFALSE;
00587    // Get current Z segment
00588    Int_t ipl = TMath::BinarySearch(fNz, fZ, point[2]);
00589    if (ipl<0 || ipl==fNz-1) return kFALSE;
00590    if (TMath::Abs(point[2]-fZ[ipl])<TGeoShape::Tolerance()) {
00591       if (ipl<fNz-2 && TGeoShape::IsSameWithinTolerance(fZ[ipl],fZ[ipl+1])) {
00592          rmin = TMath::Min(fRmin[ipl], fRmin[ipl+1]);
00593          rmax = TMath::Max(fRmax[ipl], fRmax[ipl+1]);
00594       } else if (ipl>1 && TGeoShape::IsSameWithinTolerance(fZ[ipl],fZ[ipl-1])) {
00595          rmin = TMath::Min(fRmin[ipl], fRmin[ipl+1]);
00596          rmax = TMath::Max(fRmax[ipl], fRmax[ipl+1]);
00597       } else {
00598          rmin = fRmin[ipl];
00599          rmax = fRmax[ipl];
00600       }
00601    } else {
00602       rmin = Rpg(point[2], ipl, kTRUE, apg,bpg);        
00603       rmax = Rpg(point[2], ipl, kFALSE, apg,bpg);        
00604    }
00605    Int_t iphcrt;
00606    Double_t divphi = TMath::DegToRad()*fDphi/fNedges;
00607    Double_t rproj, ndot, dist;
00608    Double_t phi1 = fPhi1*TMath::DegToRad();
00609    Double_t cosph, sinph;
00610    Double_t snextphi = 0.;
00611    Double_t step = 0;
00612    Double_t phi;
00613    memcpy(pt,point,3*sizeof(Double_t));
00614    for (iphcrt=0; iphcrt<nphi; iphcrt++) {
00615       if (step>stepmax) return kFALSE;             
00616       snextphi = stepphi[iphcrt];
00617       if (iphi[iphcrt]<0) {
00618          if (iphcrt==nphi-1) return kFALSE;
00619          if (snextphi>stepmax) return kFALSE;
00620          for (i=0; i<3; i++) pt[i] = point[i]+snextphi*dir[i];
00621          phi = phi1+(iphi[iphcrt+1]+0.5)*divphi;
00622          cosph = TMath::Cos(phi);
00623          sinph = TMath::Sin(phi);
00624          rproj = pt[0]*cosph+pt[1]*sinph;
00625          if (rproj<rmin || rproj>rmax) {
00626             step = snextphi;
00627             continue;
00628          }   
00629          snext = snextphi;
00630          return kTRUE;
00631       }
00632       // check crossing
00633       phi = phi1+(iphi[iphcrt]+0.5)*divphi;
00634       cosph = TMath::Cos(phi);
00635       sinph = TMath::Sin(phi);
00636       rproj = pt[0]*cosph+pt[1]*sinph;
00637       dist = TGeoShape::Big();
00638       ndot = dir[0]*cosph+dir[1]*sinph;
00639       if (rproj<rmin) {
00640          dist = (ndot>0)?((rmin-rproj)/ndot):TGeoShape::Big();
00641       } else {
00642          dist = (ndot<0)?((rmax-rproj)/ndot):TGeoShape::Big();
00643       }    
00644       if (dist<1E10) {
00645          snext = step+dist;
00646          if (snext<stepmax) return kTRUE;
00647       }        
00648       step = snextphi;
00649       for (i=0; i<3; i++) pt[i] = point[i]+step*dir[i];      
00650    }
00651    return kFALSE;            
00652 }  
00653 
00654 //_____________________________________________________________________________
00655 Bool_t TGeoPgon::SliceCrossingIn(Double_t *point, Double_t *dir, Int_t ipl, Int_t nphi, Int_t *iphi, Double_t *stepphi, Double_t &snext, Double_t stepmax) const
00656 {
00657 // Check boundary crossing inside phi slices. Return distance snext to first crossing
00658 // if smaller than stepmax.
00659 // Protection in case point is in phi gap or close to phi boundaries and exiting
00660    snext = 0.;
00661    if (!nphi) return kFALSE;
00662    Int_t i;
00663    Int_t iphstart = 0;
00664    Double_t pt[3];
00665    if (iphi[0]<0) {
00666       if (stepphi[0]>TGeoShape::Tolerance()) return kFALSE;
00667       iphstart = 1;
00668    }   
00669    if (nphi>1 && iphi[1]<0 && stepphi[0]<TGeoShape::Tolerance()) {
00670       snext = stepphi[0];
00671       return kTRUE;
00672    }   
00673    // Get current Z segment
00674    Double_t snextphi = 0.;
00675    Double_t step = 0;
00676    Int_t incseg = (dir[2]>0)?1:-1; // dir[2] is never 0 here
00677    // Compute the projected radius from starting point
00678    Int_t iplstart = ipl;
00679    Int_t iphcrt = 0;
00680    Double_t apr=TGeoShape::Big(), bpr=0, db=0;
00681    Double_t rpg=0, rnew=0, znew=0;
00682    Double_t rpgin=0,rpgout=0,apgin=0,apgout=0,bpgin=0,bpgout=0;
00683    Double_t divphi = TMath::DegToRad()*fDphi/fNedges;
00684    Double_t phi1 = fPhi1*TMath::DegToRad();
00685    Double_t phi=0, dz=0;
00686    Double_t cosph=0, sinph=0;
00687    Double_t distz=0, distr=0, din=0, dout=0;
00688    Double_t invdir = 1./dir[2];
00689    memcpy(pt,point,3*sizeof(Double_t));
00690    for (iphcrt=iphstart; iphcrt<nphi; iphcrt++) {
00691       // check if step to current checked slice is too big
00692       if (step>stepmax) {
00693          snext = step;
00694          return kFALSE;
00695       }
00696       if (iphi[iphcrt]<0) {
00697          snext = snextphi;
00698          return kTRUE;
00699       }   
00700       snextphi = stepphi[iphcrt];
00701       phi = phi1+(iphi[iphcrt]+0.5)*divphi;
00702       cosph = TMath::Cos(phi);
00703       sinph = TMath::Sin(phi);
00704       Double_t rproj = Rproj(pt[2], pt, dir, cosph, sinph, apr, bpr);
00705       // compute distance to next Z plane
00706       while (ipl>=0 && ipl<fNz-1) {
00707          din = dout = TGeoShape::Big();
00708          // dist to last boundary of current segment according dir
00709          distz = (fZ[ipl+((1+incseg)>>1)]-pt[2])*invdir;
00710          // length of current segment
00711          dz = fZ[ipl+1] - fZ[ipl];
00712          if (dz < TGeoShape::Tolerance()) {
00713             rnew = apr+bpr*fZ[ipl];
00714             rpg = (rnew-fRmin[ipl])*(rnew-fRmin[ipl+1]);
00715             if (rpg<=0) din=distz;
00716             rpg = (rnew-fRmax[ipl])*(rnew-fRmax[ipl+1]);
00717             if (rpg<=0) dout=distz;
00718             distr = TMath::Min(din, dout);
00719          } else {
00720             rpgin = Rpg(pt[2], ipl, kTRUE, apgin, bpgin);
00721             db = bpgin-bpr;
00722             if (TMath::Abs(db) > TGeoShape::Tolerance()) {
00723                znew = (apr-apgin)/db;
00724                din = (znew-pt[2])*invdir;
00725             }
00726             rpgout = Rpg(pt[2], ipl, kFALSE, apgout, bpgout);
00727             db = bpgout-bpr;
00728             if (TMath::Abs(db) > TGeoShape::Tolerance()) {
00729                znew = (apr-apgout)/db;
00730                dout = (znew-pt[2])*invdir;
00731             }
00732             // protection for the first segment            
00733             Double_t dinp = (din>TMath::Abs(snext-TGeoShape::Tolerance()))?din:TGeoShape::Big();
00734             Double_t doutp = (dout>TMath::Abs(snext-TGeoShape::Tolerance()))?dout:TGeoShape::Big();
00735             distr = TMath::Min(dinp, doutp);
00736             if (iphcrt==iphstart && ipl==iplstart) {
00737                if (rproj<rpgin+TGeoShape::Tolerance()) {
00738                   Double_t ndotd = dir[0]*cosph+dir[1]*sinph+dir[2]*(fRmin[ipl]-fRmin[ipl+1])/dz;
00739                   if (ndotd<0) {
00740                      snext = (din<0)?step:(step+din);
00741                      return kTRUE;
00742                   }   
00743                   distr = TMath::Max(din,dout);
00744                   if (distr<TGeoShape::Tolerance()) distr=TGeoShape::Big();
00745                } else if (rproj>rpgout-TGeoShape::Tolerance()) {
00746                   Double_t ndotd = dir[0]*cosph+dir[1]*sinph+dir[2]*(fRmax[ipl]-fRmax[ipl+1])/dz;
00747                   if (ndotd>0) {
00748                      snext = (dout<0)?step:(step+dout);
00749                      return kTRUE;
00750                   }
00751                   distr = TMath::Max(din,dout);    
00752                   if (distr<TGeoShape::Tolerance()) distr=TGeoShape::Big();
00753                }  
00754             }
00755          } 
00756          if (distr<snext-TGeoShape::Tolerance()) distr=TGeoShape::Big();
00757          if (snextphi < step+TMath::Min(distz,distr)) {
00758             for (i=0; i<3; i++) pt[i] = point[i] + snextphi*dir[i];
00759             step = snextphi;
00760             snext = 0.0;
00761             break;
00762          }   
00763          if (distr<=distz+TGeoShape::Tolerance()) {
00764             step += distr;
00765             snext = step;
00766             return (step>stepmax)?kFALSE:kTRUE;
00767          }
00768          // we have crossed a Z boundary
00769          snext = distz;
00770          if ((ipl+incseg<0) || (ipl+incseg>fNz-2)) {
00771             // it was the last boundary
00772             step += distz;
00773             snext = step;
00774             return (step>stepmax)?kFALSE:kTRUE;
00775          } 
00776          ipl += incseg;
00777       }   // end loop Z
00778    }   // end loop phi
00779    snext = TGeoShape::Big();
00780    return kFALSE;
00781 }   
00782                
00783 //_____________________________________________________________________________
00784 Bool_t TGeoPgon::SliceCrossing(Double_t *point, Double_t *dir, Int_t nphi, Int_t *iphi, Double_t *stepphi, Double_t &snext, Double_t stepmax) const
00785 {
00786 // Check boundary crossing inside phi slices. Return distance snext to first crossing
00787 // if smaller than stepmax.
00788    if (!nphi) return kFALSE;
00789    Int_t i;
00790    Double_t pt[3];
00791    if (iphi[0]<0 && nphi==1) return kFALSE;
00792          
00793    Double_t snextphi = 0.;
00794    Double_t step = 0;
00795    // Get current Z segment
00796    Int_t incseg = (dir[2]>0)?1:-1; // dir[2] is never 0 here
00797    Int_t ipl = TMath::BinarySearch(fNz, fZ, point[2]);
00798    if (ipl<0) {
00799       ipl = 0; // this should never happen
00800       if (incseg<0) return kFALSE;
00801    } else {
00802       if (ipl==fNz-1) {
00803          ipl = fNz-2;  // nor this
00804          if (incseg>0) return kFALSE;
00805       } else {
00806          if (TMath::Abs(point[2]-fZ[ipl])<TGeoShape::Tolerance()) {
00807          // we are at the sector edge, but never inside the pgon
00808             if ((ipl+incseg)<0 || (ipl+incseg)>fNz-1) return kFALSE;
00809             if (TGeoShape::IsSameWithinTolerance(fZ[ipl],fZ[ipl+incseg])) ipl += incseg;
00810             // move to next clean segment if downwards
00811             if (incseg<0) {
00812                if (TGeoShape::IsSameWithinTolerance(fZ[ipl],fZ[ipl+1])) ipl--;
00813             }   
00814          }
00815       }
00816    }         
00817    // Compute the projected radius from starting point
00818    Int_t iphcrt;
00819    Double_t apg,bpg;
00820    Double_t rpgin;
00821    Double_t rpgout;
00822    Double_t divphi = TMath::DegToRad()*fDphi/fNedges;
00823    Double_t phi1 = fPhi1*TMath::DegToRad();
00824    Double_t phi;
00825    Double_t cosph, sinph;
00826    Double_t rproj;
00827    memcpy(pt,point,3*sizeof(Double_t));
00828    for (iphcrt=0; iphcrt<nphi; iphcrt++) {
00829       // check if step to current checked slice is too big
00830       if (step>stepmax) return kFALSE;
00831       // jump over the dead sector
00832       snextphi = stepphi[iphcrt];
00833       if (iphi[iphcrt]<0) {
00834          if (iphcrt==nphi-1) return kFALSE;
00835          if (snextphi>stepmax) return kFALSE;
00836          for (i=0; i<3; i++) pt[i] = point[i]+snextphi*dir[i];
00837          // we have a new z, so check again iz
00838          if (incseg>0) {
00839             // loop z planes
00840             while (pt[2]>fZ[ipl+1]) {
00841                ipl++;
00842                if (ipl>fNz-2) return kFALSE;
00843             }
00844          } else {
00845             while (pt[2]<fZ[ipl]) {
00846                ipl--;
00847                if (ipl<0) return kFALSE;
00848             }
00849          }      
00850          // check if we have a crossing when entering new sector
00851          rpgin = Rpg(pt[2],ipl,kTRUE,apg,bpg);
00852          rpgout = Rpg(pt[2],ipl,kFALSE,apg,bpg);
00853          phi = phi1+(iphi[iphcrt+1]+0.5)*divphi;
00854          cosph = TMath::Cos(phi);
00855          sinph = TMath::Sin(phi);
00856          
00857          rproj = pt[0]*cosph+pt[1]*sinph;
00858          if (rproj<rpgin || rproj>rpgout) {
00859             step = snextphi;
00860             continue;
00861          }   
00862          snext = snextphi;
00863          return kTRUE;
00864       } 
00865       if (IsCrossingSlice(point, dir, iphi[iphcrt], step, ipl, snext, TMath::Min(snextphi, stepmax)))
00866          return kTRUE;
00867       step = snextphi;   
00868    }                  
00869    return kFALSE;
00870 }
00871 //_____________________________________________________________________________
00872 Bool_t TGeoPgon::IsCrossingSlice(Double_t *point, Double_t *dir, Int_t iphi, Double_t sstart, Int_t &ipl, Double_t &snext, Double_t stepmax) const
00873 {
00874 // Check crossing of a given pgon slice, from a starting point inside the slice
00875    if (ipl<0 || ipl>fNz-2) return kFALSE;
00876    if (sstart>stepmax) return kFALSE;
00877    Double_t pt[3];
00878    memcpy(pt, point, 3*sizeof(Double_t));
00879    if (sstart>0) for (Int_t i=0; i<3; i++) pt[i] += sstart*dir[i];
00880    stepmax -= sstart;
00881    Double_t step;
00882    Int_t incseg = (dir[2]>0)?1:-1;
00883    Double_t invdir = 1./dir[2];
00884    Double_t divphi = TMath::DegToRad()*fDphi/fNedges;
00885    Double_t phi = fPhi1*TMath::DegToRad() + (iphi+0.5)*divphi;
00886    Double_t cphi = TMath::Cos(phi);
00887    Double_t sphi = TMath::Sin(phi);
00888    Double_t apr = TGeoShape::Big();
00889    Double_t bpr = 0.;
00890    Rproj(pt[2], point, dir, cphi, sphi, apr, bpr);
00891    Double_t dz;
00892    // loop segments
00893    Int_t icrtseg = ipl;
00894    Int_t isegstart = ipl;
00895    Int_t iseglast = (incseg>0)?(fNz-1):-1;
00896    Double_t din,dout,rdot,rnew,rpg,apg,bpg,db,znew;
00897    
00898    for (ipl=isegstart; ipl!=iseglast; ipl+=incseg) {
00899       step = (fZ[ipl+1-((1+incseg)>>1)]-pt[2])*invdir;
00900       if (step>0) {
00901          if (step>stepmax) {
00902             ipl = icrtseg;
00903             return kFALSE;
00904          }
00905          icrtseg = ipl;
00906       }      
00907       din = dout = TGeoShape::Big();
00908       dz = fZ[ipl+1]-fZ[ipl];
00909       
00910 //      rdot = (rproj-fRmin[ipl])*dz - (pt[2]-fZ[ipl])*(fRmin[ipl+1]-fRmin[ipl]);
00911       if (TGeoShape::IsSameWithinTolerance(dz,0)) rdot = dir[2]*TMath::Sign(1.,fRmin[ipl]-fRmin[ipl+1]);
00912       else rdot = dir[0]*cphi+dir[1]*sphi+dir[2]*(fRmin[ipl]-fRmin[ipl+1])/dz;
00913       if (rdot>0) {
00914          // inner surface visible ->check crossing
00915 //         printf("   inner visible\n");
00916          if (TGeoShape::IsSameWithinTolerance(dz,0)) {
00917             rnew = apr+bpr*fZ[ipl];
00918             rpg = (rnew-fRmin[ipl])*(rnew-fRmin[ipl+1]);
00919             if (rpg<=0) din=(fZ[ipl]-pt[2])*invdir;
00920          } else {
00921             rpg = Rpg(pt[2], ipl, kTRUE, apg, bpg);
00922             db = bpg-bpr;
00923             if (!TGeoShape::IsSameWithinTolerance(db,0)) {
00924                znew = (apr-apg)/db;
00925                if (znew>fZ[ipl] && znew<fZ[ipl+1]) {
00926                   din=(znew-pt[2])*invdir;
00927                   if (din<0) din=TGeoShape::Big();
00928                }   
00929             }
00930          }
00931       }
00932 //      printf("   din=%f\n", din);
00933 //      rdot = (rproj-fRmax[ipl])*dz - (pt[2]-fZ[ipl])*(fRmax[ipl+1]-fRmax[ipl]);        
00934       if (TGeoShape::IsSameWithinTolerance(dz,0)) rdot = dir[2]*TMath::Sign(1.,fRmax[ipl]-fRmax[ipl+1]);
00935       else rdot = dir[0]*cphi+dir[1]*sphi+dir[2]*(fRmax[ipl]-fRmax[ipl+1])/dz;
00936       if (rdot<0) {
00937 //         printf("   outer visible\n");
00938          // outer surface visible ->check crossing
00939          if (TGeoShape::IsSameWithinTolerance(dz,0)) {
00940             rnew = apr+bpr*fZ[ipl];
00941             rpg = (rnew-fRmax[ipl])*(rnew-fRmax[ipl+1]);
00942             if (rpg<=0) dout=(fZ[ipl]-pt[2])*invdir;
00943          } else {
00944             rpg = Rpg(pt[2], ipl, kFALSE, apg, bpg);
00945             db = bpg-bpr;
00946             if (!TGeoShape::IsSameWithinTolerance(db,0)) {
00947                znew = (apr-apg)/db;
00948                if (znew>fZ[ipl] && znew<fZ[ipl+1]) dout=(znew-pt[2])*invdir;
00949                if (dout<0) dout=TGeoShape::Big();
00950             }
00951          }
00952       }
00953 //      printf("   dout=%f\n", dout);
00954       step = TMath::Min(din, dout);
00955       if (step<1E10) {
00956          // there is a crossing within this segment
00957          if (step>stepmax) {
00958             ipl = icrtseg;
00959             return kFALSE;
00960          }   
00961          snext = sstart+step;
00962          return kTRUE;
00963       }   
00964    }
00965    ipl = icrtseg;
00966    return kFALSE;
00967 }           
00968 
00969 //_____________________________________________________________________________
00970 Double_t TGeoPgon::DistFromOutside(Double_t *point, Double_t *dir, Int_t iact, Double_t step, Double_t *safe) const
00971 {
00972 // Compute distance from outside point to surface of the polygone
00973    if (iact<3 && safe) {
00974       *safe = Safety(point, kFALSE);
00975       if (iact==0) return TGeoShape::Big();               // just safety computed
00976       if (iact==1 && step<*safe) return TGeoShape::Big(); // safety mode
00977    }   
00978 // Check if the bounding box is crossed within the requested distance
00979    Double_t sdist = TGeoBBox::DistFromOutside(point,dir, fDX, fDY, fDZ, fOrigin, step);
00980    if (sdist>=step) return TGeoShape::Big();
00981    // Protection for points on last Z sections
00982    if (dir[2]<=0 && TMath::Abs(point[2]-fZ[0])<TGeoShape::Tolerance()) return TGeoShape::Big();
00983    if (dir[2]>=0 && TMath::Abs(point[2]-fZ[fNz-1])<TGeoShape::Tolerance()) return TGeoShape::Big();
00984    // copy the current point
00985    Double_t pt[3];
00986    memcpy(pt,point,3*sizeof(Double_t));
00987    // find current Z section
00988    Int_t ipl;
00989    Int_t i, ipsec;
00990    ipl = TMath::BinarySearch(fNz, fZ, pt[2]);
00991 
00992    Double_t divphi=fDphi/fNedges;
00993    // check if ray may intersect outer cylinder
00994    Double_t snext = 0.;
00995    Double_t stepmax = step;
00996    Double_t rpr, snewcross;
00997    Double_t r2 = pt[0]*pt[0]+pt[1]*pt[1];
00998    Double_t radmax = fRmax[TMath::LocMax(fNz, fRmax)];
00999    radmax = radmax/TMath::Cos(0.5*divphi*TMath::DegToRad());
01000    radmax += 1E-8;
01001    if (r2>(radmax*radmax) || pt[2]<fZ[0] || pt[2]>fZ[fNz-1]) {
01002       pt[2] -= 0.5*(fZ[0]+fZ[fNz-1]);
01003       snext = TGeoTube::DistFromOutsideS(pt,dir,0.,radmax,0.5*(fZ[fNz-1]-fZ[0]));
01004       if (snext>1E10) return TGeoShape::Big();
01005       if (snext>stepmax) return TGeoShape::Big();
01006       stepmax -= snext;
01007       pt[2] = point[2];
01008       for (i=0; i<3; i++) pt[i] += snext*dir[i];
01009       Bool_t checkz = (ipl<0 && TMath::Abs(pt[2]-fZ[0])<1E-8)?kTRUE:kFALSE;
01010       if (!checkz) checkz = (ipl==fNz-1 && TMath::Abs(pt[2]-fZ[fNz-1])<1E-8)?kTRUE:kFALSE;
01011       if (checkz) {
01012          Double_t rmin,rmax;
01013          if (ipl<0) {
01014             rmin = fRmin[0];
01015             rmax = fRmax[0];
01016          } else {
01017             rmin = fRmin[fNz-1];
01018             rmax = fRmax[fNz-1];
01019          }      
01020          Double_t phi = TMath::ATan2(pt[1], pt[0])*TMath::RadToDeg();
01021          while (phi < fPhi1) phi += 360.0;
01022          Double_t ddp = phi-fPhi1;
01023          if (ddp<=fDphi) {
01024             ipsec = Int_t(ddp/divphi);
01025             Double_t ph0 = (fPhi1+divphi*(ipsec+0.5))*TMath::DegToRad();
01026             rpr = pt[0]*TMath::Cos(ph0) + pt[1]*TMath::Sin(ph0);
01027             if (rpr>=rmin && rpr<=rmax) return snext;
01028          }   
01029       }   
01030    }   
01031    Double_t *sph = gGeoManager->GetDblBuffer(fNedges+2);
01032    Int_t *iph = gGeoManager->GetIntBuffer(fNedges+2);
01033    Int_t icrossed;
01034    // locate current phi sector [0,fNedges-1]; -1 for dead region
01035    // if ray is perpendicular to Z, solve this particular case
01036    if (TMath::Abs(dir[2])<TGeoShape::Tolerance()) {
01037       LocatePhi(pt, ipsec);
01038       icrossed = GetPhiCrossList(pt,dir,ipsec,sph,iph, stepmax);
01039       if (SliceCrossingZ(pt, dir, icrossed, iph, sph, snewcross, stepmax)) return (snext+snewcross);
01040       return TGeoShape::Big();
01041    }
01042    // Locate phi and get the phi crossing list
01043    divphi *= TMath::DegToRad();
01044    Bool_t inphi = kTRUE;
01045    Double_t ph = TMath::ATan2(pt[1], pt[0])*TMath::RadToDeg();
01046    while (ph<fPhi1) ph+=360.;
01047    ipsec = Int_t(fNedges*(ph-fPhi1)/fDphi); // [0, fNedges-1]
01048    if (ipsec>fNedges-1) ipsec = -1; // in gap
01049    Double_t phim = fPhi1+0.5*fDphi;
01050    Double_t ddp = TMath::Abs(ph-phim);
01051    if (fDphi<360.0) {
01052       inphi = (ddp<0.5*fDphi+TGeoShape::Tolerance())?kTRUE:kFALSE;
01053    } 
01054    ipl = TMath::BinarySearch(fNz, fZ, pt[2]);
01055    if (ipl<0) ipl=0;
01056    if (ipl==fNz-1) ipl--;
01057    Bool_t inz = kTRUE;
01058    if (pt[2]>fZ[fNz-1]+TGeoShape::Tolerance()) inz=kFALSE;  
01059    if (pt[2]<fZ[0]-TGeoShape::Tolerance()) inz=kFALSE;  
01060    Bool_t onphi = kFALSE;
01061    if (inphi && inz) {
01062       Bool_t done = kFALSE;
01063       Double_t dz = fZ[ipl+1]-fZ[ipl];
01064       Double_t phi = fPhi1*TMath::DegToRad() + (ipsec+0.5)*divphi;
01065       Double_t cphi = TMath::Cos(phi);
01066       Double_t sphi = TMath::Sin(phi);
01067       Double_t rproj = pt[0]*cphi+pt[1]*sphi;
01068       if (TGeoShape::IsSameWithinTolerance(dz,0)) {
01069          if (rproj<fRmin[ipl] && rproj>fRmin[ipl+1] && dir[2]>0) return 0.0;
01070          if (rproj>fRmin[ipl] && rproj<fRmin[ipl+1] && dir[2]<0) return 0.0;
01071          if (rproj>fRmax[ipl] && rproj<fRmax[ipl+1] && dir[2]>0) return 0.0;
01072          if (rproj<fRmax[ipl] && rproj>fRmax[ipl+1] && dir[2]<0) return 0.0;
01073          done = kTRUE;
01074       }
01075       if (!done) {
01076          Double_t apgout,bpgout;
01077          Double_t rpgout = Rpg(pt[2], ipl, kFALSE, apgout, bpgout);
01078          if (rproj<rpgout+1.E-8) {
01079             Double_t apgin,bpgin;
01080             Double_t rpgin = Rpg(pt[2], ipl, kTRUE, apgin, bpgin);
01081             if (rproj>rpgin-1.E-8) {
01082                Double_t safrmin = rproj-rpgin;
01083                Double_t safrmax = rpgout-rproj;
01084                Double_t safz = TMath::Min(pt[2]-fZ[ipl],fZ[ipl+1]-pt[2]);
01085                Double_t safphi = TGeoShape::Big();
01086                if (fDphi<360) {
01087                   safphi=rproj*TMath::Sin((ddp-0.5*fDphi)*TMath::DegToRad());
01088                   safphi = TMath::Abs(safphi);
01089                }   
01090 //               printf("inside pgon: safrmin=%f, safrmax=%f, safphi=%f, safz=%f\n",safrmin,safrmax,safphi,safz);
01091                Double_t dzinv = 1./dz;
01092                if (safrmin<safz && safrmin<safrmax && safrmin<safphi) {
01093                   // on inner boundary
01094                   Double_t ndotd = dir[0]*cphi+dir[1]*sphi+dir[2]*(fRmin[ipl]-fRmin[ipl+1])*dzinv;
01095 //                  printf("   - inner ndotd=%f (>0 ->0)\n",ndotd);
01096                   if (ndotd>0) return snext;
01097                   done = kTRUE;
01098                }   
01099                if (!done && safrmax<safz && safrmax<safphi) {
01100                   Double_t ndotd = dir[0]*cphi+dir[1]*sphi+dir[2]*(fRmax[ipl]-fRmax[ipl+1])*dzinv;
01101 //                  printf("   - outer ndotd=%f (<0 ->0)\n",ndotd);
01102                   if (ndotd<0) return snext;
01103                   done = kTRUE;
01104                }
01105                if (!done && safz<safphi) {
01106                   done = kTRUE;
01107                   Int_t iplc = ipl;
01108                   if (TMath::Abs(pt[2]-fZ[ipl]) > TMath::Abs(fZ[ipl+1]-pt[2])) iplc++;   
01109                   if (iplc==0 || iplc==fNz-1) {                                    
01110                      if (pt[2]*dir[2]<0) return snext;
01111                      return TGeoShape::Big();
01112                   } else {
01113                      if (TGeoShape::IsSameWithinTolerance(fZ[iplc],fZ[iplc+1])) {
01114                         if (dir[2]>0) {
01115                            if (rproj<fRmin[iplc] && rproj>fRmin[iplc+1]) return snext;
01116                            if (rproj>fRmax[iplc] && rproj<fRmax[iplc+1]) return snext;
01117                         } else {
01118                            if (rproj>fRmin[iplc] && rproj<fRmin[iplc+1]) return snext;
01119                            if (rproj<fRmax[iplc] && rproj>fRmax[iplc+1]) return snext;
01120                         }   
01121                      } else if (TGeoShape::IsSameWithinTolerance(fZ[iplc],fZ[iplc-1])) {
01122                         if (dir[2]>0) {
01123                            if (rproj<fRmin[iplc-1] && rproj>fRmin[iplc]) return snext;
01124                            if (rproj>fRmax[iplc-1] && rproj<fRmax[iplc]) return snext;
01125                         } else {
01126                            if (rproj>fRmin[iplc-1] && rproj<fRmin[iplc]) return snext;
01127                            if (rproj<fRmax[iplc-1] && rproj>fRmax[iplc]) return snext;
01128                         }                        
01129                      }
01130                   }   
01131                }
01132                if (!done) {
01133                   // point on phi boundary
01134                   onphi = kTRUE;
01135                }
01136             }               
01137          }
01138       }     
01139    }
01140    icrossed = GetPhiCrossList(pt,dir,ipsec,sph,iph, stepmax);
01141    if (onphi) {
01142       if (!icrossed) return snext;
01143       if (iph[0]<0 && sph[0]<TGeoShape::Tolerance()) return (snext+sph[0]);
01144       if (iph[0]>=0 && sph[0]>TGeoShape::Tolerance()) return snext;
01145    }
01146    // Fire-up slice crossing algorithm
01147    if (SliceCrossing(pt, dir, icrossed, iph, sph, snewcross, stepmax)) {
01148       snext += snewcross;
01149       return snext;
01150    }   
01151    return TGeoShape::Big();   
01152 }          
01153 
01154 //_____________________________________________________________________________
01155 Int_t TGeoPgon::DistancetoPrimitive(Int_t px, Int_t py)
01156 {
01157 // compute closest distance from point px,py to each corner
01158    Int_t n = fNedges+1;
01159    const Int_t numPoints = 2*n*fNz;
01160    return ShapeDistancetoPrimitive(numPoints, px, py);
01161 }
01162 
01163 //_____________________________________________________________________________
01164 TGeoVolume *TGeoPgon::Divide(TGeoVolume *voldiv, const char *divname, Int_t iaxis, Int_t ndiv, 
01165                              Double_t start, Double_t step) 
01166 {
01167 //--- Divide this polygone shape belonging to volume "voldiv" into ndiv volumes
01168 // called divname, from start position with the given step. Returns pointer
01169 // to created division cell volume in case of Z divisions. Phi divisions are
01170 // allowed only if nedges%ndiv=0 and create polygone "segments" with nedges/ndiv edges.
01171 // Z divisions can be performed if the divided range is in between two consecutive Z planes.
01172 // In case a wrong division axis is supplied, returns pointer to volume that was divided.
01173 
01174 //   printf("Dividing %s : nz=%d nedges=%d phi1=%g dphi=%g (ndiv=%d iaxis=%d start=%g step=%g)\n",
01175 //          voldiv->GetName(), fNz, fNedges, fPhi1, fDphi, ndiv, iaxis, start, step);
01176    TGeoShape *shape;           //--- shape to be created
01177    TGeoVolume *vol;            //--- division volume to be created
01178    TGeoVolumeMulti *vmulti;    //--- generic divided volume
01179    TGeoPatternFinder *finder;  //--- finder to be attached 
01180    TString opt = "";           //--- option to be attached
01181    Int_t nedges = fNedges;
01182    Double_t zmin = start;
01183    Double_t zmax = start+ndiv*step;            
01184    Int_t isect = -1;
01185    Int_t is, id, ipl;
01186    switch (iaxis) {
01187       case 1:  //---                R division
01188          Error("Divide", "makes no sense dividing a pgon on radius");
01189          return 0;
01190       case 2:  //---                Phi division
01191          if (fNedges%ndiv) {
01192             Error("Divide", "ndiv should divide number of pgon edges");
01193             return 0;
01194          }
01195          nedges = fNedges/ndiv;
01196          finder = new TGeoPatternCylPhi(voldiv, ndiv, start, start+ndiv*step);
01197          vmulti = gGeoManager->MakeVolumeMulti(divname, voldiv->GetMedium());
01198          voldiv->SetFinder(finder);
01199          finder->SetDivIndex(voldiv->GetNdaughters());            
01200          shape = new TGeoPgon(-step/2, step, nedges, fNz);
01201          vol = new TGeoVolume(divname, shape, voldiv->GetMedium());
01202          vmulti->AddVolume(vol);
01203          for (is=0; is<fNz; is++)
01204             ((TGeoPgon*)shape)->DefineSection(is, fZ[is], fRmin[is], fRmax[is]); 
01205          opt = "Phi";
01206          for (id=0; id<ndiv; id++) {
01207             voldiv->AddNodeOffset(vol, id, start+id*step+step/2, opt.Data());
01208             ((TGeoNodeOffset*)voldiv->GetNodes()->At(voldiv->GetNdaughters()-1))->SetFinder(finder);
01209          }
01210          return vmulti;
01211       case 3: // ---                Z division
01212          // find start plane
01213          for (ipl=0; ipl<fNz-1; ipl++) {
01214             if (start<fZ[ipl]) continue;
01215             else {
01216                if ((start+ndiv*step)>fZ[ipl+1]) continue;
01217             }
01218             isect = ipl;
01219             zmin = fZ[isect];
01220             zmax = fZ[isect+1];
01221             break;
01222          }
01223          if (isect<0) {
01224             Error("Divide", "cannot divide pcon on Z if divided region is not between 2 consecutive planes");
01225             return 0;
01226          }
01227          finder = new TGeoPatternZ(voldiv, ndiv, start, start+ndiv*step);
01228          vmulti = gGeoManager->MakeVolumeMulti(divname, voldiv->GetMedium());
01229          voldiv->SetFinder(finder);
01230          finder->SetDivIndex(voldiv->GetNdaughters());
01231          opt = "Z";
01232          for (id=0; id<ndiv; id++) {
01233             Double_t z1 = start+id*step;
01234             Double_t z2 = start+(id+1)*step;
01235             Double_t rmin1 = (fRmin[isect]*(zmax-z1)-fRmin[isect+1]*(zmin-z1))/(zmax-zmin);
01236             Double_t rmax1 = (fRmax[isect]*(zmax-z1)-fRmax[isect+1]*(zmin-z1))/(zmax-zmin);
01237             Double_t rmin2 = (fRmin[isect]*(zmax-z2)-fRmin[isect+1]*(zmin-z2))/(zmax-zmin);
01238             Double_t rmax2 = (fRmax[isect]*(zmax-z2)-fRmax[isect+1]*(zmin-z2))/(zmax-zmin);
01239             shape = new TGeoPgon(fPhi1, fDphi, nedges, 2); 
01240             ((TGeoPgon*)shape)->DefineSection(0, -step/2, rmin1, rmax1); 
01241             ((TGeoPgon*)shape)->DefineSection(1,  step/2, rmin2, rmax2); 
01242             vol = new TGeoVolume(divname, shape, voldiv->GetMedium());
01243             vmulti->AddVolume(vol);
01244             voldiv->AddNodeOffset(vol, id, start+id*step+step/2, opt.Data());
01245             ((TGeoNodeOffset*)voldiv->GetNodes()->At(voldiv->GetNdaughters()-1))->SetFinder(finder);
01246          }
01247          return vmulti;
01248       default:
01249          Error("Divide", "Wrong axis type for division");
01250          return 0;            
01251    }
01252 }
01253 
01254 //_____________________________________________________________________________
01255 void TGeoPgon::GetBoundingCylinder(Double_t *param) const
01256 {
01257 //--- Fill vector param[4] with the bounding cylinder parameters. The order
01258 // is the following : Rmin, Rmax, Phi1, Phi2
01259    param[0] = fRmin[0];           // Rmin
01260    param[1] = fRmax[0];           // Rmax
01261    for (Int_t i=1; i<fNz; i++) {
01262       if (fRmin[i] < param[0]) param[0] = fRmin[i];
01263       if (fRmax[i] > param[1]) param[1] = fRmax[i];
01264    }
01265    Double_t divphi = fDphi/fNedges;
01266    param[1] /= TMath::Cos(0.5*divphi*TMath::DegToRad());
01267    param[0] *= param[0];
01268    param[1] *= param[1];
01269    if (TGeoShape::IsSameWithinTolerance(fDphi,360)) {
01270       param[2] = 0.;
01271       param[3] = 360.;
01272       return;
01273    }   
01274    param[2] = (fPhi1<0)?(fPhi1+360.):fPhi1;     // Phi1
01275    param[3] = param[2]+fDphi;                   // Phi2
01276 }   
01277 
01278 //_____________________________________________________________________________
01279 void TGeoPgon::InspectShape() const
01280 {
01281 // Inspect the PGON parameters.
01282    printf("*** Shape %s: TGeoPgon ***\n", GetName());
01283    printf("    Nedges = %i\n", fNedges);
01284    TGeoPcon::InspectShape();
01285 }
01286 
01287 //_____________________________________________________________________________
01288 TBuffer3D *TGeoPgon::MakeBuffer3D() const
01289 {
01290    // Creates a TBuffer3D describing *this* shape.
01291    // Coordinates are in local reference frame.
01292 
01293    const Int_t n = GetNsegments()+1;
01294    Int_t nz = GetNz();
01295    if (nz < 2) return 0;
01296    Int_t nbPnts = nz*2*n;
01297    if (nbPnts <= 0) return 0;
01298    Double_t dphi = GetDphi();
01299    Bool_t specialCase = kFALSE;
01300    if (TGeoShape::IsSameWithinTolerance(dphi,360)) specialCase = kTRUE;
01301    Int_t nbSegs = 4*(nz*n-1+(specialCase == kTRUE));
01302    Int_t nbPols = 2*(nz*n-1+(specialCase == kTRUE));
01303 
01304    TBuffer3D* buff = new TBuffer3D(TBuffer3DTypes::kGeneric,
01305                                    nbPnts, 3*nbPnts, nbSegs, 3*nbSegs, nbPols, 6*nbPols);      
01306    if (buff)
01307    {
01308       SetPoints(buff->fPnts);
01309       SetSegsAndPols(*buff);
01310    }
01311 
01312    return buff;
01313 }
01314 
01315 //_____________________________________________________________________________
01316 void TGeoPgon::SetSegsAndPols(TBuffer3D &buff) const
01317 {
01318 // Fill TBuffer3D structure for segments and polygons.
01319    Int_t i, j;
01320    const Int_t n = GetNsegments()+1;
01321    Int_t nz = GetNz();
01322    if (nz < 2) return;
01323    Int_t nbPnts = nz*2*n;
01324    if (nbPnts <= 0) return;
01325    Double_t dphi = GetDphi();
01326    Bool_t specialCase = kFALSE;
01327    if (TGeoShape::IsSameWithinTolerance(dphi,360)) specialCase = kTRUE;
01328    Int_t c = GetBasicColor();
01329 
01330    Int_t indx, indx2, k;
01331    indx = indx2 = 0;
01332 
01333    //inside & outside circles, number of segments: 2*nz*(n-1)
01334    //             special case number of segments: 2*nz*n
01335    for (i = 0; i < nz*2; i++) {
01336       indx2 = i*n;
01337       for (j = 1; j < n; j++) {
01338          buff.fSegs[indx++] = c;
01339          buff.fSegs[indx++] = indx2+j-1;
01340          buff.fSegs[indx++] = indx2+j;
01341       }
01342       if (specialCase) {
01343          buff.fSegs[indx++] = c;
01344          buff.fSegs[indx++] = indx2+j-1;
01345          buff.fSegs[indx++] = indx2;
01346       }
01347    }
01348 
01349    //bottom & top lines, number of segments: 2*n
01350    for (i = 0; i < 2; i++) {
01351       indx2 = i*(nz-1)*2*n;
01352       for (j = 0; j < n; j++) {
01353          buff.fSegs[indx++] = c;
01354          buff.fSegs[indx++] = indx2+j;
01355          buff.fSegs[indx++] = indx2+n+j;
01356       }
01357    }
01358 
01359    //inside & outside cylinders, number of segments: 2*(nz-1)*n
01360    for (i = 0; i < (nz-1); i++) {
01361       //inside cylinder
01362       indx2 = i*n*2;
01363       for (j = 0; j < n; j++) {
01364          buff.fSegs[indx++] = c+2;
01365          buff.fSegs[indx++] = indx2+j;
01366          buff.fSegs[indx++] = indx2+n*2+j;
01367       }
01368       //outside cylinder
01369       indx2 = i*n*2+n;
01370       for (j = 0; j < n; j++) {
01371          buff.fSegs[indx++] = c+3;
01372          buff.fSegs[indx++] = indx2+j;
01373          buff.fSegs[indx++] = indx2+n*2+j;
01374       }
01375    }
01376 
01377    //left & right sections, number of segments: 2*(nz-2)
01378    //          special case number of segments: 0
01379    if (!specialCase) {
01380       for (i = 1; i < (nz-1); i++) {
01381          for (j = 0; j < 2; j++) {
01382             buff.fSegs[indx++] = c;
01383             buff.fSegs[indx++] =  2*i    * n + j*(n-1);
01384             buff.fSegs[indx++] = (2*i+1) * n + j*(n-1);
01385          }
01386       }
01387    }
01388 
01389    Int_t m = n - 1 + (specialCase == kTRUE);
01390    indx = 0;
01391 
01392    //bottom & top, number of polygons: 2*(n-1)
01393    // special case number of polygons: 2*n
01394    i = 0;
01395    for (j = 0; j < n-1; j++) {
01396       buff.fPols[indx++] = c+3;
01397       buff.fPols[indx++] = 4;
01398       buff.fPols[indx++] = 2*nz*m+i*n+j;
01399       buff.fPols[indx++] = i*(nz*2-2)*m+m+j;
01400       buff.fPols[indx++] = 2*nz*m+i*n+j+1;
01401       buff.fPols[indx++] = i*(nz*2-2)*m+j;
01402    }
01403    if (specialCase) {
01404       buff.fPols[indx++] = c+3;
01405       buff.fPols[indx++] = 4;
01406       buff.fPols[indx++] = 2*nz*m+i*n+j;
01407       buff.fPols[indx++] = i*(nz*2-2)*m+m+j;
01408       buff.fPols[indx++] = 2*nz*m+i*n;
01409       buff.fPols[indx++] = i*(nz*2-2)*m+j;
01410    }
01411    i = 1;
01412    for (j = 0; j < n-1; j++) {
01413       buff.fPols[indx++] = c+3;
01414       buff.fPols[indx++] = 4;
01415       buff.fPols[indx++] = i*(nz*2-2)*m+j;
01416       buff.fPols[indx++] = 2*nz*m+i*n+j+1;
01417       buff.fPols[indx++] = i*(nz*2-2)*m+m+j;
01418       buff.fPols[indx++] = 2*nz*m+i*n+j;
01419    }
01420    if (specialCase) {
01421       buff.fPols[indx++] = c+3;
01422       buff.fPols[indx++] = 4;
01423       buff.fPols[indx++] = i*(nz*2-2)*m+j;
01424       buff.fPols[indx++] = 2*nz*m+i*n;
01425       buff.fPols[indx++] = i*(nz*2-2)*m+m+j;
01426       buff.fPols[indx++] = 2*nz*m+i*n+j;
01427    }
01428 
01429    //inside & outside, number of polygons: (nz-1)*2*(n-1)
01430    for (k = 0; k < (nz-1); k++) {
01431       i = 0;
01432          for (j = 0; j < n-1; j++) {
01433             buff.fPols[indx++] = c+i;
01434             buff.fPols[indx++] = 4;
01435             buff.fPols[indx++] = nz*2*m+(2*k+i*1+2)*n+j+1;
01436             buff.fPols[indx++] = (2*k+i*1+2)*m+j;
01437             buff.fPols[indx++] = nz*2*m+(2*k+i*1+2)*n+j;
01438             buff.fPols[indx++] = (2*k+i*1)*m+j;
01439          }
01440          if (specialCase) {
01441             buff.fPols[indx++] = c+i;
01442             buff.fPols[indx++] = 4;
01443             buff.fPols[indx++] = nz*2*m+(2*k+i*1+2)*n;
01444             buff.fPols[indx++] = (2*k+i*1+2)*m+j;
01445             buff.fPols[indx++] = nz*2*m+(2*k+i*1+2)*n+j;
01446             buff.fPols[indx++] = (2*k+i*1)*m+j;
01447          }
01448       i = 1;
01449          for (j = 0; j < n-1; j++) {
01450             buff.fPols[indx++] = c+i;
01451             buff.fPols[indx++] = 4;
01452             buff.fPols[indx++] = (2*k+i*1)*m+j;
01453             buff.fPols[indx++] = nz*2*m+(2*k+i*1+2)*n+j;
01454             buff.fPols[indx++] = (2*k+i*1+2)*m+j;
01455             buff.fPols[indx++] = nz*2*m+(2*k+i*1+2)*n+j+1;
01456          }
01457          if (specialCase) {
01458             buff.fPols[indx++] = c+i;
01459             buff.fPols[indx++] = 4;
01460             buff.fPols[indx++] = (2*k+i*1)*m+j;
01461             buff.fPols[indx++] = nz*2*m+(2*k+i*1+2)*n+j;
01462             buff.fPols[indx++] = (2*k+i*1+2)*m+j;
01463             buff.fPols[indx++] = nz*2*m+(2*k+i*1+2)*n;
01464          }
01465    }
01466 
01467    //left & right sections, number of polygons: 2*(nz-1)
01468    //          special case number of polygons: 0
01469    if (!specialCase) {
01470       indx2 = nz*2*(n-1);
01471       for (k = 0; k < (nz-1); k++) {
01472          buff.fPols[indx++] = c+2;
01473          buff.fPols[indx++] = 4;
01474          buff.fPols[indx++] = k==0 ? indx2 : indx2+2*nz*n+2*(k-1);
01475          buff.fPols[indx++] = indx2+2*(k+1)*n;
01476          buff.fPols[indx++] = indx2+2*nz*n+2*k;
01477          buff.fPols[indx++] = indx2+(2*k+3)*n;
01478             
01479          buff.fPols[indx++] = c+2;
01480          buff.fPols[indx++] = 4;
01481          buff.fPols[indx++] = k==0 ? indx2+n-1 : indx2+2*nz*n+2*(k-1)+1;//a
01482          buff.fPols[indx++] = indx2+(2*k+3)*n+n-1;//d
01483          buff.fPols[indx++] = indx2+2*nz*n+2*k+1;//c
01484          buff.fPols[indx++] = indx2+2*(k+1)*n+n-1;//b
01485       }
01486       buff.fPols[indx-8] = indx2+n;
01487       buff.fPols[indx-2] = indx2+2*n-1;
01488    }
01489 }
01490 
01491 //_____________________________________________________________________________
01492 Double_t TGeoPgon::Rpg(Double_t z, Int_t ipl, Bool_t inner, Double_t &a, Double_t &b) const
01493 {
01494 // Computes projected pgon radius (inner or outer) corresponding to a given Z
01495 // value. Fills corresponding coefficients of:
01496 //   Rpg(z) = a + b*z
01497 // Note: ipl must be in range [0,fNz-2]
01498    Double_t rpg;
01499    if (ipl<0 || ipl>fNz-2) {
01500       Fatal("Rpg", "Plane index parameter ipl=%i out of range\n", ipl);
01501       return 0;
01502    }   
01503    Double_t dz = fZ[ipl+1] - fZ[ipl];
01504    if (dz<TGeoShape::Tolerance()) {
01505       // radius-changing region
01506       rpg = (inner)?TMath::Min(fRmin[ipl],fRmin[ipl+1]):TMath::Max(fRmax[ipl],fRmax[ipl+1]);
01507       a = rpg;
01508       b = 0.;
01509       return rpg;
01510    }   
01511    Double_t r1=0, r2=0;
01512    if (inner) {
01513       r1 = fRmin[ipl];
01514       r2 = fRmin[ipl+1];
01515    } else {
01516       r1 = fRmax[ipl];
01517       r2 = fRmax[ipl+1];
01518    }
01519    Double_t dzinv = 1./dz;
01520    a = (r1*fZ[ipl+1]-r2*fZ[ipl])*dzinv;
01521    b = (r2-r1)*dzinv;
01522    return (a+b*z);
01523 }         
01524 
01525 //_____________________________________________________________________________
01526 Double_t TGeoPgon::Rproj(Double_t z, Double_t *point, Double_t *dir, Double_t cphi, Double_t sphi, Double_t &a, Double_t &b) const
01527 {
01528 // Computes projected distance at a given Z for a given ray inside a given sector 
01529 // and fills coefficients:
01530 //   Rproj = a + b*z
01531    if (TMath::Abs(dir[2])<1E-8) {
01532       a =  b = TGeoShape::Big();
01533       return TGeoShape::Big();
01534    }
01535    Double_t invdirz = 1./dir[2];
01536    a = ((point[0]*dir[2]-point[2]*dir[0])*cphi+(point[1]*dir[2]-point[2]*dir[1])*sphi)*invdirz;
01537    b = (dir[0]*cphi+dir[1]*sphi)*invdirz;
01538    return (a+b*z);   
01539 }   
01540 
01541 //_____________________________________________________________________________
01542 Double_t TGeoPgon::SafetyToSegment(Double_t *point, Int_t ipl, Int_t iphi, Bool_t in, Double_t safphi, Double_t safmin) const
01543 {
01544 // Compute safety from POINT to segment between planes ipl, ipl+1 within safmin.
01545    Double_t saf[3];
01546    Double_t safe;
01547    Int_t i;
01548    Double_t r,rpgon, ta, calf;
01549    if (ipl<0 || ipl>fNz-2) return (safmin+1.); // error in input plane
01550 // Get info about segment.
01551    Double_t dz = fZ[ipl+1]-fZ[ipl];
01552    if (dz<1E-9) return 1E9; // skip radius-changing segment
01553    Double_t znew = point[2] - 0.5*(fZ[ipl]+fZ[ipl+1]);
01554    saf[0] = 0.5*dz - TMath::Abs(znew);
01555    if (-saf[0]>safmin) return TGeoShape::Big(); // means: stop checking further segments
01556    Double_t rmin1 = fRmin[ipl];
01557    Double_t rmax1 = fRmax[ipl];
01558    Double_t rmin2 = fRmin[ipl+1];
01559    Double_t rmax2 = fRmax[ipl+1];
01560    Double_t divphi = fDphi/fNedges;
01561    if (iphi<0) {
01562       Double_t f = 1./TMath::Cos(0.5*divphi*TMath::DegToRad());
01563       rmax1 *= f;
01564       rmax2 *= f;
01565       r = TMath::Sqrt(point[0]*point[0]+point[1]*point[1]);
01566       Double_t ro1 = 0.5*(rmin1+rmin2);
01567       Double_t tg1 = (rmin2-rmin1)/dz;
01568       Double_t cr1 = 1./TMath::Sqrt(1.+tg1*tg1);
01569       Double_t ro2 = 0.5*(rmax1+rmax2);
01570       Double_t tg2 = (rmax2-rmax1)/dz;
01571       Double_t cr2 = 1./TMath::Sqrt(1.+tg2*tg2);
01572       Double_t rin = tg1*znew+ro1;
01573       Double_t rout = tg2*znew+ro2;
01574       saf[1] = (ro1>0)?((r-rin)*cr1):TGeoShape::Big();
01575       saf[2] = (rout-r)*cr2;
01576       for (i=0; i<3; i++) saf[i]=-saf[i];
01577       safe = saf[TMath::LocMax(3,saf)];
01578       safe = TMath::Max(safe, safphi);
01579       if (safe<0) safe = 0;
01580       return safe;
01581    }
01582    Double_t ph0 = (fPhi1+divphi*(iphi+0.5))*TMath::DegToRad();
01583    r = point[0]*TMath::Cos(ph0)+point[1]*TMath::Sin(ph0);
01584    if (rmin1+rmin2>1E-10) {
01585       ta = (rmin2-rmin1)/dz;
01586       calf = 1./TMath::Sqrt(1+ta*ta);
01587       rpgon = rmin1 + (point[2]-fZ[ipl])*ta;
01588       saf[1] = (r-rpgon)*calf;
01589    } else {
01590       saf[1] = TGeoShape::Big();
01591    }   
01592    ta = (rmax2-rmax1)/dz;
01593    calf = 1./TMath::Sqrt(1+ta*ta);
01594    rpgon = rmax1 + (point[2]-fZ[ipl])*ta;
01595    saf[2] = (rpgon-r)*calf;
01596    if (in) {
01597       safe = saf[TMath::LocMin(3,saf)];
01598       safe = TMath::Min(safe, safphi);
01599    } else {          
01600       for (i=0; i<3; i++) saf[i]=-saf[i];
01601       safe = saf[TMath::LocMax(3,saf)];
01602       safe = TMath::Max(safe, safphi);
01603    }
01604    if (safe<0) safe=0;
01605    return safe;
01606 }      
01607 
01608 //_____________________________________________________________________________
01609 Double_t TGeoPgon::Safety(Double_t *point, Bool_t in) const
01610 {
01611 // computes the closest distance from given point to this shape, according
01612 // to option. The matching point on the shape is stored in spoint.
01613    Double_t safmin, saftmp, safphi;
01614    Double_t dz;
01615    Int_t ipl, iplane, iphi;
01616    LocatePhi(point, iphi);
01617    safphi = TGeoShape::SafetyPhi(point,in,fPhi1, fPhi1+fDphi);
01618    if (in) {
01619    //---> point is inside pgon
01620       ipl = TMath::BinarySearch(fNz, fZ, point[2]);
01621       if (ipl==(fNz-1)) return 0;   // point on last Z boundary
01622       if (ipl<0) return 0;          // point on first Z boundary
01623       dz = 0.5*(fZ[ipl+1]-fZ[ipl]);
01624       if (dz<1E-8) return 0;
01625       // Check safety for current segment
01626       safmin = SafetyToSegment(point, ipl, iphi, in, safphi);
01627       if (safmin>1E10) {
01628          //  something went wrong - point is not inside current segment
01629          return TGeoShape::Big();
01630       }
01631       if (safmin<1E-6) return TMath::Abs(safmin); // point on radius-changing plane
01632       // check increasing iplanes
01633       iplane = ipl+1;
01634       saftmp = 0.;
01635       while ((iplane<fNz-1) && saftmp<1E10) {
01636          saftmp = TMath::Abs(SafetyToSegment(point,iplane,iphi,kFALSE,safphi,safmin));
01637          if (saftmp<safmin) safmin=saftmp;
01638          iplane++;
01639       }   
01640       // now decreasing nplanes
01641       iplane = ipl-1;
01642       saftmp = 0.;
01643       while ((iplane>=0) && saftmp<1E10) {
01644          saftmp = TMath::Abs(SafetyToSegment(point,iplane,iphi,kFALSE,safphi,safmin));
01645          if (saftmp<safmin) safmin=saftmp;
01646          iplane--;
01647       }   
01648       return safmin;
01649    }   
01650    //---> point is outside pgon
01651    ipl = TMath::BinarySearch(fNz, fZ, point[2]);
01652    if (ipl<0) ipl=0;
01653    else if (ipl==fNz-1) ipl=fNz-2;
01654    dz = 0.5*(fZ[ipl+1]-fZ[ipl]);
01655    if (dz<1E-8) {
01656       ipl++;
01657       if (ipl>fNz-2) return 0.;  // invalid last section
01658       dz = 0.5*(fZ[ipl+1]-fZ[ipl]);
01659    }   
01660    // Check safety for current segment
01661    safmin = SafetyToSegment(point, ipl,iphi,kFALSE,safphi);
01662    if (safmin<1E-6) return TMath::Abs(safmin); // point on radius-changing plane
01663    saftmp = 0.;
01664    // check increasing iplanes
01665    iplane = ipl+1;
01666    saftmp = 0.;
01667    while ((iplane<fNz-1) && saftmp<1E10) {
01668       saftmp = TMath::Abs(SafetyToSegment(point,iplane,iphi,kFALSE,safphi,safmin));
01669       if (saftmp<safmin) safmin=saftmp;
01670       iplane++;
01671    }   
01672    // now decreasing nplanes
01673    iplane = ipl-1;
01674    saftmp = 0.;
01675    while ((iplane>=0) && saftmp<1E10) {
01676       saftmp = TMath::Abs(SafetyToSegment(point,iplane,iphi, kFALSE,safphi,safmin));
01677       if (saftmp<safmin) safmin=saftmp;
01678       iplane--;
01679    }   
01680    return safmin;
01681 }
01682 
01683 //_____________________________________________________________________________
01684 void TGeoPgon::SavePrimitive(ostream &out, Option_t * /*option*/ /*= ""*/)
01685 {
01686 // Save a primitive as a C++ statement(s) on output stream "out".
01687    if (TObject::TestBit(kGeoSavePrimitive)) return;
01688    out << "   // Shape: " << GetName() << " type: " << ClassName() << endl;
01689    out << "   phi1    = " << fPhi1 << ";" << endl;
01690    out << "   dphi    = " << fDphi << ";" << endl;
01691    out << "   nedges = " << fNedges << ";" << endl;
01692    out << "   nz      = " << fNz << ";" << endl;
01693    out << "   TGeoPgon *pgon = new TGeoPgon(\"" << GetName() << "\",phi1,dphi,nedges,nz);" << endl;
01694    for (Int_t i=0; i<fNz; i++) {
01695       out << "      z     = " << fZ[i] << ";" << endl;
01696       out << "      rmin  = " << fRmin[i] << ";" << endl;
01697       out << "      rmax  = " << fRmax[i] << ";" << endl;
01698       out << "   pgon->DefineSection(" << i << ", z,rmin,rmax);" << endl;
01699    }
01700    out << "   TGeoShape *" << GetPointerName() << " = pgon;" << endl;
01701    TObject::SetBit(TGeoShape::kGeoSavePrimitive);
01702 }
01703 
01704 //_____________________________________________________________________________
01705 void TGeoPgon::SetDimensions(Double_t *param)
01706 {
01707 // Set PGON dimensions starting from an array.
01708    fPhi1    = param[0];
01709    fDphi    = param[1];
01710    fNedges  = (Int_t)param[2];
01711    fNz      = (Int_t)param[3];
01712    if (fNz<2) {
01713       Error("SetDimensions","Pgon %s: Number of Z sections must be > 2", GetName());
01714       return;
01715    } 
01716    if (fRmin) delete [] fRmin;  
01717    if (fRmax) delete [] fRmax;  
01718    if (fZ) delete [] fZ;  
01719    fRmin = new Double_t [fNz];
01720    fRmax = new Double_t [fNz];
01721    fZ    = new Double_t [fNz];
01722    memset(fRmin, 0, fNz*sizeof(Double_t));
01723    memset(fRmax, 0, fNz*sizeof(Double_t));
01724    memset(fZ, 0, fNz*sizeof(Double_t));
01725    for (Int_t i=0; i<fNz; i++) 
01726       DefineSection(i, param[4+3*i], param[5+3*i], param[6+3*i]);
01727 }   
01728 
01729 //_____________________________________________________________________________
01730 void TGeoPgon::SetPoints(Double_t *points) const
01731 {
01732 // create polygone mesh points
01733    Double_t phi, dphi;
01734    Int_t n = fNedges + 1;
01735    dphi = fDphi/(n-1);
01736    Double_t factor = 1./TMath::Cos(TMath::DegToRad()*dphi/2);
01737    Int_t i, j;
01738    Int_t indx = 0;
01739 
01740    if (points) {
01741       for (i = 0; i < fNz; i++) {
01742          for (j = 0; j < n; j++) {
01743             phi = (fPhi1+j*dphi)*TMath::DegToRad();
01744             points[indx++] = factor * fRmin[i] * TMath::Cos(phi);
01745             points[indx++] = factor * fRmin[i] * TMath::Sin(phi);
01746             points[indx++] = fZ[i];
01747          }
01748          for (j = 0; j < n; j++) {
01749             phi = (fPhi1+j*dphi)*TMath::DegToRad();
01750             points[indx++] = factor * fRmax[i] * TMath::Cos(phi);
01751             points[indx++] = factor * fRmax[i] * TMath::Sin(phi);
01752             points[indx++] = fZ[i];
01753          }
01754       }
01755    }
01756 }
01757 
01758 //_____________________________________________________________________________
01759 void TGeoPgon::SetPoints(Float_t *points) const
01760 {
01761 // create polygone mesh points
01762    Double_t phi, dphi;
01763    Int_t n = fNedges + 1;
01764    dphi = fDphi/(n-1);
01765    Double_t factor = 1./TMath::Cos(TMath::DegToRad()*dphi/2);
01766    Int_t i, j;
01767    Int_t indx = 0;
01768 
01769    if (points) {
01770       for (i = 0; i < fNz; i++) {
01771          for (j = 0; j < n; j++) {
01772             phi = (fPhi1+j*dphi)*TMath::DegToRad();
01773             points[indx++] = factor * fRmin[i] * TMath::Cos(phi);
01774             points[indx++] = factor * fRmin[i] * TMath::Sin(phi);
01775             points[indx++] = fZ[i];
01776          }
01777          for (j = 0; j < n; j++) {
01778             phi = (fPhi1+j*dphi)*TMath::DegToRad();
01779             points[indx++] = factor * fRmax[i] * TMath::Cos(phi);
01780             points[indx++] = factor * fRmax[i] * TMath::Sin(phi);
01781             points[indx++] = fZ[i];
01782          }
01783       }
01784    }
01785 }
01786 
01787 //_____________________________________________________________________________
01788 void TGeoPgon::GetMeshNumbers(Int_t &nvert, Int_t &nsegs, Int_t &npols) const
01789 {
01790 // Returns numbers of vertices, segments and polygons composing the shape mesh.
01791    Int_t n = fNedges+1;
01792    Int_t nz = GetNz();
01793    nvert = nz*2*n;
01794    Bool_t specialCase = (TGeoShape::IsSameWithinTolerance(GetDphi(),360));
01795    nsegs = 4*(nz*n-1+(specialCase == kTRUE));
01796    npols = 2*(nz*n-1+(specialCase == kTRUE));
01797 }
01798 
01799 //_____________________________________________________________________________
01800 Int_t TGeoPgon::GetNmeshVertices() const
01801 {
01802 // Return number of vertices of the mesh representation
01803    Int_t n = fNedges+1;
01804    Int_t numPoints = fNz*2*n;
01805    return numPoints;
01806 }   
01807 
01808 //_____________________________________________________________________________
01809 void TGeoPgon::Sizeof3D() const
01810 {
01811 ///// fill size of this 3-D object
01812 ///    TVirtualGeoPainter *painter = gGeoManager->GetGeomPainter();
01813 ///    if (!painter) return;
01814 ///    Int_t n;
01815 ///
01816 ///    n = fNedges+1;
01817 ///
01818 ///    Int_t numPoints = fNz*2*n;
01819 ///    Int_t numSegs   = 4*(fNz*n-1+(fDphi == 360));
01820 ///    Int_t numPolys  = 2*(fNz*n-1+(fDphi == 360));
01821 ///    painter->AddSize3D(numPoints, numSegs, numPolys);
01822 }
01823 
01824 //_____________________________________________________________________________
01825 const TBuffer3D & TGeoPgon::GetBuffer3D(Int_t reqSections, Bool_t localFrame) const
01826 {
01827 // Fills a static 3D buffer and returns a reference.
01828    static TBuffer3D buffer(TBuffer3DTypes::kGeneric);
01829 
01830    TGeoBBox::FillBuffer3D(buffer, reqSections, localFrame);
01831 
01832    if (reqSections & TBuffer3D::kRawSizes) {
01833       const Int_t n = GetNsegments()+1;
01834       Int_t nz = GetNz();
01835       Int_t nbPnts = nz*2*n;
01836       if (nz >= 2 && nbPnts > 0) {
01837          Bool_t specialCase = (TGeoShape::IsSameWithinTolerance(GetDphi(),360));
01838          Int_t nbSegs = 4*(nz*n-1+(specialCase == kTRUE));
01839          Int_t nbPols = 2*(nz*n-1+(specialCase == kTRUE));
01840          if (buffer.SetRawSizes(nbPnts, 3*nbPnts, nbSegs, 3*nbSegs, nbPols, 6*nbPols)) {
01841             buffer.SetSectionsValid(TBuffer3D::kRawSizes);
01842          }
01843       }
01844    }
01845    // TODO: Push down to TGeoShape?? Wuld have to do raw sizes set first..
01846    // can rest of TGeoShape be defered until after this?
01847    if ((reqSections & TBuffer3D::kRaw) && buffer.SectionsValid(TBuffer3D::kRawSizes)) {
01848       SetPoints(buffer.fPnts);
01849       if (!buffer.fLocalFrame) {
01850          TransformPoints(buffer.fPnts, buffer.NbPnts());
01851       }
01852 
01853       SetSegsAndPols(buffer);      
01854       buffer.SetSectionsValid(TBuffer3D::kRaw);
01855    }
01856       
01857    return buffer;
01858 }

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