2148: Add a C++ image type extensible in Python.

https://svn.lrde.epita.fr/svn/oln/trunk/swilena Index: ChangeLog from Roland Levillain <roland@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)
participants (1)
-
Roland Levillain