2009-06-04 08:46:29 +00:00
|
|
|
/*===========================================================================*\
|
|
|
|
|
* *
|
|
|
|
|
* OpenMesh *
|
2015-01-05 15:34:10 +00:00
|
|
|
* Copyright (C) 2001-2015 by Computer Graphics Group, RWTH Aachen *
|
2009-06-04 08:46:29 +00:00
|
|
|
* www.openmesh.org *
|
|
|
|
|
* *
|
2012-09-19 16:15:39 +00:00
|
|
|
*---------------------------------------------------------------------------*
|
2009-06-04 08:46:29 +00:00
|
|
|
* This file is part of OpenMesh. *
|
|
|
|
|
* *
|
2012-09-19 16:15:39 +00:00
|
|
|
* OpenMesh is free software: you can redistribute it and/or modify *
|
2009-06-04 08:46:29 +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/>. *
|
|
|
|
|
* *
|
2011-11-16 09:45:08 +00:00
|
|
|
\*===========================================================================*/
|
2009-06-04 08:46:29 +00:00
|
|
|
|
|
|
|
|
/*===========================================================================*\
|
2012-09-19 16:15:39 +00:00
|
|
|
* *
|
2009-06-04 08:46:29 +00:00
|
|
|
* $Revision$ *
|
|
|
|
|
* $Date$ *
|
|
|
|
|
* *
|
2011-11-16 09:45:08 +00:00
|
|
|
\*===========================================================================*/
|
2009-02-06 13:37:46 +00:00
|
|
|
|
|
|
|
|
/** \file DecimaterT.cc
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
//=============================================================================
|
|
|
|
|
//
|
|
|
|
|
// CLASS DecimaterT - IMPLEMENTATION
|
|
|
|
|
//
|
|
|
|
|
//=============================================================================
|
|
|
|
|
#define OPENMESH_DECIMATER_DECIMATERT_CC
|
|
|
|
|
|
|
|
|
|
//== INCLUDES =================================================================
|
|
|
|
|
|
|
|
|
|
#include <OpenMesh/Tools/Decimater/DecimaterT.hh>
|
|
|
|
|
|
|
|
|
|
#include <vector>
|
|
|
|
|
#if defined(OM_CC_MIPS)
|
|
|
|
|
# include <float.h>
|
|
|
|
|
#else
|
|
|
|
|
# include <cfloat>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
//== NAMESPACE ===============================================================
|
|
|
|
|
|
2011-11-16 09:45:08 +00:00
|
|
|
namespace OpenMesh {
|
2009-02-06 13:37:46 +00:00
|
|
|
namespace Decimater {
|
|
|
|
|
|
|
|
|
|
//== IMPLEMENTATION ==========================================================
|
|
|
|
|
|
2011-11-16 09:45:08 +00:00
|
|
|
template<class Mesh>
|
|
|
|
|
DecimaterT<Mesh>::DecimaterT(Mesh& _mesh) :
|
2012-08-08 13:43:05 +00:00
|
|
|
BaseDecimaterT<Mesh>(_mesh),
|
|
|
|
|
mesh_(_mesh), heap_(NULL) {
|
2009-02-06 13:37:46 +00:00
|
|
|
|
|
|
|
|
// private vertex properties
|
2011-11-16 09:45:08 +00:00
|
|
|
mesh_.add_property(collapse_target_);
|
|
|
|
|
mesh_.add_property(priority_);
|
|
|
|
|
mesh_.add_property(heap_position_);
|
2009-02-06 13:37:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
2011-11-16 09:45:08 +00:00
|
|
|
template<class Mesh>
|
|
|
|
|
DecimaterT<Mesh>::~DecimaterT() {
|
2009-02-06 13:37:46 +00:00
|
|
|
|
|
|
|
|
// private vertex properties
|
|
|
|
|
mesh_.remove_property(collapse_target_);
|
|
|
|
|
mesh_.remove_property(priority_);
|
|
|
|
|
mesh_.remove_property(heap_position_);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
2011-11-16 09:45:08 +00:00
|
|
|
template<class Mesh>
|
|
|
|
|
void DecimaterT<Mesh>::heap_vertex(VertexHandle _vh) {
|
2009-02-06 13:37:46 +00:00
|
|
|
// std::clog << "heap_vertex: " << _vh << std::endl;
|
|
|
|
|
|
2011-11-16 09:45:08 +00:00
|
|
|
float prio, best_prio(FLT_MAX);
|
|
|
|
|
typename Mesh::HalfedgeHandle heh, collapse_target;
|
2009-02-06 13:37:46 +00:00
|
|
|
|
|
|
|
|
// find best target in one ring
|
|
|
|
|
typename Mesh::VertexOHalfedgeIter voh_it(mesh_, _vh);
|
2013-08-07 11:18:44 +00:00
|
|
|
for (; voh_it.is_valid(); ++voh_it) {
|
2013-08-07 09:40:10 +00:00
|
|
|
heh = *voh_it;
|
2011-11-16 09:45:08 +00:00
|
|
|
CollapseInfo ci(mesh_, heh);
|
2009-02-06 13:37:46 +00:00
|
|
|
|
2012-08-08 13:43:05 +00:00
|
|
|
if (this->is_collapse_legal(ci)) {
|
|
|
|
|
prio = this->collapse_priority(ci);
|
2011-11-16 09:45:08 +00:00
|
|
|
if (prio >= 0.0 && prio < best_prio) {
|
|
|
|
|
best_prio = prio;
|
|
|
|
|
collapse_target = heh;
|
2009-02-06 13:37:46 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// target found -> put vertex on heap
|
2011-11-16 09:45:08 +00:00
|
|
|
if (collapse_target.is_valid()) {
|
2009-02-06 13:37:46 +00:00
|
|
|
// std::clog << " added|updated" << std::endl;
|
|
|
|
|
mesh_.property(collapse_target_, _vh) = collapse_target;
|
2012-10-01 07:12:25 +00:00
|
|
|
mesh_.property(priority_, _vh) = best_prio;
|
2009-02-06 13:37:46 +00:00
|
|
|
|
2011-11-16 09:45:08 +00:00
|
|
|
if (heap_->is_stored(_vh))
|
|
|
|
|
heap_->update(_vh);
|
|
|
|
|
else
|
|
|
|
|
heap_->insert(_vh);
|
2009-02-06 13:37:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// not valid -> remove from heap
|
2011-11-16 09:45:08 +00:00
|
|
|
else {
|
2009-02-06 13:37:46 +00:00
|
|
|
// std::clog << " n/a|removed" << std::endl;
|
2011-11-16 09:45:08 +00:00
|
|
|
if (heap_->is_stored(_vh))
|
|
|
|
|
heap_->remove(_vh);
|
2009-02-06 13:37:46 +00:00
|
|
|
|
|
|
|
|
mesh_.property(collapse_target_, _vh) = collapse_target;
|
2011-11-16 09:45:08 +00:00
|
|
|
mesh_.property(priority_, _vh) = -1;
|
2009-02-06 13:37:46 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-04 12:59:37 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
2011-11-16 09:45:08 +00:00
|
|
|
template<class Mesh>
|
|
|
|
|
size_t DecimaterT<Mesh>::decimate(size_t _n_collapses) {
|
2012-10-01 07:12:25 +00:00
|
|
|
|
2012-08-08 13:43:05 +00:00
|
|
|
if (!this->is_initialized())
|
2009-02-06 13:37:46 +00:00
|
|
|
return 0;
|
|
|
|
|
|
2011-11-16 09:45:08 +00:00
|
|
|
typename Mesh::VertexIter v_it, v_end(mesh_.vertices_end());
|
|
|
|
|
typename Mesh::VertexHandle vp;
|
|
|
|
|
typename Mesh::HalfedgeHandle v0v1;
|
|
|
|
|
typename Mesh::VertexVertexIter vv_it;
|
|
|
|
|
typename Mesh::VertexFaceIter vf_it;
|
|
|
|
|
unsigned int n_collapses(0);
|
2009-02-06 13:37:46 +00:00
|
|
|
|
2011-11-16 09:45:08 +00:00
|
|
|
typedef std::vector<typename Mesh::VertexHandle> Support;
|
|
|
|
|
typedef typename Support::iterator SupportIterator;
|
2009-02-06 13:37:46 +00:00
|
|
|
|
2011-11-16 09:45:08 +00:00
|
|
|
Support support(15);
|
|
|
|
|
SupportIterator s_it, s_end;
|
2009-02-06 13:37:46 +00:00
|
|
|
|
|
|
|
|
// check _n_collapses
|
2011-11-16 09:45:08 +00:00
|
|
|
if (!_n_collapses)
|
|
|
|
|
_n_collapses = mesh_.n_vertices();
|
2009-02-06 13:37:46 +00:00
|
|
|
|
|
|
|
|
// initialize heap
|
2011-11-16 09:45:08 +00:00
|
|
|
HeapInterface HI(mesh_, priority_, heap_position_);
|
2009-02-06 13:37:46 +00:00
|
|
|
heap_ = std::auto_ptr<DeciHeap>(new DeciHeap(HI));
|
|
|
|
|
heap_->reserve(mesh_.n_vertices());
|
|
|
|
|
|
2011-11-16 09:45:08 +00:00
|
|
|
for (v_it = mesh_.vertices_begin(); v_it != v_end; ++v_it) {
|
2013-08-07 11:59:44 +00:00
|
|
|
heap_->reset_heap_position(*v_it);
|
2013-08-07 11:18:44 +00:00
|
|
|
if (!mesh_.status(*v_it).deleted())
|
|
|
|
|
heap_vertex(*v_it);
|
2009-02-06 13:37:46 +00:00
|
|
|
}
|
|
|
|
|
|
2014-05-09 08:12:17 +00:00
|
|
|
const bool update_normals = mesh_.has_face_normals();
|
|
|
|
|
|
2009-02-06 13:37:46 +00:00
|
|
|
// process heap
|
2011-11-16 09:45:08 +00:00
|
|
|
while ((!heap_->empty()) && (n_collapses < _n_collapses)) {
|
2009-02-06 13:37:46 +00:00
|
|
|
// get 1st heap entry
|
2011-11-16 09:45:08 +00:00
|
|
|
vp = heap_->front();
|
2009-02-06 13:37:46 +00:00
|
|
|
v0v1 = mesh_.property(collapse_target_, vp);
|
|
|
|
|
heap_->pop_front();
|
|
|
|
|
|
|
|
|
|
// setup collapse info
|
|
|
|
|
CollapseInfo ci(mesh_, v0v1);
|
|
|
|
|
|
|
|
|
|
// check topological correctness AGAIN !
|
2012-08-08 13:43:05 +00:00
|
|
|
if (!this->is_collapse_legal(ci))
|
2009-02-06 13:37:46 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// store support (= one ring of *vp)
|
|
|
|
|
vv_it = mesh_.vv_iter(ci.v0);
|
|
|
|
|
support.clear();
|
2013-08-07 11:18:44 +00:00
|
|
|
for (; vv_it.is_valid(); ++vv_it)
|
2013-08-07 09:40:10 +00:00
|
|
|
support.push_back(*vv_it);
|
2009-02-06 13:37:46 +00:00
|
|
|
|
|
|
|
|
// perform collapse
|
|
|
|
|
mesh_.collapse(v0v1);
|
|
|
|
|
++n_collapses;
|
|
|
|
|
|
2014-05-09 08:12:17 +00:00
|
|
|
if (update_normals)
|
|
|
|
|
{
|
|
|
|
|
// update triangle normals
|
|
|
|
|
vf_it = mesh_.vf_iter(ci.v1);
|
|
|
|
|
for (; vf_it.is_valid(); ++vf_it)
|
|
|
|
|
if (!mesh_.status(*vf_it).deleted())
|
|
|
|
|
mesh_.set_normal(*vf_it, mesh_.calc_face_normal(*vf_it));
|
|
|
|
|
}
|
2009-02-06 13:37:46 +00:00
|
|
|
|
|
|
|
|
// post-process collapse
|
2012-08-08 13:43:05 +00:00
|
|
|
this->postprocess_collapse(ci);
|
2009-02-06 13:37:46 +00:00
|
|
|
|
|
|
|
|
// update heap (former one ring of decimated vertex)
|
2011-11-16 09:45:08 +00:00
|
|
|
for (s_it = support.begin(), s_end = support.end(); s_it != s_end; ++s_it) {
|
2009-02-06 13:37:46 +00:00
|
|
|
assert(!mesh_.status(*s_it).deleted());
|
|
|
|
|
heap_vertex(*s_it);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// delete heap
|
|
|
|
|
heap_.reset();
|
|
|
|
|
|
2012-09-19 16:15:39 +00:00
|
|
|
|
2012-10-01 07:12:25 +00:00
|
|
|
|
2009-02-06 13:37:46 +00:00
|
|
|
// DON'T do garbage collection here! It's up to the application.
|
|
|
|
|
return n_collapses;
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-04 12:59:37 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
2011-11-16 09:45:08 +00:00
|
|
|
template<class Mesh>
|
|
|
|
|
size_t DecimaterT<Mesh>::decimate_to_faces(size_t _nv, size_t _nf) {
|
2012-10-01 07:12:25 +00:00
|
|
|
|
2012-08-08 13:43:05 +00:00
|
|
|
if (!this->is_initialized())
|
2011-11-04 12:59:37 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (_nv >= mesh_.n_vertices() || _nf >= mesh_.n_faces())
|
|
|
|
|
return 0;
|
|
|
|
|
|
2011-11-16 09:45:08 +00:00
|
|
|
typename Mesh::VertexIter v_it, v_end(mesh_.vertices_end());
|
|
|
|
|
typename Mesh::VertexHandle vp;
|
|
|
|
|
typename Mesh::HalfedgeHandle v0v1;
|
|
|
|
|
typename Mesh::VertexVertexIter vv_it;
|
|
|
|
|
typename Mesh::VertexFaceIter vf_it;
|
2013-07-23 16:01:46 +00:00
|
|
|
size_t nv = mesh_.n_vertices();
|
|
|
|
|
size_t nf = mesh_.n_faces();
|
2011-11-16 09:45:08 +00:00
|
|
|
unsigned int n_collapses = 0;
|
2011-11-04 12:59:37 +00:00
|
|
|
|
2011-11-16 09:45:08 +00:00
|
|
|
typedef std::vector<typename Mesh::VertexHandle> Support;
|
|
|
|
|
typedef typename Support::iterator SupportIterator;
|
2011-11-04 12:59:37 +00:00
|
|
|
|
2011-11-16 09:45:08 +00:00
|
|
|
Support support(15);
|
|
|
|
|
SupportIterator s_it, s_end;
|
2011-11-04 12:59:37 +00:00
|
|
|
|
|
|
|
|
// initialize heap
|
2011-11-16 09:45:08 +00:00
|
|
|
HeapInterface HI(mesh_, priority_, heap_position_);
|
2011-11-04 12:59:37 +00:00
|
|
|
heap_ = std::auto_ptr<DeciHeap>(new DeciHeap(HI));
|
|
|
|
|
heap_->reserve(mesh_.n_vertices());
|
|
|
|
|
|
2011-11-16 09:45:08 +00:00
|
|
|
for (v_it = mesh_.vertices_begin(); v_it != v_end; ++v_it) {
|
2013-08-07 11:59:44 +00:00
|
|
|
heap_->reset_heap_position(*v_it);
|
2013-08-07 12:44:52 +00:00
|
|
|
if (!mesh_.status(*v_it).deleted())
|
2013-08-07 11:59:44 +00:00
|
|
|
heap_vertex(*v_it);
|
2011-11-04 12:59:37 +00:00
|
|
|
}
|
|
|
|
|
|
2014-05-09 08:12:17 +00:00
|
|
|
const bool update_normals = mesh_.has_face_normals();
|
|
|
|
|
|
2011-11-04 12:59:37 +00:00
|
|
|
// process heap
|
2011-11-16 09:45:08 +00:00
|
|
|
while ((!heap_->empty()) && (_nv < nv) && (_nf < nf)) {
|
2011-11-04 12:59:37 +00:00
|
|
|
// get 1st heap entry
|
2011-11-16 09:45:08 +00:00
|
|
|
vp = heap_->front();
|
2011-11-04 12:59:37 +00:00
|
|
|
v0v1 = mesh_.property(collapse_target_, vp);
|
|
|
|
|
heap_->pop_front();
|
|
|
|
|
|
|
|
|
|
// setup collapse info
|
|
|
|
|
CollapseInfo ci(mesh_, v0v1);
|
|
|
|
|
|
|
|
|
|
// check topological correctness AGAIN !
|
2012-08-08 14:48:20 +00:00
|
|
|
if (!this->is_collapse_legal(ci))
|
2011-11-04 12:59:37 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// store support (= one ring of *vp)
|
|
|
|
|
vv_it = mesh_.vv_iter(ci.v0);
|
|
|
|
|
support.clear();
|
2013-08-07 12:44:52 +00:00
|
|
|
for (; vv_it.is_valid(); ++vv_it)
|
2013-08-07 09:40:10 +00:00
|
|
|
support.push_back(*vv_it);
|
2011-11-04 12:59:37 +00:00
|
|
|
|
|
|
|
|
// adjust complexity in advance (need boundary status)
|
|
|
|
|
++n_collapses;
|
|
|
|
|
--nv;
|
2011-11-16 09:45:08 +00:00
|
|
|
if (mesh_.is_boundary(ci.v0v1) || mesh_.is_boundary(ci.v1v0))
|
2011-11-04 12:59:37 +00:00
|
|
|
--nf;
|
2011-11-16 09:45:08 +00:00
|
|
|
else
|
|
|
|
|
nf -= 2;
|
2011-11-04 12:59:37 +00:00
|
|
|
|
|
|
|
|
// pre-processing
|
2012-08-08 14:48:20 +00:00
|
|
|
this->preprocess_collapse(ci);
|
2011-11-04 12:59:37 +00:00
|
|
|
|
|
|
|
|
// perform collapse
|
|
|
|
|
mesh_.collapse(v0v1);
|
|
|
|
|
|
|
|
|
|
// update triangle normals
|
2014-05-09 08:12:17 +00:00
|
|
|
if (update_normals)
|
|
|
|
|
{
|
|
|
|
|
vf_it = mesh_.vf_iter(ci.v1);
|
|
|
|
|
for (; vf_it.is_valid(); ++vf_it)
|
|
|
|
|
if (!mesh_.status(*vf_it).deleted())
|
|
|
|
|
mesh_.set_normal(*vf_it, mesh_.calc_face_normal(*vf_it));
|
|
|
|
|
}
|
2011-11-04 12:59:37 +00:00
|
|
|
|
|
|
|
|
// post-process collapse
|
2012-08-08 14:48:20 +00:00
|
|
|
this->postprocess_collapse(ci);
|
2011-11-04 12:59:37 +00:00
|
|
|
|
|
|
|
|
// update heap (former one ring of decimated vertex)
|
2011-11-16 09:45:08 +00:00
|
|
|
for (s_it = support.begin(), s_end = support.end(); s_it != s_end; ++s_it) {
|
2011-11-04 12:59:37 +00:00
|
|
|
assert(!mesh_.status(*s_it).deleted());
|
|
|
|
|
heap_vertex(*s_it);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// delete heap
|
|
|
|
|
heap_.reset();
|
|
|
|
|
|
2012-09-19 16:15:39 +00:00
|
|
|
|
2011-11-04 12:59:37 +00:00
|
|
|
// DON'T do garbage collection here! It's up to the application.
|
|
|
|
|
return n_collapses;
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-06 13:37:46 +00:00
|
|
|
//=============================================================================
|
2011-11-16 09:45:08 +00:00
|
|
|
}// END_NS_DECIMATER
|
2009-02-06 13:37:46 +00:00
|
|
|
} // END_NS_OPENMESH
|
|
|
|
|
//=============================================================================
|
|
|
|
|
|