#include "TXTRU.h"
#include "TVirtualPad.h"
#include "TBuffer3D.h"
#include "TBuffer3DTypes.h"
#include "TGeometry.h"
#include "TMath.h"
#include "Riostream.h"
ClassImp(TXTRU)
TXTRU::TXTRU()
: fNxy(0), fNxyAlloc(0), fNz(0), fNzAlloc(0), fXvtx(0), fYvtx(0),
fZ(0), fScale(0), fX0(0), fY0(0)
{
fPolygonShape = kUncheckedXY;
fZOrdering = kUncheckedZ;
fSplitConcave = kFALSE;
}
TXTRU::TXTRU(const char *name, const char *title, const char *material,
Int_t nxy, Int_t nz)
: TShape (name,title,material)
{
fNxy = 0;
fNxyAlloc = 0;
fNz = 0;
fNzAlloc = 0;
fXvtx = 0;
fYvtx = 0;
fZ = 0;
fScale = 0;
fX0 = 0;
fY0 = 0;
fPolygonShape = kUncheckedXY;
fZOrdering = kUncheckedZ;
fSplitConcave = kFALSE;
if ( nxy < 3 ) {
Error(name,"number of x-y points for %s must be at least three!",name);
return;
}
if ( nz < 2 ) {
Error(name,"number of z points for %s must be at least two!",name);
return;
}
fNxy = nxy;
fNxyAlloc = nxy;
fXvtx = new Float_t [fNxyAlloc];
fYvtx = new Float_t [fNxyAlloc];
Int_t i = 0;
for (i = 0; i < fNxyAlloc; i++) {
fXvtx[i] = 0;
fYvtx[i] = 0;
}
fNz = nz;
fNzAlloc = nz;
fZ = new Float_t [fNzAlloc];
fScale = new Float_t [fNzAlloc];
fX0 = new Float_t [fNzAlloc];
fY0 = new Float_t [fNzAlloc];
Int_t j = 0;
for (j = 0; j < fNzAlloc; j++) {
fZ[j] = 0;
fScale[j] = 0;
fX0[j] = 0;
fY0[j] = 0;
}
}
TXTRU::TXTRU(const TXTRU &xtru) : TShape(xtru)
{
((TXTRU&)xtru).Copy(*this);
}
TXTRU::~TXTRU()
{
if (fXvtx) delete [] fXvtx;
if (fYvtx) delete [] fYvtx;
fXvtx = 0;
fYvtx = 0;
fNxy = 0;
fNxyAlloc = 0;
if (fZ) delete [] fZ;
if (fScale) delete [] fScale;
if (fX0) delete [] fX0;
if (fY0) delete [] fY0;
fZ = 0;
fScale = 0;
fX0 = 0;
fY0 = 0;
fNz = 0;
fNzAlloc = 0;
fPolygonShape = kUncheckedXY;
fZOrdering = kUncheckedZ;
}
TXTRU& TXTRU::operator=(const TXTRU &rhs)
{
if (this == &rhs) return *this;
if (fNxyAlloc) {
delete [] fXvtx;
delete [] fYvtx;
}
if (fNzAlloc) {
delete [] fZ;
delete [] fScale;
delete [] fX0;
delete [] fY0;
}
((TXTRU&)rhs).Copy(*this);
return *this;
}
void TXTRU::Copy(TObject &obj) const
{
TObject::Copy(obj);
((TXTRU&)obj).fNxy = fNxy;
((TXTRU&)obj).fNxyAlloc = fNxyAlloc;
((TXTRU&)obj).fXvtx = new Float_t [fNxyAlloc];
((TXTRU&)obj).fYvtx = new Float_t [fNxyAlloc];
Int_t i = 0;
for (i = 0; i < fNxyAlloc; i++) {
((TXTRU&)obj).fXvtx[i] = fXvtx[i];
((TXTRU&)obj).fYvtx[i] = fYvtx[i];
}
((TXTRU&)obj).fNz = fNz;
((TXTRU&)obj).fNzAlloc = fNzAlloc;
((TXTRU&)obj).fZ = new Float_t [fNzAlloc];
((TXTRU&)obj).fScale = new Float_t [fNzAlloc];
((TXTRU&)obj).fX0 = new Float_t [fNzAlloc];
((TXTRU&)obj).fY0 = new Float_t [fNzAlloc];
Int_t j = 0;
for (j = 0; j < fNzAlloc; j++) {
((TXTRU&)obj).fZ[j] = fZ[j];
((TXTRU&)obj).fScale[j] = fScale[j];
((TXTRU&)obj).fX0[j] = fX0[j];
((TXTRU&)obj).fY0[j] = fY0[j];
}
((TXTRU&)obj).fPolygonShape = fPolygonShape;
((TXTRU&)obj).fZOrdering = fZOrdering;
}
void TXTRU::DefineSection(Int_t iz, Float_t z, Float_t scale, Float_t x0, Float_t y0)
{
if (iz < 0) return;
fZOrdering = kUncheckedZ;
if (!fZ || !fScale || iz >= fNzAlloc) {
Int_t newNalloc = iz + 1;
Float_t *newZ = new Float_t [newNalloc];
Float_t *newS = new Float_t [newNalloc];
Float_t *newX = new Float_t [newNalloc];
Float_t *newY = new Float_t [newNalloc];
Int_t i = 0;
for (i = 0; i < newNalloc; i++) {
if (i<fNz) {
newZ[i] = fZ[i];
newS[i] = fScale[i];
newX[i] = fX0[i];
newY[i] = fY0[i];
} else {
newZ[i] = 0;
newS[i] = 0;
newX[i] = 0;
newY[i] = 0;
}
}
delete [] fZ;
delete [] fScale;
delete [] fX0;
delete [] fY0;
fZ = newZ;
fScale = newS;
fX0 = newX;
fY0 = newY;
fNzAlloc = newNalloc;
}
fNz = TMath::Max(iz+1,fNz);
fZ[iz] = z;
fScale[iz] = scale;
fX0[iz] = x0;
fY0[iz] = y0;
}
void TXTRU::DefineVertex(Int_t ipt, Float_t x, Float_t y) {
if (ipt < 0) return;
fPolygonShape = kUncheckedXY;
if (!fXvtx || !fYvtx || ipt >= fNxyAlloc) {
Int_t newNalloc = ipt + 1;
Float_t *newX = new Float_t [newNalloc];
Float_t *newY = new Float_t [newNalloc];
Int_t i = 0;
for (i = 0; i < newNalloc; i++) {
if (i<fNxy) {
newX[i] = fXvtx[i];
newY[i] = fYvtx[i];
} else {
newX[i] = 0;
newY[i] = 0;
}
}
delete [] fXvtx;
delete [] fYvtx;
fXvtx = newX;
fYvtx = newY;
fNxyAlloc = newNalloc;
}
fNxy = TMath::Max(ipt+1,fNxy);
fXvtx[ipt] = x;
fYvtx[ipt] = y;
}
Int_t TXTRU::DistancetoPrimitive(Int_t px, Int_t py)
{
Int_t numPoints = fNz*fNxy;
return ShapeDistancetoPrimitive(numPoints,px,py);
}
Float_t TXTRU::GetOutlinePointX(Int_t n) const {
if ((n < 0) || (n >= fNxy)) {
Error(fName,"no such point %d [of %d]",n,fNxy);
return 0.0;
}
return fXvtx[n];
}
Float_t TXTRU::GetOutlinePointY(Int_t n) const {
if ((n < 0) || (n >= fNxy)) {
Error(fName,"no such point %d [of %d]",n,fNxy);
return 0.0;
}
return fYvtx[n];
}
Float_t TXTRU::GetSectionX0(Int_t n) const {
if ((n < 0) || (n >= fNz)) {
Error(fName,"no such section %d [of %d]",n,fNz);
return 0.0;
}
return fX0[n];
}
Float_t TXTRU::GetSectionY0(Int_t n) const {
if ((n < 0) || (n >= fNz)) {
Error(fName,"no such section %d [of %d]",n,fNz);
return 0.0;
}
return fY0[n];
}
Float_t TXTRU::GetSectionScale(Int_t n) const {
if ((n < 0) || (n >= fNz)) {
Error(fName,"no such section %d [of %d]",n,fNz);
return 0.0;
}
return fScale[n];
}
Float_t TXTRU::GetSectionZ(Int_t n) const {
if ((n < 0) || (n >= fNz)) {
Error(fName,"no such section %d [of %d]",n,fNz);
return 0.0;
}
return fZ[n];
}
void TXTRU::Print(Option_t *option) const
{
TString opt = option;
opt.ToLower();
printf("TXTRU %s Nxy=%d [of %d] Nz=%d [of %d] Option=%s\n",
GetName(),fNxy,fNxyAlloc,fNz,fNzAlloc,option);
const char *shape = 0;
const char *zorder = 0;
switch (fPolygonShape) {
case kUncheckedXY: shape = "Unchecked "; break;
case kMalformedXY: shape = "Malformed "; break;
case kConvexCCW: shape = "Convex CCW "; break;
case kConvexCW: shape = "Convex CW "; break;
case kConcaveCCW: shape = "Concave CCW"; break;
case kConcaveCW: shape = "Concave CW "; break;
}
switch (fZOrdering) {
case kUncheckedZ: zorder = "Unchecked Z"; break;
case kMalformedZ: zorder = "Malformed Z"; break;
case kConvexIncZ: zorder = "Convex Increasing Z"; break;
case kConvexDecZ: zorder = "Convex Decreasing Z"; break;
case kConcaveIncZ: zorder = "Concave Increasing Z"; break;
case kConcaveDecZ: zorder = "Concave Decreasing Z"; break;
}
printf(" XY shape '%s', '%s'\n",shape,zorder);
Int_t nxy, nz;
if (opt.Contains("alloc")) {
nxy = fNxy;
nz = fNz;
} else {
nxy = fNxyAlloc;
nz = fNzAlloc;
}
const char *name;
Float_t *p;
Int_t nlimit;
Bool_t print_vtx = opt.Contains("xy");
Bool_t print_z = opt.Contains("z");
Int_t ixyz=0;
for (ixyz=0; ixyz<6; ixyz++) {
switch (ixyz) {
case 0: p = fXvtx; name = "x"; nlimit = nxy; break;
case 1: p = fYvtx; name = "y"; nlimit = nxy; break;
case 2: p = fZ; name = "z"; nlimit = nz; break;
case 3: p = fScale; name = "scale"; nlimit = nz; break;
case 4: p = fX0; name = "x0"; nlimit = nz; break;
case 5: p = fY0; name = "y0"; nlimit = nz; break;
default: continue;
}
if (ixyz<=1 && !print_vtx) continue;
if (ixyz>=2 && !print_z) continue;
printf(" Float_t %s[] = \n { %10g",name,*p++);
Int_t i=1;
for (i=1;i<nlimit;i++) {
printf(", %10g",*p++);
if (i%6==5) printf("\n ");
}
printf(" };\n");
}
}
void TXTRU::SetPoints(Double_t *points) const
{
if (points) {
Int_t ipt, ixy, iz, ioff;
Float_t x, y;
Bool_t iscw = (fPolygonShape == kConvexCW ||
fPolygonShape == kConcaveCW );
Bool_t reversez = (fZOrdering == kConvexDecZ ||
fZOrdering == kConcaveDecZ );
ipt = 0;
Int_t i=0;
for (i=0; i<fNz; i++) {
iz = (reversez) ? fNz-1 - i : i;
Int_t j=0;
for (j=0; j<fNxy; j++) {
ixy = (iscw) ? fNxy-1 - j : j;
ioff = ipt*3;
x = fXvtx[ixy];
y = fYvtx[ixy];
points[ioff ] = x*fScale[iz] + fX0[iz];
points[ioff+1] = y*fScale[iz] + fY0[iz];
points[ioff+2] = fZ[iz];
ipt++;
}
}
}
}
void TXTRU::Sizeof3D() const
{
gSize3D.numPoints += fNz*fNxy;
gSize3D.numSegs += (2*fNz-1)*fNxy;
gSize3D.numPolys += (fNz-1)*fNxy+2;
}
void TXTRU::SplitConcavePolygon(Bool_t split)
{
fSplitConcave = split;
if (split) {
fSplitConcave = kFALSE;
cout << TNamed::GetName()
<< " TXTRU::SplitConcavePolygon is not yet implemented" << endl;
}
}
void TXTRU::TruncateNxy(Int_t npts) {
if ((npts < 0) || (npts > fNxy)) {
Error(fName,"truncate to %d impossible on %d points",npts,fNxy);
return;
}
fNxy = npts;
return;
}
void TXTRU::TruncateNz(Int_t nz) {
if ((nz < 0) || (nz > fNz)) {
Error(fName,"truncate to %d impossible on %d points",nz,fNz);
return;
}
fNz = nz;
return;
}
void TXTRU::CheckOrdering()
{
Float_t plus, minus, zero;
plus = minus = zero = 0;
Int_t ixy=0;
for (ixy=0; ixy<fNxy; ixy++) {
Int_t ixyprev = (ixy + fNxy - 1)%fNxy;
Int_t ixynext = (ixy + fNxy + 1)%fNxy;
Float_t dxprev = fXvtx[ixy] - fXvtx[ixyprev];
Float_t dyprev = fYvtx[ixy] - fYvtx[ixyprev];
Float_t dxnext = fXvtx[ixynext] - fXvtx[ixy];
Float_t dynext = fYvtx[ixynext] - fYvtx[ixy];
Float_t xprod = dxprev*dynext - dxnext*dyprev;
if (xprod > 0) {
plus += xprod;
} else if (xprod < 0) {
minus -= xprod;
} else {
zero++;
}
}
if (fNxy<3) {
fPolygonShape = kMalformedXY;
} else {
if (plus==0 || minus==0) {
if (plus>minus) {
fPolygonShape = kConvexCCW;
} else {
fPolygonShape = kConvexCW;
}
} else {
if (plus>minus) {
fPolygonShape = kConcaveCCW;
} else {
fPolygonShape = kConcaveCW;
}
}
}
plus = minus = zero = 0;
Bool_t scaleSignChange = kFALSE;
Int_t iz=0;
for (iz=0; iz<fNz; iz++) {
Int_t izprev = (iz + fNz - 1)%fNz;
Int_t iznext = (iz + fNz + 1)%fNz;
Float_t dzprev = fZ[iz] - fZ[izprev];
Float_t dsprev = fScale[iz] - fScale[izprev];
Float_t dznext = fZ[iznext] - fZ[iz];
Float_t dsnext = fScale[iznext] - fScale[iz];
if (iz==0) {
dzprev = 0;
dsprev = fScale[0];
} else if (iz==fNz-1) {
dznext = 0;
dsnext = -fScale[iz];
}
Float_t xprod = dznext*dsprev - dzprev*dsnext;
if (xprod > 0) {
plus += xprod;
} else if (xprod < 0) {
minus -= xprod;
} else {
zero++;
}
if (fScale[iz]*fScale[iznext] < 0) scaleSignChange = kTRUE;
}
if (fNz<1 || scaleSignChange) {
fZOrdering = kMalformedZ;
} else {
if (plus==0 || minus==0) {
if (plus>minus) {
fZOrdering = kConvexIncZ;
} else {
fZOrdering = kConvexDecZ;
}
} else {
if (plus>minus) {
fZOrdering = kConcaveIncZ;
} else {
fZOrdering = kConcaveDecZ;
}
}
}
}
void TXTRU::DumpPoints(int npoints, float *pointbuff) const
{
cout << "TXTRU::DumpPoints - " << npoints << " points" << endl;
int ioff = 0;
float x,y,z;
int ipt=0;
for (ipt=0; ipt<npoints; ipt++) {
x = pointbuff[ioff++];
y = pointbuff[ioff++];
z = pointbuff[ioff++];
printf(" [%4d] %6.1f %6.1f %6.1f \n",ipt,x,y,z);
}
}
void TXTRU::DumpSegments(int nsegments, int *segbuff) const
{
cout << "TXTRU::DumpSegments - " << nsegments << " segments" << endl;
int ioff = 0;
int icol, p1, p2;
int iseg=0;
for (iseg=0; iseg<nsegments; iseg++) {
icol = segbuff[ioff++];
p1 = segbuff[ioff++];
p2 = segbuff[ioff++];
printf(" [%4d] %3d (%4d,%4d)\n",iseg,icol,p1,p2);
}
}
void TXTRU::DumpPolygons(int npolygons, int *polybuff, int buffsize) const
{
cout << "TXTRU::DumpPolygons - " << npolygons << " polygons" << endl;
int ioff = 0;
int icol, nseg, iseg;
int ipoly=0;
for (ipoly=0; ipoly<npolygons; ipoly++) {
icol = polybuff[ioff++];
nseg = polybuff[ioff++];
#ifndef R__MACOSX
cout << " [" << setw(4) << ipoly << "] icol " << setw(3) << icol
<< " nseg " << setw(3) << nseg << " (";
#else
printf(" [%d4] icol %d3 nseg %d3 (", ipoly, icol, nseg);
#endif
for (iseg=0; iseg<nseg-1; iseg++) {
cout << polybuff[ioff++] << ",";
}
cout << polybuff[ioff++] << ")" << endl;
}
cout << " buffer size " << buffsize << " last used " << --ioff << endl;
}
const TBuffer3D & TXTRU::GetBuffer3D(Int_t reqSections) const
{
static TBuffer3D buffer(TBuffer3DTypes::kGeneric);
TShape::FillBuffer3D(buffer, reqSections);
if (reqSections & TBuffer3D::kRawSizes) {
if (fPolygonShape == kUncheckedXY ||
fZOrdering == kUncheckedZ) {
const_cast<TXTRU *>(this)->CheckOrdering();
}
Int_t nbPnts = fNz*fNxy;
Int_t nbSegs = fNxy*(2*fNz-1);
Int_t nbPols = fNxy*(fNz-1)+2;
if (buffer.SetRawSizes(nbPnts, 3*nbPnts, nbSegs, 3*nbSegs, nbPols, 6*(nbPols-2)+2*(2+fNxy))) {
buffer.SetSectionsValid(TBuffer3D::kRawSizes);
}
}
if (reqSections & TBuffer3D::kRaw) {
SetPoints(buffer.fPnts);
if (!buffer.fLocalFrame) {
TransformPoints(buffer.fPnts, buffer.NbPnts());
}
Int_t c = GetBasicColor();
Int_t i,j, k;
Int_t indx, indx2;
indx = indx2 = 0;
for (i=0; i<fNz; i++) {
indx2 = i*fNxy;
for (j=0; j<fNxy; j++) {
k = (j+1)%fNxy;
buffer.fSegs[indx++] = c;
buffer.fSegs[indx++] = indx2+j;
buffer.fSegs[indx++] = indx2+k;
}
}
for (i=0; i<fNz-1; i++) {
indx2 = i*fNxy;
for (j=0; j<fNxy; j++) {
k = j + fNxy;
buffer.fSegs[indx++] = c;
buffer.fSegs[indx++] = indx2+j;
buffer.fSegs[indx++] = indx2+k;
}
}
indx = 0;
for (i=0; i<fNz-1; i++) {
indx2 = i*fNxy;
for (j=0; j<fNxy; j++) {
k = (j+1)%fNxy;
buffer.fPols[indx++] = c+j%3;
buffer.fPols[indx++] = 4;
buffer.fPols[indx++] = indx2+j;
buffer.fPols[indx++] = fNz*fNxy+indx2+k;
buffer.fPols[indx++] = indx2+fNxy+j;
buffer.fPols[indx++] = fNz*fNxy+indx2+j;
}
}
buffer.fPols[indx++] = c+2;
buffer.fPols[indx++] = fNxy;
indx2 = 0;
for (j = fNxy - 1; j >= 0; --j) {
buffer.fPols[indx++] = indx2+j;
}
buffer.fPols[indx++] = c;
buffer.fPols[indx++] = fNxy;
indx2 = (fNz-1)*fNxy;
for (j=0; j<fNxy; j++) {
buffer.fPols[indx++] = indx2+j;
}
buffer.SetSectionsValid(TBuffer3D::kRaw);
}
return buffer;
}