diff --git a/src/OpenMesh/Tools/Decimater/DecimaterT.cc b/src/OpenMesh/Tools/Decimater/DecimaterT.cc index 0a384fb7dc53af343e947687e2d829af4e20ee38..6401385c79099a63cc48f6f1f2e7398f03cbce74 100644 --- a/src/OpenMesh/Tools/Decimater/DecimaterT.cc +++ b/src/OpenMesh/Tools/Decimater/DecimaterT.cc @@ -211,12 +211,10 @@ bool DecimaterT::is_collapse_legal(const CollapseInfo& _ci) { // locked ? deleted ? if (mesh_.status(_ci.v0).locked() || mesh_.status(_ci.v0).deleted()) return false; - /* - if (!mesh_.is_collapse_ok(_ci.v0v1)) - { - return false; - } - */ + + if (!mesh_.is_collapse_ok(_ci.v0v1)) + return false; + if (_ci.vl.is_valid() && _ci.vr.is_valid() && mesh_.find_halfedge(_ci.vl, _ci.vr).is_valid() && mesh_.valence(_ci.vl) == 3 && mesh_.valence(_ci.vr) == 3) { diff --git a/src/OpenMesh/Tools/Decimater/DecimaterT.hh b/src/OpenMesh/Tools/Decimater/DecimaterT.hh index 907b4613a7ed85300c0d07c9ccbe1e21131002e1..a5fd3fcc4d981a911c098207dc450f71d88c46c6 100644 --- a/src/OpenMesh/Tools/Decimater/DecimaterT.hh +++ b/src/OpenMesh/Tools/Decimater/DecimaterT.hh @@ -128,7 +128,7 @@ public: //--------------------------------------------------- module management all_modules_.push_back( _mh.module() ); set_uninitialized(); - + return true; } @@ -280,7 +280,7 @@ private: //------------------------------------------------------- private data // list of all allocated modules (including cmodule_ and all of bmodules_) ModuleList all_modules_; - + bool initialized_; diff --git a/src/OpenMesh/Tools/Decimater/McDecimaterT.cc b/src/OpenMesh/Tools/Decimater/McDecimaterT.cc new file mode 100644 index 0000000000000000000000000000000000000000..8c59353f13596969ef470b1af138e02f882db361 --- /dev/null +++ b/src/OpenMesh/Tools/Decimater/McDecimaterT.cc @@ -0,0 +1,482 @@ +/*===========================================================================*\ + * * + * 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 McDecimaterT.cc + */ + +//============================================================================= +// +// CLASS McDecimaterT - IMPLEMENTATION +// +//============================================================================= +#define OPENMESH_MULTIPLE_CHOICE_DECIMATER_DECIMATERT_CC + +//== INCLUDES ================================================================= + +#include + +#include +#if defined(OM_CC_MIPS) +# include +#else +# include +#endif + +//== NAMESPACE =============================================================== + +namespace OpenMesh { +namespace Decimater { + +//== IMPLEMENTATION ========================================================== + +template +McDecimaterT::McDecimaterT(Mesh& _mesh) : + mesh_(_mesh), cmodule_(NULL), initialized_(false),randomSamples_(10) { + + // default properties + mesh_.request_vertex_status(); + mesh_.request_halfedge_status(); + mesh_.request_edge_status(); + mesh_.request_face_status(); + mesh_.request_face_normals(); + +} + +//----------------------------------------------------------------------------- + +template +McDecimaterT::~McDecimaterT() { + // default properties + mesh_.release_vertex_status(); + mesh_.release_edge_status(); + mesh_.release_halfedge_status(); + mesh_.release_face_status(); + mesh_.release_face_normals(); + + // dispose of modules + { + set_uninitialized(); + typename ModuleList::iterator m_it, m_end = all_modules_.end(); + for (m_it = all_modules_.begin(); m_it != m_end; ++m_it) + delete *m_it; + all_modules_.clear(); + } +} + +//----------------------------------------------------------------------------- + +template +void McDecimaterT::info(std::ostream& _os) { + if (initialized_) { + _os << "initialized : yes" << std::endl; + _os << "binary modules: " << bmodules_.size() << std::endl; + for (ModuleListIterator m_it = bmodules_.begin(); m_it != bmodules_.end(); + ++m_it) { + _os << " " << (*m_it)->name() << std::endl; + } + _os << "priority module: " << cmodule_->name().c_str() << std::endl; + } else { + _os << "initialized : no" << std::endl; + _os << "available modules: " << all_modules_.size() << std::endl; + for (ModuleListIterator m_it = all_modules_.begin(); + m_it != all_modules_.end(); ++m_it) { + _os << " " << (*m_it)->name() << " : "; + if ((*m_it)->is_binary()) { + _os << "binary"; + if ((*m_it)->name() == "Quadric") { + _os << " and priority (special treatment)"; + } + } else { + _os << "priority"; + } + _os << std::endl; + } + } +} + +//----------------------------------------------------------------------------- + +template +bool McDecimaterT::initialize() { + if (initialized_) { + return true; + } + + // FIXME: quadric module shouldn't be treated specially. + // Q: Why? + // A: It isn't generic and breaks encapsulation. Also, using string + // name comparison is not reliable, since you can't guarantee that + // no one else will name their custom module "Quadric". + // Q: What should be done instead? + // A: ModBaseT API should support modules that can be both binary + // and priority, or BETTER YET, let the McDecimaterT API specify the + // priority module explicitly. + + // find the priority module: either the only non-binary module in the list, or "Quadric" + Module *quadric = NULL; + Module *pmodule = NULL; + for (ModuleListIterator m_it = all_modules_.begin(), m_end = + all_modules_.end(); m_it != m_end; ++m_it) { + if ((*m_it)->name() == "Quadric") + quadric = *m_it; + + if (!(*m_it)->is_binary()) { + if (pmodule) { + // only one priority module allowed! + set_uninitialized(); + return false; + } + pmodule = *m_it; + } + } + + // Quadric is used as default priority module (even if it is set to be binary) + if (!pmodule && quadric) { + pmodule = quadric; + } + + if (!pmodule) { + // At least one priority module required + set_uninitialized(); + return false; + } + + // set pmodule as the current priority module + cmodule_ = pmodule; + + for (ModuleListIterator m_it = all_modules_.begin(), m_end = + all_modules_.end(); m_it != m_end; ++m_it) { + // every module gets initialized + (*m_it)->initialize(); + + if (*m_it != pmodule) { + // all other modules are binary, and go into bmodules_ list + bmodules_.push_back(*m_it); + } + } + + return initialized_ = true; +} + +//----------------------------------------------------------------------------- + +template +bool McDecimaterT::is_collapse_legal(const CollapseInfo& _ci) { + // std::clog << "McDecimaterT<>::is_collapse_legal()\n"; + + // locked ? deleted ? + if (mesh_.status(_ci.v0).locked() || mesh_.status(_ci.v0).deleted()) + return false; + + if (!mesh_.is_collapse_ok(_ci.v0v1)) + return false; + + if (_ci.vl.is_valid() && _ci.vr.is_valid() + && mesh_.find_halfedge(_ci.vl, _ci.vr).is_valid() + && mesh_.valence(_ci.vl) == 3 && mesh_.valence(_ci.vr) == 3) { + return false; + } + //--- feature test --- + + if (mesh_.status(_ci.v0).feature() + && !mesh_.status(mesh_.edge_handle(_ci.v0v1)).feature()) + return false; + + //--- test one ring intersection --- + + typename Mesh::VertexVertexIter vv_it; + + for (vv_it = mesh_.vv_iter(_ci.v0); vv_it; ++vv_it) + mesh_.status(vv_it).set_tagged(false); + + for (vv_it = mesh_.vv_iter(_ci.v1); vv_it; ++vv_it) + mesh_.status(vv_it).set_tagged(true); + + for (vv_it = mesh_.vv_iter(_ci.v0); vv_it; ++vv_it) + if (mesh_.status(vv_it).tagged() && vv_it.handle() != _ci.vl + && vv_it.handle() != _ci.vr) + return false; + + // if both are invalid OR equal -> fail + if (_ci.vl == _ci.vr) + return false; + + //--- test boundary cases --- + if (mesh_.is_boundary(_ci.v0)) { + if (!mesh_.is_boundary(_ci.v1)) { // don't collapse a boundary vertex to an inner one + return false; + } else { // edge between two boundary vertices has to be a boundary edge + if (!(mesh_.is_boundary(_ci.v0v1) || mesh_.is_boundary(_ci.v1v0))) + return false; + } + // only one one ring intersection + if (_ci.vl.is_valid() && _ci.vr.is_valid()) + return false; + } + + // v0vl and v1vl must not both be boundary edges + if (_ci.vl.is_valid() && mesh_.is_boundary(_ci.vlv1) + && mesh_.is_boundary(_ci.v0vl)) + return false; + + // v0vr and v1vr must not be both boundary edges + if (_ci.vr.is_valid() && mesh_.is_boundary(_ci.vrv0) + && mesh_.is_boundary(_ci.v1vr)) + return false; + + // there have to be at least 2 incident faces at v0 + if (mesh_.cw_rotated_halfedge_handle( + mesh_.cw_rotated_halfedge_handle(_ci.v0v1)) == _ci.v0v1) + return false; + + // collapse passed all tests -> ok + return true; +} + +//----------------------------------------------------------------------------- + +template +float McDecimaterT::collapse_priority(const CollapseInfo& _ci) { + typename ModuleList::iterator m_it, m_end = bmodules_.end(); + + for (m_it = bmodules_.begin(); m_it != m_end; ++m_it) { + if ((*m_it)->collapse_priority(_ci) < 0.0) + return ModBaseT >::ILLEGAL_COLLAPSE; + } + return cmodule_->collapse_priority(_ci); +} + +//----------------------------------------------------------------------------- + +template +void McDecimaterT::postprocess_collapse(CollapseInfo& _ci) { + typename ModuleList::iterator m_it, m_end = bmodules_.end(); + + for (m_it = bmodules_.begin(); m_it != m_end; ++m_it) + (*m_it)->postprocess_collapse(_ci); + + cmodule_->postprocess_collapse(_ci); +} + +//----------------------------------------------------------------------------- + +template +void McDecimaterT::preprocess_collapse(CollapseInfo& _ci) { + typename ModuleList::iterator m_it, m_end = bmodules_.end(); + + for (m_it = bmodules_.begin(); m_it != m_end; ++m_it) + (*m_it)->preprocess_collapse(_ci); + + cmodule_->preprocess_collapse(_ci); +} + +//----------------------------------------------------------------------------- +template +size_t McDecimaterT::decimate(size_t _n_collapses) { + + if (!is_initialized()) + return 0; + + unsigned int n_collapses(0); + + while ( n_collapses < _n_collapses) { + + // Optimal id and value will be collected during the random sampling + typename Mesh::HalfedgeHandle bestHandle(-1); + double bestEnergy = FLT_MAX; + + // Generate random samples for collapses + for ( unsigned int i = 0; i < randomSamples_; ++i) { + + // Random halfedge handle + typename Mesh::HalfedgeHandle tmpHandle = typename Mesh::HalfedgeHandle(double(rand()) / RAND_MAX * mesh_.n_halfedges() ); + + // if it is not deleted, we analyse it + if ( ! mesh_.status(tmpHandle).deleted() ) { + + CollapseInfo ci(mesh_, tmpHandle); + + // Check if legal we analyze the priority of this collapse operation + if (is_collapse_legal(ci)) { + double energy = collapse_priority(ci); + + // Check if the current samples energy is better than any energy before + if ( energy < bestEnergy ) { + bestEnergy = energy; + bestHandle = tmpHandle; + } + } else { + continue; + } + } + + } + + // Found the best energy? + if ( bestEnergy != FLT_MAX ) { + + // setup collapse info + CollapseInfo ci(mesh_, bestHandle); + + // check topological correctness AGAIN ! + if (!is_collapse_legal(ci)) + continue; + + // pre-processing + preprocess_collapse(ci); + + // perform collapse + mesh_.collapse(bestHandle); + ++n_collapses; + + // update triangle normals + typename Mesh::VertexFaceIter vf_it = mesh_.vf_iter(ci.v1); + for (; vf_it; ++vf_it) + if (!mesh_.status(vf_it).deleted()) + mesh_.set_normal(vf_it, mesh_.calc_face_normal(vf_it.handle())); + + // post-process collapse + postprocess_collapse(ci); + + } + + } + + // DON'T do garbage collection here! It's up to the application. + return n_collapses; +} + +//----------------------------------------------------------------------------- + +template +size_t McDecimaterT::decimate_to_faces(size_t _nv, size_t _nf) { + if (!is_initialized()) + return 0; + + unsigned int nv = mesh_.n_vertices(); + unsigned int nf = mesh_.n_faces(); + unsigned int n_collapses(0); + + while ( (_nv < nv) && (_nf < nf) ) { + + // Optimal id and value will be collected during the random sampling + typename Mesh::HalfedgeHandle bestHandle(-1); + double bestEnergy = FLT_MAX; + + // Generate random samples for collapses + for ( unsigned int i = 0; i < randomSamples_; ++i) { + + // Random halfedge handle + typename Mesh::HalfedgeHandle tmpHandle = typename Mesh::HalfedgeHandle(double(rand()) / RAND_MAX * mesh_.n_halfedges() ); + + // if it is not deleted, we analyse it + if ( ! mesh_.status(tmpHandle).deleted() ) { + + CollapseInfo ci(mesh_, tmpHandle); + + // Check if legal we analyze the priority of this collapse operation + if (is_collapse_legal(ci)) { + double energy = collapse_priority(ci); + + // Check if the current samples energy is better than any energy before + if ( energy < bestEnergy ) { + bestEnergy = energy; + bestHandle = tmpHandle; + } + } else { + continue; + } + } + + } + + // Found the best energy? + if ( bestEnergy != FLT_MAX ) { + + // setup collapse info + CollapseInfo ci(mesh_, bestHandle); + + // check topological correctness AGAIN ! + if (!is_collapse_legal(ci)) + continue; + + // adjust complexity in advance (need boundary status) + ++n_collapses; + + // One vertex is killed by the collapse + --nv; + + // If we are at a boundary, one face is lost, + // otherwise two + if (mesh_.is_boundary(ci.v0v1) || mesh_.is_boundary(ci.v1v0)) + --nf; + else + nf -= 2; + + // pre-processing + preprocess_collapse(ci); + + // perform collapse + mesh_.collapse(bestHandle); + ++n_collapses; + + // update triangle normals + typename Mesh::VertexFaceIter vf_it = mesh_.vf_iter(ci.v1); + for (; vf_it; ++vf_it) + if (!mesh_.status(vf_it).deleted()) + mesh_.set_normal(vf_it, mesh_.calc_face_normal(vf_it.handle())); + + // post-process collapse + postprocess_collapse(ci); + + } + + } + + // DON'T do garbage collection here! It's up to the application. + return n_collapses; +} + +//============================================================================= +}// END_NS_MC_DECIMATER +} // END_NS_OPENMESH +//============================================================================= + diff --git a/src/OpenMesh/Tools/Decimater/McDecimaterT.hh b/src/OpenMesh/Tools/Decimater/McDecimaterT.hh new file mode 100644 index 0000000000000000000000000000000000000000..d62f015c14ec385cdafb0830f94cace4e22f049d --- /dev/null +++ b/src/OpenMesh/Tools/Decimater/McDecimaterT.hh @@ -0,0 +1,276 @@ +/*===========================================================================*\ + * * + * 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: 448 $ * + * $Date: 2011-11-04 13:59:37 +0100 (Fr, 04 Nov 2011) $ * + * * +\*===========================================================================*/ + +/** \file McDecimaterT.hh + */ + +//============================================================================= +// +// CLASS McDecimaterT +// +//============================================================================= + +#ifndef OPENMESH_MC_DECIMATER_DECIMATERT_HH +#define OPENMESH_MC_DECIMATER_DECIMATERT_HH + + +//== INCLUDES ================================================================= + +#include + +#include +#include + + + +//== NAMESPACE ================================================================ + +namespace OpenMesh { +namespace Decimater { + + +//== CLASS DEFINITION ========================================================= + + +/** Multiple choice decimater framework + \see BaseModT, \ref decimater_docu +*/ +template < typename MeshT > +class McDecimaterT +{ +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 + McDecimaterT( Mesh& _mesh ); + + /// Destructor + ~McDecimaterT(); + + + /** Initialize decimater and decimating modules. + + Return values: + true ok + false No ore more than one non-binary module exist. In that case + the decimater is uninitialized! + */ + bool initialize(); + + + /// Returns whether decimater has been successfully initialized. + bool is_initialized() const { return initialized_; } + + + /// Print information about modules to _os + void info( std::ostream& _os ); + +public: //--------------------------------------------------- module management + + /// access mesh. used in modules. + Mesh& mesh() { return mesh_; } + + /// add module to decimater + template < typename _Module > + bool add( ModHandleT<_Module>& _mh ) + { + if (_mh.is_valid()) + return false; + + _mh.init( new _Module(*this) ); + all_modules_.push_back( _mh.module() ); + + set_uninitialized(); + + return true; + } + + + /// remove module + template < typename _Module > + bool remove( ModHandleT<_Module>& _mh ) + { + if (!_mh.is_valid()) + return false; + + typename ModuleList::iterator it = std::find(all_modules_.begin(), + all_modules_.end(), + _mh.module() ); + + if ( it == all_modules_.end() ) // module not found + return false; + + delete *it; + all_modules_.erase( it ); // finally remove from list + _mh.clear(); + + set_uninitialized(); + return true; + } + + + /// get module referenced by handle _mh + template < typename Module > + Module& module( ModHandleT& _mh ) + { + assert( _mh.is_valid() ); + return *_mh.module(); + } + +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( size_t _n_collapses ); + + /// Decimate to target complexity, returns number of collapses + size_t decimate_to( size_t _n_vertices ) + { + return ( (_n_vertices < mesh().n_vertices()) ? + decimate( mesh().n_vertices() - _n_vertices ) : 0 ); + } + + /** Decimate to target complexity (vertices and faces). + * Returns number of performed collapses. + */ + size_t decimate_to_faces( size_t _n_vertices=0, size_t _n_faces=0 ); + +private: + + void update_modules(CollapseInfo& _ci) + { + typename ModuleList::iterator m_it, m_end = bmodules_.end(); + for (m_it = bmodules_.begin(); m_it != m_end; ++m_it) + (*m_it)->postprocess_collapse(_ci); + cmodule_->postprocess_collapse(_ci); + } + +public: + + typedef typename Mesh::VertexHandle VertexHandle; + typedef typename Mesh::HalfedgeHandle HalfedgeHandle; + + /// Heap interface + class HeapInterface + { + public: + + HeapInterface(Mesh& _mesh) + : mesh_(_mesh) + { } + + private: + Mesh& mesh_; + }; + + +private: //---------------------------------------------------- private methods + + /// Is an edge collapse legal? Performs topological test only. + /// The method evaluates the status bit Locked, Deleted, and Feature. + /// \attention The method temporarily sets the bit Tagged. After usage + /// the bit will be disabled! + bool is_collapse_legal(const CollapseInfo& _ci); + + /// Calculate priority of an halfedge collapse (using the modules) + float collapse_priority(const CollapseInfo& _ci); + + /// Pre-process a collapse + void preprocess_collapse(CollapseInfo& _ci); + + /// Post-process a collapse + void postprocess_collapse(CollapseInfo& _ci); + + // Reset the initialized flag, and clear the bmodules_ and cmodule_ + void set_uninitialized() { + initialized_ = false; + cmodule_ = 0; + bmodules_.clear(); + } + + +private: //------------------------------------------------------- private data + + + // reference to mesh + Mesh& mesh_; + + // list of binary modules + ModuleList bmodules_; + + // the current priority module + Module* cmodule_; + + // list of all allocated modules (including cmodule_ and all of bmodules_) + ModuleList all_modules_; + + bool initialized_; + + unsigned int randomSamples_; + +private: // Noncopyable + + McDecimaterT(const Self&); + Self& operator = (const Self&); + +}; + +//============================================================================= +} // END_NS_DECIMATER +} // END_NS_OPENMESH +//============================================================================= +#if defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_MULTIPLE_CHOICE_DECIMATER_DECIMATERT_CC) +#define OPENMESH_MULTIPLE_CHOICE_DECIMATER_TEMPLATES +#include "McDecimaterT.cc" +#endif +//============================================================================= +#endif // OPENMESH_DECIMATER_DECIMATERT_HH defined +//============================================================================= + diff --git a/src/OpenMesh/Tools/Decimater/ModBaseT.hh b/src/OpenMesh/Tools/Decimater/ModBaseT.hh index 61ca66e3abdce9b9b2d649e79a79b6534ec79215..a476476cc905fb4e3ad48b57b3413c0dd5581e78 100644 --- a/src/OpenMesh/Tools/Decimater/ModBaseT.hh +++ b/src/OpenMesh/Tools/Decimater/ModBaseT.hh @@ -69,6 +69,7 @@ namespace Decimater { //== FORWARD DECLARATIONS ===================================================== template class DecimaterT; +template class McDecimaterT; //== CLASS DEFINITION ========================================================= @@ -100,8 +101,10 @@ private: #if defined(OM_CC_MSVC) friend class DecimaterT; + friend class McDecimaterT; #else template friend class DecimaterT; + template friend class McDecimaterT; #endif void clear() { mod_ = NULL; } diff --git a/src/OpenMesh/Tools/Decimater/ModHausdorffT.cc b/src/OpenMesh/Tools/Decimater/ModHausdorffT.cc index 3de9b78b64a3def10249490ff62fa2b891cd1d0c..f8387fc951521f427804741e91ac55c1a508bfec 100644 --- a/src/OpenMesh/Tools/Decimater/ModHausdorffT.cc +++ b/src/OpenMesh/Tools/Decimater/ModHausdorffT.cc @@ -220,8 +220,6 @@ collapse_priority(const CollapseInfo& _ci) typename Mesh::CFVIter fv_it; bool ok; - - // collect all points to be tested // collect all faces to be tested against for (vf_it=mesh_.vf_iter(_ci.v0); vf_it; ++vf_it) { @@ -234,22 +232,17 @@ collapse_priority(const CollapseInfo& _ci) std::copy(pts.begin(), pts.end(), std::back_inserter(points)); } - // add point to be removed points.push_back(_ci.p0); - // setup iterators typename std::vector::iterator fh_it, fh_end(faces.end()); typename Points::const_iterator p_it, p_end(points.end()); - // simulate collapse mesh_.set_point(_ci.v0, _ci.p1); - - // for each point: try to find a face such that error is < tolerance ok = true; for (p_it=points.begin(); ok && p_it!=p_end; ++p_it) { @@ -265,13 +258,9 @@ collapse_priority(const CollapseInfo& _ci) } } - - // undo simulation changes mesh_.set_point(_ci.v0, _ci.p0); - - return ( ok ? Base::LEGAL_COLLAPSE : Base::ILLEGAL_COLLAPSE ); } diff --git a/src/Unittests/unittests.cc b/src/Unittests/unittests.cc index 7b92b84286444b086c78878b371e427ba49147b3..7d8a5eeee359249a4afb63fd8d5480c68a42eaef 100644 --- a/src/Unittests/unittests.cc +++ b/src/Unittests/unittests.cc @@ -7,6 +7,7 @@ #include "unittests_trimesh_collapse.hh" #include "unittests_trimesh_circulators.hh" #include "unittests_decimater.hh" +#include "unittests_mc_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 6aae46134146d135145514ce9848e1c6e2b3a710..80755a13655b80aaf86949529f133701779ba088 100644 --- a/src/Unittests/unittests_decimater.hh +++ b/src/Unittests/unittests_decimater.hh @@ -54,9 +54,9 @@ TEST_F(OpenMeshDecimater, DecimateMesh) { decimaterDBG.mesh().garbage_collection(); EXPECT_EQ(2526, removedVertices) << "The number of remove vertices is not correct!"; - EXPECT_EQ(5000, mesh_.n_vertices()) << "The number of vertices after decimation is not correct!"; - EXPECT_EQ(14994, mesh_.n_edges()) << "The number of edges after decimation is not correct!"; - EXPECT_EQ(9996, mesh_.n_faces()) << "The number of faces after decimation 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 new file mode 100644 index 0000000000000000000000000000000000000000..f975334657858ca4c938d1a399fd98511bac3fff --- /dev/null +++ b/src/Unittests/unittests_mc_decimater.hh @@ -0,0 +1,62 @@ +#ifndef INCLUDE_UNITTESTS_MC_DECIMATER_HH +#define INCLUDE_UNITTESTS_MC_DECIMATER_HH + +#include +#include +#include +#include +#include + +class OpenMeshMultipleChoiceDecimater : 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(OpenMeshMultipleChoiceDecimater, DecimateMesh) { + + bool ok = OpenMesh::IO::read_mesh(mesh_, "cube1.off"); + + ASSERT_TRUE(ok); + + typedef OpenMesh::Decimater::McDecimaterT< Mesh > Decimater; + typedef OpenMesh::Decimater::ModQuadricT< Decimater >::Handle HModQuadric; + typedef OpenMesh::Decimater::ModNormalFlippingT< Decimater >::Handle HModNormal; + + Decimater decimaterDBG(mesh_); + HModQuadric hModQuadricDBG; + decimaterDBG.add( hModQuadricDBG ); + decimaterDBG.initialize(); + int removedVertices = 0; + removedVertices = decimaterDBG.decimate_to(5000); + 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