summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzmiao <zmiao.jamie@gmail.com>2019-07-23 16:42:53 +0300
committerzmiao <zmiao.jamie@gmail.com>2019-07-23 16:42:53 +0300
commitf63b91973ab81ee9d5bf61313b414c1e17c3233c (patch)
tree3d9969ee292108f2f7523a134c47ccb6d74b8695
parentd7dd35220932726e23bb3d353b32b65bf50bc198 (diff)
downloadqtlocation-mapboxgl-f63b91973ab81ee9d5bf61313b414c1e17c3233c.tar.gz
enable cluster properties aggregation
-rw-r--r--include/mbgl/annotation/annotation.hpp1
-rw-r--r--include/mbgl/style/expression/expression.hpp8
-rw-r--r--include/mbgl/style/property_expression.hpp25
-rw-r--r--include/mbgl/style/sources/geojson_source.hpp7
-rw-r--r--src/mbgl/style/expression/compound_expression.cpp13
-rw-r--r--src/mbgl/style/expression/expression.cpp19
-rw-r--r--src/mbgl/style/expression/parsing_context.cpp3
-rw-r--r--src/mbgl/style/sources/geojson_source_impl.cpp87
m---------vendor/supercluster.hpp0
9 files changed, 126 insertions, 37 deletions
diff --git a/include/mbgl/annotation/annotation.hpp b/include/mbgl/annotation/annotation.hpp
index fb9ea5eba2..17728741bb 100644
--- a/include/mbgl/annotation/annotation.hpp
+++ b/include/mbgl/annotation/annotation.hpp
@@ -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>
diff --git a/include/mbgl/style/expression/expression.hpp b/include/mbgl/style/expression/expression.hpp
index 5f66fc6dc7..9ba5c72bce 100644
--- a/include/mbgl/style/expression/expression.hpp
+++ b/include/mbgl/style/expression/expression.hpp
@@ -23,6 +23,7 @@ public:
std::string message;
};
+
class EvaluationContext {
public:
EvaluationContext() = default;
@@ -31,6 +32,9 @@ public:
EvaluationContext(float zoom_, GeometryTileFeature const * feature_) :
zoom(zoom_), feature(feature_)
{}
+ EvaluationContext(optional<double> 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,8 +45,10 @@ public:
};
optional<float> zoom;
+ optional<double> accumulated;
GeometryTileFeature const * feature = nullptr;
optional<double> colorRampParameter;
+
// Contains formatted section object, std::unordered_map<std::string, Value>.
const Value* formattedSection = nullptr;
};
@@ -162,7 +168,7 @@ public:
type::Type getType() const { return type; };
EvaluationResult evaluate(optional<float> zoom, const Feature& feature, optional<double> colorRampParameter) const;
-
+ EvaluationResult evaluate(optional<double> 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
diff --git a/include/mbgl/style/property_expression.hpp b/include/mbgl/style/property_expression.hpp
index 32983e2380..1cf6e9683d 100644
--- a/include/mbgl/style/property_expression.hpp
+++ b/include/mbgl/style/property_expression.hpp
@@ -1,10 +1,10 @@
#pragma once
#include <mbgl/style/expression/expression.hpp>
-#include <mbgl/style/expression/is_constant.hpp>
+#include <mbgl/style/expression/find_zoom_curve.hpp>
#include <mbgl/style/expression/interpolate.hpp>
+#include <mbgl/style/expression/is_constant.hpp>
#include <mbgl/style/expression/step.hpp>
-#include <mbgl/style/expression/find_zoom_curve.hpp>
#include <mbgl/util/range.hpp>
namespace mbgl {
@@ -34,11 +34,10 @@ template <class T>
class PropertyExpression final : public PropertyExpressionBase {
public:
// Second parameter to be used only for conversions from legacy functions.
- PropertyExpression(std::unique_ptr<expression::Expression> expression_, optional<T> defaultValue_ = nullopt)
- : PropertyExpressionBase(std::move(expression_)),
- defaultValue(std::move(defaultValue_)) {
+ PropertyExpression(std::unique_ptr<expression::Expression> expression_,
+ optional<T> defaultValue_ = nullopt)
+ : PropertyExpressionBase(std::move(expression_)), defaultValue(std::move(defaultValue_)) {
}
-
T evaluate(const expression::EvaluationContext& context, T finalDefaultValue = T()) const {
assert(canEvaluateWith(context));
const expression::EvaluationResult result = expression->evaluate(context);
@@ -53,6 +52,17 @@ public:
return evaluate(expression::EvaluationContext(zoom));
}
+ T evaluate(optional<double> accumulated,
+ mapbox::feature::feature<double>& f,
+ T finalDefaultValue = T()) const {
+ const expression::EvaluationResult result = expression->evaluate(accumulated, f);
+ if (result) {
+ const optional<T> typed = expression::fromExpressionValue<T>(*result);
+ return typed ? *typed : defaultValue ? *defaultValue : finalDefaultValue;
+ }
+ return defaultValue ? *defaultValue : finalDefaultValue;
+ }
+
T evaluate(const GeometryTileFeature& feature, T finalDefaultValue) const {
return evaluate(expression::EvaluationContext(&feature), finalDefaultValue);
}
@@ -65,8 +75,7 @@ public:
return expression::fromExpressionValues<T>(expression->possibleOutputs());
}
- friend bool operator==(const PropertyExpression& lhs,
- const PropertyExpression& rhs) {
+ friend bool operator==(const PropertyExpression& lhs, const PropertyExpression& rhs) {
return *lhs.expression == *rhs.expression;
}
diff --git a/include/mbgl/style/sources/geojson_source.hpp b/include/mbgl/style/sources/geojson_source.hpp
index a03b910279..cf84704ee8 100644
--- a/include/mbgl/style/sources/geojson_source.hpp
+++ b/include/mbgl/style/sources/geojson_source.hpp
@@ -1,9 +1,13 @@
#pragma once
#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 <string>
+#include <unordered_map>
+#include <utility>
namespace mbgl {
@@ -24,6 +28,7 @@ struct GeoJSONOptions {
bool cluster = false;
uint16_t clusterRadius = 50;
uint8_t clusterMaxZoom = 17;
+ std::unordered_map<std::string, std::pair<std::string, std::string>> clusterProperties;
};
class GeoJSONSource : public Source {
diff --git a/src/mbgl/style/expression/compound_expression.cpp b/src/mbgl/style/expression/compound_expression.cpp
index cc1d58025b..6ca6eec850 100644
--- a/src/mbgl/style/expression/compound_expression.cpp
+++ b/src/mbgl/style/expression/compound_expression.cpp
@@ -368,6 +368,18 @@ const auto& lineProgressCompoundExpression() {
return signature;
}
+const auto& accumulatedCompoundExpression() {
+ static auto signature = detail::makeSignature("accumulated", [](const EvaluationContext& params) -> Result<double> {
+ if (!params.accumulated) {
+ return EvaluationError {
+ "The 'accumulated' expression is unavailable in the current evaluation context."
+ };
+ }
+ return *(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) {
@@ -870,6 +882,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 },
diff --git a/src/mbgl/style/expression/expression.cpp b/src/mbgl/style/expression/expression.cpp
index 1e5b1581d2..4a7c10fa74 100644
--- a/src/mbgl/style/expression/expression.cpp
+++ b/src/mbgl/style/expression/expression.cpp
@@ -5,13 +5,13 @@
namespace mbgl {
namespace style {
namespace expression {
-
+
class GeoJSONFeature : public GeometryTileFeature {
public:
const Feature& feature;
-
- GeoJSONFeature(const Feature& feature_) : feature(feature_) {}
-
+
+ GeoJSONFeature( const Feature& feature_) : feature(feature_) {}
+
FeatureType getType() const override {
return apply_visitor(ToFeatureType(), feature.geometry);
}
@@ -26,11 +26,16 @@ 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));
+ return this->evaluate(EvaluationContext(zoom, &f, colorRampParameter));
+}
+
+EvaluationResult Expression::evaluate(optional<double> accumulated, const Feature& feature) const{
+ GeoJSONFeature f(feature);
+ return this->evaluate(EvaluationContext(accumulated,&f));
}
} // namespace expression
diff --git a/src/mbgl/style/expression/parsing_context.cpp b/src/mbgl/style/expression/parsing_context.cpp
index a7c04f563d..6ce3a9bfaa 100644
--- a/src/mbgl/style/expression/parsing_context.cpp
+++ b/src/mbgl/style/expression/parsing_context.cpp
@@ -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;
diff --git a/src/mbgl/style/sources/geojson_source_impl.cpp b/src/mbgl/style/sources/geojson_source_impl.cpp
index 24ac1d7976..c11728c085 100644
--- a/src/mbgl/style/sources/geojson_source_impl.cpp
+++ b/src/mbgl/style/sources/geojson_source_impl.cpp
@@ -1,9 +1,12 @@
+#include <mbgl/style/property_expression.hpp>
#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/string.hpp>
#include <mapbox/geojsonvt.hpp>
+#include <mbgl/style/conversion/json.hpp>
+#include <rapidjson/document.h>
#include <supercluster.hpp>
#include <cmath>
@@ -11,11 +14,26 @@
namespace mbgl {
namespace style {
+template <class T>
+PropertyExpression<T> createPropertyExpression(const char* expr) {
+ using JSValue = rapidjson::GenericValue<rapidjson::UTF8<>, rapidjson::CrtAllocator>;
+ rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator> document;
+ document.Parse<0>(expr);
+ assert(!document.HasParseError());
+
+ // optional<expression::TypeAnnotationOption> typeAnnotationOption;
+ const JSValue* expression = &document;
+ expression::ParsingContext ctx;
+ expression::ParseResult parsed =
+ ctx.parseExpression(mbgl::style::conversion::Convertible(expression));
+ return PropertyExpression<T>(std::move(*parsed));
+}
+
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 +43,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 +60,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 +72,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);
}
@@ -68,22 +86,55 @@ private:
};
GeoJSONSource::Impl::Impl(std::string id_, GeoJSONOptions options_)
- : Source::Impl(SourceType::GeoJSON, std::move(id_)),
- options(std::move(options_)) {
+ : Source::Impl(SourceType::GeoJSON, std::move(id_)), options(std::move(options_)) {
}
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);
+ std::unordered_map<std::string, PropertyExpression<double>> mapExpressions;
+ std::unordered_map<std::string, PropertyExpression<double>> reduceExpressions;
+ for (const auto& p : options.clusterProperties) {
+ mapExpressions.emplace(p.first,
+ createPropertyExpression<double>(p.second.second.c_str()));
+ std::stringstream ss;
+ // [operator, ['accumulated'], ['get', key]]
+ ss << std::string(R"([")") << p.second.first
+ << std::string(R"(", ["accumulated"], ["get", ")") << p.first
+ << std::string(R"("]])");
+ reduceExpressions.emplace(p.first, createPropertyExpression<double>(ss.str().c_str()));
+ }
+ clusterOptions.map =
+ [&](const mapbox::feature::property_map& properties) -> mapbox::feature::property_map {
+ mapbox::feature::property_map ret{};
+ for (const auto& p : options.clusterProperties) {
+ auto feature = mapbox::feature::feature<double>();
+ feature.properties = properties;
+ auto iter = mapExpressions.find(p.first);
+ if (iter != mapExpressions.end()) {
+ ret[p.first] = iter->second.evaluate(nullopt, feature);
+ }
+ }
+ return ret;
+ };
+ clusterOptions.reduce = [&](mapbox::feature::property_map& toReturn,
+ const mapbox::feature::property_map& toFill) {
+ for (const auto& p : options.clusterProperties) {
+ auto feature = mapbox::feature::feature<double>();
+ feature.properties = toFill;
+ optional<double> accumulated(toReturn[p.first].get<double>());
+ auto iter = reduceExpressions.find(p.first);
+ if (iter != reduceExpressions.end()) {
+ toReturn[p.first] = iter->second.evaluate(accumulated, feature);
+ }
+ }
+ };
data = std::make_shared<SuperclusterData>(
geoJSON.get<mapbox::feature::feature_collection<double>>(), clusterOptions);
} else {
diff --git a/vendor/supercluster.hpp b/vendor/supercluster.hpp
-Subproject 274ec138306c7b110bf4dde47706aeb43dc8147
+Subproject fd7fafd07143ac1da6b03bff353dc7a4ebe0186