#include "TGeoManager.h"
#include "TGeoMatrix.h"
#include "TGeoNode.h"
#include "TGeoVolume.h"
#include "TGeoPatternFinder.h"
#include "TGeoVoxelFinder.h"
#include "TGeoNavigator.h"
static Double_t gTolerance = TGeoShape::Tolerance();
const char *kGeoOutsidePath = " ";
const Int_t kN3 = 3*sizeof(Double_t);
ClassImp(TGeoNavigator)
TGeoNavigator::TGeoNavigator()
:fStep(0.),
fSafety(0.),
fLastSafety(0.),
fLevel(0),
fNmany(0),
fNextDaughterIndex(0),
fOverlapSize(0),
fOverlapMark(0),
fOverlapClusters(0),
fSearchOverlaps(kFALSE),
fCurrentOverlapping(kFALSE),
fStartSafe(kFALSE),
fIsEntering(kFALSE),
fIsExiting(kFALSE),
fIsStepEntering(kFALSE),
fIsStepExiting(kFALSE),
fIsOutside(kFALSE),
fIsOnBoundary(kFALSE),
fIsSameLocation(kFALSE),
fIsNullStep(kFALSE),
fGeometry(0),
fCache(0),
fCurrentVolume(0),
fCurrentNode(0),
fLastNode(0),
fNextNode(0),
fBackupState(0),
fCurrentMatrix(0),
fGlobalMatrix(0),
fPath()
{
}
TGeoNavigator::TGeoNavigator(TGeoManager* geom)
:fStep(0.),
fSafety(0.),
fLastSafety(0.),
fLevel(0),
fNmany(0),
fNextDaughterIndex(-2),
fOverlapSize(1000),
fOverlapMark(0),
fOverlapClusters(0),
fSearchOverlaps(kFALSE),
fCurrentOverlapping(kFALSE),
fStartSafe(kTRUE),
fIsEntering(kFALSE),
fIsExiting(kFALSE),
fIsStepEntering(kFALSE),
fIsStepExiting(kFALSE),
fIsOutside(kFALSE),
fIsOnBoundary(kFALSE),
fIsSameLocation(kTRUE),
fIsNullStep(kFALSE),
fGeometry(geom),
fCache(0),
fCurrentVolume(0),
fCurrentNode(0),
fLastNode(0),
fNextNode(0),
fBackupState(0),
fCurrentMatrix(0),
fGlobalMatrix(0),
fPath()
{
for (Int_t i=0; i<3; i++) {
fNormal[i] = 0.;
fCldir[i] = 0.;
fCldirChecked[i] = 0;
fPoint[i] = 0.;
fDirection[i] = 0.;
fLastPoint[i] = 0.;
}
fCurrentMatrix = new TGeoHMatrix();
fCurrentMatrix->RegisterYourself();
fOverlapClusters = new Int_t[fOverlapSize];
}
TGeoNavigator::TGeoNavigator(const TGeoNavigator& gm)
:TObject(gm),
fStep(gm.fStep),
fSafety(gm.fSafety),
fLastSafety(gm.fLastSafety),
fLevel(gm.fLevel),
fNmany(gm.fNmany),
fNextDaughterIndex(gm.fNextDaughterIndex),
fOverlapSize(gm.fOverlapSize),
fOverlapMark(gm.fOverlapMark),
fOverlapClusters(gm.fOverlapClusters),
fSearchOverlaps(gm.fSearchOverlaps),
fCurrentOverlapping(gm.fCurrentOverlapping),
fStartSafe(gm.fStartSafe),
fIsEntering(gm.fIsEntering),
fIsExiting(gm.fIsExiting),
fIsStepEntering(gm.fIsStepEntering),
fIsStepExiting(gm.fIsStepExiting),
fIsOutside(gm.fIsOutside),
fIsOnBoundary(gm.fIsOnBoundary),
fIsSameLocation(gm.fIsSameLocation),
fIsNullStep(gm.fIsNullStep),
fGeometry(gm.fGeometry),
fCache(gm.fCache),
fCurrentVolume(gm.fCurrentVolume),
fCurrentNode(gm.fCurrentNode),
fLastNode(gm.fLastNode),
fNextNode(gm.fNextNode),
fBackupState(gm.fBackupState),
fCurrentMatrix(gm.fCurrentMatrix),
fGlobalMatrix(gm.fGlobalMatrix),
fPath(gm.fPath)
{
for (Int_t i=0; i<3; i++) {
fNormal[i] = gm.fNormal[i];
fCldir[i] = gm.fCldir[i];
fCldirChecked[i] = gm.fCldirChecked[i];
fPoint[i] = gm.fPoint[i];
fDirection[i] = gm.fDirection[i];
fLastPoint[i] = gm.fLastPoint[i];
}
}
TGeoNavigator& TGeoNavigator::operator=(const TGeoNavigator& gm)
{
if(this!=&gm) {
TObject::operator=(gm);
fStep = gm.fStep;
fSafety = gm.fSafety;
fLastSafety = gm.fLastSafety;
fLevel = gm.fLevel;
fNmany = gm.fNmany;
fNextDaughterIndex = gm.fNextDaughterIndex;
fOverlapSize=gm.fOverlapSize;
fOverlapMark=gm.fOverlapMark;
fOverlapClusters=gm.fOverlapClusters;
fSearchOverlaps = gm.fSearchOverlaps;
fCurrentOverlapping = gm.fCurrentOverlapping;
fStartSafe = gm.fStartSafe;
fIsEntering = gm.fIsEntering;
fIsExiting = gm.fIsExiting;
fIsStepEntering = gm.fIsStepEntering;
fIsStepExiting = gm.fIsStepExiting;
fIsOutside = gm.fIsOutside;
fIsOnBoundary = gm.fIsOnBoundary;
fIsSameLocation = gm.fIsSameLocation;
fIsNullStep = gm.fIsNullStep;
fGeometry = gm.fGeometry;
fCache = gm.fCache;
fCurrentVolume = gm.fCurrentVolume;
fCurrentNode = gm.fCurrentNode;
fLastNode = gm.fLastNode;
fNextNode = gm.fNextNode;
fBackupState = gm.fBackupState;
fCurrentMatrix = gm.fCurrentMatrix;
fGlobalMatrix = gm.fGlobalMatrix;
fPath = gm.fPath;
for (Int_t i=0; i<3; i++) {
fNormal[i] = gm.fNormal[i];
fCldir[i] = gm.fCldir[i];
fCldirChecked[i] = gm.fCldirChecked[i];
fPoint[i] = gm.fPoint[i];
fDirection[i] = gm.fDirection[i];
fLastPoint[i] = gm.fLastPoint[i];
}
}
return *this;
}
TGeoNavigator::~TGeoNavigator()
{
if (fCache) delete fCache;
if (fBackupState) delete fBackupState;
if (fOverlapClusters) delete [] fOverlapClusters;
}
void TGeoNavigator::BuildCache(Bool_t , Bool_t nodeid)
{
static Bool_t first = kTRUE;
Int_t nlevel = fGeometry->GetMaxLevel();
if (nlevel<=0) nlevel = 100;
if (!fCache) {
if (nlevel==100) {
if (first) Info("BuildCache","--- Maximum geometry depth set to 100");
} else {
if (first) Info("BuildCache","--- Maximum geometry depth is %i", nlevel);
}
fCache = new TGeoNodeCache(fGeometry->GetTopNode(), nodeid, nlevel+1);
fGlobalMatrix = fCache->GetCurrentMatrix();
fBackupState = new TGeoCacheState(nlevel+1);
}
first = kFALSE;
}
Bool_t TGeoNavigator::cd(const char *path)
{
if (!strlen(path)) return kFALSE;
CdTop();
TString spath = path;
TGeoVolume *vol;
Int_t length = spath.Length();
Int_t ind1 = spath.Index("/");
Int_t ind2 = 0;
Bool_t end = kFALSE;
TString name;
TGeoNode *node;
while (!end) {
ind2 = spath.Index("/", ind1+1);
if (ind2<0) {
ind2 = length;
end = kTRUE;
}
name = spath(ind1+1, ind2-ind1-1);
if (name==fGeometry->GetTopNode()->GetName()) {
ind1 = ind2;
continue;
}
vol = fCurrentNode->GetVolume();
if (vol) {
node = vol->GetNode(name.Data());
} else node = 0;
if (!node) {
Error("cd", "Path %s not valid", path);
return kFALSE;
}
CdDown(fCurrentNode->GetVolume()->GetIndex(node));
ind1 = ind2;
}
return kTRUE;
}
Bool_t TGeoNavigator::CheckPath(const char *path) const
{
Int_t length = strlen(path);
if (!length) return kFALSE;
TString spath = path;
TGeoVolume *vol;
TGeoNode *top = fGeometry->GetTopNode();
Int_t ind1 = spath.Index("/");
if (ind1<0) {
if (strcmp(path,top->GetName())) return kFALSE;
return kTRUE;
}
Int_t ind2 = ind1;
Bool_t end = kFALSE;
if (ind1>0) ind1 = -1;
else ind2 = spath.Index("/", ind1+1);
if (ind2<0) ind2 = length;
TString name(spath(ind1+1, ind2-ind1-1));
if (name==top->GetName()) {
if (ind2>=length-1) return kTRUE;
ind1 = ind2;
} else return kFALSE;
TGeoNode *node = top;
while (!end) {
ind2 = spath.Index("/", ind1+1);
if (ind2<0) {
ind2 = length;
end = kTRUE;
}
vol = node->GetVolume();
name = spath(ind1+1, ind2-ind1-1);
node = vol->GetNode(name.Data());
if (!node) return kFALSE;
if (ind2>=length-1) return kTRUE;
ind1 = ind2;
}
return kTRUE;
}
void TGeoNavigator::CdNode(Int_t nodeid)
{
if (fCache) {
fCache->CdNode(nodeid);
fGlobalMatrix = fCache->GetCurrentMatrix();
}
}
void TGeoNavigator::CdDown(Int_t index)
{
if (!fCache) return;
TGeoNode *node = fCurrentNode->GetDaughter(index);
Bool_t is_offset = node->IsOffset();
if (is_offset)
node->cd();
else
fCurrentOverlapping = node->IsOverlapping();
fCache->CdDown(index);
fCurrentNode = node;
fGlobalMatrix = fCache->GetCurrentMatrix();
if (fCurrentOverlapping) fNmany++;
fLevel++;
}
void TGeoNavigator::CdUp()
{
if (!fLevel || !fCache) return;
fLevel--;
if (!fLevel) {
CdTop();
return;
}
fCache->CdUp();
if (fCurrentOverlapping) {
fLastNode = fCurrentNode;
fNmany--;
}
fCurrentNode = fCache->GetNode();
fGlobalMatrix = fCache->GetCurrentMatrix();
if (!fCurrentNode->IsOffset()) {
fCurrentOverlapping = fCurrentNode->IsOverlapping();
} else {
Int_t up = 1;
Bool_t offset = kTRUE;
TGeoNode *mother = 0;
while (offset) {
mother = GetMother(up++);
offset = mother->IsOffset();
}
fCurrentOverlapping = mother->IsOverlapping();
}
}
void TGeoNavigator::CdTop()
{
if (!fCache) return;
fLevel = 0;
fNmany = 0;
if (fCurrentOverlapping) fLastNode = fCurrentNode;
fCurrentNode = fGeometry->GetTopNode();
fCache->CdTop();
fGlobalMatrix = fCache->GetCurrentMatrix();
fCurrentOverlapping = fCurrentNode->IsOverlapping();
if (fCurrentOverlapping) fNmany++;
}
void TGeoNavigator::CdNext()
{
if (fNextDaughterIndex == -2 || !fCache) return;
if (fNextDaughterIndex == -3) {
DoRestoreState();
fNextDaughterIndex = -2;
return;
}
if (fNextDaughterIndex == -1) {
CdUp();
while (fCurrentNode->GetVolume()->IsAssembly()) CdUp();
fNextDaughterIndex--;
return;
}
if (fCurrentNode && fNextDaughterIndex<fCurrentNode->GetNdaughters()) {
CdDown(fNextDaughterIndex);
Int_t nextindex = fCurrentNode->GetVolume()->GetNextNodeIndex();
while (nextindex>=0) {
CdDown(nextindex);
nextindex = fCurrentNode->GetVolume()->GetNextNodeIndex();
}
}
fNextDaughterIndex = -2;
}
void TGeoNavigator::GetBranchNames(Int_t *names) const
{
fCache->GetBranchNames(names);
}
void TGeoNavigator::GetBranchNumbers(Int_t *copyNumbers, Int_t *volumeNumbers) const
{
fCache->GetBranchNumbers(copyNumbers, volumeNumbers);
}
void TGeoNavigator::GetBranchOnlys(Int_t *isonly) const
{
fCache->GetBranchOnlys(isonly);
}
TGeoNode *TGeoNavigator::CrossDivisionCell()
{
TGeoPatternFinder *finder = fCurrentNode->GetFinder();
if (!finder) {
Fatal("CrossDivisionCell", "Volume has no pattern finder");
return 0;
}
TGeoNode *skip = fCurrentNode;
CdUp();
Double_t point[3], newpoint[3], dir[3];
fGlobalMatrix->MasterToLocal(fPoint, newpoint);
fGlobalMatrix->MasterToLocalVect(fDirection, dir);
Bool_t onbound = finder->IsOnBoundary(newpoint);
if (onbound) {
point[0] = newpoint[0] - dir[0]*fStep;
point[1] = newpoint[1] - dir[1]*fStep;
point[2] = newpoint[2] - dir[2]*fStep;
finder->FindNode(point, dir);
Int_t inext = finder->GetNext();
if (inext<0) {
if (fCurrentNode->IsOffset()) {
Double_t dist = fCurrentNode->GetVolume()->GetShape()->DistFromInside(point,dir,3);
if (dist < fStep+2.*gTolerance) {
return CrossDivisionCell();
}
return fCurrentNode;
}
while (fCurrentNode->GetVolume()->IsAssembly()) {
skip = fCurrentNode;
if (!fLevel) break;
CdUp();
}
return CrossBoundaryAndLocate(kFALSE, skip);
}
CdDown(inext+finder->GetDivIndex());
skip = fCurrentNode;
return CrossBoundaryAndLocate(kTRUE, skip);
}
if (fCurrentNode->IsOffset()) return CrossDivisionCell();
return CrossBoundaryAndLocate(kFALSE, skip);
}
TGeoNode *TGeoNavigator::CrossBoundaryAndLocate(Bool_t downwards, TGeoNode *skipnode)
{
Double_t extra = 100.*gTolerance;
fPoint[0] += extra*fDirection[0];
fPoint[1] += extra*fDirection[1];
fPoint[2] += extra*fDirection[2];
TGeoNode *current = SearchNode(downwards, skipnode);
fPoint[0] -= extra*fDirection[0];
fPoint[1] -= extra*fDirection[1];
fPoint[2] -= extra*fDirection[2];
if (!current) return 0;
if (downwards) {
Int_t nextindex = current->GetVolume()->GetNextNodeIndex();
while (nextindex>=0) {
CdDown(nextindex);
current = fCurrentNode;
nextindex = fCurrentNode->GetVolume()->GetNextNodeIndex();
}
return current;
}
if ((skipnode && current == skipnode) || current->GetVolume()->IsAssembly()) {
if (!fLevel) {
fIsOutside = kTRUE;
return fGeometry->GetCurrentNode();
}
CdUp();
while (fLevel && fCurrentNode->GetVolume()->IsAssembly()) CdUp();
if (!fLevel && fCurrentNode->GetVolume()->IsAssembly()) {
fIsOutside = kTRUE;
return fCurrentNode;
}
return fCurrentNode;
}
return current;
}
TGeoNode *TGeoNavigator::FindNextBoundary(Double_t stepmax, const char *path, Bool_t frombdr)
{
Int_t iact = 3;
fNextDaughterIndex = -2;
fStep = TGeoShape::Big();
fIsStepEntering = kFALSE;
fIsStepExiting = kFALSE;
Bool_t computeGlobal = kFALSE;
fIsOnBoundary = frombdr;
fSafety = 0.;
TGeoNode *top_node = fGeometry->GetTopNode();
TGeoVolume *top_volume = top_node->GetVolume();
if (stepmax<1E29) {
if (stepmax <= 0) {
stepmax = - stepmax;
computeGlobal = kTRUE;
}
if (IsSamePoint(fPoint[0], fPoint[1], fPoint[2]) && fLastSafety>=0.) fSafety = fLastSafety;
else fSafety = Safety();
fSafety = TMath::Abs(fSafety);
memcpy(fLastPoint, fPoint, kN3);
fLastSafety = fSafety;
if (fSafety<gTolerance) fIsOnBoundary = kTRUE;
else fIsOnBoundary = kFALSE;
fStep = stepmax;
if (stepmax<fSafety) {
fStep = stepmax;
return fCurrentNode;
}
}
if (computeGlobal) fCurrentMatrix->CopyFrom(fGlobalMatrix);
Double_t snext = TGeoShape::Big();
Double_t safe;
Double_t point[3];
Double_t dir[3];
if (strlen(path)) {
PushPath();
if (!cd(path)) {
PopPath();
return 0;
}
if (computeGlobal) fCurrentMatrix->CopyFrom(fGlobalMatrix);
fNextNode = fCurrentNode;
TGeoVolume *tvol=fCurrentNode->GetVolume();
fGlobalMatrix->MasterToLocal(fPoint, &point[0]);
fGlobalMatrix->MasterToLocalVect(fDirection, &dir[0]);
if (tvol->Contains(&point[0])) {
fStep=tvol->GetShape()->DistFromInside(&point[0], &dir[0], iact, fStep, &safe);
} else {
fStep=tvol->GetShape()->DistFromOutside(&point[0], &dir[0], iact, fStep, &safe);
}
PopPath();
return fNextNode;
}
if (fIsOutside) {
snext = top_volume->GetShape()->DistFromOutside(fPoint, fDirection, iact, fStep, &safe);
fNextNode = top_node;
if (snext < fStep-gTolerance) {
fIsStepEntering = kTRUE;
fStep = snext;
Int_t indnext = fNextNode->GetVolume()->GetNextNodeIndex();
fNextDaughterIndex = indnext;
while (indnext>=0) {
fNextNode = fNextNode->GetDaughter(indnext);
if (computeGlobal) fCurrentMatrix->Multiply(fNextNode->GetMatrix());
indnext = fNextNode->GetVolume()->GetNextNodeIndex();
}
return fNextNode;
}
return 0;
}
fGlobalMatrix->MasterToLocal(fPoint, &point[0]);
fGlobalMatrix->MasterToLocalVect(fDirection, &dir[0]);
TGeoVolume *vol = fCurrentNode->GetVolume();
snext = vol->GetShape()->DistFromInside(&point[0], &dir[0], iact, fStep, &safe);
if (snext < fStep-gTolerance) {
fNextNode = fCurrentNode;
fNextDaughterIndex = -1;
fIsStepExiting = kTRUE;
fStep = snext;
fIsStepEntering = kFALSE;
if (fStep<1E-6) return fCurrentNode;
}
fNextNode = (fStep<1E20)?fCurrentNode:0;
Int_t idaughter = -1;
FindNextDaughterBoundary(point,dir,idaughter,computeGlobal);
if (idaughter>=0) fNextDaughterIndex = idaughter;
TGeoNode *current = 0;
TGeoNode *dnode = 0;
TGeoVolume *mother = 0;
if (fNmany) {
Double_t mothpt[3];
Double_t vecpt[3];
Double_t dpt[3], dvec[3];
Int_t novlps;
Int_t idovlp = -1;
Int_t safelevel = GetSafeLevel();
PushPath(safelevel+1);
while (fCurrentOverlapping) {
Int_t *ovlps = fCurrentNode->GetOverlaps(novlps);
CdUp();
mother = fCurrentNode->GetVolume();
fGlobalMatrix->MasterToLocal(fPoint, &mothpt[0]);
fGlobalMatrix->MasterToLocalVect(fDirection, &vecpt[0]);
snext = TGeoShape::Big();
if (!mother->IsAssembly()) snext = mother->GetShape()->DistFromInside(&mothpt[0], &vecpt[0], iact, fStep, &safe);
if (snext<fStep-gTolerance) {
fIsStepExiting = kTRUE;
fIsStepEntering = kFALSE;
fStep = snext;
if (computeGlobal) fCurrentMatrix->CopyFrom(fGlobalMatrix);
fNextNode = fCurrentNode;
fNextDaughterIndex = -3;
DoBackupState();
}
for (Int_t i=0; i<novlps; i++) {
current = mother->GetNode(ovlps[i]);
if (!current->IsOverlapping()) {
current->cd();
current->MasterToLocal(&mothpt[0], &dpt[0]);
current->MasterToLocalVect(&vecpt[0], &dvec[0]);
snext = TGeoShape::Big();
if (!current->GetVolume()->Contains(dpt))
snext = current->GetVolume()->GetShape()->DistFromOutside(&dpt[0], &dvec[0], iact, fStep, &safe);
if (snext<fStep-gTolerance) {
if (computeGlobal) {
fCurrentMatrix->CopyFrom(fGlobalMatrix);
fCurrentMatrix->Multiply(current->GetMatrix());
}
fIsStepExiting = kTRUE;
fIsStepEntering = kFALSE;
fStep = snext;
fNextNode = current;
fNextDaughterIndex = -3;
CdDown(ovlps[i]);
DoBackupState();
CdUp();
}
} else {
current->cd();
current->MasterToLocal(&mothpt[0], &dpt[0]);
current->MasterToLocalVect(&vecpt[0], &dvec[0]);
if (current->GetVolume()->Contains(dpt)) {
if (current->GetVolume()->GetNdaughters()) {
CdDown(ovlps[i]);
fIsStepEntering = kFALSE;
fIsStepExiting = kTRUE;
dnode = FindNextDaughterBoundary(dpt,dvec,idovlp,computeGlobal);
if (dnode) {
if (computeGlobal) {
fCurrentMatrix->CopyFrom(fGlobalMatrix);
fCurrentMatrix->Multiply(dnode->GetMatrix());
}
fNextNode = dnode;
fNextDaughterIndex = -3;
CdDown(idovlp);
Int_t indnext = fCurrentNode->GetVolume()->GetNextNodeIndex();
Int_t iup=0;
while (indnext>=0) {
CdDown(indnext);
iup++;
indnext = fCurrentNode->GetVolume()->GetNextNodeIndex();
}
DoBackupState();
while (iup>0) {
CdUp();
iup--;
}
CdUp();
}
CdUp();
}
} else {
snext = current->GetVolume()->GetShape()->DistFromOutside(&dpt[0], &dvec[0], iact, fStep, &safe);
if (snext<fStep-gTolerance) {
if (computeGlobal) {
fCurrentMatrix->CopyFrom(fGlobalMatrix);
fCurrentMatrix->Multiply(current->GetMatrix());
}
fIsStepExiting = kTRUE;
fIsStepEntering = kFALSE;
fStep = snext;
fNextNode = current;
fNextDaughterIndex = -3;
CdDown(ovlps[i]);
DoBackupState();
CdUp();
}
}
}
}
}
if (fNmany) {
Int_t up = 1;
Int_t imother;
Int_t nmany = fNmany;
Bool_t ovlp = kFALSE;
Bool_t nextovlp = kFALSE;
Bool_t offset = kFALSE;
TGeoNode *currentnode = fCurrentNode;
TGeoNode *mothernode, *mup;
TGeoHMatrix *matrix;
while (nmany) {
mothernode = GetMother(up);
mup = mothernode;
imother = up+1;
offset = kFALSE;
while (mup->IsOffset()) {
mup = GetMother(imother++);
offset = kTRUE;
}
nextovlp = mup->IsOverlapping();
if (offset) {
mothernode = mup;
if (nextovlp) nmany -= imother-up;
up = imother-1;
} else {
if (ovlp) nmany--;
}
if (ovlp || nextovlp) {
matrix = GetMotherMatrix(up);
matrix->MasterToLocal(fPoint,dpt);
matrix->MasterToLocalVect(fDirection,dvec);
snext = TGeoShape::Big();
if (!mothernode->GetVolume()->IsAssembly()) snext = mothernode->GetVolume()->GetShape()->DistFromInside(dpt,dvec,iact,fStep);
if (snext<fStep-gTolerance) {
fIsStepEntering = kFALSE;
fIsStepExiting = kTRUE;
fStep = snext;
fNextNode = mothernode;
fNextDaughterIndex = -3;
if (computeGlobal) fCurrentMatrix->CopyFrom(matrix);
while (up--) CdUp();
DoBackupState();
up = 1;
currentnode = fCurrentNode;
ovlp = currentnode->IsOverlapping();
continue;
}
}
currentnode = mothernode;
ovlp = nextovlp;
up++;
}
}
PopPath();
}
return fNextNode;
}
TGeoNode *TGeoNavigator::FindNextDaughterBoundary(Double_t *point, Double_t *dir, Int_t &idaughter, Bool_t compmatrix)
{
Double_t snext = TGeoShape::Big();
idaughter = -1;
TGeoNode *nodefound = 0;
TGeoVolume *vol = fCurrentNode->GetVolume();
Int_t nd = vol->GetNdaughters();
if (!nd) return 0;
if (fGeometry->IsActivityEnabled() && !vol->IsActiveDaughters()) return 0;
Double_t lpoint[3], ldir[3];
TGeoNode *current = 0;
Int_t i=0;
TGeoPatternFinder *finder = vol->GetFinder();
if (finder) {
Int_t ifirst = finder->GetDivIndex();
Int_t ilast = ifirst+finder->GetNdiv()-1;
current = finder->FindNode(point);
if (current) {
Int_t index = current->GetIndex();
if ((index-1) >= ifirst) ifirst = index-1;
else ifirst = -1;
if ((index+1) <= ilast) ilast = index+1;
else ilast = -1;
}
if (ifirst>=0) {
current = vol->GetNode(ifirst);
current->cd();
current->MasterToLocal(&point[0], lpoint);
current->MasterToLocalVect(&dir[0], ldir);
snext = current->GetVolume()->GetShape()->DistFromOutside(lpoint, ldir, 3, fStep);
if (snext<fStep-gTolerance) {
if (compmatrix) {
fCurrentMatrix->CopyFrom(fGlobalMatrix);
fCurrentMatrix->Multiply(current->GetMatrix());
}
fIsStepExiting = kFALSE;
fIsStepEntering = kTRUE;
fStep=snext;
fNextNode = current;
nodefound = current;
idaughter = ifirst;
}
}
if (ilast==ifirst) return nodefound;
if (ilast>=0) {
current = vol->GetNode(ilast);
current->cd();
current->MasterToLocal(&point[0], lpoint);
current->MasterToLocalVect(&dir[0], ldir);
snext = current->GetVolume()->GetShape()->DistFromOutside(lpoint, ldir, 3, fStep);
if (snext<fStep-gTolerance) {
if (compmatrix) {
fCurrentMatrix->CopyFrom(fGlobalMatrix);
fCurrentMatrix->Multiply(current->GetMatrix());
}
fIsStepExiting = kFALSE;
fIsStepEntering = kTRUE;
fStep=snext;
fNextNode = current;
nodefound = current;
idaughter = ilast;
}
}
return nodefound;
}
TGeoVoxelFinder *voxels = vol->GetVoxels();
Int_t indnext;
if (nd<5 || !voxels) {
for (i=0; i<nd; i++) {
current = vol->GetNode(i);
if (fGeometry->IsActivityEnabled() && !current->GetVolume()->IsActive()) continue;
current->cd();
if (voxels && voxels->IsSafeVoxel(point, i, fStep)) continue;
current->MasterToLocal(point, lpoint);
current->MasterToLocalVect(dir, ldir);
if (current->IsOverlapping() && current->GetVolume()->Contains(lpoint)) continue;
snext = current->GetVolume()->GetShape()->DistFromOutside(lpoint, ldir, 3, fStep);
if (snext<fStep-gTolerance) {
indnext = current->GetVolume()->GetNextNodeIndex();
if (compmatrix) {
fCurrentMatrix->CopyFrom(fGlobalMatrix);
fCurrentMatrix->Multiply(current->GetMatrix());
}
fIsStepExiting = kFALSE;
fIsStepEntering = kTRUE;
fStep=snext;
fNextNode = current;
nodefound = fNextNode;
idaughter = i;
while (indnext>=0) {
current = current->GetDaughter(indnext);
if (compmatrix) fCurrentMatrix->Multiply(current->GetMatrix());
fNextNode = current;
nodefound = current;
indnext = current->GetVolume()->GetNextNodeIndex();
}
}
}
return nodefound;
}
Int_t ncheck = 0;
Int_t sumchecked = 0;
Int_t *vlist = 0;
voxels->SortCrossedVoxels(point, dir);
while ((sumchecked<nd) && (vlist=voxels->GetNextVoxel(point, dir, ncheck))) {
for (i=0; i<ncheck; i++) {
current = vol->GetNode(vlist[i]);
if (fGeometry->IsActivityEnabled() && !current->GetVolume()->IsActive()) continue;
current->cd();
current->MasterToLocal(point, lpoint);
current->MasterToLocalVect(dir, ldir);
if (current->IsOverlapping() && current->GetVolume()->Contains(lpoint)) continue;
snext = current->GetVolume()->GetShape()->DistFromOutside(lpoint, ldir, 3, fStep);
sumchecked++;
if (snext<fStep-gTolerance) {
indnext = current->GetVolume()->GetNextNodeIndex();
if (compmatrix) {
fCurrentMatrix->CopyFrom(fGlobalMatrix);
fCurrentMatrix->Multiply(current->GetMatrix());
}
fIsStepExiting = kFALSE;
fIsStepEntering = kTRUE;
fStep=snext;
fNextNode = current;
nodefound = fNextNode;
idaughter = vlist[i];
while (indnext>=0) {
current = current->GetDaughter(indnext);
if (compmatrix) fCurrentMatrix->Multiply(current->GetMatrix());
fNextNode = current;
nodefound = current;
indnext = current->GetVolume()->GetNextNodeIndex();
}
}
}
}
return nodefound;
}
TGeoNode *TGeoNavigator::FindNextBoundaryAndStep(Double_t stepmax, Bool_t compsafe)
{
static Int_t icount = 0;
icount++;
Int_t iact = 3;
Int_t nextindex;
Bool_t is_assembly;
fIsStepExiting = kFALSE;
TGeoNode *skip;
fIsStepEntering = kFALSE;
fStep = stepmax;
Double_t snext = TGeoShape::Big();
if (compsafe) {
fIsOnBoundary = kFALSE;
Safety();
if (fSafety > stepmax+gTolerance) return fCurrentNode;
}
Double_t extra = (fIsOnBoundary)?gTolerance:0.0;
fIsOnBoundary = kFALSE;
fPoint[0] += extra*fDirection[0];
fPoint[1] += extra*fDirection[1];
fPoint[2] += extra*fDirection[2];
fCurrentMatrix->CopyFrom(fGlobalMatrix);
if (fIsOutside) {
snext = fGeometry->GetTopVolume()->GetShape()->DistFromOutside(fPoint, fDirection, iact, fStep);
if (snext < fStep-gTolerance) {
if (snext<=0) {
snext = 0.0;
fStep = snext;
fPoint[0] -= extra*fDirection[0];
fPoint[1] -= extra*fDirection[1];
fPoint[2] -= extra*fDirection[2];
} else {
fStep = snext+extra;
}
fIsStepEntering = kTRUE;
fNextNode = fGeometry->GetTopNode();
nextindex = fNextNode->GetVolume()->GetNextNodeIndex();
while (nextindex>=0) {
CdDown(nextindex);
fNextNode = fCurrentNode;
nextindex = fNextNode->GetVolume()->GetNextNodeIndex();
if (nextindex<0) fCurrentMatrix->CopyFrom(fGlobalMatrix);
}
fPoint[0] += snext*fDirection[0];
fPoint[1] += snext*fDirection[1];
fPoint[2] += snext*fDirection[2];
fIsOnBoundary = kTRUE;
fIsOutside = kFALSE;
return CrossBoundaryAndLocate(kTRUE, fCurrentNode);
}
if (snext<TGeoShape::Big()) {
fNextNode = fGeometry->GetTopNode();
fPoint[0] += (fStep-extra)*fDirection[0];
fPoint[1] += (fStep-extra)*fDirection[1];
fPoint[2] += (fStep-extra)*fDirection[2];
return fNextNode;
}
fNextNode = 0;
fIsOnBoundary = kFALSE;
return 0;
}
Double_t point[3],dir[3];
Int_t icrossed = -2;
fGlobalMatrix->MasterToLocal(fPoint, &point[0]);
fGlobalMatrix->MasterToLocalVect(fDirection, &dir[0]);
TGeoVolume *vol = fCurrentNode->GetVolume();
snext = vol->GetShape()->DistFromInside(point, dir, iact, fStep);
fNextNode = fCurrentNode;
if (snext <= gTolerance) {
snext = gTolerance;
fStep = snext;
fIsOnBoundary = kTRUE;
fIsStepEntering = kFALSE;
fIsStepExiting = kTRUE;
skip = fCurrentNode;
fPoint[0] += fStep*fDirection[0];
fPoint[1] += fStep*fDirection[1];
fPoint[2] += fStep*fDirection[2];
is_assembly = fCurrentNode->GetVolume()->IsAssembly();
if (!fLevel && !is_assembly) {
fIsOutside = kTRUE;
return 0;
}
if (fCurrentNode->IsOffset()) return CrossDivisionCell();
if (fLevel) CdUp();
else skip = 0;
return CrossBoundaryAndLocate(kFALSE, skip);
}
if (snext < fStep-gTolerance) {
icrossed = -1;
fStep = snext;
fIsStepEntering = kFALSE;
fIsStepExiting = kTRUE;
}
Int_t idaughter = -1;
TGeoNode *crossed = FindNextDaughterBoundary(point,dir, idaughter, kTRUE);
if (crossed) {
fIsStepExiting = kFALSE;
icrossed = idaughter;
fIsStepEntering = kTRUE;
}
TGeoNode *current = 0;
TGeoNode *dnode = 0;
TGeoVolume *mother = 0;
if (fNmany) {
Double_t mothpt[3];
Double_t vecpt[3];
Double_t dpt[3], dvec[3];
Int_t novlps;
Int_t safelevel = GetSafeLevel();
PushPath(safelevel+1);
while (fCurrentOverlapping) {
Int_t *ovlps = fCurrentNode->GetOverlaps(novlps);
CdUp();
mother = fCurrentNode->GetVolume();
fGlobalMatrix->MasterToLocal(fPoint, &mothpt[0]);
fGlobalMatrix->MasterToLocalVect(fDirection, &vecpt[0]);
snext = TGeoShape::Big();
if (!mother->IsAssembly()) snext = mother->GetShape()->DistFromInside(mothpt, vecpt, iact, fStep);
if (snext<fStep-gTolerance) {
icrossed = -1;
PopDummy();
PushPath(safelevel+1);
fIsStepEntering = kFALSE;
fIsStepExiting = kTRUE;
fStep = snext;
fCurrentMatrix->CopyFrom(fGlobalMatrix);
fNextNode = fCurrentNode;
}
for (Int_t i=0; i<novlps; i++) {
current = mother->GetNode(ovlps[i]);
if (!current->IsOverlapping()) {
current->cd();
current->MasterToLocal(&mothpt[0], &dpt[0]);
current->MasterToLocalVect(&vecpt[0], &dvec[0]);
snext = TGeoShape::Big();
if (!current->GetVolume()->Contains(dpt))
snext = current->GetVolume()->GetShape()->DistFromOutside(dpt, dvec, iact, fStep);
if (snext<fStep-gTolerance) {
PopDummy();
PushPath(safelevel+1);
fCurrentMatrix->CopyFrom(fGlobalMatrix);
fCurrentMatrix->Multiply(current->GetMatrix());
fIsStepEntering = kFALSE;
fIsStepExiting = kTRUE;
icrossed = ovlps[i];
fStep = snext;
fNextNode = current;
}
} else {
current->cd();
current->MasterToLocal(&mothpt[0], &dpt[0]);
current->MasterToLocalVect(&vecpt[0], &dvec[0]);
if (current->GetVolume()->Contains(dpt)) {
if (current->GetVolume()->GetNdaughters()) {
CdDown(ovlps[i]);
dnode = FindNextDaughterBoundary(dpt,dvec,idaughter,kFALSE);
if (dnode) {
fCurrentMatrix->CopyFrom(fGlobalMatrix);
fCurrentMatrix->Multiply(dnode->GetMatrix());
icrossed = idaughter;
PopDummy();
PushPath(safelevel+1);
fIsStepEntering = kFALSE;
fIsStepExiting = kTRUE;
fNextNode = dnode;
}
CdUp();
}
} else {
snext = current->GetVolume()->GetShape()->DistFromOutside(dpt, dvec, iact, fStep);
if (snext<fStep-gTolerance) {
fCurrentMatrix->CopyFrom(fGlobalMatrix);
fCurrentMatrix->Multiply(current->GetMatrix());
fIsStepEntering = kFALSE;
fIsStepExiting = kTRUE;
fStep = snext;
fNextNode = current;
icrossed = ovlps[i];
PopDummy();
PushPath(safelevel+1);
}
}
}
}
}
if (fNmany) {
Int_t up = 1;
Int_t imother;
Int_t nmany = fNmany;
Bool_t ovlp = kFALSE;
Bool_t nextovlp = kFALSE;
Bool_t offset = kFALSE;
TGeoNode *currentnode = fCurrentNode;
TGeoNode *mothernode, *mup;
TGeoHMatrix *matrix;
while (nmany) {
mothernode = GetMother(up);
mup = mothernode;
imother = up+1;
offset = kFALSE;
while (mup->IsOffset()) {
mup = GetMother(imother++);
offset = kTRUE;
}
nextovlp = mup->IsOverlapping();
if (offset) {
mothernode = mup;
if (nextovlp) nmany -= imother-up;
up = imother-1;
} else {
if (ovlp) nmany--;
}
if (ovlp || nextovlp) {
matrix = GetMotherMatrix(up);
matrix->MasterToLocal(fPoint,dpt);
matrix->MasterToLocalVect(fDirection,dvec);
snext = TGeoShape::Big();
if (!mothernode->GetVolume()->IsAssembly()) snext = mothernode->GetVolume()->GetShape()->DistFromInside(dpt,dvec,iact,fStep);
fIsStepEntering = kFALSE;
fIsStepExiting = kTRUE;
if (snext<fStep-gTolerance) {
fNextNode = mothernode;
fCurrentMatrix->CopyFrom(matrix);
fStep = snext;
while (up--) CdUp();
PopDummy();
PushPath();
icrossed = -1;
up = 1;
currentnode = fCurrentNode;
ovlp = currentnode->IsOverlapping();
continue;
}
}
currentnode = mothernode;
ovlp = nextovlp;
up++;
}
}
PopPath();
}
fPoint[0] += fStep*fDirection[0];
fPoint[1] += fStep*fDirection[1];
fPoint[2] += fStep*fDirection[2];
fStep += extra;
if (icrossed == -2) {
fIsOnBoundary = kFALSE;
return fCurrentNode;
}
fIsOnBoundary = kTRUE;
if (icrossed == -1) {
skip = fCurrentNode;
is_assembly = fCurrentNode->GetVolume()->IsAssembly();
if (!fLevel && !is_assembly) {
fIsOutside = kTRUE;
return 0;
}
if (fCurrentNode->IsOffset()) return CrossDivisionCell();
if (fLevel) CdUp();
else skip = 0;
return CrossBoundaryAndLocate(kFALSE, skip);
}
current = fCurrentNode;
CdDown(icrossed);
nextindex = fCurrentNode->GetVolume()->GetNextNodeIndex();
while (nextindex>=0) {
current = fCurrentNode;
CdDown(nextindex);
nextindex = fCurrentNode->GetVolume()->GetNextNodeIndex();
}
return CrossBoundaryAndLocate(kTRUE, current);
}
TGeoNode *TGeoNavigator::FindNode(Bool_t safe_start)
{
fSafety = 0;
fSearchOverlaps = kFALSE;
fIsOutside = kFALSE;
fIsEntering = fIsExiting = kFALSE;
fIsOnBoundary = kFALSE;
fStartSafe = safe_start;
fIsSameLocation = kTRUE;
TGeoNode *last = fCurrentNode;
TGeoNode *found = SearchNode();
if (found != last) {
fIsSameLocation = kFALSE;
} else {
if (last->IsOverlapping()) fIsSameLocation = kTRUE;
}
return found;
}
TGeoNode *TGeoNavigator::FindNode(Double_t x, Double_t y, Double_t z)
{
fPoint[0] = x;
fPoint[1] = y;
fPoint[2] = z;
fSafety = 0;
fSearchOverlaps = kFALSE;
fIsOutside = kFALSE;
fIsEntering = fIsExiting = kFALSE;
fIsOnBoundary = kFALSE;
fStartSafe = kTRUE;
fIsSameLocation = kTRUE;
TGeoNode *last = fCurrentNode;
TGeoNode *found = SearchNode();
if (found != last) {
fIsSameLocation = kFALSE;
} else {
if (last->IsOverlapping()) fIsSameLocation = kTRUE;
}
return found;
}
Double_t *TGeoNavigator::FindNormalFast()
{
if (!fNextNode) return 0;
Double_t local[3];
Double_t ldir[3];
Double_t lnorm[3];
fCurrentMatrix->MasterToLocal(fPoint, local);
fCurrentMatrix->MasterToLocalVect(fDirection, ldir);
fNextNode->GetVolume()->GetShape()->ComputeNormal(local, ldir,lnorm);
fCurrentMatrix->LocalToMasterVect(lnorm, fNormal);
return fNormal;
}
Double_t *TGeoNavigator::FindNormal(Bool_t )
{
return FindNormalFast();
}
TGeoNode *TGeoNavigator::InitTrack(const Double_t *point, const Double_t *dir)
{
SetCurrentPoint(point);
SetCurrentDirection(dir);
return FindNode();
}
TGeoNode *TGeoNavigator::InitTrack(Double_t x, Double_t y, Double_t z, Double_t nx, Double_t ny, Double_t nz)
{
SetCurrentPoint(x,y,z);
SetCurrentDirection(nx,ny,nz);
return FindNode();
}
void TGeoNavigator::ResetState()
{
fSearchOverlaps = kFALSE;
fIsOutside = kFALSE;
fIsEntering = fIsExiting = kFALSE;
fIsOnBoundary = kFALSE;
fIsStepEntering = fIsStepExiting = kFALSE;
}
Double_t TGeoNavigator::Safety(Bool_t inside)
{
if (fIsOnBoundary) {
fSafety = 0;
return fSafety;
}
Double_t point[3];
if (!inside) fSafety = TGeoShape::Big();
if (fIsOutside) {
fSafety = fGeometry->GetTopVolume()->GetShape()->Safety(fPoint,kFALSE);
if (fSafety < gTolerance) {
fSafety = 0;
fIsOnBoundary = kTRUE;
}
return fSafety;
}
fGlobalMatrix->MasterToLocal(fPoint, point);
TGeoVolume *vol = fCurrentNode->GetVolume();
if (!inside) {
fSafety = vol->GetShape()->Safety(point, kTRUE);
if (fSafety < gTolerance) {
fSafety = 0;
fIsOnBoundary = kTRUE;
return fSafety;
}
}
TObjArray *nodes = vol->GetNodes();
Int_t nd = fCurrentNode->GetNdaughters();
if (!nd && !fCurrentOverlapping) return fSafety;
TGeoNode *node;
Double_t safe;
Int_t id;
TGeoPatternFinder *finder = vol->GetFinder();
if (finder) {
Int_t ifirst = finder->GetDivIndex();
node = (TGeoNode*)nodes->UncheckedAt(ifirst);
node->cd();
safe = node->Safety(point, kFALSE);
if (safe < gTolerance) {
fSafety=0;
fIsOnBoundary = kTRUE;
return fSafety;
}
if (safe<fSafety) fSafety=safe;
Int_t ilast = ifirst+finder->GetNdiv()-1;
if (ilast==ifirst) return fSafety;
node = (TGeoNode*)nodes->UncheckedAt(ilast);
node->cd();
safe = node->Safety(point, kFALSE);
if (safe < gTolerance) {
fSafety=0;
fIsOnBoundary = kTRUE;
return fSafety;
}
if (safe<fSafety) fSafety=safe;
if (fCurrentOverlapping && !inside) SafetyOverlaps();
return fSafety;
}
TGeoVoxelFinder *voxels = vol->GetVoxels();
if (!voxels) {
for (id=0; id<nd; id++) {
node = (TGeoNode*)nodes->UncheckedAt(id);
safe = node->Safety(point, kFALSE);
if (safe < gTolerance) {
fSafety=0;
fIsOnBoundary = kTRUE;
return fSafety;
}
if (safe<fSafety) fSafety=safe;
}
if (fNmany && !inside) SafetyOverlaps();
return fSafety;
} else {
if (voxels->NeedRebuild()) {
voxels->Voxelize();
vol->FindOverlaps();
}
}
Double_t *boxes = voxels->GetBoxes();
for (id=0; id<nd; id++) {
Int_t ist = 6*id;
Double_t dxyz = 0.;
Double_t dxyz0 = TMath::Abs(point[0]-boxes[ist+3])-boxes[ist];
if (dxyz0 > fSafety) continue;
Double_t dxyz1 = TMath::Abs(point[1]-boxes[ist+4])-boxes[ist+1];
if (dxyz1 > fSafety) continue;
Double_t dxyz2 = TMath::Abs(point[2]-boxes[ist+5])-boxes[ist+2];
if (dxyz2 > fSafety) continue;
if (dxyz0>0) dxyz+=dxyz0*dxyz0;
if (dxyz1>0) dxyz+=dxyz1*dxyz1;
if (dxyz2>0) dxyz+=dxyz2*dxyz2;
if (dxyz >= fSafety*fSafety) continue;
node = (TGeoNode*)nodes->UncheckedAt(id);
safe = node->Safety(point, kFALSE);
if (safe<gTolerance) {
fSafety=0;
fIsOnBoundary = kTRUE;
return fSafety;
}
if (safe<fSafety) fSafety = safe;
}
if (fNmany && !inside) SafetyOverlaps();
return fSafety;
}
void TGeoNavigator::SafetyOverlaps()
{
Double_t point[3], local[3];
Double_t safe;
Bool_t contains;
TGeoNode *nodeovlp;
TGeoVolume *vol;
Int_t novlp, io;
Int_t *ovlp;
Int_t safelevel = GetSafeLevel();
PushPath(safelevel+1);
while (fCurrentOverlapping) {
ovlp = fCurrentNode->GetOverlaps(novlp);
CdUp();
vol = fCurrentNode->GetVolume();
gGeoManager->MasterToLocal(fPoint, point);
contains = fCurrentNode->GetVolume()->Contains(point);
safe = fCurrentNode->GetVolume()->GetShape()->Safety(point, contains);
if (safe<fSafety && safe>=0) fSafety=safe;
if (!novlp || !contains) continue;
for (io=0; io<novlp; io++) {
nodeovlp = vol->GetNode(ovlp[io]);
nodeovlp->GetMatrix()->MasterToLocal(point,local);
contains = nodeovlp->GetVolume()->Contains(local);
if (contains) {
CdDown(ovlp[io]);
safe = Safety(kTRUE);
CdUp();
} else {
safe = nodeovlp->GetVolume()->GetShape()->Safety(local, kFALSE);
}
if (safe<fSafety && safe>=0) fSafety=safe;
}
}
if (fNmany) {
Int_t up = 1;
Int_t imother;
Int_t nmany = fNmany;
Bool_t crtovlp = kFALSE;
Bool_t nextovlp = kFALSE;
TGeoNode *current = fCurrentNode;
TGeoNode *mother, *mup;
TGeoHMatrix *matrix;
while (nmany) {
mother = GetMother(up);
mup = mother;
imother = up+1;
while (mup->IsOffset()) mup = GetMother(imother++);
nextovlp = mup->IsOverlapping();
if (crtovlp) nmany--;
if (crtovlp || nextovlp) {
matrix = GetMotherMatrix(up);
matrix->MasterToLocal(fPoint,local);
safe = mother->GetVolume()->GetShape()->Safety(local,kTRUE);
if (safe<fSafety) fSafety = safe;
current = mother;
crtovlp = nextovlp;
}
up++;
}
}
PopPath();
if (fSafety < gTolerance) {
fSafety = 0.;
fIsOnBoundary = kTRUE;
}
}
TGeoNode *TGeoNavigator::SearchNode(Bool_t downwards, const TGeoNode *skipnode)
{
Double_t point[3];
fNextDaughterIndex = -2;
TGeoVolume *vol = 0;
Bool_t inside_current = (fCurrentNode==skipnode)?kTRUE:kFALSE;
if (!downwards) {
if (fGeometry->IsActivityEnabled() && !vol->IsActive()) {
CdUp();
fIsSameLocation = kFALSE;
return SearchNode(kFALSE, skipnode);
}
vol=fCurrentNode->GetVolume();
if (vol->IsAssembly()) inside_current=kTRUE;
if (!inside_current) {
fGlobalMatrix->MasterToLocal(fPoint, point);
inside_current = vol->Contains(point);
}
if (fNmany) {
inside_current = GotoSafeLevel();
}
if (!inside_current) {
fIsSameLocation = kFALSE;
TGeoNode *skip = fCurrentNode;
if (!fLevel) {
fIsOutside = kTRUE;
return 0;
}
CdUp();
return SearchNode(kFALSE, skip);
}
}
vol = fCurrentNode->GetVolume();
fGlobalMatrix->MasterToLocal(fPoint, point);
if (!inside_current && downwards) {
inside_current = vol->Contains(point);
if (!inside_current) {
fIsSameLocation = kFALSE;
return 0;
} else {
if (fIsOutside) {
fIsOutside = kFALSE;
fIsSameLocation = kFALSE;
}
}
}
TGeoNode *node;
Int_t ncheck = 0;
if (!fCurrentOverlapping) {
fSearchOverlaps = kFALSE;
}
Int_t crtindex = vol->GetCurrentNodeIndex();
while (crtindex>=0 && downwards) {
CdDown(crtindex);
vol = fCurrentNode->GetVolume();
crtindex = vol->GetCurrentNodeIndex();
if (crtindex<0) fGlobalMatrix->MasterToLocal(fPoint, point);
}
Int_t nd = vol->GetNdaughters();
if (!nd) return fCurrentNode;
if (fGeometry->IsActivityEnabled() && !vol->IsActiveDaughters()) return fCurrentNode;
TGeoPatternFinder *finder = vol->GetFinder();
if (finder) {
node=finder->FindNode(&point[0]);
if (node && node!=skipnode) {
fIsSameLocation = kFALSE;
CdDown(node->GetIndex());
return SearchNode(kTRUE, node);
}
while (fCurrentNode && fCurrentNode->IsOffset()) CdUp();
return fCurrentNode;
}
TGeoVoxelFinder *voxels = vol->GetVoxels();
Int_t *check_list = 0;
Int_t id;
if (voxels) {
check_list = voxels->GetCheckList(&point[0], ncheck);
if (!check_list) {
if (!fCurrentNode->GetVolume()->IsAssembly()) return fCurrentNode;
node = fCurrentNode;
if (!fLevel) {
fIsOutside = kTRUE;
return 0;
}
CdUp();
return SearchNode(kFALSE,node);
}
for (id=0; id<ncheck; id++) {
node = vol->GetNode(check_list[id]);
if (node==skipnode) continue;
if (fGeometry->IsActivityEnabled() && !node->GetVolume()->IsActive()) continue;
if ((id<(ncheck-1)) && node->IsOverlapping()) {
if (ncheck+fOverlapMark > fOverlapSize) {
fOverlapSize = 2*(ncheck+fOverlapMark);
delete [] fOverlapClusters;
fOverlapClusters = new Int_t[fOverlapSize];
}
Int_t *cluster = fOverlapClusters + fOverlapMark;
Int_t nc = GetTouchedCluster(id, &point[0], check_list, ncheck, cluster);
if (nc>1) {
fOverlapMark += nc;
node = FindInCluster(cluster, nc);
fOverlapMark -= nc;
return node;
}
}
CdDown(check_list[id]);
node = SearchNode(kTRUE);
if (node) {
fIsSameLocation = kFALSE;
return node;
}
CdUp();
}
if (!fCurrentNode->GetVolume()->IsAssembly()) return fCurrentNode;
node = fCurrentNode;
if (!fLevel) {
fIsOutside = kTRUE;
return 0;
}
CdUp();
return SearchNode(kFALSE,node);
}
for (id=0; id<nd; id++) {
node=fCurrentNode->GetDaughter(id);
if (node==skipnode) continue;
if (fGeometry->IsActivityEnabled() && !node->GetVolume()->IsActive()) continue;
CdDown(id);
node = SearchNode(kTRUE);
if (node) {
fIsSameLocation = kFALSE;
return node;
}
CdUp();
}
if (fCurrentNode->GetVolume()->IsAssembly()) {
node = fCurrentNode;
if (!fLevel) {
fIsOutside = kTRUE;
return 0;
}
CdUp();
return SearchNode(kFALSE,node);
}
return fCurrentNode;
}
TGeoNode *TGeoNavigator::FindInCluster(Int_t *cluster, Int_t nc)
{
TGeoNode *clnode = 0;
TGeoNode *priority = fLastNode;
TGeoNode *current = fCurrentNode;
TGeoNode *found = 0;
Int_t ipop = PushPath();
fSearchOverlaps = kTRUE;
Int_t deepest = fLevel;
Int_t deepest_virtual = fLevel-GetVirtualLevel();
Int_t found_virtual = 0;
Bool_t replace = kFALSE;
Bool_t added = kFALSE;
Int_t i;
for (i=0; i<nc; i++) {
clnode = current->GetDaughter(cluster[i]);
CdDown(cluster[i]);
found = SearchNode(kTRUE, clnode);
if (!fSearchOverlaps) {
PopDummy(ipop);
return found;
}
found_virtual = fLevel-GetVirtualLevel();
if (added) {
if (found_virtual>deepest_virtual) {
replace = kTRUE;
} else {
if (found_virtual==deepest_virtual) {
if (fLevel>deepest) {
replace = kTRUE;
} else {
if ((fLevel==deepest) && (clnode==priority)) replace=kTRUE;
else replace = kFALSE;
}
} else replace = kFALSE;
}
if (i==(nc-1)) {
if (replace) {
PopDummy(ipop);
return found;
} else {
fCurrentOverlapping = PopPath();
PopDummy(ipop);
return fCurrentNode;
}
}
if (replace) {
PopDummy();
PushPath();
deepest = fLevel;
deepest_virtual = found_virtual;
}
fCurrentOverlapping = PopPath(ipop);
} else {
PushPath();
added = kTRUE;
deepest = fLevel;
deepest_virtual = found_virtual;
fCurrentOverlapping = PopPath(ipop);
}
}
PopDummy(ipop);
return fCurrentNode;
}
Int_t TGeoNavigator::GetTouchedCluster(Int_t start, Double_t *point,
Int_t *check_list, Int_t ncheck, Int_t *result)
{
TGeoNode *current = fCurrentNode->GetDaughter(check_list[start]);
Int_t novlps = 0;
Int_t *ovlps = current->GetOverlaps(novlps);
if (!ovlps) return 0;
Double_t local[3];
Int_t ntotal = 0;
current->MasterToLocal(point, &local[0]);
if (current->GetVolume()->Contains(&local[0])) {
result[ntotal++]=check_list[start];
}
Int_t jst=0, i, j;
while ((ovlps[jst]<=check_list[start]) && (jst<novlps)) jst++;
if (jst==novlps) return 0;
for (i=start; i<ncheck; i++) {
for (j=jst; j<novlps; j++) {
if (check_list[i]==ovlps[j]) {
current = fCurrentNode->GetDaughter(check_list[i]);
if (fGeometry->IsActivityEnabled() && !current->GetVolume()->IsActive()) continue;
current->MasterToLocal(point, &local[0]);
if (current->GetVolume()->Contains(&local[0])) {
result[ntotal++]=check_list[i];
}
}
}
}
return ntotal;
}
TGeoNode *TGeoNavigator::Step(Bool_t is_geom, Bool_t cross)
{
Double_t epsil = 0;
if (fStep<1E-6) {
fIsNullStep=kTRUE;
if (fStep<0) fStep = 0.;
} else {
fIsNullStep=kFALSE;
}
if (is_geom) epsil=(cross)?1E-6:-1E-6;
TGeoNode *old = fCurrentNode;
Int_t idold = GetNodeId();
if (fIsOutside) old = 0;
fStep += epsil;
for (Int_t i=0; i<3; i++) fPoint[i]+=fStep*fDirection[i];
TGeoNode *current = FindNode();
if (is_geom) {
fIsEntering = (current==old)?kFALSE:kTRUE;
if (!fIsEntering) {
Int_t id = GetNodeId();
fIsEntering = (id==idold)?kFALSE:kTRUE;
}
fIsExiting = !fIsEntering;
if (fIsEntering && fIsNullStep) fIsNullStep = kFALSE;
fIsOnBoundary = kTRUE;
} else {
fIsEntering = fIsExiting = kFALSE;
fIsOnBoundary = kFALSE;
}
return current;
}
Int_t TGeoNavigator::GetVirtualLevel()
{
if (!fCurrentOverlapping) return 0;
Int_t new_media = 0;
TGeoMedium *medium = fCurrentNode->GetMedium();
Int_t virtual_level = 1;
TGeoNode *mother = 0;
while ((mother=GetMother(virtual_level))) {
if (!mother->IsOverlapping() && !mother->IsOffset()) {
if (!new_media) new_media=(mother->GetMedium()==medium)?0:virtual_level;
break;
}
if (!new_media) new_media=(mother->GetMedium()==medium)?0:virtual_level;
virtual_level++;
}
return (new_media==0)?virtual_level:(new_media-1);
}
Bool_t TGeoNavigator::GotoSafeLevel()
{
while (fCurrentOverlapping && fLevel) CdUp();
Double_t point[3];
fGlobalMatrix->MasterToLocal(fPoint, point);
if (!fCurrentNode->GetVolume()->Contains(point)) return kFALSE;
if (fNmany) {
Int_t up = 1;
Int_t imother;
Int_t nmany = fNmany;
Bool_t ovlp = kFALSE;
Bool_t nextovlp = kFALSE;
TGeoNode *current = fCurrentNode;
TGeoNode *mother, *mup;
TGeoHMatrix *matrix;
while (nmany) {
mother = GetMother(up);
if (!mother) return kTRUE;
mup = mother;
imother = up+1;
while (mup->IsOffset()) mup = GetMother(imother++);
nextovlp = mup->IsOverlapping();
if (ovlp) nmany--;
if (ovlp || nextovlp) {
matrix = GetMotherMatrix(up);
matrix->MasterToLocal(fPoint,point);
if (!mother->GetVolume()->Contains(point)) {
up++;
while (up--) CdUp();
return GotoSafeLevel();
}
}
current = mother;
ovlp = nextovlp;
up++;
}
}
return kTRUE;
}
Int_t TGeoNavigator::GetSafeLevel() const
{
Bool_t overlapping = fCurrentOverlapping;
if (!overlapping) return fLevel;
Int_t level = fLevel;
TGeoNode *node;
while (overlapping && level) {
level--;
node = GetMother(fLevel-level);
if (!node->IsOffset()) overlapping = node->IsOverlapping();
}
return level;
}
void TGeoNavigator::InspectState() const
{
Info("InspectState","Current path is: %s",GetPath());
Int_t level;
TGeoNode *node;
Bool_t is_offset, is_overlapping;
for (level=0; level<fLevel+1; level++) {
node = GetMother(fLevel-level);
if (!node) continue;
is_offset = node->IsOffset();
is_overlapping = node->IsOverlapping();
Info("InspectState","level %i: %s div=%i many=%i",level,node->GetName(),is_offset,is_overlapping);
}
Info("InspectState","on_bound=%i entering=%i", fIsOnBoundary, fIsEntering);
}
Bool_t TGeoNavigator::IsSameLocation(Double_t x, Double_t y, Double_t z, Bool_t change)
{
Double_t oldpt[3];
if (fLastSafety>0) {
Double_t dx = (x-fLastPoint[0]);
Double_t dy = (y-fLastPoint[1]);
Double_t dz = (z-fLastPoint[2]);
Double_t dsq = dx*dx+dy*dy+dz*dz;
if (dsq<fLastSafety*fLastSafety) return kTRUE;
}
if (fCurrentOverlapping) {
Int_t cid = GetCurrentNodeId();
if (!change) PushPoint();
memcpy(oldpt, fPoint, kN3);
gGeoManager->SetCurrentPoint(x,y,z);
gGeoManager->SearchNode();
memcpy(fPoint, oldpt, kN3);
Bool_t same = (cid==GetCurrentNodeId())?kTRUE:kFALSE;
if (!change) PopPoint();
return same;
}
Double_t point[3];
point[0] = x;
point[1] = y;
point[2] = z;
if (change) memcpy(fPoint, point, kN3);
TGeoVolume *vol = fCurrentNode->GetVolume();
if (fIsOutside) {
if (vol->GetShape()->Contains(point)) {
if (!change) return kFALSE;
FindNode(x,y,z);
return kFALSE;
}
return kTRUE;
}
Double_t local[3];
MasterToLocal(point,local);
if (!vol->GetShape()->Contains(local)) {
if (!change) return kFALSE;
CdUp();
FindNode(x,y,z);
return kFALSE;
}
Int_t nd = vol->GetNdaughters();
if (!nd) return kTRUE;
TGeoNode *node;
TGeoPatternFinder *finder = vol->GetFinder();
if (finder) {
node=finder->FindNode(local);
if (node) {
if (!change) return kFALSE;
CdDown(node->GetIndex());
SearchNode(kTRUE,node);
return kFALSE;
}
return kTRUE;
}
TGeoVoxelFinder *voxels = vol->GetVoxels();
Int_t *check_list = 0;
Int_t ncheck = 0;
Double_t local1[3];
if (voxels) {
check_list = voxels->GetCheckList(local, ncheck);
if (!check_list) return kTRUE;
if (!change) PushPath();
for (Int_t id=0; id<ncheck; id++) {
node = vol->GetNode(check_list[id]);
CdDown(check_list[id]);
fCurrentNode->GetMatrix()->MasterToLocal(local,local1);
if (fCurrentNode->GetVolume()->GetShape()->Contains(local1)) {
if (!change) {
PopPath();
return kFALSE;
}
SearchNode(kTRUE);
return kFALSE;
}
CdUp();
}
if (!change) PopPath();
return kTRUE;
}
Int_t id = 0;
if (!change) PushPath();
while ((node=fCurrentNode->GetDaughter(id++))) {
CdDown(id-1);
fCurrentNode->GetMatrix()->MasterToLocal(local,local1);
if (fCurrentNode->GetVolume()->GetShape()->Contains(local1)) {
if (!change) {
PopPath();
return kFALSE;
}
SearchNode(kTRUE);
return kFALSE;
}
CdUp();
if (id == nd) {
if (!change) PopPath();
return kTRUE;
}
}
if (!change) PopPath();
return kTRUE;
}
Bool_t TGeoNavigator::IsSamePoint(Double_t x, Double_t y, Double_t z) const
{
if (x==fLastPoint[0]) {
if (y==fLastPoint[1]) {
if (z==fLastPoint[2]) return kTRUE;
}
}
return kFALSE;
}
void TGeoNavigator::DoBackupState()
{
if (fBackupState) fBackupState->SetState(fLevel,0, fNmany, fCurrentOverlapping);
}
void TGeoNavigator::DoRestoreState()
{
if (fBackupState && fCache) {
fCurrentOverlapping = fCache->RestoreState(fNmany, fBackupState);
fCurrentNode=fCache->GetNode();
fGlobalMatrix = fCache->GetCurrentMatrix();
fLevel=fCache->GetLevel();
}
}
TGeoHMatrix *TGeoNavigator::GetHMatrix()
{
if (!fCurrentMatrix) {
fCurrentMatrix = new TGeoHMatrix();
fCurrentMatrix->RegisterYourself();
}
return fCurrentMatrix;
}
const char *TGeoNavigator::GetPath() const
{
if (fIsOutside) return kGeoOutsidePath;
return fCache->GetPath();
}
void TGeoNavigator::MasterToTop(const Double_t *master, Double_t *top) const
{
fCurrentMatrix->MasterToLocal(master, top);
}
void TGeoNavigator::TopToMaster(const Double_t *top, Double_t *master) const
{
fCurrentMatrix->LocalToMaster(top, master);
}
void TGeoNavigator::ResetAll()
{
GetHMatrix();
*fCurrentMatrix = gGeoIdentity;
fCurrentNode = fGeometry->GetTopNode();
ResetState();
fStep = 0.;
fSafety = 0.;
fLastSafety = 0.;
fLevel = 0;
fNmany = 0;
fNextDaughterIndex = -2;
fCurrentOverlapping = kFALSE;
fStartSafe = kFALSE;
fIsSameLocation = kFALSE;
fIsNullStep = kFALSE;
fCurrentVolume = fGeometry->GetTopVolume();
fCurrentNode = fGeometry->GetTopNode();
fLastNode = 0;
fNextNode = 0;
fPath = "";
if (fCache) {
Bool_t dummy=fCache->IsDummy();
Bool_t nodeid = fCache->HasIdArray();
delete fCache;
delete fBackupState;
fCache = 0;
BuildCache(dummy,nodeid);
}
}
Last change: Wed Dec 17 16:19:37 2008
Last generated: 2008-12-17 16:19
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.