OpenWalnut  1.5.0dev
WMProjectionsAsContext.cpp
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2017 OpenWalnut Community
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 #include <vector>
29 
30 #include <osg/Geode>
31 #include <osg/Geometry>
32 #include <osg/Group>
33 #include <osg/Material>
34 #include <osg/ShapeDrawable>
35 #include <osg/StateAttribute>
36 
37 #include "WMProjectionsAsContext.h"
38 #include "core/dataHandler/WDataSetScalar.h"
39 #include "core/graphicsEngine/WGEColormapping.h"
40 #include "core/graphicsEngine/WGEGeodeUtils.h"
41 #include "core/graphicsEngine/WGEManagedGroupNode.h"
42 #include "core/graphicsEngine/WGEUtils.h"
43 #include "core/graphicsEngine/callbacks/WGELinearTranslationCallback.h"
44 #include "core/graphicsEngine/shaders/WGEPropertyUniform.h"
45 #include "core/graphicsEngine/shaders/WGEShader.h"
46 #include "core/kernel/WKernel.h"
47 #include "core/kernel/WModuleInputData.h"
48 
49 // This line is needed by the module loader to actually find your module.
50 W_LOADABLE_MODULE( WMProjectionsAsContext )
51 
53 WModule(),
54  m_propCondition( new WCondition() )
55 {
56 }
57 
59 {
60 }
61 
62 std::shared_ptr< WModule > WMProjectionsAsContext::factory() const
63 {
64  return std::shared_ptr< WModule >( new WMProjectionsAsContext() );
65 }
66 
67 const std::string WMProjectionsAsContext::getName() const
68 {
69  return "Projections As Context";
70 }
71 
72 const std::string WMProjectionsAsContext::getDescription() const
73 {
74  return "This module draws projections of scalar data on the faces of the data set's bounding box."
75  " The data can be projected by using either MIP or DVR.";
76 }
77 
79 {
80  m_scalarIC = WModuleInputData< WDataSetScalar >::createAndAdd( shared_from_this(), "scalarData", "Scalar Data." );
81 
82  m_transferFunction = WModuleInputData< WDataSetSingle >::createAndAdd( shared_from_this(), "transfer function", "1D Transfer Function." );
83 
85 }
86 
88 {
89  m_propCondition = std::shared_ptr< WCondition >( new WCondition() );
90 
94  NONE,
95  "None",
96  "Do not show this plane."
97  )
98  );
101  MIP,
102  "MIP (Maximum Intensity Projection)",
103  "Show this plane using the MIP Algorithm."
104  )
105  );
108  COMPOSITING_F2B,
109  "Compositing Front-to-Back (Transfer Function Needed)",
110  "Show this plane using the Compositing Algorithm (F2B)."
111  )
112  );
115  COMPOSITING_B2F,
116  "Compositing Back-to-Front (Transfer Function Needed)",
117  "Show this plane using the Compositing Algorithm (B2F)."
118  )
119  );
120 
121  // add items to dropdown menu
122  m_singleSelectionAxialTop = m_properties->addProperty( "Axial Top",
123  "Choose action for this Plane.",
124  m_possibleSelectionsUsingTypes->getSelector( 1 ),
125  m_propCondition );
126  m_singleSelectionAxialBottom = m_properties->addProperty( "Axial Bottom",
127  "Choose action for this Plane.",
128  m_possibleSelectionsUsingTypes->getSelector( 0 ),
129  m_propCondition );
130  m_singleSelectionCoronalTop = m_properties->addProperty( "Coronal Top",
131  "Choose action for this Plane.",
132  m_possibleSelectionsUsingTypes->getSelector( 1 ),
133  m_propCondition );
134  m_singleSelectionCoronalBottom = m_properties->addProperty( "Coronal Bottom",
135  "Choose action for this Plane.",
136  m_possibleSelectionsUsingTypes->getSelector( 0 ),
137  m_propCondition );
138  m_singleSelectionSagittalTop = m_properties->addProperty( "Sagittal Top",
139  "Choose action for this Plane.",
140  m_possibleSelectionsUsingTypes->getSelector( 1 ),
141  m_propCondition );
142  m_singleSelectionSagittalBottom = m_properties->addProperty( "Sagittal Bottom",
143  "Choose action for this Plane.",
144  m_possibleSelectionsUsingTypes->getSelector( 0 ),
145  m_propCondition );
146 
147  // specify single selection
160 
162  "Early Ray Termination",
163  "Used by Compositing Front-to-Back.",
164  1.0,
165  m_propCondition );
166  m_earlyRayTerminationAlpha->setMin( 0.0 );
167  m_earlyRayTerminationAlpha->setMax( 1.0 );
168 
170 }
171 
173 {
174 }
175 
177 {
178  // get notified about data changes
179  m_moduleState.setResetable( true, true );
180  m_moduleState.add( m_scalarIC->getDataChangedCondition() );
181  m_moduleState.add( m_transferFunction->getDataChangedCondition() );
183 
184  // Information output
185  m_maxCoordsPosition = m_infoProperties->addProperty( "Max Coords", "", WPosition( 0, 0, 0 ) );
186  m_normalOut = m_infoProperties->addProperty( "Normal", "", WPosition( 0, 0, 0 ) );
187  m_planeTypes[0] = m_infoProperties->addProperty( "Type Axial Top", "", 0 );
188  m_planeTypes[1] = m_infoProperties->addProperty( "Type Axial Bottom", "", 0 );
189  m_planeTypes[2] = m_infoProperties->addProperty( "Type Coronal Top", "", 0 );
190  m_planeTypes[3] = m_infoProperties->addProperty( "Type Coronal Bottom", "", 0 );
191  m_planeTypes[4] = m_infoProperties->addProperty( "Type Sagittal Top", "", 0 );
192  m_planeTypes[5] = m_infoProperties->addProperty( "Type Sagittal Bottom", "", 0 );
193 
194  ready();
195 
196  // graphics setup
197  m_rootNode = osg::ref_ptr< WGEManagedGroupNode >( new WGEManagedGroupNode( m_active ) );
198 
199  WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->insert( m_rootNode );
200 
201  m_geode = new osg::Geode();
202 
203  // create shader
204  m_shader = osg::ref_ptr< WGEShader > ( new WGEShader( "WMProjectionsAsContext", m_localPath ) );
205 
206  m_geode->getOrCreateStateSet()->setMode( GL_BLEND, osg::StateAttribute::ON );
207  m_geode->getOrCreateStateSet()->setRenderingHint( osg::StateSet::TRANSPARENT_BIN );
208 
209  // Apply colormapping
211 
212  // add geode to rootnode so that the graphics will be used/drawn in OpenWalnut
213  m_rootNode->insert( m_geode );
214 
215  // initialize a "list" to save the plane selection
216  std::vector<osg::ref_ptr<osg::Geometry> > planeList;
217  for( int i = 0; i < 6; i++ )
218  planeList.push_back( NULL );
219 
220  // for compositing
221  osg::ref_ptr< osg::Image > tfImage = new osg::Image();
222  osg::ref_ptr< osg::Texture1D > tfTexture = new osg::Texture1D();
223  tfTexture->setDataVariance( osg::Object::DYNAMIC );
224  tfTexture->setImage( tfImage );
225 
226  // bind this texture so that we can use it in our shader
227  wge::bindTexture( m_geode, tfTexture, 3, "u_transferFunction" );
228 
229  // main loop
230  while( !m_shutdownFlag() )
231  {
232  infoLog() << "Waiting ...";
234 
235  // woke up since the module is requested to finish?
236  if( m_shutdownFlag() )
237  {
238  break;
239  }
240 
241  // save data behind connectors since it might change during processing
242  scalarData = m_scalarIC->getData();
243 
244  if( !scalarData )
245  {
246  continue;
247  }
248 
249  // extract size of grid - needed for step size in shader (sampling rate)
250  WDataSetSingle::SPtr dsSingle = std::dynamic_pointer_cast< WDataSetSingle >( scalarData );
251  WGridRegular3D::SPtr regGrid = std::dynamic_pointer_cast< WGridRegular3D >( dsSingle->getGrid() );
252  int X, Y, Z;
253  X = regGrid->getNbCoordsX();
254  Y = regGrid->getNbCoordsY();
255  Z = regGrid->getNbCoordsZ();
256 
257  m_maxCoordsPosition->set( WPosition( X, Y, Z ) );
258 
259  // save selection of each dropdown box
260  size_t selection[6];
261  selection[0] = m_singleSelectionAxialTop->get().at( 0 )->getAs<MyItemType>()->getValue();
262  selection[1] = m_singleSelectionAxialBottom->get().at( 0 )->getAs<MyItemType>()->getValue();
263  selection[2] = m_singleSelectionCoronalTop->get().at( 0 )->getAs<MyItemType>()->getValue();
264  selection[3] = m_singleSelectionCoronalBottom->get().at( 0 )->getAs<MyItemType>()->getValue();
265  selection[4] = m_singleSelectionSagittalTop->get().at( 0 )->getAs<MyItemType>()->getValue();
266  selection[5] = m_singleSelectionSagittalBottom->get().at( 0 )->getAs<MyItemType>()->getValue();
267 
268  for( int i = 0; i < 6; i++ )
269  m_planeTypes[i]->set( selection[i] );
270 
271  // bind some uniforms with properties
272  m_geode->getOrCreateStateSet()->addUniform( new WGEPropertyUniform< WPropPosition >( "maxCoords", m_maxCoordsPosition ) );
273  m_geode->getOrCreateStateSet()->addUniform( new WGEPropertyUniform< WPropInt >( "axialTop", m_planeTypes[0] ) );
274  m_geode->getOrCreateStateSet()->addUniform( new WGEPropertyUniform< WPropInt >( "axialBottom", m_planeTypes[1] ) );
275  m_geode->getOrCreateStateSet()->addUniform( new WGEPropertyUniform< WPropInt >( "coronalTop", m_planeTypes[2] ) );
276  m_geode->getOrCreateStateSet()->addUniform( new WGEPropertyUniform< WPropInt >( "coronalBottom", m_planeTypes[3] ) );
277  m_geode->getOrCreateStateSet()->addUniform( new WGEPropertyUniform< WPropInt >( "sagittalTop", m_planeTypes[4] ) );
278  m_geode->getOrCreateStateSet()->addUniform( new WGEPropertyUniform< WPropInt >( "sagittalBottom", m_planeTypes[5] ) );
279 
280  m_geode->getOrCreateStateSet()->addUniform( new WGEPropertyUniform< WPropDouble >( "earlyRayTerminationAlpha", m_earlyRayTerminationAlpha ) );
281 
282  // remove all selected planes
283  for( int i = 0; i < 6; i++ )
284  m_geode->removeDrawable( planeList[i] );
285 
286  osg::ref_ptr<osg::Geometry> planeGeometry = NULL;
287  for( int i = 0; i < 6; i++ )
288  {
289  planeList[i] = NULL;
290  if( selection[i] != 0 )
291  {
292  planeList[i] = osg::ref_ptr<osg::Geometry>( new osg::Geometry() );
293  planeGeometry = planeList[i];
294  osg::Vec3Array* planeVertices = new osg::Vec3Array;
295  osg::Vec3Array* planeNormales = new osg::Vec3Array;
296  WPosition normal( 0, 0, 1 );
297  switch( static_cast<int>( floor( i/2.0f ) ) )
298  {
299  case 0:
300  {
301  WPosition tempV0( 0-10, ( i%2 == 0 )?0-10:Y+10, 0-10 );
302  WPosition tempV1( X+10, ( i%2 == 0 )?0-10:Y+10, 0-10 );
303  WPosition tempV2( X+10, ( i%2 == 0 )?0-10:Y+10, Z+10 );
304  WPosition tempV3( 0-10, ( i%2 == 0 )?0-10:Y+10, Z+10 );
305 
306  planeVertices->push_back( tempV0 );
307  planeVertices->push_back( tempV1 );
308  planeVertices->push_back( tempV2 );
309  planeVertices->push_back( tempV3 );
310 
311  normal[0] = normal[2] = 0;
312  normal[1] = 1;
313 
314  if( i%2 != 0 )
315  normal[1] = -1;
316  }
317  break; // Axial
318  case 1:
319  {
320  WPosition tempV0( 0-10, 0-10, ( i%2 == 0 )?0-10:Z+10 );
321  WPosition tempV1( X+10, 0-10, ( i%2 == 0 )?0-10:Z+10 );
322  WPosition tempV2( X+10, Y+10, ( i%2 == 0 )?0-10:Z+10 );
323  WPosition tempV3( 0-10, Y+10, ( i%2 == 0 )?0-10:Z+10 );
324  planeVertices->push_back( tempV0 );
325  planeVertices->push_back( tempV1 );
326  planeVertices->push_back( tempV2 );
327  planeVertices->push_back( tempV3 );
328 
329  normal[0] = normal[1] = 0;
330  normal[2] = 1;
331 
332  if( i%2 != 0 )
333  normal[2] = -1;
334  }
335  break; // Coronal
336  case 2:
337  {
338  WPosition tempV0( ( i%2 == 0 )?0-10:X+10, 0-10, 0-10 );
339  WPosition tempV1( ( i%2 == 0 )?0-10:X+10, 0-10, Z+10 );
340  WPosition tempV2( ( i%2 == 0 )?0-10:X+10, Y+10, Z+10 );
341  WPosition tempV3( ( i%2 == 0 )?0-10:X+10, Y+10, 0-10 );
342  planeVertices->push_back( tempV0 );
343  planeVertices->push_back( tempV1 );
344  planeVertices->push_back( tempV2 );
345  planeVertices->push_back( tempV3 );
346 
347  normal[1] = normal[2] = 0;
348  normal[0] = 1;
349 
350  if( i%2 != 0 )
351  normal[0] = -1;
352  }
353  break; // Sagittal
354  default:
355  break; // error occured
356  }
357  // add 4 normals to this plane. One for each vertex because of BIND_PER_VERTEX
358  planeNormales->push_back( normal );
359  planeNormales->push_back( normal );
360  planeNormales->push_back( normal );
361  planeNormales->push_back( normal );
362  planeGeometry->setVertexArray( planeVertices );
363  planeGeometry->setNormalArray( planeNormales );
364  planeGeometry->setNormalBinding( ( osg::Geometry::AttributeBinding )4 );
365 
366  // add plane to geode
367  osg::DrawElementsUInt* quad = new osg::DrawElementsUInt( osg::PrimitiveSet::QUADS, 0 );
368  quad->push_back( 3 );
369  quad->push_back( 2 );
370  quad->push_back( 1 );
371  quad->push_back( 0 );
372  planeGeometry->addPrimitiveSet( quad );
373 
374  m_geode->addDrawable( planeGeometry );
375  }
376  }
377 
378  if( m_transferFunction->updated() )
379  {
380  wge::bindTexture( m_geode, tfTexture, 3, "u_transferFunction" );
381  std::shared_ptr< WDataSetSingle > dataSet = m_transferFunction->getData();
382  if( !dataSet )
383  {
384  debugLog() << "no data set?";
385  }
386  else
387  {
388  WAssert( dataSet, "data set" );
389  std::shared_ptr< WValueSetBase > valueSet = dataSet->getValueSet();
390  WAssert( valueSet, "value set" );
391  std::shared_ptr< WValueSet< unsigned char > > cvalueSet(
392  std::dynamic_pointer_cast<WValueSet< unsigned char> >( valueSet )
393  );
394  if( !cvalueSet )
395  {
396  debugLog() << "invalid type";
397  }
398  else
399  {
400  size_t tfsize = cvalueSet->rawSize();
401  // create image and copy the TF
402  tfImage->allocateImage( tfsize/4, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE );
403  tfImage->setInternalTextureFormat( GL_RGBA );
404  unsigned char* data = reinterpret_cast< unsigned char* >( tfImage->data() );
405  std::copy( cvalueSet->rawData(), &cvalueSet->rawData()[ tfsize ], data );
406 
407  // force OpenGl to use the new texture
408  tfTexture->dirtyTextureObject();
409  }
410  }
411  }
412  }
413 
414  WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->remove( m_rootNode );
415 }
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
std::shared_ptr< WDataSetSingle > SPtr
Convenience typedef for a std::shared_ptr.
static void apply(osg::ref_ptr< osg::Node > node, WMatrix4d preTransform=WMatrix4d::identity(), osg::ref_ptr< WGEShader > shader=osg::ref_ptr< WGEShader >(), size_t startTexUnit=0)
Apply the colormapping to the specified node.
This class adds some convenience methods to WGEGroupNode.
Class implementing a uniform which can be controlled by a property instance.
Class encapsulating the OSG Program class for a more convenient way of adding and modifying shader.
Definition: WGEShader.h:48
std::shared_ptr< WGridRegular3DTemplate > SPtr
Convenience typedef for a std::shared_ptr< WGridRegular3DTemplate >.
A derivation of WItemSelection which can store a value of any type.
static SPtr create(T value, std::string name, std::string description="", const char **icon=NULL)
Create a instance of the item.
A class containing a list of named items.
std::shared_ptr< WItemSelection > SPtr
Convenience typedef for a std::shared_ptr< WItemSelection >
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
Computes contour lines (aka isolines) for the given data and render them on a 2D plane.
WPropSelection m_singleSelectionCoronalTop
Plane orientation type.
osg::ref_ptr< osg::Geode > m_geode
Geode holding the planes.
WPropSelection m_singleSelectionSagittalTop
Plane orientation type.
virtual ~WMProjectionsAsContext()
Destroys this module.
virtual void requirements()
Initialize requirements for this module.
std::shared_ptr< WCondition > m_propCondition
Needed for recreating the geometry, incase when resolution changes.
WPropSelection m_singleSelectionAxialTop
Plane orientation type.
WPropSelection m_singleSelectionAxialBottom
Plane orientation type.
WMProjectionsAsContext()
Creates the module for drawing contour lines.
WPropSelection m_singleSelectionSagittalBottom
Plane orientation type.
std::shared_ptr< WDataSetScalar > scalarData
The treated data set.
std::shared_ptr< WItemSelection > m_possibleSelectionsUsingTypes
Plane orientation type selection.
virtual void moduleMain()
Entry point after loading the module.
WPropPosition m_normalOut
Info property.
osg::ref_ptr< WGEShader > m_shader
Reference to shader object.
virtual const std::string getDescription() const
Gives back a description of this module.
osg::ref_ptr< WGEManagedGroupNode > m_rootNode
The OSG root node for this module.
WPropSelection m_singleSelectionCoronalBottom
Plane orientation type.
std::shared_ptr< WModuleInputData< WDataSetSingle > > m_transferFunction
The transfer function as an input data set.
virtual void properties()
Initialize the properties for this module.
virtual void connectors()
Initialize the connectors this module is using.
std::shared_ptr< WModuleInputData< WDataSetScalar > > m_scalarIC
Input connector for scalar data.
WPropPosition m_maxCoordsPosition
Info property.
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_earlyRayTerminationAlpha
Threshold for early ray termination of DVR.
virtual const std::string getName() const
Gives back the name of this module.
WPropInt m_planeTypes[6]
Info property.
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
std::shared_ptr< WProperties > m_properties
The property object for the module.
Definition: WModule.h:640
std::shared_ptr< WProperties > m_infoProperties
The property object for the module containing only module whose purpose is "PV_PURPOSE_INFORMNATION".
Definition: WModule.h:647
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
WPropBool m_active
True whenever the module should be active.
Definition: WModule.h:723
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
This only is a 3d double vector.
WBoolFlag m_shutdownFlag
Condition getting fired whenever the thread should quit.
Base Class for all value set types.
Definition: WValueSet.h:47
void addTo(WPropSelection prop)
Add the PC_NOTEMPTY constraint to the property.
void addTo(WPropSelection prop)
Add the PC_SELECTONLYONE constraint to the property.
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.