#include "TClass.h"
#include "TGeoManager.h"
#include "TGeoVoxelFinder.h"
#include "TGeoCache.h"
#include "TGeoMatrix.h"
#include "TGeoShapeAssembly.h"
#include "TGeoVolume.h"
#include "TVirtualGeoPainter.h"
#include "TGeoPhysicalNode.h"
ClassImp(TGeoPhysicalNode)
TGeoPhysicalNode::TGeoPhysicalNode() : TNamed()
{
fLevel = 0;
fMatrices = 0;
fNodes = 0;
fMatrixOrig = 0;
SetVisibility(kTRUE);
SetVisibleFull(kFALSE);
SetIsVolAtt(kTRUE);
SetAligned(kFALSE);
}
TGeoPhysicalNode::TGeoPhysicalNode(const char *path) : TNamed(path,"")
{
if (!strlen(path)) {
Error("ctor", "path not valid");
return;
}
fLevel = 0;
fMatrices = new TObjArray(30);
fNodes = new TObjArray(30);
fMatrixOrig = 0;
SetPath(path);
SetVisibility(kTRUE);
SetVisibleFull(kFALSE);
SetIsVolAtt(kTRUE);
SetAligned(kFALSE);
}
TGeoPhysicalNode::TGeoPhysicalNode(const TGeoPhysicalNode& gpn) :
TNamed(gpn),
TAttLine(gpn),
fLevel(gpn.fLevel),
fMatrices(gpn.fMatrices),
fNodes(gpn.fNodes),
fMatrixOrig(gpn.fMatrixOrig)
{
}
TGeoPhysicalNode& TGeoPhysicalNode::operator=(const TGeoPhysicalNode& gpn)
{
if(this!=&gpn) {
TNamed::operator=(gpn);
TAttLine::operator=(gpn);
fLevel=gpn.fLevel;
fMatrices=gpn.fMatrices;
fNodes=gpn.fNodes;
fMatrixOrig=gpn.fMatrixOrig;
}
return *this;
}
TGeoPhysicalNode::~TGeoPhysicalNode()
{
if (fMatrices) {
fMatrices->Delete();
delete fMatrices;
}
if (fNodes) delete fNodes;
if (fMatrixOrig) delete fMatrixOrig;
}
void TGeoPhysicalNode::Align(TGeoMatrix *newmat, TGeoShape *newshape, Bool_t check, Double_t ovlp)
{
if (!newmat && !newshape) return;
if (TGeoManager::IsLocked()) {
Error("Align", "Not performed. Geometry in LOCKED mode !");
return;
}
TGeoNode *node = GetNode();
if (node->IsOffset()) {
Error("Align", "Cannot align division nodes: %s\n",node->GetName());
return;
}
TGeoNode *nnode = 0;
TGeoVolume *vm = GetVolume(0);
TGeoVolume *vd = 0;
Int_t i;
if (!IsAligned()) {
Int_t *id = new Int_t[fLevel];
for (i=0; i<fLevel; i++) {
vd = GetVolume(i);
node = GetNode(i+1);
id[i] = vd->GetIndex(node);
if (id[i]<0) {
Error("Align","%s cannot align node %s",GetName(), node->GetName());
delete [] id;
return;
}
}
for (i=0; i<fLevel; i++) {
node = GetNode(i+1);
vd = node->GetVolume()->CloneVolume();
nnode = node->MakeCopyNode();
nnode->SetVolume(vd);
nnode->SetMotherVolume(vm);
if (vm->TestBit(TGeoVolume::kVolumeImportNodes)) {
gGeoManager->GetListOfGShapes()->Add(nnode);
}
vm->GetNodes()->RemoveAt(id[i]);
vm->GetNodes()->AddAt(nnode,id[i]);
fNodes->RemoveAt(i+1);
fNodes->AddAt(nnode,i+1);
vm = vd;
}
delete [] id;
} else {
nnode = GetNode();
}
TGeoNodeMatrix *aligned = (TGeoNodeMatrix*)nnode;
vm = nnode->GetMotherVolume();
vd = nnode->GetVolume();
if (newmat) {
if (!newmat->IsRegistered()) newmat->RegisterYourself();
aligned->SetMatrix(newmat);
TGeoHMatrix *global = GetMatrix();
TGeoHMatrix *up = GetMatrix(fLevel-1);
*global = up;
global->Multiply(newmat);
}
if (newshape) vd->SetShape(newshape);
for (i=fLevel-1; i>0; i--) {
Bool_t dassm = vd->IsAssembly();
vd = GetVolume(i);
Bool_t cassm = vd->IsAssembly();
if (cassm) ((TGeoShapeAssembly*)vd->GetShape())->NeedsBBoxRecompute();
if ((cassm || dassm) && vd->GetVoxels()) vd->GetVoxels()->SetNeedRebuild();
if (!cassm) break;
}
TGeoVoxelFinder *voxels = vm->GetVoxels();
if (voxels) voxels->SetNeedRebuild();
if (check) {
if (voxels) {
voxels->Voxelize();
vm->FindOverlaps();
}
i = fLevel;
node = GetNode(i);
if (node->IsOverlapping()) {
Info("Align", "The check for overlaps for node: \n%s\n cannot be performed since the node is declared possibly overlapping",
GetName());
} else {
gGeoManager->SetCheckedNode(node);
while ((node=GetNode(--i))) {
if (!node->GetVolume()->IsAssembly()) break;
}
if (node && node->IsOverlapping()) {
Info("Align", "The check for overlaps for assembly node: \n%s\n cannot be performed since the parent %s is declared possibly overlapping",
GetName(), node->GetName());
node = 0;
}
if (node) node->CheckOverlaps(ovlp);
gGeoManager->SetCheckedNode(0);
}
}
gGeoManager->CdTop();
SetAligned(kTRUE);
}
void TGeoPhysicalNode::cd() const
{
gGeoManager->cd(fName.Data());
}
void TGeoPhysicalNode::Draw(Option_t * )
{
}
TGeoNode *TGeoPhysicalNode::GetMother(Int_t levup) const
{
Int_t ind = fLevel-levup;
if (ind<0) return 0;
return (TGeoNode*)fNodes->UncheckedAt(ind);
}
TGeoHMatrix *TGeoPhysicalNode::GetMatrix(Int_t level) const
{
if (level<0) return (TGeoHMatrix*)fMatrices->UncheckedAt(fLevel);
if (level>fLevel) return 0;
return (TGeoHMatrix*)fMatrices->UncheckedAt(level);
}
TGeoNode *TGeoPhysicalNode::GetNode(Int_t level) const
{
if (level<0) return (TGeoNode*)fNodes->UncheckedAt(fLevel);
if (level>fLevel) return 0;
return (TGeoNode*)fNodes->UncheckedAt(level);
}
TGeoVolume *TGeoPhysicalNode::GetVolume(Int_t level) const
{
TGeoNode *node = GetNode(level);
if (node) return node->GetVolume();
return 0;
}
TGeoShape *TGeoPhysicalNode::GetShape(Int_t level) const
{
TGeoVolume *vol = GetVolume(level);
if (vol) return vol->GetShape();
return 0;
}
void TGeoPhysicalNode::Paint(Option_t * )
{
TVirtualGeoPainter *painter = gGeoManager->GetGeomPainter();
if (!painter) return;
}
void TGeoPhysicalNode::Print(Option_t * ) const
{
printf("TGeoPhysicalNode: %s level=%d aligned=%d\n", fName.Data(), fLevel, IsAligned());
for (Int_t i=0; i<=fLevel; i++) {
printf(" level %d: node %s\n", i, GetNode(i)->GetName());
printf(" local matrix:\n");
if (GetNode(i)->GetMatrix()->IsIdentity()) printf(" IDENTITY\n");
else GetNode(i)->GetMatrix()->Print();
printf(" global matrix:\n");
if (GetMatrix(i)->IsIdentity()) printf(" IDENTITY\n");
else GetMatrix(i)->Print();
}
if (IsAligned() && fMatrixOrig) {
printf(" original local matrix:\n");
fMatrixOrig->Print();
}
}
void TGeoPhysicalNode::Refresh()
{
SetPath(fName.Data());
}
void TGeoPhysicalNode::SetBranchAsState()
{
TGeoNodeCache *cache = gGeoManager->GetCache();
if (!cache) {
Error("SetBranchAsState","no state available");
return;
}
if (!cache->IsDummy()) {
Error("SetBranchAsState", "not implemented for full cache");
return;
}
if (!fNodes) fNodes = new TObjArray(30);
if (!fMatrices) fMatrices = new TObjArray(30);
TGeoHMatrix **matrices = (TGeoHMatrix **) cache->GetMatrices();
TGeoNode **branch = (TGeoNode **) cache->GetBranch();
Bool_t refresh = (fLevel>0)?kTRUE:kFALSE;
if (refresh) {
TGeoHMatrix *current;
for (Int_t i=0; i<=fLevel; i++) {
fNodes->AddAtAndExpand(branch[i],i);
current = (TGeoHMatrix*)fMatrices->UncheckedAt(i);
*current = *matrices[i];
}
return;
}
fLevel = gGeoManager->GetLevel();
for (Int_t i=0; i<=fLevel; i++) {
fNodes->AddAtAndExpand(branch[i],i);
fMatrices->AddAtAndExpand(new TGeoHMatrix(*matrices[i]),i);
}
TGeoNode *node = (TGeoNode*)fNodes->UncheckedAt(fLevel);
if (!fMatrixOrig) fMatrixOrig = new TGeoHMatrix();
*fMatrixOrig = node->GetMatrix();
}
void TGeoPhysicalNode::SetMatrixOrig(const TGeoMatrix *local)
{
if (!fMatrixOrig) fMatrixOrig = new TGeoHMatrix();
if (!local) fMatrixOrig->Clear();
*fMatrixOrig = local;
}
Bool_t TGeoPhysicalNode::SetPath(const char *path)
{
if (!gGeoManager->cd(path)) {
Error("SetPath","wrong path -> maybe RestoreMasterVolume");
return kFALSE;
}
SetBranchAsState();
return kTRUE;
}
ClassImp(TGeoPNEntry)
TGeoPNEntry::TGeoPNEntry()
{
fNode = 0;
fMatrix = 0;
fGlobalOrig = 0;
}
TGeoPNEntry::TGeoPNEntry(const char *name, const char *path)
:TNamed(name, path)
{
if (!gGeoManager || !gGeoManager->IsClosed() || !gGeoManager->CheckPath(path)) {
TString errmsg("Cannot define a physical node link without a closed geometry and a valid path !");
Error("ctor", "%s", errmsg.Data());
throw errmsg;
return;
}
gGeoManager->PushPath();
gGeoManager->cd(path);
fGlobalOrig = new TGeoHMatrix();
*fGlobalOrig = gGeoManager->GetCurrentMatrix();
gGeoManager->PopPath();
fNode = 0;
fMatrix = 0;
}
TGeoPNEntry::~TGeoPNEntry()
{
if (fMatrix && !fMatrix->IsRegistered()) delete fMatrix;
delete fGlobalOrig;
}
void TGeoPNEntry::SetPhysicalNode(TGeoPhysicalNode *node)
{
if (fNode && node) {
Warning("SetPhysicalNode", "Physical node changed for entry %s", GetName());
Warning("SetPhysicalNode", "=== New path: %s", node->GetName());
}
fNode = node;
}
void TGeoPNEntry::SetMatrix(const TGeoHMatrix *mat)
{
fMatrix = mat;
}