implement custom feature GeoJSON parser for improved performance

This commit is contained in:
artemp 2016-11-18 15:17:23 +01:00
parent f64db40a8a
commit aca229c2bb
2 changed files with 94 additions and 48 deletions

View File

@ -29,14 +29,100 @@
#include <mapnik/geometry/is_empty.hpp>
#include <mapnik/json/unicode_string_grammar_x3_def.hpp>
#include <mapnik/json/positions_grammar_x3_def.hpp>
#include <mapnik/json/geojson_grammar_x3_def.hpp>
#include <mapnik/json/generic_json_grammar_x3_def.hpp>
#include <mapnik/json/json_grammar_config.hpp>
#include <mapnik/json/create_feature.hpp>
#include <mapnik/json/create_geometry.hpp>
// stl
#include <string>
#include <vector>
#include <fstream>
namespace mapnik { namespace json { namespace {
namespace x3 = boost::spirit::x3;
using x3::lit;
using x3::omit;
using x3::char_;
struct feature_tag;
// generic json rule
auto const& value = generic_json_grammar();
// import unicode string rule
auto const& geojson_string = unicode_string_grammar();
// import positions rule
auto const& positions_rule = positions_grammar();
// geometry types symbols
struct geometry_type_ : x3::symbols<mapnik::geometry::geometry_types>
{
geometry_type_()
{
add
("\"Point\"", mapnik::geometry::geometry_types::Point)
("\"LineString\"", mapnik::geometry::geometry_types::LineString)
("\"Polygon\"", mapnik::geometry::geometry_types::Polygon)
("\"MultiPoint\"", mapnik::geometry::geometry_types::MultiPoint)
("\"MultiLineString\"", mapnik::geometry::geometry_types::MultiLineString )
("\"MultiPolygon\"",mapnik::geometry::geometry_types::MultiPolygon)
("\"GeometryCollection\"",mapnik::geometry::geometry_types::GeometryCollection)
;
}
} geometry_type_symbols;
auto const assign_geometry_type = [] (auto const& ctx)
{
std::get<0>(_val(ctx)) = _attr(ctx);
};
auto const assign_geometry = [] (auto const& ctx)
{
mapnik::feature_impl & feature = x3::get<feature_tag>(ctx);
mapnik::geometry::geometry<double> geom;
auto const type = std::get<0>(_attr(ctx));
auto const& coordinates = std::get<1>(_attr(ctx));
mapnik::json::create_geometry(geom, type, coordinates);
feature.set_geometry(std::move(geom));
};
auto const assign_positions = [] (auto const& ctx)
{
std::get<1>(_val(ctx)) = std::move(_attr(ctx));
};
auto const feature_type = lit("\"type\"") > lit(':') > lit("\"Feature\"");
auto const geometry_type = x3::rule<struct geometry_type_tag, mapnik::geometry::geometry_types> {} =
lit("\"type\"") > lit(':') > geometry_type_symbols;
auto const coordinates = x3::rule<struct coordinates_tag, positions> {} =
lit("\"coordinates\"") > lit(':') > positions_rule
;
auto const geometry = x3::rule<struct geomerty_tag, std::tuple<mapnik::geometry::geometry_types, positions>> {} =
(geometry_type[assign_geometry_type]
|
coordinates[assign_positions]
|
(omit[geojson_string] > lit(':') > omit[value])) % lit(',')
;
auto const feature_part = x3::rule<struct feature_part_rule_tag> {} =
feature_type
|
(lit("\"geometry\"") > lit(':') > lit('{') > geometry[assign_geometry] > lit('}'))
|
(lit("\"properties\"") > lit(':') > omit[value])
|
omit[geojson_string] > lit(':') > omit[value]
;
auto const feature = x3::rule<struct feature_rule_tag> {} =
lit('{') > feature_part % lit(',') > lit('}')
;
}}}
geojson_index_featureset::geojson_index_featureset(std::string const& filename, mapnik::filter_in_box const& filter)
:
#if defined(MAPNIK_MEMORY_MAPPED_FILE)
@ -77,13 +163,6 @@ geojson_index_featureset::geojson_index_featureset(std::string const& filename,
geojson_index_featureset::~geojson_index_featureset() {}
namespace {
using namespace boost::spirit;
//static const mapnik::json::keys_map keys = mapnik::json::get_keys();
static const mapnik::json::grammar::geojson_grammar_type geojson_g = mapnik::json::geojson_grammar();
}
mapnik::feature_ptr geojson_index_featureset::next()
{
while( itr_ != positions_.end())
@ -105,13 +184,14 @@ mapnik::feature_ptr geojson_index_featureset::next()
using namespace boost::spirit;
using space_type = mapnik::json::grammar::space_type;
using mapnik::json::grammar::iterator_type;
mapnik::json::geojson_value value;
auto const grammar = x3::with<mapnik::json::keys_tag>(std::ref(keys_))
[ geojson_g ];
//mapnik::json::geojson_value value;
//auto const grammar = x3::with<mapnik::json::keys_tag>(std::ref(keys_))
// [ mapnik::json::geojson_grammar() ];
auto grammar = x3::with<mapnik::json::feature_tag>(std::ref(*feature))
[ mapnik::json::feature ];
bool result = x3::phrase_parse(start, end, grammar, space_type());
bool result = x3::phrase_parse(start, end, grammar, space_type(), value);
if (!result) throw std::runtime_error("Failed to parse GeoJSON feature");
mapnik::json::create_feature(*feature, value, keys_, tr);
// skip empty geometries
if (mapnik::geometry::is_empty(feature->get_geometry()))
continue;

View File

@ -32,10 +32,6 @@
#include <mapnik/warning_ignore.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <boost/interprocess/streams/bufferstream.hpp>
#include <boost/bimap.hpp>
#include <boost/bimap/set_of.hpp>
#include <boost/bimap/unordered_set_of.hpp>
#include <boost/assign/list_of.hpp>
#pragma GCC diagnostic pop
#include <mapnik/mapped_memory_cache.hpp>
#endif
@ -43,35 +39,6 @@
#include <deque>
#include <cstdio>
namespace {
using keys_map = boost::bimap<boost::bimaps::unordered_set_of<std::string>,
boost::bimaps::set_of<int>>;
enum well_known_names
{
id = 1,
type,
features,
geometry,
coordinates,
properties
};
inline keys_map get_keys()
{
keys_map keys = boost::assign::list_of<keys_map::relation>
("type", well_known_names::type)
("features", well_known_names::features)
("geometry", well_known_names::geometry)
("coordinates", well_known_names::coordinates)
("properties", well_known_names::properties)
("id", well_known_names::id)
;
return keys;
}
}
class geojson_index_featureset : public mapnik::Featureset
{
using value_type = std::pair<std::size_t, std::size_t>;
@ -92,7 +59,6 @@ private:
mapnik::context_ptr ctx_;
std::vector<value_type> positions_;
std::vector<value_type>::iterator itr_;
keys_map keys_ = get_keys();
};
#endif // GEOJSON_INDEX_FEATURESE_HPP