00001 #include <algorithm>
00002 #include <stdexcept>
00003
00004 #include "TMultiGraph.h"
00005 #include "TH2Poly.h"
00006 #include "TGraph.h"
00007 #include "TClass.h"
00008 #include "TStyle.h"
00009 #include "TError.h"
00010 #include "TColor.h"
00011 #include "TMath.h"
00012 #include "TList.h"
00013 #include "TROOT.h"
00014
00015 #include "TGLH2PolyPainter.h"
00016 #include "TGLPlotCamera.h"
00017 #include "TGLIncludes.h"
00018
00019
00020 ClassImp(TGLH2PolyPainter)
00021
00022
00023 TGLH2PolyPainter::TGLH2PolyPainter(TH1 *hist, TGLPlotCamera *camera, TGLPlotCoordinates *coord)
00024 : TGLPlotPainter(hist, camera, coord, kFALSE, kFALSE, kFALSE),
00025 fZLog(kFALSE),
00026 fZMin(0.)
00027 {
00028
00029 if(!dynamic_cast<TH2Poly *>(hist)) {
00030 Error("TGLH2PolyPainter::TGLH2PolyPainter", "bad histogram, must be a valid TH2Poly *");
00031 throw std::runtime_error("bad TH2Poly");
00032 }
00033 }
00034
00035
00036 char *TGLH2PolyPainter::GetPlotInfo(Int_t , Int_t )
00037 {
00038
00039 fBinInfo = "";
00040 if (fSelectedPart) {
00041 if (fSelectedPart < fSelectionBase) {
00042 if (fHist->Class())
00043 fBinInfo += fHist->Class()->GetName();
00044 fBinInfo += "::";
00045 fBinInfo += fHist->GetName();
00046 } else if (!fHighColor) {
00047 const Int_t binIndex = fSelectedPart - fSelectionBase + 1;
00048 TH2Poly *h = static_cast<TH2Poly *>(fHist);
00049 fBinInfo.Form("%s (bin = %d; binc = %f)", h->GetBinTitle(binIndex), binIndex, h->GetBinContent(binIndex));
00050 } else
00051 fBinInfo = "Switch to true-color mode to obtain the correct info";
00052 }
00053
00054 return (Char_t *)fBinInfo.Data();
00055 }
00056
00057
00058 Bool_t TGLH2PolyPainter::InitGeometry()
00059 {
00060
00061
00062
00063
00064
00065 TH2Poly* hp = static_cast<TH2Poly *>(fHist);
00066 if (!fCoord->SetRanges(hp))
00067 return kFALSE;
00068
00069 fBackBox.SetPlotBox(fCoord->GetXRangeScaled(), Rgl::gH2PolyScaleXY,
00070 fCoord->GetYRangeScaled(), Rgl::gH2PolyScaleXY,
00071 fCoord->GetZRangeScaled(), 1.);
00072
00073
00074
00075 fZMin = fBackBox.Get3DBox()[0].Z();
00076
00077 if (hp->GetNewBinAdded()) {
00078 if (!CacheGeometry())
00079 return kFALSE;
00080 hp->SetNewBinAdded(kFALSE);
00081 hp->SetBinContentChanged(kFALSE);
00082 } else if (hp->GetBinContentChanged() || fZLog != fCoord->GetZLog()) {
00083 if (!UpdateGeometry())
00084 return kFALSE;
00085 hp->SetBinContentChanged(kFALSE);
00086 }
00087
00088 fZLog = fCoord->GetZLog();
00089
00090 return kTRUE;
00091 }
00092
00093
00094 void TGLH2PolyPainter::StartPan(Int_t px, Int_t py)
00095 {
00096
00097 fMousePosition.fX = px;
00098 fMousePosition.fY = fCamera->GetHeight() - py;
00099 fCamera->StartPan(px, py);
00100 fBoxCut.StartMovement(px, py);
00101 }
00102
00103
00104 void TGLH2PolyPainter::Pan(Int_t px, Int_t py)
00105 {
00106
00107 if (fSelectedPart >= fSelectionBase) {
00108 SaveModelviewMatrix();
00109 SaveProjectionMatrix();
00110
00111 fCamera->SetCamera();
00112 fCamera->Apply(fPadPhi, fPadTheta);
00113 fCamera->Pan(px, py);
00114
00115 RestoreProjectionMatrix();
00116 RestoreModelviewMatrix();
00117 } else if (fSelectedPart > 0) {
00118
00119 py = fCamera->GetHeight() - py;
00120
00121 SaveModelviewMatrix();
00122 SaveProjectionMatrix();
00123
00124 fCamera->SetCamera();
00125 fCamera->Apply(fPadPhi, fPadTheta);
00126
00127 if (!fHighColor) {
00128 if (fBoxCut.IsActive() && (fSelectedPart >= kXAxis && fSelectedPart <= kZAxis)) {
00129 fBoxCut.MoveBox(px, py, fSelectedPart);
00130 }
00131 }
00132
00133 RestoreProjectionMatrix();
00134 RestoreModelviewMatrix();
00135 }
00136
00137 fMousePosition.fX = px, fMousePosition.fY = py;
00138 fUpdateSelection = kTRUE;
00139 }
00140
00141
00142 void TGLH2PolyPainter::AddOption(const TString &)
00143 {
00144
00145 }
00146
00147
00148 void TGLH2PolyPainter::ProcessEvent(Int_t , Int_t , Int_t )
00149 {
00150
00151 }
00152
00153
00154 void TGLH2PolyPainter::InitGL()const
00155 {
00156
00157 glEnable(GL_DEPTH_TEST);
00158 glEnable(GL_LIGHTING);
00159 glEnable(GL_LIGHT0);
00160
00161 glEnable(GL_CULL_FACE);
00162 glCullFace(GL_BACK);
00163
00164 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
00165 }
00166
00167
00168 void TGLH2PolyPainter::DeInitGL()const
00169 {
00170
00171 glDisable(GL_DEPTH_TEST);
00172 glDisable(GL_LIGHTING);
00173 glDisable(GL_LIGHT0);
00174 glDisable(GL_CULL_FACE);
00175 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
00176 }
00177
00178 namespace {
00179
00180 Double_t Distance(const Double_t *p1, const Double_t *p2);
00181 Bool_t IsPolygonCW(const Double_t *xs, const Double_t *ys, Int_t n);
00182
00183 }
00184
00185
00186 void TGLH2PolyPainter::DrawPlot()const
00187 {
00188
00189
00190
00191 const Rgl::PlotTranslation trGuard(this);
00192
00193 fBackBox.DrawBox(fSelectedPart, fSelectionPass, fZLevels, fHighColor);
00194
00195 DrawExtrusion();
00196 DrawCaps();
00197 }
00198
00199
00200 void TGLH2PolyPainter::DrawExtrusion()const
00201 {
00202
00203
00204
00205 TList *bins = static_cast<TH2Poly *>(fHist)->GetBins();
00206 Int_t binIndex = 0;
00207 for(TObjLink * link = bins->FirstLink(); link; link = link->Next(), ++binIndex) {
00208 TH2PolyBin *bin = static_cast<TH2PolyBin *>(link->GetObject());
00209
00210 Double_t zMax = bin->GetContent();
00211 ClampZ(zMax);
00212
00213 if (const TGraph * poly = dynamic_cast<TGraph*>(bin->GetPolygon())) {
00214
00215 DrawExtrusion(poly, fZMin, zMax, binIndex);
00216 } else if (const TMultiGraph * mg = dynamic_cast<TMultiGraph*>(bin->GetPolygon())) {
00217
00218 DrawExtrusion(mg, fZMin, zMax, binIndex);
00219 }
00220 }
00221 }
00222
00223
00224 void TGLH2PolyPainter::DrawExtrusion(const TGraph *poly, Double_t zMin, Double_t zMax, Int_t binIndex)const
00225 {
00226
00227 const Double_t *xs = poly->GetX();
00228 const Double_t *ys = poly->GetY();
00229
00230 const Int_t nV = poly->GetN();
00231
00232
00233
00234
00235 const Int_t binID = fSelectionBase + binIndex;
00236
00237 if (fSelectionPass) {
00238 if (!fHighColor)
00239 Rgl::ObjectIDToColor(binID, kFALSE);
00240 } else {
00241 SetBinColor(binIndex);
00242 if(!fHighColor && fSelectedPart == binID)
00243 glMaterialfv(GL_FRONT, GL_EMISSION, Rgl::gOrangeEmission);
00244 }
00245
00246
00247
00248 FillTemporaryPolygon(xs, ys, 0., nV);
00249
00250 Double_t normal[3] = {};
00251 for (Int_t j = 0; j < nV - 1; ++j) {
00252 const Double_t v0[] = {fPolygon[j * 3], fPolygon[j * 3 + 1], zMin};
00253 const Double_t v1[] = {fPolygon[(j + 1) * 3], fPolygon[(j + 1) * 3 + 1], zMin};
00254
00255 if (Distance(v0, v1) < 1e-10)
00256 continue;
00257
00258 const Double_t v2[] = {v1[0], v1[1], zMax};
00259 const Double_t v3[] = {v0[0], v0[1], zMax};
00260
00261 TMath::Normal2Plane(v0, v1, v2, normal);
00262 Rgl::DrawQuadFilled(v0, v1, v2, v3, normal);
00263 }
00264
00265
00266 const Double_t v0[] = {fPolygon[(nV - 1) * 3], fPolygon[(nV - 1) * 3 + 1], zMin};
00267 const Double_t v1[] = {fPolygon[0], fPolygon[1], zMin};
00268
00269 if (Distance(v0, v1) > 1e-10) {
00270 const Double_t v2[] = {v1[0], v1[1], zMax};
00271 const Double_t v3[] = {v0[0], v0[1], zMax};
00272
00273 TMath::Normal2Plane(v0, v1, v2, normal);
00274 Rgl::DrawQuadFilled(v0, v1, v2, v3, normal);
00275 }
00276
00277 if (!fHighColor && !fSelectionPass && fSelectedPart == binID)
00278 glMaterialfv(GL_FRONT, GL_EMISSION, Rgl::gNullEmission);
00279 }
00280
00281
00282 void TGLH2PolyPainter::DrawExtrusion(const TMultiGraph *mg, Double_t zMin, Double_t zMax, Int_t binIndex)const
00283 {
00284
00285 const TList *graphs = mg->GetListOfGraphs();
00286 for (TObjLink *link = graphs->FirstLink(); link; link = link->Next())
00287 DrawExtrusion((TGraph *)(link->GetObject()), zMin, zMax, binIndex);
00288 }
00289
00290
00291 void TGLH2PolyPainter::DrawCaps()const
00292 {
00293
00294 glNormal3d(0., 0., 1.);
00295
00296 Int_t binIndex = 0;
00297 const TList *bins = static_cast<TH2Poly *>(fHist)->GetBins();
00298 CIter_t cap = fCaps.begin();
00299
00300 if(!bins->FirstLink())
00301 throw 1;
00302
00303
00304
00305
00306 for (TObjLink *link = bins->FirstLink(); link && cap != fCaps.end(); link = link->Next()) {
00307 TH2PolyBin *polyBin = static_cast<TH2PolyBin *>(link->GetObject());
00308 if (dynamic_cast<TGraph *>(polyBin->GetPolygon())) {
00309 DrawCap(cap, binIndex);
00310 ++cap;
00311 } else if (TMultiGraph *mg = dynamic_cast<TMultiGraph *>(polyBin->GetPolygon())) {
00312 const TList *gs = mg->GetListOfGraphs();
00313 TObjLink *graphLink = gs->FirstLink();
00314 for (; graphLink && cap != fCaps.end(); graphLink = graphLink->Next(), ++cap)
00315 DrawCap(cap, binIndex);
00316 }
00317
00318 ++binIndex;
00319 }
00320 }
00321
00322
00323 void TGLH2PolyPainter::DrawCap(CIter_t cap, Int_t binIndex)const
00324 {
00325
00326 const Int_t binID = fSelectionBase + binIndex;
00327 if (fSelectionPass) {
00328 if (!fHighColor)
00329 Rgl::ObjectIDToColor(binID, kFALSE);
00330 } else {
00331 SetBinColor(binIndex);
00332 if(!fHighColor && fSelectedPart == binID)
00333 glMaterialfv(GL_FRONT, GL_EMISSION, Rgl::gOrangeEmission);
00334 }
00335
00336 const Rgl::Pad::Tesselation_t &t = *cap;
00337 typedef std::list<Rgl::Pad::MeshPatch_t>::const_iterator CMIter_t;
00338 for (CMIter_t p = t.begin(); p != t.end(); ++p) {
00339 const std::vector<Double_t> &vs = p->fPatch;
00340 glBegin(GLenum(p->fPatchType));
00341 for (UInt_t i = 0; i < vs.size(); i += 3)
00342 glVertex3dv(&vs[i]);
00343 glEnd();
00344 }
00345
00346 if (!fHighColor && !fSelectionPass && fSelectedPart == binID)
00347 glMaterialfv(GL_FRONT, GL_EMISSION, Rgl::gNullEmission);
00348 }
00349
00350
00351 Bool_t TGLH2PolyPainter::CacheGeometry()
00352 {
00353
00354 TH2Poly *hp = static_cast<TH2Poly *>(fHist);
00355 TList *bins = hp->GetBins();
00356 if (!bins || !bins->GetEntries()) {
00357 Error("TGLH2PolyPainter::CacheGeometry", "Empty list of bins in TH2Poly");
00358 return kFALSE;
00359 }
00360
00361 const Double_t zMin = fHist->GetMinimum();
00362 const Double_t zMax = fHist->GetMaximum();
00363 const Int_t nColors = gStyle->GetNumberOfColors();
00364
00365 fBinColors.clear();
00366 fBinColors.reserve(bins->GetEntries());
00367 fPolygon.clear();
00368 fCaps.clear();
00369
00370 Rgl::Pad::Tesselator tesselator(kTRUE);
00371
00372 for (TObjLink * link = bins->FirstLink(); link; link = link->Next()) {
00373 TH2PolyBin * bin = static_cast<TH2PolyBin *>(link->GetObject());
00374 if (!bin || !bin->GetPolygon()) {
00375 Error("TGH2PolyPainter::InitGeometry", "Null bin or polygon pointer in a list of bins");
00376 return kFALSE;
00377 }
00378
00379 Double_t binZ = bin->GetContent();
00380 if (!ClampZ(binZ)) {
00381 Error("TGLH2PolyPainter::CacheGeometry", "Negative bin content and log scale");
00382 return kFALSE;
00383 }
00384
00385 if (const TGraph *g = dynamic_cast<TGraph *>(bin->GetPolygon())) {
00386 if (!BuildTesselation(tesselator, g, binZ))
00387 return kFALSE;
00388 } else if (const TMultiGraph *mg = dynamic_cast<TMultiGraph *>(bin->GetPolygon())) {
00389 if (!BuildTesselation(tesselator, mg, binZ))
00390 return kFALSE;
00391 } else {
00392
00393 Error("TGLH2PolyPainter::CacheGeometry", "Bin contains object of unknown type");
00394 return kFALSE;
00395 }
00396
00397 const Int_t colorIndex = gStyle->GetColorPalette(Int_t(((bin->GetContent() - zMin) / (zMax - zMin)) * (nColors - 1)));
00398 fBinColors.push_back(colorIndex);
00399 }
00400
00401 return kTRUE;
00402 }
00403
00404
00405 Bool_t TGLH2PolyPainter::BuildTesselation(Rgl::Pad::Tesselator &tess, const TGraph *g, Double_t z)
00406 {
00407
00408 const Double_t *xs = g->GetX();
00409 const Double_t *ys = g->GetY();
00410
00411 if (!xs || !ys) {
00412 Error("TGLH2PolyPainter::BuildTesselation", "null array(s) in a polygon");
00413 return kFALSE;
00414 }
00415
00416 const Int_t nV = g->GetN();
00417 if (nV < 3) {
00418 Error("TGLH2PolyPainter::BuildTesselation", "number of vertices in a polygon must be >= 3");
00419 return kFALSE;
00420 }
00421
00422 fCaps.push_back(Rgl::Pad::Tesselation_t());
00423 FillTemporaryPolygon(xs, ys, z, nV);
00424
00425 tess.SetDump(&fCaps.back());
00426
00427 GLUtesselator *t = (GLUtesselator *)tess.GetTess();
00428 gluBeginPolygon(t);
00429 gluNextContour(t, (GLenum)GLU_UNKNOWN);
00430
00431 glNormal3d(0., 0., 1.);
00432
00433 for (Int_t j = 0; j < nV; ++j) {
00434 gluTessVertex(t, &fPolygon[j * 3], &fPolygon[j * 3]);
00435 }
00436 gluEndPolygon(t);
00437
00438 return kTRUE;
00439 }
00440
00441
00442 Bool_t TGLH2PolyPainter::BuildTesselation(Rgl::Pad::Tesselator &tess, const TMultiGraph *mg, Double_t z)
00443 {
00444
00445 const TList *graphs = mg->GetListOfGraphs();
00446 if (!graphs) {
00447 Error("TGLH2PolyPainter::BuildTesselation", "null list of graphs in a multigraph");
00448 return kFALSE;
00449 }
00450
00451 for(TObjLink *link = graphs->FirstLink(); link; link = link->Next()) {
00452 const TGraph *graph = dynamic_cast<TGraph *>(link->GetObject());
00453 if (!graph) {
00454
00455 Error("TGLH2PolyPainter::BuildTesselation", "TGraph expected inside a multigraph, got something else");
00456 return kFALSE;
00457 }
00458
00459 if (!BuildTesselation(tess, graph, z))
00460 return kFALSE;
00461 }
00462
00463 return kTRUE;
00464 }
00465
00466
00467 Bool_t TGLH2PolyPainter::UpdateGeometry()
00468 {
00469
00470
00471
00472
00473 TH2Poly *hp = static_cast<TH2Poly *>(fHist);
00474 TList *bins = hp->GetBins();
00475
00476 std::list<Rgl::Pad::Tesselation_t>::iterator cap = fCaps.begin();
00477
00478
00479
00480
00481 for (TObjLink *link = bins->FirstLink(); link && cap != fCaps.end(); link = link->Next()) {
00482 TH2PolyBin *b = static_cast<TH2PolyBin *>(link->GetObject());
00483 Double_t z = b->GetContent();
00484 ClampZ(z);
00485
00486 if (dynamic_cast<TGraph *>(b->GetPolygon())) {
00487
00488 Rgl::Pad::Tesselation_t &tess = *cap;
00489 Rgl::Pad::Tesselation_t::iterator patch = tess.begin();
00490 for (; patch != tess.end(); ++patch) {
00491 std::vector<Double_t> &mesh = patch->fPatch;
00492 for (UInt_t i = 0, e = mesh.size() / 3; i < e; ++i)
00493 mesh[i * 3 + 2] = z;
00494 }
00495
00496 ++cap;
00497 } else if (const TMultiGraph *mg = dynamic_cast<TMultiGraph *>(b->GetPolygon())) {
00498 const TList *gs = mg->GetListOfGraphs();
00499 for (TObjLink * graphLink = gs->FirstLink(); graphLink && cap != fCaps.end(); graphLink = graphLink->Next(), ++cap) {
00500 Rgl::Pad::Tesselation_t &tess = *cap;
00501 Rgl::Pad::Tesselation_t::iterator patch = tess.begin();
00502 for (; patch != tess.end(); ++patch) {
00503 std::vector<Double_t> &mesh = patch->fPatch;
00504 for (UInt_t i = 0, e = mesh.size() / 3; i < e; ++i)
00505 mesh[i * 3 + 2] = z;
00506 }
00507 }
00508 }
00509 }
00510
00511 return kTRUE;
00512 }
00513
00514
00515 void TGLH2PolyPainter::SetBinColor(Int_t binIndex)const
00516 {
00517
00518 if (binIndex >= Int_t(fBinColors.size())) {
00519 Error("TGLH2PolyPainter::SetBinColor", "bin index is out of range %d, must be <= %d",
00520 binIndex, int(fBinColors.size()));
00521 return;
00522 }
00523
00524
00525 Float_t diffColor[] = {0.8f, 0.8f, 0.8f, 0.15f};
00526
00527 if (const TColor *c = gROOT->GetColor(fBinColors[binIndex]))
00528 c->GetRGB(diffColor[0], diffColor[1], diffColor[2]);
00529
00530 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffColor);
00531 const Float_t specColor[] = {1.f, 1.f, 1.f, 1.f};
00532 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specColor);
00533 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 70.f);
00534 }
00535
00536
00537 void TGLH2PolyPainter::DrawSectionXOZ()const
00538 {
00539
00540 }
00541
00542
00543 void TGLH2PolyPainter::DrawSectionYOZ()const
00544 {
00545
00546 }
00547
00548
00549 void TGLH2PolyPainter::DrawSectionXOY()const
00550 {
00551
00552 }
00553
00554
00555 void TGLH2PolyPainter::DrawPalette()const
00556 {
00557
00558 }
00559
00560
00561 void TGLH2PolyPainter::DrawPaletteAxis()const
00562 {
00563
00564 }
00565
00566
00567 void TGLH2PolyPainter::FillTemporaryPolygon(const Double_t *xs, const Double_t *ys, Double_t z, Int_t nV)const
00568 {
00569
00570 const Double_t xScale = fCoord->GetXScale();
00571 const Double_t yScale = fCoord->GetYScale();
00572
00573 fPolygon.resize(nV * 3);
00574 for (Int_t j = 0; j < nV; ++j) {
00575 fPolygon[j * 3] = xs[j] * xScale;
00576 fPolygon[j * 3 + 1] = ys[j] * yScale;
00577 fPolygon[j * 3 + 2] = z;
00578 }
00579
00580 if (IsPolygonCW(xs, ys, nV))
00581 MakePolygonCCW();
00582 }
00583
00584
00585 void TGLH2PolyPainter::MakePolygonCCW()const
00586 {
00587
00588 const Int_t nV = Int_t(fPolygon.size() / 3);
00589 for (Int_t a = 0; a <= (nV / 2) - 1; a++) {
00590 const Int_t b = nV - 1 - a;
00591 std::swap(fPolygon[a * 3], fPolygon[b * 3]);
00592 std::swap(fPolygon[a * 3 + 1], fPolygon[b * 3 + 1]);
00593 }
00594 }
00595
00596
00597 Bool_t TGLH2PolyPainter::ClampZ(Double_t &zVal)const
00598 {
00599
00600 if (fCoord->GetZLog()) {
00601 if (zVal <= 0.)
00602 return kFALSE;
00603 else
00604 zVal = TMath::Log10(zVal) * fCoord->GetZScale();
00605 } else
00606 zVal *= fCoord->GetZScale();
00607
00608 const TGLVertex3 *frame = fBackBox.Get3DBox();
00609
00610 if (zVal > frame[4].Z())
00611 zVal = frame[4].Z();
00612 else if (zVal < frame[0].Z())
00613 zVal = frame[0].Z();
00614
00615 return kTRUE;
00616 }
00617
00618
00619 namespace {
00620
00621
00622 Double_t Distance(const Double_t *p1, const Double_t *p2)
00623 {
00624
00625 return TMath::Sqrt((p1[0] - p2[0]) * (p1[0] - p2[0]) +
00626 (p1[1] - p2[1]) * (p1[1] - p2[1]) +
00627 (p1[2] - p2[2]) * (p1[2] - p2[2]));
00628 }
00629
00630
00631 Bool_t IsPolygonCW(const Double_t *xs, const Double_t *ys, Int_t n)
00632 {
00633
00634
00635 Double_t signedArea = 0.;
00636
00637 for (Int_t j = 0; j < n - 1; ++j)
00638 signedArea += xs[j] * ys[j + 1] - ys[j] * xs[j + 1];
00639
00640 return signedArea < 0.;
00641 }
00642
00643 }