diff options
Diffstat (limited to 'include')
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 |