add observer pattern to all decimaters
closes #2366 git-svn-id: http://www.openmesh.org/svnrepo/OpenMesh/trunk@1197 fdac6126-5c0c-442c-9429-916003d36597
This commit is contained in:
@@ -67,7 +67,7 @@ namespace Decimater {
|
|||||||
|
|
||||||
template<class Mesh>
|
template<class Mesh>
|
||||||
BaseDecimaterT<Mesh>::BaseDecimaterT(Mesh& _mesh) :
|
BaseDecimaterT<Mesh>::BaseDecimaterT(Mesh& _mesh) :
|
||||||
mesh_(_mesh), cmodule_(NULL), initialized_(false) {
|
mesh_(_mesh), cmodule_(NULL), initialized_(false), observer_(NULL) {
|
||||||
// default properties
|
// default properties
|
||||||
mesh_.request_vertex_status();
|
mesh_.request_vertex_status();
|
||||||
mesh_.request_edge_status();
|
mesh_.request_edge_status();
|
||||||
|
|||||||
@@ -71,6 +71,30 @@ namespace Decimater {
|
|||||||
//== CLASS DEFINITION =========================================================
|
//== CLASS DEFINITION =========================================================
|
||||||
|
|
||||||
|
|
||||||
|
class Observer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Observer(size_t _step) :
|
||||||
|
step_(_step) {
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~Observer() {
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t get_step() const { return step_; }
|
||||||
|
// give the notification step size
|
||||||
|
void set_step(size_t _step) { step_ = _step; }
|
||||||
|
|
||||||
|
//notifies about a finished decimater step with the given step number
|
||||||
|
virtual void notify(size_t _step) = 0;
|
||||||
|
//after notification, ask for abort or not, return true, if the decimater should abort
|
||||||
|
virtual bool abort() const = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t step_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/** base class decimater framework
|
/** base class decimater framework
|
||||||
\see BaseDecimaterT, \ref decimater_docu
|
\see BaseDecimaterT, \ref decimater_docu
|
||||||
*/
|
*/
|
||||||
@@ -113,6 +137,17 @@ public: //------------------------------------------------------ public methods
|
|||||||
|
|
||||||
public: //--------------------------------------------------- module management
|
public: //--------------------------------------------------- module management
|
||||||
|
|
||||||
|
// Observer interface
|
||||||
|
void set_observer(Observer* _o)
|
||||||
|
{
|
||||||
|
observer_ = _o;
|
||||||
|
}
|
||||||
|
|
||||||
|
Observer* observer()
|
||||||
|
{
|
||||||
|
return observer_;
|
||||||
|
}
|
||||||
|
|
||||||
/// access mesh. used in modules.
|
/// access mesh. used in modules.
|
||||||
Mesh& mesh() { return mesh_; }
|
Mesh& mesh() { return mesh_; }
|
||||||
|
|
||||||
@@ -166,6 +201,17 @@ public: //--------------------------------------------------- module management
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
//returns false, if abort requested by observer
|
||||||
|
bool notify_observer(size_t _n_collapses)
|
||||||
|
{
|
||||||
|
if (observer() && _n_collapses % observer()->get_step() == 0)
|
||||||
|
{
|
||||||
|
observer()->notify(_n_collapses);
|
||||||
|
return !observer()->abort();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Reset the initialized flag, and clear the bmodules_ and cmodule_
|
// Reset the initialized flag, and clear the bmodules_ and cmodule_
|
||||||
void set_uninitialized() {
|
void set_uninitialized() {
|
||||||
initialized_ = false;
|
initialized_ = false;
|
||||||
@@ -234,6 +280,8 @@ private: //------------------------------------------------------- private data
|
|||||||
// Flag if all modules were initialized
|
// Flag if all modules were initialized
|
||||||
bool initialized_;
|
bool initialized_;
|
||||||
|
|
||||||
|
// observer
|
||||||
|
Observer* observer_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -136,13 +136,13 @@ void DecimaterT<Mesh>::heap_vertex(VertexHandle _vh) {
|
|||||||
mesh_.property(priority_, _vh) = -1;
|
mesh_.property(priority_, _vh) = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
template<class Mesh>
|
template<class Mesh>
|
||||||
size_t DecimaterT<Mesh>::decimate(size_t _n_collapses) {
|
size_t DecimaterT<Mesh>::decimate(size_t _n_collapses) {
|
||||||
|
|
||||||
if (!this->is_initialized())
|
if (!this->is_initialized())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
typename Mesh::VertexIter v_it, v_end(mesh_.vertices_end());
|
typename Mesh::VertexIter v_it, v_end(mesh_.vertices_end());
|
||||||
typename Mesh::VertexHandle vp;
|
typename Mesh::VertexHandle vp;
|
||||||
@@ -212,12 +212,16 @@ size_t DecimaterT<Mesh>::decimate(size_t _n_collapses) {
|
|||||||
|
|
||||||
// update heap (former one ring of decimated vertex)
|
// update heap (former one ring of decimated vertex)
|
||||||
for (s_it = support.begin(), s_end = support.end(); s_it != s_end; ++s_it) {
|
for (s_it = support.begin(), s_end = support.end(); s_it != s_end; ++s_it) {
|
||||||
assert(!mesh_.status(*s_it).deleted());
|
assert(!mesh_.status(*s_it).deleted());
|
||||||
heap_vertex(*s_it);
|
heap_vertex(*s_it);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// notify observer and stop if the observer requests it
|
||||||
// delete heap
|
if (!this->notify_observer(n_collapses))
|
||||||
|
return n_collapses;
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete heap
|
||||||
heap_.reset();
|
heap_.reset();
|
||||||
|
|
||||||
|
|
||||||
@@ -226,13 +230,13 @@ size_t DecimaterT<Mesh>::decimate(size_t _n_collapses) {
|
|||||||
return n_collapses;
|
return n_collapses;
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
template<class Mesh>
|
template<class Mesh>
|
||||||
size_t DecimaterT<Mesh>::decimate_to_faces(size_t _nv, size_t _nf) {
|
size_t DecimaterT<Mesh>::decimate_to_faces(size_t _nv, size_t _nf) {
|
||||||
|
|
||||||
if (!this->is_initialized())
|
if (!this->is_initialized())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (_nv >= mesh_.n_vertices() || _nf >= mesh_.n_faces())
|
if (_nv >= mesh_.n_vertices() || _nf >= mesh_.n_faces())
|
||||||
return 0;
|
return 0;
|
||||||
@@ -313,12 +317,16 @@ size_t DecimaterT<Mesh>::decimate_to_faces(size_t _nv, size_t _nf) {
|
|||||||
|
|
||||||
// update heap (former one ring of decimated vertex)
|
// update heap (former one ring of decimated vertex)
|
||||||
for (s_it = support.begin(), s_end = support.end(); s_it != s_end; ++s_it) {
|
for (s_it = support.begin(), s_end = support.end(); s_it != s_end; ++s_it) {
|
||||||
assert(!mesh_.status(*s_it).deleted());
|
assert(!mesh_.status(*s_it).deleted());
|
||||||
heap_vertex(*s_it);
|
heap_vertex(*s_it);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// notify observer and stop if the observer requests it
|
||||||
// delete heap
|
if (!this->notify_observer(n_collapses))
|
||||||
|
return n_collapses;
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete heap
|
||||||
heap_.reset();
|
heap_.reset();
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -198,6 +198,10 @@ size_t McDecimaterT<Mesh>::decimate(size_t _n_collapses) {
|
|||||||
// post-process collapse
|
// post-process collapse
|
||||||
this->postprocess_collapse(ci);
|
this->postprocess_collapse(ci);
|
||||||
|
|
||||||
|
// notify observer and stop if the observer requests it
|
||||||
|
if (!this->notify_observer(n_collapses))
|
||||||
|
return n_collapses;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (oldCollapses == n_collapses) {
|
if (oldCollapses == n_collapses) {
|
||||||
if (collapsesUnchanged == false) {
|
if (collapsesUnchanged == false) {
|
||||||
@@ -337,6 +341,10 @@ size_t McDecimaterT<Mesh>::decimate_to_faces(size_t _nv, size_t _nf) {
|
|||||||
// post-process collapse
|
// post-process collapse
|
||||||
this->postprocess_collapse(ci);
|
this->postprocess_collapse(ci);
|
||||||
|
|
||||||
|
// notify observer and stop if the observer requests it
|
||||||
|
if (!this->notify_observer(n_collapses))
|
||||||
|
return n_collapses;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (oldCollapses == n_collapses) {
|
if (oldCollapses == n_collapses) {
|
||||||
if (collapsesUnchanged == false) {
|
if (collapsesUnchanged == false) {
|
||||||
@@ -491,6 +499,10 @@ size_t McDecimaterT<Mesh>::decimate_constraints_only(float _factor) {
|
|||||||
// post-process collapse
|
// post-process collapse
|
||||||
this->postprocess_collapse(ci);
|
this->postprocess_collapse(ci);
|
||||||
|
|
||||||
|
// notify observer and stop if the observer requests it
|
||||||
|
if (!this->notify_observer(n_collapses))
|
||||||
|
return n_collapses;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (oldCollapses == n_collapses) {
|
if (oldCollapses == n_collapses) {
|
||||||
if (collapsesUnchanged == false) {
|
if (collapsesUnchanged == false) {
|
||||||
|
|||||||
@@ -92,6 +92,11 @@ size_t MixedDecimaterT<Mesh>::decimate(const size_t _n_collapses, const float _m
|
|||||||
size_t r_collapses = 0;
|
size_t r_collapses = 0;
|
||||||
if (_mc_factor > 0.0)
|
if (_mc_factor > 0.0)
|
||||||
r_collapses = McDecimaterT<Mesh>::decimate(n_collapses_mc);
|
r_collapses = McDecimaterT<Mesh>::decimate(n_collapses_mc);
|
||||||
|
|
||||||
|
// returns, if the previous steps were aborted by the observer
|
||||||
|
if (this->observer() && this->observer()->abort())
|
||||||
|
return r_collapses;
|
||||||
|
|
||||||
if (_mc_factor < 1.0)
|
if (_mc_factor < 1.0)
|
||||||
r_collapses += DecimaterT<Mesh>::decimate(n_collapses_inc);
|
r_collapses += DecimaterT<Mesh>::decimate(n_collapses_inc);
|
||||||
|
|
||||||
@@ -147,6 +152,10 @@ size_t MixedDecimaterT<Mesh>::decimate_to_faces(const size_t _n_vertices,const
|
|||||||
//Update the mesh::n_vertices function, otherwise the next Decimater function will delete too much
|
//Update the mesh::n_vertices function, otherwise the next Decimater function will delete too much
|
||||||
this->mesh().garbage_collection();
|
this->mesh().garbage_collection();
|
||||||
|
|
||||||
|
// returns, if the previous steps were aborted by the observer
|
||||||
|
if (this->observer() && this->observer()->abort())
|
||||||
|
return r_collapses;
|
||||||
|
|
||||||
//reduce the rest of the mesh
|
//reduce the rest of the mesh
|
||||||
if (_mc_factor < 1.0) {
|
if (_mc_factor < 1.0) {
|
||||||
r_collapses += DecimaterT<Mesh>::decimate_to_faces(_n_vertices,_n_faces);
|
r_collapses += DecimaterT<Mesh>::decimate_to_faces(_n_vertices,_n_faces);
|
||||||
|
|||||||
@@ -129,5 +129,59 @@ TEST_F(OpenMeshDecimater, DecimateMeshExampleFromDoc) {
|
|||||||
EXPECT_EQ(9996u, mesh_.n_faces()) << "The number of faces after decimation is not correct!";
|
EXPECT_EQ(9996u, mesh_.n_faces()) << "The number of faces after decimation is not correct!";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class UnittestObserver : public OpenMesh::Decimater::Observer
|
||||||
|
{
|
||||||
|
size_t notifies_;
|
||||||
|
size_t all_steps_;
|
||||||
|
public:
|
||||||
|
UnittestObserver(size_t _steps) :Observer(_steps), notifies_(0), all_steps_(0) {}
|
||||||
|
|
||||||
|
void notify(size_t _step)
|
||||||
|
{
|
||||||
|
++notifies_;
|
||||||
|
all_steps_ = _step;
|
||||||
|
}
|
||||||
|
bool abort() const
|
||||||
|
{
|
||||||
|
return all_steps_ >= 2526u;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t countedNotifies()
|
||||||
|
{
|
||||||
|
return notifies_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(OpenMeshDecimater, DecimateMeshStoppedByObserver) {
|
||||||
|
|
||||||
|
bool ok = OpenMesh::IO::read_mesh(mesh_, "cube1.off");
|
||||||
|
|
||||||
|
ASSERT_TRUE(ok);
|
||||||
|
|
||||||
|
typedef OpenMesh::Decimater::DecimaterT< Mesh > Decimater;
|
||||||
|
typedef OpenMesh::Decimater::ModQuadricT< Mesh >::Handle HModQuadric;
|
||||||
|
|
||||||
|
Decimater decimaterDBG(mesh_);
|
||||||
|
HModQuadric hModQuadricDBG;
|
||||||
|
decimaterDBG.add(hModQuadricDBG);
|
||||||
|
|
||||||
|
decimaterDBG.module(hModQuadricDBG).unset_max_err();
|
||||||
|
|
||||||
|
decimaterDBG.initialize();
|
||||||
|
UnittestObserver obs(2);
|
||||||
|
decimaterDBG.set_observer(&obs);
|
||||||
|
size_t removedVertices = 0;
|
||||||
|
removedVertices = decimaterDBG.decimate_to_faces(0, 0);
|
||||||
|
decimaterDBG.mesh().garbage_collection();
|
||||||
|
|
||||||
|
EXPECT_TRUE(obs.abort()) << "Observer did not abort the decimater!";
|
||||||
|
EXPECT_EQ(obs.countedNotifies(), 2526u / 2u) << "Observer did not get the right amount of notifications!";
|
||||||
|
|
||||||
|
EXPECT_EQ(2526u, 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!";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,4 +106,58 @@ TEST_F(OpenMeshMultipleChoiceDecimater, DecimateMeshToFaceFaceLimit) {
|
|||||||
EXPECT_EQ(14994u, mesh_.n_edges()) << "The number of edges 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!";
|
EXPECT_EQ(9996u, mesh_.n_faces()) << "The number of faces after decimation is not correct!";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class UnittestObserver : public OpenMesh::Decimater::Observer
|
||||||
|
{
|
||||||
|
size_t notifies_;
|
||||||
|
size_t all_steps_;
|
||||||
|
public:
|
||||||
|
UnittestObserver(size_t _steps) :Observer(_steps), notifies_(0), all_steps_(0) {}
|
||||||
|
|
||||||
|
void notify(size_t _step)
|
||||||
|
{
|
||||||
|
++notifies_;
|
||||||
|
all_steps_ = _step;
|
||||||
|
}
|
||||||
|
bool abort() const
|
||||||
|
{
|
||||||
|
return all_steps_ >= 2526u;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t countedNotifies()
|
||||||
|
{
|
||||||
|
return notifies_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(OpenMeshMultipleChoiceDecimater, DecimateMeshStoppedByObserver) {
|
||||||
|
|
||||||
|
bool ok = OpenMesh::IO::read_mesh(mesh_, "cube1.off");
|
||||||
|
|
||||||
|
ASSERT_TRUE(ok);
|
||||||
|
|
||||||
|
typedef OpenMesh::Decimater::McDecimaterT< Mesh > Decimater;
|
||||||
|
typedef OpenMesh::Decimater::ModQuadricT< Mesh >::Handle HModQuadric;
|
||||||
|
|
||||||
|
Decimater decimaterDBG(mesh_);
|
||||||
|
HModQuadric hModQuadricDBG;
|
||||||
|
decimaterDBG.add(hModQuadricDBG);
|
||||||
|
|
||||||
|
decimaterDBG.module(hModQuadricDBG).unset_max_err();
|
||||||
|
|
||||||
|
decimaterDBG.initialize();
|
||||||
|
UnittestObserver obs(2);
|
||||||
|
decimaterDBG.set_observer(&obs);
|
||||||
|
size_t removedVertices = 0;
|
||||||
|
removedVertices = decimaterDBG.decimate_to_faces(0, 0);
|
||||||
|
decimaterDBG.mesh().garbage_collection();
|
||||||
|
|
||||||
|
EXPECT_TRUE(obs.abort()) << "Observer did not abort the decimater!";
|
||||||
|
EXPECT_EQ(obs.countedNotifies(), 2526u / 2u) << "Observer did not get the right amount of notifications!";
|
||||||
|
|
||||||
|
EXPECT_EQ(2526u, 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!";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,4 +106,58 @@ TEST_F(OpenMeshMixedDecimater, DecimateMeshToFaceFaceLimit) {
|
|||||||
EXPECT_EQ(14994u, mesh_.n_edges()) << "The number of edges 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!";
|
EXPECT_EQ(9996u, mesh_.n_faces()) << "The number of faces after decimation is not correct!";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class UnittestObserver : public OpenMesh::Decimater::Observer
|
||||||
|
{
|
||||||
|
size_t notifies_;
|
||||||
|
size_t all_steps_;
|
||||||
|
public:
|
||||||
|
UnittestObserver(size_t _steps) :Observer(_steps), notifies_(0), all_steps_(0) {}
|
||||||
|
|
||||||
|
void notify(size_t _step)
|
||||||
|
{
|
||||||
|
++notifies_;
|
||||||
|
all_steps_ = _step;
|
||||||
|
}
|
||||||
|
bool abort() const
|
||||||
|
{
|
||||||
|
return all_steps_ >= 2526u;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t countedNotifies()
|
||||||
|
{
|
||||||
|
return notifies_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(OpenMeshMixedDecimater, DecimateMeshStoppedByObserver) {
|
||||||
|
|
||||||
|
bool ok = OpenMesh::IO::read_mesh(mesh_, "cube1.off");
|
||||||
|
|
||||||
|
ASSERT_TRUE(ok);
|
||||||
|
|
||||||
|
typedef OpenMesh::Decimater::MixedDecimaterT< Mesh > Decimater;
|
||||||
|
typedef OpenMesh::Decimater::ModQuadricT< Mesh >::Handle HModQuadric;
|
||||||
|
|
||||||
|
Decimater decimaterDBG(mesh_);
|
||||||
|
HModQuadric hModQuadricDBG;
|
||||||
|
decimaterDBG.add(hModQuadricDBG);
|
||||||
|
|
||||||
|
decimaterDBG.module(hModQuadricDBG).unset_max_err();
|
||||||
|
|
||||||
|
decimaterDBG.initialize();
|
||||||
|
UnittestObserver obs(2);
|
||||||
|
decimaterDBG.set_observer(&obs);
|
||||||
|
size_t removedVertices = 0;
|
||||||
|
removedVertices = decimaterDBG.decimate_to_faces(0, 0);
|
||||||
|
decimaterDBG.mesh().garbage_collection();
|
||||||
|
|
||||||
|
EXPECT_TRUE(obs.abort()) << "Observer did not abort the decimater!";
|
||||||
|
EXPECT_EQ(obs.countedNotifies(), 2526u / 2u) << "Observer did not get the right amount of notifications!";
|
||||||
|
|
||||||
|
EXPECT_EQ(2526u, 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!";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user