diff options
Diffstat (limited to 'include')
69 files changed, 2889 insertions, 412 deletions
diff --git a/include/mbgl/annotation/annotation.hpp b/include/mbgl/annotation/annotation.hpp index 52916549c9..e8ac9a2fb7 100644 --- a/include/mbgl/annotation/annotation.hpp +++ b/include/mbgl/annotation/annotation.hpp @@ -1,11 +1,57 @@ #pragma once +#include <mbgl/util/geometry.hpp> +#include <mbgl/util/variant.hpp> +#include <mbgl/util/color.hpp> + #include <cstdint> #include <vector> +#include <string> namespace mbgl { using AnnotationID = uint32_t; using AnnotationIDs = std::vector<AnnotationID>; +class SymbolAnnotation { +public: + Point<double> geometry; + std::string icon; +}; + +using ShapeAnnotationGeometry = variant< + LineString<double>, + Polygon<double>, + MultiLineString<double>, + MultiPolygon<double>>; + +class LineAnnotation { +public: + ShapeAnnotationGeometry geometry; + float opacity = 1; + float width = 1; + Color color = Color::black(); +}; + +class FillAnnotation { +public: + ShapeAnnotationGeometry geometry; + float opacity = 1; + Color color = Color::black(); + Color outlineColor = { 0, 0, 0, -1 }; +}; + +// An annotation whose type and properties are sourced from a style layer. +class StyleSourcedAnnotation { +public: + ShapeAnnotationGeometry geometry; + std::string layerID; +}; + +using Annotation = variant< + SymbolAnnotation, + LineAnnotation, + FillAnnotation, + StyleSourcedAnnotation>; + } // namespace mbgl diff --git a/include/mbgl/annotation/point_annotation.hpp b/include/mbgl/annotation/point_annotation.hpp deleted file mode 100644 index c9236c3c04..0000000000 --- a/include/mbgl/annotation/point_annotation.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include <mbgl/util/geo.hpp> - -#include <string> - -namespace mbgl { - -class PointAnnotation { -public: - PointAnnotation(const LatLng& position_, const std::string& icon_ = "") - : position(position_.wrapped()), icon(icon_) {} - - const LatLng position; - const std::string icon; -}; - -} // namespace mbgl diff --git a/include/mbgl/annotation/shape_annotation.hpp b/include/mbgl/annotation/shape_annotation.hpp deleted file mode 100644 index 6e3fe95dd4..0000000000 --- a/include/mbgl/annotation/shape_annotation.hpp +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -#include <mbgl/annotation/annotation.hpp> -#include <mbgl/style/types.hpp> - -#include <mbgl/util/geo.hpp> -#include <mbgl/util/variant.hpp> - -namespace mbgl { - -using AnnotationSegment = std::vector<LatLng>; -using AnnotationSegments = std::vector<AnnotationSegment>; - -struct FillAnnotationProperties { - float opacity = 1; - Color color = {{ 0, 0, 0, 1 }}; - Color outlineColor = {{ 0, 0, 0, -1 }}; -}; - -struct LineAnnotationProperties { - float opacity = 1; - float width = 1; - Color color = {{ 0, 0, 0, 1 }}; -}; - -class ShapeAnnotation { -public: - using Properties = variant< - FillAnnotationProperties, // creates a fill annotation - LineAnnotationProperties, // creates a line annotation - std::string>; // creates an annotation whose type and properties are sourced from a style layer - - ShapeAnnotation(const AnnotationSegments& segments_, const Properties& properties_) - : segments(wrapCoordinates(segments_)), properties(properties_) {} - - const AnnotationSegments segments; - const Properties properties; - -private: - AnnotationSegments wrapCoordinates(const AnnotationSegments& segments_) { - AnnotationSegments wrappedSegments; - // Wrap all segments coordinates. - for (const auto& segment_ : segments_) { - AnnotationSegment wrappedSegment; - for (const auto& latLng_ : segment_) { - wrappedSegment.push_back(latLng_.wrapped()); - } - wrappedSegments.push_back(wrappedSegment); - } - return wrappedSegments; - } -}; - -} // namespace mbgl diff --git a/include/mbgl/gl/gl.hpp b/include/mbgl/gl/gl.hpp index 6d601d8a23..0f54b96110 100644 --- a/include/mbgl/gl/gl.hpp +++ b/include/mbgl/gl/gl.hpp @@ -60,14 +60,14 @@ namespace gl { #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..1e05984fbc 100644 --- a/include/mbgl/gl/gl_values.hpp +++ b/include/mbgl/gl/gl_values.hpp @@ -5,6 +5,7 @@ #include <array> #include <mbgl/gl/gl.hpp> +#include <mbgl/util/color.hpp> namespace mbgl { namespace gl { @@ -12,10 +13,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 +24,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 +52,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 +65,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 +78,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 +89,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 +108,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 +128,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)); @@ -146,27 +143,27 @@ struct StencilOp { 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 +173,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 +186,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 +199,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 +210,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 +243,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; @@ -242,10 +256,10 @@ struct LineWidth { struct ActiveTexture { using Type = GLint; static const Type Default; - inline static void Set(const Type& value) { + static void Set(const Type& value) { MBGL_CHECK_ERROR(glActiveTexture(value)); } - inline static Type Get() { + static Type Get() { Type activeTexture; MBGL_CHECK_ERROR(glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTexture)); return activeTexture; @@ -257,10 +271,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 +282,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; diff --git a/include/mbgl/map/camera.hpp b/include/mbgl/map/camera.hpp index 4520321655..3f39ca2dc9 100644 --- a/include/mbgl/map/camera.hpp +++ b/include/mbgl/map/camera.hpp @@ -67,10 +67,10 @@ struct AnimationOptions { 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 f074a5ae54..0e0c04ff0f 100644 --- a/include/mbgl/map/map.hpp +++ b/include/mbgl/map/map.hpp @@ -9,8 +9,7 @@ #include <mbgl/util/feature.hpp> #include <mbgl/util/noncopyable.hpp> #include <mbgl/annotation/annotation.hpp> -#include <mbgl/style/types.hpp> -#include <mbgl/style/property_transition.hpp> +#include <mbgl/style/transition_options.hpp> #include <cstdint> #include <string> @@ -23,11 +22,14 @@ namespace mbgl { class FileSource; class View; class SpriteImage; -class PointAnnotation; -class ShapeAnnotation; struct CameraOptions; struct AnimationOptions; +namespace style { +class Source; +class Layer; +} // namespace style + class Map : private util::noncopyable { public: explicit Map(View&, FileSource&, @@ -49,15 +51,15 @@ public: void update(Update update); // Styling - void addClass(const std::string&, const PropertyTransition& = {}); - void removeClass(const std::string&, const PropertyTransition& = {}); - void setClasses(const std::vector<std::string>&, const PropertyTransition& = {}); + void addClass(const std::string&, const style::TransitionOptions& = {}); + void removeClass(const std::string&, const style::TransitionOptions& = {}); + void setClasses(const std::vector<std::string>&, const style::TransitionOptions& = {}); bool hasClass(const std::string&) const; std::vector<std::string> getClasses() const; - void setStyleURL(const std::string& url); - void setStyleJSON(const std::string& json, const std::string& base = ""); + void setStyleURL(const std::string&); + void setStyleJSON(const std::string&); std::string getStyleURL() const; std::string getStyleJSON() const; @@ -142,26 +144,21 @@ public: void removeAnnotationIcon(const std::string&); double getTopOffsetPixelsForAnnotationIcon(const std::string&); - AnnotationID addPointAnnotation(const PointAnnotation&); - AnnotationIDs addPointAnnotations(const std::vector<PointAnnotation>&); - - AnnotationID addShapeAnnotation(const ShapeAnnotation&); - AnnotationIDs addShapeAnnotations(const std::vector<ShapeAnnotation>&); - - void updatePointAnnotation(AnnotationID, const PointAnnotation&); - + AnnotationID addAnnotation(const Annotation&); + void updateAnnotation(AnnotationID, const Annotation&); void removeAnnotation(AnnotationID); - void removeAnnotations(const AnnotationIDs&); AnnotationIDs getPointAnnotationsInBounds(const LatLngBounds&); - void addCustomLayer(const std::string& id, - CustomLayerInitializeFunction, - CustomLayerRenderFunction, - CustomLayerDeinitializeFunction, - void* context, - const char* before = nullptr); - void removeCustomLayer(const std::string& id); + // 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); // Feature queries std::vector<Feature> queryRenderedFeatures(const ScreenCoordinate&, const optional<std::vector<std::string>>& layerIDs = {}); 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 1c1270ac70..36ce59c01d 100644 --- a/include/mbgl/map/update.hpp +++ b/include/mbgl/map/update.hpp @@ -17,16 +17,15 @@ enum class Update : uint8_t { 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 4431e2b33c..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> @@ -36,8 +37,8 @@ public: // as a matched pair, in four situations: // // 1. When releasing GL resources during Map destruction - // 2. When calling a CustomLayerInitializeFunction, during Map::addCustomLayer - // 3. When calling a CustomLayerDeinitializeFunction, during Map::removeCustomLayer + // 2. When calling a CustomLayerInitializeFunction, during Map::addLayer + // 3. When calling a CustomLayerDeinitializeFunction, during Map::removeLayer // 4. When rendering for Map::renderStill // // They are *not* called for Map::render; it is assumed that the correct context is already 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 b5931e6262..83d00a24dd 100644 --- a/include/mbgl/platform/default/glfw_view.hpp +++ b/include/mbgl/platform/default/glfw_view.hpp @@ -3,6 +3,7 @@ #include <mbgl/mbgl.hpp> #include <mbgl/util/run_loop.hpp> #include <mbgl/util/timer.hpp> +#include <mbgl/util/geometry.hpp> #ifdef MBGL_USE_GLES2 #define GLFW_INCLUDE_ES2 @@ -13,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; @@ -43,7 +44,7 @@ public: void report(float duration); private: - mbgl::LatLng makeRandomPoint() const; + mbgl::Point<double> makeRandomPoint() const; static std::shared_ptr<const mbgl::SpriteImage> makeSpriteImage(int width, int height, float pixelRatio); 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/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/offline.hpp b/include/mbgl/storage/offline.hpp index e0c5ba6247..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 SourceInfo; /* * An offline region defined by a style URL, geographic bounding box, zoom range, and @@ -27,10 +27,10 @@ class SourceInfo; */ 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 SourceInfo&) 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 62ee549663..31df069952 100644 --- a/include/mbgl/storage/resource.hpp +++ b/include/mbgl/storage/resource.hpp @@ -2,7 +2,7 @@ #include <mbgl/storage/response.hpp> #include <mbgl/util/optional.hpp> -#include <mbgl/style/types.hpp> +#include <mbgl/util/font_stack.hpp> #include <string> @@ -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..bd7db3adfb --- /dev/null +++ b/include/mbgl/style/conversion.hpp @@ -0,0 +1,93 @@ +#pragma once + +#include <mbgl/util/variant.hpp> + +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 { const char * 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..4c0089deaf --- /dev/null +++ b/include/mbgl/style/conversion/make_property_setters.hpp @@ -0,0 +1,133 @@ +// 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["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..493c68ea31 --- /dev/null +++ b/include/mbgl/style/conversion/make_property_setters.hpp.ejs @@ -0,0 +1,45 @@ +// 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..38dd934252 --- /dev/null +++ b/include/mbgl/style/conversion/property_setter.hpp @@ -0,0 +1,55 @@ +#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..00c6afb9fe --- /dev/null +++ b/include/mbgl/style/conversion/source.hpp @@ -0,0 +1,123 @@ +#pragma once + +#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> +#include <mbgl/style/conversion.hpp> +#include <mbgl/style/conversion/tileset.hpp> +#include <mbgl/style/conversion/geojson.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" }; + } + + auto result = std::make_unique<GeoJSONSource>(id); + + 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 new file mode 100644 index 0000000000..6a5afb7b47 --- /dev/null +++ b/include/mbgl/style/filter.hpp @@ -0,0 +1,115 @@ +#pragma once + +#include <mbgl/util/variant.hpp> +#include <mbgl/util/feature.hpp> +#include <mbgl/util/geometry.hpp> + +#include <string> +#include <vector> + +namespace mbgl { +namespace style { + +class Filter; + +class NullFilter {}; + +class EqualsFilter { +public: + std::string key; + Value value; +}; + +class NotEqualsFilter { +public: + std::string key; + Value value; +}; + +class LessThanFilter { +public: + std::string key; + Value value; +}; + +class LessThanEqualsFilter { +public: + std::string key; + Value value; +}; + +class GreaterThanFilter { +public: + std::string key; + Value value; +}; + +class GreaterThanEqualsFilter { +public: + std::string key; + Value value; +}; + +class InFilter { +public: + std::string key; + std::vector<Value> values; +}; + +class NotInFilter { +public: + std::string key; + std::vector<Value> values; +}; + +class AnyFilter { +public: + std::vector<Filter> filters; +}; + +class AllFilter { +public: + std::vector<Filter> filters; +}; + +class NoneFilter { +public: + std::vector<Filter> filters; +}; + +class HasFilter { +public: + std::string key; +}; + +class NotHasFilter { +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; + + template <class PropertyAccessor> + bool operator()(FeatureType type, 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..e7b6e0f5a0 --- /dev/null +++ b/include/mbgl/style/filter_evaluator.hpp @@ -0,0 +1,181 @@ +#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 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 { + return key_ == "$type" + ? optional<Value>(uint64_t(featureType)) + : 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 std::vector<Value>&, + const std::vector<Value>&) const { + return false; + } + + bool operator()(const std::unordered_map<std::string, Value>&, + const std::unordered_map<std::string, Value>&) const { + 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_; }); + } +}; + +template <class PropertyAccessor> +bool Filter::operator()(FeatureType type, PropertyAccessor accessor) const { + return FilterBase::visit(*this, FilterEvaluator<PropertyAccessor> { type, accessor }); +} + +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/function.hpp b/include/mbgl/style/function.hpp new file mode 100644 index 0000000000..44ffa31079 --- /dev/null +++ b/include/mbgl/style/function.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include <vector> +#include <utility> + +namespace mbgl { +namespace style { + +template <typename T> +class Function { +public: + using Stop = std::pair<float, T>; + using Stops = std::vector<Stop>; + + 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; } + +private: + float base = 1; + std::vector<std::pair<float, T>> stops; +}; + +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/layer.hpp b/include/mbgl/style/layer.hpp new file mode 100644 index 0000000000..1eff9eb3dc --- /dev/null +++ b/include/mbgl/style/layer.hpp @@ -0,0 +1,78 @@ +#pragma once + +#include <mbgl/util/noncopyable.hpp> +#include <mbgl/style/types.hpp> + +#include <memory> + +namespace mbgl { +namespace style { + +/** + * The runtime representation of a [layer](https://www.mapbox.com/mapbox-gl-style-spec/#layers) from the Mapbox Style + * Specification. + * + * `Layer` is an abstract base class; concrete derived classes are provided for each layer type. `Layer` contains + * functionality that is common to all layer types: + * + * * Runtime type information: type predicates and casting + * * Accessors for properties common to all layer types: ID, visibility, etc. + * * Cloning and copying + * + * All other functionality lives in the derived classes. To instantiate a layer, create an instance of the desired + * type, passing the ID: + * + * auto circleLayer = std::make_unique<CircleLayer>("my-circle-layer"); + */ +class Layer : public mbgl::util::noncopyable { +public: + virtual ~Layer(); + + // Check whether this layer is of the given subtype. + template <class T> + bool is() const; + + // Dynamically cast this layer 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; + + // Visibility + VisibilityType getVisibility() const; + void setVisibility(VisibilityType); + + // Zoom range + float getMinZoom() const; + void setMinZoom(float) const; + float getMaxZoom() const; + void setMaxZoom(float) const; + + // Private implementation + class Impl; + const std::unique_ptr<Impl> baseImpl; + +protected: + enum class Type { + Fill, + Line, + Circle, + Symbol, + Raster, + Background, + Custom, + }; + + const Type type; + Layer(Type, std::unique_ptr<Impl>); +}; + +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/layers/background_layer.hpp b/include/mbgl/style/layers/background_layer.hpp new file mode 100644 index 0000000000..ac97ec2e6d --- /dev/null +++ b/include/mbgl/style/layers/background_layer.hpp @@ -0,0 +1,45 @@ +// 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> + +namespace mbgl { +namespace style { + +class BackgroundLayer : public Layer { +public: + BackgroundLayer(const std::string& layerID); + ~BackgroundLayer() final; + + // Paint properties + + PropertyValue<Color> getBackgroundColor() const; + void setBackgroundColor(PropertyValue<Color>, const optional<std::string>& klass = {}); + + PropertyValue<std::string> getBackgroundPattern() const; + void setBackgroundPattern(PropertyValue<std::string>, const optional<std::string>& klass = {}); + + PropertyValue<float> getBackgroundOpacity() const; + void setBackgroundOpacity(PropertyValue<float>, const optional<std::string>& klass = {}); + + // Private implementation + + class Impl; + Impl* const impl; + + BackgroundLayer(const Impl&); + BackgroundLayer(const BackgroundLayer&) = delete; +}; + +template <> +inline bool Layer::is<BackgroundLayer>() const { + return type == Type::Background; +} + +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/layers/circle_layer.hpp b/include/mbgl/style/layers/circle_layer.hpp new file mode 100644 index 0000000000..c8d99ab30e --- /dev/null +++ b/include/mbgl/style/layers/circle_layer.hpp @@ -0,0 +1,62 @@ +// 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> + +namespace mbgl { +namespace style { + +class CircleLayer : public Layer { +public: + CircleLayer(const std::string& layerID, const std::string& sourceID); + ~CircleLayer() final; + + // Source + const std::string& getSourceID() const; + const std::string& getSourceLayer() const; + void setSourceLayer(const std::string& sourceLayer); + + void setFilter(const Filter&); + const Filter& getFilter() const; + + // Paint properties + + PropertyValue<float> getCircleRadius() const; + void setCircleRadius(PropertyValue<float>, const optional<std::string>& klass = {}); + + PropertyValue<Color> getCircleColor() const; + void setCircleColor(PropertyValue<Color>, const optional<std::string>& klass = {}); + + PropertyValue<float> getCircleBlur() const; + void setCircleBlur(PropertyValue<float>, const optional<std::string>& klass = {}); + + PropertyValue<float> getCircleOpacity() const; + void setCircleOpacity(PropertyValue<float>, const optional<std::string>& klass = {}); + + PropertyValue<std::array<float, 2>> getCircleTranslate() const; + void setCircleTranslate(PropertyValue<std::array<float, 2>>, const optional<std::string>& klass = {}); + + PropertyValue<TranslateAnchorType> getCircleTranslateAnchor() const; + void setCircleTranslateAnchor(PropertyValue<TranslateAnchorType>, const optional<std::string>& klass = {}); + + // Private implementation + + class Impl; + Impl* const impl; + + CircleLayer(const Impl&); + CircleLayer(const CircleLayer&) = delete; +}; + +template <> +inline bool Layer::is<CircleLayer>() const { + return type == Type::Circle; +} + +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/layers/custom_layer.hpp b/include/mbgl/style/layers/custom_layer.hpp new file mode 100644 index 0000000000..d3867e2c4f --- /dev/null +++ b/include/mbgl/style/layers/custom_layer.hpp @@ -0,0 +1,71 @@ +#pragma once + +#include <mbgl/style/layer.hpp> + +namespace mbgl { +namespace style { + +/** + * Initialize any GL state needed by the custom layer. This method is called once, from the + * rendering thread, at a point when the GL context is active but before rendering for the + * first time. + * + * Resources that are acquired in this method must be released in the UninitializeFunction. + */ +using CustomLayerInitializeFunction = void (*)(void* context); + +/** + * Parameters that define the current camera position for a CustomLayerRenderFunction. + */ +struct CustomLayerRenderParameters { + double width; + double height; + double latitude; + double longitude; + double zoom; + double bearing; + double pitch; + double altitude; +}; + +/** + * Render the layer. This method is called once per frame. The implementation should not make + * any assumptions about the GL state (other than that the correct context is active). It may + * make changes to the state, and is not required to reset values such as the depth mask, stencil + * mask, and corresponding test flags to their original values. + */ +using CustomLayerRenderFunction = void (*)(void* context, const CustomLayerRenderParameters&); + +/** + * Destroy any GL state needed by the custom layer, and deallocate context, if necessary. This + * method is called once, from the rendering thread, at a point when the GL context is active. + * + * Note that it may be called even when the InitializeFunction has not been called. + */ +using CustomLayerDeinitializeFunction = void (*)(void* context); + +class CustomLayer : public Layer { +public: + CustomLayer(const std::string& id, + CustomLayerInitializeFunction, + CustomLayerRenderFunction, + CustomLayerDeinitializeFunction, + void* context); + ~CustomLayer() final; + + // Private implementation + + class Impl; + Impl* impl; + + CustomLayer(const Impl&); + CustomLayer(const CustomLayer&) = delete; +}; + +template <> +inline bool Layer::is<CustomLayer>() const { + return type == Type::Custom; +} + +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/layers/fill_layer.hpp b/include/mbgl/style/layers/fill_layer.hpp new file mode 100644 index 0000000000..e70d67f538 --- /dev/null +++ b/include/mbgl/style/layers/fill_layer.hpp @@ -0,0 +1,65 @@ +// 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> + +namespace mbgl { +namespace style { + +class FillLayer : public Layer { +public: + FillLayer(const std::string& layerID, const std::string& sourceID); + ~FillLayer() final; + + // Source + const std::string& getSourceID() const; + const std::string& getSourceLayer() const; + void setSourceLayer(const std::string& sourceLayer); + + void setFilter(const Filter&); + const Filter& getFilter() const; + + // Paint properties + + PropertyValue<bool> getFillAntialias() const; + void setFillAntialias(PropertyValue<bool>, const optional<std::string>& klass = {}); + + PropertyValue<float> getFillOpacity() const; + void setFillOpacity(PropertyValue<float>, const optional<std::string>& klass = {}); + + PropertyValue<Color> getFillColor() const; + void setFillColor(PropertyValue<Color>, const optional<std::string>& klass = {}); + + PropertyValue<Color> getFillOutlineColor() const; + void setFillOutlineColor(PropertyValue<Color>, const optional<std::string>& klass = {}); + + PropertyValue<std::array<float, 2>> getFillTranslate() const; + void setFillTranslate(PropertyValue<std::array<float, 2>>, const optional<std::string>& klass = {}); + + PropertyValue<TranslateAnchorType> getFillTranslateAnchor() const; + void setFillTranslateAnchor(PropertyValue<TranslateAnchorType>, const optional<std::string>& klass = {}); + + PropertyValue<std::string> getFillPattern() const; + void setFillPattern(PropertyValue<std::string>, const optional<std::string>& klass = {}); + + // Private implementation + + class Impl; + Impl* const impl; + + FillLayer(const Impl&); + FillLayer(const FillLayer&) = delete; +}; + +template <> +inline bool Layer::is<FillLayer>() const { + return type == Type::Fill; +} + +} // namespace style +} // namespace mbgl 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 new file mode 100644 index 0000000000..abcb425b96 --- /dev/null +++ b/include/mbgl/style/layers/line_layer.hpp @@ -0,0 +1,90 @@ +// 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> + +#include <vector> + +namespace mbgl { +namespace style { + +class LineLayer : public Layer { +public: + LineLayer(const std::string& layerID, const std::string& sourceID); + ~LineLayer() final; + + // Source + const std::string& getSourceID() const; + const std::string& getSourceLayer() const; + void setSourceLayer(const std::string& sourceLayer); + + void setFilter(const Filter&); + const Filter& getFilter() const; + + // Layout properties + + PropertyValue<LineCapType> getLineCap() const; + void setLineCap(PropertyValue<LineCapType>); + + PropertyValue<LineJoinType> getLineJoin() const; + void setLineJoin(PropertyValue<LineJoinType>); + + PropertyValue<float> getLineMiterLimit() const; + void setLineMiterLimit(PropertyValue<float>); + + PropertyValue<float> getLineRoundLimit() const; + void setLineRoundLimit(PropertyValue<float>); + + // Paint properties + + PropertyValue<float> getLineOpacity() const; + void setLineOpacity(PropertyValue<float>, const optional<std::string>& klass = {}); + + PropertyValue<Color> getLineColor() const; + void setLineColor(PropertyValue<Color>, const optional<std::string>& klass = {}); + + PropertyValue<std::array<float, 2>> getLineTranslate() const; + void setLineTranslate(PropertyValue<std::array<float, 2>>, const optional<std::string>& klass = {}); + + PropertyValue<TranslateAnchorType> getLineTranslateAnchor() const; + void setLineTranslateAnchor(PropertyValue<TranslateAnchorType>, const optional<std::string>& klass = {}); + + PropertyValue<float> getLineWidth() const; + void setLineWidth(PropertyValue<float>, const optional<std::string>& klass = {}); + + PropertyValue<float> getLineGapWidth() const; + void setLineGapWidth(PropertyValue<float>, const optional<std::string>& klass = {}); + + PropertyValue<float> getLineOffset() const; + void setLineOffset(PropertyValue<float>, const optional<std::string>& klass = {}); + + PropertyValue<float> getLineBlur() const; + void setLineBlur(PropertyValue<float>, const optional<std::string>& klass = {}); + + PropertyValue<std::vector<float>> getLineDasharray() const; + void setLineDasharray(PropertyValue<std::vector<float>>, const optional<std::string>& klass = {}); + + PropertyValue<std::string> getLinePattern() const; + void setLinePattern(PropertyValue<std::string>, const optional<std::string>& klass = {}); + + // Private implementation + + class Impl; + Impl* const impl; + + LineLayer(const Impl&); + LineLayer(const LineLayer&) = delete; +}; + +template <> +inline bool Layer::is<LineLayer>() const { + return type == Type::Line; +} + +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/layers/raster_layer.hpp b/include/mbgl/style/layers/raster_layer.hpp new file mode 100644 index 0000000000..dea0c26bf3 --- /dev/null +++ b/include/mbgl/style/layers/raster_layer.hpp @@ -0,0 +1,60 @@ +// 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> + +namespace mbgl { +namespace style { + +class RasterLayer : public Layer { +public: + RasterLayer(const std::string& layerID, const std::string& sourceID); + ~RasterLayer() final; + + // Source + const std::string& getSourceID() const; + + // Paint properties + + PropertyValue<float> getRasterOpacity() const; + void setRasterOpacity(PropertyValue<float>, const optional<std::string>& klass = {}); + + PropertyValue<float> getRasterHueRotate() const; + void setRasterHueRotate(PropertyValue<float>, const optional<std::string>& klass = {}); + + PropertyValue<float> getRasterBrightnessMin() const; + void setRasterBrightnessMin(PropertyValue<float>, const optional<std::string>& klass = {}); + + PropertyValue<float> getRasterBrightnessMax() const; + void setRasterBrightnessMax(PropertyValue<float>, const optional<std::string>& klass = {}); + + PropertyValue<float> getRasterSaturation() const; + void setRasterSaturation(PropertyValue<float>, const optional<std::string>& klass = {}); + + PropertyValue<float> getRasterContrast() const; + void setRasterContrast(PropertyValue<float>, const optional<std::string>& klass = {}); + + PropertyValue<float> getRasterFadeDuration() const; + void setRasterFadeDuration(PropertyValue<float>, const optional<std::string>& klass = {}); + + // Private implementation + + class Impl; + Impl* const impl; + + RasterLayer(const Impl&); + RasterLayer(const RasterLayer&) = delete; +}; + +template <> +inline bool Layer::is<RasterLayer>() const { + return type == Type::Raster; +} + +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/layers/symbol_layer.hpp b/include/mbgl/style/layers/symbol_layer.hpp new file mode 100644 index 0000000000..77b63d9b91 --- /dev/null +++ b/include/mbgl/style/layers/symbol_layer.hpp @@ -0,0 +1,192 @@ +// 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> + +#include <vector> + +namespace mbgl { +namespace style { + +class SymbolLayer : public Layer { +public: + SymbolLayer(const std::string& layerID, const std::string& sourceID); + ~SymbolLayer() final; + + // Source + const std::string& getSourceID() const; + const std::string& getSourceLayer() const; + void setSourceLayer(const std::string& sourceLayer); + + void setFilter(const Filter&); + const Filter& getFilter() const; + + // Layout properties + + PropertyValue<SymbolPlacementType> getSymbolPlacement() const; + void setSymbolPlacement(PropertyValue<SymbolPlacementType>); + + PropertyValue<float> getSymbolSpacing() const; + void setSymbolSpacing(PropertyValue<float>); + + PropertyValue<bool> getSymbolAvoidEdges() const; + void setSymbolAvoidEdges(PropertyValue<bool>); + + PropertyValue<bool> getIconAllowOverlap() const; + void setIconAllowOverlap(PropertyValue<bool>); + + PropertyValue<bool> getIconIgnorePlacement() const; + void setIconIgnorePlacement(PropertyValue<bool>); + + PropertyValue<bool> getIconOptional() const; + void setIconOptional(PropertyValue<bool>); + + 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>); + + PropertyValue<float> getIconRotate() const; + void setIconRotate(PropertyValue<float>); + + PropertyValue<float> getIconPadding() const; + void setIconPadding(PropertyValue<float>); + + PropertyValue<bool> getIconKeepUpright() const; + void setIconKeepUpright(PropertyValue<bool>); + + PropertyValue<std::array<float, 2>> getIconOffset() const; + void setIconOffset(PropertyValue<std::array<float, 2>>); + + 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>); + + PropertyValue<std::vector<std::string>> getTextFont() const; + void setTextFont(PropertyValue<std::vector<std::string>>); + + PropertyValue<float> getTextSize() const; + void setTextSize(PropertyValue<float>); + + PropertyValue<float> getTextMaxWidth() const; + void setTextMaxWidth(PropertyValue<float>); + + PropertyValue<float> getTextLineHeight() const; + void setTextLineHeight(PropertyValue<float>); + + PropertyValue<float> getTextLetterSpacing() const; + void setTextLetterSpacing(PropertyValue<float>); + + PropertyValue<TextJustifyType> getTextJustify() const; + void setTextJustify(PropertyValue<TextJustifyType>); + + PropertyValue<TextAnchorType> getTextAnchor() const; + void setTextAnchor(PropertyValue<TextAnchorType>); + + PropertyValue<float> getTextMaxAngle() const; + void setTextMaxAngle(PropertyValue<float>); + + PropertyValue<float> getTextRotate() const; + void setTextRotate(PropertyValue<float>); + + PropertyValue<float> getTextPadding() const; + void setTextPadding(PropertyValue<float>); + + PropertyValue<bool> getTextKeepUpright() const; + void setTextKeepUpright(PropertyValue<bool>); + + PropertyValue<TextTransformType> getTextTransform() const; + void setTextTransform(PropertyValue<TextTransformType>); + + PropertyValue<std::array<float, 2>> getTextOffset() const; + void setTextOffset(PropertyValue<std::array<float, 2>>); + + PropertyValue<bool> getTextAllowOverlap() const; + void setTextAllowOverlap(PropertyValue<bool>); + + PropertyValue<bool> getTextIgnorePlacement() const; + void setTextIgnorePlacement(PropertyValue<bool>); + + PropertyValue<bool> getTextOptional() const; + void setTextOptional(PropertyValue<bool>); + + // Paint properties + + PropertyValue<float> getIconOpacity() const; + void setIconOpacity(PropertyValue<float>, const optional<std::string>& klass = {}); + + PropertyValue<Color> getIconColor() const; + void setIconColor(PropertyValue<Color>, const optional<std::string>& klass = {}); + + PropertyValue<Color> getIconHaloColor() const; + void setIconHaloColor(PropertyValue<Color>, const optional<std::string>& klass = {}); + + PropertyValue<float> getIconHaloWidth() const; + void setIconHaloWidth(PropertyValue<float>, const optional<std::string>& klass = {}); + + PropertyValue<float> getIconHaloBlur() const; + void setIconHaloBlur(PropertyValue<float>, const optional<std::string>& klass = {}); + + PropertyValue<std::array<float, 2>> getIconTranslate() const; + void setIconTranslate(PropertyValue<std::array<float, 2>>, const optional<std::string>& klass = {}); + + PropertyValue<TranslateAnchorType> getIconTranslateAnchor() const; + void setIconTranslateAnchor(PropertyValue<TranslateAnchorType>, const optional<std::string>& klass = {}); + + PropertyValue<float> getTextOpacity() const; + void setTextOpacity(PropertyValue<float>, const optional<std::string>& klass = {}); + + PropertyValue<Color> getTextColor() const; + void setTextColor(PropertyValue<Color>, const optional<std::string>& klass = {}); + + PropertyValue<Color> getTextHaloColor() const; + void setTextHaloColor(PropertyValue<Color>, const optional<std::string>& klass = {}); + + PropertyValue<float> getTextHaloWidth() const; + void setTextHaloWidth(PropertyValue<float>, const optional<std::string>& klass = {}); + + PropertyValue<float> getTextHaloBlur() const; + void setTextHaloBlur(PropertyValue<float>, const optional<std::string>& klass = {}); + + PropertyValue<std::array<float, 2>> getTextTranslate() const; + void setTextTranslate(PropertyValue<std::array<float, 2>>, const optional<std::string>& klass = {}); + + PropertyValue<TranslateAnchorType> getTextTranslateAnchor() const; + void setTextTranslateAnchor(PropertyValue<TranslateAnchorType>, const optional<std::string>& klass = {}); + + // Private implementation + + class Impl; + Impl* const impl; + + SymbolLayer(const Impl&); + SymbolLayer(const SymbolLayer&) = delete; +}; + +template <> +inline bool Layer::is<SymbolLayer>() const { + return type == Type::Symbol; +} + +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/property_transition.hpp b/include/mbgl/style/property_transition.hpp deleted file mode 100644 index b9a301feea..0000000000 --- a/include/mbgl/style/property_transition.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include <mbgl/util/chrono.hpp> -#include <mbgl/util/optional.hpp> - -namespace mbgl { - -class PropertyTransition { -public: - PropertyTransition(const optional<Duration>& duration_ = {}, const optional<Duration>& delay_ = {}) - : duration(duration_), delay(delay_) {} - - optional<Duration> duration; - optional<Duration> delay; -}; - -} // namespace mbgl diff --git a/include/mbgl/style/property_value.hpp b/include/mbgl/style/property_value.hpp new file mode 100644 index 0000000000..d8f83a0fb3 --- /dev/null +++ b/include/mbgl/style/property_value.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include <mbgl/util/variant.hpp> +#include <mbgl/style/function.hpp> + +namespace mbgl { +namespace style { + +class Undefined {}; + +template <class T> +class PropertyValue { +private: + using Value = variant<Undefined, T, Function<T>>; + Value value; + +public: + PropertyValue() : value() {} + PropertyValue( T constant) : value(constant) {} + PropertyValue(Function<T> function) : value(function) {} + + bool isUndefined() const { return value.which() == 0; } + bool isConstant() const { return value.which() == 1; } + bool isFunction() const { return value.which() == 2; } + + const T & asConstant() const { return value.template get< T >(); } + const Function<T>& asFunction() const { return value.template get<Function<T>>(); } + + explicit operator bool() const { return !isUndefined(); }; + + template <typename Visitor> + static auto visit(const PropertyValue<T>& value, Visitor&& visitor) { + return Value::visit(value.value, visitor); + } +}; + +} // namespace style +} // namespace mbgl 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..3736dd44bc --- /dev/null +++ b/include/mbgl/style/sources/geojson_source.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include <mbgl/style/source.hpp> +#include <mbgl/util/geojson.hpp> + +namespace mbgl { +namespace style { + +class GeoJSONSource : public Source { +public: + GeoJSONSource(const std::string& id); + + void setURL(const std::string& url); + void setGeoJSON(GeoJSON&&); + + // 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 new file mode 100644 index 0000000000..d7a6633f0c --- /dev/null +++ b/include/mbgl/style/transition_options.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include <mbgl/util/chrono.hpp> +#include <mbgl/util/optional.hpp> + +namespace mbgl { +namespace style { + +struct TransitionOptions { + optional<Duration> duration = {}; + optional<Duration> delay = {}; +}; + +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/types.hpp b/include/mbgl/style/types.hpp index 9b03ab8a2d..28ebda9fb9 100644 --- a/include/mbgl/style/types.hpp +++ b/include/mbgl/style/types.hpp @@ -1,27 +1,10 @@ #pragma once -#include <mbgl/util/enum.hpp> - -#include <string> -#include <array> -#include <vector> +#include <cstdint> namespace mbgl { -// Stores a premultiplied color, with all four channels ranging from 0..1 -using Color = std::array<float, 4>; - -// An array of font names -using FontStack = std::vector<std::string>; - -std::string fontStackToString(const FontStack&); - -struct FontStackHash { - std::size_t operator()(const FontStack&) const; -}; - -// ------------------------------------------------------------------------------------------------- - +// TODO: should be in public source.hpp header and style namespace enum class SourceType : uint8_t { Vector, Raster, @@ -30,15 +13,7 @@ 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 { Visible, @@ -75,9 +50,10 @@ enum class SymbolPlacementType : bool { Line, }; -enum class RotationAlignmentType : bool { +enum class AlignmentType : uint8_t { Map, Viewport, + Undefined, }; enum class TextJustifyType : uint8_t { @@ -104,44 +80,12 @@ enum class TextTransformType : uint8_t { Lowercase, }; -/** - * Initialize any GL state needed by the custom layer. This method is called once, from the - * rendering thread, at a point when the GL context is active but before rendering for the - * first time. - * - * Resources that are acquired in this method must be released in the UninitializeFunction. - */ -using CustomLayerInitializeFunction = void (*)(void* context); - -/** - * Parameters that define the current camera position for a CustomLayerRenderFunction. - */ -struct CustomLayerRenderParameters { - double width; - double height; - double latitude; - double longitude; - double zoom; - double bearing; - double pitch; - double altitude; +enum class IconTextFitType : uint8_t { + None, + Both, + Width, + Height }; -/** - * Render the layer. This method is called once per frame. The implementation should not make - * any assumptions about the GL state (other than that the correct context is active). It may - * make changes to the state, and is not required to reset values such as the depth mask, stencil - * mask, and corresponding test flags to their original values. - */ -using CustomLayerRenderFunction = void (*)(void* context, const CustomLayerRenderParameters&); - -/** - * Destroy any GL state needed by the custom layer, and deallocate context, if necessary. This - * method is called once, from the rendering thread, at a point when the GL context is active. - * - * Note that it may be called even when the InitializeFunction has not been called. - */ -using CustomLayerDeinitializeFunction = void (*)(void* context); - +} // namespace style } // namespace mbgl - diff --git a/include/mbgl/util/color.hpp b/include/mbgl/util/color.hpp new file mode 100644 index 0000000000..4be380fde3 --- /dev/null +++ b/include/mbgl/util/color.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include <mbgl/util/optional.hpp> + +#include <string> + +namespace mbgl { + +// Stores a premultiplied color, with all four channels ranging from 0..1 +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/font_stack.hpp b/include/mbgl/util/font_stack.hpp new file mode 100644 index 0000000000..d0b431e9ea --- /dev/null +++ b/include/mbgl/util/font_stack.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include <string> +#include <vector> + +namespace mbgl { + +// An array of font names +using FontStack = std::vector<std::string>; + +std::string fontStackToString(const FontStack&); + +struct FontStackHash { + std::size_t operator()(const FontStack&) const; +}; + +} // namespace mbgl diff --git a/include/mbgl/util/geo.hpp b/include/mbgl/util/geo.hpp index 7e15d5c2f1..a68058048d 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); } diff --git a/include/mbgl/util/geojson.hpp b/include/mbgl/util/geojson.hpp new file mode 100644 index 0000000000..3fd8c6ac4b --- /dev/null +++ b/include/mbgl/util/geojson.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include <memory> + +namespace mapbox { +namespace geojsonvt { +class GeoJSONVT; +} // namespace geojsonvt +} // namespace mapbox + +namespace mbgl { + +class GeoJSON { +public: + GeoJSON(std::unique_ptr<mapbox::geojsonvt::GeoJSONVT>); + GeoJSON(GeoJSON&&); + ~GeoJSON(); + + std::unique_ptr<mapbox::geojsonvt::GeoJSONVT> impl; +}; + +} // namespace mbgl diff --git a/include/mbgl/util/geometry.hpp b/include/mbgl/util/geometry.hpp new file mode 100644 index 0000000000..7fc2668c2c --- /dev/null +++ b/include/mbgl/util/geometry.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include <mapbox/geometry/geometry.hpp> +#include <mapbox/geometry/point_arithmetic.hpp> + +namespace mbgl { + +enum class FeatureType : uint8_t { + Unknown = 0, + Point = 1, + LineString = 2, + Polygon = 3 +}; + +template <class T> +using Point = mapbox::geometry::point<T>; + +template <class T> +using LineString = mapbox::geometry::line_string<T>; + +template <class T> +using Polygon = mapbox::geometry::polygon<T>; + +template <class T> +using MultiPoint = mapbox::geometry::multi_point<T>; + +template <class T> +using MultiLineString = mapbox::geometry::multi_line_string<T>; + +template <class T> +using MultiPolygon = mapbox::geometry::multi_polygon<T>; + +template <class T> +using LinearRing = mapbox::geometry::linear_ring<T>; + +template <class T> +using Geometry = mapbox::geometry::geometry<T>; + +template <class S, class T> +Point<S> convertPoint(const Point<T>& p) { + return Point<S>(p.x, p.y); +} + +} // namespace mbgl diff --git a/include/mbgl/util/image.hpp b/include/mbgl/util/image.hpp index fbb0686a7b..124cdca7cd 100644 --- a/include/mbgl/util/image.hpp +++ b/include/mbgl/util/image.hpp @@ -1,5 +1,7 @@ #pragma once +#include <mbgl/util/noncopyable.hpp> + #include <string> #include <memory> #include <algorithm> @@ -12,7 +14,7 @@ enum ImageAlphaMode { }; template <ImageAlphaMode Mode> -class Image { +class Image : private util::noncopyable { public: Image() = default; @@ -26,6 +28,18 @@ public: height(h), data(std::move(data_)) {} + Image(Image&& o) + : width(o.width), + height(o.height), + data(std::move(o.data)) {} + + Image& operator=(Image&& o) { + width = o.width; + height = o.height; + data = std::move(o.data); + return *this; + } + bool operator==(const Image& rhs) const { return width == rhs.width && height == rhs.height && std::equal(data.get(), data.get() + size(), rhs.data.get(), 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/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 diff --git a/include/mbgl/util/variant.hpp b/include/mbgl/util/variant.hpp new file mode 100644 index 0000000000..68a1208a17 --- /dev/null +++ b/include/mbgl/util/variant.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include <mapbox/variant.hpp> + +namespace mbgl { + +template <typename... T> +using variant = mapbox::util::variant<T...>; + +} // namespace mbgl |