1. added boost::optional<T> to/form Python converter

2. make background color optional (Map object)
3. exposed 'blend' method for Image object
This commit is contained in:
Artem Pavlenko 2007-08-01 09:59:23 +00:00
parent d78ccbaed0
commit d959701d5a
13 changed files with 288 additions and 114 deletions

View file

@ -38,17 +38,25 @@ PyObject* rawdata( Image32 const& im)
}
void (*save_to_file2)(std::string const&,std::string const&, mapnik::Image32 const&) = mapnik::save_to_file;
void blend (Image32 & im, unsigned x, unsigned y, Image32 const& im2, float opacity)
{
im.set_rectangle_alpha2(im2.data(),x,y,opacity);
}
void export_image()
{
using namespace boost::python;
class_<Image32>("Image","This class represents a 32 bit image.",init<int,int>())
.def("width",&Image32::width)
.def("height",&Image32::height)
.def("view",&Image32::get_view)
.add_property("background",make_function
(&Image32::getBackground,return_value_policy<copy_const_reference>()),
&Image32::setBackground, "The background color of the image.")
;
.def("width",&Image32::width)
.def("height",&Image32::height)
.def("view",&Image32::get_view)
.add_property("background",make_function
(&Image32::getBackground,return_value_policy<copy_const_reference>()),
&Image32::setBackground, "The background color of the image.")
.def("set_alpha",&Image32::set_alpha)
.def("blend",&blend)
;
def("rawdata",&rawdata); // FIXME : I dont think we need this one
def("save_to_file", save_to_file2);
}

View file

@ -29,6 +29,8 @@
#include <mapnik/layer.hpp>
#include <mapnik/map.hpp>
#include "python_optional.hpp"
using mapnik::Color;
using mapnik::coord;
using mapnik::Envelope;
@ -51,7 +53,7 @@ struct map_pickle_suite : boost::python::pickle_suite
{
l.append(m.getLayer(i));
}
return boost::python::make_tuple(m.getCurrentExtent(),m.getBackground(),l);
return boost::python::make_tuple(m.getCurrentExtent(),m.background(),l);
}
static void
@ -69,7 +71,7 @@ struct map_pickle_suite : boost::python::pickle_suite
Envelope<double> ext = extract<Envelope<double> >(state[0]);
Color bg = extract<Color>(state[1]);
m.zoomToBox(ext);
m.setBackground(bg);
m.set_background(bg);
boost::python::list l=extract<boost::python::list>(state[2]);
for (int i=0;i<len(l);++i)
{
@ -83,39 +85,40 @@ std::vector<Layer> const& (Map::*layers_const)() const = &Map::layers;
void export_map()
{
using namespace boost::python;
class_<std::vector<Layer> >("Layers")
using namespace boost::python;
python_optional<mapnik::Color> ();
class_<std::vector<Layer> >("Layers")
.def(vector_indexing_suite<std::vector<Layer> >())
;
class_<Map>("Map","The map object.",init<int,int,optional<std::string const&> >())
.add_property("width",&Map::getWidth, &Map::setWidth, "The width of the map.")
.add_property("height",&Map::getHeight, &Map::setHeight, "The height of the map.")
.add_property("srs",make_function(&Map::srs,return_value_policy<copy_const_reference>()),
&Map::set_srs,"Spatial reference in proj4 format e.g. \"+proj=latlong +datum=WGS84\"")
.add_property("background",make_function
(&Map::getBackground,return_value_policy<copy_const_reference>()),
&Map::setBackground, "The background color of the map.")
.def("envelope",make_function(&Map::getCurrentExtent,
return_value_policy<copy_const_reference>()),
"The current extent of the map")
.def("scale", &Map::scale)
.def("zoom_all",&Map::zoom_all,
"Set the geographical extent of the map "
"to the combined extents of all active layers")
.def("zoom_to_box",&Map::zoomToBox, "Set the geographical extent of the map.")
.def("pan",&Map::pan)
.def("zoom",&Map::zoom)
.def("zoom_all",&Map::zoom_all)
.def("pan_and_zoom",&Map::pan_and_zoom)
.def("append_style",&Map::insert_style)
.def("remove_style",&Map::remove_style)
.def("query_point",&Map::query_point)
.def("query_map_point",&Map::query_map_point)
.add_property("layers",make_function
(layers_nonconst,return_value_policy<reference_existing_object>()),
"Get the list of layers in this map.")
.def("find_style",&Map::find_style,return_value_policy<copy_const_reference>())
.def_pickle(map_pickle_suite())
;
;
class_<Map>("Map","The map object.",init<int,int,optional<std::string const&> >())
.add_property("width",&Map::getWidth, &Map::setWidth, "The width of the map.")
.add_property("height",&Map::getHeight, &Map::setHeight, "The height of the map.")
.add_property("srs",make_function(&Map::srs,return_value_policy<copy_const_reference>()),
&Map::set_srs,"Spatial reference in proj4 format e.g. \"+proj=latlong +datum=WGS84\"")
.add_property("background",make_function
(&Map::background,return_value_policy<copy_const_reference>()),
&Map::set_background, "The background color of the map.")
.def("envelope",make_function(&Map::getCurrentExtent,
return_value_policy<copy_const_reference>()),
"The current extent of the map")
.def("scale", &Map::scale)
.def("zoom_all",&Map::zoom_all,
"Set the geographical extent of the map "
"to the combined extents of all active layers")
.def("zoom_to_box",&Map::zoomToBox, "Set the geographical extent of the map.")
.def("pan",&Map::pan)
.def("zoom",&Map::zoom)
.def("zoom_all",&Map::zoom_all)
.def("pan_and_zoom",&Map::pan_and_zoom)
.def("append_style",&Map::insert_style)
.def("remove_style",&Map::remove_style)
.def("query_point",&Map::query_point)
.def("query_map_point",&Map::query_map_point)
.add_property("layers",make_function
(layers_nonconst,return_value_policy<reference_existing_object>()),
"Get the list of layers in this map.")
.def("find_style",&Map::find_style,return_value_policy<copy_const_reference>())
.def_pickle(map_pickle_suite())
;
}

View file

@ -140,5 +140,9 @@ BOOST_PYTHON_MODULE(_mapnik)
def("load_map",&load_map,"load Map object from XML");
def("save_map",&load_map,"sace Map object to XML");
using mapnik::symbolizer;
class_<symbolizer>("Symbolizer",no_init)
;
register_ptr_to_python<mapnik::filter_ptr>();
}

View file

@ -0,0 +1,102 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2007 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
//$Id$
#include <boost/optional/optional.hpp>
#include <boost/python.hpp>
// boost::optional<T> to/from converter from John Wiegley
template <typename T, typename TfromPy>
struct object_from_python
{
object_from_python() {
boost::python::converter::registry::push_back
(&TfromPy::convertible, &TfromPy::construct,
boost::python::type_id<T>());
}
};
template <typename T, typename TtoPy, typename TfromPy>
struct register_python_conversion
{
register_python_conversion() {
boost::python::to_python_converter<T, TtoPy>();
object_from_python<T, TfromPy>();
}
};
template <typename T>
struct python_optional : public boost::noncopyable
{
struct optional_to_python
{
static PyObject * convert(const boost::optional<T>& value)
{
return (value ? boost::python::to_python_value<T>()(*value) :
boost::python::detail::none());
}
};
struct optional_from_python
{
static void * convertible(PyObject * source)
{
using namespace boost::python::converter;
if (source == Py_None)
return source;
const registration& converters(registered<T>::converters);
if (implicit_rvalue_convertible_from_python(source,
converters)) {
rvalue_from_python_stage1_data data =
rvalue_from_python_stage1(source, converters);
return rvalue_from_python_stage2(source, data, converters);
}
return NULL;
}
static void construct(PyObject * source,
boost::python::converter::rvalue_from_python_stage1_data * data)
{
using namespace boost::python::converter;
void * const storage = ((rvalue_from_python_storage<T> *)
data)->storage.bytes;
if (data->convertible == source) // == None
new (storage) boost::optional<T>(); // A Boost uninitialized value
else
new (storage) boost::optional<T>(*static_cast<T *>(data->convertible));
data->convertible = storage;
}
};
explicit python_optional() {
register_python_conversion<boost::optional<T>,
optional_to_python, optional_from_python>();
}
};

View file

@ -46,10 +46,10 @@ namespace mapnik {
private boost::noncopyable
{
public:
typedef T1 geometry_type;
typedef T2 raster_type;
typedef std::map<std::string,value>::value_type value_type;
typedef std::map<std::string,value>::size_type size_type;
typedef T1 geometry_type;
typedef T2 raster_type;
typedef std::map<std::string,value>::value_type value_type;
typedef std::map<std::string,value>::size_type size_type;
private:
int id_;

View file

@ -34,12 +34,12 @@ namespace mapnik
template <typename FeatureT>
class MAPNIK_DECL filter
{
public:
virtual bool pass(const FeatureT& feature) const=0;
virtual filter<FeatureT>* clone() const=0;
virtual void accept(filter_visitor<FeatureT>& v) = 0;
virtual std::string to_string() const=0;
virtual ~filter() {}
public:
virtual bool pass(const FeatureT& feature) const=0;
virtual filter<FeatureT>* clone() const=0;
virtual void accept(filter_visitor<FeatureT>& v) = 0;
virtual std::string to_string() const=0;
virtual ~filter() {}
};
typedef boost::shared_ptr<filter<Feature> > filter_ptr;
@ -47,43 +47,43 @@ namespace mapnik
template <typename FeatureT>
class all_filter : public filter<FeatureT>
{
public:
bool pass (const FeatureT&) const
{
return true;
}
filter<FeatureT>* clone() const
{
return new all_filter<FeatureT>;
}
std::string to_string() const
{
return "true";
}
void accept(filter_visitor<FeatureT>&) {}
virtual ~all_filter() {}
public:
bool pass (const FeatureT&) const
{
return true;
}
filter<FeatureT>* clone() const
{
return new all_filter<FeatureT>;
}
std::string to_string() const
{
return "true";
}
void accept(filter_visitor<FeatureT>&) {}
virtual ~all_filter() {}
};
template <typename FeatureT>
class none_filter : public filter<FeatureT>
{
public:
bool pass (const FeatureT&) const
{
return false;
}
filter<FeatureT>* clone() const
{
return new none_filter<FeatureT>;
}
std::string to_string() const
{
return "false";
}
void accept(filter_visitor<FeatureT>&) {}
virtual ~none_filter() {}
template <typename FeatureT>
class none_filter : public filter<FeatureT>
{
public:
bool pass (const FeatureT&) const
{
return false;
}
filter<FeatureT>* clone() const
{
return new none_filter<FeatureT>;
}
std::string to_string() const
{
return "false";
}
void accept(filter_visitor<FeatureT>&) {}
virtual ~none_filter() {}
};
}

View file

@ -146,7 +146,26 @@ namespace mapnik
}
}
}
inline void set_alpha(float alpha) // 0...1
{
unsigned w = data_.width();
unsigned h = data_.height();
unsigned a = int(0xff * alpha) & 0xff;
for (unsigned y = 0; y < h ; ++y)
{
for (unsigned x = 0; x < w ; ++x)
{
unsigned rgba = data_(x,y);
if (rgba > 0)
{
data_(x,y) = (rgba & 0x00ffffff) | (a << 24);
}
}
}
}
inline void set_rectangle_alpha(int x0,int y0,const ImageData32& data)
{
Envelope<int> ext0(0,0,width_,height_);
@ -185,6 +204,44 @@ namespace mapnik
}
}
}
inline void set_rectangle_alpha2(ImageData32 const& data, unsigned x0, unsigned y0, float opacity)
{
Envelope<int> ext0(0,0,width_,height_);
Envelope<int> ext1(x0,y0,x0 + data.width(),y0 + data.height());
unsigned a1 = int(opacity * 255);
if (ext0.intersects(ext1))
{
Envelope<int> box = ext0.intersect(ext1);
for (int y = box.miny(); y < box.maxy(); ++y)
{
for (int x = box.minx(); x < box.maxx(); ++x)
{
unsigned rgba0 = data_(x,y);
unsigned rgba1 = data(x-x0,y-y0);
if (((rgba1 >> 24) & 255)== 0) continue;
unsigned r1 = rgba1 & 0xff;
unsigned g1 = (rgba1 >> 8 ) & 0xff;
unsigned b1 = (rgba1 >> 16) & 0xff;
unsigned a0 = (rgba0 >> 24) & 0xff;
unsigned r0 = rgba0 & 0xff ;
unsigned g0 = (rgba0 >> 8 ) & 0xff;
unsigned b0 = (rgba0 >> 16) & 0xff;
unsigned a = (a1 * 255 + (255 - a1) * a0 + 127)/255;
r0 = (r1*a1 + (((255 - a1) * a0 + 127)/255) * r0 + 127)/a;
g0 = (g1*a1 + (((255 - a1) * a0 + 127)/255) * g0 + 127)/a;
b0 = (b1*a1 + (((255 - a1) * a0 + 127)/255) * b0 + 127)/a;
data_(x,y)= (a << 24)| (b0 << 16) | (g0 << 8) | (r0) ;
}
}
}
}
};
}
#endif //GRAPHICS_HPP

View file

@ -39,7 +39,7 @@ namespace mapnik
height_(height),
pData_((width!=0 && height!=0)? static_cast<T*>(::operator new(sizeof(T)*width*height)):0)
{
if (pData_) memset(pData_,0,sizeof(T)*width_*height_);
//if (pData_) memset(pData_,0,sizeof(T)*width_*height_);
}
ImageData(const ImageData<T>& rhs)
@ -77,6 +77,7 @@ namespace mapnik
}
}
}
inline const T* getData() const
{
return pData_;

View file

@ -27,6 +27,7 @@
#include <mapnik/feature_type_style.hpp>
#include <mapnik/datasource.hpp>
#include <mapnik/layer.hpp>
#include <boost/optional/optional.hpp>
namespace mapnik
{
@ -37,11 +38,10 @@ namespace mapnik
unsigned width_;
unsigned height_;
std::string srs_;
Color background_;
boost::optional<Color> background_;
std::map<std::string,feature_type_style> styles_;
std::vector<Layer> layers_;
Envelope<double> currentExtent_;
Envelope<double> currentExtent_;
public:
typedef std::map<std::string,feature_type_style>::const_iterator const_style_iterator;
typedef std::map<std::string,feature_type_style>::iterator style_iterator;
@ -72,8 +72,8 @@ namespace mapnik
void resize(unsigned width,unsigned height);
std::string const& srs() const;
void set_srs(std::string const& srs);
void setBackground(const Color& c);
const Color& getBackground() const;
void set_background(const Color& c);
boost::optional<Color> const& background() const;
void zoom(double zoom);
void zoomToBox(const Envelope<double>& box);
void zoom_all();

View file

@ -100,7 +100,7 @@ feature_ptr postgis_featureset::next()
#ifdef MAPNIK_DEBUG
std::clog << "uknown OID = " << oid << " FIXME \n";
#endif
//boost::put(*feature,name,0);
//boost::put(*feature,name,0);
}
}
++count_;

View file

@ -97,8 +97,8 @@ namespace mapnik
detector_(Envelope<double>(-64 ,-64, m.getWidth() + 64 ,m.getHeight() + 64)),
finder_(detector_,Envelope<double>(0 ,0, m.getWidth(), m.getHeight()))
{
Color const& bg = m.getBackground();
pixmap_.setBackground(bg);
boost::optional<Color> bg = m.background();
if (bg) pixmap_.setBackground(*bg);
#ifdef MAPNIK_DEBUG
std::clog << "scale=" << m.scale() << "\n";
#endif

View file

@ -56,7 +56,7 @@ namespace mapnik
if (bgcolor)
{
Color bg = color_factory::from_string(bgcolor->c_str());
map.setBackground(bg);
map.set_background(bg);
}
std::string srs = pt.get<std::string>("Map.<xmlattr>.srs",

View file

@ -39,9 +39,8 @@ namespace mapnik
Map::Map(int width,int height, std::string const& srs)
: width_(width),
height_(height),
srs_(srs),
background_(Color(255,255,255)) {}
srs_(srs) {}
Map::Map(const Map& rhs)
: width_(rhs.width_),
height_(rhs.height_),
@ -190,17 +189,17 @@ namespace mapnik
{
srs_ = srs;
}
void Map::setBackground(const Color& c)
{
background_=c;
}
const Color& Map::getBackground() const
{
return background_;
}
boost::optional<Color> const& Map::background() const
{
return background_;
}
void Map::set_background(const Color& c)
{
background_ = c;
}
void Map::zoom(double factor)
{
coord2d center = currentExtent_.center();