summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesse Crocker <jesse@gaiagps.com>2016-12-08 10:39:55 -0700
committerKonstantin Käfer <mail@kkaefer.com>2017-03-21 11:01:14 +0100
commit273a2fa4785a807abbec011ee347d9e3e4d5f74c (patch)
tree487a12dc00aaa2839a06dd0b865632a974576d45
parent461a157caeec4b21bee0fc0adc002fbb64ab1444 (diff)
downloadqtlocation-mapboxgl-273a2fa4785a807abbec011ee347d9e3e4d5f74c.tar.gz
[core] Custom vector sources
-rw-r--r--cmake/core-files.cmake4
-rw-r--r--cmake/test-files.cmake1
-rw-r--r--include/mbgl/style/sources/custom_vector_source.hpp34
-rw-r--r--include/mbgl/style/sources/geojson_source.hpp2
-rw-r--r--src/mbgl/style/sources/custom_vector_source.cpp33
-rw-r--r--src/mbgl/style/sources/custom_vector_source_impl.cpp115
-rw-r--r--src/mbgl/style/sources/custom_vector_source_impl.hpp34
-rw-r--r--test/style/custom_vector_source.test.cpp44
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);
+}