[core] default value support in categorical function conversion
This commit is contained in:
committed by
John Firebaugh
parent
141e995806
commit
8a5bff8ee6
@@ -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
|
||||
|
||||
@@ -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" };
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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&) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
)) {
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
34
test/src/mbgl/test/stub_geometry_tile_feature.hpp
Normal file
34
test/src/mbgl/test/stub_geometry_tile_feature.hpp
Normal file
@@ -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
|
||||
@@ -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) {
|
||||
|
||||
94
test/style/function/source_function.test.cpp
Normal file
94
test/style/function/source_function.test.cpp
Normal file
@@ -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));
|
||||
}
|
||||
Reference in New Issue
Block a user