TGL5DPainter.cxx

Go to the documentation of this file.
00001 // @(#)root/gl:$Id: TGL5DPainter.cxx 34286 2010-07-01 20:38:57Z rdm $
00002 // Author:  Timur Pocheptsov  28/07/2009
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2009, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 #include "TVirtualPad.h"
00013 #include "KeySymbols.h"
00014 #include "TVirtualX.h"
00015 #include "Buttons.h"
00016 #include "TString.h"
00017 #include "TError.h"
00018 #include "TROOT.h"
00019 #include "TMath.h"
00020 
00021 #include "TGLPlotCamera.h"
00022 #include "TGL5DPainter.h"
00023 #include "TGLPadUtils.h"
00024 #include "TGLIncludes.h"
00025 #include "TGL5D.h"
00026 
00027 //
00028 //TGL5DPainter implements "gl5d" option for TTree::Draw.
00029 //Data (4D) is visualized as a set of
00030 //iso-surfaces. 5D - not implemented yet.
00031 //
00032 
00033 //______________________________________________________________________________
00034 TGL5DPainter::TGL5DPainter(TGL5DDataSet *data, TGLPlotCamera *camera, TGLPlotCoordinates *coord)
00035          : TGLPlotPainter(data, camera, coord),
00036            fMeshBuilder(kTRUE),//kTRUE == average normals.
00037            fInit(kFALSE),
00038            fData(data),
00039            fShowSlider(kFALSE),
00040            fAlpha(0.4),
00041            fNContours(kNContours)
00042 {
00043    //Constructor.
00044    if (fData->fV4IsString)
00045       fNContours = Int_t(fData->fV4MinMax.second) - Int_t(fData->fV4MinMax.first) + 1;
00046 }
00047 
00048 //______________________________________________________________________________
00049 TGL5DPainter::SurfIter_t TGL5DPainter::AddSurface(Double_t v4, Color_t ci,
00050                                                   Double_t iso, Double_t sigma,
00051                                                   Double_t range, Int_t lownps)
00052 {
00053    //Try to add new iso-surface.
00054    //If something goes wrong, return
00055    //iterator to the end of fIsos.
00056    fData->SelectPoints(v4, range);
00057 
00058    if (fData->SelectedSize() < size_type(lownps)) {
00059       Warning("TGL5DPainter::AddSurface", "Too little points: %d", Int_t(fData->SelectedSize()));
00060       return fIsos.end();//This is a valid iterator, but an invalid surface.
00061    } else {
00062       Info("TGL5DPainter::AddSurface", "Selected %d points", Int_t(fData->SelectedSize()));
00063    }
00064 
00065    fKDE.BuildModel(fData, sigma);//Prepare density estimator.
00066 
00067    Info("TGL5DPainter::AddSurface", "Building the mesh ...");
00068    //Prepare grid parameters.
00069    Rgl::Mc::TGridGeometry<Float_t> geom(fXAxis, fYAxis, fZAxis,
00070                                         fCoord->GetXScale(),
00071                                         fCoord->GetYScale(),
00072                                         fCoord->GetZScale());
00073    Mesh_t mesh;
00074    fMeshBuilder.SetGeometry(fData);
00075    //Build a new mesh.
00076    fMeshBuilder.BuildMesh(&fKDE, geom, &mesh, iso);
00077 
00078    Info("TGL5DPainter::AddSurface", "Mesh has %d vertices", Int_t(mesh.fVerts.size() / 3));
00079 
00080    if (!mesh.fVerts.size())//I do not need an empty mesh.
00081       return fIsos.end();
00082    //Add surface with empty mesh and swap meshes.
00083    fIsos.push_front(fDummy);
00084 
00085    fIsos.front().fMesh.Swap(mesh);
00086    fIsos.front().f4D = v4;
00087    fIsos.front().fRange = range;
00088    fIsos.front().fShowCloud = kFALSE;
00089    fIsos.front().fHide = kFALSE;
00090    fIsos.front().fColor = ci;
00091 
00092    //Predictions for the 5-th variable.
00093    //Not-implemented yet.
00094    return fIsos.begin();
00095 }
00096 
00097 //______________________________________________________________________________
00098 void TGL5DPainter::AddSurface(Double_t v4)
00099 {
00100    //Add new surface. Simplified version for ged.
00101    const Rgl::Range_t &v4R = fData->fV4MinMax;
00102    const Bool_t isString   = fData->fV4IsString;
00103    const Double_t rms  = TMath::RMS(fData->fNP, fData->fV4);  //RMS of the N points.
00104    const Double_t d    = isString ? (v4R.second - v4R.first) / (fNContours - 1)
00105                                   : 6 * rms / fNContours;
00106    //alpha is in [0.1, 0.5], 1e-3 -s good for strings.
00107    const Double_t range = isString ? 1e-3 : fAlpha * d;
00108 
00109    AddSurface(v4, 1, 0.125, 0.05, range);
00110 }
00111 
00112 //______________________________________________________________________________
00113 void TGL5DPainter::RemoveSurface(SurfIter_t surf)
00114 {
00115    //Remove iso-surface.
00116    if (surf == fIsos.end()) {
00117       Error("TGL5DPainter::RemoveSurface", "Invalid iterator, surface does not exist.");
00118       return;
00119    }
00120 
00121    fIsos.erase(surf);
00122 }
00123 
00124 //______________________________________________________________________________
00125 char *TGL5DPainter::GetPlotInfo(Int_t /*px*/, Int_t /*py*/)
00126 {
00127    //Return info for plot part under cursor.
00128    static char mess[] = {"gl5d"};
00129    return mess;
00130 }
00131 
00132 //______________________________________________________________________________
00133 Bool_t TGL5DPainter::InitGeometry()
00134 {
00135    //Create mesh.
00136    //InitGeometry creates surfaces for auto-iso levels.
00137    //Called the first time and each time number of auto-levels is
00138    //reset via the editor.
00139    if (fInit)
00140       return kTRUE;
00141    //Only in cartesian.
00142    fCoord->SetCoordType(kGLCartesian);
00143 
00144    if (!fCoord->SetRanges(fXAxis, fYAxis, fZAxis))
00145       return kFALSE;
00146 
00147    fIsos.clear();
00148 
00149    fBackBox.SetPlotBox(fCoord->GetXRangeScaled(),
00150                        fCoord->GetYRangeScaled(),
00151                        fCoord->GetZRangeScaled());
00152    if (fCamera)
00153       fCamera->SetViewVolume(fBackBox.Get3DBox());
00154 
00155    const Rgl::Range_t &v4R = fData->fV4MinMax;
00156    const Bool_t isString   = fData->fV4IsString;
00157 
00158    //Rene's code to automatically find iso-levels.
00159    const Double_t mean = TMath::Mean(fData->fNP, fData->fV4); //mean value of the NP points.
00160    const Double_t rms  = TMath::RMS(fData->fNP, fData->fV4);  //RMS of the N points.
00161    const Double_t min  = isString ? v4R.first : mean - 3 * rms; //take a range +- 3*xrms
00162    const Double_t d    = isString ? (v4R.second - v4R.first) / (fNContours - 1)
00163                                   : 6 * rms / fNContours;
00164    //alpha is in [0.1, 0.5], 1e-3 -s good for strings.
00165    const Double_t range = isString ? 1e-3 : fAlpha * d;
00166 
00167    Info("InitGeometry", "min = %g, mean = %g, rms = %g, dx = %g", min, mean, rms, d);
00168 
00169    for (Int_t j = 0; j < fNContours; ++j) {
00170       const Double_t isoLevel = min + j * d;
00171       Info("TGL5DPainter::InitGeometry", "Iso-level %g, range is %g ...", isoLevel, range);
00172       const Color_t color = j * 6 + 1;
00173       AddSurface(isoLevel, color, 0.125, 0.05, range);
00174    }
00175 
00176    if (fIsos.size())
00177       fBoxCut.TurnOnOff();
00178 
00179    return fInit = kTRUE;
00180 }
00181 
00182 //______________________________________________________________________________
00183 void TGL5DPainter::StartPan(Int_t px, Int_t py)
00184 {
00185    //User clicks right mouse button (in a pad).
00186    fMousePosition.fX = px;
00187    fMousePosition.fY = fCamera->GetHeight() - py;
00188    fCamera->StartPan(px, py);
00189    fBoxCut.StartMovement(px, fCamera->GetHeight() - py);
00190 }
00191 
00192 //______________________________________________________________________________
00193 void TGL5DPainter::Pan(Int_t px, Int_t py)
00194 {
00195    //Mouse events handler.
00196    if (fSelectedPart >= fSelectionBase) {//Pan camera.
00197       SaveModelviewMatrix();
00198       SaveProjectionMatrix();
00199 
00200       fCamera->SetCamera();
00201       fCamera->Apply(fPadPhi, fPadTheta);
00202       fCamera->Pan(px, py);
00203 
00204       RestoreProjectionMatrix();
00205       RestoreModelviewMatrix();
00206    } else if (fSelectedPart > 0) {
00207       //Convert py into bottom-top orientation.
00208       py = fCamera->GetHeight() - py;
00209 
00210       SaveModelviewMatrix();
00211       SaveProjectionMatrix();
00212 
00213       fCamera->SetCamera();
00214       fCamera->Apply(fPadPhi, fPadTheta);
00215 
00216       if (!fHighColor) {
00217          if (fBoxCut.IsActive() && (fSelectedPart >= kXAxis && fSelectedPart <= kZAxis)) {
00218             fBoxCut.MoveBox(px, py, fSelectedPart);
00219          }
00220       }
00221 
00222       RestoreProjectionMatrix();
00223       RestoreModelviewMatrix();
00224    }
00225 
00226    fMousePosition.fX = px, fMousePosition.fY = py;
00227    fUpdateSelection = kTRUE;
00228 }
00229 
00230 //______________________________________________________________________________
00231 void TGL5DPainter::AddOption(const TString &/*option*/)
00232 {
00233    //No additional options for TGL5DPainter.
00234 }
00235 
00236 //______________________________________________________________________________
00237 void TGL5DPainter::ProcessEvent(Int_t event, Int_t /*px*/, Int_t py)
00238 {
00239 
00240    //Change color sheme.
00241    if (event == kKeyPress) {
00242       if (py == kKey_c || py == kKey_C) {
00243          if (fHighColor)
00244             Info("ProcessEvent", "Cut box does not work in high color, please, switch to true color");
00245          else {
00246             fBoxCut.TurnOnOff();
00247             fUpdateSelection = kTRUE;
00248          }
00249       }
00250    } else if (event == kButton1Double && fBoxCut.IsActive()) {
00251       if (fBoxCut.IsActive())
00252          fBoxCut.TurnOnOff();
00253       if (!gVirtualX->IsCmdThread())
00254          gROOT->ProcessLineFast(Form("((TGLPlotPainter *)0x%lx)->Paint()", (ULong_t)this));
00255       else
00256          Paint();
00257    }
00258 }
00259 
00260 //______________________________________________________________________________
00261 void TGL5DPainter::SetAlpha(Double_t newVal)
00262 {
00263    //Set selection range parameter.
00264    if (fAlpha != newVal && !fData->fV4IsString) {
00265       fAlpha = newVal;
00266       fInit = kFALSE;
00267       InitGeometry();
00268    }
00269 
00270    if (fData->fV4IsString)
00271       Warning("SetAlpha", "Alpha is not required for string data (your 4-th dimension is string).");
00272 }
00273 
00274 //______________________________________________________________________________
00275 void TGL5DPainter::SetNContours(Int_t n)
00276 {
00277    //Set the number of predefined contours.
00278 
00279    if (n <= 0) {
00280       Warning("SetNContours", "Bad number of contours: %d", n);
00281       return;
00282    }
00283 
00284    fNContours = n;
00285    fInit = kFALSE;
00286    InitGeometry();
00287 }
00288 
00289 //______________________________________________________________________________
00290 void TGL5DPainter::ResetGeometryRanges()
00291 {
00292    //No need to create or delete meshes,
00293    //number of meshes (iso-levels) are
00294    //the same, but meshes must be rebuilt
00295    //in new ranges.
00296    //Only in cartesian.
00297    fCoord->SetRanges(fXAxis, fYAxis, fZAxis);
00298    fBackBox.SetPlotBox(fCoord->GetXRangeScaled(),
00299                        fCoord->GetYRangeScaled(),
00300                        fCoord->GetZRangeScaled());
00301    if (fCamera)
00302       fCamera->SetViewVolume(fBackBox.Get3DBox());
00303    //Iterate through all surfaces and re-calculate them.
00304    for (SurfIter_t surf = fIsos.begin(); surf != fIsos.end(); ++surf) {
00305       fData->SelectPoints(surf->f4D, surf->fRange);
00306       fKDE.BuildModel(fData, 0.05);//0.05 is sigma, will be controlled via GUI.
00307       Info("TGL5DPainter::ResetGeometryRanges", "Building the mesh ...");
00308       //Prepare grid parameters.
00309       Rgl::Mc::TGridGeometry<Float_t> geom(fXAxis, fYAxis, fZAxis,
00310                                            fCoord->GetXScale(),
00311                                            fCoord->GetYScale(),
00312                                            fCoord->GetZScale());
00313       fMeshBuilder.SetGeometry(fData);
00314       Mesh_t &mesh = surf->fMesh;
00315       //Clear old data.
00316       mesh.fVerts.clear();
00317       mesh.fNorms.clear();
00318       mesh.fTris.clear();
00319       //Build new mesh.
00320       fMeshBuilder.BuildMesh(&fKDE, geom, &mesh, 0.125);//0.125 will be set via GUI.
00321       Info("TGL5DPainter::AddSurface", "Mesh has %d vertices", Int_t(mesh.fVerts.size() / 3));
00322    }
00323 
00324    fBoxCut.ResetBoxGeometry();
00325 }
00326 
00327 //______________________________________________________________________________
00328 TGL5DPainter::SurfIter_t TGL5DPainter::SurfacesBegin()
00329 {
00330    //std::list::begin.
00331    return fIsos.begin();
00332 }
00333 
00334 //______________________________________________________________________________
00335 TGL5DPainter::SurfIter_t TGL5DPainter::SurfacesEnd()
00336 {
00337    //std::list::end.
00338    return fIsos.end();
00339 }
00340 
00341 //______________________________________________________________________________
00342 void TGL5DPainter::InitGL() const
00343 {
00344    //Initialize OpenGL state variables.
00345    glEnable(GL_LIGHTING);
00346    glEnable(GL_LIGHT0);
00347    glEnable(GL_DEPTH_TEST);
00348    glDisable(GL_CULL_FACE);
00349    glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
00350 }
00351 
00352 //______________________________________________________________________________
00353 void TGL5DPainter::DeInitGL()const
00354 {
00355    //Return some gl states to original values.
00356    glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
00357    glDisable(GL_CULL_FACE);
00358    glDisable(GL_DEPTH_TEST);
00359    glDisable(GL_LIGHT0);
00360    glDisable(GL_LIGHTING);
00361 }
00362 
00363 //______________________________________________________________________________
00364 void TGL5DPainter::DrawPlot() const
00365 {
00366    //Draw a set of meshes.
00367 
00368    //Shift plot to point of origin.
00369    const Rgl::PlotTranslation trGuard(this);
00370 
00371    fBackBox.DrawBox(fSelectedPart, fSelectionPass, fZLevels, fHighColor);
00372    //
00373    if (!fIsos.size())
00374       DrawCloud();
00375    else {
00376       //Two passes. First, non-transparent surfaces.
00377       Bool_t needSecondPass = kFALSE;
00378       for (ConstSurfIter_t it = fIsos.begin(); it != fIsos.end(); ++it) {
00379          //
00380          if (it->fHide)
00381             continue;
00382          if (it->fAlpha != 100) {
00383             needSecondPass = kTRUE;
00384             continue;
00385          }
00386          if (!fSelectionPass)
00387             SetSurfaceColor(it);
00388          glEnable(GL_POLYGON_OFFSET_FILL);
00389          glPolygonOffset(1.f, 1.f);
00390          DrawMesh(it);
00391          glDisable(GL_POLYGON_OFFSET_FILL);
00392 
00393          if (!fSelectionPass && it->fHighlight) {
00394             const TGLDisableGuard lightGuard(GL_LIGHTING);
00395             const TGLEnableGuard  blendGuard(GL_BLEND);
00396             glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00397             glColor4d(1., 0.4, 0., 0.5);
00398             DrawMesh(it);
00399          }
00400       }
00401       //Second pass - semi-transparent surfaces.
00402       if (needSecondPass) {
00403          const TGLEnableGuard  blendGuard(GL_BLEND);
00404          glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00405          glDepthMask(GL_FALSE);
00406          for (ConstSurfIter_t it = fIsos.begin(); it != fIsos.end(); ++it) {
00407             //
00408             if (it->fAlpha == 100)
00409                continue;
00410             if (!fSelectionPass)
00411                SetSurfaceColor(it);
00412 
00413             glEnable(GL_POLYGON_OFFSET_FILL);
00414             glPolygonOffset(1.f, 1.f);
00415             DrawMesh(it);
00416             glDisable(GL_POLYGON_OFFSET_FILL);
00417 
00418             if (!fSelectionPass && it->fHighlight) {
00419                const TGLDisableGuard lightGuard(GL_LIGHTING);
00420                glColor4d(1., 0.4, 0., it->fAlpha / 150.);
00421                DrawMesh(it);
00422             }
00423          }
00424          glDepthMask(GL_TRUE);
00425       }
00426    }
00427 
00428    if (fBoxCut.IsActive())
00429       fBoxCut.DrawBox(fSelectionPass, fSelectedPart);
00430 }
00431 
00432 //______________________________________________________________________________
00433 void TGL5DPainter::SetSurfaceColor(ConstSurfIter_t it)const
00434 {
00435    //Set the color for iso-surface.
00436    Color_t ind = it->fColor;
00437    Float_t rgba[] = {0.f, 0.f, 0.f, it->fAlpha / 100.};
00438    Rgl::Pad::ExtractRGB(ind, rgba);
00439    //Set color for surface.
00440    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, rgba);
00441    const Float_t specColor[] = {1.f, 1.f, 1.f, 1.f};
00442    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specColor);
00443    glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 20.f);
00444 }
00445 
00446 //______________________________________________________________________________
00447 void TGL5DPainter::DrawCloud()const
00448 {
00449    //Draw full cloud of points.
00450    const TGLDisableGuard light(GL_LIGHTING);
00451    const TGLDisableGuard depth(GL_DEPTH_TEST);
00452 
00453    glColor3d(0.4, 0., 1.);
00454    glPointSize(3.f);
00455 
00456    glBegin(GL_POINTS);
00457 
00458    const Double_t xs = fCoord->GetXScale();
00459    const Double_t ys = fCoord->GetYScale();
00460    const Double_t zs = fCoord->GetZScale();
00461 
00462    for (Int_t i = 0; i < fData->fNP; ++i)
00463       glVertex3d(fData->fV1[i] * xs, fData->fV2[i] * ys, fData->fV3[i] * zs);
00464 
00465    glEnd();
00466 
00467    glPointSize(1.f);
00468 }
00469 
00470 //______________________________________________________________________________
00471 void TGL5DPainter::DrawSubCloud(Double_t v4, Double_t range, Color_t ci)const
00472 {
00473    //Draw cloud for selected iso-surface.
00474    const TGLDisableGuard light(GL_LIGHTING);
00475 
00476    Float_t rgb[3] = {};
00477    Rgl::Pad::ExtractRGB(ci, rgb);
00478 
00479    glColor3fv(rgb);
00480    glPointSize(3.f);
00481 
00482    glBegin(GL_POINTS);
00483 
00484    const Double_t xs = fCoord->GetXScale();
00485    const Double_t ys = fCoord->GetYScale();
00486    const Double_t zs = fCoord->GetZScale();
00487 
00488    for (Int_t i = 0; i < fData->fNP; ++i)
00489       if (TMath::Abs(fData->fV4[i] - v4) < range)
00490          glVertex3d(fData->fV1[i] * xs, fData->fV2[i] * ys, fData->fV3[i] * zs);
00491 
00492    glEnd();
00493 
00494    glPointSize(1.f);
00495 }
00496 
00497 //______________________________________________________________________________
00498 void TGL5DPainter::DrawMesh(ConstSurfIter_t surf)const
00499 {
00500    //Draw one iso-surface.
00501 
00502    const Mesh_t &m = surf->fMesh;
00503 
00504    if (!fBoxCut.IsActive()) {
00505       if (!fSelectionPass)
00506          Rgl::DrawMesh(m.fVerts, m.fNorms, m.fTris);
00507       else {
00508          Rgl::ObjectIDToColor(fSelectionBase, fHighColor);
00509          Rgl::DrawMesh(m.fVerts, m.fTris);
00510       }
00511    } else {
00512       if (!fSelectionPass) {
00513          Rgl::DrawMesh(m.fVerts, m.fNorms, m.fTris, fBoxCut);
00514       } else {
00515          Rgl::ObjectIDToColor(fSelectionBase, fHighColor);
00516          Rgl::DrawMesh(m.fVerts, m.fTris, fBoxCut);
00517       }
00518    }
00519 }

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