Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
REveManager.cxx
Go to the documentation of this file.
1 // @(#)root/eve7:$Id$
2 // Authors: Matevz Tadel & Alja Mrak-Tadel: 2006, 2007
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/REveManager.hxx>
13 
14 #include <ROOT/REveUtil.hxx>
15 #include <ROOT/REveSelection.hxx>
16 #include <ROOT/REveViewer.hxx>
17 #include <ROOT/REveScene.hxx>
18 #include <ROOT/REveClient.hxx>
19 #include <ROOT/REveGeomViewer.hxx>
20 #include <ROOT/RWebWindow.hxx>
21 
22 #include "TGeoManager.h"
23 #include "TObjString.h"
24 #include "TROOT.h"
25 #include "TFile.h"
26 #include "TMap.h"
27 #include "TExMap.h"
28 #include "TMacro.h"
29 #include "TFolder.h"
30 #include "TSystem.h"
31 #include "TRint.h"
32 #include "TEnv.h"
33 #include "TColor.h"
34 #include "TPluginManager.h"
35 #include "TPRegexp.h"
36 #include "TClass.h"
37 #include "THttpServer.h"
38 
39 #include "Riostream.h"
40 
41 #include "json.hpp"
42 #include <sstream>
43 #include <iostream>
44 
45 using namespace ROOT::Experimental;
46 namespace REX = ROOT::Experimental;
47 
48 REveManager* REX::gEve = 0;
49 
50 
51 
52 
53 /** \class REveManager
54 \ingroup REve
55 Central application manager for Eve.
56 Manages elements, GUI, GL scenes and GL viewers.
57 */
58 
59 ////////////////////////////////////////////////////////////////////////////////
60 
61 REveManager::REveManager() : // (Bool_t map_window, Option_t* opt) :
62  fExcHandler (nullptr),
63  fVizDB (nullptr),
64  fVizDBReplace(kTRUE),
65  fVizDBUpdate(kTRUE),
66  fGeometries (nullptr),
67  fGeometryAliases (nullptr),
68 
69  fMacroFolder (nullptr),
70 
71  fRedrawDisabled (0),
72  fResetCameras (kFALSE),
73  fDropLogicals (kFALSE),
74  fKeepEmptyCont (kFALSE),
75  fTimerActive (kFALSE),
76  fRedrawTimer ()
77 {
78  // Constructor.
79 
80  static const REveException eh("REveManager::REveManager ");
81 
82  if (REX::gEve)
83  throw eh + "There can be only one REve!";
84 
85  REX::gEve = this;
86 
87  fExcHandler = new RExceptionHandler;
88 
89  fGeometries = new TMap; fGeometries->SetOwnerKeyValue();
90  fGeometryAliases = new TMap; fGeometryAliases->SetOwnerKeyValue();
91  fVizDB = new TMap; fVizDB->SetOwnerKeyValue();
92 
93  fElementIdMap[0] = nullptr; // do not increase count for null element.
94 
95  fRedrawTimer.Connect("Timeout()", "ROOT::Experimental::REveManager", this, "DoRedraw3D()");
96  fMacroFolder = new TFolder("EVE", "Visualization macros");
97  gROOT->GetListOfBrowsables()->Add(fMacroFolder);
98 
99  fWorld = new REveScene("EveWorld", "Top-level Eve Scene");
100  fWorld->IncDenyDestroy();
101  AssignElementId(fWorld);
102 
103  fSelectionList = new REveElement("Selection List");
104  fSelectionList->SetChildClass(TClass::GetClass<REveSelection>());
105  fSelectionList->IncDenyDestroy();
106  fWorld->AddElement(fSelectionList);
107  fSelection = new REveSelection("Global Selection", "", kRed, kViolet);
108  fSelection->IncDenyDestroy();
109  fSelectionList->AddElement(fSelection);
110  fHighlight = new REveSelection("Global Highlight", "", kGreen, kCyan);
111  fHighlight->SetHighlightMode();
112  fHighlight->IncDenyDestroy();
113  fSelectionList->AddElement(fHighlight);
114 
115  fViewers = new REveViewerList("Viewers");
116  fViewers->IncDenyDestroy();
117  fWorld->AddElement(fViewers);
118 
119  fScenes = new REveSceneList ("Scenes");
120  fScenes->IncDenyDestroy();
121  fWorld->AddElement(fScenes);
122 
123  fGlobalScene = new REveScene("Geometry scene");
124  fGlobalScene->IncDenyDestroy();
125  fScenes->AddElement(fGlobalScene);
126 
127  fEventScene = new REveScene("Event scene");
128  fEventScene->IncDenyDestroy();
129  fScenes->AddElement(fEventScene);
130 
131  {
132  REveViewer *v = SpawnNewViewer("Default Viewer");
133  v->AddScene(fGlobalScene);
134  v->AddScene(fEventScene);
135  }
136 
137  // !!! AMT increase threshold to enable color pick on client
138  TColor::SetColorThreshold(0.1);
139 
140  fWebWindow = RWebWindow::Create();
141  fWebWindow->SetDefaultPage("file:rootui5sys/eve7/index.html");
142 
143  // this is call-back, invoked when message received via websocket
144  fWebWindow->SetCallBacks([this](unsigned connid) { WindowConnect(connid); },
145  [this](unsigned connid, const std::string &arg) { WindowData(connid, arg); },
146  [this](unsigned connid) { WindowDisconnect(connid); });
147  fWebWindow->SetGeometry(900, 700); // configure predefined window geometry
148  fWebWindow->SetConnLimit(100); // maximal number of connections
149  fWebWindow->SetMaxQueueLength(30); // number of allowed entries in the window queue
150 }
151 
152 ////////////////////////////////////////////////////////////////////////////////
153 /// Destructor.
154 
155 REveManager::~REveManager()
156 {
157  // Stop timer and deny further redraw requests.
158  fRedrawTimer.Stop();
159  fTimerActive = kTRUE;
160 
161  fGlobalScene->DecDenyDestroy();
162  fEventScene->DecDenyDestroy();
163  fScenes->DestroyScenes();
164  fScenes->DecDenyDestroy();
165  // Not needed - no more top-items: fScenes->Destroy();
166  fScenes = nullptr;
167 
168  fViewers->DestroyElements();
169  fViewers->DecDenyDestroy();
170  // Not needed - no more top-items: fViewers->Destroy();
171  fViewers = nullptr;
172 
173  // fWindowManager->DestroyWindows();
174  // fWindowManager->DecDenyDestroy();
175  // fWindowManager->Destroy();
176  // fWindowManager = 0;
177 
178  fHighlight->DecDenyDestroy();
179  fSelection->DecDenyDestroy();
180 
181  gROOT->GetListOfBrowsables()->Remove(fMacroFolder);
182  delete fMacroFolder;
183 
184  delete fGeometryAliases;
185  delete fGeometries;
186  delete fVizDB;
187  delete fExcHandler;
188 }
189 
190 ////////////////////////////////////////////////////////////////////////////////
191 /// Create a new GL viewer.
192 
193 REveViewer* REveManager::SpawnNewViewer(const char* name, const char* title)
194 {
195  REveViewer* v = new REveViewer(name, title);
196  fViewers->AddElement(v);
197  return v;
198 }
199 
200 ////////////////////////////////////////////////////////////////////////////////
201 /// Create a new scene.
202 
203 REveScene* REveManager::SpawnNewScene(const char* name, const char* title)
204 {
205  REveScene* s = new REveScene(name, title);
206  AddElement(s, fScenes);
207  return s;
208 }
209 
210 ////////////////////////////////////////////////////////////////////////////////
211 /// Find macro in fMacroFolder by name.
212 
213 TMacro* REveManager::GetMacro(const char* name) const
214 {
215  return dynamic_cast<TMacro*>(fMacroFolder->FindObject(name));
216 }
217 
218 ////////////////////////////////////////////////////////////////////////////////
219 /// Register a request for 3D redraw.
220 
221 void REveManager::RegisterRedraw3D()
222 {
223  fRedrawTimer.Start(0, kTRUE);
224  fTimerActive = kTRUE;
225 }
226 
227 ////////////////////////////////////////////////////////////////////////////////
228 /// Perform 3D redraw of scenes and viewers whose contents has
229 /// changed.
230 
231 void REveManager::DoRedraw3D()
232 {
233  static const REveException eh("REveManager::DoRedraw3D ");
234  nlohmann::json jobj = {};
235 
236  jobj["content"] = "BeginChanges";
237  fWebWindow->Send(0, jobj.dump());
238 
239  // Process changes in scenes.
240  fWorld ->ProcessChanges();
241  fScenes->ProcessSceneChanges();
242 
243  jobj["content"] = "EndChanges";
244  fWebWindow->Send(0, jobj.dump());
245 
246  fResetCameras = kFALSE;
247  fDropLogicals = kFALSE;
248 
249  fTimerActive = kFALSE;
250 }
251 
252 ////////////////////////////////////////////////////////////////////////////////
253 /// Perform 3D redraw of all scenes and viewers.
254 
255 void REveManager::FullRedraw3D(Bool_t /*resetCameras*/, Bool_t /*dropLogicals*/)
256 {
257  // XXXX fScenes ->RepaintAllScenes (dropLogicals);
258  // XXXX fViewers->RepaintAllViewers(resetCameras, dropLogicals);
259 }
260 
261 ////////////////////////////////////////////////////////////////////////////////
262 /// Clear all selection objects. Can make things easier for EVE when going to
263 /// the next event. Still, destruction os selected object should still work
264 /// correctly as long as it is executed within a change cycle.
265 
266 void REveManager::ClearAllSelections()
267 {
268  for (auto el : fSelectionList->fChildren)
269  {
270  dynamic_cast<REveSelection*>(el)->ClearSelection();
271  }
272 }
273 
274 ////////////////////////////////////////////////////////////////////////////////
275 /// Add an element. If parent is not specified it is added into
276 /// current event (which is created if does not exist).
277 
278 void REveManager::AddElement(REveElement *element, REveElement *parent)
279 {
280  if (parent == nullptr) {
281  // XXXX
282  }
283 
284  parent->AddElement(element);
285 }
286 
287 ////////////////////////////////////////////////////////////////////////////////
288 /// Add a global element, i.e. one that does not change on each
289 /// event, like geometry or projection manager.
290 /// If parent is not specified it is added to a global scene.
291 
292 void REveManager::AddGlobalElement(REveElement* element, REveElement* parent)
293 {
294  if (!parent)
295  parent = fGlobalScene;
296 
297  parent->AddElement(element);
298 }
299 
300 ////////////////////////////////////////////////////////////////////////////////
301 /// Remove element from parent.
302 
303 void REveManager::RemoveElement(REveElement* element,
304  REveElement* parent)
305 {
306  parent->RemoveElement(element);
307 }
308 
309 ////////////////////////////////////////////////////////////////////////////////
310 /// Lookup ElementId in element map and return corresponding REveElement*.
311 /// Returns nullptr if the id is not found
312 
313 REveElement* REveManager::FindElementById(ElementId_t id) const
314 {
315  static const REveException eh("REveManager::FindElementById ");
316 
317  auto it = fElementIdMap.find(id);
318  return (it != fElementIdMap.end()) ? it->second : nullptr;
319 }
320 
321 ////////////////////////////////////////////////////////////////////////////////
322 /// Assign a unique ElementId to given element.
323 
324 void REveManager::AssignElementId(REveElement* element)
325 {
326  static const REveException eh("REveManager::AssignElementId ");
327 
328  if (fNumElementIds == fMaxElementIds)
329  throw eh + "ElementId map is full.";
330 
331 next_free_id:
332  while (fElementIdMap.find(++fLastElementId) != fElementIdMap.end());
333  if (fLastElementId == 0) goto next_free_id;
334  // MT - alternatively, we could spawn a thread to find next thousand or so ids and
335  // put them in a vector of ranges. Or collect them when they are freed.
336  // Don't think this won't happen ... online event display can run for months
337  // and easily produce 100000 objects per minute -- about a month to use up all id space!
338 
339  element->fElementId = fLastElementId;
340  fElementIdMap.insert(std::make_pair(fLastElementId, element));
341  ++fNumElementIds;
342 }
343 
344 ////////////////////////////////////////////////////////////////////////////////
345 /// Called from REveElement prior to its destruction so the
346 /// framework components (like object editor) can unreference it.
347 
348 void REveManager::PreDeleteElement(REveElement* el)
349 {
350  if (el->fImpliedSelected > 0)
351  {
352  for (auto slc : fSelectionList->fChildren)
353  {
354  REveSelection *sel = dynamic_cast<REveSelection*>(slc);
355  sel->RemoveImpliedSelectedReferencesTo(el);
356  }
357 
358  if (el->fImpliedSelected != 0)
359  Error("REveManager::PreDeleteElement", "ImpliedSelected not zero (%d) after cleanup of selections.", el->fImpliedSelected);
360  }
361  // Primary selection deregistration is handled through Niece removal from Aunts.
362 
363  if (el->fElementId != 0)
364  {
365  auto it = fElementIdMap.find(el->fElementId);
366  if (it != fElementIdMap.end())
367  {
368  if (it->second == el)
369  {
370  fElementIdMap.erase(it);
371  --fNumElementIds;
372  }
373  else Error("PreDeleteElement", "element ptr in ElementIdMap does not match the argument element.");
374  }
375  else Error("PreDeleteElement", "element id %u was not registered in ElementIdMap.", el->fElementId);
376  }
377  else Error("PreDeleteElement", "element with 0 ElementId passed in.");
378 }
379 
380 ////////////////////////////////////////////////////////////////////////////////
381 /// Insert a new visualization-parameter database entry. Returns
382 /// true if the element is inserted successfully.
383 /// If entry with the same key already exists the behaviour depends on the
384 /// 'replace' flag:
385 /// - true - The old model is deleted and new one is inserted (default).
386 /// Clients of the old model are transferred to the new one and
387 /// if 'update' flag is true (default), the new model's parameters
388 /// are assigned to all clients.
389 /// - false - The old model is kept, false is returned.
390 ///
391 /// If insert is successful, the ownership of the model-element is
392 /// transferred to the manager.
393 
394 Bool_t REveManager::InsertVizDBEntry(const TString& tag, REveElement* model,
395  Bool_t replace, Bool_t update)
396 {
397  TPair* pair = (TPair*) fVizDB->FindObject(tag);
398  if (pair)
399  {
400  if (replace)
401  {
402  model->IncDenyDestroy();
403  model->SetRnrChildren(kFALSE);
404 
405  REveElement* old_model = dynamic_cast<REveElement*>(pair->Value());
406  if (old_model)
407  {
408  while (old_model->HasChildren())
409  {
410  REveElement *el = old_model->FirstChild();
411  el->SetVizModel(model);
412  if (update)
413  {
414  el->CopyVizParams(model);
415  el->PropagateVizParamsToProjecteds();
416  }
417  }
418  old_model->DecDenyDestroy();
419  }
420  pair->SetValue(dynamic_cast<TObject*>(model));
421  return kTRUE;
422  }
423  else
424  {
425  return kFALSE;
426  }
427  }
428  else
429  {
430  model->IncDenyDestroy();
431  model->SetRnrChildren(kFALSE);
432  fVizDB->Add(new TObjString(tag), dynamic_cast<TObject*>(model));
433  return kTRUE;
434  }
435 }
436 
437 ////////////////////////////////////////////////////////////////////////////////
438 /// Insert a new visualization-parameter database entry with the default
439 /// parameters for replace and update, as specified by members
440 /// fVizDBReplace(default=kTRUE) and fVizDBUpdate(default=kTRUE).
441 /// See docs of the above function.
442 
443 Bool_t REveManager::InsertVizDBEntry(const TString& tag, REveElement* model)
444 {
445  return InsertVizDBEntry(tag, model, fVizDBReplace, fVizDBUpdate);
446 }
447 
448 ////////////////////////////////////////////////////////////////////////////////
449 /// Find a visualization-parameter database entry corresponding to tag.
450 /// If the entry is not found 0 is returned.
451 
452 REveElement* REveManager::FindVizDBEntry(const TString& tag)
453 {
454  return dynamic_cast<REveElement*>(fVizDB->GetValue(tag));
455 }
456 
457 ////////////////////////////////////////////////////////////////////////////////
458 /// Load visualization-parameter database from file filename. The
459 /// replace, update arguments replace the values of fVizDBReplace
460 /// and fVizDBUpdate members for the duration of the macro
461 /// execution.
462 
463 void REveManager::LoadVizDB(const TString& filename, Bool_t replace, Bool_t update)
464 {
465  Bool_t ex_replace = fVizDBReplace;
466  Bool_t ex_update = fVizDBUpdate;
467  fVizDBReplace = replace;
468  fVizDBUpdate = update;
469 
470  LoadVizDB(filename);
471 
472  fVizDBReplace = ex_replace;
473  fVizDBUpdate = ex_update;
474 }
475 
476 ////////////////////////////////////////////////////////////////////////////////
477 /// Load visualization-parameter database from file filename.
478 /// State of data-members fVizDBReplace and fVizDBUpdate determine
479 /// how the registered entries are handled.
480 
481 void REveManager::LoadVizDB(const TString& filename)
482 {
483  REveUtil::Macro(filename);
484  Redraw3D();
485 }
486 
487 ////////////////////////////////////////////////////////////////////////////////
488 /// Save visualization-parameter database to file filename.
489 
490 void REveManager::SaveVizDB(const TString& filename)
491 {
492  TPMERegexp re("(.+)\\.\\w+");
493  if (re.Match(filename) != 2) {
494  Error("SaveVizDB", "filename does not match required format '(.+)\\.\\w+'.");
495  return;
496  }
497 
498  TString exp_filename(filename);
499  gSystem->ExpandPathName(exp_filename);
500 
501  std::ofstream out(exp_filename, std::ios::out | std::ios::trunc);
502  out << "void " << re[1] << "()\n";
503  out << "{\n";
504  out << " REveManager::Create();\n";
505 
506  ClearROOTClassSaved();
507 
508  Int_t var_id = 0;
509  TString var_name;
510  TIter next(fVizDB);
511  TObjString *key;
512  while ((key = (TObjString*)next()))
513  {
514  REveElement* mdl = dynamic_cast<REveElement*>(fVizDB->GetValue(key));
515  if (mdl)
516  {
517  var_name.Form("x%03d", var_id++);
518  mdl->SaveVizParams(out, key->String(), var_name);
519  }
520  else
521  {
522  Warning("SaveVizDB", "Saving failed for key '%s'.", key->String().Data());
523  }
524  }
525 
526  out << "}\n";
527  out.close();
528 }
529 
530 ////////////////////////////////////////////////////////////////////////////////
531 /// Get geometry with given filename.
532 /// This is cached internally so the second time this function is
533 /// called with the same argument the same geo-manager is returned.
534 /// gGeoManager is set to the return value.
535 
536 TGeoManager* REveManager::GetGeometry(const TString& filename)
537 {
538  static const REveException eh("REveManager::GetGeometry ");
539 
540  TString exp_filename = filename;
541  gSystem->ExpandPathName(exp_filename);
542  printf("REveManager::GetGeometry loading: '%s' -> '%s'.\n",
543  filename.Data(), exp_filename.Data());
544 
545  gGeoManager = (TGeoManager*) fGeometries->GetValue(filename);
546  if (gGeoManager)
547  {
548  gGeoIdentity = (TGeoIdentity*) gGeoManager->GetListOfMatrices()->At(0);
549  }
550  else
551  {
552  Bool_t locked = TGeoManager::IsLocked();
553  if (locked) {
554  Warning("REveManager::GetGeometry", "TGeoManager is locked ... unlocking it.");
555  TGeoManager::UnlockGeometry();
556  }
557  if (TGeoManager::Import(filename) == 0) {
558  throw eh + "TGeoManager::Import() failed for '" + exp_filename + "'.";
559  }
560  if (locked) {
561  TGeoManager::LockGeometry();
562  }
563 
564  gGeoManager->GetTopVolume()->VisibleDaughters(1);
565 
566  // Import colors exported by Gled, if they exist.
567  {
568  TFile f(exp_filename, "READ");
569  TObjArray* collist = (TObjArray*) f.Get("ColorList");
570  f.Close();
571  if (collist) {
572  TIter next(gGeoManager->GetListOfVolumes());
573  TGeoVolume* vol;
574  while ((vol = (TGeoVolume*) next()) != nullptr)
575  {
576  Int_t oldID = vol->GetLineColor();
577  TColor* col = (TColor*)collist->At(oldID);
578  Float_t r, g, b;
579  col->GetRGB(r, g, b);
580  Int_t newID = TColor::GetColor(r,g,b);
581  vol->SetLineColor(newID);
582  }
583  }
584  }
585 
586  fGeometries->Add(new TObjString(filename), gGeoManager);
587  }
588  return gGeoManager;
589 }
590 
591 ////////////////////////////////////////////////////////////////////////////////
592 /// Get geometry with given alias.
593 /// The alias must be registered via RegisterGeometryAlias().
594 
595 TGeoManager* REveManager::GetGeometryByAlias(const TString& alias)
596 {
597  static const REveException eh("REveManager::GetGeometry ");
598 
599  TObjString* full_name = (TObjString*) fGeometryAliases->GetValue(alias);
600  if (!full_name)
601  throw eh + "geometry alias '" + alias + "' not registered.";
602  return GetGeometry(full_name->String());
603 }
604 
605 ////////////////////////////////////////////////////////////////////////////////
606 /// Get the default geometry.
607 /// It should be registered via RegisterGeometryName("Default", <URL>).
608 
609 TGeoManager* REveManager::GetDefaultGeometry()
610 {
611  return GetGeometryByAlias("Default");
612 }
613 
614 ////////////////////////////////////////////////////////////////////////////////
615 /// Register 'name' as an alias for geometry file 'filename'.
616 /// The old aliases are silently overwritten.
617 /// After that the geometry can be retrieved also by calling:
618 /// REX::gEve->GetGeometryByName(name);
619 
620 void REveManager::RegisterGeometryAlias(const TString& alias, const TString& filename)
621 {
622  fGeometryAliases->Add(new TObjString(alias), new TObjString(filename));
623 }
624 
625 ////////////////////////////////////////////////////////////////////////////////
626 /// Work-around uber ugly hack used in SavePrimitive and co.
627 
628 void REveManager::ClearROOTClassSaved()
629 {
630  TIter nextcl(gROOT->GetListOfClasses());
631  TClass *cls;
632  while((cls = (TClass *)nextcl()))
633  {
634  cls->ResetBit(TClass::kClassSaved);
635  }
636 }
637 
638 ////////////////////////////////////////////////////////////////////////////////
639 /// Register new directory to THttpServer
640 // For example: AddLocation("mydir/", "/test/EveWebApp/ui5");
641 //
642 void REveManager::AddLocation(const std::string& locationName, const std::string& path)
643 {
644  fWebWindow->GetServer()->AddLocation(locationName.c_str(), path.c_str());
645 }
646 
647 ////////////////////////////////////////////////////////////////////////////////
648 /// Set content of default window HTML page
649 // Got example: SetDefaultHtmlPage("file:currentdir/test.html")
650 //
651 void REveManager::SetDefaultHtmlPage(const std::string& path)
652 {
653  fWebWindow->SetDefaultPage(path.c_str());
654 }
655 
656 
657 ////////////////////////////////////////////////////////////////////////////////
658 /// Set client version, used as prefix in scripts URL
659 /// When changed, web browser will reload all related JS files while full URL will be different
660 /// Default is empty value - no extra string in URL
661 /// Version should be string like "1.2" or "ver1.subv2" and not contain any special symbols
662 void REveManager::SetClientVersion(const std::string& version)
663 {
664  fWebWindow->SetClientVersion(version);
665 }
666 
667 ////////////////////////////////////////////////////////////////////////////////
668 /// If global REveManager* REX::gEve is not set initialize it.
669 /// Returns REX::gEve.
670 
671 REveManager* REveManager::Create()
672 {
673  static const REveException eh("REveManager::Create ");
674 
675  if (!REX::gEve)
676  {
677  // XXXX Initialize some server stuff ???
678 
679  REX::gEve = new REveManager();
680  }
681  return REX::gEve;
682 }
683 
684 ////////////////////////////////////////////////////////////////////////////////
685 /// Properly terminate global REveManager.
686 
687 void REveManager::Terminate()
688 {
689  if (!REX::gEve) return;
690 
691  delete REX::gEve;
692  REX::gEve = nullptr;
693 }
694 
695 /** \class REveManager::RExceptionHandler
696 \ingroup REve
697 Exception handler for Eve exceptions.
698 */
699 
700 
701 ////////////////////////////////////////////////////////////////////////////////
702 /// Handle exceptions deriving from REveException.
703 
704 TStdExceptionHandler::EStatus
705 REveManager::RExceptionHandler::Handle(std::exception &exc)
706 {
707  REveException *ex = dynamic_cast<REveException *>(&exc);
708  if (ex) {
709  Info("Handle", "Exception %s", ex->what());
710  // REX::gEve->SetStatusLine(ex->Data());
711  gSystem->Beep();
712  return kSEHandled;
713  }
714  return kSEProceed;
715 }
716 
717 ////////////////////////////////////////////////////////////////////////////////
718 /// Process new connection from web window
719 
720 void REveManager::WindowConnect(unsigned connid)
721 {
722  fConnList.emplace_back(connid);
723  printf("connection established %u\n", connid);
724 
725  // This prepares core and render data buffers.
726  printf("\nEVEMNG ............. streaming the world scene.\n");
727 
728  fWorld->AddSubscriber(std::make_unique<REveClient>(connid, fWebWindow));
729  fWorld->StreamElements();
730 
731  printf(" sending json, len = %d\n", (int) fWorld->fOutputJson.size());
732  Send(connid, fWorld->fOutputJson);
733  printf(" for now assume world-scene has no render data, binary-size=%d\n", fWorld->fTotalBinarySize);
734  assert(fWorld->fTotalBinarySize == 0);
735 
736  for (auto &c: fScenes->RefChildren())
737  {
738  REveScene* scene = dynamic_cast<REveScene *>(c);
739 
740  scene->AddSubscriber(std::make_unique<REveClient>(connid, fWebWindow));
741  printf("\nEVEMNG ............. streaming scene %s [%s]\n",
742  scene->GetCTitle(), scene->GetCName());
743 
744  // This prepares core and render data buffers.
745  scene->StreamElements();
746 
747  printf(" sending json, len = %d\n", (int) scene->fOutputJson.size());
748  Send(connid, scene->fOutputJson);
749 
750  if (scene->fTotalBinarySize > 0)
751  {
752  printf(" sending binary, len = %d\n", scene->fTotalBinarySize);
753  SendBinary(connid, &scene->fOutputBinary[0], scene->fTotalBinarySize);
754  }
755  else
756  {
757  printf(" NOT sending binary, len = %d\n", scene->fTotalBinarySize);
758  }
759  }
760 }
761 
762 ////////////////////////////////////////////////////////////////////////////////
763 /// Process disconnect of web window
764 
765 void REveManager::WindowDisconnect(unsigned connid)
766 {
767  auto conn = fConnList.end();
768  for (auto i = fConnList.begin(); i != fConnList.end(); ++i)
769  {
770  if (i->fId == connid)
771  {
772  conn = i;
773  break;
774  }
775  }
776  // this should not happen, just check
777  if (conn == fConnList.end()) {
778  printf("error, connection not found!");
779  } else {
780  printf("connection closed %u\n", connid);
781  fConnList.erase(conn);
782  for (auto &c: fScenes->RefChildren())
783  {
784  REveScene* scene = dynamic_cast<REveScene *>(c);
785  scene->RemoveSubscriber(connid);
786  }
787  fWorld->RemoveSubscriber(connid);
788 
789  }
790 
791 }
792 
793 ////////////////////////////////////////////////////////////////////////////////
794 /// Process data from web window
795 
796 void REveManager::WindowData(unsigned connid, const std::string &arg)
797 {
798  static const REveException eh("REveManager::WindowData ");
799 
800  // find connection object
801  auto conn = fConnList.end();
802  for (auto i = fConnList.begin(); i != fConnList.end(); ++i)
803  {
804  if (i->fId == connid)
805  {
806  conn = i;
807  break;
808  }
809  }
810  // this should not happen, just check
811  if (conn == fConnList.end()) {
812  printf("error, connection not found!");
813  return;
814  }
815 
816  fWorld->BeginAcceptingChanges();
817  fScenes->AcceptChanges(true);
818 
819  // MIR
820  nlohmann::json cj = nlohmann::json::parse(arg);
821  if (gDebug > 0)
822  ::Info("REveManager::WindowData", "MIR test %s", cj.dump().c_str());
823  std::string mir = cj["mir"];
824  std::string ctype = cj["class"];
825  int id = cj["fElementId"];
826 
827  auto el = FindElementById(id);
828  std::stringstream cmd;
829  cmd << "((" << ctype << "*)" << std::hex << std::showbase << (size_t)el << ")->" << mir << ";";
830  if (gDebug > 0)
831  ::Info("REveManager::WindowData", "MIR cmd %s", cmd.str().c_str());
832  gROOT->ProcessLine(cmd.str().c_str());
833 
834  fScenes->AcceptChanges(false);
835  fWorld->EndAcceptingChanges();
836 
837  Redraw3D();
838 
839  /*
840  nlohmann::json resp;
841  resp["function"] = "replaceElement";
842  //el->SetCoreJson(resp);
843  for (auto &conn : fConnList)
844  fWebWindow->Send(conn.fId, resp.dump());
845  */
846 }
847 
848 void REveManager::Send(unsigned connid, const std::string &data)
849 {
850  fWebWindow->Send(connid, data);
851 }
852 
853 
854 void REveManager::SendBinary(unsigned connid, const void *data, std::size_t len)
855 {
856  fWebWindow->SendBinary(connid, data, len);
857 }
858 
859 //------------------------------------------------------------------------------
860 
861 void REveManager::DestroyElementsOf(REveElement::List_t& els)
862 {
863  // XXXXX - not called, what's with end accepting changes?
864 
865  fWorld->EndAcceptingChanges();
866  fScenes->AcceptChanges(false);
867 
868  nlohmann::json jarr = nlohmann::json::array();
869 
870  nlohmann::json jhdr = {};
871  jhdr["content"] = "REveManager::DestroyElementsOf";
872 
873  nlohmann::json jels = nlohmann::json::array();
874 
875  for (auto &ep : els) {
876  jels.push_back(ep->GetElementId());
877 
878  ep->DestroyElements();
879  }
880 
881  jhdr["element_ids"] = jels;
882 
883  jarr.push_back(jhdr);
884 
885  std::string msg = jarr.dump();
886 
887  // XXXX Do we have broadcast?
888 
889  for (auto &conn : fConnList) {
890  fWebWindow->Send(conn.fId, msg);
891  }
892 }
893 
894 void REveManager::BroadcastElementsOf(REveElement::List_t &els)
895 {
896  // XXXXX - not called, what's with begin accepting changes?
897 
898  for (auto &ep : els)
899  {
900  REveScene* scene = dynamic_cast<REveScene*>(ep);
901  assert (scene != nullptr);
902 
903  printf("\nEVEMNG ............. streaming scene %s [%s]\n",
904  scene->GetCTitle(), scene->GetCName());
905 
906  // This prepares core and render data buffers.
907  scene->StreamElements();
908 
909  for (auto &conn : fConnList) {
910  printf(" sending json, len = %d --> to conn_id = %d\n", (int)scene->fOutputJson.size(), conn.fId);
911  fWebWindow->Send(conn.fId, scene->fOutputJson);
912  printf(" sending binary, len = %d --> to conn_id = %d\n", scene->fTotalBinarySize, conn.fId);
913  fWebWindow->SendBinary(conn.fId, &scene->fOutputBinary[0], scene->fTotalBinarySize);
914  }
915  }
916 
917  // AMT: These calls may not be necessary
918  fScenes->AcceptChanges(true);
919  fWorld->BeginAcceptingChanges();
920 }
921 
922 //////////////////////////////////////////////////////////////////
923 /// Show eve manager in specified browser.
924 
925 /// If rootrc variable WebEve.DisableShow is set, HTTP server will be
926 /// started and access URL printed on stdout.
927 
928 void REveManager::Show(const RWebDisplayArgs &args)
929 {
930  if (gEnv->GetValue("WebEve.DisableShow", 0) != 0) {
931  std::string url = fWebWindow->GetUrl(true);
932  printf("EVE URL %s\n", url.c_str());
933  } else {
934  fWebWindow->Show(args);
935  }
936 }
937 
938 //////////////////////////////////////////////////////////////////
939 /// Show current geometry in web browser
940 
941 std::shared_ptr<REveGeomViewer> REveManager::ShowGeometry(const RWebDisplayArgs &args)
942 {
943  if (!gGeoManager) {
944  Error("ShowGeometry", "No geometry is loaded");
945  return nullptr;
946  }
947 
948  auto viewer = std::make_shared<REveGeomViewer>(gGeoManager);
949 
950  viewer->Show(args);
951 
952  return viewer;
953 }