OpenWalnut  1.5.0dev
WMTransferFunctionColorBar.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 <memory>
27 #include <string>
28 
29 #include <osg/Geode>
30 #include <osg/Projection>
31 
32 #include "WMTransferFunctionColorBar.h"
33 #include "WMTransferFunctionColorBar.xpm"
34 #include "core/dataHandler/WDataTexture3D.h"
35 #include "core/graphicsEngine/WGEColormapping.h"
36 #include "core/graphicsEngine/WGEGeodeUtils.h"
37 #include "core/graphicsEngine/callbacks/WGEFunctorCallback.h"
38 #include "core/graphicsEngine/callbacks/WGENodeMaskCallback.h"
39 #include "core/graphicsEngine/shaders/WGEShader.h"
40 #include "core/graphicsEngine/widgets/labeling/WGELabel.h"
41 #include "core/kernel/WKernel.h"
42 
43 // This line is needed by the module loader to actually find your module.
44 W_LOADABLE_MODULE( WMTransferFunctionColorBar )
45 
47  WModule()
48 {
49  // initialize
50 }
51 
53 {
54  // cleanup
56 }
57 
58 std::shared_ptr< WModule > WMTransferFunctionColorBar::factory() const
59 {
60  return std::shared_ptr< WModule >( new WMTransferFunctionColorBar() );
61 }
62 
64 {
65  return WMTransferFunctionColorBar_xpm;
66 }
67 
68 const std::string WMTransferFunctionColorBar::getName() const
69 {
70  return "Transfer Function Color Bar";
71 }
72 
74 {
75  return "Can use the input as a texture that can be mapped to the navslices and so on.";
76 }
77 
79 {
80  m_input = WModuleInputData< WDataSetSingle >::createAndAdd( shared_from_this(), "transfer function", "Input to apply as texture." );
81 
82  // call WModules initialization
84 }
85 
87 {
88  m_propCondition = std::shared_ptr< WCondition >( new WCondition() );
89 
90  WPropGroup colorBarGroup = m_properties->addPropertyGroup( "Colorbar", "The colorbar with several properties." );
91  m_colorBarBorder = colorBarGroup->addProperty( "Show Border", "If true, a thin white border is shown around the colorbar.", true );
92  m_colorBarName = colorBarGroup->addProperty( "Show Name", "If true, a shortened version of the data name is shown.", true );
93  m_colorBarLabels = colorBarGroup->addProperty( "Colorbar Labels", "This defines the number of labels.", 10 );
94  m_colorBarLabels->setMin( 0 );
95  m_colorBarLabels->setMax( 55 );
96 
97  m_minScaleValue = m_properties->addProperty( "Min scale value", "Minimum scale value in dataset", 0.0, true );
98  m_maxScaleValue = m_properties->addProperty( "Max scale value", "Maximum scale value in dataset", 1.0, true );
99  m_colorBarDescription = m_properties->addProperty( "Description", "Description of current transfer function",
100  std::string( "TransferFunction" ), true ),
101 
103 }
104 
105 /**
106  * Formats a number properly to be usable as label
107  *
108  * \tparam T the type of value.
109  * \param number the number to format
110  *
111  * \return the formated number
112  */
113 template< typename T >
114 std::string format( T number )
115 {
116  std::ostringstream ss;
117  ss.precision( 3 );
118  ss << number;
119  return ss.str();
120 }
121 
123 {
124  // let the main loop awake if the data changes or the properties changed.
125  m_moduleState.setResetable( true, true );
126  m_moduleState.add( m_input->getDataChangedCondition() );
128 
129  m_customScale = false;
130 
131  osg::ref_ptr< WGEShader > colormapShader = osg::ref_ptr< WGEShader > ( new WGEShader( "WMTransferFunctionColorBar", m_localPath ) );
132 
133  // signal ready state
134  ready();
135 
136  // loop until the module container requests the module to quit
137  while( !m_shutdownFlag() )
138  {
139  // Now, the moduleState variable comes into play. The module can wait for the condition, which gets fired whenever the input receives data
140  // or an property changes. The main loop now waits until something happens.
141  debugLog() << "Waiting ...";
143 
144  // woke up since the module is requested to finish
145  if( m_shutdownFlag() )
146  {
147  break;
148  }
149 
150  // has the data changed?
151  if( m_input->handledUpdate() )
152  {
153  WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->remove( m_barProjection );
154  colormapShader->deactivate( m_colorBar );
155 
156  std::shared_ptr< WDataSetSingle > dataSet = m_input->getData();
157 
158  // add a colorbar
159  if( dataSet )
160  {
161  // create camera oriented 2d projection
162  m_barProjection = new osg::Projection();
163  m_barProjection->addUpdateCallback( new WGENodeMaskCallback( m_active ) );
164  m_barProjection->setMatrix( osg::Matrix::ortho2D( 0, 1.0, 0, 1.0 ) );
165  m_barProjection->getOrCreateStateSet()->setRenderBinDetails( 15, "RenderBin" );
166  m_barProjection->getOrCreateStateSet()->setDataVariance( osg::Object::DYNAMIC );
167  m_barProjection->getOrCreateStateSet()->setMode( GL_DEPTH_TEST, osg::StateAttribute::OFF );
168  m_barProjection->getOrCreateStateSet()->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
169 
170  float borderWidth = 0.001;
171 
172  // create a colorbar geode
173  m_colorBar = wge::genFinitePlane( osg::Vec3( 0.025, 0.1, 0.0 ), osg::Vec3( 0.025, 0.0, 0.0 ), osg::Vec3( 0.0, 0.8, 0.0 ) );
174  m_colorBar->setName( "Transfer Function Color Bar" );
175  osg::ref_ptr< osg::Geode > colorBarBorder = wge::genFinitePlane( osg::Vec3( 0.025 - borderWidth, 0.1 - borderWidth, -0.1 ),
176  osg::Vec3( 0.025 + 2.0 * borderWidth, 0.0, -0.1 ),
177  osg::Vec3( 0.0, 0.8 + 2.0 * borderWidth, -0.1 ) );
178  colormapShader->apply( m_colorBar );
179 
180  // create the texture for color lookup
181  WAssert( dataSet, "data set" );
182  std::shared_ptr< WValueSetBase > valueSet = dataSet->getValueSet();
183  WAssert( valueSet, "value set" );
184  std::shared_ptr< WValueSet< unsigned char > > cvalueSet( std::dynamic_pointer_cast<WValueSet< unsigned char> >( valueSet ) );
185  if( !cvalueSet )
186  {
187  debugLog() << "invalid type";
188  }
189  else
190  {
191  size_t tfsize = cvalueSet->rawSize();
192  const unsigned char* orig = cvalueSet->rawData();
193  unsigned char* data = new unsigned char[ tfsize ];
194  std::copy( orig, &orig[ tfsize ], data );
195  osg::ref_ptr < osg::Image > tfImg( new osg::Image() );
196  tfImg->setImage( tfsize/4, 1, 1, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE,
197  data, osg::Image::USE_NEW_DELETE ); // FIXME: check allocation mode
198  osg::ref_ptr< osg::Texture1D > tfTexture = new osg::Texture1D();
199  tfTexture->setImage( tfImg );
200  wge::bindTexture( m_colorBar, tfTexture, 0, "u_transferFunction" );
201  }
202 
203  // add the name label
204  osg::ref_ptr< WGELabel > nameLabel = new WGELabel();
205  nameLabel->setPosition( osg::Vec3( 0.015, 0.9, 0.0 ) );
206  nameLabel->setText( format( m_colorBarDescription->get() ) );
207  nameLabel->setCharacterSize( 0.015 );
208  nameLabel->setLayout( osgText::TextBase::VERTICAL );
209  nameLabel->setAlignment( osgText::Text::BASE_LINE );
210 
211  // the bar and the labels need to be added in an identity modelview matrix node
212  osg::ref_ptr< osg::MatrixTransform > matrix = new osg::MatrixTransform();
213  matrix->setMatrix( osg::Matrix::identity() );
214  matrix->setReferenceFrame( osg::Transform::ABSOLUTE_RF );
215 
216  // this geode contains the labels
217  osg::ref_ptr< osg::Geode > labels = new osg::Geode();
218  labels->addDrawable( nameLabel );
219  m_scaleLabels = new osg::Geode();
220  m_scaleLabels->addUpdateCallback( new WGEFunctorCallback< osg::Node >(
221  boost::bind( &WMTransferFunctionColorBar::updateColorbarScale, this, boost::placeholders::_1 )
222  ) );
223  // set some callbacks
224  colorBarBorder->addUpdateCallback( new WGENodeMaskCallback( m_colorBarBorder ) );
225  labels->addUpdateCallback( new WGENodeMaskCallback( m_colorBarName ) );
226 
227  // build pipeline
228  matrix->addChild( colorBarBorder );
229  matrix->addChild( m_colorBar );
230  matrix->addChild( m_scaleLabels );
231  matrix->addChild( labels );
232  m_barProjection->addChild( matrix );
233 
234  if( !m_customScale )
235  {
236  m_valueMin = dataSet->getTexture()->minimum()->get();
237  m_valueScale = dataSet->getTexture()->scale()->get();
238  }
239 
240  int labelCount = m_colorBarLabels->get( false );
241  m_colorBarLabels->set( 0 );
242  m_colorBarLabels->set( labelCount );
243 
244  // add
245  WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->insert( m_barProjection );
246  }
247  }
248  }
249 
250  // remove colorbar and its labels
251  WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->remove( m_barProjection );
252 }
253 
255 {
256  // Always call WModule's activate!
258 }
259 
261 {
262  if( m_minScaleValue->changed( false ) )
263  {
264  m_valueMin = m_minScaleValue->get();
265  m_customScale = true;
266  }
267  if( m_maxScaleValue->changed( false ) )
268  {
269  m_valueScale = m_maxScaleValue->get();
270  m_customScale = true;
271  }
272 
273  if( m_colorBarLabels->changed( true ) || m_minScaleValue->changed( true ) || m_maxScaleValue->changed( true ) )
274  {
275  const double labelXPos = 0.060;
276  osg::Geode* g = scaleLabels->asGeode();
277  g->removeDrawables( 0, g->getNumDrawables() );
278 
279  size_t num = m_colorBarLabels->get( true );
280  double coordStep = 0.8 / static_cast< double >( num - 1 );
281  double valueStep = m_valueScale / static_cast< double >( num - 1 );
282 
283  // less than 2 labels is useless
284  if( num < 2 )
285  {
286  return;
287  }
288 
289  osg::Vec3Array* lineVerts = new osg::Vec3Array();
290 
291  // create enough labels.
292  for( size_t i = 0; i < num; ++i )
293  {
294  double value = m_valueMin + ( valueStep * i );
295 
296  // create the label
297  osg::ref_ptr< WGELabel > label = new WGELabel();
298  label->setPosition( osg::Vec3( labelXPos, 0.1 + i * coordStep, 0.0 ) ); // bar goes from 0.1 to 0.9 in our coordinate system
299  label->setText( format( value ) );
300  label->setCharacterSize( 0.015 );
301  label->setAlignment( osgText::Text::LEFT_CENTER );
302 
303  g->addDrawable( label );
304 
305  // create the line next to the label
306  lineVerts->push_back( osg::Vec3( labelXPos - 0.010, 0.1 + i * coordStep, 0.0 ) );
307  lineVerts->push_back( osg::Vec3( labelXPos - 0.005, 0.1 + i * coordStep, 0.0 ) );
308  }
309 
310  // create the line drawable
311  osg::Geometry* lines = new osg::Geometry();
312  lines->setVertexArray( lineVerts );
313  osg::Vec3Array* color = new osg::Vec3Array();
314  color->push_back( osg::Vec3( 1.0, 1.0, 1.0 ) );
315  lines->setColorArray( color );
316  lines->setColorBinding( osg::Geometry::BIND_OVERALL );
317  lines->addPrimitiveSet( new osg::DrawArrays( GL_LINES, 0, lineVerts->size() ) );
318  g->addDrawable( lines );
319  }
320 }
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 callback allows you a simple usage of callbacks in your module.
Label layout-item.
Definition: WGELabel.h:39
This callback is useful to en-/disable nodes using the node mask based on properties.
Class encapsulating the OSG Program class for a more convenient way of adding and modifying shader.
Definition: WGEShader.h:48
static WKernel * getRunningKernel()
Returns pointer to the currently running kernel.
Definition: WKernel.cpp:117
std::shared_ptr< WGraphicsEngine > getGraphicsEngine() const
Returns pointer to currently running instance of graphics engine.
Definition: WKernel.cpp:122
This module simply registers the given dataset to the texture handling mechanism.
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...
WPropDouble m_maxScaleValue
Maximum scaling factor of the current dataset.
std::shared_ptr< WModuleInputData< WDataSetSingle > > m_input
Input connector required by this module.
osg::ref_ptr< osg::Geode > m_scaleLabels
The colorbar scale labels.
WPropBool m_colorBarName
Show colorbar name?
WPropString m_colorBarDescription
Description of the color bar.
WMTransferFunctionColorBar()
Standard constructor.
virtual void moduleMain()
Entry point after loading the module.
virtual const char ** getXPMIcon() const
Get the icon for this module in XPM format.
osg::ref_ptr< osg::Projection > m_barProjection
The projection node for the colorbar and labels.
virtual const std::string getDescription() const
Gives back a description of this module.
osg::ref_ptr< osg::Geode > m_colorBar
The colorbar.
WPropInt m_colorBarLabels
The number of colorbar labels.
bool m_customScale
Whether a custom min max was set.
double m_valueMin
The min of the current dataset.
virtual void activate()
Callback for m_active.
virtual void connectors()
Initialize the connectors this module is using.
virtual void properties()
Initialize the properties for this module.
std::shared_ptr< WCondition > m_propCondition
A condition used to notify about changes in several properties.
void updateColorbarScale(osg::Node *scaleLabels)
Callback which adds/removes scale labels to the colorbar.
double m_valueScale
The scaling factor of the current dataset.
WPropDouble m_minScaleValue
Minimum scaling factor of the current dataset.
WPropBool m_colorBarBorder
Show the border?
virtual const std::string getName() const
Gives back the name of this module.
static PtrType createAndAdd(std::shared_ptr< WModule > module, std::string name="", std::string description="")
Convenience method to create a new instance of this in data connector with proper type and add it to ...
Class representing a single module of OpenWalnut.
Definition: WModule.h:72
boost::filesystem::path m_localPath
The path where the module binary resides in.
Definition: WModule.h:734
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 removeConnectors()
Removes all connectors properly.
Definition: WModule.cpp:194
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
virtual void activate()
Callback for m_active.
Definition: WModule.cpp:220
WPropBool m_active
True whenever the module should be active.
Definition: WModule.h:723
virtual void connectors()
Initialize connectors in this function.
Definition: WModule.cpp:208
WBoolFlag m_shutdownFlag
Condition getting fired whenever the thread should quit.
Base Class for all value set types.
Definition: WValueSet.h:47
void bindTexture(osg::ref_ptr< osg::Node > node, osg::ref_ptr< WDataTexture3D > texture, size_t unit=0, std::string prefix="")
Binds the specified texture to the specified unit.
osg::ref_ptr< osg::Geode > genFinitePlane(double xSize, double ySize, const WPlane &p, const WColor &color=WColor(0.0, 0.7, 0.7, 1.0), bool border=false)
Generates a geode out of a Plane with a fixed size in direction of the vectors which span that plane.