geojson plugin

* use parse_geojson(Iterator start, Iterator end) signiture
* use Iterator = char const*
* remove unneeded I/O in 'initialise_index'
* use memory mapped file (currently #if/def)
This commit is contained in:
artemp 2015-02-03 13:33:55 +01:00
parent 9f282af61a
commit eec661d263
2 changed files with 46 additions and 32 deletions

View file

@ -29,7 +29,7 @@
// boost
#include <boost/algorithm/string.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/interprocess/mapped_region.hpp>
// mapnik
#include <mapnik/boolean.hpp>
#include <mapnik/unicode.hpp>
@ -50,6 +50,8 @@
#include <mapnik/json/extract_bounding_box_grammar_impl.hpp>
#include <mapnik/util/boost_geometry_adapters.hpp> // boost.geometry - register box2d<double>
#include <mapnik/mapped_memory_cache.hpp>
using mapnik::datasource;
using mapnik::parameters;
@ -122,11 +124,14 @@ geojson_datasource::geojson_datasource(parameters const& params)
}
if (!inline_string_.empty())
{
parse_geojson(inline_string_);
char const* start = inline_string_.c_str();
char const* end = start + inline_string_.size();
parse_geojson(start, end);
}
else
{
cache_features_ = *params.get<mapnik::boolean_type>("cache_features", true);
#if 0
mapnik::util::file file(filename_);
if (!file.open())
{
@ -136,20 +141,40 @@ geojson_datasource::geojson_datasource(parameters const& params)
std::string file_buffer;
file_buffer.resize(file.size());
std::fread(&file_buffer[0], file.size(), 1, file.get());
cache_features_ = *params.get<mapnik::boolean_type>("cache_features", true);
char const* start = file_buffer.c_str();
char const* end = start + file_buffer.length();
if (cache_features_)
{
parse_geojson(file_buffer);
parse_geojson(start, end);
}
else
{
initialise_index(file_buffer.begin(), file_buffer.end());
initialise_index(start, end);
}
#else
boost::optional<mapnik::mapped_region_ptr> mapped_region =
mapnik::mapped_memory_cache::instance().find(filename_, false);
if (!mapped_region)
{
throw std::runtime_error("could not get file mapping for "+ filename_);
}
char const* start = reinterpret_cast<char const*>((*mapped_region)->get_address());
char const* end = start + (*mapped_region)->get_size();
if (cache_features_)
{
parse_geojson(start, end);
}
else
{
initialise_index(start, end);
}
#endif
}
}
namespace {
using base_iterator_type = std::string::const_iterator;
using base_iterator_type = char const*;
const mapnik::transcoder tr("utf8");
const mapnik::json::feature_collection_grammar<base_iterator_type,mapnik::feature_impl> fc_grammar(tr);
}
@ -160,11 +185,14 @@ void geojson_datasource::initialise_index(Iterator start, Iterator end)
mapnik::json::boxes boxes;
mapnik::json::extract_bounding_box_grammar<Iterator> bbox_grammar;
boost::spirit::ascii::space_type space;
if (!boost::spirit::qi::phrase_parse(start, end, (bbox_grammar)(boost::phoenix::ref(boxes)) , space))
Iterator itr = start;
if (!boost::spirit::qi::phrase_parse(itr, end, (bbox_grammar)(boost::phoenix::ref(boxes)) , space))
{
throw mapnik::datasource_exception("GeoJSON Plugin: could not parse: '" + filename_ + "'");
}
// bulk insert initialise r-tree
tree_ = std::make_unique<spatial_index_type>(boxes);
// calculate total extent
for (auto const& item : boxes)
{
auto const& box = std::get<0>(item);
@ -174,28 +202,14 @@ void geojson_datasource::initialise_index(Iterator start, Iterator end)
extent_ = box;
// parse first feature to extract attributes schema.
// NOTE: this doesn't yield correct answer for geoJSON in general, just an indication
mapnik::util::file file(filename_);
if (!file.open())
{
throw mapnik::datasource_exception("GeoJSON Plugin: could not open: '" + filename_ + "'");
}
std::fseek(file.get(), geometry_index.first, SEEK_SET);
std::vector<char> json;
json.resize(geometry_index.second);
std::fread(json.data(), geometry_index.second, 1, file.get());
using chr_iterator_type = std::vector<char>::const_iterator;
chr_iterator_type start = json.begin();
chr_iterator_type end = json.end();
Iterator itr = start + geometry_index.first;
Iterator end = itr + geometry_index.second;
mapnik::context_ptr ctx = std::make_shared<mapnik::context_type>();
mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx,1));
using namespace boost::spirit;
static const mapnik::transcoder tr("utf8");
static const mapnik::json::feature_grammar<chr_iterator_type,mapnik::feature_impl> grammar(tr);
ascii::space_type space;
if (!qi::phrase_parse(start, end, (grammar)(boost::phoenix::ref(*feature)), space))
static const mapnik::json::feature_grammar<Iterator, mapnik::feature_impl> grammar(tr);
boost::spirit::ascii::space_type space;
if (!boost::spirit::qi::phrase_parse(itr, end, (grammar)(boost::phoenix::ref(*feature)), space))
{
throw std::runtime_error("Failed to parse geojson feature");
}
@ -213,8 +227,8 @@ void geojson_datasource::initialise_index(Iterator start, Iterator end)
}
}
template <typename T>
void geojson_datasource::parse_geojson(T const& buffer)
template <typename Iterator>
void geojson_datasource::parse_geojson(Iterator start, Iterator end)
{
boost::spirit::ascii::space_type space;
mapnik::context_ptr ctx = std::make_shared<mapnik::context_type>();
@ -222,7 +236,7 @@ void geojson_datasource::parse_geojson(T const& buffer)
mapnik::json::default_feature_callback callback(features_);
bool result = boost::spirit::qi::phrase_parse(buffer.begin(), buffer.end(), (fc_grammar)
bool result = boost::spirit::qi::phrase_parse(start, end, (fc_grammar)
(boost::phoenix::ref(ctx),boost::phoenix::ref(start_id), boost::phoenix::ref(callback)),
space);
if (!result)

View file

@ -96,8 +96,8 @@ public:
mapnik::layer_descriptor get_descriptor() const;
boost::optional<mapnik::datasource::geometry_t> get_geometry_type() const;
//
template <typename T>
void parse_geojson(T const& buffer);
template <typename Iterator>
void parse_geojson(Iterator start, Iterator end);
template <typename Iterator>
void initialise_index(Iterator start, Iterator end);
private: