Skip to content

Instantly share code, notes, and snippets.

@springmeyer
Created October 8, 2014 06:52
Show Gist options
  • Save springmeyer/739672d7414dc8741df0 to your computer and use it in GitHub Desktop.
Save springmeyer/739672d7414dc8741df0 to your computer and use it in GitHub Desktop.
diff --git a/bindings/python/mapnik_generator_grammars.cpp b/bindings/python/mapnik_generator_grammars.cpp
index e621628..f6fa4d1 100644
--- a/bindings/python/mapnik_generator_grammars.cpp
+++ b/bindings/python/mapnik_generator_grammars.cpp
@@ -29,8 +29,8 @@
using sink_type = std::back_insert_iterator<std::string>;
template struct mapnik::json::feature_generator_grammar<sink_type>;
-template struct mapnik::json::geometry_generator_grammar<sink_type>;
-template struct mapnik::json::multi_geometry_generator_grammar<sink_type>;
+template struct mapnik::json::geometry_generator_grammar<sink_type, mapnik::geometry_type>;
+template struct mapnik::json::multi_geometry_generator_grammar<sink_type, mapnik::geometry_type>;
template struct mapnik::svg::svg_path_generator<sink_type, mapnik::geometry_type>;
template struct mapnik::wkt::wkt_generator<sink_type, mapnik::geometry_type>;
template struct mapnik::wkt::wkt_multi_generator<sink_type, mapnik::geometry_container>;
diff --git a/include/mapnik/json/feature_generator_grammar.hpp b/include/mapnik/json/feature_generator_grammar.hpp
index 973c682..46ddaee 100644
--- a/include/mapnik/json/feature_generator_grammar.hpp
+++ b/include/mapnik/json/feature_generator_grammar.hpp
@@ -156,7 +156,7 @@ struct feature_generator_grammar:
feature_generator_grammar();
karma::rule<OutputIterator, mapnik::feature_impl const&()> feature;
- multi_geometry_generator_grammar<OutputIterator> geometry;
+ multi_geometry_generator_grammar<OutputIterator,mapnik::geometry_container> geometry;
escaped_string<OutputIterator> escaped_string_;
karma::rule<OutputIterator, mapnik::feature_impl const&()> properties;
karma::rule<OutputIterator, pair_type()> pair;
diff --git a/include/mapnik/json/geometry_generator_grammar.hpp b/include/mapnik/json/geometry_generator_grammar.hpp
index 2d61e9f..76d8810 100644
--- a/include/mapnik/json/geometry_generator_grammar.hpp
+++ b/include/mapnik/json/geometry_generator_grammar.hpp
@@ -26,14 +26,18 @@
// mapnik
#include <mapnik/global.hpp>
#include <mapnik/geometry.hpp>
-#include <mapnik/util/path_iterator.hpp>
-#include <mapnik/util/container_adapter.hpp>
#include <mapnik/vertex.hpp> // for CommandType::SEG_MOVETO
+#include <mapnik/util/container_adapter.hpp>
// boost
#include <boost/spirit/include/karma.hpp>
+#include <boost/spirit/include/phoenix_core.hpp>
+#include <boost/spirit/include/phoenix_operator.hpp>
+#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_function.hpp>
+#include <boost/spirit/include/phoenix_statement.hpp>
#include <boost/fusion/adapted/std_tuple.hpp>
+#include <boost/type_traits/remove_pointer.hpp>
#include <boost/math/special_functions/trunc.hpp> // for vc++ and android whose c++11 libs lack std::trunc
//stl
@@ -42,54 +46,99 @@
namespace mapnik { namespace json {
namespace karma = boost::spirit::karma;
+namespace phoenix = boost::phoenix;
namespace detail {
+template <typename Geometry>
struct get_type
{
- using result_type = int;
- result_type operator() (geometry_type const& geom) const
+ template <typename T>
+ struct result { using type = int; };
+
+ int operator() (Geometry const& geom) const
{
return static_cast<int>(geom.type());
}
};
+template <typename T>
struct get_first
{
- using result_type = geometry_type::value_type const;
- result_type operator() (geometry_type const& geom) const
+ using geometry_type = T;
+
+ template <typename U>
+ struct result { using type = const typename geometry_type::value_type; };
+
+ typename geometry_type::value_type const operator() (geometry_type const& geom) const
{
- geometry_type::value_type coord;
- std::get<0>(coord) = geom.vertex(0,&std::get<1>(coord),&std::get<2>(coord));
+ typename geometry_type::value_type coord;
+ geom.rewind(0);
+ std::get<0>(coord) = geom.vertex(&std::get<1>(coord),&std::get<2>(coord));
return coord;
}
};
-struct multi_geometry_type
+template <typename T>
+struct multi_geometry_
{
- using result_type = std::tuple<unsigned,bool> ;
- result_type operator() (geometry_container const& cont) const
+ using geometry_container = T;
+
+ template <typename U>
+ struct result { using type = bool; };
+ bool operator() (geometry_container const& geom) const
{
- unsigned type = 0u;
- bool collection = false;
- for (auto const& geom : cont)
- {
- if (type != 0u && geom.type() != type)
- {
- collection = true;
- break;
- }
- type = geom.type();
- }
- if (cont.size() > 1) type +=3;
- return std::tuple<unsigned,bool>(type, collection);
+ return geom.size() > 1 ? true : false;
+ }
+};
+
+template <typename T>
+struct get_x
+{
+ using value_type = T;
+
+ template <typename U>
+ struct result { using type = double; };
+
+ double operator() (value_type const& val) const
+ {
+ return std::get<1>(val);
}
};
+template <typename T>
+struct get_y
+{
+ using value_type = T;
+
+ template <typename U>
+ struct result { using type = double; };
+
+ double operator() (value_type const& val) const
+ {
+ return std::get<2>(val);
+ }
+};
+
+template <typename T>
+struct multi_geometry_type
+{
+ using geometry_container = T;
+
+ template <typename U>
+ struct result { using type = std::tuple<unsigned,bool>; };
+
+ std::tuple<unsigned,bool> operator() (geometry_container const& geom) const;
+};
+
+template <typename Container>
struct not_empty
{
- using result_type = bool;
- result_type operator() (geometry_container const& cont) const
+
+ template <typename T>
+ struct result { using type = bool; };
+
+ bool operator() (Container const& cont) const
{
for (auto const& geom : cont)
{
@@ -104,7 +153,6 @@ struct json_coordinate_policy : karma::real_policies<T>
{
using base_type = boost::spirit::karma::real_policies<T>;
static int floatfield(T n) { return base_type::fmtflags::fixed; }
-
static unsigned precision(T n)
{
if (n == 0.0) return 0;
@@ -121,7 +169,7 @@ struct json_coordinate_policy : karma::real_policies<T>
template <typename OutputIterator>
static bool fraction_part(OutputIterator& sink, T n
- , unsigned adjprec, unsigned precision)
+ , unsigned adjprec, unsigned precision)
{
if (n == 0) return true;
return base_type::fraction_part(sink, n, adjprec, precision);
@@ -130,44 +178,47 @@ struct json_coordinate_policy : karma::real_policies<T>
}
-template <typename OutputIterator>
+template <typename OutputIterator, typename Geometry>
struct geometry_generator_grammar :
- karma::grammar<OutputIterator, geometry_type const& ()>
+ karma::grammar<OutputIterator, Geometry const& ()>
{
+ using geometry_type = Geometry;
+ using coord_type = typename boost::remove_pointer<typename geometry_type::value_type>::type;
+
geometry_generator_grammar();
- karma::rule<OutputIterator, geometry_type const& ()> coordinates;
+ karma::rule<OutputIterator, geometry_type const& ()> json;
karma::rule<OutputIterator, geometry_type const& ()> point;
karma::rule<OutputIterator, geometry_type const& ()> linestring;
karma::rule<OutputIterator, geometry_type const& ()> polygon;
karma::rule<OutputIterator, geometry_type const& ()> coords;
karma::rule<OutputIterator, karma::locals<unsigned>, geometry_type const& ()> coords2;
- karma::rule<OutputIterator, geometry_type::value_type ()> point_coord;
- karma::rule<OutputIterator, geometry_type::value_type (unsigned& )> polygon_coord;
- boost::phoenix::function<detail::get_type > _type;
- boost::phoenix::function<detail::get_first> _first;
- karma::real_generator<double, detail::json_coordinate_policy<double> > coord_type;
+ karma::rule<OutputIterator, coord_type ()> point_coord;
+ karma::rule<OutputIterator, coord_type (unsigned& )> polygon_coord;
+ phoenix::function<detail::get_type<geometry_type>> _type;
+ phoenix::function<detail::get_first<geometry_type>> _first;
+ phoenix::function<detail::get_x<typename geometry_type::value_type> > _x;
+ phoenix::function<detail::get_y<typename geometry_type::value_type> > _y;
+ karma::real_generator<double, detail::json_coordinate_policy<double> > coordinate;
};
-template <typename OutputIterator>
+template <typename OutputIterator, typename GeometryContainer>
struct multi_geometry_generator_grammar :
- karma::grammar<OutputIterator, karma::locals<std::tuple<unsigned,bool> >,
- geometry_container const& ()>
+ karma::grammar<OutputIterator, karma::locals<std::tuple<unsigned,bool>>, GeometryContainer const& ()>
{
+ using geometry_type = typename boost::remove_pointer<typename GeometryContainer::value_type>::type;
+
multi_geometry_generator_grammar();
- karma::rule<OutputIterator, karma::locals<std::tuple<unsigned,bool> >,
- geometry_container const&()> start;
- karma::rule<OutputIterator, karma::locals<std::tuple<unsigned,bool> >,
- geometry_container const&()> geometry_collection;
- karma::rule<OutputIterator, karma::locals<std::tuple<unsigned,bool> >,
- geometry_container const&()> geometry;
- karma::rule<OutputIterator, karma::locals<unsigned>,
- geometry_type const&()> geometry2;
- karma::rule<OutputIterator, geometry_container const&()> coordinates;
- geometry_generator_grammar<OutputIterator> path;
- boost::phoenix::function<detail::multi_geometry_type> multi_type_;
- boost::phoenix::function<detail::get_type > type_;
- boost::phoenix::function<detail::not_empty> not_empty_;
+ karma::rule<OutputIterator, karma::locals<std::tuple<unsigned,bool> >, GeometryContainer const&()> json;
+ karma::rule<OutputIterator, karma::locals<std::tuple<unsigned,bool> >, GeometryContainer const&()> geometry;
+ karma::rule<OutputIterator, karma::locals<std::tuple<unsigned,bool> >, GeometryContainer const&()> geometry_collection;
+ karma::rule<OutputIterator, karma::locals<unsigned>,geometry_type const&()> geometry2;
+ karma::rule<OutputIterator, GeometryContainer const&()> coordinates;
+ geometry_generator_grammar<OutputIterator,geometry_type > path;
+ phoenix::function<detail::multi_geometry_<GeometryContainer> > is_multi;
+ phoenix::function<detail::multi_geometry_type<geometry_type>> multi_type_;
+ phoenix::function<detail::get_type<geometry_type>> type_;
+ phoenix::function<detail::not_empty<geometry_type>> not_empty_;
karma::symbols<unsigned, char const*> geometry_types;
};
diff --git a/include/mapnik/json/geometry_generator_grammar_impl.hpp b/include/mapnik/json/geometry_generator_grammar_impl.hpp
index 61be1b9..ceb8860 100644
--- a/include/mapnik/json/geometry_generator_grammar_impl.hpp
+++ b/include/mapnik/json/geometry_generator_grammar_impl.hpp
@@ -32,11 +32,34 @@
namespace mapnik { namespace json {
+template <typename T>
+std::tuple<unsigned,bool> detail::multi_geometry_type<T>::operator() (T const& geom) const
+{
+ using geometry_container = T;
+ unsigned type = 0u;
+ bool collection = false;
+
+ typename geometry_container::const_iterator itr = geom.begin();
+ typename geometry_container::const_iterator end = geom.end();
+
+ for ( ; itr != end; ++itr)
+ {
+ if (type != 0 && itr->type() != type)
+ {
+ collection = true;
+ break;
+ }
+ type = itr->type();
+ }
+ return std::tuple<unsigned,bool>(type, collection);
+}
+
+
namespace karma = boost::spirit::karma;
-template <typename OutputIterator>
-geometry_generator_grammar<OutputIterator>::geometry_generator_grammar()
- : geometry_generator_grammar::base_type(coordinates)
+template <typename OutputIterator, typename Geometry>
+geometry_generator_grammar<OutputIterator,Geometry>::geometry_generator_grammar()
+ : geometry_generator_grammar::base_type(json)
{
boost::spirit::karma::uint_type uint_;
boost::spirit::bool_type bool_;
@@ -44,11 +67,13 @@ geometry_generator_grammar<OutputIterator>::geometry_generator_grammar()
boost::spirit::karma::_1_type _1;
boost::spirit::karma::lit_type lit;
boost::spirit::karma::_a_type _a;
+ boost::spirit::karma::_b_type _b;
+ boost::spirit::karma::_c_type _c;
boost::spirit::karma::_r1_type _r1;
boost::spirit::karma::eps_type eps;
boost::spirit::karma::string_type kstring;
- coordinates = point | linestring | polygon
+ json = point | linestring | polygon
;
point = &uint_(mapnik::geometry_type::types::Point)[_1 = _type(_val)]
@@ -69,28 +94,33 @@ geometry_generator_grammar<OutputIterator>::geometry_generator_grammar()
point_coord = &uint_
<< lit('[')
- << coord_type << lit(',') << coord_type
+ << coordinate << lit(',') << coordinate
<< lit(']')
;
- polygon_coord %= ( &uint_(mapnik::SEG_MOVETO) << eps[_r1 += 1]
+ polygon_coord %= ( &uint_(mapnik::SEG_MOVETO)
+ << eps[_r1 += 1][_a = _x(_val)][ _b = _y(_val)]
<< kstring[ if_ (_r1 > 1u) [_1 = "],["]
- .else_[_1 = '[' ]]
+ .else_[_1 = '[' ]]
|
&uint_(mapnik::SEG_LINETO)
- << lit(',')) << lit('[') << coord_type << lit(',') << coord_type << lit(']')
+ << lit(',') << eps[_a = _x(_val)][_b = _y(_val)]
+ )
+ << coordinate[_1 = _a]
+ << lit(' ')
+ << coordinate[_1 = _b]
;
- coords2 %= *polygon_coord(_a)
+ coords2 %= *polygon_coord(_a,_b,_c)
;
coords = point_coord % lit(',')
;
}
-template <typename OutputIterator>
-multi_geometry_generator_grammar<OutputIterator>::multi_geometry_generator_grammar()
- : multi_geometry_generator_grammar::base_type(start)
+template <typename OutputIterator, typename GeometryContainer>
+multi_geometry_generator_grammar<OutputIterator,GeometryContainer>::multi_geometry_generator_grammar()
+ : multi_geometry_generator_grammar::base_type(json)
{
boost::spirit::karma::uint_type uint_;
boost::spirit::bool_type bool_;
@@ -110,7 +140,7 @@ multi_geometry_generator_grammar<OutputIterator>::multi_geometry_generator_gramm
(mapnik::geometry_type::types::Polygon + 3,"\"MultiPolygon\"")
;
- start %= ( eps(boost::phoenix::at_c<1>(_a))[_a = multi_type_(_val)]
+ json %= ( eps(boost::phoenix::at_c<1>(_a))[_a = multi_type_(_val)]
<< lit("{\"type\":\"GeometryCollection\",\"geometries\":[")
<< geometry_collection << lit("]}")
|
diff --git a/include/mapnik/util/geometry_to_geojson.hpp b/include/mapnik/util/geometry_to_geojson.hpp
index cbdce3d..b661d5c 100644
--- a/include/mapnik/util/geometry_to_geojson.hpp
+++ b/include/mapnik/util/geometry_to_geojson.hpp
@@ -32,7 +32,7 @@ namespace mapnik { namespace util {
inline bool to_geojson(std::string & json, mapnik::geometry_type const& geom)
{
using sink_type = std::back_insert_iterator<std::string>;
- static const mapnik::json::geometry_generator_grammar<sink_type> grammar;
+ static const mapnik::json::geometry_generator_grammar<sink_type,mapnik::geometry_type> grammar;
sink_type sink(json);
return boost::spirit::karma::generate(sink, grammar, geom);
}
@@ -40,7 +40,7 @@ inline bool to_geojson(std::string & json, mapnik::geometry_type const& geom)
inline bool to_geojson(std::string & json, mapnik::geometry_container const& geom)
{
using sink_type = std::back_insert_iterator<std::string>;
- static const mapnik::json::multi_geometry_generator_grammar<sink_type> grammar;
+ static const mapnik::json::multi_geometry_generator_grammar<sink_type,mapnik::geometry_container> grammar;
sink_type sink(json);
return boost::spirit::karma::generate(sink, grammar, geom);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment