Logo ROOT  
Reference Guide
REveGeomViewer.cxx
Go to the documentation of this file.
1 // @(#)root/eve7:$Id$
2 // Author: Sergey Linev, 13.12.2018
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 #include <ROOT/REveGeomViewer.hxx>
13 
14 #include <ROOT/RLogger.hxx>
15 #include <ROOT/RWebWindow.hxx>
16 
17 #include "TSystem.h"
18 #include "TBase64.h"
19 #include "TROOT.h"
20 #include "TEnv.h"
21 #include "THttpServer.h"
22 #include "TBufferJSON.h"
23 #include "TGeoManager.h"
24 
25 #include <fstream>
26 
27 using namespace std::string_literals;
28 
29 //////////////////////////////////////////////////////////////////////////////////////////////
30 /// constructor
31 
33 {
34  fWebWindow = RWebWindow::Create();
35  fWebWindow->SetDefaultPage("file:rootui5sys/eve7/geom.html");
36 
37  // this is call-back, invoked when message received via websocket
38  fWebWindow->SetDataCallBack([this](unsigned connid, const std::string &arg) { this->WebWindowCallback(connid, arg); });
39  fWebWindow->SetGeometry(900, 700); // configure predefined window geometry
40  fWebWindow->SetConnLimit(1); // the only connection is allowed
41  fWebWindow->SetMaxQueueLength(30); // number of allowed entries in the window queue
42 
43  fDesc.SetPreferredOffline(gEnv->GetValue("WebGui.PreferredOffline",0) != 0);
44  fDesc.SetJsonComp(gEnv->GetValue("WebGui.JsonComp", TBufferJSON::kSkipTypeInfo + TBufferJSON::kNoSpaces));
45  fDesc.SetBuildShapes(gEnv->GetValue("WebGui.GeomBuildShapes", 1));
46 
47  if (mgr) SetGeometry(mgr, volname);
48 }
49 
50 //////////////////////////////////////////////////////////////////////////////////////////////
51 /// destructor
52 
54 {
55 
56 }
57 
58 //////////////////////////////////////////////////////////////////////////////////////////////
59 /// assign new geometry to the viewer
60 
61 void ROOT::Experimental::REveGeomViewer::SetGeometry(TGeoManager *mgr, const std::string &volname)
62 {
63  fGeoManager = mgr;
64  fSelectedVolume = volname;
65 
66  fDesc.Build(mgr, volname);
67 
68  Update();
69 }
70 
71 
72 /////////////////////////////////////////////////////////////////////////////////
73 /// Select visible top volume, all other volumes will be disabled
74 
75 void ROOT::Experimental::REveGeomViewer::SelectVolume(const std::string &volname)
76 {
77  if (volname != fSelectedVolume)
78  SetGeometry(fGeoManager, volname);
79 }
80 
81 /////////////////////////////////////////////////////////////////////////////////
82 /// Show or update geometry in web window
83 /// If web browser already started - just refresh drawing like "reload" button does
84 /// If no web window exists or \param always_start_new_browser configured, starts new window
85 
86 void ROOT::Experimental::REveGeomViewer::Show(const RWebDisplayArgs &args, bool always_start_new_browser)
87 {
88  std::string user_args = "";
89  if (!GetShowHierarchy()) user_args = "{ nobrowser: true }";
90  fWebWindow->SetUserArgs(user_args);
91 
92  if ((fWebWindow->NumConnections(true) == 0) || always_start_new_browser)
93  fWebWindow->Show(args);
94  else
95  Update();
96 }
97 
98 //////////////////////////////////////////////////////////////////////////////////////////////
99 /// Update geometry drawings in all web displays
100 
102 {
103  fWebWindow->Send(0, "RELOAD");
104 }
105 
106 //////////////////////////////////////////////////////////////////////////////////////////////
107 /// convert JSON into stack array
108 
109 std::vector<int> ROOT::Experimental::REveGeomViewer::GetStackFromJson(const std::string &json, bool node_ids)
110 {
111  std::vector<int> *stack{nullptr}, res;
112 
113  if (TBufferJSON::FromJSON(stack, json.c_str())) {
114  if (node_ids) res = fDesc.MakeStackByIds(*stack);
115  else res = *stack;
116  delete stack;
117  } else {
118  R__ERROR_HERE("webeve") << "Fail convert " << json << " into vector<int>";
119  }
120 
121  return res;
122 }
123 
124 //////////////////////////////////////////////////////////////////////////////////////////////
125 /// Send data for principal geometry draw
126 
128 {
129  if (!fDesc.HasDrawData())
130  fDesc.CollectVisibles();
131 
132  auto &json = fDesc.GetDrawJson();
133 
134  R__DEBUG_HERE("webeve") << "Produce geometry JSON len: " << json.length();
135 
136  fWebWindow->Send(connid, json);
137 }
138 
139 //////////////////////////////////////////////////////////////////////////////////////////////
140 /// Configures draw option for geometry
141 /// Normally has effect before first drawing of the geometry
142 /// When geometry displayed, only "axis" and "rotate" options are updated
143 
145 {
146  fDesc.SetDrawOptions(opt);
147  unsigned connid = fWebWindow->GetConnectionId();
148  if (connid)
149  fWebWindow->Send(connid, "DROPT:"s + opt);
150 }
151 
152 //////////////////////////////////////////////////////////////////////////////////////////////
153 /// Produce PNG image of drawn geometry
154 /// Drawing should be completed at the moment
155 /// Executed asynchronous - method returns immediately, image stored when received from the client
156 
157 void ROOT::Experimental::REveGeomViewer::SaveImage(const std::string &fname)
158 {
159  unsigned connid = fWebWindow->GetConnectionId();
160  if (connid)
161  fWebWindow->Send(connid, "IMAGE:"s + fname);
162 }
163 
164 //////////////////////////////////////////////////////////////////////////////////////////////
165 /// receive data from client
166 
167 void ROOT::Experimental::REveGeomViewer::WebWindowCallback(unsigned connid, const std::string &arg)
168 {
169  printf("Recv %s\n", arg.substr(0,100).c_str());
170 
171  if (arg == "GETDRAW") {
172 
173  SendGeometry(connid);
174 
175  } else if (arg == "QUIT_ROOT") {
176 
177  fWebWindow->TerminateROOT();
178 
179  } else if (arg.compare(0, 7, "SEARCH:") == 0) {
180 
181  std::string query = arg.substr(7);
182 
183  std::string hjson, json;
184 
185  auto nmatches = fDesc.SearchVisibles(query, hjson, json);
186 
187  printf("Searches %s found %d hjson %d json %d\n", query.c_str(), nmatches, (int) hjson.length(), (int) json.length());
188 
189  // send reply with appropriate header - NOFOUND, FOUND0:, FOUND1:
190  fWebWindow->Send(connid, hjson);
191 
192  if (!json.empty())
193  fWebWindow->Send(connid, json);
194 
195  } else if (arg.compare(0,4,"GET:") == 0) {
196  // provide exact shape
197 
198  auto stack = GetStackFromJson(arg.substr(4));
199 
200  auto nodeid = fDesc.FindNodeId(stack);
201 
202  std::string json{"SHAPE:"};
203 
204  fDesc.ProduceDrawingFor(nodeid, json);
205 
206  printf("Produce shape for stack json %d\n", (int) json.length());
207 
208  fWebWindow->Send(connid, json);
209 
210  } else if (arg.compare(0, 6, "GVREQ:") == 0) {
211 
212  auto req = TBufferJSON::FromJSON<REveGeomRequest>(arg.substr(6));
213 
214  if (req && (req->oper == "HOVER")) {
215  if (req->path != "OFF")
216  req->stack = fDesc.MakeStackByPath(req->path);
217  req->path.clear();
218  } else if (req && (req->oper == "HIGHL")) {
219  if (req->stack.size() > 0)
220  req->path = fDesc.MakePathByStack(req->stack);
221  req->stack.clear();
222  } else if (req && (req->oper == "INFO")) {
223 
224  auto info = fDesc.MakeNodeInfo(req->path);
225  if (info)
226  fWebWindow->Send(connid, "NINFO:"s + TBufferJSON::ToJSON(info.get(), (fDesc.GetJsonComp() % 5) + TBufferJSON::kSameSuppression).Data());
227 
228  // not request but different object type is send
229  req.reset(nullptr);
230 
231  } else {
232  req.reset(nullptr);
233  }
234 
235  if (req)
236  fWebWindow->Send(connid, "GVRPL:"s + TBufferJSON::ToJSON(req.get(), TBufferJSON::kSkipTypeInfo + TBufferJSON::kNoSpaces).Data());
237 
238  } else if ((arg.compare(0, 7, "SETVI0:") == 0) || (arg.compare(0, 7, "SETVI1:") == 0)) {
239  // change visibility for specified nodeid
240 
241  auto nodeid = std::stoi(arg.substr(7));
242 
243  bool selected = (arg[5] == '1');
244 
245  if (fDesc.ChangeNodeVisibility(nodeid, selected)) {
246 
247  // send only modified entries, includes all nodes with same volume
248  std::string json0 = fDesc.ProduceModifyReply(nodeid);
249 
250  // when visibility disabled, client will automatically remove node from drawing
251  fWebWindow->Send(connid, json0);
252 
253  if (selected && fDesc.IsPrincipalEndNode(nodeid)) {
254  // we need to send changes in drawing elements
255  // there can be many elements, which reference same volume
256 
257  std::string json{"APPND:"};
258 
259  if (fDesc.ProduceDrawingFor(nodeid, json, true)) {
260 
261  printf("Send appending JSON %d\n", (int) json.length());
262 
263  fWebWindow->Send(connid, json);
264  }
265  } else if (selected) {
266 
267  // just resend full geometry
268  // TODO: one can improve here and send only nodes which are not exists on client
269  // TODO: for that one should remember all information send to client
270 
271  auto json = fDesc.ProcessBrowserRequest();
272  if (json.length() > 0) fWebWindow->Send(connid, json);
273 
274  SendGeometry(connid);
275  }
276  }
277  } else if (arg.compare(0,6, "BRREQ:") == 0) {
278 
279  // central place for processing browser requests
280 
281  if (!fDesc.IsBuild()) fDesc.Build(fGeoManager);
282 
283  auto json = fDesc.ProcessBrowserRequest(arg.substr(6));
284  if (json.length() > 0) fWebWindow->Send(connid, json);
285  } else if (arg.compare(0,6, "IMAGE:") == 0) {
286  auto separ = arg.find("::",6);
287  if (separ == std::string::npos) return;
288 
289  std::string fname = arg.substr(6, separ-6);
290  if (fname.empty()) {
291  int cnt = 0;
292  do {
293  fname = "geometry"s;
294  if (cnt++>0) fname += std::to_string(cnt);
295  fname += ".png"s;
296  } while (!gSystem->AccessPathName(fname.c_str()));
297  }
298 
299  TString binary = TBase64::Decode(arg.c_str() + separ + 2);
300 
301  std::ofstream ofs(fname);
302  ofs.write(binary.Data(), binary.Length());
303  ofs.close();
304 
305  printf("Image file %s size %d has been created\n", fname.c_str(), (int) binary.Length());
306 
307  } else if (arg.compare(0,4, "CFG:") == 0) {
308 
309  if (fDesc.ChangeConfiguration(arg.substr(4)))
310  SendGeometry(connid);
311 
312  } else if (arg == "RELOAD") {
313 
314  SendGeometry(connid);
315  }
316 }
ROOT::Experimental::REveGeomViewer::SelectVolume
void SelectVolume(const std::string &volname)
Select visible top volume, all other volumes will be disabled.
Definition: REveGeomViewer.cxx:75
ROOT::Experimental::REveGeomViewer::REveGeomViewer
REveGeomViewer(TGeoManager *mgr=nullptr, const std::string &volname="")
constructor
Definition: REveGeomViewer.cxx:32
ROOT::Experimental::REveGeomViewer::Show
void Show(const RWebDisplayArgs &args="", bool always_start_new_browser=false)
Show or update geometry in web window If web browser already started - just refresh drawing like "rel...
Definition: REveGeomViewer.cxx:86
ROOT::Experimental::REveGeomViewer::SetGeometry
void SetGeometry(TGeoManager *mgr, const std::string &volname="")
assign new geometry to the viewer
Definition: REveGeomViewer.cxx:61
nlohmann::json
basic_json<> json
default JSON class
Definition: REveElement.hxx:88
gEnv
R__EXTERN TEnv * gEnv
Definition: TEnv.h:171
TString::Data
const char * Data() const
Definition: TString.h:369
TGeant4Unit::s
static constexpr double s
Definition: TGeant4SystemOfUnits.h:162
TBase64::Decode
static TString Decode(const char *data)
Decode a base64 string date into a generic TString.
Definition: TBase64.cxx:131
TString::Length
Ssiz_t Length() const
Definition: TString.h:410
ROOT::Experimental::REveGeomViewer::~REveGeomViewer
virtual ~REveGeomViewer()
destructor
Definition: REveGeomViewer.cxx:53
TEnv::GetValue
virtual Int_t GetValue(const char *name, Int_t dflt) const
Returns the integer value for a resource.
Definition: TEnv.cxx:491
TBufferJSON::FromJSON
static Bool_t FromJSON(T *&obj, const char *json)
Definition: TBufferJSON.h:81
ROOT::Experimental::RWebDisplayArgs
Holds different arguments for starting browser with RWebDisplayHandle::Display() method.
Definition: RWebDisplayArgs.hxx:29
TEnv.h
TString
Basic string class.
Definition: TString.h:136
TSystem::AccessPathName
virtual Bool_t AccessPathName(const char *path, EAccessMode mode=kFileExists)
Returns FALSE if one can access a file using the specified access mode.
Definition: TSystem.cxx:1294
ROOT::Experimental::REveGeomViewer::SendGeometry
void SendGeometry(unsigned connid)
Send data for principal geometry draw.
Definition: REveGeomViewer.cxx:127
TROOT.h
TBufferJSON::kSkipTypeInfo
@ kSkipTypeInfo
Definition: TBufferJSON.h:48
RWebWindow.hxx
RLogger.hxx
R__DEBUG_HERE
#define R__DEBUG_HERE(GROUP)
Definition: RLogger.hxx:186
TSystem.h
TBase64.h
R__ERROR_HERE
#define R__ERROR_HERE(GROUP)
Definition: RLogger.hxx:183
ROOT::Experimental::REveGeomViewer::SaveImage
void SaveImage(const std::string &fname="geometry.png")
Produce PNG image of drawn geometry Drawing should be completed at the moment Executed asynchronous -...
Definition: REveGeomViewer.cxx:157
ROOT::Experimental::REveGeomViewer::WebWindowCallback
void WebWindowCallback(unsigned connid, const std::string &arg)
receive data from client
Definition: REveGeomViewer.cxx:167
TBufferJSON::kSameSuppression
@ kSameSuppression
zero suppression plus compress many similar values together
Definition: TBufferJSON.h:45
TBufferJSON.h
TBufferJSON::kNoSpaces
@ kNoSpaces
no new lines plus remove all spaces around "," and ":" symbols
Definition: TBufferJSON.h:39
gSystem
R__EXTERN TSystem * gSystem
Definition: TSystem.h:559
TGeoManager.h
THttpServer.h
TBufferJSON::ToJSON
static TString ToJSON(const T *obj, Int_t compact=0, const char *member_name=nullptr)
Definition: TBufferJSON.h:75
ROOT::Experimental::REveGeomViewer::GetStackFromJson
std::vector< int > GetStackFromJson(const std::string &json, bool node_ids=false)
convert JSON into stack array
Definition: REveGeomViewer.cxx:109
xmlio::cnt
const char * cnt
Definition: TXMLSetup.cxx:75
TGeoManager
The manager class for any TGeo geometry.
Definition: TGeoManager.h:45
ROOT::Experimental::REveGeomViewer::SetDrawOptions
void SetDrawOptions(const std::string &opt)
Configures draw option for geometry Normally has effect before first drawing of the geometry When geo...
Definition: REveGeomViewer.cxx:144
ROOT::Experimental::REveGeomViewer::Update
void Update()
Update geometry drawings in all web displays.
Definition: REveGeomViewer.cxx:101
REveGeomViewer.hxx