Commit cc213131 authored by Mathias Goldau's avatar Mathias Goldau
Browse files

[ADD #262] Now the WTriangleMesh is decomposed into its components

parent d5129085
......@@ -22,9 +22,17 @@
//
//---------------------------------------------------------------------------
#include <iostream>
#include <list>
#include <map>
#include <sstream>
#include <string>
#include <vector>
#include <boost/shared_ptr.hpp>
#include "WTriangleMesh.h"
#include "WUnionFind.h"
// init _static_ member variable and provide a linker reference to it
boost::shared_ptr< WPrototyped > WTriangleMesh::m_prototype = boost::shared_ptr< WPrototyped >();
......@@ -88,6 +96,11 @@ const std::vector< wmath::WPosition >& WTriangleMesh::getVertices() const
return m_vertices;
}
const std::vector< Triangle >& WTriangleMesh::getTriangles() const
{
return m_triangles;
}
size_t WTriangleMesh::getFastAddVertId() const
{
return m_fastAddVertId;
......@@ -237,3 +250,67 @@ void WTriangleMesh::computeVertNormals()
m_computedVertNormals = true;
}
std::ostream& tm_utils::operator<<( std::ostream& os, const WTriangleMesh& rhs )
{
std::stringstream ss;
ss << "WTriangleMesh( #vertices=" << rhs.getNumVertices() << " #triangles=" << rhs.getNumTriangles() << " )" << std::endl;
using string_utils::operator<<;
size_t count = 0;
ss << std::endl;
const std::vector< Triangle > triangles = rhs.getTriangles();
const std::vector< wmath::WPosition > vertices = rhs.getVertices();
for( std::vector< Triangle >::const_iterator triangle = triangles.begin(); triangle != triangles.end(); ++triangle, ++count )
{
std::stringstream prefix;
prefix << "triangle: " << count << "[ ";
std::string indent( prefix.str().size(), ' ' );
ss << prefix.str() << vertices[ triangle->pointID[0] ] << std::endl;
ss << indent << vertices[ triangle->pointID[1] ] << std::endl;
ss << indent << vertices[ triangle->pointID[2] ] << std::endl;
ss << std::string( indent.size() - 2, ' ' ) << "]" << std::endl;
}
return os << ss.str();
}
boost::shared_ptr< std::list< boost::shared_ptr< WTriangleMesh > > > tm_utils::componentDecomposition( const WTriangleMesh& mesh )
{
// idea: every vertex is in its own component then successivley join those components in accordance with the triangles
WUnionFind uf( mesh.getNumVertices() );
const std::vector< Triangle >& triangles = mesh.getTriangles();
for( std::vector< Triangle >::const_iterator triangle = triangles.begin(); triangle != triangles.end(); ++triangle )
{
uf.merge( triangle->pointID[0], triangle->pointID[1] );
uf.merge( triangle->pointID[0], triangle->pointID[2] );
// uf.merge( triangle->pointID[2], triangle->pointID[1] ); not neede here since they are all in same set already
}
// construct meshes
std::map< size_t, boost::shared_ptr< WTriangleMesh > > buckets;
const std::vector< wmath::WPosition >& vertices = mesh.getVertices();
for( std::vector< Triangle >::const_iterator triangle = triangles.begin(); triangle != triangles.end(); ++triangle )
{
size_t component = uf.find( triangle->pointID[0] );
if( buckets.find( component ) == buckets.end() )
{
buckets[ component ] = boost::shared_ptr< WTriangleMesh >( new WTriangleMesh() );
}
// we discard the order of the points and indices, but semantically the structure remains the same
buckets[ component ]->resizeVertices( buckets[ component ]->getNumVertices() + 3 );
buckets[ component ]->resizeTriangles( buckets[ component ]->getNumTriangles() + 1 );
size_t id = buckets[ component ]->getFastAddVertId();
buckets[ component ]->fastAddVert( vertices[ triangle->pointID[0] ] );
buckets[ component ]->fastAddVert( vertices[ triangle->pointID[1] ] );
buckets[ component ]->fastAddVert( vertices[ triangle->pointID[2] ] );
buckets[ component ]->fastAddTriangle( id, id + 1, id + 2 );
}
boost::shared_ptr< std::list< boost::shared_ptr< WTriangleMesh > > > result( new std::list< boost::shared_ptr< WTriangleMesh > >() );
for( std::map< size_t, boost::shared_ptr< WTriangleMesh > >::const_iterator value = buckets.begin(); value != buckets.end(); ++value )
{
result->push_back( value->second );
}
return result;
}
......@@ -25,9 +25,14 @@
#ifndef WTRIANGLEMESH_H
#define WTRIANGLEMESH_H
#include <algorithm>
#include <iostream>
#include <list>
#include <string>
#include <vector>
#include <boost/shared_ptr.hpp>
#include "../math/WPosition.h"
#include "../math/WVector3D.h"
#include "../WTransferable.h"
......@@ -40,8 +45,33 @@
struct Triangle
{
size_t pointID[3]; //!< the ID of the vertices representing the triangle corners
bool operator==( const Triangle& rhs ) const;
};
inline bool Triangle::operator==( const Triangle& rhs ) const
{
return pointID[0] == rhs.pointID[0] && pointID[1] == rhs.pointID[1] && pointID[2] == rhs.pointID[2];
}
class WTriangleMesh;
/**
* TriangleMesh utils
*/
namespace tm_utils
{
/**
* Decompose the given mesh into connected components.
*
* \param mesh The triangle mesh to decompose
*
* \return List of components where each of them is a WTriangleMesh again.
*/
boost::shared_ptr< std::list< boost::shared_ptr< WTriangleMesh > > > componentDecomposition( const WTriangleMesh& mesh );
std::ostream& operator<<( std::ostream& os, const WTriangleMesh& rhs );
}
/**
* Triangle mesh data structure allowing for convenient access of the elements.
*/
......@@ -134,6 +164,13 @@ public:
*/
const std::vector< wmath::WPosition >& getVertices() const;
/**
* Get the vector of triangles (vertex IDs).
*
* \return const reference to the triangles
*/
const std::vector< Triangle >& getTriangles() const;
/**
* \return the state of the variable telling fastAddVert where to insert the vertex.
*/
......@@ -222,6 +259,18 @@ public:
*/
void computeVertNormals();
/**
* Checks if two meshes are exactly the same. Same number of triangles, and
* points, and indices as well as same ordering. Keep in mind different
* ordering might result in the same structure but is considered different
* here.
*
* \param rhs The other mesh to compare with
*
* \return True if and only if both: vertices and triangles are exactly the same.
*/
bool operator==( const WTriangleMesh& rhs ) const;
protected:
static boost::shared_ptr< WPrototyped > m_prototype; //!< The prototype as singleton.
......@@ -267,4 +316,12 @@ inline const std::string WTriangleMesh::getDescription() const
{
return "Triangle mesh data structure allowing for convenient access of the elements.";
}
inline bool WTriangleMesh::operator==( const WTriangleMesh& rhs ) const
{
return std::equal( m_vertices.begin(), m_vertices.end(), rhs.m_vertices.begin() ) &&
std::equal( m_triangles.begin(), m_triangles.end(), rhs.m_triangles.begin() );
}
#endif // WTRIANGLEMESH_H
//---------------------------------------------------------------------------
//
// 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/>.
//
//---------------------------------------------------------------------------
#ifndef WTRIANGLEMESHTRAITS_H
#define WTRIANGLEMESHTRAITS_H
#include <sstream>
#include <cxxtest/TestSuite.h>
#include <cxxtest/ValueTraits.h>
#include "../../test/WTraitsBase.h"
#include "../WTriangleMesh.h"
#ifdef CXXTEST_RUNNING
namespace CxxTest
{
CXXTEST_TEMPLATE_INSTANTIATION
/**
* Enables better UnitTest OutPut if something fails with WTriangleMeshs, so you see
* immedeatly what is failing.
*/
class ValueTraits< WTriangleMesh > : public WTraitsBase
{
public:
/**
* Constructs a new ValueTrait of a WTriangleMesh for better test output
*/
explicit ValueTraits( const WTriangleMesh &mesh )
{
std::stringstream ss;
using tm_utils::operator<<;
ss << mesh;
m_s = ss.str();
}
};
}
#endif // CXXTEST_RUNNING
#endif // WTRIANGLEMESHTRAITS_H
......@@ -25,13 +25,15 @@
#ifndef WTRIANGLEMESH_TEST_H
#define WTRIANGLEMESH_TEST_H
#include <algorithm>
#include <list>
#include <vector>
#include <cxxtest/TestSuite.h>
#include "../WTriangleMesh.h"
#include "../../math/WVector3D.h"
#include "../WTriangleMesh.h"
#include "WTriangleMeshTraits.h"
/**
* Testing the WTriangleMesh class.
......@@ -285,6 +287,126 @@ public:
TS_ASSERT_DELTA( mesh.m_vertNormals[0][1], expectedVertNormal[1], delta );
TS_ASSERT_DELTA( mesh.m_vertNormals[0][2], expectedVertNormal[2], delta );
}
/**
* Two WTriangleMeshes are considered to be equal only if they have the same
* points in same order and the same indices of points for the triangles also
* in same order.
* From an objective point of view there might be different ordering resuling
* in the same structure, but this is to expensive to compute.
*/
void testEqualityOperator( void )
{
WTriangleMesh mesh;
mesh.resizeVertices( 3 );
mesh.fastAddVert( wmath::WPosition( 1, 0, 0 ) );
mesh.fastAddVert( wmath::WPosition( 0, 1, 0 ) );
mesh.fastAddVert( wmath::WPosition( 1, 0, 0 ) );
mesh.resizeTriangles( 1 );
mesh.fastAddTriangle( 0, 1, 2 );
WTriangleMesh expected( mesh );
TS_ASSERT_EQUALS( expected, mesh );
std::swap( mesh.m_triangles[0].pointID[0], mesh.m_triangles[0].pointID[1] );
TS_ASSERT_DIFFERS( expected, mesh );
}
/**
* Decompose the following scene into seven components A, B, C, D, E, F, G.
\verbatim
12 o-----o o----o
/ \ / \ |\ /|
/ \ / \ | \/ |
11 o-----o-----o | /\ |
\ / \ / |/ \|
10 \ / \ / o----o B
9 o-----o A
8 o
7 o |\
/ \ | \
/ \ | \
6 o-----o--+--o\
5 \ o-+--o C
\ /
4 o D
3 o E (degenerated)
2 o-----o F (degenerated)
1 o-----o G
\ /
\ /
0 o
0 1 2 3 4 5 6 7
\endverbatim
*/
void testComponentDecomposition( void )
{
WTriangleMesh mesh;
mesh.resizeVertices( 25 );
mesh.fastAddVert( wmath::WPosition( 1, 0, 0 ) ); // 0
mesh.fastAddVert( wmath::WPosition( 0, 1, 0 ) ); // 1
mesh.fastAddVert( wmath::WPosition( 2, 1, 0 ) ); // 2
mesh.fastAddVert( wmath::WPosition( 0, 2, 0 ) ); // 3
mesh.fastAddVert( wmath::WPosition( 2, 2, 0 ) ); // 4
mesh.fastAddVert( wmath::WPosition( 0, 3, 0 ) ); // 5
mesh.fastAddVert( wmath::WPosition( 3, 4, 0 ) ); // 6
mesh.fastAddVert( wmath::WPosition( 3, 5, 0 ) ); // 7
mesh.fastAddVert( wmath::WPosition( 5, 5, 0 ) ); // 8
mesh.fastAddVert( wmath::WPosition( 0, 6, 0 ) ); // 9
mesh.fastAddVert( wmath::WPosition( 2, 6, 0 ) ); // 10
mesh.fastAddVert( wmath::WPosition( 4, 6, 0 ) ); // 11
mesh.fastAddVert( wmath::WPosition( 1, 7, 0 ) ); // 12
mesh.fastAddVert( wmath::WPosition( 3, 8, 0 ) ); // 13
mesh.fastAddVert( wmath::WPosition( 1, 9, 0 ) ); // 14
mesh.fastAddVert( wmath::WPosition( 3, 9, 0 ) ); // 15
mesh.fastAddVert( wmath::WPosition( 6, 10, 0 ) ); // 16
mesh.fastAddVert( wmath::WPosition( 7, 10, 0 ) ); // 17
mesh.fastAddVert( wmath::WPosition( 0, 11, 0 ) ); // 18
mesh.fastAddVert( wmath::WPosition( 2, 11, 0 ) ); // 19
mesh.fastAddVert( wmath::WPosition( 4, 11, 0 ) ); // 20
mesh.fastAddVert( wmath::WPosition( 1, 12, 0 ) ); // 21
mesh.fastAddVert( wmath::WPosition( 3, 12, 0 ) ); // 23
mesh.fastAddVert( wmath::WPosition( 6, 12, 0 ) ); // 23
mesh.fastAddVert( wmath::WPosition( 7, 12, 0 ) ); // 24
mesh.resizeTriangles( 16 );
mesh.fastAddTriangle( 0, 1, 2 ); // 0
mesh.fastAddTriangle( 3, 4, 4 ); // 1
mesh.fastAddTriangle( 5, 5, 5 ); // 2
mesh.fastAddTriangle( 9, 10, 12 ); // 3
mesh.fastAddTriangle( 10, 6, 11 ); // 4
mesh.fastAddTriangle( 7, 8, 13 ); // 5
mesh.fastAddTriangle( 18, 14, 19 ); // 6
mesh.fastAddTriangle( 14, 15, 19 ); // 7
mesh.fastAddTriangle( 15, 20, 19 ); // 8
mesh.fastAddTriangle( 20, 22, 19 ); // 9
mesh.fastAddTriangle( 22, 21, 19 ); // 10
mesh.fastAddTriangle( 21, 18, 19 ); // 11
mesh.fastAddTriangle( 16, 17, 23 ); // 12
mesh.fastAddTriangle( 16, 17, 24 ); // 13
mesh.fastAddTriangle( 16, 23, 24 ); // 14
mesh.fastAddTriangle( 17, 23, 24 ); // 15
boost::shared_ptr< std::list< boost::shared_ptr< WTriangleMesh > > > components = tm_utils::componentDecomposition( mesh );
TS_ASSERT_EQUALS( components->size(), 7 );
WTriangleMesh expected;
expected.resizeVertices( 3 );
expected.fastAddVert( wmath::WPosition( 1, 0, 0 ) );
expected.fastAddVert( wmath::WPosition( 0, 1, 0 ) );
expected.fastAddVert( wmath::WPosition( 2, 1, 0 ) );
expected.resizeTriangles( 1 );
expected.fastAddTriangle( 0, 1, 2 );
TS_ASSERT_EQUALS( *components->front(), expected );
}
};
#endif // WTRIANGLEMESH_TEST_H
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment