Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RGeomData.cxx
Go to the documentation of this file.
1// Author: Sergey Linev, 14.12.2018
2
3/*************************************************************************
4 * Copyright (C) 1995-2023, Rene Brun and Fons Rademakers. *
5 * All rights reserved. *
6 * *
7 * For the licensing terms see $ROOTSYS/LICENSE. *
8 * For the list of contributors see $ROOTSYS/README/CREDITS. *
9 *************************************************************************/
10
11#include <ROOT/RGeomData.hxx>
12
15#include <ROOT/RLogger.hxx>
16#include "CsgOps.h"
17
18#include "TMath.h"
19#include "TColor.h"
20#include "TROOT.h"
21#include "TGeoNode.h"
22#include "TGeoVolume.h"
23#include "TGeoBBox.h"
24#include "TGeoSphere.h"
25#include "TGeoCone.h"
26#include "TGeoTube.h"
27#include "TGeoEltu.h"
28#include "TGeoTorus.h"
29#include "TGeoPcon.h"
30#include "TGeoPgon.h"
31#include "TGeoXtru.h"
32#include "TGeoParaboloid.h"
33#include "TGeoHype.h"
34#include "TGeoTessellated.h"
35#include "TGeoScaledShape.h"
36#include "TGeoCompositeShape.h"
37#include "TGeoManager.h"
38#include "TGeoMatrix.h"
39#include "TGeoMedium.h"
40#include "TGeoMaterial.h"
41#include "TGeoBoolNode.h"
42#include "TBuffer3D.h"
43#include "TBufferJSON.h"
44#include "TRegexp.h"
45
46#include <algorithm>
47#include <array>
48
50{
51 static ROOT::RLogChannel sLog("ROOT.Geom");
52 return sLog;
53}
54
55
56namespace ROOT {
57
58/** Iterator of hierarchical geometry structures */
59
61
63 int fParentId{-1};
64 unsigned fChild{0};
65 int fNodeId{0};
66
67 std::vector<int> fStackParents;
68 std::vector<int> fStackChilds;
69
70public:
71 RGeomBrowserIter(RGeomDescription &desc) : fDesc(desc) {}
72
73 const std::string &GetName() const { return fDesc.fDesc[fNodeId].name; }
74
75 const std::string &GetColor() const { return fDesc.fDesc[fNodeId].color; }
76
77 const std::string &GetMaterial() const { return fDesc.fDesc[fNodeId].material; }
78
79 int GetVisible() const { return fDesc.fDesc[fNodeId].vis; }
80
81 bool IsValid() const { return fNodeId >= 0; }
82
83 int GetNodeId() const { return fNodeId; }
84
85 bool HasChilds() const { return (fNodeId < 0) ? true : !fDesc.fDesc[fNodeId].chlds.empty(); }
86
87 int NumChilds() const { return (fNodeId < 0) ? 1 : fDesc.fDesc[fNodeId].chlds.size(); }
88
89 bool Enter()
90 {
91 if (fNodeId < 0) {
92 Reset();
93 fNodeId = 0;
94 return true;
95 }
96
97 if (fNodeId >= (int)fDesc.fDesc.size())
98 return false;
99
100 auto &node = fDesc.fDesc[fNodeId];
101 if (node.chlds.empty())
102 return false;
103 fStackParents.emplace_back(fParentId);
104 fStackChilds.emplace_back(fChild);
105 fParentId = fNodeId;
106 fChild = 0;
107 fNodeId = node.chlds[fChild];
108 return true;
109 }
110
111 bool Leave()
112 {
113 if (fStackParents.empty()) {
114 fNodeId = -1;
115 return false;
116 }
117 fParentId = fStackParents.back();
118 fChild = fStackChilds.back();
119
120 fStackParents.pop_back();
121 fStackChilds.pop_back();
122
123 if (fParentId < 0) {
124 fNodeId = 0;
125 } else {
126 fNodeId = fDesc.fDesc[fParentId].chlds[fChild];
127 }
128 return true;
129 }
130
131 bool Next()
132 {
133 // does not have parents
134 if ((fNodeId <= 0) || (fParentId < 0)) {
135 Reset();
136 return false;
137 }
138
139 auto &prnt = fDesc.fDesc[fParentId];
140 if (++fChild >= prnt.chlds.size()) {
141 fNodeId = -1; // not valid node, only Leave can be called
142 return false;
143 }
144
145 fNodeId = prnt.chlds[fChild];
146 return true;
147 }
148
149 bool Reset()
150 {
151 fParentId = -1;
152 fNodeId = -1;
153 fChild = 0;
154 fStackParents.clear();
155 fStackChilds.clear();
156
157 return true;
158 }
159
160 bool NextNode()
161 {
162 if (Enter())
163 return true;
164
165 if (Next())
166 return true;
167
168 while (Leave()) {
169 if (Next())
170 return true;
171 }
172
173 return false;
174 }
175
176 /** Navigate to specified path - path specified as string and should start with "/" */
177 bool Navigate(const std::string &path)
178 {
179 size_t pos = path.find('/');
180 if (pos != 0)
181 return false;
182
183 Reset(); // set to the top of element
184
185 while (++pos < path.length()) {
186 auto last = pos;
187
188 pos = path.find('/', last);
189
190 if (pos == std::string::npos)
191 pos = path.length();
192
193 std::string folder = path.substr(last, pos - last);
194
195 if (!Enter())
196 return false;
197
198 bool find = false;
199
200 do {
201 find = (folder.compare(GetName()) == 0);
202 } while (!find && Next());
203
204 if (!find)
205 return false;
206 }
207
208 return true;
209 }
210
211 /** Navigate to specified path */
212 bool Navigate(const std::vector<std::string> &path)
213 {
214 Reset(); // set to the top of element
215
216 for (auto &folder : path) {
217
218 if (!Enter())
219 return false;
220
221 bool find = false;
222
223 do {
224 find = (folder.compare(GetName()) == 0);
225 } while (!find && Next());
226
227 if (!find)
228 return false;
229 }
230
231 return true;
232 }
233
234 /** Navigate to specified volume - find first occurrence */
236 {
237 Reset();
238
239 while (NextNode()) {
240 if (vol == fDesc.GetVolume(GetNodeId()))
241 return true;
242 }
243
244 return false;
245 }
246
247 /// Returns array of ids to currently selected node
248 std::vector<int> CurrentIds() const
249 {
250 std::vector<int> res;
251 if (IsValid()) {
252 for (unsigned n = 1; n < fStackParents.size(); ++n)
253 res.emplace_back(fStackParents[n]);
254 if (fParentId >= 0)
255 res.emplace_back(fParentId);
256 res.emplace_back(fNodeId);
257 }
258 return res;
259 }
260};
261
262} // namespace ROOT
263
264using namespace ROOT;
265
266using namespace std::string_literals;
267
268namespace {
269
270int compare_stacks(const std::vector<int> &stack1, const std::vector<int> &stack2)
271{
272 unsigned len1 = stack1.size(), len2 = stack2.size(), len = (len1 < len2) ? len1 : len2, indx = 0;
273 while (indx < len) {
274 if (stack1[indx] < stack2[indx])
275 return -1;
276 if (stack1[indx] > stack2[indx])
277 return 1;
278 ++indx;
279 }
280
281 if (len1 < len2)
282 return -1;
283 if (len1 > len2)
284 return 1;
285
286 return 0;
287}
288} // namespace
289
290/////////////////////////////////////////////////////////////////////
291/// Issue signal, which distributed on all handlers - excluding source handler
292
293void RGeomDescription::IssueSignal(const void *handler, const std::string &kind)
294{
295 std::vector<RGeomSignalFunc_t> funcs;
296
297 {
298 TLockGuard lock(fMutex);
299 for (auto &pair : fSignals)
300 if (!handler || (pair.first != handler))
301 funcs.emplace_back(pair.second);
302 }
303
304 // invoke signal outside locked mutex to avoid any locking
305 for (auto func : funcs)
306 func(kind);
307}
308
309/////////////////////////////////////////////////////////////////////
310/// Add signal handler
311
313{
314 TLockGuard lock(fMutex);
315 fSignals.emplace_back(handler, func);
316}
317
318/////////////////////////////////////////////////////////////////////
319/// Remove signal handler
320
322{
323 TLockGuard lock(fMutex);
324
325 for (auto iter = fSignals.begin(); iter != fSignals.end(); ++iter)
326 if (handler == iter->first) {
327 fSignals.erase(iter);
328 return;
329 }
330}
331
332/////////////////////////////////////////////////////////////////////
333/// Pack matrix into vector, which can be send to client
334/// Following sizes can be used for vector:
335/// 0 - Identity matrix
336/// 3 - Translation
337/// 4 - Scale (last element always 1)
338/// 9 - Rotation
339/// 16 - Full size
340
341void RGeomDescription::PackMatrix(std::vector<float> &vect, TGeoMatrix *matr)
342{
343 vect.clear();
344
345 if (!matr || matr->IsIdentity())
346 return;
347
348 auto trans = matr->GetTranslation();
349 auto scale = matr->GetScale();
350 auto rotate = matr->GetRotationMatrix();
351
352 bool is_translate = matr->IsA() == TGeoTranslation::Class(), is_scale = matr->IsA() == TGeoScale::Class(),
353 is_rotate = matr->IsA() == TGeoRotation::Class();
354
355 if (!is_translate && !is_scale && !is_rotate) {
356 // check if trivial matrix
357
358 auto test = [](double val, double chk) { return (val == chk) || (TMath::Abs(val - chk) < 1e-20); };
359
360 bool no_scale = test(scale[0], 1) && test(scale[1], 1) && test(scale[2], 1);
361 bool no_trans = test(trans[0], 0) && test(trans[1], 0) && test(trans[2], 0);
362 bool no_rotate = test(rotate[0], 1) && test(rotate[1], 0) && test(rotate[2], 0) && test(rotate[3], 0) &&
363 test(rotate[4], 1) && test(rotate[5], 0) && test(rotate[6], 0) && test(rotate[7], 0) &&
364 test(rotate[8], 1);
365
366 if (no_scale && no_trans && no_rotate)
367 return;
368
369 if (no_scale && no_trans && !no_rotate) {
370 is_rotate = true;
371 } else if (no_scale && !no_trans && no_rotate) {
372 is_translate = true;
373 } else if (!no_scale && no_trans && no_rotate) {
374 is_scale = true;
375 }
376 }
377
378 if (is_translate) {
379 vect.resize(3);
380 vect[0] = trans[0];
381 vect[1] = trans[1];
382 vect[2] = trans[2];
383 return;
384 }
385
386 if (is_scale) {
387 vect.resize(4);
388 vect[0] = scale[0];
389 vect[1] = scale[1];
390 vect[2] = scale[2];
391 vect[3] = 1;
392 return;
393 }
394
395 if (is_rotate) {
396 vect.resize(9);
397 for (int n = 0; n < 9; ++n)
398 vect[n] = rotate[n];
399 return;
400 }
401
402 vect.resize(16);
403 vect[0] = rotate[0];
404 vect[4] = rotate[1];
405 vect[8] = rotate[2];
406 vect[12] = trans[0];
407 vect[1] = rotate[3];
408 vect[5] = rotate[4];
409 vect[9] = rotate[5];
410 vect[13] = trans[1];
411 vect[2] = rotate[6];
412 vect[6] = rotate[7];
413 vect[10] = rotate[8];
414 vect[14] = trans[2];
415 vect[3] = 0;
416 vect[7] = 0;
417 vect[11] = 0;
418 vect[15] = 1;
419}
420
421/////////////////////////////////////////////////////////////////////
422/// Collect information about geometry hierarchy into flat list
423/// like it done in JSROOT ClonedNodes.createClones
424
426{
427 ClearDescription();
428 if (!mgr)
429 return;
430
431 TLockGuard lock(fMutex);
432
433 // by top node visibility always enabled and harm logic
434 // later visibility can be controlled by other means
435 // mgr->GetTopNode()->GetVolume()->SetVisibility(kFALSE);
436
437 int maxnodes = mgr->GetMaxVisNodes();
438
439 SetNSegments(mgr->GetNsegments());
440 SetVisLevel(mgr->GetVisLevel());
441 SetMaxVisNodes(maxnodes);
442 SetMaxVisFaces((maxnodes > 5000 ? 5000 : (maxnodes < 1000 ? 1000 : maxnodes)) * 100);
443
444 auto topnode = mgr->GetTopNode();
445
446 BuildDescription(topnode, topnode->GetVolume());
447
448 if (!volname.empty()) {
449 auto vol = mgr->GetVolume(volname.c_str());
450 RGeomBrowserIter iter(*this);
451 if (vol && (vol != topnode->GetVolume()) && iter.Navigate(vol))
452 fSelectedStack = MakeStackByIds(iter.CurrentIds());
453 }
454}
455
456/////////////////////////////////////////////////////////////////////
457/// Collect information about geometry from single volume
458/// like it done in JSROOT ClonedNodes.createClones
459
461{
462 ClearDescription();
463 if (!vol)
464 return;
465
466 TLockGuard lock(fMutex);
467
468 fDrawVolume = vol;
469
470 fSelectedStack.clear();
471
472 BuildDescription(nullptr, fDrawVolume);
473}
474
475/////////////////////////////////////////////////////////////////////
476/// Clear geometry description
477
479{
480 TLockGuard lock(fMutex);
481
482 fDesc.clear();
483 fNodes.clear();
484 fSortMap.clear();
485 _ClearDrawData();
486 fDrawIdCut = 0;
487 fDrawVolume = nullptr;
488 fSelectedStack.clear();
489}
490
491/////////////////////////////////////////////////////////////////////
492/// Build geometry description
493
495{
496 // vector to remember numbers
497 std::vector<int> numbers;
498 int offset = 1000000000;
499
500 // try to build flat list of all nodes
503 do {
504 if (!snode) {
505 numbers.emplace_back(offset);
506 fNodes.emplace_back(nullptr);
507 } else if (snode->GetNumber() >= offset) {
508 // artificial offset already applied, used as identifier
509 iter.Skip(); // no need to look inside
510 } else {
511 numbers.emplace_back(snode->GetNumber());
512 snode->SetNumber(offset + fNodes.size()); // use id with shift 1e9
513 fNodes.emplace_back(snode);
514 }
515 } while ((snode = iter()) != nullptr);
516
517 fDesc.reserve(fNodes.size());
518 fSortMap.reserve(fNodes.size());
519
520 // array for sorting
521 std::vector<RGeomNode *> sortarr;
522 sortarr.reserve(fNodes.size());
523
524 // create vector of desc and childs
525 int cnt = 0;
526 for (auto node : fNodes) {
527
528 fDesc.emplace_back(node ? node->GetNumber() - offset : 0);
529 TGeoVolume *vol = node ? node->GetVolume() : topvolume;
530
531 auto &desc = fDesc[cnt++];
532
533 sortarr.emplace_back(&desc);
534
535 desc.name = node ? node->GetName() : vol->GetName();
536
537 auto shape = dynamic_cast<TGeoBBox *>(vol->GetShape());
538 if (shape) {
539 desc.vol = TMath::Sqrt(shape->GetDX() * shape->GetDX() + shape->GetDY() * shape->GetDY() +
540 shape->GetDZ() * shape->GetDZ());
541 desc.nfaces = CountShapeFaces(shape);
542 }
543
544 CopyMaterialProperties(vol, desc);
545
546 auto chlds = node ? node->GetNodes() : vol->GetNodes();
547
548 PackMatrix(desc.matr, node ? node->GetMatrix() : nullptr);
549
550 if (chlds)
551 for (int n = 0; n <= chlds->GetLast(); ++n) {
552 auto chld = dynamic_cast<TGeoNode *>(chlds->At(n));
553 desc.chlds.emplace_back(chld->GetNumber() - offset);
554 }
555 }
556
557 // recover numbers
558 cnt = 0;
559 for (auto node : fNodes) {
560 auto number = numbers[cnt++];
561 if (node)
562 node->SetNumber(number);
563 }
564
565 // sort in volume descent order
566 std::sort(sortarr.begin(), sortarr.end(), [](RGeomNode *a, RGeomNode *b) { return a->vol > b->vol; });
567
568 cnt = 0;
569 for (auto &elem : sortarr) {
570 fSortMap.emplace_back(elem->id);
571 elem->sortid = cnt++; // keep place in sorted array to correctly apply cut
572 }
573
574 MarkVisible(); // set visibility flags
575
576 ProduceIdShifts();
577}
578
579/////////////////////////////////////////////////////////////////////
580/// Get volume for specified nodeid
581/// If specific volume was configured, it will be returned for nodeid==0
582
584{
585 auto node = fNodes[nodeid];
586 if (node)
587 return node->GetVolume();
588 return nodeid == 0 ? fDrawVolume : nullptr;
589}
590
591/////////////////////////////////////////////////////////////////////
592/// Set visibility flag for each nodes
593
595{
596 int res = 0;
597 for (int nodeid = 0; nodeid < (int)fNodes.size(); nodeid++) {
598
599 auto node = fNodes[nodeid];
600 auto vol = GetVolume(nodeid);
601 auto &desc = fDesc[nodeid];
602 desc.vis = 0;
603 desc.nochlds = false;
604
605 if (on_screen) {
606 if (!node || node->IsOnScreen())
607 desc.vis = 99;
608 } else {
609 if (vol->IsVisible() && !vol->TestAttBit(TGeoAtt::kVisNone))
610 desc.vis = 99;
611
612 if (node && !node->IsVisDaughters())
613 desc.nochlds = true;
614
615 if ((desc.vis > 0) && (!desc.chlds.empty()) && !desc.nochlds)
616 desc.vis = 1;
617 }
618
619 if (desc.IsVisible() && desc.CanDisplay())
620 res++;
621 }
622
623 return res;
624}
625
626/////////////////////////////////////////////////////////////////////
627/// Count total number of visible childs under each node
628
630{
631 for (auto &node : fDesc)
632 node.idshift = -1;
633
634 using ScanFunc_t = std::function<int(RGeomNode &)>;
635
636 ScanFunc_t scan_func = [&, this](RGeomNode &node) {
637 if (node.idshift < 0) {
638 node.idshift = 0;
639 for (auto id : node.chlds)
640 node.idshift += scan_func(fDesc[id]);
641 }
642
643 return node.idshift + 1;
644 };
645
646 if (!fDesc.empty())
647 scan_func(fDesc[0]);
648}
649
650/////////////////////////////////////////////////////////////////////
651/// Iterate over all nodes and call function for visible
652
654{
655 if (fDesc.empty())
656 return 0;
657
658 std::vector<int> stack;
659 stack.reserve(25); // reserve enough space for most use-cases
660 int counter = 0;
661 auto viter = fVisibility.begin();
662
663 using ScanFunc_t = std::function<int(int, int, bool)>;
664
665 ScanFunc_t scan_func = [&, this](int nodeid, int lvl, bool is_inside) {
666 if (!is_inside && (fSelectedStack == stack))
667 is_inside = true;
668
669 auto &desc = fDesc[nodeid];
670 auto desc_vis = desc.vis;
671 int res = 0;
672
673 if (desc.nochlds && (lvl > 0))
674 lvl = 0;
675
676 bool can_display = desc.CanDisplay(), scan_childs = true;
677
678 if ((viter != fVisibility.end()) && (compare_stacks(viter->stack, stack) == 0)) {
679 can_display = scan_childs = viter->visible;
680 desc_vis = !viter->visible ? 0 : (!desc.chlds.empty() ? 1 : 99);
681 viter++;
682 }
683
684 // same logic as in JSROOT ClonedNodes.scanVisible
685 bool is_visible = (lvl >= 0) && (desc_vis > lvl) && can_display && is_inside;
686
687 if (is_visible || !only_visible)
688 if (func(desc, stack, is_visible, counter))
689 res++;
690
691 counter++; // count sequence id of current position in scan, will be used later for merging drawing lists
692
693 if ((!desc.chlds.empty()) && (((lvl > 0) && scan_childs) || !only_visible)) {
694 auto pos = stack.size();
695 stack.emplace_back(0);
696 for (unsigned k = 0; k < desc.chlds.size(); ++k) {
697 stack[pos] = k; // stack provides index in list of childs
698 res += scan_func(desc.chlds[k], is_inside ? lvl - 1 : lvl, is_inside);
699 }
700 stack.pop_back();
701 } else {
702 counter += desc.idshift;
703 }
704
705 return res;
706 };
707
708 if (!maxlvl && (GetVisLevel() > 0))
709 maxlvl = GetVisLevel();
710 if (!maxlvl)
711 maxlvl = 4;
712 if (maxlvl > 97)
713 maxlvl = 97; // check while vis property of node is 99 normally
714
715 return scan_func(0, maxlvl, false);
716}
717
718/////////////////////////////////////////////////////////////////////
719/// Collect nodes which are used in visibles
720
722{
723 drawing.cfg = &fCfg;
724
725 drawing.numnodes = fDesc.size();
726
727 if (all_nodes) {
728 for (auto &node : fDesc)
729 drawing.nodes.emplace_back(&node);
730 return;
731 }
732
733 // TODO: for now reset all flags, later can be kept longer
734 for (auto &node : fDesc)
735 node.useflag = false;
736
737 for (auto &item : drawing.visibles) {
738 int nodeid = 0;
739 for (auto &chindx : item.stack) {
740 auto &node = fDesc[nodeid];
741 if (!node.useflag) {
742 node.useflag = true;
743 drawing.nodes.emplace_back(&node);
744 }
745 if (chindx >= (int)node.chlds.size())
746 break;
747 nodeid = node.chlds[chindx];
748 }
749
750 if (nodeid != item.nodeid)
751 printf("Nodeid mismatch %d != %d when extracting nodes for visibles\n", nodeid, item.nodeid);
752
753 auto &node = fDesc[nodeid];
754 if (!node.useflag) {
755 node.useflag = true;
756 drawing.nodes.emplace_back(&node);
757 }
758 }
759
760 // printf("SELECT NODES %d\n", (int) drawing.nodes.size());
761}
762
763/////////////////////////////////////////////////////////////////////
764/// Method which allows to add/modify information in RGeoItem which
765/// will be provided to client - like title or some visibility flags
766/// Changes in the item attributes do not affect geometry drawing
767
768void RGeomDescription::RefineGeoItem(RGeoItem & /* item */, const std::vector<int> & /* stack */)
769{
770 // do nothing by default, placeholder for derived classes
771}
772
773
774/////////////////////////////////////////////////////////////////////////////////
775/// Decide if the whole model is streamed at once
776/// Function is called from ProcessBrowserRequest
777
779{
780 return GetNumNodes() < (IsPreferredOffline() ? 1000000 : 1000);
781}
782
783/////////////////////////////////////////////////////////////////////
784/// Find description object for requested shape
785/// If not exists - will be created
786
787std::string RGeomDescription::ProcessBrowserRequest(const std::string &msg)
788{
789 TLockGuard lock(fMutex);
790
791 std::string res;
792
793 auto request = TBufferJSON::FromJSON<RBrowserRequest>(msg);
794
795 if (msg.empty()) {
796 request = std::make_unique<RBrowserRequest>();
797 request->first = 0;
798 request->number = 100;
799 }
800
801 if (!request)
802 return res;
803
804 if (request->path.empty() && (request->first == 0) && IsFullModelStreamedAtOnce()) {
805
806 std::vector<RGeomNodeBase *> vect(fDesc.size(), nullptr);
807
808 int cnt = 0;
809 for (auto &item : fDesc)
810 vect[cnt++] = &item;
811
812 res = "DESCR:"s + TBufferJSON::ToJSON(&vect, GetJsonComp()).Data();
813
814 if (!fVisibility.empty()) {
815 res += ":__PHYSICAL_VISIBILITY__:";
816 res += TBufferJSON::ToJSON(&fVisibility, GetJsonComp()).Data();
817 }
818
819 res += ":__SELECTED_STACK__:";
820 res += TBufferJSON::ToJSON(&fSelectedStack, GetJsonComp()).Data();
821
822 } else {
823 std::vector<RGeoItem> temp_nodes;
824 bool toplevel = request->path.empty();
825
826 // create temporary object for the short time
828 reply.path = request->path;
829 reply.first = request->first;
830
831 RGeomBrowserIter iter(*this);
832 if (iter.Navigate(request->path)) {
833
834 reply.nchilds = iter.NumChilds();
835 // scan childs of selected nodes
836 if (iter.Enter()) {
837
838 while ((request->first > 0) && iter.Next()) {
839 request->first--;
840 }
841
842 // first element
843 auto stack = MakeStackByIds(iter.CurrentIds());
844
845 while (iter.IsValid() && (request->number > 0)) {
846 int pvis = IsPhysNodeVisible(stack);
847 temp_nodes.emplace_back(iter.GetName(), iter.NumChilds(), iter.GetNodeId(), iter.GetColor(),
848 iter.GetMaterial(), iter.GetVisible(), pvis < 0 ? iter.GetVisible() : pvis);
849 if (toplevel)
850 temp_nodes.back().SetExpanded(true);
851 if (stack == fSelectedStack)
852 temp_nodes.back().SetTop(true);
853
854 RefineGeoItem(temp_nodes.back(), stack);
855
856 request->number--;
857
858 if (!stack.empty())
859 stack[stack.size() - 1]++;
860
861 if (!iter.Next())
862 break;
863 }
864 }
865 }
866
867 for (auto &n : temp_nodes)
868 reply.nodes.emplace_back(&n);
869
870 res = "BREPL:"s + TBufferJSON::ToJSON(&reply, GetJsonComp()).Data();
871 }
872
873 return res;
874}
875
876/////////////////////////////////////////////////////////////////////
877/// Find description object for requested shape
878/// If not exists - will be created
879
881{
882 for (auto &descr : fShapes)
883 if (descr.fShape == shape)
884 return descr;
885
886 fShapes.emplace_back(shape);
887 auto &elem = fShapes.back();
888 elem.id = fShapes.size() - 1;
889 return elem;
890}
891
892////////////////////////////////////////////////////////////////////////
893/// Function produces mesh for provided shape, applying matrix to the result
894
895std::unique_ptr<RootCsg::TBaseMesh> MakeGeoMesh(TGeoMatrix *matr, TGeoShape *shape)
896{
897 TGeoCompositeShape *comp = dynamic_cast<TGeoCompositeShape *>(shape);
898
899 std::unique_ptr<RootCsg::TBaseMesh> res;
900
901 if (!comp) {
902 std::unique_ptr<TBuffer3D> b3d(shape->MakeBuffer3D());
903
904 if (matr) {
905 Double_t *v = b3d->fPnts;
906 Double_t buf[3];
907 for (UInt_t i = 0; i < b3d->NbPnts(); ++i) {
908 buf[0] = v[i * 3];
909 buf[1] = v[i * 3 + 1];
910 buf[2] = v[i * 3 + 2];
911 matr->LocalToMaster(buf, &v[i * 3]);
912 }
913 }
914
915 res.reset(RootCsg::ConvertToMesh(*b3d.get()));
916 } else {
917 auto node = comp->GetBoolNode();
918
919 TGeoHMatrix mleft, mright;
920 if (matr) {
921 mleft = *matr;
922 mright = *matr;
923 }
924
925 mleft.Multiply(node->GetLeftMatrix());
926 auto left = MakeGeoMesh(&mleft, node->GetLeftShape());
927
928 mright.Multiply(node->GetRightMatrix());
929 auto right = MakeGeoMesh(&mright, node->GetRightShape());
930
931 if (node->IsA() == TGeoUnion::Class())
932 res.reset(RootCsg::BuildUnion(left.get(), right.get()));
933 if (node->IsA() == TGeoIntersection::Class())
934 res.reset(RootCsg::BuildIntersection(left.get(), right.get()));
935 if (node->IsA() == TGeoSubtraction::Class())
936 res.reset(RootCsg::BuildDifference(left.get(), right.get()));
937 }
938
939 return res;
940}
941
942/////////////////////////////////////////////////////////////////////
943/// Returns really used number of cylindrical segments
944
946{
947 int nsegm = 0;
948
949 if (GetNSegments() > 0)
950 nsegm = GetNSegments();
951 else if (gGeoManager && (gGeoManager->GetNsegments() > 0))
952 nsegm = gGeoManager->GetNsegments();
953
954 return nsegm > min ? nsegm : min;
955}
956
957/////////////////////////////////////////////////////////////////////
958/// Count number of faces for the shape
959
961{
962 if (!shape)
963 return 0;
964
965 auto countTubeFaces = [this](const std::array<Double_t, 2> &outerR, const std::array<Double_t, 2> &innerR,
966 Double_t thetaLength = 360.) -> int {
967 auto hasrmin = (innerR[0] > 0) || (innerR[1] > 0);
968
969 int radiusSegments = TMath::Max(4, TMath::Nint(thetaLength / 360. * GetUsedNSegments()));
970
971 // external surface
972 int numfaces = radiusSegments * (((outerR[0] <= 0) || (outerR[1] <= 0)) ? 1 : 2);
973
974 // internal surface
975 if (hasrmin)
976 numfaces += radiusSegments * (((innerR[0] <= 0) || (innerR[1] <= 0)) ? 1 : 2);
977
978 // upper cap
979 if (outerR[0] > 0)
980 numfaces += radiusSegments * ((innerR[0] > 0) ? 2 : 1);
981 // bottom cup
982 if (outerR[1] > 0)
983 numfaces += radiusSegments * ((innerR[1] > 0) ? 2 : 1);
984
985 if (thetaLength < 360)
986 numfaces += ((outerR[0] > innerR[0]) ? 2 : 0) + ((outerR[1] > innerR[1]) ? 2 : 0);
987
988 return numfaces;
989 };
990
991 if (shape->IsA() == TGeoSphere::Class()) {
992 TGeoSphere *sphere = (TGeoSphere *)shape;
993 auto widthSegments = sphere->GetNumberOfDivisions();
994 auto heightSegments = sphere->GetNz();
995 auto phiLength = sphere->GetPhi2() - sphere->GetPhi1();
996 auto noInside = sphere->GetRmin() <= 0;
997
999 auto numtop = widthSegments * (noInside ? 1 : 2);
1000 auto numbottom = widthSegments * (noInside ? 1 : 2);
1001 auto numcut = (phiLength == 360.) ? 0 : heightSegments * (noInside ? 2 : 4);
1002
1003 return numoutside * (noInside ? 1 : 2) + numtop + numbottom + numcut;
1004 } else if (shape->IsA() == TGeoCone::Class()) {
1005 auto cone = (TGeoCone *)shape;
1006 return countTubeFaces({cone->GetRmax2(), cone->GetRmax1()}, {cone->GetRmin2(), cone->GetRmin1()});
1007 } else if (shape->IsA() == TGeoConeSeg::Class()) {
1008 auto cone = (TGeoConeSeg *)shape;
1009 return countTubeFaces({cone->GetRmax2(), cone->GetRmax1()}, {cone->GetRmin2(), cone->GetRmin1()},
1010 cone->GetPhi2() - cone->GetPhi1());
1011 } else if (shape->IsA() == TGeoTube::Class()) {
1012 auto tube = (TGeoTube *)shape;
1013 return countTubeFaces({tube->GetRmax(), tube->GetRmax()}, {tube->GetRmin(), tube->GetRmin()});
1014 } else if (shape->IsA() == TGeoTubeSeg::Class()) {
1015 auto tube = (TGeoTubeSeg *)shape;
1016 return countTubeFaces({tube->GetRmax(), tube->GetRmax()}, {tube->GetRmin(), tube->GetRmin()},
1017 tube->GetPhi2() - tube->GetPhi1());
1018 } else if (shape->IsA() == TGeoCtub::Class()) {
1019 auto tube = (TGeoCtub *)shape;
1020 return countTubeFaces({tube->GetRmax(), tube->GetRmax()}, {tube->GetRmin(), tube->GetRmin()},
1021 tube->GetPhi2() - tube->GetPhi1());
1022 } else if (shape->IsA() == TGeoEltu::Class()) {
1023 return GetUsedNSegments(4) * 4;
1024 } else if (shape->IsA() == TGeoTorus::Class()) {
1025 auto torus = (TGeoTorus *)shape;
1026 auto radialSegments = GetUsedNSegments(6);
1027 auto tubularSegments = TMath::Max(8, TMath::Nint(torus->GetDphi() / 360. * GetUsedNSegments()));
1028 return (torus->GetRmin() > 0 ? 4 : 2) * radialSegments * (tubularSegments + (torus->GetDphi() != 360. ? 1 : 0));
1029 } else if (shape->IsA() == TGeoPcon::Class()) {
1030 auto pcon = (TGeoPcon *)shape;
1031
1032 bool hasrmin = false;
1033 int radiusSegments = TMath::Max(5, TMath::Nint(pcon->GetDphi() / 360 * GetUsedNSegments()));
1034 for (int layer = 0; layer < pcon->GetNz(); ++layer)
1035 if (pcon->GetRmin(layer) > 0.)
1036 hasrmin = true;
1037 return (hasrmin ? 4 : 2) * radiusSegments * (pcon->GetNz() - 1);
1038 } else if (shape->IsA() == TGeoPgon::Class()) {
1039 auto pgon = (TGeoPgon *)shape;
1040
1041 bool hasrmin = false;
1042 int radiusSegments = TMath::Max(5, TMath::Nint(pgon->GetDphi() / 360 * GetUsedNSegments()));
1043 for (int layer = 0; layer < pgon->GetNz(); ++layer)
1044 if (pgon->GetRmin(layer) > 0.)
1045 hasrmin = true;
1046 return (hasrmin ? 4 : 2) * radiusSegments * (pgon->GetNz() - 1);
1047 } else if (shape->IsA() == TGeoXtru::Class()) {
1048 auto xtru = (TGeoXtru *)shape;
1049 return (xtru->GetNz() - 1) * xtru->GetNvert() * 2 + xtru->GetNvert() * 3;
1050 } else if (shape->IsA() == TGeoParaboloid::Class()) {
1051 auto para = (TGeoParaboloid *)shape;
1052 int radiusSegments = GetUsedNSegments(4), heightSegments = 30;
1053 int numfaces = (heightSegments + 1) * radiusSegments * 2;
1054 if (para->GetRlo() == 0.)
1055 numfaces -= radiusSegments * 2; // complete layer
1056 if (para->GetRhi() == 0.)
1057 numfaces -= radiusSegments * 2; // complete layer
1058 return numfaces;
1059 } else if (shape->IsA() == TGeoHype::Class()) {
1060 TGeoHype *hype = (TGeoHype *)shape;
1061 if ((hype->GetStIn() == 0) && (hype->GetStOut() == 0))
1062 return countTubeFaces({hype->GetRmax(), hype->GetRmax()}, {hype->GetRmin(), hype->GetRmin()});
1063 int radiusSegments = GetUsedNSegments(4), heightSegments = 30;
1064 return radiusSegments * (heightSegments + 1) * ((hype->GetRmin() > 0.) ? 4 : 2);
1065 } else if (shape->IsA() == TGeoTessellated::Class()) {
1066 auto tess = (TGeoTessellated *)shape;
1067 int numfaces = 0;
1068 for (int i = 0; i < tess->GetNfacets(); ++i) {
1069 if (tess->GetFacet(i).GetNvert() == 4)
1070 numfaces += 2;
1071 else
1072 numfaces += 1;
1073 }
1074 return numfaces;
1075 } else if (shape->IsA() == TGeoScaledShape::Class()) {
1076 auto scaled = (TGeoScaledShape *)shape;
1077 return CountShapeFaces(scaled->GetShape());
1078 } else if (shape->IsA() == TGeoCompositeShape::Class()) {
1079 auto comp = (TGeoCompositeShape *)shape;
1080 if (!comp->GetBoolNode())
1081 return 0;
1082 return CountShapeFaces(comp->GetBoolNode()->GetLeftShape()) +
1083 CountShapeFaces(comp->GetBoolNode()->GetRightShape());
1084 }
1085
1086 // many of simple shapes have 12 faces
1087 return 12;
1088}
1089
1090/////////////////////////////////////////////////////////////////////
1091/// Find description object and create render information
1092
1094{
1095 auto &elem = FindShapeDescr(shape);
1096
1097 if (elem.nfaces == 0) {
1098
1099 int boundary = 3; //
1100 if (shape->IsComposite()) {
1101 // composite is most complex for client, therefore by default build on server
1102 boundary = 1;
1103 } else if (!shape->IsCylType()) {
1104 // simple box geometry is compact and can be delivered as raw
1105 boundary = 2;
1106 }
1107
1108 if (IsBuildShapes() < boundary) {
1109 elem.nfaces = 1;
1110 elem.fShapeInfo.shape = shape;
1111 } else {
1112
1113 int old_nsegm = -1;
1114 if (fCfg.nsegm > 0 && gGeoManager) {
1116 gGeoManager->SetNsegments(fCfg.nsegm);
1117 }
1118
1119 auto mesh = MakeGeoMesh(nullptr, shape);
1120
1121 if (old_nsegm > 0 && gGeoManager)
1123
1124 Int_t num_vertices = mesh->NumberOfVertices(), num_polynoms = 0;
1125
1126 for (unsigned polyIndex = 0; polyIndex < mesh->NumberOfPolys(); ++polyIndex) {
1127
1128 auto size_of_polygon = mesh->SizeOfPoly(polyIndex);
1129
1130 if (size_of_polygon >= 3)
1132 }
1133
1134 Int_t index_buffer_size = num_polynoms * 3, // triangle indexes
1135 vertex_buffer_size = num_vertices * 3; // X,Y,Z array
1136
1137 elem.nfaces = num_polynoms;
1138
1139 std::vector<float> vertices(vertex_buffer_size);
1140
1141 for (Int_t i = 0; i < num_vertices; ++i) {
1142 auto v = mesh->GetVertex(i);
1143 vertices[i * 3] = v[0];
1144 vertices[i * 3 + 1] = v[1];
1145 vertices[i * 3 + 2] = v[2];
1146 }
1147
1148 elem.fRawInfo.raw.resize(vertices.size() * sizeof(float));
1149
1150 memcpy(reinterpret_cast<char *>(elem.fRawInfo.raw.data()), vertices.data(), vertices.size() * sizeof(float));
1151
1152 auto &indexes = elem.fRawInfo.idx;
1153
1154 indexes.resize(index_buffer_size);
1155 int pos = 0;
1156
1157 for (unsigned polyIndex = 0; polyIndex < mesh->NumberOfPolys(); ++polyIndex) {
1158 auto size_of_polygon = mesh->SizeOfPoly(polyIndex);
1159
1160 // add first triangle
1161 if (size_of_polygon >= 3)
1162 for (int i = 0; i < 3; ++i)
1163 indexes[pos++] = mesh->GetVertexIndex(polyIndex, i);
1164
1165 // add following triangles
1166 if (size_of_polygon > 3)
1167 for (unsigned vertex = 3; vertex < size_of_polygon; vertex++) {
1168 indexes[pos++] = mesh->GetVertexIndex(polyIndex, 0);
1169 indexes[pos++] = mesh->GetVertexIndex(polyIndex, vertex - 1);
1170 indexes[pos++] = mesh->GetVertexIndex(polyIndex, vertex);
1171 }
1172 }
1173 }
1174 }
1175
1176 return elem;
1177}
1178
1179/////////////////////////////////////////////////////////////////////
1180/// Copy material properties
1181
1183{
1184 if (!volume)
1185 return;
1186
1187 TColor *col = nullptr;
1188
1189 if ((volume->GetFillColor() > 1) && (volume->GetLineColor() == 1))
1190 col = gROOT->GetColor(volume->GetFillColor());
1191 else if (volume->GetLineColor() >= 0)
1192 col = gROOT->GetColor(volume->GetLineColor());
1193
1194 if (volume->GetMedium() && (volume->GetMedium() != TGeoVolume::DummyMedium()) &&
1195 volume->GetMedium()->GetMaterial()) {
1196 auto material = volume->GetMedium()->GetMaterial();
1197
1198 node.material = material->GetName();
1199
1200 auto fillstyle = material->GetFillStyle();
1201 if ((fillstyle >= 3000) && (fillstyle <= 3100))
1202 node.opacity = (3100 - fillstyle) / 100.;
1203 if (!col)
1204 col = gROOT->GetColor(material->GetFillColor());
1205 } else {
1206 node.material.clear();
1207 }
1208
1209 if (col) {
1211 colbuf.Form("#%02x%02x%02x", (int)(col->GetRed() * 255), (int)(col->GetGreen() * 255),
1212 (int)(col->GetBlue() * 255));
1213 node.color = colbuf.Data();
1214 if (node.opacity == 1.)
1215 node.opacity = col->GetAlpha();
1216 } else {
1217 node.color.clear();
1218 }
1219}
1220
1221/////////////////////////////////////////////////////////////////////
1222/// Reset shape info, which used to pack binary data
1223
1225{
1226 for (auto &s : fShapes)
1227 s.reset();
1228}
1229
1230/////////////////////////////////////////////////////////////////////
1231/// Produce JSON string which can be directly used with `build`
1232/// function from JSROOT to create three.js model of configured geometry
1233///
1234/// Collect all information required to draw geometry on the client
1235/// This includes list of each visible nodes, meshes and matrixes
1236/// If @param all_nodes is true, all existing nodes will be provided,
1237/// which allows to create complete nodes hierarchy on client side
1238///
1239/// Example of usage:
1240///
1241/// void geom() {
1242/// auto f = TFile::Open("file_name.root");
1243/// auto vol = f->Get<TGeoVolume>("object_name");
1244/// ROOT::RGeomDescription desc;
1245/// desc.Build(vol);
1246/// std::ofstream fout("geom.json");
1247/// fout << desc.ProduceJson();
1248/// }
1249///
1250/// In JSROOT one loads data from JSON file and call `build` function to
1251/// produce three.js model. Also see example in tutorials/visualisation/webgui/geom/ folder
1252
1254{
1255 TLockGuard lock(fMutex);
1256
1257 std::vector<int> viscnt(fDesc.size(), 0);
1258
1259 int level = GetVisLevel();
1260
1261 // first count how many times each individual node appears
1262 int numnodes = ScanNodes(true, level, [&viscnt](RGeomNode &node, std::vector<int> &, bool, int) {
1263 viscnt[node.id]++;
1264 return true;
1265 });
1266
1267 if (GetMaxVisNodes() > 0) {
1268 while ((numnodes > GetMaxVisNodes()) && (level > 1)) {
1269 level--;
1270 viscnt.assign(viscnt.size(), 0);
1271 numnodes = ScanNodes(true, level, [&viscnt](RGeomNode &node, std::vector<int> &, bool, int) {
1272 viscnt[node.id]++;
1273 return true;
1274 });
1275 }
1276 }
1277
1278 fActualLevel = level;
1279 fDrawIdCut = 0;
1280
1281 int totalnumfaces = 0, totalnumnodes = 0;
1282
1283 // for (auto &node : fDesc)
1284 // node.SetDisplayed(false);
1285
1286 // build all shapes in volume decreasing order
1287 for (auto &sid : fSortMap) {
1288 fDrawIdCut++; //
1289 auto &desc = fDesc[sid];
1290
1291 if ((viscnt[sid] <= 0) || (desc.vol <= 0))
1292 continue;
1293
1294 auto shape = GetVolume(sid)->GetShape();
1295 if (!shape)
1296 continue;
1297
1298 // now we need to create TEveGeoPolyShape, which can provide all rendering data
1299 auto &shape_descr = MakeShapeDescr(shape);
1300
1301 // should not happen, but just in case
1302 if (shape_descr.nfaces <= 0) {
1303 R__LOG_ERROR(RGeomLog()) << "No faces for the shape " << shape->GetName() << " class " << shape->ClassName();
1304 continue;
1305 }
1306
1307 // check how many faces are created
1308 totalnumfaces += shape_descr.nfaces * viscnt[sid];
1309 if ((GetMaxVisFaces() > 0) && (totalnumfaces > GetMaxVisFaces()))
1310 break;
1311
1312 // also avoid too many nodes
1314 if ((GetMaxVisNodes() > 0) && (totalnumnodes > GetMaxVisNodes()))
1315 break;
1316
1317 // desc.SetDisplayed(true);
1318 }
1319
1320 // finally we should create data for streaming to the client
1321 // it includes list of visible nodes and rawdata
1322
1323 RGeomDrawing drawing;
1324 ResetRndrInfos();
1325 bool has_shape = false;
1326
1327 ScanNodes(true, level, [&, this](RGeomNode &node, std::vector<int> &stack, bool, int seqid) {
1328 if ((node.sortid < fDrawIdCut) && (viscnt[node.id] > 0)) {
1329 drawing.visibles.emplace_back(node.id, seqid, stack);
1330
1331 auto &item = drawing.visibles.back();
1332 item.color = node.color;
1333 item.opacity = node.opacity;
1334
1335 auto volume = GetVolume(node.id);
1336
1337 auto &sd = MakeShapeDescr(volume->GetShape());
1338
1339 item.ri = sd.rndr_info();
1340 if (sd.has_shape())
1341 has_shape = true;
1342 }
1343 return true;
1344 });
1345
1346 CollectNodes(drawing, all_nodes);
1347
1348 return MakeDrawingJson(drawing, has_shape);
1349}
1350
1351/////////////////////////////////////////////////////////////////////
1352/// Check if there is draw data available
1353
1355{
1356 TLockGuard lock(fMutex);
1357 return (fDrawJson.length() > 0) && (fDrawIdCut > 0);
1358}
1359
1360/////////////////////////////////////////////////////////////////////
1361/// Produces search data if necessary
1362
1364{
1365 TLockGuard lock(fMutex);
1366
1367 if (fSearch.empty() || !fSearchJson.empty())
1368 return;
1369
1370 std::string hjson;
1371
1372 SearchVisibles(fSearch, hjson, fSearchJson);
1373
1374 (void)hjson; // not used here
1375}
1376
1377/////////////////////////////////////////////////////////////////////
1378/// Collect all information required to draw geometry on the client
1379/// This includes list of each visible nodes, meshes and matrixes
1380
1382{
1383 auto json = ProduceJson();
1384
1385 TLockGuard lock(fMutex);
1386
1387 fDrawJson = "GDRAW:"s + json;
1388}
1389
1390/////////////////////////////////////////////////////////////////////
1391/// Clear drawing data.
1392/// Will be rebuild when next connection established or new message need to be send
1393
1395{
1396 TLockGuard lock(fMutex);
1397
1398 _ClearDrawData();
1399}
1400
1401/////////////////////////////////////////////////////////////////////
1402/// Clear cached data, need to be clear when connection broken
1403
1405{
1406 TLockGuard lock(fMutex);
1407
1408 fShapes.clear();
1409 fSearch.clear();
1410
1411 _ClearDrawData();
1412}
1413
1414/////////////////////////////////////////////////////////////////////
1415/// return true when node used in main geometry drawing and does not have childs
1416/// for such nodes one could provide optimize toggling of visibility flags
1417
1419{
1420 TLockGuard lock(fMutex);
1421
1422 if ((nodeid < 0) || (nodeid >= (int)fDesc.size()))
1423 return false;
1424
1425 auto &desc = fDesc[nodeid];
1426
1427 return (desc.sortid < fDrawIdCut) && desc.IsVisible() && desc.CanDisplay() && (desc.chlds.empty());
1428}
1429
1430/////////////////////////////////////////////////////////////////////
1431/// Search visible nodes for provided name
1432/// If number of found elements less than 100, create description and shapes for them
1433/// Returns number of match elements
1434
1435int RGeomDescription::SearchVisibles(const std::string &find, std::string &hjson, std::string &json)
1436{
1437 TLockGuard lock(fMutex);
1438
1439 hjson.clear();
1440 json.clear();
1441
1442 if (find.empty()) {
1443 hjson = "FOUND:RESET";
1444 return 0;
1445 }
1446
1447 std::vector<int> nodescnt(fDesc.size(), 0), viscnt(fDesc.size(), 0);
1448
1449 int nmatches = 0;
1450 std::string test = find;
1451 int kind = 0;
1452 if (test.compare(0, 2, "c:") == 0) {
1453 test.erase(0, 2);
1454 kind = 1;
1455 } else if (test.compare(0, 2, "m:") == 0) {
1456 test.erase(0, 2);
1457 kind = 2;
1458 }
1459
1460 TRegexp regexp(test.c_str());
1461
1462 auto match_func = [&regexp, kind](RGeomNode &node) {
1463 return (node.vol > 0) && (TString(node.GetArg(kind)).Index(regexp) >= 0);
1464 };
1465
1466 // first count how many times each individual node appears
1467 ScanNodes(false, 0,
1468 [&nodescnt, &viscnt, &match_func, &nmatches](RGeomNode &node, std::vector<int> &, bool is_vis, int) {
1469 if (match_func(node)) {
1470 nmatches++;
1471 nodescnt[node.id]++;
1472 if (is_vis)
1473 viscnt[node.id]++;
1474 };
1475 return true;
1476 });
1477
1478 // do not send too much data, limit could be made configurable later
1479 if (nmatches == 0) {
1480 hjson = "FOUND:NO";
1481 return nmatches;
1482 }
1483
1484 if ((GetMaxVisNodes() > 0) && (nmatches > 10 * GetMaxVisNodes())) {
1485 hjson = "FOUND:Too many " + std::to_string(nmatches);
1486 return nmatches;
1487 }
1488
1489 // now build all necessary shapes and check number of faces - not too many
1490
1491 int totalnumfaces = 0, totalnumnodes = 0, scnt = 0;
1492 bool send_rawdata = true;
1493
1494 // build all shapes in volume decreasing order
1495 for (auto &sid : fSortMap) {
1496 if (scnt++ < fDrawIdCut)
1497 continue; // no need to send most significant shapes
1498
1499 if (viscnt[sid] == 0)
1500 continue; // this node is not used at all
1501
1502 auto &desc = fDesc[sid];
1503 if ((viscnt[sid] <= 0) && (desc.vol <= 0))
1504 continue;
1505
1506 auto shape = GetVolume(sid)->GetShape();
1507 if (!shape)
1508 continue;
1509
1510 // create shape raw data
1511 auto &shape_descr = MakeShapeDescr(shape);
1512
1513 // should not happen, but just in case
1514 if (shape_descr.nfaces <= 0) {
1515 R__LOG_ERROR(RGeomLog()) << "No faces for the shape " << shape->GetName() << " class " << shape->ClassName();
1516 continue;
1517 }
1518
1519 // check how many faces are created
1520 totalnumfaces += shape_descr.nfaces * viscnt[sid];
1521 if ((GetMaxVisFaces() > 0) && (totalnumfaces > GetMaxVisFaces())) {
1522 send_rawdata = false;
1523 break;
1524 }
1525
1526 // also avoid too many nodes
1528 if ((GetMaxVisNodes() > 0) && (totalnumnodes > GetMaxVisNodes())) {
1529 send_rawdata = false;
1530 break;
1531 }
1532 }
1533
1534 // only for debug purposes - remove later
1535 // send_rawdata = false;
1536
1537 // finally we should create data for streaming to the client
1538 // it includes list of visible nodes and rawdata (if there is enough space)
1539
1540 std::vector<RGeomNodeBase> found_desc; ///<! hierarchy of nodes, used for search
1541 std::vector<int> found_map(fDesc.size(), -1); ///<! mapping between nodeid - > foundid
1542
1543 // these are only selected nodes to produce hierarchy
1544
1545 found_desc.emplace_back(0);
1546 found_desc[0].vis = fDesc[0].vis;
1547 found_desc[0].name = fDesc[0].name;
1548 found_desc[0].color = fDesc[0].color;
1549 found_map[0] = 0;
1550
1551 ResetRndrInfos();
1552
1553 RGeomDrawing drawing;
1554 bool has_shape = true;
1555
1556 ScanNodes(false, 0, [&, this](RGeomNode &node, std::vector<int> &stack, bool is_vis, int seqid) {
1557 // select only nodes which should match
1558 if (!match_func(node))
1559 return true;
1560
1561 // add entries into hierarchy of found elements
1562 int prntid = 0;
1563 for (auto &s : stack) {
1564 int chldid = fDesc[prntid].chlds[s];
1565 if (found_map[chldid] <= 0) {
1566 int newid = found_desc.size();
1567 found_desc.emplace_back(newid); // potentially original id can be used here
1568 found_map[chldid] = newid; // re-map into reduced hierarchy
1569
1570 found_desc.back().vis = fDesc[chldid].vis;
1571 found_desc.back().name = fDesc[chldid].name;
1572 found_desc.back().color = fDesc[chldid].color;
1573 found_desc.back().material = fDesc[chldid].material;
1574 }
1575
1576 auto pid = found_map[prntid];
1577 auto cid = found_map[chldid];
1578
1579 // now add entry into childs lists
1580 auto &pchlds = found_desc[pid].chlds;
1581 if (std::find(pchlds.begin(), pchlds.end(), cid) == pchlds.end())
1582 pchlds.emplace_back(cid);
1583
1584 prntid = chldid;
1585 }
1586
1587 // no need to add visibles
1588 if (!is_vis)
1589 return true;
1590
1591 drawing.visibles.emplace_back(node.id, seqid, stack);
1592
1593 // no need to transfer shape if it provided with main drawing list
1594 // also no binary will be transported when too many matches are there
1595 if (!send_rawdata || (node.sortid < fDrawIdCut)) {
1596 // do not include render data
1597 return true;
1598 }
1599
1600 auto &item = drawing.visibles.back();
1601 auto volume = GetVolume(node.id);
1602
1603 item.color = node.color;
1604 item.opacity = node.opacity;
1605
1606 auto &sd = MakeShapeDescr(volume->GetShape());
1607
1608 item.ri = sd.rndr_info();
1609 if (sd.has_shape())
1610 has_shape = true;
1611 return true;
1612 });
1613
1614 hjson = "FESCR:"s + TBufferJSON::ToJSON(&found_desc, GetJsonComp()).Data();
1615
1616 CollectNodes(drawing);
1617
1618 json = "FDRAW:"s + MakeDrawingJson(drawing, has_shape);
1619
1620 return nmatches;
1621}
1622
1623/////////////////////////////////////////////////////////////////////////////////
1624/// Returns nodeid for given stack array, returns -1 in case of failure
1625
1626int RGeomDescription::FindNodeId(const std::vector<int> &stack)
1627{
1628 TLockGuard lock(fMutex);
1629
1630 int nodeid = 0;
1631
1632 for (auto &chindx : stack) {
1633 auto &node = fDesc[nodeid];
1634 if (chindx >= (int)node.chlds.size())
1635 return -1;
1636 nodeid = node.chlds[chindx];
1637 }
1638
1639 return nodeid;
1640}
1641
1642/////////////////////////////////////////////////////////////////////////////////
1643/// Creates stack for given array of ids, first element always should be 0
1644
1645std::vector<int> RGeomDescription::MakeStackByIds(const std::vector<int> &ids)
1646{
1647 TLockGuard lock(fMutex);
1648
1649 std::vector<int> stack;
1650
1651 if (ids.empty())
1652 return stack;
1653
1654 if (ids[0] != 0) {
1655 printf("Wrong first id\n");
1656 return stack;
1657 }
1658
1659 int nodeid = 0;
1660
1661 for (unsigned k = 1; k < ids.size(); ++k) {
1662
1663 int prntid = nodeid;
1664 nodeid = ids[k];
1665
1666 if (nodeid >= (int)fDesc.size()) {
1667 printf("Wrong node id %d\n", nodeid);
1668 stack.clear();
1669 return stack;
1670 }
1671 auto &chlds = fDesc[prntid].chlds;
1672 auto pos = std::find(chlds.begin(), chlds.end(), nodeid);
1673 if (pos == chlds.end()) {
1674 printf("Wrong id %d not a child of %d - fail to find stack num %d\n", nodeid, prntid, (int)chlds.size());
1675 stack.clear();
1676 return stack;
1677 }
1678
1679 stack.emplace_back(std::distance(chlds.begin(), pos));
1680 }
1681
1682 return stack;
1683}
1684
1685/////////////////////////////////////////////////////////////////////////////////
1686/// Produce stack based on string path
1687/// Used to highlight geo volumes by browser hover event
1688
1689std::vector<int> RGeomDescription::MakeStackByPath(const std::vector<std::string> &path)
1690{
1691 TLockGuard lock(fMutex);
1692
1693 std::vector<int> res;
1694
1695 RGeomBrowserIter iter(*this);
1696
1697 if (iter.Navigate(path))
1698 res = MakeStackByIds(iter.CurrentIds());
1699
1700 return res;
1701}
1702
1703/////////////////////////////////////////////////////////////////////////////////
1704/// Produce list of node ids for given stack
1705/// If found nodes preselected - use their ids
1706
1707std::vector<int> RGeomDescription::MakeIdsByStack(const std::vector<int> &stack)
1708{
1709 TLockGuard lock(fMutex);
1710
1711 std::vector<int> ids;
1712
1713 ids.emplace_back(0);
1714 int nodeid = 0;
1715 bool failure = false;
1716
1717 for (auto s : stack) {
1718 auto &chlds = fDesc[nodeid].chlds;
1719 if (s >= (int)chlds.size()) {
1720 failure = true;
1721 break;
1722 }
1723
1724 ids.emplace_back(chlds[s]);
1725
1726 nodeid = chlds[s];
1727 }
1728
1729 if (failure) {
1730 printf("Fail to convert stack into list of nodes\n");
1731 ids.clear();
1732 }
1733
1734 return ids;
1735}
1736
1737/////////////////////////////////////////////////////////////////////////////////
1738/// Returns path string for provided stack
1739
1740std::vector<std::string> RGeomDescription::MakePathByStack(const std::vector<int> &stack)
1741{
1742 TLockGuard lock(fMutex);
1743
1744 std::vector<std::string> path;
1745
1746 auto ids = MakeIdsByStack(stack);
1747 path.reserve(ids.size());
1748for (auto &id : ids)
1749 path.emplace_back(fDesc[id].name);
1750
1751 return path;
1752}
1753
1754/////////////////////////////////////////////////////////////////////////////////
1755/// Return string with only part of nodes description which were modified
1756/// Checks also volume
1757
1759{
1760 TLockGuard lock(fMutex);
1761
1762 std::vector<RGeomNodeBase *> nodes;
1763 auto vol = GetVolume(nodeid);
1764
1765 // we take not only single node, but all there same volume is referenced
1766 // nodes.push_back(&fDesc[nodeid]);
1767
1768 int id = 0;
1769 for (auto &desc : fDesc)
1770 if (GetVolume(id++) == vol)
1771 nodes.emplace_back(&desc);
1772
1773 return "MODIF:"s + TBufferJSON::ToJSON(&nodes, GetJsonComp()).Data();
1774}
1775
1776/////////////////////////////////////////////////////////////////////////////////
1777/// Produce shape rendering data for given stack
1778/// All nodes, which are referencing same shape will be transferred
1779/// Returns true if new render information provided
1780
1781bool RGeomDescription::ProduceDrawingFor(int nodeid, std::string &json, bool check_volume)
1782{
1783 TLockGuard lock(fMutex);
1784
1785 // only this shape is interesting
1786
1787 TGeoVolume *vol = (nodeid < 0) ? nullptr : GetVolume(nodeid);
1788
1789 if (!vol || !vol->GetShape()) {
1790 json.append("NO");
1791 return false;
1792 }
1793
1794 RGeomDrawing drawing;
1795
1796 ScanNodes(true, 0, [&, this](RGeomNode &node, std::vector<int> &stack, bool, int seq_id) {
1797 // select only nodes which reference same shape
1798
1799 if (check_volume) {
1800 if (GetVolume(node.id) != vol)
1801 return true;
1802 } else {
1803 if (node.id != nodeid)
1804 return true;
1805 }
1806
1807 drawing.visibles.emplace_back(node.id, seq_id, stack);
1808
1809 auto &item = drawing.visibles.back();
1810
1811 item.color = node.color;
1812 item.opacity = node.opacity;
1813 return true;
1814 });
1815
1816 // no any visible nodes were done
1817 if (drawing.visibles.empty()) {
1818 json.append("NO");
1819 return false;
1820 }
1821
1822 ResetRndrInfos();
1823
1824 bool has_shape = false, has_raw = false;
1825
1826 auto &sd = MakeShapeDescr(vol->GetShape());
1827
1828 // assign shape data
1829 for (auto &item : drawing.visibles) {
1830 item.ri = sd.rndr_info();
1831 if (sd.has_shape())
1832 has_shape = true;
1833 if (sd.has_raw())
1834 has_raw = true;
1835 }
1836
1837 CollectNodes(drawing);
1838
1839 json.append(MakeDrawingJson(drawing, has_shape));
1840
1841 return has_raw || has_shape;
1842}
1843
1844/////////////////////////////////////////////////////////////////////////////////
1845/// Produce JSON for the drawing
1846/// If TGeoShape appears in the drawing, one has to keep typeinfo
1847/// But in this case one can exclude several classes which are not interesting,
1848/// but appears very often
1849
1851{
1852 int comp = GetJsonComp();
1853
1855 return TBufferJSON::ToJSON(&drawing, comp).Data();
1856
1857 comp = comp % TBufferJSON::kSkipTypeInfo; // no typeinfo skipping
1858
1861 json.SetSkipClassInfo(TClass::GetClass<RGeomDrawing>());
1862 json.SetSkipClassInfo(TClass::GetClass<RGeomNode>());
1863 json.SetSkipClassInfo(TClass::GetClass<RGeomVisible>());
1864 json.SetSkipClassInfo(TClass::GetClass<RGeomShapeRenderInfo>());
1865 json.SetSkipClassInfo(TClass::GetClass<RGeomRawRenderInfo>());
1866
1867 return json.StoreObject(&drawing, TClass::GetClass<RGeomDrawing>()).Data();
1868}
1869
1870/////////////////////////////////////////////////////////////////////////////////
1871/// Change visibility for specified element
1872/// Returns true if changes was performed
1873
1874bool RGeomDescription::ChangeNodeVisibility(const std::vector<std::string> &path, bool selected)
1875{
1876 TLockGuard lock(fMutex);
1877
1878 RGeomBrowserIter giter(*this);
1879 if (!giter.Navigate(path))
1880 return false;
1881
1882 auto nodeid = giter.GetNodeId();
1883
1884 auto &dnode = fDesc[nodeid];
1885
1886 auto vol = GetVolume(nodeid);
1887
1888 // nothing changed
1889 if (vol->IsVisible() == selected)
1890 return false;
1891
1892 dnode.vis = selected ? 99 : 0;
1893 vol->SetVisibility(selected);
1894 if (!dnode.chlds.empty()) {
1895 if (selected)
1896 dnode.vis = 1; // visibility disabled when any child
1897 vol->SetVisDaughters(selected);
1898 }
1899
1900 int id = 0;
1901 for (auto &desc : fDesc)
1902 if (GetVolume(id++) == vol)
1903 desc.vis = dnode.vis;
1904
1905 auto stack = MakeStackByIds(giter.CurrentIds());
1906
1907 // any change in logical node visibility erase individual physical node settings
1908 for (auto iter = fVisibility.begin(); iter != fVisibility.end(); iter++)
1909 if (compare_stacks(iter->stack, stack) == 0) {
1910 fVisibility.erase(iter);
1911 break;
1912 }
1913
1914 _ClearDrawData(); // after change raw data is no longer valid
1915
1916 return true;
1917}
1918
1919/////////////////////////////////////////////////////////////////////////////////
1920/// Change visibility for specified element
1921/// Returns true if changes was performed
1922
1923std::unique_ptr<RGeomNodeInfo> RGeomDescription::MakeNodeInfo(const std::vector<int> &stack)
1924{
1925 auto path = MakePathByStack(stack);
1926
1927 TLockGuard lock(fMutex);
1928
1929 std::unique_ptr<RGeomNodeInfo> res;
1930
1931 RGeomBrowserIter iter(*this);
1932
1933 if (iter.Navigate(path)) {
1934
1935 auto node = fNodes[iter.GetNodeId()];
1936
1937 auto &desc = fDesc[iter.GetNodeId()];
1938
1939 res = std::make_unique<RGeomNodeInfo>();
1940
1941 res->path = path;
1942 res->node_name = node ? node->GetName() : "node_name";
1943 res->node_type = node ? node->ClassName() : "no class";
1944
1945 auto vol = GetVolume(iter.GetNodeId());
1946
1947 TGeoShape *shape = vol ? vol->GetShape() : nullptr;
1948
1949 if (shape) {
1950 res->shape_name = shape->GetName();
1951 res->shape_type = shape->ClassName();
1952 }
1953
1954 if (shape && desc.CanDisplay()) {
1955
1956 auto &shape_descr = MakeShapeDescr(shape);
1957
1958 res->ri = shape_descr.rndr_info(); // temporary pointer, can be used preserved for short time
1959 }
1960 }
1961
1962 return res;
1963}
1964
1965/////////////////////////////////////////////////////////////////////////////////
1966/// Select top node by path
1967/// Used by the client to change active node
1968/// Returns true if selected node was changed
1969
1970bool RGeomDescription::SelectTop(const std::vector<std::string> &path)
1971{
1972 TLockGuard lock(fMutex);
1973
1974 RGeomBrowserIter iter(*this);
1975
1976 if (!iter.Navigate(path))
1977 return false;
1978
1979 auto stack = MakeStackByIds(iter.CurrentIds());
1980 if (stack == fSelectedStack)
1981 return false;
1982
1983 fSelectedStack = stack;
1984
1985 _ClearDrawData();
1986
1987 return true;
1988}
1989
1990/////////////////////////////////////////////////////////////////////////////////
1991/// Set visibility of physical node by path
1992/// It overrules TGeo visibility flags - but only for specific physical node
1993
1994bool RGeomDescription::SetPhysNodeVisibility(const std::vector<std::string> &path, bool on)
1995{
1996 TLockGuard lock(fMutex);
1997
1998 RGeomBrowserIter giter(*this);
1999
2000 if (!giter.Navigate(path))
2001 return false;
2002
2003 auto stack = MakeStackByIds(giter.CurrentIds());
2004
2005 auto nodeid = giter.GetNodeId();
2006
2007 for (auto iter = fVisibility.begin(); iter != fVisibility.end(); iter++) {
2008 auto res = compare_stacks(iter->stack, stack);
2009
2010 if (res == 0) {
2011 bool changed = iter->visible != on;
2012 if (changed) {
2013 iter->visible = on;
2014 _ClearDrawData();
2015
2016 // no need for custom settings if match with description
2017 if ((fDesc[nodeid].vis > 0) == on)
2018 fVisibility.erase(iter);
2019 }
2020
2021 return changed;
2022 }
2023
2024 if (res > 0) {
2025 fVisibility.emplace(iter, stack, on);
2026 _ClearDrawData();
2027 return true;
2028 }
2029 }
2030
2031 fVisibility.emplace_back(stack, on);
2032 _ClearDrawData();
2033 return true;
2034}
2035
2036/////////////////////////////////////////////////////////////////////////////////
2037/// Set visibility of physical node by itemname
2038/// itemname in string with path like "/TOP_1/SUB_2/NODE_3"
2039
2041{
2042 std::vector<std::string> path;
2043 std::string::size_type p1 = 0;
2044
2045 while (p1 < itemname.length()) {
2046 if (itemname[p1] == '/') {
2047 p1++;
2048 continue;
2049 }
2050 auto p = itemname.find('/', p1);
2051 if (p == std::string::npos) {
2052 path.emplace_back(itemname.substr(p1));
2053 p1 = itemname.length();
2054 } else {
2055 path.emplace_back(itemname.substr(p1, p - p1));
2056 p1 = p + 1;
2057 }
2058 }
2059
2060 return SetPhysNodeVisibility(path, on);
2061}
2062
2063/////////////////////////////////////////////////////////////////////////////////
2064/// Check if there special settings for specified physical node
2065/// returns -1 if nothing is found
2066
2067int RGeomDescription::IsPhysNodeVisible(const std::vector<int> &stack)
2068{
2069 for (auto &item : fVisibility) {
2070 unsigned sz = item.stack.size();
2071 if (stack.size() < sz)
2072 continue;
2073 bool match = true;
2074 for (unsigned n = 0; n < sz; ++n)
2075 if (stack[n] != item.stack[n]) {
2076 match = false;
2077 break;
2078 }
2079
2080 if (match)
2081 return item.visible ? 1 : 0;
2082 }
2083 return -1;
2084}
2085
2086/////////////////////////////////////////////////////////////////////////////////
2087/// Reset custom visibility of physical node by path
2088
2089bool RGeomDescription::ClearPhysNodeVisibility(const std::vector<std::string> &path)
2090{
2091 TLockGuard lock(fMutex);
2092
2093 RGeomBrowserIter giter(*this);
2094
2095 if (!giter.Navigate(path))
2096 return false;
2097
2098 auto stack = MakeStackByIds(giter.CurrentIds());
2099
2100 for (auto iter = fVisibility.begin(); iter != fVisibility.end(); iter++)
2101 if (compare_stacks(iter->stack, stack) == 0) {
2102 fVisibility.erase(iter);
2103 _ClearDrawData();
2104 return true;
2105 }
2106
2107 return false;
2108}
2109
2110/////////////////////////////////////////////////////////////////////////////////
2111/// Reset all custom visibility settings
2112
2114{
2115 TLockGuard lock(fMutex);
2116
2117 if (fVisibility.empty())
2118 return false;
2119
2120 fVisibility.clear();
2121 _ClearDrawData();
2122 return true;
2123}
2124
2125/////////////////////////////////////////////////////////////////////////////////
2126/// Change configuration by client
2127/// Returns true if any parameter was really changed
2128
2130{
2131 auto cfg = TBufferJSON::FromJSON<RGeomConfig>(json);
2132 if (!cfg)
2133 return false;
2134
2135 TLockGuard lock(fMutex);
2136
2137 auto json1 = TBufferJSON::ToJSON(cfg.get());
2138 auto json2 = TBufferJSON::ToJSON(&fCfg);
2139
2140 if (json1 == json2)
2141 return false;
2142
2143 fCfg = *cfg; // use assign
2144
2145 _ClearDrawData();
2146
2147 return true;
2148}
2149
2150/////////////////////////////////////////////////////////////////////////////////
2151/// Change search query and belongs to it json string
2152/// Returns true if any parameter was really changed
2153
2154bool RGeomDescription::SetSearch(const std::string &query, const std::string &json)
2155{
2156 TLockGuard lock(fMutex);
2157
2158 bool changed = (fSearch != query) || (fSearchJson != json);
2159 fSearch = query;
2160 fSearchJson = json;
2161 return changed;
2162}
2163
2164/////////////////////////////////////////////////////////////////////////////////
2165/// Save geometry configuration as C++ macro
2166
2167void RGeomDescription::SavePrimitive(std::ostream &fs, const std::string &name)
2168{
2169 std::string prefix = " ";
2170
2171 if (fCfg.vislevel != 0)
2172 fs << prefix << name << "SetVisLevel(" << fCfg.vislevel << ");" << std::endl;
2173 if (fCfg.maxnumnodes != 0)
2174 fs << prefix << name << "SetMaxVisNodes(" << fCfg.maxnumnodes << ");" << std::endl;
2175 if (fCfg.maxnumfaces != 0)
2176 fs << prefix << name << "SetMaxVisFaces(" << fCfg.maxnumfaces << ");" << std::endl;
2177 if (fCfg.showtop)
2178 fs << prefix << name << "SetTopVisible(true);" << std::endl;
2179 if (fCfg.build_shapes != 1)
2180 fs << prefix << name << "SetBuildShapes(" << fCfg.build_shapes << ");" << std::endl;
2181 if (fCfg.nsegm != 0)
2182 fs << prefix << name << "SetNSegments(" << fCfg.nsegm << ");" << std::endl;
2183 if (!fCfg.drawopt.empty())
2184 fs << prefix << name << "SetDrawOptions(\"" << fCfg.drawopt << "\");" << std::endl;
2185 if (fJsonComp != 0)
2186 fs << prefix << name << "SetJsonComp(" << fJsonComp << ");" << std::endl;
2187
2188 // store custom visibility flags
2189 for (auto &item : fVisibility) {
2190 auto path = MakePathByStack(item.stack);
2191 fs << prefix << name << "SetPhysNodeVisibility(";
2192 for (int i = 0; i < (int)path.size(); ++i)
2193 fs << (i == 0 ? "{\"" : ", \"") << path[i] << "\"";
2194 fs << "}, " << (item.visible ? "true" : "false") << ");" << std::endl;
2195 }
2196}
nlohmann::json json
std::unique_ptr< RootCsg::TBaseMesh > MakeGeoMesh(TGeoMatrix *matr, TGeoShape *shape)
Function produces mesh for provided shape, applying matrix to the result.
#define R__LOG_ERROR(...)
Definition RLogger.hxx:357
#define b(i)
Definition RSha256.hxx:100
#define a(i)
Definition RSha256.hxx:99
#define e(i)
Definition RSha256.hxx:103
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 Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h offset
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void on
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t UChar_t len
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void funcs
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize fs
char name[80]
Definition TGX11.cxx:148
R__EXTERN TGeoManager * gGeoManager
#define gROOT
Definition TROOT.h:426
Reply on browser request.
Representation of single item in the geometry browser.
Definition RGeomData.hxx:88
Iterator of hierarchical geometry structures.
Definition RGeomData.cxx:60
RGeomBrowserIter(RGeomDescription &desc)
Definition RGeomData.cxx:71
std::vector< int > CurrentIds() const
Returns array of ids to currently selected node.
bool Navigate(TGeoVolume *vol)
Navigate to specified volume - find first occurrence.
std::vector< int > fStackChilds
Definition RGeomData.cxx:68
bool Navigate(const std::string &path)
Navigate to specified path - path specified as string and should start with "/".
const std::string & GetMaterial() const
Definition RGeomData.cxx:77
std::vector< int > fStackParents
Definition RGeomData.cxx:67
bool HasChilds() const
Definition RGeomData.cxx:85
RGeomDescription & fDesc
Definition RGeomData.cxx:62
const std::string & GetColor() const
Definition RGeomData.cxx:75
const std::string & GetName() const
Definition RGeomData.cxx:73
bool Navigate(const std::vector< std::string > &path)
Navigate to specified path
int IsPhysNodeVisible(const std::vector< int > &stack)
Check if there special settings for specified physical node returns -1 if nothing is found.
std::string ProcessBrowserRequest(const std::string &req="")
Find description object for requested shape If not exists - will be created.
std::vector< RGeomNode > fDesc
! converted description, send to client
void PackMatrix(std::vector< float > &arr, TGeoMatrix *matr)
Pack matrix into vector, which can be send to client Following sizes can be used for vector: 0 - Iden...
bool ProduceDrawingFor(int nodeid, std::string &json, bool check_volume=false)
Produce shape rendering data for given stack All nodes, which are referencing same shape will be tran...
std::unique_ptr< RGeomNodeInfo > MakeNodeInfo(const std::vector< int > &stack)
Change visibility for specified element Returns true if changes was performed.
bool HasDrawData() const
Check if there is draw data available.
std::vector< int > MakeIdsByStack(const std::vector< int > &stack)
Produce list of node ids for given stack If found nodes preselected - use their ids.
int MarkVisible(bool on_screen=false)
Set visibility flag for each nodes.
void IssueSignal(const void *handler, const std::string &kind)
Issue signal, which distributed on all handlers - excluding source handler.
int GetUsedNSegments(int min=20)
Returns really used number of cylindrical segments.
bool IsPrincipalEndNode(int nodeid)
return true when node used in main geometry drawing and does not have childs for such nodes one could...
bool SetSearch(const std::string &query, const std::string &json)
Change search query and belongs to it json string Returns true if any parameter was really changed.
bool SelectTop(const std::vector< std::string > &path)
Select top node by path Used by the client to change active node Returns true if selected node was ch...
void ClearCache()
Clear cached data, need to be clear when connection broken.
virtual void RefineGeoItem(RGeoItem &item, const std::vector< int > &stack)
Method which allows to add/modify information in RGeoItem which will be provided to client - like tit...
void ClearDescription()
Clear geometry description.
std::vector< int > MakeStackByIds(const std::vector< int > &ids)
Creates stack for given array of ids, first element always should be 0.
bool ChangeNodeVisibility(const std::vector< std::string > &path, bool on)
Change visibility for specified element Returns true if changes was performed.
void SavePrimitive(std::ostream &fs, const std::string &name)
Save geometry configuration as C++ macro.
bool ClearAllPhysVisibility()
Reset all custom visibility settings.
std::string MakeDrawingJson(RGeomDrawing &drawing, bool has_shapes=false)
Produce JSON for the drawing If TGeoShape appears in the drawing, one has to keep typeinfo But in thi...
TGeoVolume * GetVolume(int nodeid)
Get volume for specified nodeid If specific volume was configured, it will be returned for nodeid==0.
void ProduceDrawData()
Collect all information required to draw geometry on the client This includes list of each visible no...
bool SetPhysNodeVisibility(const std::vector< std::string > &path, bool on=true)
Set visibility of physical node by path It overrules TGeo visibility flags - but only for specific ph...
bool ClearPhysNodeVisibility(const std::vector< std::string > &path)
Reset custom visibility of physical node by path.
void BuildDescription(TGeoNode *topnode, TGeoVolume *topvolume)
Build geometry description.
int SearchVisibles(const std::string &find, std::string &hjson, std::string &json)
Search visible nodes for provided name If number of found elements less than 100, create description ...
std::string ProduceJson(bool all_nodes=false)
Produce JSON string which can be directly used with build function from JSROOT to create three....
void ClearDrawData()
Clear drawing data.
std::vector< std::string > MakePathByStack(const std::vector< int > &stack)
Returns path string for provided stack.
void AddSignalHandler(const void *handler, RGeomSignalFunc_t func)
Add signal handler.
bool ChangeConfiguration(const std::string &json)
Change configuration by client Returns true if any parameter was really changed.
void CopyMaterialProperties(TGeoVolume *vol, RGeomNode &node)
Copy material properties.
std::vector< int > MakeStackByPath(const std::vector< std::string > &path)
Produce stack based on string path Used to highlight geo volumes by browser hover event.
int ScanNodes(bool only_visible, int maxlvl, RGeomScanFunc_t func)
Iterate over all nodes and call function for visible.
void ProduceSearchData()
Produces search data if necessary.
void CollectNodes(RGeomDrawing &drawing, bool all_nodes=false)
Collect nodes which are used in visibles.
int CountShapeFaces(TGeoShape *shape)
Count number of faces for the shape.
ShapeDescr & MakeShapeDescr(TGeoShape *shape)
Find description object and create render information.
ShapeDescr & FindShapeDescr(TGeoShape *shape)
Find description object for requested shape If not exists - will be created.
void RemoveSignalHandler(const void *handler)
Remove signal handler.
int FindNodeId(const std::vector< int > &stack)
Returns nodeid for given stack array, returns -1 in case of failure.
void ProduceIdShifts()
Count total number of visible childs under each node.
std::string ProduceModifyReply(int nodeid)
Return string with only part of nodes description which were modified Checks also volume.
void ResetRndrInfos()
Reset shape info, which used to pack binary data.
virtual bool IsFullModelStreamedAtOnce() const
Decide if the whole model is streamed at once Function is called from ProcessBrowserRequest.
void Build(TGeoManager *mgr, const std::string &volname="")
Collect information about geometry hierarchy into flat list like it done in JSROOT ClonedNodes....
Object with full description for drawing geometry It includes list of visible items and list of nodes...
int numnodes
total number of nodes in description
std::vector< RGeomVisible > visibles
all visible items
RGeomConfig * cfg
current configurations
std::vector< RGeomNode * > nodes
all used nodes to display visible items and not known for client
std::string material
name of the material
Definition RGeomData.hxx:50
int sortid
! place in sorted array, to check cuts, or id of original node when used search structures
Definition RGeomData.hxx:51
std::string color
rgb code in hex format
Definition RGeomData.hxx:49
int id
node id, index in array
Definition RGeomData.hxx:43
Full node description including matrices and other attributes.
Definition RGeomData.hxx:68
float opacity
! opacity of the color
Definition RGeomData.hxx:75
A log configuration for a channel, e.g.
Definition RLogger.hxx:98
const_iterator begin() const
const_iterator end() const
virtual Color_t GetFillColor() const
Return the fill area color.
Definition TAttFill.h:32
virtual Color_t GetLineColor() const
Return the line color.
Definition TAttLine.h:36
Class for serializing object to and from JavaScript Object Notation (JSON) format.
Definition TBufferJSON.h:30
static TString ToJSON(const T *obj, Int_t compact=0, const char *member_name=nullptr)
Definition TBufferJSON.h:77
@ kSkipTypeInfo
do not store typenames in JSON
Definition TBufferJSON.h:48
void SetCompact(int level)
Set level of space/newline/array compression Lower digit of compact parameter define formatting rules...
The color creation and management class.
Definition TColor.h:22
Float_t GetRed() const
Definition TColor.h:61
static Int_t GetColor(const char *hexcolor)
Static method returning color number for color specified by hex color string of form: "#rrggbb",...
Definition TColor.cxx:1926
Float_t GetAlpha() const
Definition TColor.h:67
Float_t GetBlue() const
Definition TColor.h:63
Float_t GetGreen() const
Definition TColor.h:62
@ kVisNone
Definition TGeoAtt.h:25
Box class.
Definition TGeoBBox.h:18
Composite shapes are Boolean combinations of two or more shape components.
static TClass * Class()
A cone segment is a cone having a range in phi.
Definition TGeoCone.h:99
static TClass * Class()
The cones are defined by 5 parameters:
Definition TGeoCone.h:17
static TClass * Class()
The cut tubes constructor has the form:
Definition TGeoTube.h:174
static TClass * Class()
static TClass * Class()
Matrix class used for computing global transformations Should NOT be used for node definition.
Definition TGeoMatrix.h:459
void Multiply(const TGeoMatrix *right)
multiply to the right with an other transformation if right is identity matrix, just return
A hyperboloid is represented as a solid limited by two planes perpendicular to the Z axis (top and bo...
Definition TGeoHype.h:17
static TClass * Class()
static TClass * Class()
A geometry iterator.
Definition TGeoNode.h:249
void Skip()
Stop iterating the current branch.
The manager class for any TGeo geometry.
Definition TGeoManager.h:46
void SetNsegments(Int_t nseg)
Set number of segments for approximating circles in drawing.
Int_t GetNsegments() const
Get number of segments approximating circles.
Geometrical transformation package.
Definition TGeoMatrix.h:39
virtual const Double_t * GetTranslation() const =0
TClass * IsA() const override
Definition TGeoMatrix.h:105
virtual void LocalToMaster(const Double_t *local, Double_t *master) const
convert a point by multiplying its column vector (x, y, z, 1) to matrix inverse
virtual const Double_t * GetScale() const =0
Bool_t IsIdentity() const
Definition TGeoMatrix.h:64
virtual const Double_t * GetRotationMatrix() const =0
TGeoMaterial * GetMaterial() const
Definition TGeoMedium.h:49
A node represent a volume positioned inside another.They store links to both volumes and to the TGeoM...
Definition TGeoNode.h:39
A paraboloid is defined by the revolution surface generated by a parabola and is bounded by two plane...
static TClass * Class()
A polycone is represented by a sequence of tubes/cones, glued together at defined Z planes.
Definition TGeoPcon.h:17
static TClass * Class()
Polygons are defined in the same way as polycones, the difference being just that the segments betwee...
Definition TGeoPgon.h:20
static TClass * Class()
static TClass * Class()
static TClass * Class()
A shape scaled by a TGeoScale transformation.
static TClass * Class()
Base abstract class for all shapes.
Definition TGeoShape.h:25
virtual Bool_t IsComposite() const
Definition TGeoShape.h:139
virtual Bool_t IsCylType() const =0
const char * GetName() const override
Get the shape name.
TClass * IsA() const override
Definition TGeoShape.h:181
virtual TBuffer3D * MakeBuffer3D() const
Definition TGeoShape.h:156
TGeoSphere are not just balls having internal and external radii, but sectors of a sphere having defi...
Definition TGeoSphere.h:17
static TClass * Class()
static TClass * Class()
Tessellated solid class.
static TClass * Class()
The torus is defined by its axial radius, its inner and outer radius.
Definition TGeoTorus.h:17
static TClass * Class()
static TClass * Class()
A tube segment is a tube having a range in phi.
Definition TGeoTube.h:94
static TClass * Class()
Cylindrical tube class.
Definition TGeoTube.h:17
static TClass * Class()
static TClass * Class()
TGeoVolume, TGeoVolumeMulti, TGeoVolumeAssembly are the volume classes.
Definition TGeoVolume.h:43
TGeoMedium * GetMedium() const
Definition TGeoVolume.h:176
TObjArray * GetNodes()
Definition TGeoVolume.h:170
static TGeoMedium * DummyMedium()
TGeoShape * GetShape() const
Definition TGeoVolume.h:191
A TGeoXtru shape is represented by the extrusion of an arbitrary polygon with fixed outline between s...
Definition TGeoXtru.h:22
static TClass * Class()
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition TObject.cxx:224
Regular expression class.
Definition TRegexp.h:31
Basic string class.
Definition TString.h:138
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition TString.h:660
const Int_t n
Definition legend1.C:16
RLogChannel & RGeomLog()
Log channel for Geomviewer diagnostics.
Definition RGeomData.cxx:49
std::function< bool(RGeomNode &, std::vector< int > &, bool, int)> RGeomScanFunc_t
std::function< void(const std::string &)> RGeomSignalFunc_t
Int_t Nint(T x)
Round to nearest integer. Rounds half integers to the nearest even integer.
Definition TMath.h:704
Short_t Max(Short_t a, Short_t b)
Returns the largest of a and b.
Definition TMathBase.h:249
Double_t Sqrt(Double_t x)
Returns the square root of x.
Definition TMath.h:673
Short_t Abs(Short_t d)
Returns the absolute value of parameter Short_t d.
Definition TMathBase.h:122