diff options
author | zmiao <zmiao.jamie@gmail.com> | 2019-07-23 15:54:44 +0300 |
---|---|---|
committer | zmiao <zmiao.jamie@gmail.com> | 2019-07-23 15:54:44 +0300 |
commit | 962769aab9e628e69d5a1eb2a747765037f9086f (patch) | |
tree | d0b3578ec73a69c8515f877f50db774e120b09a0 | |
parent | 570b871b910aae375ce202398f205c6cda863f24 (diff) | |
download | qtlocation-mapboxgl-upstream/enable_cluster_properties_aggregation.tar.gz |
create map and reduce expressions from raw stringsupstream/enable_cluster_properties_aggregation
-rw-r--r-- | include/mbgl/style/expression/expression.hpp | 8 | ||||
-rw-r--r-- | include/mbgl/style/property_expression.hpp | 22 | ||||
-rw-r--r-- | include/mbgl/style/sources/geojson_source.hpp | 7 | ||||
-rw-r--r-- | src/mbgl/style/expression/expression.cpp | 6 | ||||
-rw-r--r-- | src/mbgl/style/sources/geojson_source_impl.cpp | 111 |
5 files changed, 81 insertions, 73 deletions
diff --git a/include/mbgl/style/expression/expression.hpp b/include/mbgl/style/expression/expression.hpp index 9a2f7b3b41..9ba5c72bce 100644 --- a/include/mbgl/style/expression/expression.hpp +++ b/include/mbgl/style/expression/expression.hpp @@ -32,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_)) {} @@ -42,9 +45,10 @@ public: }; optional<float> zoom; + optional<double> accumulated; GeometryTileFeature const * feature = nullptr; optional<double> colorRampParameter; - optional<double> accumulated; + // Contains formatted section object, std::unordered_map<std::string, Value>. const Value* formattedSection = nullptr; }; @@ -164,7 +168,7 @@ public: type::Type getType() const { return type; }; EvaluationResult evaluate(optional<float> zoom, const Feature& feature, optional<double> colorRampParameter) const; - EvaluationResult evaluate(const Feature& feature) 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 89a0cff418..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); @@ -52,9 +51,11 @@ public: T evaluate(float zoom) const { return evaluate(expression::EvaluationContext(zoom)); } - - T evaluate(mapbox::feature::feature<double>& f, T finalDefaultValue = T()) const { - const expression::EvaluationResult result = expression->evaluate(f); + + 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; @@ -74,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/expression.cpp b/src/mbgl/style/expression/expression.cpp index e826cf6ec0..4a7c10fa74 100644 --- a/src/mbgl/style/expression/expression.cpp +++ b/src/mbgl/style/expression/expression.cpp @@ -30,12 +30,12 @@ public: 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(const Feature& feature) const{ +EvaluationResult Expression::evaluate(optional<double> accumulated, const Feature& feature) const{ GeoJSONFeature f(feature); - return this->evaluate(EvaluationContext(&f)); + return this->evaluate(EvaluationContext(accumulated,&f)); } } // namespace expression diff --git a/src/mbgl/style/sources/geojson_source_impl.cpp b/src/mbgl/style/sources/geojson_source_impl.cpp index e1d3edbe08..425f8489ea 100644 --- a/src/mbgl/style/sources/geojson_source_impl.cpp +++ b/src/mbgl/style/sources/geojson_source_impl.cpp @@ -13,11 +13,9 @@ #include <rapidjson/error/en.h> #include <mapbox/geojsonvt.hpp> -#include <supercluster.hpp> -#include <mbgl/style/conversion/json.hpp> #include <mbgl/style/conversion/constant.hpp> -#include <mbgl/style/conversion/property_value.hpp> -#include <mbgl/style/expression/dsl.hpp> +#include <mbgl/style/conversion/json.hpp> +#include <supercluster.hpp> #include <cmath> #include <functional> @@ -25,6 +23,21 @@ 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) @@ -85,18 +98,13 @@ GeoJSONSource::Impl::Impl(std::string id_, GeoJSONOptions options_) : Source::Impl(SourceType::GeoJSON, std::move(id_)), options(std::move(options_)) { } -std::unique_ptr<style::expression::Expression> -createExpression(const char* op, std::vector<std::unique_ptr<style::expression::Expression>> args) { - style::expression::ParsingContext ctx; - style::expression::ParseResult result = - style::expression::createCompoundExpression(op, std::move(args), ctx); - assert(result); - return std::move(*result); -} - GeoJSONSource::Impl::Impl(const Impl& other, const GeoJSON& geoJSON) : Source::Impl(other), options(other.options) { constexpr double scale = util::EXTENT / util::tileSize; + options.clusterProperties = + std::unordered_map<std::string, std::pair<std::string, std::string>>{ + { "max", { "+", R"(["get", "scalerank"])" } } + }; if (options.cluster && geoJSON.is<mapbox::feature::feature_collection<double>>() && !geoJSON.get<mapbox::feature::feature_collection<double>>().empty()) { @@ -104,51 +112,42 @@ GeoJSONSource::Impl::Impl(const Impl& other, const GeoJSON& geoJSON) clusterOptions.maxZoom = options.clusterMaxZoom; clusterOptions.extent = util::EXTENT; clusterOptions.radius = ::round(scale * options.clusterRadius); - // process here, taking the cluster propeties into consideration - - using namespace mbgl::style::expression::dsl; - using namespace mbgl; - using namespace mbgl::style; - - using JSValue = rapidjson::GenericValue<rapidjson::UTF8<>, rapidjson::CrtAllocator>; - - -// std::unordered_map<std::string, const char*> -// properties{{std::string("max"), expr1}}; - const char* expr1 = R"(["get", "scalerank"])"; - rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator> document; - document.Parse<0>(expr1); - assert(!document.HasParseError()); - expression::ParsingContext ctx; -// optional<expression::TypeAnnotationOption> typeAnnotationOption; - const JSValue* expression = &document; - expression::ParseResult parsed = ctx.parseExpression(mbgl::style::conversion::Convertible(expression)); - auto mapExpression = PropertyExpression<double>(std::move(*parsed)); - - const char* expr2 = R"(["+",["accumulated"], ["get", "max"]])"; - rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator> document2; - document2.Parse<0>(expr2); - assert(!document2.HasParseError()); - expression::ParsingContext ctx2; - // optional<expression::TypeAnnotationOption> typeAnnotationOption; - const JSValue* expression2 = &document2; - expression::ParseResult parsed2 = ctx.parseExpression(mbgl::style::conversion::Convertible(expression2)); - auto reduceExpression = PropertyExpression<double>(std::move(*parsed2)); - - -// auto mapExpression = PropertyExpression<double>(get("scalerank")); -// auto reduceExpression = PropertyExpression<double>(get("max")); - clusterOptions.map = [&](const mapbox::feature::property_map& properties) -> - mapbox::feature::property_map {mapbox::feature::property_map ret{}; - auto feature = mapbox::feature::feature<double>(); - feature.properties = properties; - ret["max"] = mapExpression.evaluate(feature); + 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){ - auto feature = mapbox::feature::feature<double>(); - feature.properties = toFill; - toReturn["max"] = reduceExpression.evaluate( feature); + 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); |