https://svn.lrde.epita.fr/svn/oln/trunk/milena
Index: ChangeLog
from Roland Levillain <roland(a)lrde.epita.fr>
Add a backward iterator on complex-based images.
* mln/core/p_complex_piter.hh (mln::p_complex_bkd_piter_<D, P>):
(operator<<(std::ostream&, const p_complex_bkd_piter_<D, P>&)):
New.
(mln::p_complex_fwd_piter_<D, P>::next_): Reimplement to make it
symmetric to mln::p_complex_bkd_piter_<D, P>::next_.
* mln/core/p_complex.hh (mln::p_complex<D, P>::bkd_piter): Set
typedef to p_complex_bkd_piter_<D, P>.
* mln/core/p_complex_piter.hh: Test the backward iterator on
complex_image.
mln/core/p_complex.hh | 5
mln/core/p_complex_piter.hh | 285 ++++++++++++++++++++++++++++++++++++++++++--
tests/core/complex_image.cc | 28 +++-
3 files changed, 302 insertions(+), 16 deletions(-)
Index: tests/core/complex_image.cc
--- tests/core/complex_image.cc (revision 2147)
+++ tests/core/complex_image.cc (working copy)
@@ -194,18 +194,34 @@
| Complex-based image iterators. |
`--------------------------------*/
- mln_piter_(ima_t) p(ima.domain());
- for_all(p)
- std::cout << "ima(" << p << ") = " <<
ima(p) << std::endl;
+ mln_fwd_piter_(ima_t) fp(ima.domain());
+ for_all(fp)
+ std::cout << "ima(" << fp << ") = " <<
ima(fp) << std::endl;
+ std::cout << std::endl;
- /* FIXME: Implement windows (and neighborhoods) for complex-images.
+ mln_bkd_piter_(ima_t) bp(ima.domain());
+ for_all(bp)
+ std::cout << "ima(" << bp << ") = " <<
ima(bp) << std::endl;
+
+
+ /* FIXME: Implement other psite iterators, for instance:
+
+ - iterators on N-faces with N fixed in [0, D] (using p_faces
+ and faces_psite?)
+ - iterators on N-faces with N in a subset of [0, D];
+ - etc. */
+
+ /* FIXME: Implement windows (and neighborhoods) and corresponding
+ iterators for complex-based 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-1)-faces adjacent to P (using p_faces and
+ faces_psite?);
+ - the set of (N+1)-faces adjacent to P (using p_faces and
+ faces_psite?);
- 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
Index: mln/core/p_complex_piter.hh
--- mln/core/p_complex_piter.hh (revision 2147)
+++ mln/core/p_complex_piter.hh (working copy)
@@ -37,8 +37,12 @@
/// \file mln/core/p_complex_piter.hh
/// \brief Definition of point iterator on complex-based pset.
+// Factor p_complex_fwd_piter_<D, P> and p_complex_bkd_piter_<D, P>
+
namespace mln
{
+ /* FIXME: Get rid of P? */
+
// Fwd decls.
template <unsigned D, typename P> class p_complex;
template <unsigned D, typename P> class complex_psite;
@@ -48,8 +52,6 @@
| 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_
@@ -143,14 +145,100 @@
| p_complex_bkd_piter_<D, P>. |
`-----------------------------*/
- // FIXME: Define p_complex_bkd_piter_<D, P>.
+ /// \brief Backward iterator on point sites of a mln::p_complex<D, P>.
+ template <unsigned D, typename P>
+ class p_complex_bkd_piter_
+ : public internal::point_iterator_base_< P, p_complex_bkd_piter_<D, P> >
+ {
+ typedef p_complex_bkd_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_bkd_piter_(const p_complex<D, P>& pc);
+ p_complex_bkd_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_bkd_piter_<D, P>&
p);
# ifndef MLN_INCLUDE_ONLY
/*-----------------------------.
- | p_line_graph_fwd_piter_<P>. |
+ | p_complex_fwd_piter_<D, P>. |
`-----------------------------*/
template <unsigned D, typename P>
@@ -228,10 +316,11 @@
void
p_complex_fwd_piter_<D, P>::next_()
{
+ if (is_valid())
+ {
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
@@ -241,12 +330,16 @@
instead of the following. */
face_.set_face_id(face_id + 1);
else
+ // Start to iterate on the faces of the next dimension if
+ // possible.
+ if (n <= D)
{
- // 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);
}
+ else
+ invalidate();
}
if (is_valid())
update_();
@@ -331,7 +424,183 @@
| p_complex_bkd_piter_<D, P>. |
`-----------------------------*/
- // FIXME: Implement p_complex_bkd_piter_<D, P>.
+ template <unsigned D, typename P>
+ inline
+ p_complex_bkd_piter_<D, P>::p_complex_bkd_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_bkd_piter_<D, P>::p_complex_bkd_piter_(const p_complex_bkd_piter_<D,
P>& rhs)
+ : face_(rhs.face_),
+ psite_(rhs.psite_),
+ // Dummy value.
+ p_()
+ {
+ }
+
+ template <unsigned D, typename P>
+ inline
+ p_complex_bkd_piter_<D, P>&
+ p_complex_bkd_piter_<D, P>::operator=(const p_complex_bkd_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_bkd_piter_<D, P>::operator[](unsigned i) const
+ {
+ // Dummy value.
+ return p_[i];
+ }
+
+ template <unsigned D, typename P>
+ inline
+ bool
+ p_complex_bkd_piter_<D, P>::is_valid() const
+ {
+ return face_.is_valid();
+ }
+
+ template <unsigned D, typename P>
+ inline
+ void
+ p_complex_bkd_piter_<D, P>::invalidate()
+ {
+ face_.set_n(invalid_unsigned_());
+ face_.set_face_id(invalid_unsigned_());
+ }
+
+ template <unsigned D, typename P>
+ inline
+ void
+ p_complex_bkd_piter_<D, P>::start()
+ {
+ face_.set_n(D);
+ face_.set_face_id(face_.cplx().template nfaces<D>() - 1);
+ update_();
+ }
+
+ template <unsigned D, typename P>
+ inline
+ void
+ p_complex_bkd_piter_<D, P>::next_()
+ {
+ if (is_valid())
+ {
+ unsigned n = face_.n();
+ unsigned face_id = face_.face_id();
+
+ if (face_id > 0)
+ /* 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 previous dimension
+ // if it exists.
+ if (n > 0)
+ {
+ // FIXME: Same remark as above.
+ face_.set_n(n - 1);
+ face_.set_face_id(face_.cplx().nfaces(n - 1) - 1);
+ }
+ else
+ invalidate();
+ }
+ if (is_valid())
+ update_();
+ }
+
+ template <unsigned D, typename P>
+ inline
+ void
+ p_complex_bkd_piter_<D, P>::update_()
+ {
+ // Update psite_.
+ psite_ = complex_psite<D, P>(face_);
+ }
+
+ template <unsigned D, typename P>
+ inline
+ const P&
+ p_complex_bkd_piter_<D, P>::to_point() const
+ {
+ // Dummy value.
+ return p_;
+ }
+
+ template <unsigned D, typename P>
+ inline
+ const complex_psite<D, P>&
+ p_complex_bkd_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_bkd_piter_<D, P>::operator complex_psite<D, P>() const
+ {
+ mln_precondition(is_valid());
+ return psite_;
+ }
+
+ template <unsigned D, typename P>
+ unsigned
+ p_complex_bkd_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_bkd_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);
+ }
# endif // ! MLN_INCLUDE_ONLY
Index: mln/core/p_complex.hh
--- mln/core/p_complex.hh (revision 2147)
+++ mln/core/p_complex.hh (working copy)
@@ -73,9 +73,10 @@
/// Point_Site associated type.
typedef complex_psite<D, P> psite;
- // FIXME: Fake.
+ /// Forward Point_Iterator associated type.
typedef p_complex_fwd_piter_<D, P> fwd_piter;
- typedef void bkd_piter;
+ /// Backward Point_Iterator associated type.
+ typedef p_complex_bkd_piter_<D, P> bkd_piter;
/// \brief Return The number of points (sites) of the set, i.e., the
/// number of \em faces.