From 962769aab9e628e69d5a1eb2a747765037f9086f Mon Sep 17 00:00:00 2001 From: zmiao Date: Tue, 23 Jul 2019 15:54:44 +0300 Subject: create map and reduce expressions from raw strings --- include/mbgl/style/expression/expression.hpp | 8 +- include/mbgl/style/property_expression.hpp | 22 ++--- include/mbgl/style/sources/geojson_source.hpp | 7 +- src/mbgl/style/expression/expression.cpp | 6 +- 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 accumulated_, GeometryTileFeature const * feature_) : + accumulated(std::move(accumulated_)), feature(feature_) + {} EvaluationContext(optional zoom_, GeometryTileFeature const * feature_, optional colorRampParameter_) : zoom(std::move(zoom_)), feature(feature_), colorRampParameter(std::move(colorRampParameter_)) {} @@ -42,9 +45,10 @@ public: }; optional zoom; + optional accumulated; GeometryTileFeature const * feature = nullptr; optional colorRampParameter; - optional accumulated; + // Contains formatted section object, std::unordered_map. const Value* formattedSection = nullptr; }; @@ -164,7 +168,7 @@ public: type::Type getType() const { return type; }; EvaluationResult evaluate(optional zoom, const Feature& feature, optional colorRampParameter) const; - EvaluationResult evaluate(const Feature& feature) const; + EvaluationResult evaluate(optional 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 -#include +#include #include +#include #include -#include #include namespace mbgl { @@ -34,11 +34,10 @@ template class PropertyExpression final : public PropertyExpressionBase { public: // Second parameter to be used only for conversions from legacy functions. - PropertyExpression(std::unique_ptr expression_, optional defaultValue_ = nullopt) - : PropertyExpressionBase(std::move(expression_)), - defaultValue(std::move(defaultValue_)) { + PropertyExpression(std::unique_ptr expression_, + optional 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& f, T finalDefaultValue = T()) const { - const expression::EvaluationResult result = expression->evaluate(f); + + T evaluate(optional accumulated, + mapbox::feature::feature& f, + T finalDefaultValue = T()) const { + const expression::EvaluationResult result = expression->evaluate(accumulated, f); if (result) { const optional typed = expression::fromExpressionValue(*result); return typed ? *typed : defaultValue ? *defaultValue : finalDefaultValue; @@ -74,8 +75,7 @@ public: return expression::fromExpressionValues(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 +#include #include #include -#include + +#include +#include +#include namespace mbgl { @@ -24,6 +28,7 @@ struct GeoJSONOptions { bool cluster = false; uint16_t clusterRadius = 50; uint8_t clusterMaxZoom = 17; + std::unordered_map> 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 zoom, const Feature& feature, optional 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 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 #include -#include -#include #include -#include -#include +#include +#include #include #include @@ -25,6 +23,21 @@ namespace mbgl { namespace style { +template +PropertyExpression createPropertyExpression(const char* expr) { + using JSValue = rapidjson::GenericValue, rapidjson::CrtAllocator>; + rapidjson::GenericDocument, rapidjson::CrtAllocator> document; + document.Parse<0>(expr); + assert(!document.HasParseError()); + + // optional typeAnnotationOption; + const JSValue* expression = &document; + expression::ParsingContext ctx; + expression::ParseResult parsed = + ctx.parseExpression(mbgl::style::conversion::Convertible(expression)); + return PropertyExpression(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 -createExpression(const char* op, std::vector> 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>{ + { "max", { "+", R"(["get", "scalerank"])" } } + }; if (options.cluster && geoJSON.is>() && !geoJSON.get>().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::CrtAllocator>; - - -// std::unordered_map -// properties{{std::string("max"), expr1}}; - const char* expr1 = R"(["get", "scalerank"])"; - rapidjson::GenericDocument, rapidjson::CrtAllocator> document; - document.Parse<0>(expr1); - assert(!document.HasParseError()); - expression::ParsingContext ctx; -// optional typeAnnotationOption; - const JSValue* expression = &document; - expression::ParseResult parsed = ctx.parseExpression(mbgl::style::conversion::Convertible(expression)); - auto mapExpression = PropertyExpression(std::move(*parsed)); - - const char* expr2 = R"(["+",["accumulated"], ["get", "max"]])"; - rapidjson::GenericDocument, rapidjson::CrtAllocator> document2; - document2.Parse<0>(expr2); - assert(!document2.HasParseError()); - expression::ParsingContext ctx2; - // optional typeAnnotationOption; - const JSValue* expression2 = &document2; - expression::ParseResult parsed2 = ctx.parseExpression(mbgl::style::conversion::Convertible(expression2)); - auto reduceExpression = PropertyExpression(std::move(*parsed2)); - - -// auto mapExpression = PropertyExpression(get("scalerank")); -// auto reduceExpression = PropertyExpression(get("max")); - clusterOptions.map = [&](const mapbox::feature::property_map& properties) -> - mapbox::feature::property_map {mapbox::feature::property_map ret{}; - auto feature = mapbox::feature::feature(); - feature.properties = properties; - ret["max"] = mapExpression.evaluate(feature); + std::unordered_map> mapExpressions; + std::unordered_map> reduceExpressions; + for (const auto& p : options.clusterProperties) { + mapExpressions.emplace(p.first, + createPropertyExpression(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(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(); + 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(); - 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(); + feature.properties = toFill; + optional accumulated(toReturn[p.first].get()); + auto iter = reduceExpressions.find(p.first); + if (iter != reduceExpressions.end()) { + toReturn[p.first] = iter->second.evaluate(accumulated, feature); + } + } }; data = std::make_shared( geoJSON.get>(), clusterOptions); -- cgit v1.2.1