Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TGeoNavigator.cxx
Go to the documentation of this file.
1// @(#)root/geom:$Id$
2// Author: Mihaela Gheata 30/05/07
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 TGeoNavigator
13\ingroup Geometry_classes
14
15 Class providing navigation API for TGeo geometries. Several instances are
16allowed for a single geometry.
17A default navigator is provided for any geometry but one may add several
18others for parallel navigation:
19
20~~~ {.cpp}
21TGeoNavigator *navig = new TGeoNavigator(gGeoManager);
22Int_t inav = gGeoManager->AddNavigator(navig);
23gGeoManager->SetCurrentNavigator(inav);
24~~~
25
26.... and then switch back to the default navigator:
27
28~~~ {.cpp}
29gGeoManager->SetCurrentNavigator(0);
30~~~
31
32*/
33
34#include "TGeoNavigator.h"
35
36#include "TGeoManager.h"
37#include "TGeoMatrix.h"
38#include "TGeoNode.h"
39#include "TGeoVolume.h"
40#include "TGeoPatternFinder.h"
41#include "TGeoVoxelFinder.h"
42#include "TMath.h"
43#include "TGeoParallelWorld.h"
44#include "TGeoPhysicalNode.h"
45
47const char *kGeoOutsidePath = " ";
48const Int_t kN3 = 3 * sizeof(Double_t);
49
51
52
53////////////////////////////////////////////////////////////////////////////////
54/// Constructor
55
57 : fStep(0.),
58 fSafety(0.),
59 fLastSafety(0.),
60 fLastPWSafety(-1.),
61 fThreadId(0),
62 fLevel(0),
63 fNmany(0),
64 fNextDaughterIndex(0),
65 fOverlapSize(0),
66 fOverlapMark(0),
67 fOverlapClusters(nullptr),
68 fSearchOverlaps(kFALSE),
69 fCurrentOverlapping(kFALSE),
70 fStartSafe(kFALSE),
71 fIsEntering(kFALSE),
72 fIsExiting(kFALSE),
73 fIsStepEntering(kFALSE),
74 fIsStepExiting(kFALSE),
75 fIsOutside(kFALSE),
76 fIsOnBoundary(kFALSE),
77 fIsSameLocation(kFALSE),
78 fIsNullStep(kFALSE),
79 fGeometry(nullptr),
80 fCache(nullptr),
81 fCurrentVolume(nullptr),
82 fCurrentNode(nullptr),
83 fTopNode(nullptr),
84 fLastNode(nullptr),
85 fNextNode(nullptr),
86 fForcedNode(nullptr),
87 fBackupState(nullptr),
88 fCurrentMatrix(nullptr),
89 fGlobalMatrix(nullptr),
90 fDivMatrix(nullptr),
91 fPath()
92
93{
94 // dummy constructor
95 for (Int_t i = 0; i < 3; i++) {
96 fNormal[i] = 0.;
97 fCldir[i] = 0.;
98 fCldirChecked[i] = 0.;
99 fPoint[i] = 0.;
100 fDirection[i] = 0.;
101 fLastPoint[i] = 0.;
102 }
103}
104
105////////////////////////////////////////////////////////////////////////////////
106/// Constructor
107
109 : fStep(0.),
110 fSafety(0.),
111 fLastSafety(0.),
112 fLastPWSafety(-1.),
113 fThreadId(0),
114 fLevel(0),
115 fNmany(0),
116 fNextDaughterIndex(-2),
117 fOverlapSize(1000),
118 fOverlapMark(0),
119 fOverlapClusters(nullptr),
120 fSearchOverlaps(kFALSE),
121 fCurrentOverlapping(kFALSE),
122 fStartSafe(kTRUE),
123 fIsEntering(kFALSE),
124 fIsExiting(kFALSE),
125 fIsStepEntering(kFALSE),
126 fIsStepExiting(kFALSE),
127 fIsOutside(kFALSE),
128 fIsOnBoundary(kFALSE),
129 fIsSameLocation(kTRUE),
130 fIsNullStep(kFALSE),
131 fGeometry(geom),
132 fCache(nullptr),
133 fCurrentVolume(nullptr),
134 fCurrentNode(nullptr),
135 fTopNode(nullptr),
136 fLastNode(nullptr),
137 fNextNode(nullptr),
138 fForcedNode(nullptr),
139 fBackupState(nullptr),
140 fCurrentMatrix(nullptr),
141 fGlobalMatrix(nullptr),
142 fDivMatrix(nullptr),
143 fPath()
144
145{
146 // Default constructor.
148 // printf("Navigator: threadId=%d\n", fThreadId);
149 for (Int_t i = 0; i < 3; i++) {
150 fNormal[i] = 0.;
151 fCldir[i] = 0.;
152 fCldirChecked[i] = 0;
153 fPoint[i] = 0.;
154 fDirection[i] = 0.;
155 fLastPoint[i] = 0.;
156 }
159 fDivMatrix = new TGeoHMatrix();
162 ResetAll();
163}
164
165////////////////////////////////////////////////////////////////////////////////
166/// Destructor.
167
169{
170 if (fCache)
171 delete fCache;
172 if (fBackupState)
173 delete fBackupState;
175 delete[] fOverlapClusters;
176}
177
178////////////////////////////////////////////////////////////////////////////////
179/// Builds the cache for physical nodes and global matrices.
180
182{
183 static Bool_t first = kTRUE;
186 if (nlevel <= 0)
187 nlevel = 100;
188 if (!fCache) {
189 if (nlevel == 100) {
190 if (first && verbose > 0)
191 Info("BuildCache", "--- Maximum geometry depth set to 100");
192 } else {
193 if (first && verbose > 0)
194 Info("BuildCache", "--- Maximum geometry depth is %i", nlevel);
195 }
196 // build cache
197 fCache = new TGeoNodeCache(fGeometry->GetTopNode(), nodeid, nlevel + 1);
200 }
201 first = kFALSE;
202}
203
204////////////////////////////////////////////////////////////////////////////////
205/// Browse the tree of nodes starting from top node according to pathname.
206/// Changes the path accordingly. The path is changed to point to the top node
207/// in case of failure.
208
209Bool_t TGeoNavigator::cd(const char *path)
210{
211 CdTop();
212 if (!path[0])
213 return kTRUE;
214 TString spath = path;
215 TGeoVolume *vol;
216 Int_t length = spath.Length();
217 Int_t ind1 = spath.Index("/");
218 if (ind1 == length - 1)
219 ind1 = -1;
220 Int_t ind2 = 0;
221 Bool_t end = kFALSE;
222 Bool_t first = kTRUE;
224 TGeoNode *node;
225 while (!end) {
226 ind2 = spath.Index("/", ind1 + 1);
227 if (ind2 < 0 || ind2 == length - 1) {
228 if (ind2 < 0)
229 ind2 = length;
230 end = kTRUE;
231 }
232 name = spath(ind1 + 1, ind2 - ind1 - 1);
233 vol = fCurrentNode->GetVolume();
234 if (first) {
235 first = kFALSE;
236 if (name.BeginsWith(vol->GetName())) {
237 ind1 = ind2;
238 continue;
239 }
240 }
241 node = vol->GetNode(name.Data());
242 if (!node) {
243 Error("cd", "Path %s not valid", path);
244 return kFALSE;
245 }
246 CdDown(vol->GetIndex(node));
247 ind1 = ind2;
248 }
249 return kTRUE;
250}
251
252////////////////////////////////////////////////////////////////////////////////
253/// Check if a geometry path is valid without changing the state of the navigator.
254
255Bool_t TGeoNavigator::CheckPath(const char *path) const
256{
257 if (!path[0])
258 return kTRUE;
260 TString spath = path;
261 TGeoVolume *vol;
262 Int_t length = spath.Length();
263 Int_t ind1 = spath.Index("/");
264 if (ind1 == length - 1)
265 ind1 = -1;
266 Int_t ind2 = 0;
267 Bool_t end = kFALSE;
268 Bool_t first = kTRUE;
270 TGeoNode *node;
271 while (!end) {
272 ind2 = spath.Index("/", ind1 + 1);
273 if (ind2 < 0 || ind2 == length - 1) {
274 if (ind2 < 0)
275 ind2 = length;
276 end = kTRUE;
277 }
278 name = spath(ind1 + 1, ind2 - ind1 - 1);
279 vol = crtnode->GetVolume();
280 if (first) {
281 first = kFALSE;
282 if (name.BeginsWith(vol->GetName())) {
283 ind1 = ind2;
284 continue;
285 }
286 }
287 node = vol->GetNode(name.Data());
288 if (!node)
289 return kFALSE;
290 crtnode = node;
291 ind1 = ind2;
292 }
293 return kTRUE;
294}
295
296////////////////////////////////////////////////////////////////////////////////
297/// Change current path to point to the node having this id.
298/// Node id has to be in range : 0 to fNNodes-1 (no check for performance reasons)
299
301{
302 if (fCache) {
303 fCache->CdNode(nodeid);
305 }
306}
307
308////////////////////////////////////////////////////////////////////////////////
309/// Make a daughter of current node current. Can be called only with a valid
310/// daughter index (no check). Updates cache accordingly.
311
313{
315 Bool_t is_offset = node->IsOffset();
316 if (is_offset)
317 node->cd();
318 else
321 fCurrentNode = node;
324 fNmany++;
325 fLevel++;
326}
327
328////////////////////////////////////////////////////////////////////////////////
329/// Make a daughter of current node current. Can be called only with a valid
330/// daughter node (no check). Updates cache accordingly.
331
333{
334 Bool_t is_offset = node->IsOffset();
335 if (is_offset)
336 node->cd();
337 else
339 fCache->CdDown(node);
340 fCurrentNode = node;
343 fNmany++;
344 fLevel++;
345}
346
347////////////////////////////////////////////////////////////////////////////////
348/// Go one level up in geometry. Updates cache accordingly.
349/// Determine the overlapping state of current node.
350
352{
353 if (!fLevel || !fCache)
354 return;
355 fLevel--;
356 if (!fLevel) {
357 CdTop();
358 return;
359 }
360 fCache->CdUp();
363 fNmany--;
364 }
367 if (!fCurrentNode->IsOffset()) {
369 } else {
370 Int_t up = 1;
372 TGeoNode *mother = nullptr;
373 while (offset) {
374 mother = GetMother(up++);
375 offset = mother->IsOffset();
376 }
377 fCurrentOverlapping = mother->IsOverlapping();
378 }
379}
380
381////////////////////////////////////////////////////////////////////////////////
382/// Make top level node the current node. Updates the cache accordingly.
383/// Determine the overlapping state of current node.
384
400
401////////////////////////////////////////////////////////////////////////////////
402/// Do a cd to the node found next by FindNextBoundary
403
405{
406 if (fNextDaughterIndex == -2 || !fCache)
407 return;
408 if (fNextDaughterIndex == -3) {
409 // Next node is a many - restore it
412 return;
413 }
414 if (fNextDaughterIndex == -1) {
415 CdUp();
416 while (fCurrentNode->GetVolume()->IsAssembly())
417 CdUp();
419 return;
420 }
424 while (nextindex >= 0) {
427 }
428 }
430}
431
432////////////////////////////////////////////////////////////////////////////////
433/// Fill volume names of current branch into an array.
434
436{
437 fCache->GetBranchNames(names);
438}
439
440////////////////////////////////////////////////////////////////////////////////
441/// Fill node copy numbers of current branch into an array.
442
447
448////////////////////////////////////////////////////////////////////////////////
449/// Fill node copy numbers of current branch into an array.
450
455
456////////////////////////////////////////////////////////////////////////////////
457/// Cross a division cell. Distance to exit contained in fStep, current node
458/// points to the cell node.
459
461{
463 if (!finder) {
464 Fatal("CrossDivisionCell", "Volume has no pattern finder");
465 return nullptr;
466 }
467 // Mark current node and go up to the level of the divided volume
469 CdUp();
470 Double_t point[3], newpoint[3], dir[3];
473 // Does step cross a boundary along division axis ?
474 Bool_t onbound = finder->IsOnBoundary(newpoint);
475 if (onbound) {
476 // Work along division axis
477 // Get the starting point
478 point[0] = newpoint[0] - dir[0] * fStep * (1. - gTolerance);
479 point[1] = newpoint[1] - dir[1] * fStep * (1. - gTolerance);
480 point[2] = newpoint[2] - dir[2] * fStep * (1. - gTolerance);
481 // Find which is the next crossed cell.
482 finder->FindNode(point, dir);
483 Int_t inext = finder->GetNext();
484 if (inext < 0) {
485 // step fully exits the division along the division axis
486 // Do step exits in a mother cell ?
487 if (fCurrentNode->IsOffset()) {
488 Double_t dist = fCurrentNode->GetVolume()->GetShape()->DistFromInside(point, dir, 3);
489 // Do step exit also from mother cell ?
490 if (dist < fStep + 2. * gTolerance) {
491 // Step exits mother on its own division axis
492 return CrossDivisionCell();
493 }
494 // We end up here
495 return fCurrentNode;
496 }
497 // Exiting in a non-divided volume
498 while (fCurrentNode->GetVolume()->IsAssembly()) {
499 // Move always to mother for assemblies
501 if (!fLevel)
502 break;
503 CdUp();
504 }
506 }
507 // step enters a new cell
508 CdDown(inext + finder->GetDivIndex());
511 }
512 // step exits on an axis other than the division axis -> get next slice
513 if (fCurrentNode->IsOffset())
514 return CrossDivisionCell();
516}
517
518////////////////////////////////////////////////////////////////////////////////
519/// Cross next boundary and locate within current node
520/// The current point must be on the boundary of fCurrentNode.
521
523{
524 // Extrapolate current point with estimated error.
526 Double_t trmax = 1. + TMath::Abs(tr[0]) + TMath::Abs(tr[1]) + TMath::Abs(tr[2]);
527 Double_t extra = 100. * (trmax + fStep) * gTolerance;
529 TGeoNode *crtstate[10];
530 Int_t level = fLevel + 1;
532 for (Int_t i = 0; i < 10; ++i)
533 crtstate[i] = nullptr;
534
535 if (!downwards) {
536 for (Int_t i = 0; i < fLevel; ++i) {
537 crtstate[i] = GetMother(i);
538 if (i == 9)
539 break;
540 }
541 }
542 fPoint[0] += extra * fDirection[0];
543 fPoint[1] += extra * fDirection[1];
544 fPoint[2] += extra * fDirection[2];
546 fForcedNode = nullptr;
547 fPoint[0] -= extra * fDirection[0];
548 fPoint[1] -= extra * fDirection[1];
549 fPoint[2] -= extra * fDirection[2];
550 if (!current)
551 return nullptr;
552 if (downwards) {
554 while (nextindex >= 0) {
556 current = fCurrentNode;
558 }
559 if (idebug > 4) {
560 printf("CrossBoundaryAndLocate: entered %s\n", GetPath());
561 }
562 return current;
563 }
564
565 if (skipnode) {
566 if (current == skipnode) {
567 samepath = kTRUE;
568 if (!downwards) {
569 level = TMath::Min(level, 10);
570 for (Int_t i = 1; i < level; i++) {
571 if (crtstate[i - 1] != GetMother(i)) {
573 break;
574 }
575 }
576 }
577 }
578 }
579
580 if (samepath || current->GetVolume()->IsAssembly()) {
581 if (!fLevel) {
583 if (idebug > 4) {
584 printf("CrossBoundaryAndLocate: Exited geometry\n");
585 }
586 return fGeometry->GetCurrentNode();
587 }
588 CdUp();
589 while (fLevel && fCurrentNode->GetVolume()->IsAssembly())
590 CdUp();
591 if (!fLevel && fCurrentNode->GetVolume()->IsAssembly()) {
593 if (idebug > 4) {
594 printf("CrossBoundaryAndLocate: Exited geometry\n");
595 }
596 if (idebug > 4) {
597 printf("CrossBoundaryAndLocate: entered %s\n", GetPath());
598 }
599 return fCurrentNode;
600 }
601 return fCurrentNode;
602 }
603 if (idebug > 4) {
604 printf("CrossBoundaryAndLocate: entered %s\n", GetPath());
605 }
606 return current;
607}
608
609////////////////////////////////////////////////////////////////////////////////
610/// Find distance to next boundary and store it in fStep. Returns node to which this
611/// boundary belongs. If PATH is specified, compute only distance to the node to which
612/// PATH points. If STEPMAX is specified, compute distance only in case fSafety is smaller
613/// than this value. STEPMAX represent the step to be made imposed by other reasons than
614/// geometry (usually physics processes). Therefore in this case this method provides the
615/// answer to the question : "Is STEPMAX a safe step ?" returning a NULL node and filling
616/// fStep with a big number.
617/// In case frombdr=kTRUE, the isotropic safety is set to zero.
618///
619/// Note : safety distance for the current point is computed ONLY in case STEPMAX is
620/// specified, otherwise users have to call explicitly TGeoManager::Safety() if
621/// they want this computed for the current point.
622
624{
625 // convert current point and direction to local reference
626 Int_t iact = 3;
632 fForcedNode = nullptr;
635 fSafety = 0.;
637 TGeoVolume *top_volume = top_node->GetVolume();
638 // If inside an assembly, go logically up in the hierarchy
639 while (fCurrentNode->GetVolume()->IsAssembly() && fLevel)
640 CdUp();
641 if (stepmax < 1E29) {
642 if (stepmax <= 0) {
643 stepmax = -stepmax;
645 }
646 // if (fLastSafety>0 && IsSamePoint(fPoint[0], fPoint[1], fPoint[2])) fSafety = fLastSafety;
647 fSafety = Safety();
648 // Try to get out easy if proposed step within safe region
649 if (!frombdr && (fSafety > 0) && IsSafeStep(stepmax + gTolerance, fSafety)) {
650 fStep = stepmax;
652 return fCurrentNode;
653 }
657 if (fSafety < gTolerance)
659 else
661 fStep = stepmax;
662 if (stepmax + gTolerance < fSafety) {
664 return fCurrentNode;
665 }
666 }
667 if (computeGlobal)
671 Double_t point[3];
672 Double_t dir[3];
673 if (idebug > 4) {
674 printf("TGeoManager::FindNextBoundary: point=(%19.16f, %19.16f, %19.16f)\n", fPoint[0], fPoint[1], fPoint[2]);
675 printf(" dir= (%19.16f, %19.16f, %19.16f)\n", fDirection[0], fDirection[1],
676 fDirection[2]);
677 printf(" pstep=%9.6g path=%s\n", stepmax, GetPath());
678 }
679 if (path[0]) {
680 PushPath();
681 if (!cd(path)) {
682 PopPath();
683 return nullptr;
684 }
685 if (computeGlobal)
691 if (idebug > 4) {
692 printf("=== To path: %s\n", path);
693 printf("=== local to %s: (%19.16f, %19.16f, %19.16f, %19.16f, %19.16f, %19.16f)\n", tvol->GetName(), point[0],
694 point[1], point[2], dir[0], dir[1], dir[2]);
695 }
696 if (tvol->Contains(point)) {
697 if (idebug > 4)
698 printf("=== volume %s contains point\n", tvol->GetName());
699 fStep = tvol->GetShape()->DistFromInside(&point[0], &dir[0], iact, fStep, &safe);
700 } else {
701 fStep = tvol->GetShape()->DistFromOutside(&point[0], &dir[0], iact, fStep, &safe);
702 if (idebug > 4) {
703 printf("=== volume %s does not contain point\n", tvol->GetName());
704 printf("=== distance to path: %g\n", fStep);
705 tvol->InspectShape();
706 if (fStep < 1.E20) {
707 Double_t newpt[3];
708 newpt[0] = point[0] + fStep * dir[0];
709 newpt[1] = point[1] + fStep * dir[1];
710 newpt[2] = point[2] + fStep * dir[2];
711 printf("=== Propagated point: (%19.16f, %19.16f, %19.16f)", newpt[0], newpt[1], newpt[2]);
712 }
713 while (fLevel) {
714 CdUp();
718 printf("=== local to %s: (%19.16f, %19.16f, %19.16f, %19.16f, %19.16f, %19.16f)\n", tvol->GetName(),
719 point[0], point[1], point[2], dir[0], dir[1], dir[2]);
720 if (tvol->Contains(point)) {
721 printf("=== volume %s contains point\n", tvol->GetName());
722 } else {
723 printf("=== volume %s does not contain point\n", tvol->GetName());
724 snext = tvol->GetShape()->DistFromOutside(&point[0], &dir[0], iact, 1.E30, &safe);
725 }
726 }
727 }
728 }
729 PopPath();
730 return fNextNode;
731 }
732 // compute distance to exit point from current node and the distance to its
733 // closest boundary
734 // if point is outside, just check the top node
735 if (fIsOutside) {
736 snext = top_volume->GetShape()->DistFromOutside(fPoint, fDirection, iact, fStep, &safe);
738 if (snext < fStep - gTolerance) {
740 fStep = snext;
743 while (indnext >= 0) {
745 if (computeGlobal)
748 }
749 return fNextNode;
750 }
751 return nullptr;
752 }
756 if (idebug > 4) {
757 printf(" -> from local=(%19.16f, %19.16f, %19.16f)\n", point[0], point[1], point[2]);
758 printf(" ldir =(%19.16f, %19.16f, %19.16f)\n", dir[0], dir[1], dir[2]);
759 }
760 // find distance to exiting current node
761 snext = vol->GetShape()->DistFromInside(&point[0], &dir[0], iact, fStep, &safe);
762 if (idebug > 4) {
763 printf(" exiting %s shape %s at snext=%g\n", vol->GetName(), vol->GetShape()->ClassName(), snext);
764 }
765 if (snext < fStep - gTolerance) {
769 fStep = snext;
771 if (fStep < 1E-6)
772 return fCurrentNode;
773 }
774 fNextNode = (fStep < 1E20) ? fCurrentNode : nullptr;
775 // Find next daughter boundary for the current volume
776 Int_t idaughter = -1;
778 if (idaughter >= 0)
780 TGeoNode *current = nullptr;
781 TGeoNode *dnode = nullptr;
782 TGeoVolume *mother = nullptr;
783 // if we are in an overlapping node, check also the mother(s)
784 if (fNmany) {
785 Double_t mothpt[3];
786 Double_t vecpt[3];
787 Double_t dpt[3], dvec[3];
789 Int_t idovlp = -1;
791 PushPath(safelevel + 1);
792 while (fCurrentOverlapping) {
794 CdUp();
798 // check distance to out
800 if (!mother->IsAssembly())
801 snext = mother->GetShape()->DistFromInside(&mothpt[0], &vecpt[0], iact, fStep, &safe);
802 if (snext < fStep - gTolerance) {
805 fStep = snext;
806 if (computeGlobal)
811 }
812 // check overlapping nodes
813 for (Int_t i = 0; i < novlps; i++) {
814 current = mother->GetNode(ovlps[i]);
815 if (!current->IsOverlapping()) {
816 current->cd();
817 current->MasterToLocal(&mothpt[0], &dpt[0]);
818 current->MasterToLocalVect(&vecpt[0], &dvec[0]);
819 // Current point may be inside the other node - geometry error that we ignore
820 snext = current->GetVolume()->GetShape()->DistFromOutside(&dpt[0], &dvec[0], iact, fStep, &safe);
821 if (snext < fStep - gTolerance) {
822 if (computeGlobal) {
824 fCurrentMatrix->Multiply(current->GetMatrix());
825 }
828 fStep = snext;
829 fNextNode = current;
831 CdDown(ovlps[i]);
833 CdUp();
834 }
835 } else {
836 // another many - check if point is in or out
837 current->cd();
838 current->MasterToLocal(&mothpt[0], &dpt[0]);
839 current->MasterToLocalVect(&vecpt[0], &dvec[0]);
840 if (current->GetVolume()->Contains(dpt)) {
841 if (current->GetVolume()->GetNdaughters()) {
842 CdDown(ovlps[i]);
846 if (dnode) {
847 if (computeGlobal) {
849 fCurrentMatrix->Multiply(dnode->GetMatrix());
850 }
853 CdDown(idovlp);
855 Int_t iup = 0;
856 while (indnext >= 0) {
858 iup++;
860 }
862 while (iup > 0) {
863 CdUp();
864 iup--;
865 }
866 CdUp();
867 }
868 CdUp();
869 }
870 } else {
871 snext = current->GetVolume()->GetShape()->DistFromOutside(&dpt[0], &dvec[0], iact, fStep, &safe);
872 if (snext < fStep - gTolerance) {
873 if (computeGlobal) {
875 fCurrentMatrix->Multiply(current->GetMatrix());
876 }
879 fStep = snext;
880 fNextNode = current;
882 CdDown(ovlps[i]);
884 CdUp();
885 }
886 }
887 }
888 }
889 }
890 // Now we are in a non-overlapping node
891 if (fNmany) {
892 // We have overlaps up in the branch, check distance to exit
893 Int_t up = 1;
902 while (nmany) {
904 if (!mothernode) {
905 Fatal("FindNextBoundary", "Cannot find mother node");
906 return nullptr;
907 }
908 mup = mothernode;
909 imother = up + 1;
910 offset = kFALSE;
911 while (mup->IsOffset()) {
912 mup = GetMother(imother++);
913 offset = kTRUE;
914 }
915 nextovlp = mup->IsOverlapping();
916 if (offset) {
917 mothernode = mup;
918 if (nextovlp)
919 nmany -= imother - up;
920 up = imother - 1;
921 } else {
922 if (ovlp)
923 nmany--;
924 }
925 if (ovlp || nextovlp) {
927 if (!matrix) {
928 Fatal("FindNextBoundary", "Cannot find mother matrix");
929 return nullptr;
930 }
931 matrix->MasterToLocal(fPoint, dpt);
932 matrix->MasterToLocalVect(fDirection, dvec);
934 if (!mothernode->GetVolume()->IsAssembly())
935 snext = mothernode->GetVolume()->GetShape()->DistFromInside(dpt, dvec, iact, fStep);
936 if (snext < fStep - gTolerance) {
939 fStep = snext;
942 if (computeGlobal)
944 while (up--)
945 CdUp();
947 up = 1;
949 ovlp = currentnode->IsOverlapping();
950 continue;
951 }
952 }
954 ovlp = nextovlp;
955 up++;
956 }
957 }
958 PopPath();
959 }
960 // Compute now the distance in case we have a parallel world
963 // printf("path: %s next node %s at %g\n", GetPath(), fNextNode->GetName(), fStep);
965 if (pnode) {
966 // A boundary is hit at less than fPStep
967 fStep = parstep;
968 fNextNode = pnode->GetNode();
969 fNextDaughterIndex = -2; // No way to store it for CdNext
973 while (nextindex >= 0) {
976 }
977 }
978 }
979 return fNextNode;
980}
981
982////////////////////////////////////////////////////////////////////////////////
983/// Computes as fStep the distance to next daughter of the current volume.
984/// The point and direction must be converted in the coordinate system of the current volume.
985/// The proposed step limit is fStep.
986
988{
991 idaughter = -1; // nothing crossed
992 TGeoNode *nodefound = nullptr;
993 // Get number of daughters. If no daughters we are done.
994
996 Int_t nd = vol->GetNdaughters();
997 if (!nd)
998 return nullptr; // No daughter
1000 return nullptr;
1001 Double_t lpoint[3], ldir[3];
1002 TGeoNode *current = nullptr;
1003 Int_t i = 0;
1004 // if current volume is divided, we are in the non-divided region. We
1005 // check first if we are inside a cell in which case compute distance to next cell
1007 if (finder) {
1008 Int_t ifirst = finder->GetDivIndex();
1009 Int_t ilast = ifirst + finder->GetNdiv() - 1;
1010 current = finder->FindNode(point);
1011 if (current) {
1012 // Point inside a cell: find distance to next cell
1013 Int_t index = current->GetIndex();
1014 if ((index - 1) >= ifirst)
1015 ifirst = index - 1;
1016 else
1017 ifirst = -1;
1018 if ((index + 1) <= ilast)
1019 ilast = index + 1;
1020 else
1021 ilast = -1;
1022 }
1023 if (ifirst >= 0) {
1024 current = vol->GetNode(ifirst);
1025 current->cd();
1026 current->MasterToLocal(&point[0], lpoint);
1027 current->MasterToLocalVect(&dir[0], ldir);
1028 snext = current->GetVolume()->GetShape()->DistFromOutside(lpoint, ldir, 3, fStep);
1029 if (snext < fStep - gTolerance) {
1030 if (compmatrix) {
1032 fCurrentMatrix->Multiply(current->GetMatrix());
1033 }
1036 fStep = snext;
1037 fNextNode = current;
1038 nodefound = current;
1039 idaughter = ifirst;
1040 }
1041 }
1042 if (ilast == ifirst)
1043 return nodefound;
1044 if (ilast >= 0) {
1045 current = vol->GetNode(ilast);
1046 current->cd();
1047 current->MasterToLocal(&point[0], lpoint);
1048 current->MasterToLocalVect(&dir[0], ldir);
1049 snext = current->GetVolume()->GetShape()->DistFromOutside(lpoint, ldir, 3, fStep);
1050 if (snext < fStep - gTolerance) {
1051 if (compmatrix) {
1053 fCurrentMatrix->Multiply(current->GetMatrix());
1054 }
1057 fStep = snext;
1058 fNextNode = current;
1059 nodefound = current;
1060 idaughter = ilast;
1061 }
1062 }
1063 return nodefound;
1064 }
1065 // if only few daughters, check all and exit
1067 Int_t indnext;
1068 if (idebug > 4)
1069 printf(" Checking distance to %d daughters...\n", nd);
1070 if (nd < 5 || !voxels) {
1071 for (i = 0; i < nd; i++) {
1072 current = vol->GetNode(i);
1073 if (fGeometry->IsActivityEnabled() && !current->GetVolume()->IsActive())
1074 continue;
1075 current->cd();
1076 if (voxels && voxels->IsSafeVoxel(point, i, fStep))
1077 continue;
1078 current->MasterToLocal(point, lpoint);
1079 current->MasterToLocalVect(dir, ldir);
1080 if (current->IsOverlapping() && current->GetVolume()->Contains(lpoint) &&
1081 current->GetVolume()->GetShape()->Safety(lpoint, kTRUE) > gTolerance)
1082 continue;
1083 snext = current->GetVolume()->GetShape()->DistFromOutside(lpoint, ldir, 3, fStep);
1084 if (snext < fStep - gTolerance) {
1085 if (idebug > 4) {
1086 printf(" -> from local=(%19.16f, %19.16f, %19.16f)\n", lpoint[0], lpoint[1], lpoint[2]);
1087 printf(" ldir =(%19.16f, %19.16f, %19.16f)\n", ldir[0], ldir[1], ldir[2]);
1088 printf(" -> to: %s shape %s snext=%g\n", current->GetName(),
1089 current->GetVolume()->GetShape()->ClassName(), snext);
1090 }
1091 indnext = current->GetVolume()->GetNextNodeIndex();
1092 if (compmatrix) {
1094 fCurrentMatrix->Multiply(current->GetMatrix());
1095 }
1098 fStep = snext;
1099 fNextNode = current;
1101 idaughter = i;
1102 while (indnext >= 0) {
1103 current = current->GetDaughter(indnext);
1104 if (compmatrix)
1105 fCurrentMatrix->Multiply(current->GetMatrix());
1106 fNextNode = current;
1107 nodefound = current;
1108 indnext = current->GetVolume()->GetNextNodeIndex();
1109 }
1110 }
1111 }
1112 if (vol->IsAssembly())
1113 ((TGeoVolumeAssembly *)vol)->SetNextNodeIndex(idaughter);
1114 return nodefound;
1115 }
1116 // if current volume is voxelized, first get current voxel
1117 Int_t ncheck = 0;
1118 Int_t sumchecked = 0;
1119 Int_t *vlist = nullptr;
1121 voxels->SortCrossedVoxels(point, dir, info);
1122 while ((sumchecked < nd) && (vlist = voxels->GetNextVoxel(point, dir, ncheck, info))) {
1123 for (i = 0; i < ncheck; i++) {
1124 current = vol->GetNode(vlist[i]);
1125 if (fGeometry->IsActivityEnabled() && !current->GetVolume()->IsActive())
1126 continue;
1127 current->cd();
1128 current->MasterToLocal(point, lpoint);
1129 current->MasterToLocalVect(dir, ldir);
1130 if (current->IsOverlapping() && current->GetVolume()->Contains(lpoint) &&
1131 current->GetVolume()->GetShape()->Safety(lpoint, kTRUE) > gTolerance)
1132 continue;
1133 snext = current->GetVolume()->GetShape()->DistFromOutside(lpoint, ldir, 3, fStep);
1134 sumchecked++;
1135 // printf("checked %d from %d : snext=%g\n", sumchecked, nd, snext);
1136 if (snext < fStep - gTolerance) {
1137 if (idebug > 4) {
1138 printf(" -> from local=(%19.16f, %19.16f, %19.16f)\n", lpoint[0], lpoint[1], lpoint[2]);
1139 printf(" ldir =(%19.16f, %19.16f, %19.16f)\n", ldir[0], ldir[1], ldir[2]);
1140 printf(" -> to: %s shape %s snext=%g\n", current->GetName(),
1141 current->GetVolume()->GetShape()->ClassName(), snext);
1142 }
1143 indnext = current->GetVolume()->GetNextNodeIndex();
1144 if (compmatrix) {
1146 fCurrentMatrix->Multiply(current->GetMatrix());
1147 }
1150 fStep = snext;
1151 fNextNode = current;
1153 idaughter = vlist[i];
1154 while (indnext >= 0) {
1155 current = current->GetDaughter(indnext);
1156 if (compmatrix)
1157 fCurrentMatrix->Multiply(current->GetMatrix());
1158 fNextNode = current;
1159 nodefound = current;
1160 indnext = current->GetVolume()->GetNextNodeIndex();
1161 }
1162 }
1163 }
1164 }
1166 if (vol->IsAssembly())
1167 ((TGeoVolumeAssembly *)vol)->SetNextNodeIndex(idaughter);
1168 return nodefound;
1169}
1170
1171////////////////////////////////////////////////////////////////////////////////
1172/// Compute distance to next boundary within STEPMAX. If no boundary is found,
1173/// propagate current point along current direction with fStep=STEPMAX. Otherwise
1174/// propagate with fStep=SNEXT (distance to boundary) and locate/return the next
1175/// node.
1176
1178{
1179 Int_t iact = 3;
1183 fForcedNode = nullptr;
1185 TGeoNode *skip;
1187 fStep = stepmax;
1189 // If inside an assembly, go logically up in the hierarchy
1190 while (fCurrentNode->GetVolume()->IsAssembly() && fLevel)
1191 CdUp();
1192 if (compsafe) {
1193 // Try to get out easy if proposed step within safe region
1196 fPoint[0] += stepmax * fDirection[0];
1197 fPoint[1] += stepmax * fDirection[1];
1198 fPoint[2] += stepmax * fDirection[2];
1199 return fCurrentNode;
1200 }
1201 Safety();
1204 // If proposed step less than safety, nothing to check
1205 if (fSafety > stepmax + gTolerance) {
1206 fPoint[0] += stepmax * fDirection[0];
1207 fPoint[1] += stepmax * fDirection[1];
1208 fPoint[2] += stepmax * fDirection[2];
1209 return fCurrentNode;
1210 }
1211 }
1212 Double_t extra = (fIsOnBoundary) ? gTolerance : 0.0;
1214 fPoint[0] += extra * fDirection[0];
1215 fPoint[1] += extra * fDirection[1];
1216 fPoint[2] += extra * fDirection[2];
1218 if (idebug > 4) {
1219 printf("TGeoManager::FindNextBAndStep: point=(%19.16f, %19.16f, %19.16f)\n", fPoint[0], fPoint[1], fPoint[2]);
1220 printf(" dir= (%19.16f, %19.16f, %19.16f)\n", fDirection[0], fDirection[1],
1221 fDirection[2]);
1222 printf(" pstep=%9.6g path=%s\n", stepmax, GetPath());
1223 }
1224
1225 if (fIsOutside) {
1227 if (snext < fStep - gTolerance) {
1228 if (snext <= 0) {
1229 snext = 0.0;
1230 fStep = snext;
1231 fPoint[0] -= extra * fDirection[0];
1232 fPoint[1] -= extra * fDirection[1];
1233 fPoint[2] -= extra * fDirection[2];
1234 } else {
1235 fStep = snext + extra;
1236 }
1240 while (nextindex >= 0) {
1244 if (nextindex < 0)
1246 }
1247 // Update global point
1248 fPoint[0] += snext * fDirection[0];
1249 fPoint[1] += snext * fDirection[1];
1250 fPoint[2] += snext * fDirection[2];
1255 }
1256 if (snext < TGeoShape::Big()) {
1257 // New point still outside, but the top node is reachable
1259 fPoint[0] += (fStep - extra) * fDirection[0];
1260 fPoint[1] += (fStep - extra) * fDirection[1];
1261 fPoint[2] += (fStep - extra) * fDirection[2];
1262 return fNextNode;
1263 }
1264 // top node not reachable from current point/direction
1265 fNextNode = nullptr;
1267 return nullptr;
1268 }
1269 Double_t point[3], dir[3];
1270 Int_t icrossed = -2;
1271 fGlobalMatrix->MasterToLocal(fPoint, &point[0]);
1274 // find distance to exiting current node
1275 if (idebug > 4) {
1276 printf(" -> from local=(%19.16f, %19.16f, %19.16f)\n", point[0], point[1], point[2]);
1277 printf(" ldir =(%19.16f, %19.16f, %19.16f)\n", dir[0], dir[1], dir[2]);
1278 }
1279 // find distance to exiting current node
1280 snext = vol->GetShape()->DistFromInside(point, dir, iact, fStep);
1281 if (idebug > 4) {
1282 printf(" exiting %s shape %s at snext=%g\n", vol->GetName(), vol->GetShape()->ClassName(), snext);
1283 }
1285 if (snext <= gTolerance) {
1286 // Current point on the boundary while track exiting
1287 snext = gTolerance;
1288 fStep = snext;
1293 fPoint[0] += fStep * fDirection[0];
1294 fPoint[1] += fStep * fDirection[1];
1295 fPoint[2] += fStep * fDirection[2];
1297 if (!fLevel && !is_assembly) {
1298 fIsOutside = kTRUE;
1299 return nullptr;
1300 }
1301 if (fCurrentNode->IsOffset())
1302 return CrossDivisionCell();
1303 if (fLevel)
1304 CdUp();
1305 else
1306 skip = nullptr;
1308 }
1309
1310 if (snext < fStep - gTolerance) {
1311 // Currently the minimum step chosen is the exiting one
1312 icrossed = -1;
1313 fStep = snext;
1316 }
1317 // Find next daughter boundary for the current volume
1318 Int_t idaughter = -1;
1320 if (crossed) {
1324 }
1325 TGeoNode *current = nullptr;
1326 TGeoNode *dnode = nullptr;
1327 TGeoVolume *mother = nullptr;
1328 // if we are in an overlapping node, check also the mother(s)
1329 if (fNmany) {
1330 Double_t mothpt[3];
1331 Double_t vecpt[3];
1332 Double_t dpt[3], dvec[3];
1333 Int_t novlps;
1335 PushPath(safelevel + 1);
1336 while (fCurrentOverlapping) {
1338 CdUp();
1342 // check distance to out
1344 if (!mother->IsAssembly())
1345 snext = mother->GetShape()->DistFromInside(mothpt, vecpt, iact, fStep);
1346 if (snext < fStep - gTolerance) {
1347 // exiting mother first (extrusion)
1348 icrossed = -1;
1349 PopDummy();
1350 PushPath(safelevel + 1);
1353 fStep = snext;
1356 }
1357 // check overlapping nodes
1358 for (Int_t i = 0; i < novlps; i++) {
1359 current = mother->GetNode(ovlps[i]);
1360 if (!current->IsOverlapping()) {
1361 current->cd();
1362 current->MasterToLocal(&mothpt[0], &dpt[0]);
1363 current->MasterToLocalVect(&vecpt[0], &dvec[0]);
1365 if (snext < fStep - gTolerance) {
1366 PopDummy();
1367 PushPath(safelevel + 1);
1369 fCurrentMatrix->Multiply(current->GetMatrix());
1372 icrossed = ovlps[i];
1373 fStep = snext;
1374 fNextNode = current;
1375 }
1376 } else {
1377 // another many - check if point is in or out
1378 current->cd();
1379 current->MasterToLocal(&mothpt[0], &dpt[0]);
1380 current->MasterToLocalVect(&vecpt[0], &dvec[0]);
1381 if (current->GetVolume()->Contains(dpt)) {
1382 if (current->GetVolume()->GetNdaughters()) {
1383 CdDown(ovlps[i]);
1385 if (dnode) {
1387 fCurrentMatrix->Multiply(dnode->GetMatrix());
1389 PopDummy();
1390 PushPath(safelevel + 1);
1393 fNextNode = dnode;
1394 }
1395 CdUp();
1396 }
1397 } else {
1399 if (snext < fStep - gTolerance) {
1401 fCurrentMatrix->Multiply(current->GetMatrix());
1404 fStep = snext;
1405 fNextNode = current;
1406 icrossed = ovlps[i];
1407 PopDummy();
1408 PushPath(safelevel + 1);
1409 }
1410 }
1411 }
1412 }
1413 }
1414 // Now we are in a non-overlapping node
1415 if (fNmany) {
1416 // We have overlaps up in the branch, check distance to exit
1417 Int_t up = 1;
1418 Int_t imother;
1419 Int_t nmany = fNmany;
1420 Bool_t ovlp = kFALSE;
1426 while (nmany) {
1428 mup = mothernode;
1429 imother = up + 1;
1430 offset = kFALSE;
1431 while (mup->IsOffset()) {
1432 mup = GetMother(imother++);
1433 offset = kTRUE;
1434 }
1435 nextovlp = mup->IsOverlapping();
1436 if (offset) {
1437 mothernode = mup;
1438 if (nextovlp)
1439 nmany -= imother - up;
1440 up = imother - 1;
1441 } else {
1442 if (ovlp)
1443 nmany--;
1444 }
1445 if (ovlp || nextovlp) {
1447 matrix->MasterToLocal(fPoint, dpt);
1448 matrix->MasterToLocalVect(fDirection, dvec);
1450 if (!mothernode->GetVolume()->IsAssembly())
1451 snext = mothernode->GetVolume()->GetShape()->DistFromInside(dpt, dvec, iact, fStep);
1454 if (snext < fStep - gTolerance) {
1457 fStep = snext;
1458 while (up--)
1459 CdUp();
1460 PopDummy();
1461 PushPath();
1462 icrossed = -1;
1463 up = 1;
1465 ovlp = currentnode->IsOverlapping();
1466 continue;
1467 }
1468 }
1470 ovlp = nextovlp;
1471 up++;
1472 }
1473 }
1474 PopPath();
1475 }
1476 // Compute now the distance in case we have a parallel world
1478 TGeoPhysicalNode *pnode = nullptr;
1481 if (pnode) {
1482 // A boundary is hit at less than fPStep
1483 fStep = parstep;
1484 fPoint[0] += fStep * fDirection[0];
1485 fPoint[1] += fStep * fDirection[1];
1486 fPoint[2] += fStep * fDirection[2];
1487 fNextNode = pnode->GetNode();
1488 // icrossed = -4; //
1491 cd(pnode->GetName());
1493 while (nextindex >= 0) {
1494 current = fCurrentNode;
1497 }
1498 return fCurrentNode;
1499 }
1500 }
1501 fPoint[0] += fStep * fDirection[0];
1502 fPoint[1] += fStep * fDirection[1];
1503 fPoint[2] += fStep * fDirection[2];
1504 fStep += extra;
1505 if (icrossed == -2) {
1506 // Nothing crossed within stepmax -> propagate and return same location
1508 return fCurrentNode;
1509 }
1511 if (icrossed == -1) {
1512 // Exiting current node.
1515 if (!fLevel && !is_assembly) {
1516 fIsOutside = kTRUE;
1517 return nullptr;
1518 }
1519 if (fCurrentNode->IsOffset())
1520 return CrossDivisionCell();
1521 if (fLevel)
1522 CdUp();
1523 else
1524 skip = nullptr;
1526 }
1527
1530 while (nextindex >= 0) {
1531 current = fCurrentNode;
1534 }
1536 return CrossBoundaryAndLocate(kTRUE, current);
1537}
1538
1539////////////////////////////////////////////////////////////////////////////////
1540/// Returns deepest node containing current point.
1541
1543{
1544 fSafety = 0;
1551 TGeoNode *last = fCurrentNode;
1552 TGeoNode *found = SearchNode();
1553 if (found != last) {
1555 } else {
1556 if (last->IsOverlapping())
1558 }
1559 return found;
1560}
1561
1562////////////////////////////////////////////////////////////////////////////////
1563/// Returns deepest node containing current point.
1564
1566{
1567 fPoint[0] = x;
1568 fPoint[1] = y;
1569 fPoint[2] = z;
1570 fSafety = 0;
1575 fStartSafe = kTRUE;
1577 TGeoNode *last = fCurrentNode;
1578 TGeoNode *found = SearchNode();
1579 if (found != last) {
1581 } else {
1582 if (last->IsOverlapping())
1584 }
1585 return found;
1586}
1587
1588////////////////////////////////////////////////////////////////////////////////
1589/// Computes fast normal to next crossed boundary, assuming that the current point
1590/// is close enough to the boundary. Works only after calling FindNextBoundary.
1591
1605
1606////////////////////////////////////////////////////////////////////////////////
1607/// Computes normal vector to the next surface that will be or was already
1608/// crossed when propagating on a straight line from a given point/direction.
1609/// Returns the normal vector cosines in the MASTER coordinate system. The dot
1610/// product of the normal and the current direction is positive defined.
1611
1613{
1614 return FindNormalFast();
1615}
1616
1617////////////////////////////////////////////////////////////////////////////////
1618/// Initialize current point and current direction vector (normalized)
1619/// in MARS. Return corresponding node.
1620
1622{
1623 SetCurrentPoint(point);
1625 return FindNode();
1626}
1627
1628////////////////////////////////////////////////////////////////////////////////
1629/// Initialize current point and current direction vector (normalized)
1630/// in MARS. Return corresponding node.
1631
1638
1639////////////////////////////////////////////////////////////////////////////////
1640/// Reset current state flags.
1641
1650
1651//////////////////////////////////////////////////////////////////////////////////
1652/// Wrapper for getting the safety from the parallel world. Takes care of
1653/// caching mechanics + talking to the parallel world.
1654
1656{
1657 if (!IsPWSafetyCaching()) {
1659 }
1661 if (cached > 0) {
1662 // if cache is valid, just use it
1663 return cached;
1664 }
1665 // otherwise we need to evaluate it and update the cache
1666 // we evaluate this with saf_max = infinity to get the best
1667 // possible safety value
1668 auto pw = fGeometry->GetParallelWorld();
1669 const auto newsafety = pw->Safety(cpoint /*saf_max*/);
1670
1671 // we need to be a bit careful: A returned safety value of TGeoShape::Big()
1672 // is not the actual safety and should not be cached
1673 if (newsafety < TGeoShape::Big()) {
1675 fLastPWSaftyPnt[0] = cpoint[0];
1676 fLastPWSaftyPnt[1] = cpoint[1];
1677 fLastPWSaftyPnt[2] = cpoint[2];
1678 } else {
1679 fLastPWSafety = -1;
1680 }
1681 return newsafety;
1682}
1683
1684////////////////////////////////////////////////////////////////////////////////
1685/// Compute safe distance from the current point. This represent the distance
1686/// from POINT to the closest boundary.
1687
1689{
1690 if (fIsOnBoundary) {
1691 fSafety = 0;
1692 return fSafety;
1693 }
1694 Double_t point[3];
1695 Double_t safpar = TGeoShape::Big(); // safety from parallel world
1696 if (!inside)
1698
1699 // Check if parallel navigation is enabled
1700 const bool have_PW = fGeometry->IsParallelWorldNav();
1701
1702 if (fIsOutside) {
1704 if (fSafety < gTolerance) {
1705 fSafety = 0;
1707 return fSafety;
1708 }
1709
1710 // cross-check against the parallel world safety, using fSafety as limit
1711 if (have_PW) {
1713 }
1714 return TMath::Min(fSafety, safpar);
1715 }
1716 //---> convert point to local reference frame of current node
1718
1719 //---> compute safety to current node
1721 if (!inside) {
1722 fSafety = vol->GetShape()->Safety(point, kTRUE);
1723 //---> if we were just entering, return this safety
1724 if (fSafety < gTolerance) {
1725 fSafety = 0;
1727 return fSafety;
1728 }
1729 }
1730
1731 //---> Check against the parallel geometry safety
1732 // cross-check against the parallel world safety, using fSafety as limit
1733 if (have_PW) {
1735 }
1736 if (safpar < fSafety)
1737 fSafety = safpar;
1738
1739 //---> if we were just exiting, return this safety
1740 TObjArray *nodes = vol->GetNodes();
1742 if (!nd && !fCurrentOverlapping)
1743 return fSafety;
1744 TGeoNode *node;
1745 Double_t safe;
1746 Int_t id;
1747
1748 // if current volume is divided, we are in the non-divided region. We
1749 // check only the first and the last cell
1751 if (finder) {
1752 Int_t ifirst = finder->GetDivIndex();
1753 node = (TGeoNode *)nodes->UncheckedAt(ifirst);
1754 node->cd();
1755 safe = node->Safety(point, kFALSE);
1756 if (safe < gTolerance) {
1757 fSafety = 0;
1759 return fSafety;
1760 }
1761 if (safe < fSafety)
1762 fSafety = safe;
1763 Int_t ilast = ifirst + finder->GetNdiv() - 1;
1764 if (ilast == ifirst)
1765 return fSafety;
1766 node = (TGeoNode *)nodes->UncheckedAt(ilast);
1767 node->cd();
1768 safe = node->Safety(point, kFALSE);
1769 if (safe < gTolerance) {
1770 fSafety = 0;
1772 return fSafety;
1773 }
1774 if (safe < fSafety)
1775 fSafety = safe;
1776 if (fCurrentOverlapping && !inside)
1778 return fSafety;
1779 }
1780
1781 //---> If no voxels just loop daughters
1783 if (!voxels) {
1784 for (id = 0; id < nd; id++) {
1785 node = (TGeoNode *)nodes->UncheckedAt(id);
1786 safe = node->Safety(point, kFALSE);
1787 if (safe < gTolerance) {
1788 fSafety = 0;
1790 return fSafety;
1791 }
1792 if (safe < fSafety)
1793 fSafety = safe;
1794 }
1795 if (fNmany && !inside)
1797 return fSafety;
1798 } else {
1799 if (voxels->NeedRebuild()) {
1800 voxels->Voxelize();
1801 vol->FindOverlaps();
1802 }
1803 }
1804
1805 //---> check fast unsafe voxels
1806 Double_t *boxes = voxels->GetBoxes();
1807 for (id = 0; id < nd; id++) {
1808 Int_t ist = 6 * id;
1809 Double_t dxyz = 0.;
1810 Double_t dxyz0 = TMath::Abs(point[0] - boxes[ist + 3]) - boxes[ist];
1811 if (dxyz0 > fSafety)
1812 continue;
1813 Double_t dxyz1 = TMath::Abs(point[1] - boxes[ist + 4]) - boxes[ist + 1];
1814 if (dxyz1 > fSafety)
1815 continue;
1816 Double_t dxyz2 = TMath::Abs(point[2] - boxes[ist + 5]) - boxes[ist + 2];
1817 if (dxyz2 > fSafety)
1818 continue;
1819 if (dxyz0 > 0)
1820 dxyz += dxyz0 * dxyz0;
1821 if (dxyz1 > 0)
1822 dxyz += dxyz1 * dxyz1;
1823 if (dxyz2 > 0)
1824 dxyz += dxyz2 * dxyz2;
1825 if (dxyz >= fSafety * fSafety)
1826 continue;
1827 node = (TGeoNode *)nodes->UncheckedAt(id);
1828 safe = node->Safety(point, kFALSE);
1829 if (safe < gTolerance) {
1830 fSafety = 0;
1832 return fSafety;
1833 }
1834 if (safe < fSafety)
1835 fSafety = safe;
1836 }
1837 if (fNmany && !inside)
1839 return fSafety;
1840}
1841
1842////////////////////////////////////////////////////////////////////////////////
1843/// Compute safe distance from the current point within an overlapping node
1844
1846{
1847 Double_t point[3], local[3];
1848 Double_t safe;
1849 Bool_t contains;
1851 TGeoVolume *vol;
1852 Int_t novlp, io;
1853 Int_t *ovlp;
1855 PushPath(safelevel + 1);
1856 while (fCurrentOverlapping) {
1858 CdUp();
1859 vol = fCurrentNode->GetVolume();
1861 contains = fCurrentNode->GetVolume()->Contains(point);
1862 safe = fCurrentNode->GetVolume()->GetShape()->Safety(point, contains);
1864 fSafety = safe;
1865 if (!novlp || !contains)
1866 continue;
1867 // we are now in the container, check safety to all candidates
1868 for (io = 0; io < novlp; io++) {
1869 nodeovlp = vol->GetNode(ovlp[io]);
1870 nodeovlp->GetMatrix()->MasterToLocal(point, local);
1871 contains = nodeovlp->GetVolume()->Contains(local);
1872 if (contains) {
1873 CdDown(ovlp[io]);
1874 safe = Safety(kTRUE);
1875 CdUp();
1876 } else {
1877 safe = nodeovlp->GetVolume()->GetShape()->Safety(local, kFALSE);
1878 }
1880 fSafety = safe;
1881 }
1882 }
1883 if (fNmany) {
1884 // We have overlaps up in the branch, check distance to exit
1885 Int_t up = 1;
1886 Int_t imother;
1887 Int_t nmany = fNmany;
1890 TGeoNode *mother, *mup;
1892 while (nmany) {
1893 mother = GetMother(up);
1894 mup = mother;
1895 imother = up + 1;
1896 while (mup->IsOffset())
1897 mup = GetMother(imother++);
1898 nextovlp = mup->IsOverlapping();
1899 if (crtovlp)
1900 nmany--;
1901 if (crtovlp || nextovlp) {
1903 matrix->MasterToLocal(fPoint, local);
1904 safe = mother->GetVolume()->GetShape()->Safety(local, kTRUE);
1905 if (safe < fSafety)
1906 fSafety = safe;
1907 crtovlp = nextovlp;
1908 }
1909 up++;
1910 }
1911 }
1912 PopPath();
1913 if (fSafety < gTolerance) {
1914 fSafety = 0.;
1916 }
1917}
1918
1919////////////////////////////////////////////////////////////////////////////////
1920/// Returns the deepest node containing fPoint, which must be set a priori.
1921/// Check if parallel world navigation is enabled
1922
1924{
1927 if (pnode) {
1928 // A node from the parallel world contains the point -> stop the search
1929 // and synchronize with navigation state
1930 pnode->cd();
1932 while (crtindex >= 0) {
1933 // Make sure we did not end up in an assembly.
1936 }
1937 return fCurrentNode;
1938 }
1939 }
1940 Double_t point[3];
1941 fNextDaughterIndex = -2;
1942 TGeoVolume *vol = nullptr;
1945 if (!downwards) {
1946 // we are looking upwards until inside current node or exit
1948 // We are inside an inactive volume-> go upwards
1949 CdUp();
1951 return SearchNode(kFALSE, skipnode);
1952 }
1953 // Check if the current point is still inside the current volume
1954 vol = fCurrentNode->GetVolume();
1955 if (vol->IsAssembly())
1957 // If the current node is not to be skipped
1958 if (!inside_current) {
1960 inside_current = vol->Contains(point);
1961 }
1962 // Point might be inside an overlapping node
1963 if (fNmany) {
1965 }
1966 if (!inside_current) {
1967 // If not, go upwards
1969 TGeoNode *skip = fCurrentNode; // skip current node at next search
1970 // check if we can go up
1971 if (!fLevel) {
1972 fIsOutside = kTRUE;
1973 return nullptr;
1974 }
1975 CdUp();
1976 return SearchNode(kFALSE, skip);
1977 }
1978 }
1979 vol = fCurrentNode->GetVolume();
1981 if (!inside_current && downwards) {
1982 // we are looking downwards
1985 else
1986 inside_current = vol->Contains(point);
1987 if (!inside_current) {
1989 return nullptr;
1990 } else {
1991 if (fIsOutside) {
1994 }
1995 if (idebug > 4) {
1996 printf("Search node local=(%19.16f, %19.16f, %19.16f) -> %s\n", point[0], point[1], point[2],
1998 }
1999 }
2000 }
2001 // point inside current (safe) node -> search downwards
2002 TGeoNode *node;
2003 Int_t ncheck = 0;
2004 // if inside an non-overlapping node, reset overlap searches
2005 if (!fCurrentOverlapping) {
2007 }
2008
2010 while (crtindex >= 0 && downwards) {
2011 // Make sure we did not end up in an assembly.
2013 vol = fCurrentNode->GetVolume();
2015 if (crtindex < 0)
2017 }
2018
2019 Int_t nd = vol->GetNdaughters();
2020 // in case there are no daughters
2021 if (!nd)
2022 return fCurrentNode;
2024 return fCurrentNode;
2025
2027 // point is inside the current node
2028 // first check if inside a division
2029 if (finder) {
2030 node = finder->FindNode(point);
2031 if (!node && fForcedNode) {
2032 // Point *HAS* to be inside a cell
2033 Double_t dir[3];
2035 finder->FindNode(point, dir);
2036 node = finder->CdNext();
2037 if (!node)
2038 return fCurrentNode; // inside divided volume but not in a cell
2039 }
2040 if (node && node != skipnode) {
2041 // go inside the division cell and search downwards
2043 CdDown(node->GetIndex());
2044 fForcedNode = nullptr;
2045 return SearchNode(kTRUE, node);
2046 }
2047 // point is not inside the division, but might be in other nodes
2048 // at the same level (NOT SUPPORTED YET)
2049 while (fCurrentNode && fCurrentNode->IsOffset())
2050 CdUp();
2051 return fCurrentNode;
2052 }
2053 // second, look if current volume is voxelized
2055 Int_t *check_list = nullptr;
2056 Int_t id;
2057 if (voxels) {
2058 // get the list of nodes passing thorough the current voxel
2059 check_list = voxels->GetCheckList(&point[0], ncheck, *fCache->GetInfo());
2060 // if none in voxel, see if this is the last one
2061 if (!check_list) {
2062 if (!fCurrentNode->GetVolume()->IsAssembly()) {
2064 return fCurrentNode;
2065 }
2066 // Point in assembly - go up
2067 node = fCurrentNode;
2068 if (!fLevel) {
2069 fIsOutside = kTRUE;
2071 return nullptr;
2072 }
2073 CdUp();
2075 return SearchNode(kFALSE, node);
2076 }
2077 // loop all nodes in voxel
2078 for (id = 0; id < ncheck; id++) {
2079 node = vol->GetNode(check_list[id]);
2080 if (node == skipnode)
2081 continue;
2082 if (fGeometry->IsActivityEnabled() && !node->GetVolume()->IsActive())
2083 continue;
2084 if ((id < (ncheck - 1)) && node->IsOverlapping()) {
2085 // make the cluster of overlaps
2088 delete[] fOverlapClusters;
2090 }
2092 Int_t nc = GetTouchedCluster(id, &point[0], check_list, ncheck, cluster);
2093 if (nc > 1) {
2094 fOverlapMark += nc;
2095 node = FindInCluster(cluster, nc);
2096 fOverlapMark -= nc;
2098 return node;
2099 }
2100 }
2101 CdDown(check_list[id]);
2102 fForcedNode = nullptr;
2103 node = SearchNode(kTRUE);
2104 if (node) {
2107 return node;
2108 }
2109 CdUp();
2110 }
2111 if (!fCurrentNode->GetVolume()->IsAssembly()) {
2113 return fCurrentNode;
2114 }
2115 node = fCurrentNode;
2116 if (!fLevel) {
2117 fIsOutside = kTRUE;
2119 return nullptr;
2120 }
2121 CdUp();
2123 return SearchNode(kFALSE, node);
2124 }
2125 // if there are no voxels just loop all daughters
2126 for (id = 0; id < nd; id++) {
2127 node = fCurrentNode->GetDaughter(id);
2128 if (node == skipnode)
2129 continue;
2130 if (fGeometry->IsActivityEnabled() && !node->GetVolume()->IsActive())
2131 continue;
2132 CdDown(id);
2133 fForcedNode = nullptr;
2134 node = SearchNode(kTRUE);
2135 if (node) {
2137 return node;
2138 }
2139 CdUp();
2140 }
2141 // point is not inside one of the daughters, so it is in the current vol
2142 if (fCurrentNode->GetVolume()->IsAssembly()) {
2143 node = fCurrentNode;
2144 if (!fLevel) {
2145 fIsOutside = kTRUE;
2146 return nullptr;
2147 }
2148 CdUp();
2149 return SearchNode(kFALSE, node);
2150 }
2151 return fCurrentNode;
2152}
2153
2154////////////////////////////////////////////////////////////////////////////////
2155/// Find a node inside a cluster of overlapping nodes. Current node must
2156/// be on top of all the nodes in cluster. Always nc>1.
2157
2159{
2160 TGeoNode *clnode = nullptr;
2162 // save current node
2163 TGeoNode *current = fCurrentNode;
2164 TGeoNode *found = nullptr;
2165 // save path
2166 Int_t ipop = PushPath();
2167 // mark this search
2171 Int_t found_virtual = 0;
2172 Bool_t replace = kFALSE;
2174 Int_t i;
2175 for (i = 0; i < nc; i++) {
2176 clnode = current->GetDaughter(cluster[i]);
2177 CdDown(cluster[i]);
2179 found = SearchNode(kTRUE, clnode);
2180 if (!fSearchOverlaps || max_priority) {
2181 // an only was found during the search -> exiting
2182 // The node given by FindNextBoundary returned -> exiting
2183 PopDummy(ipop);
2184 return found;
2185 }
2187 if (added) {
2188 // we have put something in stack -> check it
2190 replace = kTRUE;
2191 } else {
2193 if (fLevel > deepest) {
2194 replace = kTRUE;
2195 } else {
2196 if ((fLevel == deepest) && (clnode == priority))
2197 replace = kTRUE;
2198 else
2199 replace = kFALSE;
2200 }
2201 } else
2202 replace = kFALSE;
2203 }
2204 // if this was the last checked node
2205 if (i == (nc - 1)) {
2206 if (replace) {
2207 PopDummy(ipop);
2208 return found;
2209 } else {
2211 PopDummy(ipop);
2212 return fCurrentNode;
2213 }
2214 }
2215 // we still have to go on
2216 if (replace) {
2217 // reset stack
2218 PopDummy();
2219 PushPath();
2220 deepest = fLevel;
2222 }
2223 // restore top of cluster
2225 } else {
2226 // the stack was clean, push new one
2227 PushPath();
2228 added = kTRUE;
2229 deepest = fLevel;
2231 // restore original path
2233 }
2234 }
2235 PopDummy(ipop);
2236 return fCurrentNode;
2237}
2238
2239////////////////////////////////////////////////////////////////////////////////
2240/// Make the cluster of overlapping nodes in a voxel, containing point in reference
2241/// of the mother. Returns number of nodes containing the point. Nodes should not be
2242/// offsets.
2243
2245{
2246 // we are in the mother reference system
2247 TGeoNode *current = fCurrentNode->GetDaughter(check_list[start]);
2248 Int_t novlps = 0;
2249 Int_t *ovlps = current->GetOverlaps(novlps);
2250 if (!ovlps)
2251 return 0;
2252 Double_t local[3];
2253 // intersect check list with overlap list
2254 Int_t ntotal = 0;
2255 current->MasterToLocal(point, &local[0]);
2256 if (current->GetVolume()->Contains(&local[0])) {
2257 result[ntotal++] = check_list[start];
2258 }
2259
2260 Int_t jst = 0, i, j;
2261 while ((jst < novlps) && (ovlps[jst] <= check_list[start]))
2262 jst++;
2263 if (jst == novlps)
2264 return 0;
2265 for (i = start; i < ncheck; i++) {
2266 for (j = jst; j < novlps; j++) {
2267 if (check_list[i] == ovlps[j]) {
2268 // overlapping node in voxel -> check if touched
2269 current = fCurrentNode->GetDaughter(check_list[i]);
2270 if (fGeometry->IsActivityEnabled() && !current->GetVolume()->IsActive())
2271 continue;
2272 current->MasterToLocal(point, &local[0]);
2273 if (current->GetVolume()->Contains(&local[0])) {
2274 result[ntotal++] = check_list[i];
2275 }
2276 }
2277 }
2278 }
2279 return ntotal;
2280}
2281
2282////////////////////////////////////////////////////////////////////////////////
2283/// Make a rectiliniar step of length fStep from current point (fPoint) on current
2284/// direction (fDirection). If the step is imposed by geometry, is_geom flag
2285/// must be true (default). The cross flag specifies if the boundary should be
2286/// crossed in case of a geometry step (default true). Returns new node after step.
2287/// Set also on boundary condition.
2288
2290{
2291 Double_t epsil = 0;
2292 if (fStep < 1E-6) {
2294 if (fStep < 0)
2295 fStep = 0.;
2296 } else {
2298 }
2299 if (is_geom)
2300 epsil = (cross) ? 1E-6 : -1E-6;
2301 TGeoNode *old = fCurrentNode;
2302 Int_t idold = GetNodeId();
2303 if (fIsOutside)
2304 old = nullptr;
2305 fStep += epsil;
2306 for (Int_t i = 0; i < 3; i++)
2307 fPoint[i] += fStep * fDirection[i];
2308 TGeoNode *current = FindNode();
2309 if (is_geom) {
2310 fIsEntering = (current == old) ? kFALSE : kTRUE;
2311 if (!fIsEntering) {
2312 Int_t id = GetNodeId();
2313 fIsEntering = (id == idold) ? kFALSE : kTRUE;
2314 }
2316 if (fIsEntering && fIsNullStep)
2319 } else {
2322 }
2323 return current;
2324}
2325
2326////////////////////////////////////////////////////////////////////////////////
2327/// Find level of virtuality of current overlapping node (number of levels
2328/// up having the same tracking media.
2329
2331{
2332 // return if the current node is ONLY
2334 return 0;
2335 Int_t new_media = 0;
2337 Int_t virtual_level = 1;
2338 TGeoNode *mother = nullptr;
2339
2340 while ((mother = GetMother(virtual_level))) {
2341 if (!mother->IsOverlapping() && !mother->IsOffset()) {
2342 if (!new_media)
2343 new_media = (mother->GetMedium() == medium) ? 0 : virtual_level;
2344 break;
2345 }
2346 if (!new_media)
2347 new_media = (mother->GetMedium() == medium) ? 0 : virtual_level;
2348 virtual_level++;
2349 }
2350 return (new_media == 0) ? virtual_level : (new_media - 1);
2351}
2352
2353////////////////////////////////////////////////////////////////////////////////
2354/// Go upwards the tree until a non-overlapping node
2355
2357{
2358 while (fCurrentOverlapping && fLevel)
2359 CdUp();
2360 Double_t point[3];
2362 if (!fCurrentNode->GetVolume()->Contains(point))
2363 return kFALSE;
2364 if (fNmany) {
2365 // We still have overlaps on the branch
2366 Int_t up = 1;
2367 Int_t imother;
2368 Int_t nmany = fNmany;
2369 Bool_t ovlp = kFALSE;
2371 TGeoNode *mother, *mup;
2373 while (nmany) {
2374 mother = GetMother(up);
2375 if (!mother)
2376 return kTRUE;
2377 mup = mother;
2378 imother = up + 1;
2379 while (mup->IsOffset())
2380 mup = GetMother(imother++);
2381 nextovlp = mup->IsOverlapping();
2382 if (ovlp)
2383 nmany--;
2384 if (ovlp || nextovlp) {
2385 // check if the point is in the next node up
2387 matrix->MasterToLocal(fPoint, point);
2388 if (!mother->GetVolume()->Contains(point)) {
2389 up++;
2390 while (up--)
2391 CdUp();
2392 return GotoSafeLevel();
2393 }
2394 }
2395 ovlp = nextovlp;
2396 up++;
2397 }
2398 }
2399 return kTRUE;
2400}
2401
2402////////////////////////////////////////////////////////////////////////////////
2403/// Go upwards the tree until a non-overlapping node
2404
2406{
2408 if (!overlapping)
2409 return fLevel;
2410 Int_t level = fLevel;
2411 TGeoNode *node;
2412 while (overlapping && level) {
2413 level--;
2414 node = GetMother(fLevel - level);
2415 if (!node->IsOffset())
2416 overlapping = node->IsOverlapping();
2417 }
2418 return level;
2419}
2420
2421////////////////////////////////////////////////////////////////////////////////
2422/// Inspects path and all flags for the current state.
2423
2425{
2426 Info("InspectState", "Current path is: %s", GetPath());
2427 Int_t level;
2428 TGeoNode *node;
2430 for (level = 0; level < fLevel + 1; level++) {
2431 node = GetMother(fLevel - level);
2432 if (!node)
2433 continue;
2434 is_offset = node->IsOffset();
2435 is_overlapping = node->IsOverlapping();
2436 Info("InspectState", "level %i: %s div=%i many=%i", level, node->GetName(), is_offset, is_overlapping);
2437 }
2438 Info("InspectState", "on_bound=%i entering=%i", fIsOnBoundary, fIsEntering);
2439}
2440
2441////////////////////////////////////////////////////////////////////////////////
2442/// Checks if point (x,y,z) is still in the current node.
2443/// check if this is an overlapping node
2444
2446{
2447 Double_t oldpt[3];
2448 if (fLastSafety > 0) {
2449 Double_t dx = (x - fLastPoint[0]);
2450 Double_t dy = (y - fLastPoint[1]);
2451 Double_t dz = (z - fLastPoint[2]);
2452 Double_t dsq = dx * dx + dy * dy + dz * dz;
2453 if (dsq < fLastSafety * fLastSafety) {
2454 if (change) {
2455 fPoint[0] = x;
2456 fPoint[1] = y;
2457 fPoint[2] = z;
2458 memcpy(fLastPoint, fPoint, 3 * sizeof(Double_t));
2460 }
2461 return kTRUE;
2462 }
2463 if (change)
2464 fLastSafety = 0;
2465 }
2466 if (fCurrentOverlapping) {
2467 // TGeoNode *current = fCurrentNode;
2469 if (!change)
2470 PushPoint();
2472 SetCurrentPoint(x, y, z);
2473 SearchNode();
2476 if (!change)
2477 PopPoint();
2478 return same;
2479 }
2480
2481 Double_t point[3];
2482 point[0] = x;
2483 point[1] = y;
2484 point[2] = z;
2485 if (change)
2486 memcpy(fPoint, point, kN3);
2488 if (fIsOutside) {
2489 if (vol->GetShape()->Contains(point)) {
2490 if (!change)
2491 return kFALSE;
2492 FindNode(x, y, z);
2493 return kFALSE;
2494 }
2495 return kTRUE;
2496 }
2497 Double_t local[3];
2498 // convert to local frame
2500 // check if still in current volume.
2501 if (!vol->GetShape()->Contains(local)) {
2502 if (!change)
2503 return kFALSE;
2504 CdUp();
2505 FindNode(x, y, z);
2506 return kFALSE;
2507 }
2508
2509 // Check if the point is in a parallel world volume
2512 if (pnode) {
2513 if (!change)
2514 return kFALSE;
2515 pnode->cd();
2517 while (crtindex >= 0) {
2518 // Make sure we did not end up in an assembly.
2521 }
2522 return kFALSE;
2523 }
2524 }
2525 // check if there are daughters
2526 Int_t nd = vol->GetNdaughters();
2527 if (!nd)
2528 return kTRUE;
2529
2530 TGeoNode *node;
2532 if (finder) {
2533 node = finder->FindNode(local);
2534 if (node) {
2535 if (!change)
2536 return kFALSE;
2537 CdDown(node->GetIndex());
2538 SearchNode(kTRUE, node);
2539 return kFALSE;
2540 }
2541 return kTRUE;
2542 }
2543 // if we are not allowed to do changes, save the current path
2545 Int_t *check_list = nullptr;
2546 Int_t ncheck = 0;
2547 Double_t local1[3];
2548 if (voxels) {
2549 check_list = voxels->GetCheckList(local, ncheck, *fCache->GetInfo());
2550 if (!check_list) {
2552 return kTRUE;
2553 }
2554 if (!change)
2555 PushPath();
2556 for (Int_t id = 0; id < ncheck; id++) {
2557 // node = vol->GetNode(check_list[id]);
2558 CdDown(check_list[id]);
2561 if (!change) {
2562 PopPath();
2564 return kFALSE;
2565 }
2568 return kFALSE;
2569 }
2570 CdUp();
2571 }
2572 if (!change)
2573 PopPath();
2575 return kTRUE;
2576 }
2577 Int_t id = 0;
2578 if (!change)
2579 PushPath();
2580 while (fCurrentNode && fCurrentNode->GetDaughter(id++)) {
2581 CdDown(id - 1);
2584 if (!change) {
2585 PopPath();
2586 return kFALSE;
2587 }
2589 return kFALSE;
2590 }
2591 CdUp();
2592 if (id == nd) {
2593 if (!change)
2594 PopPath();
2595 return kTRUE;
2596 }
2597 }
2598 if (!change)
2599 PopPath();
2600 return kTRUE;
2601}
2602
2603////////////////////////////////////////////////////////////////////////////////
2604/// In case a previous safety value was computed, check if the safety region is
2605/// still safe for the current point and proposed step. Return value changed only
2606/// if proposed distance is safe.
2607
2609{
2610 // Last safety not computed.
2611 if (fLastSafety < gTolerance)
2612 return kFALSE;
2613 // Proposed step too small
2614 if (proposed < gTolerance) {
2616 return kTRUE;
2617 }
2618 // Normal step
2619 Double_t dist = (fPoint[0] - fLastPoint[0]) * (fPoint[0] - fLastPoint[0]) +
2620 (fPoint[1] - fLastPoint[1]) * (fPoint[1] - fLastPoint[1]) +
2621 (fPoint[2] - fLastPoint[2]) * (fPoint[2] - fLastPoint[2]);
2622 dist = TMath::Sqrt(dist);
2623 Double_t safe = fLastSafety - dist;
2624 if (safe < proposed)
2625 return kFALSE;
2626 newsafety = safe;
2627 return kTRUE;
2628}
2629
2630////////////////////////////////////////////////////////////////////////////////
2631/// Check if a new point with given coordinates is the same as the last located one.
2632
2634{
2635 if (TMath::Abs(x - fLastPoint[0]) < 1.E-20) {
2636 if (TMath::Abs(y - fLastPoint[1]) < 1.E-20) {
2637 if (TMath::Abs(z - fLastPoint[2]) < 1.E-20)
2638 return kTRUE;
2639 }
2640 }
2641 return kFALSE;
2642}
2643
2644////////////////////////////////////////////////////////////////////////////////
2645/// Backup the current state without affecting the cache stack.
2646
2652
2653////////////////////////////////////////////////////////////////////////////////
2654/// Restore a backed-up state without affecting the cache stack.
2655
2665
2666////////////////////////////////////////////////////////////////////////////////
2667/// Return stored current matrix (global matrix of the next touched node).
2668
2677
2678////////////////////////////////////////////////////////////////////////////////
2679/// Get path to the current node in the form /node0/node1/...
2680
2681const char *TGeoNavigator::GetPath() const
2682{
2683 if (fIsOutside)
2684 return kGeoOutsidePath;
2685 return fCache->GetPath();
2686}
2687
2688////////////////////////////////////////////////////////////////////////////////
2689/// Convert coordinates from master volume frame to top.
2690
2695
2696////////////////////////////////////////////////////////////////////////////////
2697/// Convert coordinates from top volume frame to master.
2698
2703
2704////////////////////////////////////////////////////////////////////////////////
2705/// Reset the navigator.
2706
2708{
2709 GetHMatrix();
2712 ResetState();
2713 fStep = 0.;
2714 fSafety = 0.;
2715 fLastSafety = 0.;
2716 fLevel = 0;
2717 fNmany = 0;
2718 fNextDaughterIndex = -2;
2725 fLastNode = nullptr;
2726 fNextNode = nullptr;
2727 fPath = "";
2728 if (fCache) {
2729 Bool_t dummy = fCache->IsDummy();
2730 Bool_t nodeid = fCache->HasIdArray();
2731 delete fCache;
2732 fCache = nullptr;
2733 delete fBackupState;
2734 fBackupState = nullptr;
2735 BuildCache(dummy, nodeid);
2736 }
2737}
2738
2739
2740////////////////////////////////////////////////////////////////////////////////
2741/// Add a new navigator to the array.
2742
bool Bool_t
Boolean (0=false, 1=true) (bool)
Definition RtypesCore.h:77
int Int_t
Signed integer 4 bytes (int)
Definition RtypesCore.h:59
constexpr Bool_t kFALSE
Definition RtypesCore.h:108
double Double_t
Double 8 bytes.
Definition RtypesCore.h:73
constexpr Bool_t kTRUE
Definition RtypesCore.h:107
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h offset
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h length
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize id
char name[80]
Definition TGX11.cxx:110
const Int_t kN3
R__EXTERN TGeoIdentity * gGeoIdentity
Definition TGeoMatrix.h:537
const Int_t kN3
const char * kGeoOutsidePath
static Double_t gTolerance
virtual void SetOwner(Bool_t enable=kTRUE)
Set whether this collection is the owner (enable==true) of its content.
Class storing the state of the cache at a given moment.
Definition TGeoCache.h:28
void SetState(Int_t level, Int_t startlevel, Int_t nmany, Bool_t ovlp, Double_t *point=nullptr)
Fill current modeller state.
Matrix class used for computing global transformations Should NOT be used for node definition.
Definition TGeoMatrix.h:458
void CopyFrom(const TGeoMatrix *other)
Fast copy method.
const Double_t * GetTranslation() const override
Definition TGeoMatrix.h:527
void Multiply(const TGeoMatrix *right)
multiply to the right with an other transformation if right is identity matrix, just return
The manager class for any TGeo geometry.
Definition TGeoManager.h:45
TGeoNode * GetCurrentNode() const
TGeoParallelWorld * GetParallelWorld() const
Int_t GetMaxLevel() const
Bool_t IsParallelWorldNav() const
Bool_t IsActivityEnabled() const
TGeoNode * GetTopNode() const
static Int_t GetVerboseLevel()
Set verbosity level (static function).
void MasterToLocal(const Double_t *master, Double_t *local) const
TGeoVolume * GetTopVolume() const
static Int_t ThreadId()
Translates the current thread id to an ordinal number.
virtual void LocalToMasterVect(const Double_t *local, Double_t *master) const
convert a vector by multiplying its column vector (x, y, z, 1) to matrix inverse
virtual void MasterToLocal(const Double_t *master, Double_t *local) const
convert a point by multiplying its column vector (x, y, z, 1) to matrix
virtual void MasterToLocalVect(const Double_t *master, Double_t *local) const
convert a point by multiplying its column vector (x, y, z, 1) to matrix
virtual void RegisterYourself()
Register the matrix in the current manager, which will become the owner.
virtual void LocalToMaster(const Double_t *local, Double_t *master) const
convert a point by multiplying its column vector (x, y, z, 1) to matrix inverse
Media are used to store properties related to tracking and which are useful only when using geometry ...
Definition TGeoMedium.h:23
TGeoNavigator * AddNavigator()
Add a new navigator to the array.
TGeoManager * fGeoManager
TGeoNavigator * SetCurrentNavigator(Int_t inav)
Class providing navigation API for TGeo geometries.
void CdUp()
Go one level up in geometry.
void DoBackupState()
Backup the current state without affecting the cache stack.
TGeoNode * GetMother(Int_t up=1) const
Double_t fLastPWSaftyPnt[3]
last point for which safety was computed
void DoRestoreState()
Restore a backed-up state without affecting the cache stack.
Double_t fPoint[3]
unit vector to current checked shape
Bool_t fSearchOverlaps
internal array for overlaps
Bool_t fIsExiting
flag if current step just got into a new node
TString fPath
current local matrix of the selected division cell
TGeoHMatrix * fDivMatrix
current pointer to cached global matrix
TGeoNode * CrossBoundaryAndLocate(Bool_t downwards, TGeoNode *skipnode)
Cross next boundary and locate within current node The current point must be on the boundary of fCurr...
Double_t fLastPWSafety
last point for which parallel world safety was "evaluated"
TGeoHMatrix * GetHMatrix()
Return stored current matrix (global matrix of the next touched node).
TGeoNodeCache * fCache
current geometry
Bool_t fStartSafe
flags the type of the current node
void CdNext()
Do a cd to the node found next by FindNextBoundary.
Double_t Safety(Bool_t inside=kFALSE)
Compute safe distance from the current point.
Bool_t GotoSafeLevel()
Go upwards the tree until a non-overlapping node.
Double_t fNormal[3]
last computed safety radius
Bool_t cd(const char *path="")
Browse the tree of nodes starting from top node according to pathname.
Double_t fLastPoint[3]
current direction
Bool_t IsSameLocation() const
Double_t fCldir[3]
cosine of incident angle on current checked surface
Bool_t fIsStepEntering
flag that current track is about to leave current node
Int_t GetNodeId() const
Int_t GetVirtualLevel()
Find level of virtuality of current overlapping node (number of levels up having the same tracking me...
Bool_t PopPoint()
Int_t fOverlapSize
next daughter index after FindNextBoundary
TGeoNode * InitTrack(const Double_t *point, const Double_t *dir)
Initialize current point and current direction vector (normalized) in MARS.
void InspectState() const
Inspects path and all flags for the current state.
Int_t PushPoint(Int_t startlevel=0)
TGeoNode * Step(Bool_t is_geom=kTRUE, Bool_t cross=kTRUE)
Make a rectiliniar step of length fStep from current point (fPoint) on current direction (fDirection)...
TGeoNode * FindInCluster(Int_t *cluster, Int_t nc)
Find a node inside a cluster of overlapping nodes.
void SafetyOverlaps()
Compute safe distance from the current point within an overlapping node.
TGeoNode * CrossDivisionCell()
Cross a division cell.
void ResetState()
Reset current state flags.
static Bool_t IsPWSafetyCaching()
TGeoNode * FindNextDaughterBoundary(Double_t *point, Double_t *dir, Int_t &idaughter, Bool_t compmatrix=kFALSE)
Computes as fStep the distance to next daughter of the current volume.
Bool_t fIsSameLocation
flag that current point is on some boundary
void GetBranchNumbers(Int_t *copyNumbers, Int_t *volumeNumbers) const
Fill node copy numbers of current branch into an array.
Bool_t CheckPath(const char *path) const
Check if a geometry path is valid without changing the state of the navigator.
TGeoHMatrix * GetMotherMatrix(Int_t up=1) const
TGeoVolume * fCurrentVolume
cache of states
TGeoNode * fLastNode
top physical node
Int_t fThreadId
last safety returned from parallel world (negative if invalid)
Double_t GetPWSafetyEstimateFromCache(Double_t cpoint[3]) const
Double_t fDirection[3]
current point
void PopDummy(Int_t ipop=9999)
Int_t GetTouchedCluster(Int_t start, Double_t *point, Int_t *check_list, Int_t ncheck, Int_t *result)
Make the cluster of overlapping nodes in a voxel, containing point in reference of the mother.
TGeoNode * FindNextBoundary(Double_t stepmax=TGeoShape::Big(), const char *path="", Bool_t frombdr=kFALSE)
Find distance to next boundary and store it in fStep.
TGeoNode * FindNode(Bool_t safe_start=kTRUE)
Returns deepest node containing current point.
Int_t fOverlapMark
current size of fOverlapClusters
TGeoNode * FindNextBoundaryAndStep(Double_t stepmax=TGeoShape::Big(), Bool_t compsafe=kFALSE)
Compute distance to next boundary within STEPMAX.
void CdTop()
Make top level node the current node.
Int_t fNmany
current geometry level;
TGeoManager * fGeometry
flag that last geometric step was null
TGeoHMatrix * fGlobalMatrix
current stored global matrix
void MasterToTop(const Double_t *master, Double_t *top) const
Convert coordinates from master volume frame to top.
Int_t GetCurrentNodeId() const
Double_t * FindNormalFast()
Computes fast normal to next crossed boundary, assuming that the current point is close enough to the...
Int_t PushPath(Int_t startlevel=0)
Bool_t fIsStepExiting
flag that next geometric step will enter new volume
Bool_t fIsOnBoundary
flag that current point is outside geometry
static Bool_t fgUsePWSafetyCaching
path to current node
void GetBranchOnlys(Int_t *isonly) const
Fill node copy numbers of current branch into an array.
void TopToMaster(const Double_t *top, Double_t *master) const
Convert coordinates from top volume frame to master.
void SetCurrentPoint(const Double_t *point)
TGeoHMatrix * fCurrentMatrix
backup state
Int_t * fOverlapClusters
current recursive position in fOverlapClusters
Bool_t IsSafeStep(Double_t proposed, Double_t &newsafety) const
In case a previous safety value was computed, check if the safety region is still safe for the curren...
TGeoNode * SearchNode(Bool_t downwards=kFALSE, const TGeoNode *skipnode=nullptr)
Returns the deepest node containing fPoint, which must be set a priori.
Double_t fLastSafety
safety radius from current point
~TGeoNavigator() override
Destructor.
TGeoNavigator()
global mode is caching enabled for parallel world safety calls
void SetCurrentDirection(const Double_t *dir)
void BuildCache(Bool_t dummy=kFALSE, Bool_t nodeid=kFALSE)
Builds the cache for physical nodes and global matrices.
Int_t fNextDaughterIndex
number of overlapping nodes on current branch
Bool_t fIsNullStep
flag that a new point is in the same node as previous
void CdNode(Int_t nodeid)
Change current path to point to the node having this id.
TGeoNode * fNextNode
last searched node
Double_t fCldirChecked[3]
unit vector to current closest shape
Int_t fLevel
thread id for this navigator
Double_t GetPWSafety(Double_t cpoint[3], Double_t saf_max)
Wrapper for getting the safety from the parallel world.
void ResetAll()
Reset the navigator.
TGeoCacheState * fBackupState
current point is supposed to be inside this node
Bool_t IsSamePoint(Double_t x, Double_t y, Double_t z) const
Check if a new point with given coordinates is the same as the last located one.
Bool_t fCurrentOverlapping
flag set when an overlapping cluster is searched
Bool_t fIsOutside
flag that next geometric step will exit current volume
void CdDown(Int_t index)
Make a daughter of current node current.
Bool_t fIsEntering
flag a safe start for point classification
TGeoNode * fForcedNode
next node that will be crossed
const char * GetPath() const
Get path to the current node in the form /node0/node1/...
Int_t GetSafeLevel() const
Go upwards the tree until a non-overlapping node.
TGeoNode * fCurrentNode
current volume
Double_t fSafety
step to be done from current point and direction
Double_t * FindNormal(Bool_t forward=kTRUE)
Computes normal vector to the next surface that will be or was already crossed when propagating on a ...
void GetBranchNames(Int_t *names) const
Fill volume names of current branch into an array.
Special pool of reusable nodes.
Definition TGeoCache.h:56
Bool_t IsDummy() const
Definition TGeoCache.h:126
TGeoNode * GetNode() const
Definition TGeoCache.h:116
void CdNode(Int_t nodeid)
Change current path to point to the node having this id.
void CdTop()
Definition TGeoCache.h:92
void GetBranchOnlys(Int_t *isonly) const
Fill copy numbers of current branch nodes.
const char * GetPath()
Returns the current geometry path.
void GetBranchNumbers(Int_t *copyNumbers, Int_t *volumeNumbers) const
Fill copy numbers of current branch nodes.
TGeoStateInfo * GetInfo()
Get next state info pointer.
Bool_t HasIdArray() const
Definition TGeoCache.h:125
Bool_t CdDown(Int_t index)
Make daughter INDEX of current node the active state. Compute global matrix.
Bool_t RestoreState(Int_t &nmany, TGeoCacheState *state, Double_t *point=nullptr)
Pop next state/point from a backed-up state.
void CdUp()
Make mother of current node the active state.
void GetBranchNames(Int_t *names) const
Fill names with current branch volume names (4 char - used by GEANT3 interface).
TGeoHMatrix * GetCurrentMatrix() const
Definition TGeoCache.h:109
void ReleaseInfo()
Release last used state info pointer.
Int_t GetLevel() const
Definition TGeoCache.h:121
A node represent a volume positioned inside another.They store links to both volumes and to the TGeoM...
Definition TGeoNode.h:39
TGeoMedium * GetMedium() const
Definition TGeoNode.h:89
Bool_t IsOverlapping() const
Definition TGeoNode.h:107
TGeoVolume * GetVolume() const
Definition TGeoNode.h:99
Bool_t IsOffset() const
Definition TGeoNode.h:105
Int_t GetNdaughters() const
Definition TGeoNode.h:91
TGeoNode * GetDaughter(Int_t ind) const
Definition TGeoNode.h:83
virtual TGeoMatrix * GetMatrix() const =0
virtual void cd() const
Definition TGeoNode.h:71
Int_t * GetOverlaps(Int_t &novlp) const
Definition TGeoNode.h:94
virtual void MasterToLocal(const Double_t *master, Double_t *local) const
Convert the point coordinates from mother reference to local reference system.
Definition TGeoNode.cxx:568
virtual Int_t GetIndex() const
Definition TGeoNode.h:87
virtual TGeoPatternFinder * GetFinder() const
Definition TGeoNode.h:88
virtual void MasterToLocalVect(const Double_t *master, Double_t *local) const
Convert a vector from mother reference to local reference system.
Definition TGeoNode.cxx:576
Double_t Safety(const Double_t *point, Bool_t in=kTRUE) const
computes the closest distance from given point to this shape
Definition TGeoNode.cxx:684
Double_t Safety(Double_t point[3], Double_t safmax=1.E30)
TGeoPhysicalNode * FindNextBoundary(Double_t point[3], Double_t dir[3], Double_t &step, Double_t stepmax=1.E30)
TGeoPhysicalNode * FindNode(Double_t point[3])
base finder class for patterns. A pattern is specifying a division type
Physical nodes are the actual 'touchable' objects in the geometry, representing a path of positioned ...
static Double_t Big()
Definition TGeoShape.h:94
virtual Double_t DistFromInside(const Double_t *point, const Double_t *dir, Int_t iact=1, Double_t step=TGeoShape::Big(), Double_t *safe=nullptr) const =0
virtual Double_t Safety(const Double_t *point, Bool_t in=kTRUE) const =0
virtual void ComputeNormal(const Double_t *point, const Double_t *dir, Double_t *norm) const =0
virtual Double_t DistFromOutside(const Double_t *point, const Double_t *dir, Int_t iact=1, Double_t step=TGeoShape::Big(), Double_t *safe=nullptr) const =0
virtual Bool_t Contains(const Double_t *point) const =0
static Double_t Tolerance()
Definition TGeoShape.h:97
Volume assemblies.
Definition TGeoVolume.h:316
TGeoVolume, TGeoVolumeMulti, TGeoVolumeAssembly are the volume classes.
Definition TGeoVolume.h:43
virtual Int_t GetNextNodeIndex() const
Definition TGeoVolume.h:168
Bool_t IsActiveDaughters() const
Definition TGeoVolume.h:146
Bool_t Contains(const Double_t *point) const
Definition TGeoVolume.h:104
Int_t GetNdaughters() const
Definition TGeoVolume.h:362
TObjArray * GetNodes()
Definition TGeoVolume.h:169
void FindOverlaps() const
loop all nodes marked as overlaps and find overlapping brothers
TGeoNode * GetNode(const char *name) const
get the pointer to a daughter node
Int_t GetIndex(const TGeoNode *node) const
get index number for a given daughter
TGeoPatternFinder * GetFinder() const
Definition TGeoVolume.h:177
TGeoVoxelFinder * GetVoxels() const
Getter for optimization structure.
TGeoShape * GetShape() const
Definition TGeoVolume.h:190
virtual Int_t GetCurrentNodeIndex() const
Definition TGeoVolume.h:167
virtual Bool_t IsAssembly() const
Returns true if the volume is an assembly or a scaled assembly.
Bool_t IsActive() const
Definition TGeoVolume.h:145
Finder class handling voxels.
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
An array of TObjects.
Definition TObjArray.h:31
Int_t GetEntriesFast() const
Definition TObjArray.h:58
TObject * UncheckedAt(Int_t i) const
Definition TObjArray.h:84
void Add(TObject *obj) override
Definition TObjArray.h:68
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition TObject.cxx:226
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1071
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
Definition TObject.cxx:1099
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition TObject.cxx:1045
Basic string class.
Definition TString.h:138
Double_t y[n]
Definition legend1.C:17
Double_t x[n]
Definition legend1.C:17
Double_t Sqrt(Double_t x)
Returns the square root of x.
Definition TMath.h:673
Short_t Min(Short_t a, Short_t b)
Returns the smallest of a and b.
Definition TMathBase.h:199
Short_t Abs(Short_t d)
Returns the absolute value of parameter Short_t d.
Definition TMathBase.h:124
Statefull info for the current geometry level.