Merge branch 'master' into remove_compile_order_check

This commit is contained in:
Jan Möbius
2020-06-24 09:28:35 +02:00
491 changed files with 39363 additions and 17798 deletions

View File

@@ -11,41 +11,63 @@ endif()
if ( OPENMESH_BUILD_UNIT_TESTS )
# Search for gtest headers and libraries
find_package(GoogleTest)
find_package(GTest)
if(GTEST_FOUND)
enable_testing()
find_package(EIGEN3)
# Set correct include paths so that the compiler can find the headers
include_directories(${GTEST_INCLUDE_DIRS})
include_directories(${GTEST_INCLUDE_DIRS} )
# set additional link directories
link_directories(${GTEST_LIBRARY_DIR} )
if (EIGEN3_FOUND)
add_definitions( -DENABLE_EIGEN3_TEST )
include_directories(${EIGEN3_INCLUDE_DIR})
endif()
if ( CMAKE_GENERATOR MATCHES "^Visual Studio 11.*" )
add_definitions( /D _VARIADIC_MAX=10 )
endif()
# Create new target named unittests_hexmeshing
FILE(GLOB UNITTEST_SRC *.cc)
# Create unittest executable
acg_add_executable(unittests ${UNITTEST_SRC})
# Create unittest executable
acg_add_executable(unittests ${UNITTEST_SRC})
acg_add_executable(unittests_customvec ${UNITTEST_SRC})
acg_add_executable(unittests_doublevec ${UNITTEST_SRC})
target_compile_definitions(unittests_customvec PRIVATE TEST_CUSTOM_TRAITS)
target_compile_definitions(unittests_doublevec PRIVATE TEST_DOUBLE_TRAITS)
# For the unittest we don't want the install rpath as set by acg_add_executable
set_target_properties ( unittests PROPERTIES BUILD_WITH_INSTALL_RPATH 0 )
# For the unittest we don't want the install rpath as set by acg_add_executable
set_target_properties ( unittests PROPERTIES BUILD_WITH_INSTALL_RPATH 0 )
set_target_properties ( unittests_customvec PROPERTIES BUILD_WITH_INSTALL_RPATH 0 )
set_target_properties ( unittests_doublevec PROPERTIES BUILD_WITH_INSTALL_RPATH 0 )
# Set output directory to ${BINARY_DIR}/Unittests
set (OUTPUT_DIR "${CMAKE_BINARY_DIR}/Unittests")
set_target_properties(unittests PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${OUTPUT_DIR})
set_target_properties(unittests PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${OUTPUT_DIR})
set_target_properties(unittests_customvec PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${OUTPUT_DIR})
set_target_properties(unittests_doublevec PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${OUTPUT_DIR})
foreach(CONFIG ${CMAKE_CONFIGURATION_TYPES})
string(TOUPPER ${CONFIG} UPCONFIG)
set_target_properties(unittests PROPERTIES RUNTIME_OUTPUT_DIRECTORY_${UPCONFIG} ${OUTPUT_DIR})
set_target_properties(unittests_customvec PROPERTIES RUNTIME_OUTPUT_DIRECTORY_${UPCONFIG} ${OUTPUT_DIR})
set_target_properties(unittests_doublevec PROPERTIES RUNTIME_OUTPUT_DIRECTORY_${UPCONFIG} ${OUTPUT_DIR})
endforeach()
if ( NOT WIN32)
# Link against all necessary libraries
target_link_libraries(unittests OpenMeshCore OpenMeshTools ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES} pthread)
target_link_libraries(unittests_customvec OpenMeshCore OpenMeshTools ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES} pthread)
target_link_libraries(unittests_doublevec OpenMeshCore OpenMeshTools ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES} pthread)
@@ -55,7 +77,9 @@ if ( OPENMESH_BUILD_UNIT_TESTS )
add_definitions( -DOPENMESHDLL )
endif()
target_link_libraries(unittests OpenMeshCore OpenMeshTools ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES})
target_link_libraries(unittests OpenMeshCore OpenMeshTools ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES})
target_link_libraries(unittests_customvec OpenMeshCore OpenMeshTools ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES})
target_link_libraries(unittests_doublevec OpenMeshCore OpenMeshTools ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES})
endif()
@@ -63,10 +87,13 @@ if ( OPENMESH_BUILD_UNIT_TESTS )
if ( NOT WIN32 )
# Set compiler flags
set_target_properties(unittests PROPERTIES COMPILE_FLAGS "-g -pedantic -Wno-long-long")
set_target_properties(unittests_customvec PROPERTIES COMPILE_FLAGS "-g -pedantic -Wno-long-long")
set_target_properties(unittests_doublevec PROPERTIES COMPILE_FLAGS "-g -pedantic -Wno-long-long")
else()
# Set compiler flags
set_target_properties(unittests PROPERTIES COMPILE_FLAGS "" )
set_target_properties(unittests_customvec PROPERTIES COMPILE_FLAGS "" )
set_target_properties(unittests_doublevec PROPERTIES COMPILE_FLAGS "" )
endif()
if ( OPENMESH_BUILD_SHARED )
@@ -80,12 +107,26 @@ if ( OPENMESH_BUILD_UNIT_TESTS )
"$<TARGET_FILE:${TAR}>"
"${CMAKE_BINARY_DIR}/Unittests/$<TARGET_FILE_NAME:${TAR}>"
COMMENT "Copying OpenMesh targets to unittests directory")
add_custom_command(TARGET unittests_customvec POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E copy
"$<TARGET_FILE:${TAR}>"
"${CMAKE_BINARY_DIR}/Unittests/$<TARGET_FILE_NAME:${TAR}>"
COMMENT "Copying OpenMesh targets to unittests directory")
add_custom_command(TARGET unittests_doublevec POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E copy
"$<TARGET_FILE:${TAR}>"
"${CMAKE_BINARY_DIR}/Unittests/$<TARGET_FILE_NAME:${TAR}>"
COMMENT "Copying OpenMesh targets to unittests directory")
endforeach(TAR)
endif()
acg_copy_after_build(unittests ${CMAKE_CURRENT_SOURCE_DIR}/TestFiles ${CMAKE_BINARY_DIR}/Unittests/)
acg_copy_after_build(unittests_customvec ${CMAKE_CURRENT_SOURCE_DIR}/TestFiles ${CMAKE_BINARY_DIR}/Unittests/)
acg_copy_after_build(unittests_doublevec ${CMAKE_CURRENT_SOURCE_DIR}/TestFiles ${CMAKE_BINARY_DIR}/Unittests/)
add_test(NAME AllTestsIn_OpenMesh_tests WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/Unittests" COMMAND "${CMAKE_BINARY_DIR}/Unittests/unittests")
add_test(NAME AllTestsIn_OpenMesh_tests_with_minimal_vector WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/Unittests" COMMAND "${CMAKE_BINARY_DIR}/Unittests/unittests_customvec")
add_test(NAME AllTestsIn_OpenMesh_tests_with_double_vector WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/Unittests" COMMAND "${CMAKE_BINARY_DIR}/Unittests/unittests_doublevec")
else(GTEST_FOUND)
message(STATUS "Google testing framework was not found, unittests disabled.")

View File

@@ -0,0 +1,33 @@
ply
format ascii 1.0
comment VCGLIB generated
element vertex 8
property float x
property float y
property float z
element face 12
property list uchar int vertex_indices
property float red
property float green
property float blue
end_header
-1 -1 -1
1 -1 -1
1 1 -1
-1 1 -1
-1 -1 1
1 -1 1
1 1 1
-1 1 1
3 0 1 2 0.419608 0.462745 0.698039
3 0 2 3 1.0 0.552941 0.419608
3 5 4 7 0.698039 1.0 0.619608
3 5 7 6 0.419608 1.0 0.529412
3 6 2 1 0.643137 0.419608 0.698039
3 6 1 5 0.643137 0.419608 1.0
3 3 7 4 0.698039 0.552941 1.0
3 3 4 0 1.0 0.552941 0.419608
3 7 3 2 0.419608 0.698039 1.0
3 7 2 6 0.419608 0.698039 0.529412
3 5 1 0 1.0 0.419608 1.0
3 5 0 4 0.698039 1.0 1.0

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -8,8 +8,16 @@
#include <OpenMesh/Core/IO/MeshIO.hh>
#ifdef TEST_CUSTOM_TRAITS
#include <Unittests/unittests_common_customtraits.hh>
#elif defined(TEST_DOUBLE_TRAITS)
struct CustomTraits : public OpenMesh::DefaultTraitsDouble {
};
#else
struct CustomTraits : public OpenMesh::DefaultTraits {
};
#endif
typedef OpenMesh::TriMesh_ArrayKernelT<CustomTraits> Mesh;

View File

@@ -0,0 +1,139 @@
#ifndef UNITTESTS_COMMON_DUMMYTRAITS
#define UNITTESTS_COMMON_DUMMYTRAITS
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
#include <OpenMesh/Core/Utils/color_cast.hh>
#include <array>
namespace Custom {
/// A Vector class with the absolute minimum of built-in methods to test the
/// interface expected from Vectors used in Traits
template <int DIM> class Vec {
public:
// Constructor with DIM components
Vec(float x) : data({ x }) {}
Vec(float x, float y) : data({ x, y }) {}
Vec(float x, float y, float z) : data({{ x, y, z }}) {}
Vec(float x, float y, float z, float w) : data({ x, y, z, w }) {}
Vec() = default;
Vec(Vec<DIM> const &) = default;
float &operator[](int i) { return data[i]; }
float operator[](int i) const { return data[i]; }
private:
std::array<float, DIM> data;
};
template <int DIM> bool operator==(Vec<DIM> const &lhs, Vec<DIM> const &rhs) {
for (int i = 0; i < DIM; i++)
if (lhs[i] != rhs[i]) return false;
return true;
}
template <int DIM>
Vec<DIM> operator+(Vec<DIM> const &lhs, Vec<DIM> const &rhs) {
Vec<DIM> result;
for (int i = 0; i < DIM; i++)
result[i] = lhs[i] + rhs[i];
return result;
}
template <int DIM>
Vec<DIM> operator-(Vec<DIM> const &lhs, Vec<DIM> const &rhs) {
Vec<DIM> result;
for (int i = 0; i < DIM; i++)
result[i] = lhs[i] - rhs[i];
return result;
}
template <int DIM> Vec<DIM> operator*(Vec<DIM> const &lhs, float rhs) {
Vec<DIM> result;
for (int i = 0; i < DIM; i++)
result[i] = lhs[i] * rhs;
return result;
}
template <int DIM> Vec<DIM> operator*(float lhs, Vec<DIM> const &rhs) {
return rhs * lhs;
}
template <int DIM> Vec<DIM> operator/(Vec<DIM> const &lhs, float rhs) {
Vec<DIM> result;
for (int i = 0; i < DIM; i++)
result[i] = lhs[i] / rhs;
return result;
}
template <int DIM> Vec<DIM> &operator+=(Vec<DIM> &lhs, Vec<DIM> const &rhs) {
return lhs = lhs + rhs;
}
template <int DIM> Vec<DIM> &operator-=(Vec<DIM> &lhs, Vec<DIM> const &rhs) {
return lhs = lhs - rhs;
}
template <int DIM> Vec<DIM> &operator*=(Vec<DIM> &lhs, float rhs) {
return lhs = lhs * rhs;
}
template <int DIM> Vec<DIM> &operator/=(Vec<DIM> &lhs, float rhs) {
return lhs = lhs / rhs;
}
template <int DIM> float norm(Vec<DIM> const &v) {
float sum = 0.0f;
for (int i = 0; i < DIM; i++)
sum += v[i] * v[i];
return std::sqrt(sum);
}
template <int DIM> Vec<DIM> &normalize(Vec<DIM> &v) { return v /= norm(v); }
template <int DIM> Vec<DIM> &vectorize(Vec<DIM> &v, float val) {
for (int i = 0; i < DIM; i++)
v[i] = val;
return v;
}
template <int DIM> Vec<DIM> &minimize(Vec<DIM> &v1, Vec<DIM> const &v2) {
for (int i = 0; i < DIM; i++)
v1[i] = std::min(v1[i], v2[i]);
return v1;
}
template <int DIM> Vec<DIM> &maximize(Vec<DIM> &v1, Vec<DIM> const &v2) {
for (int i = 0; i < DIM; i++)
v1[i] = std::max(v1[i], v2[i]);
return v1;
}
template <int DIM> float dot(Vec<DIM> const &v1, Vec<DIM> const &v2) {
float sum = 0.f;
for (int i = 0; i < DIM; i++)
sum += v1[i] * v2[i];
return sum;
}
inline Vec<3> cross(Vec<3> const &v1, Vec<3> const &v2) {
return {v1[1] * v2[2] - v1[2] * v2[1], //
v1[2] * v2[0] - v1[0] * v2[2], //
v1[0] * v2[1] - v1[1] * v2[0]};
}
}
namespace OpenMesh {
template <int DIM> struct vector_traits<Custom::Vec<DIM>> {
using vector_type = Custom::Vec<DIM>;
using value_type = float;
static const size_t size_ = DIM;
static size_t size() { return size_; }
};
}
struct CustomTraits : public OpenMesh::DefaultTraits {
typedef Custom::Vec<3> Point;
typedef Custom::Vec<3> Normal;
typedef Custom::Vec<2> TexCoord2D;
typedef Custom::Vec<3> TexCoord3D;
};
#endif // UNITTESTS_COMMON_DUMMYTRAITS

View File

@@ -285,19 +285,15 @@ TEST_F(OpenMeshConvertPolyMeshToTriangle, EdgePropertyCheckDouble) {
// 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;

View File

@@ -3,6 +3,7 @@
#include <Unittests/unittests_common.hh>
#include <OpenMesh/Tools/Decimater/DecimaterT.hh>
#include <OpenMesh/Tools/Decimater/ModQuadricT.hh>
#include <OpenMesh/Tools/Decimater/ModNormalDeviationT.hh>
namespace {
@@ -49,7 +50,7 @@ TEST_F(OpenMeshDecimater, DecimateMesh) {
decimaterDBG.initialize();
size_t removedVertices = 0;
removedVertices = decimaterDBG.decimate_to(5000);
decimaterDBG.mesh().garbage_collection();
decimaterDBG.mesh().garbage_collection();
EXPECT_EQ(2526u, removedVertices) << "The number of remove vertices is not correct!";
EXPECT_EQ(5000u, mesh_.n_vertices()) << "The number of vertices after decimation is not correct!";
@@ -72,7 +73,7 @@ TEST_F(OpenMeshDecimater, DecimateMeshToFaceVerticesLimit) {
decimaterDBG.initialize();
size_t removedVertices = 0;
removedVertices = decimaterDBG.decimate_to_faces(5000, 8000);
decimaterDBG.mesh().garbage_collection();
decimaterDBG.mesh().garbage_collection();
EXPECT_EQ(2526u, removedVertices) << "The number of remove vertices is not correct!";
EXPECT_EQ(5000u, mesh_.n_vertices()) << "The number of vertices after decimation is not correct!";
@@ -95,7 +96,7 @@ TEST_F(OpenMeshDecimater, DecimateMeshToFaceFaceLimit) {
decimaterDBG.initialize();
size_t removedVertices = 0;
removedVertices = decimaterDBG.decimate_to_faces(4500, 9996);
decimaterDBG.mesh().garbage_collection();
decimaterDBG.mesh().garbage_collection();
EXPECT_EQ(2526u, removedVertices) << "The number of remove vertices is not correct!";
EXPECT_EQ(5000u, mesh_.n_vertices()) << "The number of vertices after decimation is not correct!";
@@ -103,6 +104,34 @@ TEST_F(OpenMeshDecimater, DecimateMeshToFaceFaceLimit) {
EXPECT_EQ(9996u, mesh_.n_faces()) << "The number of faces after decimation is not correct!";
}
TEST_F(OpenMeshDecimater, DecimateMeshToVertexLimitWithLowNormalDeviation) {
bool ok = OpenMesh::IO::read_mesh(mesh_, "cube1.off");
ASSERT_TRUE(ok);
typedef OpenMesh::Decimater::DecimaterT< Mesh > Decimater;
typedef OpenMesh::Decimater::ModQuadricT< Mesh >::Handle HModQuadric;
typedef OpenMesh::Decimater::ModNormalDeviationT< Mesh >::Handle HModNormalDeviation;
Decimater decimaterDBG(mesh_);
HModQuadric hModQuadricDBG;
decimaterDBG.add( hModQuadricDBG );
HModNormalDeviation hModNormalDeviation;
decimaterDBG.add( hModNormalDeviation );
decimaterDBG.module(hModNormalDeviation).set_normal_deviation(15.0);
decimaterDBG.initialize();
size_t removedVertices = 0;
removedVertices = decimaterDBG.decimate_to(8);
decimaterDBG.mesh().garbage_collection();
EXPECT_EQ(6998u, removedVertices) << "The number of remove vertices is not correct!";
EXPECT_EQ( 528u, mesh_.n_vertices()) << "The number of vertices after decimation is not correct!";
EXPECT_EQ(1578u, mesh_.n_edges()) << "The number of edges after decimation is not correct!";
EXPECT_EQ(1052u, mesh_.n_faces()) << "The number of faces after decimation is not correct!";
}
TEST_F(OpenMeshDecimater, DecimateMeshExampleFromDoc) {
bool ok = OpenMesh::IO::read_mesh(mesh_, "cube1.off");
@@ -121,7 +150,7 @@ TEST_F(OpenMeshDecimater, DecimateMeshExampleFromDoc) {
decimaterDBG.initialize();
size_t removedVertices = 0;
removedVertices = decimaterDBG.decimate_to_faces(4500, 9996);
decimaterDBG.mesh().garbage_collection();
decimaterDBG.mesh().garbage_collection();
EXPECT_EQ(2526u, removedVertices) << "The number of remove vertices is not correct!";
EXPECT_EQ(5000u, mesh_.n_vertices()) << "The number of vertices after decimation is not correct!";
@@ -134,7 +163,7 @@ class UnittestObserver : public OpenMesh::Decimater::Observer
size_t notifies_;
size_t all_steps_;
public:
UnittestObserver(size_t _steps) :Observer(_steps), notifies_(0), all_steps_(0) {}
explicit UnittestObserver(size_t _steps) :Observer(_steps), notifies_(0), all_steps_(0) {}
void notify(size_t _step)
{

View File

@@ -0,0 +1,271 @@
#ifdef ENABLE_EIGEN3_TEST
#include <gtest/gtest.h>
#include <Unittests/unittests_common.hh>
#include <iostream>
#include <OpenMesh/Core/Mesh/Traits.hh>
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
#include <OpenMesh/Tools/Decimater/DecimaterT.hh>
#include <OpenMesh/Tools/Decimater/ModQuadricT.hh>
#include <OpenMesh/Tools/Decimater/ModNormalDeviationT.hh>
#include <OpenMesh/Core/Geometry/EigenVectorT.hh>
struct EigenTraits : OpenMesh::DefaultTraits {
using Point = Eigen::Vector3d;
using Normal = Eigen::Vector3d;
using TexCoord2D = Eigen::Vector2d;
};
using EigenTriMesh = OpenMesh::TriMesh_ArrayKernelT<EigenTraits>;
namespace {
class OpenMeshEigenTest : public testing::Test {
protected:
// This function is called before each test is run
virtual void SetUp() {
// Do some initial stuff with the member data here...
}
// This function is called after all tests are through
virtual void TearDown() {
}
EigenTriMesh mesh_;
};
TEST_F(OpenMeshEigenTest, Test_external_vectorize) {
EigenTriMesh::Normal normal;
vectorize(normal,2);
EXPECT_EQ(normal[0],2.0f ) << "Wrong x value";
EXPECT_EQ(normal[1],2.0f ) << "Wrong y value";
EXPECT_EQ(normal[2],2.0f ) << "Wrong z value";
}
TEST_F(OpenMeshEigenTest, Test_external_norm) {
EigenTriMesh::Normal normal(1,0,0);
EigenTriMesh::Scalar result = norm(normal);
EXPECT_EQ(result,1.0f ) << "Wrong norm";
normal = EigenTriMesh::Normal(2,0,0);
result = norm(normal);
EXPECT_EQ(result,2.0f ) << "Wrong norm";
}
TEST_F(OpenMeshEigenTest, Test_external_sqrnorm) {
EigenTriMesh::Normal normal(1,0,0);
EigenTriMesh::Scalar result = sqrnorm(normal);
EXPECT_EQ(result,1.0f ) << "Wrong norm";
normal = EigenTriMesh::Normal(2,0,0);
result = sqrnorm(normal);
EXPECT_EQ(result,4.0f ) << "Wrong norm";
}
TEST_F(OpenMeshEigenTest, Test_external_normalize) {
EigenTriMesh::Normal normal(2,0,0);
normalize(normal);
EXPECT_EQ(norm(normal),1.0f ) << "Wrong norm after normalization";
normal = EigenTriMesh::Normal(2,6,9);
normalize(normal);
EXPECT_EQ(norm(normal),1.0f ) << "Wrong norm after normalization";
}
TEST_F(OpenMeshEigenTest, Test_external_cross_Product) {
EigenTriMesh::Normal normal1(1,0,0);
EigenTriMesh::Normal normal2(1,1,0);
EigenTriMesh::Normal result = cross(normal1,normal2);
EXPECT_EQ(result[0],0.0f ) << "Wrong result x direction";
EXPECT_EQ(result[1],0.0f ) << "Wrong result y direction";
EXPECT_EQ(result[2],1.0f ) << "Wrong result z direction";
}
TEST_F(OpenMeshEigenTest, Test_external_dot_Product) {
EigenTriMesh::Normal normal1(1,0,0);
EigenTriMesh::Normal normal2(1,1,0);
EigenTriMesh::Normal normal3(1,1,1);
EigenTriMesh::Normal normal4(2,4,6);
EigenTriMesh::Scalar result = dot(normal1,normal2);
EigenTriMesh::Scalar result1 = dot(normal3,normal4);
EXPECT_EQ(result,1.0f ) << "Wrong dot product";
EXPECT_EQ(result1,12.0f ) << "Wrong dot product";
}
TEST_F(OpenMeshEigenTest, Test_Basic_setup) {
// Add some vertices
EigenTriMesh::VertexHandle vhandle[4];
vhandle[0] = mesh_.add_vertex(EigenTriMesh::Point(0, 0, 0));
vhandle[1] = mesh_.add_vertex(EigenTriMesh::Point(0, 1, 0));
vhandle[2] = mesh_.add_vertex(EigenTriMesh::Point(1, 1, 0));
vhandle[3] = mesh_.add_vertex(EigenTriMesh::Point(1, 0, 0));
// Add two faces
std::vector<EigenTriMesh::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);
EXPECT_EQ(mesh_.n_faces(),2u) << "Wrong number of faces";
}
TEST_F(OpenMeshEigenTest, test_normal_computation) {
// Add some vertices
EigenTriMesh::VertexHandle vhandle[4];
mesh_.request_vertex_normals();
mesh_.request_face_normals();
vhandle[0] = mesh_.add_vertex(EigenTriMesh::Point(0, 0, 0));
vhandle[1] = mesh_.add_vertex(EigenTriMesh::Point(0, 1, 0));
vhandle[2] = mesh_.add_vertex(EigenTriMesh::Point(1, 1, 0));
vhandle[3] = mesh_.add_vertex(EigenTriMesh::Point(1, 0, 0));
// Add two faces
std::vector<EigenTriMesh::VertexHandle> face_vhandles;
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[0]);
EigenTriMesh::FaceHandle face1 = 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]);
EigenTriMesh::FaceHandle face2 = mesh_.add_face(face_vhandles);
mesh_.update_face_normals();
EXPECT_EQ(mesh_.n_faces(),2u) << "Wrong number of faces";
EigenTriMesh::Normal normal = mesh_.normal(face1);
EXPECT_EQ(normal[0],0.0f ) << "Wrong normal x direction";
EXPECT_EQ(normal[1],0.0f ) << "Wrong normal y direction";
EXPECT_EQ(normal[2],1.0f ) << "Wrong normal z direction";
normal = mesh_.normal(face2);
EXPECT_EQ(normal[0],0.0f ) << "Wrong normal x direction";
EXPECT_EQ(normal[1],0.0f ) << "Wrong normal y direction";
EXPECT_EQ(normal[2],1.0f ) << "Wrong normal z direction";
}
/* Just load a simple mesh file in obj format and count whether
* the right number of entities has been loaded. Afterwards recompute
* normals
*/
TEST_F(OpenMeshEigenTest, LoadSimpleOFFFile) {
mesh_.clear();
bool ok = OpenMesh::IO::read_mesh(mesh_, "cube1.off");
EXPECT_TRUE(ok);
EXPECT_EQ(7526u , mesh_.n_vertices()) << "The number of loaded vertices is not correct!";
EXPECT_EQ(22572u, mesh_.n_edges()) << "The number of loaded edges is not correct!";
EXPECT_EQ(15048u, mesh_.n_faces()) << "The number of loaded faces is not correct!";
mesh_.update_normals();
}
// Test decimation with Eigen as vector type
TEST_F(OpenMeshEigenTest, Decimater) {
mesh_.clear();
bool ok = OpenMesh::IO::read_mesh(mesh_, "cube1.off");
EXPECT_TRUE(ok);
EXPECT_EQ(7526u , mesh_.n_vertices()) << "The number of loaded vertices is not correct!";
EXPECT_EQ(22572u, mesh_.n_edges()) << "The number of loaded edges is not correct!";
EXPECT_EQ(15048u, mesh_.n_faces()) << "The number of loaded faces is not correct!";
mesh_.update_normals();
OpenMesh::Decimater::DecimaterT<EigenTriMesh> decimater(mesh_);
OpenMesh::Decimater::ModQuadricT<EigenTriMesh>::Handle hModQuadric; // use a quadric module
OpenMesh::Decimater::ModNormalDeviationT<EigenTriMesh>::Handle hModNormalDeviation; // also use normal deviation module as binary check
decimater.add(hModQuadric);
decimater.add(hModNormalDeviation);
decimater.module(hModQuadric).unset_max_err();
decimater.module(hModNormalDeviation).set_normal_deviation(15);
decimater.initialize();
size_t removedVertices = decimater.decimate_to(8);
mesh_.garbage_collection();
EXPECT_EQ(6998u, removedVertices) << "The number of remove vertices is not correct!";
EXPECT_EQ( 528u, mesh_.n_vertices()) << "The number of vertices after decimation is not correct!";
EXPECT_EQ(1578u, mesh_.n_edges()) << "The number of edges after decimation is not correct!";
EXPECT_EQ(1052u, mesh_.n_faces()) << "The number of faces after decimation is not correct!";
}
}
#endif

View File

@@ -43,7 +43,6 @@ TEST_F(OpenMeshMultipleChoiceDecimater, DecimateMesh) {
typedef OpenMesh::Decimater::McDecimaterT< Mesh > Decimater;
typedef OpenMesh::Decimater::ModQuadricT< Mesh >::Handle HModQuadric;
typedef OpenMesh::Decimater::ModNormalFlippingT< Mesh >::Handle HModNormal;
Decimater decimaterDBG(mesh_);
HModQuadric hModQuadricDBG;
@@ -67,7 +66,6 @@ TEST_F(OpenMeshMultipleChoiceDecimater, DecimateMeshToFaceVerticesLimit) {
typedef OpenMesh::Decimater::McDecimaterT< Mesh > Decimater;
typedef OpenMesh::Decimater::ModQuadricT< Mesh >::Handle HModQuadric;
typedef OpenMesh::Decimater::ModNormalFlippingT< Mesh >::Handle HModNormal;
Decimater decimaterDBG(mesh_);
HModQuadric hModQuadricDBG;
@@ -91,7 +89,6 @@ TEST_F(OpenMeshMultipleChoiceDecimater, DecimateMeshToFaceFaceLimit) {
typedef OpenMesh::Decimater::McDecimaterT< Mesh > Decimater;
typedef OpenMesh::Decimater::ModQuadricT< Mesh >::Handle HModQuadric;
typedef OpenMesh::Decimater::ModNormalFlippingT< Mesh >::Handle HModNormal;
Decimater decimaterDBG(mesh_);
HModQuadric hModQuadricDBG;
@@ -112,7 +109,7 @@ class UnittestObserver : public OpenMesh::Decimater::Observer
size_t notifies_;
size_t all_steps_;
public:
UnittestObserver(size_t _steps) :Observer(_steps), notifies_(0), all_steps_(0) {}
explicit UnittestObserver(size_t _steps) :Observer(_steps), notifies_(0), all_steps_(0) {}
void notify(size_t _step)
{

View File

@@ -0,0 +1,67 @@
#include <gtest/gtest.h>
#include <Unittests/unittests_common.hh>
namespace {
class OpenMeshTypeTest_Poly : public OpenMeshBasePoly {
protected:
// This function is called before each test is run
virtual void SetUp() {
// Do some initial stuff with the member data here...
}
// This function is called after all tests are through
virtual void TearDown() {
// Do some final stuff with the member data here...
}
};
class OpenMeshTypeTest_Triangle : public OpenMeshBase {
protected:
// This function is called before each test is run
virtual void SetUp() {
// Do some initial stuff with the member data here...
}
// This function is called after all tests are through
virtual void TearDown() {
// Do some final stuff with the member data here...
}
};
/*
* ====================================================================
* Define tests below
* ====================================================================
*/
TEST_F(OpenMeshTypeTest_Triangle, testTypeFunctions) {
EXPECT_TRUE(mesh_.is_trimesh()) << "Type Error!";
EXPECT_FALSE(mesh_.is_polymesh()) << "Type Error!";
}
TEST_F(OpenMeshTypeTest_Poly, testTypeFunctions) {
EXPECT_FALSE(mesh_.is_trimesh()) << "Type Error!";
EXPECT_TRUE(mesh_.is_polymesh()) << "Type Error!";
}
}

View File

@@ -43,7 +43,6 @@ TEST_F(OpenMeshMixedDecimater, DecimateMesh80PercentMc) {
typedef OpenMesh::Decimater::MixedDecimaterT< Mesh > Decimater;
typedef OpenMesh::Decimater::ModQuadricT< Mesh >::Handle HModQuadric;
typedef OpenMesh::Decimater::ModNormalFlippingT< Mesh >::Handle HModNormal;
Decimater decimaterDBG(mesh_);
HModQuadric hModQuadricDBG;
@@ -67,7 +66,6 @@ TEST_F(OpenMeshMixedDecimater, DecimateMeshToFaceVerticesLimit) {
typedef OpenMesh::Decimater::MixedDecimaterT< Mesh > Decimater;
typedef OpenMesh::Decimater::ModQuadricT< Mesh >::Handle HModQuadric;
typedef OpenMesh::Decimater::ModNormalFlippingT< Mesh >::Handle HModNormal;
Decimater decimaterDBG(mesh_);
HModQuadric hModQuadricDBG;
@@ -91,7 +89,6 @@ TEST_F(OpenMeshMixedDecimater, DecimateMeshToFaceFaceLimit) {
typedef OpenMesh::Decimater::MixedDecimaterT< Mesh > Decimater;
typedef OpenMesh::Decimater::ModQuadricT< Mesh >::Handle HModQuadric;
typedef OpenMesh::Decimater::ModNormalFlippingT< Mesh >::Handle HModNormal;
Decimater decimaterDBG(mesh_);
HModQuadric hModQuadricDBG;
@@ -112,7 +109,7 @@ class UnittestObserver : public OpenMesh::Decimater::Observer
size_t notifies_;
size_t all_steps_;
public:
UnittestObserver(size_t _steps) :Observer(_steps), notifies_(0), all_steps_(0) {}
explicit UnittestObserver(size_t _steps) :Observer(_steps), notifies_(0), all_steps_(0) {}
void notify(size_t _step)
{

View File

@@ -247,7 +247,7 @@ TEST_F(OpenMeshNormals, NormalCalculations_calc_vertex_normal_fast) {
mesh_.request_face_normals();
OpenMesh::Vec3f normal;
Mesh::Normal normal;
mesh_.calc_vertex_normal_fast(vhandle[2],normal);
@@ -304,7 +304,7 @@ TEST_F(OpenMeshNormals, NormalCalculations_calc_vertex_normal_correct) {
mesh_.request_halfedge_normals();
mesh_.request_face_normals();
OpenMesh::Vec3f normal;
Mesh::Normal normal;
mesh_.calc_vertex_normal_correct(vhandle[2],normal);
@@ -361,7 +361,7 @@ TEST_F(OpenMeshNormals, NormalCalculations_calc_vertex_normal_loop) {
mesh_.request_halfedge_normals();
mesh_.request_face_normals();
OpenMesh::Vec3f normal;
Mesh::Normal normal;
mesh_.calc_vertex_normal_loop(vhandle[2],normal);

View File

@@ -0,0 +1,70 @@
#include <gtest/gtest.h>
#include <Unittests/unittests_common.hh>
#include <iostream>
namespace {
class OpenMeshCollapsePoly : public OpenMeshBasePoly {
protected:
// This function is called before each test is run
virtual void SetUp() {
}
// 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
* ====================================================================
*/
/*
* This code tests is_collapse_ok on a double sided triangle. The
* test mesh comprises three vertices, that are connected to form two
* triangles of opposite orientation. All halfedges should be non collapsable.
*/
TEST_F(OpenMeshCollapsePoly, CheckCollapseOkDoublesidedTriangle) {
mesh_.clear();
Mesh::VertexHandle vh0 = mesh_.add_vertex(Mesh::Point(0,0,0));
Mesh::VertexHandle vh1 = mesh_.add_vertex(Mesh::Point(1,0,0));
Mesh::VertexHandle vh2 = mesh_.add_vertex(Mesh::Point(1,1,0));
mesh_.add_face(vh0, vh1, vh2);
mesh_.add_face(vh0, vh2, vh1);
mesh_.request_vertex_status();
mesh_.request_face_status();
mesh_.request_edge_status();
int collapsable = 0;
for ( const auto hh : mesh_.all_halfedges() )
{
if (mesh_.is_collapse_ok(hh) )
collapsable++;
}
EXPECT_EQ(collapsable,0) << "No collapse should be ok when we have only a double sided Triangle";
}
}

View File

@@ -746,5 +746,111 @@ TEST_F(OpenMeshProperties, PropertyIterators ) {
}
TEST_F(OpenMeshProperties, MeshAssignment ) {
mesh_.clear();
mesh_.add_vertex(Mesh::Point());
auto copy = mesh_;
copy.request_vertex_status();
copy.request_vertex_normals();
copy.request_vertex_colors();
copy.request_vertex_texcoords1D();
copy.request_vertex_texcoords2D();
copy.request_vertex_texcoords3D();
copy.request_halfedge_status();
copy.request_halfedge_texcoords1D();
copy.request_halfedge_texcoords2D();
copy.request_halfedge_texcoords3D();
copy.request_edge_status();
copy.request_edge_colors();
copy.request_halfedge_normals();
copy.request_halfedge_colors();
copy.request_face_status();
copy.request_face_normals();
copy.request_face_colors();
copy.request_face_texture_index();
EXPECT_TRUE(copy.has_vertex_status());
EXPECT_TRUE(copy.has_vertex_normals());
EXPECT_TRUE(copy.has_vertex_colors());
EXPECT_TRUE(copy.has_vertex_texcoords1D());
EXPECT_TRUE(copy.has_vertex_texcoords2D());
EXPECT_TRUE(copy.has_vertex_texcoords3D());
EXPECT_TRUE(copy.has_halfedge_status());
EXPECT_TRUE(copy.has_halfedge_texcoords1D());
EXPECT_TRUE(copy.has_halfedge_texcoords2D());
EXPECT_TRUE(copy.has_halfedge_texcoords3D());
EXPECT_TRUE(copy.has_edge_status());
EXPECT_TRUE(copy.has_edge_colors());
EXPECT_TRUE(copy.has_halfedge_normals());
EXPECT_TRUE(copy.has_halfedge_colors());
EXPECT_TRUE(copy.has_face_status());
EXPECT_TRUE(copy.has_face_normals());
EXPECT_TRUE(copy.has_face_colors());
EXPECT_TRUE(copy.has_face_texture_index());
copy.assign(mesh_, true);
EXPECT_FALSE(copy.has_vertex_status());
EXPECT_FALSE(copy.has_vertex_normals());
EXPECT_FALSE(copy.has_vertex_colors());
EXPECT_FALSE(copy.has_vertex_texcoords1D());
EXPECT_FALSE(copy.has_vertex_texcoords2D());
EXPECT_FALSE(copy.has_vertex_texcoords3D());
EXPECT_FALSE(copy.has_halfedge_status());
EXPECT_FALSE(copy.has_halfedge_texcoords1D());
EXPECT_FALSE(copy.has_halfedge_texcoords2D());
EXPECT_FALSE(copy.has_halfedge_texcoords3D());
EXPECT_FALSE(copy.has_edge_status());
EXPECT_FALSE(copy.has_edge_colors());
EXPECT_FALSE(copy.has_halfedge_normals());
EXPECT_FALSE(copy.has_halfedge_colors());
EXPECT_FALSE(copy.has_face_status());
EXPECT_FALSE(copy.has_face_normals());
EXPECT_FALSE(copy.has_face_colors());
EXPECT_FALSE(copy.has_face_texture_index());
copy.request_vertex_status();
copy.request_vertex_normals();
copy.request_vertex_colors();
copy.request_vertex_texcoords1D();
copy.request_vertex_texcoords2D();
copy.request_vertex_texcoords3D();
copy.request_halfedge_status();
copy.request_halfedge_texcoords1D();
copy.request_halfedge_texcoords2D();
copy.request_halfedge_texcoords3D();
copy.request_edge_status();
copy.request_edge_colors();
copy.request_halfedge_normals();
copy.request_halfedge_colors();
copy.request_face_status();
copy.request_face_normals();
copy.request_face_colors();
copy.request_face_texture_index();
EXPECT_TRUE(copy.has_vertex_status()) << "Mesh has no vertex status even though they have been requested";
EXPECT_TRUE(copy.has_vertex_normals()) << "Mesh has no vertex normals even though they have been requested";
EXPECT_TRUE(copy.has_vertex_colors()) << "Mesh has no vertex colors even though they have been requested";
EXPECT_TRUE(copy.has_vertex_texcoords1D()) << "Mesh has no vertex texcoord1D even though they have been requested";
EXPECT_TRUE(copy.has_vertex_texcoords2D()) << "Mesh has no vertex texcoord2D even though they have been requested";
EXPECT_TRUE(copy.has_vertex_texcoords3D()) << "Mesh has no vertex texcoord3D even though they have been requested";
EXPECT_TRUE(copy.has_halfedge_status()) << "Mesh has no halfedge status even though they have been requested";
EXPECT_TRUE(copy.has_halfedge_texcoords1D()) << "Mesh has no halfedge texcoords1D even though they have been requested";
EXPECT_TRUE(copy.has_halfedge_texcoords2D()) << "Mesh has no halfedge texcoords2D even though they have been requested";
EXPECT_TRUE(copy.has_halfedge_texcoords3D()) << "Mesh has no halfedge texcoords3D even though they have been requested";
EXPECT_TRUE(copy.has_edge_status()) << "Mesh has no edge status even though they have been requested";
EXPECT_TRUE(copy.has_edge_colors()) << "Mesh has no edge colors even though they have been requested";
EXPECT_TRUE(copy.has_halfedge_normals()) << "Mesh has no halfedge normals even though they have been requested";
EXPECT_TRUE(copy.has_halfedge_colors()) << "Mesh has no halfedge colors even though they have been requested";
EXPECT_TRUE(copy.has_face_status()) << "Mesh has no face status even though they have been requested";
EXPECT_TRUE(copy.has_face_normals()) << "Mesh has no face normals even though they have been requested";
EXPECT_TRUE(copy.has_face_colors()) << "Mesh has no face colors even though they have been requested";
EXPECT_TRUE(copy.has_face_texture_index()) << "Mesh has no face texture index even though they have been requested";
}
}

View File

@@ -4,6 +4,15 @@
#include <iostream>
//#define ENABLE_PROPERTY_TIMING_OUTPUT
#ifdef ENABLE_PROPERTY_TIMING_OUTPUT
#define N_VERTICES_TIMING 1000000
#define TIMING_OUTPUT(X) X
#else
#define N_VERTICES_TIMING 10
#define TIMING_OUTPUT(X)
#endif
namespace {
class OpenMeshPropertyManager : public OpenMeshBase {
@@ -62,7 +71,7 @@ TEST_F(OpenMeshPropertyManager, set_range_bool) {
{
OpenMesh::PropertyManager<
OpenMesh::VPropHandleT<bool>, Mesh> pm_v_bool(mesh_, "pm_v_bool");
OpenMesh::VPropHandleT<bool>> pm_v_bool(mesh_, "pm_v_bool");
pm_v_bool.set_range(mesh_.vertices_begin(), mesh_.vertices_end(), false);
for (int i = 0; i < 4; ++i)
ASSERT_FALSE(pm_v_bool[vhandle[i]]);
@@ -71,7 +80,7 @@ TEST_F(OpenMeshPropertyManager, set_range_bool) {
ASSERT_TRUE(pm_v_bool[vhandle[i]]);
OpenMesh::PropertyManager<
OpenMesh::EPropHandleT<bool>, Mesh> pm_e_bool(mesh_, "pm_e_bool");
OpenMesh::EPropHandleT<bool>> pm_e_bool(mesh_, "pm_e_bool");
pm_e_bool.set_range(mesh_.edges_begin(), mesh_.edges_end(), false);
for (Mesh::EdgeIter e_it = mesh_.edges_begin(), f_end = mesh_.edges_end();
e_it != f_end; ++e_it)
@@ -82,7 +91,7 @@ TEST_F(OpenMeshPropertyManager, set_range_bool) {
ASSERT_TRUE(pm_e_bool[*e_it]);
OpenMesh::PropertyManager<
OpenMesh::FPropHandleT<bool>, Mesh> pm_f_bool(mesh_, "pm_f_bool");
OpenMesh::FPropHandleT<bool>> pm_f_bool(mesh_, "pm_f_bool");
pm_f_bool.set_range(mesh_.faces_begin(), mesh_.faces_end(), false);
for (Mesh::FaceIter f_it = mesh_.faces_begin(), f_end = mesh_.faces_end();
f_it != f_end; ++f_it)
@@ -93,13 +102,12 @@ TEST_F(OpenMeshPropertyManager, set_range_bool) {
ASSERT_TRUE(pm_f_bool[*f_it]);
}
#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)
/*
* Same thing again, this time with C++11 ranges.
*/
{
OpenMesh::PropertyManager<
OpenMesh::VPropHandleT<bool>, Mesh> pm_v_bool(mesh_, "pm_v_bool2");
OpenMesh::VPropHandleT<bool>> pm_v_bool(mesh_, "pm_v_bool2");
pm_v_bool.set_range(mesh_.vertices(), false);
for (int i = 0; i < 4; ++i)
ASSERT_FALSE(pm_v_bool[vhandle[i]]);
@@ -108,7 +116,7 @@ TEST_F(OpenMeshPropertyManager, set_range_bool) {
ASSERT_TRUE(pm_v_bool[vhandle[i]]);
OpenMesh::PropertyManager<
OpenMesh::EPropHandleT<bool>, Mesh> pm_e_bool(mesh_, "pm_e_bool2");
OpenMesh::EPropHandleT<bool>> pm_e_bool(mesh_, "pm_e_bool2");
pm_e_bool.set_range(mesh_.edges(), false);
for (Mesh::EdgeIter e_it = mesh_.edges_begin(), f_end = mesh_.edges_end();
e_it != f_end; ++e_it)
@@ -119,7 +127,7 @@ TEST_F(OpenMeshPropertyManager, set_range_bool) {
ASSERT_TRUE(pm_e_bool[*e_it]);
OpenMesh::PropertyManager<
OpenMesh::FPropHandleT<bool>, Mesh> pm_f_bool(mesh_, "pm_f_bool2");
OpenMesh::FPropHandleT<bool>> pm_f_bool(mesh_, "pm_f_bool2");
pm_f_bool.set_range(mesh_.faces(), false);
for (Mesh::FaceIter f_it = mesh_.faces_begin(), f_end = mesh_.faces_end();
f_it != f_end; ++f_it)
@@ -129,64 +137,6 @@ TEST_F(OpenMeshPropertyManager, set_range_bool) {
f_it != f_end; ++f_it)
ASSERT_TRUE(pm_f_bool[*f_it]);
}
#endif
}
/*
* ====================================================================
* C++11 Specific Tests
* ====================================================================
*/
#if (defined(_MSC_VER) && (_MSC_VER >= 1800)) || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)
template<typename PropHandle, typename Mesh>
bool has_property(const Mesh& _mesh, const std::string& _name) {
auto dummy_handle = PropHandle{};
return _mesh.get_property_handle(dummy_handle, _name);
}
/*
* Temporary property
*/
TEST_F(OpenMeshPropertyManager, cpp11_temp_property) {
using handle_type = OpenMesh::VPropHandleT<int>;
const auto prop_name = "pm_v_test_property";
ASSERT_FALSE(has_property<handle_type>(mesh_, prop_name));
{
auto vprop = OpenMesh::makePropertyManagerFromNew<handle_type>(mesh_, prop_name);
static_cast<void>(vprop); // Unused variable
ASSERT_TRUE(has_property<handle_type>(mesh_, prop_name));
}
ASSERT_FALSE(has_property<handle_type>(mesh_, prop_name));
}
/*
* Two temporary properties on a mesh using the same name and type. The second
* (inner) one shadows the first (outer) one instead of aliasing.
*/
TEST_F(OpenMeshPropertyManager, cpp11_temp_property_shadowing) {
auto vh = mesh_.add_vertex({0,0,0}); // Dummy vertex to attach properties to
using handle_type = OpenMesh::VPropHandleT<int>;
const auto prop_name = "pm_v_test_property";
auto outer_prop = OpenMesh::makePropertyManagerFromNew<handle_type>(mesh_, prop_name);
outer_prop[vh] = 100;
ASSERT_EQ(100, outer_prop[vh]);
{
// inner_prop uses same type and name as outer_prop
auto inner_prop = OpenMesh::makePropertyManagerFromNew<handle_type>(mesh_, prop_name);
inner_prop[vh] = 200;
ASSERT_EQ(200, inner_prop[vh]);
// End of scope: inner_prop is removed from mesh_
}
// Ensure outer_prop still exists and its data has not been overwritten by inner_prop
ASSERT_TRUE(has_property<handle_type>(mesh_, prop_name));
ASSERT_EQ(100, outer_prop[vh]);
}
/*
@@ -199,45 +149,726 @@ TEST_F(OpenMeshPropertyManager, cpp11_temp_property_shadowing) {
TEST_F(OpenMeshPropertyManager, cpp11_persistent_and_non_owning_properties) {
auto vh = mesh_.add_vertex({0,0,0}); // Dummy vertex to attach properties to
using handle_type = OpenMesh::VPropHandleT<int>;
const auto prop_name = "pm_v_test_property";
ASSERT_FALSE(has_property<handle_type>(mesh_, prop_name));
ASSERT_FALSE((OpenMesh::hasProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name)));
{
auto prop = OpenMesh::makePropertyManagerFromExistingOrNew<handle_type>(mesh_, prop_name);
auto prop = OpenMesh::getOrMakeProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name);
prop[vh] = 100;
// End of scope, property persists
}
ASSERT_TRUE(has_property<handle_type>(mesh_, prop_name));
ASSERT_TRUE((OpenMesh::hasProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name)));
{
// Since a property of the same name and type already exists, this refers to the existing property.
auto prop = OpenMesh::makePropertyManagerFromExistingOrNew<handle_type>(mesh_, prop_name);
auto prop = OpenMesh::getOrMakeProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name);
ASSERT_EQ(100, prop[vh]);
prop[vh] = 200;
// End of scope, property persists
}
ASSERT_TRUE(has_property<handle_type>(mesh_, prop_name));
ASSERT_TRUE((OpenMesh::hasProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name)));
{
// Acquire non-owning handle to the property, knowing it exists
auto prop = OpenMesh::makePropertyManagerFromExisting<handle_type>(mesh_, prop_name);
auto prop = OpenMesh::getProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name);
ASSERT_EQ(200, prop[vh]);
}
ASSERT_TRUE(has_property<handle_type>(mesh_, prop_name));
ASSERT_TRUE((OpenMesh::hasProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name)));
{
// Attempt to acquire non-owning handle for a non-existing property
ASSERT_THROW(OpenMesh::makePropertyManagerFromExisting<handle_type>(mesh_, "wrong_property_name"), std::runtime_error);
auto code_that_throws = [&](){
OpenMesh::getProperty<OpenMesh::VertexHandle, int>(mesh_, "wrong_prop_name");
};
ASSERT_THROW(code_that_throws(), std::runtime_error);
}
ASSERT_TRUE(has_property<handle_type>(mesh_, prop_name));
ASSERT_TRUE((OpenMesh::hasProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name)));
}
#endif
TEST_F(OpenMeshPropertyManager, property_copy_construction) {
for (int i = 0; i < N_VERTICES_TIMING; ++i)
mesh_.add_vertex(Mesh::Point());
// unnamed
{
auto prop1 = OpenMesh::VProp<int>(mesh_);
for (auto vh : mesh_.vertices())
prop1[vh] = vh.idx()*2-13;
auto prop2 = prop1; // prop1 and prop2 should be two different properties with the same content
prop1.set_range(mesh_.vertices(), 0);
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13);
}
// named
{
auto prop1 = OpenMesh::VProp<int>(mesh_, "ids");
for (auto vh : mesh_.vertices())
prop1[vh] = vh.idx()*2-13;
auto prop2 = prop1; // prop1 and prop2 should refere to the same property
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13);
prop1.set_range(mesh_.vertices(), 0);
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0);
}
}
TEST_F(OpenMeshPropertyManager, property_move_construction) {
for (int i = 0; i < N_VERTICES_TIMING; ++i)
mesh_.add_vertex(Mesh::Point());
// unnamed
{
auto prop1 = OpenMesh::VProp<int>(mesh_);
for (auto vh : mesh_.vertices())
prop1[vh] = vh.idx()*2-13;
TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
auto prop2 = std::move(prop1);
TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
TIMING_OUTPUT(std::cout << "move constructing property from temporary took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
EXPECT_FALSE(prop1.isValid()) << "prop1 should have been invalidated";
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13);
}
// named
{
auto prop1 = OpenMesh::VProp<int>(mesh_, "ids");
for (auto vh : mesh_.vertices())
prop1[vh] = vh.idx()*2-13;
TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
auto prop2 = std::move(prop1); // prop1 and prop2 should refere to the same property
TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
TIMING_OUTPUT(std::cout << "move constructing from named took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
EXPECT_TRUE(prop1.isValid()) << "named properties cannot be invalidated";
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "property is not valid anymore";
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "did not copy property correctly";
prop1.set_range(mesh_.vertices(), 0);
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 0);
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0);
}
}
TEST_F(OpenMeshPropertyManager, property_copying_same_mesh) {
for (int i = 0; i < N_VERTICES_TIMING; ++i)
mesh_.add_vertex(Mesh::Point());
// unnamed to unnamed
{
auto prop1 = OpenMesh::VProp<int>(3, mesh_);
auto prop2 = OpenMesh::VProp<int>(0, mesh_);
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 3) << "Property not initialized correctly";
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
for (auto vh : mesh_.vertices())
prop1[vh] = vh.idx()*2-13;
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
prop2 = prop1;
TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
TIMING_OUTPUT(std::cout << "copying property temporary to temporary took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Temporary property got destroyed";
prop1.set_range(mesh_.vertices(), 0);
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 0) << "Property not copied correctly";
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
}
// unnamed to named
{
auto prop1 = OpenMesh::VProp<int>(mesh_);
auto prop2 = OpenMesh::VProp<int>(0, mesh_, "ids");
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
for (auto vh : mesh_.vertices())
prop1[vh] = vh.idx()*2-13;
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
prop2 = prop1;
TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
TIMING_OUTPUT(std::cout << "copying property temporary to named took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Temporary property got destroyed";
prop1.set_range(mesh_.vertices(), 0);
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
auto prop3 = OpenMesh::VProp<int>(mesh_, "ids");
EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], -13) << "property with name 'ids' was not correctly changed";
}
// named to unnamed
{
auto prop1 = OpenMesh::VProp<int>(mesh_, "ids2");
auto prop2 = OpenMesh::VProp<int>(mesh_);
prop2.set_range(mesh_.vertices(), 0);
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
for (auto vh : mesh_.vertices())
prop1[vh] = vh.idx()*2-13;
TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
prop2 = prop1;
TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
TIMING_OUTPUT(std::cout << "copying property named to temporary took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
prop1.set_range(mesh_.vertices(), 0);
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
}
// named to named (different names)
{
auto prop1 = OpenMesh::VProp<int>(mesh_, "ids3");
auto prop2 = OpenMesh::VProp<int>(mesh_, "ids4");
prop2.set_range(mesh_.vertices(), 0);
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
for (auto vh : mesh_.vertices())
prop1[vh] = vh.idx()*2-13;
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
prop2 = prop1;
TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
TIMING_OUTPUT(std::cout << "copying property named to named with different name took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
prop1.set_range(mesh_.vertices(), 0);
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
}
// named to named (same names)
{
auto prop1 = OpenMesh::VProp<int>(mesh_, "ids5");
auto prop2 = OpenMesh::VProp<int>(mesh_, "ids5");
for (auto vh : mesh_.vertices())
prop1[vh] = vh.idx()*2-13;
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
prop2 = prop1; // this should be a no op
TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
TIMING_OUTPUT(std::cout << "copying property named to named with same name took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
prop1.set_range(mesh_.vertices(), 42);
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 42) << "Property not copied correctly";
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 42) << "Property not copied correctly";
auto prop3 = OpenMesh::VProp<int>(mesh_, "ids5");
EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], 42) << "Property not copied correctly";
}
{
auto prop1 = OpenMesh::MProp<int>(mesh_);
*prop1 = 43;
auto prop2 = prop1;
prop2 = prop1;
prop2 = std::move(prop1);
}
}
TEST_F(OpenMeshPropertyManager, property_moving_same_mesh) {
for (int i = 0; i < N_VERTICES_TIMING; ++i)
mesh_.add_vertex(Mesh::Point());
// unnamed to unnamed
{
auto prop1 = OpenMesh::VProp<int>(mesh_);
auto prop2 = OpenMesh::VProp<int>(mesh_);
prop2.set_range(mesh_.vertices(), 0);
for (auto vh : mesh_.vertices())
prop1[vh] = vh.idx()*2-13;
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
prop2 = std::move(prop1); // this should be cheap
TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
TIMING_OUTPUT(std::cout << "moving property temporary to temporary took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
EXPECT_FALSE(prop1.isValid()) << "prop1 not invalidated after moving";
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
}
// unnamed to named
{
auto prop1 = OpenMesh::VProp<int>(mesh_);
auto prop2 = OpenMesh::VProp<int>(mesh_, "ids");
prop2.set_range(mesh_.vertices(), 0);
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
for (auto vh : mesh_.vertices())
prop1[vh] = vh.idx()*2-13;
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
prop2 = std::move(prop1);
TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
TIMING_OUTPUT(std::cout << "moving property temporary to named took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
EXPECT_FALSE(prop1.isValid()) << "prop1 not invalidated after moving";
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
auto prop3 = OpenMesh::VProp<int>(mesh_, "ids");
EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], -13) << "property with name 'ids' was not correctly changed";
}
// named to unnamed
{
auto prop1 = OpenMesh::VProp<int>(mesh_, "ids2");
auto prop2 = OpenMesh::VProp<int>(mesh_);
prop2.set_range(mesh_.vertices(), 0);
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
for (auto vh : mesh_.vertices())
prop1[vh] = vh.idx()*2-13;
TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
prop2 = std::move(prop1); // moving named properties will not invalidate the property and will copy the data
TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
TIMING_OUTPUT(std::cout << "moving property named to temporary took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
EXPECT_TRUE(prop1.isValid()) << "named prop1 should not be invalidated by moving";
prop1.set_range(mesh_.vertices(), 0);
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
}
// named to named (different names)
{
auto prop1 = OpenMesh::VProp<int>(mesh_, "ids3");
auto prop2 = OpenMesh::VProp<int>(mesh_, "ids4");
prop2.set_range(mesh_.vertices(), 0);
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
for (auto vh : mesh_.vertices())
prop1[vh] = vh.idx()*2-13;
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
prop2 = std::move(prop1); // moving named properties will not invalidate the property and will copy the data
TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
TIMING_OUTPUT(std::cout << "moving property named to named with different name took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
EXPECT_TRUE(prop1.isValid()) << "named prop1 should not be invalidated by moving";
prop1.set_range(mesh_.vertices(), 0);
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
}
// named to named (same names)
{
auto prop1 = OpenMesh::VProp<int>(mesh_, "ids5");
auto prop2 = OpenMesh::VProp<int>(mesh_, "ids5");
for (auto vh : mesh_.vertices())
prop1[vh] = vh.idx()*2-13;
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
prop2 = std::move(prop1); // this should be a no op
TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
TIMING_OUTPUT(std::cout << "moving property named to named with same name took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
EXPECT_TRUE(prop1.isValid()) << "named prop1 should not be invalidated by moving";
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
prop1.set_range(mesh_.vertices(), 0);
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 0) << "Property not copied correctly";
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not copied correctly";
auto prop3 = OpenMesh::VProp<int>(mesh_, "ids5");
EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], 0) << "Property not copied correctly";
}
}
TEST_F(OpenMeshPropertyManager, property_copying_different_mesh) {
for (int i = 0; i < N_VERTICES_TIMING; ++i)
mesh_.add_vertex(Mesh::Point());
auto copy = mesh_;
for (int i = 0; i < 10; ++i)
copy.add_vertex(Mesh::Point());
// unnamed to unnamed
{
auto prop1 = OpenMesh::VProp<int>(3, mesh_);
auto prop2 = OpenMesh::VProp<int>(0, copy);
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 3) << "Property not initialized correctly";
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
for (auto vh : mesh_.vertices())
prop1[vh] = vh.idx()*2-13;
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
prop2 = prop1;
TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
TIMING_OUTPUT(std::cout << "copying property temporary to temporary took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Temporary property got destroyed";
prop1.set_range(mesh_.vertices(), 0);
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 0) << "Property not copied correctly";
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
EXPECT_NO_FATAL_FAILURE(prop2[OpenMesh::VertexHandle(static_cast<int>(copy.n_vertices())-1)]) << "Property not correctly resized";
}
// unnamed to named
{
auto prop1 = OpenMesh::VProp<int>(mesh_);
auto prop2 = OpenMesh::VProp<int>(0, copy, "ids");
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
for (auto vh : mesh_.vertices())
prop1[vh] = vh.idx()*2-13;
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
prop2 = prop1;
TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
TIMING_OUTPUT(std::cout << "copying property temporary to named took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Temporary property got destroyed";
prop1.set_range(mesh_.vertices(), 0);
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
auto prop3 = OpenMesh::VProp<int>(copy, "ids");
EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], -13) << "property with name 'ids' was not correctly changed";
}
// named to unnamed
{
auto prop1 = OpenMesh::VProp<int>(mesh_, "ids2");
auto prop2 = OpenMesh::VProp<int>(copy);
prop2.set_range(mesh_.vertices(), 0);
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
for (auto vh : mesh_.vertices())
prop1[vh] = vh.idx()*2-13;
TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
prop2 = prop1;
TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
TIMING_OUTPUT(std::cout << "copying property named to temporary took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
prop1.set_range(mesh_.vertices(), 0);
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
}
// named to named (different names)
{
auto prop1 = OpenMesh::VProp<int>(mesh_, "ids3");
auto prop2 = OpenMesh::VProp<int>(copy, "ids4");
prop2.set_range(mesh_.vertices(), 0);
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
for (auto vh : mesh_.vertices())
prop1[vh] = vh.idx()*2-13;
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
prop2 = prop1;
TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
TIMING_OUTPUT(std::cout << "copying property named to named with different name took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
prop1.set_range(mesh_.vertices(), 0);
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
}
// named to named (same names)
{
auto prop1 = OpenMesh::VProp<int>(mesh_, "ids5");
auto prop2 = OpenMesh::VProp<int>(copy, "ids5");
for (auto vh : mesh_.vertices())
prop1[vh] = vh.idx()*2-13;
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
prop2 = prop1; // this should be a no op
TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
TIMING_OUTPUT(std::cout << "copying property named to named with same name took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
prop1.set_range(mesh_.vertices(), 42);
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 42) << "Property not copied correctly";
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
auto prop3 = OpenMesh::VProp<int>(mesh_, "ids5");
EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], 42) << "Property not copied correctly";
auto prop4 = OpenMesh::VProp<int>(copy, "ids5");
EXPECT_EQ(prop4[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
}
}
TEST_F(OpenMeshPropertyManager, property_moving_different_mesh) {
for (int i = 0; i < N_VERTICES_TIMING; ++i)
mesh_.add_vertex(Mesh::Point());
auto copy = mesh_;
for (int i = 0; i < 10; ++i)
copy.add_vertex(Mesh::Point());
// unnamed to unnamed
{
auto prop1 = OpenMesh::VProp<int>(mesh_);
auto prop2 = OpenMesh::VProp<int>(copy);
prop2.set_range(mesh_.vertices(), 0);
for (auto vh : mesh_.vertices())
prop1[vh] = vh.idx()*2-13;
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
prop2 = std::move(prop1); // this should be cheap
TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
TIMING_OUTPUT(std::cout << "moving property temporary to temporary took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
EXPECT_FALSE(prop1.isValid()) << "prop1 not invalidated after moving";
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
EXPECT_NO_FATAL_FAILURE(prop2[OpenMesh::VertexHandle(static_cast<int>(copy.n_vertices())-1)]) << "Property not correctly resized";
}
// unnamed to named
{
auto prop1 = OpenMesh::VProp<int>(mesh_);
auto prop2 = OpenMesh::VProp<int>(copy, "ids");
prop2.set_range(mesh_.vertices(), 0);
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
for (auto vh : mesh_.vertices())
prop1[vh] = vh.idx()*2-13;
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
prop2 = std::move(prop1);
TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
TIMING_OUTPUT(std::cout << "moving property temporary to named took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
EXPECT_FALSE(prop1.isValid()) << "prop1 not invalidated after moving";
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
auto prop3 = OpenMesh::VProp<int>(copy, "ids");
EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], -13) << "property with name 'ids' was not correctly changed";
}
// named to unnamed
{
auto prop1 = OpenMesh::VProp<int>(mesh_, "ids2");
auto prop2 = OpenMesh::VProp<int>(copy);
prop2.set_range(mesh_.vertices(), 0);
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
for (auto vh : mesh_.vertices())
prop1[vh] = vh.idx()*2-13;
TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
prop2 = std::move(prop1); // moving named properties will not invalidate the property and will copy the data
TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
TIMING_OUTPUT(std::cout << "moving property named to temporary took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
EXPECT_TRUE(prop1.isValid()) << "named prop1 should not be invalidated by moving";
prop1.set_range(mesh_.vertices(), 0);
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
}
// named to named (different names)
{
auto prop1 = OpenMesh::VProp<int>(mesh_, "ids3");
auto prop2 = OpenMesh::VProp<int>(copy, "ids4");
prop2.set_range(mesh_.vertices(), 0);
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
for (auto vh : mesh_.vertices())
prop1[vh] = vh.idx()*2-13;
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
prop2 = std::move(prop1); // moving named properties will not invalidate the property and will copy the data
TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
TIMING_OUTPUT(std::cout << "moving property named to named with different name took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
EXPECT_TRUE(prop1.isValid()) << "named prop1 should not be invalidated by moving";
prop1.set_range(mesh_.vertices(), 0);
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
}
// named to named (same names)
{
auto prop1 = OpenMesh::VProp<int>(mesh_, "ids5");
auto prop2 = OpenMesh::VProp<int>(copy, "ids5");
auto prop6 = OpenMesh::Prop<OpenMesh::VertexHandle, int>(mesh_);
prop6 = prop1;
for (auto vh : mesh_.vertices())
prop1[vh] = vh.idx()*2-13;
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
prop2 = std::move(prop1); // should copy
TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
TIMING_OUTPUT(std::cout << "moving property named to named with same name took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
EXPECT_TRUE(prop1.isValid()) << "named prop1 should not be invalidated by moving";
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
prop1.set_range(mesh_.vertices(), 42);
EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 42) << "Property not copied correctly";
EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
auto prop3 = OpenMesh::VProp<int>(mesh_, "ids5");
EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], 42) << "Property not copied correctly";
auto prop4 = OpenMesh::VProp<int>(copy, "ids5");
EXPECT_EQ(prop4[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
}
}
TEST_F(OpenMeshPropertyManager, temporary_property_on_const_mesh) {
const auto& const_ref = mesh_;
auto cog = OpenMesh::FProp<Mesh::Point>(const_ref);
auto points = OpenMesh::getPointsProperty(const_ref);
for (auto fh : const_ref.faces())
cog(fh) = fh.vertices().avg(points);
auto cog_copy = cog;
for (auto fh : const_ref.faces())
{
EXPECT_NE(&cog(fh), &cog_copy(fh)) << "Both properties point to the same memory";
EXPECT_EQ(cog(fh), cog_copy(fh)) << "Property not copied correctly";
}
auto description = OpenMesh::MProp<std::string>(const_ref);
description() = "Cool Const Mesh";
std::cout << description(OpenMesh::MeshHandle(33)) << std::endl;
}
OpenMesh::VProp<int> get_id_prop(const OpenMesh::PolyConnectivity& mesh)
{
TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
auto id_prop = OpenMesh::VProp<int>(mesh);
for (auto vh : mesh.vertices())
id_prop(vh) = vh.idx();
TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
TIMING_OUTPUT(std::cout << "Time spend in function: " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
return id_prop;
}
TEST_F(OpenMeshPropertyManager, return_property_from_function) {
for (int i = 0; i < N_VERTICES_TIMING; ++i)
mesh_.add_vertex(Mesh::Point());
TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
auto id_p = get_id_prop(mesh_);
TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
TIMING_OUTPUT(std::cout << "Time spend around function " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
for (auto vh : mesh_.vertices())
{
EXPECT_EQ(id_p(vh), vh.idx()) << "Property not returned correctly" << std::endl;
}
}
}

View File

@@ -325,9 +325,16 @@ TEST_F(OpenMeshReadWriteOBJ, LoadObjWithMaterial) {
EXPECT_TRUE(fh.is_valid()) << "fh should be valid";
#ifdef TEST_DOUBLE_TRAITS
EXPECT_FLOAT_EQ(128/255.0, mesh_.color(fh)[0] ) << "Wrong vertex color at vertex 0 component 0";
EXPECT_FLOAT_EQ(128/255.0, mesh_.color(fh)[1] ) << "Wrong vertex color at vertex 0 component 1";
EXPECT_FLOAT_EQ(128/255.0, mesh_.color(fh)[2] ) << "Wrong vertex color at vertex 0 component 2";
EXPECT_FLOAT_EQ(1.0, mesh_.color(fh)[3] ) << "Wrong vertex color at vertex 0 component 3";
#else
EXPECT_EQ(128, mesh_.color(fh)[0] ) << "Wrong vertex color at vertex 0 component 0";
EXPECT_EQ(128, mesh_.color(fh)[1] ) << "Wrong vertex color at vertex 0 component 1";
EXPECT_EQ(128, mesh_.color(fh)[2] ) << "Wrong vertex color at vertex 0 component 2";
#endif
mesh_.release_face_colors();
}
@@ -385,6 +392,24 @@ TEST_F(OpenMeshReadWriteOBJ, LoadSimpleOBJWithVertexColorsAfterVertices) {
EXPECT_EQ(18u , mesh_.n_edges()) << "The number of loaded edges is not correct!";
EXPECT_EQ(12u , mesh_.n_faces()) << "The number of loaded faces is not correct!";
#ifdef TEST_DOUBLE_TRAITS
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(0))[0] ) << "Wrong vertex color at vertex 0 component 0";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(0))[1] ) << "Wrong vertex color at vertex 0 component 1";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(0))[2] ) << "Wrong vertex color at vertex 0 component 2";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(3))[0] ) << "Wrong vertex color at vertex 3 component 0";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(3))[1] ) << "Wrong vertex color at vertex 3 component 1";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(3))[2] ) << "Wrong vertex color at vertex 3 component 2";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(4))[0] ) << "Wrong vertex color at vertex 4 component 0";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(4))[1] ) << "Wrong vertex color at vertex 4 component 1";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(4))[2] ) << "Wrong vertex color at vertex 4 component 2";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(7))[0] ) << "Wrong vertex color at vertex 7 component 0";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(7))[1] ) << "Wrong vertex color at vertex 7 component 1";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(7))[2] ) << "Wrong vertex color at vertex 7 component 2";
#else
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(0))[0] ) << "Wrong vertex color at vertex 0 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(0))[1] ) << "Wrong vertex color at vertex 0 component 1";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(0))[2] ) << "Wrong vertex color at vertex 0 component 2";
@@ -400,6 +425,7 @@ TEST_F(OpenMeshReadWriteOBJ, LoadSimpleOBJWithVertexColorsAfterVertices) {
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(7))[0] ) << "Wrong vertex color at vertex 7 component 0";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(7))[1] ) << "Wrong vertex color at vertex 7 component 1";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(7))[2] ) << "Wrong vertex color at vertex 7 component 2";
#endif
mesh_.release_vertex_colors();
}
@@ -424,6 +450,23 @@ TEST_F(OpenMeshReadWriteOBJ, LoadSimpleOBJWithVertexColorsAsVCLines) {
EXPECT_EQ(18u , mesh_.n_edges()) << "The number of loaded edges is not correct!";
EXPECT_EQ(12u , mesh_.n_faces()) << "The number of loaded faces is not correct!";
#ifdef TEST_DOUBLE_TRAITS
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(0))[0] ) << "Wrong vertex color at vertex 0 component 0";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(0))[1] ) << "Wrong vertex color at vertex 0 component 1";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(0))[2] ) << "Wrong vertex color at vertex 0 component 2";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(3))[0] ) << "Wrong vertex color at vertex 3 component 0";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(3))[1] ) << "Wrong vertex color at vertex 3 component 1";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(3))[2] ) << "Wrong vertex color at vertex 3 component 2";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(4))[0] ) << "Wrong vertex color at vertex 4 component 0";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(4))[1] ) << "Wrong vertex color at vertex 4 component 1";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(4))[2] ) << "Wrong vertex color at vertex 4 component 2";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(7))[0] ) << "Wrong vertex color at vertex 7 component 0";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(7))[1] ) << "Wrong vertex color at vertex 7 component 1";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(7))[2] ) << "Wrong vertex color at vertex 7 component 2";
#else
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(0))[0] ) << "Wrong vertex color at vertex 0 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(0))[1] ) << "Wrong vertex color at vertex 0 component 1";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(0))[2] ) << "Wrong vertex color at vertex 0 component 2";
@@ -439,6 +482,7 @@ TEST_F(OpenMeshReadWriteOBJ, LoadSimpleOBJWithVertexColorsAsVCLines) {
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(7))[0] ) << "Wrong vertex color at vertex 7 component 0";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(7))[1] ) << "Wrong vertex color at vertex 7 component 1";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(7))[2] ) << "Wrong vertex color at vertex 7 component 2";
#endif
mesh_.release_vertex_colors();
@@ -499,4 +543,88 @@ TEST_F(OpenMeshReadWriteOBJ, ReadWriteReadSimpleOBJ) {
EXPECT_EQ(1, mesh2.normal(mesh2.vertex_handle(7))[2] ) << "Wrong vertex normal at vertex 7 component 2";
}
TEST_F(OpenMeshReadWriteOBJ, FaceTexCoordTest) {
mesh_.clear();
mesh_.request_vertex_normals();
mesh_.request_halfedge_texcoords2D();
// Add some vertices
Mesh::VertexHandle vhandle[5];
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));
// Add one face
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::FaceHandle fh = mesh_.add_face(face_vhandles);
// 1 --- 2
// | /
// | /
// | /
// 0
mesh_.set_normal(vhandle[0] , Mesh::Normal(1,0,0));
mesh_.set_normal(vhandle[1] , Mesh::Normal(0,1,0));
mesh_.set_normal(vhandle[2] , Mesh::Normal(0,0,1));
float u = 8.0f;
for ( auto he : mesh_.halfedges() ) {
mesh_.set_texcoord2D(he,Mesh::TexCoord2D(u,u));
u += 1.0;
}
u = 0.0f;
for ( auto he : mesh_.fh_range(fh) )
{
mesh_.set_texcoord2D(he,Mesh::TexCoord2D(u,u));
u += 1.0f;
}
OpenMesh::IO::Options wopt;
wopt += OpenMesh::IO::Options::VertexNormal;
wopt += OpenMesh::IO::Options::FaceTexCoord;
bool ok = OpenMesh::IO::write_mesh(mesh_, "OpenMeshReadWriteOBJ_FaceTexCoordTest.obj", wopt);
EXPECT_TRUE(ok) << "Unable to write OpenMeshReadWriteOBJ_FaceTexCoordTest.obj";
mesh_.clear();
OpenMesh::IO::Options ropt;
ropt += OpenMesh::IO::Options::FaceTexCoord;
mesh_.request_vertex_normals();
mesh_.request_face_normals();
mesh_.request_halfedge_texcoords2D();
ok = OpenMesh::IO::read_mesh(mesh_, "OpenMeshReadWriteOBJ_FaceTexCoordTest.obj", ropt);
EXPECT_TRUE(ok) << "Unable to read back OpenMeshReadWriteOBJ_FaceTexCoordTest.obj";
}
}

View File

@@ -60,8 +60,13 @@ TEST_F(OpenMeshReadWriteOFF, WriteAndReadVertexColorsToAndFromOFFFile) {
mesh_.add_vertex( Mesh::Point(0,1,1) );
mesh_.add_vertex( Mesh::Point(1,0,1) );
#ifdef TEST_DOUBLE_TRAITS
// using the default color type Vec4f from DefaultTraitsDouble in Traits.hh
Mesh::Color testColor(255/255.0, 128/255.0, 64/255.0, 1.0);
#else
// using the default color type Vec3uc from DefaultTraits in Traits.hh
Mesh::Color testColor(255, 128, 64);
#endif
// setting colors (different from black)
for (Mesh::VertexIter vit = mesh_.vertices_begin(), vitend = mesh_.vertices_end(); vit != vitend; ++vit)
@@ -71,7 +76,10 @@ TEST_F(OpenMeshReadWriteOFF, WriteAndReadVertexColorsToAndFromOFFFile) {
int count = 0;
for (Mesh::VertexIter vit = mesh_.vertices_begin(), vitend = mesh_.vertices_end(); vit != vitend; ++vit) {
Mesh::Color color = mesh_.color(*vit);
if ( color[0] != testColor[0] || color[1] != testColor[1] || color[2] != testColor[2] )
bool wrong_color = false;
for (size_t i = 0; i < color.size(); ++i)
wrong_color = wrong_color || (color[i] != testColor[i]);
if (wrong_color)
++ count;
}
@@ -87,7 +95,10 @@ TEST_F(OpenMeshReadWriteOFF, WriteAndReadVertexColorsToAndFromOFFFile) {
count = 0;
for (Mesh::VertexIter vit = mesh_.vertices_begin(), vitend = mesh_.vertices_end(); vit != vitend; ++vit) {
Mesh::Color color = mesh_.color(*vit);
if ( color[0] != testColor[0] || color[1] != testColor[1] || color[2] != testColor[2] )
bool wrong_color = false;
for (size_t i = 0; i < color.size(); ++i)
wrong_color = wrong_color || (color[i] != testColor[i]);
if (wrong_color)
++ count;
}
@@ -123,21 +134,39 @@ TEST_F(OpenMeshReadWriteOFF, WriteAndReadFloatVertexColorsToAndFromOFFFile) {
EXPECT_EQ(18u , mesh_.n_edges()) << "The number of loaded edges is not correct!";
EXPECT_EQ(12u , mesh_.n_faces()) << "The number of loaded faces is not correct!";
#ifdef TEST_DOUBLE_TRAITS
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(0))[0] ) << "Wrong vertex color at vertex 0 component 0";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(0))[1] ) << "Wrong vertex color at vertex 0 component 1";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(0))[2] ) << "Wrong vertex color at vertex 0 component 2";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(3))[0] ) << "Wrong vertex color at vertex 3 component 0";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(3))[1] ) << "Wrong vertex color at vertex 3 component 1";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(3))[2] ) << "Wrong vertex color at vertex 3 component 2";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(4))[0] ) << "Wrong vertex color at vertex 4 component 0";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(4))[1] ) << "Wrong vertex color at vertex 4 component 1";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(4))[2] ) << "Wrong vertex color at vertex 4 component 2";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(7))[0] ) << "Wrong vertex color at vertex 7 component 0";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(7))[1] ) << "Wrong vertex color at vertex 7 component 1";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(7))[2] ) << "Wrong vertex color at vertex 7 component 2";
#else
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(0))[0] ) << "Wrong vertex color at vertex 0 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(0))[1] ) << "Wrong vertex color at vertex 0 component 1";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(0))[2] ) << "Wrong vertex color at vertex 0 component 2";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(0))[2] ) << "Wrong vertex color at vertex 0 component 2";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(3))[0] ) << "Wrong vertex color at vertex 3 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(3))[1] ) << "Wrong vertex color at vertex 3 component 1";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(3))[1] ) << "Wrong vertex color at vertex 3 component 1";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(3))[2] ) << "Wrong vertex color at vertex 3 component 2";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(4))[0] ) << "Wrong vertex color at vertex 4 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(4))[0] ) << "Wrong vertex color at vertex 4 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(4))[1] ) << "Wrong vertex color at vertex 4 component 1";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(4))[2] ) << "Wrong vertex color at vertex 4 component 2";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(4))[2] ) << "Wrong vertex color at vertex 4 component 2";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(7))[0] ) << "Wrong vertex color at vertex 7 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(7))[1] ) << "Wrong vertex color at vertex 7 component 1";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(7))[0] ) << "Wrong vertex color at vertex 7 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(7))[1] ) << "Wrong vertex color at vertex 7 component 1";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(7))[2] ) << "Wrong vertex color at vertex 7 component 2";
#endif
EXPECT_FALSE(opt.vertex_has_normal()) << "Wrong user opt are returned!";
EXPECT_FALSE(opt.vertex_has_texcoord()) << "Wrong user opt are returned!";
@@ -179,21 +208,39 @@ TEST_F(OpenMeshReadWriteOFF, WriteAndReadBinaryFloatVertexColorsToAndFromOFFFile
EXPECT_EQ(18u , mesh_.n_edges()) << "The number of loaded edges is not correct!";
EXPECT_EQ(12u , mesh_.n_faces()) << "The number of loaded faces is not correct!";
#ifdef TEST_DOUBLE_TRAITS
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(0))[0] ) << "Wrong vertex color at vertex 0 component 0";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(0))[1] ) << "Wrong vertex color at vertex 0 component 1";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(0))[2] ) << "Wrong vertex color at vertex 0 component 2";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(3))[0] ) << "Wrong vertex color at vertex 3 component 0";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(3))[1] ) << "Wrong vertex color at vertex 3 component 1";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(3))[2] ) << "Wrong vertex color at vertex 3 component 2";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(4))[0] ) << "Wrong vertex color at vertex 4 component 0";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(4))[1] ) << "Wrong vertex color at vertex 4 component 1";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(4))[2] ) << "Wrong vertex color at vertex 4 component 2";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(7))[0] ) << "Wrong vertex color at vertex 7 component 0";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(7))[1] ) << "Wrong vertex color at vertex 7 component 1";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(7))[2] ) << "Wrong vertex color at vertex 7 component 2";
#else
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(0))[0] ) << "Wrong vertex color at vertex 0 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(0))[1] ) << "Wrong vertex color at vertex 0 component 1";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(0))[2] ) << "Wrong vertex color at vertex 0 component 2";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(0))[2] ) << "Wrong vertex color at vertex 0 component 2";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(3))[0] ) << "Wrong vertex color at vertex 3 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(3))[1] ) << "Wrong vertex color at vertex 3 component 1";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(3))[1] ) << "Wrong vertex color at vertex 3 component 1";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(3))[2] ) << "Wrong vertex color at vertex 3 component 2";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(4))[0] ) << "Wrong vertex color at vertex 4 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(4))[0] ) << "Wrong vertex color at vertex 4 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(4))[1] ) << "Wrong vertex color at vertex 4 component 1";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(4))[2] ) << "Wrong vertex color at vertex 4 component 2";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(4))[2] ) << "Wrong vertex color at vertex 4 component 2";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(7))[0] ) << "Wrong vertex color at vertex 7 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(7))[1] ) << "Wrong vertex color at vertex 7 component 1";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(7))[0] ) << "Wrong vertex color at vertex 7 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(7))[1] ) << "Wrong vertex color at vertex 7 component 1";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(7))[2] ) << "Wrong vertex color at vertex 7 component 2";
#endif
EXPECT_FALSE(opt.vertex_has_normal()) << "Wrong user opt are returned!";
EXPECT_FALSE(opt.vertex_has_texcoord()) << "Wrong user opt are returned!";

View File

@@ -72,7 +72,7 @@ TEST_F(OpenMeshReadWriteOM, LoadSimpleOMWithTexCoords) {
bool ok = OpenMesh::IO::read_mesh(mesh_, "cube-minimal-texCoords.om",options);
EXPECT_TRUE(ok) << "Unable to load cube-minimal-texCoords.om";
ASSERT_TRUE(ok) << "Unable to load cube-minimal-texCoords.om";
EXPECT_EQ(8u , mesh_.n_vertices()) << "The number of loaded vertices is not correct!";
EXPECT_EQ(18u , mesh_.n_edges()) << "The number of loaded edges is not correct!";
@@ -118,21 +118,39 @@ TEST_F(OpenMeshReadWriteOM, LoadSimpleOMWithVertexColors) {
EXPECT_EQ(18u , mesh_.n_edges()) << "The number of loaded edges is not correct!";
EXPECT_EQ(12u , mesh_.n_faces()) << "The number of loaded faces is not correct!";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(0))[0] ) << "Wrong vertex color at vertex 0 component 0";
#ifdef TEST_DOUBLE_TRAITS
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(0))[0] ) << "Wrong vertex color at vertex 0 component 0";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(0))[1] ) << "Wrong vertex color at vertex 0 component 1";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(0))[2] ) << "Wrong vertex color at vertex 0 component 2";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(3))[0] ) << "Wrong vertex color at vertex 3 component 0";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(3))[1] ) << "Wrong vertex color at vertex 3 component 1";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(3))[2] ) << "Wrong vertex color at vertex 3 component 2";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(4))[0] ) << "Wrong vertex color at vertex 4 component 0";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(4))[1] ) << "Wrong vertex color at vertex 4 component 1";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(4))[2] ) << "Wrong vertex color at vertex 4 component 2";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(7))[0] ) << "Wrong vertex color at vertex 7 component 0";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(7))[1] ) << "Wrong vertex color at vertex 7 component 1";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(7))[2] ) << "Wrong vertex color at vertex 7 component 2";
#else
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(0))[0] ) << "Wrong vertex color at vertex 0 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(0))[1] ) << "Wrong vertex color at vertex 0 component 1";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(0))[2] ) << "Wrong vertex color at vertex 0 component 2";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(3))[0] ) << "Wrong vertex color at vertex 3 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(3))[1] ) << "Wrong vertex color at vertex 3 component 1";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(3))[2] ) << "Wrong vertex color at vertex 3 component 2";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(3))[0] ) << "Wrong vertex color at vertex 3 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(3))[1] ) << "Wrong vertex color at vertex 3 component 1";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(3))[2] ) << "Wrong vertex color at vertex 3 component 2";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(4))[0] ) << "Wrong vertex color at vertex 4 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(4))[0] ) << "Wrong vertex color at vertex 4 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(4))[1] ) << "Wrong vertex color at vertex 4 component 1";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(4))[2] ) << "Wrong vertex color at vertex 4 component 2";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(4))[2] ) << "Wrong vertex color at vertex 4 component 2";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(7))[0] ) << "Wrong vertex color at vertex 7 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(7))[1] ) << "Wrong vertex color at vertex 7 component 1";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(7))[0] ) << "Wrong vertex color at vertex 7 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(7))[1] ) << "Wrong vertex color at vertex 7 component 1";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(7))[2] ) << "Wrong vertex color at vertex 7 component 2";
#endif
EXPECT_FALSE(options.vertex_has_normal()) << "Wrong user options are returned!";
EXPECT_FALSE(options.vertex_has_texcoord()) << "Wrong user options are returned!";
@@ -203,9 +221,15 @@ TEST_F(OpenMeshReadWriteOM, WriteTriangleVertexIntegerColor) {
Mesh::VertexHandle v3 = mesh.add_vertex(Mesh::Point(0.0,0.0,1.0));
mesh.add_face(v1,v2,v3);
#ifdef TEST_DOUBLE_TRAITS
Mesh::Color c1 = Mesh::Color(0,0,123/255.0,1.0),
c2 = Mesh::Color(21/255.0,0,0,1.0),
c3 = Mesh::Color(0,222/255.0,0,1.0);
#else
Mesh::Color c1 = Mesh::Color(0,0,123),
c2 = Mesh::Color(21,0,0),
c3 = Mesh::Color(0,222,0);
#endif
mesh.set_color(v1,c1);
mesh.set_color(v2,c2);
@@ -234,9 +258,20 @@ TEST_F(OpenMeshReadWriteOM, WriteTriangleVertexIntegerColor) {
EXPECT_EQ(Mesh::Point(0.0,1.0,0.0) , cmpMesh.point(v2)) << "Wrong coordinates at vertex 1";
EXPECT_EQ(Mesh::Point(0.0,0.0,1.0) , cmpMesh.point(v3)) << "Wrong coordinates at vertex 2";
#ifdef TEST_DOUBLE_TRAITS
// OM file format does not support writing colors as float. They are stored as unsigned character.
// Thus, the values will not be exactly equal.
for (size_t i = 0; i < c1.size(); ++i)
{
EXPECT_FLOAT_EQ(c1[i] , cmpMesh.color(v1)[i]) << "Wrong colors at coordinate " << i << " of vertex 0";
EXPECT_FLOAT_EQ(c2[i] , cmpMesh.color(v2)[i]) << "Wrong colors at coordinate " << i << " of vertex 1";
EXPECT_FLOAT_EQ(c3[i] , cmpMesh.color(v3)[i]) << "Wrong colors at coordinate " << i << " of vertex 2";
}
#else
EXPECT_EQ(c1 , cmpMesh.color(v1)) << "Wrong colors at vertex 0";
EXPECT_EQ(c2 , cmpMesh.color(v2)) << "Wrong colors at vertex 1";
EXPECT_EQ(c3 , cmpMesh.color(v3)) << "Wrong colors at vertex 2";
#endif
//clean up
cmpMesh.release_vertex_colors();
@@ -464,11 +499,11 @@ TEST_F(OpenMeshReadWriteOM, WriteTriangleEdgeIntProperty) {
Mesh::EdgeHandle e2 = Mesh::EdgeHandle(1);
Mesh::EdgeHandle e3 = Mesh::EdgeHandle(2);
int va1ue1 = 10,
int value1 = 10,
value2 = 21,
value3 = 32;
mesh.property(prop,e1) = va1ue1;
mesh.property(prop,e1) = value1;
mesh.property(prop,e2) = value2;
mesh.property(prop,e3) = value3;
@@ -494,7 +529,7 @@ TEST_F(OpenMeshReadWriteOM, WriteTriangleEdgeIntProperty) {
EXPECT_EQ(Mesh::Point(0.0,1.0,0.0) , cmpMesh.point(v2)) << "Wrong coordinates at vertex 1";
EXPECT_EQ(Mesh::Point(0.0,0.0,1.0) , cmpMesh.point(v3)) << "Wrong coordinates at vertex 2";
EXPECT_EQ(va1ue1 , cmpMesh.property(prop,e1)) << "Wrong property at edge 0";
EXPECT_EQ(value1 , cmpMesh.property(prop,e1)) << "Wrong property at edge 0";
EXPECT_EQ(value2 , cmpMesh.property(prop,e2)) << "Wrong property at edge 1";
EXPECT_EQ(value3 , cmpMesh.property(prop,e3)) << "Wrong property at edge 2";
@@ -503,6 +538,308 @@ TEST_F(OpenMeshReadWriteOM, WriteTriangleEdgeIntProperty) {
}
/*
* Save and load simple mesh with custom property
*/
TEST_F(OpenMeshReadWriteOM, WriteSplitTriangleEdgeIntProperty) {
Mesh mesh;
const std::string propName = "EIProp";
const std::string filename = std::string("triangle-minimal-")+propName+".om";
// generate data
Mesh::VertexHandle v1 = mesh.add_vertex(Mesh::Point(1.0,0.0,0.0));
Mesh::VertexHandle v2 = mesh.add_vertex(Mesh::Point(0.0,1.0,0.0));
Mesh::VertexHandle v3 = mesh.add_vertex(Mesh::Point(0.0,0.0,1.0));
auto fh0 = mesh.add_face(v1,v2,v3);
auto c = mesh.calc_face_centroid(fh0);
Mesh::VertexHandle v4 = mesh.add_vertex(c);
mesh.split(fh0, v4);
OpenMesh::EPropHandleT<int> prop;
mesh.add_property(prop,propName);
mesh.property(prop).set_persistent(true);
Mesh::EdgeHandle e1 = Mesh::EdgeHandle(0);
Mesh::EdgeHandle e2 = Mesh::EdgeHandle(1);
Mesh::EdgeHandle e3 = Mesh::EdgeHandle(2);
Mesh::EdgeHandle e4 = Mesh::EdgeHandle(3);
Mesh::EdgeHandle e5 = Mesh::EdgeHandle(4);
Mesh::EdgeHandle e6 = Mesh::EdgeHandle(5);
int value1 = 10,
value2 = 21,
value3 = 32,
value4 = 43,
value5 = 54,
value6 = 65;
mesh.property(prop,e1) = value1;
mesh.property(prop,e2) = value2;
mesh.property(prop,e3) = value3;
mesh.property(prop,e4) = value4;
mesh.property(prop,e5) = value5;
mesh.property(prop,e6) = value6;
// save
OpenMesh::IO::Options options;
bool ok = OpenMesh::IO::write_mesh(mesh,filename);
EXPECT_TRUE(ok) << "Unable to write "<<filename;
// load
Mesh cmpMesh;
cmpMesh.add_property(prop,propName);
cmpMesh.property(prop).set_persistent(true);
ok = OpenMesh::IO::read_mesh(cmpMesh,filename);
EXPECT_TRUE(ok) << "Unable to read "<<filename;
// compare
EXPECT_EQ(4u , cmpMesh.n_vertices()) << "The number of loaded vertices is not correct!";
EXPECT_EQ(6u , cmpMesh.n_edges()) << "The number of loaded edges is not correct!";
EXPECT_EQ(3u , cmpMesh.n_faces()) << "The number of loaded faces is not correct!";
EXPECT_EQ(Mesh::Point(1.0,0.0,0.0) , cmpMesh.point(v1)) << "Wrong coordinates at vertex 0";
EXPECT_EQ(Mesh::Point(0.0,1.0,0.0) , cmpMesh.point(v2)) << "Wrong coordinates at vertex 1";
EXPECT_EQ(Mesh::Point(0.0,0.0,1.0) , cmpMesh.point(v3)) << "Wrong coordinates at vertex 2";
#ifdef TEST_DOUBLE_TRAITS
// TODO: should it be possible to read and write double precision exactly?
EXPECT_FLOAT_EQ(c[0] , cmpMesh.point(v4)[0]) << "Wrong coordinate 0 at vertex 4";
EXPECT_FLOAT_EQ(c[1] , cmpMesh.point(v4)[1]) << "Wrong coordinate 1 at vertex 4";
EXPECT_FLOAT_EQ(c[2] , cmpMesh.point(v4)[2]) << "Wrong coordinate 2 at vertex 4";
#else
EXPECT_EQ(c , cmpMesh.point(v4)) << "Wrong coordinates at vertex 4";
#endif
EXPECT_EQ(value1 , cmpMesh.property(prop,e1)) << "Wrong property at edge 0";
EXPECT_EQ(value2 , cmpMesh.property(prop,e2)) << "Wrong property at edge 1";
EXPECT_EQ(value3 , cmpMesh.property(prop,e3)) << "Wrong property at edge 2";
EXPECT_EQ(value4 , cmpMesh.property(prop,e4)) << "Wrong property at edge 3";
EXPECT_EQ(value5 , cmpMesh.property(prop,e5)) << "Wrong property at edge 4";
EXPECT_EQ(value6 , cmpMesh.property(prop,e6)) << "Wrong property at edge 5";
// The above only shows that the edge properties are stored in the same order which is not what we want if the edges are different
// Check edge properties based on edges defined by from and to vertex
for (auto eh : mesh.edges())
{
auto heh = mesh.halfedge_handle(eh, 0);
auto from_vh = mesh.from_vertex_handle(heh);
auto to_vh = mesh.to_vertex_handle(heh);
// find corresponding halfedge in loaded mesh
auto cmpHeh = cmpMesh.find_halfedge(from_vh, to_vh);
auto cmpEh = cmpMesh.edge_handle(cmpHeh);
EXPECT_EQ(mesh.property(prop, eh), cmpMesh.property(prop, cmpEh)) << "Wrong property at input edge " << eh.idx()
<< " corresponding to edge " << cmpEh.idx() << " in the loaded Mesh";
}
// cleanup
remove(filename.c_str());
}
/*
* Save and load simple mesh with status property
*/
TEST_F(OpenMeshReadWriteOM, WriteSplitTriangleStatusProperties) {
Mesh mesh;
mesh.request_vertex_status();
mesh.request_edge_status();
mesh.request_halfedge_status();
mesh.request_face_status();
const std::string filename = std::string("triangle-minimal-status.om");
// generate data
Mesh::VertexHandle v0 = mesh.add_vertex(Mesh::Point(1.0,0.0,0.0));
Mesh::VertexHandle v1 = mesh.add_vertex(Mesh::Point(0.0,1.0,0.0));
Mesh::VertexHandle v2 = mesh.add_vertex(Mesh::Point(0.0,0.0,1.0));
auto fh0 = mesh.add_face(v0,v1,v2);
auto c = mesh.calc_face_centroid(fh0);
Mesh::VertexHandle v3 = mesh.add_vertex(c);
mesh.split(fh0, v3);
mesh.delete_vertex(v0);
mesh.status(v1).set_selected(true);
mesh.status(v2).set_feature(true);
mesh.status(v3).set_tagged(true);
mesh.status(v2).set_tagged2(true);
std::vector<bool> vertex_deleted;
std::vector<bool> vertex_selected;
std::vector<bool> vertex_feature;
std::vector<bool> vertex_tagged;
std::vector<bool> vertex_tagged2;
for (auto vh : mesh.all_vertices())
{
vertex_deleted.push_back(mesh.status(vh).deleted());
vertex_selected.push_back(mesh.status(vh).selected());
vertex_feature.push_back(mesh.status(vh).feature());
vertex_tagged.push_back(mesh.status(vh).tagged());
vertex_tagged2.push_back(mesh.status(vh).tagged2());
}
Mesh::EdgeHandle e1 = Mesh::EdgeHandle(0);
Mesh::EdgeHandle e2 = Mesh::EdgeHandle(1);
Mesh::EdgeHandle e3 = Mesh::EdgeHandle(2);
Mesh::EdgeHandle e4 = Mesh::EdgeHandle(3);
mesh.status(e1).set_selected(true);
mesh.status(e2).set_feature(true);
mesh.status(e3).set_tagged(true);
mesh.status(e4).set_tagged2(true);
std::vector<bool> edge_deleted;
std::vector<bool> edge_selected;
std::vector<bool> edge_feature;
std::vector<bool> edge_tagged;
std::vector<bool> edge_tagged2;
for (auto eh : mesh.all_edges())
{
edge_deleted.push_back(mesh.status(eh).deleted());
edge_selected.push_back(mesh.status(eh).selected());
edge_feature.push_back(mesh.status(eh).feature());
edge_tagged.push_back(mesh.status(eh).tagged());
edge_tagged2.push_back(mesh.status(eh).tagged2());
}
Mesh::HalfedgeHandle he1 = Mesh::HalfedgeHandle(0);
Mesh::HalfedgeHandle he2 = Mesh::HalfedgeHandle(3);
Mesh::HalfedgeHandle he3 = Mesh::HalfedgeHandle(5);
Mesh::HalfedgeHandle he4 = Mesh::HalfedgeHandle(1);
mesh.status(he1).set_selected(true);
mesh.status(he2).set_feature(true);
mesh.status(he3).set_tagged(true);
mesh.status(he4).set_tagged2(true);
std::vector<bool> halfedge_deleted;
std::vector<bool> halfedge_selected;
std::vector<bool> halfedge_feature;
std::vector<bool> halfedge_tagged;
std::vector<bool> halfedge_tagged2;
for (auto heh : mesh.all_halfedges())
{
halfedge_deleted.push_back(mesh.status(heh).deleted());
halfedge_selected.push_back(mesh.status(heh).selected());
halfedge_feature.push_back(mesh.status(heh).feature());
halfedge_tagged.push_back(mesh.status(heh).tagged());
halfedge_tagged2.push_back(mesh.status(heh).tagged2());
}
Mesh::FaceHandle f1 = Mesh::FaceHandle(0);
Mesh::FaceHandle f2 = Mesh::FaceHandle(2);
Mesh::FaceHandle f3 = Mesh::FaceHandle(1);
Mesh::FaceHandle f4 = Mesh::FaceHandle(2);
mesh.status(f1).set_selected(true);
mesh.status(f2).set_feature(true);
mesh.status(f3).set_tagged(true);
mesh.status(f4).set_tagged2(true);
std::vector<bool> face_deleted;
std::vector<bool> face_selected;
std::vector<bool> face_feature;
std::vector<bool> face_tagged;
std::vector<bool> face_tagged2;
for (auto fh : mesh.all_faces())
{
face_deleted.push_back(mesh.status(fh).deleted());
face_selected.push_back(mesh.status(fh).selected());
face_feature.push_back(mesh.status(fh).feature());
face_tagged.push_back(mesh.status(fh).tagged());
face_tagged2.push_back(mesh.status(fh).tagged2());
}
// save
OpenMesh::IO::Options options = OpenMesh::IO::Options::Status;
bool ok = OpenMesh::IO::write_mesh(mesh,filename, options);
EXPECT_TRUE(ok) << "Unable to write "<<filename;
// load
Mesh cmpMesh;
cmpMesh.request_vertex_status();
cmpMesh.request_edge_status();
cmpMesh.request_halfedge_status();
cmpMesh.request_face_status();
ok = OpenMesh::IO::read_mesh(cmpMesh,filename, options);
EXPECT_TRUE(ok) << "Unable to read "<<filename;
// compare
EXPECT_EQ(4u , cmpMesh.n_vertices()) << "The number of loaded vertices is not correct!";
EXPECT_EQ(6u , cmpMesh.n_edges()) << "The number of loaded edges is not correct!";
EXPECT_EQ(3u , cmpMesh.n_faces()) << "The number of loaded faces is not correct!";
EXPECT_EQ(Mesh::Point(1.0,0.0,0.0) , cmpMesh.point(v0)) << "Wrong coordinates at vertex 0";
EXPECT_EQ(Mesh::Point(0.0,1.0,0.0) , cmpMesh.point(v1)) << "Wrong coordinates at vertex 1";
EXPECT_EQ(Mesh::Point(0.0,0.0,1.0) , cmpMesh.point(v2)) << "Wrong coordinates at vertex 2";
#ifdef TEST_DOUBLE_TRAITS
// TODO: should it be possible to read and write double precision exactly?
EXPECT_FLOAT_EQ(c[0] , cmpMesh.point(v3)[0]) << "Wrong coordinate 0 at vertex 3";
EXPECT_FLOAT_EQ(c[1] , cmpMesh.point(v3)[1]) << "Wrong coordinate 1 at vertex 3";
EXPECT_FLOAT_EQ(c[2] , cmpMesh.point(v3)[2]) << "Wrong coordinate 2 at vertex 3";
#else
EXPECT_EQ(c , cmpMesh.point(v3)) << "Wrong coordinates at vertex 3";
#endif
for (auto vh : cmpMesh.all_vertices())
{
EXPECT_EQ(cmpMesh.status(vh).deleted(), vertex_deleted [vh.idx()]) << "Wrong deleted status at vertex " << vh.idx();
EXPECT_EQ(cmpMesh.status(vh).selected(), vertex_selected[vh.idx()]) << "Wrong selected status at vertex " << vh.idx();
EXPECT_EQ(cmpMesh.status(vh).feature(), vertex_feature [vh.idx()]) << "Wrong feature status at vertex " << vh.idx();
EXPECT_EQ(cmpMesh.status(vh).tagged(), vertex_tagged [vh.idx()]) << "Wrong tagged status at vertex " << vh.idx();
EXPECT_EQ(cmpMesh.status(vh).tagged2(), vertex_tagged2 [vh.idx()]) << "Wrong tagged2 status at vertex " << vh.idx();
}
for (auto eh : cmpMesh.all_edges())
{
EXPECT_EQ(cmpMesh.status(eh).deleted(), edge_deleted [eh.idx()]) << "Wrong deleted status at edge " << eh.idx();
EXPECT_EQ(cmpMesh.status(eh).selected(), edge_selected[eh.idx()]) << "Wrong selected status at edge " << eh.idx();
EXPECT_EQ(cmpMesh.status(eh).feature(), edge_feature [eh.idx()]) << "Wrong feature status at edge " << eh.idx();
EXPECT_EQ(cmpMesh.status(eh).tagged(), edge_tagged [eh.idx()]) << "Wrong tagged status at edge " << eh.idx();
EXPECT_EQ(cmpMesh.status(eh).tagged2(), edge_tagged2 [eh.idx()]) << "Wrong tagged2 status at edge " << eh.idx();
}
for (auto heh : cmpMesh.all_halfedges())
{
EXPECT_EQ(cmpMesh.status(heh).deleted(), halfedge_deleted [heh.idx()]) << "Wrong deleted status at halfedge " << heh.idx();
EXPECT_EQ(cmpMesh.status(heh).selected(), halfedge_selected[heh.idx()]) << "Wrong selected status at halfedge " << heh.idx();
EXPECT_EQ(cmpMesh.status(heh).feature(), halfedge_feature [heh.idx()]) << "Wrong feature status at halfedge " << heh.idx();
EXPECT_EQ(cmpMesh.status(heh).tagged(), halfedge_tagged [heh.idx()]) << "Wrong tagged status at halfedge " << heh.idx();
EXPECT_EQ(cmpMesh.status(heh).tagged2(), halfedge_tagged2 [heh.idx()]) << "Wrong tagged2 status at halfedge " << heh.idx();
}
for (auto fh : cmpMesh.all_faces())
{
EXPECT_EQ(cmpMesh.status(fh).deleted(), face_deleted [fh.idx()]) << "Wrong deleted status at face " << fh.idx();
EXPECT_EQ(cmpMesh.status(fh).selected(), face_selected[fh.idx()]) << "Wrong selected status at face " << fh.idx();
EXPECT_EQ(cmpMesh.status(fh).feature(), face_feature [fh.idx()]) << "Wrong feature status at face " << fh.idx();
EXPECT_EQ(cmpMesh.status(fh).tagged(), face_tagged [fh.idx()]) << "Wrong tagged status at face " << fh.idx();
EXPECT_EQ(cmpMesh.status(fh).tagged2(), face_tagged2 [fh.idx()]) << "Wrong tagged2 status at face " << fh.idx();
}
// cleanup
remove(filename.c_str());
}
/*
* Save and load simple mesh with custom property
*/
@@ -670,4 +1007,506 @@ TEST_F(OpenMeshReadWriteOM, ReadBigMeshWithCustomProperty) {
EXPECT_FALSE(wrong) << "min one vertex has worng vertex property";
}
/*
* Save and load simple mesh with vertex status
*/
TEST_F(OpenMeshReadWriteOM, WriteReadStatusPropertyVertexOnly) {
//read file
Mesh mesh;
auto vh0 = mesh.add_vertex(Mesh::Point(0,0,0));
auto vh1 = mesh.add_vertex(Mesh::Point(1,0,0));
auto vh2 = mesh.add_vertex(Mesh::Point(0,1,0));
mesh.add_face(vh0, vh1, vh2);
mesh.request_vertex_status();
mesh.status(vh0).set_selected(true);
mesh.status(vh1).set_feature(true);
mesh.status(vh2).set_tagged(true);
mesh.status(vh0).set_locked(true);
mesh.status(vh1).set_deleted(true);
mesh.status(vh2).set_hidden(true);
mesh.status(vh0).set_fixed_nonmanifold(true);
std::string filename_without_status = "no_vertex_status_test.om";
std::string filename_with_status = "vertex_status_test.om";
OpenMesh::IO::Options opt_with_status = OpenMesh::IO::Options::Status;
OpenMesh::IO::write_mesh(mesh, filename_without_status);
OpenMesh::IO::write_mesh(mesh, filename_with_status, opt_with_status);
// Load no status from file with status
{
Mesh loaded_mesh;
OpenMesh::IO::read_mesh(loaded_mesh, filename_with_status);
EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though they should not have been loaded";
EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status";
EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though file should not have a stored status";
EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though file should not have a stored status";
}
// Load status from file with status
{
Mesh loaded_mesh;
OpenMesh::IO::read_mesh(loaded_mesh, filename_with_status, opt_with_status);
EXPECT_TRUE (loaded_mesh.has_vertex_status()) << "Mesh has no vertex status even though they should have been loaded";
EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status";
EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though file should not have a stored status";
EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though file should not have a stored status";
if (loaded_mesh.has_vertex_status())
{
for (auto vh : mesh.vertices())
{
EXPECT_EQ(mesh.status(vh).bits(), loaded_mesh.status(vh).bits());
}
}
}
// Load no status from file with status
{
Mesh loaded_mesh;
loaded_mesh.request_vertex_status();
OpenMesh::IO::read_mesh(loaded_mesh, filename_with_status);
EXPECT_TRUE (loaded_mesh.has_vertex_status()) << "Mesh vertex status was removed by reading";
EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status";
EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though file should not have a stored status";
EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though file should not have a stored status";
for (auto vh : loaded_mesh.vertices())
{
EXPECT_EQ(loaded_mesh.status(vh).bits(), 0u) << "Vertex status was modified even though it should not have been loaded";
}
}
// Try to load status from file without status
{
Mesh loaded_mesh;
OpenMesh::IO::read_mesh(loaded_mesh, filename_without_status, opt_with_status);
EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though file should not have a stored status";
EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status";
EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though they file should not have a stored status";
EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though they file should not have a stored status";
}
}
/*
* Save and load simple mesh with halfedge status
*/
TEST_F(OpenMeshReadWriteOM, WriteReadStatusPropertyHalfedgeOnly) {
//read file
Mesh mesh;
auto vh0 = mesh.add_vertex(Mesh::Point(0,0,0));
auto vh1 = mesh.add_vertex(Mesh::Point(1,0,0));
auto vh2 = mesh.add_vertex(Mesh::Point(0,1,0));
mesh.add_face(vh0, vh1, vh2);
mesh.request_halfedge_status();
auto heh0 = OpenMesh::HalfedgeHandle(0);
auto heh1 = OpenMesh::HalfedgeHandle(1);
auto heh2 = OpenMesh::HalfedgeHandle(2);
auto heh3 = OpenMesh::HalfedgeHandle(3);
auto heh4 = OpenMesh::HalfedgeHandle(4);
auto heh5 = OpenMesh::HalfedgeHandle(5);
mesh.status(heh0).set_selected(true);
mesh.status(heh1).set_feature(true);
mesh.status(heh2).set_tagged(true);
mesh.status(heh3).set_locked(true);
mesh.status(heh4).set_deleted(true);
mesh.status(heh5).set_hidden(true);
mesh.status(heh0).set_fixed_nonmanifold(true);
std::string filename_without_status = "no_halfedge_status_test.om";
std::string filename_with_status = "edge_halfstatus_test.om";
OpenMesh::IO::Options opt_with_status = OpenMesh::IO::Options::Status;
OpenMesh::IO::write_mesh(mesh, filename_without_status);
OpenMesh::IO::write_mesh(mesh, filename_with_status, opt_with_status);
// Load no status from file with status
{
Mesh loaded_mesh;
OpenMesh::IO::read_mesh(loaded_mesh, filename_with_status);
EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though they should not have been loaded";
EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status";
EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though file should not have a stored status";
EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though file should not have a stored status";
}
// Load status from file with status
{
Mesh loaded_mesh;
OpenMesh::IO::read_mesh(loaded_mesh, filename_with_status, opt_with_status);
EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though they should have been loaded";
EXPECT_TRUE(loaded_mesh.has_halfedge_status()) << "Mesh has no halfedge status even though file should not have a stored status";
EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though file should not have a stored status";
EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though file should not have a stored status";
if (loaded_mesh.has_halfedge_status())
{
for (auto heh : mesh.halfedges())
{
EXPECT_EQ(mesh.status(heh).bits(), loaded_mesh.status(heh).bits());
}
}
}
// Load no status from file with status
{
Mesh loaded_mesh;
loaded_mesh.request_halfedge_status();
OpenMesh::IO::read_mesh(loaded_mesh, filename_with_status);
EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though file should not have a stored status";
EXPECT_TRUE (loaded_mesh.has_halfedge_status()) << "Mesh halfedge status was removed by reading";
EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though file should not have a stored status";
EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though file should not have a stored status";
for (auto heh : loaded_mesh.halfedges())
{
EXPECT_EQ(loaded_mesh.status(heh).bits(), 0u) << "Edge status was modified even though it should not have been loaded";
}
}
// Try to load status from file without status
{
Mesh loaded_mesh;
OpenMesh::IO::read_mesh(loaded_mesh, filename_without_status, opt_with_status);
EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though file should not have a stored status";
EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status";
EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though they file should not have a stored status";
EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though they file should not have a stored status";
}
}
/*
* Save and load simple mesh with edge status
*/
TEST_F(OpenMeshReadWriteOM, WriteReadStatusPropertyEdgeOnly) {
//read file
Mesh mesh;
auto vh0 = mesh.add_vertex(Mesh::Point(0,0,0));
auto vh1 = mesh.add_vertex(Mesh::Point(1,0,0));
auto vh2 = mesh.add_vertex(Mesh::Point(0,1,0));
mesh.add_face(vh0, vh1, vh2);
mesh.request_edge_status();
auto eh0 = OpenMesh::EdgeHandle(0);
auto eh1 = OpenMesh::EdgeHandle(1);
auto eh2 = OpenMesh::EdgeHandle(2);
mesh.status(eh0).set_selected(true);
mesh.status(eh1).set_feature(true);
mesh.status(eh2).set_tagged(true);
mesh.status(eh0).set_locked(true);
mesh.status(eh1).set_deleted(true);
mesh.status(eh2).set_hidden(true);
mesh.status(eh0).set_fixed_nonmanifold(true);
std::string filename_without_status = "no_edge_status_test.om";
std::string filename_with_status = "edge_status_test.om";
OpenMesh::IO::Options opt_with_status = OpenMesh::IO::Options::Status;
OpenMesh::IO::write_mesh(mesh, filename_without_status);
OpenMesh::IO::write_mesh(mesh, filename_with_status, opt_with_status);
// Load no status from file with status
{
Mesh loaded_mesh;
OpenMesh::IO::read_mesh(loaded_mesh, filename_with_status);
EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though they should not have been loaded";
EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status";
EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though file should not have a stored status";
EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though file should not have a stored status";
}
// Load status from file with status
{
Mesh loaded_mesh;
OpenMesh::IO::read_mesh(loaded_mesh, filename_with_status, opt_with_status);
EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though they should have been loaded";
EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status";
EXPECT_TRUE(loaded_mesh.has_edge_status()) << "Mesh has no edge status even though file should not have a stored status";
EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though file should not have a stored status";
if (loaded_mesh.has_edge_status())
{
for (auto eh : mesh.edges())
{
EXPECT_EQ(mesh.status(eh).bits(), loaded_mesh.status(eh).bits());
}
}
}
// Load no status from file with status
{
Mesh loaded_mesh;
loaded_mesh.request_edge_status();
OpenMesh::IO::read_mesh(loaded_mesh, filename_with_status);
EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though file should not have a stored status";
EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status";
EXPECT_TRUE (loaded_mesh.has_edge_status()) << "Mesh edge status was removed by reading";
EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though file should not have a stored status";
for (auto eh : loaded_mesh.edges())
{
EXPECT_EQ(loaded_mesh.status(eh).bits(), 0u) << "Edge status was modified even though it should not have been loaded";
}
}
// Try to load status from file without status
{
Mesh loaded_mesh;
OpenMesh::IO::read_mesh(loaded_mesh, filename_without_status, opt_with_status);
EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though file should not have a stored status";
EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status";
EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though they file should not have a stored status";
EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though they file should not have a stored status";
}
}
/*
* Save and load simple mesh with face status
*/
TEST_F(OpenMeshReadWriteOM, WriteReadStatusPropertyFaceOnly) {
//read file
Mesh mesh;
auto vh0 = mesh.add_vertex(Mesh::Point(0,0,0));
auto vh1 = mesh.add_vertex(Mesh::Point(1,0,0));
auto vh2 = mesh.add_vertex(Mesh::Point(0,1,0));
auto vh3 = mesh.add_vertex(Mesh::Point(1,1,0));
auto fh0 = mesh.add_face(vh0, vh1, vh2);
auto fh1 = mesh.add_face(vh2, vh1, vh3);
mesh.request_face_status();
mesh.status(fh0).set_selected(true);
mesh.status(fh1).set_feature(true);
mesh.status(fh0).set_tagged(true);
mesh.status(fh1).set_locked(true);
mesh.status(fh0).set_deleted(true);
mesh.status(fh1).set_hidden(true);
mesh.status(fh0).set_fixed_nonmanifold(true);
std::string filename_without_status = "no_face_status_test.om";
std::string filename_with_status = "face_status_test.om";
OpenMesh::IO::Options opt_with_status = OpenMesh::IO::Options::Status;
OpenMesh::IO::write_mesh(mesh, filename_without_status);
OpenMesh::IO::write_mesh(mesh, filename_with_status, opt_with_status);
// Load no status from file with status
{
Mesh loaded_mesh;
OpenMesh::IO::read_mesh(loaded_mesh, filename_with_status);
EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though they should not have been loaded";
EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status";
EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though file should not have a stored status";
EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though file should not have a stored status";
}
// Load status from file with status
{
Mesh loaded_mesh;
OpenMesh::IO::read_mesh(loaded_mesh, filename_with_status, opt_with_status);
EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though they should have been loaded";
EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status";
EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though file should not have a stored status";
EXPECT_TRUE(loaded_mesh.has_face_status()) << "Mesh has no face status even though file should not have a stored status";
if (loaded_mesh.has_face_status())
{
for (auto fh : mesh.faces())
{
EXPECT_EQ(mesh.status(fh).bits(), loaded_mesh.status(fh).bits());
}
}
}
// Load no status from file with status
{
Mesh loaded_mesh;
loaded_mesh.request_face_status();
OpenMesh::IO::read_mesh(loaded_mesh, filename_with_status);
EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though file should not have a stored status";
EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status";
EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edgestatus even though file should not have a stored status";
EXPECT_TRUE (loaded_mesh.has_face_status()) << "Mesh face status was removed by reading";
for (auto fh : loaded_mesh.faces())
{
EXPECT_EQ(loaded_mesh.status(fh).bits(), 0u) << "Edge status was modified even though it should not have been loaded";
}
}
// Try to load status from file without status
{
Mesh loaded_mesh;
OpenMesh::IO::read_mesh(loaded_mesh, filename_without_status, opt_with_status);
EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though file should not have a stored status";
EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status";
EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though they file should not have a stored status";
EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though they file should not have a stored status";
}
}
/*
* Just load a triangle mesh from an om file of version 1.2
*/
TEST_F(OpenMeshReadWriteOM, LoadTriangleMeshVersion_1_2) {
mesh_.clear();
std::string file_name = "cube_tri_version_1_2.om";
bool ok = OpenMesh::IO::read_mesh(mesh_, file_name);
EXPECT_TRUE(ok) << file_name;
EXPECT_EQ(8u , mesh_.n_vertices()) << "The number of loaded vertices is not correct!";
EXPECT_EQ(18u , mesh_.n_edges()) << "The number of loaded edges is not correct!";
EXPECT_EQ(12u , mesh_.n_faces()) << "The number of loaded faces is not correct!";
EXPECT_EQ(36u , mesh_.n_halfedges()) << "The number of loaded halfedges is not correct!";
}
/*
* Just load a polyhedral mesh from an om file of version 1.2
*/
TEST_F(OpenMeshReadWriteOM, LoadPolyMeshVersion_1_2) {
PolyMesh mesh;
std::string file_name = "cube_poly_version_1_2.om";
bool ok = OpenMesh::IO::read_mesh(mesh, file_name);
EXPECT_TRUE(ok) << file_name;
EXPECT_EQ(8u , mesh.n_vertices()) << "The number of loaded vertices is not correct!";
EXPECT_EQ(12u , mesh.n_edges()) << "The number of loaded edges is not correct!";
EXPECT_EQ(6u , mesh.n_faces()) << "The number of loaded faces is not correct!";
EXPECT_EQ(24u , mesh.n_halfedges()) << "The number of loaded halfedges is not correct!";
}
/*
* Just load a triangle mesh from an om file of version 2.0
*/
TEST_F(OpenMeshReadWriteOM, LoadTriangleMeshVersion_2_0) {
mesh_.clear();
std::string file_name = "cube_tri_version_2_0.om";
bool ok = OpenMesh::IO::read_mesh(mesh_, file_name);
EXPECT_TRUE(ok) << file_name;
EXPECT_EQ(8u , mesh_.n_vertices()) << "The number of loaded vertices is not correct!";
EXPECT_EQ(18u , mesh_.n_edges()) << "The number of loaded edges is not correct!";
EXPECT_EQ(12u , mesh_.n_faces()) << "The number of loaded faces is not correct!";
EXPECT_EQ(36u , mesh_.n_halfedges()) << "The number of loaded halfedges is not correct!";
}
/*
* Just load a polyhedral mesh from an om file of version 2.0
*/
TEST_F(OpenMeshReadWriteOM, LoadPolyMeshVersion_2_0) {
PolyMesh mesh;
std::string file_name = "cube_poly_version_2_0.om";
bool ok = OpenMesh::IO::read_mesh(mesh, file_name);
EXPECT_TRUE(ok) << file_name;
EXPECT_EQ(8u , mesh.n_vertices()) << "The number of loaded vertices is not correct!";
EXPECT_EQ(12u , mesh.n_edges()) << "The number of loaded edges is not correct!";
EXPECT_EQ(6u , mesh.n_faces()) << "The number of loaded faces is not correct!";
EXPECT_EQ(24u , mesh.n_halfedges()) << "The number of loaded halfedges is not correct!";
}
/*
* Try to load mesh from om file with a version that is not yet supported
*/
TEST_F(OpenMeshReadWriteOM, LoadTriMeshVersion_7_5) {
PolyMesh mesh;
std::string file_name = "cube_tri_version_7_5.om";
bool ok = OpenMesh::IO::read_mesh(mesh, file_name);
EXPECT_FALSE(ok) << file_name;
}
/*
* Try to write and load positions and normals that can only be represented by doubles
*/
TEST_F(OpenMeshReadWriteOM, WriteAndLoadDoubles) {
typedef OpenMesh::PolyMesh_ArrayKernelT<OpenMesh::DefaultTraitsDouble> DoublePolyMesh;
DoublePolyMesh mesh;
mesh.request_vertex_normals();
mesh.request_face_normals();
std::vector<OpenMesh::VertexHandle> vertices;
for (int i = 0; i < 3; ++i)
{
vertices.push_back(mesh.add_vertex(DoublePolyMesh::Point(1.0/3.0, std::numeric_limits<double>::min(), std::numeric_limits<double>::max())));
mesh.set_normal(vertices.back(), DoublePolyMesh::Normal(1.0/3.0, std::numeric_limits<double>::min(), std::numeric_limits<double>::max()));
}
auto fh = mesh.add_face(vertices);
mesh.set_normal(fh, DoublePolyMesh::Normal(1.0/3.0, std::numeric_limits<double>::min(), std::numeric_limits<double>::max()));
std::string file_name = "doubles.om";
OpenMesh::IO::Options opt = OpenMesh::IO::Options::VertexNormal | OpenMesh::IO::Options::FaceNormal;
ASSERT_TRUE(OpenMesh::IO::write_mesh(mesh, file_name, opt)) << "Could not write file " << file_name;
DoublePolyMesh mesh2;
mesh2.request_vertex_normals();
mesh2.request_face_normals();
ASSERT_TRUE(OpenMesh::IO::read_mesh(mesh2, file_name, opt)) << "Could not read file " << file_name;
EXPECT_EQ(mesh.point(OpenMesh::VertexHandle(0)), mesh2.point(OpenMesh::VertexHandle(0)));
EXPECT_EQ(mesh.normal(OpenMesh::VertexHandle(0)), mesh2.normal(OpenMesh::VertexHandle(0)));
EXPECT_EQ(mesh.normal(OpenMesh::FaceHandle(0)), mesh2.normal(OpenMesh::FaceHandle(0)));
}
}

View File

@@ -81,6 +81,24 @@ TEST_F(OpenMeshReadWritePLY, LoadSimplePLY) {
}
/*
* Load a ply ascii file without a newline at the end of the file
*
*/
TEST_F(OpenMeshReadWritePLY, LoadSimplePLYNoEndl) {
mesh_.clear();
bool ok = OpenMesh::IO::read_mesh(mesh_, "sphere840.ply");
EXPECT_TRUE(ok) << "Unable to load sphere840.ply";
EXPECT_EQ(422u , mesh_.n_vertices()) << "The number of loaded vertices is not correct!";
EXPECT_EQ(1260u , mesh_.n_edges()) << "The number of loaded edges is not correct!";
EXPECT_EQ(840u , mesh_.n_faces()) << "The number of loaded faces is not correct!";
}
/*
* Just load a ply file and set vertex color option before loading
*/
@@ -129,21 +147,39 @@ TEST_F(OpenMeshReadWritePLY, LoadSimplePLYWithVertexColors) {
EXPECT_EQ(18u , mesh_.n_edges()) << "The number of loaded edges is not correct!";
EXPECT_EQ(12u , mesh_.n_faces()) << "The number of loaded faces is not correct!";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(0))[0] ) << "Wrong vertex color at vertex 0 component 0";
#ifdef TEST_DOUBLE_TRAITS
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(0))[0] ) << "Wrong vertex color at vertex 0 component 0";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(0))[1] ) << "Wrong vertex color at vertex 0 component 1";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(0))[2] ) << "Wrong vertex color at vertex 0 component 2";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(3))[0] ) << "Wrong vertex color at vertex 3 component 0";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(3))[1] ) << "Wrong vertex color at vertex 3 component 1";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(3))[2] ) << "Wrong vertex color at vertex 3 component 2";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(4))[0] ) << "Wrong vertex color at vertex 4 component 0";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(4))[1] ) << "Wrong vertex color at vertex 4 component 1";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(4))[2] ) << "Wrong vertex color at vertex 4 component 2";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(7))[0] ) << "Wrong vertex color at vertex 7 component 0";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(7))[1] ) << "Wrong vertex color at vertex 7 component 1";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(7))[2] ) << "Wrong vertex color at vertex 7 component 2";
#else
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(0))[0] ) << "Wrong vertex color at vertex 0 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(0))[1] ) << "Wrong vertex color at vertex 0 component 1";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(0))[2] ) << "Wrong vertex color at vertex 0 component 2";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(3))[0] ) << "Wrong vertex color at vertex 3 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(3))[1] ) << "Wrong vertex color at vertex 3 component 1";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(3))[2] ) << "Wrong vertex color at vertex 3 component 2";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(3))[0] ) << "Wrong vertex color at vertex 3 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(3))[1] ) << "Wrong vertex color at vertex 3 component 1";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(3))[2] ) << "Wrong vertex color at vertex 3 component 2";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(4))[0] ) << "Wrong vertex color at vertex 4 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(4))[0] ) << "Wrong vertex color at vertex 4 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(4))[1] ) << "Wrong vertex color at vertex 4 component 1";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(4))[2] ) << "Wrong vertex color at vertex 4 component 2";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(4))[2] ) << "Wrong vertex color at vertex 4 component 2";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(7))[0] ) << "Wrong vertex color at vertex 7 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(7))[1] ) << "Wrong vertex color at vertex 7 component 1";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(7))[0] ) << "Wrong vertex color at vertex 7 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(7))[1] ) << "Wrong vertex color at vertex 7 component 1";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(7))[2] ) << "Wrong vertex color at vertex 7 component 2";
#endif
EXPECT_FALSE(options.vertex_has_normal()) << "Wrong user options are returned!";
EXPECT_FALSE(options.vertex_has_texcoord()) << "Wrong user options are returned!";
@@ -172,21 +208,39 @@ TEST_F(OpenMeshReadWritePLY, LoadPLYFromMeshLabWithVertexColors) {
EXPECT_EQ(18u , mesh_.n_edges()) << "The number of loaded edges is not correct!";
EXPECT_EQ(12u , mesh_.n_faces()) << "The number of loaded faces is not correct!";
#ifdef TEST_DOUBLE_TRAITS
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(0))[0] ) << "Wrong vertex color at vertex 0 component 0";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(0))[1] ) << "Wrong vertex color at vertex 0 component 1";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(0))[2] ) << "Wrong vertex color at vertex 0 component 2";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(3))[0] ) << "Wrong vertex color at vertex 3 component 0";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(3))[1] ) << "Wrong vertex color at vertex 3 component 1";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(3))[2] ) << "Wrong vertex color at vertex 3 component 2";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(4))[0] ) << "Wrong vertex color at vertex 4 component 0";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(4))[1] ) << "Wrong vertex color at vertex 4 component 1";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(4))[2] ) << "Wrong vertex color at vertex 4 component 2";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(7))[0] ) << "Wrong vertex color at vertex 7 component 0";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(7))[1] ) << "Wrong vertex color at vertex 7 component 1";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(7))[2] ) << "Wrong vertex color at vertex 7 component 2";
#else
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(0))[0] ) << "Wrong vertex color at vertex 0 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(0))[1] ) << "Wrong vertex color at vertex 0 component 1";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(0))[2] ) << "Wrong vertex color at vertex 0 component 2";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(0))[2] ) << "Wrong vertex color at vertex 0 component 2";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(3))[0] ) << "Wrong vertex color at vertex 3 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(3))[1] ) << "Wrong vertex color at vertex 3 component 1";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(3))[1] ) << "Wrong vertex color at vertex 3 component 1";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(3))[2] ) << "Wrong vertex color at vertex 3 component 2";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(4))[0] ) << "Wrong vertex color at vertex 4 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(4))[0] ) << "Wrong vertex color at vertex 4 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(4))[1] ) << "Wrong vertex color at vertex 4 component 1";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(4))[2] ) << "Wrong vertex color at vertex 4 component 2";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(4))[2] ) << "Wrong vertex color at vertex 4 component 2";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(7))[0] ) << "Wrong vertex color at vertex 7 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(7))[1] ) << "Wrong vertex color at vertex 7 component 1";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(7))[0] ) << "Wrong vertex color at vertex 7 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(7))[1] ) << "Wrong vertex color at vertex 7 component 1";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(7))[2] ) << "Wrong vertex color at vertex 7 component 2";
#endif
EXPECT_FALSE(options.vertex_has_normal()) << "Wrong user options are returned!";
EXPECT_FALSE(options.vertex_has_texcoord()) << "Wrong user options are returned!";
@@ -224,21 +278,39 @@ TEST_F(OpenMeshReadWritePLY, WriteAndReadBinaryPLYWithVertexColors) {
EXPECT_EQ(18u , mesh_.n_edges()) << "The number of loaded edges is not correct!";
EXPECT_EQ(12u , mesh_.n_faces()) << "The number of loaded faces is not correct!";
#ifdef TEST_DOUBLE_TRAITS
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(0))[0] ) << "Wrong vertex color at vertex 0 component 0";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(0))[1] ) << "Wrong vertex color at vertex 0 component 1";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(0))[2] ) << "Wrong vertex color at vertex 0 component 2";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(3))[0] ) << "Wrong vertex color at vertex 3 component 0";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(3))[1] ) << "Wrong vertex color at vertex 3 component 1";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(3))[2] ) << "Wrong vertex color at vertex 3 component 2";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(4))[0] ) << "Wrong vertex color at vertex 4 component 0";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(4))[1] ) << "Wrong vertex color at vertex 4 component 1";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(4))[2] ) << "Wrong vertex color at vertex 4 component 2";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(7))[0] ) << "Wrong vertex color at vertex 7 component 0";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(7))[1] ) << "Wrong vertex color at vertex 7 component 1";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(7))[2] ) << "Wrong vertex color at vertex 7 component 2";
#else
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(0))[0] ) << "Wrong vertex color at vertex 0 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(0))[1] ) << "Wrong vertex color at vertex 0 component 1";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(0))[2] ) << "Wrong vertex color at vertex 0 component 2";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(0))[2] ) << "Wrong vertex color at vertex 0 component 2";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(3))[0] ) << "Wrong vertex color at vertex 3 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(3))[1] ) << "Wrong vertex color at vertex 3 component 1";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(3))[1] ) << "Wrong vertex color at vertex 3 component 1";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(3))[2] ) << "Wrong vertex color at vertex 3 component 2";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(4))[0] ) << "Wrong vertex color at vertex 4 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(4))[0] ) << "Wrong vertex color at vertex 4 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(4))[1] ) << "Wrong vertex color at vertex 4 component 1";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(4))[2] ) << "Wrong vertex color at vertex 4 component 2";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(4))[2] ) << "Wrong vertex color at vertex 4 component 2";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(7))[0] ) << "Wrong vertex color at vertex 7 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(7))[1] ) << "Wrong vertex color at vertex 7 component 1";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(7))[0] ) << "Wrong vertex color at vertex 7 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(7))[1] ) << "Wrong vertex color at vertex 7 component 1";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(7))[2] ) << "Wrong vertex color at vertex 7 component 2";
#endif
EXPECT_FALSE(options.vertex_has_normal()) << "Wrong user options are returned!";
EXPECT_FALSE(options.vertex_has_texcoord()) << "Wrong user options are returned!";
@@ -276,21 +348,39 @@ TEST_F(OpenMeshReadWritePLY, WriteAndReadPLYWithFloatVertexColors) {
EXPECT_EQ(18u , mesh_.n_edges()) << "The number of loaded edges is not correct!";
EXPECT_EQ(12u , mesh_.n_faces()) << "The number of loaded faces is not correct!";
#ifdef TEST_DOUBLE_TRAITS
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(0))[0] ) << "Wrong vertex color at vertex 0 component 0";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(0))[1] ) << "Wrong vertex color at vertex 0 component 1";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(0))[2] ) << "Wrong vertex color at vertex 0 component 2";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(3))[0] ) << "Wrong vertex color at vertex 3 component 0";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(3))[1] ) << "Wrong vertex color at vertex 3 component 1";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(3))[2] ) << "Wrong vertex color at vertex 3 component 2";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(4))[0] ) << "Wrong vertex color at vertex 4 component 0";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(4))[1] ) << "Wrong vertex color at vertex 4 component 1";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(4))[2] ) << "Wrong vertex color at vertex 4 component 2";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(7))[0] ) << "Wrong vertex color at vertex 7 component 0";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(7))[1] ) << "Wrong vertex color at vertex 7 component 1";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(7))[2] ) << "Wrong vertex color at vertex 7 component 2";
#else
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(0))[0] ) << "Wrong vertex color at vertex 0 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(0))[1] ) << "Wrong vertex color at vertex 0 component 1";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(0))[2] ) << "Wrong vertex color at vertex 0 component 2";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(0))[2] ) << "Wrong vertex color at vertex 0 component 2";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(3))[0] ) << "Wrong vertex color at vertex 3 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(3))[1] ) << "Wrong vertex color at vertex 3 component 1";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(3))[1] ) << "Wrong vertex color at vertex 3 component 1";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(3))[2] ) << "Wrong vertex color at vertex 3 component 2";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(4))[0] ) << "Wrong vertex color at vertex 4 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(4))[0] ) << "Wrong vertex color at vertex 4 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(4))[1] ) << "Wrong vertex color at vertex 4 component 1";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(4))[2] ) << "Wrong vertex color at vertex 4 component 2";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(4))[2] ) << "Wrong vertex color at vertex 4 component 2";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(7))[0] ) << "Wrong vertex color at vertex 7 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(7))[1] ) << "Wrong vertex color at vertex 7 component 1";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(7))[0] ) << "Wrong vertex color at vertex 7 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(7))[1] ) << "Wrong vertex color at vertex 7 component 1";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(7))[2] ) << "Wrong vertex color at vertex 7 component 2";
#endif
EXPECT_FALSE(options.vertex_has_normal()) << "Wrong user options are returned!";
EXPECT_FALSE(options.vertex_has_texcoord()) << "Wrong user options are returned!";
@@ -330,21 +420,39 @@ TEST_F(OpenMeshReadWritePLY, WriteAndReadBinaryPLYWithFloatVertexColors) {
EXPECT_EQ(18u , mesh_.n_edges()) << "The number of loaded edges is not correct!";
EXPECT_EQ(12u , mesh_.n_faces()) << "The number of loaded faces is not correct!";
#ifdef TEST_DOUBLE_TRAITS
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(0))[0] ) << "Wrong vertex color at vertex 0 component 0";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(0))[1] ) << "Wrong vertex color at vertex 0 component 1";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(0))[2] ) << "Wrong vertex color at vertex 0 component 2";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(3))[0] ) << "Wrong vertex color at vertex 3 component 0";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(3))[1] ) << "Wrong vertex color at vertex 3 component 1";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(3))[2] ) << "Wrong vertex color at vertex 3 component 2";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(4))[0] ) << "Wrong vertex color at vertex 4 component 0";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(4))[1] ) << "Wrong vertex color at vertex 4 component 1";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(4))[2] ) << "Wrong vertex color at vertex 4 component 2";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(7))[0] ) << "Wrong vertex color at vertex 7 component 0";
EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(7))[1] ) << "Wrong vertex color at vertex 7 component 1";
EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(7))[2] ) << "Wrong vertex color at vertex 7 component 2";
#else
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(0))[0] ) << "Wrong vertex color at vertex 0 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(0))[1] ) << "Wrong vertex color at vertex 0 component 1";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(0))[2] ) << "Wrong vertex color at vertex 0 component 2";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(0))[2] ) << "Wrong vertex color at vertex 0 component 2";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(3))[0] ) << "Wrong vertex color at vertex 3 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(3))[1] ) << "Wrong vertex color at vertex 3 component 1";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(3))[1] ) << "Wrong vertex color at vertex 3 component 1";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(3))[2] ) << "Wrong vertex color at vertex 3 component 2";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(4))[0] ) << "Wrong vertex color at vertex 4 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(4))[0] ) << "Wrong vertex color at vertex 4 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(4))[1] ) << "Wrong vertex color at vertex 4 component 1";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(4))[2] ) << "Wrong vertex color at vertex 4 component 2";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(4))[2] ) << "Wrong vertex color at vertex 4 component 2";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(7))[0] ) << "Wrong vertex color at vertex 7 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(7))[1] ) << "Wrong vertex color at vertex 7 component 1";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(7))[0] ) << "Wrong vertex color at vertex 7 component 0";
EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(7))[1] ) << "Wrong vertex color at vertex 7 component 1";
EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(7))[2] ) << "Wrong vertex color at vertex 7 component 2";
#endif
EXPECT_FALSE(options.vertex_has_normal()) << "Wrong user options are returned!";
EXPECT_FALSE(options.vertex_has_texcoord()) << "Wrong user options are returned!";
@@ -525,6 +633,91 @@ TEST_F(OpenMeshReadWritePLY, LoadSimplePLYWithCustomProps) {
}
/*
* Just load a ply with custom properties, binary mode
*/
TEST_F(OpenMeshReadWritePLY, LoadSimplePLYWithCustomPropsBinary) {
PolyMesh mesh;
OpenMesh::IO::Options options;
options += OpenMesh::IO::Options::Custom;
options += OpenMesh::IO::Options::Binary;
bool ok = OpenMesh::IO::read_mesh(mesh, "cube-minimal-custom_props-binary.ply", options);
EXPECT_TRUE(ok) << "Unable to load cube-minimal-custom_props.ply";
EXPECT_EQ(8u , mesh.n_vertices()) << "The number of loaded vertices is not correct!";
EXPECT_EQ(12u , mesh.n_edges()) << "The number of loaded edges is not correct!";
EXPECT_EQ(6u , mesh.n_faces()) << "The number of loaded faces is not correct!";
OpenMesh::VPropHandleT<float> qualityProp;
OpenMesh::VPropHandleT<unsigned int> indexProp;
ASSERT_TRUE(mesh.get_property_handle(qualityProp,"quality")) << "Could not access quality property";
ASSERT_TRUE(mesh.get_property_handle(indexProp,"index")) << "Could not access index property";
//check index property
for (unsigned i = 0; i < mesh.n_vertices(); ++i)
EXPECT_EQ(i ,mesh.property(indexProp,OpenMesh::VertexHandle(i))) << "Vertex index at vertex " << i << " is wrong";
//check quality property
EXPECT_EQ(1.f,mesh.property(qualityProp,OpenMesh::VertexHandle(0))) << "Wrong quality value at Vertex 0";
EXPECT_EQ(0.5f,mesh.property(qualityProp,OpenMesh::VertexHandle(1))) << "Wrong quality value at Vertex 1";
EXPECT_EQ(0.7f,mesh.property(qualityProp,OpenMesh::VertexHandle(2))) << "Wrong quality value at Vertex 2";
EXPECT_EQ(1.f,mesh.property(qualityProp,OpenMesh::VertexHandle(3))) << "Wrong quality value at Vertex 3";
EXPECT_EQ(0.1f,mesh.property(qualityProp,OpenMesh::VertexHandle(4))) << "Wrong quality value at Vertex 4";
EXPECT_EQ(0.f,mesh.property(qualityProp,OpenMesh::VertexHandle(5))) << "Wrong quality value at Vertex 5";
EXPECT_EQ(2.f,mesh.property(qualityProp,OpenMesh::VertexHandle(6))) << "Wrong quality value at Vertex 6";
EXPECT_EQ(5.f,mesh.property(qualityProp,OpenMesh::VertexHandle(7))) << "Wrong quality value at Vertex 7";
//check for custom list properties
OpenMesh::VPropHandleT< std::vector<int> > testValues;
ASSERT_TRUE(mesh.get_property_handle(testValues,"test_values")) << "Could not access texcoords per face";
EXPECT_EQ(2u,mesh.property(testValues,OpenMesh::VertexHandle(0)).size()) << "Wrong verctor size";
EXPECT_EQ(1,mesh.property(testValues,OpenMesh::VertexHandle(0))[0]) << "Wrong list value at Vertex 0";
EXPECT_EQ(4,mesh.property(testValues,OpenMesh::VertexHandle(1))[1]) << "Wrong list value at Vertex 1";
EXPECT_EQ(5,mesh.property(testValues,OpenMesh::VertexHandle(2))[0]) << "Wrong list value at Vertex 2";
EXPECT_EQ(8,mesh.property(testValues,OpenMesh::VertexHandle(3))[1]) << "Wrong list value at Vertex 3";
EXPECT_EQ(9,mesh.property(testValues,OpenMesh::VertexHandle(4))[0]) << "Wrong list value at Vertex 4";
EXPECT_EQ(12,mesh.property(testValues,OpenMesh::VertexHandle(5))[1]) << "Wrong list value at Vertex 5";
EXPECT_EQ(13,mesh.property(testValues,OpenMesh::VertexHandle(6))[0]) << "Wrong list value at Vertex 6";
EXPECT_EQ(16,mesh.property(testValues,OpenMesh::VertexHandle(7))[1]) << "Wrong list value at Vertex 7";
OpenMesh::FPropHandleT< std::vector<float> > texCoordsPerFace;
ASSERT_TRUE(mesh.get_property_handle(texCoordsPerFace,"texcoords")) << "Could not access texcoords per face";
for (Mesh::FaceIter f_iter = mesh.faces_begin(); f_iter != mesh.faces_end(); ++f_iter)
{
EXPECT_EQ(8u, mesh.property(texCoordsPerFace, *f_iter).size()) << "Texcoords per face container has wrong size on face: " << f_iter->idx();
if (!mesh.property(texCoordsPerFace, *f_iter).empty())
{
EXPECT_EQ(1.0, mesh.property(texCoordsPerFace, *f_iter)[0]) << "Texcoords wrong on index 0 with face: " << f_iter->idx();
EXPECT_EQ(1.0, mesh.property(texCoordsPerFace, *f_iter)[1]) << "Texcoords wrong on index 1 with face: " << f_iter->idx();
EXPECT_EQ(-1.0f, mesh.property(texCoordsPerFace, *f_iter)[2]) << "Texcoords wrong on index 2 with face: " << f_iter->idx();
EXPECT_EQ(-1.0f, mesh.property(texCoordsPerFace, *f_iter)[3]) << "Texcoords wrong on index 3 with face: " << f_iter->idx();
EXPECT_EQ(0.0f, mesh.property(texCoordsPerFace, *f_iter)[4]) << "Texcoords wrong on index 4 with face: " << f_iter->idx();
EXPECT_EQ(0.0f, mesh.property(texCoordsPerFace, *f_iter)[5]) << "Texcoords wrong on index 5 with face: " << f_iter->idx();
EXPECT_EQ(-0.5f, mesh.property(texCoordsPerFace, *f_iter)[6]) << "Texcoords wrong on index 6 with face: " << f_iter->idx();
EXPECT_EQ(-0.5f, mesh.property(texCoordsPerFace, *f_iter)[7]) << "Texcoords wrong on index 7 with face: " << f_iter->idx();
}
}
OpenMesh::FPropHandleT< unsigned > faceIndex;
ASSERT_TRUE(mesh.get_property_handle(faceIndex,"faceIndex")) << "Could not access faceIndex per face";
EXPECT_EQ(0u,mesh.property(faceIndex,OpenMesh::FaceHandle(0))) << "Wrong index value at FaceHandle 0";
EXPECT_EQ(1u,mesh.property(faceIndex,OpenMesh::FaceHandle(1))) << "Wrong index value at FaceHandle 1";
EXPECT_EQ(2u,mesh.property(faceIndex,OpenMesh::FaceHandle(2))) << "Wrong index value at FaceHandle 2";
EXPECT_EQ(3u,mesh.property(faceIndex,OpenMesh::FaceHandle(3))) << "Wrong index value at FaceHandle 3";
EXPECT_EQ(4u,mesh.property(faceIndex,OpenMesh::FaceHandle(4))) << "Wrong index value at FaceHandle 4";
EXPECT_EQ(5u,mesh.property(faceIndex,OpenMesh::FaceHandle(5))) << "Wrong index value at FaceHandle 5";
}
TEST_F(OpenMeshReadWritePLY, WriteReadSimplePLYWithCustomProps) {
@@ -728,4 +921,233 @@ TEST_F(OpenMeshReadWritePLY, LoadSimpleBinaryPLYWithExtraElements) {
EXPECT_EQ(12u, mesh_.n_faces()) << "The number of loaded faces is not correct!";
}
/*
* Ignore a file that does not contain vertices and faces
*/
TEST_F(OpenMeshReadWritePLY, IgnoreNonMeshPlyFile) {
mesh_.clear();
std::stringstream data;
data << "ply" << "\n";
data << "format binary_little_endian 1.0" << "\n";
data << "comment Image data" << "\n";
data << "element image 0" << "\n";
data << "property list uint16 uint16 row" << "\n";
data << "end_header" << "\n";
OpenMesh::IO::Options options = OpenMesh::IO::Options::Binary;
bool ok = OpenMesh::IO::read_mesh(mesh_, data, ".ply", options);
EXPECT_TRUE(ok) << "This empty file should be readable without an error!";
EXPECT_EQ(0u, mesh_.n_vertices()) << "The number of loaded vertices is not correct!";
EXPECT_EQ(0u, mesh_.n_edges()) << "The number of loaded edges is not correct!";
EXPECT_EQ(0u, mesh_.n_faces()) << "The number of loaded faces is not correct!";
}
/*
* Ignore a file that does not contain vertices and faces
*/
TEST_F(OpenMeshReadWritePLY, FailOnUnknownPropertyTypeForLists) {
mesh_.clear();
std::stringstream data;
data << "ply" << "\n";
data << "format binary_little_endian 1.0" << "\n";
data << "comment Image data" << "\n";
data << "element image 0" << "\n";
data << "property list blibb blubb row" << "\n";
data << "end_header" << "\n";
OpenMesh::IO::Options options = OpenMesh::IO::Options::Binary;
bool ok = OpenMesh::IO::read_mesh(mesh_, data, ".ply", options);
EXPECT_FALSE(ok) << "This file should fail to read!";
EXPECT_EQ(0u, mesh_.n_vertices()) << "The number of loaded vertices is not correct!";
EXPECT_EQ(0u, mesh_.n_edges()) << "The number of loaded edges is not correct!";
EXPECT_EQ(0u, mesh_.n_faces()) << "The number of loaded faces is not correct!";
}
/*
* Load an ASCII PLY file of a cube with float RGB face colors
*/
TEST_F(OpenMeshReadWritePLY, LoadSimplePLYWithFaceColors) {
mesh_.clear();
mesh_.request_face_colors();
OpenMesh::IO::Options options;
options += OpenMesh::IO::Options::FaceColor;
bool ok = OpenMesh::IO::read_mesh(mesh_, "cube-minimal-faceColors.ply",options);
EXPECT_TRUE(ok) << "Unable to load cube-minimal-faceColors.ply";
EXPECT_EQ(8u , mesh_.n_vertices()) << "The number of loaded vertices is not correct!";
EXPECT_EQ(18u, mesh_.n_edges()) << "The number of loaded edges is not correct!";
EXPECT_EQ(12u, mesh_.n_faces()) << "The number of loaded faces is not correct!";
#ifdef TEST_DOUBLE_TRAITS
EXPECT_FLOAT_EQ(107/255.0, mesh_.color(mesh_.face_handle(0))[0] ) << "Wrong face color at face 0";
EXPECT_FLOAT_EQ(117/255.0, mesh_.color(mesh_.face_handle(0))[1] ) << "Wrong face color at face 0";
EXPECT_FLOAT_EQ(177/255.0, mesh_.color(mesh_.face_handle(0))[2] ) << "Wrong face color at face 0";
EXPECT_FLOAT_EQ(107/255.0, mesh_.color(mesh_.face_handle(3))[0] ) << "Wrong face color at face 3";
EXPECT_FLOAT_EQ(255/255.0, mesh_.color(mesh_.face_handle(3))[1] ) << "Wrong face color at face 3";
EXPECT_FLOAT_EQ(135/255.0, mesh_.color(mesh_.face_handle(3))[2] ) << "Wrong face color at face 3";
EXPECT_FLOAT_EQ(163/255.0, mesh_.color(mesh_.face_handle(4))[0] ) << "Wrong face color at face 4";
EXPECT_FLOAT_EQ(107/255.0, mesh_.color(mesh_.face_handle(4))[1] ) << "Wrong face color at face 4";
EXPECT_FLOAT_EQ(177/255.0, mesh_.color(mesh_.face_handle(4))[2] ) << "Wrong face color at face 4";
EXPECT_FLOAT_EQ(255/255.0, mesh_.color(mesh_.face_handle(7))[0] ) << "Wrong face color at face 7";
EXPECT_FLOAT_EQ(140/255.0, mesh_.color(mesh_.face_handle(7))[1] ) << "Wrong face color at face 7";
EXPECT_FLOAT_EQ(107/255.0, mesh_.color(mesh_.face_handle(7))[2] ) << "Wrong face color at face 7";
#else
EXPECT_EQ(107, mesh_.color(mesh_.face_handle(0))[0] ) << "Wrong face color at face 0";
EXPECT_EQ(117, mesh_.color(mesh_.face_handle(0))[1] ) << "Wrong face color at face 0";
EXPECT_EQ(177, mesh_.color(mesh_.face_handle(0))[2] ) << "Wrong face color at face 0";
EXPECT_EQ(107, mesh_.color(mesh_.face_handle(3))[0] ) << "Wrong face color at face 3";
EXPECT_EQ(255, mesh_.color(mesh_.face_handle(3))[1] ) << "Wrong face color at face 3";
EXPECT_EQ(135, mesh_.color(mesh_.face_handle(3))[2] ) << "Wrong face color at face 3";
EXPECT_EQ(163, mesh_.color(mesh_.face_handle(4))[0] ) << "Wrong face color at face 4";
EXPECT_EQ(107, mesh_.color(mesh_.face_handle(4))[1] ) << "Wrong face color at face 4";
EXPECT_EQ(177, mesh_.color(mesh_.face_handle(4))[2] ) << "Wrong face color at face 4";
EXPECT_EQ(255, mesh_.color(mesh_.face_handle(7))[0] ) << "Wrong face color at face 7";
EXPECT_EQ(140, mesh_.color(mesh_.face_handle(7))[1] ) << "Wrong face color at face 7";
EXPECT_EQ(107, mesh_.color(mesh_.face_handle(7))[2] ) << "Wrong face color at face 7";
#endif
EXPECT_FALSE(options.vertex_has_normal()) << "Wrong user options are returned!";
EXPECT_FALSE(options.vertex_has_texcoord()) << "Wrong user options are returned!";
EXPECT_FALSE(options.vertex_has_color()) << "Wrong user options are returned!";
EXPECT_TRUE(options.face_has_color()) << "Wrong user options are returned!";
EXPECT_FALSE(options.color_has_alpha()) << "Wrong user options are returned!";
EXPECT_FALSE(options.is_binary()) << "Wrong user options are returned!";
mesh_.release_face_colors();
}
/*
* Write and read PLY files with face colors in various formats
*/
TEST_F(OpenMeshReadWritePLY, WriteAndReadPLYWithFaceColors) {
struct Format {
Format(const char* outFileName, OpenMesh::IO::Options options) :
_outFileName(outFileName),
_options(options)
{}
const char* _outFileName;
const OpenMesh::IO::Options _options;
}
formats[] =
{
Format("cube-minimal-faceColors_ascii_uchar.ply",
OpenMesh::IO::Options::Default),
Format("cube-minimal-faceColors_ascii_float.ply",
OpenMesh::IO::Options::ColorFloat),
Format("cube-minimal-faceColors_binary_uchar.ply",
OpenMesh::IO::Options::Binary),
Format("cube-minimal-faceColors_binary_float.ply",
OpenMesh::IO::Options::Binary | OpenMesh::IO::Options::ColorFloat),
// Test writing/reading alpha values (all default 1.0/255), but the test mesh
// Color type has no alpha channel so there's nothing to test below
Format("cube-minimal-faceColors_alpha_ascii_uchar.ply",
OpenMesh::IO::Options::ColorAlpha),
Format("cube-minimal-faceColors_alpha_ascii_float.ply",
OpenMesh::IO::Options::ColorFloat | OpenMesh::IO::Options::ColorAlpha),
Format("cube-minimal-faceColors_alpha_binary_uchar.ply",
OpenMesh::IO::Options::Binary | OpenMesh::IO::Options::ColorAlpha),
Format("cube-minimal-faceColors_alpha_binary_float.ply",
OpenMesh::IO::Options::Binary | OpenMesh::IO::Options::ColorFloat | OpenMesh::IO::Options::ColorAlpha),
};
for (size_t i = 0; i < sizeof(formats) / sizeof(Format); ++i)
{
const char* outFileName = formats[i]._outFileName;
mesh_.clear();
mesh_.request_face_colors();
OpenMesh::IO::Options options;
options += OpenMesh::IO::Options::FaceColor;
bool ok = OpenMesh::IO::read_mesh(mesh_, "cube-minimal-faceColors.ply", options);
EXPECT_TRUE(ok) << "Unable to load cube-minimal-faceColors.ply";
options = formats[i]._options;
options += OpenMesh::IO::Options::FaceColor;
ok = OpenMesh::IO::write_mesh(mesh_, outFileName, options);
EXPECT_TRUE(ok) << "Unable to write " << outFileName;
// Reset for reading: let the reader determine binary/float/etc.
options = OpenMesh::IO::Options::FaceColor;
mesh_.clear();
ok = OpenMesh::IO::read_mesh(mesh_, outFileName, options);
EXPECT_TRUE(ok) << "Unable to load " << outFileName;
EXPECT_EQ(8u , mesh_.n_vertices()) << "The number of loaded vertices is not correct: " << outFileName;
EXPECT_EQ(18u, mesh_.n_edges()) << "The number of loaded edges is not correct: " << outFileName;
EXPECT_EQ(12u, mesh_.n_faces()) << "The number of loaded faces is not correct: " << outFileName;
#ifdef TEST_DOUBLE_TRAITS
EXPECT_FLOAT_EQ(107/255.0, mesh_.color(mesh_.face_handle(0))[0] ) << "Wrong face color at face 0";
EXPECT_FLOAT_EQ(117/255.0, mesh_.color(mesh_.face_handle(0))[1] ) << "Wrong face color at face 0";
EXPECT_FLOAT_EQ(177/255.0, mesh_.color(mesh_.face_handle(0))[2] ) << "Wrong face color at face 0";
EXPECT_FLOAT_EQ(107/255.0, mesh_.color(mesh_.face_handle(3))[0] ) << "Wrong face color at face 3";
EXPECT_FLOAT_EQ(255/255.0, mesh_.color(mesh_.face_handle(3))[1] ) << "Wrong face color at face 3";
EXPECT_FLOAT_EQ(135/255.0, mesh_.color(mesh_.face_handle(3))[2] ) << "Wrong face color at face 3";
EXPECT_FLOAT_EQ(163/255.0, mesh_.color(mesh_.face_handle(4))[0] ) << "Wrong face color at face 4";
EXPECT_FLOAT_EQ(107/255.0, mesh_.color(mesh_.face_handle(4))[1] ) << "Wrong face color at face 4";
EXPECT_FLOAT_EQ(177/255.0, mesh_.color(mesh_.face_handle(4))[2] ) << "Wrong face color at face 4";
EXPECT_FLOAT_EQ(255/255.0, mesh_.color(mesh_.face_handle(7))[0] ) << "Wrong face color at face 7";
EXPECT_FLOAT_EQ(140/255.0, mesh_.color(mesh_.face_handle(7))[1] ) << "Wrong face color at face 7";
EXPECT_FLOAT_EQ(107/255.0, mesh_.color(mesh_.face_handle(7))[2] ) << "Wrong face color at face 7";
#else
EXPECT_EQ(107, mesh_.color(mesh_.face_handle(0))[0] ) << "Wrong face color at face 0";
EXPECT_EQ(117, mesh_.color(mesh_.face_handle(0))[1] ) << "Wrong face color at face 0";
EXPECT_EQ(177, mesh_.color(mesh_.face_handle(0))[2] ) << "Wrong face color at face 0";
EXPECT_EQ(107, mesh_.color(mesh_.face_handle(3))[0] ) << "Wrong face color at face 3";
EXPECT_EQ(255, mesh_.color(mesh_.face_handle(3))[1] ) << "Wrong face color at face 3";
EXPECT_EQ(135, mesh_.color(mesh_.face_handle(3))[2] ) << "Wrong face color at face 3";
EXPECT_EQ(163, mesh_.color(mesh_.face_handle(4))[0] ) << "Wrong face color at face 4";
EXPECT_EQ(107, mesh_.color(mesh_.face_handle(4))[1] ) << "Wrong face color at face 4";
EXPECT_EQ(177, mesh_.color(mesh_.face_handle(4))[2] ) << "Wrong face color at face 4";
EXPECT_EQ(255, mesh_.color(mesh_.face_handle(7))[0] ) << "Wrong face color at face 7";
EXPECT_EQ(140, mesh_.color(mesh_.face_handle(7))[1] ) << "Wrong face color at face 7";
EXPECT_EQ(107, mesh_.color(mesh_.face_handle(7))[2] ) << "Wrong face color at face 7";
#endif
EXPECT_FALSE(options.vertex_has_normal()) << "Wrong user options are returned: " << outFileName;
EXPECT_FALSE(options.vertex_has_texcoord()) << "Wrong user options are returned: " << outFileName;
EXPECT_FALSE(options.vertex_has_color()) << "Wrong user options are returned: " << outFileName;
EXPECT_TRUE(options.face_has_color()) << "Wrong user options are returned: " << outFileName;
EXPECT_EQ(formats[i]._options.color_is_float(), options.color_is_float()) <<
"Wrong user options are returned: " << outFileName;
EXPECT_EQ(formats[i]._options.is_binary(), options.is_binary()) <<
"Wrong user options are returned: " << outFileName;
mesh_.release_face_colors();
}
}
}

View File

@@ -0,0 +1,566 @@
#include <gtest/gtest.h>
#include <Unittests/unittests_common.hh>
#include <OpenMesh/Core/Mesh/PolyConnectivity.hh>
#include <iostream>
#include <chrono>
namespace {
class OpenMeshSmartHandles : public OpenMeshBase {
protected:
// This function is called before each test is run
virtual void SetUp() {
mesh_.clear();
// Add some vertices
Mesh::VertexHandle vhandle[8];
vhandle[0] = mesh_.add_vertex(Mesh::Point(-1, -1, 1));
vhandle[1] = mesh_.add_vertex(Mesh::Point( 1, -1, 1));
vhandle[2] = mesh_.add_vertex(Mesh::Point( 1, 1, 1));
vhandle[3] = mesh_.add_vertex(Mesh::Point(-1, 1, 1));
vhandle[4] = mesh_.add_vertex(Mesh::Point(-1, -1, -1));
vhandle[5] = mesh_.add_vertex(Mesh::Point( 1, -1, -1));
vhandle[6] = mesh_.add_vertex(Mesh::Point( 1, 1, -1));
vhandle[7] = mesh_.add_vertex(Mesh::Point(-1, 1, -1));
// Add six faces to form a cube
std::vector<Mesh::VertexHandle> face_vhandles;
face_vhandles.clear();
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[3]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[3]);
mesh_.add_face(face_vhandles);
//=======================
face_vhandles.clear();
face_vhandles.push_back(vhandle[7]);
face_vhandles.push_back(vhandle[6]);
face_vhandles.push_back(vhandle[5]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[7]);
face_vhandles.push_back(vhandle[5]);
face_vhandles.push_back(vhandle[4]);
mesh_.add_face(face_vhandles);
//=======================
face_vhandles.clear();
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[4]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[4]);
face_vhandles.push_back(vhandle[5]);
mesh_.add_face(face_vhandles);
//=======================
face_vhandles.clear();
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[5]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[5]);
face_vhandles.push_back(vhandle[6]);
mesh_.add_face(face_vhandles);
//=======================
face_vhandles.clear();
face_vhandles.push_back(vhandle[3]);
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[6]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[3]);
face_vhandles.push_back(vhandle[6]);
face_vhandles.push_back(vhandle[7]);
mesh_.add_face(face_vhandles);
//=======================
face_vhandles.clear();
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[3]);
face_vhandles.push_back(vhandle[7]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[7]);
face_vhandles.push_back(vhandle[4]);
mesh_.add_face(face_vhandles);
// Test setup:
//
//
// 3 ======== 2
// / /|
// / / | z
// 0 ======== 1 | |
// | | | | y
// | 7 | 6 | /
// | | / | /
// | |/ |/
// 4 ======== 5 -------> x
//
// Check setup
EXPECT_EQ(18u, mesh_.n_edges() ) << "Wrong number of Edges";
EXPECT_EQ(36u, mesh_.n_halfedges() ) << "Wrong number of HalfEdges";
EXPECT_EQ(8u, mesh_.n_vertices() ) << "Wrong number of vertices";
EXPECT_EQ(12u, mesh_.n_faces() ) << "Wrong number of faces";
}
// This function is called after all tests are through
virtual void TearDown() {
// Do some final stuff with the member data here...
mesh_.clear();
}
// Member already defined in OpenMeshBase
//Mesh mesh_;
};
/*
* ====================================================================
* Define tests below
* ====================================================================
*/
/* Test if navigation operations on smart handles yield the expected element
*/
TEST_F(OpenMeshSmartHandles, SimpleNavigation)
{
for (auto vh : mesh_.vertices())
{
EXPECT_EQ(mesh_.halfedge_handle(vh), vh.halfedge()) << "outgoing halfedge of vertex does not match";
}
for (auto heh : mesh_.halfedges())
{
EXPECT_EQ(mesh_.next_halfedge_handle(heh), heh.next()) << "next halfedge of halfedge does not match";
EXPECT_EQ(mesh_.prev_halfedge_handle(heh), heh.prev()) << "prevt halfedge of halfedge does not match";
EXPECT_EQ(mesh_.opposite_halfedge_handle(heh), heh.opp()) << "opposite halfedge of halfedge does not match";
EXPECT_EQ(mesh_.to_vertex_handle(heh), heh.to()) << "to vertex handle of halfedge does not match";
EXPECT_EQ(mesh_.from_vertex_handle(heh), heh.from()) << "from vertex handle of halfedge does not match";
EXPECT_EQ(mesh_.face_handle(heh), heh.face()) << "face handle of halfedge does not match";
}
for (auto eh : mesh_.edges())
{
EXPECT_EQ(mesh_.halfedge_handle(eh, 0), eh.h0()) << "halfedge 0 of edge does not match";
EXPECT_EQ(mesh_.halfedge_handle(eh, 1), eh.h1()) << "halfedge 1 of edge does not match";
EXPECT_EQ(mesh_.from_vertex_handle(mesh_.halfedge_handle(eh, 0)), eh.v0()) << "first vertex of edge does not match";
EXPECT_EQ(mesh_.to_vertex_handle (mesh_.halfedge_handle(eh, 0)), eh.v1()) << "second vertex of edge does not match";
}
for (auto fh : mesh_.faces())
{
EXPECT_EQ(mesh_.halfedge_handle(fh), fh.halfedge()) << "halfedge of face does not match";
}
}
/* Test if ranges yield the same elements when using smart handles
*/
TEST_F(OpenMeshSmartHandles, SimpleRanges)
{
for (auto vh : mesh_.vertices())
{
{
std::vector<OpenMesh::VertexHandle> handles0;
std::vector<OpenMesh::VertexHandle> handles1;
for (auto h : mesh_.vv_range(vh))
handles0.push_back(h);
for (auto h : vh.vertices())
handles1.push_back(h);
EXPECT_EQ(handles0, handles1) << "vertex range of vertex does not match";
}
{
std::vector<OpenMesh::HalfedgeHandle> handles0;
std::vector<OpenMesh::HalfedgeHandle> handles1;
for (auto h : mesh_.voh_range(vh))
handles0.push_back(h);
for (auto h : vh.outgoing_halfedges())
handles1.push_back(h);
EXPECT_EQ(handles0, handles1) << "outgoing halfedge range of vertex does not match";
}
{
std::vector<OpenMesh::HalfedgeHandle> handles0;
std::vector<OpenMesh::HalfedgeHandle> handles1;
for (auto h : mesh_.vih_range(vh))
handles0.push_back(h);
for (auto h : vh.incoming_halfedges())
handles1.push_back(h);
EXPECT_EQ(handles0, handles1) << "incoming halfedge range of vertex does not match";
}
{
std::vector<OpenMesh::EdgeHandle> handles0;
std::vector<OpenMesh::EdgeHandle> handles1;
for (auto h : mesh_.ve_range(vh))
handles0.push_back(h);
for (auto h : vh.edges())
handles1.push_back(h);
EXPECT_EQ(handles0, handles1) << "edge range of vertex does not match";
}
{
std::vector<OpenMesh::FaceHandle> handles0;
std::vector<OpenMesh::FaceHandle> handles1;
for (auto h : mesh_.vf_range(vh))
handles0.push_back(h);
for (auto h : vh.faces())
handles1.push_back(h);
EXPECT_EQ(handles0, handles1) << "face range of vertex does not match";
}
}
for (auto fh : mesh_.faces())
{
{
std::vector<OpenMesh::VertexHandle> handles0;
std::vector<OpenMesh::VertexHandle> handles1;
for (auto h : mesh_.fv_range(fh))
handles0.push_back(h);
for (auto h : fh.vertices())
handles1.push_back(h);
EXPECT_EQ(handles0, handles1) << "vertex range of face does not match";
}
{
std::vector<OpenMesh::HalfedgeHandle> handles0;
std::vector<OpenMesh::HalfedgeHandle> handles1;
for (auto h : mesh_.fh_range(fh))
handles0.push_back(h);
for (auto h : fh.halfedges())
handles1.push_back(h);
EXPECT_EQ(handles0, handles1) << "halfedge range of face does not match";
}
{
std::vector<OpenMesh::EdgeHandle> handles0;
std::vector<OpenMesh::EdgeHandle> handles1;
for (auto h : mesh_.fe_range(fh))
handles0.push_back(h);
for (auto h : fh.edges())
handles1.push_back(h);
EXPECT_EQ(handles0, handles1) << "edge range of face does not match";
}
{
std::vector<OpenMesh::FaceHandle> handles0;
std::vector<OpenMesh::FaceHandle> handles1;
for (auto h : mesh_.ff_range(fh))
handles0.push_back(h);
for (auto h : fh.faces())
handles1.push_back(h);
EXPECT_EQ(handles0, handles1) << "face range of face does not match";
}
}
}
/* Test if ranges yield the same elements when using smart handles
*/
TEST_F(OpenMeshSmartHandles, RangesOfRanges)
{
for (auto vh : mesh_.vertices())
{
{
std::vector<OpenMesh::VertexHandle> handles0;
std::vector<OpenMesh::VertexHandle> handles1;
for (auto h : mesh_.vv_range(vh))
for (auto h2 : mesh_.vv_range(h))
handles0.push_back(h2);
for (auto h : vh.vertices())
for (auto h2 : h.vertices())
handles1.push_back(h2);
EXPECT_EQ(handles0, handles1) << "vertex range of vertex range does not match";
}
{
std::vector<OpenMesh::HalfedgeHandle> handles0;
std::vector<OpenMesh::HalfedgeHandle> handles1;
for (auto h : mesh_.vv_range(vh))
for (auto h2 : mesh_.voh_range(h))
handles0.push_back(h2);
for (auto h : vh.vertices())
for (auto h2 : h.outgoing_halfedges())
handles1.push_back(h2);
EXPECT_EQ(handles0, handles1) << "outgoing halfedge range of vertex range does not match";
}
{
std::vector<OpenMesh::HalfedgeHandle> handles0;
std::vector<OpenMesh::HalfedgeHandle> handles1;
for (auto h : mesh_.vv_range(vh))
for (auto h2 : mesh_.vih_range(h))
handles0.push_back(h2);
for (auto h : vh.vertices())
for (auto h2 : h.incoming_halfedges())
handles1.push_back(h2);
EXPECT_EQ(handles0, handles1) << "incoming halfedge range of vertex range does not match";
}
{
std::vector<OpenMesh::EdgeHandle> handles0;
std::vector<OpenMesh::EdgeHandle> handles1;
for (auto h : mesh_.vv_range(vh))
for (auto h2 : mesh_.ve_range(h))
handles0.push_back(h2);
for (auto h : vh.vertices())
for (auto h2 : h.edges())
handles1.push_back(h2);
EXPECT_EQ(handles0, handles1) << "edge range of vertex range does not match";
}
{
std::vector<OpenMesh::FaceHandle> handles0;
std::vector<OpenMesh::FaceHandle> handles1;
for (auto h : mesh_.vv_range(vh))
for (auto h2 : mesh_.vf_range(h))
handles0.push_back(h2);
for (auto h : vh.vertices())
for (auto h2 : h.faces())
handles1.push_back(h2);
EXPECT_EQ(handles0, handles1) << "face range of vertex range does not match";
}
{
std::vector<OpenMesh::VertexHandle> handles0;
std::vector<OpenMesh::VertexHandle> handles1;
for (auto h : mesh_.vf_range(vh))
for (auto h2 : mesh_.fv_range(h))
handles0.push_back(h2);
for (auto h : vh.faces())
for (auto h2 : h.vertices())
handles1.push_back(h2);
EXPECT_EQ(handles0, handles1) << "vertex range of face range does not match";
}
{
std::vector<OpenMesh::HalfedgeHandle> handles0;
std::vector<OpenMesh::HalfedgeHandle> handles1;
for (auto h : mesh_.vf_range(vh))
for (auto h2 : mesh_.fh_range(h))
handles0.push_back(h2);
for (auto h : vh.faces())
for (auto h2 : h.halfedges())
handles1.push_back(h2);
EXPECT_EQ(handles0, handles1) << "vertex range of face range does not match";
}
{
std::vector<OpenMesh::FaceHandle> handles0;
std::vector<OpenMesh::FaceHandle> handles1;
for (auto h : mesh_.vf_range(vh))
for (auto h2 : mesh_.ff_range(h))
handles0.push_back(h2);
for (auto h : vh.faces())
for (auto h2 : h.faces())
handles1.push_back(h2);
EXPECT_EQ(handles0, handles1) << "vertex range of face range does not match";
}
}
}
/* Test a chain of navigation on a cube
*/
TEST_F(OpenMeshSmartHandles, ComplicatedNavigtaion)
{
for (auto vh : mesh_.vertices())
{
EXPECT_EQ(mesh_.next_halfedge_handle(
mesh_.opposite_halfedge_handle(
mesh_.halfedge_handle(vh))),
vh.out().opp().next());
EXPECT_EQ(mesh_.prev_halfedge_handle(
mesh_.prev_halfedge_handle(
mesh_.opposite_halfedge_handle(
mesh_.next_halfedge_handle(
mesh_.next_halfedge_handle(
mesh_.halfedge_handle(vh)))))),
vh.out().next().next().opp().prev().prev());
EXPECT_EQ(mesh_.face_handle(
mesh_.opposite_halfedge_handle(
mesh_.halfedge_handle(
mesh_.face_handle(
mesh_.opposite_halfedge_handle(
mesh_.next_halfedge_handle(
mesh_.halfedge_handle(vh))))))),
vh.out().next().opp().face().halfedge().opp().face());
}
}
/* Test performance of smart handles
*/
TEST_F(OpenMeshSmartHandles, Performance)
{
#if NDEBUG
int n_tests = 10000000;
#else
int n_tests = 300000;
#endif
auto t_before_old = std::chrono::high_resolution_clock::now();
std::vector<OpenMesh::HalfedgeHandle> halfedges0;
for (int i = 0; i < n_tests; ++i)
{
for (auto vh : mesh_.vertices())
{
auto heh = mesh_.prev_halfedge_handle(
mesh_.prev_halfedge_handle(
mesh_.opposite_halfedge_handle(
mesh_.next_halfedge_handle(
mesh_.next_halfedge_handle(
mesh_.halfedge_handle(vh))))));
if (i == 0)
halfedges0.push_back(heh);
}
}
auto t_after_old = std::chrono::high_resolution_clock::now();
std::vector<OpenMesh::HalfedgeHandle> halfedges1;
for (int i = 0; i < n_tests; ++i)
{
for (auto vh : mesh_.vertices())
{
auto heh = vh.out().next().next().opp().prev().prev();
if (i == 0)
halfedges1.push_back(heh);
}
}
auto t_after_new = std::chrono::high_resolution_clock::now();
std::cout << "Conventional navigation took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_after_old-t_before_old).count() << "ms" << std::endl;
std::cout << "SmartHandle navigation took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_after_new-t_after_old ).count() << "ms" << std::endl;
EXPECT_EQ(halfedges0, halfedges1) << "halfedges do not match";
}
/* Mix old and new api
*/
TEST_F(OpenMeshSmartHandles, MixOldAndNew)
{
for (OpenMesh::SmartHalfedgeHandle heh : mesh_.halfedges())
{
heh = mesh_.opposite_halfedge_handle(heh);
EXPECT_TRUE((std::is_same<OpenMesh::SmartEdgeHandle, decltype(OpenMesh::PolyConnectivity::s_edge_handle(heh))>::value));
EXPECT_TRUE((std::is_same<OpenMesh::SmartEdgeHandle, decltype(mesh_.edge_handle(heh))>::value));
EXPECT_TRUE((std::is_same<OpenMesh::SmartFaceHandle, decltype(mesh_.face_handle(heh))>::value));
}
}
/* comparability
*/
TEST_F(OpenMeshSmartHandles, ComparisionBetweenSmartHandleAndNormalHandles)
{
OpenMesh::VertexHandle vh(0);
OpenMesh::SmartVertexHandle svh(0, &mesh_);
EXPECT_EQ(vh, svh) << "Vertex handle and smart vertex handle are different";
std::vector<OpenMesh::VertexHandle> vertices = mesh_.vertices().to_vector([](OpenMesh::SmartVertexHandle _svh) { return OpenMesh::VertexHandle(_svh); });
std::replace(vertices.begin(), vertices.end(), OpenMesh::VertexHandle(0), OpenMesh::VertexHandle(1));
EXPECT_EQ(vertices[0], OpenMesh::VertexHandle(1));
std::vector<OpenMesh::SmartVertexHandle> smart_vertices = mesh_.vertices().to_vector();
std::replace(smart_vertices.begin(), smart_vertices.end(), OpenMesh::SmartVertexHandle(0, &mesh_), OpenMesh::SmartVertexHandle(1, &mesh_));
EXPECT_EQ(smart_vertices[0], OpenMesh::VertexHandle(1));
EXPECT_EQ(smart_vertices[0], OpenMesh::SmartVertexHandle(1, &mesh_));
std::replace(vertices.begin(), vertices.end(), OpenMesh::SmartVertexHandle(1, &mesh_), OpenMesh::SmartVertexHandle(2, &mesh_));
EXPECT_EQ(vertices[0], OpenMesh::VertexHandle(2));
}
TEST(OpenMeshSmartHandlesNoFixture, AddingFacesPolyMesh)
{
using MyMesh = OpenMesh::PolyMesh_ArrayKernelT<>;
MyMesh mesh;
std::vector<OpenMesh::SmartVertexHandle> vertices;
for (int i = 0; i < 4; ++i)
vertices.push_back(mesh.add_vertex(MyMesh::Point()));
auto fh = mesh.add_face(vertices);
for (auto heh : fh.halfedges())
{
heh = heh.next();
}
}
TEST(OpenMeshSmartHandlesNoFixture, AddingFacesTriMesh)
{
using MyMesh = OpenMesh::TriMesh_ArrayKernelT<>;
MyMesh mesh;
std::vector<OpenMesh::SmartVertexHandle> vertices;
for (int i = 0; i < 4; ++i)
vertices.push_back(mesh.add_vertex(MyMesh::Point()));
auto fh = mesh.add_face(vertices);
for (auto heh : fh.halfedges())
{
heh = heh.next();
}
}
TEST(OpenMeshSmartHandlesNoFixture, SplitTriMesh)
{
using MyMesh = OpenMesh::TriMesh_ArrayKernelT<>;
MyMesh mesh;
std::vector<OpenMesh::SmartVertexHandle> vertices;
for (int i = 0; i < 3; ++i)
vertices.push_back(mesh.add_vertex(MyMesh::Point()));
auto fh = mesh.add_face(vertices);
auto p = (MyMesh::Point());
OpenMesh::SmartVertexHandle vh = mesh.split(fh, p);
OpenMesh::SmartEdgeHandle eh = fh.halfedge().edge();
OpenMesh::SmartVertexHandle vh2 = mesh.split(eh, p);
EXPECT_NE(vh.idx(), vh2.idx()) << "This was only intended to fix an unused variable warning but cool that it caugth an actual error now";
}
}

View File

@@ -0,0 +1,391 @@
#include <gtest/gtest.h>
#include <Unittests/unittests_common.hh>
#include <OpenMesh/Core/Mesh/PolyConnectivity.hh>
#include <OpenMesh/Core/Utils/PropertyManager.hh>
#include <iostream>
#include <chrono>
namespace {
class OpenMeshSmartRanges : public OpenMeshBase {
protected:
// This function is called before each test is run
virtual void SetUp() {
mesh_.clear();
// Add some vertices
Mesh::VertexHandle vhandle[8];
vhandle[0] = mesh_.add_vertex(Mesh::Point(-1, -1, 1));
vhandle[1] = mesh_.add_vertex(Mesh::Point( 1, -1, 1));
vhandle[2] = mesh_.add_vertex(Mesh::Point( 1, 1, 1));
vhandle[3] = mesh_.add_vertex(Mesh::Point(-1, 1, 1));
vhandle[4] = mesh_.add_vertex(Mesh::Point(-1, -1, -1));
vhandle[5] = mesh_.add_vertex(Mesh::Point( 1, -1, -1));
vhandle[6] = mesh_.add_vertex(Mesh::Point( 1, 1, -1));
vhandle[7] = mesh_.add_vertex(Mesh::Point(-1, 1, -1));
// Add six faces to form a cube
std::vector<Mesh::VertexHandle> face_vhandles;
face_vhandles.clear();
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[3]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[3]);
mesh_.add_face(face_vhandles);
//=======================
face_vhandles.clear();
face_vhandles.push_back(vhandle[7]);
face_vhandles.push_back(vhandle[6]);
face_vhandles.push_back(vhandle[5]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[7]);
face_vhandles.push_back(vhandle[5]);
face_vhandles.push_back(vhandle[4]);
mesh_.add_face(face_vhandles);
//=======================
face_vhandles.clear();
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[4]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[4]);
face_vhandles.push_back(vhandle[5]);
mesh_.add_face(face_vhandles);
//=======================
face_vhandles.clear();
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[5]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[5]);
face_vhandles.push_back(vhandle[6]);
mesh_.add_face(face_vhandles);
//=======================
face_vhandles.clear();
face_vhandles.push_back(vhandle[3]);
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[6]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[3]);
face_vhandles.push_back(vhandle[6]);
face_vhandles.push_back(vhandle[7]);
mesh_.add_face(face_vhandles);
//=======================
face_vhandles.clear();
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[3]);
face_vhandles.push_back(vhandle[7]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[7]);
face_vhandles.push_back(vhandle[4]);
mesh_.add_face(face_vhandles);
// Test setup:
//
//
// 3 ======== 2
// / /|
// / / | z
// 0 ======== 1 | |
// | | | | y
// | 7 | 6 | /
// | | / | /
// | |/ |/
// 4 ======== 5 -------> x
//
// Check setup
EXPECT_EQ(18u, mesh_.n_edges() ) << "Wrong number of Edges";
EXPECT_EQ(36u, mesh_.n_halfedges() ) << "Wrong number of HalfEdges";
EXPECT_EQ(8u, mesh_.n_vertices() ) << "Wrong number of vertices";
EXPECT_EQ(12u, mesh_.n_faces() ) << "Wrong number of faces";
}
// This function is called after all tests are through
virtual void TearDown() {
// Do some final stuff with the member data here...
mesh_.clear();
}
// Member already defined in OpenMeshBase
//Mesh mesh_;
};
/*
* ====================================================================
* Define tests below
* ====================================================================
*/
template <typename HandleT>
struct F
{
unsigned int operator()(HandleT ) { return 1; }
};
/* Test if smart ranges work
*/
TEST_F(OpenMeshSmartRanges, Sum)
{
auto one = [](OpenMesh::VertexHandle ) { return 1u; };
EXPECT_EQ(mesh_.vertices().sum(one), mesh_.n_vertices());
EXPECT_EQ(mesh_.vertices().sum(F<OpenMesh::VertexHandle>()), mesh_.n_vertices());
EXPECT_EQ(mesh_.halfedges().sum(F<OpenMesh::HalfedgeHandle>()), mesh_.n_halfedges());
EXPECT_EQ(mesh_.edges().sum(F<OpenMesh::EdgeHandle>()), mesh_.n_edges());
EXPECT_EQ(mesh_.faces().sum(F<OpenMesh::FaceHandle>()), mesh_.n_faces());
for (auto vh : mesh_.vertices())
EXPECT_EQ(vh.vertices().sum(F<OpenMesh::VertexHandle>()), mesh_.valence(vh));
for (auto vh : mesh_.vertices())
EXPECT_EQ(vh.faces().sum(F<OpenMesh::FaceHandle>()), mesh_.valence(vh));
for (auto vh : mesh_.vertices())
EXPECT_EQ(vh.outgoing_halfedges().sum(F<OpenMesh::HalfedgeHandle>()), mesh_.valence(vh));
for (auto vh : mesh_.vertices())
EXPECT_EQ(vh.incoming_halfedges().sum(F<OpenMesh::HalfedgeHandle>()), mesh_.valence(vh));
for (auto fh : mesh_.faces())
EXPECT_EQ(fh.vertices().sum(F<OpenMesh::VertexHandle>()), mesh_.valence(fh));
for (auto fh : mesh_.faces())
EXPECT_EQ(fh.halfedges().sum(F<OpenMesh::HalfedgeHandle>()), mesh_.valence(fh));
for (auto fh : mesh_.faces())
EXPECT_EQ(fh.edges().sum(F<OpenMesh::EdgeHandle>()), mesh_.valence(fh));
for (auto fh : mesh_.faces())
EXPECT_EQ(fh.faces().sum(F<OpenMesh::FaceHandle>()), 3u);
}
/* Test if Property Manager can be used in smart ranges
*/
TEST_F(OpenMeshSmartRanges, PropertyManagerAsFunctor)
{
OpenMesh::VProp<Mesh::Point> myPos(mesh_);
for (auto vh : mesh_.vertices())
myPos(vh) = mesh_.point(vh);
Mesh::Point cog(0,0,0);
for (auto vh : mesh_.vertices())
cog += mesh_.point(vh);
cog /= mesh_.n_vertices();
auto cog2 = mesh_.vertices().avg(myPos);
EXPECT_LT(norm(cog - cog2), 0.00001) << "Computed center of gravities are significantly different.";
}
/* Test to vector
*/
TEST_F(OpenMeshSmartRanges, ToVector)
{
OpenMesh::HProp<OpenMesh::Vec2d> uvs(mesh_);
for (auto heh : mesh_.halfedges())
uvs(heh) = OpenMesh::Vec2d(heh.idx(), (heh.idx() * 13)%7);
for (auto fh : mesh_.faces())
{
auto tri_uvs = fh.halfedges().to_vector(uvs);
auto heh_handles = fh.halfedges().to_vector();
for (auto heh : heh_handles)
heh.next();
}
auto vertex_vec = mesh_.vertices().to_vector();
for (auto vh : vertex_vec)
vh.out();
}
/* Test to array
*/
TEST_F(OpenMeshSmartRanges, ToArray)
{
OpenMesh::HProp<OpenMesh::Vec2d> uvs(mesh_);
for (auto heh : mesh_.halfedges())
uvs(heh) = OpenMesh::Vec2d(heh.idx(), (heh.idx() * 13)%7);
for (auto fh : mesh_.faces())
{
fh.halfedges().to_array<3>(uvs);
fh.halfedges().to_array<3>();
}
}
/* Test bounding box
*/
TEST_F(OpenMeshSmartRanges, BoundingBox)
{
// The custom vecs OpenMesh are tested with here do not implement a min or max function.
// Thus we convert here.
OpenMesh::VProp<OpenMesh::Vec3f> myPos(mesh_);
for (auto vh : mesh_.vertices())
for (size_t i = 0; i < 3; ++i)
myPos(vh)[i] = mesh_.point(vh)[i];
auto bb_min = mesh_.vertices().min(myPos);
auto bb_max = mesh_.vertices().max(myPos);
mesh_.vertices().minmax(myPos);
EXPECT_LT(norm(bb_min - OpenMesh::Vec3f(-1,-1,-1)), 0.000001) << "Bounding box minimum seems off";
EXPECT_LT(norm(bb_max - OpenMesh::Vec3f( 1, 1, 1)), 0.000001) << "Bounding box maximum seems off";
auto uvs = OpenMesh::makeTemporaryProperty<OpenMesh::HalfedgeHandle, OpenMesh::Vec2d>(mesh_);
for (auto heh : mesh_.halfedges())
uvs(heh) = OpenMesh::Vec2d(heh.idx(), (heh.idx() * 13)%7);
for (auto fh : mesh_.faces())
{
fh.halfedges().min(uvs);
fh.halfedges().max(uvs);
}
}
/* Test for each
*/
TEST_F(OpenMeshSmartRanges, ForEach)
{
std::vector<int> vec;
auto f = [&vec](OpenMesh::VertexHandle vh) { vec.push_back(vh.idx()); };
mesh_.vertices().for_each(f);
ASSERT_EQ(vec.size(), mesh_.n_vertices()) << "vec has wrong size";
for (size_t i = 0; i < vec.size(); ++i)
EXPECT_EQ(vec[i], i) << "wrong index in vector";
}
/* Test filter
*/
TEST_F(OpenMeshSmartRanges, Filtered)
{
using VH = OpenMesh::VertexHandle;
using FH = OpenMesh::FaceHandle;
auto is_even = [](VH vh) { return vh.idx() % 2 == 0; };
auto is_odd = [](VH vh) { return vh.idx() % 2 == 1; };
auto is_divisible_by_3 = [](VH vh) { return vh.idx() % 3 == 0; };
auto to_id = [](VH vh) { return vh.idx(); };
auto even_vertices = mesh_.vertices().filtered(is_even).to_vector(to_id);
EXPECT_EQ(even_vertices.size(), 4);
EXPECT_EQ(even_vertices[0], 0);
EXPECT_EQ(even_vertices[1], 2);
EXPECT_EQ(even_vertices[2], 4);
EXPECT_EQ(even_vertices[3], 6);
auto odd_vertices = mesh_.vertices().filtered(is_odd).to_vector(to_id);
EXPECT_EQ(odd_vertices.size(), 4);
EXPECT_EQ(odd_vertices[0], 1);
EXPECT_EQ(odd_vertices[1], 3);
EXPECT_EQ(odd_vertices[2], 5);
EXPECT_EQ(odd_vertices[3], 7);
auto even_3_vertices = mesh_.vertices().filtered(is_even).filtered(is_divisible_by_3).to_vector(to_id);
EXPECT_EQ(even_3_vertices.size(), 2);
EXPECT_EQ(even_3_vertices[0], 0);
EXPECT_EQ(even_3_vertices[1], 6);
auto odd_3_vertices = mesh_.vertices().filtered(is_odd).filtered(is_divisible_by_3).to_vector(to_id);
EXPECT_EQ(odd_3_vertices.size(), 1);
EXPECT_EQ(odd_3_vertices[0], 3);
// create a vector of vertices in the order they are visited when iterating over face vertices, but every vertex only once
std::vector<VH> vertices;
OpenMesh::VProp<bool> to_be_processed(true, mesh_);
auto store_vertex = [&](VH vh) { to_be_processed(vh) = false; vertices.push_back(vh); };
for (auto fh : mesh_.faces())
fh.vertices().filtered(to_be_processed).for_each(store_vertex);
EXPECT_EQ(vertices.size(), mesh_.n_vertices()) << " number of visited vertices not correct";
EXPECT_TRUE(mesh_.vertices().all_of([&](VH vh) { return !to_be_processed(vh); })) << "did not visit all vertices";
{
OpenMesh::FProp<bool> to_be_visited(true, mesh_);
int visited_faces_in_main_loop = 0;
int visited_faces_in_sub_loop = 0;
for (auto fh : mesh_.faces().filtered(to_be_visited))
{
to_be_visited(fh) = false;
++visited_faces_in_main_loop;
for (auto neighbor : fh.faces().filtered(to_be_visited))
{
to_be_visited(neighbor) = false;
++visited_faces_in_sub_loop;
}
}
EXPECT_LT(visited_faces_in_main_loop, mesh_.n_faces()) << "Visted more faces than expected";
EXPECT_TRUE(mesh_.faces().all_of([&](FH fh) { return !to_be_visited(fh); })) << "did not visit all faces";
EXPECT_EQ(visited_faces_in_main_loop + visited_faces_in_sub_loop, mesh_.n_faces()) << "Did not visited all faces exactly once";
}
{
OpenMesh::FProp<bool> to_be_visited(true, mesh_);
const auto& to_be_visited_const_ref = to_be_visited;
int visited_faces_in_main_loop = 0;
int visited_faces_in_sub_loop = 0;
for (auto fh : mesh_.faces().filtered(to_be_visited_const_ref))
{
to_be_visited(fh) = false;
++visited_faces_in_main_loop;
for (auto neighbor : fh.faces().filtered(to_be_visited_const_ref))
{
to_be_visited(neighbor) = false;
++visited_faces_in_sub_loop;
}
}
EXPECT_LT(visited_faces_in_main_loop, mesh_.n_faces()) << "Visted more faces than expected";
EXPECT_TRUE(mesh_.faces().all_of([&](FH fh) { return !to_be_visited(fh); })) << "did not visit all faces";
EXPECT_EQ(visited_faces_in_main_loop + visited_faces_in_sub_loop, mesh_.n_faces()) << "Did not visited all faces exactly once";
}
}
}

View File

@@ -0,0 +1,252 @@
#include <gtest/gtest.h>
#include <Unittests/unittests_common.hh>
#include <iostream>
#include <OpenMesh/Tools/SmartTagger/SmartTaggerT.hh>
namespace {
class OpenMeshSmartTagger : public OpenMeshBase {
protected:
// This function is called before each test is run
virtual void SetUp() {
// Do some initial stuff with the member data here...
}
// 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 SmartTagger on vertices
*/
TEST_F(OpenMeshSmartTagger, SmartTaggerVertices) {
mesh_.clear();
// Add some vertices
Mesh::VertexHandle vhandle[7];
vhandle[0] = mesh_.add_vertex(Mesh::Point(0, 1, 0));
vhandle[1] = mesh_.add_vertex(Mesh::Point(1, 0, 0));
vhandle[2] = mesh_.add_vertex(Mesh::Point(2, 1, 0));
vhandle[3] = mesh_.add_vertex(Mesh::Point(0,-1, 0));
vhandle[4] = mesh_.add_vertex(Mesh::Point(2,-1, 0));
vhandle[5] = mesh_.add_vertex(Mesh::Point(3, 0, 0));
// Add two faces
std::vector<Mesh::VertexHandle> face_vhandles;
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[2]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[3]);
face_vhandles.push_back(vhandle[4]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[3]);
face_vhandles.push_back(vhandle[1]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[4]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[5]);
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[4]);
mesh_.add_face(face_vhandles);
/* Test setup:
0 ==== 2
|\ /|\
| \ / | \
| 1 | 5
| / \ | /
|/ \|/
3 ==== 4
*/
OpenMesh::SmartTaggerVT< Mesh > tagger(mesh_);
EXPECT_FALSE( tagger.is_tagged(vhandle[0] ) ) << "Vertex should be untagged after init!";
EXPECT_FALSE( tagger.is_tagged(vhandle[1] ) ) << "Vertex should be untagged after init!";
EXPECT_FALSE( tagger.is_tagged(vhandle[2] ) ) << "Vertex should be untagged after init!";
EXPECT_FALSE( tagger.is_tagged(vhandle[3] ) ) << "Vertex should be untagged after init!";
EXPECT_FALSE( tagger.is_tagged(vhandle[4] ) ) << "Vertex should be untagged after init!";
EXPECT_FALSE( tagger.is_tagged(vhandle[5] ) ) << "Vertex should be untagged after init!";
// Reset tagged flag on all vertices
tagger.untag_all();
EXPECT_FALSE( tagger.is_tagged(vhandle[0] ) ) << "Vertex should be untagged after first untag_all!";
EXPECT_FALSE( tagger.is_tagged(vhandle[1] ) ) << "Vertex should be untagged after first untag_all!";
EXPECT_FALSE( tagger.is_tagged(vhandle[2] ) ) << "Vertex should be untagged after first untag_all!";
EXPECT_FALSE( tagger.is_tagged(vhandle[3] ) ) << "Vertex should be untagged after first untag_all!";
EXPECT_FALSE( tagger.is_tagged(vhandle[4] ) ) << "Vertex should be untagged after first untag_all!";
EXPECT_FALSE( tagger.is_tagged(vhandle[5] ) ) << "Vertex should be untagged after first untag_all!";
// Set tagged:
tagger.set_tag(vhandle[2]);
tagger.set_tag(vhandle[4]);
EXPECT_FALSE( tagger.is_tagged(vhandle[0] ) ) << "Vertex should be untagged!";
EXPECT_FALSE( tagger.is_tagged(vhandle[1] ) ) << "Vertex should be untagged!";
EXPECT_TRUE( tagger.is_tagged(vhandle[2] ) ) << "Vertex should be tagged!";
EXPECT_FALSE( tagger.is_tagged(vhandle[3] ) ) << "Vertex should be untagged!";
EXPECT_TRUE( tagger.is_tagged(vhandle[4] ) ) << "Vertex should be tagged!";
EXPECT_FALSE( tagger.is_tagged(vhandle[5] ) ) << "Vertex should be untagged!";
// Reset tagged flag on all vertices
tagger.untag_all();
EXPECT_FALSE( tagger.is_tagged(vhandle[0] ) ) << "Vertex should be untagged after second untag_all!";
EXPECT_FALSE( tagger.is_tagged(vhandle[1] ) ) << "Vertex should be untagged after second untag_all!";
EXPECT_FALSE( tagger.is_tagged(vhandle[2] ) ) << "Vertex should be untagged after second untag_all!";
EXPECT_FALSE( tagger.is_tagged(vhandle[3] ) ) << "Vertex should be untagged after second untag_all!";
EXPECT_FALSE( tagger.is_tagged(vhandle[4] ) ) << "Vertex should be untagged after second untag_all!";
EXPECT_FALSE( tagger.is_tagged(vhandle[5] ) ) << "Vertex should be untagged after second untag_all!";
}
/* Checks SmartTagger on vertices
*/
TEST_F(OpenMeshSmartTagger, SmartTaggerFaces) {
mesh_.clear();
// Add some vertices
Mesh::VertexHandle vhandle[7];
vhandle[0] = mesh_.add_vertex(Mesh::Point(0, 1, 0));
vhandle[1] = mesh_.add_vertex(Mesh::Point(1, 0, 0));
vhandle[2] = mesh_.add_vertex(Mesh::Point(2, 1, 0));
vhandle[3] = mesh_.add_vertex(Mesh::Point(0,-1, 0));
vhandle[4] = mesh_.add_vertex(Mesh::Point(2,-1, 0));
vhandle[5] = mesh_.add_vertex(Mesh::Point(3, 0, 0));
// Add two faces
std::vector<Mesh::VertexHandle> face_vhandles;
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[2]);
Mesh::FaceHandle fh1 = mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[3]);
face_vhandles.push_back(vhandle[4]);
Mesh::FaceHandle fh2 = mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[3]);
face_vhandles.push_back(vhandle[1]);
Mesh::FaceHandle fh3 = mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[4]);
Mesh::FaceHandle fh4 = mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[5]);
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[4]);
Mesh::FaceHandle fh5 = mesh_.add_face(face_vhandles);
/* Test setup:
0 ==== 2
|\ /|\
| \ / | \
| 1 | 5
| / \ | /
|/ \|/
3 ==== 4
*/
OpenMesh::SmartTaggerFT< Mesh > tagger(mesh_);
EXPECT_FALSE( tagger.is_tagged( fh1 ) ) << "Face should be untagged after init!";
EXPECT_FALSE( tagger.is_tagged( fh2 ) ) << "Face should be untagged after init!";
EXPECT_FALSE( tagger.is_tagged( fh3 ) ) << "Face should be untagged after init!";
EXPECT_FALSE( tagger.is_tagged( fh4 ) ) << "Face should be untagged after init!";
EXPECT_FALSE( tagger.is_tagged( fh5 ) ) << "Face should be untagged after init!";
// Reset tagged flag on all vertices
tagger.untag_all();
EXPECT_FALSE( tagger.is_tagged( fh1 ) ) << "Face should be untagged after first untag_all!";
EXPECT_FALSE( tagger.is_tagged( fh2 ) ) << "Face should be untagged after first untag_all!";
EXPECT_FALSE( tagger.is_tagged( fh3 ) ) << "Face should be untagged after first untag_all!";
EXPECT_FALSE( tagger.is_tagged( fh4 ) ) << "Face should be untagged after first untag_all!";
EXPECT_FALSE( tagger.is_tagged( fh5 ) ) << "Face should be untagged after first untag_all!";
// Set tagged:
tagger.set_tag(fh3);
tagger.set_tag(fh5);
EXPECT_FALSE( tagger.is_tagged(fh1 ) ) << "Face should be untagged!";
EXPECT_FALSE( tagger.is_tagged(fh2 ) ) << "Face should be untagged!";
EXPECT_TRUE( tagger.is_tagged(fh3 ) ) << "Face should be tagged!";
EXPECT_FALSE( tagger.is_tagged(fh4 ) ) << "Face should be tagged!";
EXPECT_TRUE( tagger.is_tagged(fh5 ) ) << "Face should be tagged!";
// Reset tagged flag on all vertices
tagger.untag_all();
EXPECT_FALSE( tagger.is_tagged( fh1 ) ) << "Face should be untagged after second untag_all!";
EXPECT_FALSE( tagger.is_tagged( fh2 ) ) << "Face should be untagged after second untag_all!";
EXPECT_FALSE( tagger.is_tagged( fh3 ) ) << "Face should be untagged after second untag_all!";
EXPECT_FALSE( tagger.is_tagged( fh4 ) ) << "Face should be untagged after second untag_all!";
EXPECT_FALSE( tagger.is_tagged( fh5 ) ) << "Face should be untagged after second untag_all!";
}
}

View File

@@ -91,13 +91,15 @@ TEST_F(OpenMeshSplitEdgeCopyTriangleMesh, SplitEdgeCopyTriangleMesh) {
//set internal property
mesh_.status(eh).set_tagged(true);
// split face with new vertex
mesh_.split_edge_copy(eh, vhandle[3]);
// split edge with new vertex
mesh_.split_copy(eh, vhandle[3]);
// Check setup
Mesh::EdgeHandle eh0 = mesh_.edge_handle( mesh_.next_halfedge_handle( mesh_.halfedge_handle(eh, 1) ) );
EXPECT_EQ(999, mesh_.property(eprop_int, eh0)) << "Different Property value";
EXPECT_TRUE(mesh_.status(eh0).tagged()) << "Different internal property value";
EXPECT_EQ(3u, mesh_.valence(fh)) << "Face of TriMesh has valence other than 3";
}
/* splits an edge that has a property in a poly mesh with split_edge_copy
@@ -125,7 +127,7 @@ TEST_F(OpenMeshSplitEdgeCopyPolyMesh, SplitEdgeCopyPolymesh) {
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[3]);
PolyMesh::FaceHandle fh = mesh_.add_face(face_vhandles);
mesh_.add_face(face_vhandles);
PolyMesh::EdgeHandle eh = *mesh_.edges_begin();
// Test setup:
@@ -152,4 +154,102 @@ TEST_F(OpenMeshSplitEdgeCopyPolyMesh, SplitEdgeCopyPolymesh) {
EXPECT_EQ(999, mesh_.property(eprop_int, eh0)) << "Different Property value";
EXPECT_TRUE(mesh_.status(eh0).tagged()) << "Different internal property value";
}
/* splits an edge in a triangle mesh that has a face property with split_edge_copy
* the property should be copied to the new edge
*/
TEST_F(OpenMeshSplitEdgeCopyTriangleMesh, SplitEdgeCopyFacePropertiesTriangleMesh) {
mesh_.clear();
mesh_.request_edge_status();
mesh_.request_face_status();
static_assert(std::is_same<decltype (mesh_), Mesh>::value, "Mesh is not a triangle mesh");
// 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));
Mesh::VertexHandle inner_vertex = mesh_.add_vertex(Mesh::Point(0.5, 0.5, 0));
Mesh::VertexHandle boundary_vertex = mesh_.add_vertex(Mesh::Point(0.0, 0.5, 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::FaceHandle fh0 = 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::FaceHandle fh1 = mesh_.add_face(face_vhandles);
Mesh::EdgeHandle inner_edge = Mesh::EdgeHandle(2);
EXPECT_EQ(mesh_.n_faces(), 2u);
// Test setup:
// 1 --- 2
// | / |
// | / |
// | / |
// 0 --- 3
// set property
OpenMesh::FPropHandleT<int> fprop_int;
mesh_.add_property(fprop_int);
mesh_.property(fprop_int, fh0) = 13;
mesh_.property(fprop_int, fh1) = 17;
//set internal property
mesh_.status(fh0).set_tagged(true);
// 2 to 4 split
mesh_.split_copy(inner_edge, inner_vertex);
EXPECT_EQ(mesh_.n_faces(), 4u);
for (auto fh : mesh_.faces())
{
EXPECT_EQ(3u, mesh_.valence(fh));
}
// Check setup
Mesh::HalfedgeHandle heh21 = mesh_.find_halfedge(vhandle[2], vhandle[1]);
Mesh::HalfedgeHandle heh10 = mesh_.find_halfedge(vhandle[1], vhandle[0]);
Mesh::HalfedgeHandle heh03 = mesh_.find_halfedge(vhandle[0], vhandle[3]);
Mesh::HalfedgeHandle heh32 = mesh_.find_halfedge(vhandle[3], vhandle[2]);
EXPECT_EQ(13, mesh_.property(fprop_int, mesh_.face_handle(heh21))) << "Different Property value";
EXPECT_EQ(13, mesh_.property(fprop_int, mesh_.face_handle(heh10))) << "Different Property value";
EXPECT_EQ(17, mesh_.property(fprop_int, mesh_.face_handle(heh03))) << "Different Property value";
EXPECT_EQ(17, mesh_.property(fprop_int, mesh_.face_handle(heh32))) << "Different Property value";
EXPECT_TRUE(mesh_.status(mesh_.face_handle(heh21)).tagged()) << "Different internal property value";
EXPECT_TRUE(mesh_.status(mesh_.face_handle(heh10)).tagged()) << "Different internal property value";
EXPECT_FALSE(mesh_.status(mesh_.face_handle(heh03)).tagged()) << "Different internal property value";
EXPECT_FALSE(mesh_.status(mesh_.face_handle(heh32)).tagged()) << "Different internal property value";
// also test boundary split
Mesh::EdgeHandle boundary_edge = mesh_.edge_handle(heh10);
// 1 to 2 split
mesh_.split_copy(boundary_edge, boundary_vertex);
Mesh::HalfedgeHandle heh1b = mesh_.find_halfedge(vhandle[1], boundary_vertex);
Mesh::HalfedgeHandle hehb0 = mesh_.find_halfedge(boundary_vertex, vhandle[0]);
EXPECT_EQ(13, mesh_.property(fprop_int, mesh_.face_handle(heh1b))) << "Different Property value";
EXPECT_EQ(13, mesh_.property(fprop_int, mesh_.face_handle(hehb0))) << "Different Property value";
EXPECT_TRUE(mesh_.status(mesh_.face_handle(heh1b)).tagged()) << "Different internal property value";
EXPECT_TRUE(mesh_.status(mesh_.face_handle(hehb0)).tagged()) << "Different internal property value";
}
}

View File

@@ -1,7 +1,9 @@
#include <gtest/gtest.h>
#include <Unittests/unittests_common.hh>
#include <OpenMesh/Tools/Subdivider/Uniform/ModifiedButterFlyT.hh>
#include <OpenMesh/Tools/Subdivider/Uniform/CatmullClarkT.hh>
#include <OpenMesh/Tools/Subdivider/Uniform/LoopT.hh>
#include <OpenMesh/Tools/Subdivider/Uniform/Sqrt3T.hh>
#include <OpenMesh/Tools/Subdivider/Uniform/MidpointT.hh>
@@ -147,6 +149,371 @@ TEST_F(OpenMeshSubdividerUniform_Triangle, Subdivider_Sqrt3) {
EXPECT_EQ(216u, mesh_.n_faces() ) << "Wrong number of faces after subdivision with sqrt3";
}
TEST_F(OpenMeshSubdividerUniform_Triangle, Subdivider_Sqrt3_delete_vertex) {
for (bool collect_garbage : { false, true })
{
mesh_.clear();
// Request status flags to use delete and garbage collection
mesh_.request_vertex_status();
mesh_.request_halfedge_status();
mesh_.request_edge_status();
mesh_.request_face_status();
// Add some vertices
Mesh::VertexHandle vhandle[9];
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(0, 2, 0));
vhandle[3] = mesh_.add_vertex(Mesh::Point(1, 0, 0));
vhandle[4] = mesh_.add_vertex(Mesh::Point(1, 1, 0));
vhandle[5] = mesh_.add_vertex(Mesh::Point(1, 2, 0));
vhandle[6] = mesh_.add_vertex(Mesh::Point(2, 0, 0));
vhandle[7] = mesh_.add_vertex(Mesh::Point(2, 1, 0));
vhandle[8] = mesh_.add_vertex(Mesh::Point(2, 2, 0));
// Add eight faces
std::vector<Mesh::VertexHandle> face_vhandles;
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[4]);
face_vhandles.push_back(vhandle[3]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[4]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[4]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[5]);
face_vhandles.push_back(vhandle[4]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[3]);
face_vhandles.push_back(vhandle[7]);
face_vhandles.push_back(vhandle[6]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[3]);
face_vhandles.push_back(vhandle[4]);
face_vhandles.push_back(vhandle[7]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[4]);
face_vhandles.push_back(vhandle[8]);
face_vhandles.push_back(vhandle[7]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[4]);
face_vhandles.push_back(vhandle[5]);
face_vhandles.push_back(vhandle[8]);
mesh_.add_face(face_vhandles);
// Test setup:
// 6 === 7 === 8
// | / | / |
// | / | / |
// | / | / |
// 3 === 4 === 5
// | / | \ |
// | / | \ |
// | / | \ |
// 0 === 1 === 2
// Delete one vertex
mesh_.delete_vertex(vhandle[1]);
// Check setup
if (collect_garbage)
{
mesh_.garbage_collection();
EXPECT_EQ(8u, mesh_.n_vertices() ) << "Wrong number of vertices";
EXPECT_EQ(6u, mesh_.n_faces() ) << "Wrong number of faces";
}
else
{
EXPECT_EQ(9u, mesh_.n_vertices() ) << "Wrong number of vertices";
EXPECT_EQ(8u, mesh_.n_faces() ) << "Wrong number of faces";
}
// Initialize subdivider
OpenMesh::Subdivider::Uniform::Sqrt3T<Mesh> sqrt3;
// Execute 3 subdivision steps
sqrt3.attach(mesh_);
sqrt3( 3 );
sqrt3.detach();
if (!collect_garbage)
mesh_.garbage_collection(); // if we did not collect garbage before, do so now
// Check setup
EXPECT_EQ(94u, mesh_.n_vertices() ) << "Wrong number of vertices after subdivision with sqrt3";
EXPECT_EQ(162u, mesh_.n_faces() ) << "Wrong number of faces after subdivision with sqrt3";
}
}
TEST_F(OpenMeshSubdividerUniform_Triangle, Subdivider_Loop) {
mesh_.clear();
// Add some vertices
Mesh::VertexHandle vhandle[9];
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(0, 2, 0));
vhandle[3] = mesh_.add_vertex(Mesh::Point(1, 0, 0));
vhandle[4] = mesh_.add_vertex(Mesh::Point(1, 1, 0));
vhandle[5] = mesh_.add_vertex(Mesh::Point(1, 2, 0));
vhandle[6] = mesh_.add_vertex(Mesh::Point(2, 0, 0));
vhandle[7] = mesh_.add_vertex(Mesh::Point(2, 1, 0));
vhandle[8] = mesh_.add_vertex(Mesh::Point(2, 2, 0));
// Add eight faces
std::vector<Mesh::VertexHandle> face_vhandles;
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[4]);
face_vhandles.push_back(vhandle[3]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[4]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[4]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[5]);
face_vhandles.push_back(vhandle[4]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[3]);
face_vhandles.push_back(vhandle[7]);
face_vhandles.push_back(vhandle[6]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[3]);
face_vhandles.push_back(vhandle[4]);
face_vhandles.push_back(vhandle[7]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[4]);
face_vhandles.push_back(vhandle[8]);
face_vhandles.push_back(vhandle[7]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[4]);
face_vhandles.push_back(vhandle[5]);
face_vhandles.push_back(vhandle[8]);
mesh_.add_face(face_vhandles);
// Test setup:
// 6 === 7 === 8
// | / | / |
// | / | / |
// | / | / |
// 3 === 4 === 5
// | / | \ |
// | / | \ |
// | / | \ |
// 0 === 1 === 2
// Initialize subdivider
OpenMesh::Subdivider::Uniform::LoopT<Mesh> loop;
// Check setup
EXPECT_EQ(9u, mesh_.n_vertices() ) << "Wrong number of vertices";
EXPECT_EQ(8u, mesh_.n_faces() ) << "Wrong number of faces";
// Execute 3 subdivision steps
loop.attach(mesh_);
loop( 3 );
loop.detach();
// Check setup
EXPECT_EQ(289u, mesh_.n_vertices() ) << "Wrong number of vertices after subdivision with loop";
EXPECT_EQ(512u, mesh_.n_faces() ) << "Wrong number of faces after subdivision with loop";
}
TEST_F(OpenMeshSubdividerUniform_Triangle, Subdivider_Loop_delete_vertex) {
for (bool collect_garbage : { false, true })
{
mesh_.clear();
// Request status flags to use delete and garbage collection
mesh_.request_vertex_status();
mesh_.request_halfedge_status();
mesh_.request_edge_status();
mesh_.request_face_status();
// Add some vertices
Mesh::VertexHandle vhandle[9];
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(0, 2, 0));
vhandle[3] = mesh_.add_vertex(Mesh::Point(1, 0, 0));
vhandle[4] = mesh_.add_vertex(Mesh::Point(1, 1, 0));
vhandle[5] = mesh_.add_vertex(Mesh::Point(1, 2, 0));
vhandle[6] = mesh_.add_vertex(Mesh::Point(2, 0, 0));
vhandle[7] = mesh_.add_vertex(Mesh::Point(2, 1, 0));
vhandle[8] = mesh_.add_vertex(Mesh::Point(2, 2, 0));
// Add eight faces
std::vector<Mesh::VertexHandle> face_vhandles;
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[4]);
face_vhandles.push_back(vhandle[3]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[4]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[4]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[5]);
face_vhandles.push_back(vhandle[4]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[3]);
face_vhandles.push_back(vhandle[7]);
face_vhandles.push_back(vhandle[6]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[3]);
face_vhandles.push_back(vhandle[4]);
face_vhandles.push_back(vhandle[7]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[4]);
face_vhandles.push_back(vhandle[8]);
face_vhandles.push_back(vhandle[7]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[4]);
face_vhandles.push_back(vhandle[5]);
face_vhandles.push_back(vhandle[8]);
mesh_.add_face(face_vhandles);
// Test setup:
// 6 === 7 === 8
// | / | / |
// | / | / |
// | / | / |
// 3 === 4 === 5
// | / | \ |
// | / | \ |
// | / | \ |
// 0 === 1 === 2
// Delete one vertex
mesh_.delete_vertex(vhandle[1]);
if (collect_garbage)
{
mesh_.garbage_collection();
// Check setup
EXPECT_EQ(8u, mesh_.n_vertices() ) << "Wrong number of vertices";
EXPECT_EQ(6u, mesh_.n_faces() ) << "Wrong number of faces";
}
else
{
// Check setup
EXPECT_EQ(9u, mesh_.n_vertices() ) << "Wrong number of vertices";
EXPECT_EQ(8u, mesh_.n_faces() ) << "Wrong number of faces";
}
// Initialize subdivider
OpenMesh::Subdivider::Uniform::LoopT<Mesh> loop;
// Execute 3 subdivision steps
loop.attach(mesh_);
loop( 3 );
loop.detach();
if (!collect_garbage)
mesh_.garbage_collection(); // if we did not collect garbage before, do so now
// Check setup
EXPECT_EQ(225u, mesh_.n_vertices() ) << "Wrong number of vertices after subdivision with loop";
EXPECT_EQ(384u, mesh_.n_faces() ) << "Wrong number of faces after subdivision with loop";
}
}
/*
* ====================================================================
* Define tests below
@@ -232,6 +599,108 @@ TEST_F(OpenMeshSubdividerUniform_Poly, Subdivider_CatmullClark) {
EXPECT_EQ(256u, mesh_.n_faces() ) << "Wrong number of faces after subdivision with catmull clark";
}
TEST_F(OpenMeshSubdividerUniform_Poly, Subdivider_CatmullClark_delete_vertex) {
for (bool collect_garbage : { false, true })
{
mesh_.clear();
// Request status flags to use delete and garbage collection
mesh_.request_vertex_status();
mesh_.request_halfedge_status();
mesh_.request_edge_status();
mesh_.request_face_status();
// Add some vertices
Mesh::VertexHandle vhandle[9];
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(0, 2, 0));
vhandle[3] = mesh_.add_vertex(Mesh::Point(1, 0, 0));
vhandle[4] = mesh_.add_vertex(Mesh::Point(1, 1, 0));
vhandle[5] = mesh_.add_vertex(Mesh::Point(1, 2, 0));
vhandle[6] = mesh_.add_vertex(Mesh::Point(2, 0, 0));
vhandle[7] = mesh_.add_vertex(Mesh::Point(2, 1, 0));
vhandle[8] = mesh_.add_vertex(Mesh::Point(2, 2, 0));
// Add four faces
std::vector<Mesh::VertexHandle> face_vhandles;
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[4]);
face_vhandles.push_back(vhandle[3]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[5]);
face_vhandles.push_back(vhandle[4]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[4]);
face_vhandles.push_back(vhandle[5]);
face_vhandles.push_back(vhandle[8]);
face_vhandles.push_back(vhandle[7]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[3]);
face_vhandles.push_back(vhandle[4]);
face_vhandles.push_back(vhandle[7]);
face_vhandles.push_back(vhandle[6]);
mesh_.add_face(face_vhandles);
// Test setup:
// 6 === 7 === 8
// | | |
// | | |
// | | |
// 3 === 4 === 5
// | | |
// | | |
// | | |
// 0 === 1 === 2
mesh_.delete_vertex(vhandle[1]);
// Check setup
if (collect_garbage)
{
mesh_.garbage_collection();
EXPECT_EQ(6u, mesh_.n_vertices() ) << "Wrong number of vertices";
EXPECT_EQ(2u, mesh_.n_faces() ) << "Wrong number of faces";
}
else
{
EXPECT_EQ(9u, mesh_.n_vertices() ) << "Wrong number of vertices";
EXPECT_EQ(4u, mesh_.n_faces() ) << "Wrong number of faces";
}
// Initialize subdivider
OpenMesh::Subdivider::Uniform::CatmullClarkT<PolyMesh> catmull;
// Execute 3 subdivision steps
catmull.attach(mesh_);
catmull( 3 );
catmull.detach();
if (!collect_garbage)
mesh_.garbage_collection(); // if we did not collect garbage before, do so now
EXPECT_EQ(153u, mesh_.n_vertices() ) << "Wrong number of vertices after subdivision with catmull clark";
EXPECT_EQ(128u, mesh_.n_faces() ) << "Wrong number of faces after subdivision with catmull clark";
}
}
/* Adds a cube to a polymesh
*/
TEST_F(OpenMeshSubdividerUniform_Poly, Midpoint) {
@@ -329,4 +798,364 @@ TEST_F(OpenMeshSubdividerUniform_Poly, Midpoint) {
EXPECT_EQ(26u, mesh_.n_faces()) << "Wrong number of faces";
}
TEST_F(OpenMeshSubdividerUniform_Poly, Midpoint_delete_vertex) {
for (bool collect_garbage : { false, true })
{
mesh_.clear();
// Request status flags to use delete and garbage collection
mesh_.request_vertex_status();
mesh_.request_halfedge_status();
mesh_.request_edge_status();
mesh_.request_face_status();
// Add some vertices
Mesh::VertexHandle vhandle[8];
vhandle[0] = mesh_.add_vertex(PolyMesh::Point(-1, -1, 1));
vhandle[1] = mesh_.add_vertex(PolyMesh::Point( 1, -1, 1));
vhandle[2] = mesh_.add_vertex(PolyMesh::Point( 1, 1, 1));
vhandle[3] = mesh_.add_vertex(PolyMesh::Point(-1, 1, 1));
vhandle[4] = mesh_.add_vertex(PolyMesh::Point(-1, -1, -1));
vhandle[5] = mesh_.add_vertex(PolyMesh::Point( 1, -1, -1));
vhandle[6] = mesh_.add_vertex(PolyMesh::Point( 1, 1, -1));
vhandle[7] = mesh_.add_vertex(PolyMesh::Point(-1, 1, -1));
// Add six faces to form a cube
std::vector<Mesh::VertexHandle> face_vhandles;
face_vhandles.clear();
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[3]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[7]);
face_vhandles.push_back(vhandle[6]);
face_vhandles.push_back(vhandle[5]);
face_vhandles.push_back(vhandle[4]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[4]);
face_vhandles.push_back(vhandle[5]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[5]);
face_vhandles.push_back(vhandle[6]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[3]);
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[6]);
face_vhandles.push_back(vhandle[7]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[3]);
face_vhandles.push_back(vhandle[7]);
face_vhandles.push_back(vhandle[4]);
mesh_.add_face(face_vhandles);
// Test setup:
//
//
// 3 ======== 2
// / /|
// / / | z
// 0 ======== 1 | |
// | | | | y
// | 7 | 6 | /
// | | / | /
// | |/ |/
// 4 ======== 5 -------> x
//
mesh_.delete_vertex(vhandle[1]);
// Check setup
if (collect_garbage)
{
mesh_.garbage_collection();
EXPECT_EQ(9u, mesh_.n_edges()) << "Wrong number of Edges";
EXPECT_EQ(18u, mesh_.n_halfedges()) << "Wrong number of HalfEdges";
EXPECT_EQ(7u, mesh_.n_vertices()) << "Wrong number of vertices";
EXPECT_EQ(3u, mesh_.n_faces()) << "Wrong number of faces";
}
else
{
EXPECT_EQ(12u, mesh_.n_edges()) << "Wrong number of Edges";
EXPECT_EQ(24u, mesh_.n_halfedges()) << "Wrong number of HalfEdges";
EXPECT_EQ(8u, mesh_.n_vertices()) << "Wrong number of vertices";
EXPECT_EQ(6u, mesh_.n_faces()) << "Wrong number of faces";
}
// Check setup
// Initialize subdivider
OpenMesh::Subdivider::Uniform::MidpointT<PolyMesh> midpoint;
// Execute 2 subdivision steps
midpoint.attach(mesh_);
midpoint(2);
midpoint.detach();
if (!collect_garbage)
mesh_.garbage_collection(); // if we did not collect garbage before, do so now
// Check Result
EXPECT_EQ(15u, mesh_.n_edges()) << "Wrong number of Edges";
EXPECT_EQ(30u, mesh_.n_halfedges()) << "Wrong number of HalfEdges";
EXPECT_EQ(12u, mesh_.n_vertices()) << "Wrong number of vertices";
EXPECT_EQ(4u, mesh_.n_faces()) << "Wrong number of faces";
}
}
TEST_F(OpenMeshSubdividerUniform_Triangle, Modified_Butterfly) {
mesh_.clear();
// Add some vertices
Mesh::VertexHandle vhandle[9];
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(0, 2, 0));
vhandle[3] = mesh_.add_vertex(Mesh::Point(1, 0, 0));
vhandle[4] = mesh_.add_vertex(Mesh::Point(1, 1, 0));
vhandle[5] = mesh_.add_vertex(Mesh::Point(1, 2, 0));
vhandle[6] = mesh_.add_vertex(Mesh::Point(2, 0, 0));
vhandle[7] = mesh_.add_vertex(Mesh::Point(2, 1, 0));
vhandle[8] = mesh_.add_vertex(Mesh::Point(2, 2, 0));
// Add eight faces
std::vector<Mesh::VertexHandle> face_vhandles;
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[4]);
face_vhandles.push_back(vhandle[3]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[4]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[4]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[5]);
face_vhandles.push_back(vhandle[4]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[3]);
face_vhandles.push_back(vhandle[7]);
face_vhandles.push_back(vhandle[6]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[3]);
face_vhandles.push_back(vhandle[4]);
face_vhandles.push_back(vhandle[7]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[4]);
face_vhandles.push_back(vhandle[8]);
face_vhandles.push_back(vhandle[7]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[4]);
face_vhandles.push_back(vhandle[5]);
face_vhandles.push_back(vhandle[8]);
mesh_.add_face(face_vhandles);
// Test setup:
// 6 === 7 === 8
// | / | / |
// | / | / |
// | / | / |
// 3 === 4 === 5
// | / | \ |
// | / | \ |
// | / | \ |
// 0 === 1 === 2
// Initialize subdivider
OpenMesh::Subdivider::Uniform::ModifiedButterflyT<Mesh> butter;
// Check setup
EXPECT_EQ(9u, mesh_.n_vertices() ) << "Wrong number of vertices";
EXPECT_EQ(8u, mesh_.n_faces() ) << "Wrong number of faces";
// Execute 3 subdivision steps
butter.attach(mesh_);
butter( 3 );
butter.detach();
// Check setup
EXPECT_EQ(289u, mesh_.n_vertices() ) << "Wrong number of vertices after subdivision with loop";
EXPECT_EQ(512u, mesh_.n_faces() ) << "Wrong number of faces after subdivision with loop";
}
TEST_F(OpenMeshSubdividerUniform_Triangle, Modified_Butterfly_delete_vertex) {
for (bool collect_garbage : { false, true })
{
mesh_.clear();
// Request status flags to use delete and garbage collection
mesh_.request_vertex_status();
mesh_.request_halfedge_status();
mesh_.request_edge_status();
mesh_.request_face_status();
// Add some vertices
Mesh::VertexHandle vhandle[9];
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(0, 2, 0));
vhandle[3] = mesh_.add_vertex(Mesh::Point(1, 0, 0));
vhandle[4] = mesh_.add_vertex(Mesh::Point(1, 1, 0));
vhandle[5] = mesh_.add_vertex(Mesh::Point(1, 2, 0));
vhandle[6] = mesh_.add_vertex(Mesh::Point(2, 0, 0));
vhandle[7] = mesh_.add_vertex(Mesh::Point(2, 1, 0));
vhandle[8] = mesh_.add_vertex(Mesh::Point(2, 2, 0));
// Add eight faces
std::vector<Mesh::VertexHandle> face_vhandles;
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[4]);
face_vhandles.push_back(vhandle[3]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[4]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[4]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[5]);
face_vhandles.push_back(vhandle[4]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[3]);
face_vhandles.push_back(vhandle[7]);
face_vhandles.push_back(vhandle[6]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[3]);
face_vhandles.push_back(vhandle[4]);
face_vhandles.push_back(vhandle[7]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[4]);
face_vhandles.push_back(vhandle[8]);
face_vhandles.push_back(vhandle[7]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[4]);
face_vhandles.push_back(vhandle[5]);
face_vhandles.push_back(vhandle[8]);
mesh_.add_face(face_vhandles);
// Test setup:
// 6 === 7 === 8
// | / | / |
// | / | / |
// | / | / |
// 3 === 4 === 5
// | / | \ |
// | / | \ |
// | / | \ |
// 0 === 1 === 2
// Delete one vertex
mesh_.delete_vertex(vhandle[1]);
// Check setup
if (collect_garbage)
{
mesh_.garbage_collection();
EXPECT_EQ(8u, mesh_.n_vertices() ) << "Wrong number of vertices";
EXPECT_EQ(6u, mesh_.n_faces() ) << "Wrong number of faces";
}
else
{
EXPECT_EQ(9u, mesh_.n_vertices() ) << "Wrong number of vertices";
EXPECT_EQ(8u, mesh_.n_faces() ) << "Wrong number of faces";
}
// Initialize subdivider
OpenMesh::Subdivider::Uniform::ModifiedButterflyT<Mesh> butter;
// Execute 3 subdivision steps
butter.attach(mesh_);
butter( 3 );
butter.detach();
if (!collect_garbage)
mesh_.garbage_collection(); // if we did not collect garbage before, do so now
// Check setup
EXPECT_EQ(225u, mesh_.n_vertices() ) << "Wrong number of vertices after subdivision with butter";
EXPECT_EQ(384u, mesh_.n_faces() ) << "Wrong number of faces after subdivision with butter";
}
}
}

View File

@@ -741,5 +741,4 @@ TEST_F(OpenMeshCollapse, DeletedStatus) {
EXPECT_FALSE(mesh_.status(mesh_.opposite_halfedge_handle(bottom_right)).deleted()) << "Halfedge from vertex 5 to vertex 3 is deleted";
}
}

View File

@@ -773,7 +773,7 @@ TEST_F(OpenMeshIterators, FaceIterEmptyMeshOneDeletedFace) {
vhandle[1] = mesh_.add_vertex(Mesh::Point(0, 1, 0));
vhandle[2] = mesh_.add_vertex(Mesh::Point(1, 1, 0));
// Add two faces
// Add one faces
std::vector<Mesh::VertexHandle> face_vhandles;
face_vhandles.push_back(vhandle[2]);
@@ -841,4 +841,162 @@ TEST_F(OpenMeshIterators, FaceIterEmptyMeshOneDeletedFace) {
mesh_.release_face_status();
}
/*
* Test range iterators
*/
TEST_F(OpenMeshIterators, RangeIterators) {
mesh_.clear();
// request delete_face capability
mesh_.request_vertex_status();
mesh_.request_edge_status();
mesh_.request_halfedge_status();
mesh_.request_face_status();
// 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[0]);
face_vhandles.push_back(vhandle[3]);
face_vhandles.push_back(vhandle[2]);
Mesh::FaceHandle fh = mesh_.add_face(face_vhandles);
// Delete one face
mesh_.delete_face(fh);
// Test setup (right face deleted)
// 1 --- 2
// | / |
// | / |
// | / |
// 0 --- 3
// ====== Faces ======
int count_faces_iter = 0;
for (auto f_it = mesh_.faces_begin(); f_it != mesh_.faces_end(); ++f_it)
++count_faces_iter;
EXPECT_EQ(2, count_faces_iter) << "Wrong number of visited faces.";
int count_faces_skipping_iter = 0;
for (auto f_it = mesh_.faces_sbegin(); f_it != mesh_.faces_end(); ++f_it)
++count_faces_skipping_iter;
EXPECT_EQ(1, count_faces_skipping_iter) << "Wrong number of visited faces.";
int count_faces_range = 0;
for (auto fh : mesh_.faces())
if (fh.is_valid()) // not actually necessary but fixes unused variable warning
++count_faces_range;
EXPECT_EQ(1, count_faces_range) << "Wrong number of visited faces.";
int count_faces_range_all = 0;
for (auto fh : mesh_.all_faces())
if (fh.is_valid()) // not actually necessary but fixes unused variable warning
++count_faces_range_all;
EXPECT_EQ(2, count_faces_range_all) << "Wrong number of visited faces.";
// ====== Edges ======
int count_edges_iter = 0;
for (auto e_it = mesh_.edges_begin(); e_it != mesh_.edges_end(); ++e_it)
++count_edges_iter;
EXPECT_EQ(5, count_edges_iter) << "Wrong number of visited edges.";
int count_edges_skipping_iter = 0;
for (auto e_it = mesh_.edges_sbegin(); e_it != mesh_.edges_end(); ++e_it)
++count_edges_skipping_iter;
EXPECT_EQ(3, count_edges_skipping_iter) << "Wrong number of visited edges.";
int count_edges_range = 0;
for (auto eh : mesh_.edges())
if (eh.is_valid()) // not actually necessary but fixes unused variable warning
++count_edges_range;
EXPECT_EQ(3, count_edges_range) << "Wrong number of visited edges.";
int count_edges_range_all = 0;
for (auto eh : mesh_.all_edges())
if (eh.is_valid()) // not actually necessary but fixes unused variable warning
++count_edges_range_all;
EXPECT_EQ(5, count_edges_range_all) << "Wrong number of visited edges.";
// ====== Halfedges ======
int count_halfedges_iter = 0;
for (auto h_it = mesh_.halfedges_begin(); h_it != mesh_.halfedges_end(); ++h_it)
++count_halfedges_iter;
EXPECT_EQ(10, count_halfedges_iter) << "Wrong number of visited halfedges.";
int count_halfedges_skipping_iter = 0;
for (auto h_it = mesh_.halfedges_sbegin(); h_it != mesh_.halfedges_end(); ++h_it)
++count_halfedges_skipping_iter;
EXPECT_EQ(6, count_halfedges_skipping_iter) << "Wrong number of visited halfedges.";
int count_halfedges_range = 0;
for (auto heh : mesh_.halfedges())
if (heh.is_valid()) // not actually necessary but fixes unused variable warning
++count_halfedges_range;
EXPECT_EQ(6, count_halfedges_range) << "Wrong number of visited halfedges.";
int count_halfedges_range_all = 0;
for (auto heh : mesh_.all_halfedges())
if (heh.is_valid()) // not actually necessary but fixes unused variable warning
++count_halfedges_range_all;
EXPECT_EQ(10, count_halfedges_range_all) << "Wrong number of visited halfedges.";
// ====== Vertices ======
int count_vertices_iter = 0;
for (auto v_it = mesh_.vertices_begin(); v_it != mesh_.vertices_end(); ++v_it)
++count_vertices_iter;
EXPECT_EQ(4, count_vertices_iter) << "Wrong number of visited vertices.";
int count_vertices_skipping_iter = 0;
for (auto v_it = mesh_.vertices_sbegin(); v_it != mesh_.vertices_end(); ++v_it)
++count_vertices_skipping_iter;
EXPECT_EQ(3, count_vertices_skipping_iter) << "Wrong number of visited vertices.";
int count_vertices_range = 0;
for (auto vh : mesh_.vertices())
if (vh.is_valid()) // not actually necessary but fixes unused variable warning
++count_vertices_range;
EXPECT_EQ(3, count_vertices_range) << "Wrong number of visited vertices.";
int count_vertices_range_all = 0;
for (auto vh : mesh_.all_vertices())
if (vh.is_valid()) // not actually necessary but fixes unused variable warning
++count_vertices_range_all;
EXPECT_EQ(4, count_vertices_range_all) << "Wrong number of visited vertices.";
mesh_.release_vertex_status();
mesh_.release_edge_status();
mesh_.release_halfedge_status();
mesh_.release_face_status();
}
}

View File

@@ -164,7 +164,8 @@ TEST_F(OpenMeshOthers, CalcDihedralAngre ) {
EXPECT_EQ( 0.0 , mesh_.calc_dihedral_angle(eh) ) << "Wrong Dihedral angle!" << std::endl;
// Modify point
Mesh::Point tmp = ( Mesh::Point(0.0, 0.0, -1.0) + Mesh::Point(1.0, 1.0, -1.0) ) * static_cast<Mesh::Point::value_type>(0.5);
Mesh::Point tmp = ( Mesh::Point(0.0, 0.0, -1.0) + Mesh::Point(1.0, 1.0, -1.0) )
* static_cast<OpenMesh::vector_traits<Mesh::Point>::value_type>(0.5);
mesh_.point(vhandle[2]) = tmp;
double difference = fabs( 1.36944 - mesh_.calc_dihedral_angle(eh) );

View File

@@ -1,5 +1,6 @@
#include <gtest/gtest.h>
#include <OpenMesh/Core/Utils/PropertyManager.hh>
#include <Unittests/unittests_common.hh>
#include <string>
#include <map>
@@ -197,7 +198,7 @@ public:
public:
// construct with a given mesh
SmootherT(Mesh& _mesh)
explicit SmootherT(Mesh& _mesh)
: mesh_(_mesh)
{
mesh_.add_property( cog_ );
@@ -445,39 +446,34 @@ TEST_F(OpenMeshTutorials, using_iterators_and_circulators) {
TEST_F(OpenMeshTutorials, using_custom_properties) {
MyMesh mesh;
bool ok = OpenMesh::IO::read_mesh(mesh, "output.off");
EXPECT_TRUE(ok) << "Cannot read mesh from file 'output.off'";
bool ok = OpenMesh::IO::read_mesh(mesh, "cube_noisy.off");
EXPECT_TRUE(ok) << "Cannot read mesh from file 'cube_noisy.off'";
// this vertex property stores the computed centers of gravity
OpenMesh::VPropHandleT<MyMesh::Point> cogs;
mesh.add_property(cogs);
const int iterations = 100;
// smoothing mesh N times
MyMesh::VertexIter v_it, v_end(mesh.vertices_end());
MyMesh::VertexVertexIter vv_it;
MyMesh::Point cog;
MyMesh::Scalar valence;
unsigned int i, N(100);
for (i=0; i < N; ++i)
{
for (v_it = mesh.vertices_begin(); v_it != v_end; ++v_it)
{
mesh.property(cogs,*v_it).vectorize(0.0f);
valence = 0.0;
// Add a vertex property storing the computed centers of gravity
auto cog = OpenMesh::VProp<MyMesh::Point>(mesh);
for (vv_it = mesh.vv_iter( *v_it ); vv_it.is_valid(); ++vv_it)
{
mesh.property(cogs,*v_it) += mesh.point( *vv_it );
++valence;
// Smooth the mesh several times
for (int i = 0; i < iterations; ++i) {
// Iterate over all vertices to compute centers of gravity
for (const auto& vh : mesh.vertices()) {
cog[vh] = {0,0,0};
int valence = 0;
// Iterate over all 1-ring vertices around vh
for (const auto& vvh : mesh.vv_range(vh)) {
cog[vh] += mesh.point(vvh);
++valence;
}
cog[vh] /= valence;
}
// Move all vertices to the previously computed positions
for (const auto& vh : mesh.vertices()) {
mesh.point(vh) = cog[vh];
}
mesh.property(cogs,*v_it) /= valence;
}
for (v_it = mesh.vertices_begin(); v_it != v_end; ++v_it)
if ( !mesh.is_boundary( *v_it ) )
mesh.set_point( *v_it, mesh.property(cogs,*v_it) );
}
} // The cog vertex property is removed from the mesh at the end of this scope
// write mesh
ok = OpenMesh::IO::write_mesh(mesh, "smoothed_custom_properties_output.off");
@@ -488,8 +484,8 @@ TEST_F(OpenMeshTutorials, using_custom_properties) {
TEST_F(OpenMeshTutorials, using_STL_algorithms) {
MyMeshWithTraits mesh;
bool ok = OpenMesh::IO::read_mesh(mesh, "output.off");
EXPECT_TRUE(ok) << "Cannot read mesh from file 'output.off'";
bool ok = OpenMesh::IO::read_mesh(mesh, "cube_noisy.off");
EXPECT_TRUE(ok) << "Cannot read mesh from file 'cube_noisy.off'";
SmootherT<MyMeshWithTraits> smoother(mesh);
smoother.smooth(100);
@@ -619,20 +615,20 @@ TEST_F(OpenMeshTutorials, deleting_geometry_elements) {
mesh.request_vertex_status();
// generate vertices
MyMeshWithStatus::VertexHandle vhandle[8];
MyMeshWithStatus::FaceHandle fhandle[6];
Mesh::VertexHandle vhandle[8];
Mesh::FaceHandle fhandle[6];
vhandle[0] = mesh.add_vertex(MyMesh::Point(-1, -1, 1));
vhandle[1] = mesh.add_vertex(MyMesh::Point( 1, -1, 1));
vhandle[2] = mesh.add_vertex(MyMesh::Point( 1, 1, 1));
vhandle[3] = mesh.add_vertex(MyMesh::Point(-1, 1, 1));
vhandle[4] = mesh.add_vertex(MyMesh::Point(-1, -1, -1));
vhandle[5] = mesh.add_vertex(MyMesh::Point( 1, -1, -1));
vhandle[6] = mesh.add_vertex(MyMesh::Point( 1, 1, -1));
vhandle[7] = mesh.add_vertex(MyMesh::Point(-1, 1, -1));
vhandle[0] = mesh.add_vertex(Mesh::Point(-1, -1, 1));
vhandle[1] = mesh.add_vertex(Mesh::Point( 1, -1, 1));
vhandle[2] = mesh.add_vertex(Mesh::Point( 1, 1, 1));
vhandle[3] = mesh.add_vertex(Mesh::Point(-1, 1, 1));
vhandle[4] = mesh.add_vertex(Mesh::Point(-1, -1, -1));
vhandle[5] = mesh.add_vertex(Mesh::Point( 1, -1, -1));
vhandle[6] = mesh.add_vertex(Mesh::Point( 1, 1, -1));
vhandle[7] = mesh.add_vertex(Mesh::Point(-1, 1, -1));
// generate (quadrilateral) faces
std::vector<MyMesh::VertexHandle> tmp_face_vhandles;
std::vector<Mesh::VertexHandle> tmp_face_vhandles;
tmp_face_vhandles.clear();
tmp_face_vhandles.push_back(vhandle[0]);
tmp_face_vhandles.push_back(vhandle[1]);
@@ -807,10 +803,10 @@ TEST_F(OpenMeshTutorials, flipping_edges) {
Mesh mesh;
// Add some vertices
Mesh::VertexHandle vhandle[4];
vhandle[0] = mesh.add_vertex(MyMesh::Point(0, 0, 0));
vhandle[1] = mesh.add_vertex(MyMesh::Point(0, 1, 0));
vhandle[2] = mesh.add_vertex(MyMesh::Point(1, 1, 0));
vhandle[3] = mesh.add_vertex(MyMesh::Point(1, 0, 0));
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]);
@@ -846,13 +842,13 @@ TEST_F(OpenMeshTutorials, collapsing_edges) {
mesh.request_edge_status();
// Add some vertices as in the illustration above
PolyMesh::VertexHandle vhandle[7];
vhandle[0] = mesh.add_vertex(MyMesh::Point(-1, 1, 0));
vhandle[1] = mesh.add_vertex(MyMesh::Point(-1, 3, 0));
vhandle[2] = mesh.add_vertex(MyMesh::Point(0, 0, 0));
vhandle[3] = mesh.add_vertex(MyMesh::Point(0, 2, 0));
vhandle[4] = mesh.add_vertex(MyMesh::Point(0, 4, 0));
vhandle[5] = mesh.add_vertex(MyMesh::Point(1, 1, 0));
vhandle[6] = mesh.add_vertex(MyMesh::Point(1, 3, 0));
vhandle[0] = mesh.add_vertex(PolyMesh::Point(-1, 1, 0));
vhandle[1] = mesh.add_vertex(PolyMesh::Point(-1, 3, 0));
vhandle[2] = mesh.add_vertex(PolyMesh::Point(0, 0, 0));
vhandle[3] = mesh.add_vertex(PolyMesh::Point(0, 2, 0));
vhandle[4] = mesh.add_vertex(PolyMesh::Point(0, 4, 0));
vhandle[5] = mesh.add_vertex(PolyMesh::Point(1, 1, 0));
vhandle[6] = mesh.add_vertex(PolyMesh::Point(1, 3, 0));
// Add three quad faces
std::vector<PolyMesh::VertexHandle> face_vhandles;
face_vhandles.push_back(vhandle[1]);
@@ -886,4 +882,44 @@ TEST_F(OpenMeshTutorials, collapsing_edges) {
// Our mesh now looks like in the illustration above after the collapsing.
}
TEST_F(OpenMeshTutorials, using_smart_handles_and_smart_ranges) {
MyMesh mesh;
bool ok = OpenMesh::IO::read_mesh(mesh, "cube_noisy.off");
EXPECT_TRUE(ok) << "Cannot read mesh from file 'cube_noisy.off'";
const int iterations = 100;
{
// Add a vertex property storing the laplace vector
auto laplace = OpenMesh::VProp<MyMesh::Point>(mesh);
// Add a vertex property storing the laplace of the laplace
auto bi_laplace = OpenMesh::VProp<MyMesh::Point>(mesh);
// Get a propertymanager of the points property of the mesh to use as functor
auto points = OpenMesh::getPointsProperty(mesh);
// Smooth the mesh several times
for (int i = 0; i < iterations; ++i) {
// Iterate over all vertices to compute laplace vector
for (const auto& vh : mesh.vertices())
laplace(vh) = vh.vertices().avg(points) - points(vh);
// Iterate over all vertices to compute the laplace vector of the laplace vectors
for (const auto& vh : mesh.vertices())
bi_laplace(vh) = (vh.vertices().avg(laplace) - laplace(vh));
// update points by substracting the bi-laplacian damped by a factor of 0.5
for (const auto& vh : mesh.vertices())
points(vh) += -0.5 * bi_laplace(vh);
}
} // The laplace and update properties are removed from the mesh at the end of this scope.
// write mesh
ok = OpenMesh::IO::write_mesh(mesh, "smoothed_smart_output.off");
EXPECT_TRUE(ok) << "Cannot write mesh to file 'smoothed_smart_output.off'";
}
}

View File

@@ -185,7 +185,7 @@ LoadInfo open_progresult_mesh(const std::string& _filename)
OpenMesh::IO::restore(ifs, vr, swap);
PMInfo pminfo;
pminfo.p0 = p;
pminfo.p0 = OpenMesh::vector_cast<Mesh::Point>(p);
pminfo.v0 = result.mesh.add_vertex(p);
pminfo.v1 = Mesh::VertexHandle(v1);
pminfo.vl = Mesh::VertexHandle(vl);

View File

@@ -263,6 +263,23 @@ TEST_F(OpenMeshVectorTest, BasicArithmeticImmutable) {
EXPECT_NEAR(-2, v2neg[1], epsilon);
EXPECT_NEAR(-3, v2neg[2], epsilon);
}
template <typename V1, typename V2, typename S>
void test_dot(const V1 &v1, const V2 &v2, const S&s) {
EXPECT_NEAR(s, v1 | v2, 1e-6);
EXPECT_NEAR(s, v1.dot(v2), 1e-6);
EXPECT_NEAR(-s, (-v1) | v2, 1e-6);
EXPECT_NEAR(-s, (-v1).dot(v2), 1e-6);
EXPECT_NEAR(s, v2 | v1, 1e-6);
EXPECT_NEAR(s, v2.dot(v1), 1e-6);
}
template <typename V1, typename V2, typename V3>
void test_cross(const V1 &v1, const V2 &v2, const V3 &res) {
EXPECT_NEAR(0, (v1.cross(v2) - res).norm(), 1e-6);
EXPECT_NEAR(0, (v1 % v2 - res).norm(), 1e-6);
EXPECT_NEAR(0, (v2.cross(v1) + res).norm(), 1e-6);
EXPECT_NEAR(0, (v2 % v1 + res).norm(), 1e-6);
}
TEST_F(OpenMeshVectorTest, BasicLinearAlgebra) {
OpenMesh::Vec3d v(1, 2, 3);
@@ -285,9 +302,15 @@ TEST_F(OpenMeshVectorTest, BasicLinearAlgebra) {
EXPECT_EQ(1, OpenMesh::Vec3d(1, 3, -4).min_abs());
EXPECT_EQ(2, OpenMesh::Vec3d(-4, 2, 3).min_abs());
EXPECT_NEAR(14, OpenMesh::Vec3d(1, 2, 3) | OpenMesh::Vec3d(1, 2, 3), 1e-6);
EXPECT_NEAR(-14, OpenMesh::Vec3d(1, 2, 3) | OpenMesh::Vec3d(-1, -2, -3), 1e-6);
EXPECT_NEAR(14, OpenMesh::Vec3d(-1, -2, -3) | OpenMesh::Vec3d(-1, -2, -3), 1e-6);
test_dot(OpenMesh::Vec3d(1, 2, 3), OpenMesh::Vec3d(1, 2, 3), 14.);
test_dot(OpenMesh::Vec3d(1, 2, 3), OpenMesh::Vec3d(-1, -2, -3), -14.);
test_dot(OpenMesh::Vec3d(1, 2, 3), OpenMesh::Vec3i(1, 2, 3), 14);
test_dot(OpenMesh::Vec3i(1, 2, 3), OpenMesh::Vec3i(1, 2, 3), 14);
test_cross(OpenMesh::Vec3i(2, 0, 0), OpenMesh::Vec3i(0, 3, 0), OpenMesh::Vec3i(0, 0, 6));
test_cross(OpenMesh::Vec3d(2, 0, 0), OpenMesh::Vec3d(0, 3, 0), OpenMesh::Vec3d(0, 0, 6));
test_cross(OpenMesh::Vec3d(2, 0, 0), OpenMesh::Vec3i(0, 3, 0), OpenMesh::Vec3d(0, 0, 6));
}
TEST_F(OpenMeshVectorTest, array_init) {
@@ -397,4 +420,19 @@ TEST_F(OpenMeshVectorGCCBugTest, alignment_bug) {
}
TEST_F(OpenMeshVectorTest, Test_simple_0_constructor) {
// Create a test vector with zeroes from one parameter
OpenMesh::Vec3d testVec = OpenMesh::Vec3d(0);
EXPECT_EQ(0.0f, testVec[0]) << "Wrong Value after construction!";
EXPECT_EQ(0.0f, testVec[1]) << "Wrong Value after construction!";
EXPECT_EQ(0.0f, testVec[2]) << "Wrong Value after construction!";
}
}