2012-08-06 16:10:52 +00:00
|
|
|
/*===========================================================================*\
|
|
|
|
|
* *
|
|
|
|
|
* OpenMesh *
|
|
|
|
|
* Copyright (C) 2001-2011 by Computer Graphics Group, RWTH Aachen *
|
|
|
|
|
* www.openmesh.org *
|
|
|
|
|
* *
|
2012-09-18 10:28:26 +00:00
|
|
|
*---------------------------------------------------------------------------*
|
2012-08-06 16:10:52 +00:00
|
|
|
* This file is part of OpenMesh. *
|
|
|
|
|
* *
|
2012-09-18 10:28:26 +00:00
|
|
|
* OpenMesh is free software: you can redistribute it and/or modify *
|
2012-08-06 16:10:52 +00:00
|
|
|
* 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 <http://www.gnu.org/licenses/>. *
|
|
|
|
|
* *
|
|
|
|
|
\*===========================================================================*/
|
|
|
|
|
|
|
|
|
|
/*===========================================================================*\
|
2012-09-18 10:28:26 +00:00
|
|
|
* *
|
2012-08-06 16:10:52 +00:00
|
|
|
* $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 <OpenMesh/Tools/Decimater/McDecimaterT.hh>
|
|
|
|
|
|
|
|
|
|
#include <vector>
|
|
|
|
|
#if defined(OM_CC_MIPS)
|
|
|
|
|
# include <float.h>
|
|
|
|
|
#else
|
|
|
|
|
# include <cfloat>
|
|
|
|
|
#endif
|
2012-09-19 16:15:39 +00:00
|
|
|
#ifdef USE_OPENMP
|
|
|
|
|
#include <omp.h>
|
|
|
|
|
#endif
|
2012-08-06 16:10:52 +00:00
|
|
|
|
|
|
|
|
//== NAMESPACE ===============================================================
|
|
|
|
|
|
|
|
|
|
namespace OpenMesh {
|
|
|
|
|
namespace Decimater {
|
|
|
|
|
|
|
|
|
|
//== IMPLEMENTATION ==========================================================
|
|
|
|
|
|
|
|
|
|
template<class Mesh>
|
|
|
|
|
McDecimaterT<Mesh>::McDecimaterT(Mesh& _mesh) :
|
2012-08-08 13:43:05 +00:00
|
|
|
BaseDecimaterT<Mesh>(_mesh),
|
|
|
|
|
mesh_(_mesh), randomSamples_(10) {
|
2012-08-06 16:10:52 +00:00
|
|
|
|
|
|
|
|
// default properties
|
|
|
|
|
mesh_.request_vertex_status();
|
|
|
|
|
mesh_.request_halfedge_status();
|
|
|
|
|
mesh_.request_edge_status();
|
|
|
|
|
mesh_.request_face_status();
|
|
|
|
|
mesh_.request_face_normals();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
template<class Mesh>
|
|
|
|
|
McDecimaterT<Mesh>::~McDecimaterT() {
|
|
|
|
|
// default properties
|
|
|
|
|
mesh_.release_vertex_status();
|
|
|
|
|
mesh_.release_edge_status();
|
|
|
|
|
mesh_.release_halfedge_status();
|
|
|
|
|
mesh_.release_face_status();
|
|
|
|
|
mesh_.release_face_normals();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
template<class Mesh>
|
|
|
|
|
size_t McDecimaterT<Mesh>::decimate(size_t _n_collapses) {
|
|
|
|
|
|
2012-08-08 13:43:05 +00:00
|
|
|
if (!this->is_initialized())
|
2012-08-06 16:10:52 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
unsigned int n_collapses(0);
|
|
|
|
|
|
2012-09-19 16:15:39 +00:00
|
|
|
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;
|
|
|
|
|
|
2012-08-06 16:10:52 +00:00
|
|
|
while ( n_collapses < _n_collapses) {
|
2012-09-23 12:00:46 +00:00
|
|
|
|
2012-09-19 16:15:39 +00:00
|
|
|
if (noCollapses > 20) {
|
|
|
|
|
omlog() << "[McDecimater] : no collapses performed in over 20 iterations in a row\n";
|
|
|
|
|
break;
|
|
|
|
|
}
|
2012-08-06 16:10:52 +00:00
|
|
|
|
|
|
|
|
// Optimal id and value will be collected during the random sampling
|
|
|
|
|
typename Mesh::HalfedgeHandle bestHandle(-1);
|
2012-09-19 16:15:39 +00:00
|
|
|
typename Mesh::HalfedgeHandle tmpHandle(-1);
|
2012-08-06 16:10:52 +00:00
|
|
|
double bestEnergy = FLT_MAX;
|
2012-09-19 16:15:39 +00:00
|
|
|
double energy = FLT_MAX;
|
2012-08-06 16:10:52 +00:00
|
|
|
|
|
|
|
|
// Generate random samples for collapses
|
2012-09-23 12:00:46 +00:00
|
|
|
#ifdef USE_OPENMP
|
|
|
|
|
#pragma omp parallel for private(energy,tmpHandle) shared(bestEnergy,bestHandle)
|
|
|
|
|
#endif
|
2012-09-18 13:19:37 +00:00
|
|
|
for ( int i = 0; i < (int)randomSamples_; ++i) {
|
2012-08-06 16:10:52 +00:00
|
|
|
|
|
|
|
|
// Random halfedge handle
|
2012-09-19 16:15:39 +00:00
|
|
|
tmpHandle = typename Mesh::HalfedgeHandle((static_cast<double>(rand()) / RAND_MAX) * (mesh_.n_halfedges()-1) );
|
2012-08-06 16:10:52 +00:00
|
|
|
|
|
|
|
|
// 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
|
2012-08-08 13:43:05 +00:00
|
|
|
if (this->is_collapse_legal(ci)) {
|
2012-09-23 12:00:46 +00:00
|
|
|
#ifdef USE_OPENMP
|
|
|
|
|
#pragma omp critical(energyUpdate)
|
2012-09-19 16:15:39 +00:00
|
|
|
{
|
2012-09-23 12:00:46 +00:00
|
|
|
#endif
|
|
|
|
|
energy = this->collapse_priority(ci);
|
|
|
|
|
|
|
|
|
|
if (energy != ModBaseT<Mesh>::ILLEGAL_COLLAPSE) {
|
|
|
|
|
// Check if the current samples energy is better than any energy before
|
|
|
|
|
if ( energy < bestEnergy ) {
|
|
|
|
|
bestEnergy = energy;
|
|
|
|
|
bestHandle = tmpHandle;
|
|
|
|
|
}
|
2012-09-19 16:15:39 +00:00
|
|
|
}
|
2012-09-23 12:00:46 +00:00
|
|
|
#ifdef USE_OPENMP
|
2012-08-06 16:10:52 +00:00
|
|
|
}
|
2012-09-23 12:00:46 +00:00
|
|
|
#endif
|
2012-08-06 16:10:52 +00:00
|
|
|
} else {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Found the best energy?
|
|
|
|
|
if ( bestEnergy != FLT_MAX ) {
|
|
|
|
|
|
|
|
|
|
// setup collapse info
|
|
|
|
|
CollapseInfo ci(mesh_, bestHandle);
|
|
|
|
|
|
|
|
|
|
// check topological correctness AGAIN !
|
2012-08-08 13:43:05 +00:00
|
|
|
if (!this->is_collapse_legal(ci))
|
2012-08-06 16:10:52 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// pre-processing
|
2012-08-08 13:43:05 +00:00
|
|
|
this->preprocess_collapse(ci);
|
2012-08-06 16:10:52 +00:00
|
|
|
|
|
|
|
|
// perform collapse
|
|
|
|
|
mesh_.collapse(bestHandle);
|
|
|
|
|
++n_collapses;
|
|
|
|
|
|
2012-09-19 16:15:39 +00:00
|
|
|
// store current collapses state
|
|
|
|
|
oldCollapses = n_collapses;
|
|
|
|
|
noCollapses = 0;
|
|
|
|
|
collapsesUnchanged = false;
|
|
|
|
|
|
2012-08-06 16:10:52 +00:00
|
|
|
// 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
|
2012-08-08 13:43:05 +00:00
|
|
|
this->postprocess_collapse(ci);
|
2012-08-06 16:10:52 +00:00
|
|
|
|
2012-09-19 16:15:39 +00:00
|
|
|
} else {
|
|
|
|
|
if (oldCollapses == n_collapses) {
|
|
|
|
|
if (collapsesUnchanged == false) {
|
|
|
|
|
noCollapses = 1;
|
|
|
|
|
collapsesUnchanged = true;
|
|
|
|
|
} else {
|
|
|
|
|
noCollapses++;
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-08-06 16:10:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DON'T do garbage collection here! It's up to the application.
|
|
|
|
|
return n_collapses;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
template<class Mesh>
|
|
|
|
|
size_t McDecimaterT<Mesh>::decimate_to_faces(size_t _nv, size_t _nf) {
|
2012-08-08 13:43:05 +00:00
|
|
|
if (!this->is_initialized())
|
2012-08-06 16:10:52 +00:00
|
|
|
return 0;
|
|
|
|
|
|
2012-09-19 16:15:39 +00:00
|
|
|
// check if no vertex or face contraints were set
|
|
|
|
|
if ( (_nv == 0) && (_nf == 1) )
|
|
|
|
|
return decimate_constraints_only(1.0);
|
|
|
|
|
|
2012-08-06 16:10:52 +00:00
|
|
|
unsigned int nv = mesh_.n_vertices();
|
|
|
|
|
unsigned int nf = mesh_.n_faces();
|
|
|
|
|
unsigned int n_collapses(0);
|
|
|
|
|
|
2012-09-18 10:28:26 +00:00
|
|
|
|
2012-09-19 16:15:39 +00:00
|
|
|
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;
|
2012-09-18 10:28:26 +00:00
|
|
|
|
2012-09-23 12:00:46 +00:00
|
|
|
while ((_nv < nv) && (_nf < nf)) {
|
2012-09-19 16:15:39 +00:00
|
|
|
if (noCollapses > 20) {
|
|
|
|
|
omlog() << "[McDecimater] : no collapses performed in over 20 iterations in a row\n";
|
|
|
|
|
break;
|
|
|
|
|
}
|
2012-08-06 16:10:52 +00:00
|
|
|
|
|
|
|
|
// Optimal id and value will be collected during the random sampling
|
|
|
|
|
typename Mesh::HalfedgeHandle bestHandle(-1);
|
2012-09-19 16:15:39 +00:00
|
|
|
typename Mesh::HalfedgeHandle tmpHandle(-1);
|
2012-08-06 16:10:52 +00:00
|
|
|
double bestEnergy = FLT_MAX;
|
2012-09-19 16:15:39 +00:00
|
|
|
double energy = FLT_MAX;
|
|
|
|
|
|
2012-08-06 16:10:52 +00:00
|
|
|
// Generate random samples for collapses
|
2012-09-23 12:00:46 +00:00
|
|
|
#ifdef USE_OPENMP
|
|
|
|
|
#pragma omp parallel for private(energy,tmpHandle) shared(bestEnergy,bestHandle)
|
|
|
|
|
#endif
|
|
|
|
|
for (int i = 0; i < (int) randomSamples_; ++i) {
|
2012-08-06 16:10:52 +00:00
|
|
|
|
|
|
|
|
// Random halfedge handle
|
2012-09-23 12:00:46 +00:00
|
|
|
tmpHandle = typename Mesh::HalfedgeHandle((static_cast<double>(rand()) / RAND_MAX) * (mesh_.n_halfedges() - 1));
|
2012-08-06 16:10:52 +00:00
|
|
|
|
|
|
|
|
// if it is not deleted, we analyse it
|
2012-09-23 12:00:46 +00:00
|
|
|
if (!mesh_.status(tmpHandle).deleted()) {
|
2012-08-06 16:10:52 +00:00
|
|
|
|
|
|
|
|
CollapseInfo ci(mesh_, tmpHandle);
|
|
|
|
|
|
|
|
|
|
// Check if legal we analyze the priority of this collapse operation
|
2012-08-08 16:10:57 +00:00
|
|
|
if (this->is_collapse_legal(ci)) {
|
2012-09-23 12:00:46 +00:00
|
|
|
#ifdef USE_OPENMP
|
|
|
|
|
#pragma omp critical(energyUpdate)
|
2012-09-19 16:15:39 +00:00
|
|
|
{
|
2012-09-23 12:00:46 +00:00
|
|
|
#endif
|
|
|
|
|
energy = this->collapse_priority(ci);
|
|
|
|
|
|
|
|
|
|
if (energy != ModBaseT<Mesh>::ILLEGAL_COLLAPSE) {
|
|
|
|
|
// Check if the current samples energy is better than any energy before
|
|
|
|
|
if (energy < bestEnergy) {
|
|
|
|
|
bestEnergy = energy;
|
|
|
|
|
bestHandle = tmpHandle;
|
|
|
|
|
}
|
2012-09-19 16:15:39 +00:00
|
|
|
}
|
2012-09-23 12:00:46 +00:00
|
|
|
#ifdef USE_OPENMP
|
2012-08-06 16:10:52 +00:00
|
|
|
}
|
2012-09-23 12:00:46 +00:00
|
|
|
#endif
|
2012-08-06 16:10:52 +00:00
|
|
|
} else {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-19 16:15:39 +00:00
|
|
|
// 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++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DON'T do garbage collection here! It's up to the application.
|
|
|
|
|
return n_collapses;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
template<class Mesh>
|
|
|
|
|
size_t McDecimaterT<Mesh>::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;
|
|
|
|
|
|
|
|
|
|
|
2012-09-23 12:00:46 +00:00
|
|
|
while ((noCollapses <= 20) && (illegalCollapses <= 10) && (nv > 0) && (nf > 1)) {
|
2012-09-19 16:15:39 +00:00
|
|
|
|
|
|
|
|
// 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
|
2012-09-23 12:00:46 +00:00
|
|
|
#ifdef USE_OPENMP
|
|
|
|
|
#pragma omp parallel for private(energy,tmpHandle) shared(bestEnergy,bestHandle)
|
|
|
|
|
#endif
|
|
|
|
|
for (int i = 0; i < (int) randomSamples_; ++i) {
|
2012-09-19 16:15:39 +00:00
|
|
|
|
|
|
|
|
// Random halfedge handle
|
2012-09-23 12:00:46 +00:00
|
|
|
tmpHandle = typename Mesh::HalfedgeHandle((static_cast<double>(rand()) / RAND_MAX) * (mesh_.n_halfedges() - 1));
|
2012-09-19 16:15:39 +00:00
|
|
|
|
|
|
|
|
// if it is not deleted, we analyse it
|
2012-09-23 12:00:46 +00:00
|
|
|
if (!mesh_.status(tmpHandle).deleted()) {
|
2012-09-19 16:15:39 +00:00
|
|
|
|
|
|
|
|
CollapseInfo ci(mesh_, tmpHandle);
|
|
|
|
|
|
|
|
|
|
// Check if legal we analyze the priority of this collapse operation
|
|
|
|
|
if (this->is_collapse_legal(ci)) {
|
2012-09-23 12:00:46 +00:00
|
|
|
#ifdef USE_OPENMP
|
|
|
|
|
#pragma omp critical(energyUpdate)
|
2012-09-19 16:15:39 +00:00
|
|
|
{
|
2012-09-23 12:00:46 +00:00
|
|
|
#endif
|
2012-09-19 16:15:39 +00:00
|
|
|
|
2012-09-23 12:00:46 +00:00
|
|
|
energy = this->collapse_priority(ci);
|
2012-09-19 16:15:39 +00:00
|
|
|
|
2012-09-23 12:00:46 +00:00
|
|
|
if (energy == ModBaseT<Mesh>::ILLEGAL_COLLAPSE) {
|
|
|
|
|
if (lastCollapseIllegal) {
|
|
|
|
|
illegalCollapses++;
|
|
|
|
|
} else {
|
|
|
|
|
illegalCollapses = 1;
|
|
|
|
|
lastCollapseIllegal = true;
|
|
|
|
|
}
|
2012-09-19 16:15:39 +00:00
|
|
|
} else {
|
2012-09-23 12:00:46 +00:00
|
|
|
illegalCollapses = 0;
|
|
|
|
|
lastCollapseIllegal = false;
|
|
|
|
|
|
|
|
|
|
// Check if the current samples energy is better than any energy before
|
|
|
|
|
if (energy < bestEnergy) {
|
|
|
|
|
bestEnergy = energy;
|
|
|
|
|
bestHandle = tmpHandle;
|
|
|
|
|
}
|
2012-09-19 16:15:39 +00:00
|
|
|
}
|
2012-09-23 12:00:46 +00:00
|
|
|
#ifdef USE_OPENMP
|
2012-09-19 16:15:39 +00:00
|
|
|
}
|
2012-09-23 12:00:46 +00:00
|
|
|
#endif
|
2012-09-19 16:15:39 +00:00
|
|
|
} else {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-09-18 10:28:26 +00:00
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-06 16:10:52 +00:00
|
|
|
// Found the best energy?
|
|
|
|
|
if ( bestEnergy != FLT_MAX ) {
|
|
|
|
|
|
|
|
|
|
// setup collapse info
|
|
|
|
|
CollapseInfo ci(mesh_, bestHandle);
|
|
|
|
|
|
|
|
|
|
// check topological correctness AGAIN !
|
2012-08-08 16:10:57 +00:00
|
|
|
if (!this->is_collapse_legal(ci))
|
2012-08-06 16:10:52 +00:00
|
|
|
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
|
2012-08-08 16:10:57 +00:00
|
|
|
this->preprocess_collapse(ci);
|
2012-08-06 16:10:52 +00:00
|
|
|
|
|
|
|
|
// perform collapse
|
|
|
|
|
mesh_.collapse(bestHandle);
|
|
|
|
|
++n_collapses;
|
|
|
|
|
|
2012-09-19 16:15:39 +00:00
|
|
|
// store current collapses state
|
|
|
|
|
oldCollapses = n_collapses;
|
|
|
|
|
noCollapses = 0;
|
|
|
|
|
collapsesUnchanged = false;
|
|
|
|
|
|
|
|
|
|
|
2012-08-06 16:10:52 +00:00
|
|
|
// 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
|
2012-08-08 16:10:57 +00:00
|
|
|
this->postprocess_collapse(ci);
|
2012-08-06 16:10:52 +00:00
|
|
|
|
2012-09-19 16:15:39 +00:00
|
|
|
} else {
|
|
|
|
|
if (oldCollapses == n_collapses) {
|
|
|
|
|
if (collapsesUnchanged == false) {
|
|
|
|
|
noCollapses = 1;
|
|
|
|
|
collapsesUnchanged = true;
|
|
|
|
|
} else {
|
|
|
|
|
noCollapses++;
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-08-06 16:10:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-19 16:15:39 +00:00
|
|
|
if (_factor < 1.0)
|
|
|
|
|
this->set_error_tolerance_factor(1.0);
|
|
|
|
|
|
2012-08-06 16:10:52 +00:00
|
|
|
// DON'T do garbage collection here! It's up to the application.
|
|
|
|
|
return n_collapses;
|
2012-09-19 16:15:39 +00:00
|
|
|
|
2012-08-06 16:10:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//=============================================================================
|
|
|
|
|
}// END_NS_MC_DECIMATER
|
|
|
|
|
} // END_NS_OPENMESH
|
|
|
|
|
//=============================================================================
|
|
|
|
|
|