TGeoHype.cxx

Go to the documentation of this file.
00001 // @(#)root/geom:$Id: TGeoHype.cxx 34209 2010-06-30 09:35:28Z brun $
00002 // Author: Mihaela Gheata   20/11/04
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 
00013 #include "Riostream.h"
00014 
00015 #include "TGeoManager.h"
00016 #include "TGeoVolume.h"
00017 #include "TVirtualGeoPainter.h"
00018 #include "TGeoHype.h"
00019 #include "TVirtualPad.h"
00020 #include "TBuffer3D.h"
00021 #include "TBuffer3DTypes.h"
00022 #include "TMath.h"
00023 
00024 //_____________________________________________________________________________
00025 // TGeoHype - Hyperboloid class defined by 5 parameters. Bounded by:
00026 //            - Two z planes at z=+/-dz
00027 //            - Inner and outer lateral surfaces. These represent the surfaces 
00028 //              described by the revolution of 2 hyperbolas about the Z axis:
00029 //               r^2 - (t*z)^2 = a^2
00030 //
00031 //            r = distance between hyperbola and Z axis at coordinate z
00032 //            t = tangent of the stereo angle (angle made by hyperbola
00033 //                asimptotic lines and Z axis). t=0 means cylindrical surface.
00034 //            a = distance between hyperbola and Z axis at z=0
00035 //
00036 //          The inner hyperbolic surface is described by:
00037 //              r^2 - (tin*z)^2 = rin^2 
00038 //           - absence of the inner surface (filled hyperboloid can be forced 
00039 //             by rin=0 and sin=0
00040 //          The outer hyperbolic surface is described by:
00041 //              r^2 - (tout*z)^2 = rout^2
00042 //  TGeoHype parameters: dz[cm], rin[cm], sin[deg], rout[cm], sout[deg].
00043 //    MANDATORY conditions:
00044 //           - rin < rout
00045 //           - rout > 0
00046 //           - rin^2 + (tin*dz)^2 > rout^2 + (tout*dz)^2
00047 //    SUPPORTED CASES:
00048 //           - rin = 0, tin != 0     => inner surface conical
00049 //           - tin=0 AND/OR tout=0   => corresponding surface(s) cyllindrical
00050 //             e.g. tin=0 AND tout=0 => shape becomes a tube with: rmin,rmax,dz
00051 //    
00052 //_____________________________________________________________________________
00053 
00054 
00055 ClassImp(TGeoHype)
00056    
00057 //_____________________________________________________________________________
00058 TGeoHype::TGeoHype()
00059 {
00060 // Default constructor
00061    SetShapeBit(TGeoShape::kGeoHype);
00062    fStIn = 0.;
00063    fStOut = 0.;
00064    fTin = 0.;
00065    fTinsq = 0.;
00066    fTout = 0.;
00067    fToutsq = 0.;
00068 }   
00069 
00070 
00071 //_____________________________________________________________________________
00072 TGeoHype::TGeoHype(Double_t rin, Double_t stin, Double_t rout, Double_t stout, Double_t dz)
00073          :TGeoTube(rin, rout, dz)
00074 {
00075 // Constructor specifying hyperboloid parameters.
00076    SetShapeBit(TGeoShape::kGeoHype);
00077    SetHypeDimensions(rin, stin, rout, stout, dz);
00078    // dz<0 can be used to force dz of hyperboloid fit the container volume 
00079    if (fDz<0) SetShapeBit(kGeoRunTimeShape); 
00080    ComputeBBox();
00081 }
00082 //_____________________________________________________________________________
00083 TGeoHype::TGeoHype(const char *name,Double_t rin, Double_t stin, Double_t rout, Double_t stout, Double_t dz)
00084          :TGeoTube(name, rin, rout, dz)
00085 {
00086 // Constructor specifying parameters and name.
00087    SetShapeBit(TGeoShape::kGeoHype);
00088    SetHypeDimensions(rin, stin, rout, stout, dz);
00089    // dz<0 can be used to force dz of hyperboloid fit the container volume 
00090    if (fDz<0) SetShapeBit(kGeoRunTimeShape); 
00091    ComputeBBox();
00092 }
00093 
00094 //_____________________________________________________________________________
00095 TGeoHype::TGeoHype(Double_t *param)
00096          :TGeoTube(param[1],param[3],param[0])
00097 {
00098 // Default constructor specifying a list of parameters
00099 // param[0] = dz
00100 // param[1] = rin
00101 // param[2] = stin
00102 // param[3] = rout
00103 // param[4] = stout
00104    SetShapeBit(TGeoShape::kGeoHype);
00105    SetDimensions(param);
00106    // dz<0 can be used to force dz of hyperboloid fit the container volume 
00107    if (fDz<0) SetShapeBit(kGeoRunTimeShape); 
00108    ComputeBBox();
00109 }
00110 
00111 //_____________________________________________________________________________
00112 TGeoHype::~TGeoHype()
00113 {
00114 // destructor
00115 }
00116 
00117 //_____________________________________________________________________________
00118 Double_t TGeoHype::Capacity() const
00119 {
00120 // Computes capacity of the shape in [length^3]
00121    Double_t capacity = 2.*TMath::Pi()*fDz*(fRmax*fRmax-fRmin*fRmin) +
00122                        (2.*TMath::Pi()/3.)*fDz*fDz*fDz*(fToutsq-fTinsq);
00123    return capacity;                    
00124 }   
00125 
00126 //_____________________________________________________________________________   
00127 void TGeoHype::ComputeBBox()
00128 {
00129 // Compute bounding box of the hyperboloid
00130    if (fRmin<0.) {
00131       Warning("ComputeBBox", "Shape %s has invalid rmin=%g ! SET TO 0.", GetName(),fRmin);
00132       fRmin = 0.;
00133    }
00134    if ((fRmin>fRmax) || (fRmin*fRmin+fTinsq*fDz*fDz > fRmax*fRmax+fToutsq*fDz*fDz)) {
00135       SetShapeBit(kGeoInvalidShape);
00136       Error("ComputeBBox", "Shape %s hyperbolic surfaces are malformed: rin=%g, stin=%g, rout=%g, stout=%g",
00137              GetName(), fRmin, fStIn, fRmax, fStOut);
00138       return;       
00139    }   
00140    
00141    fDX = fDY = TMath::Sqrt(RadiusHypeSq(fDz, kFALSE));
00142    fDZ = fDz;
00143 }   
00144 
00145 //_____________________________________________________________________________   
00146 void TGeoHype::ComputeNormal(Double_t *point, Double_t *dir, Double_t *norm)
00147 {
00148 // Compute normal to closest surface from POINT. 
00149    Double_t saf[3];
00150    Double_t rsq = point[0]*point[0]+point[1]*point[1];
00151    Double_t r = TMath::Sqrt(rsq);
00152    Double_t rin = (HasInner())?(TMath::Sqrt(RadiusHypeSq(point[2],kTRUE))):0.;
00153    Double_t rout = TMath::Sqrt(RadiusHypeSq(point[2],kFALSE));
00154    saf[0] = TMath::Abs(fDz-TMath::Abs(point[2])); 
00155    saf[1] = (HasInner())?TMath::Abs(rin-r):TGeoShape::Big();
00156    saf[2] = TMath::Abs(rout-r);
00157    Int_t i = TMath::LocMin(3,saf);
00158    if (i==0 || r<1.E-10) {
00159       norm[0] = norm[1] = 0.;
00160       norm[2] = TMath::Sign(1.,dir[2]);
00161       return;
00162    }
00163    Double_t t = (i==1)?fTinsq:fToutsq;;
00164    t *= -point[2]/r;
00165    Double_t ct = TMath::Sqrt(1./(1.+t*t));
00166    Double_t st = t * ct;
00167    Double_t phi = TMath::ATan2(point[1], point[0]);
00168    Double_t cphi = TMath::Cos(phi);
00169    Double_t sphi = TMath::Sin(phi);
00170    
00171    norm[0] = ct*cphi;
00172    norm[1] = ct*sphi;
00173    norm[2] = st;
00174    if (norm[0]*dir[0]+norm[1]*dir[1]+norm[2]*dir[2]<0) {
00175       norm[0] = -norm[0];
00176       norm[1] = -norm[1];
00177       norm[2] = -norm[2];
00178    }   
00179 }
00180 
00181 //_____________________________________________________________________________
00182 Bool_t TGeoHype::Contains(Double_t *point) const
00183 {
00184 // test if point is inside this tube
00185    if (TMath::Abs(point[2]) > fDz) return kFALSE;
00186    Double_t r2 = point[0]*point[0]+point[1]*point[1];
00187    Double_t routsq = RadiusHypeSq(point[2], kFALSE);
00188    if (r2>routsq) return kFALSE;
00189    if (!HasInner()) return kTRUE;
00190    Double_t rinsq = RadiusHypeSq(point[2], kTRUE);
00191    if (r2<rinsq) return kFALSE;
00192    return kTRUE;
00193 }
00194 
00195 //_____________________________________________________________________________
00196 Int_t TGeoHype::DistancetoPrimitive(Int_t px, Int_t py)
00197 {
00198 // compute closest distance from point px,py to each corner
00199    Int_t numPoints = GetNmeshVertices();
00200    return ShapeDistancetoPrimitive(numPoints, px, py);
00201 }
00202 
00203 //_____________________________________________________________________________
00204 Double_t TGeoHype::DistFromInside(Double_t *point, Double_t *dir, Int_t iact, Double_t step, Double_t *safe) const
00205 {
00206 // Compute distance from inside point to surface of the hyperboloid.
00207    if (iact<3 && safe) {
00208       *safe = Safety(point, kTRUE);
00209       if (iact==0) return TGeoShape::Big();
00210       if ((iact==1) && (*safe>step)) return TGeoShape::Big();
00211    }
00212    // compute distance to surface 
00213    // Do Z
00214    Double_t sz = TGeoShape::Big();
00215    if (dir[2]>0) { 
00216       sz = (fDz-point[2])/dir[2];
00217       if (sz<=0.) return 0.;      
00218    } else {
00219       if (dir[2]<0) {
00220          sz = -(fDz+point[2])/dir[2];
00221          if (sz<=0.) return 0.; 
00222       }
00223    }           
00224    
00225    
00226    // Do R
00227    Double_t srin = TGeoShape::Big();
00228    Double_t srout = TGeoShape::Big();
00229    Double_t sr;
00230    // inner and outer surfaces
00231    Double_t s[2];
00232    Int_t npos;
00233    npos = DistToHype(point, dir, s, kTRUE);
00234    if (npos) srin = s[0];
00235    npos = DistToHype(point, dir, s, kFALSE);
00236    if (npos) srout = s[0];
00237    sr = TMath::Min(srin, srout);
00238    return TMath::Min(sz,sr);
00239 }
00240 
00241 
00242 //_____________________________________________________________________________
00243 Double_t TGeoHype::DistFromOutside(Double_t *point, Double_t *dir, Int_t iact, Double_t step, Double_t *safe) const
00244 {
00245 // compute distance from outside point to surface of the hyperboloid.
00246    if (iact<3 && safe) {
00247       *safe = Safety(point, kFALSE);
00248       if (iact==0) return TGeoShape::Big();
00249       if ((iact==1) && (step<=*safe)) return TGeoShape::Big();
00250    }
00251 // Check if the bounding box is crossed within the requested distance
00252    Double_t sdist = TGeoBBox::DistFromOutside(point,dir, fDX, fDY, fDZ, fOrigin, step);
00253    if (sdist>=step) return TGeoShape::Big();
00254    // find distance to shape
00255    // Do Z
00256    Double_t xi, yi, zi;
00257    Double_t sz = TGeoShape::Big();
00258    if (TMath::Abs(point[2])>=fDz) { 
00259       // We might find Z plane crossing
00260       if ((point[2]*dir[2]) < 0) {
00261          // Compute distance to Z (always positive)
00262          sz = (TMath::Abs(point[2])-fDz)/TMath::Abs(dir[2]);
00263          // Extrapolate
00264          xi = point[0]+sz*dir[0];
00265          yi = point[1]+sz*dir[1];
00266          Double_t r2 = xi*xi + yi*yi;
00267          Double_t rmin2 = RadiusHypeSq(fDz, kTRUE);
00268          if (r2 >= rmin2) {
00269             Double_t rmax2 = RadiusHypeSq(fDz, kFALSE);
00270             if (r2 <= rmax2) return sz;
00271          }
00272       }
00273    }
00274    // We do not cross Z planes.
00275    Double_t sin = TGeoShape::Big();
00276    Double_t sout = TGeoShape::Big();
00277    Double_t s[2];
00278    Int_t npos;
00279    npos = DistToHype(point, dir, s, kTRUE);
00280    if (npos) {
00281       zi = point[2] + s[0]*dir[2];
00282       if (TMath::Abs(zi) <= fDz) sin = s[0];
00283       else if (npos==2) {
00284          zi = point[2] + s[1]*dir[2];
00285          if (TMath::Abs(zi) <= fDz) sin = s[1];
00286       }
00287    }      
00288    npos = DistToHype(point, dir, s, kFALSE);
00289    if (npos) {
00290       zi = point[2] + s[0]*dir[2]; 
00291       if (TMath::Abs(zi) <= fDz) sout = s[0];
00292       else if (npos==2) {
00293          zi = point[2] + s[1]*dir[2];
00294          if (TMath::Abs(zi) <= fDz) sout = s[1];
00295       }      
00296    }   
00297    return TMath::Min(sin, sout);
00298 }
00299 
00300 //_____________________________________________________________________________
00301 Int_t TGeoHype::DistToHype(Double_t *point, Double_t *dir, Double_t *s, Bool_t inner) const
00302 {
00303 // Compute distance from an arbitrary point to inner/outer surface of hyperboloid.
00304 // Returns number of positive solutions. S[2] contains the solutions.
00305    Double_t r0, t0, snext;
00306    if (inner) {
00307       if (!HasInner()) return 0;
00308       r0 = fRmin;
00309       t0 = fTinsq;
00310    } else {
00311       r0 = fRmax;
00312       t0 = fToutsq;
00313    }
00314    Double_t a = dir[0]*dir[0] + dir[1]*dir[1] - t0*dir[2]*dir[2];
00315    Double_t b = t0*point[2]*dir[2] - point[0]*dir[0] - point[1]*dir[1];
00316    Double_t c = point[0]*point[0] + point[1]*point[1] - t0*point[2]*point[2] - r0*r0;      
00317 
00318    if (TMath::Abs(a) < TGeoShape::Tolerance()) {
00319       if (TMath::Abs(b) < TGeoShape::Tolerance()) return 0;
00320       snext = 0.5*c/b;
00321       if (snext < 0.) return 0;
00322       s[0] = snext;
00323       return 1;
00324    }
00325    
00326    Double_t delta = b*b - a*c;
00327    Double_t ainv = 1./a;
00328    Int_t npos = 0;
00329    if (delta < 0.) return 0;
00330    delta = TMath::Sqrt(delta); 
00331    Double_t sone = TMath::Sign(1.,ainv);
00332    snext = (b - sone*delta)*ainv;
00333    if (snext >= 0.) s[npos++] = snext;
00334    snext = (b + sone*delta)*ainv;
00335    if (snext >= 0.) s[npos++] = snext;
00336    return npos;
00337 }
00338    
00339 //_____________________________________________________________________________
00340 TGeoVolume *TGeoHype::Divide(TGeoVolume * /*voldiv*/, const char *divname, Int_t /*iaxis*/, Int_t /*ndiv*/, 
00341                              Double_t /*start*/, Double_t /*step*/) 
00342 {
00343 // Cannot divide hyperboloids.
00344    Error("Divide", "Hyperboloids cannot be divided. Division volume %s not created", divname);
00345    return 0;
00346 }   
00347 
00348 //_____________________________________________________________________________
00349 Double_t TGeoHype::GetAxisRange(Int_t iaxis, Double_t &xlo, Double_t &xhi) const
00350 {
00351 // Get range of shape for a given axis.
00352    xlo = 0;
00353    xhi = 0;
00354    Double_t dx = 0;
00355    switch (iaxis) {
00356       case 1: // R
00357          xlo = fRmin;
00358          xhi = TMath::Sqrt(RadiusHypeSq(fDz, kFALSE));
00359          dx = xhi-xlo;
00360          return dx;
00361       case 2: // Phi
00362          xlo = 0;
00363          xhi = 360;
00364          dx = 360;
00365          return dx;
00366       case 3: // Z
00367          xlo = -fDz;
00368          xhi = fDz;
00369          dx = xhi-xlo;
00370          return dx;
00371    }
00372    return dx;
00373 }         
00374             
00375 //_____________________________________________________________________________
00376 void TGeoHype::GetBoundingCylinder(Double_t *param) const
00377 {
00378 //--- Fill vector param[4] with the bounding cylinder parameters. The order
00379 // is the following : Rmin, Rmax, Phi1, Phi2, dZ
00380    param[0] = fRmin; // Rmin
00381    param[0] *= param[0];
00382    param[1] = TMath::Sqrt(RadiusHypeSq(fDz, kFALSE)); // Rmax
00383    param[1] *= param[1];
00384    param[2] = 0.;    // Phi1
00385    param[3] = 360.;  // Phi1
00386 }
00387 
00388 //_____________________________________________________________________________
00389 TGeoShape *TGeoHype::GetMakeRuntimeShape(TGeoShape *mother, TGeoMatrix * /*mat*/) const
00390 {
00391 // in case shape has some negative parameters, these has to be computed
00392 // in order to fit the mother
00393    if (!TestShapeBit(kGeoRunTimeShape)) return 0;
00394    Double_t rmin, rmax, dz;
00395    Double_t zmin,zmax;
00396    rmin = fRmin;
00397    rmax = fRmax;
00398    dz = fDz;
00399    if (fDz<0) {
00400       mother->GetAxisRange(3,zmin,zmax);
00401       if (zmax<0) return 0;
00402       dz=zmax;
00403    } else {
00404       Error("GetMakeRuntimeShape", "Shape %s does not have negative Z range", GetName());   
00405       return 0;
00406    }   
00407    TGeoShape *hype = new TGeoHype(GetName(), dz, fRmax, fStOut, fRmin, fStIn);
00408    return hype;
00409 }
00410 
00411 //_____________________________________________________________________________
00412 void TGeoHype::InspectShape() const
00413 {
00414 // print shape parameters
00415    printf("*** Shape %s: TGeoHype ***\n", GetName());
00416    printf("    Rin  = %11.5f\n", fRmin);
00417    printf("    sin  = %11.5f\n", fStIn);
00418    printf("    Rout = %11.5f\n", fRmax);
00419    printf("    sout = %11.5f\n", fStOut);
00420    printf("    dz   = %11.5f\n", fDz);
00421    
00422    printf(" Bounding box:\n");
00423    TGeoBBox::InspectShape();
00424 }
00425 
00426 //_____________________________________________________________________________
00427 TBuffer3D *TGeoHype::MakeBuffer3D() const
00428 { 
00429    // Creates a TBuffer3D describing *this* shape.
00430    // Coordinates are in local reference frame.
00431 
00432    Int_t n = gGeoManager->GetNsegments();
00433    Bool_t hasRmin = HasInner();
00434    Int_t nbPnts = (hasRmin)?(2*n*n):(n*n+2);
00435    Int_t nbSegs = (hasRmin)?(4*n*n):(n*(2*n+1));
00436    Int_t nbPols = (hasRmin)?(2*n*n):(n*(n+1)); 
00437 
00438    TBuffer3D* buff = new TBuffer3D(TBuffer3DTypes::kGeneric,
00439                                    nbPnts, 3*nbPnts, nbSegs, 3*nbSegs, nbPols, 6*nbPols);
00440    if (buff)
00441    {
00442       SetPoints(buff->fPnts);
00443       SetSegsAndPols(*buff);
00444    }
00445 
00446    return buff; 
00447 }
00448 
00449 //_____________________________________________________________________________
00450 void TGeoHype::SetSegsAndPols(TBuffer3D &buff) const
00451 {
00452 // Fill TBuffer3D structure for segments and polygons.
00453    Int_t c = GetBasicColor();
00454    Int_t i, j, n;
00455    n = gGeoManager->GetNsegments();
00456    Bool_t hasRmin = HasInner();
00457    Int_t irin = 0;
00458    Int_t irout = (hasRmin)?(n*n):2;
00459    // Fill segments
00460    // Case hasRmin:
00461    //   Inner circles:  [isin = 0], n (per circle) * n ( circles)
00462    //        iseg = isin+n*i+j , i = 0, n-1   , j = 0, n-1
00463    //        seg(i=1,n; j=1,n) = [irin+n*i+j] and [irin+n*i+(j+1)%n]
00464    //   Inner generators: [isgenin = isin+n*n], n (per circle) *(n-1) (slices)
00465    //        iseg = isgenin + i*n + j, i=0,n-2,  j=0,n-1
00466    //        seg(i,j) = [irin+n*i+j] and [irin+n*(i+1)+j]
00467    //   Outer circles:  [isout = isgenin+n*(n-1)], n (per circle) * n ( circles)
00468    //        iseg = isout + i*n + j , iz = 0, n-1   , j = 0, n-1
00469    //        seg(i=1,n; j=1,n) = [irout+n*i+j] and [irout+n*i+(j+1)%n]
00470    //   Outer generators: [isgenout = isout+n*n], n (per circle) *(n-1) (slices)
00471    //        iseg = isgenout + i*n + j, i=0,n-2,  j=0,n-1
00472    //        seg(i,j) = [irout+n*i+j] and [irout+n*(i+1)+j]
00473    //   Lower cap : [islow = isgenout + n*(n-1)], n radial segments
00474    //        iseg = islow + j,  j=0,n-1   
00475    //        seg(j) = [irin + j] and [irout+j]
00476    //   Upper cap: [ishi = islow + n], nradial segments
00477    //        iseg = ishi + j, j=0,n-1
00478    //        seg[j] = [irin + n*(n-1) + j] and [irout+n*(n-1) + j]
00479    //
00480    // Case !hasRmin:
00481    //   Outer circles: [isout=0], same outer circles (n*n)
00482    // Outer generators: isgenout = isout + n*n
00483    //   Lower cap: [islow = isgenout+n*(n-1)], n seg.
00484    //        iseg = islow + j, j=0,n-1
00485    //        seg[j] = [irin] and [irout+j]
00486    //   Upper cap: [ishi = islow +n]
00487    //        iseg = ishi + j, j=0,n-1
00488    //        seg[j] = [irin+1] and [irout+n*(n-1) + j]
00489    
00490    Int_t isin = 0;
00491    Int_t isgenin = (hasRmin)?(isin+n*n):0;
00492    Int_t isout = (hasRmin)?(isgenin+n*(n-1)):0;
00493    Int_t isgenout  = isout+n*n;
00494    Int_t islo = isgenout+n*(n-1);
00495    Int_t ishi = islo + n;
00496 
00497    Int_t npt = 0;
00498    // Fill inner circle segments (n*n)
00499    if (hasRmin) {
00500       for (i=0; i<n; i++) {
00501          for (j=0; j<n; j++) {
00502             npt = 3*(isin+n*i+j);
00503             buff.fSegs[npt]   = c;
00504             buff.fSegs[npt+1] = irin+n*i+j;
00505             buff.fSegs[npt+2] = irin+n*i+((j+1)%n);
00506          }
00507       }
00508       // Fill inner generators (n*(n-1))
00509       for (i=0; i<n-1; i++) {
00510          for (j=0; j<n; j++) {
00511             npt = 3*(isgenin+n*i+j);
00512             buff.fSegs[npt]   = c;
00513             buff.fSegs[npt+1] = irin+n*i+j;
00514             buff.fSegs[npt+2] = irin+n*(i+1)+j;
00515          }
00516       }      
00517    }
00518    // Fill outer circle segments (n*n)
00519    for (i=0; i<n; i++) {   
00520       for (j=0; j<n; j++) { 
00521          npt = 3*(isout + n*i+j);     
00522          buff.fSegs[npt]   = c;
00523          buff.fSegs[npt+1] = irout+n*i+j;
00524          buff.fSegs[npt+2] = irout+n*i+((j+1)%n);
00525       }
00526    }      
00527    // Fill outer generators (n*(n-1))
00528    for (i=0; i<n-1; i++) {
00529       for (j=0; j<n; j++) {
00530          npt = 3*(isgenout+n*i+j);
00531          buff.fSegs[npt]   = c;
00532          buff.fSegs[npt+1] = irout+n*i+j;
00533          buff.fSegs[npt+2] = irout+n*(i+1)+j;
00534       }
00535    }      
00536    // Fill lower cap (n)
00537    for (j=0; j<n; j++) {
00538       npt = 3*(islo+j);
00539       buff.fSegs[npt]   = c;
00540       buff.fSegs[npt+1] = irin;
00541       if (hasRmin) buff.fSegs[npt+1] += j;
00542       buff.fSegs[npt+2] = irout + j;
00543    }   
00544    // Fill upper cap (n)
00545    for (j=0; j<n; j++) {
00546       npt = 3*(ishi+j);
00547       buff.fSegs[npt]   = c;
00548       buff.fSegs[npt+1] = irin+1;
00549       if (hasRmin) buff.fSegs[npt+1] += n*(n-1)+j-1;
00550       buff.fSegs[npt+2] = irout + n*(n-1)+j;
00551    }   
00552 
00553    // Fill polygons
00554    // Inner polygons: [ipin = 0] (n-1) slices * n (edges)
00555    //   ipoly = ipin + n*i + j;  i=0,n-2   j=0,n-1
00556    //   poly[i,j] = [isin+n*i+j]  [isgenin+i*n+(j+1)%n]  [isin+n*(i+1)+j]  [isgenin+i*n+j]
00557    // Outer polygons: [ipout = ipin+n*(n-1)]  also (n-1)*n
00558    //   ipoly = ipout + n*i + j; i=0,n-2   j=0,n-1
00559    //   poly[i,j] = [isout+n*i+j]  [isgenout+i*n+j]  [isout+n*(i+1)+j]  [isgenout+i*n+(j+1)%n]
00560    // Lower cap: [iplow = ipout+n*(n-1):  n polygons
00561    //   ipoly = iplow + j;  j=0,n-1
00562    //   poly[i=0,j] = [isin+j] [islow+j] [isout+j] [islow+(j+1)%n]
00563    // Upper cap: [ipup = iplow+n] : n polygons
00564    //   ipoly = ipup + j;  j=0,n-1
00565    //   poly[i=n-1, j] = [isin+n*(n-1)+j] [ishi+(j+1)%n] [isout+n*(n-1)+j] [ishi+j]
00566    //
00567    // Case !hasRmin:
00568    // ipin = 0 no inner polygons
00569    // ipout = 0 same outer polygons
00570    // Lower cap: iplow = ipout+n*(n-1):  n polygons with 3 segments
00571    //   poly[i=0,j] = [isout+j] [islow+(j+1)%n] [islow+j]
00572    // Upper cap: ipup = iplow+n;
00573    //   poly[i=n-1,j] = [isout+n*(n-1)+j] [ishi+j] [ishi+(j+1)%n]
00574 
00575    Int_t ipin = 0;
00576    Int_t ipout = (hasRmin)?(ipin+n*(n-1)):0;
00577    Int_t iplo = ipout+n*(n-1);
00578    Int_t ipup = iplo+n;
00579    // Inner polygons n*(n-1)
00580    if (hasRmin) {
00581       for (i=0; i<n-1; i++) {
00582          for (j=0; j<n; j++) {
00583             npt = 6*(ipin+n*i+j);
00584             buff.fPols[npt]   = c;
00585             buff.fPols[npt+1] = 4;
00586             buff.fPols[npt+2] = isin+n*i+j;
00587             buff.fPols[npt+3] = isgenin+i*n+((j+1)%n);
00588             buff.fPols[npt+4] = isin+n*(i+1)+j;
00589             buff.fPols[npt+5] = isgenin+i*n+j;
00590          }
00591       }
00592    }
00593    // Outer polygons n*(n-1)
00594    for (i=0; i<n-1; i++) {        
00595       for (j=0; j<n; j++) {
00596          npt = 6*(ipout+n*i+j);
00597          buff.fPols[npt]   = c;
00598          buff.fPols[npt+1] = 4;
00599          buff.fPols[npt+2] = isout+n*i+j;
00600          buff.fPols[npt+3] = isgenout+i*n+j;
00601          buff.fPols[npt+4] = isout+n*(i+1)+j;
00602          buff.fPols[npt+5] = isgenout+i*n+((j+1)%n);
00603       }
00604    }
00605    // End caps
00606    if (hasRmin) {
00607       for (j=0; j<n; j++) {  
00608          npt = 6*(iplo+j);
00609          buff.fPols[npt]   = c+1;
00610          buff.fPols[npt+1] = 4;
00611          buff.fPols[npt+2] = isin+j;
00612          buff.fPols[npt+3] = islo+j;
00613          buff.fPols[npt+4] = isout+j;
00614          buff.fPols[npt+5] = islo+((j+1)%n);
00615       }
00616       for (j=0; j<n; j++) {  
00617          npt = 6*(ipup+j);
00618          buff.fPols[npt]   = c+2;
00619          buff.fPols[npt+1] = 4;
00620          buff.fPols[npt+2] = isin+n*(n-1)+j;
00621          buff.fPols[npt+3] = ishi+((j+1)%n);
00622          buff.fPols[npt+4] = isout+n*(n-1)+j;
00623          buff.fPols[npt+5] = ishi+j;
00624       }
00625    } else {      
00626       for (j=0; j<n; j++) {  
00627          npt = 6*iplo+5*j;
00628          buff.fPols[npt]   = c+1;
00629          buff.fPols[npt+1] = 3;
00630          buff.fPols[npt+2] = isout+j;
00631          buff.fPols[npt+3] = islo+((j+1)%n);
00632          buff.fPols[npt+4] = islo+j;
00633       }
00634       for (j=0; j<n; j++) {  
00635          npt = 6*iplo+5*(n+j);
00636          buff.fPols[npt]   = c+2;
00637          buff.fPols[npt+1] = 3;
00638          buff.fPols[npt+2] = isout+n*(n-1)+j;
00639          buff.fPols[npt+3] = ishi+j;
00640          buff.fPols[npt+4] = ishi+((j+1)%n);
00641       }
00642    }   
00643 }
00644 
00645 //_____________________________________________________________________________
00646 Double_t TGeoHype::RadiusHypeSq(Double_t z, Bool_t inner) const
00647 {
00648 // Compute r^2 = x^2 + y^2 at a given z coordinate, for either inner or outer hyperbolas.
00649    Double_t r0, tsq;
00650    if (inner) {
00651       r0 = fRmin;
00652       tsq = fTinsq;
00653    } else {
00654       r0 = fRmax;
00655       tsq = fToutsq;
00656    }
00657    return (r0*r0+tsq*z*z);
00658 }
00659          
00660 //_____________________________________________________________________________
00661 Double_t TGeoHype::ZHypeSq(Double_t r, Bool_t inner) const
00662 {
00663 // Compute z^2 at a given  r^2, for either inner or outer hyperbolas.
00664    Double_t r0, tsq;
00665    if (inner) {
00666       r0 = fRmin;
00667       tsq = fTinsq;
00668    } else {
00669       r0 = fRmax;
00670       tsq = fToutsq;
00671    }
00672    if (TMath::Abs(tsq) < TGeoShape::Tolerance()) return TGeoShape::Big();
00673    return ((r*r-r0*r0)/tsq);
00674 }     
00675 
00676 //_____________________________________________________________________________
00677 Double_t TGeoHype::Safety(Double_t *point, Bool_t in) const
00678 {
00679 // computes the closest distance from given point to this shape, according
00680 // to option. The matching point on the shape is stored in spoint.
00681    Double_t safe, safrmin, safrmax;
00682    if (in) {
00683       safe    = fDz-TMath::Abs(point[2]); 
00684       safrmin = SafetyToHype(point, kTRUE, in);
00685       if (safrmin < safe) safe = safrmin;
00686       safrmax = SafetyToHype(point, kFALSE,in);
00687       if (safrmax < safe) safe = safrmax;
00688    } else {
00689       safe    = -fDz+TMath::Abs(point[2]);
00690       safrmin = SafetyToHype(point, kTRUE, in);
00691       if (safrmin > safe) safe = safrmin;
00692       safrmax = SafetyToHype(point, kFALSE,in);
00693       if (safrmax > safe) safe = safrmax;      
00694    }   
00695    return safe;
00696 }
00697 
00698 //_____________________________________________________________________________
00699 Double_t TGeoHype::SafetyToHype(Double_t *point, Bool_t inner, Bool_t in) const
00700 {
00701 // Compute an underestimate of the closest distance from a point to inner or
00702 // outer infinite hyperbolas.
00703    Double_t r, rsq, rhsq, rh, dr, tsq, saf;
00704    if (inner && !HasInner()) return (in)?TGeoShape::Big():-TGeoShape::Big();
00705    rsq = point[0]*point[0]+point[1]*point[1];
00706    r = TMath::Sqrt(rsq);
00707    rhsq = RadiusHypeSq(point[2], inner);
00708    rh = TMath::Sqrt(rhsq);
00709    dr = r - rh;
00710    if (inner) {
00711       if (!in && dr>0) return -TGeoShape::Big();
00712       if (TMath::Abs(fStIn) < TGeoShape::Tolerance()) return TMath::Abs(dr);
00713       if (fRmin<TGeoShape::Tolerance()) return TMath::Abs(dr/TMath::Sqrt(1.+ fTinsq));
00714       tsq = fTinsq;
00715    } else {
00716       if (!in && dr<0) return -TGeoShape::Big();
00717       if (TMath::Abs(fStOut) < TGeoShape::Tolerance()) return TMath::Abs(dr);
00718       tsq = fToutsq;
00719    }
00720    if (TMath::Abs(dr)<TGeoShape::Tolerance()) return 0.;
00721    // 1. dr<0 => approximate safety with distance to tangent to hyperbola in z = |point[2]|   
00722    Double_t m;
00723    if (dr<0) {
00724       m = rh/(tsq*TMath::Abs(point[2]));
00725       saf = -m*dr/TMath::Sqrt(1.+m*m);
00726       return saf;
00727    }
00728    // 2. dr>0 => approximate safety with distance from point to segment P1(r(z0),z0) and P2(r0, z(r0))   
00729    m = (TMath::Sqrt(ZHypeSq(r,inner)) - TMath::Abs(point[2]))/dr;
00730    saf = m*dr/TMath::Sqrt(1.+m*m);        
00731    return saf;
00732 }
00733 
00734 //_____________________________________________________________________________
00735 void TGeoHype::SavePrimitive(ostream &out, Option_t * /*option*/ /*= ""*/)
00736 {
00737 // Save a primitive as a C++ statement(s) on output stream "out".
00738    if (TObject::TestBit(kGeoSavePrimitive)) return;
00739    out << "   // Shape: " << GetName() << " type: " << ClassName() << endl;
00740    out << "   rin   = " << fRmin << ";" << endl;
00741    out << "   stin  = " << fStIn << ";" << endl;
00742    out << "   rout  = " << fRmax << ";" << endl;
00743    out << "   stout = " << fStOut << ";" << endl;
00744    out << "   dz    = " << fDz << ";" << endl;
00745    out << "   TGeoShape *" << GetPointerName() << " = new TGeoHype(\"" << GetName() << "\",rin,stin,rout,stout,dz);" << endl;
00746    TObject::SetBit(TGeoShape::kGeoSavePrimitive);  
00747 }
00748 
00749 //_____________________________________________________________________________
00750 void TGeoHype::SetHypeDimensions(Double_t rin, Double_t stin, Double_t rout, Double_t stout, Double_t dz)
00751 {
00752 // Set dimensions of the hyperboloid.
00753    fRmin = rin;
00754    fRmax = rout;
00755    fDz   = dz;
00756    fStIn = stin;
00757    fStOut = stout;
00758    fTin = TMath::Tan(fStIn*TMath::DegToRad());
00759    fTinsq = fTin*fTin;
00760    fTout = TMath::Tan(fStOut*TMath::DegToRad());
00761    fToutsq = fTout*fTout;
00762    if ((fRmin==0) && (fStIn==0)) SetShapeBit(kGeoRSeg, kTRUE);
00763    else                          SetShapeBit(kGeoRSeg, kFALSE);
00764 }   
00765 
00766 //_____________________________________________________________________________
00767 void TGeoHype::SetDimensions(Double_t *param)
00768 {
00769 // Set dimensions of the hyperboloid starting from an array.
00770 // param[0] = dz
00771 // param[1] = rin
00772 // param[2] = stin
00773 // param[3] = rout
00774 // param[4] = stout
00775    Double_t dz = param[0];
00776    Double_t rin = param[1];
00777    Double_t stin = param[2];
00778    Double_t rout = param[3];
00779    Double_t stout = param[4];
00780    SetHypeDimensions(rin, stin, rout, stout, dz);
00781 }   
00782 
00783 //_____________________________________________________________________________
00784 void TGeoHype::SetPoints(Double_t *points) const
00785 {
00786 // create tube mesh points
00787    Double_t z,dz,r;
00788    Int_t i,j, n;
00789    if (!points) return;
00790    n = gGeoManager->GetNsegments();
00791    Double_t dphi = 360./n;
00792    Double_t phi = 0;
00793    dz = 2.*fDz/(n-1);
00794 
00795    Int_t indx = 0;
00796 
00797    if (HasInner()) {
00798       // Inner surface points
00799       for (i=0; i<n; i++) {
00800          z = -fDz+i*dz;
00801          r = TMath::Sqrt(RadiusHypeSq(z, kTRUE));
00802          for (j=0; j<n; j++) {
00803             phi = j*dphi*TMath::DegToRad();
00804             points[indx++] = r * TMath::Cos(phi);
00805             points[indx++] = r * TMath::Sin(phi);
00806             points[indx++] = z;
00807          }
00808       }
00809    } else {
00810       points[indx++] = 0.;
00811       points[indx++] = 0.;
00812       points[indx++] = -fDz;
00813       points[indx++] = 0.;         
00814       points[indx++] = 0.;
00815       points[indx++] = fDz;
00816    }   
00817    // Outer surface points
00818    for (i=0; i<n; i++) {
00819       z = -fDz + i*dz;
00820       r = TMath::Sqrt(RadiusHypeSq(z, kFALSE));
00821       for (j=0; j<n; j++) {
00822          phi = j*dphi*TMath::DegToRad();
00823          points[indx++] = r * TMath::Cos(phi);
00824          points[indx++] = r * TMath::Sin(phi);
00825          points[indx++] = z;
00826       }
00827    }
00828 }
00829 
00830 //_____________________________________________________________________________
00831 void TGeoHype::SetPoints(Float_t *points) const
00832 {
00833 // create tube mesh points
00834    Double_t z,dz,r;
00835    Int_t i,j, n;
00836    if (!points) return;
00837    n = gGeoManager->GetNsegments();
00838    Double_t dphi = 360./n;
00839    Double_t phi = 0;
00840    dz = 2.*fDz/(n-1);
00841 
00842    Int_t indx = 0;
00843 
00844    if (HasInner()) {
00845       // Inner surface points
00846       for (i=0; i<n; i++) {
00847          z = -fDz+i*dz;
00848          r = TMath::Sqrt(RadiusHypeSq(z, kTRUE));
00849          for (j=0; j<n; j++) {
00850             phi = j*dphi*TMath::DegToRad();
00851             points[indx++] = r * TMath::Cos(phi);
00852             points[indx++] = r * TMath::Sin(phi);
00853             points[indx++] = z;
00854          }
00855       }
00856    } else {
00857       points[indx++] = 0.;
00858       points[indx++] = 0.;
00859       points[indx++] = -fDz;
00860       points[indx++] = 0.;         
00861       points[indx++] = 0.;
00862       points[indx++] = fDz;
00863    }   
00864    // Outer surface points
00865    for (i=0; i<n; i++) {
00866       z = -fDz + i*dz;
00867       r = TMath::Sqrt(RadiusHypeSq(z, kFALSE));
00868       for (j=0; j<n; j++) {
00869          phi = j*dphi*TMath::DegToRad();
00870          points[indx++] = r * TMath::Cos(phi);
00871          points[indx++] = r * TMath::Sin(phi);
00872          points[indx++] = z;
00873       }
00874    }
00875 }
00876 
00877 //_____________________________________________________________________________
00878 void TGeoHype::GetMeshNumbers(Int_t &nvert, Int_t &nsegs, Int_t &npols) const
00879 {
00880 // Returns numbers of vertices, segments and polygons composing the shape mesh.
00881    Int_t n = gGeoManager->GetNsegments();
00882    Bool_t hasRmin = HasInner();
00883    nvert = (hasRmin)?(2*n*n):(n*n+2);
00884    nsegs = (hasRmin)?(4*n*n):(n*(2*n+1));
00885    npols = (hasRmin)?(2*n*n):(n*(n+1)); 
00886 }
00887 
00888 //_____________________________________________________________________________
00889 Int_t TGeoHype::GetNmeshVertices() const
00890 {
00891 // Return number of vertices of the mesh representation
00892    Int_t n = gGeoManager->GetNsegments();
00893    Int_t numPoints = (HasRmin())?(2*n*n):(n*n+2);
00894    return numPoints;
00895 }
00896 
00897 //_____________________________________________________________________________
00898 void TGeoHype::Sizeof3D() const
00899 {
00900 ///// fill size of this 3-D object
00901 ///    TVirtualGeoPainter *painter = gGeoManager->GetGeomPainter();
00902 ///    if (!painter) return;
00903 ///    Int_t n = gGeoManager->GetNsegments();
00904 ///    Int_t numPoints = n*4;
00905 ///    Int_t numSegs   = n*8;
00906 ///    Int_t numPolys  = n*4;
00907 ///    painter->AddSize3D(numPoints, numSegs, numPolys);
00908 }
00909 
00910 //_____________________________________________________________________________
00911 const TBuffer3D & TGeoHype::GetBuffer3D(Int_t reqSections, Bool_t localFrame) const
00912 {
00913 // Fills a static 3D buffer and returns a reference.
00914    static TBuffer3D buffer(TBuffer3DTypes::kGeneric);
00915 
00916    TGeoBBox::FillBuffer3D(buffer, reqSections, localFrame);
00917 
00918    if (reqSections & TBuffer3D::kRawSizes) {
00919       Int_t n = gGeoManager->GetNsegments();
00920       Bool_t hasRmin = HasInner();
00921       Int_t nbPnts = (hasRmin)?(2*n*n):(n*n+2);
00922       Int_t nbSegs = (hasRmin)?(4*n*n):(n*(2*n+1));
00923       Int_t nbPols = (hasRmin)?(2*n*n):(n*(n+1)); 
00924       if (buffer.SetRawSizes(nbPnts, 3*nbPnts, nbSegs, 3*nbSegs, nbPols, 6*nbPols)) {
00925          buffer.SetSectionsValid(TBuffer3D::kRawSizes);
00926       }
00927    }
00928    if ((reqSections & TBuffer3D::kRaw) && buffer.SectionsValid(TBuffer3D::kRawSizes)) {
00929       SetPoints(buffer.fPnts);
00930       if (!buffer.fLocalFrame) {
00931          TransformPoints(buffer.fPnts, buffer.NbPnts());
00932       }
00933 
00934       SetSegsAndPols(buffer);      
00935       buffer.SetSectionsValid(TBuffer3D::kRaw);
00936    }
00937       
00938    return buffer;
00939 }

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