Files
MapLibreParticleLab/src/mbgl/style/sources/geojson_source_impl.cpp

159 lines
5.8 KiB
C++

#include <mbgl/style/sources/geojson_source_impl.hpp>
#include <mbgl/tile/tile_id.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/feature.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/util/thread_pool.hpp>
#include <mbgl/util/identity.hpp>
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4244)
#endif
#include <mapbox/geojsonvt.hpp>
#include <supercluster.hpp>
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#include <cmath>
namespace mbgl {
namespace style {
class GeoJSONVTData final : public GeoJSONData {
void getTile(const CanonicalTileID& id, const std::function<void(TileFeatures)>& fn) final {
assert(fn);
sequencedScheduler->scheduleAndReplyValue(
util::SimpleIdentity::Empty,
[id, geoJSONVT_impl = this->impl]() -> TileFeatures {
return geoJSONVT_impl->getTile(id.z, id.x, id.y).features;
},
fn);
}
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; }
friend GeoJSONData;
GeoJSONVTData(const GeoJSON& geoJSON,
const mapbox::geojsonvt::Options& options,
std::shared_ptr<Scheduler> sequencedScheduler_)
: impl(std::make_shared<mapbox::geojsonvt::GeoJSONVT>(geoJSON, options)),
sequencedScheduler(std::move(sequencedScheduler_)) {
assert(sequencedScheduler);
}
std::shared_ptr<mapbox::geojsonvt::GeoJSONVT> impl; // Accessed on worker thread.
std::shared_ptr<Scheduler> sequencedScheduler;
};
class SuperclusterData final : public GeoJSONData {
void getTile(const CanonicalTileID& id, const std::function<void(TileFeatures)>& fn) final {
assert(fn);
fn(impl.getTile(id.z, id.x, id.y));
}
Features getChildren(const std::uint32_t cluster_id) final { return impl.getChildren(cluster_id); }
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);
}
std::uint8_t getClusterExpansionZoom(std::uint32_t cluster_id) final {
return impl.getClusterExpansionZoom(cluster_id);
}
friend GeoJSONData;
SuperclusterData(const Features& features, const mapbox::supercluster::Options& options)
: impl(features, options) {}
mapbox::supercluster::Supercluster impl;
};
template <class T>
T evaluateFeature(const mapbox::feature::feature<double>& f,
const std::shared_ptr<expression::Expression>& expression,
std::optional<T> accumulated = std::nullopt) {
const expression::EvaluationResult result = expression->evaluate(accumulated, f);
if (result) {
std::optional<T> typed = expression::fromExpressionValue<T>(*result);
if (typed) {
return std::move(*typed);
}
}
return T();
}
// static
std::shared_ptr<GeoJSONData> GeoJSONData::create(const GeoJSON& geoJSON,
std::shared_ptr<Scheduler> sequencedScheduler,
const Immutable<GeoJSONOptions>& options) {
constexpr double scale = util::EXTENT / util::tileSize_D;
if (options->cluster && geoJSON.is<Features>() && !geoJSON.get<Features>().empty()) {
mapbox::supercluster::Options clusterOptions;
clusterOptions.maxZoom = options->clusterMaxZoom;
clusterOptions.extent = util::EXTENT;
clusterOptions.radius = static_cast<uint16_t>(::round(scale * options->clusterRadius));
auto feature = std::make_shared<Feature>();
clusterOptions.map = [feature, options](const PropertyMap& properties) -> PropertyMap {
PropertyMap ret{};
if (properties.empty()) return ret;
for (const auto& p : options->clusterProperties) {
feature->properties = properties;
ret[p.first] = evaluateFeature<Value>(*feature, p.second.first);
}
return ret;
};
clusterOptions.reduce = [feature, options](PropertyMap& toReturn, const PropertyMap& toFill) {
for (const auto& p : options->clusterProperties) {
if (toFill.count(p.first) == 0) {
continue;
}
feature->properties = toFill;
std::optional<Value> accumulated(toReturn[p.first]);
toReturn[p.first] = evaluateFeature<Value>(*feature, p.second.second, accumulated);
}
};
return std::shared_ptr<GeoJSONData>(new SuperclusterData(geoJSON.get<Features>(), clusterOptions));
}
mapbox::geojsonvt::Options vtOptions;
vtOptions.maxZoom = options->maxzoom;
vtOptions.extent = util::EXTENT;
vtOptions.buffer = static_cast<uint16_t>(::round(scale * options->buffer));
vtOptions.tolerance = scale * options->tolerance;
vtOptions.lineMetrics = options->lineMetrics;
return std::shared_ptr<GeoJSONData>(new GeoJSONVTData(geoJSON, vtOptions, std::move(sequencedScheduler)));
}
GeoJSONSource::Impl::Impl(std::string id_, Immutable<GeoJSONOptions> options_)
: Source::Impl(SourceType::GeoJSON, std::move(id_)),
options(std::move(options_)) {}
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 {
return {options->minzoom, options->maxzoom};
}
std::weak_ptr<GeoJSONData> GeoJSONSource::Impl::getData() const {
return data;
}
std::optional<std::string> GeoJSONSource::Impl::getAttribution() const {
return {};
}
} // namespace style
} // namespace mbgl