TGeoPhysicalNode.cxx

Go to the documentation of this file.
00001 // @(#)root/geom:$Id: TGeoPhysicalNode.cxx 36632 2010-11-12 15:57:07Z agheata $
00002 // Author: Andrei Gheata   17/02/04
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 //_____________________________________________________________________________
00013 // TGeoPhysicalNode, TGeoPNEntry
00014 //
00015 // Physical nodes are the actual 'touchable' objects in the geometry, representing
00016 // a path of positioned volumes starting with the top node:
00017 //    path=/TOP/A_1/B_4/C_3 , where A, B, C represent names of volumes.
00018 // The number of physical nodes is given by the total number of possible of
00019 // branches in the geometry hierarchy. In case of detector geometries and
00020 // specially for calorimeters this number can be of the order 1e6-1e9, therefore
00021 // it is impossible to create all physical nodes as objects in memory. In TGeo,
00022 // physical nodes are represented by the class TGeoPhysicalNode and can be created
00023 // on demand for alignment purposes:
00024 //
00025 //    TGeoPhysicalNode *pn = new TGeoPhysicalNode("path_to_object")
00026 //
00027 // Once created, a physical node can be misaligned, meaning that its position
00028 // or even shape can be changed:
00029 //
00030 //    pn->Align(TGeoMatrix* newmat, TGeoShape* newshape, Bool_t check=kFALSE)
00031 //
00032 // The knowledge of the path to the objects that need to be misaligned is
00033 // essential since there is no other way of identifying them. One can however
00034 // create 'symbolic links' to any complex path to make it more representable
00035 // for the object it designates:
00036 //
00037 //    TGeoPNEntry *pne = new TGeoPNEntry("TPC_SECTOR_2", "path_to_tpc_sect2");
00038 //    pne->SetPhysicalNode(pn)
00039 //
00040 // Such a symbolic link hides the complexity of the path to the align object and
00041 // replaces it with a more meaningful name. In addition, TGeoPNEntry objects are
00042 // faster to search by name and they may optionally store an additional user
00043 // matrix.
00044 //
00045 // For more details please read the misalignment section in the Users Guide.
00046 //_____________________________________________________________________________
00047 
00048 #include "TClass.h"
00049 #include "TGeoManager.h"
00050 #include "TGeoVoxelFinder.h"
00051 #include "TGeoCache.h"
00052 #include "TGeoMatrix.h"
00053 #include "TGeoShapeAssembly.h"
00054 #include "TGeoVolume.h"
00055 #include "TVirtualGeoPainter.h"
00056 
00057 #include "TGeoPhysicalNode.h"
00058 
00059 // statics and globals
00060 
00061 ClassImp(TGeoPhysicalNode)
00062 
00063 //_____________________________________________________________________________
00064 TGeoPhysicalNode::TGeoPhysicalNode() : TNamed()
00065 {
00066 // Default constructor
00067    fLevel        = 0;
00068    fMatrices     = 0;
00069    fNodes        = 0;
00070    fMatrixOrig   = 0;
00071    SetVisibility(kTRUE);
00072    SetVisibleFull(kFALSE);
00073    SetIsVolAtt(kTRUE);
00074    SetAligned(kFALSE);
00075 }
00076 
00077 //_____________________________________________________________________________
00078 TGeoPhysicalNode::TGeoPhysicalNode(const char *path) : TNamed(path,"")
00079 {
00080 // Constructor
00081    if (!strlen(path)) {
00082       Error("ctor", "path not valid");
00083       return;
00084    }
00085    fLevel  = 0;
00086    fMatrices = new TObjArray(30);
00087    fNodes    = new TObjArray(30);
00088    fMatrixOrig   = 0;
00089    SetPath(path);
00090    SetVisibility(kTRUE);
00091    SetVisibleFull(kFALSE);
00092    SetIsVolAtt(kTRUE);
00093    SetAligned(kFALSE);
00094 }
00095 
00096 //_____________________________________________________________________________
00097 TGeoPhysicalNode::TGeoPhysicalNode(const TGeoPhysicalNode& gpn) :
00098   TNamed(gpn),
00099   TAttLine(gpn),
00100   fLevel(gpn.fLevel),
00101   fMatrices(gpn.fMatrices),
00102   fNodes(gpn.fNodes),
00103   fMatrixOrig(gpn.fMatrixOrig)
00104 {
00105    //copy constructor
00106 }
00107 
00108 //_____________________________________________________________________________
00109 TGeoPhysicalNode& TGeoPhysicalNode::operator=(const TGeoPhysicalNode& gpn)
00110 {
00111    //assignment operator
00112    if(this!=&gpn) {
00113       TNamed::operator=(gpn);
00114       TAttLine::operator=(gpn);
00115       fLevel=gpn.fLevel;
00116       fMatrices=gpn.fMatrices;
00117       fNodes=gpn.fNodes;
00118       fMatrixOrig=gpn.fMatrixOrig;
00119    }
00120    return *this;
00121 }
00122 
00123 //_____________________________________________________________________________
00124 TGeoPhysicalNode::~TGeoPhysicalNode()
00125 {
00126 // Destructor
00127    if (fMatrices) {
00128       fMatrices->Delete();
00129       delete fMatrices;
00130    }
00131    if (fNodes) delete fNodes;
00132    if (fMatrixOrig) delete fMatrixOrig;
00133 }
00134 
00135 //_____________________________________________________________________________
00136 void TGeoPhysicalNode::Align(TGeoMatrix *newmat, TGeoShape *newshape, Bool_t check, Double_t ovlp)
00137 {
00138    // Align a physical node with a new relative matrix/shape.
00139    // Example: /TOP_1/A_1/B_1/C_1
00140    //    node->Align(transl_1, box) will perform:
00141    //    - change RELATIVE translation of C_1 node (with respect to its
00142    //      container volume B) to transl_1
00143    //    - change the shape of the C volume
00144    // *NOTE* The operations will affect ONLY the LAST node in the branch. All
00145    //   volumes/nodes in the branch represented by this physical node are
00146    //   CLONED so the operation does not affect other possible replicas.
00147    if (!newmat && !newshape) return;
00148    if (TGeoManager::IsLocked()) {
00149       Error("Align", "Not performed. Geometry in LOCKED mode !");
00150       return;
00151    }
00152    TGeoNode *node = GetNode();
00153    if (node->IsOffset()) {
00154       Error("Align", "Cannot align division nodes: %s\n",node->GetName());
00155       return;
00156    }
00157    TGeoNode *nnode = 0;
00158    TGeoVolume *vm = GetVolume(0);
00159    TGeoVolume *vd = 0;
00160    Int_t i;
00161    if (!IsAligned()) {
00162       Int_t *id = new Int_t[fLevel];
00163       for (i=0; i<fLevel; i++) {
00164          // Store daughter indexes
00165          vd = GetVolume(i);
00166          node = GetNode(i+1);
00167          id[i] = vd->GetIndex(node);
00168          if (id[i]<0) {
00169             Error("Align","%s cannot align node %s",GetName(), node->GetName());
00170             delete [] id;
00171             return;
00172          }
00173       }
00174       for (i=0; i<fLevel; i++) {
00175          // Get daughter node and its id inside vm
00176          node = GetNode(i+1);
00177          // Clone daughter volume and node
00178          vd = node->GetVolume()->CloneVolume();
00179          nnode = node->MakeCopyNode();
00180          // Correct pointers to mother and volume
00181          nnode->SetVolume(vd);
00182          nnode->SetMotherVolume(vm);
00183          // Decouple old node from mother volume and connect new one
00184          if (vm->TestBit(TGeoVolume::kVolumeImportNodes)) {
00185             gGeoManager->GetListOfGShapes()->Add(nnode);
00186          }   
00187          vm->GetNodes()->RemoveAt(id[i]);
00188          vm->GetNodes()->AddAt(nnode,id[i]);
00189          fNodes->RemoveAt(i+1);
00190          fNodes->AddAt(nnode,i+1);
00191          // Consider new cloned volume as mother and continue
00192          vm = vd;
00193       }
00194       delete [] id;
00195    } else {
00196       nnode = GetNode();
00197    }
00198    // Now nnode is a cloned node of the one that need to be aligned
00199    TGeoNodeMatrix *aligned = (TGeoNodeMatrix*)nnode;
00200    vm = nnode->GetMotherVolume();
00201    vd = nnode->GetVolume();
00202    if (newmat) {
00203       // Register matrix and make it the active one
00204       if (!newmat->IsRegistered()) newmat->RegisterYourself();
00205       aligned->SetMatrix(newmat);
00206       // Update the global matrix for the aligned node
00207       TGeoHMatrix *global = GetMatrix();
00208       TGeoHMatrix *up = GetMatrix(fLevel-1);
00209       *global = up;
00210       global->Multiply(newmat);
00211    }
00212    // Change the shape for the aligned node
00213    if (newshape) vd->SetShape(newshape);
00214 
00215    // Re-compute bounding box of mother(s) if needed
00216    for (i=fLevel-1; i>0; i--) {
00217       Bool_t dassm = vd->IsAssembly(); // is daughter assembly ?
00218       vd = GetVolume(i);
00219       Bool_t cassm = vd->IsAssembly(); // is current assembly ?
00220       if (cassm) ((TGeoShapeAssembly*)vd->GetShape())->NeedsBBoxRecompute();
00221       if ((cassm || dassm) && vd->GetVoxels()) vd->GetVoxels()->SetNeedRebuild();
00222       if (!cassm) break;
00223    }
00224 
00225    // Now we have to re-voxelize the mother volume
00226    TGeoVoxelFinder *voxels = vm->GetVoxels();
00227    if (voxels) voxels->SetNeedRebuild();
00228    // Eventually check for overlaps
00229    if (check) {
00230       if (voxels) {
00231          voxels->Voxelize();
00232          vm->FindOverlaps();
00233       }
00234       // Set aligned node to be checked
00235       i = fLevel;
00236       node = GetNode(i);
00237       if (node->IsOverlapping()) {
00238          Info("Align", "The check for overlaps for node: \n%s\n cannot be performed since the node is declared possibly overlapping",
00239               GetName());
00240       } else {
00241          gGeoManager->SetCheckedNode(node);
00242          // Check overlaps for the first non-assembly parent node
00243          while ((node=GetNode(--i))) {
00244             if (!node->GetVolume()->IsAssembly()) break;
00245          }
00246          if (node && node->IsOverlapping()) {
00247             Info("Align", "The check for overlaps for assembly node: \n%s\n cannot be performed since the parent %s is declared possibly overlapping",
00248                  GetName(), node->GetName());
00249             node = 0;
00250          }
00251          if (node) node->CheckOverlaps(ovlp);
00252          gGeoManager->SetCheckedNode(0);
00253       }
00254    }
00255    // Clean current matrices from cache
00256    gGeoManager->CdTop();
00257    SetAligned(kTRUE);
00258 }
00259 
00260 //_____________________________________________________________________________
00261 void TGeoPhysicalNode::cd() const
00262 {
00263    gGeoManager->cd(fName.Data());
00264 }
00265 
00266 //_____________________________________________________________________________
00267 void TGeoPhysicalNode::Draw(Option_t * /*option*/)
00268 {
00269 // Draw this node.
00270 }
00271 
00272 //_____________________________________________________________________________
00273 TGeoNode *TGeoPhysicalNode::GetMother(Int_t levup) const
00274 {
00275 // Return parent at LEVUP generation
00276    Int_t ind = fLevel-levup;
00277    if (ind<0) return 0;
00278    return (TGeoNode*)fNodes->UncheckedAt(ind);
00279 }
00280 
00281 //_____________________________________________________________________________
00282 TGeoHMatrix *TGeoPhysicalNode::GetMatrix(Int_t level) const
00283 {
00284 // Return global matrix for node at LEVEL.
00285    if (level<0) return (TGeoHMatrix*)fMatrices->UncheckedAt(fLevel);
00286    if (level>fLevel) return 0;
00287    return (TGeoHMatrix*)fMatrices->UncheckedAt(level);
00288 }
00289 
00290 //_____________________________________________________________________________
00291 TGeoNode *TGeoPhysicalNode::GetNode(Int_t level) const
00292 {
00293 // Return node in branch at LEVEL. If not specified, return last leaf.
00294    if (level<0) return (TGeoNode*)fNodes->UncheckedAt(fLevel);
00295    if (level>fLevel) return 0;
00296    return (TGeoNode*)fNodes->UncheckedAt(level);
00297 }
00298 
00299 //_____________________________________________________________________________
00300 TGeoVolume *TGeoPhysicalNode::GetVolume(Int_t level) const
00301 {
00302 // Return volume associated with node at LEVEL in the branch
00303    TGeoNode *node = GetNode(level);
00304    if (node) return node->GetVolume();
00305    return 0;
00306 }
00307 
00308 //_____________________________________________________________________________
00309 TGeoShape *TGeoPhysicalNode::GetShape(Int_t level) const
00310 {
00311 // Return shape associated with volume.
00312    TGeoVolume *vol = GetVolume(level);
00313    if (vol) return vol->GetShape();
00314    return 0;
00315 }
00316 
00317 //_____________________________________________________________________________
00318 void TGeoPhysicalNode::Paint(Option_t * /*option*/)
00319 {
00320 // Paint this node and its content according to visualization settings.
00321    TVirtualGeoPainter *painter = gGeoManager->GetGeomPainter();
00322    if (!painter) return;
00323 //   painter->PaintNode(this, option);
00324 }
00325 
00326 //_____________________________________________________________________________
00327 void TGeoPhysicalNode::Print(Option_t * /*option*/) const
00328 {
00329 // Print info about this node.
00330    printf("TGeoPhysicalNode: %s level=%d aligned=%d\n", fName.Data(), fLevel, IsAligned());
00331    for (Int_t i=0; i<=fLevel; i++) {
00332       printf(" level %d: node %s\n", i, GetNode(i)->GetName());
00333       printf(" local matrix:\n");
00334       if (GetNode(i)->GetMatrix()->IsIdentity()) printf("   IDENTITY\n");
00335       else GetNode(i)->GetMatrix()->Print();
00336       printf(" global matrix:\n");
00337       if (GetMatrix(i)->IsIdentity()) printf("   IDENTITY\n");
00338       else GetMatrix(i)->Print();
00339    }
00340    if (IsAligned() && fMatrixOrig) {
00341       printf(" original local matrix:\n");
00342       fMatrixOrig->Print();
00343    }
00344 }
00345 
00346 //_____________________________________________________________________________
00347 void TGeoPhysicalNode::Refresh()
00348 {
00349 // Refresh this physical node. Called for all registered physical nodes
00350 // after an Align() call.
00351    SetPath(fName.Data());
00352 }
00353 
00354 //_____________________________________________________________________________
00355 void TGeoPhysicalNode::SetBranchAsState()
00356 {
00357 // Set node branch according to current state
00358    TGeoNodeCache *cache = gGeoManager->GetCache();
00359    if (!cache) {
00360       Error("SetBranchAsState","no state available");
00361       return;
00362    }
00363    if (!cache->IsDummy()) {
00364       Error("SetBranchAsState", "not implemented for full cache");
00365       return;
00366    }
00367    if (!fNodes)    fNodes = new TObjArray(30);
00368    if (!fMatrices) fMatrices = new TObjArray(30);
00369    TGeoHMatrix **matrices = (TGeoHMatrix **) cache->GetMatrices();
00370    TGeoNode **branch = (TGeoNode **) cache->GetBranch();
00371 
00372    Bool_t refresh = (fLevel>0)?kTRUE:kFALSE;
00373    if (refresh) {
00374       TGeoHMatrix *current;
00375       for (Int_t i=0; i<=fLevel; i++) {
00376          fNodes->AddAtAndExpand(branch[i],i);
00377          current = (TGeoHMatrix*)fMatrices->UncheckedAt(i);
00378          *current = *matrices[i];
00379       }
00380       return;
00381    }
00382    fLevel = gGeoManager->GetLevel();
00383    for (Int_t i=0; i<=fLevel; i++) {
00384       fNodes->AddAtAndExpand(branch[i],i);
00385       fMatrices->AddAtAndExpand(new TGeoHMatrix(*matrices[i]),i);
00386    }
00387    TGeoNode *node = (TGeoNode*)fNodes->UncheckedAt(fLevel);
00388    if (!fMatrixOrig) fMatrixOrig = new TGeoHMatrix();
00389    *fMatrixOrig = node->GetMatrix();
00390 }
00391 
00392 //_____________________________________________________________________________
00393 void TGeoPhysicalNode::SetMatrixOrig(const TGeoMatrix *local)
00394 {
00395 // Allows PN entries (or users) to preset the local original matrix for the
00396 // last node pointed by the path.
00397    if (!fMatrixOrig) fMatrixOrig = new TGeoHMatrix();
00398    if (!local) fMatrixOrig->Clear();
00399    *fMatrixOrig = local;
00400 }
00401 
00402 //_____________________________________________________________________________
00403 Bool_t TGeoPhysicalNode::SetPath(const char *path)
00404 {
00405 // Specify the path for this node.
00406    if (!gGeoManager->cd(path)) {
00407       Error("SetPath","wrong path -> maybe RestoreMasterVolume");
00408       return kFALSE;
00409    }
00410    SetBranchAsState();
00411    return kTRUE;
00412 }
00413 
00414 ClassImp(TGeoPNEntry)
00415 
00416 //_____________________________________________________________________________
00417 TGeoPNEntry::TGeoPNEntry()
00418 {
00419 // Default constructor
00420    fNode = 0;
00421    fMatrix = 0;
00422    fGlobalOrig = 0;
00423 }
00424 
00425 //_____________________________________________________________________________
00426 TGeoPNEntry::TGeoPNEntry(const char *name, const char *path)
00427             :TNamed(name, path)
00428 {
00429 // Default constructor
00430    if (!gGeoManager || !gGeoManager->IsClosed() || !gGeoManager->CheckPath(path)) {
00431       TString errmsg("Cannot define a physical node link without a closed geometry and a valid path !");
00432       Error("ctor", "%s", errmsg.Data());
00433       throw errmsg;
00434       return;
00435    }
00436    gGeoManager->PushPath();
00437    gGeoManager->cd(path);
00438    fGlobalOrig = new TGeoHMatrix();
00439    *fGlobalOrig = gGeoManager->GetCurrentMatrix();
00440    gGeoManager->PopPath();
00441    fNode = 0;
00442    fMatrix = 0;
00443 }
00444 
00445 //_____________________________________________________________________________
00446 TGeoPNEntry::~TGeoPNEntry()
00447 {
00448 // Destructor
00449    if (fMatrix && !fMatrix->IsRegistered()) delete fMatrix;
00450    delete fGlobalOrig;
00451 }
00452 
00453 //_____________________________________________________________________________
00454 void TGeoPNEntry::SetPhysicalNode(TGeoPhysicalNode *node)
00455 {
00456 // Setter for the corresponding physical node.
00457    if (fNode && node) {
00458       Warning("SetPhysicalNode", "Physical node changed for entry %s", GetName());
00459       Warning("SetPhysicalNode", "=== New path: %s", node->GetName());
00460    }
00461    fNode = node;
00462 }
00463 
00464 //_____________________________________________________________________________
00465 void TGeoPNEntry::SetMatrix(const TGeoHMatrix *mat)
00466 {
00467 // Set the additional matrix for this node entry. The matrix will be deleted
00468 // by this class unless registered by the user to gGeoManager
00469    fMatrix = mat;
00470 }

Generated on Tue Jul 5 14:12:57 2011 for ROOT_528-00b_version by  doxygen 1.5.1