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