summaryrefslogtreecommitdiff
path: root/src/mbgl/style
diff options
context:
space:
mode:
Diffstat (limited to 'src/mbgl/style')
-rw-r--r--src/mbgl/style/conversion/layer.cpp3
-rw-r--r--src/mbgl/style/conversion/make_property_setters.hpp13
-rw-r--r--src/mbgl/style/conversion/property_setter.hpp1
-rw-r--r--src/mbgl/style/conversion/tileset.cpp12
-rw-r--r--src/mbgl/style/expression/array_assertion.cpp19
-rw-r--r--src/mbgl/style/expression/assertion.cpp4
-rw-r--r--src/mbgl/style/expression/coercion.cpp7
-rw-r--r--src/mbgl/style/expression/compound_expression.cpp42
-rw-r--r--src/mbgl/style/expression/interpolate.cpp24
-rw-r--r--src/mbgl/style/expression/let.cpp15
-rw-r--r--src/mbgl/style/expression/literal.cpp8
-rw-r--r--src/mbgl/style/expression/match.cpp36
-rw-r--r--src/mbgl/style/expression/step.cpp12
-rw-r--r--src/mbgl/style/expression/value.cpp33
-rw-r--r--src/mbgl/style/layers/heatmap_layer.cpp239
-rw-r--r--src/mbgl/style/layers/heatmap_layer_impl.cpp15
-rw-r--r--src/mbgl/style/layers/heatmap_layer_impl.hpp21
-rw-r--r--src/mbgl/style/layers/heatmap_layer_properties.cpp9
-rw-r--r--src/mbgl/style/layers/heatmap_layer_properties.hpp40
-rw-r--r--src/mbgl/style/layers/layer.cpp.ejs12
-rw-r--r--src/mbgl/style/layers/layer_properties.hpp.ejs1
-rw-r--r--src/mbgl/style/paint_property.hpp23
-rw-r--r--src/mbgl/style/style_impl.cpp6
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;