Commit 640b27c4 authored by Alexander Wiebel's avatar Alexander Wiebel
Browse files

[CLEAN] removed old TriangleMesh class and ADAPTED all remaining depending

classes
parent e8dd8c97
//---------------------------------------------------------------------------
//
// 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/>.
//
//---------------------------------------------------------------------------
#include <iostream>
#include <list>
#include <map>
#include <set>
#include <sstream>
#include <string>
#include <vector>
#include <boost/shared_ptr.hpp>
#include "../math/WLine.h"
#include "../math/WMath.h"
#include "../math/WPlane.h"
#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 >();
boost::shared_ptr< WPrototyped > WTriangleMesh::getPrototype()
{
if ( !m_prototype )
{
m_prototype = boost::shared_ptr< WPrototyped >( new WTriangleMesh() );
}
return m_prototype;
}
WTriangleMesh::WTriangleMesh()
: m_fastAddVertId( 0 ),
m_fastAddTriangleId( 0 ),
m_computedTriNormals( false ),
m_triNormals( 0 ),
m_computedVertNormals( false ),
m_vertNormals( 0 )
{
}
WTriangleMesh::~WTriangleMesh()
{
clearMesh();
}
void WTriangleMesh::clearMesh()
{
m_vertices.clear();
m_triangles.clear();
m_fastAddVertId = 0;
m_fastAddTriangleId = 0;
}
void WTriangleMesh::resizeVertices( size_t size )
{
m_vertices.resize( size );
}
void WTriangleMesh::resizeTriangles( size_t size )
{
m_triangles.resize( size );
}
void WTriangleMesh::fastAddVert( const wmath::WPosition& newVert )
{
m_vertices[m_fastAddVertId] = newVert;
++m_fastAddVertId;
}
void WTriangleMesh::setVertices( const std::vector< wmath::WPosition >& vertices )
{
m_fastAddVertId = vertices.size();
m_vertices = vertices;
}
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;
}
void WTriangleMesh::fastAddTriangle( unsigned int vertA, unsigned int vertB, unsigned int vertC )
{
Triangle t = { { vertA, vertB, vertC } }; // NOLINT
m_triangles[m_fastAddTriangleId] = t;
++m_fastAddTriangleId;
}
void WTriangleMesh::setTriangles( const std::vector< Triangle >& triangles )
{
m_fastAddTriangleId = triangles.size();
m_triangles = triangles;
}
size_t WTriangleMesh::getFastAddTriangleId() const
{
return m_fastAddTriangleId;
}
std::vector< unsigned int > WTriangleMesh::getPositionTriangleNeighborsSlow( size_t i ) const
{
std::vector< unsigned int > neighborIds( 0 );
for( unsigned int triId = 0; triId < m_triangles.size(); ++triId )
{
for( unsigned int j = 0; j < 3; ++j )
{
if( m_triangles[triId].pointID[j] == i )
{
neighborIds.push_back( triId );
}
}
}
return neighborIds;
}
wmath::WVector3D WTriangleMesh::getVertexNormalSlow( size_t i ) const
{
std::vector< unsigned int > neighborIndices = getPositionTriangleNeighborsSlow( i );
wmath::WVector3D normal;
for( unsigned int triId = 0; triId < neighborIndices.size(); ++triId )
{
normal += getTriangleNormal( neighborIndices[triId] );
}
normal *= 1./neighborIndices.size();
return normal;
}
wmath::WVector3D WTriangleMesh::getVertexNormal( size_t i ) const
{
assert( m_computedVertNormals );
return m_vertNormals[i];
}
wmath::WVector3D WTriangleMesh::getTriangleNormal( size_t i ) const
{
Triangle tri = m_triangles[i];
wmath::WVector3D v1 = m_vertices[tri.pointID[1]] - m_vertices[tri.pointID[0]];
wmath::WVector3D v2 = m_vertices[tri.pointID[2]] - m_vertices[tri.pointID[0]];
wmath::WVector3D tempNormal = v1.crossProduct( v2 );
if( tempNormal.norm() < 1e-7 )
{
// If the morm of the vector is below a certain threshold
// the triangle is either very small, or its edges are
// congruent (which also means that the triangle is very
// small or zero) the triangle will probably not be visible.
// Thus we set its normal to zero.
tempNormal = wmath::WVector3D( 0, 0, 0 );
}
else
{
tempNormal.normalize();
}
return tempNormal;
}
void WTriangleMesh::computeTriNormals()
{
if( m_computedTriNormals )
{
return;
}
m_triNormals.reserve( m_triangles.size() );
for( unsigned int triId = 0; triId < m_triangles.size(); ++triId )
{
m_triNormals.push_back( getTriangleNormal( triId ) );
}
m_computedTriNormals = true;
}
void WTriangleMesh::computeVertNormals()
{
if( m_computedVertNormals )
{
return;
}
computeTriNormals();
assert( m_computedTriNormals );
//build neighborhood
std::vector< std::vector< unsigned int > > neighborIds( m_vertices.size() );
for( unsigned int triId = 0; triId < m_triangles.size(); ++triId )
{
for( unsigned int j = 0; j < 3; ++j )
{
neighborIds[m_triangles[triId].pointID[j]].push_back( triId );
}
}
m_vertNormals.reserve( m_vertices.size() );
for( unsigned int vertId = 0; vertId < m_vertices.size(); ++vertId )
{
wmath::WVector3D tempNormal( 0, 0, 0 );
for( unsigned int neighId = 0; neighId < neighborIds[vertId].size(); ++neighId )
{
tempNormal += m_triNormals[neighborIds[vertId][neighId]];
}
tempNormal *= 1./neighborIds.size();
if( tempNormal.norm() < 1e-7 )
{
// If the morm of the vector is below a certain threshold
// the triangle is either very small, or its edges are
// congruent (which also means that the triangle is very
// small or zero) the triangle will probably not be visible.
// Thus we set its normal to zero.
tempNormal = wmath::WVector3D( 0, 0, 0 );
}
else
{
tempNormal.normalize();
}
m_vertNormals.push_back( tempNormal );
}
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 )
//{
// WUnionFind uf( mesh.getNumVertices() ); // idea: every vertex in own component, then successivley join in accordance with the triangles
//
// 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] ); they are already in same
// }
//
// // ATTENTION: The reason for using the complex BucketType instead of pasting vertices directly into a new WTriangleMesh
// // is performance! For example: If there are many vertices reused inside the former WTriangleMesh mesh, then we want
// // to reuse them in the new components too. Hence we must determine if a certain vertex is already inside the new component.
// // Since the vertices are organized in a vector, we can use std::find( v.begin, v.end(), vertexToLookUp ) which results
// // in O(N^2) or we could use faster lookUp via key and value leading to the map and the somehow complicated BucketType.
// typedef std::map< wmath::WPosition, size_t > VertexType; // look up fast if a vertex is already inside the new mesh!
// typedef std::vector< Triangle > TriangleType;
// typedef std::pair< VertexType, TriangleType > BucketType; // Later on the Bucket will be transformed into the new WTriangleMesh component
// std::map< size_t, BucketType > buckets; // Key identify with the cannonical element from UnionFind the new connected component
//
// 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 ] = BucketType( VertexType(), TriangleType() ); // create new bucket
// }
//
// // Note: We discard the order of the points and indices, but semantically the structure remains the same
// VertexType& mapRef = buckets[ component ].first; // short hand alias
// Triangle x = { { 0, 0, 0 } }; // NOLINT
// for( int i = 0; i < 3; ++i )
// {
// size_t id = 0;
// const wmath::WPosition& vertex = vertices[ triangle->pointID[i] ];
// if( mapRef.find( vertex ) == mapRef.end() )
// {
// id = mapRef.size(); // since size might change in next line
// mapRef[ vertex ] = id;
// }
// else
// {
// id = mapRef[ vertex ];
// }
// x.pointID[i] = id;
// }
//
// buckets[ component ].second.push_back( x );
// }
//
// boost::shared_ptr< std::list< boost::shared_ptr< WTriangleMesh > > > result( new std::list< boost::shared_ptr< WTriangleMesh > >() );
// for( std::map< size_t, BucketType >::const_iterator cit = buckets.begin(); cit != buckets.end(); ++cit )
// {
// std::vector< wmath::WPosition > newVertices;
// newVertices.resize( cit->second.first.size() );
// for( VertexType::const_iterator vit = cit->second.first.begin(); vit != cit->second.first.end(); ++vit )
// {
// newVertices.at( vit->second ) = vit->first; // if you are sure that vit->second is always valid replace at() call with operator[]
// }
// boost::shared_ptr< WTriangleMesh > newMesh( new WTriangleMesh() );
// newMesh->resizeVertices( newVertices.size() );
// newMesh->setVertices( newVertices );
// newMesh->resizeTriangles( cit->second.second.size() );
// newMesh->setTriangles( cit->second.second );
// result->push_back( newMesh );
// }
//
// return result;
//}
//
//boost::shared_ptr< std::set< size_t > > tm_utils::intersection( const WTriangleMesh& mesh, const WPlane& plane )
//{
// boost::shared_ptr< std::set< size_t > > result( new std::set< size_t > );
// const std::vector< wmath::WPosition >& vertices = mesh.getVertices();
// const std::vector< Triangle >& triangles = mesh.getTriangles();
// for( std::vector< Triangle >::const_iterator triangle = triangles.begin(); triangle != triangles.end(); ++triangle )
// {
// if( wmath::testIntersectTriangle( vertices[ triangle->pointID[0] ],
// vertices[ triangle->pointID[1] ],
// vertices[ triangle->pointID[2] ],
// plane ) )
// {
// result->insert( triangle->pointID[0] );
// result->insert( triangle->pointID[1] );
// result->insert( triangle->pointID[2] );
// }
// }
//
// return result;
//}
//---------------------------------------------------------------------------
//
// 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 WTRIANGLEMESH_H
#define WTRIANGLEMESH_H
#include <algorithm>
#include <iostream>
#include <list>
#include <set>
#include <string>
#include <vector>
#include <boost/shared_ptr.hpp>
#include "../math/WLine.h"
#include "../math/WPlane.h"
#include "../math/WPosition.h"
#include "../math/WVector3D.h"
#include "../WTransferable.h"
#include "../WExportCommon.h"
/**
* A triangle consisting of 3 id of vertices that represent its corners
*/
struct OWCOMMON_EXPORT Triangle
{
size_t pointID[3]; //!< the ID of the vertices representing the triangle corners
/**
* Compares two triangles. Triangles having the same position in different order are considered different since it maybe to expensive.
*
* \param rhs The other triangle.
*
* \return True if and only if both triangles having the same positions in same order.
*/
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 > > > OWCOMMON_EXPORT componentDecomposition( const WTriangleMesh& mesh );
/**
* Prints for each mesh \#vertices and \#triangles, as well as each triangle with its positions. No point IDs are printed.
*
* \param os Output stream to print on.
* \param rhs The mesh instance.
*
* \return The output stream again for further usage.
*/
std::ostream& operator<<( std::ostream& os, const WTriangleMesh& rhs );
}
/**
* Triangle mesh data structure allowing for convenient access of the elements.
*/
class OWCOMMON_EXPORT WTriangleMesh : public WTransferable
{
/**
* Only UnitTests may be friends.
*/
friend class WTriangleMeshTest;
public:
/**
* Initializes some members.
*/
WTriangleMesh();
/**
* Clears and destroys mesh.
*/
virtual ~WTriangleMesh();
/**
* Gets the name of this prototype.
*
* \return the name.
*/
virtual const std::string getName() const;
/**
* Gets the description for this prototype.
*
* \return the description
*/
virtual const std::string getDescription() const;
/**
* Returns a prototype instantiated with the true type of the deriving class.
*
* \return the prototype.
*/
static boost::shared_ptr< WPrototyped > getPrototype();
/**
* \return Size of the vertex container.
*/
size_t getNumVertices() const;
/**
* \return Size of the triangle container.
*/
size_t getNumTriangles() const;
/**
* Clear all mesh information, i.e. do things like making
* the vertices and triangles containers empty and reset counter variables.
*/
void clearMesh();
/**
* Changes the size of the vertex container.
* \param size the new size of the vertex container
*/
void resizeVertices( size_t size );
/**
* Changes the size of the triangle container.
* \param size the new size of the trinagle container
*/
void resizeTriangles( size_t size );
/**
* Add a new vertex at the position given by internal state variable
* fastAddVertId. Each call increases fastAddVertId by one. Exercise care
* when using this function because it depends on the state of the WTriangleMesh.
* \param newVert The vertex that will be added.
*/
void fastAddVert( const wmath::WPosition& newVert );
/**
* Set vertices to given vector of vertex positions. Be aware that this includes
* a complete copy operation.
* \param vertices A vector of position that will be the vertices of the grid.
*/
void setVertices( const std::vector< wmath::WPosition >& vertices );
/**
* Get vector of the vertex positions.
*
* \return const reference to the vertices
*/
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.
*/
size_t getFastAddVertId() const;
/**
* Add a new triangle at the position given by internal state variable
* fastAddTriangleId. Each call increases fastAddTriangleId by one. Exercise care
* when using this function because it depends on the state of the WTriangleMesh.
* \param vertA Id of vertex in vertex array that will be the first corner of the new triangle
* \param vertB Id of vertex in vertex array that will be the second corner of the new triangle
* \param vertC Id of vertex in vertex array that will be the third corner of the new triangle
*/
void fastAddTriangle( unsigned int vertA, unsigned int vertB, unsigned int vertC );
/**
* Set triangles to given vector of vertex index triples. Be aware that this includes
* a complete copy operation.
* \param triangles Vector of triangles (i.e. encapsulated vertex IDs) that will be the mesh
*/
void setTriangles( const std::vector< Triangle >& triangles );
/**
* \return the state of the variable telling fastAddTriangle where to insert the triangle.
*/
size_t getFastAddTriangleId() const;
/**
* \param id ID of vertex
* \return position of id-th vertex.
*/
wmath::WPosition getVertex( size_t id ) const;
/**
* \param triId id of the triangle in triangle list
* \param vertId id of the vertex in the triangle's vertex list
* \return global vertex id of the vertId-th vertex of the triId-th triangle.
*/
size_t getTriangleVertexId( size_t triId, size_t vertId ) const;
/**
* \param i ID of the triangle the normal will be computed for.
* \return normal of i-th trinagle. Will be computed in the moment of the call.
* i.e. with no memory overhead but possibly slow.
* Normal will be of length 1.
*/
wmath::WVector3D getTriangleNormal( size_t i ) const;
/**
* Get the indices of the triangles surrounding the i-th position.
* This function is slow but const and memory efficient.
* Normal will be of length 1.
* \param i ID of position.
*/
std::vector< unsigned int > getPositionTriangleNeighborsSlow( size_t i ) const;