topojson grammar - re-factor to allow geometry elements to be in any order

This commit is contained in:
artemp 2016-05-23 10:51:05 +02:00
parent fee0ad05ce
commit 01967cfaff
2 changed files with 183 additions and 126 deletions

View file

@ -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 <typename T0, typename T1>
result_type operator()(T0 & coord, T1 & props) const
{
mapnik::topojson::point pt;
if (coord.template is<mapnik::topojson::coordinate>())
{
auto const& coord_ = coord.template get<mapnik::topojson::coordinate>();
pt.coord = coord_;
pt.props = props;
}
return pt;
}
};
struct create_multi_point
{
using result_type = mapnik::topojson::multi_point;
template <typename T0, typename T1>
result_type operator()(T0 & coords, T1 & props) const
{
mapnik::topojson::multi_point mpt;
if (coords.template is<std::vector<mapnik::topojson::coordinate>>())
{
auto const& points = coords.template get<std::vector<mapnik::topojson::coordinate>>();
mpt. points = points;
mpt.props = props;
}
return mpt;
}
};
struct create_line_string
{
using result_type = mapnik::topojson::linestring;
template <typename T0, typename T1>
result_type operator()(T0 & arcs, T1 & props) const
{
mapnik::topojson::linestring line;
if (arcs.template is<std::vector<index_type>>())
{
auto const& arcs_ = arcs.template get<std::vector<index_type>>();
line.rings = arcs_;
line.props = props;
}
return line;
}
};
struct create_multi_line_string
{
using result_type = mapnik::topojson::multi_linestring;
template <typename T0, typename T1>
result_type operator()(T0 & arcs, T1 & props) const
{
mapnik::topojson::multi_linestring mline;
if (arcs.template is<std::vector<std::vector<index_type>>>())
{
auto const& arcs_ = arcs.template get<std::vector<std::vector<index_type>>>();
mline.lines = arcs_;
mline.props = props;
}
return mline;
}
};
struct create_polygon
{
using result_type = mapnik::topojson::polygon;
template <typename T0, typename T1>
result_type operator()(T0 & arcs, T1 & props) const
{
mapnik::topojson::polygon poly;
if (arcs.template is<std::vector<std::vector<index_type>>>())
{
auto const& arcs_ = arcs.template get<std::vector<std::vector<index_type>>>();
poly.rings = arcs_;
poly.props = props;
}
return poly;
}
};
struct create_multi_polygon
{
using result_type = mapnik::topojson::multi_polygon;
template <typename T0, typename T1>
result_type operator()(T0 & arcs, T1 & props) const
{
mapnik::topojson::multi_polygon mpoly;
if (arcs.template is<std::vector<std::vector<std::vector<index_type>>>>())
{
auto const& arcs_ = arcs.template get<std::vector<std::vector<std::vector<index_type>>>>();
mpoly.polygons = arcs_;
mpoly.props = props;
}
return mpoly;
}
};
struct create_geometry_impl
{
using result_type = mapnik::topojson::geometry;
template <typename T0, typename T1, typename T2, typename T3>
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<coordinate,std::vector<coordinate>>;
using arcs_type = util::variant<std::vector<index_type>, std::vector<std::vector<index_type>>, std::vector<std::vector<std::vector<index_type>>>>;
template <typename Iterator, typename ErrorHandler = json::error_handler<Iterator> >
struct topojson_grammar : qi::grammar<Iterator, space_type, topology()>
@ -55,20 +187,18 @@ private:
qi::rule<Iterator, space_type, std::vector<mapnik::topojson::geometry>()> objects;
qi::rule<Iterator, space_type, std::vector<mapnik::topojson::arc>()> arcs;
qi::rule<Iterator, space_type, mapnik::topojson::arc()> arc;
qi::rule<Iterator, space_type, mapnik::topojson::coordinate()> coordinate;
qi::rule<Iterator, space_type, mapnik::topojson::coordinate()> coordinate_;
qi::rule<Iterator, space_type, coordinates_type()> coordinates;
qi::rule<Iterator, space_type, mapnik::topojson::transform()> transform;
qi::rule<Iterator, space_type, mapnik::topojson::bounding_box()> bbox;
qi::rule<Iterator, space_type, mapnik::topojson::geometry() > geometry;
qi::rule<Iterator, space_type, mapnik::topojson::point()> point;
qi::rule<Iterator, space_type, mapnik::topojson::multi_point()> multi_point;
qi::rule<Iterator, space_type, mapnik::topojson::linestring()> linestring;
qi::rule<Iterator, space_type, mapnik::topojson::multi_linestring()> multi_linestring;
qi::rule<Iterator, space_type, mapnik::topojson::polygon()> polygon;
qi::rule<Iterator, space_type, mapnik::topojson::multi_polygon()> multi_polygon;
qi::rule<Iterator, qi::locals<int, coordinates_type, arcs_type, properties>, mapnik::topojson::geometry(), space_type> geometry;
qi::rule<Iterator, space_type, void(std::vector<mapnik::topojson::geometry>&)> geometry_collection;
qi::rule<Iterator, space_type, std::vector<index_type>()> ring;
qi::rule<Iterator, space_type, std::vector<std::vector<index_type>>()> rings;
qi::rule<Iterator, space_type, arcs_type()> rings_array;
// properties
qi::rule<Iterator, space_type, mapnik::topojson::properties()> properties;
qi::symbols<char, int> geometry_type_dispatch;
};
}}

View file

@ -57,42 +57,6 @@ BOOST_FUSION_ADAPT_STRUCT(
(double, maxy)
)
BOOST_FUSION_ADAPT_STRUCT(
mapnik::topojson::point,
(mapnik::topojson::coordinate, coord)
(boost::optional<mapnik::topojson::properties>, props)
)
BOOST_FUSION_ADAPT_STRUCT(
mapnik::topojson::multi_point,
(std::vector<mapnik::topojson::coordinate>, points)
(boost::optional<mapnik::topojson::properties>, props)
)
BOOST_FUSION_ADAPT_STRUCT(
mapnik::topojson::linestring,
(std::vector<mapnik::topojson::index_type>, rings)
(boost::optional<mapnik::topojson::properties>, props)
)
BOOST_FUSION_ADAPT_STRUCT(
mapnik::topojson::multi_linestring,
(std::vector<std::vector<mapnik::topojson::index_type> >, lines)
(boost::optional<mapnik::topojson::properties>, props)
)
BOOST_FUSION_ADAPT_STRUCT(
mapnik::topojson::polygon,
(std::vector<std::vector<mapnik::topojson::index_type> >, rings)
(boost::optional<mapnik::topojson::properties>, props)
)
BOOST_FUSION_ADAPT_STRUCT(
mapnik::topojson::multi_polygon,
(std::vector<std::vector<std::vector<mapnik::topojson::index_type> > >, polygons)
(boost::optional<mapnik::topojson::properties>, props)
)
BOOST_FUSION_ADAPT_STRUCT(
mapnik::topojson::topology,
(std::vector<mapnik::topojson::geometry>, geometries)
@ -123,13 +87,28 @@ topojson_grammar<Iterator, ErrorHandler>::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<ErrorHandler> const error_handler;
boost::phoenix::function<create_geometry_impl> const create_geometry;
// generic JSON types
json.value = json.object | json.array | json.string_ | json.number
;
@ -185,89 +164,39 @@ topojson_grammar<Iterator, ErrorHandler>::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<Iterator, ErrorHandler>::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<Iterator, ErrorHandler>::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<fail>(topology, error_handler(_1, _2, _3, _4));