Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TGLSurfacePainter.cxx
Go to the documentation of this file.
1 // @(#)root/gl:$Id$
2 // Author: Timur Pocheptsov 31/08/2006
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2006, 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 <algorithm>
13 #include "Riostream.h"
14 #include <cstdlib>
15 #include <cctype>
16 
17 #include "TVirtualPad.h"
18 #include "KeySymbols.h"
19 #include "TVirtualGL.h"
20 #include "TVirtualX.h"
21 #include "Buttons.h"
22 #include "TString.h"
23 #include "TStyle.h"
24 #include "TGaxis.h"
25 #include "TColor.h"
26 #include "TROOT.h"
27 #include "TMath.h"
28 #include "TAxis.h"
29 #include "TH1.h"
30 #include "TRandom.h"
31 
32 #include "TGLSurfacePainter.h"
33 #include "TGLPlotCamera.h"
34 #include "TGLIncludes.h"
35 
36 /** \class TGLSurfacePainter
37 \ingroup opengl
38 Implements painting of TH2 with "SURF" option.
39 */
40 
41 ClassImp(TGLSurfacePainter);
42 
43 TRandom *TGLSurfacePainter::fgRandom = new TRandom(0);
44 
45 ////////////////////////////////////////////////////////////////////////////////
46 /// Constructor.
47 
48 void TGLSurfacePainter::Projection_t::Swap(Projection_t &rhs)
49 {
50  fRGBA[0] = rhs.fRGBA[0], fRGBA[1] = rhs.fRGBA[1], fRGBA[2] = rhs.fRGBA[2], fRGBA[3] = rhs.fRGBA[3];
51  fVertices.swap(rhs.fVertices);
52 }
53 
54 ////////////////////////////////////////////////////////////////////////////////
55 /// Constructor.
56 
57 TGLSurfacePainter::TGLSurfacePainter(TH1 *hist, TGLPlotCamera *camera, TGLPlotCoordinates *coord)
58  : TGLPlotPainter(hist, camera, coord, kTRUE, kTRUE, kTRUE),
59  fType(kSurf),
60  fSectionPass(kFALSE),
61  fUpdateTexMap(kTRUE)
62 {
63 }
64 
65 ////////////////////////////////////////////////////////////////////////////////
66 ///Coords for point on surface under cursor.
67 
68 char *TGLSurfacePainter::GetPlotInfo(Int_t px, Int_t py)
69 {
70  static char null[] = { "" };
71  if (fSelectedPart) {
72  if (fHighColor)
73  return fSelectedPart < fSelectionBase ? (char *)"TF2" : (char *)"Switch to true-color mode to obtain correct info";
74  return fSelectedPart < fSelectionBase ? (char *)"TF2" : WindowPointTo3DPoint(px, py);
75  }
76  return null;
77 }
78 
79 ////////////////////////////////////////////////////////////////////////////////
80 ///Set mesh, normals.
81 
82 Bool_t TGLSurfacePainter::InitGeometry()
83 {
84  Bool_t ret = kFALSE;
85  switch (fCoord->GetCoordType()) {
86  case kGLCartesian:
87  ret = InitGeometryCartesian(); break;
88  case kGLPolar:
89  ret = InitGeometryPolar(); break;
90  case kGLCylindrical:
91  ret = InitGeometryCylindrical(); break;
92  case kGLSpherical:
93  ret = InitGeometrySpherical(); break;
94  default:
95  return kFALSE;
96  }
97  if (ret && fCamera) fCamera->SetViewVolume(fBackBox.Get3DBox());
98  return ret;
99 }
100 
101 ////////////////////////////////////////////////////////////////////////////////
102 ///User clicks right mouse button (in a pad).
103 
104 void TGLSurfacePainter::StartPan(Int_t px, Int_t py)
105 {
106  fMousePosition.fX = px;
107  fMousePosition.fY = fCamera->GetHeight() - py;
108  fCamera->StartPan(px, py);
109  fBoxCut.StartMovement(px, fCamera->GetHeight() - py);
110 }
111 
112 ////////////////////////////////////////////////////////////////////////////////
113 ///User's moving mouse cursor, with middle mouse button pressed (for pad).
114 ///Calculate 3d shift related to 2d mouse movement.
115 
116 void TGLSurfacePainter::Pan(Int_t px, Int_t py)
117 {
118  if (fSelectedPart >= fSelectionBase) {//Pan camera.
119  SaveModelviewMatrix();
120  SaveProjectionMatrix();
121 
122  fCamera->SetCamera();
123  fCamera->Apply(fPadPhi, fPadTheta);
124  fCamera->Pan(px, py);
125 
126  RestoreProjectionMatrix();
127  RestoreModelviewMatrix();
128  } else if (fSelectedPart > 0) {
129  //Convert py into bottom-top orientation.
130  py = fCamera->GetHeight() - py;
131 
132  SaveModelviewMatrix();
133  SaveProjectionMatrix();
134 
135  fCamera->SetCamera();
136  fCamera->Apply(fPadPhi, fPadTheta);
137 
138 
139  if (!fHighColor) {
140  if (fBoxCut.IsActive() && (fSelectedPart >= kXAxis && fSelectedPart <= kZAxis))
141  fBoxCut.MoveBox(px, py, fSelectedPart);
142  else
143  MoveSection(px, py);
144  }
145  else
146  MoveSection(px, py);
147 
148  RestoreProjectionMatrix();
149  RestoreModelviewMatrix();
150  }
151 
152  fMousePosition.fX = px, fMousePosition.fY = py;
153  fUpdateSelection = kTRUE;
154 }
155 
156 ////////////////////////////////////////////////////////////////////////////////
157 ///Additional options for surfaces.
158 
159 void TGLSurfacePainter::AddOption(const TString &option)
160 {
161  using namespace std;
162  const Ssiz_t surfPos = option.Index("surf");//"surf" _already_ _exists_ in a string.
163  if (surfPos + 4 < option.Length() && isdigit(option[surfPos + 4])) {
164  switch (option[surfPos + 4] - '0') {
165  case 1:
166  fType = kSurf1;
167  break;
168  case 2:
169  fType = kSurf2;
170  break;
171  case 3:
172  fType = kSurf3;
173  fCoord->SetCoordType(kGLCartesian);
174  break;
175  case 4:
176  fType = kSurf4;
177  break;
178  case 5:
179  if (fCoord->GetCoordType() != kGLSpherical && fCoord->GetCoordType() != kGLCylindrical)
180  fType = kSurf3;
181  else
182  fType = kSurf5;
183  break;
184  default:
185  fType = kSurf;
186  }
187  } else
188  fType = kSurf;
189 
190  option.Index("z") == kNPOS ? fDrawPalette = kFALSE : fDrawPalette = kTRUE;
191 }
192 
193 ////////////////////////////////////////////////////////////////////////////////
194 ///Remove all profiles/sections.
195 
196 void TGLSurfacePainter::ProcessEvent(Int_t event, Int_t /*px*/, Int_t py)
197 {
198  const TGLVertex3 *frame = fBackBox.Get3DBox();
199  if (py == kKey_P || py == kKey_p) {
200 
201  if (HasSections()) {
202  fSectionPass = kTRUE;
203  DrawSectionXOZ();
204  DrawSectionYOZ();
205  DrawSectionXOY();
206  fXOZSectionPos = frame[0].Y();
207  fYOZSectionPos = frame[0].X();
208  fXOYSectionPos = frame[0].Z();
209  fSectionPass = kFALSE;
210  }
211  } else if (event == kButton1Double && (HasSections() || HasProjections() || fBoxCut.IsActive())) {
212  fXOZSectionPos = frame[0].Y();
213  fYOZSectionPos = frame[0].X();
214  fXOYSectionPos = frame[0].Z();
215  fXOZProj.clear();
216  fYOZProj.clear();
217  fXOYProj.clear();
218  if (fBoxCut.IsActive())
219  fBoxCut.TurnOnOff();
220  if (!gVirtualX->IsCmdThread())
221  gROOT->ProcessLineFast(Form("((TGLPlotPainter *)0x%lx)->Paint()", (ULong_t)this));
222  else
223  Paint();
224  } else if (event == kKeyPress && (py == kKey_c || py == kKey_C)) {
225  if (fHighColor)
226  Info("ProcessEvent", "Switch to true color to use box cut");
227  else {
228  fBoxCut.TurnOnOff();
229  fUpdateSelection = kTRUE;
230  }
231  }
232 }
233 
234 ////////////////////////////////////////////////////////////////////////////////
235 ///Initialize some OpenGL state variables.
236 
237 void TGLSurfacePainter::InitGL()const
238 {
239  glEnable(GL_LIGHTING);
240  glEnable(GL_LIGHT0);
241  glEnable(GL_DEPTH_TEST);
242  glDisable(GL_CULL_FACE);
243  glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
244 }
245 
246 ////////////////////////////////////////////////////////////////////////////////
247 ///Initialize some OpenGL state variables.
248 
249 void TGLSurfacePainter::DeInitGL()const
250 {
251  glDisable(GL_LIGHTING);
252  glDisable(GL_LIGHT0);
253  glDisable(GL_DEPTH_TEST);
254  glDisable(GL_CULL_FACE);
255  glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
256 }
257 
258 
259 ////////////////////////////////////////////////////////////////////////////////
260 ///One normal per vertex;
261 ///this normal is average of
262 ///neighbouring triangles normals.
263 
264 void TGLSurfacePainter::SetNormals()
265 {
266  const Int_t nX = fCoord->GetNXBins();
267  const Int_t nY = fCoord->GetNYBins();
268 
269  fFaceNormals.resize((nX + 1) * (nY + 1));
270  fFaceNormals.assign(fFaceNormals.size(), std::pair<TGLVector3, TGLVector3>());
271  fFaceNormals.SetRowLen(nY + 1);
272 
273 
274  //first, calculate normal for each triangle face
275  for (Int_t i = 0; i < nX - 1; ++i) {
276  for (Int_t j = 0; j < nY - 1; ++j) {
277  //first "bottom-left" triangle
278  TMath::Normal2Plane(fMesh[i][j + 1].CArr(), fMesh[i][j].CArr(), fMesh[i + 1][j].CArr(),
279  fFaceNormals[i + 1][j + 1].first.Arr());
280  //second "top-right" triangle
281  TMath::Normal2Plane(fMesh[i + 1][j].CArr(), fMesh[i + 1][j + 1].CArr(), fMesh[i][j + 1].CArr(),
282  fFaceNormals[i + 1][j + 1].second.Arr());
283  }
284  }
285 
286  fAverageNormals.resize(nX * nY);
287  fAverageNormals.SetRowLen(nY);
288 
289  fAverageNormals.assign(fAverageNormals.size(), TGLVector3());
290  //second, calculate average normal for each vertex
291  for (Int_t i = 0; i < nX; ++i) {
292  for (Int_t j = 0; j < nY; ++j) {
293  TGLVector3 &norm = fAverageNormals[i][j];
294 
295  norm += fFaceNormals[i][j].second;
296  norm += fFaceNormals[i][j + 1].first;
297  norm += fFaceNormals[i][j + 1].second;
298  norm += fFaceNormals[i + 1][j].first;
299  norm += fFaceNormals[i + 1][j].second;
300  norm += fFaceNormals[i + 1][j + 1].first;
301 
302  if (!norm.X() && !norm.Y() && !norm.Z())
303  continue;
304 
305  norm.Normalise();
306  }
307  }
308 }
309 
310 ////////////////////////////////////////////////////////////////////////////////
311 ///Set color for surface.
312 
313 void TGLSurfacePainter::SetSurfaceColor()const
314 {
315  Float_t diffColor[] = {0.8f, 0.8f, 0.8f, 0.35f};
316 
317  if (fHist->GetFillColor() != kWhite && fType != kSurf1 && fType != kSurf2 && fType != kSurf5)
318  if (const TColor *c = gROOT->GetColor(fHist->GetFillColor()))
319  c->GetRGB(diffColor[0], diffColor[1], diffColor[2]);
320 
321  glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffColor);
322  const Float_t specColor[] = {1.f, 1.f, 1.f, 1.f};
323  glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specColor);
324  glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 70.f);
325 }
326 
327 ////////////////////////////////////////////////////////////////////////////////
328 ///Draw surf/surf1/surf2/surf4
329 
330 void TGLSurfacePainter::DrawPlot()const
331 {
332  //Shift plot to point of origin.
333  const Rgl::PlotTranslation trGuard(this);
334 
335  if (fCoord->GetCoordType() == kGLCartesian) {
336  fBackBox.DrawBox(fSelectedPart, fSelectionPass, fZLevels, fHighColor);
337  DrawSections();
338  if (!fSelectionPass)
339  DrawProjections();
340  }
341 
342  if (!fSelectionPass) {
343  SetSurfaceColor();
344  glEnable(GL_POLYGON_OFFSET_FILL);
345  glPolygonOffset(1.f, 1.f);
346 
347  if (HasSections() || HasProjections())
348  {
349  //Surface is semi-transparent during dynamic profiling
350  glEnable(GL_BLEND);
351  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
352  }
353 
354  }
355 
356  if (Textured() && !fSelectionPass) {
357  if (!PreparePalette()) {
358  fType = kSurf;
359  fDrawPalette = kFALSE;
360  }
361  else if (fType != kSurf3)
362  fPalette.EnableTexture(GL_MODULATE);
363  }
364 
365  const Int_t nX = fCoord->GetNXBins();
366  const Int_t nY = fCoord->GetNYBins();
367  const Int_t frontPoint = fBackBox.GetFrontPoint();
368  Int_t i = 0, firstJ = 0;
369  const Int_t addI = frontPoint == 2 || frontPoint == 1 ? i = 0, 1 : (i = nX - 2, -1);
370  const Int_t addJ = frontPoint == 2 || frontPoint == 3 ? firstJ = 0, 1 : (firstJ = nY - 2, -1);
371 
372  if (fHighColor && fSelectionPass)
373  Rgl::ObjectIDToColor(fSelectionBase, kTRUE);
374 
375  for (; addI > 0 ? i < nX - 1 : i >= 0; i += addI) {
376  for (Int_t j = firstJ; addJ > 0 ? j < nY - 1 : j >= 0; j += addJ) {
377  Int_t triNumber = 2 * i * (nY - 1) + j * 2 + fSelectionBase;
378 
379  Double_t xMin = TMath::Min(TMath::Min(fMesh[i][j + 1].X(), fMesh[i][j].X()), fMesh[i + 1][j].X());
380  Double_t xMax = TMath::Max(TMath::Max(fMesh[i][j + 1].X(), fMesh[i][j].X()), fMesh[i + 1][j].X());
381  Double_t yMin = TMath::Min(TMath::Min(fMesh[i][j + 1].Y(), fMesh[i][j].Y()), fMesh[i + 1][j].Y());
382  Double_t yMax = TMath::Max(TMath::Max(fMesh[i][j + 1].Y(), fMesh[i][j].Y()), fMesh[i + 1][j].Y());
383  Double_t zMin = TMath::Min(TMath::Min(fMesh[i][j + 1].Z(), fMesh[i][j].Z()), fMesh[i + 1][j].Z());
384  Double_t zMax = TMath::Max(TMath::Max(fMesh[i][j + 1].Z(), fMesh[i][j].Z()), fMesh[i + 1][j].Z());
385 
386  if (fBoxCut.IsActive() && fBoxCut.IsInCut(xMin, xMax, yMin, yMax, zMin, zMax))
387  continue;
388 
389  if (fSelectionPass && !fHighColor)
390  Rgl::ObjectIDToColor(triNumber, kFALSE);
391 
392  if ((fType == kSurf1 || fType == kSurf2 || fType == kSurf5) && !fSelectionPass)
393  Rgl::DrawFaceTextured(fMesh[i][j + 1], fMesh[i][j], fMesh[i + 1][j],
394  fTexMap[i][j + 1], fTexMap[i][j], fTexMap[i + 1][j],
395  fAverageNormals[i][j + 1], fAverageNormals[i][j],
396  fAverageNormals[i + 1][j]);
397  else
398  Rgl::DrawSmoothFace(fMesh[i][j + 1], fMesh[i][j], fMesh[i + 1][j],
399  fAverageNormals[i][j + 1], fAverageNormals[i][j],
400  fAverageNormals[i + 1][j]);
401 
402  ++triNumber;
403 
404  if (fSelectionPass && !fHighColor)
405  Rgl::ObjectIDToColor(triNumber, kFALSE);
406 
407  if ((fType == kSurf1 || fType == kSurf2 || fType == kSurf5) && !fSelectionPass)
408  Rgl::DrawFaceTextured(fMesh[i + 1][j], fMesh[i + 1][j + 1], fMesh[i][j + 1],
409  fTexMap[i + 1][j], fTexMap[i + 1][j + 1], fTexMap[i][j + 1],
410  fAverageNormals[i + 1][j], fAverageNormals[i + 1][j + 1],
411  fAverageNormals[i][j + 1]);
412  else
413  Rgl::DrawSmoothFace(fMesh[i + 1][j], fMesh[i + 1][j + 1], fMesh[i][j + 1],
414  fAverageNormals[i + 1][j], fAverageNormals[i + 1][j + 1],
415  fAverageNormals[i][j + 1]);
416  }
417  }
418 
419  if (!fSelectionPass)
420  glDisable(GL_POLYGON_OFFSET_FILL);
421 
422  if (fBoxCut.IsActive())
423  fBoxCut.DrawBox(fSelectionPass, fSelectedPart);
424 
425  if (fType != kSurf3 && Textured() && !fSelectionPass)
426  fPalette.DisableTexture();
427 
428  //Draw outlines here
429  if (!fSelectionPass) {
430  const TGLEnableGuard blendGuard(GL_BLEND);
431 
432  if (fType == kSurf || fType == kSurf1 || fType == kSurf3) {
433  const TGLDisableGuard lightGuard(GL_LIGHTING);
434  const TGLEnableGuard smoothGuard(GL_LINE_SMOOTH);
435 
436  glDepthMask(GL_FALSE);
437 
438  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
439  glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
440 
441  glColor4d(0., 0., 0., 0.5);
442 
443  for (i = 0; i < nX - 1; ++i) {
444  for (Int_t j = 0; j < nY - 1; ++j) {
445  Rgl::DrawQuadOutline(fMesh[i][j + 1], fMesh[i][j], fMesh[i + 1][j], fMesh[i + 1][j + 1]);
446  }
447  }
448 
449  glDepthMask(GL_TRUE);
450  }
451  }
452 
453  if (fType == kSurf3 && !fSelectionPass) {
454  fPalette.EnableTexture(GL_MODULATE);
455  const TGLEnableGuard blend(GL_BLEND);
456  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
457  DrawContoursProjection();
458  fPalette.DisableTexture();
459  }
460 
461  if (!fSelectionPass && fSelectedPart > 6) {
462  //Draw red outline for surface.
463  const TGLDisableGuard lightGuard(GL_LIGHTING);
464  const TGLEnableGuard blendGuard(GL_BLEND);
465  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
466  const TGLEnableGuard smoothGuard(GL_LINE_SMOOTH);
467  glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
468  glLineWidth(3.f);
469 
470  glColor4d(1.f, 0.f, 0.4f, 0.6f);
471  glBegin(GL_LINE_STRIP);
472  for (i = 0; i < nX; ++i)
473  glVertex3dv(fMesh[i][0].CArr());
474  for (Int_t j = 0; j < nY; ++j)
475  glVertex3dv(fMesh[nX - 1][j].CArr());
476  for (i = nX - 1; i >= 0; --i)
477  glVertex3dv(fMesh[i][nY - 1].CArr());
478  for (Int_t j = nY - 1; j >= 0; --j)
479  glVertex3dv(fMesh[0][j].CArr());
480  glEnd();
481  glLineWidth(1.f);
482  }
483 
484  if (!fSelectionPass && fDrawPalette)
485  DrawPalette();
486 }
487 
488 ////////////////////////////////////////////////////////////////////////////////
489 ///Find bin ranges for X and Y axes,
490 ///axes ranges for X, Y and Z.
491 ///Function returns false, if logarithmic scale for
492 ///some axis was requested, but we cannot
493 ///find correct range.
494 
495 Bool_t TGLSurfacePainter::InitGeometryCartesian()
496 {
497  if (!fCoord->SetRanges(fHist, kFALSE, kFALSE)) //the second arg must be drawErrors, the third is always kFALSE.
498  return kFALSE;
499 
500  fBackBox.SetPlotBox(fCoord->GetXRangeScaled(), fCoord->GetYRangeScaled(), fCoord->GetZRangeScaled());
501  //Set surface's mesh
502  //Calculates table of X and Y for lego (Z is obtained during drawing) or
503  //calculate mesh of triangles with vertices in the centres of bins
504  const Int_t nX = fCoord->GetNXBins();
505  const Int_t nY = fCoord->GetNYBins();
506 
507  fMesh.resize(nX * nY);
508  fMesh.SetRowLen(nY);
509 
510  for (Int_t i = 0, ir = fCoord->GetFirstXBin(); i < nX; ++i, ++ir) {
511  for (Int_t j = 0, jr = fCoord->GetFirstYBin(); j < nY; ++j, ++jr) {
512  fCoord->GetXLog() ? fMesh[i][j].X() = TMath::Log10(fXAxis->GetBinCenter(ir)) * fCoord->GetXScale()
513  : fMesh[i][j].X() = fXAxis->GetBinCenter(ir) * fCoord->GetXScale();
514  fCoord->GetYLog() ? fMesh[i][j].Y() = TMath::Log10(fYAxis->GetBinCenter(jr)) * fCoord->GetYScale()
515  : fMesh[i][j].Y() = fYAxis->GetBinCenter(jr) * fCoord->GetYScale();
516 
517  Double_t z = fHist->GetBinContent(ir, jr);
518  ClampZ(z);
519  fMesh[i][j].Z() = z;
520  }
521  }
522 
523  if (Textured()) {
524  fMinMaxVal.first = fHist->GetBinContent(fCoord->GetFirstXBin(), fCoord->GetFirstYBin());
525  fMinMaxVal.second = fMinMaxVal.first;
526 
527  for (Int_t i = fCoord->GetFirstXBin(), e = fCoord->GetLastXBin(); i <= e; ++i) {
528  for (Int_t j = fCoord->GetFirstYBin(), e1 = fCoord->GetLastYBin(); j <= e1; ++j) {
529  const Double_t val = fHist->GetBinContent(i, j);
530  fMinMaxVal.first = TMath::Min(fMinMaxVal.first, val);
531  fMinMaxVal.second = TMath::Max(fMinMaxVal.second, val);
532  }
533  }
534 
535  ClampZ(fMinMaxVal.first);
536  ClampZ(fMinMaxVal.second);
537 
538  fUpdateTexMap = kTRUE;
539  }
540 
541  SetNormals();
542 
543  if (fCoord->Modified()) {
544  fUpdateSelection = kTRUE;
545  const TGLVertex3 &vertex = fBackBox.Get3DBox()[0];
546  fXOZSectionPos = vertex.Y();
547  fYOZSectionPos = vertex.X();
548  fXOYSectionPos = vertex.Z();
549  fCoord->ResetModified();
550  Rgl::SetZLevels(fZAxis, fCoord->GetZRange().first, fCoord->GetZRange().second, fCoord->GetZScale(), fZLevels);
551  }
552 
553  return kTRUE;
554 }
555 
556 ////////////////////////////////////////////////////////////////////////////////
557 ///Find bin ranges for X and Y axes,
558 ///axes ranges for X, Y and Z.
559 ///Function returns false, if logarithmic scale for
560 ///some axis was requested, but we cannot
561 ///find correct range.
562 
563 Bool_t TGLSurfacePainter::InitGeometryPolar()
564 {
565  if (!fCoord->SetRanges(fHist, kFALSE, kFALSE))
566  return kFALSE;
567 
568  fBackBox.SetPlotBox(fCoord->GetXRangeScaled(), fCoord->GetYRangeScaled(), fCoord->GetZRangeScaled());
569 
570  if (fCoord->Modified()) {
571  fUpdateSelection = kTRUE;
572  const TGLVertex3 &vertex = fBackBox.Get3DBox()[0];
573  fXOZSectionPos = vertex.Y();
574  fYOZSectionPos = vertex.X();
575  fXOYSectionPos = vertex.Z();
576  fCoord->ResetModified();
577  }
578 
579  const Int_t nY = fCoord->GetNYBins();
580  const Int_t nX = fCoord->GetNXBins();
581 
582  fMesh.resize(nX * nY);
583  fMesh.SetRowLen(nY);
584 
585  const Double_t fullAngle = fXAxis->GetBinCenter(fXAxis->GetNbins()) - fXAxis->GetBinCenter(1);
586  const Double_t phiLow = fXAxis->GetBinCenter(1);
587  const Double_t rRange = fYAxis->GetBinCenter(fYAxis->GetNbins()) - fYAxis->GetBinCenter(1);
588 
589  for (Int_t i = 0, ir = fCoord->GetFirstXBin(); i < nX; ++i, ++ir) {
590  for (Int_t j = 0, jr = fCoord->GetFirstYBin(); j < nY; ++j, ++jr) {
591  const Double_t angle = (fXAxis->GetBinCenter(ir) - phiLow) / fullAngle * TMath::TwoPi();
592  const Double_t radius = ((fYAxis->GetBinCenter(jr)) - fYAxis->GetBinCenter(1)) /
593  rRange * fCoord->GetYScale();
594  fMesh[i][j].X() = radius * TMath::Cos(angle);
595  fMesh[i][j].Y() = radius * TMath::Sin(angle);
596  Double_t z = fHist->GetBinContent(ir, jr);
597  ClampZ(z);
598  fMesh[i][j].Z() = z;
599  }
600  }
601 
602  SetNormals();
603 
604  if (Textured()) {
605  fMinMaxVal.first = fHist->GetBinContent(fCoord->GetFirstXBin(), fCoord->GetFirstYBin());
606  fMinMaxVal.second = fMinMaxVal.first;
607 
608  for (Int_t i = fCoord->GetFirstXBin(), e = fCoord->GetLastXBin(); i <= e; ++i) {
609  for (Int_t j = fCoord->GetFirstYBin(), e1 = fCoord->GetLastYBin(); j <= e1; ++j) {
610  const Double_t val = fHist->GetBinContent(i, j);
611  fMinMaxVal.first = TMath::Min(fMinMaxVal.first, val);
612  fMinMaxVal.second = TMath::Max(fMinMaxVal.second, val);
613  }
614  }
615 
616  fUpdateTexMap = kTRUE;
617  }
618 
619 
620  return kTRUE;
621 }
622 
623 ////////////////////////////////////////////////////////////////////////////////
624 ///Find bin ranges for X and Y axes,
625 ///axes ranges for X, Y and Z.
626 ///Function returns false, if logarithmic scale for
627 ///some axis was requested, but we cannot
628 ///find correct range.
629 
630 Bool_t TGLSurfacePainter::InitGeometryCylindrical()
631 {
632  if (!fCoord->SetRanges(fHist, kFALSE, kFALSE))
633  return kFALSE;
634 
635  fBackBox.SetPlotBox(fCoord->GetXRangeScaled(), fCoord->GetYRangeScaled(), fCoord->GetZRangeScaled());
636 
637  if (fCoord->Modified()) {
638  fUpdateSelection = kTRUE;
639  const TGLVertex3 &vertex = fBackBox.Get3DBox()[0];
640  fXOZSectionPos = vertex.Y();
641  fYOZSectionPos = vertex.X();
642  fXOYSectionPos = vertex.Z();
643  fCoord->ResetModified();
644  }
645 
646  const Int_t nY = fCoord->GetNYBins();
647  const Int_t nX = fCoord->GetNXBins();
648  fMesh.resize(nX * nY);
649  fMesh.SetRowLen(nY);
650 
651  Double_t legoR = gStyle->GetLegoInnerR();
652  if (legoR > 1. || legoR < 0.)
653  legoR = 0.5;
654  const Double_t rRange = fCoord->GetZLength();
655  const Double_t sc = (1 - legoR) * fCoord->GetXScale();
656  legoR *= fCoord->GetXScale();
657 
658  const Double_t fullAngle = fXAxis->GetBinCenter(fXAxis->GetNbins()) - fXAxis->GetBinCenter(1);
659  const Double_t phiLow = fXAxis->GetBinCenter(1);
660  Double_t angle = 0.;
661 
662  for (Int_t i = 0, ir = fCoord->GetFirstXBin(); i < nX; ++i, ++ir) {
663  for (Int_t j = 0, jr = fCoord->GetFirstYBin(); j < nY; ++j, ++jr) {
664  angle = (fXAxis->GetBinLowEdge(ir) - phiLow) / fullAngle * TMath::TwoPi();
665  Double_t r = fType != kSurf5 ? legoR + (fHist->GetBinContent(ir, jr) - fCoord->GetZRange().first) / rRange * sc : legoR;
666  fMesh[i][j].X() = r * TMath::Cos(angle);
667  fMesh[i][j].Y() = fCoord->GetYLog() ?
668  TMath::Log10(fYAxis->GetBinCenter(jr)) * fCoord->GetYScale()
669  :
670  fYAxis->GetBinCenter(jr) * fCoord->GetYScale();
671  fMesh[i][j].Z() = r * TMath::Sin(angle);
672  }
673  }
674 
675  if (Textured()) {
676  fMinMaxVal.first = fHist->GetBinContent(fCoord->GetFirstXBin(), fCoord->GetFirstYBin());
677  fMinMaxVal.second = fMinMaxVal.first;
678 
679  for (Int_t i = fCoord->GetFirstXBin(), e = fCoord->GetLastXBin(); i <= e; ++i) {
680  for (Int_t j = fCoord->GetFirstYBin(), e1 = fCoord->GetLastYBin(); j <= e1; ++j) {
681  const Double_t val = fHist->GetBinContent(i, j);
682  fMinMaxVal.first = TMath::Min(fMinMaxVal.first, val);
683  fMinMaxVal.second = TMath::Max(fMinMaxVal.second, val);
684  }
685  }
686 
687  fUpdateTexMap = kTRUE;
688  }
689 
690 
691  SetNormals();
692 
693  return kTRUE;
694 }
695 
696 ////////////////////////////////////////////////////////////////////////////////
697 ///Find bin ranges for X and Y axes,
698 ///axes ranges for X, Y and Z.
699 ///Function returns false, if logarithmic scale for
700 ///some axis was requested, but we cannot
701 ///find correct range.
702 
703 Bool_t TGLSurfacePainter::InitGeometrySpherical()
704 {
705  if (!fCoord->SetRanges(fHist, kFALSE, kFALSE))
706  return kFALSE;
707 
708  fBackBox.SetPlotBox(fCoord->GetXRangeScaled(), fCoord->GetYRangeScaled(), fCoord->GetZRangeScaled());
709 
710  if (fCoord->Modified()) {
711  fUpdateSelection = kTRUE;
712  const TGLVertex3 &vertex = fBackBox.Get3DBox()[0];
713  fXOZSectionPos = vertex.Y();
714  fYOZSectionPos = vertex.X();
715  fXOYSectionPos = vertex.Z();
716  fCoord->ResetModified();
717  }
718 
719  const Int_t nY = fCoord->GetNYBins();
720  const Int_t nX = fCoord->GetNXBins();
721  fMesh.resize(nX * nY);
722  fMesh.SetRowLen(nY);
723 
724  Double_t legoR = gStyle->GetLegoInnerR();
725  if (legoR > 1. || legoR < 0.)
726  legoR = 0.5;
727  const Double_t rRange = fCoord->GetZLength();
728  const Double_t sc = (1 - legoR) * fCoord->GetXScale();
729  legoR *= fCoord->GetXScale();
730 
731  //0 <= theta <= 2 * pi
732  const Double_t fullTheta = fXAxis->GetBinCenter(fXAxis->GetNbins()) - fXAxis->GetBinCenter(1);
733  const Double_t thetaLow = fXAxis->GetBinCenter(1);
734  //0 <= phi <= pi
735  const Double_t fullPhi = fYAxis->GetBinCenter(fYAxis->GetNbins()) - fYAxis->GetBinCenter(1);
736  const Double_t phiLow = fYAxis->GetBinCenter(1);
737 
738  for (Int_t i = 0, ir = fCoord->GetFirstXBin(); i < nX; ++i, ++ir) {
739 
740  const Double_t theta = (fXAxis->GetBinCenter(ir) - thetaLow) / fullTheta * TMath::TwoPi();
741 
742  for (Int_t j = 0, jr = fCoord->GetFirstYBin(); j < nY; ++j, ++jr) {
743 
744  const Double_t phi = (fYAxis->GetBinCenter(jr) - phiLow) / fullPhi * TMath::Pi();
745  const Double_t r = fType != kSurf5 ? legoR + (fHist->GetBinContent(ir, jr) - fCoord->GetZRange().first) / rRange * sc
746  : legoR;
747 
748  fMesh[i][j].X() = r * TMath::Sin(phi) * TMath::Cos(theta);
749  fMesh[i][j].Y() = r * TMath::Sin(phi) * TMath::Sin(theta);
750  fMesh[i][j].Z() = r * TMath::Cos(phi);
751  }
752  }
753 
754  if (Textured()) {
755  fMinMaxVal.first = fHist->GetBinContent(fCoord->GetFirstXBin(), fCoord->GetFirstYBin());
756  fMinMaxVal.second = fMinMaxVal.first;
757 
758  for (Int_t i = fCoord->GetFirstXBin(), e = fCoord->GetLastXBin(); i <= e; ++i) {
759  for (Int_t j = fCoord->GetFirstYBin(), e1 = fCoord->GetLastYBin(); j <= e1; ++j) {
760  const Double_t val = fHist->GetBinContent(i, j);
761  fMinMaxVal.first = TMath::Min(fMinMaxVal.first, val);
762  fMinMaxVal.second = TMath::Max(fMinMaxVal.second, val);
763  }
764  }
765 
766  fUpdateTexMap = kTRUE;
767  }
768 
769 
770  SetNormals();
771 
772  return kTRUE;
773 }
774 
775 ////////////////////////////////////////////////////////////////////////////////
776 /// Draw projections.
777 
778 void TGLSurfacePainter::DrawProjections()const
779 {
780  const TGLDisableGuard lightGuard(GL_LIGHTING);
781  const TGLEnableGuard blendGuard(GL_BLEND);
782  const TGLEnableGuard lineSmooth(GL_LINE_SMOOTH);
783  glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
784  glDepthMask(GL_FALSE);
785  glLineWidth(3.f);
786 
787  typedef std::list<Projection_t>::const_iterator CLI_t;
788  for (CLI_t begin = fXOZProj.begin(), end = fXOZProj.end(); begin != end; ++begin) {
789  const Projection_t &proj = *begin;
790  glColor4ub(proj.fRGBA[0], proj.fRGBA[1], proj.fRGBA[2], proj.fRGBA[3]);
791 
792  for(UInt_t i = 0, e = proj.fVertices.size() / 3; i < e; ++i) {
793  glBegin(GL_LINE_STRIP);
794  glVertex3dv(proj.fVertices[i * 3].CArr());
795  glVertex3dv(proj.fVertices[i * 3 + 1].CArr());
796  glVertex3dv(proj.fVertices[i * 3 + 2].CArr());
797  glEnd();
798  }
799  const Double_t y = fBackBox.GetFrontPoint() == 2 || fBackBox.GetFrontPoint() == 3 ? fBackBox.Get3DBox()[0].Y() : fBackBox.Get3DBox()[2].Y();
800  for(UInt_t i = 0, e = proj.fVertices.size() / 3; i < e; ++i) {
801  glBegin(GL_LINE_STRIP);
802  const TGLVertex3 &v1 = proj.fVertices[i * 3];
803  glVertex3d(v1.X(), y, v1.Z());
804  const TGLVertex3 &v2 = proj.fVertices[i * 3 + 1];
805  glVertex3d(v2.X(), y, v2.Z());
806  const TGLVertex3 &v3 = proj.fVertices[i * 3 + 2];
807  glVertex3d(v3.X(), y, v3.Z());
808  glEnd();
809  }
810  }
811 
812  for (CLI_t begin = fYOZProj.begin(), end = fYOZProj.end(); begin != end; ++begin) {
813  const Projection_t &proj = *begin;
814  glColor4ub(proj.fRGBA[0], proj.fRGBA[1], proj.fRGBA[2], proj.fRGBA[3]);
815 
816  for(UInt_t i = 0, e = proj.fVertices.size() / 3; i < e; ++i) {
817  glBegin(GL_LINE_STRIP);
818  glVertex3dv(proj.fVertices[i * 3].CArr());
819  glVertex3dv(proj.fVertices[i * 3 + 1].CArr());
820  glVertex3dv(proj.fVertices[i * 3 + 2].CArr());
821  glEnd();
822  }
823 
824  const Double_t x = fBackBox.GetFrontPoint() == 2 || fBackBox.GetFrontPoint() == 1 ? fBackBox.Get3DBox()[0].X() : fBackBox.Get3DBox()[2].X();
825  for(UInt_t i = 0, e = proj.fVertices.size() / 3; i < e; ++i) {
826  glBegin(GL_LINE_STRIP);
827  const TGLVertex3 &v1 = proj.fVertices[i * 3];
828  glVertex3d(x, v1.Y(), v1.Z());
829  const TGLVertex3 &v2 = proj.fVertices[i * 3 + 1];
830  glVertex3d(x, v2.Y(), v2.Z());
831  const TGLVertex3 &v3 = proj.fVertices[i * 3 + 2];
832  glVertex3d(x, v3.Y(), v3.Z());
833  glEnd();
834  }
835  }
836 
837  for (CLI_t begin = fXOYProj.begin(), end = fXOYProj.end(); begin != end; ++begin) {
838  const Projection_t &proj = *begin;
839  glColor4ub(proj.fRGBA[0], proj.fRGBA[1], proj.fRGBA[2], proj.fRGBA[3]);
840 
841  for(UInt_t i = 0, e = proj.fVertices.size() / 2; i < e; ++i) {
842  glBegin(GL_LINES);
843  glVertex3dv(proj.fVertices[i * 2].CArr());
844  glVertex3dv(proj.fVertices[i * 2 + 1].CArr());
845  glEnd();
846  }
847 
848 
849  for(UInt_t i = 0, e = proj.fVertices.size() / 2; i < e; ++i) {
850  glBegin(GL_LINES);
851  const TGLVertex3 &v1 = proj.fVertices[i * 2];
852  glVertex3d(v1.X(), v1.Y(), fBackBox.Get3DBox()[0].Z());
853  const TGLVertex3 &v2 = proj.fVertices[i * 2 + 1];
854  glVertex3d(v2.X(), v2.Y(), fBackBox.Get3DBox()[0].Z());
855  glEnd();
856  }
857 
858  }
859 
860  glDepthMask(GL_TRUE);
861  glLineWidth(1.f);
862 }
863 
864 ////////////////////////////////////////////////////////////////////////////////
865 /// Draw section X.
866 
867 void TGLSurfacePainter::DrawSectionXOZ()const
868 {
869  using namespace std;
870  //XOZ parallel section.
871  Int_t binY = -1;
872  for (Int_t j = 0, e = fCoord->GetNYBins() - 1; j < e; ++j) {
873  if (fMesh[0][j].Y() <= fXOZSectionPos && fXOZSectionPos <= fMesh[0][j + 1].Y()) {
874  binY = j;
875  break;
876  }
877  }
878 
879  if (binY >= 0) {
880  //Draw 2d curve on the profile's plane.
881  const TGLPlane profilePlane(0., 1., 0., -fXOZSectionPos);
882 
883  if (!fSectionPass) {
884  glColor3d(1., 0., 0.);
885  glLineWidth(3.f);
886 
887  for (Int_t i = 0, e = fCoord->GetNXBins() - 1; i < e; ++i) {
888  glBegin(GL_LINE_STRIP);
889  glVertex3dv(Intersection(profilePlane, TGLLine3(fMesh[i + 1][binY], fMesh[i + 1][binY + 1]), kFALSE).second.CArr());
890  glVertex3dv(Intersection(profilePlane, TGLLine3(fMesh[i + 1][binY], fMesh[i][binY + 1]), kFALSE).second.CArr());
891  glVertex3dv(Intersection(profilePlane, TGLLine3(fMesh[i][binY], fMesh[i][binY + 1]), kFALSE).second.CArr());
892  glEnd();
893  }
894  glLineWidth(1.f);
895  } else {
896  fProj.fVertices.clear();
897  for (Int_t i = 0, e = fCoord->GetNXBins() - 1; i < e; ++i) {
898  fProj.fVertices.push_back(Intersection(profilePlane, TGLLine3(fMesh[i + 1][binY], fMesh[i + 1][binY + 1]), kFALSE).second);
899  fProj.fVertices.push_back(Intersection(profilePlane, TGLLine3(fMesh[i + 1][binY], fMesh[i][binY + 1]), kFALSE).second);
900  fProj.fVertices.push_back(Intersection(profilePlane, TGLLine3(fMesh[i][binY], fMesh[i][binY + 1]), kFALSE).second);
901  }
902  if (fProj.fVertices.size()) {
903  fProj.fRGBA[0] = (UChar_t) (50 + fgRandom->Integer(206));
904  fProj.fRGBA[1] = (UChar_t) fgRandom->Integer(150);
905  fProj.fRGBA[2] = (UChar_t) fgRandom->Integer(150);
906  fProj.fRGBA[3] = 150;
907  static Projection_t dummy;
908  fXOZProj.push_back(dummy);
909  fXOZProj.back().Swap(fProj);
910  }
911  }
912  }
913 }
914 
915 ////////////////////////////////////////////////////////////////////////////////
916 /// Draw section Y.
917 
918 void TGLSurfacePainter::DrawSectionYOZ()const
919 {
920  using namespace std;
921  //YOZ parallel section.
922  Int_t binX = -1;
923  for (Int_t i = 0, e = fCoord->GetNXBins() - 1; i < e; ++i) {
924  if (fMesh[i][0].X() <= fYOZSectionPos && fYOZSectionPos <= fMesh[i + 1][0].X()) {
925  binX = i;
926  break;
927  }
928  }
929 
930  if (binX >= 0) {
931  //Draw 2d curve on the profile's plane.
932  const TGLPlane profilePlane(1., 0., 0., -fYOZSectionPos);
933 
934  if (!fSectionPass) {
935  glColor3d(1., 0., 0.);
936  glLineWidth(3.f);
937  for (Int_t j = 0, e = fCoord->GetNYBins() - 1; j < e; ++j) {
938  glBegin(GL_LINE_STRIP);
939  glVertex3dv(Intersection(profilePlane, TGLLine3(fMesh[binX][j + 1], fMesh[binX + 1][j + 1]), kFALSE).second.CArr());
940  glVertex3dv(Intersection(profilePlane, TGLLine3(fMesh[binX][j + 1], fMesh[binX + 1][j]), kFALSE).second.CArr());
941  glVertex3dv(Intersection(profilePlane, TGLLine3(fMesh[binX][j], fMesh[binX + 1][j]), kFALSE).second.CArr());
942  glEnd();
943  }
944  glLineWidth(1.f);
945  } else {
946  fProj.fVertices.clear();
947  for (Int_t j = 0, e = fCoord->GetNYBins() - 1; j < e; ++j) {
948  fProj.fVertices.push_back(Intersection(profilePlane, TGLLine3(fMesh[binX][j + 1], fMesh[binX + 1][j + 1]), kFALSE).second);
949  fProj.fVertices.push_back(Intersection(profilePlane, TGLLine3(fMesh[binX][j + 1], fMesh[binX + 1][j]), kFALSE).second);
950  fProj.fVertices.push_back(Intersection(profilePlane, TGLLine3(fMesh[binX][j], fMesh[binX + 1][j]), kFALSE).second);
951  }
952  if (fProj.fVertices.size()) {
953  fProj.fRGBA[0] = (UChar_t) (50 + fgRandom->Integer(206));
954  fProj.fRGBA[1] = (UChar_t) fgRandom->Integer(150);
955  fProj.fRGBA[2] = (UChar_t) fgRandom->Integer(150);
956  fProj.fRGBA[3] = 150;
957  static Projection_t dummy;
958  fYOZProj.push_back(dummy);
959  fYOZProj.back().Swap(fProj);
960  }
961  }
962 
963  }
964 }
965 
966 ////////////////////////////////////////////////////////////////////////////////
967 /// Draw section Z.
968 
969 void TGLSurfacePainter::DrawSectionXOY()const
970 {
971  using namespace std;
972  //XOY parallel section.
973  const Int_t nX = fCoord->GetNXBins();
974  const Int_t nY = fCoord->GetNYBins();
975  const TGLPlane profilePlane(0., 0., 1., -fXOYSectionPos);
976  TGLVertex3 intersection[2];
977 
978 
979  if (fSectionPass)
980  fProj.fVertices.clear();
981  else {
982  glColor3d(1., 0., 0.);
983  glLineWidth(3.f);
984  }
985 
986  for (Int_t i = 0; i < nX - 1; ++i) {
987  for (Int_t j = 0; j < nY - 1; ++j) {
988  const TGLVertex3 &v1 = fMesh[i + 1][j], &v2 = fMesh[i][j], &v3 = fMesh[i][j + 1], &v4 = fMesh[i + 1][j + 1];
989  Double_t zMin = TMath::Min(TMath::Min(v1.Z(), v2.Z()), v3.Z());
990  Double_t zMax = TMath::Max(TMath::Max(v1.Z(), v2.Z()), v3.Z());
991 
992  if (zMin < fXOYSectionPos && zMax > fXOYSectionPos) {
993  Int_t np = 0;
994  if ((v1.Z() > fXOYSectionPos && v2.Z() < fXOYSectionPos) || (v2.Z() > fXOYSectionPos && v1.Z() < fXOYSectionPos)) {
995  TGLLine3 line(v1, v2);
996  intersection[np++] = Intersection(profilePlane, line, kFALSE).second;
997  }
998  if ((v2.Z() > fXOYSectionPos && v3.Z() < fXOYSectionPos) || (v3.Z() > fXOYSectionPos && v2.Z() < fXOYSectionPos)) {
999  TGLLine3 line(v2, v3);
1000  intersection[np++] = Intersection(profilePlane, line, kFALSE).second;
1001  }
1002  if ((np < 2 && v1.Z() > fXOYSectionPos && v3.Z() < fXOYSectionPos) || (v3.Z() > fXOYSectionPos && v1.Z() < fXOYSectionPos)) {
1003  TGLLine3 line(v1, v3);
1004  intersection[np++] = Intersection(profilePlane, line, kFALSE).second;
1005  }
1006  if (np > 1) {
1007  if (!fSectionPass) {
1008  glBegin(GL_LINES);
1009  glVertex3dv(intersection[0].CArr());
1010  glVertex3dv(intersection[1].CArr());
1011  glEnd();
1012  } else {
1013  fProj.fVertices.push_back(intersection[0]);
1014  fProj.fVertices.push_back(intersection[1]);
1015  }
1016  }
1017  }
1018  zMin = TMath::Min(v4.Z(), zMin);
1019  zMax = TMath::Max(v4.Z(), zMax);
1020  if (zMin < fXOYSectionPos && zMax > fXOYSectionPos) {
1021  Int_t np = 0;
1022  if ((v3.Z() > fXOYSectionPos && v4.Z() < fXOYSectionPos) || (v4.Z() > fXOYSectionPos && v3.Z() < fXOYSectionPos)) {
1023  TGLLine3 line(v3, v4);
1024  intersection[np++] = Intersection(profilePlane, line, kFALSE).second;
1025  }
1026  if ((v4.Z() > fXOYSectionPos && v1.Z() < fXOYSectionPos) || (v1.Z() > fXOYSectionPos && v4.Z() < fXOYSectionPos)) {
1027  TGLLine3 line(v4, v1);
1028  intersection[np++] = Intersection(profilePlane, line, kFALSE).second;
1029  }
1030  if ((np < 2 && v3.Z() > fXOYSectionPos && v1.Z() < fXOYSectionPos) || (v1.Z() > fXOYSectionPos && v3.Z() < fXOYSectionPos)) {
1031  TGLLine3 line(v3, v1);
1032  intersection[np++] = Intersection(profilePlane, line, kFALSE).second;
1033  }
1034  if (np > 1) {
1035  if (!fSectionPass) {
1036  glBegin(GL_LINES);
1037  glVertex3dv(intersection[0].CArr());
1038  glVertex3dv(intersection[1].CArr());
1039  glEnd();
1040  } else {
1041  fProj.fVertices.push_back(intersection[0]);
1042  fProj.fVertices.push_back(intersection[1]);
1043  }
1044  }
1045  }
1046  }
1047  }
1048 
1049  if (fSectionPass && fProj.fVertices.size()) {
1050  fProj.fRGBA[0] = (UChar_t) fgRandom->Integer(150);
1051  fProj.fRGBA[1] = (UChar_t) fgRandom->Integer(150);
1052  fProj.fRGBA[2] = (UChar_t) (50 + fgRandom->Integer(206));
1053  fProj.fRGBA[3] = 150;
1054  static Projection_t dummy;
1055  fXOYProj.push_back(dummy);
1056  fXOYProj.back().Swap(fProj);
1057  }
1058 
1059  if (!fSectionPass)
1060  glLineWidth(1.f);
1061 }
1062 
1063 ////////////////////////////////////////////////////////////////////////////////
1064 ///Clamp z value.
1065 
1066 void TGLSurfacePainter::ClampZ(Double_t &zVal)const
1067 {
1068  const TGLVertex3 *frame = fBackBox.Get3DBox();
1069 
1070  if (fCoord->GetZLog())
1071  if (zVal <= 0.)
1072  zVal = frame[0].Z();
1073  else
1074  zVal = TMath::Log10(zVal) * fCoord->GetZScale();
1075  else
1076  zVal *= fCoord->GetZScale();
1077 
1078  if (zVal > frame[4].Z())
1079  zVal = frame[4].Z();
1080  else if (zVal < frame[0].Z())
1081  zVal = frame[0].Z();
1082 }
1083 
1084 ////////////////////////////////////////////////////////////////////////////////
1085 ///Find 3d coords using mouse cursor coords.
1086 
1087 char *TGLSurfacePainter::WindowPointTo3DPoint(Int_t px, Int_t py)const
1088 {
1089  py = fCamera->GetHeight() - py;
1090 
1091  const Int_t nY = fCoord->GetNYBins() - 1;
1092  Int_t selected = fSelectedPart - (fSelectionBase - 1);
1093  Int_t k = selected / 2;
1094  Int_t i = k / nY;
1095  Int_t j = k % nY;
1096 
1097  const Bool_t odd = selected & 1;
1098  const TGLVertex3 &v1 = odd ? fMesh[i][j + 1] : fMesh[i + 1][j];
1099  const TGLVertex3 &v2 = odd ? fMesh[i + 1][j + 1] : fMesh[i][j];
1100  const TGLVertex3 &v3 = odd ? fMesh[i + 1][j] : fMesh[i][j + 1];
1101 
1102  TGLVertex3 winV1, winV2, winV3;
1103 
1104  Double_t mvMatrix[16] = {0.};
1105  glGetDoublev(GL_MODELVIEW_MATRIX, mvMatrix);
1106  Double_t prMatrix[16] = {0.};
1107  glGetDoublev(GL_PROJECTION_MATRIX, prMatrix);
1108  Int_t viewport[4] = {0};
1109  glGetIntegerv(GL_VIEWPORT, viewport);
1110 
1111  gluProject(v1.X(), v1.Y(), v1.Z(), mvMatrix, prMatrix, viewport, &winV1.X(), &winV1.Y(), &winV1.Z());
1112  gluProject(v2.X(), v2.Y(), v2.Z(), mvMatrix, prMatrix, viewport, &winV2.X(), &winV2.Y(), &winV2.Z());
1113  gluProject(v3.X(), v3.Y(), v3.Z(), mvMatrix, prMatrix, viewport, &winV3.X(), &winV3.Y(), &winV3.Z());
1114 
1115  Double_t planeABCD[4] = {0.};
1116  TMath::Normal2Plane(winV1.CArr(), winV2.CArr(), winV3.CArr(), planeABCD);
1117  planeABCD[3] = - winV1.X() * planeABCD[0] - winV1.Y() * planeABCD[1] - winV1.Z() * planeABCD[2];
1118  Double_t pz = (-planeABCD[3] - planeABCD[0] * px - planeABCD[1] * py) / planeABCD[2];
1119  Double_t rez[3] = {0.};
1120 
1121  gluUnProject(px, py, pz, mvMatrix, prMatrix, viewport, rez, rez + 1, rez + 2);
1122 
1123  fObjectInfo.Form("(x == %f, y == %f, z == %f)",
1124  rez[0] / fCoord->GetXScale(),
1125  rez[1] / fCoord->GetYScale(),
1126  rez[2] / fCoord->GetZScale());
1127 
1128  return (char *)fObjectInfo.Data();
1129 }
1130 
1131 ////////////////////////////////////////////////////////////////////////////////
1132 ///Generate palette.
1133 
1134 Bool_t TGLSurfacePainter::PreparePalette()const
1135 {
1136  if (!fUpdateTexMap)
1137  return kTRUE;
1138 
1139  if(fMinMaxVal.first == fMinMaxVal.second)
1140  return kFALSE;//must be std::abs(fMinMaxVal.second - fMinMaxVal.first) < ...
1141 
1142  //User-defined contours are disabled. To be fixed.
1143  if (fHist->TestBit(TH1::kUserContour))
1144  fHist->ResetBit(TH1::kUserContour);
1145 
1146  UInt_t paletteSize = gStyle->GetNumberContours();
1147  if (!paletteSize)
1148  paletteSize = 20;
1149 
1150  Bool_t rez = fPalette.GeneratePalette(paletteSize, fMinMaxVal);
1151 
1152  if (rez && fUpdateTexMap) {
1153  GenTexMap();
1154  fUpdateTexMap = kFALSE;
1155  }
1156 
1157  return rez;
1158 }
1159 
1160 ////////////////////////////////////////////////////////////////////////////////
1161 ///Find texture coordinates.
1162 
1163 void TGLSurfacePainter::GenTexMap()const
1164 {
1165  const Int_t nX = fCoord->GetNXBins();
1166  const Int_t nY = fCoord->GetNYBins();
1167 
1168  fTexMap.resize(nX * nY);
1169  fTexMap.SetRowLen(nY);
1170 
1171  for (Int_t i = 0, ir = fCoord->GetFirstXBin(); i < nX; ++i, ++ir) {
1172  for (Int_t j = 0, jr = fCoord->GetFirstYBin(); j < nY; ++j, ++jr) {
1173  Double_t z = fHist->GetBinContent(ir, jr);
1174  if (fCoord->GetCoordType() == kGLCartesian)
1175  ClampZ(z);
1176  fTexMap[i][j] = fPalette.GetTexCoord(z);
1177  }
1178  }
1179 }
1180 
1181 ////////////////////////////////////////////////////////////////////////////////
1182 ///Draw flat textured surface.
1183 
1184 void TGLSurfacePainter::DrawContoursProjection()const
1185 {
1186  static const Float_t whiteDiffuse[] = {0.8f, 0.8f, 0.8f, 0.65f};
1187  glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, whiteDiffuse);
1188  for (Int_t i = 0, ei = fCoord->GetNXBins() - 1; i < ei; ++i) {
1189  for (Int_t j = 0, ej = fCoord->GetNYBins() - 1; j < ej; ++j) {
1190  Rgl::DrawFaceTextured(fMesh[i][j + 1], fMesh[i][j], fMesh[i + 1][j],
1191  fTexMap[i][j + 1], fTexMap[i][j], fTexMap[i + 1][j],
1192  fBackBox.Get3DBox()[4].Z(), TGLVector3(0., 0., 1.));
1193  Rgl::DrawFaceTextured(fMesh[i + 1][j], fMesh[i + 1][j + 1], fMesh[i][j + 1],
1194  fTexMap[i + 1][j], fTexMap[i + 1][j + 1], fTexMap[i][j + 1],
1195  fBackBox.Get3DBox()[4].Z(), TGLVector3(0., 0., 1.));
1196  }
1197  }
1198 }
1199 
1200 ////////////////////////////////////////////////////////////////////////////////
1201 ///Checks, if surf requires texture.
1202 
1203 Bool_t TGLSurfacePainter::Textured()const
1204 {
1205  switch (fType) {
1206  case kSurf1:
1207  case kSurf2:
1208  case kSurf3:
1209  case kSurf5:
1210  return kTRUE;
1211  default:;
1212  }
1213 
1214  return kFALSE;
1215 }
1216 
1217 ////////////////////////////////////////////////////////////////////////////////
1218 ///Any section exists.
1219 
1220 Bool_t TGLSurfacePainter::HasSections()const
1221 {
1222  return fXOZSectionPos > fBackBox.Get3DBox()[0].Y() || fYOZSectionPos > fBackBox.Get3DBox()[0].X() ||
1223  fXOYSectionPos > fBackBox.Get3DBox()[0].Z();
1224 }
1225 
1226 ////////////////////////////////////////////////////////////////////////////////
1227 ///Any projection exists.
1228 
1229 Bool_t TGLSurfacePainter::HasProjections()const
1230 {
1231  return fXOZProj.size() || fYOZProj.size() || fXOYProj.size();
1232 }
1233 
1234 ////////////////////////////////////////////////////////////////////////////////
1235 ///Draw. Palette.
1236 ///Originally, fCamera was never null.
1237 ///It can be a null now because of gl-viewer.
1238 
1239 void TGLSurfacePainter::DrawPalette()const
1240 {
1241  if (!fCamera) {
1242  //Thank you, gl-viewer!
1243  return;
1244  }
1245 
1246  Rgl::DrawPalette(fCamera, fPalette);
1247 
1248  glFinish();
1249 
1250  fCamera->SetCamera();
1251  fCamera->Apply(fPadPhi, fPadTheta);
1252 }
1253 
1254 ////////////////////////////////////////////////////////////////////////////////
1255 ///Draw. Palette. Axis.
1256 
1257 void TGLSurfacePainter::DrawPaletteAxis()const
1258 {
1259  gVirtualX->SetDrawMode(TVirtualX::kCopy);//TCanvas by default sets in kInverse
1260  Rgl::DrawPaletteAxis(fCamera, fMinMaxVal, fCoord->GetCoordType() == kGLCartesian ? fCoord->GetZLog() : kFALSE);
1261 }