Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TGeoPhysicalNode.cxx
Go to the documentation of this file.
1 // @(#)root/geom:$Id$
2 // Author: Andrei Gheata 17/02/04
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 /** \class TGeoPhysicalNode
13 \ingroup Geometry_classes
14 
15 Physical nodes are the actual 'touchable' objects in the geometry, representing
16 a path of positioned volumes starting with the top node:
17  path=/TOP/A_1/B_4/C_3 , where A, B, C represent names of volumes.
18 
19 The number of physical nodes is given by the total number of possible of
20 branches in the geometry hierarchy. In case of detector geometries and
21 specially for calorimeters this number can be of the order 1e6-1e9, therefore
22 it is impossible to create all physical nodes as objects in memory. In TGeo,
23 physical nodes are represented by the class TGeoPhysicalNode and can be created
24 on demand for alignment purposes:
25 
26 ~~~ {.cpp}
27  TGeoPhysicalNode *pn = new TGeoPhysicalNode("path_to_object")
28 ~~~
29 
30 Once created, a physical node can be misaligned, meaning that its position
31 or even shape can be changed:
32 
33 ~~~ {.cpp}
34  pn->Align(TGeoMatrix* newmat, TGeoShape* newshape, Bool_t check=kFALSE)
35 ~~~
36 */
37 
38 /** \class TGeoPNEntry
39 \ingroup Geometry_classes
40 
41 The knowledge of the path to the objects that need to be misaligned is
42 essential since there is no other way of identifying them. One can however
43 create 'symbolic links' to any complex path to make it more representable
44 for the object it designates:
45 
46 ~~~ {.cpp}
47  TGeoPNEntry *pne = new TGeoPNEntry("TPC_SECTOR_2", "path_to_tpc_sect2");
48  pne->SetPhysicalNode(pn)
49 ~~~
50 
51 Such a symbolic link hides the complexity of the path to the align object and
52 replaces it with a more meaningful name. In addition, TGeoPNEntry objects are
53 faster to search by name and they may optionally store an additional user
54 matrix.
55 
56 For more details please read the misalignment section in the Users Guide.
57 */
58 
59 #include "TClass.h"
60 #include "TGeoManager.h"
61 #include "TGeoVoxelFinder.h"
62 #include "TGeoCache.h"
63 #include "TGeoMatrix.h"
64 #include "TGeoShapeAssembly.h"
65 #include "TGeoCompositeShape.h"
66 #include "TGeoBoolNode.h"
67 #include "TGeoVolume.h"
68 #include "TVirtualGeoPainter.h"
69 
70 #include "TGeoPhysicalNode.h"
71 
72 // statics and globals
73 
74 ClassImp(TGeoPhysicalNode);
75 
76 ////////////////////////////////////////////////////////////////////////////////
77 /// Default constructor
78 
79 TGeoPhysicalNode::TGeoPhysicalNode() : TNamed()
80 {
81  fLevel = 0;
82  fMatrices = 0;
83  fNodes = 0;
84  fMatrixOrig = 0;
85  SetVisibility(kTRUE);
86  SetVisibleFull(kFALSE);
87  SetIsVolAtt(kTRUE);
88  SetAligned(kFALSE);
89 }
90 
91 ////////////////////////////////////////////////////////////////////////////////
92 /// Constructor
93 
94 TGeoPhysicalNode::TGeoPhysicalNode(const char *path) : TNamed(path,"")
95 {
96  if (!path[0]) {
97  Error("ctor", "path not valid");
98  return;
99  }
100  fLevel = 0;
101  fMatrices = new TObjArray(30);
102  fNodes = new TObjArray(30);
103  fMatrixOrig = 0;
104  SetPath(path);
105  SetVisibility(kTRUE);
106  SetVisibleFull(kFALSE);
107  SetIsVolAtt(kTRUE);
108  SetAligned(kFALSE);
109 }
110 
111 ////////////////////////////////////////////////////////////////////////////////
112 ///copy constructor
113 
114 TGeoPhysicalNode::TGeoPhysicalNode(const TGeoPhysicalNode& gpn) :
115  TNamed(gpn),
116  TAttLine(gpn),
117  fLevel(gpn.fLevel),
118  fMatrices(gpn.fMatrices),
119  fNodes(gpn.fNodes),
120  fMatrixOrig(gpn.fMatrixOrig)
121 {
122 }
123 
124 ////////////////////////////////////////////////////////////////////////////////
125 ///assignment operator
126 
127 TGeoPhysicalNode& TGeoPhysicalNode::operator=(const TGeoPhysicalNode& gpn)
128 {
129  if(this!=&gpn) {
130  TNamed::operator=(gpn);
131  TAttLine::operator=(gpn);
132  fLevel=gpn.fLevel;
133  fMatrices=gpn.fMatrices;
134  fNodes=gpn.fNodes;
135  fMatrixOrig=gpn.fMatrixOrig;
136  }
137  return *this;
138 }
139 
140 ////////////////////////////////////////////////////////////////////////////////
141 /// Destructor
142 
143 TGeoPhysicalNode::~TGeoPhysicalNode()
144 {
145  if (fMatrices) {
146  fMatrices->Delete();
147  delete fMatrices;
148  }
149  if (fNodes) delete fNodes;
150  if (fMatrixOrig) delete fMatrixOrig;
151 }
152 
153 ////////////////////////////////////////////////////////////////////////////////
154 /// Align a physical node with a new relative matrix/shape.
155 /// Example: /TOP_1/A_1/B_1/C_1
156 /// node->Align(transl_1, box) will perform:
157 /// - change RELATIVE translation of C_1 node (with respect to its
158 /// container volume B) to transl_1
159 /// - change the shape of the C volume
160 /// *NOTE* The operations will affect ONLY the LAST node in the branch. All
161 /// volumes/nodes in the branch represented by this physical node are
162 /// CLONED so the operation does not affect other possible replicas.
163 
164 Bool_t TGeoPhysicalNode::Align(TGeoMatrix *newmat, TGeoShape *newshape, Bool_t check, Double_t ovlp)
165 {
166  if (!newmat && !newshape) return kFALSE;
167  if (TGeoManager::IsLocked()) {
168  Error("Align", "Not performed. Geometry in LOCKED mode !");
169  return kFALSE;
170  }
171  if (newmat == gGeoIdentity) {
172  Error("Align", "Cannot align using gGeoIdentity. Use some default matrix constructor to represent identities.");
173  return kFALSE;
174  }
175  TGeoNode *node = GetNode();
176  if (node->IsOffset()) {
177  Error("Align", "Cannot align division nodes: %s\n",node->GetName());
178  return kFALSE;
179  }
180  // Refresh the node since other Align calls may have altered the stored nodes
181  Refresh();
182  TGeoNode *nnode = 0;
183  TGeoVolume *vm = GetVolume(0);
184  TGeoVolume *vd = 0;
185  Int_t i;
186  if (!IsAligned()) {
187  Int_t *id = new Int_t[fLevel];
188  for (i=0; i<fLevel; i++) {
189  // Store daughter indexes
190  vd = GetVolume(i);
191  node = GetNode(i+1);
192  id[i] = vd->GetIndex(node);
193  if (id[i]<0) {
194  Error("Align","%s cannot align node %s",GetName(), node->GetName());
195  delete [] id;
196  return kFALSE;
197  }
198  }
199  for (i=0; i<fLevel; i++) {
200  // Get daughter node and its id inside vm
201  node = GetNode(i+1);
202  // Clone daughter volume and node if not done yet
203  if (node->IsCloned()) {
204  vd = node->GetVolume();
205  nnode = node;
206  } else {
207  vd = node->GetVolume()->CloneVolume();
208  if (!vd) {
209  delete [] id;
210  Fatal("Align", "Cannot clone volume %s", node->GetVolume()->GetName());
211  return kFALSE;
212  }
213  nnode = node->MakeCopyNode();
214  if (!nnode) {
215  delete [] id;
216  Fatal("Align", "Cannot make copy node for %s", node->GetName());
217  return kFALSE;
218  }
219  // Correct pointers to mother and volume
220  nnode->SetVolume(vd);
221  nnode->SetMotherVolume(vm);
222  // Decouple old node from mother volume and connect new one
223  if (vm->TestBit(TGeoVolume::kVolumeImportNodes)) {
224  gGeoManager->GetListOfGShapes()->Add(nnode);
225  }
226  vm->GetNodes()->RemoveAt(id[i]);
227  vm->GetNodes()->AddAt(nnode,id[i]);
228  fNodes->RemoveAt(i+1);
229  fNodes->AddAt(nnode,i+1);
230  // node->GetVolume()->Release();
231  }
232  // Consider new cloned volume as mother and continue
233  vm = vd;
234  }
235  delete [] id;
236  } else {
237  nnode = GetNode();
238  }
239  // Now nnode is a cloned node of the one that need to be aligned
240  TGeoNodeMatrix *aligned = (TGeoNodeMatrix*)nnode;
241  vm = nnode->GetMotherVolume();
242  vd = nnode->GetVolume();
243  if (newmat) {
244  // Check if the old matrix for this node was shared
245  Bool_t shared = kFALSE;
246  Int_t nd = vm->GetNdaughters();
247  TGeoCompositeShape *cs;
248  if (nnode->GetMatrix()->IsShared()) {
249  // Now find the node having a composite shape using this shared matrix
250  for (i=0; i<nd; i++) {
251  node = vm->GetNode(i);
252  if (node==nnode) continue;
253  if (node->IsOffset()) continue;
254  if (!node->GetVolume()->GetShape()->IsComposite()) continue;
255  // We found a node having a composite shape, scan for the shared matrix
256  cs = (TGeoCompositeShape*)node->GetVolume()->GetShape();
257  if (cs->GetBoolNode()->GetRightMatrix() != nnode->GetMatrix()) continue;
258  // The composite uses the matrix -> replace it
259  TGeoCompositeShape *ncs = new TGeoCompositeShape(cs->GetName(), cs->GetBoolNode()->MakeClone());
260  ncs->GetBoolNode()->ReplaceMatrix(nnode->GetMatrix(), newmat);
261  // We have to clone the node/volume having the composite shape
262  TGeoVolume *newvol = node->GetVolume()->CloneVolume();
263  if (!newvol) {
264  Error("Align", "Cannot clone volume %s", node->GetVolume()->GetName());
265  return kFALSE;
266  }
267  newvol->SetShape(ncs);
268  TGeoNode *newnode = node->MakeCopyNode();
269  if (!newnode) {
270  Error("Align", "Cannot clone node %s", node->GetName());
271  return kFALSE;
272  }
273  newnode->SetVolume(newvol);
274  newnode->SetMotherVolume(vm);
275  if (vm->TestBit(TGeoVolume::kVolumeImportNodes)) {
276  gGeoManager->GetListOfGShapes()->Add(newnode);
277  }
278  vm->GetNodes()->RemoveAt(i);
279  vm->GetNodes()->AddAt(newnode,i);
280  shared = kTRUE;
281  }
282  if (!shared) Error("Align", "The matrix replaced for %s is not actually shared", GetName());
283  } else {
284  // The aligned node may have a composite shape containing a shared matrix
285  if (vd->GetShape()->IsComposite()) {
286  cs = (TGeoCompositeShape*)vd->GetShape();
287  if (cs->GetBoolNode()->GetRightMatrix()->IsShared()) {
288  if (!nnode->GetMatrix()->IsIdentity()) {
289  Error("Align", "The composite shape having a shared matrix on the subtracted branch must be positioned using identity matrix.");
290  return kFALSE;
291  }
292  // We have to put the alignment matrix on top of the left branch
293  // of the composite shape. The node is already decoupled from logical tree.
294  TGeoCompositeShape *ncs = new TGeoCompositeShape(cs->GetName(), cs->GetBoolNode()->MakeClone());
295  TGeoMatrix *oldmat = ncs->GetBoolNode()->GetLeftMatrix();
296  TGeoHMatrix *newmat1 = new TGeoHMatrix(*newmat);
297  newmat1->Multiply(oldmat);
298  ncs->GetBoolNode()->ReplaceMatrix(oldmat, newmat1);
299  vd->SetShape(ncs);
300  // The right-side matrix pointer is preserved, so no need to update nodes.
301  aligned = 0; // to prevent updating its matrix
302  }
303  }
304  }
305  // Register matrix and make it the active one
306  if (!newmat->IsRegistered()) newmat->RegisterYourself();
307  if (aligned) {
308  aligned->SetMatrix(newmat);
309  // Update the global matrix for the aligned node
310  TGeoHMatrix *global = GetMatrix();
311  TGeoHMatrix *up = GetMatrix(fLevel-1);
312  *global = up;
313  global->Multiply(newmat);
314  }
315  }
316  // Change the shape for the aligned node
317  if (newshape) vd->SetShape(newshape);
318 
319  // Re-compute bounding box of mother(s) if needed
320  for (i=fLevel-1; i>0; i--) {
321  Bool_t dassm = vd->IsAssembly(); // is daughter assembly ?
322  vd = GetVolume(i);
323  if (!vd) break;
324  Bool_t cassm = vd->IsAssembly(); // is current assembly ?
325  if (cassm) ((TGeoShapeAssembly*)vd->GetShape())->NeedsBBoxRecompute();
326  if ((cassm || dassm) && vd->GetVoxels()) vd->GetVoxels()->SetNeedRebuild();
327  if (!cassm) break;
328  }
329 
330  // Now we have to re-voxelize the mother volume
331  TGeoVoxelFinder *voxels = vm->GetVoxels();
332  if (voxels) voxels->SetNeedRebuild();
333  // Eventually check for overlaps
334  if (check) {
335  if (voxels) {
336  voxels->Voxelize();
337  vm->FindOverlaps();
338  }
339  // Set aligned node to be checked
340  i = fLevel;
341  node = GetNode(i);
342  if (!node) return kTRUE;
343  if (node->IsOverlapping()) {
344  Info("Align", "The check for overlaps for node: \n%s\n cannot be performed since the node is declared possibly overlapping",
345  GetName());
346  } else {
347  gGeoManager->SetCheckedNode(node);
348  // Check overlaps for the first non-assembly parent node
349  while ((node=GetNode(--i))) {
350  if (!node->GetVolume()->IsAssembly()) break;
351  }
352  if (node && node->IsOverlapping()) {
353  Info("Align", "The check for overlaps for assembly node: \n%s\n cannot be performed since the parent %s is declared possibly overlapping",
354  GetName(), node->GetName());
355  node = 0;
356  }
357  if (node) node->CheckOverlaps(ovlp);
358  gGeoManager->SetCheckedNode(0);
359  }
360  }
361  // Clean current matrices from cache
362  gGeoManager->CdTop();
363  SetAligned(kTRUE);
364  return kTRUE;
365 }
366 
367 ////////////////////////////////////////////////////////////////////////////////
368 
369 void TGeoPhysicalNode::cd() const
370 {
371  if (GetNode(0) != gGeoManager->GetTopNode()) return;
372  gGeoManager->cd(fName.Data());
373 }
374 
375 ////////////////////////////////////////////////////////////////////////////////
376 /// Draw this node.
377 
378 void TGeoPhysicalNode::Draw(Option_t * /*option*/)
379 {
380 }
381 
382 ////////////////////////////////////////////////////////////////////////////////
383 /// Return parent at LEVUP generation
384 
385 TGeoNode *TGeoPhysicalNode::GetMother(Int_t levup) const
386 {
387  Int_t ind = fLevel-levup;
388  if (ind<0) return 0;
389  return (TGeoNode*)fNodes->UncheckedAt(ind);
390 }
391 
392 ////////////////////////////////////////////////////////////////////////////////
393 /// Return global matrix for node at LEVEL.
394 
395 TGeoHMatrix *TGeoPhysicalNode::GetMatrix(Int_t level) const
396 {
397  if (level<0) return (TGeoHMatrix*)fMatrices->UncheckedAt(fLevel);
398  if (level>fLevel) return 0;
399  return (TGeoHMatrix*)fMatrices->UncheckedAt(level);
400 }
401 
402 ////////////////////////////////////////////////////////////////////////////////
403 /// Return node in branch at LEVEL. If not specified, return last leaf.
404 
405 TGeoNode *TGeoPhysicalNode::GetNode(Int_t level) const
406 {
407  if (level<0) return (TGeoNode*)fNodes->UncheckedAt(fLevel);
408  if (level>fLevel) return 0;
409  return (TGeoNode*)fNodes->UncheckedAt(level);
410 }
411 
412 ////////////////////////////////////////////////////////////////////////////////
413 /// Return volume associated with node at LEVEL in the branch
414 
415 TGeoVolume *TGeoPhysicalNode::GetVolume(Int_t level) const
416 {
417  TGeoNode *node = GetNode(level);
418  if (node) return node->GetVolume();
419  return 0;
420 }
421 
422 ////////////////////////////////////////////////////////////////////////////////
423 /// Return shape associated with volume.
424 
425 TGeoShape *TGeoPhysicalNode::GetShape(Int_t level) const
426 {
427  TGeoVolume *vol = GetVolume(level);
428  if (vol) return vol->GetShape();
429  return 0;
430 }
431 
432 ////////////////////////////////////////////////////////////////////////////////
433 /// Paint this node and its content according to visualization settings.
434 
435 void TGeoPhysicalNode::Paint(Option_t * /*option*/)
436 {
437  TVirtualGeoPainter *painter = gGeoManager->GetGeomPainter();
438  if (!painter) return;
439 // painter->PaintNode(this, option);
440 }
441 
442 ////////////////////////////////////////////////////////////////////////////////
443 /// Print info about this node.
444 
445 void TGeoPhysicalNode::Print(Option_t * /*option*/) const
446 {
447  printf("TGeoPhysicalNode: %s level=%d aligned=%d\n", fName.Data(), fLevel, IsAligned());
448  for (Int_t i=0; i<=fLevel; i++) {
449  printf(" level %d: node %s\n", i, GetNode(i)->GetName());
450  printf(" local matrix:\n");
451  if (GetNode(i)->GetMatrix()->IsIdentity()) printf(" IDENTITY\n");
452  else GetNode(i)->GetMatrix()->Print();
453  printf(" global matrix:\n");
454  if (GetMatrix(i)->IsIdentity()) printf(" IDENTITY\n");
455  else GetMatrix(i)->Print();
456  }
457  if (IsAligned() && fMatrixOrig) {
458  printf(" original local matrix:\n");
459  fMatrixOrig->Print();
460  }
461 }
462 
463 ////////////////////////////////////////////////////////////////////////////////
464 /// Refresh this physical node. Called for all registered physical nodes
465 /// after an Align() call.
466 
467 void TGeoPhysicalNode::Refresh()
468 {
469  SetPath(fName.Data());
470 }
471 
472 ////////////////////////////////////////////////////////////////////////////////
473 /// Set node branch according to current state
474 
475 void TGeoPhysicalNode::SetBranchAsState()
476 {
477  TGeoNodeCache *cache = gGeoManager->GetCache();
478  if (!cache) {
479  Error("SetBranchAsState","no state available");
480  return;
481  }
482  if (!cache->IsDummy()) {
483  Error("SetBranchAsState", "not implemented for full cache");
484  return;
485  }
486  if (!fNodes) fNodes = new TObjArray(30);
487  if (!fMatrices) fMatrices = new TObjArray(30);
488  TGeoHMatrix **matrices = (TGeoHMatrix **) cache->GetMatrices();
489  TGeoNode **branch = (TGeoNode **) cache->GetBranch();
490 
491  Bool_t refresh = (fLevel>0)?kTRUE:kFALSE;
492  if (refresh) {
493  TGeoHMatrix *current;
494  for (Int_t i=0; i<=fLevel; i++) {
495  fNodes->AddAtAndExpand(branch[i],i);
496  current = (TGeoHMatrix*)fMatrices->UncheckedAt(i);
497  *current = *matrices[i];
498  }
499  return;
500  }
501  fLevel = gGeoManager->GetLevel();
502  for (Int_t i=0; i<=fLevel; i++) {
503  fNodes->AddAtAndExpand(branch[i],i);
504  fMatrices->AddAtAndExpand(new TGeoHMatrix(*matrices[i]),i);
505  }
506  TGeoNode *node = (TGeoNode*)fNodes->UncheckedAt(fLevel);
507  if (!fMatrixOrig) fMatrixOrig = new TGeoHMatrix();
508  *fMatrixOrig = node->GetMatrix();
509 }
510 
511 ////////////////////////////////////////////////////////////////////////////////
512 /// Allows PN entries (or users) to preset the local original matrix for the
513 /// last node pointed by the path.
514 
515 void TGeoPhysicalNode::SetMatrixOrig(const TGeoMatrix *local)
516 {
517  if (!fMatrixOrig) fMatrixOrig = new TGeoHMatrix();
518  if (!local) {
519  fMatrixOrig->Clear();
520  return;
521  }
522  *fMatrixOrig = local;
523 }
524 
525 ////////////////////////////////////////////////////////////////////////////////
526 /// Specify the path for this node.
527 
528 Bool_t TGeoPhysicalNode::SetPath(const char *path)
529 {
530  if (!gGeoManager->cd(path)) {
531  Error("SetPath","wrong path -> maybe RestoreMasterVolume");
532  return kFALSE;
533  }
534  SetBranchAsState();
535  return kTRUE;
536 }
537 
538 ////////////////////////////////////////////////////////////////////////////////
539 /// Checks if a given navigator state matches this physical node
540 
541 Bool_t TGeoPhysicalNode::IsMatchingState(TGeoNavigator *nav) const
542 {
543  TGeoNodeCache *cache = nav->GetCache();
544  if (!cache) {
545  Fatal("SetBranchAsState","no state available");
546  return kFALSE;
547  }
548  TGeoNode **branch = (TGeoNode **) cache->GetBranch();
549  for (Int_t i=1; i<=fLevel; i++)
550  if (fNodes->At(i) != branch[i]) return kFALSE;
551  return kTRUE;
552 }
553 
554 ClassImp(TGeoPNEntry);
555 
556 ////////////////////////////////////////////////////////////////////////////////
557 /// Default constructor
558 
559 TGeoPNEntry::TGeoPNEntry()
560 {
561  fNode = 0;
562  fMatrix = 0;
563  fGlobalOrig = 0;
564 }
565 
566 ////////////////////////////////////////////////////////////////////////////////
567 /// Default constructor
568 
569 TGeoPNEntry::TGeoPNEntry(const char *name, const char *path)
570  :TNamed(name, path)
571 {
572  if (!gGeoManager || !gGeoManager->IsClosed() || !gGeoManager->CheckPath(path)) {
573  TString errmsg("Cannot define a physical node link without a closed geometry and a valid path !");
574  Error("ctor", "%s", errmsg.Data());
575  throw errmsg;
576  return;
577  }
578  gGeoManager->PushPath();
579  gGeoManager->cd(path);
580  fGlobalOrig = new TGeoHMatrix();
581  *fGlobalOrig = gGeoManager->GetCurrentMatrix();
582  gGeoManager->PopPath();
583  fNode = 0;
584  fMatrix = 0;
585 }
586 
587 ////////////////////////////////////////////////////////////////////////////////
588 /// Destructor
589 
590 TGeoPNEntry::~TGeoPNEntry()
591 {
592  if (fMatrix && !fMatrix->IsRegistered()) delete fMatrix;
593  delete fGlobalOrig;
594 }
595 
596 ////////////////////////////////////////////////////////////////////////////////
597 /// Setter for the corresponding physical node.
598 
599 void TGeoPNEntry::SetPhysicalNode(TGeoPhysicalNode *node)
600 {
601  if (fNode && node) {
602  Warning("SetPhysicalNode", "Physical node changed for entry %s", GetName());
603  Warning("SetPhysicalNode", "=== New path: %s", node->GetName());
604  }
605  fNode = node;
606 }
607 
608 ////////////////////////////////////////////////////////////////////////////////
609 /// Set the additional matrix for this node entry. The matrix will be deleted
610 /// by this class unless registered by the user to gGeoManager
611 
612 void TGeoPNEntry::SetMatrix(const TGeoHMatrix *mat)
613 {
614  fMatrix = mat;
615 }