WMMarchingCubes.h 11.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------

25 26
#ifndef WMMARCHINGCUBES_H
#define WMMARCHINGCUBES_H
27

Alexander Wiebel's avatar
Alexander Wiebel committed
28 29 30 31
#include <map>
#include <string>
#include <vector>

32 33 34 35
#include <osg/Node>
#include <osg/Geode>
#include <osg/Uniform>

36
#include "../../common/datastructures/WTriangleMesh.h"
37
#include "../../kernel/WModule.h"
38
#include "../../kernel/WModuleInputData.h"
39
#include "../../kernel/WModuleOutputData.h"
40
#include "../../dataHandler/WGridRegular3D.h"
41
#include "../../graphicsEngine/WShader.h"
42
#include "../../graphicsEngine/WGEGroupNode.h"
43

44 45 46
/**
 * A point consisting of its coordinates and ID
 */
Alexander Wiebel's avatar
Alexander Wiebel committed
47 48
struct WPointXYZId
{
49 50 51 52
    unsigned int newID; //!< ID of the point
    double x; //!< x coordinates of the point.
    double y; //!< y coordinates of the point.
    double z; //!< z coordinates of the point.
53 54 55 56
};

typedef std::map< unsigned int, WPointXYZId > ID2WPointXYZId;

57 58 59
/**
 * Encapsulated ids representing a triangle.
 */
Alexander Wiebel's avatar
Alexander Wiebel committed
60 61
struct WMCTriangle
{
62
    unsigned int pointID[3]; //!< The IDs of the vertices of the triangle.
63 64 65 66
};

typedef std::vector<WMCTriangle> WMCTriangleVECTOR;

67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
// -------------------------------------------------------
//
// Numbering of edges (0..B) and vertices (0..7) per cube.
//
//      5--5--6
//     /|    /|
//    4 |   6 |    A=10
//   /  9  /  A
//  4--7--7   |
//  |   | |   |
//  |   1-|1--2
//  8  /  B  /
//  | 0   | 2      B=11
//  |/    |/
//  0--3--3
//
//  |  /
//  z y
//  |/
//  0--x--
//
// -------------------------------------------------------

90
/**
91
 * Module implementing the marching cubes algorithm with consistent triangulation for data
92
 * given on regular grids with axis-aligned cells.
93
 * \ingroup modules
94
 */
95
class WMMarchingCubes : public WModule
96
{
97 98 99
/**
 * Only UnitTests may be friends.
 */
100
friend class WMMarchingCubesTest;
101

102 103 104 105
public:
    /**
     * Standard constructor.
     */
106
    WMMarchingCubes();
107 108 109 110

    /**
     * Destructor.
     */
111
    ~WMMarchingCubes();
112 113 114 115 116 117 118 119 120 121 122 123 124

    /**
     * Gives back the name of this module.
     * \return the module's name.
     */
    virtual const std::string getName() const;

    /**
     * Gives back a description of this module.
     * \return description of module.
     */
    virtual const std::string getDescription() const;

125 126 127
    /**
     * Due to the prototype design pattern used to build modules, this method returns a new instance of this method. NOTE: it
     * should never be initialized or modified in some other way. A simple new instance is required.
128
     *
129 130 131 132
     * \return the prototype used to create every module in OpenWalnut.
     */
    virtual boost::shared_ptr< WModule > factory() const;

133 134 135 136 137
    /**
     * Get the icon for this module in XPM format.
     */
    virtual const char** getXPMIcon() const;

138 139 140 141 142 143
    /**
     * Transform the positions to the correct coordiante system given by the grid.
     * \param positions A data structure holding the positions.
     */
    void transformPositions( ID2WPointXYZId* positions );

144
    /**
145 146 147 148
     * Generate the triangles for the surface on the given dataSet (inGrid, vals).
     * \param inGrid The grid of the data set
     * \param vals the value set of the data set
     * \param isoValue The surface will run through all positions with this value.
149
     */
150
    template< typename T > void generateSurface( boost::shared_ptr< WGrid > inGrid, boost::shared_ptr< WValueSet< T > > vals, double isoValue );
151

152 153 154 155
    /**
     * Activate the rendering of the computed surface.
     * This converts the surface to a WTriangleMesh and calls renderMesh afterwards
     */
156 157
    void renderSurface();

158 159 160 161 162
    /**
     *  updates textures and shader parameters
     */
    void updateTextures();

163 164 165 166
protected:
    /**
     * Entry point after loading the module. Runs in separate thread.
     */
167
    virtual void moduleMain();
168 169 170 171 172 173 174 175 176 177 178 179

    /**
     * Initialize the connectors this module is using.
     */
    virtual void connectors();

    /**
     * Initialize the properties for this module.
     */
    virtual void properties();

private:
180

181 182 183 184
    WPropDouble m_isoValueProp; //!< Property holding the iso value
    WPropInt m_opacityProp; //!< Property holding the opacity valueassigned to the surface
    WPropBool m_useTextureProp; //!< Property indicating whether to use texturing with scalar data sets.

185 186 187 188 189 190 191 192 193 194
    /**
     * Used as callback which simply sets m_textureChanged to true. Called by WSubject whenever the datasets change.
     */
    void notifyTextureChange();

    /**
     * True when textures haven changed.
     */
    bool m_textureChanged;

195
    /**
196
     * This condition denotes whether we need to recompute the surface
197
     */
198
    boost::shared_ptr< WCondition > m_recompute;
199

200 201 202 203
    /**
     * Prepares and commits everything for rendering with the OSG
     * \param mesh The mesh that will be rendered.
     */
204
    void renderMesh( boost::shared_ptr< WTriangleMesh > mesh );
205

206
    boost::shared_ptr< WModuleInputData< WDataSetSingle > > m_input;  //!< Input connector required by this module.
207 208 209
    boost::shared_ptr< WModuleOutputData< WTriangleMesh > > m_output;  //!< Input connector required by this module.

    boost::shared_ptr< WTriangleMesh > m_triMesh; //!< This triangle mesh is proved as output through the connector.
210

Alexander Wiebel's avatar
Alexander Wiebel committed
211 212
    static const unsigned int m_edgeTable[256];  //!< Lookup table for edges used in the construction of the isosurface.
    static const int m_triTable[256][16];  //!< Lookup table for triangles used in the construction of the isosurface.
213 214

    /**
215
     * Calculates the intersection point id of the isosurface with an
216
     * edge.
217 218 219 220 221
     * \param vals the value set that determines the values at the vertices
     * \param nX id of cell in x direction
     * \param nY id of cell in y direction
     * \param nZ id of cell in z direction
     * \param nEdgeNo id of the edge the point that will be interpolates lies on
222
     */
223 224
    template< typename T > WPointXYZId calculateIntersection( boost::shared_ptr< WValueSet< T > > vals,
                                                              unsigned int nX, unsigned int nY, unsigned int nZ, unsigned int nEdgeNo );
225 226 227 228

    /**
     * Interpolates between two grid points to produce the point at which
     * the isosurface intersects an edge.
229 230 231 232 233 234 235 236
     * \param fX1 x coordinate of first position
     * \param fY1 y coordinate of first position
     * \param fZ1 z coordinate of first position
     * \param fX2 x coordinate of second position
     * \param fY2 y coordinate of first position
     * \param fZ2 z coordinate of first position
     * \param tVal1 scalar value at first position
     * \param tVal2 scalar value at second position
237 238
     */
    WPointXYZId interpolate( double fX1, double fY1, double fZ1, double fX2, double fY2, double fZ2, double tVal1, double tVal2 );
239

240 241
    /**
     * Returns the edge ID.
242 243 244 245 246
     * \param nX ID of desired cell along x axis
     * \param nY ID of desired cell along y axis
     * \param nZ ID of desired cell along z axis
     * \param nEdgeNo id of edge inside cell
     * \return The id of the edge in the large array.
247 248 249 250
     */
    int getEdgeID( unsigned int nX, unsigned int nY, unsigned int nZ, unsigned int nEdgeNo );

    /**
251 252 253 254
     * Returns the ID of the vertex given by by the IDs along the axis
     * \param nX ID of desired vertex along x axis
     * \param nY ID of desired vertex along y axis
     * \param nZ ID of desired vertex along z axis
255
     */
Alexander Wiebel's avatar
Alexander Wiebel committed
256
    unsigned int getVertexID( unsigned int nX, unsigned int nY, unsigned int nZ );
257

Alexander Wiebel's avatar
Alexander Wiebel committed
258 259 260
    unsigned int m_nCellsX;  //!< No. of cells in x direction.
    unsigned int m_nCellsY;  //!< No. of cells in y direction.
    unsigned int m_nCellsZ;  //!< No. of cells in z direction.
261

Alexander Wiebel's avatar
Alexander Wiebel committed
262 263 264
    double m_fCellLengthX;  //!< Cell length in x direction.
    double m_fCellLengthY;  //!< Cell length in y direction.
    double m_fCellLengthZ;  //!< Cell length in z direction.
265

Alexander Wiebel's avatar
Alexander Wiebel committed
266
    double m_tIsoLevel;  //!< The isovalue.
267

Alexander Wiebel's avatar
Alexander Wiebel committed
268 269
    ID2WPointXYZId m_idToVertices;  //!< List of WPointXYZIds which form the isosurface.
    WMCTriangleVECTOR m_trivecTriangles;  //!< List of WMCTriangleS which form the triangulation of the isosurface.
270

271 272
    /**
     * Store the mesh in legacy vtk file format.
273 274
     * \param fileName the file where the triMesh will be written to
     * \param triMesh this mesh will be stored.
275
     */
276 277 278
    bool save( std::string fileName, const WTriangleMesh& triMesh ) const;

    /**
279
     * Load meshes saved with WMMarchingCubes::save
280
     * \param fileName the mesh will be loaded from this file
281 282
     */
    WTriangleMesh load( std::string fileName );
283

284 285 286 287 288
    /**
     * Kind of a convenience function for generate surface.
     * It performs the conversions of the value sets of different data types.
     * \param isoValue The surface will represent this value.
     */
289
    void generateSurfacePre( double isoValue );
290 291

    boost::shared_ptr< const WDataSetSingle > m_dataSet; //!< pointer to dataSet to be able to access it throughout the whole module.
292
    boost::shared_ptr< WGridRegular3D > m_grid; //!< pointer to grid, because we need to access the grid for the dimensions of the texture.
293

294

295
    bool m_shaderUseLighting; //!< shall the shader use lighting?
296
    bool m_shaderUseTransparency; //!< shall the shader use transparency?
297

298 299 300
    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.

    osg::ref_ptr< osg::Geode > m_surfaceGeode; //!< Pointer to geode containing the surface.
301

302 303 304
    /**
     * The shader used for the iso surface in m_geode
     */
305
    osg::ref_ptr< WShader > m_shader;
306

307 308 309 310 311 312
    std::vector< osg::ref_ptr< osg::Uniform > > m_typeUniforms; //!< uniforms for ...... ? for shader
    std::vector< osg::ref_ptr< osg::Uniform > > m_alphaUniforms; //!< uniforms for opacities of textures in shader
    std::vector< osg::ref_ptr< osg::Uniform > > m_thresholdUniforms; //!< uniforms for thresholds of textures in shader
    std::vector< osg::ref_ptr< osg::Uniform > > m_samplerUniforms; //!< uniforms for ids of textures in shader
};

313 314 315
/**
 * Adapter object for realizing callbacks of the node representing the isosurface in the osg
 */
316
class SurfaceNodeCallback : public osg::NodeCallback
317 318
{
public:
Alexander Wiebel's avatar
Alexander Wiebel committed
319 320 321 322
    /**
     * Constructor of the callback adapter.
     * \param module A function of this module will be called
     */
323
    explicit SurfaceNodeCallback( boost::shared_ptr< WMMarchingCubes > module );
324

325 326 327 328 329
    /**
     * Function that is called by the osg and that call the function in the module.
     * \param node The node we are called.
     * \param nv the visitor calling us.
     */
330 331
    virtual void operator()( osg::Node* node, osg::NodeVisitor* nv );

332
private:
333
    boost::shared_ptr< WMMarchingCubes > m_module; //!< Pointer to the module to which the function that is called belongs to.
334 335
};

336 337 338 339 340 341 342 343 344 345 346 347 348 349
inline SurfaceNodeCallback::SurfaceNodeCallback( boost::shared_ptr< WMMarchingCubes > module )
    : m_module( module )
{
}

inline void SurfaceNodeCallback::operator()( osg::Node* node, osg::NodeVisitor* nv )
{
    if ( m_module )
    {
        m_module->updateTextures();
    }
    traverse( node, nv );
}

350
#endif  // WMMARCHINGCUBES_H