/***************************************************************************** * * This file is part of Mapnik (c++ mapping toolkit) * * Copyright (C) 2015 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 * *****************************************************************************/ #include #include "boost_std_shared_shim.hpp" #pragma GCC diagnostic push #include #include #include #include #include #include #include #pragma GCC diagnostic pop // mapnik #include #include #include #include #include #include #include #include #include // from_wkt #include // from_geojson #include // to_geojson #include // to_wkb #include // to_wkt //#include #include // stl #include namespace { std::shared_ptr > from_wkb_impl(std::string const& wkb) { std::shared_ptr > geom = std::make_shared >(); try { *geom = mapnik::geometry_utils::from_wkb(wkb.c_str(), wkb.size()); } catch (...) { throw std::runtime_error("Failed to parse WKB"); } return geom; } std::shared_ptr > from_wkt_impl(std::string const& wkt) { std::shared_ptr > geom = std::make_shared >(); if (!mapnik::from_wkt(wkt, *geom)) throw std::runtime_error("Failed to parse WKT geometry"); return geom; } std::shared_ptr > from_geojson_impl(std::string const& json) { std::shared_ptr > geom = std::make_shared >(); if (!mapnik::json::from_geojson(json, *geom)) throw std::runtime_error("Failed to parse geojson geometry"); return geom; } } inline std::string boost_version() { std::ostringstream s; s << BOOST_VERSION/100000 << "." << BOOST_VERSION/100 % 1000 << "." << BOOST_VERSION % 100; return s.str(); } PyObject* to_wkb_impl(mapnik::geometry::geometry const& geom, mapnik::wkbByteOrder byte_order) { mapnik::util::wkb_buffer_ptr wkb = mapnik::util::to_wkb(geom,byte_order); if (wkb) { return #if PY_VERSION_HEX >= 0x03000000 ::PyBytes_FromStringAndSize #else ::PyString_FromStringAndSize #endif ((const char*)wkb->buffer(),wkb->size()); } else { Py_RETURN_NONE; } } std::string to_geojson_impl(mapnik::geometry::geometry const& geom) { std::string wkt; if (!mapnik::util::to_geojson(wkt, geom)) { throw std::runtime_error("Generate JSON failed"); } return wkt; } std::string to_wkt_impl(mapnik::geometry::geometry const& geom) { std::string wkt; if (!mapnik::util::to_wkt(wkt,geom)) { throw std::runtime_error("Generate WKT failed"); } return wkt; } mapnik::geometry::geometry_types geometry_type_impl(mapnik::geometry::geometry const& geom) { return mapnik::geometry::geometry_type(geom); } mapnik::box2d geometry_envelope_impl(mapnik::geometry::geometry const& geom) { return mapnik::geometry::envelope(geom); } // Mapnik requires Boost >= 1.58 for the is_valid and is_simple functions #if BOOST_VERSION >= 105800 bool geometry_is_valid_impl(mapnik::geometry::geometry const& geom) { return mapnik::geometry::is_valid(geom); } bool geometry_is_simple_impl(mapnik::geometry::geometry const& geom) { return mapnik::geometry::is_simple(geom); } #endif bool geometry_is_empty_impl(mapnik::geometry::geometry const& geom) { return mapnik::geometry::is_empty(geom); } void geometry_correct_impl(mapnik::geometry::geometry & geom) { mapnik::geometry::correct(geom); } void line_string_add_coord_impl1(mapnik::geometry::line_string & l, double x, double y) { l.emplace_back(x, y); } void line_string_add_coord_impl2(mapnik::geometry::line_string & l, mapnik::geometry::point const& p) { l.push_back(p); } void linear_ring_add_coord_impl1(mapnik::geometry::linear_ring & l, double x, double y) { l.emplace_back(x, y); } void linear_ring_add_coord_impl2(mapnik::geometry::linear_ring & l, mapnik::geometry::point const& p) { l.push_back(p); } void polygon_add_ring_impl(mapnik::geometry::polygon & poly, mapnik::geometry::linear_ring const& ring) { poly.push_back(ring); // copy } mapnik::geometry::point geometry_centroid_impl(mapnik::geometry::geometry const& geom) { mapnik::geometry::point pt; mapnik::geometry::centroid(geom, pt); return pt; } void export_geometry() { using namespace boost::python; implicitly_convertible, mapnik::geometry::geometry >(); implicitly_convertible, mapnik::geometry::geometry >(); implicitly_convertible, mapnik::geometry::geometry >(); enum_("GeometryType") .value("Unknown",mapnik::geometry::geometry_types::Unknown) .value("Point",mapnik::geometry::geometry_types::Point) .value("LineString",mapnik::geometry::geometry_types::LineString) .value("Polygon",mapnik::geometry::geometry_types::Polygon) .value("MultiPoint",mapnik::geometry::geometry_types::MultiPoint) .value("MultiLineString",mapnik::geometry::geometry_types::MultiLineString) .value("MultiPolygon",mapnik::geometry::geometry_types::MultiPolygon) .value("GeometryCollection",mapnik::geometry::geometry_types::GeometryCollection) ; enum_("wkbByteOrder") .value("XDR",mapnik::wkbXDR) .value("NDR",mapnik::wkbNDR) ; using mapnik::geometry::geometry; using mapnik::geometry::point; using mapnik::geometry::line_string; using mapnik::geometry::linear_ring; using mapnik::geometry::polygon; class_ >("Point", init((arg("x"), arg("y")), "Constructs a new Point object\n")) .add_property("x", &point::x, "X coordinate") .add_property("y", &point::y, "Y coordinate") #if BOOST_VERSION >= 105800 .def("is_valid", &geometry_is_valid_impl) .def("is_simple", &geometry_is_simple_impl) #endif .def("to_geojson",&to_geojson_impl) .def("to_wkb",&to_wkb_impl) .def("to_wkt",&to_wkt_impl) ; class_ >("LineString", init<>( "Constructs a new LineString object\n")) .def("add_coord", &line_string_add_coord_impl1, "Adds coord x,y") .def("add_point", &line_string_add_coord_impl2, "Adds point") #if BOOST_VERSION >= 105800 .def("is_valid", &geometry_is_valid_impl) .def("is_simple", &geometry_is_simple_impl) #endif .def("to_geojson",&to_geojson_impl) .def("to_wkb",&to_wkb_impl) .def("to_wkt",&to_wkt_impl) ; class_ >("LinearRing", init<>( "Constructs a new LinearRtring object\n")) .def("add_coord", &linear_ring_add_coord_impl1, "Adds coord x,y") .def("add_point", &linear_ring_add_coord_impl2, "Adds point") ; class_ >("Polygon", init<>( "Constructs a new Polygon object\n")) .def("add_ring", &polygon_add_ring_impl, "Add ring") .def("num_rings", &polygon::size, "Number of rings") #if BOOST_VERSION >= 105800 .def("is_valid", &geometry_is_valid_impl) .def("is_simple", &geometry_is_simple_impl) #endif .def("to_geojson",&to_geojson_impl) .def("to_wkb",&to_wkb_impl) .def("to_wkt",&to_wkt_impl) ; class_, std::shared_ptr >, boost::noncopyable>("Geometry",no_init) .def("envelope",&geometry_envelope_impl) .def("from_geojson", from_geojson_impl) .def("from_wkt", from_wkt_impl) .def("from_wkb", from_wkb_impl) .staticmethod("from_geojson") .staticmethod("from_wkt") .staticmethod("from_wkb") .def("__str__",&to_wkt_impl) .def("type",&geometry_type_impl) #if BOOST_VERSION >= 105800 .def("is_valid", &geometry_is_valid_impl) .def("is_simple", &geometry_is_simple_impl) #endif .def("is_empty", &geometry_is_empty_impl) .def("correct", &geometry_correct_impl) .def("centroid",&geometry_centroid_impl) .def("to_wkb",&to_wkb_impl) .def("to_wkt",&to_wkt_impl) .def("to_geojson",&to_geojson_impl) //.def("to_svg",&to_svg) // TODO add other geometry_type methods ; }