Merge branch 'master' of github.com:mapnik/mapnik

This commit is contained in:
kunitoki 2011-12-05 11:12:02 +01:00
commit d6cbdd3412
33 changed files with 1078 additions and 304 deletions

7
.gitignore vendored
View file

@ -35,3 +35,10 @@ tests/cpp_tests/svg_renderer_tests/path_element_test
tests/cpp_tests/svg_renderer_tests/path_element_test_case_1.svg tests/cpp_tests/svg_renderer_tests/path_element_test_case_1.svg
tests/cpp_tests/svg_renderer_tests/root_element_test tests/cpp_tests/svg_renderer_tests/root_element_test
tests/data/sqlite/*index tests/data/sqlite/*index
demo/c++/cairo-demo.pdf
demo/c++/cairo-demo.png
demo/c++/cairo-demo256.png
demo/c++/demo.jpg
demo/c++/demo.png
demo/c++/demo256.png

View file

@ -34,7 +34,6 @@
#include <mapnik/datasource.hpp> #include <mapnik/datasource.hpp>
#include <mapnik/wkb.hpp> #include <mapnik/wkb.hpp>
#include <mapnik/wkt/wkt_factory.hpp> #include <mapnik/wkt/wkt_factory.hpp>
#include "mapnik_value_converter.hpp"
mapnik::geometry_type & (mapnik::Feature::*get_geom1)(unsigned) = &mapnik::Feature::get_geometry; mapnik::geometry_type & (mapnik::Feature::*get_geom1)(unsigned) = &mapnik::Feature::get_geometry;
@ -95,9 +94,11 @@ namespace boost { namespace python {
template <class Class> template <class Class>
static void static void
extension_def(Class& /*cl*/) extension_def(Class& cl)
{ {
cl
.def("get", &get)
;
} }
static data_type& static data_type&
@ -106,12 +107,25 @@ namespace boost { namespace python {
typename Container::iterator i = container.props().find(i_); typename Container::iterator i = container.props().find(i_);
if (i == container.end()) if (i == container.end())
{ {
PyErr_SetString(PyExc_KeyError, "Invalid key"); PyErr_SetString(PyExc_KeyError, i_.c_str());
throw_error_already_set(); throw_error_already_set();
} }
// will be auto-converted to proper python type by `mapnik_value_to_python`
return i->second; return i->second;
} }
static data_type
get(Container& container, index_type i_)
{
typename Container::iterator i = container.props().find(i_);
if (i != container.end())
{
// will be auto-converted to proper python type by `mapnik_value_to_python`
return i->second;
}
return mapnik::value_null();
}
static void static void
set_item(Container& container, index_type i, data_type const& v) set_item(Container& container, index_type i, data_type const& v)
{ {

View file

@ -31,6 +31,7 @@
#include <mapnik/geometry.hpp> #include <mapnik/geometry.hpp>
#include <mapnik/wkt/wkt_factory.hpp> #include <mapnik/wkt/wkt_factory.hpp>
#include <mapnik/wkb.hpp> #include <mapnik/wkb.hpp>
#include <mapnik/util/geometry_to_wkb.hpp>
namespace { namespace {
@ -47,19 +48,47 @@ geometry_type const& getitem_impl(path_type & p, int key)
throw boost::python::error_already_set(); throw boost::python::error_already_set();
} }
void from_wkt_impl(path_type& p, std::string const& wkt) void add_wkt_impl(path_type& p, std::string const& wkt)
{ {
bool result = mapnik::from_wkt(wkt , p); bool result = mapnik::from_wkt(wkt , p);
if (!result) throw std::runtime_error("Failed to parse WKT"); if (!result) throw std::runtime_error("Failed to parse WKT");
} }
void from_wkb_impl(path_type& p, std::string const& wkb) void add_wkb_impl(path_type& p, std::string const& wkb)
{ {
mapnik::geometry_utils::from_wkb(p, wkb.c_str(), wkb.size(), true); mapnik::geometry_utils::from_wkb(p, wkb.c_str(), wkb.size(), true);
} }
boost::shared_ptr<path_type> from_wkt_impl(std::string const& wkt)
{
boost::shared_ptr<path_type> paths = boost::make_shared<path_type>();
bool result = mapnik::from_wkt(wkt, *paths);
if (!result) throw std::runtime_error("Failed to parse WKT");
return paths;
} }
boost::shared_ptr<path_type> from_wkb_impl(std::string const& wkb)
{
boost::shared_ptr<path_type> paths = boost::make_shared<path_type>();
mapnik::geometry_utils::from_wkb(*paths, wkb.c_str(), wkb.size(), true);
return paths;
}
}
PyObject* to_wkb( geometry_type const& geom)
{
mapnik::util::wkb_buffer_ptr wkb = mapnik::util::to_wkb(geom,mapnik::util::wkbXDR);
return
#if PY_VERSION_HEX >= 0x03000000
::PyBytes_FromStringAndSize
#else
::PyString_FromStringAndSize
#endif
((const char*)wkb->buffer(),wkb->size());
}
void export_geometry() void export_geometry()
{ {
using namespace boost::python; using namespace boost::python;
@ -78,14 +107,19 @@ void export_geometry()
.def("envelope",&geometry_type::envelope) .def("envelope",&geometry_type::envelope)
// .def("__str__",&geometry_type::to_string) // .def("__str__",&geometry_type::to_string)
.def("type",&geometry_type::type) .def("type",&geometry_type::type)
.def("to_wkb",&to_wkb)
// TODO add other geometry_type methods // TODO add other geometry_type methods
; ;
class_<path_type,boost::noncopyable>("Path") class_<path_type, boost::shared_ptr<path_type>, boost::noncopyable>("Path")
.def("__getitem__", getitem_impl,return_value_policy<reference_existing_object>()) .def("__getitem__", getitem_impl,return_value_policy<reference_existing_object>())
.def("__len__", &path_type::size) .def("__len__", &path_type::size)
.def("add_wkt",add_wkt_impl)
.def("add_wkb",add_wkb_impl)
.def("from_wkt",from_wkt_impl) .def("from_wkt",from_wkt_impl)
.def("from_wkb",from_wkb_impl) .def("from_wkb",from_wkb_impl)
.staticmethod("from_wkt")
.staticmethod("from_wkb")
; ;
} }

View file

@ -119,6 +119,8 @@ struct map_pickle_suite : boost::python::pickle_suite
std::vector<layer>& (Map::*layers_nonconst)() = &Map::layers; std::vector<layer>& (Map::*layers_nonconst)() = &Map::layers;
std::vector<layer> const& (Map::*layers_const)() const = &Map::layers; std::vector<layer> const& (Map::*layers_const)() const = &Map::layers;
mapnik::parameters& (Map::*attr_nonconst)() = &Map::get_extra_attributes;
mapnik::parameters& (Map::*params_nonconst)() = &Map::get_extra_parameters;
mapnik::feature_type_style find_style (mapnik::Map const& m, std::string const& name) mapnik::feature_type_style find_style (mapnik::Map const& m, std::string const& name)
{ {
@ -173,6 +175,7 @@ mapnik::featureset_ptr query_map_point(mapnik::Map const& m, int index, double x
return m.query_map_point(idx, x, y); return m.query_map_point(idx, x, y);
} }
void export_map() void export_map()
{ {
using namespace boost::python; using namespace boost::python;
@ -449,7 +452,8 @@ void export_map()
"about the hit areas rendered on the map.\n" "about the hit areas rendered on the map.\n"
) )
.def("extra_attributes",&Map::get_extra_attributes,return_value_policy<copy_const_reference>(),"TODO") .add_property("extra_attributes",make_function(attr_nonconst,return_value_policy<reference_existing_object>()),"TODO")
.add_property("params",make_function(params_nonconst,return_value_policy<reference_existing_object>()),"TODO")
.add_property("aspect_fix_mode", .add_property("aspect_fix_mode",
&Map::get_aspect_fix_mode, &Map::get_aspect_fix_mode,

View file

@ -48,6 +48,6 @@ void export_palette ()
( arg("palette"), arg("type")), ( arg("palette"), arg("type")),
"Creates a new color palette from a file\n" "Creates a new color palette from a file\n"
)*/ )*/
.def( "__init__", boost::python::make_constructor( &make_palette)) .def( "__init__", boost::python::make_constructor(make_palette))
; ;
} }

View file

@ -2,7 +2,7 @@
* *
* This file is part of Mapnik (c++ mapping toolkit) * This file is part of Mapnik (c++ mapping toolkit)
* *
* Copyright (C) 2006 Artem Pavlenko, Jean-Francois Doyon * Copyright (C) 2011 Artem Pavlenko
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -19,50 +19,26 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
* *
*****************************************************************************/ *****************************************************************************/
//$Id: mapnik_parameters.cpp 17 2005-03-08 23:58:43Z pavlenko $
// boost // boost
#include <boost/python.hpp> #include <boost/python.hpp>
#include <boost/make_shared.hpp>
// mapnik // mapnik
#include <mapnik/params.hpp> #include <mapnik/params.hpp>
#include <mapnik/unicode.hpp>
#include <mapnik/value.hpp>
using mapnik::parameter; using mapnik::parameter;
using mapnik::parameters; using mapnik::parameters;
struct pickle_value : public boost::static_visitor<>
{
public:
pickle_value( boost::python::list vals):
vals_(vals) {}
void operator () ( int val )
{
vals_.append(val);
}
void operator () ( double val )
{
vals_.append(val);
}
void operator () ( std::string val )
{
vals_.append(val);
}
private:
boost::python::list vals_;
};
struct parameter_pickle_suite : boost::python::pickle_suite struct parameter_pickle_suite : boost::python::pickle_suite
{ {
static boost::python::tuple static boost::python::tuple
getinitargs(const parameter& p) getinitargs(const parameter& p)
{ {
using namespace boost::python; using namespace boost::python;
return boost::python::make_tuple(p.first,boost::get<std::string>(p.second)); return boost::python::make_tuple(p.first,p.second);
} }
}; };
@ -76,11 +52,7 @@ struct parameters_pickle_suite : boost::python::pickle_suite
parameters::const_iterator pos=p.begin(); parameters::const_iterator pos=p.begin();
while(pos!=p.end()) while(pos!=p.end())
{ {
boost::python::list vals; d[pos->first] = pos->second;
pickle_value serializer( vals );
mapnik::value_holder val = pos->second;
boost::apply_visitor( serializer, val );
d[pos->first] = vals[0];
++pos; ++pos;
} }
return boost::python::make_tuple(d); return boost::python::make_tuple(d);
@ -107,7 +79,9 @@ struct parameters_pickle_suite : boost::python::pickle_suite
extract<std::string> ex0(obj); extract<std::string> ex0(obj);
extract<int> ex1(obj); extract<int> ex1(obj);
extract<double> ex2(obj); extract<double> ex2(obj);
extract<UnicodeString> ex3(obj);
// TODO - this is never hit - we need proper python string -> std::string to get invoked here
if (ex0.check()) if (ex0.check())
{ {
p[key] = ex0(); p[key] = ex0();
@ -120,72 +94,131 @@ struct parameters_pickle_suite : boost::python::pickle_suite
{ {
p[key] = ex2(); p[key] = ex2();
} }
else if (ex3.check())
/* {
extract_value serializer( p, key ); std::string buffer;
mapnik::value_holder val = extract<mapnik::value_holder>(d[key]); mapnik::to_utf8(ex3(),buffer);
boost::apply_visitor( serializer, val ); p[key] = buffer;
*/ }
else
{
std::clog << "could not unpickle key: " << key << "\n";
}
} }
} }
}; };
boost::python::dict dict_params(parameters& p)
mapnik::value_holder get_params_by_key1(mapnik::parameters const& p, std::string const& key)
{ {
boost::python::dict d; parameters::const_iterator pos = p.find(key);
parameters::const_iterator pos=p.begin(); if (pos != p.end())
while(pos!=p.end())
{ {
boost::python::list vals; // will be auto-converted to proper python type by `mapnik_params_to_python`
pickle_value serializer( vals ); return pos->second;
mapnik::value_holder val = pos->second;
boost::apply_visitor( serializer, val );
d[pos->first] = vals[0];
++pos;
} }
return d; return mapnik::value_null();
} }
boost::python::list list_params(parameters& p) mapnik::value_holder get_params_by_key2(mapnik::parameters const& p, std::string const& key)
{ {
boost::python::list l; parameters::const_iterator pos = p.find(key);
parameters::const_iterator pos=p.begin(); if (pos == p.end())
while(pos!=p.end())
{ {
boost::python::list vals; PyErr_SetString(PyExc_KeyError, key.c_str());
pickle_value serializer( vals ); boost::python::throw_error_already_set();
mapnik::value_holder val = pos->second;
boost::apply_visitor( serializer, val );
l.append(boost::python::make_tuple(pos->first,vals[0]));
++pos;
} }
return l; // will be auto-converted to proper python type by `mapnik_params_to_python`
return pos->second;
} }
boost::python::dict dict_param(parameter& p) mapnik::parameter get_params_by_index(mapnik::parameters const& p, int index)
{ {
boost::python::dict d; if (index < 0 || index > p.size())
d[p.first] = boost::get<std::string>(p.second); {
return d; PyErr_SetString(PyExc_IndexError, "Index is out of range");
throw boost::python::error_already_set();
} }
boost::python::tuple tuple_param(parameter& p) parameters::const_iterator itr = p.begin();
parameters::const_iterator end = p.end();
unsigned idx = 0;
while (itr != p.end())
{ {
return boost::python::make_tuple(p.first,boost::get<std::string>(p.second)); if (idx == index)
{
return *itr;
} }
++idx;
++itr;
}
PyErr_SetString(PyExc_IndexError, "Index is out of range");
throw boost::python::error_already_set();
}
void add_parameter(mapnik::parameters & p, mapnik::parameter const& param)
{
p[param.first] = param.second;
}
mapnik::value_holder get_param(mapnik::parameter const& p, int index)
{
if (index == 0)
{
return p.first;
}
else if (index == 1)
{
return p.second;
}
else
{
PyErr_SetString(PyExc_IndexError, "Index is out of range");
throw boost::python::error_already_set();
}
}
boost::shared_ptr<mapnik::parameter> create_parameter_from_string(std::string const& key, std::string const& value)
{
return boost::make_shared<mapnik::parameter>(key,mapnik::value_holder(value));
}
boost::shared_ptr<mapnik::parameter> create_parameter_from_int(std::string const& key, int value)
{
return boost::make_shared<mapnik::parameter>(key,mapnik::value_holder(value));
}
boost::shared_ptr<mapnik::parameter> create_parameter_from_float(std::string const& key, double value)
{
return boost::make_shared<mapnik::parameter>(key,mapnik::value_holder(value));
}
void export_parameters() void export_parameters()
{ {
using namespace boost::python; using namespace boost::python;
class_<parameter>("Parameter",init<std::string,std::string>()) class_<parameter,boost::shared_ptr<parameter> >("Parameter",no_init)
.def("__init__", make_constructor(create_parameter_from_string),
"Create a mapnik.Parameter from a pair of values, the first being a string\n"
"and the second being either a string, and integer, or a float")
.def("__init__", make_constructor(create_parameter_from_int),
"Create a mapnik.Parameter from a pair of values, the first being a string\n"
"and the second being either a string, and integer, or a float")
.def("__init__", make_constructor(create_parameter_from_float),
"Create a mapnik.Parameter from a pair of values, the first being a string\n"
"and the second being either a string, and integer, or a float")
.def_pickle(parameter_pickle_suite()) .def_pickle(parameter_pickle_suite())
.def("as_dict",dict_param) .def("__getitem__",get_param)
.def("as_tuple",tuple_param)
; ;
class_<parameters>("Parameters",init<>()) class_<parameters>("Parameters",init<>())
.def_pickle(parameters_pickle_suite()) .def_pickle(parameters_pickle_suite())
.def("as_dict",dict_params) .def("get",get_params_by_key1)
.def("as_list",list_params) .def("__getitem__",get_params_by_key2)
.def("__getitem__",get_params_by_index)
.def("__len__",&parameters::size)
.def("append",add_parameter)
.def("iteritems",iterator<parameters>())
; ;
} }

View file

@ -83,24 +83,13 @@ void export_label_collision_detector();
#include <mapnik/value_error.hpp> #include <mapnik/value_error.hpp>
#include <mapnik/save_map.hpp> #include <mapnik/save_map.hpp>
#include "python_grid_utils.hpp" #include "python_grid_utils.hpp"
#include "mapnik_value_converter.hpp"
#if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO) #if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO)
#include <pycairo.h> #include <pycairo.h>
static Pycairo_CAPI_t *Pycairo_CAPI; static Pycairo_CAPI_t *Pycairo_CAPI;
#endif #endif
namespace boost { namespace python {
struct mapnik_value_to_python
{
static PyObject* convert(mapnik::value const& v)
{
return boost::apply_visitor(value_converter(),v.base());
}
};
}}
void render(const mapnik::Map& map, void render(const mapnik::Map& map,
mapnik::image_32& image, mapnik::image_32& image,
double scale_factor = 1.0, double scale_factor = 1.0,
@ -651,5 +640,6 @@ BOOST_PYTHON_MODULE(_mapnik)
register_ptr_to_python<mapnik::expression_ptr>(); register_ptr_to_python<mapnik::expression_ptr>();
register_ptr_to_python<mapnik::path_expression_ptr>(); register_ptr_to_python<mapnik::path_expression_ptr>();
to_python_converter<mapnik::value_holder,mapnik_param_to_python>();
to_python_converter<mapnik::value,mapnik_value_to_python>(); to_python_converter<mapnik::value,mapnik_value_to_python>();
} }

View file

@ -27,6 +27,7 @@
#include <boost/implicit_cast.hpp> #include <boost/implicit_cast.hpp>
namespace boost { namespace python { namespace boost { namespace python {
struct value_converter : public boost::static_visitor<PyObject*> struct value_converter : public boost::static_visitor<PyObject*>
{ {
PyObject * operator() (int val) const PyObject * operator() (int val) const
@ -48,6 +49,13 @@ namespace boost { namespace python {
return ::PyBool_FromLong(val); return ::PyBool_FromLong(val);
} }
PyObject * operator() (std::string const& s) const
{
PyObject *obj = Py_None;
obj = ::PyUnicode_DecodeUTF8(s.c_str(),implicit_cast<ssize_t>(s.length()),0);
return obj;
}
PyObject * operator() (UnicodeString const& s) const PyObject * operator() (UnicodeString const& s) const
{ {
std::string buffer; std::string buffer;
@ -63,6 +71,25 @@ namespace boost { namespace python {
} }
}; };
struct mapnik_value_to_python
{
static PyObject* convert(mapnik::value const& v)
{
return boost::apply_visitor(value_converter(),v.base());
}
};
struct mapnik_param_to_python
{
static PyObject* convert(mapnik::value_holder const& v)
{
return boost::apply_visitor(value_converter(),v);
}
};
} }
} }

View file

@ -253,10 +253,13 @@ int main ( int argc , char** argv)
save_to_file<image_data_32>(buf.data(),"demo.jpg","jpeg"); save_to_file<image_data_32>(buf.data(),"demo.jpg","jpeg");
save_to_file<image_data_32>(buf.data(),"demo.png","png"); save_to_file<image_data_32>(buf.data(),"demo.png","png");
save_to_file<image_data_32>(buf.data(),"demo256.png","png256"); save_to_file<image_data_32>(buf.data(),"demo256.png","png256");
save_to_file<image_data_32>(buf.data(),"demo.tif","tiff");
std::cout << "Three maps have been rendered using AGG in the current directory:\n" std::cout << "Three maps have been rendered using AGG in the current directory:\n"
"- demo.jpg\n" "- demo.jpg\n"
"- demo.png\n" "- demo.png\n"
"- demo256.png\n" "- demo256.png\n"
"- demo.tif\n"
"Have a look!\n"; "Have a look!\n";
#if defined(HAVE_CAIRO) #if defined(HAVE_CAIRO)

View file

@ -322,7 +322,7 @@ m.layers.append(popplaces_lyr)
# Set the initial extent of the map in 'master' spherical Mercator projection # Set the initial extent of the map in 'master' spherical Mercator projection
m.zoom_to_box(mapnik.Box2d(-8024477.28459,5445190.38849,-7381388.20071,5662941.44855)) m.zoom_to_box(mapnik.Box2d(-8024477.28459,5445190.38849,-7381388.20071,5662941.44855))
# Render two maps, two PNGs, one JPEG. # Render map
im = mapnik.Image(m.width,m.height) im = mapnik.Image(m.width,m.height)
mapnik.render(m, im) mapnik.render(m, im)
@ -347,6 +347,9 @@ images_.append('demo_high.jpg')
im.save('demo_low.jpg', 'jpeg50') im.save('demo_low.jpg', 'jpeg50')
images_.append('demo_low.jpg') images_.append('demo_low.jpg')
im.save('demo.tif', 'tiff')
images_.append('demo.tif')
# Render cairo examples # Render cairo examples
if HAS_PYCAIRO_MODULE and mapnik.has_pycairo(): if HAS_PYCAIRO_MODULE and mapnik.has_pycairo():

View file

@ -84,6 +84,7 @@ private:
boost::optional<box2d<double> > maximum_extent_; boost::optional<box2d<double> > maximum_extent_;
std::string base_path_; std::string base_path_;
parameters extra_attr_; parameters extra_attr_;
parameters extra_params_;
public: public:
@ -444,14 +445,34 @@ public:
std::string get_metawriter_property(std::string name) const; std::string get_metawriter_property(std::string name) const;
/*! /*!
* @brief Get extra properties that can be carried on the Map * @brief Get extra valid attributes of the Map that are not true members
*/ */
parameters const& get_extra_attributes() const; parameters const& get_extra_attributes() const;
/*! /*!
* @brief Set extra properties that can be carried on the Map * @brief Get non-const extra valid attributes of the Map that are not true members
*/ */
void set_extra_attributes(parameters& params); parameters& get_extra_attributes();
/*!
* @brief Set extra attributes of the Map
*/
void set_extra_attributes(parameters& attr);
/*!
* @brief Get extra, arbitrary Parameters attached to the Map
*/
parameters const& get_extra_parameters() const;
/*!
* @brief Get non-const extra, arbitrary Parameters attached to the Map
*/
parameters& get_extra_parameters();
/*!
* @brief Set extra, arbitary Parameters of the Map
*/
void set_extra_parameters(parameters& params);
private: private:
void fixAspectRatio(); void fixAspectRatio();

View file

@ -23,19 +23,22 @@
#ifndef MAPNIK_PARAMS_HPP #ifndef MAPNIK_PARAMS_HPP
#define MAPNIK_PARAMS_HPP #define MAPNIK_PARAMS_HPP
// mapnik // boost
#include <boost/variant.hpp> #include <boost/variant.hpp>
#include <boost/optional.hpp> #include <boost/optional.hpp>
#include <boost/none.hpp> #include <boost/none.hpp>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
// mapnik
#include <mapnik/value.hpp>
// stl // stl
#include <string> #include <string>
#include <map> #include <map>
namespace mapnik namespace mapnik
{ {
typedef boost::variant<int,double,std::string> value_holder; typedef boost::variant<value_null,int,double,std::string> value_holder;
typedef std::pair<const std::string, value_holder> parameter; typedef std::pair<const std::string, value_holder> parameter;
typedef std::map<const std::string, value_holder> param_map; typedef std::map<const std::string, value_holder> param_map;

View file

@ -0,0 +1,235 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2011 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$
#ifndef MAPNIK_GEOMETRY_TO_WKB_HPP
#define MAPNIK_GEOMETRY_TO_WKB_HPP
// mapnik
#include <mapnik/global.hpp>
#include <mapnik/geometry.hpp>
// boost
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/interprocess/streams/bufferstream.hpp>
#include <boost/foreach.hpp>
// stl
#include <vector>
#include <cstdio>
namespace mapnik { namespace util {
std::string to_hex(const char* blob, unsigned size)
{
std::string buf;
buf.reserve(size*2);
std::ostringstream s(buf);
s.seekp(0);
char hex[3];
std::memset(hex,0,3);
for ( unsigned pos=0; pos < size; ++pos)
{
std::sprintf (hex, "%02x", int(blob[pos]) & 0xff);
s << hex;
}
return s.str();
}
enum wkbByteOrder {
wkbXDR=0,
wkbNDR=1
};
inline void reverse_bytes(char size, char *address)
{
char * first = address;
char * last = first + size - 1;
for(;first < last;++first, --last)
{
char x = *last;
*last = *first;
*first = x;
}
}
template <typename S, typename T>
inline void write (S & stream, T val, std::size_t size, wkbByteOrder byte_order)
{
#ifdef MAPNIK_BIG_ENDIAN
bool need_swap = byte_order ? wkbNDR : wkbXDR;
#else
bool need_swap = byte_order ? wkbXDR : wkbNDR;
#endif
char* buf = reinterpret_cast<char*>(&val);
if (need_swap)
{
reverse_bytes(size,buf);
}
stream.write(buf,size);
}
struct wkb_buffer
{
wkb_buffer(std::size_t size)
: size_(size),
data_( (size_!=0) ? static_cast<char*>(::operator new (size_)):0)
{}
~wkb_buffer()
{
::operator delete(data_);
}
inline std::size_t size() const
{
return size_;
}
inline char* buffer()
{
return data_;
}
std::size_t size_;
char * data_;
};
typedef boost::shared_ptr<wkb_buffer> wkb_buffer_ptr;
wkb_buffer_ptr to_point_wkb( geometry_type const& g, wkbByteOrder byte_order)
{
assert(g.num_points() == 1);
std::size_t size = 1 + 4 + 8*2 ; // byteOrder + wkbType + Point
wkb_buffer_ptr wkb = boost::make_shared<wkb_buffer>(size);
boost::interprocess::bufferstream ss(wkb->buffer(), wkb->size(), std::ios::out | std::ios::binary);
ss.write(reinterpret_cast<char*>(&byte_order),1);
int type = static_cast<int>(g.type());
write(ss,type,4,byte_order);
double x,y;
g.get_vertex(0,&x,&y);
write(ss,x,8,byte_order);
write(ss,y,8,byte_order);
assert(ss.good());
return wkb;
}
wkb_buffer_ptr to_line_string_wkb( geometry_type const& g, wkbByteOrder byte_order)
{
unsigned num_points = g.num_points();
assert(num_points > 1);
std::size_t size = 1 + 4 + 4 + 8*2*num_points ; // byteOrder + wkbType + numPoints + Point*numPoints
wkb_buffer_ptr wkb = boost::make_shared<wkb_buffer>(size);
boost::interprocess::bufferstream ss(wkb->buffer(), wkb->size(), std::ios::out | std::ios::binary);
ss.write(reinterpret_cast<char*>(&byte_order),1);
int type = static_cast<int>(g.type());
write(ss,type,4,byte_order);
write(ss,num_points,4,byte_order);
double x,y;
for (unsigned i=0; i< num_points; ++i)
{
g.get_vertex(i,&x,&y);
write(ss,x,8,byte_order);
write(ss,y,8,byte_order);
}
assert(ss.good());
return wkb;
}
wkb_buffer_ptr to_polygon_wkb( geometry_type const& g, wkbByteOrder byte_order)
{
unsigned num_points = g.num_points();
assert(num_points > 1);
typedef std::pair<double,double> point_type;
typedef std::vector<point_type> linear_ring;
boost::ptr_vector<linear_ring> rings;
double x,y;
std::size_t size = 1 + 4 + 4 ; // byteOrder + wkbType + numRings
for (unsigned i=0; i< num_points; ++i)
{
unsigned command = g.get_vertex(i,&x,&y);
if (command == SEG_MOVETO)
{
rings.push_back(new linear_ring); // start new loop
size += 4; // num_points
}
rings.back().push_back(std::make_pair(x,y));
size += 2 * 8; // point
}
unsigned num_rings = rings.size();
wkb_buffer_ptr wkb = boost::make_shared<wkb_buffer>(size);
boost::interprocess::bufferstream ss(wkb->buffer(), wkb->size(), std::ios::out | std::ios::binary);
ss.write(reinterpret_cast<char*>(&byte_order),1);
int type = static_cast<int>(g.type());
write(ss,type,4,byte_order);
write(ss,num_rings,4,byte_order);
BOOST_FOREACH ( linear_ring const& ring, rings)
{
unsigned num_points = ring.size();
write(ss,num_points,4,byte_order);
BOOST_FOREACH ( point_type const& pt, ring)
{
double x = pt.first;
double y = pt.second;
write(ss,x,8,byte_order);
write(ss,y,8,byte_order);
}
}
assert(ss.good());
return wkb;
}
wkb_buffer_ptr to_wkb(geometry_type const& g, wkbByteOrder byte_order )
{
wkb_buffer_ptr wkb;
switch (g.type())
{
case mapnik::Point :
wkb = to_point_wkb(g, byte_order);
break;
case mapnik::LineString:
wkb = to_line_string_wkb(g, byte_order);
break;
case mapnik::Polygon:
wkb = to_polygon_wkb(g, byte_order);
break;
case mapnik::MultiPoint:
case mapnik::MultiLineString:
case mapnik::MultiPolygon:
break;
default:
break;
}
return wkb;
}
}}
#endif // MAPNIK_GEOMETRY_TO_WKB_HPP

View file

@ -351,19 +351,23 @@ includes = glob.glob('../include/mapnik/*.hpp')
svg_includes = glob.glob('../include/mapnik/svg/*.hpp') svg_includes = glob.glob('../include/mapnik/svg/*.hpp')
wkt_includes = glob.glob('../include/mapnik/wkt/*.hpp') wkt_includes = glob.glob('../include/mapnik/wkt/*.hpp')
grid_includes = glob.glob('../include/mapnik/grid/*.hpp') grid_includes = glob.glob('../include/mapnik/grid/*.hpp')
util_includes = glob.glob('../include/mapnik/util/*.hpp')
inc_target = os.path.normpath(env['INSTALL_PREFIX']+'/include/mapnik') inc_target = os.path.normpath(env['INSTALL_PREFIX']+'/include/mapnik')
svg_inc_target = os.path.normpath(env['INSTALL_PREFIX']+'/include/mapnik/svg') svg_inc_target = os.path.normpath(env['INSTALL_PREFIX']+'/include/mapnik/svg')
wkt_inc_target = os.path.normpath(env['INSTALL_PREFIX']+'/include/mapnik/wkt') wkt_inc_target = os.path.normpath(env['INSTALL_PREFIX']+'/include/mapnik/wkt')
grid_inc_target = os.path.normpath(env['INSTALL_PREFIX']+'/include/mapnik/grid') grid_inc_target = os.path.normpath(env['INSTALL_PREFIX']+'/include/mapnik/grid')
util_inc_target = os.path.normpath(env['INSTALL_PREFIX']+'/include/mapnik/util')
if 'uninstall' not in COMMAND_LINE_TARGETS: if 'uninstall' not in COMMAND_LINE_TARGETS:
env.Alias(target='install', source=env.Install(inc_target, includes)) env.Alias(target='install', source=env.Install(inc_target, includes))
env.Alias(target='install', source=env.Install(svg_inc_target, svg_includes)) env.Alias(target='install', source=env.Install(svg_inc_target, svg_includes))
env.Alias(target='install', source=env.Install(wkt_inc_target, wkt_includes)) env.Alias(target='install', source=env.Install(wkt_inc_target, wkt_includes))
env.Alias(target='install', source=env.Install(grid_inc_target, grid_includes)) env.Alias(target='install', source=env.Install(grid_inc_target, grid_includes))
env.Alias(target='install', source=env.Install(util_inc_target, util_includes))
env['create_uninstall_target'](env, inc_target) env['create_uninstall_target'](env, inc_target)
env['create_uninstall_target'](env, svg_inc_target) env['create_uninstall_target'](env, svg_inc_target)
env['create_uninstall_target'](env, wkt_inc_target) env['create_uninstall_target'](env, wkt_inc_target)
env['create_uninstall_target'](env, grid_inc_target) env['create_uninstall_target'](env, grid_inc_target)
env['create_uninstall_target'](env, util_inc_target)

View file

@ -226,6 +226,10 @@ void datasource_cache::register_datasources(const std::string& str)
#endif #endif
registered_=true; registered_=true;
} }
else if (!ds_name)
{
std::clog << "Problem loading plugin library '" << itr->path().string() << "' (plugin is lacking compatible interface)" << std::endl;
}
} }
else else
{ {

View file

@ -255,10 +255,10 @@ void map_parser::parse_map( Map & map, ptree const & pt, std::string const& base
} }
else else
{ {
std::ostringstream s; std::ostringstream s_err;
s << "failed to parse 'maximum-extent'"; s << "failed to parse 'maximum-extent'";
if ( strict_ ) if ( strict_ )
throw config_error(s.str()); throw config_error(s_err.str());
else else
std::clog << "### WARNING: " << s.str() << std::endl; std::clog << "### WARNING: " << s.str() << std::endl;
} }
@ -311,6 +311,7 @@ void map_parser::parse_map( Map & map, ptree const & pt, std::string const& base
} }
} }
map.set_extra_attributes(extra_attr); map.set_extra_attributes(extra_attr);
} }
catch (const config_error & ex) catch (const config_error & ex)
@ -389,6 +390,32 @@ void map_parser::parse_map_include( Map & map, ptree const & include )
} }
datasource_templates_[name] = params; datasource_templates_[name] = params;
} }
else if (v.first == "Parameters")
{
std::string name = get_attr(v.second, "name", std::string("Unnamed"));
parameters & params = map.get_extra_parameters();
ptree::const_iterator paramIter = v.second.begin();
ptree::const_iterator endParam = v.second.end();
for (; paramIter != endParam; ++paramIter)
{
ptree const& param = paramIter->second;
if (paramIter->first == "Parameter")
{
std::string name = get_attr<std::string>(param, "name");
std::string value = get_value<std::string>( param,
"parameter");
params[name] = value;
}
else if( paramIter->first != "<xmlattr>" &&
paramIter->first != "<xmlcomment>" )
{
throw config_error(std::string("Unknown child node in ") +
"'Parameters'. Expected 'Parameter' but got '" +
paramIter->first + "'");
}
}
}
else if (v.first != "<xmlcomment>" && else if (v.first != "<xmlcomment>" &&
v.first != "<xmlattr>") v.first != "<xmlattr>")
{ {
@ -2185,20 +2212,12 @@ std::string map_parser::ensure_relative_to_xml( boost::optional<std::string> opt
void map_parser::ensure_attrs(ptree const& sym, std::string name, std::string attrs) void map_parser::ensure_attrs(ptree const& sym, std::string name, std::string attrs)
{ {
typedef ptree::key_type::value_type Ch; typedef ptree::key_type::value_type Ch;
//typedef boost::property_tree::xml_parser::xmlattr<Ch> x_att;
std::set<std::string> attr_set;
boost::split(attr_set, attrs, boost::is_any_of(","));
for (ptree::const_iterator itr = sym.begin(); itr != sym.end(); ++itr)
{
//ptree::value_type const& v = *itr;
if (itr->first == boost::property_tree::xml_parser::xmlattr<Ch>())
{
optional<const ptree &> attribs = sym.get_child_optional( boost::property_tree::xml_parser::xmlattr<Ch>() ); optional<const ptree &> attribs = sym.get_child_optional( boost::property_tree::xml_parser::xmlattr<Ch>() );
if (attribs) if (attribs)
{ {
std::set<std::string> attr_set;
boost::split(attr_set, attrs, boost::is_any_of(","));
std::ostringstream s(""); std::ostringstream s("");
s << "### " << name << " properties warning: "; s << "### " << name << " properties warning: ";
int missing = 0; int missing = 0;
@ -2208,20 +2227,27 @@ void map_parser::ensure_attrs(ptree const& sym, std::string name, std::string at
bool found = (attr_set.find(name) != attr_set.end()); bool found = (attr_set.find(name) != attr_set.end());
if (!found) if (!found)
{ {
if (missing) s << ","; if (missing)
{
s << ",";
}
s << "'" << name << "'"; s << "'" << name << "'";
++missing; ++missing;
} }
} }
if (missing) { if (missing) {
if (missing > 1) s << " are"; if (missing > 1)
else s << " is"; {
s << " are";
}
else
{
s << " is";
}
s << " invalid, acceptable values are:\n'" << attrs << "'\n"; s << " invalid, acceptable values are:\n'" << attrs << "'\n";
std::clog << s.str(); std::clog << s.str();
} }
} }
} }
}
}
} // end of namespace mapnik } // end of namespace mapnik

View file

@ -92,7 +92,8 @@ Map::Map(const Map& rhs)
current_extent_(rhs.current_extent_), current_extent_(rhs.current_extent_),
maximum_extent_(rhs.maximum_extent_), maximum_extent_(rhs.maximum_extent_),
base_path_(rhs.base_path_), base_path_(rhs.base_path_),
extra_attr_(rhs.extra_attr_) {} extra_attr_(rhs.extra_attr_),
extra_params_(rhs.extra_params_) {}
Map& Map::operator=(const Map& rhs) Map& Map::operator=(const Map& rhs)
{ {
@ -110,6 +111,7 @@ Map& Map::operator=(const Map& rhs)
maximum_extent_=rhs.maximum_extent_; maximum_extent_=rhs.maximum_extent_;
base_path_=rhs.base_path_; base_path_=rhs.base_path_;
extra_attr_=rhs.extra_attr_; extra_attr_=rhs.extra_attr_;
extra_params_=rhs.extra_params_;
return *this; return *this;
} }
@ -677,9 +679,29 @@ parameters const& Map::get_extra_attributes() const
return extra_attr_; return extra_attr_;
} }
void Map::set_extra_attributes(parameters& params) parameters& Map::get_extra_attributes()
{ {
extra_attr_ = params; return extra_attr_;
}
void Map::set_extra_attributes(parameters& attr)
{
extra_attr_ = attr;
}
parameters const& Map::get_extra_parameters() const
{
return extra_params_;
}
parameters& Map::get_extra_parameters()
{
return extra_params_;
}
void Map::set_extra_parameters(parameters& params)
{
extra_params_ = params;
} }
} }

View file

@ -120,11 +120,9 @@ void raster_colorizer::colorize(raster_ptr const& raster,const std::map<std::str
const std::map<std::string,value>::const_iterator fi = Props.find("NODATA"); const std::map<std::string,value>::const_iterator fi = Props.find("NODATA");
if (fi != Props.end()) if (fi != Props.end())
//if (Props.count("NODATA")>0)
{ {
hasNoData = true; hasNoData = true;
//noDataValue = Props.at("NODATA").to_double(); noDataValue = static_cast<float>(fi->second.to_double());
noDataValue = fi->second.to_double();
} }
for (int i=0; i<len; ++i) for (int i=0; i<len; ++i)
@ -138,9 +136,9 @@ void raster_colorizer::colorize(raster_ptr const& raster,const std::map<std::str
} }
} }
inline float interpolate(float start,float end, float fraction) inline unsigned interpolate(unsigned start, unsigned end, float fraction)
{ {
return fraction * (end - start) + start; return static_cast<unsigned>(fraction * (end - start) + start);
} }
color raster_colorizer::get_color(float value) const { color raster_colorizer::get_color(float value) const {
@ -213,10 +211,10 @@ color raster_colorizer::get_color(float value) const {
else { else {
float fraction = (value - stopValue) / (nextStopValue - stopValue); float fraction = (value - stopValue) / (nextStopValue - stopValue);
float r = interpolate(stopColor.red(), nextStopColor.red(),fraction); unsigned r = interpolate(stopColor.red(), nextStopColor.red(),fraction);
float g = interpolate(stopColor.green(), nextStopColor.green(),fraction); unsigned g = interpolate(stopColor.green(), nextStopColor.green(),fraction);
float b = interpolate(stopColor.blue(), nextStopColor.blue(),fraction); unsigned b = interpolate(stopColor.blue(), nextStopColor.blue(),fraction);
float a = interpolate(stopColor.alpha(), nextStopColor.alpha(),fraction); unsigned a = interpolate(stopColor.alpha(), nextStopColor.alpha(),fraction);
outputColor.set_red(r); outputColor.set_red(r);
outputColor.set_green(g); outputColor.set_green(g);

View file

@ -761,6 +761,24 @@ void serialize_datasource( ptree & layer_node, datasource_ptr datasource)
} }
} }
void serialize_parameters( ptree & map_node, mapnik::parameters const& params)
{
ptree & params_node = map_node.push_back(
ptree::value_type("Parameters", ptree()))->second;
parameters::const_iterator it = params.begin();
parameters::const_iterator end = params.end();
for (; it != end; ++it)
{
boost::property_tree::ptree & param_node = params_node.push_back(
boost::property_tree::ptree::value_type("Parameter",
boost::property_tree::ptree()))->second;
param_node.put("<xmlattr>.name", it->first );
param_node.put_value( it->second );
}
}
void serialize_layer( ptree & map_node, const layer & layer, bool explicit_defaults ) void serialize_layer( ptree & map_node, const layer & layer, bool explicit_defaults )
{ {
ptree & layer_node = map_node.push_back( ptree & layer_node = map_node.push_back(
@ -901,6 +919,8 @@ void serialize_map(ptree & pt, Map const & map, bool explicit_defaults)
set_attr( map_node, p_it->first, p_it->second ); set_attr( map_node, p_it->first, p_it->second );
} }
serialize_parameters( map_node, map.get_extra_parameters());
Map::const_style_iterator it = map.styles().begin(); Map::const_style_iterator it = map.styles().begin();
Map::const_style_iterator end = map.styles().end(); Map::const_style_iterator end = map.styles().end();
for (; it != end; ++it) for (; it != end; ++it)

View file

@ -0,0 +1,20 @@
<Map>
<!--
totally arbirary Parameters can also be attached to the map
which will be respected during serialization.
This makes it easier for calling applications that work with mapnik
xml, and leverage its serialization, to pass through directives that
the calling application needs which describe how to handle the map.
-->
<Parameters>
<Parameter name="key"><![CDATA[value]]></Parameter>
<!-- this one will override previous key with same name -->
<Parameter name="key"><![CDATA[value2]]></Parameter>
<Parameter name="key3"><![CDATA[value3]]></Parameter>
<Parameter name="unicode"><![CDATA[iván]]></Parameter>
</Parameters>
</Map>

View file

@ -0,0 +1,11 @@
<Map font-directory="." minimum-version="0.0.0">
<!--
font-directory and minimin-version are extra attributes known
to load_map which are and attached to the map object in order to be
carried through and respected by save map.
They are treated as 'extra' because they have no role during map rendering
-->
</Map>

View file

@ -0,0 +1,40 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from nose.tools import *
from utilities import execution_path
from Queue import Queue
import threading
import os, mapnik
import sqlite3
def setup():
# All of the paths used are relative, if we run the tests
# from another directory we need to chdir()
os.chdir(execution_path('.'))
def test_non_member_known_attributes():
m = mapnik.Map(256,256)
mapnik.load_map(m,'../data/good_maps/extra_known_map_attributes.xml')
attr = m.extra_attributes
eq_(len(attr),2)
eq_(attr['font-directory'],'.')
eq_(attr['minimum-version'],'0.0.0')
def test_arbitrary_parameters_attached_to_map():
m = mapnik.Map(256,256)
mapnik.load_map(m,'../data/good_maps/extra_arbitary_map_parameters.xml')
attr = m.extra_attributes
eq_(len(attr),0)
eq_(len(m.params),3)
eq_(m.params['key'],'value2')
eq_(m.params['key3'],'value3')
eq_(m.params['unicode'],u'iván')
if __name__ == "__main__":
setup()
[eval(run)() for run in dir() if 'test_' in run]

View file

@ -2,7 +2,7 @@
from nose.tools import * from nose.tools import *
import mapnik, pickle import mapnik
# Tests that exercise fonts. # Tests that exercise fonts.

View file

@ -0,0 +1,45 @@
#encoding: utf8
from nose.tools import *
import os
from utilities import execution_path
import mapnik
wkts = [
[1,"POINT (30 10)"],
[1,"LINESTRING (30 10, 10 30, 40 40)"],
[1,"POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10))"],
[1,"POLYGON ((35 10, 10 20, 15 40, 45 45, 35 10),(20 30, 35 35, 30 20, 20 30))"],
[4,"MULTIPOINT ((10 40), (40 30), (20 20), (30 10))"],
[2,"MULTILINESTRING ((10 10, 20 20, 10 40),(40 40, 30 30, 40 20, 30 10))"],
[2,"MULTIPOLYGON (((30 20, 10 40, 45 40, 30 20)),((15 5, 40 10, 10 20, 5 10, 15 5)))"],
[2,"MULTIPOLYGON (((40 40, 20 45, 45 30, 40 40)),((20 35, 45 20, 30 5, 10 10, 10 30, 20 35),(30 20, 20 25, 20 15, 30 20)))"]
]
def compare_wkb_from_wkt(wkt,num):
f = mapnik.Feature(1)
f.add_geometries_from_wkt(wkt)
eq_(len(f.geometries()),num)
paths = mapnik.Path.from_wkt(wkt)
eq_(len(paths),num)
eq_(f.geometries()[0].to_wkb(),paths[0].to_wkb())
paths2 = mapnik.Path()
for path in paths:
paths2.add_wkb(path.to_wkb())
eq_(len(paths2),num)
eq_(f.geometries()[0].to_wkb(),paths2[0].to_wkb())
def test_point():
for wkt in wkts:
try:
compare_wkb_from_wkt(wkt[1],wkt[0])
except RuntimeError, e:
raise RuntimeError('%s %s' % (e, wkt))
if __name__ == "__main__":
[eval(run)() for run in dir() if 'test_' in run]

View file

@ -5,8 +5,9 @@ import os
from nose.tools import * from nose.tools import *
from utilities import execution_path from utilities import execution_path
from utilities import Todo from utilities import Todo
import tempfile
import mapnik, pickle import mapnik
def setup(): def setup():
# All of the paths used are relative, if we run the tests # All of the paths used are relative, if we run the tests
@ -122,17 +123,6 @@ def test_pointsymbolizer_init():
#def test_pointsymbolizer_missing_image(): #def test_pointsymbolizer_missing_image():
# p = mapnik.PointSymbolizer(mapnik.PathExpression("../data/images/broken.png")) # p = mapnik.PointSymbolizer(mapnik.PathExpression("../data/images/broken.png"))
# PointSymbolizer pickling
def test_pointsymbolizer_pickle():
raise Todo("point_symbolizer pickling currently disabled")
p = mapnik.PointSymbolizer(mapnik.PathExpression("../data/images/dummy.png"))
p2 = pickle.loads(pickle.dumps(p,pickle.HIGHEST_PROTOCOL))
# image type, width, and height only used in contructor...
eq_(p.filename, p2.filename)
eq_(p.allow_overlap, p2.allow_overlap)
eq_(p.opacity, p2.opacity)
eq_(p.ignore_placement, p2.ignore_placement)
eq_(p.placement, p2.placement)
# PolygonSymbolizer initialization # PolygonSymbolizer initialization
def test_polygonsymbolizer_init(): def test_polygonsymbolizer_init():
@ -146,17 +136,6 @@ def test_polygonsymbolizer_init():
eq_(p.fill, mapnik.Color('blue')) eq_(p.fill, mapnik.Color('blue'))
eq_(p.fill_opacity, 1) eq_(p.fill_opacity, 1)
# PolygonSymbolizer pickling
def test_polygonsymbolizer_pickle():
p = mapnik.PolygonSymbolizer(mapnik.Color('black'))
p.fill_opacity = .5
# does not work for some reason...
#eq_(pickle.loads(pickle.dumps(p)), p)
p2 = pickle.loads(pickle.dumps(p,pickle.HIGHEST_PROTOCOL))
eq_(p.fill, p2.fill)
eq_(p.fill_opacity, p2.fill_opacity)
# Stroke initialization # Stroke initialization
def test_stroke_init(): def test_stroke_init():
s = mapnik.Stroke() s = mapnik.Stroke()
@ -187,25 +166,6 @@ def test_stroke_dash_arrays():
eq_(s.get_dashes(), [(1,2),(3,4),(5,6)]) eq_(s.get_dashes(), [(1,2),(3,4),(5,6)])
# Stroke pickling
def test_stroke_pickle():
s = mapnik.Stroke(mapnik.Color('black'),4.5)
eq_(s.width, 4.5)
eq_(s.color, mapnik.Color('black'))
s.add_dash(1,2)
s.add_dash(3,4)
s.add_dash(5,6)
s2 = pickle.loads(pickle.dumps(s,pickle.HIGHEST_PROTOCOL))
eq_(s.color, s2.color)
eq_(s.width, s2.width)
eq_(s.opacity, s2.opacity)
eq_(s.get_dashes(), s2.get_dashes())
eq_(s.line_cap, s2.line_cap)
eq_(s.line_join, s2.line_join)
# LineSymbolizer initialization # LineSymbolizer initialization
def test_linesymbolizer_init(): def test_linesymbolizer_init():
@ -234,19 +194,6 @@ def test_linesymbolizer_init():
eq_(l.stroke.line_cap, mapnik.line_cap.BUTT_CAP) eq_(l.stroke.line_cap, mapnik.line_cap.BUTT_CAP)
eq_(l.stroke.line_join, mapnik.line_join.MITER_JOIN) eq_(l.stroke.line_join, mapnik.line_join.MITER_JOIN)
# LineSymbolizer pickling
def test_linesymbolizer_pickle():
p = mapnik.LineSymbolizer()
p2 = pickle.loads(pickle.dumps(p,pickle.HIGHEST_PROTOCOL))
# line and stroke eq fails, so we compare attributes for now..
s,s2 = p.stroke, p2.stroke
eq_(s.color, s2.color)
eq_(s.opacity, s2.opacity)
eq_(s.width, s2.width)
eq_(s.get_dashes(), s2.get_dashes())
eq_(s.line_cap, s2.line_cap)
eq_(s.line_join, s2.line_join)
# TextSymbolizer initialization # TextSymbolizer initialization
def test_textsymbolizer_init(): def test_textsymbolizer_init():
@ -258,56 +205,6 @@ def test_textsymbolizer_init():
eq_(ts.fill, mapnik.Color('black')) eq_(ts.fill, mapnik.Color('black'))
eq_(ts.label_placement, mapnik.label_placement.POINT_PLACEMENT) eq_(ts.label_placement, mapnik.label_placement.POINT_PLACEMENT)
# TextSymbolizer pickling
def test_textsymbolizer_pickle():
ts = mapnik.TextSymbolizer(mapnik.Expression('[Field_Name]'), 'Font Name', 8, mapnik.Color('black'))
eq_(str(ts.name), str(mapnik.Expression('[Field_Name]')))
eq_(ts.face_name, 'Font Name')
eq_(ts.text_size, 8)
eq_(ts.fill, mapnik.Color('black'))
raise Todo("text_symbolizer pickling currently disabled")
ts2 = pickle.loads(pickle.dumps(ts,pickle.HIGHEST_PROTOCOL))
eq_(ts.name, ts2.name)
eq_(ts.face_name, ts2.face_name)
eq_(ts.allow_overlap, ts2.allow_overlap)
eq_(ts.displacement, ts2.displacement)
eq_(ts.anchor, ts2.anchor)
eq_(ts.fill, ts2.fill)
eq_(ts.force_odd_labels, ts2.force_odd_labels)
eq_(ts.halo_fill, ts2.halo_fill)
eq_(ts.halo_radius, ts2.halo_radius)
eq_(ts.label_placement, ts2.label_placement)
eq_(ts.minimum_distance, ts2.minimum_distance)
eq_(ts.text_ratio, ts2.text_ratio)
eq_(ts.text_size, ts2.text_size)
eq_(ts.wrap_width, ts2.wrap_width)
eq_(ts.vertical_alignment, ts2.vertical_alignment)
eq_(ts.label_spacing, ts2.label_spacing)
eq_(ts.label_position_tolerance, ts2.label_position_tolerance)
# 22.5 * M_PI/180.0 initialized by default
assert_almost_equal(s.max_char_angle_delta, 0.39269908169872414)
eq_(ts.wrap_character, ts2.wrap_character)
eq_(ts.text_transform, ts2.text_transform)
eq_(ts.line_spacing, ts2.line_spacing)
eq_(ts.character_spacing, ts2.character_spacing)
# r1341
eq_(ts.wrap_before, ts2.wrap_before)
eq_(ts.horizontal_alignment, ts2.horizontal_alignment)
eq_(ts.justify_alignment, ts2.justify_alignment)
eq_(ts.opacity, ts2.opacity)
# r2300
eq_(s.minimum_padding, 0.0)
raise Todo("FontSet pickling support needed: http://trac.mapnik.org/ticket/348")
eq_(ts.fontset, ts2.fontset)
# Map initialization # Map initialization
def test_layer_init(): def test_layer_init():
l = mapnik.Layer('test') l = mapnik.Layer('test')
@ -365,11 +262,13 @@ def test_map_init_from_string():
eq_(m.base, './') eq_(m.base, './')
mapnik.load_map_from_string(m, map_string, False, "") # this "" will have no effect mapnik.load_map_from_string(m, map_string, False, "") # this "" will have no effect
eq_(m.base, './') eq_(m.base, './')
tmp_dir = tempfile.gettempdir()
try: try:
mapnik.load_map_from_string(m, map_string, False, "/tmp") mapnik.load_map_from_string(m, map_string, False, tmp_dir)
except RuntimeError: except RuntimeError:
pass # runtime error expected because shapefile path should be wrong and datasource will throw pass # runtime error expected because shapefile path should be wrong and datasource will throw
eq_(m.base, '/tmp') # /tmp will be set despite the exception because load_map mostly worked eq_(m.base, tmp_dir) # tmp_dir will be set despite the exception because load_map mostly worked
m.base = 'foo' m.base = 'foo'
mapnik.load_map_from_string(m, map_string, True, ".") mapnik.load_map_from_string(m, map_string, True, ".")
eq_(m.base, '.') eq_(m.base, '.')
@ -379,19 +278,6 @@ def test_map_init_from_string():
if not 'Could not create datasource' in str(e): if not 'Could not create datasource' in str(e):
raise RuntimeError(e) raise RuntimeError(e)
# Map pickling
def test_map_pickle():
# Fails due to scale() not matching, possibly other things
raise(Todo("Map does not support pickling yet (Tickets #345)."))
m = mapnik.Map(256, 256)
eq_(pickle.loads(pickle.dumps(m)), m)
m = mapnik.Map(256, 256, '+proj=latlong')
eq_(pickle.loads(pickle.dumps(m)), m)
# Color initialization # Color initialization
@raises(Exception) # Boost.Python.ArgumentError @raises(Exception) # Boost.Python.ArgumentError
@ -505,20 +391,6 @@ def test_color_equality():
eq_(c3, mapnik.Color(0,0,255,128)) eq_(c3, mapnik.Color(0,0,255,128))
# Color pickling
def test_color_pickle():
c = mapnik.Color('blue')
eq_(pickle.loads(pickle.dumps(c)), c)
c = mapnik.Color(0, 64, 128)
eq_(pickle.loads(pickle.dumps(c)), c)
c = mapnik.Color(0, 64, 128, 192)
eq_(pickle.loads(pickle.dumps(c)), c)
# Rule initialization # Rule initialization
def test_rule_init(): def test_rule_init():
min_scale = 5 min_scale = 5
@ -678,12 +550,6 @@ def test_envelope_static_init():
eq_(c.x, 150) eq_(c.x, 150)
eq_(c.y, 150) eq_(c.y, 150)
# Box2d pickling
def test_envelope_pickle():
e = mapnik.Box2d(100, 100, 200, 200)
eq_(pickle.loads(pickle.dumps(e)), e)
# Box2d multiplication # Box2d multiplication
def test_envelope_multiplication(): def test_envelope_multiplication():
e = mapnik.Box2d(100, 100, 200, 200) e = mapnik.Box2d(100, 100, 200, 200)
@ -716,7 +582,7 @@ def test_envelope_multiplication():
eq_(c.y, 150) eq_(c.y, 150)
# Box2d clipping # Box2d clipping
def test_envelope_pickle(): def test_envelope_clipping():
e1 = mapnik.Box2d(-180,-90,180,90) e1 = mapnik.Box2d(-180,-90,180,90)
e2 = mapnik.Box2d(-120,40,-110,48) e2 = mapnik.Box2d(-120,40,-110,48)
e1.clip(e2) e1.clip(e2)

View file

@ -0,0 +1,53 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
from nose.tools import *
from utilities import execution_path
import mapnik
import pickle
def setup():
os.chdir(execution_path('.'))
def test_parameter():
p = mapnik.Parameter('key','value')
eq_(p[0],'key')
eq_(p[1],'value')
p = mapnik.Parameter('int',1)
eq_(p[0],'int')
eq_(p[1],1)
p = mapnik.Parameter('float',1.0777)
eq_(p[0],'float')
eq_(p[1],1.0777)
def test_parameters():
params = mapnik.Parameters()
p = mapnik.Parameter('float',1.0777)
eq_(p[0],'float')
eq_(p[1],1.0777)
params.append(p)
eq_(params[0][0],'float')
eq_(params[0][1],1.0777)
eq_(params.get('float'),1.0777)
def test_parameters_pickling():
params = mapnik.Parameters()
params.append(mapnik.Parameter('oh',str('yeah')))
params2 = pickle.loads(pickle.dumps(params,pickle.HIGHEST_PROTOCOL))
eq_(params[0][0],params2[0][0])
eq_(params[0][1],params2[0][1])
if __name__ == "__main__":
setup()
[eval(run)() for run in dir() if 'test_' in run]

View file

@ -0,0 +1,159 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
from nose.tools import *
from utilities import execution_path
from utilities import Todo
import tempfile
import mapnik, pickle
def setup():
# All of the paths used are relative, if we run the tests
# from another directory we need to chdir()
os.chdir(execution_path('.'))
# PointSymbolizer pickling
def test_pointsymbolizer_pickle():
raise Todo("point_symbolizer pickling currently disabled")
p = mapnik.PointSymbolizer(mapnik.PathExpression("../data/images/dummy.png"))
p2 = pickle.loads(pickle.dumps(p,pickle.HIGHEST_PROTOCOL))
# image type, width, and height only used in contructor...
eq_(p.filename, p2.filename)
eq_(p.allow_overlap, p2.allow_overlap)
eq_(p.opacity, p2.opacity)
eq_(p.ignore_placement, p2.ignore_placement)
eq_(p.placement, p2.placement)
# PolygonSymbolizer pickling
def test_polygonsymbolizer_pickle():
p = mapnik.PolygonSymbolizer(mapnik.Color('black'))
p.fill_opacity = .5
# does not work for some reason...
#eq_(pickle.loads(pickle.dumps(p)), p)
p2 = pickle.loads(pickle.dumps(p,pickle.HIGHEST_PROTOCOL))
eq_(p.fill, p2.fill)
eq_(p.fill_opacity, p2.fill_opacity)
# Stroke pickling
def test_stroke_pickle():
s = mapnik.Stroke(mapnik.Color('black'),4.5)
eq_(s.width, 4.5)
eq_(s.color, mapnik.Color('black'))
s.add_dash(1,2)
s.add_dash(3,4)
s.add_dash(5,6)
s2 = pickle.loads(pickle.dumps(s,pickle.HIGHEST_PROTOCOL))
eq_(s.color, s2.color)
eq_(s.width, s2.width)
eq_(s.opacity, s2.opacity)
eq_(s.get_dashes(), s2.get_dashes())
eq_(s.line_cap, s2.line_cap)
eq_(s.line_join, s2.line_join)
# LineSymbolizer pickling
def test_linesymbolizer_pickle():
p = mapnik.LineSymbolizer()
p2 = pickle.loads(pickle.dumps(p,pickle.HIGHEST_PROTOCOL))
# line and stroke eq fails, so we compare attributes for now..
s,s2 = p.stroke, p2.stroke
eq_(s.color, s2.color)
eq_(s.opacity, s2.opacity)
eq_(s.width, s2.width)
eq_(s.get_dashes(), s2.get_dashes())
eq_(s.line_cap, s2.line_cap)
eq_(s.line_join, s2.line_join)
# TextSymbolizer pickling
def test_textsymbolizer_pickle():
ts = mapnik.TextSymbolizer(mapnik.Expression('[Field_Name]'), 'Font Name', 8, mapnik.Color('black'))
eq_(str(ts.name), str(mapnik.Expression('[Field_Name]')))
eq_(ts.face_name, 'Font Name')
eq_(ts.text_size, 8)
eq_(ts.fill, mapnik.Color('black'))
raise Todo("text_symbolizer pickling currently disabled")
ts2 = pickle.loads(pickle.dumps(ts,pickle.HIGHEST_PROTOCOL))
eq_(ts.name, ts2.name)
eq_(ts.face_name, ts2.face_name)
eq_(ts.allow_overlap, ts2.allow_overlap)
eq_(ts.displacement, ts2.displacement)
eq_(ts.anchor, ts2.anchor)
eq_(ts.fill, ts2.fill)
eq_(ts.force_odd_labels, ts2.force_odd_labels)
eq_(ts.halo_fill, ts2.halo_fill)
eq_(ts.halo_radius, ts2.halo_radius)
eq_(ts.label_placement, ts2.label_placement)
eq_(ts.minimum_distance, ts2.minimum_distance)
eq_(ts.text_ratio, ts2.text_ratio)
eq_(ts.text_size, ts2.text_size)
eq_(ts.wrap_width, ts2.wrap_width)
eq_(ts.vertical_alignment, ts2.vertical_alignment)
eq_(ts.label_spacing, ts2.label_spacing)
eq_(ts.label_position_tolerance, ts2.label_position_tolerance)
# 22.5 * M_PI/180.0 initialized by default
assert_almost_equal(s.max_char_angle_delta, 0.39269908169872414)
eq_(ts.wrap_character, ts2.wrap_character)
eq_(ts.text_transform, ts2.text_transform)
eq_(ts.line_spacing, ts2.line_spacing)
eq_(ts.character_spacing, ts2.character_spacing)
# r1341
eq_(ts.wrap_before, ts2.wrap_before)
eq_(ts.horizontal_alignment, ts2.horizontal_alignment)
eq_(ts.justify_alignment, ts2.justify_alignment)
eq_(ts.opacity, ts2.opacity)
# r2300
eq_(s.minimum_padding, 0.0)
raise Todo("FontSet pickling support needed: http://trac.mapnik.org/ticket/348")
eq_(ts.fontset, ts2.fontset)
def test_map_pickle():
# Fails due to scale() not matching, possibly other things
raise(Todo("Map does not support pickling yet (Tickets #345)."))
m = mapnik.Map(256, 256)
eq_(pickle.loads(pickle.dumps(m)), m)
m = mapnik.Map(256, 256, '+proj=latlong')
eq_(pickle.loads(pickle.dumps(m)), m)
def test_color_pickle():
c = mapnik.Color('blue')
eq_(pickle.loads(pickle.dumps(c)), c)
c = mapnik.Color(0, 64, 128)
eq_(pickle.loads(pickle.dumps(c)), c)
c = mapnik.Color(0, 64, 128, 192)
eq_(pickle.loads(pickle.dumps(c)), c)
def test_envelope_pickle():
e = mapnik.Box2d(100, 100, 200, 200)
eq_(pickle.loads(pickle.dumps(e)), e)
if __name__ == "__main__":
setup()
[eval(run)() for run in dir() if 'test_' in run]

View file

@ -35,7 +35,7 @@ def psql_can_connect():
call('psql %s -c "select postgis_version()"' % POSTGIS_TEMPLATE_DBNAME) call('psql %s -c "select postgis_version()"' % POSTGIS_TEMPLATE_DBNAME)
return True return True
except RuntimeError, e: except RuntimeError, e:
print 'Notice: skipping postgis tests as basic auth is not correctly set up. Error was: %s' % e.message print 'Notice: skipping postgis tests (connection)'
return False return False
def shp2pgsql_on_path(): def shp2pgsql_on_path():
@ -47,7 +47,7 @@ def shp2pgsql_on_path():
call('shp2pgsql') call('shp2pgsql')
return True return True
except RuntimeError, e: except RuntimeError, e:
print 'Notice: skipping postgis tests because shp2pgsql not found. Error was: %s' % e.message print 'Notice: skipping postgis tests (shp2pgsql)'
return False return False
def createdb_and_dropdb_on_path(): def createdb_and_dropdb_on_path():
@ -60,7 +60,7 @@ def createdb_and_dropdb_on_path():
call('dropdb --help') call('dropdb --help')
return True return True
except RuntimeError, e: except RuntimeError, e:
print 'Notice: skipping postgis tests because createdb or dropdb not found. Error was: %s' % e.message print 'Notice: skipping postgis tests (createdb/dropdb)'
return False return False
def postgis_setup(): def postgis_setup():

View file

@ -2,7 +2,7 @@
from nose.tools import * from nose.tools import *
import mapnik, pickle import mapnik
# Tests that exercise map projections. # Tests that exercise map projections.

View file

@ -2,10 +2,9 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from nose.tools import * from nose.tools import *
import tempfile
import os, mapnik import os, mapnik
from nose.tools import * from nose.tools import *
from utilities import execution_path from utilities import execution_path
from utilities import Todo from utilities import Todo
@ -216,7 +215,7 @@ def test_render_points():
p = mapnik.Projection(projs[projdescr]) p = mapnik.Projection(projs[projdescr])
m.zoom_to_box(p.forward(mapnik.Box2d(ul_lonlat,lr_lonlat))) m.zoom_to_box(p.forward(mapnik.Box2d(ul_lonlat,lr_lonlat)))
# Render to SVG so that it can be checked how many points are there with string comparison # Render to SVG so that it can be checked how many points are there with string comparison
svg_file = '/tmp/%s.svg' svg_file = os.path.join(tempfile.gettempdir(),'%s.svg')
mapnik.render_to_file(m, svg_file) mapnik.render_to_file(m, svg_file)
num_points_present = len(places_ds.all_features()) num_points_present = len(places_ds.all_features())
svg = open(svg_file,'r').read() svg = open(svg_file,'r').read()

View file

@ -42,9 +42,14 @@ if 'sqlite' in mapnik.DatasourceCache.instance().plugin_names():
eq_(os.path.exists(index),True) eq_(os.path.exists(index),True)
conn = sqlite3.connect(index) conn = sqlite3.connect(index)
cur = conn.cursor() cur = conn.cursor()
try:
cur.execute("Select count(*) from idx_%s_GEOMETRY" % TABLE.replace("'","")) cur.execute("Select count(*) from idx_%s_GEOMETRY" % TABLE.replace("'",""))
conn.commit() conn.commit()
eq_(cur.fetchone()[0],TOTAL) eq_(cur.fetchone()[0],TOTAL)
except sqlite3.OperationalError:
# don't worry about testing # of index records if
# python's sqlite module does not support rtree
pass
cur.close() cur.close()
ds = mapnik.SQLite(file=DB,table=TABLE) ds = mapnik.SQLite(file=DB,table=TABLE)

View file

@ -0,0 +1,19 @@
######################################################################
MAPNIK_INCLUDE_DIR = "/opt/mapnik/include" ;
MAPNIK_LIB_DIR = "/opt/mapnik/lib" ;
BOOST_INCLUDE_DIR = "/opt/boost_1_48_0/include" ;
lib mapnik : : <name>mapnik <search>$(MAPNIK_LIB_DIR) ;
lib icu : : <name>icuuc <search>/usr/local/lib ;
exe to_wkb :
main.cpp
.//mapnik
.//icu
:
<include>$(MAPNIK_INCLUDE_DIR)
<include>$(BOOST_INCLUDE_DIR)
;

View file

@ -0,0 +1,109 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2011 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 <iostream>
#include <string>
#include <mapnik/geometry.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/datasource_cache.hpp>
#include <mapnik/util/geometry_to_wkb.hpp>
#include <boost/foreach.hpp>
int main (int argc, char ** argv )
{
if ( argc !=2)
{
std::cerr << "Usage: " << argv[0] << " <path-to-shapefile>\n";
return EXIT_SUCCESS;
}
std::cerr << "Geometry to WKB converter\n";
mapnik::datasource_cache::instance()->register_datasources("/opt/mapnik/lib/mapnik/input/");
std::string filename(argv[1]);
std::cerr << filename << std::endl;
mapnik::parameters p;
p["type"] = "shape";
p["file"] = filename;
mapnik::datasource_ptr ds;
try
{
ds = mapnik::datasource_cache::instance()->create(p);
}
catch ( ... )
{
std::cerr << "Can't create datasource!\n";
return EXIT_FAILURE;
}
if (ds)
{
std::cerr << ds->envelope() << std::endl;
mapnik::query q(ds->envelope());
mapnik::layer_descriptor layer_desc = ds->get_descriptor();
BOOST_FOREACH ( mapnik::attribute_descriptor const& attr_desc, layer_desc.get_descriptors())
{
q.add_property_name(attr_desc.get_name());
}
mapnik::featureset_ptr fs = ds->features(q);
mapnik::feature_ptr f = fs->next();
while(f)
{
std::cerr << *f << std::endl;
boost::ptr_vector<mapnik::geometry_type> & paths = f->paths();
BOOST_FOREACH ( mapnik::geometry_type const& geom, paths)
{
// NDR
{
mapnik::util::wkb_buffer_ptr wkb = mapnik::util::to_wkb(geom,mapnik::util::wkbNDR);
std::cerr << mapnik::util::to_hex(wkb->buffer(),wkb->size()) << std::endl;
}
// XDR
{
mapnik::util::wkb_buffer_ptr wkb = mapnik::util::to_wkb(geom,mapnik::util::wkbXDR);
std::cerr << mapnik::util::to_hex(wkb->buffer(),wkb->size()) << std::endl;
}
}
f = fs->next();
}
}
return EXIT_SUCCESS;
}