
* 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@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@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