From b949eb4452a32c4816336040f7c4e82843550044 Mon Sep 17 00:00:00 2001
From: Matevz Tadel <matevz.tadel@cern.ch>
Date: Thu, 29 May 2008 17:03:48 +0000
Subject: [PATCH] From Alja:

- TEveCaloVizEditor:
  Read eta limits from data.

- TEveCaloData, TEveCalo, TEveCalo3DGL, TEveCaloLegoGL, TEveCalo2DGL:
  Enable variable eta and phi range.

- TEveLegoOverlay:
  Draw axis using THLimits finder.


git-svn-id: http://root.cern.ch/svn/root/trunk@24052 27541ba8-7e3a-0410-8455-c3a389f83636
---
 graf3d/eve/inc/TEveCalo.h            |  30 +-
 graf3d/eve/inc/TEveCaloData.h        |  19 +-
 graf3d/eve/inc/TEveCaloLegoGL.h      |  13 +-
 graf3d/eve/src/TEveCalo.cxx          |  93 +++--
 graf3d/eve/src/TEveCalo2DGL.cxx      |  22 +-
 graf3d/eve/src/TEveCalo3DGL.cxx      |   4 +-
 graf3d/eve/src/TEveCaloData.cxx      | 152 +++++---
 graf3d/eve/src/TEveCaloLegoGL.cxx    | 521 +++++++++++++++------------
 graf3d/eve/src/TEveCaloVizEditor.cxx |   4 +-
 graf3d/eve/src/TEveLegoOverlay.cxx   |  99 +++--
 10 files changed, 571 insertions(+), 386 deletions(-)

diff --git a/graf3d/eve/inc/TEveCalo.h b/graf3d/eve/inc/TEveCalo.h
index c26a339e444..3bbd835a1f5 100644
--- a/graf3d/eve/inc/TEveCalo.h
+++ b/graf3d/eve/inc/TEveCalo.h
@@ -38,13 +38,11 @@ private:
 protected:
    TEveCaloData* fData;  // event data reference
 
-   Float_t      fEtaLowLimit;
-   Float_t      fEtaHighLimit;
-   Float_t      fEtaMin;
-   Float_t      fEtaMax;
+   Double_t      fEtaMin;
+   Double_t      fEtaMax;
 
-   Float_t      fPhi;
-   Float_t      fPhiRng;
+   Double_t      fPhi;
+   Double_t      fPhiRng;
 
    Float_t      fBarrelRadius;  // barrel raidus in cm
    Float_t      fEndCapPos;     // end cap z coordinate in cm
@@ -87,12 +85,19 @@ public:
    TEveRGBAPalette* AssertPalette();
 
 
-   void SetEta(Float_t l, Float_t u) { fEtaMin=l; fEtaMax=u; InvalidateCache(); }
-   void SetEtaLimits(Float_t l, Float_t h) { fEtaLowLimit=l; fEtaHighLimit =h; InvalidateCache(); }
+   void SetEta(Float_t l, Float_t u);
+   Float_t GetEta() const { return (fEtaMin+fEtaMax)*0.5f;}
+   Float_t GetEtaMin() const {return fEtaMin;}
+   Float_t GetEtaMax() const {return fEtaMax;}
+   Float_t GetEtaRng() const {return fEtaMax-fEtaMin;}
 
-   void SetPhi(Float_t x)    { fPhi    = x; InvalidateCache(); }
-   void SetPhiRng(Float_t r) { fPhiRng = r; InvalidateCache(); }
-   void SetPhiWithRng(Float_t x, Float_t r) { fPhi = x; fPhiRng = r; InvalidateCache(); }
+   virtual void SetPhi(Float_t phi)    { SetPhiWithRng(phi, fPhiRng); }
+   virtual void SetPhiRng(Float_t rng) { SetPhiWithRng(fPhi, rng); }
+   virtual void SetPhiWithRng(Float_t x, Float_t r);
+   Float_t GetPhi() const { return fPhi;}
+   Float_t GetPhiMin() const {return fPhi-fPhiRng;}
+   Float_t GetPhiMax() const {return fPhi+fPhiRng;}
+   Float_t GetPhiRng() const {return fPhiRng;}
 
 
    virtual void ResetCache() = 0;
@@ -194,15 +199,12 @@ protected:
    Bool_t                  fDrawHPlane;
    Float_t                 fHPlaneVal;
 
-
 public:
    TEveCaloLego(const Text_t* n="TEveCaloLego", const Text_t* t="");
    TEveCaloLego(TEveCaloData* data);
 
    virtual ~TEveCaloLego(){}
 
-   Int_t  GetAxisStep(Float_t max) const;
-
    Color_t  GetFontColor() const { return fFontColor; }
    void     SetFontColor(Color_t ci) { fFontColor=ci; }
 
diff --git a/graf3d/eve/inc/TEveCaloData.h b/graf3d/eve/inc/TEveCaloData.h
index 1a714bb55f9..20ac3781d68 100644
--- a/graf3d/eve/inc/TEveCaloData.h
+++ b/graf3d/eve/inc/TEveCaloData.h
@@ -89,19 +89,23 @@ public:
                              Float_t etaMin, Float_t etaMax,
                              Float_t phi, Float_t phiRng, vCellId_t &out) = 0;
 
-   virtual void  GetCellData(const CellId_t &id, CellData_t& data) = 0;
+   virtual void GetCellData(const CellId_t &id, CellData_t& data) = 0;
+   virtual void GetCellData(const CellId_t &id, Float_t  phiMin, Float_t phiRng, CellData_t& data) = 0;
 
    virtual Int_t GetNSlices() const = 0;
 
    virtual Float_t  GetMaxVal() const = 0;
 
+   virtual void  GetEtaLimits(Double_t &min, Double_t &max) const=0;
+   virtual void  GetPhiLimits(Double_t &min, Double_t &max) const=0;
+
    Float_t GetThreshold() {return fThreshold;}
    void    SetThreshold(Float_t t) {fThreshold = t;}
 
    virtual Bool_t SupportsEtaBinning(){ return kFALSE; }
    virtual Bool_t SupportsPhiBinning(){ return kFALSE; }
-   virtual const TAxis* GetEtaBins(){ return 0 ;}
-   virtual const TAxis* GetPhiBins(){ return 0 ;}
+   virtual TAxis* GetEtaBins(){ return 0 ;}
+   virtual TAxis* GetPhiBins(){ return 0 ;}
 
    ClassDef(TEveCaloData, 0); // Manages calorimeter event data.
 };
@@ -127,10 +131,13 @@ public:
                              Float_t phi, Float_t phiRng, vCellId_t &out);
 
    virtual void GetCellData(const TEveCaloData::CellId_t &id, TEveCaloData::CellData_t& data);
+   virtual void GetCellData(const CellId_t &id, Float_t  phiMin, Float_t phiRng, CellData_t& data);
 
    virtual Int_t GetNSlices() const;
 
-   virtual Float_t  GetMaxVal() const;
+   virtual Float_t GetMaxVal() const;
+   virtual void    GetEtaLimits(Double_t &min, Double_t &max) const;
+   virtual void    GetPhiLimits(Double_t &min, Double_t &max) const;
 
    virtual Bool_t SupportsEtaBinning(){ return kTRUE; }
    virtual Bool_t SupportsPhiBinning(){ return kTRUE; }
@@ -138,8 +145,8 @@ public:
    void   AddHistogram(TH2F* hist);
    const  TH2F*  GetHistogram(Int_t slice);
 
-   const TAxis* GetEtaBins();
-   const TAxis* GetPhiBins();
+   TAxis* GetEtaBins();
+   TAxis* GetPhiBins();
 
    ClassDef(TEveCaloDataHist, 0); // Manages calorimeter TH2F event data.
 };
diff --git a/graf3d/eve/inc/TEveCaloLegoGL.h b/graf3d/eve/inc/TEveCaloLegoGL.h
index c4d272b29fa..c6ffb6e9f6a 100644
--- a/graf3d/eve/inc/TEveCaloLegoGL.h
+++ b/graf3d/eve/inc/TEveCaloLegoGL.h
@@ -27,12 +27,15 @@ private:
    TEveCaloLegoGL& operator=(const TEveCaloLegoGL&); // Not implemented
 
    // cached variables
-   mutable Float_t    fDataMax;
-   mutable Int_t      fZAxisStep;
-   mutable Int_t      fZAxisMax;
+   mutable Float_t   fDataMax;
+   mutable Double_t  fZAxisStep;
+   mutable Double_t  fZAxisMax;
+
+   mutable TAxis*    fEtaAxis;
+   mutable TAxis*    fPhiAxis;
 
 protected:
-   Int_t   GetGridStep(Int_t axId, const TAxis* ax, TGLRnrCtx &rnrCtx) const;
+   Int_t   GetGridStep(Int_t axId, TGLRnrCtx &rnrCtx) const;
 
    void    SetFont(Float_t axis_len, TGLRnrCtx &rnrCtx) const;
    void    RnrText(const char* txt, Float_t x, Float_t y, Float_t z,
@@ -60,8 +63,6 @@ protected:
    mutable TGLFont          fNumFont;
    mutable TGLFont          fSymbolFont;
 
-   const   Float_t          fTMSize; //  XY tick-mark size in world coordinates
-
    // grid density modes
    Int_t                    fNBinSteps;
    Int_t*                   fBinSteps;
diff --git a/graf3d/eve/src/TEveCalo.cxx b/graf3d/eve/src/TEveCalo.cxx
index ed81ef3ddda..9fa4bed96bc 100644
--- a/graf3d/eve/src/TEveCalo.cxx
+++ b/graf3d/eve/src/TEveCalo.cxx
@@ -23,6 +23,7 @@
 #include "TBuffer3DTypes.h"
 #include "TVirtualPad.h"
 #include "TVirtualViewer3D.h"
+#include "TAxis.h"
 
 #include "TGLUtil.h"
 
@@ -41,10 +42,8 @@ TEveCaloViz::TEveCaloViz(const Text_t* n, const Text_t* t) :
 
    fData(0),
 
-   fEtaLowLimit(-5.f),
-   fEtaHighLimit(5.f),
-   fEtaMin(fEtaLowLimit),
-   fEtaMax(fEtaHighLimit),
+   fEtaMin(-1),
+   fEtaMax(1),
 
    fPhi(0.),
    fPhiRng(TMath::Pi()),
@@ -71,10 +70,8 @@ TEveCaloViz::TEveCaloViz(TEveCaloData* data, const Text_t* n, const Text_t* t) :
 
    fData(0),
 
-   fEtaLowLimit(-5.f),
-   fEtaHighLimit(5.f),
-   fEtaMin(fEtaLowLimit),
-   fEtaMax(fEtaHighLimit),
+   fEtaMin(-1),
+   fEtaMax(1),
 
    fPhi(0.),
    fPhiRng(TMath::Pi()),
@@ -103,6 +100,33 @@ TEveCaloViz::~TEveCaloViz()
    if (fData) fData->DecRefCount();
 }
 
+//______________________________________________________________________________
+void TEveCaloViz::SetEta(Float_t l, Float_t u)
+{
+   // Set eta range.
+
+   fEtaMin=l;
+   fEtaMax=u;
+
+   if(fData && fData->GetEtaBins())
+         fData->GetEtaBins()->SetRangeUser(l, u);
+
+   InvalidateCache();
+}
+
+ //______________________________________________________________________________
+void TEveCaloViz::SetPhiWithRng(Float_t phi, Float_t rng)
+{
+   // Set phi range.
+
+   using namespace TMath;
+
+   fPhi = phi;
+   fPhiRng = rng;
+
+   InvalidateCache();
+}
+
 //______________________________________________________________________________
 Float_t TEveCaloViz::GetTransitionTheta() const
 {
@@ -130,6 +154,14 @@ void TEveCaloViz::SetData(TEveCaloData* data)
    if (fData) fData->DecRefCount();
    fData = data;
    if (fData) fData->IncRefCount();
+
+
+   fData->GetEtaLimits(fEtaMin, fEtaMax);
+   Double_t min, max;
+   fData->GetPhiLimits(min, max);
+   fPhi = (max+min)*0.5;
+   fPhiRng =(max-min)*0.5;
+
    InvalidateCache();
 }
 
@@ -142,8 +174,6 @@ void TEveCaloViz::AssignCaloVizParameters(TEveCaloViz* m)
 
    fEtaMin    = m->fEtaMin;
    fEtaMax    = m->fEtaMax;
-   fEtaLowLimit = m->fEtaLowLimit;
-   fEtaHighLimit = m->fEtaHighLimit;
 
    fPhi       = m->fPhi;
    fPhiRng    = m->fPhiRng;
@@ -390,7 +420,10 @@ TEveCaloLego::TEveCaloLego(const Text_t* n, const Text_t* t):
    fBinWidth(5),
 
    fProjection(kAuto),
-   f2DMode(kValColor)
+   f2DMode(kValColor),
+
+   fDrawHPlane(kFALSE),
+   fHPlaneVal(0)
 {
    // Constructor.
 
@@ -399,7 +432,7 @@ TEveCaloLego::TEveCaloLego(const Text_t* n, const Text_t* t):
 
 //______________________________________________________________________________
 TEveCaloLego::TEveCaloLego(TEveCaloData* data):
-   TEveCaloViz(data),
+   TEveCaloViz(),
 
    fFontColor(0),
    fGridColor(kGray+3),
@@ -414,19 +447,15 @@ TEveCaloLego::TEveCaloLego(TEveCaloData* data):
    fProjection(kAuto),
    f2DMode(kValColor),
 
-   fBoxMode(kBack)
+   fBoxMode(kBack),
+
+   fDrawHPlane(kFALSE),
+   fHPlaneVal(0)
 {
    // Constructor.
 
    SetElementNameTitle("TEveCaloLego", "TEveCaloLego");
-}
-
-//______________________________________________________________________________
-Int_t TEveCaloLego::GetAxisStep(Float_t max) const
-{
-   // Returns reasonable step between two axis labels.
-
-   return 5*TMath::CeilNint(max*1.f/(fNZSteps*5));
+   SetData(data);
 }
 
 //______________________________________________________________________________
@@ -453,12 +482,22 @@ void TEveCaloLego::ComputeBBox()
 
    BBoxInit();
 
-   fBBox[0] = 1.2f*fEtaMin;
-   fBBox[1] = 1.2f*fEtaMax;
+   // Float_t[6] X(min,max), Y(min,max), Z(min,max)
+   if (fData)
+   {
+      Float_t ex = 1.2;
+
+      Double_t em, eM, pm, pM;
+      fData->GetEtaLimits(em, eM);
+      fData->GetPhiLimits(pm, pM);
 
-   fBBox[2] = fPhi - 1.2f*fPhiRng;
-   fBBox[3] = fPhi + 1.2f*fPhiRng;
+      fBBox[0] = ex*em;
+      fBBox[1] = ex*eM;
 
-   fBBox[4] = -GetDefaultCellHeight()*fCellZScale*0.2;
-   fBBox[5] =  GetDefaultCellHeight()*fCellZScale*1.2;
+      fBBox[2] = ex*pm;
+      fBBox[3] = ex*pM;
+
+      fBBox[4] = -GetDefaultCellHeight()*fCellZScale*0.2;
+      fBBox[5] =  GetDefaultCellHeight()*fCellZScale*1.2;
+   }
 }
diff --git a/graf3d/eve/src/TEveCalo2DGL.cxx b/graf3d/eve/src/TEveCalo2DGL.cxx
index b85575e5ffe..1cc8b1af6ea 100644
--- a/graf3d/eve/src/TEveCalo2DGL.cxx
+++ b/graf3d/eve/src/TEveCalo2DGL.cxx
@@ -122,12 +122,12 @@ void TEveCalo2DGL::DrawRPhi(TGLRnrCtx & rnrCtx) const
 
    if (fM->fCacheOK == kFALSE) {
       fM->ResetCache();
-      Float_t eta = (fM->fEtaMax+fM->fEtaMin)*0.5f;
-      Float_t etaRng = fM->fEtaMax-fM->fEtaMin;
+      Float_t eta = fM->GetEta();
+      Float_t etaRng = fM->GetEtaRng();
       Float_t pr[4];
       // calculate the two intervals when circle is cut
-      Float_t phi1 = fM->fPhi - fM->fPhiRng;
-      Float_t phi2 = fM->fPhi + fM->fPhiRng;
+      Float_t phi1 = fM->GetPhiMin();
+      Float_t phi2 = fM->GetPhiMax();
       if (phi2 >Pi() && phi1<-Pi()) {
          pr[0] =  phi1;
          pr[1] =  Pi();
@@ -145,13 +145,13 @@ void TEveCalo2DGL::DrawRPhi(TGLRnrCtx & rnrCtx) const
       }
 
       Int_t nBins = ax->GetNbins();
-      for (Int_t ibin=0; ibin<nBins; ibin++) {
+      for (Int_t ibin=1; ibin<=nBins; ibin++) {
          if ( (   ax->GetBinLowEdge(ibin)>=pr[0] && ax->GetBinUpEdge(ibin)<pr[1])
               || (ax->GetBinLowEdge(ibin)>=pr[2] && ax->GetBinUpEdge(ibin)<pr[3]))
          {
             TEveCaloData::vCellId_t* clv = new TEveCaloData::vCellId_t();
             Int_t nc = data->GetCellList(fM->fPalette->GetMinVal(), fM->fPalette->GetMaxVal(),
-                                         eta, etaRng, ax->GetBinCenter(ibin), ax->GetBinWidth(ibin),*clv);
+                                         eta, etaRng, fM->fPhi+ax->GetBinCenter(ibin), ax->GetBinWidth(ibin),*clv);
             if (nc)
                fM->fCellLists.push_back(clv);
             else
@@ -206,7 +206,7 @@ void TEveCalo2DGL::DrawRPhi(TGLRnrCtx & rnrCtx) const
 void TEveCalo2DGL::MakeRhoZCell(const TEveCaloData::CellData_t &cell, Float_t& offset, Bool_t phiPlus, Float_t towerH) const
 {
    // Draw cell in RhoZ projection.
- 
+
    Float_t pnts[8];
 
    Float_t sin1 = Sin(cell.ThetaMin());
@@ -225,7 +225,7 @@ void TEveCalo2DGL::MakeRhoZCell(const TEveCaloData::CellData_t &cell, Float_t& o
       pnts[4] = r2*sin2; pnts[5] = r2*cos2;
       pnts[6] = r1*sin2; pnts[7] = r1*cos2;
    }
-   else 
+   else
    {
       // endcap
       Float_t r1 =fM->GetEndCapPos()/Abs(Cos((cell.ThetaMin()+cell.ThetaMax())*0.5)) + offset;
@@ -265,12 +265,12 @@ void TEveCalo2DGL::DrawRhoZ(TGLRnrCtx & rnrCtx) const
       fM->ResetCache();
       const TAxis* ax = data->GetEtaBins();
       Int_t nBins = ax->GetNbins();
-      for (Int_t ibin=0; ibin<nBins; ibin++){
+      for (Int_t ibin=1; ibin<=nBins; ibin++){
          if (ax->GetBinLowEdge(ibin)>fM->fEtaMin && ax->GetBinUpEdge(ibin)<=fM->fEtaMax)
          {
             TEveCaloData::vCellId_t* aa = new TEveCaloData::vCellId_t();
             data->GetCellList(fM->fPalette->GetMinVal(), fM->fPalette->GetMaxVal(),
-                              ax->GetBinCenter(ibin), ax->GetBinWidth(ibin),
+                              fM->GetEta() + ax->GetBinCenter(ibin), ax->GetBinWidth(ibin),
                               fM->fPhi, fM->fPhiRng, *aa);
             if (aa->size()) fM->fCellLists.push_back(aa);
          }
@@ -287,7 +287,7 @@ void TEveCalo2DGL::DrawRhoZ(TGLRnrCtx & rnrCtx) const
 
 
    if (rnrCtx.SecSelection()) glPushName(0);
-   for (UInt_t vi=0; vi<fM->fCellLists.size(); vi++) {   
+   for (UInt_t vi=0; vi<fM->fCellLists.size(); vi++) {
 
       // clear
       Float_t offUp  = 0;
diff --git a/graf3d/eve/src/TEveCalo3DGL.cxx b/graf3d/eve/src/TEveCalo3DGL.cxx
index 4506f1696b1..2f53efc33e3 100644
--- a/graf3d/eve/src/TEveCalo3DGL.cxx
+++ b/graf3d/eve/src/TEveCalo3DGL.cxx
@@ -307,9 +307,7 @@ void TEveCalo3DGL::DirectDraw(TGLRnrCtx &rnrCtx) const
    {
       fM->ResetCache();
       fM->fData->GetCellList(fM->fPalette->GetMinVal(), fM->fPalette->GetMaxVal(),
-                             0.5f*(fM->fEtaMin + fM->fEtaMax),
-                             fM->fEtaMax - fM->fEtaMin,
-                             fM->fPhi, fM->fPhiRng, fM->fCellList);
+                             fM->GetEta(), fM->GetEtaRng(), fM->GetPhi(), fM->GetPhiRng(), fM->fCellList);
       fM->fCacheOK= kTRUE;
    }
 
diff --git a/graf3d/eve/src/TEveCaloData.cxx b/graf3d/eve/src/TEveCaloData.cxx
index 8bdee984bff..33529950c09 100644
--- a/graf3d/eve/src/TEveCaloData.cxx
+++ b/graf3d/eve/src/TEveCaloData.cxx
@@ -53,12 +53,13 @@ void TEveCaloData::CellData_t::Configure(Float_t v, Float_t e1, Float_t e2, Floa
       fZSideSign = 1;
    }
 
-   fPhiMin = p1;
-   fPhiMax = p2;
 
    fEtaMin = e1;
    fEtaMax = e2;
 
+   fPhiMin = p1;
+   fPhiMax = p2;
+
    fValue  = v;
 }
 
@@ -106,33 +107,10 @@ Int_t TEveCaloDataHist::GetCellList(Float_t minVal, Float_t maxVal,
 
    using namespace TMath;
 
-   etaD *= 1.01f;
-   phiD *= 1.01f;
-
-   // eta interval
-   Float_t etaMin = eta - etaD*0.5f;
-   Float_t etaMax = eta + etaD*0.5f;
-
-   // phi interval
-   Float_t pr[4];
-   Float_t phi1  = phi - phiD;
-   Float_t phi2  = phi + phiD;
-   if (phi2 >TMath::Pi() && phi1>-Pi()) {
-      pr[0] =  phi1;
-      pr[1] =  Pi();
-      pr[2] =  -Pi();
-      pr[3] =  -TwoPi()+phi2;
-   }
-   else if (phi1<-TMath::Pi() && phi2<=Pi()) {
-      pr[0] = -Pi();
-      pr[1] =  phi2;
-      pr[2] =  TwoPi()+phi1;
-      pr[3] =  Pi();
-   }
-   else {
-      pr[0] = pr[2] = phi1;
-      pr[1] = pr[3] = phi2;
-   }
+   Float_t phiMin = phi - phiD;
+   Float_t phiMax = phi + phiD;
+   Float_t etaMin = eta - etaD;
+   Float_t etaMax = eta + etaD;
 
    TH2F *hist0 = (TH2F*)fHStack->GetStack()->At(0);
    TAxis *ax = hist0->GetXaxis();
@@ -141,23 +119,48 @@ Int_t TEveCaloDataHist::GetCellList(Float_t minVal, Float_t maxVal,
 
    Int_t bin = 0;
    Float_t val = 0;
-   for (Int_t ieta=0; ieta<ax->GetNbins(); ieta++) {
-      for (Int_t iphi=0; iphi<ay->GetNbins(); iphi++)  {
-         if ( ax->GetBinLowEdge(ieta)   >= etaMin
-              && ax->GetBinUpEdge(ieta) <  etaMax
-              && ((ay->GetBinLowEdge(iphi)>=pr[0] && ay->GetBinUpEdge(iphi)<pr[1])
-                  || (ay->GetBinLowEdge(iphi)>=pr[2] && ay->GetBinUpEdge(iphi)<pr[3])))
+   Double_t phi0, phi1;
+   Bool_t phiInside;
+   for (Int_t ieta=1; ieta<=ax->GetNbins(); ieta++) {
+      for (Int_t iphi=1; iphi<=ay->GetNbins(); iphi++)  {
+         if ( ax->GetBinLowEdge(ieta)>=etaMin && ax->GetBinUpEdge(ieta)<=etaMax)
          {
-            TIter next(fHStack->GetHists());
-            Int_t slice = 0;
-            bin = hist0->GetBin(ieta, iphi);
-            while ((hist = (TH2F*) next()) != 0) {
-               val = hist->GetBinContent(bin);
-               if (val>fThreshold && val>minVal && val<=maxVal)
-               {
-                  out.push_back(TEveCaloData::CellId_t(bin, slice));
+            phiInside = kFALSE;
+            phi0 = ay->GetBinLowEdge(iphi);
+            phi1 = ay->GetBinUpEdge(iphi);
+
+            if ( phi0>=phiMin && phi1 <=phiMax)
+            {
+               phiInside = kTRUE;
+            }
+            else if (phiMax>Pi() && phi1<phiMin)
+            {
+               phi0 += TwoPi();
+               phi1 += TwoPi();
+               if (phi0>phiMin && phi1<phiMax)
+                  phiInside = kTRUE;
+            }
+            else if (phiMin<-Pi() && phi0>phiMax)
+            {
+               phi0 -= TwoPi();
+               phi1 -= TwoPi();
+               if (phi0>=phiMin && phi1<=phiMax)
+                  phiInside = kTRUE;
+            }
+
+            if (phiInside)
+            {
+               TIter next(fHStack->GetHists());
+               Int_t slice = 0;
+               bin = hist0->GetBin(ieta, iphi);
+               while ((hist = (TH2F*) next()) != 0) {
+                  val = hist->GetBinContent(bin);
+                  if (val>fThreshold && val>minVal && val<=maxVal)
+                  {
+                     out.push_back(TEveCaloData::CellId_t(bin, slice));
+                  }
+                  slice++;
                }
-               slice++;
             }
          }
       }
@@ -182,6 +185,43 @@ void TEveCaloDataHist::GetCellData(const TEveCaloData::CellId_t &id, TEveCaloDat
                       hist->GetYaxis()->GetBinUpEdge(y));
 }
 
+//______________________________________________________________________________
+void TEveCaloDataHist::GetCellData(const TEveCaloData::CellId_t &id, Float_t phi, Float_t phiRng,
+                                   TEveCaloData::CellData_t& cellData)
+{
+   // Get cell geometry and value from cell ID.
+   // Respect external phi range shifted for a given phi.
+
+   using namespace TMath;
+
+   Float_t phiMin = phi-phiRng;
+   Float_t phiMax = phi+phiRng;
+
+   TH2F* hist  = (TH2F*) (fHStack->GetHists()->At(id.fSlice));
+
+   Int_t x, y, z;
+   hist->GetBinXYZ(id.fTower, x, y, z);
+
+   Float_t phi1 = hist->GetYaxis()->GetBinLowEdge(y);
+   Float_t phi2 = hist->GetYaxis()->GetBinUpEdge(y);
+
+   if (phiMax>Pi() && phi2<=phiMin)
+   {
+      phi1 += TwoPi();
+      phi2 += TwoPi();
+   }
+   else if (phiMin<-Pi() && phi1>=phiMax)
+   {
+      phi1 -= TwoPi();
+      phi2 -= TwoPi();
+   }
+
+   cellData.Configure(hist->GetBinContent(id.fTower),
+                      hist->GetXaxis()->GetBinLowEdge(x),
+                      hist->GetXaxis()->GetBinUpEdge(x),
+                      phi1, phi2);
+}
+
 //______________________________________________________________________________
 void TEveCaloDataHist::AddHistogram(TH2F* h)
 {
@@ -207,7 +247,27 @@ Float_t TEveCaloDataHist::GetMaxVal() const
 }
 
 //______________________________________________________________________________
-const TAxis* TEveCaloDataHist::GetEtaBins()
+void TEveCaloDataHist::GetEtaLimits(Double_t &min, Double_t &max) const
+{
+   // Get eta limits.
+
+   TH2F* hist  = (TH2F*) (fHStack->GetHists()->At(0));
+   min = hist->GetXaxis()->GetXmin();
+   max = hist->GetXaxis()->GetXmax();
+}
+
+//______________________________________________________________________________
+void TEveCaloDataHist::GetPhiLimits(Double_t &min, Double_t &max) const
+{
+   // Get phi limits.
+
+   TH2F* hist  = (TH2F*) (fHStack->GetHists()->At(0));
+   min = hist->GetYaxis()->GetXmin();
+   max = hist->GetYaxis()->GetXmax();
+}
+
+//______________________________________________________________________________
+TAxis* TEveCaloDataHist::GetEtaBins()
 {
    // Get eta axis.
 
@@ -216,7 +276,7 @@ const TAxis* TEveCaloDataHist::GetEtaBins()
 }
 
 //______________________________________________________________________________
-const TAxis* TEveCaloDataHist::GetPhiBins()
+TAxis* TEveCaloDataHist::GetPhiBins()
 {
    // Get phi axis.
 
diff --git a/graf3d/eve/src/TEveCaloLegoGL.cxx b/graf3d/eve/src/TEveCaloLegoGL.cxx
index 0639185c19a..d1683d05216 100644
--- a/graf3d/eve/src/TEveCaloLegoGL.cxx
+++ b/graf3d/eve/src/TEveCaloLegoGL.cxx
@@ -36,16 +36,17 @@ ClassImp(TEveCaloLegoGL);
 //______________________________________________________________________________
 TEveCaloLegoGL::TEveCaloLegoGL() :
    TGLObject(),
-   
+
    fDataMax(0),
    fZAxisStep(0),
    fZAxisMax(0),
 
+   fEtaAxis(0),
+   fPhiAxis(0),
+
    fDLCacheOK(kFALSE),
    fM(0),
 
-   fTMSize(0.1),
-
    fNBinSteps(5),
    fBinSteps(0),
 
@@ -71,7 +72,6 @@ TEveCaloLegoGL::~TEveCaloLegoGL()
    delete [] fBinSteps;
 }
 
-
 //______________________________________________________________________________
 Bool_t TEveCaloLegoGL::SetModel(TObject* obj, const Option_t* /*opt*/)
 {
@@ -226,7 +226,7 @@ void TEveCaloLegoGL::MakeDisplayList() const
             prevTower = fM->fCellList[i].fTower;
          }
 
-         fM->fData->GetCellData(fM->fCellList[i], cellData);
+         fM->fData->GetCellData(fM->fCellList[i], fM->fPhi, fM->fPhiRng, cellData);
          if (s == fM->fCellList[i].fSlice)
          {
             glLoadName(i);
@@ -275,7 +275,6 @@ void TEveCaloLegoGL::RnrText(const char* txt,
    glPopMatrix();
 }
 
-
 //______________________________________________________________________________
 void TEveCaloLegoGL::SetFont(Float_t cfs, TGLRnrCtx & rnrCtx) const
 {
@@ -315,7 +314,9 @@ void TEveCaloLegoGL::DrawZScales2D(TGLRnrCtx & rnrCtx, Float_t x0, Float_t y0) c
    SetFont(etal*0.1, rnrCtx);
    TGLUtil::Color(fM->fFontColor);
    fNumFont.PreRender(kFALSE);
-   RnrText(Form("Et[GeV] %d ", fZAxisMax), x0 - fTMSize*2, y0, 0, fNumFont, 2);
+
+   const char* txt = Form("Et[GeV] %s",TEveUtil::FormAxisValue(fZAxisMax));
+   RnrText(txt, x0, y0, 0, fNumFont, 2);
    fNumFont.PostRender();
 }
 
@@ -330,28 +331,41 @@ void TEveCaloLegoGL::DrawZAxis(TGLRnrCtx &rnrCtx, Float_t azX, Float_t azY) cons
    // size of tick-mark 8 pixels
    TGLVertex3 worldRef(0, 0, fZAxisMax*0.5);
    TGLVector3 off = rnrCtx.RefCamera().ViewportDeltaToWorld(worldRef, -8, 0);
- 
-   // tick-marks
-   Float_t tmStep = fZAxisStep*0.2f;
-   Int_t ntm = (fM->fNZSteps)*5;
+
+   // primary tick-marks
+   Int_t np = TMath::CeilNint(fZAxisMax/fZAxisStep);
    glBegin(GL_LINES);
-   for (Int_t i = 1; i <= ntm; ++i)
+   Float_t z =fZAxisStep;
+   for (Int_t i = 0; i < np; ++i)
+   {
+      glVertex3f(0, 0, z);
+      glVertex3f(off.X(), off.Y(), z-off.Z());
+      z += fZAxisStep;
+   }
+
+   // secondary
+   off  = off*0.5f;
+   Double_t omin2, omax2, step2;
+   Int_t div2;
+   THLimitsFinder::Optimize(0, fZAxisStep, fM->GetNZSteps(), omin2, omax2, div2, step2);
+   Double_t z2 = step2;
+   while (z2<fZAxisMax)
    {
-      glVertex3f(0, 0, i*tmStep);
-      if (i % 5 != 0)
-         glVertex3f(off.X()*0.5, off.Y()*0.5, i*tmStep-off.Z()*0.5);
-      else
-         glVertex3f(off.X(), off.Y(), i*tmStep-off.Z());
+      glVertex3f(0, 0, z2);
+      glVertex3f(off.X(), off.Y(), z2-off.Z());
+      z2 += step2;
    }
    glEnd();
 
+
    off *= 4; // label offset
    fNumFont.PreRender(kFALSE);
    TGLUtil::Color(fM->fFontColor);
-   RnrText( Form("Et[GeV]  %d", fZAxisMax), off.X(), off.Y(), fZAxisMax+off.Z(), fNumFont, 3);
+   for (Int_t i = 1; i < np; ++i)
+      RnrText(TEveUtil::FormAxisValue(i*fZAxisStep), off.X(), off.Y(), i*fZAxisStep+off.Z(), fNumFont, 3);
 
-   for (Int_t i = 1; i < fM->fNZSteps; ++i)
-      RnrText(Form("%d",i*fZAxisStep), off.X(), off.Y(), i*fZAxisStep+off.Z(), fNumFont, 3);
+   const char* txt = TEveUtil::FormAxisValue(fZAxisMax);
+   RnrText(Form("Et[GeV] %s", txt), off.X(), off.Y(), fZAxisMax+off.Z(), fNumFont, 3);
 
    fNumFont.PostRender();
 
@@ -380,6 +394,7 @@ void TEveCaloLegoGL::DrawZScales3D(TGLRnrCtx & rnrCtx,
    gluProject(x1, y1, 0, mm, pm, vp, &x[2], &y[2], &z[2]);
    gluProject(x0, y1, 0, mm, pm, vp, &x[3], &y[3], &z[3]);
 
+
    /**************************************************************************/
 
    // get pos of z axis (left most corner)
@@ -501,7 +516,7 @@ void TEveCaloLegoGL::DrawZScales3D(TGLRnrCtx & rnrCtx,
       glLineStipple(1, 0x5555);
       glEnable(GL_LINE_STIPPLE);
       glBegin(GL_LINES);
-      Int_t nhs = fM->fNZSteps;
+      Int_t nhs = TMath::CeilNint(fZAxisMax/fZAxisStep);
       Float_t hz  = 0;
       for (Int_t i = 1; i<=nhs; ++i, hz+=fZAxisStep)
       {
@@ -530,7 +545,7 @@ void TEveCaloLegoGL::DrawZScales3D(TGLRnrCtx & rnrCtx,
    {
       // left most corner of the picked tower
       TEveCaloData::CellData_t cd;
-      fM->fData->GetCellData(fM->fCellList[fTowerPicked], cd);
+      fM->fData->GetCellData(fM->fCellList[fTowerPicked], fM->fPhi, fM->fPhiRng, cd);
       switch(idxLeft)
       {
          case 0:
@@ -546,7 +561,7 @@ void TEveCaloLegoGL::DrawZScales3D(TGLRnrCtx & rnrCtx,
             azX  =  cd.EtaMin();      azY  =  cd.PhiMax();
             break;
       }
-      DrawZAxis(rnrCtx, azX,  azY);        
+      DrawZAxis(rnrCtx, azX,  azY);
    }
 } // DrawZScales3D
 
@@ -606,135 +621,140 @@ void TEveCaloLegoGL::DrawXYScales(TGLRnrCtx & rnrCtx,
          break;
    }
 
- 
-  
-   Float_t zOff =  -fDataMax*0.03;
+   Float_t zOff  = -fDataMax*0.03;
+   Float_t zOff2 =  zOff*0.5;
+
+
+   Float_t rxy = (fEtaAxis->GetXmax()-fEtaAxis->GetXmin())/(fPhiAxis->GetXmax()-fPhiAxis->GetXmin());
+   Float_t yOff  =  0.03*TMath::Sign(y1-y0, axY)/rxy;
+   Float_t yOff2 =  yOff*0.5;
+
+   Float_t xOff  =  0.03*TMath::Sign(x1-x0, ayX)*rxy;
+   Float_t xOff2 =  xOff*0.5;
 
-   // XY labels
    glPushMatrix();
    glTranslatef(0, 0, zOff);
-   fNumFont.PreRender(kFALSE);     
+   fNumFont.PreRender(kFALSE);
    TGLUtil::Color(fM->fFontColor);
 
-   // title
-   RnrText("h", axtX, 1.1f*axY, 0, fSymbolFont, (axY>0 && ayX>0) || (axY<0 && ayX<0));
-   RnrText("f", 1.1f*ayX, aytY, 0, fSymbolFont, (ayX>0 && axY<0) || (ayX<0 && axY>0));
+   // titles
+   RnrText("h", axtX, axY+yOff, 0, fSymbolFont, (axY>0 && ayX>0) || (axY<0 && ayX<0));
+   RnrText("f", ayX+xOff, aytY, 0, fSymbolFont, (ayX>0 && axY<0) || (ayX<0 && axY>0));
 
-   // X optimised limits
+   // X labels
    Double_t oXmin, oXmax, oXbw;
    Int_t oXndiv;
    THLimitsFinder::Optimize(x0, x1, fM->fNZSteps, oXmin, oXmax, oXndiv, oXbw);
    for (Int_t i=0; i<=oXndiv; i++)
-      RnrText(Form("%.0f", oXmin + oXbw*i), oXmin+oXbw*i, axY + TMath::Sign(fTMSize*3,axY), 0, fNumFont, 2);
+      RnrText(TEveUtil::FormAxisValue(oXmin + oXbw*i), oXmin+oXbw*i, axY + TMath::Sign(yOff*1.5f,axY), 0, fNumFont, 2);
 
-   // Y optimised limits
+   // Y labels
    Double_t oYmin, oYmax, oYbw;
    Int_t oYndiv;
    THLimitsFinder::Optimize(y0, y1, fM->fNZSteps, oYmin, oYmax, oYndiv, oYbw);
    for (Int_t i=0; i<=oYndiv; ++i)
-      RnrText(Form("%.0f", oYmin + oYbw*i), ayX + TMath::Sign(fTMSize*3,ayX), oYmin+oYbw*i, 0, fNumFont, 2);
+      RnrText(TEveUtil::FormAxisValue(oYmin + oYbw*i), ayX + TMath::Sign(xOff*1.5f,ayX), oYmin+oYbw*i, 0, fNumFont, 2);
 
    glPopMatrix();
    fNumFont.PostRender();
 
-   // XY tick-marks
-   TGLUtil::Color(fM->fGridColor);
+
+   /**************************************************************************/
+   // draw X  axis lines
+
+   glPushMatrix();
+   glTranslatef(0, axY, 0);
+   glBegin(GL_LINES);
+   // body
+   glVertex3f(x0, 0, 0);
+   glVertex3f(x1, 0, 0);
+   // tick-marks
+   Double_t oXmin2, oXmax2, oXbw2;
+   Int_t oXndiv2;
+   THLimitsFinder::Optimize(oXmin, oXbw+oXmin, fM->fNZSteps, oXmin2, oXmax2, oXndiv2, oXbw2);
+   Float_t xt = oXmin;
+   Float_t xt2;
+   for(Int_t i=0; i<=oXndiv; i++)
    {
-     
-      // second order tick-marks
-      Double_t oXmin2, oXmax2, oXbw2;
-      Int_t oXndiv2;
-      Float_t zOff2 = zOff*0.5;
-      Float_t yOff =  axY *0.03;
-      Float_t yOff2 = yOff*0.5;
- 
-      glPushMatrix();
-      glTranslatef(0, axY, 0);
-      glBegin(GL_LINES);
-      glVertex3f(x0, 0, 0);
-      glVertex3f(x1, 0, 0);
-      THLimitsFinder::Optimize(oXmin, oXbw+oXmin, fM->fNZSteps, oXmin2, oXmax2, oXndiv2, oXbw2);
-      Float_t xt = oXmin;
-      Float_t xt2;
-      for(Int_t i=0; i<=oXndiv; i++)
+      glVertex3f(xt, 0,    0);
+      glVertex3f(xt, 0,    zOff);
+      glVertex3f(xt, 0,    0);
+      glVertex3f(xt, yOff, 0);
+      xt2 = xt;
+      for (Int_t j=0; j<=oXndiv2; j++)
       {
-         glVertex3f(xt, 0, 0);
-         glVertex3f(xt, 0, zOff);
-         glVertex3f(xt, 0, 0);
-         glVertex3f(xt, 0+yOff, 0);
-         xt2 = xt;
-         for (Int_t j=0; j<=oXndiv2; j++)
-         {
-            if (xt2 >= x1) break;
-            glVertex3f(xt2, 0, 0);
-            glVertex3f(xt2, 0, zOff2);
-            glVertex3f(xt2, 0, 0);
-            glVertex3f(xt2, yOff2, 0);
-            xt2 += oXbw2;
-         }
-         xt += oXbw;
-      }
-      // draw wertices below optimised minimum
-      xt2 = oXmin;
-      while(xt2 > x0)
-      {
-         glVertex3f(xt2, 0, 0);
-         glVertex3f(xt2, 0, zOff2);
-         glVertex3f(xt2, 0, 0);
+         if (xt2 >= x1) break;
+         glVertex3f(xt2, 0,     0);
+         glVertex3f(xt2, 0,     zOff2);
+         glVertex3f(xt2, 0,     0);
          glVertex3f(xt2, yOff2, 0);
-         xt2 -= oXbw2;
+         xt2 += oXbw2;
       }
+      xt += oXbw;
+   }
+   xt2 = oXmin;
+   while(xt2 > x0)
+   {
+      glVertex3f(xt2, 0,     0);
+      glVertex3f(xt2, 0,     zOff2);
+      glVertex3f(xt2, 0,     0);
+      glVertex3f(xt2, yOff2, 0);
+      xt2 -= oXbw2;
+   }
+   glEnd();
+   glPopMatrix();
 
-      glEnd();
-      glPopMatrix();
+   /**************************************************************************/
+   // Y axis lines
 
-      glPushMatrix();
-      glTranslatef(ayX, 0, 0);
-      glBegin(GL_LINES);
-      glVertex3f(0, y0, 0);
-      glVertex3f(0, y1, 0);
-      Double_t oYmin2, oYmax2, oYbw2;
-      Int_t oYndiv2;
-      THLimitsFinder::Optimize(oYmin, oYbw+oYmin, fM->fNZSteps, oYmin2, oYmax2, oYndiv2, oYbw2);
-      Float_t yt = oYmin; 
-      Float_t yt2;
-      for(Int_t i=0; i<=oYndiv; i++)
-      {
-         glVertex3f(0, yt, 0);
-         glVertex3f(0, yt, zOff);
-         glVertex3f(0, yt, 0);
-         glVertex3f(yOff, yt, 0);
-         yt2 = yt;
-         for (Int_t j=0; j<=oYndiv2; j++)
-         {  
-            if (yt2 >= y1) break;
-            glVertex3f(0, yt2, 0);
-            glVertex3f(0, yt2, zOff2);
-            glVertex3f(0, yt2, 0);
-            glVertex3f(yOff2, yt2, 0);
-            yt2 += oYbw2;
-         }
-         yt += oYbw;
-      }
-      yt2 = oYmin;
-      while(yt2 > y0)
+   glPushMatrix();
+   glTranslatef(ayX, 0, 0);
+   glBegin(GL_LINES);
+   // body
+   glVertex3f(0, y0, 0);
+   glVertex3f(0, y1, 0);
+   // tick-marks
+   Double_t oYmin2, oYmax2, oYbw2;
+   Int_t oYndiv2;
+   THLimitsFinder::Optimize(oYmin, oYbw+oYmin, fM->fNZSteps, oYmin2, oYmax2, oYndiv2, oYbw2);
+   Float_t yt = oYmin;
+   Float_t yt2;
+   for(Int_t i=0; i<=oYndiv; i++)
+   {
+      glVertex3f(0,    yt, 0);
+      glVertex3f(0,    yt, zOff);
+      glVertex3f(0,    yt, 0);
+      glVertex3f(xOff, yt, 0);
+      yt2 = yt;
+      for (Int_t j=0; j<=oYndiv2; j++)
       {
-         glVertex3f(0, yt2, 0);
-         glVertex3f(0, yt2, zOff2);
-         glVertex3f(0, yt2, 0);
-         glVertex3f(yOff2, yt2, 0);
-         yt2 -= oYbw2;  
+         if (yt2 >= y1) break;
+         glVertex3f(0,     yt2, 0);
+         glVertex3f(0,     yt2, zOff2);
+         glVertex3f(0,     yt2, 0);
+         glVertex3f(xOff2, yt2, 0);
+         yt2 += oYbw2;
       }
-      glEnd();
-      glPopMatrix();
+      yt += oYbw;
+   }
+   yt2 = oYmin;
+   while(yt2 > y0)
+   {
+      glVertex3f(0,     yt2, 0);
+      glVertex3f(0,     yt2, zOff2);
+      glVertex3f(0,     yt2, 0);
+      glVertex3f(xOff2, yt2, 0);
+      yt2 -= oYbw2;
    }
+   glEnd();
+   glPopMatrix();
+
 } // DrawXYScales
 
 //______________________________________________________________________________
-Int_t TEveCaloLegoGL::GetGridStep(Int_t axId, const TAxis* ax, TGLRnrCtx &rnrCtx) const
+Int_t TEveCaloLegoGL::GetGridStep(Int_t axId, TGLRnrCtx &rnrCtx) const
 {
    // Calculate view-dependent grid density.
-
    GLdouble xp0, yp0, zp0, xp1, yp1, zp1;
    GLdouble mm[16];
    GLint    vp[4];
@@ -742,91 +762,107 @@ Int_t TEveCaloLegoGL::GetGridStep(Int_t axId, const TAxis* ax, TGLRnrCtx &rnrCtx
    glGetIntegerv(GL_VIEWPORT, vp);
    const GLdouble *pm = rnrCtx.RefCamera().RefLastNoPickProjM().CArr();
 
-   for (Int_t idx =0; idx<fNBinSteps; ++idx)
+   Int_t firstX = fEtaAxis->GetFirst();
+   Int_t lastX  = fEtaAxis->GetLast();
+   Int_t firstY = fPhiAxis->GetFirst();
+   Int_t lastY  = fPhiAxis->GetLast();
+
+
+   Float_t gap;
+
+   if (axId == 0)
    {
-      if (axId == 0)
+      Float_t y0 = fPhiAxis->GetBinLowEdge(firstY);
+      for (Int_t idx =0; idx<fNBinSteps; ++idx)
       {
-         gluProject(ax->GetBinLowEdge(0), 0, 0, mm, pm, vp, &xp0, &yp0, &zp0);
-         gluProject(ax->GetBinLowEdge(fBinSteps[idx]), 0, 0, mm, pm, vp, &xp1, &yp1, &zp1);
+         if (firstX +fBinSteps[idx] > lastX) return 1;
+         gluProject(fEtaAxis->GetBinLowEdge(firstX), y0, 0, mm, pm, vp, &xp0, &yp0, &zp0);
+         gluProject(fEtaAxis->GetBinLowEdge(firstX+fBinSteps[idx]), y0, 0, mm, pm, vp, &xp1, &yp1, &zp1);
+         gap = TMath::Sqrt((xp0-xp1)*(xp0-xp1) + (yp0-yp1)*(yp0-yp1));
+         if (gap>fM->fBinWidth)
+            return fBinSteps[idx];
       }
-      else
-      {
-         gluProject(0, ax->GetBinLowEdge(0), 0, mm, pm, vp, &xp0, &yp0, &zp0);
-         gluProject(0, ax->GetBinLowEdge(fBinSteps[idx]), 0, mm, pm, vp, &xp1, &yp1, &zp1);
-      }
-
-      Float_t  gap = TMath::Sqrt((xp0-xp1)*(xp0-xp1) + (yp0-yp1)*(yp0-yp1));
-      if (gap>fM->fBinWidth)
+   }
+   else if (axId == 1)
+   {
+      Float_t x0 = fEtaAxis->GetBinLowEdge(firstX);
+      for (Int_t idx =firstY; idx<fNBinSteps; ++idx)
       {
-         return fBinSteps[idx];
+         if (firstY +fBinSteps[idx] > lastY) return 1;
+         gluProject(x0, fEtaAxis->GetBinLowEdge(firstY), 0, mm, pm, vp, &xp0, &yp0, &zp0);
+         gluProject(x0, fEtaAxis->GetBinLowEdge(firstY+fBinSteps[idx]), 0, mm, pm, vp, &xp1, &yp1, &zp1);
+         Float_t  gap = TMath::Sqrt((xp0-xp1)*(xp0-xp1) + (yp0-yp1)*(yp0-yp1));
+         if (gap>fM->fBinWidth)
+            return fBinSteps[idx];
       }
    }
-   return fBinSteps[fNBinSteps-1];
+   return 1;
 }
 
-//______________________________________________________________________________
+ //______________________________________________________________________________
 void TEveCaloLegoGL::DrawHistBase(TGLRnrCtx &rnrCtx) const
 {
    // Draw basic histogram components: x-y grid
 
+   Int_t es = GetGridStep(0, rnrCtx);
+   Int_t ps = GetGridStep(1, rnrCtx);
+
+   Float_t eta0 = fM->fEtaMin;
+   Float_t eta1 = fM->fEtaMax;
+   Float_t phi0 = fM->GetPhiMin();
+   Float_t phi1 = fM->GetPhiMax();
+
    TGLCapabilitySwitch lights_off(GL_LIGHTING, kFALSE);
    TGLCapabilitySwitch sw_blend(GL_BLEND, kTRUE);
 
-   const TAxis* ax = fM->fData->GetEtaBins();
-   const TAxis* ay = fM->fData->GetPhiBins();
-   Float_t eta0 = ax->GetBinLowEdge(0);
-   Float_t etaT = ax->GetBinUpEdge(ax->GetNbins());
-   Float_t phi0 = ay->GetBinLowEdge(0);
-   Float_t phiT = ay->GetBinUpEdge(ay->GetNbins());
-
    TGLUtil::Color(fM->fGridColor);
-   Int_t es = GetGridStep(0, ax, rnrCtx);
-   Int_t ps = GetGridStep(1, ay, rnrCtx);
+
    glBegin(GL_LINES);
+
+   glVertex2f(eta0, phi0);
+   glVertex2f(eta0, phi1);
+   glVertex2f(eta1, phi0);
+   glVertex2f(eta1, phi1);
+
+   glVertex2f(eta0, phi0);
+   glVertex2f(eta1, phi0);
+   glVertex2f(eta0, phi1);
+   glVertex2f(eta1, phi1);
+
    if ((es == 1 && ps == 1) || fM->fProjection == TEveCaloLego::k3D)
    {
-      // original binning
-      glVertex2f(eta0, phi0);
-      glVertex2f(eta0, phiT);
-      for (Int_t i=1; i<ax->GetNbins(); i+= es)
+      // original
+      for (Int_t i=fEtaAxis->GetFirst(); i<fEtaAxis->GetLast(); i+= es)
       {
-         glVertex2f(ax->GetBinUpEdge(i), phi0);
-         glVertex2f(ax->GetBinUpEdge(i), phiT);
+         glVertex2f(fEtaAxis->GetBinUpEdge(i), phi0);
+         glVertex2f(fEtaAxis->GetBinUpEdge(i), phi1);
       }
-      glVertex2f(etaT, phi0);
-      glVertex2f(etaT, phiT);
 
-      glVertex2f(eta0, phi0);
-      glVertex2f(etaT, phi0);
-      for (Int_t j=1; j<ay->GetNbins(); j+=ps)
+      for (Int_t i=fPhiAxis->GetFirst(); i<fPhiAxis->GetLast(); i+= es)
       {
-         glVertex2f(eta0, ay->GetBinUpEdge(j));
-         glVertex2f(etaT, ay->GetBinUpEdge(j));
+         glVertex2f(eta0, fEtaAxis->GetBinUpEdge(i));
+         glVertex2f(eta1, fEtaAxis->GetBinUpEdge(i));
       }
-      glVertex2f(eta0, phiT);
-      glVertex2f(etaT, phiT);
    }
    else
    {
-      // equidistant binning
-      Int_t   nEta = TMath::CeilNint(ax->GetNbins()/es);
-      Int_t   nPhi = TMath::CeilNint(ay->GetNbins()/ps);
-      Float_t etaStep = (etaT-eta0)/nEta;
-      Float_t phiStep = (phiT-phi0)/nPhi;
-
-      Float_t a = eta0;
-      for (Int_t i=0; i<=nEta; i++)
+      // scaled
+      Float_t ebw = es*(eta1-eta0)/fEtaAxis->GetNbins();
+      Int_t i0 = Int_t(eta0/ebw);
+      Int_t i1 = Int_t(eta1/ebw);
+      for (Int_t i=i0; i<=i1; i++)
       {
-         glVertex2f(a, phi0);
-         glVertex2f(a, phiT);
-         a += etaStep;
+         glVertex2f(i*ebw, phi0);
+         glVertex2f(i*ebw, phi1);
       }
-      a = phi0;
-      for (Int_t i=0; i<=nPhi; i++)
+
+      Float_t pbw = ps*(phi1-phi0)/fPhiAxis->GetNbins();
+      Int_t j0 = Int_t(phi0/pbw);
+      Int_t j1 = Int_t(phi1/pbw);
+      for (Int_t j=j0; j<=j1; j++)
       {
-         glVertex2f(eta0, a);
-         glVertex2f(etaT, a);
-         a += phiStep;
+         glVertex2f(eta0, j*pbw);
+         glVertex2f(eta1, j*pbw);
       }
    }
    glEnd();
@@ -834,13 +870,13 @@ void TEveCaloLegoGL::DrawHistBase(TGLRnrCtx &rnrCtx) const
    glPushAttrib(GL_ENABLE_BIT | GL_LINE_BIT | GL_POLYGON_BIT);
    glLineWidth(2);
 
-   // labels, titles and tickmarks
+   // axis
    if ( fM->fProjection == TEveCaloLego::k3D || rnrCtx.RefCamera().GetCamBase().GetBaseVec(1).Z() == 0)
-      DrawZScales3D(rnrCtx, eta0, etaT, phi0, phiT);
+      DrawZScales3D(rnrCtx, eta0, eta1, phi0, phi1);
    else
       DrawZScales2D(rnrCtx, eta0, phi0);
 
-   DrawXYScales(rnrCtx, eta0, etaT, phi0, phiT);
+   DrawXYScales(rnrCtx, eta0, eta1, phi0, phi1);
    glPopAttrib();
 }
 
@@ -877,17 +913,12 @@ void TEveCaloLegoGL::DrawCells2D(TGLRnrCtx & rnrCtx) const
 
    using namespace TMath;
 
-   const TAxis* ax = fM->fData->GetEtaBins();
-   const TAxis* ay = fM->fData->GetPhiBins();
-   Int_t es = GetGridStep(0, ax, rnrCtx);
-   Int_t ps = GetGridStep(1, ay, rnrCtx);
-   Float_t eta0 = ax->GetBinLowEdge(0);
-   Float_t etaT = ax->GetBinUpEdge(ax->GetNbins());
-   Float_t phi0 = ay->GetBinLowEdge(0);
-   Float_t phiT = ay->GetBinUpEdge(ay->GetNbins());
+   static const TEveException eh("TEveCaloLegoGL::DrawCells2D ");
 
    UChar_t col[4];
    Color_t defCol = fM->GetPalette()->GetDefaultColor();
+   Int_t es = GetGridStep(0, rnrCtx);
+   Int_t ps = GetGridStep(1, rnrCtx);
    if (es==1 && ps==1)
    {
       // draw in original binning
@@ -898,7 +929,7 @@ void TEveCaloLegoGL::DrawCells2D(TGLRnrCtx & rnrCtx) const
 
       for (TEveCaloData::vCellId_t::iterator it=fM->fCellList.begin(); it!=fM->fCellList.end(); it++)
       {
-         fM->fData->GetCellData(*it, cellData);
+         fM->fData->GetCellData(*it, fM->fPhi, fM->fPhiRng, cellData);
          glLoadName(name);
          glBegin(GL_QUADS);
          if ((*it).fTower != prevTower)
@@ -936,23 +967,34 @@ void TEveCaloLegoGL::DrawCells2D(TGLRnrCtx & rnrCtx) const
    else
    {
       // prepare values in the scaled cells
-      Int_t   nEta = CeilNint(ax->GetNbins()/es);
-      Int_t   nPhi = CeilNint(ay->GetNbins()/ps);
-      Float_t etaStep = (etaT-eta0)/nEta;
-      Float_t phiStep = (phiT-phi0)/nPhi;
+
+      Float_t eta0 = fM->fEtaMin;
+      Float_t eta1 = fM->fEtaMax;
+      Float_t phi0 = fM->GetPhiMin();
+      Float_t phi1 = fM->GetPhiMax();
+
+      Int_t   nEta = CeilNint(fEtaAxis->GetNbins()/es);
+      Int_t   nPhi = CeilNint(fPhiAxis->GetNbins()/ps);
+      Float_t etaStep = (eta1-eta0)/nEta;
+      Float_t phiStep = (phi1-phi0)/nPhi;
+
 
       std::vector<Float_t> vec;
-      vec.assign(nEta*nPhi, 0.f);
+      vec.assign((nEta)*(nPhi), 0.f);
+
       TEveCaloData::CellData_t cd;
       Float_t left, right, up, down; // cell corners
       for (TEveCaloData::vCellId_t::iterator it=fM->fCellList.begin(); it!=fM->fCellList.end(); it++)
       {
-         fM->fData->GetCellData(*it, cd);
+         fM->fData->GetCellData(*it, fM->fPhi, fM->fPhiRng, cd);
          Int_t iMin = FloorNint((cd.EtaMin()- eta0)/etaStep);
          Int_t iMax = CeilNint ((cd.EtaMax()- eta0)/etaStep);
          Int_t jMin = FloorNint((cd.PhiMin()- phi0)/phiStep);
          Int_t jMax = CeilNint ((cd.PhiMax()- phi0)/phiStep);
 
+         if (jMin <0)
+            throw(eh + "cell phi %f less than set minimum %f.", cd.PhiMin(), cd.PhiMin());
+
          for (Int_t i=iMin; i<iMax; i++)
          {
             left  = i*etaStep;
@@ -983,6 +1025,7 @@ void TEveCaloLegoGL::DrawCells2D(TGLRnrCtx & rnrCtx) const
       for (std::vector<Float_t>::iterator it=vec.begin(); it !=vec.end(); it++)
          if (*it > maxv) maxv = *it;
 
+
       Float_t paletteFac = fM->fPalette->GetHighLimit()*1.f/maxv;
       Float_t logMax = Log(maxv+1);
       Float_t logPaletteFac = fM->fPalette->GetHighLimit()*1.f/logMax;
@@ -992,35 +1035,33 @@ void TEveCaloLegoGL::DrawCells2D(TGLRnrCtx & rnrCtx) const
       glBegin(GL_QUADS);
       for (std::vector<Float_t>::iterator it=vec.begin(); it !=vec.end(); it++)
       {
-         if(*it>0)
+         Float_t logVal = Log(*it+1);
+         Float_t eta = Int_t(cid/nPhi)*etaStep + eta0;
+         Float_t phi = (cid -Int_t(cid/nPhi)*nPhi)*phiStep + phi0;
+         if ( fM->f2DMode == TEveCaloLego::kValColor)
          {
-            Float_t logVal = Log(*it+1);
-            Float_t eta = Int_t(cid/nPhi)*etaStep + eta0;
-            Float_t phi = (cid -Int_t(cid/nPhi)*nPhi)*phiStep + phi0;
-            if (fM->f2DMode == TEveCaloLego::kValColor)
-            {
-               fM->fPalette->ColorFromValue((Int_t)(logVal*logPaletteFac), col);
-               TGLUtil::Color4ubv(col);
-               {
-                  glVertex3f(eta        , phi,         (*it)*paletteFac);
-                  glVertex3f(eta+etaStep, phi,         (*it)*paletteFac);
-                  glVertex3f(eta+etaStep, phi+phiStep, (*it)*paletteFac);
-                  glVertex3f(eta        , phi+phiStep, (*it)*paletteFac);
-               }
-            }
-            else if (fM->f2DMode == TEveCaloLego::kValSize)
+            fM->fPalette->ColorFromValue((Int_t)(logVal*logPaletteFac), col);
+            TGLUtil::Color4ubv(col);
+
             {
-               TGLUtil::Color(defCol);
-               eta += etaStep*0.5f;
-               phi += phiStep*0.5f;
-               etaW = etaStep*0.5f*logVal/logMax;
-               phiW = phiStep*0.5f*logVal/logMax;
-               glVertex3f(eta -etaW, phi -phiW, (*it)*paletteFac);
-               glVertex3f(eta +etaW, phi -phiW, (*it)*paletteFac);
-               glVertex3f(eta +etaW, phi +phiW, (*it)*paletteFac);
-               glVertex3f(eta -etaW, phi +phiW, (*it)*paletteFac);
+               glVertex3f(eta        , phi,         (*it)*paletteFac);
+               glVertex3f(eta+etaStep, phi,         (*it)*paletteFac);
+               glVertex3f(eta+etaStep, phi+phiStep, (*it)*paletteFac);
+               glVertex3f(eta        , phi+phiStep, (*it)*paletteFac);
             }
          }
+         else if (fM->f2DMode == TEveCaloLego::kValSize)
+         {
+            TGLUtil::Color(defCol);
+            eta += etaStep*0.5f;
+            phi += phiStep*0.5f;
+            etaW = etaStep*0.5f*logVal/logMax;
+            phiW = phiStep*0.5f*logVal/logMax;
+            glVertex3f(eta -etaW, phi -phiW, (*it)*paletteFac);
+            glVertex3f(eta +etaW, phi -phiW, (*it)*paletteFac);
+            glVertex3f(eta +etaW, phi +phiW, (*it)*paletteFac);
+            glVertex3f(eta -etaW, phi +phiW, (*it)*paletteFac);
+         }
          cid++;
       }
       glEnd();
@@ -1031,6 +1072,8 @@ void TEveCaloLegoGL::DrawCells2D(TGLRnrCtx & rnrCtx) const
 void TEveCaloLegoGL::DirectDraw(TGLRnrCtx & rnrCtx) const
 {
    // Draw the object.
+   fEtaAxis = fM->fData->GetEtaBins();
+   fPhiAxis = fM->fData->GetPhiBins();
 
    // projection type
    Bool_t cells3D;
@@ -1043,8 +1086,10 @@ void TEveCaloLegoGL::DirectDraw(TGLRnrCtx & rnrCtx) const
 
    // init cached variables
    fDataMax   = fM->fData->GetMaxVal();
-   fZAxisStep = fM->GetAxisStep(fDataMax);
-   fZAxisMax  = fZAxisStep*fM->fNZSteps;
+   Int_t ondiv;
+   Double_t omin, omax;
+   THLimitsFinder::Optimize(0, fDataMax, fM->fNZSteps, omin, omax, ondiv,  fZAxisStep);
+   fZAxisMax = (ondiv+1)*fZAxisStep;
 
    // cache
    fM->AssertPalette();
@@ -1053,13 +1098,21 @@ void TEveCaloLegoGL::DirectDraw(TGLRnrCtx & rnrCtx) const
       fDLCacheOK = kFALSE;
       fM->ResetCache();
       fM->fData->GetCellList(fM->fPalette->GetMinVal(), fM->fPalette->GetMaxVal(),
-                             (fM->fEtaMin + fM->fEtaMax)*0.5f, fM->fEtaMax - fM->fEtaMin,
+                             fM->GetEta(), fM->GetEtaRng()*0.5,
                              fM->fPhi, fM->fPhiRng, fM->fCellList);
       fM->fCacheOK = kTRUE;
    }
    if (cells3D && fDLCacheOK == kFALSE) MakeDisplayList();
 
 
+   // set modelview matrix
+   glPushMatrix();
+   glTranslatef(0, -fM->fPhi, 0);
+
+   glScalef((fEtaAxis->GetXmax()-fEtaAxis->GetXmin())/fM->GetEtaRng(),
+            0.5*(fPhiAxis->GetXmax()-fPhiAxis->GetXmin())/fM->fPhiRng,
+            fM->fCellZScale*fM->GetDefaultCellHeight()/fZAxisMax);
+
    glPushAttrib(GL_ENABLE_BIT | GL_LINE_BIT | GL_POLYGON_BIT);
    glLineWidth(1);
    glDisable(GL_LIGHTING);
@@ -1067,39 +1120,33 @@ void TEveCaloLegoGL::DirectDraw(TGLRnrCtx & rnrCtx) const
    glEnable(GL_NORMALIZE);
    glEnable(GL_POLYGON_OFFSET_FILL);
 
-   // make z coordinate and value equivalent
-   glPushMatrix();
-   glScalef(1.f, 1.f,fM->fCellZScale*fM->GetDefaultCellHeight()/fZAxisMax);
-
-
-   // draw cells
-   glPushName(0);
-   glPolygonOffset(0.8, 1);
-   cells3D ? DrawCells3D(rnrCtx):DrawCells2D(rnrCtx);
-   glPopName();
 
    // draw histogram base
    if (rnrCtx.Selection() == kFALSE && rnrCtx.Highlight() == kFALSE)
    {
       DrawHistBase(rnrCtx);
-      if (fM->fDrawHPlane) 
+      if (fM->fDrawHPlane)
       {
          glEnable(GL_BLEND);
          glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
          glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
          TGLUtil::ColorTransparency(fM->fPlaneColor, fM->fPlaneTransparency);
-         const TAxis* ax = fM->fData->GetEtaBins();
-         const TAxis* ay = fM->fData->GetPhiBins();
          Float_t zhp = fM->fHPlaneVal*fZAxisMax;
          glBegin(GL_POLYGON);
-         glVertex3f(ax->GetBinLowEdge(0), ay->GetBinLowEdge(0), zhp);
-         glVertex3f(ax->GetBinUpEdge(ax->GetNbins()), ay->GetBinLowEdge(0), zhp);
-         glVertex3f(ax->GetBinUpEdge(ax->GetNbins()), ay->GetBinUpEdge(ay->GetNbins()), zhp);
-         glVertex3f(ax->GetBinLowEdge(0), ay->GetBinUpEdge(ay->GetNbins()), zhp);
+         glVertex3f(fM->fEtaMin, fM->GetPhiMin(), zhp);
+         glVertex3f(fM->fEtaMax, fM->GetPhiMin(), zhp);
+         glVertex3f(fM->fEtaMax, fM->GetPhiMax(), zhp);
+         glVertex3f(fM->fEtaMin, fM->GetPhiMax(), zhp);
          glEnd();
       }
    }
 
+   // draw cells
+   glPushName(0);
+   glPolygonOffset(0.8, 1);
+   cells3D ? DrawCells3D(rnrCtx):DrawCells2D(rnrCtx);
+   glPopName();
+
    glPopMatrix();
    glPopAttrib();
 }
diff --git a/graf3d/eve/src/TEveCaloVizEditor.cxx b/graf3d/eve/src/TEveCaloVizEditor.cxx
index cb92133b3b8..b8039e16f27 100644
--- a/graf3d/eve/src/TEveCaloVizEditor.cxx
+++ b/graf3d/eve/src/TEveCaloVizEditor.cxx
@@ -101,7 +101,9 @@ void TEveCaloVizEditor::SetModel(TObject* obj)
 
    fM = dynamic_cast<TEveCaloViz*>(obj);
 
-   fEtaRng->SetLimits(fM->fEtaLowLimit, fM->fEtaHighLimit);
+   Double_t min, max;
+   fM->GetData()->GetEtaLimits(min, max);
+   fEtaRng->SetLimits((Float_t)min, (Float_t)max);
    fEtaRng->SetValues(fM->fEtaMin, fM->fEtaMax);
 
    fPhi->SetValue(fM->fPhi*TMath::RadToDeg());
diff --git a/graf3d/eve/src/TEveLegoOverlay.cxx b/graf3d/eve/src/TEveLegoOverlay.cxx
index 27d8d3e0e42..013b16992e9 100644
--- a/graf3d/eve/src/TEveLegoOverlay.cxx
+++ b/graf3d/eve/src/TEveLegoOverlay.cxx
@@ -20,6 +20,9 @@
 #include <TGLUtil.h>
 #include <TGLCamera.h>
 
+#include <THLimitsFinder.h>
+
+
 //______________________________________________________________________________
 //
 //
@@ -74,25 +77,10 @@ void TEveLegoOverlay::DrawSlider(TGLRnrCtx& rnrCtx)
 {
    // Draw slider and calorimeter Z scale on left side of screen.
 
-   Float_t w = fButtonW*fMenuW*0.5f;
-   glTranslatef(0, fSliderPosY, 0);
-
-   Int_t tickval = fCalo->GetAxisStep(fCalo->GetData()->GetMaxVal());
-   Float_t scale = fSliderH/(fCalo->GetNZSteps()*tickval);
-   // event handling
-   if ( rnrCtx.Selection())
-   {
-      TGLUtil::Color(2);
-      glLoadName(2);
-      glBegin(GL_QUADS);
-      glVertex2f(-w, 0);
-      glVertex2f( w, 0);
-      glVertex2f( w, fSliderH);
-      glVertex2f(-w, fSliderH);
-      glEnd();
-   }
+   TGLUtil::Color(fCalo->GetFontColor());
+   Float_t off = -0.01; 
 
-   // labels
+   // font
    TGLRect& wprt = rnrCtx.RefCamera().RefViewport();
    Float_t cfs =   wprt.Height()*fSliderH*0.07;
    Int_t fs = TGLFontManager::GetFontSize(cfs);
@@ -106,45 +94,86 @@ void TEveLegoOverlay::DrawSlider(TGLRnrCtx& rnrCtx)
       rnrCtx.RegisterFont(fs, "arial",  TGLFont::kPixmap, fNumFont);
    }
 
-   TGLUtil::Color(fCalo->GetFontColor());
-   Float_t off = -0.008;
+   // optimize binning
+   Float_t w = fButtonW*fMenuW*0.5f;
+   glTranslatef(0, fSliderPosY, 0);
+   Int_t nsteps, ndiv;
+   Double_t omin, omax, zmax, tickval;
+   THLimitsFinder::Optimize(0, fCalo->GetData()->GetMaxVal(), fCalo->GetNZSteps(), omin, omax, ndiv, tickval);
+   nsteps = ndiv+1;
+   zmax = nsteps*tickval;
+   
+   // labels
    fNumFont.PreRender(kFALSE);
-   Int_t val = 0;
    glPushMatrix();
    glTranslatef(3*off, 0, 0);
-   for(Int_t i=0; i<=fCalo->GetNZSteps(); i++)
+   glScalef(1, fSliderH/zmax , 1.);
+   Double_t val = 0;
+   for(Int_t i=0; i<=nsteps; i++)
    {
-      RenderText(Form("%d", val), val*scale);
+      RenderText(TEveUtil::FormAxisValue(val), val);
       val+= tickval;
    }
    glPopMatrix();
    fNumFont.PostRender();
 
-   // tick-marks
-   Int_t nt = 5*fCalo->GetNZSteps();
-   Float_t tmStep =  fSliderH/nt;
 
-   glLineWidth(2);
-   glBegin(GL_LINES);
-   glVertex2f(0, 0);
-   glVertex2f(0, tickval*scale*fCalo->GetNZSteps());
-   glEnd();
+  // event handling
+   if (rnrCtx.Selection())
+   {
+      glLoadName(2);
+      glBegin(GL_QUADS);
+      glVertex2f(-w, 0);
+      glVertex2f( w, 0);
+      glVertex2f( w, fSliderH);
+      glVertex2f(-w, fSliderH);
+      glEnd();
+   }
+
 
+   glPushMatrix();
+   glScalef(1, fSliderH/zmax , 1.);
+
+   // body
    glLineWidth(1);
    glBegin(GL_LINES);
-   for (Int_t i = 0; i <= nt; ++i)
+   glVertex2f(0, 0);
+   glVertex2f(0, zmax);
+   // primary tick-marks
+   Double_t tv1= 0;
+   for (Int_t i = 0; i <= nsteps; ++i)
    {
-      glVertex2f(0,  i*tmStep);
-      glVertex2f((i % 5) ? off :2*off,  i*tmStep);
+      glVertex2d(0,  tv1);
+      glVertex2d(2*off , tv1);
+      tv1+= tickval;
+   }
+
+   // secondary tick-marks
+   Double_t omin2, zmax2, tickval2;
+   Int_t nsteps2;
+   THLimitsFinder::Optimize(0, tickval, fCalo->GetNZSteps(), omin2, zmax2, nsteps2, tickval2);
+   Int_t nt2 = Int_t(zmax/tickval2);
+   Float_t step2 = zmax/nt2;
+
+   Double_t tv2= 0;
+   for (Int_t i = 0; i <= nt2; ++i)
+   {
+      glVertex2d(0,  tv2);
+      glVertex2d(off , tv2);
+      tv2+= step2;
    }
    glEnd();
 
+   glPopMatrix();
+   
+
    // marker
    TGLUtil::Color((fActiveID == 2) ? fActiveCol : 3);
    glPointSize(8);
    glBegin(GL_POINTS);
    glVertex3f(0, fSliderVal*fSliderH, -0.1);
-   glEnd();
+   glEnd(); 
+
 }
 
 /******************************************************************************/
-- 
GitLab