[core, node] Implement bindings for addSource
This commit is contained in:
@@ -83,9 +83,9 @@ public:
|
||||
template <class T, class Enable = void>
|
||||
struct Converter;
|
||||
|
||||
template <class T, class V>
|
||||
Result<T> convert(const V& value) {
|
||||
return Converter<T>()(value);
|
||||
template <class T, class V, class...Args>
|
||||
Result<T> convert(const V& value, Args&&...args) {
|
||||
return Converter<T>()(value, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
} // namespace conversion
|
||||
|
||||
15
include/mbgl/style/conversion/geojson.hpp
Normal file
15
include/mbgl/style/conversion/geojson.hpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/style/conversion.hpp>
|
||||
#include <mbgl/style/sources/geojson_source.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace style {
|
||||
namespace conversion {
|
||||
|
||||
template <class V>
|
||||
Result<GeoJSON> convertGeoJSON(const V& value);
|
||||
|
||||
} // namespace conversion
|
||||
} // namespace style
|
||||
} // namespace mbgl
|
||||
123
include/mbgl/style/conversion/source.hpp
Normal file
123
include/mbgl/style/conversion/source.hpp
Normal file
@@ -0,0 +1,123 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/style/source.hpp>
|
||||
#include <mbgl/style/sources/geojson_source.hpp>
|
||||
#include <mbgl/style/sources/raster_source.hpp>
|
||||
#include <mbgl/style/sources/vector_source.hpp>
|
||||
#include <mbgl/style/conversion.hpp>
|
||||
#include <mbgl/style/conversion/tileset.hpp>
|
||||
#include <mbgl/style/conversion/geojson.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace style {
|
||||
namespace conversion {
|
||||
|
||||
template <>
|
||||
struct Converter<std::unique_ptr<Source>> {
|
||||
public:
|
||||
template <class V>
|
||||
Result<std::unique_ptr<Source>> operator()(const V& value, const std::string& id) const {
|
||||
if (!isObject(value)) {
|
||||
return Error { "source must be an object" };
|
||||
}
|
||||
|
||||
auto typeValue = objectMember(value, "type");
|
||||
if (!typeValue) {
|
||||
return Error { "source must have a type" };
|
||||
}
|
||||
|
||||
optional<std::string> type = toString(*typeValue);
|
||||
if (!type) {
|
||||
return Error { "source type must be a string" };
|
||||
}
|
||||
|
||||
if (*type == "raster") {
|
||||
return convertRasterSource(id, value);
|
||||
} else if (*type == "vector") {
|
||||
return convertVectorSource(id, value);
|
||||
} else if (*type == "geojson") {
|
||||
return convertGeoJSONSource(id, value);
|
||||
} else {
|
||||
return Error { "invalid source type" };
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// A tile source can either specify a URL to TileJSON, or inline TileJSON.
|
||||
template <class V>
|
||||
Result<variant<std::string, Tileset>> convertURLOrTileset(const V& value) const {
|
||||
auto urlVal = objectMember(value, "url");
|
||||
if (!urlVal) {
|
||||
Result<Tileset> tileset = convert<Tileset>(value);
|
||||
if (!tileset) {
|
||||
return tileset.error();
|
||||
}
|
||||
return *tileset;
|
||||
}
|
||||
|
||||
optional<std::string> url = toString(*urlVal);
|
||||
if (!url) {
|
||||
return Error { "source url must be a string" };
|
||||
}
|
||||
|
||||
return *url;
|
||||
}
|
||||
|
||||
template <class V>
|
||||
Result<std::unique_ptr<Source>> convertRasterSource(const std::string& id, const V& value) const {
|
||||
Result<variant<std::string, Tileset>> urlOrTileset = convertURLOrTileset(value);
|
||||
if (!urlOrTileset) {
|
||||
return urlOrTileset.error();
|
||||
}
|
||||
|
||||
uint16_t tileSize = util::tileSize;
|
||||
auto tileSizeValue = objectMember(value, "tileSize");
|
||||
if (tileSizeValue) {
|
||||
optional<float> size = toNumber(*tileSizeValue);
|
||||
if (!size || *size < 0 || *size > std::numeric_limits<uint16_t>::max()) {
|
||||
return Error { "invalid tileSize" };
|
||||
}
|
||||
tileSize = *size;
|
||||
}
|
||||
|
||||
return std::make_unique<RasterSource>(id, std::move(*urlOrTileset), tileSize);
|
||||
}
|
||||
|
||||
template <class V>
|
||||
Result<std::unique_ptr<Source>> convertVectorSource(const std::string& id, const V& value) const {
|
||||
Result<variant<std::string, Tileset>> urlOrTileset = convertURLOrTileset(value);
|
||||
if (!urlOrTileset) {
|
||||
return urlOrTileset.error();
|
||||
}
|
||||
|
||||
return std::make_unique<VectorSource>(id, std::move(*urlOrTileset));
|
||||
}
|
||||
|
||||
template <class V>
|
||||
Result<std::unique_ptr<Source>> 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" };
|
||||
}
|
||||
|
||||
auto result = std::make_unique<GeoJSONSource>(id);
|
||||
|
||||
if (isObject(*dataValue)) {
|
||||
Result<GeoJSON> geoJSON = convertGeoJSON(*dataValue);
|
||||
if (!geoJSON) {
|
||||
return geoJSON.error();
|
||||
}
|
||||
result->setGeoJSON(std::move(*geoJSON));
|
||||
} else if (toString(*dataValue)) {
|
||||
result->setURL(*toString(*dataValue));
|
||||
} else {
|
||||
return Error { "GeoJSON data must be a URL or an object" };
|
||||
}
|
||||
|
||||
return std::move(result);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace conversion
|
||||
} // namespace style
|
||||
} // namespace mbgl
|
||||
67
include/mbgl/style/conversion/tileset.hpp
Normal file
67
include/mbgl/style/conversion/tileset.hpp
Normal file
@@ -0,0 +1,67 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/util/tileset.hpp>
|
||||
#include <mbgl/style/conversion.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace style {
|
||||
namespace conversion {
|
||||
|
||||
template <>
|
||||
struct Converter<Tileset> {
|
||||
public:
|
||||
template <class V>
|
||||
Result<Tileset> operator()(const V& value) const {
|
||||
Tileset result;
|
||||
|
||||
auto tiles = objectMember(value, "tiles");
|
||||
if (!tiles) {
|
||||
return Error { "source must have tiles" };
|
||||
}
|
||||
|
||||
if (!isArray(*tiles)) {
|
||||
return Error { "source tiles must be an array" };
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < arrayLength(*tiles); i++) {
|
||||
optional<std::string> urlTemplate = toString(arrayMember(*tiles, i));
|
||||
if (!urlTemplate) {
|
||||
return Error { "source tiles member must be a string" };
|
||||
}
|
||||
result.tiles.push_back(std::move(*urlTemplate));
|
||||
}
|
||||
|
||||
auto minzoomValue = objectMember(value, "minzoom");
|
||||
if (minzoomValue) {
|
||||
optional<float> minzoom = toNumber(*minzoomValue);
|
||||
if (!minzoom || *minzoom < 0 || *minzoom > std::numeric_limits<uint8_t>::max()) {
|
||||
return Error { "invalid minzoom" };
|
||||
}
|
||||
result.zoomRange.min = *minzoom;
|
||||
}
|
||||
|
||||
auto maxzoomValue = objectMember(value, "maxzoom");
|
||||
if (maxzoomValue) {
|
||||
optional<float> maxzoom = toNumber(*maxzoomValue);
|
||||
if (!maxzoom || *maxzoom < 0 || *maxzoom > std::numeric_limits<uint8_t>::max()) {
|
||||
return Error { "invalid maxzoom" };
|
||||
}
|
||||
result.zoomRange.max = *maxzoom;
|
||||
}
|
||||
|
||||
auto attributionValue = objectMember(value, "attribution");
|
||||
if (attributionValue) {
|
||||
optional<std::string> attribution = toString(*attributionValue);
|
||||
if (!attribution) {
|
||||
return Error { "source attribution must be a string" };
|
||||
}
|
||||
result.attribution = std::move(*attribution);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace conversion
|
||||
} // namespace style
|
||||
} // namespace mbgl
|
||||
@@ -1,26 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/style/source.hpp>
|
||||
#include <mbgl/util/geojson.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace style {
|
||||
|
||||
class GeoJSONSource : public Source {
|
||||
public:
|
||||
// Future public API:
|
||||
// void setData(FeatureCollection&&);
|
||||
// void setJSON(const std::string& json);
|
||||
// void loadData(const std::string& url);
|
||||
GeoJSONSource(const std::string& id);
|
||||
|
||||
void setURL(const std::string& url);
|
||||
void setGeoJSON(GeoJSON&&);
|
||||
|
||||
// Private implementation
|
||||
|
||||
class Impl;
|
||||
|
||||
template <class Fn>
|
||||
GeoJSONSource(Fn&& fn)
|
||||
: Source(SourceType::GeoJSON, fn(*this)) {
|
||||
}
|
||||
Impl* const impl;
|
||||
};
|
||||
|
||||
} // namespace style
|
||||
|
||||
22
include/mbgl/util/geojson.hpp
Normal file
22
include/mbgl/util/geojson.hpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace mapbox {
|
||||
namespace geojsonvt {
|
||||
class GeoJSONVT;
|
||||
} // namespace geojsonvt
|
||||
} // namespace mapbox
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class GeoJSON {
|
||||
public:
|
||||
GeoJSON(std::unique_ptr<mapbox::geojsonvt::GeoJSONVT>);
|
||||
GeoJSON(GeoJSON&&);
|
||||
~GeoJSON();
|
||||
|
||||
std::unique_ptr<mapbox::geojsonvt::GeoJSONVT> impl;
|
||||
};
|
||||
|
||||
} // namespace mbgl
|
||||
@@ -23,7 +23,7 @@
|
||||
"express": "^4.11.1",
|
||||
"mapbox-gl-shaders": "mapbox/mapbox-gl-shaders#59e998295d548f208ee3ec10cdd21ff2630e2079",
|
||||
"mapbox-gl-style-spec": "mapbox/mapbox-gl-style-spec#194fc55b6a7dd54c1e2cf2dd9048fbb5e836716d",
|
||||
"mapbox-gl-test-suite": "mapbox/mapbox-gl-test-suite#1633d164231dddf006777366de82178bf34fe866",
|
||||
"mapbox-gl-test-suite": "mapbox/mapbox-gl-test-suite#cb733d358a95d46344c2212f1546ed94022718f7",
|
||||
"node-gyp": "^3.3.1",
|
||||
"request": "^2.72.0",
|
||||
"tape": "^4.5.1"
|
||||
|
||||
@@ -127,7 +127,7 @@ OfflineRegionStatus OfflineDownload::getStatus() const {
|
||||
|
||||
case SourceType::GeoJSON: {
|
||||
style::GeoJSONSource::Impl* geojsonSource = static_cast<style::GeoJSONSource::Impl*>(source->baseImpl.get());
|
||||
const variant<std::string, style::GeoJSONSource::Impl::GeoJSON>& urlOrGeoJSON = geojsonSource->getURLOrGeoJSON();
|
||||
const variant<std::string, GeoJSON>& urlOrGeoJSON = geojsonSource->getURLOrGeoJSON();
|
||||
|
||||
if (urlOrGeoJSON.is<std::string>()) {
|
||||
result.requiredResourceCount += 1;
|
||||
@@ -190,7 +190,7 @@ void OfflineDownload::activateDownload() {
|
||||
|
||||
case SourceType::GeoJSON: {
|
||||
style::GeoJSONSource::Impl* geojsonSource = static_cast<style::GeoJSONSource::Impl*>(source->baseImpl.get());
|
||||
const variant<std::string, style::GeoJSONSource::Impl::GeoJSON>& urlOrGeoJSON = geojsonSource->getURLOrGeoJSON();
|
||||
const variant<std::string, GeoJSON>& urlOrGeoJSON = geojsonSource->getURLOrGeoJSON();
|
||||
|
||||
if (urlOrGeoJSON.is<std::string>()) {
|
||||
ensureResource(Resource::source(urlOrGeoJSON.get<std::string>()));
|
||||
|
||||
14
platform/node/src/node_geojson.hpp
Normal file
14
platform/node/src/node_geojson.hpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#include <mbgl/style/conversion/geojson.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace style {
|
||||
namespace conversion {
|
||||
|
||||
template <>
|
||||
Result<GeoJSON> convertGeoJSON(const v8::Local<v8::Value>&) {
|
||||
return Error { "not implemented" };
|
||||
}
|
||||
|
||||
} // namespace conversion
|
||||
} // namespace style
|
||||
} // namespace mbgl
|
||||
@@ -2,9 +2,11 @@
|
||||
#include "node_request.hpp"
|
||||
#include "node_feature.hpp"
|
||||
#include "node_conversion.hpp"
|
||||
#include "node_geojson.hpp"
|
||||
|
||||
#include <mbgl/platform/default/headless_display.hpp>
|
||||
#include <mbgl/util/exception.hpp>
|
||||
#include <mbgl/style/conversion/source.hpp>
|
||||
#include <mbgl/style/conversion/layer.hpp>
|
||||
#include <mbgl/style/conversion/filter.hpp>
|
||||
|
||||
@@ -56,6 +58,7 @@ NAN_MODULE_INIT(NodeMap::Init) {
|
||||
Nan::SetPrototypeMethod(tpl, "release", Release);
|
||||
|
||||
Nan::SetPrototypeMethod(tpl, "addClass", AddClass);
|
||||
Nan::SetPrototypeMethod(tpl, "addSource", AddSource);
|
||||
Nan::SetPrototypeMethod(tpl, "addLayer", AddLayer);
|
||||
Nan::SetPrototypeMethod(tpl, "setLayoutProperty", SetLayoutProperty);
|
||||
Nan::SetPrototypeMethod(tpl, "setPaintProperty", SetPaintProperty);
|
||||
@@ -484,6 +487,30 @@ NAN_METHOD(NodeMap::AddClass) {
|
||||
info.GetReturnValue().SetUndefined();
|
||||
}
|
||||
|
||||
NAN_METHOD(NodeMap::AddSource) {
|
||||
using namespace mbgl::style;
|
||||
using namespace mbgl::style::conversion;
|
||||
|
||||
auto nodeMap = Nan::ObjectWrap::Unwrap<NodeMap>(info.Holder());
|
||||
if (!nodeMap->map) return Nan::ThrowError(releasedMessage());
|
||||
|
||||
if (info.Length() != 2) {
|
||||
return Nan::ThrowTypeError("Two argument required");
|
||||
}
|
||||
|
||||
if (!info[0]->IsString()) {
|
||||
return Nan::ThrowTypeError("First argument must be a string");
|
||||
}
|
||||
|
||||
Result<std::unique_ptr<Source>> source = convert<std::unique_ptr<Source>>(info[1], *Nan::Utf8String(info[0]));
|
||||
if (!source) {
|
||||
Nan::ThrowTypeError(source.error().message);
|
||||
return;
|
||||
}
|
||||
|
||||
nodeMap->map->addSource(std::move(*source));
|
||||
}
|
||||
|
||||
NAN_METHOD(NodeMap::AddLayer) {
|
||||
using namespace mbgl::style;
|
||||
using namespace mbgl::style::conversion;
|
||||
|
||||
@@ -26,6 +26,7 @@ public:
|
||||
static NAN_METHOD(Render);
|
||||
static NAN_METHOD(Release);
|
||||
static NAN_METHOD(AddClass);
|
||||
static NAN_METHOD(AddSource);
|
||||
static NAN_METHOD(AddLayer);
|
||||
static NAN_METHOD(SetLayoutProperty);
|
||||
static NAN_METHOD(SetPaintProperty);
|
||||
|
||||
@@ -1,23 +1,13 @@
|
||||
#include <mbgl/style/parser.hpp>
|
||||
#include <mbgl/style/sources/raster_source_impl.hpp>
|
||||
#include <mbgl/style/sources/vector_source_impl.hpp>
|
||||
#include <mbgl/style/sources/geojson_source_impl.hpp>
|
||||
#include <mbgl/style/layer_impl.hpp>
|
||||
#include <mbgl/style/layers/fill_layer.hpp>
|
||||
#include <mbgl/style/layers/line_layer.hpp>
|
||||
#include <mbgl/style/layers/circle_layer.hpp>
|
||||
#include <mbgl/style/layers/symbol_layer.hpp>
|
||||
#include <mbgl/style/layers/raster_layer.hpp>
|
||||
#include <mbgl/style/layers/background_layer.hpp>
|
||||
#include <mbgl/style/rapidjson_conversion.hpp>
|
||||
#include <mbgl/style/conversion.hpp>
|
||||
#include <mbgl/style/conversion/source.hpp>
|
||||
#include <mbgl/style/conversion/layer.hpp>
|
||||
|
||||
#include <mbgl/platform/log.hpp>
|
||||
|
||||
#include <mbgl/tile/geometry_tile_data.hpp>
|
||||
#include <mbgl/util/enum.hpp>
|
||||
#include <mbgl/util/tileset.hpp>
|
||||
#include <mapbox/geojsonvt.hpp>
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/error/en.h>
|
||||
@@ -75,54 +65,18 @@ void Parser::parseSources(const JSValue& value) {
|
||||
return;
|
||||
}
|
||||
|
||||
JSValue::ConstMemberIterator itr = value.MemberBegin();
|
||||
for (; itr != value.MemberEnd(); ++itr) {
|
||||
const JSValue& nameVal = itr->name;
|
||||
const JSValue& sourceVal = itr->value;
|
||||
for (auto it = value.MemberBegin(); it != value.MemberEnd(); ++it) {
|
||||
std::string id = *conversion::toString(it->name);
|
||||
|
||||
if (!sourceVal.HasMember("type")) {
|
||||
Log::Warning(Event::ParseStyle, "source must have a type");
|
||||
conversion::Result<std::unique_ptr<Source>> source
|
||||
= conversion::convert<std::unique_ptr<Source>>(it->value, id);
|
||||
if (!source) {
|
||||
Log::Warning(Event::ParseStyle, source.error().message);
|
||||
continue;
|
||||
}
|
||||
|
||||
const JSValue& typeVal = sourceVal["type"];
|
||||
if (!typeVal.IsString()) {
|
||||
Log::Warning(Event::ParseStyle, "source type must be a string");
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto type = Enum<SourceType>::toEnum({ typeVal.GetString(), typeVal.GetStringLength() });
|
||||
if (!type) {
|
||||
Log::Warning(Event::ParseStyle, "source type must have one of the enum values");
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string id { nameVal.GetString(), nameVal.GetStringLength() };
|
||||
std::unique_ptr<Source> source;
|
||||
|
||||
switch (*type) {
|
||||
case SourceType::Raster: {
|
||||
source = RasterSource::Impl::parse(id, sourceVal);
|
||||
break;
|
||||
}
|
||||
|
||||
case SourceType::Vector:
|
||||
source = VectorSource::Impl::parse(id, sourceVal);
|
||||
break;
|
||||
|
||||
case SourceType::GeoJSON:
|
||||
source = GeoJSONSource::Impl::parse(id, sourceVal);
|
||||
break;
|
||||
|
||||
default:
|
||||
Log::Error(Event::ParseStyle, "source type '%s' is not supported", typeVal.GetString());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (source) {
|
||||
sourcesMap.emplace(id, source.get());
|
||||
sources.emplace_back(std::move(source));
|
||||
}
|
||||
sourcesMap.emplace(id, (*source).get());
|
||||
sources.emplace_back(std::move(*source));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,5 +4,18 @@
|
||||
namespace mbgl {
|
||||
namespace style {
|
||||
|
||||
GeoJSONSource::GeoJSONSource(const std::string& id)
|
||||
: Source(SourceType::GeoJSON, std::make_unique<GeoJSONSource::Impl>(std::move(id), *this))
|
||||
, impl(static_cast<Impl*>(baseImpl.get())) {
|
||||
}
|
||||
|
||||
void GeoJSONSource::setURL(const std::string& url) {
|
||||
impl->setURL(url);
|
||||
}
|
||||
|
||||
void GeoJSONSource::setGeoJSON(GeoJSON&& geoJSON) {
|
||||
impl->setGeoJSON(std::move(geoJSON));
|
||||
}
|
||||
|
||||
} // namespace style
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
#include <mbgl/style/sources/geojson_source_impl.hpp>
|
||||
#include <mbgl/style/source_observer.hpp>
|
||||
#include <mbgl/style/parser.hpp>
|
||||
#include <mbgl/style/conversion/geojson.hpp>
|
||||
#include <mbgl/tile/geojson_tile.hpp>
|
||||
#include <mbgl/storage/file_source.hpp>
|
||||
#include <mbgl/platform/log.hpp>
|
||||
#include <mbgl/util/rapidjson.hpp>
|
||||
|
||||
#include <mapbox/geojsonvt.hpp>
|
||||
#include <mapbox/geojsonvt/convert.hpp>
|
||||
@@ -12,57 +13,39 @@
|
||||
|
||||
#include <sstream>
|
||||
|
||||
using namespace mapbox::geojsonvt;
|
||||
|
||||
namespace mbgl {
|
||||
namespace style {
|
||||
|
||||
std::unique_ptr<mapbox::geojsonvt::GeoJSONVT> GeoJSONSource::Impl::parseGeoJSON(const JSValue& value) {
|
||||
using namespace mapbox::geojsonvt;
|
||||
|
||||
namespace conversion {
|
||||
template <>
|
||||
Result<GeoJSON> convertGeoJSON(const JSValue& value) {
|
||||
Options options;
|
||||
options.buffer = util::EXTENT / util::tileSize * 128;
|
||||
options.extent = util::EXTENT;
|
||||
|
||||
try {
|
||||
return std::make_unique<GeoJSONVT>(Convert::convert(value, 0), options);
|
||||
return GeoJSON { std::make_unique<GeoJSONVT>(Convert::convert(value, 0), options) };
|
||||
} catch (const std::exception& ex) {
|
||||
Log::Error(Event::ParseStyle, "Failed to parse GeoJSON data: %s", ex.what());
|
||||
// Create an empty GeoJSON VT object to make sure we're not infinitely waiting for
|
||||
// tiles to load.
|
||||
return std::make_unique<GeoJSONVT>(std::vector<ProjectedFeature>{}, options);
|
||||
return Error { ex.what() };
|
||||
}
|
||||
}
|
||||
} // namespace conversion
|
||||
|
||||
std::unique_ptr<GeoJSONSource> GeoJSONSource::Impl::parse(const std::string& id, const JSValue& value) {
|
||||
// We should probably split this up to have URLs in the url property, and actual data
|
||||
// in the data property. Until then, we're going to detect the content based on the
|
||||
// object type.
|
||||
if (!value.HasMember("data")) {
|
||||
Log::Error(Event::ParseStyle, "GeoJSON source must have a data value");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const JSValue& dataVal = value["data"];
|
||||
if (dataVal.IsString()) {
|
||||
return std::make_unique<GeoJSONSource>([&] (Source& base) {
|
||||
return std::make_unique<Impl>(id, base, std::string(dataVal.GetString(), dataVal.GetStringLength()));
|
||||
});
|
||||
} else if (dataVal.IsObject()) {
|
||||
return std::make_unique<GeoJSONSource>([&] (Source& base) {
|
||||
return std::make_unique<Impl>(id, base, parseGeoJSON(dataVal));
|
||||
});
|
||||
} else {
|
||||
Log::Error(Event::ParseStyle, "GeoJSON data must be a URL or an object");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
GeoJSONSource::Impl::Impl(std::string id_, Source& base_, variant<std::string, GeoJSON> urlOrGeoJSON_)
|
||||
: Source::Impl(SourceType::GeoJSON, std::move(id_), base_),
|
||||
urlOrGeoJSON(std::move(urlOrGeoJSON_)) {
|
||||
GeoJSONSource::Impl::Impl(std::string id_, Source& base_)
|
||||
: Source::Impl(SourceType::GeoJSON, std::move(id_), base_) {
|
||||
}
|
||||
|
||||
GeoJSONSource::Impl::~Impl() = default;
|
||||
|
||||
void GeoJSONSource::Impl::setURL(std::string url) {
|
||||
urlOrGeoJSON = std::move(url);
|
||||
}
|
||||
|
||||
void GeoJSONSource::Impl::setGeoJSON(GeoJSON&& geoJSON) {
|
||||
urlOrGeoJSON = std::move(geoJSON);
|
||||
}
|
||||
|
||||
void GeoJSONSource::Impl::load(FileSource& fileSource) {
|
||||
if (urlOrGeoJSON.is<GeoJSON>()) {
|
||||
loaded = true;
|
||||
@@ -94,9 +77,17 @@ void GeoJSONSource::Impl::load(FileSource& fileSource) {
|
||||
|
||||
invalidateTiles();
|
||||
|
||||
urlOrGeoJSON = parseGeoJSON(d);
|
||||
loaded = true;
|
||||
conversion::Result<GeoJSON> geoJSON = conversion::convertGeoJSON<JSValue>(d);
|
||||
if (!geoJSON) {
|
||||
Log::Error(Event::ParseStyle, "Failed to parse GeoJSON data: %s", geoJSON.error().message);
|
||||
// Create an empty GeoJSON VT object to make sure we're not infinitely waiting for
|
||||
// tiles to load.
|
||||
urlOrGeoJSON = GeoJSON { std::make_unique<GeoJSONVT>(std::vector<ProjectedFeature>()) };
|
||||
} else {
|
||||
urlOrGeoJSON = std::move(*geoJSON);
|
||||
}
|
||||
|
||||
loaded = true;
|
||||
observer->onSourceLoaded(base);
|
||||
}
|
||||
});
|
||||
@@ -104,13 +95,13 @@ void GeoJSONSource::Impl::load(FileSource& fileSource) {
|
||||
|
||||
Range<uint8_t> GeoJSONSource::Impl::getZoomRange() {
|
||||
assert(loaded);
|
||||
return { 0, urlOrGeoJSON.get<GeoJSON>()->options.maxZoom };
|
||||
return { 0, urlOrGeoJSON.get<GeoJSON>().impl->options.maxZoom };
|
||||
}
|
||||
|
||||
std::unique_ptr<Tile> GeoJSONSource::Impl::createTile(const OverscaledTileID& tileID,
|
||||
const UpdateParameters& parameters) {
|
||||
const UpdateParameters& parameters) {
|
||||
assert(loaded);
|
||||
return std::make_unique<GeoJSONTile>(tileID, base.getID(), parameters, *urlOrGeoJSON.get<GeoJSON>());
|
||||
return std::make_unique<GeoJSONTile>(tileID, base.getID(), parameters, *urlOrGeoJSON.get<GeoJSON>().impl);
|
||||
}
|
||||
|
||||
} // namespace style
|
||||
|
||||
@@ -2,15 +2,8 @@
|
||||
|
||||
#include <mbgl/style/sources/geojson_source.hpp>
|
||||
#include <mbgl/style/source_impl.hpp>
|
||||
#include <mbgl/util/rapidjson.hpp>
|
||||
#include <mbgl/util/variant.hpp>
|
||||
|
||||
namespace mapbox {
|
||||
namespace geojsonvt {
|
||||
class GeoJSONVT;
|
||||
} // namespace geojsonvt
|
||||
} // namespace mapbox
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class AsyncRequest;
|
||||
@@ -19,15 +12,12 @@ namespace style {
|
||||
|
||||
class GeoJSONSource::Impl : public Source::Impl {
|
||||
public:
|
||||
using GeoJSON = std::unique_ptr<mapbox::geojsonvt::GeoJSONVT>;
|
||||
|
||||
static std::unique_ptr<GeoJSONSource> parse(const std::string& id, const JSValue&);
|
||||
static GeoJSON parseGeoJSON(const JSValue&);
|
||||
|
||||
Impl(std::string id, Source&,
|
||||
variant<std::string, GeoJSON> urlOrGeoJSON);
|
||||
Impl(std::string id, Source&);
|
||||
~Impl() final;
|
||||
|
||||
void setURL(std::string);
|
||||
void setGeoJSON(GeoJSON&&);
|
||||
|
||||
void load(FileSource&) final;
|
||||
|
||||
uint16_t getTileSize() const final {
|
||||
|
||||
@@ -1,30 +1,9 @@
|
||||
#include <mbgl/style/sources/raster_source_impl.hpp>
|
||||
#include <mbgl/tile/raster_tile.hpp>
|
||||
#include <mbgl/platform/log.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace style {
|
||||
|
||||
std::unique_ptr<RasterSource> RasterSource::Impl::parse(std::string id, const JSValue& value) {
|
||||
optional<variant<std::string, Tileset>> urlOrTileset = TileSourceImpl::parseURLOrTileset(value);
|
||||
if (!urlOrTileset) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint16_t tileSize = util::tileSize;
|
||||
if (value.HasMember("tileSize")) {
|
||||
const JSValue& tileSizeVal = value["tileSize"];
|
||||
if (tileSizeVal.IsNumber() && tileSizeVal.GetUint64() <= std::numeric_limits<uint16_t>::max()) {
|
||||
tileSize = tileSizeVal.GetUint64();
|
||||
} else {
|
||||
Log::Error(Event::ParseStyle, "invalid tileSize");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_unique<RasterSource>(std::move(id), std::move(*urlOrTileset), tileSize);
|
||||
}
|
||||
|
||||
RasterSource::Impl::Impl(std::string id_, Source& base_,
|
||||
variant<std::string, Tileset> urlOrTileset_,
|
||||
uint16_t tileSize_)
|
||||
|
||||
@@ -8,8 +8,6 @@ namespace style {
|
||||
|
||||
class RasterSource::Impl : public TileSourceImpl {
|
||||
public:
|
||||
static std::unique_ptr<RasterSource> parse(std::string id, const JSValue&);
|
||||
|
||||
Impl(std::string id, Source&, variant<std::string, Tileset>, uint16_t tileSize);
|
||||
|
||||
private:
|
||||
|
||||
@@ -4,14 +4,6 @@
|
||||
namespace mbgl {
|
||||
namespace style {
|
||||
|
||||
std::unique_ptr<VectorSource> VectorSource::Impl::parse(std::string id, const JSValue& value) {
|
||||
optional<variant<std::string, Tileset>> urlOrTileset = TileSourceImpl::parseURLOrTileset(value);
|
||||
if (!urlOrTileset) {
|
||||
return nullptr;
|
||||
}
|
||||
return std::make_unique<VectorSource>(std::move(id), std::move(*urlOrTileset));
|
||||
}
|
||||
|
||||
VectorSource::Impl::Impl(std::string id_, Source& base_, variant<std::string, Tileset> urlOrTileset_)
|
||||
: TileSourceImpl(SourceType::Vector, std::move(id_), base_, std::move(urlOrTileset_), util::tileSize) {
|
||||
}
|
||||
|
||||
@@ -8,8 +8,6 @@ namespace style {
|
||||
|
||||
class VectorSource::Impl : public TileSourceImpl {
|
||||
public:
|
||||
static std::unique_ptr<VectorSource> parse(std::string id, const JSValue&);
|
||||
|
||||
Impl(std::string id, Source&, variant<std::string, Tileset>);
|
||||
|
||||
private:
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#include <mbgl/style/tile_source_impl.hpp>
|
||||
#include <mbgl/style/source_observer.hpp>
|
||||
#include <mbgl/style/parser.hpp>
|
||||
#include <mbgl/style/rapidjson_conversion.hpp>
|
||||
#include <mbgl/style/conversion/tileset.hpp>
|
||||
#include <mbgl/util/tileset.hpp>
|
||||
#include <mbgl/util/mapbox.hpp>
|
||||
#include <mbgl/storage/file_source.hpp>
|
||||
#include <mbgl/platform/log.hpp>
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/error/en.h>
|
||||
@@ -14,73 +14,6 @@
|
||||
namespace mbgl {
|
||||
namespace style {
|
||||
|
||||
namespace {
|
||||
|
||||
void parseTileJSONMember(const JSValue& value, std::vector<std::string>& target, const char* name) {
|
||||
if (!value.HasMember(name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const JSValue& property = value[name];
|
||||
if (!property.IsArray()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (rapidjson::SizeType i = 0; i < property.Size(); i++) {
|
||||
if (!property[i].IsString()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (rapidjson::SizeType i = 0; i < property.Size(); i++) {
|
||||
target.emplace_back(std::string(property[i].GetString(), property[i].GetStringLength()));
|
||||
}
|
||||
}
|
||||
|
||||
void parseTileJSONMember(const JSValue& value, std::string& target, const char* name) {
|
||||
if (!value.HasMember(name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const JSValue& property = value[name];
|
||||
if (!property.IsString()) {
|
||||
return;
|
||||
}
|
||||
|
||||
target = { property.GetString(), property.GetStringLength() };
|
||||
}
|
||||
|
||||
void parseTileJSONMember(const JSValue& value, uint8_t& target, const char* name) {
|
||||
if (!value.HasMember(name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const JSValue& property = value[name];
|
||||
if (!property.IsUint()) {
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int uint = property.GetUint();
|
||||
if (uint > std::numeric_limits<uint8_t>::max()) {
|
||||
return;
|
||||
}
|
||||
|
||||
target = uint;
|
||||
}
|
||||
|
||||
Tileset parseTileJSON(const JSValue& value) {
|
||||
Tileset result;
|
||||
|
||||
parseTileJSONMember(value, result.tiles, "tiles");
|
||||
parseTileJSONMember(value, result.zoomRange.min, "minzoom");
|
||||
parseTileJSONMember(value, result.zoomRange.max, "maxzoom");
|
||||
parseTileJSONMember(value, result.attribution, "attribution");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
|
||||
Tileset TileSourceImpl::parseTileJSON(const std::string& json, const std::string& sourceURL, SourceType type, uint16_t tileSize) {
|
||||
rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator> document;
|
||||
document.Parse<0>(json.c_str());
|
||||
@@ -91,30 +24,19 @@ Tileset TileSourceImpl::parseTileJSON(const std::string& json, const std::string
|
||||
throw std::runtime_error(message.str());
|
||||
}
|
||||
|
||||
Tileset result = mbgl::style::parseTileJSON(document);
|
||||
conversion::Result<Tileset> result = conversion::convert<Tileset>(document);
|
||||
if (!result) {
|
||||
throw std::runtime_error(result.error().message);
|
||||
}
|
||||
|
||||
// TODO: Remove this hack by delivering proper URLs in the TileJSON to begin with.
|
||||
if (util::mapbox::isMapboxURL(sourceURL)) {
|
||||
for (auto& url : result.tiles) {
|
||||
for (auto& url : (*result).tiles) {
|
||||
url = util::mapbox::canonicalizeTileURL(url, type, tileSize);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
optional<variant<std::string, Tileset>> TileSourceImpl::parseURLOrTileset(const JSValue& value) {
|
||||
if (!value.HasMember("url")) {
|
||||
return { mbgl::style::parseTileJSON(value) };
|
||||
}
|
||||
|
||||
const JSValue& urlVal = value["url"];
|
||||
if (!urlVal.IsString()) {
|
||||
Log::Error(Event::ParseStyle, "source url must be a string");
|
||||
return {};
|
||||
}
|
||||
|
||||
return { std::string(urlVal.GetString(), urlVal.GetStringLength()) };
|
||||
return *result;
|
||||
}
|
||||
|
||||
TileSourceImpl::TileSourceImpl(SourceType type_, std::string id_, Source& base_,
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include <mbgl/util/tileset.hpp>
|
||||
#include <mbgl/util/variant.hpp>
|
||||
#include <mbgl/util/optional.hpp>
|
||||
#include <mbgl/util/rapidjson.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
@@ -18,8 +17,6 @@ namespace style {
|
||||
*/
|
||||
class TileSourceImpl : public Source::Impl {
|
||||
public:
|
||||
// A tile source can either specify a URL to TileJSON, or inline TileJSON.
|
||||
static optional<variant<std::string, Tileset>> parseURLOrTileset(const JSValue&);
|
||||
static Tileset parseTileJSON(const std::string& json, const std::string& sourceURL, SourceType, uint16_t tileSize);
|
||||
|
||||
TileSourceImpl(SourceType, std::string id, Source&,
|
||||
|
||||
11
src/mbgl/util/geojson.cpp
Normal file
11
src/mbgl/util/geojson.cpp
Normal file
@@ -0,0 +1,11 @@
|
||||
#include <mbgl/util/geojson.hpp>
|
||||
|
||||
#include <mapbox/geojsonvt.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
GeoJSON::GeoJSON(std::unique_ptr<mapbox::geojsonvt::GeoJSONVT> impl_) : impl(std::move(impl_)) {}
|
||||
GeoJSON::GeoJSON(GeoJSON&&) = default;
|
||||
GeoJSON::~GeoJSON() = default;
|
||||
|
||||
} // namespace mbgl
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"default": {
|
||||
"log": [
|
||||
[1, "ERROR", "ParseStyle", "GeoJSON data must be a URL or an object"]
|
||||
[1, "WARNING", "ParseStyle", "GeoJSON data must be a URL or an object"]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"default": {
|
||||
"log": [
|
||||
[1, "ERROR", "ParseStyle", "GeoJSON source must have a data value"]
|
||||
[1, "WARNING", "ParseStyle", "GeoJSON source must have a data value"]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user