https://svn.lrde.epita.fr/svn/oln/trunk/milena
Index: ChangeLog
from Roland Levillain <roland(a)lrde.epita.fr>
Add a forward iterator on complex-based images.
* mln/core/p_complex_piter.hh: New.
* mln/core/p_complex.h (mln::p_complex<D, P>::fwd_piter): Set
typedef to p_complex_fwd_piter_<D, P>.
(mln::p_complex<D, P>::cplx_): Make it mutable.
(mln::p_complex<D, P>::cplx() const): Remove const qualifier on
return type.
* mln/core/face.hh
(mln::any_face_handle<D>::is_valid): Fix this method: check the
dimension too.
(mln::any_face_handle<D>::set_cplx)
(mln::any_face_handle<D>::set_n)
(mln::any_face_handle<D>::set_face_id):
New methods.
* tests/core/complex_image.cc: Don't forget to initialize all
cells of `values', including the ones of highest dimension.
Test the forward iterator on complex_image.
mln/core/face.hh | 36 ++++
mln/core/p_complex.hh | 26 ++-
mln/core/p_complex_piter.hh | 341 ++++++++++++++++++++++++++++++++++++++++++++
tests/core/complex_image.cc | 37 ++++
4 files changed, 430 insertions(+), 10 deletions(-)
Index: tests/core/complex_image.cc
--- tests/core/complex_image.cc (revision 2146)
+++ tests/core/complex_image.cc (working copy)
@@ -147,7 +147,6 @@
any_face_handle<D> af(e0_);
// An associated psite.
complex_psite<D, point2d> cs(af);
- std::cout << cs << std::endl;
/*--------------------.
@@ -180,7 +179,7 @@
// Values.
metal::vec<D + 1, std::vector< int_u8 > > values;
// Assign 0 to 0-faces, 1 to 1-faces and 2 to 2-faces.
- for (unsigned d = 0; d < D; ++d)
+ for (unsigned d = 0; d <= D; ++d)
for (unsigned n = 0; n < pc.cplx().nfaces(d); ++n)
values[d].push_back(d);
@@ -195,8 +194,36 @@
| Complex-based image iterators. |
`--------------------------------*/
- // FIXME: Enable when iterators are available.
-#if 0
mln_piter_(ima_t) p(ima.domain());
-#endif
+ for_all(p)
+ std::cout << "ima(" << p << ") = " <<
ima(p) << std::endl;
+
+
+ /* FIXME: Implement windows (and neighborhoods) for complex-images.
+
+ For a given (fixed) dimension N and a psite P on a N-face,
+ implement windows returning
+
+ - the set of (N-1)-faces adjacent to P;
+ - the set of (N+1)-faces adjacent to P;
+
+ - the set of N-faces sharing a (N-1)-face with P;
+ - the set of N-faces sharing a (N-1)-face or (N-2)-face (by
+ transitivity) with P (is it useful?);
+
+ - the set of the ``cell'' including P (named ``P-hat'' in
+ couprie.08.pami), i.e., the set of all M-faces adjacent to P,
+ where M is in [0, N-1].
+
+ In that definition, P is said adjacent to an M-face Q if
+ if there is a sequence (M1, M2, ..., Mn) of faces so that
+ - M1 is an (M+1)-face adjacent to M ;
+ - M2 is an (M+2)-face adjacent to M1 ;
+ - and so on;
+ - Mn is an (N-1)-face adjacent to N.
+
+ - what else?
+
+ We might want to look at operators on (simplicial?) complexes
+ like star, link, etc. and possibly implement them. */
}
Index: mln/core/p_complex_piter.hh
--- mln/core/p_complex_piter.hh (revision 0)
+++ mln/core/p_complex_piter.hh (revision 0)
@@ -0,0 +1,341 @@
+// Copyright (C) 2008 EPITA Research and Development Laboratory (LRDE)
+//
+// This file is part of the Olena Library. This library is free
+// software; you can redistribute it and/or modify it under the terms
+// of the GNU General Public License version 2 as published by the
+// Free Software Foundation.
+//
+// This library 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 this library; see the file COPYING. If not, write to
+// the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+// Boston, MA 02111-1307, USA.
+//
+// As a special exception, you may use this file as part of a free
+// software library 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.
+// reasons why the executable file might be covered by the GNU General
+// Public License.
+
+#ifndef MLN_CORE_P_COMPLEX_PITER_HH
+# define MLN_CORE_P_COMPLEX_PITER_HH
+
+# include <limits>
+
+# include <mln/core/internal/point_iterator_base.hh>
+# include <mln/core/p_complex.hh>
+# include <mln/core/complex_psite.hh>
+
+/// \file mln/core/p_complex_piter.hh
+/// \brief Definition of point iterator on complex-based pset.
+
+namespace mln
+{
+ // Fwd decls.
+ template <unsigned D, typename P> class p_complex;
+ template <unsigned D, typename P> class complex_psite;
+
+
+ /*-----------------------------.
+ | p_complex_fwd_piter_<D, P>. |
+ `-----------------------------*/
+
+ /* FIXME: Get rid of P? */
+
+ /// \brief Forward iterator on point sites of a mln::p_complex<D, P>.
+ template <unsigned D, typename P>
+ class p_complex_fwd_piter_
+ : public internal::point_iterator_base_< P, p_complex_fwd_piter_<D, P> >
+ {
+ typedef p_complex_fwd_piter_<D, P> self_;
+ typedef internal::point_iterator_base_< P, self_ > super_;
+
+ public:
+ // Make definitions from super class available.
+ // FIXME: Is it still meaningful for a complex?
+ enum { dim = super_::dim };
+
+ typedef complex_psite<D, P> psite;
+ typedef P point;
+ typedef mln_coord(point) coord;
+
+ /// Construction and assignment.
+ /// \{
+ p_complex_fwd_piter_(const p_complex<D, P>& pc);
+ p_complex_fwd_piter_(const self_& rhs);
+ self_& operator= (const self_& rhs);
+ /// \}
+
+ /// Manipulation.
+ /// \{
+ /// Test if the iterator is valid.
+ bool is_valid() const;
+ /// Invalidate the iterator.
+ void invalidate();
+ /// Start an iteration.
+ void start();
+
+ /// Go to the next point.
+ void next_();
+ /// Update the internal data of the iterator.
+ void update_();
+ /// \}
+
+ /// Conversion and accessors.
+ /// \{
+ /// Reference to the corresponding point.
+ // FIXME: Don't use this method (dummy value).
+ const point& to_point () const;
+ /// Reference to the corresponding point site.
+ const psite& to_psite () const;
+ /// Convert the iterator into a line graph psite.
+ operator psite() const;
+
+ /// Read-only access to the \a i-th coordinate.
+ // FIXME: Don't use this operator (dummy value).
+ coord operator[](unsigned i) const;
+ /// \}
+
+ private:
+ /// The face handle this iterator is pointing to.
+ any_face_handle<D> face_;
+ /// The psite corresponding to this iterator.
+ psite psite_;
+ /// \brief The point associated to this psite.
+ // FIXME: Actually, this is a dummy value!
+ point p_;
+
+ /// \brief An invalid value for both the dimension and the id of
+ /// the face.
+ ///
+ /// Use a function instead of a static constant, since `static'
+ /// variables needs to be compiled once, which requires a compiled
+ /// library to avoid duplicate symbols, which is something that
+ /// was not really planned in Milena. A function tagged `inlined'
+ /// can appear multiple times in a program, and solves this
+ /// problem. We rely on the compiler to inline this call.
+ ///
+ /// Of course, we could have used UINT_MAX, but it is not very
+ /// C++.
+ unsigned invalid_unsigned_() const;
+ };
+
+
+ /* FIXME: This hand-made delegation is painful. We should rely on
+ the general mechanism provided by Point_Site. But then again, we
+ need to refine/adjust the interface of Point_Site w.r.t. the
+ mandatory conversions to points. */
+ template <unsigned D, typename P>
+ inline
+ std::ostream&
+ operator<<(std::ostream& ostr, const p_complex_fwd_piter_<D, P>&
p);
+
+
+ /*-----------------------------.
+ | p_complex_bkd_piter_<D, P>. |
+ `-----------------------------*/
+
+ // FIXME: Define p_complex_bkd_piter_<D, P>.
+
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ /*-----------------------------.
+ | p_line_graph_fwd_piter_<P>. |
+ `-----------------------------*/
+
+ template <unsigned D, typename P>
+ inline
+ p_complex_fwd_piter_<D, P>::p_complex_fwd_piter_(const p_complex<D, P>&
pc)
+ // Initialize psite_ and p_ a dummy values.
+ : psite_(),
+ p_()
+ {
+ face_.set_cplx(pc.cplx());
+ // Invalidate face_.
+ invalidate();
+ }
+
+ template <unsigned D, typename P>
+ inline
+ p_complex_fwd_piter_<D, P>::p_complex_fwd_piter_(const p_complex_fwd_piter_<D,
P>& rhs)
+ : face_(rhs.face_),
+ psite_(rhs.psite_),
+ // Dummy value.
+ p_()
+ {
+ }
+
+ template <unsigned D, typename P>
+ inline
+ p_complex_fwd_piter_<D, P>&
+ p_complex_fwd_piter_<D, P>::operator=(const p_complex_fwd_piter_<D, P>&
rhs)
+ {
+ if (&rhs == this)
+ return *this;
+ face_ = rhs.face_;
+ psite_ = rhs.psite_;
+ return *this;
+ }
+
+ template <unsigned D, typename P>
+ inline
+ mln_coord(P)
+ p_complex_fwd_piter_<D, P>::operator[](unsigned i) const
+ {
+ // Dummy value.
+ return p_[i];
+ }
+
+ template <unsigned D, typename P>
+ inline
+ bool
+ p_complex_fwd_piter_<D, P>::is_valid() const
+ {
+ return face_.is_valid();
+ }
+
+ template <unsigned D, typename P>
+ inline
+ void
+ p_complex_fwd_piter_<D, P>::invalidate()
+ {
+ face_.set_n(invalid_unsigned_());
+ face_.set_face_id(invalid_unsigned_());
+ }
+
+ template <unsigned D, typename P>
+ inline
+ void
+ p_complex_fwd_piter_<D, P>::start()
+ {
+ face_.set_n(0u);
+ face_.set_face_id(0u);
+ update_();
+ }
+
+ template <unsigned D, typename P>
+ inline
+ void
+ p_complex_fwd_piter_<D, P>::next_()
+ {
+ unsigned n = face_.n();
+ unsigned face_id = face_.face_id();
+ if (n <= D)
+ {
+ if (face_id + 1 < face_.cplx().nfaces(n))
+ /* FIXME: Provide accessor any_face_handle::n() returning
+ a mutable reference? This way, we could just write
+
+ ++face_.face_id();
+
+ instead of the following. */
+ face_.set_face_id(face_id + 1);
+ else
+ {
+ // Start to iterate on the faces of the next dimension.
+ // FIXME: Same remark as above.
+ face_.set_n(n + 1);
+ face_.set_face_id(0u);
+ }
+ }
+ if (is_valid())
+ update_();
+ }
+
+ template <unsigned D, typename P>
+ inline
+ void
+ p_complex_fwd_piter_<D, P>::update_()
+ {
+ // Update psite_.
+ psite_ = complex_psite<D, P>(face_);
+ }
+
+ template <unsigned D, typename P>
+ inline
+ const P&
+ p_complex_fwd_piter_<D, P>::to_point() const
+ {
+ // Dummy value.
+ return p_;
+ }
+
+ template <unsigned D, typename P>
+ inline
+ const complex_psite<D, P>&
+ p_complex_fwd_piter_<D, P>::to_psite() const
+ {
+ /* We don't check whether the iterator is valid before returning
+ the value using
+
+ mln_precondition(is_valid());
+
+ since this method may be called *before* the iterator is
+ actually initialized. This is the case for instance when this
+ point iterator (say, P) is used to initialize another iterator
+ on window or neighborhood (say, Q); most of the time, for_all()
+ is responsible for the initialization of P, but it takes place
+ *after* the creation of Q. */
+ return psite_;
+ }
+
+ template <unsigned D, typename P>
+ inline
+ p_complex_fwd_piter_<D, P>::operator complex_psite<D, P>() const
+ {
+ mln_precondition(is_valid());
+ return psite_;
+ }
+
+ template <unsigned D, typename P>
+ unsigned
+ p_complex_fwd_piter_<D, P>::invalid_unsigned_() const
+ {
+ return std::numeric_limits<unsigned>::max();
+ }
+
+
+ template <unsigned D, typename P>
+ inline
+ std::ostream&
+ operator<<(std::ostream& ostr, const p_complex_fwd_piter_<D, P>&
p)
+ {
+ /* FIXME: We should use p.to_psite() here, but as it lacks the
+ precondition the conversion operator has, so we use the latter.
+
+ We should
+ - rename `to_psite' as `to_psite_';
+ - write a new `to_psite' routine checking the validity of the
+ iterator;
+ - have the conversion operator to psite use this new `to_psite'
+ routine;
+ - adjust former clients of `to_psite'
+
+ This is a general remark that applies to all point/psite
+ iterators of Milena. */
+ return ostr << static_cast< complex_psite<D, P> >(p);
+ }
+
+
+ /*-----------------------------.
+ | p_complex_bkd_piter_<D, P>. |
+ `-----------------------------*/
+
+ // FIXME: Implement p_complex_bkd_piter_<D, P>.
+
+# endif // ! MLN_INCLUDE_ONLY
+
+} // end of mln
+
+
+#endif // ! MLN_CORE_P_COMPLEX_PITER_HH
Index: mln/core/face.hh
--- mln/core/face.hh (revision 2146)
+++ mln/core/face.hh (working copy)
@@ -162,6 +162,7 @@
/// Return the complex the face belongs to.
complex<D>& cplx() const;
/// Return the id of the face.
+ // FIXME: Rename as `id'?
unsigned face_id() const;
/// Return the mln::face pointed by this handle.
@@ -174,6 +175,7 @@
/// A const face_handle can be used to modify a complex.
mutable complex<D>* cplx_;
/// \brief The id of the face.
+ // FIXME: Rename as `id_'?
unsigned face_id_;
};
@@ -275,10 +277,19 @@
/// Return the complex the face belongs to.
complex<D>& cplx() const;
/// Return the dimension of the face.
+ // FIXME: Rename as `dim'?
unsigned n() const;
/// Return the id of the face.
+ // FIXME: Rename as `id'?
unsigned face_id() const;
+ /// Set the complex the face belongs to.
+ void set_cplx(complex<D>& cplx);
+ /// Set the dimension of the face.
+ void set_n(unsigned n);
+ /// Set the id of the face.
+ void set_face_id(unsigned face_id);
+
/// Return the mln::face pointed by this handle.
template <unsigned N>
face<N, D>& to_face() const;
@@ -290,8 +301,10 @@
/// A const any_face_handle can be used to modify a complex.
mutable complex<D>* cplx_;
/// The dimension of the face.
+ // FIXME: Rename as `dim_'?
unsigned n_;
/// \brief The id of the face.
+ // FIXME: Rename as `id_'?
unsigned face_id_;
};
@@ -538,7 +551,7 @@
bool
any_face_handle<D>::is_valid() const
{
- return cplx_ != 0 && face_id_ < cplx_->nfaces(n_);
+ return cplx_ != 0 && n_ <= D && face_id_ <
cplx_->nfaces(n_);
}
template <unsigned D>
@@ -564,6 +577,27 @@
}
template <unsigned D>
+ void
+ any_face_handle<D>::set_cplx(complex<D>& cplx)
+ {
+ cplx_ = &cplx;
+ }
+
+ template <unsigned D>
+ void
+ any_face_handle<D>::set_n(unsigned n)
+ {
+ n_ = n;
+ }
+
+ template <unsigned D>
+ void
+ any_face_handle<D>::set_face_id(unsigned face_id)
+ {
+ face_id_ = face_id;
+ }
+
+ template <unsigned D>
template <unsigned N>
face<N, D>&
any_face_handle<D>::to_face() const
Index: mln/core/p_complex.hh
--- mln/core/p_complex.hh (revision 2146)
+++ mln/core/p_complex.hh (working copy)
@@ -38,6 +38,7 @@
# include <mln/core/complex.hh>
# include <mln/core/complex_psite.hh>
+# include <mln/core/p_complex_piter.hh>
namespace mln
@@ -73,7 +74,7 @@
typedef complex_psite<D, P> psite;
// FIXME: Fake.
- typedef void fwd_piter;
+ typedef p_complex_fwd_piter_<D, P> fwd_piter;
typedef void bkd_piter;
/// \brief Return The number of points (sites) of the set, i.e., the
@@ -93,7 +94,9 @@
/// \{
/// Return the complex associated to the p_complex domain (const
/// version)
- const complex<D>& cplx() const;
+ /* FIXME: Move back the const qualifier on this return type (see
+ comment below on cplx_). */
+ complex<D>& cplx() const;
/// Return the complex associated to the p_complex domain (mutable
/// version).
complex<D>& cplx();
@@ -104,7 +107,22 @@
private:
/// The complex on which this pset is built.
- util::tracked_ptr< complex<D> > cplx_;
+ /* FIXME:Get rid of this `mutable' qualifier. This is needed for
+ compatiblity reasons with any_face_handle (see p_complex_piter)
+
+ We should either
+
+ - do not use any_face_handle in the implementation of
+ p_complex_piter;
+
+ - have an additional version of any_face_handles holding a
+ const (not mutable) complex;
+
+ - or even have face_handle and any_face_handle do not hold a
+ reference on a complex, leading to a design of complexes
+ similar to graphs, where vertex and edge handles (named `id's)
+ are not tied to a specific graph. */
+ mutable util::tracked_ptr< complex<D> > cplx_;
// FIXME: Remove as soon as bbox become optional.
box_<P> bb_;
};
@@ -176,7 +194,7 @@
}
template <unsigned D, typename P>
- const complex<D>&
+ complex<D>&
p_complex<D, P>::cplx() const
{
mln_precondition(cplx_);