OpenWalnut  1.5.0dev
WMSplineSurface.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 <cmath>
26 #include <fstream>
27 #include <iostream>
28 #include <memory>
29 #include <string>
30 #include <vector>
31 
32 #include <osg/Geode>
33 #include <osg/Geometry>
34 #include <osg/LightModel>
35 #include <osg/Material>
36 #include <osg/PolygonMode>
37 #include <osg/StateAttribute>
38 #include <osg/StateSet>
39 #include <osgDB/WriteFile>
40 
41 #include "WMSplineSurface.h"
42 #include "WMSplineSurface.xpm"
43 #include "WSurface.h"
44 #include "core/common/WAssert.h"
45 #include "core/common/WLimits.h"
46 #include "core/common/WPathHelper.h"
47 #include "core/common/WProgress.h"
48 #include "core/common/math/WLinearAlgebraFunctions.h"
49 #include "core/common/math/linearAlgebra/WPosition.h"
50 #include "core/common/math/linearAlgebra/WVectorFixed.h"
51 #include "core/dataHandler/WDataHandler.h"
52 #include "core/dataHandler/WSubject.h"
53 #include "core/graphicsEngine/WGEColormapping.h"
54 #include "core/graphicsEngine/WGEUtils.h"
55 #include "core/graphicsEngine/shaders/WGEShaderPropertyDefineOptions.h"
56 #include "core/kernel/WKernel.h"
57 
58 // This line is needed by the module loader to actually find your module.
59 W_LOADABLE_MODULE( WMSplineSurface )
60 
62  WModule(), m_recompute( std::shared_ptr< WCondition >( new WCondition() ) ),
63  m_moduleNode( new WGEGroupNode() ), m_surfaceGeode( 0 )
64 {
65  // WARNING: initializing connectors inside the constructor will lead to an exception.
66  // Implement WModule::initializeConnectors instead.
67 }
68 
70 {
71  // cleanup
73 }
74 
75 std::shared_ptr< WModule > WMSplineSurface::factory() const
76 {
77  return std::shared_ptr< WModule >( new WMSplineSurface() );
78 }
79 
80 const char** WMSplineSurface::getXPMIcon() const
81 {
82  return spline_surface_xpm;
83 }
84 
85 const std::string WMSplineSurface::getName() const
86 {
87  return "Spline Surface";
88 }
89 
90 const std::string WMSplineSurface::getDescription() const
91 {
92  return "<font color=\"#0000ff\"><b>[Unfinished Status]</b></font> This module implements the marching cubes"
93  " algorithm with a consistent triangulation. It allows one to compute isosurfaces"
94  " for a given isovalue on data given on a grid only consisting of cubes. It yields"
95  " the surface as triangle soup.";
96 }
97 
99 {
100  // use the m_input "data changed" flag
101  m_moduleState.setResetable( true, true );
103 
104  // signal ready state
105  ready();
106 
107  // loop until the module container requests the module to quit
108  while( !m_shutdownFlag() )
109  {
110  // update isosurface
111  debugLog() << "Computing surface ...";
112 
113  WSurface surf;
114 
115  //////////////////////////////////////////////////////////////////////////////////////////////////////
116  std::vector< WVector3d > givenPoints;
117  for( int y = 0; y < 11; ++y )
118  {
119  for( int z = 0; z < 11; ++z )
120  {
121  float pi = 3.14159265;
122  float pi2 = pi * 2;
123  float yy = pi2 * y / 10.;
124  float zz = pi2 * z / 10.;
125 
126  WVector3d p;
127  p[0] = 60. + sin( yy ) * 10 + cos( zz ) * 10;
128  p[1] = y * 20.;
129  p[2] = z * 16.;
130  givenPoints.push_back( p );
131  }
132  }
133  surf.setSupportPoints( givenPoints );
134  //////////////////////////////////////////////////////////////////////////////////////////////////////
135 
136  surf.execute();
137  m_triMesh = surf.getTriangleMesh();
138 
139  debugLog() << "Rendering surface ...";
140 
141  renderMesh();
142  m_output->updateData( m_triMesh );
143 
144  debugLog() << "Done!";
145 
146  // this waits for m_moduleState to fire. By default, this is only the m_shutdownFlag condition.
147  // NOTE: you can add your own conditions to m_moduleState using m_moduleState.add( ... )
149  }
150 
151  WKernel::getRunningKernel()->getGraphicsEngine()->getViewer()->getScene()->remove( m_moduleNode );
152 }
153 
155 {
156  // TODO(someone): This connector should be used as soon as the module gets more functionality.
157  // The surface will aligned to these tracts.
158  typedef WModuleInputData< const WFiberCluster > InputType; // just an alias
159  m_input = std::shared_ptr< InputType >( new InputType( shared_from_this(), "Tracts", "A cluster of tracts." ) );
161 
162  m_output = std::shared_ptr< WModuleOutputData< WTriangleMesh > >( new WModuleOutputData< WTriangleMesh > ( shared_from_this(), "out",
163  "The mesh representing the spline surface." ) );
164 
166 
167  // call WModules initialization
169 }
170 
172 {
173  m_opacityProp = m_properties->addProperty( "Opacity %", "Opaqueness of surface.", 100 );
174  m_opacityProp->setMin( 0 );
175  m_opacityProp->setMax( 100 );
176 
177  m_useTextureProp = m_properties->addProperty( "Use texture", "Use texturing of the surface?", true );
178 
179  m_surfaceColor = m_properties->addProperty( "Surface color", "Description.", WColor( 0.5, 0.5, 0.5, 1.0 ) );
180 
181  m_savePropGroup = m_properties->addPropertyGroup( "Save Surface", "" );
182  m_saveTriggerProp = m_savePropGroup->addProperty( "Do save", "Press!", WPVBaseTypes::PV_TRIGGER_READY );
183  m_saveTriggerProp->getCondition()->subscribeSignal( boost::bind( &WMSplineSurface::save, this ) );
184 
185  m_meshFile = m_savePropGroup->addProperty( "Mesh file", "", WPathHelper::getAppPath() );
186 
188 }
189 
191 {
192  // WKernel::getRunningKernel()->getGraphicsEngine()->getScene()
193  m_moduleNode->remove( m_surfaceGeode );
194  osg::Geometry* surfaceGeometry = new osg::Geometry();
195  m_surfaceGeode = osg::ref_ptr< osg::Geode >( new osg::Geode );
196 
197  m_surfaceGeode->setName( "spline surface" );
198 
199  surfaceGeometry->setVertexArray( m_triMesh->getVertexArray() );
200 
201  osg::DrawElementsUInt* surfaceElement;
202 
203  surfaceElement = new osg::DrawElementsUInt( osg::PrimitiveSet::TRIANGLES, 0 );
204 
205  std::vector< size_t > tris = m_triMesh->getTriangles();
206  surfaceElement->reserve( tris.size() );
207 
208  for( unsigned int vertId = 0; vertId < tris.size(); ++vertId )
209  {
210  surfaceElement->push_back( tris[vertId] );
211  }
212  surfaceGeometry->addPrimitiveSet( surfaceElement );
213 
214  // ------------------------------------------------
215  // normals
216  surfaceGeometry->setNormalArray( m_triMesh->getVertexNormalArray() );
217  surfaceGeometry->setNormalBinding( osg::Geometry::BIND_PER_VERTEX );
218 
219  m_surfaceGeode->addDrawable( surfaceGeometry );
220  osg::StateSet* state = m_surfaceGeode->getOrCreateStateSet();
221 
222  // ------------------------------------------------
223  // colors
224  osg::Vec4Array* colors = new osg::Vec4Array;
225  colors->push_back( m_surfaceColor->get( true ) );
226  surfaceGeometry->setColorArray( colors );
227  surfaceGeometry->setColorBinding( osg::Geometry::BIND_OVERALL );
228 
229  osg::ref_ptr< osg::LightModel > lightModel = new osg::LightModel();
230  lightModel->setTwoSided( true );
231  state->setAttributeAndModes( lightModel.get(), osg::StateAttribute::ON );
232  state->setMode( GL_BLEND, osg::StateAttribute::ON );
233 
234  osg::ref_ptr< WGEShader > shader = osg::ref_ptr< WGEShader >( new WGEShader( "WMSplineSurface", m_localPath ) );
235  shader->addPreprocessor( WGEShaderPreprocessor::SPtr(
236  new WGEShaderPropertyDefineOptions< WPropBool >( m_useTextureProp, "COLORMAPPING_DISABLED", "COLORMAPPING_ENABLED" ) )
237  );
238  state->addUniform( new WGEPropertyUniform< WPropInt >( "u_opacity", m_opacityProp ) );
239  shader->apply( m_surfaceGeode );
240 
241  // Colormapping
243 
244  m_moduleNode->insert( m_surfaceGeode );
245  WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->insert( m_moduleNode );
246 
247  m_moduleNode->addUpdateCallback( new SplineSurfaceNodeCallback( this ) );
248 }
249 
251 {
252  // m_saveTriggerProp->set( WPVBaseTypes::PV_TRIGGER_READY, false );
253  //
254  // if( m_triMesh->vertSize() == 0 )
255  // {
256  // WLogger::getLogger()->addLogMessage( "Will not write file that contains 0 vertices.", "Marching Cubes", LL_ERROR );
257  // return false;
258  // }
259  //
260  // if( m_triMesh->triangleSize() == 0 )
261  // {
262  // WLogger::getLogger()->addLogMessage( "Will not write file that contains 0 triangles.", "Marching Cubes", LL_ERROR );
263  // return false;
264  // }
265  //
266  // const char* c_file = m_meshFile->get().string().c_str();
267  // std::ofstream dataFile( c_file );
268  //
269  // if( dataFile )
270  // {
271  // WLogger::getLogger()->addLogMessage( "opening file", "Marching Cubes", LL_DEBUG );
272  // }
273  // else
274  // {
275  // WLogger::getLogger()->addLogMessage( "open file failed" + m_meshFile->get().string() , "Marching Cubes", LL_ERROR );
276  // return false;
277  // }
278  //
279  // dataFile.precision( 16 );
280  //
281  // WLogger::getLogger()->addLogMessage( "start writing file", "Marching Cubes", LL_DEBUG );
282  // dataFile << ( "# vtk DataFile Version 2.0\n" );
283  // dataFile << ( "generated using OpenWalnut\n" );
284  // dataFile << ( "ASCII\n" );
285  // dataFile << ( "DATASET UNSTRUCTURED_GRID\n" );
286  //
287  // WPosition point;
288  // dataFile << "POINTS " << m_triMesh->vertSize() << " float\n";
289  // for( size_t i = 0; i < m_triMesh->vertSize(); ++i )
290  // {
291  // point = m_triMesh->getVertex( i );
292  // if( !( !wlimits::isInf( point[0] ) && !wlimits::isInf( point[1] ) && !wlimits::isInf( point[2] ) ) )
293  // {
294  // WLogger::getLogger()->addLogMessage( "Will not write file from data that contains NAN or INF.", "Marching Cubes", LL_ERROR );
295  // return false;
296  // }
297  // dataFile << point[0] << " " << point[1] << " " << point[2] << "\n";
298  // }
299  //
300  // dataFile << "CELLS " << m_triMesh->triangleSize() << " " << m_triMesh->triangleSize() * 4 << "\n";
301  // for( size_t i = 0; i < m_triMesh->triangleSize(); ++i )
302  // {
303  // dataFile << "3 " << m_triMesh->getTriVertId0( i ) << " "
304  // << m_triMesh->getTriVertId1( i ) << " "
305  // << m_triMesh->getTriVertId2( i ) << "\n";
306  // }
307  // dataFile << "CELL_TYPES "<< m_triMesh->triangleSize() <<"\n";
308  // for( size_t i = 0; i < m_triMesh->triangleSize(); ++i )
309  // {
310  // dataFile << "5\n";
311  // }
312  // dataFile << "POINT_DATA " << m_triMesh->vertSize() << "\n";
313  // dataFile << "SCALARS scalars float\n";
314  // dataFile << "LOOKUP_TABLE default\n";
315  // for( size_t i = 0; i < m_triMesh->vertSize(); ++i )
316  // {
317  // dataFile << "0\n";
318  // }
319  // dataFile.close();
320  // WLogger::getLogger()->addLogMessage( "saving done", "Marching Cubes", LL_DEBUG );
321  return true;
322 }
323 
325 {
326  if( m_active->get() )
327  {
328  m_surfaceGeode->setNodeMask( 0xFFFFFFFF );
329  }
330  else
331  {
332  m_surfaceGeode->setNodeMask( 0x0 );
333  }
334 
335  if( m_surfaceColor->changed() )
336  {
337  osg::Vec4Array* colors = new osg::Vec4Array;
338  colors->push_back( m_surfaceColor->get( true ) );
339  m_surfaceGeode->getDrawable( 0 )->asGeometry()->setColorArray( colors );
340  m_surfaceGeode->getDrawable( 0 )->asGeometry()->setColorBinding( osg::Geometry::BIND_OVERALL );
341  }
342 }
Adapter object for realizing callbacks of the node representing the isosurface in the osg.
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
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.
Class to wrap around the osg Group node and providing a thread safe add/removal mechanism.
Definition: WGEGroupNode.h:48
Class implementing a uniform which can be controlled by a property instance.
std::shared_ptr< WGEShaderPreprocessor > SPtr
Shared pointer for this class.
This is a WGEShaderDefineOptions class which additionally uses a property to automatically control th...
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
Module implementing the marching cubes algorithm with consistent triangulation for data given on regu...
virtual const char ** getXPMIcon() const
Get the icon for this module in XPM format.
WPropBool m_useTextureProp
Property indicating whether to use texturing with scalar data sets.
osg::ref_ptr< osg::Geode > m_surfaceGeode
Pointer to geode containing the surface.
WPropColor m_surfaceColor
Property determining the color for the surface if no textures are displayed.
virtual const std::string getName() const
Gives back the name of this module.
void updateGraphics()
updates textures and shader parameters
virtual void moduleMain()
Entry point after loading the module.
bool save() const
Store the mesh in legacy vtk file format.
osg::ref_ptr< WGEGroupNode > m_moduleNode
Pointer to the modules group node. We need it to be able to update it when callback is invoked.
virtual void properties()
Initialize the properties for this module.
virtual const std::string getDescription() const
Gives back a description of this module.
~WMSplineSurface()
Destructor.
WMSplineSurface()
Standard constructor.
WPropInt m_opacityProp
Property holding the opacity valueassigned to the surface.
std::shared_ptr< WTriangleMesh > m_triMesh
This triangle mesh is provided as output through the connector.
virtual void connectors()
Initialize the connectors this module is using.
std::shared_ptr< WModuleOutputData< WTriangleMesh > > m_output
Input connector required by this module.
WPropGroup m_savePropGroup
Property group containing properties needed for saving the mesh.
void renderMesh()
Prepares and commits everything for rendering with the OSG.
WPropFilename m_meshFile
The mesh will be written to this file.
std::shared_ptr< WModuleInputData< const WFiberCluster > > m_input
Input connector for a fiber cluster.
WPropTrigger m_saveTriggerProp
This property triggers the actual writing,.
std::shared_ptr< WCondition > m_recompute
This condition denotes whether we need to recompute the surface.
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...
Class offering an instantiate-able data connection between modules.
Class offering an instantiate-able data connection between modules.
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
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
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
static boost::filesystem::path getAppPath()
The path where the binary file resides in.
Definition: WPathHelper.cpp:93
Constructs a triangle mesh representation of a spline surface from a given number of input points.
Definition: WSurface.h:40
void setSupportPoints(std::vector< WVector3d > supportPoints, bool forceUpdate=false)
sets the vector of support points the surface is calculated from
Definition: WSurface.cpp:291
void execute()
Runs the algo and constructs a spine surface from the given input points.
Definition: WSurface.cpp:174
std::shared_ptr< WTriangleMesh > getTriangleMesh()
getter
Definition: WSurface.cpp:300
WBoolFlag m_shutdownFlag
Condition getting fired whenever the thread should quit.
@ PV_TRIGGER_READY
Trigger property: is ready to be triggered (again)