From d8005e3486b38426f6821bc9a7b4fc51e7afdf2e Mon Sep 17 00:00:00 2001 From: Artem Pavlenko Date: Mon, 20 Feb 2012 10:51:45 +0000 Subject: [PATCH] + feature/geometry geojson generator impl --- include/mapnik/json/feature_generator.hpp | 236 +++++++++++++++++ include/mapnik/json/geometry_generator.hpp | 278 +++++++++++++++++++++ 2 files changed, 514 insertions(+) create mode 100644 include/mapnik/json/feature_generator.hpp create mode 100644 include/mapnik/json/geometry_generator.hpp diff --git a/include/mapnik/json/feature_generator.hpp b/include/mapnik/json/feature_generator.hpp new file mode 100644 index 000000000..ddf6a98e5 --- /dev/null +++ b/include/mapnik/json/feature_generator.hpp @@ -0,0 +1,236 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2012 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 + * + *****************************************************************************/ +#ifndef MAPNIK_JSON_FEATURE_GENERATOR_HPP +#define MAPNIK_JSON_FEATURE_GENERATOR_HPP + +// mapnik +#include +#include +#include + +// boost +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { namespace spirit { namespace traits { + +template <> +struct is_container : mpl::false_ {} ; + +template <> +struct container_iterator +{ + typedef mapnik::feature_kv_iterator type; +}; + +template <> +struct begin_container +{ + static mapnik::feature_kv_iterator + call (mapnik::Feature const& f) + { + return f.begin(); + } +}; + +template <> +struct end_container +{ + static mapnik::feature_kv_iterator + call (mapnik::Feature const& f) + { + return f.end(); + } +}; + +template <> +struct transform_attribute, + mapnik::geometry_container const& ,karma::domain> +{ + typedef mapnik::geometry_container const& type; + static type pre(const boost::fusion::cons& f) + { + return boost::fusion::at >(f).paths(); + } +}; + +}}} + +namespace mapnik { namespace json { + +namespace karma = boost::spirit::karma; +namespace phoenix = boost::phoenix; + +struct get_id +{ + template + struct result { typedef int type; }; + + int operator() (mapnik::Feature const& f) const + { + return f.id(); + } +}; + +struct make_properties_range +{ + typedef boost::iterator_range properties_range_type; + + template + struct result { typedef properties_range_type type; }; + + properties_range_type operator() (mapnik::Feature const& f) const + { + return boost::make_iterator_range(f.begin(),f.end()); + } +}; + + +struct utf8 +{ + template + struct result { typedef std::string type; }; + + std::string operator() (UnicodeString const& ustr) const + { + std::string result; + to_utf8(ustr,result); + return result; + } +}; + +struct value_base +{ + template + struct result { typedef mapnik::value_base const& type; }; + + mapnik::value_base const& operator() (mapnik::value const& val) const + { + return val.base(); + } +}; + +template +struct escaped_string + : karma::grammar +{ + escaped_string() + : escaped_string::base_type(esc_str) + { + using boost::spirit::karma::maxwidth; + using boost::spirit::karma::right_align; + + esc_char.add('\a', "\\a")('\b', "\\b")('\f', "\\f")('\n', "\\n") + ('\r', "\\r")('\t', "\\t")('\v', "\\v")('\\', "\\\\") + ('\'', "\\\'")('\"', "\\\"") + ; + + esc_str = karma::lit(karma::_r1) + << *(esc_char + | karma::print + | "\\u" << right_align(4,karma::lit('0'))[karma::hex]) + << karma::lit(karma::_r1) + ; + } + + karma::rule esc_str; + karma::symbols esc_char; + +}; + +template +struct feature_generator: + karma::grammar +{ + typedef boost::tuple pair_type; + typedef make_properties_range::properties_range_type range_type; + + feature_generator() + : feature_generator::base_type(feature) + , quote_("\"") + + { + using boost::spirit::karma::lit; + using boost::spirit::karma::uint_; + using boost::spirit::karma::bool_; + using boost::spirit::karma::int_; + using boost::spirit::karma::double_; + using boost::spirit::karma::_val; + using boost::spirit::karma::_1; + using boost::spirit::karma::_r1; + using boost::spirit::karma::string; + using boost::spirit::karma::eps; + + feature = lit("{\"type\":\"Feature\",\"id\":") + << uint_[_1 = id_(_val)] + << lit(",\"geometry\":") << geometry + << lit(",\"properties\":") << properties + << lit('}') + ; + + properties = lit('{') + << pair % lit(',') + << lit('}') + ; + + pair = lit('"') + << string[_1 = phoenix::at_c<0>(_val)] << lit('"') + << lit(':') + << value(phoenix::at_c<1>(_val)) + ; + + value = (value_null_| bool_ | int_| double_ | ustring)[_1 = value_base_(_r1)] + ; + + value_null_ = string[_1 = "null"] + ; + + ustring = escaped_string_(quote_.c_str())[_1 = utf8_(_val)] + ; + } + + // rules + karma::rule feature; + multi_geometry_generator geometry; + escaped_string escaped_string_; + karma::rule properties; + karma::rule pair; + karma::rule value; + karma::rule value_null_; + karma::rule ustring; + // phoenix functions + phoenix::function id_; + phoenix::function value_base_; + phoenix::function utf8_; + std::string quote_; +}; + +}} + +#endif // MAPNIK_JSON_FEATURE_GENERATOR_HPP diff --git a/include/mapnik/json/geometry_generator.hpp b/include/mapnik/json/geometry_generator.hpp new file mode 100644 index 000000000..ef983a796 --- /dev/null +++ b/include/mapnik/json/geometry_generator.hpp @@ -0,0 +1,278 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2012 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_JSON_GEOMETRY_GENERATOR_HPP +#define MAPNIK_JSON_GEOMETRY_GENERATOR_HPP + +// mapnik +#include +#include +#include +#include +// boost +#include +#include +#include +#include +#include +#include +#include +#include + + +//#define BOOST_SPIRIT_USE_PHOENIX_V3 1 + +namespace boost { namespace spirit { namespace traits { + +// make gcc and darwin toolsets happy. +template <> +struct is_container + : mpl::false_ +{}; + +}}} + +namespace mapnik { namespace json { + +namespace karma = boost::spirit::karma; +namespace phoenix = boost::phoenix; + +namespace { + +struct get_type +{ + template + struct result { typedef int type; }; + + int operator() (geometry_type const& geom) const + { + return static_cast(geom.type()); + } +}; + +struct get_first +{ + template + struct result { typedef geometry_type::value_type const type; }; + + geometry_type::value_type const operator() (geometry_type const& geom) const + { + geometry_type::value_type coord; + boost::get<0>(coord) = geom.get_vertex(0,&boost::get<1>(coord),&boost::get<2>(coord)); + return coord; + } +}; + +struct multi_geometry_type +{ + template + struct result { typedef boost::tuple type; }; + + boost::tuple operator() (geometry_container const& geom) const + { + unsigned type = 0u; + bool collection = false; + + geometry_container::const_iterator itr = geom.begin(); + geometry_container::const_iterator end = geom.end(); + + for ( ; itr != end; ++itr) + { + if (type != 0u && itr->type() != type) + { + collection = true; + break; + } + type = itr->type(); + } + if (geom.size() > 1) type +=3; + return boost::tuple(type, collection); + } +}; + + +template +struct json_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 12 ;} +}; + +} + +template +struct geometry_generator : + karma::grammar +{ + + geometry_generator() + : geometry_generator::base_type(coordinates) + { + using boost::spirit::karma::uint_; + using boost::spirit::karma::_val; + using boost::spirit::karma::_1; + using boost::spirit::karma::lit; + using boost::spirit::karma::_a; + using boost::spirit::karma::_r1; + using boost::spirit::karma::eps; + using boost::spirit::karma::string; + + coordinates = point | linestring | polygon + ; + + point = &uint_(mapnik::Point)[_1 = _type(_val)] + << point_coord [_1 = _first(_val)] + ; + + linestring = &uint_(mapnik::LineString)[_1 = _type(_val)] + << lit('[') + << coords + << lit(']') + ; + + polygon = &uint_(mapnik::Polygon)[_1 = _type(_val)] + << lit('[') + << coords2 + << lit("]]") + ; + + point_coord = &uint_ + << lit('[') + << coord_type << lit(',') << coord_type + << lit("]") + ; + + polygon_coord %= ( &uint_(mapnik::SEG_MOVETO) << eps[_r1 += 1] + << string[ if_ (_r1 > 1) [_1 = "],["] + .else_[_1 = '[' ]] | &uint_ << lit(',')) + << lit('[') << coord_type + << lit(',') + << coord_type << lit(']') + ; + + coords2 %= *polygon_coord(_a) + ; + + coords = point_coord % lit(',') + ; + + } + // rules + karma::rule coordinates; + karma::rule point; + karma::rule linestring; + karma::rule polygon; + + karma::rule coords; + karma::rule, geometry_type const& ()> coords2; + karma::rule point_coord; + karma::rule polygon_coord; + + // phoenix functions + phoenix::function _type; + phoenix::function _first; + // + karma::real_generator > coord_type; + +}; + + +template +struct multi_geometry_generator : + karma::grammar >, + geometry_container const& ()> +{ + + multi_geometry_generator() + : multi_geometry_generator::base_type(start) + { + using boost::spirit::karma::lit; + using boost::spirit::karma::eps; + using boost::spirit::karma::_val; + using boost::spirit::karma::_1; + using boost::spirit::karma::_a; + using boost::spirit::karma::_r1; + using boost::spirit::karma::string; + + geometry_types.add + (mapnik::Point,"\"Point\"") + (mapnik::LineString,"\"LineString\"") + (mapnik::Polygon,"\"Polygon\"") + (mapnik::Point + 3,"\"MultiPoint\"") + (mapnik::LineString + 3,"\"MultiLineString\"") + (mapnik::Polygon + 3,"\"MultiPolygon\"") + ; + + start %= ( eps(phoenix::at_c<1>(_a))[_a = _multi_type(_val)] + << lit("{\"type\":\"GeometryCollection\",\"geometries\":[") + << geometry_collection << lit("]}") + | + geometry) + ; + + geometry_collection = -(geometry2 % lit(',')) + ; + + geometry = (lit("{\"type\":") + << geometry_types[_1 = phoenix::at_c<0>(_a)][_a = _multi_type(_val)] + << lit(",\"coordinates\":") + << string[ if_ (phoenix::at_c<0>(_a) > 3) [_1 = '[']] + << coordinates + << string[ if_ (phoenix::at_c<0>(_a) > 3) [_1 = ']']] + << lit('}')) | lit("null") + ; + + geometry2 = lit("{\"type\":") + << geometry_types[_1 = _a][_a = type_(_val)] + << lit(",\"coordinates\":") + << path + << lit('}') + ; + + coordinates %= path % lit(',') + ; + + } + // rules + karma::rule >, + geometry_container const&()> start; + karma::rule >, + geometry_container const&()> geometry_collection; + karma::rule >, + geometry_container const&()> geometry; + karma::rule, + geometry_type const&()> geometry2; + karma::rule coordinates; + geometry_generator path; + // phoenix + phoenix::function _multi_type; + phoenix::function type_; + // symbols table + karma::symbols geometry_types; +}; + +}} + +#endif // MAPNIK_JSON_GEOMETRY_GENERATOR_HPP