From 48289493f317279855e9cba7156bf5dc0ee8ef4a Mon Sep 17 00:00:00 2001 From: Isaak Lim Date: Wed, 19 Sep 2012 16:15:39 +0000 Subject: [PATCH] - added the set_error_tolerance_factor function to ModBaseT and implemented it in inherited classes as necessary - added the set_error_tolerance_factor function to BaseDecimaterT, which calls set_error_tolerance_factor for all loaded Mods - implemented a decimate_constraints_only function for the McDecimater (and adjusted the MixedDecimater accordingly) - implemented stop criterions for the McDecimater - added some OpenMP loops for the sample generation to the McDecimater git-svn-id: http://www.openmesh.org/svnrepo/OpenMesh/trunk@685 fdac6126-5c0c-442c-9429-916003d36597 --- .../Tools/Decimater/BaseDecimaterT.cc | 13 + .../Tools/Decimater/BaseDecimaterT.hh | 10 + src/OpenMesh/Tools/Decimater/DecimaterT.cc | 8 +- src/OpenMesh/Tools/Decimater/McDecimaterT.cc | 281 +++++++++++++++--- src/OpenMesh/Tools/Decimater/McDecimaterT.hh | 14 +- .../Tools/Decimater/MixedDecimaterT.cc | 19 +- .../Tools/Decimater/ModAspectRatioT.cc | 14 + .../Tools/Decimater/ModAspectRatioT.hh | 3 + src/OpenMesh/Tools/Decimater/ModBaseT.hh | 49 +-- .../Tools/Decimater/ModEdgeLengthT.cc | 14 + .../Tools/Decimater/ModEdgeLengthT.hh | 3 + src/OpenMesh/Tools/Decimater/ModHausdorffT.cc | 17 +- src/OpenMesh/Tools/Decimater/ModHausdorffT.hh | 3 + .../Tools/Decimater/ModNormalDeviationT.hh | 14 +- .../Tools/Decimater/ModNormalFlippingT.hh | 65 ++-- src/OpenMesh/Tools/Decimater/ModQuadricT.cc | 25 +- src/OpenMesh/Tools/Decimater/ModQuadricT.hh | 11 +- src/OpenMesh/Tools/Decimater/ModRoundnessT.hh | 49 +-- 18 files changed, 493 insertions(+), 119 deletions(-) diff --git a/src/OpenMesh/Tools/Decimater/BaseDecimaterT.cc b/src/OpenMesh/Tools/Decimater/BaseDecimaterT.cc index e33d4f71..31b6ef48 100644 --- a/src/OpenMesh/Tools/Decimater/BaseDecimaterT.cc +++ b/src/OpenMesh/Tools/Decimater/BaseDecimaterT.cc @@ -207,6 +207,19 @@ void BaseDecimaterT::preprocess_collapse(CollapseInfo& _ci) { cmodule_->preprocess_collapse(_ci); } +//----------------------------------------------------------------------------- + +template +void BaseDecimaterT::set_error_tolerance_factor(double _factor) { + if (_factor >= 0.0 && _factor <= 1.0) { + typename ModuleList::iterator m_it, m_end = bmodules_.end(); + + for (m_it = bmodules_.begin(); m_it != m_end; ++m_it) + (*m_it)->set_error_tolerance_factor(_factor); + + cmodule_->set_error_tolerance_factor(_factor); + } +} //----------------------------------------------------------------------------- diff --git a/src/OpenMesh/Tools/Decimater/BaseDecimaterT.hh b/src/OpenMesh/Tools/Decimater/BaseDecimaterT.hh index 9046518f..b2ee120f 100644 --- a/src/OpenMesh/Tools/Decimater/BaseDecimaterT.hh +++ b/src/OpenMesh/Tools/Decimater/BaseDecimaterT.hh @@ -199,6 +199,16 @@ protected: //---------------------------------------------------- private method /// Post-process a collapse void postprocess_collapse(CollapseInfo& _ci); + /** + * This provides a function that allows the setting of a percentage + * of the original contraint of the modules + * + * Note that some modules might re-initialize in their + * set_error_tolerance_factor function as necessary + * @param factor_ has to be in the closed interval between 0.0 and 1.0 + */ + void set_error_tolerance_factor(double _factor); + private: //------------------------------------------------------- private data diff --git a/src/OpenMesh/Tools/Decimater/DecimaterT.cc b/src/OpenMesh/Tools/Decimater/DecimaterT.cc index 2a38676b..34b0bda0 100644 --- a/src/OpenMesh/Tools/Decimater/DecimaterT.cc +++ b/src/OpenMesh/Tools/Decimater/DecimaterT.cc @@ -4,10 +4,10 @@ * 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 * + * 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 * @@ -33,7 +33,7 @@ \*===========================================================================*/ /*===========================================================================*\ - * * + * * * $Revision$ * * $Date$ * * * @@ -214,6 +214,7 @@ size_t DecimaterT::decimate(size_t _n_collapses) { // delete heap heap_.reset(); + // DON'T do garbage collection here! It's up to the application. return n_collapses; } @@ -307,6 +308,7 @@ size_t DecimaterT::decimate_to_faces(size_t _nv, size_t _nf) { // delete heap heap_.reset(); + // DON'T do garbage collection here! It's up to the application. return n_collapses; } diff --git a/src/OpenMesh/Tools/Decimater/McDecimaterT.cc b/src/OpenMesh/Tools/Decimater/McDecimaterT.cc index a0e2085d..0127d3b5 100644 --- a/src/OpenMesh/Tools/Decimater/McDecimaterT.cc +++ b/src/OpenMesh/Tools/Decimater/McDecimaterT.cc @@ -59,6 +59,9 @@ #else # include #endif +#ifdef USE_OPENMP +#include +#endif //== NAMESPACE =============================================================== @@ -103,17 +106,33 @@ size_t McDecimaterT::decimate(size_t _n_collapses) { unsigned int n_collapses(0); + bool collapsesUnchanged = false; + // old n_collapses in order to check for convergence + unsigned int oldCollapses = 0; + // number of iterations where no new collapses where + // performed in a row + unsigned int noCollapses = 0; + while ( n_collapses < _n_collapses) { + if (noCollapses > 20) { + omlog() << "[McDecimater] : no collapses performed in over 20 iterations in a row\n"; + break; + } // Optimal id and value will be collected during the random sampling typename Mesh::HalfedgeHandle bestHandle(-1); + typename Mesh::HalfedgeHandle tmpHandle(-1); double bestEnergy = FLT_MAX; + double energy = FLT_MAX; // Generate random samples for collapses +#ifdef USE_OPENMP +#pragma omp parallel for private(energy,tmpHandle) shared(bestEnergy,bestHandle) +#endif for ( int i = 0; i < (int)randomSamples_; ++i) { // Random halfedge handle - typename Mesh::HalfedgeHandle tmpHandle = typename Mesh::HalfedgeHandle((static_cast(rand()) / RAND_MAX) * (mesh_.n_halfedges()-1) ); + tmpHandle = typename Mesh::HalfedgeHandle((static_cast(rand()) / RAND_MAX) * (mesh_.n_halfedges()-1) ); // if it is not deleted, we analyse it if ( ! mesh_.status(tmpHandle).deleted() ) { @@ -122,13 +141,22 @@ size_t McDecimaterT::decimate(size_t _n_collapses) { // Check if legal we analyze the priority of this collapse operation if (this->is_collapse_legal(ci)) { - double energy = this->collapse_priority(ci); +#ifdef USE_OPENMP +#pragma omp critical(energyUpdate) + { +#endif + energy = this->collapse_priority(ci); - // Check if the current samples energy is better than any energy before - if ( energy < bestEnergy ) { - bestEnergy = energy; - bestHandle = tmpHandle; + if (energy != ModBaseT::ILLEGAL_COLLAPSE) { + // Check if the current samples energy is better than any energy before + if ( energy < bestEnergy ) { + bestEnergy = energy; + bestHandle = tmpHandle; + } } +#ifdef USE_OPENMP + } +#endif } else { continue; } @@ -153,6 +181,11 @@ size_t McDecimaterT::decimate(size_t _n_collapses) { mesh_.collapse(bestHandle); ++n_collapses; + // store current collapses state + oldCollapses = n_collapses; + noCollapses = 0; + collapsesUnchanged = false; + // update triangle normals typename Mesh::VertexFaceIter vf_it = mesh_.vf_iter(ci.v1); for (; vf_it; ++vf_it) @@ -162,6 +195,15 @@ size_t McDecimaterT::decimate(size_t _n_collapses) { // post-process collapse this->postprocess_collapse(ci); + } else { + if (oldCollapses == n_collapses) { + if (collapsesUnchanged == false) { + noCollapses = 1; + collapsesUnchanged = true; + } else { + noCollapses++; + } + } } } @@ -177,34 +219,43 @@ size_t McDecimaterT::decimate_to_faces(size_t _nv, size_t _nf) { if (!this->is_initialized()) return 0; + // check if no vertex or face contraints were set + if ( (_nv == 0) && (_nf == 1) ) + return decimate_constraints_only(1.0); + unsigned int nv = mesh_.n_vertices(); unsigned int nf = mesh_.n_faces(); unsigned int n_collapses(0); - // check if no vertex or face contraints were set - bool contraintsOnly = (_nv == 0) && (_nf == 1); + bool collapsesUnchanged = false; + // old n_collapses in order to check for convergence + unsigned int oldCollapses = 0; + // number of iterations where no new collapses where + // performed in a row + unsigned int noCollapses = 0; - // check if no legal collapses were found three times in a row - // for the sampled halfedges - bool foundNoLegalCollapsesThrice = false; - - // store the last two amount of legal collapses found - int lastLegalCollapses = -1; - int beforeLastLegalCollapses = -1; - - while ( !foundNoLegalCollapsesThrice && (_nv < nv) && (_nf < nf) ) { + while ( (_nv < nv) && (_nf < nf) ) { + if (noCollapses > 20) { + omlog() << "[McDecimater] : no collapses performed in over 20 iterations in a row\n"; + break; + } // Optimal id and value will be collected during the random sampling typename Mesh::HalfedgeHandle bestHandle(-1); + typename Mesh::HalfedgeHandle tmpHandle(-1); double bestEnergy = FLT_MAX; + double energy = FLT_MAX; + // Generate random samples for collapses - unsigned int legalCollapses = 0; +#ifdef USE_OPENMP +#pragma omp parallel for private(energy,tmpHandle) shared(bestEnergy,bestHandle) +#endif for ( int i = 0; i < (int)randomSamples_; ++i) { // Random halfedge handle - typename Mesh::HalfedgeHandle tmpHandle = typename Mesh::HalfedgeHandle((static_cast(rand()) / RAND_MAX) * (mesh_.n_halfedges()-1) ); + tmpHandle = typename Mesh::HalfedgeHandle((static_cast(rand()) / RAND_MAX) * (mesh_.n_halfedges()-1) ); // if it is not deleted, we analyse it if ( ! mesh_.status(tmpHandle).deleted() ) { @@ -213,14 +264,22 @@ size_t McDecimaterT::decimate_to_faces(size_t _nv, size_t _nf) { // Check if legal we analyze the priority of this collapse operation if (this->is_collapse_legal(ci)) { - ++legalCollapses; - double energy = this->collapse_priority(ci); +#ifdef USE_OPENMP +#pragma omp critical(energyUpdate) + { +#endif + energy = this->collapse_priority(ci); - // Check if the current samples energy is better than any energy before - if ( energy < bestEnergy ) { - bestEnergy = energy; - bestHandle = tmpHandle; + if (energy != ModBaseT::ILLEGAL_COLLAPSE) { + // Check if the current samples energy is better than any energy before + if ( energy < bestEnergy ) { + bestEnergy = energy; + bestHandle = tmpHandle; + } + } +#ifdef USE_OPENMP } +#endif } else { continue; } @@ -228,15 +287,6 @@ size_t McDecimaterT::decimate_to_faces(size_t _nv, size_t _nf) { } - if (contraintsOnly) { - // check if no legal collapses were found three times in a row - foundNoLegalCollapsesThrice = (beforeLastLegalCollapses == 0) && (lastLegalCollapses == 0) && (legalCollapses == 0); - - // store amount of last legal collapses found - beforeLastLegalCollapses = lastLegalCollapses; - lastLegalCollapses = legalCollapses; - } - // Found the best energy? if ( bestEnergy != FLT_MAX ) { @@ -267,6 +317,11 @@ size_t McDecimaterT::decimate_to_faces(size_t _nv, size_t _nf) { mesh_.collapse(bestHandle); ++n_collapses; + // store current collapses state + oldCollapses = n_collapses; + noCollapses = 0; + collapsesUnchanged = false; + // update triangle normals typename Mesh::VertexFaceIter vf_it = mesh_.vf_iter(ci.v1); for (; vf_it; ++vf_it) @@ -276,6 +331,15 @@ size_t McDecimaterT::decimate_to_faces(size_t _nv, size_t _nf) { // post-process collapse this->postprocess_collapse(ci); + } else { + if (oldCollapses == n_collapses) { + if (collapsesUnchanged == false) { + noCollapses = 1; + collapsesUnchanged = true; + } else { + noCollapses++; + } + } } } @@ -284,6 +348,155 @@ size_t McDecimaterT::decimate_to_faces(size_t _nv, size_t _nf) { return n_collapses; } +//----------------------------------------------------------------------------- + +template +size_t McDecimaterT::decimate_constraints_only(float _factor) { + if (!this->is_initialized()) + return 0; + + if (_factor < 1.0) + this->set_error_tolerance_factor(_factor); + + unsigned int n_collapses(0); + unsigned int nv = mesh_.n_vertices(); + unsigned int nf = mesh_.n_faces(); + + bool lastCollapseIllegal = false; + // number of illegal collapses that occured in a row + unsigned int illegalCollapses = 0; + + bool collapsesUnchanged = false; + // old n_collapses in order to check for convergence + unsigned int oldCollapses = 0; + // number of iterations where no new collapses where + // performed in a row + unsigned int noCollapses = 0; + + + while ( (noCollapses <= 20) && (illegalCollapses <= 10) && (nv > 0) && (nf > 1) ) { + + // Optimal id and value will be collected during the random sampling + typename Mesh::HalfedgeHandle bestHandle(-1); + typename Mesh::HalfedgeHandle tmpHandle(-1); + double bestEnergy = FLT_MAX; + double energy = FLT_MAX; + + // Generate random samples for collapses +#ifdef USE_OPENMP +#pragma omp parallel for private(energy,tmpHandle) shared(bestEnergy,bestHandle) +#endif + for ( int i = 0; i < (int)randomSamples_; ++i) { + + // Random halfedge handle + tmpHandle = typename Mesh::HalfedgeHandle((static_cast(rand()) / RAND_MAX) * (mesh_.n_halfedges()-1) ); + + // 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 (this->is_collapse_legal(ci)) { +#ifdef USE_OPENMP +#pragma omp critical(energyUpdate) + { +#endif + + energy = this->collapse_priority(ci); + + if (energy == ModBaseT::ILLEGAL_COLLAPSE){ + if (lastCollapseIllegal) { + illegalCollapses++; + } else { + illegalCollapses = 1; + lastCollapseIllegal = true; + } + } else { + illegalCollapses = 0; + lastCollapseIllegal = false; + + // Check if the current samples energy is better than any energy before + if ( energy < bestEnergy ) { + bestEnergy = energy; + bestHandle = tmpHandle; + } + } +#ifdef USE_OPENMP + } +#endif + } else { + continue; + } + } + + } + + // Found the best energy? + if ( bestEnergy != FLT_MAX ) { + + // setup collapse info + CollapseInfo ci(mesh_, bestHandle); + + // check topological correctness AGAIN ! + if (!this->is_collapse_legal(ci)) + continue; + + // adjust complexity in advance (need boundary status) + + // 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 + this->preprocess_collapse(ci); + + // perform collapse + mesh_.collapse(bestHandle); + ++n_collapses; + + // store current collapses state + oldCollapses = n_collapses; + noCollapses = 0; + collapsesUnchanged = false; + + + // 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 + this->postprocess_collapse(ci); + + } else { + if (oldCollapses == n_collapses) { + if (collapsesUnchanged == false) { + noCollapses = 1; + collapsesUnchanged = true; + } else { + noCollapses++; + } + } + } + + } + + if (_factor < 1.0) + this->set_error_tolerance_factor(1.0); + + // 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 index c7de26bb..d16f1808 100644 --- a/src/OpenMesh/Tools/Decimater/McDecimaterT.hh +++ b/src/OpenMesh/Tools/Decimater/McDecimaterT.hh @@ -4,10 +4,10 @@ * 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 * + * 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 * @@ -30,10 +30,10 @@ * License along with OpenMesh. If not, * * see . * * * -\*===========================================================================*/ +\*===========================================================================*/ /*===========================================================================*\ - * * + * * * $Revision: 448 $ * * $Date: 2011-11-04 13:59:37 +0100 (Fr, 04 Nov 2011) $ * * * @@ -111,6 +111,12 @@ public: */ size_t decimate_to_faces( size_t _n_vertices=0, size_t _n_faces=0 ); + /** + * Decimate only with constraints, while _factor gives the + * percentage of the constraints that should be used + */ + size_t decimate_constraints_only(float _factor); + size_t samples(){return randomSamples_;} void set_samples(const size_t _value){randomSamples_ = _value;} diff --git a/src/OpenMesh/Tools/Decimater/MixedDecimaterT.cc b/src/OpenMesh/Tools/Decimater/MixedDecimaterT.cc index 400eb4d7..55535532 100644 --- a/src/OpenMesh/Tools/Decimater/MixedDecimaterT.cc +++ b/src/OpenMesh/Tools/Decimater/MixedDecimaterT.cc @@ -94,6 +94,7 @@ size_t MixedDecimaterT::decimate(const size_t _n_collapses, const float _m r_collapses = McDecimaterT::decimate(n_collapses_mc); if (_mc_factor < 1.0) r_collapses += DecimaterT::decimate(n_collapses_inc); + return r_collapses; } @@ -106,13 +107,18 @@ size_t MixedDecimaterT::decimate_to_faces(const size_t _n_vertices,const 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)); + bool constraintsOnly = (_n_vertices == 0) && (_n_faces == 1); + if (!constraintsOnly) { + 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); + r_collapses = McDecimaterT::decimate_to_faces(n_vertices_mc, n_faces_mc); + } else { + r_collapses = McDecimaterT::decimate_constraints_only(_mc_factor); + } } //update the mesh::n_vertices function, otherwise the next Decimater function will delete to much @@ -122,6 +128,7 @@ size_t MixedDecimaterT::decimate_to_faces(const size_t _n_vertices,const if (_mc_factor < 1.0) r_collapses += DecimaterT::decimate_to_faces(_n_vertices,_n_faces); + return r_collapses; } diff --git a/src/OpenMesh/Tools/Decimater/ModAspectRatioT.cc b/src/OpenMesh/Tools/Decimater/ModAspectRatioT.cc index 6d160fec..20860d6b 100644 --- a/src/OpenMesh/Tools/Decimater/ModAspectRatioT.cc +++ b/src/OpenMesh/Tools/Decimater/ModAspectRatioT.cc @@ -173,6 +173,20 @@ float ModAspectRatioT::collapse_priority(const CollapseInfo& _ci) { } } +//----------------------------------------------------------------------------- + +template +void ModAspectRatioT::set_error_tolerance_factor(double _factor) { + if (_factor >= 0.0 && _factor <= 1.0) { + // the smaller the factor, the larger min_aspect_ gets + // thus creating a stricter constraint + // division by (2.0 - error_tolerance_factor_) is for normalization + double min_aspect = min_aspect_ * (2.0 - _factor) / (2.0 - this->error_tolerance_factor_); + set_aspect_ratio(1.0/min_aspect); + this->error_tolerance_factor_ = _factor; + } +} + //============================================================================= } } diff --git a/src/OpenMesh/Tools/Decimater/ModAspectRatioT.hh b/src/OpenMesh/Tools/Decimater/ModAspectRatioT.hh index b04f246a..946cd989 100644 --- a/src/OpenMesh/Tools/Decimater/ModAspectRatioT.hh +++ b/src/OpenMesh/Tools/Decimater/ModAspectRatioT.hh @@ -118,6 +118,9 @@ class ModAspectRatioT: public ModBaseT { /// update aspect ratio of one-ring void preprocess_collapse(const CollapseInfo& _ci); + /// set percentage of aspect ratio + void set_error_tolerance_factor(double _factor); + private: /** \brief return aspect ratio (length/height) of triangle diff --git a/src/OpenMesh/Tools/Decimater/ModBaseT.hh b/src/OpenMesh/Tools/Decimater/ModBaseT.hh index 44177f5f..2d6b0e39 100644 --- a/src/OpenMesh/Tools/Decimater/ModBaseT.hh +++ b/src/OpenMesh/Tools/Decimater/ModBaseT.hh @@ -4,10 +4,10 @@ * 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 * + * 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 * @@ -30,10 +30,10 @@ * License along with OpenMesh. If not, * * see . * * * -\*===========================================================================*/ +\*===========================================================================*/ /*===========================================================================*\ - * * + * * * $Revision$ * * $Date$ * * * @@ -88,11 +88,11 @@ public: public: /// Default constructor - ModHandleT() : mod_(NULL) {} + ModHandleT() : mod_(NULL) {} /// Destructor ~ModHandleT() { /* don't delete mod_, since handle is not owner! */ } - + /// Check handle status /// \return \c true, if handle is valid, else \c false. bool is_valid() const { return mod_ != NULL; } @@ -132,13 +132,13 @@ private: /** Convenience macro, to be used in derived modules - * The macro defines the types + * The macro defines the types * - \c Handle, type of the module's handle. * - \c Base, type of ModBaseT<>. * - \c Mesh, type of the associated mesh passed by the decimater type. * - \c CollapseInfo, to your convenience * and uses DECIMATER_MODNAME() to define the name of the module. - * + * * \param Classname The name of the derived class. * \param MeshT Pass here the mesh type, which is the * template parameter passed to ModBaseT. @@ -160,7 +160,7 @@ private: /** Base class for all decimation modules. Each module has to implement this interface. - To build your own module you have to + To build your own module you have to -# derive from this class. -# create the basic settings with DECIMATING_MODULE(). -# override collapse_priority(), if necessary. @@ -199,20 +199,20 @@ public: }; protected: - + /// Default constructor /// \see \ref decimater_docu ModBaseT(MeshT& _mesh, bool _is_binary) - : mesh_(_mesh), is_binary_(_is_binary) {} + : error_tolerance_factor_(1.0), mesh_(_mesh), is_binary_(_is_binary) {} public: /// Virtual desctructor - virtual ~ModBaseT() { } + virtual ~ModBaseT() { } /// Set module's name (using DECIMATER_MODNAME macro) DECIMATER_MODNAME(ModBase); - + /// Returns true if criteria returns a binary value. bool is_binary(void) const { return is_binary_; } @@ -222,11 +222,11 @@ public: public: // common interface - + /// Initialize module-internal stuff virtual void initialize() { } - /** Return collapse priority. + /** Return collapse priority. * * In the binary mode collapse_priority() checks a constraint and * returns LEGAL_COLLAPSE or ILLEGAL_COLLAPSE. @@ -237,7 +237,7 @@ public: // common interface * constraint is violated, collapse_priority() must return * ILLEGAL_COLLAPSE. * - * \return Collapse priority in the range [0,inf), + * \return Collapse priority in the range [0,inf), * \c LEGAL_COLLAPSE or \c ILLEGAL_COLLAPSE. */ virtual float collapse_priority(const CollapseInfoT& /* _ci */) @@ -250,11 +250,23 @@ public: // common interface {} /** After _from_vh has been collapsed into _to_vh, this method - will be called. + will be called. */ virtual void postprocess_collapse(const CollapseInfoT& /* _ci */) {} + /** + * This provides a function that allows the setting of a percentage + * of the original contraint. + * + * Note that the module might need to be re-initialized again after + * setting the percentage + * @param factor_ has to be in the closed interval between 0.0 and 1.0 + */ + virtual void set_error_tolerance_factor(double _factor) { + if (_factor >= 0.0 && _factor <= 1.0) + error_tolerance_factor_ = _factor; + } protected: @@ -262,6 +274,9 @@ protected: /// Access the mesh associated with the decimater. MeshT& mesh() { return mesh_; } + // current percentage of the original constraint + double error_tolerance_factor_; + private: // hide copy constructor & assignemnt diff --git a/src/OpenMesh/Tools/Decimater/ModEdgeLengthT.cc b/src/OpenMesh/Tools/Decimater/ModEdgeLengthT.cc index 7e7f8538..517bc2b7 100644 --- a/src/OpenMesh/Tools/Decimater/ModEdgeLengthT.cc +++ b/src/OpenMesh/Tools/Decimater/ModEdgeLengthT.cc @@ -76,6 +76,20 @@ float ModEdgeLengthT::collapse_priority(const CollapseInfo& _ci) { return ( (sqr_length <= sqr_edge_length_) ? sqr_length : float(Base::ILLEGAL_COLLAPSE)); } +//----------------------------------------------------------------------------- + +template +void ModEdgeLengthT::set_error_tolerance_factor(double _factor) { + if (_factor >= 0.0 && _factor <= 1.0) { + // the smaller the factor, the smaller edge_length_ gets + // thus creating a stricter constraint + // division by error_tolerance_factor_ is for normalization + float edge_length = edge_length_ * _factor / this->error_tolerance_factor_; + set_edge_length(edge_length); + this->error_tolerance_factor_ = _factor; + } +} + //============================================================================= } } diff --git a/src/OpenMesh/Tools/Decimater/ModEdgeLengthT.hh b/src/OpenMesh/Tools/Decimater/ModEdgeLengthT.hh index 4b3c7fdd..5db07ff0 100644 --- a/src/OpenMesh/Tools/Decimater/ModEdgeLengthT.hh +++ b/src/OpenMesh/Tools/Decimater/ModEdgeLengthT.hh @@ -99,6 +99,9 @@ class ModEdgeLengthT: public ModBaseT { */ float collapse_priority(const CollapseInfo& _ci); + /// set the percentage of edge length + void set_error_tolerance_factor(double _factor); + private: Mesh& mesh_; diff --git a/src/OpenMesh/Tools/Decimater/ModHausdorffT.cc b/src/OpenMesh/Tools/Decimater/ModHausdorffT.cc index d2b2c02a..88b63619 100644 --- a/src/OpenMesh/Tools/Decimater/ModHausdorffT.cc +++ b/src/OpenMesh/Tools/Decimater/ModHausdorffT.cc @@ -269,9 +269,21 @@ collapse_priority(const CollapseInfo& _ci) return ( ok ? Base::LEGAL_COLLAPSE : Base::ILLEGAL_COLLAPSE ); } - //----------------------------------------------------------------------------- +template +void ModHausdorffT::set_error_tolerance_factor(double _factor) { + if (_factor >= 0.0 && _factor <= 1.0) { + // the smaller the factor, the smaller tolerance gets + // thus creating a stricter constraint + // division by error_tolerance_factor_ is for normalization + Scalar tolerance = tolerance_ * _factor / this->error_tolerance_factor_; + set_tolerance(tolerance); + this->error_tolerance_factor_ = _factor; + } +} + +//----------------------------------------------------------------------------- template void @@ -380,8 +392,11 @@ compute_sqr_error(FaceHandle _fh, const Point& _p) const #pragma omp parallel for private(e) shared(emax) for (int i = 0; i < pointsCount; ++i) { e = distPointTriangleSquared(points[i], p0, p1, p2, dummy); +#pragma omp critical(emaxUpdate) + { if (e > emax) emax = e; + } } #else for (; p_it!=p_end; ++p_it) { diff --git a/src/OpenMesh/Tools/Decimater/ModHausdorffT.hh b/src/OpenMesh/Tools/Decimater/ModHausdorffT.hh index 24428637..926a4cd0 100644 --- a/src/OpenMesh/Tools/Decimater/ModHausdorffT.hh +++ b/src/OpenMesh/Tools/Decimater/ModHausdorffT.hh @@ -124,6 +124,9 @@ class ModHausdorffT: public ModBaseT { /// re-distribute points virtual void postprocess_collapse(const CollapseInfo& _ci); + /// set the percentage of tolerance + void set_error_tolerance_factor(double _factor); + private: /// squared distance from point _p to triangle (_v0, _v1, _v2) diff --git a/src/OpenMesh/Tools/Decimater/ModNormalDeviationT.hh b/src/OpenMesh/Tools/Decimater/ModNormalDeviationT.hh index 7532adc6..4eb80b74 100644 --- a/src/OpenMesh/Tools/Decimater/ModNormalDeviationT.hh +++ b/src/OpenMesh/Tools/Decimater/ModNormalDeviationT.hh @@ -87,7 +87,7 @@ template class ModNormalDeviationT : public ModBaseT< MeshT > { public: - + DECIMATING_MODULE( ModNormalDeviationT, MeshT, NormalDeviation ); typedef typename Mesh::Scalar Scalar; @@ -191,6 +191,18 @@ public: return (max_angle < 0.5 * normal_deviation_ ? max_angle : float( Base::ILLEGAL_COLLAPSE )); } + /// set the percentage of normal deviation + void set_error_tolerance_factor(double _factor) { + if (_factor >= 0.0 && _factor <= 1.0) { + // the smaller the factor, the smaller normal_deviation_ gets + // thus creating a stricter constraint + // division by error_tolerance_factor_ is for normalization + Scalar normal_deviation = (normal_deviation_ * 180.0/M_PI) * _factor / this->error_tolerance_factor_; + set_normal_deviation(normal_deviation); + this->error_tolerance_factor_ = _factor; + } + } + void postprocess_collapse(const CollapseInfo& _ci) { // account for changed normals diff --git a/src/OpenMesh/Tools/Decimater/ModNormalFlippingT.hh b/src/OpenMesh/Tools/Decimater/ModNormalFlippingT.hh index 5ec40c03..6393180f 100644 --- a/src/OpenMesh/Tools/Decimater/ModNormalFlippingT.hh +++ b/src/OpenMesh/Tools/Decimater/ModNormalFlippingT.hh @@ -4,10 +4,10 @@ * 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 * + * 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 * @@ -30,17 +30,17 @@ * License along with OpenMesh. If not, * * see . * * * -\*===========================================================================*/ +\*===========================================================================*/ /*===========================================================================*\ - * * + * * * $Revision$ * * $Date$ * * * \*===========================================================================*/ /** \file ModNormalFlippingT.hh - + */ //============================================================================= @@ -67,44 +67,44 @@ namespace Decimater { // BEGIN_NS_DECIMATER //== CLASS DEFINITION ========================================================= /** Decimating module to avoid flipping of faces. - * + * * This module can be used only as a binary module. The criterion * of allowing/disallowing the collapse is the angular deviation between * the face normal of the original faces and normals of the faces after the * collapse. The collapse will pass the test, if the deviation is below * a given threshold. - */ + */ template class ModNormalFlippingT : public ModBaseT< MeshT > -{ +{ public: DECIMATING_MODULE( ModNormalFlippingT, MeshT, NormalFlipping ); public: - + /// Constructor ModNormalFlippingT( MeshT &_mesh) : Base(_mesh, true) { set_max_normal_deviation( 90.0f ); } - - ~ModNormalFlippingT() + + ~ModNormalFlippingT() { } - + public: - + /** Compute collapse priority due to angular deviation of face normals * before and after a collapse. * * -# Compute for each adjacent face of \c _ci.v0 the face - * normal if the collpase would be executed. + * normal if the collpase would be executed. * * -# Prevent the collapse, if the cosine of the angle between the * original and the new normal is below a given threshold. - * + * * \param _ci The collapse description * \return LEGAL_COLLAPSE or ILLEGAL_COLLAPSE * @@ -114,13 +114,13 @@ public: { // simulate collapse Base::mesh().set_point(_ci.v0, _ci.p1); - + // check for flipping normals typename Mesh::ConstVertexFaceIter vf_it(Base::mesh(), _ci.v0); typename Mesh::FaceHandle fh; typename Mesh::Scalar c(1.0); - - for (; vf_it; ++vf_it) + + for (; vf_it; ++vf_it) { fh = vf_it.handle(); if (fh != _ci.fl && fh != _ci.fr) @@ -129,40 +129,51 @@ public: typename Mesh::Normal n2 = Base::mesh().calc_face_normal(fh); c = dot(n1, n2); - + if (c < min_cos_) break; } } - + // undo simulation changes Base::mesh().set_point(_ci.v0, _ci.p0); return float( (c < min_cos_) ? Base::ILLEGAL_COLLAPSE : Base::LEGAL_COLLAPSE ); } + /// set the percentage of maximum normal deviation + void set_error_tolerance_factor(double _factor) { + if (_factor >= 0.0 && _factor <= 1.0) { + // the smaller the factor, the smaller max_deviation_ gets + // thus creating a stricter constraint + // division by error_tolerance_factor_ is for normalization + float max_normal_deviation = (max_deviation_ * 180.0/M_PI) * _factor / this->error_tolerance_factor_; + set_max_normal_deviation(max_normal_deviation); + this->error_tolerance_factor_ = _factor; + } + } public: - + /// get normal deviation float max_normal_deviation() const { return max_deviation_ / M_PI * 180.0; } - + /** Set normal deviation - * + * * Set the maximum angular deviation of the orignal normal and the new * normal in degrees. */ - void set_max_normal_deviation(float _f) { - max_deviation_ = _f / 180.0 * M_PI; + void set_max_normal_deviation(float _f) { + max_deviation_ = _f / 180.0 * M_PI; min_cos_ = cos(max_deviation_); } - + private: // hide this method void set_binary(bool _b) {} - + private: // maximum normal deviation diff --git a/src/OpenMesh/Tools/Decimater/ModQuadricT.cc b/src/OpenMesh/Tools/Decimater/ModQuadricT.cc index e77c1e0b..faba097b 100644 --- a/src/OpenMesh/Tools/Decimater/ModQuadricT.cc +++ b/src/OpenMesh/Tools/Decimater/ModQuadricT.cc @@ -4,10 +4,10 @@ * 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 * + * 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 * @@ -30,10 +30,10 @@ * License along with OpenMesh. If not, * * see . * * * -\*===========================================================================*/ +\*===========================================================================*/ /*===========================================================================*\ - * * + * * * $Revision$ * * $Date$ * * * @@ -129,6 +129,23 @@ initialize() } } +//----------------------------------------------------------------------------- + +template +void ModQuadricT::set_error_tolerance_factor(double _factor) { + if (this->is_binary()) { + if (_factor >= 0.0 && _factor <= 1.0) { + // the smaller the factor, the smaller max_err_ gets + // thus creating a stricter constraint + // division by error_tolerance_factor_ is for normalization + double max_err = max_err_ * _factor / this->error_tolerance_factor_; + set_max_err(max_err); + this->error_tolerance_factor_ = _factor; + + initialize(); + } + } +} //============================================================================= } // END_NS_DECIMATER diff --git a/src/OpenMesh/Tools/Decimater/ModQuadricT.hh b/src/OpenMesh/Tools/Decimater/ModQuadricT.hh index 4a5fe008..82839913 100644 --- a/src/OpenMesh/Tools/Decimater/ModQuadricT.hh +++ b/src/OpenMesh/Tools/Decimater/ModQuadricT.hh @@ -4,10 +4,10 @@ * 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 * + * 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 * @@ -30,10 +30,10 @@ * License along with OpenMesh. If not, * * see . * * * -\*===========================================================================*/ +\*===========================================================================*/ /*===========================================================================*\ - * * + * * * $Revision$ * * $Date$ * * * @@ -138,6 +138,9 @@ public: // inherited Base::mesh().property(quadrics_, _ci.v0); } + /// set the percentage of maximum quadric error + void set_error_tolerance_factor(double _factor); + public: // specific methods diff --git a/src/OpenMesh/Tools/Decimater/ModRoundnessT.hh b/src/OpenMesh/Tools/Decimater/ModRoundnessT.hh index b1295816..f57d9779 100644 --- a/src/OpenMesh/Tools/Decimater/ModRoundnessT.hh +++ b/src/OpenMesh/Tools/Decimater/ModRoundnessT.hh @@ -4,10 +4,10 @@ * 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 * + * 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 * @@ -30,10 +30,10 @@ * License along with OpenMesh. If not, * * see . * * * -\*===========================================================================*/ +\*===========================================================================*/ /*===========================================================================*\ - * * + * * * $Revision$ * * $Date$ * * * @@ -96,7 +96,7 @@ class ModRoundnessT : public ModBaseT /// Constructor ModRoundnessT( MeshT &_dec ) : - Base(_dec, false), + Base(_dec, false), min_r_(-1.0) { } @@ -109,14 +109,14 @@ class ModRoundnessT : public ModBaseT * * The roundness is computed by dividing the radius of the * circumference by the length of the shortest edge. The result is - * normalized. + * normalized. * * \return [0:1] or ILLEGAL_COLLAPSE in non-binary mode * \return LEGAL_COLLAPSE or ILLEGAL_COLLAPSE in binary mode * \see set_min_roundness() */ - float collapse_priority(const CollapseInfo& _ci) - { + float collapse_priority(const CollapseInfo& _ci) + { // using namespace OpenMesh; typename Mesh::ConstVertexOHalfedgeIter voh_it(Base::mesh(), _ci.v0); @@ -126,11 +126,11 @@ class ModRoundnessT : public ModBaseT Vec3f B,C; if ( min_r_ < 0.0 ) // continues mode - { + { C = vector_cast(Base::mesh().point( Base::mesh().to_vertex_handle(voh_it))); fhC = Base::mesh().face_handle( voh_it.handle() ); - for (++voh_it; voh_it; ++voh_it) + for (++voh_it; voh_it; ++voh_it) { B = C; fhB = fhC; @@ -153,7 +153,7 @@ class ModRoundnessT : public ModBaseT C = vector_cast(Base::mesh().point( Base::mesh().to_vertex_handle(voh_it))); fhC = Base::mesh().face_handle( voh_it.handle() ); - for (++voh_it; voh_it && (priority==Base::LEGAL_COLLAPSE); ++voh_it) + for (++voh_it; voh_it && (priority==Base::LEGAL_COLLAPSE); ++voh_it) { B = C; fhB = fhC; @@ -171,6 +171,19 @@ class ModRoundnessT : public ModBaseT return (float) priority; } + /// set the percentage of minimum roundness + void set_error_tolerance_factor(double _factor) { + if (this->is_binary()) { + if (_factor >= 0.0 && _factor <= 1.0) { + // the smaller the factor, the smaller min_r_ gets + // thus creating a stricter constraint + // division by error_tolerance_factor_ is for normalization + value_type min_roundness = min_r_ * _factor / this->error_tolerance_factor_; + set_min_roundness(min_roundness); + this->error_tolerance_factor_ = _factor; + } +} + } public: // specific methods @@ -197,12 +210,12 @@ public: // specific methods double r2 = roundness(A,B,C); - set_min_roundness( value_type(std::min(r1,r2)), true ); + set_min_roundness( value_type(std::min(r1,r2)), true ); } /** Set a minimum roundness value. * \param _min_roundness in range (0,1) - * \param _binary Set true, if the binary mode should be enabled, + * \param _binary Set true, if the binary mode should be enabled, * else false. In latter case the collapse_priority() * returns a float value if the constraint does not apply * and ILLEGAL_COLLAPSE else. @@ -230,11 +243,11 @@ public: // specific methods // // then define // - // radius of circumference + // radius of circumference // R := ----------------------- // length of shortest edge // - // ||a|| * ||b|| * ||c|| + // ||a|| * ||b|| * ||c|| // --------------------- // 4 * Area ||a|| * ||b|| * ||c|| // = ----------------------- = ----------------------------------- @@ -254,7 +267,7 @@ public: // specific methods // // At angle 60� R has it's minimum for all edge lengths = sqrt(1/3) // - // Define normalized roundness + // Define normalized roundness // // nR := sqrt(1/3) / R // @@ -266,7 +279,7 @@ public: // specific methods { const value_type epsilon = value_type(1e-15); - static const value_type sqrt43 = value_type(sqrt(4.0/3.0)); // 60�,a=b=c, **) + static const value_type sqrt43 = value_type(sqrt(4.0/3.0)); // 60�,a=b=c, **) Vec3f vecAC = C-A; Vec3f vecAB = B-A; @@ -281,7 +294,7 @@ public: // specific methods return 0.0; double nom = AA * std::min( std::min(aa,bb),cc ); - double denom = aa * bb * cc; + double denom = aa * bb * cc; double nR = sqrt43 * sqrt(nom/denom); return nR;