Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
REveUtil.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/REveUtil.hxx>
13 #include <ROOT/REveElement.hxx>
14 #include <ROOT/REveManager.hxx>
15 
16 #include "TError.h"
17 #include "TGeoManager.h"
18 #include "TGeoMatrix.h"
19 #include "TClass.h"
20 #include "TMath.h"
21 
22 #include "TStyle.h"
23 #include "TColor.h"
24 
25 #include "TROOT.h"
26 #include "TInterpreter.h"
27 #include "TSystem.h"
28 
29 #include "TGClient.h"
30 #include "TGMimeTypes.h"
31 
32 #include "Riostream.h"
33 
34 #include <list>
35 #include <algorithm>
36 #include <string>
37 
38 using namespace ROOT::Experimental;
39 namespace REX = ROOT::Experimental;
40 
41 /** \class REveUtil
42 \ingroup REve
43 Standard utility functions for Eve.
44 */
45 
46 TObjArray* REX::REveUtil::fgDefaultColors = nullptr;
47 
48 namespace
49 {
50 ////////////////////////////////////////////////////////////////////////////////
51 /// Remove last part of string 's', starting from the last
52 /// occurrence of character 'c'.
53 /// Remove directory part -- everything until the last '/'.
54 
55 void ChompTailAndDir(TString& s, char c='.')
56 {
57  Ssiz_t p = s.Last(c);
58  if (p != kNPOS)
59  s.Remove(p);
60 
61  Ssiz_t ls = s.Last('/');
62  if (ls != kNPOS)
63  s.Remove(0, ls + 1);
64 }
65 }
66 
67 ////////////////////////////////////////////////////////////////////////////////
68 /// Checks if macro 'mac' is loaded.
69 
70 Bool_t REveUtil::CheckMacro(const char* mac)
71 {
72  // Axel's advice; now sth seems slow, using old method below for test.
73  // return gROOT->GetInterpreter()->IsLoaded(mac);
74 
75  // Previous version expected function with same name and used ROOT's
76  // list of global functions.
77 
78  TString foo(mac); ChompTailAndDir(foo);
79  if (gROOT->GetGlobalFunction(foo.Data(), 0, kFALSE) != 0)
80  return kTRUE;
81  else
82  return (gROOT->GetGlobalFunction(foo.Data(), 0, kTRUE) != 0);
83 }
84 
85 ////////////////////////////////////////////////////////////////////////////////
86 /// Load and execute macro 'mac' if it has not been loaded yet.
87 
88 void REveUtil::AssertMacro(const char* mac)
89 {
90  if( CheckMacro(mac) == kFALSE) {
91  gROOT->Macro(mac);
92  }
93 }
94 
95 ////////////////////////////////////////////////////////////////////////////////
96 /// Execute macro 'mac'. Do not reload the macro.
97 
98 void REveUtil::Macro(const char* mac)
99 {
100  if (CheckMacro(mac) == kFALSE) {
101  gROOT->LoadMacro(mac);
102  }
103  TString foo(mac); ChompTailAndDir(foo); foo += "()";
104  gROOT->ProcessLine(foo.Data());
105 }
106 
107 ////////////////////////////////////////////////////////////////////////////////
108 /// Makes sure that macro 'mac' is loaded, but do not reload it.
109 
110 void REveUtil::LoadMacro(const char* mac)
111 {
112  if (CheckMacro(mac) == kFALSE) {
113  gROOT->LoadMacro(mac);
114  }
115 }
116 
117 ////////////////////////////////////////////////////////////////////////////////
118 /// Fill col with RGBA values corresponding to index ci. If alpha
119 /// is true, set alpha component of col to 255.
120 /// ROOT's indexed color palette does not support transparency.
121 
122 void REveUtil::ColorFromIdx(Color_t ci, UChar_t col[4], Bool_t alpha)
123 {
124  TColor* c = gROOT->GetColor(ci);
125  if (c)
126  {
127  col[0] = (UChar_t)(255*c->GetRed());
128  col[1] = (UChar_t)(255*c->GetGreen());
129  col[2] = (UChar_t)(255*c->GetBlue());
130  if (alpha) col[3] = 255;
131  }
132  else
133  {
134  // Set to magenta.
135  col[0] = 255; col[1] = 0; col[2] = 255;
136  if (alpha) col[3] = 255;
137  return;
138  }
139 }
140 
141 ////////////////////////////////////////////////////////////////////////////////
142 /// Fill col with RGBA values corresponding to index ci and transparency.
143 /// ROOT's indexed color palette does not support transparency.
144 
145 void REveUtil::ColorFromIdx(Color_t ci, UChar_t col[4], Char_t transparency)
146 {
147  UChar_t alpha = (255*(100 - transparency))/100;
148 
149  TColor* c = gROOT->GetColor(ci);
150  if (c)
151  {
152  col[0] = (UChar_t)(255*c->GetRed());
153  col[1] = (UChar_t)(255*c->GetGreen());
154  col[2] = (UChar_t)(255*c->GetBlue());
155  col[3] = alpha;
156  }
157  else
158  {
159  // Set to magenta.
160  col[0] = 255; col[1] = 0; col[2] = 255; col[3] = alpha;
161  return;
162  }
163 }
164 
165 ////////////////////////////////////////////////////////////////////////////////
166 /// Fill col with weighted RGBA values corresponding to
167 /// color-indices c1 and c2. If alpha is true, set alpha component
168 /// of col to 255.
169 
170 void REveUtil::ColorFromIdx(Float_t f1, Color_t c1, Float_t f2, Color_t c2,
171  UChar_t col[4], Bool_t alpha)
172 {
173  TColor* t1 = gROOT->GetColor(c1);
174  TColor* t2 = gROOT->GetColor(c2);
175  if(t1 && t2) {
176  col[0] = (UChar_t)(255*(f1*t1->GetRed() + f2*t2->GetRed()));
177  col[1] = (UChar_t)(255*(f1*t1->GetGreen() + f2*t2->GetGreen()));
178  col[2] = (UChar_t)(255*(f1*t1->GetBlue() + f2*t2->GetBlue()));
179  if (alpha) col[3] = 255;
180  }
181 }
182 
183 ////////////////////////////////////////////////////////////////////////////////
184 /// Find address of Color_t data-member with name varname in object
185 /// obj.
186 ///
187 /// This is used to access color information for TGListTreeItem
188 /// coloration from visualization macros that wrap TObjects into
189 /// REveElementObjectPtr instances.
190 
191 Color_t* REveUtil::FindColorVar(TObject* obj, const char* varname)
192 {
193  static const REveException eh("REveUtil::FindColorVar");
194 
195  Int_t off = obj->IsA()->GetDataMemberOffset(varname);
196  if(off == 0)
197  throw(eh + "could not find member '" + varname + "' in class " + obj->IsA()->GetName() + ".");
198  return (Color_t*) (((char*)obj) + off);
199 }
200 
201 ////////////////////////////////////////////////////////////////////////////////
202 /// Tweak all ROOT colors to become brighter (if value > 0) or
203 /// darker (value < 0). Reasonable values for the value argument are
204 /// from -2.5 to 2.5 (error will be printed otherwise).
205 /// If value is zero, the original colors are restored.
206 ///
207 /// You should call REveManager::FullRedraw3D() afterwards or set
208 /// the argument full_redraw to true (default is false).
209 
210 void REveUtil::SetColorBrightness(Float_t value, Bool_t full_redraw)
211 {
212  if (value < -2.5 || value > 2.5)
213  {
214  Error("REveUtil::SetColorBrightness", "value '%f' out of range [-0.5, 0.5].", value);
215  return;
216  }
217 
218  TObjArray *colors = (TObjArray*) gROOT->GetListOfColors();
219 
220  if (fgDefaultColors == 0)
221  {
222  const Int_t n_col = colors->GetEntriesFast();
223  fgDefaultColors = new TObjArray(n_col);
224  for (Int_t i = 0; i < n_col; ++i)
225  {
226  TColor* c = (TColor*) colors->At(i);
227  if (c)
228  fgDefaultColors->AddAt(new TColor(*c), i);
229  }
230  }
231 
232  const Int_t n_col = fgDefaultColors->GetEntriesFast();
233  for (Int_t i = 0; i < n_col; ++i)
234  {
235  TColor* cdef = (TColor*) fgDefaultColors->At(i);
236  if (cdef)
237  {
238  TColor* croot = (TColor*) colors->At(i);
239  if (!croot)
240  {
241  croot = new TColor(*cdef);
242  colors->AddAt(croot, i);
243  }
244  else
245  {
246  cdef->Copy(*croot);
247  }
248 
249  Float_t r, g, b;
250  croot->GetRGB(r, g, b);
251  r = TMath::Power( r, (2.5 - value)/2.5);
252  g = TMath::Power(g, (2.5 - value)/2.5);
253  b = TMath::Power(b, (2.5 - value)/2.5);
254 
255  r = TMath::Min(r, 1.0f);
256  g = TMath::Min(g, 1.0f);
257  b = TMath::Min(b, 1.0f);
258 
259  croot->SetRGB(r, g, b);
260  }
261  else
262  {
263  delete colors->RemoveAt(i);
264  }
265  }
266 
267  if (full_redraw && REX::gEve)
268  REX::gEve->FullRedraw3D();
269 }
270 
271 ////////////////////////////////////////////////////////////////////////////////
272 /// Return true if interval Q is contained within interval M for U1 variables.
273 /// It is assumed that all values are within the [-2pi, 2pi] interval and
274 /// minM <= maxM & minQ <= maxQ.
275 
276 Bool_t REveUtil::IsU1IntervalContainedByMinMax(Float_t minM, Float_t maxM,
277  Float_t minQ, Float_t maxQ)
278 {
279  using namespace TMath;
280 
281  if (maxQ < minM)
282  {
283  minQ += TwoPi(); maxQ += TwoPi();
284  }
285  else if (minQ > maxM)
286  {
287  minQ -= TwoPi(); maxQ -= TwoPi();
288  }
289  return minQ >= minM && maxQ <= maxM;
290 }
291 
292 ////////////////////////////////////////////////////////////////////////////////
293 /// Return true if interval Q is overlapping within interval M for U1 variables.
294 /// It is assumed that all values are within the [-2pi, 2pi] interval and
295 /// minM <= maxM & minQ <= maxQ.
296 
297 Bool_t REveUtil::IsU1IntervalOverlappingByMinMax(Float_t minM, Float_t maxM,
298  Float_t minQ, Float_t maxQ)
299 {
300  using namespace TMath;
301 
302  if (maxQ < minM)
303  {
304  minQ += TwoPi(); maxQ += TwoPi();
305  }
306  else if (minQ > maxM)
307  {
308  minQ -= TwoPi(); maxQ -= TwoPi();
309  }
310  return maxQ >= minM && minQ <= maxM;
311 }
312 
313 ////////////////////////////////////////////////////////////////////////////////
314 /// Get fraction of interval [minQ, maxQ] in [minM, maxM]
315 
316 Float_t REveUtil::GetFraction(Float_t minM, Float_t maxM, Float_t minQ, Float_t maxQ)
317 {
318  if (minQ>=minM && maxQ<=maxM)
319  return 1;
320 
321  else if (minQ<minM && maxQ>maxM)
322  return (maxM-minM)/(maxQ-minQ);
323 
324  else if (minQ>=minM && maxQ>maxM)
325  return (maxM-minQ)/(maxQ-minQ);
326 
327  else if (minQ<minM && maxQ<=maxM)
328  return (maxQ-minM)/(maxQ-minQ);
329 
330  return 0;
331 }
332 
333 
334 /** \class REveGeoManagerHolder
335 \ingroup REve
336 Exception safe wrapper for setting gGeoManager.
337 Functionality to lock-unlock via setting of a static lock in
338 TGeoManager should be added (new feature of TGeoManager).
339 */
340 
341 ////////////////////////////////////////////////////////////////////////////////
342 /// Constructor.
343 /// If n_seg is specified and larger than 2, the new geo-manager's
344 /// NSegments is set to this value.
345 
346 REveGeoManagerHolder::REveGeoManagerHolder(TGeoManager* new_gmgr, Int_t n_seg) :
347  fManager (gGeoManager),
348  fNSegments (0)
349 {
350  gGeoManager = new_gmgr;
351  if (gGeoManager) {
352  gGeoIdentity = (TGeoIdentity *)gGeoManager->GetListOfMatrices()->At(0);
353  if (n_seg > 2) {
354  fNSegments = gGeoManager->GetNsegments();
355  gGeoManager->SetNsegments(n_seg);
356  }
357  } else {
358  gGeoIdentity = nullptr;
359  }
360 }
361 
362 ////////////////////////////////////////////////////////////////////////////////
363 /// Destructor.
364 
365 REveGeoManagerHolder::~REveGeoManagerHolder()
366 {
367  if (gGeoManager && fNSegments > 2) {
368  gGeoManager->SetNsegments(fNSegments);
369  }
370  gGeoManager = fManager;
371  if (gGeoManager) {
372  gGeoIdentity = (TGeoIdentity *)gGeoManager->GetListOfMatrices()->At(0);
373  } else {
374  gGeoIdentity = nullptr;
375  }
376 }
377 
378 /** \class REveRefCnt
379 \ingroup REve
380 Base-class for reference-counted objects.
381 By default the object is destroyed when zero reference-count is reached.
382 */
383 
384 /** \class REveRefBackPtr
385 \ingroup REve
386 Base-class for reference-counted objects with reverse references to
387 REveElement objects.
388 */
389 
390 ////////////////////////////////////////////////////////////////////////////////
391 /// Default constructor.
392 
393 REveRefBackPtr::REveRefBackPtr() :
394  REveRefCnt(),
395  fBackRefs()
396 {
397 }
398 
399 ////////////////////////////////////////////////////////////////////////////////
400 /// Destructor. Noop, should complain if back-ref list is not empty.
401 
402 REveRefBackPtr::~REveRefBackPtr()
403 {
404  // !!! Complain if list not empty.
405 }
406 
407 ////////////////////////////////////////////////////////////////////////////////
408 /// Copy constructor. New copy starts with zero reference count and
409 /// empty back-reference list.
410 
411 REveRefBackPtr::REveRefBackPtr(const REveRefBackPtr&) :
412  REveRefCnt(),
413  fBackRefs()
414 {
415 }
416 
417 ////////////////////////////////////////////////////////////////////////////////
418 /// Assignment operator. Reference count and back-reference
419 /// information is not assigned as these object hold pointers to a
420 /// specific object.
421 
422 REveRefBackPtr& REveRefBackPtr::operator=(const REveRefBackPtr&)
423 {
424  return *this;
425 }
426 
427 ////////////////////////////////////////////////////////////////////////////////
428 /// Increase reference count and add re to the list of back-references.
429 
430 void REveRefBackPtr::IncRefCount(REveElement* re)
431 {
432  REveRefCnt::IncRefCount();
433  ++fBackRefs[re];
434 }
435 
436 ////////////////////////////////////////////////////////////////////////////////
437 /// Decrease reference count and remove re from the list of back-references.
438 
439 void REveRefBackPtr::DecRefCount(REveElement *re)
440 {
441  auto i = fBackRefs.find(re);
442  if (i != fBackRefs.end()) {
443  if (--(i->second) <= 0)
444  fBackRefs.erase(i);
445  REveRefCnt::DecRefCount();
446  } else {
447  Warning("REveRefBackPtr::DecRefCount", "element '%s' not found in back-refs.", re->GetCName());
448  }
449 }
450 
451 ////////////////////////////////////////////////////////////////////////////////
452 /// Add given stamps to elements in the list of reverse references.
453 
454 void REveRefBackPtr::StampBackPtrElements(UChar_t stamps)
455 {
456  for (auto &i: fBackRefs)
457  i.first->AddStamp(stamps);
458 }