OpenWalnut  1.5.0dev
WMMultiHistogramView.cpp
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6 // For more information see http://www.openwalnut.org/copying
7 //
8 // This file is part of OpenWalnut.
9 //
10 // OpenWalnut is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // OpenWalnut is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
22 //
23 //---------------------------------------------------------------------------
24 
25 #include <algorithm>
26 #include <limits>
27 #include <memory>
28 #include <string>
29 #include <utility>
30 #include <vector>
31 
32 #include <boost/bind/bind.hpp>
33 #include <boost/thread/locks.hpp>
34 #include <boost/thread/mutex.hpp>
35 #include <osg/Drawable>
36 #include <osg/Geode>
37 #include <osg/Geometry>
38 #include <osg/LineWidth>
39 #include <osgText/Text>
40 
41 #include "WMHistogramView.xpm"
42 #include "WMMultiHistogramView.h"
43 #include "core/common/WPathHelper.h"
44 #include "core/common/WStringUtils.h"
45 #include "core/graphicsEngine/WGERequirement.h"
46 #include "core/kernel/WKernel.h"
47 #include "core/ui/WUI.h"
48 #include "core/ui/WUIViewEventHandler.h"
49 #include "core/ui/WUIViewWidget.h"
50 
51 //! The number of inputs/datasets/histograms.
52 #define NUM_INPUTS 3
53 
55 
57  : WModule(),
58  m_mousePos(),
59  m_frameSize( 0.04 )
60 {
61 }
62 
64 {
65 }
66 
67 std::shared_ptr< WModule > WMMultiHistogramView::factory() const
68 {
69  return std::shared_ptr< WModule >( new WMMultiHistogramView() );
70 }
71 
73 {
74  return WMHistogramView_xpm;
75 }
76 const std::string WMMultiHistogramView::getName() const
77 {
78  return "MultiHistogramView";
79 }
80 
81 const std::string WMMultiHistogramView::getDescription() const
82 {
83  return "Draws histograms of one or more datasets.";
84 }
85 
87 {
88  m_input.resize( NUM_INPUTS );
89 
90  for( std::size_t k = 0; k < m_input.size(); ++k )
91  {
92  m_input[ k ] = std::shared_ptr< WModuleInputData< WDataSetSingle > >(
94  shared_from_this(),
95  std::string( "Input dataset #" ) + string_utils::toString( k ),
96  "A dataset to show in the histogram viewer." ) );
97  addConnector( m_input[ k ] );
98  }
99 
101 }
102 
104 {
105  m_propCondition = std::shared_ptr< WCondition >( new WCondition() );
106 
107  m_histoBins = m_properties->addProperty( "Histogram bins", "Number of bins for the histogram.", 100, m_propCondition );
108  m_histoBins->setMin( 1 );
109  m_histoBins->setMax( 2000 );
110 
111  std::shared_ptr< WItemSelection > selections( new WItemSelection() );
112 
113  // add the possible histogram styles and
114  // corresponding geometry generation functions
115  selections->addItem( "Bars", "Draws transparent bars on top of each other." );
116  m_geometryFunctions.push_back( boost::bind( &WMMultiHistogramView::createGeometryBars, this, 1 ) );
117 
118  selections->addItem( "Parallel Bars", "Draws bars of the datasets next to each other per bin." );
119  m_geometryFunctions.push_back( boost::bind( &WMMultiHistogramView::createGeometryBars, this, 2 ) );
120 
121  selections->addItem( "Cumulative Bars", "Draws stacked bars." );
122  m_geometryFunctions.push_back( boost::bind( &WMMultiHistogramView::createGeometryBars, this, 3 ) );
123 
124  selections->addItem( "Curves", "Draws curves." );
125  m_geometryFunctions.push_back( boost::bind( &WMMultiHistogramView::createGeometryCurves, this, 1 ) );
126 
127  selections->addItem( "Cumulative Curves", "Draws stacked curves." );
128  m_geometryFunctions.push_back( boost::bind( &WMMultiHistogramView::createGeometryCurves, this, 2 ) );
129 
130  selections->addItem( "Stairs", "Draws 'stairs'." );
131  m_geometryFunctions.push_back( boost::bind( &WMMultiHistogramView::createGeometryStairs, this, 1 ) );
132 
133  selections->addItem( "Cumulative Stairs", "Draws stacked 'staris'" );
134  m_geometryFunctions.push_back( boost::bind( &WMMultiHistogramView::createGeometryStairs, this, 2 ) );
135 
136  // add the actual selection property
137  m_styleSelection = m_properties->addProperty( "Histogram style", "How the histograms should be rendered",
138  selections->getSelectorFirst(), m_propCondition );
140 
141  // add NUM_INPUTS color selection properties
142  m_colors.resize( NUM_INPUTS );
143 
144  for( std::size_t k = 0; k < m_colors.size(); ++k )
145  {
146  m_colors[ k ] = m_properties->addProperty( std::string( "Input " ) + string_utils::toString( k ) + " color",
147  std::string( "Choose a color for the histogram of input dataset " )
148  + string_utils::toString( k ), WColor( 1.0, 0.0, 0.0, 1.0 ), m_propCondition );
149  }
150 
152 }
153 
155 {
156  // we need graphics to draw anything
157  m_requirements.push_back( new WGERequirement() );
158  m_requirements.push_back( new WUIRequirement() );
159 }
160 
162 {
163  if( m_mainNode )
164  {
165  if( m_infoNode )
166  {
167  m_mainNode->remove( m_infoNode );
168  }
169  if( m_markerNode )
170  {
171  m_mainNode->remove( m_markerNode );
172  }
173 
174  if( !m_histograms.empty() ) // Bug: module will crash on mouse events when no data was connected
175  {
176  createInfo( pos );
177  }
178  }
179 }
180 
181 void WMMultiHistogramView::handleResize( int /* x */, int /* y */, int width, int height )
182 {
183  if( m_mainNode )
184  {
185  m_windowWidth = width;
186  m_windowHeight = height;
187 
188  m_redrawMutex.lock();
189 
190  m_mainNode->clear();
191  if( m_windowHeight != 0 && m_windowWidth != 0 && m_histograms.size() != 0 )
192  {
193  redraw();
194  }
195 
196  m_redrawMutex.unlock();
197  }
198 }
199 
201 {
202  m_moduleState.setResetable( true, true );
204 
205  for( std::size_t k = 0; k < m_input.size(); ++k )
206  {
207  m_moduleState.add( m_input[ k ]->getDataChangedCondition() );
208  }
209 
211 
212  // resize data vector to the number of input connectors
213  m_data.resize( m_input.size() );
214 
215  ready();
216 
217  //! Holds the reference to the custom widget used for displaying the histogram
218  m_widget = WKernel::getRunningKernel()->getUI()->getWidgetFactory()->createViewWidget(
220  WGECamera::TWO_D, m_shutdownFlag.getValueChangeCondition() );
221  osg::ref_ptr< WUIViewEventHandler > eh = new WUIViewEventHandler( m_widget );
222  eh->subscribeMove( boost::bind( &WMMultiHistogramView::handleMouseMove, this, boost::placeholders::_1 ) );
223  eh->subscribeResize( boost::bind( &WMMultiHistogramView::handleResize,
224  this,
225  boost::placeholders::_1,
226  boost::placeholders::_2,
227  boost::placeholders::_3,
228  boost::placeholders::_4 ) );
229  m_widget->addEventHandler( eh );
230 
231  m_widget->show();
232 
233  if( m_widget )
234  {
235  // window width and height
236  m_windowWidth = m_widget->width();
237  m_windowHeight = m_widget->height();
238 
239  m_mainNode = m_widget->getScene();
240  if( !m_mainNode )
241  {
242  errorLog() << "Could not acquire scene node from widget.";
243  }
244  }
245  else
246  {
247  errorLog() << "Could not create widget for the histogram.";
248  }
249 
250  while( !m_shutdownFlag() )
251  {
252  debugLog() << "Waiting ...";
253 
255 
256  if( m_shutdownFlag() )
257  {
258  break;
259  }
260 
261  // if we do not have a main node, there is no point in doing anything
262  if( m_mainNode )
263  {
264  m_redrawMutex.lock();
265 
266  bool dataChanged = false;
267  bool hasData = false;
268  for( std::size_t k = 0; k < m_data.size(); ++k )
269  {
270  dataChanged = dataChanged || ( m_input[ k ]->getData() && m_data[ k ] != m_input[ k ]->getData() );
271  hasData = hasData || ( m_input[ k ]->getData() || m_data[ k ] );
272  }
273 
274  if( !hasData )
275  {
276  continue;
277  }
278 
279  bool colorChanged = false;
280  for( std::size_t k = 0; k < m_colors.size(); ++k )
281  {
282  colorChanged = colorChanged | m_colors[ k ]->changed();
283  }
284 
285  if( dataChanged || colorChanged || m_histoBins->changed() || m_styleSelection->changed() )
286  {
287  infoLog() << "Recalculating histogram.";
288 
289  // get current data
290  for( std::size_t k = 0; k < m_data.size(); ++k )
291  {
292  m_data[ k ] = m_input[ k ]->getData();
293  }
294 
295  if( dataChanged || m_histoBins->changed() )
296  {
298  }
299 
300  // remove all child nodes from main node
301  m_mainNode->clear();
302  redraw();
303  }
304 
305  m_redrawMutex.unlock();
306  }
307  }
308 
309  debugLog() << "Shutting down...";
310 
311  // clear main node, just in case
312  if( m_mainNode )
313  {
314  m_mainNode->clear();
315  }
316 
317  m_widget->close();
318 
319  debugLog() << "Finished. Good bye!";
320 }
321 
323 {
324  int sel = m_styleSelection->get( true ).getItemIndexOfSelected( 0 );
325  if( sel >= static_cast< int >( m_geometryFunctions.size() ) )
326  {
327  errorLog() << "BUG: There is no geometry generation function for this style!";
328  }
329  else
330  {
331  // call sel'th geometry generation function
332  // this adds the osg nodes that draw the histogram
333  // depending on which style was selected
334  m_geometryFunctions[ sel ]();
335 
336  // this creates the frame and labels
337  createFrame();
338  }
339 }
340 
342 {
343  m_histograms = std::vector< std::shared_ptr< WHistogramBasic > >( m_data.size() );
344  int histoBins = m_histoBins->get( true );
345 
346  // get the maximum and minimum of all datasets
347  double min = std::numeric_limits< double >::max();
348  double max = std::numeric_limits< double >::min();
349  for( std::size_t k = 0; k < m_data.size(); ++k )
350  {
351  if( !m_data[ k ] )
352  {
353  continue;
354  }
355  if( min > m_data[ k ]->getValueSet()->getMinimumValue() )
356  {
357  min = m_data[ k ]->getValueSet()->getMinimumValue();
358  }
359  if( max < m_data[ k ]->getValueSet()->getMaximumValue() )
360  {
361  max = m_data[ k ]->getValueSet()->getMaximumValue();
362  }
363  }
364 
365  // init histograms
366  for( std::size_t k = 0; k < m_data.size(); ++k )
367  {
368  // create new histogram
369  m_histograms[ k ] = std::shared_ptr< WHistogramBasic >( new WHistogramBasic( min, max, histoBins ) );
370 
371  if( m_data[ k ] )
372  {
373  // add data
374  for( std::size_t j = 0; j < m_data[ k ]->getValueSet()->size(); ++j )
375  {
376  m_histograms[ k ]->insert( m_data[ k ]->getValueSet()->getScalarDouble( j ) );
377  }
378  }
379  }
380 
381  // these are the lower left and upper right corners of the histogram (excluding frame and labels)
382  m_histogramLowerLeft[ 0 ] = min;
383  m_histogramLowerLeft[ 1 ] = 0.0;
384 
385  m_histogramUpperRight[ 0 ] = max;
386  // this sets m_histogramUpperRight[ 1 ]
387  updateHistogramMax( false );
388 }
389 
391 {
392  double max = std::numeric_limits< double >::min();
393 
394  // for all bins/buckets
395  for( std::size_t j = 0; j < m_histograms[ 0 ]->size(); ++j )
396  {
397  double val = 0.0;
398  // for all histograms
399  for( std::size_t k = 0; k < m_data.size(); ++k )
400  {
401  if( cumulative )
402  {
403  val += m_histograms[ k ]->at( j );
404  }
405  else
406  {
407  val = std::max( val, static_cast< double >( m_histograms[ k ]->at( j ) ) );
408  }
409  }
410  if( val > max )
411  {
412  max = val;
413  }
414  }
415  m_histogramUpperRight[ 1 ] = max;
416 }
417 
419 {
420  // the number of valid inputs
421  std::size_t numData = 0;
422  for( std::size_t k = 0; k < m_data.size(); ++k )
423  {
424  if( m_data[ k ] )
425  {
426  numData++;
427  }
428  }
429 
430  double const onenth = 1.0 / numData; // 1 / n
431 
432  // k will be the index of the data in the m_data array
433  // while h will be index into the valid pointers in m_data
434  std::size_t h = 0;
435 
436  // we will accumulate histogram values in this vector
437  std::vector< std::size_t > accu( m_histograms[ 0 ]->size(), 0 );
438 
439  // update the histogram size member
440  updateHistogramMax( type == 3 );
441 
442  // update the frame size
445 
446  // create a drawable for every dataset
447  for( int k = m_data.size() - 1; k >= 0; --k )
448  {
449  // if we do not have data, there is no point in creating geometry
450  if( !m_data[ k ] )
451  {
452  // reset changed flag of colors
453  m_colors[ k ]->get( true );
454  continue;
455  }
456 
457  // this is the geode for the histogram bars
458  osg::ref_ptr< osg::Geode > geode = new osg::Geode();
459  geode->setDataVariance( osg::Object::STATIC );
460 
461  osg::ref_ptr< osg::Vec2Array > quadVertices = new osg::Vec2Array;
462  osg::ref_ptr< osg::Vec2Array > quadTexCoords = new osg::Vec2Array;
463  osg::ref_ptr< osg::Vec4Array > quadColors = new osg::Vec4Array;
464 
465  osg::ref_ptr< osg::Vec2Array > lineVertices = new osg::Vec2Array;
466  osg::ref_ptr< osg::Vec4Array > lineColors = new osg::Vec4Array;
467 
468  // one color per dataset
469  WColor color = m_colors[ k ]->get( true );
470  WColor lighterColor = WColor( color[ 0 ] * 1.1, color[ 1 ] * 1.1, color[ 2 ] * 1.1, 1.0 );
471  WColor darkerColor = WColor( color[ 0 ] * 0.9, color[ 1 ] * 0.9, color[ 2 ] * 0.9, 1.0 );
472 
473  if( type == 1 && h != 0 )
474  {
475  color[ 3 ] = lighterColor[ 3 ] = darkerColor[ 3 ] = 0.8;
476  }
477  quadColors->push_back( color );
478 
479  // add a quad for every bar/bucket/bin
480  for( std::size_t j = 0; j < m_histograms[ k ]->size(); ++j )
481  {
482  // 'histogram' coords for bar j
483  std::pair< double, double > barPosHistoCoordsX = m_histograms[ k ]->getIntervalForIndex( j );
484  WVector2d barLowerLeft( barPosHistoCoordsX.first, accu[ j ] );
485  WVector2d barUpperRight( barPosHistoCoordsX.second, accu[ j ] + m_histograms[ k ]->at( j ) );
486 
487  // vertex position depends on whether we want to draw bars from different datasets
488  // on top of each other or next to each other
489  if( type == 2 )
490  {
491  // if next to each other, reduce width to one n'th where n is m_data.size() and then
492  // move by h / n in x-direction
493  double newWidth = onenth * ( barUpperRight[ 0 ] - barLowerLeft[ 0 ] );
494  barLowerLeft[ 0 ] = barLowerLeft[ 0 ] + newWidth * h;
495  barUpperRight[ 0 ] = barLowerLeft[ 0 ] + newWidth;
496  }
497 
498  // vertices
499  quadVertices->push_back( histogramSpaceToWindowSpace( barLowerLeft ) );
500  quadVertices->push_back( histogramSpaceToWindowSpace( WVector2d( barUpperRight[ 0 ], barLowerLeft[ 1 ] ) ) );
501  quadVertices->push_back( histogramSpaceToWindowSpace( barUpperRight ) );
502  quadVertices->push_back( histogramSpaceToWindowSpace( WVector2d( barLowerLeft[ 0 ], barUpperRight[ 1 ] ) ) );
503 
504  // tex coords
505  // these are not used yet,
506  // but they may be used to color the bars with the dataset's colormap
507  quadTexCoords->push_back( WVector2d( barPosHistoCoordsX.first, 0.0 ) );
508  quadTexCoords->push_back( WVector2d( barPosHistoCoordsX.second, 0.0 ) );
509  quadTexCoords->push_back( WVector2d( barPosHistoCoordsX.second, 0.0 ) );
510  quadTexCoords->push_back( WVector2d( barPosHistoCoordsX.first, 0.0 ) );
511 
512  // outline vertices
513  lineVertices->push_back( histogramSpaceToWindowSpace( barLowerLeft ) );
514  lineVertices->push_back( histogramSpaceToWindowSpace( WVector2d( barLowerLeft[ 0 ], barUpperRight[ 1 ] ) ) );
515  lineVertices->push_back( histogramSpaceToWindowSpace( WVector2d( barLowerLeft[ 0 ], barUpperRight[ 1 ] ) ) );
516  lineVertices->push_back( histogramSpaceToWindowSpace( barUpperRight ) );
517  lineVertices->push_back( histogramSpaceToWindowSpace( barUpperRight ) );
518  lineVertices->push_back( histogramSpaceToWindowSpace( WVector2d( barUpperRight[ 0 ], barLowerLeft[ 1 ] ) ) );
519 
520  // outline colors
521  lineColors->push_back( lighterColor );
522  lineColors->push_back( lighterColor );
523  lineColors->push_back( lighterColor );
524  lineColors->push_back( lighterColor );
525  lineColors->push_back( darkerColor );
526  lineColors->push_back( darkerColor );
527 
528  if( type == 3 )
529  {
530  accu[ j ] += m_histograms[ k ]->at( j );
531  }
532  }
533 
534  // create drawable for the quads
535  {
536  osg::ref_ptr< osg::Geometry > geometry = new osg::Geometry;
537 
538  geometry->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::QUADS, 0, 4 * m_histograms[ k ]->size() ) );
539  geometry->setVertexArray( quadVertices );
540  geometry->setColorArray( quadColors );
541  geometry->setColorBinding( osg::Geometry::BIND_OVERALL );
542  geometry->setTexCoordArray( 0, quadTexCoords );
543 
544  // enable VBO
545  geometry->setUseDisplayList( false );
546  geometry->setUseVertexBufferObjects( true );
547 
548  geode->addDrawable( geometry );
549  }
550 
551  // create drawable for the outlines
552  {
553  osg::ref_ptr< osg::Geometry > geometry = new osg::Geometry;
554 
555  geometry->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::LINES, 0, 6 * m_histograms[ k ]->size() ) );
556  geometry->setVertexArray( lineVertices );
557  geometry->setColorArray( lineColors );
558  geometry->setColorBinding( osg::Geometry::BIND_PER_VERTEX );
559 
560  // enable VBO
561  geometry->setUseDisplayList( false );
562  geometry->setUseVertexBufferObjects( true );
563 
564  geode->addDrawable( geometry );
565  }
566 
567  ++h;
568 
569  // we do not want any lighting
570  osg::StateSet* state = geode->getOrCreateStateSet();
571  state->setMode( GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED );
572 
573  // no depth test
574  state->setMode( GL_DEPTH_TEST, osg::StateAttribute::OFF );
575 
576  // enable blending if we draw bars on top of each other
577  if( type == 1 )
578  {
579  state->setMode( GL_BLEND, osg::StateAttribute::ON );
580  state->setRenderingHint( osg::StateSet::TRANSPARENT_BIN );
581  }
582  else
583  {
584  state->setMode( GL_BLEND, osg::StateAttribute::OFF );
585  }
586  state->setRenderBinDetails( 1001 + m_data.size() - k, "RenderBin" );
587 
588  m_mainNode->insert( geode );
589  }
590 }
591 
593 {
594  // we will accumulate histogram values in this vector
595  std::vector< std::size_t > accu( m_histograms[ 0 ]->size(), 0 );
596 
597  // update the histogram size member
598  updateHistogramMax( type == 2 );
599 
600  // update the frame size
603 
604  // create a drawable for every dataset
605  for( std::size_t k = 0; k < m_data.size(); ++k )
606  {
607  // if we do not have data, there is no point in creating geometry
608  if( !m_data[ k ] )
609  {
610  // reset changed flag of color
611  m_colors[ k ]->get( true );
612  continue;
613  }
614 
615  // this is the geode for the histogram curve
616  osg::ref_ptr< osg::Geode > geode = new osg::Geode();
617  geode->setDataVariance( osg::Object::STATIC );
618 
619  osg::ref_ptr< osg::Vec2Array > quadVertices = new osg::Vec2Array;
620  osg::ref_ptr< osg::Vec2Array > quadTexCoords = new osg::Vec2Array;
621  osg::ref_ptr< osg::Vec4Array > quadColors = new osg::Vec4Array;
622 
623  osg::ref_ptr< osg::Vec2Array > lineVertices = new osg::Vec2Array;
624  osg::ref_ptr< osg::Vec4Array > lineColors = new osg::Vec4Array;
625 
626  // one color per dataset
627  WColor color = m_colors[ k ]->get( true );
628  WColor c = color;
629 
630  if( type == 1 )
631  {
632  c[ 3 ] = 0.2;
633  }
634  else
635  {
636  c[ 3 ] = 1.0;
637  c[ 2 ] = 0.8 + c[ 2 ] * 0.2;
638  c[ 1 ] = 0.8 + c[ 1 ] * 0.2;
639  c[ 0 ] = 0.8 + c[ 0 ] * 0.2;
640  }
641 
642  quadColors->push_back( c );
643  lineColors->push_back( color );
644 
645  // add a quad for every bar/bucket/bin
646  for( std::size_t j = 0; j < m_histograms[ k ]->size() - 1; ++j )
647  {
648  // 'histogram' coords for bar j
649  double quadLeft = m_histograms[ k ]->getIntervalForIndex( j ).first + m_histograms[ k ]->getIntervalForIndex( j ).second;
650  quadLeft *= 0.5;
651  double quadRight = m_histograms[ k ]->getIntervalForIndex( j + 1 ).first + m_histograms[ k ]->getIntervalForIndex( j + 1 ).second;
652  quadRight *= 0.5;
653 
654  WVector2d quad[ 4 ];
655  quad[ 0 ] = WVector2d( quadLeft, accu[ j ] );
656  quad[ 1 ] = WVector2d( quadRight, accu[ j + 1 ] );
657  quad[ 2 ] = WVector2d( quadRight, accu[ j + 1 ] + m_histograms[ k ]->at( j + 1 ) );
658  quad[ 3 ] = WVector2d( quadLeft, accu[ j ] + m_histograms[ k ]->at( j ) );
659 
660  // transform to window coords
661  for( std::size_t i = 0; i < 4; ++i )
662  {
663  quad[ i ] = histogramSpaceToWindowSpace( quad[ i ] );
664  quadVertices->push_back( quad[ i ] );
665  }
666 
667  // tex coords
668  quadTexCoords->push_back( WVector2d( quadLeft, 0.0 ) );
669  quadTexCoords->push_back( WVector2d( quadRight, 0.0 ) );
670  quadTexCoords->push_back( WVector2d( quadRight, 0.0 ) );
671  quadTexCoords->push_back( WVector2d( quadLeft, 0.0 ) );
672 
673  // line vertices
674  if( j == 0 )
675  {
676  lineVertices->push_back( quad[ 3 ] );
677  }
678  lineVertices->push_back( quad[ 2 ] );
679  }
680 
681  if( type == 2 )
682  {
683  for( std::size_t j = 0; j < m_histograms[ k ]->size(); ++j )
684  {
685  accu[ j ] += m_histograms[ k ]->at( j );
686  }
687  }
688 
689  // create drawable for the quads
690  {
691  osg::ref_ptr< osg::Geometry > geometry = new osg::Geometry;
692 
693  geometry->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::QUADS, 0, 4 * m_histograms[ k ]->size() - 4 ) );
694  geometry->setVertexArray( quadVertices );
695  geometry->setColorArray( quadColors );
696  geometry->setColorBinding( osg::Geometry::BIND_OVERALL );
697  geometry->setTexCoordArray( 0, quadTexCoords );
698 
699  // enable VBO
700  geometry->setUseDisplayList( false );
701  geometry->setUseVertexBufferObjects( true );
702 
703  geode->addDrawable( geometry );
704  }
705 
706  // create drawable for the outlines
707  {
708  osg::ref_ptr< osg::Geometry > geometry = new osg::Geometry;
709 
710  geometry->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::LINE_STRIP, 0, m_histograms[ k ]->size() ) );
711  geometry->setVertexArray( lineVertices );
712  geometry->setColorArray( lineColors );
713  geometry->setColorBinding( osg::Geometry::BIND_OVERALL );
714 
715  // enable VBO
716  geometry->setUseDisplayList( false );
717  geometry->setUseVertexBufferObjects( true );
718 
719  geode->addDrawable( geometry );
720  }
721 
722  // we do not want any lighting
723  osg::StateSet* state = geode->getOrCreateStateSet();
724  state->setMode( GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED );
725 
726  // no depth test
727  state->setMode( GL_DEPTH_TEST, osg::StateAttribute::OFF );
728 
729  // enable blending if we draw stuff on top of each other
730  if( type == 1 )
731  {
732  state->setMode( GL_BLEND, osg::StateAttribute::ON );
733  state->setRenderingHint( osg::StateSet::TRANSPARENT_BIN );
734  }
735  else
736  {
737  state->setMode( GL_BLEND, osg::StateAttribute::OFF );
738  }
739 
740  state->setRenderBinDetails( 1001 + m_data.size() - k, "RenderBin" );
741 
742  m_mainNode->insert( geode );
743  }
744 }
745 
747 {
748  // we will accumulate histogram values in this vector
749  std::vector< std::size_t > accu( m_histograms[ 0 ]->size(), 0 );
750 
751  updateHistogramMax( type == 2 );
752 
753  // update the frame size
756 
757  // create a drawable for every dataset
758  for( int k = m_data.size() - 1; k >= 0; --k )
759  {
760  // if we do not have data, there is no point in creating geometry
761  if( !m_data[ k ] )
762  {
763  // reset changed flag of color
764  m_colors[ k ]->get( true );
765  continue;
766  }
767 
768  // this is the geode for the histogram bars
769  osg::ref_ptr< osg::Geode > geode = new osg::Geode();
770  geode->setDataVariance( osg::Object::STATIC );
771 
772  osg::ref_ptr< osg::Vec2Array > lineVertices = new osg::Vec2Array;
773  osg::ref_ptr< osg::Vec4Array > lineColors = new osg::Vec4Array;
774 
775  // one color per dataset
776  WColor color = m_colors[ k ]->get( true );
777  color[ 3 ] = 1.0;
778  lineColors->push_back( color );
779 
780  // add lines for every bar/bucket/bin
781  for( std::size_t j = 0; j < m_histograms[ k ]->size(); ++j )
782  {
783  // 'histogram' coords for bar j
784  std::pair< double, double > barPosHistoCoordsX = m_histograms[ k ]->getIntervalForIndex( j );
785  WVector2d barLowerLeft( barPosHistoCoordsX.first, accu[ j ] );
786  WVector2d barUpperRight( barPosHistoCoordsX.second, accu[ j ] + m_histograms[ k ]->at( j ) );
787 
788  // transform to window coords
789  barLowerLeft = histogramSpaceToWindowSpace( barLowerLeft );
790  barUpperRight = histogramSpaceToWindowSpace( barUpperRight );
791 
792  // line vertices
793  if( j == 0 )
794  {
795  lineVertices->push_back( barLowerLeft );
796  }
797  lineVertices->push_back( WVector2d( barLowerLeft[ 0 ], barUpperRight[ 1 ] ) );
798  lineVertices->push_back( barUpperRight );
799  if( j == m_histograms[ k ]->size() - 1 )
800  {
801  lineVertices->push_back( WVector2d( barUpperRight[ 0 ], barLowerLeft[ 1 ] ) );
802  }
803 
804  if( type == 2 )
805  {
806  accu[ j ] += m_histograms[ k ]->at( j );
807  }
808  }
809 
810  // create drawable for the lines
811  {
812  osg::ref_ptr< osg::Geometry > geometry = new osg::Geometry;
813 
814  geometry->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::LINE_STRIP, 0, 2 * m_histograms[ k ]->size() + 2 ) );
815  geometry->setVertexArray( lineVertices );
816  geometry->setColorArray( lineColors );
817  geometry->setColorBinding( osg::Geometry::BIND_OVERALL );
818 
819  // enable VBO
820  geometry->setUseDisplayList( false );
821  geometry->setUseVertexBufferObjects( true );
822 
823  geode->addDrawable( geometry );
824  }
825 
826  // we do not want any lighting
827  osg::StateSet* state = geode->getOrCreateStateSet();
828  state->setMode( GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED );
829 
830  // no depth test
831  state->setMode( GL_DEPTH_TEST, osg::StateAttribute::OFF );
832 
833  state->setRenderBinDetails( 1001 + m_data.size() - k, "RenderBin" );
834 
835  m_mainNode->insert( geode );
836  }
837 }
838 
839 double WMMultiHistogramView::findOptimalSpacing( double intervalLength, double availableSpace, double textSize )
840 {
841  if( intervalLength < 0.0 )
842  {
843  throw WException( "Error in label spacing calculation!" );
844  }
845 
846  // minimum distance of two labels in window coordinates (pixels)
847  double const minDistance = 2 * textSize;
848 
849  if( availableSpace < minDistance )
850  {
851  return 0.0;
852  }
853 
854  // fact will be the power of 10 close to the interval length
855  double fact = 1.0;
856  double l = intervalLength;
857  while( l > 10.0 )
858  {
859  l *= 0.1;
860  fact *= 10.0;
861  }
862  while( l < 1.0 )
863  {
864  l *= 10.0;
865  fact *= 0.1;
866  }
867 
868  // try different spacings until the distance between labels
869  // for the chosen spacing f[ k ] * fact is larger than the minimum
870  // distance
871  double f[ 9 ] = { 0.1, 0.2, 0.25, 0.5, 1.0, 2.0, 2.5, 5.0, 10.0 };
872  double distance;
873  int k = 0;
874  do
875  {
876  distance = f[ k ] * fact * availableSpace / intervalLength;
877  ++k;
878  }
879  while( distance < minDistance && k < 9 );
880  return f[ k ] * fact;
881 }
882 
884 {
885  // find optimal label spacing for y direction
886  double l = m_histogramUpperRight[ 1 ];
887  double textSize = 12;
888  m_frameSpacing[ 1 ] = findOptimalSpacing( l, m_windowHeight * ( 1.0 - m_frameSize ) - m_framePosition[ 1 ], textSize );
889 
890  int factorYEnd = 1;
891  if( m_frameSpacing[ 1 ] != 0.0 )
892  {
893  // now round the maximum value up to the next multiple of spacing
894  factorYEnd = static_cast< int >( m_histogramUpperRight[ 1 ] / m_frameSpacing[ 1 ] );
895  if( factorYEnd * m_frameSpacing[ 1 ] < m_histogramUpperRight[ 1 ] )
896  {
897  factorYEnd++;
898  }
899  // minumum value is 0 in this case
900  }
901  else
902  {
904  }
905 
906  // find optimal spacing for x direction
908  textSize = 8 * static_cast< int >( std::abs( std::log10( m_frameSpacing[ 0 ] ) ) + 1 );
909  m_frameSpacing[ 0 ] = findOptimalSpacing( l, m_windowWidth * ( 1.0 - m_frameSize ) - m_framePosition[ 0 ], textSize );
910 
911  int factorXStart = 0;
912  int factorXEnd = 1;
913 
914  if( m_frameSpacing[ 0 ] != 0.0 )
915  {
916  // now round the minimum value down to the next multiple of spacing
917  factorXStart = static_cast< int >( m_histogramLowerLeft[ 0 ] / m_frameSpacing[ 0 ] );
918  if( m_histogramLowerLeft[ 0 ] >= 0.0 && factorXStart * m_frameSpacing[ 0 ] < m_histogramLowerLeft[ 0 ] )
919  {
920  factorXStart++;
921  }
922  if( m_histogramLowerLeft[ 0 ] < 0.0 && factorXStart * m_frameSpacing[ 0 ] > m_histogramLowerLeft[ 0 ] )
923  {
924  factorXStart--;
925  }
926 
927  // now round the maximum value up to the next multiple of spacing
928  factorXEnd = static_cast< int >( m_histogramUpperRight[ 0 ] / m_frameSpacing[ 0 ] );
929  if( m_histogramUpperRight[ 0 ] >= 0.0 && factorXEnd * m_frameSpacing[ 0 ] < m_histogramUpperRight[ 0 ] )
930  {
931  factorXEnd++;
932  }
933  if( m_histogramUpperRight[ 0 ] < 0.0 && factorXEnd * m_frameSpacing[ 0 ] > m_histogramUpperRight[ 0 ] )
934  {
935  factorXEnd--;
936  }
937  }
938  else
939  {
940  m_frameSpacing[ 0 ] = l;
941  }
942 
943  m_frameLowerLeft[ 0 ] = factorXStart * m_frameSpacing[ 0 ];
944  m_frameLowerLeft[ 1 ] = 0.0;
945  m_frameUpperRight[ 0 ] = factorXEnd * m_frameSpacing[ 0 ];
946  m_frameUpperRight[ 1 ] = factorYEnd * m_frameSpacing[ 1 ];
947 }
948 
950 {
951  // the funny equation estimates the number of characters needed to write a label times
952  // the estimated size of a character
953  m_framePosition[ 0 ] = 1.3 * 8.0 * static_cast< int >( std::abs( log10( m_frameSpacing[ 1 ] ) ) + 1 );
954  // as we write from left to right, text size is constant in y-direction
955  m_framePosition[ 1 ] = 2 * 1.000000 * 12;
956  // all these formulas are somewhat arbitrary
957 }
958 
960 {
961  WVector2d res = v;
962 
963  // move the histogram to 0,0
964  res -= m_histogramLowerLeft;
965 
966  // scale by the actual size of the part of the window where we want to draw to
967  // the size of that part is the window size minus some space over and to the right of the histogram
968  // and some space under and left to the histogram reserved for the frame and labels
969  //
970  // we also divide by the frame size to fit the framed histogram region to the part of the window
971  //
972  // we use the frame size instead of the histogram size (that we also know) because we want our frame size to be a
973  // multiple of the tick/label spacing
974  // by using the frame size for scaling, we ensure the frame fits into the window (except when the window is too
975  // small, but then you won't see anything anyway)
976  res[ 0 ] *= ( ( 1.0 - m_frameSize ) * m_windowWidth - m_framePosition[ 0 ] ) / ( m_frameUpperRight[ 0 ] - m_frameLowerLeft[ 0 ] );
977  res[ 1 ] *= ( ( 1.0 - m_frameSize ) * m_windowHeight - m_framePosition[ 1 ] ) / ( m_frameUpperRight[ 1 ] - m_frameLowerLeft[ 1 ] );
978 
979  // now translate by the frame position
980  res += m_framePosition;
981 
982  // note that when changing this function, you should change windowSpaceToHistogramSpace(...) accordingly
983  return res;
984 }
985 
987 {
988  // note that when changing this function, you should change histogramSpaceToWindowSpace(...) accordingly
989  WVector2d res = v;
990 
991  res -= m_framePosition;
992 
993  res[ 0 ] /= ( ( 1.0 - m_frameSize ) * m_windowWidth - m_framePosition[ 0 ] ) / ( m_frameUpperRight[ 0 ] - m_frameLowerLeft[ 0 ] );
994  res[ 1 ] /= ( ( 1.0 - m_frameSize ) * m_windowHeight - m_framePosition[ 1 ] ) / ( m_frameUpperRight[ 1 ] - m_frameLowerLeft[ 1 ] );
995 
996  res += m_histogramLowerLeft;
997 
998  return res;
999 }
1000 
1002 {
1003  m_frameNode = new osg::Geode();
1004  m_frameNode->setDataVariance( osg::Object::STATIC );
1005 
1006  osg::ref_ptr< osg::Vec2Array > lineVertices = new osg::Vec2Array;
1007  osg::ref_ptr< osg::Vec4Array > lineColors = new osg::Vec4Array;
1008 
1009  // add color
1010  WColor const frameColor( 0.2, 0.2, 0.2, 0.8 );
1011  lineColors->push_back( frameColor );
1012 
1013  // horizontal frame
1014  lineVertices->push_back( histogramSpaceToWindowSpace( m_frameLowerLeft ) );
1015  lineVertices->push_back( histogramSpaceToWindowSpace( WVector2d( m_frameUpperRight[ 0 ], m_frameLowerLeft[ 1 ] ) ) );
1016 
1017  // vertical frame
1018  lineVertices->push_back( histogramSpaceToWindowSpace( m_frameLowerLeft ) );
1019  lineVertices->push_back( histogramSpaceToWindowSpace( WVector2d( m_frameLowerLeft[ 0 ], m_frameUpperRight[ 1 ] ) ) );
1020 
1021  WVector2d offsetX( 6, 0.0 );
1022  WVector2d offsetY( 0.0, 6 );
1023 
1024  // label ticks
1025  int numLabels = 0;
1026  // x axis
1027  for( double i = m_frameLowerLeft[ 0 ]; i <= m_frameUpperRight[ 0 ]; i += m_frameSpacing[ 0 ] )
1028  {
1029  lineVertices->push_back( histogramSpaceToWindowSpace( WVector2d( i, 0.0 ) ) );
1030  lineVertices->push_back( histogramSpaceToWindowSpace( WVector2d( i, 0.0 ) ) - offsetY );
1031  ++numLabels;
1032 
1033  // add label text
1034  osgText::Text* text = new osgText::Text;
1035  WVector2d textPos = histogramSpaceToWindowSpace( WVector2d( i, 0.0 ) ) - offsetY * 1.2;
1036 
1037  text->setFont( WPathHelper::getAllFonts().Default.string() );
1038  text->setColor( frameColor );
1039  text->setCharacterSize( 12 );
1040  text->setAlignment( osgText::TextBase::CENTER_TOP );
1041  text->setPosition( WVector3d( textPos[ 0 ], textPos[ 1 ], 0.0 ) );
1042  text->setLayout( osgText::Text::LEFT_TO_RIGHT );
1043  text->setText( string_utils::toString( i ) );
1044 
1045  m_frameNode->addDrawable( text );
1046  }
1047 
1048  // y axis
1049  for( double i = m_frameLowerLeft[ 1 ]; i <= m_frameUpperRight[ 1 ]; i += m_frameSpacing[ 1 ] )
1050  {
1051  lineVertices->push_back( histogramSpaceToWindowSpace( WVector2d( m_frameLowerLeft[ 0 ], i ) ) );
1052  lineVertices->push_back( histogramSpaceToWindowSpace( WVector2d( m_frameLowerLeft[ 0 ], i ) ) - offsetX );
1053  ++numLabels;
1054 
1055  // add label text
1056  osgText::Text* text = new osgText::Text;
1057  WVector2d textPos = histogramSpaceToWindowSpace( WVector2d( m_frameLowerLeft[ 0 ], i ) ) - offsetX * 1.2;
1058 
1059  text->setFont( WPathHelper::getAllFonts().Default.string() );
1060  text->setColor( frameColor );
1061  text->setCharacterSize( 12 );
1062  text->setAlignment( osgText::TextBase::RIGHT_CENTER );
1063  text->setPosition( WVector3d( textPos[ 0 ], textPos[ 1 ], 0.0 ) );
1064  text->setLayout( osgText::Text::LEFT_TO_RIGHT );
1065  text->setText( string_utils::toString( i ) );
1066 
1067  m_frameNode->addDrawable( text );
1068  }
1069 
1070  // create drawable for the lines
1071  {
1072  osg::ref_ptr< osg::Geometry > geometry = new osg::Geometry;
1073 
1074  geometry->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::LINES, 0, 4 + 2 * numLabels ) );
1075  geometry->setVertexArray( lineVertices );
1076  geometry->setColorArray( lineColors );
1077  geometry->setColorBinding( osg::Geometry::BIND_OVERALL );
1078 
1079  // enable VBO
1080  geometry->setUseDisplayList( false );
1081  geometry->setUseVertexBufferObjects( true );
1082 
1083  m_frameNode->addDrawable( geometry );
1084  }
1085 
1086  // we do not want any lighting
1087  osg::StateSet* state = m_frameNode->getOrCreateStateSet();
1088  state->setMode( GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED );
1089 
1090  // no depth test
1091  state->setMode( GL_DEPTH_TEST, osg::StateAttribute::OFF );
1092 
1093  state->setRenderBinDetails( 1002 + m_data.size(), "RenderBin" );
1094  state->setMode( GL_BLEND, osg::StateAttribute::OFF );
1095 
1096  m_mainNode->insert( m_frameNode );
1097 }
1098 
1100 {
1101  m_createInfoMutex.lock();
1102  // transform mouse position to histogram space
1103  WVector2d m = windowSpaceToHistogramSpace( WVector2d( mousePos ) );
1104 
1105  if( m_data.size() == 0 )
1106  {
1107  return;
1108  }
1109 
1110  if( m[ 0 ] >= m_histogramLowerLeft[ 0 ] && m[ 0 ] <= m_histogramUpperRight[ 0 ] )
1111  {
1112  m_infoNode = new osg::Geode;
1113 
1114  osg::StateSet* state = m_infoNode->getOrCreateStateSet();
1115  state->setMode( GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED );
1116  state->setMode( GL_DEPTH_TEST, osg::StateAttribute::OFF );
1117  state->setMode( GL_BLEND, osg::StateAttribute::OFF );
1118  state->setRenderBinDetails( 1002 + m_data.size(), "RenderBin" );
1119 
1120  // this finds the bin selected by the mouse cursor
1121  std::size_t bin;
1122  for( bin = 0; m_histograms[ 0 ]->getIntervalForIndex( bin ).second < m[ 0 ]; ++bin )
1123  {
1124  }
1125 
1126  // if the bin is in the histogram
1127  if( bin < m_histograms[ 0 ]->size() )
1128  {
1129  // add the bin value for every dataset as a text in the top right corner of the window
1130  int h = 1;
1131 
1132  for( std::size_t k = 0; k < m_data.size(); ++k )
1133  {
1134  if( !m_data[ k ] )
1135  {
1136  continue;
1137  }
1138 
1139  WVector3d textPos( m_windowWidth - 20.0, m_windowHeight - h * 16, 0.0 );
1140 
1141  osgText::Text* text = new osgText::Text;
1142 
1143  text->setFont( WPathHelper::getAllFonts().Default.string() );
1144  text->setColor( m_colors[ k ]->get( false ) );
1145  text->setCharacterSize( 12 );
1146  text->setAlignment( osgText::TextBase::RIGHT_CENTER );
1147  text->setPosition( textPos );
1148  text->setLayout( osgText::Text::LEFT_TO_RIGHT );
1149  text->setText( string_utils::toString( m_histograms[ k ]->at( bin ) ) );
1150 
1151  m_infoNode->addDrawable( text );
1152 
1153  ++h;
1154  }
1155 
1156  // add the bin minimum and maximum
1157  WVector3d textPos( m_windowWidth - 20.0, m_windowHeight - h * 16, 0.0 );
1158 
1159  osgText::Text* text = new osgText::Text;
1160  std::stringstream s;
1161  s << "[" << m_histograms[ 0 ]->getIntervalForIndex( bin ).first
1162  << "," << m_histograms[ 0 ]->getIntervalForIndex( bin ).second
1163  << ")";
1164 
1165  text->setFont( WPathHelper::getAllFonts().Default.string() );
1166  text->setColor( WColor( 0.0, 0.0, 0.0, 1.0 ) );
1167  text->setCharacterSize( 12 );
1168  text->setAlignment( osgText::TextBase::RIGHT_CENTER );
1169  text->setPosition( textPos );
1170  text->setLayout( osgText::Text::LEFT_TO_RIGHT );
1171  text->setText( s.str() );
1172 
1173  m_infoNode->addDrawable( text );
1174 
1175  // mark the currently selected histogram bin by simple drawing a bar in the background
1176  m_markerNode = new osg::Geode;
1177 
1178  osg::StateSet* markerState = m_markerNode->getOrCreateStateSet();
1179  markerState->setMode( GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED );
1180  markerState->setMode( GL_DEPTH_TEST, osg::StateAttribute::OFF );
1181  markerState->setMode( GL_BLEND, osg::StateAttribute::OFF );
1182  markerState->setRenderBinDetails( 1000, "RenderBin" );
1183 
1184  osg::ref_ptr< osg::Vec2Array > quadVertices = new osg::Vec2Array;
1185  osg::ref_ptr< osg::Vec4Array > quadColors = new osg::Vec4Array;
1186 
1187  // the color should be adapted to the window background color
1188  quadColors->push_back( WColor( 0.95, 0.95, 0.95, 1.0 ) );
1189 
1190  quadVertices->push_back( histogramSpaceToWindowSpace(
1191  WVector2d( m_histograms[ 0 ]->getIntervalForIndex( bin ).first, 0.0 ) ) );
1192  quadVertices->push_back( histogramSpaceToWindowSpace(
1193  WVector2d( m_histograms[ 0 ]->getIntervalForIndex( bin ).second, 0.0 ) ) );
1194  quadVertices->push_back( histogramSpaceToWindowSpace(
1195  WVector2d( m_histograms[ 0 ]->getIntervalForIndex( bin ).second, m_histogramUpperRight[ 1 ] ) ) );
1196  quadVertices->push_back( histogramSpaceToWindowSpace(
1197  WVector2d( m_histograms[ 0 ]->getIntervalForIndex( bin ).first, m_histogramUpperRight[ 1 ] ) ) );
1198 
1199  osg::Geometry* geometry = new osg::Geometry;
1200 
1201  geometry->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::QUADS, 0, 4 ) );
1202  geometry->setVertexArray( quadVertices );
1203  geometry->setColorArray( quadColors );
1204  geometry->setColorBinding( osg::Geometry::BIND_OVERALL );
1205 
1206  // enable VBO
1207  geometry->setUseDisplayList( false );
1208  geometry->setUseVertexBufferObjects( true );
1209 
1210  m_markerNode->addDrawable( geometry );
1211 
1212  // TODO(reichenbach): only insert the info node if there is enough space to do so
1213 
1214  m_mainNode->insert( m_infoNode );
1215  m_mainNode->insert( m_markerNode );
1216  }
1217  }
1218  m_createInfoMutex.unlock();
1219 }
1220 
1222 {
1223  errorLog() << "This histogram style is not yet implemented.";
1224 }
virtual void wait() const
Wait for the condition.
void setResetable(bool resetable=true, bool autoReset=true)
Sets the resetable flag.
virtual void add(std::shared_ptr< WCondition > condition)
Adds another condition to the set of conditions to wait for.
Class to encapsulate boost::condition_variable_any.
Definition: WCondition.h:42
This is a simple but thread-safe counter.
Definition: WCounter.h:37
Basic exception handler.
Definition: WException.h:39
std::shared_ptr< WCondition > getValueChangeCondition()
Returns the condition denoting a value change.
Definition: WFlag.h:325
This requirement ensures an up and running WGE.
Container which associate values with (uniform width) bins (aka intervals or buckets).
A class containing a list of named items.
static WKernel * getRunningKernel()
Returns pointer to the currently running kernel.
Definition: WKernel.cpp:117
std::shared_ptr< WUI > getUI() const
Getter for the associated UI.
Definition: WKernel.cpp:132
void createFrame()
Creates the geometry for the frame and the ticks/labels.
virtual void requirements()
Initialize requirements for this module.
int m_instanceID
The number of this WMHistogram instance. Used to generate a unique window title for every instance of...
WVector2d m_frameLowerLeft
The lower left vertex of the frame box in histogram coordinates.
osg::ref_ptr< osg::Geode > m_infoNode
Draws histogram bin info to the top right corner of the window.
void redraw()
Redraws the histogram and add it to the main geode.
void calculateFramePosition()
Finds a good position of the frame relative to the lower left corner of the window.
void createGeometryBars(int type)
Creates the geometry for histogram bars.
virtual std::shared_ptr< WModule > factory() const
Due to the prototype design pattern used to build modules, this method returns a new instance of this...
WVector2d windowSpaceToHistogramSpace(WVector2d const &v)
This is the inverse of histogramSpaceToWindowSpace.
std::vector< boost::function< void(void) > > m_geometryFunctions
A vector containing functions to use for histogram geometry generation.
void calculateFrameSize()
Finds a good size for the frame, depending on the chosen spacing for axis labels.
virtual void moduleMain()
Entry point after loading the module.
virtual void properties()
Initialize the properties for this module.
std::vector< WPropColor > m_colors
A vector of color properties for the datasets.
std::shared_ptr< WCondition > m_propCondition
A condition for property updates.
boost::mutex m_redrawMutex
Whenever a redraw is made this mutex should be used.
void handleMouseMove(WVector2f pos)
Called on every mouse move event from the custom widget.
osg::ref_ptr< osg::Geode > m_frameNode
Draws the frame and ticks/labels.
void calculateHistograms()
This simply calculates a histogram per dataset, where the bin sizes and positions are the same for ea...
void createGeometryStairs(int type)
Creates the geometry for stairs (i.e.
void handleResize(int x, int y, int width, int height)
Called on every resize event from the custom widget.
virtual const std::string getDescription() const
Gives back a description of this module.
void createNothing()
This simply prints a NYI message to the errorLog.
WVector2d m_frameSpacing
The spacing between labels at the histogram axis in histogram coordinates.
virtual const std::string getName() const
Gives back the name of this module.
std::vector< std::shared_ptr< WDataSetSingle > > m_data
A vector of current datasets.
int m_windowHeight
The height of the window.
osg::ref_ptr< WGEGroupNode > m_mainNode
The scene node of the custom window. All geometry nodes are added as children of this node.
WPropInt m_histoBins
A property that is used to set the number of bins to use.
WUIViewWidget::SPtr m_widget
Holds the reference to the custom widget used for displaying the histogram.
double findOptimalSpacing(double intervalLength, double availableSpace, double textSize)
This finds a suitable spacing of ticks to use for an axis with a certain length and value interval.
WVector2d m_frameUpperRight
The upper right vertex of the frame box in histogram coordinates.
void createInfo(WVector2f mousePos)
Writes the values of the currently selected histogram bin to the top right corner of the window.
int m_windowWidth
The width of the window.
WVector2d m_histogramUpperRight
The upper right corner of the histogram in histogram coordinates.
WVector2d histogramSpaceToWindowSpace(WVector2d const &v)
This transforms histogram space coordinates to window coordinates.
static WCounter m_instanceCounter
The instance counter used to get the instance ID.
std::vector< std::shared_ptr< WModuleInputData< WDataSetSingle > > > m_input
A vector of input connectors.
virtual const char ** getXPMIcon() const
Get the icon for this module in XPM format.
std::vector< std::shared_ptr< WHistogramBasic > > m_histograms
A vector of histograms, one histogram per input.
WVector2d m_histogramLowerLeft
The lower left corner of the histogram in histogram coordinates.
virtual ~WMMultiHistogramView()
Destructor.
boost::mutex m_createInfoMutex
Whenever a new info node is made this mutex should be used.
WVector2d m_framePosition
The space to the left and under the frame in window coordinates.
double const m_frameSize
The distance between the histogram frame and the top resp. right side of the window in relative windo...
void createGeometryCurves(int type)
Creates the geometry for curves.
virtual void connectors()
Initialize the connectors this module is using.
WPropSelection m_styleSelection
Allows to select which one of the geometry generation functions should be used.
void updateHistogramMax(bool cumulative)
This updates the maximum value of the histograms.
osg::ref_ptr< osg::Geode > m_markerNode
Draws a marker showing the currently selected histogram bin.
A fixed size matrix class.
Definition: WMatrixFixed.h:150
Class representing a single module of OpenWalnut.
Definition: WModule.h:72
Requirements m_requirements
The list of requirements.
Definition: WModule.h:754
virtual void properties()
Initialize properties in this function.
Definition: WModule.cpp:212
wlog::WStreamedLogger debugLog() const
Logger instance for comfortable debug logging.
Definition: WModule.cpp:575
void addConnector(std::shared_ptr< WModuleInputConnector > con)
Adds the specified connector to the list of inputs.
Definition: WModule.cpp:108
std::shared_ptr< WProperties > m_properties
The property object for the module.
Definition: WModule.h:640
void ready()
Call this whenever your module is ready and can react on property changes.
Definition: WModule.cpp:505
WConditionSet m_moduleState
The internal state of the module.
Definition: WModule.h:703
wlog::WStreamedLogger errorLog() const
Logger instance for comfortable error logging.
Definition: WModule.cpp:570
wlog::WStreamedLogger infoLog() const
Logger instance for comfortable info logging.
Definition: WModule.cpp:565
virtual void connectors()
Initialize connectors in this function.
Definition: WModule.cpp:208
static Fonts getAllFonts()
The paths to all fonts supported.
WBoolFlag m_shutdownFlag
Condition getting fired whenever the thread should quit.
This requirement ensures an up and running UI which properly implements the WUI interface.
An event handler for a custom widget which eases interaction with GUIEvents within your module.
void addTo(WPropSelection prop)
Add the PC_SELECTONLYONE constraint to the property.
std::string toString(const T &value)
Convert a given value to a string.
Definition: WStringUtils.h:120