CMS 3D CMS Logo

IgSoCircularHist.cc

Go to the documentation of this file.
00001 //<<<<<< INCLUDES                       >>>>>>
00002 
00003 #include "Iguana/Inventor/interface/IgSoCircularHist.h" 
00004 #include <Inventor/nodes/SoText2.h>
00005 #include <Inventor/nodes/SoFont.h>
00006 #include <Inventor/nodes/SoTranslation.h>
00007 #include <Inventor/nodes/SoRotation.h>
00008 #include <Inventor/nodes/SoSeparator.h>
00009 #include <Inventor/nodes/SoIndexedFaceSet.h>
00010 #include <Inventor/nodes/SoShapeHints.h>
00011 #include <Inventor/nodes/SoMaterial.h>
00012 #include <Inventor/nodes/SoMaterialBinding.h>
00013 #include <Inventor/nodes/SoIndexedLineSet.h>
00014 #include <Inventor/nodes/SoVertexProperty.h>
00015 #include <Inventor/nodes/SoCoordinate3.h>
00016 #include <Inventor/nodes/SoFaceSet.h>
00017 #include <vector>
00018 
00019 //<<<<<< PRIVATE DEFINES                                                >>>>>>
00020 //<<<<<< PRIVATE CONSTANTS                                              >>>>>>
00021 //<<<<<< PRIVATE TYPES                                                  >>>>>>
00022 //<<<<<< PRIVATE VARIABLE DEFINITIONS                                   >>>>>>
00023 //<<<<<< PUBLIC VARIABLE DEFINITIONS                                    >>>>>>
00024 //<<<<<< CLASS STRUCTURE INITIALIZATION                                 >>>>>>
00025 
00026 SO_KIT_SOURCE (IgSoCircularHist);
00027 
00028 //<<<<<< PRIVATE FUNCTION DEFINITIONS                                   >>>>>>
00029 
00030 // returns x, y, z coordinates given polar coordinates
00031 // @ param radialCoords = ( radius, angle, z)
00032 // angle supposed to be in rad
00033 
00034 inline SbVec3f 
00035 convertCoordinates (SbVec3f radialCoords)
00036 {
00037     SbVec3f cartesianCoords;
00038     cartesianCoords [0] = radialCoords [0] * cos (radialCoords [1]);
00039     cartesianCoords [1] = radialCoords [0] * sin (radialCoords [1]);
00040     cartesianCoords [2] = radialCoords [2];
00041     return cartesianCoords;
00042 }
00043 
00044 //<<<<<< PUBLIC FUNCTION DEFINITIONS                                    >>>>>>
00045 //<<<<<< MEMBER FUNCTION DEFINITIONS                                    >>>>>>
00046 
00047 void 
00048 IgSoCircularHist::initClass (void)
00049 { SO_KIT_INIT_CLASS (IgSoCircularHist, IgSoShapeKit, "IgSoShapeKit"); }
00050 
00051 IgSoCircularHist::IgSoCircularHist (void)
00052 {
00053     SO_KIT_CONSTRUCTOR (IgSoCircularHist);
00054     // parameters of the constructor
00055     SO_KIT_ADD_FIELD (minRadius,                (1.3));
00056     SO_KIT_ADD_FIELD (maxRadius,                (1.5));
00057     SO_KIT_ADD_FIELD (numberOfBins,             (180));    
00058     SO_KIT_ADD_FIELD (energies,                 (0.0)); // vector of positive energies in GeV
00059     SO_KIT_ADD_FIELD (logScale,                 (false));
00060     SO_KIT_ADD_FIELD (layer,                    (0.0)); // determines the z position of the histogram
00061     SO_KIT_ADD_FIELD (scaleFactor,              (0.1)); // for unconstrained linear and log scale the histograms can be scaled with this factor
00062     SO_KIT_ADD_FIELD (showAnnotations,          (false));
00063     SO_KIT_ADD_CATALOG_ENTRY (shapeHints, SoShapeHints, FALSE, separator,\x0, TRUE);
00064     SO_KIT_ADD_CATALOG_ENTRY (faceSet, SoIndexedFaceSet, FALSE, separator,\x0, TRUE);
00065     SO_KIT_ADD_CATALOG_ENTRY (lines, SoIndexedLineSet, FALSE, separator,\x0, TRUE);    
00066     SO_KIT_ADD_CATALOG_ENTRY (ruler, SoSeparator, FALSE, separator,\x0, TRUE);
00067     
00068     SO_KIT_INIT_INSTANCE ();
00069     setUpConnections (true, true);
00070 }
00071 
00072 void
00073 IgSoCircularHist::refresh (void)
00074 {
00075     if (energies.getNum () == 0)
00076     {
00077         setPart ("shapeHints", NULL);
00078         setPart ("faceSet",    NULL);
00079         setPart ("lines",      NULL);
00080         setPart ("ruler",      NULL);
00081         return;
00082     }
00083 
00084     // ingredients for the circular histogram
00085     SoIndexedFaceSet* faceSet = new SoIndexedFaceSet;
00086     SoIndexedLineSet* lineSet = new SoIndexedLineSet;
00087     SoShapeHints* shapeHints = new SoShapeHints;    
00088     SoVertexProperty* vtx = new SoVertexProperty;   
00089     
00090     // make a local copy of SO_KIT fields
00091     float               rMin = minRadius.getValue ();
00092     float               rMax = maxRadius.getValue ();
00093     int                 nbrOfBins =  numberOfBins.getValue ();    
00094     float               zLayer = layer.getValue ();
00095     float               factor = scaleFactor.getValue ();
00096     bool                annotations = showAnnotations.getValue ();
00097     bool                logarithmic = logScale.getValue ();
00098     
00099     // enabling rendering of front and back faces   
00100     shapeHints->vertexOrdering = SoShapeHints::COUNTERCLOCKWISE;
00101     shapeHints->faceType = SoShapeHints::CONVEX;
00102 
00103     // prepare space for  a local copy of the energy vector
00104     std::vector<float> energies2 (nbrOfBins);
00105     
00106     // look for bin with maximum energy sum
00107     float               maxEn  = 0.0;
00108     int                 maxEnIndex = 0;
00109     for (int i = 0; i < nbrOfBins; i++)
00110     {
00111         if (energies [i] > maxEn)
00112         {
00113             maxEn = energies [i];
00114             maxEnIndex = i;             
00115         }
00116     }
00117     
00118     // if constrained linear scale is used find the maximum energy value
00119     // for logscale  apply  log to contents of the energy vector
00120     if (logarithmic)
00121     {
00122         for (int i = 0; i < nbrOfBins; i++)
00123         {
00124             energies2 [i] = factor  * log (energies [i] + 1.0);   
00125         }                   
00126     }
00127    
00128     /* building  vector containing the vertices for the faces of the shape*/
00129     std::vector<SbVec3f> vertexData (3 * nbrOfBins + 1);        
00130 
00131     vertexData [0] = convertCoordinates (SbVec3f (rMin, 0.0, zLayer));
00132     for (int i = 0; i < nbrOfBins ; i++)
00133     {
00134         float phi = 2.0 * M_PI / nbrOfBins * (i + 1);
00135         // for liner scale
00136         if (! logarithmic)
00137         {
00138             // if rMax == -1, print energy towers according to energy amount in bin
00139             if (rMax == -1) 
00140             {
00141                 vertexData [i * 3 + 1] = convertCoordinates (SbVec3f (rMin, phi, zLayer));
00142                 vertexData [i * 3 + 2] = convertCoordinates (SbVec3f (rMin + factor * energies [i], phi, zLayer));
00143                 vertexData [i * 3 + 3] = convertCoordinates (SbVec3f (rMin + factor * energies [i], 2 * M_PI / nbrOfBins * i, zLayer));         
00144             }
00145             // otherwise scale the towers to [rMin, rMax] such that the maximum energy results in a tower of height rMax
00146             else
00147             {
00148                 vertexData [i * 3 + 1] = convertCoordinates (SbVec3f (rMin, phi, zLayer));
00149                 vertexData [i * 3 + 2] = convertCoordinates (SbVec3f (rMin + energies [i] / maxEn * (rMax - rMin), phi, zLayer));
00150                 vertexData [i * 3 + 3] = convertCoordinates (SbVec3f (rMin + energies [i] / maxEn * (rMax - rMin), 2 * M_PI / nbrOfBins * i, zLayer)); 
00151             }
00152         }
00153         // if logScale == true, use energies2 = log(energies)
00154         else
00155         {
00156             if ((rMax >= rMin) || (rMax == -1))
00157             {
00158                 vertexData [i * 3 + 1] = convertCoordinates (SbVec3f (rMin, phi, zLayer));
00159                 vertexData [i * 3 + 2] = convertCoordinates (SbVec3f (rMin + energies2 [i], phi, zLayer));
00160                 vertexData [i * 3 + 3] = convertCoordinates (SbVec3f (rMin + energies2 [i], 2 * M_PI / nbrOfBins * i, zLayer));      
00161             }
00162             else
00163             {
00164                 vertexData [i * 3 + 1] = convertCoordinates (SbVec3f (rMin, phi, zLayer));
00165                 vertexData [i * 3 + 2] = convertCoordinates (SbVec3f (rMin - energies2 [i], phi, zLayer));
00166                 vertexData [i * 3 + 3] = convertCoordinates (SbVec3f (rMin - energies2 [i], 2 * M_PI / nbrOfBins * i, zLayer));  
00167             }
00168         }
00169     }
00170    
00171     /* building  vector indicating the vertices belonging to each face*/
00172     std::vector<int> faceIndices (nbrOfBins * 5);
00173     faceIndices [0] = 0;
00174     faceIndices [1] = 1;
00175     faceIndices [2] = 2;
00176     faceIndices [3] = 3;
00177     faceIndices [4] = SO_END_FACE_INDEX;
00178 
00179     for (int i = 1; i < nbrOfBins; i++)
00180     { 
00181         faceIndices [i * 5] = (i - 1) * 3 + 1;
00182         faceIndices [i * 5 + 1] = (i - 1) * 3 + 4;
00183         faceIndices [i * 5 + 2] = (i - 1) * 3 + 5;
00184         faceIndices [i * 5 + 3] = (i - 1) * 3 + 6;
00185         faceIndices [i * 5 + 4] = SO_END_FACE_INDEX; 
00186     }
00187     
00188     vtx->vertex.setValues (0, nbrOfBins * 3 + 1 ,&vertexData [0]);
00189     vtx->materialBinding = SoMaterialBinding::PER_FACE_INDEXED;
00190     
00191     faceSet->coordIndex.setValues (0, nbrOfBins * 5, &faceIndices [0]);
00192     faceSet->vertexProperty = vtx;
00193 
00194     // building  vector indication the vertices belonging to each line
00195     std::vector<int>  lineIndices (2 * nbrOfBins + 1);
00196     
00197     for (int i = 0; i < nbrOfBins; i++)
00198     {
00199         lineIndices [2 * i] = 3 * i + 3;
00200         lineIndices [2 * i + 1] = 3 * i + 2;      
00201     }
00202     lineIndices [2 * nbrOfBins] = 3;
00203   
00204     SoVertexProperty* lineVtx = new SoVertexProperty;
00205     lineVtx->vertex.setValues (0, nbrOfBins * 3 + 1, &vertexData [0]);
00206   
00207     lineSet->coordIndex.setValues (0, 2 * nbrOfBins + 1, &lineIndices [0]);
00208     lineSet->vertexProperty = lineVtx;
00209 
00212     setPart ("shapeHints", shapeHints);
00213     setPart ("faceSet", faceSet);
00214     setPart ("lines", lineSet);             
00215 
00219     // compute all the stuff only if annotations are requested ///////////////////////////////
00220     if (annotations)
00221     {   
00222         float offset; // fraction or ruler length equivalent to remainder of (maximum energy div 10 GeV)
00223         int nbrOfDivisions;   
00224         float divisionLength; 
00225         float rulerLength; //ruler length =  nbrOfDivisions*divisionLength + offset 
00226 
00227         // find the appropriate length for the scale axis
00228         // in case of negativ energies the ruler length is negative
00229         if (! logarithmic)
00230         {
00231             // if unconstrained linear scale is used, the length equals the maximum found energy sum otherwise the rMax - rMin     
00232             rulerLength = (rMax == -1 ) ? factor  *  maxEn : rMax - rMin;
00233         }               
00234         // for log scale the length equals log( maxEn)
00235         else
00236         {
00237             rulerLength = ((rMax >= rMin) || (rMax == -1)) ? energies2 [maxEnIndex] : (-energies2 [maxEnIndex]);
00238         }       
00239 
00240         // if the axis is not too small, prepare drawing
00241         if ((rulerLength > 0.1) || (rulerLength < -0.1))
00242         {
00243             // ingredients for the ruler
00244             SoSeparator* ruler = new  SoSeparator;
00245             SoMaterial* axisMaterial = new SoMaterial;            
00246             SoRotation* zrot = new SoRotation;
00247             //SoTranslation* ytrans = new SoTranslation;
00248             
00249             // define the material for the axis
00250             axisMaterial->diffuseColor.setValue(0.0, 0.0, 0.0); // orange          
00251                 
00252             // the offset has to be computed in order to compute the correct division length
00253             offset = (rulerLength >= 0) ? (rulerLength * (1.0 -  floor (0.1 * maxEn) / (maxEn * 0.1))) : (-rulerLength * (1.0 -  floor (0.1 * maxEn) / (maxEn * 0.1)));
00254            
00255             if (! logarithmic)
00256             {
00257                 nbrOfDivisions = static_cast<int>(floor (maxEn * 0.1));
00258 
00259                 if (nbrOfDivisions == 0)
00260                 {
00261                     nbrOfDivisions = 1;
00262                     divisionLength = rulerLength;
00263                 }
00264                 else
00265                 {
00266                     divisionLength = (rulerLength - offset) / nbrOfDivisions;
00267                     // if (offset - divisionLength) is larger then the arrowhead draw one marker more
00268                     if (! (offset == 0) && ((offset - divisionLength) > 0.1  * rulerLength))
00269                     {
00270                         nbrOfDivisions += 1;
00271                     }
00272                 }               
00273             }
00274             //our axis is not able to display logarithmic scale, so in logScale case we do not draw division markers
00275             else 
00276             {
00277                 nbrOfDivisions = 1;
00278                 divisionLength = rulerLength;
00279             }
00280             
00281             float w = 2 * M_PI / nbrOfBins; // bin width in rad 
00282             float rulerAngle =  2 * M_PI / nbrOfBins * (float (maxEnIndex) + 0.5) ; // angle of the bin with highest energy
00283             float zDist = 0.001; // put the ruler slightly above the Histogram by adding zDist to z coordinate to make it visible
00284 
00285             // construct the ruler vertices, first a quad and an triangle for the arrow, than the devision markers
00286             std::vector<SbVec3f>  rulerVtx (7 + 4 * nbrOfDivisions);         
00287             
00288             rulerVtx [0] = convertCoordinates (SbVec3f (rMin,                           rulerAngle - w / 4.0,   zLayer + zDist));           
00289             rulerVtx [1] = convertCoordinates (SbVec3f (rMin + 9.0/10.0*rulerLength,    rulerAngle - w / 8.0,   zLayer + zDist));           
00290             rulerVtx [2] = convertCoordinates (SbVec3f (rMin + 9.0/10.0*rulerLength,    rulerAngle + w / 8.0,   zLayer + zDist));           
00291             rulerVtx [3] = convertCoordinates (SbVec3f (rMin,                           rulerAngle + w / 4.0,   zLayer + zDist));           
00292             rulerVtx [4] = convertCoordinates (SbVec3f (rMin + 9.0/10.0*rulerLength,    rulerAngle - w / 4.0,   zLayer + zDist));           
00293             rulerVtx [5] = convertCoordinates (SbVec3f (rMin + rulerLength,             rulerAngle,             zLayer + zDist));           
00294             rulerVtx [6] = convertCoordinates (SbVec3f (rMin + 9.0/10.0*rulerLength,    rulerAngle + w / 4.0,   zLayer + zDist));    
00295             
00296             for (int i = 1; i < nbrOfDivisions; i++)
00297             {
00298                 rulerVtx [3+ i * 4]     = convertCoordinates (SbVec3f (rMin + divisionLength * i - 0.01, rulerAngle - w / 3.0,  zLayer + zDist));  
00299                 rulerVtx [3+ i * 4 + 1] = convertCoordinates (SbVec3f (rMin + divisionLength * i + 0.01, rulerAngle - w / 3.0,  zLayer + zDist));
00300                 rulerVtx [3+ i * 4 + 2] = convertCoordinates (SbVec3f (rMin + divisionLength * i + 0.01, rulerAngle + w / 3.0,  zLayer + zDist));
00301                 rulerVtx [3+ i * 4 + 3] = convertCoordinates (SbVec3f (rMin + divisionLength * i - 0.01, rulerAngle + w / 3.0,  zLayer + zDist));
00302             }
00303             
00304             SoCoordinate3* rulerCoords = new SoCoordinate3;
00305             rulerCoords->point.setValues (0, 7 + 4 * (nbrOfDivisions - 1), &rulerVtx [0]);
00306 
00307             std::vector<int> numVtx (1 + nbrOfDivisions);
00308             numVtx [0] = 4;
00309             numVtx [1] = 3;
00310             for (int i = 0; i < (nbrOfDivisions - 1); i++)
00311             {
00312                 numVtx [2 + i] = 4;
00313             }
00314             
00315             SoFaceSet* rulerFaceSet = new SoFaceSet;
00316             rulerFaceSet->numVertices.setValues (0, 2 + nbrOfDivisions - 1 , &numVtx [0]);
00317             
00318             // prepare the label of the ruler and translate it to the proper place on the arrowhead
00319             // label the axis with appropriate unit, if maxEn > 100 GeV, change to TeV
00320             char label [50];
00321             if (maxEn >= 100.0)
00322             {
00323                 sprintf (label, "Emax = %.1f TeV", maxEn / 1000.0);
00324             }
00325             else
00326             {
00327                 sprintf (label, "Emax = %.1f GeV", maxEn);
00328             }
00329             
00330             SoFont* labelFont = new SoFont;
00331             labelFont->size.setValue (16.0);
00332             labelFont->name.setValue ("Times-Roman");
00333 
00334             SoText2* labelText = new SoText2;
00335             labelText->string = label;
00336             labelText->justification = SoText2::CENTER;
00337 
00338             SoTranslation* labelTrans = new SoTranslation;
00339 
00340             // compute the rotation and translation to align the label with the bin with the maximum energy sum
00341             // if unconstrained linear scale or linear / logarithmic scale for positive energies  is used , axis has always to point outside
00342             // rotate to middle of wanted bin which has  phi = 2 * M_PI / nbrOfBins *( float(maxEnIndex) + 0.5)
00343             if ((rMax == -1) || (rMax >= rMin))
00344             {
00345                 zrot->rotation.setValue (SbVec3f (0.0, 0.0, 1.0), - (M_PI / 2 - 2 * M_PI / nbrOfBins * (float (maxEnIndex) + 0.5)));
00346                 labelTrans->translation.setValue (0.0, 1.1 * (rMin + rulerLength), zLayer + zDist);
00347             }
00348             // else hawe have constrained linear for negative energies or logarithmic scale for negative energies, hence ruler  points inwards
00349             else
00350             {
00351                 zrot->rotation.setValue (SbVec3f (0.0, 0.0, 1.0), - (M_PI / 2 - 2 * M_PI / nbrOfBins * (float (maxEnIndex) + 0.5)) + M_PI);
00352                 labelTrans->translation.setValue (0.0, -0.9 * (rMin + rulerLength), zLayer + zDist);
00353             }
00354             
00355             // now construct the ruler and add it to the scene graph
00356             ruler->addChild (axisMaterial);
00357             ruler->addChild (rulerCoords);
00358             ruler->addChild (rulerFaceSet);
00359             ruler->addChild (labelFont);
00360             ruler->addChild (zrot);
00361             ruler->addChild (labelTrans);
00362             ruler->addChild (labelText);
00363             
00364             setPart ("ruler",   ruler);
00365         }
00366     }
00367 }

Generated on Tue Jun 9 17:38:45 2009 for CMSSW by  doxygen 1.5.4