TGLTH3Composition.cxx

Go to the documentation of this file.
00001 // @(#)root/gl:$Id: TGLTH3Composition.cxx 34286 2010-07-01 20:38:57Z rdm $
00002 // Author:  Timur Pocheptsov  07/08/2009
00003 
00004 #include <stdexcept>
00005 
00006 #include "KeySymbols.h"
00007 #include "TVirtualX.h"
00008 #include "Buttons.h"
00009 #include "TString.h"
00010 #include "TError.h"
00011 #include "TColor.h"
00012 #include "TROOT.h"
00013 #include "TMath.h"
00014 
00015 #include "TGLTH3Composition.h"
00016 #include "TGLIncludes.h"
00017 
00018 //
00019 //TGLTH3Composition.
00020 //
00021 
00022 ClassImp(TGLTH3Composition)
00023 
00024 //______________________________________________________________________________
00025 TGLTH3Composition::TGLTH3Composition()
00026 {
00027    //I have to define it, since explicit copy ctor was declared.
00028 }
00029 
00030 namespace {
00031 
00032 void CompareAxes(const TAxis *a1, const TAxis *a2, const TString &axisName);
00033 
00034 }
00035 
00036 //______________________________________________________________________________
00037 void TGLTH3Composition::AddTH3(const TH3 *h, ETH3BinShape shape)
00038 {
00039    //Add TH3 into collection. Throw if fHists is not empty
00040    //but ranges are not equal.
00041    const TAxis *xa = h->GetXaxis();
00042    const TAxis *ya = h->GetYaxis();
00043    const TAxis *za = h->GetZaxis();
00044 
00045    if (!fHists.size()) {
00046       //This is the first hist in a composition,
00047       //take its ranges and reset axes for the composition.
00048       fXaxis.Set(h->GetNbinsX(), xa->GetBinLowEdge(xa->GetFirst()), xa->GetBinUpEdge(xa->GetLast()));
00049       fYaxis.Set(h->GetNbinsY(), ya->GetBinLowEdge(ya->GetFirst()), ya->GetBinUpEdge(ya->GetLast()));
00050       fZaxis.Set(h->GetNbinsZ(), za->GetBinLowEdge(za->GetFirst()), za->GetBinUpEdge(za->GetLast()));
00051    } else {
00052       CompareAxes(xa, GetXaxis(), "X");
00053       CompareAxes(ya, GetYaxis(), "Y");
00054       CompareAxes(za, GetZaxis(), "Z");
00055    }
00056 
00057    fHists.push_back(TH3Pair_t(h, shape));
00058 }
00059 
00060 //______________________________________________________________________________
00061 Int_t TGLTH3Composition::DistancetoPrimitive(Int_t px, Int_t py)
00062 {
00063    //Check if "this" is under cursor.
00064    if (!fPainter.get())
00065       return 9999;
00066 
00067    return fPainter->DistancetoPrimitive(px, py);
00068 }
00069 
00070 //______________________________________________________________________________
00071 void TGLTH3Composition::ExecuteEvent(Int_t event, Int_t px, Int_t py)
00072 {
00073    //Mouse and keyboard events.
00074    fPainter->ExecuteEvent(event, px, py);
00075 }
00076 
00077 //______________________________________________________________________________
00078 char *TGLTH3Composition::GetObjectInfo(Int_t /*px*/, Int_t /*py*/) const
00079 {
00080    //I cannot show bin content in a status bar -
00081    //since there can be several bins in one.
00082    static char message[] = "TH3 composition";
00083    return message;
00084 }
00085 
00086 //______________________________________________________________________________
00087 void TGLTH3Composition::Paint(Option_t * /*option*/)
00088 {
00089    //Paint a composition of 3d hists.
00090    if (!fHists.size())
00091       return;
00092 
00093    //create a painter.
00094    if (!fPainter.get())
00095       fPainter.reset(new TGLHistPainter(this));
00096 
00097    fPainter->Paint("dummy");
00098 }
00099 
00100 //
00101 //TGLTH3CompositionPainter.
00102 //
00103 
00104 ClassImp(TGLTH3CompositionPainter)
00105 
00106 //______________________________________________________________________________
00107 TGLTH3CompositionPainter::TGLTH3CompositionPainter(TGLTH3Composition *data, TGLPlotCamera *cam,
00108                                                    TGLPlotCoordinates *coord)
00109                              : TGLPlotPainter(data, cam, coord, kFALSE, kFALSE, kFALSE),
00110                                fData(data)
00111 {
00112    //Ctor.
00113 }
00114 
00115 //______________________________________________________________________________
00116 char *TGLTH3CompositionPainter::GetPlotInfo(Int_t /*px*/, Int_t /*py*/)
00117 {
00118    //Will be never called from TPad.
00119    static char message[] = "TH3 composition";
00120    return message;
00121 }
00122 
00123 //______________________________________________________________________________
00124 Bool_t TGLTH3CompositionPainter::InitGeometry()
00125 {
00126    if (!fData->fHists.size())
00127       return kFALSE;
00128 
00129    //Prepare plot painter.
00130    //Forget about log scale.
00131    fCoord->SetZLog(kFALSE);
00132    fCoord->SetYLog(kFALSE);
00133    fCoord->SetXLog(kFALSE);
00134 
00135    if (!fCoord->SetRanges(fHist, kFALSE, kTRUE))//kFALSE == drawErrors, kTRUE == zAsBins
00136       return kFALSE;
00137 
00138    fBackBox.SetPlotBox(fCoord->GetXRangeScaled(), fCoord->GetYRangeScaled(), fCoord->GetZRangeScaled());
00139    if (fCamera)
00140       fCamera->SetViewVolume(fBackBox.Get3DBox());
00141 
00142    //Loop on hists.
00143    const TH3 *h = fData->fHists[0].first;
00144    fMinMaxVal.second  = h->GetBinContent(fCoord->GetFirstXBin(),
00145                                          fCoord->GetFirstYBin(),
00146                                          fCoord->GetFirstZBin());
00147    fMinMaxVal.first = fMinMaxVal.second;
00148 
00149    for (UInt_t hNum = 0, lastH = fData->fHists.size(); hNum < lastH; ++hNum) {
00150       h = fData->fHists[hNum].first;
00151       for (Int_t ir = fCoord->GetFirstXBin(); ir <= fCoord->GetLastXBin(); ++ir) {
00152          for (Int_t jr = fCoord->GetFirstYBin(); jr <= fCoord->GetLastYBin(); ++jr) {
00153             for (Int_t kr = fCoord->GetFirstZBin();  kr <= fCoord->GetLastZBin(); ++kr) {
00154                fMinMaxVal.second = TMath::Max(fMinMaxVal.second, h->GetBinContent(ir, jr, kr));
00155                fMinMaxVal.first = TMath::Min(fMinMaxVal.first, h->GetBinContent(ir, jr, kr));
00156             }
00157          }
00158       }
00159    }
00160 
00161    if (fCoord->Modified()) {
00162       fUpdateSelection = kTRUE;
00163       fCoord->ResetModified();
00164    }
00165 
00166    return kTRUE;
00167 }
00168 
00169 //______________________________________________________________________________
00170 void TGLTH3CompositionPainter::StartPan(Int_t px, Int_t py)
00171 {
00172    //Move plot or box cut.
00173    fMousePosition.fX = px;
00174    fMousePosition.fY = fCamera->GetHeight() - py;
00175    fCamera->StartPan(px, py);
00176    fBoxCut.StartMovement(px, fCamera->GetHeight() - py);
00177 }
00178 
00179 //______________________________________________________________________________
00180 void TGLTH3CompositionPainter::Pan(Int_t px, Int_t py)
00181 {
00182    // User's moving mouse cursor, with middle mouse button pressed (for pad).
00183    // Calculate 3d shift related to 2d mouse movement.
00184    if (fSelectedPart >= fSelectionBase) {//Pan camera.
00185       SaveModelviewMatrix();
00186       SaveProjectionMatrix();
00187 
00188       fCamera->SetCamera();
00189       fCamera->Apply(fPadPhi, fPadTheta);
00190       fCamera->Pan(px, py);
00191 
00192       RestoreProjectionMatrix();
00193       RestoreModelviewMatrix();
00194    } else if (fSelectedPart > 0) {
00195       //Convert py into bottom-top orientation.
00196       //Possibly, move box here
00197       py = fCamera->GetHeight() - py;
00198       SaveModelviewMatrix();
00199       SaveProjectionMatrix();
00200 
00201       fCamera->SetCamera();
00202       fCamera->Apply(fPadPhi, fPadTheta);
00203 
00204       if (!fHighColor) {
00205          if (fBoxCut.IsActive() && (fSelectedPart >= kXAxis && fSelectedPart <= kZAxis))
00206             fBoxCut.MoveBox(px, py, fSelectedPart);
00207       }
00208 
00209       RestoreProjectionMatrix();
00210       RestoreModelviewMatrix();
00211    }
00212 
00213    fMousePosition.fX = px, fMousePosition.fY = py;
00214    fUpdateSelection = kTRUE;
00215 }
00216 
00217 //______________________________________________________________________________
00218 void TGLTH3CompositionPainter::AddOption(const TString &/*option*/)
00219 {
00220    //No options for composition.
00221 }
00222 
00223 //______________________________________________________________________________
00224 void TGLTH3CompositionPainter::ProcessEvent(Int_t event, Int_t /*px*/, Int_t py)
00225 {
00226    //Switch on/off box cut.
00227    if (event == kButton1Double && fBoxCut.IsActive()) {
00228       fBoxCut.TurnOnOff();
00229       if (!gVirtualX->IsCmdThread())
00230          gROOT->ProcessLineFast(Form("((TGLPlotPainter *)0x%lx)->Paint()", (ULong_t)this));
00231       else
00232          Paint();
00233    } else if (event == kKeyPress && (py == kKey_c || py == kKey_C)) {
00234       if (fHighColor)
00235          Info("ProcessEvent", "Switch to true color mode to use box cut");
00236       else {
00237          fBoxCut.TurnOnOff();
00238          fUpdateSelection = kTRUE;
00239       }
00240    }
00241 }
00242 
00243 //______________________________________________________________________________
00244 void TGLTH3CompositionPainter::InitGL()const
00245 {
00246    // Initialize some gl state variables.
00247    glEnable(GL_DEPTH_TEST);
00248    glEnable(GL_LIGHTING);
00249    glEnable(GL_LIGHT0);
00250    glEnable(GL_CULL_FACE);
00251    glCullFace(GL_BACK);
00252 
00253    glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
00254 }
00255 
00256 //______________________________________________________________________________
00257 void TGLTH3CompositionPainter::DeInitGL()const
00258 {
00259    //Return back some gl state variables.
00260    glDisable(GL_DEPTH_TEST);
00261    glDisable(GL_LIGHTING);
00262    glDisable(GL_LIGHT0);
00263    glDisable(GL_CULL_FACE);
00264    glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
00265 }
00266 
00267 //______________________________________________________________________________
00268 void TGLTH3CompositionPainter::DrawPlot()const
00269 {
00270    //Draw composition of TH3s.
00271 
00272    //Shift plot to point of origin.
00273    const Rgl::PlotTranslation trGuard(this);
00274 
00275    fBackBox.DrawBox(fSelectedPart, fSelectionPass, fZLevels, fHighColor);
00276 
00277    if (!fSelectionPass) {
00278       glEnable(GL_POLYGON_OFFSET_FILL);//[0
00279       glPolygonOffset(1.f, 1.f);
00280    } else
00281       return;
00282 
00283    //Using front point, find the correct order to draw boxes from
00284    //back to front/from bottom to top (it's important only for semi-transparent boxes).
00285    const Int_t frontPoint = fBackBox.GetFrontPoint();
00286    Int_t irInit = fCoord->GetFirstXBin(), iInit = 0;
00287    const Int_t nX = fCoord->GetNXBins();
00288    Int_t jrInit = fCoord->GetFirstYBin(), jInit = 0;
00289    const Int_t nY = fCoord->GetNYBins();
00290    Int_t krInit = fCoord->GetFirstZBin(), kInit = 0;
00291    const Int_t nZ = fCoord->GetNZBins();
00292 
00293    const Int_t addI = frontPoint == 2 || frontPoint == 1 ? 1 : (iInit = nX - 1, irInit = fCoord->GetLastXBin(), -1);
00294    const Int_t addJ = frontPoint == 2 || frontPoint == 3 ? 1 : (jInit = nY - 1, jrInit = fCoord->GetLastYBin(), -1);
00295    const Int_t addK = fBackBox.Get2DBox()[frontPoint + 4].Y() < fBackBox.Get2DBox()[frontPoint].Y() ? 1
00296                      : (kInit = nZ - 1, krInit = fCoord->GetLastZBin(),-1);
00297    const Double_t xScale = fCoord->GetXScale();
00298    const Double_t yScale = fCoord->GetYScale();
00299    const Double_t zScale = fCoord->GetZScale();
00300    const TAxis   *xA = fXAxis;
00301    const TAxis   *yA = fYAxis;
00302    const TAxis   *zA = fZAxis;
00303 
00304    Double_t maxContent = TMath::Max(TMath::Abs(fMinMaxVal.first), TMath::Abs(fMinMaxVal.second));
00305    if(!maxContent)//bad, find better way to check zero.
00306       maxContent = 1.;
00307 
00308    for (UInt_t hNum = 0; hNum < fData->fHists.size(); ++hNum) {
00309       const TH3 *h = fData->fHists[hNum].first;
00310       const TGLTH3Composition::ETH3BinShape shape = fData->fHists[hNum].second;
00311       SetColor(h->GetFillColor());
00312 
00313       for(Int_t ir = irInit, i = iInit; addI > 0 ? i < nX : i >= 0; ir += addI, i += addI) {
00314          for(Int_t jr = jrInit, j = jInit; addJ > 0 ? j < nY : j >= 0; jr += addJ, j += addJ) {
00315             for(Int_t kr = krInit, k = kInit; addK > 0 ? k < nZ : k >= 0; kr += addK, k += addK) {
00316                const Double_t binContent = h->GetBinContent(ir, jr, kr);
00317                const Double_t w = TMath::Abs(binContent) / maxContent;
00318                if (!w)
00319                   continue;
00320 
00321                const Double_t xMin = xScale * (xA->GetBinLowEdge(ir) / 2 + xA->GetBinUpEdge(ir) / 2 - w * xA->GetBinWidth(ir) / 2);
00322                const Double_t xMax = xScale * (xA->GetBinLowEdge(ir) / 2 + xA->GetBinUpEdge(ir) / 2 + w * xA->GetBinWidth(ir) / 2);
00323                const Double_t yMin = yScale * (yA->GetBinLowEdge(jr) / 2 + yA->GetBinUpEdge(jr) / 2 - w * yA->GetBinWidth(jr) / 2);
00324                const Double_t yMax = yScale * (yA->GetBinLowEdge(jr) / 2 + yA->GetBinUpEdge(jr) / 2 + w * yA->GetBinWidth(jr) / 2);
00325                const Double_t zMin = zScale * (zA->GetBinLowEdge(kr) / 2 + zA->GetBinUpEdge(kr) / 2 - w * zA->GetBinWidth(kr) / 2);
00326                const Double_t zMax = zScale * (zA->GetBinLowEdge(kr) / 2 + zA->GetBinUpEdge(kr) / 2 + w * zA->GetBinWidth(kr) / 2);
00327 
00328                if (fBoxCut.IsActive() && fBoxCut.IsInCut(xMin, xMax, yMin, yMax, zMin, zMax))
00329                   continue;
00330 
00331                if (shape == TGLTH3Composition::kSphere)
00332                   Rgl::DrawSphere(&fQuadric, xMin, xMax, yMin, yMax, zMin, zMax);
00333                else
00334                   Rgl::DrawBoxFront(xMin, xMax, yMin, yMax, zMin, zMax, frontPoint);
00335             }
00336          }
00337       }
00338    }
00339 
00340    if (fBoxCut.IsActive())
00341       fBoxCut.DrawBox(fSelectionPass, fSelectedPart);
00342 
00343    glDisable(GL_POLYGON_OFFSET_FILL);//0]
00344    const TGLDisableGuard lightGuard(GL_LIGHTING);//[2 - 2]
00345    glColor4d(0., 0., 0., 0.25);
00346    glPolygonMode(GL_FRONT, GL_LINE);//[3
00347 
00348    const TGLEnableGuard blendGuard(GL_BLEND);//[4-4] + 1]
00349    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00350    const TGLEnableGuard smoothGuard(GL_LINE_SMOOTH);//[5-5]
00351    glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
00352 
00353    for (UInt_t hNum = 0; hNum < fData->fHists.size(); ++hNum) {
00354       if (fData->fHists[hNum].second == TGLTH3Composition::kSphere)
00355          continue;//No outlines for spherical bins.
00356 
00357       const TH3 *h = fData->fHists[hNum].first;
00358 
00359       for(Int_t ir = irInit, i = iInit; addI > 0 ? i < nX : i >= 0; ir += addI, i += addI) {
00360          for(Int_t jr = jrInit, j = jInit; addJ > 0 ? j < nY : j >= 0; jr += addJ, j += addJ) {
00361             for(Int_t kr = krInit, k = kInit; addK > 0 ? k < nZ : k >= 0; kr += addK, k += addK) {
00362                const Double_t w = TMath::Abs(h->GetBinContent(ir, jr, kr)) / maxContent;
00363                if (!w)
00364                   continue;
00365 
00366                const Double_t xMin = xScale * (xA->GetBinLowEdge(ir) / 2 + xA->GetBinUpEdge(ir) / 2 - w * xA->GetBinWidth(ir) / 2);
00367                const Double_t xMax = xScale * (xA->GetBinLowEdge(ir) / 2 + xA->GetBinUpEdge(ir) / 2 + w * xA->GetBinWidth(ir) / 2);
00368                const Double_t yMin = yScale * (yA->GetBinLowEdge(jr) / 2 + yA->GetBinUpEdge(jr) / 2 - w * yA->GetBinWidth(jr) / 2);
00369                const Double_t yMax = yScale * (yA->GetBinLowEdge(jr) / 2 + yA->GetBinUpEdge(jr) / 2 + w * yA->GetBinWidth(jr) / 2);
00370                const Double_t zMin = zScale * (zA->GetBinLowEdge(kr) / 2 + zA->GetBinUpEdge(kr) / 2 - w * zA->GetBinWidth(kr) / 2);
00371                const Double_t zMax = zScale * (zA->GetBinLowEdge(kr) / 2 + zA->GetBinUpEdge(kr) / 2 + w * zA->GetBinWidth(kr) / 2);
00372 
00373                if (fBoxCut.IsActive() && fBoxCut.IsInCut(xMin, xMax, yMin, yMax, zMin, zMax))
00374                   continue;
00375 
00376                Rgl::DrawBoxFront(xMin, xMax, yMin, yMax, zMin, zMax, frontPoint);
00377             }
00378          }
00379       }
00380    }
00381 
00382    glPolygonMode(GL_FRONT, GL_FILL);//3]
00383 }
00384 
00385 //______________________________________________________________________________
00386 void TGLTH3CompositionPainter::SetColor(Int_t color)const
00387 {
00388    //Set material.
00389    Float_t diffColor[] = {0.8f, 0.8f, 0.8f, 0.05f};
00390 
00391    if (color != kWhite)
00392       if (const TColor *c = gROOT->GetColor(color))
00393          c->GetRGB(diffColor[0], diffColor[1], diffColor[2]);
00394 
00395    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffColor);
00396    const Float_t specColor[] = {1.f, 1.f, 1.f, 1.f};
00397    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specColor);
00398    glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 70.f);
00399 }
00400 
00401 namespace {
00402 
00403 //______________________________________________________________________________
00404 void AxisError(const TString & errorMsg)
00405 {
00406    Error("TGLTH3Composition::AddTH3", "%s", errorMsg.Data());
00407    throw std::runtime_error(errorMsg.Data());
00408 }
00409 
00410 //______________________________________________________________________________
00411 void CompareAxes(const TAxis *a1, const TAxis *a2, const TString &axisName)
00412 {
00413    //Check number of bins.
00414    if (a1->GetNbins() != a2->GetNbins())
00415       AxisError("New hist has different number of bins along " + axisName);
00416 
00417    //Check bin ranges.
00418    const Int_t firstBin1 = a1->GetFirst(), lastBin1 = a1->GetLast();
00419    const Int_t firstBin2 = a2->GetFirst(), lastBin2 = a2->GetLast();
00420 
00421    if (firstBin1 != firstBin2)
00422       AxisError("New hist has different first bin along " + axisName);
00423 
00424    if (lastBin1 != lastBin2)
00425       AxisError("New hist has different last bin along " + axisName);
00426 
00427    const Double_t eps = 1e-7;//?????:((((
00428    //Check axes ranges.
00429    if (TMath::Abs(a1->GetBinLowEdge(firstBin1) - a2->GetBinLowEdge(firstBin2)) > eps)
00430       AxisError("New hist has different low edge along " + axisName);
00431    if (TMath::Abs(a1->GetBinUpEdge(lastBin1) - a2->GetBinUpEdge(lastBin2)) > eps)
00432       AxisError("New hist has different low edge along " + axisName);
00433 }
00434 
00435 }

Generated on Tue Jul 5 14:18:09 2011 for ROOT_528-00b_version by  doxygen 1.5.1