OpenWalnut  1.5.0dev
WMSurfaceIllustrator.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 <list>
28 #include <map>
29 #include <memory>
30 #include <string>
31 #include <vector>
32 
33 #include <osg/Geode>
34 #include <osg/LightModel>
35 
36 #include "WMSurfaceIllustrator.h"
37 #include "WMSurfaceIllustrator.xpm"
38 #include "core/common/WLimits.h"
39 #include "core/common/math/WMath.h"
40 #include "core/graphicsEngine/WGEColormapping.h"
41 #include "core/graphicsEngine/WGEGeodeUtils.h"
42 #include "core/graphicsEngine/WGEUtils.h"
43 #include "core/graphicsEngine/WTriangleMesh.h"
44 #include "core/graphicsEngine/shaders/WGEPropertyUniform.h"
45 #include "core/graphicsEngine/shaders/WGEShader.h"
46 #include "core/graphicsEngine/shaders/WGEShaderPropertyDefineOptions.h"
47 #include "core/kernel/WKernel.h"
48 
49 // This line is needed by the module loader to actually find your module.
50 W_LOADABLE_MODULE( WMSurfaceIllustrator )
51 
53  WModule()
54 {
55 }
56 
58 {
59  // Cleanup!
60 }
61 
62 std::shared_ptr< WModule > WMSurfaceIllustrator::factory() const
63 {
64  // See "src/modules/template/" for an extensively documented example.
65  return std::shared_ptr< WModule >( new WMSurfaceIllustrator() );
66 }
67 
69 {
70  return WMSurfaceIllustrator_xpm;
71 }
72 
73 const std::string WMSurfaceIllustrator::getName() const
74 {
75  return "Surface Illustrator";
76 }
77 
78 const std::string WMSurfaceIllustrator::getDescription() const
79 {
80  return "Takes a (parameterized) triangle mesh as input and renders it as a shaded surface with serverall illustration options.";
81 }
82 
83 void WMSurfaceIllustrator::updateMinMax( double& minX, double& maxX, // NOLINT
84  double& minY, double& maxY, // NOLINT
85  double& minZ, double& maxZ, const osg::Vec3d& vector ) const // NOLINT
86 {
87  minX = std::min( minX, vector.x() );
88  minY = std::min( minY, vector.y() );
89  minZ = std::min( minZ, vector.z() );
90 
91  maxX = std::max( maxX, vector.x() );
92  maxY = std::max( maxY, vector.y() );
93  maxZ = std::max( maxZ, vector.z() );
94 }
95 
96 double WMSurfaceIllustrator::getMedian( double x, double y, double z ) const
97 {
98  if( ( y < x && z > x ) || ( z < x && y > x ) )
99  {
100  return x;
101  }
102 
103  if( ( x < y && z > y ) || ( x < y && z > y ) )
104  {
105  return y;
106  }
107 
108  if( ( y < z && x > z ) || ( x < z && y > z ) )
109  {
110  return z;
111  }
112 
113  if( x == y )
114  {
115  return x;
116  }
117  if( x == z )
118  {
119  return x;
120  }
121  if( y == z )
122  {
123  return z;
124  }
125  if( x == y && y == z && x == z )
126  {
127  return x;
128  }
129 
130  return 0;
131 }
132 
134 {
135  // this input contains the triangle data
136  m_meshInput = WModuleInputData< WTriangleMesh >::createAndAdd( shared_from_this(), "mesh", "The mesh to display" );
137 
138  // this input provides an additional map from vertex ID to color. This is especially useful for using the trimesh renderer in conjunction
139  // with clustering mechanisms and so on
140  m_colorMapInput = WModuleInputData< WColoredVertices >::createAndAdd( shared_from_this(), "colorMap", "The special colors" );
141 
142  // call WModule's initialization
144 }
145 
147 {
148  m_nbTriangles = m_infoProperties->addProperty( "Triangles", "The number of triangles in the mesh.", 0 );
149  m_nbTriangles->setMax( std::numeric_limits< int >::max() );
150 
151  m_nbVertices = m_infoProperties->addProperty( "Vertices", "The number of vertices in the mesh.", 0 );
152  m_nbVertices->setMax( std::numeric_limits< int >::max() );
153 
154  // some properties need to trigger an update
155  m_propCondition = std::shared_ptr< WCondition >( new WCondition() );
156 
157  // setup all the properties. See header file for their meaning and purpose.
158  m_showOutline = m_properties->addProperty( "Outline", "Show all edges of the trinagulation as lines.", false, m_propCondition );
159 
160  m_coloringGroup = m_properties->addPropertyGroup( "Coloring", "Coloring options and colormap options." );
161 
162  m_opacity = m_coloringGroup->addProperty( "Opacity %", "Opaqueness of surface.", 100.0 );
163  m_opacity->setMin( 0.0 );
164  m_opacity->setMax( 100.0 );
165 
166  // Allow the user to select different color modes
167  std::shared_ptr< WItemSelection > colorModes( std::shared_ptr< WItemSelection >( new WItemSelection() ) );
168  colorModes->addItem( "Single Color", "The whole surface is colored using the default color." );
169  colorModes->addItem( "From Mesh", "The surface is colored according to the mesh." );
170  colorModes->addItem( "From colormap connector", "The surface is colored using the colormap on colorMap connector." );
171  m_colorMode = m_coloringGroup->addProperty( "Color mode", "Choose one of the available colorings.", colorModes->getSelectorFirst(),
172  m_propCondition );
174 
175  // this is the color used if single color is selected
176  m_color = m_coloringGroup->addProperty( "Default color", "The color of of the surface.",
177  WColor( .9f, .9f, 0.9f, 1.0f ), m_propCondition );
178 
179  m_colormap = m_coloringGroup->addProperty( "Enable colormapping", "Turn colormapping on", false );
180  m_parameterCenter = m_coloringGroup->addProperty( "Parameter center", "Parameter center selection", 0.5 );
181  m_parameterCenter->setMin( -2.0 );
182  m_parameterCenter->setMax( 2.0 );
183  m_parameterWidth = m_coloringGroup->addProperty( "Parameter width", "Parameter width selection", 0.1 );
184  m_parameterWidth->setMin( 0.0 );
185  m_parameterWidth->setMax( 2.0 );
186 
187  // Allow the user to select different rendering modes
188  std::shared_ptr< WItemSelection > illustrationModes( std::shared_ptr< WItemSelection >( new WItemSelection() ) );
189  illustrationModes->addItem( "None", "Standard rendering." );
190  illustrationModes->addItem( "X-slab", "Slab normal to x-axis." );
191  illustrationModes->addItem( "Stream ribbon", "A range of streamlines (if red color represents s-parameter of surface)." );
192  illustrationModes->addItem( "Time ribbon", "A range timelines (if green color represents t-parameter of surface)." );
193  illustrationModes->addItem( "View-dependent opacity", "Less opaque where surface normal parallel to view direction." );
194  illustrationModes->addItem( "View-dependent opacity (inverted)", "More opqaue where surface normal parallel to view direction." );
195  m_illustrationMode = m_coloringGroup->addProperty( "Illustration mode",
196  "Choose one of the types of illustrating the surface.",
197  illustrationModes->getSelectorFirst(),
198  m_propCondition );
200 
201 
202  // call WModule's initialization
204 }
205 
207 {
208  // let the main loop awake if the data changes.
209  m_moduleState.setResetable( true, true );
210  m_moduleState.add( m_meshInput->getDataChangedCondition() );
211  m_moduleState.add( m_colorMapInput->getDataChangedCondition() );
213 
214  // signal ready state. The module is now ready to be used.
215  ready();
216 
217  ////////////////////////////////////////////////////////////////////////////////////////////////////
218  // setup the main graphics-node:
219  ////////////////////////////////////////////////////////////////////////////////////////////////////
220 
221  // create a OSG node, which will contain the triangle data and allows easy transformations:
223 
224  osg::ref_ptr<osg::LightModel> lightModel( new osg::LightModel() );
225  osg::ref_ptr<osg::StateSet> moduleNodeState = m_moduleNode->getOrCreateStateSet();
226  lightModel->setTwoSided( true );
227  moduleNodeState->setAttributeAndModes( lightModel.get(), osg::StateAttribute::ON );
228 
229  WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->insert( m_moduleNode );
230 
231  // load the GLSL shader:
232  m_shader = new WGEShader( "WMSurfaceIllustrator", m_localPath );
233  m_colorMapTransformation = new osg::Uniform( "u_colorMapTransformation", osg::Matrixd::identity() );
234  m_shader->addPreprocessor( WGEShaderPreprocessor::SPtr(
235  new WGEShaderPropertyDefineOptions< WPropBool >( m_colormap, "COLORMAPPING_DISABLED", "COLORMAPPING_ENABLED" ) )
236  );
237 
238 
239  // set the opacity and material color property as GLSL uniforms:
240  moduleNodeState->addUniform( new WGEPropertyUniform< WPropDouble >( "u_opacity", m_opacity ) );
241 
242  // loop until the module container requests the module to quit
243  while( !m_shutdownFlag() )
244  {
245  // Now, the moduleState variable comes into play. The module can wait for the condition, which gets fired whenever the input receives data
246  // or an property changes. The main loop now waits until something happens.
247  debugLog() << "Waiting ...";
249 
250  // woke up since the module is requested to finish
251  if( m_shutdownFlag() )
252  {
253  break;
254  }
255 
256  // Get data and check for invalid data.
257  std::shared_ptr< WTriangleMesh > mesh = m_meshInput->getData();
258  if( !mesh )
259  {
260  debugLog() << "Invalid Data. Disabling.";
261  continue;
262  }
263 
264  renderMesh( mesh );
265  }
266 
267  // it is important to always remove the modules again
268  WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->remove( m_moduleNode );
269 }
270 
271 
272 
273 void WMSurfaceIllustrator::renderMesh( std::shared_ptr< WTriangleMesh > mesh )
274 {
275  std::shared_ptr< WColoredVertices > colorMap = m_colorMapInput->getData();
276 
277  m_nbTriangles->set( mesh->triangleSize() );
278  m_nbVertices->set( mesh->vertSize() );
279 
280  // prepare the geometry node
281  debugLog() << "Start rendering Mesh";
282  osg::ref_ptr< osg::Geometry > geometry;
283  osg::ref_ptr< osg::Geode > geode( new osg::Geode );
284  geode->getOrCreateStateSet()->addUniform( m_colorMapTransformation );
285  geode->getOrCreateStateSet()->addUniform( new WGEPropertyUniform< WPropDouble >( "u_parameterCenter", m_parameterCenter ) );
286  geode->getOrCreateStateSet()->addUniform( new WGEPropertyUniform< WPropDouble >( "u_parameterWidth", m_parameterWidth ) );
287  WItemSelector illustrationModeSelector = m_illustrationMode->get( true );
288  int illustrationTypeId = static_cast<int>( illustrationModeSelector.getItemIndexOfSelected( 0 ) );
289  geode->getOrCreateStateSet()->addUniform( new osg::Uniform( "u_renderingType", illustrationTypeId ) );
290 
291  // apply shader only to mesh
292  m_shader->apply( geode );
293 
294  // get the middle point of the mesh
295  std::vector< size_t >triangles = mesh->getTriangles();
296  std::vector< size_t >::const_iterator trianglesIterator;
297  double minX = wlimits::MAX_DOUBLE;
298  double minY = wlimits::MAX_DOUBLE;
299  double minZ = wlimits::MAX_DOUBLE;
300 
301 
302  double maxX = wlimits::MIN_DOUBLE;
303  double maxY = wlimits::MIN_DOUBLE;
304  double maxZ = wlimits::MIN_DOUBLE;
305 
306  for( trianglesIterator = triangles.begin();
307  trianglesIterator != triangles.end();
308  trianglesIterator++ )
309  {
310  osg::Vec3d vectorX = mesh->getVertex( *trianglesIterator );
311  updateMinMax( minX, maxX, minY, maxY, minZ, maxZ, vectorX );
312  }
313 
314  // start rendering
315  std::shared_ptr< WProgress > progress( new WProgress( "Rendering", 3 ) );
316  m_progress->addSubProgress( progress );
317 
318  ++*progress;
319 
320  // now create the mesh but handle the color mode properly
321  if( m_showOutline->get( true ) )
322  {
323  geometry = wge::convertToOsgGeometryLines( mesh, m_color->get(), false );
324  }
325  else
326  {
327  WItemSelector colorModeSelector = m_colorMode->get( true );
328  if( colorModeSelector.getItemIndexOfSelected( 0 ) == 0 )
329  {
330  // use single color
331  geometry = wge::convertToOsgGeometry( mesh, m_color->get(), true, true, false );
332  }
333  else if( colorModeSelector.getItemIndexOfSelected( 0 ) == 1 )
334  {
335  // take color from mesh
336  geometry = wge::convertToOsgGeometry( mesh, m_color->get(), true, true, true );
337  }
338  else
339  {
340  // take color from map
341  if( colorMap )
342  {
343  geometry = wge::convertToOsgGeometry( mesh, *colorMap, m_color->get(), true, true );
344  }
345  else
346  {
347  warnLog() << "External colormap not connected. Using default color.";
348  geometry = wge::convertToOsgGeometry( mesh, m_color->get(), true, true, false );
349  }
350  }
351  }
352 
354 
355  // done. Set the new drawable
356 
357  geode->addDrawable( geometry );
358  geode->setName( "Surface Illustrator Geode" );
359  m_moduleNode->clear();
360  m_moduleNode->insert( geode );
361  debugLog() << "Rendering Mesh done";
362  progress->finish();
363 }
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.
This class adds some convenience methods to WGEGroupNode.
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
A class containing a list of named items.
This class represents a subset of a WItemSelection.
Definition: WItemSelector.h:53
virtual size_t getItemIndexOfSelected(size_t index) const
Helps to get the index of an selected item in the 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
This module renders the triangle mesh given at its input connector as a surface.
WPropBool m_colormap
Turn Colormapping on/off.
std::shared_ptr< WCondition > m_propCondition
A condition used to notify about changes in several properties.
WPropBool m_showOutline
Toggle showing outline instead fo surface.
WPropInt m_nbTriangles
Info-property showing the number of triangles in the mesh.
WPropSelection m_colorMode
Which colormode should be used?
osg::ref_ptr< osg::Uniform > m_colorMapTransformation
OSG Uniform for the transformation matrix which transforms the mesh.
std::shared_ptr< WModuleInputData< WColoredVertices > > m_colorMapInput
A map for mapping each vertex to a color.
WGEManagedGroupNode::SPtr m_moduleNode
The node containing all geometry nodes.
WPropInt m_nbVertices
Info-property showing the number of vertices in the mesh.
virtual void properties()
Initialize the properties for this module.
virtual const std::string getDescription() const
Gives back a description of this module.
virtual const char ** getXPMIcon() const
Get the icon for this module in XPM format.
void renderMesh(std::shared_ptr< WTriangleMesh > mesh)
Render the mesh.
void updateMinMax(double &minX, double &maxX, double &minY, double &maxY, double &minZ, double &maxZ, const osg::Vec3d &vector) const
Calculates the bounding box of a vector and increases the specified one if needed.
WPropColor m_color
The color of the mesh to be rendered.
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...
virtual void connectors()
Initialize the connectors this module is using.
WMSurfaceIllustrator()
Constructor.
WPropDouble m_parameterWidth
Set width of selected surface parameter interval.
WPropDouble m_parameterCenter
Set center of selected surface parameter.
virtual void moduleMain()
Entry point after loading the module.
WPropDouble m_opacity
The mesh's opacity value.
osg::ref_ptr< WGEShader > m_shader
The shader for the mesh.
std::shared_ptr< WModuleInputData< WTriangleMesh > > m_meshInput
An input connector used to get meshes from other modules.
double getMedian(double x, double y, double z) const
Gets the median of three values.
WPropSelection m_illustrationMode
Select the type of illustration applied in the shader.
virtual ~WMSurfaceIllustrator()
Destructor.
WPropGroup m_coloringGroup
Group for all color and colormapping options.
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
wlog::WStreamedLogger warnLog() const
Logger instance for comfortable warning- logs.
Definition: WModule.cpp:580
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
std::shared_ptr< WProgressCombiner > m_progress
Progress indicator used as parent for all progress' of this module.
Definition: WModule.h:652
virtual void connectors()
Initialize connectors in this function.
Definition: WModule.cpp:208
Class managing progress inside of modules.
Definition: WProgress.h:42
WBoolFlag m_shutdownFlag
Condition getting fired whenever the thread should quit.
void addTo(WPropSelection prop)
Add the PC_SELECTONLYONE constraint to the property.
osg::ref_ptr< osg::Geometry > convertToOsgGeometryLines(WTriangleMesh::SPtr mesh, const WColor &defaultColor=WColor(1.0, 1.0, 1.0, 1.0), bool useMeshColor=true)
Convert triangle mesh to lines representing it.
osg::ref_ptr< osg::Geometry > convertToOsgGeometry(WTriangleMesh::SPtr mesh, const WColor &defaultColor=WColor(1.0, 1.0, 1.0, 1.0), bool includeNormals=false, bool lighting=false, bool useMeshColor=true)
Extract the vertices and triangles from a WTriangleMesh and save them into an osg::Geometry.
const double MAX_DOUBLE
Maximum double value.
Definition: WLimits.cpp:31
const double MIN_DOUBLE
Positive minimum double value.
Definition: WLimits.cpp:36