https://svn.lrde.epita.fr/svn/oln/trunk/milena
Index: ChangeLog
from Thierry Geraud <thierry.geraud(a)lrde.epita.fr>
Add stack and transpose morphers.
* tests/t_image.cc: New.
* tests/stack.cc: New.
* tests/approx_median.cc: New.
* mln/core/t_image.hh: New.
* mln/value/stack.hh: New.
* tests/median.cc: Update.
* tests/README: Update.
* mln/core/internal/image_base.hh
(morpher_lvalue_): New.
* mln/core/internal/image_adaptor.hh: Use morpher_lvalue_.
(image_adaptor_): Change Image<I> into I.
* mln/core/safe.hh: Update.
* mln/core/image2d_b.hh: Remove dead code.
* mln/metal/vec.hh: Split decls and defs.
(operator<<): New.
* mln/level/median.hh (hline2d): Update.
(vline2d): New.
mln/core/image2d_b.hh | 18 ---
mln/core/internal/image_adaptor.hh | 8 -
mln/core/internal/image_base.hh | 13 ++
mln/core/safe.hh | 4
mln/core/t_image.hh | 178 ++++++++++++++++++++++++++++++++++
mln/level/median.hh | 45 ++++----
mln/metal/vec.hh | 44 +++++++-
mln/value/stack.hh | 191 +++++++++++++++++++++++++++++++++++++
tests/README | 14 ++
tests/approx_median.cc | 59 +++++++++++
tests/median.cc | 4
tests/stack.cc | 49 +++++++++
tests/t_image.cc | 52 ++++++++++
13 files changed, 626 insertions(+), 53 deletions(-)
Index: tests/median.cc
--- tests/median.cc (revision 1041)
+++ tests/median.cc (working copy)
@@ -38,7 +38,6 @@
#include <mln/value/int_u8.hh>
#include <mln/level/median.hh>
-#include <mln/level/approx/median.hh>
@@ -57,7 +56,4 @@
level::median(lena, rect, out);
io::save_pgm(out, "out.pgm");
-
-// level::approx::median(lena, rec, out);
-// io::save_pgm(out, "outa.pgm");
}
Index: tests/t_image.cc
--- tests/t_image.cc (revision 0)
+++ tests/t_image.cc (revision 0)
@@ -0,0 +1,52 @@
+// Copyright (C) 2007 EPITA Research and Development Laboratory
+//
+// 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. This exception does not however invalidate any other
+// reasons why the executable file might be covered by the GNU General
+// Public License.
+
+/*! \file tests/+t_image.cc
+ *
+ * \brief Tests on mln::t_image.
+ */
+
+#include <mln/core/image2d_b.hh>
+#include <mln/core/t_image.hh>
+
+#include <mln/debug/iota.hh>
+#include <mln/debug/println.hh>
+
+
+int main()
+{
+ using namespace mln;
+
+ typedef image2d_b<int> I;
+
+ I ima(2, 3);
+ debug::iota(ima);
+ debug::println(ima);
+
+ t_image<I> tima(ima, 0, 1);
+ debug::println(tima);
+}
Index: tests/stack.cc
--- tests/stack.cc (revision 0)
+++ tests/stack.cc (revision 0)
@@ -0,0 +1,49 @@
+// Copyright (C) 2007 EPITA Research and Development Laboratory
+//
+// 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. This exception does not however invalidate any other
+// reasons why the executable file might be covered by the GNU General
+// Public License.
+
+/*! \file tests/stack.cc
+ *
+ * \brief Tests on mln::value::stack.
+ */
+
+#include <mln/core/image2d_b.hh>
+#include <mln/value/stack.hh>
+#include <mln/debug/iota.hh>
+#include <mln/debug/println.hh>
+
+
+int main()
+{
+ using namespace mln;
+
+ typedef image2d_b<int> I;
+
+ I ima(2, 3);
+ debug::iota(ima);
+ debug::println(ima);
+ debug::println(value::stack(ima, ima));
+}
Index: tests/approx_median.cc
--- tests/approx_median.cc (revision 0)
+++ tests/approx_median.cc (revision 0)
@@ -0,0 +1,59 @@
+// Copyright (C) 2007 EPITA Research and Development Laboratory
+//
+// 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. This exception does not however invalidate any other
+// reasons why the executable file might be covered by the GNU General
+// Public License.
+
+/*! \file tests/approx_median.cc
+ *
+ * \brief Test on mln::level::approx::median.
+ */
+
+#include <mln/core/image2d_b.hh>
+#include <mln/core/win/rectangle2d.hh>
+
+#include <mln/io/load_pgm.hh>
+#include <mln/io/save_pgm.hh>
+
+#include <mln/value/int_u8.hh>
+#include <mln/level/approx/median.hh>
+
+
+
+
+int main()
+{
+ using namespace mln;
+ using value::int_u8;
+
+ win::rectangle2d rect(51, 51);
+ border::thickness = 52;
+
+ image2d_b<int_u8>
+ lena = io::load_pgm("../img/lena.pgm"),
+ out(lena.domain());
+
+ level::approx::median(lena, rect, out);
+ io::save_pgm(out, "out.pgm");
+}
Index: tests/README
--- tests/README (revision 1041)
+++ tests/README (working copy)
@@ -1,3 +1,17 @@
+
+ -*- outline -*-
+
+
+* compilation
+
g++-4.1 -ansi -pedantic -W -Wall -Wextra -Wconversion -I.. sample.cc
g++-2.95 -ansi -pedantic -W -Wall -Wconversion -ftemplate-depth-51 -I.. sample.cc
+
+
+* bench
+
+naive: 18s
+median: 1s
+approx: 0.05s
+
Index: mln/core/internal/image_adaptor.hh
--- mln/core/internal/image_adaptor.hh (revision 1041)
+++ mln/core/internal/image_adaptor.hh (working copy)
@@ -68,7 +68,7 @@
typedef mln_rvalue(I) rvalue;
/// Return type of read-write access.
- typedef mln_lvalue(I) lvalue;
+ typedef typename internal::morpher_lvalue_<I>::ret lvalue;
/// Test if this image has been initialized.
@@ -94,7 +94,7 @@
I& adaptee_;
/// Constructor from an \p adaptee image.
- image_adaptor_(Image<I>& adaptee);
+ image_adaptor_(I& adaptee);
};
// FIXME: image_const_adaptor_
@@ -148,8 +148,8 @@
}
template <typename I, typename E, typename S>
- image_adaptor_<I,E,S>::image_adaptor_(Image<I>& adaptee)
- : adaptee_(exact(adaptee))
+ image_adaptor_<I,E,S>::image_adaptor_(I& adaptee)
+ : adaptee_(adaptee)
{
}
Index: mln/core/internal/image_base.hh
--- mln/core/internal/image_base.hh (revision 1041)
+++ mln/core/internal/image_base.hh (working copy)
@@ -43,6 +43,19 @@
{
+ template <typename I>
+ struct morpher_lvalue_
+ {
+ typedef mln_lvalue(I) ret;
+ };
+
+ template <typename I>
+ struct morpher_lvalue_< const I >
+ {
+ typedef mln_rvalue(I) ret;
+ };
+
+
template <typename Is_fast, typename E>
struct select_image_concept_;
Index: mln/core/safe.hh
--- mln/core/safe.hh (revision 1041)
+++ mln/core/safe.hh (working copy)
@@ -51,6 +51,7 @@
{
typedef safe_image<mln_ch_value(I, U)> ret;
};
+
};
@@ -62,10 +63,9 @@
# ifndef MLN_INCLUDE_ONLY
-
template <typename I>
safe_image<I>::safe_image(Image<I>& ima)
- : super(ima)
+ : super(exact(ima))
{
}
Index: mln/core/t_image.hh
--- mln/core/t_image.hh (revision 0)
+++ mln/core/t_image.hh (revision 0)
@@ -0,0 +1,178 @@
+// Copyright (C) 2007 EPITA Research and Development Laboratory
+//
+// 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. This exception does not however invalidate any other
+// reasons why the executable file might be covered by the GNU General
+// Public License.
+
+#ifndef MLN_CORE_T_IMAGE_HH
+# define MLN_CORE_T_IMAGE_HH
+
+/*! \file mln/core/t_image.hh
+ *
+ * \brief Definition of the "transposed" image class mln::t_image.
+ */
+
+# include <mln/core/internal/image_adaptor.hh>
+
+
+namespace mln
+{
+
+
+ /*! \brief Transposed image class.
+ *
+ * Swap a couple of coordinates.
+ *
+ * \warning This class only works on images whose domain is a box.
+ */
+ template <typename I>
+ struct t_image : public internal::image_adaptor_< I, t_image<I> >
+ {
+
+ /// Test if a pixel value is accessible at \p p.
+ bool owns_(const mln_point(I)& p) const;
+
+ /// Give the definition domain.
+ const box_<mln_point(I)>& domain() const;
+
+ /// Read-only access of pixel value at point site \p p.
+ mln_rvalue(I) operator()(const mln_point(I)& p) const;
+
+ /// Type returned by the read-write pixel value operator.
+ typedef typename internal::morpher_lvalue_<I>::ret lvalue;
+
+ /// Read-write access of pixel value at point site \p p.
+ lvalue operator()(const mln_point(I)& p);
+
+
+ /// Change value type.
+ template <typename U>
+ struct change_value
+ {
+ typedef mln_ch_value(I, U) ret;
+ };
+
+
+ /// Constructor.
+ t_image(I& ima, unsigned c1, unsigned c2);
+
+ protected:
+
+ typedef internal::image_adaptor_< I, t_image<I> > super_;
+ const unsigned c1_, c2_; // coords to swap
+ box_<mln_point(I)> b_;
+
+ mln_point(I) transpose_(const mln_point(I)& p) const;
+ };
+
+
+ template <typename I>
+ t_image<I> swap_coords(Image<I>& ima, unsigned c1, unsigned c2);
+
+ template <typename I>
+ t_image<const I> swap_coords(const Image<I>& ima, unsigned c1, unsigned
c2);
+
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ template <typename I>
+ t_image<I> swap_coords(Image<I>& ima, unsigned c1, unsigned c2)
+ {
+ typedef mln_point(I) P;
+ mln_precondition(c1 != c2);
+ mln_precondition(c1 <= P::dim && c2 <= P::dim);
+ t_image<I> tmp(exact(ima), c1, c2);
+ return tmp;
+ }
+
+ template <typename I>
+ t_image<const I> swap_coords(const Image<I>& ima, unsigned c1, unsigned
c2)
+ {
+ typedef mln_point(I) P;
+ mln_precondition(c1 != c2);
+ mln_precondition(c1 <= P::dim && c2 <= P::dim);
+ t_image<const I> tmp(exact(ima), c1, c2);
+ return tmp;
+ }
+
+ template <typename I>
+ t_image<I>::t_image(I& ima, unsigned c1, unsigned c2)
+ : super_(ima),
+ c1_(c1),
+ c2_(c2)
+ {
+ mln_precondition(ima.has_data());
+ b_.pmin() = transpose_(this->adaptee_.bbox().pmin());
+ b_.pmax() = transpose_(this->adaptee_.bbox().pmax());
+ }
+
+ template <typename I>
+ mln_point(I)
+ t_image<I>::transpose_(const mln_point(I)& p) const
+ {
+ mln_point(I) tmp(p);
+ tmp[c1_] = p[c2_];
+ tmp[c2_] = p[c1_];
+ return tmp;
+ }
+
+ template <typename I>
+ const box_<mln_point(I)>&
+ t_image<I>::domain() const
+ {
+ mln_precondition(this->has_data());
+ return b_;
+ }
+
+ template <typename I>
+ bool
+ t_image<I>::owns_(const mln_point(I)& p) const
+ {
+ mln_precondition(this->has_data());
+ return this->adaptee_.owns_(transpose_(p));
+ }
+
+ template <typename I>
+ mln_rvalue(I)
+ t_image<I>::operator()(const mln_point(I)& p) const
+ {
+ mln_precondition(this->owns_(p));
+ return this->adaptee_(transpose_(p));
+ }
+
+ template <typename I>
+ typename internal::morpher_lvalue_<I>::ret
+ t_image<I>::operator()(const mln_point(I)& p)
+ {
+ mln_precondition(this->owns_(p));
+ return this->adaptee_(transpose_(p));
+ }
+
+# endif // ! MLN_INCLUDE_ONLY
+
+} // end of namespace mln
+
+
+#endif // ! MLN_CORE_T_IMAGE_HH
Index: mln/core/image2d_b.hh
--- mln/core/image2d_b.hh (revision 1041)
+++ mln/core/image2d_b.hh (working copy)
@@ -78,28 +78,14 @@
struct image2d_b : public internal::image_base_< box2d, image2d_b<T> >,
public internal::box_impl_< 2, int, image2d_b<T> >
{
-
- // warning: just to make effective types appear in Doxygen
+ // Warning: just to make effective types appear in Doxygen:
typedef box2d pset;
typedef point2d psite;
typedef point2d point;
typedef dpoint2d dpoint;
typedef mln_fwd_piter(box2d) fwd_piter;
typedef mln_bkd_piter(box2d) bkd_piter;
- // end of warning
-
-
-
- // FIXME:
-
-// /// Forward pixel iterator associated to image2d
-// typedef fwd_pixter2d_b<T> fwd_pixter;
-
-// /// Foward pixel iterator on dpoints assoicated to image 2d
-// typedef dpoints_pixter< image2d_b<T> > fwd_qixter;
-
-// typedef fwd_pixter pixter;
-// typedef fwd_qixter qixter;
+ // End of warning.
/// Value associated type.
Index: mln/metal/vec.hh
--- mln/metal/vec.hh (revision 1041)
+++ mln/metal/vec.hh (working copy)
@@ -28,6 +28,8 @@
#ifndef MLN_CORE_METAL_VEC_HH
# define MLN_CORE_METAL_VEC_HH
+# include <cstdarg>
+
# include <mln/core/concept/object.hh>
@@ -37,27 +39,55 @@
namespace metal
{
+ // FIXME: Doc! + Change coord into comp.
+
template <unsigned n, typename T>
struct vec : public Object< vec<n,T> >
{
enum { dim = n };
typedef T coord;
- T& operator[](unsigned i)
+ T& operator[](unsigned i);
+ T operator[](unsigned i) const;
+
+ protected:
+ T coord_[n];
+ };
+
+
+ template <unsigned n, typename T>
+ std::ostream& operator<<(std::ostream& ostr, const vec<n,T>&
v);
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ template <unsigned n, typename T>
+ T&
+ vec<n,T>::operator[](unsigned i)
{
- assert(i < n);
+ mln_precondition(i < n);
return coord_[i];
}
- T operator[](unsigned i) const
+ template <unsigned n, typename T>
+ T
+ vec<n,T>::operator[](unsigned i) const
{
- assert(i < n);
+ mln_precondition(i < n);
return coord_[i];
}
- protected:
- T coord_[n];
- };
+ template <unsigned n, typename T>
+ std::ostream& operator<<(std::ostream& ostr, const vec<n,T>&
v)
+ {
+ ostr << "[ ";
+ for (unsigned i = 0; i < n; ++i)
+ ostr << v[i] << ' ';
+ return ostr << ']';
+ }
+
+# endif // ! MLN_INCLUDE_ONLY
+
} // end of namespace mln::metal
Index: mln/level/median.hh
--- mln/level/median.hh (revision 1041)
+++ mln/level/median.hh (working copy)
@@ -38,6 +38,7 @@
# include <mln/core/window2d.hh>
# include <mln/core/win/hline2d.hh>
+# include <mln/core/t_image.hh>
# include <mln/accu/median.hh>
# include <mln/canvas/sbrowsing.hh>
@@ -156,37 +157,41 @@
}
-
-
template <typename I, typename O>
void median(const I& input, const win::hline2d& win, O& output)
{
typedef mln_coord(I) coord;
const coord
- max_row = input.max_row(),
- min_col = input.min_col(),
- max_col = input.max_col();
+ max_row = input.bbox().max_row(),
+ min_col = input.bbox().min_col(),
+ max_col = input.bbox().max_col();
const coord half = win.length() / 2;
point2d p;
coord& row = p.row();
coord& col = p.col();
+ point2d pt;
+ coord& ct = pt.col();
+
+ point2d pu;
+ coord& cu = pu.col();
+
accu::median<mln_vset(I)> med(input.values());
- for (row = input.min_row(); row <= max_row; ++row)
+ for (row = input.bbox().min_row(); row <= max_row; ++row)
{
- coord ct, cu;
+ pt.row() = pu.row() = row;
// initialization (before first point of the row)
med.init();
for (ct = min_col; ct < min_col + half; ++ct)
- med.take(input.at(row, ct));
+ med.take(input(pt));
// left columns (just take new points)
for (col = min_col; col <= min_col + half; ++col, ++ct)
{
- med.take(input.at(row, ct));
+ med.take(input(pt));
output(p) = med;
}
@@ -194,29 +199,29 @@
cu = min_col;
for (; col <= max_col - half; ++cu, ++col, ++ct)
{
- med.take(input.at(row, ct));
- med.untake(input.at(row, cu));
+ med.take(input(pt));
+ med.untake(input(pu));
output(p) = med;
}
// right columns (now just untake old points)
for (; col <= max_col; ++cu, ++col)
{
- med.untake(input.at(row, cu));
+ med.untake(input(pu));
output(p) = med;
}
}
}
- // FIXME: Use transpose.
-
-// template <typename I, typename O>
-// void median(const I& input, const win::vline2d& win, O& output)
-// {
-
-// median(, win::hline2d(win.length()), output);
-// }
+ template <typename I, typename O>
+ void median(const I& input, const win::vline2d& win, O& output)
+ {
+ t_image<O> swap_output = swap_coords(output, 0, 1);
+ impl::median(swap_coords(input, 0, 1),
+ win::hline2d(win.length()),
+ swap_output);
+ }
} // end of namespace mln::level::impl
Index: mln/value/stack.hh
--- mln/value/stack.hh (revision 0)
+++ mln/value/stack.hh (revision 0)
@@ -0,0 +1,191 @@
+// Copyright (C) 2007 EPITA Research and Development Laboratory
+//
+// 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. This exception does not however invalidate any other
+// reasons why the executable file might be covered by the GNU General
+// Public License.
+
+#ifndef MLN_VALUE_STACK_HH
+# define MLN_VALUE_STACK_HH
+
+/*! \file mln/value/stack.hh
+ *
+ * \brief Definition of an image class FIXME
+ */
+
+# include <mln/core/internal/image_base.hh>
+# include <mln/metal/vec.hh>
+# include <mln/value/set.hh>
+
+
+namespace mln
+{
+
+ namespace value
+ {
+
+ /*! \brief FIXME
+ *
+ */
+ template <unsigned n, typename I>
+ struct stack_image : public mln::internal::image_base_< mln_pset(I),
stack_image<n,I> >
+ {
+ /// Point_Site associated type.
+ typedef mln_psite(I) psite;
+
+ /// Point_Set associated type.
+ typedef mln_pset(I) pset;
+
+ /// Value associated type.
+ typedef metal::vec<n, mln_value(I)> value;
+
+ /// Return type of read-only access.
+ typedef value rvalue;
+
+ /// Return type of read-write access.
+ typedef void lvalue; // FIXME
+
+ /// Value set associated type.
+ typedef mln::value::set<value> vset;
+
+
+ /// Constructor.
+ stack_image(const metal::vec<n,I*>& imas);
+
+
+ /// Test if this image has been initialized.
+ bool has_data() const;
+
+ /// Test if a pixel value is accessible at \p p.
+ bool owns_(const psite& p) const;
+
+ /// Give the definition domain.
+ const mln_pset(I)& domain() const;
+
+ /// Read-only access of pixel value at point site \p p.
+ rvalue operator()(const psite& p) const;
+
+ /// Read-write access of pixel value at point site \p p.
+ void operator()(const psite&);
+
+ /// Give the set of values of the image.
+ const vset& values() const;
+
+ /// Change value type.
+ template <typename U>
+ struct change_value
+ {
+ typedef metal::vec<n,U> vec_n_U;
+ typedef mln_ch_value(I, vec_n_U) ret;
+ };
+
+ protected:
+ metal::vec<n,I*> imas_;
+ };
+
+
+
+ template <typename I>
+ stack_image<2,const I>
+ stack(const Image<I>& ima1, const Image<I>& ima2)
+ {
+ mln_precondition(exact(ima1).domain() = exact(ima2).domain());
+ metal::vec<2, const I*> imas;
+ imas[0] = & exact(ima1);
+ imas[1] = & exact(ima2);
+ stack_image<2, const I> tmp(imas);
+ return tmp;
+ }
+
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ template <unsigned n, typename I>
+ stack_image<n,I>::stack_image(const metal::vec<n,I*>& imas)
+ : imas_(imas)
+ {
+ for (unsigned i = 0; i < n; ++i)
+ {
+ mln_precondition(imas[i] != 0);
+ mln_precondition(imas[i]->has_data());
+ }
+ }
+
+ template <unsigned n, typename I>
+ bool stack_image<n,I>::has_data() const
+ {
+ for (unsigned i = 0; i < n; ++i)
+ mln_invariant(imas_[i]->has_data());
+ return true;
+ }
+
+ template <unsigned n, typename I>
+ bool stack_image<n,I>::owns_(const psite& p) const
+ {
+ for (unsigned i = 0; i < n; ++i)
+ if (! imas_[i]->owns_(p))
+ return false;
+ return true;
+ }
+
+ template <unsigned n, typename I>
+ const mln_pset(I)&
+ stack_image<n,I>::domain() const
+ {
+ return imas_[0]->domain();
+ }
+
+ template <unsigned n, typename I>
+ metal::vec<n, mln_value(I)>
+ stack_image<n,I>::operator()(const psite& p) const
+ {
+ mln_precondition(this->owns_(p));
+ metal::vec<n, mln_value(I)> tmp;
+ for (unsigned i = 0; i < n; ++i)
+ tmp[i] = imas_[i]->operator()(p);
+ return tmp;
+ }
+
+ template <unsigned n, typename I>
+ void
+ stack_image<n,I>::operator()(const psite&)
+ {
+ mln_invariant(0); // FIXME: Turn into a compile-time error...
+ }
+
+ template <unsigned n, typename I>
+ const mln::value::set< metal::vec<n, mln_value(I)> >&
+ stack_image<n,I>::values() const
+ {
+ return vset::the();
+ }
+
+# endif // ! MLN_INCLUDE_ONLY
+
+ } // end of namespace mln::value
+
+} // end of namespace mln
+
+
+#endif // ! MLN_VALUE_STACK_HH