[core] Introduce and apply GeoJSONData::create() API

This commit is contained in:
Mikhail Pozdnyakov
2019-10-30 11:30:54 +02:00
parent 6900ac9837
commit 8c498cd36c
4 changed files with 49 additions and 40 deletions

View File

@@ -2,6 +2,7 @@
#include <mbgl/style/expression/expression.hpp>
#include <mbgl/style/source.hpp>
#include <mbgl/tile/tile_id.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/geojson.hpp>
#include <mbgl/util/optional.hpp>
@@ -34,6 +35,20 @@ struct GeoJSONOptions {
using ClusterProperties = std::unordered_map<std::string, ClusterExpression>;
ClusterProperties clusterProperties;
};
class GeoJSONData {
public:
static std::shared_ptr<GeoJSONData> create(const GeoJSON&, const GeoJSONOptions&);
virtual ~GeoJSONData() = default;
virtual mapbox::feature::feature_collection<int16_t> getTile(const CanonicalTileID&) = 0;
// SuperclusterData
virtual mapbox::feature::feature_collection<double> getChildren(const std::uint32_t) = 0;
virtual mapbox::feature::feature_collection<double> getLeaves(const std::uint32_t,
const std::uint32_t limit = 10u,
const std::uint32_t offset = 0u) = 0;
virtual std::uint8_t getClusterExpansionZoom(std::uint32_t) = 0;
};
class GeoJSONSource final : public Source {
public:
@@ -42,6 +57,7 @@ public:
void setURL(const std::string& url);
void setGeoJSON(const GeoJSON&);
void setGeoJSONData(std::shared_ptr<GeoJSONData>);
optional<std::string> getURL() const;

View File

@@ -32,8 +32,12 @@ void GeoJSONSource::setURL(const std::string& url_) {
}
void GeoJSONSource::setGeoJSON(const mapbox::geojson::geojson& geoJSON) {
setGeoJSONData(GeoJSONData::create(geoJSON, impl().getOptions()));
}
void GeoJSONSource::setGeoJSONData(std::shared_ptr<GeoJSONData> geoJSONData) {
req.reset();
baseImpl = makeMutable<Impl>(impl(), geoJSON);
baseImpl = makeMutable<Impl>(impl(), std::move(geoJSONData));
observer->onSourceChanged(*this);
}
@@ -62,17 +66,15 @@ void GeoJSONSource::loadDescription(FileSource& fileSource) {
*this, std::make_exception_ptr(std::runtime_error("unexpectedly empty GeoJSON")));
} else {
conversion::Error error;
optional<GeoJSON> geoJSON = conversion::convertJSON<GeoJSON>(*res.data, error);
if (!geoJSON) {
std::shared_ptr<GeoJSONData> geoJSONData;
if (optional<GeoJSON> geoJSON = conversion::convertJSON<GeoJSON>(*res.data, error)) {
geoJSONData = GeoJSONData::create(*geoJSON, impl().getOptions());
} else {
// Create an empty GeoJSON VT object to make sure we're not infinitely waiting for tiles to load.
Log::Error(Event::ParseStyle, "Failed to parse GeoJSON data: %s",
error.message.c_str());
// Create an empty GeoJSON VT object to make sure we're not infinitely waiting for
// tiles to load.
baseImpl = makeMutable<Impl>(impl(), GeoJSON{ FeatureCollection{} });
} else {
baseImpl = makeMutable<Impl>(impl(), *geoJSON);
}
baseImpl = makeMutable<Impl>(impl(), std::move(geoJSONData));
loaded = true;
observer->onSourceLoaded(*this);
}

View File

@@ -82,13 +82,8 @@ T evaluateFeature(const mapbox::feature::feature<double>& f,
return T();
}
GeoJSONSource::Impl::Impl(std::string id_, optional<GeoJSONOptions> options_)
: Source::Impl(SourceType::GeoJSON, std::move(id_)) {
options = options_ ? std::move(*options_) : GeoJSONOptions{};
}
GeoJSONSource::Impl::Impl(const Impl& other, const GeoJSON& geoJSON)
: Source::Impl(other), options(other.options) {
// static
std::shared_ptr<GeoJSONData> GeoJSONData::create(const GeoJSON& geoJSON, const GeoJSONOptions& options) {
constexpr double scale = util::EXTENT / util::tileSize;
if (options.cluster && geoJSON.is<mapbox::feature::feature_collection<double>>() &&
!geoJSON.get<mapbox::feature::feature_collection<double>>().empty()) {
@@ -116,19 +111,27 @@ GeoJSONSource::Impl::Impl(const Impl& other, const GeoJSON& geoJSON)
toReturn[p.first] = evaluateFeature<Value>(feature, p.second.second, accumulated);
}
};
data = std::make_shared<SuperclusterData>(
geoJSON.get<mapbox::feature::feature_collection<double>>(), clusterOptions);
} else {
mapbox::geojsonvt::Options vtOptions;
vtOptions.maxZoom = options.maxzoom;
vtOptions.extent = util::EXTENT;
vtOptions.buffer = ::round(scale * options.buffer);
vtOptions.tolerance = scale * options.tolerance;
vtOptions.lineMetrics = options.lineMetrics;
data = std::make_shared<GeoJSONVTData>(geoJSON, vtOptions);
return std::make_shared<SuperclusterData>(geoJSON.get<mapbox::feature::feature_collection<double>>(),
clusterOptions);
}
mapbox::geojsonvt::Options vtOptions;
vtOptions.maxZoom = options.maxzoom;
vtOptions.extent = util::EXTENT;
vtOptions.buffer = ::round(scale * options.buffer);
vtOptions.tolerance = scale * options.tolerance;
vtOptions.lineMetrics = options.lineMetrics;
return std::make_shared<GeoJSONVTData>(geoJSON, vtOptions);
}
GeoJSONSource::Impl::Impl(std::string id_, optional<GeoJSONOptions> options_)
: Source::Impl(SourceType::GeoJSON, std::move(id_)) {
options = options_ ? std::move(*options_) : GeoJSONOptions{};
}
GeoJSONSource::Impl::Impl(const GeoJSONSource::Impl& other, std::shared_ptr<GeoJSONData> data_)
: Source::Impl(other), options(other.options), data(std::move(data_)) {}
GeoJSONSource::Impl::~Impl() = default;
Range<uint8_t> GeoJSONSource::Impl::getZoomRange() const {

View File

@@ -11,27 +11,15 @@ class CanonicalTileID;
namespace style {
class GeoJSONData {
public:
virtual ~GeoJSONData() = default;
virtual mapbox::feature::feature_collection<int16_t> getTile(const CanonicalTileID&) = 0;
// SuperclusterData
virtual mapbox::feature::feature_collection<double> getChildren(const std::uint32_t) = 0;
virtual mapbox::feature::feature_collection<double> getLeaves(const std::uint32_t,
const std::uint32_t limit = 10u,
const std::uint32_t offset = 0u) = 0;
virtual std::uint8_t getClusterExpansionZoom(std::uint32_t) = 0;
};
class GeoJSONSource::Impl : public Source::Impl {
public:
Impl(std::string id, optional<GeoJSONOptions>);
Impl(const GeoJSONSource::Impl&, const GeoJSON&);
Impl(const GeoJSONSource::Impl&, std::shared_ptr<GeoJSONData>);
~Impl() final;
Range<uint8_t> getZoomRange() const;
std::weak_ptr<GeoJSONData> getData() const;
const GeoJSONOptions& getOptions() const { return options; }
optional<std::string> getAttribution() const final;