From e89eb99e28f39706af176e6d23345e788ac040fb Mon Sep 17 00:00:00 2001 From: Artem Pavlenko Date: Wed, 13 Jun 2012 13:30:58 +0100 Subject: [PATCH] + geojson input plugin (thanks, @tmcw!) --- SConstruct | 1 + plugins/input/geojson/build.py | 51 ++++++ plugins/input/geojson/geojson_datasource.cpp | 165 +++++++++++++++++++ plugins/input/geojson/geojson_datasource.hpp | 68 ++++++++ plugins/input/geojson/geojson_featureset.cpp | 51 ++++++ plugins/input/geojson/geojson_featureset.hpp | 23 +++ 6 files changed, 359 insertions(+) create mode 100644 plugins/input/geojson/build.py create mode 100644 plugins/input/geojson/geojson_datasource.cpp create mode 100644 plugins/input/geojson/geojson_datasource.hpp create mode 100644 plugins/input/geojson/geojson_featureset.cpp create mode 100644 plugins/input/geojson/geojson_featureset.hpp diff --git a/SConstruct b/SConstruct index 3efef7ad2..e2b492df7 100644 --- a/SConstruct +++ b/SConstruct @@ -102,6 +102,7 @@ PLUGINS = { # plugins with external dependencies 'shape': {'default':True,'path':None,'inc':None,'lib':None,'lang':'C++'}, 'csv': {'default':True,'path':None,'inc':None,'lib':None,'lang':'C++'}, 'raster': {'default':True,'path':None,'inc':None,'lib':None,'lang':'C++'}, + 'geojson': {'default':True,'path':None,'inc':None,'lib':None,'lang':'C++'}, 'kismet': {'default':False,'path':None,'inc':None,'lib':None,'lang':'C++'}, } diff --git a/plugins/input/geojson/build.py b/plugins/input/geojson/build.py new file mode 100644 index 000000000..8bda87f45 --- /dev/null +++ b/plugins/input/geojson/build.py @@ -0,0 +1,51 @@ +# +# This file is part of Mapnik (c++ mapping toolkit) +# +# Copyright (C) 2012 Artem Pavlenko +# +# Mapnik 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 +# + + +Import ('plugin_base') +Import ('env') + +prefix = env['PREFIX'] + +plugin_env = plugin_base.Clone() + +geojson_src = Split( + """ + geojson_datasource.cpp + geojson_featureset.cpp + """ + ) + +libraries = [] +# Link Library to Dependencies +libraries.append('mapnik') +libraries.append(env['ICU_LIB_NAME']) +libraries.append('boost_system%s' % env['BOOST_APPEND']) +if env['THREADING'] == 'multi': + libraries.append('boost_thread%s' % env['BOOST_APPEND']) + +input_plugin = plugin_env.SharedLibrary('../geojson', source=geojson_src, SHLIBPREFIX='', SHLIBSUFFIX='.input', LIBS=libraries, LINKFLAGS=env['CUSTOM_LDFLAGS']) + +# if the plugin links to libmapnik ensure it is built first +Depends(input_plugin, env.subst('../../../src/%s' % env['MAPNIK_LIB_NAME'])) + +if 'uninstall' not in COMMAND_LINE_TARGETS: + env.Install(env['MAPNIK_INPUT_PLUGINS_DEST'], input_plugin) + env.Alias('install', env['MAPNIK_INPUT_PLUGINS_DEST']) diff --git a/plugins/input/geojson/geojson_datasource.cpp b/plugins/input/geojson/geojson_datasource.cpp new file mode 100644 index 000000000..7c1fc978f --- /dev/null +++ b/plugins/input/geojson/geojson_datasource.cpp @@ -0,0 +1,165 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2012 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 "geojson_datasource.hpp" +#include "geojson_featureset.hpp" + +#include +#include + +// boost +#include +#include +#include +#include +#include +#include +#include +#include +// mapnik +#include +#include +#include +#include + +using mapnik::datasource; +using mapnik::parameters; + +DATASOURCE_PLUGIN(geojson_datasource) + +geojson_datasource::geojson_datasource(parameters const& params, bool bind) +: datasource(params), + type_(datasource::Vector), + desc_(*params_.get("type"), + *params_.get("encoding","utf-8")), + file_(*params_.get("file","")), + extent_(), + tr_(new mapnik::transcoder(*params_.get("encoding","utf-8"))), + features_(), + tree_(16,1) +{ + if (file_.empty()) throw mapnik::datasource_exception("GeoJSON Plugin: missing parameter"); + if (bind) + { + this->bind(); + } +} + +void geojson_datasource::bind() const +{ + if (is_bound_) return; + + typedef std::istreambuf_iterator base_iterator_type; + + std::ifstream is(file_.c_str()); + boost::spirit::multi_pass begin = + boost::spirit::make_default_multi_pass(base_iterator_type(is)); + + boost::spirit::multi_pass end = + boost::spirit::make_default_multi_pass(base_iterator_type()); + + mapnik::context_ptr ctx = boost::make_shared(); + mapnik::json::feature_collection_parser > p(ctx,*tr_); + bool result = p.parse(begin,end, features_); + if (!result) + { + MAPNIK_LOG_WARN(geojson) << "geojson_datasource: Failed parse GeoJSON file " << file_; + return; + } + + bool first = true; + std::size_t count=0; + BOOST_FOREACH (mapnik::feature_ptr f, features_) + { + mapnik::box2d const& box = f->envelope(); + if (first) + { + extent_ = box; + first = false; + } + else + { + extent_.expand_to_include(box); + } + tree_.insert(box_type(point_type(box.minx(),box.miny()),point_type(box.maxx(),box.maxy())), count++); + } + is_bound_ = true; +} + +geojson_datasource::~geojson_datasource() { } + +std::string const geojson_datasource::name_="geojson"; + +std::string geojson_datasource::name() +{ + return name_; +} + +boost::optional geojson_datasource::get_geometry_type() const +{ + return boost::optional(); +} + +mapnik::datasource::datasource_t geojson_datasource::type() const +{ + return type_; +} + +std::map geojson_datasource::get_statistics() const +{ + return statistics_; +} + +// FIXME: implement +mapnik::box2d geojson_datasource::envelope() const +{ + if (!is_bound_) bind(); + + return extent_; +} + +mapnik::layer_descriptor geojson_datasource::get_descriptor() const +{ + if (!is_bound_) bind(); + + return desc_; +} + +mapnik::featureset_ptr geojson_datasource::features(mapnik::query const& q) const +{ + if (!is_bound_) bind(); + + // if the query box intersects our world extent then query for features + if (extent_.intersects(q.get_bbox())) + { + return boost::make_shared(features_,tree_); + } + // otherwise return an empty featureset pointer + return mapnik::featureset_ptr(); +} + +// FIXME +mapnik::featureset_ptr geojson_datasource::features_at_point(mapnik::coord2d const& pt) const +{ + if (!is_bound_) bind(); + return mapnik::featureset_ptr(); +} diff --git a/plugins/input/geojson/geojson_datasource.hpp b/plugins/input/geojson/geojson_datasource.hpp new file mode 100644 index 000000000..829a30f5f --- /dev/null +++ b/plugins/input/geojson/geojson_datasource.hpp @@ -0,0 +1,68 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2012 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 GEOJSON_DATASOURCE_HPP +#define GEOJSON_DATASOURCE_HPP + +// mapnik +#include +// boost +#include +#include +#include +#include +#include +#include + +class geojson_datasource : public mapnik::datasource +{ +public: + typedef boost::geometry::model::d2::point_xy point_type; + typedef boost::geometry::model::box box_type; + typedef boost::geometry::index::rtree spatial_index_type; + + // constructor + geojson_datasource(mapnik::parameters const& params, bool bind=true); + virtual ~geojson_datasource (); + mapnik::datasource::datasource_t type() const; + static std::string name(); + mapnik::featureset_ptr features(mapnik::query const& q) const; + mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const; + mapnik::box2d envelope() const; + mapnik::layer_descriptor get_descriptor() const; + std::map get_statistics() const; + boost::optional get_geometry_type() const; + void bind() const; +private: + static const std::string name_; + mapnik::datasource::datasource_t type_; + mutable std::map statistics_; + mutable mapnik::layer_descriptor desc_; + mutable std::string file_; + mutable mapnik::box2d extent_; + boost::shared_ptr tr_; + mutable std::vector features_; + mutable spatial_index_type tree_; +}; + + +#endif // FILE_DATASOURCE_HPP diff --git a/plugins/input/geojson/geojson_featureset.cpp b/plugins/input/geojson/geojson_featureset.cpp new file mode 100644 index 000000000..bf5cb7878 --- /dev/null +++ b/plugins/input/geojson/geojson_featureset.cpp @@ -0,0 +1,51 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2011 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 + * + *****************************************************************************/ + +// mapnik +#include +// stl +#include +#include +#include + +#include "geojson_featureset.hpp" + +geojson_featureset::geojson_featureset(std::vector const& features, + geojson_datasource::spatial_index_type const& tree) + : feature_id_(1), + features_(features), + tree_(tree) {} + +geojson_featureset::~geojson_featureset() {} + +mapnik::feature_ptr geojson_featureset::next() +{ + feature_id_++; + if (feature_id_ <= features_.size()) + { + return features_.at(feature_id_ - 1); + } + else + { + return mapnik::feature_ptr(); + } +} diff --git a/plugins/input/geojson/geojson_featureset.hpp b/plugins/input/geojson/geojson_featureset.hpp new file mode 100644 index 000000000..6a463f66e --- /dev/null +++ b/plugins/input/geojson/geojson_featureset.hpp @@ -0,0 +1,23 @@ +#ifndef GEOJSON_FEATURESET_HPP +#define GEOJSON_FEATURESET_HPP + +#include +#include +#include "geojson_datasource.hpp" + +class geojson_featureset : public mapnik::Featureset +{ +public: + geojson_featureset(std::vector const& features, + geojson_datasource::spatial_index_type const& tree); + virtual ~geojson_featureset(); + mapnik::feature_ptr next(); + +private: + mapnik::box2d box_; + unsigned int feature_id_; + std::vector const& features_; + geojson_datasource::spatial_index_type const& tree_; +}; + +#endif // GEOJSON_FEATURESET_HPP