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