diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index 7bdd9b90c..02e2d5ba9 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -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_("Image","This class represents a 32 bit image.",init()) - .def("width",&Image32::width) - .def("height",&Image32::height) - .def("view",&Image32::get_view) - .add_property("background",make_function - (&Image32::getBackground,return_value_policy()), - &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()), + &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); } diff --git a/bindings/python/mapnik_map.cpp b/bindings/python/mapnik_map.cpp index d5ad7a3e8..444cab42b 100644 --- a/bindings/python/mapnik_map.cpp +++ b/bindings/python/mapnik_map.cpp @@ -29,6 +29,8 @@ #include #include +#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 ext = extract >(state[0]); Color bg = extract(state[1]); m.zoomToBox(ext); - m.setBackground(bg); + m.set_background(bg); boost::python::list l=extract(state[2]); for (int i=0;i const& (Map::*layers_const)() const = &Map::layers; void export_map() { - using namespace boost::python; - class_ >("Layers") + using namespace boost::python; + python_optional (); + class_ >("Layers") .def(vector_indexing_suite >()) - ; - - class_("Map","The map object.",init >()) - .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()), - &Map::set_srs,"Spatial reference in proj4 format e.g. \"+proj=latlong +datum=WGS84\"") - .add_property("background",make_function - (&Map::getBackground,return_value_policy()), - &Map::setBackground, "The background color of the map.") - .def("envelope",make_function(&Map::getCurrentExtent, - return_value_policy()), - "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()), - "Get the list of layers in this map.") - .def("find_style",&Map::find_style,return_value_policy()) - .def_pickle(map_pickle_suite()) - ; + ; + + class_("Map","The map object.",init >()) + .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()), + &Map::set_srs,"Spatial reference in proj4 format e.g. \"+proj=latlong +datum=WGS84\"") + .add_property("background",make_function + (&Map::background,return_value_policy()), + &Map::set_background, "The background color of the map.") + .def("envelope",make_function(&Map::getCurrentExtent, + return_value_policy()), + "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()), + "Get the list of layers in this map.") + .def("find_style",&Map::find_style,return_value_policy()) + .def_pickle(map_pickle_suite()) + ; } diff --git a/bindings/python/mapnik_python.cpp b/bindings/python/mapnik_python.cpp index c6d1ff429..6eb30983c 100644 --- a/bindings/python/mapnik_python.cpp +++ b/bindings/python/mapnik_python.cpp @@ -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",no_init) + ; + register_ptr_to_python(); } diff --git a/bindings/python/python_optional.hpp b/bindings/python/python_optional.hpp new file mode 100644 index 000000000..54ab4ff6a --- /dev/null +++ b/bindings/python/python_optional.hpp @@ -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 +#include + +// boost::optional to/from converter from John Wiegley + +template +struct object_from_python +{ + object_from_python() { + boost::python::converter::registry::push_back + (&TfromPy::convertible, &TfromPy::construct, + boost::python::type_id()); + } +}; + +template +struct register_python_conversion +{ + register_python_conversion() { + boost::python::to_python_converter(); + object_from_python(); + } +}; + +template +struct python_optional : public boost::noncopyable +{ + struct optional_to_python + { + static PyObject * convert(const boost::optional& value) + { + return (value ? boost::python::to_python_value()(*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::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 *) + data)->storage.bytes; + + if (data->convertible == source) // == None + new (storage) boost::optional(); // A Boost uninitialized value + else + new (storage) boost::optional(*static_cast(data->convertible)); + + data->convertible = storage; + } + }; + + explicit python_optional() { + register_python_conversion, + optional_to_python, optional_from_python>(); + } +}; + diff --git a/include/mapnik/feature.hpp b/include/mapnik/feature.hpp index 09783727d..39f0f5bea 100644 --- a/include/mapnik/feature.hpp +++ b/include/mapnik/feature.hpp @@ -46,10 +46,10 @@ namespace mapnik { private boost::noncopyable { public: - typedef T1 geometry_type; - typedef T2 raster_type; - typedef std::map::value_type value_type; - typedef std::map::size_type size_type; + typedef T1 geometry_type; + typedef T2 raster_type; + typedef std::map::value_type value_type; + typedef std::map::size_type size_type; private: int id_; diff --git a/include/mapnik/filter.hpp b/include/mapnik/filter.hpp index 664572b63..8005ac2e8 100644 --- a/include/mapnik/filter.hpp +++ b/include/mapnik/filter.hpp @@ -34,12 +34,12 @@ namespace mapnik template class MAPNIK_DECL filter { - public: - virtual bool pass(const FeatureT& feature) const=0; - virtual filter* clone() const=0; - virtual void accept(filter_visitor& v) = 0; - virtual std::string to_string() const=0; - virtual ~filter() {} + public: + virtual bool pass(const FeatureT& feature) const=0; + virtual filter* clone() const=0; + virtual void accept(filter_visitor& v) = 0; + virtual std::string to_string() const=0; + virtual ~filter() {} }; typedef boost::shared_ptr > filter_ptr; @@ -47,43 +47,43 @@ namespace mapnik template class all_filter : public filter { - public: - bool pass (const FeatureT&) const - { - return true; - } - - filter* clone() const - { - return new all_filter; - } - std::string to_string() const - { - return "true"; - } - void accept(filter_visitor&) {} - virtual ~all_filter() {} + public: + bool pass (const FeatureT&) const + { + return true; + } + + filter* clone() const + { + return new all_filter; + } + std::string to_string() const + { + return "true"; + } + void accept(filter_visitor&) {} + virtual ~all_filter() {} }; - - template - class none_filter : public filter - { - public: - bool pass (const FeatureT&) const - { - return false; - } - - filter* clone() const - { - return new none_filter; - } - std::string to_string() const - { - return "false"; - } - void accept(filter_visitor&) {} - virtual ~none_filter() {} + + template + class none_filter : public filter + { + public: + bool pass (const FeatureT&) const + { + return false; + } + + filter* clone() const + { + return new none_filter; + } + std::string to_string() const + { + return "false"; + } + void accept(filter_visitor&) {} + virtual ~none_filter() {} }; } diff --git a/include/mapnik/graphics.hpp b/include/mapnik/graphics.hpp index 1430cabba..fb9fbfc80 100644 --- a/include/mapnik/graphics.hpp +++ b/include/mapnik/graphics.hpp @@ -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 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 ext0(0,0,width_,height_); + Envelope ext1(x0,y0,x0 + data.width(),y0 + data.height()); + unsigned a1 = int(opacity * 255); + + if (ext0.intersects(ext1)) + { + Envelope 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 diff --git a/include/mapnik/image_data.hpp b/include/mapnik/image_data.hpp index c1c0521b2..774360f45 100644 --- a/include/mapnik/image_data.hpp +++ b/include/mapnik/image_data.hpp @@ -39,7 +39,7 @@ namespace mapnik height_(height), pData_((width!=0 && height!=0)? static_cast(::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& rhs) @@ -77,6 +77,7 @@ namespace mapnik } } } + inline const T* getData() const { return pData_; diff --git a/include/mapnik/map.hpp b/include/mapnik/map.hpp index d74107e64..5e3888c19 100644 --- a/include/mapnik/map.hpp +++ b/include/mapnik/map.hpp @@ -27,6 +27,7 @@ #include #include #include +#include namespace mapnik { @@ -37,11 +38,10 @@ namespace mapnik unsigned width_; unsigned height_; std::string srs_; - Color background_; + boost::optional background_; std::map styles_; std::vector layers_; - Envelope currentExtent_; - + Envelope currentExtent_; public: typedef std::map::const_iterator const_style_iterator; typedef std::map::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 const& background() const; void zoom(double zoom); void zoomToBox(const Envelope& box); void zoom_all(); diff --git a/plugins/input/postgis/postgisfs.cpp b/plugins/input/postgis/postgisfs.cpp index 075a1b465..50fdf76d5 100644 --- a/plugins/input/postgis/postgisfs.cpp +++ b/plugins/input/postgis/postgisfs.cpp @@ -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_; diff --git a/src/agg_renderer.cpp b/src/agg_renderer.cpp index cc4e3f9b2..48d1f68d9 100644 --- a/src/agg_renderer.cpp +++ b/src/agg_renderer.cpp @@ -97,8 +97,8 @@ namespace mapnik detector_(Envelope(-64 ,-64, m.getWidth() + 64 ,m.getHeight() + 64)), finder_(detector_,Envelope(0 ,0, m.getWidth(), m.getHeight())) { - Color const& bg = m.getBackground(); - pixmap_.setBackground(bg); + boost::optional bg = m.background(); + if (bg) pixmap_.setBackground(*bg); #ifdef MAPNIK_DEBUG std::clog << "scale=" << m.scale() << "\n"; #endif diff --git a/src/load_map.cpp b/src/load_map.cpp index fb68e18e5..b310affaa 100644 --- a/src/load_map.cpp +++ b/src/load_map.cpp @@ -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("Map..srs", diff --git a/src/map.cpp b/src/map.cpp index 4cd0f5a52..89011dae3 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -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 const& Map::background() const + { + return background_; + } + + void Map::set_background(const Color& c) + { + background_ = c; + } + void Map::zoom(double factor) { coord2d center = currentExtent_.center();