Indroduce clusterProperty option for aggregation (#15287)
* indroduce clusterProperty option for aggregation * remove unnecessary codes * update geojson_option conversion * fix reviewing findings
This commit is contained in:
@@ -4,7 +4,6 @@
|
||||
#include <mbgl/util/variant.hpp>
|
||||
#include <mbgl/util/color.hpp>
|
||||
#include <mbgl/style/property_value.hpp>
|
||||
#include <mbgl/style/property_value.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/style/expression/value.hpp>
|
||||
#include <mbgl/style/expression/expression.hpp>
|
||||
#include <mbgl/style/expression/interpolator.hpp>
|
||||
#include <mbgl/style/expression/value.hpp>
|
||||
#include <mbgl/util/ignore.hpp>
|
||||
|
||||
#include <initializer_list>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <initializer_list>
|
||||
|
||||
namespace mbgl {
|
||||
namespace style {
|
||||
@@ -24,15 +24,18 @@ std::vector<std::unique_ptr<Expression>> vec(Args... args) {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> createExpression(const char* expr);
|
||||
std::unique_ptr<Expression> createExpression(const mbgl::style::conversion::Convertible& expr);
|
||||
std::unique_ptr<Expression> error(std::string);
|
||||
|
||||
std::unique_ptr<Expression> literal(const char* value);
|
||||
std::unique_ptr<Expression> literal(Value value);
|
||||
std::unique_ptr<Expression> literal(std::initializer_list<double> value);
|
||||
std::unique_ptr<Expression> literal(std::initializer_list<const char *> value);
|
||||
std::unique_ptr<Expression> literal(std::initializer_list<const char*> value);
|
||||
|
||||
std::unique_ptr<Expression> assertion(type::Type, std::unique_ptr<Expression>,
|
||||
std::unique_ptr<Expression> def = nullptr);
|
||||
std::unique_ptr<Expression>
|
||||
assertion(type::Type, std::unique_ptr<Expression>,
|
||||
std::unique_ptr<Expression> def = nullptr);
|
||||
std::unique_ptr<Expression> number(std::unique_ptr<Expression>,
|
||||
std::unique_ptr<Expression> def = nullptr);
|
||||
std::unique_ptr<Expression> string(std::unique_ptr<Expression>,
|
||||
@@ -46,21 +49,17 @@ std::unique_ptr<Expression> toString(std::unique_ptr<Expression>,
|
||||
std::unique_ptr<Expression> def = nullptr);
|
||||
std::unique_ptr<Expression> toFormatted(std::unique_ptr<Expression>,
|
||||
std::unique_ptr<Expression> def = nullptr);
|
||||
|
||||
|
||||
std::unique_ptr<Expression> get(const char* value);
|
||||
std::unique_ptr<Expression> get(std::unique_ptr<Expression>);
|
||||
|
||||
std::unique_ptr<Expression> id();
|
||||
std::unique_ptr<Expression> zoom();
|
||||
|
||||
std::unique_ptr<Expression> eq(std::unique_ptr<Expression>,
|
||||
std::unique_ptr<Expression>);
|
||||
std::unique_ptr<Expression> ne(std::unique_ptr<Expression>,
|
||||
std::unique_ptr<Expression>);
|
||||
std::unique_ptr<Expression> gt(std::unique_ptr<Expression>,
|
||||
std::unique_ptr<Expression>);
|
||||
std::unique_ptr<Expression> lt(std::unique_ptr<Expression>,
|
||||
std::unique_ptr<Expression>);
|
||||
std::unique_ptr<Expression> eq(std::unique_ptr<Expression>, std::unique_ptr<Expression>);
|
||||
std::unique_ptr<Expression> ne(std::unique_ptr<Expression>, std::unique_ptr<Expression>);
|
||||
std::unique_ptr<Expression> gt(std::unique_ptr<Expression>, std::unique_ptr<Expression>);
|
||||
std::unique_ptr<Expression> lt(std::unique_ptr<Expression>, std::unique_ptr<Expression>);
|
||||
|
||||
std::unique_ptr<Expression> step(std::unique_ptr<Expression> input,
|
||||
std::unique_ptr<Expression> output0,
|
||||
@@ -86,7 +85,7 @@ std::unique_ptr<Expression> interpolate(Interpolator interpolator,
|
||||
double input3, std::unique_ptr<Expression> output3);
|
||||
|
||||
std::unique_ptr<Expression> concat(std::vector<std::unique_ptr<Expression>> inputs);
|
||||
|
||||
|
||||
std::unique_ptr<Expression> format(const char* value);
|
||||
std::unique_ptr<Expression> format(std::unique_ptr<Expression>);
|
||||
|
||||
|
||||
@@ -31,6 +31,9 @@ public:
|
||||
EvaluationContext(float zoom_, GeometryTileFeature const * feature_) :
|
||||
zoom(zoom_), feature(feature_)
|
||||
{}
|
||||
EvaluationContext(optional<mbgl::Value> accumulated_, GeometryTileFeature const * feature_) :
|
||||
accumulated(std::move(accumulated_)), feature(feature_)
|
||||
{}
|
||||
EvaluationContext(optional<float> zoom_, GeometryTileFeature const * feature_, optional<double> colorRampParameter_) :
|
||||
zoom(std::move(zoom_)), feature(feature_), colorRampParameter(std::move(colorRampParameter_))
|
||||
{}
|
||||
@@ -41,6 +44,7 @@ public:
|
||||
};
|
||||
|
||||
optional<float> zoom;
|
||||
optional<mbgl::Value> accumulated;
|
||||
GeometryTileFeature const * feature = nullptr;
|
||||
optional<double> colorRampParameter;
|
||||
// Contains formatted section object, std::unordered_map<std::string, Value>.
|
||||
@@ -162,7 +166,7 @@ public:
|
||||
type::Type getType() const { return type; };
|
||||
|
||||
EvaluationResult evaluate(optional<float> zoom, const Feature& feature, optional<double> colorRampParameter) const;
|
||||
|
||||
EvaluationResult evaluate(optional<mbgl::Value> accumulated, const Feature& feature) const;
|
||||
/**
|
||||
* Statically analyze the expression, attempting to enumerate possible outputs. Returns
|
||||
* an array of values plus the sentinel null optional value, used to indicate that the
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/style/expression/expression.hpp>
|
||||
#include <mbgl/style/source.hpp>
|
||||
#include <mbgl/util/constants.hpp>
|
||||
#include <mbgl/util/geojson.hpp>
|
||||
#include <mbgl/util/optional.hpp>
|
||||
#include <mbgl/util/constants.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
@@ -24,11 +29,15 @@ struct GeoJSONOptions {
|
||||
bool cluster = false;
|
||||
uint16_t clusterRadius = 50;
|
||||
uint8_t clusterMaxZoom = 17;
|
||||
using ClusterExpression = std::pair<std::shared_ptr<mbgl::style::expression::Expression>,
|
||||
std::shared_ptr<mbgl::style::expression::Expression>>;
|
||||
using ClusterProperties = std::unordered_map<std::string, ClusterExpression>;
|
||||
ClusterProperties clusterProperties;
|
||||
};
|
||||
|
||||
class GeoJSONSource : public Source {
|
||||
public:
|
||||
GeoJSONSource(const std::string& id, const GeoJSONOptions& = {});
|
||||
GeoJSONSource(const std::string& id, optional<GeoJSONOptions> = nullopt);
|
||||
~GeoJSONSource() final;
|
||||
|
||||
void setURL(const std::string& url);
|
||||
|
||||
@@ -85,7 +85,6 @@
|
||||
"render-tests/text-variable-anchor/pitched-rotated-debug": "https://github.com/mapbox/mapbox-gl-native/issues/14211",
|
||||
"render-tests/text-variable-anchor/rotated-offset": "https://github.com/mapbox/mapbox-gl-native/issues/14211",
|
||||
"render-tests/text-variable-anchor/remember-last-placement": "skip - fails on gl-native, as symbol index is not functional at static map mode - needs issue",
|
||||
"render-tests/geojson/clustered-properties": "https://github.com/mapbox/mapbox-gl-native/issues/14043",
|
||||
"render-tests/remove-feature-state/composite-expression": "https://github.com/mapbox/mapbox-gl-native/issues/12413",
|
||||
"render-tests/remove-feature-state/data-expression": "https://github.com/mapbox/mapbox-gl-native/issues/12413",
|
||||
"render-tests/remove-feature-state/vector-source": "https://github.com/mapbox/mapbox-gl-native/issues/12413",
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
#include <mbgl/style/conversion/geojson_options.hpp>
|
||||
#include <mbgl/style/conversion_impl.hpp>
|
||||
#include <mbgl/style/expression/dsl.hpp>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace mbgl {
|
||||
namespace style {
|
||||
namespace conversion {
|
||||
|
||||
optional<GeoJSONOptions> Converter<GeoJSONOptions>::operator()(const Convertible& value, Error& error) const {
|
||||
optional<GeoJSONOptions> Converter<GeoJSONOptions>::operator()(const Convertible& value,
|
||||
Error& error) const {
|
||||
GeoJSONOptions options;
|
||||
|
||||
const auto minzoomValue = objectMember(value, "minzoom");
|
||||
@@ -83,12 +87,71 @@ optional<GeoJSONOptions> Converter<GeoJSONOptions>::operator()(const Convertible
|
||||
if (toBool(*lineMetricsValue)) {
|
||||
options.lineMetrics = *toBool(*lineMetricsValue);
|
||||
} else {
|
||||
error = { "GeoJSON source lineMetrics value must be a boolean" };
|
||||
error.message = "GeoJSON source lineMetrics value must be a boolean";
|
||||
return nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
return { options };
|
||||
const auto clusterProperties = objectMember(value, "clusterProperties");
|
||||
if (clusterProperties) {
|
||||
if (!isObject(*clusterProperties)) {
|
||||
error.message = "GeoJSON source clusterProperties value must be an object";
|
||||
return nullopt;
|
||||
}
|
||||
GeoJSONOptions::ClusterProperties result;
|
||||
assert(error.message.empty());
|
||||
eachMember(
|
||||
*clusterProperties,
|
||||
[&](const std::string& k,
|
||||
const mbgl::style::conversion::Convertible& v) -> optional<conversion::Error> {
|
||||
// Each property shall be formed as ["key" : [operator, [mapExpression]]]
|
||||
// or ["key" : [[operator, ['accumulated'], ['get', key]], [mapExpression]]]
|
||||
if (!isArray(v) || arrayLength(v) != 2) {
|
||||
error.message =
|
||||
"GeoJSON source clusterProperties member must be an array with length of 2";
|
||||
return nullopt;
|
||||
}
|
||||
auto map = expression::dsl::createExpression(arrayMember(v, 1));
|
||||
if (!map) {
|
||||
error.message =
|
||||
"Failed to convert GeoJSON source clusterProperties map expression";
|
||||
return nullopt;
|
||||
}
|
||||
std::unique_ptr<expression::Expression> reduce;
|
||||
if (isArray(arrayMember(v, 0))) {
|
||||
reduce = expression::dsl::createExpression(arrayMember(v, 0));
|
||||
} else {
|
||||
auto reduceOp = toString(arrayMember(v, 0));
|
||||
if (!reduceOp) {
|
||||
error.message =
|
||||
"GeoJSON source clusterProperties member must contain a valid operator";
|
||||
return nullopt;
|
||||
}
|
||||
std::stringstream ss;
|
||||
// Reformulate reduce expression to [operator, ['accumulated'], ['get', key]]
|
||||
// The reason to create expression via parsing string instead of invoking function
|
||||
// createCompoundExpression is due to expression type disunity can’t be resolved
|
||||
// with current logic of createCompoundExpression
|
||||
ss << std::string(R"([")") << *reduceOp
|
||||
<< std::string(R"(", ["accumulated"], ["get", ")") << k
|
||||
<< std::string(R"("]])");
|
||||
reduce = expression::dsl::createExpression(ss.str().c_str());
|
||||
}
|
||||
if (!reduce) {
|
||||
error.message =
|
||||
"Failed to convert GeoJSON source clusterProperties reduce expression";
|
||||
return nullopt;
|
||||
}
|
||||
result.emplace(k, std::make_pair(std::move(map), std::move(reduce)));
|
||||
return nullopt;
|
||||
});
|
||||
if (!error.message.empty()) {
|
||||
return nullopt;
|
||||
}
|
||||
options.clusterProperties = std::move(result);
|
||||
}
|
||||
|
||||
return { std::move(options) };
|
||||
}
|
||||
|
||||
} // namespace conversion
|
||||
|
||||
@@ -368,6 +368,18 @@ const auto& lineProgressCompoundExpression() {
|
||||
return signature;
|
||||
}
|
||||
|
||||
const auto& accumulatedCompoundExpression() {
|
||||
const static auto signature = detail::makeSignature("accumulated", [](const EvaluationContext& params) -> Result<Value> {
|
||||
if (!params.accumulated) {
|
||||
return EvaluationError {
|
||||
"The 'accumulated' expression is unavailable in the current evaluation context."
|
||||
};
|
||||
}
|
||||
return Value(toExpressionValue(*params.accumulated));
|
||||
});
|
||||
return signature;
|
||||
}
|
||||
|
||||
const auto& hasContextCompoundExpression() {
|
||||
static auto signature = detail::makeSignature("has", [](const EvaluationContext& params, const std::string& key) -> Result<bool> {
|
||||
if (!params.feature) {
|
||||
@@ -871,6 +883,7 @@ MAPBOX_ETERNAL_CONSTEXPR const auto compoundExpressionRegistry = mapbox::eternal
|
||||
{ "zoom", zoomCompoundExpression },
|
||||
{ "heatmap-density", heatmapDensityCompoundExpression },
|
||||
{ "line-progress", lineProgressCompoundExpression },
|
||||
{ "accumulated", accumulatedCompoundExpression },
|
||||
{ "has", hasContextCompoundExpression },
|
||||
{ "has", hasObjectCompoundExpression },
|
||||
{ "get", getContextCompoundExpression },
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
#include <mbgl/style/expression/compound_expression.hpp>
|
||||
#include <mbgl/style/expression/format_expression.hpp>
|
||||
|
||||
#include <mapbox/geojsonvt.hpp>
|
||||
#include <mbgl/style/conversion/json.hpp>
|
||||
#include <rapidjson/document.h>
|
||||
|
||||
namespace mbgl {
|
||||
namespace style {
|
||||
namespace expression {
|
||||
@@ -21,6 +25,25 @@ std::unique_ptr<Expression> compound(const char* op, std::vector<std::unique_ptr
|
||||
assert(result);
|
||||
return std::move(*result);
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> createExpression(const char* expr) {
|
||||
using JSValue = rapidjson::GenericValue<rapidjson::UTF8<>, rapidjson::CrtAllocator>;
|
||||
rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator> document;
|
||||
document.Parse<0>(expr);
|
||||
if (document.HasParseError()) return nullptr;
|
||||
|
||||
const JSValue* expression = &document;
|
||||
expression::ParsingContext ctx;
|
||||
expression::ParseResult parsed =
|
||||
ctx.parseExpression(mbgl::style::conversion::Convertible(expression));
|
||||
return parsed ? std::move(*parsed) : nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> createExpression(const mbgl::style::conversion::Convertible& expr) {
|
||||
expression::ParsingContext ctx;
|
||||
expression::ParseResult parsed = ctx.parseExpression(expr);
|
||||
return parsed ? std::move(*parsed) : nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<Expression> error(std::string message) {
|
||||
return std::make_unique<Error>(std::move(message));
|
||||
|
||||
@@ -25,13 +25,17 @@ public:
|
||||
return optional<mbgl::Value>();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
EvaluationResult Expression::evaluate(optional<float> zoom, const Feature& feature, optional<double> colorRampParameter) const {
|
||||
GeoJSONFeature f(feature);
|
||||
return this->evaluate(EvaluationContext(zoom, &f, colorRampParameter));
|
||||
}
|
||||
|
||||
EvaluationResult Expression::evaluate(optional<mbgl::Value> accumulated, const Feature& feature) const {
|
||||
GeoJSONFeature f(feature);
|
||||
return this->evaluate(EvaluationContext(accumulated, &f));
|
||||
}
|
||||
|
||||
} // namespace expression
|
||||
} // namespace style
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -73,7 +73,8 @@ bool isConstant(const Expression& expression) {
|
||||
|
||||
return isFeatureConstant(expression) &&
|
||||
isGlobalPropertyConstant(expression, std::array<std::string, 2>{{"zoom", "heatmap-density"}}) &&
|
||||
isGlobalPropertyConstant(expression, std::array<std::string, 2>{{"zoom", "line-progress"}});
|
||||
isGlobalPropertyConstant(expression, std::array<std::string, 2>{{"zoom", "line-progress"}}) &&
|
||||
isGlobalPropertyConstant(expression, std::array<std::string, 2>{{"zoom", "accumulated"}});
|
||||
}
|
||||
|
||||
using namespace mbgl::style::conversion;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
namespace mbgl {
|
||||
namespace style {
|
||||
|
||||
GeoJSONSource::GeoJSONSource(const std::string& id, const GeoJSONOptions& options)
|
||||
GeoJSONSource::GeoJSONSource(const std::string& id, optional<GeoJSONOptions> options)
|
||||
: Source(makeMutable<Impl>(std::move(id), options)) {
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <mbgl/style/sources/geojson_source_impl.hpp>
|
||||
#include <mbgl/util/constants.hpp>
|
||||
#include <mbgl/tile/tile_id.hpp>
|
||||
#include <mbgl/util/constants.hpp>
|
||||
#include <mbgl/util/feature.hpp>
|
||||
#include <mbgl/util/string.hpp>
|
||||
|
||||
#include <mapbox/geojsonvt.hpp>
|
||||
@@ -13,9 +14,9 @@ namespace style {
|
||||
|
||||
class GeoJSONVTData : public GeoJSONData {
|
||||
public:
|
||||
GeoJSONVTData(const GeoJSON& geoJSON,
|
||||
const mapbox::geojsonvt::Options& options)
|
||||
: impl(geoJSON, options) {}
|
||||
GeoJSONVTData(const GeoJSON& geoJSON, const mapbox::geojsonvt::Options& options)
|
||||
: impl(geoJSON, options) {
|
||||
}
|
||||
|
||||
mapbox::feature::feature_collection<int16_t> getTile(const CanonicalTileID& tileID) final {
|
||||
return impl.getTile(tileID.z, tileID.x, tileID.y).features;
|
||||
@@ -25,9 +26,8 @@ public:
|
||||
return {};
|
||||
}
|
||||
|
||||
mapbox::feature::feature_collection<double> getLeaves(const std::uint32_t,
|
||||
const std::uint32_t,
|
||||
const std::uint32_t) final {
|
||||
mapbox::feature::feature_collection<double>
|
||||
getLeaves(const std::uint32_t, const std::uint32_t, const std::uint32_t) final {
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -43,7 +43,8 @@ class SuperclusterData : public GeoJSONData {
|
||||
public:
|
||||
SuperclusterData(const mapbox::feature::feature_collection<double>& features,
|
||||
const mapbox::supercluster::Options& options)
|
||||
: impl(features, options) {}
|
||||
: impl(features, options) {
|
||||
}
|
||||
|
||||
mapbox::feature::feature_collection<int16_t> getTile(const CanonicalTileID& tileID) final {
|
||||
return impl.getTile(tileID.z, tileID.x, tileID.y);
|
||||
@@ -54,8 +55,8 @@ public:
|
||||
}
|
||||
|
||||
mapbox::feature::feature_collection<double> getLeaves(const std::uint32_t cluster_id,
|
||||
const std::uint32_t limit,
|
||||
const std::uint32_t offset) final {
|
||||
const std::uint32_t limit,
|
||||
const std::uint32_t offset) final {
|
||||
return impl.getLeaves(cluster_id, limit, offset);
|
||||
}
|
||||
|
||||
@@ -67,23 +68,53 @@ private:
|
||||
mapbox::supercluster::Supercluster impl;
|
||||
};
|
||||
|
||||
GeoJSONSource::Impl::Impl(std::string id_, GeoJSONOptions options_)
|
||||
: Source::Impl(SourceType::GeoJSON, std::move(id_)),
|
||||
options(std::move(options_)) {
|
||||
template <class T>
|
||||
T evaluateFeature(const mapbox::feature::feature<double>& f,
|
||||
const std::shared_ptr<expression::Expression>& expression,
|
||||
optional<T> accumulated = nullopt) {
|
||||
const expression::EvaluationResult result = expression->evaluate(accumulated, f);
|
||||
if (result) {
|
||||
optional<T> typed = expression::fromExpressionValue<T>(*result);
|
||||
if (typed) {
|
||||
return std::move(*typed);
|
||||
}
|
||||
}
|
||||
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) {
|
||||
: Source::Impl(other), options(other.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<mapbox::feature::feature_collection<double>>() &&
|
||||
!geoJSON.get<mapbox::feature::feature_collection<double>>().empty()) {
|
||||
mapbox::supercluster::Options clusterOptions;
|
||||
clusterOptions.maxZoom = options.clusterMaxZoom;
|
||||
clusterOptions.extent = util::EXTENT;
|
||||
clusterOptions.radius = ::round(scale * options.clusterRadius);
|
||||
Feature feature;
|
||||
clusterOptions.map = [&](const PropertyMap& properties) -> PropertyMap {
|
||||
PropertyMap ret{};
|
||||
for (const auto& p : options.clusterProperties) {
|
||||
feature.properties = properties;
|
||||
ret[p.first] = evaluateFeature<Value>(feature, p.second.first);
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
clusterOptions.reduce = [&](PropertyMap& toReturn, const PropertyMap& toFill) {
|
||||
for (const auto& p : options.clusterProperties) {
|
||||
if (toFill.count(p.first) == 0) {
|
||||
continue;
|
||||
}
|
||||
feature.properties = toFill;
|
||||
optional<Value> accumulated(toReturn[p.first]);
|
||||
toReturn[p.first] = evaluateFeature<Value>(feature, p.second.second, accumulated);
|
||||
}
|
||||
};
|
||||
data = std::make_shared<SuperclusterData>(
|
||||
geoJSON.get<mapbox::feature::feature_collection<double>>(), clusterOptions);
|
||||
} else {
|
||||
|
||||
@@ -26,7 +26,7 @@ public:
|
||||
|
||||
class GeoJSONSource::Impl : public Source::Impl {
|
||||
public:
|
||||
Impl(std::string id, GeoJSONOptions);
|
||||
Impl(std::string id, optional<GeoJSONOptions>);
|
||||
Impl(const GeoJSONSource::Impl&, const GeoJSON&);
|
||||
~Impl() final;
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ TEST(GeoJSONOptions, RetainsDefaults) {
|
||||
ASSERT_EQ(converted.cluster, defaults.cluster);
|
||||
ASSERT_EQ(converted.clusterRadius, defaults.clusterRadius);
|
||||
ASSERT_EQ(converted.clusterMaxZoom, defaults.clusterMaxZoom);
|
||||
ASSERT_TRUE(converted.clusterProperties.empty());
|
||||
}
|
||||
|
||||
TEST(GeoJSONOptions, FullConversion) {
|
||||
@@ -49,7 +50,12 @@ TEST(GeoJSONOptions, FullConversion) {
|
||||
"cluster": true,
|
||||
"clusterRadius": 4,
|
||||
"clusterMaxZoom": 5,
|
||||
"lineMetrics": true
|
||||
"lineMetrics": true,
|
||||
"clusterProperties": {
|
||||
"max": ["max", ["get", "scalerank"]],
|
||||
"sum": [["+", ["accumulated"], ["get", "sum"]], ["get", "scalerank"]],
|
||||
"has_island": ["any", ["==", ["get", "featureclass"], "island"]]
|
||||
}
|
||||
})JSON", error);
|
||||
|
||||
// GeoJSON-VT
|
||||
@@ -63,4 +69,8 @@ TEST(GeoJSONOptions, FullConversion) {
|
||||
ASSERT_EQ(converted.cluster, true);
|
||||
ASSERT_EQ(converted.clusterRadius, 4);
|
||||
ASSERT_EQ(converted.clusterMaxZoom, 5);
|
||||
ASSERT_EQ(converted.clusterProperties.size(), 3);
|
||||
ASSERT_EQ(converted.clusterProperties.count("max"), 1);
|
||||
ASSERT_EQ(converted.clusterProperties.count("sum"), 1);
|
||||
ASSERT_EQ(converted.clusterProperties.count("has_island"), 1);
|
||||
}
|
||||
|
||||
@@ -36,8 +36,7 @@ TEST(Expression, IsExpression) {
|
||||
// TODO: "feature-state": https://github.com/mapbox/mapbox-gl-native/issues/12613
|
||||
// TODO: "interpolate-hcl": https://github.com/mapbox/mapbox-gl-native/issues/8720
|
||||
// TODO: "interpolate-lab": https://github.com/mapbox/mapbox-gl-native/issues/8720
|
||||
// TODO: "accumulated": https://github.com/mapbox/mapbox-gl-native/issues/14043
|
||||
if (name == "feature-state" || name == "interpolate-hcl" || name == "interpolate-lab" || name == "accumulated") {
|
||||
if (name == "feature-state" || name == "interpolate-hcl" || name == "interpolate-lab") {
|
||||
if (expression::isExpression(conversion::Convertible(expression))) {
|
||||
ASSERT_TRUE(false) << "Expression name" << name << "is implemented - please update Expression.IsExpression test.";
|
||||
}
|
||||
|
||||
2
vendor/supercluster.hpp
vendored
2
vendor/supercluster.hpp
vendored
Submodule vendor/supercluster.hpp updated: 274ec13830...03c026c49c
Reference in New Issue
Block a user