summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/mbgl/annotation/annotation.hpp13
-rw-r--r--include/mbgl/gl/gl.hpp10
-rw-r--r--include/mbgl/gl/gl_helper.hpp4
-rw-r--r--include/mbgl/gl/gl_values.hpp134
-rw-r--r--include/mbgl/map/camera.hpp30
-rw-r--r--include/mbgl/map/map.hpp10
-rw-r--r--include/mbgl/map/mode.hpp17
-rw-r--r--include/mbgl/map/update.hpp12
-rw-r--r--include/mbgl/map/view.hpp1
-rw-r--r--include/mbgl/platform/darwin/settings_nsuserdefaults.hpp27
-rw-r--r--include/mbgl/platform/default/glfw_view.hpp4
-rw-r--r--include/mbgl/platform/default/headless_view.hpp4
-rw-r--r--include/mbgl/platform/event.hpp31
-rw-r--r--include/mbgl/platform/log.hpp10
-rw-r--r--include/mbgl/platform/platform.hpp6
-rw-r--r--include/mbgl/storage/default_file_source.hpp4
-rw-r--r--include/mbgl/storage/file_source.hpp8
-rw-r--r--include/mbgl/storage/network_status.hpp5
-rw-r--r--include/mbgl/storage/offline.hpp10
-rw-r--r--include/mbgl/storage/resource.hpp4
-rw-r--r--include/mbgl/storage/response.hpp2
-rw-r--r--include/mbgl/style/conversion.hpp95
-rw-r--r--include/mbgl/style/conversion/constant.hpp174
-rw-r--r--include/mbgl/style/conversion/filter.hpp150
-rw-r--r--include/mbgl/style/conversion/function.hpp69
-rw-r--r--include/mbgl/style/conversion/geojson.hpp15
-rw-r--r--include/mbgl/style/conversion/layer.hpp208
-rw-r--r--include/mbgl/style/conversion/make_property_setters.hpp136
-rw-r--r--include/mbgl/style/conversion/make_property_setters.hpp.ejs47
-rw-r--r--include/mbgl/style/conversion/property_setter.hpp57
-rw-r--r--include/mbgl/style/conversion/property_value.hpp36
-rw-r--r--include/mbgl/style/conversion/source.hpp182
-rw-r--r--include/mbgl/style/conversion/tileset.hpp67
-rw-r--r--include/mbgl/style/filter.hpp44
-rw-r--r--include/mbgl/style/filter_evaluator.hpp212
-rw-r--r--include/mbgl/style/function.hpp4
-rw-r--r--include/mbgl/style/layer.hpp5
-rw-r--r--include/mbgl/style/layers/background_layer.hpp6
-rw-r--r--include/mbgl/style/layers/circle_layer.hpp20
-rw-r--r--include/mbgl/style/layers/fill_layer.hpp19
-rw-r--r--include/mbgl/style/layers/layer.hpp.ejs75
-rw-r--r--include/mbgl/style/layers/line_layer.hpp25
-rw-r--r--include/mbgl/style/layers/raster_layer.hpp18
-rw-r--r--include/mbgl/style/layers/symbol_layer.hpp50
-rw-r--r--include/mbgl/style/source.hpp63
-rw-r--r--include/mbgl/style/sources/geojson_source.hpp54
-rw-r--r--include/mbgl/style/sources/raster_source.hpp20
-rw-r--r--include/mbgl/style/sources/vector_source.hpp20
-rw-r--r--include/mbgl/style/transition_options.hpp10
-rw-r--r--include/mbgl/style/types.hpp25
-rw-r--r--include/mbgl/util/char_array_buffer.hpp55
-rw-r--r--include/mbgl/util/color.hpp34
-rw-r--r--include/mbgl/util/constants.hpp7
-rw-r--r--include/mbgl/util/convert.hpp17
-rw-r--r--include/mbgl/util/enum.hpp60
-rw-r--r--include/mbgl/util/exception.hpp16
-rw-r--r--include/mbgl/util/feature.hpp12
-rw-r--r--include/mbgl/util/geo.hpp32
-rw-r--r--include/mbgl/util/geojson.hpp10
-rw-r--r--include/mbgl/util/geometry.hpp24
-rw-r--r--include/mbgl/util/projection.hpp14
-rw-r--r--include/mbgl/util/range.hpp25
-rw-r--r--include/mbgl/util/run_loop.hpp10
-rw-r--r--include/mbgl/util/tileset.hpp20
-rw-r--r--include/mbgl/util/traits.hpp4
-rw-r--r--include/mbgl/util/unitbezier.hpp39
66 files changed, 2249 insertions, 382 deletions
diff --git a/include/mbgl/annotation/annotation.hpp b/include/mbgl/annotation/annotation.hpp
index 6cb26e6a82..a72c65b8c4 100644
--- a/include/mbgl/annotation/annotation.hpp
+++ b/include/mbgl/annotation/annotation.hpp
@@ -3,6 +3,7 @@
#include <mbgl/util/geometry.hpp>
#include <mbgl/util/variant.hpp>
#include <mbgl/util/color.hpp>
+#include <mbgl/style/property_value.hpp>
#include <cstdint>
#include <vector>
@@ -28,17 +29,17 @@ using ShapeAnnotationGeometry = variant<
class LineAnnotation {
public:
ShapeAnnotationGeometry geometry;
- float opacity = 1;
- float width = 1;
- Color color = {{ 0, 0, 0, 1 }};
+ style::PropertyValue<float> opacity { 1.0f };
+ style::PropertyValue<float> width { 1.0f };
+ style::PropertyValue<Color> color { Color::black() };
};
class FillAnnotation {
public:
ShapeAnnotationGeometry geometry;
- float opacity = 1;
- Color color = {{ 0, 0, 0, 1 }};
- Color outlineColor = {{ 0, 0, 0, -1 }};
+ style::PropertyValue<float> opacity { 1.0f };
+ style::PropertyValue<Color> color { Color::black() };
+ style::PropertyValue<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 6d601d8a23..d033fef549 100644
--- a/include/mbgl/gl/gl.hpp
+++ b/include/mbgl/gl/gl.hpp
@@ -45,9 +45,9 @@ namespace gl {
GLsizei length,
const GLchar *message,
const void *userParam);
-
+
template <class... Args> void mbx_trapExtension(const char *name, Args... args);
-
+
void mbx_trapExtension(const char *);
void mbx_trapExtension(const char *, GLint, const char *);
void mbx_trapExtension(const char *, GLsizei, GLuint *);
@@ -58,16 +58,16 @@ namespace gl {
void mbx_trapExtension(const char *, GLuint, GLuint, GLuint, GLuint, GLint, const char *, const void*);
void mbx_trapExtension(const char *name, GLuint array);
#endif
-
+
struct Error : ::std::runtime_error {
- inline Error(GLenum err, const std::string &msg) : ::std::runtime_error(msg), code(err) {};
+ Error(GLenum err, const std::string &msg) : ::std::runtime_error(msg), code(err) {};
const GLenum code;
};
void checkError(const char *cmd, const char *file, int line);
#if defined(DEBUG)
-#define MBGL_CHECK_ERROR(cmd) ([&]() { struct __MBGL_C_E { inline ~__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() { ::mbgl::gl::checkError(#cmd, __FILE__, __LINE__); } } __MBGL_C_E; return cmd; }())
#else
#define MBGL_CHECK_ERROR(cmd) (cmd)
#endif
diff --git a/include/mbgl/gl/gl_helper.hpp b/include/mbgl/gl/gl_helper.hpp
index 893c73e0c3..9d46d018c3 100644
--- a/include/mbgl/gl/gl_helper.hpp
+++ b/include/mbgl/gl/gl_helper.hpp
@@ -6,9 +6,9 @@ namespace gl {
template <typename T>
class Preserve {
public:
- inline Preserve() : data(T::Get()) {
+ Preserve() : data(T::Get()) {
}
- inline ~Preserve() {
+ ~Preserve() {
T::Set(data);
}
diff --git a/include/mbgl/gl/gl_values.hpp b/include/mbgl/gl/gl_values.hpp
index 4204ca8e13..29a5281cca 100644
--- a/include/mbgl/gl/gl_values.hpp
+++ b/include/mbgl/gl/gl_values.hpp
@@ -3,8 +3,10 @@
#include <cstdint>
#include <tuple>
#include <array>
+#include <cassert>
#include <mbgl/gl/gl.hpp>
+#include <mbgl/util/color.hpp>
namespace mbgl {
namespace gl {
@@ -12,10 +14,10 @@ namespace gl {
struct ClearDepth {
using Type = GLfloat;
static const Type Default;
- inline static void Set(const Type& value) {
+ static void Set(const Type& value) {
MBGL_CHECK_ERROR(glClearDepth(value));
}
- inline static Type Get() {
+ static Type Get() {
Type clearDepth;
MBGL_CHECK_ERROR(glGetFloatv(GL_DEPTH_CLEAR_VALUE, &clearDepth));
return clearDepth;
@@ -23,29 +25,25 @@ struct ClearDepth {
};
struct ClearColor {
- struct Type { GLfloat r, g, b, a; };
+ using Type = Color;
static const Type Default;
- inline static void Set(const Type& value) {
+ static void Set(const Type& value) {
MBGL_CHECK_ERROR(glClearColor(value.r, value.g, value.b, value.a));
}
- inline static Type Get() {
+ static Type Get() {
GLfloat floats[4];
MBGL_CHECK_ERROR(glGetFloatv(GL_COLOR_CLEAR_VALUE, floats));
return { floats[0], floats[1], floats[2], floats[3] };
}
};
-inline bool operator!=(const ClearColor::Type& a, const ClearColor::Type& b) {
- return a.r != b.r || a.g != b.g || a.b != b.b || a.a != b.a;
-}
-
struct ClearStencil {
using Type = GLint;
static const Type Default;
- inline static void Set(const Type& value) {
+ static void Set(const Type& value) {
MBGL_CHECK_ERROR(glClearStencil(value));
}
- inline static Type Get() {
+ static Type Get() {
Type clearStencil;
MBGL_CHECK_ERROR(glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &clearStencil));
return clearStencil;
@@ -55,10 +53,10 @@ struct ClearStencil {
struct StencilMask {
using Type = GLuint;
static const Type Default;
- inline static void Set(const Type& value) {
+ static void Set(const Type& value) {
MBGL_CHECK_ERROR(glStencilMask(value));
}
- inline static Type Get() {
+ static Type Get() {
GLint stencilMask;
MBGL_CHECK_ERROR(glGetIntegerv(GL_STENCIL_WRITEMASK, &stencilMask));
return stencilMask;
@@ -68,10 +66,10 @@ struct StencilMask {
struct DepthMask {
using Type = GLboolean;
static const Type Default;
- inline static void Set(const Type& value) {
+ static void Set(const Type& value) {
MBGL_CHECK_ERROR(glDepthMask(value));
}
- inline static Type Get() {
+ static Type Get() {
Type depthMask;
MBGL_CHECK_ERROR(glGetBooleanv(GL_DEPTH_WRITEMASK, &depthMask));
return depthMask;
@@ -81,10 +79,10 @@ struct DepthMask {
struct ColorMask {
struct Type { bool r, g, b, a; };
static const Type Default;
- inline static void Set(const Type& value) {
+ static void Set(const Type& value) {
MBGL_CHECK_ERROR(glColorMask(value.r, value.g, value.b, value.a));
}
- inline static Type Get() {
+ static Type Get() {
GLboolean bools[4];
MBGL_CHECK_ERROR(glGetBooleanv(GL_COLOR_WRITEMASK, bools));
return { static_cast<bool>(bools[0]), static_cast<bool>(bools[1]),
@@ -92,17 +90,17 @@ struct ColorMask {
}
};
-inline bool operator!=(const ColorMask::Type& a, const ColorMask::Type& b) {
+constexpr bool operator!=(const ColorMask::Type& a, const ColorMask::Type& b) {
return a.r != b.r || a.g != b.g || a.b != b.b || a.a != b.a;
}
struct StencilFunc {
struct Type { GLenum func; GLint ref; GLuint mask; };
static const Type Default;
- inline static void Set(const Type& value) {
+ static void Set(const Type& value) {
MBGL_CHECK_ERROR(glStencilFunc(value.func, value.ref, value.mask));
}
- inline static Type Get() {
+ static Type Get() {
GLint func, ref, mask;
MBGL_CHECK_ERROR(glGetIntegerv(GL_STENCIL_FUNC, &func));
MBGL_CHECK_ERROR(glGetIntegerv(GL_STENCIL_REF, &ref));
@@ -111,17 +109,17 @@ struct StencilFunc {
}
};
-inline bool operator!=(const StencilFunc::Type& a, const StencilFunc::Type& b) {
+constexpr bool operator!=(const StencilFunc::Type& a, const StencilFunc::Type& b) {
return a.func != b.func || a.ref != b.ref || a.mask != b.mask;
}
struct StencilTest {
using Type = bool;
static const Type Default;
- inline static void Set(const Type& value) {
+ static void Set(const Type& value) {
MBGL_CHECK_ERROR(value ? glEnable(GL_STENCIL_TEST) : glDisable(GL_STENCIL_TEST));
}
- inline static Type Get() {
+ static Type Get() {
Type stencilTest;
MBGL_CHECK_ERROR(stencilTest = glIsEnabled(GL_STENCIL_TEST));
return stencilTest;
@@ -131,10 +129,10 @@ struct StencilTest {
struct StencilOp {
struct Type { GLenum sfail, dpfail, dppass; };
static const Type Default;
- inline static void Set(const Type& value) {
+ static void Set(const Type& value) {
MBGL_CHECK_ERROR(glStencilOp(value.sfail, value.dpfail, value.dppass));
}
- inline static Type Get() {
+ static Type Get() {
GLint sfail, dpfail, dppass;
MBGL_CHECK_ERROR(glGetIntegerv(GL_STENCIL_FAIL, &sfail));
MBGL_CHECK_ERROR(glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &dpfail));
@@ -143,30 +141,34 @@ struct StencilOp {
}
};
+constexpr bool operator!=(const StencilOp::Type& a, const StencilOp::Type& b) {
+ return a.sfail != b.sfail || a.dpfail != b.dpfail || a.dppass != b.dppass;
+}
+
struct DepthRange {
struct Type { GLfloat near, far; };
static const Type Default;
- inline static void Set(const Type& value) {
+ static void Set(const Type& value) {
MBGL_CHECK_ERROR(glDepthRange(value.near, value.far));
}
- inline static Type Get() {
+ static Type Get() {
GLfloat floats[2];
MBGL_CHECK_ERROR(glGetFloatv(GL_DEPTH_RANGE, floats));
return { floats[0], floats[1] };
}
};
-inline bool operator!=(const DepthRange::Type& a, const DepthRange::Type& b) {
+constexpr bool operator!=(const DepthRange::Type& a, const DepthRange::Type& b) {
return a.near != b.near || a.far != b.far;
}
struct DepthTest {
using Type = bool;
static const Type Default;
- inline static void Set(const Type& value) {
+ static void Set(const Type& value) {
MBGL_CHECK_ERROR(value ? glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST));
}
- inline static Type Get() {
+ static Type Get() {
Type depthTest;
MBGL_CHECK_ERROR(depthTest = glIsEnabled(GL_DEPTH_TEST));
return depthTest;
@@ -176,10 +178,10 @@ struct DepthTest {
struct DepthFunc {
using Type = GLenum;
static const Type Default;
- inline static void Set(const Type& value) {
+ static void Set(const Type& value) {
MBGL_CHECK_ERROR(glDepthFunc(value));
}
- inline static Type Get() {
+ static Type Get() {
GLint depthFunc;
MBGL_CHECK_ERROR(glGetIntegerv(GL_DEPTH_FUNC, &depthFunc));
return depthFunc;
@@ -189,10 +191,10 @@ struct DepthFunc {
struct Blend {
using Type = bool;
static const Type Default;
- inline static void Set(const Type& value) {
+ static void Set(const Type& value) {
MBGL_CHECK_ERROR(value ? glEnable(GL_BLEND) : glDisable(GL_BLEND));
}
- inline static Type Get() {
+ static Type Get() {
Type blend;
MBGL_CHECK_ERROR(blend = glIsEnabled(GL_BLEND));
return blend;
@@ -202,10 +204,10 @@ struct Blend {
struct BlendFunc {
struct Type { GLenum sfactor, dfactor; };
static const Type Default;
- inline static void Set(const Type& value) {
+ static void Set(const Type& value) {
MBGL_CHECK_ERROR(glBlendFunc(value.sfactor, value.dfactor));
}
- inline static Type Get() {
+ static Type Get() {
GLint sfactor, dfactor;
MBGL_CHECK_ERROR(glGetIntegerv(GL_BLEND_SRC_ALPHA, &sfactor));
MBGL_CHECK_ERROR(glGetIntegerv(GL_BLEND_DST_ALPHA, &dfactor));
@@ -213,13 +215,30 @@ struct BlendFunc {
}
};
+constexpr bool operator!=(const BlendFunc::Type& a, const BlendFunc::Type& b) {
+ return a.sfactor != b.sfactor || a.dfactor != b.dfactor;
+}
+
+struct BlendColor {
+ using Type = Color;
+ static const Type Default;
+ inline static void Set(const Type& value) {
+ MBGL_CHECK_ERROR(glBlendColor(value.r, value.g, value.b, value.a));
+ }
+ inline static Type Get() {
+ GLfloat floats[4];
+ MBGL_CHECK_ERROR(glGetFloatv(GL_BLEND_COLOR, floats));
+ return { floats[0], floats[1], floats[2], floats[3] };
+ }
+};
+
struct Program {
using Type = GLuint;
static const Type Default;
- inline static void Set(const Type& value) {
+ static void Set(const Type& value) {
MBGL_CHECK_ERROR(glUseProgram(value));
}
- inline static Type Get() {
+ static Type Get() {
GLint program;
MBGL_CHECK_ERROR(glGetIntegerv(GL_CURRENT_PROGRAM, &program));
return program;
@@ -229,10 +248,10 @@ struct Program {
struct LineWidth {
using Type = GLfloat;
static const Type Default;
- inline static void Set(const Type& value) {
+ static void Set(const Type& value) {
MBGL_CHECK_ERROR(glLineWidth(value));
}
- inline static Type Get() {
+ static Type Get() {
Type lineWidth;
MBGL_CHECK_ERROR(glGetFloatv(GL_LINE_WIDTH, &lineWidth));
return lineWidth;
@@ -240,15 +259,15 @@ struct LineWidth {
};
struct ActiveTexture {
- using Type = GLint;
+ using Type = uint8_t;
static const Type Default;
- inline static void Set(const Type& value) {
- MBGL_CHECK_ERROR(glActiveTexture(value));
+ static void Set(const Type& value) {
+ MBGL_CHECK_ERROR(glActiveTexture(GL_TEXTURE0 + value));
}
- inline static Type Get() {
- Type activeTexture;
+ static Type Get() {
+ GLint activeTexture;
MBGL_CHECK_ERROR(glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTexture));
- return activeTexture;
+ return activeTexture - GL_TEXTURE0;
}
};
@@ -257,10 +276,10 @@ struct ActiveTexture {
struct PixelZoom {
struct Type { GLfloat xfactor; GLfloat yfactor; };
static const Type Default;
- inline static void Set(const Type& value) {
+ static void Set(const Type& value) {
MBGL_CHECK_ERROR(glPixelZoom(value.xfactor, value.yfactor));
}
- inline static Type Get() {
+ static Type Get() {
Type value;
MBGL_CHECK_ERROR(glGetFloatv(GL_ZOOM_X, &value.xfactor));
MBGL_CHECK_ERROR(glGetFloatv(GL_ZOOM_Y, &value.yfactor));
@@ -268,17 +287,17 @@ struct PixelZoom {
}
};
-inline bool operator!=(const PixelZoom::Type& a, const PixelZoom::Type& b) {
+constexpr bool operator!=(const PixelZoom::Type& a, const PixelZoom::Type& b) {
return a.xfactor != b.xfactor || a.yfactor != b.yfactor;
}
struct RasterPos {
using Type = std::array<GLdouble, 4>;
static const Type Default;
- inline static void Set(const Type& value) {
+ static void Set(const Type& value) {
MBGL_CHECK_ERROR(glRasterPos4d(value[0], value[1], value[2], value[3]));
}
- inline static Type Get() {
+ static Type Get() {
Type pos;
MBGL_CHECK_ERROR(glGetDoublev(GL_CURRENT_RASTER_POSITION, pos.data()));
return pos;
@@ -287,5 +306,18 @@ struct RasterPos {
#endif // GL_ES_VERSION_2_0
+struct BindTexture {
+ using Type = GLuint;
+ static const Type Default;
+ static void Set(const Type& value) {
+ MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, value));
+ }
+ static Type Get() {
+ GLint texture;
+ MBGL_CHECK_ERROR(glGetIntegerv(GL_TEXTURE_BINDING_2D, &texture));
+ return texture;
+ }
+};
+
} // namespace gl
} // namespace mbgl
diff --git a/include/mbgl/map/camera.hpp b/include/mbgl/map/camera.hpp
index 4520321655..1c389577f0 100644
--- a/include/mbgl/map/camera.hpp
+++ b/include/mbgl/map/camera.hpp
@@ -14,23 +14,23 @@ namespace mbgl {
struct CameraOptions {
/** Coordinate at the center of the map. */
optional<LatLng> center;
-
+
/** Padding around the interior of the view that affects the frame of
reference for `center`. */
optional<EdgeInsets> padding;
-
+
/** Point of reference for `zoom` and `angle`, assuming an origin at the
top-left corner of the view. */
optional<ScreenCoordinate> anchor;
-
+
/** Zero-based zoom level. Constrained to the minimum and maximum zoom
levels. */
optional<double> zoom;
-
+
/** Bearing, measured in radians counterclockwise from true north. Wrapped
to [−π rad, π rad). */
optional<double> angle;
-
+
/** Pitch toward the horizon measured in radians, with 0 rad resulting in a
two-dimensional map. */
optional<double> pitch;
@@ -42,35 +42,35 @@ struct CameraOptions {
struct AnimationOptions {
/** Time to animate to the viewpoint defined herein. */
optional<Duration> duration;
-
+
/** Average velocity of a flyTo() transition, measured in screenfuls per
second, assuming a linear timing curve.
-
+
A <i>screenful</i> is the visible span in pixels. It does not correspond
to a fixed physical distance but rather varies by zoom level. */
optional<double> velocity;
-
+
/** Zero-based zoom level at the peak of the flyTo() transition’s flight
path. */
optional<double> minZoom;
-
+
/** The easing timing curve of the transition. */
optional<mbgl::util::UnitBezier> easing;
-
+
/** A function that is called on each frame of the transition, just before a
screen update, except on the last frame. The first parameter indicates
the elapsed time as a percentage of the duration. */
std::function<void(double)> transitionFrameFn;
-
+
/** A function that is called once on the last frame of the transition, just
before the corresponding screen update. */
std::function<void()> transitionFinishFn;
-
+
/** Creates an animation with no options specified. */
- inline AnimationOptions() {}
-
+ AnimationOptions() {}
+
/** Creates an animation with the specified duration. */
- inline AnimationOptions(Duration d)
+ AnimationOptions(Duration d)
: duration(d) {}
};
diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp
index f805680b7b..0e0c04ff0f 100644
--- a/include/mbgl/map/map.hpp
+++ b/include/mbgl/map/map.hpp
@@ -26,8 +26,9 @@ struct CameraOptions;
struct AnimationOptions;
namespace style {
+class Source;
class Layer;
-}
+} // namespace style
class Map : private util::noncopyable {
public:
@@ -149,6 +150,13 @@ public:
AnnotationIDs getPointAnnotationsInBounds(const LatLngBounds&);
+ // Sources
+ style::Source* getSource(const std::string& sourceID);
+ void addSource(std::unique_ptr<style::Source>);
+ void removeSource(const std::string& sourceID);
+
+ // Layers
+ style::Layer* getLayer(const std::string& layerID);
void addLayer(std::unique_ptr<style::Layer>, const optional<std::string>& beforeLayerID = {});
void removeLayer(const std::string& layerID);
diff --git a/include/mbgl/map/mode.hpp b/include/mbgl/map/mode.hpp
index 074bc3f08e..c9b9f60953 100644
--- a/include/mbgl/map/mode.hpp
+++ b/include/mbgl/map/mode.hpp
@@ -1,5 +1,7 @@
#pragma once
+#include <mbgl/util/traits.hpp>
+
#include <cstdint>
namespace mbgl {
@@ -41,24 +43,23 @@ enum class MapDebugOptions : EnumType {
ParseStatus = 1 << 2,
Timestamps = 1 << 3,
Collision = 1 << 4,
- Wireframe = 1 << 5,
+ Overdraw = 1 << 5,
// FIXME: https://github.com/mapbox/mapbox-gl-native/issues/5117
#ifndef GL_ES_VERSION_2_0
StencilClip = 1 << 6,
#endif // GL_ES_VERSION_2_0
};
-inline MapDebugOptions operator| (const MapDebugOptions& lhs, const MapDebugOptions& rhs) {
- return MapDebugOptions(static_cast<EnumType>(lhs) | static_cast<EnumType>(rhs));
+constexpr MapDebugOptions operator|(MapDebugOptions lhs, MapDebugOptions rhs) {
+ return MapDebugOptions(mbgl::underlying_type(lhs) | mbgl::underlying_type(rhs));
}
-inline MapDebugOptions& operator|=(MapDebugOptions& lhs, const MapDebugOptions& rhs) {
- lhs = lhs | rhs;
- return lhs;
+constexpr MapDebugOptions& operator|=(MapDebugOptions& lhs, MapDebugOptions rhs) {
+ return (lhs = lhs | rhs);
}
-inline bool operator& (const MapDebugOptions& lhs, const MapDebugOptions& rhs) {
- return static_cast<EnumType>(lhs) & static_cast<EnumType>(rhs);
+constexpr bool operator&(MapDebugOptions lhs, MapDebugOptions rhs) {
+ return mbgl::underlying_type(lhs) & mbgl::underlying_type(rhs);
}
} // namespace mbgl
diff --git a/include/mbgl/map/update.hpp b/include/mbgl/map/update.hpp
index 3915545bb0..36ce59c01d 100644
--- a/include/mbgl/map/update.hpp
+++ b/include/mbgl/map/update.hpp
@@ -13,19 +13,19 @@ enum class Update : uint8_t {
RecalculateStyle = 1 << 3,
RenderStill = 1 << 4,
Repaint = 1 << 5,
- Annotations = 1 << 6,
+ AnnotationStyle = 1 << 6,
+ AnnotationData = 1 << 7,
};
-inline Update operator| (const Update& lhs, const Update& rhs) {
+constexpr Update operator|(Update lhs, Update rhs) {
return Update(mbgl::underlying_type(lhs) | mbgl::underlying_type(rhs));
}
-inline Update& operator|=(Update& lhs, const Update& rhs) {
- lhs = lhs | rhs;
- return lhs;
+constexpr Update& operator|=(Update& lhs, const Update& rhs) {
+ return (lhs = lhs | rhs);
}
-inline bool operator& (const Update& lhs, const Update& rhs) {
+constexpr bool operator& (Update lhs, Update rhs) {
return mbgl::underlying_type(lhs) & mbgl::underlying_type(rhs);
}
diff --git a/include/mbgl/map/view.hpp b/include/mbgl/map/view.hpp
index 9f12ee5fb6..fa6f91d910 100644
--- a/include/mbgl/map/view.hpp
+++ b/include/mbgl/map/view.hpp
@@ -4,6 +4,7 @@
#include <mbgl/util/chrono.hpp>
#include <mbgl/util/image.hpp>
+#include <array>
#include <functional>
#include <memory>
diff --git a/include/mbgl/platform/darwin/settings_nsuserdefaults.hpp b/include/mbgl/platform/darwin/settings_nsuserdefaults.hpp
deleted file mode 100644
index b0ca060b85..0000000000
--- a/include/mbgl/platform/darwin/settings_nsuserdefaults.hpp
+++ /dev/null
@@ -1,27 +0,0 @@
-#pragma once
-
-#import <mbgl/ios/MGLTypes.h>
-
-namespace mbgl {
-
-class Settings_NSUserDefaults {
-public:
- Settings_NSUserDefaults();
- void load();
- void save();
- void clear();
-
-public:
- double longitude = 0;
- double latitude = 0;
- double zoom = 0;
- double bearing = 0;
- double pitch = 0;
-
- MGLUserTrackingMode userTrackingMode = MGLUserTrackingModeNone;
- bool showsUserLocation = false;
-
- uint32_t debug = 0;
-};
-
-}
diff --git a/include/mbgl/platform/default/glfw_view.hpp b/include/mbgl/platform/default/glfw_view.hpp
index b1204ce96d..38ab922414 100644
--- a/include/mbgl/platform/default/glfw_view.hpp
+++ b/include/mbgl/platform/default/glfw_view.hpp
@@ -14,7 +14,7 @@
class GLFWView : public mbgl::View {
public:
GLFWView(bool fullscreen = false, bool benchmark = false);
- ~GLFWView();
+ ~GLFWView() override;
float getPixelRatio() const override;
std::array<uint16_t, 2> getSize() const override;
@@ -44,6 +44,7 @@ public:
void report(float duration);
private:
+ mbgl::Color makeRandomColor() const;
mbgl::Point<double> makeRandomPoint() const;
static std::shared_ptr<const mbgl::SpriteImage>
makeSpriteImage(int width, int height, float pixelRatio);
@@ -51,6 +52,7 @@ private:
void nextOrientation();
void addRandomPointAnnotations(int count);
+ void addRandomLineAnnotations(int count);
void addRandomShapeAnnotations(int count);
void addRandomCustomPointAnnotations(int count);
diff --git a/include/mbgl/platform/default/headless_view.hpp b/include/mbgl/platform/default/headless_view.hpp
index d787eb1691..e3acc8e379 100644
--- a/include/mbgl/platform/default/headless_view.hpp
+++ b/include/mbgl/platform/default/headless_view.hpp
@@ -31,7 +31,7 @@ class HeadlessView : public View {
public:
HeadlessView(float pixelRatio, uint16_t width = 256, uint16_t height = 256);
HeadlessView(std::shared_ptr<HeadlessDisplay> display, float pixelRatio, uint16_t width = 256, uint16_t height = 256);
- ~HeadlessView();
+ ~HeadlessView() override;
float getPixelRatio() const override;
std::array<uint16_t, 2> getSize() const override;
@@ -74,7 +74,7 @@ private:
#if MBGL_USE_GLX
Display *xDisplay = nullptr;
GLXFBConfig *fbConfigs = nullptr;
- GLXContext glContext = 0;
+ GLXContext glContext = nullptr;
GLXPbuffer glxPbuffer = 0;
#endif
diff --git a/include/mbgl/platform/event.hpp b/include/mbgl/platform/event.hpp
index 0b3b79df6b..ee1ce6fa4e 100644
--- a/include/mbgl/platform/event.hpp
+++ b/include/mbgl/platform/event.hpp
@@ -1,7 +1,5 @@
#pragma once
-#include <mbgl/util/enum.hpp>
-
#include <cstdint>
namespace mbgl {
@@ -13,14 +11,6 @@ enum class EventSeverity : uint8_t {
Error,
};
-MBGL_DEFINE_ENUM_CLASS(EventSeverityClass, EventSeverity, {
- { EventSeverity::Debug, "DEBUG" },
- { EventSeverity::Info, "INFO" },
- { EventSeverity::Warning, "WARNING" },
- { EventSeverity::Error, "ERROR" },
- { EventSeverity(-1), "UNKNOWN" },
-});
-
enum class Event : uint8_t {
General,
Setup,
@@ -40,27 +30,6 @@ enum class Event : uint8_t {
Glyph,
};
-MBGL_DEFINE_ENUM_CLASS(EventClass, Event, {
- { Event::General, "General" },
- { Event::Setup, "Setup" },
- { Event::Shader, "Shader" },
- { Event::ParseStyle, "ParseStyle" },
- { Event::ParseTile, "ParseTile" },
- { Event::Render, "Render" },
- { Event::Style, "Style" },
- { Event::Database, "Database" },
- { Event::HttpRequest, "HttpRequest" },
- { Event::Sprite, "Sprite" },
- { Event::Image, "Image" },
- { Event::OpenGL, "OpenGL" },
- { Event::JNI, "JNI" },
- { Event::Android, "Android" },
- { Event::Crash, "Crash" },
- { Event::Glyph, "Glyph" },
- { Event(-1), "Unknown" },
-});
-
-
struct EventPermutation {
const EventSeverity severity;
const Event event;
diff --git a/include/mbgl/platform/log.hpp b/include/mbgl/platform/log.hpp
index 48b9e3dc70..d5bb1c2fcc 100644
--- a/include/mbgl/platform/log.hpp
+++ b/include/mbgl/platform/log.hpp
@@ -37,27 +37,27 @@ private:
public:
template <typename ...Args>
- static inline void Debug(Event event, Args&& ...args) {
+ static void Debug(Event event, Args&& ...args) {
Record(EventSeverity::Debug, event, ::std::forward<Args>(args)...);
}
template <typename ...Args>
- static inline void Info(Event event, Args&& ...args) {
+ static void Info(Event event, Args&& ...args) {
Record(EventSeverity::Info, event, ::std::forward<Args>(args)...);
}
template <typename ...Args>
- static inline void Warning(Event event, Args&& ...args) {
+ static void Warning(Event event, Args&& ...args) {
Record(EventSeverity::Warning, event, ::std::forward<Args>(args)...);
}
template <typename ...Args>
- static inline void Error(Event event, Args&& ...args) {
+ static void Error(Event event, Args&& ...args) {
Record(EventSeverity::Error, event, ::std::forward<Args>(args)...);
}
template <typename ...Args>
- static inline void Record(EventSeverity severity, Event event, Args&& ...args) {
+ static void Record(EventSeverity severity, Event event, Args&& ...args) {
if (!includes(severity, disabledEventSeverities) &&
!includes(event, disabledEvents) &&
!includes({ severity, event }, disabledEventPermutations)) {
diff --git a/include/mbgl/platform/platform.hpp b/include/mbgl/platform/platform.hpp
index 59ba7f97f3..cc8327c470 100644
--- a/include/mbgl/platform/platform.hpp
+++ b/include/mbgl/platform/platform.hpp
@@ -14,6 +14,12 @@ std::string uppercase(const std::string &string);
// Lowercase a string, potentially using platform-specific routines.
std::string lowercase(const std::string &string);
+// Gets the name of the current thread.
+std::string getCurrentThreadName();
+
+// Set the name of the current thread, truncated at 15.
+void setCurrentThreadName(const std::string& name);
+
// Makes the current thread low priority.
void makeThreadLowPriority();
diff --git a/include/mbgl/storage/default_file_source.hpp b/include/mbgl/storage/default_file_source.hpp
index e77befda1b..235e738254 100644
--- a/include/mbgl/storage/default_file_source.hpp
+++ b/include/mbgl/storage/default_file_source.hpp
@@ -26,6 +26,10 @@ public:
uint64_t maximumCacheSize = util::DEFAULT_MAX_CACHE_SIZE);
~DefaultFileSource() override;
+ bool supportsOptionalRequests() const override {
+ return true;
+ }
+
void setAccessToken(const std::string&);
std::string getAccessToken() const;
diff --git a/include/mbgl/storage/file_source.hpp b/include/mbgl/storage/file_source.hpp
index 88e0336187..404c683fdb 100644
--- a/include/mbgl/storage/file_source.hpp
+++ b/include/mbgl/storage/file_source.hpp
@@ -23,6 +23,14 @@ public:
// If the request is cancelled before the callback is executed, the callback will
// not be executed.
virtual std::unique_ptr<AsyncRequest> request(const Resource&, Callback) = 0;
+
+ // When a file source supports optional requests, it must return true.
+ // Optional requests are requests that aren't as urgent, but could be useful, e.g.
+ // to cover part of the map while loading. The FileSource should only do cheap actions to
+ // retrieve the data, e.g. load it from a cache, but not from the internet.
+ virtual bool supportsOptionalRequests() const {
+ return false;
+ }
};
} // namespace mbgl
diff --git a/include/mbgl/storage/network_status.hpp b/include/mbgl/storage/network_status.hpp
index 1b5471a44e..d7f502a3b2 100644
--- a/include/mbgl/storage/network_status.hpp
+++ b/include/mbgl/storage/network_status.hpp
@@ -1,7 +1,6 @@
#pragma once
-#include <mbgl/util/atomic.hpp>
-
+#include <atomic>
#include <mutex>
#include <set>
@@ -27,7 +26,7 @@ public:
static void Unsubscribe(util::AsyncTask* async);
private:
- static util::Atomic<bool> online;
+ static std::atomic<bool> online;
static std::mutex mtx;
static std::set<util::AsyncTask*> observers;
};
diff --git a/include/mbgl/storage/offline.hpp b/include/mbgl/storage/offline.hpp
index 990c8470bb..818cfe2ba5 100644
--- a/include/mbgl/storage/offline.hpp
+++ b/include/mbgl/storage/offline.hpp
@@ -1,6 +1,7 @@
#pragma once
#include <mbgl/util/geo.hpp>
+#include <mbgl/util/range.hpp>
#include <mbgl/util/optional.hpp>
#include <mbgl/style/types.hpp>
#include <mbgl/storage/response.hpp>
@@ -12,7 +13,6 @@
namespace mbgl {
class TileID;
-class Tileset;
/*
* An offline region defined by a style URL, geographic bounding box, zoom range, and
@@ -27,10 +27,10 @@ class Tileset;
*/
class OfflineTilePyramidRegionDefinition {
public:
- OfflineTilePyramidRegionDefinition(const std::string&, const LatLngBounds&, double, double, float);
+ OfflineTilePyramidRegionDefinition(std::string, LatLngBounds, double, double, float);
/* Private */
- std::vector<CanonicalTileID> tileCover(SourceType, uint16_t tileSize, const Tileset&) const;
+ std::vector<CanonicalTileID> tileCover(SourceType, uint16_t tileSize, const Range<uint8_t>& zoomRange) const;
const std::string styleURL;
const LatLngBounds bounds;
@@ -200,8 +200,8 @@ private:
friend class OfflineDatabase;
OfflineRegion(int64_t id,
- const OfflineRegionDefinition&,
- const OfflineRegionMetadata&);
+ OfflineRegionDefinition,
+ OfflineRegionMetadata);
const int64_t id;
const OfflineRegionDefinition definition;
diff --git a/include/mbgl/storage/resource.hpp b/include/mbgl/storage/resource.hpp
index a75de380a1..31df069952 100644
--- a/include/mbgl/storage/resource.hpp
+++ b/include/mbgl/storage/resource.hpp
@@ -33,10 +33,10 @@ public:
Required = true,
};
- Resource(Kind kind_, const std::string& url_, optional<TileData> tileData_ = {}, Necessity necessity_ = Required)
+ Resource(Kind kind_, std::string url_, optional<TileData> tileData_ = {}, Necessity necessity_ = Required)
: kind(kind_),
necessity(necessity_),
- url(url_),
+ url(std::move(url_)),
tileData(std::move(tileData_)) {
}
diff --git a/include/mbgl/storage/response.hpp b/include/mbgl/storage/response.hpp
index 83227573cf..6c79f5e181 100644
--- a/include/mbgl/storage/response.hpp
+++ b/include/mbgl/storage/response.hpp
@@ -49,7 +49,7 @@ public:
std::string message;
public:
- Error(Reason, const std::string& = "");
+ Error(Reason, std::string = "");
};
std::ostream& operator<<(std::ostream&, Response::Error::Reason);
diff --git a/include/mbgl/style/conversion.hpp b/include/mbgl/style/conversion.hpp
new file mode 100644
index 0000000000..e53adcb942
--- /dev/null
+++ b/include/mbgl/style/conversion.hpp
@@ -0,0 +1,95 @@
+#pragma once
+
+#include <mbgl/util/variant.hpp>
+
+#include <string>
+
+namespace mbgl {
+namespace style {
+namespace conversion {
+
+/*
+ The `conversion` namespace defines conversions from a templated type `V` representing a JSON
+ object conforming to the schema defined by the Mapbox Style Specification, to the various C++
+ types that form the C++ model of that domain:
+
+ * `std::unique_ptr<Source>`
+ * `std::unique_ptr<Layer>`
+ * `Filter`
+ * `PropertyValue<T>`
+
+ A single template function serves as the public interface:
+
+ template <class T, class V>
+ Result<T> convert(const V& value);
+
+ Where `T` is one of the above types. If the conversion fails, the `Error` variant of `Result` is
+ returned, which includes diagnostic text suitable for presentation to a library user. Otherwise,
+ the `T` variant of `Result` is returned.
+
+ The implementation of `convert` requires that the following are legal expressions for a value `v`
+ of type `const V&`:
+
+ * `isUndefined(v)` -- returns a boolean indication whether `v` is undefined or a JSON null
+
+ * `isArray(v)` -- returns a boolean indicating whether `v` represents a JSON array
+ * `arrayLength(v)` -- called only if `isArray(v)`; returns a size_t length
+ * `arrayMember(v)` -- called only if `isArray(v)`; returns `V` or `V&`
+
+ * `isObject(v)` -- returns a boolean indicating whether `v` represents a JSON object
+ * `objectMember(v, name)` -- called only if `isObject(v)`; `name` is `const char *`; return value:
+ * is true when evaluated in a boolean context iff the named member exists
+ * is convertable to a `V` or `V&` when dereferenced
+ * `eachMember(v, [] (const std::string&, const V&) -> optional<Error> {...})` -- called
+ only if `isObject(v)`; calls the provided lambda once for each key and value of the object;
+ short-circuits if any call returns an `Error`
+
+ * `toBool(v)` -- returns `optional<bool>`, absence indicating `v` is not a JSON boolean
+ * `toNumber(v)` -- returns `optional<float>`, absence indicating `v` is not a JSON number
+ * `toString(v)` -- returns `optional<std::string>`, absence indicating `v` is not a JSON string
+ * `toValue(v)` -- returns `optional<mbgl::Value>`, a variant type, for generic conversion,
+ absence indicating `v` is not a boolean, number, or string. Numbers should be converted to
+ unsigned integer, signed integer, or floating point, in descending preference.
+
+ The mbgl core implements these requirements for RapidJSON types, and the node bindings implement
+ them for v8 types.
+*/
+
+struct Error { std::string message; };
+
+template <class T>
+class Result : private variant<T, Error> {
+public:
+ using variant<T, Error>::variant;
+
+ explicit operator bool() const {
+ return this->template is<T>();
+ }
+
+ T& operator*() {
+ assert(this->template is<T>());
+ return this->template get<T>();
+ }
+
+ const T& operator*() const {
+ assert(this->template is<T>());
+ return this->template get<T>();
+ }
+
+ const Error& error() const {
+ assert(this->template is<Error>());
+ return this->template get<Error>();
+ }
+};
+
+template <class T, class Enable = void>
+struct Converter;
+
+template <class T, class V, class...Args>
+Result<T> convert(const V& value, Args&&...args) {
+ return Converter<T>()(value, std::forward<Args>(args)...);
+}
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/conversion/constant.hpp b/include/mbgl/style/conversion/constant.hpp
new file mode 100644
index 0000000000..05bf968f4d
--- /dev/null
+++ b/include/mbgl/style/conversion/constant.hpp
@@ -0,0 +1,174 @@
+#pragma once
+
+#include <mbgl/style/conversion.hpp>
+#include <mbgl/util/optional.hpp>
+#include <mbgl/util/color.hpp>
+#include <mbgl/util/enum.hpp>
+
+#include <array>
+#include <string>
+#include <vector>
+
+namespace mbgl {
+namespace style {
+namespace conversion {
+
+template <>
+struct Converter<bool> {
+ template <class V>
+ Result<bool> operator()(const V& value) const {
+ optional<bool> converted = toBool(value);
+ if (!converted) {
+ return Error { "value must be a boolean" };
+ }
+ return *converted;
+ }
+};
+
+template <>
+struct Converter<float> {
+ template <class V>
+ Result<float> operator()(const V& value) const {
+ optional<float> converted = toNumber(value);
+ if (!converted) {
+ return Error { "value must be a number" };
+ }
+ return *converted;
+ }
+};
+
+template <>
+struct Converter<std::string> {
+ template <class V>
+ Result<std::string> operator()(const V& value) const {
+ optional<std::string> converted = toString(value);
+ if (!converted) {
+ return Error { "value must be a string" };
+ }
+ return *converted;
+ }
+};
+
+template <class T>
+struct Converter<T, typename std::enable_if_t<std::is_enum<T>::value>> {
+ template <class V>
+ Result<T> operator()(const V& value) const {
+ optional<std::string> string = toString(value);
+ if (!string) {
+ return Error { "value must be a string" };
+ }
+
+ const auto result = Enum<T>::toEnum(*string);
+ if (!result) {
+ return Error { "value must be a valid enumeration value" };
+ }
+
+ return *result;
+ }
+};
+
+template <>
+struct Converter<Color> {
+ template <class V>
+ Result<Color> operator()(const V& value) const {
+ optional<std::string> string = toString(value);
+ if (!string) {
+ return Error { "value must be a string" };
+ }
+
+ optional<Color> color = Color::parse(*string);
+ if (!color) {
+ return Error { "value must be a valid color" };
+ }
+
+ return *color;
+ }
+};
+
+template <>
+struct Converter<std::array<float, 2>> {
+ template <class V>
+ Result<std::array<float, 2>> operator()(const V& value) const {
+ if (!isArray(value) || arrayLength(value) != 2) {
+ return Error { "value must be an array of two numbers" };
+ }
+
+ optional<float> first = toNumber(arrayMember(value, 0));
+ optional<float> second = toNumber(arrayMember(value, 1));
+ if (!first || !second) {
+ return Error { "value must be an array of two numbers" };
+ }
+
+ return std::array<float, 2> {{ *first, *second }};
+ }
+};
+
+template <>
+struct Converter<std::array<float, 4>> {
+ template <class V>
+ Result<std::array<float, 4>> operator()(const V& value) const {
+ if (!isArray(value) || arrayLength(value) != 4) {
+ return Error { "value must be an array of four numbers" };
+ }
+
+ optional<float> first = toNumber(arrayMember(value, 0));
+ optional<float> second = toNumber(arrayMember(value, 1));
+ optional<float> third = toNumber(arrayMember(value, 2));
+ optional<float> fourth = toNumber(arrayMember(value, 3));
+ if (!first || !second) {
+ return Error { "value must be an array of four numbers" };
+ }
+
+ return std::array<float, 4> {{ *first, *second, *third, *fourth }};
+ }
+};
+
+template <>
+struct Converter<std::vector<float>> {
+ template <class V>
+ Result<std::vector<float>> operator()(const V& value) const {
+ if (!isArray(value)) {
+ return Error { "value must be an array" };
+ }
+
+ std::vector<float> result;
+ result.reserve(arrayLength(value));
+
+ for (std::size_t i = 0; i < arrayLength(value); ++i) {
+ optional<float> number = toNumber(arrayMember(value, i));
+ if (!number) {
+ return Error { "value must be an array of numbers" };
+ }
+ result.push_back(*number);
+ }
+
+ return result;
+ }
+};
+
+template <>
+struct Converter<std::vector<std::string>> {
+ template <class V>
+ Result<std::vector<std::string>> operator()(const V& value) const {
+ if (!isArray(value)) {
+ return Error { "value must be an array" };
+ }
+
+ std::vector<std::string> result;
+ result.reserve(arrayLength(value));
+
+ for (std::size_t i = 0; i < arrayLength(value); ++i) {
+ optional<std::string> string = toString(arrayMember(value, i));
+ if (!string) {
+ return Error { "value must be an array of strings" };
+ }
+ result.push_back(*string);
+ }
+
+ return result;
+ }
+};
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/conversion/filter.hpp b/include/mbgl/style/conversion/filter.hpp
new file mode 100644
index 0000000000..3ab91e5bbc
--- /dev/null
+++ b/include/mbgl/style/conversion/filter.hpp
@@ -0,0 +1,150 @@
+#pragma once
+
+#include <mbgl/style/filter.hpp>
+#include <mbgl/style/conversion.hpp>
+#include <mbgl/util/geometry.hpp>
+
+namespace mbgl {
+namespace style {
+namespace conversion {
+
+template <>
+struct Converter<Filter> {
+public:
+ template <class V>
+ Result<Filter> operator()(const V& value) const {
+ if (!isArray(value)) {
+ return Error { "filter expression must be an array" };
+ }
+
+ if (arrayLength(value) < 1) {
+ return Error { "filter expression must have at least 1 element" };
+ }
+
+ optional<std::string> op = toString(arrayMember(value, 0));
+ if (!op) {
+ return Error { "filter operator must be a string" };
+ }
+
+ if (*op == "==") {
+ return convertBinaryFilter<EqualsFilter>(value);
+ } else if (*op == "!=") {
+ return convertBinaryFilter<NotEqualsFilter>(value);
+ } else if (*op == ">") {
+ return convertBinaryFilter<GreaterThanFilter>(value);
+ } else if (*op == ">=") {
+ return convertBinaryFilter<GreaterThanEqualsFilter>(value);
+ } else if (*op == "<") {
+ return convertBinaryFilter<LessThanFilter>(value);
+ } else if (*op == "<=") {
+ return convertBinaryFilter<LessThanEqualsFilter>(value);
+ } else if (*op == "in") {
+ return convertSetFilter<InFilter>(value);
+ } else if (*op == "!in") {
+ return convertSetFilter<NotInFilter>(value);
+ } else if (*op == "all") {
+ return convertCompoundFilter<AllFilter>(value);
+ } else if (*op == "any") {
+ return convertCompoundFilter<AnyFilter>(value);
+ } else if (*op == "none") {
+ return convertCompoundFilter<NoneFilter>(value);
+ } else if (*op == "has") {
+ return convertUnaryFilter<HasFilter>(value);
+ } else if (*op == "!has") {
+ return convertUnaryFilter<NotHasFilter>(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 {
+ if (!value) {
+ return Error { "filter expression value must be a boolean, number, or string" };
+ } else if (key != "$type") {
+ 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));
+ } else {
+ return Error { "value for $type filter must be Point, LineString, or Polygon" };
+ }
+ }
+
+ template <class FilterType, class V>
+ Result<Filter> convertUnaryFilter(const V& value) const {
+ if (arrayLength(value) < 2) {
+ return Error { "filter expression must have 2 elements" };
+ }
+
+ optional<std::string> key = toString(arrayMember(value, 1));
+ if (!key) {
+ return Error { "filter expression key must be a string" };
+ }
+
+ return FilterType { *key };
+ }
+
+ template <class FilterType, class V>
+ Result<Filter> convertBinaryFilter(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" };
+ }
+
+ Result<Value> filterValue = normalizeValue(*key, toValue(arrayMember(value, 2)));
+ if (!filterValue) {
+ return filterValue.error();
+ }
+
+ return FilterType { *key, *filterValue };
+ }
+
+ template <class FilterType, class V>
+ Result<Filter> convertSetFilter(const V& value) const {
+ if (arrayLength(value) < 2) {
+ return Error { "filter expression must at least 2 elements" };
+ }
+
+ optional<std::string> key = toString(arrayMember(value, 1));
+ if (!key) {
+ 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();
+ }
+ values.push_back(*filterValue);
+ }
+
+ return FilterType { *key, std::move(values) };
+ }
+
+ template <class FilterType, class V>
+ Result<Filter> convertCompoundFilter(const V& value) const {
+ std::vector<Filter> filters;
+ for (std::size_t i = 1; i < arrayLength(value); ++i) {
+ Result<Filter> element = operator()(arrayMember(value, i));
+ if (!element) {
+ return element.error();
+ }
+ filters.push_back(*element);
+ }
+
+ return FilterType { std::move(filters) };
+ }
+};
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/conversion/function.hpp b/include/mbgl/style/conversion/function.hpp
new file mode 100644
index 0000000000..f14b5089be
--- /dev/null
+++ b/include/mbgl/style/conversion/function.hpp
@@ -0,0 +1,69 @@
+#pragma once
+
+#include <mbgl/style/function.hpp>
+#include <mbgl/style/conversion.hpp>
+#include <mbgl/style/conversion/constant.hpp>
+
+namespace mbgl {
+namespace style {
+namespace conversion {
+
+template <class T>
+struct Converter<Function<T>> {
+ template <class V>
+ Result<Function<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" };
+ }
+
+ if (!isArray(*stopsValue)) {
+ return Error { "function stops must be an array" };
+ }
+
+ std::vector<std::pair<float, T>> 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" };
+ }
+
+ optional<float> z = toNumber(arrayMember(stopValue, 0));
+ if (!z) {
+ return Error { "function stop zoom level must be a number" };
+ }
+
+ Result<T> v = convert<T>(arrayMember(stopValue, 1));
+ if (!v) {
+ return v.error();
+ }
+
+ stops.emplace_back(*z, *v);
+ }
+
+ auto baseValue = objectMember(value, "base");
+ if (!baseValue) {
+ return Function<T>(stops, 1.0f);
+ }
+
+ optional<float> base = toNumber(*baseValue);
+ if (!base) {
+ return Error { "function base must be a number"};
+ }
+
+ return Function<T>(stops, *base);
+ }
+};
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/conversion/geojson.hpp b/include/mbgl/style/conversion/geojson.hpp
new file mode 100644
index 0000000000..ba10b3ecc8
--- /dev/null
+++ b/include/mbgl/style/conversion/geojson.hpp
@@ -0,0 +1,15 @@
+#pragma once
+
+#include <mbgl/style/conversion.hpp>
+#include <mbgl/style/sources/geojson_source.hpp>
+
+namespace mbgl {
+namespace style {
+namespace conversion {
+
+template <class V>
+Result<GeoJSON> convertGeoJSON(const V& value);
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/conversion/layer.hpp b/include/mbgl/style/conversion/layer.hpp
new file mode 100644
index 0000000000..0539dcf9ad
--- /dev/null
+++ b/include/mbgl/style/conversion/layer.hpp
@@ -0,0 +1,208 @@
+#pragma once
+
+#include <mbgl/style/layer.hpp>
+#include <mbgl/style/layers/background_layer.hpp>
+#include <mbgl/style/layers/circle_layer.hpp>
+#include <mbgl/style/layers/fill_layer.hpp>
+#include <mbgl/style/layers/line_layer.hpp>
+#include <mbgl/style/layers/raster_layer.hpp>
+#include <mbgl/style/layers/symbol_layer.hpp>
+#include <mbgl/style/conversion.hpp>
+#include <mbgl/style/conversion/constant.hpp>
+#include <mbgl/style/conversion/filter.hpp>
+#include <mbgl/style/conversion/make_property_setters.hpp>
+
+namespace mbgl {
+namespace style {
+namespace conversion {
+
+template <class V>
+optional<Error> setLayoutProperty(Layer& layer, const std::string& name, const V& value) {
+ static const auto setters = makeLayoutPropertySetters<V>();
+ auto it = setters.find(name);
+ if (it == setters.end()) {
+ return Error { "property not found" };
+ }
+ return it->second(layer, value);
+}
+
+template <class V>
+optional<Error> setPaintProperty(Layer& layer, const std::string& name, const V& value, const optional<std::string>& klass) {
+ static const auto setters = makePaintPropertySetters<V>();
+ auto it = setters.find(name);
+ if (it == setters.end()) {
+ return Error { "property not found" };
+ }
+ return it->second(layer, value, klass);
+}
+
+template <class V>
+optional<Error> setPaintProperties(Layer& layer, const V& value) {
+ return eachMember(value, [&] (const std::string& paintName, const V& paintValue) -> optional<Error> {
+ if (paintName.compare(0, 5, "paint") != 0) {
+ return {};
+ }
+
+ optional<std::string> klass;
+ if (paintName.compare(0, 6, "paint.") == 0) {
+ klass = paintName.substr(6);
+ }
+
+ return eachMember(paintValue, [&] (const std::string& k, const V& v) {
+ return setPaintProperty(layer, k, v, klass);
+ });
+ });
+}
+
+template <>
+struct Converter<std::unique_ptr<Layer>> {
+public:
+ template <class V>
+ Result<std::unique_ptr<Layer>> operator()(const V& value) const {
+ if (!isObject(value)) {
+ return Error { "layer must be an object" };
+ }
+
+ auto idValue = objectMember(value, "id");
+ if (!idValue) {
+ return Error { "layer must have an id" };
+ }
+
+ optional<std::string> id = toString(*idValue);
+ if (!id) {
+ return Error { "layer id must be a string" };
+ }
+
+ auto typeValue = objectMember(value, "type");
+ if (!typeValue) {
+ return Error { "layer must have a type" };
+ }
+
+ optional<std::string> type = toString(*typeValue);
+ if (!type) {
+ return Error { "layer type must be a string" };
+ }
+
+ Result<std::unique_ptr<Layer>> converted;
+
+ if (*type == "fill") {
+ converted = convertVectorLayer<FillLayer>(*id, value);
+ } else if (*type == "line") {
+ converted = convertVectorLayer<LineLayer>(*id, value);
+ } else if (*type == "circle") {
+ converted = convertVectorLayer<CircleLayer>(*id, value);
+ } else if (*type == "symbol") {
+ converted = convertVectorLayer<SymbolLayer>(*id, value);
+ } else if (*type == "raster") {
+ converted = convertRasterLayer(*id, value);
+ } else if (*type == "background") {
+ converted = convertBackgroundLayer(*id, value);
+ } else {
+ return Error { "invalid layer type" };
+ }
+
+ if (!converted) {
+ return converted;
+ }
+
+ std::unique_ptr<Layer> layer = std::move(*converted);
+
+ auto minzoomValue = objectMember(value, "minzoom");
+ if (minzoomValue) {
+ optional<float> minzoom = toNumber(*minzoomValue);
+ if (!minzoom) {
+ return Error { "minzoom must be numeric" };
+ }
+ layer->setMinZoom(*minzoom);
+ }
+
+ auto maxzoomValue = objectMember(value, "maxzoom");
+ if (maxzoomValue) {
+ optional<float> maxzoom = toNumber(*maxzoomValue);
+ if (!maxzoom) {
+ return Error { "maxzoom must be numeric" };
+ }
+ layer->setMaxZoom(*maxzoom);
+ }
+
+ auto layoutValue = objectMember(value, "layout");
+ if (layoutValue) {
+ if (!isObject(*layoutValue)) {
+ return Error { "layout must be an object" };
+ }
+ optional<Error> error = eachMember(*layoutValue, [&] (const std::string& k, const V& v) {
+ return setLayoutProperty(*layer, k, v);
+ });
+ if (error) {
+ return *error;
+ }
+ }
+
+ optional<Error> error = setPaintProperties(*layer, value);
+ if (error) {
+ return *error;
+ }
+
+ return std::move(layer);
+ }
+
+private:
+ template <class LayerType, class V>
+ Result<std::unique_ptr<Layer>> convertVectorLayer(const std::string& id, const V& value) const {
+ auto sourceValue = objectMember(value, "source");
+ if (!sourceValue) {
+ return Error { "layer must have a source" };
+ }
+
+ optional<std::string> source = toString(*sourceValue);
+ if (!source) {
+ return Error { "layer source must be a string" };
+ }
+
+ std::unique_ptr<LayerType> layer = std::make_unique<LayerType>(id, *source);
+
+ auto sourceLayerValue = objectMember(value, "source-layer");
+ if (sourceLayerValue) {
+ optional<std::string> sourceLayer = toString(*sourceLayerValue);
+ if (!sourceLayer) {
+ return Error { "layer source-layer must be a string" };
+ }
+ layer->setSourceLayer(*sourceLayer);
+ }
+
+ auto filterValue = objectMember(value, "filter");
+ if (filterValue) {
+ Result<Filter> filter = convert<Filter>(*filterValue);
+ if (!filter) {
+ return filter.error();
+ }
+ layer->setFilter(*filter);
+ }
+
+ return std::move(layer);
+ }
+
+ template <class V>
+ Result<std::unique_ptr<Layer>> convertRasterLayer(const std::string& id, const V& value) const {
+ auto sourceValue = objectMember(value, "source");
+ if (!sourceValue) {
+ return Error { "layer must have a source" };
+ }
+
+ optional<std::string> source = toString(*sourceValue);
+ if (!source) {
+ return Error { "layer source must be a string" };
+ }
+
+ return std::make_unique<RasterLayer>(id, *source);
+ }
+
+ template <class V>
+ Result<std::unique_ptr<Layer>> convertBackgroundLayer(const std::string& id, const V&) const {
+ return std::make_unique<BackgroundLayer>(id);
+ }
+};
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/conversion/make_property_setters.hpp b/include/mbgl/style/conversion/make_property_setters.hpp
new file mode 100644
index 0000000000..a3ba5e5d5a
--- /dev/null
+++ b/include/mbgl/style/conversion/make_property_setters.hpp
@@ -0,0 +1,136 @@
+#pragma once
+
+// This file is generated. Edit make_property_setters.hpp.ejs, then run `make style-code`.
+
+#include <mbgl/style/conversion/property_setter.hpp>
+
+#include <mbgl/style/layers/fill_layer.hpp>
+#include <mbgl/style/layers/line_layer.hpp>
+#include <mbgl/style/layers/symbol_layer.hpp>
+#include <mbgl/style/layers/circle_layer.hpp>
+#include <mbgl/style/layers/raster_layer.hpp>
+#include <mbgl/style/layers/background_layer.hpp>
+
+#include <unordered_map>
+
+namespace mbgl {
+namespace style {
+namespace conversion {
+
+template <class V>
+auto makeLayoutPropertySetters() {
+ std::unordered_map<std::string, LayoutPropertySetter<V>> result;
+
+ result["visibility"] = &setVisibility<V>;
+
+
+ result["line-cap"] = makePropertySetter<V>(&LineLayer::setLineCap);
+ result["line-join"] = makePropertySetter<V>(&LineLayer::setLineJoin);
+ result["line-miter-limit"] = makePropertySetter<V>(&LineLayer::setLineMiterLimit);
+ result["line-round-limit"] = makePropertySetter<V>(&LineLayer::setLineRoundLimit);
+
+ result["symbol-placement"] = makePropertySetter<V>(&SymbolLayer::setSymbolPlacement);
+ result["symbol-spacing"] = makePropertySetter<V>(&SymbolLayer::setSymbolSpacing);
+ result["symbol-avoid-edges"] = makePropertySetter<V>(&SymbolLayer::setSymbolAvoidEdges);
+ result["icon-allow-overlap"] = makePropertySetter<V>(&SymbolLayer::setIconAllowOverlap);
+ result["icon-ignore-placement"] = makePropertySetter<V>(&SymbolLayer::setIconIgnorePlacement);
+ result["icon-optional"] = makePropertySetter<V>(&SymbolLayer::setIconOptional);
+ result["icon-rotation-alignment"] = makePropertySetter<V>(&SymbolLayer::setIconRotationAlignment);
+ result["icon-size"] = makePropertySetter<V>(&SymbolLayer::setIconSize);
+ result["icon-text-fit"] = makePropertySetter<V>(&SymbolLayer::setIconTextFit);
+ result["icon-text-fit-padding"] = makePropertySetter<V>(&SymbolLayer::setIconTextFitPadding);
+ result["icon-image"] = makePropertySetter<V>(&SymbolLayer::setIconImage);
+ result["icon-rotate"] = makePropertySetter<V>(&SymbolLayer::setIconRotate);
+ result["icon-padding"] = makePropertySetter<V>(&SymbolLayer::setIconPadding);
+ result["icon-keep-upright"] = makePropertySetter<V>(&SymbolLayer::setIconKeepUpright);
+ result["icon-offset"] = makePropertySetter<V>(&SymbolLayer::setIconOffset);
+ result["text-pitch-alignment"] = makePropertySetter<V>(&SymbolLayer::setTextPitchAlignment);
+ result["text-rotation-alignment"] = makePropertySetter<V>(&SymbolLayer::setTextRotationAlignment);
+ result["text-field"] = makePropertySetter<V>(&SymbolLayer::setTextField);
+ result["text-font"] = makePropertySetter<V>(&SymbolLayer::setTextFont);
+ result["text-size"] = makePropertySetter<V>(&SymbolLayer::setTextSize);
+ result["text-max-width"] = makePropertySetter<V>(&SymbolLayer::setTextMaxWidth);
+ result["text-line-height"] = makePropertySetter<V>(&SymbolLayer::setTextLineHeight);
+ result["text-letter-spacing"] = makePropertySetter<V>(&SymbolLayer::setTextLetterSpacing);
+ result["text-justify"] = makePropertySetter<V>(&SymbolLayer::setTextJustify);
+ result["text-anchor"] = makePropertySetter<V>(&SymbolLayer::setTextAnchor);
+ result["text-max-angle"] = makePropertySetter<V>(&SymbolLayer::setTextMaxAngle);
+ result["text-rotate"] = makePropertySetter<V>(&SymbolLayer::setTextRotate);
+ result["text-padding"] = makePropertySetter<V>(&SymbolLayer::setTextPadding);
+ result["text-keep-upright"] = makePropertySetter<V>(&SymbolLayer::setTextKeepUpright);
+ result["text-transform"] = makePropertySetter<V>(&SymbolLayer::setTextTransform);
+ result["text-offset"] = makePropertySetter<V>(&SymbolLayer::setTextOffset);
+ result["text-allow-overlap"] = makePropertySetter<V>(&SymbolLayer::setTextAllowOverlap);
+ result["text-ignore-placement"] = makePropertySetter<V>(&SymbolLayer::setTextIgnorePlacement);
+ result["text-optional"] = makePropertySetter<V>(&SymbolLayer::setTextOptional);
+
+
+
+
+ return result;
+}
+
+template <class V>
+auto makePaintPropertySetters() {
+ std::unordered_map<std::string, PaintPropertySetter<V>> result;
+
+ result["fill-antialias"] = makePropertySetter<V>(&FillLayer::setFillAntialias);
+ result["fill-opacity"] = makePropertySetter<V>(&FillLayer::setFillOpacity);
+ result["fill-color"] = makePropertySetter<V>(&FillLayer::setFillColor);
+ result["fill-outline-color"] = makePropertySetter<V>(&FillLayer::setFillOutlineColor);
+ result["fill-translate"] = makePropertySetter<V>(&FillLayer::setFillTranslate);
+ result["fill-translate-anchor"] = makePropertySetter<V>(&FillLayer::setFillTranslateAnchor);
+ result["fill-pattern"] = makePropertySetter<V>(&FillLayer::setFillPattern);
+
+ result["line-opacity"] = makePropertySetter<V>(&LineLayer::setLineOpacity);
+ result["line-color"] = makePropertySetter<V>(&LineLayer::setLineColor);
+ result["line-translate"] = makePropertySetter<V>(&LineLayer::setLineTranslate);
+ result["line-translate-anchor"] = makePropertySetter<V>(&LineLayer::setLineTranslateAnchor);
+ result["line-width"] = makePropertySetter<V>(&LineLayer::setLineWidth);
+ result["line-gap-width"] = makePropertySetter<V>(&LineLayer::setLineGapWidth);
+ result["line-offset"] = makePropertySetter<V>(&LineLayer::setLineOffset);
+ result["line-blur"] = makePropertySetter<V>(&LineLayer::setLineBlur);
+ result["line-dasharray"] = makePropertySetter<V>(&LineLayer::setLineDasharray);
+ result["line-pattern"] = makePropertySetter<V>(&LineLayer::setLinePattern);
+
+ result["icon-opacity"] = makePropertySetter<V>(&SymbolLayer::setIconOpacity);
+ result["icon-color"] = makePropertySetter<V>(&SymbolLayer::setIconColor);
+ result["icon-halo-color"] = makePropertySetter<V>(&SymbolLayer::setIconHaloColor);
+ result["icon-halo-width"] = makePropertySetter<V>(&SymbolLayer::setIconHaloWidth);
+ result["icon-halo-blur"] = makePropertySetter<V>(&SymbolLayer::setIconHaloBlur);
+ result["icon-translate"] = makePropertySetter<V>(&SymbolLayer::setIconTranslate);
+ result["icon-translate-anchor"] = makePropertySetter<V>(&SymbolLayer::setIconTranslateAnchor);
+ result["text-opacity"] = makePropertySetter<V>(&SymbolLayer::setTextOpacity);
+ result["text-color"] = makePropertySetter<V>(&SymbolLayer::setTextColor);
+ result["text-halo-color"] = makePropertySetter<V>(&SymbolLayer::setTextHaloColor);
+ result["text-halo-width"] = makePropertySetter<V>(&SymbolLayer::setTextHaloWidth);
+ result["text-halo-blur"] = makePropertySetter<V>(&SymbolLayer::setTextHaloBlur);
+ result["text-translate"] = makePropertySetter<V>(&SymbolLayer::setTextTranslate);
+ result["text-translate-anchor"] = makePropertySetter<V>(&SymbolLayer::setTextTranslateAnchor);
+
+ result["circle-radius"] = makePropertySetter<V>(&CircleLayer::setCircleRadius);
+ result["circle-color"] = makePropertySetter<V>(&CircleLayer::setCircleColor);
+ result["circle-blur"] = makePropertySetter<V>(&CircleLayer::setCircleBlur);
+ result["circle-opacity"] = makePropertySetter<V>(&CircleLayer::setCircleOpacity);
+ result["circle-translate"] = makePropertySetter<V>(&CircleLayer::setCircleTranslate);
+ result["circle-translate-anchor"] = makePropertySetter<V>(&CircleLayer::setCircleTranslateAnchor);
+ result["circle-pitch-scale"] = makePropertySetter<V>(&CircleLayer::setCirclePitchScale);
+
+ result["raster-opacity"] = makePropertySetter<V>(&RasterLayer::setRasterOpacity);
+ result["raster-hue-rotate"] = makePropertySetter<V>(&RasterLayer::setRasterHueRotate);
+ result["raster-brightness-min"] = makePropertySetter<V>(&RasterLayer::setRasterBrightnessMin);
+ result["raster-brightness-max"] = makePropertySetter<V>(&RasterLayer::setRasterBrightnessMax);
+ result["raster-saturation"] = makePropertySetter<V>(&RasterLayer::setRasterSaturation);
+ result["raster-contrast"] = makePropertySetter<V>(&RasterLayer::setRasterContrast);
+ result["raster-fade-duration"] = makePropertySetter<V>(&RasterLayer::setRasterFadeDuration);
+
+ result["background-color"] = makePropertySetter<V>(&BackgroundLayer::setBackgroundColor);
+ result["background-pattern"] = makePropertySetter<V>(&BackgroundLayer::setBackgroundPattern);
+ result["background-opacity"] = makePropertySetter<V>(&BackgroundLayer::setBackgroundOpacity);
+
+ return result;
+}
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/conversion/make_property_setters.hpp.ejs b/include/mbgl/style/conversion/make_property_setters.hpp.ejs
new file mode 100644
index 0000000000..54e3958180
--- /dev/null
+++ b/include/mbgl/style/conversion/make_property_setters.hpp.ejs
@@ -0,0 +1,47 @@
+#pragma once
+
+// This file is generated. Edit make_property_setters.hpp.ejs, then run `make style-code`.
+
+#include <mbgl/style/conversion/property_setter.hpp>
+
+<% for (const layer of locals.layers) { -%>
+#include <mbgl/style/layers/<%- layer.type %>_layer.hpp>
+<% } -%>
+
+#include <unordered_map>
+
+namespace mbgl {
+namespace style {
+namespace conversion {
+
+template <class V>
+auto makeLayoutPropertySetters() {
+ std::unordered_map<std::string, LayoutPropertySetter<V>> result;
+
+ result["visibility"] = &setVisibility<V>;
+
+<% for (const layer of locals.layers) { -%>
+<% for (const property of layer.layoutProperties) { -%>
+ result["<%- property.name %>"] = makePropertySetter<V>(&<%- camelize(layer.type) %>Layer::set<%- camelize(property.name) %>);
+<% } -%>
+
+<% } -%>
+ return result;
+}
+
+template <class V>
+auto makePaintPropertySetters() {
+ std::unordered_map<std::string, PaintPropertySetter<V>> result;
+
+<% 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) %>);
+<% } -%>
+
+<% } -%>
+ return result;
+}
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/conversion/property_setter.hpp b/include/mbgl/style/conversion/property_setter.hpp
new file mode 100644
index 0000000000..1a601c7c1b
--- /dev/null
+++ b/include/mbgl/style/conversion/property_setter.hpp
@@ -0,0 +1,57 @@
+#pragma once
+
+#include <mbgl/style/layer.hpp>
+#include <mbgl/style/conversion.hpp>
+#include <mbgl/style/conversion/constant.hpp>
+#include <mbgl/style/conversion/property_value.hpp>
+
+#include <functional>
+#include <string>
+
+namespace mbgl {
+namespace style {
+namespace conversion {
+
+template <class V>
+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)) {
+ 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);
+ if (!typedValue) {
+ return typedValue.error();
+ }
+
+ (typedLayer->*setter)(*typedValue, args...);
+ return {};
+ };
+}
+
+template <class V>
+optional<Error> setVisibility(Layer& layer, const V& value) {
+ if (isUndefined(value)) {
+ layer.setVisibility(VisibilityType::Visible);
+ return {};
+ }
+
+ Result<VisibilityType> visibility = convert<VisibilityType>(value);
+ if (!visibility) {
+ return visibility.error();
+ }
+
+ layer.setVisibility(*visibility);
+ return {};
+}
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/conversion/property_value.hpp b/include/mbgl/style/conversion/property_value.hpp
new file mode 100644
index 0000000000..de95b56155
--- /dev/null
+++ b/include/mbgl/style/conversion/property_value.hpp
@@ -0,0 +1,36 @@
+#pragma once
+
+#include <mbgl/style/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<PropertyValue<T>> {
+ template <class V>
+ Result<PropertyValue<T>> operator()(const V& value) const {
+ if (isUndefined(value)) {
+ return {};
+ } else if (isObject(value)) {
+ Result<Function<T>> function = convert<Function<T>>(value);
+ if (!function) {
+ return function.error();
+ }
+ return *function;
+ } else {
+ Result<T> constant = convert<T>(value);
+ if (!constant) {
+ return constant.error();
+ }
+ return *constant;
+ }
+ }
+};
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/conversion/source.hpp b/include/mbgl/style/conversion/source.hpp
new file mode 100644
index 0000000000..c4b2fe303f
--- /dev/null
+++ b/include/mbgl/style/conversion/source.hpp
@@ -0,0 +1,182 @@
+#pragma once
+
+#include <mbgl/style/conversion.hpp>
+#include <mbgl/style/conversion/geojson.hpp>
+#include <mbgl/style/conversion/tileset.hpp>
+#include <mbgl/style/source.hpp>
+#include <mbgl/style/sources/geojson_source.hpp>
+#include <mbgl/style/sources/raster_source.hpp>
+#include <mbgl/style/sources/vector_source.hpp>
+
+namespace mbgl {
+namespace style {
+namespace conversion {
+
+template <>
+struct Converter<std::unique_ptr<Source>> {
+public:
+ template <class V>
+ Result<std::unique_ptr<Source>> operator()(const V& value, const std::string& id) const {
+ if (!isObject(value)) {
+ return Error{ "source must be an object" };
+ }
+
+ auto typeValue = objectMember(value, "type");
+ if (!typeValue) {
+ return Error{ "source must have a type" };
+ }
+
+ optional<std::string> type = toString(*typeValue);
+ if (!type) {
+ return Error{ "source type must be a string" };
+ }
+
+ if (*type == "raster") {
+ return convertRasterSource(id, value);
+ } else if (*type == "vector") {
+ return convertVectorSource(id, value);
+ } else if (*type == "geojson") {
+ return convertGeoJSONSource(id, value);
+ } else {
+ return Error{ "invalid source type" };
+ }
+ }
+
+private:
+ // A tile source can either specify a URL to TileJSON, or inline TileJSON.
+ template <class V>
+ Result<variant<std::string, Tileset>> convertURLOrTileset(const V& value) const {
+ auto urlVal = objectMember(value, "url");
+ if (!urlVal) {
+ Result<Tileset> tileset = convert<Tileset>(value);
+ if (!tileset) {
+ return tileset.error();
+ }
+ return *tileset;
+ }
+
+ optional<std::string> url = toString(*urlVal);
+ if (!url) {
+ return Error{ "source url must be a string" };
+ }
+
+ return *url;
+ }
+
+ template <class V>
+ Result<std::unique_ptr<Source>> convertRasterSource(const std::string& id,
+ const V& value) const {
+ Result<variant<std::string, Tileset>> urlOrTileset = convertURLOrTileset(value);
+ if (!urlOrTileset) {
+ return urlOrTileset.error();
+ }
+
+ uint16_t tileSize = util::tileSize;
+ auto tileSizeValue = objectMember(value, "tileSize");
+ if (tileSizeValue) {
+ optional<float> size = toNumber(*tileSizeValue);
+ if (!size || *size < 0 || *size > std::numeric_limits<uint16_t>::max()) {
+ return Error{ "invalid tileSize" };
+ }
+ tileSize = *size;
+ }
+
+ return std::make_unique<RasterSource>(id, std::move(*urlOrTileset), tileSize);
+ }
+
+ template <class V>
+ Result<std::unique_ptr<Source>> convertVectorSource(const std::string& id,
+ const V& value) const {
+ Result<variant<std::string, Tileset>> urlOrTileset = convertURLOrTileset(value);
+ if (!urlOrTileset) {
+ return urlOrTileset.error();
+ }
+
+ return std::make_unique<VectorSource>(id, std::move(*urlOrTileset));
+ }
+
+ template <class V>
+ Result<std::unique_ptr<Source>> convertGeoJSONSource(const std::string& id,
+ const V& value) const {
+ auto dataValue = objectMember(value, "data");
+ if (!dataValue) {
+ return Error{ "GeoJSON source must have a data value" };
+ }
+
+ GeoJSONOptions options;
+
+ const auto maxzoomValue = objectMember(value, "maxzoom");
+ if (maxzoomValue) {
+ if (toNumber(*maxzoomValue)) {
+ options.maxzoom = static_cast<uint8_t>(*toNumber(*maxzoomValue));
+ } else {
+ return Error{ "GeoJSON source maxzoom value must be a number" };
+ }
+ }
+
+ const auto bufferValue = objectMember(value, "buffer");
+ if (bufferValue) {
+ if (toNumber(*bufferValue)) {
+ options.buffer = static_cast<uint16_t>(*toNumber(*bufferValue));
+ } else {
+ return Error{ "GeoJSON source buffer value must be a number" };
+ }
+ }
+
+ const auto toleranceValue = objectMember(value, "tolerance");
+ if (toleranceValue) {
+ if (toNumber(*toleranceValue)) {
+ options.tolerance = static_cast<double>(*toNumber(*toleranceValue));
+ } else {
+ return Error{ "GeoJSON source tolerance value must be a number" };
+ }
+ }
+
+ const auto clusterValue = objectMember(value, "cluster");
+ if (clusterValue) {
+ if (toBool(*clusterValue)) {
+ options.cluster = *toBool(*clusterValue);
+ } else {
+ return Error{ "GeoJSON source cluster value must be a boolean" };
+ }
+ }
+
+ const auto clusterMaxZoomValue = objectMember(value, "clusterMaxZoom");
+ if (clusterMaxZoomValue) {
+ if (toNumber(*clusterMaxZoomValue)) {
+ options.clusterMaxZoom = static_cast<uint8_t>(*toNumber(*clusterMaxZoomValue));
+ } else {
+ return Error{ "GeoJSON source clusterMaxZoom value must be a number" };
+ }
+ }
+
+ const auto clusterRadiusValue = objectMember(value, "clusterRadius");
+ if (clusterRadiusValue) {
+ if (toNumber(*clusterRadiusValue)) {
+ options.clusterRadius = static_cast<double>(*toNumber(*clusterRadiusValue));
+ } else {
+ return Error{ "GeoJSON source clusterRadius value must be a number" };
+ }
+ }
+
+ auto result = std::make_unique<GeoJSONSource>(id, options);
+
+ if (isObject(*dataValue)) {
+ Result<GeoJSON> geoJSON = convertGeoJSON(*dataValue);
+ if (!geoJSON) {
+ return geoJSON.error();
+ }
+ result->setGeoJSON(std::move(*geoJSON));
+ } else if (toString(*dataValue)) {
+ result->setURL(*toString(*dataValue));
+ } else {
+ return Error{ "GeoJSON data must be a URL or an object" };
+ }
+
+ return std::move(result);
+ }
+};
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/conversion/tileset.hpp b/include/mbgl/style/conversion/tileset.hpp
new file mode 100644
index 0000000000..46425597af
--- /dev/null
+++ b/include/mbgl/style/conversion/tileset.hpp
@@ -0,0 +1,67 @@
+#pragma once
+
+#include <mbgl/util/tileset.hpp>
+#include <mbgl/style/conversion.hpp>
+
+namespace mbgl {
+namespace style {
+namespace conversion {
+
+template <>
+struct Converter<Tileset> {
+public:
+ template <class V>
+ Result<Tileset> operator()(const V& value) const {
+ Tileset result;
+
+ auto tiles = objectMember(value, "tiles");
+ if (!tiles) {
+ return Error { "source must have tiles" };
+ }
+
+ if (!isArray(*tiles)) {
+ return Error { "source tiles must be an array" };
+ }
+
+ for (std::size_t i = 0; i < arrayLength(*tiles); i++) {
+ optional<std::string> urlTemplate = toString(arrayMember(*tiles, i));
+ if (!urlTemplate) {
+ return Error { "source tiles member must be a string" };
+ }
+ result.tiles.push_back(std::move(*urlTemplate));
+ }
+
+ auto minzoomValue = objectMember(value, "minzoom");
+ if (minzoomValue) {
+ optional<float> minzoom = toNumber(*minzoomValue);
+ if (!minzoom || *minzoom < 0 || *minzoom > std::numeric_limits<uint8_t>::max()) {
+ return Error { "invalid minzoom" };
+ }
+ result.zoomRange.min = *minzoom;
+ }
+
+ auto maxzoomValue = objectMember(value, "maxzoom");
+ if (maxzoomValue) {
+ optional<float> maxzoom = toNumber(*maxzoomValue);
+ if (!maxzoom || *maxzoom < 0 || *maxzoom > std::numeric_limits<uint8_t>::max()) {
+ return Error { "invalid maxzoom" };
+ }
+ result.zoomRange.max = *maxzoom;
+ }
+
+ auto attributionValue = objectMember(value, "attribution");
+ if (attributionValue) {
+ optional<std::string> attribution = toString(*attributionValue);
+ if (!attribution) {
+ return Error { "source attribution must be a string" };
+ }
+ result.attribution = std::move(*attribution);
+ }
+
+ return result;
+ }
+};
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/filter.hpp b/include/mbgl/style/filter.hpp
index 9cf84f5e1d..dd2b20cd0d 100644
--- a/include/mbgl/style/filter.hpp
+++ b/include/mbgl/style/filter.hpp
@@ -2,6 +2,7 @@
#include <mbgl/util/variant.hpp>
#include <mbgl/util/feature.hpp>
+#include <mbgl/util/geometry.hpp>
#include <string>
#include <vector>
@@ -9,22 +10,7 @@
namespace mbgl {
namespace style {
-typedef variant<
- class NullFilter,
- class EqualsFilter,
- class NotEqualsFilter,
- class LessThanFilter,
- class LessThanEqualsFilter,
- class GreaterThanFilter,
- class GreaterThanEqualsFilter,
- class InFilter,
- class NotInFilter,
- class AnyFilter,
- class AllFilter,
- class NoneFilter,
- class HasFilter,
- class NotHasFilter
- > Filter;
+class Filter;
class NullFilter {};
@@ -101,5 +87,31 @@ public:
std::string key;
};
+using FilterBase = variant<
+ class NullFilter,
+ class EqualsFilter,
+ class NotEqualsFilter,
+ class LessThanFilter,
+ class LessThanEqualsFilter,
+ class GreaterThanFilter,
+ class GreaterThanEqualsFilter,
+ class InFilter,
+ class NotInFilter,
+ class AnyFilter,
+ class AllFilter,
+ class NoneFilter,
+ class HasFilter,
+ class NotHasFilter>;
+
+class Filter : public FilterBase {
+public:
+ using FilterBase::FilterBase;
+
+ bool operator()(const Feature&) const;
+
+ template <class PropertyAccessor>
+ bool operator()(FeatureType type, optional<FeatureIdentifier> id, PropertyAccessor accessor) const;
+};
+
} // namespace style
} // namespace mbgl
diff --git a/include/mbgl/style/filter_evaluator.hpp b/include/mbgl/style/filter_evaluator.hpp
new file mode 100644
index 0000000000..793abe6da0
--- /dev/null
+++ b/include/mbgl/style/filter_evaluator.hpp
@@ -0,0 +1,212 @@
+#pragma once
+
+#include <mbgl/style/filter.hpp>
+#include <mbgl/util/geometry.hpp>
+
+#include <type_traits>
+
+namespace mbgl {
+namespace style {
+
+/*
+ A visitor that evaluates a `Filter` for a given feature type and properties. For maximum
+ flexibility, it is templated on the PropertyAccessor type, which must be a callable type with
+ function signature `optional<Value> (const std::string&)`, returning the value for the given
+ key, if it exists.
+
+ Use via `Filter::operator()`. For example:
+
+ if (filter(feature.getType(), [&] (const std::string& key) { return feature.getValue(key); })) {
+ // matches the filter
+ } else {
+ // does not match
+ }
+*/
+template <class PropertyAccessor>
+class FilterEvaluator {
+public:
+ const FeatureType featureType;
+ const optional<FeatureIdentifier> featureIdentifier;
+ const PropertyAccessor propertyAccessor;
+
+ bool operator()(const NullFilter&) const {
+ return true;
+ }
+
+ bool operator()(const EqualsFilter& filter) const {
+ optional<Value> actual = getValue(filter.key);
+ return actual && equal(*actual, filter.value);
+ }
+
+ bool operator()(const NotEqualsFilter& filter) const {
+ optional<Value> actual = getValue(filter.key);
+ return !actual || !equal(*actual, filter.value);
+ }
+
+ bool operator()(const LessThanFilter& filter) const {
+ optional<Value> actual = getValue(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);
+ 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);
+ 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);
+ 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);
+ if (!actual)
+ return false;
+ for (const auto& v: filter.values) {
+ if (equal(*actual, v)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool operator()(const NotInFilter& filter) const {
+ optional<Value> actual = getValue(filter.key);
+ if (!actual)
+ return true;
+ for (const auto& v: filter.values) {
+ if (equal(*actual, v)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool operator()(const AnyFilter& filter) const {
+ for (const auto& f: filter.filters) {
+ if (Filter::visit(f, *this)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool operator()(const AllFilter& filter) const {
+ for (const auto& f: filter.filters) {
+ if (!Filter::visit(f, *this)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool operator()(const NoneFilter& filter) const {
+ for (const auto& f: filter.filters) {
+ if (Filter::visit(f, *this)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool operator()(const HasFilter& filter) const {
+ return bool(getValue(filter.key));
+ }
+
+ bool operator()(const NotHasFilter& filter) const {
+ return !getValue(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>();
+ }
+ } else {
+ return propertyAccessor(key_);
+ }
+ }
+
+ template <class Op>
+ struct Comparator {
+ const Op& op;
+
+ template <class T>
+ bool operator()(const T& lhs, const T& rhs) const {
+ return op(lhs, rhs);
+ }
+
+ template <class T0, class T1>
+ auto operator()(const T0& lhs, const T1& rhs) const
+ -> typename std::enable_if_t<std::is_arithmetic<T0>::value && !std::is_same<T0, bool>::value &&
+ std::is_arithmetic<T1>::value && !std::is_same<T1, bool>::value, bool> {
+ return op(double(lhs), double(rhs));
+ }
+
+ template <class T0, class T1>
+ auto operator()(const T0&, const T1&) const
+ -> typename std::enable_if_t<!std::is_arithmetic<T0>::value || std::is_same<T0, bool>::value ||
+ !std::is_arithmetic<T1>::value || std::is_same<T1, bool>::value, bool> {
+ return false;
+ }
+
+ bool operator()(const NullValue&,
+ const NullValue&) const {
+ // Should be unreachable; null is not currently allowed by the style specification.
+ assert(false);
+ return false;
+ }
+
+ bool operator()(const std::vector<Value>&,
+ const std::vector<Value>&) const {
+ // Should be unreachable; nested values are not currently allowed by the style specification.
+ assert(false);
+ return false;
+ }
+
+ bool operator()(const std::unordered_map<std::string, Value>&,
+ const std::unordered_map<std::string, Value>&) const {
+ // Should be unreachable; nested values are not currently allowed by the style specification.
+ assert(false);
+ return false;
+ }
+ };
+
+ template <class Op>
+ bool compare(const Value& lhs, const Value& rhs, const Op& op) const {
+ return Value::binary_visit(lhs, rhs, Comparator<Op> { op });
+ }
+
+ bool equal(const Value& lhs, const Value& rhs) const {
+ return compare(lhs, rhs, [] (const auto& lhs_, const auto& rhs_) { return lhs_ == rhs_; });
+ }
+};
+
+inline bool Filter::operator()(const Feature& feature) const {
+ return operator()(apply_visitor(ToFeatureType(), feature.geometry), feature.id, [&] (const std::string& key) -> optional<Value> {
+ auto it = feature.properties.find(key);
+ if (it == feature.properties.end())
+ return {};
+ return it->second;
+ });
+}
+
+template <class PropertyAccessor>
+bool Filter::operator()(FeatureType type, optional<FeatureIdentifier> id, PropertyAccessor accessor) const {
+ return FilterBase::visit(*this, FilterEvaluator<PropertyAccessor> { type, id, accessor });
+}
+
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/function.hpp b/include/mbgl/style/function.hpp
index da2659c76a..44ffa31079 100644
--- a/include/mbgl/style/function.hpp
+++ b/include/mbgl/style/function.hpp
@@ -12,8 +12,8 @@ public:
using Stop = std::pair<float, T>;
using Stops = std::vector<Stop>;
- explicit Function(const Stops& stops_, float base_)
- : base(base_), stops(stops_) {}
+ explicit Function(Stops stops_, float base_)
+ : base(base_), stops(std::move(stops_)) {}
float getBase() const { return base; }
const std::vector<std::pair<float, T>>& getStops() const { return stops; }
diff --git a/include/mbgl/style/layer.hpp b/include/mbgl/style/layer.hpp
index 1f4a6fdf35..1eff9eb3dc 100644
--- a/include/mbgl/style/layer.hpp
+++ b/include/mbgl/style/layer.hpp
@@ -55,11 +55,6 @@ public:
float getMaxZoom() const;
void setMaxZoom(float) const;
- // Create a new layer with the specified `id` and `ref`. All other properties
- // are copied from this layer.
- std::unique_ptr<Layer> copy(const std::string& id,
- const std::string& ref) const;
-
// Private implementation
class Impl;
const std::unique_ptr<Impl> baseImpl;
diff --git a/include/mbgl/style/layers/background_layer.hpp b/include/mbgl/style/layers/background_layer.hpp
index 2eb84ee499..ac97ec2e6d 100644
--- a/include/mbgl/style/layers/background_layer.hpp
+++ b/include/mbgl/style/layers/background_layer.hpp
@@ -19,13 +19,13 @@ public:
// Paint properties
PropertyValue<Color> getBackgroundColor() const;
- void setBackgroundColor(PropertyValue<Color>);
+ void setBackgroundColor(PropertyValue<Color>, const optional<std::string>& klass = {});
PropertyValue<std::string> getBackgroundPattern() const;
- void setBackgroundPattern(PropertyValue<std::string>);
+ void setBackgroundPattern(PropertyValue<std::string>, const optional<std::string>& klass = {});
PropertyValue<float> getBackgroundOpacity() const;
- void setBackgroundOpacity(PropertyValue<float>);
+ void setBackgroundOpacity(PropertyValue<float>, 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 10d281b6ac..873f95bcff 100644
--- a/include/mbgl/style/layers/circle_layer.hpp
+++ b/include/mbgl/style/layers/circle_layer.hpp
@@ -13,14 +13,13 @@ namespace style {
class CircleLayer : public Layer {
public:
- CircleLayer(const std::string& layerID);
+ CircleLayer(const std::string& layerID, const std::string& sourceID);
~CircleLayer() final;
// Source
-
- void setSource(const std::string& sourceID, const std::string& sourceLayer);
const std::string& getSourceID() const;
const std::string& getSourceLayer() const;
+ void setSourceLayer(const std::string& sourceLayer);
void setFilter(const Filter&);
const Filter& getFilter() const;
@@ -28,22 +27,25 @@ public:
// Paint properties
PropertyValue<float> getCircleRadius() const;
- void setCircleRadius(PropertyValue<float>);
+ void setCircleRadius(PropertyValue<float>, const optional<std::string>& klass = {});
PropertyValue<Color> getCircleColor() const;
- void setCircleColor(PropertyValue<Color>);
+ void setCircleColor(PropertyValue<Color>, const optional<std::string>& klass = {});
PropertyValue<float> getCircleBlur() const;
- void setCircleBlur(PropertyValue<float>);
+ void setCircleBlur(PropertyValue<float>, const optional<std::string>& klass = {});
PropertyValue<float> getCircleOpacity() const;
- void setCircleOpacity(PropertyValue<float>);
+ void setCircleOpacity(PropertyValue<float>, const optional<std::string>& klass = {});
PropertyValue<std::array<float, 2>> getCircleTranslate() const;
- void setCircleTranslate(PropertyValue<std::array<float, 2>>);
+ void setCircleTranslate(PropertyValue<std::array<float, 2>>, const optional<std::string>& klass = {});
PropertyValue<TranslateAnchorType> getCircleTranslateAnchor() const;
- void setCircleTranslateAnchor(PropertyValue<TranslateAnchorType>);
+ void setCircleTranslateAnchor(PropertyValue<TranslateAnchorType>, const optional<std::string>& klass = {});
+
+ PropertyValue<CirclePitchScaleType> getCirclePitchScale() const;
+ void setCirclePitchScale(PropertyValue<CirclePitchScaleType>, 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 a14bf4a390..e70d67f538 100644
--- a/include/mbgl/style/layers/fill_layer.hpp
+++ b/include/mbgl/style/layers/fill_layer.hpp
@@ -13,14 +13,13 @@ namespace style {
class FillLayer : public Layer {
public:
- FillLayer(const std::string& layerID);
+ FillLayer(const std::string& layerID, const std::string& sourceID);
~FillLayer() final;
// Source
-
- void setSource(const std::string& sourceID, const std::string& sourceLayer);
const std::string& getSourceID() const;
const std::string& getSourceLayer() const;
+ void setSourceLayer(const std::string& sourceLayer);
void setFilter(const Filter&);
const Filter& getFilter() const;
@@ -28,25 +27,25 @@ public:
// Paint properties
PropertyValue<bool> getFillAntialias() const;
- void setFillAntialias(PropertyValue<bool>);
+ void setFillAntialias(PropertyValue<bool>, const optional<std::string>& klass = {});
PropertyValue<float> getFillOpacity() const;
- void setFillOpacity(PropertyValue<float>);
+ void setFillOpacity(PropertyValue<float>, const optional<std::string>& klass = {});
PropertyValue<Color> getFillColor() const;
- void setFillColor(PropertyValue<Color>);
+ void setFillColor(PropertyValue<Color>, const optional<std::string>& klass = {});
PropertyValue<Color> getFillOutlineColor() const;
- void setFillOutlineColor(PropertyValue<Color>);
+ void setFillOutlineColor(PropertyValue<Color>, const optional<std::string>& klass = {});
PropertyValue<std::array<float, 2>> getFillTranslate() const;
- void setFillTranslate(PropertyValue<std::array<float, 2>>);
+ void setFillTranslate(PropertyValue<std::array<float, 2>>, const optional<std::string>& klass = {});
PropertyValue<TranslateAnchorType> getFillTranslateAnchor() const;
- void setFillTranslateAnchor(PropertyValue<TranslateAnchorType>);
+ void setFillTranslateAnchor(PropertyValue<TranslateAnchorType>, const optional<std::string>& klass = {});
PropertyValue<std::string> getFillPattern() const;
- void setFillPattern(PropertyValue<std::string>);
+ void setFillPattern(PropertyValue<std::string>, 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
new file mode 100644
index 0000000000..aaae30287c
--- /dev/null
+++ b/include/mbgl/style/layers/layer.hpp.ejs
@@ -0,0 +1,75 @@
+<%
+ const type = locals.type;
+ const layoutProperties = locals.layoutProperties;
+ const paintProperties = locals.paintProperties;
+-%>
+// This file is generated. Do not edit.
+
+#pragma once
+
+#include <mbgl/style/layer.hpp>
+#include <mbgl/style/filter.hpp>
+#include <mbgl/style/property_value.hpp>
+
+#include <mbgl/util/color.hpp>
+
+<% if (type === 'line' || type === 'symbol') { -%>
+#include <vector>
+
+<% } -%>
+namespace mbgl {
+namespace style {
+
+class <%- camelize(type) %>Layer : public Layer {
+public:
+<% if (type === 'background') { -%>
+ <%- camelize(type) %>Layer(const std::string& layerID);
+<% } else { -%>
+ <%- camelize(type) %>Layer(const std::string& layerID, const std::string& sourceID);
+<% } -%>
+ ~<%- camelize(type) %>Layer() final;
+
+<% if (type !== 'background') { -%>
+ // Source
+ const std::string& getSourceID() const;
+<% if (type !== 'raster') { -%>
+ const std::string& getSourceLayer() const;
+ void setSourceLayer(const std::string& sourceLayer);
+
+ void setFilter(const Filter&);
+ const Filter& getFilter() const;
+<% } -%>
+
+<% } -%>
+<% if (layoutProperties.length) { -%>
+ // Layout properties
+
+<% for (const property of layoutProperties) { -%>
+ PropertyValue<<%- propertyType(property) %>> get<%- camelize(property.name) %>() const;
+ void set<%- camelize(property.name) %>(PropertyValue<<%- propertyType(property) %>>);
+
+<% } -%>
+<% } -%>
+ // Paint properties
+
+<% for (const property of paintProperties) { -%>
+ PropertyValue<<%- propertyType(property) %>> get<%- camelize(property.name) %>() const;
+ void set<%- camelize(property.name) %>(PropertyValue<<%- propertyType(property) %>>, const optional<std::string>& klass = {});
+
+<% } -%>
+ // Private implementation
+
+ class Impl;
+ Impl* const impl;
+
+ <%- camelize(type) %>Layer(const Impl&);
+ <%- camelize(type) %>Layer(const <%- camelize(type) %>Layer&) = delete;
+};
+
+template <>
+inline bool Layer::is<<%- camelize(type) %>Layer>() const {
+ return type == Type::<%- camelize(type) %>;
+}
+
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/layers/line_layer.hpp b/include/mbgl/style/layers/line_layer.hpp
index fb9e37811a..abcb425b96 100644
--- a/include/mbgl/style/layers/line_layer.hpp
+++ b/include/mbgl/style/layers/line_layer.hpp
@@ -15,14 +15,13 @@ namespace style {
class LineLayer : public Layer {
public:
- LineLayer(const std::string& layerID);
+ LineLayer(const std::string& layerID, const std::string& sourceID);
~LineLayer() final;
// Source
-
- void setSource(const std::string& sourceID, const std::string& sourceLayer);
const std::string& getSourceID() const;
const std::string& getSourceLayer() const;
+ void setSourceLayer(const std::string& sourceLayer);
void setFilter(const Filter&);
const Filter& getFilter() const;
@@ -44,34 +43,34 @@ public:
// Paint properties
PropertyValue<float> getLineOpacity() const;
- void setLineOpacity(PropertyValue<float>);
+ void setLineOpacity(PropertyValue<float>, const optional<std::string>& klass = {});
PropertyValue<Color> getLineColor() const;
- void setLineColor(PropertyValue<Color>);
+ void setLineColor(PropertyValue<Color>, const optional<std::string>& klass = {});
PropertyValue<std::array<float, 2>> getLineTranslate() const;
- void setLineTranslate(PropertyValue<std::array<float, 2>>);
+ void setLineTranslate(PropertyValue<std::array<float, 2>>, const optional<std::string>& klass = {});
PropertyValue<TranslateAnchorType> getLineTranslateAnchor() const;
- void setLineTranslateAnchor(PropertyValue<TranslateAnchorType>);
+ void setLineTranslateAnchor(PropertyValue<TranslateAnchorType>, const optional<std::string>& klass = {});
PropertyValue<float> getLineWidth() const;
- void setLineWidth(PropertyValue<float>);
+ void setLineWidth(PropertyValue<float>, const optional<std::string>& klass = {});
PropertyValue<float> getLineGapWidth() const;
- void setLineGapWidth(PropertyValue<float>);
+ void setLineGapWidth(PropertyValue<float>, const optional<std::string>& klass = {});
PropertyValue<float> getLineOffset() const;
- void setLineOffset(PropertyValue<float>);
+ void setLineOffset(PropertyValue<float>, const optional<std::string>& klass = {});
PropertyValue<float> getLineBlur() const;
- void setLineBlur(PropertyValue<float>);
+ void setLineBlur(PropertyValue<float>, const optional<std::string>& klass = {});
PropertyValue<std::vector<float>> getLineDasharray() const;
- void setLineDasharray(PropertyValue<std::vector<float>>);
+ void setLineDasharray(PropertyValue<std::vector<float>>, const optional<std::string>& klass = {});
PropertyValue<std::string> getLinePattern() const;
- void setLinePattern(PropertyValue<std::string>);
+ void setLinePattern(PropertyValue<std::string>, 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 6d0c7dd91c..dea0c26bf3 100644
--- a/include/mbgl/style/layers/raster_layer.hpp
+++ b/include/mbgl/style/layers/raster_layer.hpp
@@ -13,36 +13,34 @@ namespace style {
class RasterLayer : public Layer {
public:
- RasterLayer(const std::string& layerID);
+ RasterLayer(const std::string& layerID, const std::string& sourceID);
~RasterLayer() final;
// Source
-
- void setSource(const std::string& sourceID);
const std::string& getSourceID() const;
// Paint properties
PropertyValue<float> getRasterOpacity() const;
- void setRasterOpacity(PropertyValue<float>);
+ void setRasterOpacity(PropertyValue<float>, const optional<std::string>& klass = {});
PropertyValue<float> getRasterHueRotate() const;
- void setRasterHueRotate(PropertyValue<float>);
+ void setRasterHueRotate(PropertyValue<float>, const optional<std::string>& klass = {});
PropertyValue<float> getRasterBrightnessMin() const;
- void setRasterBrightnessMin(PropertyValue<float>);
+ void setRasterBrightnessMin(PropertyValue<float>, const optional<std::string>& klass = {});
PropertyValue<float> getRasterBrightnessMax() const;
- void setRasterBrightnessMax(PropertyValue<float>);
+ void setRasterBrightnessMax(PropertyValue<float>, const optional<std::string>& klass = {});
PropertyValue<float> getRasterSaturation() const;
- void setRasterSaturation(PropertyValue<float>);
+ void setRasterSaturation(PropertyValue<float>, const optional<std::string>& klass = {});
PropertyValue<float> getRasterContrast() const;
- void setRasterContrast(PropertyValue<float>);
+ void setRasterContrast(PropertyValue<float>, const optional<std::string>& klass = {});
PropertyValue<float> getRasterFadeDuration() const;
- void setRasterFadeDuration(PropertyValue<float>);
+ void setRasterFadeDuration(PropertyValue<float>, 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 3806310c95..77b63d9b91 100644
--- a/include/mbgl/style/layers/symbol_layer.hpp
+++ b/include/mbgl/style/layers/symbol_layer.hpp
@@ -15,14 +15,13 @@ namespace style {
class SymbolLayer : public Layer {
public:
- SymbolLayer(const std::string& layerID);
+ SymbolLayer(const std::string& layerID, const std::string& sourceID);
~SymbolLayer() final;
// Source
-
- void setSource(const std::string& sourceID, const std::string& sourceLayer);
const std::string& getSourceID() const;
const std::string& getSourceLayer() const;
+ void setSourceLayer(const std::string& sourceLayer);
void setFilter(const Filter&);
const Filter& getFilter() const;
@@ -47,12 +46,18 @@ public:
PropertyValue<bool> getIconOptional() const;
void setIconOptional(PropertyValue<bool>);
- PropertyValue<RotationAlignmentType> getIconRotationAlignment() const;
- void setIconRotationAlignment(PropertyValue<RotationAlignmentType>);
+ PropertyValue<AlignmentType> getIconRotationAlignment() const;
+ void setIconRotationAlignment(PropertyValue<AlignmentType>);
PropertyValue<float> getIconSize() const;
void setIconSize(PropertyValue<float>);
+ PropertyValue<IconTextFitType> getIconTextFit() const;
+ void setIconTextFit(PropertyValue<IconTextFitType>);
+
+ PropertyValue<std::array<float, 4>> getIconTextFitPadding() const;
+ void setIconTextFitPadding(PropertyValue<std::array<float, 4>>);
+
PropertyValue<std::string> getIconImage() const;
void setIconImage(PropertyValue<std::string>);
@@ -68,8 +73,11 @@ public:
PropertyValue<std::array<float, 2>> getIconOffset() const;
void setIconOffset(PropertyValue<std::array<float, 2>>);
- PropertyValue<RotationAlignmentType> getTextRotationAlignment() const;
- void setTextRotationAlignment(PropertyValue<RotationAlignmentType>);
+ PropertyValue<AlignmentType> getTextPitchAlignment() const;
+ void setTextPitchAlignment(PropertyValue<AlignmentType>);
+
+ PropertyValue<AlignmentType> getTextRotationAlignment() const;
+ void setTextRotationAlignment(PropertyValue<AlignmentType>);
PropertyValue<std::string> getTextField() const;
void setTextField(PropertyValue<std::string>);
@@ -125,46 +133,46 @@ public:
// Paint properties
PropertyValue<float> getIconOpacity() const;
- void setIconOpacity(PropertyValue<float>);
+ void setIconOpacity(PropertyValue<float>, const optional<std::string>& klass = {});
PropertyValue<Color> getIconColor() const;
- void setIconColor(PropertyValue<Color>);
+ void setIconColor(PropertyValue<Color>, const optional<std::string>& klass = {});
PropertyValue<Color> getIconHaloColor() const;
- void setIconHaloColor(PropertyValue<Color>);
+ void setIconHaloColor(PropertyValue<Color>, const optional<std::string>& klass = {});
PropertyValue<float> getIconHaloWidth() const;
- void setIconHaloWidth(PropertyValue<float>);
+ void setIconHaloWidth(PropertyValue<float>, const optional<std::string>& klass = {});
PropertyValue<float> getIconHaloBlur() const;
- void setIconHaloBlur(PropertyValue<float>);
+ void setIconHaloBlur(PropertyValue<float>, const optional<std::string>& klass = {});
PropertyValue<std::array<float, 2>> getIconTranslate() const;
- void setIconTranslate(PropertyValue<std::array<float, 2>>);
+ void setIconTranslate(PropertyValue<std::array<float, 2>>, const optional<std::string>& klass = {});
PropertyValue<TranslateAnchorType> getIconTranslateAnchor() const;
- void setIconTranslateAnchor(PropertyValue<TranslateAnchorType>);
+ void setIconTranslateAnchor(PropertyValue<TranslateAnchorType>, const optional<std::string>& klass = {});
PropertyValue<float> getTextOpacity() const;
- void setTextOpacity(PropertyValue<float>);
+ void setTextOpacity(PropertyValue<float>, const optional<std::string>& klass = {});
PropertyValue<Color> getTextColor() const;
- void setTextColor(PropertyValue<Color>);
+ void setTextColor(PropertyValue<Color>, const optional<std::string>& klass = {});
PropertyValue<Color> getTextHaloColor() const;
- void setTextHaloColor(PropertyValue<Color>);
+ void setTextHaloColor(PropertyValue<Color>, const optional<std::string>& klass = {});
PropertyValue<float> getTextHaloWidth() const;
- void setTextHaloWidth(PropertyValue<float>);
+ void setTextHaloWidth(PropertyValue<float>, const optional<std::string>& klass = {});
PropertyValue<float> getTextHaloBlur() const;
- void setTextHaloBlur(PropertyValue<float>);
+ void setTextHaloBlur(PropertyValue<float>, const optional<std::string>& klass = {});
PropertyValue<std::array<float, 2>> getTextTranslate() const;
- void setTextTranslate(PropertyValue<std::array<float, 2>>);
+ void setTextTranslate(PropertyValue<std::array<float, 2>>, const optional<std::string>& klass = {});
PropertyValue<TranslateAnchorType> getTextTranslateAnchor() const;
- void setTextTranslateAnchor(PropertyValue<TranslateAnchorType>);
+ void setTextTranslateAnchor(PropertyValue<TranslateAnchorType>, const optional<std::string>& klass = {});
// Private implementation
diff --git a/include/mbgl/style/source.hpp b/include/mbgl/style/source.hpp
new file mode 100644
index 0000000000..92341066b1
--- /dev/null
+++ b/include/mbgl/style/source.hpp
@@ -0,0 +1,63 @@
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/style/types.hpp>
+
+#include <memory>
+#include <string>
+
+namespace mbgl {
+namespace style {
+
+/**
+ * The runtime representation of a [source](https://www.mapbox.com/mapbox-gl-style-spec/#sources) from the Mapbox Style
+ * Specification.
+ *
+ * `Source` is an abstract base class; concrete derived classes are provided for each source type. `Source` contains
+ * functionality that is common to all layer types:
+ *
+ * * Runtime type information: type predicates and casting
+ * * Accessors for properties common to all source types: ID, etc.
+ * * Cloning and copying
+ *
+ * All other functionality lives in the derived classes. To instantiate a source, create an instance of the desired
+ * type, passing the ID:
+ *
+ * auto vectorSource = std::make_unique<VectorSource>("my-vector-source");
+ */
+class Source : public mbgl::util::noncopyable {
+public:
+ virtual ~Source();
+
+ // Check whether this source is of the given subtype.
+ template <class T>
+ bool is() const;
+
+ // Dynamically cast this source to the given subtype.
+ template <class T>
+ T* as() {
+ return is<T>() ? reinterpret_cast<T*>(this) : nullptr;
+ }
+
+ template <class T>
+ const T* as() const {
+ return is<T>() ? reinterpret_cast<const T*>(this) : nullptr;
+ }
+
+ const std::string& getID() const;
+
+ // Create a new source with the specified `id`. All other properties
+ // are copied from this source.
+ std::unique_ptr<Source> copy(const std::string& id) const;
+
+ // Private implementation
+ class Impl;
+ const std::unique_ptr<Impl> baseImpl;
+
+protected:
+ const SourceType type;
+ Source(SourceType, std::unique_ptr<Impl>);
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/sources/geojson_source.hpp b/include/mbgl/style/sources/geojson_source.hpp
new file mode 100644
index 0000000000..37ddce1bcc
--- /dev/null
+++ b/include/mbgl/style/sources/geojson_source.hpp
@@ -0,0 +1,54 @@
+#pragma once
+
+#include <mbgl/style/source.hpp>
+#include <mbgl/util/geojson.hpp>
+
+#include <mapbox/geojson.hpp>
+
+namespace mapbox {
+
+namespace geojsonvt {
+class GeoJSONVT;
+} // namespace geojsonvt
+
+namespace supercluster {
+class Supercluster;
+} // namespace supercluster
+
+} // namespace mapbox
+
+namespace mbgl {
+namespace style {
+
+using GeoJSONVTPointer = std::unique_ptr<mapbox::geojsonvt::GeoJSONVT>;
+using SuperclusterPointer = std::unique_ptr<mapbox::supercluster::Supercluster>;
+
+struct GeoJSONOptions {
+ // GeoJSON-VT options
+ uint8_t maxzoom = 18;
+ uint16_t buffer = 128;
+ double tolerance = 0.375;
+
+ // Supercluster options
+ bool cluster = false;
+ uint16_t clusterRadius = 50;
+ uint8_t clusterMaxZoom = 17;
+};
+
+class GeoJSONSource : public Source {
+public:
+ GeoJSONSource(const std::string& id, const GeoJSONOptions options_ = GeoJSONOptions());
+
+ void setURL(const std::string& url);
+ void setGeoJSON(const GeoJSON&);
+
+ std::string getURL();
+
+ // Private implementation
+
+ class Impl;
+ Impl* const impl;
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/sources/raster_source.hpp b/include/mbgl/style/sources/raster_source.hpp
new file mode 100644
index 0000000000..2d1d648eec
--- /dev/null
+++ b/include/mbgl/style/sources/raster_source.hpp
@@ -0,0 +1,20 @@
+#pragma once
+
+#include <mbgl/style/source.hpp>
+#include <mbgl/util/tileset.hpp>
+#include <mbgl/util/variant.hpp>
+
+namespace mbgl {
+namespace style {
+
+class RasterSource : public Source {
+public:
+ RasterSource(std::string id, variant<std::string, Tileset> urlOrTileset, uint16_t tileSize);
+
+ // Private implementation
+
+ class Impl;
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/sources/vector_source.hpp b/include/mbgl/style/sources/vector_source.hpp
new file mode 100644
index 0000000000..3d53362734
--- /dev/null
+++ b/include/mbgl/style/sources/vector_source.hpp
@@ -0,0 +1,20 @@
+#pragma once
+
+#include <mbgl/style/source.hpp>
+#include <mbgl/util/tileset.hpp>
+#include <mbgl/util/variant.hpp>
+
+namespace mbgl {
+namespace style {
+
+class VectorSource : public Source {
+public:
+ VectorSource(std::string id, variant<std::string, Tileset> urlOrTileset);
+
+ // Private implementation
+
+ class Impl;
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/transition_options.hpp b/include/mbgl/style/transition_options.hpp
index 87faff21f8..d7a6633f0c 100644
--- a/include/mbgl/style/transition_options.hpp
+++ b/include/mbgl/style/transition_options.hpp
@@ -6,13 +6,9 @@
namespace mbgl {
namespace style {
-class TransitionOptions {
-public:
- TransitionOptions(const optional<Duration>& duration_ = {}, const optional<Duration>& delay_ = {})
- : duration(duration_), delay(delay_) {}
-
- optional<Duration> duration;
- optional<Duration> delay;
+struct TransitionOptions {
+ optional<Duration> duration = {};
+ optional<Duration> delay = {};
};
} // namespace style
diff --git a/include/mbgl/style/types.hpp b/include/mbgl/style/types.hpp
index 27b524a800..34e5642ec6 100644
--- a/include/mbgl/style/types.hpp
+++ b/include/mbgl/style/types.hpp
@@ -1,6 +1,6 @@
#pragma once
-#include <mbgl/util/enum.hpp>
+#include <cstdint>
namespace mbgl {
@@ -13,14 +13,6 @@ enum class SourceType : uint8_t {
Annotations
};
-MBGL_DEFINE_ENUM_CLASS(SourceTypeClass, SourceType, {
- { SourceType::Vector, "vector" },
- { SourceType::Raster, "raster" },
- { SourceType::GeoJSON, "geojson" },
- { SourceType::Video, "video" },
- { SourceType::Annotations, "annotations" },
-});
-
namespace style {
enum class VisibilityType : bool {
@@ -53,14 +45,20 @@ enum class RotateAnchorType : bool {
Viewport,
};
+enum class CirclePitchScaleType : bool {
+ Map,
+ Viewport,
+};
+
enum class SymbolPlacementType : bool {
Point,
Line,
};
-enum class RotationAlignmentType : bool {
+enum class AlignmentType : uint8_t {
Map,
Viewport,
+ Undefined,
};
enum class TextJustifyType : uint8_t {
@@ -87,5 +85,12 @@ enum class TextTransformType : uint8_t {
Lowercase,
};
+enum class IconTextFitType : uint8_t {
+ None,
+ Both,
+ Width,
+ Height
+};
+
} // namespace style
} // namespace mbgl
diff --git a/include/mbgl/util/char_array_buffer.hpp b/include/mbgl/util/char_array_buffer.hpp
new file mode 100644
index 0000000000..177f005477
--- /dev/null
+++ b/include/mbgl/util/char_array_buffer.hpp
@@ -0,0 +1,55 @@
+#pragma once
+
+#include <streambuf>
+
+namespace mbgl {
+namespace util {
+
+// ref https://artofcode.wordpress.com/2010/12/12/deriving-from-stdstreambuf/
+
+class CharArrayBuffer : public std::streambuf
+{
+public:
+ CharArrayBuffer(char const* data, std::size_t size)
+ : begin_(data), end_(data + size), current_(data) {}
+
+private:
+ int_type underflow() final {
+ if (current_ == end_) {
+ return traits_type::eof();
+ }
+ return traits_type::to_int_type(*current_);
+ }
+
+ int_type uflow() final {
+ if (current_ == end_) {
+ return traits_type::eof();
+ }
+ return traits_type::to_int_type(*current_++);
+ }
+
+ int_type pbackfail(int_type ch) final {
+ if (current_ == begin_ || (ch != traits_type::eof() && ch != current_[-1])) {
+ return traits_type::eof();
+ }
+ return traits_type::to_int_type(*--current_);
+ }
+
+ std::streamsize showmanyc() final {
+ return end_ - current_;
+ }
+
+ pos_type seekoff(off_type off, std::ios_base::seekdir dir, std::ios_base::openmode) final {
+ if (dir == std::ios_base::beg) current_ = std::min(begin_ + off, end_);
+ else if (dir == std::ios_base::cur) current_ = std::min(current_ + off, end_);
+ else current_ = std::max(end_ - off, begin_); // dir == std::ios_base::end
+ return pos_type(off_type(current_ - begin_));
+ }
+
+ char const * const begin_;
+ char const * const end_;
+ char const * current_;
+};
+
+} // namespace util
+} // namespace mbgl
diff --git a/include/mbgl/util/color.hpp b/include/mbgl/util/color.hpp
index d7fe61c640..4be380fde3 100644
--- a/include/mbgl/util/color.hpp
+++ b/include/mbgl/util/color.hpp
@@ -1,10 +1,40 @@
#pragma once
-#include <array>
+#include <mbgl/util/optional.hpp>
+
+#include <string>
namespace mbgl {
// Stores a premultiplied color, with all four channels ranging from 0..1
-using Color = std::array<float, 4>;
+class Color {
+public:
+ float r = 0.0f;
+ float g = 0.0f;
+ float b = 0.0f;
+ float a = 0.0f;
+
+ static constexpr Color black() { return { 0.0f, 0.0f, 0.0f, 1.0f }; };
+ static constexpr Color white() { return { 1.0f, 1.0f, 1.0f, 1.0f }; };
+
+ static optional<Color> parse(const std::string&);
+};
+
+constexpr bool operator==(const Color& colorA, const Color& colorB) {
+ return colorA.r == colorB.r && colorA.g == colorB.g && colorA.b == colorB.b && colorA.a == colorB.a;
+}
+
+constexpr bool operator!=(const Color& colorA, const Color& colorB) {
+ return !(colorA == colorB);
+}
+
+constexpr Color operator*(const Color& color, float alpha) {
+ return {
+ color.r * alpha,
+ color.g * alpha,
+ color.b * alpha,
+ color.a * alpha
+ };
+}
} // namespace mbgl
diff --git a/include/mbgl/util/constants.hpp b/include/mbgl/util/constants.hpp
index 621fc1820e..3c0b3eb93e 100644
--- a/include/mbgl/util/constants.hpp
+++ b/include/mbgl/util/constants.hpp
@@ -1,6 +1,7 @@
#pragma once
#include <mbgl/util/chrono.hpp>
+#include <mbgl/util/unitbezier.hpp>
#include <cmath>
#include <string>
@@ -17,7 +18,7 @@ constexpr float tileSize = 512;
* In practice, all features are converted to this extent before being added.
*
* Positions are stored as signed 16bit integers.
- * One bit is lost for signedness to support featuers extending past the left edge of the tile.
+ * One bit is lost for signedness to support features extending past the left edge of the tile.
* One bit is lost because the line vertex buffer packs 1 bit of other data into the int.
* One bit is lost to support features extending past the extent on the right edge of the tile.
* This leaves us with 2^13 = 8192
@@ -35,11 +36,13 @@ constexpr double PITCH_MAX = M_PI / 3;
constexpr double MIN_ZOOM = 0.0;
constexpr double MAX_ZOOM = 25.5;
-constexpr uint64_t DEFAULT_MAX_CACHE_SIZE = 50 * 1024 * 1024;;
+constexpr uint64_t DEFAULT_MAX_CACHE_SIZE = 50 * 1024 * 1024;
constexpr Duration DEFAULT_FADE_DURATION = Milliseconds(300);
constexpr Seconds CLOCK_SKEW_RETRY_TIMEOUT { 30 };
+constexpr UnitBezier DEFAULT_TRANSITION_EASE = { 0, 0, 0.25, 1 };
+
} // namespace util
namespace debug {
diff --git a/include/mbgl/util/convert.hpp b/include/mbgl/util/convert.hpp
new file mode 100644
index 0000000000..c2b3d9950d
--- /dev/null
+++ b/include/mbgl/util/convert.hpp
@@ -0,0 +1,17 @@
+#include <array>
+#include <type_traits>
+#include <utility>
+
+namespace mbgl {
+namespace util {
+
+template<typename To, typename From, std::size_t Size,
+ typename = std::enable_if_t<std::is_convertible<From, To>::value>>
+constexpr std::array<To, Size> convert(const std::array<From, Size>&from) {
+ std::array<To, Size> to {};
+ std::copy(std::begin(from), std::end(from), std::begin(to));
+ return to;
+}
+
+} // namespace util
+} // namespace mbgl
diff --git a/include/mbgl/util/enum.hpp b/include/mbgl/util/enum.hpp
index 3fbf313aed..48ffda463e 100644
--- a/include/mbgl/util/enum.hpp
+++ b/include/mbgl/util/enum.hpp
@@ -1,52 +1,36 @@
#pragma once
-#include <iosfwd>
+#include <mbgl/util/optional.hpp>
+
+#include <algorithm>
+#include <cassert>
#include <string>
namespace mbgl {
-template <typename Type>
-struct EnumValue {
- const Type value;
- const char *name;
-};
-
-template <typename EnumName, const EnumValue<EnumName> *names, const size_t length>
-struct Enum {
- using Type = EnumName;
- Type value;
- static const constexpr size_t l = length;
-private:
- static constexpr inline bool compare(const char *a, const char *b) {
- return *a == *b && (*a == '\0' || compare(a + 1, b + 1));
- }
- static constexpr inline const char *lookup_type(Type e, EnumValue<Type> const * const list, size_t r) {
- return r == 0 ? "" : list->value == e ? list->name : lookup_type(e, list + 1, r - 1);
- }
- static constexpr inline Type lookup_name(const char *n, EnumValue<Type> const * const list, size_t r) {
- return r == 0 ? Type(-1) : compare(list->name, n) ? list->value : lookup_name(n, list + 1, r - 1);
- }
+template <typename T>
+class Enum {
public:
- inline constexpr Enum(const char *n) : value(lookup_name(n, names, length)) {}
- inline constexpr Enum(const std::string &n) : value(lookup_name(n.c_str(), names, length)) {}
- inline constexpr Enum(Type t) : value(t) {}
-
- inline void operator=(const char *n) { value = lookup_name(n, names, length); }
- inline void operator=(const std::string &n) { *this = n.c_str(); }
- inline void operator=(Type t) { value = t; }
+ using Value = std::pair<const T, const char *>;
- inline constexpr bool valid() const { return value != Type(-1); }
+ static const char * toString(T t) {
+ auto it = std::find_if(begin, end, [&] (const auto& v) { return t == v.first; });
+ assert(it != end); return it->second;
+ }
- inline constexpr const char *c_str() const { return lookup_type(value, names, length); }
- inline std::string str() const { return c_str(); }
+ static optional<T> toEnum(const std::string& s) {
+ auto it = std::find_if(begin, end, [&] (const auto& v) { return s == v.second; });
+ return it == end ? optional<T>() : it->first;
+ }
- inline constexpr operator Type() const { return value; }
+private:
+ static const Value* begin;
+ static const Value* end;
};
-#define MBGL_DEFINE_ENUM_CLASS(name, type, strings...) \
- const constexpr ::mbgl::EnumValue<type> type##_names[] = strings; \
- using name = ::mbgl::Enum<type, type##_names, sizeof(type##_names) / sizeof(::mbgl::EnumValue<type>)>; \
- inline std::ostream& operator<<(std::ostream& os, type t) { return os << name(t).str(); }
+#define MBGL_DEFINE_ENUM(type, strings...) \
+const constexpr Enum<type>::Value type##_names[] = strings; \
+template <> const Enum<type>::Value* Enum<type>::begin = std::begin(type##_names); \
+template <> const Enum<type>::Value* Enum<type>::end = std::end(type##_names)
} // namespace mbgl
-
diff --git a/include/mbgl/util/exception.hpp b/include/mbgl/util/exception.hpp
index b73a94fcd2..7c331636d4 100644
--- a/include/mbgl/util/exception.hpp
+++ b/include/mbgl/util/exception.hpp
@@ -6,23 +6,23 @@ namespace mbgl {
namespace util {
struct Exception : std::runtime_error {
- inline Exception(const char *msg) : std::runtime_error(msg) {}
- inline Exception(const std::string &msg) : std::runtime_error(msg) {}
+ Exception(const char *msg) : std::runtime_error(msg) {}
+ Exception(const std::string &msg) : std::runtime_error(msg) {}
};
struct SpriteImageException : Exception {
- inline SpriteImageException(const char *msg) : Exception(msg) {}
- inline SpriteImageException(const std::string &msg) : Exception(msg) {}
+ SpriteImageException(const char *msg) : Exception(msg) {}
+ SpriteImageException(const std::string &msg) : Exception(msg) {}
};
struct MisuseException : Exception {
- inline MisuseException(const char *msg) : Exception(msg) {}
- inline MisuseException(const std::string &msg) : Exception(msg) {}
+ MisuseException(const char *msg) : Exception(msg) {}
+ MisuseException(const std::string &msg) : Exception(msg) {}
};
struct ShaderException : Exception {
- inline ShaderException(const char *msg) : Exception(msg) {}
- inline ShaderException(const std::string &msg) : Exception(msg) {}
+ ShaderException(const char *msg) : Exception(msg) {}
+ ShaderException(const std::string &msg) : Exception(msg) {}
};
} // namespace util
diff --git a/include/mbgl/util/feature.hpp b/include/mbgl/util/feature.hpp
index 7747d34ee9..b72aa15ddd 100644
--- a/include/mbgl/util/feature.hpp
+++ b/include/mbgl/util/feature.hpp
@@ -7,13 +7,9 @@
namespace mbgl {
using Value = mapbox::geometry::value;
-
-class Feature : public mapbox::geometry::feature<double> {
-public:
- Feature(geometry_type&& geometry_)
- : mapbox::geometry::feature<double> { std::move(geometry_) } {}
-
- optional<uint64_t> id;
-};
+using NullValue = mapbox::geometry::null_value_t;
+using PropertyMap = mapbox::geometry::property_map;
+using FeatureIdentifier = mapbox::geometry::identifier;
+using Feature = mapbox::geometry::feature<double>;
} // namespace mbgl
diff --git a/include/mbgl/util/geo.hpp b/include/mbgl/util/geo.hpp
index 7e15d5c2f1..9dca10eb84 100644
--- a/include/mbgl/util/geo.hpp
+++ b/include/mbgl/util/geo.hpp
@@ -57,18 +57,18 @@ public:
LatLng(const UnwrappedTileID& id);
};
-inline bool operator==(const LatLng& a, const LatLng& b) {
+constexpr bool operator==(const LatLng& a, const LatLng& b) {
return a.latitude == b.latitude && a.longitude == b.longitude;
}
-inline bool operator!=(const LatLng& a, const LatLng& b) {
+constexpr bool operator!=(const LatLng& a, const LatLng& b) {
return !(a == b);
}
class ProjectedMeters {
public:
- double northing = 0;
- double easting = 0;
+ double northing;
+ double easting;
ProjectedMeters(double n = 0, double e = 0)
: northing(n), easting(e) {}
@@ -78,6 +78,10 @@ public:
}
};
+constexpr bool operator==(const ProjectedMeters& a, const ProjectedMeters& b) {
+ return a.northing == b.northing && a.easting == b.easting;
+}
+
class LatLngBounds {
public:
// Return a bounds covering the entire (unwrapped) world.
@@ -157,18 +161,18 @@ private:
LatLng sw;
LatLng ne;
- LatLngBounds(const LatLng& sw_, const LatLng& ne_)
- : sw(sw_), ne(ne_) {}
+ LatLngBounds(LatLng sw_, LatLng ne_)
+ : sw(std::move(sw_)), ne(std::move(ne_)) {}
- friend bool operator==(const LatLngBounds&, const LatLngBounds&);
- friend bool operator!=(const LatLngBounds&, const LatLngBounds&);
+ friend constexpr bool operator==(const LatLngBounds&, const LatLngBounds&);
+ friend constexpr bool operator!=(const LatLngBounds&, const LatLngBounds&);
};
-inline bool operator==(const LatLngBounds& a, const LatLngBounds& b) {
+constexpr bool operator==(const LatLngBounds& a, const LatLngBounds& b) {
return a.sw == b.sw && a.ne == b.ne;
}
-inline bool operator!=(const LatLngBounds& a, const LatLngBounds& b) {
+constexpr bool operator!=(const LatLngBounds& a, const LatLngBounds& b) {
return !(a == b);
}
@@ -187,12 +191,12 @@ public:
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() {}
-
+
EdgeInsets(const double t, const double l, const double b, const double r)
: top(t), left(l), bottom(b), right(r) {}
-
+
explicit operator bool() const {
return !(std::isnan(top) || std::isnan(left) || std::isnan(bottom) || std::isnan(right))
&& (top || left || bottom || right);
@@ -210,7 +214,7 @@ public:
top + o.top, left + o.left, bottom + o.bottom, right + o.right,
};
}
-
+
ScreenCoordinate getCenter(uint16_t width, uint16_t height) const;
};
diff --git a/include/mbgl/util/geojson.hpp b/include/mbgl/util/geojson.hpp
new file mode 100644
index 0000000000..b4e789a3ac
--- /dev/null
+++ b/include/mbgl/util/geojson.hpp
@@ -0,0 +1,10 @@
+#pragma once
+
+#include <mapbox/geojson.hpp>
+
+namespace mbgl {
+
+using GeoJSON = mapbox::geojson::geojson;
+using FeatureCollection = mapbox::geojson::feature_collection;
+
+} // namespace mbgl
diff --git a/include/mbgl/util/geometry.hpp b/include/mbgl/util/geometry.hpp
index 6b9c332bf2..6dc16bc514 100644
--- a/include/mbgl/util/geometry.hpp
+++ b/include/mbgl/util/geometry.hpp
@@ -5,6 +5,13 @@
namespace mbgl {
+enum class FeatureType : uint8_t {
+ Unknown = 0,
+ Point = 1,
+ LineString = 2,
+ Polygon = 3
+};
+
template <class T>
using Point = mapbox::geometry::point<T>;
@@ -34,4 +41,21 @@ Point<S> convertPoint(const Point<T>& p) {
return Point<S>(p.x, p.y);
}
+struct ToFeatureType {
+ template <class T>
+ FeatureType operator()(const Point<T> &) const { return FeatureType::Point; }
+ template <class T>
+ FeatureType operator()(const MultiPoint<T> &) const { return FeatureType::Point; }
+ template <class T>
+ FeatureType operator()(const LineString<T> &) const { return FeatureType::LineString; }
+ template <class T>
+ FeatureType operator()(const MultiLineString<T> &) const { return FeatureType::LineString; }
+ template <class T>
+ FeatureType operator()(const Polygon<T> &) const { return FeatureType::Polygon; }
+ template <class T>
+ FeatureType operator()(const MultiPolygon<T> &) const { return FeatureType::Polygon; }
+ template <class T>
+ FeatureType operator()(const mapbox::geometry::geometry_collection<T> &) const { return FeatureType::Unknown; }
+};
+
} // namespace mbgl
diff --git a/include/mbgl/util/projection.hpp b/include/mbgl/util/projection.hpp
index 8e1c994657..eb45088580 100644
--- a/include/mbgl/util/projection.hpp
+++ b/include/mbgl/util/projection.hpp
@@ -11,30 +11,32 @@ namespace mbgl {
class Projection {
public:
- static inline double getMetersPerPixelAtLatitude(double lat, double zoom) {
- const double mapPixelWidthAtZoom = std::pow(2.0, zoom) * util::tileSize;
+ static double getMetersPerPixelAtLatitude(double lat, double zoom) {
+ const double constrainedZoom = util::clamp(zoom, util::MIN_ZOOM, util::MAX_ZOOM);
+ const double mapPixelWidthAtZoom = std::pow(2.0, constrainedZoom) * util::tileSize;
const double constrainedLatitude = util::clamp(lat, -util::LATITUDE_MAX, util::LATITUDE_MAX);
-
return std::cos(constrainedLatitude * util::DEG2RAD) * util::M2PI * util::EARTH_RADIUS_M / mapPixelWidthAtZoom;
}
- static inline ProjectedMeters projectedMetersForLatLng(const LatLng& latLng) {
+ static ProjectedMeters projectedMetersForLatLng(const LatLng& latLng) {
const double constrainedLatitude = util::clamp(latLng.latitude, -util::LATITUDE_MAX, util::LATITUDE_MAX);
+ const double constrainedLongitude = util::clamp(latLng.longitude, -util::LONGITUDE_MAX, util::LONGITUDE_MAX);
const double m = 1 - 1e-15;
const double f = util::clamp(std::sin(util::DEG2RAD * constrainedLatitude), -m, m);
- const double easting = util::EARTH_RADIUS_M * latLng.longitude * util::DEG2RAD;
+ const double easting = util::EARTH_RADIUS_M * constrainedLongitude * util::DEG2RAD;
const double northing = 0.5 * util::EARTH_RADIUS_M * std::log((1 + f) / (1 - f));
return ProjectedMeters(northing, easting);
}
- static inline LatLng latLngForProjectedMeters(const ProjectedMeters& projectedMeters) {
+ static LatLng latLngForProjectedMeters(const ProjectedMeters& projectedMeters) {
double latitude = (2 * std::atan(std::exp(projectedMeters.northing / util::EARTH_RADIUS_M)) - (M_PI / 2)) * util::RAD2DEG;
double longitude = projectedMeters.easting * util::RAD2DEG / util::EARTH_RADIUS_M;
latitude = util::clamp(latitude, -util::LATITUDE_MAX, util::LATITUDE_MAX);
+ longitude = util::clamp(longitude, -util::LONGITUDE_MAX, util::LONGITUDE_MAX);
return LatLng(latitude, longitude);
}
diff --git a/include/mbgl/util/range.hpp b/include/mbgl/util/range.hpp
new file mode 100644
index 0000000000..8da2dd45bb
--- /dev/null
+++ b/include/mbgl/util/range.hpp
@@ -0,0 +1,25 @@
+#pragma once
+
+namespace mbgl {
+
+template <class T>
+class Range {
+public:
+ Range(const T& min_, const T& max_)
+ : min(min_), max(max_) {}
+
+ T min;
+ T max;
+};
+
+template <class T>
+bool operator==(const Range<T>& a, const Range<T>& b) {
+ return a.min == b.min && a.max == b.max;
+}
+
+template <class T>
+bool operator!=(const Range<T>& a, const Range<T>& b) {
+ return !(a == b);
+}
+
+} // namespace mbgl
diff --git a/include/mbgl/util/run_loop.hpp b/include/mbgl/util/run_loop.hpp
index 56965c97e6..25f07c0312 100644
--- a/include/mbgl/util/run_loop.hpp
+++ b/include/mbgl/util/run_loop.hpp
@@ -1,11 +1,11 @@
#pragma once
-#include <mbgl/util/atomic.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/util.hpp>
#include <mbgl/util/work_task.hpp>
#include <mbgl/util/work_request.hpp>
+#include <atomic>
#include <functional>
#include <utility>
#include <queue>
@@ -59,7 +59,7 @@ public:
template <class Fn, class... Args>
std::unique_ptr<AsyncRequest>
invokeCancellable(Fn&& fn, Args&&... args) {
- auto flag = std::make_shared<util::Atomic<bool>>();
+ auto flag = std::make_shared<std::atomic<bool>>();
*flag = false;
auto tuple = std::make_tuple(std::move(args)...);
@@ -77,7 +77,7 @@ public:
template <class Fn, class Cb, class... Args>
std::unique_ptr<AsyncRequest>
invokeWithCallback(Fn&& fn, Cb&& callback, Args&&... args) {
- auto flag = std::make_shared<util::Atomic<bool>>();
+ auto flag = std::make_shared<std::atomic<bool>>();
*flag = false;
// Create a lambda L1 that invokes another lambda L2 on the current RunLoop R, that calls
@@ -114,7 +114,7 @@ private:
template <class F, class P>
class Invoker : public WorkTask {
public:
- Invoker(F&& f, P&& p, std::shared_ptr<util::Atomic<bool>> canceled_ = nullptr)
+ Invoker(F&& f, P&& p, std::shared_ptr<std::atomic<bool>> canceled_ = nullptr)
: canceled(std::move(canceled_)),
func(std::move(f)),
params(std::move(p)) {
@@ -148,7 +148,7 @@ private:
}
std::recursive_mutex mutex;
- std::shared_ptr<util::Atomic<bool>> canceled;
+ std::shared_ptr<std::atomic<bool>> canceled;
F func;
P params;
diff --git a/include/mbgl/util/tileset.hpp b/include/mbgl/util/tileset.hpp
new file mode 100644
index 0000000000..8a7fbe9b73
--- /dev/null
+++ b/include/mbgl/util/tileset.hpp
@@ -0,0 +1,20 @@
+#pragma once
+
+#include <mbgl/util/range.hpp>
+
+#include <vector>
+#include <string>
+#include <cstdint>
+
+namespace mbgl {
+
+class Tileset {
+public:
+ std::vector<std::string> tiles;
+ Range<uint8_t> zoomRange { 0, 22 };
+ std::string attribution;
+
+ // TileJSON also includes center, zoom, and bounds, but they are not used by mbgl.
+};
+
+} // namespace mbgl
diff --git a/include/mbgl/util/traits.hpp b/include/mbgl/util/traits.hpp
index 7c9499897e..9d6f947cd2 100644
--- a/include/mbgl/util/traits.hpp
+++ b/include/mbgl/util/traits.hpp
@@ -5,8 +5,8 @@
namespace mbgl {
template<typename T>
-constexpr auto underlying_type(T t) -> typename std::underlying_type<T>::type {
- return static_cast<typename std::underlying_type<T>::type>(t);
+constexpr auto underlying_type(T t) -> typename std::underlying_type_t<T> {
+ return typename std::underlying_type_t<T>(t);
}
} // namespace mbgl
diff --git a/include/mbgl/util/unitbezier.hpp b/include/mbgl/util/unitbezier.hpp
index ce3e78f3cc..3a4994917b 100644
--- a/include/mbgl/util/unitbezier.hpp
+++ b/include/mbgl/util/unitbezier.hpp
@@ -31,32 +31,31 @@ namespace mbgl {
namespace util {
struct UnitBezier {
- UnitBezier(double p1x, double p1y, double p2x, double p2y) {
- // Calculate the polynomial coefficients, implicit first and last control points are (0,0) and (1,1).
- cx = 3.0 * p1x;
- bx = 3.0 * (p2x - p1x) - cx;
- ax = 1.0 - cx - bx;
-
- cy = 3.0 * p1y;
- by = 3.0 * (p2y - p1y) - cy;
- ay = 1.0 - cy - by;
+ // Calculate the polynomial coefficients, implicit first and last control points are (0,0) and (1,1).
+ constexpr UnitBezier(double p1x, double p1y, double p2x, double p2y)
+ : cx(3.0 * p1x)
+ , bx(3.0 * (p2x - p1x) - cx)
+ , ax(1.0 - cx - bx)
+ , cy(3.0 * p1y)
+ , by(3.0 * (p2y - p1y) - cy)
+ , ay(1.0 - cy - by) {
}
- double sampleCurveX(double t) {
+ double sampleCurveX(double t) const {
// `ax t^3 + bx t^2 + cx t' expanded using Horner's rule.
return ((ax * t + bx) * t + cx) * t;
}
- double sampleCurveY(double t) {
+ double sampleCurveY(double t) const {
return ((ay * t + by) * t + cy) * t;
}
- double sampleCurveDerivativeX(double t) {
+ double sampleCurveDerivativeX(double t) const {
return (3.0 * ax * t + 2.0 * bx) * t + cx;
}
// Given an x value, find a parametric value it came from.
- double solveCurveX(double x, double epsilon) {
+ double solveCurveX(double x, double epsilon) const {
double t0;
double t1;
double t2;
@@ -100,18 +99,18 @@ struct UnitBezier {
return t2;
}
- double solve(double x, double epsilon) {
+ double solve(double x, double epsilon) const {
return sampleCurveY(solveCurveX(x, epsilon));
}
private:
- double ax;
- double bx;
- double cx;
+ const double cx;
+ const double bx;
+ const double ax;
- double ay;
- double by;
- double cy;
+ const double cy;
+ const double by;
+ const double ay;
};
} // namespace util