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>
|
<b>Core</b>
|
||||||
<ul>
|
<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>make all negative handles invalid, not just -1</li>
|
||||||
<li>Several warnings fixed (Including the checked iterators)</li>
|
<li>Several warnings fixed (Including the checked iterators)</li>
|
||||||
</ul>
|
</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
|
protected: //------------------------------------------------- low-level access
|
||||||
|
|
||||||
public: // used by non-native kernel and MeshIO, should be protected
|
public: // used by non-native kernel and MeshIO, should be protected
|
||||||
|
|||||||
@@ -186,6 +186,8 @@ public:
|
|||||||
|
|
||||||
// --- constructor/destructor
|
// --- constructor/destructor
|
||||||
PolyMeshT() {}
|
PolyMeshT() {}
|
||||||
|
template<typename T>
|
||||||
|
explicit PolyMeshT(const T& t) : Kernel(t) {}
|
||||||
virtual ~PolyMeshT() {}
|
virtual ~PolyMeshT() {}
|
||||||
|
|
||||||
/** Uses default copy and assignment operator.
|
/** Uses default copy and assignment operator.
|
||||||
|
|||||||
@@ -74,7 +74,8 @@
|
|||||||
|
|
||||||
namespace OpenMesh {
|
namespace OpenMesh {
|
||||||
|
|
||||||
|
template<class Traits>
|
||||||
|
class TriMesh_ArrayKernelT;
|
||||||
//== CLASS DEFINITION =========================================================
|
//== CLASS DEFINITION =========================================================
|
||||||
|
|
||||||
/// Helper class to build a PolyMesh-type
|
/// Helper class to build a PolyMesh-type
|
||||||
@@ -97,7 +98,18 @@ struct PolyMesh_ArrayKernel_GeneratorT
|
|||||||
template <class Traits = DefaultTraits>
|
template <class Traits = DefaultTraits>
|
||||||
class PolyMesh_ArrayKernelT
|
class PolyMesh_ArrayKernelT
|
||||||
: public PolyMesh_ArrayKernel_GeneratorT<Traits>::Mesh
|
: 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
|
/// Default constructor
|
||||||
TriMeshT() : PolyMesh() {}
|
TriMeshT() : PolyMesh() {}
|
||||||
|
explicit TriMeshT(PolyMesh rhs) : PolyMesh((rhs.triangulate(), rhs))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// Destructor
|
/// Destructor
|
||||||
virtual ~TriMeshT() {}
|
virtual ~TriMeshT() {}
|
||||||
|
|
||||||
|
|||||||
@@ -74,7 +74,8 @@
|
|||||||
|
|
||||||
namespace OpenMesh {
|
namespace OpenMesh {
|
||||||
|
|
||||||
|
template<class Traits>
|
||||||
|
class PolyMesh_ArrayKernelT;
|
||||||
//== CLASS DEFINITION =========================================================
|
//== CLASS DEFINITION =========================================================
|
||||||
|
|
||||||
|
|
||||||
@@ -97,7 +98,18 @@ struct TriMesh_ArrayKernel_GeneratorT
|
|||||||
template <class Traits = DefaultTraits>
|
template <class Traits = DefaultTraits>
|
||||||
class TriMesh_ArrayKernelT
|
class TriMesh_ArrayKernelT
|
||||||
: public TriMesh_ArrayKernel_GeneratorT<Traits>::Mesh
|
: 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