https://svn.lrde.epita.fr/svn/oln/trunk/milena
Index: ChangeLog
from Roland Levillain <roland(a)lrde.epita.fr>
Add a complex-base image type.
* mln/core/complex_image.hh: New.
* mln/trait/ch_value.hh
(mln::trait::impl::ch_value_<M<D, tag::psite_<P>, tag::value_<T> >,
V>):
New specialization for mln::complex_image<D, P, T>.
* mln/core/p_complex.hh (mln::p_complex<D, P>::cplx):
New mutable accessor.
* mln/core/complex_psite.hh
(mln::complex_psite<D, P>::n)
(mln::complex_psite<D, P>::face_id):
New accessors.
* mln/core/face.hh
(any_face_handle<D>::any_face_handle(const face_handle<N, D>&)):
New ctor.
(any_face_handle<D>::any_face_handle(const any_face_handle<D>&)):
Don't forget to initialize n_.
(any_face_handle<D>::any_face_handle(complex<D>&, unsigned, unsigned)):
Ensure N is compatible with D.
* tests/core/complex_image.cc: Exercise mln::complex_image.
mln/core/complex_image.hh | 301 ++++++++++++++++++++++++++++++++++++++++++++
mln/core/complex_psite.hh | 24 +++
mln/core/face.hh | 17 ++
mln/core/p_complex.hh | 42 ++++--
mln/trait/ch_value.hh | 8 +
tests/core/complex_image.cc | 91 +++++++++++--
6 files changed, 457 insertions(+), 26 deletions(-)
Index: tests/core/complex_image.cc
--- tests/core/complex_image.cc (revision 2142)
+++ tests/core/complex_image.cc (working copy)
@@ -30,12 +30,11 @@
#include <iostream>
+#include <mln/value/int_u8.hh>
#include <mln/core/point2d.hh>
-// #include <mln/core/complex_image.hh>
#include <mln/core/p_faces.hh>
-#include <mln/core/p_complex.hh>
-
+#include <mln/core/complex_image.hh>
int main()
@@ -91,9 +90,61 @@
`---------------------*/
// A pset.
- p_complex<D, point2d> pc0(c);
- // An any-face handle (on E0)
- any_face_handle<D> af(c, 1, 0);
+ p_complex<D, point2d> pc(c);
+ /* An any-face handle (on E0).
+
+ Note that AF is built on `e0_', not `e0' (e0_ is built on
+ `pc.cplx()', not `c'), since the p_complex `pc' makes a copy of
+ the complex `c', and crossed-ownership tests doesn't work. I.e.,
+
+ pc.has(e0);
+
+ is false.
+
+
+ FIXME: This might be a problem, since `pc.cplx()' and `c'
+ represent the same complex, in two different memory location (but
+ the former is controlled by PC, while the latter can be modified,
+ or even destroyed). This is a common problem for ``big'' values
+ that we don't want to manipulate by value (copy), or when we
+ don't want to use expensive, deep comparisons of pset to ensure
+ consistency. Here (and in graph-based images), we choose to
+ create a copy of the pset once, and manipulate it with a
+ tracked_ptr, to ensure both
+
+ 1. perfect control of the lifetime of the pset (here, you can
+ delete `c', and `pc' will still be valid);
+
+ 2. no pset duplication when creating new images based on it.
+
+
+ I (Roland) don't see elegant solutions here. A possiblity would
+ be to disconnect a face_handle from its complex (currently, a
+ face_handle is a bit like a Trivial Iterator from the C++
+ Standard Library), but this means relaxed dynamic checks, and
+ more obscure errors.
+
+ At least, we could have better error messages, i.e., something
+ like
+
+ mln/core/complex_image.hh 267:
+ mln::complex_image<D, P, V>::operator(): Uncompatible p_complex.
+
+ instead of
+
+ mln/core/complex_image.hh:267:
+ typename mln::complex_image<D, P, V>::lvalue
+ mln::complex_image<D, P, V>::operator()(const mln::complex_psite<D,
P>&)
+ [with unsigned int D = 2u,
+ P = mln::point_<mln::grid::square, int>,
+ V = mln::value::int_u<8u>]:
+ Assertion `this->data_->pc_.has(p)' failed.
+
+ (which looks even uglier in the original, non-indented version).
+
+ Ask Akim for his improved versions of abort() and assert(). */
+ face_handle<1, D> e0_(pc.cplx(), 0);
+ any_face_handle<D> af(e0_);
// An associated psite.
complex_psite<D, point2d> cs(af);
@@ -115,20 +166,36 @@
faces_psite<2, D, point2d> fs2(t0);
- // FIXME: Enable when complex_image is available.
-#if 0
/*----------------------.
| Complex-based image. |
`----------------------*/
+ using mln::value::int_u8;
+
// An image type built on a 2-complex with mln::int_u8 values on
// each face.
- typedef ima_t complex_image< p_complex<D, point2d>, int_u8>;
+ typedef complex_image<D, point2d, int_u8> ima_t;
- // FIXME: Create and init IMA.
- // ...
- ima_t ima(pc2);
+ // 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 n = 0; n < pc.cplx().nfaces(d); ++n)
+ values[d].push_back(d);
+ // Create and init an image based on PC.
+ ima_t ima(pc, values);
+
+ // Check the value associated to edge E0_ (through complex psite CS).
+ mln_assertion(ima(cs) == 1u);
+
+
+ /*--------------------------------.
+ | Complex-based image iterators. |
+ `--------------------------------*/
+
+ // FIXME: Enable when iterators are available.
+#if 0
mln_piter_(ima_t) p(ima.domain());
#endif
}
Index: mln/trait/ch_value.hh
--- mln/trait/ch_value.hh (revision 2142)
+++ mln/trait/ch_value.hh (working copy)
@@ -110,6 +110,14 @@
typedef mln_ch_value(I, V) ret;
};
+ // For mln::complex_image<D, P, T>.
+ template < template <unsigned, class, class> class M,
+ unsigned D, typename P, typename T, typename V >
+ struct ch_value_< M< D, tag::psite_<P>, tag::value_<T> >, V
>
+ {
+ typedef M< D, P, V > ret;
+ };
+
// For mln::neighb::image<I, N>.
template < template <class, class> class M, typename I, typename N,
typename V >
Index: mln/core/complex_image.hh
--- mln/core/complex_image.hh (revision 0)
+++ mln/core/complex_image.hh (revision 0)
@@ -0,0 +1,301 @@
+// 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. 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_COMPLEX_IMAGE_HH
+# define MLN_CORE_COMPLEX_IMAGE_HH
+
+/// \file mln/core/complex_image.hh
+/// \brief Definition of a line complex-based image.
+
+# include <vector>
+
+# include <mln/trait/images.hh>
+
+# include <mln/core/internal/image_primary.hh>
+# include <mln/metal/vec.hh>
+# include <mln/core/p_complex.hh>
+# include <mln/core/complex_psite.hh>
+# include <mln/value/set.hh>
+
+
+/* FIXME: In the current implementation, the type of values on faces
+ of different dimensions is necessarily the same (V). We should
+ allow different data types for vertices and edges. */
+
+
+namespace mln
+{
+
+ // Fwd decl.
+ template <unsigned D, typename P, typename V> struct complex_image;
+
+ namespace internal
+ {
+
+ /// \internal Data structure for \c mln::complex_image<P,V>.
+ template <unsigned D, typename P, typename V>
+ struct data_< complex_image<D, P, V> >
+ {
+ data_(const p_complex<D, P>& pc,
+ const metal::vec< D + 1, std::vector<V> >& values);
+
+ metal::vec< D + 1, std::vector<V> > values_;
+ const p_complex<D, P> pc_;
+ };
+
+ } // end of namespace mln::internal
+
+
+ namespace trait
+ {
+
+ template <unsigned D, typename P, typename V>
+ struct image_< complex_image<D, P, V> >
+ : default_image_< V, complex_image<D, P, V> >
+ {
+ typedef trait::image::category::primary category;
+
+ // FIXME: Is that right?
+ typedef trait::image::access::random access;
+ typedef typename trait::image::space_from_point<P>::ret space;
+ typedef trait::image::size::regular size;
+ typedef trait::image::support::irregular support;
+
+ typedef trait::image::border::none border;
+ typedef trait::image::data::stored data;
+ typedef trait::image::io::read_write io;
+ // FIXME: Is that right?
+ typedef trait::image::speed::fast speed;
+ };
+
+ } // end of namespace mln::trait
+
+
+ /// \brief Image based on a complex.
+ ///
+ /// Values are stored on the vertices of the graph.
+ template <unsigned D, typename P, typename V>
+ struct complex_image :
+ public internal::image_primary_< p_complex<D, P>, complex_image<D, P,
V> >
+ {
+ /// Super type.
+ typedef mln::internal::image_base_< p_complex<D, P>,
+ complex_image<D, P, V> > super_;
+
+ /// Value associated type.
+ typedef V value;
+
+ /// \brief Return type of read-write access.
+ ///
+ /// We use the associated type \c reference instead of a plain
+ /// reference on th value type (\v V), because it's the only way
+ /// to safely form a reference on the element in the case of a
+ /// std::vector<bool>.
+ typedef typename std::vector<V>::reference lvalue;
+
+ /// Return type of read-only access.
+ typedef typename std::vector<V>::const_reference rvalue;
+
+ /// Value set associated type.
+ typedef mln::value::set<value> vset;
+
+ /// Skeleton.
+ typedef complex_image< D, tag::psite_<P>, tag::value_<V> >
skeleton;
+
+ /// Constructors.
+ /// \{
+ complex_image();
+ complex_image(const p_complex<D, P>& pc);
+ complex_image(const p_complex<D, P>& pc,
+ const metal::vec< D + 1, std::vector<V> >& values);
+ /// \}
+
+ /// Initialize an empty image.
+ void init_(const p_complex<D, P>& pc,
+ const metal::vec< D + 1, std::vector<V> >& values);
+
+ /// Read-only access of pixel value at point site \p p.
+ rvalue operator()(const complex_psite<D, P>& p) const;
+
+ /// Read-write access of pixel value at point site \p p.
+ lvalue operator()(const complex_psite<D, P>& p);
+
+ /// Accessors.
+ /// \{
+ /// Return the domain of psites od the image.
+ const p_complex<D, P>& domain() const;
+ /// Return the domain of values of the image.
+ const vset& values() const;
+
+ /// Return the array of values associated to the faces.
+ const metal::vec<D + 1, std::vector<V> >& face_values() const;
+ /// \}
+ };
+
+ // Fwd decl.
+ template <unsigned D, typename P, typename V, typename W>
+ void init_(tag::image_t,
+ complex_image<D, P, V>& target,
+ const complex_image<D, P, W>& model);
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ /*-----------------.
+ | Initialization. |
+ `-----------------*/
+
+ template <unsigned D, typename P, typename V, typename W>
+ inline
+ void init_(tag::image_t,
+ complex_image<D, P, V>& target,
+ const complex_image<D, P, W>& model)
+ {
+ metal::vec<D + 1, std::vector<V> > values;
+ for (unsigned i = 0; i < D; ++i)
+ values[i].resize(model.values[i].size());
+ target.init_(model.domain(), values);
+ }
+
+ /*-------.
+ | Data. |
+ `-------*/
+
+ namespace internal
+ {
+ template <unsigned D, typename P, typename V>
+ inline
+ data_< complex_image<D, P, V> >::data_(const p_complex<D, P>&
pc,
+ const metal::vec< D + 1,
+ std::vector<V> >& values)
+ : values_(values),
+ pc_(pc)
+ {
+ // Ensure the complex is consistent with the values.
+ /* FIXME: We need additional macros in mln/core/contract.hh for
+ big blocks of preconditions like this one. */
+# ifndef NDEBUG
+ for (unsigned i = 0; i < D; ++i)
+ mln_precondition(pc.cplx().nfaces(i) == values[i].size());
+# endif // !NDEBUG
+ }
+
+ } // end of namespace mln::internal
+
+ /*---------------.
+ | Construction. |
+ `---------------*/
+
+ template <unsigned D, typename P, typename V>
+ inline
+ complex_image<D, P, V>::complex_image()
+ {
+ }
+
+ template <unsigned D, typename P, typename V>
+ inline
+ complex_image<D, P, V>::complex_image(const p_complex<D, P>& pc)
+ {
+ metal::vec<D + 1, std::vector<V> > values;
+ for (unsigned i = 0; i < D; ++i)
+ values[i].resize(pc.cplx().nfaces(i));
+ init_(pc, values);
+ }
+
+ template <unsigned D, typename P, typename V>
+ inline
+ complex_image<D, P, V>::complex_image(const p_complex<D, P>& pc,
+ const metal::vec< D + 1,
+ std::vector<V> >&
values)
+ {
+ init_(pc, values);
+ }
+
+ template <unsigned D, typename P, typename V>
+ inline
+ void
+ complex_image<D, P, V>::init_(const p_complex<D, P>& pc,
+ const metal::vec< D + 1, std::vector<V> >& values)
+ {
+ mln_precondition(! this->has_data());
+ this->data_ =
+ new internal::data_< complex_image<D, P, V> >(pc, values);
+ }
+
+ /*---------------.
+ | Manipulation. |
+ `---------------*/
+
+ template <unsigned D, typename P, typename V>
+ inline
+ typename complex_image<D, P, V>::rvalue
+ complex_image<D, P, V>::operator()(const complex_psite<D, P>& p) const
+ {
+ mln_precondition(this->data_->pc_.has(p));
+ return this->data_->values_[p.n()][p.face_id()];
+ }
+
+ template <unsigned D, typename P, typename V>
+ inline
+ typename complex_image<D, P, V>::lvalue
+ complex_image<D, P, V>::operator()(const complex_psite<D, P>& p)
+ {
+ mln_precondition(this->data_->pc_.has(p));
+ return this->data_->values_[p.n()][p.face_id()];
+ }
+
+ template <unsigned D, typename P, typename V>
+ inline
+ const mln::value::set<V> &
+ complex_image<D, P, V>::values() const
+ {
+ return vset::the();
+ }
+
+ template <unsigned D, typename P, typename V>
+ inline
+ const metal::vec< D + 1, std::vector<V> >&
+ complex_image<D, P, V>::face_values() const
+ {
+ return this->data_->val_;
+ }
+
+ template <unsigned D, typename P, typename V>
+ inline
+ const p_complex<D, P>&
+ complex_image<D, P, V>::domain() const
+ {
+ mln_precondition(this->has_data());
+ return this->data_->pc_;
+ }
+
+# endif // ! MLN_INCLUDE_ONLY
+
+} // end of namespace mln
+
+
+#endif // ! MLN_CORE_COMPLEX_IMAGE_HH
Index: mln/core/complex_psite.hh
--- mln/core/complex_psite.hh (revision 2142)
+++ mln/core/complex_psite.hh (working copy)
@@ -76,11 +76,19 @@
coord operator[](unsigned face) const;
/// \}
+ /// Accessors
+ /// \{
/// Return the face handle of this point site.
any_face_handle<D> face() const;
/// Return the complex on which this site is built.
const complex<D>& cplx() const;
+ /// Return the dimension of the face of this psite.
+ unsigned n() const;
+ /// Return the id of the face of this psite.
+ unsigned face_id() const;
+ /// \}
+
/// Is this psite valid?
bool is_valid() const;
@@ -208,6 +216,22 @@
return face_.cplx();
}
+ template <unsigned D, typename P>
+ inline
+ unsigned
+ complex_psite<D, P>::n() const
+ {
+ return face_.n();
+ }
+
+ template <unsigned D, typename P>
+ inline
+ unsigned
+ complex_psite<D, P>::face_id() const
+ {
+ return face_.face_id();
+ }
+
/*--------------.
| Comparisons. |
`--------------*/
Index: mln/core/face.hh
--- mln/core/face.hh (revision 2142)
+++ mln/core/face.hh (working copy)
@@ -257,6 +257,10 @@
/// Build a face handle from \a complex and \a face_id.
any_face_handle(complex<D>& complex, unsigned n, unsigned face_id);
+ /// Build a face handle from a face_handle.
+ template <unsigned N>
+ any_face_handle(const face_handle<N, D>& f);
+
/// Copy and assignment.
/// \{
any_face_handle(const any_face_handle<D>& rhs);
@@ -499,11 +503,22 @@
: cplx_(&c), n_(n), face_id_(face_id)
{
// Ensure N is compatible with D.
+ mln_precondition(n <= D);
+ }
+
+ template <unsigned D>
+ template <unsigned N>
+ any_face_handle<D>::any_face_handle(const face_handle<N, D>& f)
+ : cplx_(&f.cplx()), n_(N), face_id_(f.face_id())
+ {
+ // Ensure N is compatible with D.
+ metal::bool_< N <= D >::check();
+
}
template <unsigned D>
any_face_handle<D>::any_face_handle(const any_face_handle<D>& rhs)
- : cplx_(rhs.cplx_), face_id_(rhs.face_id_)
+ : cplx_(rhs.cplx_), n_(rhs.n_), face_id_(rhs.face_id_)
{
}
Index: mln/core/p_complex.hh
--- mln/core/p_complex.hh (revision 2142)
+++ mln/core/p_complex.hh (working copy)
@@ -85,13 +85,22 @@
/// Return The number of faces in the complex.
std::size_t nfaces() const;
- /// Give the exact bounding box.
- const box_<P>& bbox() const;
+ // FIXME: Add nfaces(unsigned) routines?
bool has(const psite& p) const;
- /// Return the complex associated to the p_complex domain.
+ /// Accessors.
+ /// \{
+ /// Return the complex associated to the p_complex domain (const
+ /// version)
const complex<D>& cplx() const;
+ /// Return the complex associated to the p_complex domain (mutable
+ /// version).
+ complex<D>& cplx();
+
+ /// Give the exact bounding box.
+ const box_<P>& bbox() const;
+ /// \}
private:
/// The complex on which this pset is built.
@@ -156,15 +165,6 @@
template <unsigned D, typename P>
inline
- const box_<P>&
- p_complex<D, P>::bbox() const
- {
- // FIXME: Dummy value.
- return bb_;
- }
-
- template <unsigned D, typename P>
- inline
bool
p_complex<D, P>::has(const psite& p) const
{
@@ -175,7 +175,6 @@
p.face().is_valid();
}
-
template <unsigned D, typename P>
const complex<D>&
p_complex<D, P>::cplx() const
@@ -184,6 +183,23 @@
return *cplx_.ptr_;
}
+ template <unsigned D, typename P>
+ complex<D>&
+ p_complex<D, P>::cplx()
+ {
+ mln_precondition(cplx_);
+ return *cplx_.ptr_;
+ }
+
+ template <unsigned D, typename P>
+ inline
+ const box_<P>&
+ p_complex<D, P>::bbox() const
+ {
+ // FIXME: Dummy value.
+ return bb_;
+ }
+
template <unsigned D, typename P>
bool