Merge branch 'featureMeshConversion' into 'master'
Feature mesh conversion implements a cast from polyMesh to Mesh and vice versa using static_cast<Mesh>(polymeshInstance) or static_cast<PolyMesh>(trimeshInstance) as mentioned in #23 . Copy constructors for respective mesh types were added as well as a function to copy all properties from one mesh to another. Unittest for mesh conversions were added checking the number of vertices / faces as well as custom double vertex properties and edge properties. Note: The used triangulation only works for convex polygons, it should be replaced by the earclipping triangulation mentioned in #33 See merge request !110
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
|
||||
<b>Core</b>
|
||||
<ul>
|
||||
<li>Implemented a cast from polyMesh to Mesh and vice versa using static_cast(polymeshInstance) or static_cast(trimeshInstance)</li>
|
||||
<li>make all negative handles invalid, not just -1</li>
|
||||
<li>Several warnings fixed (Including the checked iterators)</li>
|
||||
</ul>
|
||||
|
||||
@@ -583,6 +583,18 @@ public:
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief copy_all_kernel_properties uses the = operator to copy all properties from a given other BaseKernel.
|
||||
* @param _other Another BaseKernel, to copy the properties from.
|
||||
*/
|
||||
void copy_all_kernel_properties(const BaseKernel & _other)
|
||||
{
|
||||
this->vprops_ = _other.vprops_;
|
||||
this->eprops_ = _other.eprops_;
|
||||
this->hprops_ = _other.hprops_;
|
||||
this->fprops_ = _other.fprops_;
|
||||
}
|
||||
|
||||
protected: //------------------------------------------------- low-level access
|
||||
|
||||
public: // used by non-native kernel and MeshIO, should be protected
|
||||
|
||||
@@ -186,6 +186,8 @@ public:
|
||||
|
||||
// --- constructor/destructor
|
||||
PolyMeshT() {}
|
||||
template<typename T>
|
||||
explicit PolyMeshT(const T& t) : Kernel(t) {}
|
||||
virtual ~PolyMeshT() {}
|
||||
|
||||
/** Uses default copy and assignment operator.
|
||||
|
||||
@@ -74,7 +74,8 @@
|
||||
|
||||
namespace OpenMesh {
|
||||
|
||||
|
||||
template<class Traits>
|
||||
class TriMesh_ArrayKernelT;
|
||||
//== CLASS DEFINITION =========================================================
|
||||
|
||||
/// Helper class to build a PolyMesh-type
|
||||
@@ -97,7 +98,18 @@ struct PolyMesh_ArrayKernel_GeneratorT
|
||||
template <class Traits = DefaultTraits>
|
||||
class PolyMesh_ArrayKernelT
|
||||
: public PolyMesh_ArrayKernel_GeneratorT<Traits>::Mesh
|
||||
{};
|
||||
{
|
||||
public:
|
||||
PolyMesh_ArrayKernelT() {}
|
||||
template<class OtherTraits>
|
||||
PolyMesh_ArrayKernelT( const TriMesh_ArrayKernelT<OtherTraits> & t)
|
||||
{
|
||||
//assign the connectivity (add vertices)
|
||||
this->assign(t);
|
||||
//copy properties from triMesh
|
||||
this->copy_all_kernel_properties(t);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
@@ -169,6 +169,10 @@ public:
|
||||
|
||||
/// Default constructor
|
||||
TriMeshT() : PolyMesh() {}
|
||||
explicit TriMeshT(PolyMesh rhs) : PolyMesh((rhs.triangulate(), rhs))
|
||||
{
|
||||
}
|
||||
|
||||
/// Destructor
|
||||
virtual ~TriMeshT() {}
|
||||
|
||||
|
||||
@@ -74,7 +74,8 @@
|
||||
|
||||
namespace OpenMesh {
|
||||
|
||||
|
||||
template<class Traits>
|
||||
class PolyMesh_ArrayKernelT;
|
||||
//== CLASS DEFINITION =========================================================
|
||||
|
||||
|
||||
@@ -97,7 +98,18 @@ struct TriMesh_ArrayKernel_GeneratorT
|
||||
template <class Traits = DefaultTraits>
|
||||
class TriMesh_ArrayKernelT
|
||||
: public TriMesh_ArrayKernel_GeneratorT<Traits>::Mesh
|
||||
{};
|
||||
{
|
||||
public:
|
||||
TriMesh_ArrayKernelT() {}
|
||||
template<class OtherTraits>
|
||||
TriMesh_ArrayKernelT( const PolyMesh_ArrayKernelT<OtherTraits> & t)
|
||||
{
|
||||
//assign the connectivity (add vertices)
|
||||
this->assign(t);
|
||||
//copy properties from polyMesh
|
||||
this->copy_all_kernel_properties(t);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
314
src/Unittests/unittests_convert_meshes.cc
Normal file
314
src/Unittests/unittests_convert_meshes.cc
Normal file
@@ -0,0 +1,314 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <Unittests/unittests_common.hh>
|
||||
#include <OpenMesh/Core/Utils/PropertyManager.hh>
|
||||
|
||||
namespace {
|
||||
|
||||
class OpenMeshConvertTriangleMeshToPoly : public OpenMeshBase {
|
||||
|
||||
protected:
|
||||
|
||||
// This function is called before each test is run
|
||||
virtual void SetUp() {
|
||||
mesh_.clear();
|
||||
|
||||
// Add some vertices
|
||||
Mesh::VertexHandle vhandle[4];
|
||||
|
||||
vhandle[0] = mesh_.add_vertex(Mesh::Point(0, 0, 0));
|
||||
vhandle[1] = mesh_.add_vertex(Mesh::Point(0, 1, 0));
|
||||
vhandle[2] = mesh_.add_vertex(Mesh::Point(1, 1, 0));
|
||||
vhandle[3] = mesh_.add_vertex(Mesh::Point(1, 0, 0));
|
||||
|
||||
// Add two faces
|
||||
std::vector<Mesh::VertexHandle> face_vhandles;
|
||||
|
||||
face_vhandles.push_back(vhandle[2]);
|
||||
face_vhandles.push_back(vhandle[1]);
|
||||
face_vhandles.push_back(vhandle[0]);
|
||||
mesh_.add_face(face_vhandles);
|
||||
|
||||
face_vhandles.clear();
|
||||
|
||||
face_vhandles.push_back(vhandle[2]);
|
||||
face_vhandles.push_back(vhandle[0]);
|
||||
face_vhandles.push_back(vhandle[3]);
|
||||
mesh_.add_face(face_vhandles);
|
||||
|
||||
// Test setup:
|
||||
// 1 === 2
|
||||
// | / |
|
||||
// | / |
|
||||
// | / |
|
||||
// 0 === 3
|
||||
}
|
||||
|
||||
// This function is called after all tests are through
|
||||
virtual void TearDown() {
|
||||
|
||||
// Do some final stuff with the member data here...
|
||||
}
|
||||
|
||||
// Member already defined in OpenMeshBase
|
||||
//Mesh mesh_;
|
||||
};
|
||||
|
||||
class OpenMeshConvertPolyMeshToTriangle : public OpenMeshBasePoly {
|
||||
|
||||
protected:
|
||||
|
||||
// This function is called before each test is run
|
||||
virtual void SetUp() {
|
||||
mesh_.clear();
|
||||
|
||||
// Add some vertices
|
||||
Mesh::VertexHandle vhandle[4];
|
||||
|
||||
vhandle[0] = mesh_.add_vertex(Mesh::Point(0, 0, 0));
|
||||
vhandle[1] = mesh_.add_vertex(Mesh::Point(0, 1, 0));
|
||||
vhandle[2] = mesh_.add_vertex(Mesh::Point(1, 1, 0));
|
||||
vhandle[3] = mesh_.add_vertex(Mesh::Point(1, 0, 0));
|
||||
|
||||
// Add two faces
|
||||
std::vector<Mesh::VertexHandle> face_vhandles;
|
||||
|
||||
face_vhandles.push_back(vhandle[2]);
|
||||
face_vhandles.push_back(vhandle[1]);
|
||||
face_vhandles.push_back(vhandle[0]);
|
||||
face_vhandles.push_back(vhandle[3]);
|
||||
mesh_.add_face(face_vhandles);
|
||||
|
||||
// Test setup:
|
||||
// 1 --- 2
|
||||
// | |
|
||||
// | |
|
||||
// | |
|
||||
// 0 --- 3
|
||||
}
|
||||
|
||||
// This function is called after all tests are through
|
||||
virtual void TearDown() {
|
||||
|
||||
// Do some final stuff with the member data here...
|
||||
}
|
||||
|
||||
// Member already defined in OpenMeshBase
|
||||
//Mesh mesh_;
|
||||
};
|
||||
|
||||
/*
|
||||
* ====================================================================
|
||||
* Define tests below
|
||||
* ====================================================================
|
||||
*/
|
||||
|
||||
/* Checks the converted mesh #faces and #vertices behaviour of adding
|
||||
* vertices and faces to a trimesh after the conversion.
|
||||
*/
|
||||
TEST_F(OpenMeshConvertTriangleMeshToPoly, VertexFaceCheck) {
|
||||
|
||||
EXPECT_EQ(4u, mesh_.n_vertices() ) << "Wrong number of vertices in TriMesh";
|
||||
EXPECT_EQ(2u, mesh_.n_faces() ) << "Wrong number of faces in TriMesh";
|
||||
|
||||
//convert triMesh to PolyMesh
|
||||
PolyMesh p = static_cast<PolyMesh>(mesh_);
|
||||
|
||||
// Check setup
|
||||
EXPECT_EQ(4u, p.n_vertices() ) << "Wrong number of vertices in PolyMesh";
|
||||
EXPECT_EQ(2u, p.n_faces() ) << "Wrong number of faces in PolyMesh";
|
||||
|
||||
//add vertex to original mesh
|
||||
Mesh::VertexHandle vhand = mesh_.add_vertex(Mesh::Point(1, 1, 1));
|
||||
|
||||
EXPECT_EQ(5u, mesh_.n_vertices() ) << "Wrong number of vertices in TriMesh";
|
||||
EXPECT_EQ(4u, p.n_vertices() ) << "Wrong number of vertices in PolyMesh";
|
||||
|
||||
Mesh::VertexIter it = mesh_.vertices_begin();
|
||||
//add face to original mesh
|
||||
mesh_.add_face(vhand,(*it),(*++it));
|
||||
|
||||
EXPECT_EQ(3u, mesh_.n_faces() ) << "Wrong number of faces in TriMesh";
|
||||
EXPECT_EQ(2u, p.n_faces() ) << "Wrong number of faces in PolyMesh";
|
||||
}
|
||||
|
||||
/* Creates a double property and checks if it works after conversion
|
||||
*/
|
||||
TEST_F(OpenMeshConvertTriangleMeshToPoly, VertexPropertyCheckDouble) {
|
||||
|
||||
// Add a double vertex property
|
||||
OpenMesh::VPropHandleT<double> doubleHandle;
|
||||
|
||||
EXPECT_FALSE( mesh_.get_property_handle(doubleHandle,"doubleProp") );
|
||||
|
||||
mesh_.add_property(doubleHandle,"doubleProp");
|
||||
|
||||
// Fill property
|
||||
double index = 0.0;
|
||||
|
||||
for ( Mesh::VertexIter v_it = mesh_.vertices_begin() ; v_it != mesh_.vertices_end(); ++v_it ) {
|
||||
mesh_.property(doubleHandle,*v_it) = index;
|
||||
index += 1.0;
|
||||
}
|
||||
|
||||
EXPECT_TRUE(mesh_.get_property_handle(doubleHandle,"doubleProp"));
|
||||
|
||||
//convert triMesh to PolyMesh
|
||||
PolyMesh p = static_cast<PolyMesh>(mesh_);
|
||||
|
||||
EXPECT_TRUE(p.get_property_handle(doubleHandle,"doubleProp"));
|
||||
|
||||
// Check if it is ok.
|
||||
Mesh::VertexIter v_it = p.vertices_begin();
|
||||
EXPECT_EQ( p.property(doubleHandle,*v_it) , 0.0 ) << "Invalid double value for vertex 0";
|
||||
++v_it;
|
||||
|
||||
EXPECT_EQ( p.property(doubleHandle,*v_it) , 1.0 ) << "Invalid double value for vertex 1";
|
||||
++v_it;
|
||||
|
||||
EXPECT_EQ( p.property(doubleHandle,*v_it) , 2.0 ) << "Invalid double value for vertex 2";
|
||||
++v_it;
|
||||
|
||||
EXPECT_EQ( p.property(doubleHandle,*v_it) , 3.0 ) << "Invalid double value for vertex 3";
|
||||
|
||||
//check if deletion in the original mesh affects the converted one.
|
||||
mesh_.get_property_handle(doubleHandle,"doubleProp");
|
||||
mesh_.remove_property(doubleHandle);
|
||||
EXPECT_FALSE(mesh_.get_property_handle(doubleHandle,"doubleProp"));
|
||||
EXPECT_TRUE(p.get_property_handle(doubleHandle,"doubleProp"));
|
||||
|
||||
}
|
||||
|
||||
/* Checks the converted mesh #faces and #vertices behaviour of adding
|
||||
* vertices and faces to a trimesh after the conversion.
|
||||
*/
|
||||
TEST_F(OpenMeshConvertPolyMeshToTriangle, VertexFaceCheck) {
|
||||
|
||||
EXPECT_EQ(4u, mesh_.n_vertices() ) << "Wrong number of vertices in PolyMesh";
|
||||
EXPECT_EQ(1u, mesh_.n_faces() ) << "Wrong number of faces in PolyMesh";
|
||||
|
||||
//convert PolyMesh to TriMesh
|
||||
Mesh p = static_cast<Mesh>(mesh_);
|
||||
|
||||
// Check setup
|
||||
EXPECT_EQ(4u, p.n_vertices() ) << "Wrong number of vertices in TriMesh";
|
||||
EXPECT_EQ(2u, p.n_faces() ) << "Wrong number of faces in TriMesh";
|
||||
|
||||
//add vertex to original mesh
|
||||
Mesh::VertexHandle vhand = mesh_.add_vertex(Mesh::Point(1, 1, 1));
|
||||
|
||||
EXPECT_EQ(5u, mesh_.n_vertices() ) << "Wrong number of vertices in PolyMesh";
|
||||
EXPECT_EQ(4u, p.n_vertices() ) << "Wrong number of vertices in TriMesh";
|
||||
|
||||
Mesh::VertexIter it = mesh_.vertices_begin();
|
||||
//add face to original mesh
|
||||
mesh_.add_face(vhand,(*it),(*++it));
|
||||
|
||||
EXPECT_EQ(2u, mesh_.n_faces() ) << "Wrong number of faces in PolyMesh";
|
||||
EXPECT_EQ(2u, p.n_faces() ) << "Wrong number of faces in TriMesh";
|
||||
}
|
||||
|
||||
/* Creates a double property and checks if it works after conversion
|
||||
*/
|
||||
TEST_F(OpenMeshConvertPolyMeshToTriangle, VertexPropertyCheckDouble) {
|
||||
|
||||
// Add a double vertex property
|
||||
OpenMesh::VPropHandleT<double> doubleHandle;
|
||||
|
||||
EXPECT_FALSE( mesh_.get_property_handle(doubleHandle,"doubleProp") );
|
||||
|
||||
mesh_.add_property(doubleHandle,"doubleProp");
|
||||
|
||||
// Fill property
|
||||
double index = 0.0;
|
||||
|
||||
for ( Mesh::VertexIter v_it = mesh_.vertices_begin() ; v_it != mesh_.vertices_end(); ++v_it ) {
|
||||
mesh_.property(doubleHandle,*v_it) = index;
|
||||
index += 1.0;
|
||||
}
|
||||
|
||||
EXPECT_TRUE(mesh_.get_property_handle(doubleHandle,"doubleProp"));
|
||||
|
||||
//convert triMesh to PolyMesh
|
||||
Mesh p = static_cast<Mesh>(mesh_);
|
||||
|
||||
EXPECT_TRUE(p.get_property_handle(doubleHandle,"doubleProp"));
|
||||
|
||||
// Check if it is ok.
|
||||
Mesh::VertexIter v_it = p.vertices_begin();
|
||||
EXPECT_EQ( p.property(doubleHandle,*v_it) , 0.0 ) << "Invalid double value for vertex 0";
|
||||
++v_it;
|
||||
|
||||
EXPECT_EQ( p.property(doubleHandle,*v_it) , 1.0 ) << "Invalid double value for vertex 1";
|
||||
++v_it;
|
||||
|
||||
EXPECT_EQ( p.property(doubleHandle,*v_it) , 2.0 ) << "Invalid double value for vertex 2";
|
||||
++v_it;
|
||||
|
||||
EXPECT_EQ( p.property(doubleHandle,*v_it) , 3.0 ) << "Invalid double value for vertex 3";
|
||||
|
||||
//check if deletion in the original mesh affects the converted one.
|
||||
mesh_.get_property_handle(doubleHandle,"doubleProp");
|
||||
mesh_.remove_property(doubleHandle);
|
||||
EXPECT_FALSE(mesh_.get_property_handle(doubleHandle,"doubleProp"));
|
||||
EXPECT_TRUE(p.get_property_handle(doubleHandle,"doubleProp"));
|
||||
|
||||
}
|
||||
|
||||
/* Creates a double property and checks if it works after conversion
|
||||
* especially if edge properties are preserved after triangulation
|
||||
*/
|
||||
TEST_F(OpenMeshConvertPolyMeshToTriangle, EdgePropertyCheckDouble) {
|
||||
|
||||
// Add a double vertex property
|
||||
OpenMesh::EPropHandleT<double> doubleHandle;
|
||||
|
||||
EXPECT_FALSE( mesh_.get_property_handle(doubleHandle,"doubleProp") );
|
||||
|
||||
mesh_.add_property(doubleHandle,"doubleProp");
|
||||
|
||||
// Fill property
|
||||
double index = 0.0;
|
||||
|
||||
for ( Mesh::EdgeIter v_it = mesh_.edges_begin() ; v_it != mesh_.edges_end(); ++v_it ) {
|
||||
mesh_.property(doubleHandle,*v_it) = index;
|
||||
index += 1.0;
|
||||
}
|
||||
|
||||
EXPECT_TRUE(mesh_.get_property_handle(doubleHandle,"doubleProp"));
|
||||
|
||||
//convert triMesh to PolyMesh
|
||||
Mesh p = static_cast<Mesh>(mesh_);
|
||||
|
||||
EXPECT_TRUE(p.get_property_handle(doubleHandle,"doubleProp"));
|
||||
|
||||
// Check if it is ok.
|
||||
Mesh::EdgeIter v_it = p.edges_begin();
|
||||
|
||||
if(p.is_boundary( (*v_it) ))
|
||||
EXPECT_EQ( p.property(doubleHandle,*v_it) , 0.0 ) << "Invalid double value for vertex 0";
|
||||
++v_it;
|
||||
|
||||
if(p.is_boundary( (*v_it) ))
|
||||
EXPECT_EQ( p.property(doubleHandle,*v_it) , 1.0 ) << "Invalid double value for vertex 1";
|
||||
++v_it;
|
||||
|
||||
if(p.is_boundary( (*v_it) ))
|
||||
EXPECT_EQ( p.property(doubleHandle,*v_it) , 2.0 ) << "Invalid double value for vertex 2";
|
||||
++v_it;
|
||||
|
||||
if(p.is_boundary( (*v_it) ))
|
||||
EXPECT_EQ( p.property(doubleHandle,*v_it) , 3.0 ) << "Invalid double value for vertex 3";
|
||||
++v_it;
|
||||
|
||||
EXPECT_FALSE( p.is_boundary(*v_it)) << "Invalid Edge after triangulation";
|
||||
|
||||
//check if deletion in the original mesh affects the converted one.
|
||||
mesh_.get_property_handle(doubleHandle,"doubleProp");
|
||||
mesh_.remove_property(doubleHandle);
|
||||
EXPECT_FALSE(mesh_.get_property_handle(doubleHandle,"doubleProp"));
|
||||
EXPECT_TRUE(p.get_property_handle(doubleHandle,"doubleProp"));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user