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.;