summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonstantin Käfer <mail@kkaefer.com>2015-12-09 16:24:51 -0800
committerKonstantin Käfer <mail@kkaefer.com>2015-12-11 16:23:42 -0800
commit0f9922cff59772375d81202a43284b732b6aacb3 (patch)
treec2fb557962ddbaddf7269ac39e55b02a96c3e63d
parent2f973d0a7e29bdaaa0fc8f2b13d040ef0c189544 (diff)
downloadqtlocation-mapboxgl-0f9922cff59772375d81202a43284b732b6aacb3.tar.gz
[core] create GeoJSON tiles from inline GeoJSON in sources
-rw-r--r--src/mbgl/map/source.cpp3
-rw-r--r--src/mbgl/map/source_info.cpp5
-rw-r--r--src/mbgl/map/source_info.hpp9
-rw-r--r--src/mbgl/style/style_parser.cpp5
-rw-r--r--src/mbgl/tile/geojson_tile.cpp134
-rw-r--r--src/mbgl/tile/geojson_tile.hpp78
6 files changed, 231 insertions, 3 deletions
diff --git a/src/mbgl/map/source.cpp b/src/mbgl/map/source.cpp
index a761d28ab5..28ea69f007 100644
--- a/src/mbgl/map/source.cpp
+++ b/src/mbgl/map/source.cpp
@@ -4,6 +4,7 @@
#include <mbgl/map/tile.hpp>
#include <mbgl/map/vector_tile.hpp>
#include <mbgl/annotation/annotation_tile.hpp>
+#include <mbgl/tile/geojson_tile.hpp>
#include <mbgl/renderer/painter.hpp>
#include <mbgl/util/exception.hpp>
#include <mbgl/util/constants.hpp>
@@ -207,6 +208,8 @@ TileData::State Source::addTile(const TileID& id, const StyleUpdateParameters& p
monitor = std::make_unique<VectorTileMonitor>(info, normalized_id, parameters.pixelRatio);
} else if (info.type == SourceType::Annotations) {
monitor = std::make_unique<AnnotationTileMonitor>(normalized_id, parameters.data);
+ } else if (info.type == SourceType::GeoJSON) {
+ monitor = std::make_unique<GeoJSONTileMonitor>(info.geojsonvt.get(), normalized_id);
} else {
Log::Warning(Event::Style, "Source type '%s' is not implemented", SourceTypeClass(info.type).c_str());
return TileData::State::invalid;
diff --git a/src/mbgl/map/source_info.cpp b/src/mbgl/map/source_info.cpp
index b8ab84b550..3a79cb9dff 100644
--- a/src/mbgl/map/source_info.cpp
+++ b/src/mbgl/map/source_info.cpp
@@ -3,6 +3,8 @@
#include <mbgl/util/string.hpp>
#include <mbgl/util/token.hpp>
+#include <mapbox/geojsonvt.hpp>
+
namespace mbgl {
namespace {
@@ -83,6 +85,9 @@ void parse(const rapidjson::Value& value, std::array<float, N>& target, const ch
} // end namespace
+// Destructor in implementation file because header only contains forward declarations.
+SourceInfo::~SourceInfo() = default;
+
void SourceInfo::parseTileJSONProperties(const rapidjson::Value& value) {
parse(value, tiles, "tiles");
parse(value, min_zoom, "minzoom");
diff --git a/src/mbgl/map/source_info.hpp b/src/mbgl/map/source_info.hpp
index 725e9f4249..5b4e4e2e15 100644
--- a/src/mbgl/map/source_info.hpp
+++ b/src/mbgl/map/source_info.hpp
@@ -14,10 +14,18 @@
#include <vector>
#include <cstdint>
+namespace mapbox {
+namespace geojsonvt {
+class GeoJSONVT;
+} // namespace geojsonvt
+} // namespace mapbox
+
namespace mbgl {
class SourceInfo : private util::noncopyable {
public:
+ ~SourceInfo();
+
SourceType type = SourceType::Vector;
std::string url;
std::vector<std::string> tiles;
@@ -28,6 +36,7 @@ public:
std::array<float, 3> center = { { 0, 0, 0 } };
std::array<float, 4> bounds = { { -180, -90, 180, 90 } };
std::string source_id = "";
+ std::unique_ptr<mapbox::geojsonvt::GeoJSONVT> geojsonvt;
void parseTileJSONProperties(const rapidjson::Value&);
std::string tileURL(const TileID& id, float pixelRatio) const;
diff --git a/src/mbgl/style/style_parser.cpp b/src/mbgl/style/style_parser.cpp
index 483d096a7f..259517b0a5 100644
--- a/src/mbgl/style/style_parser.cpp
+++ b/src/mbgl/style/style_parser.cpp
@@ -168,11 +168,10 @@ bool StyleParser::parseGeoJSONSource(Source& source, const JSVal& sourceVal) {
if (dataVal.IsString()) {
// We need to load an external GeoJSON file
source.info.url = { dataVal.GetString(), dataVal.GetStringLength() };
-
} else if (dataVal.IsObject()) {
// We need to parse dataVal as a GeoJSON object
- auto geojsonvt = std::make_unique<mapbox::geojsonvt::GeoJSONVT>(mapbox::geojsonvt::Convert::convert(dataVal, 0));
- // TODO
+ using namespace mapbox::geojsonvt;
+ source.info.geojsonvt = std::make_unique<GeoJSONVT>(Convert::convert(dataVal, 0));
} else {
Log::Warning(Event::ParseStyle, "GeoJSON data must be a URL or an object");
return false;
diff --git a/src/mbgl/tile/geojson_tile.cpp b/src/mbgl/tile/geojson_tile.cpp
new file mode 100644
index 0000000000..9f14780ca4
--- /dev/null
+++ b/src/mbgl/tile/geojson_tile.cpp
@@ -0,0 +1,134 @@
+#include <mbgl/tile/geojson_tile.hpp>
+#include <mbgl/storage/file_source.hpp>
+#include <mapbox/geojsonvt.hpp>
+
+namespace mbgl {
+
+GeoJSONTileFeature::GeoJSONTileFeature(FeatureType type_,
+ GeometryCollection&& geometries_,
+ GeoJSONTileFeature::Tags&& tags_)
+ : type(type_), geometries(std::move(geometries_)), tags(std::move(tags_)) {
+}
+
+FeatureType GeoJSONTileFeature::getType() const {
+ return type;
+}
+
+mapbox::util::optional<Value> GeoJSONTileFeature::getValue(const std::string& key) const {
+ auto it = tags.find(key);
+ if (it != tags.end()) {
+ return mapbox::util::optional<Value>(it->second);
+ }
+ return mapbox::util::optional<Value>();
+}
+
+GeometryCollection GeoJSONTileFeature::getGeometries() const {
+ return geometries;
+}
+
+GeoJSONTileLayer::GeoJSONTileLayer(Features&& features_) : features(std::move(features_)) {
+}
+
+std::size_t GeoJSONTileLayer::featureCount() const {
+ return features.size();
+}
+
+util::ptr<const GeometryTileFeature> GeoJSONTileLayer::getFeature(std::size_t i) const {
+ return features[i];
+}
+
+GeoJSONTile::GeoJSONTile(std::shared_ptr<GeoJSONTileLayer> layer_) : layer(std::move(layer_)) {
+}
+
+util::ptr<GeometryTileLayer> GeoJSONTile::getLayer(const std::string&) const {
+ // We're ignoring the layer name because GeoJSON tiles only have one layer.
+ return layer;
+}
+
+// Converts the geojsonvt::Tile to a a GeoJSONTile. They have a differing internal structure.
+std::unique_ptr<GeoJSONTile> convertTile(const mapbox::geojsonvt::Tile& tile) {
+ std::shared_ptr<GeoJSONTileLayer> layer;
+
+ if (tile) {
+ std::vector<std::shared_ptr<const GeoJSONTileFeature>> features;
+ std::vector<Coordinate> line;
+
+ for (auto& feature : tile.features) {
+ const FeatureType featureType =
+ (feature.type == mapbox::geojsonvt::TileFeatureType::Point
+ ? FeatureType::Point
+ : (feature.type == mapbox::geojsonvt::TileFeatureType::LineString
+ ? FeatureType::LineString
+ : (feature.type == mapbox::geojsonvt::TileFeatureType::Polygon
+ ? FeatureType::Polygon
+ : FeatureType::Unknown)));
+ if (featureType == FeatureType::Unknown) {
+ continue;
+ }
+
+ GeometryCollection geometry;
+
+ // Flatten the geometry; GeoJSONVT distinguishes between a Points array and Rings array
+ // (Points = GeoJSON types Point, MultiPoint, LineString)
+ // (Rings = GeoJSON types MultiLineString, Polygon, MultiPolygon)
+ // However, in Mapbox GL, we use one structure for both types, and just have one outer
+ // element for Points.
+ if (feature.tileGeometry.is<mapbox::geojsonvt::TilePoints>()) {
+ line.clear();
+ for (auto& point : feature.tileGeometry.get<mapbox::geojsonvt::TilePoints>()) {
+ line.emplace_back(point.x, point.y);
+ }
+ geometry.emplace_back(std::move(line));
+ } else if (feature.tileGeometry.is<mapbox::geojsonvt::TileRings>()) {
+ for (auto& ring : feature.tileGeometry.get<mapbox::geojsonvt::TileRings>()) {
+ line.clear();
+ for (auto& point : ring) {
+ line.emplace_back(point.x, point.y);
+ }
+ geometry.emplace_back(std::move(line));
+ }
+ }
+
+ GeoJSONTileFeature::Tags tags{ feature.tags.begin(), feature.tags.end() };
+
+ features.emplace_back(std::make_shared<GeoJSONTileFeature>(
+ featureType, std::move(geometry), std::move(tags)));
+ }
+
+ layer = std::make_unique<GeoJSONTileLayer>(std::move(features));
+ }
+
+ return std::make_unique<GeoJSONTile>(layer);
+}
+
+GeoJSONTileMonitor::GeoJSONTileMonitor(mapbox::geojsonvt::GeoJSONVT* geojsonvt_, const TileID& id)
+ : tileID(id), geojsonvt(geojsonvt_) {
+}
+
+GeoJSONTileMonitor::~GeoJSONTileMonitor() = default;
+
+// A monitor can have its GeoJSONVT object swapped out (e.g. when loading a new GeoJSON file).
+// In that case, we're sending new notifications to all observers.
+void GeoJSONTileMonitor::setGeoJSONVT(mapbox::geojsonvt::GeoJSONVT* vt) {
+ // Don't duplicate notifications in case of nil changes.
+ if (geojsonvt != vt) {
+ geojsonvt = vt;
+ update();
+ }
+}
+
+void GeoJSONTileMonitor::update() {
+ if (geojsonvt) {
+ auto tile = convertTile(geojsonvt->getTile(tileID.z, tileID.x, tileID.y));
+ callback(nullptr, std::move(tile), Seconds::zero(), Seconds::zero());
+ }
+}
+
+std::unique_ptr<FileRequest>
+GeoJSONTileMonitor::monitorTile(const GeometryTileMonitor::Callback& cb) {
+ callback = cb;
+ update();
+ return nullptr;
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/tile/geojson_tile.hpp b/src/mbgl/tile/geojson_tile.hpp
new file mode 100644
index 0000000000..e5e9766a17
--- /dev/null
+++ b/src/mbgl/tile/geojson_tile.hpp
@@ -0,0 +1,78 @@
+#ifndef MBGL_ANNOTATION_GEOJSON_VT_TILE
+#define MBGL_ANNOTATION_GEOJSON_VT_TILE
+
+#include <mbgl/map/geometry_tile.hpp>
+#include <mbgl/map/tile_id.hpp>
+
+#include <unordered_map>
+
+namespace mapbox {
+namespace geojsonvt {
+class GeoJSONVT;
+} // namespace geojsonvt
+} // namespace mapbox
+
+namespace mbgl {
+
+// Implements a simple in-memory Tile type that holds GeoJSON values. A GeoJSON tile can only have
+// one layer, and it is always returned regardless of which layer is requested.
+
+class GeoJSONTileFeature : public GeometryTileFeature {
+public:
+ using Tags = std::unordered_map<std::string, std::string>;
+
+ GeoJSONTileFeature(FeatureType, GeometryCollection&&, Tags&& = Tags{});
+ FeatureType getType() const override;
+ mapbox::util::optional<Value> getValue(const std::string&) const override;
+ GeometryCollection getGeometries() const override;
+
+private:
+ const FeatureType type;
+ const GeometryCollection geometries;
+ const Tags tags;
+};
+
+class GeoJSONTileLayer : public GeometryTileLayer {
+public:
+ using Features = std::vector<std::shared_ptr<const GeoJSONTileFeature>>;
+
+ GeoJSONTileLayer(Features&&);
+ std::size_t featureCount() const override;
+ util::ptr<const GeometryTileFeature> getFeature(std::size_t) const override;
+
+private:
+ const Features features;
+};
+
+class GeoJSONTile : public GeometryTile {
+public:
+ GeoJSONTile(std::shared_ptr<GeoJSONTileLayer>);
+ util::ptr<GeometryTileLayer> getLayer(const std::string&) const override;
+
+private:
+ const std::shared_ptr<GeoJSONTileLayer> layer;
+};
+
+class GeoJSONTileMonitor : public GeometryTileMonitor {
+public:
+ GeoJSONTileMonitor(mapbox::geojsonvt::GeoJSONVT*, const TileID&);
+ virtual ~GeoJSONTileMonitor();
+
+ std::unique_ptr<FileRequest> monitorTile(const GeometryTileMonitor::Callback&) override;
+
+ void setGeoJSONVT(mapbox::geojsonvt::GeoJSONVT*);
+
+private:
+ void update();
+
+public:
+ const TileID tileID;
+
+private:
+ mapbox::geojsonvt::GeoJSONVT* geojsonvt = nullptr;
+ GeometryTileMonitor::Callback callback;
+};
+
+} // namespace mbgl
+
+#endif