Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Commit

Permalink
[core] create GeoJSON tiles from inline GeoJSON in sources
Browse files Browse the repository at this point in the history
  • Loading branch information
kkaefer committed Dec 10, 2015
1 parent 81715e6 commit e1b56b7
Show file tree
Hide file tree
Showing 6 changed files with 231 additions and 3 deletions.
3 changes: 3 additions & 0 deletions src/mbgl/map/source.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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;
Expand Down
5 changes: 5 additions & 0 deletions src/mbgl/map/source_info.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include <mbgl/util/string.hpp>
#include <mbgl/util/token.hpp>

#include <mapbox/geojsonvt.hpp>

namespace mbgl {

namespace {
Expand Down Expand Up @@ -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");
Expand Down
9 changes: 9 additions & 0 deletions src/mbgl/map/source_info.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -28,6 +36,7 @@ class SourceInfo : private util::noncopyable {
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;
Expand Down
5 changes: 2 additions & 3 deletions src/mbgl/style/style_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
134 changes: 134 additions & 0 deletions src/mbgl/tile/geojson_tile.cpp
Original file line number Diff line number Diff line change
@@ -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
78 changes: 78 additions & 0 deletions src/mbgl/tile/geojson_tile.hpp
Original file line number Diff line number Diff line change
@@ -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&& = {});
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

0 comments on commit e1b56b7

Please sign in to comment.