diff options
Diffstat (limited to 'src/mbgl/style')
23 files changed, 566 insertions, 29 deletions
diff --git a/src/mbgl/style/conversion/layer.cpp b/src/mbgl/style/conversion/layer.cpp index ad6998341d..19472bc8d6 100644 --- a/src/mbgl/style/conversion/layer.cpp +++ b/src/mbgl/style/conversion/layer.cpp @@ -6,6 +6,7 @@ #include <mbgl/style/layers/circle_layer.hpp> #include <mbgl/style/layers/fill_layer.hpp> #include <mbgl/style/layers/fill_extrusion_layer.hpp> +#include <mbgl/style/layers/heatmap_layer.hpp> #include <mbgl/style/layers/hillshade_layer.hpp> #include <mbgl/style/layers/line_layer.hpp> #include <mbgl/style/layers/raster_layer.hpp> @@ -165,6 +166,8 @@ optional<std::unique_ptr<Layer>> Converter<std::unique_ptr<Layer>>::operator()(c converted = convertVectorLayer<SymbolLayer>(*id, value, error); } else if (*type == "raster") { converted = convertRasterLayer(*id, value, error); + } else if (*type == "heatmap") { + converted = convertVectorLayer<HeatmapLayer>(*id, value, error); } else if (*type == "hillshade") { converted = convertHillshadeLayer(*id, value, error); } else if (*type == "background") { diff --git a/src/mbgl/style/conversion/make_property_setters.hpp b/src/mbgl/style/conversion/make_property_setters.hpp index adfcc4dd61..25c8fdb1ca 100644 --- a/src/mbgl/style/conversion/make_property_setters.hpp +++ b/src/mbgl/style/conversion/make_property_setters.hpp @@ -8,6 +8,7 @@ #include <mbgl/style/layers/line_layer.hpp> #include <mbgl/style/layers/symbol_layer.hpp> #include <mbgl/style/layers/circle_layer.hpp> +#include <mbgl/style/layers/heatmap_layer.hpp> #include <mbgl/style/layers/fill_extrusion_layer.hpp> #include <mbgl/style/layers/raster_layer.hpp> #include <mbgl/style/layers/hillshade_layer.hpp> @@ -72,6 +73,7 @@ inline auto makeLayoutPropertySetters() { + return result; } @@ -166,6 +168,17 @@ inline auto makePaintPropertySetters() { result["circle-stroke-opacity"] = &setProperty<CircleLayer, DataDrivenPropertyValue<float>, &CircleLayer::setCircleStrokeOpacity>; result["circle-stroke-opacity-transition"] = &setTransition<CircleLayer, &CircleLayer::setCircleStrokeOpacityTransition>; + result["heatmap-radius"] = &setProperty<HeatmapLayer, DataDrivenPropertyValue<float>, &HeatmapLayer::setHeatmapRadius>; + result["heatmap-radius-transition"] = &setTransition<HeatmapLayer, &HeatmapLayer::setHeatmapRadiusTransition>; + result["heatmap-weight"] = &setProperty<HeatmapLayer, DataDrivenPropertyValue<float>, &HeatmapLayer::setHeatmapWeight>; + result["heatmap-weight-transition"] = &setTransition<HeatmapLayer, &HeatmapLayer::setHeatmapWeightTransition>; + result["heatmap-intensity"] = &setProperty<HeatmapLayer, PropertyValue<float>, &HeatmapLayer::setHeatmapIntensity>; + result["heatmap-intensity-transition"] = &setTransition<HeatmapLayer, &HeatmapLayer::setHeatmapIntensityTransition>; + result["heatmap-color"] = &setProperty<HeatmapLayer, HeatmapColorPropertyValue, &HeatmapLayer::setHeatmapColor>; + result["heatmap-color-transition"] = &setTransition<HeatmapLayer, &HeatmapLayer::setHeatmapColorTransition>; + result["heatmap-opacity"] = &setProperty<HeatmapLayer, PropertyValue<float>, &HeatmapLayer::setHeatmapOpacity>; + result["heatmap-opacity-transition"] = &setTransition<HeatmapLayer, &HeatmapLayer::setHeatmapOpacityTransition>; + result["fill-extrusion-opacity"] = &setProperty<FillExtrusionLayer, PropertyValue<float>, &FillExtrusionLayer::setFillExtrusionOpacity>; result["fill-extrusion-opacity-transition"] = &setTransition<FillExtrusionLayer, &FillExtrusionLayer::setFillExtrusionOpacityTransition>; result["fill-extrusion-color"] = &setProperty<FillExtrusionLayer, DataDrivenPropertyValue<Color>, &FillExtrusionLayer::setFillExtrusionColor>; diff --git a/src/mbgl/style/conversion/property_setter.hpp b/src/mbgl/style/conversion/property_setter.hpp index 9e382b9c38..e3716a18dc 100644 --- a/src/mbgl/style/conversion/property_setter.hpp +++ b/src/mbgl/style/conversion/property_setter.hpp @@ -5,6 +5,7 @@ #include <mbgl/style/conversion/constant.hpp> #include <mbgl/style/conversion/property_value.hpp> #include <mbgl/style/conversion/data_driven_property_value.hpp> +#include <mbgl/style/conversion/heatmap_color_property_value.hpp> #include <mbgl/style/conversion/transition_options.hpp> #include <string> diff --git a/src/mbgl/style/conversion/tileset.cpp b/src/mbgl/style/conversion/tileset.cpp index 6e559c0cac..6d89cef944 100644 --- a/src/mbgl/style/conversion/tileset.cpp +++ b/src/mbgl/style/conversion/tileset.cpp @@ -6,7 +6,7 @@ namespace style { namespace conversion { bool validateLatitude(const double lat) { - return lat < 90 && lat > -90; + return lat <= 90 && lat >= -90; } optional<Tileset> Converter<Tileset>::operator()(const Convertible& value, Error& error) const { @@ -40,6 +40,16 @@ optional<Tileset> Converter<Tileset>::operator()(const Convertible& value, Error } } + auto encodingValue = objectMember(value, "encoding"); + if (encodingValue) { + optional<std::string> encoding = toString(*encodingValue); + if (encoding && *encoding == "terrarium") { + result.encoding = Tileset::DEMEncoding::Terrarium; + } else if (encoding && *encoding != "mapbox") { + error = { "invalid raster-dem encoding type - valid types are 'mapbox' and 'terrarium' " }; + } + } + auto minzoomValue = objectMember(value, "minzoom"); if (minzoomValue) { optional<float> minzoom = toNumber(*minzoomValue); diff --git a/src/mbgl/style/expression/array_assertion.cpp b/src/mbgl/style/expression/array_assertion.cpp index 29f6a47b10..4049301b0b 100644 --- a/src/mbgl/style/expression/array_assertion.cpp +++ b/src/mbgl/style/expression/array_assertion.cpp @@ -81,6 +81,25 @@ ParseResult ArrayAssertion::parse(const Convertible& value, ParsingContext& ctx) )); } +mbgl::Value ArrayAssertion::serialize() const { + std::vector<mbgl::Value> serialized; + serialized.emplace_back(getOperator()); + + + const auto array = getType().get<type::Array>(); + if (array.itemType.is<type::StringType>() + || array.itemType.is<type::NumberType>() + || array.itemType.is<type::BooleanType>()) { + serialized.emplace_back(type::toString(array.itemType)); + if (array.N) { + serialized.emplace_back(uint64_t(*array.N)); + } + } + + serialized.emplace_back(input->serialize()); + return serialized; +} + } // namespace expression } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/expression/assertion.cpp b/src/mbgl/style/expression/assertion.cpp index 0187921af9..d6f3f1b584 100644 --- a/src/mbgl/style/expression/assertion.cpp +++ b/src/mbgl/style/expression/assertion.cpp @@ -35,6 +35,10 @@ ParseResult Assertion::parse(const Convertible& value, ParsingContext& ctx) { return ParseResult(std::make_unique<Assertion>(it->second, std::move(parsed))); } +std::string Assertion::getOperator() const { + return type::toString(getType()); +} + EvaluationResult Assertion::evaluate(const EvaluationContext& params) const { for (std::size_t i = 0; i < inputs.size(); i++) { EvaluationResult value = inputs[i]->evaluate(params); diff --git a/src/mbgl/style/expression/coercion.cpp b/src/mbgl/style/expression/coercion.cpp index 56ab33fcfd..d9cd3ffdc9 100644 --- a/src/mbgl/style/expression/coercion.cpp +++ b/src/mbgl/style/expression/coercion.cpp @@ -81,6 +81,13 @@ Coercion::Coercion(type::Type type_, std::vector<std::unique_ptr<Expression>> in } } +std::string Coercion::getOperator() const { + return getType().match( + [](const type::NumberType&) { return "to-number"; }, + [](const type::ColorType&) { return "to-color"; }, + [](const auto&) { assert(false); return ""; }); +} + using namespace mbgl::style::conversion; ParseResult Coercion::parse(const Convertible& value, ParsingContext& ctx) { static std::unordered_map<std::string, type::Type> types { diff --git a/src/mbgl/style/expression/compound_expression.cpp b/src/mbgl/style/expression/compound_expression.cpp index 42cb655024..86d968c521 100644 --- a/src/mbgl/style/expression/compound_expression.cpp +++ b/src/mbgl/style/expression/compound_expression.cpp @@ -42,20 +42,19 @@ template <class R, class... Params> struct Signature<R (Params...)> : SignatureBase { using Args = std::array<std::unique_ptr<Expression>, sizeof...(Params)>; - Signature(R (*evaluate_)(Params...)) : + Signature(R (*evaluate_)(Params...), std::string name_) : SignatureBase( valueTypeToExpressionType<std::decay_t<typename R::Value>>(), - std::vector<type::Type> {valueTypeToExpressionType<std::decay_t<Params>>()...} + std::vector<type::Type> {valueTypeToExpressionType<std::decay_t<Params>>()...}, + std::move(name_) ), - evaluate(evaluate_) - {} + evaluate(evaluate_) {} EvaluationResult apply(const EvaluationContext& evaluationParameters, const Args& args) const { return applyImpl(evaluationParameters, args, std::index_sequence_for<Params...>{}); } - std::unique_ptr<Expression> makeExpression(const std::string& name, - std::vector<std::unique_ptr<Expression>> args) const override { + std::unique_ptr<Expression> makeExpression(std::vector<std::unique_ptr<Expression>> args) const override { typename Signature::Args argsArray; std::copy_n(std::make_move_iterator(args.begin()), sizeof...(Params), argsArray.begin()); return std::make_unique<CompoundExpression<Signature>>(name, *this, std::move(argsArray)); @@ -80,16 +79,16 @@ template <class R, typename T> struct Signature<R (const Varargs<T>&)> : SignatureBase { using Args = std::vector<std::unique_ptr<Expression>>; - Signature(R (*evaluate_)(const Varargs<T>&)) : + Signature(R (*evaluate_)(const Varargs<T>&), std::string name_) : SignatureBase( valueTypeToExpressionType<std::decay_t<typename R::Value>>(), - VarargsType { valueTypeToExpressionType<T>() } + VarargsType { valueTypeToExpressionType<T>() }, + std::move(name_) ), evaluate(evaluate_) {} - std::unique_ptr<Expression> makeExpression(const std::string& name, - std::vector<std::unique_ptr<Expression>> args) const override { + std::unique_ptr<Expression> makeExpression(std::vector<std::unique_ptr<Expression>> args) const override { return std::make_unique<CompoundExpression<Signature>>(name, *this, std::move(args)); }; @@ -115,16 +114,16 @@ template <class R, class... Params> struct Signature<R (const EvaluationContext&, Params...)> : SignatureBase { using Args = std::array<std::unique_ptr<Expression>, sizeof...(Params)>; - Signature(R (*evaluate_)(const EvaluationContext&, Params...)) : + Signature(R (*evaluate_)(const EvaluationContext&, Params...), std::string name_) : SignatureBase( valueTypeToExpressionType<std::decay_t<typename R::Value>>(), - std::vector<type::Type> {valueTypeToExpressionType<std::decay_t<Params>>()...} + std::vector<type::Type> {valueTypeToExpressionType<std::decay_t<Params>>()...}, + std::move(name_) ), evaluate(evaluate_) {} - std::unique_ptr<Expression> makeExpression(const std::string& name, - std::vector<std::unique_ptr<Expression>> args) const override { + std::unique_ptr<Expression> makeExpression(std::vector<std::unique_ptr<Expression>> args) const override { typename Signature::Args argsArray; std::copy_n(std::make_move_iterator(args.begin()), sizeof...(Params), argsArray.begin()); return std::make_unique<CompoundExpression<Signature>>(name, *this, std::move(argsArray)); @@ -176,14 +175,14 @@ struct Signature<Lambda, std::enable_if_t<std::is_class<Lambda>::value>> using Definition = CompoundExpressionRegistry::Definition; template <typename Fn> -static std::unique_ptr<detail::SignatureBase> makeSignature(Fn evaluateFunction) { - return std::make_unique<detail::Signature<Fn>>(evaluateFunction); +static std::unique_ptr<detail::SignatureBase> makeSignature(Fn evaluateFunction, std::string name) { + return std::make_unique<detail::Signature<Fn>>(evaluateFunction, std::move(name)); } std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initializeDefinitions() { std::unordered_map<std::string, CompoundExpressionRegistry::Definition> definitions; auto define = [&](std::string name, auto fn) { - definitions[name].push_back(makeSignature(fn)); + definitions[name].push_back(makeSignature(fn, name)); }; define("e", []() -> Result<double> { return 2.718281828459045; }); @@ -461,7 +460,7 @@ ParseResult parseCompoundExpression(const std::string name, const Convertible& v } args.push_back(std::move(*parsed)); } - return createCompoundExpression(name, definition, std::move(args), ctx); + return createCompoundExpression(definition, std::move(args), ctx); } @@ -469,12 +468,11 @@ ParseResult createCompoundExpression(const std::string& name, std::vector<std::unique_ptr<Expression>> args, ParsingContext& ctx) { - return createCompoundExpression(name, CompoundExpressionRegistry::definitions.at(name), std::move(args), ctx); + return createCompoundExpression(CompoundExpressionRegistry::definitions.at(name), std::move(args), ctx); } -ParseResult createCompoundExpression(const std::string& name, - const Definition& definition, +ParseResult createCompoundExpression(const Definition& definition, std::vector<std::unique_ptr<Expression>> args, ParsingContext& ctx) { @@ -512,7 +510,7 @@ ParseResult createCompoundExpression(const std::string& name, } if (signatureContext.getErrors().size() == 0) { - return ParseResult(signature->makeExpression(name, std::move(args))); + return ParseResult(signature->makeExpression(std::move(args))); } } diff --git a/src/mbgl/style/expression/interpolate.cpp b/src/mbgl/style/expression/interpolate.cpp index 4cb22a3e4f..30b2cba81b 100644 --- a/src/mbgl/style/expression/interpolate.cpp +++ b/src/mbgl/style/expression/interpolate.cpp @@ -216,6 +216,30 @@ std::vector<optional<Value>> InterpolateBase::possibleOutputs() const { return result; } +template <typename T> +mbgl::Value Interpolate<T>::serialize() const { + std::vector<mbgl::Value> serialized; + serialized.emplace_back(getOperator()); + + interpolator.match( + [&](const ExponentialInterpolator& exponential) { + serialized.emplace_back(std::vector<mbgl::Value>{{ std::string("exponential"), exponential.base }}); + }, + [&](const CubicBezierInterpolator& cubicBezier) { + static const std::string cubicBezierTag("cubic-bezier"); + auto p1 = cubicBezier.ub.getP1(); + auto p2 = cubicBezier.ub.getP2(); + serialized.emplace_back(std::vector<mbgl::Value>{{ cubicBezierTag, p1.first, p1.second, p2.first, p2.second }}); + } + ); + serialized.emplace_back(input->serialize()); + for (auto& entry : stops) { + serialized.emplace_back(entry.first); + serialized.emplace_back(entry.second->serialize()); + }; + return serialized; +} + } // namespace expression } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/expression/let.cpp b/src/mbgl/style/expression/let.cpp index fe48138ac3..242a995b0b 100644 --- a/src/mbgl/style/expression/let.cpp +++ b/src/mbgl/style/expression/let.cpp @@ -65,6 +65,17 @@ ParseResult Let::parse(const Convertible& value, ParsingContext& ctx) { return ParseResult(std::make_unique<Let>(std::move(bindings_), std::move(*result_))); } +mbgl::Value Let::serialize() const { + std::vector<mbgl::Value> serialized; + serialized.emplace_back(getOperator()); + for (auto entry : bindings) { + serialized.emplace_back(entry.first); + serialized.emplace_back(entry.second->serialize()); + } + serialized.emplace_back(result->serialize()); + return serialized; +} + EvaluationResult Var::evaluate(const EvaluationContext& params) const { return value->evaluate(params); } @@ -95,6 +106,10 @@ ParseResult Var::parse(const Convertible& value_, ParsingContext& ctx) { return ParseResult(std::make_unique<Var>(name_, std::move(*bindingValue))); } +mbgl::Value Var::serialize() const { + return std::vector<mbgl::Value>{{ getOperator(), name }}; +} + } // namespace expression } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/expression/literal.cpp b/src/mbgl/style/expression/literal.cpp index 7e79fcbfe6..8a63980dba 100644 --- a/src/mbgl/style/expression/literal.cpp +++ b/src/mbgl/style/expression/literal.cpp @@ -102,6 +102,14 @@ ParseResult Literal::parse(const Convertible& value, ParsingContext& ctx) { } } +mbgl::Value Literal::serialize() const { + if (getType().is<type::Array>() || getType().is<type::ObjectType>()) { + return std::vector<mbgl::Value>{{ getOperator(), *fromExpressionValue<mbgl::Value>(value) }}; + } else { + return *fromExpressionValue<mbgl::Value>(value); + } +} + } // namespace expression } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/expression/match.cpp b/src/mbgl/style/expression/match.cpp index 0b2790b688..3d41f0bdd3 100644 --- a/src/mbgl/style/expression/match.cpp +++ b/src/mbgl/style/expression/match.cpp @@ -40,6 +40,42 @@ std::vector<optional<Value>> Match<T>::possibleOutputs() const { return result; } +template <typename T> +mbgl::Value Match<T>::serialize() const { + std::vector<mbgl::Value> serialized; + serialized.emplace_back(getOperator()); + serialized.emplace_back(input->serialize()); + + // Sort so serialization has an arbitrary defined order, even though branch order doesn't affect evaluation + std::map<T, std::shared_ptr<Expression>> sortedBranches(branches.begin(), branches.end()); + + // Group branches by unique match expression to support condensed serializations + // of the form [case1, case2, ...] -> matchExpression + std::map<Expression*, size_t> outputLookup; + std::vector<std::pair<Expression*, std::vector<mbgl::Value>>> groupedByOutput; + for (auto& entry : sortedBranches) { + auto outputIndex = outputLookup.find(entry.second.get()); + if (outputIndex == outputLookup.end()) { + // First time seeing this output, add it to the end of the grouped list + outputLookup[entry.second.get()] = groupedByOutput.size(); + groupedByOutput.emplace_back(entry.second.get(), std::vector<mbgl::Value>{{entry.first}}); + } else { + // We've seen this expression before, add the label to that output's group + groupedByOutput[outputIndex->second].second.emplace_back(entry.first); + } + }; + + for (auto& entry : groupedByOutput) { + entry.second.size() == 1 + ? serialized.emplace_back(entry.second[0]) // Only a single label matches this output expression + : serialized.emplace_back(entry.second); // Array of literal labels pointing to this output expression + serialized.emplace_back(entry.first->serialize()); // The output expression itself + } + + serialized.emplace_back(otherwise->serialize()); + return serialized; +} + template<> EvaluationResult Match<std::string>::evaluate(const EvaluationContext& params) const { const EvaluationResult inputValue = input->evaluate(params); diff --git a/src/mbgl/style/expression/step.cpp b/src/mbgl/style/expression/step.cpp index 34537d48ae..ddaf9417cb 100644 --- a/src/mbgl/style/expression/step.cpp +++ b/src/mbgl/style/expression/step.cpp @@ -168,6 +168,18 @@ ParseResult Step::parse(const mbgl::style::conversion::Convertible& value, Parsi return ParseResult(std::make_unique<Step>(*outputType, std::move(*input), std::move(stops))); } +mbgl::Value Step::serialize() const { + std::vector<mbgl::Value> serialized; + serialized.emplace_back(getOperator()); + serialized.emplace_back(input->serialize()); + for (auto& entry : stops) { + if (entry.first > -std::numeric_limits<double>::infinity()) { + serialized.emplace_back(entry.first); + } + serialized.emplace_back(entry.second->serialize()); + } + return serialized; +} } // namespace expression } // namespace style diff --git a/src/mbgl/style/expression/value.cpp b/src/mbgl/style/expression/value.cpp index faa44e78aa..72779d4956 100644 --- a/src/mbgl/style/expression/value.cpp +++ b/src/mbgl/style/expression/value.cpp @@ -103,6 +103,37 @@ Value ValueConverter<mbgl::Value>::toExpressionValue(const mbgl::Value& value) { return mbgl::Value::visit(value, FromMBGLValue()); } +mbgl::Value ValueConverter<mbgl::Value>::fromExpressionValue(const Value& value) { + return value.match( + [&](const Color& color)->mbgl::Value { + return std::vector<mbgl::Value>{ + std::string("rgba"), + double(255 * color.r / color.a), + double(255 * color.g / color.a), + double(255 * color.b / color.a), + double(color.a) + }; + }, + [&](const std::vector<Value>& values)->mbgl::Value { + std::vector<mbgl::Value> converted; + converted.reserve(values.size()); + for (const Value& v : values) { + converted.emplace_back(fromExpressionValue(v)); + } + return converted; + }, + [&](const std::unordered_map<std::string, Value>& values)->mbgl::Value { + std::unordered_map<std::string, mbgl::Value> converted; + converted.reserve(values.size()); + for(const auto& entry : values) { + converted.emplace(entry.first, fromExpressionValue(entry.second)); + } + return converted; + }, + [&](const auto& a)->mbgl::Value { return a; } + ); +} + Value ValueConverter<float>::toExpressionValue(const float value) { return static_cast<double>(value); } @@ -237,7 +268,7 @@ template <> type::Type valueTypeToExpressionType<type::ErrorType>() { return typ template Value toExpressionValue(const mbgl::Value&); - +template optional<mbgl::Value> fromExpressionValue<mbgl::Value>(const Value&); // for to_rgba expression template type::Type valueTypeToExpressionType<std::array<double, 4>>(); diff --git a/src/mbgl/style/layers/heatmap_layer.cpp b/src/mbgl/style/layers/heatmap_layer.cpp new file mode 100644 index 0000000000..4989ff15f1 --- /dev/null +++ b/src/mbgl/style/layers/heatmap_layer.cpp @@ -0,0 +1,239 @@ +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. + +#include <mbgl/style/layers/heatmap_layer.hpp> +#include <mbgl/style/layers/heatmap_layer_impl.hpp> +#include <mbgl/style/layer_observer.hpp> +// for constructing default heatmap-color ramp expression from style JSON +#include <mbgl/style/conversion.hpp> +#include <mbgl/style/conversion/json.hpp> +#include <mbgl/style/conversion/heatmap_color_property_value.hpp> + +namespace mbgl { +namespace style { + +HeatmapLayer::HeatmapLayer(const std::string& layerID, const std::string& sourceID) + : Layer(makeMutable<Impl>(LayerType::Heatmap, layerID, sourceID)) { +} + +HeatmapLayer::HeatmapLayer(Immutable<Impl> impl_) + : Layer(std::move(impl_)) { +} + +HeatmapLayer::~HeatmapLayer() = default; + +const HeatmapLayer::Impl& HeatmapLayer::impl() const { + return static_cast<const Impl&>(*baseImpl); +} + +Mutable<HeatmapLayer::Impl> HeatmapLayer::mutableImpl() const { + return makeMutable<Impl>(impl()); +} + +std::unique_ptr<Layer> HeatmapLayer::cloneRef(const std::string& id_) const { + auto impl_ = mutableImpl(); + impl_->id = id_; + impl_->paint = HeatmapPaintProperties::Transitionable(); + return std::make_unique<HeatmapLayer>(std::move(impl_)); +} + +void HeatmapLayer::Impl::stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const { +} + +// Source + +const std::string& HeatmapLayer::getSourceID() const { + return impl().source; +} + +void HeatmapLayer::setSourceLayer(const std::string& sourceLayer) { + auto impl_ = mutableImpl(); + impl_->sourceLayer = sourceLayer; + baseImpl = std::move(impl_); +} + +const std::string& HeatmapLayer::getSourceLayer() const { + return impl().sourceLayer; +} + +// Filter + +void HeatmapLayer::setFilter(const Filter& filter) { + auto impl_ = mutableImpl(); + impl_->filter = filter; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +const Filter& HeatmapLayer::getFilter() const { + return impl().filter; +} + +// Visibility + +void HeatmapLayer::setVisibility(VisibilityType value) { + if (value == getVisibility()) + return; + auto impl_ = mutableImpl(); + impl_->visibility = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +// Zoom range + +void HeatmapLayer::setMinZoom(float minZoom) { + auto impl_ = mutableImpl(); + impl_->minZoom = minZoom; + baseImpl = std::move(impl_); +} + +void HeatmapLayer::setMaxZoom(float maxZoom) { + auto impl_ = mutableImpl(); + impl_->maxZoom = maxZoom; + baseImpl = std::move(impl_); +} + +// Layout properties + + +// Paint properties + +DataDrivenPropertyValue<float> HeatmapLayer::getDefaultHeatmapRadius() { + return { 30 }; +} + +DataDrivenPropertyValue<float> HeatmapLayer::getHeatmapRadius() const { + return impl().paint.template get<HeatmapRadius>().value; +} + +void HeatmapLayer::setHeatmapRadius(DataDrivenPropertyValue<float> value) { + if (value == getHeatmapRadius()) + return; + auto impl_ = mutableImpl(); + impl_->paint.template get<HeatmapRadius>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +void HeatmapLayer::setHeatmapRadiusTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<HeatmapRadius>().options = options; + baseImpl = std::move(impl_); +} + +TransitionOptions HeatmapLayer::getHeatmapRadiusTransition() const { + return impl().paint.template get<HeatmapRadius>().options; +} + +DataDrivenPropertyValue<float> HeatmapLayer::getDefaultHeatmapWeight() { + return { 1 }; +} + +DataDrivenPropertyValue<float> HeatmapLayer::getHeatmapWeight() const { + return impl().paint.template get<HeatmapWeight>().value; +} + +void HeatmapLayer::setHeatmapWeight(DataDrivenPropertyValue<float> value) { + if (value == getHeatmapWeight()) + return; + auto impl_ = mutableImpl(); + impl_->paint.template get<HeatmapWeight>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +void HeatmapLayer::setHeatmapWeightTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<HeatmapWeight>().options = options; + baseImpl = std::move(impl_); +} + +TransitionOptions HeatmapLayer::getHeatmapWeightTransition() const { + return impl().paint.template get<HeatmapWeight>().options; +} + +PropertyValue<float> HeatmapLayer::getDefaultHeatmapIntensity() { + return { 1 }; +} + +PropertyValue<float> HeatmapLayer::getHeatmapIntensity() const { + return impl().paint.template get<HeatmapIntensity>().value; +} + +void HeatmapLayer::setHeatmapIntensity(PropertyValue<float> value) { + if (value == getHeatmapIntensity()) + return; + auto impl_ = mutableImpl(); + impl_->paint.template get<HeatmapIntensity>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +void HeatmapLayer::setHeatmapIntensityTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<HeatmapIntensity>().options = options; + baseImpl = std::move(impl_); +} + +TransitionOptions HeatmapLayer::getHeatmapIntensityTransition() const { + return impl().paint.template get<HeatmapIntensity>().options; +} + +HeatmapColorPropertyValue HeatmapLayer::getDefaultHeatmapColor() { + conversion::Error error; + std::string rawValue = R"JSON(["interpolate",["linear"],["heatmap-density"],0,"rgba(0, 0, 255, 0)",0.1,"royalblue",0.3,"cyan",0.5,"lime",0.7,"yellow",1,"red"])JSON"; + return *conversion::convertJSON<HeatmapColorPropertyValue>(rawValue, error); +} + +HeatmapColorPropertyValue HeatmapLayer::getHeatmapColor() const { + return impl().paint.template get<HeatmapColor>().value; +} + +void HeatmapLayer::setHeatmapColor(HeatmapColorPropertyValue value) { + if (value == getHeatmapColor()) + return; + auto impl_ = mutableImpl(); + impl_->paint.template get<HeatmapColor>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +void HeatmapLayer::setHeatmapColorTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<HeatmapColor>().options = options; + baseImpl = std::move(impl_); +} + +TransitionOptions HeatmapLayer::getHeatmapColorTransition() const { + return impl().paint.template get<HeatmapColor>().options; +} + +PropertyValue<float> HeatmapLayer::getDefaultHeatmapOpacity() { + return { 1 }; +} + +PropertyValue<float> HeatmapLayer::getHeatmapOpacity() const { + return impl().paint.template get<HeatmapOpacity>().value; +} + +void HeatmapLayer::setHeatmapOpacity(PropertyValue<float> value) { + if (value == getHeatmapOpacity()) + return; + auto impl_ = mutableImpl(); + impl_->paint.template get<HeatmapOpacity>().value = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} + +void HeatmapLayer::setHeatmapOpacityTransition(const TransitionOptions& options) { + auto impl_ = mutableImpl(); + impl_->paint.template get<HeatmapOpacity>().options = options; + baseImpl = std::move(impl_); +} + +TransitionOptions HeatmapLayer::getHeatmapOpacityTransition() const { + return impl().paint.template get<HeatmapOpacity>().options; +} + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/layers/heatmap_layer_impl.cpp b/src/mbgl/style/layers/heatmap_layer_impl.cpp new file mode 100644 index 0000000000..af20888d9d --- /dev/null +++ b/src/mbgl/style/layers/heatmap_layer_impl.cpp @@ -0,0 +1,15 @@ +#include <mbgl/style/layers/heatmap_layer_impl.hpp> + +namespace mbgl { +namespace style { + +bool HeatmapLayer::Impl::hasLayoutDifference(const Layer::Impl& other) const { + assert(dynamic_cast<const HeatmapLayer::Impl*>(&other)); + const auto& impl = static_cast<const style::HeatmapLayer::Impl&>(other); + return filter != impl.filter || + visibility != impl.visibility || + paint.hasDataDrivenPropertyDifference(impl.paint); +} + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/layers/heatmap_layer_impl.hpp b/src/mbgl/style/layers/heatmap_layer_impl.hpp new file mode 100644 index 0000000000..cc27c3076a --- /dev/null +++ b/src/mbgl/style/layers/heatmap_layer_impl.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include <mbgl/style/layer_impl.hpp> +#include <mbgl/style/layers/heatmap_layer.hpp> +#include <mbgl/style/layers/heatmap_layer_properties.hpp> + +namespace mbgl { +namespace style { + +class HeatmapLayer::Impl : public Layer::Impl { +public: + using Layer::Impl::Impl; + + bool hasLayoutDifference(const Layer::Impl&) const override; + void stringifyLayout(rapidjson::Writer<rapidjson::StringBuffer>&) const override; + + HeatmapPaintProperties::Transitionable paint; +}; + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/layers/heatmap_layer_properties.cpp b/src/mbgl/style/layers/heatmap_layer_properties.cpp new file mode 100644 index 0000000000..2edb839589 --- /dev/null +++ b/src/mbgl/style/layers/heatmap_layer_properties.cpp @@ -0,0 +1,9 @@ +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. + +#include <mbgl/style/layers/heatmap_layer_properties.hpp> + +namespace mbgl { +namespace style { + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/layers/heatmap_layer_properties.hpp b/src/mbgl/style/layers/heatmap_layer_properties.hpp new file mode 100644 index 0000000000..f7afa5fbeb --- /dev/null +++ b/src/mbgl/style/layers/heatmap_layer_properties.hpp @@ -0,0 +1,40 @@ +// This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. + +#pragma once + +#include <mbgl/style/types.hpp> +#include <mbgl/style/layout_property.hpp> +#include <mbgl/style/paint_property.hpp> +#include <mbgl/style/properties.hpp> +#include <mbgl/programs/attributes.hpp> +#include <mbgl/programs/uniforms.hpp> + +namespace mbgl { +namespace style { + +struct HeatmapRadius : DataDrivenPaintProperty<float, attributes::a_radius, uniforms::u_radius> { + static float defaultValue() { return 30; } +}; + +struct HeatmapWeight : DataDrivenPaintProperty<float, attributes::a_weight, uniforms::u_weight> { + static float defaultValue() { return 1; } +}; + +struct HeatmapIntensity : PaintProperty<float> { + static float defaultValue() { return 1; } +}; + +struct HeatmapOpacity : PaintProperty<float> { + static float defaultValue() { return 1; } +}; + +class HeatmapPaintProperties : public Properties< + HeatmapRadius, + HeatmapWeight, + HeatmapIntensity, + HeatmapColor, + HeatmapOpacity +> {}; + +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/layers/layer.cpp.ejs b/src/mbgl/style/layers/layer.cpp.ejs index be44bb353d..657a7f5a8a 100644 --- a/src/mbgl/style/layers/layer.cpp.ejs +++ b/src/mbgl/style/layers/layer.cpp.ejs @@ -8,6 +8,12 @@ #include <mbgl/style/layers/<%- type.replace('-', '_') %>_layer.hpp> #include <mbgl/style/layers/<%- type.replace('-', '_') %>_layer_impl.hpp> #include <mbgl/style/layer_observer.hpp> +<% if (type === 'heatmap') { -%> +// for constructing default heatmap-color ramp expression from style JSON +#include <mbgl/style/conversion.hpp> +#include <mbgl/style/conversion/json.hpp> +#include <mbgl/style/conversion/heatmap_color_property_value.hpp> +<% } -%> namespace mbgl { namespace style { @@ -134,7 +140,13 @@ void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>(<%- propertyV // Paint properties <% for (const property of paintProperties) { %> <%- propertyValueType(property) %> <%- camelize(type) %>Layer::getDefault<%- camelize(property.name) %>() { +<% if (property.name === 'heatmap-color') { -%> + conversion::Error error; + std::string rawValue = R"JSON(<%- JSON.stringify(property.default) %>)JSON"; + return *conversion::convertJSON<<%- propertyValueType(property)%>>(rawValue, error); +<% } else { -%> return { <%- defaultValue(property) %> }; +<% } -%> } <%- propertyValueType(property) %> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>() const { diff --git a/src/mbgl/style/layers/layer_properties.hpp.ejs b/src/mbgl/style/layers/layer_properties.hpp.ejs index cde1b80b7b..1bceb84960 100644 --- a/src/mbgl/style/layers/layer_properties.hpp.ejs +++ b/src/mbgl/style/layers/layer_properties.hpp.ejs @@ -25,6 +25,7 @@ struct <%- camelize(property.name) %> : <%- layoutPropertyType(property, type) % <% } -%> <% for (const property of paintProperties) { -%> +<% if (property.name === 'heatmap-color') continue; -%> struct <%- camelize(property.name) %> : <%- paintPropertyType(property, type) %> { static <%- evaluatedType(property) %> defaultValue() { return <%- defaultValue(property) %>; } }; diff --git a/src/mbgl/style/paint_property.hpp b/src/mbgl/style/paint_property.hpp index c4c996b3bd..195eb645a9 100644 --- a/src/mbgl/style/paint_property.hpp +++ b/src/mbgl/style/paint_property.hpp @@ -2,6 +2,7 @@ #include <mbgl/style/properties.hpp> #include <mbgl/style/property_value.hpp> +#include <mbgl/style/heatmap_color_property_value.hpp> #include <mbgl/style/data_driven_property_value.hpp> #include <mbgl/renderer/property_evaluator.hpp> #include <mbgl/renderer/cross_faded_property_evaluator.hpp> @@ -48,5 +49,27 @@ public: static constexpr bool IsDataDriven = false; }; +/* + * Special-case paint property traits for heatmap-color, needed because + * heatmap-color values do not fit into the + * Undefined | Value | {Camera,Source,Composite}Function taxonomy that applies + * to all other paint properties. + * + * These traits are provided here--despite the fact that heatmap-color + * is not used like other paint properties--to allow the parameter-pack-based + * batch evaluation of paint properties to compile properly. + */ +class HeatmapColor { +public: + using TransitionableType = Transitionable<HeatmapColorPropertyValue>; + using UnevaluatedType = Transitioning<HeatmapColorPropertyValue>; + using EvaluatorType = PropertyEvaluator<Color>; + using PossiblyEvaluatedType = Color; + using Type = Color; + static constexpr bool IsDataDriven = false; + + static Color defaultValue() { return {}; } +}; + } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/style_impl.cpp b/src/mbgl/style/style_impl.cpp index f2a9c0f222..0c7f924917 100644 --- a/src/mbgl/style/style_impl.cpp +++ b/src/mbgl/style/style_impl.cpp @@ -6,6 +6,7 @@ #include <mbgl/style/layers/background_layer.hpp> #include <mbgl/style/layers/fill_layer.hpp> #include <mbgl/style/layers/fill_extrusion_layer.hpp> +#include <mbgl/style/layers/heatmap_layer.hpp> #include <mbgl/style/layers/line_layer.hpp> #include <mbgl/style/layers/circle_layer.hpp> #include <mbgl/style/layers/raster_layer.hpp> @@ -54,11 +55,6 @@ void Style::Impl::loadURL(const std::string& url_) { url = url_; styleRequest = fileSource.request(Resource::style(url), [this](Response res) { - // Once we get a fresh style, or the style is mutated, stop revalidating. - if (res.isFresh() || mutated) { - styleRequest.reset(); - } - // Don't allow a loaded, mutated style to be overwritten with a new version. if (mutated && loaded) { return; |