upgrade WKT grammar to boost::spirit::x3

This commit is contained in:
artemp 2016-09-13 15:11:05 +02:00
parent 46fe1d6f4a
commit e4e628ecd5
6 changed files with 187 additions and 290 deletions

View file

@ -2,7 +2,7 @@
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2015 Artem Pavlenko
* Copyright (C) 2016 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -25,24 +25,12 @@
// mapnik
#include <mapnik/geometry.hpp>
#include <mapnik/wkt/wkt_grammar.hpp>
#include <mapnik/wkt/wkt_generator_grammar.hpp>
// stl
#include <string>
namespace mapnik {
inline bool from_wkt(std::string const& wkt, mapnik::geometry::geometry<double> & geom)
{
using namespace boost::spirit;
static const mapnik::wkt::wkt_grammar<std::string::const_iterator> g;
ascii::space_type space;
std::string::const_iterator first = wkt.begin();
std::string::const_iterator last = wkt.end();
return qi::phrase_parse(first, last, (g)(boost::phoenix::ref(geom)), space);
}
bool from_wkt(std::string const& wkt, mapnik::geometry::geometry<double> & geom);
}

View file

@ -1,117 +0,0 @@
/*****************************************************************************
*
* 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
*
*****************************************************************************/
#ifndef MAPNIK_WKT_GRAMMAR_HPP
#define MAPNIK_WKT_GRAMMAR_HPP
// mapnik
#include <mapnik/config.hpp>
#include <mapnik/geometry.hpp>
#pragma GCC diagnostic push
#include <mapnik/warning_ignore.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_function.hpp>
#pragma GCC diagnostic pop
namespace mapnik { namespace wkt {
using namespace boost::spirit;
namespace detail {
struct assign
{
using result_type = void;
template <typename T0, typename T1>
void operator() (T0 & geom, T1 && obj) const
{
geom = std::move(obj);
}
};
struct move_part
{
using result_type = void;
template <typename Geometry, typename Part>
void operator() (Geometry & geom, Part && part) const
{
geom.push_back(std::move(part));
}
};
struct set_exterior
{
using result_type = void;
template <typename Polygon, typename Ring>
void operator() (Polygon & poly, Ring && ring) const
{
poly.set_exterior_ring(std::move(ring));
}
};
struct add_hole
{
using result_type = void;
template <typename Polygon, typename Ring>
void operator() (Polygon & poly, Ring && ring) const
{
poly.add_hole(std::move(ring));
}
};
}
template <typename Iterator>
struct wkt_grammar : qi::grammar<Iterator, void(mapnik::geometry::geometry<double> &) , ascii::space_type>
{
wkt_grammar();
qi::rule<Iterator, void(mapnik::geometry::geometry<double> &), ascii::space_type> geometry_tagged_text;
qi::rule<Iterator, void(mapnik::geometry::geometry<double> &), ascii::space_type> point_tagged_text;
qi::rule<Iterator, void(mapnik::geometry::geometry<double> &), ascii::space_type> linestring_tagged_text;
qi::rule<Iterator, void(mapnik::geometry::geometry<double> &), ascii::space_type> polygon_tagged_text;
qi::rule<Iterator, void(mapnik::geometry::geometry<double> &), ascii::space_type> multipoint_tagged_text;
qi::rule<Iterator, void(mapnik::geometry::geometry<double> &), ascii::space_type> multilinestring_tagged_text;
qi::rule<Iterator, void(mapnik::geometry::geometry<double> &), ascii::space_type> multipolygon_tagged_text;
qi::rule<Iterator, void(mapnik::geometry::geometry<double> &), ascii::space_type> geometrycollection_tagged_text;
qi::rule<Iterator, mapnik::geometry::point<double>(), ascii::space_type> point_text;
qi::rule<Iterator, mapnik::geometry::line_string<double>(), ascii::space_type> linestring_text;
qi::rule<Iterator, mapnik::geometry::linear_ring<double>(), ascii::space_type> linearring_text;
qi::rule<Iterator, mapnik::geometry::polygon<double>(), ascii::space_type> polygon_text;
qi::rule<Iterator, mapnik::geometry::multi_point<double>(), ascii::space_type> multipoint_text;
qi::rule<Iterator, mapnik::geometry::multi_line_string<double>(), ascii::space_type> multilinestring_text;
qi::rule<Iterator, mapnik::geometry::multi_polygon<double>(), ascii::space_type> multipolygon_text;
qi::rule<Iterator, qi::locals<mapnik::geometry::geometry<double> >,
mapnik::geometry::geometry_collection<double>(), ascii::space_type> geometrycollection_text;
qi::rule<Iterator, mapnik::geometry::point<double>(), ascii::space_type> point;
qi::rule<Iterator, mapnik::geometry::line_string<double>(), ascii::space_type> points;
qi::rule<Iterator, mapnik::geometry::linear_ring<double>(), ascii::space_type> ring_points;
qi::rule<Iterator,ascii::space_type> empty_set;
boost::phoenix::function<detail::assign> assign;
boost::phoenix::function<detail::move_part> move_part;
boost::phoenix::function<detail::set_exterior> set_exterior;
boost::phoenix::function<detail::add_hole> add_hole;
};
}}
#endif // MAPNIK_WKT_GRAMMAR_HPP

View file

@ -1,154 +0,0 @@
/*****************************************************************************
*
* 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 <mapnik/wkt/wkt_grammar.hpp>
#include <mapnik/geometry/fusion_adapted.hpp>
#pragma GCC diagnostic push
#include <mapnik/warning_ignore.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/phoenix/object/construct.hpp>
#pragma GCC diagnostic pop
namespace mapnik { namespace wkt {
using namespace boost::spirit;
template <typename Iterator>
wkt_grammar<Iterator>::wkt_grammar()
: wkt_grammar::base_type(geometry_tagged_text)
{
qi::eps_type eps;
qi::_r1_type _r1;
qi::_val_type _val;
qi::lit_type lit;
qi::no_case_type no_case;
qi::double_type double_;
qi::_1_type _1;
qi::_a_type _a;
using boost::phoenix::construct;
geometry_tagged_text = point_tagged_text(_r1)
| linestring_tagged_text(_r1)
| polygon_tagged_text(_r1)
| multipoint_tagged_text(_r1)
| multilinestring_tagged_text(_r1)
| multipolygon_tagged_text(_r1)
| geometrycollection_tagged_text(_r1)
;
// <point tagged text> ::= point <point text>
point_tagged_text = no_case[lit("POINT")]
>> (point_text[assign(_r1,_1)] | empty_set[assign(_r1,construct<geometry::geometry_empty>())])
;
// <point text> ::= <empty set> | <left paren> <point> <right paren>
point_text = (lit("(") >> point >> lit(')'))
//| empty_set - we're catching 'POINT EMPTY' case in point_tagged_text rule ^^ by creating geometry_empty
// because our geometry::point<double> can't be empty
;
//<linestring tagged text> ::= linestring <linestring text>
linestring_tagged_text = no_case[lit("LINESTRING")]
>> linestring_text[assign(_r1,_1)]
;
// <linestring text> ::= <empty set> | <left paren> <point> {<comma> <point>}* <right paren>
linestring_text = points | empty_set
;
// <polygon tagged text> ::= polygon <polygon text>
polygon_tagged_text = no_case[lit("POLYGON")]
>> polygon_text[assign(_r1,_1)]
;
// <polygon text> ::= <empty set> | <left paren> <linestring text> {<comma> <linestring text>}* <right paren>
polygon_text =
(lit('(') >> linearring_text[set_exterior(_val,_1)] >> *(lit(',') >> linearring_text[add_hole(_val,_1)]) >> lit(')'))
|
empty_set
;
linearring_text = ring_points | empty_set
;
//<multipoint tagged text> ::= multipoint <multipoint text>
multipoint_tagged_text = no_case[lit("MULTIPOINT")]
>> multipoint_text[assign(_r1,_1)]
;
// <multipoint text> ::= <empty set> | <left paren> <point text> {<comma> <point text>}* <right paren>
multipoint_text = (lit('(')
>> point_text % lit(',')
>> lit(')'))
|
(lit('(')
>> point % lit(',')
>> lit(')'))
|
empty_set
;
// <multilinestring tagged text> ::= multilinestring <multilinestring text>
multilinestring_tagged_text = no_case[lit("MULTILINESTRING")]
>> multilinestring_text[assign(_r1,_1)] ;
// <multilinestring text> ::= <empty set> | <left paren> <linestring text> {<comma> <linestring text>}* <right paren>
multilinestring_text = (lit('(')
>> points[move_part(_val,_1)] % lit(',')
>> lit(')')) | empty_set;
// <multipolygon tagged text> ::= multipolygon <multipolygon text>
multipolygon_tagged_text = no_case[lit("MULTIPOLYGON")]
>> multipolygon_text[assign(_r1,_1)] ;
//<multipolygon text> ::= <empty set> | <left paren> <polygon text> {<comma> <polygon text>}* <right paren>
multipolygon_text = (lit('(')
>> polygon_text[move_part(_val,_1)] % lit(',')
>> lit(')'))
|
empty_set;
// geometry collection tagged text
geometrycollection_tagged_text = no_case[lit("GEOMETRYCOLLECTION")]
>> geometrycollection_text[assign(_r1,_1)]
;
// geometry collection text
geometrycollection_text = (lit('(')
>> ( eps[_a = construct<geometry::geometry<double> >()]
>> geometry_tagged_text(_a)[move_part(_val,_a)] % lit(','))
>> lit(')'))
|
empty_set;
// points
points = lit('(') >> point % lit(',') >> lit(')')
;
// ring points
ring_points = lit('(') >> point % lit(',') >> lit(')')
;
// point
point = double_ >> double_
;
// <empty set>
empty_set = no_case[lit("EMPTY")];
}
}}

View file

@ -0,0 +1,49 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2016 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_WKT_GRAMMAR_X3_HPP
#define MAPNIK_WKT_GRAMMAR_X3_HPP
#pragma GCC diagnostic push
#include <mapnik/warning_ignore.hpp>
#include <boost/spirit/home/x3.hpp>
#pragma GCC diagnostic pop
#include <mapnik/geometry.hpp>
namespace mapnik { namespace grammar {
namespace x3 = boost::spirit::x3;
struct wkt_class; // top-most ID
using wkt_grammar_type = x3::rule<wkt_class, mapnik::geometry::geometry<double>>;
BOOST_SPIRIT_DECLARE(wkt_grammar_type);
}}
namespace mapnik
{
grammar::wkt_grammar_type wkt_grammar();
}
#endif // MAPNIK_WKT_GRAMMAR_X3_HPP

View file

@ -0,0 +1,130 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2016 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_WKT_GRAMMAR_X3_DEF_HPP
#define MAPNIK_WKT_GRAMMAR_X3_DEF_HPP
#include <mapnik/wkt/wkt_grammar_x3.hpp>
#include <mapnik/geometry/fusion_adapted.hpp>
namespace mapnik { namespace grammar {
namespace x3 = boost::spirit::x3;
namespace ascii = boost::spirit::x3::ascii;
using x3::lit;
using x3::double_;
using x3::no_case;
// functors
auto make_empty = [](auto const& ctx)
{
_val(ctx) = geometry::geometry_empty();
};
auto set_exterior = [](auto const& ctx)
{
_val(ctx).set_exterior_ring(std::move(_attr(ctx)));
};
auto add_hole = [](auto const& ctx)
{
_val(ctx).add_hole(std::move(_attr(ctx)));
};
// start rule
wkt_grammar_type const wkt("wkt");
// rules
x3::rule<class empty, mapnik::geometry::geometry_empty> const empty("EMPTY");
x3::rule<class point, mapnik::geometry::geometry<double> > const point("POINT");
x3::rule<class line_string, mapnik::geometry::line_string<double> > const line_string("LINESTRING");
x3::rule<class polygon, mapnik::geometry::polygon<double> > const polygon("POLYGON");
x3::rule<class multi_point, mapnik::geometry::multi_point<double> > const multi_point("MULTIPOINT");
x3::rule<class multi_line_string, mapnik::geometry::multi_line_string<double> > const multi_line_string("MULTILINESTRING");
x3::rule<class multi_polygon, mapnik::geometry::multi_polygon<double> > const multi_polygon("MULTIPOLYGON");
x3::rule<class geometry_collection, mapnik::geometry::geometry_collection<double> > const geometry_collection("GEOMETRYCOLLECTION");
x3::rule<class point_text, mapnik::geometry::point<double> > const point_text("point-text");
x3::rule<class positions, mapnik::geometry::line_string<double> > const positions("positions");
x3::rule<class polygon_rings, mapnik::geometry::polygon<double> > const polygon_rings("polygon-rings");
x3::rule<class points, mapnik::geometry::multi_point<double> > const points("points");
x3::rule<class lines, mapnik::geometry::multi_line_string<double> > const lines("lines");
x3::rule<class polygons, mapnik::geometry::multi_polygon<double> > const polygons("polygons");
x3::rule<class geometries, mapnik::geometry::geometry_collection<double> > const geometries("geometries");
auto const point_text_def = '(' > double_ > double_ > ')';
auto const positions_def = lit('(') > (double_ > double_) % lit(',') > lit(')');
auto const polygon_rings_def = '(' > positions[set_exterior] > *(lit(',') > positions[add_hole]) > ')';
auto const points_def = (lit('(') >> ((point_text_def % ',') > lit(')'))) | positions_def ;
auto const lines_def = lit('(') > (positions_def % lit(',')) > lit(')');
auto const polygons_def = lit('(') > (polygon_rings % lit(',')) > lit(')');
auto const geometries_def = lit('(') > -(wkt % ',') > lit(')');
//
auto const wkt_def = point | line_string | polygon | multi_point | multi_line_string | multi_polygon | geometry_collection;
// EMPTY
auto const empty_def = no_case["EMPTY"][make_empty];
// POINT
auto const point_def = no_case["POINT"] > (point_text | empty);
// LINESTRING
auto const line_string_def = no_case["LINESTRING"] > (positions | no_case["EMPTY"]);
// POLYGON
auto const polygon_def = no_case["POLYGON"] > (polygon_rings | no_case["EMPTY"]);
// MULTIPOINT
auto const multi_point_def = no_case["MULTIPOINT"] > (points | no_case["EMPTY"]);
// MULTILINESTRING
auto const multi_line_string_def = no_case["MULTILINESTRING"] > (lines | no_case["EMPTY"]);
// MULTIPOLYGON
auto const multi_polygon_def = no_case["MULTIPOLYGON"] > (polygons | no_case["EMPTY"]);
// GEOMETRYCOLLECTION
auto const geometry_collection_def = no_case["GEOMETRYCOLLECTION"] > (geometries | no_case["EMPTY"]);
BOOST_SPIRIT_DEFINE(
wkt,
point_text,
positions,
points,
lines,
polygons,
geometries,
empty,
point,
line_string,
polygon_rings,
polygon,
multi_point,
multi_line_string,
multi_polygon,
geometry_collection
);
}}
namespace mapnik
{
grammar::wkt_grammar_type wkt_grammar()
{
return grammar::wkt;
}
}
#endif // MAPNIK_WKT_GRAMMAR_X3_DEF_HPP

View file

@ -2,7 +2,7 @@
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2015 Artem Pavlenko
* Copyright (C) 2016 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -20,12 +20,13 @@
*
*****************************************************************************/
#include <mapnik/wkt/wkt_grammar_impl.hpp>
#include <string>
#include <mapnik/wkt/wkt_grammar_x3_def.hpp>
namespace mapnik { namespace wkt {
namespace mapnik { namespace grammar {
namespace x3 = boost::spirit::x3;
using iterator_type = std::string::const_iterator;
template struct wkt_grammar<iterator_type>;
using context_type = x3::phrase_parse_context<x3::ascii::space_type>::type;
BOOST_SPIRIT_INSTANTIATE(wkt_grammar_type, iterator_type, context_type);
}}