Logo ROOT  
Reference Guide
Loading...
Searching...
No Matches
TGeoVolume.cxx
Go to the documentation of this file.
1// @(#)root/geom:$Id$
2// Author: Andrei Gheata 30/05/02
3// Divide(), CheckOverlaps() implemented by Mihaela Gheata
4
5/*************************************************************************
6 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
7 * All rights reserved. *
8 * *
9 * For the licensing terms see $ROOTSYS/LICENSE. *
10 * For the list of contributors see $ROOTSYS/README/CREDITS. *
11 *************************************************************************/
12
13/** \class TGeoVolume
14\ingroup Shapes_classes
15
16TGeoVolume, TGeoVolumeMulti, TGeoVolumeAssembly are the volume classes
17
18 Volumes are the basic objects used in building the geometrical hierarchy.
19They represent unpositioned objects but store all information about the
20placement of the other volumes they may contain. Therefore a volume can
21be replicated several times in the geometry. In order to create a volume, one
22has to put together a shape and a medium which are already defined. Volumes
23have to be named by users at creation time. Every different name may represent a
24an unique volume object, but may also represent more general a family (class)
25of volume objects having the same shape type and medium, but possibly
26different shape parameters. It is the user's task to provide different names
27for different volume families in order to avoid ambiguities at tracking time.
28A generic family rather than a single volume is created only in two cases :
29when a generic shape is provided to the volume constructor or when a division
30operation is applied. Each volume in the geometry stores an unique
31ID corresponding to its family. In order to ease-up their creation, the manager
32class is providing an API that allows making a shape and a volume in a single step.
33
34 Volumes are objects that can be visualized, therefore having visibility,
35colour, line and fill attributes that can be defined or modified any time after
36the volume creation. It is advisable however to define these properties just
37after the first creation of a volume namespace, since in case of volume families
38any new member created by the modeler inherits these properties.
39
40 In order to provide navigation features, volumes have to be able to find
41the proper container of any point defined in the local reference frame. This
42can be the volume itself, one of its positioned daughter volumes or none if
43the point is actually outside. On the other hand, volumes have to provide also
44other navigation methods such as finding the distances to its shape boundaries
45or which daughter will be crossed first. The implementation of these features
46is done at shape level, but the local mother-daughters management is handled
47by volumes that builds additional optimisation structures upon geometry closure.
48In order to have navigation features properly working one has to follow the
49general rules for building a valid geometry (see TGeoManager class).
50
51 Now let's make a simple volume representing a copper wire. We suppose that
52a medium is already created (see TGeoMedium class on how to create media).
53We will create a TUBE shape for our wire, having Rmin=0cm, Rmax=0.01cm
54and a half-length dZ=1cm :
55
56~~~ {.cpp}
57 TGeoTube *tube = new TGeoTube("wire_tube", 0, 0.01, 1);
58~~~
59
60One may omit the name for the shape if no retrieving by name is further needed
61during geometry building. The same shape can be shared by different volumes
62having different names and materials. Now let's make the volume for our wire.
63The prototype for volumes constructor looks like :
64
65 TGeoVolume::TGeoVolume(const char *name, TGeoShape *shape, TGeoMedium *med)
66
67Since TGeoTube derives from the base shape class, we can provide it to the volume
68constructor :
69
70~~~ {.cpp}
71 TGeoVolume *wire_co = new TGeoVolume("WIRE_CO", tube, ptrCOPPER);
72~~~
73
74Do not bother to delete neither the media, shapes or volumes that you have
75created since all will be automatically cleaned on exit by the manager class.
76If we would have taken a look inside TGeoManager::MakeTube() method, we would
77have been able to create our wire with a single line :
78
79~~~ {.cpp}
80 TGeoVolume *wire_co = gGeoManager->MakeTube("WIRE_CO", ptrCOPPER, 0, 0.01, 1);
81~~~
82
83The same applies for all primitive shapes, for which there can be found
84corresponding MakeSHAPE() methods. Their usage is much more convenient unless
85a shape has to be shared between more volumes. Let's make now an aluminium wire
86having the same shape, supposing that we have created the copper wire with the
87line above :
88
89~~~ {.cpp}
90 TGeoVolume *wire_al = new TGeoVolume("WIRE_AL", wire_co->GetShape(), ptrAL);
91~~~
92
93Now that we have learned how to create elementary volumes, let's see how we
94can create a geometrical hierarchy.
95
96
97### Positioning volumes
98
99 When creating a volume one does not specify if this will contain or not other
100volumes. Adding daughters to a volume implies creating those and adding them
101one by one to the list of daughters. Since the volume has to know the position
102of all its daughters, we will have to supply at the same time a geometrical
103transformation with respect to its local reference frame for each of them.
104The objects referencing a volume and a transformation are called NODES and
105their creation is fully handled by the modeler. They represent the link
106elements in the hierarchy of volumes. Nodes are unique and distinct geometrical
107objects ONLY from their container point of view. Since volumes can be replicated
108in the geometry, the same node may be found on different branches.
109
110\image html geom_t_example.png width=600px
111
112 An important observation is that volume objects are owned by the TGeoManager
113class. This stores a list of all volumes in the geometry, that is cleaned
114upon destruction.
115
116 Let's consider positioning now our wire in the middle of a gas chamber. We
117need first to define the gas chamber :
118
119~~~ {.cpp}
120 TGeoVolume *chamber = gGeoManager->MakeTube("CHAMBER", ptrGAS, 0, 1, 1);
121~~~
122
123Now we can put the wire inside :
124
125~~~ {.cpp}
126 chamber->AddNode(wire_co, 1);
127~~~
128
129If we inspect now the chamber volume in a browser, we will notice that it has
130one daughter. Of course the gas has some container also, but let's keep it like
131that for the sake of simplicity. The full prototype of AddNode() is :
132
133~~~ {.cpp}
134 TGeoVolume::AddNode(TGeoVolume *daughter, Int_t usernumber,
135 TGeoMatrix *matrix=gGeoIdentity)
136~~~
137
138Since we did not supplied the third argument, the wire will be positioned with
139an identity transformation inside the chamber. One will notice that the inner
140radii of the wire and chamber are both zero - therefore, aren't the two volumes
141overlapping ? The answer is no, the modeler is even relaying on the fact that
142any daughter is fully contained by its mother. On the other hand, neither of
143the nodes positioned inside a volume should overlap with each other. We will
144see that there are allowed some exceptions to those rules.
145
146### Overlapping volumes
147
148 Positioning volumes that does not overlap their neighbours nor extrude
149their container is sometimes quite strong constraint. Some parts of the geometry
150might overlap naturally, e.g. two crossing tubes. The modeller supports such
151cases only if the overlapping nodes are declared by the user. In order to do
152that, one should use TGeoVolume::AddNodeOverlap() instead of TGeoVolume::AddNode().
153 When 2 or more positioned volumes are overlapping, not all of them have to
154be declared so, but at least one. A point inside an overlapping region equally
155belongs to all overlapping nodes, but the way these are defined can enforce
156the modeler to give priorities.
157 The general rule is that the deepest node in the hierarchy containing a point
158have the highest priority. For the same geometry level, non-overlapping is
159prioritised over overlapping. In order to illustrate this, we will consider
160few examples. We will designate non-overlapping nodes as ONLY and the others
161MANY as in GEANT3, where this concept was introduced:
162 1. The part of a MANY node B extruding its container A will never be "seen"
163during navigation, as if B was in fact the result of the intersection of A and B.
164 2. If we have two nodes A (ONLY) and B (MANY) inside the same container, all
165points in the overlapping region of A and B will be designated as belonging to A.
166 3. If A an B in the above case were both MANY, points in the overlapping
167part will be designated to the one defined first. Both nodes must have the
168same medium.
169 4. The slices of a divided MANY will be as well MANY.
170
171One needs to know that navigation inside geometry parts MANY nodes is much
172slower. Any overlapping part can be defined based on composite shapes - this
173is always recommended.
174
175### Replicating volumes
176
177 What can we do if our chamber contains two identical wires instead of one ?
178What if then we would need 1000 chambers in our detector ? Should we create
1792000 wires and 1000 chamber volumes ? No, we will just need to replicate the
180ones that we have already created.
181
182~~~ {.cpp}
183 chamber->AddNode(wire_co, 1, new TGeoTranslation(-0.2,0,0));
184 chamber->AddNode(wire_co, 2, new TGeoTranslation(0.2,0,0));
185~~~
186
187 The 2 nodes that we have created inside chamber will both point to a wire_co
188object, but will be completely distinct : WIRE_CO_1 and WIRE_CO_2. We will
189want now to place symmetrically 1000 chambers on a pad, following a pattern
190of 20 rows and 50 columns. One way to do this will be to replicate our chamber
191by positioning it 1000 times in different positions of the pad. Unfortunately,
192this is far from being the optimal way of doing what we want.
193Imagine that we would like to find out which of the 1000 chambers is containing
194a (x,y,z) point defined in the pad reference. You will never have to do that,
195since the modeller will take care of it for you, but let's guess what it has
196to do. The most simple algorithm will just loop over all daughters, convert
197the point from mother to local reference and check if the current chamber
198contains the point or not. This might be efficient for pads with few chambers,
199but definitely not for 1000. Fortunately the modeler is smarter than that and
200create for each volume some optimization structures called voxels (see Voxelization)
201to minimize the penalty having too many daughters, but if you have 100 pads like
202this in your geometry you will anyway loose a lot in your tracking performance.
203
204 The way out when volumes can be arranged according to simple patterns is the
205usage of divisions. We will describe them in detail later on. Let's think now
206at a different situation : instead of 1000 chambers of the same type, we may
207have several types of chambers. Let's say all chambers are cylindrical and have
208a wire inside, but their dimensions are different. However, we would like all
209to be represented by a single volume family, since they have the same properties.
210*/
211
212/** \class TGeoVolumeMulti
213\ingroup Geometry_classes
214
215Volume families
216
217A volume family is represented by the class TGeoVolumeMulti. It represents
218a class of volumes having the same shape type and each member will be
219identified by the same name and volume ID. Any operation applied to a
220TGeoVolume equally affects all volumes in that family. The creation of a
221family is generally not a user task, but can be forced in particular cases:
222
223~~~ {.cpp}
224 TGeoManager::Volume(const char *vname, const char *shape, Int_t nmed);
225~~~
226
227where VNAME is the family name, NMED is the medium number and SHAPE is the
228shape type that can be:
229
230~~~ {.cpp}
231 box - for TGeoBBox
232 trd1 - for TGeoTrd1
233 trd2 - for TGeoTrd2
234 trap - for TGeoTrap
235 gtra - for TGeoGtra
236 para - for TGeoPara
237 tube, tubs - for TGeoTube, TGeoTubeSeg
238 cone, cons - for TGeoCone, TgeoCons
239 eltu - for TGeoEltu
240 ctub - for TGeoCtub
241 pcon - for TGeoPcon
242 pgon - for TGeoPgon
243~~~
244
245Volumes are then added to a given family upon adding the generic name as node
246inside other volume:
247
248~~~ {.cpp}
249 TGeoVolume *box_family = gGeoManager->Volume("BOXES", "box", nmed);
250 ...
251 gGeoManager->Node("BOXES", Int_t copy_no, "mother_name",
252 Double_t x, Double_t y, Double_t z, Int_t rot_index,
253 Bool_t is_only, Double_t *upar, Int_t npar);
254~~~
255
256here:
257
258~~~ {.cpp}
259 BOXES - name of the family of boxes
260 copy_no - user node number for the created node
261 mother_name - name of the volume to which we want to add the node
262 x,y,z - translation components
263 rot_index - indx of a rotation matrix in the list of matrices
264 upar - array of actual shape parameters
265 npar - number of parameters
266~~~
267
268The parameters order and number are the same as in the corresponding shape
269constructors.
270
271 Another particular case where volume families are used is when we want
272that a volume positioned inside a container to match one ore more container
273limits. Suppose we want to position the same box inside 2 different volumes
274and we want the Z size to match the one of each container:
275
276~~~ {.cpp}
277 TGeoVolume *container1 = gGeoManager->MakeBox("C1", imed, 10,10,30);
278 TGeoVolume *container2 = gGeoManager->MakeBox("C2", imed, 10,10,20);
279 TGeoVolume *pvol = gGeoManager->MakeBox("PVOL", jmed, 3,3,-1);
280 container1->AddNode(pvol, 1);
281 container2->AddNode(pvol, 1);
282~~~
283
284 Note that the third parameter of PVOL is negative, which does not make sense
285as half-length on Z. This is interpreted as: when positioned, create a box
286replacing all invalid parameters with the corresponding dimensions of the
287container. This is also internally handled by the TGeoVolumeMulti class, which
288does not need to be instantiated by users.
289
290### Dividing volumes
291
292 Volumes can be divided according a pattern. The most simple division can
293be done along one axis, that can be: X, Y, Z, Phi, Rxy or Rxyz. Let's take
294the most simple case: we would like to divide a box in N equal slices along X
295coordinate, representing a new volume family. Supposing we already have created
296the initial box, this can be done like:
297
298~~~ {.cpp}
299 TGeoVolume *slicex = box->Divide("SLICEX", 1, N);
300~~~
301
302where SLICE is the name of the new family representing all slices and 1 is the
303slicing axis. The meaning of the axis index is the following: for all volumes
304having shapes like box, trd1, trd2, trap, gtra or para - 1,2,3 means X,Y,Z; for
305tube, tubs, cone, cons - 1 means Rxy, 2 means phi and 3 means Z; for pcon and
306pgon - 2 means phi and 3 means Z; for spheres 1 means R and 2 means phi.
307 In fact, the division operation has the same effect as positioning volumes
308in a given order inside the divided container - the advantage being that the
309navigation in such a structure is much faster. When a volume is divided, a
310volume family corresponding to the slices is created. In case all slices can
311be represented by a single shape, only one volume is added to the family and
312positioned N times inside the divided volume, otherwise, each slice will be
313represented by a distinct volume in the family.
314 Divisions can be also performed in a given range of one axis. For that, one
315have to specify also the starting coordinate value and the step:
316
317~~~ {.cpp}
318 TGeoVolume *slicex = box->Divide("SLICEX", 1, N, start, step);
319~~~
320
321A check is always done on the resulting division range : if not fitting into
322the container limits, an error message is posted. If we will browse the divided
323volume we will notice that it will contain N nodes starting with index 1 upto
324N. The first one has the lower X limit at START position, while the last one
325will have the upper X limit at START+N*STEP. The resulting slices cannot
326be positioned inside an other volume (they are by default positioned inside the
327divided one) but can be further divided and may contain other volumes:
328
329~~~ {.cpp}
330 TGeoVolume *slicey = slicex->Divide("SLICEY", 2, N1);
331 slicey->AddNode(other_vol, index, some_matrix);
332~~~
333
334 When doing that, we have to remember that SLICEY represents a family, therefore
335all members of the family will be divided on Y and the other volume will be
336added as node inside all.
337 In the example above all the resulting slices had the same shape as the
338divided volume (box). This is not always the case. For instance, dividing a
339volume with TUBE shape on PHI axis will create equal slices having TUBESEG
340shape. Other divisions can also create slices having shapes with different
341dimensions, e.g. the division of a TRD1 volume on Z.
342 When positioning volumes inside slices, one can do it using the generic
343volume family (e.g. slicey). This should be done as if the coordinate system
344of the generic slice was the same as the one of the divided volume. The generic
345slice in case of PHI division is centered with respect to X axis. If the
346family contains slices of different sizes, any volume positioned inside should
347fit into the smallest one.
348 Examples for specific divisions according to shape types can be found inside
349shape classes.
350
351~~~ {.cpp}
352 TGeoVolume::Divide(N, Xmin, Xmax, "X");
353~~~
354
355 The GEANT3 option MANY is supported by TGeoVolumeOverlap class. An overlapping
356volume is in fact a virtual container that does not represent a physical object.
357It contains a list of nodes that are not its daughters but that must be checked
358always before the container itself. This list must be defined by users and it
359is checked and resolved in a priority order. Note that the feature is non-standard
360to geometrical modelers and it was introduced just to support conversions of
361GEANT3 geometries, therefore its extensive usage should be avoided.
362*/
363
364/** \class TGeoVolumeAssembly
365\ingroup Geometry_classes
366
367Volume assemblies
368
369Assemblies a volumes that have neither a shape or a material/medium. Assemblies
370behave exactly like normal volumes grouping several daughters together, but
371the daughters can never extrude the assembly since this has no shape. However,
372a bounding box and a voxelization structure are built for assemblies as for
373normal volumes, so that navigation is still optimized. Assemblies are useful
374for grouping hierarchically volumes which are otherwise defined in a flat
375manner, but also to avoid clashes between container shapes.
376To define an assembly one should just input a name, then start adding other
377volumes (or volume assemblies) as content.
378*/
379
380#include <fstream>
381#include <iomanip>
382
383#include <TString.h>
384#include <TBuffer.h>
385#include <TBrowser.h>
386#include <TStyle.h>
387#include <TH2F.h>
388#include <TROOT.h>
389#include <TEnv.h>
390#include <TMap.h>
391#include <TFile.h>
392#include <TKey.h>
393#ifdef R__USE_IMT
395#endif
396#include <TStopwatch.h>
397
398#include "TGeoManager.h"
399#include "TGeoNode.h"
400#include "TGeoMatrix.h"
401#include "TVirtualGeoPainter.h"
402#include "TVirtualGeoChecker.h"
403#include "TGeoVolume.h"
404#include "TGeoShapeAssembly.h"
405#include "TGeoScaledShape.h"
406#include "TGeoCompositeShape.h"
407#include "TGeoVoxelFinder.h"
408#include "TGeoExtension.h"
409
411
412////////////////////////////////////////////////////////////////////////////////
413/// Create a dummy medium
414
416{
417 if (fgDummyMedium)
418 return;
420 fgDummyMedium->SetName("dummy");
421 TGeoMaterial *dummyMaterial = new TGeoMaterial();
422 dummyMaterial->SetName("dummy");
423 fgDummyMedium->SetMaterial(dummyMaterial);
424}
425
426////////////////////////////////////////////////////////////////////////////////
427
429{
430 if (fFinder)
431 fFinder->ClearThreadData();
432 if (fShape)
433 fShape->ClearThreadData();
434}
435
436////////////////////////////////////////////////////////////////////////////////
437
439{
440 if (fFinder)
441 fFinder->CreateThreadData(nthreads);
442 if (fShape)
443 fShape->CreateThreadData(nthreads);
444}
445
446////////////////////////////////////////////////////////////////////////////////
447
452
453////////////////////////////////////////////////////////////////////////////////
454/// dummy constructor
455
457{
458 fNodes = nullptr;
459 fShape = nullptr;
460 fMedium = nullptr;
461 fFinder = nullptr;
462 fVoxels = nullptr;
464 fField = nullptr;
465 fOption = "";
466 fNumber = 0;
467 fNtotal = 0;
468 fRefCount = 0;
469 fUserExtension = nullptr;
470 fFWExtension = nullptr;
471 fTransparency = -1;
473}
474
475////////////////////////////////////////////////////////////////////////////////
476/// default constructor
477
478TGeoVolume::TGeoVolume(const char *name, const TGeoShape *shape, const TGeoMedium *med) : TNamed(name, "")
479{
480 fName = fName.Strip();
481 fNodes = nullptr;
482 fShape = (TGeoShape *)shape;
483 if (fShape) {
484 if (fShape->TestShapeBit(TGeoShape::kGeoBad)) {
485 Warning("Ctor", "volume %s has invalid shape", name);
486 }
487 if (!fShape->IsValid()) {
488 Fatal("ctor", "Shape of volume %s invalid. Aborting!", fName.Data());
489 }
490 }
491 fMedium = (TGeoMedium *)med;
492 if (fMedium && fMedium->GetMaterial())
493 fMedium->GetMaterial()->SetUsed();
494 fFinder = nullptr;
495 fVoxels = nullptr;
497 fField = nullptr;
498 fOption = "";
499 fNumber = 0;
500 fNtotal = 0;
501 fRefCount = 0;
502 fUserExtension = nullptr;
503 fFWExtension = nullptr;
504 fTransparency = -1;
506 fNumber = fGeoManager->AddVolume(this);
508}
509
510////////////////////////////////////////////////////////////////////////////////
511/// Destructor
512
514{
515 if (fNodes) {
517 fNodes->Delete();
518 }
519 delete fNodes;
520 }
522 delete fFinder;
523 if (fVoxels)
524 delete fVoxels;
525 if (fUserExtension) {
526 fUserExtension->Release();
527 fUserExtension = nullptr;
528 }
529 if (fFWExtension) {
530 fFWExtension->Release();
531 fFWExtension = nullptr;
532 }
533}
534
535////////////////////////////////////////////////////////////////////////////////
536/// How to browse a volume
537
539{
540 if (!b)
541 return;
542
543 // if (!GetNdaughters()) b->Add(this, GetName(), IsVisible());
544 TGeoVolume *daughter;
545 TString title;
546 for (Int_t i = 0; i < GetNdaughters(); i++) {
547 daughter = GetNode(i)->GetVolume();
548 if (daughter->GetTitle()[0]) {
549 if (daughter->IsAssembly())
550 title.TString::Format("Assembly with %d daughter(s)", daughter->GetNdaughters());
551 else if (daughter->GetFinder()) {
552 TString s1 = daughter->GetFinder()->ClassName();
553 s1.ReplaceAll("TGeoPattern", "");
554 title.TString::Format("Volume having %s shape divided in %d %s slices", daughter->GetShape()->ClassName(),
555 daughter->GetNdaughters(), s1.Data());
556
557 } else
558 title.TString::Format("Volume with %s shape having %d daughter(s)", daughter->GetShape()->ClassName(),
559 daughter->GetNdaughters());
560 daughter->SetTitle(title.Data());
561 }
562 b->Add(daughter, daughter->GetName(), daughter->IsVisible());
563 // if (IsVisDaughters())
564 // b->AddCheckBox(daughter, daughter->IsVisible());
565 // else
566 // b->AddCheckBox(daughter, kFALSE);
567 }
568}
569
570////////////////////////////////////////////////////////////////////////////////
571/// Computes the capacity of this [cm^3] as the capacity of its shape.
572/// In case of assemblies, the capacity is computed as the sum of daughter's capacities.
573
575{
576 if (!IsAssembly())
577 return fShape->Capacity();
578 Double_t capacity = 0.0;
579 Int_t nd = GetNdaughters();
580 Int_t i;
581 for (i = 0; i < nd; i++)
582 capacity += GetNode(i)->GetVolume()->Capacity();
583 return capacity;
584}
585
586////////////////////////////////////////////////////////////////////////////////
587/// Shoot nrays with random directions from starting point (startx, starty, startz)
588/// in the reference frame of this volume. Track each ray until exiting geometry, then
589/// shoot backwards from exiting point and compare boundary crossing points.
590
591void TGeoVolume::CheckGeometry(Int_t nrays, Double_t startx, Double_t starty, Double_t startz) const
592{
593 TGeoVolume *old_vol = fGeoManager->GetTopVolume();
594 if (old_vol != this)
595 fGeoManager->SetTopVolume((TGeoVolume *)this);
596 else
597 old_vol = nullptr;
598 fGeoManager->GetTopVolume()->Draw();
599 auto checker = fGeoManager->GetGeomChecker();
600 checker->CheckGeometry(nrays, startx, starty, startz);
601}
602
603////////////////////////////////////////////////////////////////////////////////
604/// Overlap checking tool. Check for illegal overlaps within a limit OVLP.
605
607{
608 TString opt(option);
609 opt.ToLower();
610 if (opt.Contains("s")) {
611 Info("CheckOverlaps", "Option 's' deprecated. Use CheckOverlapsBySampling() instead.");
612 return;
613 }
614
615 TStopwatch timer;
616 timer.Start();
617 auto geom = fGeoManager;
618 geom->ClearOverlaps();
619 geom->SetCheckingOverlaps(kTRUE);
620
621 Info("CheckOverlaps", "Checking overlaps for %s and daughters within %g", GetName(), ovlp);
622
623 auto checker = geom->GetGeomChecker();
624
625 // -------- Stage 1: enumerate candidates (main thread)
626 std::vector<TGeoOverlapCandidate> candidates;
627 candidates.reserve(2048);
628
629 Int_t ncand = checker->EnumerateOverlapCandidates(this, ovlp, option, candidates);
630 TGeoIterator next((TGeoVolume *)this);
631 TGeoNode *node = nullptr;
632 while ((node = next())) {
633 if (!node->GetVolume()->IsSelected()) {
634 node->GetVolume()->SelectVolume(kFALSE);
635 ncand += checker->EnumerateOverlapCandidates(node->GetVolume(), ovlp, option, candidates);
636 }
637 }
638 timer.Stop();
639 Info("CheckOverlaps", "--- found %d candidates in %g [sec]", ncand, timer.RealTime());
640
641 Info("CheckOverlaps", "--- filling points to be checked...");
642 timer.Start();
643 checker->BuildMeshPointsCache(candidates);
644 timer.Stop();
645 Info("CheckOverlaps", "--- points filled in: %g [sec]", timer.RealTime());
647
648 // -------- Stage 2: compute (parallel)
649 std::vector<TGeoOverlapResult> results;
650 results.reserve(256);
651
652#ifdef R__USE_IMT
653 // parallelized version
654 const size_t chunkSize = 1024; // tune: 256..4096
655 auto makeChunks = [&](size_t n) {
656 std::vector<std::pair<size_t, size_t>> chunks;
657 chunks.reserve((n + chunkSize - 1) / chunkSize);
658 for (size_t b = 0; b < n; b += chunkSize)
659 chunks.emplace_back(b, std::min(n, b + chunkSize));
660 return chunks;
661 };
662
663 auto chunks = makeChunks(candidates.size());
664 std::mutex resultsMutex;
665
666 // Policy: if ROOT IMT is enabled, follow the number of threads defined via:
667 // ROOT::EnableImplicitMT()
669 auto nthreads = pool.GetPoolSize();
671 Info("CheckOverlaps", "--- checking candidates with %u threads (use ROOT::EnableImplicitMT(N) to change)...",
672 nthreads);
673 else
674 Info("CheckOverlaps", "--- checking candidates with %u threads...", nthreads);
675
676 // Make sure TGeoManager MT mode follows, otherwise TGeo is thread unsafe
677 if (nthreads > 1)
678 geom->SetMaxThreads(nthreads);
679
680 timer.Start();
681 pool.Foreach(
682 [&](const std::pair<size_t, size_t> &range) {
683 // one-time init per OS thread
684 static thread_local bool navInit = false;
685 if (!navInit) {
686 if (!geom->GetCurrentNavigator())
687 geom->AddNavigator();
688 navInit = true;
689 }
690
691 std::vector<TGeoOverlapResult> local;
692 local.reserve(32);
693
694 for (size_t i = range.first; i < range.second; ++i) {
696 if (checker->ComputeOverlap(candidates[i], r))
697 local.emplace_back(std::move(r));
698 }
699
700 if (!local.empty()) {
701 std::lock_guard<std::mutex> lock(resultsMutex);
702 results.insert(results.end(), std::make_move_iterator(local.begin()), std::make_move_iterator(local.end()));
703 }
704 },
705 chunks);
706#else
707 // serial version
708 Info("CheckOverlaps", "--- checking candidates with on a single thread (IMT not configured)...");
709 timer.Start();
710 for (size_t i = 0; i < candidates.size(); ++i) {
712 if (checker->ComputeOverlap(candidates[i], r))
713 results.emplace_back(std::move(r));
714 }
715#endif
716
717 // -------- Stage 3: materialize overlaps (main thread)
718 for (const auto &r : results)
719 checker->MaterializeOverlap(r);
720
721 geom->SetCheckingOverlaps(kFALSE);
722 geom->SortOverlaps();
723
724 // Rename overlaps as before
725 TObjArray *overlaps = geom->GetListOfOverlaps();
726 const Int_t novlps = overlaps->GetEntriesFast();
727 for (Int_t i = 0; i < novlps; i++)
728 ((TNamed *)overlaps->At(i))->SetName(TString::Format("ov%05d", i));
729
730 timer.Stop();
731 Info("CheckOverlaps", "Number of illegal overlaps/extrusions : %d found in %g [sec]", novlps, timer.RealTime());
732}
733
734////////////////////////////////////////////////////////////////////////////////
735/// Overlap by sampling legacy checking tool. Check for illegal overlaps within a limit OVLP.
736
738{
739 if (!GetNdaughters() || fFinder)
740 return;
741 auto checker = fGeoManager->GetGeomChecker();
742 if (!fGeoManager->IsCheckingOverlaps()) {
743 fGeoManager->ClearOverlaps();
744 Info("CheckOverlaps", "[LEGACY] Checking overlaps by sampling %d points for volume %s", npoints, GetName());
745 Info("CheckOverlaps", "=== NOTE: Many overlaps may be missed. Extrusions NOT checked with sampling option ! ===");
746 }
747
748 checker->CheckOverlapsBySampling(this, ovlp, npoints);
749
750 if (!fGeoManager->IsCheckingOverlaps()) {
751 fGeoManager->SortOverlaps();
752 TObjArray *overlaps = fGeoManager->GetListOfOverlaps();
753 Int_t novlps = overlaps->GetEntriesFast();
754 TNamed *obj;
756 for (Int_t i = 0; i < novlps; i++) {
757 obj = (TNamed *)overlaps->At(i);
758 if (novlps < 1000)
759 name = TString::Format("ov%03d", i);
760 else
761 name = TString::Format("ov%06d", i);
762 obj->SetName(name);
763 }
764 Info("CheckOverlaps", "Number of illegal overlaps/extrusions sampled for volume %s: %d\n", GetName(), novlps);
765 }
766}
767
768////////////////////////////////////////////////////////////////////////////////
769/// Tests for checking the shape navigation algorithms. See TGeoShape::CheckShape()
770
771void TGeoVolume::CheckShape(Int_t testNo, Int_t nsamples, Option_t *option)
772{
773 fShape->CheckShape(testNo, nsamples, option);
774}
775
776////////////////////////////////////////////////////////////////////////////////
777/// Clean data of the volume.
778
780{
781 ClearNodes();
782 ClearShape();
783}
784
785////////////////////////////////////////////////////////////////////////////////
786/// Clear the shape of this volume from the list held by the current manager.
787
789{
790 fGeoManager->ClearShape(fShape);
791}
792
793////////////////////////////////////////////////////////////////////////////////
794/// check for negative parameters in shapes.
795
797{
798 if (fShape->IsRunTimeShape()) {
799 Error("CheckShapes", "volume %s has run-time shape", GetName());
800 InspectShape();
801 return;
802 }
803 if (!fNodes)
804 return;
805 Int_t nd = fNodes->GetEntriesFast();
806 TGeoNode *node = nullptr;
807 TGeoNode *new_node;
808 const TGeoShape *shape = nullptr;
809 TGeoVolume *old_vol;
810 for (Int_t i = 0; i < nd; i++) {
811 node = (TGeoNode *)fNodes->At(i);
812 // check if node has name
813 if (!node->GetName()[0])
814 printf("Daughter %i of volume %s - NO NAME!!!\n", i, GetName());
815 old_vol = node->GetVolume();
816 shape = old_vol->GetShape();
817 if (shape->IsRunTimeShape()) {
818 // printf(" Node %s/%s has shape with negative parameters. \n",
819 // GetName(), node->GetName());
820 // old_vol->InspectShape();
821 // make a copy of the node
822 new_node = node->MakeCopyNode();
823 if (!new_node) {
824 Fatal("CheckShapes", "Cannot make copy node for %s", node->GetName());
825 return;
826 }
827 TGeoShape *new_shape = shape->GetMakeRuntimeShape(fShape, node->GetMatrix());
828 if (!new_shape) {
829 Error("CheckShapes", "cannot resolve runtime shape for volume %s/%s\n", GetName(), old_vol->GetName());
830 continue;
831 }
832 TGeoVolume *new_volume = old_vol->MakeCopyVolume(new_shape);
833 // printf(" new volume %s shape params :\n", new_volume->GetName());
834 // new_volume->InspectShape();
835 new_node->SetVolume(new_volume);
836 // decouple the old node and put the new one instead
837 fNodes->AddAt(new_node, i);
838 // new_volume->CheckShapes();
839 }
840 }
841}
842
843////////////////////////////////////////////////////////////////////////////////
844/// Count total number of subnodes starting from this volume, nlevels down
845/// - option = 0 (default) - count only once per volume
846/// - option = 1 - count every time
847/// - option = 2 - count volumes on visible branches
848/// - option = 3 - return maximum level counted already with option = 0
849
851{
852 static Int_t maxlevel = 0;
853 static Int_t nlev = 0;
854
855 if (option < 0 || option > 3)
856 option = 0;
857 Int_t visopt = 0;
858 Int_t nd = GetNdaughters();
859 Bool_t last = (!nlevels || !nd) ? kTRUE : kFALSE;
860 switch (option) {
861 case 0:
862 if (fNtotal)
863 return fNtotal;
864 case 1: fNtotal = 1; break;
865 case 2:
866 visopt = fGeoManager->GetVisOption();
867 if (!IsVisDaughters())
868 last = kTRUE;
869 switch (visopt) {
870 case TVirtualGeoPainter::kGeoVisDefault: fNtotal = (IsVisible()) ? 1 : 0; break;
871 case TVirtualGeoPainter::kGeoVisLeaves: fNtotal = (IsVisible() && last) ? 1 : 0;
872 }
873 if (!IsVisibleDaughters())
874 return fNtotal;
875 break;
876 case 3: return maxlevel;
877 }
878 if (last)
879 return fNtotal;
880 if (gGeoManager->GetTopVolume() == this) {
881 maxlevel = 0;
882 nlev = 0;
883 }
884 if (nlev > maxlevel)
885 maxlevel = nlev;
886 TGeoNode *node;
887 TGeoVolume *vol;
888 nlev++;
889 for (Int_t i = 0; i < nd; i++) {
890 node = GetNode(i);
891 vol = node->GetVolume();
892 fNtotal += vol->CountNodes(nlevels - 1, option);
893 }
894 nlev--;
895 return fNtotal;
896}
897
898////////////////////////////////////////////////////////////////////////////////
899/// Return TRUE if volume and all daughters are invisible.
900
902{
903 if (IsVisible())
904 return kFALSE;
905 Int_t nd = GetNdaughters();
906 for (Int_t i = 0; i < nd; i++)
907 if (GetNode(i)->GetVolume()->IsVisible())
908 return kFALSE;
909 return kTRUE;
910}
911
912////////////////////////////////////////////////////////////////////////////////
913/// Make volume and each of it daughters (in)visible.
914
916{
917 SetAttVisibility(!flag);
918 Int_t nd = GetNdaughters();
919 TObjArray *list = new TObjArray(nd + 1);
920 list->Add(this);
921 TGeoVolume *vol;
922 for (Int_t i = 0; i < nd; i++) {
923 vol = GetNode(i)->GetVolume();
924 vol->SetAttVisibility(!flag);
925 list->Add(vol);
926 }
927 TIter next(gROOT->GetListOfBrowsers());
928 TBrowser *browser = nullptr;
929 while ((browser = (TBrowser *)next())) {
930 for (Int_t i = 0; i < nd + 1; i++) {
931 vol = (TGeoVolume *)list->At(i);
932 browser->CheckObjectItem(vol, !flag);
933 }
934 browser->Refresh();
935 }
936 delete list;
937 fGeoManager->SetVisOption(4);
938}
939
940////////////////////////////////////////////////////////////////////////////////
941/// Return TRUE if volume contains nodes
942
944{
945 return kTRUE;
946}
947
948////////////////////////////////////////////////////////////////////////////////
949/// check if the visibility and attributes are the default ones
950
952{
953 if (!IsVisible())
954 return kFALSE;
955 if (GetLineColor() != gStyle->GetLineColor())
956 return kFALSE;
957 if (GetLineStyle() != gStyle->GetLineStyle())
958 return kFALSE;
959 if (GetLineWidth() != gStyle->GetLineWidth())
960 return kFALSE;
961 return kTRUE;
962}
963
964////////////////////////////////////////////////////////////////////////////////
965/// True if this is the top volume of the geometry
966
968{
969 if (fGeoManager->GetTopVolume() == this)
970 return kTRUE;
971 return kFALSE;
972}
973
974////////////////////////////////////////////////////////////////////////////////
975/// Check if the painter is currently ray-tracing the content of this volume.
976
981
982////////////////////////////////////////////////////////////////////////////////
983/// Inspect the material for this volume.
984
986{
987 GetMaterial()->Print();
988}
989
990////////////////////////////////////////////////////////////////////////////////
991/// Import a volume from a file.
992
993TGeoVolume *TGeoVolume::Import(const char *filename, const char *name, Option_t * /*option*/)
994{
995 if (!gGeoManager)
996 gGeoManager = new TGeoManager("geometry", "");
997 if (!filename)
998 return nullptr;
999 TGeoVolume *volume = nullptr;
1000 if (strstr(filename, ".gdml")) {
1001 // import from a gdml file
1002 } else {
1003 // import from a root file
1005 TFile *f = TFile::Open(filename);
1006 if (!f || f->IsZombie()) {
1007 printf("Error: TGeoVolume::Import : Cannot open file %s\n", filename);
1008 return nullptr;
1009 }
1010 if (name && name[0]) {
1011 volume = (TGeoVolume *)f->Get(name);
1012 } else {
1013 TIter next(f->GetListOfKeys());
1014 TKey *key;
1015 while ((key = (TKey *)next())) {
1016 if (strcmp(key->GetClassName(), "TGeoVolume") != 0)
1017 continue;
1018 volume = (TGeoVolume *)key->ReadObj();
1019 break;
1020 }
1021 }
1022 delete f;
1023 }
1024 if (!volume)
1025 return nullptr;
1026 volume->RegisterYourself();
1027 return volume;
1028}
1029
1030////////////////////////////////////////////////////////////////////////////////
1031/// Export this volume to a file.
1032///
1033/// - Case 1: root file or root/xml file
1034/// if filename end with ".root". The key will be named name
1035/// if filename end with ".xml" a root/xml file is produced.
1036///
1037/// - Case 2: C++ script
1038/// if filename end with ".C"
1039///
1040/// - Case 3: gdml file
1041/// if filename end with ".gdml"
1042///
1043/// NOTE that to use this option, the PYTHONPATH must be defined like
1044/// export PYTHONPATH=$ROOTSYS/lib:$ROOTSYS/gdml
1045///
1046
1047Int_t TGeoVolume::Export(const char *filename, const char *name, Option_t *option)
1048{
1049 TString sfile(filename);
1050 if (sfile.Contains(".C")) {
1051 // Save volume as a C++ script
1052 Info("Export", "Exporting volume %s as C++ code", GetName());
1053 SaveAs(filename, "");
1054 return 1;
1055 }
1056 if (sfile.Contains(".gdml")) {
1057 // Save geometry as a gdml file
1058 Info("Export", "Exporting %s as gdml code - not implemented yet", GetName());
1059 return 0;
1060 }
1061 if (sfile.Contains(".root") || sfile.Contains(".xml")) {
1062 // Save volume in a root file
1063 Info("Export", "Exporting %s as root file.", GetName());
1064 TString opt(option);
1065 if (!opt.Length())
1066 opt = "recreate";
1067 TFile *f = TFile::Open(filename, opt.Data());
1068 if (!f || f->IsZombie()) {
1069 Error("Export", "Cannot open file");
1070 return 0;
1071 }
1072 TString keyname(name);
1073 if (keyname.IsNull())
1074 keyname = GetName();
1075 Int_t nbytes = Write(keyname);
1076 delete f;
1077 return nbytes;
1078 }
1079 return 0;
1080}
1081
1082////////////////////////////////////////////////////////////////////////////////
1083/// Actualize matrix of node indexed `<inode>`
1084
1085void TGeoVolume::cd(Int_t inode) const
1086{
1087 if (fFinder)
1088 fFinder->cd(inode - fFinder->GetDivIndex());
1089}
1090
1091////////////////////////////////////////////////////////////////////////////////
1092/// Add a TGeoNode to the list of nodes. This is the usual method for adding
1093/// daughters inside the container volume.
1094
1096{
1097 TGeoMatrix *matrix = mat;
1098 if (matrix == nullptr)
1099 matrix = gGeoIdentity;
1100 else
1101 matrix->RegisterYourself();
1102 if (!vol) {
1103 Error("AddNode", "Volume is NULL");
1104 return nullptr;
1105 }
1106 if (!vol->IsValid()) {
1107 Error("AddNode", "Won't add node with invalid shape");
1108 printf("### invalid volume was : %s\n", vol->GetName());
1109 return nullptr;
1110 }
1111 if (!fNodes)
1112 fNodes = new TObjArray();
1113
1114 if (fFinder) {
1115 // volume already divided.
1116 Error("AddNode", "Cannot add node %s_%i into divided volume %s", vol->GetName(), copy_no, GetName());
1117 return nullptr;
1118 }
1119
1120 TGeoNodeMatrix *node = nullptr;
1121 node = new TGeoNodeMatrix(vol, matrix);
1122 node->SetMotherVolume(this);
1123 fNodes->Add(node);
1124 TString name = TString::Format("%s_%d", vol->GetName(), copy_no);
1125 // if (fNodes->FindObject(name))
1126 // Warning("AddNode", "Volume %s : added node %s with same name", GetName(), name.Data());
1127 node->SetName(name);
1128 node->SetNumber(copy_no);
1129 fRefCount++;
1130 vol->Grab();
1131 return node;
1132}
1133
1134////////////////////////////////////////////////////////////////////////////////
1135/// Add a division node to the list of nodes. The method is called by
1136/// TGeoVolume::Divide() for creating the division nodes.
1137
1138void TGeoVolume::AddNodeOffset(TGeoVolume *vol, Int_t copy_no, Double_t offset, Option_t * /*option*/)
1139{
1140 if (!vol) {
1141 Error("AddNodeOffset", "invalid volume");
1142 return;
1143 }
1144 if (!vol->IsValid()) {
1145 Error("AddNode", "Won't add node with invalid shape");
1146 printf("### invalid volume was : %s\n", vol->GetName());
1147 return;
1148 }
1149 if (!fNodes)
1150 fNodes = new TObjArray();
1151 TGeoNode *node = new TGeoNodeOffset(vol, copy_no, offset);
1152 node->SetMotherVolume(this);
1153 fNodes->Add(node);
1154 TString name = TString::Format("%s_%d", vol->GetName(), copy_no + 1);
1155 node->SetName(name);
1156 node->SetNumber(copy_no + 1);
1157 vol->Grab();
1158}
1159
1160////////////////////////////////////////////////////////////////////////////////
1161/// Add a TGeoNode to the list of nodes. This is the usual method for adding
1162/// daughters inside the container volume.
1163
1165{
1166 if (!vol) {
1167 Error("AddNodeOverlap", "Volume is NULL");
1168 return;
1169 }
1170 if (!vol->IsValid()) {
1171 Error("AddNodeOverlap", "Won't add node with invalid shape");
1172 printf("### invalid volume was : %s\n", vol->GetName());
1173 return;
1174 }
1175 if (vol->IsAssembly()) {
1176 Warning("AddNodeOverlap",
1177 "Declaring assembly %s as possibly overlapping inside %s not allowed. Using AddNode instead !",
1178 vol->GetName(), GetName());
1179 AddNode(vol, copy_no, mat, option);
1180 return;
1181 }
1182 TGeoMatrix *matrix = mat;
1183 if (matrix == nullptr)
1184 matrix = gGeoIdentity;
1185 else
1186 matrix->RegisterYourself();
1187 if (!fNodes)
1188 fNodes = new TObjArray();
1189
1190 if (fFinder) {
1191 // volume already divided.
1192 Error("AddNodeOverlap", "Cannot add node %s_%i into divided volume %s", vol->GetName(), copy_no, GetName());
1193 return;
1194 }
1195
1196 TGeoNodeMatrix *node = new TGeoNodeMatrix(vol, matrix);
1197 node->SetMotherVolume(this);
1198 fNodes->Add(node);
1199 TString name = TString::Format("%s_%d", vol->GetName(), copy_no);
1200 if (fNodes->FindObject(name))
1201 Warning("AddNode", "Volume %s : added node %s with same name", GetName(), name.Data());
1202 node->SetName(name);
1203 node->SetNumber(copy_no);
1204 node->SetOverlapping();
1205 if (vol->GetMedium() == fMedium)
1206 node->SetVirtual();
1207 vol->Grab();
1208}
1209
1210////////////////////////////////////////////////////////////////////////////////
1211/// Division a la G3. The volume will be divided along IAXIS (see shape classes), in NDIV
1212/// slices, from START with given STEP. The division volumes will have medium number NUMED.
1213/// If NUMED=0 they will get the medium number of the divided volume (this). If NDIV<=0,
1214/// all range of IAXIS will be divided and the resulting number of divisions will be centered on
1215/// IAXIS. If STEP<=0, the real STEP will be computed as the full range of IAXIS divided by NDIV.
1216/// Options (case insensitive):
1217/// - N - divide all range in NDIV cells (same effect as STEP<=0) (GSDVN in G3)
1218/// - NX - divide range starting with START in NDIV cells (GSDVN2 in G3)
1219/// - S - divide all range with given STEP. NDIV is computed and divisions will be centered
1220/// in full range (same effect as NDIV<=0) (GSDVS, GSDVT in G3)
1221/// - SX - same as DVS, but from START position. (GSDVS2, GSDVT2 in G3)
1222
1223TGeoVolume *TGeoVolume::Divide(const char *divname, Int_t iaxis, Int_t ndiv, Double_t start, Double_t step, Int_t numed,
1224 Option_t *option)
1225{
1226 if (fFinder) {
1227 // volume already divided.
1228 Fatal("Divide", "volume %s already divided", GetName());
1229 return nullptr;
1230 }
1231 TString opt(option);
1232 opt.ToLower();
1233 TString stype = fShape->ClassName();
1234 if (!fNodes)
1235 fNodes = new TObjArray();
1236 Double_t xlo, xhi, range;
1237 range = fShape->GetAxisRange(iaxis, xlo, xhi);
1238 // for phi divisions correct the range
1239 if (!strcmp(fShape->GetAxisName(iaxis), "PHI")) {
1240 if ((start - xlo) < -1E-3)
1241 start += 360.;
1242 if (TGeoShape::IsSameWithinTolerance(range, 360)) {
1243 xlo = start;
1244 xhi = start + range;
1245 }
1246 }
1247 if (range <= 0) {
1248 InspectShape();
1249 Fatal("Divide", "cannot divide volume %s (%s) on %s axis", GetName(), stype.Data(), fShape->GetAxisName(iaxis));
1250 return nullptr;
1251 }
1252 if (ndiv <= 0 || opt.Contains("s")) {
1253 if (step <= 0) {
1254 Fatal("Divide", "invalid division type for volume %s : ndiv=%i, step=%g", GetName(), ndiv, step);
1255 return nullptr;
1256 }
1257 if (opt.Contains("x")) {
1258 if ((xlo - start) > 1E-3 || (xhi - start) < -1E-3) {
1259 Fatal("Divide", "invalid START=%g for division on axis %s of volume %s. Range is (%g, %g)", start,
1260 fShape->GetAxisName(iaxis), GetName(), xlo, xhi);
1261 return nullptr;
1262 }
1263 xlo = start;
1264 range = xhi - xlo;
1265 }
1266 ndiv = Int_t((range + 0.1 * step) / step);
1267 Double_t ddx = range - ndiv * step;
1268 // always center the division in this case
1269 if (ddx > 1E-3)
1270 Warning("Divide", "division of volume %s on %s axis (ndiv=%d) will be centered in the full range", GetName(),
1271 fShape->GetAxisName(iaxis), ndiv);
1272 start = xlo + 0.5 * ddx;
1273 }
1274 if (step <= 0 || opt.Contains("n")) {
1275 if (opt.Contains("x")) {
1276 if ((xlo - start) > 1E-3 || (xhi - start) < -1E-3) {
1277 Fatal("Divide", "invalid START=%g for division on axis %s of volume %s. Range is (%g, %g)", start,
1278 fShape->GetAxisName(iaxis), GetName(), xlo, xhi);
1279 return nullptr;
1280 }
1281 xlo = start;
1282 range = xhi - xlo;
1283 }
1284 step = range / ndiv;
1285 start = xlo;
1286 }
1287
1288 Double_t end = start + ndiv * step;
1289 if (((start - xlo) < -1E-3) || ((end - xhi) > 1E-3)) {
1290 Fatal("Divide", "division of volume %s on axis %s exceed range (%g, %g)", GetName(), fShape->GetAxisName(iaxis),
1291 xlo, xhi);
1292 return nullptr;
1293 }
1294 TGeoVolume *voldiv = fShape->Divide(this, divname, iaxis, ndiv, start, step);
1295 if (numed) {
1296 TGeoMedium *medium = fGeoManager->GetMedium(numed);
1297 if (!medium) {
1298 Fatal("Divide", "invalid medium number %d for division volume %s", numed, divname);
1299 return voldiv;
1300 }
1301 voldiv->SetMedium(medium);
1302 if (medium->GetMaterial())
1303 medium->GetMaterial()->SetUsed();
1304 }
1305 return voldiv;
1306}
1307
1308////////////////////////////////////////////////////////////////////////////////
1309/// compute the closest distance of approach from point px,py to this volume
1310
1312{
1313 if (gGeoManager != fGeoManager)
1315 TVirtualGeoPainter *painter = fGeoManager->GetPainter();
1316 Int_t dist = 9999;
1317 if (!painter)
1318 return dist;
1319 dist = painter->DistanceToPrimitiveVol(this, px, py);
1320 return dist;
1321}
1322
1323////////////////////////////////////////////////////////////////////////////////
1324/// draw top volume according to option
1325
1327{
1328 if (gGeoManager != fGeoManager)
1330 fGeoManager->SetUserPaintVolume(this);
1331 TVirtualGeoPainter *painter = fGeoManager->GetGeomPainter();
1333 if (!IsVisContainers())
1334 SetVisLeaves();
1335 if (option && option[0] > 0) {
1336 painter->DrawVolume(this, option);
1337 } else {
1338 painter->DrawVolume(this, gEnv->GetValue("Viewer3D.DefaultDrawOption", ""));
1339 }
1340}
1341
1342////////////////////////////////////////////////////////////////////////////////
1343/// draw only this volume
1344
1346{
1347 if (IsAssembly()) {
1348 Info("DrawOnly", "Volume assemblies do not support this option.");
1349 return;
1350 }
1351 if (gGeoManager != fGeoManager)
1353 SetVisOnly();
1355 TVirtualGeoPainter *painter = fGeoManager->GetGeomPainter();
1356 if (option && option[0] > 0) {
1357 painter->DrawVolume(this, option);
1358 } else {
1359 painter->DrawVolume(this, gEnv->GetValue("Viewer3D.DefaultDrawOption", ""));
1360 }
1361}
1362
1363////////////////////////////////////////////////////////////////////////////////
1364/// Perform an extensive sampling to find which type of voxelization is
1365/// most efficient.
1366
1368{
1369 printf("Optimizing volume %s ...\n", GetName());
1370 auto checker = fGeoManager->GetGeomChecker();
1371 return checker->TestVoxels(this);
1372}
1373
1374////////////////////////////////////////////////////////////////////////////////
1375/// Print volume info
1376
1378{
1379 printf("== Volume: %s type %s positioned %d times\n", GetName(), ClassName(), fRefCount);
1380 InspectShape();
1382}
1383
1384////////////////////////////////////////////////////////////////////////////////
1385/// paint volume
1386
1388{
1389 TVirtualGeoPainter *painter = fGeoManager->GetGeomPainter();
1390 painter->SetTopVolume(this);
1391 // painter->Paint(option);
1392 if (option && option[0] > 0) {
1393 painter->Paint(option);
1394 } else {
1395 painter->Paint(gEnv->GetValue("Viewer3D.DefaultDrawOption", ""));
1396 }
1397}
1398
1399////////////////////////////////////////////////////////////////////////////////
1400/// Print the voxels for this volume.
1401
1403{
1404 if (fVoxels)
1405 fVoxels->Print();
1406}
1407
1408////////////////////////////////////////////////////////////////////////////////
1409/// Recreate the content of the other volume without pointer copying. Voxels are
1410/// ignored and supposed to be created in a later step via Voxelize.
1411
1413{
1414 Int_t nd = other->GetNdaughters();
1415 if (!nd)
1416 return;
1417 TGeoPatternFinder *finder = other->GetFinder();
1418 if (finder) {
1419 Int_t iaxis = finder->GetDivAxis();
1420 Int_t ndiv = finder->GetNdiv();
1421 Double_t start = finder->GetStart();
1422 Double_t step = finder->GetStep();
1423 Int_t numed = other->GetNode(0)->GetVolume()->GetMedium()->GetId();
1424 TGeoVolume *voldiv = Divide(other->GetNode(0)->GetVolume()->GetName(), iaxis, ndiv, start, step, numed);
1425 voldiv->ReplayCreation(other->GetNode(0)->GetVolume());
1426 return;
1427 }
1428 for (Int_t i = 0; i < nd; i++) {
1429 TGeoNode *node = other->GetNode(i);
1430 if (node->IsOverlapping())
1431 AddNodeOverlap(node->GetVolume(), node->GetNumber(), node->GetMatrix());
1432 else
1433 AddNode(node->GetVolume(), node->GetNumber(), node->GetMatrix());
1434 }
1435}
1436
1437////////////////////////////////////////////////////////////////////////////////
1438/// print nodes
1439
1441{
1442 Int_t nd = GetNdaughters();
1443 for (Int_t i = 0; i < nd; i++) {
1444 printf("%s\n", GetNode(i)->GetName());
1445 cd(i);
1446 GetNode(i)->GetMatrix()->Print();
1447 }
1448}
1449////////////////////////////////////////////////////////////////////////////////
1450/// Generate a lego plot fot the top volume, according to option.
1451
1452TH2F *TGeoVolume::LegoPlot(Int_t ntheta, Double_t themin, Double_t themax, Int_t nphi, Double_t phimin, Double_t phimax,
1453 Double_t rmin, Double_t rmax, Option_t *option)
1454{
1455 auto checker = fGeoManager->GetGeomChecker();
1456 TGeoVolume *old_vol = fGeoManager->GetTopVolume();
1457 if (old_vol != this)
1458 fGeoManager->SetTopVolume(this);
1459 else
1460 old_vol = nullptr;
1461 TH2F *hist = checker->LegoPlot(ntheta, themin, themax, nphi, phimin, phimax, rmin, rmax, option);
1462 hist->Draw("lego1sph");
1463 return hist;
1464}
1465
1466////////////////////////////////////////////////////////////////////////////////
1467/// Register the volume and all materials/media/matrices/shapes to the manager.
1468
1470{
1471 if (fGeoManager->GetListOfVolumes()->FindObject(this))
1472 return;
1473 // Register volume
1474 fGeoManager->AddVolume(this);
1475 // Register shape
1476 if (!fGeoManager->GetListOfShapes()->FindObject(fShape)) {
1477 if (fShape->IsComposite()) {
1479 comp->RegisterYourself();
1480 } else {
1481 fGeoManager->AddShape(fShape);
1482 }
1483 }
1484 // Register medium/material
1485 if (fMedium && !fGeoManager->GetListOfMedia()->FindObject(fMedium)) {
1486 fGeoManager->GetListOfMedia()->Add(fMedium);
1487 if (!fGeoManager->GetListOfMaterials()->FindObject(fMedium->GetMaterial()))
1488 fGeoManager->AddMaterial(fMedium->GetMaterial());
1489 }
1490 // Register matrices for nodes.
1491 TGeoMatrix *matrix;
1492 TGeoNode *node;
1493 Int_t nd = GetNdaughters();
1494 Int_t i;
1495 for (i = 0; i < nd; i++) {
1496 node = GetNode(i);
1497 matrix = node->GetMatrix();
1498 if (!matrix->IsRegistered())
1499 matrix->RegisterYourself();
1500 else if (!fGeoManager->GetListOfMatrices()->FindObject(matrix)) {
1501 fGeoManager->GetListOfMatrices()->Add(matrix);
1502 }
1503 }
1504 // Call RegisterYourself recursively
1505 for (i = 0; i < nd; i++)
1506 GetNode(i)->GetVolume()->RegisterYourself(option);
1507}
1508
1509////////////////////////////////////////////////////////////////////////////////
1510/// Draw random points in the bounding box of this volume.
1511
1513{
1514 if (gGeoManager != fGeoManager)
1516 TGeoVolume *old_vol = fGeoManager->GetTopVolume();
1517 if (old_vol != this)
1518 fGeoManager->SetTopVolume(this);
1519 else
1520 old_vol = nullptr;
1521 fGeoManager->RandomPoints(this, npoints, option);
1522 if (old_vol)
1523 fGeoManager->SetTopVolume(old_vol);
1524}
1525
1526////////////////////////////////////////////////////////////////////////////////
1527/// Random raytracing method.
1528
1529void TGeoVolume::RandomRays(Int_t nrays, Double_t startx, Double_t starty, Double_t startz, const char *target_vol,
1530 Bool_t check_norm)
1531{
1532 if (gGeoManager != fGeoManager)
1534 TGeoVolume *old_vol = fGeoManager->GetTopVolume();
1535 if (old_vol != this)
1536 fGeoManager->SetTopVolume(this);
1537 else
1538 old_vol = nullptr;
1539 fGeoManager->RandomRays(nrays, startx, starty, startz, target_vol, check_norm);
1540 if (old_vol)
1541 fGeoManager->SetTopVolume(old_vol);
1542}
1543
1544////////////////////////////////////////////////////////////////////////////////
1545/// Draw this volume with current settings and perform raytracing in the pad.
1546
1548{
1550 if (gGeoManager != fGeoManager)
1552 TVirtualGeoPainter *painter = fGeoManager->GetGeomPainter();
1553 Bool_t drawn = (painter->GetDrawnVolume() == this) ? kTRUE : kFALSE;
1554 if (!drawn) {
1555 painter->DrawVolume(this, "");
1557 painter->ModifiedPad();
1558 return;
1559 }
1561 painter->ModifiedPad();
1562}
1563
1564////////////////////////////////////////////////////////////////////////////////
1565/// Save geometry having this as top volume as a C++ macro.
1566
1567void TGeoVolume::SaveAs(const char *filename, Option_t *option) const
1568{
1569 if (!filename)
1570 return;
1571 std::ofstream out;
1572 out.open(filename, std::ios::out);
1573 if (out.bad()) {
1574 Error("SavePrimitive", "Bad file name: %s", filename);
1575 return;
1576 }
1577 if (fGeoManager->GetTopVolume() != this)
1578 fGeoManager->SetTopVolume((TGeoVolume *)this);
1579
1580 TString fname(filename);
1581 Int_t ind = fname.Index(".");
1582 if (ind > 0)
1583 fname.Remove(ind);
1584 out << "void " << fname << "() {" << std::endl;
1585 out << " gSystem->Load(\"libGeom\");" << std::endl;
1587 out << std::setprecision(prec);
1588 ((TGeoVolume *)this)->SavePrimitive(out, option);
1589 out << "}" << std::endl;
1590}
1591
1592////////////////////////////////////////////////////////////////////////////////
1593/// Connect user-defined extension to the volume. The volume "grabs" a copy, so
1594/// the original object can be released by the producer. Release the previously
1595/// connected extension if any.
1596///
1597/// NOTE: This interface is intended for user extensions and is guaranteed not
1598/// to be used by TGeo
1599
1601{
1603 fUserExtension = nullptr;
1604 if (ext)
1605 fUserExtension = ext->Grab();
1606 if (tmp)
1607 tmp->Release();
1608}
1609
1610////////////////////////////////////////////////////////////////////////////////
1611/// Connect framework defined extension to the volume. The volume "grabs" a copy,
1612/// so the original object can be released by the producer. Release the previously
1613/// connected extension if any.
1614///
1615/// NOTE: This interface is intended for the use by TGeo and the users should
1616/// NOT connect extensions using this method
1617
1619{
1621 fFWExtension = nullptr;
1622 if (ext)
1623 fFWExtension = ext->Grab();
1624 if (tmp)
1625 tmp->Release();
1626}
1627
1628////////////////////////////////////////////////////////////////////////////////
1629/// Get a copy of the user extension pointer. The user must call Release() on
1630/// the copy pointer once this pointer is not needed anymore (equivalent to
1631/// delete() after calling new())
1632
1634{
1635 if (fUserExtension)
1636 return fUserExtension->Grab();
1637 return nullptr;
1638}
1639
1640////////////////////////////////////////////////////////////////////////////////
1641/// Get a copy of the framework extension pointer. The user must call Release() on
1642/// the copy pointer once this pointer is not needed anymore (equivalent to
1643/// delete() after calling new())
1644
1646{
1647 if (fFWExtension)
1648 return fFWExtension->Grab();
1649 return nullptr;
1650}
1651
1652////////////////////////////////////////////////////////////////////////////////
1653/// Save a primitive as a C++ statement(s) on output stream "out".
1654
1655void TGeoVolume::SavePrimitive(std::ostream &out, Option_t *option /*= ""*/)
1656{
1657 Int_t i, icopy;
1658 Int_t nd = GetNdaughters();
1659 TGeoVolume *dvol;
1660 TGeoNode *dnode;
1661 TGeoMatrix *matrix;
1662
1663 // check if we need to save shape/volume
1664 Bool_t mustDraw = kFALSE;
1665 if (fGeoManager->GetGeomPainter()->GetTopVolume() == this)
1666 mustDraw = kTRUE;
1667 if (!option[0]) {
1668 fGeoManager->SetAllIndex();
1669 out << " new TGeoManager(\"" << fGeoManager->GetName() << "\", \"" << fGeoManager->GetTitle() << "\");"
1670 << std::endl
1671 << std::endl;
1672 // if (mustDraw) out << " Bool_t mustDraw = kTRUE;" << std::endl;
1673 // else out << " Bool_t mustDraw = kFALSE;" << std::endl;
1674 out << " Double_t dx, dy, dz;" << std::endl;
1675 out << " Double_t dx1, dx2, dy1, dy2;" << std::endl;
1676 out << " Double_t vert[20], par[20];" << std::endl;
1677 out << " Double_t theta, phi, h1, bl1, tl1, alpha1, h2, bl2, tl2, alpha2;" << std::endl;
1678 out << " Double_t twist;" << std::endl;
1679 out << " Double_t origin[3];" << std::endl;
1680 out << " Double_t rmin, rmax, rmin1, rmax1, rmin2, rmax2;" << std::endl;
1681 out << " Double_t r, rlo, rhi;" << std::endl;
1682 out << " Double_t a, b;" << std::endl;
1683 out << " Double_t point[3], norm[3];" << std::endl;
1684 out << " Double_t rin, stin, rout, stout;" << std::endl;
1685 out << " Double_t thx, phx, thy, phy, thz, phz;" << std::endl;
1686 out << " Double_t alpha, theta1, theta2, phi1, phi2, dphi;" << std::endl;
1687 out << " Double_t tr[3], rot[9];" << std::endl;
1688 out << " Double_t z, density, radl, absl, w;" << std::endl;
1689 out << " Double_t lx, ly, lz, tx, ty, tz;" << std::endl;
1690 out << " Double_t xvert[50], yvert[50];" << std::endl;
1691 out << " Double_t zsect, x0, y0, scale0;" << std::endl;
1692 out << " Int_t nel, numed, nz, nedges, nvert;" << std::endl;
1693 out << " TGeoBoolNode *pBoolNode = nullptr;" << std::endl << std::endl;
1694 // first save materials/media
1695 out << " // MATERIALS, MIXTURES AND TRACKING MEDIA" << std::endl;
1696 SavePrimitive(out, "m");
1697 // then, save matrices
1698 out << std::endl << " // TRANSFORMATION MATRICES" << std::endl;
1699 SavePrimitive(out, "x");
1700 // save this volume and shape
1701 SavePrimitive(out, "s");
1702 out << std::endl << " // SET TOP VOLUME OF GEOMETRY" << std::endl;
1703 out << " gGeoManager->SetTopVolume(" << GetPointerName() << ");" << std::endl;
1704 // save daughters
1705 out << std::endl << " // SHAPES, VOLUMES AND GEOMETRICAL HIERARCHY" << std::endl;
1706 SavePrimitive(out, "d");
1707 out << std::endl << " // CLOSE GEOMETRY" << std::endl;
1708 out << " gGeoManager->CloseGeometry();" << std::endl;
1709 if (mustDraw) {
1710 if (!IsRaytracing())
1711 out << " gGeoManager->GetTopVolume()->Draw();" << std::endl;
1712 else
1713 out << " gGeoManager->GetTopVolume()->Raytrace();" << std::endl;
1714 }
1715 return;
1716 }
1717 // check if we need to save shape/volume
1718 if (!strcmp(option, "s")) {
1719 // create the shape for this volume
1721 return;
1722 if (!IsAssembly()) {
1723 fShape->SavePrimitive(out, option);
1724 out << " // Volume: " << GetName() << std::endl;
1725 out << " TGeoVolume *" << GetPointerName() << " = new TGeoVolume(\"" << GetName() << "\","
1726 << fShape->GetPointerName();
1727 if (fMedium)
1728 out << ", " << fMedium->GetPointerName();
1729 out << ");" << std::endl;
1730 } else {
1731 out << " // Assembly: " << GetName() << std::endl;
1732 out << " " << GetPointerName() << " = new TGeoVolumeAssembly(\"" << GetName() << "\""
1733 << ");" << std::endl;
1734 }
1735 SaveLineAttributes(out, GetPointerName(), 1, 1, 1);
1736 if (!IsVisible() && !IsAssembly())
1737 out << " " << GetPointerName() << "->SetVisibility(kFALSE);" << std::endl;
1738 if (!IsVisibleDaughters())
1739 out << " " << GetPointerName() << "->VisibleDaughters(kFALSE);" << std::endl;
1740 if (IsVisContainers())
1741 out << " " << GetPointerName() << "->SetVisContainers(kTRUE);" << std::endl;
1742 if (IsVisLeaves())
1743 out << " " << GetPointerName() << "->SetVisLeaves(kTRUE);" << std::endl;
1745 }
1746 // check if we need to save the media
1747 if (!strcmp(option, "m")) {
1748 if (fMedium)
1749 fMedium->SavePrimitive(out, option);
1750 for (i = 0; i < nd; i++) {
1751 dvol = GetNode(i)->GetVolume();
1752 dvol->SavePrimitive(out, option);
1753 }
1754 return;
1755 }
1756 // check if we need to save the matrices
1757 if (!strcmp(option, "x")) {
1758 if (fFinder) {
1759 dvol = GetNode(0)->GetVolume();
1760 dvol->SavePrimitive(out, option);
1761 return;
1762 }
1763 for (i = 0; i < nd; i++) {
1764 dnode = GetNode(i);
1765 matrix = dnode->GetMatrix();
1766 if (!matrix->IsIdentity())
1767 matrix->SavePrimitive(out, option);
1768 dnode->GetVolume()->SavePrimitive(out, option);
1769 }
1770 return;
1771 }
1772 // check if we need to save volume daughters
1773 if (!strcmp(option, "d")) {
1774 if (!nd)
1775 return;
1777 return;
1779 if (fFinder) {
1780 // volume divided: generate volume->Divide()
1781 dnode = GetNode(0);
1782 dvol = dnode->GetVolume();
1783 out << " TGeoVolume *" << dvol->GetPointerName() << " = ";
1784 out << GetPointerName() << "->Divide(\"" << dvol->GetName() << "\", ";
1785 fFinder->SavePrimitive(out, option);
1786 if (fMedium != dvol->GetMedium())
1787 out << ", " << dvol->GetMedium()->GetId();
1788 out << ");" << std::endl;
1789 dvol->SavePrimitive(out, "d");
1790 return;
1791 }
1792 for (i = 0; i < nd; i++) {
1793 dnode = GetNode(i);
1794 dvol = dnode->GetVolume();
1795 dvol->SavePrimitive(out, "s");
1796 matrix = dnode->GetMatrix();
1797 icopy = dnode->GetNumber();
1798 // generate AddNode()
1799 out << " " << GetPointerName() << "->AddNode";
1800 if (dnode->IsOverlapping())
1801 out << "Overlap";
1802 out << "(" << dvol->GetPointerName() << ", " << icopy;
1803 if (!matrix->IsIdentity())
1804 out << ", " << matrix->GetPointerName();
1805 out << ");" << std::endl;
1806 }
1807 // Recursive loop to daughters
1808 for (i = 0; i < nd; i++) {
1809 dnode = GetNode(i);
1810 dvol = dnode->GetVolume();
1811 dvol->SavePrimitive(out, "d");
1812 }
1813 }
1814}
1815
1816////////////////////////////////////////////////////////////////////////////////
1817/// Reset SavePrimitive bits.
1818
1826
1827////////////////////////////////////////////////////////////////////////////////
1828/// Execute mouse actions on this volume.
1829
1831{
1832 TVirtualGeoPainter *painter = fGeoManager->GetPainter();
1833 if (!painter)
1834 return;
1835 painter->ExecuteVolumeEvent(this, event, px, py);
1836}
1837
1838////////////////////////////////////////////////////////////////////////////////
1839/// search a daughter inside the list of nodes
1840
1842{
1843 return ((TGeoNode *)fNodes->FindObject(name));
1844}
1845
1846////////////////////////////////////////////////////////////////////////////////
1847/// Get the index of a daughter within check_list by providing the node pointer.
1848
1849Int_t TGeoVolume::GetNodeIndex(const TGeoNode *node, Int_t *check_list, Int_t ncheck) const
1850{
1851 TGeoNode *current = nullptr;
1852 for (Int_t i = 0; i < ncheck; i++) {
1853 current = (TGeoNode *)fNodes->At(check_list[i]);
1854 if (current == node)
1855 return check_list[i];
1856 }
1857 return -1;
1858}
1859
1860////////////////////////////////////////////////////////////////////////////////
1861/// get index number for a given daughter
1862
1864{
1865 TGeoNode *current = nullptr;
1866 Int_t nd = GetNdaughters();
1867 if (!nd)
1868 return -1;
1869 for (Int_t i = 0; i < nd; i++) {
1870 current = (TGeoNode *)fNodes->At(i);
1871 if (current == node)
1872 return i;
1873 }
1874 return -1;
1875}
1876
1877////////////////////////////////////////////////////////////////////////////////
1878/// Get volume info for the browser.
1879
1881{
1882 TGeoVolume *vol = (TGeoVolume *)this;
1883 TVirtualGeoPainter *painter = fGeoManager->GetPainter();
1884 if (!painter)
1885 return nullptr;
1886 return (char *)painter->GetVolumeInfo(vol, px, py);
1887}
1888
1889////////////////////////////////////////////////////////////////////////////////
1890/// Returns true if cylindrical voxelization is optimal.
1891
1893{
1894 Int_t nd = GetNdaughters();
1895 if (!nd)
1896 return kFALSE;
1897 Int_t id;
1898 Int_t ncyl = 0;
1899 TGeoNode *node;
1900 for (id = 0; id < nd; id++) {
1901 node = (TGeoNode *)fNodes->At(id);
1902 ncyl += node->GetOptimalVoxels();
1903 }
1904 if (ncyl > (nd / 2))
1905 return kTRUE;
1906 return kFALSE;
1907}
1908
1909////////////////////////////////////////////////////////////////////////////////
1910/// Provide a pointer name containing uid.
1911
1913{
1914 static TString name;
1915 name.Form("p%s_%zx", GetName(), (size_t)this);
1916 return name.Data();
1917}
1918
1919////////////////////////////////////////////////////////////////////////////////
1920/// Getter for optimization structure.
1921
1923{
1924 if (fVoxels && !fVoxels->IsInvalid())
1925 return fVoxels;
1926 return nullptr;
1927}
1928
1929////////////////////////////////////////////////////////////////////////////////
1930/// Move perspective view focus to this volume
1931
1933{
1934 TVirtualGeoPainter *painter = fGeoManager->GetPainter();
1935 if (painter)
1936 painter->GrabFocus();
1937}
1938
1939////////////////////////////////////////////////////////////////////////////////
1940/// Returns true if the volume is an assembly or a scaled assembly.
1941
1943{
1944 return fShape->IsAssembly();
1945}
1946
1947////////////////////////////////////////////////////////////////////////////////
1948/// Clone this volume.
1949/// build a volume with same name, shape and medium
1950
1952{
1953 TGeoVolume *vol = new TGeoVolume(GetName(), fShape, fMedium);
1954 Int_t i;
1955 // copy volume attributes
1956 vol->SetTitle(GetTitle());
1957 vol->SetLineColor(GetLineColor());
1958 vol->SetLineStyle(GetLineStyle());
1959 vol->SetLineWidth(GetLineWidth());
1960 vol->SetFillColor(GetFillColor());
1961 vol->SetFillStyle(GetFillStyle());
1962 // copy other attributes
1963 Int_t nbits = 8 * sizeof(UInt_t);
1964 for (i = 0; i < nbits; i++)
1965 vol->SetAttBit(1 << i, TGeoAtt::TestAttBit(1 << i));
1966 for (i = 14; i < 24; i++)
1967 vol->SetBit(1 << i, TestBit(1 << i));
1968
1969 // copy field
1970 vol->SetField(fField);
1971 // Set bits
1972 for (i = 0; i < nbits; i++)
1973 vol->SetBit(1 << i, TObject::TestBit(1 << i));
1974 vol->SetBit(kVolumeClone);
1975 // copy nodes
1976 // CloneNodesAndConnect(vol);
1977 vol->MakeCopyNodes(this);
1978 // if volume is divided, copy finder
1979 vol->SetFinder(fFinder);
1980 // copy voxels
1981 TGeoVoxelFinder *voxels = nullptr;
1982 if (fVoxels) {
1983 voxels = new TGeoVoxelFinder(vol);
1984 vol->SetVoxelFinder(voxels);
1985 }
1986 // copy option, uid
1987 vol->SetOption(fOption);
1988 vol->SetNumber(fNumber);
1989 vol->SetNtotal(fNtotal);
1990 // copy extensions
1994 return vol;
1995}
1996
1997////////////////////////////////////////////////////////////////////////////////
1998/// Clone the array of nodes.
1999
2001{
2002 if (!fNodes)
2003 return;
2004 TGeoNode *node;
2005 Int_t nd = fNodes->GetEntriesFast();
2006 if (!nd)
2007 return;
2008 // create new list of nodes
2009 TObjArray *list = new TObjArray(nd);
2010 // attach it to new volume
2011 newmother->SetNodes(list);
2012 // ((TObject*)newmother)->SetBit(kVolumeImportNodes);
2013 for (Int_t i = 0; i < nd; i++) {
2014 // create copies of nodes and add them to list
2015 node = GetNode(i)->MakeCopyNode();
2016 if (!node) {
2017 Fatal("CloneNodesAndConnect", "cannot make copy node");
2018 return;
2019 }
2020 node->SetMotherVolume(newmother);
2021 list->Add(node);
2022 }
2023}
2024
2025////////////////////////////////////////////////////////////////////////////////
2026/// make a new list of nodes and copy all nodes of other volume inside
2027
2029{
2030 Int_t nd = other->GetNdaughters();
2031 if (!nd)
2032 return;
2033 if (fNodes) {
2035 fNodes->Delete();
2036 delete fNodes;
2037 }
2038 fNodes = new TObjArray();
2039 for (Int_t i = 0; i < nd; i++)
2040 fNodes->Add(other->GetNode(i));
2042}
2043
2044////////////////////////////////////////////////////////////////////////////////
2045/// make a copy of this volume
2046/// build a volume with same name, shape and medium
2047
2049{
2050 TGeoVolume *vol = new TGeoVolume(GetName(), newshape, fMedium);
2051 // copy volume attributes
2052 vol->SetVisibility(IsVisible());
2053 vol->SetLineColor(GetLineColor());
2054 vol->SetLineStyle(GetLineStyle());
2055 vol->SetLineWidth(GetLineWidth());
2056 vol->SetFillColor(GetFillColor());
2057 vol->SetFillStyle(GetFillStyle());
2058 // copy field
2059 vol->SetField(fField);
2060 // if divided, copy division object
2061 if (fFinder) {
2062 // Error("MakeCopyVolume", "volume %s divided", GetName());
2063 vol->SetFinder(fFinder);
2064 }
2065 // Copy extensions
2069 // ((TObject*)vol)->SetBit(kVolumeImportNodes);
2070 ((TObject *)vol)->SetBit(kVolumeClone);
2072 return vol;
2073}
2074
2075////////////////////////////////////////////////////////////////////////////////
2076/// Make a copy of this volume which is reflected with respect to XY plane.
2077
2079{
2080 static TMap map(100);
2081 if (!fGeoManager->IsClosed()) {
2082 Error("MakeReflectedVolume", "Geometry must be closed.");
2083 return nullptr;
2084 }
2085 TGeoVolume *vol = (TGeoVolume *)map.GetValue(this);
2086 if (vol) {
2087 if (newname && newname[0])
2088 vol->SetName(newname);
2089 return vol;
2090 }
2091 // printf("Making reflection for volume: %s\n", GetName());
2092 vol = CloneVolume();
2093 if (!vol) {
2094 Fatal("MakeReflectedVolume", "Cannot clone volume %s\n", GetName());
2095 return nullptr;
2096 }
2097 map.Add((TObject *)this, vol);
2098 if (newname && newname[0])
2099 vol->SetName(newname);
2100 delete vol->GetNodes();
2101 vol->SetNodes(nullptr);
2104 // The volume is now properly cloned, but with the same shape.
2105 // Reflect the shape (if any) and connect it.
2106 if (fShape) {
2107 TGeoShape *reflected_shape =
2108 TGeoScaledShape::MakeScaledShape(fShape->GetName(), fShape, new TGeoScale(1., 1., -1.));
2109 vol->SetShape(reflected_shape);
2110 }
2111 // Reflect the daughters.
2112 Int_t nd = vol->GetNdaughters();
2113 if (!nd)
2114 return vol;
2115 TGeoNodeMatrix *node;
2116 TGeoMatrix *local, *local_cloned;
2117 TGeoVolume *new_vol;
2118 if (!vol->GetFinder()) {
2119 for (Int_t i = 0; i < nd; i++) {
2120 node = (TGeoNodeMatrix *)vol->GetNode(i);
2121 local = node->GetMatrix();
2122 // printf("%s before\n", node->GetName());
2123 // local->Print();
2124 Bool_t reflected = local->IsReflection();
2125 local_cloned = new TGeoCombiTrans(*local);
2126 local_cloned->RegisterYourself();
2127 node->SetMatrix(local_cloned);
2128 if (!reflected) {
2129 // We need to reflect only the translation and propagate to daughters.
2130 // H' = Sz * H * Sz
2131 local_cloned->ReflectZ(kTRUE);
2132 local_cloned->ReflectZ(kFALSE);
2133 // printf("%s after\n", node->GetName());
2134 // node->GetMatrix()->Print();
2135 new_vol = node->GetVolume()->MakeReflectedVolume();
2136 node->SetVolume(new_vol);
2137 continue;
2138 }
2139 // The next daughter is already reflected, so reflect on Z everything and stop
2140 local_cloned->ReflectZ(kTRUE); // rot + tr
2141 // printf("%s already reflected... After:\n", node->GetName());
2142 // node->GetMatrix()->Print();
2143 }
2144 if (vol->GetVoxels())
2145 vol->GetVoxels()->Voxelize();
2146 return vol;
2147 }
2148 // Volume is divided, so we have to reflect the division.
2149 // printf(" ... divided %s\n", fFinder->ClassName());
2150 TGeoPatternFinder *new_finder = fFinder->MakeCopy(kTRUE);
2151 if (!new_finder) {
2152 Fatal("MakeReflectedVolume", "Could not copy finder for volume %s", GetName());
2153 return nullptr;
2154 }
2155 new_finder->SetVolume(vol);
2156 vol->SetFinder(new_finder);
2157 TGeoNodeOffset *nodeoff;
2158 new_vol = nullptr;
2159 for (Int_t i = 0; i < nd; i++) {
2160 nodeoff = (TGeoNodeOffset *)vol->GetNode(i);
2161 nodeoff->SetFinder(new_finder);
2162 new_vol = nodeoff->GetVolume()->MakeReflectedVolume();
2163 nodeoff->SetVolume(new_vol);
2164 }
2165 return vol;
2166}
2167
2168////////////////////////////////////////////////////////////////////////////////
2169/// Set this volume as the TOP one (the whole geometry starts from here)
2170
2172{
2173 fGeoManager->SetTopVolume(this);
2174}
2175
2176////////////////////////////////////////////////////////////////////////////////
2177/// Set the current tracking point.
2178
2180{
2181 fGeoManager->SetCurrentPoint(x, y, z);
2182}
2183
2184////////////////////////////////////////////////////////////////////////////////
2185/// set the shape associated with this volume
2186
2188{
2189 if (!shape) {
2190 Error("SetShape", "No shape");
2191 return;
2192 }
2193 fShape = (TGeoShape *)shape;
2194}
2195
2196////////////////////////////////////////////////////////////////////////////////
2197/// sort nodes by decreasing volume of the bounding box. ONLY nodes comes first,
2198/// then overlapping nodes and finally division nodes.
2199
2201{
2202 if (!Valid()) {
2203 Error("SortNodes", "Bounding box not valid");
2204 return;
2205 }
2206 Int_t nd = GetNdaughters();
2207 // printf("volume : %s, nd=%i\n", GetName(), nd);
2208 if (!nd)
2209 return;
2210 if (fFinder)
2211 return;
2212 // printf("Nodes for %s\n", GetName());
2213 Int_t id = 0;
2214 TGeoNode *node = nullptr;
2215 TObjArray *nodes = new TObjArray(nd);
2216 Int_t inode = 0;
2217 // first put ONLY's
2218 for (id = 0; id < nd; id++) {
2219 node = GetNode(id);
2220 if (node->InheritsFrom(TGeoNodeOffset::Class()) || node->IsOverlapping())
2221 continue;
2222 nodes->Add(node);
2223 // printf("inode %i ONLY\n", inode);
2224 inode++;
2225 }
2226 // second put overlapping nodes
2227 for (id = 0; id < nd; id++) {
2228 node = GetNode(id);
2229 if (node->InheritsFrom(TGeoNodeOffset::Class()) || (!node->IsOverlapping()))
2230 continue;
2231 nodes->Add(node);
2232 // printf("inode %i MANY\n", inode);
2233 inode++;
2234 }
2235 // third put the divided nodes
2236 if (fFinder) {
2237 fFinder->SetDivIndex(inode);
2238 for (id = 0; id < nd; id++) {
2239 node = GetNode(id);
2240 if (!node->InheritsFrom(TGeoNodeOffset::Class()))
2241 continue;
2242 nodes->Add(node);
2243 // printf("inode %i DIV\n", inode);
2244 inode++;
2245 }
2246 }
2247 if (inode != nd)
2248 printf(" volume %s : number of nodes does not match!!!\n", GetName());
2249 delete fNodes;
2250 fNodes = nodes;
2251}
2252
2253////////////////////////////////////////////////////////////////////////////////
2254/// Stream an object of class TGeoVolume.
2255
2257{
2258 if (R__b.IsReading()) {
2259 R__b.ReadClassBuffer(TGeoVolume::Class(), this);
2260 if (fVoxels && fVoxels->IsInvalid())
2261 Voxelize("");
2262 } else {
2263 if (!fVoxels) {
2264 R__b.WriteClassBuffer(TGeoVolume::Class(), this);
2265 } else {
2266 if (!fGeoManager->IsStreamingVoxels()) {
2267 TGeoVoxelFinder *voxels = fVoxels;
2268 fVoxels = nullptr;
2269 R__b.WriteClassBuffer(TGeoVolume::Class(), this);
2270 fVoxels = voxels;
2271 } else {
2272 R__b.WriteClassBuffer(TGeoVolume::Class(), this);
2273 }
2274 }
2275 }
2276}
2277
2278////////////////////////////////////////////////////////////////////////////////
2279/// Set the current options (none implemented)
2280
2281void TGeoVolume::SetOption(const char *option)
2282{
2283 fOption = option;
2284}
2285
2286////////////////////////////////////////////////////////////////////////////////
2287/// Set the line color.
2288
2290{
2291 TAttLine::SetLineColor(lcolor);
2292}
2293
2294////////////////////////////////////////////////////////////////////////////////
2295/// Set the line style.
2296
2298{
2299 TAttLine::SetLineStyle(lstyle);
2300}
2301
2302////////////////////////////////////////////////////////////////////////////////
2303/// Set the line width.
2304
2306{
2307 TAttLine::SetLineWidth(lwidth);
2308}
2309
2310////////////////////////////////////////////////////////////////////////////////
2311/// get the pointer to a daughter node
2312
2314{
2315 if (!fNodes)
2316 return nullptr;
2317 TGeoNode *node = (TGeoNode *)fNodes->FindObject(name);
2318 return node;
2319}
2320
2321////////////////////////////////////////////////////////////////////////////////
2322/// get the total size in bytes for this volume
2323
2325{
2326 Int_t count = 28 + 2 + 6 + 4 + 0; // TNamed+TGeoAtt+TAttLine+TAttFill+TAtt3D
2327 count += fName.Capacity() + fTitle.Capacity(); // name+title
2328 count += 7 * sizeof(char *); // fShape + fMedium + fFinder + fField + fNodes + 2 extensions
2329 count += fOption.Capacity(); // fOption
2330 if (fShape)
2331 count += fShape->GetByteCount();
2332 if (fFinder)
2333 count += fFinder->GetByteCount();
2334 if (fNodes) {
2335 count += 32 + 4 * fNodes->GetEntries(); // TObjArray
2336 TIter next(fNodes);
2337 TGeoNode *node;
2338 while ((node = (TGeoNode *)next()))
2339 count += node->GetByteCount();
2340 }
2341 return count;
2342}
2343
2344////////////////////////////////////////////////////////////////////////////////
2345/// loop all nodes marked as overlaps and find overlapping brothers
2346
2348{
2349 if (!Valid()) {
2350 Error("FindOverlaps", "Bounding box not valid");
2351 return;
2352 }
2353 if (!fVoxels)
2354 return;
2355 Int_t nd = GetNdaughters();
2356 if (!nd)
2357 return;
2358 TGeoNode *node = nullptr;
2359 Int_t inode = 0;
2360 for (inode = 0; inode < nd; inode++) {
2361 node = GetNode(inode);
2362 if (!node->IsOverlapping())
2363 continue;
2364 fVoxels->FindOverlaps(inode);
2365 }
2366}
2367
2368////////////////////////////////////////////////////////////////////////////////
2369/// Remove an existing daughter.
2370
2372{
2373 if (!fNodes || !fNodes->GetEntriesFast())
2374 return;
2375 if (!fNodes->Remove(node))
2376 return;
2377 fNodes->Compress();
2378 if (fVoxels)
2379 fVoxels->SetNeedRebuild();
2380 if (IsAssembly())
2381 fShape->ComputeBBox();
2382}
2383
2384////////////////////////////////////////////////////////////////////////////////
2385/// Replace an existing daughter with a new volume having the same name but
2386/// possibly a new shape, position or medium. Not allowed for positioned assemblies.
2387/// For division cells, the new shape/matrix are ignored.
2388
2390{
2391 Int_t ind = GetIndex(nodeorig);
2392 if (ind < 0)
2393 return nullptr;
2394 TGeoVolume *oldvol = nodeorig->GetVolume();
2395 if (oldvol->IsAssembly()) {
2396 Error("ReplaceNode", "Cannot replace node %s since it is an assembly", nodeorig->GetName());
2397 return nullptr;
2398 }
2399 TGeoShape *shape = oldvol->GetShape();
2400 if (newshape && !nodeorig->IsOffset())
2401 shape = newshape;
2402 TGeoMedium *med = oldvol->GetMedium();
2403 if (newmed)
2404 med = newmed;
2405 // Make a new volume
2406 TGeoVolume *vol = new TGeoVolume(oldvol->GetName(), shape, med);
2407 // copy volume attributes
2408 vol->SetVisibility(oldvol->IsVisible());
2409 vol->SetLineColor(oldvol->GetLineColor());
2410 vol->SetLineStyle(oldvol->GetLineStyle());
2411 vol->SetLineWidth(oldvol->GetLineWidth());
2412 vol->SetFillColor(oldvol->GetFillColor());
2413 vol->SetFillStyle(oldvol->GetFillStyle());
2414 // copy field
2415 vol->SetField(oldvol->GetField());
2416 // Make a copy of the node
2417 TGeoNode *newnode = nodeorig->MakeCopyNode();
2418 if (!newnode) {
2419 Fatal("ReplaceNode", "Cannot make copy node for %s", nodeorig->GetName());
2420 return nullptr;
2421 }
2422 // Change the volume for the new node
2423 newnode->SetVolume(vol);
2424 // Replace the matrix
2425 if (newpos && !nodeorig->IsOffset()) {
2426 TGeoNodeMatrix *nodemat = (TGeoNodeMatrix *)newnode;
2427 nodemat->SetMatrix(newpos);
2428 }
2429 // Replace nodeorig with new one
2430 fNodes->RemoveAt(ind);
2431 fNodes->AddAt(newnode, ind);
2432 if (fVoxels)
2433 fVoxels->SetNeedRebuild();
2434 if (IsAssembly())
2435 fShape->ComputeBBox();
2436 return newnode;
2437}
2438
2439////////////////////////////////////////////////////////////////////////////////
2440/// Select this volume as matching an arbitrary criteria. The volume is added to
2441/// a static list and the flag TGeoVolume::kVolumeSelected is set. All flags need
2442/// to be reset at the end by calling the method with CLEAR=true. This will also clear
2443/// the list.
2444
2446{
2447 static TObjArray array(256);
2448 static Int_t len = 0;
2449 Int_t i;
2450 TObject *vol;
2451 if (clear) {
2452 for (i = 0; i < len; i++) {
2453 vol = array.At(i);
2455 }
2456 array.Clear();
2457 len = 0;
2458 return;
2459 }
2461 array.AddAtAndExpand(this, len++);
2462}
2463
2464////////////////////////////////////////////////////////////////////////////////
2465/// set visibility of this volume
2466
2468{
2470 if (fGeoManager->IsClosed())
2472 fGeoManager->SetVisOption(4);
2473 TSeqCollection *brlist = gROOT->GetListOfBrowsers();
2474 TIter next(brlist);
2475 TBrowser *browser = nullptr;
2476 while ((browser = (TBrowser *)next())) {
2477 browser->CheckObjectItem(this, vis);
2478 browser->Refresh();
2479 }
2480}
2481
2482////////////////////////////////////////////////////////////////////////////////
2483/// Set visibility for containers.
2484
2486{
2488 if (fGeoManager && fGeoManager->IsClosed()) {
2489 if (flag)
2491 else
2493 }
2494}
2495
2496////////////////////////////////////////////////////////////////////////////////
2497/// Set visibility for leaves.
2498
2500{
2502 if (fGeoManager && fGeoManager->IsClosed()) {
2503 if (flag)
2505 else
2507 }
2508}
2509
2510////////////////////////////////////////////////////////////////////////////////
2511/// Set visibility for leaves.
2512
2514{
2515 if (IsAssembly())
2516 return;
2517 TGeoAtt::SetVisOnly(flag);
2518 if (fGeoManager && fGeoManager->IsClosed()) {
2519 if (flag)
2521 else
2523 }
2524}
2525
2526////////////////////////////////////////////////////////////////////////////////
2527/// Check if the shape of this volume is valid.
2528
2530{
2531 return fShape->IsValidBox();
2532}
2533
2534////////////////////////////////////////////////////////////////////////////////
2535/// Find a daughter node having VOL as volume and fill TGeoManager::fHMatrix
2536/// with its global matrix.
2537
2539{
2540 if (vol == this)
2541 return kTRUE;
2542 Int_t nd = GetNdaughters();
2543 if (!nd)
2544 return kFALSE;
2545 TGeoHMatrix *global = fGeoManager->GetHMatrix();
2546 if (!global)
2547 return kFALSE;
2548 TGeoNode *dnode;
2549 TGeoVolume *dvol;
2550 TGeoMatrix *local;
2551 Int_t i;
2552 for (i = 0; i < nd; i++) {
2553 dnode = GetNode(i);
2554 dvol = dnode->GetVolume();
2555 if (dvol == vol) {
2556 local = dnode->GetMatrix();
2557 global->MultiplyLeft(local);
2558 return kTRUE;
2559 }
2560 }
2561 for (i = 0; i < nd; i++) {
2562 dnode = GetNode(i);
2563 dvol = dnode->GetVolume();
2564 if (dvol->FindMatrixOfDaughterVolume(vol))
2565 return kTRUE;
2566 }
2567 return kFALSE;
2568}
2569
2570////////////////////////////////////////////////////////////////////////////////
2571/// set visibility for daughters
2572
2574{
2575 SetVisDaughters(vis);
2576 if (fGeoManager->IsClosed())
2578 fGeoManager->SetVisOption(4);
2579}
2580
2581////////////////////////////////////////////////////////////////////////////////
2582/// build the voxels for this volume
2583
2585{
2586 if (!Valid()) {
2587 Error("Voxelize", "Bounding box not valid");
2588 return;
2589 }
2590 // do not voxelize divided volumes
2591 if (fFinder)
2592 return;
2593 // or final leaves
2594 Int_t nd = GetNdaughters();
2595 if (!nd)
2596 return;
2597 // If this is an assembly, re-compute bounding box
2598 if (IsAssembly())
2599 fShape->ComputeBBox();
2600 // delete old voxelization if any
2601 if (fVoxels) {
2603 delete fVoxels;
2604 fVoxels = nullptr;
2605 }
2606 // Create the voxels structure
2607 fVoxels = new TGeoVoxelFinder(this);
2608 fVoxels->Voxelize(option);
2609 if (fVoxels) {
2610 if (fVoxels->IsInvalid()) {
2611 delete fVoxels;
2612 fVoxels = nullptr;
2613 }
2614 }
2615}
2616
2617////////////////////////////////////////////////////////////////////////////////
2618/// Estimate the weight of a volume (in kg) with SIGMA(M)/M better than PRECISION.
2619/// Option can contain : v - verbose, a - analytical (default)
2620
2622{
2623 TGeoVolume *top = fGeoManager->GetTopVolume();
2624 if (top != this)
2625 fGeoManager->SetTopVolume(this);
2626 else
2627 top = nullptr;
2628 Double_t weight = fGeoManager->Weight(precision, option);
2629 if (top)
2630 fGeoManager->SetTopVolume(top);
2631 return weight;
2632}
2633
2634////////////////////////////////////////////////////////////////////////////////
2635/// Analytical computation of the weight.
2636
2638{
2639 Double_t capacity = Capacity();
2640 Double_t weight = 0.0;
2641 Int_t i;
2642 Int_t nd = GetNdaughters();
2643 TGeoVolume *daughter;
2644 for (i = 0; i < nd; i++) {
2645 daughter = GetNode(i)->GetVolume();
2646 weight += daughter->WeightA();
2647 capacity -= daughter->Capacity();
2648 }
2649 Double_t density = 0.0;
2650 if (!IsAssembly()) {
2651 if (fMedium)
2652 density = fMedium->GetMaterial()->GetDensity();
2653 if (density < 0.01)
2654 density = 0.0; // do not weight gases
2655 }
2656 weight += 0.001 * capacity * density; //[kg]
2657 return weight;
2658}
2659
2660////////////////////////////////////////////////////////////////////////////////
2661/// dummy constructor
2662
2664{
2665 fVolumes = nullptr;
2666 fDivision = nullptr;
2667 fNumed = 0;
2668 fNdiv = 0;
2669 fAxis = 0;
2670 fStart = 0;
2671 fStep = 0;
2672 fAttSet = kFALSE;
2674}
2675
2676////////////////////////////////////////////////////////////////////////////////
2677/// default constructor
2678
2680{
2681 fVolumes = new TObjArray();
2682 fDivision = nullptr;
2683 fNumed = 0;
2684 fNdiv = 0;
2685 fAxis = 0;
2686 fStart = 0;
2687 fStep = 0;
2688 fAttSet = kFALSE;
2690 SetName(name);
2691 SetMedium(med);
2692 fGeoManager->AddVolume(this);
2693 // printf("--- volume multi %s created\n", name);
2694}
2695
2696////////////////////////////////////////////////////////////////////////////////
2697/// Destructor
2698
2700{
2701 if (fVolumes)
2702 delete fVolumes;
2703}
2704
2705////////////////////////////////////////////////////////////////////////////////
2706/// Add a volume with valid shape to the list of volumes. Copy all existing nodes
2707/// to this volume
2708
2710{
2711 Int_t idx = fVolumes->GetEntriesFast();
2712 fVolumes->AddAtAndExpand(vol, idx);
2713 vol->SetUniqueID(idx + 1);
2714 TGeoVolumeMulti *div;
2715 TGeoVolume *cell;
2716 if (fDivision) {
2717 div = (TGeoVolumeMulti *)vol->Divide(fDivision->GetName(), fAxis, fNdiv, fStart, fStep, fNumed, fOption.Data());
2718 if (!div) {
2719 Fatal("AddVolume", "Cannot divide volume %s", vol->GetName());
2720 return;
2721 }
2722 for (Int_t i = 0; i < div->GetNvolumes(); i++) {
2723 cell = div->GetVolume(i);
2724 fDivision->AddVolume(cell);
2725 }
2726 }
2727 if (fNodes) {
2728 Int_t nd = fNodes->GetEntriesFast();
2729 for (Int_t id = 0; id < nd; id++) {
2730 TGeoNode *node = (TGeoNode *)fNodes->At(id);
2731 Bool_t many = node->IsOverlapping();
2732 if (many)
2733 vol->AddNodeOverlap(node->GetVolume(), node->GetNumber(), node->GetMatrix());
2734 else
2735 vol->AddNode(node->GetVolume(), node->GetNumber(), node->GetMatrix());
2736 }
2737 }
2738 // vol->MakeCopyNodes(this);
2739}
2740
2741////////////////////////////////////////////////////////////////////////////////
2742/// Add a new node to the list of nodes. This is the usual method for adding
2743/// daughters inside the container volume.
2744
2746{
2747 TGeoNode *n = TGeoVolume::AddNode(vol, copy_no, mat, option);
2748 Int_t nvolumes = fVolumes->GetEntriesFast();
2749 TGeoVolume *volume = nullptr;
2750 for (Int_t ivo = 0; ivo < nvolumes; ivo++) {
2751 volume = GetVolume(ivo);
2752 volume->SetLineColor(GetLineColor());
2753 volume->SetLineStyle(GetLineStyle());
2754 volume->SetLineWidth(GetLineWidth());
2755 volume->SetVisibility(IsVisible());
2756 volume->AddNode(vol, copy_no, mat, option);
2757 }
2758 // printf("--- vmulti %s : node %s added to %i components\n", GetName(), vol->GetName(), nvolumes);
2759 return n;
2760}
2761
2762////////////////////////////////////////////////////////////////////////////////
2763/// Add a new node to the list of nodes, This node is possibly overlapping with other
2764/// daughters of the volume or extruding the volume.
2765
2767{
2768 TGeoVolume::AddNodeOverlap(vol, copy_no, mat, option);
2769 Int_t nvolumes = fVolumes->GetEntriesFast();
2770 TGeoVolume *volume = nullptr;
2771 for (Int_t ivo = 0; ivo < nvolumes; ivo++) {
2772 volume = GetVolume(ivo);
2773 volume->SetLineColor(GetLineColor());
2774 volume->SetLineStyle(GetLineStyle());
2775 volume->SetLineWidth(GetLineWidth());
2776 volume->SetVisibility(IsVisible());
2777 volume->AddNodeOverlap(vol, copy_no, mat, option);
2778 }
2779 // printf("--- vmulti %s : node ovlp %s added to %i components\n", GetName(), vol->GetName(), nvolumes);
2780}
2781
2782////////////////////////////////////////////////////////////////////////////////
2783/// Returns the last shape.
2784
2786{
2787 TGeoVolume *vol = GetVolume(fVolumes->GetEntriesFast() - 1);
2788 if (!vol)
2789 return nullptr;
2790 return vol->GetShape();
2791}
2792
2793////////////////////////////////////////////////////////////////////////////////
2794/// division of multiple volumes
2795
2796TGeoVolume *TGeoVolumeMulti::Divide(const char *divname, Int_t iaxis, Int_t ndiv, Double_t start, Double_t step,
2797 Int_t numed, const char *option)
2798{
2799 if (fDivision) {
2800 Error("Divide", "volume %s already divided", GetName());
2801 return nullptr;
2802 }
2803 Int_t nvolumes = fVolumes->GetEntriesFast();
2804 TGeoMedium *medium = fMedium;
2805 if (numed) {
2806 medium = fGeoManager->GetMedium(numed);
2807 if (!medium) {
2808 Error("Divide", "Invalid medium number %d for division volume %s", numed, divname);
2809 medium = fMedium;
2810 }
2811 }
2812 if (!nvolumes) {
2813 // this is a virtual volume
2814 fDivision = new TGeoVolumeMulti(divname, medium);
2815 fNumed = medium->GetId();
2816 fOption = option;
2817 fAxis = iaxis;
2818 fNdiv = ndiv;
2819 fStart = start;
2820 fStep = step;
2821 // nothing else to do at this stage
2822 return fDivision;
2823 }
2824 TGeoVolume *vol = nullptr;
2825 fDivision = new TGeoVolumeMulti(divname, medium);
2826 if (medium)
2827 fNumed = medium->GetId();
2828 fOption = option;
2829 fAxis = iaxis;
2830 fNdiv = ndiv;
2831 fStart = start;
2832 fStep = step;
2833 for (Int_t ivo = 0; ivo < nvolumes; ivo++) {
2834 vol = GetVolume(ivo);
2835 vol->SetLineColor(GetLineColor());
2836 vol->SetLineStyle(GetLineStyle());
2837 vol->SetLineWidth(GetLineWidth());
2838 vol->SetVisibility(IsVisible());
2839 fDivision->AddVolume(vol->Divide(divname, iaxis, ndiv, start, step, numed, option));
2840 }
2841 // printf("--- volume multi %s (%i volumes) divided\n", GetName(), nvolumes);
2842 if (numed)
2843 fDivision->SetMedium(medium);
2844 return fDivision;
2845}
2846
2847////////////////////////////////////////////////////////////////////////////////
2848/// Make a copy of this volume
2849/// build a volume with same name, shape and medium
2850
2852{
2853 TGeoVolume *vol = new TGeoVolume(GetName(), newshape, fMedium);
2854 Int_t i = 0;
2855 // copy volume attributes
2856 vol->SetVisibility(IsVisible());
2857 vol->SetLineColor(GetLineColor());
2858 vol->SetLineStyle(GetLineStyle());
2859 vol->SetLineWidth(GetLineWidth());
2860 vol->SetFillColor(GetFillColor());
2861 vol->SetFillStyle(GetFillStyle());
2862 // copy field
2863 vol->SetField(fField);
2864 // Copy extensions
2867 // if divided, copy division object
2868 // if (fFinder) {
2869 // Error("MakeCopyVolume", "volume %s divided", GetName());
2870 // vol->SetFinder(fFinder);
2871 // }
2872 if (fDivision) {
2873 TGeoVolume *cell;
2874 TGeoVolumeMulti *div =
2875 (TGeoVolumeMulti *)vol->Divide(fDivision->GetName(), fAxis, fNdiv, fStart, fStep, fNumed, fOption.Data());
2876 if (!div) {
2877 Fatal("MakeCopyVolume", "Cannot divide volume %s", vol->GetName());
2878 return nullptr;
2879 }
2880 for (i = 0; i < div->GetNvolumes(); i++) {
2881 cell = div->GetVolume(i);
2882 fDivision->AddVolume(cell);
2883 }
2884 }
2885
2886 if (!fNodes)
2887 return vol;
2888 TGeoNode *node;
2889 Int_t nd = fNodes->GetEntriesFast();
2890 if (!nd)
2891 return vol;
2892 // create new list of nodes
2893 TObjArray *list = new TObjArray();
2894 // attach it to new volume
2895 vol->SetNodes(list);
2896 ((TObject *)vol)->SetBit(kVolumeImportNodes);
2897 for (i = 0; i < nd; i++) {
2898 // create copies of nodes and add them to list
2899 node = GetNode(i)->MakeCopyNode();
2900 if (!node) {
2901 Fatal("MakeCopyNode", "cannot make copy node for daughter %d of %s", i, GetName());
2902 return nullptr;
2903 }
2904 node->SetMotherVolume(vol);
2905 list->Add(node);
2906 }
2907 return vol;
2908}
2909
2910////////////////////////////////////////////////////////////////////////////////
2911/// Set the line color for all components.
2912
2914{
2916 Int_t nvolumes = fVolumes->GetEntriesFast();
2917 TGeoVolume *vol = nullptr;
2918 for (Int_t ivo = 0; ivo < nvolumes; ivo++) {
2919 vol = GetVolume(ivo);
2920 vol->SetLineColor(lcolor);
2921 }
2922}
2923
2924////////////////////////////////////////////////////////////////////////////////
2925/// Set the line style for all components.
2926
2928{
2930 Int_t nvolumes = fVolumes->GetEntriesFast();
2931 TGeoVolume *vol = nullptr;
2932 for (Int_t ivo = 0; ivo < nvolumes; ivo++) {
2933 vol = GetVolume(ivo);
2934 vol->SetLineStyle(lstyle);
2935 }
2936}
2937
2938////////////////////////////////////////////////////////////////////////////////
2939/// Set the line width for all components.
2940
2942{
2944 Int_t nvolumes = fVolumes->GetEntriesFast();
2945 TGeoVolume *vol = nullptr;
2946 for (Int_t ivo = 0; ivo < nvolumes; ivo++) {
2947 vol = GetVolume(ivo);
2948 vol->SetLineWidth(lwidth);
2949 }
2950}
2951
2952////////////////////////////////////////////////////////////////////////////////
2953/// Set medium for a multiple volume.
2954
2956{
2958 Int_t nvolumes = fVolumes->GetEntriesFast();
2959 TGeoVolume *vol = nullptr;
2960 for (Int_t ivo = 0; ivo < nvolumes; ivo++) {
2961 vol = GetVolume(ivo);
2962 vol->SetMedium(med);
2963 }
2964}
2965
2966////////////////////////////////////////////////////////////////////////////////
2967/// Set visibility for all components.
2968
2970{
2972 Int_t nvolumes = fVolumes->GetEntriesFast();
2973 TGeoVolume *vol = nullptr;
2974 for (Int_t ivo = 0; ivo < nvolumes; ivo++) {
2975 vol = GetVolume(ivo);
2976 vol->SetVisibility(vis);
2977 }
2978}
2979
2980////////////////////////////////////////////////////////////////////////////////
2981/// Constructor.
2982
2984
2985////////////////////////////////////////////////////////////////////////////////
2986/// Destructor.
2987
2989
2990////////////////////////////////////////////////////////////////////////////////
2991
2997
2998////////////////////////////////////////////////////////////////////////////////
2999
3001{
3002 std::lock_guard<std::mutex> guard(fMutex);
3004 std::vector<ThreadData_t *>::iterator i = fThreadData.begin();
3005 while (i != fThreadData.end()) {
3006 delete *i;
3007 ++i;
3008 }
3009 fThreadData.clear();
3010 fThreadSize = 0;
3011}
3012
3013////////////////////////////////////////////////////////////////////////////////
3014
3016{
3017 std::lock_guard<std::mutex> guard(fMutex);
3018 // Create assembly thread data here
3019 fThreadData.resize(nthreads);
3020 fThreadSize = nthreads;
3021 for (Int_t tid = 0; tid < nthreads; tid++) {
3022 if (fThreadData[tid] == nullptr) {
3023 fThreadData[tid] = new ThreadData_t;
3024 }
3025 }
3027}
3028
3029////////////////////////////////////////////////////////////////////////////////
3030
3035
3036////////////////////////////////////////////////////////////////////////////////
3037
3042
3043////////////////////////////////////////////////////////////////////////////////
3044
3046{
3047 fThreadData[TGeoManager::ThreadId()]->fCurrent = index;
3048}
3049
3050////////////////////////////////////////////////////////////////////////////////
3051
3053{
3054 fThreadData[TGeoManager::ThreadId()]->fNext = index;
3055}
3056
3057////////////////////////////////////////////////////////////////////////////////
3058/// Default constructor
3059
3065
3066////////////////////////////////////////////////////////////////////////////////
3067/// Constructor. Just the name has to be provided. Assemblies does not have their own
3068/// shape or medium.
3069
3071{
3072 fName = name;
3073 fName = fName.Strip();
3074 fShape = new TGeoShapeAssembly(this);
3075 if (fGeoManager)
3076 fNumber = fGeoManager->AddVolume(this);
3077 fThreadSize = 0;
3079}
3080
3081////////////////////////////////////////////////////////////////////////////////
3082/// Destructor. The assembly is owner of its "shape".
3083
3085{
3087 if (fShape)
3088 delete fShape;
3089}
3090
3091////////////////////////////////////////////////////////////////////////////////
3092/// Add a component to the assembly.
3093
3095{
3096 TGeoNode *node = TGeoVolume::AddNode(vol, copy_no, mat, option);
3097 // ((TGeoShapeAssembly*)fShape)->RecomputeBoxLast();
3098 ((TGeoShapeAssembly *)fShape)->NeedsBBoxRecompute();
3099 return node;
3100}
3101
3102////////////////////////////////////////////////////////////////////////////////
3103/// Add an overlapping node - not allowed for assemblies.
3104
3106{
3107 Warning("AddNodeOverlap",
3108 "Declaring assembly %s as possibly overlapping inside %s not allowed. Using AddNode instead !",
3109 vol->GetName(), GetName());
3110 AddNode(vol, copy_no, mat, option);
3111}
3112
3113////////////////////////////////////////////////////////////////////////////////
3114/// Clone this volume.
3115/// build a volume with same name, shape and medium
3116
3118{
3120 Int_t i;
3121 // copy other attributes
3122 Int_t nbits = 8 * sizeof(UInt_t);
3123 for (i = 0; i < nbits; i++)
3124 vol->SetAttBit(1 << i, TGeoAtt::TestAttBit(1 << i));
3125 for (i = 14; i < 24; i++)
3126 vol->SetBit(1 << i, TestBit(1 << i));
3127
3128 // copy field
3129 vol->SetField(fField);
3130 // Set bits
3131 for (i = 0; i < nbits; i++)
3132 vol->SetBit(1 << i, TObject::TestBit(1 << i));
3133 vol->SetBit(kVolumeClone);
3134 // make copy nodes
3135 vol->MakeCopyNodes(this);
3136 // CloneNodesAndConnect(vol);
3137 ((TGeoShapeAssembly *)vol->GetShape())->NeedsBBoxRecompute();
3138 // copy voxels
3139 TGeoVoxelFinder *voxels = nullptr;
3140 if (fVoxels) {
3141 voxels = new TGeoVoxelFinder(vol);
3142 vol->SetVoxelFinder(voxels);
3143 }
3144 // copy option, uid
3145 vol->SetOption(fOption);
3146 vol->SetNumber(fNumber);
3147 vol->SetNtotal(fNtotal);
3148 vol->SetTitle(GetTitle());
3149 // copy extensions
3152 return vol;
3153}
3154
3155////////////////////////////////////////////////////////////////////////////////
3156/// Division makes no sense for assemblies.
3157
3159{
3160 Error("Divide", "Assemblies cannot be divided");
3161 return nullptr;
3162}
3163
3164////////////////////////////////////////////////////////////////////////////////
3165/// Assign to the assembly a collection of identical volumes positioned according
3166/// a predefined pattern. The option can be spaced out or touching depending on the empty
3167/// space between volumes.
3168
3170{
3171 if (fNodes) {
3172 Error("Divide", "Cannot divide assembly %s since it has nodes", GetName());
3173 return nullptr;
3174 }
3175 if (fFinder) {
3176 Error("Divide", "Assembly %s already divided", GetName());
3177 return nullptr;
3178 }
3179 Int_t ncells = pattern->GetNdiv();
3180 if (!ncells || pattern->GetStep() <= 0) {
3181 Error("Divide", "Pattern finder for dividing assembly %s not initialized. Use SetRange() method.", GetName());
3182 return nullptr;
3183 }
3184 fFinder = pattern;
3185 TString opt(option);
3186 opt.ToLower();
3187 if (opt.Contains("spacedout"))
3188 fFinder->SetSpacedOut(kTRUE);
3189 else
3190 fFinder->SetSpacedOut(kFALSE);
3191 // Position volumes
3192 for (Int_t i = 0; i < ncells; i++) {
3193 fFinder->cd(i);
3194 TGeoNodeOffset *node = new TGeoNodeOffset(cell, i, 0.);
3195 node->SetFinder(fFinder);
3196 fNodes->Add(node);
3197 }
3198 return cell;
3199}
3200
3201////////////////////////////////////////////////////////////////////////////////
3202/// Make a clone of volume VOL but which is an assembly.
3203
3205{
3206 if (volorig->IsAssembly() || volorig->IsVolumeMulti())
3207 return nullptr;
3208 Int_t nd = volorig->GetNdaughters();
3209 if (!nd)
3210 return nullptr;
3211 TGeoVolumeAssembly *vol = new TGeoVolumeAssembly(volorig->GetName());
3212 Int_t i;
3213 // copy other attributes
3214 Int_t nbits = 8 * sizeof(UInt_t);
3215 for (i = 0; i < nbits; i++)
3216 vol->SetAttBit(1 << i, volorig->TestAttBit(1 << i));
3217 for (i = 14; i < 24; i++)
3218 vol->SetBit(1 << i, volorig->TestBit(1 << i));
3219
3220 // copy field
3221 vol->SetField(volorig->GetField());
3222 // Set bits
3223 for (i = 0; i < nbits; i++)
3224 vol->SetBit(1 << i, volorig->TestBit(1 << i));
3225 vol->SetBit(kVolumeClone);
3226 // make copy nodes
3227 vol->MakeCopyNodes(volorig);
3228 // volorig->CloneNodesAndConnect(vol);
3229 vol->GetShape()->ComputeBBox();
3230 // copy voxels
3231 TGeoVoxelFinder *voxels = nullptr;
3232 if (volorig->GetVoxels()) {
3233 voxels = new TGeoVoxelFinder(vol);
3234 vol->SetVoxelFinder(voxels);
3235 }
3236 // copy option, uid
3237 vol->SetOption(volorig->GetOption());
3238 vol->SetNumber(volorig->GetNumber());
3239 vol->SetNtotal(volorig->GetNtotal());
3240 return vol;
3241}
ROOT::R::TRInterface & r
Definition Object.C:4
#define b(i)
Definition RSha256.hxx:100
#define f(i)
Definition RSha256.hxx:104
#define s1(x)
Definition RSha256.hxx:91
start
Definition Rotated.cxx:223
int Int_t
Signed integer 4 bytes (int).
Definition RtypesCore.h:59
unsigned int UInt_t
Unsigned integer 4 bytes (unsigned int).
Definition RtypesCore.h:60
short Width_t
Line width (short).
Definition RtypesCore.h:98
bool Bool_t
Boolean (0=false, 1=true) (bool).
Definition RtypesCore.h:77
constexpr Bool_t kFALSE
Definition RtypesCore.h:108
double Double_t
Double 8 bytes.
Definition RtypesCore.h:73
short Color_t
Color number (short).
Definition RtypesCore.h:99
short Style_t
Style number (short).
Definition RtypesCore.h:96
constexpr Bool_t kTRUE
Definition RtypesCore.h:107
const char Option_t
Option string (const char).
Definition RtypesCore.h:80
if(name) objname
externTEnv * gEnv
Definition TEnv.h:170
XFontStruct * id
Definition TGX11.cxx:147
char name[80]
Definition TGX11.cxx:148
externTGeoManager * gGeoManager
externTGeoIdentity * gGeoIdentity
Definition TGeoMatrix.h:538
#define gROOT
Definition TROOT.h:417
externTStyle * gStyle
Definition TStyle.h:442
This class provides a simple interface to execute the same task multiple times in parallel threads,...
unsigned GetPoolSize() const
Returns the number of worker threads in the task arena.
void Foreach(F func, unsigned nTimes, unsigned nChunks=0)
Execute a function without arguments several times in parallel, dividing the execution in nChunks.
virtual Color_t GetFillColor() const
Return the fill area color.
Definition TAttFill.h:32
virtual Style_t GetFillStyle() const
Return the fill area style.
Definition TAttFill.h:33
virtual void SetFillColor(Color_t fcolor)
Set the fill area color.
Definition TAttFill.h:40
virtual void SetFillStyle(Style_t fstyle)
Set the fill area style.
Definition TAttFill.h:42
virtual Color_t GetLineColor() const
Return the line color.
Definition TAttLine.h:36
virtual void SetLineStyle(Style_t lstyle)
Set the line style.
Definition TAttLine.h:46
virtual Width_t GetLineWidth() const
Return the line width.
Definition TAttLine.h:38
virtual void SetLineWidth(Width_t lwidth)
Set the line width.
Definition TAttLine.h:47
virtual void SaveLineAttributes(std::ostream &out, const char *name, Int_t coldef=1, Int_t stydef=1, Int_t widdef=1)
virtual void SetLineColor(Color_t lcolor)
Set the line color.
Definition TAttLine.h:44
virtual Style_t GetLineStyle() const
Return the line style.
Definition TAttLine.h:37
Using a TBrowser one can browse all ROOT objects.
Definition TBrowser.h:37
void CheckObjectItem(TObject *obj, Bool_t check=kFALSE)
Change status of checkbox for this item.
Definition TBrowser.cxx:345
void Refresh()
Refresh browser contents.
Definition TBrowser.cxx:438
Buffer base class used for serializing objects.
Definition TBuffer.h:43
virtual Int_t ReadClassBuffer(const TClass *cl, void *pointer, const TClass *onfile_class=nullptr)=0
Bool_t IsReading() const
Definition TBuffer.h:86
virtual Int_t WriteClassBuffer(const TClass *cl, void *pointer)=0
TDirectory::TContext keeps track and restore the current directory.
Definition TDirectory.h:89
A file, usually with extension .root, that stores data and code in the form of serialized objects in ...
Definition TFile.h:130
static TFile * Open(const char *name, Option_t *option="", const char *ftitle="", Int_t compress=ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault, Int_t netopt=0)
Create / open a file.
Definition TFile.cxx:3787
Bool_t IsVisRaytrace() const
Definition TGeoAtt.h:82
virtual void SetVisOnly(Bool_t flag=kTRUE)
Set branch type visibility.
Definition TGeoAtt.cxx:93
Bool_t TestAttBit(UInt_t f) const
Definition TGeoAtt.h:64
virtual void SetVisLeaves(Bool_t flag=kTRUE)
Set branch type visibility.
Definition TGeoAtt.cxx:83
@ kSaveNodesAtt
Definition TGeoAtt.h:50
@ kSavePrimitiveAtt
Definition TGeoAtt.h:50
void SetVisDaughters(Bool_t vis=kTRUE)
Set visibility for the daughters.
Definition TGeoAtt.cxx:115
void ResetAttBit(UInt_t f)
Definition TGeoAtt.h:63
void SetVisRaytrace(Bool_t flag=kTRUE)
Definition TGeoAtt.h:66
Bool_t IsVisDaughters() const
Definition TGeoAtt.h:84
virtual void SetVisibility(Bool_t vis=kTRUE)
Set visibility for this object.
Definition TGeoAtt.cxx:103
void SetAttBit(UInt_t f)
Definition TGeoAtt.h:61
void SetVisTouched(Bool_t vis=kTRUE)
Mark visualization attributes as "modified".
Definition TGeoAtt.cxx:137
virtual void SetVisContainers(Bool_t flag=kTRUE)
Set branch type visibility.
Definition TGeoAtt.cxx:75
Class describing rotation + translation.
Definition TGeoMatrix.h:318
Composite shapes are Boolean combinations of two or more shape components.
void RegisterYourself()
Register the shape and all components to TGeoManager class.
ABC for user objects attached to TGeoVolume or TGeoNode.
virtual TGeoExtension * Grab()=0
virtual void Release() const =0
Matrix class used for computing global transformations Should NOT be used for node definition.
Definition TGeoMatrix.h:459
void MultiplyLeft(const TGeoMatrix *left)
multiply to the left with an other transformation if right is identity matrix, just return
A geometry iterator.
Definition TGeoNode.h:249
The manager class for any TGeo geometry.
Definition TGeoManager.h:46
static UInt_t GetExportPrecision()
static Int_t ThreadId()
Translates the current thread id to an ordinal number.
Base class describing materials.
void SetUsed(Bool_t flag=kTRUE)
void Print(const Option_t *option="") const override
print characteristics of this material
Geometrical transformation package.
Definition TGeoMatrix.h:39
void Print(Option_t *option="") const override
print the matrix in 4x4 format
virtual void ReflectZ(Bool_t leftside, Bool_t rotonly=kFALSE)
Multiply by a reflection respect to XY.
Bool_t IsReflection() const
Definition TGeoMatrix.h:67
virtual void RegisterYourself()
Register the matrix in the current manager, which will become the owner.
Bool_t IsIdentity() const
Definition TGeoMatrix.h:64
const char * GetPointerName() const
Provide a pointer name containing uid.
Bool_t IsRegistered() const
Definition TGeoMatrix.h:73
Media are used to store properties related to tracking and which are useful only when using geometry ...
Definition TGeoMedium.h:23
Int_t GetId() const
Definition TGeoMedium.h:45
TGeoMaterial * GetMaterial() const
Definition TGeoMedium.h:49
A node containing local transformation.
Definition TGeoNode.h:155
void SetMatrix(const TGeoMatrix *matrix)
Matrix setter.
Definition TGeoNode.cxx:955
TGeoMatrix * GetMatrix() const override
Definition TGeoNode.h:172
Node containing an offset.
Definition TGeoNode.h:185
void SetFinder(TGeoPatternFinder *finder)
Definition TGeoNode.h:211
static TClass * Class()
A node represent a volume positioned inside another.They store links to both volumes and to the TGeoM...
Definition TGeoNode.h:39
Bool_t IsOverlapping() const
Definition TGeoNode.h:108
TGeoVolume * GetVolume() const
Definition TGeoNode.h:100
void SetVolume(TGeoVolume *volume)
Definition TGeoNode.h:118
Bool_t IsOffset() const
Definition TGeoNode.h:106
virtual Int_t GetByteCount() const
Definition TGeoNode.h:83
void SetOverlapping(Bool_t flag=kTRUE)
Definition TGeoNode.h:121
virtual Int_t GetOptimalVoxels() const
Definition TGeoNode.h:102
virtual TGeoMatrix * GetMatrix() const =0
void SetMotherVolume(TGeoVolume *mother)
Definition TGeoNode.h:126
virtual TGeoNode * MakeCopyNode() const
Definition TGeoNode.h:114
void SetVirtual()
Definition TGeoNode.h:122
Int_t GetNumber() const
Definition TGeoNode.h:94
void SetNumber(Int_t number)
Definition TGeoNode.h:119
base finder class for patterns. A pattern is specifying a division type
virtual Int_t GetDivAxis()
Int_t GetNdiv() const
void SetVolume(TGeoVolume *vol)
Double_t GetStep() const
Double_t GetStart() const
Class describing scale transformations.
Definition TGeoMatrix.h:254
static TGeoShape * MakeScaledShape(const char *name, TGeoShape *shape, TGeoScale *scale)
Create a scaled shape starting from a non-scaled one.
The shape encapsulating an assembly (union) of volumes.
Base abstract class for all shapes.
Definition TGeoShape.h:25
static Bool_t IsSameWithinTolerance(Double_t a, Double_t b)
Check if two numbers differ with less than a tolerance.
Bool_t IsRunTimeShape() const
Definition TGeoShape.h:152
virtual void ComputeBBox()=0
@ kGeoSavePrimitive
Definition TGeoShape.h:65
virtual TGeoShape * GetMakeRuntimeShape(TGeoShape *mother, TGeoMatrix *mat) const =0
static TGeoVolumeAssembly * MakeAssemblyFromVolume(TGeoVolume *vol)
Make a clone of volume VOL but which is an assembly.
~TGeoVolumeAssembly() override
Destructor. The assembly is owner of its "shape".
Int_t GetNextNodeIndex() const override
void CreateThreadData(Int_t nthreads) override
TGeoVolumeAssembly(const TGeoVolumeAssembly &)=delete
TGeoNode * AddNode(TGeoVolume *vol, Int_t copy_no, TGeoMatrix *mat=nullptr, Option_t *option="") override
Add a component to the assembly.
void ClearThreadData() const override
TGeoVolume * CloneVolume() const override
Clone this volume.
void AddNodeOverlap(TGeoVolume *vol, Int_t copy_no, TGeoMatrix *mat, Option_t *option) override
Add an overlapping node - not allowed for assemblies.
std::vector< ThreadData_t * > fThreadData
! Thread specific data vector
Definition TGeoVolume.h:332
std::mutex fMutex
! Mutex for concurrent operations
Definition TGeoVolume.h:334
Int_t fThreadSize
! Thread vector size
Definition TGeoVolume.h:333
void SetNextNodeIndex(Int_t index)
Int_t GetCurrentNodeIndex() const override
void SetCurrentNodeIndex(Int_t index)
TGeoVolumeAssembly()
Default constructor.
TGeoVolume * Divide(const char *divname, Int_t iaxis, Int_t ndiv, Double_t start, Double_t step, Int_t numed=0, Option_t *option="") override
Division makes no sense for assemblies.
ThreadData_t & GetThreadData() const
TGeoVolume * Divide(const char *divname, Int_t iaxis, Int_t ndiv, Double_t start, Double_t step, Int_t numed=0, Option_t *option="") override
division of multiple volumes
void SetLineColor(Color_t lcolor) override
Set the line color for all components.
Double_t fStart
Definition TGeoVolume.h:274
void AddVolume(TGeoVolume *vol)
Add a volume with valid shape to the list of volumes.
TGeoVolume * MakeCopyVolume(TGeoShape *newshape) override
Make a copy of this volume build a volume with same name, shape and medium.
void SetMedium(TGeoMedium *medium) override
Set medium for a multiple volume.
TGeoNode * AddNode(TGeoVolume *vol, Int_t copy_no, TGeoMatrix *mat, Option_t *option="") override
Add a new node to the list of nodes.
TGeoVolume * GetVolume(Int_t id) const
Definition TGeoVolume.h:287
void SetVisibility(Bool_t vis=kTRUE) override
Set visibility for all components.
~TGeoVolumeMulti() override
Destructor.
TGeoVolumeMulti * fDivision
Definition TGeoVolume.h:270
TGeoVolumeMulti()
dummy constructor
void SetLineWidth(Width_t lwidth) override
Set the line width for all components.
TGeoVolumeMulti(const TGeoVolumeMulti &)=delete
TGeoShape * GetLastShape() const
Returns the last shape.
void AddNodeOverlap(TGeoVolume *vol, Int_t copy_no, TGeoMatrix *mat, Option_t *option="") override
Add a new node to the list of nodes, This node is possibly overlapping with other daughters of the vo...
void SetLineStyle(Style_t lstyle) override
Set the line style for all components.
Int_t GetNvolumes() const
Definition TGeoVolume.h:294
TObjArray * fVolumes
Definition TGeoVolume.h:269
Double_t WeightA() const
Analytical computation of the weight.
void AddNodeOffset(TGeoVolume *vol, Int_t copy_no, Double_t offset=0, Option_t *option="")
Add a division node to the list of nodes.
void SetVisContainers(Bool_t flag=kTRUE) override
Set visibility for containers.
virtual void cd(Int_t inode) const
Actualize matrix of node indexed <inode>.
virtual void ClearThreadData() const
void SetVisibility(Bool_t vis=kTRUE) override
set visibility of this volume
Bool_t IsVisContainers() const
Definition TGeoVolume.h:158
void SetVoxelFinder(TGeoVoxelFinder *finder)
Definition TGeoVolume.h:244
void RemoveNode(TGeoNode *node)
Remove an existing daughter.
Int_t GetNodeIndex(const TGeoNode *node, Int_t *check_list, Int_t ncheck) const
Get the index of a daughter within check_list by providing the node pointer.
Bool_t Valid() const
Check if the shape of this volume is valid.
void CheckOverlapsBySampling(Double_t ovlp=0.1, Int_t npoints=1000000)
Overlap by sampling legacy checking tool. Check for illegal overlaps within a limit OVLP.
Bool_t IsAllInvisible() const
Return TRUE if volume and all daughters are invisible.
Int_t fNtotal
Definition TGeoVolume.h:56
void MakeCopyNodes(const TGeoVolume *other)
make a new list of nodes and copy all nodes of other volume inside
void SetUserExtension(TGeoExtension *ext)
Connect user-defined extension to the volume.
TGeoExtension * GrabFWExtension() const
Get a copy of the framework extension pointer.
void SetNumber(Int_t number)
Definition TGeoVolume.h:246
void ClearNodes()
Definition TGeoVolume.h:95
void SetLineWidth(Width_t lwidth) override
Set the line width.
void Raytrace(Bool_t flag=kTRUE)
Draw this volume with current settings and perform raytracing in the pad.
void RandomRays(Int_t nrays=10000, Double_t startx=0, Double_t starty=0, Double_t startz=0, const char *target_vol=nullptr, Bool_t check_norm=kFALSE)
Random raytracing method.
TGeoVolume()
dummy constructor
TGeoMedium * GetMedium() const
Definition TGeoVolume.h:176
char * GetObjectInfo(Int_t px, Int_t py) const override
Get volume info for the browser.
void Print(Option_t *option="") const override
Print volume info.
void CloneNodesAndConnect(TGeoVolume *newmother) const
Clone the array of nodes.
Bool_t IsSelected() const
Definition TGeoVolume.h:151
void SortNodes()
sort nodes by decreasing volume of the bounding box.
Bool_t FindMatrixOfDaughterVolume(TGeoVolume *vol) const
Find a daughter node having VOL as volume and fill TGeoManager::fHMatrix with its global matrix.
void Voxelize(Option_t *option)
build the voxels for this volume
Double_t Capacity() const
Computes the capacity of this [cm^3] as the capacity of its shape.
virtual TGeoVolume * MakeCopyVolume(TGeoShape *newshape)
make a copy of this volume build a volume with same name, shape and medium
void ReplayCreation(const TGeoVolume *other)
Recreate the content of the other volume without pointer copying.
Double_t Weight(Double_t precision=0.01, Option_t *option="va")
Estimate the weight of a volume (in kg) with SIGMA(M)/M better than PRECISION.
Int_t fNumber
Definition TGeoVolume.h:55
virtual void CreateThreadData(Int_t nthreads)
virtual Int_t GetByteCount() const
get the total size in bytes for this volume
virtual TGeoNode * AddNode(TGeoVolume *vol, Int_t copy_no, TGeoMatrix *mat=nullptr, Option_t *option="")
Add a TGeoNode to the list of nodes.
Bool_t OptimizeVoxels()
Perform an extensive sampling to find which type of voxelization is most efficient.
void Browse(TBrowser *b) override
How to browse a volume.
void SetCurrentPoint(Double_t x, Double_t y, Double_t z)
Set the current tracking point.
void Paint(Option_t *option="") override
paint volume
void SetVisOnly(Bool_t flag=kTRUE) override
Set visibility for leaves.
TGeoManager * fGeoManager
! pointer to TGeoManager owning this volume
Definition TGeoVolume.h:51
TH2F * LegoPlot(Int_t ntheta=20, Double_t themin=0., Double_t themax=180., Int_t nphi=60, Double_t phimin=0., Double_t phimax=360., Double_t rmin=0., Double_t rmax=9999999, Option_t *option="")
Generate a lego plot fot the top volume, according to option.
void Draw(Option_t *option="") override
draw top volume according to option
TGeoVoxelFinder * fVoxels
Definition TGeoVolume.h:50
TGeoMaterial * GetMaterial() const
Definition TGeoVolume.h:175
virtual Bool_t IsVolumeMulti() const
Definition TGeoVolume.h:111
TGeoExtension * GrabUserExtension() const
Get a copy of the user extension pointer.
@ kVolumeSelected
Definition TGeoVolume.h:73
@ kVolumeImportNodes
Definition TGeoVolume.h:76
Int_t CountNodes(Int_t nlevels=1000, Int_t option=0)
Count total number of subnodes starting from this volume, nlevels down.
void GrabFocus()
Move perspective view focus to this volume.
void UnmarkSaved()
Reset SavePrimitive bits.
void ExecuteEvent(Int_t event, Int_t px, Int_t py) override
Execute mouse actions on this volume.
virtual TGeoVolume * CloneVolume() const
Clone this volume.
void SetFinder(TGeoPatternFinder *finder)
Definition TGeoVolume.h:245
Int_t GetNdaughters() const
Definition TGeoVolume.h:363
Bool_t IsValid() const
Definition TGeoVolume.h:155
void Grab()
Definition TGeoVolume.h:137
void CheckGeometry(Int_t nrays=1, Double_t startx=0, Double_t starty=0, Double_t startz=0) const
Shoot nrays with random directions from starting point (startx, starty, startz) in the reference fram...
void SelectVolume(Bool_t clear=kFALSE)
Select this volume as matching an arbitrary criteria.
const char * GetPointerName() const
Provide a pointer name containing uid.
static TClass * Class()
TObjArray * GetNodes()
Definition TGeoVolume.h:170
void ClearShape()
Clear the shape of this volume from the list held by the current manager.
void SetFWExtension(TGeoExtension *ext)
Connect framework defined extension to the volume.
void VisibleDaughters(Bool_t vis=kTRUE)
set visibility for daughters
void FindOverlaps() const
loop all nodes marked as overlaps and find overlapping brothers
virtual void AddNodeOverlap(TGeoVolume *vol, Int_t copy_no, TGeoMatrix *mat=nullptr, Option_t *option="")
Add a TGeoNode to the list of nodes.
TGeoNode * GetNode(const char *name) const
get the pointer to a daughter node
Int_t DistancetoPrimitive(Int_t px, Int_t py) override
compute the closest distance of approach from point px,py to this volume
void RandomPoints(Int_t npoints=1000000, Option_t *option="")
Draw random points in the bounding box of this volume.
void CheckShapes()
check for negative parameters in shapes.
void SetNtotal(Int_t ntotal)
Definition TGeoVolume.h:247
Bool_t GetOptimalVoxels() const
Returns true if cylindrical voxelization is optimal.
TGeoNode * ReplaceNode(TGeoNode *nodeorig, TGeoShape *newshape=nullptr, TGeoMatrix *newpos=nullptr, TGeoMedium *newmed=nullptr)
Replace an existing daughter with a new volume having the same name but possibly a new shape,...
void InvisibleAll(Bool_t flag=kTRUE)
Make volume and each of it daughters (in)visible.
Bool_t IsVisibleDaughters() const
Definition TGeoVolume.h:157
TString fOption
! option - if any
Definition TGeoVolume.h:54
Int_t GetIndex(const TGeoNode *node) const
get index number for a given daughter
void SetNodes(TObjArray *nodes)
Definition TGeoVolume.h:224
TGeoPatternFinder * GetFinder() const
Definition TGeoVolume.h:178
void PrintVoxels() const
Print the voxels for this volume.
TGeoExtension * fUserExtension
! Transient user-defined extension to volumes
Definition TGeoVolume.h:59
virtual void SetMedium(TGeoMedium *medium)
Definition TGeoVolume.h:243
TGeoVoxelFinder * GetVoxels() const
Getter for optimization structure.
void SetAttVisibility(Bool_t vis)
Definition TGeoVolume.h:234
~TGeoVolume() override
Destructor.
void SetShape(const TGeoShape *shape)
set the shape associated with this volume
static TGeoMedium * DummyMedium()
TObject * fField
! just a hook for now
Definition TGeoVolume.h:53
void SetLineColor(Color_t lcolor) override
Set the line color.
Int_t GetNumber() const
Definition TGeoVolume.h:185
void SavePrimitive(std::ostream &out, Option_t *option="") override
Save a primitive as a C++ statement(s) on output stream "out".
void CleanAll()
Clean data of the volume.
Bool_t IsTopVolume() const
True if this is the top volume of the geometry.
TGeoMedium * fMedium
Definition TGeoVolume.h:47
TGeoShape * GetShape() const
Definition TGeoVolume.h:191
void InspectMaterial() const
Inspect the material for this volume.
void PrintNodes() const
print nodes
static TGeoMedium * fgDummyMedium
! dummy medium
Definition TGeoVolume.h:48
void RegisterYourself(Option_t *option="")
Register the volume and all materials/media/matrices/shapes to the manager.
void CheckOverlaps(Double_t ovlp=0.1, Option_t *option="")
Overlap checking tool. Check for illegal overlaps within a limit OVLP.
TGeoVolume(const TGeoVolume &)=delete
virtual TGeoVolume * Divide(const char *divname, Int_t iaxis, Int_t ndiv, Double_t start, Double_t step, Int_t numed=0, Option_t *option="")
Division a la G3.
Bool_t IsRaytracing() const
Check if the painter is currently ray-tracing the content of this volume.
void SaveAs(const char *filename="", Option_t *option="") const override
Save geometry having this as top volume as a C++ macro.
TGeoShape * fShape
Definition TGeoVolume.h:46
void SetField(TObject *field)
Definition TGeoVolume.h:232
static TGeoVolume * Import(const char *filename, const char *name="", Option_t *option="")
Import a volume from a file.
Bool_t IsStyleDefault() const
check if the visibility and attributes are the default ones
Char_t fTransparency
Definition TGeoVolume.h:58
static void CreateDummyMedium()
Create a dummy medium.
TGeoExtension * fFWExtension
! Transient framework-defined extension to volumes
Definition TGeoVolume.h:60
void SetAsTopVolume()
Set this volume as the TOP one (the whole geometry starts from here).
Bool_t IsVisLeaves() const
Definition TGeoVolume.h:159
Option_t * GetOption() const override
Definition TGeoVolume.h:188
TObject * GetField() const
Definition TGeoVolume.h:177
TGeoPatternFinder * fFinder
Definition TGeoVolume.h:49
Int_t Export(const char *filename, const char *name="", Option_t *option="")
Export this volume to a file.
virtual void DrawOnly(Option_t *option="")
draw only this volume
void SetLineStyle(Style_t lstyle) override
Set the line style.
void SetOption(const char *option)
Set the current options (none implemented).
virtual Bool_t IsAssembly() const
Returns true if the volume is an assembly or a scaled assembly.
TGeoVolume * MakeReflectedVolume(const char *newname="") const
Make a copy of this volume which is reflected with respect to XY plane.
TObjArray * fNodes
Definition TGeoVolume.h:45
virtual Bool_t IsVisible() const
Definition TGeoVolume.h:156
Int_t GetNtotal() const
Definition TGeoVolume.h:172
void SetVisLeaves(Bool_t flag=kTRUE) override
Set visibility for leaves.
void InspectShape() const
Definition TGeoVolume.h:196
Bool_t IsFolder() const override
Return TRUE if volume contains nodes.
TGeoNode * FindNode(const char *name) const
search a daughter inside the list of nodes
void SetOverlappingCandidate(Bool_t flag)
Definition TGeoVolume.h:229
Bool_t IsOverlappingCandidate() const
Definition TGeoVolume.h:149
Int_t fRefCount
Definition TGeoVolume.h:57
void Streamer(TBuffer &) override
Stream an object of class TGeoVolume.
void CheckShape(Int_t testNo, Int_t nsamples=10000, Option_t *option="")
Tests for checking the shape navigation algorithms. See TGeoShape::CheckShape().
Finder class handling voxels.
virtual void Voxelize(Option_t *option="")
Voxelize attached volume according to option If the volume is an assembly, make sure the bbox is comp...
void Draw(Option_t *option="") override
Draw this histogram with options.
Definition TH1.cxx:3097
2-D histogram with a float per channel (see TH1 documentation)
Definition TH2.h:345
Book space in a file, create I/O buffers, to fill them, (un)compress them.
Definition TKey.h:28
virtual const char * GetClassName() const
Definition TKey.h:77
virtual TObject * ReadObj()
To read a TObject* from the file.
Definition TKey.cxx:792
TMap implements an associative array of (key,value) pairs using a THashTable for efficient retrieval ...
Definition TMap.h:40
virtual void SetTitle(const char *title="")
Set the title of the TNamed.
Definition TNamed.cxx:173
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
const char * GetTitle() const override
Returns title of object.
Definition TNamed.h:50
TString fTitle
Definition TNamed.h:33
TNamed()
Definition TNamed.h:38
TString fName
Definition TNamed.h:32
virtual void SetName(const char *name)
Set the name of the TNamed.
Definition TNamed.cxx:149
An array of TObjects.
Definition TObjArray.h:31
Int_t GetEntriesFast() const
Definition TObjArray.h:58
void Clear(Option_t *option="") override
Remove all objects from the array.
virtual void AddAtAndExpand(TObject *obj, Int_t idx)
Add object at position idx.
TObject * At(Int_t idx) const override
Definition TObjArray.h:170
void Add(TObject *obj) override
Definition TObjArray.h:68
Bool_t TestBit(UInt_t f) const
Definition TObject.h:204
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition TObject.cxx:227
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx:1084
virtual void SavePrimitive(std::ostream &out, Option_t *option="")
Save a primitive as a C++ statement(s) on output stream "out".
Definition TObject.cxx:858
virtual Int_t Write(const char *name=nullptr, Int_t option=0, Int_t bufsize=0)
Write this object to the current directory.
Definition TObject.cxx:989
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition TObject.cxx:888
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition TObject.cxx:549
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1098
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
Definition TObject.cxx:1126
virtual void SetUniqueID(UInt_t uid)
Set the unique object id.
Definition TObject.cxx:899
TObject()
TObject constructor.
Definition TObject.h:259
void ResetBit(UInt_t f)
Definition TObject.h:203
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition TObject.cxx:1072
Sequenceable collection abstract base class.
Stopwatch class.
Definition TStopwatch.h:28
Double_t RealTime()
Stop the stopwatch (if it is running) and return the realtime (in seconds) passed between the start a...
void Start(Bool_t reset=kTRUE)
Start the stopwatch.
void Stop()
Stop the stopwatch.
Basic string class.
Definition TString.h:138
Ssiz_t Length() const
Definition TString.h:425
void ToLower()
Change string to lower-case.
Definition TString.cxx:1189
const char * Data() const
Definition TString.h:384
Bool_t IsNull() const
Definition TString.h:422
TString & Remove(Ssiz_t pos)
Definition TString.h:694
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString.
Definition TString.cxx:2385
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition TString.h:641
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition TString.h:660
Abstract class for geometry painters.
virtual void SetTopVolume(TGeoVolume *vol)=0
virtual void ModifiedPad(Bool_t update=kFALSE) const =0
virtual void DrawVolume(TGeoVolume *vol, Option_t *option="")=0
virtual void GrabFocus(Int_t nfr=0, Double_t dlong=0, Double_t dlat=0, Double_t dpsi=0)=0
virtual Int_t DistanceToPrimitiveVol(TGeoVolume *vol, Int_t px, Int_t py)=0
void Paint(Option_t *option="") override=0
This method must be overridden if a class wants to paint itself.
virtual TGeoVolume * GetDrawnVolume() const =0
virtual const char * GetVolumeInfo(const TGeoVolume *volume, Int_t px, Int_t py) const =0
virtual void ExecuteVolumeEvent(TGeoVolume *volume, Int_t event, Int_t px, Int_t py)=0
STL class.
Double_t y[n]
Definition legend1.C:17
Double_t x[n]
Definition legend1.C:17
const Int_t n
Definition legend1.C:16
Bool_t IsImplicitMTEnabled()
Returns true if the implicit multi-threading in ROOT is enabled.
Definition TROOT.cxx:669
UInt_t GetThreadPoolSize()
Returns the size of ROOT's thread pool.
Definition TROOT.cxx:676
Int_t fCurrent
! index of current selected node
Definition TGeoVolume.h:320
Int_t fNext
! index of next node to be entered
Definition TGeoVolume.h:321