#include "TGeoBranchArray.h"
#include "TMath.h"
#include "TThread.h"
#include "TString.h"
#include "TGeoNavigator.h"
#include "TGeoCache.h"
#include "TGeoManager.h"
ClassImp(TGeoBranchArray)
TGeoBranchArray::TGeoBranchArray(Int_t maxlevel)
:fLevel(-1),
fMaxLevel(maxlevel),
fMatrix(),
fArray(&fRealArray[0])
{
memset(fRealArray, 0, fMaxLevel*sizeof(TGeoNode*));
}
TGeoBranchArray * TGeoBranchArray::MakeInstance(size_t maxlevel)
{
TGeoBranchArray* ba = 0;
size_t needed = SizeOf(maxlevel);
char *ptr = new char[ needed ];
if (!ptr) return 0;
new (ptr) TGeoBranchArray(maxlevel);
ba = reinterpret_cast<TGeoBranchArray*>(ptr);
ba->SetBit(kBASelfAlloc, kTRUE);
return ba;
}
TGeoBranchArray * TGeoBranchArray::MakeInstanceAt(size_t maxlevel, void *addr)
{
TGeoBranchArray* ba = 0;
new (addr) TGeoBranchArray(maxlevel);
ba = reinterpret_cast<TGeoBranchArray*>(addr);
ba->SetBit(kBASelfAlloc, kFALSE);
return ba;
}
TGeoBranchArray * TGeoBranchArray::MakeCopy(const TGeoBranchArray &other)
{
TGeoBranchArray *copy = 0;
size_t needed = SizeOf(other.fMaxLevel);
char *ptr = new char[ needed ];
if (!ptr) return 0;
new (ptr) TGeoBranchArray(other.fMaxLevel);
copy = reinterpret_cast<TGeoBranchArray*>(ptr);
copy->SetBit(kBASelfAlloc, kTRUE);
copy->fLevel = other.fLevel;
copy->fMatrix = other.fMatrix;
if (other.fLevel+1) memcpy(copy->fArray, other.fArray, (other.fLevel+1)*sizeof(TGeoNode*));
return copy;
}
TGeoBranchArray * TGeoBranchArray::MakeCopyAt(const TGeoBranchArray &other, void *addr)
{
TGeoBranchArray *copy = 0;
new (addr) TGeoBranchArray(other.fMaxLevel);
copy = reinterpret_cast<TGeoBranchArray*>(addr);
copy->SetBit(kBASelfAlloc, kFALSE);
copy->fLevel = other.fLevel;
copy->fMatrix = other.fMatrix;
if (other.fLevel+1) memcpy(copy->fArray, other.fArray, (other.fLevel+1)*sizeof(TGeoNode*));
return copy;
}
void TGeoBranchArray::CopyTo(TGeoBranchArray *dest)
{
memcpy(dest->DataStart(), DataStart(), DataSize());
dest->fArray = &(dest->fRealArray[0]);
}
void TGeoBranchArray::ReleaseInstance(TGeoBranchArray *obj)
{
obj->~TGeoBranchArray();
if (obj->TestBit(kBASelfAlloc)) delete [] (char*)obj;
}
void TGeoBranchArray::UpdateArray(size_t nobj)
{
size_t needed = SizeOf();
char *where = reinterpret_cast<char*>(this);
for (size_t i=0; i<nobj; ++i, where += needed) {
TGeoBranchArray *obj = reinterpret_cast<TGeoBranchArray*>(where);
obj->fArray = &(obj->fRealArray[0]);
}
}
TGeoBranchArray::TGeoBranchArray(const TGeoBranchArray& other)
:TObject(other),
fLevel(other.fLevel),
fMaxLevel(other.fMaxLevel),
fMatrix(other.fMatrix),
fArray(NULL)
{
if (fMaxLevel) {
fArray = new TGeoNode*[fMaxLevel];
if (fLevel+1) memcpy(fArray, other.fArray, (fLevel+1)*sizeof(TGeoNode*));
}
}
TGeoBranchArray& TGeoBranchArray::operator=(const TGeoBranchArray& other)
{
if (&other == this) return *this;
fLevel = other.fLevel;
fMatrix.CopyFrom(&other.fMatrix);
if (fLevel+1) memcpy(fArray, other.fArray, (fLevel+1)*sizeof(TGeoNode*));
return *this;
}
void TGeoBranchArray::AddLevel(Int_t dindex)
{
if (fLevel<0) {
Error("AddLevel", "You must initialize from navigator or copy from another branch array first.");
return;
}
if (fLevel>fMaxLevel) {
Fatal("AddLevel", "Max level = %d reached\n", fMaxLevel);
return;
}
fLevel++;
fArray[fLevel] = fArray[fLevel-1]->GetVolume()->GetNode(dindex);
}
Bool_t TGeoBranchArray::operator ==(const TGeoBranchArray& other) const
{
Int_t value = Compare(&other);
if (value==0) return kTRUE;
return kFALSE;
}
Bool_t TGeoBranchArray::operator !=(const TGeoBranchArray& other) const
{
Int_t value = Compare(&other);
if (value!=0) return kTRUE;
return kFALSE;
}
Bool_t TGeoBranchArray::operator >(const TGeoBranchArray& other) const
{
Int_t value = Compare(&other);
if (value>0) return kTRUE;
return kFALSE;
}
Bool_t TGeoBranchArray::operator <(const TGeoBranchArray& other) const
{
Int_t value = Compare(&other);
if (value<0) return kTRUE;
return kFALSE;
}
Bool_t TGeoBranchArray::operator >=(const TGeoBranchArray& other) const
{
Int_t value = Compare(&other);
if (value>=0) return kTRUE;
return kFALSE;
}
Bool_t TGeoBranchArray::operator <=(const TGeoBranchArray& other) const
{
Int_t value = Compare(&other);
if (value<=0) return kTRUE;
return kFALSE;
}
Long64_t TGeoBranchArray::BinarySearch(Long64_t n, const TGeoBranchArray **array, TGeoBranchArray *value)
{
Long64_t nabove, nbelow, middle;
const TGeoBranchArray *pind;
nabove = n+1;
nbelow = 0;
while(nabove-nbelow > 1) {
middle = (nabove+nbelow)/2;
pind = array[middle-1];
if (*value == *pind) return middle-1;
if (*value < *pind) nabove = middle;
else nbelow = middle;
}
return nbelow-1;
}
Int_t TGeoBranchArray::Compare(const TObject *obj) const
{
Int_t i;
TGeoBranchArray *other = (TGeoBranchArray*)obj;
Int_t otherLevel = other->GetLevel();
Int_t maxLevel = TMath::Min(fLevel, otherLevel);
TGeoNode **otherArray = other->GetArray();
for (i=0; i<maxLevel+1; i++) {
if (fArray[i]==otherArray[i]) continue;
if ((Long64_t)fArray[i]<(Long64_t)otherArray[i]) return -1;
return 1;
}
if (fLevel==otherLevel) return 0;
if (fLevel<otherLevel) return -1;
return 1;
}
void TGeoBranchArray::CleanMatrix()
{
}
void TGeoBranchArray::Init(TGeoNode **branch, TGeoMatrix *global, Int_t level)
{
fMatrix.CopyFrom(global);
if (level>fMaxLevel) {
Fatal("Init", "Requested level %d exceeds maximum level %d", level+1, fMaxLevel);
return;
}
fLevel = level;
memcpy(fArray, branch, (fLevel+1)*sizeof(TGeoNode*));
}
void TGeoBranchArray::InitFromNavigator(TGeoNavigator *nav)
{
TGeoNodeCache *cache = nav->GetCache();
const TGeoNode **branch = (const TGeoNode**)cache->GetBranch();
Int_t level = cache->GetLevel();
fMatrix.CopyFrom(cache->GetCurrentMatrix());
if (level>fMaxLevel) {
Fatal("InitFromNavigator", "Requested level %d exceeds maximum level %d", level+1, fMaxLevel);
return;
}
fLevel = level;
memcpy(fArray, branch, (fLevel+1)*sizeof(TGeoNode*));
if (nav->IsOutside()) fLevel = -1;
}
void TGeoBranchArray::GetPath(TString &path) const
{
path = "";
if (!fArray || !fArray[0]) return;
for (Int_t i=0; i<fLevel+1; i++) {
path += "/";
path += fArray[i]->GetName();
}
}
void TGeoBranchArray::Print(Option_t *) const
{
TString path;
GetPath(path);
printf("branch: %s\n", path.Data());
}
void TGeoBranchArray::Sort(Int_t n, TGeoBranchArray **array, Int_t *index, Bool_t down)
{
for (Int_t i=0; i<n; i++) index[i] = i;
if (down)
std::sort(index, index + n, compareBAdesc(array));
else
std::sort(index, index + n, compareBAasc(array));
}
void TGeoBranchArray::UpdateNavigator(TGeoNavigator *nav) const
{
if (fLevel<0) {nav->SetOutside(kTRUE); return;}
Int_t matchlev = 0;
Int_t navlev = nav->GetLevel();
Int_t i;
Int_t maxlev = TMath::Min(fLevel, navlev);
for (i=1; i<maxlev+1; ++i) {
if (fArray[i] != nav->GetMother(navlev-i)) break;
matchlev++;
}
for (i=0; i<navlev-matchlev; i++) nav->CdUp();
for (i=matchlev+1; i<fLevel+1; i++) nav->CdDown(fArray[i]);
}