Logo ROOT   6.10/09
Reference Guide
TGLTH3Composition.cxx
Go to the documentation of this file.
1 // @(#)root/gl:$Id$
2 // Author: Timur Pocheptsov 07/08/2009
3 
4 #include <stdexcept>
5 
6 #include "KeySymbols.h"
7 #include "TVirtualX.h"
8 #include "Buttons.h"
9 #include "TString.h"
10 #include "TError.h"
11 #include "TColor.h"
12 #include "TROOT.h"
13 #include "TMath.h"
14 
15 #include "TGLTH3Composition.h"
16 #include "TGLIncludes.h"
17 
18 /** \class TGLTH3Composition
19 \ingroup opengl
20 */
21 
23 
24 ////////////////////////////////////////////////////////////////////////////////
25 ///I have to define it, since explicit copy ctor was declared.
26 
28 {
29 }
30 
31 namespace {
32 
33 void CompareAxes(const TAxis *a1, const TAxis *a2, const TString &axisName);
34 
35 }
36 
37 ////////////////////////////////////////////////////////////////////////////////
38 ///Add TH3 into collection. Throw if fHists is not empty
39 ///but ranges are not equal.
40 
42 {
43  const TAxis *xa = h->GetXaxis();
44  const TAxis *ya = h->GetYaxis();
45  const TAxis *za = h->GetZaxis();
46 
47  if (!fHists.size()) {
48  //This is the first hist in a composition,
49  //take its ranges and reset axes for the composition.
50  fXaxis.Set(h->GetNbinsX(), xa->GetBinLowEdge(xa->GetFirst()), xa->GetBinUpEdge(xa->GetLast()));
51  fYaxis.Set(h->GetNbinsY(), ya->GetBinLowEdge(ya->GetFirst()), ya->GetBinUpEdge(ya->GetLast()));
52  fZaxis.Set(h->GetNbinsZ(), za->GetBinLowEdge(za->GetFirst()), za->GetBinUpEdge(za->GetLast()));
53  } else {
54  CompareAxes(xa, GetXaxis(), "X");
55  CompareAxes(ya, GetYaxis(), "Y");
56  CompareAxes(za, GetZaxis(), "Z");
57  }
58 
59  fHists.push_back(TH3Pair_t(h, shape));
60 }
61 
62 ////////////////////////////////////////////////////////////////////////////////
63 ///Check if "this" is under cursor.
64 
66 {
67  if (!fPainter.get())
68  return 9999;
69 
70  return fPainter->DistancetoPrimitive(px, py);
71 }
72 
73 ////////////////////////////////////////////////////////////////////////////////
74 ///Mouse and keyboard events.
75 
77 {
78  fPainter->ExecuteEvent(event, px, py);
79 }
80 
81 ////////////////////////////////////////////////////////////////////////////////
82 ///I cannot show bin content in a status bar -
83 ///since there can be several bins in one.
84 
85 char *TGLTH3Composition::GetObjectInfo(Int_t /*px*/, Int_t /*py*/) const
86 {
87  static char message[] = "TH3 composition";
88  return message;
89 }
90 
91 ////////////////////////////////////////////////////////////////////////////////
92 ///Paint a composition of 3d hists.
93 
95 {
96  if (!fHists.size())
97  return;
98 
99  //create a painter.
100  if (!fPainter.get())
101  fPainter.reset(new TGLHistPainter(this));
102 
103  fPainter->Paint("dummy");
104 }
105 
106 /** \class TGLTH3CompositionPainter
107 \ingroup opengl
108 */
109 
111 
112 ////////////////////////////////////////////////////////////////////////////////
113 ///Ctor.
114 
116  TGLPlotCoordinates *coord)
117  : TGLPlotPainter(data, cam, coord, kFALSE, kFALSE, kFALSE),
118  fData(data)
119 {
120 }
121 
122 ////////////////////////////////////////////////////////////////////////////////
123 ///Will be never called from TPad.
124 
126 {
127  static char message[] = "TH3 composition";
128  return message;
129 }
130 
131 ////////////////////////////////////////////////////////////////////////////////
132 
134 {
135  if (!fData->fHists.size())
136  return kFALSE;
137 
138  //Prepare plot painter.
139  //Forget about log scale.
140  fCoord->SetZLog(kFALSE);
141  fCoord->SetYLog(kFALSE);
142  fCoord->SetXLog(kFALSE);
143 
144  if (!fCoord->SetRanges(fHist, kFALSE, kTRUE))//kFALSE == drawErrors, kTRUE == zAsBins
145  return kFALSE;
146 
147  fBackBox.SetPlotBox(fCoord->GetXRangeScaled(), fCoord->GetYRangeScaled(), fCoord->GetZRangeScaled());
148  if (fCamera)
149  fCamera->SetViewVolume(fBackBox.Get3DBox());
150 
151  //Loop on hists.
152  const TH3 *h = fData->fHists[0].first;
153  fMinMaxVal.second = h->GetBinContent(fCoord->GetFirstXBin(),
154  fCoord->GetFirstYBin(),
155  fCoord->GetFirstZBin());
156  fMinMaxVal.first = fMinMaxVal.second;
157 
158  for (UInt_t hNum = 0, lastH = fData->fHists.size(); hNum < lastH; ++hNum) {
159  h = fData->fHists[hNum].first;
160  for (Int_t ir = fCoord->GetFirstXBin(); ir <= fCoord->GetLastXBin(); ++ir) {
161  for (Int_t jr = fCoord->GetFirstYBin(); jr <= fCoord->GetLastYBin(); ++jr) {
162  for (Int_t kr = fCoord->GetFirstZBin(); kr <= fCoord->GetLastZBin(); ++kr) {
163  fMinMaxVal.second = TMath::Max(fMinMaxVal.second, h->GetBinContent(ir, jr, kr));
164  fMinMaxVal.first = TMath::Min(fMinMaxVal.first, h->GetBinContent(ir, jr, kr));
165  }
166  }
167  }
168  }
169 
170  if (fCoord->Modified()) {
171  fUpdateSelection = kTRUE;
172  fCoord->ResetModified();
173  }
174 
175  return kTRUE;
176 }
177 
178 ////////////////////////////////////////////////////////////////////////////////
179 ///Move plot or box cut.
180 
182 {
183  fMousePosition.fX = px;
184  fMousePosition.fY = fCamera->GetHeight() - py;
185  fCamera->StartPan(px, py);
186  fBoxCut.StartMovement(px, fCamera->GetHeight() - py);
187 }
188 
189 ////////////////////////////////////////////////////////////////////////////////
190 /// User's moving mouse cursor, with middle mouse button pressed (for pad).
191 /// Calculate 3d shift related to 2d mouse movement.
192 
194 {
195  if (fSelectedPart >= fSelectionBase) {//Pan camera.
196  SaveModelviewMatrix();
197  SaveProjectionMatrix();
198 
199  fCamera->SetCamera();
200  fCamera->Apply(fPadPhi, fPadTheta);
201  fCamera->Pan(px, py);
202 
203  RestoreProjectionMatrix();
204  RestoreModelviewMatrix();
205  } else if (fSelectedPart > 0) {
206  //Convert py into bottom-top orientation.
207  //Possibly, move box here
208  py = fCamera->GetHeight() - py;
209  SaveModelviewMatrix();
210  SaveProjectionMatrix();
211 
212  fCamera->SetCamera();
213  fCamera->Apply(fPadPhi, fPadTheta);
214 
215  if (!fHighColor) {
216  if (fBoxCut.IsActive() && (fSelectedPart >= kXAxis && fSelectedPart <= kZAxis))
217  fBoxCut.MoveBox(px, py, fSelectedPart);
218  }
219 
220  RestoreProjectionMatrix();
221  RestoreModelviewMatrix();
222  }
223 
224  fMousePosition.fX = px, fMousePosition.fY = py;
225  fUpdateSelection = kTRUE;
226 }
227 
228 ////////////////////////////////////////////////////////////////////////////////
229 ///No options for composition.
230 
232 {
233 }
234 
235 ////////////////////////////////////////////////////////////////////////////////
236 ///Switch on/off box cut.
237 
239 {
240  if (event == kButton1Double && fBoxCut.IsActive()) {
241  fBoxCut.TurnOnOff();
242  if (!gVirtualX->IsCmdThread())
243  gROOT->ProcessLineFast(Form("((TGLPlotPainter *)0x%lx)->Paint()", (ULong_t)this));
244  else
245  Paint();
246  } else if (event == kKeyPress && (py == kKey_c || py == kKey_C)) {
247  if (fHighColor)
248  Info("ProcessEvent", "Switch to true color mode to use box cut");
249  else {
250  fBoxCut.TurnOnOff();
251  fUpdateSelection = kTRUE;
252  }
253  }
254 }
255 
256 ////////////////////////////////////////////////////////////////////////////////
257 /// Initialize some gl state variables.
258 
260 {
261  glEnable(GL_DEPTH_TEST);
262  glEnable(GL_LIGHTING);
263  glEnable(GL_LIGHT0);
264  glEnable(GL_CULL_FACE);
265  glCullFace(GL_BACK);
266 
267  glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
268 }
269 
270 ////////////////////////////////////////////////////////////////////////////////
271 ///Return back some gl state variables.
272 
274 {
275  glDisable(GL_DEPTH_TEST);
276  glDisable(GL_LIGHTING);
277  glDisable(GL_LIGHT0);
278  glDisable(GL_CULL_FACE);
279  glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
280 }
281 
282 ////////////////////////////////////////////////////////////////////////////////
283 ///Draw composition of TH3s.
284 
286 {
287  //Shift plot to point of origin.
288  const Rgl::PlotTranslation trGuard(this);
289 
290  fBackBox.DrawBox(fSelectedPart, fSelectionPass, fZLevels, fHighColor);
291 
292  if (!fSelectionPass) {
293  glEnable(GL_POLYGON_OFFSET_FILL);//[0
294  glPolygonOffset(1.f, 1.f);
295  } else
296  return;
297 
298  //Using front point, find the correct order to draw boxes from
299  //back to front/from bottom to top (it's important only for semi-transparent boxes).
300  const Int_t frontPoint = fBackBox.GetFrontPoint();
301  Int_t irInit = fCoord->GetFirstXBin(), iInit = 0;
302  const Int_t nX = fCoord->GetNXBins();
303  Int_t jrInit = fCoord->GetFirstYBin(), jInit = 0;
304  const Int_t nY = fCoord->GetNYBins();
305  Int_t krInit = fCoord->GetFirstZBin(), kInit = 0;
306  const Int_t nZ = fCoord->GetNZBins();
307 
308  const Int_t addI = frontPoint == 2 || frontPoint == 1 ? 1 : (iInit = nX - 1, irInit = fCoord->GetLastXBin(), -1);
309  const Int_t addJ = frontPoint == 2 || frontPoint == 3 ? 1 : (jInit = nY - 1, jrInit = fCoord->GetLastYBin(), -1);
310  const Int_t addK = fBackBox.Get2DBox()[frontPoint + 4].Y() < fBackBox.Get2DBox()[frontPoint].Y() ? 1
311  : (kInit = nZ - 1, krInit = fCoord->GetLastZBin(),-1);
312  const Double_t xScale = fCoord->GetXScale();
313  const Double_t yScale = fCoord->GetYScale();
314  const Double_t zScale = fCoord->GetZScale();
315  const TAxis *xA = fXAxis;
316  const TAxis *yA = fYAxis;
317  const TAxis *zA = fZAxis;
318 
319  Double_t maxContent = TMath::Max(TMath::Abs(fMinMaxVal.first), TMath::Abs(fMinMaxVal.second));
320  if(!maxContent)//bad, find better way to check zero.
321  maxContent = 1.;
322 
323  for (UInt_t hNum = 0; hNum < fData->fHists.size(); ++hNum) {
324  const TH3 *h = fData->fHists[hNum].first;
325  const TGLTH3Composition::ETH3BinShape shape = fData->fHists[hNum].second;
326  SetColor(h->GetFillColor());
327 
328  for(Int_t ir = irInit, i = iInit; addI > 0 ? i < nX : i >= 0; ir += addI, i += addI) {
329  for(Int_t jr = jrInit, j = jInit; addJ > 0 ? j < nY : j >= 0; jr += addJ, j += addJ) {
330  for(Int_t kr = krInit, k = kInit; addK > 0 ? k < nZ : k >= 0; kr += addK, k += addK) {
331  const Double_t binContent = h->GetBinContent(ir, jr, kr);
332  const Double_t w = TMath::Abs(binContent) / maxContent;
333  if (!w)
334  continue;
335 
336  const Double_t xMin = xScale * (xA->GetBinLowEdge(ir) / 2 + xA->GetBinUpEdge(ir) / 2 - w * xA->GetBinWidth(ir) / 2);
337  const Double_t xMax = xScale * (xA->GetBinLowEdge(ir) / 2 + xA->GetBinUpEdge(ir) / 2 + w * xA->GetBinWidth(ir) / 2);
338  const Double_t yMin = yScale * (yA->GetBinLowEdge(jr) / 2 + yA->GetBinUpEdge(jr) / 2 - w * yA->GetBinWidth(jr) / 2);
339  const Double_t yMax = yScale * (yA->GetBinLowEdge(jr) / 2 + yA->GetBinUpEdge(jr) / 2 + w * yA->GetBinWidth(jr) / 2);
340  const Double_t zMin = zScale * (zA->GetBinLowEdge(kr) / 2 + zA->GetBinUpEdge(kr) / 2 - w * zA->GetBinWidth(kr) / 2);
341  const Double_t zMax = zScale * (zA->GetBinLowEdge(kr) / 2 + zA->GetBinUpEdge(kr) / 2 + w * zA->GetBinWidth(kr) / 2);
342 
343  if (fBoxCut.IsActive() && fBoxCut.IsInCut(xMin, xMax, yMin, yMax, zMin, zMax))
344  continue;
345 
346  if (shape == TGLTH3Composition::kSphere)
347  Rgl::DrawSphere(&fQuadric, xMin, xMax, yMin, yMax, zMin, zMax);
348  else
349  Rgl::DrawBoxFront(xMin, xMax, yMin, yMax, zMin, zMax, frontPoint);
350  }
351  }
352  }
353  }
354 
355  if (fBoxCut.IsActive())
356  fBoxCut.DrawBox(fSelectionPass, fSelectedPart);
357 
358  glDisable(GL_POLYGON_OFFSET_FILL);//0]
359  const TGLDisableGuard lightGuard(GL_LIGHTING);//[2 - 2]
360  glColor4d(0., 0., 0., 0.25);
361  glPolygonMode(GL_FRONT, GL_LINE);//[3
362 
363  const TGLEnableGuard blendGuard(GL_BLEND);//[4-4] + 1]
364  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
365  const TGLEnableGuard smoothGuard(GL_LINE_SMOOTH);//[5-5]
366  glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
367 
368  for (UInt_t hNum = 0; hNum < fData->fHists.size(); ++hNum) {
369  if (fData->fHists[hNum].second == TGLTH3Composition::kSphere)
370  continue;//No outlines for spherical bins.
371 
372  const TH3 *h = fData->fHists[hNum].first;
373 
374  for(Int_t ir = irInit, i = iInit; addI > 0 ? i < nX : i >= 0; ir += addI, i += addI) {
375  for(Int_t jr = jrInit, j = jInit; addJ > 0 ? j < nY : j >= 0; jr += addJ, j += addJ) {
376  for(Int_t kr = krInit, k = kInit; addK > 0 ? k < nZ : k >= 0; kr += addK, k += addK) {
377  const Double_t w = TMath::Abs(h->GetBinContent(ir, jr, kr)) / maxContent;
378  if (!w)
379  continue;
380 
381  const Double_t xMin = xScale * (xA->GetBinLowEdge(ir) / 2 + xA->GetBinUpEdge(ir) / 2 - w * xA->GetBinWidth(ir) / 2);
382  const Double_t xMax = xScale * (xA->GetBinLowEdge(ir) / 2 + xA->GetBinUpEdge(ir) / 2 + w * xA->GetBinWidth(ir) / 2);
383  const Double_t yMin = yScale * (yA->GetBinLowEdge(jr) / 2 + yA->GetBinUpEdge(jr) / 2 - w * yA->GetBinWidth(jr) / 2);
384  const Double_t yMax = yScale * (yA->GetBinLowEdge(jr) / 2 + yA->GetBinUpEdge(jr) / 2 + w * yA->GetBinWidth(jr) / 2);
385  const Double_t zMin = zScale * (zA->GetBinLowEdge(kr) / 2 + zA->GetBinUpEdge(kr) / 2 - w * zA->GetBinWidth(kr) / 2);
386  const Double_t zMax = zScale * (zA->GetBinLowEdge(kr) / 2 + zA->GetBinUpEdge(kr) / 2 + w * zA->GetBinWidth(kr) / 2);
387 
388  if (fBoxCut.IsActive() && fBoxCut.IsInCut(xMin, xMax, yMin, yMax, zMin, zMax))
389  continue;
390 
391  Rgl::DrawBoxFront(xMin, xMax, yMin, yMax, zMin, zMax, frontPoint);
392  }
393  }
394  }
395  }
396 
397  glPolygonMode(GL_FRONT, GL_FILL);//3]
398 }
399 
400 ////////////////////////////////////////////////////////////////////////////////
401 ///Set material.
402 
404 {
405  Float_t diffColor[] = {0.8f, 0.8f, 0.8f, 0.05f};
406 
407  if (color != kWhite)
408  if (const TColor *c = gROOT->GetColor(color))
409  c->GetRGB(diffColor[0], diffColor[1], diffColor[2]);
410 
411  glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffColor);
412  const Float_t specColor[] = {1.f, 1.f, 1.f, 1.f};
413  glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specColor);
414  glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 70.f);
415 }
416 
417 namespace {
418 
419 ////////////////////////////////////////////////////////////////////////////////
420 
421 void AxisError(const TString & errorMsg)
422 {
423  Error("TGLTH3Composition::AddTH3", "%s", errorMsg.Data());
424  throw std::runtime_error(errorMsg.Data());
425 }
426 
427 ////////////////////////////////////////////////////////////////////////////////
428 ///Check number of bins.
429 
430 void CompareAxes(const TAxis *a1, const TAxis *a2, const TString &axisName)
431 {
432  if (a1->GetNbins() != a2->GetNbins())
433  AxisError("New hist has different number of bins along " + axisName);
434 
435  //Check bin ranges.
436  const Int_t firstBin1 = a1->GetFirst(), lastBin1 = a1->GetLast();
437  const Int_t firstBin2 = a2->GetFirst(), lastBin2 = a2->GetLast();
438 
439  if (firstBin1 != firstBin2)
440  AxisError("New hist has different first bin along " + axisName);
441 
442  if (lastBin1 != lastBin2)
443  AxisError("New hist has different last bin along " + axisName);
444 
445  const Double_t eps = 1e-7;//?????:((((
446  //Check axes ranges.
447  if (TMath::Abs(a1->GetBinLowEdge(firstBin1) - a2->GetBinLowEdge(firstBin2)) > eps)
448  AxisError("New hist has different low edge along " + axisName);
449  if (TMath::Abs(a1->GetBinUpEdge(lastBin1) - a2->GetBinUpEdge(lastBin2)) > eps)
450  AxisError("New hist has different low edge along " + axisName);
451 }
452 
453 }
Camera for TGLPlotPainter and sub-classes.
Definition: TGLPlotCamera.h:21
void Pan(Int_t px, Int_t py)
User&#39;s moving mouse cursor, with middle mouse button pressed (for pad).
Int_t GetFirst() const
Return first bin on the axis i.e.
Definition: TAxis.cxx:444
float Float_t
Definition: RtypesCore.h:53
const char Option_t
Definition: RtypesCore.h:62
virtual Double_t GetBinLowEdge(Int_t bin) const
Return low edge of bin.
Definition: TAxis.cxx:504
TH1 * h
Definition: legend2.C:5
virtual Int_t GetNbinsZ() const
Definition: TH1.h:279
#define gROOT
Definition: TROOT.h:375
Basic string class.
Definition: TString.h:129
Short_t Min(Short_t a, Short_t b)
Definition: TMathBase.h:168
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
virtual Double_t GetBinContent(Int_t bin) const
Return content of bin number bin.
Definition: TH3.h:91
void DeInitGL() const
Return back some gl state variables.
Short_t Abs(Short_t d)
Definition: TMathBase.h:108
void ProcessEvent(Int_t event, Int_t px, Int_t py)
Switch on/off box cut.
virtual Double_t GetBinUpEdge(Int_t bin) const
Return up edge of bin.
Definition: TAxis.cxx:514
Int_t DistancetoPrimitive(Int_t px, Int_t py)
Check if "this" is under cursor.
void StartPan(Int_t px, Int_t py)
Move plot or box cut.
void DrawPlot() const
Draw composition of TH3s.
void Info(const char *location, const char *msgfmt,...)
char * GetObjectInfo(Int_t px, Int_t py) const
I cannot show bin content in a status bar - since there can be several bins in one.
void Error(const char *location, const char *msgfmt,...)
The 3-D histogram classes derived from the 1-D histogram classes.
Definition: TH3.h:31
void Paint(Option_t *option)
Paint a composition of 3d hists.
Definition: Rtypes.h:55
void DrawBoxFront(Double_t xMin, Double_t xMax, Double_t yMin, Double_t yMax, Double_t zMin, Double_t zMax, Int_t fp)
Draws lego&#39;s bar as a 3d box.
Definition: TGLUtil.cxx:2974
Int_t GetLast() const
Return last bin on the axis i.e.
Definition: TAxis.cxx:455
Class to manage histogram axis.
Definition: TAxis.h:30
Helper class for plot-painters holding information about axis ranges, numbers of bins and flags if ce...
unsigned int UInt_t
Definition: RtypesCore.h:42
char * Form(const char *fmt,...)
TAxis * GetYaxis()
Definition: TH1.h:301
Base class for plot-painters that provide GL rendering of various 2D and 3D histograms, functions and parametric surfaces.
#define gVirtualX
Definition: TVirtualX.h:350
const Bool_t kFALSE
Definition: RtypesCore.h:92
std::pair< const TH3 *, ETH3BinShape > TH3Pair_t
#define ClassImp(name)
Definition: Rtypes.h:336
double f(double x)
double Double_t
Definition: RtypesCore.h:55
void SetColor(Int_t color) const
Set material.
unsigned long ULong_t
Definition: RtypesCore.h:51
virtual Color_t GetFillColor() const
Return the fill area color.
Definition: TAttFill.h:30
you should not use this method at all Int_t Int_t Double_t Double_t Double_t e
Definition: TRolke.cxx:630
The color creation and management class.
Definition: TColor.h:19
TAxis * GetZaxis()
Definition: TH1.h:302
void DrawSphere(TGLQuadric *quadric, Double_t xMin, Double_t xMax, Double_t yMin, Double_t yMax, Double_t zMin, Double_t zMax)
Cylinder for lego3.
Definition: TGLUtil.cxx:3242
The histogram painter class using OpenGL.
void ExecuteEvent(Int_t event, Int_t px, Int_t py)
Mouse and keyboard events.
void InitGL() const
Initialize some gl state variables.
void AddOption(const TString &option)
No options for composition.
virtual Double_t GetBinWidth(Int_t bin) const
Return bin width.
Definition: TAxis.cxx:526
char * GetPlotInfo(Int_t px, Int_t py)
Will be never called from TPad.
Short_t Max(Short_t a, Short_t b)
Definition: TMathBase.h:200
void AddTH3(const TH3 *hist, ETH3BinShape shape=kBox)
Add TH3 into collection.
virtual Int_t GetNbinsX() const
Definition: TH1.h:277
Int_t GetNbins() const
Definition: TAxis.h:121
virtual void Set(Int_t nbins, Double_t xmin, Double_t xmax)
Initialize axis with fix bins.
Definition: TAxis.cxx:717
const Bool_t kTRUE
Definition: RtypesCore.h:91
TAxis * GetXaxis()
Definition: TH1.h:300
virtual Int_t GetNbinsY() const
Definition: TH1.h:278
const char * Data() const
Definition: TString.h:347