diff --git a/include/mapnik/json/create_feature.hpp b/include/mapnik/json/create_feature.hpp new file mode 100644 index 000000000..3d6beea65 --- /dev/null +++ b/include/mapnik/json/create_feature.hpp @@ -0,0 +1,237 @@ +/***************************************************************************** + * + * 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_JSON_CREATE_FEATURE_HPP +#define MAPNIK_JSON_CREATE_FEATURE_HPP + +#include +#include +#include +#include + +#include +#include +#include + +namespace mapnik { namespace json { + +struct stringifier +{ + std::string operator()(std::string const& val) const + { + return "\"" + val + "\""; + } + + std::string operator()(value_null) const + { + return "null"; + } + + std::string operator()(value_bool val) const + { + return val ? "true" : "false"; + } + + std::string operator()(value_integer val) const + { + std::string str; + util::to_string(str, val); + return str; + } + + std::string operator()(value_double val) const + { + std::string str; + util::to_string(str, val); + return str; + } + + std::string operator()(mapnik::json::geojson_array const& array) const + { + std::string str = "["; + bool first = true; + for (auto const& val : array) + { + if (first) first = false; + else str += ","; + str += mapnik::util::apply_visitor(*this, val); + } + str += "]"; + return str; + } + + std::string operator()(mapnik::json::geojson_object const& object, keys_map const& keys) const + { + std::string str = "{"; + bool first = true; + for (auto const& kv : object) + { + auto itr = keys.right.find(std::get<0>(kv)); + if (itr != keys.right.end()) + { + if (first) first = false; + else str += ","; + str += "\"" + itr->second + "\""; + str += ":"; + str += mapnik::util::apply_visitor(*this, kv.second); + } + } + str += "}"; + return str; + } + template + std::string operator()(T const&) const + { + return ""; + } +}; + +struct attribute_value_visitor +{ +public: + attribute_value_visitor(mapnik::transcoder const& tr, keys_map const& keys) + : tr_(tr), + keys_(keys) {} + + mapnik::value operator()(std::string const& val) const + { + return mapnik::value(tr_.transcode(val.c_str())); + } + + mapnik::value operator()(mapnik::json::geojson_array const& array) const + { + std::string str = stringifier()(array); + return mapnik::value(tr_.transcode(str.c_str())); + } + + mapnik::value operator()(mapnik::json::geojson_object const& object) const + { + std::string str = stringifier()(object, keys_); + return mapnik::value(tr_.transcode(str.c_str())); + } + + mapnik::value operator() (mapnik::value_bool val) const + { + return mapnik::value(val); + } + + mapnik::value operator() (mapnik::value_integer val) const + { + return mapnik::value(val); + } + + mapnik::value operator() (mapnik::value_double val) const + { + return mapnik::value(val); + } + + template + mapnik::value operator()(T const& val) const + { + return mapnik::value_null{}; + } + + mapnik::transcoder const& tr_; + mapnik::json::keys_map const& keys_; +}; + +void create_feature(feature_impl & feature, + mapnik::json::geojson_value const& value, + mapnik::json::keys_map const& keys, + mapnik::transcoder const& tr) +{ + + if (!value.is()) + { + throw std::runtime_error("Expecting an GeoJSON object"); + } + mapnik::json::geojson_object const& feature_value = mapnik::util::get(value); + for (auto const& elem : feature_value) + { + auto const key = std::get<0>(elem); + if (key == mapnik::json::well_known_names::geometry) + { + auto const& geom_value = std::get<1>(elem); + if (!geom_value.is()) + { + throw std::runtime_error("\"geometry\": xxx <-- expecting an JSON object here"); + } + auto const& geometry = mapnik::util::get(geom_value); + mapnik::geometry::geometry_types geom_type; + mapnik::json::positions const* coordinates = nullptr; + for (auto & elem2 : geometry) + { + auto const key2 = std::get<0>(elem2); + if (key2 == mapnik::json::well_known_names::type) + { + auto const& geom_type_value = std::get<1>(elem2); + if (!geom_type_value.is()) + { + throw std::runtime_error("\"type\": xxx <-- expecting an GeoJSON geometry type here"); + } + geom_type = mapnik::util::get(geom_type_value); + if (geom_type == mapnik::geometry::geometry_types::GeometryCollection) + { + throw std::runtime_error("GeometryCollections are not allowed"); + } + } + else if (key2 == mapnik::json::well_known_names::coordinates) + { + auto const& coordinates_value = std::get<1>(elem2); + if (!coordinates_value.is()) + { + throw std::runtime_error("\"coordinates\": xxx <-- expecting an GeoJSON positions here"); + } + coordinates = &mapnik::util::get(coordinates_value); + } + } + + mapnik::geometry::geometry geom; + mapnik::json::create_geometry(geom, geom_type, *coordinates); + feature.set_geometry(std::move(geom)); + } + else if (key == mapnik::json::well_known_names::properties) + { + auto const& prop_value = std::get<1>(elem); + if (!prop_value.is()) + { + throw std::runtime_error("\"properties\": xxx <-- expecting an JSON object here"); + } + auto const& properties = mapnik::util::get(prop_value); + auto end = keys.right.end(); + for (auto const& kv : properties) + { + auto itr = keys.right.find(std::get<0>(kv)); + if (itr != end) + { + feature.put_new(itr->second, + mapnik::util::apply_visitor(mapnik::json::attribute_value_visitor(tr, keys), + std::get<1>(kv))); + } + } + } + } +} + +}} + +#endif //MAPNIK_JSON_CREATE_FEATURE_HPP