Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
REveGeoOverlaps.cxx
Go to the documentation of this file.
1
7
8#include "TGeoBBox.h"
9#include "TGeoManager.h"
10#include "TGeoNode.h"
11#include "TGeoOverlap.h"
12#include "TGeoShape.h"
13#include "TGeoVolume.h"
14#include "TObjArray.h"
15#include "TPolyMarker3D.h"
16
17#include <algorithm>
18#include <cmath>
19#include <cstdio>
20#include <map>
21#include <set>
22#include <utility>
23
24using namespace ROOT::Experimental;
25
26namespace {
27
28/// Volume plus matrix is what ties a TGeoOverlap to a daughter, since it never
29/// names the node itself.
30bool SameMatrix(const TGeoMatrix *a, const TGeoMatrix *b)
31{
32 constexpr double tol = 1e-9;
33 if (!a || !b)
34 return false;
35 const Double_t *ta = a->GetTranslation(), *tb = b->GetTranslation();
36 for (int i = 0; i < 3; ++i)
37 if (std::fabs(ta[i] - tb[i]) > tol)
38 return false;
39 const Double_t *ra = a->GetRotationMatrix(), *rb = b->GetRotationMatrix();
40 for (int i = 0; i < 9; ++i)
41 if (std::fabs(ra[i] - rb[i]) > tol)
42 return false;
43 return true;
44}
45
46bool IsDaughter(TGeoVolume *mom, TGeoVolume *vol, const TGeoMatrix *matr)
47{
48 if (!mom || !vol || !matr)
49 return false;
50 for (int d = 0; d < mom->GetNdaughters(); ++d) {
51 TGeoNode *node = mom->GetNode(d);
52 if (node->GetVolume() == vol && SameMatrix(node->GetMatrix(), matr))
53 return true;
54 }
55 return false;
56}
57
58bool IsFinitePoint(const Float_t *p)
59{
60 return std::isfinite(p[0]) && std::isfinite(p[1]) && std::isfinite(p[2]);
61}
62
63bool InsideWorld(const Float_t *p, double limit)
64{
65 if (limit <= 0.)
66 return true;
67 return std::fabs(p[0]) <= limit && std::fabs(p[1]) <= limit && std::fabs(p[2]) <= limit;
68}
69
70/// A representative size for a volume's shape, for scaling a marker to fit
71/// next to it. TGeoBBox is the common ancestor of nearly every TGeoShape
72/// subclass -- tubes, cones, trapezoids all derive from it and fill in its
73/// dx/dy/dz via their own ComputeBBox() -- so this isn't limited to literal
74/// boxes. The *smallest* half-extent is what matters: a thin plate a metre
75/// wide and a millimetre thick is a millimetre-scale feature, not a metre-scale
76/// one, and a cross sized off the wrong dimension would stick out past it.
77double ShapeSize(TGeoVolume *vol)
78{
79 if (!vol || !vol->GetShape())
80 return 0.;
81 if (auto *bbox = dynamic_cast<TGeoBBox *>(vol->GetShape()))
82 return std::min({bbox->GetDX(), bbox->GetDY(), bbox->GetDZ()});
83 return 0.;
84}
85
86} // namespace
87
88////////////////////////////////////////////////////////////////////////////////
89
91{
92 fHolder = new REveElement("OverlapViz", "Shapes of the selected overlap");
93}
94
95////////////////////////////////////////////////////////////////////////////////
96/// Find every overlap and extrusion in the geometry and work out where each one is.
97///
98/// One pass over the top volume. CheckOverlaps() is recursive, so checking volumes
99/// one at a time would repeat the same work and cost seconds each time.
100
102{
103 fMgr = mgr;
104 fEntries.clear();
105 fSelected = -1;
106 fPrecision = precision;
107 ++fScanGen;
108
109 if (!mgr || !mgr->GetTopVolume())
110 return;
111
112 // CheckOverlaps() needs a navigator for whichever thread calls it -- its very
113 // first line is SetCheckingOverlaps(), which crashes on a null navigator. The
114 // initial scan runs on the main thread, which already has one from loading the
115 // geometry; a rescan from SetPrecision() runs on REveManager's MIR-exec thread,
116 // which does not.
117 if (!mgr->GetCurrentNavigator())
118 mgr->AddNavigator();
119
120 mgr->ClearOverlaps();
121 mgr->GetTopVolume()->CheckOverlaps(precision);
122
123 TObjArray *lst = mgr->GetListOfOverlaps();
124 if (!lst)
125 return;
126
127 // Mother candidates per volume. Only genuine overlaps need this -- there both
128 // sides are daughters of some common mother; an extrusion names its mother itself.
129 std::map<TGeoVolume *, std::vector<TGeoVolume *>> mothers;
130 bool mothersBuilt = false;
131 auto buildMothers = [&mothers, mgr]() {
132 TIter next(mgr->GetListOfVolumes());
133 while (auto *vol = static_cast<TGeoVolume *>(next()))
134 for (int d = 0; d < vol->GetNdaughters(); ++d)
135 mothers[vol->GetNode(d)->GetVolume()].emplace_back(vol);
136 };
137
138 // Every TGeoVolume* actually placed somewhere under top. A candidate mother
139 // can satisfy IsDaughter() below (right daughters, right matrices) and still
140 // be the wrong pick: some geometries (ALICE's does) carry two structurally
141 // identical TGeoVolume objects sharing one name, only one of which the real
142 // tree ever places -- the other is a registered-but-orphaned duplicate.
143 // IsDaughter() alone can't tell them apart since it only ever looks at a
144 // candidate's own local daughter list, never at whether the candidate itself
145 // is reachable, so that has to be checked separately.
146 std::set<TGeoVolume *> reachable;
147 bool reachableBuilt = false;
148 auto buildReachable = [&reachable, mgr]() {
149 TGeoVolume *top = mgr->GetTopVolume();
150 reachable.insert(top);
151 TGeoIterator iter(top);
152 TGeoNode *node = nullptr;
153 while ((node = iter.Next()))
154 reachable.insert(node->GetVolume());
155 };
156
157 // A coarse fuse against numeric garbage. TGeoOverlap's points are in the
158 // mother's own (small) local frame -- see LocalizeMarkers() -- so anything
159 // legitimate is nowhere near the size of the world; this only exists to catch
160 // outright nonsense (CMS has points out at 1e16) before it ever reaches a
161 // TGeoShape::Contains()/Safety() call. LocalizeMarkers() does the real,
162 // targeted filtering once the mother/daughters are known.
163 double worldLimit = 0.;
164 if (auto *wbox = dynamic_cast<TGeoBBox *>(mgr->GetTopVolume()->GetShape()))
165 worldLimit = 2. * std::max(wbox->GetDX(), std::max(wbox->GetDY(), wbox->GetDZ())) + 100.;
166
167 std::vector<std::vector<float>> rawMarkers; // mother-local points, kept until the mother is known
168
169 for (int i = 0; i < lst->GetEntriesFast(); ++i) {
170 auto *ovl = dynamic_cast<TGeoOverlap *>(lst->At(i));
171 if (!ovl)
172 continue;
173
174 Entry ent;
175 ent.fName = ovl->GetName() ? ovl->GetName() : "";
176 ent.fTitle = ovl->GetTitle() ? ovl->GetTitle() : "";
177 ent.fExtrusion = ovl->IsExtrusion();
178 ent.fValue = ovl->GetOverlap();
179 ent.fV1 = ovl->GetFirstVolume();
180 ent.fV2 = ovl->GetSecondVolume();
181 ent.fVol1 = ent.fV1 ? ent.fV1->GetName() : "";
182 ent.fVol2 = ent.fV2 ? ent.fV2->GetName() : "";
183 if (ovl->GetFirstMatrix())
184 ent.fM1 = *ovl->GetFirstMatrix();
185 if (ovl->GetSecondMatrix())
186 ent.fM2 = *ovl->GetSecondMatrix();
187
188 if (ent.fExtrusion) {
189 ent.fMother = ent.fV1;
190 } else {
191 if (!mothersBuilt) {
192 buildMothers();
193 mothersBuilt = true;
194 }
195 if (!reachableBuilt) {
197 reachableBuilt = true;
198 }
199 auto it = mothers.find(ent.fV1);
200 if (it != mothers.end())
201 for (auto *cand : it->second)
202 if (reachable.count(cand) && IsDaughter(cand, ent.fV1, ovl->GetFirstMatrix()) &&
203 IsDaughter(cand, ent.fV2, ovl->GetSecondMatrix())) {
204 ent.fMother = cand;
205 break;
206 }
207 }
208
209 // Without a mother there is no frame to place it in. Drawing it anyway would
210 // put it somewhere arbitrary, which is worse than leaving it out.
211 if (!ent.fMother)
212 continue;
213
214 std::vector<float> pts;
215 if (TPolyMarker3D *pm = ovl->GetPolyMarker()) {
216 const Float_t *p = pm->GetP();
217 ent.fNumRawMarkers = pm->GetN();
218 pts.reserve(3 * pm->GetN());
219 for (int k = 0; k < pm->GetN(); ++k)
220 if (IsFinitePoint(p + 3 * k) && InsideWorld(p + 3 * k, worldLimit)) {
221 pts.push_back(p[3 * k]);
222 pts.push_back(p[3 * k + 1]);
223 pts.push_back(p[3 * k + 2]);
224 }
225 }
226
227 fEntries.emplace_back(std::move(ent));
228 rawMarkers.emplace_back(std::move(pts));
229 }
230
232
233 for (size_t i = 0; i < fEntries.size(); ++i)
235
236 BuildGroups();
237
239}
240
241////////////////////////////////////////////////////////////////////////////////
242/// Global matrix of every physical placement of each mother volume.
243///
244/// One walk of the geometry serves all entries; the set of mothers is small (four
245/// volumes for the CMS geometry) but finding them needs the full traversal anyway.
246
248{
249 std::set<TGeoVolume *> wanted;
250 for (auto &ent : fEntries)
251 wanted.insert(ent.fMother);
252
253 std::map<TGeoVolume *, std::vector<TGeoHMatrix>> found;
254
255 TGeoVolume *top = mgr->GetTopVolume();
256 if (wanted.count(top))
257 found[top].emplace_back(TGeoHMatrix()); // identity: the top volume is the world
258
259 TGeoIterator iter(top);
260 TGeoNode *node = nullptr;
261 while ((node = iter.Next())) {
262 TGeoVolume *vol = node->GetVolume();
263 if (!wanted.count(vol))
264 continue;
265 const TGeoMatrix *cur = iter.GetCurrentMatrix();
266 found[vol].emplace_back(cur ? TGeoHMatrix(*cur) : TGeoHMatrix());
267 }
268
269 for (auto &ent : fEntries) {
270 auto it = found.find(ent.fMother);
271 if (it != found.end())
272 ent.fGlobals = it->second;
273 }
274}
275
276////////////////////////////////////////////////////////////////////////////////
277/// Filter the marker points down to the ones that plausibly belong to this flaw.
278///
279/// TGeoOverlap's TPolyMarker3D is filled in the frame of whichever node
280/// CheckOverlaps() was examining -- i.e. already the mother's own local frame,
281/// the same one fM1/fM2 are expressed in. There is no placement to guess and no
282/// conversion to do: the points already are what they need to be.
283///
284/// What *is* still worth doing is dropping outliers: TGeoOverlap's own points
285/// can be finite and plausible-looking while sitting nowhere near either
286/// daughter, and for a flaw a fraction of a millimeter across that's glaring --
287/// the crude "inside the world" fuse applied before this function is far too
288/// loose to catch it (it exists only to stop outright numeric garbage, not to
289/// judge plausibility). So each point is tested against the two daughter
290/// shapes it should be between and dropped if it's near neither.
291///
292/// The shapes involved can be anything the geometry uses -- a tube, a
293/// composite, not just a box -- so the test goes through
294/// TGeoShape::Contains()/Safety() rather than assuming a TGeoBBox.
295
297{
298 ent.fLocalMarkers.clear();
299 if (localPts.empty())
300 return;
301
302 const size_t npt = localPts.size() / 3;
303
304 // a little slack: the points sit on the offending surface, not strictly inside
305 const double margin = 1.0;
306 const double farAway = 1.e6; // stands in for "no daughter to test against"
307
308 auto daughterDistance = [](TGeoVolume *vol, const TGeoHMatrix &local, const Double_t *lp) {
309 if (!vol || !vol->GetShape())
310 return -1.; // no shape to test: not a vote against, just not informative
311 Double_t dl[3];
312 local.MasterToLocal(lp, dl); // lp is mother-local; bring it into the daughter's own frame
313 if (vol->GetShape()->Contains(dl))
314 return 0.;
315 return vol->GetShape()->Safety(dl, kFALSE);
316 };
317
318 // For an extrusion, fV1 *is* the mother -- testing a point against the whole
319 // mother would accept almost anything inside it, so only genuine daughters
320 // (not the mother itself) are tested.
321 bool testV1 = ent.fV1 && ent.fV1 != ent.fMother;
322 bool testV2 = ent.fV2 && ent.fV2 != ent.fMother;
323
324 // Distance from lp to the nearer of the two daughters, or 0 if neither is
325 // testable (nothing to judge the point against, so don't disqualify it).
326 auto distance = [&](const Double_t *lp) {
327 if (!testV1 && !testV2)
328 return 0.;
329 double d1 = testV1 ? daughterDistance(ent.fV1, ent.fM1, lp) : farAway;
330 double d2 = testV2 ? daughterDistance(ent.fV2, ent.fM2, lp) : farAway;
331 return std::min(d1 < 0. ? farAway : d1, d2 < 0. ? farAway : d2);
332 };
333
334 ent.fLocalMarkers.reserve(localPts.size());
335 for (size_t k = 0; k < npt; ++k) {
336 Double_t lp[3] = {localPts[3 * k], localPts[3 * k + 1], localPts[3 * k + 2]};
337 if (distance(lp) > margin)
338 continue;
339 ent.fLocalMarkers.push_back(localPts[3 * k]);
340 ent.fLocalMarkers.push_back(localPts[3 * k + 1]);
341 ent.fLocalMarkers.push_back(localPts[3 * k + 2]);
342 }
343}
344
345////////////////////////////////////////////////////////////////////////////////
346/// Text shown when the mouse is over one of the drawn pieces.
347///
348/// The client puts this straight into innerHTML, so <br> works and one element can
349/// carry the whole story: which flaw, how big, which two volumes, and -- the part
350/// that is otherwise impossible to tell by looking -- which placement out of how
351/// many this particular piece is.
352///
353/// \param which 0 = first volume, 1 = second volume, 2 = the marker points
354
355std::string REveGeoOverlapTable::MakeTip(const Entry &ent, int which, int placement, int inst, int ninst) const
356{
357 TString t;
358 t += TString::Format("<b>%s</b> &middot; %s &middot; <b>%.5f cm</b><br>", ent.fName.c_str(),
359 ent.fExtrusion ? "extrusion" : "overlap", ent.fValue);
360
361 // mark the volume this piece actually is
362 t += TString::Format("%sA %s%s<br>", which == 0 ? "<b>" : "", ent.fVol1.c_str(), which == 0 ? "</b>" : "");
363 t += TString::Format("%sB %s%s<br>", which == 1 ? "<b>" : "", ent.fVol2.c_str(), which == 1 ? "</b>" : "");
364
365 if (ent.fMother)
366 t += TString::Format("in %s<br>", ent.fMother->GetName());
367
368 if (ent.fGlobals.size() > 1)
369 t += TString::Format("placement %d of %d<br>", placement + 1, (int)ent.fGlobals.size());
370
371 if (ninst > 1)
372 t += TString::Format("instance %d of %d<br>", inst + 1, ninst);
373
374 if (which == 2) {
375 int kept = (int)(ent.fLocalMarkers.size() / 3);
376 int dropped = ent.fNumRawMarkers - kept;
377 if (dropped > 0)
378 t += TString::Format("%d points (%d dropped as out of range)", kept, dropped);
379 else
380 t += TString::Format("%d points", kept);
381 }
382
383 return std::string(t.Data());
384}
385
386////////////////////////////////////////////////////////////////////////////////
387/// Draw one placement of the selected overlap: the two shapes and the points.
388
390 std::set<std::string> *seen, int inst, int ninst)
391{
392 auto addShape = [&](TGeoVolume *vol, const TGeoHMatrix &local, Color_t col, const char *tag, int which) {
393 if (!vol || !vol->GetShape())
394 return;
396 m.Multiply(&local);
397
398 // Drawing a whole group would otherwise stack 36 identical copies of the
399 // shared mother on top of each other -- same volume, same matrix, no extra
400 // information and a much heavier scene.
401 if (seen) {
402 const Double_t *t = m.GetTranslation(), *r = m.GetRotationMatrix();
403 char key[512];
404 int n = snprintf(key, sizeof(key), "%p|%.4f,%.4f,%.4f", (void *)vol, t[0], t[1], t[2]);
405 for (int i = 0; i < 9 && n < (int)sizeof(key); ++i)
406 n += snprintf(key + n, sizeof(key) - n, ",%.6f", r[i]);
407 if (!seen->insert(key).second)
408 return;
409 }
410 // REveGeoShape uses TGeoShape::UniqueID as a reference count and deletes the
411 // shape when it drops to zero. The shapes here belong to the TGeoManager and
412 // do not take part in that scheme, so handing one over directly means the
413 // geometry's own shape is deleted as soon as these elements are destroyed --
414 // which happens on the very next selection. Give each element a private clone.
415 auto *geoShape = static_cast<TGeoShape *>(vol->GetShape()->Clone());
416 if (!geoShape)
417 return;
418 geoShape->SetUniqueID(0);
419
420 auto *shape = new REveGeoShape(TString::Format("%s_%s_%s", ent.fName.c_str(), tag, vol->GetName()).Data(),
421 MakeTip(ent, which, placement, inst, ninst).c_str());
422 shape->SetShape(geoShape);
423 shape->SetTransMatrix(m);
424 shape->SetMainColor(col);
425 shape->SetMainTransparency(50);
426 // fPickable defaults to false, and without it the element never enters the
427 // pick pass at all -- no highlight and no tooltip, with nothing to say why.
428 shape->SetPickable(kTRUE);
429 fHolder->AddElement(shape);
430 };
431
432 addShape(ent.fV1, ent.fM1, kRed, "A", 0);
433 addShape(ent.fV2, ent.fM2, kYellow, "B", 1);
434
435 if (ent.fLocalMarkers.empty())
436 return;
437
438 const size_t npt = ent.fLocalMarkers.size() / 3;
439 auto *ps = new REvePointSet(TString::Format("%s_points", ent.fName.c_str()).Data(),
440 MakeTip(ent, 2, placement, inst, ninst).c_str(), npt);
441 ps->SetMarkerColor(kCyan);
442 ps->SetMarkerSize(fMarkerSize);
443 ps->SetPickable(kTRUE);
444 ps->SetMarkerStyle(4);
445
446 // A GL point can vanish behind a transparent volume depending on draw order,
447 // so give every marker a second, harder-to-hide representation: a 3D cross,
448 // three lines through the point along x/y/z.
449 auto *cross = new REveStraightLineSet(TString::Format("%s_cross", ent.fName.c_str()).Data(),
450 MakeTip(ent, 2, placement, inst, ninst).c_str());
451 cross->SetMainColor(kCyan);
452 cross->SetLineWidth(2);
453 cross->SetPickable(kTRUE);
454
455 // Scaled to the smaller of the two daughters, not a flat constant: entries in
456 // this table range from a 33 cm overlap down to a 0.02 cm one, and a fixed
457 // arm length is either invisible against the big one or many times the size
458 // of the small one. fCrossSize remains the cap, in cm, it always was --
459 // still tunable via SetCrossSize() -- but the arm only uses that much of it
460 // when the smaller shape is actually big enough to warrant it; otherwise it
461 // scales down to a fraction of that shape instead of overshooting it.
462 constexpr double kCrossFraction = 0.3; // arm half-length as a fraction of the smaller daughter's thinnest dimension
463 double s1 = ShapeSize(ent.fV1), s2 = ShapeSize(ent.fV2);
464 double smallest = (s1 > 0. && s2 > 0.) ? std::min(s1, s2) : std::max(s1, s2);
466 const float h = (float)std::min(proportional, (double)fCrossSize);
467
468 for (size_t k = 0; k < npt; ++k) {
469 Double_t lp[3] = {ent.fLocalMarkers[3 * k], ent.fLocalMarkers[3 * k + 1], ent.fLocalMarkers[3 * k + 2]}, gp[3];
470 global.LocalToMaster(lp, gp);
471 ps->SetNextPoint((float)gp[0], (float)gp[1], (float)gp[2]);
472
473 float x = (float)gp[0], y = (float)gp[1], z = (float)gp[2];
474 cross->AddLine(x - h, y, z, x + h, y, z);
475 cross->AddLine(x, y - h, z, x, y + h, z);
476 cross->AddLine(x, y, z - h, x, y, z + h);
477 }
478 fHolder->AddElement(ps);
479 fHolder->AddElement(cross);
480}
481
482////////////////////////////////////////////////////////////////////////////////
483/// Show one overlap and nothing else. Called from the client as a MIR when a row
484/// is picked; a negative index just clears the view.
485
487{
489
490 fSelected = ((idx >= 0) && (idx < (int)fEntries.size())) ? idx : -1;
491 fSelectedGroup = -1;
492
493 if (fSelected >= 0) {
494 const Entry &ent = fEntries[fSelected];
495 for (size_t p = 0; p < ent.fGlobals.size(); ++p)
496 AddPlacement(ent, ent.fGlobals[p], (int)p);
497 }
498
501}
502
503////////////////////////////////////////////////////////////////////////////////
504/// Collapse entries that are the same flaw repeated.
505///
506/// Two entries belong together when they are the same kind of problem between the
507/// same pair of logical volumes. The value is the same across a group in practice,
508/// but the largest is kept rather than assumed.
509
511{
512 fGroups.clear();
513 std::map<std::string, int> index;
514
515 for (size_t i = 0; i < fEntries.size(); ++i) {
516 const Entry &e = fEntries[i];
517 std::string key = e.fVol1 + "|" + e.fVol2 + "|" + (e.fExtrusion ? "e" : "o");
518 auto it = index.find(key);
519 if (it == index.end()) {
520 index[key] = (int)fGroups.size();
521 Group g;
522 g.fVol1 = e.fVol1;
523 g.fVol2 = e.fVol2;
524 g.fExtrusion = e.fExtrusion;
525 g.fValue = e.fValue;
526 g.fMembers.emplace_back((int)i);
527 fGroups.emplace_back(std::move(g));
528 } else {
529 Group &g = fGroups[it->second];
530 g.fMembers.emplace_back((int)i);
531 if (e.fValue > g.fValue)
532 g.fValue = e.fValue;
533 }
534 }
535}
536
537////////////////////////////////////////////////////////////////////////////////
538/// Show every instance of one kind of flaw at once.
539///
540/// Seeing all 36 supermodule extrusions together is the point of the grouped view:
541/// it says at a glance whether the problem is systematic or confined to a few
542/// placements. Shapes are de-duplicated, so the shared mother is drawn once.
543
545{
547 fSelected = -1;
548 fSelectedGroup = ((gidx >= 0) && (gidx < (int)fGroups.size())) ? gidx : -1;
549
550 if (fSelectedGroup >= 0) {
551 std::set<std::string> seen;
552 const auto &mem = fGroups[fSelectedGroup].fMembers;
553 for (size_t k = 0; k < mem.size(); ++k) {
554 const Entry &ent = fEntries[mem[k]];
555 for (size_t p = 0; p < ent.fGlobals.size(); ++p)
556 AddPlacement(ent, ent.fGlobals[p], (int)p, &seen, (int)k, (int)mem.size());
557 }
558 }
559
562}
563
564////////////////////////////////////////////////////////////////////////////////
565/// Re-run whichever selection is current, so a change of appearance takes effect
566/// without the client having to re-pick the row.
567
575
576////////////////////////////////////////////////////////////////////////////////
577/// Marker size for the overlap points. The points are the small thing in a scene
578/// full of large volumes, so this wants to be generous.
579
581{
582 if (size <= 0.f)
583 return;
585 Redraw();
586}
587
588////////////////////////////////////////////////////////////////////////////////
589/// Cap, in cm, on the half-length of each marker's 3D-cross arm. AddPlacement()
590/// scales the actual arm to a fraction of the smaller daughter's size, so this
591/// only bites when that would otherwise exceed it.
592
594{
595 if (size <= 0.f)
596 return;
598 Redraw();
599}
600
601////////////////////////////////////////////////////////////////////////////////
602/// Re-run the overlap check at a new precision and rebuild the table from
603/// scratch. Whatever was selected no longer means anything -- ScanOverlaps()
604/// rebuilds fEntries/fGroups in a new order with new indices -- so the 3D view
605/// is cleared rather than left showing a stale selection.
606
608{
609 if (precision <= 0. || !fMgr)
610 return;
611
613 fSelectedGroup = -1;
614 ScanOverlaps(fMgr, precision); // clears fSelected, resets fPrecision, stamps object props
615}
616
617////////////////////////////////////////////////////////////////////////////////
618/// Print one overlap's details to the server console: name, volumes, mother,
619/// TGeoOverlap's own title (usually the pair of node paths), every placement's
620/// global translation, and how many marker points survived filtering. For
621/// debugging from the client's row context menu -- this doesn't touch the 3D
622/// view or the selection.
623
625{
626
627 if ((idx < 0) || (idx >= (int)fEntries.size())) {
628 printf("REveGeoOverlapTable::PrintOverlap: index %d out of range (%d entries)\n", idx, (int)fEntries.size());
629 fflush(stdout);
630 return;
631 }
632
633 const Entry &e = fEntries[idx];
634 printf("=== %s : %s : %.6f cm ===\n", e.fName.c_str(), e.fExtrusion ? "extrusion" : "overlap", e.fValue);
635 printf(" A: %s\n", e.fVol1.c_str());
636 printf(" B: %s\n", e.fVol2.c_str());
637 printf(" mother: %s\n", e.fMother ? e.fMother->GetName() : "(none)");
638 if (!e.fTitle.empty())
639 printf(" title: %s\n", e.fTitle.c_str());
640 printf(" placements: %d\n", (int)e.fGlobals.size());
641 for (size_t p = 0; p < e.fGlobals.size(); ++p) {
642 const Double_t *t = e.fGlobals[p].GetTranslation();
643 printf(" [%d] translation = (%.4f, %.4f, %.4f)\n", (int)p, t[0], t[1], t[2]);
644 }
645 int kept = (int)(e.fLocalMarkers.size() / 3);
646 printf(" points: %d raw, %d kept (%d dropped)\n", e.fNumRawMarkers, kept, e.fNumRawMarkers - kept);
647 // stdout is fully buffered when it isn't a tty (the normal case for a
648 // long-running web server process), so without this the output just sits in
649 // the buffer indefinitely instead of reaching the terminal.
650 fflush(stdout);
651}
652
653////////////////////////////////////////////////////////////////////////////////
654/// Print a whole group -- every entry sharing this (vol1, vol2, extrusion) --
655/// to the server console, as one PrintOverlap() block per member.
656
658{
659 if ((gidx < 0) || (gidx >= (int)fGroups.size())) {
660 printf("REveGeoOverlapTable::PrintUniqueOverlap: index %d out of range (%d groups)\n", gidx, (int)fGroups.size());
661 fflush(stdout);
662 return;
663 }
664
665 const Group &g = fGroups[gidx];
666 printf("=== group: %s | %s | %s (%d members) ===\n", g.fVol1.c_str(), g.fVol2.c_str(),
667 g.fExtrusion ? "extrusion" : "overlap", (int)g.fMembers.size());
668 for (int ei : g.fMembers)
670}
671
672////////////////////////////////////////////////////////////////////////////////
673
675{
677
678 j["fPrecision"] = fPrecision;
679 j["fScanGen"] = fScanGen;
680 j["fSelected"] = fSelected;
681
682 nlohmann::json arr = nlohmann::json::array();
683 for (size_t i = 0; i < fEntries.size(); ++i) {
684 const Entry &e = fEntries[i];
685 nlohmann::json o = nlohmann::json::object();
686 o["idx"] = (int)i;
687 o["name"] = e.fName;
688 o["kind"] = e.fExtrusion ? "extrusion" : "overlap";
689 o["value"] = e.fValue;
690 o["vol1"] = e.fVol1;
691 o["vol2"] = e.fVol2;
692 o["mother"] = e.fMother ? e.fMother->GetName() : "";
693 o["nplaced"] = (int)e.fGlobals.size();
694 o["npoints"] = (int)(e.fLocalMarkers.size() / 3);
695 o["ndropped"] = e.fNumRawMarkers - (int)(e.fLocalMarkers.size() / 3);
696 o["title"] = e.fTitle;
697 arr.emplace_back(std::move(o));
698 }
699 j["fOverlaps"] = std::move(arr);
700
701 nlohmann::json garr = nlohmann::json::array();
702 for (size_t i = 0; i < fGroups.size(); ++i) {
703 const Group &g = fGroups[i];
704 int npts = 0;
705 for (int ei : g.fMembers)
706 npts += (int)(fEntries[ei].fLocalMarkers.size() / 3);
707 nlohmann::json o = nlohmann::json::object();
708 o["idx"] = (int)i;
709 o["kind"] = g.fExtrusion ? "extrusion" : "overlap";
710 o["value"] = g.fValue;
711 o["vol1"] = g.fVol1;
712 o["vol2"] = g.fVol2;
713 o["ninst"] = (int)g.fMembers.size();
714 o["npoints"] = npts;
715 o["name"] = g.fMembers.empty() ? "" : fEntries[g.fMembers.front()].fName;
716 garr.emplace_back(std::move(o));
717 }
718 j["fGroups"] = std::move(garr);
719 j["fSelectedGroup"] = fSelectedGroup;
720 j["fMarkerSize"] = fMarkerSize;
721 j["fCrossSize"] = fCrossSize;
722
723 return ret;
724}
#define d(i)
Definition RSha256.hxx:102
#define b(i)
Definition RSha256.hxx:100
#define g(i)
Definition RSha256.hxx:105
#define a(i)
Definition RSha256.hxx:99
#define s1(x)
Definition RSha256.hxx:91
#define h(i)
Definition RSha256.hxx:106
#define e(i)
Definition RSha256.hxx:103
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
short Color_t
Color number (short)
Definition RtypesCore.h:100
char Text_t
General string (char)
Definition RtypesCore.h:77
float Float_t
Float 4 bytes (float)
Definition RtypesCore.h:72
constexpr Bool_t kFALSE
Definition RtypesCore.h:109
constexpr Bool_t kTRUE
Definition RtypesCore.h:108
@ kRed
Definition Rtypes.h:66
@ kCyan
Definition Rtypes.h:66
@ kYellow
Definition Rtypes.h:66
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t r
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
virtual Int_t WriteCoreJson(nlohmann::json &cj, Int_t rnr_offset)
Write core json.
virtual void AddElement(REveElement *el)
Add el to the list of children.
virtual void DestroyElements()
Destroy all children of this element.
REveElement(const std::string &name="", const std::string &title="")
Default constructor.
void ScanOverlaps(TGeoManager *mgr, double precision=0.001)
Find every overlap and extrusion in the geometry and work out where each one is.
void SelectOverlap(int idx)
Show one overlap and nothing else.
std::string MakeTip(const Entry &ent, int which, int placement, int inst, int ninst) const
Text shown when the mouse is over one of the drawn pieces.
float fCrossSize
cap, in cm, on the half-length of each marker's 3D-cross arm; AddPlacement() scales the actual arm to...
void AddPlacement(const Entry &ent, const TGeoHMatrix &global, int placement, std::set< std::string > *seen=nullptr, int inst=-1, int ninst=0)
Draw one placement of the selected overlap: the two shapes and the points.
void SetMarkerSize(float size)
Marker size for the overlap points.
REveElement * fHolder
! where the selected overlap is drawn; put this in a 3D scene
TGeoManager * fMgr
! kept from ScanOverlaps() so SetPrecision() can re-run it
void SetPrecision(double precision)
Re-run the overlap check at a new precision and rebuild the table from scratch.
REveGeoOverlapTable(const REveGeoOverlapTable &)=delete
void PrintOverlap(int idx)
Print one overlap's details to the server console: name, volumes, mother, TGeoOverlap's own title (us...
void Redraw()
Re-run whichever selection is current, so a change of appearance takes effect without the client havi...
void SelectUniqueOverlap(int gidx)
Show every instance of one kind of flaw at once.
void LocalizeMarkers(Entry &ent, const std::vector< float > &localPts)
Filter the marker points down to the ones that plausibly belong to this flaw.
int fScanGen
bumped by ScanOverlaps(); lets the client tell a rescan from an ordinary selection stamp
void PrintUniqueOverlap(int gidx)
Print a whole group – every entry sharing this (vol1, vol2, extrusion) – to the server console,...
void SetCrossSize(float size)
Cap, in cm, on the half-length of each marker's 3D-cross arm.
void CollectPlacements(TGeoManager *mgr)
Global matrix of every physical placement of each mother volume.
Int_t WriteCoreJson(nlohmann::json &j, Int_t rnr_offset) override
Write core json.
void BuildGroups()
Collapse entries that are the same flaw repeated.
REveStraightLineSet Set of straight lines with optional markers along the lines.
const_iterator end() const
Box class.
Definition TGeoBBox.h:18
Matrix class used for computing global transformations Should NOT be used for node definition.
Definition TGeoMatrix.h:459
A geometry iterator.
Definition TGeoNode.h:249
const TGeoMatrix * GetCurrentMatrix() const
Returns global matrix for current node.
TGeoNode * Next()
Returns next node.
The manager class for any TGeo geometry.
Definition TGeoManager.h:46
Geometrical transformation package.
Definition TGeoMatrix.h:39
A node represent a volume positioned inside another.They store links to both volumes and to the TGeoM...
Definition TGeoNode.h:39
TGeoVolume * GetVolume() const
Definition TGeoNode.h:100
virtual TGeoMatrix * GetMatrix() const =0
Base class describing geometry overlaps.
Definition TGeoOverlap.h:37
Base abstract class for all shapes.
Definition TGeoShape.h:25
virtual Double_t Safety(const Double_t *point, Bool_t in=kTRUE) const =0
virtual Bool_t Contains(const Double_t *point) const =0
TGeoVolume, TGeoVolumeMulti, TGeoVolumeAssembly are the volume classes.
Definition TGeoVolume.h:45
Int_t GetNdaughters() const
Definition TGeoVolume.h:371
TGeoNode * GetNode(const char *name) const
get the pointer to a daughter node
TGeoShape * GetShape() const
Definition TGeoVolume.h:193
TObject * Clone(const char *newname="") const override
Make a clone of an object using the Streamer facility.
Definition TNamed.cxx:73
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
An array of TObjects.
Definition TObjArray.h:31
A 3D polymarker.
Basic string class.
Definition TString.h:137
const char * Data() const
Definition TString.h:385
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:2460
Double_t y[n]
Definition legend1.C:17
Double_t x[n]
Definition legend1.C:17
const Int_t n
Definition legend1.C:16
Namespace for ROOT features in testing.
Definition TROOT.h:100
One kind of flaw, with every placement of it that the geometry contains.
std::vector< int > fMembers
indices into the entry list
TMarker m
Definition textangle.C:8