// @(#)root/gl:$Id$ // Author: Timur Pocheptsov 14/06/2006 /************************************************************************* * Copyright (C) 1995-2004, Rene Brun and Fons Rademakers. * * All rights reserved. * * * * For the licensing terms see $ROOTSYS/LICENSE. * * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ #include #include #include "KeySymbols.h" #include "TVirtualX.h" #include "Buttons.h" #include "TString.h" #include "TColor.h" #include "TROOT.h" #include "TClass.h" #include "TStyle.h" #include "TAxis.h" #include "TMath.h" #include "TH1.h" #include "TGLLegoPainter.h" #include "TGLPlotCamera.h" #include "TGLIncludes.h" //______________________________________________________________________________ // // Plot-painter implementing LEGO rendering of TH2 histograms in // cartesian, polar, cylindrical and spherical coordinates. ClassImp(TGLLegoPainter) //______________________________________________________________________________ TGLLegoPainter::TGLLegoPainter(TH1 *hist, TGLPlotCamera *cam, TGLPlotCoordinates *coord) : TGLPlotPainter(hist, cam, coord, kFALSE, kTRUE, kTRUE), fLegoType(kColorSimple), fMinZ(0.), fDrawErrors(kFALSE) { //Ctor. } //______________________________________________________________________________ char *TGLLegoPainter::GetPlotInfo(Int_t /*px*/, Int_t /*py*/) { //Obtain bin's info (i, j, value). fBinInfo = ""; if (fSelectedPart) { if (fSelectedPart < fSelectionBase) { if (fHist->Class()) fBinInfo += fHist->Class()->GetName(); fBinInfo += "::"; fBinInfo += fHist->GetName(); } else if (!fHighColor) { const Int_t binI = (fSelectedPart - fSelectionBase) / fCoord->GetNYBins() + fCoord->GetFirstXBin(); const Int_t binJ = (fSelectedPart - fSelectionBase) % fCoord->GetNYBins() + fCoord->GetFirstYBin(); fBinInfo.Form("(binx = %d; biny = %d; binc = %f)", binI, binJ, fHist->GetBinContent(binI, binJ)); } else fBinInfo = "Switch to true-color mode to obtain correct info"; } return (Char_t *)fBinInfo.Data(); } //______________________________________________________________________________ Bool_t TGLLegoPainter::InitGeometry() { //Select method. Bool_t ret = kFALSE; switch (fCoord->GetCoordType()) { case kGLCartesian: ret = InitGeometryCartesian(); break; case kGLPolar: ret = InitGeometryPolar(); break; case kGLCylindrical: ret = InitGeometryCylindrical(); break; case kGLSpherical: ret = InitGeometrySpherical(); break; default: return kFALSE; } if (ret && fCamera) fCamera->SetViewVolume(fBackBox.Get3DBox()); return ret; } //______________________________________________________________________________ Bool_t TGLLegoPainter::InitGeometryCartesian() { //Geometry for lego in cartesian coords. if (!fCoord->SetRanges(fHist, fDrawErrors, kFALSE)) return kFALSE; fBackBox.SetPlotBox(fCoord->GetXRangeScaled(), fCoord->GetYRangeScaled(), fCoord->GetZRangeScaled()); //Find bin edges const Int_t nX = fCoord->GetNXBins(); const Double_t barWidth = fHist->GetBarWidth(), barOffset = fHist->GetBarOffset(); const TGLVertex3 *frame = fBackBox.Get3DBox(); fXEdges.resize(nX); if (fCoord->GetXLog()) { for (Int_t i = 0, ir = fCoord->GetFirstXBin(); i < nX; ++i, ++ir) { const Double_t xWidth = fXAxis->GetBinWidth(ir); Double_t low = fXAxis->GetBinLowEdge(ir) + xWidth * barOffset; fXEdges[i].first = TMath::Log10(low) * fCoord->GetXScale(); fXEdges[i].second = TMath::Log10(low + xWidth * barWidth) * fCoord->GetXScale(); if (fXEdges[i].second > frame[1].X()) fXEdges[i].second = frame[1].X(); if (fXEdges[i].first < frame[0].X()) fXEdges[i].first = frame[0].X(); if (fXEdges[i].second < frame[0].X()) fXEdges[i].second = frame[0].X(); } } else { for (Int_t i = 0, ir = fCoord->GetFirstXBin(); i < nX; ++i, ++ir) { const Double_t xWidth = fXAxis->GetBinWidth(ir); fXEdges[i].first = (fXAxis->GetBinLowEdge(ir) + xWidth * barOffset) * fCoord->GetXScale(); fXEdges[i].second = fXEdges[i].first + xWidth * barWidth * fCoord->GetXScale(); if (fXEdges[i].second > frame[1].X()) fXEdges[i].second = frame[1].X(); if (fXEdges[i].first < frame[0].X()) fXEdges[i].first = frame[0].X(); if (fXEdges[i].second < frame[0].X()) fXEdges[i].second = frame[0].X(); } } const Int_t nY = fCoord->GetNYBins(); fYEdges.resize(nY); if (fCoord->GetYLog()) { for (Int_t j = 0, jr = fCoord->GetFirstYBin(); j < nY; ++j, ++jr) { const Double_t yWidth = fYAxis->GetBinWidth(jr); Double_t low = fYAxis->GetBinLowEdge(jr) + yWidth * barOffset; fYEdges[j].first = TMath::Log10(low) * fCoord->GetYScale(); fYEdges[j].second = TMath::Log10(low + yWidth * barWidth) * fCoord->GetYScale(); if (fYEdges[j].second > frame[2].Y()) fYEdges[j].second = frame[2].Y(); if (fYEdges[j].first < frame[0].Y()) fYEdges[j].first = frame[0].Y(); if (fYEdges[j].second < frame[0].Y()) fYEdges[j].second = frame[0].Y(); } } else { for (Int_t j = 0, jr = fCoord->GetFirstYBin(); j < nY; ++j, ++jr) { const Double_t yWidth = fYAxis->GetBinWidth(jr); fYEdges[j].first = (fYAxis->GetBinLowEdge(jr) + yWidth * barOffset) * fCoord->GetYScale(); fYEdges[j].second = fYEdges[j].first + yWidth * barWidth * fCoord->GetYScale(); if (fYEdges[j].second > frame[2].Y()) fYEdges[j].second = frame[2].Y(); if (fYEdges[j].first < frame[0].Y()) fYEdges[j].first = frame[0].Y(); if (fYEdges[j].second < frame[0].Y()) fYEdges[j].second = frame[0].Y(); } } fMinZ = frame[0].Z(); if (fMinZ < 0.) frame[4].Z() > 0. ? fMinZ = 0. : fMinZ = frame[4].Z(); if (fCoord->Modified()) { fUpdateSelection = kTRUE; fXOZSectionPos = frame[0].Y(); fYOZSectionPos = frame[0].X(); fXOYSectionPos = frame[0].Z(); fCoord->ResetModified(); Rgl::SetZLevels(fZAxis, fCoord->GetZRange().first, fCoord->GetZRange().second, fCoord->GetZScale(), fZLevels); } fMinMaxVal.first = fHist->GetBinContent(fCoord->GetFirstXBin(), fCoord->GetFirstYBin()); fMinMaxVal.second = fMinMaxVal.first; for (Int_t i = fCoord->GetFirstXBin(), e = fCoord->GetLastXBin(); i <= e; ++i) { for (Int_t j = fCoord->GetFirstYBin(), e1 = fCoord->GetLastYBin(); j <= e1; ++j) { Double_t val = fHist->GetBinContent(i, j); fMinMaxVal.first = TMath::Min(fMinMaxVal.first, val); fMinMaxVal.second = TMath::Max(fMinMaxVal.second, val); } } ClampZ(fMinMaxVal.first); ClampZ(fMinMaxVal.second); return kTRUE; } //______________________________________________________________________________ Bool_t TGLLegoPainter::InitGeometryPolar() { //Geometry for lego in polar coords. if (!fCoord->SetRanges(fHist, kFALSE, kFALSE)) return kFALSE; fBackBox.SetPlotBox(fCoord->GetXRangeScaled(), fCoord->GetYRangeScaled(), fCoord->GetZRangeScaled()); if (fCoord->Modified()) { fUpdateSelection = kTRUE; fCoord->ResetModified(); } const Int_t nY = fCoord->GetNYBins();//yBins.second - yBins.first + 1; fYEdges.resize(nY); for (Int_t j = 0, jr = fCoord->GetFirstYBin(); j < nY; ++j, ++jr) { fYEdges[j].first = ((fYAxis->GetBinLowEdge(jr)) - fCoord->GetYRange().first) / fCoord->GetYLength() * fCoord->GetYScale(); fYEdges[j].second = ((fYAxis->GetBinUpEdge(jr)) - fCoord->GetYRange().first) / fCoord->GetYLength() * fCoord->GetYScale(); } const Int_t nX = fCoord->GetNXBins(); fCosSinTableX.resize(nX + 1); const Double_t fullAngle = fXAxis->GetXmax() - fXAxis->GetXmin(); const Double_t phiLow = fXAxis->GetXmin(); Double_t angle = 0; for (Int_t i = 0, ir = fCoord->GetFirstXBin(); i < nX; ++i, ++ir) { angle = (fXAxis->GetBinLowEdge(ir) - phiLow) / fullAngle * TMath::TwoPi(); fCosSinTableX[i].first = TMath::Cos(angle); fCosSinTableX[i].second = TMath::Sin(angle); } angle = (fXAxis->GetBinUpEdge(fCoord->GetLastXBin()) - phiLow) / fullAngle * TMath::TwoPi(); fCosSinTableX[nX].first = TMath::Cos(angle); fCosSinTableX[nX].second = TMath::Sin(angle); fMinZ = fBackBox.Get3DBox()[0].Z(); if (fMinZ < 0.) fBackBox.Get3DBox()[4].Z() > 0. ? fMinZ = 0. : fMinZ = fBackBox.Get3DBox()[4].Z(); fMinMaxVal.first = fHist->GetBinContent(fCoord->GetFirstXBin(), fCoord->GetFirstYBin()); fMinMaxVal.second = fMinMaxVal.first; for (Int_t i = fCoord->GetFirstXBin(), e = fCoord->GetLastXBin(); i <= e; ++i) { for (Int_t j = fCoord->GetFirstYBin(), e1 = fCoord->GetLastYBin(); j <= e1; ++j) { Double_t val = fHist->GetBinContent(i, j); fMinMaxVal.first = TMath::Min(fMinMaxVal.first, val); fMinMaxVal.second = TMath::Max(fMinMaxVal.second, val); } } ClampZ(fMinMaxVal.first); ClampZ(fMinMaxVal.second); return kTRUE; } //______________________________________________________________________________ Bool_t TGLLegoPainter::InitGeometryCylindrical() { //Geometry for lego in cylindrical coords. if (!fCoord->SetRanges(fHist, kFALSE, kFALSE)) return kFALSE; fBackBox.SetPlotBox(fCoord->GetXRangeScaled(), fCoord->GetYRangeScaled(), fCoord->GetZRangeScaled()); const Int_t nY = fCoord->GetNYBins(); fYEdges.resize(nY); if (fCoord->GetYLog()) { for (Int_t j = 0, jr = fCoord->GetFirstYBin(); j < nY; ++j, ++jr) { fYEdges[j].first = TMath::Log10(fYAxis->GetBinLowEdge(jr)) * fCoord->GetYScale(); fYEdges[j].second = TMath::Log10(fYAxis->GetBinUpEdge(jr)) * fCoord->GetYScale(); } } else { for (Int_t j = 0, jr = fCoord->GetFirstYBin(); j < nY; ++j, ++jr) { fYEdges[j].first = fYAxis->GetBinLowEdge(jr) * fCoord->GetYScale(); fYEdges[j].second = fYAxis->GetBinUpEdge(jr) * fCoord->GetYScale(); } } const Int_t nX = fCoord->GetNXBins(); fCosSinTableX.resize(nX + 1); const Double_t fullAngle = fXAxis->GetXmax() - fXAxis->GetXmin(); const Double_t phiLow = fXAxis->GetXmin(); Double_t angle = 0.; for (Int_t i = 0, ir = fCoord->GetFirstXBin(); i < nX; ++i, ++ir) { angle = (fXAxis->GetBinLowEdge(ir) - phiLow) / fullAngle * TMath::TwoPi(); fCosSinTableX[i].first = TMath::Cos(angle); fCosSinTableX[i].second = TMath::Sin(angle); } angle = (fXAxis->GetBinUpEdge(fCoord->GetLastXBin()) - phiLow) / fullAngle * TMath::TwoPi(); fCosSinTableX[nX].first = TMath::Cos(angle); fCosSinTableX[nX].second = TMath::Sin(angle); if (fCoord->Modified()) { fUpdateSelection = kTRUE; fCoord->ResetModified(); } fMinZ = fCoord->GetZRange().first; if (fMinZ < 0.) fCoord->GetZRange().second > 0. ? fMinZ = 0. : fMinZ = fCoord->GetZRange().second; fMinMaxVal.first = fHist->GetBinContent(fCoord->GetFirstXBin(), fCoord->GetFirstYBin()); fMinMaxVal.second = fMinMaxVal.first; for (Int_t i = fCoord->GetFirstXBin(), e = fCoord->GetLastXBin(); i <= e; ++i) { for (Int_t j = fCoord->GetFirstYBin(), e1 = fCoord->GetLastYBin(); j <= e1; ++j) { Double_t val = fHist->GetBinContent(i, j); fMinMaxVal.first = TMath::Min(fMinMaxVal.first, val); fMinMaxVal.second = TMath::Max(fMinMaxVal.second, val); } } return kTRUE; } //______________________________________________________________________________ Bool_t TGLLegoPainter::InitGeometrySpherical() { //Geometry for lego in spherical coords. if (!fCoord->SetRanges(fHist, kFALSE, kFALSE)) return kFALSE; fBackBox.SetPlotBox(fCoord->GetXRangeScaled(), fCoord->GetYRangeScaled(), fCoord->GetZRangeScaled()); const Int_t nY = fCoord->GetNYBins(); fCosSinTableY.resize(nY + 1); const Double_t fullTheta = fYAxis->GetXmax() - fYAxis->GetXmin(); const Double_t thetaLow = fYAxis->GetXmin(); Double_t angle = 0.; for (Int_t j = 0, jr = fCoord->GetFirstYBin(); j < nY; ++j, ++jr) { angle = (fYAxis->GetBinLowEdge(jr) - thetaLow) / fullTheta * TMath::Pi(); fCosSinTableY[j].first = TMath::Cos(angle); fCosSinTableY[j].second = TMath::Sin(angle); } angle = (fYAxis->GetBinUpEdge(fCoord->GetLastYBin()) - thetaLow) / fullTheta * TMath::Pi(); fCosSinTableY[nY].first = TMath::Cos(angle); fCosSinTableY[nY].second = TMath::Sin(angle); const Int_t nX = fCoord->GetNXBins(); fCosSinTableX.resize(nX + 1); const Double_t fullPhi = fXAxis->GetXmax() - fXAxis->GetXmin(); const Double_t phiLow = fXAxis->GetXmin(); for (Int_t i = 0, ir = fCoord->GetFirstXBin(); i < nX; ++i, ++ir) { angle = (fXAxis->GetBinLowEdge(ir) - phiLow) / fullPhi * TMath::TwoPi(); fCosSinTableX[i].first = TMath::Cos(angle); fCosSinTableX[i].second = TMath::Sin(angle); } angle = (fXAxis->GetBinUpEdge(fCoord->GetLastXBin()) - phiLow) / fullPhi * TMath::TwoPi(); fCosSinTableX[nX].first = TMath::Cos(angle); fCosSinTableX[nX].second = TMath::Sin(angle); fMinZ = fCoord->GetZRange().first; if (fMinZ < 0.) fCoord->GetZRange().second > 0. ? fMinZ = 0. : fMinZ = fCoord->GetZRange().second; fMinMaxVal.first = fHist->GetBinContent(fCoord->GetFirstXBin(), fCoord->GetFirstYBin()); fMinMaxVal.second = fMinMaxVal.first; for (Int_t i = fCoord->GetFirstXBin(), e = fCoord->GetLastXBin(); i <= e; ++i) { for (Int_t j = fCoord->GetFirstYBin(), e1 = fCoord->GetLastYBin(); j <= e1; ++j) { Double_t val = fHist->GetBinContent(i, j); fMinMaxVal.first = TMath::Min(fMinMaxVal.first, val); fMinMaxVal.second = TMath::Max(fMinMaxVal.second, val); } } return kTRUE; } //______________________________________________________________________________ void TGLLegoPainter::StartPan(Int_t px, Int_t py) { //User clicks on a lego with middle mouse button (middle for pad). fMousePosition.fX = px; fMousePosition.fY = fCamera->GetHeight() - py; fCamera->StartPan(px, py); fBoxCut.StartMovement(px, py); } //______________________________________________________________________________ void TGLLegoPainter::Pan(Int_t px, Int_t py) { //Move lego or section. if (fSelectedPart >= fSelectionBase || fSelectedPart == 1) { SaveModelviewMatrix(); SaveProjectionMatrix(); fCamera->SetCamera(); fCamera->Apply(fPadPhi, fPadTheta); fCamera->Pan(px, py); RestoreProjectionMatrix(); RestoreModelviewMatrix(); } else if (fSelectedPart > 0) { //Convert py into bottom-top orientation. py = fCamera->GetHeight() - py; SaveModelviewMatrix(); SaveProjectionMatrix(); fCamera->SetCamera(); fCamera->Apply(fPadPhi, fPadTheta); if (!fHighColor) { if (fBoxCut.IsActive() && (fSelectedPart >= kXAxis && fSelectedPart <= kZAxis)) fBoxCut.MoveBox(px, py, fSelectedPart); else MoveSection(px, py); } else MoveSection(px, py); RestoreProjectionMatrix(); RestoreModelviewMatrix(); } fMousePosition.fX = px, fMousePosition.fY = py; fUpdateSelection = kTRUE; } //______________________________________________________________________________ void TGLLegoPainter::AddOption(const TString &option) { //Parse additional options. using namespace std; const Ssiz_t legoPos = option.Index("lego");//"lego" _already_ _exists_ in a string. if (legoPos + 4 < option.Length() && isdigit(option[legoPos + 4])) { switch (option[legoPos + 4] - '0') { case 1: fLegoType = kColorSimple; break; case 2: fLegoType = kColorLevel; break; case 3: fLegoType = kCylindricBars; break; default: fLegoType = kColorSimple; break; } } else fLegoType = kColorSimple; //check 'e' option Ssiz_t ePos = option.Index("e"); if (ePos == legoPos + 1) ePos = option.Index("e", legoPos + 4); fDrawErrors = ePos != kNPOS ? kTRUE : kFALSE; option.Index("z") == kNPOS ? fDrawPalette = kFALSE : fDrawPalette = kTRUE; } //______________________________________________________________________________ void TGLLegoPainter::InitGL()const { //Initialize some gl state variables. glEnable(GL_DEPTH_TEST); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); //For lego, back polygons are culled (but not for sections). glEnable(GL_CULL_FACE); glCullFace(GL_BACK); glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); } //______________________________________________________________________________ void TGLLegoPainter::DeInitGL()const { //Return some gl states to original values. glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); glDisable(GL_LIGHT0); glDisable(GL_CULL_FACE); glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE); } //______________________________________________________________________________ void TGLLegoPainter::DrawPlot()const { //Select method corresponding to coordinate system. //Shift plot to point of origin. const Rgl::PlotTranslation trGuard(this); switch (fCoord->GetCoordType()) { case kGLCartesian: return DrawLegoCartesian(); case kGLPolar: return DrawLegoPolar(); case kGLCylindrical: return DrawLegoCylindrical(); case kGLSpherical: return DrawLegoSpherical(); default:; } } //______________________________________________________________________________ void TGLLegoPainter::DrawLegoCartesian()const { //Lego in cartesian system. if (fCoord->GetCoordType() == kGLCartesian) { fBackBox.DrawBox(fSelectedPart, fSelectionPass, fZLevels, fHighColor); const TGLDisableGuard cullGuard(GL_CULL_FACE); DrawSections(); } //const TGLDisableGuard depthTest(GL_DEPTH_TEST); //[0-0] if (!fSelectionPass) { glEnable(GL_POLYGON_OFFSET_FILL);//[0 glPolygonOffset(1.f, 1.f); SetLegoColor(); if (fXOZSectionPos > fBackBox.Get3DBox()[0].Y() || fYOZSectionPos> fBackBox.Get3DBox()[0].X()) { //Lego is semi-transparent if we have any sections. glEnable(GL_BLEND);//[1 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } } //Using front point, find the correct order to draw bars from //back to front (it's important only for semi-transparent lego). //Only in cartesian. const Int_t nX = fXEdges.size(); const Int_t nY = fYEdges.size(); const Int_t frontPoint = fBackBox.GetFrontPoint(); Int_t iInit = 0, jInit = 0, irInit = fCoord->GetFirstXBin(), jrInit = fCoord->GetFirstYBin(); const Int_t addI = frontPoint == 2 || frontPoint == 1 ? 1 : (iInit = nX - 1, irInit = fCoord->GetLastXBin(), -1); const Int_t addJ = frontPoint == 2 || frontPoint == 3 ? 1 : (jInit = nY - 1, jrInit = fCoord->GetLastYBin(), -1); if (fLegoType == kColorLevel && !fSelectionPass) { if (!PreparePalette()) { fLegoType = kColorSimple; fDrawPalette = kFALSE; } else fPalette.EnableTexture(GL_MODULATE); } if (fSelectionPass && fHighColor) Rgl::ObjectIDToColor(fSelectionBase, kTRUE); for(Int_t i = iInit, ir = irInit; addI > 0 ? i < nX : i >= 0; i += addI, ir += addI) { for(Int_t j = jInit, jr = jrInit; addJ > 0 ? j < nY : j >= 0; j += addJ, jr += addJ) { Double_t zMax = fHist->GetCellContent(ir, jr) * fCoord->GetFactor(); if (!ClampZ(zMax)) continue; const Int_t binID = fSelectionBase + i * fCoord->GetNYBins() + j; if (fSelectionPass && !fHighColor) Rgl::ObjectIDToColor(binID, kFALSE); else if(!fHighColor && fSelectedPart == binID) glMaterialfv(GL_FRONT, GL_EMISSION, Rgl::gOrangeEmission); if (fLegoType == kCylindricBars) { Rgl::DrawCylinder(&fQuadric, fXEdges[i].first, fXEdges[i].second, fYEdges[j].first, fYEdges[j].second, fMinZ, zMax); } else if (fLegoType == kColorLevel && !fSelectionPass) { Rgl::DrawBoxFrontTextured(fXEdges[i].first, fXEdges[i].second, fYEdges[j].first, fYEdges[j].second, fMinZ, zMax, fPalette.GetTexCoord(fMinZ), fPalette.GetTexCoord(zMax), frontPoint); } else { Rgl::DrawBoxFront(fXEdges[i].first, fXEdges[i].second, fYEdges[j].first, fYEdges[j].second, fMinZ, zMax, frontPoint); } if (!fHighColor && !fSelectionPass && fSelectedPart == binID) glMaterialfv(GL_FRONT, GL_EMISSION, Rgl::gNullEmission); } } if (fLegoType == kColorLevel && !fSelectionPass) fPalette.DisableTexture(); //Draw outlines for non-cylindrical bars. if (!fSelectionPass) { glDisable(GL_POLYGON_OFFSET_FILL);//0] const TGLDisableGuard lightGuard(GL_LIGHTING);//[2 - 2] if (fXOZSectionPos <= fBackBox.Get3DBox()[0].Y() && fYOZSectionPos <= fBackBox.Get3DBox()[0].X()) glColor3d(0., 0., 0.); else glColor4d(0., 0., 0., 0.4); glPolygonMode(GL_FRONT, GL_LINE);//[3 const TGLEnableGuard blendGuard(GL_BLEND);//[4-4] + 1] glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); const TGLEnableGuard smoothGuard(GL_LINE_SMOOTH);//[5-5] glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); for(Int_t i = iInit, ir = irInit; addI > 0 ? i < nX : i >= 0; i += addI, ir += addI) { for(Int_t j = jInit, jr = jrInit; addJ > 0 ? j < nY : j >= 0; j += addJ, jr += addJ) { Double_t zMax = fHist->GetCellContent(ir, jr) * fCoord->GetFactor(); if (!ClampZ(zMax)) continue; if (fLegoType != kCylindricBars) { Rgl::DrawBoxFront(fXEdges[i].first, fXEdges[i].second, fYEdges[j].first, fYEdges[j].second, fMinZ, zMax, frontPoint); } if (fDrawErrors && zMax > 0.) { Double_t errorZMax = (fHist->GetCellContent(ir, jr) + fHist->GetCellError(ir, jr)) * fCoord->GetFactor(); ClampZ(errorZMax); Rgl::DrawError(fXEdges[i].first, fXEdges[i].second, fYEdges[j].first, fYEdges[j].second, zMax, errorZMax); } } } glPolygonMode(GL_FRONT, GL_FILL);//3] } if(!fSelectionPass && fDrawPalette) DrawPalette(); } //______________________________________________________________________________ void TGLLegoPainter::DrawLegoPolar()const { //Lego in polar system. const Int_t nX = fCosSinTableX.size() - 1; const Int_t nY = fYEdges.size(); if (!fSelectionPass) { SetLegoColor(); glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(1.f, 1.f); } Double_t points[4][2] = {}; if (fLegoType == kColorLevel && !fSelectionPass) { if (!PreparePalette()) { fLegoType = kColorSimple; fDrawPalette = kFALSE; } else fPalette.EnableTexture(GL_MODULATE); } if (fHighColor && fSelectionPass) Rgl::ObjectIDToColor(fSelectionBase, kTRUE); for(Int_t i = 0, ir = fCoord->GetFirstXBin(); i < nX; ++i, ++ir) { for(Int_t j = 0, jr = fCoord->GetFirstYBin(); j < nY; ++j, ++jr) { Double_t zMax = fHist->GetCellContent(ir, jr); if (!ClampZ(zMax)) continue; points[0][0] = fYEdges[j].first * fCosSinTableX[i].first; points[0][1] = fYEdges[j].first * fCosSinTableX[i].second; points[1][0] = fYEdges[j].second * fCosSinTableX[i].first; points[1][1] = fYEdges[j].second * fCosSinTableX[i].second; points[2][0] = fYEdges[j].second * fCosSinTableX[i + 1].first; points[2][1] = fYEdges[j].second * fCosSinTableX[i + 1].second; points[3][0] = fYEdges[j].first * fCosSinTableX[i + 1].first; points[3][1] = fYEdges[j].first * fCosSinTableX[i + 1].second; const Int_t binID = fSelectionBase + i * fCoord->GetNYBins() + j; if (!fHighColor && fSelectionPass) Rgl::ObjectIDToColor(binID, kFALSE); else if(!fHighColor && fSelectedPart == binID) glMaterialfv(GL_FRONT, GL_EMISSION, Rgl::gOrangeEmission); if (fLegoType == kColorLevel && !fSelectionPass) Rgl::DrawTrapezoidTextured(points, fMinZ, zMax, fPalette.GetTexCoord(fMinZ), fPalette.GetTexCoord(zMax)); else Rgl::DrawTrapezoid(points, fMinZ, zMax); if (!fHighColor && !fSelectionPass && fSelectedPart == binID) glMaterialfv(GL_FRONT, GL_EMISSION, Rgl::gNullEmission); } } if (fLegoType == kColorLevel && !fSelectionPass) fPalette.DisableTexture(); //Draw otulines. if (!fSelectionPass) { glDisable(GL_POLYGON_OFFSET_FILL);//0] const TGLDisableGuard lightGuard(GL_LIGHTING);//[2-2] glColor3d(0., 0., 0.); glPolygonMode(GL_FRONT, GL_LINE);//[3 const TGLEnableGuard blendGuard(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); const TGLEnableGuard smoothGuard(GL_LINE_SMOOTH); glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); for(Int_t i = 0, ir = fCoord->GetFirstXBin(); i < nX; ++i, ++ir) { for(Int_t j = 0, jr = fCoord->GetFirstYBin(); j < nY; ++j, ++jr) { Double_t zMax = fHist->GetCellContent(ir, jr); if (!ClampZ(zMax)) continue; points[0][0] = fYEdges[j].first * fCosSinTableX[i].first; points[0][1] = fYEdges[j].first * fCosSinTableX[i].second; points[1][0] = fYEdges[j].second * fCosSinTableX[i].first; points[1][1] = fYEdges[j].second * fCosSinTableX[i].second; points[2][0] = fYEdges[j].second * fCosSinTableX[i + 1].first; points[2][1] = fYEdges[j].second * fCosSinTableX[i + 1].second; points[3][0] = fYEdges[j].first * fCosSinTableX[i + 1].first; points[3][1] = fYEdges[j].first * fCosSinTableX[i + 1].second; Rgl::DrawTrapezoid(points, fMinZ, zMax, kFALSE); } } glPolygonMode(GL_FRONT, GL_FILL);//3] } if(!fSelectionPass && fDrawPalette) DrawPalette(); } //______________________________________________________________________________ void TGLLegoPainter::DrawLegoCylindrical()const { //Lego in cylindrical system. const Int_t nX = fCosSinTableX.size() - 1; const Int_t nY = fYEdges.size(); Double_t legoR = gStyle->GetLegoInnerR(); if (legoR > 1. || legoR < 0.) legoR = 0.5; const Double_t rRange = fCoord->GetZLength(); if (!fSelectionPass) { SetLegoColor(); glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(1.f, 1.f); } Double_t points[4][2] = {}; const Double_t sc = (1 - legoR) * fCoord->GetXScale(); legoR *= fCoord->GetXScale(); if (fLegoType == kColorLevel && !fSelectionPass) { if (!PreparePalette()) { fLegoType = kColorSimple; fDrawPalette = kFALSE; } else fPalette.EnableTexture(GL_MODULATE); } if (fHighColor && fSelectionPass) Rgl::ObjectIDToColor(fSelectionBase, kTRUE); for(Int_t i = 0, ir = fCoord->GetFirstXBin(); i < nX; ++i, ++ir) { for(Int_t j = 0, jr = fCoord->GetFirstYBin(); j < nY; ++j, ++jr) { Double_t zMin = legoR + (fMinZ - fCoord->GetZRange().first) / rRange * sc; Double_t zMax = legoR + (fHist->GetCellContent(ir, jr) - fCoord->GetZRange().first) / rRange * sc; if (zMin > zMax) std::swap(zMin, zMax); points[0][0] = fCosSinTableX[i].first * zMin; points[0][1] = fCosSinTableX[i].second * zMin; points[1][0] = fCosSinTableX[i].first * zMax; points[1][1] = fCosSinTableX[i].second * zMax; points[2][0] = fCosSinTableX[i + 1].first * zMax; points[2][1] = fCosSinTableX[i + 1].second * zMax; points[3][0] = fCosSinTableX[i + 1].first * zMin; points[3][1] = fCosSinTableX[i + 1].second * zMin; const Int_t binID = fSelectionBase + i * fCoord->GetNYBins() + j; if (fSelectionPass && !fHighColor) Rgl::ObjectIDToColor(binID, kFALSE); else if(!fHighColor && fSelectedPart == binID) glMaterialfv(GL_FRONT, GL_EMISSION, Rgl::gOrangeEmission); if (fLegoType == kColorLevel && !fSelectionPass){ Rgl::DrawTrapezoidTextured2(points, fYEdges[j].first, fYEdges[j].second, fPalette.GetTexCoord(fMinZ), fPalette.GetTexCoord(fHist->GetCellContent(ir, jr))); }else Rgl::DrawTrapezoid(points, fYEdges[j].first, fYEdges[j].second); if(!fSelectionPass && !fHighColor && fSelectedPart == binID) glMaterialfv(GL_FRONT, GL_EMISSION, Rgl::gNullEmission); } } if (fLegoType == kColorLevel && !fSelectionPass) fPalette.DisableTexture(); //Draw otulines. if (!fSelectionPass) { glDisable(GL_POLYGON_OFFSET_FILL);//0] const TGLDisableGuard lightGuard(GL_LIGHTING);//[2-2] glColor3d(0., 0., 0.); glPolygonMode(GL_FRONT, GL_LINE);//[3 const TGLEnableGuard blendGuard(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); const TGLEnableGuard smoothGuard(GL_LINE_SMOOTH); glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); for(Int_t i = 0, ir = fCoord->GetFirstXBin(); i < nX; ++i, ++ir) { for(Int_t j = 0, jr = fCoord->GetFirstYBin(); j < nY; ++j, ++jr) { Double_t zMin = legoR + (fMinZ - fCoord->GetZRange().first) / rRange * sc; Double_t zMax = legoR + (fHist->GetCellContent(ir, jr) - fCoord->GetZRange().first) / rRange * sc; if (zMin > zMax) std::swap(zMin, zMax); points[0][0] = fCosSinTableX[i].first * zMin; points[0][1] = fCosSinTableX[i].second * zMin; points[1][0] = fCosSinTableX[i].first * zMax; points[1][1] = fCosSinTableX[i].second * zMax; points[2][0] = fCosSinTableX[i + 1].first * zMax; points[2][1] = fCosSinTableX[i + 1].second * zMax; points[3][0] = fCosSinTableX[i + 1].first * zMin; points[3][1] = fCosSinTableX[i + 1].second * zMin; Rgl::DrawTrapezoid(points, fYEdges[j].first, fYEdges[j].second); } } glPolygonMode(GL_FRONT, GL_FILL);//3] } if(!fSelectionPass && fDrawPalette) DrawPalette(); } //______________________________________________________________________________ void TGLLegoPainter::DrawLegoSpherical()const { //Lego in spherical system. const Int_t nX = fCosSinTableX.size() - 1; const Int_t nY = fCosSinTableY.size() - 1; const Double_t rRange = fCoord->GetZLength(); Double_t legoR = gStyle->GetLegoInnerR(); if (legoR > 1. || legoR < 0.) legoR = 0.5; if (!fSelectionPass) { SetLegoColor(); glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(1.f, 1.f); } Double_t points[8][3] = {}; const Double_t sc = 1 - legoR; if (fLegoType == kColorLevel && !fSelectionPass) { if (!PreparePalette()) { fLegoType = kColorSimple; fDrawPalette = kFALSE; } else fPalette.EnableTexture(GL_MODULATE); } if (fSelectionPass && fHighColor) Rgl::ObjectIDToColor(fSelectionBase, kTRUE); for(Int_t i = 0, ir = fCoord->GetFirstXBin(); i < nX; ++i, ++ir) { for(Int_t j = 0, jr = fCoord->GetFirstYBin(); j < nY; ++j, ++jr) { Double_t zMin = legoR + (fMinZ - fCoord->GetZRange().first) / rRange * sc; Double_t zMax = legoR + (fHist->GetCellContent(ir, jr) - fCoord->GetZRange().first) / rRange * sc; if (zMin > zMax) std::swap(zMin, zMax); points[4][0] = zMin * fCosSinTableY[j].second * fCosSinTableX[i].first; points[4][1] = zMin * fCosSinTableY[j].second * fCosSinTableX[i].second; points[4][2] = zMin * fCosSinTableY[j].first; points[5][0] = zMin * fCosSinTableY[j].second * fCosSinTableX[i + 1].first; points[5][1] = zMin * fCosSinTableY[j].second * fCosSinTableX[i + 1].second; points[5][2] = zMin * fCosSinTableY[j].first; points[6][0] = zMax * fCosSinTableY[j].second * fCosSinTableX[i + 1].first; points[6][1] = zMax * fCosSinTableY[j].second * fCosSinTableX[i + 1].second; points[6][2] = zMax * fCosSinTableY[j].first; points[7][0] = zMax * fCosSinTableY[j].second * fCosSinTableX[i].first; points[7][1] = zMax * fCosSinTableY[j].second * fCosSinTableX[i].second; points[7][2] = zMax * fCosSinTableY[j].first; points[0][0] = zMin * fCosSinTableY[j + 1].second * fCosSinTableX[i].first; points[0][1] = zMin * fCosSinTableY[j + 1].second * fCosSinTableX[i].second; points[0][2] = zMin * fCosSinTableY[j + 1].first; points[1][0] = zMin * fCosSinTableY[j + 1].second * fCosSinTableX[i + 1].first; points[1][1] = zMin * fCosSinTableY[j + 1].second * fCosSinTableX[i + 1].second; points[1][2] = zMin * fCosSinTableY[j + 1].first; points[2][0] = zMax * fCosSinTableY[j + 1].second * fCosSinTableX[i + 1].first; points[2][1] = zMax * fCosSinTableY[j + 1].second * fCosSinTableX[i + 1].second; points[2][2] = zMax * fCosSinTableY[j + 1].first; points[3][0] = zMax * fCosSinTableY[j + 1].second * fCosSinTableX[i].first; points[3][1] = zMax * fCosSinTableY[j + 1].second * fCosSinTableX[i].second; points[3][2] = zMax * fCosSinTableY[j + 1].first; const Int_t binID = fSelectionBase + i * fCoord->GetNYBins() + j; if (fSelectionPass && !fHighColor) Rgl::ObjectIDToColor(binID, kFALSE); else if(!fHighColor && fSelectedPart == binID) glMaterialfv(GL_FRONT, GL_EMISSION, Rgl::gOrangeEmission); if (fLegoType == kColorLevel && !fSelectionPass) Rgl::DrawTrapezoidTextured(points, fPalette.GetTexCoord(fMinZ), fPalette.GetTexCoord(fHist->GetCellContent(ir, jr))); else Rgl::DrawTrapezoid(points); if(!fHighColor && fSelectedPart == binID) glMaterialfv(GL_FRONT, GL_EMISSION, Rgl::gNullEmission); } } if (fLegoType == kColorLevel && !fSelectionPass) fPalette.DisableTexture(); //Draw otulines. if (!fSelectionPass) { glDisable(GL_POLYGON_OFFSET_FILL);//0] const TGLDisableGuard lightGuard(GL_LIGHTING);//[2-2] glColor3d(0., 0., 0.); glPolygonMode(GL_FRONT, GL_LINE);//[3 const TGLEnableGuard blendGuard(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); const TGLEnableGuard smoothGuard(GL_LINE_SMOOTH); glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); for(Int_t i = 0, ir = fCoord->GetFirstXBin(); i < nX; ++i, ++ir) { for(Int_t j = 0, jr = fCoord->GetFirstYBin(); j < nY; ++j, ++jr) { Double_t zMin = legoR + (fMinZ - fCoord->GetZRange().first) / rRange * sc; Double_t zMax = legoR + (fHist->GetCellContent(ir, jr) - fCoord->GetZRange().first) / rRange * sc; if (zMin > zMax) std::swap(zMin, zMax); points[4][0] = zMin * fCosSinTableY[j].second * fCosSinTableX[i].first; points[4][1] = zMin * fCosSinTableY[j].second * fCosSinTableX[i].second; points[4][2] = zMin * fCosSinTableY[j].first; points[5][0] = zMin * fCosSinTableY[j].second * fCosSinTableX[i + 1].first; points[5][1] = zMin * fCosSinTableY[j].second * fCosSinTableX[i + 1].second; points[5][2] = zMin * fCosSinTableY[j].first; points[6][0] = zMax * fCosSinTableY[j].second * fCosSinTableX[i + 1].first; points[6][1] = zMax * fCosSinTableY[j].second * fCosSinTableX[i + 1].second; points[6][2] = zMax * fCosSinTableY[j].first; points[7][0] = zMax * fCosSinTableY[j].second * fCosSinTableX[i].first; points[7][1] = zMax * fCosSinTableY[j].second * fCosSinTableX[i].second; points[7][2] = zMax * fCosSinTableY[j].first; points[0][0] = zMin * fCosSinTableY[j + 1].second * fCosSinTableX[i].first; points[0][1] = zMin * fCosSinTableY[j + 1].second * fCosSinTableX[i].second; points[0][2] = zMin * fCosSinTableY[j + 1].first; points[1][0] = zMin * fCosSinTableY[j + 1].second * fCosSinTableX[i + 1].first; points[1][1] = zMin * fCosSinTableY[j + 1].second * fCosSinTableX[i + 1].second; points[1][2] = zMin * fCosSinTableY[j + 1].first; points[2][0] = zMax * fCosSinTableY[j + 1].second * fCosSinTableX[i + 1].first; points[2][1] = zMax * fCosSinTableY[j + 1].second * fCosSinTableX[i + 1].second; points[2][2] = zMax * fCosSinTableY[j + 1].first; points[3][0] = zMax * fCosSinTableY[j + 1].second * fCosSinTableX[i].first; points[3][1] = zMax * fCosSinTableY[j + 1].second * fCosSinTableX[i].second; points[3][2] = zMax * fCosSinTableY[j + 1].first; Rgl::DrawTrapezoid(points); } } glPolygonMode(GL_FRONT, GL_FILL);//3] } if(!fSelectionPass && fDrawPalette) DrawPalette(); } //______________________________________________________________________________ void TGLLegoPainter::SetLegoColor()const { //Set lego's color. Float_t diffColor[] = {0.8f, 0.8f, 0.8f, 0.15f}; if (fLegoType != kColorLevel && fHist->GetFillColor() != kWhite) if (const TColor *c = gROOT->GetColor(fHist->GetFillColor())) c->GetRGB(diffColor[0], diffColor[1], diffColor[2]); glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffColor); const Float_t specColor[] = {1.f, 1.f, 1.f, 1.f}; glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specColor); glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 70.f); } //______________________________________________________________________________ void TGLLegoPainter::DrawSectionXOZ()const { //XOZ plane parallel section. Int_t binY = -1; for (Int_t i = 0, e = fYEdges.size(); i < e; ++i) { if (fYEdges[i].first <= fXOZSectionPos && fXOZSectionPos <= fYEdges[i].second) { binY = i; break; } } if (binY >= 0) { binY += fCoord->GetFirstYBin(); glColor3d(1., 0., 0.); glLineWidth(3.f); //Draw 2d hist on the profile's plane. for (UInt_t i = 0, ir = fCoord->GetFirstXBin(), e = fXEdges.size(); i < e; ++i, ++ir) { Double_t zMax = fHist->GetBinContent(Int_t(ir), binY); if (!ClampZ(zMax)) continue; glBegin(GL_LINE_LOOP); glVertex3d(fXEdges[i].first, fXOZSectionPos, fMinZ); glVertex3d(fXEdges[i].first, fXOZSectionPos, zMax); glVertex3d(fXEdges[i].second, fXOZSectionPos, zMax); glVertex3d(fXEdges[i].second, fXOZSectionPos, fMinZ); glEnd(); } glLineWidth(1.f); } } //______________________________________________________________________________ void TGLLegoPainter::DrawSectionYOZ()const { //YOZ plane parallel section. Int_t binX = -1; for (Int_t i = 0, e = fXEdges.size(); i < e; ++i) { if (fXEdges[i].first <= fYOZSectionPos && fYOZSectionPos <= fXEdges[i].second) { binX = i; break; } } if (binX >= 0) { binX += fCoord->GetFirstXBin();//fBinsX.first; glColor3d(1., 0., 0.); glLineWidth(3.f); //Draw 2d hist on the profile's plane. for (UInt_t i = 0, ir = fCoord->GetFirstYBin(), e = fYEdges.size(); i < e; ++i, ++ir) { Double_t zMax = fHist->GetBinContent(binX, ir); if (!ClampZ(zMax)) continue; glBegin(GL_LINE_LOOP); glVertex3d(fYOZSectionPos, fYEdges[i].first, fMinZ); glVertex3d(fYOZSectionPos, fYEdges[i].first, zMax); glVertex3d(fYOZSectionPos, fYEdges[i].second, zMax); glVertex3d(fYOZSectionPos, fYEdges[i].second, fMinZ); glEnd(); } glLineWidth(1.f); } } //______________________________________________________________________________ void TGLLegoPainter::DrawSectionXOY()const { //Empty. No such sections for lego. } //______________________________________________________________________________ void TGLLegoPainter::ProcessEvent(Int_t event, Int_t /*px*/, Int_t py) { //Remove all sections and repaint. const TGLVertex3 *frame = fBackBox.Get3DBox(); if (event == kButton1Double && (fXOZSectionPos > frame[0].Y() || fYOZSectionPos > frame[0].X())) { fXOZSectionPos = frame[0].Y(); fYOZSectionPos = frame[0].X(); if (fBoxCut.IsActive()) fBoxCut.TurnOnOff(); //gGLManager->PaintSingleObject(this); if (!gVirtualX->IsCmdThread()) gROOT->ProcessLineFast(Form("((TGLPlotPainter *)0x%lx)->Paint()", (ULong_t)this)); else Paint(); } else if (event == kKeyPress && (py == kKey_c || py == kKey_C)) { Info("ProcessEvent", "Box cut does not exist for lego"); } } //______________________________________________________________________________ Bool_t TGLLegoPainter::ClampZ(Double_t &zVal)const { //Clamp z value. if (fCoord->GetZLog()) if (zVal <= 0.) return kFALSE; else zVal = TMath::Log10(zVal) * fCoord->GetZScale(); else zVal *= fCoord->GetZScale(); const TGLVertex3 *frame = fBackBox.Get3DBox(); if (zVal > frame[4].Z()) zVal = frame[4].Z(); else if (zVal < frame[0].Z()) zVal = frame[0].Z(); return kTRUE; } //______________________________________________________________________________ Bool_t TGLLegoPainter::PreparePalette()const { //Initialize color palette. if(fMinMaxVal.first == fMinMaxVal.second) return kFALSE;//must be std::abs(fMinMaxVal.second - fMinMaxVal.first) < ... //User-defined contours are disabled, to be fixed in a future. if (fHist->TestBit(TH1::kUserContour)) fHist->ResetBit(TH1::kUserContour); UInt_t paletteSize = gStyle->GetNumberContours(); if (!paletteSize) paletteSize = 20; return fPalette.GeneratePalette(paletteSize, Rgl::Range_t(fMinZ, fMinMaxVal.second)); } //______________________________________________________________________________ void TGLLegoPainter::DrawPalette()const { //Draw. Palette. //Originally, fCamera was never null. //It can be a null now because of gl-viewer. if (!fCamera) { //Thank you, gl-viewer! return; } Rgl::DrawPalette(fCamera, fPalette); glFinish(); fCamera->SetCamera(); fCamera->Apply(fPadPhi, fPadTheta); } //______________________________________________________________________________ void TGLLegoPainter::DrawPaletteAxis()const { //Draw. Palette. Axis. gVirtualX->SetDrawMode(TVirtualX::kCopy);//TCanvas by default sets in kInverse Rgl::DrawPaletteAxis(fCamera, fMinMaxVal, fCoord->GetCoordType() == kGLCartesian ? fCoord->GetZLog() : kFALSE); }