Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
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#include <ROOT/REveScene.hxx>
17#include <ROOT/REveTrans.hxx>
18
19#include "TBuffer3D.h"
20#include "TBuffer3DTypes.h"
21
22#include "TClass.h"
23
24#include <algorithm>
25#include <cmath>
26#include <cstring>
27#include <functional>
28
29#include <list>
30
31/** \class REveProjectionManager
32\ingroup REve
33Manager class for steering of projections and managing projected objects.
34
35Recursively projects REveElement's and draws axis in the projected
36scene. It enables to interactively set REveProjection parameters
37and updates projected scene accordingly.
38*/
39
40using namespace ROOT::Experimental;
41namespace REX = ROOT::Experimental;
42
43namespace {
44
45////////////////////////////////////////////////////////////////////////////////
46/// Warn if `el` has a transformation other than identity. The vertices of a
47/// projected element are final, so the client must not transform them again.
48/// Identity is allowed: REveStraightLineSet's constructor sets one.
49
50void WarnIfTransformed(REveElement *el)
51{
52 static const REveTrans unit;
53 if (el->HasMainTrans() && std::memcmp(el->RefMainTrans().Array(), unit.Array(), 16 * sizeof(Double_t)) != 0) {
54 ::Warning("REveProjectionManager::ImportElements",
55 "'%s' has a transformation, which the client applies to its projected vertices again.", el->GetCName());
56 }
57}
58
59////////////////////////////////////////////////////////////////////////////////
60/// Warn if projected elements put under `receiver` are drawn in a frame other
61/// than that of `mng`. GetModelTrans() projects into the frame of the manager,
62/// and the client places the projected elements with the matrices of
63/// `receiver` and of its mothers, so the two products must be equal.
64
65void WarnIfFrameDiffers(REveProjectionManager *mng, REveElement *receiver)
66{
67 REveTrans wm, wr;
68 const int nm = mng->ComposeSceneTrans(wm);
69 const int nr = receiver->ComposeSceneTrans(wr);
70 if (nm == 0 && nr == 0)
71 return;
72
73 // Tolerance for the rounding of the inversion, relative to the translations.
74 Double_t scale = 1;
75 for (int i = 12; i < 15; ++i)
76 scale = std::max({scale, std::abs(wm.Array()[i]), std::abs(wr.Array()[i])});
77
78 // d = inverse(W(manager)) * W(receiver), the identity when the frames agree.
80 if (nm > 0) {
81 wm.Invert();
82 d = wm;
83 if (nr > 0)
84 d.MultRight(wr);
85 } else {
86 d = wr;
87 }
88
89 static const REveTrans unit;
90 for (int i = 0; i < 16; ++i) {
91 if (std::abs(d.Array()[i] - unit.Array()[i]) > 1e-6 * scale) {
92 ::Warning("REveProjectionManager::ImportElements",
93 "'%s' places projected elements in a frame other than that of '%s', in which they are "
94 "projected; the client draws them transformed.",
95 receiver->GetCName(), mng->GetCName());
96 return;
97 }
98 }
99}
100
101} // namespace
102
103////////////////////////////////////////////////////////////////////////////////
104/// Constructor.
105
106REveProjectionManager::REveProjectionManager(REveProjection::EPType_e type):
107 REveElement("REveProjectionManager","")
108{
109 for (Int_t i = 0; i < REveProjection::kPT_End; ++i)
110 fProjections[i] = nullptr;
111
114}
115
116////////////////////////////////////////////////////////////////////////////////
117/// Destructor.
118/// Destroys also dependent elements.
119
121{
122 for (Int_t i = 0; i < REveProjection::kPT_End; ++i) {
123 delete fProjections[i];
124 }
125 while ( ! fDependentEls.empty()) {
126 fDependentEls.front()->Destroy();
127 }
128}
129
130////////////////////////////////////////////////////////////////////////////////
131/// Add el as dependent element.
132
134{
135 fDependentEls.push_back(el);
136}
137
138////////////////////////////////////////////////////////////////////////////////
139/// Remove el as dependent element.
140
145
146////////////////////////////////////////////////////////////////////////////////
147/// Updates name to have consistent information with projection.
148
149////////////////////////////////////////////////////////////////////////////////
150/// Add `steps` * 1e-4 to the distortion of the current projection, clamped at
151/// zero, and reproject, which also refreshes the REveProjectionAxis nieces.
152/// Called by MIR.
153
155{
156 if (!fProjection)
157 return;
158
159 Float_t d = fProjection->GetDistortion() + steps * 1e-4f;
160 if (d < 0.f)
161 d = 0.f;
163
164 UpdateName();
166}
167
169{
170 if (fProjection->Is2D())
171 SetName(Form ("%s (%3.1f)", fProjection->GetName(), fProjection->GetDistortion()*1000));
172 else
174}
175
176////////////////////////////////////////////////////////////////////////////////
177/// Set projection type and distortion.
178
180{
181 static const REveException eH("REveProjectionManager::SetProjection ");
182
183 if (fProjections[type] == nullptr)
184 {
185 switch (type)
186 {
188 {
190 break;
191 }
193 {
195 break;
196 }
198 {
200 break;
201 }
203 {
205 break;
206 }
208 {
210 break;
211 }
213 {
215 break;
216 }
218 {
220 break;
221 }
222 default:
223 throw eH + "projection type not valid.";
224 break;
225 }
226 }
227
229 {
230 throw eH + "switching between 2D and 3D projections not implemented.";
231 }
232
235 UpdateName();
236}
237
238////////////////////////////////////////////////////////////////////////////////
239/// Set projection center and rebuild projected scene.
240
247
248////////////////////////////////////////////////////////////////////////////////
249/// Returns true if element el should be imported.
250///
251/// Behaviour depends on the value of the fImportEmpty member:
252/// false - el or any of its children must be projectable (default);
253/// true - always import.
254
256{
257 if (fImportEmpty)
258 return kTRUE;
259
260 if (el->IsA()->InheritsFrom(TClass::GetClass<REveProjectable>()))
261 return kTRUE;
262 for (auto &c: el->RefChildren())
263 if (ShouldImport(c))
264 return kTRUE;
265 return kFALSE;
266}
267
268////////////////////////////////////////////////////////////////////////////////
269/// Update dependent elements' bounding boxes, and tell the nieces, such as an
270/// REveProjectionAxis, that the manager changed. Called after every import and
271/// reprojection.
272
274{
275 for (auto &d : fDependentEls)
276 d->ComputeBBox();
277
278 for (auto &n : fNieces)
279 n->AuntChanged(this);
280}
281
282////////////////////////////////////////////////////////////////////////////////
283/// If el is REveProjectable add projected instance else add plain
284/// REveElementList to parent. Call the same function on el's
285/// children.
286///
287/// Returns the projected replica of el. Can be 0, if el and none of
288/// its children are projectable.
289
291 REveElement* parent)
292{
293 static const REveException eh("REveProjectionManager::ImportElementsRecurse ");
294
295 REveElement *new_el = nullptr;
296
297 if (ShouldImport(el))
298 {
299 REveProjected *new_pr = nullptr;
300 REveProjectable *pble = dynamic_cast<REveProjectable*>(el);
301 if (pble)
302 {
303 new_el = (REveElement*) pble->ProjectedClass(fProjection)->New();
304 new_pr = dynamic_cast<REveProjected*>(new_el);
305 new_pr->SetProjection(this, pble);
306 new_pr->SetDepth(fCurrentDepth);
307 }
308 else
309 {
310 new_el = new REveElement;
311 }
312 new_el->SetName (Form("%s [P]", el->GetCName()));
313 new_el->SetTitle(Form("Projected replica.\n%s", el->GetCTitle()));
314 new_el->SetRnrSelf (el->GetRnrSelf());
315 new_el->SetRnrChildren (el->GetRnrChildren());
316 new_el->SetPickable (el->IsPickable());
317
318 parent->AddElement(new_el);
319 WarnIfTransformed(new_el);
320
321 REveCompound *cmpnd = dynamic_cast<REveCompound*>(el);
322 REveCompound *cmpnd_pr = dynamic_cast<REveCompound*>(new_el);
323 for (auto &c: el->RefChildren()) {
324 REveElement *child_pr = ImportElementsRecurse(c, new_el);
325 if (cmpnd && c->GetCompound() == cmpnd)
326 child_pr->SetCompound(cmpnd_pr);
327 }
328 }
329
330 return new_el;
331}
332
333////////////////////////////////////////////////////////////////////////////////
334/// Recursively import elements and apply projection to the newly
335/// imported objects.
336///
337/// If ext_list is not 0 the new element is also added to the list.
338/// This simplifies construction of complex views where projected
339/// elements are distributed into several scenes for optimization of
340/// updates and rendering.
341///
342/// Returns the projected replica of el. Can be 0, if el and none of
343/// its children are projectable.
344
346 REveElement* ext_list)
347{
348 WarnIfFrameDiffers(this, ext_list ? ext_list : this);
349 REveElement* new_el = ImportElementsRecurse(el, ext_list ? ext_list : this);
350 if (new_el)
351 {
352 AssertBBox();
355
357
358 if (ext_list)
359 AddNiece(new_el);
360 }
361 return new_el;
362}
363
364////////////////////////////////////////////////////////////////////////////////
365/// Recursively import elements and apply projection to the newly
366/// imported objects.
367///
368/// The proj_parent argument should be a projected replica of parent
369/// of element 'el'. This allows to insert projected children of
370/// a given element when they are added after the projection has
371/// been already performed on the parent.
372/// This is called from REveElement::ProjectChild().
373///
374/// Returns the projected replica of el. Can be 0, if el and none of
375/// its children are projectable.
376
378 REveElement* proj_parent)
379{
380 WarnIfFrameDiffers(this, proj_parent);
381 REveElement* new_el = ImportElementsRecurse(el, proj_parent);
382 if (new_el)
383 {
384 AssertBBox();
387
389 }
390 return new_el;
391}
392
393////////////////////////////////////////////////////////////////////////////////
394/// Recursively import children elements of el and apply projection
395/// to the newly imported objects.
396///
397/// The proj_parent argument should be a projected replica of
398/// element 'el'. This allows to insert projected children of
399/// a given element when they are added after the projection has
400/// been already performed on the parent.
401/// This is called from REveElement::ProjectChild().
402///
403/// Returns the projected replica of el. Can be 0, if el and none of
404/// its children are projectable.
405
407{
408 WarnIfFrameDiffers(this, proj_parent);
409 List_t new_els;
410 for (auto &c: el->RefChildren()) {
411 auto new_el = ImportElementsRecurse(c, proj_parent);
412 if (new_el)
413 new_els.push_back(new_el);
414 }
415
416 if (!new_els.empty())
417 {
418 AssertBBox();
419 for (auto &nel: new_els)
422
423 UpdateDependentElements(proj_parent);
424 }
425 return (Int_t) new_els.size();
426}
427
428////////////////////////////////////////////////////////////////////////////////
429/// Project el (via REveProjected::UpdateProjection()) and recurse
430/// through el's children.
431/// Bounding-box is updated along the recursion.
432
434{
435 REveProjected* pted = dynamic_cast<REveProjected*>(el);
436 if (pted)
437 {
438 pted->UpdateProjection();
439 el->StampObjProps();
440 if (el->AssertBBox() == kBBoxSet) {
443 }
444 }
445
446 for (auto &c : el->RefChildren()) ProjectChildrenRecurse(c);
447}
448
449////////////////////////////////////////////////////////////////////////////////
450/// Project all children recursively, update bounding-box and notify
451/// EveManger about the scenes that have been changed.
452
454{
455 BBoxInit();
456
457 for (auto &c : fChildren) ProjectChildrenRecurse(c);
458
459 for (auto &n : fNieces) ProjectChildrenRecurse(n);
460
462
464}
465
466////////////////////////////////////////////////////////////////////////////////
467/// Return the matrix that takes the coordinates of `model` into the frame of
468/// this manager, in which the projection is computed:
469/// inverse(W(this)) * W(model), with W(x) from x->ComposeSceneTrans(), as the
470/// client composes them for the 3D view. When the two chains do not meet, their
471/// tops are taken to be in the same frame.
472///
473/// Returns nullptr when neither chain has a matrix, and the model's own matrix
474/// when it is the only one. Otherwise fills `t` and returns it, so `t` must
475/// outlive the result.
476
478{
479 REveTrans wm;
480 const int nm = ComposeSceneTrans(wm);
481 const int n = model->ComposeSceneTrans(t);
482
483 if (nm == 0) {
484 if (n == 0)
485 return nullptr;
486 if (n == 1 && model->PtrMainTrans(kFALSE))
487 return model->PtrMainTrans(kFALSE);
488 return &t;
489 }
490
491 wm.Invert();
492 if (n == 0)
493 t = wm;
494 else
495 t.MultLeft(wm);
496 return &t;
497}
498
499////////////////////////////////////////////////////////////////////////////////
500/// Fill the bounding box (virtual from REveElement) with the union of the
501/// boxes of the projected elements below the children and the nieces.
502/// ImportElements() and ProjectChildren() also widen it as they project.
503
505{
506 if ( ! HasChildren() && ! HasNieces())
507 {
508 BBoxZero();
509 return;
510 }
511
512 BBoxInit();
513
514 std::function<void(REveElement *)> add = [&](REveElement *el) {
515 if (dynamic_cast<REveProjected *>(el) && el->AssertBBox() == kBBoxSet &&
516 el->GetBBoxMin().fX <= el->GetBBoxMax().fX) {
517 BBoxCheckPoint(el->GetBBoxMin());
518 BBoxCheckPoint(el->GetBBoxMax());
519 }
520 for (auto &c : el->RefChildren())
521 add(c);
522 };
523 for (auto &c : fChildren)
524 add(c);
525 for (auto &n : fNieces)
526 add(n);
527
529}
#define d(i)
Definition RSha256.hxx:102
#define c(i)
Definition RSha256.hxx:101
#define e(i)
Definition RSha256.hxx:103
constexpr Bool_t kFALSE
Definition RtypesCore.h:109
constexpr Bool_t kTRUE
Definition RtypesCore.h:108
void Warning(const char *location, const char *msgfmt,...)
Use this function in warning situations.
Definition TError.cxx:252
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition TString.cxx:2571
virtual void AddNiece(REveElement *el)
virtual Bool_t HasMainTrans() const
TClass * IsA() const
Return class for this element Return REveElement class in case dicitonary is not exisiting.
const char * GetCTitle() const
void SetCompound(REveCompound *c)
virtual REveTrans & RefMainTrans()
Return reference to main transformation.
void BBoxCheckPoint(const REveVector &v)
const char * GetCName() const
virtual void AddElement(REveElement *el)
Add el to the list of children.
virtual Bool_t GetRnrSelf() const
Int_t ComposeSceneTrans(REveTrans &t) const
Compose into t the matrices of this element and of its mothers up to, not including,...
virtual Bool_t SetRnrChildren(Bool_t rnr)
Set render state of this element's children, i.e.
void SetTitle(const std::string &title)
Set title of an element.
void AssertBBoxExtents(Float_t epsilon=0.005)
Widen every side of the bounding box shorter than epsilon to epsilon, keeping its centre.
void BBoxZero(Float_t epsilon=0, Float_t x=0, Float_t y=0, Float_t z=0)
Set the bounding box to a cube of half-side epsilon at (x, y, z); with the defaults,...
const REveVector & GetBBoxMax() const
virtual Bool_t SetRnrSelf(Bool_t rnr)
Set render state of this element, i.e.
virtual Bool_t GetRnrChildren() const
void BBoxInit()
Start filling the bounding box with BBoxCheckPoint(): min at +infinity, max at -infinity,...
EBBoxState AssertBBox()
Compute the bounding box if it is invalid, and return its state.
const REveVector & GetBBoxMin() const
std::list< REveElement * > List_t
REveElement(const std::string &name="", const std::string &title="")
Default constructor.
void SetName(const std::string &name)
Set name of an element.
REveException Exception-type thrown by Eve classes.
Definition REveTypes.hxx:42
virtual TClass * ProjectedClass(const REveProjection *p) const =0
virtual void SetProjection(REveProjectionManager *mng, REveProjectable *model)
Sets projection manager and reference in the projectable object.
virtual void SetDepth(Float_t d)
Set depth coordinate for the element.
REveProjectionManager Manager class for steering of projections and managing projected objects.
REveProjection * fProjections[REveProjection::kPT_End]
void AddDependent(REveElement *el)
Add el as dependent element.
virtual REveElement * ImportElements(REveElement *el, REveElement *ext_list=nullptr)
Recursively import elements and apply projection to the newly imported objects.
virtual void UpdateDependentElements(REveElement *root)
Update dependent elements' bounding boxes, and tell the nieces, such as an REveProjectionAxis,...
void SetProjection(REveProjection::EPType_e type)
Set projection type and distortion.
virtual REveElement * ImportElementsRecurse(REveElement *el, REveElement *parent)
If el is REveProjectable add projected instance else add plain REveElementList to parent.
void ComputeBBox() override
Fill the bounding box (virtual from REveElement) with the union of the boxes of the projected element...
virtual REveElement * SubImportElements(REveElement *el, REveElement *proj_parent)
Recursively import elements and apply projection to the newly imported objects.
void RemoveDependent(REveElement *el)
Remove el as dependent element.
void BumpDistortion(Int_t steps)
Updates name to have consistent information with projection.
virtual void ProjectChildren()
Project all children recursively, update bounding-box and notify EveManger about the scenes that have...
virtual void ProjectChildrenRecurse(REveElement *el)
Project el (via REveProjected::UpdateProjection()) and recurse through el's children.
const REveTrans * GetModelTrans(REveElement *model, REveTrans &t)
Return the matrix that takes the coordinates of model into the frame of this manager,...
void SetCenter(Float_t x, Float_t y, Float_t z)
Set projection center and rebuild projected scene.
virtual Bool_t ShouldImport(REveElement *el)
Returns true if element el should be imported.
virtual Int_t SubImportChildren(REveElement *el, REveElement *proj_parent)
Recursively import children elements of el and apply projection to the newly imported objects.
virtual void SetCenter(REveVector &v)
virtual Bool_t Is2D() const =0
void SetDistortion(Float_t d)
Set distortion.
Double_t Invert()
Invert matrix.
void MultRight(const REveTrans &t)
Multiply from right: this = this * t.
void MultLeft(const REveTrans &t)
Multiply from left: this = t * this.
void Set(const Float_t *v)
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Return a pointer to a newly allocated object of this class.
Definition TClass.cxx:5111
Bool_t InheritsFrom(const char *cl) const override
Return kTRUE if this class inherits from a class with name "classname".
Definition TClass.cxx:4995
Double_t y[n]
Definition legend1.C:17
Double_t x[n]
Definition legend1.C:17
const Int_t n
Definition legend1.C:16
Namespace for ROOT features in testing.
Definition TROOT.h:100