2148: Add a backward iterator on complex-based images.

https://svn.lrde.epita.fr/svn/oln/trunk/milena Index: ChangeLog from Roland Levillain <roland@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.
participants (1)
-
Roland Levillain