* mln/topo/is_simple_pair.hh,
* mln/topo/detach_pair.hh:
New.
* tests/topo/is_simple_pair.cc,
* tests/topo/detach_pair.cc:
New tests.
* tests/topo/Makefile.am (check_PROGRAMS): Add is_simple_pair and
detach_pair.
(detach_pair_SOURCES, is_simple_pair_SOURCES): New.
(MOSTLYCLEANFILES): New. Add detach_pair-out.vtk.
---
milena/ChangeLog | 15 ++
milena/mln/topo/detach_pair.hh | 191 +++++++++++++++++
milena/mln/topo/is_simple_pair.hh | 225 ++++++++++++++++++++
milena/tests/topo/Makefile.am | 8 +-
.../{io/vtk/load_bin.cc => topo/detach_pair.cc} | 55 +++--
.../{io/vtk/load_bin.cc => topo/is_simple_pair.cc} | 43 +++--
6 files changed, 500 insertions(+), 37 deletions(-)
create mode 100644 milena/mln/topo/detach_pair.hh
create mode 100644 milena/mln/topo/is_simple_pair.hh
copy milena/tests/{io/vtk/load_bin.cc => topo/detach_pair.cc} (51%)
copy milena/tests/{io/vtk/load_bin.cc => topo/is_simple_pair.cc} (53%)
diff --git a/milena/ChangeLog b/milena/ChangeLog
index b1b2d74..214ccdc 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,3 +1,18 @@
+2011-03-14 Roland Levillain <roland(a)lrde.epita.fr>
+
+ Add routines to identify and detach (collapse) simple pairs.
+
+ * mln/topo/is_simple_pair.hh,
+ * mln/topo/detach_pair.hh:
+ New.
+ * tests/topo/is_simple_pair.cc,
+ * tests/topo/detach_pair.cc:
+ New tests.
+ * tests/topo/Makefile.am (check_PROGRAMS): Add is_simple_pair and
+ detach_pair.
+ (detach_pair_SOURCES, is_simple_pair_SOURCES): New.
+ (MOSTLYCLEANFILES): New. Add detach_pair-out.vtk.
+
2011-03-01 Roland Levillain <roland(a)lrde.epita.fr>
Add preliminary VTK input for binary images.
diff --git a/milena/mln/topo/detach_pair.hh b/milena/mln/topo/detach_pair.hh
new file mode 100644
index 0000000..a40bd5c
--- /dev/null
+++ b/milena/mln/topo/detach_pair.hh
@@ -0,0 +1,191 @@
+// Copyright (C) 2011 EPITA Research and Development Laboratory (LRDE)
+//
+// This file is part of Olena.
+//
+// Olena is free software: you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation, version 2 of the License.
+//
+// Olena 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
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Olena. If not, see <http://www.gnu.org/licenses/>.
+//
+// As a special exception, you may use this file as part of a free
+// software project without restriction. Specifically, 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 General Public License. This
+// exception does not however invalidate any other reasons why the
+// executable file might be covered by the GNU General Public License.
+
+#ifndef MLN_TOPO_DETACH_PAIR_HH
+# define MLN_TOPO_DETACH_PAIR_HH
+
+/// \file
+/// \brief Detaching a simple pair from a binary (probably
+/// complex-based) image (elementary collapse operation).
+
+# include <mln/core/concept/function.hh>
+# include <mln/core/concept/image.hh>
+# include <mln/core/concept/neighborhood.hh>
+
+# include <mln/topo/is_simple_pair.hh>
+
+
+namespace mln
+{
+
+ namespace topo
+ {
+
+ /** \ brief A functor detaching a simple pair from a binary
+ (probably complex-based) image (elementary collapse
+ operation).
+
+ \tparam I The type of the image.
+ \tparam NL The neighborhood type returning the set of
+ (n-1)-faces adjacent to a an n-face.
+ \tparam NH The neighborhood type returning the set of
+ (n+1)-faces adjacent to a an n-face. */
+ template <typename I, typename NL, typename NH>
+ class detach_pair
+ {
+ public:
+ /// Constructors.
+ /// \{
+ /** Construct an mln::topo::detach_pair from a couple of
+ neighborhoods.
+
+ \param lower_adj_nbh An adjacency relationship between faces
+ returning the set of (n-1)-faces
+ adjacent to a given n-face.
+ \param higher_adj_nbh An adjacency relationship between faces
+ returning the set of (n+1)-faces
+ adjacent to a given n-face. */
+ detach_pair(const Neighborhood<NL>& lower_adj_nbh,
+ const Neighborhood<NH>& higher_adj_nbh);
+
+ /** Construct an mln::topo::detach_pair from an image and a
+ couple of neighborhoods.
+
+ \pre \a ima is an image of Boolean values.
+
+ \param ima The input image from which the pair is
+ to be detached.
+ \param lower_adj_nbh An adjacency relationship between faces
+ returning the set of (n-1)-faces
+ adjacent to a given n-face.
+ \param higher_adj_nbh An adjacency relationship between faces
+ returning the set of (n+1)-faces
+ adjacent to a given n-face. */
+ detach_pair(mln::Image<I>& ima,
+ const Neighborhood<NL>& lower_adj_nbh,
+ const Neighborhood<NH>& higher_adj_nbh);
+ /// \}
+
+ /* FIXME: Rename as init() or something like this? See how other
+ functors are written. */
+ /// Set the underlying image.
+ void set_image(mln::Image<I>& ima);
+
+ /** Detach the pair (\a f, \a q) from \a ima_.
+
+ \param f An n-facet of \a ima
+ \param g An (n-1)-face ajacent to \a f. */
+ void operator()(const mln_psite(I)& f, const mln_psite(I)& g);
+
+ /** Detach a simple pair from \a ima_ containing the face \a f.
+
+ \param f An n-facet of \a ima. */
+ void operator()(const mln_psite(I)& f);
+
+ private:
+ I* ima_;
+ const NL& lower_adj_nbh_;
+ const NH& higher_adj_nbh_;
+ /// Simplicity citerion.
+ is_simple_pair<I, NL, NH> is_simple_;
+ };
+
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ template <typename I, typename NL, typename NH>
+ inline
+ detach_pair<I, NL, NH>::detach_pair(const Neighborhood<NL>&
lower_adj_nbh,
+ const Neighborhood<NH>& higher_adj_nbh)
+ : ima_(0),
+ lower_adj_nbh_(exact(lower_adj_nbh)),
+ higher_adj_nbh_(exact(higher_adj_nbh)),
+ is_simple_(lower_adj_nbh, higher_adj_nbh)
+ {
+ mlc_equal(mln_value(I), bool)::check();
+ }
+
+ template <typename I, typename NL, typename NH>
+ inline
+ detach_pair<I, NL, NH>::detach_pair(mln::Image<I>& ima,
+ const Neighborhood<NL>& lower_adj_nbh,
+ const Neighborhood<NH>& higher_adj_nbh)
+ : ima_(exact(&ima)),
+ lower_adj_nbh_(exact(lower_adj_nbh)),
+ higher_adj_nbh_(exact(higher_adj_nbh)),
+ is_simple_(ima, lower_adj_nbh, higher_adj_nbh)
+ {
+ mlc_equal(mln_value(I), bool)::check();
+ }
+
+ template <typename I, typename NL, typename NH>
+ inline
+ void
+ detach_pair<I, NL, NH>::set_image(mln::Image<I>& ima)
+ {
+ ima_ = exact(&ima);
+ is_simple_.set_image(ima);
+ }
+
+ template <typename I, typename NL, typename NH>
+ inline
+ void
+ detach_pair<I, NL, NH>::operator()(const mln_psite(I)& f,
+ const mln_psite(I)& g)
+ {
+ mln_precondition(ima_);
+ mln_precondition(is_simple_(f, g));
+
+ // Shortcut.
+ // FIXME: Introduce an `ima()' accessor instead?
+ I& ima = *ima_;
+
+ ima(f) = false;
+ ima(g) = false;
+ }
+
+ // FIXME: What about moving this operator() into its own functor?
+ template <typename I, typename NL, typename NH>
+ inline
+ void
+ detach_pair<I, NL, NH>::operator()(const mln_psite(I)& f)
+ {
+ mln_niter(NL) g(lower_adj_nbh_, f);
+ for_all(g)
+ {
+ if (is_simple_(f, g))
+ // Delegate the detach operation to the binary operator().
+ return (*this)(f, g);
+ }
+ }
+
+# endif // MLN_INCLUDE_ONLY
+
+ } // end of namespace mln::topo
+
+} // end of namespace mln
+
+#endif // ! MLN_TOPO_DETACH_PAIR_HH
diff --git a/milena/mln/topo/is_simple_pair.hh b/milena/mln/topo/is_simple_pair.hh
new file mode 100644
index 0000000..2b5d89b
--- /dev/null
+++ b/milena/mln/topo/is_simple_pair.hh
@@ -0,0 +1,225 @@
+// Copyright (C) 2011 EPITA Research and Development Laboratory (LRDE)
+//
+// This file is part of Olena.
+//
+// Olena is free software: you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation, version 2 of the License.
+//
+// Olena 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
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Olena. If not, see <http://www.gnu.org/licenses/>.
+//
+// As a special exception, you may use this file as part of a free
+// software project without restriction. Specifically, 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 General Public License. This
+// exception does not however invalidate any other reasons why the
+// executable file might be covered by the GNU General Public License.
+
+#ifndef MLN_TOPO_IS_SIMPLE_PAIR_HH
+# define MLN_TOPO_IS_SIMPLE_PAIR_HH
+
+/// \file
+/// \brief Testing whether a pair of faces is simple (or whether a
+/// face belongs to a simple pair)
+
+# include <mln/core/concept/function.hh>
+# include <mln/core/concept/image.hh>
+# include <mln/core/concept/neighborhood.hh>
+
+# include <mln/topo/is_facet.hh>
+
+
+namespace mln
+{
+
+ namespace topo
+ {
+
+ /** \brief A predicate for the simplicity of a pair (or a face
+ that might belong to a simple pair).
+
+ The functor may either take a pair composed of an n-face F and
+ an (n-1)-face G (where F is a facet), or just a single facet
+ F. In this latter case, it tries to find an (n-1)-face G so
+ that (F, G) form a simple pair.
+
+ \tparam I The type of the image.
+ \tparam NL The neighborhood type returning the set of
+ (n-1)-faces adjacent to a an n-face.
+ \tparam NH The neighborhood type returning the set of
+ (n+1)-faces adjacent to a an n-face. */
+ template <typename I, typename NL, typename NH>
+ class is_simple_pair
+ : public mln::Function_v2b< is_simple_pair<I, NL, NH> >
+ {
+ public:
+ /// Result type of the functor.
+ typedef bool result;
+
+ /// Constructors.
+ /// \{
+ /** Construct an mln::topo::is_simple_pair from a couple of
+ neighborhoods.
+
+ \param lower_adj_nbh An adjacency relationship between faces
+ returning the set of (n-1)-faces
+ adjacent to a given n-face.
+ \param higher_adj_nbh An adjacency relationship between faces
+ returning the set of (n+1)-faces
+ adjacent to a given n-face. */
+ is_simple_pair(const Neighborhood<NL>& lower_adj_nbh,
+ const Neighborhood<NH>& higher_adj_nbh);
+
+ /** Construct an mln::topo::detach_pair from an image and a
+ couple of neighborhoods.
+
+ \pre \a ima is an image of Boolean values.
+
+ \param ima The input image the pair belongs to.
+ \param lower_adj_nbh An adjacency relationship between faces
+ returning the set of (n-1)-faces
+ adjacent to a given n-face.
+ \param higher_adj_nbh An adjacency relationship between faces
+ returning the set of (n+1)-faces
+ adjacent to a given n-face. */
+ is_simple_pair(const mln::Image<I>& ima,
+ const Neighborhood<NL>& lower_adj_nbh,
+ const Neighborhood<NH>& higher_adj_nbh);
+ /// \}
+
+ /* FIXME: Rename as init() or something like this? See how other
+ functors are written. */
+ /// Set the underlying image.
+ void set_image(const mln::Image<I>& ima);
+
+ /** \brief Test whether the pair (\a f, \a g) is simple.
+
+ If \a f is not a facet, return false.
+ If \a g is not a (n-1)-face adjacent to the n-face \a f,
+ return false. */
+ bool operator()(const mln_psite(I)& f, const mln_psite(I)& g) const;
+
+ /** \brief Test whether \a f is part of a simple pair.
+
+ If \a f is not a facet, return false. */
+ bool operator()(const mln_psite(I)& f) const;
+
+ private:
+ const I* ima_;
+ const NL& lower_adj_nbh_;
+ const NH& higher_adj_nbh_;
+ };
+
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ template <typename I, typename NL, typename NH>
+ inline
+ is_simple_pair<I, NL, NH>::is_simple_pair(const Neighborhood<NL>&
lower_adj_nbh,
+ const Neighborhood<NH>& higher_adj_nbh)
+ : ima_(0),
+ lower_adj_nbh_(exact(lower_adj_nbh)),
+ higher_adj_nbh_(exact(higher_adj_nbh))
+ {
+ mlc_equal(mln_value(I), bool)::check();
+ }
+
+ template <typename I, typename NL, typename NH>
+ inline
+ is_simple_pair<I, NL, NH>::is_simple_pair(const mln::Image<I>& ima,
+ const Neighborhood<NL>& lower_adj_nbh,
+ const Neighborhood<NH>& higher_adj_nbh)
+ : ima_(exact(&ima)),
+ lower_adj_nbh_(exact(lower_adj_nbh)),
+ higher_adj_nbh_(exact(higher_adj_nbh))
+ {
+ mlc_equal(mln_value(I), bool)::check();
+ }
+
+ template <typename I, typename NL, typename NH>
+ inline
+ void
+ is_simple_pair<I, NL, NH>::set_image(const mln::Image<I>& ima)
+ {
+ ima_ = exact(&ima);
+ }
+
+ template <typename I, typename NL, typename NH>
+ inline
+ bool
+ is_simple_pair<I, NL, NH>::operator()(const mln_psite(I)& f,
+ const mln_psite(I)& g) const
+ {
+ mln_precondition(ima_);
+ // Shortcut.
+ // FIXME: Introduce an `ima()' accessor instead?
+ const I& ima = *ima_;
+
+ // (F, G) cannot be a simple pair unless they are part of
+ // objects in IMA.
+ if (!ima(f) || !ima(g))
+ return false;
+
+ // F cannot be part of a simple pair unless it is a facet.
+ if (!is_facet(ima, f, higher_adj_nbh_))
+ return false;
+
+ /* FIXME: It would be nice if we could skip this check when G is
+ passed by the unary operator(), since this one already
+ ensuress that F and G are adjacent. */
+ // Ensure the (n-1)-face G is adjacent to the n-face F.
+ {
+ bool f_g_adjacent = false;
+ mln_niter(NH) h(higher_adj_nbh_, g);
+ for_all(h)
+ if (h == f)
+ {
+ f_g_adjacent = true;
+ break;
+ }
+ if (!f_g_adjacent)
+ return false;
+ }
+
+ // Check whether G is stricly included in F.
+ mln_niter(NH) h(higher_adj_nbh_, g);
+ for_all(h)
+ if (h != f && ima.has(h) && ima(h))
+ return false;
+ return true;
+ }
+
+ // FIXME: What about moving this operator() into its own functor
+ // called e.g. mln::topo::is_in_simple_pair?
+ template <typename I, typename NL, typename NH>
+ inline
+ bool
+ is_simple_pair<I, NL, NH>::operator()(const mln_psite(I)& f) const
+ {
+ mln_niter(NL) g(lower_adj_nbh_, f);
+ for_all(g)
+ {
+ // Delegate the computation to the binary operator().
+ if ((*this)(f, g))
+ // (F, G) is a simple pair.
+ return true;
+ }
+ return false;
+ }
+
+# endif // MLN_INCLUDE_ONLY
+
+ } // end of namespace mln::topo
+
+} // end of namespace mln
+
+#endif // ! MLN_TOPO_IS_SIMPLE_PAIR_HH
diff --git a/milena/tests/topo/Makefile.am b/milena/tests/topo/Makefile.am
index 6da7c28..608ac92 100644
--- a/milena/tests/topo/Makefile.am
+++ b/milena/tests/topo/Makefile.am
@@ -21,9 +21,15 @@ SUBDIRS = skeleton
check_PROGRAMS = \
complex \
- is_facet
+ detach_pair \
+ is_facet \
+ is_simple_pair
complex_SOURCES = complex.cc
+detach_pair_SOURCES = detach_pair.cc
is_facet_SOURCES = is_facet.cc
+is_simple_pair_SOURCES = is_simple_pair.cc
TESTS = $(check_PROGRAMS)
+
+MOSTLYCLEANFILES = detach_pair-out.vtk
diff --git a/milena/tests/io/vtk/load_bin.cc b/milena/tests/topo/detach_pair.cc
similarity index 51%
copy from milena/tests/io/vtk/load_bin.cc
copy to milena/tests/topo/detach_pair.cc
index a4ddf10..ac2133b 100644
--- a/milena/tests/io/vtk/load_bin.cc
+++ b/milena/tests/topo/detach_pair.cc
@@ -24,13 +24,15 @@
// executable file might be covered by the GNU General Public License.
/// \file
-/// \brief Exercise mln::io::vtk::load on binary mesh images.
+/// \brief Exercise mln::topo::detach_pair.
-#include <algorithm>
-#include <iterator>
-#include <iostream>
+#include <mln/core/alias/complex_image.hh>
+#include <mln/core/image/complex_neighborhoods.hh>
+
+#include <mln/topo/detach_pair.hh>
#include <mln/io/vtk/load.hh>
+#include <mln/io/vtk/save.hh>
#include "tests/data.hh"
@@ -38,23 +40,34 @@
int
main()
{
- using namespace mln;
+ // Image type.
+ typedef mln::bin_2complex_image3df ima_t;
+ // Dimension of the image (and thus of the complex).
+ static const unsigned D = ima_t::dim;
+ // Geometry of the image.
+ typedef mln_geom_(ima_t) G;
- typedef bin_2complex_image3df ima_t;
ima_t ima;
- io::vtk::load(ima, MLN_MESH_DIR "/tetrahedron.vtk");
-
- std::cout << ima.domain().cplx() << std::endl;
-
- mln_piter_(ima_t) p(ima.domain());
- for_all(p)
- {
- std::cout << "ima(" << p << ") = " <<
ima(p) << " ( ";
- // Print site(s).
- typedef mln_site_(ima_t) site_t;
- site_t s(p);
- std::copy (s.sites.begin(), s.sites.end(),
- std::ostream_iterator<site_t::location>(std::cout, " "));
- std::cout << ")" << std::endl;
- }
+ mln::io::vtk::load(ima, MLN_MESH_DIR "/pseudo-manifold.vtk");
+
+ // Neighborhood type returning the set of (n-1)-faces adjacent to a
+ // an n-face.
+ typedef mln::complex_lower_neighborhood<D, G> lower_adj_nbh_t;
+ lower_adj_nbh_t lower_adj_nbh;
+ // Neighborhood type returning the set of (n+1)-faces adjacent to a
+ // an n-face.
+ typedef mln::complex_higher_neighborhood<D, G> higher_adj_nbh_t;
+ higher_adj_nbh_t higher_adj_nbh;
+ // Functor detaching a simple pair.
+ typedef mln::topo::detach_pair< ima_t,
+ lower_adj_nbh_t,
+ higher_adj_nbh_t > detach_t;
+
+ // Detach simple 2-faces from IMA.
+ detach_t detach(ima, lower_adj_nbh, higher_adj_nbh);
+ mln::p_n_faces_fwd_piter<D, G> f(ima.domain(), 2);
+ for_all(f)
+ detach(f);
+
+ mln::io::vtk::save(ima, "detach_pair-out.vtk");
}
diff --git a/milena/tests/io/vtk/load_bin.cc b/milena/tests/topo/is_simple_pair.cc
similarity index 53%
copy from milena/tests/io/vtk/load_bin.cc
copy to milena/tests/topo/is_simple_pair.cc
index a4ddf10..55f46d4 100644
--- a/milena/tests/io/vtk/load_bin.cc
+++ b/milena/tests/topo/is_simple_pair.cc
@@ -24,11 +24,12 @@
// executable file might be covered by the GNU General Public License.
/// \file
-/// \brief Exercise mln::io::vtk::load on binary mesh images.
+/// \brief Exercise mln::topo::is_simple_pair.
-#include <algorithm>
-#include <iterator>
-#include <iostream>
+#include <mln/core/alias/complex_image.hh>
+#include <mln/core/image/complex_neighborhoods.hh>
+
+#include <mln/topo/is_simple_pair.hh>
#include <mln/io/vtk/load.hh>
@@ -38,23 +39,35 @@
int
main()
{
- using namespace mln;
+ // Image type.
+ typedef mln::bin_2complex_image3df ima_t;
+ // Dimension of the image (and thus of the complex).
+ static const unsigned D = ima_t::dim;
+ // Geometry of the image.
+ typedef mln_geom_(ima_t) G;
- typedef bin_2complex_image3df ima_t;
ima_t ima;
- io::vtk::load(ima, MLN_MESH_DIR "/tetrahedron.vtk");
+ mln::io::vtk::load(ima, MLN_MESH_DIR "/pseudo-manifold.vtk");
- std::cout << ima.domain().cplx() << std::endl;
+ // Neighborhood type returning the set of (n-1)-faces adjacent to a
+ // an n-face.
+ typedef mln::complex_lower_neighborhood<D, G> lower_adj_nbh_t;
+ lower_adj_nbh_t lower_adj_nbh;
+ // Neighborhood type returning the set of (n+1)-faces adjacent to a
+ // an n-face.
+ typedef mln::complex_higher_neighborhood<D, G> higher_adj_nbh_t;
+ higher_adj_nbh_t higher_adj_nbh;
+ // Predicate type: does a triangle (2-face) belongs to a simple pair?
+ typedef mln::topo::is_simple_pair< ima_t,
+ lower_adj_nbh_t,
+ higher_adj_nbh_t > is_simple_t;
+ // Check the simplicity of IMA's faces.
+ is_simple_t is_simple(ima, lower_adj_nbh, higher_adj_nbh);
mln_piter_(ima_t) p(ima.domain());
for_all(p)
{
- std::cout << "ima(" << p << ") = " <<
ima(p) << " ( ";
- // Print site(s).
- typedef mln_site_(ima_t) site_t;
- site_t s(p);
- std::copy (s.sites.begin(), s.sites.end(),
- std::ostream_iterator<site_t::location>(std::cout, " "));
- std::cout << ")" << std::endl;
+ if (is_simple(p))
+ std::cout << p << std::endl;
}
}
--
1.5.6.5