diff --git a/include/mapnik/json/topojson_grammar.hpp b/include/mapnik/json/topojson_grammar.hpp index 47708def7..77c58c26a 100644 --- a/include/mapnik/json/topojson_grammar.hpp +++ b/include/mapnik/json/topojson_grammar.hpp @@ -42,6 +42,138 @@ namespace qi = boost::spirit::qi; namespace fusion = boost::fusion; using space_type = mapnik::json::space_type; +struct create_point +{ + using result_type = mapnik::topojson::point; + template + result_type operator()(T0 & coord, T1 & props) const + { + mapnik::topojson::point pt; + if (coord.template is()) + { + auto const& coord_ = coord.template get(); + pt.coord = coord_; + pt.props = props; + } + return pt; + } +}; + +struct create_multi_point +{ + using result_type = mapnik::topojson::multi_point; + template + result_type operator()(T0 & coords, T1 & props) const + { + mapnik::topojson::multi_point mpt; + if (coords.template is>()) + { + auto const& points = coords.template get>(); + mpt. points = points; + mpt.props = props; + } + return mpt; + } +}; + +struct create_line_string +{ + using result_type = mapnik::topojson::linestring; + template + result_type operator()(T0 & arcs, T1 & props) const + { + mapnik::topojson::linestring line; + if (arcs.template is>()) + { + auto const& arcs_ = arcs.template get>(); + line.rings = arcs_; + line.props = props; + } + return line; + } +}; + +struct create_multi_line_string +{ + using result_type = mapnik::topojson::multi_linestring; + template + result_type operator()(T0 & arcs, T1 & props) const + { + mapnik::topojson::multi_linestring mline; + if (arcs.template is>>()) + { + auto const& arcs_ = arcs.template get>>(); + mline.lines = arcs_; + mline.props = props; + } + return mline; + } +}; + +struct create_polygon +{ + using result_type = mapnik::topojson::polygon; + template + result_type operator()(T0 & arcs, T1 & props) const + { + mapnik::topojson::polygon poly; + if (arcs.template is>>()) + { + auto const& arcs_ = arcs.template get>>(); + poly.rings = arcs_; + poly.props = props; + } + return poly; + } +}; + +struct create_multi_polygon +{ + using result_type = mapnik::topojson::multi_polygon; + template + result_type operator()(T0 & arcs, T1 & props) const + { + mapnik::topojson::multi_polygon mpoly; + if (arcs.template is>>>()) + { + auto const& arcs_ = arcs.template get>>>(); + mpoly.polygons = arcs_; + mpoly.props = props; + } + return mpoly; + } +}; + + +struct create_geometry_impl +{ + using result_type = mapnik::topojson::geometry; + template + result_type operator()(T0 geom_type, T1 & coord, T2 & arcs, T3 & props) const + { + switch (geom_type) + { + case 1: //Point + return create_point()(coord, props); + case 2: //LineString + return create_line_string()(arcs, props); + case 3: //Polygon + return create_polygon()(arcs, props); + case 4: //MultiPoint + return create_multi_point()(coord, props); + case 5: //MultiLineString + return create_multi_line_string()(arcs, props); + case 6: //MultiPolygon + return create_multi_polygon()(arcs, props); + default: + break; + } + return mapnik::topojson::geometry(); //empty + } +}; + +using coordinates_type = util::variant>; +using arcs_type = util::variant, std::vector>, std::vector>>>; template > struct topojson_grammar : qi::grammar @@ -55,20 +187,18 @@ private: qi::rule()> objects; qi::rule()> arcs; qi::rule arc; - qi::rule coordinate; + qi::rule coordinate_; + qi::rule coordinates; qi::rule transform; qi::rule bbox; - qi::rule geometry; - qi::rule point; - qi::rule multi_point; - qi::rule linestring; - qi::rule multi_linestring; - qi::rule polygon; - qi::rule multi_polygon; + qi::rule, mapnik::topojson::geometry(), space_type> geometry; qi::rule&)> geometry_collection; qi::rule()> ring; + qi::rule>()> rings; + qi::rule rings_array; // properties qi::rule properties; + qi::symbols geometry_type_dispatch; }; }} diff --git a/include/mapnik/json/topojson_grammar_impl.hpp b/include/mapnik/json/topojson_grammar_impl.hpp index 88ac70e3f..00ae2e3cd 100644 --- a/include/mapnik/json/topojson_grammar_impl.hpp +++ b/include/mapnik/json/topojson_grammar_impl.hpp @@ -57,42 +57,6 @@ BOOST_FUSION_ADAPT_STRUCT( (double, maxy) ) -BOOST_FUSION_ADAPT_STRUCT( - mapnik::topojson::point, - (mapnik::topojson::coordinate, coord) - (boost::optional, props) - ) - -BOOST_FUSION_ADAPT_STRUCT( - mapnik::topojson::multi_point, - (std::vector, points) - (boost::optional, props) - ) - -BOOST_FUSION_ADAPT_STRUCT( - mapnik::topojson::linestring, - (std::vector, rings) - (boost::optional, props) - ) - -BOOST_FUSION_ADAPT_STRUCT( - mapnik::topojson::multi_linestring, - (std::vector >, lines) - (boost::optional, props) - ) - -BOOST_FUSION_ADAPT_STRUCT( - mapnik::topojson::polygon, - (std::vector >, rings) - (boost::optional, props) - ) - -BOOST_FUSION_ADAPT_STRUCT( - mapnik::topojson::multi_polygon, - (std::vector > >, polygons) - (boost::optional, props) - ) - BOOST_FUSION_ADAPT_STRUCT( mapnik::topojson::topology, (std::vector, geometries) @@ -123,13 +87,28 @@ topojson_grammar::topojson_grammar() qi::_3_type _3; qi::_4_type _4; qi::_r1_type _r1; + qi::_a_type _a; + qi::_b_type _b; + qi::_c_type _c; + qi::_d_type _d; using qi::fail; using qi::on_error; using phoenix::push_back; using phoenix::construct; + geometry_type_dispatch.add + ("\"Point\"",1) + ("\"LineString\"",2) + ("\"Polygon\"",3) + ("\"MultiPoint\"",4) + ("\"MultiLineString\"",5) + ("\"MultiPolygon\"",6) + ("\"GeometryCollection\"",7) + ; + // error handler boost::phoenix::function const error_handler; + boost::phoenix::function const create_geometry; // generic JSON types json.value = json.object | json.array | json.string_ | json.number ; @@ -185,89 +164,39 @@ topojson_grammar::topojson_grammar() >> lit('}') ; - geometry = - point | - linestring | - polygon | - multi_point | - multi_linestring | - multi_polygon | - omit[json.object] + geometry = lit('{')[_a = 0] + > ((lit("\"type\"") > lit(':') > geometry_type_dispatch[_a = _1]) + | + (lit("\"coordinates\"") > lit(':') > coordinates[_b = _1]) + | + (lit("\"arcs\"") > lit(':') > rings_array[_c = _1]) + | + properties[_d = _1] + | + json.key_value) % lit(',') + > lit('}')[_val = create_geometry(_a, _b, _c, _d)] ; + geometry_collection = lit('{') >> lit("\"type\"") >> lit(':') >> lit("\"GeometryCollection\"") - >> -(lit(',') >> omit[bbox]) - >> lit(',') >> lit("\"geometries\"") >> lit(':') >> lit('[') >> -(geometry[push_back(_r1, _1)] % lit(',')) + >> lit(',') >> lit("\"geometries\"") >> lit(':') + >> lit('[') + >> -(geometry[push_back(_r1, _1)] % lit(',')) >> lit(']') >> lit('}') ; - point = lit('{') - >> lit("\"type\"") >> lit(':') >> lit("\"Point\"") - >> -(lit(',') >> omit[bbox]) - >> ((lit(',') >> lit("\"coordinates\"") >> lit(':') >> coordinate) - ^ - (lit(',') >> properties) - ^ - (lit(',') >> omit[json.key_value])) - >> lit('}') - ; - - multi_point = lit('{') - >> lit("\"type\"") >> lit(':') >> lit("\"MultiPoint\"") - >> -(lit(',') >> omit[bbox]) - >> ((lit(',') >> lit("\"coordinates\"") >> lit(':') - >> lit('[') >> -(coordinate % lit(',')) >> lit(']')) - ^ - (lit(',') >> properties) ^ (lit(',') >> omit[json.key_value])) - >> lit('}') - ; - - linestring = lit('{') - >> lit("\"type\"") >> lit(':') >> lit("\"LineString\"") - >> (lit(',') >> (lit("\"arcs\"") >> lit(':') >> ring) - ^ - (lit(',') >> properties)) - //^ - // (lit(',') >> omit[json.key_value])) - >> lit('}') - ; - - multi_linestring = lit('{') - >> lit("\"type\"") >> lit(':') >> lit("\"MultiLineString\"") - >> -(lit(',') >> omit[bbox]) - >> ((lit(',') >> lit("\"arcs\"") >> lit(':') - >> lit('[') >> -(ring % lit(',')) >> lit(']')) - ^ - (lit(',') >> properties) - ^ - (lit(',') >> omit[json.key_value])) - >> lit('}') - ; - - polygon = lit('{') - >> lit("\"type\"") >> lit(':') >> lit("\"Polygon\"") - >> -(lit(',') >> omit[bbox]) - >> ((lit(',') >> lit("\"arcs\"") >> lit(':') - >> lit('[') >> -(ring % lit(',')) >> lit(']')) - ^ (lit(',') >> properties)) - //^ (lit(',') >> omit[json.key_value])) - >> lit('}') - ; - - multi_polygon = lit('{') - >> lit("\"type\"") >> lit(':') >> lit("\"MultiPolygon\"") - >> -(lit(',') >> omit[bbox]) - >> ((lit(',') >> lit("\"arcs\"") >> lit(':') - >> lit('[') - >> -((lit('[') >> -(ring % lit(',')) >> lit(']')) % lit(',')) - >> lit(']')) ^ (lit(',') >> properties) ^ (lit(',') >> omit[json.key_value])) - >> lit('}') - ; - ring = lit('[') >> -(int_ % lit(',')) >> lit(']') ; + rings = lit('[') >> -(ring % lit(',')) >> lit(']') + ; + rings_array = lit('[') >> -(rings % lit(',')) >> lit(']') + | + rings + | + ring + ; properties = lit("\"properties\"") >> lit(':') @@ -277,9 +206,12 @@ topojson_grammar::topojson_grammar() arcs = lit("\"arcs\"") >> lit(':') >> lit('[') >> -( arc % lit(',')) >> lit(']') ; - arc = lit('[') >> -(coordinate % lit(',')) >> lit(']') ; + arc = lit('[') >> -(coordinate_ % lit(',')) >> lit(']') ; - coordinate = lit('[') >> double_ >> lit(',') >> double_ >> lit(']'); + coordinate_ = lit('[') > double_ > lit(',') > double_ > lit(']'); + + coordinates = (lit('[') >> coordinate_ % lit(',') > lit(']')) + | coordinate_; topology.name("topology"); transform.name("transform"); @@ -287,13 +219,8 @@ topojson_grammar::topojson_grammar() arc.name("arc"); arcs.name("arcs"); json.value.name("value"); - coordinate.name("coordinate"); - - point.name("point"); - multi_point.name("multi_point"); - linestring.name("linestring"); - polygon.name("polygon"); - multi_polygon.name("multi_polygon"); + coordinate_.name("coordinate"); + geometry.name("geometry"); geometry_collection.name("geometry_collection"); // error handler on_error(topology, error_handler(_1, _2, _3, _4));