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:
Matthias Möller
2015-01-15 10:19:39 +00:00
parent 094a7f540f
commit b9fd3edef9
8 changed files with 266 additions and 27 deletions

View File

@@ -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();

View File

@@ -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_;
}; };

View File

@@ -215,6 +215,10 @@ size_t DecimaterT<Mesh>::decimate(size_t _n_collapses) {
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
if (!this->notify_observer(n_collapses))
return n_collapses;
} }
// delete heap // delete heap
@@ -316,6 +320,10 @@ size_t DecimaterT<Mesh>::decimate_to_faces(size_t _nv, size_t _nf) {
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
if (!this->notify_observer(n_collapses))
return n_collapses;
} }
// delete heap // delete heap

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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!";
}
} }

View File

@@ -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!";
}
} }

View File

@@ -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!";
}
} }