Commit 0a619acf authored by Roland Levillain's avatar Roland Levillain
Browse files

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.


git-svn-id: https://svn.lrde.epita.fr/svn/oln/trunk@2143 4aad255d-cdde-0310-9447-f3009e2ae8c0
parent f601a073
2008-08-11 Roland Levillain <roland@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.
2008-08-11 Roland Levillain <roland@lrde.epita.fr>
Aesthetic changes w.r.t. domain names in graph-based images.
......
// 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
......@@ -76,11 +76,19 @@ namespace mln
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 @@ namespace mln
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. |
`--------------*/
......
......@@ -257,6 +257,10 @@ namespace mln
/// 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 @@ namespace mln
: 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_)
{
}
......
......@@ -85,13 +85,22 @@ namespace mln
/// 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.
......@@ -154,15 +163,6 @@ namespace mln
return cplx_->nfaces();
}
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
......@@ -175,7 +175,6 @@ namespace mln
p.face().is_valid();
}
template <unsigned D, typename P>
const complex<D>&
p_complex<D, P>::cplx() const
......@@ -184,6 +183,23 @@ namespace mln
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
......
......@@ -110,6 +110,14 @@ namespace mln
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 >
......
......@@ -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 @@ int main()
`---------------------*/
// 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 @@ int main()
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
}