Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
REveScene.cxx
Go to the documentation of this file.
1// @(#)root/eve7:$Id$
2// Authors: Matevz Tadel & Alja Mrak-Tadel: 2006, 2007, 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/REveScene.hxx>
13#include <ROOT/REveViewer.hxx>
14#include <ROOT/REveManager.hxx>
15#include <ROOT/REveTrans.hxx>
17#include <ROOT/REveClient.hxx>
18#include <ROOT/REveUtil.hxx>
19#include <ROOT/RWebWindow.hxx>
20
21#include <cassert>
22
23#include <nlohmann/json.hpp>
24
25using namespace ROOT::Experimental;
26namespace REX = ROOT::Experimental;
27
28/** \class REveScene
29\ingroup REve
30Eve representation of TGLScene.
31The GLScene is owned by this class - it is created on construction
32time and deleted at destruction.
33
34Normally all objects are positioned directly in global scene-space.
35By setting the fHierarchical flag, positions of children get
36calculated by multiplying the transformation matrices of all parents.
37*/
38
39////////////////////////////////////////////////////////////////////////////////
40/// Constructor.
41
42REveScene::REveScene(const std::string& n, const std::string& t) :
43 REveElement(n, t)
44{
45 fScene = this;
46}
47
48////////////////////////////////////////////////////////////////////////////////
49/// Destructor.
50
58//------------------------------------------------------------------------------
59
60int REveScene::WriteCoreJson(nlohmann::json &j, Int_t rnr_offset)
61{
62 j["Mandatory"] = fMandatory;
63 j["IsOverlay"] = fIsOverlay;
64
65 return REveElement::WriteCoreJson(j, rnr_offset);
66}
67
68//------------------------------------------------------------------------------
69
70void REveScene::AddSubscriber(std::unique_ptr<REveClient> &&sub)
71{
72 assert(sub.get() != nullptr && fAcceptingChanges == kFALSE);
73
74 fSubscribers.emplace_back(std::move(sub));
75
76 // XXX Here should send out the package to the new subscriber,
77 // In principle can expect a new one in short time?
78 // Keep streamed data until next begin change, maybe.
79}
80
82{
83 auto pred = [&](std::unique_ptr<REveClient> &client) {
84 return client->fId == id;
85 };
86
87 fSubscribers.erase(std::remove_if(fSubscribers.begin(), fSubscribers.end(), pred), fSubscribers.end());
88}
89
90// Add Button in client gui with this command
91void REveScene::AddCommand(const std::string &name, const std::string &icon, const REveElement *element, const std::string &action)
92{
93 static const REveException eh("REveScene::AddCommand ");
94 if (element->GetElementId() && element->IsA())
95 {
96 fCommands.emplace_back(name, icon, element, action);
97 }
98 else
99 {
100 throw eh + "Element id and dictionary has to be defined";
101 }
102}
103
105{
106 if (fAcceptingChanges) return;
107
108 if (HasSubscribers()) {
110 /*
111 for (auto &&client : fSubscribers) {
112 REX::gEve->SceneSubscriberProcessingChanges(client->fId);
113 }
114 */
115 }
116}
117
119{
120 assert(fAcceptingChanges);
121
122 fChangedElements.push_back(element);
123}
124
126{
127 fRemovedElements.push_back(id);
128}
129
131{
132 if ( ! fAcceptingChanges) return;
133
135}
136
138{
139 fOutputJson.clear();
140 fOutputBinary.clear();
141
142 fElsWithBinaryData.clear();
144
145 nlohmann::json jarr = nlohmann::json::array();
146
147 nlohmann::json jhdr = {};
148 jhdr["content"] = "REveScene::StreamElements";
149 jhdr["fSceneId"] = fElementId;
150
151 if (!fCommands.empty()) {
152 jhdr["commands"] = nlohmann::json::array();
153 for (auto &&cmd : fCommands) {
154 nlohmann::json jcmd = {};
155 jcmd["name"] = cmd.fName;
156 jcmd["icon"] = cmd.fIcon;
157 jcmd["elementid"] = cmd.fElementId;
158 jcmd["elementclass"] = cmd.fElementClass;
159 jcmd["func"] = cmd.fAction; // SL: may be not needed on client side, can use name
160 jhdr["commands"].push_back(jcmd);
161 }
162 }
163
164 jarr.push_back(jhdr);
165
166 StreamJsonRecurse(this, jarr);
167 // for (auto &c : fChildren)
168 // {
169 // StreamJsonRecurse(c, jarr);
170 // }
171
173 Int_t off = 0;
174
175 for (auto &&e : fElsWithBinaryData)
176 {
177 auto rd_size = e->fRenderData->Write(&fOutputBinary[off], fOutputBinary.size() - off);
178 off += rd_size;
179 }
180 assert(off == fTotalBinarySize);
181
182 jarr.front()["fTotalBinarySize"] = fTotalBinarySize;
183
184 fOutputJson = jarr.dump();
185 REveUtil::AppendServerTime(fOutputJson); // stamped again just before each send
186}
187
188void REveScene::StreamJsonRecurse(REveElement *el, nlohmann::json &jarr)
189{
190 nlohmann::json jobj = {};
191 Int_t rd_size = el->WriteCoreJson(jobj, fTotalBinarySize);
192 jarr.push_back(jobj);
193
194 // If this is another scene, do not stream additional details.
195 // It should be requested / subscribed to independently.
196
197 if (el->fScene == el && el != this)
198 {
199 return;
200 }
201
202 if (rd_size > 0)
203 {
204 assert (rd_size % 4 == 0);
205
206 fTotalBinarySize += rd_size;
207 fElsWithBinaryData.push_back(el);
208 }
209
210 for (auto &&c : el->fChildren)
211 {
212 // Stream only objects element el is a mother of.
213 //
214 // XXXX This is spooky side effect of multi-parenting.
215 //
216 // In particular screwed up for selection.
217 // Selection now streams element ids and implied selected ids
218 // and secondary-ids as part of core json.
219 //
220 // I wonder how this screws up REveProjectionManager (should
221 // we hold a map of already streamed ids?).
222 //
223 // Do uncles and aunts and figure out a clean way for backrefs.
224
225 if (c->GetMother() == el)
226 {
227 StreamJsonRecurse(c, jarr);
228 }
229 }
230}
231
232////////////////////////////////////////////////////////////////////////////////
233/// Move every element whose only pending change is kCBTrans from the change
234/// list into `arr`, for REveManager::SendMotionChanges(). The remaining
235/// elements are streamed as ordinary, acknowledged scene changes.
236
237void REveScene::StreamMotionChanges(nlohmann::json &arr)
238{
239 if (fChangedElements.empty())
240 return;
241
242 List_t keep;
243
244 for (auto &el : fChangedElements) {
245 if (el->GetChangeBits() != REveElement::kCBTrans) {
246 keep.push_back(el);
247 continue;
248 }
249
250 nlohmann::json jobj = {};
251 // clang-format off
252 jobj["fElementId"] = el->GetElementId();
253 jobj["fSceneId"] = GetElementId();
254 // clang-format on
255 el->WriteTransJson(jobj);
256 arr.push_back(jobj);
257
258 el->ClearStamps();
259 }
260
261 fChangedElements.swap(keep);
262}
263
264////////////////////////////////////////////////////////////////////////////////
265//
266/// Prepare data for sending element changes
267//
268////////////////////////////////////////////////////////////////////////////////
269
271{
272 fElsWithBinaryData.clear();
274
275 nlohmann::json jarr = nlohmann::json::array();
276
277 nlohmann::json jhdr = {};
278 jhdr["content"] = "ElementsRepresentaionChanges";
279 jhdr["fSceneId"] = fElementId;
280
281 jhdr["removedElements"] = nlohmann::json::array();
282 for (auto &re : fRemovedElements)
283 jhdr["removedElements"].push_back(re);
284
285 jhdr["numRepresentationChanged"] = fChangedElements.size();
286
287 // jarr.push_back(jhdr);
288
289 for (auto &el: fChangedElements)
290 {
291 UChar_t bits = el->GetChangeBits();
292
293 nlohmann::json jobj = {};
294 jobj["fElementId"] = el->GetElementId();
295 jobj["changeBit"] = bits;
296
297 if (bits & kCBElementAdded || bits & kCBObjProps)
298 {
299 if (gDebug > 0 && bits & kCBElementAdded)
300 {
301 Info("REveScene::StreamRepresentationChanges", "new element change %s %d\n",
302 el->GetCName(), bits);
303 }
304
305 Int_t rd_size = el->WriteCoreJson(jobj, fTotalBinarySize);
306 if (rd_size) {
307 assert (rd_size % 4 == 0);
308 fTotalBinarySize += rd_size;
309 fElsWithBinaryData.push_back(el);
310 }
311 }
312 else
313 {
314 if (bits & kCBVisibility)
315 {
316 jobj["fRnrSelf"] = el->GetRnrSelf();
317 jobj["fRnrChildren"] = el->GetRnrChildren();
318 }
319
320 if (bits & kCBCoreJson) {
321 el->WriteCoreJson(jobj, -1);
322 }
323
324 if (bits & kCBTrans) {
325 el->WriteTransJson(jobj);
326 }
327 }
328
329 jarr.push_back(jobj);
330
331 el->ClearStamps();
332 }
333
334 fChangedElements.clear();
335 fRemovedElements.clear();
336
337 // render data for total change
339 Int_t off = 0;
340
341 for (auto &e : fElsWithBinaryData) {
342 auto rd_size = e->fRenderData->Write(&fOutputBinary[off], fOutputBinary.size() - off);
343
344 off += rd_size;
345 }
346 assert(off == fTotalBinarySize);
347
348 jhdr["fTotalBinarySize"] = fTotalBinarySize;
349
350 nlohmann::json msg = { {"header", jhdr}, {"arr", jarr}};
351 fOutputJson = msg.dump();
352 REveUtil::AppendServerTime(fOutputJson); // stamped again just before each send
353
354 if (gDebug > 0)
355 Info("REveScene::StreamRepresentationChanges", "class: %s changes %s ...", GetCName(), msg.dump(1).c_str() );
356}
357
359{
360 for (auto && client : fSubscribers) {
361 if (!fOutputJson.empty()) {
363 if (gDebug > 0)
364 printf(" sending json, len = %d --> to conn_id = %d\n", (int) fOutputJson.size(), client->fId);
365 client->fWebWindow->Send(client->fId, fOutputJson);
366 }
367 if (fTotalBinarySize) {
368 if (gDebug > 0)
369 printf(" sending binary, len = %d --> to conn_id = %d\n", fTotalBinarySize, client->fId);
370 client->fWebWindow->SendBinary(client->fId, &fOutputBinary[0], fTotalBinarySize);
371 }
373 }
374 fOutputJson.clear();
375 fOutputBinary.clear();
377}
378
380{
381 if (gDebug > 0)
382 ::Info("REveScene::IsChanged","%s (changed_or_added=%d, removed=%d)", GetCName(),
383 (int) fChangedElements.size(), (int) fRemovedElements.size());
384
385 return ! (fChangedElements.empty() && fRemovedElements.empty());
386}
387
388
389/** \class REveSceneList
390\ingroup REve
391List of Scenes providing common operations on REveScene collections.
392*/
393
394////////////////////////////////////////////////////////////////////////////////
395/// Constructor.
396
397REveSceneList::REveSceneList(const std::string& n, const std::string& t) :
398 REveElement(n, t)
399{
400 SetChildClass(TClass::GetClass<REveScene>());
401}
402
403////////////////////////////////////////////////////////////////////////////////
404/// Destroy all scenes and their contents.
405/// The object with non-zero deny-destroy will still survive.
406
408{
409 auto i = fChildren.begin();
410 while (i != fChildren.end())
411 {
412 REveScene* s = (REveScene*) *(i++);
413 s->DestroyElements();
414 s->DestroyOrWarn();
415 }
416}
417
418////////////////////////////////////////////////////////////////////////////////
419/// Loop-wrapers over Scene children, element type checked on insertion.
420
422{
423 for (auto &c: fChildren)
424 {
425 static_cast<REveScene*>(c)->BeginAcceptingChanges();
426 }
427}
428
430{
431 for (auto &c: fChildren)
432 {
433 static_cast<REveScene*>(c)->EndAcceptingChanges();
434 }
435}
436
438{
439 for (auto &el : fChildren)
440 {
441 if (((REveScene*) el)->IsChanged())
442 return true;
443 }
444 return false;
445}
#define c(i)
Definition RSha256.hxx:101
#define e(i)
Definition RSha256.hxx:103
unsigned char UChar_t
Unsigned Character 1 byte (unsigned char)
Definition RtypesCore.h:53
constexpr Bool_t kFALSE
Definition RtypesCore.h:109
constexpr Bool_t kTRUE
Definition RtypesCore.h:108
void Info(const char *location, const char *msgfmt,...)
Use this function for informational messages.
Definition TError.cxx:241
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize id
char name[80]
Definition TGX11.cxx:142
Int_t gDebug
Global variable setting the debug level. Set to 0 to disable, increase it in steps of 1 to increase t...
Definition TROOT.cxx:792
virtual void DestroyOrWarn()
Destroy this element. Prints a warning if deny-destroy is in force.
TClass * IsA() const
Return class for this element Return REveElement class in case dicitonary is not exisiting.
virtual Int_t WriteCoreJson(nlohmann::json &cj, Int_t rnr_offset)
Write core json.
const char * GetCName() const
virtual void DestroyElements()
Destroy all children of this element.
ElementId_t GetElementId() const
std::list< REveElement * > List_t
virtual void RemoveElement(REveElement *el)
Remove el from the list of children.
REveException Exception-type thrown by Eve classes.
Definition REveTypes.hxx:42
REveSceneList * GetScenes() const
void SceneSubscriberWaitingResponse(unsigned cinnId)
REveViewerList * GetViewers() const
REveSceneList(const REveSceneList &)=delete
void BeginAcceptingChanges()
Loop-wrapers over Scene children, element type checked on insertion.
void DestroyScenes()
Destroy all scenes and their contents.
std::vector< std::unique_ptr< REveClient > > fSubscribers
!
Definition REveScene.hxx:72
void AddCommand(const std::string &name, const std::string &icon, const REveElement *element, const std::string &action)
Definition REveScene.cxx:91
void AddSubscriber(std::unique_ptr< REveClient > &&sub)
Definition REveScene.cxx:70
std::vector< char > fOutputBinary
!
Definition REveScene.hxx:76
~REveScene() override
Destructor.
Definition REveScene.cxx:51
void SceneElementRemoved(ElementId_t id)
void StreamRepresentationChanges()
Prepare data for sending element changes.
void StreamJsonRecurse(REveElement *el, nlohmann::json &jobj)
std::vector< SceneCommand > fCommands
!
Definition REveScene.hxx:79
void StreamMotionChanges(nlohmann::json &arr)
Move every element whose only pending change is kCBTrans from the change list into arr,...
Int_t WriteCoreJson(nlohmann::json &cj, Int_t rnr_offset) override
Write core json.
Definition REveScene.cxx:60
std::vector< ElementId_t > fRemovedElements
!
Definition REveScene.hxx:70
void SceneElementChanged(REveElement *element)
void RemoveSubscriber(unsigned int)
Definition REveScene.cxx:81
static void AppendServerTime(std::string &msg)
Append "server_time" to the JSON message msg, a non-empty object or array: as its last key,...
Definition REveUtil.cxx:63
static void StampServerTime(std::string &msg)
Set the "server_time" that AppendServerTime() put at the end of msg to now.
Definition REveUtil.cxx:76
void SceneDestructing(REveScene *scene)
Callback done from a REveScene destructor allowing proper removal of the scene from affected viewers.
const Int_t n
Definition legend1.C:16
Namespace for ROOT features in testing.
Definition TROOT.h:100
R__EXTERN REveManager * gEve