From 9ecc0d95979ca2fa3154f4b47c8f9fa4717fe696 Mon Sep 17 00:00:00 2001 From: Vladimir Agafonkin Date: Wed, 27 Jul 2016 20:18:41 +0300 Subject: GeoJSON point clustering (#5724) * add supercluster dependency * prepare GeoJSONTile for Supercluster * prepare GeoJSONSource for accepting options * try removing mbgl::GeoJSON * fix setGeoJSON types * add GeoJSONSource getURL * add geojson to include path * add Supercluster index in GeoJSONSource * fix GeoJSONSource getZoomRange * bring back mbgl::GeoJSON header * fix tidy warnings hopefully * try test-suite with enabled cluster test * fix formatting in clustering-related files --- include/mbgl/style/conversion/source.hpp | 89 ++++++++++++++++++++++----- include/mbgl/style/sources/geojson_source.hpp | 35 ++++++++++- include/mbgl/util/geojson.hpp | 18 +----- 3 files changed, 110 insertions(+), 32 deletions(-) (limited to 'include') diff --git a/include/mbgl/style/conversion/source.hpp b/include/mbgl/style/conversion/source.hpp index 00c6afb9fe..c4b2fe303f 100644 --- a/include/mbgl/style/conversion/source.hpp +++ b/include/mbgl/style/conversion/source.hpp @@ -1,12 +1,12 @@ #pragma once +#include +#include +#include #include #include #include #include -#include -#include -#include namespace mbgl { namespace style { @@ -18,17 +18,17 @@ public: template Result> operator()(const V& value, const std::string& id) const { if (!isObject(value)) { - return Error { "source must be an object" }; + return Error{ "source must be an object" }; } auto typeValue = objectMember(value, "type"); if (!typeValue) { - return Error { "source must have a type" }; + return Error{ "source must have a type" }; } optional type = toString(*typeValue); if (!type) { - return Error { "source type must be a string" }; + return Error{ "source type must be a string" }; } if (*type == "raster") { @@ -38,7 +38,7 @@ public: } else if (*type == "geojson") { return convertGeoJSONSource(id, value); } else { - return Error { "invalid source type" }; + return Error{ "invalid source type" }; } } @@ -57,14 +57,15 @@ private: optional url = toString(*urlVal); if (!url) { - return Error { "source url must be a string" }; + return Error{ "source url must be a string" }; } return *url; } template - Result> convertRasterSource(const std::string& id, const V& value) const { + Result> convertRasterSource(const std::string& id, + const V& value) const { Result> urlOrTileset = convertURLOrTileset(value); if (!urlOrTileset) { return urlOrTileset.error(); @@ -75,7 +76,7 @@ private: if (tileSizeValue) { optional size = toNumber(*tileSizeValue); if (!size || *size < 0 || *size > std::numeric_limits::max()) { - return Error { "invalid tileSize" }; + return Error{ "invalid tileSize" }; } tileSize = *size; } @@ -84,7 +85,8 @@ private: } template - Result> convertVectorSource(const std::string& id, const V& value) const { + Result> convertVectorSource(const std::string& id, + const V& value) const { Result> urlOrTileset = convertURLOrTileset(value); if (!urlOrTileset) { return urlOrTileset.error(); @@ -94,13 +96,70 @@ private: } template - Result> convertGeoJSONSource(const std::string& id, const V& value) const { + Result> convertGeoJSONSource(const std::string& id, + const V& value) const { auto dataValue = objectMember(value, "data"); if (!dataValue) { - return Error { "GeoJSON source must have a data value" }; + return Error{ "GeoJSON source must have a data value" }; + } + + GeoJSONOptions options; + + const auto maxzoomValue = objectMember(value, "maxzoom"); + if (maxzoomValue) { + if (toNumber(*maxzoomValue)) { + options.maxzoom = static_cast(*toNumber(*maxzoomValue)); + } else { + return Error{ "GeoJSON source maxzoom value must be a number" }; + } + } + + const auto bufferValue = objectMember(value, "buffer"); + if (bufferValue) { + if (toNumber(*bufferValue)) { + options.buffer = static_cast(*toNumber(*bufferValue)); + } else { + return Error{ "GeoJSON source buffer value must be a number" }; + } + } + + const auto toleranceValue = objectMember(value, "tolerance"); + if (toleranceValue) { + if (toNumber(*toleranceValue)) { + options.tolerance = static_cast(*toNumber(*toleranceValue)); + } else { + return Error{ "GeoJSON source tolerance value must be a number" }; + } + } + + const auto clusterValue = objectMember(value, "cluster"); + if (clusterValue) { + if (toBool(*clusterValue)) { + options.cluster = *toBool(*clusterValue); + } else { + return Error{ "GeoJSON source cluster value must be a boolean" }; + } + } + + const auto clusterMaxZoomValue = objectMember(value, "clusterMaxZoom"); + if (clusterMaxZoomValue) { + if (toNumber(*clusterMaxZoomValue)) { + options.clusterMaxZoom = static_cast(*toNumber(*clusterMaxZoomValue)); + } else { + return Error{ "GeoJSON source clusterMaxZoom value must be a number" }; + } + } + + const auto clusterRadiusValue = objectMember(value, "clusterRadius"); + if (clusterRadiusValue) { + if (toNumber(*clusterRadiusValue)) { + options.clusterRadius = static_cast(*toNumber(*clusterRadiusValue)); + } else { + return Error{ "GeoJSON source clusterRadius value must be a number" }; + } } - auto result = std::make_unique(id); + auto result = std::make_unique(id, options); if (isObject(*dataValue)) { Result geoJSON = convertGeoJSON(*dataValue); @@ -111,7 +170,7 @@ private: } else if (toString(*dataValue)) { result->setURL(*toString(*dataValue)); } else { - return Error { "GeoJSON data must be a URL or an object" }; + return Error{ "GeoJSON data must be a URL or an object" }; } return std::move(result); diff --git a/include/mbgl/style/sources/geojson_source.hpp b/include/mbgl/style/sources/geojson_source.hpp index 3736dd44bc..37ddce1bcc 100644 --- a/include/mbgl/style/sources/geojson_source.hpp +++ b/include/mbgl/style/sources/geojson_source.hpp @@ -3,15 +3,46 @@ #include #include +#include + +namespace mapbox { + +namespace geojsonvt { +class GeoJSONVT; +} // namespace geojsonvt + +namespace supercluster { +class Supercluster; +} // namespace supercluster + +} // namespace mapbox + namespace mbgl { namespace style { +using GeoJSONVTPointer = std::unique_ptr; +using SuperclusterPointer = std::unique_ptr; + +struct GeoJSONOptions { + // GeoJSON-VT options + uint8_t maxzoom = 18; + uint16_t buffer = 128; + double tolerance = 0.375; + + // Supercluster options + bool cluster = false; + uint16_t clusterRadius = 50; + uint8_t clusterMaxZoom = 17; +}; + class GeoJSONSource : public Source { public: - GeoJSONSource(const std::string& id); + GeoJSONSource(const std::string& id, const GeoJSONOptions options_ = GeoJSONOptions()); void setURL(const std::string& url); - void setGeoJSON(GeoJSON&&); + void setGeoJSON(const GeoJSON&); + + std::string getURL(); // Private implementation diff --git a/include/mbgl/util/geojson.hpp b/include/mbgl/util/geojson.hpp index 3fd8c6ac4b..b4e789a3ac 100644 --- a/include/mbgl/util/geojson.hpp +++ b/include/mbgl/util/geojson.hpp @@ -1,22 +1,10 @@ #pragma once -#include - -namespace mapbox { -namespace geojsonvt { -class GeoJSONVT; -} // namespace geojsonvt -} // namespace mapbox +#include namespace mbgl { -class GeoJSON { -public: - GeoJSON(std::unique_ptr); - GeoJSON(GeoJSON&&); - ~GeoJSON(); - - std::unique_ptr impl; -}; +using GeoJSON = mapbox::geojson::geojson; +using FeatureCollection = mapbox::geojson::feature_collection; } // namespace mbgl -- cgit v1.2.1