diff options
author | Ivo van Dongen <info@ivovandongen.nl> | 2017-01-31 15:44:18 +0200 |
---|---|---|
committer | John Firebaugh <john.firebaugh@gmail.com> | 2017-02-02 09:44:42 -0800 |
commit | 8a5bff8ee630673c6ebc496322eab94a41ae9353 (patch) | |
tree | 8bb6428cd9c3d591c237d77f94d4b0e56efb0ee0 | |
parent | 141e995806576364d185626176c1b993fc519291 (diff) | |
download | qtlocation-mapboxgl-8a5bff8ee630673c6ebc496322eab94a41ae9353.tar.gz |
[core] default value support in categorical function conversion
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)); +} |