25 ClassImp(TGLH2PolyPainter);
 
   30 TGLH2PolyPainter::TGLH2PolyPainter(TH1 *hist, TGLPlotCamera *camera, TGLPlotCoordinates *coord)
 
   31                    : TGLPlotPainter(hist, camera, coord, kFALSE, kFALSE, kFALSE),
 
   35    if(!dynamic_cast<TH2Poly *>(hist)) {
 
   36       Error(
"TGLH2PolyPainter::TGLH2PolyPainter", 
"bad histogram, must be a valid TH2Poly *");
 
   37       throw std::runtime_error(
"bad TH2Poly");
 
   44 char *TGLH2PolyPainter::GetPlotInfo(Int_t , Int_t )
 
   48       if (fSelectedPart < fSelectionBase) {
 
   50             fBinInfo += fHist->Class()->GetName();
 
   52          fBinInfo += fHist->GetName();
 
   53       } 
else if (!fHighColor) {
 
   54          const Int_t binIndex = fSelectedPart - fSelectionBase + 1;
 
   55          TH2Poly *h = 
static_cast<TH2Poly *
>(fHist);
 
   56          fBinInfo.Form(
"%s (bin = %d; binc = %f)", h->GetBinTitle(binIndex), binIndex, h->GetBinContent(binIndex));
 
   58          fBinInfo = 
"Switch to true-color mode to obtain the correct info";
 
   61    return (Char_t *)fBinInfo.Data();
 
   71 Bool_t TGLH2PolyPainter::InitGeometry()
 
   73    TH2Poly* hp = 
static_cast<TH2Poly *
>(fHist);
 
   74    if (!fCoord->SetRanges(hp))
 
   77    fBackBox.SetPlotBox(fCoord->GetXRangeScaled(), Rgl::gH2PolyScaleXY,
 
   78                        fCoord->GetYRangeScaled(), Rgl::gH2PolyScaleXY,
 
   79                        fCoord->GetZRangeScaled(), 1.);
 
   83    fZMin = fBackBox.Get3DBox()[0].Z();
 
   85    if (hp->GetNewBinAdded()) {
 
   88       hp->SetNewBinAdded(kFALSE);
 
   89       hp->SetBinContentChanged(kFALSE);
 
   90    } 
else if (hp->GetBinContentChanged() || fZLog != fCoord->GetZLog()) {
 
   91       if (!UpdateGeometry())
 
   93       hp->SetBinContentChanged(kFALSE);
 
   96    fZLog = fCoord->GetZLog();
 
  104 void TGLH2PolyPainter::StartPan(Int_t px, Int_t py)
 
  106    fMousePosition.fX = px;
 
  107    fMousePosition.fY = fCamera->GetHeight() - py;
 
  108    fCamera->StartPan(px, py);
 
  109    fBoxCut.StartMovement(px, py);
 
  115 void TGLH2PolyPainter::Pan(Int_t px, Int_t py)
 
  117    if (fSelectedPart >= fSelectionBase) {
 
  118       SaveModelviewMatrix();
 
  119       SaveProjectionMatrix();
 
  121       fCamera->SetCamera();
 
  122       fCamera->Apply(fPadPhi, fPadTheta);
 
  123       fCamera->Pan(px, py);
 
  125       RestoreProjectionMatrix();
 
  126       RestoreModelviewMatrix();
 
  127    } 
else if (fSelectedPart > 0) {
 
  129       py = fCamera->GetHeight() - py;
 
  131       SaveModelviewMatrix();
 
  132       SaveProjectionMatrix();
 
  134       fCamera->SetCamera();
 
  135       fCamera->Apply(fPadPhi, fPadTheta);
 
  138          if (fBoxCut.IsActive() && (fSelectedPart >= kXAxis && fSelectedPart <= kZAxis)) {
 
  139             fBoxCut.MoveBox(px, py, fSelectedPart);
 
  143       RestoreProjectionMatrix();
 
  144       RestoreModelviewMatrix();
 
  147    fMousePosition.fX = px, fMousePosition.fY = py;
 
  148    fUpdateSelection = kTRUE;
 
  154 void TGLH2PolyPainter::AddOption(
const TString &)
 
  161 void TGLH2PolyPainter::ProcessEvent(Int_t , Int_t , Int_t )
 
  168 void TGLH2PolyPainter::InitGL()
const 
  170    glEnable(GL_DEPTH_TEST);
 
  171    glEnable(GL_LIGHTING);
 
  174    glEnable(GL_CULL_FACE);
 
  177    glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
 
  183 void TGLH2PolyPainter::DeInitGL()
const 
  185    glDisable(GL_DEPTH_TEST);
 
  186    glDisable(GL_LIGHTING);
 
  187    glDisable(GL_LIGHT0);
 
  188    glDisable(GL_CULL_FACE);
 
  189    glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
 
  194 Double_t Distance(
const Double_t *p1, 
const Double_t *p2);
 
  195 Bool_t   IsPolygonCW(
const Double_t *xs, 
const Double_t *ys, Int_t n);
 
  202 void TGLH2PolyPainter::DrawPlot()
const 
  205    const Rgl::PlotTranslation trGuard(
this);
 
  207    fBackBox.DrawBox(fSelectedPart, fSelectionPass, fZLevels, fHighColor);
 
  218 void TGLH2PolyPainter::DrawExtrusion()
const 
  220    TList *bins = 
static_cast<TH2Poly *
>(fHist)->GetBins();
 
  222    for(TObjLink * link = bins->FirstLink(); link; link = link->Next(), ++binIndex) {
 
  223       TH2PolyBin *bin = 
static_cast<TH2PolyBin *
>(link->GetObject());
 
  225       Double_t zMax = bin->GetContent();
 
  228       if (
const TGraph * poly = dynamic_cast<TGraph*>(bin->GetPolygon())) {
 
  230          DrawExtrusion(poly, fZMin, zMax, binIndex);
 
  231       } 
else if (
const TMultiGraph * mg = dynamic_cast<TMultiGraph*>(bin->GetPolygon())) {
 
  233          DrawExtrusion(mg, fZMin, zMax, binIndex);
 
  241 void TGLH2PolyPainter::DrawExtrusion(
const TGraph *poly, Double_t zMin, Double_t zMax, Int_t binIndex)
const 
  243    const Double_t *xs = poly->GetX();
 
  244    const Double_t *ys = poly->GetY();
 
  246    const Int_t nV = poly->GetN();
 
  251    const Int_t binID = fSelectionBase + binIndex;
 
  253    if (fSelectionPass) {
 
  255          Rgl::ObjectIDToColor(binID, kFALSE);
 
  257       SetBinColor(binIndex);
 
  258       if(!fHighColor && fSelectedPart == binID)
 
  259          glMaterialfv(GL_FRONT, GL_EMISSION, Rgl::gOrangeEmission);
 
  264    FillTemporaryPolygon(xs, ys, 0., nV); 
 
  266    Double_t normal[3] = {};
 
  267    for (Int_t j = 0; j < nV - 1; ++j) {
 
  268       const Double_t v0[] = {fPolygon[j * 3], fPolygon[j * 3 + 1], zMin};
 
  269       const Double_t v1[] = {fPolygon[(j + 1) * 3], fPolygon[(j + 1) * 3 + 1], zMin};
 
  271       if (Distance(v0, v1) < 1e-10)
 
  274       const Double_t v2[] = {v1[0], v1[1], zMax};
 
  275       const Double_t v3[] = {v0[0], v0[1], zMax};
 
  277       TMath::Normal2Plane(v0, v1, v2, normal);
 
  278       Rgl::DrawQuadFilled(v0, v1, v2, v3, normal);
 
  282    const Double_t v0[] = {fPolygon[(nV - 1) * 3], fPolygon[(nV - 1) * 3 + 1], zMin};
 
  283    const Double_t v1[] = {fPolygon[0], fPolygon[1], zMin};
 
  285    if (Distance(v0, v1) > 1e-10) {
 
  286       const Double_t v2[] = {v1[0], v1[1], zMax};
 
  287       const Double_t v3[] = {v0[0], v0[1], zMax};
 
  289       TMath::Normal2Plane(v0, v1, v2, normal);
 
  290       Rgl::DrawQuadFilled(v0, v1, v2, v3, normal);
 
  293    if (!fHighColor && !fSelectionPass && fSelectedPart == binID)
 
  294       glMaterialfv(GL_FRONT, GL_EMISSION, Rgl::gNullEmission);
 
  300 void TGLH2PolyPainter::DrawExtrusion(
const TMultiGraph *mg, Double_t zMin, Double_t zMax, Int_t binIndex)
const 
  302    const TList *graphs = mg->GetListOfGraphs();
 
  303    for (TObjLink *link = graphs->FirstLink(); link; link = link->Next())
 
  304       DrawExtrusion((TGraph *)(link->GetObject()), zMin, zMax, binIndex);
 
  310 void TGLH2PolyPainter::DrawCaps()
const 
  313    const TList *bins = 
static_cast<TH2Poly *
>(fHist)->GetBins();
 
  314    CIter_t cap = fCaps.begin();
 
  316    assert(bins->FirstLink());
 
  322    for (TObjLink *link = bins->FirstLink(); link && cap != fCaps.end(); link = link->Next()) {
 
  323       TH2PolyBin *polyBin = 
static_cast<TH2PolyBin *
>(link->GetObject());
 
  324       if (dynamic_cast<TGraph *>(polyBin->GetPolygon())) {
 
  325          DrawCap(cap, binIndex, 
false);
 
  326          DrawCap(cap, binIndex, 
true);
 
  328       } 
else if (TMultiGraph *mg = dynamic_cast<TMultiGraph *>(polyBin->GetPolygon())) {
 
  329          const TList *gs = mg->GetListOfGraphs();
 
  330          TObjLink *graphLink = gs->FirstLink();
 
  331          for (; graphLink && cap != fCaps.end(); graphLink = graphLink->Next(), ++cap) {
 
  332             DrawCap(cap, binIndex, 
false);
 
  333             DrawCap(cap, binIndex, 
true);
 
  344 void TGLH2PolyPainter::DrawCap(CIter_t cap, Int_t binIndex, 
bool bottomCap)
const 
  346    const Int_t binID = fSelectionBase + binIndex;
 
  347    if (fSelectionPass) {
 
  349          Rgl::ObjectIDToColor(binID, kFALSE);
 
  351       SetBinColor(binIndex);
 
  352       if(!fHighColor && fSelectedPart == binID)
 
  353          glMaterialfv(GL_FRONT, GL_EMISSION, Rgl::gOrangeEmission);
 
  356    glNormal3d(0., 0., bottomCap ? -1. : 1.);
 
  361    const Rgl::Pad::Tesselation_t &t = *cap;
 
  362    typedef std::list<Rgl::Pad::MeshPatch_t>::const_iterator CMIter_t;
 
  364        for (CMIter_t p = t.begin(); p != t.end(); ++p) {
 
  365           const std::vector<Double_t> &vs = p->fPatch;
 
  366           glBegin(GLenum(p->fPatchType));
 
  367           for (UInt_t i = 0; i < vs.size(); i += 3)
 
  368              glVertex3d(vs[i], vs[i + 1], fZMin);
 
  372       for (CMIter_t p = t.begin(); p != t.end(); ++p) {
 
  373          const std::vector<Double_t> &vs = p->fPatch;
 
  374          glBegin(GLenum(p->fPatchType));
 
  375          for (UInt_t i = 0; i < vs.size(); i += 3)
 
  382    if (!fHighColor && !fSelectionPass && fSelectedPart == binID)
 
  383       glMaterialfv(GL_FRONT, GL_EMISSION, Rgl::gNullEmission);
 
  392 Bool_t TGLH2PolyPainter::CacheGeometry()
 
  394    TH2Poly *hp = 
static_cast<TH2Poly *
>(fHist);
 
  395    TList *bins = hp->GetBins();
 
  396    if (!bins || !bins->GetEntries()) {
 
  397       Error(
"TGLH2PolyPainter::CacheGeometry", 
"Empty list of bins in TH2Poly");
 
  401    const Double_t zMin = fHist->GetMinimum();
 
  402    const Double_t zMax = fHist->GetMaximum();
 
  403    const Int_t nColors = gStyle->GetNumberOfColors();
 
  406    fBinColors.reserve(bins->GetEntries());
 
  410    Rgl::Pad::Tesselator tesselator(kTRUE);
 
  412    for (TObjLink * link = bins->FirstLink(); link; link = link->Next()) {
 
  413       TH2PolyBin * bin = 
static_cast<TH2PolyBin *
>(link->GetObject());
 
  414       if (!bin || !bin->GetPolygon()) {
 
  415          Error(
"TGH2PolyPainter::InitGeometry", 
"Null bin or polygon pointer in a list of bins");
 
  419       Double_t binZ = bin->GetContent();
 
  421          Error(
"TGLH2PolyPainter::CacheGeometry", 
"Negative bin content and log scale");
 
  425       if (
const TGraph *g = dynamic_cast<TGraph *>(bin->GetPolygon())) {
 
  426          if (!BuildTesselation(tesselator, g,  binZ))
 
  428       } 
else if (
const TMultiGraph *mg = dynamic_cast<TMultiGraph *>(bin->GetPolygon())) {
 
  429          if (!BuildTesselation(tesselator, mg, binZ))
 
  432          Error(
"TGLH2PolyPainter::CacheGeometry", 
"Bin contains object of unknown type");
 
  436       const Int_t colorIndex = gStyle->GetColorPalette(Int_t(((bin->GetContent() - zMin) / (zMax - zMin)) * (nColors - 1)));
 
  437       fBinColors.push_back(colorIndex);
 
  446 Bool_t TGLH2PolyPainter::BuildTesselation(Rgl::Pad::Tesselator &tess, 
const TGraph *g, Double_t z)
 
  448    const Double_t *xs = g->GetX();
 
  449    const Double_t *ys = g->GetY();
 
  452       Error(
"TGLH2PolyPainter::BuildTesselation", 
"null array(s) in a polygon");
 
  456    const Int_t nV = g->GetN();
 
  458       Error(
"TGLH2PolyPainter::BuildTesselation", 
"number of vertices in a polygon must be >= 3");
 
  462    fCaps.push_back(Rgl::Pad::Tesselation_t());
 
  463    FillTemporaryPolygon(xs, ys, z, nV);
 
  465    tess.SetDump(&fCaps.back());
 
  467    GLUtesselator *t = (GLUtesselator *)tess.GetTess();
 
  469    gluNextContour(t, (GLenum)GLU_UNKNOWN);
 
  471    glNormal3d(0., 0., 1.);
 
  473    for (Int_t j = 0; j < nV; ++j) {
 
  474       gluTessVertex(t, &fPolygon[j * 3], &fPolygon[j * 3]);
 
  484 Bool_t TGLH2PolyPainter::BuildTesselation(Rgl::Pad::Tesselator &tess, 
const TMultiGraph *mg, Double_t z)
 
  486    const TList *graphs = mg->GetListOfGraphs();
 
  488       Error(
"TGLH2PolyPainter::BuildTesselation", 
"null list of graphs in a multigraph");
 
  492    for(TObjLink *link = graphs->FirstLink(); link; link = link->Next()) {
 
  493       const TGraph *graph = 
dynamic_cast<TGraph *
>(link->GetObject());
 
  495          Error(
"TGLH2PolyPainter::BuildTesselation", 
"TGraph expected inside a multigraph, got something else");
 
  499       if (!BuildTesselation(tess, graph, z))
 
  511 Bool_t TGLH2PolyPainter::UpdateGeometry()
 
  513    TH2Poly *hp = 
static_cast<TH2Poly *
>(fHist);
 
  514    TList *bins = hp->GetBins();
 
  516    std::list<Rgl::Pad::Tesselation_t>::iterator cap = fCaps.begin();
 
  521    for (TObjLink *link = bins->FirstLink(); link && cap != fCaps.end(); link = link->Next()) {
 
  522       TH2PolyBin *b = 
static_cast<TH2PolyBin *
>(link->GetObject());
 
  523       Double_t z = b->GetContent();
 
  526       if (dynamic_cast<TGraph *>(b->GetPolygon())) {
 
  528          Rgl::Pad::Tesselation_t &tess = *cap;
 
  529          Rgl::Pad::Tesselation_t::iterator patch = tess.begin();
 
  530          for (; patch != tess.end(); ++patch) {
 
  531             std::vector<Double_t> &mesh = patch->fPatch;
 
  532             for (UInt_t i = 0, e = mesh.size() / 3; i < e; ++i)
 
  537       } 
else if (
const TMultiGraph *mg = dynamic_cast<TMultiGraph *>(b->GetPolygon())) {
 
  538          const TList *gs = mg->GetListOfGraphs();
 
  539          for (TObjLink * graphLink = gs->FirstLink(); graphLink && cap != fCaps.end(); graphLink = graphLink->Next(), ++cap) {
 
  540             Rgl::Pad::Tesselation_t &tess = *cap;
 
  541             Rgl::Pad::Tesselation_t::iterator patch = tess.begin();
 
  542             for (; patch != tess.end(); ++patch) {
 
  543                std::vector<Double_t> &mesh = patch->fPatch;
 
  544                for (UInt_t i = 0, e = mesh.size() / 3; i < e; ++i)
 
  557 void TGLH2PolyPainter::SetBinColor(Int_t binIndex)
const 
  559    if (binIndex >= Int_t(fBinColors.size())) {
 
  560       Error(
"TGLH2PolyPainter::SetBinColor", 
"bin index is out of range %d, must be <= %d",
 
  561             binIndex, 
int(fBinColors.size()));
 
  566    Float_t diffColor[] = {0.8f, 0.8f, 0.8f, 0.15f};
 
  568    if (
const TColor *c = gROOT->GetColor(fBinColors[binIndex]))
 
  569       c->GetRGB(diffColor[0], diffColor[1], diffColor[2]);
 
  571    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffColor);
 
  572    const Float_t specColor[] = {0.2f, 0.2f, 0.2f, 0.2f};
 
  573    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specColor);
 
  574    glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 70.f);
 
  580 void TGLH2PolyPainter::DrawSectionXOZ()
const 
  587 void TGLH2PolyPainter::DrawSectionYOZ()
const 
  594 void TGLH2PolyPainter::DrawSectionXOY()
const 
  601 void TGLH2PolyPainter::DrawPalette()
const 
  608 void TGLH2PolyPainter::DrawPaletteAxis()
const 
  615 void TGLH2PolyPainter::FillTemporaryPolygon(
const Double_t *xs, 
const Double_t *ys, Double_t z, Int_t nV)
const 
  617    const Double_t xScale = fCoord->GetXScale();
 
  618    const Double_t yScale = fCoord->GetYScale();
 
  620    fPolygon.resize(nV * 3);
 
  621    for (Int_t j = 0; j < nV; ++j) {
 
  622       fPolygon[j * 3]     = xs[j] * xScale;
 
  623       fPolygon[j * 3 + 1] = ys[j] * yScale;
 
  624       fPolygon[j * 3 + 2] = z;
 
  627    if (IsPolygonCW(xs, ys, nV))
 
  634 void TGLH2PolyPainter::MakePolygonCCW()
const 
  636    const Int_t nV = Int_t(fPolygon.size() / 3);
 
  637    for (Int_t a = 0; a <= (nV / 2) - 1; a++) {
 
  638       const Int_t b = nV - 1 - a;
 
  639       std::swap(fPolygon[a * 3], fPolygon[b * 3]);
 
  640       std::swap(fPolygon[a * 3 + 1], fPolygon[b * 3 + 1]);
 
  647 Bool_t TGLH2PolyPainter::ClampZ(Double_t &zVal)
const 
  649    if (fCoord->GetZLog()) {
 
  653          zVal = TMath::Log10(zVal) * fCoord->GetZScale();
 
  655       zVal *= fCoord->GetZScale();
 
  657    const TGLVertex3 *frame = fBackBox.Get3DBox();
 
  659    if (zVal > frame[4].Z())
 
  661    else if (zVal < frame[0].Z())
 
  673 Double_t Distance(
const Double_t *p1, 
const Double_t *p2)
 
  675    return TMath::Sqrt((p1[0] - p2[0]) * (p1[0] - p2[0]) +
 
  676                       (p1[1] - p2[1]) * (p1[1] - p2[1]) +
 
  677                       (p1[2] - p2[2]) * (p1[2] - p2[2]));
 
  684 Bool_t IsPolygonCW(
const Double_t *xs, 
const Double_t *ys, Int_t n)
 
  686    Double_t signedArea = 0.;
 
  688    for (Int_t j = 0; j < n - 1; ++j)
 
  689       signedArea += xs[j] * ys[j + 1] - ys[j] * xs[j + 1];
 
  691    return signedArea < 0.;