diff --git a/bindings/python/mapnik_geometry.cpp b/bindings/python/mapnik_geometry.cpp index 929b7fdec..22a68eba5 100644 --- a/bindings/python/mapnik_geometry.cpp +++ b/bindings/python/mapnik_geometry.cpp @@ -117,6 +117,24 @@ std::string to_wkt( geometry_type const& geom) #endif } +std::string to_wkt2( path_type const& geom) +{ +#if BOOST_VERSION >= 104700 + std::string wkt; // Use Python String directly ? + bool result = mapnik::util::to_wkt(wkt,geom); + if (!result) + { + throw std::runtime_error("Generate WKT failed"); + } + return wkt; +#else + std::ostringstream s; + s << BOOST_VERSION/100000 << "." << BOOST_VERSION/100 % 1000 << "." << BOOST_VERSION % 100; + throw std::runtime_error("mapnik::to_wkt() requires at least boost 1.47 while your build was compiled against boost " + s.str()); +#endif +} + + void export_geometry() { using namespace boost::python; @@ -142,6 +160,7 @@ void export_geometry() .def("__len__", &path_type::size) .def("add_wkt",add_wkt_impl) .def("add_wkb",add_wkb_impl) + .def("to_wkt",&to_wkt2) .def("from_wkt",from_wkt_impl) .def("from_wkb",from_wkb_impl) .staticmethod("from_wkt") diff --git a/include/mapnik/util/geometry_to_wkt.hpp b/include/mapnik/util/geometry_to_wkt.hpp index 962909f00..42735c3a2 100644 --- a/include/mapnik/util/geometry_to_wkt.hpp +++ b/include/mapnik/util/geometry_to_wkt.hpp @@ -42,7 +42,16 @@ bool to_wkt(std::string & wkt, mapnik::geometry_type const& geom) { typedef std::back_insert_iterator sink_type; sink_type sink(wkt); - wkt_generator generator; + wkt_generator generator(true); + bool result = karma::generate(sink, generator, geom); + return result; +} + +bool to_wkt(std::string & wkt, mapnik::geometry_container const& geom) +{ + typedef std::back_insert_iterator sink_type; + sink_type sink(wkt); + wkt_multi_generator generator; bool result = karma::generate(sink, generator, geom); return result; } diff --git a/include/mapnik/util/geometry_wkt_generator.hpp b/include/mapnik/util/geometry_wkt_generator.hpp index 7ff923ce0..df7bab059 100644 --- a/include/mapnik/util/geometry_wkt_generator.hpp +++ b/include/mapnik/util/geometry_wkt_generator.hpp @@ -30,7 +30,6 @@ #include #include #include - // boost #include #include @@ -49,6 +48,8 @@ namespace mapnik { namespace util { namespace karma = boost::spirit::karma; namespace phoenix = boost::phoenix; +namespace { + struct get_type { template @@ -73,21 +74,52 @@ struct get_first } }; + +struct multi_geometry_ +{ + template + struct result { typedef bool type; }; + + bool operator() (geometry_container const& geom) const + { + return geom.size() > 1 ? true : false; + } +}; + +struct multi_geometry_type +{ + template + struct result { typedef unsigned type; }; + + unsigned operator() (geometry_container const& geom) const + { + unsigned type = 0u; + geometry_container::const_iterator itr = geom.begin(); + geometry_container::const_iterator end = geom.end(); + for ( ; itr != end; ++itr) + { + type = itr->type(); + } + return type; + } +}; + template struct coordinate_policy : karma::real_policies { typedef boost::spirit::karma::real_policies base_type; static int floatfield(T n) { return base_type::fmtflags::fixed; } - static unsigned precision(T n) { return 6u ;} + static unsigned precision(T n) { return 6 ;} }; +} template struct wkt_generator : karma::grammar { - wkt_generator() + wkt_generator(bool single = false) : wkt_generator::base_type(wkt) { using boost::spirit::karma::uint_; @@ -97,22 +129,27 @@ struct wkt_generator : using boost::spirit::karma::_a; using boost::spirit::karma::_r1; using boost::spirit::karma::eps; + using boost::spirit::karma::string; wkt = point | linestring | polygon ; point = &uint_(mapnik::Point)[_1 = _type(_val)] - << lit("Point(") << point_coord [_1 = _first(_val)] << lit(')') + << string[ phoenix::if_ (single) [_1 = "Point("] + .else_[_1 = "("]] + << point_coord [_1 = _first(_val)] << lit(')') ; linestring = &uint_(mapnik::LineString)[_1 = _type(_val)] - << lit("LineString(") + << string[ phoenix::if_ (single) [_1 = "LineString("] + .else_[_1 = "("]] << coords << lit(')') ; polygon = &uint_(mapnik::Polygon)[_1 = _type(_val)] - << lit("Polygon(") + << string[ phoenix::if_ (single) [_1 = "Polygon("] + .else_[_1 = "("]] << coords2 << lit("))") ; @@ -121,8 +158,8 @@ struct wkt_generator : ; polygon_coord %= ( &uint_(mapnik::SEG_MOVETO) << eps[_r1 += 1] - << karma::string[ if_ (_r1 > 1) [_1 = "),("] - .else_[_1 = "("] ] | &uint_ << ",") + << string[ if_ (_r1 > 1) [_1 = "),("] + .else_[_1 = "("] ] | &uint_ << ",") << coord_type << lit(' ') << coord_type @@ -144,7 +181,7 @@ struct wkt_generator : karma::rule coords; karma::rule, geometry_type const& ()> coords2; karma::rule point_coord; - karma::rule polygon_coord; + karma::rule polygon_coord; // phoenix functions phoenix::function _type; @@ -154,6 +191,50 @@ struct wkt_generator : }; + +template +struct wkt_multi_generator : + karma::grammar +{ + + wkt_multi_generator() + : wkt_multi_generator::base_type(wkt) + { + using boost::spirit::karma::lit; + using boost::spirit::karma::eps; + using boost::spirit::karma::_val; + using boost::spirit::karma::_1; + + geometry_types.add + (mapnik::Point,"Point") + (mapnik::LineString,"LineString") + (mapnik::Polygon,"Polygon") + ; + + wkt = eps(_multi(_val)) << "Multi" << geometry_types[_1 = _type(_val)] + << "(" << multi_geometry << ")" | geometry_types[_1 = _type(_val)] + << geometry + ; + + geometry = *path + ; + + multi_geometry = -(path % lit(',')) + ; + + } + // rules + karma::rule wkt; + karma::rule geometry; + karma::rule multi_geometry; + wkt_generator path; + // phoenix + phoenix::function _multi; + phoenix::function _type; + // + karma::symbols geometry_types; +}; + }}