Commit 366a438f authored by Roland Levillain's avatar Roland Levillain
Browse files

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.


git-svn-id: https://svn.lrde.epita.fr/svn/oln/trunk@2147 4aad255d-cdde-0310-9447-f3009e2ae8c0
parent 1f09a450
2008-08-12 Roland Levillain <roland@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.
2008-08-12 Roland Levillain <roland@lrde.epita.fr>
Add a missing (disabled) conversion method to
......
......@@ -162,6 +162,7 @@ namespace mln
/// 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 @@ namespace mln
/// 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 @@ namespace mln
/// 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 @@ namespace mln
/// 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 @@ namespace mln
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>
......@@ -563,6 +576,27 @@ namespace mln
return face_id_;
}
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>&
......
......@@ -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 @@ namespace mln
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 @@ namespace mln
/// \{
/// 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 @@ namespace mln
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 @@ namespace mln
}
template <unsigned D, typename P>
const complex<D>&
complex<D>&
p_complex<D, P>::cplx() const
{
mln_precondition(cplx_);
......
// 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
......@@ -147,7 +147,6 @@ int main()
any_face_handle<D> af(e0_);
// An associated psite.
complex_psite<D, point2d> cs(af);
std::cout << cs << std::endl;
/*--------------------.
......@@ -180,7 +179,7 @@ int main()
// 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 @@ int main()
| 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. */
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment