Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TGLVoxelPainter.cxx
Go to the documentation of this file.
1 #include <algorithm>
2 
3 #include "KeySymbols.h"
4 #include "TVirtualX.h"
5 #include "Buttons.h"
6 #include "TString.h"
7 #include "TROOT.h"
8 #include "TClass.h"
9 #include "TColor.h"
10 #include "TStyle.h"
11 #include "TH3.h"
12 #include "TF1.h"
13 
14 #include "TGLVoxelPainter.h"
15 #include "TGLPlotCamera.h"
16 #include "TGLIncludes.h"
17 
18 /** \class TGLVoxelPainter
19 \ingroup opengl
20 Paint TH3 histograms as "voxels" - colored boxes, transparent if transfer function was specified.
21 */
22 
23 ClassImp(TGLVoxelPainter);
24 
25 ////////////////////////////////////////////////////////////////////////////////
26 /// Constructor.
27 ///This plot always needs a palette.
28 
29 TGLVoxelPainter::TGLVoxelPainter(TH1 *hist, TGLPlotCamera *cam, TGLPlotCoordinates *coord)
30  : TGLPlotPainter(hist, cam, coord, kFALSE, kFALSE, kFALSE),
31  fTransferFunc(0)
32 {
33  fDrawPalette = kTRUE;
34 }
35 
36 
37 ////////////////////////////////////////////////////////////////////////////////
38 ///Show box info (i, j, k, binContent).
39 
40 char *TGLVoxelPainter::GetPlotInfo(Int_t, Int_t)
41 {
42  fPlotInfo = "";
43 
44  if (fSelectedPart) {
45  if (fSelectedPart < fSelectionBase) {
46  if (fHist->Class())
47  fPlotInfo += fHist->Class()->GetName();
48  fPlotInfo += "::";
49  fPlotInfo += fHist->GetName();
50  } else if (!fHighColor){
51  const Int_t arr2Dsize = fCoord->GetNYBins() * fCoord->GetNZBins();
52  const Int_t binI = (fSelectedPart - fSelectionBase) / arr2Dsize + fCoord->GetFirstXBin();
53  const Int_t binJ = (fSelectedPart - fSelectionBase) % arr2Dsize / fCoord->GetNZBins() + fCoord->GetFirstYBin();
54  const Int_t binK = (fSelectedPart - fSelectionBase) % arr2Dsize % fCoord->GetNZBins() + fCoord->GetFirstZBin();
55 
56  fPlotInfo.Form("(binx = %d; biny = %d; binz = %d; binc = %f)", binI, binJ, binK,
57  fHist->GetBinContent(binI, binJ, binK));
58  } else
59  fPlotInfo = "Switch to true color mode to get correct info";
60  }
61 
62  return (Char_t *)fPlotInfo.Data();
63 }
64 
65 
66 ////////////////////////////////////////////////////////////////////////////////
67 ///Set ranges, find min and max bin content.
68 
69 Bool_t TGLVoxelPainter::InitGeometry()
70 {
71  fCoord->SetZLog(kFALSE);
72  fCoord->SetYLog(kFALSE);
73  fCoord->SetXLog(kFALSE);
74 
75  if (!fCoord->SetRanges(fHist, kFALSE, kTRUE))//kFALSE == drawErrors, kTRUE == zAsBins
76  return kFALSE;
77 
78  fBackBox.SetPlotBox(fCoord->GetXRangeScaled(), fCoord->GetYRangeScaled(), fCoord->GetZRangeScaled());
79  if(fCamera) fCamera->SetViewVolume(fBackBox.Get3DBox());
80 
81  fMinMaxVal.second = fHist->GetBinContent(fCoord->GetFirstXBin(), fCoord->GetFirstYBin(), fCoord->GetFirstZBin());
82  fMinMaxVal.first = fMinMaxVal.second;
83  //Bad. You can up-date some bin value and get wrong picture.
84  for (Int_t ir = fCoord->GetFirstXBin(); ir <= fCoord->GetLastXBin(); ++ir) {
85  for (Int_t jr = fCoord->GetFirstYBin(); jr <= fCoord->GetLastYBin(); ++jr) {
86  for (Int_t kr = fCoord->GetFirstZBin(); kr <= fCoord->GetLastZBin(); ++kr) {
87  fMinMaxVal.second = TMath::Max(fMinMaxVal.second, fHist->GetBinContent(ir, jr, kr));
88  fMinMaxVal.first = TMath::Min(fMinMaxVal.first, fHist->GetBinContent(ir, jr, kr));
89  }
90  }
91  }
92 
93  if (fCoord->Modified()) {
94  fUpdateSelection = kTRUE;
95  fXOZSectionPos = fBackBox.Get3DBox()[0].Y();
96  fYOZSectionPos = fBackBox.Get3DBox()[0].X();
97  fXOYSectionPos = fBackBox.Get3DBox()[0].Z();
98  fCoord->ResetModified();
99  }
100 
101  const TList *funcList = fHist->GetListOfFunctions();
102  fTransferFunc = dynamic_cast<TF1*>(funcList->FindObject("TransferFunction"));
103 
104  return kTRUE;
105 }
106 
107 
108 ////////////////////////////////////////////////////////////////////////////////
109 /// User clicks right mouse button (in a pad).
110 
111 void TGLVoxelPainter::StartPan(Int_t px, Int_t py)
112 {
113  fMousePosition.fX = px;
114  fMousePosition.fY = fCamera->GetHeight() - py;
115  fCamera->StartPan(px, py);
116  fBoxCut.StartMovement(px, fCamera->GetHeight() - py);
117 }
118 
119 
120 ////////////////////////////////////////////////////////////////////////////////
121 /// User's moving mouse cursor, with middle mouse button pressed (for pad).
122 /// Calculate 3d shift related to 2d mouse movement.
123 
124 void TGLVoxelPainter::Pan(Int_t px, Int_t py)
125 {
126  // User's moving mouse cursor, with middle mouse button pressed (for pad).
127  // Calculate 3d shift related to 2d mouse movement.
128  if (fSelectedPart >= fSelectionBase) {//Pan camera.
129  SaveModelviewMatrix();
130  SaveProjectionMatrix();
131 
132  fCamera->SetCamera();
133  fCamera->Apply(fPadPhi, fPadTheta);
134  fCamera->Pan(px, py);
135 
136  RestoreProjectionMatrix();
137  RestoreModelviewMatrix();
138  } else if (fSelectedPart > 0) {
139  //Convert py into bottom-top orientation.
140  //Possibly, move box here
141  py = fCamera->GetHeight() - py;
142  SaveModelviewMatrix();
143  SaveProjectionMatrix();
144 
145  fCamera->SetCamera();
146  fCamera->Apply(fPadPhi, fPadTheta);
147 
148 
149  if (!fHighColor) {
150  if (fBoxCut.IsActive() && (fSelectedPart >= kXAxis && fSelectedPart <= kZAxis))
151  fBoxCut.MoveBox(px, py, fSelectedPart);
152  else
153  MoveSection(px, py);
154  } else {
155  MoveSection(px, py);
156  }
157 
158  RestoreProjectionMatrix();
159  RestoreModelviewMatrix();
160  }
161 
162  fMousePosition.fX = px, fMousePosition.fY = py;
163  fUpdateSelection = kTRUE;
164 }
165 
166 
167 ////////////////////////////////////////////////////////////////////////////////
168 /// "z" draw palette or not.
169 
170 void TGLVoxelPainter::AddOption(const TString &option)
171 {
172  option.Index("z") == kNPOS ? fDrawPalette = kFALSE : fDrawPalette = kTRUE;
173 
174 }
175 
176 ////////////////////////////////////////////////////////////////////////////////
177 /// Remove sections, switch on/off box cut.
178 
179 void TGLVoxelPainter::ProcessEvent(Int_t event, Int_t /*px*/, Int_t py)
180 {
181  if (event == kButton1Double && fBoxCut.IsActive()) {
182  if (fBoxCut.IsActive())
183  fBoxCut.TurnOnOff();
184  if (!gVirtualX->IsCmdThread())
185  gROOT->ProcessLineFast(Form("((TGLPlotPainter *)0x%lx)->Paint()", ULong_t(this)));
186  else
187  Paint();
188  } else if (event == kKeyPress && (py == kKey_c || py == kKey_C)) {
189  if (fHighColor)
190  Info("ProcessEvent", "Switch to true color mode to use box cut");
191  else {
192  fBoxCut.TurnOnOff();
193  fUpdateSelection = kTRUE;
194  }
195  }
196 }
197 
198 ////////////////////////////////////////////////////////////////////////////////
199 /// Initialize some gl state variables.
200 
201 void TGLVoxelPainter::InitGL()const
202 {
203  glEnable(GL_DEPTH_TEST);
204  glEnable(GL_LIGHTING);
205  glEnable(GL_LIGHT0);
206 
207  glEnable(GL_CULL_FACE);
208  glCullFace(GL_BACK);
209 
210  glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
211 }
212 
213 ////////////////////////////////////////////////////////////////////////////////
214 /// Return back some gl state variables.
215 
216 void TGLVoxelPainter::DeInitGL()const
217 {
218  glDisable(GL_DEPTH_TEST);
219  glDisable(GL_LIGHTING);
220  glDisable(GL_LIGHT0);
221  glDisable(GL_CULL_FACE);
222  glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
223 }
224 
225 ////////////////////////////////////////////////////////////////////////////////
226 /// Draw "voxels".
227 
228 void TGLVoxelPainter::DrawPlot()const
229 {
230  //Shift plot to point of origin.
231  const Rgl::PlotTranslation trGuard(this);
232 
233  if (!fSelectionPass)
234  PreparePalette();
235 
236  fBackBox.DrawBox(fSelectedPart, fSelectionPass, fZLevels, fHighColor);
237 
238  TGLDisableGuard depthTest(GL_DEPTH_TEST);
239 
240  if (!fSelectionPass) {
241  glEnable(GL_BLEND);//[1
242  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
243  }
244 
245  //Using front point, find the correct order to draw boxes from
246  //back to front/from bottom to top (it's important only for semi-transparent boxes).
247  const Int_t frontPoint = fBackBox.GetFrontPoint();
248  Int_t irInit = fCoord->GetFirstXBin(), iInit = 0;
249  const Int_t nX = fCoord->GetNXBins();
250  Int_t jrInit = fCoord->GetFirstYBin(), jInit = 0;
251  const Int_t nY = fCoord->GetNYBins();
252  Int_t krInit = fCoord->GetFirstZBin(), kInit = 0;
253  const Int_t nZ = fCoord->GetNZBins();
254 
255  const Int_t addI = frontPoint == 2 || frontPoint == 1 ? 1 : (iInit = nX - 1, irInit = fCoord->GetLastXBin(), -1);
256  const Int_t addJ = frontPoint == 2 || frontPoint == 3 ? 1 : (jInit = nY - 1, jrInit = fCoord->GetLastYBin(), -1);
257  const Int_t addK = fBackBox.Get2DBox()[frontPoint + 4].Y() > fBackBox.Get2DBox()[frontPoint].Y() ? 1
258  : (kInit = nZ - 1, krInit = fCoord->GetLastZBin(),-1);
259  const Double_t xScale = fCoord->GetXScale();
260  const Double_t yScale = fCoord->GetYScale();
261  const Double_t zScale = fCoord->GetZScale();
262  const TAxis *xA = fXAxis;
263  const TAxis *yA = fYAxis;
264  const TAxis *zA = fZAxis;
265 
266  if (fSelectionPass && fHighColor)
267  Rgl::ObjectIDToColor(fSelectionBase, fHighColor);//base + 1 == 7
268 
269  Double_t maxContent = TMath::Max(TMath::Abs(fMinMaxVal.first), TMath::Abs(fMinMaxVal.second));
270  if(!maxContent)//bad, find better way to check zero.
271  maxContent = 1.;
272 
273  Float_t rgba[4] = {};
274 
275  for(Int_t ir = irInit, i = iInit; addI > 0 ? i < nX : i >= 0; ir += addI, i += addI) {
276  for(Int_t jr = jrInit, j = jInit; addJ > 0 ? j < nY : j >= 0; jr += addJ, j += addJ) {
277 // for(Int_t kr = krInit, k = kInit; addK > 0 ? k < nZ : k >= 0; kr += addK, k += addK) {
278  for(Int_t kr = krInit, k = kInit; addK > 0 ? k < nZ : k >= 0; kr += addK, k += addK) {
279  const Double_t xMin = xScale * xA->GetBinLowEdge(ir);
280  const Double_t xMax = xScale * xA->GetBinUpEdge(ir);
281  const Double_t yMin = yScale * yA->GetBinLowEdge(jr);
282  const Double_t yMax = yScale * yA->GetBinUpEdge(jr);
283  const Double_t zMin = zScale * zA->GetBinLowEdge(kr);
284  const Double_t zMax = zScale * zA->GetBinUpEdge(kr);
285 
286  if (fBoxCut.IsActive() && fBoxCut.IsInCut(xMin, xMax, yMin, yMax, zMin, zMax))
287  continue;
288 
289  FindVoxelColor(fHist->GetBinContent(ir, jr, kr), rgba);
290 
291  if (rgba[3] < 0.01f)
292  continue;
293 
294  if (!fSelectionPass)
295  SetVoxelColor(rgba);
296 
297  const Int_t binID = fSelectionBase + i * fCoord->GetNZBins() * fCoord->GetNYBins() + j * fCoord->GetNZBins() + k;
298 
299  if (fSelectionPass && !fHighColor)
300  Rgl::ObjectIDToColor(binID, fHighColor);
301  else if(!fHighColor && fSelectedPart == binID)
302  glMaterialfv(GL_FRONT, GL_EMISSION, Rgl::gOrangeEmission);
303 
304  Rgl::DrawBoxFront(xMin, xMax, yMin, yMax, zMin, zMax, frontPoint);
305 
306  if (!fSelectionPass && !fHighColor && fSelectedPart == binID)
307  glMaterialfv(GL_FRONT, GL_EMISSION, Rgl::gNullEmission);
308  }
309  }
310  }
311 
312  if (fBoxCut.IsActive())
313  fBoxCut.DrawBox(fSelectionPass, fSelectedPart);
314 
315  if (!fSelectionPass) {
316  if (fDrawPalette)
317  DrawPalette();
318  glDisable(GL_BLEND);//1]
319  }
320 }
321 
322 ////////////////////////////////////////////////////////////////////////////////
323 /// Noop.
324 
325 void TGLVoxelPainter::DrawSectionXOZ()const
326 {
327 }
328 
329 ////////////////////////////////////////////////////////////////////////////////
330 /// Noop.
331 
332 void TGLVoxelPainter::DrawSectionYOZ()const
333 {
334 }
335 
336 
337 ////////////////////////////////////////////////////////////////////////////////
338 /// Noop.
339 
340 void TGLVoxelPainter::DrawSectionXOY()const
341 {
342 }
343 
344 ////////////////////////////////////////////////////////////////////////////////
345 ///Draw. Palette.
346 
347 void TGLVoxelPainter::DrawPalette()const
348 {
349  if (!fPalette.GetPaletteSize() || !fCamera)
350  return;
351 
352  if (!fHist->TestBit(TH1::kUserContour))
353  Rgl::DrawPalette(fCamera, fPalette);
354  else
355  Rgl::DrawPalette(fCamera, fPalette, fLevels);
356 
357  glFinish();
358 
359  fCamera->SetCamera();
360  fCamera->Apply(fPadPhi, fPadTheta);
361 }
362 
363 ////////////////////////////////////////////////////////////////////////////////
364 ///Draw. Palette. Axis.
365 
366 void TGLVoxelPainter::DrawPaletteAxis()const
367 {
368  if (fCamera) {
369  gVirtualX->SetDrawMode(TVirtualX::kCopy);//TCanvas by default sets in kInverse
370  Rgl::DrawPaletteAxis(fCamera, fMinMaxVal, kFALSE);
371  }
372 }
373 
374 ////////////////////////////////////////////////////////////////////////////////
375 ///Generate palette.
376 
377 void TGLVoxelPainter::PreparePalette()const
378 {
379  if(fMinMaxVal.first == fMinMaxVal.second)
380  return;//must be std::abs(fMinMaxVal.second - fMinMaxVal.first) < ...
381 
382  fLevels.clear();
383  UInt_t paletteSize = 0;
384 
385  if (fHist->TestBit(TH1::kUserContour)) {
386  if (const UInt_t trySize = fHist->GetContour()) {
387  fLevels.reserve(trySize);
388 
389  for (UInt_t i = 0; i < trySize; ++i) {
390  const Double_t level = fHist->GetContourLevel(Int_t(i));
391  if (level <= fMinMaxVal.first || level >= fMinMaxVal.second)
392  continue;
393  fLevels.push_back(level);
394  }
395  //sort levels
396  if (fLevels.size()) {
397  std::sort(fLevels.begin(), fLevels.end());
398  fLevels.push_back(fMinMaxVal.second);
399  fLevels.insert(fLevels.begin(), fMinMaxVal.first);
400  fPalette.SetContours(&fLevels);
401  paletteSize = fLevels.size() - 1;
402  }
403  }
404 
405  if (!paletteSize)
406  fHist->ResetBit(TH1::kUserContour);
407  }
408 
409  if (!paletteSize && !(paletteSize = gStyle->GetNumberContours()))
410  paletteSize = 20;
411 
412  fPalette.GeneratePalette(paletteSize, fMinMaxVal);
413 }
414 
415 ////////////////////////////////////////////////////////////////////////////////
416 /// Find box color.
417 
418 void TGLVoxelPainter::FindVoxelColor(Double_t binContent, Float_t *rgba)const
419 {
420  const UChar_t * tc = fPalette.GetColour(binContent);
421  rgba[3] = 0.06f; //Just a constant transparency.
422 
423 
424  if (fTransferFunc) {
425  rgba[3] = fTransferFunc->Eval(binContent);
426  }
427 
428  rgba[0] = tc[0] / 255.f;
429  rgba[1] = tc[1] / 255.f;
430  rgba[2] = tc[2] / 255.f;
431 }
432 
433 
434 ////////////////////////////////////////////////////////////////////////////////
435 /// Set box color.
436 
437 void TGLVoxelPainter::SetVoxelColor(const Float_t *diffColor)const
438 {
439  glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffColor);
440  const Float_t specColor[] = {1.f, 1.f, 1.f, 1.f};
441  glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specColor);
442  glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 70.f);
443 }