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/RWebWindow.hxx>
19
20#include <cassert>
21
22#include <nlohmann/json.hpp>
23
24using namespace ROOT::Experimental;
25namespace REX = ROOT::Experimental;
26
27/** \class REveScene
28\ingroup REve
29Eve representation of TGLScene.
30The GLScene is owned by this class - it is created on construction
31time and deleted at destruction.
32
33Normally all objects are positioned directly in global scene-space.
34By setting the fHierarchical flag, positions of children get
35calculated by multiplying the transformation matrices of all parents.
36*/
37
38////////////////////////////////////////////////////////////////////////////////
39/// Constructor.
40
41REveScene::REveScene(const std::string& n, const std::string& t) :
42 REveElement(n, t)
43{
44 fScene = this;
45}
46
47////////////////////////////////////////////////////////////////////////////////
48/// Destructor.
49
57//------------------------------------------------------------------------------
58
59int REveScene::WriteCoreJson(nlohmann::json &j, Int_t rnr_offset)
60{
61 j["Mandatory"] = fMandatory;
62 j["IsOverlay"] = fIsOverlay;
63
64 return REveElement::WriteCoreJson(j, rnr_offset);
65}
66
67//------------------------------------------------------------------------------
68
69void REveScene::AddSubscriber(std::unique_ptr<REveClient> &&sub)
70{
71 assert(sub.get() != nullptr && fAcceptingChanges == kFALSE);
72
73 fSubscribers.emplace_back(std::move(sub));
74
75 // XXX Here should send out the package to the new subscriber,
76 // In principle can expect a new one in short time?
77 // Keep streamed data until next begin change, maybe.
78}
79
81{
82 auto pred = [&](std::unique_ptr<REveClient> &client) {
83 return client->fId == id;
84 };
85
86 fSubscribers.erase(std::remove_if(fSubscribers.begin(), fSubscribers.end(), pred), fSubscribers.end());
87}
88
89// Add Button in client gui with this command
90void REveScene::AddCommand(const std::string &name, const std::string &icon, const REveElement *element, const std::string &action)
91{
92 static const REveException eh("REveScene::AddCommand ");
93 if (element->GetElementId() && element->IsA())
94 {
95 fCommands.emplace_back(name, icon, element, action);
96 }
97 else
98 {
99 throw eh + "Element id and dictionary has to be defined";
100 }
101}
102
104{
105 if (fAcceptingChanges) return;
106
107 if (HasSubscribers()) {
109 /*
110 for (auto &&client : fSubscribers) {
111 REX::gEve->SceneSubscriberProcessingChanges(client->fId);
112 }
113 */
114 }
115}
116
118{
119 assert(fAcceptingChanges);
120
121 fChangedElements.push_back(element);
122}
123
125{
126 fRemovedElements.push_back(id);
127}
128
130{
131 if ( ! fAcceptingChanges) return;
132
134}
135
137{
138 fOutputJson.clear();
139 fOutputBinary.clear();
140
141 fElsWithBinaryData.clear();
143
144 nlohmann::json jarr = nlohmann::json::array();
145
146 nlohmann::json jhdr = {};
147 jhdr["content"] = "REveScene::StreamElements";
148 jhdr["fSceneId"] = fElementId;
149
150 if (!fCommands.empty()) {
151 jhdr["commands"] = nlohmann::json::array();
152 for (auto &&cmd : fCommands) {
153 nlohmann::json jcmd = {};
154 jcmd["name"] = cmd.fName;
155 jcmd["icon"] = cmd.fIcon;
156 jcmd["elementid"] = cmd.fElementId;
157 jcmd["elementclass"] = cmd.fElementClass;
158 jcmd["func"] = cmd.fAction; // SL: may be not needed on client side, can use name
159 jhdr["commands"].push_back(jcmd);
160 }
161 }
162
163 jarr.push_back(jhdr);
164
165 StreamJsonRecurse(this, jarr);
166 // for (auto &c : fChildren)
167 // {
168 // StreamJsonRecurse(c, jarr);
169 // }
170
172 Int_t off = 0;
173
174 for (auto &&e : fElsWithBinaryData)
175 {
176 auto rd_size = e->fRenderData->Write(&fOutputBinary[off], fOutputBinary.size() - off);
177 off += rd_size;
178 }
179 assert(off == fTotalBinarySize);
180
181 jarr.front()["fTotalBinarySize"] = fTotalBinarySize;
182
183 fOutputJson = jarr.dump();
184}
185
186void REveScene::StreamJsonRecurse(REveElement *el, nlohmann::json &jarr)
187{
188 nlohmann::json jobj = {};
189 Int_t rd_size = el->WriteCoreJson(jobj, fTotalBinarySize);
190 jarr.push_back(jobj);
191
192 // If this is another scene, do not stream additional details.
193 // It should be requested / subscribed to independently.
194
195 if (el->fScene == el && el != this)
196 {
197 return;
198 }
199
200 if (rd_size > 0)
201 {
202 assert (rd_size % 4 == 0);
203
204 fTotalBinarySize += rd_size;
205 fElsWithBinaryData.push_back(el);
206 }
207
208 for (auto &&c : el->fChildren)
209 {
210 // Stream only objects element el is a mother of.
211 //
212 // XXXX This is spooky side effect of multi-parenting.
213 //
214 // In particular screwed up for selection.
215 // Selection now streams element ids and implied selected ids
216 // and secondary-ids as part of core json.
217 //
218 // I wonder how this screws up REveProjectionManager (should
219 // we hold a map of already streamed ids?).
220 //
221 // Do uncles and aunts and figure out a clean way for backrefs.
222
223 if (c->GetMother() == el)
224 {
225 StreamJsonRecurse(c, jarr);
226 }
227 }
228}
229
230////////////////////////////////////////////////////////////////////////////////
231/// Move every element whose only pending change is kCBTransBBox from the change
232/// list into `arr`, for REveManager::SendMotionChanges(). The remaining
233/// elements are streamed as ordinary, acknowledged scene changes.
234
235void REveScene::StreamMotionChanges(nlohmann::json &arr)
236{
237 if (fChangedElements.empty())
238 return;
239
240 List_t keep;
241
242 for (auto &el : fChangedElements) {
243 if (el->GetChangeBits() != REveElement::kCBTransBBox) {
244 keep.push_back(el);
245 continue;
246 }
247
248 nlohmann::json jobj = {};
249 // clang-format off
250 jobj["fElementId"] = el->GetElementId();
251 jobj["fSceneId"] = GetElementId();
252 // clang-format on
253 el->WriteTransJson(jobj);
254 arr.push_back(jobj);
255
256 el->ClearStamps();
257 }
258
259 fChangedElements.swap(keep);
260}
261
262////////////////////////////////////////////////////////////////////////////////
263//
264/// Prepare data for sending element changes
265//
266////////////////////////////////////////////////////////////////////////////////
267
269{
270 fElsWithBinaryData.clear();
272
273 nlohmann::json jarr = nlohmann::json::array();
274
275 nlohmann::json jhdr = {};
276 jhdr["content"] = "ElementsRepresentaionChanges";
277 jhdr["fSceneId"] = fElementId;
278
279 jhdr["removedElements"] = nlohmann::json::array();
280 for (auto &re : fRemovedElements)
281 jhdr["removedElements"].push_back(re);
282
283 jhdr["numRepresentationChanged"] = fChangedElements.size();
284
285 // jarr.push_back(jhdr);
286
287 for (auto &el: fChangedElements)
288 {
289 UChar_t bits = el->GetChangeBits();
290
291 nlohmann::json jobj = {};
292 jobj["fElementId"] = el->GetElementId();
293 jobj["changeBit"] = bits;
294
295 if (bits & kCBElementAdded || bits & kCBObjProps)
296 {
297 if (gDebug > 0 && bits & kCBElementAdded)
298 {
299 Info("REveScene::StreamRepresentationChanges", "new element change %s %d\n",
300 el->GetCName(), bits);
301 }
302
303 Int_t rd_size = el->WriteCoreJson(jobj, fTotalBinarySize);
304 if (rd_size) {
305 assert (rd_size % 4 == 0);
306 fTotalBinarySize += rd_size;
307 fElsWithBinaryData.push_back(el);
308 }
309 }
310 else
311 {
312 if (bits & kCBVisibility)
313 {
314 jobj["fRnrSelf"] = el->GetRnrSelf();
315 jobj["fRnrChildren"] = el->GetRnrChildren();
316 }
317
318 if (bits & kCBColorSelection)
319 {
320 el->WriteCoreJson(jobj, -1);
321 }
322
323 if (bits & kCBTransBBox)
324 {
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
353 if (gDebug > 0)
354 Info("REveScene::StreamRepresentationChanges", "class: %s changes %s ...", GetCName(), msg.dump(1).c_str() );
355}
356
358{
359 for (auto && client : fSubscribers) {
360 if (!fOutputJson.empty()) {
361 if (gDebug > 0)
362 printf(" sending json, len = %d --> to conn_id = %d\n", (int) fOutputJson.size(), client->fId);
363 client->fWebWindow->Send(client->fId, fOutputJson);
364 }
365 if (fTotalBinarySize) {
366 if (gDebug > 0)
367 printf(" sending binary, len = %d --> to conn_id = %d\n", fTotalBinarySize, client->fId);
368 client->fWebWindow->SendBinary(client->fId, &fOutputBinary[0], fTotalBinarySize);
369 }
371 }
372 fOutputJson.clear();
373 fOutputBinary.clear();
375}
376
378{
379 if (gDebug > 0)
380 ::Info("REveScene::IsChanged","%s (changed_or_added=%d, removed=%d)", GetCName(),
381 (int) fChangedElements.size(), (int) fRemovedElements.size());
382
383 return ! (fChangedElements.empty() && fRemovedElements.empty());
384}
385
386
387/** \class REveSceneList
388\ingroup REve
389List of Scenes providing common operations on REveScene collections.
390*/
391
392////////////////////////////////////////////////////////////////////////////////
393/// Constructor.
394
395REveSceneList::REveSceneList(const std::string& n, const std::string& t) :
396 REveElement(n, t)
397{
398 SetChildClass(TClass::GetClass<REveScene>());
399}
400
401////////////////////////////////////////////////////////////////////////////////
402/// Destroy all scenes and their contents.
403/// The object with non-zero deny-destroy will still survive.
404
406{
407 auto i = fChildren.begin();
408 while (i != fChildren.end())
409 {
410 REveScene* s = (REveScene*) *(i++);
411 s->DestroyElements();
412 s->DestroyOrWarn();
413 }
414}
415
416////////////////////////////////////////////////////////////////////////////////
417/// Loop-wrapers over Scene children, element type checked on insertion.
418
420{
421 for (auto &c: fChildren)
422 {
423 static_cast<REveScene*>(c)->BeginAcceptingChanges();
424 }
425}
426
428{
429 for (auto &c: fChildren)
430 {
431 static_cast<REveScene*>(c)->EndAcceptingChanges();
432 }
433}
434
436{
437 for (auto &el : fChildren)
438 {
439 if (((REveScene*) el)->IsChanged())
440 return true;
441 }
442 return false;
443}
#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:90
void AddSubscriber(std::unique_ptr< REveClient > &&sub)
Definition REveScene.cxx:69
std::vector< char > fOutputBinary
!
Definition REveScene.hxx:76
~REveScene() override
Destructor.
Definition REveScene.cxx:50
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 kCBTransBBox from the change list into arr,...
Int_t WriteCoreJson(nlohmann::json &cj, Int_t rnr_offset) override
Write core json.
Definition REveScene.cxx:59
std::vector< ElementId_t > fRemovedElements
!
Definition REveScene.hxx:70
void SceneElementChanged(REveElement *element)
void RemoveSubscriber(unsigned int)
Definition REveScene.cxx:80
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