summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmake/test-files.cmake2
-rw-r--r--include/mbgl/style/conversion/function.hpp33
-rw-r--r--include/mbgl/style/function/camera_function.hpp2
-rw-r--r--include/mbgl/style/function/categorical_stops.hpp10
-rw-r--r--include/mbgl/style/function/composite_function.hpp23
-rw-r--r--include/mbgl/style/function/exponential_stops.hpp2
-rw-r--r--include/mbgl/style/function/identity_stops.hpp2
-rw-r--r--include/mbgl/style/function/interval_stops.hpp6
-rw-r--r--include/mbgl/style/function/source_function.hpp17
-rw-r--r--src/mbgl/layout/symbol_layout.cpp4
-rw-r--r--src/mbgl/style/conversion/stringify.hpp8
-rw-r--r--src/mbgl/style/function/categorical_stops.cpp6
-rw-r--r--src/mbgl/style/function/identity_stops.cpp22
-rw-r--r--src/mbgl/style/layout_property.hpp11
-rw-r--r--src/mbgl/style/paint_property_binder.hpp18
-rw-r--r--src/mbgl/style/possibly_evaluated_property_value.hpp7
-rw-r--r--test/src/mbgl/test/stub_geometry_tile_feature.hpp34
-rw-r--r--test/style/conversion/stringify.test.cpp6
-rw-r--r--test/style/function/source_function.test.cpp94
19 files changed, 243 insertions, 64 deletions
diff --git a/cmake/test-files.cmake b/cmake/test-files.cmake
index 2e2c297492..9ab9918162 100644
--- a/cmake/test-files.cmake
+++ b/cmake/test-files.cmake
@@ -50,6 +50,7 @@ set(MBGL_TEST_FILES
test/src/mbgl/test/fixture_log_observer.hpp
test/src/mbgl/test/stub_file_source.cpp
test/src/mbgl/test/stub_file_source.hpp
+ test/src/mbgl/test/stub_geometry_tile_feature.hpp
test/src/mbgl/test/stub_layer_observer.hpp
test/src/mbgl/test/stub_style_observer.hpp
test/src/mbgl/test/stub_tile_observer.hpp
@@ -80,6 +81,7 @@ set(MBGL_TEST_FILES
# style/function
test/style/function/camera_function.test.cpp
+ test/style/function/source_function.test.cpp
# style
test/style/group_by_layout.test.cpp
diff --git a/include/mbgl/style/conversion/function.hpp b/include/mbgl/style/conversion/function.hpp
index 90b4b95063..7d69fa55c5 100644
--- a/include/mbgl/style/conversion/function.hpp
+++ b/include/mbgl/style/conversion/function.hpp
@@ -198,6 +198,21 @@ struct Converter<CameraFunction<T>> {
}
};
+template <class T, class V>
+Result<optional<T>> convertDefaultValue(const V& value) {
+ auto defaultValueValue = objectMember(value, "defaultValue");
+ if (!defaultValueValue) {
+ return {};
+ }
+
+ auto defaultValue = convert<T>(*defaultValueValue);
+ if (!defaultValue) {
+ return Error { "wrong type for \"default\": " + defaultValue.error().message };
+ }
+
+ return *defaultValue;
+}
+
template <class T>
struct Converter<SourceFunction<T>> {
template <class V>
@@ -221,7 +236,12 @@ struct Converter<SourceFunction<T>> {
return stops.error();
}
- return SourceFunction<T>(*propertyString, *stops);
+ auto defaultValue = convertDefaultValue<T>(value);
+ if (!defaultValue) {
+ return defaultValue.error();
+ }
+
+ return SourceFunction<T>(*propertyString, *stops, *defaultValue);
}
};
@@ -280,6 +300,11 @@ struct Converter<CompositeFunction<T>> {
return Error { "function property must be a string" };
}
+ auto defaultValue = convertDefaultValue<T>(value);
+ if (!defaultValue) {
+ return defaultValue.error();
+ }
+
std::string type = "exponential";
auto typeValue = objectMember(value, "type");
if (typeValue && toString(*typeValue)) {
@@ -305,7 +330,7 @@ struct Converter<CompositeFunction<T>> {
inner.stops.emplace(stop.first.second, stop.second);
}
- return CompositeFunction<T>(*propertyString, convertedStops);
+ return CompositeFunction<T>(*propertyString, convertedStops, *defaultValue);
} else if (type == "interval") {
auto stops = convertStops<CompositeValue<float>, T>(value);
if (!stops) {
@@ -318,7 +343,7 @@ struct Converter<CompositeFunction<T>> {
inner.stops.emplace(stop.first.second, stop.second);
}
- return CompositeFunction<T>(*propertyString, convertedStops);
+ return CompositeFunction<T>(*propertyString, convertedStops, *defaultValue);
} else if (type == "categorical") {
auto stops = convertStops<CompositeValue<CategoricalValue>, T>(value);
if (!stops) {
@@ -331,7 +356,7 @@ struct Converter<CompositeFunction<T>> {
inner.stops.emplace(stop.first.second, stop.second);
}
- return CompositeFunction<T>(*propertyString, convertedStops);
+ return CompositeFunction<T>(*propertyString, convertedStops, *defaultValue);
} else {
return Error { "unsupported function type" };
}
diff --git a/include/mbgl/style/function/camera_function.hpp b/include/mbgl/style/function/camera_function.hpp
index a96978939d..5636b1663c 100644
--- a/include/mbgl/style/function/camera_function.hpp
+++ b/include/mbgl/style/function/camera_function.hpp
@@ -25,7 +25,7 @@ public:
T evaluate(float zoom) const {
return stops.match([&] (const auto& s) {
- return s.evaluate(Value(double(zoom)));
+ return s.evaluate(Value(double(zoom))).value_or(T());
});
}
diff --git a/include/mbgl/style/function/categorical_stops.hpp b/include/mbgl/style/function/categorical_stops.hpp
index 11ec2a0e5a..c8505115ab 100644
--- a/include/mbgl/style/function/categorical_stops.hpp
+++ b/include/mbgl/style/function/categorical_stops.hpp
@@ -21,20 +21,18 @@ public:
using Stops = std::map<CategoricalValue, T>;
Stops stops;
- T defaultValue;
CategoricalStops() = default;
- CategoricalStops(Stops stops_, T defaultValue_ = T())
- : stops(std::move(stops_)),
- defaultValue(std::move(defaultValue_)) {
+ CategoricalStops(Stops stops_)
+ : stops(std::move(stops_)) {
assert(stops.size() > 0);
}
- T evaluate(const Value&) const;
+ optional<T> evaluate(const Value&) const;
friend bool operator==(const CategoricalStops& lhs,
const CategoricalStops& rhs) {
- return lhs.stops == rhs.stops && lhs.defaultValue == rhs.defaultValue;
+ return lhs.stops == rhs.stops;
}
};
diff --git a/include/mbgl/style/function/composite_function.hpp b/include/mbgl/style/function/composite_function.hpp
index 169a455435..f42a5f06f4 100644
--- a/include/mbgl/style/function/composite_function.hpp
+++ b/include/mbgl/style/function/composite_function.hpp
@@ -43,9 +43,10 @@ public:
std::map<float, IntervalStops<T>>,
std::map<float, CategoricalStops<T>>>>;
- CompositeFunction(std::string property_, Stops stops_)
+ CompositeFunction(std::string property_, Stops stops_, optional<T> defaultValue_ = {})
: property(std::move(property_)),
- stops(std::move(stops_)) {
+ stops(std::move(stops_)),
+ defaultValue(std::move(defaultValue_)) {
}
std::tuple<Range<float>, Range<InnerStops>>
@@ -73,13 +74,17 @@ public:
}
Range<T> evaluate(Range<InnerStops> coveringStops,
- const GeometryTileFeature& feature) const {
+ const GeometryTileFeature& feature,
+ T finalDefaultValue) const {
optional<Value> v = feature.getValue(property);
if (!v) {
- return { T(), T() };
+ return {
+ defaultValue.value_or(finalDefaultValue),
+ defaultValue.value_or(finalDefaultValue)
+ };
}
auto eval = [&] (const auto& s) {
- return s.evaluate(*v);
+ return s.evaluate(*v).value_or(defaultValue.value_or(finalDefaultValue));
};
return Range<T> {
coveringStops.min.match(eval),
@@ -87,9 +92,9 @@ public:
};
}
- T evaluate(float zoom, const GeometryTileFeature& feature) const {
+ T evaluate(float zoom, const GeometryTileFeature& feature, T finalDefaultValue) const {
std::tuple<Range<float>, Range<InnerStops>> ranges = coveringRanges(zoom);
- Range<T> resultRange = evaluate(std::get<1>(ranges), feature);
+ Range<T> resultRange = evaluate(std::get<1>(ranges), feature, finalDefaultValue);
return util::interpolate(
resultRange.min,
resultRange.max,
@@ -98,11 +103,13 @@ public:
friend bool operator==(const CompositeFunction& lhs,
const CompositeFunction& rhs) {
- return lhs.property == rhs.property && lhs.stops == rhs.stops;
+ return std::tie(lhs.property, lhs.stops, lhs.defaultValue)
+ == std::tie(rhs.property, rhs.stops, rhs.defaultValue);
}
std::string property;
Stops stops;
+ optional<T> defaultValue;
};
} // namespace style
diff --git a/include/mbgl/style/function/exponential_stops.hpp b/include/mbgl/style/function/exponential_stops.hpp
index 7bd8783614..051f5aa9aa 100644
--- a/include/mbgl/style/function/exponential_stops.hpp
+++ b/include/mbgl/style/function/exponential_stops.hpp
@@ -22,7 +22,7 @@ public:
base(base_) {
}
- T evaluate(const Value& value) const {
+ optional<T> evaluate(const Value& value) const {
if (stops.empty()) {
assert(false);
return T();
diff --git a/include/mbgl/style/function/identity_stops.hpp b/include/mbgl/style/function/identity_stops.hpp
index 4e199f2e15..741ebbbe0c 100644
--- a/include/mbgl/style/function/identity_stops.hpp
+++ b/include/mbgl/style/function/identity_stops.hpp
@@ -8,7 +8,7 @@ namespace style {
template <class T>
class IdentityStops {
public:
- T evaluate(const Value&) const;
+ optional<T> evaluate(const Value&) const;
friend bool operator==(const IdentityStops&,
const IdentityStops&) {
diff --git a/include/mbgl/style/function/interval_stops.hpp b/include/mbgl/style/function/interval_stops.hpp
index cf879d730b..50f2b48453 100644
--- a/include/mbgl/style/function/interval_stops.hpp
+++ b/include/mbgl/style/function/interval_stops.hpp
@@ -18,15 +18,15 @@ public:
: stops(std::move(stops_)) {
}
- T evaluate(const Value& value) const {
+ optional<T> evaluate(const Value& value) const {
if (stops.empty()) {
assert(false);
- return T();
+ return {};
}
optional<float> z = numericValue<float>(value);
if (!z) {
- return T();
+ return {};
}
auto it = stops.upper_bound(*z);
diff --git a/include/mbgl/style/function/source_function.hpp b/include/mbgl/style/function/source_function.hpp
index e998be082a..29b1067a19 100644
--- a/include/mbgl/style/function/source_function.hpp
+++ b/include/mbgl/style/function/source_function.hpp
@@ -28,28 +28,31 @@ public:
CategoricalStops<T>,
IdentityStops<T>>>;
- SourceFunction(std::string property_, Stops stops_)
+ SourceFunction(std::string property_, Stops stops_, optional<T> defaultValue_ = {})
: property(std::move(property_)),
- stops(std::move(stops_)) {
+ stops(std::move(stops_)),
+ defaultValue(std::move(defaultValue_)) {
}
- T evaluate(const GeometryTileFeature& feature) const {
+ T evaluate(const GeometryTileFeature& feature, T finalDefaultValue) const {
optional<Value> v = feature.getValue(property);
if (!v) {
- return T();
+ return defaultValue.value_or(finalDefaultValue);
}
- return stops.match([&] (const auto& s) {
- return s.evaluate(*v);
+ return stops.match([&] (const auto& s) -> T {
+ return s.evaluate(*v).value_or(defaultValue.value_or(finalDefaultValue));
});
}
friend bool operator==(const SourceFunction& lhs,
const SourceFunction& rhs) {
- return lhs.property == rhs.property && lhs.stops == rhs.stops;
+ return std::tie(lhs.property, lhs.stops, lhs.defaultValue)
+ == std::tie(rhs.property, rhs.stops, rhs.defaultValue);
}
std::string property;
Stops stops;
+ optional<T> defaultValue;
};
} // namespace style
diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp
index 5dd36c41bd..665806cb0e 100644
--- a/src/mbgl/layout/symbol_layout.cpp
+++ b/src/mbgl/layout/symbol_layout.cpp
@@ -129,8 +129,8 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters,
if (hasIcon) {
ft.icon = util::replaceTokens(layout.get<IconImage>(), getValue);
- ft.iconOffset = layout.get<IconOffset>().evaluate(zoom, *feature);
- ft.iconRotation = layout.get<IconRotate>().evaluate(zoom, *feature) * util::DEG2RAD;
+ ft.iconOffset = layout.evaluate<IconOffset>(zoom, *feature);
+ ft.iconRotation = layout.evaluate<IconRotate>(zoom, *feature) * util::DEG2RAD;
}
if (ft.text || ft.icon) {
diff --git a/src/mbgl/style/conversion/stringify.hpp b/src/mbgl/style/conversion/stringify.hpp
index 71755bd9d6..5aab1076fd 100644
--- a/src/mbgl/style/conversion/stringify.hpp
+++ b/src/mbgl/style/conversion/stringify.hpp
@@ -330,6 +330,10 @@ void stringify(Writer& writer, const SourceFunction<T>& f) {
writer.Key("property");
writer.String(f.property);
SourceFunction<T>::Stops::visit(f.stops, StringifyStops<Writer> { writer });
+ if (f.defaultValue) {
+ writer.Key("default");
+ stringify(writer, *f.defaultValue);
+ }
writer.EndObject();
}
@@ -339,6 +343,10 @@ void stringify(Writer& writer, const CompositeFunction<T>& f) {
writer.Key("property");
writer.String(f.property);
CompositeFunction<T>::Stops::visit(f.stops, StringifyStops<Writer> { writer });
+ if (f.defaultValue) {
+ writer.Key("default");
+ stringify(writer, *f.defaultValue);
+ }
writer.EndObject();
}
diff --git a/src/mbgl/style/function/categorical_stops.cpp b/src/mbgl/style/function/categorical_stops.cpp
index bcdf170f17..21df4fa9f6 100644
--- a/src/mbgl/style/function/categorical_stops.cpp
+++ b/src/mbgl/style/function/categorical_stops.cpp
@@ -18,13 +18,13 @@ optional<CategoricalValue> categoricalValue(const Value& value) {
}
template <class T>
-T CategoricalStops<T>::evaluate(const Value& value) const {
+optional<T> CategoricalStops<T>::evaluate(const Value& value) const {
auto v = categoricalValue(value);
if (!v) {
- return defaultValue;
+ return {};
}
auto it = stops.find(*v);
- return it == stops.end() ? defaultValue : it->second;
+ return it == stops.end() ? optional<T>() : it->second;
}
template class CategoricalStops<float>;
diff --git a/src/mbgl/style/function/identity_stops.cpp b/src/mbgl/style/function/identity_stops.cpp
index e210b4d773..9bddc3feac 100644
--- a/src/mbgl/style/function/identity_stops.cpp
+++ b/src/mbgl/style/function/identity_stops.cpp
@@ -7,36 +7,34 @@ namespace mbgl {
namespace style {
template <>
-float IdentityStops<float>::evaluate(const Value& value) const {
- return numericValue<float>(value)
- .value_or(0.0f);
+optional<float> IdentityStops<float>::evaluate(const Value& value) const {
+ return numericValue<float>(value);
}
template <>
-Color IdentityStops<Color>::evaluate(const Value& value) const {
+optional<Color> IdentityStops<Color>::evaluate(const Value& value) const {
if (!value.is<std::string>()) {
- return Color::black();
+ return {};
}
- return Color::parse(value.get<std::string>())
- .value_or(Color::black());
+ return Color::parse(value.get<std::string>());
}
template <>
-std::array<float, 2> IdentityStops<std::array<float, 2>>::evaluate(const Value& value) const {
+optional<std::array<float, 2>> IdentityStops<std::array<float, 2>>::evaluate(const Value& value) const {
if (!value.is<std::vector<Value>>()) {
- return {{ 0, 0 }};
+ return {};
}
const std::vector<Value>& vector = value.get<std::vector<Value>>();
if (vector.size() != 2 || !numericValue<float>(vector[0]) || !numericValue<float>(vector[1])) {
- return {{ 0, 0 }};
+ return {};
}
- return {{
+ return {{{
*numericValue<float>(vector[0]),
*numericValue<float>(vector[1])
- }};
+ }}};
}
} // namespace style
diff --git a/src/mbgl/style/layout_property.hpp b/src/mbgl/style/layout_property.hpp
index 7ce2ecc7b8..25cff4b92d 100644
--- a/src/mbgl/style/layout_property.hpp
+++ b/src/mbgl/style/layout_property.hpp
@@ -17,6 +17,7 @@ public:
using UnevaluatedType = PropertyValue<T>;
using EvaluatorType = PropertyEvaluator<T>;
using EvaluatedType = T;
+ using Type = T;
};
template <class T>
@@ -25,6 +26,7 @@ public:
using UnevaluatedType = DataDrivenPropertyValue<T>;
using EvaluatorType = DataDrivenPropertyEvaluator<T>;
using EvaluatedType = PossiblyEvaluatedPropertyValue<T>;
+ using Type = T;
};
template <class... Ps>
@@ -40,6 +42,15 @@ public:
class Evaluated : public Tuple<EvaluatedTypes> {
public:
using Tuple<EvaluatedTypes>::Tuple;
+
+ template <class P>
+ typename P::Type evaluate(float z, const GeometryTileFeature& feature) const {
+ using T = typename P::Type;
+ return this->template get<P>().match(
+ [&] (const T& t) { return t; },
+ [&] (const SourceFunction<T>& t) { return t.evaluate(feature, P::defaultValue()); },
+ [&] (const CompositeFunction<T>& t) { return t.evaluate(z, feature, P::defaultValue()); });
+ }
};
class Unevaluated : public Tuple<UnevaluatedTypes> {
diff --git a/src/mbgl/style/paint_property_binder.hpp b/src/mbgl/style/paint_property_binder.hpp
index 964f33d2ec..79c7692b2f 100644
--- a/src/mbgl/style/paint_property_binder.hpp
+++ b/src/mbgl/style/paint_property_binder.hpp
@@ -50,12 +50,13 @@ public:
using Attributes = gl::Attributes<Attribute>;
using Vertex = typename Attributes::Vertex;
- SourceFunctionPaintPropertyBinder(SourceFunction<T> function_)
- : function(std::move(function_)) {
+ SourceFunctionPaintPropertyBinder(SourceFunction<T> function_, T defaultValue_)
+ : function(std::move(function_)),
+ defaultValue(std::move(defaultValue_)) {
}
void populateVertexVector(const GeometryTileFeature& feature, std::size_t length) {
- AttributeValue value = Attribute::value(function.evaluate(feature));
+ AttributeValue value = Attribute::value(function.evaluate(feature, defaultValue));
for (std::size_t i = vertexVector.vertexSize(); i < length; ++i) {
vertexVector.emplace_back(Vertex { value });
}
@@ -86,6 +87,7 @@ public:
private:
SourceFunction<T> function;
+ T defaultValue;
gl::VertexVector<Vertex> vertexVector;
optional<gl::VertexBuffer<Vertex>> vertexBuffer;
};
@@ -103,13 +105,14 @@ public:
using Attributes = gl::Attributes<MinAttribute, MaxAttribute>;
using Vertex = typename Attributes::Vertex;
- CompositeFunctionPaintPropertyBinder(CompositeFunction<T> function_, float zoom)
+ CompositeFunctionPaintPropertyBinder(CompositeFunction<T> function_, float zoom, T defaultValue_)
: function(std::move(function_)),
+ defaultValue(std::move(defaultValue_)),
coveringRanges(function.coveringRanges(zoom)) {
}
void populateVertexVector(const GeometryTileFeature& feature, std::size_t length) {
- Range<T> range = function.evaluate(std::get<1>(coveringRanges), feature);
+ Range<T> range = function.evaluate(std::get<1>(coveringRanges), feature, defaultValue);
AttributeValue min = Attribute::value(range.min);
AttributeValue max = Attribute::value(range.max);
for (std::size_t i = vertexVector.vertexSize(); i < length; ++i) {
@@ -148,6 +151,7 @@ public:
private:
using InnerStops = typename CompositeFunction<T>::InnerStops;
CompositeFunction<T> function;
+ T defaultValue;
std::tuple<Range<float>, Range<InnerStops>> coveringRanges;
gl::VertexVector<Vertex> vertexVector;
optional<gl::VertexBuffer<Vertex>> vertexBuffer;
@@ -171,10 +175,10 @@ public:
return ConstantPaintPropertyBinder<Type, Attribute>(constant);
},
[&] (const SourceFunction<Type>& function) {
- return SourceFunctionPaintPropertyBinder<Type, Attribute>(function);
+ return SourceFunctionPaintPropertyBinder<Type, Attribute>(function, PaintProperty::defaultValue());
},
[&] (const CompositeFunction<Type>& function) {
- return CompositeFunctionPaintPropertyBinder<Type, Attribute>(function, zoom);
+ return CompositeFunctionPaintPropertyBinder<Type, Attribute>(function, zoom, PaintProperty::defaultValue());
}
)) {
}
diff --git a/src/mbgl/style/possibly_evaluated_property_value.hpp b/src/mbgl/style/possibly_evaluated_property_value.hpp
index bb917442f6..8c3f1780a6 100644
--- a/src/mbgl/style/possibly_evaluated_property_value.hpp
+++ b/src/mbgl/style/possibly_evaluated_property_value.hpp
@@ -43,13 +43,6 @@ public:
auto match(Ts&&... ts) const {
return value.match(std::forward<Ts>(ts)...);
}
-
- T evaluate(float z, const GeometryTileFeature& feature) const {
- return value.match(
- [&] (const T& t) { return t; },
- [&] (const SourceFunction<T>& t) { return t.evaluate(feature); },
- [&] (const CompositeFunction<T>& t) { return t.evaluate(z, feature); });
- }
};
} // namespace style
diff --git a/test/src/mbgl/test/stub_geometry_tile_feature.hpp b/test/src/mbgl/test/stub_geometry_tile_feature.hpp
new file mode 100644
index 0000000000..21d198a96b
--- /dev/null
+++ b/test/src/mbgl/test/stub_geometry_tile_feature.hpp
@@ -0,0 +1,34 @@
+#include <mbgl/tile/geometry_tile_data.hpp>
+#include <mbgl/util/feature.hpp>
+
+namespace mbgl {
+
+class StubGeometryTileFeature : public GeometryTileFeature {
+public:
+ StubGeometryTileFeature(PropertyMap properties_)
+ : properties(std::move(properties_)) {
+ }
+
+ PropertyMap properties;
+ optional<FeatureIdentifier> id = {};
+ FeatureType type = FeatureType::Point;
+ GeometryCollection geometry = {};
+
+ FeatureType getType() const override {
+ return type;
+ }
+
+ optional<FeatureIdentifier> getID() const override {
+ return id;
+ }
+
+ optional<Value> getValue(const std::string& key) const override {
+ return properties.count(key) ? properties.at(key) : optional<Value>();
+ }
+
+ GeometryCollection getGeometries() const override {
+ return geometry;
+ }
+};
+
+} // namespace mbgl
diff --git a/test/style/conversion/stringify.test.cpp b/test/style/conversion/stringify.test.cpp
index 6814563ceb..dd04789d4b 100644
--- a/test/style/conversion/stringify.test.cpp
+++ b/test/style/conversion/stringify.test.cpp
@@ -95,6 +95,8 @@ TEST(Stringify, SourceFunction) {
"{\"property\":\"property\",\"type\":\"categorical\",\"stops\":[[true,1.0]]}");
ASSERT_EQ(stringify(SourceFunction<float>("property", IdentityStops<float> {})),
"{\"property\":\"property\",\"type\":\"identity\"}");
+ ASSERT_EQ(stringify(SourceFunction<float>("property", IdentityStops<float> {}, 0.0f)),
+ "{\"property\":\"property\",\"type\":\"identity\",\"default\":0.0}");
}
TEST(Stringify, CompositeFunction) {
@@ -102,11 +104,11 @@ TEST(Stringify, CompositeFunction) {
std::map<float, ExponentialStops<float>> {
{ 0, ExponentialStops<float> { {{0, 1}}, 2 } },
{ 1, ExponentialStops<float> { {{0, 1}}, 2 } }
- })),
+ }, 0.0f)),
"{\"property\":\"property\",\"type\":\"exponential\",\"base\":2.0,"
"\"stops\":["
"[{\"zoom\":0.0,\"value\":0.0},1.0],"
- "[{\"zoom\":1.0,\"value\":0.0},1.0]]}");
+ "[{\"zoom\":1.0,\"value\":0.0},1.0]],\"default\":0.0}");
}
TEST(Stringify, PropertyValue) {
diff --git a/test/style/function/source_function.test.cpp b/test/style/function/source_function.test.cpp
new file mode 100644
index 0000000000..260620c8d0
--- /dev/null
+++ b/test/style/function/source_function.test.cpp
@@ -0,0 +1,94 @@
+#include <mbgl/test/util.hpp>
+#include <mbgl/test/stub_geometry_tile_feature.hpp>
+
+#include <mbgl/style/function/source_function.hpp>
+
+using namespace mbgl;
+using namespace mbgl::style;
+
+using namespace std::string_literals;
+
+static StubGeometryTileFeature oneInteger {
+ PropertyMap {{ "property", uint64_t(1) }}
+};
+
+static StubGeometryTileFeature oneDouble {
+ PropertyMap {{ "property", 1.0 }}
+};
+
+static StubGeometryTileFeature oneString {
+ PropertyMap {{ "property", "1"s }}
+};
+
+static StubGeometryTileFeature red {
+ PropertyMap {{ "property", "red"s }}
+};
+
+static StubGeometryTileFeature oneTwoInteger {
+ PropertyMap {{ "property", std::vector<Value>({uint64_t(1), uint64_t(2)}) }}
+};
+
+static StubGeometryTileFeature oneTwoDouble {
+ PropertyMap {{ "property", std::vector<Value>({1.0, 2.0}) }}
+};
+
+static StubGeometryTileFeature oneTwoString {
+ PropertyMap {{ "property", std::vector<Value>({"1"s, "2"s}) }}
+};
+
+static StubGeometryTileFeature trueFeature {
+ PropertyMap {{ "property", true }}
+};
+
+static StubGeometryTileFeature falseFeature {
+ PropertyMap {{ "property", false }}
+};
+
+TEST(SourceFunction, Identity) {
+ EXPECT_EQ(1.0f, SourceFunction<float>("property", IdentityStops<float>(), 0.0f)
+ .evaluate(oneInteger, 2.0f));
+ EXPECT_EQ(1.0f, SourceFunction<float>("property", IdentityStops<float>(), 0.0f)
+ .evaluate(oneDouble, 2.0f));
+ EXPECT_EQ(0.0f, SourceFunction<float>("property", IdentityStops<float>(), 0.0f)
+ .evaluate(oneString, 2.0f));
+ EXPECT_EQ(2.0f, SourceFunction<float>("property", IdentityStops<float>())
+ .evaluate(oneString, 2.0f));
+
+ EXPECT_EQ(Color::red(), SourceFunction<Color>("property", IdentityStops<Color>(), Color::black())
+ .evaluate(red, Color::black()));
+ EXPECT_EQ(Color::black(), SourceFunction<Color>("property", IdentityStops<Color>(), Color::black())
+ .evaluate(oneInteger, Color::black()));
+
+ std::array<float, 2> zeroArray {{ 0, 0 }};
+ EXPECT_EQ((std::array<float, 2> {{ 1, 2 }}), (SourceFunction<std::array<float, 2>>("property", IdentityStops<std::array<float, 2>>(), zeroArray)
+ .evaluate(oneTwoInteger, zeroArray)));
+ EXPECT_EQ((std::array<float, 2> {{ 1, 2 }}), (SourceFunction<std::array<float, 2>>("property", IdentityStops<std::array<float, 2>>(), zeroArray)
+ .evaluate(oneTwoDouble, zeroArray)));
+ EXPECT_EQ((std::array<float, 2> {{ 0, 0 }}), (SourceFunction<std::array<float, 2>>("property", IdentityStops<std::array<float, 2>>(), zeroArray)
+ .evaluate(oneTwoString, zeroArray)));
+}
+
+TEST(SourceFunction, Categorical) {
+ EXPECT_EQ(1.0f, SourceFunction<float>("property", CategoricalStops<float>({{ int64_t(1), 1.0f }}))
+ .evaluate(oneInteger, 0.0f));
+ EXPECT_EQ(1.0f, SourceFunction<float>("property", CategoricalStops<float>({{ int64_t(1), 1.0f }}))
+ .evaluate(oneDouble, 0.0f));
+ EXPECT_EQ(0.0f, SourceFunction<float>("property", CategoricalStops<float>({{ int64_t(1), 1.0f }}))
+ .evaluate(oneString, 0.0f));
+
+ EXPECT_EQ(0.0f, SourceFunction<float>("property", CategoricalStops<float>({{ "1"s, 1.0f }}))
+ .evaluate(oneInteger, 0.0f));
+ EXPECT_EQ(0.0f, SourceFunction<float>("property", CategoricalStops<float>({{ "1"s, 1.0f }}))
+ .evaluate(oneDouble, 0.0f));
+ EXPECT_EQ(1.0f, SourceFunction<float>("property", CategoricalStops<float>({{ "1"s, 1.0f }}))
+ .evaluate(oneString, 0.0f));
+
+ EXPECT_EQ(1.0f, SourceFunction<float>("property", CategoricalStops<float>({{ true, 1.0f }}))
+ .evaluate(trueFeature, 0.0f));
+ EXPECT_EQ(0.0f, SourceFunction<float>("property", CategoricalStops<float>({{ true, 1.0f }}))
+ .evaluate(falseFeature, 0.0f));
+ EXPECT_EQ(0.0f, SourceFunction<float>("property", CategoricalStops<float>({{ false, 1.0f }}))
+ .evaluate(trueFeature, 0.0f));
+ EXPECT_EQ(1.0f, SourceFunction<float>("property", CategoricalStops<float>({{ false, 1.0f }}))
+ .evaluate(falseFeature, 0.0f));
+}