https://svn.lrde.epita.fr/svn/oln/trunk/swilena
Index: ChangeLog
from Roland Levillain <roland(a)lrde.epita.fr>
Add a C++ image type extensible in Python.
* dynamic_image2d.i: New.
* Makefile.am: Add dynamic_image2d.i.
* point2d.i: Add row() and col() accessors.
* box2d.i: Add nrows() and ncols() accessors.
* python/dynamic-image2d-misc.py: New test.
* python/Makefile.am (AM_SWIGFLAGS): Add `-Wall'
Handle module dynamic_image2d.
(TESTS): Add dynamic-image2d-misc.py.
Makefile.am | 4
box2d.i | 16 ++
dynamic_image2d.i | 317 +++++++++++++++++++++++++++++++++++++++++
point2d.i | 9 +
python/Makefile.am | 14 +
python/dynamic-image2d-misc.py | 81 ++++++++++
6 files changed, 438 insertions(+), 3 deletions(-)
Index: dynamic_image2d.i
--- dynamic_image2d.i (revision 0)
+++ dynamic_image2d.i (revision 0)
@@ -0,0 +1,317 @@
+// -*- C++ -*-
+// 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.
+
+/// \file dynamic_image2d
+/// \brief A dynamic version of image2d, extendable in the target language.
+
+
+%module(directors="1") dynamic_image2d
+
+%import "point2d.i"
+%import "box2d.i"
+
+%import "int_u8.i"
+// FIXME: The import directive does not include the `%{ ... %}' clauses.
+%{
+#include "mln/value/int_u8.hh"
+%}
+
+%{
+# include <mln/core/concept/image.hh>
+# include <mln/core/box2d.hh>
+# include <mln/core/init.hh>
+
+# include <mln/value/set.hh>
+%}
+
+// Shortcuts macros.
+%include "mln/core/macros.hh"
+
+// Concept.
+%include "mln/core/concept/image.hh"
+
+%feature("director");
+
+%inline %{
+namespace mln
+{
+
+ // FIXME: Separate interface and implementation (and/or move the C++
+ // code into its own file).
+
+ // Fwd decl.
+ template <typename T> struct dynamic_image2d;
+
+
+ namespace trait
+ {
+
+ template <typename T>
+ struct image_< dynamic_image2d<T> >
+ : default_image_< T, dynamic_image2d<T> >
+ {
+ typedef trait::image::category::primary category;
+
+ typedef trait::image::access::random access;
+ typedef trait::image::space::two_d space;
+ typedef trait::image::size::regular size;
+ typedef trait::image::support::aligned support;
+
+ typedef trait::image::border::none border;
+ typedef trait::image::data::raw data;
+ typedef trait::image::io::read_write io;
+ typedef trait::image::speed::fast speed;
+ };
+
+ } // end of namespace mln::trait
+
+
+ /* FIXME: Inherit from internal::image_base to factor methods (see
+ below)? */
+ // \brief A semi-abstract class that serves as an entry point
+ // (called � director � by SWIG) for Python code.
+ //
+ // This class is not really abstract in the C++ sense, but it lacks
+ // methods to be a real image class.
+ template <typename T>
+ struct dynamic_image2d : Image< dynamic_image2d<T> >
+ {
+ 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.
+
+
+ /// Value associated type.
+ typedef T value;
+
+ /// Return type of read-only access.
+ typedef const T& rvalue;
+
+ /// Return type of read-write access.
+ typedef T& lvalue;
+
+
+ /// Skeleton.
+ typedef dynamic_image2d< tag::value_<T> > skeleton;
+
+
+ /// Value_Set associated type.
+ typedef mln::value::set<T> vset;
+
+
+ /// Constructor without argument.
+ dynamic_image2d();
+
+ /// Constructor with the numbers of rows and columns and the
+ /// border thickness.
+ dynamic_image2d(int nrows, int ncols);
+
+ /// Constructor with a box and the border thickness (default is
+ /// 3).
+ dynamic_image2d(const box2d& b);
+
+
+ /// Initialize an empty image.
+ virtual void init_(const box2d& b);
+
+
+ /// Test if \p p is valid.
+ virtual bool owns_(const point2d& p) const;
+
+ /// Give the set of values of the image.
+ virtual const vset& values() const;
+
+ /// Give the definition domain.
+ virtual const box2d& domain() const;
+
+ /// Read-only access to the image value located at point \p p.
+ virtual const T& operator()(const point2d& p) const;
+
+ /// Read-write access to the image value located at point \p p.
+ virtual T& operator()(const point2d& p);
+
+
+ // From internal::image_base.
+
+ /// Mesh associated type.
+ typedef mln_mesh(pset) mesh;
+ /// Coordinate associated type.
+ typedef mln_coord(point) coord;
+
+ /// Test if \p p belongs to the image domain.
+ virtual bool has(const psite& p) const;
+ /// Give a bounding box of the image domain.
+ virtual const box2d& bbox() const;
+ /// Give the number of points of the image domain.
+ virtual std::size_t npoints() const;
+ /// Test if this image has been initialized; default impl.
+ virtual bool has_data() const;
+
+ // We can set domain_ to protected, otherwise Python subclasses
+ // won't see it.
+ pset domain_;
+ };
+
+
+ template <typename T, typename J>
+ inline
+ void init_(tag::image_t, dynamic_image2d<T>& target, const J& model)
+ {
+ box2d b;
+ init_(tag::bbox, b, model);
+ target.init_(b);
+ }
+
+
+ template <typename T>
+ inline
+ dynamic_image2d<T>::dynamic_image2d()
+ {
+ }
+
+ template <typename T>
+ inline
+ dynamic_image2d<T>::dynamic_image2d(int nrows, int ncols)
+ {
+ init_(make::box2d(nrows, ncols));
+ }
+
+ template <typename T>
+ inline
+ dynamic_image2d<T>::dynamic_image2d(const box2d& b)
+ {
+ init_(b);
+ }
+
+ template <typename T>
+ inline
+ void
+ dynamic_image2d<T>::init_(const box2d& b)
+ {
+ domain_ = b;
+ }
+
+ template <typename T>
+ inline
+ bool
+ dynamic_image2d<T>::owns_(const point2d& p) const
+ {
+ mln_precondition(exact(this)->has_data());
+ return exact(this)->has(p);
+ }
+
+ template <typename T>
+ inline
+ const typename dynamic_image2d<T>::vset&
+ dynamic_image2d<T>::values() const
+ {
+ return vset::the();
+ }
+
+ template <typename T>
+ inline
+ const box2d&
+ dynamic_image2d<T>::domain() const
+ {
+ mln_precondition(this->has_data());
+ return domain_;
+ }
+
+ // Dummy implementation, provided to have swig wrap the class (swig won't
+ // wrap an abstract class).
+ template <typename T>
+ inline
+ const T&
+ dynamic_image2d<T>::operator()(const point2d& p) const
+ {
+ // Nothing.
+ assert(false);
+ }
+
+ // Dummy implementation, provided to have swig wrap the class (swig won't
+ // wrap an abstract class).
+ template <typename T>
+ inline
+ T&
+ dynamic_image2d<T>::operator()(const point2d& p)
+ {
+ // Nothing.
+ assert(false);
+ }
+
+ template <typename T>
+ inline
+ bool
+ dynamic_image2d<T>::has(const psite& p) const
+ {
+ mln_precondition(exact(this)->has_data());
+ return exact(this)->domain().has(p);
+ }
+
+ template <typename T>
+ inline
+ const box2d&
+ dynamic_image2d<T>::bbox() const
+ {
+ mln_precondition(exact(this)->has_data());
+ return exact(this)->domain().bbox();
+ }
+
+ template <typename T>
+ inline
+ std::size_t
+ dynamic_image2d<T>::npoints() const
+ {
+ mln_precondition(exact(this)->has_data());
+ return exact(this)->domain().npoints();
+ }
+
+ template <typename T>
+ inline
+ bool
+ dynamic_image2d<T>::has_data() const
+ {
+ return true;
+ }
+
+} // end of namespace mln
+%}
+
+
+%template(dynamic_image2d_int_u8) mln::dynamic_image2d< mln::value::int_u<8>
>;
+
+
+%include "fill.ixx"
+%template(fill) mln::level::fill< mln::dynamic_image2d< mln::value::int_u<8>
> >;
+
+%include "println.ixx"
+%template(println) mln::debug::println< mln::dynamic_image2d<
mln::value::int_u<8> > >;
Index: Makefile.am
--- Makefile.am (revision 2148)
+++ Makefile.am (working copy)
@@ -11,7 +11,9 @@
# Wrappers (generating actual modules).
wrappers = \
box2d.i dpoint2d.i image2d_int.i image2d_int_u8.i int_u8.i \
- int_u32.i neighb2d.i point2d.i window2d.i
+ int_u32.i neighb2d.i point2d.i window2d.i \
+ \
+ dynamic_image2d.i
EXTRA_DIST = $(meta_wrappers) $(wrappers)
Index: point2d.i
--- point2d.i (revision 2148)
+++ point2d.i (working copy)
@@ -61,4 +61,13 @@
%ignore mln::point_<mln::grid::square,int>::point_(int);
%ignore mln::point_<mln::grid::square,int>::point_(int, int, int);
+/* FIXME: Swig doesn't wrap operator[]... Provide row() and col()
+ accessors instead (we should wrap internal::mutable_coord_impl_
+ instead). */
+%extend mln::point_
+{
+ int row() const { return $self->operator[](0); }
+ int col() const { return $self->operator[](1); }
+}
+
%template(point2d) mln::point_<mln::grid::square, int>;
Index: box2d.i
--- box2d.i (revision 2148)
+++ box2d.i (working copy)
@@ -52,4 +52,20 @@
typename mln::point_<mln::grid::square, int>::coord,
typename mln::point_<mln::grid::square, int>::coord);
+%extend mln::box_
+{
+ unsigned nrows() const
+ {
+ // FIXME: This is the exact content of box_impl_<2, C, E>::nrows.
+ return mln::internal::force_exact<mln::box2d>(*$self).bbox().len(0);
+ }
+
+ unsigned ncols() const
+ {
+ // FIXME: This is the exact content of box_impl_<2, C, E>::ncols.
+ return mln::internal::force_exact<mln::box2d>(*$self).bbox().len(1);
+ }
+}
+
+
%template(box2d) mln::box_< mln::point_<mln::grid::square, int> >;
Index: python/dynamic-image2d-misc.py
--- python/dynamic-image2d-misc.py (revision 0)
+++ python/dynamic-image2d-misc.py (revision 0)
@@ -0,0 +1,81 @@
+#! /usr/bin/env python
+
+# 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.
+
+# \file python/dynamic-image2d-misc.py
+# \brief Test on C++ ``dynamic'' image2d extended in Python.
+
+
+from swilena import *
+import dynamic_image2d
+
+# Shortcuts.
+image = dynamic_image2d
+dyn_ima2d = image.dynamic_image2d_int_u8
+
+
+# A simple image extending dynamic_image2d_int_u8.
+class simple_image(dyn_ima2d):
+
+ # FIXME: Implement other ctors.
+ def __init__(self, b):
+ dyn_ima2d.__init__(self, b)
+ # FIXME: There must be a better way...
+ self.values_ = []
+ for n in range(0, b.nrows() * b.ncols()):
+ self.values_.append(int_u8())
+
+ def __call__(self, p):
+ # FIXME: This assumes the box starts at (0, 0), which is not
+ # always true!
+ off = p.row() * self.domain_.ncols() + p.col()
+ return self.values_[off]
+
+
+# FIXME: Why can't I use
+#
+# b = box2d(10, 10)
+#
+# directly?
+#
+# I think this is probably because SWIG's way to handle overloading in
+# Python depends just on the *number* of arguments, not their types --
+# and we already have a wrapped ctor with 2 arguments, the one taking
+# two mln::point2d's, so the second one (with two int's) is probably
+# hidden). Pay more attention to swig's warnings!
+b = box2d(point2d(0,0), point2d(9,9))
+ima = simple_image(b)
+
+image.fill(ima, int_u8(42))
+image.println(ima)
+
+# FIXME: Doesn't really work yet, since int_u8 is not convertible
+# to int.
+# for r in range(0, 10):
+# for c in range(0, 10):
+# print ima(point2d(r, c))
Index: python/Makefile.am
--- python/Makefile.am (revision 2148)
+++ python/Makefile.am (working copy)
@@ -10,7 +10,7 @@
AM_CPPFLAGS = -I$(PYTHONINC) -I$(top_srcdir)/milena
TOOLS_CXXFLAGS = @TOOLS_CXXFLAGS@
AM_CXXFLAGS = $(TOOLS_CXXFLAGS)
-AM_SWIGFLAGS = -c++ -python -I$(top_srcdir)/milena
+AM_SWIGFLAGS = -Wall -c++ -python -I$(top_srcdir)/milena
## We build modules, not plain libs.
AM_LDFLAGS = -avoid-version -module -shared
#### All the modules depend on libhw.
@@ -134,6 +134,16 @@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/_image2d_int_u8-wrap.Pcc@am__quote@
nodist_python_PYTHON += image2d_int_u8.py
+## dynamic_image2d.
+pyexec_LTLIBRARIES += _dynamic_image2d.la
+nodist__dynamic_image2d_la_SOURCES = dynamic_image2d-wrap.cc
+_dynamic_image2d_la_LIBADD = $(AM_LIBADD)
+CLEANFILES += $(nodist__dynamic_image2d_la_SOURCES) dynamic_image2d.py
dynamic_image2d.py[co]
+## Include the dependency files. Copied from Automake's generated
+## case for C++.
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/_dynamic_image2d-wrap.Pcc@am__quote@
+nodist_python_PYTHON += dynamic_image2d.py
+
## ---------------------------- ##
## Swilena Python Shell (sps). ##
@@ -172,5 +182,5 @@
$(MAKE) $(AM_MAKEFLAGS) $(RUN)
@mv -f $@.tmp $@
-TESTS = image2d-misc.py morpho-fun.py morpho-segm.py
+TESTS = image2d-misc.py morpho-fun.py morpho-segm.py dynamic-image2d-misc.py
EXTRA_DIST += $(TESTS)