// @(#)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);
}
}