From 6c9fc60520744729bf85ac05a69ad84089a98f9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20M=C3=B6ller?= Date: Wed, 22 Aug 2012 08:49:55 +0000 Subject: [PATCH] add: mixedDecimater add: unittests (for all Decimaters) fix: collapses counter in McDecimater refs #998 git-svn-id: http://www.openmesh.org/svnrepo/OpenMesh/trunk@653 fdac6126-5c0c-442c-9429-916003d36597 --- src/OpenMesh/Tools/Decimater/DecimaterT.hh | 3 +- src/OpenMesh/Tools/Decimater/McDecimaterT.cc | 1 - src/OpenMesh/Tools/Decimater/McDecimaterT.hh | 6 +- .../Tools/Decimater/MixedDecimaterT.cc | 131 ++++++++++++++++++ .../Tools/Decimater/MixedDecimaterT.hh | 129 +++++++++++++++++ src/Unittests/unittests.cc | 1 + src/Unittests/unittests_decimater.hh | 48 +++++++ src/Unittests/unittests_mc_decimater.hh | 48 +++++++ src/Unittests/unittests_mixed_decimater.hh | 110 +++++++++++++++ 9 files changed, 474 insertions(+), 3 deletions(-) create mode 100644 src/OpenMesh/Tools/Decimater/MixedDecimaterT.cc create mode 100644 src/OpenMesh/Tools/Decimater/MixedDecimaterT.hh create mode 100644 src/Unittests/unittests_mixed_decimater.hh diff --git a/src/OpenMesh/Tools/Decimater/DecimaterT.hh b/src/OpenMesh/Tools/Decimater/DecimaterT.hh index ef03ec04..89a1f715 100644 --- a/src/OpenMesh/Tools/Decimater/DecimaterT.hh +++ b/src/OpenMesh/Tools/Decimater/DecimaterT.hh @@ -75,7 +75,7 @@ namespace Decimater { \see BaseModT, \ref decimater_docu */ template < typename MeshT > -class DecimaterT : public BaseDecimaterT +class DecimaterT : virtual public BaseDecimaterT //virtual especially for the mixed decimater { public: //-------------------------------------------------------- public types @@ -109,6 +109,7 @@ public: } /** Decimate to target complexity (vertices and faces). + * Stops when the number of vertices or the number of faces is reached. * Returns number of performed collapses. */ size_t decimate_to_faces( size_t _n_vertices=0, size_t _n_faces=0 ); diff --git a/src/OpenMesh/Tools/Decimater/McDecimaterT.cc b/src/OpenMesh/Tools/Decimater/McDecimaterT.cc index 626d3f35..6a406ca5 100644 --- a/src/OpenMesh/Tools/Decimater/McDecimaterT.cc +++ b/src/OpenMesh/Tools/Decimater/McDecimaterT.cc @@ -225,7 +225,6 @@ size_t McDecimaterT::decimate_to_faces(size_t _nv, size_t _nf) { continue; // adjust complexity in advance (need boundary status) - ++n_collapses; // One vertex is killed by the collapse --nv; diff --git a/src/OpenMesh/Tools/Decimater/McDecimaterT.hh b/src/OpenMesh/Tools/Decimater/McDecimaterT.hh index 9ee7af48..c7de26bb 100644 --- a/src/OpenMesh/Tools/Decimater/McDecimaterT.hh +++ b/src/OpenMesh/Tools/Decimater/McDecimaterT.hh @@ -72,7 +72,7 @@ namespace Decimater { \see BaseModT, \ref decimater_docu */ template < typename MeshT > -class McDecimaterT : public BaseDecimaterT +class McDecimaterT : virtual public BaseDecimaterT //virtual especially for the mixed decimater { public: //-------------------------------------------------------- public types @@ -106,10 +106,14 @@ public: } /** Decimate to target complexity (vertices and faces). + * Stops when the number of vertices or the number of faces is reached. * Returns number of performed collapses. */ size_t decimate_to_faces( size_t _n_vertices=0, size_t _n_faces=0 ); + size_t samples(){return randomSamples_;} + void set_samples(const size_t _value){randomSamples_ = _value;} + private: //------------------------------------------------------- private data diff --git a/src/OpenMesh/Tools/Decimater/MixedDecimaterT.cc b/src/OpenMesh/Tools/Decimater/MixedDecimaterT.cc new file mode 100644 index 00000000..400eb4d7 --- /dev/null +++ b/src/OpenMesh/Tools/Decimater/MixedDecimaterT.cc @@ -0,0 +1,131 @@ +/*===========================================================================*\ +* * +* OpenMesh * +* Copyright (C) 2001-2011 by Computer Graphics Group, RWTH Aachen * +* www.openmesh.org * +* * +*---------------------------------------------------------------------------* +* This file is part of OpenMesh. * +* * +* OpenMesh is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, either version 3 of * +* the License, or (at your option) any later version with the * +* following exceptions: * +* * +* If other files instantiate templates or use macros * +* or inline functions from this file, or you compile this file and * +* link it with other files to produce an executable, this file does * +* not by itself cause the resulting executable to be covered by the * +* GNU Lesser General Public License. This exception does not however * +* invalidate any other reasons why the executable file might be * +* covered by the GNU Lesser General Public License. * +* * +* OpenMesh is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU Lesser General Public License for more details. * +* * +* You should have received a copy of the GNU LesserGeneral Public * +* License along with OpenMesh. If not, * +* see . * +* * +\*===========================================================================*/ + +/*===========================================================================*\ +* * +* $Revision: 460 $ * +* $Date: 2011-11-16 10:45:08 +0100 (Mi, 16 Nov 2011) $ * +* * +\*===========================================================================*/ + +/** \file MixedDecimaterT.cc +*/ + +//============================================================================= +// +// CLASS MixedDecimaterT - IMPLEMENTATION +// +//============================================================================= +#define OPENMESH_MIXED_DECIMATER_DECIMATERT_CC + +//== INCLUDES ================================================================= + +#include + +#include +#if defined(OM_CC_MIPS) +# include +#else +# include +#endif + +//== NAMESPACE =============================================================== +namespace OpenMesh { +namespace Decimater { + +//== IMPLEMENTATION ========================================================== + +template +MixedDecimaterT::MixedDecimaterT(Mesh& _mesh) : + BaseDecimaterT(_mesh),McDecimaterT(_mesh), DecimaterT(_mesh) { + +} + +//----------------------------------------------------------------------------- + +template +MixedDecimaterT::~MixedDecimaterT() { + +} + +//----------------------------------------------------------------------------- +template +size_t MixedDecimaterT::decimate(const size_t _n_collapses, const float _mc_factor) { + + if (_mc_factor > 1.0) + return 0; + + size_t n_collapses_mc = static_cast(_mc_factor*_n_collapses); + size_t n_collapses_inc = static_cast(_n_collapses - n_collapses_mc); + + size_t r_collapses = 0; + if (_mc_factor > 0.0) + r_collapses = McDecimaterT::decimate(n_collapses_mc); + if (_mc_factor < 1.0) + r_collapses += DecimaterT::decimate(n_collapses_inc); + return r_collapses; + +} + +template +size_t MixedDecimaterT::decimate_to_faces(const size_t _n_vertices,const size_t _n_faces, const float _mc_factor ){ + if (_mc_factor > 1.0) + return 0; + + std::size_t r_collapses = 0; + if (_mc_factor > 0.0) + { + size_t mesh_faces = this->mesh().n_faces(); + size_t mesh_vertices = this->mesh().n_vertices(); + //reduce the mesh only for _mc_factor + size_t n_vertices_mc = static_cast(mesh_vertices - _mc_factor * (mesh_vertices - _n_vertices)); + size_t n_faces_mc = static_cast(mesh_faces - _mc_factor * (mesh_faces - _n_faces)); + + r_collapses = McDecimaterT::decimate_to_faces(n_vertices_mc, n_faces_mc); + } + + //update the mesh::n_vertices function, otherwise the next Decimater function will delete to much + this->mesh().garbage_collection(); + + //reduce the rest of the mesh + if (_mc_factor < 1.0) + r_collapses += DecimaterT::decimate_to_faces(_n_vertices,_n_faces); + + return r_collapses; +} + +//============================================================================= +}// END_NS_MC_DECIMATER +} // END_NS_OPENMESH +//============================================================================= diff --git a/src/OpenMesh/Tools/Decimater/MixedDecimaterT.hh b/src/OpenMesh/Tools/Decimater/MixedDecimaterT.hh new file mode 100644 index 00000000..234204b4 --- /dev/null +++ b/src/OpenMesh/Tools/Decimater/MixedDecimaterT.hh @@ -0,0 +1,129 @@ +/*===========================================================================*\ + * * + * OpenMesh * + * Copyright (C) 2001-2011 by Computer Graphics Group, RWTH Aachen * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + * * + * OpenMesh is free software: you can redistribute it and/or modify * + * it under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 3 of * + * the License, or (at your option) any later version with the * + * following exceptions: * + * * + * If other files instantiate templates or use macros * + * or inline functions from this file, or you compile this file and * + * link it with other files to produce an executable, this file does * + * not by itself cause the resulting executable to be covered by the * + * GNU Lesser General Public License. This exception does not however * + * invalidate any other reasons why the executable file might be * + * covered by the GNU Lesser General Public License. * + * * + * OpenMesh is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU LesserGeneral Public * + * License along with OpenMesh. If not, * + * see . * + * * + \*===========================================================================*/ + +/*===========================================================================*\ + * * + * $Revision: 460 $ * + * $Date: 2011-11-16 10:45:08 +0100 (Mi, 16 Nov 2011) $ * + * * + \*===========================================================================*/ + +/** \file MixedDecimaterT.cc + */ + +//============================================================================= +// +// CLASS MixedDecimaterT - IMPLEMENTATION +// +//============================================================================= + +#ifndef OPENMESH_MIXED_DECIMATER_DECIMATERT_HH +#define OPENMESH_MIXED_DECIMATER_DECIMATERT_HH + + +//== INCLUDES ================================================================= + +#include +#include +#include + + + +//== NAMESPACE ================================================================ + +namespace OpenMesh { +namespace Decimater { + + +//== CLASS DEFINITION ========================================================= + + +/** Mixed decimater framework + \see BaseModT, \ref decimater_docu +*/ +template < typename MeshT > +class MixedDecimaterT : public McDecimaterT, public DecimaterT +{ +public: //-------------------------------------------------------- public types + + typedef McDecimaterT< MeshT > Self; + typedef MeshT Mesh; + typedef CollapseInfoT CollapseInfo; + typedef ModBaseT Module; + typedef std::vector< Module* > ModuleList; + typedef typename ModuleList::iterator ModuleListIterator; + +public: //------------------------------------------------------ public methods + + /// Constructor + MixedDecimaterT( Mesh& _mesh ); + + /// Destructor + ~MixedDecimaterT(); + +public: + + /** Decimate (perform _n_collapses collapses). Return number of + performed collapses. If _n_collapses is not given reduce as + much as possible */ + size_t decimate( const size_t _n_collapses, const float _mc_factor ); + + /// Decimate to target complexity, returns number of collapses + size_t decimate_to( size_t _n_vertices, const float _mc_factor ) + { + return ( (_n_vertices < this->mesh().n_vertices()) ? + decimate( this->mesh().n_vertices() - _n_vertices, _mc_factor ) : 0 ); + } + + /** Decimate to target complexity (vertices and faces). + * Stops when the number of vertices or the number of faces is reached. + * Returns number of performed collapses. + */ + size_t decimate_to_faces( const size_t _n_vertices=0, const size_t _n_faces=0 , const float _mc_factor = 0.8); + +private: //------------------------------------------------------- private data + +}; + +//============================================================================= +} // END_NS_DECIMATER +} // END_NS_OPENMESH +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_MIXED_DECIMATER_DECIMATERT_CC) +#define OPENMESH_MIXED_DECIMATER_TEMPLATES +#include "MixedDecimaterT.cc" +#endif +//============================================================================= +#endif // OPENMESH_MIXED_DECIMATER_DECIMATERT_HH +//============================================================================= diff --git a/src/Unittests/unittests.cc b/src/Unittests/unittests.cc index 7d8a5eee..95a6fcab 100644 --- a/src/Unittests/unittests.cc +++ b/src/Unittests/unittests.cc @@ -8,6 +8,7 @@ #include "unittests_trimesh_circulators.hh" #include "unittests_decimater.hh" #include "unittests_mc_decimater.hh" +#include "unittests_mixed_decimater.hh" #include "unittests_subdivider.hh" #include "unittests_trimesh_normal_calculations.hh" #include "unittests_trimesh_others.hh" diff --git a/src/Unittests/unittests_decimater.hh b/src/Unittests/unittests_decimater.hh index c54f6824..7da994c2 100644 --- a/src/Unittests/unittests_decimater.hh +++ b/src/Unittests/unittests_decimater.hh @@ -59,4 +59,52 @@ TEST_F(OpenMeshDecimater, DecimateMesh) { EXPECT_EQ(9996u, mesh_.n_faces()) << "The number of faces after decimation is not correct!"; } +TEST_F(OpenMeshDecimater, DecimateMeshToFaceVerticesLimit) { + + 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::ModNormalFlippingT< Mesh >::Handle HModNormal; + + Decimater decimaterDBG(mesh_); + HModQuadric hModQuadricDBG; + decimaterDBG.add( hModQuadricDBG ); + decimaterDBG.initialize(); + int removedVertices = 0; + removedVertices = decimaterDBG.decimate_to_faces(5000, 8000); + decimaterDBG.mesh().garbage_collection(); + + EXPECT_EQ(2526, removedVertices) << "The number of remove vertices is not correct!"; + EXPECT_EQ(5000u, mesh_.n_vertices()) << "The number of vertices after decimation is not correct!"; + EXPECT_EQ(14994u, mesh_.n_edges()) << "The number of edges after decimation is not correct!"; + EXPECT_EQ(9996u, mesh_.n_faces()) << "The number of faces after decimation is not correct!"; +} + +TEST_F(OpenMeshDecimater, DecimateMeshToFaceFaceLimit) { + + 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::ModNormalFlippingT< Mesh >::Handle HModNormal; + + Decimater decimaterDBG(mesh_); + HModQuadric hModQuadricDBG; + decimaterDBG.add( hModQuadricDBG ); + decimaterDBG.initialize(); + int removedVertices = 0; + removedVertices = decimaterDBG.decimate_to_faces(4500, 9996); + decimaterDBG.mesh().garbage_collection(); + + EXPECT_EQ(2526, removedVertices) << "The number of remove vertices is not correct!"; + EXPECT_EQ(5000u, mesh_.n_vertices()) << "The number of vertices after decimation is not correct!"; + EXPECT_EQ(14994u, mesh_.n_edges()) << "The number of edges after decimation is not correct!"; + EXPECT_EQ(9996u, mesh_.n_faces()) << "The number of faces after decimation is not correct!"; +} + #endif // INCLUDE GUARD diff --git a/src/Unittests/unittests_mc_decimater.hh b/src/Unittests/unittests_mc_decimater.hh index 9cc89e78..3f7e7d06 100644 --- a/src/Unittests/unittests_mc_decimater.hh +++ b/src/Unittests/unittests_mc_decimater.hh @@ -59,4 +59,52 @@ TEST_F(OpenMeshMultipleChoiceDecimater, DecimateMesh) { EXPECT_EQ(9996u, mesh_.n_faces()) << "The number of faces after decimation is not correct!"; } +TEST_F(OpenMeshMultipleChoiceDecimater, DecimateMeshToFaceVerticesLimit) { + + bool ok = OpenMesh::IO::read_mesh(mesh_, "cube1.off"); + + ASSERT_TRUE(ok); + + 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; + decimaterDBG.add( hModQuadricDBG ); + decimaterDBG.initialize(); + int removedVertices = 0; + removedVertices = decimaterDBG.decimate_to_faces(5000, 8000); + decimaterDBG.mesh().garbage_collection(); + + EXPECT_EQ(2526, removedVertices) << "The number of remove vertices is not correct!"; + EXPECT_EQ(5000u, mesh_.n_vertices()) << "The number of vertices after decimation is not correct!"; + EXPECT_EQ(14994u, mesh_.n_edges()) << "The number of edges after decimation is not correct!"; + EXPECT_EQ(9996u, mesh_.n_faces()) << "The number of faces after decimation is not correct!"; +} + +TEST_F(OpenMeshMultipleChoiceDecimater, DecimateMeshToFaceFaceLimit) { + + bool ok = OpenMesh::IO::read_mesh(mesh_, "cube1.off"); + + ASSERT_TRUE(ok); + + 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; + decimaterDBG.add( hModQuadricDBG ); + decimaterDBG.initialize(); + int removedVertices = 0; + removedVertices = decimaterDBG.decimate_to_faces(4500, 9996); + decimaterDBG.mesh().garbage_collection(); + + EXPECT_EQ(2526, removedVertices) << "The number of remove vertices is not correct!"; + EXPECT_EQ(5000u, mesh_.n_vertices()) << "The number of vertices after decimation is not correct!"; + EXPECT_EQ(14994u, mesh_.n_edges()) << "The number of edges after decimation is not correct!"; + EXPECT_EQ(9996u, mesh_.n_faces()) << "The number of faces after decimation is not correct!"; +} + #endif // INCLUDE GUARD diff --git a/src/Unittests/unittests_mixed_decimater.hh b/src/Unittests/unittests_mixed_decimater.hh new file mode 100644 index 00000000..6846337d --- /dev/null +++ b/src/Unittests/unittests_mixed_decimater.hh @@ -0,0 +1,110 @@ +#ifndef INCLUDE_UNITTESTS_MIXED_DECIMATER_HH +#define INCLUDE_UNITTESTS_MIXED_DECIMATER_HH + +#include +#include +#include +#include +#include + +class OpenMeshMixedDecimater : 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 + * ==================================================================== + */ + +/* + */ +TEST_F(OpenMeshMixedDecimater, DecimateMesh80PercentMc) { + + bool ok = OpenMesh::IO::read_mesh(mesh_, "cube1.off"); + + ASSERT_TRUE(ok); + + 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; + decimaterDBG.add( hModQuadricDBG ); + decimaterDBG.initialize(); + int removedVertices = 0; + removedVertices = decimaterDBG.decimate_to(5000,0.8); + decimaterDBG.mesh().garbage_collection(); + + EXPECT_EQ(2526, removedVertices) << "The number of remove vertices is not correct!"; + EXPECT_EQ(5000u, mesh_.n_vertices()) << "The number of vertices after decimation is not correct!"; + EXPECT_EQ(14994u, mesh_.n_edges()) << "The number of edges after decimation is not correct!"; + EXPECT_EQ(9996u, mesh_.n_faces()) << "The number of faces after decimation is not correct!"; +} + +TEST_F(OpenMeshMixedDecimater, DecimateMeshToFaceVerticesLimit) { + + bool ok = OpenMesh::IO::read_mesh(mesh_, "cube1.off"); + + ASSERT_TRUE(ok); + + 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; + decimaterDBG.add( hModQuadricDBG ); + decimaterDBG.initialize(); + int removedVertices = 0; + removedVertices = decimaterDBG.decimate_to_faces(5000, 8000, 0.7); + decimaterDBG.mesh().garbage_collection(); + + EXPECT_EQ(2526, removedVertices) << "The number of remove vertices is not correct!"; + EXPECT_EQ(5000u, mesh_.n_vertices()) << "The number of vertices after decimation is not correct!"; + EXPECT_EQ(14994u, mesh_.n_edges()) << "The number of edges after decimation is not correct!"; + EXPECT_EQ(9996u, mesh_.n_faces()) << "The number of faces after decimation is not correct!"; +} + +TEST_F(OpenMeshMixedDecimater, DecimateMeshToFaceFaceLimit) { + + bool ok = OpenMesh::IO::read_mesh(mesh_, "cube1.off"); + + ASSERT_TRUE(ok); + + 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; + decimaterDBG.add( hModQuadricDBG ); + decimaterDBG.initialize(); + int removedVertices = 0; + removedVertices = decimaterDBG.decimate_to_faces(4500, 9996, 0.7); + decimaterDBG.mesh().garbage_collection(); + + EXPECT_EQ(2526, removedVertices) << "The number of remove vertices is not correct!"; + EXPECT_EQ(5000u, mesh_.n_vertices()) << "The number of vertices after decimation is not correct!"; + EXPECT_EQ(14994u, mesh_.n_edges()) << "The number of edges after decimation is not correct!"; + EXPECT_EQ(9996u, mesh_.n_faces()) << "The number of faces after decimation is not correct!"; +} + +#endif // INCLUDE GUARD