// @(#)root/g3d:$Name:  $:$Id: TSPHE.cxx,v 1.12 2004/11/02 16:55:20 brun Exp $
// Author: Rene Brun   13/06/97

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "TSPHE.h"
#include "TNode.h"
#include "TVirtualPad.h"
#include "TBuffer3D.h"
#include "TGeometry.h"


ClassImp(TSPHE)


//______________________________________________________________________________
// 


// SPHE is a Sphere. It has 9 parameters:
//
//     - name       name of the shape
//     - title      shape's title
//     - material  (see TMaterial)
//     - rmin       minimum radius
//     - rmax       maximum radius
//     - themin     theta min
//     - themax     theta max
//     - phimin     phi min
//     - phimax     phi max

// ROOT color indx = max(i-i0,j-j0);


//______________________________________________________________________________
 TSPHE::TSPHE()
{
   // SPHE shape default constructor

   fRmin       = 0;
   fRmax       = 0;
   fThemin     = 0;
   fThemax     = 0;
   fPhimin     = 0;
   fPhimax     = 0;
   fSiTab      = 0;
   fCoTab      = 0;
   fCoThetaTab = 0;
   fNdiv       = 0;
   fAspectRatio=1.0;
   faX = faY = faZ = 1.0;      // Coeff along Ox
}


//______________________________________________________________________________
 TSPHE::TSPHE(const char *name, const char *title, const char *material, Float_t rmin, Float_t rmax, Float_t themin,
             Float_t themax, Float_t phimin, Float_t phimax)
     : TShape(name, title,material)
{
   // SPHE shape normal constructor

   fRmin   = rmin;
   fRmax   = rmax;
   fThemin = themin;
   fThemax = themax;
   fPhimin = phimin;
   fPhimax = phimax;

   fSiTab      = 0;
   fCoTab      = 0;
   fCoThetaTab = 0;
   fNdiv       = 0;

   fAspectRatio=1.0;
   faX = faY = faZ = 1.0;      // Coeff along Ox

   SetNumberOfDivisions (20);
}


//______________________________________________________________________________
 TSPHE::TSPHE(const char *name, const char *title, const char *material, Float_t rmax)
     : TShape(name, title,material)
{
   // SPHE shape "simplified" constructor

   fRmin   = 0;
   fRmax   = rmax;
   fThemin = 0;
   fThemax = 180;
   fPhimin = 0;
   fPhimax = 360;

   fSiTab      = 0;
   fCoTab      = 0;
   fCoThetaTab = 0;
   fNdiv       = 0;

   fAspectRatio=1.0;
   faX = faY = faZ = 1.0;      // Coeff along Ox

   SetNumberOfDivisions (20);
}


//______________________________________________________________________________
 TSPHE::~TSPHE()
{
   // SPHE shape default destructor

   if (fCoThetaTab) delete [] fCoThetaTab;
   if (fSiTab) delete [] fSiTab;
   if (fCoTab) delete [] fCoTab;

   fCoTab = 0;
   fSiTab = 0;
   fCoThetaTab=0;
}


//______________________________________________________________________________
 Int_t TSPHE::DistancetoPrimitive(Int_t px, Int_t py)
{
   // Compute distance from point px,py to a PSPHE
   //
   // Compute the closest distance of approach from point px,py to each
   // computed outline point of the PSPHE (stolen from PCON).

   Int_t n = GetNumberOfDivisions()+1;
   Int_t numPoints = 2*n*(fNz+1);
   return ShapeDistancetoPrimitive(numPoints,px,py);
}


//______________________________________________________________________________
 void TSPHE::Paint(Option_t *option)
{
   // Paint this 3-D shape with its current attributes

   Int_t i, j;
   const Int_t n = GetNumberOfDivisions()+1;

   // In case of OpenGL a simple sphere can be drawn with a specialized function
   TBuffer3D *buff = gPad->AllocateBuffer3D(11, 0, 0);
   if (!buff) return;
   if (buff->fOption == TBuffer3D::kOGL &&
       fRmin == 0 && fThemin == 0 && fThemax >= 180 && fPhimin == 0 && fPhimax >= 360) {
      buff->fNbPnts  = 3;
      buff->fNbSegs  = 0;
      buff->fNbPols  = 0;
      buff->fColor   = GetLineColor();
      buff->fPnts[0] =      0; buff->fPnts[1] =      0; buff->fPnts[2] =      0;
      buff->fPnts[3] =  fRmax; buff->fPnts[4] =  fRmax; buff->fPnts[5] =  fRmax;
      buff->fPnts[6] = -fRmax; buff->fPnts[7] = -fRmax; buff->fPnts[8] = -fRmax;
      buff->fPnts[9] = (Float_t)n;
      buff->fPnts[10] = fRmax;
      TransformPoints(buff);
      buff->fId   = this;
      buff->fType = TBuffer3D::kSPHE;
      buff->Paint(option);
      return;
   }

   Int_t nz = fNz+1;
   if (nz < 2) return;
   Int_t NbPnts = 2*n*nz;
   if (NbPnts <= 0) return;
 
   Bool_t specialCase = kFALSE;
   if (TMath::Abs(TMath::Sin(2*(fPhimax - fPhimin))) <= 0.01) specialCase = kTRUE;

   Int_t NbSegs = 4*(nz*n-1+(specialCase == kTRUE));
   Int_t NbPols = 2*(nz*n-1+(specialCase == kTRUE));

   buff = gPad->AllocateBuffer3D(3*NbPnts, 3*NbSegs, 6*NbPols);
   if (!buff) return;

   buff->fType = TBuffer3D::kANY;

   buff->fId   = this;

   // Fill gPad->fBuffer3D. Points coordinates are in Master space
   buff->fNbPnts = NbPnts;
   buff->fNbSegs = NbSegs;
   buff->fNbPols = NbPols;
   // In case of option "size" it is not necessary to fill the buffer
   if (buff->fOption == TBuffer3D::kSIZE) {
      buff->Paint(option);
      return;
   }

   SetPoints(buff->fPnts);

   TransformPoints(buff);

   // Basic colors: 0, 1, ... 7
   buff->fColor = GetLineColor();
   Int_t c = (((buff->fColor) %8) -1) * 4;
   if (c < 0) c = 0;

   Int_t indx, indx2, k;
   indx = indx2 = 0;
   //inside & outside spheres, number of segments: 2*nz*(n-1)
   //             special case number of segments: 2*nz*n
   for (i = 0; i < nz*2; i++) {
      indx2 = i*n;
      for (j = 1; j < n; j++) {
         buff->fSegs[indx++] = c;
         buff->fSegs[indx++] = indx2+j-1;
         buff->fSegs[indx++] = indx2+j;
      }
      if (specialCase) {
         buff->fSegs[indx++] = c;
         buff->fSegs[indx++] = indx2+j-1;
         buff->fSegs[indx++] = indx2;
      }
   }

   //bottom & top lines, number of segments: 2*n
   for (i = 0; i < 2; i++) {
      indx2 = i*(nz-1)*2*n;
      for (j = 0; j < n; j++) {
         buff->fSegs[indx++] = c;
         buff->fSegs[indx++] = indx2+j;
         buff->fSegs[indx++] = indx2+n+j;
      }
   }

   //inside & outside spheres, number of segments: 2*(nz-1)*n
   for (i = 0; i < (nz-1); i++) {

      //inside sphere
      indx2 = i*n*2;
      for (j = 0; j < n; j++) {
         buff->fSegs[indx++] = c+2;
         buff->fSegs[indx++] = indx2+j;
         buff->fSegs[indx++] = indx2+n*2+j;
      }
      //outside sphere
      indx2 = i*n*2+n;
      for (j = 0; j < n; j++) {
         buff->fSegs[indx++] = c+3;
         buff->fSegs[indx++] = indx2+j;
         buff->fSegs[indx++] = indx2+n*2+j;
      }
   }

   //left & right sections, number of segments: 2*(nz-2)
   //          special case number of segments: 0
   if (!specialCase) {
      for (i = 1; i < (nz-1); i++) {
         for (j = 0; j < 2; j++) {
            buff->fSegs[indx++] = c;
            buff->fSegs[indx++] =  2*i    * n + j*(n-1);
            buff->fSegs[indx++] = (2*i+1) * n + j*(n-1);
         }
      }
   }

   Int_t m = n - 1 + (specialCase == kTRUE);
   indx = 0;

   //bottom & top, number of polygons: 2*(n-1)
   // special case number of polygons: 2*n
   for (j = 0; j < n-1; j++) {
      buff->fPols[indx++] = c+3;
      buff->fPols[indx++] = 4;
      buff->fPols[indx++] = 2*nz*m+j;
      buff->fPols[indx++] = m+j;
      buff->fPols[indx++] = 2*nz*m+j+1;
      buff->fPols[indx++] = j;
   }
   for (j = 0; j < n-1; j++) {
      buff->fPols[indx++] = c+3;
      buff->fPols[indx++] = 4;
      buff->fPols[indx++] = 2*nz*m+n+j;
      buff->fPols[indx++] = (nz*2-2)*m+j;
      buff->fPols[indx++] = 2*nz*m+n+j+1;
      buff->fPols[indx++] = (nz*2-2)*m+m+j;
   }
   if (specialCase) {
      buff->fPols[indx++] = c+3;
      buff->fPols[indx++] = 4;
      buff->fPols[indx++] = 2*nz*m+j;
      buff->fPols[indx++] = m+j;
      buff->fPols[indx++] = 2*nz*m;
      buff->fPols[indx++] = j;
      
      buff->fPols[indx++] = c+3;
      buff->fPols[indx++] = 4;
      buff->fPols[indx++] = 2*nz*m+n+j;
      buff->fPols[indx++] = (nz*2-2)*m+j;
      buff->fPols[indx++] = 2*nz*m+n;
      buff->fPols[indx++] = (nz*2-2)*m+m+j;
   }

   //inside & outside, number of polygons: (nz-1)*2*(n-1)
   for (k = 0; k < (nz-1); k++) {
     for (j = 0; j < n-1; j++) {
        buff->fPols[indx++] = c;
        buff->fPols[indx++] = 4;
        buff->fPols[indx++] = 2*k*m+j;
        buff->fPols[indx++] = nz*2*m+(2*k+2)*n+j+1;
        buff->fPols[indx++] = (2*k+2)*m+j;
        buff->fPols[indx++] = nz*2*m+(2*k+2)*n+j;
     }
     for (j = 0; j < n-1; j++) {
        buff->fPols[indx++] = c+1;
        buff->fPols[indx++] = 4;
        buff->fPols[indx++] = (2*k+1)*m+j;
        buff->fPols[indx++] = nz*2*m+(2*k + 3)*n+j;
        buff->fPols[indx++] = (2*k+ 3)*m+j;
        buff->fPols[indx++] = nz*2*m+(2*k+3)*n+j+1;
     }
    	 
     if (specialCase) {
         buff->fPols[indx++] = c;
         buff->fPols[indx++] = 4;
         buff->fPols[indx++] = 2*k*m+j;
         buff->fPols[indx++] = nz*2*m+(2*k+2)*n+j;
         buff->fPols[indx++] = (2*k+2)*m+j;
         buff->fPols[indx++] = nz*2*m+(2*k+2)*n;
	    
         buff->fPols[indx++] = c+1;
         buff->fPols[indx++] = 4;
         buff->fPols[indx++] = (2*k+1)*m+j;
         buff->fPols[indx++] = nz*2*m+(2*k+3)*n+j;
         buff->fPols[indx++] = (2*k+3)*m+j;
         buff->fPols[indx++] = nz*2*m+(2*k+3)*n;
      }
   }

   //left & right sections, number of polygons: 2*(nz-1)
   //          special case number of polygons: 0
   if (!specialCase) {
      indx2 = nz*2*(n-1);
      for (k = 0; k < (nz-1); k++) {
         buff->fPols[indx++] = c+2;
         buff->fPols[indx++] = 4;
         buff->fPols[indx++] = k==0 ? indx2 : indx2+2*nz*n+2*(k-1);
         buff->fPols[indx++] = indx2+2*(k+1)*n;
         buff->fPols[indx++] = indx2+2*nz*n+2*k;
         buff->fPols[indx++] = indx2+(2*k+3)*n;
	    
	 buff->fPols[indx++] = c+2;
         buff->fPols[indx++] = 4;
         buff->fPols[indx++] = k==0 ? indx2+n-1 : indx2+2*nz*n+2*(k-1)+1;
         buff->fPols[indx++] = indx2+(2*k+3)*n+n-1;
         buff->fPols[indx++] = indx2+2*nz*n+2*k+1;
         buff->fPols[indx++] = indx2+2*(k+1)*n+n-1;
      }

      buff->fPols[indx-8] = indx2+n;
      buff->fPols[indx-2] = indx2+2*n-1;
   }

   // Paint gPad->fBuffer3D
   buff->Paint(option);
}


//______________________________________________________________________________
 void TSPHE::SetEllipse(const Float_t *factors){

   if (factors[0] > 0) faX = factors[0];
   if (factors[1] > 0) faY = factors[1];
   if (factors[2] > 0) faZ = factors[2];
}


//______________________________________________________________________________
 void TSPHE::SetNumberOfDivisions (Int_t p)
{
    if (GetNumberOfDivisions () == p) return;
    fNdiv=p;
    fNz = Int_t(fAspectRatio*fNdiv*(fThemax - fThemin )/(fPhimax - fPhimin )) + 1;
    MakeTableOfCoSin();
}


//______________________________________________________________________________
 void TSPHE::SetPoints(Double_t *buff)
{
   // Create SPHE points

   Int_t i, j, n;
   Int_t indx = 0;

   n = GetNumberOfDivisions()+1;

   if (buff) {
      if (!fCoTab)   MakeTableOfCoSin();
      Float_t z;
      for (i = 0; i < fNz+1; i++) {
         z = fRmin * fCoThetaTab[i]; // fSinPhiTab[i];
         Float_t sithet = TMath::Sqrt(TMath::Abs(1-fCoThetaTab[i]*fCoThetaTab[i]));
         Float_t zi = fRmin*sithet;
         for (j = 0; j < n; j++) {
            buff[indx++] = faX*zi * fCoTab[j];
            buff[indx++] = faY*zi * fSiTab[j];
            buff[indx++] = faZ*z;
         }
         z = fRmax * fCoThetaTab[i];
         zi = fRmax*sithet;
         for (j = 0; j < n; j++) {
            buff[indx++] = faX*zi * fCoTab[j];
            buff[indx++] = faY*zi * fSiTab[j];
            buff[indx++] = faZ*z;
         }
      }
   }
}


//______________________________________________________________________________
 void TSPHE::Sizeof3D() const
{
   // Return total X3D needed by TNode::ls (when called with option "x")

   Int_t n;

   n = GetNumberOfDivisions()+1;
   Int_t nz = fNz+1;
   Bool_t specialCase = kFALSE;

   if (TMath::Abs(TMath::Sin(2*(fPhimax - fPhimin))) <= 0.01)  //mark this as a very special case, when
         specialCase = kTRUE;                                  //we have to draw this PCON like a TUBE

   gSize3D.numPoints += 2*n*nz;
   gSize3D.numSegs   += 4*(nz*n-1+(specialCase == kTRUE));
   gSize3D.numPolys  += 2*(nz*n-1+(specialCase == kTRUE));
}


//______________________________________________________________________________
 void TSPHE::MakeTableOfCoSin()
{
    const Double_t PI  = TMath::ATan(1) * 4.0;
    const Double_t ragrad  = PI/180.0;

    Float_t dphi = fPhimax - fPhimin;
    while (dphi > 360) dphi -= 360;

    Float_t dtet = fThemax - fThemin;
    while (dtet > 180) dtet -= 180;

    Int_t j;
    Int_t n = GetNumberOfDivisions () + 1;
    if (fCoTab)
        delete [] fCoTab; // Delete the old tab if any
        fCoTab = new Double_t [n];
    if (!fCoTab ) return;

    if (fSiTab)
        delete [] fSiTab; // Delete the old tab if any
    fSiTab = new Double_t [n];
    if (!fSiTab ) return;

    Double_t range   = Double_t(dphi * ragrad);
    Double_t phi1    = Double_t(fPhimin  * ragrad);
    Double_t angstep = range/(n-1);

    Double_t ph = phi1;
    for (j = 0; j < n; j++)
    {
        ph = phi1 + j*angstep;
        fCoTab[j] = TMath::Cos(ph);
        fSiTab[j] = TMath::Sin(ph);
    }

    n  = fNz + 1;

    if (fCoThetaTab)
        delete [] fCoThetaTab; // Delete the old tab if any
    fCoThetaTab = new Double_t [n];
    if (!fCoThetaTab ) return;

    range   = Double_t(dtet * ragrad);
    phi1    = Double_t(fThemin  * ragrad);
    angstep = range/(n-1);

    ph = phi1;
    for (j = 0; j < n; j++)
    {
        fCoThetaTab[n-j-1] = TMath::Cos(ph);
        ph += angstep;
    }

}


//_______________________________________________________________________
 void TSPHE::Streamer(TBuffer &b)
{
   // Stream a class object

   if (b.IsReading()) {
      UInt_t R__s, R__c;
      Version_t R__v = b.ReadVersion(&R__s, &R__c);
      if (R__v > 2) {
         TSPHE::Class()->ReadBuffer(b, this, R__v, R__s, R__c);
         Int_t ndiv = fNdiv;
         fNdiv = 0;
         SetNumberOfDivisions (ndiv);
         return;
      }
      //====process old versions before automatic schema evolution
      TShape::Streamer(b);
      b >> fRmin;    // minimum radius
      b >> fRmax;    // maximum radius
      b >> fThemin;  // minimum theta
      b >> fThemax;  // maximum theta
      b >> fPhimin;  // minimum phi
      b >> fPhimax;  // maximum phi
      Int_t tNdiv;   // XXX added by RvdE XXX (fNdiv is set by SetNumberOfDivisions)
      b >> tNdiv;
      if (R__v > 1) {
        b >> faX;
        b >> faY;
        b >> faZ;
      }
      SetNumberOfDivisions (tNdiv); // XXX added by RvdE
      b.CheckByteCount(R__s, R__c, TSPHE::IsA());
      //====end of old versions
      
   } else {
      TSPHE::Class()->WriteBuffer(b,this);
   }
}


ROOT page - Class index - Class Hierarchy - Top of the page

This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.