summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/mbgl/annotation/annotation.hpp11
-rw-r--r--include/mbgl/gl/gl.hpp2
-rw-r--r--include/mbgl/map/backend.hpp17
-rw-r--r--include/mbgl/map/backend_scope.hpp18
-rw-r--r--include/mbgl/map/map.hpp38
-rw-r--r--include/mbgl/storage/default_file_source.hpp25
-rw-r--r--include/mbgl/storage/online_file_source.hpp6
-rw-r--r--include/mbgl/storage/response.hpp4
-rw-r--r--include/mbgl/style/conversion/data_driven_property_value.hpp46
-rw-r--r--include/mbgl/style/conversion/filter.hpp144
-rw-r--r--include/mbgl/style/conversion/function.hpp380
-rw-r--r--include/mbgl/style/conversion/make_property_setters.hpp58
-rw-r--r--include/mbgl/style/conversion/make_property_setters.hpp.ejs1
-rw-r--r--include/mbgl/style/conversion/property_setter.hpp26
-rw-r--r--include/mbgl/style/conversion/property_value.hpp2
-rw-r--r--include/mbgl/style/conversion/transition_options.hpp45
-rw-r--r--include/mbgl/style/data_driven_property_value.hpp56
-rw-r--r--include/mbgl/style/filter.hpp101
-rw-r--r--include/mbgl/style/filter_evaluator.hpp92
-rw-r--r--include/mbgl/style/function.hpp40
-rw-r--r--include/mbgl/style/function/camera_function.hpp41
-rw-r--r--include/mbgl/style/function/categorical_stops.hpp40
-rw-r--r--include/mbgl/style/function/composite_categorical_stops.hpp30
-rw-r--r--include/mbgl/style/function/composite_exponential_stops.hpp35
-rw-r--r--include/mbgl/style/function/composite_function.hpp116
-rw-r--r--include/mbgl/style/function/composite_interval_stops.hpp32
-rw-r--r--include/mbgl/style/function/exponential_stops.hpp54
-rw-r--r--include/mbgl/style/function/identity_stops.hpp20
-rw-r--r--include/mbgl/style/function/interval_stops.hpp49
-rw-r--r--include/mbgl/style/function/source_function.hpp59
-rw-r--r--include/mbgl/style/layers/background_layer.hpp6
-rw-r--r--include/mbgl/style/layers/circle_layer.hpp61
-rw-r--r--include/mbgl/style/layers/fill_extrusion_layer.hpp28
-rw-r--r--include/mbgl/style/layers/fill_layer.hpp28
-rw-r--r--include/mbgl/style/layers/layer.hpp.ejs16
-rw-r--r--include/mbgl/style/layers/line_layer.hpp43
-rw-r--r--include/mbgl/style/layers/raster_layer.hpp10
-rw-r--r--include/mbgl/style/layers/symbol_layer.hpp101
-rw-r--r--include/mbgl/style/property_value.hpp26
-rw-r--r--include/mbgl/style/undefined.hpp12
-rw-r--r--include/mbgl/util/chrono.hpp2
-rw-r--r--include/mbgl/util/compression.hpp4
-rw-r--r--include/mbgl/util/constants.hpp4
-rw-r--r--include/mbgl/util/feature.hpp17
-rw-r--r--include/mbgl/util/geo.hpp8
-rw-r--r--include/mbgl/util/image.hpp72
-rw-r--r--include/mbgl/util/size.hpp4
47 files changed, 1725 insertions, 305 deletions
diff --git a/include/mbgl/annotation/annotation.hpp b/include/mbgl/annotation/annotation.hpp
index a72c65b8c4..de83d24712 100644
--- a/include/mbgl/annotation/annotation.hpp
+++ b/include/mbgl/annotation/annotation.hpp
@@ -4,6 +4,7 @@
#include <mbgl/util/variant.hpp>
#include <mbgl/util/color.hpp>
#include <mbgl/style/property_value.hpp>
+#include <mbgl/style/data_driven_property_value.hpp>
#include <cstdint>
#include <vector>
@@ -29,17 +30,17 @@ using ShapeAnnotationGeometry = variant<
class LineAnnotation {
public:
ShapeAnnotationGeometry geometry;
- style::PropertyValue<float> opacity { 1.0f };
+ style::DataDrivenPropertyValue<float> opacity { 1.0f };
style::PropertyValue<float> width { 1.0f };
- style::PropertyValue<Color> color { Color::black() };
+ style::DataDrivenPropertyValue<Color> color { Color::black() };
};
class FillAnnotation {
public:
ShapeAnnotationGeometry geometry;
- style::PropertyValue<float> opacity { 1.0f };
- style::PropertyValue<Color> color { Color::black() };
- style::PropertyValue<Color> outlineColor {};
+ style::DataDrivenPropertyValue<float> opacity { 1.0f };
+ style::DataDrivenPropertyValue<Color> color { Color::black() };
+ style::DataDrivenPropertyValue<Color> outlineColor {};
};
// An annotation whose type and properties are sourced from a style layer.
diff --git a/include/mbgl/gl/gl.hpp b/include/mbgl/gl/gl.hpp
index 425f78bcba..7521b4c80d 100644
--- a/include/mbgl/gl/gl.hpp
+++ b/include/mbgl/gl/gl.hpp
@@ -41,7 +41,7 @@ struct Error : std::runtime_error {
void checkError(const char *cmd, const char *file, int line);
#ifndef NDEBUG
-#define MBGL_CHECK_ERROR(cmd) ([&]() { struct __MBGL_C_E { ~__MBGL_C_E() { ::mbgl::gl::checkError(#cmd, __FILE__, __LINE__); } } __MBGL_C_E; return cmd; }())
+#define MBGL_CHECK_ERROR(cmd) ([&]() { struct __MBGL_C_E { ~__MBGL_C_E() noexcept(false) { ::mbgl::gl::checkError(#cmd, __FILE__, __LINE__); } } __MBGL_C_E; return cmd; }())
#else
#define MBGL_CHECK_ERROR(cmd) (cmd)
#endif
diff --git a/include/mbgl/map/backend.hpp b/include/mbgl/map/backend.hpp
index 0468449155..4a43921c0b 100644
--- a/include/mbgl/map/backend.hpp
+++ b/include/mbgl/map/backend.hpp
@@ -41,24 +41,9 @@ protected:
virtual void activate() = 0;
virtual void deactivate() = 0;
-private:
- const std::unique_ptr<gl::Context> context;
+ std::unique_ptr<gl::Context> context;
friend class BackendScope;
};
-class BackendScope {
-public:
- BackendScope(Backend& backend_) : backend(backend_) {
- backend.activate();
- }
-
- ~BackendScope() {
- backend.deactivate();
- }
-
-private:
- Backend& backend;
-};
-
} // namespace mbgl
diff --git a/include/mbgl/map/backend_scope.hpp b/include/mbgl/map/backend_scope.hpp
new file mode 100644
index 0000000000..5a207e6ac4
--- /dev/null
+++ b/include/mbgl/map/backend_scope.hpp
@@ -0,0 +1,18 @@
+#pragma once
+
+namespace mbgl {
+
+class Backend;
+
+class BackendScope {
+public:
+ BackendScope(Backend&);
+ ~BackendScope();
+
+private:
+ BackendScope* priorScope;
+ BackendScope* nextScope;
+ Backend& backend;
+};
+
+} // namespace mbgl
diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp
index c80420371d..95a82ebd74 100644
--- a/include/mbgl/map/map.hpp
+++ b/include/mbgl/map/map.hpp
@@ -9,6 +9,7 @@
#include <mbgl/util/size.hpp>
#include <mbgl/annotation/annotation.hpp>
#include <mbgl/style/transition_options.hpp>
+#include <mbgl/map/camera.hpp>
#include <cstdint>
#include <string>
@@ -86,22 +87,23 @@ public:
void flyTo(const CameraOptions&, const AnimationOptions&);
// Position
- void moveBy(const ScreenCoordinate&, const Duration& = Duration::zero());
- void setLatLng(const LatLng&, optional<ScreenCoordinate>, const Duration& = Duration::zero());
- void setLatLng(const LatLng&, optional<EdgeInsets>, const Duration& = Duration::zero());
- void setLatLng(const LatLng&, const Duration& = Duration::zero());
+ void moveBy(const ScreenCoordinate&, const AnimationOptions& = {});
+ void setLatLng(const LatLng&, optional<ScreenCoordinate>, const AnimationOptions& = {});
+ void setLatLng(const LatLng&, optional<EdgeInsets>, const AnimationOptions& = {});
+ void setLatLng(const LatLng&, const AnimationOptions& = {});
LatLng getLatLng(optional<EdgeInsets> = {}) const;
void resetPosition(optional<EdgeInsets> = {});
// Scale
- void scaleBy(double ds, optional<ScreenCoordinate> = {}, const Duration& = Duration::zero());
- void setScale(double scale, optional<ScreenCoordinate> = {}, const Duration& = Duration::zero());
+ void scaleBy(double ds, optional<ScreenCoordinate> = {}, const AnimationOptions& = {});
+ void setScale(double scale, optional<ScreenCoordinate> = {}, const AnimationOptions& = {});
double getScale() const;
- void setZoom(double zoom, const Duration& = Duration::zero());
- void setZoom(double zoom, optional<EdgeInsets>, const Duration& = Duration::zero());
+ void setZoom(double zoom, const AnimationOptions& = {});
+ void setZoom(double zoom, optional<ScreenCoordinate>, const AnimationOptions& = {});
+ void setZoom(double zoom, optional<EdgeInsets>, const AnimationOptions& = {});
double getZoom() const;
- void setLatLngZoom(const LatLng&, double zoom, const Duration& = Duration::zero());
- void setLatLngZoom(const LatLng&, double zoom, optional<EdgeInsets>, const Duration& = Duration::zero());
+ void setLatLngZoom(const LatLng&, double zoom, const AnimationOptions& = {});
+ void setLatLngZoom(const LatLng&, double zoom, optional<EdgeInsets>, const AnimationOptions& = {});
CameraOptions cameraForLatLngBounds(const LatLngBounds&, optional<EdgeInsets>) const;
CameraOptions cameraForLatLngs(const std::vector<LatLng>&, optional<EdgeInsets>) const;
void resetZoom();
@@ -111,17 +113,17 @@ public:
double getMaxZoom() const;
// Rotation
- void rotateBy(const ScreenCoordinate& first, const ScreenCoordinate& second, const Duration& = Duration::zero());
- void setBearing(double degrees, const Duration& = Duration::zero());
- void setBearing(double degrees, optional<ScreenCoordinate>, const Duration& = Duration::zero());
- void setBearing(double degrees, optional<EdgeInsets>, const Duration& = Duration::zero());
+ void rotateBy(const ScreenCoordinate& first, const ScreenCoordinate& second, const AnimationOptions& = {});
+ void setBearing(double degrees, const AnimationOptions& = {});
+ void setBearing(double degrees, optional<ScreenCoordinate>, const AnimationOptions& = {});
+ void setBearing(double degrees, optional<EdgeInsets>, const AnimationOptions& = {});
double getBearing() const;
- void resetNorth(const Duration& = Milliseconds(500));
- void resetNorth(optional<EdgeInsets>, const Duration& = Milliseconds(500));
+ void resetNorth(const AnimationOptions& = {{mbgl::Milliseconds(500)}});
+ void resetNorth(optional<EdgeInsets>, const AnimationOptions& = {{mbgl::Milliseconds(500)}});
// Pitch
- void setPitch(double pitch, const Duration& = Duration::zero());
- void setPitch(double pitch, optional<ScreenCoordinate>, const Duration& = Duration::zero());
+ void setPitch(double pitch, const AnimationOptions& = {});
+ void setPitch(double pitch, optional<ScreenCoordinate>, const AnimationOptions& = {});
double getPitch() const;
// North Orientation
diff --git a/include/mbgl/storage/default_file_source.hpp b/include/mbgl/storage/default_file_source.hpp
index b8f5e1167e..9262e0a1bc 100644
--- a/include/mbgl/storage/default_file_source.hpp
+++ b/include/mbgl/storage/default_file_source.hpp
@@ -29,13 +29,15 @@ public:
bool supportsOptionalRequests() const override {
return true;
}
-
+
void setAPIBaseURL(const std::string&);
std::string getAPIBaseURL() const;
void setAccessToken(const std::string&);
std::string getAccessToken() const;
+ void setResourceTransform(std::function<std::string(Resource::Kind, std::string&&)>);
+
std::unique_ptr<AsyncRequest> request(const Resource&, Callback) override;
/*
@@ -113,6 +115,25 @@ public:
*/
void setOfflineMapboxTileCountLimit(uint64_t) const;
+ /*
+ * Pause file request activity.
+ *
+ * If pause is called then no revalidation or network request activity
+ * will occur.
+ *
+ * Note: Calling pause and then calling getAPIBaseURL or getAccessToken
+ * will lock the thread that those calls are made on.
+ */
+ void pause();
+
+ /*
+ * Resume file request activity.
+ *
+ * Calling resume will unpause the file source and process any tasks that
+ * expired while the file source was paused.
+ */
+ void resume();
+
// For testing only.
void put(const Resource&, const Response&);
@@ -122,6 +143,8 @@ private:
const std::unique_ptr<util::Thread<Impl>> thread;
const std::unique_ptr<FileSource> assetFileSource;
const std::unique_ptr<FileSource> localFileSource;
+ std::string cachedBaseURL = mbgl::util::API_BASE_URL;
+ std::string cachedAccessToken;
};
} // namespace mbgl
diff --git a/include/mbgl/storage/online_file_source.hpp b/include/mbgl/storage/online_file_source.hpp
index 9c7feceb47..51cfc5a2a1 100644
--- a/include/mbgl/storage/online_file_source.hpp
+++ b/include/mbgl/storage/online_file_source.hpp
@@ -12,10 +12,14 @@ public:
void setAPIBaseURL(const std::string& t) { apiBaseURL = t; }
std::string getAPIBaseURL() const { return apiBaseURL; }
-
+
void setAccessToken(const std::string& t) { accessToken = t; }
std::string getAccessToken() const { return accessToken; }
+ using ResourceTransform =
+ std::function<std::unique_ptr<AsyncRequest>(Resource::Kind, std::string&&, std::function<void(std::string&&)>)>;
+ void setResourceTransform(ResourceTransform&& cb);
+
std::unique_ptr<AsyncRequest> request(const Resource&, Callback) override;
private:
diff --git a/include/mbgl/storage/response.hpp b/include/mbgl/storage/response.hpp
index 448423c1cb..32fe4e0c8a 100644
--- a/include/mbgl/storage/response.hpp
+++ b/include/mbgl/storage/response.hpp
@@ -35,7 +35,7 @@ public:
optional<std::string> etag;
bool isFresh() const {
- return !expires || *expires > util::now();
+ return expires ? *expires > util::now() : !error;
}
};
@@ -53,7 +53,7 @@ public:
// An error message from the request handler, e.g. a server message or a system message
// informing the user about the reason for the failure.
std::string message;
-
+
optional<Timestamp> retryAfter;
public:
diff --git a/include/mbgl/style/conversion/data_driven_property_value.hpp b/include/mbgl/style/conversion/data_driven_property_value.hpp
new file mode 100644
index 0000000000..83f44fdb27
--- /dev/null
+++ b/include/mbgl/style/conversion/data_driven_property_value.hpp
@@ -0,0 +1,46 @@
+#pragma once
+
+#include <mbgl/style/data_driven_property_value.hpp>
+#include <mbgl/style/conversion.hpp>
+#include <mbgl/style/conversion/constant.hpp>
+#include <mbgl/style/conversion/function.hpp>
+
+namespace mbgl {
+namespace style {
+namespace conversion {
+
+template <class T>
+struct Converter<DataDrivenPropertyValue<T>> {
+ template <class V>
+ Result<DataDrivenPropertyValue<T>> operator()(const V& value) const {
+ if (isUndefined(value)) {
+ return {};
+ } else if (!isObject(value)) {
+ Result<T> constant = convert<T>(value);
+ if (!constant) {
+ return constant.error();
+ }
+ return DataDrivenPropertyValue<T>(*constant);
+ } else if (!objectMember(value, "property")) {
+ Result<CameraFunction<T>> function = convert<CameraFunction<T>>(value);
+ if (!function) {
+ return function.error();
+ }
+ return DataDrivenPropertyValue<T>(*function);
+ } else {
+ Result<CompositeFunction<T>> composite = convert<CompositeFunction<T>>(value);
+ if (composite) {
+ return DataDrivenPropertyValue<T>(*composite);
+ }
+ Result<SourceFunction<T>> source = convert<SourceFunction<T>>(value);
+ if (!source) {
+ return source.error();
+ }
+ return DataDrivenPropertyValue<T>(*source);
+ }
+ }
+};
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/conversion/filter.hpp b/include/mbgl/style/conversion/filter.hpp
index 3ab91e5bbc..2c4eeb4ac7 100644
--- a/include/mbgl/style/conversion/filter.hpp
+++ b/include/mbgl/style/conversion/filter.hpp
@@ -27,9 +27,9 @@ public:
}
if (*op == "==") {
- return convertBinaryFilter<EqualsFilter>(value);
+ return convertEqualityFilter<EqualsFilter, TypeEqualsFilter, IdentifierEqualsFilter>(value);
} else if (*op == "!=") {
- return convertBinaryFilter<NotEqualsFilter>(value);
+ return convertEqualityFilter<NotEqualsFilter, TypeNotEqualsFilter, IdentifierNotEqualsFilter>(value);
} else if (*op == ">") {
return convertBinaryFilter<GreaterThanFilter>(value);
} else if (*op == ">=") {
@@ -39,9 +39,9 @@ public:
} else if (*op == "<=") {
return convertBinaryFilter<LessThanEqualsFilter>(value);
} else if (*op == "in") {
- return convertSetFilter<InFilter>(value);
+ return convertSetFilter<InFilter, TypeInFilter, IdentifierInFilter>(value);
} else if (*op == "!in") {
- return convertSetFilter<NotInFilter>(value);
+ return convertSetFilter<NotInFilter, TypeNotInFilter, IdentifierNotInFilter>(value);
} else if (*op == "all") {
return convertCompoundFilter<AllFilter>(value);
} else if (*op == "any") {
@@ -49,32 +49,57 @@ public:
} else if (*op == "none") {
return convertCompoundFilter<NoneFilter>(value);
} else if (*op == "has") {
- return convertUnaryFilter<HasFilter>(value);
+ return convertUnaryFilter<HasFilter, HasIdentifierFilter>(value);
} else if (*op == "!has") {
- return convertUnaryFilter<NotHasFilter>(value);
+ return convertUnaryFilter<NotHasFilter, NotHasIdentifierFilter>(value);
}
return Error { "filter operator must be one of \"==\", \"!=\", \">\", \">=\", \"<\", \"<=\", \"in\", \"!in\", \"all\", \"any\", \"none\", \"has\", or \"!has\"" };
}
private:
- Result<Value> normalizeValue(const std::string& key, const optional<Value>& value) const {
+ Result<Value> normalizeValue(const optional<Value>& value) const {
if (!value) {
return Error { "filter expression value must be a boolean, number, or string" };
- } else if (key != "$type") {
+ } else {
return *value;
- } else if (*value == std::string("Point")) {
- return Value(uint64_t(FeatureType::Point));
- } else if (*value == std::string("LineString")) {
- return Value(uint64_t(FeatureType::LineString));
- } else if (*value == std::string("Polygon")) {
- return Value(uint64_t(FeatureType::Polygon));
+ }
+ }
+
+ template <class V>
+ Result<FeatureType> toFeatureType(const V& value) const {
+ optional<std::string> type = toString(value);
+ if (!type) {
+ return Error { "value for $type filter must be a string" };
+ } else if (*type == "Point") {
+ return FeatureType::Point;
+ } else if (*type == "LineString") {
+ return FeatureType::LineString;
+ } else if (*type == "Polygon") {
+ return FeatureType::Polygon;
} else {
return Error { "value for $type filter must be Point, LineString, or Polygon" };
}
}
- template <class FilterType, class V>
+ template <class V>
+ Result<FeatureIdentifier> toFeatureIdentifier(const V& value) const {
+ optional<Value> identifier = toValue(value);
+ if (!identifier) {
+ return Error { "filter expression value must be a boolean, number, or string" };
+ } else {
+ return (*identifier).match(
+ [] (uint64_t t) -> Result<FeatureIdentifier> { return t; },
+ [] ( int64_t t) -> Result<FeatureIdentifier> { return t; },
+ [] ( double t) -> Result<FeatureIdentifier> { return t; },
+ [] (const std::string& t) -> Result<FeatureIdentifier> { return t; },
+ [] (const auto&) -> Result<FeatureIdentifier> {
+ return Error { "filter expression value must be a boolean, number, or string" };
+ });
+ }
+ }
+
+ template <class FilterType, class IdentifierFilterType, class V>
Result<Filter> convertUnaryFilter(const V& value) const {
if (arrayLength(value) < 2) {
return Error { "filter expression must have 2 elements" };
@@ -85,7 +110,48 @@ private:
return Error { "filter expression key must be a string" };
}
- return FilterType { *key };
+ if (*key == "$id") {
+ return IdentifierFilterType {};
+ } else {
+ return FilterType { *key };
+ }
+ }
+
+ template <class FilterType, class TypeFilterType, class IdentifierFilterType, class V>
+ Result<Filter> convertEqualityFilter(const V& value) const {
+ if (arrayLength(value) < 3) {
+ return Error { "filter expression must have 3 elements" };
+ }
+
+ optional<std::string> key = toString(arrayMember(value, 1));
+ if (!key) {
+ return Error { "filter expression key must be a string" };
+ }
+
+ if (*key == "$type") {
+ Result<FeatureType> filterValue = toFeatureType(arrayMember(value, 2));
+ if (!filterValue) {
+ return filterValue.error();
+ }
+
+ return TypeFilterType { *filterValue };
+
+ } else if (*key == "$id") {
+ Result<FeatureIdentifier> filterValue = toFeatureIdentifier(arrayMember(value, 2));
+ if (!filterValue) {
+ return filterValue.error();
+ }
+
+ return IdentifierFilterType { *filterValue };
+
+ } else {
+ Result<Value> filterValue = normalizeValue(toValue(arrayMember(value, 2)));
+ if (!filterValue) {
+ return filterValue.error();
+ }
+
+ return FilterType { *key, *filterValue };
+ }
}
template <class FilterType, class V>
@@ -99,7 +165,7 @@ private:
return Error { "filter expression key must be a string" };
}
- Result<Value> filterValue = normalizeValue(*key, toValue(arrayMember(value, 2)));
+ Result<Value> filterValue = normalizeValue(toValue(arrayMember(value, 2)));
if (!filterValue) {
return filterValue.error();
}
@@ -107,7 +173,7 @@ private:
return FilterType { *key, *filterValue };
}
- template <class FilterType, class V>
+ template <class FilterType, class TypeFilterType, class IdentifierFilterType, class V>
Result<Filter> convertSetFilter(const V& value) const {
if (arrayLength(value) < 2) {
return Error { "filter expression must at least 2 elements" };
@@ -118,16 +184,42 @@ private:
return Error { "filter expression key must be a string" };
}
- std::vector<Value> values;
- for (std::size_t i = 2; i < arrayLength(value); ++i) {
- Result<Value> filterValue = normalizeValue(*key, toValue(arrayMember(value, i)));
- if (!filterValue) {
- return filterValue.error();
+ if (*key == "$type") {
+ std::vector<FeatureType> values;
+ for (std::size_t i = 2; i < arrayLength(value); ++i) {
+ Result<FeatureType> filterValue = toFeatureType(arrayMember(value, i));
+ if (!filterValue) {
+ return filterValue.error();
+ }
+ values.push_back(*filterValue);
}
- values.push_back(*filterValue);
- }
- return FilterType { *key, std::move(values) };
+ return TypeFilterType { std::move(values) };
+
+ } else if (*key == "$id") {
+ std::vector<FeatureIdentifier> values;
+ for (std::size_t i = 2; i < arrayLength(value); ++i) {
+ Result<FeatureIdentifier> filterValue = toFeatureIdentifier(arrayMember(value, i));
+ if (!filterValue) {
+ return filterValue.error();
+ }
+ values.push_back(*filterValue);
+ }
+
+ return IdentifierFilterType { std::move(values) };
+
+ } else {
+ std::vector<Value> values;
+ for (std::size_t i = 2; i < arrayLength(value); ++i) {
+ Result<Value> filterValue = normalizeValue(toValue(arrayMember(value, i)));
+ if (!filterValue) {
+ return filterValue.error();
+ }
+ values.push_back(*filterValue);
+ }
+
+ return FilterType { *key, std::move(values) };
+ }
}
template <class FilterType, class V>
diff --git a/include/mbgl/style/conversion/function.hpp b/include/mbgl/style/conversion/function.hpp
index 6a0b67618f..a5979e6799 100644
--- a/include/mbgl/style/conversion/function.hpp
+++ b/include/mbgl/style/conversion/function.hpp
@@ -1,70 +1,382 @@
#pragma once
-#include <mbgl/style/function.hpp>
+#include <mbgl/style/function/camera_function.hpp>
+#include <mbgl/style/function/source_function.hpp>
+#include <mbgl/style/function/composite_function.hpp>
#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/constant.hpp>
+#include <mbgl/util/ignore.hpp>
namespace mbgl {
namespace style {
namespace conversion {
+template <class D, class R, class V>
+Result<std::map<D, R>> convertStops(const V& value) {
+ auto stopsValue = objectMember(value, "stops");
+ if (!stopsValue) {
+ return Error { "function value must specify stops" };
+ }
+
+ if (!isArray(*stopsValue)) {
+ return Error { "function stops must be an array" };
+ }
+
+ if (arrayLength(*stopsValue) == 0) {
+ return Error { "function must have at least one stop" };
+ }
+
+ std::map<D, R> stops;
+ for (std::size_t i = 0; i < arrayLength(*stopsValue); ++i) {
+ const auto& stopValue = arrayMember(*stopsValue, i);
+
+ if (!isArray(stopValue)) {
+ return Error { "function stop must be an array" };
+ }
+
+ if (arrayLength(stopValue) != 2) {
+ return Error { "function stop must have two elements" };
+ }
+
+ Result<D> d = convert<D>(arrayMember(stopValue, 0));
+ if (!d) {
+ return d.error();
+ }
+
+ Result<R> r = convert<R>(arrayMember(stopValue, 1));
+ if (!r) {
+ return r.error();
+ }
+
+ stops.emplace(*d, *r);
+ }
+
+ return stops;
+}
+
+template <class T>
+struct Converter<ExponentialStops<T>> {
+ static constexpr const char * type = "exponential";
+
+ template <class V>
+ Result<ExponentialStops<T>> operator()(const V& value) const {
+ auto stops = convertStops<float, T>(value);
+ if (!stops) {
+ return stops.error();
+ }
+
+ auto baseValue = objectMember(value, "base");
+ if (!baseValue) {
+ return ExponentialStops<T>(*stops);
+ }
+
+ optional<float> base = toNumber(*baseValue);
+ if (!base) {
+ return Error { "function base must be a number"};
+ }
+
+ return ExponentialStops<T>(*stops, *base);
+ }
+};
+
+template <class T>
+struct Converter<IntervalStops<T>> {
+ static constexpr const char * type = "interval";
+
+ template <class V>
+ Result<IntervalStops<T>> operator()(const V& value) const {
+ auto stops = convertStops<float, T>(value);
+ if (!stops) {
+ return stops.error();
+ }
+ return IntervalStops<T>(*stops);
+ }
+};
+
+template <>
+struct Converter<CategoricalValue> {
+ template <class V>
+ Result<CategoricalValue> operator()(const V& value) const {
+ auto b = toBool(value);
+ if (b) {
+ return *b;
+ }
+
+ auto n = toNumber(value);
+ if (n) {
+ return int64_t(*n);
+ }
+
+ auto s = toString(value);
+ if (s) {
+ return *s;
+ }
+
+ return Error { "stop domain value must be a number, string, or boolean" };
+ }
+};
+
+template <class T>
+struct Converter<CategoricalStops<T>> {
+ static constexpr const char * type = "categorical";
+
+ template <class V>
+ Result<CategoricalStops<T>> operator()(const V& value) const {
+ auto stops = convertStops<CategoricalValue, T>(value);
+ if (!stops) {
+ return stops.error();
+ }
+ return CategoricalStops<T>(
+ std::map<CategoricalValue, T>((*stops).begin(), (*stops).end()));
+ }
+};
+
+template <class T>
+struct Converter<IdentityStops<T>> {
+ static constexpr const char * type = "identity";
+
+ template <class V>
+ Result<IdentityStops<T>> operator()(const V&) const {
+ return IdentityStops<T>();
+ }
+};
+
+template <class, class>
+struct StopsConverter;
+
+template <class T, class... Ts>
+struct StopsConverter<T, variant<Ts...>> {
+public:
+ template <class V>
+ Result<variant<Ts...>> operator()(const V& value) const {
+ std::string type = util::Interpolatable<T> ? "exponential" : "interval";
+
+ auto typeValue = objectMember(value, "type");
+ if (typeValue && toString(*typeValue)) {
+ type = *toString(*typeValue);
+ }
+
+ optional<Result<variant<Ts...>>> result;
+
+ // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47226
+ auto tryConvert = [&] (auto* tp) {
+ using Stops = std::decay_t<decltype(*tp)>;
+ if (type == Converter<Stops>::type) {
+ auto stops = convert<Stops>(value);
+ result = stops
+ ? Result<variant<Ts...>>(*stops)
+ : Result<variant<Ts...>>(stops.error());
+ }
+ };
+
+ util::ignore({
+ (tryConvert((Ts*)nullptr), 0)...
+ });
+
+ if (!result) {
+ return Error { "unsupported function type" };
+ }
+
+ return *result;
+ }
+};
+
+template <class T>
+struct Converter<CameraFunction<T>> {
+ template <class V>
+ Result<CameraFunction<T>> operator()(const V& value) const {
+ if (!isObject(value)) {
+ return Error { "function must be an object" };
+ }
+
+ auto stops = StopsConverter<T, typename CameraFunction<T>::Stops>()(value);
+ if (!stops) {
+ return stops.error();
+ }
+
+ return CameraFunction<T>(*stops);
+ }
+};
+
+template <class T, class V>
+Result<optional<T>> convertDefaultValue(const V& value) {
+ auto defaultValueValue = objectMember(value, "default");
+ 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<Function<T>> {
+struct Converter<SourceFunction<T>> {
template <class V>
- Result<Function<T>> operator()(const V& value) const {
+ Result<SourceFunction<T>> operator()(const V& value) const {
if (!isObject(value)) {
return Error { "function must be an object" };
}
- auto stopsValue = objectMember(value, "stops");
- if (!stopsValue) {
- return Error { "function value must specify stops" };
+ auto propertyValue = objectMember(value, "property");
+ if (!propertyValue) {
+ return Error { "function must specify property" };
}
- if (!isArray(*stopsValue)) {
- return Error { "function stops must be an array" };
+ auto propertyString = toString(*propertyValue);
+ if (!propertyString) {
+ return Error { "function property must be a string" };
}
- if (arrayLength(*stopsValue) == 0) {
- return Error { "function must have at least one stop" };
+ auto stops = StopsConverter<T, typename SourceFunction<T>::Stops>()(value);
+ if (!stops) {
+ return stops.error();
}
- std::vector<std::pair<float, T>> stops;
- for (std::size_t i = 0; i < arrayLength(*stopsValue); ++i) {
- const auto& stopValue = arrayMember(*stopsValue, i);
+ auto defaultValue = convertDefaultValue<T>(value);
+ if (!defaultValue) {
+ return defaultValue.error();
+ }
- if (!isArray(stopValue)) {
- return Error { "function stop must be an array" };
- }
+ return SourceFunction<T>(*propertyString, *stops, *defaultValue);
+ }
+};
- if (arrayLength(stopValue) != 2) {
- return Error { "function stop must have two elements" };
- }
+template <class S>
+struct CompositeValue : std::pair<float, S> {
+ using std::pair<float, S>::pair;
+};
- optional<float> z = toNumber(arrayMember(stopValue, 0));
- if (!z) {
- return Error { "function stop zoom level must be a number" };
- }
+template <class S>
+struct Converter<CompositeValue<S>> {
+ template <class V>
+ Result<CompositeValue<S>> operator()(const V& value) const {
+ if (!isObject(value)) {
+ return Error { "stop must be an object" };
+ }
- Result<T> v = convert<T>(arrayMember(stopValue, 1));
- if (!v) {
- return v.error();
- }
+ auto zoomValue = objectMember(value, "zoom");
+ if (!zoomValue) {
+ return Error { "stop must specify zoom" };
+ }
+
+ auto propertyValue = objectMember(value, "value");
+ if (!propertyValue) {
+ return Error { "stop must specify value" };
+ }
+
+ Result<float> z = convert<float>(*zoomValue);
+ if (!z) {
+ return z.error();
+ }
+
+ Result<S> s = convert<S>(*propertyValue);
+ if (!s) {
+ return s.error();
+ }
+
+ return CompositeValue<S> { *z, *s };
+ }
+};
+
+template <class T>
+struct Converter<CompositeExponentialStops<T>> {
+ static constexpr const char * type = "exponential";
- stops.emplace_back(*z, *v);
+ template <class V>
+ Result<CompositeExponentialStops<T>> operator()(const V& value) const {
+ auto stops = convertStops<CompositeValue<float>, T>(value);
+ if (!stops) {
+ return stops.error();
}
+ auto base = 1.0f;
auto baseValue = objectMember(value, "base");
- if (!baseValue) {
- return Function<T>(stops, 1.0f);
+ if (baseValue && toNumber(*baseValue)) {
+ base = *toNumber(*baseValue);
}
- optional<float> base = toNumber(*baseValue);
- if (!base) {
- return Error { "function base must be a number"};
+ std::map<float, std::map<float, T>> convertedStops;
+ for (const auto& stop : *stops) {
+ convertedStops[stop.first.first].emplace(stop.first.second, stop.second);
+ }
+
+ return CompositeExponentialStops<T>(convertedStops, base);
+ }
+};
+
+template <class T>
+struct Converter<CompositeIntervalStops<T>> {
+ static constexpr const char * type = "interval";
+
+ template <class V>
+ Result<CompositeIntervalStops<T>> operator()(const V& value) const {
+ auto stops = convertStops<CompositeValue<float>, T>(value);
+ if (!stops) {
+ return stops.error();
+ }
+
+ std::map<float, std::map<float, T>> convertedStops;
+ for (const auto& stop : *stops) {
+ convertedStops[stop.first.first].emplace(stop.first.second, stop.second);
+ }
+
+ return CompositeIntervalStops<T>(convertedStops);
+ }
+};
+
+template <class T>
+struct Converter<CompositeCategoricalStops<T>> {
+ static constexpr const char * type = "categorical";
+
+ template <class V>
+ Result<CompositeCategoricalStops<T>> operator()(const V& value) const {
+ auto stops = convertStops<CompositeValue<CategoricalValue>, T>(value);
+ if (!stops) {
+ return stops.error();
+ }
+
+ std::map<float, std::map<CategoricalValue, T>> convertedStops;
+ for (const auto& stop : *stops) {
+ convertedStops[stop.first.first].emplace(stop.first.second, stop.second);
+ }
+
+ return CompositeCategoricalStops<T>(convertedStops);
+ }
+};
+
+template <class T>
+struct Converter<CompositeFunction<T>> {
+ template <class V>
+ Result<CompositeFunction<T>> operator()(const V& value) const {
+ if (!isObject(value)) {
+ return Error { "function must be an object" };
+ }
+
+ auto propertyValue = objectMember(value, "property");
+ if (!propertyValue) {
+ return Error { "function must specify property" };
+ }
+
+ auto propertyString = toString(*propertyValue);
+ if (!propertyString) {
+ return Error { "function property must be a string" };
+ }
+
+ auto stops = StopsConverter<T, typename CompositeFunction<T>::Stops>()(value);
+ if (!stops) {
+ return stops.error();
+ }
+
+ auto defaultValue = convertDefaultValue<T>(value);
+ if (!defaultValue) {
+ return defaultValue.error();
}
- return Function<T>(stops, *base);
+ return CompositeFunction<T>(*propertyString, *stops, *defaultValue);
}
};
diff --git a/include/mbgl/style/conversion/make_property_setters.hpp b/include/mbgl/style/conversion/make_property_setters.hpp
index e30359937e..32fa810f0b 100644
--- a/include/mbgl/style/conversion/make_property_setters.hpp
+++ b/include/mbgl/style/conversion/make_property_setters.hpp
@@ -77,69 +77,127 @@ auto makePaintPropertySetters() {
std::unordered_map<std::string, PaintPropertySetter<V>> result;
result["fill-antialias"] = makePropertySetter<V>(&FillLayer::setFillAntialias);
+ result["fill-antialias-transition"] = makeTransitionSetter<V>(&FillLayer::setFillAntialiasTransition);
result["fill-opacity"] = makePropertySetter<V>(&FillLayer::setFillOpacity);
+ result["fill-opacity-transition"] = makeTransitionSetter<V>(&FillLayer::setFillOpacityTransition);
result["fill-color"] = makePropertySetter<V>(&FillLayer::setFillColor);
+ result["fill-color-transition"] = makeTransitionSetter<V>(&FillLayer::setFillColorTransition);
result["fill-outline-color"] = makePropertySetter<V>(&FillLayer::setFillOutlineColor);
+ result["fill-outline-color-transition"] = makeTransitionSetter<V>(&FillLayer::setFillOutlineColorTransition);
result["fill-translate"] = makePropertySetter<V>(&FillLayer::setFillTranslate);
+ result["fill-translate-transition"] = makeTransitionSetter<V>(&FillLayer::setFillTranslateTransition);
result["fill-translate-anchor"] = makePropertySetter<V>(&FillLayer::setFillTranslateAnchor);
+ result["fill-translate-anchor-transition"] = makeTransitionSetter<V>(&FillLayer::setFillTranslateAnchorTransition);
result["fill-pattern"] = makePropertySetter<V>(&FillLayer::setFillPattern);
+ result["fill-pattern-transition"] = makeTransitionSetter<V>(&FillLayer::setFillPatternTransition);
result["line-opacity"] = makePropertySetter<V>(&LineLayer::setLineOpacity);
+ result["line-opacity-transition"] = makeTransitionSetter<V>(&LineLayer::setLineOpacityTransition);
result["line-color"] = makePropertySetter<V>(&LineLayer::setLineColor);
+ result["line-color-transition"] = makeTransitionSetter<V>(&LineLayer::setLineColorTransition);
result["line-translate"] = makePropertySetter<V>(&LineLayer::setLineTranslate);
+ result["line-translate-transition"] = makeTransitionSetter<V>(&LineLayer::setLineTranslateTransition);
result["line-translate-anchor"] = makePropertySetter<V>(&LineLayer::setLineTranslateAnchor);
+ result["line-translate-anchor-transition"] = makeTransitionSetter<V>(&LineLayer::setLineTranslateAnchorTransition);
result["line-width"] = makePropertySetter<V>(&LineLayer::setLineWidth);
+ result["line-width-transition"] = makeTransitionSetter<V>(&LineLayer::setLineWidthTransition);
result["line-gap-width"] = makePropertySetter<V>(&LineLayer::setLineGapWidth);
+ result["line-gap-width-transition"] = makeTransitionSetter<V>(&LineLayer::setLineGapWidthTransition);
result["line-offset"] = makePropertySetter<V>(&LineLayer::setLineOffset);
+ result["line-offset-transition"] = makeTransitionSetter<V>(&LineLayer::setLineOffsetTransition);
result["line-blur"] = makePropertySetter<V>(&LineLayer::setLineBlur);
+ result["line-blur-transition"] = makeTransitionSetter<V>(&LineLayer::setLineBlurTransition);
result["line-dasharray"] = makePropertySetter<V>(&LineLayer::setLineDasharray);
+ result["line-dasharray-transition"] = makeTransitionSetter<V>(&LineLayer::setLineDasharrayTransition);
result["line-pattern"] = makePropertySetter<V>(&LineLayer::setLinePattern);
+ result["line-pattern-transition"] = makeTransitionSetter<V>(&LineLayer::setLinePatternTransition);
result["icon-opacity"] = makePropertySetter<V>(&SymbolLayer::setIconOpacity);
+ result["icon-opacity-transition"] = makeTransitionSetter<V>(&SymbolLayer::setIconOpacityTransition);
result["icon-color"] = makePropertySetter<V>(&SymbolLayer::setIconColor);
+ result["icon-color-transition"] = makeTransitionSetter<V>(&SymbolLayer::setIconColorTransition);
result["icon-halo-color"] = makePropertySetter<V>(&SymbolLayer::setIconHaloColor);
+ result["icon-halo-color-transition"] = makeTransitionSetter<V>(&SymbolLayer::setIconHaloColorTransition);
result["icon-halo-width"] = makePropertySetter<V>(&SymbolLayer::setIconHaloWidth);
+ result["icon-halo-width-transition"] = makeTransitionSetter<V>(&SymbolLayer::setIconHaloWidthTransition);
result["icon-halo-blur"] = makePropertySetter<V>(&SymbolLayer::setIconHaloBlur);
+ result["icon-halo-blur-transition"] = makeTransitionSetter<V>(&SymbolLayer::setIconHaloBlurTransition);
result["icon-translate"] = makePropertySetter<V>(&SymbolLayer::setIconTranslate);
+ result["icon-translate-transition"] = makeTransitionSetter<V>(&SymbolLayer::setIconTranslateTransition);
result["icon-translate-anchor"] = makePropertySetter<V>(&SymbolLayer::setIconTranslateAnchor);
+ result["icon-translate-anchor-transition"] = makeTransitionSetter<V>(&SymbolLayer::setIconTranslateAnchorTransition);
result["text-opacity"] = makePropertySetter<V>(&SymbolLayer::setTextOpacity);
+ result["text-opacity-transition"] = makeTransitionSetter<V>(&SymbolLayer::setTextOpacityTransition);
result["text-color"] = makePropertySetter<V>(&SymbolLayer::setTextColor);
+ result["text-color-transition"] = makeTransitionSetter<V>(&SymbolLayer::setTextColorTransition);
result["text-halo-color"] = makePropertySetter<V>(&SymbolLayer::setTextHaloColor);
+ result["text-halo-color-transition"] = makeTransitionSetter<V>(&SymbolLayer::setTextHaloColorTransition);
result["text-halo-width"] = makePropertySetter<V>(&SymbolLayer::setTextHaloWidth);
+ result["text-halo-width-transition"] = makeTransitionSetter<V>(&SymbolLayer::setTextHaloWidthTransition);
result["text-halo-blur"] = makePropertySetter<V>(&SymbolLayer::setTextHaloBlur);
+ result["text-halo-blur-transition"] = makeTransitionSetter<V>(&SymbolLayer::setTextHaloBlurTransition);
result["text-translate"] = makePropertySetter<V>(&SymbolLayer::setTextTranslate);
+ result["text-translate-transition"] = makeTransitionSetter<V>(&SymbolLayer::setTextTranslateTransition);
result["text-translate-anchor"] = makePropertySetter<V>(&SymbolLayer::setTextTranslateAnchor);
+ result["text-translate-anchor-transition"] = makeTransitionSetter<V>(&SymbolLayer::setTextTranslateAnchorTransition);
result["circle-radius"] = makePropertySetter<V>(&CircleLayer::setCircleRadius);
+ result["circle-radius-transition"] = makeTransitionSetter<V>(&CircleLayer::setCircleRadiusTransition);
result["circle-color"] = makePropertySetter<V>(&CircleLayer::setCircleColor);
+ result["circle-color-transition"] = makeTransitionSetter<V>(&CircleLayer::setCircleColorTransition);
result["circle-blur"] = makePropertySetter<V>(&CircleLayer::setCircleBlur);
+ result["circle-blur-transition"] = makeTransitionSetter<V>(&CircleLayer::setCircleBlurTransition);
result["circle-opacity"] = makePropertySetter<V>(&CircleLayer::setCircleOpacity);
+ result["circle-opacity-transition"] = makeTransitionSetter<V>(&CircleLayer::setCircleOpacityTransition);
result["circle-translate"] = makePropertySetter<V>(&CircleLayer::setCircleTranslate);
+ result["circle-translate-transition"] = makeTransitionSetter<V>(&CircleLayer::setCircleTranslateTransition);
result["circle-translate-anchor"] = makePropertySetter<V>(&CircleLayer::setCircleTranslateAnchor);
+ result["circle-translate-anchor-transition"] = makeTransitionSetter<V>(&CircleLayer::setCircleTranslateAnchorTransition);
result["circle-pitch-scale"] = makePropertySetter<V>(&CircleLayer::setCirclePitchScale);
+ result["circle-pitch-scale-transition"] = makeTransitionSetter<V>(&CircleLayer::setCirclePitchScaleTransition);
result["circle-stroke-width"] = makePropertySetter<V>(&CircleLayer::setCircleStrokeWidth);
+ result["circle-stroke-width-transition"] = makeTransitionSetter<V>(&CircleLayer::setCircleStrokeWidthTransition);
result["circle-stroke-color"] = makePropertySetter<V>(&CircleLayer::setCircleStrokeColor);
+ result["circle-stroke-color-transition"] = makeTransitionSetter<V>(&CircleLayer::setCircleStrokeColorTransition);
result["circle-stroke-opacity"] = makePropertySetter<V>(&CircleLayer::setCircleStrokeOpacity);
+ result["circle-stroke-opacity-transition"] = makeTransitionSetter<V>(&CircleLayer::setCircleStrokeOpacityTransition);
result["fill-extrusion-opacity"] = makePropertySetter<V>(&FillExtrusionLayer::setFillExtrusionOpacity);
+ result["fill-extrusion-opacity-transition"] = makeTransitionSetter<V>(&FillExtrusionLayer::setFillExtrusionOpacityTransition);
result["fill-extrusion-color"] = makePropertySetter<V>(&FillExtrusionLayer::setFillExtrusionColor);
+ result["fill-extrusion-color-transition"] = makeTransitionSetter<V>(&FillExtrusionLayer::setFillExtrusionColorTransition);
result["fill-extrusion-translate"] = makePropertySetter<V>(&FillExtrusionLayer::setFillExtrusionTranslate);
+ result["fill-extrusion-translate-transition"] = makeTransitionSetter<V>(&FillExtrusionLayer::setFillExtrusionTranslateTransition);
result["fill-extrusion-translate-anchor"] = makePropertySetter<V>(&FillExtrusionLayer::setFillExtrusionTranslateAnchor);
+ result["fill-extrusion-translate-anchor-transition"] = makeTransitionSetter<V>(&FillExtrusionLayer::setFillExtrusionTranslateAnchorTransition);
result["fill-extrusion-pattern"] = makePropertySetter<V>(&FillExtrusionLayer::setFillExtrusionPattern);
+ result["fill-extrusion-pattern-transition"] = makeTransitionSetter<V>(&FillExtrusionLayer::setFillExtrusionPatternTransition);
result["fill-extrusion-height"] = makePropertySetter<V>(&FillExtrusionLayer::setFillExtrusionHeight);
+ result["fill-extrusion-height-transition"] = makeTransitionSetter<V>(&FillExtrusionLayer::setFillExtrusionHeightTransition);
result["fill-extrusion-base"] = makePropertySetter<V>(&FillExtrusionLayer::setFillExtrusionBase);
+ result["fill-extrusion-base-transition"] = makeTransitionSetter<V>(&FillExtrusionLayer::setFillExtrusionBaseTransition);
result["raster-opacity"] = makePropertySetter<V>(&RasterLayer::setRasterOpacity);
+ result["raster-opacity-transition"] = makeTransitionSetter<V>(&RasterLayer::setRasterOpacityTransition);
result["raster-hue-rotate"] = makePropertySetter<V>(&RasterLayer::setRasterHueRotate);
+ result["raster-hue-rotate-transition"] = makeTransitionSetter<V>(&RasterLayer::setRasterHueRotateTransition);
result["raster-brightness-min"] = makePropertySetter<V>(&RasterLayer::setRasterBrightnessMin);
+ result["raster-brightness-min-transition"] = makeTransitionSetter<V>(&RasterLayer::setRasterBrightnessMinTransition);
result["raster-brightness-max"] = makePropertySetter<V>(&RasterLayer::setRasterBrightnessMax);
+ result["raster-brightness-max-transition"] = makeTransitionSetter<V>(&RasterLayer::setRasterBrightnessMaxTransition);
result["raster-saturation"] = makePropertySetter<V>(&RasterLayer::setRasterSaturation);
+ result["raster-saturation-transition"] = makeTransitionSetter<V>(&RasterLayer::setRasterSaturationTransition);
result["raster-contrast"] = makePropertySetter<V>(&RasterLayer::setRasterContrast);
+ result["raster-contrast-transition"] = makeTransitionSetter<V>(&RasterLayer::setRasterContrastTransition);
result["raster-fade-duration"] = makePropertySetter<V>(&RasterLayer::setRasterFadeDuration);
+ result["raster-fade-duration-transition"] = makeTransitionSetter<V>(&RasterLayer::setRasterFadeDurationTransition);
result["background-color"] = makePropertySetter<V>(&BackgroundLayer::setBackgroundColor);
+ result["background-color-transition"] = makeTransitionSetter<V>(&BackgroundLayer::setBackgroundColorTransition);
result["background-pattern"] = makePropertySetter<V>(&BackgroundLayer::setBackgroundPattern);
+ result["background-pattern-transition"] = makeTransitionSetter<V>(&BackgroundLayer::setBackgroundPatternTransition);
result["background-opacity"] = makePropertySetter<V>(&BackgroundLayer::setBackgroundOpacity);
+ result["background-opacity-transition"] = makeTransitionSetter<V>(&BackgroundLayer::setBackgroundOpacityTransition);
return result;
}
diff --git a/include/mbgl/style/conversion/make_property_setters.hpp.ejs b/include/mbgl/style/conversion/make_property_setters.hpp.ejs
index ed8f6e891c..65fbdea63e 100644
--- a/include/mbgl/style/conversion/make_property_setters.hpp.ejs
+++ b/include/mbgl/style/conversion/make_property_setters.hpp.ejs
@@ -36,6 +36,7 @@ auto makePaintPropertySetters() {
<% for (const layer of locals.layers) { -%>
<% for (const property of layer.paintProperties) { -%>
result["<%- property.name %>"] = makePropertySetter<V>(&<%- camelize(layer.type) %>Layer::set<%- camelize(property.name) %>);
+ result["<%- property.name %>-transition"] = makeTransitionSetter<V>(&<%- camelize(layer.type) %>Layer::set<%- camelize(property.name) %>Transition);
<% } -%>
<% } -%>
diff --git a/include/mbgl/style/conversion/property_setter.hpp b/include/mbgl/style/conversion/property_setter.hpp
index 1a601c7c1b..6a15c64026 100644
--- a/include/mbgl/style/conversion/property_setter.hpp
+++ b/include/mbgl/style/conversion/property_setter.hpp
@@ -4,6 +4,8 @@
#include <mbgl/style/conversion.hpp>
#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/transition_options.hpp>
#include <functional>
#include <string>
@@ -18,15 +20,15 @@ using LayoutPropertySetter = std::function<optional<Error> (Layer&, const V&)>;
template <class V>
using PaintPropertySetter = std::function<optional<Error> (Layer&, const V&, const optional<std::string>&)>;
-template <class V, class L, class T, class...Args>
-auto makePropertySetter(void (L::*setter)(PropertyValue<T>, const Args&...args)) {
+template <class V, class L, class PropertyValue, class...Args>
+auto makePropertySetter(void (L::*setter)(PropertyValue, const Args&...args)) {
return [setter] (Layer& layer, const V& value, const Args&...args) -> optional<Error> {
L* typedLayer = layer.as<L>();
if (!typedLayer) {
return Error { "layer doesn't support this property" };
}
- Result<PropertyValue<T>> typedValue = convert<PropertyValue<T>>(value);
+ Result<PropertyValue> typedValue = convert<PropertyValue>(value);
if (!typedValue) {
return typedValue.error();
}
@@ -36,6 +38,24 @@ auto makePropertySetter(void (L::*setter)(PropertyValue<T>, const Args&...args))
};
}
+template <class V, class L, class...Args>
+auto makeTransitionSetter(void (L::*setter)(const TransitionOptions&, const Args&...args)) {
+ return [setter] (Layer& layer, const V& value, const Args&...args) -> optional<Error> {
+ L* typedLayer = layer.as<L>();
+ if (!typedLayer) {
+ return Error { "layer doesn't support this property" };
+ }
+
+ Result<TransitionOptions> transition = convert<TransitionOptions>(value);
+ if (!transition) {
+ return transition.error();
+ }
+
+ (typedLayer->*setter)(*transition, args...);
+ return {};
+ };
+}
+
template <class V>
optional<Error> setVisibility(Layer& layer, const V& value) {
if (isUndefined(value)) {
diff --git a/include/mbgl/style/conversion/property_value.hpp b/include/mbgl/style/conversion/property_value.hpp
index de95b56155..d5e2a5c3c8 100644
--- a/include/mbgl/style/conversion/property_value.hpp
+++ b/include/mbgl/style/conversion/property_value.hpp
@@ -16,7 +16,7 @@ struct Converter<PropertyValue<T>> {
if (isUndefined(value)) {
return {};
} else if (isObject(value)) {
- Result<Function<T>> function = convert<Function<T>>(value);
+ Result<CameraFunction<T>> function = convert<CameraFunction<T>>(value);
if (!function) {
return function.error();
}
diff --git a/include/mbgl/style/conversion/transition_options.hpp b/include/mbgl/style/conversion/transition_options.hpp
new file mode 100644
index 0000000000..cdd65cfe9f
--- /dev/null
+++ b/include/mbgl/style/conversion/transition_options.hpp
@@ -0,0 +1,45 @@
+#pragma once
+
+#include <mbgl/style/transition_options.hpp>
+#include <mbgl/style/conversion.hpp>
+
+namespace mbgl {
+namespace style {
+namespace conversion {
+
+template <>
+struct Converter<TransitionOptions> {
+public:
+ template <class V>
+ Result<TransitionOptions> operator()(const V& value) const {
+ if (!isObject(value)) {
+ return Error { "transition must be an object" };
+ }
+
+ TransitionOptions result;
+
+ auto duration = objectMember(value, "duration");
+ if (duration) {
+ auto number = toNumber(*duration);
+ if (!number) {
+ return Error { "duration must be a number" };
+ }
+ result.duration = { std::chrono::milliseconds(int64_t(*number)) };
+ }
+
+ auto delay = objectMember(value, "delay");
+ if (delay) {
+ auto number = toNumber(*delay);
+ if (!number) {
+ return Error { "delay must be a number" };
+ }
+ result.delay = { std::chrono::milliseconds(int64_t(*number)) };
+ }
+
+ return result;
+ }
+};
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/data_driven_property_value.hpp b/include/mbgl/style/data_driven_property_value.hpp
new file mode 100644
index 0000000000..3f9ac69436
--- /dev/null
+++ b/include/mbgl/style/data_driven_property_value.hpp
@@ -0,0 +1,56 @@
+#pragma once
+
+#include <mbgl/util/variant.hpp>
+#include <mbgl/style/undefined.hpp>
+#include <mbgl/style/function/camera_function.hpp>
+#include <mbgl/style/function/source_function.hpp>
+#include <mbgl/style/function/composite_function.hpp>
+
+namespace mbgl {
+namespace style {
+
+template <class T>
+class DataDrivenPropertyValue {
+private:
+ using Value = variant<
+ Undefined,
+ T,
+ CameraFunction<T>,
+ SourceFunction<T>,
+ CompositeFunction<T>>;
+
+ Value value;
+
+ friend bool operator==(const DataDrivenPropertyValue& lhs,
+ const DataDrivenPropertyValue& rhs) {
+ return lhs.value == rhs.value;
+ }
+
+ friend bool operator!=(const DataDrivenPropertyValue& lhs,
+ const DataDrivenPropertyValue& rhs) {
+ return !(lhs == rhs);
+ }
+
+public:
+ DataDrivenPropertyValue() = default;
+ DataDrivenPropertyValue( T v) : value(std::move(v)) {}
+ DataDrivenPropertyValue( CameraFunction<T> v) : value(std::move(v)) {}
+ DataDrivenPropertyValue( SourceFunction<T> v) : value(std::move(v)) {}
+ DataDrivenPropertyValue(CompositeFunction<T> v) : value(std::move(v)) {}
+
+ bool isUndefined() const {
+ return value.template is<Undefined>();
+ }
+
+ bool isDataDriven() const {
+ return value.template is<SourceFunction<T>>() || value.template is<CompositeFunction<T>>();
+ }
+
+ template <typename Evaluator>
+ auto evaluate(const Evaluator& evaluator) const {
+ return Value::visit(value, evaluator);
+ }
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/filter.hpp b/include/mbgl/style/filter.hpp
index e5d8081d82..5e61adf064 100644
--- a/include/mbgl/style/filter.hpp
+++ b/include/mbgl/style/filter.hpp
@@ -145,6 +145,95 @@ public:
}
};
+
+class TypeEqualsFilter {
+public:
+ FeatureType value;
+
+ friend bool operator==(const TypeEqualsFilter& lhs, const TypeEqualsFilter& rhs) {
+ return lhs.value == rhs.value;
+ }
+};
+
+class TypeNotEqualsFilter {
+public:
+ FeatureType value;
+
+ friend bool operator==(const TypeNotEqualsFilter& lhs, const TypeNotEqualsFilter& rhs) {
+ return lhs.value == rhs.value;
+ }
+};
+
+class TypeInFilter {
+public:
+ std::vector<FeatureType> values;
+
+ friend bool operator==(const TypeInFilter& lhs, const TypeInFilter& rhs) {
+ return lhs.values == rhs.values;
+ }
+};
+
+class TypeNotInFilter {
+public:
+ std::vector<FeatureType> values;
+
+ friend bool operator==(const TypeNotInFilter& lhs, const TypeNotInFilter& rhs) {
+ return lhs.values == rhs.values;
+ }
+};
+
+
+class IdentifierEqualsFilter {
+public:
+ FeatureIdentifier value;
+
+ friend bool operator==(const IdentifierEqualsFilter& lhs, const IdentifierEqualsFilter& rhs) {
+ return lhs.value == rhs.value;
+ }
+};
+
+class IdentifierNotEqualsFilter {
+public:
+ FeatureIdentifier value;
+
+ friend bool operator==(const IdentifierNotEqualsFilter& lhs, const IdentifierNotEqualsFilter& rhs) {
+ return lhs.value == rhs.value;
+ }
+};
+
+class IdentifierInFilter {
+public:
+ std::vector<FeatureIdentifier> values;
+
+ friend bool operator==(const IdentifierInFilter& lhs, const IdentifierInFilter& rhs) {
+ return lhs.values == rhs.values;
+ }
+};
+
+class IdentifierNotInFilter {
+public:
+ std::vector<FeatureIdentifier> values;
+
+ friend bool operator==(const IdentifierNotInFilter& lhs, const IdentifierNotInFilter& rhs) {
+ return lhs.values == rhs.values;
+ }
+};
+
+class HasIdentifierFilter {
+public:
+ friend bool operator==(const HasIdentifierFilter&, const HasIdentifierFilter&) {
+ return true;
+ }
+};
+
+class NotHasIdentifierFilter {
+public:
+ friend bool operator==(const NotHasIdentifierFilter&, const NotHasIdentifierFilter&) {
+ return true;
+ }
+};
+
+
using FilterBase = variant<
class NullFilter,
class EqualsFilter,
@@ -159,7 +248,17 @@ using FilterBase = variant<
class AllFilter,
class NoneFilter,
class HasFilter,
- class NotHasFilter>;
+ class NotHasFilter,
+ class TypeEqualsFilter,
+ class TypeNotEqualsFilter,
+ class TypeInFilter,
+ class TypeNotInFilter,
+ class IdentifierEqualsFilter,
+ class IdentifierNotEqualsFilter,
+ class IdentifierInFilter,
+ class IdentifierNotInFilter,
+ class HasIdentifierFilter,
+ class NotHasIdentifierFilter>;
class Filter : public FilterBase {
public:
diff --git a/include/mbgl/style/filter_evaluator.hpp b/include/mbgl/style/filter_evaluator.hpp
index 659f554bba..370064445a 100644
--- a/include/mbgl/style/filter_evaluator.hpp
+++ b/include/mbgl/style/filter_evaluator.hpp
@@ -31,37 +31,37 @@ public:
}
bool operator()(const EqualsFilter& filter) const {
- optional<Value> actual = getValue(filter.key);
+ optional<Value> actual = propertyAccessor(filter.key);
return actual && equal(*actual, filter.value);
}
bool operator()(const NotEqualsFilter& filter) const {
- optional<Value> actual = getValue(filter.key);
+ optional<Value> actual = propertyAccessor(filter.key);
return !actual || !equal(*actual, filter.value);
}
bool operator()(const LessThanFilter& filter) const {
- optional<Value> actual = getValue(filter.key);
+ optional<Value> actual = propertyAccessor(filter.key);
return actual && compare(*actual, filter.value, [] (const auto& lhs_, const auto& rhs_) { return lhs_ < rhs_; });
}
bool operator()(const LessThanEqualsFilter& filter) const {
- optional<Value> actual = getValue(filter.key);
+ optional<Value> actual = propertyAccessor(filter.key);
return actual && compare(*actual, filter.value, [] (const auto& lhs_, const auto& rhs_) { return lhs_ <= rhs_; });
}
bool operator()(const GreaterThanFilter& filter) const {
- optional<Value> actual = getValue(filter.key);
+ optional<Value> actual = propertyAccessor(filter.key);
return actual && compare(*actual, filter.value, [] (const auto& lhs_, const auto& rhs_) { return lhs_ > rhs_; });
}
bool operator()(const GreaterThanEqualsFilter& filter) const {
- optional<Value> actual = getValue(filter.key);
+ optional<Value> actual = propertyAccessor(filter.key);
return actual && compare(*actual, filter.value, [] (const auto& lhs_, const auto& rhs_) { return lhs_ >= rhs_; });
}
bool operator()(const InFilter& filter) const {
- optional<Value> actual = getValue(filter.key);
+ optional<Value> actual = propertyAccessor(filter.key);
if (!actual)
return false;
for (const auto& v: filter.values) {
@@ -73,7 +73,7 @@ public:
}
bool operator()(const NotInFilter& filter) const {
- optional<Value> actual = getValue(filter.key);
+ optional<Value> actual = propertyAccessor(filter.key);
if (!actual)
return true;
for (const auto& v: filter.values) {
@@ -112,30 +112,76 @@ public:
}
bool operator()(const HasFilter& filter) const {
- return bool(getValue(filter.key));
+ return bool(propertyAccessor(filter.key));
}
bool operator()(const NotHasFilter& filter) const {
- return !getValue(filter.key);
+ return !propertyAccessor(filter.key);
}
-private:
- optional<Value> getValue(const std::string& key_) const {
- if (key_ == "$type") {
- return optional<Value>(uint64_t(featureType));
- } else if (key_ == "$id") {
- if (featureIdentifier) {
- return FeatureIdentifier::visit(*featureIdentifier, [] (auto id) {
- return Value(std::move(id));
- });
- } else {
- return optional<Value>();
+
+ bool operator()(const TypeEqualsFilter& filter) const {
+ return featureType == filter.value;
+ }
+
+ bool operator()(const TypeNotEqualsFilter& filter) const {
+ return featureType != filter.value;
+ }
+
+ bool operator()(const TypeInFilter& filter) const {
+ for (const auto& v: filter.values) {
+ if (featureType == v) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool operator()(const TypeNotInFilter& filter) const {
+ for (const auto& v: filter.values) {
+ if (featureType == v) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ bool operator()(const IdentifierEqualsFilter& filter) const {
+ return featureIdentifier == filter.value;
+ }
+
+ bool operator()(const IdentifierNotEqualsFilter& filter) const {
+ return featureIdentifier != filter.value;
+ }
+
+ bool operator()(const IdentifierInFilter& filter) const {
+ for (const auto& v: filter.values) {
+ if (featureIdentifier == v) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool operator()(const IdentifierNotInFilter& filter) const {
+ for (const auto& v: filter.values) {
+ if (featureIdentifier == v) {
+ return false;
}
- } else {
- return propertyAccessor(key_);
}
+ return true;
}
+ bool operator()(const HasIdentifierFilter&) const {
+ return bool(featureIdentifier);
+ }
+
+ bool operator()(const NotHasIdentifierFilter&) const {
+ return !featureIdentifier;
+ }
+
+private:
template <class Op>
struct Comparator {
const Op& op;
diff --git a/include/mbgl/style/function.hpp b/include/mbgl/style/function.hpp
deleted file mode 100644
index b023229e4f..0000000000
--- a/include/mbgl/style/function.hpp
+++ /dev/null
@@ -1,40 +0,0 @@
-#pragma once
-
-#include <cassert>
-#include <utility>
-#include <vector>
-
-namespace mbgl {
-namespace style {
-
-template <typename T>
-class Function {
-public:
- using Stop = std::pair<float, T>;
- using Stops = std::vector<Stop>;
-
- Function(Stops stops_, float base_)
- : base(base_), stops(std::move(stops_)) {
- assert(stops.size() > 0);
- }
-
- float getBase() const { return base; }
- const std::vector<std::pair<float, T>>& getStops() const { return stops; }
-
- T evaluate(float z) const;
-
- friend bool operator==(const Function& lhs, const Function& rhs) {
- return lhs.base == rhs.base && lhs.stops == rhs.stops;
- }
-
- friend bool operator!=(const Function& lhs, const Function& rhs) {
- return !(lhs == rhs);
- }
-
-private:
- float base = 1;
- std::vector<std::pair<float, T>> stops;
-};
-
-} // namespace style
-} // namespace mbgl
diff --git a/include/mbgl/style/function/camera_function.hpp b/include/mbgl/style/function/camera_function.hpp
new file mode 100644
index 0000000000..5636b1663c
--- /dev/null
+++ b/include/mbgl/style/function/camera_function.hpp
@@ -0,0 +1,41 @@
+#pragma once
+
+#include <mbgl/style/function/exponential_stops.hpp>
+#include <mbgl/style/function/interval_stops.hpp>
+#include <mbgl/util/interpolate.hpp>
+#include <mbgl/util/variant.hpp>
+
+namespace mbgl {
+namespace style {
+
+template <class T>
+class CameraFunction {
+public:
+ using Stops = std::conditional_t<
+ util::Interpolatable<T>,
+ variant<
+ ExponentialStops<T>,
+ IntervalStops<T>>,
+ variant<
+ IntervalStops<T>>>;
+
+ CameraFunction(Stops stops_)
+ : stops(std::move(stops_)) {
+ }
+
+ T evaluate(float zoom) const {
+ return stops.match([&] (const auto& s) {
+ return s.evaluate(Value(double(zoom))).value_or(T());
+ });
+ }
+
+ friend bool operator==(const CameraFunction& lhs,
+ const CameraFunction& rhs) {
+ return lhs.stops == rhs.stops;
+ }
+
+ Stops stops;
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/function/categorical_stops.hpp b/include/mbgl/style/function/categorical_stops.hpp
new file mode 100644
index 0000000000..c8505115ab
--- /dev/null
+++ b/include/mbgl/style/function/categorical_stops.hpp
@@ -0,0 +1,40 @@
+#pragma once
+
+#include <mbgl/util/feature.hpp>
+#include <mbgl/util/variant.hpp>
+
+#include <cassert>
+#include <utility>
+#include <map>
+
+namespace mbgl {
+namespace style {
+
+class CategoricalValue : public variant<bool, int64_t, std::string> {
+public:
+ using variant<bool, int64_t, std::string>::variant;
+};
+
+template <class T>
+class CategoricalStops {
+public:
+ using Stops = std::map<CategoricalValue, T>;
+
+ Stops stops;
+
+ CategoricalStops() = default;
+ CategoricalStops(Stops stops_)
+ : stops(std::move(stops_)) {
+ assert(stops.size() > 0);
+ }
+
+ optional<T> evaluate(const Value&) const;
+
+ friend bool operator==(const CategoricalStops& lhs,
+ const CategoricalStops& rhs) {
+ return lhs.stops == rhs.stops;
+ }
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/function/composite_categorical_stops.hpp b/include/mbgl/style/function/composite_categorical_stops.hpp
new file mode 100644
index 0000000000..b796621d1a
--- /dev/null
+++ b/include/mbgl/style/function/composite_categorical_stops.hpp
@@ -0,0 +1,30 @@
+#pragma once
+
+#include <mbgl/style/function/categorical_stops.hpp>
+
+namespace mbgl {
+namespace style {
+
+template <class T>
+class CompositeCategoricalStops {
+public:
+ using Stops = std::map<float, std::map<CategoricalValue, T>>;
+ Stops stops;
+
+ CompositeCategoricalStops() = default;
+ CompositeCategoricalStops(Stops stops_)
+ : stops(std::move(stops_)) {
+ }
+
+ CategoricalStops<T> innerStops(const std::map<CategoricalValue, T>& stops_) const {
+ return CategoricalStops<T>(stops_);
+ }
+
+ friend bool operator==(const CompositeCategoricalStops& lhs,
+ const CompositeCategoricalStops& rhs) {
+ return lhs.stops == rhs.stops;
+ }
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/function/composite_exponential_stops.hpp b/include/mbgl/style/function/composite_exponential_stops.hpp
new file mode 100644
index 0000000000..f1ad32a04d
--- /dev/null
+++ b/include/mbgl/style/function/composite_exponential_stops.hpp
@@ -0,0 +1,35 @@
+#pragma once
+
+#include <mbgl/style/function/exponential_stops.hpp>
+
+#include <map>
+
+namespace mbgl {
+namespace style {
+
+template <class T>
+class CompositeExponentialStops {
+public:
+ using Stops = std::map<float, std::map<float, T>>;
+
+ Stops stops;
+ float base = 1.0f;
+
+ CompositeExponentialStops() = default;
+ CompositeExponentialStops(Stops stops_, float base_ = 1.0f)
+ : stops(std::move(stops_)),
+ base(base_) {
+ }
+
+ ExponentialStops<T> innerStops(const std::map<float, T>& stops_) const {
+ return ExponentialStops<T>(stops_, base);
+ }
+
+ friend bool operator==(const CompositeExponentialStops& lhs,
+ const CompositeExponentialStops& rhs) {
+ return lhs.stops == rhs.stops && lhs.base == rhs.base;
+ }
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/function/composite_function.hpp b/include/mbgl/style/function/composite_function.hpp
new file mode 100644
index 0000000000..be238fe9c3
--- /dev/null
+++ b/include/mbgl/style/function/composite_function.hpp
@@ -0,0 +1,116 @@
+#pragma once
+
+#include <mbgl/style/function/composite_exponential_stops.hpp>
+#include <mbgl/style/function/composite_interval_stops.hpp>
+#include <mbgl/style/function/composite_categorical_stops.hpp>
+#include <mbgl/util/interpolate.hpp>
+#include <mbgl/util/range.hpp>
+#include <mbgl/util/variant.hpp>
+
+#include <string>
+#include <tuple>
+
+namespace mbgl {
+
+class GeometryTileFeature;
+
+namespace style {
+
+// A CompositeFunction consists of an outer zoom function whose stop range values are
+// "inner" source functions. It provides the GL Native implementation of
+// "zoom-and-property" functions from the style spec.
+
+template <class T>
+class CompositeFunction {
+public:
+ using InnerStops = std::conditional_t<
+ util::Interpolatable<T>,
+ variant<
+ ExponentialStops<T>,
+ IntervalStops<T>,
+ CategoricalStops<T>>,
+ variant<
+ IntervalStops<T>,
+ CategoricalStops<T>>>;
+
+ using Stops = std::conditional_t<
+ util::Interpolatable<T>,
+ variant<
+ CompositeExponentialStops<T>,
+ CompositeIntervalStops<T>,
+ CompositeCategoricalStops<T>>,
+ variant<
+ CompositeIntervalStops<T>,
+ CompositeCategoricalStops<T>>>;
+
+ CompositeFunction(std::string property_, Stops stops_, optional<T> defaultValue_ = {})
+ : property(std::move(property_)),
+ stops(std::move(stops_)),
+ defaultValue(std::move(defaultValue_)) {
+ }
+
+ std::tuple<Range<float>, Range<InnerStops>>
+ coveringRanges(float zoom) const {
+ return stops.match(
+ [&] (const auto& s) {
+ assert(!s.stops.empty());
+ auto minIt = s.stops.lower_bound(zoom);
+ auto maxIt = s.stops.upper_bound(zoom);
+ if (minIt != s.stops.begin()) {
+ minIt--;
+ }
+ return std::make_tuple(
+ Range<float> {
+ minIt == s.stops.end() ? s.stops.rbegin()->first : minIt->first,
+ maxIt == s.stops.end() ? s.stops.rbegin()->first : maxIt->first
+ },
+ Range<InnerStops> {
+ s.innerStops(minIt == s.stops.end() ? s.stops.rbegin()->second : minIt->second),
+ s.innerStops(maxIt == s.stops.end() ? s.stops.rbegin()->second : maxIt->second)
+ }
+ );
+ }
+ );
+ }
+
+ Range<T> evaluate(Range<InnerStops> coveringStops,
+ const GeometryTileFeature& feature,
+ T finalDefaultValue) const {
+ optional<Value> v = feature.getValue(property);
+ if (!v) {
+ return {
+ defaultValue.value_or(finalDefaultValue),
+ defaultValue.value_or(finalDefaultValue)
+ };
+ }
+ auto eval = [&] (const auto& s) {
+ return s.evaluate(*v).value_or(defaultValue.value_or(finalDefaultValue));
+ };
+ return Range<T> {
+ coveringStops.min.match(eval),
+ coveringStops.max.match(eval)
+ };
+ }
+
+ 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, finalDefaultValue);
+ return util::interpolate(
+ resultRange.min,
+ resultRange.max,
+ util::interpolationFactor(1.0f, std::get<0>(ranges), zoom));
+ }
+
+ friend bool operator==(const CompositeFunction& lhs,
+ const CompositeFunction& rhs) {
+ 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
+} // namespace mbgl
diff --git a/include/mbgl/style/function/composite_interval_stops.hpp b/include/mbgl/style/function/composite_interval_stops.hpp
new file mode 100644
index 0000000000..3c495f2a7f
--- /dev/null
+++ b/include/mbgl/style/function/composite_interval_stops.hpp
@@ -0,0 +1,32 @@
+#pragma once
+
+#include <mbgl/style/function/interval_stops.hpp>
+
+#include <map>
+
+namespace mbgl {
+namespace style {
+
+template <class T>
+class CompositeIntervalStops {
+public:
+ using Stops = std::map<float, std::map<float, T>>;
+ Stops stops;
+
+ CompositeIntervalStops() = default;
+ CompositeIntervalStops(Stops stops_)
+ : stops(std::move(stops_)) {
+ }
+
+ IntervalStops<T> innerStops(const std::map<float, T>& stops_) const {
+ return IntervalStops<T>(stops_);
+ }
+
+ friend bool operator==(const CompositeIntervalStops& lhs,
+ const CompositeIntervalStops& rhs) {
+ return lhs.stops == rhs.stops;
+ }
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/function/exponential_stops.hpp b/include/mbgl/style/function/exponential_stops.hpp
new file mode 100644
index 0000000000..051f5aa9aa
--- /dev/null
+++ b/include/mbgl/style/function/exponential_stops.hpp
@@ -0,0 +1,54 @@
+#pragma once
+
+#include <mbgl/util/feature.hpp>
+#include <mbgl/util/interpolate.hpp>
+
+#include <map>
+
+namespace mbgl {
+namespace style {
+
+template <class T>
+class ExponentialStops {
+public:
+ using Stops = std::map<float, T>;
+
+ Stops stops;
+ float base = 1.0f;
+
+ ExponentialStops() = default;
+ ExponentialStops(Stops stops_, float base_ = 1.0f)
+ : stops(std::move(stops_)),
+ base(base_) {
+ }
+
+ optional<T> evaluate(const Value& value) const {
+ if (stops.empty()) {
+ assert(false);
+ return T();
+ }
+
+ optional<float> z = numericValue<float>(value);
+ if (!z) {
+ return T();
+ }
+
+ auto it = stops.upper_bound(*z);
+ if (it == stops.end()) {
+ return stops.rbegin()->second;
+ } else if (it == stops.begin()) {
+ return stops.begin()->second;
+ } else {
+ return util::interpolate(std::prev(it)->second, it->second,
+ util::interpolationFactor(base, { std::prev(it)->first, it->first }, *z));
+ }
+ }
+
+ friend bool operator==(const ExponentialStops& lhs,
+ const ExponentialStops& rhs) {
+ return lhs.stops == rhs.stops && lhs.base == rhs.base;
+ }
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/function/identity_stops.hpp b/include/mbgl/style/function/identity_stops.hpp
new file mode 100644
index 0000000000..741ebbbe0c
--- /dev/null
+++ b/include/mbgl/style/function/identity_stops.hpp
@@ -0,0 +1,20 @@
+#pragma once
+
+#include <mbgl/util/feature.hpp>
+
+namespace mbgl {
+namespace style {
+
+template <class T>
+class IdentityStops {
+public:
+ optional<T> evaluate(const Value&) const;
+
+ friend bool operator==(const IdentityStops&,
+ const IdentityStops&) {
+ return true;
+ }
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/function/interval_stops.hpp b/include/mbgl/style/function/interval_stops.hpp
new file mode 100644
index 0000000000..50f2b48453
--- /dev/null
+++ b/include/mbgl/style/function/interval_stops.hpp
@@ -0,0 +1,49 @@
+#pragma once
+
+#include <mbgl/util/feature.hpp>
+
+#include <map>
+
+namespace mbgl {
+namespace style {
+
+template <class T>
+class IntervalStops {
+public:
+ using Stops = std::map<float, T>;
+ Stops stops;
+
+ IntervalStops() = default;
+ IntervalStops(Stops stops_)
+ : stops(std::move(stops_)) {
+ }
+
+ optional<T> evaluate(const Value& value) const {
+ if (stops.empty()) {
+ assert(false);
+ return {};
+ }
+
+ optional<float> z = numericValue<float>(value);
+ if (!z) {
+ return {};
+ }
+
+ auto it = stops.upper_bound(*z);
+ if (it == stops.end()) {
+ return stops.rbegin()->second;
+ } else if (it == stops.begin()) {
+ return stops.begin()->second;
+ } else {
+ return std::prev(it)->second;
+ }
+ }
+
+ friend bool operator==(const IntervalStops& lhs,
+ const IntervalStops& rhs) {
+ return lhs.stops == rhs.stops;
+ }
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/function/source_function.hpp b/include/mbgl/style/function/source_function.hpp
new file mode 100644
index 0000000000..29b1067a19
--- /dev/null
+++ b/include/mbgl/style/function/source_function.hpp
@@ -0,0 +1,59 @@
+#pragma once
+
+#include <mbgl/style/function/exponential_stops.hpp>
+#include <mbgl/style/function/interval_stops.hpp>
+#include <mbgl/style/function/categorical_stops.hpp>
+#include <mbgl/style/function/identity_stops.hpp>
+#include <mbgl/tile/geometry_tile_data.hpp>
+#include <mbgl/util/interpolate.hpp>
+#include <mbgl/util/variant.hpp>
+
+#include <string>
+
+namespace mbgl {
+namespace style {
+
+template <class T>
+class SourceFunction {
+public:
+ using Stops = std::conditional_t<
+ util::Interpolatable<T>,
+ variant<
+ ExponentialStops<T>,
+ IntervalStops<T>,
+ CategoricalStops<T>,
+ IdentityStops<T>>,
+ variant<
+ IntervalStops<T>,
+ CategoricalStops<T>,
+ IdentityStops<T>>>;
+
+ SourceFunction(std::string property_, Stops stops_, optional<T> defaultValue_ = {})
+ : property(std::move(property_)),
+ stops(std::move(stops_)),
+ defaultValue(std::move(defaultValue_)) {
+ }
+
+ T evaluate(const GeometryTileFeature& feature, T finalDefaultValue) const {
+ optional<Value> v = feature.getValue(property);
+ if (!v) {
+ return defaultValue.value_or(finalDefaultValue);
+ }
+ 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 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
+} // namespace mbgl
diff --git a/include/mbgl/style/layers/background_layer.hpp b/include/mbgl/style/layers/background_layer.hpp
index c120b7f493..94076931e7 100644
--- a/include/mbgl/style/layers/background_layer.hpp
+++ b/include/mbgl/style/layers/background_layer.hpp
@@ -5,12 +5,15 @@
#include <mbgl/style/layer.hpp>
#include <mbgl/style/filter.hpp>
#include <mbgl/style/property_value.hpp>
+#include <mbgl/style/data_driven_property_value.hpp>
#include <mbgl/util/color.hpp>
namespace mbgl {
namespace style {
+class TransitionOptions;
+
class BackgroundLayer : public Layer {
public:
BackgroundLayer(const std::string& layerID);
@@ -21,14 +24,17 @@ public:
static PropertyValue<Color> getDefaultBackgroundColor();
PropertyValue<Color> getBackgroundColor(const optional<std::string>& klass = {}) const;
void setBackgroundColor(PropertyValue<Color>, const optional<std::string>& klass = {});
+ void setBackgroundColorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<std::string> getDefaultBackgroundPattern();
PropertyValue<std::string> getBackgroundPattern(const optional<std::string>& klass = {}) const;
void setBackgroundPattern(PropertyValue<std::string>, const optional<std::string>& klass = {});
+ void setBackgroundPatternTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<float> getDefaultBackgroundOpacity();
PropertyValue<float> getBackgroundOpacity(const optional<std::string>& klass = {}) const;
void setBackgroundOpacity(PropertyValue<float>, const optional<std::string>& klass = {});
+ void setBackgroundOpacityTransition(const TransitionOptions&, const optional<std::string>& klass = {});
// Private implementation
diff --git a/include/mbgl/style/layers/circle_layer.hpp b/include/mbgl/style/layers/circle_layer.hpp
index 5562126c2f..35db4b3962 100644
--- a/include/mbgl/style/layers/circle_layer.hpp
+++ b/include/mbgl/style/layers/circle_layer.hpp
@@ -5,12 +5,15 @@
#include <mbgl/style/layer.hpp>
#include <mbgl/style/filter.hpp>
#include <mbgl/style/property_value.hpp>
+#include <mbgl/style/data_driven_property_value.hpp>
#include <mbgl/util/color.hpp>
namespace mbgl {
namespace style {
+class TransitionOptions;
+
class CircleLayer : public Layer {
public:
CircleLayer(const std::string& layerID, const std::string& sourceID);
@@ -26,45 +29,55 @@ public:
// Paint properties
- static PropertyValue<float> getDefaultCircleRadius();
- PropertyValue<float> getCircleRadius(const optional<std::string>& klass = {}) const;
- void setCircleRadius(PropertyValue<float>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<float> getDefaultCircleRadius();
+ DataDrivenPropertyValue<float> getCircleRadius(const optional<std::string>& klass = {}) const;
+ void setCircleRadius(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
+ void setCircleRadiusTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<Color> getDefaultCircleColor();
- PropertyValue<Color> getCircleColor(const optional<std::string>& klass = {}) const;
- void setCircleColor(PropertyValue<Color>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<Color> getDefaultCircleColor();
+ DataDrivenPropertyValue<Color> getCircleColor(const optional<std::string>& klass = {}) const;
+ void setCircleColor(DataDrivenPropertyValue<Color>, const optional<std::string>& klass = {});
+ void setCircleColorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<float> getDefaultCircleBlur();
- PropertyValue<float> getCircleBlur(const optional<std::string>& klass = {}) const;
- void setCircleBlur(PropertyValue<float>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<float> getDefaultCircleBlur();
+ DataDrivenPropertyValue<float> getCircleBlur(const optional<std::string>& klass = {}) const;
+ void setCircleBlur(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
+ void setCircleBlurTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<float> getDefaultCircleOpacity();
- PropertyValue<float> getCircleOpacity(const optional<std::string>& klass = {}) const;
- void setCircleOpacity(PropertyValue<float>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<float> getDefaultCircleOpacity();
+ DataDrivenPropertyValue<float> getCircleOpacity(const optional<std::string>& klass = {}) const;
+ void setCircleOpacity(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
+ void setCircleOpacityTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<std::array<float, 2>> getDefaultCircleTranslate();
PropertyValue<std::array<float, 2>> getCircleTranslate(const optional<std::string>& klass = {}) const;
void setCircleTranslate(PropertyValue<std::array<float, 2>>, const optional<std::string>& klass = {});
+ void setCircleTranslateTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<TranslateAnchorType> getDefaultCircleTranslateAnchor();
PropertyValue<TranslateAnchorType> getCircleTranslateAnchor(const optional<std::string>& klass = {}) const;
void setCircleTranslateAnchor(PropertyValue<TranslateAnchorType>, const optional<std::string>& klass = {});
+ void setCircleTranslateAnchorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<CirclePitchScaleType> getDefaultCirclePitchScale();
PropertyValue<CirclePitchScaleType> getCirclePitchScale(const optional<std::string>& klass = {}) const;
void setCirclePitchScale(PropertyValue<CirclePitchScaleType>, const optional<std::string>& klass = {});
-
- static PropertyValue<float> getDefaultCircleStrokeWidth();
- PropertyValue<float> getCircleStrokeWidth(const optional<std::string>& klass = {}) const;
- void setCircleStrokeWidth(PropertyValue<float>, const optional<std::string>& klass = {});
-
- static PropertyValue<Color> getDefaultCircleStrokeColor();
- PropertyValue<Color> getCircleStrokeColor(const optional<std::string>& klass = {}) const;
- void setCircleStrokeColor(PropertyValue<Color>, const optional<std::string>& klass = {});
-
- static PropertyValue<float> getDefaultCircleStrokeOpacity();
- PropertyValue<float> getCircleStrokeOpacity(const optional<std::string>& klass = {}) const;
- void setCircleStrokeOpacity(PropertyValue<float>, const optional<std::string>& klass = {});
+ void setCirclePitchScaleTransition(const TransitionOptions&, const optional<std::string>& klass = {});
+
+ static DataDrivenPropertyValue<float> getDefaultCircleStrokeWidth();
+ DataDrivenPropertyValue<float> getCircleStrokeWidth(const optional<std::string>& klass = {}) const;
+ void setCircleStrokeWidth(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
+ void setCircleStrokeWidthTransition(const TransitionOptions&, const optional<std::string>& klass = {});
+
+ static DataDrivenPropertyValue<Color> getDefaultCircleStrokeColor();
+ DataDrivenPropertyValue<Color> getCircleStrokeColor(const optional<std::string>& klass = {}) const;
+ void setCircleStrokeColor(DataDrivenPropertyValue<Color>, const optional<std::string>& klass = {});
+ void setCircleStrokeColorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
+
+ static DataDrivenPropertyValue<float> getDefaultCircleStrokeOpacity();
+ DataDrivenPropertyValue<float> getCircleStrokeOpacity(const optional<std::string>& klass = {}) const;
+ void setCircleStrokeOpacity(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
+ void setCircleStrokeOpacityTransition(const TransitionOptions&, const optional<std::string>& klass = {});
// Private implementation
diff --git a/include/mbgl/style/layers/fill_extrusion_layer.hpp b/include/mbgl/style/layers/fill_extrusion_layer.hpp
index 08728af309..c19a4ee168 100644
--- a/include/mbgl/style/layers/fill_extrusion_layer.hpp
+++ b/include/mbgl/style/layers/fill_extrusion_layer.hpp
@@ -5,12 +5,15 @@
#include <mbgl/style/layer.hpp>
#include <mbgl/style/filter.hpp>
#include <mbgl/style/property_value.hpp>
+#include <mbgl/style/data_driven_property_value.hpp>
#include <mbgl/util/color.hpp>
namespace mbgl {
namespace style {
+class TransitionOptions;
+
class FillExtrusionLayer : public Layer {
public:
FillExtrusionLayer(const std::string& layerID, const std::string& sourceID);
@@ -29,30 +32,37 @@ public:
static PropertyValue<float> getDefaultFillExtrusionOpacity();
PropertyValue<float> getFillExtrusionOpacity(const optional<std::string>& klass = {}) const;
void setFillExtrusionOpacity(PropertyValue<float>, const optional<std::string>& klass = {});
+ void setFillExtrusionOpacityTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<Color> getDefaultFillExtrusionColor();
- PropertyValue<Color> getFillExtrusionColor(const optional<std::string>& klass = {}) const;
- void setFillExtrusionColor(PropertyValue<Color>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<Color> getDefaultFillExtrusionColor();
+ DataDrivenPropertyValue<Color> getFillExtrusionColor(const optional<std::string>& klass = {}) const;
+ void setFillExtrusionColor(DataDrivenPropertyValue<Color>, const optional<std::string>& klass = {});
+ void setFillExtrusionColorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<std::array<float, 2>> getDefaultFillExtrusionTranslate();
PropertyValue<std::array<float, 2>> getFillExtrusionTranslate(const optional<std::string>& klass = {}) const;
void setFillExtrusionTranslate(PropertyValue<std::array<float, 2>>, const optional<std::string>& klass = {});
+ void setFillExtrusionTranslateTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<TranslateAnchorType> getDefaultFillExtrusionTranslateAnchor();
PropertyValue<TranslateAnchorType> getFillExtrusionTranslateAnchor(const optional<std::string>& klass = {}) const;
void setFillExtrusionTranslateAnchor(PropertyValue<TranslateAnchorType>, const optional<std::string>& klass = {});
+ void setFillExtrusionTranslateAnchorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<std::string> getDefaultFillExtrusionPattern();
PropertyValue<std::string> getFillExtrusionPattern(const optional<std::string>& klass = {}) const;
void setFillExtrusionPattern(PropertyValue<std::string>, const optional<std::string>& klass = {});
+ void setFillExtrusionPatternTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<float> getDefaultFillExtrusionHeight();
- PropertyValue<float> getFillExtrusionHeight(const optional<std::string>& klass = {}) const;
- void setFillExtrusionHeight(PropertyValue<float>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<float> getDefaultFillExtrusionHeight();
+ DataDrivenPropertyValue<float> getFillExtrusionHeight(const optional<std::string>& klass = {}) const;
+ void setFillExtrusionHeight(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
+ void setFillExtrusionHeightTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<float> getDefaultFillExtrusionBase();
- PropertyValue<float> getFillExtrusionBase(const optional<std::string>& klass = {}) const;
- void setFillExtrusionBase(PropertyValue<float>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<float> getDefaultFillExtrusionBase();
+ DataDrivenPropertyValue<float> getFillExtrusionBase(const optional<std::string>& klass = {}) const;
+ void setFillExtrusionBase(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
+ void setFillExtrusionBaseTransition(const TransitionOptions&, const optional<std::string>& klass = {});
// Private implementation
diff --git a/include/mbgl/style/layers/fill_layer.hpp b/include/mbgl/style/layers/fill_layer.hpp
index 4b9201641d..c064eab350 100644
--- a/include/mbgl/style/layers/fill_layer.hpp
+++ b/include/mbgl/style/layers/fill_layer.hpp
@@ -5,12 +5,15 @@
#include <mbgl/style/layer.hpp>
#include <mbgl/style/filter.hpp>
#include <mbgl/style/property_value.hpp>
+#include <mbgl/style/data_driven_property_value.hpp>
#include <mbgl/util/color.hpp>
namespace mbgl {
namespace style {
+class TransitionOptions;
+
class FillLayer : public Layer {
public:
FillLayer(const std::string& layerID, const std::string& sourceID);
@@ -29,30 +32,37 @@ public:
static PropertyValue<bool> getDefaultFillAntialias();
PropertyValue<bool> getFillAntialias(const optional<std::string>& klass = {}) const;
void setFillAntialias(PropertyValue<bool>, const optional<std::string>& klass = {});
+ void setFillAntialiasTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<float> getDefaultFillOpacity();
- PropertyValue<float> getFillOpacity(const optional<std::string>& klass = {}) const;
- void setFillOpacity(PropertyValue<float>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<float> getDefaultFillOpacity();
+ DataDrivenPropertyValue<float> getFillOpacity(const optional<std::string>& klass = {}) const;
+ void setFillOpacity(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
+ void setFillOpacityTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<Color> getDefaultFillColor();
- PropertyValue<Color> getFillColor(const optional<std::string>& klass = {}) const;
- void setFillColor(PropertyValue<Color>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<Color> getDefaultFillColor();
+ DataDrivenPropertyValue<Color> getFillColor(const optional<std::string>& klass = {}) const;
+ void setFillColor(DataDrivenPropertyValue<Color>, const optional<std::string>& klass = {});
+ void setFillColorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<Color> getDefaultFillOutlineColor();
- PropertyValue<Color> getFillOutlineColor(const optional<std::string>& klass = {}) const;
- void setFillOutlineColor(PropertyValue<Color>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<Color> getDefaultFillOutlineColor();
+ DataDrivenPropertyValue<Color> getFillOutlineColor(const optional<std::string>& klass = {}) const;
+ void setFillOutlineColor(DataDrivenPropertyValue<Color>, const optional<std::string>& klass = {});
+ void setFillOutlineColorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<std::array<float, 2>> getDefaultFillTranslate();
PropertyValue<std::array<float, 2>> getFillTranslate(const optional<std::string>& klass = {}) const;
void setFillTranslate(PropertyValue<std::array<float, 2>>, const optional<std::string>& klass = {});
+ void setFillTranslateTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<TranslateAnchorType> getDefaultFillTranslateAnchor();
PropertyValue<TranslateAnchorType> getFillTranslateAnchor(const optional<std::string>& klass = {}) const;
void setFillTranslateAnchor(PropertyValue<TranslateAnchorType>, const optional<std::string>& klass = {});
+ void setFillTranslateAnchorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<std::string> getDefaultFillPattern();
PropertyValue<std::string> getFillPattern(const optional<std::string>& klass = {}) const;
void setFillPattern(PropertyValue<std::string>, const optional<std::string>& klass = {});
+ void setFillPatternTransition(const TransitionOptions&, const optional<std::string>& klass = {});
// Private implementation
diff --git a/include/mbgl/style/layers/layer.hpp.ejs b/include/mbgl/style/layers/layer.hpp.ejs
index 15d0fcee61..d66eae8198 100644
--- a/include/mbgl/style/layers/layer.hpp.ejs
+++ b/include/mbgl/style/layers/layer.hpp.ejs
@@ -10,6 +10,7 @@
#include <mbgl/style/layer.hpp>
#include <mbgl/style/filter.hpp>
#include <mbgl/style/property_value.hpp>
+#include <mbgl/style/data_driven_property_value.hpp>
#include <mbgl/util/color.hpp>
@@ -20,6 +21,8 @@
namespace mbgl {
namespace style {
+class TransitionOptions;
+
class <%- camelize(type) %>Layer : public Layer {
public:
<% if (type === 'background') { -%>
@@ -45,18 +48,19 @@ public:
// Layout properties
<% for (const property of layoutProperties) { -%>
- static PropertyValue<<%- propertyType(property) %>> getDefault<%- camelize(property.name) %>();
- PropertyValue<<%- propertyType(property) %>> get<%- camelize(property.name) %>() const;
- void set<%- camelize(property.name) %>(PropertyValue<<%- propertyType(property) %>>);
+ static <%- propertyValueType(property) %> getDefault<%- camelize(property.name) %>();
+ <%- propertyValueType(property) %> get<%- camelize(property.name) %>() const;
+ void set<%- camelize(property.name) %>(<%- propertyValueType(property) %>);
<% } -%>
<% } -%>
// Paint properties
<% for (const property of paintProperties) { -%>
- static PropertyValue<<%- propertyType(property) %>> getDefault<%- camelize(property.name) %>();
- PropertyValue<<%- propertyType(property) %>> get<%- camelize(property.name) %>(const optional<std::string>& klass = {}) const;
- void set<%- camelize(property.name) %>(PropertyValue<<%- propertyType(property) %>>, const optional<std::string>& klass = {});
+ static <%- propertyValueType(property) %> getDefault<%- camelize(property.name) %>();
+ <%- propertyValueType(property) %> get<%- camelize(property.name) %>(const optional<std::string>& klass = {}) const;
+ void set<%- camelize(property.name) %>(<%- propertyValueType(property) %>, const optional<std::string>& klass = {});
+ void set<%- camelize(property.name) %>Transition(const TransitionOptions&, const optional<std::string>& klass = {});
<% } -%>
// Private implementation
diff --git a/include/mbgl/style/layers/line_layer.hpp b/include/mbgl/style/layers/line_layer.hpp
index c3c1026bcd..2ed269ae74 100644
--- a/include/mbgl/style/layers/line_layer.hpp
+++ b/include/mbgl/style/layers/line_layer.hpp
@@ -5,6 +5,7 @@
#include <mbgl/style/layer.hpp>
#include <mbgl/style/filter.hpp>
#include <mbgl/style/property_value.hpp>
+#include <mbgl/style/data_driven_property_value.hpp>
#include <mbgl/util/color.hpp>
@@ -13,6 +14,8 @@
namespace mbgl {
namespace style {
+class TransitionOptions;
+
class LineLayer : public Layer {
public:
LineLayer(const std::string& layerID, const std::string& sourceID);
@@ -46,45 +49,55 @@ public:
// Paint properties
- static PropertyValue<float> getDefaultLineOpacity();
- PropertyValue<float> getLineOpacity(const optional<std::string>& klass = {}) const;
- void setLineOpacity(PropertyValue<float>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<float> getDefaultLineOpacity();
+ DataDrivenPropertyValue<float> getLineOpacity(const optional<std::string>& klass = {}) const;
+ void setLineOpacity(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
+ void setLineOpacityTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<Color> getDefaultLineColor();
- PropertyValue<Color> getLineColor(const optional<std::string>& klass = {}) const;
- void setLineColor(PropertyValue<Color>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<Color> getDefaultLineColor();
+ DataDrivenPropertyValue<Color> getLineColor(const optional<std::string>& klass = {}) const;
+ void setLineColor(DataDrivenPropertyValue<Color>, const optional<std::string>& klass = {});
+ void setLineColorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<std::array<float, 2>> getDefaultLineTranslate();
PropertyValue<std::array<float, 2>> getLineTranslate(const optional<std::string>& klass = {}) const;
void setLineTranslate(PropertyValue<std::array<float, 2>>, const optional<std::string>& klass = {});
+ void setLineTranslateTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<TranslateAnchorType> getDefaultLineTranslateAnchor();
PropertyValue<TranslateAnchorType> getLineTranslateAnchor(const optional<std::string>& klass = {}) const;
void setLineTranslateAnchor(PropertyValue<TranslateAnchorType>, const optional<std::string>& klass = {});
+ void setLineTranslateAnchorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<float> getDefaultLineWidth();
PropertyValue<float> getLineWidth(const optional<std::string>& klass = {}) const;
void setLineWidth(PropertyValue<float>, const optional<std::string>& klass = {});
+ void setLineWidthTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<float> getDefaultLineGapWidth();
- PropertyValue<float> getLineGapWidth(const optional<std::string>& klass = {}) const;
- void setLineGapWidth(PropertyValue<float>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<float> getDefaultLineGapWidth();
+ DataDrivenPropertyValue<float> getLineGapWidth(const optional<std::string>& klass = {}) const;
+ void setLineGapWidth(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
+ void setLineGapWidthTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<float> getDefaultLineOffset();
- PropertyValue<float> getLineOffset(const optional<std::string>& klass = {}) const;
- void setLineOffset(PropertyValue<float>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<float> getDefaultLineOffset();
+ DataDrivenPropertyValue<float> getLineOffset(const optional<std::string>& klass = {}) const;
+ void setLineOffset(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
+ void setLineOffsetTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<float> getDefaultLineBlur();
- PropertyValue<float> getLineBlur(const optional<std::string>& klass = {}) const;
- void setLineBlur(PropertyValue<float>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<float> getDefaultLineBlur();
+ DataDrivenPropertyValue<float> getLineBlur(const optional<std::string>& klass = {}) const;
+ void setLineBlur(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
+ void setLineBlurTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<std::vector<float>> getDefaultLineDasharray();
PropertyValue<std::vector<float>> getLineDasharray(const optional<std::string>& klass = {}) const;
void setLineDasharray(PropertyValue<std::vector<float>>, const optional<std::string>& klass = {});
+ void setLineDasharrayTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<std::string> getDefaultLinePattern();
PropertyValue<std::string> getLinePattern(const optional<std::string>& klass = {}) const;
void setLinePattern(PropertyValue<std::string>, const optional<std::string>& klass = {});
+ void setLinePatternTransition(const TransitionOptions&, const optional<std::string>& klass = {});
// Private implementation
diff --git a/include/mbgl/style/layers/raster_layer.hpp b/include/mbgl/style/layers/raster_layer.hpp
index ae6ec7f91c..72665baa72 100644
--- a/include/mbgl/style/layers/raster_layer.hpp
+++ b/include/mbgl/style/layers/raster_layer.hpp
@@ -5,12 +5,15 @@
#include <mbgl/style/layer.hpp>
#include <mbgl/style/filter.hpp>
#include <mbgl/style/property_value.hpp>
+#include <mbgl/style/data_driven_property_value.hpp>
#include <mbgl/util/color.hpp>
namespace mbgl {
namespace style {
+class TransitionOptions;
+
class RasterLayer : public Layer {
public:
RasterLayer(const std::string& layerID, const std::string& sourceID);
@@ -24,30 +27,37 @@ public:
static PropertyValue<float> getDefaultRasterOpacity();
PropertyValue<float> getRasterOpacity(const optional<std::string>& klass = {}) const;
void setRasterOpacity(PropertyValue<float>, const optional<std::string>& klass = {});
+ void setRasterOpacityTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<float> getDefaultRasterHueRotate();
PropertyValue<float> getRasterHueRotate(const optional<std::string>& klass = {}) const;
void setRasterHueRotate(PropertyValue<float>, const optional<std::string>& klass = {});
+ void setRasterHueRotateTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<float> getDefaultRasterBrightnessMin();
PropertyValue<float> getRasterBrightnessMin(const optional<std::string>& klass = {}) const;
void setRasterBrightnessMin(PropertyValue<float>, const optional<std::string>& klass = {});
+ void setRasterBrightnessMinTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<float> getDefaultRasterBrightnessMax();
PropertyValue<float> getRasterBrightnessMax(const optional<std::string>& klass = {}) const;
void setRasterBrightnessMax(PropertyValue<float>, const optional<std::string>& klass = {});
+ void setRasterBrightnessMaxTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<float> getDefaultRasterSaturation();
PropertyValue<float> getRasterSaturation(const optional<std::string>& klass = {}) const;
void setRasterSaturation(PropertyValue<float>, const optional<std::string>& klass = {});
+ void setRasterSaturationTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<float> getDefaultRasterContrast();
PropertyValue<float> getRasterContrast(const optional<std::string>& klass = {}) const;
void setRasterContrast(PropertyValue<float>, const optional<std::string>& klass = {});
+ void setRasterContrastTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<float> getDefaultRasterFadeDuration();
PropertyValue<float> getRasterFadeDuration(const optional<std::string>& klass = {}) const;
void setRasterFadeDuration(PropertyValue<float>, const optional<std::string>& klass = {});
+ void setRasterFadeDurationTransition(const TransitionOptions&, const optional<std::string>& klass = {});
// Private implementation
diff --git a/include/mbgl/style/layers/symbol_layer.hpp b/include/mbgl/style/layers/symbol_layer.hpp
index 1e2e6ac454..aeccabb97e 100644
--- a/include/mbgl/style/layers/symbol_layer.hpp
+++ b/include/mbgl/style/layers/symbol_layer.hpp
@@ -5,6 +5,7 @@
#include <mbgl/style/layer.hpp>
#include <mbgl/style/filter.hpp>
#include <mbgl/style/property_value.hpp>
+#include <mbgl/style/data_driven_property_value.hpp>
#include <mbgl/util/color.hpp>
@@ -13,6 +14,8 @@
namespace mbgl {
namespace style {
+class TransitionOptions;
+
class SymbolLayer : public Layer {
public:
SymbolLayer(const std::string& layerID, const std::string& sourceID);
@@ -72,9 +75,9 @@ public:
PropertyValue<std::string> getIconImage() const;
void setIconImage(PropertyValue<std::string>);
- static PropertyValue<float> getDefaultIconRotate();
- PropertyValue<float> getIconRotate() const;
- void setIconRotate(PropertyValue<float>);
+ static DataDrivenPropertyValue<float> getDefaultIconRotate();
+ DataDrivenPropertyValue<float> getIconRotate() const;
+ void setIconRotate(DataDrivenPropertyValue<float>);
static PropertyValue<float> getDefaultIconPadding();
PropertyValue<float> getIconPadding() const;
@@ -84,9 +87,9 @@ public:
PropertyValue<bool> getIconKeepUpright() const;
void setIconKeepUpright(PropertyValue<bool>);
- static PropertyValue<std::array<float, 2>> getDefaultIconOffset();
- PropertyValue<std::array<float, 2>> getIconOffset() const;
- void setIconOffset(PropertyValue<std::array<float, 2>>);
+ static DataDrivenPropertyValue<std::array<float, 2>> getDefaultIconOffset();
+ DataDrivenPropertyValue<std::array<float, 2>> getIconOffset() const;
+ void setIconOffset(DataDrivenPropertyValue<std::array<float, 2>>);
static PropertyValue<AlignmentType> getDefaultTextPitchAlignment();
PropertyValue<AlignmentType> getTextPitchAlignment() const;
@@ -96,9 +99,9 @@ public:
PropertyValue<AlignmentType> getTextRotationAlignment() const;
void setTextRotationAlignment(PropertyValue<AlignmentType>);
- static PropertyValue<std::string> getDefaultTextField();
- PropertyValue<std::string> getTextField() const;
- void setTextField(PropertyValue<std::string>);
+ static DataDrivenPropertyValue<std::string> getDefaultTextField();
+ DataDrivenPropertyValue<std::string> getTextField() const;
+ void setTextField(DataDrivenPropertyValue<std::string>);
static PropertyValue<std::vector<std::string>> getDefaultTextFont();
PropertyValue<std::vector<std::string>> getTextFont() const;
@@ -144,9 +147,9 @@ public:
PropertyValue<bool> getTextKeepUpright() const;
void setTextKeepUpright(PropertyValue<bool>);
- static PropertyValue<TextTransformType> getDefaultTextTransform();
- PropertyValue<TextTransformType> getTextTransform() const;
- void setTextTransform(PropertyValue<TextTransformType>);
+ static DataDrivenPropertyValue<TextTransformType> getDefaultTextTransform();
+ DataDrivenPropertyValue<TextTransformType> getTextTransform() const;
+ void setTextTransform(DataDrivenPropertyValue<TextTransformType>);
static PropertyValue<std::array<float, 2>> getDefaultTextOffset();
PropertyValue<std::array<float, 2>> getTextOffset() const;
@@ -166,61 +169,75 @@ public:
// Paint properties
- static PropertyValue<float> getDefaultIconOpacity();
- PropertyValue<float> getIconOpacity(const optional<std::string>& klass = {}) const;
- void setIconOpacity(PropertyValue<float>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<float> getDefaultIconOpacity();
+ DataDrivenPropertyValue<float> getIconOpacity(const optional<std::string>& klass = {}) const;
+ void setIconOpacity(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
+ void setIconOpacityTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<Color> getDefaultIconColor();
- PropertyValue<Color> getIconColor(const optional<std::string>& klass = {}) const;
- void setIconColor(PropertyValue<Color>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<Color> getDefaultIconColor();
+ DataDrivenPropertyValue<Color> getIconColor(const optional<std::string>& klass = {}) const;
+ void setIconColor(DataDrivenPropertyValue<Color>, const optional<std::string>& klass = {});
+ void setIconColorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<Color> getDefaultIconHaloColor();
- PropertyValue<Color> getIconHaloColor(const optional<std::string>& klass = {}) const;
- void setIconHaloColor(PropertyValue<Color>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<Color> getDefaultIconHaloColor();
+ DataDrivenPropertyValue<Color> getIconHaloColor(const optional<std::string>& klass = {}) const;
+ void setIconHaloColor(DataDrivenPropertyValue<Color>, const optional<std::string>& klass = {});
+ void setIconHaloColorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<float> getDefaultIconHaloWidth();
- PropertyValue<float> getIconHaloWidth(const optional<std::string>& klass = {}) const;
- void setIconHaloWidth(PropertyValue<float>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<float> getDefaultIconHaloWidth();
+ DataDrivenPropertyValue<float> getIconHaloWidth(const optional<std::string>& klass = {}) const;
+ void setIconHaloWidth(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
+ void setIconHaloWidthTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<float> getDefaultIconHaloBlur();
- PropertyValue<float> getIconHaloBlur(const optional<std::string>& klass = {}) const;
- void setIconHaloBlur(PropertyValue<float>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<float> getDefaultIconHaloBlur();
+ DataDrivenPropertyValue<float> getIconHaloBlur(const optional<std::string>& klass = {}) const;
+ void setIconHaloBlur(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
+ void setIconHaloBlurTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<std::array<float, 2>> getDefaultIconTranslate();
PropertyValue<std::array<float, 2>> getIconTranslate(const optional<std::string>& klass = {}) const;
void setIconTranslate(PropertyValue<std::array<float, 2>>, const optional<std::string>& klass = {});
+ void setIconTranslateTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<TranslateAnchorType> getDefaultIconTranslateAnchor();
PropertyValue<TranslateAnchorType> getIconTranslateAnchor(const optional<std::string>& klass = {}) const;
void setIconTranslateAnchor(PropertyValue<TranslateAnchorType>, const optional<std::string>& klass = {});
+ void setIconTranslateAnchorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<float> getDefaultTextOpacity();
- PropertyValue<float> getTextOpacity(const optional<std::string>& klass = {}) const;
- void setTextOpacity(PropertyValue<float>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<float> getDefaultTextOpacity();
+ DataDrivenPropertyValue<float> getTextOpacity(const optional<std::string>& klass = {}) const;
+ void setTextOpacity(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
+ void setTextOpacityTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<Color> getDefaultTextColor();
- PropertyValue<Color> getTextColor(const optional<std::string>& klass = {}) const;
- void setTextColor(PropertyValue<Color>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<Color> getDefaultTextColor();
+ DataDrivenPropertyValue<Color> getTextColor(const optional<std::string>& klass = {}) const;
+ void setTextColor(DataDrivenPropertyValue<Color>, const optional<std::string>& klass = {});
+ void setTextColorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<Color> getDefaultTextHaloColor();
- PropertyValue<Color> getTextHaloColor(const optional<std::string>& klass = {}) const;
- void setTextHaloColor(PropertyValue<Color>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<Color> getDefaultTextHaloColor();
+ DataDrivenPropertyValue<Color> getTextHaloColor(const optional<std::string>& klass = {}) const;
+ void setTextHaloColor(DataDrivenPropertyValue<Color>, const optional<std::string>& klass = {});
+ void setTextHaloColorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<float> getDefaultTextHaloWidth();
- PropertyValue<float> getTextHaloWidth(const optional<std::string>& klass = {}) const;
- void setTextHaloWidth(PropertyValue<float>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<float> getDefaultTextHaloWidth();
+ DataDrivenPropertyValue<float> getTextHaloWidth(const optional<std::string>& klass = {}) const;
+ void setTextHaloWidth(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
+ void setTextHaloWidthTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<float> getDefaultTextHaloBlur();
- PropertyValue<float> getTextHaloBlur(const optional<std::string>& klass = {}) const;
- void setTextHaloBlur(PropertyValue<float>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<float> getDefaultTextHaloBlur();
+ DataDrivenPropertyValue<float> getTextHaloBlur(const optional<std::string>& klass = {}) const;
+ void setTextHaloBlur(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
+ void setTextHaloBlurTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<std::array<float, 2>> getDefaultTextTranslate();
PropertyValue<std::array<float, 2>> getTextTranslate(const optional<std::string>& klass = {}) const;
void setTextTranslate(PropertyValue<std::array<float, 2>>, const optional<std::string>& klass = {});
+ void setTextTranslateTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<TranslateAnchorType> getDefaultTextTranslateAnchor();
PropertyValue<TranslateAnchorType> getTextTranslateAnchor(const optional<std::string>& klass = {}) const;
void setTextTranslateAnchor(PropertyValue<TranslateAnchorType>, const optional<std::string>& klass = {});
+ void setTextTranslateAnchorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
// Private implementation
diff --git a/include/mbgl/style/property_value.hpp b/include/mbgl/style/property_value.hpp
index 83c4b4cf1b..e784633aa7 100644
--- a/include/mbgl/style/property_value.hpp
+++ b/include/mbgl/style/property_value.hpp
@@ -1,20 +1,16 @@
#pragma once
#include <mbgl/util/variant.hpp>
-#include <mbgl/style/function.hpp>
+#include <mbgl/style/undefined.hpp>
+#include <mbgl/style/function/camera_function.hpp>
namespace mbgl {
namespace style {
-class Undefined {};
-
-inline bool operator==(const Undefined&, const Undefined&) { return true; }
-inline bool operator!=(const Undefined&, const Undefined&) { return false; }
-
template <class T>
class PropertyValue {
private:
- using Value = variant<Undefined, T, Function<T>>;
+ using Value = variant<Undefined, T, CameraFunction<T>>;
Value value;
friend bool operator==(const PropertyValue& lhs, const PropertyValue& rhs) {
@@ -26,16 +22,16 @@ private:
}
public:
- PropertyValue() : value() {}
- PropertyValue( T constant) : value(constant) {}
- PropertyValue(Function<T> function) : value(function) {}
+ PropertyValue() : value() {}
+ PropertyValue( T constant) : value(constant) {}
+ PropertyValue(CameraFunction<T> function) : value(function) {}
- bool isUndefined() const { return value.which() == 0; }
- bool isConstant() const { return value.which() == 1; }
- bool isFunction() const { return value.which() == 2; }
+ bool isUndefined() const { return value.which() == 0; }
+ bool isConstant() const { return value.which() == 1; }
+ bool isCameraFunction() const { return value.which() == 2; }
- const T & asConstant() const { return value.template get< T >(); }
- const Function<T>& asFunction() const { return value.template get<Function<T>>(); }
+ const T & asConstant() const { return value.template get< T >(); }
+ const CameraFunction<T>& asCameraFunction() const { return value.template get<CameraFunction<T>>(); }
explicit operator bool() const { return !isUndefined(); };
diff --git a/include/mbgl/style/undefined.hpp b/include/mbgl/style/undefined.hpp
new file mode 100644
index 0000000000..e43f132a80
--- /dev/null
+++ b/include/mbgl/style/undefined.hpp
@@ -0,0 +1,12 @@
+#pragma once
+
+namespace mbgl {
+namespace style {
+
+class Undefined {};
+
+inline bool operator==(const Undefined&, const Undefined&) { return true; }
+inline bool operator!=(const Undefined&, const Undefined&) { return false; }
+
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/util/chrono.hpp b/include/mbgl/util/chrono.hpp
index 4adf030331..723cd131e3 100644
--- a/include/mbgl/util/chrono.hpp
+++ b/include/mbgl/util/chrono.hpp
@@ -29,7 +29,7 @@ std::string rfc1123(Timestamp);
std::string iso8601(Timestamp);
Timestamp parseTimestamp(const char *);
-
+
Timestamp parseTimestamp(const int32_t timestamp);
// C++17 polyfill
diff --git a/include/mbgl/util/compression.hpp b/include/mbgl/util/compression.hpp
index 5e232187c3..93a3ddb8bc 100644
--- a/include/mbgl/util/compression.hpp
+++ b/include/mbgl/util/compression.hpp
@@ -4,9 +4,9 @@
namespace mbgl {
namespace util {
-
+
std::string compress(const std::string& raw);
std::string decompress(const std::string& raw);
-
+
} // namespace util
} // namespace mbgl
diff --git a/include/mbgl/util/constants.hpp b/include/mbgl/util/constants.hpp
index 85e19c2ff0..0f2779e33b 100644
--- a/include/mbgl/util/constants.hpp
+++ b/include/mbgl/util/constants.hpp
@@ -44,11 +44,11 @@ constexpr Duration DEFAULT_FADE_DURATION = Milliseconds(300);
constexpr Seconds CLOCK_SKEW_RETRY_TIMEOUT { 30 };
constexpr UnitBezier DEFAULT_TRANSITION_EASE = { 0, 0, 0.25, 1 };
-
+
constexpr int DEFAULT_RATE_LIMIT_TIMEOUT = 5;
constexpr const char* API_BASE_URL = "https://api.mapbox.com";
-
+
} // namespace util
namespace debug {
diff --git a/include/mbgl/util/feature.hpp b/include/mbgl/util/feature.hpp
index b72aa15ddd..4eeceda944 100644
--- a/include/mbgl/util/feature.hpp
+++ b/include/mbgl/util/feature.hpp
@@ -12,4 +12,21 @@ using PropertyMap = mapbox::geometry::property_map;
using FeatureIdentifier = mapbox::geometry::identifier;
using Feature = mapbox::geometry::feature<double>;
+template <class T>
+optional<T> numericValue(const Value& value) {
+ return value.match(
+ [] (uint64_t t) {
+ return optional<T>(t);
+ },
+ [] (int64_t t) {
+ return optional<T>(t);
+ },
+ [] (double t) {
+ return optional<T>(t);
+ },
+ [] (auto) {
+ return optional<T>();
+ });
+}
+
} // namespace mbgl
diff --git a/include/mbgl/util/geo.hpp b/include/mbgl/util/geo.hpp
index 9dca10eb84..57a028e467 100644
--- a/include/mbgl/util/geo.hpp
+++ b/include/mbgl/util/geo.hpp
@@ -187,10 +187,10 @@ enum class NorthOrientation : uint8_t {
/// The distance on each side between a rectangle and a rectangle within.
class EdgeInsets {
public:
- double top = 0; ///< Number of pixels inset from the top edge.
- double left = 0; ///< Number of pixels inset from the left edge.
- double bottom = 0; ///< Number of pixels inset from the bottom edge.
- double right = 0; ///< Number of pixels inset from the right edge.
+ double top = 0; // Number of pixels inset from the top edge.
+ double left = 0; // Number of pixels inset from the left edge.
+ double bottom = 0; // Number of pixels inset from the bottom edge.
+ double right = 0; // Number of pixels inset from the right edge.
EdgeInsets() {}
diff --git a/include/mbgl/util/image.hpp b/include/mbgl/util/image.hpp
index 1d84d4824a..5d1462e7c4 100644
--- a/include/mbgl/util/image.hpp
+++ b/include/mbgl/util/image.hpp
@@ -1,6 +1,7 @@
#pragma once
#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/geometry.hpp>
#include <mbgl/util/size.hpp>
#include <string>
@@ -24,6 +25,15 @@ public:
: size(std::move(size_)),
data(std::make_unique<uint8_t[]>(bytes())) {}
+ Image(Size size_, const uint8_t* srcData, std::size_t srcLength)
+ : size(std::move(size_)) {
+ if (srcLength != bytes()) {
+ throw std::invalid_argument("mismatched image size");
+ }
+ data = std::make_unique<uint8_t[]>(bytes());
+ std::copy(srcData, srcData + srcLength, data.get());
+ }
+
Image(Size size_, std::unique_ptr<uint8_t[]> data_)
: size(std::move(size_)),
data(std::move(data_)) {}
@@ -38,19 +48,73 @@ public:
return *this;
}
- bool operator==(const Image& rhs) const {
- return size == rhs.size &&
- std::equal(data.get(), data.get() + bytes(), rhs.data.get(),
- rhs.data.get() + rhs.bytes());
+ friend bool operator==(const Image& lhs, const Image& rhs) {
+ return std::equal(lhs.data.get(), lhs.data.get() + lhs.bytes(),
+ rhs.data.get(), rhs.data.get() + rhs.bytes());
+ }
+
+ friend bool operator!=(const Image& lhs, const Image& rhs) {
+ return !(lhs == rhs);
}
bool valid() const {
return size && data.get() != nullptr;
}
+ template <typename T = Image>
+ T clone() const {
+ T copy(size);
+ std::copy(data.get(), data.get() + bytes(), copy.data.get());
+ return copy;
+ }
+
size_t stride() const { return channels * size.width; }
size_t bytes() const { return stride() * size.height; }
+ void fill(uint8_t value) {
+ std::fill(data.get(), data.get() + bytes(), value);
+ }
+
+ // Copy image data within `rect` from `src` to the rectangle of the same size at `pt`
+ // in `dst`. If the specified bounds exceed the bounds of the source or destination,
+ // throw `std::out_of_range`. Must not be used to move data within a single Image.
+ static void copy(const Image& srcImg, Image& dstImg, const Point<uint32_t>& srcPt, const Point<uint32_t>& dstPt, const Size& size) {
+ if (!srcImg.valid()) {
+ throw std::invalid_argument("invalid source for image copy");
+ }
+
+ if (!dstImg.valid()) {
+ throw std::invalid_argument("invalid destination for image copy");
+ }
+
+ if (size.width > srcImg.size.width ||
+ size.height > srcImg.size.height ||
+ srcPt.x > srcImg.size.width - size.width ||
+ srcPt.y > srcImg.size.height - size.height) {
+ throw std::out_of_range("out of range source coordinates for image copy");
+ }
+
+ if (size.width > dstImg.size.width ||
+ size.height > dstImg.size.height ||
+ dstPt.x > dstImg.size.width - size.width ||
+ dstPt.y > dstImg.size.height - size.height) {
+ throw std::out_of_range("out of range destination coordinates for image copy");
+ }
+
+ const uint8_t* srcData = srcImg.data.get();
+ uint8_t* dstData = dstImg.data.get();
+
+ assert(srcData != dstData);
+
+ for (uint32_t y = 0; y < size.height; y++) {
+ const std::size_t srcOffset = (srcPt.y + y) * srcImg.stride() + srcPt.x * channels;
+ const std::size_t dstOffset = (dstPt.y + y) * dstImg.stride() + dstPt.x * channels;
+ std::copy(srcData + srcOffset,
+ srcData + srcOffset + size.width * channels,
+ dstData + dstOffset);
+ }
+ }
+
Size size;
static constexpr size_t channels = Mode == ImageAlphaMode::Exclusive ? 1 : 4;
std::unique_ptr<uint8_t[]> data;
diff --git a/include/mbgl/util/size.hpp b/include/mbgl/util/size.hpp
index 1af85bcff5..79679a92fb 100644
--- a/include/mbgl/util/size.hpp
+++ b/include/mbgl/util/size.hpp
@@ -13,6 +13,10 @@ public:
constexpr Size(const uint32_t width_, const uint32_t height_) : width(width_), height(height_) {
}
+ constexpr uint32_t area() const {
+ return width * height;
+ }
+
constexpr explicit operator bool() const {
return width > 0 && height > 0;
}