[core] Calculate GeoJSON tile geometries in a background thread
Call `mapbox::geojsonvt::GeoJSONVT::getTile()` in a background thread, so that the rendering thread is not blocked.
This commit is contained in:
@@ -39,17 +39,19 @@ struct GeoJSONOptions {
|
||||
};
|
||||
class GeoJSONData {
|
||||
public:
|
||||
using TileFeatures = mapbox::feature::feature_collection<int16_t>;
|
||||
using Features = mapbox::feature::feature_collection<double>;
|
||||
static std::shared_ptr<GeoJSONData> create(const GeoJSON&,
|
||||
Immutable<GeoJSONOptions> = GeoJSONOptions::defaultOptions());
|
||||
|
||||
virtual ~GeoJSONData() = default;
|
||||
virtual mapbox::feature::feature_collection<int16_t> getTile(const CanonicalTileID&) = 0;
|
||||
virtual void getTile(const CanonicalTileID&, const std::function<void(TileFeatures)>&) = 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 Features getChildren(const std::uint32_t) = 0;
|
||||
virtual Features 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;
|
||||
};
|
||||
|
||||
|
||||
@@ -95,8 +95,7 @@ void RenderGeoJSONSource::update(Immutable<style::Source::Impl> baseImpl_,
|
||||
const uint8_t maxZ = impl().getZoomRange().max;
|
||||
for (const auto& pair : tilePyramid.getTiles()) {
|
||||
if (pair.first.canonical.z <= maxZ) {
|
||||
static_cast<GeoJSONTile*>(pair.second.get())
|
||||
->updateData(data_->getTile(pair.first.canonical), needsRelayout);
|
||||
static_cast<GeoJSONTile*>(pair.second.get())->updateData(data_, needsRelayout);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,8 +111,8 @@ void RenderGeoJSONSource::update(Immutable<style::Source::Impl> baseImpl_,
|
||||
util::tileSize,
|
||||
impl().getZoomRange(),
|
||||
optional<LatLngBounds>{},
|
||||
[&, data_] (const OverscaledTileID& tileID) {
|
||||
return std::make_unique<GeoJSONTile>(tileID, impl().id, parameters, data_->getTile(tileID.canonical));
|
||||
[&, data_](const OverscaledTileID& tileID) {
|
||||
return std::make_unique<GeoJSONTile>(tileID, impl().id, parameters, data_);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <mbgl/util/constants.hpp>
|
||||
#include <mbgl/util/feature.hpp>
|
||||
#include <mbgl/util/string.hpp>
|
||||
#include <mbgl/util/thread_pool.hpp>
|
||||
|
||||
#include <mapbox/geojsonvt.hpp>
|
||||
#include <supercluster.hpp>
|
||||
@@ -18,18 +19,16 @@ public:
|
||||
: impl(geoJSON, options) {
|
||||
}
|
||||
|
||||
mapbox::feature::feature_collection<int16_t> getTile(const CanonicalTileID& tileID) final {
|
||||
return impl.getTile(tileID.z, tileID.x, tileID.y).features;
|
||||
void getTile(const CanonicalTileID& id, const std::function<void(TileFeatures)>& fn) final {
|
||||
assert(fn);
|
||||
// It's safe to pass `this` as scheduler will die earlier.
|
||||
scheduler.scheduleAndReplyValue(
|
||||
[id, this]() -> TileFeatures { return impl.getTile(id.z, id.x, id.y).features; }, fn);
|
||||
}
|
||||
|
||||
mapbox::feature::feature_collection<double> getChildren(const std::uint32_t) final {
|
||||
return {};
|
||||
}
|
||||
Features getChildren(const std::uint32_t) final { return {}; }
|
||||
|
||||
mapbox::feature::feature_collection<double>
|
||||
getLeaves(const std::uint32_t, const std::uint32_t, const std::uint32_t) final {
|
||||
return {};
|
||||
}
|
||||
Features getLeaves(const std::uint32_t, const std::uint32_t, const std::uint32_t) final { return {}; }
|
||||
|
||||
std::uint8_t getClusterExpansionZoom(std::uint32_t) final {
|
||||
return 0;
|
||||
@@ -37,26 +36,22 @@ public:
|
||||
|
||||
private:
|
||||
mapbox::geojsonvt::GeoJSONVT impl;
|
||||
SequencedScheduler scheduler;
|
||||
};
|
||||
|
||||
class SuperclusterData : public GeoJSONData {
|
||||
public:
|
||||
SuperclusterData(const mapbox::feature::feature_collection<double>& features,
|
||||
const mapbox::supercluster::Options& options)
|
||||
: impl(features, options) {
|
||||
SuperclusterData(const Features& features, const mapbox::supercluster::Options& options)
|
||||
: impl(features, options) {}
|
||||
|
||||
void getTile(const CanonicalTileID& id, const std::function<void(TileFeatures)>& fn) final {
|
||||
assert(fn);
|
||||
fn(impl.getTile(id.z, id.x, id.y));
|
||||
}
|
||||
|
||||
mapbox::feature::feature_collection<int16_t> getTile(const CanonicalTileID& tileID) final {
|
||||
return impl.getTile(tileID.z, tileID.x, tileID.y);
|
||||
}
|
||||
Features getChildren(const std::uint32_t cluster_id) final { return impl.getChildren(cluster_id); }
|
||||
|
||||
mapbox::feature::feature_collection<double> getChildren(const std::uint32_t cluster_id) final {
|
||||
return impl.getChildren(cluster_id);
|
||||
}
|
||||
|
||||
mapbox::feature::feature_collection<double> getLeaves(const std::uint32_t cluster_id,
|
||||
const std::uint32_t limit,
|
||||
const std::uint32_t offset) final {
|
||||
Features getLeaves(const std::uint32_t cluster_id, const std::uint32_t limit, const std::uint32_t offset) final {
|
||||
return impl.getLeaves(cluster_id, limit, offset);
|
||||
}
|
||||
|
||||
@@ -85,8 +80,7 @@ T evaluateFeature(const mapbox::feature::feature<double>& f,
|
||||
// static
|
||||
std::shared_ptr<GeoJSONData> GeoJSONData::create(const GeoJSON& geoJSON, Immutable<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()) {
|
||||
if (options->cluster && geoJSON.is<Features>() && !geoJSON.get<Features>().empty()) {
|
||||
mapbox::supercluster::Options clusterOptions;
|
||||
clusterOptions.maxZoom = options->clusterMaxZoom;
|
||||
clusterOptions.extent = util::EXTENT;
|
||||
@@ -111,8 +105,7 @@ std::shared_ptr<GeoJSONData> GeoJSONData::create(const GeoJSON& geoJSON, Immutab
|
||||
toReturn[p.first] = evaluateFeature<Value>(*feature, p.second.second, accumulated);
|
||||
}
|
||||
};
|
||||
return std::make_shared<SuperclusterData>(geoJSON.get<mapbox::feature::feature_collection<double>>(),
|
||||
clusterOptions);
|
||||
return std::make_shared<SuperclusterData>(geoJSON.get<Features>(), clusterOptions);
|
||||
}
|
||||
|
||||
mapbox::geojsonvt::Options vtOptions;
|
||||
|
||||
@@ -1,20 +1,29 @@
|
||||
#include <mbgl/tile/geojson_tile.hpp>
|
||||
#include <mbgl/tile/geojson_tile_data.hpp>
|
||||
#include <mbgl/renderer/query.hpp>
|
||||
#include <mbgl/renderer/tile_parameters.hpp>
|
||||
|
||||
#include <mbgl/style/sources/geojson_source.hpp>
|
||||
#include <mbgl/tile/geojson_tile.hpp>
|
||||
#include <mbgl/tile/geojson_tile_data.hpp>
|
||||
namespace mbgl {
|
||||
|
||||
GeoJSONTile::GeoJSONTile(const OverscaledTileID& overscaledTileID,
|
||||
std::string sourceID_,
|
||||
const TileParameters& parameters,
|
||||
mapbox::feature::feature_collection<int16_t> features)
|
||||
std::shared_ptr<style::GeoJSONData> data_)
|
||||
: GeometryTile(overscaledTileID, sourceID_, parameters) {
|
||||
updateData(std::move(features));
|
||||
updateData(std::move(data_));
|
||||
}
|
||||
|
||||
void GeoJSONTile::updateData(mapbox::feature::feature_collection<int16_t> features, bool resetLayers) {
|
||||
setData(std::make_unique<GeoJSONTileData>(std::move(features)), resetLayers);
|
||||
void GeoJSONTile::updateData(std::shared_ptr<style::GeoJSONData> data_, bool resetLayers) {
|
||||
assert(data_);
|
||||
data = std::move(data_);
|
||||
data->getTile(id.canonical,
|
||||
[this, self = weakFactory.makeWeakPtr(), capturedData = data.get(), resetLayers](
|
||||
style::GeoJSONData::TileFeatures features) {
|
||||
if (!self) return;
|
||||
if (data.get() != capturedData) return;
|
||||
auto tileData = std::make_unique<GeoJSONTileData>(std::move(features));
|
||||
setData(std::move(tileData), resetLayers);
|
||||
});
|
||||
}
|
||||
|
||||
void GeoJSONTile::querySourceFeatures(
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
#include <mbgl/util/feature.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace style {
|
||||
class GeoJSONData;
|
||||
} // namespace style
|
||||
|
||||
class TileParameters;
|
||||
|
||||
@@ -12,13 +15,17 @@ public:
|
||||
GeoJSONTile(const OverscaledTileID&,
|
||||
std::string sourceID,
|
||||
const TileParameters&,
|
||||
mapbox::feature::feature_collection<int16_t>);
|
||||
std::shared_ptr<style::GeoJSONData>);
|
||||
|
||||
void updateData(mapbox::feature::feature_collection<int16_t>, bool resetLayers = false);
|
||||
void updateData(std::shared_ptr<style::GeoJSONData> data, bool resetLayers = false);
|
||||
|
||||
void querySourceFeatures(
|
||||
std::vector<Feature>& result,
|
||||
const SourceQueryOptions&) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<style::GeoJSONData> data;
|
||||
mapbox::base::WeakPtrFactory<GeoJSONTile> weakFactory{this};
|
||||
};
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -4,15 +4,16 @@
|
||||
#include <mbgl/tile/geojson_tile.hpp>
|
||||
#include <mbgl/tile/tile_loader_impl.hpp>
|
||||
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
#include <mbgl/annotation/annotation_manager.hpp>
|
||||
#include <mbgl/map/transform.hpp>
|
||||
#include <mbgl/renderer/image_manager.hpp>
|
||||
#include <mbgl/renderer/tile_parameters.hpp>
|
||||
#include <mbgl/style/style.hpp>
|
||||
#include <mbgl/style/layers/circle_layer.hpp>
|
||||
#include <mbgl/style/layers/circle_layer_impl.hpp>
|
||||
#include <mbgl/annotation/annotation_manager.hpp>
|
||||
#include <mbgl/renderer/image_manager.hpp>
|
||||
#include <mbgl/style/sources/geojson_source.hpp>
|
||||
#include <mbgl/style/style.hpp>
|
||||
#include <mbgl/text/glyph_manager.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
@@ -43,6 +44,29 @@ public:
|
||||
};
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
class FakeGeoJSONData : public GeoJSONData {
|
||||
public:
|
||||
FakeGeoJSONData(TileFeatures features_) : features(std::move(features_)) {}
|
||||
|
||||
void getTile(const CanonicalTileID&, const std::function<void(TileFeatures)>& fn) final {
|
||||
assert(fn);
|
||||
fn(features);
|
||||
}
|
||||
|
||||
Features getChildren(const std::uint32_t) final { return {}; }
|
||||
|
||||
Features getLeaves(const std::uint32_t, const std::uint32_t, const std::uint32_t) final { return {}; }
|
||||
|
||||
std::uint8_t getClusterExpansionZoom(std::uint32_t) final { return 0; }
|
||||
|
||||
private:
|
||||
TileFeatures features;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(GeoJSONTile, Issue7648) {
|
||||
GeoJSONTileTest test;
|
||||
|
||||
@@ -50,8 +74,8 @@ TEST(GeoJSONTile, Issue7648) {
|
||||
|
||||
mapbox::feature::feature_collection<int16_t> features;
|
||||
features.push_back(mapbox::feature::feature<int16_t> { mapbox::geometry::point<int16_t>(0, 0) });
|
||||
|
||||
GeoJSONTile tile(OverscaledTileID(0, 0, 0), "source", test.tileParameters, features);
|
||||
auto data = std::make_shared<FakeGeoJSONData>(std::move(features));
|
||||
GeoJSONTile tile(OverscaledTileID(0, 0, 0), "source", test.tileParameters, data);
|
||||
Immutable<LayerProperties> layerProperties = makeMutable<CircleLayerProperties>(staticImmutableCast<CircleLayer::Impl>(layer.baseImpl));
|
||||
StubTileObserver observer;
|
||||
observer.tileChanged = [&] (const Tile&) {
|
||||
@@ -68,7 +92,7 @@ TEST(GeoJSONTile, Issue7648) {
|
||||
test.loop.runOnce();
|
||||
}
|
||||
|
||||
tile.updateData(features);
|
||||
tile.updateData(data);
|
||||
while (!tile.isComplete()) {
|
||||
test.loop.runOnce();
|
||||
}
|
||||
@@ -83,8 +107,8 @@ TEST(GeoJSONTile, Issue9927) {
|
||||
|
||||
mapbox::feature::feature_collection<int16_t> features;
|
||||
features.push_back(mapbox::feature::feature<int16_t> { mapbox::geometry::point<int16_t>(0, 0) });
|
||||
|
||||
GeoJSONTile tile(OverscaledTileID(0, 0, 0), "source", test.tileParameters, features);
|
||||
auto data = std::make_shared<FakeGeoJSONData>(std::move(features));
|
||||
GeoJSONTile tile(OverscaledTileID(0, 0, 0), "source", test.tileParameters, data);
|
||||
|
||||
Immutable<LayerProperties> layerProperties = makeMutable<CircleLayerProperties>(staticImmutableCast<CircleLayer::Impl>(layer.baseImpl));
|
||||
std::vector<Immutable<LayerProperties>> layers { layerProperties };
|
||||
|
||||
Reference in New Issue
Block a user