Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
REveProjectionManager.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 
13 #include <ROOT/REveManager.hxx>
15 #include <ROOT/REveCompound.hxx>
16 
17 #include "TBuffer3D.h"
18 #include "TBuffer3DTypes.h"
19 
20 #include "TClass.h"
21 
22 #include <list>
23 
24 /** \class REveProjectionManager
25 \ingroup REve
26 Manager class for steering of projections and managing projected objects.
27 
28 Recursively projects REveElement's and draws axis in the projected
29 scene. It enables to interactively set REveProjection parameters
30 and updates projected scene accordingly.
31 */
32 
33 using namespace ROOT::Experimental;
34 namespace REX = ROOT::Experimental;
35 
36 ////////////////////////////////////////////////////////////////////////////////
37 /// Constructor.
38 
39 REveProjectionManager::REveProjectionManager(REveProjection::EPType_e type):
40  REveElement("REveProjectionManager","")
41 {
42  for (Int_t i = 0; i < REveProjection::kPT_End; ++i)
43  fProjections[i] = nullptr;
44 
45  if (type != REveProjection::kPT_Unknown)
46  SetProjection(type);
47 }
48 
49 ////////////////////////////////////////////////////////////////////////////////
50 /// Destructor.
51 /// Destroys also dependent elements.
52 
53 REveProjectionManager::~REveProjectionManager()
54 {
55  for (Int_t i = 0; i < REveProjection::kPT_End; ++i) {
56  delete fProjections[i];
57  }
58  while ( ! fDependentEls.empty()) {
59  fDependentEls.front()->Destroy();
60  }
61 }
62 
63 ////////////////////////////////////////////////////////////////////////////////
64 /// Add el as dependent element.
65 
66 void REveProjectionManager::AddDependent(REveElement *el)
67 {
68  fDependentEls.push_back(el);
69 }
70 
71 ////////////////////////////////////////////////////////////////////////////////
72 /// Remove el as dependent element.
73 
74 void REveProjectionManager::RemoveDependent(REveElement *el)
75 {
76  fDependentEls.remove(el);
77 }
78 
79 ////////////////////////////////////////////////////////////////////////////////
80 /// Updates name to have consistent information with projection.
81 
82 void REveProjectionManager::UpdateName()
83 {
84  if (fProjection->Is2D())
85  SetName(Form ("%s (%3.1f)", fProjection->GetName(), fProjection->GetDistortion()*1000));
86  else
87  SetName(fProjection->GetName());
88 }
89 
90 ////////////////////////////////////////////////////////////////////////////////
91 /// Set projection type and distortion.
92 
93 void REveProjectionManager::SetProjection(REveProjection::EPType_e type)
94 {
95  static const REveException eH("REveProjectionManager::SetProjection ");
96 
97  if (fProjections[type] == 0)
98  {
99  switch (type)
100  {
101  case REveProjection::kPT_RPhi:
102  {
103  fProjections[type] = new REveRPhiProjection();
104  break;
105  }
106  case REveProjection::kPT_RhoZ:
107  {
108  fProjections[type] = new REveRhoZProjection();
109  break;
110  }
111  case REveProjection::kPT_3D:
112  {
113  fProjections[type] = new REve3DProjection();
114  break;
115  }
116  default:
117  throw eH + "projection type not valid.";
118  break;
119  }
120  }
121 
122  if (fProjection && fProjection->Is2D() != fProjections[type]->Is2D())
123  {
124  throw eH + "switching between 2D and 3D projections not implemented.";
125  }
126 
127  fProjection = fProjections[type];
128  fProjection->SetCenter(fCenter);
129  UpdateName();
130 }
131 
132 ////////////////////////////////////////////////////////////////////////////////
133 /// Set projection center and rebuild projected scene.
134 
135 void REveProjectionManager::SetCenter(Float_t x, Float_t y, Float_t z)
136 {
137  fCenter.Set(x, y, z);
138  fProjection->SetCenter(fCenter);
139  ProjectChildren();
140 }
141 
142 ////////////////////////////////////////////////////////////////////////////////
143 /// Returns true if element el should be imported.
144 ///
145 /// Behaviour depends on the value of the fImportEmpty member:
146 /// false - el or any of its children must be projectable (default);
147 /// true - always import.
148 
149 Bool_t REveProjectionManager::ShouldImport(REveElement *el)
150 {
151  if (fImportEmpty)
152  return kTRUE;
153 
154  if (el->IsA()->InheritsFrom(TClass::GetClass<REveProjectable>()))
155  return kTRUE;
156  for (auto &c: el->RefChildren())
157  if (ShouldImport(c))
158  return kTRUE;
159  return kFALSE;
160 }
161 
162 ////////////////////////////////////////////////////////////////////////////////
163 /// Update dependent elements' bounding box and mark scenes
164 /// containing element root or its children as requiring a repaint.
165 
166 void REveProjectionManager::UpdateDependentElsAndScenes(REveElement * /*root*/)
167 {
168  for (auto &d: fDependentEls) {
169  TAttBBox* bbox = dynamic_cast<TAttBBox *>(d);
170  if (bbox)
171  bbox->ComputeBBox();
172  }
173 
174  static int warn_count = 0;
175  if (++warn_count <= 5)
176  Warning("REveProjectionManager::UpdateDependentElsAndScenes",
177  "Figure out if scene stamping is still needed.");
178  /*
179  List_t scenes;
180  root->CollectScenes(scenes);
181  if (root == this)
182  for (auto &n : fNieces)
183  n->CollectScenes(scenes);
184 
185  REX::gEve->ScenesChanged(scenes);
186  */
187 }
188 
189 ////////////////////////////////////////////////////////////////////////////////
190 /// If el is REveProjectable add projected instance else add plain
191 /// REveElementList to parent. Call the same function on el's
192 /// children.
193 ///
194 /// Returns the projected replica of el. Can be 0, if el and none of
195 /// its children are projectable.
196 
197 REveElement* REveProjectionManager::ImportElementsRecurse(REveElement* el,
198  REveElement* parent)
199 {
200  static const REveException eh("REveProjectionManager::ImportElementsRecurse ");
201 
202  REveElement *new_el = nullptr;
203 
204  if (ShouldImport(el))
205  {
206  REveProjected *new_pr = nullptr;
207  REveProjectable *pble = dynamic_cast<REveProjectable*>(el);
208  if (pble)
209  {
210  new_el = (REveElement*) pble->ProjectedClass(fProjection)->New();
211  new_pr = dynamic_cast<REveProjected*>(new_el);
212  new_pr->SetProjection(this, pble);
213  new_pr->SetDepth(fCurrentDepth);
214  }
215  else
216  {
217  new_el = new REveElement;
218  }
219  new_el->SetName (Form("%s [P]", el->GetCName()));
220  new_el->SetTitle(Form("Projected replica.\n%s", el->GetCTitle()));
221  new_el->SetRnrSelf (el->GetRnrSelf());
222  new_el->SetRnrChildren (el->GetRnrChildren());
223  new_el->SetPickable (el->IsPickable());
224 
225  parent->AddElement(new_el);
226 
227  REveCompound *cmpnd = dynamic_cast<REveCompound*>(el);
228  REveCompound *cmpnd_pr = dynamic_cast<REveCompound*>(new_el);
229  for (auto &c: el->RefChildren()) {
230  REveElement *child_pr = ImportElementsRecurse(c, new_el);
231  if (cmpnd && c->GetCompound() == cmpnd)
232  child_pr->SetCompound(cmpnd_pr);
233  }
234  }
235 
236  return new_el;
237 }
238 
239 ////////////////////////////////////////////////////////////////////////////////
240 /// Recursively import elements and apply projection to the newly
241 /// imported objects.
242 ///
243 /// If ext_list is not 0 the new element is also added to the list.
244 /// This simplifies construction of complex views where projected
245 /// elements are distributed into several scenes for optimization of
246 /// updates and rendering.
247 ///
248 /// Returns the projected replica of el. Can be 0, if el and none of
249 /// its children are projectable.
250 
251 REveElement* REveProjectionManager::ImportElements(REveElement* el,
252  REveElement* ext_list)
253 {
254  REveElement* new_el = ImportElementsRecurse(el, ext_list ? ext_list : this);
255  if (new_el)
256  {
257  AssertBBox();
258  ProjectChildrenRecurse(new_el);
259  AssertBBoxExtents(0.1);
260  StampTransBBox();
261 
262  UpdateDependentElsAndScenes(new_el);
263 
264  if (ext_list)
265  AddNiece(new_el);
266  }
267  return new_el;
268 }
269 
270 ////////////////////////////////////////////////////////////////////////////////
271 /// Recursively import elements and apply projection to the newly
272 /// imported objects.
273 ///
274 /// The proj_parent argument should be a projected replica of parent
275 /// of element 'el'. This allows to insert projected children of
276 /// a given element when they are added after the projection has
277 /// been already performed on the parent.
278 /// This is called from REveElement::ProjectChild().
279 ///
280 /// Returns the projected replica of el. Can be 0, if el and none of
281 /// its children are projectable.
282 
283 REveElement* REveProjectionManager::SubImportElements(REveElement* el,
284  REveElement* proj_parent)
285 {
286  REveElement* new_el = ImportElementsRecurse(el, proj_parent);
287  if (new_el)
288  {
289  AssertBBox();
290  ProjectChildrenRecurse(new_el);
291  AssertBBoxExtents(0.1);
292  StampTransBBox();
293 
294  UpdateDependentElsAndScenes(new_el);
295  }
296  return new_el;
297 }
298 
299 ////////////////////////////////////////////////////////////////////////////////
300 /// Recursively import children elements of el and apply projection
301 /// to the newly imported objects.
302 ///
303 /// The proj_parent argument should be a projected replica of
304 /// element 'el'. This allows to insert projected children of
305 /// a given element when they are added after the projection has
306 /// been already performed on the parent.
307 /// This is called from REveElement::ProjectChild().
308 ///
309 /// Returns the projected replica of el. Can be 0, if el and none of
310 /// its children are projectable.
311 
312 Int_t REveProjectionManager::SubImportChildren(REveElement* el, REveElement* proj_parent)
313 {
314  List_t new_els;
315  for (auto &c: el->RefChildren()) {
316  auto new_el = ImportElementsRecurse(c, proj_parent);
317  if (new_el)
318  new_els.push_back(new_el);
319  }
320 
321  if (!new_els.empty())
322  {
323  AssertBBox();
324  for (auto &nel: new_els)
325  ProjectChildrenRecurse(nel);
326  AssertBBoxExtents(0.1);
327  StampTransBBox();
328 
329  UpdateDependentElsAndScenes(proj_parent);
330  }
331  return (Int_t) new_els.size();
332 }
333 
334 ////////////////////////////////////////////////////////////////////////////////
335 /// Project el (via REveProjected::UpdateProjection()) and recurse
336 /// through el's children.
337 /// Bounding-box is updated along the recursion.
338 
339 void REveProjectionManager::ProjectChildrenRecurse(REveElement* el)
340 {
341  REveProjected* pted = dynamic_cast<REveProjected*>(el);
342  if (pted)
343  {
344  pted->UpdateProjection();
345  TAttBBox* bb = dynamic_cast<TAttBBox*>(pted);
346  if (bb)
347  {
348  Float_t* b = bb->AssertBBox();
349  BBoxCheckPoint(b[0], b[2], b[4]);
350  BBoxCheckPoint(b[1], b[3], b[5]);
351  }
352  el->StampObjProps();
353  }
354 
355  for (auto &c : el->RefChildren()) ProjectChildrenRecurse(c);
356 }
357 
358 ////////////////////////////////////////////////////////////////////////////////
359 /// Project all children recursively, update bounding-box and notify
360 /// EveManger about the scenes that have been changed.
361 
362 void REveProjectionManager::ProjectChildren()
363 {
364  BBoxInit();
365 
366  for (auto &c : fChildren) ProjectChildrenRecurse(c);
367 
368  for (auto &n : fNieces) ProjectChildrenRecurse(n);
369 
370  AssertBBoxExtents(0.1);
371  StampTransBBox();
372 
373  UpdateDependentElsAndScenes(this);
374 }
375 
376 ////////////////////////////////////////////////////////////////////////////////
377 /// Virtual from TAttBBox; fill bounding-box information.
378 ///
379 /// The bounding-box information is kept coherent during addition of
380 /// projected elements and projection parameter updates. This is
381 /// called only in case the manager has not been populated at all.
382 
383 void REveProjectionManager::ComputeBBox()
384 {
385  static const REveException eH("REveProjectionManager::ComputeBBox ");
386 
387  if ( ! HasChildren() && ! HasNieces())
388  {
389  BBoxZero();
390  return;
391  }
392 
393  BBoxInit();
394 }