diff options
author | Jesse Crocker <jesse@gaiagps.com> | 2016-12-08 10:39:55 -0700 |
---|---|---|
committer | Konstantin Käfer <mail@kkaefer.com> | 2017-03-21 11:01:14 +0100 |
commit | 273a2fa4785a807abbec011ee347d9e3e4d5f74c (patch) | |
tree | 487a12dc00aaa2839a06dd0b865632a974576d45 | |
parent | 461a157caeec4b21bee0fc0adc002fbb64ab1444 (diff) | |
download | qtlocation-mapboxgl-273a2fa4785a807abbec011ee347d9e3e4d5f74c.tar.gz |
[core] Custom vector sources
-rw-r--r-- | cmake/core-files.cmake | 4 | ||||
-rw-r--r-- | cmake/test-files.cmake | 1 | ||||
-rw-r--r-- | include/mbgl/style/sources/custom_vector_source.hpp | 34 | ||||
-rw-r--r-- | include/mbgl/style/sources/geojson_source.hpp | 2 | ||||
-rw-r--r-- | src/mbgl/style/sources/custom_vector_source.cpp | 33 | ||||
-rw-r--r-- | src/mbgl/style/sources/custom_vector_source_impl.cpp | 115 | ||||
-rw-r--r-- | src/mbgl/style/sources/custom_vector_source_impl.hpp | 34 | ||||
-rw-r--r-- | test/style/custom_vector_source.test.cpp | 44 |
8 files changed, 267 insertions, 0 deletions
diff --git a/cmake/core-files.cmake b/cmake/core-files.cmake index 2b8e41b2d4..16fcad9552 100644 --- a/cmake/core-files.cmake +++ b/cmake/core-files.cmake @@ -365,9 +365,13 @@ set(MBGL_CORE_FILES src/mbgl/style/layers/symbol_layer_properties.hpp # style/sources + include/mbgl/style/sources/custom_vector_source.hpp include/mbgl/style/sources/geojson_source.hpp include/mbgl/style/sources/raster_source.hpp include/mbgl/style/sources/vector_source.hpp + src/mbgl/style/sources/custom_vector_source.cpp + src/mbgl/style/sources/custom_vector_source_impl.cpp + src/mbgl/style/sources/custom_vector_source_impl.hpp src/mbgl/style/sources/geojson_source.cpp src/mbgl/style/sources/geojson_source_impl.cpp src/mbgl/style/sources/geojson_source_impl.hpp diff --git a/cmake/test-files.cmake b/cmake/test-files.cmake index 873afa3d9f..8e333ce8d8 100644 --- a/cmake/test-files.cmake +++ b/cmake/test-files.cmake @@ -80,6 +80,7 @@ set(MBGL_TEST_FILES test/style/conversion/stringify.test.cpp # style + test/style/custom_vector_source.test.cpp test/style/filter.test.cpp # style/function diff --git a/include/mbgl/style/sources/custom_vector_source.hpp b/include/mbgl/style/sources/custom_vector_source.hpp new file mode 100644 index 0000000000..6574abb9bd --- /dev/null +++ b/include/mbgl/style/sources/custom_vector_source.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include <mbgl/style/source.hpp> +#include <mbgl/style/sources/geojson_source.hpp> +#include <mbgl/util/geo.hpp> +#include <mbgl/util/geojson.hpp> + +namespace mbgl { +namespace style { + +class CustomVectorSource : public Source { +public: + CustomVectorSource(std::string id, + GeoJSONOptions options, + std::function<void(const CanonicalTileID&)> fetchTile); + + void setTileData(const CanonicalTileID&, const mapbox::geojson::geojson&); + void reloadTile(const CanonicalTileID&); + void reloadRegion(mbgl::LatLngBounds bounds, uint8_t z); + void reload(); + + // Private implementation + + class Impl; + Impl* const impl; +}; + +template <> +inline bool Source::is<CustomVectorSource>() const { + return type == SourceType::Vector; +} + +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/sources/geojson_source.hpp b/include/mbgl/style/sources/geojson_source.hpp index cff8a34644..d5d15f5db1 100644 --- a/include/mbgl/style/sources/geojson_source.hpp +++ b/include/mbgl/style/sources/geojson_source.hpp @@ -3,6 +3,7 @@ #include <mbgl/style/source.hpp> #include <mbgl/util/geojson.hpp> #include <mbgl/util/optional.hpp> +#include <mbgl/util/constants.hpp> #include <mapbox/geojson.hpp> @@ -28,6 +29,7 @@ struct GeoJSONOptions { // GeoJSON-VT options uint8_t minzoom = 0; uint8_t maxzoom = 18; + uint16_t tileSize = util::tileSize; uint16_t buffer = 128; double tolerance = 0.375; diff --git a/src/mbgl/style/sources/custom_vector_source.cpp b/src/mbgl/style/sources/custom_vector_source.cpp new file mode 100644 index 0000000000..d401b5c3fb --- /dev/null +++ b/src/mbgl/style/sources/custom_vector_source.cpp @@ -0,0 +1,33 @@ +#include <mbgl/style/sources/custom_vector_source.hpp> +#include <mbgl/style/sources/custom_vector_source_impl.hpp> + +namespace mbgl { +namespace style { + +CustomVectorSource::CustomVectorSource(std::string id, + const GeoJSONOptions options, + std::function<void(const CanonicalTileID&)> fetchTile) + : Source(SourceType::Vector, + std::make_unique<CustomVectorSource::Impl>(std::move(id), *this, options, fetchTile)), + impl(static_cast<Impl*>(baseImpl.get())) { +} + +void CustomVectorSource::setTileData(const CanonicalTileID& tileId, + const mapbox::geojson::geojson& geoJSON) { + impl->setTileData(tileId, geoJSON); +} + +void CustomVectorSource::reloadRegion(mbgl::LatLngBounds bounds, uint8_t z) { + impl->reloadRegion(bounds, z); +} + +void CustomVectorSource::reloadTile(const CanonicalTileID& tileId) { + impl->reloadTile(tileId); +} + +void CustomVectorSource::reload() { + impl->reload(); +} + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/sources/custom_vector_source_impl.cpp b/src/mbgl/style/sources/custom_vector_source_impl.cpp new file mode 100644 index 0000000000..1a2f90bbc7 --- /dev/null +++ b/src/mbgl/style/sources/custom_vector_source_impl.cpp @@ -0,0 +1,115 @@ +#include <mbgl/style/sources/custom_vector_source_impl.hpp> + +#include <mbgl/style/source_observer.hpp> +#include <mbgl/tile/geojson_tile.hpp> +#include <mbgl/tile/vector_tile.hpp> +#include <mbgl/util/tile_cover.hpp> + +#include <mapbox/geojsonvt.hpp> +#include <supercluster.hpp> + +namespace mbgl { +namespace style { + +CustomVectorSource::Impl::Impl(std::string id_, + Source& base_, + const GeoJSONOptions options_, + std::function<void(const CanonicalTileID&)> fetchTile_) + : Source::Impl(SourceType::Vector, std::move(id_), base_), + options(options_), + fetchTile(fetchTile_) { + loaded = true; +} + +Range<uint8_t> CustomVectorSource::Impl::getZoomRange() const { + return { options.minzoom, options.maxzoom }; +} + +uint16_t CustomVectorSource::Impl::getTileSize() const { + return options.tileSize; +} + +std::unique_ptr<Tile> CustomVectorSource::Impl::createTile(const OverscaledTileID& tileID, + const UpdateParameters& parameters) { + auto tilePointer = std::make_unique<GeoJSONTile>(tileID, base.getID(), parameters); + fetchTile(tileID.canonical); + return std::move(tilePointer); +} + +void CustomVectorSource::Impl::setTileData(const CanonicalTileID& tileID, + const mapbox::geojson::geojson& geoJSON) { + constexpr double scale = util::EXTENT / util::tileSize; + + if (geoJSON.is<FeatureCollection>() && geoJSON.get<FeatureCollection>().empty()) { + for (auto const& item : tiles) { + GeoJSONTile* tile = static_cast<GeoJSONTile*>(item.second.get()); + if (tile->id.canonical == tileID) { + tile->updateData(mapbox::geometry::feature_collection<int16_t>()); + } + } + } else { + variant<GeoJSONVTPointer, SuperclusterPointer> geoJSONOrSupercluster; + if (!options.cluster) { + mapbox::geojsonvt::Options vtOptions; + vtOptions.maxZoom = options.maxzoom; + vtOptions.extent = util::EXTENT; + vtOptions.buffer = std::round(scale * options.buffer); + vtOptions.tolerance = scale * options.tolerance; + geoJSONOrSupercluster = + std::make_unique<mapbox::geojsonvt::GeoJSONVT>(geoJSON, vtOptions); + } else { + mapbox::supercluster::Options clusterOptions; + clusterOptions.maxZoom = options.clusterMaxZoom; + clusterOptions.extent = util::EXTENT; + clusterOptions.radius = std::round(scale * options.clusterRadius); + + const auto& features = geoJSON.get<mapbox::geometry::feature_collection<double>>(); + geoJSONOrSupercluster = + std::make_unique<mapbox::supercluster::Supercluster>(features, clusterOptions); + } + + for (auto const& item : tiles) { + GeoJSONTile* tile = static_cast<GeoJSONTile*>(item.second.get()); + if (tile->id.canonical == tileID) { + if (geoJSONOrSupercluster.is<GeoJSONVTPointer>()) { + tile->updateData(geoJSONOrSupercluster.get<GeoJSONVTPointer>() + ->getTile(tileID.z, tileID.x, tileID.y) + .features); + } else { + assert(geoJSONOrSupercluster.is<SuperclusterPointer>()); + tile->updateData(geoJSONOrSupercluster.get<SuperclusterPointer>()->getTile( + tileID.z, tileID.x, tileID.y)); + } + } + } + } +} + +void CustomVectorSource::Impl::reloadTile(const CanonicalTileID& tileId) { + if (cache.has(OverscaledTileID(tileId.z, tileId.x, tileId.y))) { + cache.clear(); + } + for (auto const& item : tiles) { + GeoJSONTile* tile = static_cast<GeoJSONTile*>(item.second.get()); + if (tile->id.canonical == tileId) { + fetchTile(tileId); + } + } +} + +void CustomVectorSource::Impl::reloadRegion(mbgl::LatLngBounds bounds, const uint8_t z) { + for (const auto& tile : mbgl::util::tileCover(bounds, z)) { + reloadTile(tile.canonical); + } +} + +void CustomVectorSource::Impl::reload() { + cache.clear(); + for (auto const& item : tiles) { + GeoJSONTile* tile = static_cast<GeoJSONTile*>(item.second.get()); + fetchTile(tile->id.canonical); + } +} + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/sources/custom_vector_source_impl.hpp b/src/mbgl/style/sources/custom_vector_source_impl.hpp new file mode 100644 index 0000000000..c000a16a5f --- /dev/null +++ b/src/mbgl/style/sources/custom_vector_source_impl.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include <mbgl/style/source_impl.hpp> +#include <mbgl/style/sources/custom_vector_source.hpp> + +namespace mbgl { +namespace style { + +class CustomVectorSource::Impl : public Source::Impl { +public: + Impl(std::string id, + Source&, + GeoJSONOptions options, + std::function<void(const CanonicalTileID&)> fetchTile); + + void loadDescription(FileSource&) final { + } + void setTileData(const CanonicalTileID& tileID, const mapbox::geojson::geojson&); + void reloadTile(const CanonicalTileID& tileID); + void reloadRegion(mbgl::LatLngBounds bounds, uint8_t z); + void reload(); + +private: + uint16_t getTileSize() const; + Range<uint8_t> getZoomRange() const final; + std::unique_ptr<Tile> createTile(const OverscaledTileID&, const UpdateParameters&) final; + +private: + GeoJSONOptions options; + std::function<void(const CanonicalTileID&)> fetchTile; +}; + +} // namespace style +} // namespace mbgl diff --git a/test/style/custom_vector_source.test.cpp b/test/style/custom_vector_source.test.cpp new file mode 100644 index 0000000000..711c753a8e --- /dev/null +++ b/test/style/custom_vector_source.test.cpp @@ -0,0 +1,44 @@ +#include <mbgl/test/util.hpp> + +#include <mbgl/style/sources/custom_vector_source.hpp> +#include <mbgl/style/sources/geojson_source.hpp> +#include <mbgl/tile/tile_id.hpp> +#include <mbgl/util/geo.hpp> + +using namespace mbgl; + +TEST(CustomVectorSource, EmptyData) { + mbgl::style::GeoJSONOptions options; + + const auto callback = [](CanonicalTileID) {}; + + auto testSource = + std::make_unique<mbgl::style::CustomVectorSource>("source", options, callback); + + mbgl::FeatureCollection featureCollection; + testSource->setTileData(CanonicalTileID(0, 0, 0), mbgl::GeoJSON{ featureCollection }); +} + +TEST(CustomVectorSource, Geometry) { + mbgl::style::GeoJSONOptions options; + + const auto callback = [](CanonicalTileID) {}; + + auto testSource = + std::make_unique<mbgl::style::CustomVectorSource>("source", options, callback); + + Polygon<double> polygon = { { { { 0, 0 }, { 0, 45 }, { 45, 45 }, { 45, 0 } } } }; + testSource->setTileData(CanonicalTileID(0, 0, 0), mbgl::GeoJSON{ polygon }); +} + +TEST(CustomVectorSource, ReloadWithNoTiles) { + mbgl::style::GeoJSONOptions options; + + bool called = false; + const auto callback = [&called](CanonicalTileID) { called = true; }; + + auto testSource = + std::make_unique<mbgl::style::CustomVectorSource>("source", options, callback); + testSource->reloadRegion(mbgl::LatLngBounds::world(), 0); + EXPECT_EQ(called, false); +} |