URL: https://svn.lrde.epita.fr/svn/oln/branches/cleanup-2008
ChangeLog:
2008-09-11 Guillaume Lazzara <z(a)lrde.epita.fr>
Add a section about graph images in tutorial.
* milena/doc/tutorial/tutorial.tex: Add a section about graph images and fix few mistakes all along the tutorial.
---
tutorial.tex | 281 ++++++++++++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 239 insertions(+), 42 deletions(-)
Index: branches/cleanup-2008/milena/doc/tutorial/tutorial.tex
===================================================================
--- branches/cleanup-2008/milena/doc/tutorial/tutorial.tex (revision 2214)
+++ branches/cleanup-2008/milena/doc/tutorial/tutorial.tex (revision 2215)
@@ -144,17 +144,26 @@
The previous methods are available depending on the site set. A box
will have the bbox() method since it can be retrived in constant time: a box
-is it's own bounding box (see \ref{fig:box_bbox}). A p\_array does not have this
+is it's own bounding box (see \ref{fig:box_bbox}).
+
+\begin{lstlisting}[frame=single]
+ box2d b(2,3);
+
+ // The bbox can be retrived in constant time.
+ std::cout << b.bbox() << std::endl;
+
+ // nsites can be retrieved in constant time.
+ std::cout << "nsites = " << b.nsites() << std::endl;
+\end{lstlisting}
+
+A p\_array does not have this
method since sites do not have to be adjacent. Maintaining such information, in
order to keep getting the bbox in constant time, would be time and memory
consuming. Instead of providing a method directly in p\_array, an algorithm is
-available if this information needed (see \ref{fig:parray_bbox}).
+available if this information is needed.
P\_array and box both have a nsites method since the internal structure allow a
constant time retrieval.
-\subsubsection*{Sample code}
-
-\begin{figure}[ht!]
\begin{lstlisting}[frame=single]
p_array<point2d> arr;
@@ -166,21 +175,9 @@
// it can be retrieved in constant time.
std::cout << "nsites = " << arr.nsites() << std::endl;
\end{lstlisting}
- \caption{How to retrieve information from a p\_array.\label{fig:parray_bbox}}
-\end{figure}
-\begin{figure}[ht!]
- \begin{lstlisting}[frame=single]
- box2d b(2,3);
- // The bbox can be retrived in constant time.
- std::cout << b.bbox() << std::endl;
- // nsites can be retrieved in constant time.
- std::cout << "nsites = " << b.nsites() << std::endl;
- \end{lstlisting}
- \caption{How to retrieve information from a box.\label{fig:box_bbox}}
-\end{figure}
\clearpage
\newpage
@@ -199,8 +196,8 @@
\item A site set, also called the "domain".
\end{itemize}
-Every image type is defined on a specific site type. An image2d will always
-have a domain defined by a box2d.
+An image2d will always have its bouding box defined by a box2d whatever the
+site set used to define its domain.
The Value set, which includes all the possible values a site can have, is also
called "destination" set.
@@ -208,7 +205,7 @@
border is virtual since the image can have an extended domain as well.
That one is optional, it defines sites outside the virtual border which is
useful in algorithms when working with sites being part of the domain but close
-to the borders. The virtual border can be defined thanks to a function, an
+to the borders. The extended domain can be defined thanks to a function, an
image or a site set.
//FIXME: remove this line
@@ -373,7 +370,6 @@
\chapter{Iterators}
-Every objects
Each container object in Olena like site sets or images have iterators.
There are usually three kinds:
\begin{itemize}
@@ -413,14 +409,11 @@
Example of different forward iterations:
\begin{itemize}
\item box2d: from top to bottom then from left to right.
- \item p\_array<point2d>: from left to right.
+ \item p\_array$<$point2d$>$: from left to right.
\end{itemize}
-A for\_all() macro is available to iterate over all the sites
-(Fig. \ref{fig:for_all}). \\
+A for\_all() macro is available to iterate over all the sites: \\
-
-\begin{figure}[ht!]
\begin{lstlisting}[frame=single]
box2d b(3, 2);
mln_piter(box2d) p(b);
@@ -428,16 +421,12 @@
for_all(p)
std::cout << p; //prints every site coordinates.
\end{lstlisting}
- \caption{Use of the for\_all() macro.\label{fig:for_all}}
-\end{figure}
Note that when you declare an iterator, prefer using the "mln\_*iter" macros.
They resolve the iterator type automatically from the given container type
passed as parameter. These macros can be used with any container like images or
site sets.
-(\ref{fig:iter_allcontainers}).
-\begin{figure}[ht!]
\begin{lstlisting}[frame=single]
image2d<int> ima(box2d(2, 3));
@@ -449,23 +438,28 @@
for_all(v)
std::cout << v << std::endl;
\end{lstlisting}
- \caption{mln\_*iter macros can be used with any
-containers.\label{fig:iter_allcontainers}}
-\end{figure}
\chapter{Basic operations}
//FIXME : illustrer
-\begin{itemize}
- \item level::clone(), creates a deep copy of an object. Any shared data is
-duplicated.
- \item level::fill(), fill an object with a value (fig. \ref{fig:fill_impl}).
- \item level::paste(), paste object data to another object (fig.
-\ref{fig:paste_impl})
- \item labeling::blobs(), find and label the different components of an image.
-\end{itemize}
+\section{Basic routines}
+\begin{tabular}{|l|p{8cm}|}
+\hline
+Routine name & Description \\ \hline
+level::clone() & creates a deep copy of an object. Any shared data is
+duplicated. \\ \hline
+
+level::fill() & fill an object with a value. \\ \hline
+
+level::paste() & paste object data to another object. \\ \hline
+labeling::blobs() & find and label the different components of an image. \\
+\hline
+\end{tabular} \\
+
+
+\section{Examples}
First, create an image:
\begin{lstlisting}[frame=single]
image2d<char> imga(0, 0, 20, 20);
@@ -572,7 +566,7 @@
\caption{Implementation of the paste routine.\label{fig:paste_impl}}
\end{figure}
-
+\newpage
\section{Working with parts of an image}
Sometime it may be interesting to work only on some part of the image or to
@@ -604,6 +598,21 @@
by a function\_p2v to another Value.
The following sample code illustrates this feature.
+In order to use C functions as predicate, they must have one of the following
+prototype if you work on 2D images:
+\begin{lstlisting}[frame=single]
+//function_p2b
+bool my_function_p2b(mln::point2d p);
+
+//function_p2v
+//V is the value type used in the image.
+V my_function_p2v(mln::point2d p);
+\end{lstlisting}
+Of course, you just need to change the point type if you use another image
+type. For instance, you would use point3d with 3D images.
+The returned value type V for function\_p2v depends on the image value type.
+With image2d<int>, V would be int.
+
In this section, all along the examples, the image "ima" will refer to the
following declaration:
\begin{lstlisting}[frame=single]
@@ -675,9 +684,197 @@
fill(inplace(lab.domain(2)), color::red);
\end{lstlisting}
+Here is an example using a C function:
+\begin{lstlisting}[frame=single]
+bool row_oddity(mln::point2d p)
+{
+ return p.row() % 2;
+}
+
+void my_function()
+{
+ ...
+ //Prints only sites which are on odd lines.
+ debug::println(ima | row_oddity};
+ ...
+}
+\end{lstlisting}
\chapter{Graphes and images}
+\section{Description}
+Olena enables the possibility of using graphes with images.
+Graphes can help you to handle directly parts of an image and represent their
+relationship.
+Specific data can be associated to each vertex and/or edges.
+
+//FIXME: Add more explanations?
+
+\section{Example}
+
+First, create a graph which looks like the following:
+\begin{lstlisting}[frame=single]
+ 0 1 2 3 4
+ .-----------
+ 0 | 0 2
+ 1 | \ / |
+ 2 | 1 |
+ 3 | \ |
+ 4 | 3-4
+\end{lstlisting}
+
+To do so, we need to create a site set containing the sites we are going to use
+as vertices:
+
+\begin{lstlisting}
+std::vector<point2d> sites;
+
+// Site associated to...
+sites.push_back(point2d(0,0)); // ... vertex 0.
+sites.push_back(point2d(2,2)); // ... vertex 1.
+sites.push_back(point2d(0,4)); // ... vertex 2.
+sites.push_back(point2d(4,3)); // ... vertex 3.
+sites.push_back(point2d(4,4)); // ... vertex 4.
+\end{lstlisting}
+
+Then populate the graph with vertices:
+\begin{lstlisting}
+util::graph<point2d> g;
+
+for (unsigned i = 0; i < points.size(); ++i)
+ g.add_vertex (points[i]);
+\end{lstlisting}
+
+Finally, populate the graph with edges:
+\begin{lstlisting}
+g.add_edge(0, 1); // Associated to edge 0.
+g.add_edge(1, 2); // Associated to edge 1.
+g.add_edge(1, 3); // Associated to edge 2.
+g.add_edge(3, 4); // Associated to edge 3.
+g.add_edge(4, 2); // Associated to edge 4.
+\end{lstlisting}
+
+Now, a graph structure is created but contains only site relationship
+information. We may like to map data to it. Vertices and edges are mapped to
+indexes. Indexes start from 0 and respect the insertion order.
+Therefore, the idea is to provide a function which returns the associated data
+according to the index given as parameter. Combining this function and the
+graph, which is actually a sort of site set, we get an image. Since this is an
+image, you can use it with algorithms and for\_all loops.
+
+\begin{lstlisting}[frame=single]
+
+Value my_data_fun(vertex_index_t index)
+{
+ if (index == 0)
+ return value1;
+ else if (index > 1 && < 4)
+ return value2;
+ return value3;
+}
+
+Value my_data_fun(edge_index_t index)
+{
+ if (index == 0)
+ return value1;
+ else if (index > 1 && < 4)
+ return value2;
+ return value3;
+}
+
+void my_fun()
+{
+ ...
+ // Constructs an image which associates
+ // data and edges. A site is actually an edge.
+ mln_VAR(graph_edge_ima, my_data_fun | g.edges());
+
+ //Prints each edge.
+ mln_piter p(graph_edge_ima);
+ for_all(p)
+ std::cout << p << std::endl;
+
+ // Constructs an image which associates
+ // data and vertices. A site is actually a vertex.
+ mln_VAR(graph_vertices_ima, my_data_fun2 | g.vertices());
+
+ //Prints each vertex
+ mln_piter p(graph_vertices_ima);
+ for_all(p)
+ std::Cout << p << std::endl;
+ ...
+}
+\end{lstlisting}
+
+Note that like any image in Olena, graph images share their data. Therefore,
+while constructing a graph image from a graph and a function, the graph is not
+copied and this is NOT a costly operation.
+
+Like other images, graph images also have an overloaded operator() to access the
+data associated to a vertex or an edge.
+\begin{lstlisting}
+ //Prints each edge's associated value.
+ mln_piter p(graph_edge_ima);
+ for_all(p)
+ std::cout << graph_edge_ima(p) << std::endl;
+
+ //Prints each vertex's associated value.
+ mln_piter p(graph_vertex_ima);
+ for_all(p)
+ std::cout << graph_vertex_ima(p) << std::endl;
+\end{lstlisting}
+
+Of course, creating a graph image is not necessary and you can work directly
+with the graph and container/function mapping indexes and data.
+
+\begin{lstlisting}
+// Iterator on vertices.
+mln_Viter V(g);
+
+// Prints each vertex and its associated value.
+for_all(V)
+{
+ std::cout << V << " : " << my_data_fun(V) << std::endl;
+}
+\end{lstlisting}
+
+Graphes have iterators like any other site sets and also provide
+specific iterators in order to iterate over graphes in a more intuitive way.
+
+\begin{lstlisting}
+// Iterator on vertices.
+mln_Viter V(g);
+
+// Iterator on V's edges.
+mln_Eiter n(g, V);
+
+// Prints the graph
+// List all edges for each vertex.
+for_all(V)
+{
+ std::cout << V << " : ";
+ for_all(n)
+ std::cout << n << " ";
+ std::cout << std::endl;
+}
+
+// Iterator on edges.
+mln_Eiter E(g);
+
+// Iterator on vertices adjacent to E.
+mln_Viter n(g, E);
+
+// Prints the graph
+// List all adjacent vertices for each edge.
+for_all(E)
+{
+ std::cout << E << " : ";
+ for_all(n)
+ std::cout << n << " ";
+ std::cout << std::endl;
+}
+\end{lstlisting}
+//FIXME talk about p_vertices and p_edges.
\end{document}
\ No newline at end of file
---
milena/ChangeLog | 4 ++++
milena/tests/core/complex_image.cc | 8 ++++----
2 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/milena/ChangeLog b/milena/ChangeLog
index 8138447..957f2e9 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,5 +1,9 @@
2008-09-10 Roland Levillain <roland(a)lrde.epita.fr>
+ * tests/core/complex_image.cc: Fix comment about complex windows.
+
+2008-09-10 Roland Levillain <roland(a)lrde.epita.fr>
+
* mln/core/complex_psite.hh (operator<<): Fix indentation.
2008-09-10 Roland Levillain <roland(a)lrde.epita.fr>
diff --git a/milena/tests/core/complex_image.cc b/milena/tests/core/complex_image.cc
index b704793..7c69de6 100644
--- a/milena/tests/core/complex_image.cc
+++ b/milena/tests/core/complex_image.cc
@@ -232,11 +232,11 @@ int main()
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 ;
+ there is a sequence (M1, M2, ..., Mk) of faces so that
+ - M1 is an (N-1)-face adjacent to P ;
+ - M2 is an (N-2)-face adjacent to M1 ;
- and so on;
- - Mn is an (N-1)-face adjacent to N.
+ - Mk is an (M+1)-face adjacent to Q.
- what else?
--
1.6.0.1
* mln/core/complex_iter.hh: New
* mln/core/complex.hh: Add forward declarations for class
complex_fwd_iter_ and class complex_bkd_iter_.
(mln::complex<D>::fwd_citer, mln::complex<D>::bkd_citer):
New typedefs.
* mln/core/macros.hh (mln_citer, mln_citer_)
(mln_bkd_citer, mln_bkd_citer_, mln_fwd_citer, mln_fwd_citer_):
New shortcut macros.
* tests/core/complex.cc: Exercise iterators on complexes.
---
milena/ChangeLog | 14 ++
milena/mln/core/complex.hh | 11 +-
milena/mln/core/complex_iter.hh | 449 +++++++++++++++++++++++++++++++++++++++
milena/mln/core/macros.hh | 18 ++
milena/tests/core/complex.cc | 24 ++
5 files changed, 515 insertions(+), 1 deletions(-)
create mode 100644 milena/mln/core/complex_iter.hh
diff --git a/milena/ChangeLog b/milena/ChangeLog
index 65eba6d..1778c8e 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,3 +1,17 @@
+2008-09-10 Roland Levillain <roland(a)lrde.epita.fr>
+
+ Add forward and backward iterators on complexes.
+
+ * mln/core/complex_iter.hh: New
+ * mln/core/complex.hh: Add forward declarations for class
+ complex_fwd_iter_ and class complex_bkd_iter_.
+ (mln::complex<D>::fwd_citer, mln::complex<D>::bkd_citer):
+ New typedefs.
+ * mln/core/macros.hh (mln_citer, mln_citer_)
+ (mln_bkd_citer, mln_bkd_citer_, mln_fwd_citer, mln_fwd_citer_):
+ New shortcut macros.
+ * tests/core/complex.cc: Exercise iterators on complexes.
+
2008-09-05 Ugo Jardonnet <ugo.jardonnet(a)lrde.epita.fr>
Minor fix : Translation Rotation.
diff --git a/milena/mln/core/complex.hh b/milena/mln/core/complex.hh
index 6715acd..c0c1b80 100644
--- a/milena/mln/core/complex.hh
+++ b/milena/mln/core/complex.hh
@@ -45,16 +45,20 @@
# include <mln/core/face.hh>
+# include <mln/core/complex_iter.hh>
+
namespace mln
{
- // Forward declaration.
+ // Forward declarations.
namespace internal
{
template <unsigned N, unsigned D>
struct faces_set_mixin;
}
+ template <unsigned D> class complex_fwd_iter_;
+ template <unsigned D> class complex_bkd_iter_;
/*----------.
@@ -66,6 +70,11 @@ namespace mln
class complex : private internal::faces_set_mixin<D, D>
{
public:
+ /// Forward mln::Iterator associated type.
+ typedef complex_fwd_iter_<D> fwd_citer;
+ /// Backward mln::Iterator associated type.
+ typedef complex_bkd_iter_<D> bkd_citer;
+
/// Complex construction.
/// \{
/// \brief Add a 0-face to the complex.
diff --git a/milena/mln/core/complex_iter.hh b/milena/mln/core/complex_iter.hh
new file mode 100644
index 0000000..f2701e3
--- /dev/null
+++ b/milena/mln/core/complex_iter.hh
@@ -0,0 +1,449 @@
+// 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_COMPLEX_ITER_HH
+# define MLN_CORE_COMPLEX_ITER_HH
+
+/// \file mln/core/complex_iter.hh
+/// \brief Definition of forward and backward iterators on complexes.
+
+
+# include <limits>
+
+# include <mln/core/concept/iterator.hh>
+# include <mln/core/complex.hh>
+
+
+// Factor complex_fwd_iter_<D> and complex_bkd_iter_<D>?
+
+namespace mln
+{
+
+ // Fwd decls.
+ template <unsigned D> class complex;
+
+
+ /*-----------------------.
+ | complex_fwd_iter_<D>. |
+ `-----------------------*/
+
+ /// \brief Forward iterator on all the faces of mln::complex<D>.
+ template <unsigned D>
+ class complex_fwd_iter_ : public Iterator< complex_fwd_iter_<D> >
+ {
+ typedef complex_fwd_iter_<D> self_;
+
+ public:
+ typedef any_face_handle<D> face;
+
+ /// Construction and assignment.
+ /// \{
+ /* FIXME: Keep this non-const? See a (big) comment about this in
+ milena/tests/complex_image.cc. */
+ complex_fwd_iter_(complex<D>& c);
+ complex_fwd_iter_(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_();
+ /// \}
+
+ /// Conversion and accessors.
+ /// \{
+ /// Reference to the corresponding any-face handle.
+ const face& to_face () const;
+ /// Convert the iterator into an any-face handle.
+ operator face() const;
+ /// \}
+
+ private:
+ /// The face handle this iterator is pointing to.
+ face face_;
+
+ /// \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>
+ inline
+ std::ostream&
+ operator<<(std::ostream& ostr, const complex_fwd_iter_<D>& p);
+
+
+ /*-----------------------.
+ | complex_bkd_iter_<D>. |
+ `-----------------------*/
+
+ /// \brief Backward iterator on all the faces of mln::complex<D>.
+ template <unsigned D>
+ class complex_bkd_iter_ : public Iterator< complex_bkd_iter_<D> >
+ {
+ typedef complex_bkd_iter_<D> self_;
+
+ public:
+ typedef any_face_handle<D> face;
+
+ /// Construction and assignment.
+ /// \{
+ /* FIXME: Keep this non-const? See a (big) comment about this in
+ milena/tests/complex_image.cc. */
+ complex_bkd_iter_(complex<D>& c);
+ complex_bkd_iter_(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_();
+ /// \}
+
+ /// Conversion and accessors.
+ /// \{
+ /// Reference to the corresponding any-face handle.
+ const face& to_face () const;
+ /// Convert the iterator into an any-face handle.
+ operator face() const;
+ /// \}
+
+ private:
+ /// The face handle this iterator is pointing to.
+ face face_;
+
+ /// \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>
+ inline
+ std::ostream&
+ operator<<(std::ostream& ostr, const complex_bkd_iter_<D>& p);
+
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ /*-----------------------.
+ | complex_fwd_iter_<D>. |
+ `-----------------------*/
+
+ template <unsigned D>
+ inline
+ complex_fwd_iter_<D>::complex_fwd_iter_(complex<D>& c)
+ {
+ face_.set_cplx(c);
+ // Invalidate face_.
+ invalidate();
+ }
+
+ template <unsigned D>
+ inline
+ complex_fwd_iter_<D>::complex_fwd_iter_(const complex_fwd_iter_<D>& rhs)
+ : face_(rhs.face_)
+ {
+ }
+
+ template <unsigned D>
+ inline
+ complex_fwd_iter_<D>&
+ complex_fwd_iter_<D>::operator=(const complex_fwd_iter_<D>& rhs)
+ {
+ if (&rhs == this)
+ return *this;
+ face_ = rhs.face_;
+ return *this;
+ }
+
+ template <unsigned D>
+ inline
+ bool
+ complex_fwd_iter_<D>::is_valid() const
+ {
+ return face_.is_valid();
+ }
+
+ template <unsigned D>
+ inline
+ void
+ complex_fwd_iter_<D>::invalidate()
+ {
+ face_.set_n(invalid_unsigned_());
+ face_.set_face_id(invalid_unsigned_());
+ }
+
+ template <unsigned D>
+ inline
+ void
+ complex_fwd_iter_<D>::start()
+ {
+ face_.set_n(0u);
+ face_.set_face_id(0u);
+ }
+
+ template <unsigned D>
+ inline
+ void
+ complex_fwd_iter_<D>::next_()
+ {
+ if (is_valid())
+ {
+ unsigned n = face_.n();
+ unsigned face_id = face_.face_id();
+
+ 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 if
+ // possible.
+ if (n <= D)
+ {
+ // FIXME: Same remark as above.
+ face_.set_n(n + 1);
+ face_.set_face_id(0u);
+ }
+ else
+ invalidate();
+ }
+ }
+
+ template <unsigned D>
+ inline
+ const any_face_handle<D>&
+ complex_fwd_iter_<D>::to_face() const
+ {
+ return face_;
+ }
+
+ template <unsigned D>
+ inline
+ complex_fwd_iter_<D>::operator any_face_handle<D>() const
+ {
+ mln_precondition(is_valid());
+ return face_;
+ }
+
+ template <unsigned D>
+ unsigned
+ complex_fwd_iter_<D>::invalid_unsigned_() const
+ {
+ return std::numeric_limits<unsigned>::max();
+ }
+
+
+ template <unsigned D>
+ inline
+ std::ostream&
+ operator<<(std::ostream& ostr, const complex_fwd_iter_<D>& p)
+ {
+ return ostr << "(dim = " << p.to_face().n()
+ << ", id = " << p.to_face().face_id() << ')';
+ }
+
+
+ /*-----------------------.
+ | complex_bkd_iter_<D>. |
+ `-----------------------*/
+
+ template <unsigned D>
+ inline
+ complex_bkd_iter_<D>::complex_bkd_iter_(complex<D>& c)
+ {
+ face_.set_cplx(c);
+ // Invalidate face_.
+ invalidate();
+ }
+
+ template <unsigned D>
+ inline
+ complex_bkd_iter_<D>::complex_bkd_iter_(const complex_bkd_iter_<D>& rhs)
+ : face_(rhs.face_)
+ {
+ }
+
+ template <unsigned D>
+ inline
+ complex_bkd_iter_<D>&
+ complex_bkd_iter_<D>::operator=(const complex_bkd_iter_<D>& rhs)
+ {
+ if (&rhs == this)
+ return *this;
+ face_ = rhs.face_;
+ return *this;
+ }
+
+ template <unsigned D>
+ inline
+ bool
+ complex_bkd_iter_<D>::is_valid() const
+ {
+ return face_.is_valid();
+ }
+
+ template <unsigned D>
+ inline
+ void
+ complex_bkd_iter_<D>::invalidate()
+ {
+ face_.set_n(invalid_unsigned_());
+ face_.set_face_id(invalid_unsigned_());
+ }
+
+ template <unsigned D>
+ inline
+ void
+ complex_bkd_iter_<D>::start()
+ {
+ face_.set_n(D);
+ face_.set_face_id(face_.cplx().template nfaces<D>() - 1);
+ }
+
+ template <unsigned D>
+ inline
+ void
+ complex_bkd_iter_<D>::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();
+ }
+ }
+
+ template <unsigned D>
+ inline
+ const any_face_handle<D>&
+ complex_bkd_iter_<D>::to_face() const
+ {
+ return face_;
+ }
+
+ template <unsigned D>
+ inline
+ complex_bkd_iter_<D>::operator any_face_handle<D>() const
+ {
+ mln_precondition(is_valid());
+ return face_;
+ }
+
+ template <unsigned D>
+ unsigned
+ complex_bkd_iter_<D>::invalid_unsigned_() const
+ {
+ return std::numeric_limits<unsigned>::max();
+ }
+
+
+ template <unsigned D>
+ inline
+ std::ostream&
+ operator<<(std::ostream& ostr, const complex_bkd_iter_<D>& p)
+ {
+ return ostr << "(dim = " << p.to_face().n()
+ << ", id = " << p.to_face().face_id() << ')';
+ }
+
+# endif // ! MLN_INCLUDE_ONLY
+
+} // end of mln
+
+
+#endif // ! MLN_CORE_COMPLEX_ITER_HH
diff --git a/milena/mln/core/macros.hh b/milena/mln/core/macros.hh
index 705509f..a7376ca 100644
--- a/milena/mln/core/macros.hh
+++ b/milena/mln/core/macros.hh
@@ -45,6 +45,12 @@
// b
+/// Shortcuts to access the bkd_citer type associated to T.
+/// \{
+# define mln_bkd_citer(T) typename T::bkd_citer
+# define mln_bkd_citer_(T) T::bkd_citer
+/// \}
+
/// Shortcuts to access the bkd_niter type associated to T.
/// \{
# define mln_bkd_niter(T) typename T::bkd_niter
@@ -78,6 +84,12 @@
// c
+/// Shortcuts to access the citer type associated to T.
+/// \{
+# define mln_citer(T) typename T::fwd_citer
+# define mln_citer_(T) T::fwd_citer
+/// \}
+
/// Shortcuts to access the coord type associated to T.
/// \{
# define mln_coord(T) typename T::coord
@@ -111,6 +123,12 @@
// f
+/// Shortcuts to access the fwd_citer type associated to T.
+/// \{
+# define mln_fwd_citer(T) typename T::fwd_citer
+# define mln_fwd_citer_(T) T::fwd_citer
+/// \}
+
/// Shortcuts to access the fwd_niter type associated to T.
/// \{
# define mln_fwd_niter(T) typename T::fwd_niter
diff --git a/milena/tests/core/complex.cc b/milena/tests/core/complex.cc
index ad3f991..1bacd6e 100644
--- a/milena/tests/core/complex.cc
+++ b/milena/tests/core/complex.cc
@@ -109,4 +109,28 @@ int main()
const face<1, D>& face2 = af.to_face<1>();
mln_assertion(&face1 == &face2);
+
+
+ /*------------.
+ | Iteration. |
+ `------------*/
+
+ // Iterators on a complex (not complex_image), or more precisely on
+ // the faces of a complex.
+
+ mln_fwd_citer_(complex<D>) ff(c);
+ for_all(ff)
+ std::cout << ff << std::endl;
+
+ std::cout << std::endl;
+
+ mln_bkd_citer_(complex<D>) bf(c);
+ for_all(bf)
+ std::cout << bf << std::endl;
+
+ /* FIXME: Exercice more iterators (see
+ milena/tests/core/complex_image.cc) and ticket #162
+ (https://trac.lrde.org/olena/ticket/162) */
+ // ...
+
}
--
1.5.6.5