Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TGLHistPainter.cxx
Go to the documentation of this file.
1 // @(#)root/gl:$Id$
2 // Author: Timur Pocheptsov 17/11/2005
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2005, 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 <stdexcept>
13 #include <cstring>
14 
15 #include "TVirtualGL.h"
16 #include "KeySymbols.h"
17 #include "Buttons.h"
18 #include "TH2Poly.h"
19 #include "TClass.h"
20 #include "TROOT.h"
21 #include "TGL5D.h"
22 #include "TMath.h"
23 #include "TPad.h"
24 #include "TH3.h"
25 #include "TF3.h"
26 
27 #include "TGLSurfacePainter.h"
28 #include "TGLTH3Composition.h"
29 #include "TGLH2PolyPainter.h"
30 #include "TGLVoxelPainter.h"
31 #include "TGLHistPainter.h"
32 #include "TGLLegoPainter.h"
33 #include "TGLBoxPainter.h"
34 #include "TGLTF3Painter.h"
35 #include "TGLParametric.h"
36 #include "TGL5DPainter.h"
37 #include "TGLUtil.h"
38 
39 ClassImp(TGLHistPainter);
40 
41 /** \class TGLHistPainter
42 \ingroup opengl
43 The histogram painter class using OpenGL.
44 
45 Histograms are, by default, drawn via the `THistPainter` class.
46 `TGLHistPainter` allows to paint them using the OpenGL 3D graphics
47 library. The plotting options provided by `TGLHistPainter` start with
48 `GL` keyword.
49 
50 ### General information: plot types and supported options
51 
52 The following types of plots are provided:
53 
54 #### Lego - (`TGLLegoPainter`)
55  The supported options are:
56 
57  - `"GLLEGO" :` Draw a lego plot.
58  - `"GLLEGO2" :` Bins with color levels.
59  - `"GLLEGO3" :` Cylindrical bars.
60 
61  Lego painter in cartesian supports logarithmic scales for X, Y, Z.
62  In polar only Z axis can be logarithmic, in cylindrical only Y (if you see
63  what it means).
64 
65 
66 #### Surfaces (`TF2` and `TH2` with `"GLSURF"` options) - (`TGLSurfacePainter`)
67  The supported options are:
68 
69  - `"GLSURF" :` Draw a surface.
70  - `"GLSURF1" :` Surface with color levels
71  - `"GLSURF2" :` The same as `"GLSURF1"` but without polygon outlines.
72  - `"GLSURF3" :` Color level projection on top of plot (works only in cartesian coordinate system).
73  - `"GLSURF4" :` Same as `"GLSURF"` but without polygon outlines.
74 
75 
76  The surface painting in cartesian coordinates supports logarithmic scales along X, Y, Z axis.
77  In polar coordinates only the Z axis can be logarithmic, in cylindrical coordinates only the Y axis.
78 
79 #### Additional options to `SURF` and `LEGO` - Coordinate systems:
80  The supported options are:
81 
82  - `" " :` Default, cartesian coordinates system.
83  - `"POL" :` Polar coordinates system.
84  - `"CYL" :` Cylindrical coordinates system.
85  - `"SPH" :` Spherical coordinates system.
86 
87 
88 #### `TH3` as boxes (spheres) - (`TGLBoxPainter`)
89  The supported options are:
90 
91  - `"GLBOX" :` TH3 as a set of boxes, size of box is proportional to bin content.
92  - `"GLBOX1":` the same as "glbox", but spheres are drawn instead of boxes.
93 
94 
95 #### `TH3` as iso-surface(s) - (`TGLIsoPainter`)
96  The supported option is:
97 
98  - `"GLISO" :` TH3 is drawn using iso-surfaces.
99 
100 
101 #### `TH3` as color boxes - (`TGLVoxelPainter`)
102  The supported option is:
103 
104  - `"GLCOL" :` TH3 is drawn using semi-transparent colored boxes.
105  See `$ROOTSYS/tutorials/gl/glvox1.C`.
106 
107 
108 #### `TF3` (implicit function) - (`TGLTF3Painter`)
109  The supported option is:
110 
111  - `"GLTF3" :` Draw a `TF3`.
112 
113 
114 #### Parametric surfaces - (`TGLParametricPlot`)
115  `$ROOTSYS/tutorials/gl/glparametric.C` shows how to create parametric equations and
116  visualize the surface.
117 
118 
119 ### Interaction with the plots
120 
121 
122 #### General information.
123 
124  All the interactions are implemented via standard methods `DistancetoPrimitive` and
125  `ExecuteEvent`. That's why all the interactions with the OpenGL plots are possible i
126  only when the mouse cursor is in the plot's area (the plot's area is the part of a the pad
127  occupied by gl-produced picture). If the mouse cursor is not above gl-picture,
128  the standard pad interaction is performed.
129 
130 #### Selectable parts.
131 
132  Different parts of the plot can be selected:
133 
134  - *xoz, yoz, xoy back planes*:
135  When such a plane selected, it's highlighted in green if the dynamic slicing
136  by this plane is supported, and it's highlighted in red, if the dynamic slicing
137  is not supported.
138  -*The plot itself*:
139  On surfaces, the selected surface is outlined in red. (TF3 and ISO are not
140  outlined). On lego plots, the selected bin is highlihted. The bin number and content are displayed in pad's status
141  bar. In box plots, the box or sphere is highlighted and the bin info is displayed in pad's status bar.
142 
143 #### Rotation and zooming.
144 
145  - *Rotation*:
146 
147  When the plot is selected, it can be rotated by pressing and holding the left mouse button and move the cursor.
148  - *Zoom/Unzoom*:
149 
150  Mouse wheel or `'j'`, `'J'`, `'k'`, `'K'` keys.
151 
152 
153 #### Panning.
154 
155  The selected plot can be moved in a pad's area by
156  pressing and holding the left mouse button and the shift key.
157 
158 ### Box cut
159  Surface, iso, box, TF3 and parametric painters support box cut by pressing the `'c'` or
160  `'C'` key when the mouse cursor is in a plot's area. That will display a transparent box,
161  cutting away part of the surface (or boxes) in order to show internal part of plot.
162  This box can be moved inside the plot's area (the full size of the box is equal to the plot's
163  surrounding box) by selecting one of the box cut axes and pressing the left mouse button to move it.
164 
165 ### Plot specific interactions (dynamic slicing etc.)
166  Currently, all gl-plots support some form of slicing.
167  When back plane is selected (and if it's highlighted in green)
168  you can press and hold left mouse button and shift key
169  and move this back plane inside plot's area, creating the slice.
170  During this "slicing" plot becomes semi-transparent. To remove all slices (and projected curves for surfaces)
171  - double click with left mouse button in a plot's area.
172 
173  #### Surface with option `"GLSURF"`
174 
175  The surface profile is displayed on the slicing plane.
176  The profile projection is drawn on the back plane
177  by pressing `'p'` or `'P'` key.
178 
179  #### TF3
180 
181  The contour plot is drawn on the slicing plane.
182  For `TF3` the color scheme can be changed by pressing `'s'` or `'S'`.
183 
184  #### Box
185 
186  The contour plot corresponding to slice plane position is drawn in real time.
187 
188  #### Iso
189 
190  Slicing is similar to `"GLBOX"` option.
191 
192  #### Parametric plot
193 
194  No slicing. Additional keys: `'s'` or `'S'` to change color scheme - about 20 color schemes supported
195  (`'s'` for "scheme"); `'l'` or `'L'` to increase number of polygons (`'l'` for "level" of details),
196  `'w'` or `'W'` to show outlines (`'w'` for "wireframe").
197 */
198 
199 ////////////////////////////////////////////////////////////////////////////////
200 /// ROOT does not use exceptions, so, if default painter's creation failed,
201 /// fDefaultPainter is 0. In each function, which use it, I have to check the pointer first.
202 
203 TGLHistPainter::TGLHistPainter(TH1 *hist)
204  : fDefaultPainter(TVirtualHistPainter::HistPainter(hist)),
205  fEq(0),
206  fHist(hist),
207  fF3(0),
208  fStack(0),
209  fPlotType(kGLDefaultPlot)//THistPainter
210 {
211 }
212 
213 ////////////////////////////////////////////////////////////////////////////////
214 ///This ctor creates gl-parametric plot's painter.
215 
216 TGLHistPainter::TGLHistPainter(TGLParametricEquation *equation)
217  : fEq(equation),
218  fHist(0),
219  fF3(0),
220  fStack(0),
221  fPlotType(kGLParametricPlot)//THistPainter
222 {
223  fGLPainter.reset(new TGLParametricPlot(equation, &fCamera));
224 }
225 
226 ////////////////////////////////////////////////////////////////////////////////
227 ///This ctor creates plot painter for TGL5DDataSet.
228 
229 TGLHistPainter::TGLHistPainter(TGL5DDataSet *data)
230  : fEq(0),
231  fHist(0),
232  fF3(0),
233  fStack(0),
234  fPlotType(kGL5D)//THistPainter
235 {
236  fGLPainter.reset(new TGL5DPainter(data, &fCamera, &fCoord));
237 }
238 
239 ////////////////////////////////////////////////////////////////////////////////
240 ///This ctor creates plot painter for TGL5DDataSet.
241 
242 TGLHistPainter::TGLHistPainter(TGLTH3Composition *data)
243  : fEq(0),
244  fHist(data),
245  fF3(0),
246  fStack(0),
247  fPlotType(kGLTH3Composition)
248 {
249  fGLPainter.reset(new TGLTH3CompositionPainter(data, &fCamera, &fCoord));
250 }
251 
252 ////////////////////////////////////////////////////////////////////////////////
253 ///Selects plot or axis.
254 ///9999 is the magic number, ROOT's classes use in DistancetoPrimitive.
255 
256 Int_t TGLHistPainter::DistancetoPrimitive(Int_t px, Int_t py)
257 {
258  //[tp: return statement added.
259  //tp]
260 
261  if (fPlotType == kGLDefaultPlot)
262  return fDefaultPainter.get() ? fDefaultPainter->DistancetoPrimitive(px, py) : 9999;
263  else {
264  //Adjust px and py - canvas can have several pads inside, so we need to convert
265  //the from canvas' system into pad's.
266 
267  //Retina-related adjustments must be done inside!!!
268 
269  py = gPad->GetWh() - py;
270 
271  //One hist can be appended to several pads,
272  //the current pad should have valid OpenGL context.
273  const Int_t glContext = gPad->GetGLDevice();
274 
275  if (glContext != -1) {
276  //Add "viewport" extraction here.
277  PadToViewport(kTRUE);
278 
279  if (!gGLManager->PlotSelected(fGLPainter.get(), px, py))
280  gPad->SetSelected(gPad);
281  } else {
282  Error("DistancetoPrimitive",
283  "Attempt to use TGLHistPainter, while the current pad (gPad) does not support gl");
284  gPad->SetSelected(gPad);
285  }
286 
287  return 0;
288  }
289 }
290 
291 ////////////////////////////////////////////////////////////////////////////////
292 ///Default implementation is OK
293 ///This function is called from a context menu
294 ///after right click on a plot's area. Opens window
295 ///("panel") with several controls.
296 
297 void TGLHistPainter::DrawPanel()
298 {
299  if (fDefaultPainter.get())
300  fDefaultPainter->DrawPanel();
301 }
302 
303 ////////////////////////////////////////////////////////////////////////////////
304 ///Execute event.
305 ///Events are: mouse events in a plot's area,
306 ///key presses (while mouse cursor is in plot's area).
307 ///"Event execution" means one of the following actions:
308 /// 1. Rotation.
309 /// 2. Panning.
310 /// 3. Zoom changing.
311 /// 4. Moving dynamic profile.
312 /// 5. Plot specific events - for example, 's' or 'S' key press for TF3.
313 
314 void TGLHistPainter::ExecuteEvent(Int_t event, Int_t px, Int_t py)
315 {
316  if (fPlotType == kGLDefaultPlot) {
317  if(fDefaultPainter.get()) {
318  fDefaultPainter->ExecuteEvent(event, px, py);
319  }
320  } else {
321  //One hist can be appended to several pads,
322  //the current pad should have valid OpenGL context.
323  const Int_t glContext = gPad->GetGLDevice();
324 
325  if (glContext == -1) {
326  Error("ExecuteEvent",
327  "Attempt to use TGLHistPainter, while the current pad (gPad) does not support gl");
328  return;
329  } else {
330  //Add viewport extraction here.
331  /*fGLDevice.SetGLDevice(glContext);
332  fGLPainter->SetGLDevice(&fGLDevice);*/
333  PadToViewport();
334  }
335 
336  if (event != kKeyPress) {
337  //Adjust px and py - canvas can have several pads inside, so we need to convert
338  //the from canvas' system into pad's. If it was a key press event,
339  //px and py ARE NOT coordinates.
340  py -= Int_t((1 - gPad->GetHNDC() - gPad->GetYlowNDC()) * gPad->GetWh());
341  px -= Int_t(gPad->GetXlowNDC() * gPad->GetWw());
342 
343  //We also have to take care of retina displays with a different viewports.
344  TGLUtil::InitializeIfNeeded();
345  const Float_t scale = TGLUtil::GetScreenScalingFactor();
346  if (scale > 1) {
347  px *= scale;
348  py *= scale;
349  }
350  }
351 
352  switch (event) {
353  case kButton1Double:
354  //Left double click removes dynamic sections, user created (if plot type supports sections).
355  fGLPainter->ProcessEvent(event, px, py);
356  break;
357  case kButton1Down:
358  //Left mouse down in a plot area starts rotation.
359  if (!fGLPainter->CutAxisSelected())
360  fCamera.StartRotation(px, py);
361  else
362  fGLPainter->StartPan(px, py);
363  //During rotation, usual TCanvas/TPad machinery (CopyPixmap/Flush/UpdateWindow/etc.)
364  //is skipped - I use "bit blasting" functions to copy picture directly onto window.
365  //gGLManager->MarkForDirectCopy(glContext, kTRUE);
366  break;
367  case kButton1Motion:
368  //Rotation invalidates "selection buffer"
369  // - (color-to-object map, previously read from gl-buffer).
370  fGLPainter->InvalidateSelection();
371  if (fGLPainter->CutAxisSelected())
372  gGLManager->PanObject(fGLPainter.get(), px, py);
373  else
374  fCamera.RotateCamera(px, py);
375  //Draw modified scene onto canvas' window.
376  //gGLManager->PaintSingleObject(fGLPainter.get());
377  gPad->Update();
378  break;
379  case kButton1Up:
380  case kButton2Up:
381  gGLManager->MarkForDirectCopy(glContext, kFALSE);
382  break;
383  case kMouseMotion:
384  gPad->SetCursor(kRotate);
385  break;
386  case 7://kButton1Down + shift modifier
387  //The current version of ROOT does not
388  //have enumerators for button events + key modifiers,
389  //so I use hardcoded literals. :(
390  //With left mouse button down and shift pressed
391  //we can move plot as the whole or move
392  //plot's parts - dynamic sections.
393  fGLPainter->StartPan(px, py);
394  gGLManager->MarkForDirectCopy(glContext, kTRUE);
395  break;
396  case 8://kButton1Motion + shift modifier
397  gGLManager->PanObject(fGLPainter.get(), px, py);
398  //gGLManager->PaintSingleObject(fGLPainter.get());
399  gPad->Update();
400  break;
401  case kKeyPress:
402  case 5:
403  case 6:
404  //5, 6 are mouse wheel events (see comment about literals above).
405  //'p'/'P' - specific events processed by TGLSurfacePainter,
406  //'s'/'S' - specific events processed by TGLTF3Painter,
407  //'c'/'C' - turn on/off box cut.
408  gGLManager->MarkForDirectCopy(glContext, kTRUE);
409  if (event == 6 || py == kKey_J || py == kKey_j) {
410  fCamera.ZoomIn();
411  fGLPainter->InvalidateSelection();
412  //gGLManager->PaintSingleObject(fGLPainter.get());
413  gPad->Update();
414  } else if (event == 5 || py == kKey_K || py == kKey_k) {
415  fCamera.ZoomOut();
416  fGLPainter->InvalidateSelection();
417  //gGLManager->PaintSingleObject(fGLPainter.get());
418  gPad->Update();
419  } else if (py == kKey_p || py == kKey_P || py == kKey_S || py == kKey_s
420  || py == kKey_c || py == kKey_C || py == kKey_x || py == kKey_X
421  || py == kKey_y || py == kKey_Y || py == kKey_z || py == kKey_Z
422  || py == kKey_w || py == kKey_W || py == kKey_l || py == kKey_L
423  /*|| py == kKey_r || py == kKey_R*/)
424  {
425  fGLPainter->ProcessEvent(event, px, py);
426  //gGLManager->PaintSingleObject(fGLPainter.get());
427  gPad->Update();
428  }
429  gGLManager->MarkForDirectCopy(glContext, kFALSE);
430  break;
431  }
432  }
433 }
434 
435 ////////////////////////////////////////////////////////////////////////////////
436 ///Get contour list.
437 ///I do not use this function. Contours are implemented in
438 ///a completely different way by gl-painters.
439 
440 TList *TGLHistPainter::GetContourList(Double_t contour)const
441 {
442  return fDefaultPainter.get() ? fDefaultPainter->GetContourList(contour) : 0;
443 }
444 
445 ////////////////////////////////////////////////////////////////////////////////
446 ///Overrides TObject::GetObjectInfo.
447 ///For lego info is: bin numbers (i, j), bin content.
448 ///For TF2 info is: x,y,z 3d surface-point for 2d screen-point under cursor
449 ///(this can work incorrectly now, because of wrong code in TF2).
450 ///For TF3 no info now.
451 ///For box info is: bin numbers (i, j, k), bin content.
452 
453 char *TGLHistPainter::GetObjectInfo(Int_t px, Int_t py)const
454 {
455  static char errMsg[] = { "TGLHistPainter::GetObjectInfo: Error in a hist painter\n" };
456  if (fPlotType == kGLDefaultPlot)
457  return fDefaultPainter.get() ? fDefaultPainter->GetObjectInfo(px, py)
458  : errMsg;
459  else {
460  TGLUtil::InitializeIfNeeded();
461  const Float_t scale = TGLUtil::GetScreenScalingFactor();
462  if (scale > 1.f) {
463  px *= scale;
464  py *= scale;
465  }
466 
467  return gGLManager->GetPlotInfo(fGLPainter.get(), px, py);
468  }
469 }
470 
471 ////////////////////////////////////////////////////////////////////////////////
472 /// Get stack.
473 
474 TList *TGLHistPainter::GetStack()const
475 {
476  return fStack;
477 }
478 
479 ////////////////////////////////////////////////////////////////////////////////
480 ///Returns kTRUE if the cell ix, iy is inside one of the graphical cuts.
481 ///I do not use this function anywhere, this is a "default implementation".
482 
483 Bool_t TGLHistPainter::IsInside(Int_t x, Int_t y)
484 {
485  if (fPlotType == kGLDefaultPlot)
486  return fDefaultPainter.get() ? fDefaultPainter->IsInside(x, y) : kFALSE;
487 
488  return kFALSE;
489 }
490 
491 ////////////////////////////////////////////////////////////////////////////////
492 ///Returns kTRUE if the cell x, y is inside one of the graphical cuts.
493 ///I do not use this function anywhere, this is a "default implementation".
494 
495 Bool_t TGLHistPainter::IsInside(Double_t x, Double_t y)
496 {
497  if (fPlotType == kGLDefaultPlot)
498  return fDefaultPainter.get() ? fDefaultPainter->IsInside(x, y) : kFALSE;
499 
500  return kFALSE;
501 }
502 
503 ////////////////////////////////////////////////////////////////////////////////
504 ///Paint statistics.
505 ///This does not work on windows.
506 
507 void TGLHistPainter::PaintStat(Int_t dostat, TF1 *fit)
508 {
509  if (fDefaultPainter.get())
510  fDefaultPainter->PaintStat(dostat, fit);
511 }
512 
513 ////////////////////////////////////////////////////////////////////////////////
514 /// Process message.
515 
516 void TGLHistPainter::ProcessMessage(const char *m, const TObject *o)
517 {
518  if (!std::strcmp(m, "SetF3"))
519  fF3 = (TF3 *)o;
520 
521  if (fDefaultPainter.get())
522  fDefaultPainter->ProcessMessage(m, o);
523 }
524 
525 ////////////////////////////////////////////////////////////////////////////////
526 /// Set highlight mode
527 
528 void TGLHistPainter::SetHighlight()
529 {
530  if (fDefaultPainter.get())
531  fDefaultPainter->SetHighlight();
532 }
533 
534 ////////////////////////////////////////////////////////////////////////////////
535 /// Set histogram.
536 
537 void TGLHistPainter::SetHistogram(TH1 *h)
538 {
539  fHist = h;
540 
541  if (fDefaultPainter.get())
542  fDefaultPainter->SetHistogram(h);
543 }
544 
545 ////////////////////////////////////////////////////////////////////////////////
546 /// Set stack.
547 
548 void TGLHistPainter::SetStack(TList *s)
549 {
550  fStack = s;
551 
552  if (fDefaultPainter.get())
553  fDefaultPainter->SetStack(s);
554 }
555 
556 ////////////////////////////////////////////////////////////////////////////////
557 /// Make cuts.
558 
559 Int_t TGLHistPainter::MakeCuts(char *o)
560 {
561  if (fPlotType == kGLDefaultPlot && fDefaultPainter.get())
562  return fDefaultPainter->MakeCuts(o);
563 
564  return 0;
565 }
566 
567 struct TGLHistPainter::PlotOption_t {
568  EGLPlotType fPlotType;
569  EGLCoordType fCoordType;
570  Bool_t fBackBox;
571  Bool_t fFrontBox;
572  Bool_t fDrawAxes;
573  Bool_t fLogX;
574  Bool_t fLogY;
575  Bool_t fLogZ;
576 };
577 
578 ////////////////////////////////////////////////////////////////////////////////
579 ///Final-overrider for TObject::Paint.
580 
581 void TGLHistPainter::Paint(Option_t *o)
582 {
583  TString option(o);
584  option.ToLower();
585 
586  const Ssiz_t glPos = option.Index("gl");
587  if (glPos != kNPOS)
588  option.Remove(glPos, 2);
589  else if (fPlotType != kGLParametricPlot && fPlotType != kGL5D && fPlotType != kGLTH3Composition) {
590  gPad->SetCopyGLDevice(kFALSE);
591  if (fDefaultPainter.get())
592  fDefaultPainter->Paint(o);//option.Data());
593  return;
594  }
595 
596  if (fPlotType != kGLParametricPlot && fPlotType != kGL5D && fPlotType != kGLTH3Composition)
597  CreatePainter(ParsePaintOption(option), option);
598 
599  if (fPlotType == kGLDefaultPlot) {
600  //In case of default plot pad
601  //should not copy gl-buffer (it will be simply black)
602 
603  //[tp: code was commented.
604  //gPad->SetCopyGLDevice(kFALSE);
605  //tp]
606 
607  if (fDefaultPainter.get())
608  fDefaultPainter->Paint(option.Data());
609  } else {
610  Int_t glContext = gPad->GetGLDevice();
611 
612  if (glContext != -1) {
613  //With gl-plot, pad should copy
614  //gl-buffer into the final pad/canvas pixmap/DIB.
615  //fGLDevice.SetGLDevice(glContext);
616 
617  //[tp: code commented.
618  //gPad->SetCopyGLDevice(kTRUE);
619  //tp]
620  //fGLPainter->SetGLDevice(&fGLDevice);
621  //Add viewport extraction here.
622  PadToViewport();
623  if (gPad->GetFrameFillColor() != kWhite)
624  fGLPainter->SetFrameColor(gROOT->GetColor(gPad->GetFrameFillColor()));
625  fGLPainter->SetPadColor(gROOT->GetColor(gPad->GetFillColor()));
626  if (fGLPainter->InitGeometry())
627  gGLManager->PaintSingleObject(fGLPainter.get());
628  }
629  }
630 }
631 
632 namespace {
633 
634 Bool_t FindAndRemoveOption(TString &options, const char *toFind)
635 {
636  const UInt_t len = std::strlen(toFind);
637  const Ssiz_t index = options.Index(toFind);
638 
639  if (index != kNPOS) {
640  options.Remove(index, len);
641  return kTRUE;
642  }
643 
644  return kFALSE;
645 }
646 
647 }
648 
649 ////////////////////////////////////////////////////////////////////////////////
650 ///In principle, we can have several conflicting options: "lego surf pol sph", surfbb: surf, fb, bb.
651 ///but only one will be selected, which one - depends on parsing order in this function.
652 
653 TGLHistPainter::PlotOption_t
654 TGLHistPainter::ParsePaintOption(const TString &o)const
655 {
656  TString options(o);
657 
658  PlotOption_t parsedOption = {kGLDefaultPlot, kGLCartesian,
659  kTRUE, kTRUE, kTRUE, //Show back box, show front box, show axes.
660  Bool_t(gPad->GetLogx()), Bool_t(gPad->GetLogy()),
661  Bool_t(gPad->GetLogz())};
662 
663  //Check coordinate system type.
664  if (FindAndRemoveOption(options, "pol"))
665  parsedOption.fCoordType = kGLPolar;
666  if (FindAndRemoveOption(options, "cyl"))
667  parsedOption.fCoordType = kGLCylindrical;
668  if (FindAndRemoveOption(options, "sph"))
669  parsedOption.fCoordType = kGLSpherical;
670 
671  //Define plot type.
672  if (FindAndRemoveOption(options, "lego"))
673  fStack ? parsedOption.fPlotType = kGLStackPlot : parsedOption.fPlotType = kGLLegoPlot;
674  if (FindAndRemoveOption(options, "surf"))
675  parsedOption.fPlotType = kGLSurfacePlot;
676  if (FindAndRemoveOption(options, "tf3"))
677  parsedOption.fPlotType = kGLTF3Plot;
678  if (FindAndRemoveOption(options, "box"))
679  parsedOption.fPlotType = kGLBoxPlot;
680  if (FindAndRemoveOption(options, "iso"))
681  parsedOption.fPlotType = kGLIsoPlot;
682  if (FindAndRemoveOption(options, "col"))
683  parsedOption.fPlotType = kGLVoxel;
684 
685  //Check BB and FB options.
686  if (FindAndRemoveOption(options, "bb"))
687  parsedOption.fBackBox = kFALSE;
688  if (FindAndRemoveOption(options, "fb"))
689  parsedOption.fFrontBox = kFALSE;
690 
691  //Check A option.
692  if (FindAndRemoveOption(options, "a"))
693  parsedOption.fDrawAxes = kFALSE;
694 
695  return parsedOption;
696 }
697 
698 ////////////////////////////////////////////////////////////////////////////////
699 /// Create painter.
700 
701 void TGLHistPainter::CreatePainter(const PlotOption_t &option, const TString &addOption)
702 {
703  if (option.fPlotType != fPlotType) {
704  fCoord.ResetModified();
705  fGLPainter.reset(0);
706  }
707 
708  if (option.fPlotType == kGLLegoPlot) {
709  if (!fGLPainter.get()) {
710  if (dynamic_cast<TH2Poly*>(fHist))
711  fGLPainter.reset(new TGLH2PolyPainter(fHist, &fCamera, &fCoord));
712  else
713  fGLPainter.reset(new TGLLegoPainter(fHist, &fCamera, &fCoord));
714  }
715  } else if (option.fPlotType == kGLSurfacePlot) {
716  if (!fGLPainter.get())
717  fGLPainter.reset(new TGLSurfacePainter(fHist, &fCamera, &fCoord));
718  } else if (option.fPlotType == kGLBoxPlot) {
719  if (!fGLPainter.get())
720  fGLPainter.reset(new TGLBoxPainter(fHist, &fCamera, &fCoord));
721  } else if (option.fPlotType == kGLTF3Plot) {
722  if (!fGLPainter.get())
723  fGLPainter.reset(new TGLTF3Painter(fF3, fHist, &fCamera, &fCoord));
724  } else if (option.fPlotType == kGLIsoPlot) {
725  if (!fGLPainter.get())
726  fGLPainter.reset(new TGLIsoPainter(fHist, &fCamera, &fCoord));
727  } else if (option.fPlotType == kGLVoxel) {
728  if (!fGLPainter.get())
729  fGLPainter.reset(new TGLVoxelPainter(fHist, &fCamera, &fCoord));
730  }
731 
732  if (fGLPainter.get()) {
733  fPlotType = option.fPlotType;
734  fCoord.SetXLog(gPad->GetLogx());
735  fCoord.SetYLog(gPad->GetLogy());
736  fCoord.SetZLog(gPad->GetLogz());
737  fCoord.SetCoordType(option.fCoordType);
738  fGLPainter->AddOption(addOption);
739 
740  fGLPainter->SetDrawFrontBox(option.fFrontBox);
741  fGLPainter->SetDrawBackBox(option.fBackBox);
742  fGLPainter->SetDrawAxes(option.fDrawAxes);
743  } else
744  fPlotType = kGLDefaultPlot;
745 }
746 
747 ////////////////////////////////////////////////////////////////////////////////
748 /// Set show projection.
749 
750 void TGLHistPainter::SetShowProjection(const char *option, Int_t nbins)
751 {
752  if (fDefaultPainter.get()) fDefaultPainter->SetShowProjection(option, nbins);
753 }
754 
755 ////////////////////////////////////////////////////////////////////////////////
756 
757 void TGLHistPainter::PadToViewport(Bool_t /*selectionPass*/)
758 {
759  if (!fGLPainter.get())
760  return;
761 
762  TGLRect vp;
763  vp.Width() = Int_t(gPad->GetAbsWNDC() * gPad->GetWw());
764  vp.Height() = Int_t(gPad->GetAbsHNDC() * gPad->GetWh());
765 
766  vp.X() = Int_t(gPad->XtoAbsPixel(gPad->GetX1()));
767  vp.Y() = Int_t((gPad->GetWh() - gPad->YtoAbsPixel(gPad->GetY1())));
768 
769  TGLUtil::InitializeIfNeeded();
770  const Float_t scale = TGLUtil::GetScreenScalingFactor();
771 
772  if (scale > 1.f) {
773  vp.X() = Int_t(vp.X() * scale);
774  vp.Y() = Int_t(vp.Y() * scale);
775 
776  vp.Width() = Int_t(vp.Width() * scale);
777  vp.Height() = Int_t(vp.Height() * scale);
778  }
779 
780  fCamera.SetViewport(vp);
781  if (fCamera.ViewportChanged() && fGLPainter.get())
782  fGLPainter->InvalidateSelection();
783 }