```// @(#)root/geom:\$Id: TGeoParaboloid.cxx 21494 2007-12-19 15:50:40Z brun \$
// Author: Mihaela Gheata   20/06/04

/*************************************************************************
*                                                                       *
* For the licensing terms see \$ROOTSYS/LICENSE.                         *
* For the list of contributors see \$ROOTSYS/README/CREDITS.             *
*************************************************************************/

//_____________________________________________________________________________
// TGeoParaboloid - Paraboloid  class. A paraboloid is the solid bounded by
//            the following surfaces:
//            - 2 planes parallel with XY cutting the Z axis at Z=-dz and Z=+dz
//            - the surface of revolution of a parabola described by:
//                 z = a*(x*x + y*y) + b
//       The parameters a and b are automatically computed from:
//            - rlo - the radius of the circle of intersection between the
//              parabolic surface and the plane z = -dz
//            - rhi - the radius of the circle of intersection between the
//              parabolic surface and the plane z = +dz
//         | -dz = a*rlo*rlo + b
//         |  dz = a*rhi*rhi + b      where: rlo != rhi, both >= 0
//_____________________________________________________________________________

#include "Riostream.h"
#include "TGeoManager.h"
#include "TGeoVolume.h"
#include "TVirtualGeoPainter.h"
#include "TGeoParaboloid.h"
#include "TBuffer3D.h"
#include "TBuffer3DTypes.h"
#include "TMath.h"

ClassImp(TGeoParaboloid)

//_____________________________________________________________________________
TGeoParaboloid::TGeoParaboloid()
{
// Dummy constructor
fRlo = 0;
fRhi = 0;
fDz  = 0;
fA   = 0;
fB   = 0;
SetShapeBit(TGeoShape::kGeoParaboloid);
}

//_____________________________________________________________________________
TGeoParaboloid::TGeoParaboloid(Double_t rlo, Double_t rhi, Double_t dz)
:TGeoBBox(0,0,0)
{
// Default constructor specifying X and Y semiaxis length
fRlo = 0;
fRhi = 0;
fDz  = 0;
fA   = 0;
fB   = 0;
SetShapeBit(TGeoShape::kGeoParaboloid);
SetParaboloidDimensions(rlo, rhi, dz);
ComputeBBox();
}

//_____________________________________________________________________________
TGeoParaboloid::TGeoParaboloid(const char *name, Double_t rlo, Double_t rhi, Double_t dz)
:TGeoBBox(name, 0, 0, 0)
{
// Default constructor specifying X and Y semiaxis length
fRlo = 0;
fRhi = 0;
fDz  = 0;
fA   = 0;
fB   = 0;
SetShapeBit(TGeoShape::kGeoParaboloid);
SetParaboloidDimensions(rlo, rhi, dz);
ComputeBBox();
}

//_____________________________________________________________________________
TGeoParaboloid::TGeoParaboloid(Double_t *param)
{
// Default constructor specifying minimum and maximum radius
// param[0] =  rlo
// param[1] =  rhi
// param[2] = dz
SetShapeBit(TGeoShape::kGeoParaboloid);
SetDimensions(param);
ComputeBBox();
}

//_____________________________________________________________________________
TGeoParaboloid::~TGeoParaboloid()
{
// destructor
}

//_____________________________________________________________________________
Double_t TGeoParaboloid::Capacity() const
{
// Computes capacity of the shape in [length^3]
Double_t capacity = TMath::Pi()*fDz*(fRlo*fRlo+fRhi*fRhi);
return capacity;
}

//_____________________________________________________________________________
void TGeoParaboloid::ComputeBBox()
{
// compute bounding box of the tube
fDX = TMath::Max(fRlo, fRhi);
fDY = fDX;
fDZ = fDz;
}

//_____________________________________________________________________________
void TGeoParaboloid::ComputeNormal(Double_t *point, Double_t *dir, Double_t *norm)
{
// Compute normal to closest surface from POINT.
if ((TMath::Abs(point[2])-fDz) > -1E-5) {
norm[0] = norm[1] = 0.0;
norm[2] = TMath::Sign(1., dir[2]);
return;
}
Double_t talf = 2.*TMath::Sqrt(fA*(point[2]-fB))*TMath::Sign(1.0, fA);
Double_t calf = 1./TMath::Sqrt(1.+talf*talf);
Double_t salf = talf * calf;
Double_t phi = TMath::ATan2(point[1], point[0]);
if (phi<0) phi+=2.*TMath::Pi();
Double_t cphi = TMath::Cos(phi);
Double_t sphi = TMath::Sin(phi);
Double_t ct   = - calf*TMath::Sign(1.,fA);
Double_t st   = salf*TMath::Sign(1.,fA);

norm[0] = st*cphi;
norm[1] = st*sphi;
norm[2] = ct;
Double_t ndotd = norm[0]*dir[0]+norm[1]*dir[1]+norm[2]*dir[2];
if (ndotd < 0) {
norm[0] = -norm[0];
norm[1] = -norm[1];
norm[2] = -norm[2];
}
}

//_____________________________________________________________________________
Bool_t TGeoParaboloid::Contains(Double_t *point) const
{
// test if point is inside the elliptical tube
if (TMath::Abs(point[2])>fDz) return kFALSE;
Double_t aa = fA*(point[2]-fB);
if (aa < 0) return kFALSE;
Double_t rsq = point[0]*point[0]+point[1]*point[1];
if (aa < fA*fA*rsq) return kFALSE;
return kTRUE;
}

//_____________________________________________________________________________
Int_t TGeoParaboloid::DistancetoPrimitive(Int_t px, Int_t py)
{
// compute closest distance from point px,py to each vertex
Int_t n = gGeoManager->GetNsegments();
const Int_t numPoints=n*(n+1)+2;
return ShapeDistancetoPrimitive(numPoints, px, py);
}

//_____________________________________________________________________________
Double_t TGeoParaboloid::DistToParaboloid(Double_t *point, Double_t *dir) const
{
// Compute distance from a point to the parabola given by:
//  z = a*rsq + b;   rsq = x*x+y*y
Double_t a = fA * (dir[0]*dir[0] + dir[1]*dir[1]);
Double_t b = 2.*fA*(point[0]*dir[0]+point[1]*dir[1])-dir[2];
Double_t c = fA*(point[0]*point[0]+point[1]*point[1]) + fB - point[2];
Double_t dist = TGeoShape::Big();
if (a==0) {
if (b==0) return dist; // big
dist = -c/b;
if (dist < 0) return TGeoShape::Big();
return dist; // OK
}
Double_t ainv = 1./a;
Double_t sum = - b*ainv;
Double_t prod = c*ainv;
Double_t delta = sum*sum - 4.*prod;
if (delta<0) return dist; // big
if (prod == 0) return 0.;
if (prod < 0) {
dist = 0.5*(sum + TMath::Sqrt(delta));
return dist; // OK
}
if (sum < 0) return dist; // big
dist = 0.5 * (sum - TMath::Sqrt(delta));
return dist; // OK
}

//_____________________________________________________________________________
Double_t TGeoParaboloid::DistFromInside(Double_t *point, Double_t *dir, Int_t iact, Double_t step, Double_t *safe) const
{
// compute distance from inside point to surface of the paraboloid
if (iact<3 && safe) {
// compute safe distance
*safe = Safety(point, kTRUE);
if (iact==0) return TGeoShape::Big();
if (iact==1 && step<*safe) return TGeoShape::Big();
}

Double_t dz = TGeoShape::Big();
if (dir[2]<0) {
dz = -(point[2]+fDz)/dir[2];
} else if (dir[2]>0) {
dz = (fDz-point[2])/dir[2];
}
Double_t dpara = DistToParaboloid(point, dir);
return TMath::Min(dz, dpara);
}

//_____________________________________________________________________________
Double_t TGeoParaboloid::DistFromOutside(Double_t *point, Double_t *dir, Int_t iact, Double_t step, Double_t *safe) const
{
// compute distance from outside point to surface of the paraboloid and safe distance
Double_t snxt = TGeoShape::Big();
if (iact<3 && safe) {
// compute safe distance
*safe = Safety(point, kFALSE);
if (iact==0) return TGeoShape::Big();
if (iact==1 && step<*safe) return TGeoShape::Big();
}
Double_t xnew, ynew, znew;
if (point[2]<=-fDz) {
if (dir[2]<=0) return TGeoShape::Big();
snxt = -(fDz+point[2])/dir[2];
// find extrapolated X and Y
xnew = point[0]+snxt*dir[0];
ynew = point[1]+snxt*dir[1];
if ((xnew*xnew+ynew*ynew) <= fRlo*fRlo) return snxt;
} else if (point[2]>=fDz) {
if (dir[2]>=0) return TGeoShape::Big();
snxt = (fDz-point[2])/dir[2];
// find extrapolated X and Y
xnew = point[0]+snxt*dir[0];
ynew = point[1]+snxt*dir[1];
if ((xnew*xnew+ynew*ynew) <= fRhi*fRhi) return snxt;
}
snxt = DistToParaboloid(point, dir);
if (snxt > 1E20) return snxt;
znew = point[2]+snxt*dir[2];
if (TMath::Abs(znew) <= fDz) return snxt;
return TGeoShape::Big();
}

//_____________________________________________________________________________
TGeoVolume *TGeoParaboloid::Divide(TGeoVolume * /*voldiv*/, const char * /*divname*/, Int_t /*iaxis*/, Int_t /*ndiv*/,
Double_t /*start*/, Double_t /*step*/)
{
// Divide the paraboloid along one axis.
Error("Divide", "Paraboloid divisions not implemented");
return 0;
}

//_____________________________________________________________________________
void TGeoParaboloid::GetBoundingCylinder(Double_t *param) const
{
//--- Fill vector param[4] with the bounding cylinder parameters. The order
// is the following : Rmin, Rmax, Phi1, Phi2
param[0] = 0.;                  // Rmin
param[1] = fDX;                 // Rmax
param[1] *= param[1];
param[2] = 0.;                  // Phi1
param[3] = 360.;                // Phi2
}

//_____________________________________________________________________________
TGeoShape *TGeoParaboloid::GetMakeRuntimeShape(TGeoShape *, TGeoMatrix *) const
{
// in case shape has some negative parameters, these has to be computed
// in order to fit the mother
return 0;
}

//_____________________________________________________________________________
void TGeoParaboloid::InspectShape() const
{
// print shape parameters
printf("*** Shape %s: TGeoParaboloid ***\n", GetName());
printf("    rlo    = %11.5f\n", fRlo);
printf("    rhi    = %11.5f\n", fRhi);
printf("    dz     = %11.5f\n", fDz);
printf(" Bounding box:\n");
TGeoBBox::InspectShape();
}

//_____________________________________________________________________________
TBuffer3D *TGeoParaboloid::MakeBuffer3D() const
{
// Creates a TBuffer3D describing *this* shape.
// Coordinates are in local reference frame.

Int_t n = gGeoManager->GetNsegments();
Int_t nbPnts = n*(n+1)+2;
Int_t nbSegs = n*(2*n+3);
Int_t nbPols = n*(n+2);

TBuffer3D* buff = new TBuffer3D(TBuffer3DTypes::kGeneric,
nbPnts, 3*nbPnts, nbSegs, 3*nbSegs, nbPols, 2*n*5 + n*n*6);

if (buff)
{
SetPoints(buff->fPnts);
SetSegsAndPols(*buff);
}

return buff;
}

//_____________________________________________________________________________
void TGeoParaboloid::SetSegsAndPols(TBuffer3D &buff) const
{
// Fill TBuffer3D structure for segments and polygons.
Int_t indx, i, j;
Int_t n = gGeoManager->GetNsegments();

Int_t c = GetBasicColor();

Int_t nn1 = (n+1)*n+1;
indx = 0;
// Lower end-cap (n radial segments)
for (j=0; j<n; j++) {
buff.fSegs[indx++] = c+2;
buff.fSegs[indx++] = 0;
buff.fSegs[indx++] = j+1;
}
// Sectors (n)
for (i=0; i<n+1; i++) {
// lateral (circles) segments (n)
for (j=0; j<n; j++) {
buff.fSegs[indx++] = c;
buff.fSegs[indx++] = n*i+1+j;
buff.fSegs[indx++] = n*i+1+((j+1)%n);
}
if (i==n) break;  // skip i=n for generators
// generator segments (n)
for (j=0; j<n; j++) {
buff.fSegs[indx++] = c;
buff.fSegs[indx++] = n*i+1+j;
buff.fSegs[indx++] = n*(i+1)+1+j;
}
}
// Upper end-cap
for (j=0; j<n; j++) {
buff.fSegs[indx++] = c+1;
buff.fSegs[indx++] = n*n+1+j;
buff.fSegs[indx++] = nn1;
}

indx = 0;

// lower end-cap (n polygons)
for (j=0; j<n; j++) {
buff.fPols[indx++] = c+2;
buff.fPols[indx++] = 3;
buff.fPols[indx++] = n+j;
buff.fPols[indx++] = (j+1)%n;
buff.fPols[indx++] = j;
}
// Sectors (n)
for (i=0; i<n; i++) {
// lateral faces (n)
for (j=0; j<n; j++) {
buff.fPols[indx++] = c;
buff.fPols[indx++] = 4;
buff.fPols[indx++] = (2*i+1)*n+j;
buff.fPols[indx++] = 2*(i+1)*n+j;
buff.fPols[indx++] = (2*i+3)*n+j;
buff.fPols[indx++] = 2*(i+1)*n+((j+1)%n);
}
}
// upper end-cap (n polygons)
for (j=0; j<n; j++) {
buff.fPols[indx++] = c+1;
buff.fPols[indx++] = 3;
buff.fPols[indx++] = 2*n*(n+1)+j;
buff.fPols[indx++] = 2*n*(n+1)+((j+1)%n);
buff.fPols[indx++] = (2*n+1)*n+j;
}
}

//_____________________________________________________________________________
Double_t TGeoParaboloid::Safety(Double_t * /*point*/, Bool_t /*in*/) const
{
// computes the closest distance from given point to this shape, according
// to option. The matching point on the shape is stored in spoint.
return TGeoShape::Big();
}

//_____________________________________________________________________________
void TGeoParaboloid::SetParaboloidDimensions(Double_t rlo, Double_t rhi, Double_t dz)
{
// Set paraboloid dimensions.
if ((rlo<0) || (rlo<0) || (dz<=0) || (rlo==rhi)) {
SetShapeBit(kGeoRunTimeShape);
Error("SetParaboloidDimensions", "Dimensions of %s invalid: check (rlo>=0) (rhi>=0) (rlo!=rhi) dz>0",GetName());
return;
}
fRlo = rlo;
fRhi = rhi;
fDz  = dz;
Double_t dd = 1./(fRhi*fRhi - fRlo*fRlo);
fA = 2.*fDz*dd;
fB = - fDz * (fRlo*fRlo + fRhi*fRhi)*dd;
}

//_____________________________________________________________________________
void TGeoParaboloid::SetDimensions(Double_t *param)
{
// Set paraboloid dimensions starting from an array.
Double_t rlo    = param[0];
Double_t rhi    = param[1];
Double_t dz     = param[2];
SetParaboloidDimensions(rlo, rhi, dz);
}

//_____________________________________________________________________________
void TGeoParaboloid::SetPoints(Double_t *points) const
{
// Create paraboloid mesh points.
// Npoints = n*(n+1) + 2
//   ifirst = 0
//   ipoint(i,j) = 1+i*n+j;                              i=[0,n]  j=[0,n-1]
//   ilast = 1+n*(n+1)
// Nsegments = n*(2*n+3)
//   lower: (0, j+1);                                    j=[0,n-1]
//   circle(i): (n*i+1+j, n*i+1+(j+1)%n);                i=[0,n]  j=[0,n-1]
//   generator(i): (n*i+1+j, n*(i+1)+1+j);               i,j=[0,n-1]
//   upper: (n*n+1+j, (n+1)*n+1)                           j=[0,n-1]
// Npolygons = n*(n+2)
//   lower: (n+j, (j+1)%n, j)                              j=[0,n-1]
//   lateral(i): ((2*i+1)*n+j, 2*(i+1)*n+j, (2*i+3)*n+j, 2*(i+1)*n+(j+1)%n)
//                                                      i,j = [0,n-1]
//   upper: ((2n+1)*n+j, 2*n*(n+1)+(j+1)%n, 2*n*(n+1)+j)   j=[0,n-1]
if (!points) return;
Double_t ttmin, ttmax;
ttmin = TMath::ATan2(-fDz, fRlo);
ttmax = TMath::ATan2(fDz, fRhi);
Int_t n = gGeoManager->GetNsegments();
Double_t dtt = (ttmax-ttmin)/n;
Double_t dphi = 360./n;
Double_t tt;
Double_t r, z, delta;
Double_t phi, sph, cph;
Int_t indx = 0;
// center of the lower endcap:
points[indx++] = 0; // x
points[indx++] = 0; // y
points[indx++] = -fDz;
for (Int_t i=0; i<n+1; i++) {  // nz planes = n+1
if (i==0) {
r = fRlo;
z = -fDz;
} else if (i==n) {
r = fRhi;
z = fDz;
} else {
tt = TMath::Tan(ttmin + i*dtt);
delta = tt*tt - 4*fA*fB; // should be always positive (a*b<0)
r = 0.5*(tt+TMath::Sqrt(delta))/fA;
z = r*tt;
}
for (Int_t j=0; j<n; j++) {
sph=TMath::Sin(phi);
cph=TMath::Cos(phi);
points[indx++] = r*cph;
points[indx++] = r*sph;
points[indx++] = z;
}
}
// center of the upper endcap
points[indx++] = 0; // x
points[indx++] = 0; // y
points[indx++] = fDz;
}

//_____________________________________________________________________________
void TGeoParaboloid::GetMeshNumbers(Int_t &nvert, Int_t &nsegs, Int_t &npols) const
{
// Returns numbers of vertices, segments and polygons composing the shape mesh.
Int_t n = gGeoManager->GetNsegments();
nvert = n*(n+1)+2;
nsegs = n*(2*n+3);
npols = n*(n+2);
}

//_____________________________________________________________________________
Int_t TGeoParaboloid::GetNmeshVertices() const
{
// Returns number of vertices on the paraboloid mesh.
Int_t n = gGeoManager->GetNsegments();
return (n*(n+1)+2);
}

//_____________________________________________________________________________
void TGeoParaboloid::SavePrimitive(ostream &out, Option_t * /*option*/ /*= ""*/)
{
// Save a primitive as a C++ statement(s) on output stream "out".
if (TObject::TestBit(kGeoSavePrimitive)) return;
out << "   // Shape: " << GetName() << " type: " << ClassName() << endl;
out << "   rlo = " << fRlo << ";" << endl;
out << "   rhi = " << fRhi << ";" << endl;
out << "   dz  = " << fDZ << ";" << endl;
out << "   TGeoShape *" << GetPointerName() << " = new TGeoParaboloid(\"" << GetName() << "\", rlo,rhi,dz);" << endl;
TObject::SetBit(TGeoShape::kGeoSavePrimitive);
}

//_____________________________________________________________________________
void TGeoParaboloid::SetPoints(Float_t *points) const
{
// Create paraboloid mesh points.
if (!points) return;
Double_t ttmin, ttmax;
ttmin = TMath::ATan2(-fDz, fRlo);
ttmax = TMath::ATan2(fDz, fRhi);
Int_t n = gGeoManager->GetNsegments();
Double_t dtt = (ttmax-ttmin)/n;
Double_t dphi = 360./n;
Double_t tt;
Double_t r, z, delta;
Double_t phi, sph, cph;
Int_t indx = 0;
// center of the lower endcap:
points[indx++] = 0; // x
points[indx++] = 0; // y
points[indx++] = -fDz;
for (Int_t i=0; i<n+1; i++) {  // nz planes = n+1
if (i==0) {
r = fRlo;
z = -fDz;
} else if (i==n) {
r = fRhi;
z = fDz;
} else {
tt = TMath::Tan(ttmin + i*dtt);
delta = tt*tt - 4*fA*fB; // should be always positive (a*b<0)
r = 0.5*(tt+TMath::Sqrt(delta))/fA;
z = r*tt;
}
for (Int_t j=0; j<n; j++) {
sph=TMath::Sin(phi);
cph=TMath::Cos(phi);
points[indx++] = r*cph;
points[indx++] = r*sph;
points[indx++] = z;
}
}
// center of the upper endcap
points[indx++] = 0; // x
points[indx++] = 0; // y
points[indx++] = fDz;
}

//_____________________________________________________________________________
void TGeoParaboloid::Sizeof3D() const
{
///   Int_t n = gGeoManager->GetNsegments();
///   TVirtualGeoPainter *painter = gGeoManager->GetGeomPainter();
///   if (painter) painter->AddSize3D(n*(n+1)+2, n*(2*n+3), n*(n+2));
}

//_____________________________________________________________________________
const TBuffer3D & TGeoParaboloid::GetBuffer3D(Int_t reqSections, Bool_t localFrame) const
{
// Fills a static 3D buffer and returns a reference.
static TBuffer3D buffer(TBuffer3DTypes::kGeneric);
TGeoBBox::FillBuffer3D(buffer, reqSections, localFrame);

if (reqSections & TBuffer3D::kRawSizes) {
Int_t n = gGeoManager->GetNsegments();
Int_t nbPnts = n*(n+1)+2;
Int_t nbSegs = n*(2*n+3);
Int_t nbPols = n*(n+2);
if (buffer.SetRawSizes(nbPnts, 3*nbPnts, nbSegs, 3*nbSegs, nbPols, 2*n*5 + n*n*6)) {
buffer.SetSectionsValid(TBuffer3D::kRawSizes);
}
}
if ((reqSections & TBuffer3D::kRaw) && buffer.SectionsValid(TBuffer3D::kRawSizes)) {
SetPoints(buffer.fPnts);
if (!buffer.fLocalFrame) {
TransformPoints(buffer.fPnts, buffer.NbPnts());
}
SetSegsAndPols(buffer);
buffer.SetSectionsValid(TBuffer3D::kRaw);
}

return buffer;
}
```

Last update: Thu Jan 17 08:55:57 2008

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.