#include "Riostream.h"
#include "TGLBoundingBox.h"
#include "TGLIncludes.h"
#include "TMathBase.h"
ClassImp(TGLBoundingBox)
TGLBoundingBox::TGLBoundingBox() :
fVertex(8)
{
SetEmpty();
}
TGLBoundingBox::TGLBoundingBox(const TGLVertex3 vertex[8]) :
fVertex(8)
{
Set(vertex);
}
TGLBoundingBox::TGLBoundingBox(const Double_t vertex[8][3]) :
fVertex(8)
{
Set(vertex);
}
TGLBoundingBox::TGLBoundingBox(const TGLVertex3 & lowVertex, const TGLVertex3 & highVertex) :
fVertex(8)
{
SetAligned(lowVertex, highVertex);
}
TGLBoundingBox::TGLBoundingBox(const TGLBoundingBox & other) :
fVertex(8)
{
Set(other);
}
TGLBoundingBox::~TGLBoundingBox()
{
}
void TGLBoundingBox::UpdateCache()
{
fAxes[0].Set(fVertex[1] - fVertex[0]);
fAxes[1].Set(fVertex[3] - fVertex[0]);
fAxes[2].Set(fVertex[4] - fVertex[0]);
Bool_t fixZeroMagAxis = kFALSE;
Int_t zeroMagAxisInd = -1;
for (UInt_t i = 0; i<3; i++) {
fAxesNorm[i] = fAxes[i];
Double_t mag = fAxesNorm[i].Mag();
if (mag > 0.0) {
fAxesNorm[i] /= mag;
} else {
if (!fixZeroMagAxis && zeroMagAxisInd == -1) {
zeroMagAxisInd = i;
fixZeroMagAxis = kTRUE;
} else if (fixZeroMagAxis) {
fixZeroMagAxis = kFALSE;
}
}
}
if (fixZeroMagAxis) {
fAxesNorm[zeroMagAxisInd] = Cross(fAxesNorm[(zeroMagAxisInd+1)%3],
fAxesNorm[(zeroMagAxisInd+2)%3]);
}
TGLVector3 extents = Extents();
fVolume = TMath::Abs(extents.X() * extents.Y() * extents.Z());
fDiagonal = extents.Mag();
}
void TGLBoundingBox::Set(const TGLVertex3 vertex[8])
{
for (UInt_t v = 0; v < 8; v++) {
fVertex[v] = vertex[v];
}
UpdateCache();
}
void TGLBoundingBox::Set(const Double_t vertex[8][3])
{
for (UInt_t v = 0; v < 8; v++) {
for (UInt_t a = 0; a < 3; a++) {
fVertex[v][a] = vertex[v][a];
}
}
UpdateCache();
}
void TGLBoundingBox::Set(const TGLBoundingBox & other)
{
for (UInt_t v = 0; v < 8; v++) {
fVertex[v].Set(other.fVertex[v]);
}
UpdateCache();
}
void TGLBoundingBox::SetEmpty()
{
for (UInt_t v = 0; v < 8; v++) {
fVertex[v].Fill(0.0);
}
UpdateCache();
}
void TGLBoundingBox::SetAligned(const TGLVertex3 & lowVertex, const TGLVertex3 & highVertex)
{
TGLVector3 diff = highVertex - lowVertex;
if (diff.X() < 0.0 || diff.Y() < 0.0 || diff.Z() < 0.0) {
Error("TGLBoundingBox::SetAligned", "low/high vertex range error");
}
fVertex[0] = lowVertex;
fVertex[1] = lowVertex; fVertex[1].X() += diff.X();
fVertex[2] = lowVertex; fVertex[2].X() += diff.X(); fVertex[2].Y() += diff.Y();
fVertex[3] = lowVertex; fVertex[3].Y() += diff.Y();
fVertex[4] = highVertex; fVertex[4].X() -= diff.X(); fVertex[4].Y() -= diff.Y();
fVertex[5] = highVertex; fVertex[5].Y() -= diff.Y();
fVertex[6] = highVertex;
fVertex[7] = highVertex; fVertex[7].X() -= diff.X();
UpdateCache();
}
void TGLBoundingBox::SetAligned(UInt_t nbPnts, const Double_t * pnts)
{
if (nbPnts < 1 || !pnts) {
assert(false);
return;
}
TGLVertex3 low(pnts[0], pnts[1], pnts[2]);
TGLVertex3 high(pnts[0], pnts[1], pnts[2]);
for (UInt_t p = 1; p < nbPnts; p++) {
for (UInt_t i = 0; i < 3; i++) {
if (pnts[3*p + i] < low[i]) {
low[i] = pnts[3*p + i] ;
}
if (pnts[3*p + i] > high[i]) {
high[i] = pnts[3*p + i] ;
}
}
}
SetAligned(low, high);
}
void TGLBoundingBox::MergeAligned(const TGLBoundingBox & other)
{
if (other.IsEmpty()) return;
if (IsEmpty())
{
Set(other);
}
else
{
TGLVertex3 low (other.MinAAVertex());
TGLVertex3 high(other.MaxAAVertex());
low .Minimum(MinAAVertex());
high.Maximum(MaxAAVertex());
SetAligned(low, high);
}
}
void TGLBoundingBox::ExpandAligned(const TGLVertex3 & point)
{
TGLVertex3 low (MinAAVertex());
TGLVertex3 high(MaxAAVertex());
low .Minimum(point);
high.Maximum(point);
SetAligned(low, high);
}
void TGLBoundingBox::Scale(Double_t factor)
{
Scale(factor, factor, factor);
UpdateCache();
}
void TGLBoundingBox::Scale(Double_t xFactor, Double_t yFactor, Double_t zFactor)
{
const TGLVector3 xOffset = Axis(0, kFALSE)*(xFactor - 1.0) / 2.0;
const TGLVector3 yOffset = Axis(1, kFALSE)*(yFactor - 1.0) / 2.0;
const TGLVector3 zOffset = Axis(2, kFALSE)*(zFactor - 1.0) / 2.0;
fVertex[0] += -xOffset - yOffset - zOffset;
fVertex[1] += xOffset - yOffset - zOffset;
fVertex[2] += xOffset + yOffset - zOffset;
fVertex[3] += -xOffset + yOffset - zOffset;
fVertex[4] += -xOffset - yOffset + zOffset;
fVertex[5] += xOffset - yOffset + zOffset;
fVertex[6] += xOffset + yOffset + zOffset;
fVertex[7] += -xOffset + yOffset + zOffset;
UpdateCache();
}
void TGLBoundingBox::Translate(const TGLVector3 & offset)
{
for (UInt_t v = 0; v < 8; v++) {
fVertex[v] = fVertex[v] + offset;
}
}
void TGLBoundingBox::Transform(const TGLMatrix & matrix)
{
for (UInt_t v = 0; v < 8; v++) {
matrix.TransformVertex(fVertex[v]);
}
UpdateCache();
}
const std::vector<UInt_t> & TGLBoundingBox::FaceVertices(EFace face) const
{
static Bool_t init = kFALSE;
static std::vector<UInt_t> faceIndexes[kFaceCount];
if (!init) {
faceIndexes[kFaceLowX].push_back(7);
faceIndexes[kFaceLowX].push_back(4);
faceIndexes[kFaceLowX].push_back(0);
faceIndexes[kFaceLowX].push_back(3);
faceIndexes[kFaceHighX].push_back(2);
faceIndexes[kFaceHighX].push_back(1);
faceIndexes[kFaceHighX].push_back(5);
faceIndexes[kFaceHighX].push_back(6);
faceIndexes[kFaceLowY].push_back(5);
faceIndexes[kFaceLowY].push_back(1);
faceIndexes[kFaceLowY].push_back(0);
faceIndexes[kFaceLowY].push_back(4);
faceIndexes[kFaceHighY].push_back(2);
faceIndexes[kFaceHighY].push_back(6);
faceIndexes[kFaceHighY].push_back(7);
faceIndexes[kFaceHighY].push_back(3);
faceIndexes[kFaceLowZ].push_back(3);
faceIndexes[kFaceLowZ].push_back(0);
faceIndexes[kFaceLowZ].push_back(1);
faceIndexes[kFaceLowZ].push_back(2);
faceIndexes[kFaceHighZ].push_back(6);
faceIndexes[kFaceHighZ].push_back(5);
faceIndexes[kFaceHighZ].push_back(4);
faceIndexes[kFaceHighZ].push_back(7);
init= kTRUE;
}
return faceIndexes[face];
}
void TGLBoundingBox::PlaneSet(TGLPlaneSet_t & planeSet) const
{
assert(planeSet.empty());
planeSet.push_back(TGLPlane( fAxesNorm[2], fVertex[4]));
planeSet.push_back(TGLPlane(-fAxesNorm[2], fVertex[0]));
planeSet.push_back(TGLPlane(-fAxesNorm[0], fVertex[0]));
planeSet.push_back(TGLPlane( fAxesNorm[0], fVertex[1]));
planeSet.push_back(TGLPlane(-fAxesNorm[1], fVertex[0]));
planeSet.push_back(TGLPlane( fAxesNorm[1], fVertex[3]));
}
TGLPlane TGLBoundingBox::GetNearPlane() const
{
return TGLPlane(fAxesNorm[2], fVertex[4]);
}
EOverlap TGLBoundingBox::Overlap(const TGLPlane & plane) const
{
if (plane.DistanceTo(Center()) + (Extents().Mag()/2.0) < 0.0) {
return kOutside;
}
Int_t verticesInsidePlane = 8;
for (UInt_t v = 0; v < 8; v++) {
if (plane.DistanceTo(fVertex[v]) < 0.0) {
verticesInsidePlane--;
}
}
if ( verticesInsidePlane == 0 ) {
return kOutside;
} else if ( verticesInsidePlane == 8 ) {
return kInside;
} else {
return kPartial;
}
}
EOverlap TGLBoundingBox::Overlap(const TGLBoundingBox & other) const
{
const TGLBoundingBox & a = *this;
const TGLBoundingBox & b = other;
TGLVector3 aHL = a.Extents() / 2.0;
TGLVector3 bHL = b.Extents() / 2.0;
TGLVector3 parentT = b.Center() - a.Center();
Double_t aSphereRadius = aHL[0] < aHL[1] ? aHL[0] : aHL[1];
if (aHL[2] < aSphereRadius) {
aSphereRadius = aHL[2];
}
Double_t bSphereRadius = bHL.Mag();
if (bSphereRadius + parentT.Mag() < aSphereRadius) {
return kInside;
}
TGLVector3 aT(Dot(parentT, a.Axis(0)), Dot(parentT, a.Axis(1)), Dot(parentT, a.Axis(2)));
Double_t roaT[3][3];
UInt_t i, k;
for (i=0 ; i<3 ; i++) {
for (k=0; k<3; k++) {
roaT[i][k] = Dot(a.Axis(i), b.Axis(k));
if (fabs(roaT[i][k]) < 1e-14) {
roaT[i][k] = 0.0;
}
}
Double_t norm = sqrt(roaT[i][0]*roaT[i][0] + roaT[i][1]*roaT[i][1] + roaT[i][2]*roaT[i][2]);
roaT[i][0] /= norm; roaT[i][1] /= norm; roaT[i][2] /= norm;
}
Double_t ra, rb, t;
for (i=0; i<3; i++) {
ra = aHL[i];
rb = bHL[0]*fabs(roaT[i][0]) + bHL[1]*fabs(roaT[i][1]) + bHL[2]*fabs(roaT[i][2]);
t = fabs(aT[i]);
if (t > ra + rb)
return kOutside;
else if (ra < t + rb)
return kPartial;
}
for (k=0; k<3; k++) {
ra = aHL[0]*fabs(roaT[0][k]) + aHL[1]*fabs(roaT[1][k]) + aHL[2]*fabs(roaT[2][k]);
rb = bHL[k];
t = fabs(aT[0]*roaT[0][k] + aT[1]*roaT[1][k] + aT[2]*roaT[2][k]);
if (t > ra + rb)
return kOutside;
else if (ra < t + rb)
return kPartial;
}
ra = aHL[1]*fabs(roaT[2][0]) + aHL[2]*fabs(roaT[1][0]);
rb = bHL[1]*fabs(roaT[0][2]) + bHL[2]*fabs(roaT[0][1]);
t = fabs(aT[2]*roaT[1][0] - aT[1]*roaT[2][0]);
if (t > ra + rb)
return kOutside;
else if (ra < t + rb)
return kPartial;
ra = aHL[1]*fabs(roaT[2][1]) + aHL[2]*fabs(roaT[1][1]);
rb = bHL[0]*fabs(roaT[0][2]) + bHL[2]*fabs(roaT[0][0]);
t = fabs(aT[2]*roaT[1][1] - aT[1]*roaT[2][1]);
if (t > ra + rb)
return kOutside;
else if (ra < t + rb)
return kPartial;
ra = aHL[1]*fabs(roaT[2][2]) + aHL[2]*fabs(roaT[1][2]);
rb = bHL[0]*fabs(roaT[0][1]) + bHL[1]*fabs(roaT[0][0]);
t = fabs(aT[2]*roaT[1][2] - aT[1]*roaT[2][2]);
if (t > ra + rb)
return kOutside;
else if (ra < t + rb)
return kPartial;
ra = aHL[0]*fabs(roaT[2][0]) + aHL[2]*fabs(roaT[0][0]);
rb = bHL[1]*fabs(roaT[1][2]) + bHL[2]*fabs(roaT[1][1]);
t = fabs(aT[0]*roaT[2][0] - aT[2]*roaT[0][0]);
if (t > ra + rb)
return kOutside;
else if (ra < t + rb)
return kPartial;
ra = aHL[0]*fabs(roaT[2][1]) + aHL[2]*fabs(roaT[0][1]);
rb = bHL[0]*fabs(roaT[1][2]) + bHL[2]*fabs(roaT[1][0]);
t = fabs(aT[0]*roaT[2][1] - aT[2]*roaT[0][1]);
if (t > ra + rb)
return kOutside;
else if (ra < t + rb)
return kPartial;
ra = aHL[0]*fabs(roaT[2][2]) + aHL[2]*fabs(roaT[0][2]);
rb = bHL[0]*fabs(roaT[1][1]) + bHL[1]*fabs(roaT[1][0]);
t = fabs(aT[0]*roaT[2][2] - aT[2]*roaT[0][2]);
if (t > ra + rb)
return kOutside;
else if (ra < t + rb)
return kPartial;
ra = aHL[0]*fabs(roaT[1][0]) + aHL[1]*fabs(roaT[0][0]);
rb = bHL[1]*fabs(roaT[2][2]) + bHL[2]*fabs(roaT[2][1]);
t = fabs(aT[1]*roaT[0][0] - aT[0]*roaT[1][0]);
if (t > ra + rb)
return kOutside;
else if (ra < t + rb)
return kPartial;
ra = aHL[0]*fabs(roaT[1][1]) + aHL[1]*fabs(roaT[0][1]);
rb = bHL[0]*fabs(roaT[2][2]) + bHL[2]*fabs(roaT[2][0]);
t = fabs(aT[1]*roaT[0][1] - aT[0]*roaT[1][1]);
if (t > ra + rb)
return kOutside;
else if (ra < t + rb)
return kPartial;
ra = aHL[0]*fabs(roaT[1][2]) + aHL[1]*fabs(roaT[0][2]);
rb = bHL[0]*fabs(roaT[2][1]) + bHL[1]*fabs(roaT[2][0]);
t = fabs(aT[1]*roaT[0][2] - aT[0]*roaT[1][2]);
if (t > ra + rb)
return kOutside;
else if (ra < t + rb)
return kPartial;
return kInside;
}
void TGLBoundingBox::Draw(Bool_t solid) const
{
if (!solid) {
glBegin(GL_LINE_LOOP);
glVertex3dv(fVertex[0].CArr());
glVertex3dv(fVertex[1].CArr());
glVertex3dv(fVertex[2].CArr());
glVertex3dv(fVertex[3].CArr());
glVertex3dv(fVertex[7].CArr());
glVertex3dv(fVertex[6].CArr());
glVertex3dv(fVertex[5].CArr());
glVertex3dv(fVertex[4].CArr());
glEnd();
glBegin(GL_LINES);
glVertex3dv(fVertex[1].CArr());
glVertex3dv(fVertex[5].CArr());
glVertex3dv(fVertex[2].CArr());
glVertex3dv(fVertex[6].CArr());
glVertex3dv(fVertex[0].CArr());
glVertex3dv(fVertex[3].CArr());
glVertex3dv(fVertex[4].CArr());
glVertex3dv(fVertex[7].CArr());
glEnd();
} else {
glBegin(GL_QUADS);
glNormal3d ( fAxesNorm[2].X(), fAxesNorm[2].Y(), fAxesNorm[2].Z());
glVertex3dv(fVertex[4].CArr());
glVertex3dv(fVertex[7].CArr());
glVertex3dv(fVertex[6].CArr());
glVertex3dv(fVertex[5].CArr());
glNormal3d (-fAxesNorm[2].X(), -fAxesNorm[2].Y(), -fAxesNorm[2].Z());
glVertex3dv(fVertex[0].CArr());
glVertex3dv(fVertex[1].CArr());
glVertex3dv(fVertex[2].CArr());
glVertex3dv(fVertex[3].CArr());
glNormal3d (-fAxesNorm[0].X(), -fAxesNorm[0].Y(), -fAxesNorm[0].Z());
glVertex3dv(fVertex[0].CArr());
glVertex3dv(fVertex[3].CArr());
glVertex3dv(fVertex[7].CArr());
glVertex3dv(fVertex[4].CArr());
glNormal3d ( fAxesNorm[0].X(), fAxesNorm[0].Y(), fAxesNorm[0].Z());
glVertex3dv(fVertex[6].CArr());
glVertex3dv(fVertex[2].CArr());
glVertex3dv(fVertex[1].CArr());
glVertex3dv(fVertex[5].CArr());
glNormal3d ( fAxesNorm[1].X(), fAxesNorm[1].Y(), fAxesNorm[1].Z());
glVertex3dv(fVertex[3].CArr());
glVertex3dv(fVertex[2].CArr());
glVertex3dv(fVertex[6].CArr());
glVertex3dv(fVertex[7].CArr());
glNormal3d (-fAxesNorm[1].X(), -fAxesNorm[1].Y(), -fAxesNorm[1].Z());
glVertex3dv(fVertex[4].CArr());
glVertex3dv(fVertex[5].CArr());
glVertex3dv(fVertex[1].CArr());
glVertex3dv(fVertex[0].CArr());
glEnd();
}
}
Double_t TGLBoundingBox::Min(UInt_t index) const
{
Double_t min = fVertex[0][index];
for (UInt_t v = 1; v < 8; v++) {
if (fVertex[v][index] < min) {
min = fVertex[v][index];
}
}
return min;
}
Double_t TGLBoundingBox::Max(UInt_t index) const
{
Double_t max = fVertex[0][index];
for (UInt_t v = 1; v < 8; v++) {
if (fVertex[v][index] > max) {
max = fVertex[v][index];
}
}
return max;
}
TGLVertex3 TGLBoundingBox::MinAAVertex() const
{
return TGLVertex3(Min(0), Min(1), Min(2));
}
TGLVertex3 TGLBoundingBox::MaxAAVertex() const
{
return TGLVertex3(Max(0), Max(1), Max(2));
}
void TGLBoundingBox::Dump() const
{
for (UInt_t i = 0; i<8; i++) {
std::cout << "[" << i << "] (" << fVertex[i].X() << "," << fVertex[i].Y() << "," << fVertex[i].Z() << ")" << std::endl;
}
std::cout << "Center: "; Center().Dump();
std::cout << "Extents: "; Extents().Dump();
std::cout << "Volume: " << Volume() << std::endl;
}