diff --git a/bindings/python/mapnik_geometry.cpp b/bindings/python/mapnik_geometry.cpp index 5e5ec8c2c..30f2876df 100644 --- a/bindings/python/mapnik_geometry.cpp +++ b/bindings/python/mapnik_geometry.cpp @@ -31,6 +31,7 @@ #include #include #include +#include namespace { @@ -47,19 +48,47 @@ geometry_type const& getitem_impl(path_type & p, int key) 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); 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); } +boost::shared_ptr from_wkt_impl(std::string const& wkt) +{ + boost::shared_ptr paths = boost::make_shared(); + bool result = mapnik::from_wkt(wkt, *paths); + if (!result) throw std::runtime_error("Failed to parse WKT"); + return paths; } +boost::shared_ptr from_wkb_impl(std::string const& wkb) +{ + boost::shared_ptr paths = boost::make_shared(); + 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() { using namespace boost::python; @@ -74,18 +103,23 @@ void export_geometry() ; using mapnik::geometry_type; - class_,boost::noncopyable>("Geometry2d",no_init) + class_, boost::noncopyable>("Geometry2d",no_init) .def("envelope",&geometry_type::envelope) // .def("__str__",&geometry_type::to_string) .def("type",&geometry_type::type) + .def("to_wkb",&to_wkb) // TODO add other geometry_type methods ; - class_("Path") + class_, boost::noncopyable>("Path") .def("__getitem__", getitem_impl,return_value_policy()) .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_wkb",from_wkb_impl) + .staticmethod("from_wkt") + .staticmethod("from_wkb") ; } diff --git a/tests/python_tests/geometry_wkb_test.py b/tests/python_tests/geometry_wkb_test.py new file mode 100644 index 000000000..9750ef405 --- /dev/null +++ b/tests/python_tests/geometry_wkb_test.py @@ -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]